diff --git a/AUTHORS b/AUTHORS
index 6953eeaa..4152024 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1559,6 +1559,7 @@
 Yong Wang <ccyongwang@tencent.com>
 Yonggang Luo <luoyonggang@gmail.com>
 Yongha Lee <yongha78.lee@samsung.com>
+Yongsang Park <yongsangpark980813@gmail.com>
 Yongseok Choi <yongseok.choi@navercorp.com>
 Yongsheng Zhu <yongsheng.zhu@intel.com>
 Yoonjae Cho <yoonjae.cho92@gmail.com>
diff --git a/DEPS b/DEPS
index 2486608..1f45b8f 100644
--- a/DEPS
+++ b/DEPS
@@ -304,15 +304,15 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '618beab475b6ee5b33a4c3040dc330359b960eab',
+  'skia_revision': '320dccf1a32dbc4d477fdb194515f75731903a6a',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '7264a6ecc7eb4ccbcef3acf035ab962f987fa4ea',
+  'v8_revision': '07f299fcadd1e0c201ce1f82d0c39d5b43a5e275',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '10d56e63f489477d325fd9667861c06b4c5887bc',
+  'angle_revision': 'c335ddfa1e135806405cad9f1d4cd3e610571ba7',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -324,7 +324,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
-  'boringssl_revision': '604868d748c06d2c5c03505915e125ec5131eca0',
+  'boringssl_revision': '40ec347196a939bd4fd1f801df896b2f4e2205dc',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Fuchsia sdk
   # and whatever else without interference from each other.
@@ -396,7 +396,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling devtools-frontend
   # and whatever else without interference from each other.
-  'devtools_frontend_revision': 'b20e8d5ddd78f6d04a0b1fd4147aaa821f1bb6a2',
+  'devtools_frontend_revision': 'b5ed0ccf1e934c3b15df0239c022f4282dd5a3a5',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libprotobuf-mutator
   # and whatever else without interference from each other.
@@ -420,11 +420,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': 'bc562481f3a6eb08ddc4b20ae2a2bb70f0a15409',
+  'dawn_revision': 'ca2e3757ae7c8e8236ac780a2f10f75fdc9da156',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'quiche_revision': '0b682f33d185e50cfdf1e417fe6a021162a5fa18',
+  'quiche_revision': '92bef88ae524d684ff4e1397853ca51604d1da11',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ios_webkit
   # and whatever else without interference from each other.
@@ -1287,7 +1287,7 @@
 
   'src/clank': {
     'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' +
-    '123f9cd86c36186e08fafb2445dd5fa0e5688a94',
+    '5ff4aacc9038c4be345d8e97699a2a5f1f8aed60',
     'condition': 'checkout_android and checkout_src_internal',
   },
 
@@ -1430,7 +1430,7 @@
     'packages': [
       {
           'package': 'chromium/third_party/androidx',
-          'version': 'kybJUIH8jna1eCue2pU_s_jKcjfJPx_omp68wERCkBEC',
+          'version': 'kweONX_nTXLzK4f1w8RdW2UMA2iJpf8l4NU5_Glg1moC',
       },
     ],
     'condition': 'checkout_android and non_git_source',
@@ -1760,13 +1760,13 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'c36eb432d9887c0872ba39e582a97dd3b76c0c22',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '1ad5b6c0df87d570420c9f833c0c024fa863853b',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
 
   'src/third_party/devtools-frontend-internal': {
-      'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + '660f3660a28aaf564aeff5015f013cec4f17f72c',
+      'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + 'f13f62055a86f13f3f560fb10ea9c5cd6ecaf62a',
     'condition': 'checkout_src_internal',
   },
 
@@ -2540,7 +2540,7 @@
       'dep_type': 'cipd',
   },
 
-  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@3b92cef97febae53dc21de79c51ec3ddf2d4390e',
+  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@49bb428cd4514a34c4626a7589e2251d5b50dced',
   'src/third_party/glslang/src': '{chromium_git}/external/github.com/KhronosGroup/glslang@12a17b7ce41436427e358608183100b1103274da',
   'src/third_party/spirv-cross/src': '{chromium_git}/external/github.com/KhronosGroup/SPIRV-Cross@b8fcf307f1f347089e3c46eb4451d27f32ebc8d3',
   'src/third_party/spirv-headers/src': '{chromium_git}/external/github.com/KhronosGroup/SPIRV-Headers@2a9b6f951c7d6b04b6c21fe1bf3f475b68b84801',
@@ -2549,7 +2549,7 @@
   'src/third_party/vulkan-loader/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Loader@1108bba6c97174d172d45470a7470a3d6a564647',
   'src/third_party/vulkan-tools/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Tools@4c63e845962ff3b197855f3ae4907a47d0863f5a',
   'src/third_party/vulkan-utility-libraries/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Utility-Libraries@ea5774a13e3017b6d5d79af6fba9f0d72ca5c61a',
-  'src/third_party/vulkan-validation-layers/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-ValidationLayers@99de3c17fbc2db6b6da0347916c9e01a383c2758',
+  'src/third_party/vulkan-validation-layers/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-ValidationLayers@50910c05fdc909aba59cc71e6320b0c5908912cd',
 
   'src/third_party/vulkan_memory_allocator':
     Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + '56300b29fbfcc693ee6609ddad3fdd5b7a449a21',
@@ -2586,10 +2586,10 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '1b6371436a0a60e6b9a4ae2a40a8eba198e3af02',
 
   'src/third_party/webgpu-cts/src':
-    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '7568697695ffd3e4eebee494d833feb99f65494b',
+    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'e42b1f6ef712353f416f4528267a37895631180c',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'e922cd12628e32b37c06c2be4d23e4f8a1452e80',
+    Var('webrtc_git') + '/src.git' + '@' + '47d48a2089ab765a3ef1177c5c1456eb3d67aa8a',
 
   # Wuffs' canonical repository is at github.com/google/wuffs, but we use
   # Skia's mirror of Wuffs, the same as in upstream Skia's DEPS file.
@@ -2718,7 +2718,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/boca_app/app',
-        'version': 'lBuFCpYxNLCu5UtyS2Xx2S_eVPj5Jz6waOMSqCu1A80C',
+        'version': 'N4dGsCDUtOI6er8IvHIxM54CFzMZX4H7orGsE9ff3-AC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -2773,7 +2773,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/projector_app/app',
-        'version': 'laSnH9dTH80FxxcYjvkPHhQteH0l-zIR1qbt17d0mLIC',
+        'version': 'j9lUwWGNRZabvTeLd3IxOKiRGLmOSkdLVu4GXpDiHqwC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -4322,7 +4322,7 @@
 
   'src/components/optimization_guide/internal': {
       'url': Var('chrome_git') + '/chrome/components/optimization_guide.git' + '@' +
-        'b8ec0d2bf23c43dbf82b8d579c3cbc97a5771df0',
+        'e3a75e7f401aaa2cf290716560fd066072fb2772',
       'condition': 'checkout_src_internal',
   },
 
@@ -4382,7 +4382,7 @@
 
   'src/ios_internal':  {
       'url': Var('chrome_git') + '/chrome/ios_internal.git' + '@' +
-        'cb9d0f308d6dd05d93f35f9e1fd6098fb968839a',
+        '7a2df944059b4837fd4c2cfabe6b251b3c8c6b47',
       'condition': 'checkout_ios and checkout_src_internal',
   },
 
diff --git a/android_webview/browser/BUILD.gn b/android_webview/browser/BUILD.gn
index 754b6df0..a0c8d0e6 100644
--- a/android_webview/browser/BUILD.gn
+++ b/android_webview/browser/BUILD.gn
@@ -216,8 +216,6 @@
     "safe_browsing/aw_safe_browsing_ui_manager.h",
     "safe_browsing/aw_url_checker_delegate_impl.cc",
     "safe_browsing/aw_url_checker_delegate_impl.h",
-    "sensitive_content/aw_sensitive_content_client.cc",
-    "sensitive_content/aw_sensitive_content_client.h",
     "state_serializer.cc",
     "state_serializer.h",
     "supervised_user/aw_supervised_user_blocking_page.cc",
@@ -310,7 +308,6 @@
     "//components/safe_browsing/core/common/hashprefix_realtime:hash_realtime_utils",
     "//components/security_interstitials/content:security_interstitial_page",
     "//components/security_interstitials/core",
-    "//components/sensitive_content",
     "//components/services/heap_profiling/public/cpp",
     "//components/spellcheck:buildflags",
     "//components/strings:components_strings_grit",
diff --git a/android_webview/browser/DEPS b/android_webview/browser/DEPS
index fda6b8af..dcb5553 100644
--- a/android_webview/browser/DEPS
+++ b/android_webview/browser/DEPS
@@ -49,7 +49,6 @@
   "+components/safe_browsing/core/browser",
   "+components/safe_browsing/core/common",
   "+components/security_interstitials",
-  "+components/sensitive_content",
   "+components/services/heap_profiling",
   "+components/spellcheck/browser",
   "+components/spellcheck/common",
diff --git a/android_webview/browser/sensitive_content/OWNERS b/android_webview/browser/sensitive_content/OWNERS
deleted file mode 100644
index c186703c..0000000
--- a/android_webview/browser/sensitive_content/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-file://components/sensitive_content/OWNERS
diff --git a/android_webview/browser/sensitive_content/aw_sensitive_content_client.cc b/android_webview/browser/sensitive_content/aw_sensitive_content_client.cc
deleted file mode 100644
index bc991b4..0000000
--- a/android_webview/browser/sensitive_content/aw_sensitive_content_client.cc
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2024 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "android_webview/browser/sensitive_content/aw_sensitive_content_client.h"
-
-#include "content/public/browser/web_contents.h"
-
-namespace sensitive_content {
-
-AwSensitiveContentClient::AwSensitiveContentClient(
-    content::WebContents* web_contents)
-    : content::WebContentsUserData<AwSensitiveContentClient>(*web_contents),
-      manager_(web_contents, this) {}
-
-AwSensitiveContentClient::~AwSensitiveContentClient() = default;
-
-void AwSensitiveContentClient::SetContentSensitivity(
-    bool content_is_sensitive) {}
-
-std::string_view AwSensitiveContentClient::GetHistogramPrefix() {
-  return "SensitiveContent.WebView.";
-}
-
-}  // namespace sensitive_content
diff --git a/android_webview/browser/sensitive_content/aw_sensitive_content_client.h b/android_webview/browser/sensitive_content/aw_sensitive_content_client.h
deleted file mode 100644
index d921663b..0000000
--- a/android_webview/browser/sensitive_content/aw_sensitive_content_client.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2024 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef ANDROID_WEBVIEW_BROWSER_SENSITIVE_CONTENT_AW_SENSITIVE_CONTENT_CLIENT_H_
-#define ANDROID_WEBVIEW_BROWSER_SENSITIVE_CONTENT_AW_SENSITIVE_CONTENT_CLIENT_H_
-
-#include "components/sensitive_content/sensitive_content_client.h"
-#include "components/sensitive_content/sensitive_content_manager.h"
-#include "content/public/browser/web_contents_user_data.h"
-
-namespace content {
-class WebContents;
-}  // namespace content
-
-namespace sensitive_content {
-
-class AwSensitiveContentClient
-    : public SensitiveContentClient,
-      public content::WebContentsUserData<AwSensitiveContentClient> {
- public:
-  explicit AwSensitiveContentClient(content::WebContents* web_contents);
-
-  AwSensitiveContentClient(const AwSensitiveContentClient&) = delete;
-  AwSensitiveContentClient& operator=(const AwSensitiveContentClient&) = delete;
-  ~AwSensitiveContentClient() override;
-
-  void SetContentSensitivity(bool content_is_sensitive) override;
-
-  std::string_view GetHistogramPrefix() override;
-
- private:
-  SensitiveContentManager manager_;
-};
-
-}  // namespace sensitive_content
-
-#endif  // ANDROID_WEBVIEW_BROWSER_SENSITIVE_CONTENT_AW_SENSITIVE_CONTENT_CLIENT_H_
diff --git a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
index 5c02c46..9a052e5 100644
--- a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
+++ b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
@@ -1055,6 +1055,7 @@
         Flag.baseFeature(
                 AwFeatures.WEBVIEW_DIGITAL_ASSET_LINKS_LOAD_INCLUDES,
                 "Enable loading include statements when checking digital asset links."),
+        Flag.baseFeature("PrefetchNewWaitLoop"),
 
         // Add new commandline switches and features above. The final entry should have a
         // trailing comma for cleaner diffs.
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 916cc98..a37000bc 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -397,6 +397,8 @@
     "birch/birch_ranker.h",
     "birch/birch_weather_provider.cc",
     "birch/birch_weather_provider.h",
+    "birch/coral_item_remover.cc",
+    "birch/coral_item_remover.h",
     "bluetooth_devices_observer.cc",
     "bluetooth_devices_observer.h",
     "booting/booting_animation_controller.cc",
@@ -3734,6 +3736,7 @@
     "birch/birch_model_unittest.cc",
     "birch/birch_ranker_unittest.cc",
     "birch/birch_weather_provider_unittest.cc",
+    "birch/coral_item_remover_unittest.cc",
     "bubble//simple_grid_layout_unittest.cc",
     "bubble/bubble_event_filter_unittest.cc",
     "bubble/bubble_utils_unittest.cc",
diff --git a/ash/birch/coral_item_remover.cc b/ash/birch/coral_item_remover.cc
new file mode 100644
index 0000000..04ea7a1fc
--- /dev/null
+++ b/ash/birch/coral_item_remover.cc
@@ -0,0 +1,24 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/birch/coral_item_remover.h"
+
+namespace ash {
+
+CoralItemRemover::CoralItemRemover() = default;
+
+CoralItemRemover::~CoralItemRemover() = default;
+
+void CoralItemRemover::RemoveItem(const coral_util::ContentItem& item) {
+  removed_content_items_.insert(coral_util::GetIdentifier(item));
+}
+
+void CoralItemRemover::FilterRemovedItems(
+    std::vector<coral_util::ContentItem>* items) {
+  std::erase_if(*items, [this](const coral_util::ContentItem& item) {
+    return removed_content_items_.contains(coral_util::GetIdentifier(item));
+  });
+}
+
+}  // namespace ash
diff --git a/ash/birch/coral_item_remover.h b/ash/birch/coral_item_remover.h
new file mode 100644
index 0000000..305ffb25
--- /dev/null
+++ b/ash/birch/coral_item_remover.h
@@ -0,0 +1,40 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_BIRCH_CORAL_ITEM_REMOVER_H_
+#define ASH_BIRCH_CORAL_ITEM_REMOVER_H_
+
+#include <set>
+
+#include "ash/ash_export.h"
+#include "ash/public/cpp/coral_util.h"
+
+namespace ash {
+
+// Manages a list of ContentItems which have been removed by the user. Removed
+// items are stored for the current session only. ContentItem lists can be
+// filtered to erase any items that have been removed by the user.
+class ASH_EXPORT CoralItemRemover {
+ public:
+  CoralItemRemover();
+  CoralItemRemover(const CoralItemRemover&) = delete;
+  CoralItemRemover& operator=(const CoralItemRemover&) = delete;
+  ~CoralItemRemover();
+
+  // Records the coral_util::ContentItem to be removed for the current session.
+  void RemoveItem(const coral_util::ContentItem& item);
+
+  // Erases from the ContentItem list any items which have been removed by the
+  // user. The list is mutated in place.
+  void FilterRemovedItems(std::vector<coral_util::ContentItem>* content_items);
+
+ private:
+  // Stores the unique identifier for content items that should be filtered for
+  //  the rest of the current user session.
+  std::set<std::string> removed_content_items_;
+};
+
+}  // namespace ash
+
+#endif  // ASH_BIRCH_CORAL_ITEM_REMOVER_H_
diff --git a/ash/birch/coral_item_remover_unittest.cc b/ash/birch/coral_item_remover_unittest.cc
new file mode 100644
index 0000000..25c59c8
--- /dev/null
+++ b/ash/birch/coral_item_remover_unittest.cc
@@ -0,0 +1,46 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/birch/coral_item_remover.h"
+
+#include "ash/public/cpp/coral_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace ash {
+
+using CoralItemRemoverTest = ::testing::Test;
+
+TEST_F(CoralItemRemoverTest, FilterContent) {
+  CoralItemRemover coral_item_remover_;
+  coral_util::ContentItem item0 =
+      coral_util::TabData("tab 0 title", "tab 0 source");
+  coral_util::ContentItem item1 =
+      coral_util::TabData("tab 1 title", "tab 1 source");
+  coral_util::ContentItem item2 = coral_util::TabData("app 0 id", "app 0 name");
+  coral_util::ContentItem item3 = coral_util::TabData("app 1 id", "app 1 name");
+  std::vector<coral_util::ContentItem> tab_items = {item0, item1, item2, item3};
+
+  // Filter `tab_items` before any items are removed. The list should remain
+  // unchanged.
+  coral_item_remover_.FilterRemovedItems(&tab_items);
+  ASSERT_EQ(4u, tab_items.size());
+
+  // Remove `item2`, and filter it from the list of tabs.
+  coral_item_remover_.RemoveItem(item2);
+  coral_item_remover_.FilterRemovedItems(&tab_items);
+
+  // Check that `item2` is filtered out.
+  ASSERT_EQ(3u, tab_items.size());
+  EXPECT_EQ(tab_items, std::vector({item0, item1, item3}));
+
+  // Remove `item1`, and filter it from the list of tabs.
+  coral_item_remover_.RemoveItem(item1);
+  coral_item_remover_.FilterRemovedItems(&tab_items);
+
+  // Check that `item1` is filtered out.
+  ASSERT_EQ(2u, tab_items.size());
+  EXPECT_EQ(tab_items, std::vector({item0, item3}));
+}
+
+}  // namespace ash
diff --git a/ash/components/arc/mojom/arc_bridge.mojom b/ash/components/arc/mojom/arc_bridge.mojom
index 7c3c0880..d2c986f 100644
--- a/ash/components/arc/mojom/arc_bridge.mojom
+++ b/ash/components/arc/mojom/arc_bridge.mojom
@@ -145,7 +145,7 @@
 
   // Notifies Chrome that the ErrorNotificationInstance interface is ready.
   [MinVersion=67] OnErrorNotificationInstanceReady@172(
-    pending_remote<ErrorNotificationInstance> instance_remote);
+      pending_remote<ErrorNotificationInstance> instance_remote);
 
   // Notifies Chrome that the FileSystemInstance interface is ready.
   [MinVersion=13] OnFileSystemInstanceReady@119(
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index 9f7effb..e3bb2a1 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -1743,6 +1743,13 @@
              "ImeKoreanOnlyModeSwitchOnRightAlt",
              base::FEATURE_ENABLED_BY_DEFAULT);
 
+// Enables a change in the IME switching logic such that the mojo connection
+// status is tracked via a global boolean instead of checking if the runner is
+// idle.
+BASE_FEATURE(kImeSwitchCheckConnectionStatus,
+             "ImeSwitchCheckConnectionStatus",
+             base::FEATURE_ENABLED_BY_DEFAULT);
+
 // Controls whether to show new improved UI for cryptohome errors that happened
 // during login. UI contains links to help center and might provide actions
 // that can be taken to resolve the problem.
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h
index 6f73979..135bc9b 100644
--- a/ash/constants/ash_features.h
+++ b/ash/constants/ash_features.h
@@ -579,6 +579,8 @@
 COMPONENT_EXPORT(ASH_CONSTANTS)
 BASE_DECLARE_FEATURE(kImeKoreanModeSwitchDebug);
 COMPONENT_EXPORT(ASH_CONSTANTS)
+BASE_DECLARE_FEATURE(kImeSwitchCheckConnectionStatus);
+COMPONENT_EXPORT(ASH_CONSTANTS)
 BASE_DECLARE_FEATURE(kImeKoreanOnlyModeSwitchOnRightAlt);
 COMPONENT_EXPORT(ASH_CONSTANTS)
 BASE_DECLARE_FEATURE(kImprovedLoginErrorHandling);
diff --git a/ash/picker/views/picker_image_item_grid_view.cc b/ash/picker/views/picker_image_item_grid_view.cc
index 5aa57951..2fbce44 100644
--- a/ash/picker/views/picker_image_item_grid_view.cc
+++ b/ash/picker/views/picker_image_item_grid_view.cc
@@ -53,10 +53,14 @@
   }
 }
 
-std::unique_ptr<views::View> CreateListItemView() {
+std::unique_ptr<views::View> CreateListItemView(size_t pos_in_set) {
   auto view = std::make_unique<views::View>();
   view->SetUseDefaultFillLayout(true);
   view->GetViewAccessibility().SetRole(ax::mojom::Role::kListItem);
+  view->GetViewAccessibility().SetPosInSet(pos_in_set);
+  // Setting the hierarchical level explicitly allows the SetSize to be
+  // overridden later.
+  view->GetViewAccessibility().SetHierarchicalLevel(1);
   return view;
 }
 
@@ -181,9 +185,16 @@
                           return v->GetPreferredSize().height();
                         });
   PickerImageItemView* new_item =
-      shortest_column->AddChildView(CreateListItemView())
+      shortest_column
+          ->AddChildView(CreateListItemView(focusable_items_.size() + 1))
           ->AddChildView(std::move(image_item));
   focusable_items_.push_back(new_item);
+
+  // Update the SetSize for all items.
+  for (views::View* view : focusable_items_) {
+    view->parent()->GetViewAccessibility().SetSetSize(focusable_items_.size());
+  }
+
   return new_item;
 }
 
diff --git a/ash/picker/views/picker_image_item_row_view.cc b/ash/picker/views/picker_image_item_row_view.cc
index 31f4cfb7..5f30bd6 100644
--- a/ash/picker/views/picker_image_item_row_view.cc
+++ b/ash/picker/views/picker_image_item_row_view.cc
@@ -86,6 +86,9 @@
                                   std::move(more_items_accessible_name),
                                   /*is_togglable=*/false,
                                   /*has_border=*/false))
+                              // The kSubmenuArrowChromeRefreshIcon flips
+                              // itself, so don't flip it again.
+                              .SetFlipCanvasOnPaintForRTLUI(false)
                               .CopyAddressTo(&more_items_button_))))
       .BuildChildren();
   GetViewAccessibility().SetRole(ax::mojom::Role::kGrid);
diff --git a/ash/public/cpp/coral_util.cc b/ash/public/cpp/coral_util.cc
index e3863bf9..54c5f12a 100644
--- a/ash/public/cpp/coral_util.cc
+++ b/ash/public/cpp/coral_util.cc
@@ -4,8 +4,20 @@
 
 #include "ash/public/cpp/coral_util.h"
 
+#include "base/notreached.h"
+
 namespace ash::coral_util {
 
+std::string GetIdentifier(const ContentItem& item) {
+  if (std::holds_alternative<AppData>(item)) {
+    return std::get<AppData>(item).app_id;
+  }
+  if (std::holds_alternative<TabData>(item)) {
+    return std::get<TabData>(item).source;
+  }
+  NOTREACHED();
+}
+
 CoralRequest::CoralRequest() = default;
 
 CoralRequest::~CoralRequest() = default;
diff --git a/ash/public/cpp/coral_util.h b/ash/public/cpp/coral_util.h
index 1f0945d..b3b15b9 100644
--- a/ash/public/cpp/coral_util.h
+++ b/ash/public/cpp/coral_util.h
@@ -34,6 +34,9 @@
 
 using ContentItem = std::variant<AppData, TabData>;
 
+// Gets the unique identifier for `item`.
+std::string ASH_PUBLIC_EXPORT GetIdentifier(const ContentItem& item);
+
 class ASH_PUBLIC_EXPORT CoralRequest {
  public:
   enum class RequestType {
diff --git a/ash/system/camera/camera_effects_controller.cc b/ash/system/camera/camera_effects_controller.cc
index 7d4e6d6..b4c79fd 100644
--- a/ash/system/camera/camera_effects_controller.cc
+++ b/ash/system/camera/camera_effects_controller.cc
@@ -405,13 +405,8 @@
 
   registry->RegisterBooleanPref(prefs::kBackgroundReplace, false);
 
-  // If the Studio Look feature is available, the portrait relighting and face
-  // retouch prefs are used to determine which effects are applied. Enable both
-  // of them by default. Otherwise, disable both of them.
-  registry->RegisterBooleanPref(prefs::kPortraitRelighting,
-                                features::IsVcStudioLookEnabled());
-  registry->RegisterBooleanPref(prefs::kFaceRetouch,
-                                features::IsVcStudioLookEnabled());
+  registry->RegisterBooleanPref(prefs::kPortraitRelighting, false);
+  registry->RegisterBooleanPref(prefs::kFaceRetouch, false);
 
   // If the Studio Look feature is available, disable Studio Look by default.
   // Otherwise, set it to always true to apply effects based on the portrait
@@ -716,9 +711,10 @@
         // Make sure that `studio_look_enabled` is set to true. Otherwise, this
         // will override the value of `relight_enabled`.
         new_effects->studio_look_enabled = true;
+      } else {
+        new_effects->studio_look_enabled =
+            new_effects->relight_enabled || new_effects->retouch_enabled;
       }
-      // TODO(b/354069928): Toggle off the Studio Look button when both
-      // relighting and retouch are disabled.
       break;
     }
     case VcEffectId::kFaceRetouch: {
@@ -728,22 +724,17 @@
         // Make sure that `studio_look_enabled` is set to true. Otherwise, this
         // will override the value of `retouch_enabled`.
         new_effects->studio_look_enabled = true;
+      } else {
+        new_effects->studio_look_enabled =
+            new_effects->relight_enabled || new_effects->retouch_enabled;
       }
-      // TODO(b/354069928): Toggle off the Studio Look button when both
-      // relighting and retouch are disabled.
       break;
     }
     case VcEffectId::kStudioLook: {
       new_effects->studio_look_enabled =
           state.value_or(!new_effects->studio_look_enabled);
-      if (new_effects->studio_look_enabled && !new_effects->relight_enabled &&
-          !new_effects->retouch_enabled) {
-        // When Studio Look is toggled enabled but portrait relighting and face
-        // retouch are currently both disabled, the portrait relighting and face
-        // retouch prefs are updated to be enabled.
-        new_effects->relight_enabled = true;
-        new_effects->retouch_enabled = true;
-      }
+      new_effects->relight_enabled = new_effects->studio_look_enabled;
+      new_effects->retouch_enabled = new_effects->studio_look_enabled;
       break;
     }
     case VcEffectId::kCameraFraming: {
@@ -757,6 +748,14 @@
       NOTREACHED();
   }
 
+  if (new_effects->studio_look_enabled !=
+      current_effects_->studio_look_enabled) {
+    VideoConferenceTrayController::Get()
+        ->GetEffectsManager()
+        .NotifyEffectChanged(VcEffectId::kStudioLook,
+                             new_effects->studio_look_enabled);
+  }
+
   SetCameraEffects(std::move(new_effects), /*is_initialization*/ false,
                    base::DoNothing());
 }
diff --git a/ash/system/focus_mode/focus_mode_controller_unittest.cc b/ash/system/focus_mode/focus_mode_controller_unittest.cc
index ce1b092..6ff7c44 100644
--- a/ash/system/focus_mode/focus_mode_controller_unittest.cc
+++ b/ash/system/focus_mode/focus_mode_controller_unittest.cc
@@ -604,43 +604,6 @@
       2);
 }
 
-// Verify that when we start a focus session, the histogram will record whether
-// there is a selected task or not.
-TEST_F(FocusModeControllerMultiUserTest, CheckHasSelectedTaskHistogram) {
-  base::HistogramTester histogram_tester;
-
-  auto* controller = FocusModeController::Get();
-  EXPECT_FALSE(controller->in_focus_session());
-  histogram_tester.ExpectTotalCount(
-      focus_mode_histogram_names::kHasSelectedTaskOnSessionStartHistogramName,
-      0);
-
-  // 1. Start a focus session without a selected task.
-  EXPECT_FALSE(controller->HasSelectedTask());
-  controller->ToggleFocusMode();
-  EXPECT_TRUE(controller->in_focus_session());
-  histogram_tester.ExpectBucketCount(
-      focus_mode_histogram_names::kHasSelectedTaskOnSessionStartHistogramName,
-      false, 1);
-  controller->ToggleFocusMode();
-  EXPECT_FALSE(controller->in_focus_session());
-
-  // 2. Start a focus session with a selected task.
-  FocusModeTask task;
-  task.task_id = {.list_id = "abc", .id = "1"};
-  task.title = "Focus Task";
-  task.updated = base::Time::Now();
-
-  controller->SetSelectedTask(task);
-  EXPECT_TRUE(controller->HasSelectedTask());
-
-  controller->ToggleFocusMode();
-  EXPECT_TRUE(controller->in_focus_session());
-  histogram_tester.ExpectBucketCount(
-      focus_mode_histogram_names::kHasSelectedTaskOnSessionStartHistogramName,
-      true, 1);
-}
-
 // Tests that the histogram will record how many tasks we selected during a
 // focus session.
 TEST_F(FocusModeControllerMultiUserTest, CheckTasksSelectedHistogram) {
diff --git a/ash/system/focus_mode/focus_mode_histogram_names.h b/ash/system/focus_mode/focus_mode_histogram_names.h
index ae96a4a..ff6d3c8 100644
--- a/ash/system/focus_mode/focus_mode_histogram_names.h
+++ b/ash/system/focus_mode/focus_mode_histogram_names.h
@@ -12,8 +12,6 @@
 constexpr char kLongSuffix[] = "Long";
 
 // Histograms recorded when starting a session.
-constexpr char kHasSelectedTaskOnSessionStartHistogramName[] =
-    "Ash.FocusMode.StartSession.HasSelectedTask";
 constexpr char kInitialDurationOnSessionStartsHistogramName[] =
     "Ash.FocusMode.StartSession.InitialDuration";
 constexpr char kStartSessionSourceHistogramName[] =
diff --git a/ash/system/focus_mode/focus_mode_metrics_recorder.cc b/ash/system/focus_mode/focus_mode_metrics_recorder.cc
index 1204e51d..ae6ac2f0 100644
--- a/ash/system/focus_mode/focus_mode_metrics_recorder.cc
+++ b/ash/system/focus_mode/focus_mode_metrics_recorder.cc
@@ -56,13 +56,6 @@
   }
 }
 
-void RecordHasSelectedTaskOnSessionStartHistogram() {
-  base::UmaHistogramBoolean(
-      /*name=*/focus_mode_histogram_names::
-          kHasSelectedTaskOnSessionStartHistogramName,
-      /*sample=*/FocusModeController::Get()->HasSelectedTask());
-}
-
 void RecordTasksSelectedHistogram(const int tasks_selected_count) {
   base::UmaHistogramCounts100(
       focus_mode_histogram_names::kTasksSelectedHistogramName,
@@ -289,8 +282,6 @@
   RecordInitialDurationHistogram(
       /*session_duration=*/initial_session_duration_);
   RecordStartSessionSourceHistogram(source);
-  // TODO(b/344594740): Remove `RecordHasSelectedTaskOnSessionStartHistogram()`.
-  RecordHasSelectedTaskOnSessionStartHistogram();
   RecordStartedWithTaskHistogram(selected_task_id);
   RecordExistingMediaPlayingOnStartHistogram();
 }
diff --git a/ash/system/video_conference/bubble/settings_button.cc b/ash/system/video_conference/bubble/settings_button.cc
index 657704e..e995319 100644
--- a/ash/system/video_conference/bubble/settings_button.cc
+++ b/ash/system/video_conference/bubble/settings_button.cc
@@ -12,6 +12,7 @@
 #include "ash/style/switch.h"
 #include "ash/system/camera/camera_effects_controller.h"
 #include "ash/system/model/system_tray_model.h"
+#include "ash/system/video_conference/video_conference_utils.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
 #include "ui/base/models/simple_menu_model.h"
@@ -246,10 +247,18 @@
         client->ShowPrivacyAndSecuritySettings();
         break;
       case CommandId::kPortraitRelighting:
+        base::UmaHistogramBoolean(
+            video_conference_utils::GetEffectHistogramNameForClick(
+                VcEffectId::kPortraitRelighting),
+            !IsCommandIdChecked(command_id));
         effects_controller_->OnEffectControlActivated(
             VcEffectId::kPortraitRelighting, /*state=*/std::nullopt);
         break;
       case CommandId::kFaceRetouch:
+        base::UmaHistogramBoolean(
+            video_conference_utils::GetEffectHistogramNameForClick(
+                VcEffectId::kFaceRetouch),
+            !IsCommandIdChecked(command_id));
         effects_controller_->OnEffectControlActivated(VcEffectId::kFaceRetouch,
                                                       /*state=*/std::nullopt);
         break;
diff --git a/ash/system/video_conference/bubble/toggle_effects_view.cc b/ash/system/video_conference/bubble/toggle_effects_view.cc
index 1a8cc1f5..c687af2 100644
--- a/ash/system/video_conference/bubble/toggle_effects_view.cc
+++ b/ash/system/video_conference/bubble/toggle_effects_view.cc
@@ -12,6 +12,7 @@
 #include "ash/bubble/bubble_utils.h"
 #include "ash/constants/ash_features.h"
 #include "ash/resources/vector_icons/vector_icons.h"
+#include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/style/icon_button.h"
 #include "ash/style/typography.h"
@@ -242,16 +243,33 @@
   if (container_id.has_value()) {
     SetID(container_id.value());
   }
+
+  VideoConferenceTrayController::Get()->GetEffectsManager().AddObserver(this);
 }
 
-ToggleEffectsButton::~ToggleEffectsButton() = default;
+ToggleEffectsButton::~ToggleEffectsButton() {
+  VideoConferenceTrayController::Get()->GetEffectsManager().RemoveObserver(
+      this);
+}
+
+void ToggleEffectsButton::OnEffectChanged(VcEffectId effect_id, bool is_on) {
+  if (effect_id != effect_id_ || is_on == toggled_) {
+    return;
+  }
+
+  toggled_ = is_on;
+  UpdateColorsAndBackground();
+  UpdateTooltip();
+}
 
 void ToggleEffectsButton::OnButtonClicked(const ui::Event& event) {
-  callback_.Run(event);
-
   // Sets the toggled state.
   toggled_ = !toggled_;
 
+  // Run `callback_` after `toggled_` is updated to avoid duplicated work with
+  // OnCameraEffectChange().
+  callback_.Run(event);
+
   base::UmaHistogramBoolean(
       video_conference_utils::GetEffectHistogramNameForClick(effect_id_),
       toggled_);
@@ -260,12 +278,7 @@
       !toggled_, ui::HapticTouchpadEffectStrength::kMedium);
 
   UpdateColorsAndBackground();
-  SetTooltipText(l10n_util::GetStringFUTF16(
-      VIDEO_CONFERENCE_TOGGLE_BUTTON_TOOLTIP,
-      l10n_util::GetStringUTF16(accessible_name_id_),
-      l10n_util::GetStringUTF16(
-          toggled_ ? VIDEO_CONFERENCE_TOGGLE_BUTTON_STATE_ON
-                   : VIDEO_CONFERENCE_TOGGLE_BUTTON_STATE_OFF)));
+  UpdateTooltip();
 }
 
 void ToggleEffectsButton::UpdateColorsAndBackground() {
@@ -283,6 +296,15 @@
   label_->SetEnabledColorId(foreground_color_id);
 }
 
+void ToggleEffectsButton::UpdateTooltip() {
+  SetTooltipText(l10n_util::GetStringFUTF16(
+      VIDEO_CONFERENCE_TOGGLE_BUTTON_TOOLTIP,
+      l10n_util::GetStringUTF16(accessible_name_id_),
+      l10n_util::GetStringUTF16(
+          toggled_ ? VIDEO_CONFERENCE_TOGGLE_BUTTON_STATE_ON
+                   : VIDEO_CONFERENCE_TOGGLE_BUTTON_STATE_OFF)));
+}
+
 BEGIN_METADATA(ToggleEffectsButton);
 END_METADATA
 
diff --git a/ash/system/video_conference/bubble/toggle_effects_view.h b/ash/system/video_conference/bubble/toggle_effects_view.h
index 5e05ae7..1a78ce9 100644
--- a/ash/system/video_conference/bubble/toggle_effects_view.h
+++ b/ash/system/video_conference/bubble/toggle_effects_view.h
@@ -5,6 +5,7 @@
 #ifndef ASH_SYSTEM_VIDEO_CONFERENCE_BUBBLE_TOGGLE_EFFECTS_VIEW_H_
 #define ASH_SYSTEM_VIDEO_CONFERENCE_BUBBLE_TOGGLE_EFFECTS_VIEW_H_
 
+#include "ash/system/video_conference/effects/video_conference_tray_effects_manager.h"
 #include "base/memory/raw_ptr.h"
 #include "ui/base/metadata/metadata_header_macros.h"
 #include "ui/views/controls/button/button.h"
@@ -33,7 +34,8 @@
 // A single toggle button for a video conference effect, combined with a text
 // label. WARNING: `callback` provided must not destroy the button or the bubble
 // (i.e. close the bubble) as it would result in a crash in `OnButtonClicked()`.
-class ToggleEffectsButton : public views::Button {
+class ToggleEffectsButton : public views::Button,
+                            public VideoConferenceTrayEffectsManager::Observer {
   METADATA_HEADER(ToggleEffectsButton, views::Button)
 
  public:
@@ -51,6 +53,9 @@
 
   ~ToggleEffectsButton() override;
 
+  // VideoConferenceTrayEffectsManager::Observer:
+  void OnEffectChanged(VcEffectId effect_id, bool is_on) override;
+
   views::FlexLayout* layout() { return layout_; }
 
   views::ImageView* icon() { return icon_; }
@@ -62,6 +67,9 @@
   // Update the color of icon/label and background.
   void UpdateColorsAndBackground();
 
+  // Update the tooltip text.
+  void UpdateTooltip();
+
   views::Button::PressedCallback callback_;
 
   // Indicates the toggled state of the button.
diff --git a/ash/system/video_conference/bubble/vc_tile_ui_controller.cc b/ash/system/video_conference/bubble/vc_tile_ui_controller.cc
index 3d28e892..e50a4bb 100644
--- a/ash/system/video_conference/bubble/vc_tile_ui_controller.cc
+++ b/ash/system/video_conference/bubble/vc_tile_ui_controller.cc
@@ -36,20 +36,24 @@
   effect_state_ = effect->GetWeakState(/*index=*/0);
   effect_state_label_for_debug_ = effect_state_->label_text();
   auto* dlc_service_client = DlcserviceClient::Get();
-  if (!dlc_service_client) {
+  if (dlc_service_client) {
     // `dlc_service_client` may not exist in tests.
-    return;
+    dlc_service_client->AddObserver(this);
   }
-  dlc_service_client->AddObserver(this);
+  VideoConferenceTrayController::Get()->GetEffectsManager().AddObserver(this);
 }
 
 VcTileUiController::~VcTileUiController() {
   auto* dlc_service_client = DlcserviceClient::Get();
-  if (!dlc_service_client) {
+  if (dlc_service_client) {
     // `dlc_service_client` may not exist in tests.
-    return;
+    dlc_service_client->RemoveObserver(this);
   }
-  dlc_service_client->RemoveObserver(this);
+  auto* vc_tray_controller = VideoConferenceTrayController::Get();
+  if (vc_tray_controller) {
+    // `vc_tray_controller` may be destroyed before this destructor.
+    vc_tray_controller->GetEffectsManager().RemoveObserver(this);
+  }
 }
 
 std::unique_ptr<FeatureTile> VcTileUiController::CreateTile() {
@@ -103,18 +107,29 @@
   UpdateDlcDownloadUi();
 }
 
+void VcTileUiController::OnEffectChanged(VcEffectId effect_id, bool is_on) {
+  if (effect_id != effect_id_ || is_on == tile_->IsToggled()) {
+    return;
+  }
+
+  tile_->SetToggled(is_on);
+  tile_->UpdateColors();
+  UpdateTooltip();
+}
+
 void VcTileUiController::OnPressed(const ui::Event& event) {
   if (!effect_state_ || !tile_) {
     return;
   }
 
-  // Execute the associated tile's callback.
-  views::Button::PressedCallback(effect_state_->button_callback()).Run(event);
-
   // Set the toggled state.
   bool toggled = !tile_->IsToggled();
   tile_->SetToggled(toggled);
 
+  // Execute the associated tile's callback. This should be called after
+  // SetToggled() to avoid duplicated work with OnCameraEffectChange().
+  views::Button::PressedCallback(effect_state_->button_callback()).Run(event);
+
   // Track UMA metrics about the toggled state.
   TrackToggleUMA(toggled);
 
diff --git a/ash/system/video_conference/bubble/vc_tile_ui_controller.h b/ash/system/video_conference/bubble/vc_tile_ui_controller.h
index 1f188e0..1eced93 100644
--- a/ash/system/video_conference/bubble/vc_tile_ui_controller.h
+++ b/ash/system/video_conference/bubble/vc_tile_ui_controller.h
@@ -9,6 +9,7 @@
 
 #include "ash/ash_export.h"
 #include "ash/system/unified/feature_tile.h"
+#include "ash/system/video_conference/effects/video_conference_tray_effects_manager.h"
 #include "ash/system/video_conference/effects/video_conference_tray_effects_manager_types.h"
 #include "base/containers/flat_set.h"
 #include "base/memory/weak_ptr.h"
@@ -27,7 +28,9 @@
 // `ash::VcEffectsDelegate`.
 //
 // Note: This class is only used when `VcDlcUi` is enabled.
-class ASH_EXPORT VcTileUiController : public DlcserviceClient::Observer {
+class ASH_EXPORT VcTileUiController
+    : public DlcserviceClient::Observer,
+      public VideoConferenceTrayEffectsManager::Observer {
  public:
   explicit VcTileUiController(const VcHostedEffect* effect);
   VcTileUiController(const VcTileUiController&) = delete;
@@ -88,6 +91,9 @@
   // DlcserviceClient::Observer:
   void OnDlcStateChanged(const dlcservice::DlcState& dlc_state) override;
 
+  // VideoConferenceTrayEffectsManager::Observer:
+  void OnEffectChanged(VcEffectId effect_id, bool is_on) override;
+
   // Called when the `FeatureTile` associated with this controller is pressed.
   void OnPressed(const ui::Event& event);
 
diff --git a/ash/system/video_conference/effects/video_conference_tray_effects_delegate.cc b/ash/system/video_conference/effects/video_conference_tray_effects_delegate.cc
index 4d47c1e..fdecb30 100644
--- a/ash/system/video_conference/effects/video_conference_tray_effects_delegate.cc
+++ b/ash/system/video_conference/effects/video_conference_tray_effects_delegate.cc
@@ -5,6 +5,8 @@
 #include "ash/system/video_conference/effects/video_conference_tray_effects_delegate.h"
 
 #include "ash/constants/ash_features.h"
+#include "ash/shell.h"
+#include "ash/system/camera/camera_effects_controller.h"
 #include "ash/system/video_conference/effects/video_conference_tray_effects_manager_types.h"
 #include "ash/system/video_conference/video_conference_tray_controller.h"
 #include "ash/system/video_conference/video_conference_utils.h"
@@ -110,10 +112,25 @@
           video_conference_utils::GetEffectHistogramNameForInitialState(
               effect_id),
           current_state.value());
+      if (effect_id == VcEffectId::kStudioLook) {
+        // Records initial preference states associated with Stduio Look effect.
+        raw_ptr<CameraEffectsController> effects_controller_ =
+            Shell::Get()->camera_effects_controller();
+        base::UmaHistogramBoolean(
+            video_conference_utils::GetEffectHistogramNameForInitialState(
+                VcEffectId::kPortraitRelighting),
+            *effects_controller_->GetEffectState(
+                VcEffectId::kPortraitRelighting) != 0);
+        base::UmaHistogramBoolean(
+            video_conference_utils::GetEffectHistogramNameForInitialState(
+                VcEffectId::kFaceRetouch),
+            *effects_controller_->GetEffectState(VcEffectId::kFaceRetouch) !=
+                0);
+      }
     } else {
       RecordMetricsForSetValueEffectOnStartup(effect_id, current_state.value());
     }
   }
 }
 
-}  // namespace ash
\ No newline at end of file
+}  // namespace ash
diff --git a/ash/system/video_conference/effects/video_conference_tray_effects_manager.cc b/ash/system/video_conference/effects/video_conference_tray_effects_manager.cc
index 1da7cfca..86d87c2 100644
--- a/ash/system/video_conference/effects/video_conference_tray_effects_manager.cc
+++ b/ash/system/video_conference/effects/video_conference_tray_effects_manager.cc
@@ -151,6 +151,14 @@
   }
 }
 
+void VideoConferenceTrayEffectsManager::NotifyEffectChanged(
+    VcEffectId effect_id,
+    bool is_on) {
+  for (auto& observer : observers_) {
+    observer.OnEffectChanged(effect_id, is_on);
+  }
+}
+
 void VideoConferenceTrayEffectsManager::RecordInitialStates() {
   for (ash::VcEffectsDelegate* delegate : effect_delegates_) {
     delegate->RecordInitialStates();
diff --git a/ash/system/video_conference/effects/video_conference_tray_effects_manager.h b/ash/system/video_conference/effects/video_conference_tray_effects_manager.h
index b9d725b2..69633b6 100644
--- a/ash/system/video_conference/effects/video_conference_tray_effects_manager.h
+++ b/ash/system/video_conference/effects/video_conference_tray_effects_manager.h
@@ -42,7 +42,11 @@
    public:
     // Called when an affect has change its support state.
     virtual void OnEffectSupportStateChanged(VcEffectId effect_id,
-                                             bool is_supported) = 0;
+                                             bool is_supported) {}
+
+    // Called when an effect changes. Currently, only observes
+    // `kStudioLook` effect.
+    virtual void OnEffectChanged(VcEffectId effect_id, bool is_on) {}
   };
 
   // Adds/removes `VideoConferenceTrayEffectsManager::Observer`.
@@ -92,6 +96,9 @@
   // Notifies all observers about effect support state changed.
   void NotifyEffectSupportStateChanged(VcEffectId effect_id, bool is_supported);
 
+  // Notifies all observers about effect state changed.
+  void NotifyEffectChanged(VcEffectId effect_id, bool is_on);
+
   // Records the current state of all effects to metrics.
   void RecordInitialStates();
 
diff --git a/ash/webui/personalization_app/mojom/personalization_app.mojom b/ash/webui/personalization_app/mojom/personalization_app.mojom
index 1dbae8f..5d78995c 100644
--- a/ash/webui/personalization_app/mojom/personalization_app.mojom
+++ b/ash/webui/personalization_app/mojom/personalization_app.mojom
@@ -671,7 +671,8 @@
   // Notifies the JS side about the system geolocation permission change.
   // TODO(b/319443587): Refactor out the Geolocation interfaces from Ambient*
   // and Theme* intefaces.
-  OnGeolocationPermissionForSystemServicesChanged(bool enabled);
+  OnGeolocationPermissionForSystemServicesChanged(bool enabled,
+                                                  bool is_user_modifiable);
 };
 
 // Provides APIs to expose Ambient mode settings.
@@ -726,6 +727,10 @@
   // services.
   IsGeolocationEnabledForSystemServices() => (bool geolocation_enabled);
 
+  // Returns if the geolocation setting can be changed by the user.
+  // E.g. admins can force the value through a policy.
+  IsGeolocationUserModifiable() => (bool geolocation_is_user_modifiable);
+
   // Sets the system geolocation permission to "Only allowed for system".
   EnableGeolocationForSystemServices();
 };
diff --git a/ash/webui/personalization_app/personalization_app_ui.cc b/ash/webui/personalization_app/personalization_app_ui.cc
index 926820b..9406a2c 100644
--- a/ash/webui/personalization_app/personalization_app_ui.cc
+++ b/ash/webui/personalization_app/personalization_app_ui.cc
@@ -167,6 +167,8 @@
        IDS_PERSONALIZATION_APP_ERROR_TOOLTIP_AUTO_COLOR_MODE},
       {"geolocationWarningTextForWeather",
        IDS_PERSONALIZATION_APP_THEME_GEOLOCATION_WARNING_TEXT_FOR_WEATHER},
+      {"geolocationWarningManagedTextForWeather",
+       IDS_PERSONALIZATION_APP_THEME_GEOLOCATION_WARNING_MANAGED_TEXT_FOR_WEATHER},
       {"autoModeGeolocationDialogText",
        IDS_PERSONALIZATION_APP_THEME_GEOLOCATION_DIALOG_BODY},
       {"autoModeGeolocationDialogConfirmButton",
diff --git a/ash/webui/personalization_app/resources/js/ambient/ambient_actions.ts b/ash/webui/personalization_app/resources/js/ambient/ambient_actions.ts
index d6120175..847cc79c 100644
--- a/ash/webui/personalization_app/resources/js/ambient/ambient_actions.ts
+++ b/ash/webui/personalization_app/resources/js/ambient/ambient_actions.ts
@@ -23,13 +23,14 @@
   SET_AMBIENT_UI_VISIBILITY = 'set_ambient_ui_visibility',
   SET_SHOULD_SHOW_TIME_OF_DAY_BANNER = 'set_should_show_time_of_day_banner',
   SET_GEOLOCATION_PERMISSION_ENABLED = 'set_geolocation_permission_enabled',
+  SET_GEOLOCATION_IS_USER_MODIFIABLE = 'set_geolocation_is_user_modifiable',
 }
 
-export type AmbientActions =
-    SetAlbumsAction|SetAlbumSelectedAction|SetAmbientModeEnabledAction|
-    SetAmbientThemeAction|SetPreviewsAction|SetScreenSaverDurationAction|
-    SetTopicSourceAction|SetTemperatureUnitAction|SetAmbientUiVisibilityAction|
-    SetShouldShowTimeOfDayBannerAction|SetGeolocationPermissionEnabledAction;
+export type AmbientActions = SetAlbumsAction|SetAlbumSelectedAction|
+    SetAmbientModeEnabledAction|SetAmbientThemeAction|SetPreviewsAction|
+    SetScreenSaverDurationAction|SetTopicSourceAction|SetTemperatureUnitAction|
+    SetAmbientUiVisibilityAction|SetShouldShowTimeOfDayBannerAction|
+    SetGeolocationPermissionEnabledAction|SetGeolocationIsUserModifiableAction;
 
 export interface SetAlbumsAction extends Action {
   name: AmbientActionName.SET_ALBUMS;
@@ -94,6 +95,11 @@
   enabled: boolean;
 }
 
+export interface SetGeolocationIsUserModifiableAction extends Action {
+  name: AmbientActionName.SET_GEOLOCATION_IS_USER_MODIFIABLE;
+  isUserModifiable: boolean;
+}
+
 
 /**
  * Sets the current value of the albums.
@@ -179,3 +185,11 @@
     SetGeolocationPermissionEnabledAction {
   return {name: AmbientActionName.SET_GEOLOCATION_PERMISSION_ENABLED, enabled};
 }
+
+export function setGeolocationIsUserModifiableAction(isUserModifiable: boolean):
+    SetGeolocationIsUserModifiableAction {
+  return {
+    name: AmbientActionName.SET_GEOLOCATION_IS_USER_MODIFIABLE,
+    isUserModifiable,
+  };
+}
diff --git a/ash/webui/personalization_app/resources/js/ambient/ambient_controller.ts b/ash/webui/personalization_app/resources/js/ambient/ambient_controller.ts
index b4ddc53e..e1583069 100644
--- a/ash/webui/personalization_app/resources/js/ambient/ambient_controller.ts
+++ b/ash/webui/personalization_app/resources/js/ambient/ambient_controller.ts
@@ -7,7 +7,7 @@
 import {AmbientModeAlbum, AmbientProviderInterface, AmbientTheme, TemperatureUnit, TopicSource} from '../../personalization_app.mojom-webui.js';
 import {PersonalizationStore} from '../personalization_store.js';
 
-import {setAlbumSelectedAction, setAmbientModeEnabledAction, setAmbientThemeAction, setGeolocationPermissionEnabledAction, setScreenSaverDurationAction, setShouldShowTimeOfDayBannerAction, setTemperatureUnitAction, setTopicSourceAction} from './ambient_actions.js';
+import {setAlbumSelectedAction, setAmbientModeEnabledAction, setAmbientThemeAction, setGeolocationIsUserModifiableAction, setGeolocationPermissionEnabledAction, setScreenSaverDurationAction, setShouldShowTimeOfDayBannerAction, setTemperatureUnitAction, setTopicSourceAction} from './ambient_actions.js';
 import {getAmbientProvider} from './ambient_interface_provider.js';
 import {isValidTopicSourceAndTheme} from './utils.js';
 
@@ -22,9 +22,16 @@
 export async function initializeData(
     provider: AmbientProviderInterface,
     store: PersonalizationStore): Promise<void> {
-  const {geolocationEnabled} =
-      await provider.isGeolocationEnabledForSystemServices();
+  const [{geolocationEnabled}, {geolocationIsUserModifiable}] =
+      await Promise.all([
+        provider.isGeolocationEnabledForSystemServices(),
+        provider.isGeolocationUserModifiable(),
+      ]);
+  store.beginBatchUpdate();
   store.dispatch(setGeolocationPermissionEnabledAction(geolocationEnabled));
+  store.dispatch(
+      setGeolocationIsUserModifiableAction(geolocationIsUserModifiable));
+  store.endBatchUpdate();
 }
 
 // Enable or disable ambient mode.
diff --git a/ash/webui/personalization_app/resources/js/ambient/ambient_observer.ts b/ash/webui/personalization_app/resources/js/ambient/ambient_observer.ts
index 2b3dff6..36db6bb 100644
--- a/ash/webui/personalization_app/resources/js/ambient/ambient_observer.ts
+++ b/ash/webui/personalization_app/resources/js/ambient/ambient_observer.ts
@@ -12,7 +12,7 @@
 import {PersonalizationStore} from '../personalization_store.js';
 import {isRecentHighlightsAlbum} from '../utils.js';
 
-import {setAlbumsAction, setAmbientModeEnabledAction, setAmbientThemeAction, setAmbientUiVisibilityAction, setGeolocationPermissionEnabledAction, setPreviewsAction, setScreenSaverDurationAction, setTemperatureUnitAction, setTopicSourceAction} from './ambient_actions.js';
+import {setAlbumsAction, setAmbientModeEnabledAction, setAmbientThemeAction, setAmbientUiVisibilityAction, setGeolocationIsUserModifiableAction, setGeolocationPermissionEnabledAction, setPreviewsAction, setScreenSaverDurationAction, setTemperatureUnitAction, setTopicSourceAction} from './ambient_actions.js';
 import {getAmbientProvider} from './ambient_interface_provider.js';
 
 /** @fileoverview listens for updates on ambient mode changes. */
@@ -135,8 +135,12 @@
     store.dispatch(setAmbientUiVisibilityAction(ambientUiVisibility));
   }
 
-  onGeolocationPermissionForSystemServicesChanged(enabled: boolean): void {
+  onGeolocationPermissionForSystemServicesChanged(
+      enabled: boolean, isUserModifiable: boolean): void {
     const store = PersonalizationStore.getInstance();
+    store.beginBatchUpdate();
     store.dispatch(setGeolocationPermissionEnabledAction(enabled));
+    store.dispatch(setGeolocationIsUserModifiableAction(isUserModifiable));
+    store.endBatchUpdate();
   }
 }
diff --git a/ash/webui/personalization_app/resources/js/ambient/ambient_reducers.ts b/ash/webui/personalization_app/resources/js/ambient/ambient_reducers.ts
index a97fbdb5..38782ba 100644
--- a/ash/webui/personalization_app/resources/js/ambient/ambient_reducers.ts
+++ b/ash/webui/personalization_app/resources/js/ambient/ambient_reducers.ts
@@ -125,6 +125,17 @@
   }
 }
 
+export function geolocationIsUserModifiableReducer(
+    state: AmbientState['geolocationIsUserModifiable'], action: Actions,
+    _: PersonalizationState): AmbientState['geolocationIsUserModifiable'] {
+  switch (action.name) {
+    case AmbientActionName.SET_GEOLOCATION_IS_USER_MODIFIABLE:
+      return action.isUserModifiable;
+    default:
+      return state;
+  }
+}
+
 
 export const ambientReducers:
     {[K in keyof AmbientState]: ReducerFunction<AmbientState[K]>} = {
@@ -138,4 +149,5 @@
       ambientUiVisibility: ambientUiVisibilityReducer,
       shouldShowTimeOfDayBanner: shouldShowTimeOfDayBannerReducer,
       geolocationPermissionEnabled: geolocationPermissionEnabledReducer,
+      geolocationIsUserModifiable: geolocationIsUserModifiableReducer,
     };
diff --git a/ash/webui/personalization_app/resources/js/ambient/ambient_state.ts b/ash/webui/personalization_app/resources/js/ambient/ambient_state.ts
index a1acf68..06fcb8e 100644
--- a/ash/webui/personalization_app/resources/js/ambient/ambient_state.ts
+++ b/ash/webui/personalization_app/resources/js/ambient/ambient_state.ts
@@ -21,6 +21,7 @@
   ambientUiVisibility: AmbientUiVisibility|null;
   shouldShowTimeOfDayBanner: boolean;
   geolocationPermissionEnabled: boolean|null;
+  geolocationIsUserModifiable: boolean|null;
 }
 
 export function emptyState(): AmbientState {
@@ -35,5 +36,6 @@
     ambientUiVisibility: null,
     shouldShowTimeOfDayBanner: false,
     geolocationPermissionEnabled: null,
+    geolocationIsUserModifiable: null,
   };
 }
diff --git a/ash/webui/personalization_app/resources/js/ambient/ambient_weather_element.html b/ash/webui/personalization_app/resources/js/ambient/ambient_weather_element.html
index 8f51bd23..198d431 100644
--- a/ash/webui/personalization_app/resources/js/ambient/ambient_weather_element.html
+++ b/ash/webui/personalization_app/resources/js/ambient/ambient_weather_element.html
@@ -17,6 +17,11 @@
     width: inherit;
     margin: 0 10px;
   }
+
+  #policyIcon {
+    margin-inline-start: auto;
+    margin-inline-end: 10px;
+  }
 </style>
 <div id="weatherDiv">
   <h3 id="weatherTitle" class="ambient-subpage-element-title">
@@ -24,10 +29,20 @@
   </h3>
   <template is="dom-if" if="[[shouldShowGeolocationWarningText_]]" restamp>
     <div id="geolocationWarningDiv">
-      <localized-link
-          on-link-clicked="openGeolocationDialog_"
-          localized-string="$i18n{geolocationWarningTextForWeather}">
-      </localized-link>
+      <template is="dom-if" if="[[geolocationIsUserModifiable_]]" restamp>
+        <localized-link
+            on-link-clicked="openGeolocationDialog_"
+            localized-string="$i18n{geolocationWarningTextForWeather}">
+        </localized-link>
+      </template>
+      <template is="dom-if" if="[[!geolocationIsUserModifiable_]]" restamp>
+        $i18n{geolocationWarningManagedTextForWeather}
+        <cr-policy-indicator
+            id="policyIcon"
+            indicator-type="userPolicy"
+            title="$i18n{managedSetting}">
+        </cr-policy-indicator>
+      </template>
     </div>
   </template>
   <template is="dom-if" if="[[!shouldShowGeolocationWarningText_]]" restamp>
diff --git a/ash/webui/personalization_app/resources/js/ambient/ambient_weather_element.ts b/ash/webui/personalization_app/resources/js/ambient/ambient_weather_element.ts
index 5cd48e72..0c123d80 100644
--- a/ash/webui/personalization_app/resources/js/ambient/ambient_weather_element.ts
+++ b/ash/webui/personalization_app/resources/js/ambient/ambient_weather_element.ts
@@ -10,6 +10,7 @@
 import 'chrome://resources/ash/common/personalization/common.css.js';
 import 'chrome://resources/ash/common/cr_elements/cr_radio_button/cr_radio_button.js';
 import 'chrome://resources/ash/common/cr_elements/cr_radio_group/cr_radio_group.js';
+import 'chrome://resources/ash/common/cr_elements/policy/cr_policy_indicator.js';
 import 'chrome://resources/ash/common/cr_elements/cr_shared_style.css.js';
 import 'chrome://resources/ash/common/cr_elements/localized_link/localized_link.js';
 import '../geolocation_dialog.js';
@@ -53,6 +54,11 @@
         value: null,
       },
 
+      geolocationIsUserModifiable_: {
+        type: Boolean,
+        value: null,
+      },
+
       shouldShowGeolocationWarningText_: {
         type: Boolean,
         computed: 'computeShouldShowGeolocationWarningText_(' +
@@ -65,6 +71,7 @@
   private temperatureUnit_: TemperatureUnit;
   private selectedTemperatureUnit: string;
   private geolocationPermissionEnabled_: boolean|null;
+  private geolocationIsUserModifiable_: boolean|null;
   private shouldShowGeolocationDialog_: boolean;
   private shouldShowGeolocationWarningText_: boolean;
 
@@ -75,6 +82,9 @@
     this.watch<AmbientWeatherUnitElement['geolocationPermissionEnabled_']>(
         'geolocationPermissionEnabled_',
         state => state.ambient.geolocationPermissionEnabled);
+    this.watch<AmbientWeatherUnitElement['geolocationIsUserModifiable_']>(
+        'geolocationIsUserModifiable_',
+        state => state.ambient.geolocationIsUserModifiable);
     this.updateFromStore();
 
     initializeData(getAmbientProvider(), this.getStore());
diff --git a/ash/webui/personalization_app/test/fake_personalization_app_ambient_provider.cc b/ash/webui/personalization_app/test/fake_personalization_app_ambient_provider.cc
index 8c78224..3d0602f9 100644
--- a/ash/webui/personalization_app/test/fake_personalization_app_ambient_provider.cc
+++ b/ash/webui/personalization_app/test/fake_personalization_app_ambient_provider.cc
@@ -39,6 +39,11 @@
   std::move(callback).Run(geolocation_enabled_for_system);
 }
 
+void FakePersonalizationAppAmbientProvider::IsGeolocationUserModifiable(
+    IsGeolocationUserModifiableCallback callback) {
+  std::move(callback).Run(is_geolocation_user_modifiable);
+}
+
 void FakePersonalizationAppAmbientProvider::
     EnableGeolocationForSystemServices() {
   geolocation_enabled_for_system = true;
diff --git a/ash/webui/personalization_app/test/fake_personalization_app_ambient_provider.h b/ash/webui/personalization_app/test/fake_personalization_app_ambient_provider.h
index 82664b7..e186385 100644
--- a/ash/webui/personalization_app/test/fake_personalization_app_ambient_provider.h
+++ b/ash/webui/personalization_app/test/fake_personalization_app_ambient_provider.h
@@ -59,10 +59,13 @@
   void HandleTimeOfDayBannerDismissed() override {}
   void IsGeolocationEnabledForSystemServices(
       IsGeolocationEnabledForSystemServicesCallback callback) override;
+  void IsGeolocationUserModifiable(
+      IsGeolocationUserModifiableCallback callback) override;
   void EnableGeolocationForSystemServices() override;
 
  private:
   bool geolocation_enabled_for_system = true;
+  bool is_geolocation_user_modifiable = true;
   mojo::Receiver<ash::personalization_app::mojom::AmbientProvider>
       ambient_receiver_{this};
 };
diff --git a/ash/webui/personalization_app/test/personalization_app_mojom_banned_mocha_test_base.cc b/ash/webui/personalization_app/test/personalization_app_mojom_banned_mocha_test_base.cc
index 6dd44349..5851e98f 100644
--- a/ash/webui/personalization_app/test/personalization_app_mojom_banned_mocha_test_base.cc
+++ b/ash/webui/personalization_app/test/personalization_app_mojom_banned_mocha_test_base.cc
@@ -74,6 +74,10 @@
               IsGeolocationEnabledForSystemServices,
               (IsGeolocationEnabledForSystemServicesCallback callback),
               (override));
+  MOCK_METHOD(void,
+              IsGeolocationUserModifiable,
+              (IsGeolocationUserModifiableCallback callback),
+              (override));
 };
 
 class MockPersonalizationAppKeyboardBacklightProvider
diff --git a/ash/webui/recorder_app_ui/resources.h b/ash/webui/recorder_app_ui/resources.h
index 53b0172df..0e0a9622 100644
--- a/ash/webui/recorder_app_ui/resources.h
+++ b/ash/webui/recorder_app_ui/resources.h
@@ -11,6 +11,7 @@
 namespace ash {
 
 const webui::LocalizedString kLocalizedStrings[] = {
+    {"backToMainButtonAriaLabel", IDS_RECORDER_BACK_TO_MAIN_BUTTON_ARIA_LABEL},
     {"backToMainButtonTooltip", IDS_RECORDER_BACK_TO_MAIN_BUTTON_TOOLTIP},
     {"closeDialogButtonTooltip", IDS_RECORDER_CLOSE_DIALOG_BUTTON_TOOLTIP},
     {"exportDialogAudioFormatWebmOption",
@@ -29,6 +30,8 @@
      IDS_RECORDER_GEN_AI_ERROR_SUMMARY_TRUST_AND_SAFETY_LABEL},
     {"genAiErrorTitleSuggestionTrustAndSafetyLabel",
      IDS_RECORDER_GEN_AI_ERROR_TITLE_SUGGESTION_TRUST_AND_SAFETY_LABEL},
+    {"genAiErrorTranscriptionTooShortLabel",
+     IDS_RECORDER_GEN_AI_ERROR_TRANSCRIPTION_TOO_SHORT_LABEL},
     {"genAiExperimentBadge", IDS_RECORDER_GEN_AI_EXPERIMENT_BADGE},
     {"genAiLearnMoreLink", IDS_RECORDER_GEN_AI_LEARN_MORE_LINK},
     {"genaiNegativeFeedbackButtonTooltip",
@@ -155,12 +158,22 @@
      IDS_RECORDER_RECORD_TRANSCRIPTION_OFF_DESCRIPTION},
     {"recordTranscriptionOffHeader",
      IDS_RECORDER_RECORD_TRANSCRIPTION_OFF_HEADER},
+    {"recordingItemOptionsButtonAriaLabel",
+     IDS_RECORDER_RECORDING_ITEM_OPTIONS_BUTTON_ARIA_LABEL},
     {"recordingItemOptionsButtonTooltip",
      IDS_RECORDER_RECORDING_ITEM_OPTIONS_BUTTON_TOOLTIP},
+    {"recordingItemPauseButtonAriaLabel",
+     IDS_RECORDER_RECORDING_ITEM_PAUSE_BUTTON_ARIA_LABEL},
+    {"recordingItemPlayButtonAriaLabel",
+     IDS_RECORDER_RECORDING_ITEM_PLAY_BUTTON_ARIA_LABEL},
     {"recordingItemPlayButtonTooltip",
      IDS_RECORDER_RECORDING_ITEM_PLAY_BUTTON_TOOLTIP},
     {"recordingListHeader", IDS_RECORDER_RECORDING_LIST_HEADER},
     {"recordingListNoMatchText", IDS_RECORDER_RECORDING_LIST_NO_MATCH_TEXT},
+    {"recordingListSearchBoxClearButtonAriaLabel",
+     IDS_RECORDER_RECORDING_LIST_SEARCH_BOX_CLEAR_BUTTON_ARIA_LABEL},
+    {"recordingListSearchBoxCloseButtonAriaLabel",
+     IDS_RECORDER_RECORDING_LIST_SEARCH_BOX_CLOSE_BUTTON_ARIA_LABEL},
     {"recordingListSearchBoxPlaceholder",
      IDS_RECORDER_RECORDING_LIST_SEARCH_BOX_PLACEHOLDER},
     {"recordingListSearchButtonTooltip",
@@ -226,6 +239,7 @@
     {"titleSuggestionButtonTooltip",
      IDS_RECORDER_TITLE_SUGGESTION_BUTTON_TOOLTIP},
     {"titleSuggestionHeader", IDS_RECORDER_TITLE_SUGGESTION_HEADER},
+    {"titleTextfieldAriaLabel", IDS_RECORDER_TITLE_TEXTFIELD_ARIA_LABEL},
     {"transcriptionAutoscrollButton",
      IDS_RECORDER_TRANSCRIPTION_AUTOSCROLL_BUTTON},
     {"transcriptionNoSpeechText", IDS_RECORDER_TRANSCRIPTION_NO_SPEECH_TEXT},
diff --git a/ash/webui/recorder_app_ui/resources/components/genai-error.ts b/ash/webui/recorder_app_ui/resources/components/genai-error.ts
index c3d63a4..6d36707 100644
--- a/ash/webui/recorder_app_ui/resources/components/genai-error.ts
+++ b/ash/webui/recorder_app_ui/resources/components/genai-error.ts
@@ -13,6 +13,7 @@
 } from 'chrome://resources/mwc/lit/index.js';
 
 import {i18n} from '../core/i18n.js';
+import {MIN_WORD_LENGTH} from '../core/on_device_model/ai_feature_constants.js';
 import {ModelResponseError} from '../core/on_device_model/types.js';
 import {ReactiveLitElement} from '../core/reactive/lit.js';
 import {assertExhaustive, assertExists} from '../core/utils/assert.js';
@@ -26,6 +27,7 @@
   static override styles: CSSResultGroup = css`
     :host {
       align-items: center;
+      text-align: center;
       display: flex;
       flex-flow: column;
       font: var(--cros-button-1-font);
@@ -54,6 +56,13 @@
         imageName = 'genai_error_general';
         message = i18n.genAiErrorGeneralLabel;
         break;
+
+      case ModelResponseError.UNSUPPORTED_TRANSCRIPTION_IS_TOO_SHORT: {
+        imageName = 'genai_error_general';
+        message = i18n.genAiErrorTranscriptionTooShortLabel(MIN_WORD_LENGTH);
+        break;
+      }
+
       case ModelResponseError.UNSAFE: {
         imageName = 'genai_error_unsafe';
         const resultType = assertExists(this.resultType);
diff --git a/ash/webui/recorder_app_ui/resources/components/recording-file-list-item.ts b/ash/webui/recorder_app_ui/resources/components/recording-file-list-item.ts
index dc05e101..5739ebf 100644
--- a/ash/webui/recorder_app_ui/resources/components/recording-file-list-item.ts
+++ b/ash/webui/recorder_app_ui/resources/components/recording-file-list-item.ts
@@ -406,6 +406,10 @@
       '--progress':
         this.playProgress === null ? null : clamp(this.playProgress, 0, 100),
     };
+    const title = assertExists(this.recording?.title);
+    const ariaLabel = this.playing ?
+      i18n.recordingItemPauseButtonAriaLabel(title) :
+      i18n.recordingItemPlayButtonAriaLabel(title);
 
     return html`
       <cra-icon-button
@@ -414,7 +418,7 @@
         shape="circle"
         @click=${this.onPlayClick}
         @pointerdown=${/* To prevent ripple on card. */ stopPropagation}
-        aria-label=${i18n.recordingItemPlayButtonTooltip}
+        aria-label=${ariaLabel}
       >
         <cra-icon slot="icon" .name=${playIcon}></cra-icon>
       </cra-icon-button>
@@ -429,6 +433,7 @@
     const classes = {
       'menu-shown': this.menuShown.value,
     };
+    const title = this.recording.title;
 
     // TODO(pihsun): Check why the ripple sometimes doesn't happen on touch
     // long-press but sometimes does.
@@ -446,7 +451,7 @@
           >
             ${this.renderPlayButton()}
             <div id="recording-info">
-              ${this.renderTitle(this.recording.title, this.searchHighlight)}
+              ${this.renderTitle(title, this.searchHighlight)}
               ${this.renderDescription(this.recording.description)}
               ${this.renderRecordingTimeline(this.recording)}
             </div>
@@ -455,7 +460,7 @@
             buttonstyle="floating"
             id="options"
             @click=${this.onOptionsClick}
-            aria-label=${i18n.recordingItemOptionsButtonTooltip}
+            aria-label=${i18n.recordingItemOptionsButtonAriaLabel(title)}
           >
             <cra-icon slot="icon" name="more_vertical"></cra-icon>
           </cra-icon-button>
diff --git a/ash/webui/recorder_app_ui/resources/components/recording-info-dialog.ts b/ash/webui/recorder_app_ui/resources/components/recording-info-dialog.ts
index 7f71882..3542f69 100644
--- a/ash/webui/recorder_app_ui/resources/components/recording-info-dialog.ts
+++ b/ash/webui/recorder_app_ui/resources/components/recording-info-dialog.ts
@@ -198,6 +198,7 @@
           size="small"
           shape="circle"
           @click=${this.hide}
+          aria-label=${i18n.closeDialogButtonTooltip}
         >
           <cra-icon slot="icon" name="close"></cra-icon>
         </cra-icon-button>
diff --git a/ash/webui/recorder_app_ui/resources/components/recording-search-box.ts b/ash/webui/recorder_app_ui/resources/components/recording-search-box.ts
index c0c19a7..04e1dac9 100644
--- a/ash/webui/recorder_app_ui/resources/components/recording-search-box.ts
+++ b/ash/webui/recorder_app_ui/resources/components/recording-search-box.ts
@@ -174,6 +174,7 @@
           slot="trailing"
           shape="circle"
           @click=${this.closeSearchBox}
+          aria-label=${i18n.recordingListSearchBoxClearButtonAriaLabel}
         >
           <cra-icon slot="icon" name="remove_fill"></cra-icon>
         </cra-icon-button>`;
@@ -200,6 +201,7 @@
         size="small"
         slot="leading"
         @click=${this.closeSearchBox}
+        aria-label=${i18n.recordingListSearchBoxCloseButtonAriaLabel}
       >
         <cra-icon slot="icon" name="search"></cra-icon>
       </cra-icon-button>
diff --git a/ash/webui/recorder_app_ui/resources/components/recording-title-suggestion.ts b/ash/webui/recorder_app_ui/resources/components/recording-title-suggestion.ts
index 9218efd..31ab72e 100644
--- a/ash/webui/recorder_app_ui/resources/components/recording-title-suggestion.ts
+++ b/ash/webui/recorder_app_ui/resources/components/recording-title-suggestion.ts
@@ -15,6 +15,7 @@
   css,
   html,
   map,
+  nothing,
   PropertyDeclarations,
 } from 'chrome://resources/mwc/lit/index.js';
 
@@ -47,20 +48,17 @@
       /* To have the border-radius applied to content. */
       overflow: hidden;
       z-index: 30;
+
+      & > cra-icon-button {
+        position: absolute;
+        top: 4px;
+        right: 4px;
+      }
     }
 
     #header {
-      align-items: flex-end;
-      display: flex;
-      flex-flow: row;
       font: var(--cros-title-1-font);
-      justify-content: space-between;
-      padding: 4px 4px 0 16px;
-      position: relative;
-
-      & > cra-icon-button {
-        margin: 0;
-      }
+      padding: 16px 8px 0 16px;
     }
 
     #loading {
@@ -203,20 +201,29 @@
     }
   }
 
+  private renderHeader(): RenderResult {
+    if (this.suggestedTitles?.value?.kind === 'error') {
+      return nothing;
+    }
+    return html`
+    <div id="header">
+      ${i18n.titleSuggestionHeader}
+    </div>
+    `;
+  }
+
   override render(): RenderResult {
     return html`
-      <div id="header">
-        <span>${i18n.titleSuggestionHeader}</span>
-        <cra-icon-button
-          buttonstyle="floating"
-          size="small"
-          shape="circle"
-          @click=${this.onCloseClick}
-          aria-label=${i18n.closeDialogButtonTooltip}
-        >
-          <cra-icon slot="icon" name="close"></cra-icon>
-        </cra-icon-button>
-      </div>
+      ${this.renderHeader()}
+      <cra-icon-button
+        buttonstyle="floating"
+        size="small"
+        shape="circle"
+        @click=${this.onCloseClick}
+        aria-label=${i18n.closeDialogButtonTooltip}
+      >
+        <cra-icon slot="icon" name="close"></cra-icon>
+      </cra-icon-button>
       ${this.renderContent()}
     `;
   }
diff --git a/ash/webui/recorder_app_ui/resources/components/recording-title.ts b/ash/webui/recorder_app_ui/resources/components/recording-title.ts
index 9b41577..0d426d0 100644
--- a/ash/webui/recorder_app_ui/resources/components/recording-title.ts
+++ b/ash/webui/recorder_app_ui/resources/components/recording-title.ts
@@ -126,13 +126,15 @@
     return assertExists(this.recordingTitleSuggestion.value);
   }
 
+  private readonly recordingId = computed(() => {
+    return this.recordingMetadataSignal.value?.id ?? null;
+  });
+
   private readonly transcription = new ScopedAsyncComputed(this, async () => {
-    if (this.recordingMetadataSignal.value === null) {
+    if (this.recordingId.value === null) {
       return null;
     }
-    return this.recordingDataManager.getTranscription(
-      this.recordingMetadataSignal.value.id,
-    );
+    return this.recordingDataManager.getTranscription(this.recordingId.value);
   });
 
   private readonly shouldShowTitleSuggestion = computed(() => {
@@ -147,13 +149,13 @@
   private readonly suggestedTitles = new ScopedAsyncComputed(this, async () => {
     // TODO(pihsun): Cache title suggestion between hide/show the suggestion
     // dialog?
-    if (!this.suggestionShown.value || this.recordingMetadata === null ||
-        !this.shouldShowTitleSuggestion.value) {
+    if (!this.suggestionShown.value || !this.shouldShowTitleSuggestion.value) {
       return null;
     }
     if (this.transcription.value === null) {
       return null;
     }
+
     // TODO(pihsun): Have a specific format for transcription to be used as
     // model input.
     const text = this.transcription.value.toPlainText();
@@ -276,6 +278,7 @@
           .value=${this.recordingMetadata?.title ?? ''}
           @change=${this.onChangeTitle}
           @focusout=${this.onFocusout}
+          aria-label=${i18n.titleTextfieldAriaLabel}
         >
           ${suggestionIconButton}
         </cros-textfield>
diff --git a/ash/webui/recorder_app_ui/resources/components/summarization-view.ts b/ash/webui/recorder_app_ui/resources/components/summarization-view.ts
index d3a5c87..422eea0 100644
--- a/ash/webui/recorder_app_ui/resources/components/summarization-view.ts
+++ b/ash/webui/recorder_app_ui/resources/components/summarization-view.ts
@@ -24,7 +24,9 @@
 
 import {i18n} from '../core/i18n.js';
 import {usePlatformHandler} from '../core/lit/context.js';
-import {ModelResponse} from '../core/on_device_model/types.js';
+import {
+  ModelResponse,
+} from '../core/on_device_model/types.js';
 import {ReactiveLitElement} from '../core/reactive/lit.js';
 import {signal} from '../core/reactive/signal.js';
 import {Transcription} from '../core/soda/soda.js';
@@ -200,6 +202,7 @@
   private async requestSummary() {
     this.summaryRequested.value = true;
     this.summaryOpened.value = true;
+
     const text = this.transcription?.toPlainText() ?? '';
     const model = await this.platformHandler.summaryModelLoader.load();
     try {
diff --git a/ash/webui/recorder_app_ui/resources/core/core.gni b/ash/webui/recorder_app_ui/resources/core/core.gni
index bf3ea482..6c1e070 100644
--- a/ash/webui/recorder_app_ui/resources/core/core.gni
+++ b/ash/webui/recorder_app_ui/resources/core/core.gni
@@ -11,6 +11,7 @@
   "lit/context.ts",
   "microphone_manager.ts",
   "on_device_model/types.ts",
+  "on_device_model/ai_feature_constants.ts",
   "platform_handler.ts",
   "reactive/lit.ts",
   "reactive/local_storage.ts",
diff --git a/ash/webui/recorder_app_ui/resources/core/i18n.ts b/ash/webui/recorder_app_ui/resources/core/i18n.ts
index cd09233..e47d2da 100644
--- a/ash/webui/recorder_app_ui/resources/core/i18n.ts
+++ b/ash/webui/recorder_app_ui/resources/core/i18n.ts
@@ -19,6 +19,7 @@
 }
 
 const noArgStringNames = [
+  'backToMainButtonAriaLabel',
   'backToMainButtonTooltip',
   'closeDialogButtonTooltip',
   'exportDialogAudioFormatWebmOption',
@@ -111,6 +112,8 @@
   'recordingItemPlayButtonTooltip',
   'recordingListHeader',
   'recordingListNoMatchText',
+  'recordingListSearchBoxClearButtonAriaLabel',
+  'recordingListSearchBoxCloseButtonAriaLabel',
   'recordingListSearchBoxPlaceholder',
   'recordingListSearchButtonTooltip',
   'recordingListSortButtonTooltip',
@@ -144,6 +147,7 @@
   'titleRenameTooltip',
   'titleSuggestionButtonTooltip',
   'titleSuggestionHeader',
+  'titleTextfieldAriaLabel',
   'transcriptionAutoscrollButton',
   'transcriptionNoSpeechText',
   'transcriptionSpeakerLabelPendingLabel',
@@ -157,6 +161,10 @@
   // Usage example:
   // Add `fooBar: withArgs<[number, string]>(),` here,
   // then `i18n.fooBar(1, '2')` works.
+  genAiErrorTranscriptionTooShortLabel: withArgs<[number]>(),
+  recordingItemOptionsButtonAriaLabel: withArgs<[string]>(),
+  recordingItemPauseButtonAriaLabel: withArgs<[string]>(),
+  recordingItemPlayButtonAriaLabel: withArgs<[string]>(),
   settingsOptionsSummaryDownloadingProgressDescription: withArgs<[number]>(),
   settingsOptionsTranscriptionDownloadingProgressDescription:
     withArgs<[number]>(),
diff --git a/ash/webui/recorder_app_ui/resources/core/on_device_model/ai_feature_constants.ts b/ash/webui/recorder_app_ui/resources/core/on_device_model/ai_feature_constants.ts
new file mode 100644
index 0000000..ce0b23f
--- /dev/null
+++ b/ash/webui/recorder_app_ui/resources/core/on_device_model/ai_feature_constants.ts
@@ -0,0 +1,6 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// The minimum transcript word length for title generation and summarization.
+export const MIN_WORD_LENGTH = 150;
diff --git a/ash/webui/recorder_app_ui/resources/core/on_device_model/types.ts b/ash/webui/recorder_app_ui/resources/core/on_device_model/types.ts
index bbf1f073..4885a70d 100644
--- a/ash/webui/recorder_app_ui/resources/core/on_device_model/types.ts
+++ b/ash/webui/recorder_app_ui/resources/core/on_device_model/types.ts
@@ -29,6 +29,10 @@
   // General error.
   GENERAL = 'GENERAL',
 
+  // The transcription word count is less than the minimum length.
+  UNSUPPORTED_TRANSCRIPTION_IS_TOO_SHORT =
+    'UNSUPPORTED_TRANSCRIPTION_IS_TOO_SHORT',
+
   // Filtered by T&S on the request or response string.
   UNSAFE = 'UNSAFE',
 }
diff --git a/ash/webui/recorder_app_ui/resources/core/utils/utils.ts b/ash/webui/recorder_app_ui/resources/core/utils/utils.ts
index 2fa78fd9..a150907 100644
--- a/ash/webui/recorder_app_ui/resources/core/utils/utils.ts
+++ b/ash/webui/recorder_app_ui/resources/core/utils/utils.ts
@@ -57,6 +57,17 @@
 }
 
 /**
+ * Returns the number of space-delimited words in a given string.
+ *
+ * TODO(hsuanling): Apply different logic so that it can work for languages like
+ * Chinese or Japanese.
+ */
+export function getWordCount(s: string): number {
+  const words = s.match(/\S+/g);
+  return words?.length ?? 0;
+}
+
+/**
  * Shorten the given string to at most `maxWords` space-delimited words by
  * snipping the middle of string as "(...)".
  */
diff --git a/ash/webui/recorder_app_ui/resources/pages/playback-page.ts b/ash/webui/recorder_app_ui/resources/pages/playback-page.ts
index 0f98504..70275fe 100644
--- a/ash/webui/recorder_app_ui/resources/pages/playback-page.ts
+++ b/ash/webui/recorder_app_ui/resources/pages/playback-page.ts
@@ -642,7 +642,7 @@
           buttonstyle="floating"
           @click=${() => navigateTo('main')}
           ${ref(this.backButton)}
-          aria-label=${i18n.backToMainButtonTooltip}
+          aria-label=${i18n.backToMainButtonAriaLabel}
         >
           <cra-icon slot="icon" name="arrow_back"></cra-icon>
         </cra-icon-button>
diff --git a/ash/webui/recorder_app_ui/resources/pages/record-page.ts b/ash/webui/recorder_app_ui/resources/pages/record-page.ts
index b47226d..7e5b830 100644
--- a/ash/webui/recorder_app_ui/resources/pages/record-page.ts
+++ b/ash/webui/recorder_app_ui/resources/pages/record-page.ts
@@ -809,7 +809,7 @@
         <cra-icon-button
           buttonstyle="floating"
           @click=${this.onBackClick}
-          aria-label=${i18n.backToMainButtonTooltip}
+          aria-label=${i18n.backToMainButtonAriaLabel}
         >
           <cra-icon slot="icon" name="arrow_back"></cra-icon>
         </cra-icon-button>
diff --git a/ash/webui/recorder_app_ui/resources/platforms/swa/on_device_model.ts b/ash/webui/recorder_app_ui/resources/platforms/swa/on_device_model.ts
index 34e356e..aac2217 100644
--- a/ash/webui/recorder_app_ui/resources/platforms/swa/on_device_model.ts
+++ b/ash/webui/recorder_app_ui/resources/platforms/swa/on_device_model.ts
@@ -3,6 +3,9 @@
 // found in the LICENSE file.
 
 import {
+  MIN_WORD_LENGTH,
+} from '../../core/on_device_model/ai_feature_constants.js';
+import {
   Model,
   ModelLoader as ModelLoaderBase,
   ModelResponse,
@@ -15,7 +18,7 @@
   assertExists,
   assertNotReached,
 } from '../../core/utils/assert.js';
-import {shorten} from '../../core/utils/utils.js';
+import {getWordCount, shorten} from '../../core/utils/utils.js';
 
 import {
   FormatFeature,
@@ -54,6 +57,8 @@
     // TODO(pihsun): Handle disconnection error
   }
 
+  // TODO(hsuanling): Have a loadAndExecute method so that input check can be
+  // done before loading models.
   abstract execute(content: string): Promise<ModelResponse<T>>;
 
   private executeRaw(text: string): Promise<string> {
@@ -159,6 +164,12 @@
 
 export class SummaryModel extends OnDeviceModel<string> {
   override async execute(content: string): Promise<ModelResponse<string>> {
+    if (getWordCount(content) < MIN_WORD_LENGTH) {
+      return {
+        kind: 'error',
+        error: ModelResponseError.UNSUPPORTED_TRANSCRIPTION_IS_TOO_SHORT,
+      };
+    }
     content = shorten(content, MAX_CONTENT_WORDS);
     const resp = await this.formatAndExecute(
       FormatFeature.kAudioSummary,
@@ -179,6 +190,12 @@
 
 export class TitleSuggestionModel extends OnDeviceModel<string[]> {
   override async execute(content: string): Promise<ModelResponse<string[]>> {
+    if (getWordCount(content) < MIN_WORD_LENGTH) {
+      return {
+        kind: 'error',
+        error: ModelResponseError.UNSUPPORTED_TRANSCRIPTION_IS_TOO_SHORT,
+      };
+    }
     content = shorten(content, MAX_CONTENT_WORDS);
     const resp = await this.formatAndExecute(
       FormatFeature.kAudioTitle,
diff --git a/base/test/metrics/action_suffix_reader.cc b/base/test/metrics/action_suffix_reader.cc
index a34123b..9f946c83 100644
--- a/base/test/metrics/action_suffix_reader.cc
+++ b/base/test/metrics/action_suffix_reader.cc
@@ -115,7 +115,7 @@
     if (node_name == "action-suffix") {
       // Try to step into the node.
       if (reader.Read()) {
-        const auto suffixes =
+        auto suffixes =
             ParseActionSuffixesFromActionsXml(affected_action, reader);
         if (suffixes) {
           result.emplace_back(std::move(*suffixes));
diff --git a/build/android/gyp/compile_java.py b/build/android/gyp/compile_java.py
index 82154e8..1d88e21 100755
--- a/build/android/gyp/compile_java.py
+++ b/build/android/gyp/compile_java.py
@@ -5,10 +5,11 @@
 # found in the LICENSE file.
 
 import functools
+import itertools
 import logging
-import multiprocessing
 import optparse
 import os
+import pathlib
 import re
 import shutil
 import sys
@@ -332,39 +333,34 @@
   logging.info('Completed jar file: %s', jar_path)
 
 
+# Java lines end in semicolon, whereas Kotlin lines do not.
+_PACKAGE_RE = re.compile(r'^package\s+(.*?)(;|\s*$)', flags=re.MULTILINE)
+
+# Finds all top-level classes (by looking for those that are not indented).
+_CLASSES_RE = re.compile(
+    # Start of line, or after /* package */
+    r'^(?:/\*.*\*/\s*)?'
+    # Annotations
+    r'(?:@\w+(?:\(.*\))\s+)*'
+    r'(?:(?:public|protected|private)\s+)?'
+    r'(?:(?:static|abstract|final|sealed)\s+)*'
+    r'(?:class|@?interface|enum|record)\s+'
+    r'(\w+?)\b[^"]*?$',
+    flags=re.MULTILINE)
+
+
 def _ParsePackageAndClassNames(source_file):
   """This should support both Java and Kotlin files."""
+  data = pathlib.Path(source_file).read_text()
+
   package_name = ''
-  class_names = []
-  with open(source_file) as f:
-    for l in f:
-      # Strip unindented comments.
-      # Considers a leading * as a continuation of a multi-line comment (our
-      # linter doesn't enforce a space before it like there should be).
-      l = re.sub(r'^(?://.*|/?\*.*?(?:\*/\s*|$))', '', l)
-      # Stripping things between double quotes (strings), so if the word "class"
-      # shows up in a string this doesn't trigger. This isn't strictly correct
-      # (with escaped quotes) but covers a very large percentage of cases.
-      l = re.sub('(?:".*?")', '', l)
+  if m := _PACKAGE_RE.search(data):
+    package_name = m.group(1)
 
-      # Java lines end in semicolon, whereas Kotlin lines do not.
-      m = re.match(r'package\s+(.*?)(;|\s*$)', l)
-      if m and not package_name:
-        package_name = m.group(1)
-
-      # Not exactly a proper parser, but works for sources that Chrome uses.
-      # In order to not match nested classes, it just checks for lack of indent.
-      m = re.match(r'(?:\S.*?)?(?:class|@?interface|enum)\s+(.+?)\b', l)
-      if m:
-        class_names.append(m.group(1))
+  class_names = _CLASSES_RE.findall(data)
   return package_name, class_names
 
 
-def _ProcessSourceFileForInfo(source_file):
-  package_name, class_names = _ParsePackageAndClassNames(source_file)
-  return source_file, package_name, class_names
-
-
 class _InfoFileContext:
   """Manages the creation of the class->source file .info file."""
 
@@ -373,10 +369,6 @@
     self._excluded_globs = excluded_globs
     # Map of .java path -> .srcjar/nested/path.java.
     self._srcjar_files = {}
-    # List of generators from pool.imap_unordered().
-    self._results = []
-    # Lazily created multiprocessing.Pool.
-    self._pool = None
 
   def AddSrcJarSources(self, srcjar_path, extracted_paths, parent_dir):
     for path in extracted_paths:
@@ -385,19 +377,6 @@
       self._srcjar_files[path] = '{}/{}'.format(
           srcjar_path, os.path.relpath(path, parent_dir))
 
-  def SubmitFiles(self, source_files):
-    if not source_files:
-      return
-    if self._pool is None:
-      # Restrict to just one process to not slow down compiling. Compiling
-      # is always slower.
-      self._pool = multiprocessing.Pool(1)
-    logging.info('Submitting %d files for info', len(source_files))
-    self._results.append(
-        self._pool.imap_unordered(_ProcessSourceFileForInfo,
-                                  source_files,
-                                  chunksize=1000))
-
   def _CheckPathMatchesClassName(self, source_file, package_name, class_name):
     if source_file.endswith('.java'):
       parts = package_name.split('.') + [class_name + '.java']
@@ -416,7 +395,8 @@
       if '_aidl.srcjar' in source:
         continue
       assert not self._chromium_code or len(class_names) == 1, (
-          'Chromium java files must only have one class: {}'.format(source))
+          'Chromium java files must only have one class: {} found: {}'.format(
+              source, class_names))
       if self._chromium_code:
         # This check is not necessary but nice to check this somewhere.
         self._CheckPathMatchesClassName(java_file, package_name, class_names[0])
@@ -425,36 +405,21 @@
     name_as_class_glob = fully_qualified_name.replace('.', '/') + '.class'
     return not build_utils.MatchesGlob(name_as_class_glob, self._excluded_globs)
 
-  def _Collect(self):
-    if self._pool is None:
-      return {}
-    ret = {}
-    for result in self._results:
-      for java_file, package_name, class_names in result:
-        source = self._srcjar_files.get(java_file, java_file)
-        for fully_qualified_name in self._ProcessInfo(java_file, package_name,
-                                                      class_names, source):
-          if self._ShouldIncludeInJarInfo(fully_qualified_name):
-            ret[fully_qualified_name] = java_file
-    return ret
-
-  def Close(self):
-    # Work around for Python 2.x bug with multiprocessing and daemon threads:
-    # https://bugs.python.org/issue4106
-    if self._pool is not None:
-      logging.info('Joining multiprocessing.Pool')
-      self._pool.terminate()
-      self._pool.join()
-      logging.info('Done.')
-
-  def Commit(self, output_path):
+  def Run(self, output_path, java_files, kt_files=None):
     """Writes a .jar.info file.
 
     Maps fully qualified names for classes to either the java file that they
     are defined in or the path of the srcjar that they came from.
     """
     logging.info('Collecting info file entries')
-    entries = self._Collect()
+    entries = {}
+    for path in itertools.chain(java_files, kt_files or []):
+      package_name, class_names = _ParsePackageAndClassNames(path)
+      source = self._srcjar_files.get(path, path)
+      for fully_qualified_name in self._ProcessInfo(path, package_name,
+                                                    class_names, source):
+        if self._ShouldIncludeInJarInfo(fully_qualified_name):
+          entries[fully_qualified_name] = path
 
     logging.info('Writing info file: %s', output_path)
     with action_helpers.atomic_output(output_path, mode='wb') as f:
@@ -640,10 +605,6 @@
                              pattern='META-INF/services/*')
       logging.info('Done extracting service provider configs')
 
-    if save_info_file and java_files:
-      info_file_context.SubmitFiles(java_files)
-      info_file_context.SubmitFiles(kt_files)
-
     if java_files:
       # Don't include the output directory in the initial set of args since it
       # being in a temp dir makes it unstable (breaks md5 stamping).
@@ -665,13 +626,21 @@
 
       logging.debug('Build command %s', cmd)
       start = time.time()
+      before_join_callback = None
+      if save_info_file:
+        before_join_callback = lambda: info_file_context.Run(
+            jar_info_path, java_files, kt_files)
+
       build_utils.CheckOutput(cmd,
                               print_stdout=options.chromium_code,
                               stdout_filter=process_javac_output_partial,
                               stderr_filter=process_javac_output_partial,
-                              fail_on_output=options.warnings_as_errors)
+                              fail_on_output=options.warnings_as_errors,
+                              before_join_callback=before_join_callback)
       end = time.time() - start
       logging.info('Java compilation took %ss', end)
+    elif save_info_file:
+      info_file_context.Run(jar_info_path, java_files, kt_files)
 
     CreateJarFile(jar_path, classes_dir, service_provider_configuration,
                   options.additional_jar_files, options.kotlin_jar_path)
@@ -685,13 +654,8 @@
         if '_jni_java/' in p and not p.endswith('Jni.java'):
           os.unlink(p)
 
-    if save_info_file:
-      info_file_context.Commit(jar_info_path)
-
     logging.info('Completed all steps in _RunCompiler')
   finally:
-    if info_file_context:
-      info_file_context.Close()
     shutil.rmtree(temp_dir)
 
 
diff --git a/build/android/gyp/create_app_bundle.py b/build/android/gyp/create_app_bundle.py
index 10f9396d..3b62c72 100755
--- a/build/android/gyp/create_app_bundle.py
+++ b/build/android/gyp/create_app_bundle.py
@@ -428,7 +428,10 @@
 
 def _GetComponentNames(manifest, tag_name):
   android_name = '{%s}name' % manifest_utils.ANDROID_NAMESPACE
-  return [s.attrib.get(android_name) for s in manifest.iter(tag_name)]
+  return [
+      s.attrib.get(android_name)
+      for s in manifest.iterfind(f'application/{tag_name}')
+  ]
 
 
 def _ClassesFromZip(module_zip):
diff --git a/build/android/gyp/util/build_utils.py b/build/android/gyp/util/build_utils.py
index 5b1473e..f12a7f0 100644
--- a/build/android/gyp/util/build_utils.py
+++ b/build/android/gyp/util/build_utils.py
@@ -217,6 +217,7 @@
                 stdout_filter=None,
                 stderr_filter=None,
                 fail_on_output=True,
+                before_join_callback=None,
                 fail_func=lambda returncode, stderr: returncode != 0):
   if not cwd:
     cwd = os.getcwd()
@@ -225,6 +226,8 @@
   child = subprocess.Popen(args,
       stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd, env=env)
 
+  if before_join_callback:
+    before_join_callback()
   stdout, stderr = child.communicate()
 
   # For Python3 only:
diff --git a/chrome/VERSION b/chrome/VERSION
index c29e1526..589869c 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=130
 MINOR=0
-BUILD=6711
+BUILD=6712
 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 998bb451..d04ad9e 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -1043,6 +1043,7 @@
       "//chrome/browser/browser_controls/android:java",
       "//chrome/browser/browser_controls/android:junit",
       "//chrome/browser/commerce/android:java",
+      "//chrome/browser/commerce/android:junit",
       "//chrome/browser/commerce/merchant_viewer/android:junit",
       "//chrome/browser/commerce/price_change/android:junit",
       "//chrome/browser/commerce/price_insights/android:junit",
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupOverflowMenuCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupOverflowMenuCoordinator.java
index 9924667..9ec3356 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupOverflowMenuCoordinator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupOverflowMenuCoordinator.java
@@ -9,6 +9,7 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.database.DataSetObserver;
+import android.graphics.drawable.Drawable;
 import android.text.TextUtils;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -51,6 +52,7 @@
  * menu and displaying the menu.
  */
 public abstract class TabGroupOverflowMenuCoordinator {
+
     /** Helper interface for handling menu item clicks for tab group related actions. */
     @FunctionalInterface
     public interface OnItemClickedCallback {
@@ -73,8 +75,8 @@
                 @StyleRes int animStyle,
                 @HorizontalOrientation int horizontalOrientation,
                 @LayoutRes int menuLayout,
+                Drawable menuBackground,
                 OnItemClickedCallback onItemClickedCallback,
-                boolean isIncognito,
                 int tabId,
                 @Nullable String collaborationId,
                 @DimenRes int popupWidthRes,
@@ -126,14 +128,11 @@
 
             View decorView = activity.getWindow().getDecorView();
 
-            final @DrawableRes int bgDrawableId =
-                    isIncognito ? R.drawable.menu_bg_tinted_on_dark_bg : R.drawable.menu_bg_tinted;
-
             mMenuWindow =
                     new AnchoredPopupWindow(
                             mContext,
                             decorView,
-                            AppCompatResources.getDrawable(mContext, bgDrawableId),
+                            menuBackground,
                             mContentView,
                             anchorViewRectProvider);
             mMenuWindow.setFocusable(true);
@@ -264,6 +263,14 @@
     /** Concrete class required to get a specific menu width for the menu pop up window. */
     protected abstract @DimenRes int getMenuWidth();
 
+    /** Returns menu background drawable. */
+    public Drawable getMenuBackground(Context context, boolean isIncognito) {
+        final @DrawableRes int bgDrawableId =
+                isIncognito ? R.drawable.menu_bg_tinted_on_dark_bg : R.drawable.menu_bg_tinted;
+
+        return AppCompatResources.getDrawable(context, bgDrawableId);
+    }
+
     // TODO(crbug.com/357878838): Pass the activity through constructor and setup test to test this
     // method
     /** See {@link #createAndShowMenu(RectProvider, int, boolean, boolean, Integer, Activity)} */
@@ -300,6 +307,7 @@
         assert mMenuHolder == null;
         boolean isIncognito = mTabModelSupplier.get().isIncognitoBranded();
         @Nullable String collaborationId = getCollaborationIdOrNull(tabId);
+        Drawable menuBackground = getMenuBackground(activity, isIncognito);
         mMenuHolder =
                 new OverflowMenuHolder(
                         anchorViewRectProvider,
@@ -308,8 +316,8 @@
                         animStyle,
                         horizontalOrientation,
                         mMenuLayout,
+                        menuBackground,
                         mOnItemClickedCallback,
-                        isIncognito,
                         tabId,
                         collaborationId,
                         getMenuWidth(),
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutGroupTitle.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutGroupTitle.java
index d6199b0..069d5dd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutGroupTitle.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutGroupTitle.java
@@ -11,7 +11,6 @@
 import androidx.annotation.ColorInt;
 
 import org.chromium.base.MathUtils;
-import org.chromium.base.supplier.Supplier;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.ui.base.LocalizationUtils;
@@ -25,23 +24,6 @@
 
     private final Context mContext;
 
-    /**
-     * Get the bounds of the view w.r.t screen.
-     *
-     * @param out Screen coordinates of the view to populate.
-     * @param windowRectSupplier Supplier for holder window bounds for computation.
-     */
-    public void getDrawBoundsOnScreen(Rect out, Supplier<Rect> windowRectSupplier) {
-        float dpToPx = mContext.getResources().getDisplayMetrics().density;
-        int leftWithOffset = (int) (getPaddedX() * dpToPx) + windowRectSupplier.get().left;
-        int topWithOffset = (int) (getPaddedY() * dpToPx) + windowRectSupplier.get().top;
-        out.set(
-                leftWithOffset,
-                topWithOffset,
-                (int) (leftWithOffset + (getPaddedWidth() * dpToPx)),
-                (int) (topWithOffset + (getPaddedHeight() * dpToPx)));
-    }
-
     /** Delegate for additional group title functionality. */
     public interface StripLayoutGroupTitleDelegate extends StripLayoutViewOnClickHandler {
         /**
@@ -175,6 +157,20 @@
     }
 
     /**
+     * Get padded bounds for this view.
+     *
+     * @param out Rect to set the bounds.
+     */
+    public void getPaddedBoundsPx(Rect out) {
+        float dpToPx = mContext.getResources().getDisplayMetrics().density;
+        out.set(
+                (int) (getPaddedX() * dpToPx),
+                (int) (getPaddedY() * dpToPx),
+                (int) ((getPaddedX() + getPaddedWidth()) * dpToPx),
+                (int) ((getPaddedY() + getPaddedHeight()) * dpToPx));
+    }
+
+    /**
      * @return The tint color resource that represents the tab group title indicator background.
      */
     public @ColorInt int getTint() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java
index 69ecbde..6b673655 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java
@@ -16,6 +16,7 @@
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -349,7 +350,6 @@
     private final StripTabEventHandler mStripTabEventHandler = new StripTabEventHandler();
     private final TabLoadTrackerCallback mTabLoadTrackerHost = new TabLoadTrackerCallbackImpl();
     private final RectF mTouchableRect = new RectF();
-    private final Supplier<Rect> mWindowRectSupplier;
 
     // Common state used for animations on the strip triggered by independent actions including and
     // not limited to tab closure, tab creation/selection, and tab reordering. Not intended to be
@@ -505,7 +505,6 @@
             LayoutManagerHost managerHost,
             LayoutUpdateHost updateHost,
             LayoutRenderHost renderHost,
-            Supplier<Rect> windowRectSupplier,
             boolean incognito,
             CompositorButton modelSelectorButton,
             @Nullable TabDragSource tabDragSource,
@@ -526,7 +525,6 @@
         mLastHoverCardExitTime = INVALID_TIME;
         mTabStripHeight = tabStripHeight;
         mTabStripVisibleSupplier = tabStripVisibleSupplier;
-        mWindowRectSupplier = windowRectSupplier;
 
         // Use toolbar menu button padding to align NTB with menu button.
         mFixedEndPadding =
@@ -1942,10 +1940,26 @@
                             TabGroupSyncFeatures.isTabGroupSyncEnabled(mModel.getProfile()));
         }
         // Popup menu requires screen coordinates for anchor view. Get absolute position for title.
-        Rect tabGroupTitleRect = new Rect();
-        groupTitle.getDrawBoundsOnScreen(tabGroupTitleRect, mWindowRectSupplier);
-        mTabGroupContextMenuCoordinator.showMenu(
-                new RectProvider(tabGroupTitleRect), groupTitle.getRootId());
+        RectProvider anchorRectProvider = new RectProvider();
+        getAnchorRect(groupTitle, anchorRectProvider);
+        mTabGroupContextMenuCoordinator.showMenu(anchorRectProvider, groupTitle.getRootId());
+    }
+
+    private void getAnchorRect(StripLayoutGroupTitle groupTitle, RectProvider anchorRectProvider) {
+        int[] toolbarCoordinates = new int[2];
+        Rect backgroundPadding = new Rect();
+        mToolbarContainerView.getLocationInWindow(toolbarCoordinates);
+        Drawable background =
+                mTabGroupContextMenuCoordinator.getMenuBackground(mContext, mIncognito);
+        background.getPadding(backgroundPadding);
+        groupTitle.getPaddedBoundsPx(anchorRectProvider.getRect());
+        // Use parent toolbar view coordinates to offset title rect.
+        // Also shift the anchor left by menu padding to align the menu exactly with title x.
+        int xOffset =
+                MathUtils.flipSignIf(
+                        toolbarCoordinates[0] - backgroundPadding.left,
+                        LocalizationUtils.isLayoutRtl());
+        anchorRectProvider.getRect().offset(xOffset, toolbarCoordinates[1]);
     }
 
     private void startDragOrReorderTab(long time, float x, float y, StripLayoutTab clickedTab) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManager.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManager.java
index fa44104..4eb306a0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManager.java
@@ -19,7 +19,6 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.View.OnDragListener;
-import android.view.View.OnLayoutChangeListener;
 import android.view.ViewStub;
 import android.view.animation.Interpolator;
 
@@ -35,7 +34,6 @@
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.base.supplier.ObservableSupplierImpl;
-import org.chromium.base.supplier.Supplier;
 import org.chromium.cc.input.BrowserControlsOffsetTagsInfo;
 import org.chromium.cc.input.BrowserControlsState;
 import org.chromium.chrome.R;
@@ -117,8 +115,7 @@
                 PauseResumeWithNativeObserver,
                 TabStripTransitionDelegate,
                 TopResumedActivityChangedObserver,
-                AppHeaderObserver,
-                OnLayoutChangeListener {
+                AppHeaderObserver {
 
     /**
      * POD type that contains the necessary tab model info on startup. Used in the startup flicker
@@ -203,8 +200,6 @@
     // External influences
     private TabModelSelector mTabModelSelector;
     private final LayoutUpdateHost mUpdateHost;
-    private final WindowAndroid mWindowAndroid;
-    private final Rect mWindowRect = new Rect();
 
     // Event Filters
     private final AreaMotionEventFilter mEventFilter;
@@ -504,22 +499,12 @@
         mToolbarManager = toolbarManager;
         mStatusBarColorController = mToolbarManager.getStatusBarColorController();
 
-        mWindowAndroid = windowAndroid;
-        mWindowAndroid
-                .getActivity()
-                .get()
-                .getWindow()
-                .getDecorView()
-                .addOnLayoutChangeListener(this);
-        Supplier<Rect> mWindowRectSupplier = () -> mWindowRect;
-
         mNormalHelper =
                 new StripLayoutHelper(
                         context,
                         managerHost,
                         updateHost,
                         renderHost,
-                        mWindowRectSupplier,
                         false,
                         mModelSelectorButton,
                         mTabDragSource,
@@ -537,7 +522,6 @@
                         managerHost,
                         updateHost,
                         renderHost,
-                        mWindowRectSupplier,
                         true,
                         mModelSelectorButton,
                         mTabDragSource,
@@ -701,12 +685,6 @@
             mDesktopWindowStateProvider.removeObserver(this);
         }
         mStripVisibilityStateSupplier.removeObserver(mStripVisibilityStateObserver);
-        mWindowAndroid
-                .getActivity()
-                .get()
-                .getWindow()
-                .getDecorView()
-                .removeOnLayoutChangeListener(this);
     }
 
     /** Mark whether tab strip is hidden by a height transition. */
@@ -1546,31 +1524,6 @@
         return mStripVisibilityStateSupplier.get();
     }
 
-    /**
-     * Layout event for activity decorView to update window rect. Required to compute absolute
-     * positions for strip views.
-     */
-    @Override
-    public void onLayoutChange(
-            View rootView,
-            int left,
-            int top,
-            int right,
-            int bottom,
-            int oldLeft,
-            int oldTop,
-            int oldRight,
-            int oldBottom) {
-        rootView.getWindowVisibleDisplayFrame(mWindowRect);
-
-        // In multi-window, the coordinates of root view will be different than (0,0).
-        // So we translate the coordinates of |mWindowRect| w.r.t. its window. This ensures the
-        // |mWindowRect| always starts at (0,0).
-        int[] rootCoordinates = new int[2];
-        rootView.getLocationOnScreen(rootCoordinates);
-        mWindowRect.offset(-rootCoordinates[0], -rootCoordinates[1]);
-    }
-
     void simulateHoverEventForTesting(int event, float x, float y) {
         if (event == MotionEvent.ACTION_HOVER_ENTER) {
             mTabStripEventHandler.onHoverEnter(x, y);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java
index a1669388..05fafae 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.contextmenu;
 
+import static org.chromium.chrome.browser.contextmenu.ContextMenuItemProperties.ENABLED;
 import static org.chromium.chrome.browser.contextmenu.ContextMenuItemProperties.MENU_ID;
 import static org.chromium.chrome.browser.contextmenu.ContextMenuItemProperties.TEXT;
 import static org.chromium.chrome.browser.contextmenu.ContextMenuItemWithIconButtonProperties.BUTTON_CONTENT_DESC;
@@ -31,6 +32,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.contextmenu.ChromeContextMenuItem.Item;
 import org.chromium.chrome.browser.contextmenu.ContextMenuCoordinator.ListItemType;
+import org.chromium.chrome.browser.download.DownloadUtils;
 import org.chromium.chrome.browser.ephemeraltab.EphemeralTabCoordinator;
 import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
 import org.chromium.chrome.browser.firstrun.FirstRunStatus;
@@ -301,7 +303,11 @@
             if (FirstRunStatus.getFirstRunFlowComplete()) {
                 if (!mItemDelegate.isIncognito()
                         && UrlUtilities.isDownloadableScheme(mParams.getLinkUrl())) {
-                    linkGroup.add(createListItem(Item.SAVE_LINK_AS));
+                    linkGroup.add(
+                            createListItem(
+                                    Item.SAVE_LINK_AS,
+                                    /* showInProductHelp= */ false,
+                                    !DownloadUtils.isDownloadRestrictedByPolicy(getProfile())));
                 }
                 if (!mParams.isImage()
                         && ReadingListUtils.isReadingListSupported(mParams.getLinkUrl())) {
@@ -363,7 +369,11 @@
             }
             imageGroup.add(createListItem(Item.COPY_IMAGE));
             if (isSrcDownloadableScheme) {
-                imageGroup.add(createListItem(Item.SAVE_IMAGE));
+                imageGroup.add(
+                        createListItem(
+                                Item.SAVE_IMAGE,
+                                /* showInProductHelp= */ false,
+                                !DownloadUtils.isDownloadRestrictedByPolicy(getProfile())));
             }
 
             if (mMode == ContextMenuMode.CUSTOM_TAB || mMode == ContextMenuMode.NORMAL) {
@@ -398,7 +408,11 @@
                 && mParams.canSaveMedia()
                 && UrlUtilities.isDownloadableScheme(mParams.getSrcUrl())) {
             ModelList videoGroup = new ModelList();
-            videoGroup.add(createListItem(Item.SAVE_VIDEO));
+            videoGroup.add(
+                    createListItem(
+                            Item.SAVE_VIDEO,
+                            /* showInProductHelp= */ false,
+                            !DownloadUtils.isDownloadRestrictedByPolicy(getProfile())));
             groupedItems.add(new Pair<>(R.string.contextmenu_video_title, videoGroup));
         }
 
@@ -900,10 +914,14 @@
     }
 
     private ListItem createListItem(@Item int item) {
-        return createListItem(item, false);
+        return createListItem(item, /* showInProductHelp= */ false, /* enabled= */ true);
     }
 
     private ListItem createListItem(@Item int item, boolean showInProductHelp) {
+        return createListItem(item, showInProductHelp, /* enabled= */ true);
+    }
+
+    private ListItem createListItem(@Item int item, boolean showInProductHelp, boolean enabled) {
         final PropertyModel model =
                 new PropertyModel.Builder(ContextMenuItemProperties.ALL_KEYS)
                         .with(MENU_ID, ChromeContextMenuItem.getMenuId(item))
@@ -911,6 +929,7 @@
                                 TEXT,
                                 ChromeContextMenuItem.getTitle(
                                         mContext, getProfile(), item, showInProductHelp))
+                        .with(ENABLED, enabled)
                         .build();
         return new ListItem(ListItemType.CONTEXT_MENU_ITEM, model);
     }
@@ -921,6 +940,7 @@
         final PropertyModel model =
                 new PropertyModel.Builder(ContextMenuItemWithIconButtonProperties.ALL_KEYS)
                         .with(MENU_ID, ChromeContextMenuItem.getMenuId(item))
+                        .with(ENABLED, true)
                         .with(
                                 TEXT,
                                 ChromeContextMenuItem.getTitle(mContext, getProfile(), item, false))
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuCoordinator.java
index 87cf603..e236951d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuCoordinator.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.contextmenu;
 
+import static org.chromium.chrome.browser.contextmenu.ContextMenuItemProperties.ENABLED;
 import static org.chromium.chrome.browser.contextmenu.ContextMenuItemProperties.MENU_ID;
 import static org.chromium.chrome.browser.contextmenu.ContextMenuItemWithIconButtonProperties.BUTTON_CLICK_LISTENER;
 import static org.chromium.chrome.browser.contextmenu.ContextMenuItemWithIconButtonProperties.BUTTON_MENU_ID;
@@ -258,9 +259,12 @@
 
                     @Override
                     public boolean isEnabled(int position) {
-                        return getItemViewType(position) == ListItemType.CONTEXT_MENU_ITEM
+                        if (getItemViewType(position) == ListItemType.CONTEXT_MENU_ITEM
                                 || getItemViewType(position)
-                                        == ListItemType.CONTEXT_MENU_ITEM_WITH_ICON_BUTTON;
+                                        == ListItemType.CONTEXT_MENU_ITEM_WITH_ICON_BUTTON) {
+                            return ((ListItem) getItem(position)).model.get(ENABLED);
+                        }
+                        return false;
                     }
 
                     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuItemProperties.java b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuItemProperties.java
index 6db413e..dc4c188 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuItemProperties.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuItemProperties.java
@@ -5,6 +5,7 @@
 package org.chromium.chrome.browser.contextmenu;
 
 import org.chromium.ui.modelutil.PropertyKey;
+import org.chromium.ui.modelutil.PropertyModel.WritableBooleanPropertyKey;
 import org.chromium.ui.modelutil.PropertyModel.WritableIntPropertyKey;
 import org.chromium.ui.modelutil.PropertyModel.WritableObjectPropertyKey;
 
@@ -12,6 +13,7 @@
     public static final WritableObjectPropertyKey<CharSequence> TEXT =
             new WritableObjectPropertyKey<>();
     public static final WritableIntPropertyKey MENU_ID = new WritableIntPropertyKey();
+    public static final WritableBooleanPropertyKey ENABLED = new WritableBooleanPropertyKey();
 
-    public static final PropertyKey[] ALL_KEYS = {TEXT, MENU_ID};
+    public static final PropertyKey[] ALL_KEYS = {TEXT, MENU_ID, ENABLED};
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuItemViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuItemViewBinder.java
index fb1c869..86d9ff9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuItemViewBinder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuItemViewBinder.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.contextmenu;
 
+import static org.chromium.chrome.browser.contextmenu.ContextMenuItemProperties.ENABLED;
 import static org.chromium.chrome.browser.contextmenu.ContextMenuItemProperties.TEXT;
 
 import android.view.View;
@@ -16,6 +17,8 @@
     public static void bind(PropertyModel model, View view, PropertyKey propertyKey) {
         if (propertyKey == TEXT) {
             ((TextView) view).setText(model.get(TEXT));
+        } else if (propertyKey == ENABLED) {
+            view.setEnabled(model.get(ENABLED));
         }
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java
index 03babc8..5790a28 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java
@@ -12,6 +12,7 @@
 
 import android.app.Activity;
 import android.content.Intent;
+import android.os.Bundle;
 import android.util.Pair;
 import android.view.KeyEvent;
 
@@ -92,6 +93,8 @@
 public abstract class BaseCustomTabActivity extends ChromeActivity<BaseCustomTabActivityComponent> {
     protected static Integer sOverrideCoreCountForTesting;
 
+    private final CipherFactory mCipherFactory = new CipherFactory();
+
     protected BaseCustomTabRootUiCoordinator mBaseCustomTabRootUiCoordinator;
     protected BrowserServicesIntentDataProvider mIntentDataProvider;
     protected CustomTabDelegateFactory mDelegateFactory;
@@ -306,14 +309,14 @@
                                 intentIgnoringCriterion,
                                 getTopUiThemeColorProvider(),
                                 new DefaultBrowserProviderImpl(),
-                                CipherFactory.getInstance())
+                                mCipherFactory)
                         : new BaseCustomTabActivityModule(
                                 mIntentDataProvider,
                                 mNightModeStateController,
                                 intentIgnoringCriterion,
                                 getTopUiThemeColorProvider(),
                                 new DefaultBrowserProviderImpl(),
-                                CipherFactory.getInstance());
+                                mCipherFactory);
         BaseCustomTabActivityComponent component =
                 ChromeApplicationImpl.getComponent()
                         .createBaseCustomTabActivityComponent(commonsModule, baseCustomTabsModule);
@@ -824,4 +827,10 @@
         }
         return mLastPipMode == PictureInPictureMode.MINIMIZED_CUSTOM_TAB;
     }
+
+    @Override
+    public void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        mCipherFactory.saveToBundle(outState);
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabController.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabController.java
index 4bdcfdb..f309d390 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabController.java
@@ -34,6 +34,7 @@
 import org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider;
 import org.chromium.chrome.browser.compositor.CompositorViewHolder;
 import org.chromium.chrome.browser.content.WebContentsFactory;
+import org.chromium.chrome.browser.crypto.CipherFactory;
 import org.chromium.chrome.browser.customtabs.CustomTabDelegateFactory;
 import org.chromium.chrome.browser.customtabs.CustomTabIncognitoManager;
 import org.chromium.chrome.browser.customtabs.CustomTabIntentDataProvider;
@@ -117,6 +118,7 @@
     private final Supplier<Bundle> mSavedInstanceStateSupplier;
     private final ActivityWindowAndroid mWindowAndroid;
     private final TabModelInitializer mTabModelInitializer;
+    private final CipherFactory mCipherFactory;
 
     @Nullable private final CustomTabsSessionToken mSession;
     private final Intent mIntent;
@@ -144,7 +146,8 @@
             Lazy<AsyncTabParamsManager> asyncTabParamsManager,
             @Named(SAVED_INSTANCE_SUPPLIER) Supplier<Bundle> savedInstanceStateSupplier,
             ActivityWindowAndroid windowAndroid,
-            TabModelInitializer tabModelInitializer) {
+            TabModelInitializer tabModelInitializer,
+            CipherFactory cipherFactory) {
         mProfileProviderSupplier = profileProviderSupplier;
         mCustomTabDelegateFactory = customTabDelegateFactory;
         mActivity = activity;
@@ -166,6 +169,7 @@
         mSavedInstanceStateSupplier = savedInstanceStateSupplier;
         mWindowAndroid = windowAndroid;
         mTabModelInitializer = tabModelInitializer;
+        mCipherFactory = cipherFactory;
 
         mSession = mIntentDataProvider.getSession();
         mIntent = mIntentDataProvider.getIntent();
@@ -360,7 +364,11 @@
 
     private @Nullable Tab tryRestoringTab(TabModelOrchestrator tabModelOrchestrator) {
         if (mSavedInstanceStateSupplier.get() == null) return null;
-        tabModelOrchestrator.loadState(true, null);
+
+        boolean hadCipherData = mCipherFactory.restoreFromBundle(mSavedInstanceStateSupplier.get());
+        if (!hadCipherData && mIntentDataProvider.isOffTheRecord()) return null;
+
+        tabModelOrchestrator.loadState(/* ignoreIncognitoFiles= */ false, null);
         tabModelOrchestrator.restoreTabs(true);
         Tab tab = tabModelOrchestrator.getTabModelSelector().getCurrentTab();
         if (tab != null) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java
index e59983f..af2581b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java
@@ -85,13 +85,15 @@
             "org.chromium.chrome.browser.download.OTR_PROFILE_ID";
     private static final String MIME_TYPE_ZIP = "application/zip";
     private static final String DOCUMENTS_UI_PACKAGE_NAME = "com.android.documentsui";
+    private static Boolean sIsDownloadRestrictedByPolicyForTesting;
 
     /**
      * Displays the download manager UI. Note the UI is different on tablets and on phones.
+     *
      * @param activity The current activity is available.
      * @param tab The current tab if it exists.
      * @param otrProfileID The {@link OTRProfileID} to determine whether download home should be
-     * opened in incognito mode. If null, download page will be opened in normal profile.
+     *     opened in incognito mode. If null, download page will be opened in normal profile.
      * @param source The source where the user action is coming from.
      * @return Whether the UI was shown.
      */
@@ -691,7 +693,26 @@
     }
 
     /**
+     * Returns whether download is restricted by policy.
+     *
+     * @param profile Profile to be checked.
+     * @return True if download is restricted, or false otherwise.
+     */
+    public static boolean isDownloadRestrictedByPolicy(Profile profile) {
+        if (sIsDownloadRestrictedByPolicyForTesting != null) {
+            return sIsDownloadRestrictedByPolicyForTesting;
+        }
+        return DownloadUtilsJni.get().isDownloadRestrictedByPolicy(profile);
+    }
+
+    public static void setIsDownloadRestrictedByPolicyForTesting(
+            Boolean isDownloadRestrictedByPolicy) {
+        sIsDownloadRestrictedByPolicyForTesting = isDownloadRestrictedByPolicy;
+    }
+
+    /**
      * Helper method to get the text to be displayed for duplicate download.
+     *
      * @param template Message template.
      * @param fileName Name of the file.
      * @param addSizeStringIfAvailable Whether size string should be added to the dialog text.
@@ -736,5 +757,7 @@
         int getResumeMode(
                 @JniType("std::string") String url,
                 @FailState @JniType("offline_items_collection::FailState") int failState);
+
+        boolean isDownloadRestrictedByPolicy(@JniType("Profile*") Profile profile);
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulatorTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulatorTest.java
index 09c71a9..3afafba 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulatorTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulatorTest.java
@@ -5,12 +5,14 @@
 package org.chromium.chrome.browser.contextmenu;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.when;
 
+import static org.chromium.chrome.browser.contextmenu.ContextMenuItemProperties.ENABLED;
 import static org.chromium.chrome.browser.contextmenu.ContextMenuItemProperties.MENU_ID;
 import static org.chromium.chrome.browser.contextmenu.ContextMenuItemProperties.TEXT;
 
@@ -42,6 +44,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.IntentHandler;
 import org.chromium.chrome.browser.contextmenu.ChromeContextMenuPopulator.ContextMenuMode;
+import org.chromium.chrome.browser.download.DownloadUtils;
 import org.chromium.chrome.browser.ephemeraltab.EphemeralTabCoordinator;
 import org.chromium.chrome.browser.firstrun.FirstRunStatus;
 import org.chromium.chrome.browser.lens.LensEntryPoint;
@@ -59,6 +62,7 @@
 import org.chromium.content_public.browser.test.NativeLibraryTestUtils;
 import org.chromium.ui.base.MenuSourceType;
 import org.chromium.ui.modelutil.MVCListAdapter.ModelList;
+import org.chromium.ui.modelutil.PropertyModel;
 import org.chromium.url.GURL;
 
 import java.util.ArrayList;
@@ -100,6 +104,7 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         mAutomotiveRule.setIsAutomotive(false);
+        DownloadUtils.setIsDownloadRestrictedByPolicyForTesting(false);
         NativeLibraryTestUtils.loadNativeLibraryNoBrowserProcess();
 
         GURL pageUrl = new GURL(PAGE_URL);
@@ -122,6 +127,7 @@
 
     @After
     public void tearDown() {
+        DownloadUtils.setIsDownloadRestrictedByPolicyForTesting(null);
         ThreadUtils.runOnUiThreadBlocking(
                 () -> {
                     ApplicationStatus.resetActivitiesForInstrumentationTests();
@@ -145,7 +151,7 @@
         doReturn(true).when(mExternalAuthUtils).isGoogleSigned(IntentHandler.PACKAGE_GSA);
     }
 
-    private void checkMenuOptions(int[]... groups) {
+    private void checkMenuOptions(List<Integer> disabled, int[]... groups) {
         List<Pair<Integer, ModelList>> contextMenuState = mPopulator.buildContextMenu();
 
         assertEquals(
@@ -156,7 +162,13 @@
         for (int i = 0; i < contextMenuState.size(); i++) {
             int[] availableInTab = new int[contextMenuState.get(i).second.size()];
             for (int j = 0; j < contextMenuState.get(i).second.size(); j++) {
-                availableInTab[j] = contextMenuState.get(i).second.get(j).model.get(MENU_ID);
+                PropertyModel model = contextMenuState.get(i).second.get(j).model;
+                if (disabled.contains(model.get(MENU_ID))) {
+                    assertFalse(model.get(ENABLED));
+                } else {
+                    assertTrue(model.get(ENABLED));
+                }
+                availableInTab[j] = model.get(MENU_ID);
             }
 
             int[] expectedItemsInGroup = groups[i];
@@ -189,6 +201,10 @@
         }
     }
 
+    private void checkMenuOptions(int[]... groups) {
+        checkMenuOptions(/* disabled= */ new ArrayList<Integer>(), groups);
+    }
+
     @Test
     @SmallTest
     @UiThreadTest
@@ -266,6 +282,68 @@
     @Test
     @SmallTest
     @UiThreadTest
+    public void testHttpLinkWithDownloadBlockedByPolicy() {
+        FirstRunStatus.setFirstRunFlowComplete(true);
+        DownloadUtils.setIsDownloadRestrictedByPolicyForTesting(true);
+        ContextMenuParams params =
+                new ContextMenuParams(
+                        0,
+                        0,
+                        new GURL(PAGE_URL),
+                        new GURL(LINK_URL),
+                        LINK_TEXT,
+                        GURL.emptyGURL(),
+                        GURL.emptyGURL(),
+                        "",
+                        null,
+                        false,
+                        0,
+                        0,
+                        MenuSourceType.MENU_SOURCE_TOUCH,
+                        false,
+                        /* additionalNavigationParams= */ null);
+
+        initializePopulator(ChromeContextMenuPopulator.ContextMenuMode.NORMAL, params);
+        int[] expected2 = {
+            R.id.contextmenu_open_in_new_tab_in_group,
+            R.id.contextmenu_open_in_new_tab,
+            R.id.contextmenu_open_in_incognito_tab,
+            R.id.contextmenu_open_in_ephemeral_tab,
+            R.id.contextmenu_copy_link_address,
+            R.id.contextmenu_copy_link_text,
+            R.id.contextmenu_save_link_as,
+            R.id.contextmenu_read_later,
+            R.id.contextmenu_share_link
+        };
+        checkMenuOptions(Arrays.asList(R.id.contextmenu_save_link_as), expected2);
+
+        initializePopulator(ChromeContextMenuPopulator.ContextMenuMode.CUSTOM_TAB, params);
+        int[] expected3 = {
+            R.id.contextmenu_open_in_browser_id,
+            R.id.contextmenu_open_in_ephemeral_tab,
+            R.id.contextmenu_copy_link_address,
+            R.id.contextmenu_copy_link_text,
+            R.id.contextmenu_save_link_as,
+            R.id.contextmenu_read_later,
+            R.id.contextmenu_share_link
+        };
+        checkMenuOptions(Arrays.asList(R.id.contextmenu_save_link_as), expected3);
+
+        initializePopulator(ChromeContextMenuPopulator.ContextMenuMode.WEB_APP, params);
+        int[] expected4 = {
+            R.id.contextmenu_copy_link_address,
+            R.id.contextmenu_copy_link_text,
+            R.id.contextmenu_save_link_as,
+            R.id.contextmenu_read_later,
+            R.id.contextmenu_share_link,
+            R.id.contextmenu_open_in_chrome
+        };
+        checkMenuOptions(Arrays.asList(R.id.contextmenu_save_link_as), expected4);
+    }
+
+    @Test
+    @SmallTest
+    @UiThreadTest
     public void testHttpLinkWithPreviewTabEnabled() {
         ContextMenuParams params =
                 new ContextMenuParams(
@@ -539,6 +617,80 @@
     @Test
     @SmallTest
     @UiThreadTest
+    public void testVideoLinkWithDownloadBlockedByPolicy() {
+        FirstRunStatus.setFirstRunFlowComplete(true);
+        DownloadUtils.setIsDownloadRestrictedByPolicyForTesting(true);
+        GURL sourceUrl = new GURL("http://www.blah.com/");
+        GURL url = new GURL(sourceUrl.getSpec() + "I_love_mouse_video.avi");
+        ContextMenuParams params =
+                new ContextMenuParams(
+                        0,
+                        ContextMenuDataMediaType.VIDEO,
+                        new GURL(PAGE_URL),
+                        url,
+                        "VIDEO!",
+                        GURL.emptyGURL(),
+                        sourceUrl,
+                        "",
+                        null,
+                        true,
+                        0,
+                        0,
+                        MenuSourceType.MENU_SOURCE_TOUCH,
+                        false,
+                        /* additionalNavigationParams= */ null);
+
+        initializePopulator(ChromeContextMenuPopulator.ContextMenuMode.NORMAL, params);
+        int[] expected2Tab1 = {
+            R.id.contextmenu_open_in_new_tab_in_group,
+            R.id.contextmenu_open_in_new_tab,
+            R.id.contextmenu_open_in_incognito_tab,
+            R.id.contextmenu_open_in_ephemeral_tab,
+            R.id.contextmenu_copy_link_address,
+            R.id.contextmenu_copy_link_text,
+            R.id.contextmenu_save_link_as,
+            R.id.contextmenu_read_later,
+            R.id.contextmenu_share_link
+        };
+        int[] expected2Tab2 = {R.id.contextmenu_save_video};
+        checkMenuOptions(
+                Arrays.asList(R.id.contextmenu_save_link_as, R.id.contextmenu_save_video),
+                expected2Tab1,
+                expected2Tab2);
+
+        initializePopulator(ChromeContextMenuPopulator.ContextMenuMode.CUSTOM_TAB, params);
+        int[] expected3Tab1 = {
+            R.id.contextmenu_open_in_browser_id,
+            R.id.contextmenu_open_in_ephemeral_tab,
+            R.id.contextmenu_copy_link_address,
+            R.id.contextmenu_copy_link_text,
+            R.id.contextmenu_save_link_as,
+            R.id.contextmenu_read_later,
+            R.id.contextmenu_share_link
+        };
+        checkMenuOptions(
+                Arrays.asList(R.id.contextmenu_save_link_as, R.id.contextmenu_save_video),
+                expected3Tab1,
+                expected2Tab2);
+
+        initializePopulator(ChromeContextMenuPopulator.ContextMenuMode.WEB_APP, params);
+        int[] expected4Tab1 = {
+            R.id.contextmenu_copy_link_address,
+            R.id.contextmenu_copy_link_text,
+            R.id.contextmenu_save_link_as,
+            R.id.contextmenu_read_later,
+            R.id.contextmenu_share_link
+        };
+        int[] expected4Tab2 = {R.id.contextmenu_save_video, R.id.contextmenu_open_in_chrome};
+        checkMenuOptions(
+                Arrays.asList(R.id.contextmenu_save_link_as, R.id.contextmenu_save_video),
+                expected4Tab1,
+                expected4Tab2);
+    }
+
+    @Test
+    @SmallTest
+    @UiThreadTest
     public void testImageHiFi() {
         FirstRunStatus.setFirstRunFlowComplete(false);
         ContextMenuParams params =
@@ -691,6 +843,61 @@
     @Test
     @SmallTest
     @UiThreadTest
+    public void testImageWithDownloadBlockedByPolicy() {
+        FirstRunStatus.setFirstRunFlowComplete(true);
+        DownloadUtils.setIsDownloadRestrictedByPolicyForTesting(true);
+        ContextMenuParams params =
+                new ContextMenuParams(
+                        0,
+                        ContextMenuDataMediaType.IMAGE,
+                        new GURL(PAGE_URL),
+                        GURL.emptyGURL(),
+                        "",
+                        GURL.emptyGURL(),
+                        new GURL(IMAGE_SRC_URL),
+                        IMAGE_TITLE_TEXT,
+                        null,
+                        true,
+                        0,
+                        0,
+                        MenuSourceType.MENU_SOURCE_TOUCH,
+                        false,
+                        /* additionalNavigationParams= */ null);
+
+        initializePopulator(ChromeContextMenuPopulator.ContextMenuMode.NORMAL, params);
+        int[] expected2 = {
+            R.id.contextmenu_open_image_in_new_tab,
+            R.id.contextmenu_open_image_in_ephemeral_tab,
+            R.id.contextmenu_copy_image,
+            R.id.contextmenu_save_image,
+            R.id.contextmenu_share_image
+        };
+        checkMenuOptions(Arrays.asList(R.id.contextmenu_save_image), expected2);
+
+        initializePopulator(ChromeContextMenuPopulator.ContextMenuMode.CUSTOM_TAB, params);
+        int[] expected3 = {
+            R.id.contextmenu_open_in_browser_id,
+            R.id.contextmenu_open_image,
+            R.id.contextmenu_open_image_in_ephemeral_tab,
+            R.id.contextmenu_copy_image,
+            R.id.contextmenu_save_image,
+            R.id.contextmenu_share_image
+        };
+        checkMenuOptions(Arrays.asList(R.id.contextmenu_save_image), expected3);
+
+        initializePopulator(ChromeContextMenuPopulator.ContextMenuMode.WEB_APP, params);
+        int[] expected4 = {
+            R.id.contextmenu_copy_image,
+            R.id.contextmenu_save_image,
+            R.id.contextmenu_share_image,
+            R.id.contextmenu_open_in_chrome
+        };
+        checkMenuOptions(Arrays.asList(R.id.contextmenu_save_image), expected4);
+    }
+
+    @Test
+    @SmallTest
+    @UiThreadTest
     public void testReadLater() {
         FirstRunStatus.setFirstRunFlowComplete(true);
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuItemViewTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuItemViewTest.java
index ff387db..157d8aa 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuItemViewTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuItemViewTest.java
@@ -61,6 +61,7 @@
                             new PropertyModel.Builder(
                                             ContextMenuItemWithIconButtonProperties.ALL_KEYS)
                                     .with(ContextMenuItemWithIconButtonProperties.TEXT, "")
+                                    .with(ContextMenuItemWithIconButtonProperties.ENABLED, true)
                                     .with(
                                             ContextMenuItemWithIconButtonProperties.BUTTON_IMAGE,
                                             null)
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuRenderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuRenderTest.java
index 8e503aa7..68556bd1 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuRenderTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuRenderTest.java
@@ -250,6 +250,7 @@
                                         "chrome/test/data/android/UiCapture/dots.png")));
         return new PropertyModel.Builder(ContextMenuItemWithIconButtonProperties.ALL_KEYS)
                 .with(ContextMenuItemWithIconButtonProperties.TEXT, title)
+                .with(ContextMenuItemWithIconButtonProperties.ENABLED, true)
                 .with(ContextMenuItemWithIconButtonProperties.BUTTON_IMAGE, drawable)
                 .build();
     }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperTest.java
index 79015d2..3ff192e 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperTest.java
@@ -33,6 +33,7 @@
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
 import android.os.Build;
 import android.text.TextUtils;
 import android.view.ContextThemeWrapper;
@@ -60,7 +61,6 @@
 import org.robolectric.annotation.LooperMode.Mode;
 
 import org.chromium.base.Callback;
-import org.chromium.base.supplier.Supplier;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.Features.DisableFeatures;
@@ -169,7 +169,6 @@
     private static final float REORDER_OVERLAP_SWITCH_PERCENTAGE = 0.53f;
     private static final PointF DRAG_START_POINT = new PointF(70f, 20f);
     private static final float EPSILON = 0.001f;
-    private final Supplier<Rect> mWindowRectSupplier = () -> new Rect(1, 1, 1000, 100);
 
     /** Reset the environment before each test. */
     @Before
@@ -1799,6 +1798,9 @@
         groupTabs(0, 1);
         StripLayoutTab[] tabs = getMockedStripLayoutTabs(150f);
         mStripLayoutHelper.setStripLayoutTabsForTesting(tabs);
+        Drawable mockDrawable = mock(Drawable.class);
+        when(mTabGroupContextMenuCoordinator.getMenuBackground(any(), anyBoolean()))
+                .thenReturn(mockDrawable);
 
         // Set up tabModel and menu coordinator.
         MockTabModel tabModel = new MockTabModel(mProfile, null);
@@ -1819,9 +1821,9 @@
         StripLayoutView view = mStripLayoutHelper.getViewAtPositionX(10f, true);
         assertTrue(view instanceof StripLayoutGroupTitle);
         StripLayoutGroupTitle titleView = (StripLayoutGroupTitle) view;
-        Rect actualRect = rectProviderArgumentCaptor.getValue().getRect();
         Rect expectedRect = new Rect();
-        titleView.getDrawBoundsOnScreen(expectedRect, mWindowRectSupplier);
+        titleView.getPaddedBoundsPx(expectedRect);
+        Rect actualRect = rectProviderArgumentCaptor.getValue().getRect();
         assertEquals("Anchor view for menu is positioned incorrectly", expectedRect, actualRect);
     }
 
@@ -4044,7 +4046,6 @@
                         mManagerHost,
                         mUpdateHost,
                         mRenderHost,
-                        mWindowRectSupplier,
                         incognito,
                         mModelSelectorBtn,
                         mTabDragSource,
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/contextmenu/ContextMenuCoordinatorTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/contextmenu/ContextMenuCoordinatorTest.java
index cf54fa2..d79c6bc 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/contextmenu/ContextMenuCoordinatorTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/contextmenu/ContextMenuCoordinatorTest.java
@@ -6,8 +6,11 @@
 
 import static org.hamcrest.CoreMatchers.equalTo;
 import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.doReturn;
 
+import static org.chromium.chrome.browser.contextmenu.ContextMenuItemProperties.ENABLED;
 import static org.chromium.chrome.browser.contextmenu.ContextMenuItemProperties.MENU_ID;
 import static org.chromium.chrome.browser.contextmenu.ContextMenuItemProperties.TEXT;
 
@@ -205,6 +208,62 @@
         assertThat(itemList.get(7).type, equalTo(ListItemType.CONTEXT_MENU_ITEM));
         assertThat(itemList.get(8).type, equalTo(ListItemType.CONTEXT_MENU_ITEM));
         assertThat(itemList.get(9).type, equalTo(ListItemType.CONTEXT_MENU_ITEM_WITH_ICON_BUTTON));
+        // "Save link as"  and "save image" should be enabled.
+        assertTrue(itemList.get(4).model.get(ENABLED));
+        assertTrue(itemList.get(8).model.get(ENABLED));
+    }
+
+    @Test
+    public void testGetItemListWithDownloadBlockedByPolicy() {
+        final ContextMenuParams params =
+                new ContextMenuParams(
+                        0,
+                        ContextMenuDataMediaType.IMAGE,
+                        GURL.emptyGURL(),
+                        GURL.emptyGURL(),
+                        "",
+                        GURL.emptyGURL(),
+                        GURL.emptyGURL(),
+                        "",
+                        null,
+                        false,
+                        0,
+                        0,
+                        0,
+                        false,
+                        /* additionalNavigationParams= */ null);
+        List<Pair<Integer, ModelList>> rawItems = new ArrayList<>();
+        // Link items
+        ModelList groupOne = new ModelList();
+        groupOne.add(createListItem(Item.OPEN_IN_NEW_TAB));
+        groupOne.add(createListItem(Item.OPEN_IN_INCOGNITO_TAB));
+        groupOne.add(createListItem(Item.SAVE_LINK_AS, false));
+        groupOne.add(createShareListItem(Item.SHARE_LINK));
+        rawItems.add(new Pair<>(ContextMenuGroup.LINK, groupOne));
+        // Image Items
+        ModelList groupTwo = new ModelList();
+        groupTwo.add(createListItem(Item.OPEN_IMAGE_IN_NEW_TAB));
+        groupTwo.add(createListItem(Item.SAVE_IMAGE, false));
+        groupTwo.add(createShareListItem(Item.SHARE_IMAGE));
+        rawItems.add(new Pair<>(ContextMenuGroup.IMAGE, groupTwo));
+
+        mCoordinator.initializeHeaderCoordinatorForTesting(
+                mActivity, params, mProfile, mNativeDelegate);
+        ModelList itemList = mCoordinator.getItemList(mActivity, rawItems, (i) -> {}, true);
+
+        assertThat(itemList.get(0).type, equalTo(ListItemType.HEADER));
+        assertThat(itemList.get(1).type, equalTo(ListItemType.DIVIDER));
+        assertThat(itemList.get(2).type, equalTo(ListItemType.CONTEXT_MENU_ITEM));
+        assertThat(itemList.get(3).type, equalTo(ListItemType.CONTEXT_MENU_ITEM));
+        assertThat(itemList.get(4).type, equalTo(ListItemType.CONTEXT_MENU_ITEM));
+        assertThat(itemList.get(5).type, equalTo(ListItemType.CONTEXT_MENU_ITEM_WITH_ICON_BUTTON));
+        assertThat(itemList.get(6).type, equalTo(ListItemType.DIVIDER));
+        assertThat(itemList.get(7).type, equalTo(ListItemType.CONTEXT_MENU_ITEM));
+        assertThat(itemList.get(8).type, equalTo(ListItemType.CONTEXT_MENU_ITEM));
+        assertThat(itemList.get(9).type, equalTo(ListItemType.CONTEXT_MENU_ITEM_WITH_ICON_BUTTON));
+        // "Save link as"  and "save image" should be disabled.
+        assertFalse(itemList.get(4).model.get(ENABLED));
+        assertFalse(itemList.get(8).model.get(ENABLED));
     }
 
     @Test
@@ -452,9 +511,14 @@
     }
 
     private ListItem createListItem(@Item int item) {
+        return createListItem(item, /* enabled= */ true);
+    }
+
+    private ListItem createListItem(@Item int item, boolean enabled) {
         final PropertyModel model =
                 new PropertyModel.Builder(ContextMenuItemProperties.ALL_KEYS)
                         .with(MENU_ID, ChromeContextMenuItem.getMenuId(item))
+                        .with(ENABLED, enabled)
                         .with(
                                 TEXT,
                                 ChromeContextMenuItem.getTitle(mActivity, mProfile, item, false))
@@ -466,6 +530,7 @@
         final PropertyModel model =
                 new PropertyModel.Builder(ContextMenuItemWithIconButtonProperties.ALL_KEYS)
                         .with(MENU_ID, ChromeContextMenuItem.getMenuId(item))
+                        .with(ENABLED, true)
                         .with(
                                 TEXT,
                                 ChromeContextMenuItem.getTitle(mActivity, mProfile, item, false))
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityContentTestEnvironment.java b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityContentTestEnvironment.java
index f9c149de2..6c19e529 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityContentTestEnvironment.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityContentTestEnvironment.java
@@ -35,6 +35,7 @@
 import org.chromium.chrome.browser.browserservices.intents.ColorProvider;
 import org.chromium.chrome.browser.compositor.CompositorViewHolder;
 import org.chromium.chrome.browser.content.WebContentsFactory;
+import org.chromium.chrome.browser.crypto.CipherFactory;
 import org.chromium.chrome.browser.customtabs.CloseButtonNavigator;
 import org.chromium.chrome.browser.customtabs.CustomTabDelegateFactory;
 import org.chromium.chrome.browser.customtabs.CustomTabIncognitoManager;
@@ -105,6 +106,8 @@
     @Mock public WebContents webContents;
     @Mock public CustomTabMinimizationManagerHolder mMinimizationManagerHolder;
     @Mock public ProfileProvider profileProvider;
+    @Mock public CipherFactory cipherFactory;
+
     public AsyncTabParamsManager realAsyncTabParamsManager =
             AsyncTabParamsManagerFactory.createAsyncTabParamsManager();
 
@@ -182,7 +185,8 @@
                 () -> realAsyncTabParamsManager,
                 () -> activity.getSavedInstanceState(),
                 activity.getWindowAndroid(),
-                tabModelInitializer);
+                tabModelInitializer,
+                cipherFactory);
     }
 
     public CustomTabActivityNavigationController createNavigationController(
@@ -287,6 +291,7 @@
         when(tab.isIncognito()).thenAnswer((mock) -> isOffTheRecord);
         when(tab.isOffTheRecord()).thenAnswer((mock) -> isOffTheRecord);
         when(tab.isIncognitoBranded()).thenAnswer((mock) -> isOffTheRecord);
+        when(intentDataProvider.isOffTheRecord()).thenReturn(isOffTheRecord);
         return tab;
     }
 }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabControllerUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabControllerUnitTest.java
index baef9e8..01643f8 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabControllerUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabControllerUnitTest.java
@@ -105,6 +105,28 @@
     }
 
     @Test
+    public void usesRestoredTab_IfOffTheRecord_IfAvailable() {
+        env.isOffTheRecord = true;
+        Tab savedTab = env.prepareTab();
+        env.saveTab(savedTab);
+        when(env.cipherFactory.restoreFromBundle(any())).thenReturn(true);
+        env.reachNativeInit(mTabController);
+        assertEquals(savedTab, env.tabProvider.getTab());
+        assertEquals(TabCreationMode.RESTORED, env.tabProvider.getInitialTabCreationMode());
+    }
+
+    @Test
+    public void doesntUseRestoredTab_IfOffTheRecord_NoCipherKey() {
+        env.isOffTheRecord = true;
+        Tab savedTab = env.prepareTab();
+        env.saveTab(savedTab);
+        when(env.cipherFactory.restoreFromBundle(any())).thenReturn(false);
+        env.reachNativeInit(mTabController);
+        assertEquals(env.tabFromFactory, env.tabProvider.getTab());
+        assertEquals(TabCreationMode.DEFAULT, env.tabProvider.getInitialTabCreationMode());
+    }
+
+    @Test
     public void doesntCreateNewTab_IfRestored() {
         Tab savedTab = env.prepareTab();
         env.saveTab(savedTab);
diff --git a/chrome/android/profiles/arm.newest.txt b/chrome/android/profiles/arm.newest.txt
index 4e43751..eeb10cfa 100644
--- a/chrome/android/profiles/arm.newest.txt
+++ b/chrome/android/profiles/arm.newest.txt
@@ -1 +1 @@
-chromeos-chrome-arm-130.0.6709.0_rc-r1-merged.afdo.bz2
+chromeos-chrome-arm-130.0.6710.0_rc-r1-merged.afdo.bz2
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index 42f9860..267257e 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -6908,6 +6908,32 @@
     Switch themes at sunrise and sunset
   </message>
 
+  <!-- Split Modifier Screen -->
+  <message name="IDS_OOBE_SPLIT_MODIFIER_INFO_TITLE" desc="Title of the split modifier info screen." translateable="false">
+    Test new feature on your device after setup
+  </message>
+  <message name="IDS_OOBE_SPLIT_MODIFIER_INFO_SUBTITLE" desc="Subtitle of the split modifier info screen." translateable="false">
+    Test new feature on your device after setup.
+  </message>
+  <message name="IDS_OOBE_SPLIT_MODIFIER_INFO_FIRST_DESCRIPTION_TITLE" desc="Title of the first description section." translateable="false">
+    Testing
+  </message>
+  <message name="IDS_OOBE_SPLIT_MODIFIER_INFO_FIRST_DESCRIPTION_TEXT" desc="Text inside the first description section." translateable="false">
+    Test your device with the new features added to the Chromebook and more.
+  </message>
+  <message name="IDS_OOBE_SPLIT_MODIFIER_INFO_FIRST_DESCRIPTION_ACCESSIBILITY" desc="Additional information for the accessibility tools for the first description section." translateable="false">
+    Test your device with the new features added to the Chromebook and more.
+  </message>
+  <message name="IDS_OOBE_SPLIT_MODIFIER_INFO_SECOND_DESCRIPTION_TITLE" desc="Title of the second description section." translateable="false">
+    Testing
+  </message>
+  <message name="IDS_OOBE_SPLIT_MODIFIER_INFO_SECOND_DESCRIPTION_TEXT" desc="Text inside the second description section." translateable="false">
+    Test your device with the new features added to the Chromebook and more.
+  </message>
+  <message name="IDS_OOBE_SPLIT_MODIFIER_INFO_SECOND_DESCRIPTION_ACCESSIBILITY" desc="Additional information for the accessibility tools for the second description section." translateable="false">
+    Test your device with the new features added to the Chromebook and more.
+  </message>
+
   <!-- Touchpad Scroll -->
   <message name="IDS_OOBE_TOUCHPAD_SCROLL_TITLE" desc="Title of the touchpad scroll direction screen.">
     Change touchpad scrolling direction
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index aed3a95..bf02bd2 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -838,18 +838,6 @@
     Hide password for <ph name="USERNAME">$1<ex>example@gmail.com</ex></ph> on <ph name="DOMAIN">$2<ex>www.google.com</ex></ph>
   </message>
 
-  <if expr="is_macosx">
-  <message name="IDS_SETTINGS_PASSWORDS_BIOMETRIC_AUTHENTICATION_FOR_FILLING_TOGGLE_LABEL_MAC" desc="Label for a toggle that allows users to be authenticate using their TouchID or any other means of authentication when logging into webpages.">
-    Use your screen lock when filling passwords
-  </message>
-  </if>
-
-  <if expr="is_win">
-  <message name="IDS_SETTINGS_PASSWORDS_BIOMETRIC_AUTHENTICATION_FOR_FILLING_TOGGLE_LABEL_WIN" desc="Label for a toggle that allows users to be authenticate using their Windows Hello when logging into webpages.">
-    Use Windows Hello when filling passwords
-  </message>
-  </if>
-
   <!-- Default Browser Page -->
   <if expr="not is_chromeos">
     <message name="IDS_SETTINGS_DEFAULT_BROWSER" desc="Name of the Default Browser page, which allows users to set which browser will open .html files within the OS.">
@@ -2966,6 +2954,21 @@
   <message name="IDS_SETTINGS_SITE_SETTINGS_HID_DEVICES_BLOCKED" desc="Label for the disabled option of the hid devices site setting.">
     Don't allow sites to connect to HID devices
   </message>
+  <message name="IDS_SITE_SETTINGS_SMART_CARD_READERS" desc="Main heading for the Smart Card Readers section in settings.">
+    Smart card readers
+  </message>
+  <message name="IDS_SITE_SETTINGS_SMART_CARD_READERS_DESCRIPTION" desc="Description of how Isolated Web Apps interact with smart card readers.">
+    Isolated Web Apps control smart card readers to gain access to smart cards that are inserted or presented to them. Smart cards usually contain identities that are used to authenticate or authorize operations, log into services, etc.
+  </message>
+  <message name="IDS_SITE_SETTINGS_SMART_CARDS_DEFAULT_DESCRIPTION" desc="Label indicating the default behavior for smart card access.">
+    Isolated Web Apps automatically follow this setting.
+  </message>
+  <message name="IDS_SITE_SETTINGS_SMART_CARDS_ALLOWED" desc="Option to allow Isolated Web Apps to control smart card readers.">
+    Isolated Web Apps can ask to control smart card readers. Apps will gain access to smart cards presented to readers under their control.
+  </message>
+  <message name="IDS_SITE_SETTINGS_SMART_CARDS_BLOCKED" desc="Option to block Isolated Web Apps from controlling smart card readers.">
+    Isolated Web Apps cannot control smart card readers. Apps won't gain access to any smart card.
+  </message>
   <message name="IDS_SETTINGS_SITE_SETTINGS_IMAGES_DESCRIPTION" desc="Description of the images content setting.">
     Sites usually show images to provide illustration, like photos for online stores or news articles
   </message>
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_PASSWORDS_BIOMETRIC_AUTHENTICATION_FOR_FILLING_TOGGLE_LABEL_MAC.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_PASSWORDS_BIOMETRIC_AUTHENTICATION_FOR_FILLING_TOGGLE_LABEL_MAC.png.sha1
deleted file mode 100644
index a1f772e1..0000000
--- a/chrome/app/settings_strings_grdp/IDS_SETTINGS_PASSWORDS_BIOMETRIC_AUTHENTICATION_FOR_FILLING_TOGGLE_LABEL_MAC.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-0617a4bdb1de065d7a286d39035ba582aba8a299
\ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_PASSWORDS_BIOMETRIC_AUTHENTICATION_FOR_FILLING_TOGGLE_LABEL_WIN.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_PASSWORDS_BIOMETRIC_AUTHENTICATION_FOR_FILLING_TOGGLE_LABEL_WIN.png.sha1
deleted file mode 100644
index a42d44b..0000000
--- a/chrome/app/settings_strings_grdp/IDS_SETTINGS_PASSWORDS_BIOMETRIC_AUTHENTICATION_FOR_FILLING_TOGGLE_LABEL_WIN.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-2bfe8761db1d38a368700c3835677ce3192ee5bb
\ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SITE_SETTINGS_SMART_CARDS_ALLOWED.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SITE_SETTINGS_SMART_CARDS_ALLOWED.png.sha1
new file mode 100644
index 0000000..622e3ce2
--- /dev/null
+++ b/chrome/app/settings_strings_grdp/IDS_SITE_SETTINGS_SMART_CARDS_ALLOWED.png.sha1
@@ -0,0 +1 @@
+7b0452fcd6c55d88c4596974fa49ee2c7d6209cd
\ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SITE_SETTINGS_SMART_CARDS_BLOCKED.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SITE_SETTINGS_SMART_CARDS_BLOCKED.png.sha1
new file mode 100644
index 0000000..622e3ce2
--- /dev/null
+++ b/chrome/app/settings_strings_grdp/IDS_SITE_SETTINGS_SMART_CARDS_BLOCKED.png.sha1
@@ -0,0 +1 @@
+7b0452fcd6c55d88c4596974fa49ee2c7d6209cd
\ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SITE_SETTINGS_SMART_CARDS_DEFAULT_DESCRIPTION.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SITE_SETTINGS_SMART_CARDS_DEFAULT_DESCRIPTION.png.sha1
new file mode 100644
index 0000000..622e3ce2
--- /dev/null
+++ b/chrome/app/settings_strings_grdp/IDS_SITE_SETTINGS_SMART_CARDS_DEFAULT_DESCRIPTION.png.sha1
@@ -0,0 +1 @@
+7b0452fcd6c55d88c4596974fa49ee2c7d6209cd
\ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SITE_SETTINGS_SMART_CARD_READERS.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SITE_SETTINGS_SMART_CARD_READERS.png.sha1
new file mode 100644
index 0000000..622e3ce2
--- /dev/null
+++ b/chrome/app/settings_strings_grdp/IDS_SITE_SETTINGS_SMART_CARD_READERS.png.sha1
@@ -0,0 +1 @@
+7b0452fcd6c55d88c4596974fa49ee2c7d6209cd
\ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SITE_SETTINGS_SMART_CARD_READERS_DESCRIPTION.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SITE_SETTINGS_SMART_CARD_READERS_DESCRIPTION.png.sha1
new file mode 100644
index 0000000..622e3ce2
--- /dev/null
+++ b/chrome/app/settings_strings_grdp/IDS_SITE_SETTINGS_SMART_CARD_READERS_DESCRIPTION.png.sha1
@@ -0,0 +1 @@
+7b0452fcd6c55d88c4596974fa49ee2c7d6209cd
\ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 0029e73..50a5bdd4 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -660,6 +660,8 @@
     "language/language_model_manager_factory.h",
     "language/url_language_histogram_factory.cc",
     "language/url_language_histogram_factory.h",
+    "language_detection/language_detection_model_service_factory.cc",
+    "language_detection/language_detection_model_service_factory.h",
     "lifetime/application_lifetime.cc",
     "lifetime/application_lifetime.h",
     "lifetime/browser_shutdown.cc",
@@ -1700,8 +1702,6 @@
     "translate/chrome_translate_client.h",
     "translate/translate_frame_binder.cc",
     "translate/translate_frame_binder.h",
-    "translate/translate_model_service_factory.cc",
-    "translate/translate_model_service_factory.h",
     "translate/translate_ranker_factory.cc",
     "translate/translate_ranker_factory.h",
     "translate/translate_ranker_metrics_provider.cc",
@@ -1804,6 +1804,7 @@
   # Any circular includes must depend on the target
   # "browser_public_dependencies".
   allow_circular_includes_from = [
+    "//chrome/browser/ui/autofill:impl",
     "//chrome/browser/ui/autofill/payments",
     "//chrome/browser/ui/autofill/payments:impl",
     "//chrome/browser/ui/bluetooth:impl",
@@ -1972,6 +1973,8 @@
     "//chrome/browser/ui:ui_features",
     "//chrome/browser/ui/actions:actions",
     "//chrome/browser/ui/actions:actions_headers",
+    "//chrome/browser/ui/autofill",
+    "//chrome/browser/ui/autofill:impl",
     "//chrome/browser/ui/autofill/payments",
     "//chrome/browser/ui/autofill/payments:impl",
     "//chrome/browser/ui/blocked_content",
@@ -1986,6 +1989,7 @@
     "//chrome/browser/ui/omnibox",
     "//chrome/browser/ui/omnibox:impl",
     "//chrome/browser/ui/tabs",
+    "//chrome/browser/ui/webui",
     "//chrome/browser/ui/webui:configs",
     "//chrome/browser/ui/zoom",
     "//chrome/browser/updater:scheduler",
@@ -2125,6 +2129,7 @@
     "//components/language/core/common",
     "//components/language/core/language_model",
     "//components/language_detection/content/browser",
+    "//components/language_detection/core/browser:language_detection_model_service",
     "//components/lens",
     "//components/lens:buildflags",
     "//components/lens:enterprise_policy",
@@ -2345,7 +2350,6 @@
     "//components/tracing:startup_tracing",
     "//components/translate/content/browser",
     "//components/translate/core/browser",
-    "//components/translate/core/browser:translate_model_service",
     "//components/translate/core/common",
     "//components/trusted_vault",
     "//components/ui_devtools",
@@ -2778,8 +2782,6 @@
       "android/send_tab_to_self/android_notification_handler.h",
       "android/send_tab_to_self/metrics_recorder.cc",
       "android/send_tab_to_self/send_tab_to_self_android_bridge.cc",
-      "android/sensitive_content/chrome_sensitive_content_client.cc",
-      "android/sensitive_content/chrome_sensitive_content_client.h",
       "android/service_tab_launcher.cc",
       "android/service_tab_launcher.h",
       "android/shortcut_helper.cc",
@@ -3320,6 +3322,7 @@
       "//chrome/browser/translate/android:jni_headers",
       "//chrome/browser/ui/android/layouts:android",
       "//chrome/browser/ui/android/pdf:pdf_jni_headers",
+      "//chrome/browser/ui/digital_credentials",
       "//chrome/browser/usb/android:jni_headers",
       "//chrome/browser/wallet/android:jni_headers",
       "//chrome/common:non_code_constants",
@@ -3404,7 +3407,7 @@
       "//components/search:start_suggest",
       "//components/security_state/content/android",
       "//components/send_tab_to_self",
-      "//components/sensitive_content",
+      "//components/sensitive_content:features",
       "//components/sharing_message",
       "//components/signin/internal/identity_manager",  # cf android/signin/DEPS
       "//components/signin/public/android:jni_headers",
@@ -4255,6 +4258,8 @@
       "//chrome/browser/task_manager",
       "//chrome/browser/task_manager:impl",
       "//chrome/browser/themes",
+      "//chrome/browser/ui:browser_list",
+      "//chrome/browser/ui:browser_list_impl",
       "//chrome/browser/ui/actions:actions_headers",
       "//chrome/browser/ui/apps",
       "//chrome/browser/ui/apps:impl",
@@ -4396,6 +4401,7 @@
       "//chrome/browser/picture_in_picture:impl",
       "//chrome/browser/ui/signin:impl",
       "//chrome/browser/ui/webui/signin:impl",
+      "//chrome/browser/ui:browser_list_impl",
     ]
 
     #!is_android
@@ -6703,6 +6709,7 @@
       "//chrome/browser/enterprise/connectors/device_trust/common",
       "//chrome/browser/enterprise/connectors/device_trust/signals",
       "//chrome/browser/enterprise/connectors/device_trust/signals/decorators/common",
+      "//chrome/browser/ui/device_signals_consent",
       "//components/device_signals/core/browser",
       "//components/device_signals/core/common",
       "//components/enterprise/core",
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS
index f062973..5e62a561 100644
--- a/chrome/browser/DEPS
+++ b/chrome/browser/DEPS
@@ -193,6 +193,7 @@
   "+components/language/core/browser",
   "+components/language/core/common",
   "+components/language/core/language_model",
+  "+components/language_detection/core/browser",
   "+components/lens",
   "+components/leveldb_proto/content",
   "+components/leveldb_proto/public",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 34288c40..4bf6aa6 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -5835,6 +5835,10 @@
      flag_descriptions::kImeKoreanOnlyModeSwitchOnRightAltName,
      flag_descriptions::kImeKoreanOnlyModeSwitchOnRightAltDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(ash::features::kImeKoreanOnlyModeSwitchOnRightAlt)},
+    {"enable-cros-ime-switch-check-connection-status",
+     flag_descriptions::kImeSwitchCheckConnectionStatusName,
+     flag_descriptions::kImeSwitchCheckConnectionStatusDescription, kOsCrOS,
+     FEATURE_VALUE_TYPE(ash::features::kImeSwitchCheckConnectionStatus)},
     {"enable-cros-japanese-os-settings",
      flag_descriptions::kJapaneseOSSettingsName,
      flag_descriptions::kJapaneseOSSettingsDescription, kOsCrOS,
@@ -11927,6 +11931,13 @@
      kOsMac | kOsWin | kOsLinux | kOsAndroid,
      FEATURE_VALUE_TYPE(features::kCertVerificationNetworkTime)},
 
+#if !BUILDFLAG(IS_ANDROID)
+    {"enable-lens-overlay-translate-button",
+     flag_descriptions::kLensOverlayTranslateButtonName,
+     flag_descriptions::kLensOverlayTranslateButtonDescription, kOsDesktop,
+     FEATURE_VALUE_TYPE(lens::features::kLensOverlayTranslateButton)},
+#endif  // !BUILDFLAG(IS_ANDROID)
+
     // NOTE: Adding a new flag requires adding a corresponding entry to enum
     // "LoginCustomFlags" in tools/metrics/histograms/enums.xml. See "Flag
     // Histograms" in tools/metrics/histograms/README.md (run the
diff --git a/chrome/browser/ai/ai_manager_keyed_service.cc b/chrome/browser/ai/ai_manager_keyed_service.cc
index 0a165e2..08d4d967 100644
--- a/chrome/browser/ai/ai_manager_keyed_service.cc
+++ b/chrome/browser/ai/ai_manager_keyed_service.cc
@@ -104,7 +104,7 @@
         kModelToBeInstalled:
       return blink::mojom::ModelAvailabilityCheckResult::kAfterDownload;
     case optimization_guide::OnDeviceModelEligibilityReason::kSuccess:
-      NOTREACHED_IN_MIGRATION();
+      NOTREACHED();
   }
   NOTREACHED();
 }
@@ -361,6 +361,7 @@
     mojo::PendingReceiver<blink::mojom::AITextSession> receiver,
     blink::mojom::AITextSessionSamplingParamsPtr sampling_params,
     const std::optional<std::string>& system_prompt,
+    std::vector<blink::mojom::AIAssistantInitialPromptPtr> initial_prompts,
     CreateTextSessionCallback callback) {
   // Since this is a mojo IPC implementation, the context should be non-null;
   AIContextBoundObjectSet* context_bound_object_set =
@@ -374,10 +375,11 @@
     return;
   }
 
-  if (system_prompt.has_value()) {
-    // If the system prompt is provided, we need to set the system prompt and
-    // invoke the callback after it.
-    session->SetSystemPrompt(system_prompt.value(), std::move(callback));
+  if (system_prompt.has_value() || !initial_prompts.empty()) {
+    // If the initial prompt is provided, we need to set it and invoke the
+    // callback after this, because the token counting happens asynchronously.
+    session->SetInitialPrompts(system_prompt, std::move(initial_prompts),
+                               std::move(callback));
   } else {
     std::move(callback).Run(session->GetTextSessionInfo());
   }
diff --git a/chrome/browser/ai/ai_manager_keyed_service.h b/chrome/browser/ai/ai_manager_keyed_service.h
index 8959022c..093f01fb 100644
--- a/chrome/browser/ai/ai_manager_keyed_service.h
+++ b/chrome/browser/ai/ai_manager_keyed_service.h
@@ -53,6 +53,7 @@
       mojo::PendingReceiver<blink::mojom::AITextSession> receiver,
       blink::mojom::AITextSessionSamplingParamsPtr sampling_params,
       const std::optional<std::string>& system_prompt,
+      std::vector<blink::mojom::AIAssistantInitialPromptPtr> initial_prompts,
       CreateTextSessionCallback callback) override;
   void GetTextModelInfo(GetTextModelInfoCallback callback) override;
   void CreateWriter(
diff --git a/chrome/browser/ai/ai_manager_keyed_service_unittest.cc b/chrome/browser/ai/ai_manager_keyed_service_unittest.cc
index 62710957f..087ddc3 100644
--- a/chrome/browser/ai/ai_manager_keyed_service_unittest.cc
+++ b/chrome/browser/ai/ai_manager_keyed_service_unittest.cc
@@ -115,7 +115,9 @@
   // After creating one `AITextSession`, the `AIUserDataSet` contains 1
   // element.
   mock_remote->CreateTextSession(mock_session.BindNewPipeAndPassReceiver(),
-                                 nullptr, std::nullopt, callback.Get());
+                                 /*sampling_params=*/nullptr,
+                                 /*system_prompt=*/std::nullopt,
+                                 /*initial_prompts=*/{}, callback.Get());
   run_loop.Run();
   ASSERT_EQ(1u, context_bound_objects->GetSizeForTesting());
 
diff --git a/chrome/browser/ai/ai_text_session.cc b/chrome/browser/ai/ai_text_session.cc
index 755507c14..4e88774c 100644
--- a/chrome/browser/ai/ai_text_session.cc
+++ b/chrome/browser/ai/ai_text_session.cc
@@ -10,6 +10,7 @@
 #include "base/check_op.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback_forward.h"
+#include "base/notreached.h"
 #include "base/strings/stringprintf.h"
 #include "chrome/browser/ai/ai_manager_keyed_service.h"
 #include "chrome/browser/ai/ai_manager_keyed_service_factory.h"
@@ -21,6 +22,7 @@
 #include "components/optimization_guide/core/optimization_guide_util.h"
 #include "components/optimization_guide/proto/common_types.pb.h"
 #include "components/optimization_guide/proto/string_value.pb.h"
+#include "third_party/blink/public/mojom/ai/ai_manager.mojom-shared.h"
 #include "third_party/blink/public/mojom/ai/ai_text_session_info.mojom.h"
 #include "third_party/blink/public/mojom/ai/model_streaming_responder.mojom.h"
 
@@ -28,9 +30,30 @@
 
 // The format for the prompt and the context. The prompt structure helps the
 // model distinguish the roles in the previous conversation.
-const char kPromptFormat[] = "User: %s\nModel: ";
-const char kContextFormat[] = "%s\n%s\n";
+
+// The template used to format each prompt input. Example:
+// ```
+// User: what is the opposite of large?
+// Model:
+// ```
+const char kPromptFormat[] = "%s: %s\n%s: ";
+// The template used to format each context entry. Example:
+// ```
+// User: what is the opposite of large?
+// Model: small.
+// ```
+const char kContextFormat[] = "%s%s\n";
+
+// The templates used to format different parts of the system prompt. Example:
+// ```
+// You are a professor of antonyms.      [system prompt]
+// User: what is the opposite of big?    [initial prompt for `User` role]
+// Model: small.                         [initial prompt for `Assistant` role]
+// User: what is the opposite of cheap?  [initial prompt for `User` role]
+// Model: expensive.                     [initial prompt for `Assistant` role]
+// ```
 const char kSystemPromptFormat[] = "%s\n";
+const char kInitialPromptFormat[] = "%s: %s\n";
 
 }  // namespace
 
@@ -38,13 +61,13 @@
     OptimizationGuideModelExecutionError::ModelExecutionError;
 
 AITextSession::Context::Context(uint32_t max_tokens,
-                                std::optional<ContextItem> system_prompt)
-    : max_tokens_(max_tokens), system_prompt_(system_prompt) {
-  if (system_prompt.has_value()) {
-    CHECK_GE(max_tokens_, system_prompt->tokens)
-        << "the caller shouldn't create an AITextSession with the system "
-           "prompt containing more tokens than the limit.";
-    current_tokens_ += system_prompt->tokens;
+                                std::optional<ContextItem> initial_prompts)
+    : max_tokens_(max_tokens), initial_prompts_(initial_prompts) {
+  if (initial_prompts.has_value()) {
+    CHECK_GE(max_tokens_, initial_prompts->tokens)
+        << "the caller shouldn't create an AITextSession with the initial "
+           "prompts containing more tokens than the limit.";
+    current_tokens_ += initial_prompts->tokens;
   }
 }
 
@@ -63,9 +86,9 @@
 
 std::string AITextSession::Context::GetContextString() {
   std::string context;
-  if (system_prompt_.has_value()) {
+  if (initial_prompts_.has_value()) {
     context =
-        base::StringPrintf(kSystemPromptFormat, system_prompt_->text.c_str());
+        base::StringPrintf(kSystemPromptFormat, initial_prompts_->text.c_str());
   }
   for (auto& context_item : context_items_) {
     context.append(context_item.text);
@@ -74,7 +97,7 @@
 }
 
 bool AITextSession::Context::HasContextItem() {
-  return system_prompt_.has_value() || !context_items_.empty();
+  return initial_prompts_.has_value() || !context_items_.empty();
 }
 
 AITextSession::AITextSession(
@@ -102,12 +125,22 @@
 
 AITextSession::~AITextSession() = default;
 
-void AITextSession::SetSystemPrompt(std::string system_prompt,
-                                    CreateTextSessionCallback callback) {
+void AITextSession::SetInitialPrompts(
+    const std::optional<std::string> system_prompt,
+    std::vector<blink::mojom::AIAssistantInitialPromptPtr> initial_prompts,
+    CreateTextSessionCallback callback) {
+  std::string initial_prompts_str = base::StringPrintf(
+      kSystemPromptFormat, system_prompt.value_or("").c_str());
+  for (auto& initial_prompt : initial_prompts) {
+    initial_prompts_str += base::StringPrintf(
+        kInitialPromptFormat, FormatPromptRole(initial_prompt->role),
+        initial_prompt->content.c_str());
+  }
+  base::TrimString(initial_prompts_str, "\n", &initial_prompts_str);
   session_->GetSizeInTokens(
-      system_prompt,
-      base::BindOnce(&AITextSession::InitializeContextWithSystemPrompt,
-                     weak_ptr_factory_.GetWeakPtr(), system_prompt,
+      initial_prompts_str,
+      base::BindOnce(&AITextSession::InitializeContextWithInitialPrompts,
+                     weak_ptr_factory_.GetWeakPtr(), initial_prompts_str,
                      std::move(callback)));
 }
 
@@ -115,8 +148,8 @@
   receiver_.set_disconnect_handler(std::move(deletion_callback));
 }
 
-void AITextSession::InitializeContextWithSystemPrompt(
-    const std::string& text,
+void AITextSession::InitializeContextWithInitialPrompts(
+    const std::string& initial_prompts_text,
     CreateTextSessionCallback callback,
     uint32_t size) {
   // If the on device model service fails to get the size, it will be 0.
@@ -135,8 +168,8 @@
     return;
   }
 
-  context_ =
-      std::make_unique<Context>(max_token, Context::ContextItem{text, size});
+  context_ = std::make_unique<Context>(
+      max_token, Context::ContextItem{initial_prompts_text, size});
   std::move(callback).Run(GetTextSessionInfo());
 }
 
@@ -212,8 +245,11 @@
   mojo::RemoteSetElementId responder_id =
       responder_set_.Add(std::move(pending_responder));
   optimization_guide::proto::StringValue request;
-  const std::string formatted_input =
-      base::StringPrintf(kPromptFormat, input.c_str());
+  const std::string formatted_input = base::StringPrintf(
+      kPromptFormat,
+      FormatPromptRole(blink::mojom::AIAssistantInitialPromptRole::kUser),
+      input.c_str(),
+      FormatPromptRole(blink::mojom::AIAssistantInitialPromptRole::kAssistant));
   request.set_value(formatted_input);
   session_->ExecuteModel(
       request, base::BindRepeating(&AITextSession::ModelExecutionCallback,
@@ -269,11 +305,15 @@
 }
 
 // static
-std::string AITextSession::GetPromptFormatForTesting() {
-  return kPromptFormat;
-}
-
-// static
-std::string AITextSession::GetSystemPromptFormatForTesting() {
-  return kSystemPromptFormat;
+const char* AITextSession::FormatPromptRole(
+    blink::mojom::AIAssistantInitialPromptRole role) {
+  switch (role) {
+    case blink::mojom::AIAssistantInitialPromptRole::kSystem:
+      return "System";
+    case blink::mojom::AIAssistantInitialPromptRole::kUser:
+      return "User";
+    case blink::mojom::AIAssistantInitialPromptRole::kAssistant:
+      return "Model";
+  }
+  NOTREACHED();
 }
diff --git a/chrome/browser/ai/ai_text_session.h b/chrome/browser/ai/ai_text_session.h
index 8ee0d47..e860415 100644
--- a/chrome/browser/ai/ai_text_session.h
+++ b/chrome/browser/ai/ai_text_session.h
@@ -19,6 +19,7 @@
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/remote_set.h"
+#include "third_party/blink/public/mojom/ai/ai_manager.mojom-forward.h"
 #include "third_party/blink/public/mojom/ai/ai_text_session.mojom.h"
 #include "third_party/blink/public/mojom/ai/ai_text_session_info.mojom-forward.h"
 #include "third_party/blink/public/mojom/ai/model_streaming_responder.mojom-forward.h"
@@ -65,7 +66,7 @@
    private:
     uint32_t max_tokens_;
     uint32_t current_tokens_ = 0;
-    std::optional<ContextItem> system_prompt_;
+    std::optional<ContextItem> initial_prompts_;
     std::deque<ContextItem> context_items_;
   };
 
@@ -102,15 +103,16 @@
             ForkCallback callback) override;
   void Destroy() override;
 
-  // Gets the token count for the system prompt, updates the session, and passes
-  // the session information back through the callback.
-  void SetSystemPrompt(std::string system_prompt,
-                       CreateTextSessionCallback callback);
+  // Format the initial prompts, gets the token count, updates the session, and
+  // passes the session information back through the callback.
+  void SetInitialPrompts(
+      const std::optional<std::string> system_prompt,
+      std::vector<blink::mojom::AIAssistantInitialPromptPtr> initial_prompts,
+      CreateTextSessionCallback callback);
   blink::mojom::AITextSessionInfoPtr GetTextSessionInfo();
 
-  // The following methods expose the format for testing.
-  static std::string GetPromptFormatForTesting();
-  static std::string GetSystemPromptFormatForTesting();
+  static const char* FormatPromptRole(
+      blink::mojom::AIAssistantInitialPromptRole role);
 
  private:
   void ModelExecutionCallback(
@@ -119,9 +121,10 @@
       optimization_guide::OptimizationGuideModelStreamingExecutionResult
           result);
 
-  void InitializeContextWithSystemPrompt(const std::string& text,
-                                         CreateTextSessionCallback callback,
-                                         uint32_t size);
+  void InitializeContextWithInitialPrompts(
+      const std::string& initial_prompts_text,
+      CreateTextSessionCallback callback,
+      uint32_t size);
 
   // This function is passed as a completion callback to the
   // `GetSizeInTokens()`. It will
diff --git a/chrome/browser/ai/ai_text_session_unittest.cc b/chrome/browser/ai/ai_text_session_unittest.cc
index e142579..83311298c 100644
--- a/chrome/browser/ai/ai_text_session_unittest.cc
+++ b/chrome/browser/ai/ai_text_session_unittest.cc
@@ -15,23 +15,51 @@
 #include "components/optimization_guide/proto/string_value.pb.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/mojom/ai/ai_manager.mojom-forward.h"
+#include "third_party/blink/public/mojom/ai/ai_manager.mojom-shared.h"
 #include "third_party/blink/public/mojom/ai/ai_text_session.mojom.h"
 #include "third_party/blink/public/mojom/ai/ai_text_session_info.mojom.h"
 
 using testing::_;
 using testing::Test;
+using Role = blink::mojom::AIAssistantInitialPromptRole;
 
 namespace {
 
 const uint32_t kTestMaxContextToken = 10u;
-const uint32_t kTestSystemPromptToken = 5u;
+const uint32_t kTestInitialPromptsToken = 5u;
 const uint32_t kDefaultTopK = 1;
 const float kDefaultTemperature = 0.0;
 
 const char kTestPrompt[] = "Test prompt";
-const char kTestSystemPrompt[] = "Test system prompt";
+const char kExpectedFormattedTestPrompt[] = "User: Test prompt\nModel: ";
+const char kTestSystemPrompts[] = "Test system prompt";
+const char kExpectedFormattedSystemPrompts[] = "Test system prompt\n";
 const char kTestResponse[] = "Test response";
 
+const char kTestInitialPromptsUser1[] = "How are you?";
+const char kTestInitialPromptsSystem1[] = "I'm fine, thank you, and you?";
+const char kTestInitialPromptsUser2[] = "I'm fine too.";
+const char kExpectedFormattedInitialPrompts[] =
+    "User: How are you?\nModel: I'm fine, thank you, and you?\nUser: I'm fine "
+    "too.\n";
+const char kExpectedFormattedSystemPromptAndInitialPrompts[] =
+    "Test system prompt\nUser: How are you?\nModel: I'm fine, thank you, and "
+    "you?\nUser: I'm fine too.\n";
+std::vector<blink::mojom::AIAssistantInitialPromptPtr> GetTestInitialPrompts() {
+  auto create_initial_prompt = [](Role role, const char* content) {
+    return blink::mojom::AIAssistantInitialPrompt::New(role, content);
+  };
+  std::vector<blink::mojom::AIAssistantInitialPromptPtr> initial_prompts{};
+  initial_prompts.push_back(
+      create_initial_prompt(Role::kUser, kTestInitialPromptsUser1));
+  initial_prompts.push_back(
+      create_initial_prompt(Role::kAssistant, kTestInitialPromptsSystem1));
+  initial_prompts.push_back(
+      create_initial_prompt(Role::kUser, kTestInitialPromptsUser2));
+  return initial_prompts;
+}
+
 }  // namespace
 
 class AITextSessionTest : public AITestUtils::AITestBase {
@@ -40,7 +68,10 @@
   void RunPromptTest(
       const std::string& prompt_input,
       blink::mojom::AITextSessionSamplingParamsPtr sampling_params,
-      const std::optional<std::string>& system_prompt) {
+      const std::optional<std::string>& system_prompt,
+      std::vector<blink::mojom::AIAssistantInitialPromptPtr> initial_prompts,
+      const std::string& expected_context,
+      const std::string& expected_prompt) {
     blink::mojom::AITextSessionSamplingParamsPtr sampling_params_copy;
     if (sampling_params) {
       sampling_params_copy = sampling_params->Clone();
@@ -79,18 +110,13 @@
                   });
 
           ON_CALL(*session, AddContext(_))
-              .WillByDefault([&system_prompt](
-                                 const google::protobuf::MessageLite&
+              .WillByDefault([&](const google::protobuf::MessageLite&
                                      request_metadata) {
-                EXPECT_TRUE(system_prompt.has_value());
                 EXPECT_THAT(
                     static_cast<const optimization_guide::proto::StringValue*>(
                         &request_metadata)
                         ->value(),
-                    base::StringPrintf(
-                        AITextSession::GetSystemPromptFormatForTesting()
-                            .c_str(),
-                        system_prompt->c_str()));
+                    expected_context.c_str());
               });
           EXPECT_CALL(*session, ExecuteModel(_, _))
               .WillOnce(
@@ -103,9 +129,7 @@
                             const optimization_guide::proto::StringValue*>(
                             &request_metadata)
                             ->value(),
-                        base::StringPrintf(
-                            AITextSession::GetPromptFormatForTesting().c_str(),
-                            kTestPrompt));
+                        expected_prompt);
                     callback.Run(CreateExecutionResult(kTestResponse,
                                                        /*is_complete=*/true));
                   });
@@ -114,9 +138,9 @@
 
     mojo::Remote<blink::mojom::AIManager> ai_manager = GetAIManagerRemote();
     mojo::Remote<blink::mojom::AITextSession> mock_session;
-    ai_manager->CreateTextSession(mock_session.BindNewPipeAndPassReceiver(),
-                                  std::move(sampling_params), system_prompt,
-                                  base::NullCallback());
+    ai_manager->CreateTextSession(
+        mock_session.BindNewPipeAndPassReceiver(), std::move(sampling_params),
+        system_prompt, std::move(initial_prompts), base::NullCallback());
 
     AITestUtils::MockModelStreamingResponder mock_responder;
 
@@ -167,70 +191,88 @@
 
 TEST_F(AITextSessionTest, PromptDefaultSession) {
   RunPromptTest(kTestPrompt, /*sampling_params=*/nullptr,
-                /*system_prompt=*/std::nullopt);
+                /*system_prompt=*/std::nullopt, /*initial_prompts=*/{},
+                /*expected_context=*/"", kExpectedFormattedTestPrompt);
 }
 
 TEST_F(AITextSessionTest, PromptSessionWithSamplingParams) {
   RunPromptTest(kTestPrompt,
                 blink::mojom::AITextSessionSamplingParams::New(
                     /*top_k=*/10, /*temperature=*/0.6),
-                /*system_prompt=*/std::nullopt);
+                /*system_prompt=*/std::nullopt, /*initial_prompts=*/{},
+                /*expected_context=*/"", kExpectedFormattedTestPrompt);
 }
 
 TEST_F(AITextSessionTest, PromptSessionWithSystemPrompt) {
-  RunPromptTest(kTestPrompt, /*sampling_params=*/nullptr, kTestSystemPrompt);
+  RunPromptTest(kTestPrompt, /*sampling_params=*/nullptr, kTestSystemPrompts,
+                /*initial_prompts=*/{}, kExpectedFormattedSystemPrompts,
+                kExpectedFormattedTestPrompt);
 }
 
-// Tests `AITextSession::Context` creation without system prompt.
-TEST(AITextSessionContextCreationTest, CreateContext_WithoutSystemPrompt) {
+TEST_F(AITextSessionTest, PromptSessionWithInitialPrompts) {
+  RunPromptTest(kTestPrompt, /*sampling_params=*/nullptr,
+                /*system_prompt=*/std::nullopt, GetTestInitialPrompts(),
+                kExpectedFormattedInitialPrompts, kExpectedFormattedTestPrompt);
+}
+
+TEST_F(AITextSessionTest, PromptSessionWithSystemPromptAndInitialPrompts) {
+  RunPromptTest(kTestPrompt, /*sampling_params=*/nullptr, kTestSystemPrompts,
+                GetTestInitialPrompts(),
+                kExpectedFormattedSystemPromptAndInitialPrompts,
+                kExpectedFormattedTestPrompt);
+}
+
+// Tests `AITextSession::Context` creation without initial prompts.
+TEST(AITextSessionContextCreationTest, CreateContext_WithoutInitialPrompts) {
   AITextSession::Context context(kTestMaxContextToken, std::nullopt);
   EXPECT_FALSE(context.HasContextItem());
 }
 
-// Tests `AITextSession::Context` creation with valid system prompt.
-TEST(AITextSessionContextCreationTest, CreateContext_WithSystemPrompt_Normal) {
+// Tests `AITextSession::Context` creation with valid initial prompts.
+TEST(AITextSessionContextCreationTest,
+     CreateContext_WithInitialPrompts_Normal) {
   AITextSession::Context context(
       kTestMaxContextToken, AITextSession::Context::ContextItem{
-                                "system prompt\n", kTestSystemPromptToken});
+                                "initial prompts\n", kTestInitialPromptsToken});
   EXPECT_TRUE(context.HasContextItem());
 }
 
-// Tests `AITextSession::Context` creation with system prompt that exceeds the
+// Tests `AITextSession::Context` creation with initial prompts that exceeds the
 // max token limit.
 TEST(AITextSessionContextCreationTest,
-     CreateContext_WithSystemPrompt_Overflow) {
+     CreateContext_WithInitialPrompts_Overflow) {
   EXPECT_DEATH_IF_SUPPORTED(
       AITextSession::Context context(
           kTestMaxContextToken,
-          AITextSession::Context::ContextItem{"long system prompt\n",
+          AITextSession::Context::ContextItem{"long initial prompts\n",
                                               kTestMaxContextToken + 1u}),
       "");
 }
 
-// Tests the `AITextSession::Context` that's initialized with/without any system
-// prompt.
-class AITextSessionContextTest
-    : public testing::Test,
-      public testing::WithParamInterface</*is_init_with_system_prompt=*/bool> {
+// Tests the `AITextSession::Context` that's initialized with/without any
+// initial prompt.
+class AITextSessionContextTest : public testing::Test,
+                                 public testing::WithParamInterface<
+                                     /*is_init_with_initial_prompts=*/bool> {
  public:
-  bool IsInitializedWithSystemPrompt() { return GetParam(); }
+  bool IsInitializedWithInitialPrompts() { return GetParam(); }
 
   uint32_t GetMaxContextToken() {
-    return IsInitializedWithSystemPrompt()
-               ? kTestMaxContextToken - kTestSystemPromptToken
+    return IsInitializedWithInitialPrompts()
+               ? kTestMaxContextToken - kTestInitialPromptsToken
                : kTestMaxContextToken;
   }
 
-  std::string GetSystemPromptPrefix() {
-    return IsInitializedWithSystemPrompt() ? "system prompt\n" : "";
+  std::string GetInitialPromptsPrefix() {
+    return IsInitializedWithInitialPrompts() ? "initial prompts\n" : "";
   }
 
   AITextSession::Context context_{
       kTestMaxContextToken,
-      IsInitializedWithSystemPrompt()
+      IsInitializedWithInitialPrompts()
           ? std::optional<
-                AITextSession::Context::ContextItem>{{"system prompt",
-                                                      kTestSystemPromptToken}}
+                AITextSession::Context::ContextItem>{{"initial prompts",
+                                                      kTestInitialPromptsToken}}
           : std::nullopt};
 };
 
@@ -238,15 +280,15 @@
                          AITextSessionContextTest,
                          testing::Bool(),
                          [](const testing::TestParamInfo<bool>& info) {
-                           return info.param ? "WithSystemPrompt"
-                                             : "WithoutSystemPrompt";
+                           return info.param ? "WithInitialPrompts"
+                                             : "WithoutInitialPrompts";
                          });
 
 // Tests `GetContextString()` and `HasContextItem()` when the context is empty.
 TEST_P(AITextSessionContextTest, TestContextOperation_Empty) {
-  EXPECT_EQ(context_.GetContextString(), GetSystemPromptPrefix());
+  EXPECT_EQ(context_.GetContextString(), GetInitialPromptsPrefix());
 
-  if (IsInitializedWithSystemPrompt()) {
+  if (IsInitializedWithInitialPrompts()) {
     EXPECT_TRUE(context_.HasContextItem());
   } else {
     EXPECT_FALSE(context_.HasContextItem());
@@ -257,26 +299,26 @@
 // to the context.
 TEST_P(AITextSessionContextTest, TestContextOperation_NonEmpty) {
   context_.AddContextItem({"test", 1u});
-  EXPECT_EQ(context_.GetContextString(), GetSystemPromptPrefix() + "test");
+  EXPECT_EQ(context_.GetContextString(), GetInitialPromptsPrefix() + "test");
   EXPECT_TRUE(context_.HasContextItem());
 
   context_.AddContextItem({" test again", 2u});
   EXPECT_EQ(context_.GetContextString(),
-            GetSystemPromptPrefix() + "test test again");
+            GetInitialPromptsPrefix() + "test test again");
   EXPECT_TRUE(context_.HasContextItem());
 }
 
 // Tests `GetContextString()` and `HasContextItem()` when the items overflow.
 TEST_P(AITextSessionContextTest, TestContextOperation_Overflow) {
   context_.AddContextItem({"test", 1u});
-  EXPECT_EQ(context_.GetContextString(), GetSystemPromptPrefix() + "test");
+  EXPECT_EQ(context_.GetContextString(), GetInitialPromptsPrefix() + "test");
   EXPECT_TRUE(context_.HasContextItem());
 
   // Since the total number of tokens will exceed `kTestMaxContextToken`, the
   // old item will be evicted.
   context_.AddContextItem({"test long token", GetMaxContextToken()});
   EXPECT_EQ(context_.GetContextString(),
-            GetSystemPromptPrefix() + "test long token");
+            GetInitialPromptsPrefix() + "test long token");
   EXPECT_TRUE(context_.HasContextItem());
 }
 
@@ -284,8 +326,8 @@
 // the first insertion.
 TEST_P(AITextSessionContextTest, TestContextOperation_OverflowOnFirstItem) {
   context_.AddContextItem({"test very long token", GetMaxContextToken() + 1u});
-  EXPECT_EQ(context_.GetContextString(), GetSystemPromptPrefix());
-  if (IsInitializedWithSystemPrompt()) {
+  EXPECT_EQ(context_.GetContextString(), GetInitialPromptsPrefix());
+  if (IsInitializedWithInitialPrompts()) {
     EXPECT_TRUE(context_.HasContextItem());
   } else {
     EXPECT_FALSE(context_.HasContextItem());
diff --git a/chrome/browser/android/DEPS b/chrome/browser/android/DEPS
index c7ebac9..0d31842fc 100644
--- a/chrome/browser/android/DEPS
+++ b/chrome/browser/android/DEPS
@@ -11,7 +11,6 @@
   "+components/browser_ui/sms/android",
   "+components/browser_ui/util/android/url_constants.h",
   "+components/query_tiles",
-  "+components/sensitive_content",
   "+components/session_proto_db",
   "+components/webapk",
   "+device/vr/buildflags/buildflags.h",
diff --git a/chrome/browser/android/crypto/java/src/org/chromium/chrome/browser/crypto/CipherFactory.java b/chrome/browser/android/crypto/java/src/org/chromium/chrome/browser/crypto/CipherFactory.java
index 434facc..7970061 100644
--- a/chrome/browser/android/crypto/java/src/org/chromium/chrome/browser/crypto/CipherFactory.java
+++ b/chrome/browser/android/crypto/java/src/org/chromium/chrome/browser/crypto/CipherFactory.java
@@ -90,8 +90,12 @@
         return LazyHolder.sInstance;
     }
 
+    /** Constructor. Should only be called by {@link BaseCustomTabActivity}. */
+    public CipherFactory() {}
+
     /**
      * Creates a secure Cipher for encrypting data.
+     *
      * @param opmode One of Cipher.{ENCRYPT,DECRYPT}_MODE.
      * @return A Cipher, or null if it is not possible to instantiate one.
      */
@@ -196,6 +200,4 @@
 
         return false;
     }
-
-    private CipherFactory() {}
 }
diff --git a/chrome/browser/android/sensitive_content/OWNERS b/chrome/browser/android/sensitive_content/OWNERS
deleted file mode 100644
index c186703c..0000000
--- a/chrome/browser/android/sensitive_content/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-file://components/sensitive_content/OWNERS
diff --git a/chrome/browser/android/sensitive_content/chrome_sensitive_content_client.cc b/chrome/browser/android/sensitive_content/chrome_sensitive_content_client.cc
deleted file mode 100644
index 4feafa3..0000000
--- a/chrome/browser/android/sensitive_content/chrome_sensitive_content_client.cc
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2024 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/android/sensitive_content/chrome_sensitive_content_client.h"
-
-#include "content/public/browser/web_contents.h"
-
-namespace sensitive_content {
-
-ChromeSensitiveContentClient::ChromeSensitiveContentClient(
-    content::WebContents* web_contents)
-    : content::WebContentsUserData<ChromeSensitiveContentClient>(*web_contents),
-      manager_(web_contents, this) {}
-
-ChromeSensitiveContentClient::~ChromeSensitiveContentClient() = default;
-
-void ChromeSensitiveContentClient::SetContentSensitivity(
-    bool content_is_sensitive) {}
-
-std::string_view ChromeSensitiveContentClient::GetHistogramPrefix() {
-  return "SensitiveContent.Chrome.";
-}
-
-}  // namespace sensitive_content
diff --git a/chrome/browser/android/sensitive_content/chrome_sensitive_content_client.h b/chrome/browser/android/sensitive_content/chrome_sensitive_content_client.h
deleted file mode 100644
index 2d7e428f..0000000
--- a/chrome/browser/android/sensitive_content/chrome_sensitive_content_client.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2024 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_ANDROID_SENSITIVE_CONTENT_CHROME_SENSITIVE_CONTENT_CLIENT_H_
-#define CHROME_BROWSER_ANDROID_SENSITIVE_CONTENT_CHROME_SENSITIVE_CONTENT_CLIENT_H_
-
-#include "components/sensitive_content/sensitive_content_client.h"
-#include "components/sensitive_content/sensitive_content_manager.h"
-#include "content/public/browser/web_contents_user_data.h"
-
-namespace content {
-class WebContents;
-}  // namespace content
-
-namespace sensitive_content {
-
-class ChromeSensitiveContentClient
-    : public SensitiveContentClient,
-      public content::WebContentsUserData<ChromeSensitiveContentClient> {
- public:
-  explicit ChromeSensitiveContentClient(content::WebContents* web_contents);
-
-  ChromeSensitiveContentClient(const ChromeSensitiveContentClient&) = delete;
-  ChromeSensitiveContentClient& operator=(const ChromeSensitiveContentClient&) =
-      delete;
-  ~ChromeSensitiveContentClient() override;
-
-  void SetContentSensitivity(bool content_is_sensitive) override;
-
-  std::string_view GetHistogramPrefix() override;
-
- private:
-  SensitiveContentManager manager_;
-};
-
-}  // namespace sensitive_content
-
-#endif  // CHROME_BROWSER_ANDROID_SENSITIVE_CONTENT_CHROME_SENSITIVE_CONTENT_CLIENT_H_
diff --git a/chrome/browser/apps/app_service/media_access_browsertest.cc b/chrome/browser/apps/app_service/media_access_browsertest.cc
index 46051a3..862313c2c 100644
--- a/chrome/browser/apps/app_service/media_access_browsertest.cc
+++ b/chrome/browser/apps/app_service/media_access_browsertest.cc
@@ -11,6 +11,7 @@
 #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
 #include "chrome/browser/media/webrtc/media_stream_capture_indicator.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h"
 #include "chrome/browser/ui/web_applications/web_app_browsertest_base.h"
diff --git a/chrome/browser/apps/app_shim/BUILD.gn b/chrome/browser/apps/app_shim/BUILD.gn
index 6919b30a..67d4c6c7 100644
--- a/chrome/browser/apps/app_shim/BUILD.gn
+++ b/chrome/browser/apps/app_shim/BUILD.gn
@@ -34,6 +34,7 @@
     "//chrome/browser/apps/app_service",
     "//chrome/browser/apps/app_service:constants",
     "//chrome/browser/profiles:profile",
+    "//chrome/browser/ui:browser_list",
     "//chrome/browser/ui:ui_features",
     "//chrome/browser/web_applications:web_applications",
     "//chrome/common",
diff --git a/chrome/browser/apps/platform_apps/BUILD.gn b/chrome/browser/apps/platform_apps/BUILD.gn
index e6d0f89..3d976867 100644
--- a/chrome/browser/apps/platform_apps/BUILD.gn
+++ b/chrome/browser/apps/platform_apps/BUILD.gn
@@ -60,6 +60,7 @@
     "//chrome/browser/media/router/discovery",
     "//chrome/browser/profiles",
     "//chrome/browser/profiles:profile",
+    "//chrome/browser/ui:browser_list",
     "//chrome/browser/web_applications",
     "//chrome/browser/web_applications/extensions",
     "//chrome/common",
diff --git a/chrome/browser/ash/BUILD.gn b/chrome/browser/ash/BUILD.gn
index 90e8eea..d0dba67 100644
--- a/chrome/browser/ash/BUILD.gn
+++ b/chrome/browser/ash/BUILD.gn
@@ -27,8 +27,6 @@
     "browser_context_keyed_service_factories.h",
     "chrome_browser_main_parts_ash.cc",
     "chrome_browser_main_parts_ash.h",
-    "idle_detector.cc",
-    "idle_detector.h",
     "system_token_cert_db_initializer.cc",
     "system_token_cert_db_initializer.h",
     "tpm_firmware_update.cc",
diff --git a/chrome/browser/ash/accessibility/accessibility_extension_api_browsertest.cc b/chrome/browser/ash/accessibility/accessibility_extension_api_browsertest.cc
index 537cc04..fb51dbdf 100644
--- a/chrome/browser/ash/accessibility/accessibility_extension_api_browsertest.cc
+++ b/chrome/browser/ash/accessibility/accessibility_extension_api_browsertest.cc
@@ -15,6 +15,7 @@
 #include "chrome/browser/ash/accessibility/dictation_bubble_test_helper.h"
 #include "chrome/browser/ash/system_web_apps/system_web_app_manager.h"
 #include "chrome/browser/extensions/extension_apitest.h"
+#include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/chrome_pages.h"
 #include "chrome/browser/ui/settings_window_manager_chromeos.h"
diff --git a/chrome/browser/ash/app_list/BUILD.gn b/chrome/browser/ash/app_list/BUILD.gn
index 4d04d0f..e14beb23 100644
--- a/chrome/browser/ash/app_list/BUILD.gn
+++ b/chrome/browser/ash/app_list/BUILD.gn
@@ -81,6 +81,7 @@
     "//chrome/browser/ash/crosapi:browser_util",
     "//chrome/browser/scalable_iph:scalable_iph_factory",
     "//chrome/browser/search_engines",
+    "//chrome/browser/ui:browser_list",
     "//chrome/browser/ui:browser_navigator_params_headers",
     "//chrome/browser/ui/ash/app_icon_color_cache",
     "//chrome/browser/ui/webui/ash/settings/app_management",
diff --git a/chrome/browser/ash/boca/on_task/BUILD.gn b/chrome/browser/ash/boca/on_task/BUILD.gn
index b0f0dcf65..6408f1a 100644
--- a/chrome/browser/ash/boca/on_task/BUILD.gn
+++ b/chrome/browser/ash/boca/on_task/BUILD.gn
@@ -18,6 +18,7 @@
 
   public_deps = [
     "//chrome/browser:browser_public_dependencies",
+    "//chrome/browser/ui:browser_list",
     "//chrome/browser/ui/tabs:tab_strip_model_observer",
   ]
 
diff --git a/chrome/browser/ash/boot_times_recorder/BUILD.gn b/chrome/browser/ash/boot_times_recorder/BUILD.gn
index 238295f2..803fc79 100644
--- a/chrome/browser/ash/boot_times_recorder/BUILD.gn
+++ b/chrome/browser/ash/boot_times_recorder/BUILD.gn
@@ -19,6 +19,7 @@
   deps = [
     "//base",
     "//chrome/browser:browser_process",
+    "//chrome/browser/ui:browser_list",
     "//chrome/common",
     "//chromeos/ash/components/metrics",
     "//components/prefs",
diff --git a/chrome/browser/ash/child_accounts/BUILD.gn b/chrome/browser/ash/child_accounts/BUILD.gn
index 9c6ca331..76231295 100644
--- a/chrome/browser/ash/child_accounts/BUILD.gn
+++ b/chrome/browser/ash/child_accounts/BUILD.gn
@@ -87,6 +87,7 @@
     "//chrome/browser/ash/settings",
     "//chrome/browser/profiles:profile",
     "//chrome/browser/profiles:profiles",
+    "//chrome/browser/ui:browser_list",
     "//chrome/common",
     "//chrome/common:constants",
     "//chromeos/ash/components/dbus",
diff --git a/chrome/browser/ash/child_accounts/time_limits/BUILD.gn b/chrome/browser/ash/child_accounts/time_limits/BUILD.gn
index f1461e0f..3f9deff 100644
--- a/chrome/browser/ash/child_accounts/time_limits/BUILD.gn
+++ b/chrome/browser/ash/child_accounts/time_limits/BUILD.gn
@@ -45,6 +45,7 @@
     "//ash/public/cpp",
     "//chrome/browser/ash/app_list/arc",
     "//chrome/browser/profiles:profile",
+    "//chrome/browser/ui:browser_list",
     "//chrome/common",
     "//chromeos/crosapi/mojom",
     "//chromeos/ui/vector_icons",
diff --git a/chrome/browser/ash/eche_app/BUILD.gn b/chrome/browser/ash/eche_app/BUILD.gn
index 7d274d7..7537229 100644
--- a/chrome/browser/ash/eche_app/BUILD.gn
+++ b/chrome/browser/ash/eche_app/BUILD.gn
@@ -42,6 +42,7 @@
     "//chrome/browser/ash/profiles",
     "//chrome/browser/ash/secure_channel",
     "//chrome/browser/ash/system_web_apps/types",
+    "//chrome/browser/ui:browser_list",
     "//chrome/common:channel_info",
     "//chromeos/ash/components/multidevice/logging",
     "//chromeos/ash/components/phonehub",
diff --git a/chrome/browser/ash/extensions/autotest_private/BUILD.gn b/chrome/browser/ash/extensions/autotest_private/BUILD.gn
index eb94e56..b01ea8e3 100644
--- a/chrome/browser/ash/extensions/autotest_private/BUILD.gn
+++ b/chrome/browser/ash/extensions/autotest_private/BUILD.gn
@@ -49,6 +49,7 @@
     "//chrome/browser/ash/settings",
     "//chrome/browser/ash/system",
     "//chrome/browser/ash/system_web_apps",
+    "//chrome/browser/ui:browser_list",
     "//chrome/browser/ui/ash/default_pinned_apps",
     "//chrome/browser/ui/aura/accessibility",
     "//chrome/browser/ui/views/bruschetta",
diff --git a/chrome/browser/ash/extensions/file_manager/DEPS b/chrome/browser/ash/extensions/file_manager/DEPS
index 6905392d..44bd5bc 100644
--- a/chrome/browser/ash/extensions/file_manager/DEPS
+++ b/chrome/browser/ash/extensions/file_manager/DEPS
@@ -59,6 +59,7 @@
   "+chrome/browser/ui/ash/holding_space",
   "+chrome/browser/ui/ash/multi_user",
   "+chrome/browser/ui/ash/system_web_apps",
+  "+chrome/browser/ui/browser.h",
   "+chrome/browser/ui/browser_list.h",
   "+chrome/browser/ui/browser_window.h",
   "+chrome/browser/ui/chrome_pages.h",
diff --git a/chrome/browser/ash/extensions/file_manager/file_manager_private_apitest.cc b/chrome/browser/ash/extensions/file_manager/file_manager_private_apitest.cc
index 3f7a972..74171bc1 100644
--- a/chrome/browser/ash/extensions/file_manager/file_manager_private_apitest.cc
+++ b/chrome/browser/ash/extensions/file_manager/file_manager_private_apitest.cc
@@ -52,6 +52,7 @@
 #include "chrome/browser/chromeos/policy/dlp/test/mock_dlp_rules_manager.h"
 #include "chrome/browser/extensions/extension_apitest.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
+#include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/chrome_paths.h"
diff --git a/chrome/browser/ash/growth/BUILD.gn b/chrome/browser/ash/growth/BUILD.gn
index 4cdcf58..2dd6b62 100644
--- a/chrome/browser/ash/growth/BUILD.gn
+++ b/chrome/browser/ash/growth/BUILD.gn
@@ -41,6 +41,7 @@
     "//chrome/browser/ash/login/demo_mode",
     "//chrome/browser/ash/ownership",
     "//chrome/browser/ash/system_web_apps",
+    "//chrome/browser/ui:browser_list",
     "//chromeos/ash/components/growth",
     "//chromeos/ash/components/growth:config_provider",
     "//chromeos/ash/components/growth:utils",
diff --git a/chrome/browser/ash/login/demo_mode/DEPS b/chrome/browser/ash/login/demo_mode/DEPS
index 77b474e..b3c7fb4 100644
--- a/chrome/browser/ash/login/demo_mode/DEPS
+++ b/chrome/browser/ash/login/demo_mode/DEPS
@@ -18,7 +18,6 @@
   "+chrome/browser/apps/platform_apps",
   "+chrome/browser/ash/extensions",
   "+chrome/browser/ash/file_manager",
-  "+chrome/browser/ash/idle_detector.h",
   "+chrome/browser/ash/login",
   "+chrome/browser/ash/policy/core",
   "+chrome/browser/ash/policy/enrollment",
diff --git a/chrome/browser/ash/login/login_ui_keyboard_browsertest.cc b/chrome/browser/ash/login/login_ui_keyboard_browsertest.cc
index 9ef5ca3e..0a09a5a 100644
--- a/chrome/browser/ash/login/login_ui_keyboard_browsertest.cc
+++ b/chrome/browser/ash/login/login_ui_keyboard_browsertest.cc
@@ -32,12 +32,12 @@
 #include "chrome/browser/ash/policy/core/device_policy_cros_browser_test.h"
 #include "chrome/browser/ash/settings/stub_cros_settings_provider.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/ui/ash/login_screen_shown_observer.h"
 #include "chrome/browser/ui/webui/ash/login/user_creation_screen_handler.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/ash/components/language_preferences/language_preferences.h"
 #include "chromeos/ash/components/login/auth/public/user_context.h"
 #include "chromeos/ash/components/settings/cros_settings_names.h"
+#include "chromeos/ash/experiences/login/login_screen_shown_observer.h"
 #include "components/account_id/account_id.h"
 #include "components/prefs/pref_service.h"
 #include "components/user_manager/known_user.h"
diff --git a/chrome/browser/ash/login/screens/BUILD.gn b/chrome/browser/ash/login/screens/BUILD.gn
index a59df9d..b95251e6 100644
--- a/chrome/browser/ash/login/screens/BUILD.gn
+++ b/chrome/browser/ash/login/screens/BUILD.gn
@@ -195,6 +195,7 @@
     "//chromeos/ash/components/login/auth/public:authpublic",
     "//chromeos/ash/components/network",
     "//chromeos/ash/components/proximity_auth",
+    "//chromeos/ash/experiences/idle_detector",
     "//chromeos/ash/services/device_sync:group_private_key_and_better_together_metadata_status",
     "//chromeos/ash/services/nearby/public/mojom",
     "//chromeos/dbus/power",
diff --git a/chrome/browser/ash/login/screens/DEPS b/chrome/browser/ash/login/screens/DEPS
index 526d7b4..1cdecf5 100644
--- a/chrome/browser/ash/login/screens/DEPS
+++ b/chrome/browser/ash/login/screens/DEPS
@@ -30,7 +30,6 @@
   "+chrome/browser/ash/customization",
   "+chrome/browser/ash/device_sync",
   "+chrome/browser/ash/drive",
-  "+chrome/browser/ash/idle_detector.h",
   "+chrome/browser/ash/login",
   "+chrome/browser/ash/multidevice_setup",
   "+chrome/browser/ash/net",
diff --git a/chrome/browser/ash/login/screens/chromevox_hint/BUILD.gn b/chrome/browser/ash/login/screens/chromevox_hint/BUILD.gn
index 573b68f..3993df3 100644
--- a/chrome/browser/ash/login/screens/chromevox_hint/BUILD.gn
+++ b/chrome/browser/ash/login/screens/chromevox_hint/BUILD.gn
@@ -16,6 +16,7 @@
 
   deps = [
     "//ash/constants",
+    "//chromeos/ash/experiences/idle_detector",
     "//chromeos/dbus/constants",
   ]
 }
diff --git a/chrome/browser/ash/login/screens/chromevox_hint/chromevox_hint_detector.cc b/chrome/browser/ash/login/screens/chromevox_hint/chromevox_hint_detector.cc
index e2ef8ba3..ff60a89c 100644
--- a/chrome/browser/ash/login/screens/chromevox_hint/chromevox_hint_detector.cc
+++ b/chrome/browser/ash/login/screens/chromevox_hint/chromevox_hint_detector.cc
@@ -9,7 +9,7 @@
 #include "base/check.h"
 #include "base/command_line.h"
 #include "base/functional/bind.h"
-#include "chrome/browser/ash/idle_detector.h"
+#include "chromeos/ash/experiences/idle_detector/idle_detector.h"
 #include "chromeos/dbus/constants/dbus_switches.h"
 
 namespace ash {
diff --git a/chrome/browser/ash/login/screens/offline_login_screen.h b/chrome/browser/ash/login/screens/offline_login_screen.h
index 7ce3be5..976ab139 100644
--- a/chrome/browser/ash/login/screens/offline_login_screen.h
+++ b/chrome/browser/ash/login/screens/offline_login_screen.h
@@ -9,9 +9,9 @@
 
 #include "base/functional/callback.h"
 #include "base/scoped_observation.h"
-#include "chrome/browser/ash/idle_detector.h"
 #include "chrome/browser/ash/login/screens/base_screen.h"
 #include "chrome/browser/ui/webui/ash/login/network_state_informer.h"
+#include "chromeos/ash/experiences/idle_detector/idle_detector.h"
 
 namespace ash {
 
diff --git a/chrome/browser/ash/login/test/user_adding_screen_utils.cc b/chrome/browser/ash/login/test/user_adding_screen_utils.cc
index 963e3902..479e844 100644
--- a/chrome/browser/ash/login/test/user_adding_screen_utils.cc
+++ b/chrome/browser/ash/login/test/user_adding_screen_utils.cc
@@ -7,7 +7,7 @@
 #include "base/run_loop.h"
 #include "chrome/browser/ash/login/ui/user_adding_screen.h"
 #include "chrome/browser/ui/ash/login/login_screen_client_impl.h"
-#include "chrome/browser/ui/ash/login_screen_shown_observer.h"
+#include "chromeos/ash/experiences/login/login_screen_shown_observer.h"
 
 namespace ash {
 namespace test {
diff --git a/chrome/browser/ash/login/ui/BUILD.gn b/chrome/browser/ash/login/ui/BUILD.gn
index 50f6ccd..c3791a77 100644
--- a/chrome/browser/ash/login/ui/BUILD.gn
+++ b/chrome/browser/ash/login/ui/BUILD.gn
@@ -55,6 +55,7 @@
     "//chrome/browser:primitives",
     "//chrome/browser/ash/customization",
     "//chrome/browser/ash/login/oobe_quick_start",
+    "//chrome/browser/ui:browser_list",
     "//chrome/browser/ui/ash/keyboard",
     "//chromeos/ash/components/audio",
     "//chromeos/ash/components/dbus/session_manager",
@@ -111,6 +112,7 @@
     "//chrome/browser/profiles:profile",
     "//chrome/browser/safe_browsing",
     "//chrome/browser/themes",
+    "//chrome/browser/ui/autofill",
     "//chrome/browser/ui/content_settings",
     "//chrome/browser/ui/views/toolbar",
     "//chrome/browser/ui/webui/ash/diagnostics_dialog",
diff --git a/chrome/browser/ash/net/secure_dns_manager.cc b/chrome/browser/ash/net/secure_dns_manager.cc
index 12bd06f..335610a 100644
--- a/chrome/browser/ash/net/secure_dns_manager.cc
+++ b/chrome/browser/ash/net/secure_dns_manager.cc
@@ -37,19 +37,94 @@
 #include "net/dns/public/secure_dns_mode.h"
 #include "third_party/cros_system_api/dbus/shill/dbus-constants.h"
 
+namespace {
+void MigratePrefIfNecessary(const std::string& pref_name,
+                            PrefService* from_local_state,
+                            PrefService* to_profile_prefs) {
+  const base::Value* user_pref_value =
+      to_profile_prefs->GetUserPrefValue(pref_name);
+  // If there's already a user-set value in the profile prefs, do not override
+  // it.
+  if (user_pref_value) {
+    return;
+  }
+  const base::Value* pref_value = from_local_state->GetUserPrefValue(pref_name);
+  if (!pref_value) {
+    return;
+  }
+  to_profile_prefs->Set(pref_name, *pref_value);
+
+  // TODO(b/323547098): Clear the DoH user-set local state pref once the
+  // migration code has ran for a couple of milestones.
+  //  from_local_state->ClearPref(pref_name);
+}
+
+bool IsUserSetSecureDnsConfigInvalid(const PrefService* local_state) {
+  const base::Value* secure_dns_mode =
+      local_state->GetUserPrefValue(::prefs::kDnsOverHttpsMode);
+
+  // Can be missing in tests.
+  if (!secure_dns_mode) {
+    return false;
+  }
+  if (*secure_dns_mode != base::Value(SecureDnsConfig::kModeSecure)) {
+    return false;
+  }
+
+  const base::Value* secure_dns_template =
+      local_state->GetUserPrefValue(::prefs::kDnsOverHttpsTemplates);
+  if (!secure_dns_template || *secure_dns_template == base::Value()) {
+    return true;
+  }
+
+  return false;
+}
+
+// Although DNS configurations are user specific, the initial implementation
+// stored the secure DNS config to local_state, making it available to all users
+// of the device. Part of restricting the user-set secure DNS preference to the
+// user session is migrating the related preferences from local_state to profile
+// prefs. See b/323547098 for details.
+void MigrateDnsOverHttpsPrefs(PrefService* from_local_state,
+                              PrefService* to_profile_prefs) {
+  if (IsUserSetSecureDnsConfigInvalid(from_local_state)) {
+    // Remove the invalid config. See b/335400734.
+    from_local_state->ClearPref(::prefs::kDnsOverHttpsMode);
+    return;
+  }
+  // Migrate local state to user pref.
+  MigratePrefIfNecessary(::prefs::kDnsOverHttpsTemplates, from_local_state,
+                         to_profile_prefs);
+  MigratePrefIfNecessary(::prefs::kDnsOverHttpsMode, from_local_state,
+                         to_profile_prefs);
+}
+}  // namespace
 namespace ash {
 
 SecureDnsManager::SecureDnsManager(PrefService* local_state,
+                                   PrefService* profile_prefs,
                                    bool is_profile_managed)
-    : local_state_(local_state) {
+    : local_state_(local_state),
+      profile_prefs_(profile_prefs),
+      is_profile_managed_(is_profile_managed) {
+  if (!is_profile_managed) {
+    CHECK(profile_prefs) << "Profile prefs cannot be empty for unmanaged users";
+    MigrateDnsOverHttpsPrefs(local_state, profile_prefs);
+  }
   doh_templates_uri_resolver_ =
       std::make_unique<dns_over_https::TemplatesUriResolverImpl>();
 
-  MonitorPolicyPrefs();
   LoadProviders();
-  OnPolicyPrefChanged();
-  OnDoHIncludedDomainsPrefChanged();
-  OnDoHExcludedDomainsPrefChanged();
+
+  if (is_profile_managed) {
+    MonitorLocalStatePrefs();
+    OnLocalStatePrefsChanged();
+    OnDoHIncludedDomainsPrefChanged();
+    OnDoHExcludedDomainsPrefChanged();
+  } else {
+    MonitorUserPrefs();
+    OnPrefChanged();
+  }
 
   // The DNS-over-HTTPS config source is reset in the destructor of the
   // `SecureDnsManager`. This means the `SecureDnsManager` instance should
@@ -60,7 +135,40 @@
           std::make_unique<AshDnsOverHttpsConfigSource>(this, local_state));
 }
 
-void SecureDnsManager::MonitorPolicyPrefs() {
+void SecureDnsManager::SetPrimaryProfilePropertiesForTesting(
+    PrefService* profile_prefs,
+    bool is_profile_managed) {
+  profile_prefs_registrar_.Reset();
+  local_state_registrar_.Reset();
+  is_profile_managed_ = is_profile_managed;
+
+  if (is_profile_managed) {
+    MonitorLocalStatePrefs();
+    OnLocalStatePrefsChanged();
+    OnDoHIncludedDomainsPrefChanged();
+    OnDoHExcludedDomainsPrefChanged();
+  } else {
+    MonitorUserPrefs();
+    OnPrefChanged();
+  }
+}
+
+void SecureDnsManager::MonitorUserPrefs() {
+  profile_prefs_->SetDefaultPrefValue(
+      ::prefs::kDnsOverHttpsMode,
+      local_state_->GetDefaultPrefValue(::prefs::kDnsOverHttpsMode)->Clone());
+
+  profile_prefs_registrar_.Init(profile_prefs_);
+  profile_prefs_registrar_.Add(
+      ::prefs::kDnsOverHttpsMode,
+      base::BindRepeating(&SecureDnsManager::OnPrefChanged,
+                          base::Unretained(this)));
+  profile_prefs_registrar_.Add(
+      ::prefs::kDnsOverHttpsTemplates,
+      base::BindRepeating(&SecureDnsManager::OnPrefChanged,
+                          base::Unretained(this)));
+}
+void SecureDnsManager::MonitorLocalStatePrefs() {
   local_state_registrar_.Init(local_state_);
   static constexpr std::array<const char*, 4> secure_dns_pref_names = {
       ::prefs::kDnsOverHttpsMode, ::prefs::kDnsOverHttpsTemplates,
@@ -68,8 +176,9 @@
       ::prefs::kDnsOverHttpsSalt};
   for (auto* const pref_name : secure_dns_pref_names) {
     local_state_registrar_.Add(
-        pref_name, base::BindRepeating(&SecureDnsManager::OnPolicyPrefChanged,
-                                       base::Unretained(this)));
+        pref_name,
+        base::BindRepeating(&SecureDnsManager::OnLocalStatePrefsChanged,
+                            base::Unretained(this)));
   }
   local_state_registrar_.Add(
       prefs::kDnsOverHttpsIncludedDomains,
@@ -192,7 +301,22 @@
   UpdateTemplateUri();
 }
 
-void SecureDnsManager::OnPolicyPrefChanged() {
+void SecureDnsManager::OnPrefChanged() {
+  CHECK(profile_prefs_);
+  bool template_uris_changed =
+      profile_prefs_->GetString(::prefs::kDnsOverHttpsTemplates) !=
+      cached_template_uris_;
+  bool mode_changed =
+      profile_prefs_->GetString(::prefs::kDnsOverHttpsMode) != cached_mode_;
+
+  cached_template_uris_ =
+      profile_prefs_->GetString(::prefs::kDnsOverHttpsTemplates);
+  cached_mode_ = profile_prefs_->GetString(::prefs::kDnsOverHttpsMode);
+
+  BroadcastUpdates(template_uris_changed, mode_changed);
+}
+
+void SecureDnsManager::OnLocalStatePrefsChanged() {
   UpdateTemplateUri();
   ToggleNetworkMonitoring();
 }
@@ -287,10 +411,16 @@
 void SecureDnsManager::UpdateTemplateUri() {
   doh_templates_uri_resolver_->Update(local_state_);
 
-  const std::string new_templates =
+  std::string new_templates =
       doh_templates_uri_resolver_->GetEffectiveTemplates();
-  const std::string new_mode =
-      local_state_->GetString(::prefs::kDnsOverHttpsMode);
+  std::string new_mode = local_state_->GetString(::prefs::kDnsOverHttpsMode);
+
+  // The DoH config is stored in the local_state only when controlled by policy.
+  // If the local_state DoH pref is user-set, it should be ignored.
+  if (!local_state_->IsManagedPreference(::prefs::kDnsOverHttpsMode)) {
+    new_mode = SecureDnsConfig::kModeOff;
+    new_templates = std::string();
+  }
 
   bool template_uris_changed = new_templates != cached_template_uris_;
   bool mode_changed = new_mode != cached_mode_;
@@ -305,14 +435,23 @@
 
   // May be missing in tests.
   if (NetworkHandler::Get()->network_metadata_store()) {
+    // TODO(b/323547098): Remove the pref management check. In older OS
+    // versions, user DoH settings were in local_state, but DoH with identifiers
+    // is enterprise-only feature.
     NetworkHandler::Get()
         ->network_metadata_store()
         ->SetSecureDnsTemplatesWithIdentifiersActive(
-            doh_templates_uri_resolver_->GetDohWithIdentifiersActive());
+            doh_templates_uri_resolver_->GetDohWithIdentifiersActive() &&
+            local_state_->IsManagedPreference(::prefs::kDnsOverHttpsMode));
   }
 }
 
 // static
+void SecureDnsManager::RegisterProfilePrefs(PrefRegistrySimple* registry) {
+  registry->RegisterStringPref(::prefs::kDnsOverHttpsMode, std::string());
+  registry->RegisterStringPref(::prefs::kDnsOverHttpsTemplates, std::string());
+}
+// static
 void SecureDnsManager::RegisterLocalStatePrefs(PrefRegistrySimple* registry) {
   registry->RegisterStringPref(::prefs::kDnsOverHttpsSalt, std::string());
   registry->RegisterStringPref(::prefs::kDnsOverHttpsTemplatesWithIdentifiers,
diff --git a/chrome/browser/ash/net/secure_dns_manager.h b/chrome/browser/ash/net/secure_dns_manager.h
index e6606b66..a10c934b6 100644
--- a/chrome/browser/ash/net/secure_dns_manager.h
+++ b/chrome/browser/ash/net/secure_dns_manager.h
@@ -26,6 +26,12 @@
 // Responds to changes in the SecureDNS preferences from the local state and
 // generates and updates the corresponding shill property which can then be used
 // by downstream services.
+// The enterprise policies which control secure DNS settings in the browser are
+// cross-platform policies that map to local state. This is required because the
+// DNS config is global in the Network Service. On ChromeOS, local state is
+// shared between all user sessions (including guest). For this reason, the
+// user-set preferences map to the pref service that belongs to the primary
+// profile.
 class SecureDnsManager : public NetworkStateHandlerObserver {
  public:
   // Observes changes in the DNS-over-HTTPS configuration.
@@ -46,14 +52,14 @@
   void AddObserver(Observer* observer);
   void RemoveObserver(Observer* observer);
 
-  // If `is_profile_managed` is true, then the secure DNS settings can only be
-  // configured by enterprise policy; otherwise the secure DNS settings can be
-  // configured by the user in the settings UI.
-  SecureDnsManager(PrefService* local_state, bool is_profile_managed);
+  SecureDnsManager(PrefService* local_state,
+                   PrefService* profile_prefs,
+                   bool is_profile_managed);
   SecureDnsManager(const SecureDnsManager&) = delete;
   SecureDnsManager& operator=(const SecureDnsManager&) = delete;
   ~SecureDnsManager() override;
 
+  static void RegisterProfilePrefs(PrefRegistrySimple* registry);
   static void RegisterLocalStatePrefs(PrefRegistrySimple* registry);
 
   void SetDoHTemplatesUriResolverForTesting(
@@ -65,6 +71,9 @@
   // plain text version of the URI templates. Otherwise returns nullopt.
   std::optional<std::string> GetDohWithIdentifiersDisplayServers() const;
 
+  void SetPrimaryProfilePropertiesForTesting(PrefService* profile_prefs,
+                                             bool is_profile_managed);
+
  private:
   void DefaultNetworkChanged(const NetworkState* network) override;
 
@@ -78,13 +87,16 @@
   base::Value::Dict GetProviders(const std::string& mode,
                                  const std::string& templates) const;
 
+  // Starts tracking user-configured secure DNS settings. This settings are
+  // mapped to the pref service that belongs to the profile associated with the
+  // primary user.
+  void MonitorUserPrefs();
+  void OnPrefChanged();
+
   // Starts tracking secure DNS enterprise policy changes. The policy values are
   // mapped by the policy service to the local state pref service.
-  void MonitorPolicyPrefs();
-
-  // Callback for the registrar. Evaluates the current settings and publishes
-  // the result to shill.
-  void OnPolicyPrefChanged();
+  void MonitorLocalStatePrefs();
+  void OnLocalStatePrefsChanged();
 
   void OnDoHIncludedDomainsPrefChanged();
   void OnDoHExcludedDomainsPrefChanged();
@@ -104,8 +116,8 @@
   base::ScopedObservation<NetworkStateHandler, NetworkStateHandlerObserver>
       network_state_handler_observer_{this};
 
-  PrefChangeRegistrar local_state_registrar_;
-  raw_ptr<PrefService> local_state_;
+  PrefChangeRegistrar local_state_registrar_, profile_prefs_registrar_;
+  raw_ptr<PrefService> local_state_, profile_prefs_;
 
   // Maps secure DNS provider URL templates to their corresponding standard DNS
   // name servers. Providers that are either disabled or not applicable for the
@@ -118,7 +130,9 @@
 
   std::string cached_template_uris_;
   std::string cached_mode_;
+
   bool cached_is_config_managed_ = false;
+  bool is_profile_managed_ = false;
 
   base::ObserverList<Observer> observers_;
 };
diff --git a/chrome/browser/ash/net/secure_dns_manager_unittest.cc b/chrome/browser/ash/net/secure_dns_manager_unittest.cc
index 1c17f57..c7ebb8d9 100644
--- a/chrome/browser/ash/net/secure_dns_manager_unittest.cc
+++ b/chrome/browser/ash/net/secure_dns_manager_unittest.cc
@@ -174,15 +174,15 @@
   SecureDnsManagerTest& operator=(const SecureDnsManagerTest&) = delete;
 
   void SetUp() override {
+    SecureDnsManager::RegisterProfilePrefs(profile_prefs_.registry());
+    SecureDnsManager::RegisterLocalStatePrefs(local_state_.registry());
+
     local_state_.registry()->RegisterStringPref(::prefs::kDnsOverHttpsMode,
                                                 SecureDnsConfig::kModeOff);
     local_state_.registry()->RegisterStringPref(::prefs::kDnsOverHttpsTemplates,
                                                 "");
     local_state_.registry()->RegisterStringPref(
-        ::prefs::kDnsOverHttpsTemplatesWithIdentifiers, "");
-    local_state_.registry()->RegisterStringPref(
         ::prefs::kDnsOverHttpsEffectiveTemplatesChromeOS, "");
-    local_state_.registry()->RegisterStringPref(::prefs::kDnsOverHttpsSalt, "");
     local_state_.registry()->RegisterListPref(
         prefs::kDnsOverHttpsExcludedDomains, base::Value::List());
     local_state_.registry()->RegisterListPref(
@@ -193,7 +193,8 @@
         ::prefs::kAdditionalDnsQueryTypesEnabled, true);
     network_handler_test_helper_.RegisterPrefs(profile_prefs_.registry(),
                                                local_state_.registry());
-    network_handler_test_helper_.InitializePrefs(&local_state_, &local_state_);
+    network_handler_test_helper_.InitializePrefs(&profile_prefs_,
+                                                 &local_state_);
     network_handler_test_helper_.AddDefaultProfiles();
 
     // SystemNetworkContextManager cannot be instantiated here,
@@ -205,7 +206,7 @@
         stub_resolver_config_reader_.get());
 
     secure_dns_manager_ = std::make_unique<SecureDnsManager>(
-        local_state(), /*is_profile_managed=*/true);
+        local_state(), /*profile_prefs=*/nullptr, /*is_profile_managed=*/true);
     secure_dns_manager_observer_ =
         std::make_unique<SecureDnsManagerObserver>(secure_dns_manager_.get());
   }
@@ -227,7 +228,7 @@
         path, shill::kUIDataProperty, base::Value(ui_data->GetAsJson()));
   }
 
-  PrefService* local_state() { return &local_state_; }
+  TestingPrefServiceSimple* local_state() { return &local_state_; }
   PrefService* profile_prefs() { return &profile_prefs_; }
   SecureDnsManager* secure_dns_manager() { return secure_dns_manager_.get(); }
   SecureDnsManagerObserver* secure_dns_manager_observer() {
@@ -276,8 +277,8 @@
 }
 
 TEST_F(SecureDnsManagerTest, SetModeSecure) {
-  local_state()->Set(::prefs::kDnsOverHttpsMode,
-                     base::Value(SecureDnsConfig::kModeSecure));
+  local_state()->SetManagedPref(::prefs::kDnsOverHttpsMode,
+                                base::Value(SecureDnsConfig::kModeSecure));
   local_state()->Set(::prefs::kDnsOverHttpsTemplates, base::Value(kGoogleDns));
 
   auto providers = GetDOHProviders();
@@ -294,8 +295,8 @@
 }
 
 TEST_F(SecureDnsManagerTest, SetModeSecureMultipleTemplates) {
-  local_state()->Set(::prefs::kDnsOverHttpsMode,
-                     base::Value(SecureDnsConfig::kModeSecure));
+  local_state()->SetManagedPref(::prefs::kDnsOverHttpsMode,
+                                base::Value(SecureDnsConfig::kModeSecure));
   local_state()->Set(::prefs::kDnsOverHttpsTemplates,
                      base::Value(kMultipleTemplates));
 
@@ -315,8 +316,8 @@
 }
 
 TEST_F(SecureDnsManagerTest, SetModeSecureWithFallback) {
-  local_state()->Set(::prefs::kDnsOverHttpsMode,
-                     base::Value(SecureDnsConfig::kModeAutomatic));
+  local_state()->SetManagedPref(::prefs::kDnsOverHttpsMode,
+                                base::Value(SecureDnsConfig::kModeAutomatic));
   local_state()->Set(::prefs::kDnsOverHttpsTemplates, base::Value(kGoogleDns));
 
   auto providers = GetDOHProviders();
@@ -329,8 +330,8 @@
 }
 
 TEST_F(SecureDnsManagerTest, SetModeSecureWithFallbackMultipleTemplates) {
-  local_state()->Set(::prefs::kDnsOverHttpsMode,
-                     base::Value(SecureDnsConfig::kModeAutomatic));
+  local_state()->SetManagedPref(::prefs::kDnsOverHttpsMode,
+                                base::Value(SecureDnsConfig::kModeAutomatic));
   local_state()->Set(::prefs::kDnsOverHttpsTemplates,
                      base::Value(kMultipleTemplates));
 
@@ -350,8 +351,8 @@
 }
 
 TEST_F(SecureDnsManagerTest, SetModeAutomaticWithTemplates) {
-  local_state()->Set(::prefs::kDnsOverHttpsMode,
-                     base::Value(SecureDnsConfig::kModeAutomatic));
+  local_state()->SetManagedPref(::prefs::kDnsOverHttpsMode,
+                                base::Value(SecureDnsConfig::kModeAutomatic));
   local_state()->Set(::prefs::kDnsOverHttpsTemplates,
                      base::Value(kMultipleTemplates));
 
@@ -387,8 +388,8 @@
   secure_dns_manager()->SetDoHTemplatesUriResolverForTesting(
       std::move(template_uri_resolver));
 
-  local_state()->Set(::prefs::kDnsOverHttpsMode,
-                     base::Value(SecureDnsConfig::kModeAutomatic));
+  local_state()->SetManagedPref(::prefs::kDnsOverHttpsMode,
+                                base::Value(SecureDnsConfig::kModeAutomatic));
   local_state()->Set(::prefs::kDnsOverHttpsTemplates,
                      base::Value(kMultipleTemplates));
   local_state()->Set(::prefs::kDnsOverHttpsTemplatesWithIdentifiers,
@@ -422,8 +423,8 @@
       AccountId::FromUserEmailGaiaId("test-user@testdomain.com", "1234567890"));
   fake_user_manager->AddUser(account_id);
 
-  local_state()->Set(::prefs::kDnsOverHttpsMode,
-                     base::Value(SecureDnsConfig::kModeAutomatic));
+  local_state()->SetManagedPref(::prefs::kDnsOverHttpsMode,
+                                base::Value(SecureDnsConfig::kModeAutomatic));
   local_state()->Set(::prefs::kDnsOverHttpsTemplatesWithIdentifiers,
                      base::Value("https://dns.google/dns-query{?dns}"));
   local_state()->Set(::prefs::kDnsOverHttpsSalt, base::Value("testsalt"));
@@ -463,8 +464,8 @@
       "https://dns.google.alternativeuri/"
       "B07D2C5D119EB1881671C3B8D84CBE4FE3595C0C9ECBBF7670B18DDFDA072F66/{?dns}";
 
-  local_state()->Set(::prefs::kDnsOverHttpsMode,
-                     base::Value(SecureDnsConfig::kModeAutomatic));
+  local_state()->SetManagedPref(::prefs::kDnsOverHttpsMode,
+                                base::Value(SecureDnsConfig::kModeAutomatic));
   local_state()->Set(::prefs::kDnsOverHttpsTemplatesWithIdentifiers,
                      base::Value(kUriTemplateWithIdentifiers));
   local_state()->Set(::prefs::kDnsOverHttpsTemplates, base::Value(kGoogleDns));
@@ -526,8 +527,8 @@
   EXPECT_EQ(actual_uri_template_update_count,
             expected_uri_template_update_count);
 
-  local_state()->Set(::prefs::kDnsOverHttpsMode,
-                     base::Value(SecureDnsConfig::kModeAutomatic));
+  local_state()->SetManagedPref(::prefs::kDnsOverHttpsMode,
+                                base::Value(SecureDnsConfig::kModeAutomatic));
   local_state()->Set(::prefs::kDnsOverHttpsTemplatesWithIdentifiers,
                      base::Value(kUriTemplateWithEmail));
   // Each pref update above will trigger an update request for the URI
@@ -557,8 +558,8 @@
 }
 
 TEST_F(SecureDnsManagerTest, DefaultTemplateUrisForwardedToShill) {
-  local_state()->Set(::prefs::kDnsOverHttpsMode,
-                     base::Value(SecureDnsConfig::kModeAutomatic));
+  local_state()->SetManagedPref(::prefs::kDnsOverHttpsMode,
+                                base::Value(SecureDnsConfig::kModeAutomatic));
   auto providers = GetDOHProviders();
   // The content of the provider list depends on the current country.
   EXPECT_FALSE(providers.empty());
@@ -620,8 +621,8 @@
 
   EXPECT_EQ(actual_uri_template_update_count, 0);
 
-  local_state()->Set(::prefs::kDnsOverHttpsMode,
-                     base::Value(SecureDnsConfig::kModeAutomatic));
+  local_state()->SetManagedPref(::prefs::kDnsOverHttpsMode,
+                                base::Value(SecureDnsConfig::kModeAutomatic));
   local_state()->Set(::prefs::kDnsOverHttpsTemplatesWithIdentifiers,
                      base::Value(kTemplateUri1));
   local_state()->Set(::prefs::kDnsOverHttpsTemplatesWithIdentifiers,
@@ -653,6 +654,81 @@
 
   EXPECT_EQ(domains, GetDOHExcludedDomains());
 }
+// This test verifies the user-set local_state to user-set profile_prefs
+// migration logic for DoH prefs.
+TEST_F(SecureDnsManagerTest, LocalStateToProfilePrefMigration) {
+  local_state()->Set(::prefs::kDnsOverHttpsMode,
+                     base::Value(SecureDnsConfig::kModeSecure));
+  local_state()->Set(::prefs::kDnsOverHttpsTemplates, base::Value(kGoogleDns));
+
+  EXPECT_EQ(profile_prefs()->GetString(::prefs::kDnsOverHttpsMode), "");
+  EXPECT_EQ(profile_prefs()->GetString(::prefs::kDnsOverHttpsTemplates), "");
+
+  {
+    auto consumer_secure_dns_manager = std::make_unique<SecureDnsManager>(
+        local_state(), profile_prefs(), /*is_profile_managed=*/false);
+    // Verify that the user-set local state prefs are copied to profile prefs
+    // for unmanaged users.
+    EXPECT_EQ(profile_prefs()->GetString(::prefs::kDnsOverHttpsMode),
+              SecureDnsConfig::kModeSecure);
+    EXPECT_EQ(profile_prefs()->GetString(::prefs::kDnsOverHttpsTemplates),
+              kGoogleDns);
+  }
+
+  profile_prefs()->ClearPref(::prefs::kDnsOverHttpsMode);
+  profile_prefs()->ClearPref(::prefs::kDnsOverHttpsTemplates);
+
+  {
+    auto consumer_secure_dns_manager = std::make_unique<SecureDnsManager>(
+        local_state(), profile_prefs(), /*is_profile_managed=*/true);
+    // Verify that the user-set local state prefs are not copied to profile
+    // prefs for managed users. SecureDnsConfig::kModeAutomatic is the default
+    // value for secure DoH mode.
+    EXPECT_EQ(profile_prefs()->GetString(::prefs::kDnsOverHttpsMode),
+              SecureDnsConfig::kModeAutomatic);
+    EXPECT_EQ(profile_prefs()->GetString(::prefs::kDnsOverHttpsTemplates), "");
+  }
+
+  profile_prefs()->Set(::prefs::kDnsOverHttpsMode,
+                       base::Value(SecureDnsConfig::kModeSecure));
+  profile_prefs()->Set(::prefs::kDnsOverHttpsTemplates,
+                       base::Value(kCloudflareDns));
+
+  {
+    auto consumer_secure_dns_manager = std::make_unique<SecureDnsManager>(
+        local_state(), profile_prefs(), /*is_profile_managed=*/false);
+    // When the profile prefs already have DoH prefs configured, verify that the
+    // pref migration will not override them.
+    EXPECT_EQ(profile_prefs()->GetString(::prefs::kDnsOverHttpsMode),
+              SecureDnsConfig::kModeSecure);
+    EXPECT_EQ(profile_prefs()->GetString(::prefs::kDnsOverHttpsTemplates),
+              kCloudflareDns);
+  }
+}
+
+// This test verifies that the SecureDnsManager updates observers with the
+// correct DoH configuration when the user profile is not managed.
+TEST_F(SecureDnsManagerTest, ObserverForUnmanagedUsers) {
+  local_state()->Set(::prefs::kDnsOverHttpsMode,
+                     base::Value(SecureDnsConfig::kModeAutomatic));
+  local_state()->Set(::prefs::kDnsOverHttpsTemplates, base::Value(kGoogleDns));
+
+  auto consumer_secure_dns_manager = std::make_unique<SecureDnsManager>(
+      local_state(), profile_prefs(), /*is_profile_managed=*/false);
+  auto consumer_observer = std::make_unique<SecureDnsManagerObserver>(
+      consumer_secure_dns_manager.get());
+
+  EXPECT_EQ(consumer_observer->doh_template_uri(), kGoogleDns);
+  EXPECT_EQ(consumer_observer->doh_mode(), SecureDnsConfig::kModeAutomatic);
+
+  profile_prefs()->Set(::prefs::kDnsOverHttpsMode,
+                       base::Value(SecureDnsConfig::kModeSecure));
+  profile_prefs()->Set(::prefs::kDnsOverHttpsTemplates,
+                       base::Value(kCloudflareDns));
+
+  EXPECT_EQ(consumer_observer->doh_template_uri(), kCloudflareDns);
+  EXPECT_EQ(consumer_observer->doh_mode(), SecureDnsConfig::kModeSecure);
+}
 
 }  // namespace
 }  // namespace ash
diff --git a/chrome/browser/ash/os_feedback/BUILD.gn b/chrome/browser/ash/os_feedback/BUILD.gn
index 7708168..4911bbbf 100644
--- a/chrome/browser/ash/os_feedback/BUILD.gn
+++ b/chrome/browser/ash/os_feedback/BUILD.gn
@@ -30,6 +30,7 @@
     "//chrome/browser/ash/system_web_apps/apps",
     "//chrome/browser/feedback",
     "//chrome/browser/profiles:profile",
+    "//chrome/browser/ui:browser_list",
     "//chrome/browser/ui/ash/system_web_apps",
     "//chrome/browser/ui/webui/ash/diagnostics_dialog",
     "//chrome/common",
diff --git a/chrome/browser/ash/policy/dlp/BUILD.gn b/chrome/browser/ash/policy/dlp/BUILD.gn
index cefad54..4399f37 100644
--- a/chrome/browser/ash/policy/dlp/BUILD.gn
+++ b/chrome/browser/ash/policy/dlp/BUILD.gn
@@ -28,7 +28,11 @@
     "files_policy_string_util.h",
   ]
 
-  public_deps = [ "//chrome/browser:browser_public_dependencies" ]
+  public_deps = [
+    "//chrome/browser:browser_public_dependencies",
+    "//chrome/browser/ui:browser_list",
+    "//chromeos/ash/experiences/screenshot_area",
+  ]
 
   deps = [
     "//ash",
@@ -132,6 +136,7 @@
     "//chrome/test:test_support",
     "//chromeos/ash/components/disks",
     "//chromeos/ash/components/disks:test_support",
+    "//chromeos/ash/experiences/screenshot_area",
     "//chromeos/dbus/dlp",
     "//chromeos/dbus/dlp:dlp_proto",
     "//chromeos/ui/base",
@@ -207,6 +212,7 @@
     "//chrome/common:constants",
     "//chrome/test:test_support",
     "//chrome/test:test_support_ui",
+    "//chromeos/ash/experiences/screenshot_area",
     "//components/enterprise/data_controls/core/browser",
     "//components/enterprise/data_controls/core/browser:dlp_policy_event_proto",
     "//components/exo",
diff --git a/chrome/browser/ash/policy/dlp/dlp_content_manager_ash.h b/chrome/browser/ash/policy/dlp/dlp_content_manager_ash.h
index 2351f4b..ca1c214 100644
--- a/chrome/browser/ash/policy/dlp/dlp_content_manager_ash.h
+++ b/chrome/browser/ash/policy/dlp/dlp_content_manager_ash.h
@@ -20,7 +20,7 @@
 #include "chrome/browser/chromeos/policy/dlp/dlp_content_manager.h"
 #include "chrome/browser/chromeos/policy/dlp/dlp_content_restriction_set.h"
 #include "chrome/browser/chromeos/policy/dlp/dlp_rules_manager.h"
-#include "chrome/browser/ui/ash/screenshot_area.h"
+#include "chromeos/ash/experiences/screenshot_area/screenshot_area.h"
 #include "components/exo/window_properties.h"
 #include "content/public/browser/desktop_media_id.h"
 #include "content/public/browser/media_stream_request.h"
diff --git a/chrome/browser/ash/policy/dlp/dlp_content_manager_ash_browsertest.cc b/chrome/browser/ash/policy/dlp/dlp_content_manager_ash_browsertest.cc
index 7e9f5b1..ba292ff7e 100644
--- a/chrome/browser/ash/policy/dlp/dlp_content_manager_ash_browsertest.cc
+++ b/chrome/browser/ash/policy/dlp/dlp_content_manager_ash_browsertest.cc
@@ -39,7 +39,6 @@
 #include "chrome/browser/notifications/notification_display_service_tester.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/ash/capture_mode/chrome_capture_mode_delegate.h"
-#include "chrome/browser/ui/ash/screenshot_area.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/browser_window.h"
@@ -47,6 +46,7 @@
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/interactive_test_utils.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "chromeos/ash/experiences/screenshot_area/screenshot_area.h"
 #include "components/enterprise/data_controls/core/browser/dlp_histogram_helper.h"
 #include "components/enterprise/data_controls/core/browser/dlp_policy_event.pb.h"
 #include "components/exo/shell_surface.h"
diff --git a/chrome/browser/ash/policy/dlp/dlp_content_manager_ash_unittest.cc b/chrome/browser/ash/policy/dlp/dlp_content_manager_ash_unittest.cc
index 32301fc..7777829 100644
--- a/chrome/browser/ash/policy/dlp/dlp_content_manager_ash_unittest.cc
+++ b/chrome/browser/ash/policy/dlp/dlp_content_manager_ash_unittest.cc
@@ -31,10 +31,10 @@
 #include "chrome/browser/notifications/notification_display_service_tester.h"
 #include "chrome/browser/policy/messaging_layer/public/report_client_test_util.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/ui/ash/screenshot_area.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chrome/test/base/testing_profile_manager.h"
+#include "chromeos/ash/experiences/screenshot_area/screenshot_area.h"
 #include "components/enterprise/data_controls/core/browser/dlp_histogram_helper.h"
 #include "components/enterprise/data_controls/core/browser/dlp_policy_event.pb.h"
 #include "components/reporting/client/mock_report_queue.h"
diff --git a/chrome/browser/ash/policy/enrollment/auto_enrollment_type_checker_unittest.cc b/chrome/browser/ash/policy/enrollment/auto_enrollment_type_checker_unittest.cc
index 8949dfe..a5e7d3cf 100644
--- a/chrome/browser/ash/policy/enrollment/auto_enrollment_type_checker_unittest.cc
+++ b/chrome/browser/ash/policy/enrollment/auto_enrollment_type_checker_unittest.cc
@@ -59,12 +59,6 @@
   ~AutoEnrollmentTypeCheckerTest() override = default;
 
  protected:
-  void SetUpNonchromeDevice() {
-    fake_statistics_provider_.SetMachineStatistic(
-        ash::system::kFirmwareTypeKey,
-        ash::system::kFirmwareTypeValueNonchrome);
-  }
-
   void SetUpFlexDeviceWithFREOnFlexEnabled() {
     enrollment_test_helper_.SetUpFlexDevice();
     enrollment_test_helper_.EnableFREOnFlex();
@@ -736,7 +730,7 @@
 }
 
 TEST_F(AutoEnrollmentTypeCheckerUSDStatusTest, NonChrome) {
-  SetUpNonchromeDevice();
+  enrollment_test_helper_.SetUpNonchromeDevice();
 
   AutoEnrollmentTypeChecker::IsUnifiedStateDeterminationEnabled();
 
@@ -769,7 +763,7 @@
   void SetUp() override {
     AutoEnrollmentTypeCheckerTest::SetUp();
     if (device_os_ == DeviceOs::Nonchrome) {
-      SetUpNonchromeDevice();
+      enrollment_test_helper_.SetUpNonchromeDevice();
     } else if (device_os_ == DeviceOs::FlexWithoutFRE) {
       enrollment_test_helper_.SetUpFlexDevice();
     } else if (device_os_ == DeviceOs::FlexWithFRE) {
diff --git a/chrome/browser/ash/policy/enrollment/enrollment_test_helper.cc b/chrome/browser/ash/policy/enrollment/enrollment_test_helper.cc
index e3952e80..8ac8161c 100644
--- a/chrome/browser/ash/policy/enrollment/enrollment_test_helper.cc
+++ b/chrome/browser/ash/policy/enrollment/enrollment_test_helper.cc
@@ -29,13 +29,17 @@
   ash::OobeConfigurationClient::Shutdown();
 }
 
-void EnrollmentTestHelper::SetUpFlexDevice() {
-  command_line_->GetProcessCommandLine()->AppendSwitch(
-      ash::switches::kRevenBranding);
+void EnrollmentTestHelper::SetUpNonchromeDevice() {
   statistics_provider_->SetMachineStatistic(
       ash::system::kFirmwareTypeKey, ash::system::kFirmwareTypeValueNonchrome);
 }
 
+void EnrollmentTestHelper::SetUpFlexDevice() {
+  SetUpNonchromeDevice();
+  command_line_->GetProcessCommandLine()->AppendSwitch(
+      ash::switches::kRevenBranding);
+}
+
 void EnrollmentTestHelper::SetUpEnrollmentTokenConfig(
     const char config[]) {
   static_cast<ash::FakeOobeConfigurationClient*>(
diff --git a/chrome/browser/ash/policy/enrollment/enrollment_test_helper.h b/chrome/browser/ash/policy/enrollment/enrollment_test_helper.h
index dbe33b7..43a2f9bd 100644
--- a/chrome/browser/ash/policy/enrollment/enrollment_test_helper.h
+++ b/chrome/browser/ash/policy/enrollment/enrollment_test_helper.h
@@ -27,7 +27,9 @@
   EnrollmentTestHelper(const EnrollmentTestHelper&) = delete;
   EnrollmentTestHelper& operator=(const EnrollmentTestHelper&) = delete;
 
-  // Configures ash::switches::IsRevenBranding() checks to pass.
+  // Pretends that the device is not a Chrome ("nonchrome") device.
+  void SetUpNonchromeDevice();
+  // Pretends that the device is a ChromeOS Flex device.
   void SetUpFlexDevice();
   // Configures OobeConfiguration with an enrollment token for testing.
   void SetUpEnrollmentTokenConfig(
diff --git a/chrome/browser/ash/power/ml/BUILD.gn b/chrome/browser/ash/power/ml/BUILD.gn
index 17a0597..00e63dc 100644
--- a/chrome/browser/ash/power/ml/BUILD.gn
+++ b/chrome/browser/ash/power/ml/BUILD.gn
@@ -42,6 +42,7 @@
     "//chrome/browser/ash/power",
     "//chrome/browser/ash/power/ml/smart_dim",
     "//chrome/browser/profiles:profile",
+    "//chrome/browser/ui:browser_list",
     "//chrome/common:constants",
     "//chromeos/ash/components/dbus",
     "//chromeos/ash/components/install_attributes",
diff --git a/chrome/browser/ash/system_web_apps/apps/personalization_app/personalization_app_ambient_provider_impl.cc b/chrome/browser/ash/system_web_apps/apps/personalization_app/personalization_app_ambient_provider_impl.cc
index f1a1ce9f..abf719a 100644
--- a/chrome/browser/ash/system_web_apps/apps/personalization_app/personalization_app_ambient_provider_impl.cc
+++ b/chrome/browser/ash/system_web_apps/apps/personalization_app/personalization_app_ambient_provider_impl.cc
@@ -161,6 +161,13 @@
   }
 }
 
+bool PersonalizationAppAmbientProviderImpl::IsGeolocationUserModifiable() {
+  PrefService* pref_service = profile_->GetPrefs();
+  CHECK(pref_service);
+  return pref_service->IsUserModifiablePreference(
+      prefs::kUserGeolocationAccessLevel);
+}
+
 void PersonalizationAppAmbientProviderImpl::
     NotifyGeolocationPermissionChanged() {
   if (!ambient_observer_remote_.is_bound()) {
@@ -168,7 +175,7 @@
   }
 
   ambient_observer_remote_->OnGeolocationPermissionForSystemServicesChanged(
-      IsGeolocationEnabledForSystemServices());
+      IsGeolocationEnabledForSystemServices(), IsGeolocationUserModifiable());
 }
 
 void PersonalizationAppAmbientProviderImpl::SetAmbientObserver(
@@ -768,6 +775,11 @@
   std::move(callback).Run(IsGeolocationEnabledForSystemServices());
 }
 
+void PersonalizationAppAmbientProviderImpl::IsGeolocationUserModifiable(
+    IsGeolocationUserModifiableCallback callback) {
+  std::move(callback).Run(IsGeolocationUserModifiable());
+}
+
 void PersonalizationAppAmbientProviderImpl::
     EnableGeolocationForSystemServices() {
   PrefService* pref_service = profile_->GetPrefs();
diff --git a/chrome/browser/ash/system_web_apps/apps/personalization_app/personalization_app_ambient_provider_impl.h b/chrome/browser/ash/system_web_apps/apps/personalization_app/personalization_app_ambient_provider_impl.h
index 76e8be2..02661ea 100644
--- a/chrome/browser/ash/system_web_apps/apps/personalization_app/personalization_app_ambient_provider_impl.h
+++ b/chrome/browser/ash/system_web_apps/apps/personalization_app/personalization_app_ambient_provider_impl.h
@@ -69,6 +69,8 @@
   void HandleTimeOfDayBannerDismissed() override;
   void IsGeolocationEnabledForSystemServices(
       IsGeolocationEnabledForSystemServicesCallback callback) override;
+  void IsGeolocationUserModifiable(
+      IsGeolocationUserModifiableCallback callback) override;
   void EnableGeolocationForSystemServices() override;
 
   // Notify WebUI the latest values.
@@ -86,6 +88,7 @@
   bool IsAmbientModeEnabled();
 
   bool IsGeolocationEnabledForSystemServices();
+  bool IsGeolocationUserModifiable();
 
   // Notify webUI the current state of system geolocation permission.
   void NotifyGeolocationPermissionChanged();
diff --git a/chrome/browser/ash/system_web_apps/apps/personalization_app/personalization_app_ambient_provider_impl_unittest.cc b/chrome/browser/ash/system_web_apps/apps/personalization_app/personalization_app_ambient_provider_impl_unittest.cc
index f23f9c2..d4c0f73 100644
--- a/chrome/browser/ash/system_web_apps/apps/personalization_app/personalization_app_ambient_provider_impl_unittest.cc
+++ b/chrome/browser/ash/system_web_apps/apps/personalization_app/personalization_app_ambient_provider_impl_unittest.cc
@@ -36,6 +36,7 @@
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chrome/test/base/testing_profile_manager.h"
+#include "components/sync_preferences/testing_pref_service_syncable.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_task_environment.h"
 #include "content/public/test/test_web_ui.h"
@@ -102,8 +103,11 @@
     ambient_ui_visibility_ = visibility;
   }
 
-  void OnGeolocationPermissionForSystemServicesChanged(bool enabled) override {
+  void OnGeolocationPermissionForSystemServicesChanged(
+      bool enabled,
+      bool is_user_modifiable) override {
     geolocation_permission_enabled_ = enabled;
+    is_geolocation_user_modifiable_ = is_user_modifiable;
   }
 
   mojo::PendingRemote<ash::personalization_app::mojom::AmbientObserver>
@@ -156,6 +160,11 @@
     return geolocation_permission_enabled_;
   }
 
+  bool is_geolocation_user_modifiable() {
+    ambient_observer_receiver_.FlushForTesting();
+    return is_geolocation_user_modifiable_;
+  }
+
  private:
   mojo::Receiver<ash::personalization_app::mojom::AmbientObserver>
       ambient_observer_receiver_{this};
@@ -170,6 +179,7 @@
   ash::AmbientUiVisibility ambient_ui_visibility_ =
       ash::AmbientUiVisibility::kClosed;
   bool geolocation_permission_enabled_ = true;
+  bool is_geolocation_user_modifiable_ = true;
   std::vector<ash::personalization_app::mojom::AmbientModeAlbumPtr> albums_;
   std::vector<GURL> previews_;
 };
@@ -292,6 +302,11 @@
     return test_ambient_observer_.is_geolocation_enabled();
   }
 
+  bool ObservedGeolocationIsManaged() {
+    ambient_provider_remote_.FlushForTesting();
+    return !test_ambient_observer_.is_geolocation_user_modifiable();
+  }
+
   std::optional<ash::AmbientSettings>& settings() {
     return ambient_provider_->settings_;
   }
@@ -301,7 +316,10 @@
                                       enabled);
   }
 
-  void SetGeolocationPref(bool enabled) {
+  // Depending on the `managed` argument, sets the value of the
+  // `kUserGeolocationAccessLevel` pref either in `PrefStoreType::MANAGED_STORE`
+  // or in `PrefStoreType::USER_STORE` PrefStore.
+  void SetGeolocationPref(bool enabled, bool managed) {
     GeolocationAccessLevel level;
     if (enabled) {
       level = GeolocationAccessLevel::kOnlyAllowedForSystem;
@@ -309,8 +327,15 @@
       level = GeolocationAccessLevel::kDisallowed;
     }
 
-    profile()->GetPrefs()->SetInteger(ash::prefs::kUserGeolocationAccessLevel,
-                                      static_cast<int>(level));
+    if (managed) {
+      profile()->GetTestingPrefService()->SetManagedPref(
+          ash::prefs::kUserGeolocationAccessLevel,
+          base::Value(static_cast<int>(level)));
+    } else {
+      profile()->GetTestingPrefService()->SetUserPref(
+          ash::prefs::kUserGeolocationAccessLevel,
+          base::Value(static_cast<int>(level)));
+    }
   }
 
   void SetAmbientTheme(mojom::AmbientTheme ambient_theme) {
@@ -639,11 +664,26 @@
 TEST_F(PersonalizationAppAmbientProviderImplTest,
        ShouldCallOnGeolocationPermissionForSystemServicesChanged) {
   SetAmbientObserver();
+
+  // Check default values:
   EXPECT_TRUE(ObservedGeolocationPermissionEnabled());
-  SetGeolocationPref(/*enabled=*/false);
+  EXPECT_FALSE(ObservedGeolocationIsManaged());
+
+  // Check consumer scenario:
+  SetGeolocationPref(/*enabled=*/false, /*managed=*/false);
   EXPECT_FALSE(ObservedGeolocationPermissionEnabled());
-  SetGeolocationPref(/*enabled=*/true);
+  EXPECT_FALSE(ObservedGeolocationIsManaged());
+  SetGeolocationPref(/*enabled=*/true, /*managed=*/false);
   EXPECT_TRUE(ObservedGeolocationPermissionEnabled());
+  EXPECT_FALSE(ObservedGeolocationIsManaged());
+
+  // Check managed scenario:
+  SetGeolocationPref(/*enabled=*/false, /*managed=*/true);
+  EXPECT_FALSE(ObservedGeolocationPermissionEnabled());
+  EXPECT_TRUE(ObservedGeolocationIsManaged());
+  SetGeolocationPref(/*enabled=*/true, /*managed=*/true);
+  EXPECT_TRUE(ObservedGeolocationPermissionEnabled());
+  EXPECT_TRUE(ObservedGeolocationIsManaged());
 }
 
 TEST_F(PersonalizationAppAmbientProviderImplTest, SetTopicSource) {
diff --git a/chrome/browser/ash/system_web_apps/test_support/BUILD.gn b/chrome/browser/ash/system_web_apps/test_support/BUILD.gn
index dacd64d..2618141 100644
--- a/chrome/browser/ash/system_web_apps/test_support/BUILD.gn
+++ b/chrome/browser/ash/system_web_apps/test_support/BUILD.gn
@@ -34,6 +34,7 @@
     "//chrome/browser/profiles:profile",
     "//chrome/browser/ui",
     "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/web_applications",
     "//chrome/browser/web_applications:web_applications_test_support",
     "//components/crx_file",
diff --git a/chrome/browser/autofill/BUILD.gn b/chrome/browser/autofill/BUILD.gn
index cb02b781..b3ea56c 100644
--- a/chrome/browser/autofill/BUILD.gn
+++ b/chrome/browser/autofill/BUILD.gn
@@ -134,6 +134,7 @@
   deps = [
     "//chrome/browser/autofill:autofill",
     "//chrome/browser/profiles:profile",
+    "//chrome/browser/ui/autofill",
     "//components/autofill/content/browser:browser",
     "//components/autofill/content/common/mojom",
     "//components/autofill/core/browser:test_support",
@@ -208,6 +209,8 @@
 
     deps = [
       "//chrome/browser/autofill",
+      "//chrome/browser/ui/autofill",
+      "//chrome/browser/ui/autofill:test_support",
       "//chrome/test:test_support",
       "//chrome/test:test_support",
       "//chrome/test:test_support_ui",
@@ -231,6 +234,7 @@
       "//chrome/browser",
       "//chrome/browser/profiles:profile",
       "//chrome/browser/ui",
+      "//chrome/browser/ui/autofill",
       "//chrome/common:chrome_features",
       "//chrome/common:non_code_constants",
       "//chrome/test:test_support",
@@ -283,6 +287,8 @@
 
     deps = [
       "//chrome/browser/autofill:test_support_ui",
+      "//chrome/browser/ui/autofill",
+      "//chrome/browser/ui/autofill:test_support",
       "//chrome/test:test_support",
       "//components/autofill/core/common:autofill_regex",
     ]
diff --git a/chrome/browser/browser_process_platform_part_ash.cc b/chrome/browser/browser_process_platform_part_ash.cc
index b1bcc7f2..954be39d 100644
--- a/chrome/browser/browser_process_platform_part_ash.cc
+++ b/chrome/browser/browser_process_platform_part_ash.cc
@@ -244,7 +244,7 @@
   }
 
   secure_dns_manager_ = std::make_unique<ash::SecureDnsManager>(
-      g_browser_process->local_state(),
+      g_browser_process->local_state(), primary_profile->GetPrefs(),
       primary_profile->GetProfilePolicyConnector()->IsManaged());
 }
 
diff --git a/chrome/browser/captive_portal/captive_portal_browsertest.cc b/chrome/browser/captive_portal/captive_portal_browsertest.cc
index b6f726eb..896b61d5 100644
--- a/chrome/browser/captive_portal/captive_portal_browsertest.cc
+++ b/chrome/browser/captive_portal/captive_portal_browsertest.cc
@@ -2953,11 +2953,17 @@
 #define MAYBE_SecureDnsCaptivePortal SecureDnsCaptivePortal
 #endif
 IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, MAYBE_SecureDnsCaptivePortal) {
-  PrefService* local_state = g_browser_process->local_state();
-  local_state->SetString(prefs::kDnsOverHttpsMode,
-                         SecureDnsConfig::kModeSecure);
-  local_state->SetString(prefs::kDnsOverHttpsTemplates,
-                         "https://bar.test/dns-query{?dns}");
+  PrefService* pref_service = g_browser_process->local_state();
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  // On Chrome OS, the local_state is shared between all users so the user-set
+  // pref is stored in the profile's pref service.
+  pref_service = browser()->profile()->GetPrefs();
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+
+  pref_service->SetString(prefs::kDnsOverHttpsMode,
+                          SecureDnsConfig::kModeSecure);
+  pref_service->SetString(prefs::kDnsOverHttpsTemplates,
+                          "https://bar.test/dns-query{?dns}");
 
   Browser* login_browser = nullptr;
   SlowLoadBehindCaptivePortal(browser(), true /* expect_open_login_tab */,
@@ -2998,11 +3004,16 @@
 #endif
 IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest,
                        MAYBE_SecureDnsErrorTriggersCheck) {
-  PrefService* local_state = g_browser_process->local_state();
-  local_state->SetString(prefs::kDnsOverHttpsTemplates,
-                         "https://bar.test/dns-query{?dns}");
-  local_state->SetString(prefs::kDnsOverHttpsMode,
-                         SecureDnsConfig::kModeSecure);
+  PrefService* pref_service = g_browser_process->local_state();
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  // On Chrome OS, the local_state is shared between all users so the user-set
+  // pref is stored in the profile's pref service.
+  pref_service = browser()->profile()->GetPrefs();
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+  pref_service->SetString(prefs::kDnsOverHttpsTemplates,
+                          "https://bar.test/dns-query{?dns}");
+  pref_service->SetString(prefs::kDnsOverHttpsMode,
+                          SecureDnsConfig::kModeSecure);
 
   TabStripModel* tab_strip_model = browser()->tab_strip_model();
   WebContents* broken_tab_contents = tab_strip_model->GetActiveWebContents();
@@ -3046,11 +3057,16 @@
 #endif
 IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest,
                        MAYBE_SlowLoadSecureDnsErrorWithCaptivePortal) {
-  PrefService* local_state = g_browser_process->local_state();
-  local_state->SetString(prefs::kDnsOverHttpsTemplates,
-                         "https://bar.test/dns-query{?dns}");
-  local_state->SetString(prefs::kDnsOverHttpsMode,
-                         SecureDnsConfig::kModeSecure);
+  PrefService* pref_service = g_browser_process->local_state();
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  // On Chrome OS, the local_state is shared between all users so the user-set
+  // pref is stored in the profile's pref service.
+  pref_service = browser()->profile()->GetPrefs();
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+  pref_service->SetString(prefs::kDnsOverHttpsTemplates,
+                          "https://bar.test/dns-query{?dns}");
+  pref_service->SetString(prefs::kDnsOverHttpsMode,
+                          SecureDnsConfig::kModeSecure);
 
   SlowLoadBehindCaptivePortal(browser(), true /* expect_open_login_tab */,
                               true /* expect_new_login_browser */);
@@ -3082,11 +3098,16 @@
 #endif
 IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest,
                        MAYBE_SlowLoadSecureDnsErrorAfterLogin) {
-  PrefService* local_state = g_browser_process->local_state();
-  local_state->SetString(prefs::kDnsOverHttpsTemplates,
-                         "https://bar.test/dns-query{?dns}");
-  local_state->SetString(prefs::kDnsOverHttpsMode,
-                         SecureDnsConfig::kModeSecure);
+  PrefService* pref_service = g_browser_process->local_state();
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  // On Chrome OS, the local_state is shared between all users so the user-set
+  // pref is stored in the profile's pref service.
+  pref_service = browser()->profile()->GetPrefs();
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+  pref_service->SetString(prefs::kDnsOverHttpsTemplates,
+                          "https://bar.test/dns-query{?dns}");
+  pref_service->SetString(prefs::kDnsOverHttpsMode,
+                          SecureDnsConfig::kModeSecure);
 
   Browser* login_browser = nullptr;
   SlowLoadBehindCaptivePortal(browser(), true /* expect_open_login_tab */,
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 075b12b4..fe7656b4 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -471,7 +471,6 @@
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/ash/smb_client/fileapi/smbfs_file_system_backend_delegate.h"
 #include "chrome/browser/ash/system/input_device_settings.h"
-#include "chrome/browser/ash/url_handler/url_handler.h"
 #include "chrome/browser/chromeos/app_mode/kiosk_settings_navigation_throttle.h"
 #include "chrome/browser/speech/tts_chromeos.h"
 #include "chrome/browser/speech/tts_controller_delegate_impl.h"
@@ -4251,13 +4250,6 @@
   DCHECK(profile);
   *no_javascript_access = false;
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-  // Try to intercept the request and open the URL with Lacros.
-  if (ash::TryOpenUrl(target_url, disposition)) {
-    return false;
-  }
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
-
   // If the opener is trying to create a background window but doesn't have
   // the appropriate permission, fail the attempt.
   if (container_type == content::mojom::WindowContainerType::BACKGROUND) {
diff --git a/chrome/browser/chromeos/app_mode/BUILD.gn b/chrome/browser/chromeos/app_mode/BUILD.gn
index 8f6b3ab..559c9fa3 100644
--- a/chrome/browser/chromeos/app_mode/BUILD.gn
+++ b/chrome/browser/chromeos/app_mode/BUILD.gn
@@ -60,6 +60,7 @@
     "//build:chromeos_buildflags",
     "//chrome/browser:browser_public_dependencies",
     "//chrome/browser/profiles:profile",
+    "//chrome/browser/ui:browser_list",
     "//chrome/browser/web_applications",
     "//chromeos/crosapi/mojom",
     "//chromeos/dbus/power",
diff --git a/chrome/browser/chromeos/extensions/login_screen/login/cleanup/BUILD.gn b/chrome/browser/chromeos/extensions/login_screen/login/cleanup/BUILD.gn
index 91a7fe6..735b8f4 100644
--- a/chrome/browser/chromeos/extensions/login_screen/login/cleanup/BUILD.gn
+++ b/chrome/browser/chromeos/extensions/login_screen/login/cleanup/BUILD.gn
@@ -45,7 +45,10 @@
     ]
   }
 
-  public_deps = [ "//chrome/browser:browser_public_dependencies" ]
+  public_deps = [
+    "//chrome/browser:browser_public_dependencies",
+    "//chrome/browser/ui:browser_list",
+  ]
 
   deps = [
     "//base",
diff --git a/chrome/browser/chromeos/policy/dlp/BUILD.gn b/chrome/browser/chromeos/policy/dlp/BUILD.gn
index ced83a4..779ea67 100644
--- a/chrome/browser/chromeos/policy/dlp/BUILD.gn
+++ b/chrome/browser/chromeos/policy/dlp/BUILD.gn
@@ -72,6 +72,7 @@
 
   public_deps = [
     "//chrome/browser:browser_public_dependencies",
+    "//chrome/browser/ui:browser_list",
     "//chrome/browser/ui/tabs:tab_strip_model_observer",
   ]
 
diff --git a/chrome/browser/chromeos/tablet_mode/BUILD.gn b/chrome/browser/chromeos/tablet_mode/BUILD.gn
index 9c33473..19f6924 100644
--- a/chrome/browser/chromeos/tablet_mode/BUILD.gn
+++ b/chrome/browser/chromeos/tablet_mode/BUILD.gn
@@ -27,6 +27,7 @@
     "//chrome/browser/chromeos/arc",
     "//chrome/browser/profiles:profile",
     "//chrome/browser/search",
+    "//chrome/browser/ui:browser_list",
     "//chrome/common",
     "//content/public/browser",
     "//content/public/common",
diff --git a/chrome/browser/commerce/android/BUILD.gn b/chrome/browser/commerce/android/BUILD.gn
index b67b22c96..8fd67b8 100644
--- a/chrome/browser/commerce/android/BUILD.gn
+++ b/chrome/browser/commerce/android/BUILD.gn
@@ -9,7 +9,11 @@
 android_library("java") {
   srcjar_deps = [ ":shopping_service_jni" ]
   sources = [
+    "java/src/org/chromium/chrome/browser/commerce/CommerceBottomSheetContentBinder.java",
+    "java/src/org/chromium/chrome/browser/commerce/CommerceBottomSheetContentCoordinator.java",
     "java/src/org/chromium/chrome/browser/commerce/CommerceBottomSheetContentListener.java",
+    "java/src/org/chromium/chrome/browser/commerce/CommerceBottomSheetContentMediator.java",
+    "java/src/org/chromium/chrome/browser/commerce/CommerceBottomSheetContentProperties.java",
     "java/src/org/chromium/chrome/browser/commerce/CommerceBottomSheetContentProvider.java",
     "java/src/org/chromium/chrome/browser/commerce/PriceNotificationSettingsFragment.java",
     "java/src/org/chromium/chrome/browser/commerce/PriceTrackingUtils.java",
@@ -40,6 +44,7 @@
     "//third_party/androidx:androidx_annotation_annotation_java",
     "//third_party/androidx:androidx_fragment_fragment_java",
     "//third_party/androidx:androidx_preference_preference_java",
+    "//third_party/androidx:androidx_recyclerview_recyclerview_java",
     "//third_party/jni_zero:jni_zero_java",
     "//ui/android:ui_java",
   ]
@@ -48,7 +53,13 @@
 }
 
 android_resources("java_resources") {
-  sources = [ "java/res/xml/price_notification_preferences.xml" ]
+  sources = [
+    "java/res/drawable/commerce_content_item_container_background.xml",
+    "java/res/layout/commerce_bottom_sheet_content_container.xml",
+    "java/res/layout/commerce_bottom_sheet_content_item_container.xml",
+    "java/res/values/dimens.xml",
+    "java/res/xml/price_notification_preferences.xml",
+  ]
 
   deps = [
     "//chrome/browser/ui/android/strings:ui_strings_grd",
@@ -58,14 +69,17 @@
 
 android_library("javatests") {
   testonly = true
+  resources_package = "org.chromium.chrome.browser.commerce"
 
   sources = [
+    "javatests/src/org/chromium/chrome/browser/commerce/CommerceBottomSheetContentRenderTest.java",
     "javatests/src/org/chromium/chrome/browser/commerce/PriceNotificationSettingsFragmentTest.java",
     "javatests/src/org/chromium/chrome/browser/commerce/PriceUtilsTest.java",
   ]
 
   deps = [
     ":java",
+    ":java_resources",
     "//base:base_java",
     "//base:base_java_test_support",
     "//chrome/android:chrome_java",
@@ -76,15 +90,20 @@
     "//chrome/browser/signin/services/android:java",
     "//chrome/test/android:chrome_java_integration_test_support",
     "//components/browser_ui/settings/android:java",
+    "//components/browser_ui/widget/android:test_support_java",
     "//components/payments/content/android:java",
     "//components/prefs/android:java",
     "//components/signin/public/android:java",
     "//content/public/android:content_full_java",
     "//third_party/androidx:androidx_fragment_fragment_java",
     "//third_party/androidx:androidx_preference_preference_java",
+    "//third_party/androidx:androidx_recyclerview_recyclerview_java",
     "//third_party/androidx:androidx_test_runner_java",
     "//third_party/junit:junit",
     "//third_party/mockito:mockito_java",
+    "//ui/android:ui_java_test_support",
+    "//ui/android:ui_no_recycler_view_java",
+    "//ui/android:ui_recycler_view_java",
   ]
 }
 
@@ -94,3 +113,18 @@
     "java/src/org/chromium/chrome/browser/commerce/ShoppingServiceFactory.java",
   ]
 }
+
+robolectric_library("junit") {
+  testonly = true
+  resources_package = "org.chromium.chrome.browser.commerce"
+
+  sources = [ "junit/src/org/chromium/chrome/browser/commerce/CommerceBottomSheetContentMediatorUnitTest.java" ]
+
+  deps = [
+    ":java",
+    "//base:base_junit_test_support",
+    "//third_party/junit:junit",
+    "//third_party/mockito:mockito_java",
+    "//ui/android:ui_no_recycler_view_java",
+  ]
+}
diff --git a/chrome/browser/commerce/android/java/res/drawable/commerce_content_item_container_background.xml b/chrome/browser/commerce/android/java/res/drawable/commerce_content_item_container_background.xml
new file mode 100644
index 0000000..e37b82b
--- /dev/null
+++ b/chrome/browser/commerce/android/java/res/drawable/commerce_content_item_container_background.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2024 The Chromium Authors
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+  <!-- TODO(b/364812942): Use dynamic color. -->
+  <solid android:color="@color/price_insights_sheet_bg_color"/>
+  <corners android:radius="@dimen/content_item_container_background_radius" />
+</shape>
\ No newline at end of file
diff --git a/chrome/browser/commerce/android/java/res/layout/commerce_bottom_sheet_content_container.xml b/chrome/browser/commerce/android/java/res/layout/commerce_bottom_sheet_content_container.xml
new file mode 100644
index 0000000..562dc30
--- /dev/null
+++ b/chrome/browser/commerce/android/java/res/layout/commerce_bottom_sheet_content_container.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2024 The Chromium Authors
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/commerce_bottom_sheet_content_container"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+  <include layout="@layout/bottom_sheet_handlebar" />
+  <androidx.recyclerview.widget.RecyclerView
+      android:id="@+id/commerce_content_recycler_view"
+      android:layout_width="match_parent"
+      android:layout_height="0dp"
+      android:layout_weight="1"
+      android:padding="@dimen/content_recycler_view_padding"
+      android:orientation="vertical"
+      app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/chrome/browser/commerce/android/java/res/layout/commerce_bottom_sheet_content_item_container.xml b/chrome/browser/commerce/android/java/res/layout/commerce_bottom_sheet_content_item_container.xml
new file mode 100644
index 0000000..59916a1
--- /dev/null
+++ b/chrome/browser/commerce/android/java/res/layout/commerce_bottom_sheet_content_item_container.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2024 The Chromium Authors
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/item_container"
+      android:layout_width="match_parent"
+      android:layout_height="wrap_content"
+      android:padding="@dimen/content_item_container_padding"
+      android:background="@drawable/commerce_content_item_container_background"
+      android:orientation="vertical">
+    <TextView
+        android:id="@+id/title"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="@dimen/content_item_title_bottom_margin"
+        android:textAppearance="@style/TextAppearance.TextAccentMediumThick" />
+    <FrameLayout
+        android:id="@+id/content_view_container"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/chrome/browser/commerce/android/java/res/values/dimens.xml b/chrome/browser/commerce/android/java/res/values/dimens.xml
new file mode 100644
index 0000000..ec140d4
--- /dev/null
+++ b/chrome/browser/commerce/android/java/res/values/dimens.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2024 The Chromium Authors
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<resources>
+<!-- Commerce bottom sheet dimensions. -->
+  <dimen name="content_item_container_background_radius">24dp</dimen>
+  <dimen name="content_item_container_padding">16dp</dimen>
+  <dimen name="content_item_container_top_offset">16dp</dimen>
+  <dimen name="content_item_title_bottom_margin">16dp</dimen>
+  <dimen name="content_recycler_view_padding">16dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/chrome/browser/commerce/android/java/src/org/chromium/chrome/browser/commerce/CommerceBottomSheetContentBinder.java b/chrome/browser/commerce/android/java/src/org/chromium/chrome/browser/commerce/CommerceBottomSheetContentBinder.java
new file mode 100644
index 0000000..e1ef1bfe
--- /dev/null
+++ b/chrome/browser/commerce/android/java/src/org/chromium/chrome/browser/commerce/CommerceBottomSheetContentBinder.java
@@ -0,0 +1,37 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.commerce;
+
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.FrameLayout.LayoutParams;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import org.chromium.ui.modelutil.PropertyKey;
+import org.chromium.ui.modelutil.PropertyModel;
+
+public class CommerceBottomSheetContentBinder {
+    public static void bind(PropertyModel model, LinearLayout view, PropertyKey propertyKey) {
+        if (propertyKey == CommerceBottomSheetContentProperties.CUSTOM_VIEW) {
+            FrameLayout container = view.findViewById(R.id.content_view_container);
+            container.addView(
+                    model.get(CommerceBottomSheetContentProperties.CUSTOM_VIEW),
+                    new LayoutParams(
+                            ViewGroup.LayoutParams.MATCH_PARENT,
+                            ViewGroup.LayoutParams.WRAP_CONTENT));
+        } else if (propertyKey == CommerceBottomSheetContentProperties.TITLE) {
+            TextView titleView = view.findViewById(R.id.title);
+            titleView.setText(model.get(CommerceBottomSheetContentProperties.TITLE));
+        } else if (propertyKey == CommerceBottomSheetContentProperties.HAS_TITLE) {
+            TextView titleView = view.findViewById(R.id.title);
+            titleView.setVisibility(
+                    model.get(CommerceBottomSheetContentProperties.HAS_TITLE)
+                            ? View.VISIBLE
+                            : View.GONE);
+        }
+    }
+}
diff --git a/chrome/browser/commerce/android/java/src/org/chromium/chrome/browser/commerce/CommerceBottomSheetContentCoordinator.java b/chrome/browser/commerce/android/java/src/org/chromium/chrome/browser/commerce/CommerceBottomSheetContentCoordinator.java
new file mode 100644
index 0000000..669cfae
--- /dev/null
+++ b/chrome/browser/commerce/android/java/src/org/chromium/chrome/browser/commerce/CommerceBottomSheetContentCoordinator.java
@@ -0,0 +1,100 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.commerce;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.view.LayoutInflater;
+import android.view.View;
+
+import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.RecyclerView.ItemDecoration;
+import androidx.recyclerview.widget.RecyclerView.State;
+
+import org.chromium.ui.modelutil.LayoutViewBuilder;
+import org.chromium.ui.modelutil.MVCListAdapter.ModelList;
+import org.chromium.ui.modelutil.SimpleRecyclerViewAdapter;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.List;
+
+/** Coordinator for building a commerce bottom sheet content. */
+public class CommerceBottomSheetContentCoordinator {
+    /** Supported content types, the content is prioritized based on this order. */
+    @IntDef({ContentType.PRICE_TRACKING, ContentType.DISCOUNTS, ContentType.PRICE_INSIGHTS})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ContentType {
+        int PRICE_TRACKING = 0;
+        int DISCOUNTS = 1;
+        int PRICE_INSIGHTS = 2;
+    }
+
+    private List<CommerceBottomSheetContentProvider> mContentProviders;
+    private final CommerceBottomSheetContentMediator mMediator;
+    private RecyclerView mContenRecyclerView;
+    private View mCommerceBottomSheetContentContainer;
+    private ModelList mModelList;
+
+    private final Context mContext;
+
+    public CommerceBottomSheetContentCoordinator(Context context) {
+        mContext = context;
+        mModelList = new ModelList();
+        SimpleRecyclerViewAdapter adapter = new SimpleRecyclerViewAdapter(mModelList);
+        adapter.registerType(
+                0,
+                new LayoutViewBuilder(R.layout.commerce_bottom_sheet_content_item_container),
+                CommerceBottomSheetContentBinder::bind);
+
+        mCommerceBottomSheetContentContainer =
+                LayoutInflater.from(context)
+                        .inflate(
+                                R.layout.commerce_bottom_sheet_content_container, /* root= */ null);
+        mContenRecyclerView =
+                mCommerceBottomSheetContentContainer.findViewById(
+                        R.id.commerce_content_recycler_view);
+        mContenRecyclerView.setAdapter(adapter);
+        mContenRecyclerView.addItemDecoration(
+                new ItemDecoration() {
+                    @Override
+                    public void getItemOffsets(
+                            @NonNull Rect outRect,
+                            @NonNull View view,
+                            @NonNull RecyclerView parent,
+                            @NonNull State state) {
+                        if (parent.getChildAdapterPosition(view) != 0) {
+                            outRect.top =
+                                    mContext.getResources()
+                                            .getDimensionPixelOffset(
+                                                    R.dimen.content_item_container_top_offset);
+                        }
+                    }
+                });
+
+        mMediator = new CommerceBottomSheetContentMediator(mModelList);
+    }
+
+    /** Request to show the bottom sheet. */
+    public void requestShowContent() {
+        for (CommerceBottomSheetContentProvider provider : mContentProviders) {
+            provider.requestShowContent(mMediator);
+        }
+    }
+
+    public RecyclerView getRecyclerViewForTesting() {
+        return mContenRecyclerView;
+    }
+
+    public ModelList getModelListForTesting() {
+        return mModelList;
+    }
+
+    public View getContentViewForTesting() {
+        return mCommerceBottomSheetContentContainer;
+    }
+}
diff --git a/chrome/browser/commerce/android/java/src/org/chromium/chrome/browser/commerce/CommerceBottomSheetContentMediator.java b/chrome/browser/commerce/android/java/src/org/chromium/chrome/browser/commerce/CommerceBottomSheetContentMediator.java
new file mode 100644
index 0000000..ea4a9565
--- /dev/null
+++ b/chrome/browser/commerce/android/java/src/org/chromium/chrome/browser/commerce/CommerceBottomSheetContentMediator.java
@@ -0,0 +1,44 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.commerce;
+
+import org.chromium.ui.modelutil.MVCListAdapter.ListItem;
+import org.chromium.ui.modelutil.MVCListAdapter.ModelList;
+import org.chromium.ui.modelutil.PropertyModel;
+
+import java.util.Arrays;
+
+public class CommerceBottomSheetContentMediator implements CommerceBottomSheetContentListener {
+    private final ModelList mModelList;
+
+    public CommerceBottomSheetContentMediator(ModelList modelList) {
+        mModelList = modelList;
+    }
+
+    @Override
+    public void onContentReady(PropertyModel model) {
+        assert isValidPropertyModel(model)
+                : "Miss required property in PropertyModel from"
+                        + " CommerceBottomSheetContentProperties.";
+        int index = 0;
+        int currentType = model.get(CommerceBottomSheetContentProperties.TYPE);
+        for (; index < mModelList.size(); index++) {
+            int type = mModelList.get(index).model.get(CommerceBottomSheetContentProperties.TYPE);
+
+            assert currentType != type : "There can only be one view per commerce content type";
+
+            if (currentType < type) {
+                break;
+            }
+        }
+
+        mModelList.add(index, new ListItem(0, model));
+    }
+
+    private boolean isValidPropertyModel(PropertyModel model) {
+        return model.getAllProperties()
+                .containsAll(Arrays.asList(CommerceBottomSheetContentProperties.ALL_KEYS));
+    }
+}
diff --git a/chrome/browser/commerce/android/java/src/org/chromium/chrome/browser/commerce/CommerceBottomSheetContentProperties.java b/chrome/browser/commerce/android/java/src/org/chromium/chrome/browser/commerce/CommerceBottomSheetContentProperties.java
new file mode 100644
index 0000000..32495ce6
--- /dev/null
+++ b/chrome/browser/commerce/android/java/src/org/chromium/chrome/browser/commerce/CommerceBottomSheetContentProperties.java
@@ -0,0 +1,25 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.commerce;
+
+import android.view.View;
+
+import org.chromium.ui.modelutil.PropertyKey;
+import org.chromium.ui.modelutil.PropertyModel.ReadableBooleanPropertyKey;
+import org.chromium.ui.modelutil.PropertyModel.ReadableIntPropertyKey;
+import org.chromium.ui.modelutil.PropertyModel.ReadableObjectPropertyKey;
+
+public class CommerceBottomSheetContentProperties {
+    public static final ReadableIntPropertyKey TYPE = new ReadableIntPropertyKey();
+    public static final ReadableBooleanPropertyKey HAS_TITLE = new ReadableBooleanPropertyKey();
+
+    public static final ReadableObjectPropertyKey<String> TITLE = new ReadableObjectPropertyKey<>();
+
+    public static final ReadableObjectPropertyKey<View> CUSTOM_VIEW =
+            new ReadableObjectPropertyKey<>();
+
+    public static final PropertyKey[] ALL_KEYS =
+            new PropertyKey[] {TYPE, HAS_TITLE, TITLE, CUSTOM_VIEW};
+}
diff --git a/chrome/browser/commerce/android/javatests/src/org/chromium/chrome/browser/commerce/CommerceBottomSheetContentRenderTest.java b/chrome/browser/commerce/android/javatests/src/org/chromium/chrome/browser/commerce/CommerceBottomSheetContentRenderTest.java
new file mode 100644
index 0000000..2548e7f
--- /dev/null
+++ b/chrome/browser/commerce/android/javatests/src/org/chromium/chrome/browser/commerce/CommerceBottomSheetContentRenderTest.java
@@ -0,0 +1,104 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.commerce;
+
+import static org.chromium.ui.test.util.RenderTestRule.Component.UI_BROWSER_SHOPPING;
+
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.TextView;
+
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.ThreadUtils;
+import org.chromium.base.test.util.Batch;
+import org.chromium.base.test.util.Feature;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.components.browser_ui.widget.RecyclerViewTestUtils;
+import org.chromium.ui.modelutil.MVCListAdapter.ListItem;
+import org.chromium.ui.modelutil.MVCListAdapter.ModelList;
+import org.chromium.ui.modelutil.PropertyModel;
+import org.chromium.ui.test.util.BlankUiTestActivityTestCase;
+import org.chromium.ui.test.util.RenderTestRule;
+
+import java.io.IOException;
+
+/** Render Tests for the View build by the CommerceBottomSheetContent component. */
+@RunWith(ChromeJUnit4ClassRunner.class)
+@Batch(Batch.UNIT_TESTS)
+public class CommerceBottomSheetContentRenderTest extends BlankUiTestActivityTestCase {
+    @Rule
+    public RenderTestRule mRenderTestRule =
+            RenderTestRule.Builder.withPublicCorpus().setBugComponent(UI_BROWSER_SHOPPING).build();
+
+    private ModelList mModelList;
+    private View mContentView;
+    private RecyclerView mRecyclerView;
+
+    private CommerceBottomSheetContentCoordinator mCoordinator;
+
+    private PropertyModel createPropertyModel(int type, boolean hasTitle) {
+        TextView view = new TextView(getActivity());
+        view.setText("custom view");
+        return new PropertyModel.Builder(CommerceBottomSheetContentProperties.ALL_KEYS)
+                .with(CommerceBottomSheetContentProperties.TYPE, type)
+                .with(CommerceBottomSheetContentProperties.HAS_TITLE, hasTitle)
+                .with(CommerceBottomSheetContentProperties.TITLE, "Title " + type)
+                .with(CommerceBottomSheetContentProperties.CUSTOM_VIEW, view)
+                .build();
+    }
+
+    @Override
+    public void setUpTest() throws Exception {
+        super.setUpTest();
+        ThreadUtils.runOnUiThreadBlocking(
+                () -> {
+                    ViewGroup rootView = new FrameLayout(getActivity());
+                    FrameLayout.LayoutParams params =
+                            new FrameLayout.LayoutParams(
+                                    ViewGroup.LayoutParams.MATCH_PARENT,
+                                    ViewGroup.LayoutParams.WRAP_CONTENT);
+                    getActivity().setContentView(rootView, params);
+
+                    mCoordinator = new CommerceBottomSheetContentCoordinator(getActivity());
+                    mContentView = mCoordinator.getContentViewForTesting();
+                    mRecyclerView = mCoordinator.getRecyclerViewForTesting();
+                    mModelList = mCoordinator.getModelListForTesting();
+                    rootView.addView(mContentView);
+                });
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"RenderTest"})
+    public void testSingleContent() throws IOException {
+        ThreadUtils.runOnUiThreadBlocking(
+                () -> {
+                    mModelList.add(new ListItem(0, createPropertyModel(0, true)));
+                });
+        RecyclerViewTestUtils.waitForStableMvcRecyclerView(mRecyclerView);
+        mRenderTestRule.render(mContentView, "single_content");
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"RenderTest"})
+    public void testMultipleContents() throws IOException {
+        ThreadUtils.runOnUiThreadBlocking(
+                () -> {
+                    mModelList.add(new ListItem(0, createPropertyModel(0, true)));
+                    mModelList.add(new ListItem(0, createPropertyModel(1, false)));
+                    mModelList.add(new ListItem(0, createPropertyModel(2, false)));
+                });
+        RecyclerViewTestUtils.waitForStableMvcRecyclerView(mRecyclerView);
+        mRenderTestRule.render(mContentView, "multiple_content");
+    }
+}
diff --git a/chrome/browser/commerce/android/junit/src/org/chromium/chrome/browser/commerce/CommerceBottomSheetContentMediatorUnitTest.java b/chrome/browser/commerce/android/junit/src/org/chromium/chrome/browser/commerce/CommerceBottomSheetContentMediatorUnitTest.java
new file mode 100644
index 0000000..0c776bfd
--- /dev/null
+++ b/chrome/browser/commerce/android/junit/src/org/chromium/chrome/browser/commerce/CommerceBottomSheetContentMediatorUnitTest.java
@@ -0,0 +1,79 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.commerce;
+
+import static org.junit.Assert.assertEquals;
+
+import android.view.View;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.ui.modelutil.MVCListAdapter.ModelList;
+import org.chromium.ui.modelutil.PropertyModel;
+
+@RunWith(BaseRobolectricTestRunner.class)
+public class CommerceBottomSheetContentMediatorUnitTest {
+    @Mock View mContentCustomView;
+    private ModelList mModelList;
+    private CommerceBottomSheetContentMediator mMediator;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        mModelList = new ModelList();
+        mMediator = new CommerceBottomSheetContentMediator(mModelList);
+    }
+
+    private PropertyModel createPropertyModel(int type) {
+        return new PropertyModel.Builder(CommerceBottomSheetContentProperties.ALL_KEYS)
+                .with(CommerceBottomSheetContentProperties.TYPE, type)
+                .with(CommerceBottomSheetContentProperties.HAS_TITLE, true)
+                .with(CommerceBottomSheetContentProperties.TITLE, "title")
+                .with(CommerceBottomSheetContentProperties.CUSTOM_VIEW, mContentCustomView)
+                .build();
+    }
+
+    @Test(expected = AssertionError.class)
+    public void testOnContentReady_assertOnInvalidPropertyModel() {
+        mMediator.onContentReady(new PropertyModel());
+    }
+
+    @Test
+    public void testOnContentReady_firstPropertyModel() {
+        mMediator.onContentReady(createPropertyModel(0));
+
+        assertEquals(1, mModelList.size());
+    }
+
+    @Test
+    public void testOnContentReady_MultiPropertyModels() {
+        PropertyModel model0 = createPropertyModel(0);
+        PropertyModel model1 = createPropertyModel(1);
+        PropertyModel model2 = createPropertyModel(2);
+
+        mMediator.onContentReady(model1);
+        mMediator.onContentReady(model0);
+        mMediator.onContentReady(model2);
+
+        assertEquals(3, mModelList.size());
+        assertEquals(model0, mModelList.get(0).model);
+        assertEquals(model1, mModelList.get(1).model);
+        assertEquals(model2, mModelList.get(2).model);
+    }
+
+    @Test(expected = AssertionError.class)
+    public void testOnContentReady_assertOnSameType() {
+        PropertyModel model0 = createPropertyModel(0);
+        PropertyModel model1 = createPropertyModel(0);
+
+        mMediator.onContentReady(model0);
+        mMediator.onContentReady(model1);
+    }
+}
diff --git a/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingUIDelegateImpl.java b/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingUIDelegateImpl.java
index 9a7bd39..b3c427f 100644
--- a/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingUIDelegateImpl.java
+++ b/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingUIDelegateImpl.java
@@ -11,7 +11,6 @@
 import androidx.annotation.NonNull;
 
 import org.chromium.base.Callback;
-import org.chromium.base.UserData;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.components.data_sharing.DataSharingUIDelegate;
 import org.chromium.components.data_sharing.configs.AvatarConfig;
@@ -22,7 +21,7 @@
 import java.util.List;
 
 /** Implementation of {@link DataSharingUIDelegate}. */
-class DataSharingUIDelegateImpl implements DataSharingUIDelegate, UserData {
+class DataSharingUIDelegateImpl implements DataSharingUIDelegate {
 
     private final Profile mProfile;
 
diff --git a/chrome/browser/devtools/BUILD.gn b/chrome/browser/devtools/BUILD.gn
index 4d0feef9..4fb5c2e0b 100644
--- a/chrome/browser/devtools/BUILD.gn
+++ b/chrome/browser/devtools/BUILD.gn
@@ -110,6 +110,7 @@
     "//chrome/browser/search",
     "//chrome/browser/search_engines",
     "//chrome/browser/sync",
+    "//chrome/browser/ui/autofill",
 
     # To prevent circular GN dependencies, this target does not depend on
     # //chrome/browser:browser, even though it has a real build dependency on
@@ -138,7 +139,10 @@
   ]
 
   if (!is_android) {
-    public_deps += [ "//chrome/browser/ui/tabs:tab_strip_model_observer" ]
+    public_deps += [
+      "//chrome/browser/ui:browser_list",
+      "//chrome/browser/ui/tabs:tab_strip_model_observer",
+    ]
     deps += [
       "//build:chromeos_buildflags",
       "//chrome:extra_resources",
diff --git a/chrome/browser/download/android/download_utils.cc b/chrome/browser/download/android/download_utils.cc
index 7fbe603..7251f54 100644
--- a/chrome/browser/download/android/download_utils.cc
+++ b/chrome/browser/download/android/download_utils.cc
@@ -17,6 +17,8 @@
 #include "components/download/public/common/download_utils.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/download_item_utils.h"
+#include "content/public/browser/download_manager.h"
+#include "content/public/browser/download_manager_delegate.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "url/gurl.h"
 
@@ -45,6 +47,16 @@
       true /* user_action_required */));
 }
 
+static jboolean JNI_DownloadUtils_IsDownloadRestrictedByPolicy(
+    JNIEnv* env,
+    Profile* profile) {
+  content::DownloadManager* manager = profile->GetDownloadManager();
+  if (manager) {
+    return manager->GetDelegate()->IsDownloadRestrictedByPolicy();
+  }
+  return false;
+}
+
 // static
 base::FilePath DownloadUtils::GetUriStringForPath(
     const base::FilePath& file_path) {
diff --git a/chrome/browser/download/chrome_download_manager_delegate.cc b/chrome/browser/download/chrome_download_manager_delegate.cc
index 9dcb675..f6cdc397 100644
--- a/chrome/browser/download/chrome_download_manager_delegate.cc
+++ b/chrome/browser/download/chrome_download_manager_delegate.cc
@@ -2101,6 +2101,11 @@
 bool ChromeDownloadManagerDelegate::ShouldOpenPdfInline() {
   return ShouldOpenPdfInlineInternal(profile_->IsOffTheRecord());
 }
+
+bool ChromeDownloadManagerDelegate::IsDownloadRestrictedByPolicy() {
+  return download_prefs_->download_restriction() ==
+         DownloadPrefs::DownloadRestriction::ALL_FILES;
+}
 #endif  // BUILDFLAG(IS_ANDROID)
 
 #if BUILDFLAG(FULL_SAFE_BROWSING)
diff --git a/chrome/browser/download/chrome_download_manager_delegate.h b/chrome/browser/download/chrome_download_manager_delegate.h
index 5fad334..32d23a0 100644
--- a/chrome/browser/download/chrome_download_manager_delegate.h
+++ b/chrome/browser/download/chrome_download_manager_delegate.h
@@ -158,6 +158,7 @@
 #if BUILDFLAG(IS_ANDROID)
   bool IsFromExternalApp(download::DownloadItem* item) override;
   bool ShouldOpenPdfInline() override;
+  bool IsDownloadRestrictedByPolicy() override;
 #else
   void AttachExtraInfo(download::DownloadItem* item) override;
 #endif  // BUILDFLAG(IS_ANDROID)
diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn
index a48702c..b874faa7 100644
--- a/chrome/browser/extensions/BUILD.gn
+++ b/chrome/browser/extensions/BUILD.gn
@@ -746,6 +746,7 @@
     "//chrome/browser/media/webrtc",
     "//chrome/browser/resource_coordinator:tab_lifecycle_observer",
     "//chrome/browser/task_manager",
+    "//chrome/browser/ui:browser_list",
     "//chrome/browser/ui/tabs:tab_strip_model_observer",
     "//chrome/common",
     "//chrome/common/extensions/api",
@@ -787,6 +788,7 @@
     "//chrome/browser/ui:browser_navigator_params_headers",
     "//chrome/browser/ui:ui_features",
     "//chrome/browser/ui/apps",
+    "//chrome/browser/ui/autofill",
     "//chrome/browser/ui/browser_window",
     "//chrome/browser/ui/views/side_panel",
     "//chrome/browser/ui/views/toolbar",
diff --git a/chrome/browser/extensions/api/cookies/cookies_api.cc b/chrome/browser/extensions/api/cookies/cookies_api.cc
index 21df21d..e7ecb33 100644
--- a/chrome/browser/extensions/api/cookies/cookies_api.cc
+++ b/chrome/browser/extensions/api/cookies/cookies_api.cc
@@ -22,6 +22,7 @@
 #include "chrome/browser/safe_browsing/extension_telemetry/cookies_get_signal.h"
 #include "chrome/browser/safe_browsing/extension_telemetry/extension_telemetry_service.h"
 #include "chrome/browser/safe_browsing/extension_telemetry/extension_telemetry_service_factory.h"
+#include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/common/extensions/api/cookies.h"
 #include "components/safe_browsing/core/common/features.h"
diff --git a/chrome/browser/extensions/api/settings_private/prefs_util.cc b/chrome/browser/extensions/api/settings_private/prefs_util.cc
index 526ec55..a44658d9 100644
--- a/chrome/browser/extensions/api/settings_private/prefs_util.cc
+++ b/chrome/browser/extensions/api/settings_private/prefs_util.cc
@@ -89,6 +89,7 @@
 #include "chrome/browser/ash/system/timezone_util.h"
 #include "chrome/browser/extensions/api/settings_private/chromeos_resolve_time_zone_by_geolocation_method_short.h"
 #include "chrome/browser/extensions/api/settings_private/chromeos_resolve_time_zone_by_geolocation_on_off.h"
+#include "chrome/browser/policy/profile_policy_connector.h"
 #include "chromeos/ash/components/settings/cros_settings.h"
 #include "chromeos/ash/components/settings/cros_settings_names.h"
 #include "chromeos/ash/components/tether/pref_names.h"
@@ -1645,6 +1646,21 @@
 #endif
   }
 
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  // Secure DNS configurations should apply to the current user session. The
+  // secure DNS preferences are mapped to local_state, which is applied to the
+  // current user session on all platforms except Chrome OS. On Chrome OS,
+  // local_state is a global pref service so the user preference has to be
+  // explicitly mapped to profile prefs when changed in chrome://settings.
+  if (pref_name == prefs::kDnsOverHttpsMode ||
+      pref_name == prefs::kDnsOverHttpsTemplates) {
+    if (profile_->GetProfilePolicyConnector()->IsManaged()) {
+      return g_browser_process->local_state();
+    }
+    return user_prefs;
+  }
+#endif
+
   // Find which PrefService contains the given pref. Pref names should not
   // be duplicated across services, however if they are, prefer the user's
   // prefs.
diff --git a/chrome/browser/facilitated_payments/BUILD.gn b/chrome/browser/facilitated_payments/BUILD.gn
index b21fe7e9..8170f1b 100644
--- a/chrome/browser/facilitated_payments/BUILD.gn
+++ b/chrome/browser/facilitated_payments/BUILD.gn
@@ -16,6 +16,7 @@
     "//chrome/browser/autofill",
     "//chrome/browser/facilitated_payments/ui/android",
     "//chrome/browser/profiles:profile",
+    "//chrome/browser/ui/autofill",
     "//components/autofill/core/browser",
     "//components/facilitated_payments/content/browser",
     "//components/facilitated_payments/core/browser",
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 048dc73..53d64da 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -2866,6 +2866,11 @@
     "expiry_milestone" : 116
   },
   {
+    "name": "enable-cros-ime-switch-check-connection-status",
+    "owners": [ "zacpartridge@chromium.org", "essential-inputs-team@google.com" ],
+    "expiry_milestone": 135
+  },
+  {
     "name": "enable-cros-ime-system-emoji-picker-clipboard",
     "owners": [ "jopalmer@chromium.org", "essential-inputs-team@google.com" ],
     "expiry_milestone": 116
@@ -3529,12 +3534,17 @@
     "owners": [ "schechter@chromium.org", "hujasonx@chromium.org" ],
     "expiry_milestone": 125
   },
-    {
+  {
     "name": "enable-lens-overlay",
     "owners": [ "stkhapugin@chromium.org", "jdonnelly@chromium.org", "lens-chrome@google.com" ],
     "expiry_milestone": 135
   },
   {
+    "name": "enable-lens-overlay-translate-button",
+    "owners": [ "juanmojica@google.com", "jdonnelly@chromium.org", "lens-chrome@google.com" ],
+    "expiry_milestone": 135
+  },
+  {
     "name": "enable-lens-region-search-static-page",
     "owners": ["juanmojica@google.com", "stanfield@google.com", "lens-chrome@google.com"],
     "expiry_milestone": 126
@@ -3830,7 +3840,7 @@
     "owners": [
       "simonha@chromium.org"
     ],
-    "expiry_milestone": 130
+    "expiry_milestone": 140
   },
   {
     "name": "enable-process-per-site-up-to-main-frame-threshold",
@@ -3916,7 +3926,7 @@
   {
     "name": "enable-run-on-os-login",
     "owners": [ "sfiss@chromium.org" ],
-    "expiry_milestone": 130
+    "expiry_milestone": 140
   },
   {
     "name": "enable-save-to-drive",
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index b90702f..3dcb734 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -2428,6 +2428,10 @@
 const char kLensOverlayDescription[] =
     "Enables Lens search via an overlay on any page.";
 
+const char kLensOverlayTranslateButtonName[] = "Lens overlay translate button";
+const char kLensOverlayTranslateButtonDescription[] =
+    "Enables translate button via the Lens overlay.";
+
 const char kLensImageTranslateName[] =
     "Translate text in images with Google Lens";
 const char kLensImageTranslateDescription[] =
@@ -7115,6 +7119,12 @@
     "When enabled and in Korean input method, right-Alt key location solely "
     "toggles internal Korean/English mode, without Alt modifier functionality";
 
+const char kImeSwitchCheckConnectionStatusName[] =
+    "Enable Ime switching using global boolean";
+const char kImeSwitchCheckConnectionStatusDescription[] =
+    "When enabled and swapping between input methods, this prevents a race "
+    "condition.";
+
 const char kIppFirstSetupForUsbPrintersName[] =
     "Try to setup USB printers with IPP first";
 const char kIppFirstSetupForUsbPrintersDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index c34274c88..3d92f9e 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1372,6 +1372,9 @@
 extern const char kLensOverlayName[];
 extern const char kLensOverlayDescription[];
 
+extern const char kLensOverlayTranslateButtonName[];
+extern const char kLensOverlayTranslateButtonDescription[];
+
 extern const char kLensImageFormatOptimizationsName[];
 extern const char kLensImageFormatOptimizationsDescription[];
 
@@ -4108,6 +4111,9 @@
 extern const char kImeKoreanOnlyModeSwitchOnRightAltName[];
 extern const char kImeKoreanOnlyModeSwitchOnRightAltDescription[];
 
+extern const char kImeSwitchCheckConnectionStatusName[];
+extern const char kImeSwitchCheckConnectionStatusDescription[];
+
 extern const char kIppFirstSetupForUsbPrintersName[];
 extern const char kIppFirstSetupForUsbPrintersDescription[];
 
diff --git a/chrome/browser/language_detection/OWNERS b/chrome/browser/language_detection/OWNERS
new file mode 100644
index 0000000..f619a2976
--- /dev/null
+++ b/chrome/browser/language_detection/OWNERS
@@ -0,0 +1 @@
+file://components/language_detection/OWNERS
diff --git a/chrome/browser/translate/translate_model_service_factory.cc b/chrome/browser/language_detection/language_detection_model_service_factory.cc
similarity index 62%
rename from chrome/browser/translate/translate_model_service_factory.cc
rename to chrome/browser/language_detection/language_detection_model_service_factory.cc
index ced8737..14f7384d 100644
--- a/chrome/browser/translate/translate_model_service_factory.cc
+++ b/chrome/browser/language_detection/language_detection_model_service_factory.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/translate/translate_model_service_factory.h"
+#include "chrome/browser/language_detection/language_detection_model_service_factory.h"
 
 #include "base/memory/scoped_refptr.h"
 #include "base/no_destructor.h"
@@ -12,25 +12,26 @@
 #include "chrome/browser/optimization_guide/optimization_guide_keyed_service.h"
 #include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
-#include "components/translate/core/browser/translate_model_service.h"
+#include "components/language_detection/core/browser/language_detection_model_service.h"
 #include "components/translate/core/common/translate_util.h"
 
 // static
-translate::TranslateModelService* TranslateModelServiceFactory::GetForProfile(
-    Profile* profile) {
-  return static_cast<translate::TranslateModelService*>(
+language_detection::LanguageDetectionModelService*
+LanguageDetectionModelServiceFactory::GetForProfile(Profile* profile) {
+  return static_cast<language_detection::LanguageDetectionModelService*>(
       GetInstance()->GetServiceForBrowserContext(profile, true));
 }
 
 // static
-TranslateModelServiceFactory* TranslateModelServiceFactory::GetInstance() {
-  static base::NoDestructor<TranslateModelServiceFactory> factory;
+LanguageDetectionModelServiceFactory*
+LanguageDetectionModelServiceFactory::GetInstance() {
+  static base::NoDestructor<LanguageDetectionModelServiceFactory> factory;
   return factory.get();
 }
 
-TranslateModelServiceFactory::TranslateModelServiceFactory()
+LanguageDetectionModelServiceFactory::LanguageDetectionModelServiceFactory()
     : ProfileKeyedServiceFactory(
-          "TranslateModelService",
+          "LanguageDetectionModelService",
           ProfileSelections::Builder()
               .WithRegular(ProfileSelection::kOwnInstance)
               // TODO(crbug.com/40257657): Check if this service is needed in
@@ -40,16 +41,19 @@
               // Ash Internals.
               .WithAshInternals(ProfileSelection::kOwnInstance)
               .Build()) {
-  if (translate::IsTFLiteLanguageDetectionEnabled())
+  if (translate::IsTFLiteLanguageDetectionEnabled()) {
     DependsOn(OptimizationGuideKeyedServiceFactory::GetInstance());
+  }
 }
 
-TranslateModelServiceFactory::~TranslateModelServiceFactory() = default;
+LanguageDetectionModelServiceFactory::~LanguageDetectionModelServiceFactory() =
+    default;
 
-KeyedService* TranslateModelServiceFactory::BuildServiceInstanceFor(
+KeyedService* LanguageDetectionModelServiceFactory::BuildServiceInstanceFor(
     content::BrowserContext* context) const {
-  if (!translate::IsTFLiteLanguageDetectionEnabled())
+  if (!translate::IsTFLiteLanguageDetectionEnabled()) {
     return nullptr;
+  }
 
   // The optimization guide service must be available for the translate model
   // service to be created.
@@ -60,8 +64,8 @@
     scoped_refptr<base::SequencedTaskRunner> background_task_runner =
         base::ThreadPool::CreateSequencedTaskRunner(
             {base::MayBlock(), base::TaskPriority::BEST_EFFORT});
-    return new translate::TranslateModelService(opt_guide,
-                                                background_task_runner);
+    return new language_detection::LanguageDetectionModelService(
+        opt_guide, background_task_runner);
   }
   return nullptr;
 }
diff --git a/chrome/browser/language_detection/language_detection_model_service_factory.h b/chrome/browser/language_detection/language_detection_model_service_factory.h
new file mode 100644
index 0000000..2c1b5bb
--- /dev/null
+++ b/chrome/browser/language_detection/language_detection_model_service_factory.h
@@ -0,0 +1,44 @@
+// Copyright 2020 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_LANGUAGE_DETECTION_LANGUAGE_DETECTION_MODEL_SERVICE_FACTORY_H_
+#define CHROME_BROWSER_LANGUAGE_DETECTION_LANGUAGE_DETECTION_MODEL_SERVICE_FACTORY_H_
+
+#include "base/no_destructor.h"
+#include "chrome/browser/profiles/profile_keyed_service_factory.h"
+#include "components/language_detection/core/browser/language_detection_model_service.h"
+
+namespace content {
+class BrowserContext;
+}  // namespace content
+
+class Profile;
+
+// LazyInstance that owns all LanguageDetectionModelService(s) and associates
+// them with Profiles.
+class LanguageDetectionModelServiceFactory : public ProfileKeyedServiceFactory {
+ public:
+  // Gets the LanguageDetectionModelService for the profile.
+  //
+  // Returns null if the features that allow for this to provide useful
+  // information are disabled. Importantly, only available when the
+  // optimization guide service is.
+  static language_detection::LanguageDetectionModelService* GetForProfile(
+      Profile* profile);
+
+  // Gets the LazyInstance that owns all LanguageDetectionModelService(s).
+  static LanguageDetectionModelServiceFactory* GetInstance();
+
+ private:
+  friend base::NoDestructor<LanguageDetectionModelServiceFactory>;
+
+  LanguageDetectionModelServiceFactory();
+  ~LanguageDetectionModelServiceFactory() override;
+
+  // BrowserContextKeyedServiceFactory:
+  KeyedService* BuildServiceInstanceFor(
+      content::BrowserContext* context) const override;
+};
+
+#endif  // CHROME_BROWSER_LANGUAGE_DETECTION_LANGUAGE_DETECTION_MODEL_SERVICE_FACTORY_H_
diff --git a/chrome/browser/translate/language_detection_service_browsertest.cc b/chrome/browser/language_detection/language_detection_service_browsertest.cc
similarity index 99%
rename from chrome/browser/translate/language_detection_service_browsertest.cc
rename to chrome/browser/language_detection/language_detection_service_browsertest.cc
index 9a05596..1fd86ed3 100644
--- a/chrome/browser/translate/language_detection_service_browsertest.cc
+++ b/chrome/browser/language_detection/language_detection_service_browsertest.cc
@@ -2,13 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "components/services/language_detection/public/cpp/language_detection_service.h"
+
 #include <string>
 
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/bind.h"
 #include "chrome/test/base/in_process_browser_test.h"
-#include "components/services/language_detection/public/cpp/language_detection_service.h"
 #include "components/services/language_detection/public/mojom/language_detection.mojom.h"
 #include "content/public/test/browser_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/manta/manta_service_factory.cc b/chrome/browser/manta/manta_service_factory.cc
index 495a820..ff5a34c 100644
--- a/chrome/browser/manta/manta_service_factory.cc
+++ b/chrome/browser/manta/manta_service_factory.cc
@@ -6,7 +6,9 @@
 
 #include <memory>
 
+#include "base/version.h"
 #include "base/version_info/channel.h"
+#include "base/version_info/version_info.h"
 #include "build/chromeos_buildflags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
@@ -72,16 +74,16 @@
                                               signin::ConsentLevel::kSync);
   bool is_otr_profile = !profile->IsRegularProfile() || !is_signed_in;
 
-  std::string chrome_version, locale;
-  if (PrefService* pref_service = profile->GetPrefs()) {
-    chrome_version = pref_service->GetString(prefs::kProfileCreatedByVersion);
-    // Check to make sure that the locale pref is set before accessing.
+  std::string chrome_version = version_info::GetVersion().GetString();
+  std::string locale;
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+  if (PrefService* pref_service = profile->GetPrefs()) {
+    // Check to make sure that the locale pref is set before accessing.
     locale = pref_service->GetString(language::prefs::kApplicationLocale);
-#else
-    locale = g_browser_process->GetApplicationLocale();
-#endif
   }
+#else
+  locale = g_browser_process->GetApplicationLocale();
+#endif
 
   return std::make_unique<MantaService>(
       profile->GetDefaultStoragePartition()
diff --git a/chrome/browser/media/webrtc/BUILD.gn b/chrome/browser/media/webrtc/BUILD.gn
index 567705e..ac14cb43 100644
--- a/chrome/browser/media/webrtc/BUILD.gn
+++ b/chrome/browser/media/webrtc/BUILD.gn
@@ -195,6 +195,7 @@
       "//extensions/buildflags",
     ]
     deps += [
+      "//chrome/browser/ui:browser_list",
       "//extensions/browser",
       "//extensions/browser/kiosk",
       "//extensions/common",
diff --git a/chrome/browser/net/dns_probe_browsertest.cc b/chrome/browser/net/dns_probe_browsertest.cc
index 724559b0e..b74167d5 100644
--- a/chrome/browser/net/dns_probe_browsertest.cc
+++ b/chrome/browser/net/dns_probe_browsertest.cc
@@ -432,11 +432,16 @@
     content::FlushNetworkServiceInstanceForTesting();
 
     // Update prefs to enable Secure DNS in secure mode.
-    PrefService* local_state = g_browser_process->local_state();
-    local_state->SetString(prefs::kDnsOverHttpsMode,
-                           SecureDnsConfig::kModeSecure);
-    local_state->SetString(prefs::kDnsOverHttpsTemplates,
-                           "https://bar.test/dns-query{?dns}");
+    PrefService* pref_service = g_browser_process->local_state();
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+    // On Chrome OS, the local_state is shared between all users so the user-set
+    // pref is stored in the profile's pref service.
+    pref_service = browser()->profile()->GetPrefs();
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+    pref_service->SetString(prefs::kDnsOverHttpsMode,
+                            SecureDnsConfig::kModeSecure);
+    pref_service->SetString(prefs::kDnsOverHttpsTemplates,
+                            "https://bar.test/dns-query{?dns}");
 
     SetFakeHostResolverResults(
         {{net::ERR_NAME_NOT_RESOLVED,
diff --git a/chrome/browser/net/stub_resolver_config_reader_browsertest.cc b/chrome/browser/net/stub_resolver_config_reader_browsertest.cc
index 71ab870..a771e17b 100644
--- a/chrome/browser/net/stub_resolver_config_reader_browsertest.cc
+++ b/chrome/browser/net/stub_resolver_config_reader_browsertest.cc
@@ -139,10 +139,19 @@
   std::string multiple_good_templates =
       "  " + good_get_template + "   " + good_post_template + "  ";
 
-  PrefService* local_state = g_browser_process->local_state();
-  local_state->SetString(prefs::kDnsOverHttpsMode,
-                         SecureDnsConfig::kModeSecure);
-  local_state->SetString(kDnsOverHttpsTemplatesPrefName, bad_template);
+  PrefService* pref_service_for_user_settings =
+      g_browser_process->local_state();
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  // On ChromeOS, the local_state is shared between all users so the user-set
+  // pref is stored in the profile's pref service.
+  pref_service_for_user_settings = browser()->profile()->GetPrefs();
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+
+  pref_service_for_user_settings->SetString(prefs::kDnsOverHttpsMode,
+                                            SecureDnsConfig::kModeSecure);
+  pref_service_for_user_settings->SetString(kDnsOverHttpsTemplatesPrefName,
+                                            bad_template);
   SecureDnsConfig secure_dns_config = config_reader_->GetSecureDnsConfiguration(
       false /* force_check_parental_controls_for_automatic_mode */);
   EXPECT_EQ(async_dns_feature_enabled,
@@ -150,7 +159,8 @@
   EXPECT_EQ(net::SecureDnsMode::kSecure, secure_dns_config.mode());
   EXPECT_THAT(secure_dns_config.doh_servers().servers(), testing::IsEmpty());
 
-  local_state->SetString(kDnsOverHttpsTemplatesPrefName, good_post_template);
+  pref_service_for_user_settings->SetString(kDnsOverHttpsTemplatesPrefName,
+                                            good_post_template);
   secure_dns_config = config_reader_->GetSecureDnsConfiguration(
       false /* force_check_parental_controls_for_automatic_mode */);
   EXPECT_EQ(async_dns_feature_enabled,
@@ -159,9 +169,10 @@
   EXPECT_EQ(*net::DnsOverHttpsConfig::FromString(good_post_template),
             secure_dns_config.doh_servers());
 
-  local_state->SetString(prefs::kDnsOverHttpsMode,
-                         SecureDnsConfig::kModeAutomatic);
-  local_state->SetString(kDnsOverHttpsTemplatesPrefName, bad_template);
+  pref_service_for_user_settings->SetString(prefs::kDnsOverHttpsMode,
+                                            SecureDnsConfig::kModeAutomatic);
+  pref_service_for_user_settings->SetString(kDnsOverHttpsTemplatesPrefName,
+                                            bad_template);
   secure_dns_config = config_reader_->GetSecureDnsConfiguration(
       false /* force_check_parental_controls_for_automatic_mode */);
   EXPECT_EQ(async_dns_feature_enabled,
@@ -169,8 +180,8 @@
   EXPECT_EQ(net::SecureDnsMode::kAutomatic, secure_dns_config.mode());
   EXPECT_THAT(secure_dns_config.doh_servers().servers(), testing::IsEmpty());
 
-  local_state->SetString(kDnsOverHttpsTemplatesPrefName,
-                         good_then_bad_template);
+  pref_service_for_user_settings->SetString(kDnsOverHttpsTemplatesPrefName,
+                                            good_then_bad_template);
   secure_dns_config = config_reader_->GetSecureDnsConfiguration(
       false /* force_check_parental_controls_for_automatic_mode */);
   EXPECT_EQ(async_dns_feature_enabled,
@@ -179,8 +190,8 @@
   EXPECT_EQ(*net::DnsOverHttpsConfig::FromString(good_get_template),
             secure_dns_config.doh_servers());
 
-  local_state->SetString(kDnsOverHttpsTemplatesPrefName,
-                         bad_then_good_template);
+  pref_service_for_user_settings->SetString(kDnsOverHttpsTemplatesPrefName,
+                                            bad_then_good_template);
   secure_dns_config = config_reader_->GetSecureDnsConfiguration(
       false /* force_check_parental_controls_for_automatic_mode */);
   EXPECT_EQ(async_dns_feature_enabled,
@@ -189,8 +200,8 @@
   EXPECT_EQ(*net::DnsOverHttpsConfig::FromString(good_get_template),
             secure_dns_config.doh_servers());
 
-  local_state->SetString(kDnsOverHttpsTemplatesPrefName,
-                         multiple_good_templates);
+  pref_service_for_user_settings->SetString(kDnsOverHttpsTemplatesPrefName,
+                                            multiple_good_templates);
   secure_dns_config = config_reader_->GetSecureDnsConfiguration(
       false /* force_check_parental_controls_for_automatic_mode */);
   EXPECT_EQ(async_dns_feature_enabled,
@@ -199,8 +210,10 @@
   EXPECT_EQ(*net::DnsOverHttpsConfig::FromString(multiple_good_templates),
             secure_dns_config.doh_servers());
 
-  local_state->SetString(prefs::kDnsOverHttpsMode, SecureDnsConfig::kModeOff);
-  local_state->SetString(kDnsOverHttpsTemplatesPrefName, good_get_template);
+  pref_service_for_user_settings->SetString(prefs::kDnsOverHttpsMode,
+                                            SecureDnsConfig::kModeOff);
+  pref_service_for_user_settings->SetString(kDnsOverHttpsTemplatesPrefName,
+                                            good_get_template);
   secure_dns_config = config_reader_->GetSecureDnsConfiguration(
       false /* force_check_parental_controls_for_automatic_mode */);
   EXPECT_EQ(async_dns_feature_enabled,
@@ -208,7 +221,8 @@
   EXPECT_EQ(net::SecureDnsMode::kOff, secure_dns_config.mode());
   EXPECT_THAT(secure_dns_config.doh_servers().servers(), testing::IsEmpty());
 
-  local_state->SetString(prefs::kDnsOverHttpsMode, "no_match");
+  pref_service_for_user_settings->SetString(prefs::kDnsOverHttpsMode,
+                                            "no_match");
   secure_dns_config = config_reader_->GetSecureDnsConfiguration(
       false /* force_check_parental_controls_for_automatic_mode */);
   EXPECT_EQ(async_dns_feature_enabled,
@@ -218,8 +232,10 @@
 
   // Test case with policy BuiltInDnsClientEnabled enabled. The DoH fields
   // should be unaffected.
-  local_state->Set(prefs::kBuiltInDnsClientEnabled,
-                   base::Value(!async_dns_feature_enabled));
+  // The `prefs::kBuiltInDnsClientEnabled` pref is stored on local_state on all
+  // platforms (including Chrome OS).
+  g_browser_process->local_state()->Set(
+      prefs::kBuiltInDnsClientEnabled, base::Value(!async_dns_feature_enabled));
   secure_dns_config = config_reader_->GetSecureDnsConfiguration(
       false /* force_check_parental_controls_for_automatic_mode */);
   EXPECT_EQ(!async_dns_feature_enabled,
@@ -382,35 +398,6 @@
   EXPECT_THAT(secure_dns_config.doh_servers().servers(), testing::IsEmpty());
 }
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-constexpr char kTemplateIdentifiers[] =
-    "https://dns.google.alternativeuri/"
-    "${USER_EMAIL}";
-constexpr char kEffectiveTemplateIdentifiers[] =
-    "https://dns.google.alternativeuri/"
-    "8E71AF9783B71B6996DAE103B28BC55882BD5CB93B29260D000D8121D9D10977";
-IN_PROC_BROWSER_TEST_P(StubResolverConfigReaderBrowsertest,
-                       DohWithIdentifiers) {
-  PrefService* local_state = g_browser_process->local_state();
-
-  std::unique_ptr<ash::SecureDnsManager> secure_dns_manager =
-      std::make_unique<ash::SecureDnsManager>(local_state,
-                                              /*is_profile_managed=*/true);
-
-  local_state->SetString(prefs::kDnsOverHttpsMode,
-                         SecureDnsConfig::kModeSecure);
-  local_state->SetString(prefs::kDnsOverHttpsTemplatesWithIdentifiers,
-                         kTemplateIdentifiers);
-  local_state->SetString(prefs::kDnsOverHttpsSalt, "test-salt");
-
-  SecureDnsConfig secure_dns_config = config_reader_->GetSecureDnsConfiguration(
-      false /* force_check_parental_controls_for_automatic_mode */);
-
-  EXPECT_EQ(secure_dns_config.doh_servers().ToString(),
-            kEffectiveTemplateIdentifiers);
-}
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
-
 INSTANTIATE_TEST_SUITE_P(All,
                          StubResolverConfigReaderBrowsertest,
                          ::testing::Bool());
diff --git a/chrome/browser/page_load_metrics/observers/prerender_page_load_metrics_observer_browsertest.cc b/chrome/browser/page_load_metrics/observers/prerender_page_load_metrics_observer_browsertest.cc
index 9f46c9c..47b9b80 100644
--- a/chrome/browser/page_load_metrics/observers/prerender_page_load_metrics_observer_browsertest.cc
+++ b/chrome/browser/page_load_metrics/observers/prerender_page_load_metrics_observer_browsertest.cc
@@ -75,10 +75,6 @@
       content::PreloadingTriggerType trigger_type =
           content::PreloadingTriggerType::kSpeculationRule,
       const std::string& embedder_suffix = "") {
-    histogram_tester().ExpectBucketCount(
-        internal::kPageLoadPrerenderObserverEvent,
-        internal::PageLoadPrerenderObserverEvent::kOnFirstPaintInPage, 1);
-
     // FirstPaint should be recorded in the prerender PageLoad, not in the
     // regular PageLoad.
     histogram_tester().ExpectTotalCount(
@@ -93,11 +89,6 @@
       content::PreloadingTriggerType trigger_type =
           content::PreloadingTriggerType::kSpeculationRule,
       const std::string& embedder_suffix = "") {
-    histogram_tester().ExpectBucketCount(
-        internal::kPageLoadPrerenderObserverEvent,
-        internal::PageLoadPrerenderObserverEvent::kOnFirstContentfulPaintInPage,
-        1);
-
     // FirstContentfulPaint should be recorded in the prerender PageLoad, not in
     // the regular PageLoad.
     histogram_tester().ExpectTotalCount(
@@ -113,10 +104,6 @@
       content::PreloadingTriggerType trigger_type =
           content::PreloadingTriggerType::kSpeculationRule,
       const std::string& embedder_suffix = "") {
-    histogram_tester().ExpectBucketCount(
-        internal::kPageLoadPrerenderObserverEvent,
-        internal::PageLoadPrerenderObserverEvent::kOnFirstInputInPage, 1);
-
     // FirstInputDelay should be recorded in the prerender PageLoad, not in the
     // regular PageLoad.
     histogram_tester().ExpectTotalCount(
@@ -131,14 +118,6 @@
       content::PreloadingTriggerType trigger_type =
           content::PreloadingTriggerType::kSpeculationRule,
       const std::string& embedder_suffix = "") {
-    histogram_tester().ExpectBucketCount(
-        internal::kPageLoadPrerenderObserverEvent,
-        internal::PageLoadPrerenderObserverEvent::kOnComplete, 1);
-    histogram_tester().ExpectBucketCount(
-        internal::kPageLoadPrerenderObserverEvent,
-        internal::PageLoadPrerenderObserverEvent::kRecordSessionEndHistograms,
-        1);
-
     // LargestContentfulPaint should be recorded in the prerender PageLoad, not
     // in the regular PageLoad.
     histogram_tester().ExpectTotalCount(
@@ -151,12 +130,6 @@
   }
 
   void CheckResponsivenessMetrics(const GURL& url) {
-    histogram_tester().ExpectBucketCount(
-        internal::kPageLoadPrerenderObserverEvent,
-        internal::PageLoadPrerenderObserverEvent::
-            kRecordNormalizedResponsivenessMetrics,
-        1);
-
     std::vector<std::string> ukm_list = {
         "InteractiveTiming.WorstUserInteractionLatency.MaxEventDuration",
         "InteractiveTiming.UserInteractionLatency.HighPercentile2."
@@ -212,10 +185,6 @@
   GURL prerender_url = embedded_test_server()->GetURL("/title2.html");
   prerender_helper_.AddPrerender(prerender_url);
 
-  histogram_tester().ExpectBucketCount(
-      internal::kPageLoadPrerenderObserverEvent,
-      internal::PageLoadPrerenderObserverEvent::kOnPrerenderStart, 1);
-
   // Activate and wait for FCP.
   auto waiter = std::make_unique<page_load_metrics::PageLoadMetricsTestWaiter>(
       web_contents());
@@ -224,12 +193,6 @@
   prerender_helper_.NavigatePrimaryPage(prerender_url);
   waiter->Wait();
 
-  histogram_tester().ExpectBucketCount(
-      page_load_metrics::internal::kPageLoadPrerender2VisibilityAtActivation,
-      page_load_metrics::internal::VisibilityAtActivation::kVisible, 1);
-  histogram_tester().ExpectBucketCount(
-      internal::kPageLoadPrerenderObserverEvent,
-      internal::PageLoadPrerenderObserverEvent::kDidActivatePrerenderedPage, 1);
   histogram_tester().ExpectTotalCount(
       prerender_helper_.GenerateHistogramName(
           internal::kHistogramPrerenderNavigationToActivation,
@@ -258,10 +221,6 @@
   // Expect only LCP for prerender is recorded.
   CheckLargestContentfulPaintMetrics();
 
-  histogram_tester().ExpectBucketCount(
-      internal::kPageLoadPrerenderObserverEvent,
-      internal::PageLoadPrerenderObserverEvent::kRecordLayoutShiftScoreMetrics,
-      1);
   histogram_tester().ExpectTotalCount(
       prerender_helper_.GenerateHistogramName(
           internal::kHistogramPrerenderCumulativeShiftScore,
@@ -353,10 +312,6 @@
   GURL prerender_url = embedded_test_server()->GetURL("/title2.html");
   prerender_helper_.AddPrerender(prerender_url);
 
-  histogram_tester().ExpectBucketCount(
-      internal::kPageLoadPrerenderObserverEvent,
-      internal::PageLoadPrerenderObserverEvent::kOnPrerenderStart, 1);
-
   // Start an activation.
   prerender_helper_.NavigatePrimaryPage(prerender_url);
 
@@ -370,19 +325,6 @@
   ASSERT_TRUE(
       ui_test_utils::NavigateToURL(browser(), GURL(url::kAboutBlankURL)));
 
-  // The visibility at activation should be visible as the page gets hidden
-  // after prerender activation starts.
-  histogram_tester().ExpectBucketCount(
-      page_load_metrics::internal::kPageLoadPrerender2VisibilityAtActivation,
-      page_load_metrics::internal::VisibilityAtActivation::kVisible, 1);
-
-  histogram_tester().ExpectBucketCount(
-      internal::kPageLoadPrerenderObserverEvent,
-      internal::PageLoadPrerenderObserverEvent::kOnComplete, 1);
-  histogram_tester().ExpectBucketCount(
-      internal::kPageLoadPrerenderObserverEvent,
-      internal::PageLoadPrerenderObserverEvent::kRecordSessionEndHistograms, 1);
-
   auto entries = GetMergedUkmEntries(PrerenderPageLoad::kEntryName);
   EXPECT_EQ(2u, entries.size());
 
@@ -432,10 +374,6 @@
       prerender_helper_.GetHostForUrl(prerender_url);
   EXPECT_TRUE(host_id);
 
-  histogram_tester().ExpectBucketCount(
-      internal::kPageLoadPrerenderObserverEvent,
-      internal::PageLoadPrerenderObserverEvent::kOnPrerenderStart, 1);
-
   // Activate and wait for FCP.
   auto waiter = std::make_unique<page_load_metrics::PageLoadMetricsTestWaiter>(
       web_contents());
@@ -452,12 +390,6 @@
       /*navigation_handle_callback=*/{});
   waiter->Wait();
 
-  histogram_tester().ExpectBucketCount(
-      page_load_metrics::internal::kPageLoadPrerender2VisibilityAtActivation,
-      page_load_metrics::internal::VisibilityAtActivation::kVisible, 1);
-  histogram_tester().ExpectBucketCount(
-      internal::kPageLoadPrerenderObserverEvent,
-      internal::PageLoadPrerenderObserverEvent::kDidActivatePrerenderedPage, 1);
   histogram_tester().ExpectTotalCount(
       prerender_helper_.GenerateHistogramName(
           internal::kHistogramPrerenderNavigationToActivation,
@@ -493,10 +425,6 @@
       content::PreloadingTriggerType::kEmbedder,
       prerender_utils::kDirectUrlInputMetricSuffix);
 
-  histogram_tester().ExpectBucketCount(
-      internal::kPageLoadPrerenderObserverEvent,
-      internal::PageLoadPrerenderObserverEvent::kRecordLayoutShiftScoreMetrics,
-      1);
   histogram_tester().ExpectTotalCount(
       prerender_helper_.GenerateHistogramName(
           internal::kHistogramPrerenderCumulativeShiftScore,
@@ -547,10 +475,6 @@
   const content::FrameTreeNodeId host_id =
       prerender_helper_.AddPrerender(prerender_url);
 
-  histogram_tester().ExpectBucketCount(
-      internal::kPageLoadPrerenderObserverEvent,
-      internal::PageLoadPrerenderObserverEvent::kOnPrerenderStart, 1);
-
   content::test::PrerenderHostObserver observer(*web_contents(), host_id);
   prerender_helper_.CancelPrerenderedPage(host_id);
   observer.WaitForDestroyed();
@@ -560,26 +484,6 @@
   ASSERT_TRUE(
       ui_test_utils::NavigateToURL(browser(), GURL(url::kAboutBlankURL)));
 
-  histogram_tester().ExpectTotalCount(
-      page_load_metrics::internal::kPageLoadPrerender2VisibilityAtActivation,
-      0);
-  histogram_tester().ExpectBucketCount(
-      internal::kPageLoadPrerenderObserverEvent,
-      internal::PageLoadPrerenderObserverEvent::kDidActivatePrerenderedPage, 0);
-  histogram_tester().ExpectBucketCount(
-      internal::kPageLoadPrerenderObserverEvent,
-      internal::PageLoadPrerenderObserverEvent::kOnFirstPaintInPage, 0);
-  histogram_tester().ExpectBucketCount(
-      internal::kPageLoadPrerenderObserverEvent,
-      internal::PageLoadPrerenderObserverEvent::kOnFirstContentfulPaintInPage,
-      0);
-  histogram_tester().ExpectBucketCount(
-      internal::kPageLoadPrerenderObserverEvent,
-      internal::PageLoadPrerenderObserverEvent::kOnComplete, 1);
-  histogram_tester().ExpectBucketCount(
-      internal::kPageLoadPrerenderObserverEvent,
-      internal::PageLoadPrerenderObserverEvent::kRecordSessionEndHistograms, 1);
-
   // As the prerender was cancelled, no prerendering metrics are recorded.
   EXPECT_EQ(0u, histogram_tester()
                     .GetTotalCountsForPrefix("PageLoad.Clients.Prerender.")
@@ -603,10 +507,6 @@
                                                       redirected_url.spec());
   prerender_helper_.AddPrerender(prerender_url);
 
-  histogram_tester().ExpectBucketCount(
-      internal::kPageLoadPrerenderObserverEvent,
-      internal::PageLoadPrerenderObserverEvent::kOnPrerenderStart, 1);
-
   // Activate and wait for FCP.
   auto waiter = std::make_unique<page_load_metrics::PageLoadMetricsTestWaiter>(
       web_contents());
@@ -615,12 +515,6 @@
   prerender_helper_.NavigatePrimaryPage(prerender_url);
   waiter->Wait();
 
-  histogram_tester().ExpectBucketCount(
-      page_load_metrics::internal::kPageLoadPrerender2VisibilityAtActivation,
-      page_load_metrics::internal::VisibilityAtActivation::kVisible, 1);
-  histogram_tester().ExpectBucketCount(
-      internal::kPageLoadPrerenderObserverEvent,
-      internal::PageLoadPrerenderObserverEvent::kDidActivatePrerenderedPage, 1);
   CheckFirstPaintMetrics();
   CheckFirstContentfulPaintMetrics();
 
@@ -678,10 +572,6 @@
     registry_observer.WaitForTrigger(kPrerenderingUrl);
   }
 
-  histogram_tester().ExpectBucketCount(
-      internal::kPageLoadPrerenderObserverEvent,
-      internal::PageLoadPrerenderObserverEvent::kOnPrerenderStart, 1);
-
   content::FrameTreeNodeId host_id =
       prerender_helper_.GetHostForUrl(kPrerenderingUrl);
   content::test::PrerenderHostObserver prerender_observer(*web_contents(),
@@ -708,13 +598,6 @@
   prerender_observer.WaitForActivation();
   waiter->Wait();
 
-  histogram_tester().ExpectBucketCount(
-      page_load_metrics::internal::kPageLoadPrerender2VisibilityAtActivation,
-      page_load_metrics::internal::VisibilityAtActivation::kVisible, 1);
-  histogram_tester().ExpectBucketCount(
-      internal::kPageLoadPrerenderObserverEvent,
-      internal::PageLoadPrerenderObserverEvent::kDidActivatePrerenderedPage, 1);
-
   // Force navigation to another page, which should force logging of metrics
   // persisted at the end of the page load lifetime.
   ASSERT_TRUE(
@@ -809,12 +692,6 @@
   prerender_helper_.NavigatePrerenderedPage(host_id, navigation_url);
   prerender_helper_.WaitForPrerenderLoadCompletion(host_id);
 
-  // Expect that OnPrerenderStart is called twice for the initial prerender
-  // navigation and the main frame navigation in the prerendered page.
-  histogram_tester().ExpectBucketCount(
-      internal::kPageLoadPrerenderObserverEvent,
-      internal::PageLoadPrerenderObserverEvent::kOnPrerenderStart, 2);
-
   // Activate and wait for FCP.
   auto waiter = std::make_unique<page_load_metrics::PageLoadMetricsTestWaiter>(
       web_contents());
@@ -823,22 +700,6 @@
   prerender_helper_.NavigatePrimaryPage(prerender_url);
   waiter->Wait();
 
-  // "PageLoad.Internal.Prerender2.VisibilityAtActivation" is recorded only once
-  // when the activation is finished. It's not recorded for the initial
-  // prerendering navigation.
-  histogram_tester().ExpectBucketCount(
-      page_load_metrics::internal::kPageLoadPrerender2VisibilityAtActivation,
-      page_load_metrics::internal::VisibilityAtActivation::kVisible, 1);
-  histogram_tester().ExpectBucketCount(
-      page_load_metrics::internal::kPageLoadPrerender2VisibilityAtActivation,
-      page_load_metrics::internal::VisibilityAtActivation::kOccluded, 0);
-  histogram_tester().ExpectBucketCount(
-      page_load_metrics::internal::kPageLoadPrerender2VisibilityAtActivation,
-      page_load_metrics::internal::VisibilityAtActivation::kHidden, 0);
-
-  histogram_tester().ExpectBucketCount(
-      internal::kPageLoadPrerenderObserverEvent,
-      internal::PageLoadPrerenderObserverEvent::kDidActivatePrerenderedPage, 1);
   histogram_tester().ExpectTotalCount(
       prerender_helper_.GenerateHistogramName(
           internal::kHistogramPrerenderNavigationToActivation,
@@ -864,17 +725,6 @@
   ASSERT_TRUE(
       ui_test_utils::NavigateToURL(browser(), GURL(url::kAboutBlankURL)));
 
-  // Expect only LCP for prerender is recorded.
-  // PrerenderPageLoadMetricsObserver::RecordSessionEndHistograms and OnComplete
-  // are called twice but LCP is recorded only once because the initial
-  // prerendered page is finished in the background.
-  histogram_tester().ExpectBucketCount(
-      internal::kPageLoadPrerenderObserverEvent,
-      internal::PageLoadPrerenderObserverEvent::kOnComplete, 2);
-  histogram_tester().ExpectBucketCount(
-      internal::kPageLoadPrerenderObserverEvent,
-      internal::PageLoadPrerenderObserverEvent::kRecordSessionEndHistograms, 2);
-
   // LargestContentfulPaint should be recorded in the prerender PageLoad, not
   // in the regular PageLoad.
   histogram_tester().ExpectTotalCount(
@@ -887,10 +737,6 @@
       internal::kHistogramLargestContentfulPaint, 0);
 
   // Expect CLS for prerender is recorded.
-  histogram_tester().ExpectBucketCount(
-      internal::kPageLoadPrerenderObserverEvent,
-      internal::PageLoadPrerenderObserverEvent::kRecordLayoutShiftScoreMetrics,
-      1);
   histogram_tester().ExpectTotalCount(
       prerender_helper_.GenerateHistogramName(
           internal::kHistogramPrerenderCumulativeShiftScore,
diff --git a/chrome/browser/password_manager/android/BUILD.gn b/chrome/browser/password_manager/android/BUILD.gn
index 67917ba..6d9c146 100644
--- a/chrome/browser/password_manager/android/BUILD.gn
+++ b/chrome/browser/password_manager/android/BUILD.gn
@@ -622,6 +622,7 @@
     "//chrome/browser/sync",
     "//chrome/browser/touch_to_fill/password_manager/password_generation/android:public",
     "//chrome/browser/touch_to_fill/password_manager/password_generation/android:test_support",
+    "//chrome/browser/ui/autofill",
     "//chrome/test:test_support",
     "//components/affiliations/core/browser:test_support",
     "//components/autofill/core/browser",
diff --git a/chrome/browser/policy/BUILD.gn b/chrome/browser/policy/BUILD.gn
index 8d0e0859..647956a75 100644
--- a/chrome/browser/policy/BUILD.gn
+++ b/chrome/browser/policy/BUILD.gn
@@ -222,6 +222,7 @@
     "//chrome/app:command_ids",
     "//chrome/browser",
     "//chrome/browser/media/webrtc",
+    "//chrome/browser/ui/autofill",
     "//chrome/common",
     "//chrome/test:test_support",
     "//components/policy/core/common",
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 5dc4b0f..c21fd38 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -2142,6 +2142,7 @@
   ash::EduCoexistenceLoginHandler::RegisterProfilePrefs(registry);
   ash::SigninErrorNotifier::RegisterPrefs(registry);
   ash::ServicesCustomizationDocument::RegisterProfilePrefs(registry);
+  ash::SecureDnsManager::RegisterProfilePrefs(registry);
   ash::settings::OSSettingsUI::RegisterProfilePrefs(registry);
   ash::StartupUtils::RegisterOobeProfilePrefs(registry);
   ash::user_image::prefs::RegisterProfilePrefs(registry);
diff --git a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
index 97032aa..0cf6acd 100644
--- a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
+++ b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
@@ -86,6 +86,7 @@
 #include "chrome/browser/language/accept_languages_service_factory.h"
 #include "chrome/browser/language/language_model_manager_factory.h"
 #include "chrome/browser/language/url_language_histogram_factory.h"
+#include "chrome/browser/language_detection/language_detection_model_service_factory.h"
 #include "chrome/browser/login_detection/login_detection_keyed_service_factory.h"
 #include "chrome/browser/lookalikes/lookalike_url_service.h"
 #include "chrome/browser/manta/manta_service_factory.h"
@@ -202,7 +203,6 @@
 #include "chrome/browser/tpcd/support/origin_trial_service_factory.h"
 #include "chrome/browser/tpcd/support/top_level_trial_service_factory.h"
 #include "chrome/browser/tpcd/support/tpcd_support_service_factory.h"
-#include "chrome/browser/translate/translate_model_service_factory.h"
 #include "chrome/browser/translate/translate_ranker_factory.h"
 #include "chrome/browser/ui/autofill/autofill_client_provider_factory.h"
 #include "chrome/browser/ui/cookie_controls/cookie_controls_service_factory.h"
@@ -473,7 +473,6 @@
 
 #if defined(TOOLKIT_VIEWS)
 #include "chrome/browser/bookmarks/bookmark_expanded_state_tracker_factory.h"
-#include "chrome/browser/ui/webui/top_chrome/webui_contents_wrapper_service_factory.h"
 #endif
 
 #if BUILDFLAG(ENABLE_PLUGINS)
@@ -713,9 +712,6 @@
   browser_sync::UserEventServiceFactory::GetInstance();
   browsing_topics::BrowsingTopicsServiceFactory::GetInstance();
   BrowsingDataHistoryObserverService::Factory::GetInstance();
-#if defined(TOOLKIT_VIEWS)
-  WebUIContentsWrapperServiceFactory::GetInstance();
-#endif
   BulkLeakCheckServiceFactory::GetInstance();
 #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_LACROS)
   captions::LiveCaptionControllerFactory::GetInstance();
@@ -945,6 +941,7 @@
   JumpListFactory::GetInstance();
 #endif
   KAnonymityServiceFactory::GetInstance();
+  LanguageDetectionModelServiceFactory::GetInstance();
   LanguageModelManagerFactory::GetInstance();
 #if BUILDFLAG(IS_ANDROID)
   LevelDBPersistedTabDataStorageAndroidFactory::GetInstance();
@@ -1318,7 +1315,6 @@
   TrackingProtectionOnboardingFactory::GetInstance();
   TrackingProtectionSettingsFactory::GetInstance();
   translate::TranslateRankerFactory::GetInstance();
-  TranslateModelServiceFactory::GetInstance();
 #if !BUILDFLAG(IS_ANDROID)
   TriggeredProfileResetterFactory::GetInstance();
 #endif
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.cc b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
index cad0c1e..a0bd58a 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu.cc
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
@@ -310,7 +310,6 @@
 #include "chrome/browser/ash/arc/intent_helper/arc_intent_helper_mojo_ash.h"
 #include "chrome/browser/ash/input_method/editor_mediator.h"
 #include "chrome/browser/ash/system_web_apps/types/system_web_app_delegate.h"
-#include "chrome/browser/ash/url_handler/url_handler.h"
 #include "chrome/browser/ui/ash/system_web_apps/system_web_app_ui_utils.h"
 #include "chrome/browser/ui/settings_window_manager_chromeos.h"
 #include "chrome/browser/ui/webui/ash/system_web_dialog/system_web_dialog_delegate.h"
@@ -3157,11 +3156,6 @@
     ui::PageTransition transition,
     const std::string& extra_headers,
     bool started_from_context_menu) {
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-  if (ash::TryOpenUrl(params_.link_url, disposition)) {
-    return;
-  }
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
   RenderViewContextMenuBase::OpenURLWithExtraHeaders(
       url, referring_url, initiator, disposition, transition, extra_headers,
       started_from_context_menu);
@@ -3203,11 +3197,6 @@
     case IDC_CONTENT_CONTEXT_OPENLINKNEWTAB: {
       WindowOpenDisposition new_tab_disposition =
           WindowOpenDisposition::NEW_BACKGROUND_TAB;
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-      if (ash::TryOpenUrl(params_.link_url, new_tab_disposition)) {
-        break;
-      }
-#endif
       Browser* browser = nullptr;
       if (IsInProgressiveWebApp()) {
         browser = FindNormalBrowser(GetProfile());
diff --git a/chrome/browser/resources/chromeos/login/screens/common/split_modifier_keyboard_info.html b/chrome/browser/resources/chromeos/login/screens/common/split_modifier_keyboard_info.html
index afa556aa..f918c15 100644
--- a/chrome/browser/resources/chromeos/login/screens/common/split_modifier_keyboard_info.html
+++ b/chrome/browser/resources/chromeos/login/screens/common/split_modifier_keyboard_info.html
@@ -76,10 +76,10 @@
 <oobe-adaptive-dialog id="splitModifierKeyboardInfoDialog" role="dialog">
   <iron-icon slot="icon" icon="oobe-48:keyboard"></iron-icon>
   <h1 slot="title" aria-live="polite">
-    Test new feature on your device after setup
+    [[i18nDynamic(locale, 'splitModifierTitle')]]
   </h1>
   <div slot="subtitle">
-    Test new feature on your device after setup.
+    [[i18nDynamic(locale, 'splitModifierSubtitle')]]
   </div>
   <div slot="content" class="flex layout vertical center">
     <div class="illustration-content">
@@ -93,12 +93,12 @@
             role="heading"
             aria-level="2"
             tabindex="0"
-            aria-description="Test your device with the new features added to the Chromebook and more.">
+            aria-description="[[i18nDynamic(locale, 'splitModifierFirstDescriptionAccessibility')]]">
           <span class="title">
-            Testing
+            [[i18nDynamic(locale, 'splitModifierFirstDescriptionTitle')]]
           </span>
           <span class="subtitle">
-            Test your device with the new features added to the Chromebook and more.
+            [[i18nDynamic(locale, 'splitModifierFirstDescriptionText')]]
           </span>
         </div>
       </div>
@@ -108,12 +108,12 @@
             role="heading"
             aria-level="2"
             tabindex="0"
-            aria-description="Test your device with the new features added to the Chromebook and more.">
+            aria-description="[[i18nDynamic(locale, 'splitModifierSecondDescriptionAccessibility')]]">
           <span class="title">
-            Testing
+            [[i18nDynamic(locale, 'splitModifierSecondDescriptionTitle')]]
           </span>
           <span class="subtitle">
-            Test your device with the new features added to the Chromebook and more.
+            [[i18nDynamic(locale, 'splitModifierSecondDescriptionText')]]
           </span>
         </div>
       </div>
diff --git a/chrome/browser/resources/lens/overlay/translate_button.html b/chrome/browser/resources/lens/overlay/translate_button.html
index b884e9f..cbbbf95 100644
--- a/chrome/browser/resources/lens/overlay/translate_button.html
+++ b/chrome/browser/resources/lens/overlay/translate_button.html
@@ -14,6 +14,7 @@
   .button {
     border: none;
     padding: 0;
+    pointer-events: all;
   }
 
   .button-label {
@@ -46,7 +47,16 @@
     gap: 0px;
     margin-block-start: 5px;
     margin-block-end: 5px;
+    transform-origin: right;
+    transform: scaleX(0);
+    transition: transform 200ms cubic-bezier(0.05, 0.7, 0.1, 1.0);
+  }
+
+  :host([is-translate-mode-enabled]) .language-picker-button {
+    max-width: 150px;
     min-width: 77px;
+    transform: scaleX(1);
+    transition-delay: 33ms;
   }
 
   .language-picker-label {
@@ -145,13 +155,33 @@
     display: flex;
   }
 
+  .translate-icon {
+    display: block;
+    height: 20px;
+    mask-image: url('translate.svg');
+    mask-position: center;
+    mask-repeat: no-repeat;
+    mask-size: 100%;
+    width: 20px;
+  }
+
   #languagePicker {
     border-radius: 100px;
     display: flex;
-    gap: 6px;
     height: 48px;
+    gap: 6px;
+    max-width: 0px;
+    opacity: 0;
+    transition: max-width 200ms cubic-bezier(0.05, 0.7, 0.1, 1.0) 0s,
+                opacity 50ms linear 0s;
     pointer-events: all;
-    position: relative;
+  }
+
+  :host([is-translate-mode-enabled]) #languagePicker {
+    max-width: 320px;
+    opacity: 1;
+    transition: max-width 200ms cubic-bezier(0.05, 0.7, 0.1, 1.0) 33ms,
+                opacity 100ms linear 33ms;
   }
 
   #languagePickerMenuStarsIcon {
@@ -207,54 +237,75 @@
     margin-inline-start: 16px;
   }
 
-  #translateButton {
-    background-color: var(--color-selection-element);
-    height: 48px;
-    min-width: 50px;
-    pointer-events: all;
-    width: 164px;
-  }
-
-  :host([is-translate-mode-enabled]) #translateButton {
+  #translateDisableButton {
     background-color: var(--color-surface-container-highest-dark);
     gap: 0px;
     height: 38px;
     margin-block-start: 5px;
     margin-block-end: 5px;
     margin-inline-end: 5px;
-    min-width: 38px;
+    min-width: 0px;
+    opacity: 0;
+    transform-origin: right;
+    transform: scaleX(0);
+    transition: opacity 50ms linear,
+                transform 200ms cubic-bezier(0.05, 0.7, 0.1, 1.0),
+                width 200ms cubic-bezier(0.05, 0.7, 0.1, 1.0);
+    width: 0px;
+  }
+
+  :host([is-translate-mode-enabled]) #translateDisableButton {
+    opacity: 1;
+    transform: scaleX(1);
+    transition: opacity 100ms linear 33ms,
+                transform 200ms cubic-bezier(0.05, 0.7, 0.1, 1.0) 33ms,
+                width 200ms cubic-bezier(0.05, 0.7, 0.1, 1.0) 33ms;
     width: 38px;
   }
 
+  #translateEnableButton {
+    background-color: transparent;
+    height: 48px;
+    opacity: 1;
+    transition: opacity 150ms linear 50ms;
+    position: absolute;
+    width: 164px;
+  }
+
+  :host([is-translate-mode-enabled]) #translateEnableButton {
+    left: 50%;
+    opacity: 0;
+    top: 50%;
+    transform: translate(-50%, -50%);
+    transition: opacity 50ms linear;
+  }
+
   #translateButtonLabel {
     color: var(--color-scrim);
     line-height: 50px;
   }
 
   #translateContainer {
-    background-color: white;
+    background-color: var(--color-selection-element);
     border-radius: 36px;
     display: flex;
     flex-direction: row;
+    min-width: 164px;
+    overflow: hidden;
   }
 
-  #translateIcon {
-    background-color: var(--color-primary);
-    display: block;
-    height: 20px;
-    mask-image: url('translate.svg');
-    mask-position: center;
-    mask-repeat: no-repeat;
-    mask-size: 100%;
-    width: 20px;
+  :host([is-translate-mode-enabled]) #translateContainer {
+    background-color: white;
   }
 
-  :host([is-translate-mode-enabled]) #translateIcon {
+  #translateDisableIcon {
     background-color: var(--color-overlay-icon);
   }
 
-  :host([is-translate-mode-enabled]) #translateButtonLabel,
-  :host(:not([is-translate-mode-enabled])) #languagePicker,
+  #translateEnableIcon {
+    background-color: var(--color-primary);
+  }
+
   :host(:not([should-show-stars-icon])) #starsIcon {
     display: none;
   }
@@ -266,6 +317,14 @@
   }
 </style>
 <div id="translateContainer">
+  <cr-button id="translateEnableButton" class="button"
+  on-click="onTranslateButtonClick">
+    <span id="translateEnableIcon" class="translate-icon" slot="prefix-icon">
+    </span>
+    <span id="translateButtonLabel" class="button-label">
+      $i18n{translateButtonLabel}
+    </span>
+  </cr-button>
   <div id="languagePicker">
     <cr-button id="sourceLanguageButton" class="button language-picker-button"
         on-click="onSourceLanguageButtonClick">
@@ -283,11 +342,9 @@
       </span>
     </cr-button>
   </div>
-  <cr-button id="translateButton" class="button"
+  <cr-button id="translateDisableButton" class="button"
   on-click="onTranslateButtonClick">
-    <span id="translateIcon" slot="prefix-icon"></span>
-    <span id="translateButtonLabel" class="button-label">
-      $i18n{translateButtonLabel}
+    <span id="translateDisableIcon" class="translate-icon" slot="prefix-icon">
     </span>
   </cr-button>
   <div id="sourceLanguagePickerMenu" class="language-picker-menu" role="menu"
diff --git a/chrome/browser/resources/lens/overlay/translate_button.ts b/chrome/browser/resources/lens/overlay/translate_button.ts
index 818fa4f3..0a8abed5 100644
--- a/chrome/browser/resources/lens/overlay/translate_button.ts
+++ b/chrome/browser/resources/lens/overlay/translate_button.ts
@@ -54,7 +54,8 @@
     targetLanguageButton: CrButtonElement,
     targetLanguagePickerContainer: DomRepeat,
     targetLanguagePickerMenu: HTMLDivElement,
-    translateButton: CrButtonElement,
+    translateDisableButton: CrButtonElement,
+    translateEnableButton: CrButtonElement,
   };
 }
 
diff --git a/chrome/browser/resources/settings/BUILD.gn b/chrome/browser/resources/settings/BUILD.gn
index f8d0930a..f54a927 100644
--- a/chrome/browser/resources/settings/BUILD.gn
+++ b/chrome/browser/resources/settings/BUILD.gn
@@ -204,6 +204,7 @@
     "site_settings_page/site_settings_page.ts",
     "site_settings_page/unused_site_permissions.ts",
     "site_settings/offer_writing_help_page.ts",
+    "site_settings/smart_card_readers_page.ts",
     "site_settings/pdf_documents.ts",
     "site_settings/protocol_handlers.ts",
     "site_settings/settings_category_default_radio_group.ts",
diff --git a/chrome/browser/resources/settings/privacy_icons.html b/chrome/browser/resources/settings/privacy_icons.html
index 012fb30..91ac460 100644
--- a/chrome/browser/resources/settings/privacy_icons.html
+++ b/chrome/browser/resources/settings/privacy_icons.html
@@ -152,6 +152,12 @@
       <g id="sensors-off" viewBox="0 -960 960 960">
         <path d="M768-90 322-536q-5 13-7.5 27t-2.5 29q0 35 13 65.5t36 53.5l-50 50q-33-32-52-75.5T240-480q0-30 7.5-57.5T268-590l-53-54q-22 36-34.5 77.5T168-480q0 65 24.5 121.5T260-260l-51 51q-53-52-83-121.5T96-480q0-60 17-114.5T162-696l-72-72 51-51 678 678-51 51Zm30-174-53-52q22-36 34.5-77.5T792-480q0-65-24.5-121.5T700-700l51-51q53 52 83 121.5T864-480q0 60-17 115t-49 101ZM693-369l-55-55q5-14 7.5-27.5T648-480q0-35-13-65.5T599-599l50-50q33 32 52 75.5t19 93.5q0 30-6.5 58T693-369Z"></path>
       </g>
+      <g id="smart-card-reader" viewBox="0 -960 960 960">
+        <path d="M80-80v-120q0-33 23.5-56.5T160-280h640q33 0 56.5 23.5T880-200v120H80Zm80-80h640v-40H160v40Zm40-180v-460q0-33 23.5-56.5T280-880h400q33 0 56.5 23.5T760-800v460h-80v-460H280v460h-80Zm120-60h23q44 0 70.5-44T440-560q0-72-26.5-116T343-720h-23v320Zm240-80q33 0 56.5-23.5T640-560q0-33-23.5-56.5T560-640q-33 0-56.5 23.5T480-560q0 33 23.5 56.5T560-480Zm-80 320Zm0-410Z"></path>
+      </g>
+      <g id="smart-card-reader-off" viewBox="0 -960 960 960">
+        <path d="M680-932q33 0 56.5 23.5T760-852v460h-28l-52-52v-408H273l-53-53q11-13 26.5-20t33.5-7h400Zm-91 396L485-639q9-23 29-38t46-15q33 0 56.5 23.5T640-612q0 26-14 46.5T589-536Zm-269 86v-242l118 118q-7 57-32 90.5T343-450h-23ZM160-212h527l-40-40H160v40ZM819-80l-52-52H80v-120q0-33 23.5-56.5T160-332h407L280-620v228h-80v-308L28-872l56-56 792 791-57 57ZM424-212Zm52-436Zm-82 142Z"></path>
+      </g>
       <g id="storage-access" viewBox="0 -960 960 960">
         <path d="M312-255q-97-32-156.5-113.5T96-552q0-130 91-221t221-91q102 0 183.5 59.5T705-648h-77q-29-66-88.5-105T408-792q-100 0-170 70t-70 170q0 72 39 131t105 88v78ZM456-96q-29.7 0-50.85-21.15Q384-138.3 384-168v-336q0-29.7 21.15-50.85Q426.3-576 456-576h336q29.7 0 50.85 21.15Q864-533.7 864-504v336q0 29.7-21.15 50.85Q821.7-96 792-96H456Zm0-72h336v-336H456v336Zm24-48h288l-91-120-72 95-53-71-72 96Zm144-120ZM398-563Z"></path>
       </g>
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.html b/chrome/browser/resources/settings/privacy_page/privacy_page.html
index 3bd53430..be6ff2e 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_page.html
+++ b/chrome/browser/resources/settings/privacy_page/privacy_page.html
@@ -1407,6 +1407,14 @@
           </settings-subpage>
        </template>
       </template>
+      <template is="dom-if" if="[[enableSmartCardReadersContentSetting_]]">
+        <template is="dom-if" route-path="/content/smartCardReaders" no-search>
+          <settings-subpage page-title="$i18n{siteSettingsSmartCardReaders}">
+            <settings-smart-card-readers-page filter="[[searchFilter_]]">
+            </settings-smart-card-readers-page>
+          </settings-subpage>
+       </template>
+      </template>
       <template is="dom-if" if="[[enableAutomaticFullscreenContentSetting_]]">
         <template is="dom-if" route-path="/content/automaticFullScreen"
             no-search>
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.ts b/chrome/browser/resources/settings/privacy_page/privacy_page.ts
index bb825e3d..e260702 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_page.ts
+++ b/chrome/browser/resources/settings/privacy_page/privacy_page.ts
@@ -23,6 +23,7 @@
 import '../settings_shared.css.js';
 import '../site_settings/offer_writing_help_page.js';
 import '../site_settings/settings_category_default_radio_group.js';
+import '../site_settings/smart_card_readers_page.js';
 import './privacy_guide/privacy_guide_dialog.js';
 
 import {PrefsMixin} from '/shared/settings/prefs/prefs_mixin.js';
@@ -159,6 +160,14 @@
         },
       },
 
+      enableSmartCardReadersContentSetting_: {
+        type: Boolean,
+        value() {
+          return loadTimeData.getBoolean(
+              'enableSmartCardReadersContentSetting');
+        },
+      },
+
       enableWebBluetoothNewPermissionsBackend_: {
         type: Boolean,
         value: () =>
@@ -359,6 +368,7 @@
   private enableHandTrackingContentSetting_: boolean;
   private enableExperimentalWebPlatformFeatures_: boolean;
   private enableSecurityKeysSubpage_: boolean;
+  private enableSmartCardReadersContentSetting_: boolean;
   private enableWebBluetoothNewPermissionsBackend_: boolean;
   private enableWebPrintingContentSetting_: boolean;
   private showNotificationPermissionsReview_: boolean;
diff --git a/chrome/browser/resources/settings/route.ts b/chrome/browser/resources/settings/route.ts
index 71de39e..95ac605 100644
--- a/chrome/browser/resources/settings/route.ts
+++ b/chrome/browser/resources/settings/route.ts
@@ -88,6 +88,10 @@
     r.SITE_SETTINGS_CAPTURED_SURFACE_CONTROL =
         r.SITE_SETTINGS.createChild('capturedSurfaceControl');
   }
+  if (loadTimeData.getBoolean('enableSmartCardReadersContentSetting')) {
+    r.SITE_SETTINGS_SMART_CARD_READERS =
+        r.SITE_SETTINGS.createChild('smartCardReaders');
+  }
   if (loadTimeData.getBoolean('privateStateTokensEnabled')) {
     r.SITE_SETTINGS_AUTO_VERIFY = r.SITE_SETTINGS.createChild('autoVerify');
   }
diff --git a/chrome/browser/resources/settings/router.ts b/chrome/browser/resources/settings/router.ts
index 41e0c3bd..2cb2bc07 100644
--- a/chrome/browser/resources/settings/router.ts
+++ b/chrome/browser/resources/settings/router.ts
@@ -101,6 +101,7 @@
   SITE_SETTINGS_POPUPS: Route;
   SITE_SETTINGS_PROTECTED_CONTENT: Route;
   SITE_SETTINGS_SERIAL_PORTS: Route;
+  SITE_SETTINGS_SMART_CARD_READERS: Route;
   SITE_SETTINGS_SITE_DATA: Route;
   SITE_SETTINGS_SITE_DETAILS: Route;
   SITE_SETTINGS_STORAGE_ACCESS: Route;
diff --git a/chrome/browser/resources/settings/site_settings/constants.ts b/chrome/browser/resources/settings/site_settings/constants.ts
index 6eb140d..0dc240e 100644
--- a/chrome/browser/resources/settings/site_settings/constants.ts
+++ b/chrome/browser/resources/settings/site_settings/constants.ts
@@ -50,6 +50,7 @@
   PROTOCOL_HANDLERS = 'register-protocol-handler',
   SENSORS = 'sensors',
   SERIAL_PORTS = 'serial-ports',
+  SMART_CARD_READERS = 'smart-card-readers',
   SOUND = 'sound',
   STORAGE_ACCESS = 'storage-access',
   TRACKING_PROTECTION = 'tracking-protection',
diff --git a/chrome/browser/resources/settings/site_settings/settings_category_default_radio_group.ts b/chrome/browser/resources/settings/site_settings/settings_category_default_radio_group.ts
index 814fb8f..33256e6 100644
--- a/chrome/browser/resources/settings/site_settings/settings_category_default_radio_group.ts
+++ b/chrome/browser/resources/settings/site_settings/settings_category_default_radio_group.ts
@@ -162,6 +162,7 @@
       case ContentSettingsTypes.NOTIFICATIONS:
       case ContentSettingsTypes.POINTER_LOCK:
       case ContentSettingsTypes.SERIAL_PORTS:
+      case ContentSettingsTypes.SMART_CARD_READERS:
       case ContentSettingsTypes.STORAGE_ACCESS:
       case ContentSettingsTypes.USB_DEVICES:
       case ContentSettingsTypes.VR:
diff --git a/chrome/browser/resources/settings/site_settings/smart_card_readers_page.html b/chrome/browser/resources/settings/site_settings/smart_card_readers_page.html
new file mode 100644
index 0000000..93681b2
--- /dev/null
+++ b/chrome/browser/resources/settings/site_settings/smart_card_readers_page.html
@@ -0,0 +1,20 @@
+<style include="cr-shared-style settings-shared iron-flex">
+  .content-settings-header,
+  .radio-group {
+    padding: 0 var(--cr-section-padding);
+  }
+</style>
+
+<div class="content-settings-header secondary">
+  $i18n{siteSettingsSmartCardReadersDescription}
+</div>
+<settings-category-default-radio-group
+    category="[[contentSettingsType_]]"
+    description=
+        "$i18n{siteSettingsSmartCardReadersDefaultDescription}"
+    allow-option-label=
+        "$i18n{siteSettingsSmartCardReadersAllowed}"
+    allow-option-icon="privacy:smart-card-reader"
+    block-option-label="$i18n{siteSettingsSmartCardReadersBlocked}"
+    block-option-icon="privacy:smart-card-reader-off">
+</settings-category-default-radio-group>
diff --git a/chrome/browser/resources/settings/site_settings/smart_card_readers_page.ts b/chrome/browser/resources/settings/site_settings/smart_card_readers_page.ts
new file mode 100644
index 0000000..44f6bdc
--- /dev/null
+++ b/chrome/browser/resources/settings/site_settings/smart_card_readers_page.ts
@@ -0,0 +1,39 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import '../controls/settings_toggle_button.js';
+
+import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {ContentSettingsTypes} from './constants.js';
+import {getTemplate} from './smart_card_readers_page.html.js';
+
+export class SettingsSmartCardReadersPageElement extends PolymerElement {
+  static get is() {
+    return 'settings-smart-card-readers-page';
+  }
+
+  static get template() {
+    return getTemplate();
+  }
+
+  static get properties() {
+    return {
+      contentSettingsType_: {
+        type: ContentSettingsTypes,
+        value: ContentSettingsTypes.SMART_CARD_READERS,
+      },
+    };
+  }
+}
+
+declare global {
+  interface HTMLElementTagNameMap {
+    'settings-smart-card-readers-page': SettingsSmartCardReadersPageElement;
+  }
+}
+
+customElements.define(
+    SettingsSmartCardReadersPageElement.is,
+    SettingsSmartCardReadersPageElement);
diff --git a/chrome/browser/resources/settings/site_settings_page/site_settings_page.ts b/chrome/browser/resources/settings/site_settings_page/site_settings_page.ts
index 158b9b60..20fe241 100644
--- a/chrome/browser/resources/settings/site_settings_page/site_settings_page.ts
+++ b/chrome/browser/resources/settings/site_settings_page/site_settings_page.ts
@@ -369,6 +369,16 @@
       icon: 'privacy:database',
     },
     {
+      route: routes.SITE_SETTINGS_SMART_CARD_READERS,
+      id: Id.SMART_CARD_READERS,
+      label: 'siteSettingsSmartCardReaders',
+      icon: 'privacy:smart-card-reader',
+      enabledLabel: 'siteSettingsSmartCardReadersAllowed',
+      disabledLabel: 'siteSettingsSmartCardReadersBlocked',
+      shouldShow: () =>
+          loadTimeData.getBoolean('enableSmartCardReadersContentSetting'),
+    },
+    {
       route: routes.SITE_SETTINGS_SOUND,
       id: Id.SOUND,
       label: 'siteSettingsSound',
@@ -526,6 +536,7 @@
               Id.CAPTURED_SURFACE_CONTROL,
               Id.KEYBOARD_LOCK,
               Id.POINTER_LOCK,
+              Id.SMART_CARD_READERS,
 
             ]),
             contentBasic: buildItemListFromIds([
diff --git a/chrome/browser/resources/settings/site_settings_page/site_settings_page_util.ts b/chrome/browser/resources/settings/site_settings_page/site_settings_page_util.ts
index 4b629236..ff96a3be 100644
--- a/chrome/browser/resources/settings/site_settings_page/site_settings_page_util.ts
+++ b/chrome/browser/resources/settings/site_settings_page/site_settings_page_util.ts
@@ -102,6 +102,7 @@
     case ContentSettingsTypes.SITE_DATA:
     case ContentSettingsTypes.TRACKING_PROTECTION:
     case ContentSettingsTypes.OFFER_WRITING_HELP:
+    case ContentSettingsTypes.SMART_CARD_READERS:
       return null;
     default:
       assertNotReached();
diff --git a/chrome/browser/safe_browsing/BUILD.gn b/chrome/browser/safe_browsing/BUILD.gn
index 66c4aeeb..5207830 100644
--- a/chrome/browser/safe_browsing/BUILD.gn
+++ b/chrome/browser/safe_browsing/BUILD.gn
@@ -30,6 +30,7 @@
     "//chrome/browser/profiles",
     "//chrome/browser/profiles:profile",
     "//chrome/browser/sync",
+    "//chrome/browser/ui/autofill",
     "//chrome/common",
     "//chrome/common:constants",
     "//components/browser_sync",
@@ -441,6 +442,9 @@
           "//chromeos/crosapi/cpp:cpp",
         ]
       }
+      if (!is_android) {
+        deps += [ "//chrome/browser/ui:browser_list" ]
+      }
     } else if (safe_browsing_mode == 2) {
       if (is_android) {
         sources += [
diff --git a/chrome/browser/storage/shared_storage_browsertest.cc b/chrome/browser/storage/shared_storage_browsertest.cc
index 246c32d..9bc714c5a 100644
--- a/chrome/browser/storage/shared_storage_browsertest.cc
+++ b/chrome/browser/storage/shared_storage_browsertest.cc
@@ -3917,7 +3917,7 @@
   EXPECT_EQ("Finish executing 'test-url-selection-operation'",
             base::UTF16ToUTF8(console_observer.messages()[0].message));
 
-  WaitForHistograms({kErrorTypeHistogram});
+  WaitForHistogramsWithSampleCounts({std::make_tuple(kErrorTypeHistogram, 2)});
   histogram_tester_.ExpectUniqueSample(
       kErrorTypeHistogram, blink::SharedStorageWorkletErrorType::kSuccess, 2);
 }
@@ -3969,7 +3969,7 @@
   EXPECT_EQ("Finish executing 'test-operation'",
             base::UTF16ToUTF8(console_observer.messages()[0].message));
 
-  WaitForHistograms({kErrorTypeHistogram});
+  WaitForHistogramsWithSampleCounts({std::make_tuple(kErrorTypeHistogram, 2)});
   histogram_tester_.ExpectUniqueSample(
       kErrorTypeHistogram, blink::SharedStorageWorkletErrorType::kSuccess, 2);
 }
diff --git a/chrome/browser/sync/BUILD.gn b/chrome/browser/sync/BUILD.gn
index 7b46061..7b56ec6 100644
--- a/chrome/browser/sync/BUILD.gn
+++ b/chrome/browser/sync/BUILD.gn
@@ -154,7 +154,10 @@
       "sync_ui_util.cc",
       "sync_ui_util.h",
     ]
-    public_deps += [ "//chrome/browser/ui/tabs:tab_strip_model_observer" ]
+    public_deps += [
+      "//chrome/browser/ui:browser_list",
+      "//chrome/browser/ui/tabs:tab_strip_model_observer",
+    ]
     deps += [
       "//chrome/browser/themes",
       "//chrome/browser/web_applications",
diff --git a/chrome/browser/translate/chrome_translate_client.cc b/chrome/browser/translate/chrome_translate_client.cc
index 305f3216..400534b 100644
--- a/chrome/browser/translate/chrome_translate_client.cc
+++ b/chrome/browser/translate/chrome_translate_client.cc
@@ -19,9 +19,9 @@
 #include "chrome/browser/language/accept_languages_service_factory.h"
 #include "chrome/browser/language/language_model_manager_factory.h"
 #include "chrome/browser/language/url_language_histogram_factory.h"
+#include "chrome/browser/language_detection/language_detection_model_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_key.h"
-#include "chrome/browser/translate/translate_model_service_factory.h"
 #include "chrome/browser/translate/translate_ranker_factory.h"
 #include "chrome/browser/translate/translate_service.h"
 #include "chrome/browser/ui/translate/translate_bubble_factory.h"
@@ -33,6 +33,7 @@
 #include "components/language/core/browser/language_model_manager.h"
 #include "components/language/core/browser/pref_names.h"
 #include "components/language_detection/content/browser/content_language_detection_driver.h"
+#include "components/language_detection/core/browser/language_detection_model_service.h"
 #include "components/prefs/pref_service.h"
 #include "components/translate/content/browser/content_translate_driver.h"
 #include "components/translate/core/browser/language_state.h"
@@ -42,7 +43,6 @@
 #include "components/translate/core/browser/translate_infobar_delegate.h"
 #include "components/translate/core/browser/translate_manager.h"
 #include "components/translate/core/browser/translate_metrics_logger.h"
-#include "components/translate/core/browser/translate_model_service.h"
 #include "components/translate/core/browser/translate_prefs.h"
 #include "components/translate/core/common/language_detection_details.h"
 #include "components/translate/core/common/translate_util.h"
@@ -113,7 +113,7 @@
               web_contents->GetBrowserContext()))),
       language_detection_driver_(
           new language_detection::ContentLanguageDetectionDriver(
-              TranslateModelServiceFactory::GetForProfile(
+              LanguageDetectionModelServiceFactory::GetForProfile(
                   Profile::FromBrowserContext(
                       web_contents->GetBrowserContext())))),
       translate_manager_(new translate::TranslateManager(
diff --git a/chrome/browser/translate/language_detection_model_service_browsertest.cc b/chrome/browser/translate/language_detection_model_service_browsertest.cc
new file mode 100644
index 0000000..0e89c66d
--- /dev/null
+++ b/chrome/browser/translate/language_detection_model_service_browsertest.cc
@@ -0,0 +1,595 @@
+// Copyright 2020 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <memory>
+#include <optional>
+
+#include "base/base_paths.h"
+#include "base/files/file.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/functional/bind.h"
+#include "base/path_service.h"
+#include "base/run_loop.h"
+#include "base/task/thread_pool/thread_pool_instance.h"
+#include "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/threading/thread_restrictions.h"
+#include "build/build_config.h"
+#include "chrome/browser/language_detection/language_detection_model_service_factory.h"
+#include "chrome/browser/optimization_guide/optimization_guide_keyed_service.h"
+#include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_key.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "components/metrics/content/subprocess_metrics_provider.h"
+#include "components/optimization_guide/core/model_util.h"
+#include "components/optimization_guide/core/optimization_guide_features.h"
+#include "components/optimization_guide/core/optimization_guide_test_util.h"
+#include "components/optimization_guide/core/test_model_info_builder.h"
+#include "components/optimization_guide/proto/models.pb.h"
+#include "components/translate/core/common/translate_util.h"
+#include "components/translate/core/language_detection/language_detection_model.h"
+#include "content/public/test/browser_test.h"
+#include "content/public/test/browser_test_utils.h"
+#include "net/dns/mock_host_resolver.h"
+#include "net/http/http_status_code.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/test/embedded_test_server/http_request.h"
+#include "net/test/embedded_test_server/http_response.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace language_detection {
+namespace {
+
+// Fetch and calculate the total number of samples from all the bins for
+// |histogram_name|. Note: from some browertests run (such as chromeos) there
+// might be two profiles created, and this will return the total sample count
+// across profiles.
+int GetTotalHistogramSamples(const base::HistogramTester* histogram_tester,
+                             const std::string& histogram_name) {
+  std::vector<base::Bucket> buckets =
+      histogram_tester->GetAllSamples(histogram_name);
+  int total = 0;
+  for (const auto& bucket : buckets) {
+    total += bucket.count;
+  }
+
+  return total;
+}
+
+// Retries fetching |histogram_name| until it contains at least |count| samples.
+int RetryForHistogramUntilCountReached(
+    const base::HistogramTester* histogram_tester,
+    const std::string& histogram_name,
+    int count) {
+  while (true) {
+    base::ThreadPoolInstance::Get()->FlushForTesting();
+    base::RunLoop().RunUntilIdle();
+
+    int total = GetTotalHistogramSamples(histogram_tester, histogram_name);
+    if (total >= count) {
+      return total;
+    }
+
+    content::FetchHistogramsFromChildProcesses();
+    metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
+    base::RunLoop().RunUntilIdle();
+  }
+}
+
+class LanguageDetectionModelServiceDisabledBrowserTest
+    : public InProcessBrowserTest {
+ public:
+  LanguageDetectionModelServiceDisabledBrowserTest() {
+    scoped_feature_list_.InitAndDisableFeature(
+        translate::kTFLiteLanguageDetectionEnabled);
+  }
+
+  void SetUp() override {
+    origin_server_ = std::make_unique<net::EmbeddedTestServer>(
+        net::EmbeddedTestServer::TYPE_HTTPS);
+    origin_server_->ServeFilesFromSourceDirectory(
+        "chrome/test/data/optimization_guide");
+
+    ASSERT_TRUE(origin_server_->Start());
+    english_url_ = origin_server_->GetURL("/hello_world.html");
+    InProcessBrowserTest::SetUp();
+  }
+
+  ~LanguageDetectionModelServiceDisabledBrowserTest() override = default;
+
+  const GURL& english_url() const { return english_url_; }
+
+ private:
+  GURL english_url_;
+  std::unique_ptr<net::EmbeddedTestServer> origin_server_;
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+IN_PROC_BROWSER_TEST_F(LanguageDetectionModelServiceDisabledBrowserTest,
+                       LanguageDetectionModelServiceDisabled) {
+  EXPECT_FALSE(LanguageDetectionModelServiceFactory::GetForProfile(
+      browser()->profile()));
+}
+
+class LanguageDetectionModelServiceWithoutOptimizationGuideBrowserTest
+    : public LanguageDetectionModelServiceDisabledBrowserTest {
+ public:
+  LanguageDetectionModelServiceWithoutOptimizationGuideBrowserTest() {
+    scoped_feature_list_.InitWithFeatures(
+        {translate::kTFLiteLanguageDetectionEnabled},
+        {optimization_guide::features::kOptimizationHints});
+  }
+
+  ~LanguageDetectionModelServiceWithoutOptimizationGuideBrowserTest() override =
+      default;
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+// This test confirms the translate model service is not available if
+// the optimization guide does not exist.
+IN_PROC_BROWSER_TEST_F(
+    LanguageDetectionModelServiceWithoutOptimizationGuideBrowserTest,
+    LanguageDetectionModelServiceEnabled) {
+  EXPECT_FALSE(LanguageDetectionModelServiceFactory::GetForProfile(
+      browser()->profile()));
+}
+
+IN_PROC_BROWSER_TEST_F(LanguageDetectionModelServiceDisabledBrowserTest,
+                       LanguageDetectionModelNotCreated) {
+  base::HistogramTester histogram_tester;
+
+  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), english_url()));
+  RetryForHistogramUntilCountReached(
+      &histogram_tester, "Translate.CLD3.TopLanguageEvaluationDuration", 1);
+  histogram_tester.ExpectTotalCount(
+      "LanguageDetection.TFLiteModel.WasModelAvailableForDetection", 0);
+}
+
+// Makes requesting and waiting for the model file easy. This can only be used
+// once.
+class ModelFileGetter {
+ public:
+  explicit ModelFileGetter(
+      LanguageDetectionModelService& language_detection_model_service)
+      : language_detection_model_service_(language_detection_model_service) {}
+
+  // Queues a request to get the model file. Do not call this again.
+  void RequestModelFile() {
+    CHECK_EQ(state_, State::kUnused);
+    language_detection_model_service_->GetLanguageDetectionModelFile(
+        base::BindOnce(
+            [](ModelFileGetter* getter, base::File model_file) {
+              getter->waiter_.OnEvent();
+              getter->model_file_ = std::move(model_file);
+            },
+            base::Unretained(this)));
+    state_ = State::kWaiting;
+  }
+
+  // Waits for the file and returns it if the request is satisfied. Returns
+  // `nullopt` if the waiting is interrupted before the request is satisfied.
+  // `RequestModelFile` must be called first.
+  [[nodiscard]] std::optional<base::File> WaitForModelFile() {
+    CHECK_EQ(state_, State::kWaiting);
+    if (waiter_.Wait()) {
+      state_ = State::kUsed;
+      return std::move(model_file_);
+    } else {
+      // This should really only happen if the test times out.
+      return std::nullopt;
+    }
+  }
+
+  // Wraps requesting and waiting.
+  [[nodiscard]] std::optional<base::File> RequestAndWaitForModelFile() {
+    RequestModelFile();
+    return WaitForModelFile();
+  }
+
+  // Returns whether a file has been received.
+  bool HasFileBeenReceived() { return model_file_.has_value(); }
+
+ private:
+  raw_ref<LanguageDetectionModelService> language_detection_model_service_;
+  content::WaiterHelper waiter_;
+  enum class State {
+    kUnused = 0,
+    kWaiting = 1,
+    kUsed = 2,
+  };
+  State state_ = State::kUnused;
+  std::optional<base::File> model_file_;
+};
+
+class LanguageDetectionModelServiceBrowserTest
+    : public LanguageDetectionModelServiceDisabledBrowserTest {
+ public:
+  LanguageDetectionModelServiceBrowserTest() {
+    scoped_feature_list_.InitWithFeatures(
+        {translate::kTFLiteLanguageDetectionEnabled,
+         optimization_guide::features::kOptimizationHints,
+         optimization_guide::features::kRemoteOptimizationGuideFetching},
+        {});
+  }
+
+  void SetUp() override {
+    origin_server_ = std::make_unique<net::EmbeddedTestServer>(
+        net::EmbeddedTestServer::TYPE_HTTPS);
+    origin_server_->ServeFilesFromSourceDirectory(
+        "chrome/test/data/optimization_guide");
+    origin_server_->RegisterRequestHandler(base::BindRepeating(
+        &LanguageDetectionModelServiceBrowserTest::RequestHandler,
+        base::Unretained(this)));
+    ASSERT_TRUE(origin_server_->Start());
+    english_url_ = origin_server_->GetURL("/hello_world.html");
+    InProcessBrowserTest::SetUp();
+  }
+
+  // Waits for the model file to be resolved. `nullopt` will be returned if the
+  // waiting is interrupted, e.g. by test timeout.
+  [[nodiscard]] std::optional<base::File> RequestAndWaitForModelFile() {
+    ModelFileGetter getter(*language_detection_model_service());
+    return getter.RequestAndWaitForModelFile();
+  }
+
+  ~LanguageDetectionModelServiceBrowserTest() override = default;
+
+  LanguageDetectionModelService* language_detection_model_service() {
+    return LanguageDetectionModelServiceFactory::GetForProfile(
+        browser()->profile());
+  }
+
+  const GURL& english_url() const { return english_url_; }
+
+ private:
+  std::unique_ptr<net::test_server::HttpResponse> RequestHandler(
+      const net::test_server::HttpRequest& request) {
+    std::string path_value;
+
+    // This script is render blocking in the HTML, but is intentionally slow.
+    // This provides important time between commit and first layout for model
+    // requests to make it to the renderer, reducing flakes.
+    if (request.GetURL().path() == "/slow-first-layout.js") {
+      std::unique_ptr<net::test_server::DelayedHttpResponse> resp =
+          std::make_unique<net::test_server::DelayedHttpResponse>(
+              base::Milliseconds(500));
+      resp->set_code(net::HTTP_OK);
+      resp->set_content_type("application/javascript");
+      resp->set_content(std::string());
+      return resp;
+    }
+
+    return nullptr;
+  }
+  base::test::ScopedFeatureList scoped_feature_list_;
+  GURL english_url_;
+  std::unique_ptr<net::EmbeddedTestServer> origin_server_;
+};
+
+base::FilePath model_file_path() {
+  base::FilePath source_root_dir;
+  base::PathService::Get(base::DIR_SRC_TEST_DATA_ROOT, &source_root_dir);
+  return source_root_dir.AppendASCII("components")
+      .AppendASCII("test")
+      .AppendASCII("data")
+      .AppendASCII("translate")
+      .AppendASCII("valid_model.tflite");
+}
+
+IN_PROC_BROWSER_TEST_F(LanguageDetectionModelServiceBrowserTest,
+                       LanguageDetectionModelServiceEnabled) {
+  EXPECT_TRUE(language_detection_model_service());
+}
+
+IN_PROC_BROWSER_TEST_F(LanguageDetectionModelServiceBrowserTest,
+                       LanguageDetectionModelServiceEnabled_OffTheRecord) {
+  EXPECT_TRUE(LanguageDetectionModelServiceFactory::GetForProfile(
+      browser()->profile()->GetPrimaryOTRProfile(/*create_if_needed=*/true)));
+}
+
+IN_PROC_BROWSER_TEST_F(LanguageDetectionModelServiceBrowserTest,
+                       LanguageDetectionModelReadyOnRequest) {
+  base::ScopedAllowBlockingForTesting allow_io_for_test_setup;
+  base::HistogramTester histogram_tester;
+  ASSERT_TRUE(language_detection_model_service());
+
+  OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile())
+      ->OverrideTargetModelForTesting(
+          optimization_guide::proto::OPTIMIZATION_TARGET_LANGUAGE_DETECTION,
+          optimization_guide::TestModelInfoBuilder()
+              .SetModelFilePath(model_file_path())
+              .Build());
+
+  RetryForHistogramUntilCountReached(
+      &histogram_tester,
+      "TranslateModelService.LanguageDetectionModel.WasLoaded", 1);
+  histogram_tester.ExpectUniqueSample(
+      "TranslateModelService.LanguageDetectionModel.WasLoaded", true, 1);
+
+  ASSERT_TRUE(RequestAndWaitForModelFile()->IsValid());
+}
+
+IN_PROC_BROWSER_TEST_F(LanguageDetectionModelServiceBrowserTest,
+                       LanguageDetectionModelLoadedAfterRequest) {
+  base::ScopedAllowBlockingForTesting allow_io_for_test_setup;
+  base::HistogramTester histogram_tester;
+  ASSERT_TRUE(language_detection_model_service());
+
+  ModelFileGetter getter(*language_detection_model_service());
+  getter.RequestModelFile();
+  ASSERT_FALSE(getter.HasFileBeenReceived());
+
+  OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile())
+      ->OverrideTargetModelForTesting(
+          optimization_guide::proto::OPTIMIZATION_TARGET_LANGUAGE_DETECTION,
+          optimization_guide::TestModelInfoBuilder()
+              .SetModelFilePath(model_file_path())
+              .Build());
+
+  RetryForHistogramUntilCountReached(
+      &histogram_tester,
+      "TranslateModelService.LanguageDetectionModel.WasLoaded", 1);
+  histogram_tester.ExpectUniqueSample(
+      "TranslateModelService.LanguageDetectionModel.WasLoaded", true, 1);
+
+  auto model_file = getter.WaitForModelFile();
+  ASSERT_TRUE(model_file.has_value());
+  EXPECT_TRUE(model_file->IsValid());
+}
+
+IN_PROC_BROWSER_TEST_F(LanguageDetectionModelServiceBrowserTest,
+                       InvalidModelWhenLoading) {
+  base::ScopedAllowBlockingForTesting allow_io_for_test_setup;
+  base::HistogramTester histogram_tester;
+  ASSERT_TRUE(language_detection_model_service());
+  OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile())
+      ->OverrideTargetModelForTesting(
+          optimization_guide::proto::OPTIMIZATION_TARGET_LANGUAGE_DETECTION,
+          optimization_guide::TestModelInfoBuilder()
+              .SetModelFilePath(
+                  base::FilePath(optimization_guide::StringToFilePath(
+                                     optimization_guide::kTestAbsoluteFilePath)
+                                     .value()))
+              .Build());
+
+  RetryForHistogramUntilCountReached(
+      &histogram_tester,
+      "TranslateModelService.LanguageDetectionModel.WasLoaded", 1);
+  histogram_tester.ExpectUniqueSample(
+      "TranslateModelService.LanguageDetectionModel.WasLoaded", false, 1);
+}
+
+// TODO(crbug.com/40836720): Re-enable this test
+#if BUILDFLAG(IS_CHROMEOS)
+#define MAYBE_LanguageDetectionModelAvailableForDetection \
+  DISABLED_LanguageDetectionModelAvailableForDetection
+#else
+#define MAYBE_LanguageDetectionModelAvailableForDetection \
+  LanguageDetectionModelAvailableForDetection
+#endif
+IN_PROC_BROWSER_TEST_F(LanguageDetectionModelServiceBrowserTest,
+                       MAYBE_LanguageDetectionModelAvailableForDetection) {
+  base::HistogramTester histogram_tester;
+  OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile())
+      ->OverrideTargetModelForTesting(
+          optimization_guide::proto::OPTIMIZATION_TARGET_LANGUAGE_DETECTION,
+          optimization_guide::TestModelInfoBuilder()
+              .SetModelFilePath(model_file_path())
+              .Build());
+  RetryForHistogramUntilCountReached(
+      &histogram_tester,
+      "TranslateModelService.LanguageDetectionModel.WasLoaded", 1);
+  histogram_tester.ExpectUniqueSample(
+      "TranslateModelService.LanguageDetectionModel.WasLoaded", true, 1);
+
+  ui_test_utils::NavigateToURLWithDisposition(
+      browser(), english_url(), WindowOpenDisposition::NEW_FOREGROUND_TAB,
+      ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP);
+
+  RetryForHistogramUntilCountReached(
+      &histogram_tester,
+      "LanguageDetection.TFLiteModel.WasModelAvailableForDetection", 1);
+  histogram_tester.ExpectUniqueSample(
+      "LanguageDetection.TFLiteModel.WasModelAvailableForDetection", true, 1);
+}
+
+// Disabled on linux+ASAN, macOS+ASAN, chromeOS+ASAN and windows due to high
+// failure rate: crbug.com/1199854 crbug.com/1297485.
+// TODO(crbug.com/40904444): Re-enable this test
+#if (BUILDFLAG(IS_CHROMEOS) && !defined(NDEBUG)) ||        \
+    (BUILDFLAG(IS_LINUX) && BUILDFLAG(IS_MAC)) ||          \
+    (BUILDFLAG(IS_LINUX) && defined(ADDRESS_SANITIZER)) || \
+    (BUILDFLAG(IS_MAC) && defined(ADDRESS_SANITIZER)) || BUILDFLAG(IS_WIN)
+#define MAYBE_LanguageDetectionWithBackgroundTab \
+  DISABLED_LanguageDetectionWithBackgroundTab
+#else
+#define MAYBE_LanguageDetectionWithBackgroundTab \
+  LanguageDetectionWithBackgroundTab
+#endif
+IN_PROC_BROWSER_TEST_F(LanguageDetectionModelServiceBrowserTest,
+                       MAYBE_LanguageDetectionWithBackgroundTab) {
+  base::HistogramTester histogram_tester;
+  OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile())
+      ->OverrideTargetModelForTesting(
+          optimization_guide::proto::OPTIMIZATION_TARGET_LANGUAGE_DETECTION,
+          optimization_guide::TestModelInfoBuilder()
+              .SetModelFilePath(model_file_path())
+              .Build());
+
+  RetryForHistogramUntilCountReached(
+      &histogram_tester,
+      "TranslateModelService.LanguageDetectionModel.WasLoaded", 1);
+  histogram_tester.ExpectUniqueSample(
+      "TranslateModelService.LanguageDetectionModel.WasLoaded", true, 1);
+
+  ui_test_utils::NavigateToURLWithDisposition(
+      browser(), english_url(), WindowOpenDisposition::NEW_BACKGROUND_TAB,
+      ui_test_utils::BROWSER_TEST_NO_WAIT);
+
+  // Opening the browser causes the first model deferral event. The second
+  // is due to the background tab.
+  RetryForHistogramUntilCountReached(
+      &histogram_tester,
+      "LanguageDetection.TFLiteModel.WasModelRequestDeferred", 2);
+  histogram_tester.ExpectBucketCount(
+      "LanguageDetection.TFLiteModel.WasModelRequestDeferred", true, 2);
+
+  // Make the background tab the active tab.
+  browser()->tab_strip_model()->SelectNextTab();
+
+  RetryForHistogramUntilCountReached(
+      &histogram_tester,
+      "LanguageDetection.TFLiteModel.WasModelAvailableForDetection", 1);
+  histogram_tester.ExpectBucketCount(
+      "LanguageDetection.TFLiteModel.WasModelAvailableForDetection", true, 1);
+}
+
+IN_PROC_BROWSER_TEST_F(LanguageDetectionModelServiceBrowserTest,
+                       ModelUpdateFromOptimizationGuide) {
+  base::ScopedAllowBlockingForTesting allow_io_for_test_setup;
+  base::HistogramTester histogram_tester;
+  ASSERT_TRUE(language_detection_model_service());
+
+  OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile())
+      ->OverrideTargetModelForTesting(
+          optimization_guide::proto::OPTIMIZATION_TARGET_LANGUAGE_DETECTION,
+          optimization_guide::TestModelInfoBuilder()
+              .SetModelFilePath(model_file_path())
+              .Build());
+
+  RetryForHistogramUntilCountReached(
+      &histogram_tester,
+      "TranslateModelService.LanguageDetectionModel.WasLoaded", 1);
+  histogram_tester.ExpectUniqueSample(
+      "TranslateModelService.LanguageDetectionModel.WasLoaded", true, 1);
+
+  OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile())
+      ->OverrideTargetModelForTesting(
+          optimization_guide::proto::OPTIMIZATION_TARGET_LANGUAGE_DETECTION,
+          optimization_guide::TestModelInfoBuilder()
+              .SetModelFilePath(model_file_path())
+              .Build());
+
+  RetryForHistogramUntilCountReached(
+      &histogram_tester,
+      "TranslateModelService.LanguageDetectionModel.WasLoaded", 2);
+  histogram_tester.ExpectUniqueSample(
+      "TranslateModelService.LanguageDetectionModel.WasLoaded", true, 2);
+
+  ASSERT_TRUE(RequestAndWaitForModelFile()->IsValid());
+}
+
+// Test that the service correctly handles being notified that there is no
+// longer a valid model available and also that it then handles a valid model
+// becoming available.
+IN_PROC_BROWSER_TEST_F(LanguageDetectionModelServiceBrowserTest,
+                       ModelUpdateFromOptimizationGuideMissingModelInfo) {
+  base::ScopedAllowBlockingForTesting allow_io_for_test_setup;
+  base::HistogramTester histogram_tester;
+  ASSERT_TRUE(language_detection_model_service());
+
+  OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile())
+      ->OverrideTargetModelForTesting(
+          optimization_guide::proto::OPTIMIZATION_TARGET_LANGUAGE_DETECTION,
+          optimization_guide::TestModelInfoBuilder()
+              .SetModelFilePath(model_file_path())
+              .Build());
+
+  RetryForHistogramUntilCountReached(
+      &histogram_tester,
+      "TranslateModelService.LanguageDetectionModel.WasLoaded", 1);
+  histogram_tester.ExpectUniqueSample(
+      "TranslateModelService.LanguageDetectionModel.WasLoaded", true, 1);
+
+  ASSERT_TRUE(RequestAndWaitForModelFile()->IsValid());
+
+  // Tell the service that there is no longer a model available.
+  OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile())
+      ->OverrideTargetModelForTesting(
+          optimization_guide::proto::OPTIMIZATION_TARGET_LANGUAGE_DETECTION,
+          nullptr);
+  histogram_tester.ExpectUniqueSample(
+      "TranslateModelService.LanguageDetectionModel.WasLoaded", true, 1);
+
+  ASSERT_FALSE(RequestAndWaitForModelFile()->IsValid());
+
+  // Tell the service that a model is available again.
+  OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile())
+      ->OverrideTargetModelForTesting(
+          optimization_guide::proto::OPTIMIZATION_TARGET_LANGUAGE_DETECTION,
+          optimization_guide::TestModelInfoBuilder()
+              .SetModelFilePath(model_file_path())
+              .Build());
+
+  RetryForHistogramUntilCountReached(
+      &histogram_tester,
+      "TranslateModelService.LanguageDetectionModel.WasLoaded", 2);
+  histogram_tester.ExpectUniqueSample(
+      "TranslateModelService.LanguageDetectionModel.WasLoaded", true, 2);
+
+  ASSERT_TRUE(RequestAndWaitForModelFile()->IsValid());
+}
+
+// Tests that we immediately reject requests if we exceed the allowed number of
+// pending requests.
+IN_PROC_BROWSER_TEST_F(LanguageDetectionModelServiceBrowserTest,
+                       LimitPendingRequests) {
+  base::ScopedAllowBlockingForTesting allow_io_for_test_setup;
+  base::HistogramTester histogram_tester;
+  ASSERT_TRUE(language_detection_model_service());
+
+  ASSERT_GE(kMaxPendingRequestsAllowed, 1);
+
+  // The intention is to queue `kMaxPendingRequestsAllowed` pending requests and
+  // then one more that should fail immediately. However sometimes a request is
+  // already queued due to the renderer process, so we queue 1-less than max,
+  // expecting them all to remain pending and then be successfully fulfilled and
+  // then one more which may or may not remain pending.
+  // TODO(https://crbug.com/364504537): Make this a unittest to avoid this race
+  // condition.
+  std::vector<std::unique_ptr<ModelFileGetter>> getters;
+  for (int i = 0; i < kMaxPendingRequestsAllowed - 1; i++) {
+    getters.emplace_back(
+        std::make_unique<ModelFileGetter>(*language_detection_model_service()));
+    getters.back()->RequestModelFile();
+  }
+
+  // This one might exceed the max depending on whether we received a request
+  // from the renderer, so we never check its status.
+  ModelFileGetter maybe_getter(*language_detection_model_service());
+  maybe_getter.RequestModelFile();
+
+  // Requesting one more should definitely give an invalid file immediately.
+  ASSERT_FALSE(RequestAndWaitForModelFile()->IsValid());
+  // The first `kMaxPendingRequestsAllowed - 1` pending ones should still be
+  // pending.
+  for (auto& getter_good : getters) {
+    ASSERT_FALSE(getter_good->HasFileBeenReceived());
+  }
+
+  OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile())
+      ->OverrideTargetModelForTesting(
+          optimization_guide::proto::OPTIMIZATION_TARGET_LANGUAGE_DETECTION,
+          optimization_guide::TestModelInfoBuilder()
+              .SetModelFilePath(model_file_path())
+              .Build());
+
+  // The first `kMaxPendingRequestsAllowed` should get a valid file now.
+  for (auto& getter_good : getters) {
+    ASSERT_TRUE(getter_good->WaitForModelFile()->IsValid());
+  }
+
+  // Requesting one more now should give a valid file because the queue has been
+  // emptied.
+  ASSERT_TRUE(RequestAndWaitForModelFile()->IsValid());
+}
+
+}  // namespace
+}  // namespace language_detection
diff --git a/chrome/browser/translate/translate_model_service_browsertest.cc b/chrome/browser/translate/translate_model_service_browsertest.cc
deleted file mode 100644
index be1af14..0000000
--- a/chrome/browser/translate/translate_model_service_browsertest.cc
+++ /dev/null
@@ -1,431 +0,0 @@
-// Copyright 2020 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/base_paths.h"
-#include "base/files/file.h"
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/functional/bind.h"
-#include "base/path_service.h"
-#include "base/run_loop.h"
-#include "base/task/thread_pool/thread_pool_instance.h"
-#include "base/test/metrics/histogram_tester.h"
-#include "base/test/scoped_feature_list.h"
-#include "base/threading/thread_restrictions.h"
-#include "build/build_config.h"
-#include "chrome/browser/optimization_guide/optimization_guide_keyed_service.h"
-#include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/profiles/profile_key.h"
-#include "chrome/browser/translate/translate_model_service_factory.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/test/base/in_process_browser_test.h"
-#include "chrome/test/base/ui_test_utils.h"
-#include "components/metrics/content/subprocess_metrics_provider.h"
-#include "components/optimization_guide/core/model_util.h"
-#include "components/optimization_guide/core/optimization_guide_features.h"
-#include "components/optimization_guide/core/optimization_guide_test_util.h"
-#include "components/optimization_guide/core/test_model_info_builder.h"
-#include "components/optimization_guide/proto/models.pb.h"
-#include "components/translate/core/common/translate_util.h"
-#include "components/translate/core/language_detection/language_detection_model.h"
-#include "content/public/test/browser_test.h"
-#include "content/public/test/browser_test_utils.h"
-#include "net/dns/mock_host_resolver.h"
-#include "net/http/http_status_code.h"
-#include "net/test/embedded_test_server/embedded_test_server.h"
-#include "net/test/embedded_test_server/http_request.h"
-#include "net/test/embedded_test_server/http_response.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace translate {
-namespace {
-
-// Fetch and calculate the total number of samples from all the bins for
-// |histogram_name|. Note: from some browertests run (such as chromeos) there
-// might be two profiles created, and this will return the total sample count
-// across profiles.
-int GetTotalHistogramSamples(const base::HistogramTester* histogram_tester,
-                             const std::string& histogram_name) {
-  std::vector<base::Bucket> buckets =
-      histogram_tester->GetAllSamples(histogram_name);
-  int total = 0;
-  for (const auto& bucket : buckets)
-    total += bucket.count;
-
-  return total;
-}
-
-// Retries fetching |histogram_name| until it contains at least |count| samples.
-int RetryForHistogramUntilCountReached(
-    const base::HistogramTester* histogram_tester,
-    const std::string& histogram_name,
-    int count) {
-  while (true) {
-    base::ThreadPoolInstance::Get()->FlushForTesting();
-    base::RunLoop().RunUntilIdle();
-
-    int total = GetTotalHistogramSamples(histogram_tester, histogram_name);
-    if (total >= count)
-      return total;
-
-    content::FetchHistogramsFromChildProcesses();
-    metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
-    base::RunLoop().RunUntilIdle();
-  }
-}
-
-class TranslateModelServiceDisabledBrowserTest : public InProcessBrowserTest {
- public:
-  TranslateModelServiceDisabledBrowserTest() {
-    scoped_feature_list_.InitAndDisableFeature(
-        translate::kTFLiteLanguageDetectionEnabled);
-  }
-
-  void SetUp() override {
-    origin_server_ = std::make_unique<net::EmbeddedTestServer>(
-        net::EmbeddedTestServer::TYPE_HTTPS);
-    origin_server_->ServeFilesFromSourceDirectory(
-        "chrome/test/data/optimization_guide");
-
-    ASSERT_TRUE(origin_server_->Start());
-    english_url_ = origin_server_->GetURL("/hello_world.html");
-    InProcessBrowserTest::SetUp();
-  }
-
-  ~TranslateModelServiceDisabledBrowserTest() override = default;
-
-  const GURL& english_url() const { return english_url_; }
-
- private:
-  GURL english_url_;
-  std::unique_ptr<net::EmbeddedTestServer> origin_server_;
-  base::test::ScopedFeatureList scoped_feature_list_;
-};
-
-IN_PROC_BROWSER_TEST_F(TranslateModelServiceDisabledBrowserTest,
-                       TranslateModelServiceDisabled) {
-  EXPECT_FALSE(
-      TranslateModelServiceFactory::GetForProfile(browser()->profile()));
-}
-
-class TranslateModelServiceWithoutOptimizationGuideBrowserTest
-    : public TranslateModelServiceDisabledBrowserTest {
- public:
-  TranslateModelServiceWithoutOptimizationGuideBrowserTest() {
-    scoped_feature_list_.InitWithFeatures(
-        {translate::kTFLiteLanguageDetectionEnabled},
-        {optimization_guide::features::kOptimizationHints});
-  }
-
-  ~TranslateModelServiceWithoutOptimizationGuideBrowserTest() override =
-      default;
-
- private:
-  base::test::ScopedFeatureList scoped_feature_list_;
-};
-
-// This test confirms the translate model service is not available if
-// the optimization guide does not exist.
-IN_PROC_BROWSER_TEST_F(TranslateModelServiceWithoutOptimizationGuideBrowserTest,
-                       TranslateModelServiceEnabled) {
-  EXPECT_FALSE(
-      TranslateModelServiceFactory::GetForProfile(browser()->profile()));
-}
-
-IN_PROC_BROWSER_TEST_F(TranslateModelServiceDisabledBrowserTest,
-                       LanguageDetectionModelNotCreated) {
-  base::HistogramTester histogram_tester;
-
-  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), english_url()));
-  RetryForHistogramUntilCountReached(
-      &histogram_tester, "Translate.CLD3.TopLanguageEvaluationDuration", 1);
-  histogram_tester.ExpectTotalCount(
-      "LanguageDetection.TFLiteModel.WasModelAvailableForDetection", 0);
-}
-
-class TranslateModelServiceBrowserTest
-    : public TranslateModelServiceDisabledBrowserTest {
- public:
-  TranslateModelServiceBrowserTest() {
-    scoped_feature_list_.InitWithFeatures(
-        {translate::kTFLiteLanguageDetectionEnabled,
-         optimization_guide::features::kOptimizationHints,
-         optimization_guide::features::kRemoteOptimizationGuideFetching},
-        {});
-  }
-
-  void SetUp() override {
-    origin_server_ = std::make_unique<net::EmbeddedTestServer>(
-        net::EmbeddedTestServer::TYPE_HTTPS);
-    origin_server_->ServeFilesFromSourceDirectory(
-        "chrome/test/data/optimization_guide");
-    origin_server_->RegisterRequestHandler(
-        base::BindRepeating(&TranslateModelServiceBrowserTest::RequestHandler,
-                            base::Unretained(this)));
-    ASSERT_TRUE(origin_server_->Start());
-    english_url_ = origin_server_->GetURL("/hello_world.html");
-    InProcessBrowserTest::SetUp();
-  }
-
-  ~TranslateModelServiceBrowserTest() override = default;
-
-  translate::TranslateModelService* translate_model_service() {
-    return TranslateModelServiceFactory::GetForProfile(browser()->profile());
-  }
-
-  const GURL& english_url() const { return english_url_; }
-
- private:
-  std::unique_ptr<net::test_server::HttpResponse> RequestHandler(
-      const net::test_server::HttpRequest& request) {
-    std::string path_value;
-
-    // This script is render blocking in the HTML, but is intentionally slow.
-    // This provides important time between commit and first layout for model
-    // requests to make it to the renderer, reducing flakes.
-    if (request.GetURL().path() == "/slow-first-layout.js") {
-      std::unique_ptr<net::test_server::DelayedHttpResponse> resp =
-          std::make_unique<net::test_server::DelayedHttpResponse>(
-              base::Milliseconds(500));
-      resp->set_code(net::HTTP_OK);
-      resp->set_content_type("application/javascript");
-      resp->set_content(std::string());
-      return resp;
-    }
-
-    return nullptr;
-  }
-  base::test::ScopedFeatureList scoped_feature_list_;
-  GURL english_url_;
-  std::unique_ptr<net::EmbeddedTestServer> origin_server_;
-};
-
-base::FilePath model_file_path() {
-  base::FilePath source_root_dir;
-  base::PathService::Get(base::DIR_SRC_TEST_DATA_ROOT, &source_root_dir);
-  return source_root_dir.AppendASCII("components")
-      .AppendASCII("test")
-      .AppendASCII("data")
-      .AppendASCII("translate")
-      .AppendASCII("valid_model.tflite");
-}
-
-IN_PROC_BROWSER_TEST_F(TranslateModelServiceBrowserTest,
-                       TranslateModelServiceEnabled) {
-  EXPECT_TRUE(translate_model_service());
-}
-
-IN_PROC_BROWSER_TEST_F(TranslateModelServiceBrowserTest,
-                       TranslateModelServiceEnabled_OffTheRecord) {
-  EXPECT_TRUE(TranslateModelServiceFactory::GetForProfile(
-      browser()->profile()->GetPrimaryOTRProfile(/*create_if_needed=*/true)));
-}
-
-IN_PROC_BROWSER_TEST_F(TranslateModelServiceBrowserTest,
-                       LanguageDetectionModelReadyOnRequest) {
-  base::ScopedAllowBlockingForTesting allow_io_for_test_setup;
-  base::HistogramTester histogram_tester;
-  ASSERT_TRUE(translate_model_service());
-
-  OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile())
-      ->OverrideTargetModelForTesting(
-          optimization_guide::proto::OPTIMIZATION_TARGET_LANGUAGE_DETECTION,
-          optimization_guide::TestModelInfoBuilder()
-              .SetModelFilePath(model_file_path())
-              .Build());
-
-  RetryForHistogramUntilCountReached(
-      &histogram_tester,
-      "TranslateModelService.LanguageDetectionModel.WasLoaded", 1);
-  histogram_tester.ExpectUniqueSample(
-      "TranslateModelService.LanguageDetectionModel.WasLoaded", true, 1);
-
-  base::File model_file =
-      translate_model_service()->GetLanguageDetectionModelFile();
-  EXPECT_TRUE(model_file.IsValid());
-}
-
-IN_PROC_BROWSER_TEST_F(TranslateModelServiceBrowserTest,
-                       LanguageDetectionModelLoadedAfterRequest) {
-  base::ScopedAllowBlockingForTesting allow_io_for_test_setup;
-  base::HistogramTester histogram_tester;
-  ASSERT_TRUE(translate_model_service());
-  EXPECT_FALSE(translate_model_service()->IsModelAvailable());
-
-  std::unique_ptr<base::RunLoop> run_loop = std::make_unique<base::RunLoop>();
-  translate_model_service()->NotifyOnModelFileAvailable(base::BindOnce(
-      [](base::RunLoop* run_loop,
-         TranslateModelService* translate_model_service, bool is_available) {
-        EXPECT_TRUE(translate_model_service->IsModelAvailable());
-        EXPECT_TRUE(is_available);
-        run_loop->Quit();
-      },
-      run_loop.get(), translate_model_service()));
-
-  OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile())
-      ->OverrideTargetModelForTesting(
-          optimization_guide::proto::OPTIMIZATION_TARGET_LANGUAGE_DETECTION,
-          optimization_guide::TestModelInfoBuilder()
-              .SetModelFilePath(model_file_path())
-              .Build());
-
-  RetryForHistogramUntilCountReached(
-      &histogram_tester,
-      "TranslateModelService.LanguageDetectionModel.WasLoaded", 1);
-  histogram_tester.ExpectUniqueSample(
-      "TranslateModelService.LanguageDetectionModel.WasLoaded", true, 1);
-  run_loop->Run();
-
-  base::File model_file =
-      translate_model_service()->GetLanguageDetectionModelFile();
-  EXPECT_TRUE(model_file.IsValid());
-}
-
-IN_PROC_BROWSER_TEST_F(TranslateModelServiceBrowserTest,
-                       InvalidModelWhenLoading) {
-  base::ScopedAllowBlockingForTesting allow_io_for_test_setup;
-  base::HistogramTester histogram_tester;
-  ASSERT_TRUE(translate_model_service());
-  OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile())
-      ->OverrideTargetModelForTesting(
-          optimization_guide::proto::OPTIMIZATION_TARGET_LANGUAGE_DETECTION,
-          optimization_guide::TestModelInfoBuilder()
-              .SetModelFilePath(
-                  base::FilePath(optimization_guide::StringToFilePath(
-                                     optimization_guide::kTestAbsoluteFilePath)
-                                     .value()))
-              .Build());
-
-  RetryForHistogramUntilCountReached(
-      &histogram_tester,
-      "TranslateModelService.LanguageDetectionModel.WasLoaded", 1);
-  histogram_tester.ExpectUniqueSample(
-      "TranslateModelService.LanguageDetectionModel.WasLoaded", false, 1);
-}
-
-// TODO(crbug.com/40836720): Re-enable this test
-#if BUILDFLAG(IS_CHROMEOS)
-#define MAYBE_LanguageDetectionModelAvailableForDetection \
-  DISABLED_LanguageDetectionModelAvailableForDetection
-#else
-#define MAYBE_LanguageDetectionModelAvailableForDetection \
-  LanguageDetectionModelAvailableForDetection
-#endif
-IN_PROC_BROWSER_TEST_F(TranslateModelServiceBrowserTest,
-                       MAYBE_LanguageDetectionModelAvailableForDetection) {
-  base::HistogramTester histogram_tester;
-  OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile())
-      ->OverrideTargetModelForTesting(
-          optimization_guide::proto::OPTIMIZATION_TARGET_LANGUAGE_DETECTION,
-          optimization_guide::TestModelInfoBuilder()
-              .SetModelFilePath(model_file_path())
-              .Build());
-  RetryForHistogramUntilCountReached(
-      &histogram_tester,
-      "TranslateModelService.LanguageDetectionModel.WasLoaded", 1);
-  histogram_tester.ExpectUniqueSample(
-      "TranslateModelService.LanguageDetectionModel.WasLoaded", true, 1);
-
-  ui_test_utils::NavigateToURLWithDisposition(
-      browser(), english_url(), WindowOpenDisposition::NEW_FOREGROUND_TAB,
-      ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP);
-
-  RetryForHistogramUntilCountReached(
-      &histogram_tester,
-      "LanguageDetection.TFLiteModel.WasModelAvailableForDetection", 1);
-  histogram_tester.ExpectUniqueSample(
-      "LanguageDetection.TFLiteModel.WasModelAvailableForDetection", true, 1);
-}
-
-// Disabled on linux+ASAN, macOS+ASAN, chromeOS+ASAN and windows due to high
-// failure rate: crbug.com/1199854 crbug.com/1297485.
-// TODO(crbug.com/40904444): Re-enable this test
-#if (BUILDFLAG(IS_CHROMEOS) && !defined(NDEBUG)) ||        \
-    (BUILDFLAG(IS_LINUX) && BUILDFLAG(IS_MAC)) ||          \
-    (BUILDFLAG(IS_LINUX) && defined(ADDRESS_SANITIZER)) || \
-    (BUILDFLAG(IS_MAC) && defined(ADDRESS_SANITIZER)) || BUILDFLAG(IS_WIN)
-#define MAYBE_LanguageDetectionWithBackgroundTab \
-  DISABLED_LanguageDetectionWithBackgroundTab
-#else
-#define MAYBE_LanguageDetectionWithBackgroundTab \
-  LanguageDetectionWithBackgroundTab
-#endif
-IN_PROC_BROWSER_TEST_F(TranslateModelServiceBrowserTest,
-                       MAYBE_LanguageDetectionWithBackgroundTab) {
-  base::HistogramTester histogram_tester;
-  OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile())
-      ->OverrideTargetModelForTesting(
-          optimization_guide::proto::OPTIMIZATION_TARGET_LANGUAGE_DETECTION,
-          optimization_guide::TestModelInfoBuilder()
-              .SetModelFilePath(model_file_path())
-              .Build());
-
-  RetryForHistogramUntilCountReached(
-      &histogram_tester,
-      "TranslateModelService.LanguageDetectionModel.WasLoaded", 1);
-  histogram_tester.ExpectUniqueSample(
-      "TranslateModelService.LanguageDetectionModel.WasLoaded", true, 1);
-
-  ui_test_utils::NavigateToURLWithDisposition(
-      browser(), english_url(), WindowOpenDisposition::NEW_BACKGROUND_TAB,
-      ui_test_utils::BROWSER_TEST_NO_WAIT);
-
-  // Opening the browser causes the first model deferral event. The second
-  // is due to the background tab.
-  RetryForHistogramUntilCountReached(
-      &histogram_tester,
-      "LanguageDetection.TFLiteModel.WasModelRequestDeferred", 2);
-  histogram_tester.ExpectBucketCount(
-      "LanguageDetection.TFLiteModel.WasModelRequestDeferred", true, 2);
-
-  // Make the background tab the active tab.
-  browser()->tab_strip_model()->SelectNextTab();
-
-  RetryForHistogramUntilCountReached(
-      &histogram_tester,
-      "LanguageDetection.TFLiteModel.WasModelAvailableForDetection", 1);
-  histogram_tester.ExpectBucketCount(
-      "LanguageDetection.TFLiteModel.WasModelAvailableForDetection", true, 1);
-}
-
-IN_PROC_BROWSER_TEST_F(TranslateModelServiceBrowserTest,
-                       ModelUpdateFromOptimizationGuide) {
-  base::ScopedAllowBlockingForTesting allow_io_for_test_setup;
-  base::HistogramTester histogram_tester;
-  ASSERT_TRUE(translate_model_service());
-
-  OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile())
-      ->OverrideTargetModelForTesting(
-          optimization_guide::proto::OPTIMIZATION_TARGET_LANGUAGE_DETECTION,
-          optimization_guide::TestModelInfoBuilder()
-              .SetModelFilePath(model_file_path())
-              .Build());
-
-  RetryForHistogramUntilCountReached(
-      &histogram_tester,
-      "TranslateModelService.LanguageDetectionModel.WasLoaded", 1);
-  histogram_tester.ExpectUniqueSample(
-      "TranslateModelService.LanguageDetectionModel.WasLoaded", true, 1);
-
-  OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile())
-      ->OverrideTargetModelForTesting(
-          optimization_guide::proto::OPTIMIZATION_TARGET_LANGUAGE_DETECTION,
-          optimization_guide::TestModelInfoBuilder()
-              .SetModelFilePath(model_file_path())
-              .Build());
-
-  RetryForHistogramUntilCountReached(
-      &histogram_tester,
-      "TranslateModelService.LanguageDetectionModel.WasLoaded", 2);
-  histogram_tester.ExpectUniqueSample(
-      "TranslateModelService.LanguageDetectionModel.WasLoaded", true, 2);
-
-  base::File model_file =
-      translate_model_service()->GetLanguageDetectionModelFile();
-  EXPECT_TRUE(model_file.IsValid());
-}
-
-}  // namespace
-}  // namespace translate
diff --git a/chrome/browser/translate/translate_model_service_factory.h b/chrome/browser/translate/translate_model_service_factory.h
deleted file mode 100644
index a44d49f4..0000000
--- a/chrome/browser/translate/translate_model_service_factory.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2020 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_TRANSLATE_TRANSLATE_MODEL_SERVICE_FACTORY_H_
-#define CHROME_BROWSER_TRANSLATE_TRANSLATE_MODEL_SERVICE_FACTORY_H_
-
-#include "base/no_destructor.h"
-#include "chrome/browser/profiles/profile_keyed_service_factory.h"
-#include "components/translate/core/browser/translate_model_service.h"
-
-namespace content {
-class BrowserContext;
-}  // namespace content
-
-class Profile;
-
-// LazyInstance that owns all TranslateModelService(s) and associates
-// them with Profiles.
-class TranslateModelServiceFactory : public ProfileKeyedServiceFactory {
- public:
-  // Gets the TranslateModelService for the profile.
-  //
-  // Returns null if the features that allow for this to provide useful
-  // information are disabled. Importantly, only available when the
-  // optimization guide service is.
-  static translate::TranslateModelService* GetForProfile(Profile* profile);
-
-  // Gets the LazyInstance that owns all TranslateModelService(s).
-  static TranslateModelServiceFactory* GetInstance();
-
- private:
-  friend base::NoDestructor<TranslateModelServiceFactory>;
-
-  TranslateModelServiceFactory();
-  ~TranslateModelServiceFactory() override;
-
-  // BrowserContextKeyedServiceFactory:
-  KeyedService* BuildServiceInstanceFor(
-      content::BrowserContext* context) const override;
-};
-
-#endif  // CHROME_BROWSER_TRANSLATE_TRANSLATE_MODEL_SERVICE_FACTORY_H_
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index f840abf..82c3396 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -54,30 +54,6 @@
     "app_list/app_list_util.h",
 
     # All other app_list/ files go under is_chromeos_ash below.
-    "autofill/autofill_bubble_handler.h",
-    "autofill/autofill_client_provider.cc",
-    "autofill/autofill_client_provider.h",
-    "autofill/autofill_client_provider_factory.cc",
-    "autofill/autofill_client_provider_factory.h",
-    "autofill/autofill_popup_controller.h",
-    "autofill/autofill_popup_hide_helper.cc",
-    "autofill/autofill_popup_hide_helper.h",
-    "autofill/autofill_popup_view.h",
-    "autofill/autofill_popup_view_delegate.h",
-    "autofill/autofill_suggestion_controller.cc",
-    "autofill/autofill_suggestion_controller.h",
-    "autofill/autofill_suggestion_controller_utils.cc",
-    "autofill/autofill_suggestion_controller_utils.h",
-    "autofill/chrome_autofill_client.cc",
-    "autofill/chrome_autofill_client.h",
-    "autofill/next_idle_barrier.cc",
-    "autofill/next_idle_barrier.h",
-    "autofill/popup_controller_common.cc",
-    "autofill/popup_controller_common.h",
-    "autofill/risk_util.cc",
-    "autofill/risk_util.h",
-    "autofill/test/test_autofill_bubble_handler.cc",
-    "autofill/test/test_autofill_bubble_handler.h",
     "bluetooth/bluetooth_dialogs.h",
     "browser_dialogs.cc",
     "browser_dialogs.h",
@@ -89,7 +65,6 @@
     "confirm_bubble.h",
     "crypto_module_password_dialog.h",
     "cryptuiapi_shim.h",
-    "digital_credentials/digital_identity_safety_interstitial_controller.h",
     "enterprise_startup_dialog.h",
     "file_system_access/file_system_access_dangerous_file_dialog.cc",
     "file_system_access/file_system_access_dangerous_file_dialog.h",
@@ -266,8 +241,6 @@
     "webui/components/components_handler.h",
     "webui/components/components_ui.cc",
     "webui/components/components_ui.h",
-    "webui/constrained_web_dialog_ui.cc",
-    "webui/constrained_web_dialog_ui.h",
     "webui/data_sharing_internals/data_sharing_internals_page_handler_impl.cc",
     "webui/data_sharing_internals/data_sharing_internals_page_handler_impl.h",
     "webui/data_sharing_internals/data_sharing_internals_ui.cc",
@@ -457,6 +430,8 @@
     "//chrome/browser/signin:identity_manager_provider",
     "//chrome/browser/storage_access_api",
     "//chrome/browser/sync",
+    "//chrome/browser/ui/autofill",
+    "//chrome/browser/ui/autofill:impl",
     "//chrome/browser/ui/autofill/payments",
     "//chrome/browser/ui/autofill/payments:impl",
     "//chrome/browser/ui/blocked_content",
@@ -464,12 +439,14 @@
     "//chrome/browser/ui/bluetooth",
     "//chrome/browser/ui/bluetooth:impl",
     "//chrome/browser/ui/cookie_controls",
+    "//chrome/browser/ui/digital_credentials",
     "//chrome/browser/ui/find_bar",
     "//chrome/browser/ui/find_bar:impl",
     "//chrome/browser/ui/omnibox",
     "//chrome/browser/ui/omnibox:impl",
     "//chrome/browser/ui/page_action:icon_type",
     "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/zoom",
     "//chrome/common",
     "//chrome/common/net",
@@ -769,6 +746,7 @@
 
     "//chrome/browser/ui/bluetooth:impl",
     "//chrome/browser/picture_in_picture:impl",
+    "//chrome/browser/ui/autofill:impl",
   ]
 
   if (enable_vr && is_win) {
@@ -923,16 +901,7 @@
       "android/toolbar/location_bar_model_android.h",
       "android/webid/account_selection_view_android.cc",
       "android/webid/account_selection_view_android.h",
-      "autofill/autofill_bubble_base.h",
-      "autofill/autofill_bubble_controller_base.cc",
-      "autofill/autofill_bubble_controller_base.h",
-      "autofill/autofill_keyboard_accessory_controller.h",
-      "autofill/autofill_keyboard_accessory_controller_impl.cc",
-      "autofill/autofill_keyboard_accessory_controller_impl.h",
-      "autofill/autofill_keyboard_accessory_view.h",
       "browser_otr_state_android.cc",
-      "digital_credentials/digital_identity_safety_interstitial_bridge_android.cc",
-      "digital_credentials/digital_identity_safety_interstitial_bridge_android.h",
       "fast_checkout/fast_checkout_controller.h",
       "fast_checkout/fast_checkout_controller_impl.cc",
       "fast_checkout/fast_checkout_controller_impl.h",
@@ -1031,10 +1000,6 @@
     sources += [
       "app_icon_loader.cc",
       "app_icon_loader.h",
-      "autofill/autofill_context_menu_manager.cc",
-      "autofill/autofill_context_menu_manager.h",
-      "autofill/autofill_popup_controller_impl.cc",
-      "autofill/autofill_popup_controller_impl.h",
       "bluetooth/chrome_bluetooth_chooser_controller.cc",
       "bluetooth/chrome_bluetooth_chooser_controller.h",
       "bookmarks/bookmark_bar.h",
@@ -1076,9 +1041,6 @@
       "browser_finder.h",
       "browser_instant_controller.cc",
       "browser_instant_controller.h",
-      "browser_list.cc",
-      "browser_list.h",
-      "browser_list_observer.h",
       "browser_live_tab_context.cc",
       "browser_live_tab_context.h",
       "browser_location_bar_model_delegate.cc",
@@ -2092,6 +2054,8 @@
     # Non-android public_deps for "ui" target.
     public_deps += [
       "//chrome/browser/task_manager",
+      "//chrome/browser/ui:browser_list",
+      "//chrome/browser/ui:browser_list_impl",
       "//chrome/browser/ui/tabs:tab_enums",
       "//chrome/browser/ui/views/side_panel",
     ]
@@ -2134,6 +2098,8 @@
 
       "//chrome/browser/ui/signin:impl",
       "//chrome/browser/ui/webui/signin:impl",
+
+      "//chrome/browser/ui:browser_list_impl",
     ]
 
     if (is_mac) {
@@ -3504,10 +3470,6 @@
 
     if (enable_dice_support) {
       sources += [
-        "autofill/autofill_bubble_signin_promo_controller.cc",
-        "autofill/autofill_bubble_signin_promo_controller.h",
-        "autofill/autofill_signin_promo_tab_helper.cc",
-        "autofill/autofill_signin_promo_tab_helper.h",
         "profiles/batch_upload_ui_delegate.cc",
         "profiles/batch_upload_ui_delegate.h",
         "profiles/signin_intercept_first_run_experience_dialog.cc",
@@ -3586,8 +3548,6 @@
 
   if (is_mac) {
     sources += [
-      "autofill/autofill_popup_controller_impl_mac.h",
-      "autofill/autofill_popup_controller_impl_mac.mm",
       "browser_commands_mac.h",
       "browser_commands_mac.mm",
       "browser_mac.cc",
@@ -3941,10 +3901,10 @@
   # limited to the same set of platforms.
   if (is_win || is_mac || is_linux || is_chromeos_ash) {
     sources += [
-      "device_signals_consent/consent_requester.h",
       "views/device_signals_consent/consent_dialog_coordinator.cc",
       "views/device_signals_consent/consent_dialog_coordinator.h",
     ]
+    deps += [ "//chrome/browser/ui/device_signals_consent" ]
   }
 
   if (enable_webui_certificate_viewer) {
@@ -3975,37 +3935,6 @@
 
   if (toolkit_views) {
     sources += [
-      "autofill/add_new_address_bubble_controller.cc",
-      "autofill/add_new_address_bubble_controller.h",
-      "autofill/address_bubble_controller_delegate.h",
-      "autofill/address_bubbles_controller.cc",
-      "autofill/address_bubbles_controller.h",
-      "autofill/address_bubbles_icon_controller.cc",
-      "autofill/address_bubbles_icon_controller.h",
-      "autofill/address_editor_controller.cc",
-      "autofill/address_editor_controller.h",
-      "autofill/autofill_bubble_base.h",
-      "autofill/autofill_bubble_controller_base.cc",
-      "autofill/autofill_bubble_controller_base.h",
-      "autofill/autofill_field_promo_controller.h",
-      "autofill/autofill_field_promo_controller_impl.cc",
-      "autofill/autofill_field_promo_controller_impl.h",
-      "autofill/autofill_field_promo_view.h",
-      "autofill/autofill_prediction_improvements/save_autofill_prediction_improvements_controller.h",
-      "autofill/autofill_prediction_improvements/save_autofill_prediction_improvements_controller_impl.cc",
-      "autofill/autofill_prediction_improvements/save_autofill_prediction_improvements_controller_impl.h",
-      "autofill/delete_address_profile_dialog_controller.h",
-      "autofill/delete_address_profile_dialog_controller_impl.cc",
-      "autofill/delete_address_profile_dialog_controller_impl.h",
-      "autofill/delete_address_profile_dialog_view.h",
-      "autofill/edit_address_profile_dialog_controller.h",
-      "autofill/edit_address_profile_dialog_controller_impl.cc",
-      "autofill/edit_address_profile_dialog_controller_impl.h",
-      "autofill/edit_address_profile_view.h",
-      "autofill/save_address_bubble_controller.cc",
-      "autofill/save_address_bubble_controller.h",
-      "autofill/update_address_bubble_controller.cc",
-      "autofill/update_address_bubble_controller.h",
       "bubble_anchor_util.h",
       "dialogs/outdated_upgrade_bubble.cc",
       "dialogs/outdated_upgrade_bubble.h",
@@ -6137,6 +6066,28 @@
   deps = []
 }
 
+if (!is_android) {
+  source_set("browser_list") {
+    sources = [
+      "browser_list.h",
+      "browser_list_observer.h",
+    ]
+    public_deps = [ "//base" ]
+  }
+
+  source_set("browser_list_impl") {
+    sources = [ "browser_list.cc" ]
+    public_deps = [ "//chrome/browser:browser_public_dependencies" ]
+    deps = [
+      "//base",
+      "//chrome/browser:browser_process",
+      "//chrome/browser:buildflags",
+      "//chrome/browser/profiles:profile",
+      "//chrome/browser/ui:browser_list",
+    ]
+  }
+}
+
 # In GYP this is part of test_support_common.
 static_library("test_support") {
   testonly = true
@@ -6270,14 +6221,6 @@
     public_deps += [ "//chrome/browser/ui/exclusive_access" ]
   }
 
-  if (is_win || is_mac || is_linux || is_chromeos_ash) {
-    sources += [
-      "device_signals_consent/mock_consent_requester.cc",
-      "device_signals_consent/mock_consent_requester.h",
-    ]
-    deps += [ "//components/device_signals/core/browser" ]
-  }
-
   if (enable_extensions) {
     sources += [
       "toolbar/test_toolbar_action_view_controller.cc",
diff --git a/chrome/browser/ui/ash/BUILD.gn b/chrome/browser/ui/ash/BUILD.gn
index ddb90439..bf35161 100644
--- a/chrome/browser/ui/ash/BUILD.gn
+++ b/chrome/browser/ui/ash/BUILD.gn
@@ -12,11 +12,8 @@
   sources = [
     "crosapi_new_window_delegate.cc",
     "crosapi_new_window_delegate.h",
-    "login_screen_shown_observer.h",
     "screen_orientation_delegate_chromeos.cc",
     "screen_orientation_delegate_chromeos.h",
-    "screenshot_area.cc",
-    "screenshot_area.h",
     "system_sounds_delegate_impl.cc",
     "system_sounds_delegate_impl.h",
     "window_pin_util_ash.cc",
@@ -369,8 +366,6 @@
 
   defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ]
 
-  sources = [ "screen_orientation_delegate_chromeos_browsertest.cc" ]
-
   deps = [
     ":ash",
     "//ash",
diff --git a/chrome/browser/ui/ash/accelerator/BUILD.gn b/chrome/browser/ui/ash/accelerator/BUILD.gn
index c89fa704..b84ba636 100644
--- a/chrome/browser/ui/ash/accelerator/BUILD.gn
+++ b/chrome/browser/ui/ash/accelerator/BUILD.gn
@@ -16,7 +16,6 @@
 
   deps = [
     "//ash",
-    "//chrome/browser/ash/app_list/arc",
     "//components/user_manager",
   ]
 }
diff --git a/chrome/browser/ui/ash/accelerator/DEPS b/chrome/browser/ui/ash/accelerator/DEPS
index b95cc04d..c0e4eff 100644
--- a/chrome/browser/ui/ash/accelerator/DEPS
+++ b/chrome/browser/ui/ash/accelerator/DEPS
@@ -10,7 +10,6 @@
   # Existing dependencies within //chrome. There is an active effort to
   # refactor ash codes in //chrome to break these dependencies; see b/332804822.
   # Whenever possible, avoid adding new //chrome dependencies to this list.
-  "+chrome/browser/ash/app_list/arc",
   "+chrome/browser/policy/profile_policy_connector.h",
   "+chrome/browser/profiles/profile_manager.h",
 ]
diff --git a/chrome/browser/ui/ash/accelerator/chrome_accelerator_prefs_delegate.cc b/chrome/browser/ui/ash/accelerator/chrome_accelerator_prefs_delegate.cc
index b4bdbaa..c037c63a 100644
--- a/chrome/browser/ui/ash/accelerator/chrome_accelerator_prefs_delegate.cc
+++ b/chrome/browser/ui/ash/accelerator/chrome_accelerator_prefs_delegate.cc
@@ -4,7 +4,6 @@
 
 #include "chrome/browser/ui/ash/accelerator/chrome_accelerator_prefs_delegate.h"
 
-#include "chrome/browser/ash/app_list/arc/arc_app_list_prefs.h"
 #include "chrome/browser/policy/profile_policy_connector.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "components/user_manager/user_manager.h"
diff --git a/chrome/browser/ui/ash/capture_mode/BUILD.gn b/chrome/browser/ui/ash/capture_mode/BUILD.gn
index 5de2e3d..075f5d3 100644
--- a/chrome/browser/ui/ash/capture_mode/BUILD.gn
+++ b/chrome/browser/ui/ash/capture_mode/BUILD.gn
@@ -36,6 +36,7 @@
     "//chrome/common",
     "//chromeos/ash/components/drivefs/mojom",
     "//chromeos/ash/components/login/login_state",
+    "//chromeos/ash/experiences/screenshot_area",
     "//chromeos/ash/services/recording/public/mojom",
     "//components/drive",
     "//content/public/browser",
diff --git a/chrome/browser/ui/ash/capture_mode/chrome_capture_mode_delegate.cc b/chrome/browser/ui/ash/capture_mode/chrome_capture_mode_delegate.cc
index 4ab9cfc1..97cfb80 100644
--- a/chrome/browser/ui/ash/capture_mode/chrome_capture_mode_delegate.cc
+++ b/chrome/browser/ui/ash/capture_mode/chrome_capture_mode_delegate.cc
@@ -33,12 +33,12 @@
 #include "chrome/browser/policy/system_features_disable_list_policy_handler.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/ash/capture_mode/search_results_view.h"
-#include "chrome/browser/ui/ash/screenshot_area.h"
 #include "chrome/browser/ui/ash/system_web_apps/system_web_app_ui_utils.h"
 #include "chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_util.h"
 #include "chrome/browser/web_applications/web_app_id_constants.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/ash/components/login/login_state/login_state.h"
+#include "chromeos/ash/experiences/screenshot_area/screenshot_area.h"
 #include "chromeos/ash/services/recording/public/mojom/recording_service.mojom.h"
 #include "components/drive/file_errors.h"
 #include "components/prefs/pref_service.h"
diff --git a/chrome/browser/ui/ash/login/DEPS b/chrome/browser/ui/ash/login/DEPS
index 087347e..c560567 100644
--- a/chrome/browser/ui/ash/login/DEPS
+++ b/chrome/browser/ui/ash/login/DEPS
@@ -13,7 +13,6 @@
   "+chrome/browser/ash/child_accounts/parent_access_code",
   "+chrome/browser/ash/login",
   "+chrome/browser/profiles",
-  "+chrome/browser/ui/ash/login_screen_shown_observer.h",
   "+chrome/browser/ui/ash/wallpaper",
   "+chrome/browser/ui/settings_window_manager_chromeos.h",
   "+chrome/browser/ui/webui/ash/lock_screen_reauth",
diff --git a/chrome/browser/ui/ash/login/login_screen_client_impl.h b/chrome/browser/ui/ash/login/login_screen_client_impl.h
index 22b48701..eb76d519 100644
--- a/chrome/browser/ui/ash/login/login_screen_client_impl.h
+++ b/chrome/browser/ui/ash/login/login_screen_client_impl.h
@@ -14,7 +14,7 @@
 #include "base/scoped_observation_traits.h"
 #include "base/time/time.h"
 #include "base/values.h"
-#include "chrome/browser/ui/ash/login_screen_shown_observer.h"
+#include "chromeos/ash/experiences/login/login_screen_shown_observer.h"
 #include "components/user_manager/user_manager.h"
 
 namespace ash {
diff --git a/chrome/browser/ui/ash/media_client/BUILD.gn b/chrome/browser/ui/ash/media_client/BUILD.gn
index e87c84c..a6f34d3 100644
--- a/chrome/browser/ui/ash/media_client/BUILD.gn
+++ b/chrome/browser/ui/ash/media_client/BUILD.gn
@@ -16,6 +16,7 @@
     "//ash",
     "//ash/public/cpp",
     "//base",
+    "//chrome/browser/ui:browser_list",
     "//media/capture:capture_lib",
     "//media/capture/video/chromeos/mojom:cros_camera",
     "//services/video_capture/public/mojom",
diff --git a/chrome/browser/ui/ash/multi_user/BUILD.gn b/chrome/browser/ui/ash/multi_user/BUILD.gn
index ef058ea..3be6072 100644
--- a/chrome/browser/ui/ash/multi_user/BUILD.gn
+++ b/chrome/browser/ui/ash/multi_user/BUILD.gn
@@ -20,7 +20,10 @@
     "multi_user_window_manager_stub.h",
   ]
 
-  public_deps = [ "//chrome/browser:browser_public_dependencies" ]
+  public_deps = [
+    "//chrome/browser:browser_public_dependencies",
+    "//chrome/browser/ui:browser_list",
+  ]
 
   deps = [
     "//ash",
diff --git a/chrome/browser/ui/ash/picker/picker_accessibility_browsertest.cc b/chrome/browser/ui/ash/picker/picker_accessibility_browsertest.cc
index 3f2e0a4..cbb0c8f0 100644
--- a/chrome/browser/ui/ash/picker/picker_accessibility_browsertest.cc
+++ b/chrome/browser/ui/ash/picker/picker_accessibility_browsertest.cc
@@ -635,28 +635,53 @@
           /*submenu_controller=*/nullptr));
   ash::PickerSectionView* section = view->AddSection();
   section->AddTitleLabel(u"Section1");
-  ash::PickerImageItemView* item =
+  ash::PickerImageItemView* item1 =
       section->AddImageGridItem(std::make_unique<ash::PickerImageItemView>(
           std::make_unique<views::ImageView>(
               ui::ImageModel::FromImage(gfx::test::CreateImage(1))),
           u"title1", base::DoNothing()));
-  item->SetAction(ash::PickerActionType::kInsert);
-  section->AddImageGridItem(std::make_unique<ash::PickerImageItemView>(
-      std::make_unique<views::ImageView>(
-          ui::ImageModel::FromImage(gfx::test::CreateImage(1))),
-      u"title2", base::DoNothing()));
-  section->AddImageGridItem(std::make_unique<ash::PickerImageItemView>(
-      std::make_unique<views::ImageView>(
-          ui::ImageModel::FromImage(gfx::test::CreateImage(1))),
-      u"title3", base::DoNothing()));
+  item1->SetAction(ash::PickerActionType::kInsert);
 
-  sm_.Call([item]() { item->RequestFocus(); });
+  ash::PickerImageItemView* item2 =
+      section->AddImageGridItem(std::make_unique<ash::PickerImageItemView>(
+          std::make_unique<views::ImageView>(
+              ui::ImageModel::FromImage(gfx::test::CreateImage(1))),
+          u"title2", base::DoNothing()));
+  item2->SetAction(ash::PickerActionType::kOpen);
+
+  ash::PickerImageItemView* item3 =
+      section->AddImageGridItem(std::make_unique<ash::PickerImageItemView>(
+          std::make_unique<views::ImageView>(
+              ui::ImageModel::FromImage(gfx::test::CreateImage(1))),
+          u"title3", base::DoNothing()));
+
+  sm_.Call([item1]() { item1->RequestFocus(); });
 
   sm_.ExpectSpeechPattern("Insert title1");
   sm_.ExpectSpeechPattern("Button");
   sm_.ExpectSpeechPattern("List item");
   sm_.ExpectSpeechPattern("1 of 3");
   sm_.ExpectSpeechPattern("Press * to activate");
+
+  sm_.Call([item2]() { item2->RequestFocus(); });
+
+  // TODO: b/362129770 - item2 should not have "List end".
+  sm_.ExpectSpeechPattern("Open title2");
+  sm_.ExpectSpeechPattern("Button");
+  sm_.ExpectSpeechPattern("List item");
+  sm_.ExpectSpeechPattern("2 of 3");
+  sm_.ExpectSpeechPattern("List end");
+  sm_.ExpectSpeechPattern("Press * to activate");
+
+  sm_.Call([item3]() { item3->RequestFocus(); });
+
+  // TODO: b/362129770 - item3 should have "List end".
+  sm_.ExpectSpeechPattern("title3");
+  sm_.ExpectSpeechPattern("Button");
+  sm_.ExpectSpeechPattern("List item");
+  sm_.ExpectSpeechPattern("3 of 3");
+  sm_.ExpectSpeechPattern("Press * to activate");
+
   sm_.Replay();
 }
 
diff --git a/chrome/browser/ui/ash/picker/picker_interactive_uitest.cc b/chrome/browser/ui/ash/picker/picker_interactive_uitest.cc
index 20be73a..3f3d352 100644
--- a/chrome/browser/ui/ash/picker/picker_interactive_uitest.cc
+++ b/chrome/browser/ui/ash/picker/picker_interactive_uitest.cc
@@ -109,6 +109,10 @@
   };
 
   PickerInteractiveUiTest() {
+    feature_list_.InitWithFeatures(
+        /*enabled_features=*/{ash::features::kPicker,
+                              ash::features::kPickerGrid},
+        /*disabled_features=*/{});
     ash::PickerController::DisableFeatureKeyCheck();
     ash::PickerController::DisableFeatureTourForTesting();
   }
@@ -158,7 +162,7 @@
   }
 
  private:
-  base::test::ScopedFeatureList feature_list_{ash::features::kPicker};
+  base::test::ScopedFeatureList feature_list_;
 };
 
 // Searches for 'thumbs up', checks the top emoji result is '👍', and inserts it
diff --git a/chrome/browser/ui/ash/shelf/app_service/BUILD.gn b/chrome/browser/ui/ash/shelf/app_service/BUILD.gn
index 9f9a85d..3998f27 100644
--- a/chrome/browser/ui/ash/shelf/app_service/BUILD.gn
+++ b/chrome/browser/ui/ash/shelf/app_service/BUILD.gn
@@ -55,6 +55,7 @@
     "//chrome/browser/ash/plugin_vm",
     "//chrome/browser/ash/profiles",
     "//chrome/browser/profiles:profile",
+    "//chrome/browser/ui:browser_list",
     "//chrome/browser/ui/ash/multi_user",
     "//chrome/browser/ui/views/crostini",
     "//chrome/browser/ui/webui/ash/settings/app_management",
diff --git a/chrome/browser/ui/ash/system_web_apps/BUILD.gn b/chrome/browser/ui/ash/system_web_apps/BUILD.gn
index df54b757..7cf7404 100644
--- a/chrome/browser/ui/ash/system_web_apps/BUILD.gn
+++ b/chrome/browser/ui/ash/system_web_apps/BUILD.gn
@@ -29,6 +29,7 @@
     "//chrome/browser/ash/system_web_apps/types",
     "//chrome/browser/profiles:profile",
     "//chrome/browser/scalable_iph:scalable_iph_factory",
+    "//chrome/browser/ui:browser_list",
     "//chrome/browser/ui/ash/multi_user",
     "//chrome/browser/web_applications",
     "//chrome/common",
diff --git a/chrome/browser/ui/autofill/BUILD.gn b/chrome/browser/ui/autofill/BUILD.gn
new file mode 100644
index 0000000..ce15402
--- /dev/null
+++ b/chrome/browser/ui/autofill/BUILD.gn
@@ -0,0 +1,498 @@
+# Copyright 2024 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/ui.gni")
+import("//build/util/branding.gni")
+import("//components/signin/features.gni")
+
+assert(is_win || is_mac || is_linux || is_chromeos || is_android)
+
+source_set("autofill") {
+  sources = [
+    "autofill_bubble_base.h",
+    "autofill_bubble_controller_base.h",
+    "autofill_bubble_handler.h",
+    "autofill_client_provider.h",
+    "autofill_client_provider_factory.h",
+    "autofill_popup_controller.h",
+    "autofill_popup_hide_helper.h",
+    "autofill_popup_view.h",
+    "autofill_popup_view_delegate.h",
+    "autofill_suggestion_controller.h",
+    "autofill_suggestion_controller_utils.h",
+    "chrome_autofill_client.h",
+    "next_idle_barrier.h",
+    "popup_controller_common.h",
+    "risk_util.h",
+  ]
+
+  public_deps = [
+    "//base",
+    "//base:i18n",
+    "//chrome/browser/picture_in_picture",
+    "//chrome/browser/profiles:profile",
+    "//chrome/browser/ui/autofill/payments",
+    "//chrome/browser/ui/page_action:icon_type",
+    "//components/autofill/content/browser",
+    "//components/autofill/core/browser",
+    "//components/autofill/core/common",
+    "//components/input",
+    "//components/keyed_service/core",
+    "//components/signin/public/identity_manager",
+    "//components/zoom",
+    "//content/public/browser",
+    "//ui/gfx",
+    "//ui/gfx/geometry",
+  ]
+
+  if (is_android) {
+    sources += [
+      "autofill_keyboard_accessory_controller.h",
+      "autofill_keyboard_accessory_controller_impl.h",
+      "autofill_keyboard_accessory_view.h",
+    ]
+    public_deps += [
+      "//components/autofill/android:autofill_core_browser_java_enums",
+      "//components/password_manager/core/browser:metrics_util",
+      "//components/password_manager/core/browser:password_manager_java_enums_srcjar",
+      "//content/public/android:content_public_android_java_enums_srcjar",
+    ]
+  } else {
+    sources += [
+      "add_new_address_bubble_controller.h",
+      "address_bubble_controller_delegate.h",
+      "address_bubbles_controller.h",
+      "address_bubbles_icon_controller.h",
+      "address_editor_controller.h",
+      "autofill_context_menu_manager.h",
+      "autofill_field_promo_controller.h",
+      "autofill_field_promo_controller_impl.h",
+      "autofill_field_promo_view.h",
+      "autofill_popup_controller_impl.h",
+      "autofill_prediction_improvements/save_autofill_prediction_improvements_controller.h",
+      "autofill_prediction_improvements/save_autofill_prediction_improvements_controller_impl.h",
+      "delete_address_profile_dialog_controller.h",
+      "delete_address_profile_dialog_controller_impl.h",
+      "delete_address_profile_dialog_view.h",
+      "edit_address_profile_dialog_controller.h",
+      "edit_address_profile_dialog_controller_impl.h",
+      "edit_address_profile_view.h",
+      "save_address_bubble_controller.h",
+      "update_address_bubble_controller.h",
+    ]
+    public_deps += [
+      "//components/password_manager/core/browser",
+      "//components/password_manager/core/browser:password_form",
+      "//components/renderer_context_menu",
+      "//third_party/abseil-cpp:absl",
+      "//ui/base",
+      "//ui/views",
+    ]
+  }
+
+  if (enable_dice_support) {
+    sources += [
+      "autofill_bubble_signin_promo_controller.h",
+      "autofill_signin_promo_tab_helper.h",
+    ]
+  }
+
+  if (is_mac) {
+    sources += [ "autofill_popup_controller_impl_mac.h" ]
+  }
+
+  allow_circular_includes_from = [ "//chrome/browser/ui/autofill/payments" ]
+}
+
+source_set("impl") {
+  sources = [
+    "autofill_bubble_controller_base.cc",
+    "autofill_client_provider.cc",
+    "autofill_client_provider_factory.cc",
+    "autofill_popup_hide_helper.cc",
+    "autofill_suggestion_controller.cc",
+    "autofill_suggestion_controller_utils.cc",
+    "chrome_autofill_client.cc",
+    "next_idle_barrier.cc",
+    "popup_controller_common.cc",
+    "risk_util.cc",
+  ]
+
+  public_deps = [ "//chrome/browser:browser_public_dependencies" ]
+
+  deps = [
+    ":autofill",
+    "//chrome/browser:browser_process",
+    "//chrome/browser/autofill",
+    "//chrome/browser/profiles:profile",
+    "//chrome/browser/sync",
+    "//chrome/browser/ui:browser_element_identifiers",
+    "//chrome/browser/ui/autofill/payments",
+    "//components/autofill/content/browser",
+    "//components/autofill/content/browser:risk_proto",
+    "//components/autofill_prediction_improvements/core/browser",
+    "//components/compose/core/browser",
+    "//components/compose/core/browser:features",
+    "//components/embedder_support:browser_util",
+    "//components/feature_engagement/public",
+    "//components/infobars/content",
+    "//components/infobars/core",
+    "//components/language/core/browser",
+    "//components/password_manager/content/browser",
+    "//components/password_manager/core/browser",
+    "//components/password_manager/core/browser:metrics_util",
+    "//components/password_manager/core/browser:password_form",
+    "//components/password_manager/core/browser/form_parsing",
+    "//components/plus_addresses:features",
+    "//components/plus_addresses:types",
+    "//components/profile_metrics",
+    "//components/security_state/content",
+    "//components/unified_consent",
+    "//components/variations/service",
+  ]
+
+  if (is_android) {
+    sources += [ "autofill_keyboard_accessory_controller_impl.cc" ]
+    deps += [
+      "//chrome/browser/autofill/android:jni_headers",
+      "//chrome/browser/keyboard_accessory/android:public",
+      "//chrome/browser/password_manager/android/access_loss:public",
+      "//components/android_autofill/browser:android",
+      "//components/messages/android:feature_flags",
+      "//components/password_manager/core/browser/features:password_features",
+    ]
+  } else {
+    sources += [
+      "add_new_address_bubble_controller.cc",
+      "address_bubbles_controller.cc",
+      "address_bubbles_icon_controller.cc",
+      "address_editor_controller.cc",
+      "autofill_context_menu_manager.cc",
+      "autofill_field_promo_controller_impl.cc",
+      "autofill_popup_controller_impl.cc",
+      "autofill_prediction_improvements/save_autofill_prediction_improvements_controller_impl.cc",
+      "delete_address_profile_dialog_controller_impl.cc",
+      "edit_address_profile_dialog_controller_impl.cc",
+      "save_address_bubble_controller.cc",
+      "update_address_bubble_controller.cc",
+    ]
+    deps += [
+      "//chrome/app:command_ids",
+      "//chrome/app/vector_icons",
+      "//chrome/browser/accessibility:utils",
+      "//chrome/browser/apps/platform_apps",
+      "//chrome/browser/feedback",
+      "//chrome/browser/ui:ui_features",
+      "//components/password_manager/core/browser/features:password_features",
+      "//components/plus_addresses",
+      "//extensions/browser",
+    ]
+
+    if (is_chrome_branded) {
+      deps += [ "//components/plus_addresses/resources:vector_icons" ]
+    }
+  }
+
+  if (enable_dice_support) {
+    sources += [
+      "autofill_bubble_signin_promo_controller.cc",
+      "autofill_signin_promo_tab_helper.cc",
+    ]
+  }
+
+  if (is_mac) {
+    sources += [ "autofill_popup_controller_impl_mac.mm" ]
+  }
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "autofill_client_provider_unittest.cc",
+    "autofill_suggestion_controller_unittest.cc",
+    "chrome_autofill_client_unittest.cc",
+  ]
+
+  deps = [
+    ":autofill",
+    ":test_support",
+    ":test_support_unit",
+    "//base",
+    "//base/test:test_support",
+    "//build:branding_buildflags",
+    "//build:chromeos_buildflags",
+    "//chrome/browser",
+    "//chrome/browser:browser_process",
+    "//chrome/browser/accessibility:utils",
+    "//chrome/browser/autofill",
+    "//chrome/browser/autofill:test_support",
+    "//chrome/browser/sync",
+    "//chrome/browser/ui",
+    "//chrome/browser/ui:browser_element_identifiers",
+    "//chrome/browser/ui:test_support",
+    "//chrome/browser/ui/autofill/payments",
+    "//chrome/browser/ui/tabs:tab_enums",
+    "//chrome/test:test_support",
+    "//components/autofill/content/browser:test_support",
+    "//components/autofill/core/browser:test_support",
+    "//components/autofill/core/common:test_support",
+    "//components/input",
+    "//components/keyed_service/content",
+    "//components/keyed_service/core",
+    "//components/password_manager/core/browser:password_form",
+    "//components/password_manager/core/common",
+    "//components/plus_addresses:features",
+    "//components/prefs:test_support",
+    "//components/signin/public/identity_manager",
+    "//components/strings:components_strings",
+    "//components/sync:test_support",
+    "//components/unified_consent",
+    "//components/user_education/common",
+    "//components/user_education/test",
+    "//content/public/browser",
+    "//content/test:test_support",
+    "//mojo/public/cpp/bindings",
+    "//testing/gmock",
+    "//testing/gtest",
+    "//third_party/blink/public/common:headers",
+    "//ui/accessibility",
+    "//ui/accessibility:ax_base",
+    "//ui/base",
+    "//ui/events",
+    "//ui/events:dom_keycode_converter",
+    "//ui/gfx",
+    "//ui/gfx/geometry",
+    "//ui/gfx/range",
+  ]
+
+  if (is_android) {
+    sources += [ "autofill_keyboard_accessory_controller_impl_unittest.cc" ]
+  } else {
+    sources += [
+      "add_new_address_bubble_controller_unittest.cc",
+      "address_bubbles_controller_unittest.cc",
+      "address_editor_controller_unittest.cc",
+      "autofill_field_promo_controller_impl_unittest.cc",
+      "autofill_popup_controller_impl_unittest.cc",
+      "delete_address_profile_dialog_controller_impl_unittest.cc",
+      "edit_address_profile_dialog_controller_impl_unittest.cc",
+      "save_address_bubble_controller_unittest.cc",
+      "update_address_bubble_controller_unittest.cc",
+    ]
+  }
+
+  if (enable_dice_support) {
+    sources += [ "autofill_bubble_signin_promo_controller_unittest.cc" ]
+  }
+}
+
+source_set("test_support") {
+  testonly = true
+  sources = [
+    "test/test_autofill_bubble_handler.cc",
+    "test/test_autofill_bubble_handler.h",
+  ]
+
+  public_deps = [ ":autofill" ]
+
+  if (is_android) {
+    sources += [ "autofill_keyboard_accessory_controller_impl_test_api.h" ]
+    public_deps +=
+        [ "//chrome/browser/password_manager/android/access_loss:public" ]
+  } else {
+    sources += [
+      "autofill_popup_controller_impl_test_api.h",
+      "mock_autofill_popup_controller.cc",
+      "mock_autofill_popup_controller.h",
+    ]
+    public_deps += [
+      "//testing/gmock",
+      "//ui/gfx:test_support",
+    ]
+  }
+}
+
+if (!is_android && !is_chromeos_device) {
+  source_set("interactive_ui_tests") {
+    testonly = true
+
+    defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ]
+
+    deps = [
+      ":autofill",
+      "//base",
+      "//base:i18n",
+      "//base/test:test_support",
+      "//build:buildflag_header_h",
+      "//build:chromeos_buildflags",
+      "//chrome/app:command_ids",
+      "//chrome/browser/autofill:test_support",
+      "//chrome/browser/profiles:profile",
+      "//chrome/browser/sync",
+      "//chrome/browser/sync:factories",
+      "//chrome/browser/ui",
+      "//chrome/common:constants",
+      "//chrome/test:test_support",
+      "//chrome/test:test_support_ui",
+      "//components/autofill/content/browser:test_support",
+      "//components/autofill/core/browser:test_support",
+      "//components/autofill/core/common:features",
+      "//components/autofill/core/common:test_support",
+      "//components/feature_engagement/public",
+      "//components/feature_engagement/test:test_support",
+      "//components/keyed_service/content",
+      "//components/prefs:test_support",
+      "//components/sync:test_support",
+      "//content/public/browser",
+      "//content/test:test_support",
+      "//net:test_support",
+      "//testing/gmock",
+      "//testing/gtest",
+      "//third_party/blink/public/common",
+      "//ui/base",
+      "//ui/compositor",
+      "//ui/gfx/geometry",
+      "//ui/views",
+      "//url",
+    ]
+
+    sources = [
+      "autofill_context_menu_manager_interactive_uitest.cc",
+      "autofill_popup_controller_interactive_uitest.cc",
+      "chrome_autofill_client_interactive_uitest.cc",
+    ]
+
+    if (toolkit_views) {
+      sources += [
+        "address_bubbles_controller_interactive_uitest.cc",
+        "delete_address_profile_dialog_controller_impl_interactive_uitest.cc",
+        "edit_address_profile_dialog_controller_impl_interactive_uitest.cc",
+      ]
+    }
+  }
+}
+
+source_set("test_support_unit") {
+  testonly = true
+
+  sources = [
+    "autofill_suggestion_controller_test_base.cc",
+    "autofill_suggestion_controller_test_base.h",
+    "mock_autofill_popup_view.cc",
+    "mock_autofill_popup_view.h",
+  ]
+
+  public_deps = [
+    ":autofill",
+    ":test_support",
+    "//base",
+    "//chrome/browser/autofill",
+    "//chrome/browser/ui",
+    "//chrome/test:test_support",
+    "//components/autofill/content/browser:test_support",
+    "//components/autofill/core/common:test_support",
+    "//testing/gmock",
+    "//testing/gtest",
+  ]
+
+  if (is_android) {
+    sources += [
+      "mock_autofill_keyboard_accessory_view.cc",
+      "mock_autofill_keyboard_accessory_view.h",
+      "test_autofill_keyboard_accessory_controller_autofill_client.h",
+    ]
+    public_deps += [
+      "//chrome/browser/keyboard_accessory/test_utils/android",
+      "//chrome/browser/password_manager/android/access_loss:test_support",
+    ]
+  } else {
+    sources += [ "test_autofill_popup_controller_autofill_client.h" ]
+  }
+}
+
+if (is_chromeos_lacros) {
+  source_set("lacros_chrome_browsertests") {
+    testonly = true
+
+    defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ]
+
+    sources = [ "autofill_context_menu_manager_lacros_browsertest.cc" ]
+
+    deps = [
+      ":autofill",
+      "//base/test:test_support",
+      "//chrome/app:command_ids",
+      "//chrome/browser/ui",
+      "//chrome/common:constants",
+      "//chrome/test:test_support",
+      "//chrome/test:test_support_ui",
+      "//components/autofill/core/browser:test_support",
+      "//components/autofill/core/common:features",
+      "//components/prefs:test_support",
+      "//content/test:test_support",
+    ]
+  }
+}
+
+if (!is_android) {
+  source_set("browser_tests") {
+    testonly = true
+
+    defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ]
+
+    sources = []
+
+    deps = [
+      ":autofill",
+      "//base",
+      "//base/test:test_support",
+      "//chrome/app:command_ids",
+      "//chrome/app:generated_resources",
+      "//chrome/browser",
+      "//chrome/browser/autofill",
+      "//chrome/browser/autofill:test_support",
+      "//chrome/browser/sync",
+      "//chrome/browser/ui",
+      "//chrome/test:test_support",
+      "//chrome/test:test_support_ui",
+      "//components/autofill/content/browser:test_support",
+      "//components/autofill/core/browser:test_support",
+      "//components/autofill/core/common",
+      "//components/autofill_prediction_improvements/core/browser",
+      "//components/keyed_service/content",
+      "//components/keyed_service/core",
+      "//components/password_manager/content/browser",
+      "//components/password_manager/core/browser",
+      "//components/password_manager/core/browser:password_form",
+      "//components/password_manager/core/browser:test_support",
+      "//components/password_manager/core/browser/features:password_features",
+      "//components/password_manager/core/browser/password_store:password_store_interface",
+      "//components/password_manager/core/browser/password_store:test_support",
+      "//components/password_manager/core/common",
+      "//components/plus_addresses:blocklist_data",
+      "//components/plus_addresses:plus_address_blocklist_proto",
+      "//components/plus_addresses:test_support",
+      "//components/signin/public/base",
+      "//components/signin/public/identity_manager:test_support",
+      "//components/strings:components_strings",
+      "//components/sync:test_support",
+      "//components/sync/base:features",
+      "//components/user_manager",
+      "//components/variations/service",
+      "//content/public/browser",
+      "//content/test:test_support",
+      "//testing/gtest",
+      "//ui/base",
+      "//url",
+    ]
+
+    if (!is_chromeos_lacros) {
+      sources += [ "autofill_context_menu_manager_browsertest.cc" ]
+    }
+
+    if (enable_dice_support) {
+      sources += [ "autofill_signin_promo_tab_helper_browsertest.cc" ]
+    }
+  }
+}
diff --git a/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl.h b/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl.h
index ac40710a..571d4fcc 100644
--- a/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl.h
+++ b/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl.h
@@ -10,7 +10,6 @@
 #include <vector>
 
 #include "base/memory/weak_ptr.h"
-#include "chrome/browser/password_manager/android/access_loss/password_access_loss_warning_bridge.h"
 #include "chrome/browser/ui/autofill/autofill_keyboard_accessory_controller.h"
 #include "chrome/browser/ui/autofill/autofill_popup_hide_helper.h"
 #include "chrome/browser/ui/autofill/next_idle_barrier.h"
@@ -27,6 +26,7 @@
 }  // namespace content
 
 class Profile;
+class PasswordAccessLossWarningBridge;
 
 namespace autofill {
 
diff --git a/chrome/browser/ui/autofill/autofill_prediction_improvements/save_autofill_prediction_improvements_controller.h b/chrome/browser/ui/autofill/autofill_prediction_improvements/save_autofill_prediction_improvements_controller.h
index 2e44ee5..d640710 100644
--- a/chrome/browser/ui/autofill/autofill_prediction_improvements/save_autofill_prediction_improvements_controller.h
+++ b/chrome/browser/ui/autofill/autofill_prediction_improvements/save_autofill_prediction_improvements_controller.h
@@ -5,6 +5,8 @@
 #ifndef CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_PREDICTION_IMPROVEMENTS_SAVE_AUTOFILL_PREDICTION_IMPROVEMENTS_CONTROLLER_H_
 #define CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_PREDICTION_IMPROVEMENTS_SAVE_AUTOFILL_PREDICTION_IMPROVEMENTS_CONTROLLER_H_
 
+#include <vector>
+
 #include "base/memory/weak_ptr.h"
 #include "content/public/browser/web_contents.h"
 
@@ -28,6 +30,13 @@
     // The bubble lost focus and was closed.
     kLostFocus,
   };
+  struct PredictionImprovement {
+    // The prediction key displayed to the user and also used to identify it.
+    std::u16string key;
+    // The value of the prediction.
+    std::u16string value;
+  };
+
   SaveAutofillPredictionImprovementsController() = default;
   SaveAutofillPredictionImprovementsController(
       const SaveAutofillPredictionImprovementsController&) = delete;
@@ -40,9 +49,16 @@
 
   // Shows a save improved predictions bubble which the user can accept or
   // decline.
-  virtual void OfferSave() = 0;
+  virtual void OfferSave(
+      std::vector<PredictionImprovement> prediction_improvements) = 0;
+
   // Called when the user accepts to save prediction improvements.
   virtual void OnSaveButtonClicked() = 0;
+
+  // Returns the prediction improvements to be displayed in the UI.
+  virtual const std::vector<PredictionImprovement>& GetPredictionImprovements()
+      const = 0;
+
   // Called when the prediction improvements bubble is closed.
   virtual void OnBubbleClosed(
       PredictionImprovementsBubbleClosedReason closed_reason) = 0;
diff --git a/chrome/browser/ui/autofill/autofill_prediction_improvements/save_autofill_prediction_improvements_controller_impl.cc b/chrome/browser/ui/autofill/autofill_prediction_improvements/save_autofill_prediction_improvements_controller_impl.cc
index 5c1f1ad..79987a0 100644
--- a/chrome/browser/ui/autofill/autofill_prediction_improvements/save_autofill_prediction_improvements_controller_impl.cc
+++ b/chrome/browser/ui/autofill/autofill_prediction_improvements/save_autofill_prediction_improvements_controller_impl.cc
@@ -40,12 +40,13 @@
       web_contents);
 }
 
-void SaveAutofillPredictionImprovementsControllerImpl::OfferSave() {
+void SaveAutofillPredictionImprovementsControllerImpl::OfferSave(
+    std::vector<PredictionImprovement> new_prediction_improvements) {
   // Don't show the bubble if it's already visible.
   if (bubble_view()) {
     return;
   }
-
+  prediction_improvements_ = std::move(new_prediction_improvements);
   DoShowBubble();
 }
 
@@ -78,6 +79,13 @@
   return weak_ptr_factory_.GetWeakPtr();
 }
 
+const std::vector<
+    SaveAutofillPredictionImprovementsController::PredictionImprovement>&
+SaveAutofillPredictionImprovementsControllerImpl::GetPredictionImprovements()
+    const {
+  return prediction_improvements_;
+}
+
 WEB_CONTENTS_USER_DATA_KEY_IMPL(
     SaveAutofillPredictionImprovementsControllerImpl);
 
diff --git a/chrome/browser/ui/autofill/autofill_prediction_improvements/save_autofill_prediction_improvements_controller_impl.h b/chrome/browser/ui/autofill/autofill_prediction_improvements/save_autofill_prediction_improvements_controller_impl.h
index 3e10722..b3623b6 100644
--- a/chrome/browser/ui/autofill/autofill_prediction_improvements/save_autofill_prediction_improvements_controller_impl.h
+++ b/chrome/browser/ui/autofill/autofill_prediction_improvements/save_autofill_prediction_improvements_controller_impl.h
@@ -5,6 +5,8 @@
 #ifndef CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_PREDICTION_IMPROVEMENTS_SAVE_AUTOFILL_PREDICTION_IMPROVEMENTS_CONTROLLER_IMPL_H_
 #define CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_PREDICTION_IMPROVEMENTS_SAVE_AUTOFILL_PREDICTION_IMPROVEMENTS_CONTROLLER_IMPL_H_
 
+#include <vector>
+
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/ui/autofill/autofill_bubble_controller_base.h"
 #include "chrome/browser/ui/autofill/autofill_prediction_improvements/save_autofill_prediction_improvements_controller.h"
@@ -28,11 +30,14 @@
   ~SaveAutofillPredictionImprovementsControllerImpl() override;
 
   // SaveAutofillPredictionImprovementsController:
-  void OfferSave() override;
+  void OfferSave(
+      std::vector<PredictionImprovement> prediction_improvements) override;
   void OnSaveButtonClicked() override;
+  const std::vector<PredictionImprovement>& GetPredictionImprovements()
+      const override;
   void OnBubbleClosed(
-      SaveAutofillPredictionImprovementsController::
-          PredictionImprovementsBubbleClosedReason closed_reason) override;
+
+      PredictionImprovementsBubbleClosedReason closed_reason) override;
   base::WeakPtr<SaveAutofillPredictionImprovementsController> GetWeakPtr()
       override;
 
@@ -51,6 +56,10 @@
 
   void ShowBubble();
 
+  // A list of prediction improvements keys and values that the user can accept
+  // to save.
+  std::vector<PredictionImprovement> prediction_improvements_;
+
   // Weak pointer factory for this save prediction improvements bubble
   // controller.
   base::WeakPtrFactory<SaveAutofillPredictionImprovementsControllerImpl>
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.cc b/chrome/browser/ui/autofill/chrome_autofill_client.cc
index 318441f..32793ab8 100644
--- a/chrome/browser/ui/autofill/chrome_autofill_client.cc
+++ b/chrome/browser/ui/autofill/chrome_autofill_client.cc
@@ -43,6 +43,7 @@
 #include "chrome/browser/translate/chrome_translate_client.h"
 #include "chrome/browser/ui/autofill/address_bubbles_controller.h"
 #include "chrome/browser/ui/autofill/autofill_field_promo_controller_impl.h"
+#include "chrome/browser/ui/autofill/autofill_prediction_improvements/save_autofill_prediction_improvements_controller.h"
 #include "chrome/browser/ui/autofill/autofill_suggestion_controller.h"
 #include "chrome/browser/ui/autofill/delete_address_profile_dialog_controller_impl.h"
 #include "chrome/browser/ui/autofill/edit_address_profile_dialog_controller_impl.h"
@@ -128,6 +129,7 @@
 #include "chrome/browser/android/tab_android.h"
 #include "chrome/browser/flags/android/chrome_feature_list.h"
 #include "chrome/browser/ui/android/autofill/autofill_accessibility_utils.h"
+#include "chrome/browser/ui/android/autofill/save_update_address_profile_flow_manager.h"
 #include "chrome/browser/ui/autofill/payments/autofill_snackbar_controller_impl.h"
 #include "chrome/browser/ui/autofill/payments/offer_notification_controller_android.h"
 #include "components/autofill/core/browser/autofill_prediction_improvements_delegate.h"
@@ -549,7 +551,7 @@
     bool is_migration_to_account,
     AddressProfileSavePromptCallback callback) {
 #if BUILDFLAG(IS_ANDROID)
-  save_update_address_profile_flow_manager_.OfferSave(
+  save_update_address_profile_flow_manager_->OfferSave(
       web_contents(), profile, original_profile, is_migration_to_account,
       std::move(callback));
 #else
@@ -792,7 +794,7 @@
   if (SaveAutofillPredictionImprovementsController* controller =
           SaveAutofillPredictionImprovementsController::GetOrCreate(
               web_contents())) {
-    controller->OfferSave();
+    controller->OfferSave({});
   }
 #endif  // !BUILDFLAG(IS_ANDROID)
 }
@@ -812,6 +814,8 @@
   GetStrikeDatabase();
 
 #if BUILDFLAG(IS_ANDROID)
+  save_update_address_profile_flow_manager_ =
+      std::make_unique<SaveUpdateAddressProfileFlowManager>();
   fast_checkout_client_ = std::make_unique<FastCheckoutClientImpl>(this);
 #endif
 }
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.h b/chrome/browser/ui/autofill/chrome_autofill_client.h
index dd9658de..4c217c6 100644
--- a/chrome/browser/ui/autofill/chrome_autofill_client.h
+++ b/chrome/browser/ui/autofill/chrome_autofill_client.h
@@ -20,7 +20,6 @@
 #include "chrome/browser/ui/autofill/autofill_field_promo_controller.h"
 #include "chrome/browser/ui/autofill/autofill_suggestion_controller.h"
 #include "chrome/browser/ui/autofill/payments/chrome_payments_autofill_client.h"
-#include "chrome/browser/ui/hats/hats_service_desktop.h"
 #include "components/autofill/content/browser/content_autofill_client.h"
 #include "components/autofill/content/browser/content_autofill_driver.h"
 #include "components/autofill/core/browser/autofill_ablation_study.h"
@@ -36,7 +35,6 @@
 #include "content/public/browser/web_contents_observer.h"
 
 #if BUILDFLAG(IS_ANDROID)
-#include "chrome/browser/ui/android/autofill/save_update_address_profile_flow_manager.h"
 #include "components/autofill/core/browser/ui/fast_checkout_client.h"
 #else
 #include "chrome/browser/ui/autofill/payments/manage_migration_ui_controller.h"
@@ -44,6 +42,13 @@
 
 namespace autofill {
 
+#if BUILDFLAG(IS_ANDROID)
+// TODO(crbug.com/364089352): When //c/b/ui/android/autofill gets modularized,
+// //c/b/ui/autofill/ can depend directly on it. Now, forward declare the
+// SaveUpdateAddressProfileFlowManager.
+class SaveUpdateAddressProfileFlowManager;
+#endif
+
 class AutofillOptimizationGuide;
 class FormFieldData;
 enum class SuggestionType;
@@ -228,7 +233,8 @@
   // the test machine, that may normally cause the popup to be hidden
   bool keep_popup_open_for_testing_ = false;
 #if BUILDFLAG(IS_ANDROID)
-  SaveUpdateAddressProfileFlowManager save_update_address_profile_flow_manager_;
+  std::unique_ptr<SaveUpdateAddressProfileFlowManager>
+      save_update_address_profile_flow_manager_;
   std::unique_ptr<FastCheckoutClient> fast_checkout_client_;
 #endif
   std::unique_ptr<AutofillFieldPromoController>
diff --git a/chrome/browser/ui/autofill/payments/BUILD.gn b/chrome/browser/ui/autofill/payments/BUILD.gn
index e79494f..6b61b439 100644
--- a/chrome/browser/ui/autofill/payments/BUILD.gn
+++ b/chrome/browser/ui/autofill/payments/BUILD.gn
@@ -55,6 +55,7 @@
     ]
     public_deps += [
       "//chrome/browser/profiles:profile",
+      "//chrome/browser/ui:browser_list",
       "//components/autofill/core/browser:legal_message_line",
       "//components/signin/public/identity_manager",
       "//ui/gfx",
@@ -104,6 +105,7 @@
     "//chrome/app:generated_resources",
     "//chrome/app:generated_resources_grit",
     "//chrome/browser/autofill",
+    "//chrome/browser/ui/autofill",
     "//chrome/browser/ui/page_action:icon_type",
     "//components/autofill/content/browser",
     "//components/strings:components_strings_grit",
@@ -179,6 +181,7 @@
     public_deps = [
       ":payments",
       "//chrome/browser/ui",
+      "//chrome/browser/ui/autofill",
       "//components/autofill/core/browser",
       "//components/prefs",
       "//content/public/browser",
@@ -236,6 +239,8 @@
     "//base/test:test_support",
     "//chrome/browser",
     "//chrome/browser/ui",
+    "//chrome/browser/ui/autofill",
+    "//chrome/browser/ui/autofill:test_support",
     "//chrome/test:test_support",
     "//components/autofill/core/browser",
     "//components/autofill/core/browser:test_support",
diff --git a/chrome/browser/ui/autofill/payments/chrome_payments_autofill_client_unittest.cc b/chrome/browser/ui/autofill/payments/chrome_payments_autofill_client_unittest.cc
index 863979c..6589b579 100644
--- a/chrome/browser/ui/autofill/payments/chrome_payments_autofill_client_unittest.cc
+++ b/chrome/browser/ui/autofill/payments/chrome_payments_autofill_client_unittest.cc
@@ -8,6 +8,7 @@
 
 #include "base/test/mock_callback.h"
 #include "base/test/scoped_feature_list.h"
+#include "build/branding_buildflags.h"
 #include "chrome/browser/ui/autofill/chrome_autofill_client.h"
 #include "chrome/browser/ui/autofill/payments/chrome_payments_autofill_client.h"
 #include "chrome/browser/ui/autofill/payments/virtual_card_enroll_bubble_controller_impl.h"
diff --git a/chrome/browser/ui/autofill/payments/desktop_payments_window_manager.cc b/chrome/browser/ui/autofill/payments/desktop_payments_window_manager.cc
index e6ac346..8290647 100644
--- a/chrome/browser/ui/autofill/payments/desktop_payments_window_manager.cc
+++ b/chrome/browser/ui/autofill/payments/desktop_payments_window_manager.cc
@@ -11,6 +11,7 @@
 #include "base/types/expected.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/autofill/payments/view_factory.h"
+#include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_navigator.h"
 #include "chrome/browser/ui/browser_navigator_params.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
diff --git a/chrome/browser/ui/blocked_content/BUILD.gn b/chrome/browser/ui/blocked_content/BUILD.gn
index 518093df..15d3098 100644
--- a/chrome/browser/ui/blocked_content/BUILD.gn
+++ b/chrome/browser/ui/blocked_content/BUILD.gn
@@ -58,6 +58,7 @@
     ]
 
     deps += [
+      "//chrome/browser/ui:browser_list",
       "//components/guest_view/browser",
       "//extensions/common:common_constants",
     ]
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index 739be98a9..6760b85 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -264,7 +264,6 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "ash/constants/ash_features.h"
 #include "chrome/browser/ash/guest_os/guest_os_terminal.h"
-#include "chrome/browser/ash/url_handler/url_handler.h"
 #include "chrome/browser/ui/settings_window_manager_chromeos.h"
 #include "components/session_manager/core/session_manager.h"
 #endif
@@ -1789,13 +1788,6 @@
                                   std::move(navigation_handle_callback));
   }
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-  // Try to intercept the request and open the URL with Lacros.
-  if (ash::TryOpenUrl(params.url, params.disposition)) {
-    return nullptr;
-  }
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
-
   NavigateParams nav_params(this, params.url, params.transition);
   nav_params.FillNavigateParamsFromOpenURLParams(params);
   nav_params.source_contents = source;
diff --git a/chrome/browser/ui/browser_list.h b/chrome/browser/ui/browser_list.h
index bb51a408..b571223 100644
--- a/chrome/browser/ui/browser_list.h
+++ b/chrome/browser/ui/browser_list.h
@@ -18,12 +18,13 @@
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "build/build_config.h"
-#include "chrome/browser/ui/browser.h"
 
 #if BUILDFLAG(IS_ANDROID)
 #error This file should only be included on desktop.
 #endif
 
+enum class BrowserClosingStatus;
+
 class Browser;
 class Profile;
 
diff --git a/chrome/browser/ui/device_signals_consent/BUILD.gn b/chrome/browser/ui/device_signals_consent/BUILD.gn
new file mode 100644
index 0000000..f7625ee
--- /dev/null
+++ b/chrome/browser/ui/device_signals_consent/BUILD.gn
@@ -0,0 +1,23 @@
+# Copyright 2024 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+assert(is_win || is_mac || is_linux || is_chromeos)
+
+source_set("device_signals_consent") {
+  sources = [ "consent_requester.h" ]
+  deps = [ "//base" ]
+}
+
+source_set("test_support") {
+  testonly = true
+  sources = [
+    "mock_consent_requester.cc",
+    "mock_consent_requester.h",
+  ]
+  deps = [
+    ":device_signals_consent",
+    "//components/device_signals/core/browser",
+    "//testing/gmock:gmock",
+  ]
+}
diff --git a/chrome/browser/ui/device_signals_consent/consent_requester.h b/chrome/browser/ui/device_signals_consent/consent_requester.h
index abb2adf..5b2b522 100644
--- a/chrome/browser/ui/device_signals_consent/consent_requester.h
+++ b/chrome/browser/ui/device_signals_consent/consent_requester.h
@@ -15,6 +15,12 @@
 
 // Class that requests the collection of user consent for
 // sharing device signals.
+//
+// TODO(crbug.com/365680823): This interface can be eliminated, in favor using
+// //c/b/ui/views/device_signals_consent/consent_dialog_coordinator.h
+// altogether. It's an abstract-base-class that serves no purpose other than to
+// satisfy a historical constraint (no referencing views from outside of views)
+// which has since been deleted.
 class ConsentRequester {
  public:
   virtual ~ConsentRequester() = default;
diff --git a/chrome/browser/ui/digital_credentials/BUILD.gn b/chrome/browser/ui/digital_credentials/BUILD.gn
new file mode 100644
index 0000000..03ce20b6
--- /dev/null
+++ b/chrome/browser/ui/digital_credentials/BUILD.gn
@@ -0,0 +1,22 @@
+# Copyright 2024 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+assert(is_win || is_mac || is_linux || is_chromeos || is_android)
+
+source_set("digital_credentials") {
+  sources = [ "digital_identity_safety_interstitial_controller.h" ]
+  deps = []
+  public_deps = [ "//content/public/browser" ]
+
+  if (is_android) {
+    sources += [
+      "digital_identity_safety_interstitial_bridge_android.cc",
+      "digital_identity_safety_interstitial_bridge_android.h",
+    ]
+    deps += [
+      "//chrome/browser/ui/android/digital_credentials:jni_headers",
+      "//ui/android",
+    ]
+  }
+}
diff --git a/chrome/browser/ui/lens/BUILD.gn b/chrome/browser/ui/lens/BUILD.gn
index 85bf0fc..e6577b7 100644
--- a/chrome/browser/ui/lens/BUILD.gn
+++ b/chrome/browser/ui/lens/BUILD.gn
@@ -100,6 +100,7 @@
     "//chrome/browser/ui/views/side_panel",
     "//chrome/browser/ui/views/toolbar",
     "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/searchbox",
     "//chrome/browser/ui/webui/util",
     "//chrome/common",
diff --git a/chrome/browser/ui/omnibox/BUILD.gn b/chrome/browser/ui/omnibox/BUILD.gn
index 88a660f..948bf95 100644
--- a/chrome/browser/ui/omnibox/BUILD.gn
+++ b/chrome/browser/ui/omnibox/BUILD.gn
@@ -79,6 +79,7 @@
       "//chrome/browser/favicon",
       "//chrome/browser/profiles:profile",
       "//chrome/browser/search_engines",
+      "//chrome/browser/ui:browser_list",
       "//components/bookmarks/browser",
       "//components/favicon/content",
       "//components/favicon/core",
diff --git a/chrome/browser/ui/prefs/prefs_tab_helper.cc b/chrome/browser/ui/prefs/prefs_tab_helper.cc
index 2435933..e06062e 100644
--- a/chrome/browser/ui/prefs/prefs_tab_helper.cc
+++ b/chrome/browser/ui/prefs/prefs_tab_helper.cc
@@ -67,7 +67,12 @@
 #endif
 
 #if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
+// If a font name in prefs default values starts with a comma, consider it's a
+// comma-separated font list and resolve it to the first available font.
+#define PREFS_FONT_LIST 1
 #include "ui/gfx/font_list.h"
+#else
+#define PREFS_FONT_LIST 0
 #endif
 
 using blink::web_pref::WebPreferences;
@@ -117,12 +122,6 @@
 }
 #endif  // !BUILDFLAG(IS_ANDROID)
 
-#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
-// Resolves the comma-separated font list to the first available font in the
-// default value. crbug.com/41323186.
-BASE_FEATURE(kPrefsFontList, "PrefsFontList", base::FEATURE_ENABLED_BY_DEFAULT);
-#endif
-
 #if BUILDFLAG(IS_WIN)
 // On Windows with antialiasing we want to use an alternate fixed font like
 // Consolas, which looks much better than Courier New.
@@ -432,16 +431,15 @@
     // not be really critical after all.
     if (browser_script != pref_script) {
       std::string value = l10n_util::GetStringUTF8(pref.resource_id);
-#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
-      if (value.starts_with(',') &&
-          base::FeatureList::IsEnabled(kPrefsFontList)) {
+#if PREFS_FONT_LIST
+      if (value.starts_with(',')) {
         value = gfx::FontList::FirstAvailableOrFirst(value);
       }
-#else
+#else   // !PREFS_FONT_LIST
       DCHECK(!value.starts_with(','))
           << "This platform doesn't support default font lists. "
           << pref.pref_name << "=" << value;
-#endif
+#endif  // PREFS_FONT_LIST
       registry->RegisterStringPref(pref.pref_name, value);
       fonts_with_defaults.insert(pref.pref_name);
     }
diff --git a/chrome/browser/ui/singleton_tabs.cc b/chrome/browser/ui/singleton_tabs.cc
index 2a07adf1..d2705747 100644
--- a/chrome/browser/ui/singleton_tabs.cc
+++ b/chrome/browser/ui/singleton_tabs.cc
@@ -17,12 +17,6 @@
 #include "content/public/browser/browser_url_handler.h"
 #include "content/public/browser/web_contents.h"
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-#include "ash/constants/ash_switches.h"
-#include "chrome/browser/ash/crosapi/browser_util.h"
-#include "chrome/browser/ash/url_handler/url_handler.h"
-#endif
-
 namespace {
 
 // Returns true if two URLs are equal after taking |replacements| into account.
@@ -38,14 +32,6 @@
 }  // namespace
 
 void ShowSingletonTab(Profile* profile, const GURL& url) {
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-  if (!crosapi::browser_util::IsAshWebBrowserEnabled()) {
-    ash::TryOpenUrl(url, WindowOpenDisposition::SINGLETON_TAB,
-                    NavigateParams::RESPECT,
-                    ash::ChromeSchemeSemantics::kLacros);
-    return;
-  }
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
   chrome::ScopedTabbedBrowserDisplayer displayer(profile);
   NavigateParams params(
       GetSingletonTabNavigateParams(displayer.browser(), url));
@@ -53,14 +39,6 @@
 }
 
 void ShowSingletonTab(Browser* browser, const GURL& url) {
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-  if (!crosapi::browser_util::IsAshWebBrowserEnabled()) {
-    ash::TryOpenUrl(url, WindowOpenDisposition::SINGLETON_TAB,
-                    NavigateParams::RESPECT,
-                    ash::ChromeSchemeSemantics::kLacros);
-    return;
-  }
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
   NavigateParams params(GetSingletonTabNavigateParams(browser, url));
   Navigate(&params);
 }
@@ -69,13 +47,6 @@
     Profile* profile,
     const GURL& url,
     NavigateParams::PathBehavior path_behavior) {
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-  if (!crosapi::browser_util::IsAshWebBrowserEnabled()) {
-    ash::TryOpenUrl(url, WindowOpenDisposition::SINGLETON_TAB, path_behavior,
-                    ash::ChromeSchemeSemantics::kLacros);
-    return;
-  }
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
   chrome::ScopedTabbedBrowserDisplayer displayer(profile);
   NavigateParams params(
       GetSingletonTabNavigateParams(displayer.browser(), url));
@@ -87,13 +58,6 @@
     Browser* browser,
     const GURL& url,
     NavigateParams::PathBehavior path_behavior) {
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-  if (!crosapi::browser_util::IsAshWebBrowserEnabled()) {
-    ash::TryOpenUrl(url, WindowOpenDisposition::SINGLETON_TAB, path_behavior,
-                    ash::ChromeSchemeSemantics::kLacros);
-    return;
-  }
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
   NavigateParams params(GetSingletonTabNavigateParams(browser, url));
   params.path_behavior = path_behavior;
   ShowSingletonTabOverwritingNTP(&params);
@@ -101,12 +65,6 @@
 
 void ShowSingletonTabOverwritingNTP(NavigateParams* params) {
   DCHECK_EQ(params->disposition, WindowOpenDisposition::SINGLETON_TAB);
-
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-  CHECK(crosapi::browser_util::IsAshWebBrowserEnabled() ||
-        ash::switches::IsAshDebugBrowserEnabled());
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
-
   content::WebContents* contents =
       params->browser->tab_strip_model()->GetActiveWebContents();
   if (contents) {
diff --git a/chrome/browser/ui/tabs/tab_strip_model_observer.cc b/chrome/browser/ui/tabs/tab_strip_model_observer.cc
index 8b76474..dc6057c 100644
--- a/chrome/browser/ui/tabs/tab_strip_model_observer.cc
+++ b/chrome/browser/ui/tabs/tab_strip_model_observer.cc
@@ -7,7 +7,6 @@
 #include <utility>
 
 #include "base/check_op.h"
-#include "base/memory/raw_ptr.h"
 #include "base/trace_event/trace_event.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "content/public/browser/web_contents.h"
diff --git a/chrome/browser/ui/ui_features.cc b/chrome/browser/ui/ui_features.cc
index 38f3b78..a7a7a9cb 100644
--- a/chrome/browser/ui/ui_features.cc
+++ b/chrome/browser/ui/ui_features.cc
@@ -425,12 +425,6 @@
              "EnterpriseUpdatedProfileCreationScreen",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
-// This enables enables persistence of a WebContents in a 1-to-1 association
-// with the current Profile for WebUI bubbles. See https://crbug.com/1177048.
-BASE_FEATURE(kWebUIBubblePerProfilePersistence,
-             "WebUIBubblePerProfilePersistence",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-
 // Enables a web-based tab strip. See https://crbug.com/989131. Note this
 // feature only works when the ENABLE_WEBUI_TAB_STRIP buildflag is enabled.
 BASE_FEATURE(kWebUITabStrip,
diff --git a/chrome/browser/ui/ui_features.h b/chrome/browser/ui/ui_features.h
index 510c85d8..5a19fd8a 100644
--- a/chrome/browser/ui/ui_features.h
+++ b/chrome/browser/ui/ui_features.h
@@ -267,8 +267,6 @@
 BASE_DECLARE_FEATURE(kManagementToolbarButton);
 BASE_DECLARE_FEATURE(kManagementToolbarButtonForTrustedManagementSources);
 
-BASE_DECLARE_FEATURE(kWebUIBubblePerProfilePersistence);
-
 BASE_DECLARE_FEATURE(kWebUITabStrip);
 
 // Controls whether the context menu is shown on a touch press or a touch
diff --git a/chrome/browser/ui/views/autofill/autofill_prediction_improvements/save_autofill_prediction_improvements_bubble_view.cc b/chrome/browser/ui/views/autofill/autofill_prediction_improvements/save_autofill_prediction_improvements_bubble_view.cc
index 58a2289..374c5bb8 100644
--- a/chrome/browser/ui/views/autofill/autofill_prediction_improvements/save_autofill_prediction_improvements_bubble_view.cc
+++ b/chrome/browser/ui/views/autofill/autofill_prediction_improvements/save_autofill_prediction_improvements_bubble_view.cc
@@ -5,15 +5,42 @@
 #include "chrome/browser/ui/views/autofill/autofill_prediction_improvements/save_autofill_prediction_improvements_bubble_view.h"
 
 #include "chrome/browser/ui/autofill/autofill_prediction_improvements/save_autofill_prediction_improvements_controller.h"
+#include "chrome/browser/ui/views/accessibility/theme_tracking_non_accessible_image_view.h"
 #include "chrome/browser/ui/views/chrome_layout_provider.h"
+#include "chrome/grit/theme_resources.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
 #include "ui/base/ui_base_types.h"
+#include "ui/gfx/geometry/rect.h"
 #include "ui/views/accessibility/view_accessibility.h"
 #include "ui/views/controls/label.h"
 
 namespace autofill {
 
 namespace {
+
+constexpr int kHeaderImageWidthAndHeight = 36;
+constexpr int kBubbleWidth = 320;
+constexpr gfx::Size kHeaderImageSize(kHeaderImageWidthAndHeight,
+                                     kHeaderImageWidthAndHeight);
+
+std::unique_ptr<views::View> BuildPredictedValueRow(
+    const std::u16string key,
+    const std::u16string value) {
+  return views::Builder<views::BoxLayoutView>()
+      .SetOrientation(views::BoxLayout::Orientation::kVertical)
+      .SetMainAxisAlignment(views::LayoutAlignment::kStart)
+      .AddChildren(
+          views::Builder<views::Label>()
+              .SetText(key)
+              .SetTextStyle(views::style::STYLE_BODY_4)
+              .SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT),
+          views::Builder<views::Label>()
+              .SetText(value)
+              .SetTextStyle(views::style::STYLE_BODY_4_BOLD)
+              .SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT))
+      .Build();
+}
+
 SaveAutofillPredictionImprovementsController::
     PredictionImprovementsBubbleClosedReason
     GetPredictionImprovementsBubbleClosedReasonFromWidget(
@@ -52,18 +79,41 @@
         SaveAutofillPredictionImprovementsController* controller)
     : AutofillLocationBarBubble(anchor_view, web_contents),
       controller_(controller->GetWeakPtr()) {
-  set_fixed_width(views::LayoutProvider::Get()->GetDistanceMetric(
-      views::DISTANCE_BUBBLE_PREFERRED_WIDTH));
+  set_fixed_width(kBubbleWidth);
   SetLayoutManager(std::make_unique<views::BoxLayout>(
       views::BoxLayout::Orientation::kVertical));
   set_margins(ChromeLayoutProvider::Get()->GetDialogInsetsForContentType(
       views::DialogContentType::kText, views::DialogContentType::kText));
-  auto description = std::make_unique<views::Label>(
-      u"Description", views::style::CONTEXT_DIALOG_BODY_TEXT,
-      views::style::STYLE_SECONDARY);
-  AddChildView(std::move(description));
+
+  const int kVerficalSpacing = ChromeLayoutProvider::Get()->GetDistanceMetric(
+      DISTANCE_CONTROL_LIST_VERTICAL);
+
+  auto* improved_predicted_values_container =
+      AddChildView(views::Builder<views::BoxLayoutView>()
+                       .SetOrientation(views::BoxLayout::Orientation::kVertical)
+                       .SetBetweenChildSpacing(kVerficalSpacing)
+                       .SetCrossAxisAlignment(views::LayoutAlignment::kStart)
+                       .Build());
+
+  for (const SaveAutofillPredictionImprovementsController::
+           PredictionImprovement& prediction_improvement :
+       controller_->GetPredictionImprovements()) {
+    improved_predicted_values_container->AddChildView(BuildPredictedValueRow(
+        prediction_improvement.key, prediction_improvement.value));
+  }
+
+  // TODO(crbug.com/362227379): Add this string to a string.grpd file.
+  DialogDelegate::SetButtonLabel(ui::mojom::DialogButton::kCancel,
+                                 u"No Thanks");
+  SetAcceptCallback(base::BindOnce(
+      &SaveAutofillPredictionImprovementsBubbleView::OnDialogAccepted,
+      base::Unretained(this)));
+  SetShowCloseButton(true);
 }
 
+SaveAutofillPredictionImprovementsBubbleView::
+    ~SaveAutofillPredictionImprovementsBubbleView() = default;
+
 void SaveAutofillPredictionImprovementsBubbleView::Hide() {
   CloseBubble();
   if (controller_) {
@@ -74,8 +124,35 @@
 }
 
 void SaveAutofillPredictionImprovementsBubbleView::AddedToWidget() {
-  GetBubbleFrameView()->SetTitleView(
-      std::make_unique<views::Label>(u"Prediction improvements"));
+  const int kHorizontalSpacing = ChromeLayoutProvider::Get()->GetDistanceMetric(
+      DISTANCE_RELATED_LABEL_HORIZONTAL_LIST);
+  auto header_container =
+      views::Builder<views::BoxLayoutView>()
+          .SetOrientation(views::BoxLayout::Orientation::kHorizontal)
+          .SetBetweenChildSpacing(kHorizontalSpacing)
+          .SetMainAxisAlignment(views::LayoutAlignment::kStart)
+          .SetCrossAxisAlignment(views::LayoutAlignment::kStretch)
+          .SetInsideBorderInsets(
+              ChromeLayoutProvider::Get()->GetDialogInsetsForContentType(
+                  views::DialogContentType::kText,
+                  views::DialogContentType::kText))
+          .Build();
+  // TODO(crbug.com/362227379): This image is currently hardcoded, align with UX
+  // on the right one.
+  auto image = std::make_unique<ThemeTrackingNonAccessibleImageView>(
+      ui::ImageModel::FromResourceId(IDR_SAVE_ADDRESS),
+      ui::ImageModel::FromResourceId(IDR_SAVE_ADDRESS_DARK),
+      base::BindRepeating(&views::BubbleDialogDelegate::GetBackgroundColor,
+                          base::Unretained(this)));
+  image->SetImageSize(kHeaderImageSize);
+  header_container->AddChildView(std::move(image));
+  header_container->AddChildView(
+      views::Builder<views::Label>()
+          .SetText(u"Save info to autofill")
+          .SetTextStyle(views::style::STYLE_HEADLINE_4_BOLD)
+          .SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT)
+          .Build());
+  GetBubbleFrameView()->SetHeaderView(std::move(header_container));
 }
 
 void SaveAutofillPredictionImprovementsBubbleView::WindowClosing() {
@@ -87,8 +164,11 @@
   controller_ = nullptr;
 }
 
-SaveAutofillPredictionImprovementsBubbleView::
-    ~SaveAutofillPredictionImprovementsBubbleView() = default;
+void SaveAutofillPredictionImprovementsBubbleView::OnDialogAccepted() {
+  if (controller_) {
+    controller_->OnSaveButtonClicked();
+  }
+}
 
 BEGIN_METADATA(SaveAutofillPredictionImprovementsBubbleView)
 END_METADATA
diff --git a/chrome/browser/ui/views/autofill/autofill_prediction_improvements/save_autofill_prediction_improvements_bubble_view.h b/chrome/browser/ui/views/autofill/autofill_prediction_improvements/save_autofill_prediction_improvements_bubble_view.h
index e7d1e1b..395a8f92 100644
--- a/chrome/browser/ui/views/autofill/autofill_prediction_improvements/save_autofill_prediction_improvements_bubble_view.h
+++ b/chrome/browser/ui/views/autofill/autofill_prediction_improvements/save_autofill_prediction_improvements_bubble_view.h
@@ -40,6 +40,7 @@
   void WindowClosing() override;
 
  private:
+  void OnDialogAccepted();
   base::WeakPtr<SaveAutofillPredictionImprovementsController> controller_;
 };
 
diff --git a/chrome/browser/ui/views/autofill/autofill_prediction_improvements/save_autofill_prediction_improvements_bubble_view_unittest.cc b/chrome/browser/ui/views/autofill/autofill_prediction_improvements/save_autofill_prediction_improvements_bubble_view_unittest.cc
new file mode 100644
index 0000000..0d87eb9
--- /dev/null
+++ b/chrome/browser/ui/views/autofill/autofill_prediction_improvements/save_autofill_prediction_improvements_bubble_view_unittest.cc
@@ -0,0 +1,126 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/views/autofill/autofill_prediction_improvements/save_autofill_prediction_improvements_bubble_view.h"
+
+#include "base/memory/raw_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "chrome/browser/ui/autofill/autofill_prediction_improvements/save_autofill_prediction_improvements_controller.h"
+#include "chrome/test/base/testing_profile.h"
+#include "chrome/test/views/chrome_views_test_base.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/test/test_renderer_host.h"
+#include "content/public/test/web_contents_tester.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// TODO(crbug.com/362227379): Consider having an interactive UI test to evaluate
+// both the controller and the view working together.
+namespace autofill {
+
+class MockSaveAutofillPredictionImprovementsController
+    : public SaveAutofillPredictionImprovementsController {
+ public:
+  MockSaveAutofillPredictionImprovementsController() = default;
+  MOCK_METHOD(void,
+              OfferSave,
+              (std::vector<PredictionImprovement>),
+              (override));
+  MOCK_METHOD(const std::vector<PredictionImprovement>&,
+              GetPredictionImprovements,
+              (),
+              (const override));
+  MOCK_METHOD(void, OnSaveButtonClicked, (), (override));
+  MOCK_METHOD(void,
+              OnBubbleClosed,
+              (PredictionImprovementsBubbleClosedReason),
+              (override));
+  base::WeakPtr<SaveAutofillPredictionImprovementsController> GetWeakPtr()
+      override {
+    return weak_ptr_factory_.GetWeakPtr();
+  }
+
+ private:
+  base::WeakPtrFactory<SaveAutofillPredictionImprovementsController>
+      weak_ptr_factory_{this};
+};
+
+class SaveAutofillPredictionImprovementsBubbleViewTest
+    : public ChromeViewsTestBase {
+ public:
+  SaveAutofillPredictionImprovementsBubbleViewTest() = default;
+  ~SaveAutofillPredictionImprovementsBubbleViewTest() override = default;
+
+  // views::ViewsTestBase:
+  void SetUp() override {
+    ChromeViewsTestBase::SetUp();
+    web_contents_ =
+        content::WebContentsTester::CreateTestWebContents(&profile_, nullptr);
+  }
+
+  void CreateViewAndShow();
+
+  void TearDown() override {
+    view_ = nullptr;
+    anchor_widget_.reset();
+    ChromeViewsTestBase::TearDown();
+  }
+
+  SaveAutofillPredictionImprovementsBubbleView* view() { return view_; }
+  MockSaveAutofillPredictionImprovementsController& mock_controller() {
+    return mock_controller_;
+  }
+
+ private:
+  content::RenderViewHostTestEnabler render_view_host_test_enabler_;
+  TestingProfile profile_;
+  std::unique_ptr<content::WebContents> web_contents_;
+  std::unique_ptr<views::Widget> anchor_widget_;
+  raw_ptr<SaveAutofillPredictionImprovementsBubbleView> view_ = nullptr;
+  testing::NiceMock<MockSaveAutofillPredictionImprovementsController>
+      mock_controller_;
+};
+
+void SaveAutofillPredictionImprovementsBubbleViewTest::CreateViewAndShow() {
+  // The bubble needs the parent as an anchor.
+  views::Widget::InitParams params =
+      CreateParams(views::Widget::InitParams::CLIENT_OWNS_WIDGET,
+                   views::Widget::InitParams::TYPE_WINDOW);
+  anchor_widget_ = std::make_unique<views::Widget>();
+  anchor_widget_->Init(std::move(params));
+  anchor_widget_->Show();
+
+  ON_CALL(mock_controller(), GetPredictionImprovements())
+      .WillByDefault(testing::ReturnRefOfCopy(
+          std::vector<SaveAutofillPredictionImprovementsController::
+                          PredictionImprovement>()));
+
+  auto view_unique =
+      std::make_unique<SaveAutofillPredictionImprovementsBubbleView>(
+          anchor_widget_->GetContentsView(), web_contents_.get(),
+          &mock_controller_);
+  view_ = view_unique.get();
+  views::BubbleDialogDelegateView::CreateBubble(std::move(view_unique))->Show();
+}
+
+TEST_F(SaveAutofillPredictionImprovementsBubbleViewTest, HasCloseButton) {
+  CreateViewAndShow();
+  EXPECT_TRUE(view()->ShouldShowCloseButton());
+}
+
+TEST_F(SaveAutofillPredictionImprovementsBubbleViewTest,
+       AcceptInvokesTheController) {
+  CreateViewAndShow();
+  EXPECT_CALL(mock_controller(), OnSaveButtonClicked);
+  view()->AcceptDialog();
+}
+
+TEST_F(SaveAutofillPredictionImprovementsBubbleViewTest,
+       CancelInvokesTheController) {
+  CreateViewAndShow();
+  EXPECT_CALL(mock_controller(), OnBubbleClosed);
+  view()->CancelDialog();
+}
+
+}  // namespace autofill
diff --git a/chrome/browser/ui/views/bubble/BUILD.gn b/chrome/browser/ui/views/bubble/BUILD.gn
index 97bc6a7..a904762 100644
--- a/chrome/browser/ui/views/bubble/BUILD.gn
+++ b/chrome/browser/ui/views/bubble/BUILD.gn
@@ -31,6 +31,7 @@
     "//chrome/browser/ui:webui_name_variants",
   ]
   deps = [
+    "//chrome/browser/ui:browser_list",
     "//chrome/browser/ui/webui/top_chrome",
     "//components/input",
   ]
diff --git a/chrome/browser/ui/views/bubble/webui_bubble_manager.h b/chrome/browser/ui/views/bubble/webui_bubble_manager.h
index 875aecf6..f62127b 100644
--- a/chrome/browser/ui/views/bubble/webui_bubble_manager.h
+++ b/chrome/browser/ui/views/bubble/webui_bubble_manager.h
@@ -16,13 +16,10 @@
 #include "base/observer_list.h"
 #include "base/scoped_observation.h"
 #include "base/time/time.h"
-#include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/ui/views/bubble/webui_bubble_dialog_view.h"
 #include "chrome/browser/ui/views/bubble/webui_bubble_manager_observer.h"
 #include "chrome/browser/ui/views/close_bubble_on_tab_activation_helper.h"
 #include "chrome/browser/ui/webui/top_chrome/webui_contents_warmup_level.h"
-#include "chrome/browser/ui/webui/top_chrome/webui_contents_wrapper_service.h"
-#include "chrome/browser/ui/webui/top_chrome/webui_contents_wrapper_service_factory.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/web_contents.h"
@@ -94,9 +91,6 @@
  protected:
   WebUIBubbleManager();
 
-  // Creates the persistent renderer process if the feature is enabled.
-  virtual void MaybeInitPersistentRenderer() = 0;
-
   virtual base::WeakPtr<WebUIBubbleDialogView> CreateWebUIBubbleDialog(
       const std::optional<gfx::Rect>& anchor,
       views::BubbleBorder::Arrow arrow) = 0;
@@ -168,7 +162,6 @@
 
  private:
   // WebUIBubbleManager:
-  void MaybeInitPersistentRenderer() override;
   base::WeakPtr<WebUIBubbleDialogView> CreateWebUIBubbleDialog(
       const std::optional<gfx::Rect>& anchor,
       views::BubbleBorder::Arrow arrow) override;
@@ -198,64 +191,21 @@
 }
 
 template <typename T>
-void WebUIBubbleManagerImpl<T>::MaybeInitPersistentRenderer() {
-  if (base::FeatureList::IsEnabled(
-          features::kWebUIBubblePerProfilePersistence)) {
-    auto* service =
-        WebUIContentsWrapperServiceFactory::GetForProfile(profile_, true);
-    if (service && !service->GetWebUIContentsWrapperFromURL(webui_url_)) {
-      service->template InitWebUIContentsWrapper<T>(webui_url_,
-                                                    task_manager_string_id_);
-    }
-  }
-}
-
-template <typename T>
 base::WeakPtr<WebUIBubbleDialogView>
 WebUIBubbleManagerImpl<T>::CreateWebUIBubbleDialog(
     const std::optional<gfx::Rect>& anchor,
     views::BubbleBorder::Arrow arrow) {
   WebUIContentsWrapper* contents_wrapper = nullptr;
 
-  // Only use per profile peristence if the flag is set and if a
-  // WebUIContentsWrapperService exists for the current profile. The service
-  // may not exist for off the record profiles.
-  auto* service =
-      WebUIContentsWrapperServiceFactory::GetForProfile(profile_, true);
-  if (service && base::FeatureList::IsEnabled(
-                     features::kWebUIBubblePerProfilePersistence)) {
-    set_bubble_using_cached_web_contents(
-        !!service->GetWebUIContentsWrapperFromURL(webui_url_));
+  set_bubble_using_cached_web_contents(!!cached_contents_wrapper());
 
-    // If using per-profile WebContents persistence get the associated
-    // WebUIContentsWrapper from the WebUIContentsWrapperService.
-    MaybeInitPersistentRenderer();
-    contents_wrapper = service->GetWebUIContentsWrapperFromURL(webui_url_);
-    DCHECK(contents_wrapper);
-
-    // If there is a host currently associated to this contents wrapper ensure
-    // the host has closed and the association has been removed.
-    if (contents_wrapper->GetHost()) {
-      contents_wrapper->CloseUI();
-    }
-    DCHECK(!contents_wrapper->GetHost());
-
-    // If the wrapped WebContents has crashed ensure we reload it here before
-    // passing it over to the dialog host.
-    if (contents_wrapper->web_contents()->IsCrashed()) {
-      contents_wrapper->ReloadWebContents();
-    }
-  } else {
-    set_bubble_using_cached_web_contents(!!cached_contents_wrapper());
-
-    if (!cached_contents_wrapper()) {
-      set_cached_contents_wrapper(std::make_unique<WebUIContentsWrapperT<T>>(
-          webui_url_, profile_, task_manager_string_id_));
-    }
-
-    contents_wrapper = cached_contents_wrapper();
+  if (!cached_contents_wrapper()) {
+    set_cached_contents_wrapper(std::make_unique<WebUIContentsWrapperT<T>>(
+        webui_url_, profile_, task_manager_string_id_));
   }
 
+  contents_wrapper = cached_contents_wrapper();
+
   // If the contents has already navigated to the current WebUI page force a
   // reload. This will force the contents back through the page load lifecycle.
   if (force_load_on_create_ &&
@@ -280,22 +230,7 @@
 
 template <typename T>
 WebUIContentsWrapper* WebUIBubbleManagerImpl<T>::GetContentsWrapper() {
-  if (cached_contents_wrapper()) {
-    return cached_contents_wrapper();
-  }
-
-  if (!base::FeatureList::IsEnabled(
-          features::kWebUIBubblePerProfilePersistence)) {
-    return nullptr;
-  }
-
-  auto* service =
-      WebUIContentsWrapperServiceFactory::GetForProfile(profile_, true);
-  if (!service) {
-    return nullptr;
-  }
-
-  return service->GetWebUIContentsWrapperFromURL(webui_url_);
+  return cached_contents_wrapper();
 }
 
 #endif  // CHROME_BROWSER_UI_VIEWS_BUBBLE_WEBUI_BUBBLE_MANAGER_H_
diff --git a/chrome/browser/ui/views/bubble/webui_bubble_manager_browsertest.cc b/chrome/browser/ui/views/bubble/webui_bubble_manager_browsertest.cc
index 3dc59f2..00bd380 100644
--- a/chrome/browser/ui/views/bubble/webui_bubble_manager_browsertest.cc
+++ b/chrome/browser/ui/views/bubble/webui_bubble_manager_browsertest.cc
@@ -36,10 +36,6 @@
 void DestroyBubble(WebUIBubbleManager* bubble_manager, Profile* profile) {
   bubble_manager->CloseBubble();
   bubble_manager->ResetContentsWrapperForTesting();
-  if (auto* service =
-          WebUIContentsWrapperServiceFactory::GetForProfile(profile, true)) {
-    service->Shutdown();
-  }
   base::RunLoop().RunUntilIdle();
 }
 
diff --git a/chrome/browser/ui/views/bubble/webui_bubble_manager_unittest.cc b/chrome/browser/ui/views/bubble/webui_bubble_manager_unittest.cc
index ed23dfd..59716cbe 100644
--- a/chrome/browser/ui/views/bubble/webui_bubble_manager_unittest.cc
+++ b/chrome/browser/ui/views/bubble/webui_bubble_manager_unittest.cc
@@ -74,100 +74,6 @@
   TestingProfileManager profile_manager_;
 };
 
-// Fixture for testing the persistent renderer functionality.
-class WebUIBubbleManagerPersistentRendererTest : public WebUIBubbleManagerTest {
- public:
-  // WebUIBubbleManagerTest:
-  void SetUp() override {
-    scoped_feature_list_.InitWithFeatures(
-        {features::kWebUIBubblePerProfilePersistence}, {});
-    WebUIBubbleManagerTest::SetUp();
-  }
-
- private:
-  base::test::ScopedFeatureList scoped_feature_list_;
-};
-
-TEST_F(WebUIBubbleManagerPersistentRendererTest,
-       UsesPersistentContentsWrapperPerProfile) {
-  const char* kProfileName = "Person 1";
-  auto* test_profile = profile_manager()->CreateTestingProfile(kProfileName);
-
-  // Owned by |test_profile|.
-  auto* service =
-      WebUIContentsWrapperServiceFactory::GetForProfile(test_profile, true);
-  ASSERT_NE(nullptr, service);
-
-  std::unique_ptr<views::Widget> anchor_widget =
-      CreateTestWidget(views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET,
-                       views::Widget::InitParams::TYPE_WINDOW);
-  auto bubble_manager = WebUIBubbleManager::Create<TestWebUIController>(
-      anchor_widget->GetContentsView(), test_profile, GURL(kTestURL), 1);
-  bubble_manager->DisableCloseBubbleHelperForTesting();
-
-  // The per-profile persistent renderer will not have been created until the
-  // first time the bubble is invoked.
-  WebUIContentsWrapper* contents_wrapper =
-      service->GetWebUIContentsWrapperFromURL(GURL(kTestURL));
-  EXPECT_EQ(nullptr, contents_wrapper);
-
-  // Open the bubble, this should create the persistent renderer-backed
-  // `contents_wrapper`.
-  EXPECT_EQ(nullptr, bubble_manager->GetBubbleWidget());
-  bubble_manager->ShowBubble();
-  contents_wrapper = service->GetWebUIContentsWrapperFromURL(GURL(kTestURL));
-  EXPECT_NE(nullptr, bubble_manager->GetBubbleWidget());
-  EXPECT_FALSE(bubble_manager->GetBubbleWidget()->IsClosed());
-  EXPECT_EQ(contents_wrapper, bubble_manager->bubble_view_for_testing()
-                                  ->get_contents_wrapper_for_testing());
-
-  // After closing the bubble the `contents_wrapper` should continue to persist.
-  bubble_manager->CloseBubble();
-  EXPECT_TRUE(bubble_manager->GetBubbleWidget()->IsClosed());
-  EXPECT_EQ(contents_wrapper,
-            service->GetWebUIContentsWrapperFromURL(GURL(kTestURL)));
-
-  service->Shutdown();  // Need to Shutdown() before the profile owning it.
-  profile_manager()->DeleteTestingProfile(kProfileName);
-}
-
-TEST_F(WebUIBubbleManagerPersistentRendererTest,
-       PerProfileContentsWrapperNotUsedForOffTheRecordProfile) {
-  const char* kProfileName = "Person 1";
-  auto* test_profile = profile_manager()->CreateTestingProfile(kProfileName);
-  auto* otr_profile = test_profile->GetOffTheRecordProfile(
-      Profile::OTRProfileID::CreateUniqueForTesting(),
-      /*create_if_needed=*/true);
-
-  std::unique_ptr<views::Widget> anchor_widget =
-      CreateTestWidget(views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET,
-                       views::Widget::InitParams::TYPE_WINDOW);
-  auto bubble_manager = WebUIBubbleManager::Create<TestWebUIController>(
-      anchor_widget->GetContentsView(), otr_profile, GURL(kTestURL), 1);
-  bubble_manager->DisableCloseBubbleHelperForTesting();
-
-  // The service should not exist for off the record profiles.
-  auto* service =
-      WebUIContentsWrapperServiceFactory::GetForProfile(otr_profile, true);
-  ASSERT_EQ(nullptr, service);
-
-  // Open the bubble for the given bubble manager
-  EXPECT_EQ(nullptr, bubble_manager->GetBubbleWidget());
-  bubble_manager->ShowBubble();
-  EXPECT_NE(nullptr, bubble_manager->GetBubbleWidget());
-
-  // The contents wrapper should exist despite `service` not existing for the
-  // off the record profile.
-  EXPECT_NE(nullptr, bubble_manager->bubble_view_for_testing()
-                         ->get_contents_wrapper_for_testing());
-
-  bubble_manager->CloseBubble();
-  EXPECT_TRUE(bubble_manager->GetBubbleWidget()->IsClosed());
-
-  bubble_manager->ResetContentsWrapperForTesting();
-  profile_manager()->DeleteTestingProfile(kProfileName);
-}
-
 TEST_F(WebUIBubbleManagerTest, CreateWebUIBubbleDialogWithAnchorProvided) {
   const char* kProfileName = "Person 1";
   auto* test_profile = profile_manager()->CreateTestingProfile(kProfileName);
@@ -185,102 +91,3 @@
 
   EXPECT_EQ(bubble_view->GetAnchorRect(), anchor);
 }
-
-#if !BUILDFLAG(IS_CHROMEOS_ASH)  // No multi-profile on ChromeOS.
-
-TEST_F(WebUIBubbleManagerPersistentRendererTest,
-       UsesPersistentContentsWrapperPerProfileMultiProfile) {
-  const char* kProfileName1 = "Person 1";
-  const char* kProfileName2 = "Person 2";
-  auto* profile1 = profile_manager()->CreateTestingProfile(kProfileName1);
-  auto* profile2 = profile_manager()->CreateTestingProfile(kProfileName2);
-
-  auto* service1 =
-      WebUIContentsWrapperServiceFactory::GetForProfile(profile1, true);
-  auto* service2 =
-      WebUIContentsWrapperServiceFactory::GetForProfile(profile2, true);
-
-  std::unique_ptr<views::Widget> anchor_widget =
-      CreateTestWidget(views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET,
-                       views::Widget::InitParams::TYPE_WINDOW);
-  auto create_manager = [&](Profile* profile) {
-    std::unique_ptr<WebUIBubbleManager> manager =
-        WebUIBubbleManager::Create<TestWebUIController>(
-            anchor_widget->GetContentsView(), profile, GURL(kTestURL), 1);
-    manager->DisableCloseBubbleHelperForTesting();
-    return manager;
-  };
-  auto manager1 = create_manager(profile1);
-  auto manager2 = create_manager(profile1);
-  auto manager3 = create_manager(profile2);
-
-  WebUIContentsWrapper* contents_wrapper_profile1 =
-      service1->GetWebUIContentsWrapperFromURL(GURL(kTestURL));
-  WebUIContentsWrapper* contents_wrapper_profile2 =
-      service2->GetWebUIContentsWrapperFromURL(GURL(kTestURL));
-
-  // Content wrappers should be null until the first time the bubble is shown.
-  EXPECT_EQ(nullptr, contents_wrapper_profile1);
-  EXPECT_EQ(nullptr, contents_wrapper_profile2);
-
-  // Show bubbles for each manager one at a time, manager1 and manager2 should
-  // leverage the same contents wrapper. manager3 should be using a unique
-  // contents wrapper as it is backed by a different profile.
-  auto show_bubble = [](WebUIBubbleManager* manager,
-                        WebUIContentsWrapperService* service) {
-    // Open the bubble for the given bubble manager
-    EXPECT_EQ(nullptr, manager->GetBubbleWidget());
-
-    manager->ShowBubble();
-    auto* contents_wrapper =
-        service->GetWebUIContentsWrapperFromURL(GURL(kTestURL));
-    EXPECT_NE(nullptr, manager->GetBubbleWidget());
-    EXPECT_NE(nullptr, contents_wrapper);
-    EXPECT_EQ(
-        contents_wrapper,
-        manager->bubble_view_for_testing()->get_contents_wrapper_for_testing());
-
-    manager->CloseBubble();
-    EXPECT_TRUE(manager->GetBubbleWidget()->IsClosed());
-    views::test::WidgetDestroyedWaiter destroyed_waiter(
-        manager->GetBubbleWidget());
-    destroyed_waiter.Wait();
-    return contents_wrapper;
-  };
-  contents_wrapper_profile1 = show_bubble(manager1.get(), service1);
-  EXPECT_EQ(contents_wrapper_profile1, show_bubble(manager2.get(), service1));
-  contents_wrapper_profile2 = show_bubble(manager3.get(), service2);
-
-  auto test_manager = [](WebUIBubbleManager* manager,
-                         WebUIContentsWrapperService* service,
-                         WebUIContentsWrapper* expected_wrapper) {
-    // Open the bubble for the given bubble manager
-    EXPECT_EQ(nullptr, manager->GetBubbleWidget());
-    manager->ShowBubble();
-    EXPECT_NE(nullptr, manager->GetBubbleWidget());
-
-    // The `expected_wrapper` matches the one used by the bubble.
-    EXPECT_EQ(
-        expected_wrapper,
-        manager->bubble_view_for_testing()->get_contents_wrapper_for_testing());
-
-    // Close the bubble, ensure the service's contents wrapper still exists and
-    // matches the `expected_wrapper`.
-    EXPECT_FALSE(manager->GetBubbleWidget()->IsClosed());
-    manager->CloseBubble();
-    EXPECT_TRUE(manager->GetBubbleWidget()->IsClosed());
-
-    EXPECT_EQ(expected_wrapper,
-              service->GetWebUIContentsWrapperFromURL(GURL(kTestURL)));
-  };
-
-  test_manager(manager1.get(), service1, contents_wrapper_profile1);
-  test_manager(manager2.get(), service1, contents_wrapper_profile1);
-  test_manager(manager3.get(), service2, contents_wrapper_profile2);
-  service1->Shutdown();  // Need to Shutdown() before the profile owning it.
-  service2->Shutdown();  // Need to Shutdown() before the profile owning it.
-  profile_manager()->DeleteTestingProfile(kProfileName1);
-  profile_manager()->DeleteTestingProfile(kProfileName2);
-}
-
-#endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/ui/views/side_panel/BUILD.gn b/chrome/browser/ui/views/side_panel/BUILD.gn
index d286291..52963cb 100644
--- a/chrome/browser/ui/views/side_panel/BUILD.gn
+++ b/chrome/browser/ui/views/side_panel/BUILD.gn
@@ -119,6 +119,7 @@
     "//chrome/browser/companion/core/mojom:mojo_bindings",
     "//chrome/browser/companion/visual_query",
     "//chrome/browser/profiles:profile",
+    "//chrome/browser/ui:browser_list",
     "//chrome/browser/ui/actions:actions_headers",
     "//chrome/browser/ui/color:color_headers",
     "//chrome/browser/ui/customize_chrome",
diff --git a/chrome/browser/ui/webui/BUILD.gn b/chrome/browser/ui/webui/BUILD.gn
index 6599e9b..a1640e5 100644
--- a/chrome/browser/ui/webui/BUILD.gn
+++ b/chrome/browser/ui/webui/BUILD.gn
@@ -5,6 +5,7 @@
 import("//build/config/chromeos/ui_mode.gni")
 import("//chromeos/dbus/config/use_real_dbus_clients.gni")
 import("//components/metrics/generate_allowlist_from_histograms_file.gni")
+import("//extensions/buildflags/buildflags.gni")
 
 generate_allowlist_from_histograms_file("webui_url_hashes") {
   namespace = "webui_metrics"
@@ -26,7 +27,6 @@
 
   deps = [
     "//chrome/browser/ui",
-    "//chrome/browser/ui/webui",
     "//components/compose:buildflags",
     "//components/lens:buildflags",
     "//content/public/browser",
@@ -53,24 +53,48 @@
   }
 }
 
-source_set("webui") {
+source_set("webui_util") {
   sources = [
     "webui_util.cc",
     "webui_util.h",
   ]
 
-  sources += get_target_outputs(":webui_url_hashes")
+  public_deps = [
+    "//base",
+    "//ui/base",
+  ]
 
   deps = [
-    ":webui_url_hashes",
-    "//base",
+    "//build:chromeos_buildflags",
     "//content/public/browser",
     "//content/public/common",
     "//services/network/public/mojom",
-    "//ui/base",
     "//ui/resources",
   ]
+
   if (is_chromeos_lacros) {
     deps += [ "//chromeos/startup" ]
   }
 }
+
+source_set("webui") {
+  sources = [
+    "constrained_web_dialog_ui.cc",
+    "constrained_web_dialog_ui.h",
+  ]
+
+  sources += get_target_outputs(":webui_url_hashes")
+
+  public_deps = [ "//content/public/browser" ]
+
+  deps = [
+    ":webui_url_hashes",
+    "//extensions/buildflags",
+  ]
+  if (enable_extensions) {
+    deps += [ "//chrome/browser/extensions" ]
+  }
+  if (!is_android) {
+    deps += [ "//ui/web_dialogs" ]
+  }
+}
diff --git a/chrome/browser/ui/webui/ash/account_manager/BUILD.gn b/chrome/browser/ui/webui/ash/account_manager/BUILD.gn
index 21a615f..0582a95 100644
--- a/chrome/browser/ui/webui/ash/account_manager/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/account_manager/BUILD.gn
@@ -34,7 +34,7 @@
     "//chrome/browser:resources",
     "//chrome/browser:resources_grit",
     "//chrome/browser/profiles:profile",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/signin/ash",
     "//chrome/common:constants",
     "//components/account_manager_core",
diff --git a/chrome/browser/ui/webui/ash/add_supervision/BUILD.gn b/chrome/browser/ui/webui/ash/add_supervision/BUILD.gn
index 238755c..8e74c13 100644
--- a/chrome/browser/ui/webui/ash/add_supervision/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/add_supervision/BUILD.gn
@@ -55,7 +55,7 @@
     "//chrome/browser/resources/chromeos/add_supervision:resources_grit",
     "//chrome/browser/resources/chromeos/supervision:resources",
     "//chrome/browser/resources/chromeos/supervision:resources_grit",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//components/constrained_window",
     "//components/google/core/common",
     "//components/services/app_service/public/cpp:app_types",
diff --git a/chrome/browser/ui/webui/ash/app_install/BUILD.gn b/chrome/browser/ui/webui/ash/app_install/BUILD.gn
index 9da8a5f..55296052 100644
--- a/chrome/browser/ui/webui/ash/app_install/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/app_install/BUILD.gn
@@ -54,7 +54,7 @@
     "//chrome/browser/apps/app_service/app_icon",
     "//chrome/browser/resources/chromeos/app_install:resources",
     "//chrome/browser/ui",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/web_applications",
     "//chrome/common",
     "//chromeos/constants",
diff --git a/chrome/browser/ui/webui/ash/assistant_optin/BUILD.gn b/chrome/browser/ui/webui/ash/assistant_optin/BUILD.gn
index 0801eb6..7a6207d 100644
--- a/chrome/browser/ui/webui/ash/assistant_optin/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/assistant_optin/BUILD.gn
@@ -40,7 +40,7 @@
     "//chrome/browser/ash/login/ui",
     "//chrome/browser/profiles:profile",
     "//chrome/browser/resources/chromeos/assistant_optin:resources",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chromeos/ash/components/assistant:buildflags",
     "//chromeos/ash/components/audio",
     "//chromeos/ash/services/assistant/public/cpp",
diff --git a/chrome/browser/ui/webui/ash/audio/BUILD.gn b/chrome/browser/ui/webui/ash/audio/BUILD.gn
index 2941378..e70a362 100644
--- a/chrome/browser/ui/webui/ash/audio/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/audio/BUILD.gn
@@ -35,6 +35,6 @@
     "//ash/constants",
     "//chrome/browser/resources/chromeos/audio:resources",
     "//chrome/browser/ui",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
   ]
 }
diff --git a/chrome/browser/ui/webui/ash/bluetooth/BUILD.gn b/chrome/browser/ui/webui/ash/bluetooth/BUILD.gn
index 10efdfc..95424e4 100644
--- a/chrome/browser/ui/webui/ash/bluetooth/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/bluetooth/BUILD.gn
@@ -20,7 +20,7 @@
     "//base",
     "//chrome/browser/profiles:profile",
     "//chrome/browser/resources/chromeos/bluetooth_pairing_dialog:resources",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/system_web_dialog",
     "//chrome/common",
     "//chromeos/ash/components/network",
diff --git a/chrome/browser/ui/webui/ash/borealis_installer/BUILD.gn b/chrome/browser/ui/webui/ash/borealis_installer/BUILD.gn
index 61c21f35..1e0e1c4 100644
--- a/chrome/browser/ui/webui/ash/borealis_installer/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/borealis_installer/BUILD.gn
@@ -47,7 +47,7 @@
     "//chrome/browser/resources/chromeos/borealis_installer:resources",
     "//chrome/browser/ui",
     "//chrome/browser/ui/views/borealis",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//components/strings:components_strings",
     "//ui/aura",
     "//ui/base",
diff --git a/chrome/browser/ui/webui/ash/cellular_setup/BUILD.gn b/chrome/browser/ui/webui/ash/cellular_setup/BUILD.gn
index 79e13b4..2c37984d 100644
--- a/chrome/browser/ui/webui/ash/cellular_setup/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/cellular_setup/BUILD.gn
@@ -30,7 +30,7 @@
     "//chrome/browser:resources",
     "//chrome/browser/ash/mobile",
     "//chrome/browser/profiles:profile",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chrome/common",
     "//chromeos/ash/components/network",
     "//components/login",
diff --git a/chrome/browser/ui/webui/ash/cloud_upload/BUILD.gn b/chrome/browser/ui/webui/ash/cloud_upload/BUILD.gn
index 21f039a..8c6cb64 100644
--- a/chrome/browser/ui/webui/ash/cloud_upload/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/cloud_upload/BUILD.gn
@@ -88,7 +88,7 @@
     "//chrome/browser/extensions",
     "//chrome/browser/resources/chromeos/cloud_upload:resources",
     "//chrome/browser/ui/ash/system_web_apps",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/settings/pages/files",
     "//chrome/common:chrome_features",
     "//chromeos/ash/components/browser_context_helper",
diff --git a/chrome/browser/ui/webui/ash/config/BUILD.gn b/chrome/browser/ui/webui/ash/config/BUILD.gn
index 692c4753..3b46fae 100644
--- a/chrome/browser/ui/webui/ash/config/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/config/BUILD.gn
@@ -61,7 +61,7 @@
     "//chrome/browser/ash/system_web_apps/apps/vc_background_ui",
     "//chrome/browser/ui",
     "//chrome/browser/ui/ash/holding_space",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/account_manager",
     "//chrome/browser/ui/webui/ash/add_supervision",
     "//chrome/browser/ui/webui/ash/app_install",
diff --git a/chrome/browser/ui/webui/ash/crostini_installer/BUILD.gn b/chrome/browser/ui/webui/ash/crostini_installer/BUILD.gn
index 1a032498..8a42e2f 100644
--- a/chrome/browser/ui/webui/ash/crostini_installer/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/crostini_installer/BUILD.gn
@@ -26,7 +26,7 @@
     "//chrome/browser:resources",
     "//chrome/browser/ash/crostini:crostini_installer_types_mojom",
     "//chrome/browser/profiles:profile",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/system_web_dialog",
     "//chrome/common",
     "//chromeos/ash/components/dbus/spaced",
diff --git a/chrome/browser/ui/webui/ash/crostini_upgrader/BUILD.gn b/chrome/browser/ui/webui/ash/crostini_upgrader/BUILD.gn
index 6ffd8fe..c219688 100644
--- a/chrome/browser/ui/webui/ash/crostini_upgrader/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/crostini_upgrader/BUILD.gn
@@ -26,7 +26,7 @@
     "//chrome/browser:resources",
     "//chrome/browser/ash/crostini",
     "//chrome/browser/profiles:profile",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/system_web_dialog",
     "//chrome/common",
     "//components/strings:components_strings",
diff --git a/chrome/browser/ui/webui/ash/curtain_ui/BUILD.gn b/chrome/browser/ui/webui/ash/curtain_ui/BUILD.gn
index f494834..d5e8aa9b 100644
--- a/chrome/browser/ui/webui/ash/curtain_ui/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/curtain_ui/BUILD.gn
@@ -17,7 +17,7 @@
     "//chrome/browser/profiles:profile",
     "//chrome/browser/resources/chromeos/remote_maintenance_curtain:resources",
     "//chrome/browser/resources/chromeos/remote_maintenance_curtain:resources_grit",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/login",
     "//chrome/common",
     "//content/public/browser",
diff --git a/chrome/browser/ui/webui/ash/emoji/BUILD.gn b/chrome/browser/ui/webui/ash/emoji/BUILD.gn
index 776038d..3e6131f 100644
--- a/chrome/browser/ui/webui/ash/emoji/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/emoji/BUILD.gn
@@ -82,7 +82,7 @@
     "//chrome/app:generated_resources",
     "//chrome/browser/resources/chromeos/emoji_picker:resources",
     "//chrome/browser/resources/chromeos/seal:resources",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chrome/common:channel_info",
     "//chromeos/ash/components/emoji:resources",
     "//components/prefs",
diff --git a/chrome/browser/ui/webui/ash/enterprise_reporting/BUILD.gn b/chrome/browser/ui/webui/ash/enterprise_reporting/BUILD.gn
index 5dfc9f83..fdae701 100644
--- a/chrome/browser/ui/webui/ash/enterprise_reporting/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/enterprise_reporting/BUILD.gn
@@ -41,7 +41,7 @@
     "//chrome/browser/ash/policy/core",
     "//chrome/browser/profiles:profile",
     "//chrome/browser/resources/chromeos/enterprise_reporting:resources",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//components/reporting/util:status",
     "//components/version_info",
     "//content/public/browser",
diff --git a/chrome/browser/ui/webui/ash/extended_updates/BUILD.gn b/chrome/browser/ui/webui/ash/extended_updates/BUILD.gn
index 398b867..f8ac745f 100644
--- a/chrome/browser/ui/webui/ash/extended_updates/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/extended_updates/BUILD.gn
@@ -42,7 +42,7 @@
     "//chrome/browser/ash/login/ui",
     "//chrome/browser/profiles:profile",
     "//chrome/browser/resources/ash/extended_updates:resources",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/login",
     "//chrome/common",
     "//components/services/app_service",
diff --git a/chrome/browser/ui/webui/ash/healthd_internals/BUILD.gn b/chrome/browser/ui/webui/ash/healthd_internals/BUILD.gn
index 63297c4..d02cff0 100644
--- a/chrome/browser/ui/webui/ash/healthd_internals/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/healthd_internals/BUILD.gn
@@ -27,7 +27,7 @@
   deps = [
     "//ash/constants",
     "//chrome/browser/resources/chromeos/healthd_internals:resources",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chromeos/ash/services/cros_healthd/public/cpp",
   ]
 }
diff --git a/chrome/browser/ui/webui/ash/in_session_password_change/BUILD.gn b/chrome/browser/ui/webui/ash/in_session_password_change/BUILD.gn
index 8271bda..f9b25b4c 100644
--- a/chrome/browser/ui/webui/ash/in_session_password_change/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/in_session_password_change/BUILD.gn
@@ -41,7 +41,7 @@
     "//chrome/browser/profiles:profile",
     "//chrome/browser/resources/chromeos/password_change:resources",
     "//chrome/browser/resources/gaia_auth_host:resources",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chrome/common:constants",
     "//chromeos/ash/components/login/auth/public:authpublic",
     "//chromeos/strings",
diff --git a/chrome/browser/ui/webui/ash/internet/BUILD.gn b/chrome/browser/ui/webui/ash/internet/BUILD.gn
index 829a7fd..33ac368d 100644
--- a/chrome/browser/ui/webui/ash/internet/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/internet/BUILD.gn
@@ -19,7 +19,7 @@
     "//chrome/browser/profiles:profile",
     "//chrome/browser/resources/chromeos/internet_config_dialog:resources",
     "//chrome/browser/resources/chromeos/internet_detail_dialog:resources",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/cellular_setup",
     "//chrome/browser/ui/webui/ash/system_web_dialog",
     "//chrome/common",
diff --git a/chrome/browser/ui/webui/ash/kerberos/BUILD.gn b/chrome/browser/ui/webui/ash/kerberos/BUILD.gn
index f777a6e0..f0f73c8 100644
--- a/chrome/browser/ui/webui/ash/kerberos/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/kerberos/BUILD.gn
@@ -30,7 +30,7 @@
     "//chrome/app:generated_resources",
     "//chrome/browser/profiles:profile",
     "//chrome/browser/resources/chromeos/kerberos:resources",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//content/public/browser",
     "//net",
     "//ui/aura",
diff --git a/chrome/browser/ui/webui/ash/launcher_internals/BUILD.gn b/chrome/browser/ui/webui/ash/launcher_internals/BUILD.gn
index d380ec48..be80efe 100644
--- a/chrome/browser/ui/webui/ash/launcher_internals/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/launcher_internals/BUILD.gn
@@ -35,6 +35,6 @@
     "//chrome/browser/ash/app_list",
     "//chrome/browser/ash/app_list/search/common",
     "//chrome/browser/resources/chromeos/launcher_internals:resources",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
   ]
 }
diff --git a/chrome/browser/ui/webui/ash/lock_screen_reauth/BUILD.gn b/chrome/browser/ui/webui/ash/lock_screen_reauth/BUILD.gn
index 5673019f..b5cc741 100644
--- a/chrome/browser/ui/webui/ash/lock_screen_reauth/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/lock_screen_reauth/BUILD.gn
@@ -65,7 +65,7 @@
     "//chrome/browser/resources/chromeos/lock_screen_reauth:resources",
     "//chrome/browser/resources/gaia_auth_host:resources",
     "//chrome/browser/ui/ash/login",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/internet",
     "//chrome/browser/ui/webui/ash/login",
     "//chrome/common:chrome_features",
diff --git a/chrome/browser/ui/webui/ash/login/split_modifier_keyboard_info_screen_handler.cc b/chrome/browser/ui/webui/ash/login/split_modifier_keyboard_info_screen_handler.cc
index 870f076..5aa2c4b 100644
--- a/chrome/browser/ui/webui/ash/login/split_modifier_keyboard_info_screen_handler.cc
+++ b/chrome/browser/ui/webui/ash/login/split_modifier_keyboard_info_screen_handler.cc
@@ -18,7 +18,22 @@
 
 // Add localized values that you want to propagate to the JS side here.
 void SplitModifierKeyboardInfoScreenHandler::DeclareLocalizedValues(
-    ::login::LocalizedValuesBuilder* builder) {}
+    ::login::LocalizedValuesBuilder* builder) {
+  builder->Add("splitModifierTitle", IDS_OOBE_SPLIT_MODIFIER_INFO_TITLE);
+  builder->Add("splitModifierSubtitle", IDS_OOBE_SPLIT_MODIFIER_INFO_SUBTITLE);
+  builder->Add("splitModifierFirstDescriptionTitle",
+               IDS_OOBE_SPLIT_MODIFIER_INFO_FIRST_DESCRIPTION_TITLE);
+  builder->Add("splitModifierFirstDescriptionText",
+               IDS_OOBE_SPLIT_MODIFIER_INFO_FIRST_DESCRIPTION_TEXT);
+  builder->Add("splitModifierFirstDescriptionAccessibility",
+               IDS_OOBE_SPLIT_MODIFIER_INFO_FIRST_DESCRIPTION_ACCESSIBILITY);
+  builder->Add("splitModifierSecondDescriptionTitle",
+               IDS_OOBE_SPLIT_MODIFIER_INFO_SECOND_DESCRIPTION_TITLE);
+  builder->Add("splitModifierSecondDescriptionText",
+               IDS_OOBE_SPLIT_MODIFIER_INFO_SECOND_DESCRIPTION_TEXT);
+  builder->Add("splitModifierSecondDescriptionAccessibility",
+               IDS_OOBE_SPLIT_MODIFIER_INFO_SECOND_DESCRIPTION_ACCESSIBILITY);
+}
 
 void SplitModifierKeyboardInfoScreenHandler::Show() {
   ShowInWebUI();
diff --git a/chrome/browser/ui/webui/ash/mako/BUILD.gn b/chrome/browser/ui/webui/ash/mako/BUILD.gn
index 6f4d2648..ee2de31 100644
--- a/chrome/browser/ui/webui/ash/mako/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/mako/BUILD.gn
@@ -48,7 +48,7 @@
     "//chrome/browser/ash/input_method",
     "//chrome/browser/profiles:profile",
     "//chrome/browser/resources/chromeos/mako:resources",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chrome/common:mojo_bindings",
     "//chromeos/constants",
     "//components/input",
diff --git a/chrome/browser/ui/webui/ash/manage_mirrorsync/BUILD.gn b/chrome/browser/ui/webui/ash/manage_mirrorsync/BUILD.gn
index 3c46d16..30e1708b 100644
--- a/chrome/browser/ui/webui/ash/manage_mirrorsync/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/manage_mirrorsync/BUILD.gn
@@ -44,7 +44,7 @@
     "//chrome/browser/ash/file_manager",
     "//chrome/browser/profiles:profile",
     "//chrome/browser/resources/chromeos/manage_mirrorsync:resources",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//ui/aura",
     "//ui/base:types",
     "//ui/webui",
diff --git a/chrome/browser/ui/webui/ash/multidevice_internals/BUILD.gn b/chrome/browser/ui/webui/ash/multidevice_internals/BUILD.gn
index e1e715c1..78141ed 100644
--- a/chrome/browser/ui/webui/ash/multidevice_internals/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/multidevice_internals/BUILD.gn
@@ -33,7 +33,7 @@
     "//chrome/browser/ash/phonehub",
     "//chrome/browser/profiles:profile",
     "//chrome/browser/resources/chromeos/multidevice_internals:resources",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chromeos/ash/components/phonehub:debug",
     "//chromeos/ash/components/phonehub/proto",
     "//components/prefs",
diff --git a/chrome/browser/ui/webui/ash/multidevice_setup/BUILD.gn b/chrome/browser/ui/webui/ash/multidevice_setup/BUILD.gn
index ca373ca..c3b7ebc2 100644
--- a/chrome/browser/ui/webui/ash/multidevice_setup/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/multidevice_setup/BUILD.gn
@@ -43,7 +43,7 @@
     "//chrome/browser/ash/profiles",
     "//chrome/browser/profiles:profile",
     "//chrome/browser/resources/chromeos:multidevice_setup_resources",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/login",
     "//chrome/browser/ui/webui/ash/user_image",
     "//chromeos/ash/services/multidevice_setup",
diff --git a/chrome/browser/ui/webui/ash/network_ui/BUILD.gn b/chrome/browser/ui/webui/ash/network_ui/BUILD.gn
index 32ca99d..d801880 100644
--- a/chrome/browser/ui/webui/ash/network_ui/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/network_ui/BUILD.gn
@@ -34,7 +34,7 @@
     "//chrome/browser/profiles:profile",
     "//chrome/browser/resources/chromeos/network_ui:resources",
     "//chrome/browser/ui/ash/system",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/cellular_setup",
     "//chrome/browser/ui/webui/ash/internet",
     "//chromeos/ash/components/dbus/debug_daemon",
diff --git a/chrome/browser/ui/webui/ash/notification_tester/BUILD.gn b/chrome/browser/ui/webui/ash/notification_tester/BUILD.gn
index 008eebe..0ffd903 100644
--- a/chrome/browser/ui/webui/ash/notification_tester/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/notification_tester/BUILD.gn
@@ -30,7 +30,7 @@
     "//chrome/browser:resources",
     "//chrome/browser/profiles:profile",
     "//chrome/browser/resources/chromeos/notification_tester:resources",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chromeos/constants",
     "//ui/base",
     "//ui/chromeos/styles:cros_tokens_color_mappings",
diff --git a/chrome/browser/ui/webui/ash/office_fallback/BUILD.gn b/chrome/browser/ui/webui/ash/office_fallback/BUILD.gn
index 02c4f150..06538ee 100644
--- a/chrome/browser/ui/webui/ash/office_fallback/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/office_fallback/BUILD.gn
@@ -45,7 +45,7 @@
     "//chrome/browser/chromeos",
     "//chrome/browser/chromeos/upload_office_to_cloud",
     "//chrome/browser/profiles:profile",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/cloud_upload",
     "//chromeos/constants",
     "//ui/base",
diff --git a/chrome/browser/ui/webui/ash/parent_access/BUILD.gn b/chrome/browser/ui/webui/ash/parent_access/BUILD.gn
index 1790f1cd..59c391b 100644
--- a/chrome/browser/ui/webui/ash/parent_access/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/parent_access/BUILD.gn
@@ -62,7 +62,7 @@
     "//chrome/browser/profiles:profile",
     "//chrome/browser/resources/chromeos/parent_access:resources",
     "//chrome/browser/resources/chromeos/supervision:resources",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//components/google/core/common",
     "//components/signin/public/base",
     "//google_apis",
diff --git a/chrome/browser/ui/webui/ash/power_ui/BUILD.gn b/chrome/browser/ui/webui/ash/power_ui/BUILD.gn
index c6a5cc9..a93b3e0 100644
--- a/chrome/browser/ui/webui/ash/power_ui/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/power_ui/BUILD.gn
@@ -16,7 +16,7 @@
     "//base",
     "//chrome/browser/ash/power",
     "//chrome/browser/profiles:profile",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chrome/common",
     "//content/public/browser",
     "//content/public/common",
diff --git a/chrome/browser/ui/webui/ash/sensor_info/BUILD.gn b/chrome/browser/ui/webui/ash/sensor_info/BUILD.gn
index 4a6f102..c68b4f26 100644
--- a/chrome/browser/ui/webui/ash/sensor_info/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/sensor_info/BUILD.gn
@@ -36,7 +36,7 @@
     "//chrome/browser/ash/file_manager",
     "//chrome/browser/profiles:profile",
     "//chrome/browser/resources/chromeos/sensor_info:resources",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
   ]
 }
 
diff --git a/chrome/browser/ui/webui/ash/set_time/BUILD.gn b/chrome/browser/ui/webui/ash/set_time/BUILD.gn
index c6886ae..4ae8a96f 100644
--- a/chrome/browser/ui/webui/ash/set_time/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/set_time/BUILD.gn
@@ -22,7 +22,7 @@
     "//chrome/browser/profiles:profile",
     "//chrome/browser/resources/chromeos/set_time_dialog:resources",
     "//chrome/browser/resources/chromeos/set_time_dialog:resources_grit",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/system_web_dialog",
     "//chrome/common",
     "//chromeos/ash/components/dbus/system_clock",
diff --git a/chrome/browser/ui/webui/ash/settings/BUILD.gn b/chrome/browser/ui/webui/ash/settings/BUILD.gn
index 5942d9b..84b8818 100644
--- a/chrome/browser/ui/webui/ash/settings/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/settings/BUILD.gn
@@ -75,7 +75,7 @@
     "//chrome/browser/resources/ash/settings:resources",
     "//chrome/browser/resources/settings_shared:resources",
     "//chrome/browser/ui/ash/wallpaper",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/settings/pages/apps",
     "//chrome/browser/ui/webui/ash/settings/pages/date_time",
     "//chrome/browser/ui/webui/ash/settings/pages/device",
diff --git a/chrome/browser/ui/webui/ash/settings/pages/a11y/BUILD.gn b/chrome/browser/ui/webui/ash/settings/pages/a11y/BUILD.gn
index b8bc1203..2364977 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/a11y/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/settings/pages/a11y/BUILD.gn
@@ -47,7 +47,7 @@
     "//chrome/browser/ash/crosapi:browser_util",
     "//chrome/browser/ash/url_handler",
     "//chrome/browser/profiles:profile",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/settings/search",
     "//chrome/common",
     "//chromeos/components/kiosk",
diff --git a/chrome/browser/ui/webui/ash/settings/pages/about/BUILD.gn b/chrome/browser/ui/webui/ash/settings/pages/about/BUILD.gn
index d2ab68c..9ecf5e9c 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/about/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/settings/pages/about/BUILD.gn
@@ -32,7 +32,7 @@
     "//chrome/browser:browser_process",
     "//chrome/browser/ash/arc",
     "//chrome/browser/ash/policy/core",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/settings/search",
     "//chrome/common",
     "//chrome/common:channel_info",
diff --git a/chrome/browser/ui/webui/ash/settings/pages/apps/BUILD.gn b/chrome/browser/ui/webui/ash/settings/pages/apps/BUILD.gn
index 7928968..4cb9169 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/apps/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/settings/pages/apps/BUILD.gn
@@ -42,7 +42,7 @@
     "//chrome/browser/ash/plugin_vm",
     "//chrome/browser/profiles:profile",
     "//chrome/browser/resources/ash/settings:resources",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/settings/pages/crostini",
     "//chrome/browser/ui/webui/ash/settings/search",
     "//chrome/browser/web_applications",
diff --git a/chrome/browser/ui/webui/ash/settings/pages/bluetooth/BUILD.gn b/chrome/browser/ui/webui/ash/settings/pages/bluetooth/BUILD.gn
index 66b0143..7787f0a 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/bluetooth/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/settings/pages/bluetooth/BUILD.gn
@@ -34,7 +34,7 @@
     "//ash/webui/settings/public/constants:mojom",
     "//chrome/app:generated_resources",
     "//chrome/browser:browser_public_dependencies",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/bluetooth",
     "//chrome/browser/ui/webui/ash/settings/search",
     "//chrome/browser/ui/webui/ash/settings/search/mojom",
diff --git a/chrome/browser/ui/webui/ash/settings/pages/date_time/BUILD.gn b/chrome/browser/ui/webui/ash/settings/pages/date_time/BUILD.gn
index 58086ae..d2117ca 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/date_time/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/settings/pages/date_time/BUILD.gn
@@ -38,7 +38,7 @@
     "//chrome/browser/ash/profiles",
     "//chrome/browser/ash/system",
     "//chrome/browser/profiles:profile",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/set_time",
     "//chrome/browser/ui/webui/ash/settings/search",
     "//chrome/common",
diff --git a/chrome/browser/ui/webui/ash/settings/pages/device/BUILD.gn b/chrome/browser/ui/webui/ash/settings/pages/device/BUILD.gn
index a3f86299..f004c002 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/device/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/settings/pages/device/BUILD.gn
@@ -51,7 +51,7 @@
     "//chrome/browser/ash/note_taking",
     "//chrome/browser/profiles:profile",
     "//chrome/browser/ui/ash/system_web_apps",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/settings/search",
     "//chrome/common",
     "//chrome/common:chrome_features",
diff --git a/chrome/browser/ui/webui/ash/settings/pages/files/BUILD.gn b/chrome/browser/ui/webui/ash/settings/pages/files/BUILD.gn
index b6da4bc..7f60714f 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/files/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/settings/pages/files/BUILD.gn
@@ -37,7 +37,7 @@
     "//chrome/browser/ash/file_manager",
     "//chrome/browser/ash/profiles",
     "//chrome/browser/chromeos/upload_office_to_cloud",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/settings/search",
     "//chrome/browser/ui/webui/ash/smb_shares",
     "//chrome/common",
diff --git a/chrome/browser/ui/webui/ash/settings/pages/internet/BUILD.gn b/chrome/browser/ui/webui/ash/settings/pages/internet/BUILD.gn
index cb762cb..cbf441d 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/internet/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/settings/pages/internet/BUILD.gn
@@ -39,7 +39,7 @@
     "//chrome/browser/ash/profiles",
     "//chrome/browser/chromeos/extensions/vpn_provider",
     "//chrome/browser/profiles:profile",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/cellular_setup",
     "//chrome/browser/ui/webui/ash/settings/search",
     "//chrome/common",
diff --git a/chrome/browser/ui/webui/ash/settings/pages/kerberos/BUILD.gn b/chrome/browser/ui/webui/ash/settings/pages/kerberos/BUILD.gn
index 229ed43..d5c7e67 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/kerberos/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/settings/pages/kerberos/BUILD.gn
@@ -27,7 +27,7 @@
     "//chrome/browser:browser_process",
     "//chrome/browser:browser_public_dependencies",
     "//chrome/browser/profiles:profile",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/settings/search",
     "//chrome/common",
     "//chrome/common:constants",
diff --git a/chrome/browser/ui/webui/ash/settings/pages/languages/BUILD.gn b/chrome/browser/ui/webui/ash/settings/pages/languages/BUILD.gn
index 6137f4ba..34a8c5ac 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/languages/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/settings/pages/languages/BUILD.gn
@@ -25,7 +25,7 @@
     "//chrome/browser/ash/input_method",
     "//chrome/browser/profiles:profile",
     "//chrome/browser/ui/ash/keyboard",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/settings/search",
     "//chrome/common",
     "//chromeos/components/quick_answers/public/cpp",
diff --git a/chrome/browser/ui/webui/ash/settings/pages/main/BUILD.gn b/chrome/browser/ui/webui/ash/settings/pages/main/BUILD.gn
index a6e01d36..da0de42 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/main/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/settings/pages/main/BUILD.gn
@@ -35,7 +35,7 @@
     "//chrome/browser/ash/profiles",
     "//chrome/browser/profiles:profile",
     "//chrome/browser/resources/ash/settings:resources",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/settings/search",
     "//chrome/browser/ui/webui/ash/settings/services/hats",
     "//chrome/common",
diff --git a/chrome/browser/ui/webui/ash/settings/pages/multidevice/BUILD.gn b/chrome/browser/ui/webui/ash/settings/pages/multidevice/BUILD.gn
index 48220c0..33b62c2 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/multidevice/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/settings/pages/multidevice/BUILD.gn
@@ -38,7 +38,7 @@
     "//chrome/browser/nearby_sharing/common",
     "//chrome/browser/profiles:profile",
     "//chrome/browser/ui/ash/session",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/multidevice_setup",
     "//chrome/browser/ui/webui/ash/settings/search",
     "//chrome/common",
diff --git a/chrome/browser/ui/webui/ash/settings/pages/people/BUILD.gn b/chrome/browser/ui/webui/ash/settings/pages/people/BUILD.gn
index de6eeac..9e8ba801 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/people/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/settings/pages/people/BUILD.gn
@@ -57,7 +57,7 @@
     "//chrome/browser/profiles:profile",
     "//chrome/browser/sync",
     "//chrome/browser/ui:ui_features",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/account_manager",
     "//chrome/browser/ui/webui/ash/add_supervision",
     "//chrome/browser/ui/webui/ash/settings/search",
diff --git a/chrome/browser/ui/webui/ash/settings/pages/printing/BUILD.gn b/chrome/browser/ui/webui/ash/settings/pages/printing/BUILD.gn
index 49d81127..f9776ad3 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/printing/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/settings/pages/printing/BUILD.gn
@@ -33,7 +33,7 @@
     "//chrome/app:generated_resources",
     "//chrome/browser:browser_process",
     "//chrome/browser/profiles:profile",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/settings/search",
     "//chrome/common",
     "//chrome/common:chrome_features",
diff --git a/chrome/browser/ui/webui/ash/settings/pages/privacy/BUILD.gn b/chrome/browser/ui/webui/ash/settings/pages/privacy/BUILD.gn
index 031069b..1d251746 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/privacy/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/settings/pages/privacy/BUILD.gn
@@ -57,7 +57,7 @@
     "//chrome/browser/ash/profiles",
     "//chrome/browser/ash/settings",
     "//chrome/browser/ash/system",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/settings/search",
     "//chrome/browser/web_applications",
     "//chrome/common",
diff --git a/chrome/browser/ui/webui/ash/settings/pages/reset/BUILD.gn b/chrome/browser/ui/webui/ash/settings/pages/reset/BUILD.gn
index 8bb6589f..283c150 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/reset/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/settings/pages/reset/BUILD.gn
@@ -21,7 +21,7 @@
     "//chrome/app/resources:locale_settings",
     "//chrome/browser:browser_process",
     "//chrome/browser:browser_public_dependencies",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/settings/search",
     "//components/user_manager",
     "//content/public/browser",
diff --git a/chrome/browser/ui/webui/ash/settings/pages/search/BUILD.gn b/chrome/browser/ui/webui/ash/settings/pages/search/BUILD.gn
index 862a2868b..ea52974a 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/search/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/settings/pages/search/BUILD.gn
@@ -30,7 +30,7 @@
     "//chrome/browser:browser_public_dependencies",
     "//chrome/browser/ash/assistant",
     "//chrome/browser/profiles:profile",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/assistant_optin",
     "//chrome/browser/ui/webui/ash/settings/search",
     "//chrome/common",
diff --git a/chrome/browser/ui/webui/ash/skyvault/BUILD.gn b/chrome/browser/ui/webui/ash/skyvault/BUILD.gn
index 5c381b7..3f3fd3a 100644
--- a/chrome/browser/ui/webui/ash/skyvault/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/skyvault/BUILD.gn
@@ -35,7 +35,7 @@
     "//chrome/browser/ash/policy/skyvault",
     "//chrome/browser/profiles:profile",
     "//chrome/browser/resources/chromeos/skyvault:resources",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chrome/common",
     "//chrome/common:chrome_features",
     "//content/public/browser",
diff --git a/chrome/browser/ui/webui/ash/slow/BUILD.gn b/chrome/browser/ui/webui/ash/slow/BUILD.gn
index 15a478a..800a2f0 100644
--- a/chrome/browser/ui/webui/ash/slow/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/slow/BUILD.gn
@@ -17,7 +17,7 @@
   deps = [
     "//base",
     "//chrome/browser/profiles:profile",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chrome/common",
     "//components/feedback/content",
     "//content/public/browser",
diff --git a/chrome/browser/ui/webui/ash/smb_shares/BUILD.gn b/chrome/browser/ui/webui/ash/smb_shares/BUILD.gn
index 0ad993b3..5470c95 100644
--- a/chrome/browser/ui/webui/ash/smb_shares/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/smb_shares/BUILD.gn
@@ -31,7 +31,7 @@
     "//chrome/browser/ash/profiles",
     "//chrome/browser/ash/smb_client",
     "//chrome/browser/profiles:profile",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chrome/common",
     "//chromeos/constants",
     "//components/strings:components_strings",
diff --git a/chrome/browser/ui/webui/ash/sys_internals/BUILD.gn b/chrome/browser/ui/webui/ash/sys_internals/BUILD.gn
index b234b91..b1e82b28 100644
--- a/chrome/browser/ui/webui/ash/sys_internals/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/sys_internals/BUILD.gn
@@ -18,7 +18,7 @@
     "//base",
     "//chrome/browser:resources",
     "//chrome/browser/profiles:profile",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chrome/common",
     "//content/public/browser",
     "//content/public/common",
diff --git a/chrome/browser/ui/webui/ash/vc_tray_tester/BUILD.gn b/chrome/browser/ui/webui/ash/vc_tray_tester/BUILD.gn
index e178b10..b4cef04 100644
--- a/chrome/browser/ui/webui/ash/vc_tray_tester/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/vc_tray_tester/BUILD.gn
@@ -17,7 +17,7 @@
     "//chrome/browser:resources",
     "//chrome/browser/profiles:profile",
     "//chrome/browser/resources/chromeos/vc_tray_tester:resources",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chrome/common",
     "//content/public/browser",
   ]
diff --git a/chrome/browser/ui/webui/ash/vm/BUILD.gn b/chrome/browser/ui/webui/ash/vm/BUILD.gn
index bc6144a..b6c0001a 100644
--- a/chrome/browser/ui/webui/ash/vm/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/vm/BUILD.gn
@@ -20,7 +20,7 @@
     "//chrome/browser:resources",
     "//chrome/browser/ash/plugin_vm",
     "//chrome/browser/profiles:profile",
-    "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:webui_util",
     "//chrome/common",
     "//components/strings:components_strings",
     "//content/public/browser",
diff --git a/chrome/browser/ui/webui/chrome_web_contents_handler.cc b/chrome/browser/ui/webui/chrome_web_contents_handler.cc
index e8ad003..ce4a679 100644
--- a/chrome/browser/ui/webui/chrome_web_contents_handler.cc
+++ b/chrome/browser/ui/webui/chrome_web_contents_handler.cc
@@ -19,10 +19,6 @@
 #include "content/public/browser/web_contents.h"
 #include "third_party/blink/public/mojom/window_features/window_features.mojom.h"
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-#include "chrome/browser/ash/url_handler/url_handler.h"
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
-
 using content::BrowserContext;
 using content::OpenURLParams;
 using content::WebContents;
@@ -47,13 +43,6 @@
   if (!context)
     return nullptr;
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-  // Try to intercept the request and open the URL with Lacros.
-  if (ash::TryOpenUrl(params.url, params.disposition)) {
-    return nullptr;
-  }
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
-
   Profile* profile = Profile::FromBrowserContext(context);
 
   Browser* browser = chrome::FindTabbedBrowser(profile, false);
diff --git a/chrome/browser/ui/webui/management/management_ui_handler_unittest.cc b/chrome/browser/ui/webui/management/management_ui_handler_unittest.cc
index 93b2684..467c6cf 100644
--- a/chrome/browser/ui/webui/management/management_ui_handler_unittest.cc
+++ b/chrome/browser/ui/webui/management/management_ui_handler_unittest.cc
@@ -307,7 +307,7 @@
   }
   void CreateSecureDnsManagerForTesting(PrefService* local_state) {
     secure_dns_manager_ = std::make_unique<ash::SecureDnsManager>(
-        local_state, /*is_profile_managed=*/true);
+        local_state, /*profile_prefs=*/nullptr, /*is_profile_managed=*/true);
   }
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
@@ -1495,8 +1495,8 @@
 TEST_F(ManagementUIHandlerTests,
        ShowPrivacyDisclosureForSecureDnsWithIdentifiers) {
   ResetTestConfig();
-  local_state_.Set(prefs::kDnsOverHttpsMode,
-                   base::Value(SecureDnsConfig::kModeSecure));
+  local_state_.SetManagedPref(prefs::kDnsOverHttpsMode,
+                              base::Value(SecureDnsConfig::kModeSecure));
   local_state_.Set(prefs::kDnsOverHttpsSalt, base::Value("test-salt"));
   local_state_.Set(prefs::kDnsOverHttpsTemplatesWithIdentifiers,
                    base::Value("www.test-dns.com"));
diff --git a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
index 6026f29..0edb8b76 100644
--- a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
@@ -1233,12 +1233,8 @@
        IDS_AUTOFILL_MANAGE_PASSKEYS_MORE_ACTIONS_LABEL},
 #endif
 #if BUILDFLAG(IS_MAC)
-      {"biometricAuthenticaionForFillingLabel",
-       IDS_SETTINGS_PASSWORDS_BIOMETRIC_AUTHENTICATION_FOR_FILLING_TOGGLE_LABEL_MAC},
       {"managePasskeysSubTitle", IDS_AUTOFILL_MANAGE_PASSKEYS_SUB_TITLE_MAC},
 #elif BUILDFLAG(IS_WIN)
-      {"biometricAuthenticaionForFillingLabel",
-       IDS_SETTINGS_PASSWORDS_BIOMETRIC_AUTHENTICATION_FOR_FILLING_TOGGLE_LABEL_WIN},
       {"managePasskeysSubTitle", IDS_AUTOFILL_MANAGE_PASSKEYS_SUB_TITLE_WIN},
 #endif
       {"plusAddressSettings", IDS_PLUS_ADDRESS_SETTINGS_LABEL},
@@ -3372,7 +3368,15 @@
        IDS_SETTINGS_OFFER_WRITING_HELP_NO_DISABLED_SITES},
       {"offerWritingHelpRemoveDisabledSiteAriaLabel",
        IDS_SETTINGS_OFFER_WRITING_HELP_REMOVE_SITE_ARIA_LABEL},
-  };
+      {"siteSettingsSmartCardReaders", IDS_SITE_SETTINGS_SMART_CARD_READERS},
+      {"siteSettingsSmartCardReadersDescription",
+       IDS_SITE_SETTINGS_SMART_CARD_READERS_DESCRIPTION},
+      {"siteSettingsSmartCardReadersDefaultDescription",
+       IDS_SITE_SETTINGS_SMART_CARDS_DEFAULT_DESCRIPTION},
+      {"siteSettingsSmartCardReadersAllowed",
+       IDS_SITE_SETTINGS_SMART_CARDS_ALLOWED},
+      {"siteSettingsSmartCardReadersBlocked",
+       IDS_SITE_SETTINGS_SMART_CARDS_BLOCKED}};
   html_source->AddLocalizedStrings(kLocalizedStrings);
 
   // Tracking protection learn more links.
diff --git a/chrome/browser/ui/webui/settings/settings_secure_dns_handler_browsertest.cc b/chrome/browser/ui/webui/settings/settings_secure_dns_handler_browsertest.cc
index af7df4e..e70f4eb 100644
--- a/chrome/browser/ui/webui/settings/settings_secure_dns_handler_browsertest.cc
+++ b/chrome/browser/ui/webui/settings/settings_secure_dns_handler_browsertest.cc
@@ -35,7 +35,12 @@
 #include "chrome/browser/ash/login/session/user_session_manager.h"
 #include "chrome/browser/ash/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/ash/net/secure_dns_manager.h"
+#include "chrome/browser/browser_process_platform_part_ash.h"
+#include "chrome/browser/policy/profile_policy_connector.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
 #include "components/account_id/account_id.h"
+#include "components/prefs/testing_pref_service.h"
 #include "components/user_manager/scoped_user_manager.h"
 #include "components/user_manager/user_type.h"
 #endif
@@ -263,24 +268,34 @@
   std::string doh_config;
   int management_mode;
 
-  local_state->SetString(prefs::kDnsOverHttpsMode, SecureDnsConfig::kModeOff);
+  PrefService* pref_service_for_user_settings = local_state;
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  // On Chrome OS, the local_state is shared between all users so the user-set
+  // pref is stored in the profile's pref service.
+  pref_service_for_user_settings = browser()->profile()->GetPrefs();
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+
+  pref_service_for_user_settings->SetString(prefs::kDnsOverHttpsMode,
+                                            SecureDnsConfig::kModeOff);
   EXPECT_TRUE(GetLastSettingsChangedMessage(&secure_dns_mode, &doh_config,
                                             &management_mode));
   EXPECT_EQ(SecureDnsConfig::kModeOff, secure_dns_mode);
 
-  local_state->SetString(prefs::kDnsOverHttpsMode,
-                         SecureDnsConfig::kModeAutomatic);
+  pref_service_for_user_settings->SetString(prefs::kDnsOverHttpsMode,
+                                            SecureDnsConfig::kModeAutomatic);
   EXPECT_TRUE(GetLastSettingsChangedMessage(&secure_dns_mode, &doh_config,
                                             &management_mode));
   EXPECT_EQ(SecureDnsConfig::kModeAutomatic, secure_dns_mode);
 
-  local_state->SetString(prefs::kDnsOverHttpsMode,
-                         SecureDnsConfig::kModeSecure);
+  pref_service_for_user_settings->SetString(prefs::kDnsOverHttpsMode,
+                                            SecureDnsConfig::kModeSecure);
   EXPECT_TRUE(GetLastSettingsChangedMessage(&secure_dns_mode, &doh_config,
                                             &management_mode));
   EXPECT_EQ(SecureDnsConfig::kModeSecure, secure_dns_mode);
 
-  local_state->SetString(prefs::kDnsOverHttpsMode, "unknown");
+  pref_service_for_user_settings->SetString(prefs::kDnsOverHttpsMode,
+                                            "unknown");
   EXPECT_TRUE(GetLastSettingsChangedMessage(&secure_dns_mode, &doh_config,
                                             &management_mode));
   EXPECT_EQ(SecureDnsConfig::kModeOff, secure_dns_mode);
@@ -396,26 +411,37 @@
   std::string secure_dns_mode;
   std::string doh_config;
   int management_mode;
-  PrefService* local_state = g_browser_process->local_state();
-  local_state->SetString(prefs::kDnsOverHttpsMode,
-                         SecureDnsConfig::kModeAutomatic);
-  local_state->SetString(kDnsOverHttpsTemplatesPrefName, good_post_template);
+  PrefService* pref_service_for_user_settings =
+      g_browser_process->local_state();
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  // On Chrome OS, the local_state is shared between all users so the user-set
+  // pref is stored in the profile's pref service.
+  pref_service_for_user_settings = browser()->profile()->GetPrefs();
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+
+  pref_service_for_user_settings->SetString(prefs::kDnsOverHttpsMode,
+                                            SecureDnsConfig::kModeAutomatic);
+  pref_service_for_user_settings->SetString(kDnsOverHttpsTemplatesPrefName,
+                                            good_post_template);
   EXPECT_TRUE(GetLastSettingsChangedMessage(&secure_dns_mode, &doh_config,
                                             &management_mode));
   EXPECT_EQ(good_post_template, doh_config);
   std::string two_templates = good_post_template + "\n" + good_get_template;
-  local_state->SetString(kDnsOverHttpsTemplatesPrefName, two_templates);
+  pref_service_for_user_settings->SetString(kDnsOverHttpsTemplatesPrefName,
+                                            two_templates);
   EXPECT_TRUE(GetLastSettingsChangedMessage(&secure_dns_mode, &doh_config,
                                             &management_mode));
   EXPECT_EQ(two_templates, doh_config);
 
-  local_state->SetString(kDnsOverHttpsTemplatesPrefName, bad_template);
+  pref_service_for_user_settings->SetString(kDnsOverHttpsTemplatesPrefName,
+                                            bad_template);
   EXPECT_TRUE(GetLastSettingsChangedMessage(&secure_dns_mode, &doh_config,
                                             &management_mode));
   EXPECT_THAT(doh_config, IsEmpty());
 
-  local_state->SetString(kDnsOverHttpsTemplatesPrefName,
-                         bad_template + " " + good_post_template);
+  pref_service_for_user_settings->SetString(
+      kDnsOverHttpsTemplatesPrefName, bad_template + " " + good_post_template);
   EXPECT_TRUE(GetLastSettingsChangedMessage(&secure_dns_mode, &doh_config,
                                             &management_mode));
   EXPECT_EQ(good_post_template, doh_config);
@@ -427,35 +453,34 @@
   std::string templatesWithIdentifier =
       "https://foo.test-${USER_EMAIL}/dns-query{?dns}";
   std::string templatesWithIdentifierDisplay =
-      "https://foo.test-${testuser@managed.com}/dns-query{?dns}";
+      "https://foo.test-${stub-user@example.com}/dns-query{?dns}";
   std::string templatesWithIdentifierEffective =
       "https://"
       "foo.test-"
-      "FD5DFBED0D7B875A6416AFC61A37DBB63B6BA05B627AE9F5BE463A1F858F2D4E/"
+      "A3AB66F42D4B8C81160D04124BFFF7B197C9B10EB04BB4E75DBE0E3FFCF39FA4/"
       "dns-query{?dns}";
   std::string templates = "https://bar.test/dns-query{?dns}";
-  PrefService* local_state = g_browser_process->local_state();
 
-  // Create an affiliated user.
-  auto user_manager = std::make_unique<ash::FakeChromeUserManager>();
-  const AccountId account_id0(AccountId::FromUserEmail("testuser@managed.com"));
-  user_manager->AddUserWithAffiliationAndTypeAndProfile(
-      account_id0, /* is_affiliated=*/true, user_manager::UserType::kRegular,
-      nullptr);
-  user_manager::ScopedUserManager user_manager_enabler(std::move(user_manager));
+  g_browser_process->platform_part()
+      ->secure_dns_manager()
+      ->SetPrimaryProfilePropertiesForTesting(browser()->profile()->GetPrefs(),
+                                              /*is_profile_managed=*/true);
 
   std::string secure_dns_mode;
   std::string doh_config, doh_config_for_display;
   bool doh_with_identifiers_active;
   int management_mode;
 
-  local_state->SetString(prefs::kDnsOverHttpsMode,
-                         SecureDnsConfig::kModeSecure);
-  local_state->SetString(prefs::kDnsOverHttpsTemplatesWithIdentifiers,
-                         templatesWithIdentifier);
-  local_state->SetString(prefs::kDnsOverHttpsSalt, "salt-for-test");
-  local_state->SetString(prefs::kDnsOverHttpsTemplates, templates);
-
+  policy::PolicyMap policy_map;
+  SetPolicyForPolicyKey(&policy_map, policy::key::kDnsOverHttpsMode,
+                        base::Value(SecureDnsConfig::kModeSecure));
+  SetPolicyForPolicyKey(&policy_map, policy::key::kDnsOverHttpsTemplates,
+                        base::Value(templates));
+  SetPolicyForPolicyKey(&policy_map,
+                        policy::key::kDnsOverHttpsTemplatesWithIdentifiers,
+                        base::Value(templatesWithIdentifier));
+  SetPolicyForPolicyKey(&policy_map, policy::key::kDnsOverHttpsSalt,
+                        base::Value("salt-for-test"));
   EXPECT_TRUE(GetLastSettingsChangedMessage(&secure_dns_mode, &doh_config,
                                             &management_mode));
   EXPECT_TRUE(GetIdentifierConfigsFromLastSettingsChangedMessage(
@@ -464,7 +489,9 @@
   EXPECT_EQ(templatesWithIdentifierDisplay, doh_config_for_display);
   EXPECT_TRUE(doh_with_identifiers_active);
 
-  local_state->ClearPref(prefs::kDnsOverHttpsTemplatesWithIdentifiers);
+  SetPolicyForPolicyKey(&policy_map,
+                        policy::key::kDnsOverHttpsTemplatesWithIdentifiers,
+                        base::Value());
   EXPECT_TRUE(GetLastSettingsChangedMessage(&secure_dns_mode, &doh_config,
                                             &management_mode));
   EXPECT_TRUE(GetIdentifierConfigsFromLastSettingsChangedMessage(
@@ -472,6 +499,44 @@
   EXPECT_EQ(templates, doh_config);
   EXPECT_FALSE(doh_with_identifiers_active);
 }
+
+// Unmanaged users store the secure DoH config as profile prefs.
+IN_PROC_BROWSER_TEST_F(SecureDnsHandlerTest,
+                       SecureDnsTemplatesForUnmanagedUsers) {
+  const char kTemplates[] = "https://test1/dns-query{?dns}";
+  const char kTemplatesAlt[] = "https://test2/dns-query{?dns}";
+
+  PrefService* local_state = g_browser_process->local_state();
+  PrefService* profile_prefs = browser()->profile()->GetPrefs();
+
+  local_state->SetString(prefs::kDnsOverHttpsMode,
+                         SecureDnsConfig::kModeSecure);
+  local_state->SetString(prefs::kDnsOverHttpsTemplates, kTemplates);
+
+  std::string secure_dns_mode;
+  std::string doh_config;
+  int management_mode;
+
+  EXPECT_FALSE(GetLastSettingsChangedMessage(&secure_dns_mode, &doh_config,
+                                             &management_mode));
+
+  profile_prefs->SetString(prefs::kDnsOverHttpsMode,
+                           SecureDnsConfig::kModeSecure);
+  profile_prefs->SetString(prefs::kDnsOverHttpsTemplates, kTemplates);
+  EXPECT_TRUE(GetLastSettingsChangedMessage(&secure_dns_mode, &doh_config,
+                                            &management_mode));
+  EXPECT_EQ(secure_dns_mode, SecureDnsConfig::kModeSecure);
+  EXPECT_EQ(doh_config, kTemplates);
+
+  profile_prefs->SetString(prefs::kDnsOverHttpsMode,
+                           SecureDnsConfig::kModeAutomatic);
+  profile_prefs->SetString(prefs::kDnsOverHttpsTemplates, kTemplatesAlt);
+  EXPECT_TRUE(GetLastSettingsChangedMessage(&secure_dns_mode, &doh_config,
+                                            &management_mode));
+  EXPECT_EQ(secure_dns_mode, SecureDnsConfig::kModeAutomatic);
+  EXPECT_EQ(doh_config, kTemplatesAlt);
+}
+
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 IN_PROC_BROWSER_TEST_F(SecureDnsHandlerTest, TemplateValid) {
diff --git a/chrome/browser/ui/webui/settings/settings_ui.cc b/chrome/browser/ui/webui/settings/settings_ui.cc
index 7d24453..2dae4745 100644
--- a/chrome/browser/ui/webui/settings/settings_ui.cc
+++ b/chrome/browser/ui/webui/settings/settings_ui.cc
@@ -409,14 +409,6 @@
       download::IsDownloadBubbleEnabled() &&
           download::IsDownloadBubblePartialViewControlledByPref());
 
-#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
-  html_source->AddBoolean(
-      "biometricAuthenticationForFilling",
-      password_manager_util::
-          ShouldBiometricAuthenticationForFillingToggleBeVisible(
-              g_browser_process->local_state()));
-#endif
-
 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   html_source->AddBoolean(
       "showGetTheMostOutOfChromeSection",
@@ -579,6 +571,10 @@
                           base::FeatureList::IsEnabled(
                               features::kAutomaticFullscreenContentSetting));
 
+  html_source->AddBoolean(
+      "enableSmartCardReadersContentSetting",
+      base::FeatureList::IsEnabled(blink::features::kSmartCard));
+
 #if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
   // System
   html_source->AddBoolean(
diff --git a/chrome/browser/ui/webui/settings/site_settings_helper.cc b/chrome/browser/ui/webui/settings/site_settings_helper.cc
index 6ac41c9..6f4e156 100644
--- a/chrome/browser/ui/webui/settings/site_settings_helper.cc
+++ b/chrome/browser/ui/webui/settings/site_settings_helper.cc
@@ -168,6 +168,8 @@
     {ContentSettingsType::TRACKING_PROTECTION, "tracking-protection"},
     {ContentSettingsType::TOP_LEVEL_STORAGE_ACCESS, "top-level-storage-access"},
     {ContentSettingsType::WEB_APP_INSTALLATION, "web-app-installation"},
+    {ContentSettingsType::SMART_CARD_GUARD, "smart-card-readers"},
+    {ContentSettingsType::SMART_CARD_DATA, "smart-card-readers-data"},
 
     // Add new content settings here if a corresponding Javascript string
     // representation for it is not required, for example if the content setting
@@ -235,9 +237,6 @@
     {ContentSettingsType::FILE_SYSTEM_ACCESS_EXTENDED_PERMISSION, nullptr},
     {ContentSettingsType::TPCD_HEURISTICS_GRANTS, nullptr},
     {ContentSettingsType::FILE_SYSTEM_ACCESS_RESTORE_PERMISSION, nullptr},
-    // TODO(crbug.com/40275778): Update name once UI design is done.
-    {ContentSettingsType::SMART_CARD_GUARD, nullptr},
-    {ContentSettingsType::SMART_CARD_DATA, nullptr},
     {ContentSettingsType::TOP_LEVEL_TPCD_TRIAL, nullptr},
     {ContentSettingsType::SUB_APP_INSTALLATION_PROMPTS, nullptr},
     {ContentSettingsType::DIRECT_SOCKETS, nullptr},
diff --git a/chrome/browser/ui/webui/signin/BUILD.gn b/chrome/browser/ui/webui/signin/BUILD.gn
index c1aa5e7..9651bed 100644
--- a/chrome/browser/ui/webui/signin/BUILD.gn
+++ b/chrome/browser/ui/webui/signin/BUILD.gn
@@ -42,6 +42,9 @@
 
   if (!is_chromeos_ash) {
     sources += [ "signin_email_confirmation_dialog.cc" ]
-    deps += [ "//chrome/common" ]
+    deps += [
+      "//chrome/browser/ui/webui",
+      "//chrome/common",
+    ]
   }
 }
diff --git a/chrome/browser/ui/webui/top_chrome/BUILD.gn b/chrome/browser/ui/webui/top_chrome/BUILD.gn
index 97a83d8f..af1fc3a 100644
--- a/chrome/browser/ui/webui/top_chrome/BUILD.gn
+++ b/chrome/browser/ui/webui/top_chrome/BUILD.gn
@@ -17,15 +17,12 @@
     "webui_contents_warmup_level.h",
     "webui_contents_warmup_level_recorder.h",
     "webui_contents_wrapper.h",
-    "webui_contents_wrapper_service.h",
-    "webui_contents_wrapper_service_factory.h",
   ]
 
   public_deps = [
     "//base",
     "//chrome/browser/profiles:profile",
     "//chrome/browser/ui:webui_name_variants",
-    "//components/keyed_service/core",
     "//content/public/browser",
     "//ui/base",
     "//ui/webui",
@@ -51,8 +48,6 @@
     "webui_contents_warmup_level.cc",
     "webui_contents_warmup_level_recorder.cc",
     "webui_contents_wrapper.cc",
-    "webui_contents_wrapper_service.cc",
-    "webui_contents_wrapper_service_factory.cc",
   ]
 
   deps = [
diff --git a/chrome/browser/ui/webui/top_chrome/webui_contents_wrapper_service.cc b/chrome/browser/ui/webui/top_chrome/webui_contents_wrapper_service.cc
deleted file mode 100644
index 7cd59907..0000000
--- a/chrome/browser/ui/webui/top_chrome/webui_contents_wrapper_service.cc
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/webui/top_chrome/webui_contents_wrapper_service.h"
-
-#include "chrome/browser/profiles/profile.h"
-#include "url/gurl.h"
-
-WebUIContentsWrapperService::WebUIContentsWrapperService(Profile* profile)
-    : profile_(profile) {}
-
-WebUIContentsWrapperService::~WebUIContentsWrapperService() = default;
-
-void WebUIContentsWrapperService::Shutdown() {
-  for (auto& webui_contents : web_contents_map_) {
-    webui_contents.second->CloseUI();
-    DCHECK(!webui_contents.second->GetHost());
-  }
-  web_contents_map_.clear();
-}
-
-WebUIContentsWrapper*
-WebUIContentsWrapperService::GetWebUIContentsWrapperFromURL(
-    const GURL& webui_url) {
-  auto it = web_contents_map_.find(webui_url.host());
-  return it == web_contents_map_.end() ? nullptr : it->second.get();
-}
diff --git a/chrome/browser/ui/webui/top_chrome/webui_contents_wrapper_service.h b/chrome/browser/ui/webui/top_chrome/webui_contents_wrapper_service.h
deleted file mode 100644
index 8eee895..0000000
--- a/chrome/browser/ui/webui/top_chrome/webui_contents_wrapper_service.h
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_WEBUI_TOP_CHROME_WEBUI_CONTENTS_WRAPPER_SERVICE_H_
-#define CHROME_BROWSER_UI_WEBUI_TOP_CHROME_WEBUI_CONTENTS_WRAPPER_SERVICE_H_
-
-#include <memory>
-#include <string>
-
-#include "base/containers/flat_map.h"
-#include "base/memory/raw_ptr.h"
-#include "chrome/browser/ui/webui/top_chrome/webui_contents_wrapper.h"
-#include "components/keyed_service/core/keyed_service.h"
-
-class GURL;
-class Profile;
-
-// This service maintains a 1-to-1 mapping of WebUIContentsWrapper to WebUI URL
-// hostname for a given profile. This allows multiple WebUI bubbles across
-// profile windows to share the same WebUIContentsWrapper instance, minimizing
-// the resource cost of persisting the wrapped WebContents. Persisting a
-// WebContents is done to improve initialization delays for WebUI bubbles.
-// A KeyedService is used to ensure any references to the Profile from the
-// wrapped WebContents instances are removed before Profile destruction.
-class WebUIContentsWrapperService : public KeyedService {
- public:
-  explicit WebUIContentsWrapperService(Profile* profile);
-  ~WebUIContentsWrapperService() override;
-
-  template <typename T>
-  void InitWebUIContentsWrapper(const GURL& webui_url,
-                                 int task_manager_string_id) {
-    // If replacing an existing WebUIContentsWrapper make sure it has no
-    // associated host.
-    auto it = web_contents_map_.find(webui_url.host());
-    if (it != web_contents_map_.end() && it->second->GetHost()) {
-      it->second->CloseUI();
-      DCHECK(!it->second->GetHost());
-    }
-
-    auto contents_wrapper = std::make_unique<WebUIContentsWrapperT<T>>(
-        webui_url, profile_, task_manager_string_id);
-    web_contents_map_.insert({webui_url.host(), std::move(contents_wrapper)});
-  }
-
-  void Shutdown() override;
-
-  WebUIContentsWrapper* GetWebUIContentsWrapperFromURL(const GURL& webui_url);
-
- private:
-  using WebContentsMap =
-      base::flat_map<std::string, std::unique_ptr<WebUIContentsWrapper>>;
-
-  // Profile associated with this service.
-  const raw_ptr<Profile> profile_;
-
-  // Associates WebUIContentsWrapper instances with their WebUI URL hostname.
-  WebContentsMap web_contents_map_;
-};
-
-#endif  // CHROME_BROWSER_UI_WEBUI_TOP_CHROME_WEBUI_CONTENTS_WRAPPER_SERVICE_H_
diff --git a/chrome/browser/ui/webui/top_chrome/webui_contents_wrapper_service_factory.cc b/chrome/browser/ui/webui/top_chrome/webui_contents_wrapper_service_factory.cc
deleted file mode 100644
index 44d8b57..0000000
--- a/chrome/browser/ui/webui/top_chrome/webui_contents_wrapper_service_factory.cc
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/webui/top_chrome/webui_contents_wrapper_service_factory.h"
-
-#include "base/no_destructor.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/webui/top_chrome/webui_contents_wrapper_service.h"
-
-// static
-WebUIContentsWrapperService*
-WebUIContentsWrapperServiceFactory::GetForProfile(Profile* profile,
-                                                   bool create_if_necessary) {
-  return static_cast<WebUIContentsWrapperService*>(
-      GetInstance()->GetServiceForBrowserContext(profile, create_if_necessary));
-}
-
-// static
-WebUIContentsWrapperServiceFactory*
-WebUIContentsWrapperServiceFactory::GetInstance() {
-  static base::NoDestructor<WebUIContentsWrapperServiceFactory> factory;
-  return factory.get();
-}
-
-WebUIContentsWrapperServiceFactory::WebUIContentsWrapperServiceFactory()
-    : ProfileKeyedServiceFactory(
-          "WebUIContentsWrapperService",
-          ProfileSelections::Builder()
-              .WithRegular(ProfileSelection::kOriginalOnly)
-              // TODO(crbug.com/40257657): Check if this service is needed in
-              // Guest mode.
-              .WithGuest(ProfileSelection::kOriginalOnly)
-              // TODO(crbug.com/41488885): Check if this service is needed for
-              // Ash Internals.
-              .WithAshInternals(ProfileSelection::kOriginalOnly)
-              .Build()) {}
-
-std::unique_ptr<KeyedService>
-WebUIContentsWrapperServiceFactory::BuildServiceInstanceForBrowserContext(
-    content::BrowserContext* context) const {
-  return std::make_unique<WebUIContentsWrapperService>(
-      Profile::FromBrowserContext(context));
-}
-
-WebUIContentsWrapperServiceFactory::~WebUIContentsWrapperServiceFactory() =
-    default;
diff --git a/chrome/browser/ui/webui/top_chrome/webui_contents_wrapper_service_factory.h b/chrome/browser/ui/webui/top_chrome/webui_contents_wrapper_service_factory.h
deleted file mode 100644
index 09987323..0000000
--- a/chrome/browser/ui/webui/top_chrome/webui_contents_wrapper_service_factory.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_WEBUI_TOP_CHROME_WEBUI_CONTENTS_WRAPPER_SERVICE_FACTORY_H_
-#define CHROME_BROWSER_UI_WEBUI_TOP_CHROME_WEBUI_CONTENTS_WRAPPER_SERVICE_FACTORY_H_
-
-#include "base/no_destructor.h"
-#include "chrome/browser/profiles/profile_keyed_service_factory.h"
-
-class WebUIContentsWrapperService;
-class Profile;
-
-class WebUIContentsWrapperServiceFactory : public ProfileKeyedServiceFactory {
- public:
-  static WebUIContentsWrapperService* GetForProfile(Profile* profile,
-                                                    bool create_if_necessary);
-  static WebUIContentsWrapperServiceFactory* GetInstance();
-
-  WebUIContentsWrapperServiceFactory(
-      const WebUIContentsWrapperServiceFactory&) = delete;
-  WebUIContentsWrapperServiceFactory& operator=(
-      const WebUIContentsWrapperServiceFactory&) = delete;
-
- private:
-  friend base::NoDestructor<WebUIContentsWrapperServiceFactory>;
-
-  WebUIContentsWrapperServiceFactory();
-  ~WebUIContentsWrapperServiceFactory() override;
-
-  // BrowserContextKeyedServiceFactory:
-  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
-      content::BrowserContext* context) const override;
-};
-
-#endif  // CHROME_BROWSER_UI_WEBUI_TOP_CHROME_WEBUI_CONTENTS_WRAPPER_SERVICE_FACTORY_H_
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index dafa706..1e4e68473 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1726005491-94846b5fbb8dfdbf78a27603b96b29f3b01b0ef6-1d38fb86a4ab7a2652d28109e7afbbe64d921e23.profdata
+chrome-mac-arm-main-1726036975-62469123f3b16861e65525e70c02429e9f90c84e-9ba8dc9b39452f50fa7cba992aaa68bb505f63b8.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index 2b9059852..1579b46e 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1725991190-5286f368172fa4432169f41b9b3e563221792c81-b34b7c4498378ea2312efe9ff3a0ae23127c4dca.profdata
+chrome-mac-main-1726012499-547c9008eea4fee55209c02e8283f4176d4f0624-91acefc7c413109996a65a3482da480d80d0276a.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index d8481a2..868ffdb 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1726001946-70d4753af0df4f22539a2b86cc77ba912d13906c-d6371ec593dc342c2ee18517e9ef52aaea6908b6.profdata
+chrome-win32-main-1726034234-88cd7738056b2b329b699e4c33469f07eeb57ad0-bb608df17366e5cd7d6399d8fdb7460b18bc27fa.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 6b422e8..8f9603c 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1725991190-4329617499220518a9a3a806e07078c4dd382c5b-b34b7c4498378ea2312efe9ff3a0ae23127c4dca.profdata
+chrome-win64-main-1726023451-f71e5c4c3b336958b823cc7f01beb2547a58ef1e-7e9682e58ca8bf9081b51e89a893a12c1e3bca58.profdata
diff --git a/chrome/renderer/DEPS b/chrome/renderer/DEPS
index 5fbf3908..5265466 100644
--- a/chrome/renderer/DEPS
+++ b/chrome/renderer/DEPS
@@ -31,6 +31,7 @@
   "+components/history_clusters/core/config.h",
   "+components/heap_profiling/in_process/heap_profiler_controller.h",
   "+components/language/core/common",
+  "+components/language_detection/core",
   "+components/lens/lens_metadata.mojom.h",
   "+components/metrics/call_stacks/call_stack_profile_builder.h",
   "+components/nacl/common",
diff --git a/chrome/renderer/chrome_render_frame_observer_unittest.cc b/chrome/renderer/chrome_render_frame_observer_unittest.cc
index 43b6ab0a..1f19bf7 100644
--- a/chrome/renderer/chrome_render_frame_observer_unittest.cc
+++ b/chrome/renderer/chrome_render_frame_observer_unittest.cc
@@ -4,11 +4,19 @@
 
 #include "chrome/renderer/chrome_render_frame_observer.h"
 
+#include "base/test/scoped_feature_list.h"
 #include "chrome/common/chrome_render_frame.mojom.h"
+#include "components/language_detection/core/features.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-class ChromeRenderFrameObserverTest : public testing::Test {
+class ChromeRenderFrameObserverTest : public testing::Test,
+                                      public testing::WithParamInterface<bool> {
  public:
+  ChromeRenderFrameObserverTest() {
+    scoped_feature_list_.InitWithFeatureState(
+        language_detection::features::kLazyUpdateTranslateModel, GetParam());
+  }
+
   bool NeedsDownscale(const gfx::Size& original_image_size,
                       int32_t requested_image_min_area_pixels,
                       const gfx::Size& requested_image_max_size) {
@@ -26,9 +34,14 @@
   bool IsAnimatedWebp(const std::vector<uint8_t> image_data) {
     return ChromeRenderFrameObserver::IsAnimatedWebp(image_data);
   }
+
+ protected:
+  base::test::ScopedFeatureList scoped_feature_list_;
 };
 
-TEST_F(ChromeRenderFrameObserverTest,
+INSTANTIATE_TEST_SUITE_P(All, ChromeRenderFrameObserverTest, testing::Bool());
+
+TEST_P(ChromeRenderFrameObserverTest,
        NeedsDownscale_RequestLargeThanOriginalReturnFalse) {
   EXPECT_FALSE(
       NeedsDownscale(/* original_image_size */ gfx::Size(10, 10),
@@ -36,27 +49,27 @@
                      /* requested_image_max_size */ gfx::Size(20, 20)));
 }
 
-TEST_F(ChromeRenderFrameObserverTest, NeedsDownscale_SameSizeReturnFalse) {
+TEST_P(ChromeRenderFrameObserverTest, NeedsDownscale_SameSizeReturnFalse) {
   EXPECT_FALSE(
       NeedsDownscale(/* original_image_size */ gfx::Size(10, 10),
                      /* requested_image_min_area_pixels */ 100,
                      /* requested_image_max_size */ gfx::Size(10, 10)));
 }
 
-TEST_F(ChromeRenderFrameObserverTest, NeedsDownscale_OnlyWidthShortReturnTrue) {
+TEST_P(ChromeRenderFrameObserverTest, NeedsDownscale_OnlyWidthShortReturnTrue) {
   EXPECT_TRUE(NeedsDownscale(/* original_image_size */ gfx::Size(10, 10),
                              /* requested_image_min_area_pixels */ 100,
                              /* requested_image_max_size */ gfx::Size(9, 10)));
 }
 
-TEST_F(ChromeRenderFrameObserverTest, NeedsDownscale_OnlyAreaSmallReturnFalse) {
+TEST_P(ChromeRenderFrameObserverTest, NeedsDownscale_OnlyAreaSmallReturnFalse) {
   EXPECT_FALSE(
       NeedsDownscale(/* original_image_size */ gfx::Size(10, 10),
                      /* requested_image_min_area_pixels */ 20,
                      /* requested_image_max_size */ gfx::Size(20, 20)));
 }
 
-TEST_F(ChromeRenderFrameObserverTest, NeedsEncodeImage_JpegFormat) {
+TEST_P(ChromeRenderFrameObserverTest, NeedsEncodeImage_JpegFormat) {
   EXPECT_TRUE(
       NeedsEncodeImage(/* image_extension */ ".png",
                        /* image_format */ chrome::mojom::ImageFormat::JPEG));
@@ -74,7 +87,7 @@
                        /* image_format */ chrome::mojom::ImageFormat::JPEG));
 }
 
-TEST_F(ChromeRenderFrameObserverTest, NeedsEncodeImage_PngFormat) {
+TEST_P(ChromeRenderFrameObserverTest, NeedsEncodeImage_PngFormat) {
   EXPECT_FALSE(
       NeedsEncodeImage(/* image_extension */ ".png",
                        /* image_format */ chrome::mojom::ImageFormat::PNG));
@@ -92,7 +105,7 @@
                        /* image_format */ chrome::mojom::ImageFormat::PNG));
 }
 
-TEST_F(ChromeRenderFrameObserverTest, NeedsEncodeImage_WebpFormat) {
+TEST_P(ChromeRenderFrameObserverTest, NeedsEncodeImage_WebpFormat) {
   EXPECT_TRUE(
       NeedsEncodeImage(/* image_extension */ ".png",
                        /* image_format */ chrome::mojom::ImageFormat::WEBP));
@@ -110,7 +123,7 @@
                        /* image_format */ chrome::mojom::ImageFormat::WEBP));
 }
 
-TEST_F(ChromeRenderFrameObserverTest, NeedsEncodeImage_OriginalFormat) {
+TEST_P(ChromeRenderFrameObserverTest, NeedsEncodeImage_OriginalFormat) {
   EXPECT_FALSE(NeedsEncodeImage(
       /* image_extension */ ".png",
       /* image_format */ chrome::mojom::ImageFormat::ORIGINAL));
@@ -128,7 +141,7 @@
       /* image_format */ chrome::mojom::ImageFormat::ORIGINAL));
 }
 
-TEST_F(ChromeRenderFrameObserverTest,
+TEST_P(ChromeRenderFrameObserverTest,
        IsAnimatedWebp_HeaderTooSmall_ReturnsFalse) {
   // First 10 bytes taken from a real animated webp image.
   const std::vector<uint8_t> broken_image_data{82, 73, 70, 70, 228,
@@ -136,7 +149,7 @@
   EXPECT_FALSE(IsAnimatedWebp(broken_image_data));
 }
 
-TEST_F(ChromeRenderFrameObserverTest, IsAnimatedWebp_StaticWebp_ReturnsFalse) {
+TEST_P(ChromeRenderFrameObserverTest, IsAnimatedWebp_StaticWebp_ReturnsFalse) {
   // First 75 bytes taken from a real animated webp image.
   const std::vector<uint8_t> static_webp_image_data{
       82,  73,  70,  70,  88,  59,  1,   0,   87,  69,  66,  80,  86,
@@ -148,7 +161,7 @@
   EXPECT_FALSE(IsAnimatedWebp(static_webp_image_data));
 }
 
-TEST_F(ChromeRenderFrameObserverTest, IsAnimatedWebp_Jpeg_ReturnsFalse) {
+TEST_P(ChromeRenderFrameObserverTest, IsAnimatedWebp_Jpeg_ReturnsFalse) {
   // First 75 bytes taken from a real jpeg image.
   const std::vector<uint8_t> jpeg_image_data{
       255, 216, 255, 224, 0,  16,  74,  70,  73,  70, 0,  1,  1,  1,   0,
@@ -159,7 +172,7 @@
   EXPECT_FALSE(IsAnimatedWebp(jpeg_image_data));
 }
 
-TEST_F(ChromeRenderFrameObserverTest, IsAnimatedWebp_AnimatedWebp_ReturnsTrue) {
+TEST_P(ChromeRenderFrameObserverTest, IsAnimatedWebp_AnimatedWebp_ReturnsTrue) {
   // First 75 bytes taken from a real animated webp image.
   const std::vector<uint8_t> animated_webp_image_data{
       82, 73, 70, 70, 228, 26, 0, 0, 87,  69,  66,  80,  86,  80,  56,
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index ed21987..2dd1196 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -360,6 +360,7 @@
     public_deps += [
       "//apps:test_support",
       "//chrome/browser/extensions:test_support",
+      "//chrome/browser/ui/autofill:test_support",
       "//chrome/common/extensions/api",
       "//components/guest_view/browser:test_support",
       "//extensions:test_support",
@@ -664,7 +665,6 @@
     ]
 
     sources += [
-      "../browser/ui/autofill/autofill_keyboard_accessory_controller_impl_test_api.h",
       "../browser/webapps/installable/ml_promotion_browsertest_base.cc",
       "../browser/webapps/installable/ml_promotion_browsertest_base.h",
     ]
@@ -749,9 +749,6 @@
       "../browser/sync_file_system/mock_remote_file_sync_service.h",
       "../browser/themes/test/theme_service_changed_waiter.cc",
       "../browser/themes/test/theme_service_changed_waiter.h",
-      "../browser/ui/autofill/autofill_popup_controller_impl_test_api.h",
-      "../browser/ui/autofill/mock_autofill_popup_controller.cc",
-      "../browser/ui/autofill/mock_autofill_popup_controller.h",
       "../browser/ui/performance_controls/test_support/battery_saver_browser_test_mixin.h",
       "../browser/ui/performance_controls/test_support/memory_metrics_refresh_waiter.cc",
       "../browser/ui/performance_controls/test_support/memory_metrics_refresh_waiter.h",
@@ -1973,6 +1970,7 @@
       "//chrome/browser/ui:ui_features",
       "//chrome/browser/ui:ui_features",
       "//chrome/browser/ui/apps",
+      "//chrome/browser/ui/autofill:browser_tests",
       "//chrome/browser/ui/autofill/payments:browser_tests",
       "//chrome/browser/ui/blocked_content",
       "//chrome/browser/ui/blocked_content:browser_tests",
@@ -2719,6 +2717,7 @@
       "../browser/invalidation/profile_invalidation_provider_factory_browsertest.cc",
       "../browser/k_anonymity_service/k_anonymity_service_client_browsertest.cc",
       "../browser/l10n_util_browsertest.cc",
+      "../browser/language_detection/language_detection_service_browsertest.cc",
       "../browser/launch_time_navigation_signal/launch_time_navigation_signal_browsertest.cc",
       "../browser/lifetime/browser_close_manager_browsertest.cc",
       "../browser/lifetime/browser_shutdown_browsertest.cc",
@@ -3038,10 +3037,9 @@
       "../browser/tpcd/metadata/manager_browsertest.cc",
       "../browser/tpcd/support/top_level_trial_service_browsertest.cc",
       "../browser/tracing/chrome_tracing_delegate_browsertest.cc",
-      "../browser/translate/language_detection_service_browsertest.cc",
+      "../browser/translate/language_detection_model_service_browsertest.cc",
       "../browser/translate/translate_frame_binder_browsertest.cc",
       "../browser/translate/translate_manager_browsertest.cc",
-      "../browser/translate/translate_model_service_browsertest.cc",
       "../browser/trusted_vault/trusted_vault_encryption_keys_tab_helper_browsertest.cc",
       "../browser/ui/ask_google_for_suggestions_dialog_browsertest.cc",
       "../browser/ui/bookmarks/bookmark_browsertest.cc",
@@ -3361,7 +3359,6 @@
         # lacros_chrome_browsertests below.
         "../browser/media/webrtc/capture_handle_browsertest.cc",
         "../browser/media/webrtc/webrtc_getdisplaymedia_browsertest.cc",
-        "../browser/ui/autofill/autofill_context_menu_manager_browsertest.cc",
         "../browser/ui/views/intent_picker_bubble_view_browsertest.cc",
         "../browser/ui/views/location_bar/intent_chip_button_browsertest.cc",
         "../browser/ui/views/tabs/alert_indicator_button_browsertest.cc",
@@ -3853,7 +3850,6 @@
         "../browser/signin/dice_browsertest.cc",
         "../browser/signin/dice_web_signin_interceptor_browsertest.cc",
         "../browser/signin/signin_ui_util_browsertest.cc",
-        "../browser/ui/autofill/autofill_signin_promo_tab_helper_browsertest.cc",
         "../browser/ui/profiles/signin_intercept_first_run_experience_dialog_browsertest.cc",
         "../browser/ui/views/sync/inline_login_ui_browsertest.cc",
         "../browser/unified_consent/unified_consent_browsertest.cc",
@@ -4654,6 +4650,7 @@
         "//chrome/browser/lens/core/mojom:mojo_bindings",
         "//chrome/browser/ui/actions:actions",
         "//chrome/browser/ui/actions:actions_headers",
+        "//chrome/browser/ui/autofill:test_support",
         "//chrome/browser/ui/commerce",
         "//chrome/browser/ui/commerce:browser_tests",
         "//chrome/browser/ui/commerce:test_support",
@@ -5522,7 +5519,6 @@
       "../browser/sync/test/lacros/sync_apps_toggle_sharing_lacros_browsertest.cc",
       "../browser/sync/test/lacros/sync_custom_passphrase_sharing_lacros_browsertest.cc",
       "../browser/sync/test/lacros/trusted_vault_keys_sharing_lacros_browsertest.cc",
-      "../browser/ui/autofill/autofill_context_menu_manager_lacros_browsertest.cc",
       "../browser/ui/browser_navigator_browsertest.cc",
       "../browser/ui/browser_navigator_browsertest.h",
       "../browser/ui/browser_navigator_browsertest_chromeos.cc",
@@ -5595,6 +5591,7 @@
       "//chrome/browser/themes",
       "//chrome/browser/ui:browser_element_identifiers",
       "//chrome/browser/ui:browser_navigator_params_headers",
+      "//chrome/browser/ui/autofill:lacros_chrome_browsertests",
       "//chrome/browser/ui/chromeos",
       "//chrome/browser/ui/chromeos:test_support",
       "//chrome/browser/ui/web_applications:app_service_browser_tests",
@@ -6361,9 +6358,6 @@
     "../browser/translate/fake_translate_agent.h",
     "../browser/translate/translate_service_unittest.cc",
     "../browser/trusted_vault/trusted_vault_encryption_keys_tab_helper_unittest.cc",
-    "../browser/ui/autofill/autofill_client_provider_unittest.cc",
-    "../browser/ui/autofill/autofill_suggestion_controller_unittest.cc",
-    "../browser/ui/autofill/chrome_autofill_client_unittest.cc",
     "../browser/ui/chrome_select_file_policy_unittest.cc",
     "../browser/ui/file_system_access/file_system_access_dangerous_file_dialog_unittest.cc",
     "../browser/ui/file_system_access/file_system_access_permission_dialog_unittest.cc",
@@ -6438,7 +6432,6 @@
       "../browser/site_protection/site_protection_metrics_observer_unittest.cc",
       "../browser/ssl/generated_https_first_mode_pref_unittest.cc",
       "../browser/supervised_user/supervised_user_verification_page_unittest.cc",
-      "../browser/ui/autofill/autofill_popup_controller_impl_unittest.cc",
       "../browser/ui/download/download_bubble_row_list_view_info_unittest.cc",
       "../browser/ui/download/download_bubble_row_view_info_unittest.cc",
       "../browser/ui/download/download_bubble_security_view_info_unittest.cc",
@@ -6687,11 +6680,14 @@
     "//chrome/browser/ui:browser_element_identifiers",
     "//chrome/browser/ui:test_support",
     "//chrome/browser/ui:ui_features",
+    "//chrome/browser/ui/autofill:test_support",
+    "//chrome/browser/ui/autofill:unit_tests",
     "//chrome/browser/ui/autofill/payments",
     "//chrome/browser/ui/autofill/payments:unit_tests",
     "//chrome/browser/ui/blocked_content:unit_tests",
     "//chrome/browser/ui/color:color_headers",
     "//chrome/browser/ui/find_bar:unit_tests",
+    "//chrome/browser/ui/webui",
     "//chrome/browser/updates/announcement_notification:unit_tests",
     "//chrome/browser/web_share_target:unit_tests",
     "//chrome/common:test_support",
@@ -6784,6 +6780,7 @@
     "//components/ip_protection:browser",
     "//components/ip_protection:ip_protection",
     "//components/language/core/browser",
+    "//components/language_detection/core:language_detection",
     "//components/lens",
     "//components/leveldb_proto:test_support",
     "//components/live_caption:constants",
@@ -7331,7 +7328,6 @@
       "../browser/signin/dice_web_signin_interceptor_unittest.cc",
       "../browser/signin/logout_tab_helper_unittest.cc",
       "../browser/signin/process_dice_header_delegate_impl_unittest.cc",
-      "../browser/ui/autofill/autofill_bubble_signin_promo_controller_unittest.cc",
       "../browser/ui/startup/first_run_service_unittest.cc",
       "../browser/ui/startup/startup_browser_policy_unittest.cc",
       "../browser/ui/views/profiles/dice_web_signin_interception_bubble_view_unittest.cc",
@@ -7494,7 +7490,6 @@
       "../browser/ui/android/tab_model/tab_model_list_unittest.cc",
       "../browser/ui/android/toolbar/adaptive_toolbar_bridge_unittest.cc",
       "../browser/ui/android/toolbar/location_bar_model_android_unittest.cc",
-      "../browser/ui/autofill/autofill_keyboard_accessory_controller_impl_unittest.cc",
       "../browser/ui/fast_checkout/fast_checkout_controller_impl_unittest.cc",
       "../browser/ui/safety_hub/password_status_check_result_android_unittest.cc",
       "../browser/wallet/android/boarding_pass_detector_unittest.cc",
@@ -7804,14 +7799,6 @@
       "../browser/themes/theme_service_unittest.cc",
       "../browser/themes/theme_syncable_service_unittest.cc",
       "../browser/translate/translate_manager_render_view_host_unittest.cc",
-      "../browser/ui/autofill/add_new_address_bubble_controller_unittest.cc",
-      "../browser/ui/autofill/address_bubbles_controller_unittest.cc",
-      "../browser/ui/autofill/address_editor_controller_unittest.cc",
-      "../browser/ui/autofill/autofill_field_promo_controller_impl_unittest.cc",
-      "../browser/ui/autofill/delete_address_profile_dialog_controller_impl_unittest.cc",
-      "../browser/ui/autofill/edit_address_profile_dialog_controller_impl_unittest.cc",
-      "../browser/ui/autofill/save_address_bubble_controller_unittest.cc",
-      "../browser/ui/autofill/update_address_bubble_controller_unittest.cc",
       "../browser/ui/bookmarks/bookmark_context_menu_controller_unittest.cc",
       "../browser/ui/bookmarks/bookmark_drag_drop_unittest.cc",
       "../browser/ui/bookmarks/bookmark_editor_unittest.cc",
@@ -7948,6 +7935,7 @@
       "../browser/ui/views/autofill/add_new_address_bubble_view_unittest.cc",
       "../browser/ui/views/autofill/address_editor_view_unittest.cc",
       "../browser/ui/views/autofill/autofill_field_promo_view_impl_unittest.cc",
+      "../browser/ui/views/autofill/autofill_prediction_improvements/save_autofill_prediction_improvements_bubble_view_unittest.cc",
       "../browser/ui/views/autofill/edit_address_profile_view_unittest.cc",
       "../browser/ui/views/autofill/save_address_profile_view_unittest.cc",
       "../browser/ui/views/autofill/update_address_profile_view_unittest.cc",
@@ -9754,6 +9742,7 @@
       "../browser/enterprise/connectors/device_trust/signals/decorators/common",
       "../browser/enterprise/connectors/device_trust/signals/decorators/common:test_support",
       "../browser/enterprise/connectors/device_trust/signals/decorators/common:unit_tests",
+      "//chrome/browser/ui/device_signals_consent:test_support",
       "//components/device_signals/core/browser",
       "//components/device_signals/core/browser:test_support",
       "//components/device_signals/core/common",
@@ -10397,13 +10386,7 @@
 
 static_library("test_support_unit") {
   testonly = true
-  sources = [
-    "../browser/ui/autofill/autofill_suggestion_controller_test_base.cc",
-    "../browser/ui/autofill/autofill_suggestion_controller_test_base.h",
-    "../browser/ui/autofill/mock_autofill_popup_view.cc",
-    "../browser/ui/autofill/mock_autofill_popup_view.h",
-    "base/run_all_unittests.cc",
-  ]
+  sources = [ "base/run_all_unittests.cc" ]
 
   public_deps = [
     ":test_support",
@@ -10445,23 +10428,6 @@
     deps += [ "//chromeos/lacros:test_support" ]
   }
 
-  if (is_android) {
-    sources += [
-      "../browser/ui/autofill/mock_autofill_keyboard_accessory_view.cc",
-      "../browser/ui/autofill/mock_autofill_keyboard_accessory_view.h",
-      "../browser/ui/autofill/test_autofill_keyboard_accessory_controller_autofill_client.h",
-    ]
-
-    deps += [
-      "//chrome/browser/keyboard_accessory/test_utils/android",
-      "//chrome/browser/password_manager/android/access_loss:test_support",
-    ]
-  } else {
-    sources += [
-      "../browser/ui/autofill/test_autofill_popup_controller_autofill_client.h",
-    ]
-  }
-
   if (enable_bound_session_credentials) {
     sources += [
       "../browser/signin/bound_session_credentials/fake_bound_session_cookie_refresh_service.cc",
@@ -10614,6 +10580,7 @@
       "//chrome/browser/ui/signin",
       "//chrome/browser/ui/views/toolbar",
       "//chrome/browser/ui/webui",
+      "//chrome/browser/ui/webui:webui_util",
       "//chrome/browser/ui/webui/signin",
       "//chrome/browser/web_applications",
       "//chrome/browser/web_applications:web_applications_test_support",
@@ -10918,9 +10885,6 @@
       "../browser/site_isolation/site_per_process_interactive_browsertest.cc",
       "../browser/site_isolation/site_per_process_text_input_browsertest.cc",
       "../browser/ssl/typed_navigation_upgrade_throttle_browsertest.cc",
-      "../browser/ui/autofill/autofill_context_menu_manager_interactive_uitest.cc",
-      "../browser/ui/autofill/autofill_popup_controller_interactive_uitest.cc",
-      "../browser/ui/autofill/chrome_autofill_client_interactive_uitest.cc",
       "../browser/ui/browser_command_controller_interactive_browsertest.cc",
       "../browser/ui/browser_focus_uitest.cc",
       "../browser/ui/exclusive_access/fullscreen_controller_interactive_browsertest.cc",
@@ -11062,6 +11026,9 @@
       "//chrome/browser/ui:browser_element_identifiers",
       "//chrome/browser/ui:ui_features",
       "//chrome/browser/ui/apps",
+      "//chrome/browser/ui/autofill",
+      "//chrome/browser/ui/autofill:interactive_ui_tests",
+      "//chrome/browser/ui/autofill:test_support",
       "//chrome/browser/ui/autofill/payments:interactive_ui_tests",
       "//chrome/browser/ui/blocked_content:interactive_ui_tests",
       "//chrome/browser/ui/browser_window",
@@ -11287,9 +11254,6 @@
     if (toolkit_views) {
       sources += [
         "../browser/media/webrtc/conditional_focus_browsertest.cc",
-        "../browser/ui/autofill/address_bubbles_controller_interactive_uitest.cc",
-        "../browser/ui/autofill/delete_address_profile_dialog_controller_impl_interactive_uitest.cc",
-        "../browser/ui/autofill/edit_address_profile_dialog_controller_impl_interactive_uitest.cc",
         "../browser/ui/toolbar/app_menu_fullscreen_interactive_uitest.cc",
         "../browser/ui/toolbar/app_menu_model_interactive_uitest.cc",
         "../browser/ui/user_education/show_promo_in_page_interactive_uitest.cc",
@@ -12368,6 +12332,7 @@
       "//chrome/browser/autofill:test_support_ui",
       "//chrome/browser/devtools",
       "//chrome/browser/sync",
+      "//chrome/browser/ui/autofill",
       "//chrome/renderer",
       "//components/javascript_dialogs",
       "//components/resources",
diff --git a/chrome/test/data/webui/BUILD.gn b/chrome/test/data/webui/BUILD.gn
index 71c713f..6c1c8ea9 100644
--- a/chrome/test/data/webui/BUILD.gn
+++ b/chrome/test/data/webui/BUILD.gn
@@ -190,6 +190,7 @@
     "//chrome/browser/ui/lens",
     "//chrome/browser/ui/tabs",
     "//chrome/browser/ui/views/side_panel",
+    "//chrome/browser/ui/webui",
     "//chrome/test:test_support",
     "//components/bookmarks/browser",
     "//components/bookmarks/managed",
diff --git a/chrome/test/data/webui/chromeos/personalization_app/ambient_subpage_element_test.ts b/chrome/test/data/webui/chromeos/personalization_app/ambient_subpage_element_test.ts
index d1ce4ed8..cf7efcd 100644
--- a/chrome/test/data/webui/chromeos/personalization_app/ambient_subpage_element_test.ts
+++ b/chrome/test/data/webui/chromeos/personalization_app/ambient_subpage_element_test.ts
@@ -485,6 +485,8 @@
       });
 
   test('show Geolocation dialog and click allow', async () => {
+    personalizationStore.setReducersEnabled(true);
+
     ambientSubpageElement = await displayMainSettings(
         TopicSource.kArtGallery, TemperatureUnit.kFahrenheit,
         /*ambientModeEnabled=*/ true);
@@ -496,8 +498,7 @@
     // Enable Privacy Hub feature flag.
     loadTimeData.overrideValues({isCrosPrivacyHubLocationEnabled: true});
 
-    // Disable geolocation and select Auto Schedule; This should show the
-    // warning message.
+    // Disable geolocation; this should show the warning message.
     personalizationStore.data.ambient.geolocationPermissionEnabled = false;
     personalizationStore.notifyObservers();
     await waitAfterNextRender(ambientSubpageElement);
@@ -526,7 +527,6 @@
 
     // Confirm the dialog; this should enable the geolocation permission,
     // resulting in both the dialog and warning text disappearing.
-    personalizationStore.setReducersEnabled(true);
     personalizationStore.expectAction(
         AmbientActionName.SET_GEOLOCATION_PERMISSION_ENABLED);
     confirmButton.click();
@@ -548,6 +548,49 @@
     assertFalse(!!geolocationDialog);
   });
 
+  test('show Geolocation warning text when location is managed', async () => {
+    // Enable Privacy Hub feature flag.
+    loadTimeData.overrideValues({isCrosPrivacyHubLocationEnabled: true});
+
+    personalizationStore.setReducersEnabled(true);
+
+    ambientSubpageElement = await displayMainSettings(
+        TopicSource.kArtGallery, TemperatureUnit.kFahrenheit,
+        /*ambientModeEnabled=*/ true);
+
+    const weatherUnit =
+        ambientSubpageElement.shadowRoot!.querySelector('ambient-weather-unit');
+    assertTrue(!!weatherUnit);
+    // Check no warning is shown by default.
+    let warningElement =
+        weatherUnit!.shadowRoot!.getElementById('geolocationWarningDiv');
+    assertFalse(!!warningElement);
+
+
+    // Disable geolocation and mark as unmodifiable by the user. This happens
+    // when the respective setting is policy-set.
+    personalizationStore.data.ambient.geolocationPermissionEnabled = false;
+    personalizationStore.data.ambient.geolocationIsUserModifiable = false;
+    personalizationStore.notifyObservers();
+    await waitAfterNextRender(ambientSubpageElement);
+
+    // Check warning message is present.
+    warningElement =
+        weatherUnit!.shadowRoot!.getElementById('geolocationWarningDiv');
+    assertTrue(!!warningElement);
+
+    // Check that managed icon is present.
+    assertTrue(!!warningElement.querySelector('cr-policy-indicator'));
+
+    // Check that users are not prompted to change location.
+    assertFalse(!!warningElement.querySelector('localized-link'));
+
+    // Check the displayed string.
+    assertEquals(
+        ambientSubpageElement.i18n('geolocationWarningManagedTextForWeather'),
+        warningElement.innerText);
+  });
+
   test('duration is default to ten minutes', async () => {
     ambientSubpageElement = await displayMainSettings(
         TopicSource.kArtGallery, TemperatureUnit.kFahrenheit,
diff --git a/chrome/test/data/webui/chromeos/personalization_app/test_ambient_interface_provider.ts b/chrome/test/data/webui/chromeos/personalization_app/test_ambient_interface_provider.ts
index 8776b93..254d59c 100644
--- a/chrome/test/data/webui/chromeos/personalization_app/test_ambient_interface_provider.ts
+++ b/chrome/test/data/webui/chromeos/personalization_app/test_ambient_interface_provider.ts
@@ -67,6 +67,7 @@
 
   shouldShowBanner: boolean = true;
   geolocationEnabled: boolean = true;
+  geolocationIsUserModifiable: boolean = true;
 
   previews: Url[] = [
     {url: 'http://preview0'},
@@ -91,6 +92,7 @@
       'shouldShowTimeOfDayBanner',
       'handleTimeOfDayBannerDismissed',
       'isGeolocationEnabledForSystemServices',
+      'isGeolocationUserModifiable',
       'enableGeolocationForSystemServices',
     ]);
   }
@@ -171,6 +173,13 @@
     return Promise.resolve({geolocationEnabled: this.geolocationEnabled});
   }
 
+  isGeolocationUserModifiable():
+      Promise<{geolocationIsUserModifiable: boolean}> {
+    this.methodCalled('isGeolocationUserModifiable');
+    return Promise.resolve(
+        {geolocationIsUserModifiable: this.geolocationIsUserModifiable});
+  }
+
   enableGeolocationForSystemServices() {
     this.geolocationEnabled = true;
     this.methodCalled('enableGeolocationForSystemServices');
diff --git a/chrome/test/data/webui/lens/overlay/translate_button_test.ts b/chrome/test/data/webui/lens/overlay/translate_button_test.ts
index 0eae65a..8e69076e 100644
--- a/chrome/test/data/webui/lens/overlay/translate_button_test.ts
+++ b/chrome/test/data/webui/lens/overlay/translate_button_test.ts
@@ -26,6 +26,15 @@
   let testLanguageBrowserProxy: TestLanguageBrowserProxy;
   let metrics: MetricsTracker;
 
+  // Remove CSS transitions to prevent race conditions due to an element not
+  // being visible.
+  function disableCssTransitions(element: TranslateButtonElement) {
+    const sheet = new CSSStyleSheet();
+    sheet.insertRule('* { transition: none !important; }');
+    const shadow = element.shadowRoot!;
+    shadow.adoptedStyleSheets = [sheet];
+  }
+
   setup(async () => {
     // Resetting the HTML needs to be the first thing we do in setup to
     // guarantee that any singleton instances don't change while any UI is still
@@ -41,6 +50,7 @@
 
     overlayTranslateButtonElement = document.createElement('translate-button');
     document.body.appendChild(overlayTranslateButtonElement);
+    disableCssTransitions(overlayTranslateButtonElement);
     metrics = fakeMetricsPrivate();
     await flushTasks();
   });
@@ -51,7 +61,7 @@
     const focusRegionEventPromise =
         eventToPromise('focus-region', document.body);
     // Click the translate button to show the language picker.
-    overlayTranslateButtonElement.$.translateButton.click();
+    overlayTranslateButtonElement.$.translateEnableButton.click();
     // Clicking the translate button should focus the shimmer.
     const focusRegionEvent = await focusRegionEventPromise;
     assertEquals(
@@ -76,7 +86,7 @@
     // request.
     const unfocusRegionEventPromise =
         eventToPromise('unfocus-region', document.body);
-    overlayTranslateButtonElement.$.translateButton.click();
+    overlayTranslateButtonElement.$.translateDisableButton.click();
     // Clicking the translate button again should unfocus the shimmer.
     await unfocusRegionEventPromise;
     const unfocusRegionEvent = await unfocusRegionEventPromise;
@@ -115,7 +125,7 @@
         isVisible(overlayTranslateButtonElement.$.sourceLanguageButton));
 
     // Click the translate button to show the language picker.
-    overlayTranslateButtonElement.$.translateButton.click();
+    overlayTranslateButtonElement.$.translateEnableButton.click();
 
     // The source language button should be visible but the language picker menu
     // should not be visible.
@@ -136,7 +146,7 @@
         isVisible(overlayTranslateButtonElement.$.targetLanguageButton));
 
     // Click the translate button to show the language picker.
-    overlayTranslateButtonElement.$.translateButton.click();
+    overlayTranslateButtonElement.$.translateEnableButton.click();
 
     // The target language button should be visible but the language picker menu
     // should not be visible.
@@ -157,7 +167,7 @@
         isVisible(overlayTranslateButtonElement.$.sourceLanguageButton));
 
     // Click the translate button to show the language picker.
-    overlayTranslateButtonElement.$.translateButton.click();
+    overlayTranslateButtonElement.$.translateEnableButton.click();
 
     // The source language button should be visible but the language picker menu
     // should not be visible.
@@ -243,7 +253,7 @@
         isVisible(overlayTranslateButtonElement.$.targetLanguageButton));
 
     // Click the translate button to show the language picker.
-    overlayTranslateButtonElement.$.translateButton.click();
+    overlayTranslateButtonElement.$.translateEnableButton.click();
 
     // The target language button should be visible but the language picker menu
     // should not be visible.
@@ -314,7 +324,7 @@
     await waitAfterNextRender(overlayTranslateButtonElement);
 
     // Click the translate button to show the language picker.
-    overlayTranslateButtonElement.$.translateButton.click();
+    overlayTranslateButtonElement.$.translateEnableButton.click();
 
     // Source language should show the detected language.
     assertEquals(
diff --git a/chromeos/ash/components/emoji/emoji_search.cc b/chromeos/ash/components/emoji/emoji_search.cc
index 7a4e67b..279c2fc 100644
--- a/chromeos/ash/components/emoji/emoji_search.cc
+++ b/chromeos/ash/components/emoji/emoji_search.cc
@@ -40,9 +40,9 @@
 
 // Map from keyword -> sum of position weightings
 std::map<std::u16string, double, std::less<>> CombineSearchTerms(
-    base::span<const std::string> long_search_terms) {
+    base::span<const std::string_view> long_search_terms) {
   std::map<std::u16string, double, std::less<>> ret;
-  for (const std::string& long_string : long_search_terms) {
+  for (std::string_view long_string : long_search_terms) {
     std::vector<std::string_view> words = base::SplitStringPieceUsingSubstr(
         long_string, " ", base::WhitespaceHandling::TRIM_WHITESPACE,
         base::SplitResult::SPLIT_WANT_NONEMPTY);
@@ -55,61 +55,10 @@
 }
 
 // Convert a JSON file to a map from search term to emoji weighted by
-// position in keyword / name.
+// position in keyword / name, as well as storing names in `names`.
 void AddDataFromFileToMap(
     const int file_id_in_resources,
-    std::map<std::u16string, std::vector<EmojiSearchEntry>, std::less<>>& map) {
-  std::string json_string =
-      ui::ResourceBundle::GetSharedInstance().LoadDataResourceString(
-          file_id_in_resources);
-  // Can be empty in certain test environments.
-  if (json_string.empty()) {
-    CHECK_IS_TEST();
-    return;
-  }
-
-  // TODO(b/309343774): switch to JSON reading service
-  std::optional<base::Value> json = base::JSONReader::Read(json_string);
-  CHECK(json) << "parse failed for " << file_id_in_resources << ":"
-              << json_string << "EOF";
-  base::Value::List groups = std::move(*json).TakeList();
-  // TODO(b/309343774): Consider using json_value_converter
-  for (auto& group : groups) {
-    for (const auto& emoji : *group.GetDict().FindList("emoji")) {
-      const base::Value::Dict* base = emoji.GetDict().FindDict("base");
-      const std::string* emoji_string = base->FindString("string");
-      CHECK(emoji_string) << "All emoji should have names";
-      // Gather possible search terms for the emoji
-      std::vector<std::string> search_terms;
-      const base::Value::List* keywords = base->FindList("keywords");
-      if (keywords) {
-        search_terms.reserve(keywords->size());
-        for (const auto& keyword : *keywords) {
-          search_terms.push_back(keyword.GetString());
-        }
-      }
-      for (const auto& search_term : CombineSearchTerms(search_terms)) {
-        // Keywords have less weighting (0.25)
-        map[search_term.first].push_back(
-            EmojiSearchEntry{.weighting = 0.25 * search_term.second,
-                             .emoji_string = *emoji_string});
-      }
-      const std::string* name = base->FindString("name");
-      if (name) {
-        for (const auto& search_term : CombineSearchTerms({{*name}})) {
-          map[search_term.first].push_back(
-              // Name has full weighting (1.0)
-              EmojiSearchEntry{.weighting = 1 * search_term.second,
-                               .emoji_string = *emoji_string});
-        }
-      }
-    }
-  }
-}
-
-// Convert a JSON file to a map of emoji to name.
-void AddNamesFromFileToMap(
-    const int file_id_in_resources,
+    EmojiEntryMap& map,
     std::map<std::string, std::string, std::less<>>& names) {
   std::string json_string =
       ui::ResourceBundle::GetSharedInstance().LoadDataResourceString(
@@ -131,8 +80,29 @@
       const base::Value::Dict* base = emoji.GetDict().FindDict("base");
       const std::string* emoji_string = base->FindString("string");
       CHECK(emoji_string) << "All emoji should have names";
+      // Gather possible search terms for the emoji
+      std::vector<std::string_view> search_terms;
+      const base::Value::List* keywords = base->FindList("keywords");
+      if (keywords) {
+        search_terms.reserve(keywords->size());
+        for (const auto& keyword : *keywords) {
+          search_terms.push_back(keyword.GetString());
+        }
+      }
+      for (const auto& search_term : CombineSearchTerms(search_terms)) {
+        // Keywords have less weighting (0.25)
+        map[search_term.first].push_back(
+            EmojiSearchEntry{.weighting = 0.25 * search_term.second,
+                             .emoji_string = *emoji_string});
+      }
       const std::string* name = base->FindString("name");
       if (name) {
+        for (const auto& search_term : CombineSearchTerms({{*name}})) {
+          map[search_term.first].push_back(
+              // Name has full weighting (1.0)
+              EmojiSearchEntry{.weighting = 1 * search_term.second,
+                               .emoji_string = *emoji_string});
+        }
         names.emplace(*emoji_string, *name);
       }
     }
@@ -140,8 +110,7 @@
 }
 
 std::map<std::string_view, double> GetResultsFromMap(
-    const std::map<std::u16string, std::vector<EmojiSearchEntry>, std::less<>>&
-        map,
+    const EmojiEntryMap& map,
     base::span<const std::u16string_view> lowercase_words) {
   std::map<std::string_view, double> scored_emoji;
   for (const std::u16string_view lowercase_word : lowercase_words) {
@@ -412,29 +381,22 @@
   if (std::optional<EmojiLanguageResourceIds> resource_ids =
           GetLanguageResourceIds(*lang);
       resource_ids.has_value()) {
-    AddDataFromFileToMap(resource_ids->emoji_start_resource_id,
-                         new_data.emojis);
+    AddDataFromFileToMap(resource_ids->emoji_start_resource_id, new_data.emojis,
+                         new_data.names);
     AddDataFromFileToMap(resource_ids->emoji_remaining_resource_id,
-                         new_data.emojis);
-    AddDataFromFileToMap(resource_ids->symbols_resource_id, new_data.symbols);
+                         new_data.emojis, new_data.names);
+    AddDataFromFileToMap(resource_ids->symbols_resource_id, new_data.symbols,
+                         new_data.names);
 
 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
     AddDataFromFileToMap(resource_ids->emoji_internal_resource_id,
-                         new_data.emojis);
+                         new_data.emojis, new_data.names);
 #endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 
-    AddNamesFromFileToMap(resource_ids->emoji_start_resource_id,
-                          new_data.names);
-    AddNamesFromFileToMap(resource_ids->emoji_remaining_resource_id,
-                          new_data.names);
-    AddNamesFromFileToMap(resource_ids->symbols_resource_id, new_data.names);
-
     if (*lang == EmojiLanguageCode::kEn) {
       // Only English has Emoticons.
       AddDataFromFileToMap(IDR_EMOJI_PICKER_EMOTICON_ORDERING_JSON,
-                           new_data.emoticons);
-      AddNamesFromFileToMap(IDR_EMOJI_PICKER_EMOTICON_ORDERING_JSON,
-                            new_data.names);
+                           new_data.emoticons, new_data.names);
     }
   }
 
diff --git a/chromeos/ash/experiences/DEPS b/chromeos/ash/experiences/DEPS
new file mode 100644
index 0000000..3cbaa8f
--- /dev/null
+++ b/chromeos/ash/experiences/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+ui",
+]
diff --git a/chromeos/ash/experiences/idle_detector/BUILD.gn b/chromeos/ash/experiences/idle_detector/BUILD.gn
new file mode 100644
index 0000000..488ae00
--- /dev/null
+++ b/chromeos/ash/experiences/idle_detector/BUILD.gn
@@ -0,0 +1,21 @@
+# Copyright 2024 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/chromeos/ui_mode.gni")
+
+assert(is_chromeos_ash)
+
+component("idle_detector") {
+  sources = [
+    "idle_detector.cc",
+    "idle_detector.h",
+  ]
+
+  public_deps = [
+    "//base",
+    "//ui/base",
+  ]
+
+  defines = [ "IS_CHROMEOS_ASH_EXPERIENCES_IDLE_DETECTOR_IMPL" ]
+}
diff --git a/chrome/browser/ash/idle_detector.cc b/chromeos/ash/experiences/idle_detector/idle_detector.cc
similarity index 91%
rename from chrome/browser/ash/idle_detector.cc
rename to chromeos/ash/experiences/idle_detector/idle_detector.cc
index dfedfd32..b0e3ea3 100644
--- a/chrome/browser/ash/idle_detector.cc
+++ b/chromeos/ash/experiences/idle_detector/idle_detector.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ash/idle_detector.h"
+#include "chromeos/ash/experiences/idle_detector/idle_detector.h"
 
 #include "base/location.h"
 #include "base/time/default_tick_clock.h"
@@ -37,10 +37,11 @@
 }
 
 void IdleDetector::ResetTimer() {
-  if (timer_.IsRunning())
+  if (timer_.IsRunning()) {
     timer_.Reset();
-  else
+  } else {
     timer_.Start(FROM_HERE, timeout_, idle_callback_);
+  }
 }
 
 }  // namespace ash
diff --git a/chrome/browser/ash/idle_detector.h b/chromeos/ash/experiences/idle_detector/idle_detector.h
similarity index 75%
rename from chrome/browser/ash/idle_detector.h
rename to chromeos/ash/experiences/idle_detector/idle_detector.h
index 78af449..8958686 100644
--- a/chrome/browser/ash/idle_detector.h
+++ b/chromeos/ash/experiences/idle_detector/idle_detector.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_ASH_IDLE_DETECTOR_H_
-#define CHROME_BROWSER_ASH_IDLE_DETECTOR_H_
+#ifndef CHROMEOS_ASH_EXPERIENCES_IDLE_DETECTOR_IDLE_DETECTOR_H_
+#define CHROMEOS_ASH_EXPERIENCES_IDLE_DETECTOR_IDLE_DETECTOR_H_
 
 #include "base/functional/callback.h"
 #include "base/time/tick_clock.h"
@@ -13,7 +13,8 @@
 
 namespace ash {
 
-class IdleDetector : public ui::UserActivityObserver {
+class COMPONENT_EXPORT(CHROMEOS_ASH_EXPERIENCES_IDLE_DETECTOR) IdleDetector
+    : public ui::UserActivityObserver {
  public:
   IdleDetector(const base::RepeatingClosure& on_idle_callback,
                const base::TickClock* tick_clock);
@@ -41,4 +42,4 @@
 
 }  // namespace ash
 
-#endif  // CHROME_BROWSER_ASH_IDLE_DETECTOR_H_
+#endif  // CHROMEOS_ASH_EXPERIENCES_IDLE_DETECTOR_IDLE_DETECTOR_H_
diff --git a/chromeos/ash/experiences/login/BUILD.gn b/chromeos/ash/experiences/login/BUILD.gn
new file mode 100644
index 0000000..292b120c
--- /dev/null
+++ b/chromeos/ash/experiences/login/BUILD.gn
@@ -0,0 +1,13 @@
+# Copyright 2024 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/chromeos/ui_mode.gni")
+
+assert(is_chromeos_ash)
+
+component("login") {
+  sources = [ "login_screen_shown_observer.h" ]
+
+  public_deps = [ "//base" ]
+}
diff --git a/chrome/browser/ui/ash/login_screen_shown_observer.h b/chromeos/ash/experiences/login/login_screen_shown_observer.h
similarity index 71%
rename from chrome/browser/ui/ash/login_screen_shown_observer.h
rename to chromeos/ash/experiences/login/login_screen_shown_observer.h
index 56d3f7e8..7e6640c 100644
--- a/chrome/browser/ui/ash/login_screen_shown_observer.h
+++ b/chromeos/ash/experiences/login/login_screen_shown_observer.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_UI_ASH_LOGIN_SCREEN_SHOWN_OBSERVER_H_
-#define CHROME_BROWSER_UI_ASH_LOGIN_SCREEN_SHOWN_OBSERVER_H_
+#ifndef CHROMEOS_ASH_EXPERIENCES_LOGIN_LOGIN_SCREEN_SHOWN_OBSERVER_H_
+#define CHROMEOS_ASH_EXPERIENCES_LOGIN_LOGIN_SCREEN_SHOWN_OBSERVER_H_
 
 #include "base/observer_list_types.h"
 
@@ -17,4 +17,4 @@
   virtual void OnLoginScreenShown() = 0;
 };
 
-#endif  // CHROME_BROWSER_UI_ASH_LOGIN_SCREEN_SHOWN_OBSERVER_H_
+#endif  // CHROMEOS_ASH_EXPERIENCES_LOGIN_LOGIN_SCREEN_SHOWN_OBSERVER_H_
diff --git a/chromeos/ash/experiences/screenshot_area/BUILD.gn b/chromeos/ash/experiences/screenshot_area/BUILD.gn
new file mode 100644
index 0000000..9d24ac80
--- /dev/null
+++ b/chromeos/ash/experiences/screenshot_area/BUILD.gn
@@ -0,0 +1,19 @@
+# Copyright 2024 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/chromeos/ui_mode.gni")
+
+assert(is_chromeos_ash)
+
+static_library("screenshot_area") {
+  sources = [
+    "screenshot_area.cc",
+    "screenshot_area.h",
+  ]
+
+  public_deps = [
+    "//base",
+    "//ui/gfx/geometry",
+  ]
+}
diff --git a/chrome/browser/ui/ash/screenshot_area.cc b/chromeos/ash/experiences/screenshot_area/screenshot_area.cc
similarity index 92%
rename from chrome/browser/ui/ash/screenshot_area.cc
rename to chromeos/ash/experiences/screenshot_area/screenshot_area.cc
index 7898df28..89b2c425 100644
--- a/chrome/browser/ui/ash/screenshot_area.cc
+++ b/chromeos/ash/experiences/screenshot_area/screenshot_area.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/ash/screenshot_area.h"
+#include "chromeos/ash/experiences/screenshot_area/screenshot_area.h"
 
 // static
 ScreenshotArea ScreenshotArea::CreateForAllRootWindows() {
diff --git a/chrome/browser/ui/ash/screenshot_area.h b/chromeos/ash/experiences/screenshot_area/screenshot_area.h
similarity index 85%
rename from chrome/browser/ui/ash/screenshot_area.h
rename to chromeos/ash/experiences/screenshot_area/screenshot_area.h
index 4784d965..cd22ea4 100644
--- a/chrome/browser/ui/ash/screenshot_area.h
+++ b/chromeos/ash/experiences/screenshot_area/screenshot_area.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_UI_ASH_SCREENSHOT_AREA_H_
-#define CHROME_BROWSER_UI_ASH_SCREENSHOT_AREA_H_
+#ifndef CHROMEOS_ASH_EXPERIENCES_SCREENSHOT_AREA_SCREENSHOT_AREA_H_
+#define CHROMEOS_ASH_EXPERIENCES_SCREENSHOT_AREA_SCREENSHOT_AREA_H_
 
 #include <optional>
 
@@ -43,4 +43,4 @@
                  std::optional<const gfx::Rect> rect);
 };
 
-#endif  // CHROME_BROWSER_UI_ASH_SCREENSHOT_AREA_H_
+#endif  // CHROMEOS_ASH_EXPERIENCES_SCREENSHOT_AREA_SCREENSHOT_AREA_H_
diff --git a/chromeos/ash/services/ime/ime_service.cc b/chromeos/ash/services/ime/ime_service.cc
index cdc8e44..9ac10a4 100644
--- a/chromeos/ash/services/ime/ime_service.cc
+++ b/chromeos/ash/services/ime/ime_service.cc
@@ -175,7 +175,7 @@
       &features::kAutocorrectUseReplaceSurroundingText,
       &features::kInputMethodKoreanRightAltKeyDownFix,
       &features::kImeKoreanModeSwitchDebug,
-  };
+      &features::kImeSwitchCheckConnectionStatus};
 
   // Use consistent feature flag names as in CrOS base::Feature::name and always
   // wire 1:1 to CrOS feature flags without extra logic.
diff --git a/chromeos/ash/services/ime/public/cpp/shared_lib/proto/japanese_dictionary.proto b/chromeos/ash/services/ime/public/cpp/shared_lib/proto/japanese_dictionary.proto
index 8753f7a2..c172ebc 100644
--- a/chromeos/ash/services/ime/public/cpp/shared_lib/proto/japanese_dictionary.proto
+++ b/chromeos/ash/services/ime/public/cpp/shared_lib/proto/japanese_dictionary.proto
@@ -41,6 +41,10 @@
   optional int64 dictionary_id = 1;
 }
 
+message ExportJapaneseDictionaryRequest {
+  optional int64 dictionary_id = 1;
+}
+
 // Based on:
 // https://github.com/google/mozc/blob/master/src/protocol/user_dictionary_storage.proto
 message JapaneseDictionary {
diff --git a/chromeos/ash/services/ime/public/cpp/shared_lib/proto/user_data_service.proto b/chromeos/ash/services/ime/public/cpp/shared_lib/proto/user_data_service.proto
index 1de83f1..c5b18f9 100644
--- a/chromeos/ash/services/ime/public/cpp/shared_lib/proto/user_data_service.proto
+++ b/chromeos/ash/services/ime/public/cpp/shared_lib/proto/user_data_service.proto
@@ -28,6 +28,8 @@
     RenameJapaneseDictionaryRequest rename_japanese_dictionary = 7;
     // Deletes a japanese dictionary.
     DeleteJapaneseDictionaryRequest delete_japanese_dictionary = 8;
+    // Returns the TSV string that represents a japanese dictionary.
+    ExportJapaneseDictionaryRequest export_japanese_dictionary = 9;
   }
 }
 
@@ -37,5 +39,7 @@
     FetchJapaneseLegacyConfigResponse fetch_japanese_legacy_config = 2;
     // Get all user dictionary data.
     FetchJapaneseDictionaryResponse fetch_japanese_dictionary = 3;
+    // Dictionary Data as TSV
+    string export_japanese_dictionary = 4;
   }
 }
diff --git a/chromeos/chromeos_strings.grd b/chromeos/chromeos_strings.grd
index e170eca..cf3a2ca 100644
--- a/chromeos/chromeos_strings.grd
+++ b/chromeos/chromeos_strings.grd
@@ -2595,6 +2595,9 @@
         <message name="IDS_PERSONALIZATION_APP_THEME_GEOLOCATION_WARNING_TEXT_FOR_WEATHER" desc="In Personalization > Screen saver, the warning text that tells users that system geolocation permission is needed for displaying local weather info">
           OFF - To display local weather <ph name="BEGIN_LINK">&lt;a href="#"&gt;</ph>turn on system location access<ph name="END_LINK">&lt;/a&gt;</ph>
         </message>
+        <message name="IDS_PERSONALIZATION_APP_THEME_GEOLOCATION_WARNING_MANAGED_TEXT_FOR_WEATHER" desc="In Personalization > Screen saver, the warning text that tells users that system geolocation permission is needed (but is managed by the admin) for displaying local weather info">
+          OFF - This setting is managed by your administrator.
+        </message>
         <message name="IDS_PERSONALIZATION_APP_THEME_GEOLOCATION_DIALOG_BODY" desc="Description of the dialog that prompts the user to enable system geolocation access. This gives detailed explanation of the outcomes of enabling system geolocation access for system services.">
           Current schedule is set to <ph name="SUNRISE">$1<ex>6am</ex></ph>-<ph name="SUNSET">$2<ex>6pm</ex></ph>. To automatically update the sunset and sunrise schedule, turn on system location access.
         </message>
diff --git a/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_THEME_GEOLOCATION_WARNING_MANAGED_TEXT_FOR_WEATHER.png.sha1 b/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_THEME_GEOLOCATION_WARNING_MANAGED_TEXT_FOR_WEATHER.png.sha1
new file mode 100644
index 0000000..a287b49
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_THEME_GEOLOCATION_WARNING_MANAGED_TEXT_FOR_WEATHER.png.sha1
@@ -0,0 +1 @@
+3fd03fdda34f0fb8c104624a45f6204681b9e33b
\ No newline at end of file
diff --git a/chromeos/constants/chromeos_features.cc b/chromeos/constants/chromeos_features.cc
index b90f995..430809b 100644
--- a/chromeos/constants/chromeos_features.cc
+++ b/chromeos/constants/chromeos_features.cc
@@ -209,6 +209,13 @@
              "OrcaUseL10nStrings",
              base::FEATURE_ENABLED_BY_DEFAULT);
 
+// Whether a set of UI optimizations within `OverviewSession::Init()` are
+// enabled or not. These should have no user-visible impact, except a faster
+// presentation time for the first frame of most overview sessions.
+BASE_FEATURE(kOverviewSessionInitOptimizations,
+             "OverviewSessionInitOptimizations",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 // Feature management flag used to gate preinstallation of the container app.
 // This flag is meant to be enabled by the feature management module.
 BASE_FEATURE(kFeatureManagementContainerAppPreinstall,
@@ -567,6 +574,10 @@
   return base::FeatureList::IsEnabled(kFeatureManagementHistoryEmbedding);
 }
 
+bool AreOverviewSessionInitOptimizationsEnabled() {
+  return base::FeatureList::IsEnabled(kOverviewSessionInitOptimizations);
+}
+
 int RoundedWindowsRadius() {
   if (!IsRoundedWindowsEnabled()) {
     return 0;
diff --git a/chromeos/constants/chromeos_features.h b/chromeos/constants/chromeos_features.h
index 2fba0dd..65d2057 100644
--- a/chromeos/constants/chromeos_features.h
+++ b/chromeos/constants/chromeos_features.h
@@ -93,6 +93,8 @@
 COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
 BASE_DECLARE_FEATURE(kNotificationWidthIncrease);
 COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
+BASE_DECLARE_FEATURE(kOverviewSessionInitOptimizations);
+COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
 BASE_DECLARE_FEATURE(kPreinstalledWebAppsCoreOnly);
 COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
 BASE_DECLARE_FEATURE(kQuickAnswersMaterialNextUI);
@@ -181,6 +183,8 @@
 bool IsMicrosoftOneDriveIntegrationForEnterpriseEnabled();
 COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
 bool IsFeatureManagementHistoryEmbeddingEnabled();
+COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
+bool AreOverviewSessionInitOptimizationsEnabled();
 }  // namespace features
 }  // namespace chromeos
 
diff --git a/chromeos/profiles/bigcore.afdo.newest.txt b/chromeos/profiles/bigcore.afdo.newest.txt
index 19ff1f7c..9d10b168 100644
--- a/chromeos/profiles/bigcore.afdo.newest.txt
+++ b/chromeos/profiles/bigcore.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-bigcore-130-6668.28-1725850545-benchmark-130.0.6709.0-r1-redacted.afdo.xz
+chromeos-chrome-amd64-bigcore-130-6668.28-1725850545-benchmark-130.0.6710.0-r1-redacted.afdo.xz
diff --git a/chromeos/recorder_strings.grdp b/chromeos/recorder_strings.grdp
index 411b9a6..18037c0 100644
--- a/chromeos/recorder_strings.grdp
+++ b/chromeos/recorder_strings.grdp
@@ -5,6 +5,9 @@
   <message desc="Name of the Recorder App." name="IDS_RECORDER_APP_NAME">
     Recorder
   </message>
+  <message desc="Accessibility label of the button to navigate back to main page." name="IDS_RECORDER_BACK_TO_MAIN_BUTTON_ARIA_LABEL">
+    Back to main page
+  </message>
   <message desc="Tooltip of the button to navigate back to main page." meaning="Go back to main page." name="IDS_RECORDER_BACK_TO_MAIN_BUTTON_TOOLTIP">
     Back
   </message>
@@ -50,6 +53,9 @@
   <message desc="Error message for trust and safety related error for title suggestion generative AI feature." name="IDS_RECORDER_GEN_AI_ERROR_TITLE_SUGGESTION_TRUST_AND_SAFETY_LABEL">
     Can’t create recording names for this content
   </message>
+  <message desc="Error message for too-short transcript length in generative AI features." name="IDS_RECORDER_GEN_AI_ERROR_TRANSCRIPTION_TOO_SHORT_LABEL">
+    For now, a transcript fewer than <ph name="MIN_WORD_LENGTH">$1<ex>150</ex></ph> words is not supported
+  </message>
   <message desc="Badge for experimental state of generative AI features." name="IDS_RECORDER_GEN_AI_EXPERIMENT_BADGE">
     Experiment
   </message>
@@ -183,9 +189,18 @@
   <message desc="Accessibility label of the volume slider for the playback." meaning="Set the playback volume." name="IDS_RECORDER_PLAYBACK_VOLUME_ARIA_LABEL">
     Volume
   </message>
+  <message desc="Accessibility label of the button to open more recording options." name="IDS_RECORDER_RECORDING_ITEM_OPTIONS_BUTTON_ARIA_LABEL">
+    More options for <ph name="RECORDING_NAME">$1<ex>Audio recording</ex></ph>
+  </message>
   <message desc="Tooltip of the button to open more record options." name="IDS_RECORDER_RECORDING_ITEM_OPTIONS_BUTTON_TOOLTIP">
     More options
   </message>
+  <message desc="Accessibility label of the button to pause the recording." meaning="Pause the audio recording." name="IDS_RECORDER_RECORDING_ITEM_PAUSE_BUTTON_ARIA_LABEL">
+    Pause <ph name="RECORDING_NAME">$1<ex>Audio recording</ex></ph>
+  </message>
+  <message desc="Accessibility label of the button to play the recording." meaning="Play the audio recording." name="IDS_RECORDER_RECORDING_ITEM_PLAY_BUTTON_ARIA_LABEL">
+    Play <ph name="RECORDING_NAME">$1<ex>Audio recording</ex></ph>
+  </message>
   <message desc="Tooltip of the button to play the recording." meaning="Play the audio recording." name="IDS_RECORDER_RECORDING_ITEM_PLAY_BUTTON_TOOLTIP">
     Play
   </message>
@@ -195,6 +210,12 @@
   <message desc="Message when there’re no recordings with the titles matching with the search keyword." name="IDS_RECORDER_RECORDING_LIST_NO_MATCH_TEXT">
     No matching results
   </message>
+  <message desc="Accessibility of the button to clear the text in the search box." meaning="Clear the search box." name="IDS_RECORDER_RECORDING_LIST_SEARCH_BOX_CLEAR_BUTTON_ARIA_LABEL">
+    Clear search
+  </message>
+  <message desc="Accessibility of the button to close the search box." meaning="Close the search box." name="IDS_RECORDER_RECORDING_LIST_SEARCH_BOX_CLOSE_BUTTON_ARIA_LABEL">
+    Close search
+  </message>
   <message desc="Placeholder text on the search box used to search recordings." name="IDS_RECORDER_RECORDING_LIST_SEARCH_BOX_PLACEHOLDER">
     Search recording name
   </message>
@@ -390,6 +411,9 @@
   <message desc="Header of title suggestion." name="IDS_RECORDER_TITLE_SUGGESTION_HEADER">
     A few options:
   </message>
+  <message desc="Accessibility label for the textfield showing the recording name." meaning="Textfield for the recording name being renamed." name="IDS_RECORDER_TITLE_TEXTFIELD_ARIA_LABEL">
+    Recording name
+  </message>
   <message desc="Button to enable autoscroll for transcription." name="IDS_RECORDER_TRANSCRIPTION_AUTOSCROLL_BUTTON">
     Autoscroll
   </message>
diff --git a/chromeos/recorder_strings_grdp/IDS_RECORDER_BACK_TO_MAIN_BUTTON_ARIA_LABEL.png.sha1 b/chromeos/recorder_strings_grdp/IDS_RECORDER_BACK_TO_MAIN_BUTTON_ARIA_LABEL.png.sha1
new file mode 100644
index 0000000..1565fc2
--- /dev/null
+++ b/chromeos/recorder_strings_grdp/IDS_RECORDER_BACK_TO_MAIN_BUTTON_ARIA_LABEL.png.sha1
@@ -0,0 +1 @@
+855cf57b8a3cd4a8313e704455098c1293ff7ef4
\ No newline at end of file
diff --git a/chromeos/recorder_strings_grdp/IDS_RECORDER_GEN_AI_ERROR_TRANSCRIPTION_TOO_SHORT_LABEL.png.sha1 b/chromeos/recorder_strings_grdp/IDS_RECORDER_GEN_AI_ERROR_TRANSCRIPTION_TOO_SHORT_LABEL.png.sha1
new file mode 100644
index 0000000..1b8f981
--- /dev/null
+++ b/chromeos/recorder_strings_grdp/IDS_RECORDER_GEN_AI_ERROR_TRANSCRIPTION_TOO_SHORT_LABEL.png.sha1
@@ -0,0 +1 @@
+21497ce0624eb419a8282815f7735d61b939c91d
\ No newline at end of file
diff --git a/chromeos/recorder_strings_grdp/IDS_RECORDER_RECORDING_ITEM_OPTIONS_BUTTON_ARIA_LABEL.png.sha1 b/chromeos/recorder_strings_grdp/IDS_RECORDER_RECORDING_ITEM_OPTIONS_BUTTON_ARIA_LABEL.png.sha1
new file mode 100644
index 0000000..4bf14e6
--- /dev/null
+++ b/chromeos/recorder_strings_grdp/IDS_RECORDER_RECORDING_ITEM_OPTIONS_BUTTON_ARIA_LABEL.png.sha1
@@ -0,0 +1 @@
+51e607fbca3faad89f1a8fd8a139edfba9e57ac2
\ No newline at end of file
diff --git a/chromeos/recorder_strings_grdp/IDS_RECORDER_RECORDING_ITEM_PAUSE_BUTTON_ARIA_LABEL.png.sha1 b/chromeos/recorder_strings_grdp/IDS_RECORDER_RECORDING_ITEM_PAUSE_BUTTON_ARIA_LABEL.png.sha1
new file mode 100644
index 0000000..5697c42
--- /dev/null
+++ b/chromeos/recorder_strings_grdp/IDS_RECORDER_RECORDING_ITEM_PAUSE_BUTTON_ARIA_LABEL.png.sha1
@@ -0,0 +1 @@
+187e9461264295fc5e68a0622bc20f2e7ddafeb0
\ No newline at end of file
diff --git a/chromeos/recorder_strings_grdp/IDS_RECORDER_RECORDING_ITEM_PLAY_BUTTON_ARIA_LABEL.png.sha1 b/chromeos/recorder_strings_grdp/IDS_RECORDER_RECORDING_ITEM_PLAY_BUTTON_ARIA_LABEL.png.sha1
new file mode 100644
index 0000000..348d5f5
--- /dev/null
+++ b/chromeos/recorder_strings_grdp/IDS_RECORDER_RECORDING_ITEM_PLAY_BUTTON_ARIA_LABEL.png.sha1
@@ -0,0 +1 @@
+1763c45ede64a6f1c1e5b5863e6b7657efaf82d7
\ No newline at end of file
diff --git a/chromeos/recorder_strings_grdp/IDS_RECORDER_RECORDING_LIST_SEARCH_BOX_CLEAR_BUTTON_ARIA_LABEL.png.sha1 b/chromeos/recorder_strings_grdp/IDS_RECORDER_RECORDING_LIST_SEARCH_BOX_CLEAR_BUTTON_ARIA_LABEL.png.sha1
new file mode 100644
index 0000000..80359b0
--- /dev/null
+++ b/chromeos/recorder_strings_grdp/IDS_RECORDER_RECORDING_LIST_SEARCH_BOX_CLEAR_BUTTON_ARIA_LABEL.png.sha1
@@ -0,0 +1 @@
+68853bb28ab41611c37ab47911ac0b58839b1ea6
\ No newline at end of file
diff --git a/chromeos/recorder_strings_grdp/IDS_RECORDER_RECORDING_LIST_SEARCH_BOX_CLOSE_BUTTON_ARIA_LABEL.png.sha1 b/chromeos/recorder_strings_grdp/IDS_RECORDER_RECORDING_LIST_SEARCH_BOX_CLOSE_BUTTON_ARIA_LABEL.png.sha1
new file mode 100644
index 0000000..551f261
--- /dev/null
+++ b/chromeos/recorder_strings_grdp/IDS_RECORDER_RECORDING_LIST_SEARCH_BOX_CLOSE_BUTTON_ARIA_LABEL.png.sha1
@@ -0,0 +1 @@
+7b5e91714a4fed279a18a262be51fddc10a1617e
\ No newline at end of file
diff --git a/chromeos/recorder_strings_grdp/IDS_RECORDER_TITLE_TEXTFIELD_ARIA_LABEL.png.sha1 b/chromeos/recorder_strings_grdp/IDS_RECORDER_TITLE_TEXTFIELD_ARIA_LABEL.png.sha1
new file mode 100644
index 0000000..7dda414
--- /dev/null
+++ b/chromeos/recorder_strings_grdp/IDS_RECORDER_TITLE_TEXTFIELD_ARIA_LABEL.png.sha1
@@ -0,0 +1 @@
+6a8744702ed2f435a69b13e2d2936e449ca45640
\ No newline at end of file
diff --git a/clank b/clank
index 123f9cd8..5ff4aac 160000
--- a/clank
+++ b/clank
@@ -1 +1 @@
-Subproject commit 123f9cd86c36186e08fafb2445dd5fa0e5688a94
+Subproject commit 5ff4aacc9038c4be345d8e97699a2a5f1f8aed60
diff --git a/components/autofill/core/browser/autofill_external_delegate_unittest.cc b/components/autofill/core/browser/autofill_external_delegate_unittest.cc
index 0e13224..b82d91d 100644
--- a/components/autofill/core/browser/autofill_external_delegate_unittest.cc
+++ b/components/autofill/core/browser/autofill_external_delegate_unittest.cc
@@ -383,8 +383,6 @@
         std::make_unique<NiceMock<MockPersonalDataManager>>());
     pdm().set_address_data_manager(
         std::make_unique<NiceMock<MockAddressDataManager>>());
-    client().set_plus_address_delegate(
-        std::make_unique<NiceMock<MockAutofillPlusAddressDelegate>>());
     autofill_driver_ =
         std::make_unique<NiceMock<MockAutofillDriver>>(&client());
     auto mock_browser_autofill_manager =
@@ -457,10 +455,6 @@
   MockAddressDataManager& address_data_manager() {
     return static_cast<MockAddressDataManager&>(pdm().address_data_manager());
   }
-  MockAutofillPlusAddressDelegate& plus_address_delegate() {
-    return static_cast<MockAutofillPlusAddressDelegate&>(
-        *client().GetPlusAddressDelegate());
-  }
   MockCreditCardAccessManager& cc_access_manager() {
     return static_cast<MockCreditCardAccessManager&>(
         manager().GetCreditCardAccessManager());
@@ -2140,10 +2134,49 @@
       return info.param.test_name;
     });
 
+class AutofillExternalDelegatePlusAddressUnitTest
+    : public AutofillExternalDelegateUnitTest {
+ public:
+  AutofillExternalDelegatePlusAddressUnitTest() = default;
+
+  void SetUp() override {
+    AutofillExternalDelegateUnitTest::SetUp();
+    client().set_plus_address_delegate(
+        std::make_unique<NiceMock<MockAutofillPlusAddressDelegate>>());
+  }
+
+ protected:
+  MockAutofillPlusAddressDelegate& plus_address_delegate() {
+    return static_cast<MockAutofillPlusAddressDelegate&>(
+        *client().GetPlusAddressDelegate());
+  }
+
+  const std::vector<Suggestion>& suggestions() const { return suggestions_; }
+
+  void ShowPlusAddressInlineSuggestion(
+      std::optional<std::u16string> plus_address) {
+    IssueOnQuery();
+
+    suggestions_.emplace_back(/*main_text=*/u"Create plus address",
+                              SuggestionType::kCreateNewPlusAddressInline);
+    suggestions_.back().payload = Suggestion::PlusAddressPayload(plus_address);
+    OnSuggestionsReturned(queried_field().global_id(), suggestions_);
+    ON_CALL(client(), GetAutofillSuggestions)
+        .WillByDefault(Return(base::span<const Suggestion>(suggestions_)));
+    client().set_suggestion_ui_session_id(
+        AutofillClient::SuggestionUiSessionId(123));
+  }
+
+ private:
+  // The currently shown suggestions. Kept as a member since
+  // `GetAutofillSuggestions` returns a span.
+  std::vector<Suggestion> suggestions_;
+};
+
 // Mock out an existing plus address autofill suggestion, and ensure that
 // choosing it results in the field being filled with its value (as opposed to
 // the mocked address used in the creation flow).
-TEST_F(AutofillExternalDelegateUnitTest,
+TEST_F(AutofillExternalDelegatePlusAddressUnitTest,
        ExternalDelegateFillsExistingPlusAddress) {
   IssueOnQuery();
 
@@ -2189,7 +2222,7 @@
 
 // Mock out the new plus address creation flow, and ensure that its completion
 // results in the field being filled with the resulting plus address.
-TEST_F(AutofillExternalDelegateUnitTest,
+TEST_F(AutofillExternalDelegatePlusAddressUnitTest,
        ExternalDelegateOffersPlusAddressCreation) {
   const std::u16string kMockPlusAddressForCreationCallback =
       u"test+1234@test.example";
@@ -2239,25 +2272,18 @@
 // Tests that showing a plus address inline suggestion calls
 // `AutofillPlusAddressDelegate` with a callback that updates the Autofill
 // popup.
-TEST_F(AutofillExternalDelegateUnitTest, PlusAddressInlineSuggestionShown) {
-  IssueOnQuery();
+TEST_F(AutofillExternalDelegatePlusAddressUnitTest,
+       PlusAddressInlineSuggestionShown) {
+  ShowPlusAddressInlineSuggestion(std::nullopt);
 
-  const std::u16string plus_address = u"test+plus@test.example";
-  std::vector<Suggestion> suggestions;
-  suggestions.emplace_back(/*main_text=*/plus_address,
-                           SuggestionType::kCreateNewPlusAddressInline);
-  suggestions.back().payload = Suggestion::PlusAddressPayload();
-  OnSuggestionsReturned(queried_field().global_id(), suggestions);
-  client().set_suggestion_ui_session_id(
-      AutofillClient::SuggestionUiSessionId(123));
   {
     InSequence s;
-    std::vector<Suggestion> updated_suggestions = suggestions;
+    std::vector<Suggestion> updated_suggestions = suggestions();
     updated_suggestions[0].payload =
-        Suggestion::PlusAddressPayload(plus_address);
+        Suggestion::PlusAddressPayload(u"test+plus@test.example");
     EXPECT_CALL(plus_address_delegate(),
                 OnShowedInlineSuggestion(
-                    _, base::span<const Suggestion>(suggestions), _))
+                    _, base::span<const Suggestion>(suggestions()), _))
         .WillOnce(RunOnceCallback<2>(updated_suggestions,
                                      AutofillSuggestionTriggerSource::
                                          kPlusAddressUpdatedInBrowserProcess));
@@ -2267,20 +2293,16 @@
                     AutofillSuggestionTriggerSource::
                         kPlusAddressUpdatedInBrowserProcess));
   }
-  external_delegate().OnSuggestionsShown(suggestions);
+
+  external_delegate().OnSuggestionsShown(suggestions());
 }
 
 // Tests that selecting an inline plus address suggestion previews the value
 // stored in the payload.
-TEST_F(AutofillExternalDelegateUnitTest, PlusAddressInlineSuggestionSelected) {
-  IssueOnQuery();
-
+TEST_F(AutofillExternalDelegatePlusAddressUnitTest,
+       PlusAddressInlineSuggestionSelected) {
   const std::u16string plus_address = u"test+plus@test.example";
-  std::vector<Suggestion> suggestions;
-  suggestions.emplace_back(/*main_text=*/plus_address,
-                           SuggestionType::kCreateNewPlusAddressInline);
-  suggestions.back().payload = Suggestion::PlusAddressPayload(plus_address);
-  OnSuggestionsReturned(queried_field().global_id(), suggestions);
+  ShowPlusAddressInlineSuggestion(plus_address);
 
   EXPECT_CALL(driver(), RendererShouldClearPreviewedForm());
   EXPECT_CALL(
@@ -2290,53 +2312,36 @@
                          HasQueriedFormId(), HasQueriedFieldId(), plus_address,
                          SuggestionType::kCreateNewPlusAddressInline,
                          std::optional(EMAIL_ADDRESS)));
-  external_delegate().DidSelectSuggestion(suggestions[0]);
+  external_delegate().DidSelectSuggestion(suggestions()[0]);
 }
 
 // Tests that selecting an inline plus address suggestion with an empty address
 // value does not preview anything.
-TEST_F(AutofillExternalDelegateUnitTest,
+TEST_F(AutofillExternalDelegatePlusAddressUnitTest,
        PlusAddressInlineSuggestionSelectedWithNoAddress) {
-  IssueOnQuery();
-
-  const std::u16string plus_address = u"test+plus@test.example";
-  std::vector<Suggestion> suggestions;
-  suggestions.emplace_back(/*main_text=*/plus_address,
-                           SuggestionType::kCreateNewPlusAddressInline);
-  suggestions.back().payload = Suggestion::PlusAddressPayload();
-  OnSuggestionsReturned(queried_field().global_id(), suggestions);
+  ShowPlusAddressInlineSuggestion(std::nullopt);
 
   EXPECT_CALL(driver(), RendererShouldClearPreviewedForm());
   EXPECT_CALL(manager(), FillOrPreviewField).Times(0);
-  external_delegate().DidSelectSuggestion(suggestions[0]);
+  external_delegate().DidSelectSuggestion(suggestions()[0]);
 }
 
 // Tests that triggering the extra button action on a plus address inline
 // suggestion informs the plus address delegate and passes a callback that can
 // be used to update the Autofill suggestions.
-TEST_F(AutofillExternalDelegateUnitTest, PlusAddressExtraButtonAction) {
-  IssueOnQuery();
-
-  const std::u16string plus_address = u"test+plus@test.example";
-  std::vector<Suggestion> suggestions;
-  suggestions.emplace_back(/*main_text=*/u"Create plus address",
-                           SuggestionType::kCreateNewPlusAddressInline);
-  suggestions.back().payload = Suggestion::PlusAddressPayload(plus_address);
-  OnSuggestionsReturned(queried_field().global_id(), suggestions);
-  ON_CALL(client(), GetAutofillSuggestions)
-      .WillByDefault(Return(base::span<const Suggestion>(suggestions)));
-  client().set_suggestion_ui_session_id(
-      AutofillClient::SuggestionUiSessionId(123));
+TEST_F(AutofillExternalDelegatePlusAddressUnitTest,
+       PlusAddressExtraButtonAction) {
+  ShowPlusAddressInlineSuggestion(u"test+plus@test.example");
 
   {
     InSequence s;
 
-    std::vector<Suggestion> updated_suggestions = suggestions;
+    std::vector<Suggestion> updated_suggestions = suggestions();
     updated_suggestions.back().payload = Suggestion::PlusAddressPayload();
     EXPECT_CALL(driver(), RendererShouldClearPreviewedForm);
     EXPECT_CALL(plus_address_delegate(),
                 OnClickedRefreshInlineSuggestion(
-                    _, base::span<const Suggestion>(suggestions),
+                    _, base::span<const Suggestion>(suggestions()),
                     /*current_suggestion_index=*/0, _))
         .WillOnce(RunOnceCallback<3>(updated_suggestions,
                                      AutofillSuggestionTriggerSource::
@@ -2349,13 +2354,13 @@
   }
 
   external_delegate().DidPerformButtonActionForSuggestion(
-      suggestions[0], SuggestionButtonAction());
+      suggestions()[0], SuggestionButtonAction());
 }
 
 // Tests that triggering the extra button action on a plus address error
 // suggestion informs the plus address delegate and passes a callback that can
 // be used to update the Autofill suggestions.
-TEST_F(AutofillExternalDelegateUnitTest,
+TEST_F(AutofillExternalDelegatePlusAddressUnitTest,
        PlusAddressExtraButtonActionForErrorSuggestion) {
   IssueOnQuery();
 
@@ -2398,35 +2403,24 @@
 
 // Tests that running the update callback is a no-op if the session id of the
 // suggestions UI has changed since the update callback was requested.
-TEST_F(AutofillExternalDelegateUnitTest,
+TEST_F(AutofillExternalDelegatePlusAddressUnitTest,
        PlusAddressExtraButtonActionUiSessionIdChanged) {
-  IssueOnQuery();
-
-  const std::u16string plus_address = u"test+plus@test.example";
-  std::vector<Suggestion> suggestions;
-  suggestions.emplace_back(u"Some other suggestion");
-  suggestions.emplace_back(/*main_text=*/u"Create plus address",
-                           SuggestionType::kCreateNewPlusAddressInline);
-  suggestions.back().payload = Suggestion::PlusAddressPayload(plus_address);
-  OnSuggestionsReturned(queried_field().global_id(), suggestions);
-  ON_CALL(client(), GetAutofillSuggestions)
-      .WillByDefault(Return(base::span<const Suggestion>(suggestions)));
+  ShowPlusAddressInlineSuggestion(u"test+plus@test.example");
 
   base::OnceCallback<void(std::vector<Suggestion>,
                           AutofillSuggestionTriggerSource)>
       update_callback;
-
   EXPECT_CALL(client(), UpdateAutofillSuggestions).Times(0);
   EXPECT_CALL(plus_address_delegate(),
               OnClickedRefreshInlineSuggestion(
-                  _, base::span<const Suggestion>(suggestions),
-                  /*current_suggestion_index=*/1, _))
+                  _, base::span<const Suggestion>(suggestions()),
+                  /*current_suggestion_index=*/0, _))
       .WillOnce(MoveArg<3>(&update_callback));
 
   client().set_suggestion_ui_session_id(
       AutofillClient::SuggestionUiSessionId(3));
   external_delegate().DidPerformButtonActionForSuggestion(
-      suggestions[1], SuggestionButtonAction());
+      suggestions()[0], SuggestionButtonAction());
   ASSERT_TRUE(update_callback);
 
   // Now simulate that the popup has a new session id.
@@ -2434,63 +2428,42 @@
       AutofillClient::SuggestionUiSessionId(4));
   std::move(update_callback)
       .Run(
-          suggestions,
+          suggestions(),
           AutofillSuggestionTriggerSource::kPlusAddressUpdatedInBrowserProcess);
 }
 
 // Tests that running the update callback is safe even after AED has been
 // destroyed.
-TEST_F(AutofillExternalDelegateUnitTest,
+TEST_F(AutofillExternalDelegatePlusAddressUnitTest,
        PlusAddressExtraButtonActionIsAlwaysSafeToCall) {
-  IssueOnQuery();
-
-  const std::u16string plus_address = u"test+plus@test.example";
-  std::vector<Suggestion> suggestions;
-  suggestions.emplace_back(u"Some other suggestion");
-  suggestions.emplace_back(/*main_text=*/u"Create plus address",
-                           SuggestionType::kCreateNewPlusAddressInline);
-  suggestions.back().payload = Suggestion::PlusAddressPayload(plus_address);
-  OnSuggestionsReturned(queried_field().global_id(), suggestions);
-  ON_CALL(client(), GetAutofillSuggestions)
-      .WillByDefault(Return(base::span<const Suggestion>(suggestions)));
+  ShowPlusAddressInlineSuggestion(u"test+plus@test.example");
 
   base::OnceCallback<void(std::vector<Suggestion>,
                           AutofillSuggestionTriggerSource)>
       update_callback;
-
   EXPECT_CALL(client(), UpdateAutofillSuggestions).Times(0);
   EXPECT_CALL(plus_address_delegate(),
               OnClickedRefreshInlineSuggestion(
-                  _, base::span<const Suggestion>(suggestions),
-                  /*current_suggestion_index=*/1, _))
+                  _, base::span<const Suggestion>(suggestions()),
+                  /*current_suggestion_index=*/0, _))
       .WillOnce(MoveArg<3>(&update_callback));
 
   external_delegate().DidPerformButtonActionForSuggestion(
-      suggestions[1], SuggestionButtonAction());
+      suggestions()[0], SuggestionButtonAction());
   ASSERT_TRUE(update_callback);
   ResetDriver();
   std::move(update_callback)
       .Run(
-          suggestions,
+          suggestions(),
           AutofillSuggestionTriggerSource::kPlusAddressUpdatedInBrowserProcess);
 }
 
 // Tests that triggering the extra button action on a plus address inline
 // suggestion informs the plus address delegate and passes a callback that can
 // be used to update the Autofill suggestions.
-TEST_F(AutofillExternalDelegateUnitTest, PlusAddressInlineAccepted) {
-  IssueOnQuery();
-
+TEST_F(AutofillExternalDelegatePlusAddressUnitTest, PlusAddressInlineAccepted) {
   const std::u16string plus_address = u"test+plus@test.example";
-  std::vector<Suggestion> suggestions;
-  suggestions.emplace_back(/*main_text=*/u"Create plus address",
-                           SuggestionType::kCreateNewPlusAddressInline);
-  suggestions.back().payload = Suggestion::PlusAddressPayload(plus_address);
-  OnSuggestionsReturned(queried_field().global_id(), suggestions);
-  ON_CALL(client(), GetAutofillSuggestions)
-      .WillByDefault(Return(base::span<const Suggestion>(suggestions)));
-  client().set_suggestion_ui_session_id(
-      AutofillClient::SuggestionUiSessionId(123));
+  ShowPlusAddressInlineSuggestion(plus_address);
 
   using UpdateSuggestionsCallback =
       AutofillPlusAddressDelegate::UpdateSuggestionsCallback;
@@ -2499,7 +2472,7 @@
   UpdateSuggestionsCallback update_callback;
   HideSuggestionsCallback hide_callback;
   PlusAddressCallback filling_callback;
-  std::vector<Suggestion> updated_suggestions = suggestions;
+  std::vector<Suggestion> updated_suggestions = suggestions();
   updated_suggestions.back().is_loading = Suggestion::IsLoading(true);
   MockFunction<void()> check;
   {
@@ -2509,7 +2482,7 @@
     // combined via `DoAll` - therefore use a helper.
     EXPECT_CALL(plus_address_delegate(),
                 OnAcceptedInlineSuggestion(
-                    _, base::span<const Suggestion>(suggestions),
+                    _, base::span<const Suggestion>(suggestions()),
                     /*current_suggestion_index=*/0, _, _, _, _, _))
         .WillOnce(
             [&](const url::Origin& primary_main_frame_origin,
@@ -2542,7 +2515,7 @@
                                    std::optional(EMAIL_ADDRESS)));
   }
 
-  external_delegate().DidAcceptSuggestion(suggestions[0],
+  external_delegate().DidAcceptSuggestion(suggestions()[0],
                                           SuggestionPosition{.row = 0});
   ASSERT_TRUE(update_callback);
   ASSERT_TRUE(hide_callback);
@@ -2562,21 +2535,9 @@
 // `ShowAffiliationErrorDialogCallback` that, when run, triggers showing a plus
 // address affiliation error dialog in `AutofillClient`. If that dialog is
 // accepted, the affiliated plus address is filled.
-TEST_F(AutofillExternalDelegateUnitTest,
+TEST_F(AutofillExternalDelegatePlusAddressUnitTest,
        PlusAddressInlineAcceptedAffiliationError) {
-  IssueOnQuery();
-
-  const std::u16string plus_address = u"test+plus@test.example";
-  std::vector<Suggestion> suggestions;
-  suggestions.emplace_back(/*main_text=*/u"Create plus address",
-                           SuggestionType::kCreateNewPlusAddressInline);
-  suggestions.back().payload = Suggestion::PlusAddressPayload(plus_address);
-  OnSuggestionsReturned(queried_field().global_id(), suggestions);
-  ON_CALL(client(), GetAutofillSuggestions)
-      .WillByDefault(Return(base::span<const Suggestion>(suggestions)));
-  client().set_suggestion_ui_session_id(
-      AutofillClient::SuggestionUiSessionId(123));
-
+  ShowPlusAddressInlineSuggestion(u"test+plus@test.example");
   const std::u16string affiliated_domain = u"https://bar.com";
   const std::u16string affiliated_plus_address = u"foo@bar.com";
 
@@ -2585,7 +2546,7 @@
   {
     EXPECT_CALL(plus_address_delegate(),
                 OnAcceptedInlineSuggestion(
-                    _, base::span<const Suggestion>(suggestions),
+                    _, base::span<const Suggestion>(suggestions()),
                     /*current_suggestion_index=*/0, _, _, _, _, _))
         .WillOnce(MoveArg<6>(&show_affiliation_error_callback));
     // Simulate accepting the dialog.
@@ -2601,7 +2562,7 @@
                                    std::optional(EMAIL_ADDRESS)));
   }
 
-  external_delegate().DidAcceptSuggestion(suggestions[0],
+  external_delegate().DidAcceptSuggestion(suggestions()[0],
                                           SuggestionPosition{.row = 0});
   ASSERT_TRUE(show_affiliation_error_callback);
   // Simulate showing the affiliation error dialog.
@@ -2612,25 +2573,15 @@
 // Tests that `OnAcceptedInlineSuggestion` gets passed a
 // `ShowErrorDialogCallback` that, when run, triggers showing a plus address
 // error dialog in `AutofillClient`.
-TEST_F(AutofillExternalDelegateUnitTest, PlusAddressInlineAcceptedQuotaError) {
-  IssueOnQuery();
-
-  const std::u16string plus_address = u"test+plus@test.example";
-  std::vector<Suggestion> suggestions;
-  suggestions.emplace_back(/*main_text=*/u"Create plus address",
-                           SuggestionType::kCreateNewPlusAddressInline);
-  suggestions.back().payload = Suggestion::PlusAddressPayload(plus_address);
-  OnSuggestionsReturned(queried_field().global_id(), suggestions);
-  ON_CALL(client(), GetAutofillSuggestions)
-      .WillByDefault(Return(base::span<const Suggestion>(suggestions)));
-  client().set_suggestion_ui_session_id(
-      AutofillClient::SuggestionUiSessionId(123));
+TEST_F(AutofillExternalDelegatePlusAddressUnitTest,
+       PlusAddressInlineAcceptedQuotaError) {
+  ShowPlusAddressInlineSuggestion(u"test+plus@test.example");
 
   AutofillPlusAddressDelegate::ShowErrorDialogCallback show_error_callback;
   {
     EXPECT_CALL(plus_address_delegate(),
                 OnAcceptedInlineSuggestion(
-                    _, base::span<const Suggestion>(suggestions),
+                    _, base::span<const Suggestion>(suggestions()),
                     /*current_suggestion_index=*/0, _, _, _, _, _))
         .WillOnce(MoveArg<7>(&show_error_callback));
     EXPECT_CALL(
@@ -2639,7 +2590,7 @@
             AutofillClient::PlusAddressErrorDialogType::kQuotaExhausted, _));
   }
 
-  external_delegate().DidAcceptSuggestion(suggestions[0],
+  external_delegate().DidAcceptSuggestion(suggestions()[0],
                                           SuggestionPosition{.row = 0});
   ASSERT_TRUE(show_error_callback);
   std::move(show_error_callback)
diff --git a/components/autofill/core/browser/browser_autofill_manager.cc b/components/autofill/core/browser/browser_autofill_manager.cc
index 85ff04e..2bac542 100644
--- a/components/autofill/core/browser/browser_autofill_manager.cc
+++ b/components/autofill/core/browser/browser_autofill_manager.cc
@@ -2861,7 +2861,9 @@
       }
     } else {
       suggestions = GetSuggestionsForCreditCards(
-          client(), trigger_field, last_four_list_for_cvc_suggestion_filtering,
+          client(), trigger_field,
+          base::flat_set<std::u16string>(
+              std::move(last_four_list_for_cvc_suggestion_filtering)),
           trigger_field_type, trigger_source,
           ShouldShowScanCreditCard(form, trigger_field),
           ShouldShowCardsFromAccountOption(form, trigger_field, trigger_source),
diff --git a/components/autofill/core/browser/data_model/autofill_structured_address.cc b/components/autofill/core/browser/data_model/autofill_structured_address.cc
index 9822be9..b995fa8 100644
--- a/components/autofill/core/browser/data_model/autofill_structured_address.cc
+++ b/components/autofill/core/browser/data_model/autofill_structured_address.cc
@@ -14,6 +14,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "components/autofill/core/browser/autofill_type.h"
+#include "components/autofill/core/browser/data_model/autofill_i18n_api.h"
 #include "components/autofill/core/browser/data_model/autofill_structured_address_component.h"
 #include "components/autofill/core/browser/data_model/autofill_structured_address_regex_provider.h"
 #include "components/autofill/core/browser/data_model/autofill_structured_address_utils.h"
@@ -92,6 +93,13 @@
   DCHECK(pattern_provider);
   const std::string country_code =
       base::UTF16ToUTF8(GetRootNode().GetValueForType(ADDRESS_HOME_COUNTRY));
+  // Countries with custom hierarchies are not guaranteed to support street
+  // names, house numbers, floors and apartment numbers. Therefore, we don't
+  // apply the hardcoded fallback regular expressions.
+  if (i18n_model_definition::IsCustomHierarchyAvailableForCountry(
+          AddressCountryCode(country_code))) {
+    return {};
+  }
   return {pattern_provider->GetRegEx(RegEx::kParseHouseNumberStreetName,
                                      country_code),
           pattern_provider->GetRegEx(RegEx::kParseStreetNameHouseNumber,
diff --git a/components/autofill/core/browser/data_model/autofill_structured_address_unittest.cc b/components/autofill/core/browser/data_model/autofill_structured_address_unittest.cc
index d6fc699..a79eac03 100644
--- a/components/autofill/core/browser/data_model/autofill_structured_address_unittest.cc
+++ b/components/autofill/core/browser/data_model/autofill_structured_address_unittest.cc
@@ -316,6 +316,12 @@
        .house_number = "1",
        .floor = "",
        .apartment_num = "3"},
+      // Regression test for crbug.com/365252089 (the trailing \n is important
+      // because it means that the AddressLinesDecomposition part of the
+      // street-address-alternative-1 cascade failed and the legacy fallback
+      // regular expressions tried to bind an apartment number which is not part
+      // of the DE custom hierarchy).
+      {.country_code = "DE", .street_address = "2 Foo, Apt 2\n"},
   };
 
   for (const auto& test_case : test_cases) {
diff --git a/components/autofill/core/browser/metrics/autofill_metrics.cc b/components/autofill/core/browser/metrics/autofill_metrics.cc
index 4ccd9bc..399f837 100644
--- a/components/autofill/core/browser/metrics/autofill_metrics.cc
+++ b/components/autofill/core/browser/metrics/autofill_metrics.cc
@@ -2460,7 +2460,7 @@
   SetStatusVector(AutofillStatus::kWasFocusedByTapOrClick,
                   OptionalBooleanToBool(was_focused_by_tap_or_click));
   SetStatusVector(AutofillStatus::kIsInSubFrame,
-                  form.ToFormData().host_frame() != field.host_frame());
+                  form.global_id().frame_token != field.host_frame());
 
   if (filling_prevented_by_iframe_security_policy !=
       OptionalBoolean::kUndefined) {
diff --git a/components/autofill/core/browser/payments_suggestion_generator.cc b/components/autofill/core/browser/payments_suggestion_generator.cc
index f4b7191..7df6903 100644
--- a/components/autofill/core/browser/payments_suggestion_generator.cc
+++ b/components/autofill/core/browser/payments_suggestion_generator.cc
@@ -10,6 +10,7 @@
 
 #include "base/check_deref.h"
 #include "base/containers/contains.h"
+#include "base/containers/flat_set.h"
 #include "base/feature_list.h"
 #include "base/i18n/case_conversion.h"
 #include "base/memory/raw_ptr.h"
@@ -768,6 +769,22 @@
                                                   client);
 }
 
+// Filter cards based on `last_four_set_for_cvc_suggestion_filtering`. Remove
+// cards that don't have last four in
+// `last_four_set_for_cvc_suggestion_filtering`.
+void MaybeFilterCardsToSuggest(std::vector<CreditCard>& cards_to_suggest,
+                               const base::flat_set<std::u16string>&
+                                   last_four_set_for_cvc_suggestion_filtering) {
+  if (last_four_set_for_cvc_suggestion_filtering.empty()) {
+    return;
+  }
+  std::erase_if(cards_to_suggest, [&last_four_set_for_cvc_suggestion_filtering](
+                                      const CreditCard& credit_card) {
+    return !last_four_set_for_cvc_suggestion_filtering.contains(
+        credit_card.LastFourDigits());
+  });
+}
+
 // Returns the local and server cards ordered by the Autofill ranking.
 // If `suppress_disused_cards`, local expired disused cards are removed.
 // If `prefix_match`, cards are matched with the contents of `trigger_field`.
@@ -924,7 +941,8 @@
 std::vector<Suggestion> GetSuggestionsForCreditCards(
     const AutofillClient& client,
     const FormFieldData& trigger_field,
-    const std::vector<std::u16string>& last_four_list_for_suggestion_filtering,
+    const base::flat_set<std::u16string>&
+        last_four_set_for_cvc_suggestion_filtering,
     FieldType trigger_field_type,
     AutofillSuggestionTriggerSource trigger_source,
     bool should_show_scan_credit_card,
@@ -959,6 +977,18 @@
                                require_non_empty_value_on_trigger_field,
                                /*include_virtual_cards=*/true);
 
+  static constexpr FieldTypeSet kCvcFieldTypes = {
+      FieldType::CREDIT_CARD_VERIFICATION_CODE,
+      FieldType::CREDIT_CARD_STANDALONE_VERIFICATION_CODE};
+  if (kCvcFieldTypes.contains(trigger_field_type) &&
+      trigger_source !=
+          AutofillSuggestionTriggerSource::kManualFallbackPayments &&
+      base::FeatureList::IsEnabled(
+          features::kAutofillEnableCvcStorageAndFillingEnhancement)) {
+    MaybeFilterCardsToSuggest(cards_to_suggest,
+                              last_four_set_for_cvc_suggestion_filtering);
+  }
+
   // If autofill for cards is triggered from the context menu on a credit card
   // field and no suggestions can be shown (i.e. if a user has only cards
   // without names and then triggers autofill from the context menu on a card
@@ -976,7 +1006,7 @@
       base::FeatureList::IsEnabled(
           features::kAutofillForUnclassifiedFieldsAvailable)) {
     return GetSuggestionsForCreditCards(
-        client, trigger_field, last_four_list_for_suggestion_filtering,
+        client, trigger_field, last_four_set_for_cvc_suggestion_filtering,
         UNKNOWN_TYPE, trigger_source, should_show_scan_credit_card,
         should_show_cards_from_account, summary);
   }
diff --git a/components/autofill/core/browser/payments_suggestion_generator.h b/components/autofill/core/browser/payments_suggestion_generator.h
index 012198d..0b59963 100644
--- a/components/autofill/core/browser/payments_suggestion_generator.h
+++ b/components/autofill/core/browser/payments_suggestion_generator.h
@@ -47,14 +47,16 @@
 // Generates suggestions for all available credit cards based on the
 // `trigger_field_type`, `trigger_field` and `trigger_source`.
 // `summary` contains metadata about the returned suggestions.
-// `last_four_list_for_suggestion_filtering` is a list of card number last four
-// that will be used for suggestion filtering. It is a list because it can be a
-// list of last four extracted from the DOM.
+// `last_four_set_for_cvc_suggestion_filtering` is a set of card number last
+// four that will be used for suggestion filtering. This is used to avoid
+// showing suggestions that is unrelated to the cards that have already been
+// autofilled in the form.
 // TODO(crbug.com/40916587): Implement last four extraction from the DOM.
 std::vector<Suggestion> GetSuggestionsForCreditCards(
     const AutofillClient& client,
     const FormFieldData& trigger_field,
-    const std::vector<std::u16string>& last_four_list_for_suggestion_filtering,
+    const base::flat_set<std::u16string>&
+        last_four_set_for_cvc_suggestion_filtering,
     FieldType trigger_field_type,
     AutofillSuggestionTriggerSource trigger_source,
     bool should_show_scan_credit_card,
diff --git a/components/autofill/core/browser/payments_suggestion_generator_unittest.cc b/components/autofill/core/browser/payments_suggestion_generator_unittest.cc
index 5b55f78..8197b5d6 100644
--- a/components/autofill/core/browser/payments_suggestion_generator_unittest.cc
+++ b/components/autofill/core/browser/payments_suggestion_generator_unittest.cc
@@ -185,6 +185,13 @@
   return true;
 }
 
+// Checks that `arg` is the expected suggestion with `guid`. `arg` has to be of
+// type Suggestion.
+MATCHER_P(SuggestionWithGuidPayload, guid, "") {
+  return arg.template GetPayload<Suggestion::BackendId>() ==
+         Suggestion::BackendId(guid);
+}
+
 // TODO(crbug.com/40176273): Move GetSuggestionsForCreditCard tests and
 // BrowserAutofillManagerTestForSharingNickname here from
 // browser_autofill_manager_unittest.cc.
@@ -660,7 +667,7 @@
   CreditCardSuggestionSummary summary;
   std::vector<Suggestion> suggestions = GetSuggestionsForCreditCards(
       *autofill_client(), FormFieldData(),
-      /*last_four_list_for_suggestion_filtering=*/
+      /*last_four_set_for_cvc_suggestion_filtering=*/
       {}, CREDIT_CARD_NAME_FULL,
       AutofillSuggestionTriggerSource::kManualFallbackPayments,
       /*should_show_scan_credit_card=*/false,
@@ -677,7 +684,7 @@
 
   suggestions = GetSuggestionsForCreditCards(
       *autofill_client(), FormFieldData(),
-      /*last_four_list_for_suggestion_filtering=*/
+      /*last_four_set_for_cvc_suggestion_filtering=*/
       {}, CREDIT_CARD_VERIFICATION_CODE,
       AutofillSuggestionTriggerSource::kManualFallbackPayments,
       /*should_show_scan_credit_card=*/false,
@@ -868,7 +875,7 @@
   CreditCardSuggestionSummary summary;
   std::vector<Suggestion> suggestions = GetSuggestionsForCreditCards(
       *autofill_client(), FormFieldData(),
-      /*last_four_list_for_suggestion_filtering=*/
+      /*last_four_set_for_cvc_suggestion_filtering=*/
       {}, UNKNOWN_TYPE,
       AutofillSuggestionTriggerSource::kManualFallbackPayments,
       /*should_show_scan_credit_card=*/false,
@@ -928,7 +935,7 @@
   CreditCardSuggestionSummary summary;
   std::vector<Suggestion> suggestions = GetSuggestionsForCreditCards(
       *autofill_client(), FormFieldData(),
-      /*last_four_list_for_suggestion_filtering=*/
+      /*last_four_set_for_cvc_suggestion_filtering=*/
       {}, CREDIT_CARD_NUMBER, kDefaultTriggerSource,
       /*should_show_scan_credit_card=*/false,
       /*should_show_cards_from_account=*/false, summary);
@@ -1009,7 +1016,7 @@
   CreditCardSuggestionSummary summary;
   std::vector<Suggestion> suggestions = GetSuggestionsForCreditCards(
       *autofill_client(), FormFieldData(),
-      /*last_four_list_for_suggestion_filtering=*/
+      /*last_four_set_for_cvc_suggestion_filtering=*/
       {}, CREDIT_CARD_NUMBER, kDefaultTriggerSource,
       /*should_show_scan_credit_card=*/false,
       /*should_show_cards_from_account=*/false, summary);
@@ -1035,7 +1042,7 @@
     CreditCardSuggestionSummary summary;
     std::vector<Suggestion> suggestions = GetSuggestionsForCreditCards(
         *autofill_client(), FormFieldData(),
-        /*last_four_list_for_suggestion_filtering=*/
+        /*last_four_set_for_cvc_suggestion_filtering=*/
         {}, CREDIT_CARD_NUMBER, kDefaultTriggerSource,
         /*should_show_scan_credit_card=*/false,
         /*should_show_cards_from_account=*/false, summary);
@@ -1062,7 +1069,7 @@
     CreditCardSuggestionSummary summary;
     std::vector<Suggestion> suggestions = GetSuggestionsForCreditCards(
         *autofill_client(), FormFieldData(),
-        /*last_four_list_for_suggestion_filtering=*/
+        /*last_four_set_for_cvc_suggestion_filtering=*/
         {}, CREDIT_CARD_NUMBER, kDefaultTriggerSource,
         /*should_show_scan_credit_card=*/false,
         /*should_show_cards_from_account=*/false, summary);
@@ -1091,7 +1098,7 @@
     CreditCardSuggestionSummary summary;
     std::vector<Suggestion> suggestions = GetSuggestionsForCreditCards(
         *autofill_client(), FormFieldData(),
-        /*last_four_list_for_suggestion_filtering=*/
+        /*last_four_set_for_cvc_suggestion_filtering=*/
         {}, CREDIT_CARD_NUMBER, kDefaultTriggerSource,
         /*should_show_scan_credit_card=*/false,
         /*should_show_cards_from_account=*/false, summary);
@@ -1108,7 +1115,7 @@
   CreditCardSuggestionSummary summary;
   std::vector<Suggestion> suggestions = GetSuggestionsForCreditCards(
       *autofill_client(), field,
-      /*last_four_list_for_suggestion_filtering=*/
+      /*last_four_set_for_cvc_suggestion_filtering=*/
       {}, CREDIT_CARD_NUMBER, kDefaultTriggerSource,
       /*should_show_scan_credit_card=*/true,
       /*should_show_cards_from_account=*/true, summary);
@@ -1121,7 +1128,7 @@
   CreditCardSuggestionSummary summary;
   std::vector<Suggestion> suggestions = GetSuggestionsForCreditCards(
       *autofill_client(), FormFieldData(),
-      /*last_four_list_for_suggestion_filtering=*/
+      /*last_four_set_for_cvc_suggestion_filtering=*/
       {}, CREDIT_CARD_NUMBER, kDefaultTriggerSource,
       /*should_show_scan_credit_card=*/true,
       /*should_show_cards_from_account=*/false, summary);
@@ -1143,7 +1150,7 @@
   CreditCardSuggestionSummary summary;
   std::vector<Suggestion> suggestions = GetSuggestionsForCreditCards(
       *autofill_client(), FormFieldData(),
-      /*last_four_list_for_suggestion_filtering=*/
+      /*last_four_set_for_cvc_suggestion_filtering=*/
       {}, CREDIT_CARD_NUMBER, kDefaultTriggerSource,
       /*should_show_scan_credit_card=*/false,
       /*should_show_cards_from_account=*/true, summary);
@@ -1169,7 +1176,7 @@
   CreditCardSuggestionSummary summary;
   std::vector<Suggestion> suggestions = GetSuggestionsForCreditCards(
       *autofill_client(), field,
-      /*last_four_list_for_suggestion_filtering=*/
+      /*last_four_set_for_cvc_suggestion_filtering=*/
       {}, CREDIT_CARD_NUMBER, kDefaultTriggerSource,
       /*should_show_scan_credit_card=*/false,
       /*should_show_cards_from_account=*/false, summary);
@@ -2007,7 +2014,7 @@
   CreditCardSuggestionSummary summary;
   std::vector<Suggestion> suggestions = GetSuggestionsForCreditCards(
       *autofill_client(), field_data,
-      /*last_four_list_for_suggestion_filtering=*/
+      /*last_four_set_for_cvc_suggestion_filtering=*/
       {}, UNKNOWN_TYPE,
       AutofillSuggestionTriggerSource::kManualFallbackPayments,
       /*should_show_scan_credit_card=*/false,
@@ -2035,7 +2042,7 @@
   CreditCardSuggestionSummary summary;
   const std::vector<Suggestion> suggestions = GetSuggestionsForCreditCards(
       *autofill_client(), FormFieldData(),
-      /*last_four_list_for_suggestion_filtering=*/
+      /*last_four_set_for_cvc_suggestion_filtering=*/
       {}, CREDIT_CARD_VERIFICATION_CODE, kDefaultTriggerSource,
       /*should_show_scan_credit_card=*/false,
       /*should_show_cards_from_account=*/false, summary);
@@ -2069,7 +2076,7 @@
   CreditCardSuggestionSummary summary;
   const std::vector<Suggestion> suggestions = GetSuggestionsForCreditCards(
       *autofill_client(), FormFieldData(),
-      /*last_four_list_for_suggestion_filtering=*/
+      /*last_four_set_for_cvc_suggestion_filtering=*/
       {}, CREDIT_CARD_VERIFICATION_CODE, kDefaultTriggerSource,
       /*should_show_scan_credit_card=*/false,
       /*should_show_cards_from_account=*/false, summary);
@@ -2093,7 +2100,7 @@
   CreditCardSuggestionSummary summary;
   const std::vector<Suggestion> suggestions = GetSuggestionsForCreditCards(
       *autofill_client(), FormFieldData(),
-      /*last_four_list_for_suggestion_filtering=*/
+      /*last_four_set_for_cvc_suggestion_filtering=*/
       {}, CREDIT_CARD_VERIFICATION_CODE, kDefaultTriggerSource,
       /*should_show_scan_credit_card=*/false,
       /*should_show_cards_from_account=*/false, summary);
@@ -2131,7 +2138,7 @@
   CreditCardSuggestionSummary summary;
   const std::vector<Suggestion> suggestions = GetSuggestionsForCreditCards(
       *autofill_client(), FormFieldData(),
-      /*last_four_list_for_suggestion_filtering=*/
+      /*last_four_set_for_cvc_suggestion_filtering=*/
       {}, CREDIT_CARD_VERIFICATION_CODE, kDefaultTriggerSource,
       /*should_show_scan_credit_card=*/false,
       /*should_show_cards_from_account=*/false, summary);
@@ -2471,7 +2478,7 @@
 
     CreditCardSuggestionSummary summary;
     GetSuggestionsForCreditCards(*autofill_client(), FormFieldData(),
-                                 /*last_four_list_for_suggestion_filtering=*/
+                                 /*last_four_set_for_cvc_suggestion_filtering=*/
                                  {}, CREDIT_CARD_NUMBER, kDefaultTriggerSource,
                                  /*should_show_scan_credit_card=*/false,
                                  /*should_show_cards_from_account=*/false,
@@ -2506,7 +2513,7 @@
 
     CreditCardSuggestionSummary summary;
     GetSuggestionsForCreditCards(*autofill_client(), FormFieldData(),
-                                 /*last_four_list_for_suggestion_filtering=*/
+                                 /*last_four_set_for_cvc_suggestion_filtering=*/
                                  {}, CREDIT_CARD_NUMBER, kDefaultTriggerSource,
                                  /*should_show_scan_credit_card=*/false,
                                  /*should_show_cards_from_account=*/false,
@@ -2553,7 +2560,7 @@
   CreditCardSuggestionSummary summary;
   std::vector<Suggestion> suggestions = GetSuggestionsForCreditCards(
       *autofill_client(), FormFieldData(),
-      /*last_four_list_for_suggestion_filtering=*/
+      /*last_four_set_for_cvc_suggestion_filtering=*/
       {}, CREDIT_CARD_NUMBER, kDefaultTriggerSource,
       /*should_show_scan_credit_card=*/false,
       /*should_show_cards_from_account=*/false, summary);
@@ -2782,7 +2789,7 @@
 
   CreditCardSuggestionSummary summary;
   GetSuggestionsForCreditCards(*autofill_client(), FormFieldData(),
-                               /*last_four_list_for_suggestion_filtering=*/
+                               /*last_four_set_for_cvc_suggestion_filtering=*/
                                {}, CREDIT_CARD_NUMBER, kDefaultTriggerSource,
                                /*should_show_scan_credit_card=*/false,
                                /*should_show_cards_from_account=*/false,
@@ -2817,7 +2824,7 @@
   payments_data().AddServerCreditCard(card);
   CreditCardSuggestionSummary summary;
   GetSuggestionsForCreditCards(*autofill_client(), FormFieldData(),
-                               /*last_four_list_for_suggestion_filtering=*/
+                               /*last_four_set_for_cvc_suggestion_filtering=*/
                                {}, CREDIT_CARD_NUMBER, kDefaultTriggerSource,
                                /*should_show_scan_credit_card=*/false,
                                /*should_show_cards_from_account=*/false,
@@ -2826,6 +2833,238 @@
       summary.ranking_context.suggestion_rankings_difference_map.empty());
 }
 
+// Params of GetFilteredCardsToSuggestTest:
+// -- bool IsCvcStorageEnhancementEnabled: Indicates if the flag is enabled.
+// -- FieldType get_trigger_field_type: Indicates triggered field type.
+class GetFilteredCardsToSuggestTest
+    : public PaymentsSuggestionGeneratorTest,
+      public testing::WithParamInterface<std::tuple<bool, FieldType>> {
+ public:
+  bool IsCvcStorageEnhancementEnabled() { return std::get<0>(GetParam()); }
+  FieldType get_trigger_field_type() { return std::get<1>(GetParam()); }
+
+ private:
+  void SetUp() override {
+    PaymentsSuggestionGeneratorTest::SetUp();
+    scoped_feature_list_.InitWithFeatureState(
+        features::kAutofillEnableCvcStorageAndFillingEnhancement,
+        IsCvcStorageEnhancementEnabled());
+    // Create 2 local cards and 2 server cards.
+    payments_data().ClearCreditCards();
+    CreditCard local_card_1 =
+        CreateLocalCard(/*guid=*/"00000000-0000-0000-0000-000000000001");
+    local_card_1.SetNumber(u"4111111111111111");
+    CreditCard local_card_2 =
+        CreateLocalCard(/*guid=*/"00000000-0000-0000-0000-000000000002");
+    local_card_2.SetNumber(u"4111111111111112");
+    CreditCard server_card_1 = CreateServerCard(
+        /*guid=*/"00000000-0000-0000-0000-000000000003",
+        /*server_id=*/"server_i3", /*instrument_id=*/1);
+    server_card_1.SetNumber(u"4111111111111113");
+    CreditCard server_card_2 = CreateServerCard(
+        /*guid=*/"00000000-0000-0000-0000-000000000004",
+        /*server_id=*/"server_i4", /*instrument_id=*/1);
+    server_card_2.SetNumber(u"4111111111111114");
+    payments_data().AddCreditCard(local_card_1);
+    payments_data().AddCreditCard(local_card_2);
+    payments_data().AddServerCreditCard(server_card_1);
+    payments_data().AddServerCreditCard(server_card_2);
+  }
+
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+INSTANTIATE_TEST_SUITE_P(
+    PaymentsSuggestionGeneratorTest,
+    GetFilteredCardsToSuggestTest,
+    testing::Combine(
+        testing::Bool(),
+        testing::Values(FieldType::CREDIT_CARD_VERIFICATION_CODE,
+                        FieldType::CREDIT_CARD_NUMBER,
+                        FieldType::CREDIT_CARD_STANDALONE_VERIFICATION_CODE)));
+
+// Verify that suggestions are filtered based on
+// `last_four_set_for_cvc_suggestion_filtering` when flag is on and triggered
+// field type is CVC.
+TEST_P(GetFilteredCardsToSuggestTest, GetFilteredCardsToSuggest) {
+  FormFieldData field;
+  CreditCardSuggestionSummary summary;
+
+  std::vector<Suggestion> suggestions = GetSuggestionsForCreditCards(
+      *autofill_client(), field,
+      /*last_four_set_for_cvc_suggestion_filtering=*/
+      {u"1111", u"1113"}, get_trigger_field_type(), kDefaultTriggerSource,
+      /*should_show_scan_credit_card=*/false,
+      /*should_show_cards_from_account=*/false, summary);
+
+  if (IsCvcStorageEnhancementEnabled() &&
+      (get_trigger_field_type() == FieldType::CREDIT_CARD_VERIFICATION_CODE ||
+       get_trigger_field_type() ==
+           FieldType::CREDIT_CARD_STANDALONE_VERIFICATION_CODE)) {
+    // There are 4 suggestions, 1 for local card suggestion and 1 for server
+    // card suggestion, followed by a separator, and followed by "Manage payment
+    // methods..." which redirects to the Chrome payment methods settings page.
+    EXPECT_THAT(
+        suggestions,
+        UnorderedElementsAre(
+            SuggestionWithGuidPayload(
+                Suggestion::Guid("00000000-0000-0000-0000-000000000001")),
+            SuggestionWithGuidPayload(
+                Suggestion::Guid("00000000-0000-0000-0000-000000000003")),
+            EqualsSuggestion(SuggestionType::kSeparator),
+            EqualsManagePaymentsMethodsSuggestion(/*with_gpay_logo=*/false)));
+    EXPECT_THAT(suggestions,
+                ContainsCreditCardFooterSuggestions(/*with_gpay_logo=*/false));
+  } else {
+    // There are 6 suggestions, 4 for card suggestions, followed by a separator,
+    // and followed by "Manage payment methods..." which redirects to the Chrome
+    // payment methods settings page.
+    EXPECT_THAT(
+        suggestions,
+        UnorderedElementsAre(
+            SuggestionWithGuidPayload(
+                Suggestion::Guid("00000000-0000-0000-0000-000000000001")),
+            SuggestionWithGuidPayload(
+                Suggestion::Guid("00000000-0000-0000-0000-000000000002")),
+            SuggestionWithGuidPayload(
+                Suggestion::Guid("00000000-0000-0000-0000-000000000003")),
+            SuggestionWithGuidPayload(
+                Suggestion::Guid("00000000-0000-0000-0000-000000000004")),
+            EqualsSuggestion(SuggestionType::kSeparator),
+            EqualsManagePaymentsMethodsSuggestion(/*with_gpay_logo=*/false)));
+    EXPECT_THAT(suggestions,
+                ContainsCreditCardFooterSuggestions(/*with_gpay_logo=*/false));
+  }
+}
+
+// Verify that suggestions are not filtered if
+// `last_four_set_for_cvc_suggestion_filtering` is empty.
+TEST_P(GetFilteredCardsToSuggestTest, EmptyFilteringSet) {
+  FormFieldData field;
+  CreditCardSuggestionSummary summary;
+
+  std::vector<Suggestion> suggestions = GetSuggestionsForCreditCards(
+      *autofill_client(), field,
+      /*last_four_set_for_cvc_suggestion_filtering=*/
+      {}, get_trigger_field_type(), kDefaultTriggerSource,
+      /*should_show_scan_credit_card=*/false,
+      /*should_show_cards_from_account=*/false, summary);
+
+  // There are 6 suggestions, 4 for card suggestions, followed by a separator,
+  // and followed by "Manage payment methods..." which redirects to the Chrome
+  // payment methods settings page.
+  EXPECT_THAT(
+      suggestions,
+      UnorderedElementsAre(
+          SuggestionWithGuidPayload(
+              Suggestion::Guid("00000000-0000-0000-0000-000000000001")),
+          SuggestionWithGuidPayload(
+              Suggestion::Guid("00000000-0000-0000-0000-000000000002")),
+          SuggestionWithGuidPayload(
+              Suggestion::Guid("00000000-0000-0000-0000-000000000003")),
+          SuggestionWithGuidPayload(
+              Suggestion::Guid("00000000-0000-0000-0000-000000000004")),
+          EqualsSuggestion(SuggestionType::kSeparator),
+          EqualsManagePaymentsMethodsSuggestion(/*with_gpay_logo=*/false)));
+  EXPECT_THAT(suggestions,
+              ContainsCreditCardFooterSuggestions(/*with_gpay_logo=*/false));
+}
+
+// Verify that suggestions are not filtered if triggered field is not CVC.
+TEST_P(GetFilteredCardsToSuggestTest, TriggerFieldIsNotCvc) {
+  FormFieldData field;
+  CreditCardSuggestionSummary summary;
+
+  std::vector<Suggestion> suggestions = GetSuggestionsForCreditCards(
+      *autofill_client(), field,
+      /*last_four_set_for_cvc_suggestion_filtering=*/
+      {u"1111", u"1112"}, FieldType::CREDIT_CARD_NUMBER, kDefaultTriggerSource,
+      /*should_show_scan_credit_card=*/false,
+      /*should_show_cards_from_account=*/false, summary);
+
+  // There are 6 suggestions, 4 for card suggestions, followed by a separator,
+  // and followed by "Manage payment methods..." which redirects to the Chrome
+  // payment methods settings page.
+  EXPECT_THAT(
+      suggestions,
+      UnorderedElementsAre(
+          SuggestionWithGuidPayload(
+              Suggestion::Guid("00000000-0000-0000-0000-000000000001")),
+          SuggestionWithGuidPayload(
+              Suggestion::Guid("00000000-0000-0000-0000-000000000002")),
+          SuggestionWithGuidPayload(
+              Suggestion::Guid("00000000-0000-0000-0000-000000000003")),
+          SuggestionWithGuidPayload(
+              Suggestion::Guid("00000000-0000-0000-0000-000000000004")),
+          EqualsSuggestion(SuggestionType::kSeparator),
+          EqualsManagePaymentsMethodsSuggestion(/*with_gpay_logo=*/false)));
+  EXPECT_THAT(suggestions,
+              ContainsCreditCardFooterSuggestions(/*with_gpay_logo=*/false));
+}
+
+// Verify that suggestions are empty if there is no card matched.
+TEST_P(GetFilteredCardsToSuggestTest, NoMatchCard) {
+  FormFieldData field;
+  CreditCardSuggestionSummary summary;
+
+  std::vector<Suggestion> suggestions = GetSuggestionsForCreditCards(
+      *autofill_client(), field,
+      /*last_four_set_for_cvc_suggestion_filtering=*/
+      {u"9999"}, get_trigger_field_type(), kDefaultTriggerSource,
+      /*should_show_scan_credit_card=*/false,
+      /*should_show_cards_from_account=*/false, summary);
+
+  if (IsCvcStorageEnhancementEnabled() &&
+      (get_trigger_field_type() == FieldType::CREDIT_CARD_VERIFICATION_CODE ||
+       get_trigger_field_type() ==
+           FieldType::CREDIT_CARD_STANDALONE_VERIFICATION_CODE)) {
+    // There are no suggestions.
+    EXPECT_EQ(suggestions.size(), 0U);
+  } else {
+    EXPECT_THAT(
+        suggestions,
+        UnorderedElementsAre(
+            SuggestionWithGuidPayload(
+                Suggestion::Guid("00000000-0000-0000-0000-000000000001")),
+            SuggestionWithGuidPayload(
+                Suggestion::Guid("00000000-0000-0000-0000-000000000002")),
+            SuggestionWithGuidPayload(
+                Suggestion::Guid("00000000-0000-0000-0000-000000000003")),
+            SuggestionWithGuidPayload(
+                Suggestion::Guid("00000000-0000-0000-0000-000000000004")),
+            EqualsSuggestion(SuggestionType::kSeparator),
+            EqualsManagePaymentsMethodsSuggestion(/*with_gpay_logo=*/false)));
+  }
+}
+
+// Verify that suggestions are not filtered if triggered from manual fallback.
+TEST_P(GetFilteredCardsToSuggestTest, NofilteringForManualFallbacks) {
+  FormFieldData field;
+  CreditCardSuggestionSummary summary;
+
+  std::vector<Suggestion> suggestions = GetSuggestionsForCreditCards(
+      *autofill_client(), field,
+      /*last_four_set_for_cvc_suggestion_filtering=*/
+      {u"1111"}, get_trigger_field_type(),
+      AutofillSuggestionTriggerSource::kManualFallbackPayments,
+      /*should_show_scan_credit_card=*/false,
+      /*should_show_cards_from_account=*/false, summary);
+
+  EXPECT_THAT(
+      suggestions,
+      UnorderedElementsAre(
+          SuggestionWithGuidPayload(
+              Suggestion::Guid("00000000-0000-0000-0000-000000000001")),
+          SuggestionWithGuidPayload(
+              Suggestion::Guid("00000000-0000-0000-0000-000000000002")),
+          SuggestionWithGuidPayload(
+              Suggestion::Guid("00000000-0000-0000-0000-000000000003")),
+          SuggestionWithGuidPayload(
+              Suggestion::Guid("00000000-0000-0000-0000-000000000004")),
+          EqualsSuggestion(SuggestionType::kSeparator),
+          EqualsManagePaymentsMethodsSuggestion(/*with_gpay_logo=*/false)));
+}
+
 TEST_F(
     PaymentsSuggestionGeneratorTestWithNewSuggestionRankingAlgorithm,
     GetSuggestionsForCreditCards_SuggestionRankingContext_NoRankingDifference) {
@@ -2840,7 +3079,7 @@
 
   CreditCardSuggestionSummary summary;
   GetSuggestionsForCreditCards(*autofill_client(), FormFieldData(),
-                               /*last_four_list_for_suggestion_filtering=*/
+                               /*last_four_set_for_cvc_suggestion_filtering=*/
                                {}, CREDIT_CARD_NUMBER, kDefaultTriggerSource,
                                /*should_show_scan_credit_card=*/false,
                                /*should_show_cards_from_account=*/false,
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamQuicTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamQuicTest.java
index 26ea2f1a..acbee7b1 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamQuicTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamQuicTest.java
@@ -8,6 +8,8 @@
 
 import static org.chromium.net.truth.UrlResponseInfoSubject.assertThat;
 
+import android.os.Build;
+
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
@@ -16,10 +18,13 @@
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.RuleChain;
 import org.junit.runner.RunWith;
 
 import org.chromium.net.CronetTestRule.CronetImplementation;
 import org.chromium.net.CronetTestRule.IgnoreFor;
+import org.chromium.net.impl.CronetLogger.CronetTrafficInfo;
+import org.chromium.net.impl.TestLogger;
 
 import java.nio.ByteBuffer;
 import java.util.Date;
@@ -33,12 +38,19 @@
                 "The fallback implementation doesn't support bidirectional streaming. "
                         + "crbug.com/1494870: Enable for AOSP_PLATFORM once fixed")
 public class BidirectionalStreamQuicTest {
-    @Rule public final CronetTestRule mTestRule = CronetTestRule.withManualEngineStartup();
+    private final CronetTestRule mTestRule = CronetTestRule.withManualEngineStartup();
+    private final CronetLoggerTestRule<TestLogger> mLoggerTestRule =
+            new CronetLoggerTestRule<>(TestLogger.class);
+
+    @Rule public final RuleChain chain = RuleChain.outerRule(mTestRule).around(mLoggerTestRule);
+
+    private TestLogger mTestLogger;
 
     private ExperimentalCronetEngine mCronetEngine;
 
     @Before
     public void setUp() throws Exception {
+        mTestLogger = mLoggerTestRule.mTestLogger;
         mTestRule
                 .getTestFramework()
                 .applyEngineBuilderPatch(
@@ -46,7 +58,9 @@
                             QuicTestServer.startQuicTestServer(
                                     mTestRule.getTestFramework().getContext());
 
-                            JSONObject quicParams = new JSONObject();
+                            JSONObject quicParams =
+                                    new JSONObject()
+                                            .put("retry_without_alt_svc_on_quic_errors", false);
                             JSONObject hostResolverParams =
                                     CronetTestUtil.generateHostResolverRules();
                             JSONObject experimentalOptions =
@@ -68,6 +82,7 @@
 
     @After
     public void tearDown() throws Exception {
+        mTestLogger = null;
         QuicTestServer.shutdownQuicTestServer();
     }
 
@@ -337,7 +352,7 @@
 
     @Test
     @SmallTest
-    public void testStreamFailWithQuicDetailedErrorCode() throws Exception {
+    public void testServerAbruptShutdownShouldTerminateConnection() throws Exception {
         String path = "/simple.txt";
         String quicURL = QuicTestServer.getServerURL() + path;
         TestBidirectionalStreamCallback callback =
@@ -360,10 +375,54 @@
         callback.blockForDone();
         assertThat(stream.isDone()).isTrue();
         assertThat(callback.mError).isNotNull();
-        if (callback.mError instanceof QuicException) {
-            QuicException quicException = (QuicException) callback.mError;
-            // Checks that detailed quic error code is not QUIC_NO_ERROR == 0.
-            assertThat(quicException.getQuicDetailedErrorCode()).isGreaterThan(0);
+        // TODO(b/365787337): Investigate the flaky QUIC error code when the server shuts down
+        // abruptly.
+        // The network error returned when a server shutdowns abruptly is non-deterministic
+        // for the test server that we are using (QuicTestServer). It could return one of the
+        // following:
+        // (1) QuicException with error code (51) PACKET_READ_ERROR.
+        // (2) QuicException with error code (16) PEER_GOING_AWAY.
+        // (3) BidirectionalStreamNetworkException with internal error code
+        // ERR_QUIC_GOAWAY_REQUEST_CAN_BE_RETRIED.
+        // That's why there is no explicit check for the error code.
+        assertThat(callback.mError).isInstanceOf(NetworkException.class);
+    }
+
+    @Test
+    @SmallTest
+    public void testServerSendQuicConnectionCloseCorrectlyReported() throws Exception {
+        String quicURL = QuicTestServer.getServerURL() + QuicTestServer.getConnectionClosePath();
+        TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCallback();
+        BidirectionalStream stream =
+                mCronetEngine
+                        .newBidirectionalStreamBuilder(quicURL, callback, callback.getExecutor())
+                        .setHttpMethod("GET")
+                        .addHeader("Content-Type", "zebra")
+                        .build();
+        stream.start();
+        callback.blockForDone();
+        assertThat(stream.isDone()).isTrue();
+        assertThat(callback.mError).isNotNull();
+
+        assertThat(callback.mError).isInstanceOf(QuicException.class);
+        QuicException quicException = (QuicException) callback.mError;
+        // 0 is QUIC_NO_ERROR, This is expected because of the test-server behavior, see
+        // https://source.chromium.org/chromium/_/quiche/quiche/+/86e3e869377b05a7143dfa07a4d1219881396661:quiche/quic/tools/quic_simple_server_stream.cc;l=286;
+        assertThat(quicException.getQuicDetailedErrorCode()).isEqualTo(0);
+        assertThat(quicException.getConnectionCloseSource()).isEqualTo(ConnectionCloseSource.PEER);
+        assertThat(quicException.getErrorCode())
+                .isEqualTo(NetworkException.ERROR_QUIC_PROTOCOL_FAILED);
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+            mTestLogger.waitForLogCronetTrafficInfo();
+            final CronetTrafficInfo trafficInfo = mTestLogger.getLastCronetTrafficInfo();
+            assertThat(trafficInfo.getConnectionCloseSource())
+                    .isEqualTo(quicException.getConnectionCloseSource());
+            assertThat(trafficInfo.getNetworkInternalErrorCode())
+                    .isEqualTo(quicException.getCronetInternalErrorCode());
+            assertThat(trafficInfo.getQuicErrorCode())
+                    .isEqualTo(quicException.getQuicDetailedErrorCode());
+            assertThat(trafficInfo.getFailureReason())
+                    .isEqualTo(CronetTrafficInfo.RequestFailureReason.NETWORK);
         }
     }
 }
diff --git a/components/data_sharing/public/android/java/src/org/chromium/components/data_sharing/DataSharingUIDelegate.java b/components/data_sharing/public/android/java/src/org/chromium/components/data_sharing/DataSharingUIDelegate.java
index e50ce1e6..3c7c8f2 100644
--- a/components/data_sharing/public/android/java/src/org/chromium/components/data_sharing/DataSharingUIDelegate.java
+++ b/components/data_sharing/public/android/java/src/org/chromium/components/data_sharing/DataSharingUIDelegate.java
@@ -14,7 +14,6 @@
 import org.jni_zero.JNINamespace;
 
 import org.chromium.base.Callback;
-import org.chromium.base.UserData;
 import org.chromium.components.data_sharing.configs.AvatarConfig;
 import org.chromium.components.data_sharing.configs.GroupMemberConfig;
 import org.chromium.components.data_sharing.configs.MemberPickerConfig;
@@ -22,9 +21,9 @@
 
 import java.util.List;
 
-/** An interface that shows sharing UI screens. TODO(b/339685767): Remove UserData base class. */
+/** An interface that shows sharing UI screens. */
 @JNINamespace("data_sharing")
-public interface DataSharingUIDelegate extends UserData {
+public interface DataSharingUIDelegate {
 
     /** Interface for callback when members are picked. */
     public interface MemberPickerListener {
diff --git a/components/device_signals/core/browser/base_signals_collector.cc b/components/device_signals/core/browser/base_signals_collector.cc
index e2da467..8ef1b6b 100644
--- a/components/device_signals/core/browser/base_signals_collector.cc
+++ b/components/device_signals/core/browser/base_signals_collector.cc
@@ -13,7 +13,7 @@
 namespace device_signals {
 
 BaseSignalsCollector::BaseSignalsCollector(
-    const std::unordered_map<const SignalName, GetSignalCallback>
+    std::unordered_map<const SignalName, GetSignalCallback>
         signals_collection_map)
     : signals_collection_map_(std::move(signals_collection_map)) {
   DCHECK(!signals_collection_map_.empty());
diff --git a/components/device_signals/core/browser/base_signals_collector.h b/components/device_signals/core/browser/base_signals_collector.h
index d5c93187..d60f417 100644
--- a/components/device_signals/core/browser/base_signals_collector.h
+++ b/components/device_signals/core/browser/base_signals_collector.h
@@ -31,7 +31,7 @@
                                    base::OnceClosure)>;
 
   explicit BaseSignalsCollector(
-      const std::unordered_map<const SignalName, GetSignalCallback>
+      std::unordered_map<const SignalName, GetSignalCallback>
           signals_collection_map);
 
  private:
diff --git a/components/enterprise/obfuscation/core/utils.cc b/components/enterprise/obfuscation/core/utils.cc
index f3378dd..e433b513 100644
--- a/components/enterprise/obfuscation/core/utils.cc
+++ b/components/enterprise/obfuscation/core/utils.cc
@@ -181,11 +181,11 @@
   base::span<const uint8_t> salt = base::span(header).subspan(1, kSaltSize);
 
   // Extract nonce_prefix.
-  const std::vector<uint8_t> nonce_prefix(header.begin() + 1 + kSaltSize,
-                                          header.end());
+  std::vector<uint8_t> nonce_prefix(header.begin() + 1 + kSaltSize,
+                                    header.end());
 
   // Generate file-specific key.
-  const std::vector<uint8_t> derived_key = crypto::HkdfSha256(
+  std::vector<uint8_t> derived_key = crypto::HkdfSha256(
       GetSymmetricKey(), salt, base::span<uint8_t>(), kKeySize);
 
   return base::ok(std::pair(std::move(derived_key), std::move(nonce_prefix)));
diff --git a/components/history/core/browser/visit_database.cc b/components/history/core/browser/visit_database.cc
index e28d5bf..ff83bc3 100644
--- a/components/history/core/browser/visit_database.cc
+++ b/components/history/core/browser/visit_database.cc
@@ -42,7 +42,7 @@
   // '/'. This effectively applies the GLOB optimization by doing it in C++
   // instead of relying on SQLite to do it.
   static_assert('/' + 1 == '0', "");
-  const std::string origin_query_min = origin.DeprecatedGetOriginAsURL().spec();
+  std::string origin_query_min = origin.DeprecatedGetOriginAsURL().spec();
   DCHECK(!origin_query_min.empty());
   DCHECK_EQ('/', origin_query_min.back());
 
diff --git a/components/history/core/browser/visitsegment_database.cc b/components/history/core/browser/visitsegment_database.cc
index 3899624..c61104e 100644
--- a/components/history/core/browser/visitsegment_database.cc
+++ b/components/history/core/browser/visitsegment_database.cc
@@ -10,12 +10,14 @@
 
 #include <algorithm>
 #include <memory>
+#include <numeric>
 #include <string>
 #include <string_view>
 #include <vector>
 
 #include "base/check_op.h"
 #include "base/functional/callback.h"
+#include "base/memory/raw_ptr.h"
 #include "base/strings/string_util.h"
 #include "components/history/core/browser/page_usage_data.h"
 #include "sql/statement.h"
@@ -37,11 +39,91 @@
 
 namespace history {
 
-VisitSegmentDatabase::VisitSegmentDatabase() {
+namespace {
+
+constexpr SegmentID kEmptySegmentID = 0;
+
+struct SegmentInfo {
+  SegmentID segment_id;
+  std::vector<base::Time> time_slots;
+  std::vector<int> visit_counts;
+};
+
+// Visits segment_usage entries in the history database, grouped by segment ID
+// and ordered by increasing segment ID.
+class SegmentVisitor {
+ public:
+  // |statement| selects (segment_id, time_slot, visit_count) from segment_usage
+  // table, ordered by segment_id.
+  explicit SegmentVisitor(raw_ptr<sql::Statement> statement)
+      : statement_(statement) {
+    cur_segment_id_ = (statement_->is_valid() && statement_->Step())
+                          ? statement_->ColumnInt64(0)
+                          : kEmptySegmentID;
+  }
+
+  ~SegmentVisitor() = default;
+
+  // Reads the next batch of segment_usage entries with a common segment ID, and
+  // writes the result to |*segment_info|. Returns whether the returned entry is
+  // valid. If false, clears |*segment_info|.
+  bool Step(SegmentInfo* segment_info) {
+    segment_info->segment_id = cur_segment_id_;
+    segment_info->time_slots.clear();
+    segment_info->visit_counts.clear();
+
+    if (cur_segment_id_ == kEmptySegmentID) {
+      return false;
+    }
+
+    SegmentID next_segment_id = kEmptySegmentID;
+    do {
+      segment_info->time_slots.push_back(statement_->ColumnTime(1));
+      segment_info->visit_counts.push_back(statement_->ColumnInt(2));
+      next_segment_id =
+          statement_->Step() ? statement_->ColumnInt64(0) : kEmptySegmentID;
+    } while (next_segment_id == cur_segment_id_);
+
+    cur_segment_id_ = next_segment_id;
+    return true;
+  }
+
+ private:
+  raw_ptr<sql::Statement> statement_;
+
+  // Look-ahead SegmentID of the segment to be retrieved for the next Step()
+  // call. Indicates end of data if value is |kEmptySegmentID|.
+  SegmentID cur_segment_id_;
+};
+
+// Scoring function for a segment.
+float ComputeSegmentScore(const SegmentInfo& segment_info, base::Time now) {
+  float score = 0.0f;
+  size_t n = segment_info.time_slots.size();
+  for (size_t i = 0; i < n; ++i) {
+    base::Time time_slot = segment_info.time_slots[i];
+    int visit_count = segment_info.visit_counts[i];
+    // Score for this day in isolation.
+    float day_visits_score = (visit_count <= 0.0f)
+                                 ? 0.0f
+                                 : 1.0f + log(static_cast<float>(visit_count));
+    // Recent visits count more than historical ones, so we multiply in a boost
+    // related to how long ago this day was.
+    // This boost is a curve that smoothly goes through these values:
+    // Today gets 3x, a week ago 2x, three weeks ago 1.5x, falling off to 1x at
+    // the limit of how far we reach into the past.
+    int days_ago = (now - time_slot).InDays();
+    float recency_boost = 1.0f + (2.0f * (1.0f / (1.0f + days_ago / 7.0f)));
+    score += recency_boost * day_visits_score;
+  }
+  return score;
 }
 
-VisitSegmentDatabase::~VisitSegmentDatabase() {
-}
+}  // namespace
+
+VisitSegmentDatabase::VisitSegmentDatabase() = default;
+
+VisitSegmentDatabase::~VisitSegmentDatabase() = default;
 
 bool VisitSegmentDatabase::InitSegmentTables() {
   // Segments table.
@@ -198,16 +280,15 @@
   return true;
 }
 
+// Gathers the highest-ranked segments, computed in two phases.
 std::vector<std::unique_ptr<PageUsageData>>
 VisitSegmentDatabase::QuerySegmentUsage(
     int max_result_count,
     const base::RepeatingCallback<bool(const GURL&)>& url_filter) {
-  // This function gathers the highest-ranked segments in two queries.
-  // The first gathers scores for all segments.
-  // The second gathers segment data (url, title, etc.) for the highest-ranked
-  // segments.
+  // Phase 1: Gather all segments and compute scores.
+  std::vector<std::unique_ptr<PageUsageData>> segments;
+  base::Time now = base::Time::Now();
 
-  // Gather all the segment scores.
   sql::Statement statement(
       GetDB().GetCachedStatement(SQL_FROM_HERE,
                                  "SELECT segment_id, time_slot, visit_count "
@@ -215,38 +296,20 @@
   if (!statement.is_valid())
     return std::vector<std::unique_ptr<PageUsageData>>();
 
-  std::vector<std::unique_ptr<PageUsageData>> segments;
-  base::Time now = base::Time::Now();
-  SegmentID previous_segment_id = 0;
-  while (statement.Step()) {
-    SegmentID segment_id = statement.ColumnInt64(0);
-    if (segment_id != previous_segment_id) {
-      segments.push_back(std::make_unique<PageUsageData>(segment_id));
-      previous_segment_id = segment_id;
-    }
+  SegmentVisitor segment_visitor(&statement);
+  SegmentInfo segment_info;
+  while (segment_visitor.Step(&segment_info)) {
+    DCHECK(!segment_info.time_slots.empty());
+    DCHECK_EQ(segment_info.time_slots.size(), segment_info.visit_counts.size());
 
-    base::Time timeslot = statement.ColumnTime(1);
-    if (timeslot > segments.back()->GetLastVisitTimeslot()) {
-      segments.back()->SetLastVisitTimeslot(timeslot);
-    }
-
-    int visit_count = statement.ColumnInt(2);
-    segments.back()->SetVisitCount(segments.back()->GetVisitCount() +
-                                   visit_count);
-
-    // Score for this day in isolation.
-    float day_visits_score = visit_count <= 0.0f
-                                 ? 0.0f
-                                 : 1.0f + log(static_cast<float>(visit_count));
-    // Recent visits count more than historical ones, so we multiply in a boost
-    // related to how long ago this day was.
-    // This boost is a curve that smoothly goes through these values:
-    // Today gets 3x, a week ago 2x, three weeks ago 1.5x, falling off to 1x
-    // at the limit of how far we reach into the past.
-    int days_ago = (now - timeslot).InDays();
-    float recency_boost = 1.0f + (2.0f * (1.0f / (1.0f + days_ago/7.0f)));
-    float score = recency_boost * day_visits_score;
-    segments.back()->SetScore(segments.back()->GetScore() + score);
+    std::unique_ptr<PageUsageData> segment =
+        std::make_unique<PageUsageData>(segment_info.segment_id);
+    segment->SetLastVisitTimeslot(*std::max_element(
+        segment_info.time_slots.begin(), segment_info.time_slots.end()));
+    segment->SetVisitCount(std::accumulate(segment_info.visit_counts.begin(),
+                                           segment_info.visit_counts.end(), 0));
+    segment->SetScore(ComputeSegmentScore(segment_info, now));
+    segments.push_back(std::move(segment));
   }
 
   // Order by descending scores.
@@ -256,12 +319,11 @@
               return lhs->GetScore() > rhs->GetScore();
             });
 
-  // Now fetch the details about the entries we care about.
+  // Phase 2: Read details (url, title, etc.) for the highest-ranked segments.
   sql::Statement statement2(GetDB().GetCachedStatement(SQL_FROM_HERE,
       "SELECT urls.url, urls.title FROM urls "
       "JOIN segments ON segments.url_id = urls.id "
       "WHERE segments.id = ?"));
-
   if (!statement2.is_valid())
     return std::vector<std::unique_ptr<PageUsageData>>();
 
diff --git a/components/keyed_service/README.md b/components/keyed_service/README.md
index 779c2cd..86198bd 100644
--- a/components/keyed_service/README.md
+++ b/components/keyed_service/README.md
@@ -3,8 +3,8 @@
 content::BrowserContext or web::BrowserState), and whose teardown order is
 managed according to the expressed dependency order.
 
-KeyedService is a layered component
-(https://sites.google.com/a/chromium.org/dev/developers/design-documents/layered-components-design)
+KeyedService is a
+[layered component](https://crsrc.org/docs/website/site/developers/design-documents/layered-components-design/index.md)
 to enable it to be shared cleanly on iOS.
 
 This component has the following structure:
diff --git a/components/language_detection/content/browser/BUILD.gn b/components/language_detection/content/browser/BUILD.gn
index f032a23..1a81fe8 100644
--- a/components/language_detection/content/browser/BUILD.gn
+++ b/components/language_detection/content/browser/BUILD.gn
@@ -13,7 +13,7 @@
   deps = [
     "//base",
     "//components/language_detection/content/common:common",
-    "//components/translate/core/browser:translate_model_service",
+    "//components/language_detection/core/browser:language_detection_model_service",
     "//mojo/public/cpp/bindings:bindings",
   ]
 }
diff --git a/components/language_detection/content/browser/DEPS b/components/language_detection/content/browser/DEPS
index 9cdd7506..5354567 100644
--- a/components/language_detection/content/browser/DEPS
+++ b/components/language_detection/content/browser/DEPS
@@ -1,3 +1,3 @@
 include_rules = [
-  "+components/translate/core/browser/translate_model_service.h",
+  "+components/language_detection/core/browser",
 ]
diff --git a/components/language_detection/content/browser/content_language_detection_driver.cc b/components/language_detection/content/browser/content_language_detection_driver.cc
index 2bbfdd1..88d7d75 100644
--- a/components/language_detection/content/browser/content_language_detection_driver.cc
+++ b/components/language_detection/content/browser/content_language_detection_driver.cc
@@ -6,13 +6,13 @@
 
 #include <memory>
 
-#include "components/translate/core/browser/translate_model_service.h"
+#include "components/language_detection/core/browser/language_detection_model_service.h"
 
 namespace language_detection {
 
 ContentLanguageDetectionDriver::ContentLanguageDetectionDriver(
-    translate::TranslateModelService* translate_model_service)
-    : translate_model_service_(translate_model_service) {}
+    LanguageDetectionModelService* language_detection_model_service)
+    : language_detection_model_service_(language_detection_model_service) {}
 
 ContentLanguageDetectionDriver::~ContentLanguageDetectionDriver() = default;
 
@@ -23,34 +23,13 @@
 
 void ContentLanguageDetectionDriver::GetLanguageDetectionModel(
     GetLanguageDetectionModelCallback callback) {
-  if (!translate_model_service_) {
+  if (!language_detection_model_service_) {
     std::move(callback).Run(base::File());
     return;
   }
-  // If the model file is not available, request the translate model service
-  // notify `this` when it is. The two-step process is to ensure that
-  // the model file and callback lifetimes are carefully managed so they
-  // are not freed without be handled on the appropriate thread, particularly
-  // for the model file.
-  if (!translate_model_service_->IsModelAvailable()) {
-    translate_model_service_->NotifyOnModelFileAvailable(base::BindOnce(
-        &ContentLanguageDetectionDriver::OnLanguageModelFileAvailabilityChanged,
-        weak_pointer_factory_.GetWeakPtr(), std::move(callback)));
-    return;
-  }
 
-  OnLanguageModelFileAvailabilityChanged(std::move(callback), true);
-}
-
-void ContentLanguageDetectionDriver::OnLanguageModelFileAvailabilityChanged(
-    GetLanguageDetectionModelCallback callback,
-    bool is_available) {
-  if (!is_available) {
-    std::move(callback).Run(base::File());
-    return;
-  }
-  std::move(callback).Run(
-      translate_model_service_->GetLanguageDetectionModelFile());
+  language_detection_model_service_->GetLanguageDetectionModelFile(
+      std::move(callback));
 }
 
 }  // namespace language_detection
diff --git a/components/language_detection/content/browser/content_language_detection_driver.h b/components/language_detection/content/browser/content_language_detection_driver.h
index d414898..fd08529 100644
--- a/components/language_detection/content/browser/content_language_detection_driver.h
+++ b/components/language_detection/content/browser/content_language_detection_driver.h
@@ -13,18 +13,16 @@
 #include "mojo/public/cpp/bindings/receiver_set.h"
 #include "mojo/public/cpp/bindings/remote.h"
 
-namespace translate {
-class TranslateModelService;
-}  // namespace translate
-
 namespace language_detection {
 
+class LanguageDetectionModelService;
+
 // Content implementation of LanguageDetectionDriver.
 class ContentLanguageDetectionDriver
     : public mojom::ContentLanguageDetectionDriver {
  public:
   explicit ContentLanguageDetectionDriver(
-      translate::TranslateModelService* translate_model_service);
+      LanguageDetectionModelService* language_detection_model_service);
 
   ContentLanguageDetectionDriver(const ContentLanguageDetectionDriver&) =
       delete;
@@ -59,7 +57,8 @@
 
   // The service that provides the model files needed for translate. Not owned
   // but guaranteed to outlive `this`.
-  const raw_ptr<translate::TranslateModelService> translate_model_service_;
+  const raw_ptr<LanguageDetectionModelService>
+      language_detection_model_service_;
 
   base::WeakPtrFactory<ContentLanguageDetectionDriver> weak_pointer_factory_{
       this};
diff --git a/components/language_detection/content/renderer/language_detection_agent.cc b/components/language_detection/content/renderer/language_detection_agent.cc
index c29e732..03d200b 100644
--- a/components/language_detection/content/renderer/language_detection_agent.cc
+++ b/components/language_detection/content/renderer/language_detection_agent.cc
@@ -7,7 +7,10 @@
 #include "base/functional/bind.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/task/task_traits.h"
+#include "base/task/thread_pool.h"
 #include "base/trace_event/trace_event.h"
+#include "components/language_detection/core/features.h"
 #include "components/language_detection/core/language_detection_model.h"
 #include "components/language_detection/core/language_detection_provider.h"
 #include "content/public/renderer/render_frame.h"
@@ -64,9 +67,26 @@
   TRACE_EVENT("browser", "TranslateAgent::UpdateLanguageDetectionModel");
   base::ScopedUmaHistogramTimer timer(
       "LanguageDetection.TFLiteModel.UpdateLanaguageDetectionModelTime");
-  language_detection::LanguageDetectionModel& language_detection_model =
-      language_detection::GetLanguageDetectionModel();
-  language_detection_model.UpdateWithFile(std::move(model_file));
+
+  auto update_file = base::BindOnce(
+      [](base::File model_file) {
+        language_detection::LanguageDetectionModel& language_detection_model =
+            language_detection::GetLanguageDetectionModel();
+        language_detection_model.UpdateWithFile(std::move(model_file));
+      },
+      std::move(model_file));
+
+  // When enabled, we postpone updating the language detection model to avoid
+  // congesting the render main thread during navigation critical timing
+  // (crbug.com/361215212).
+  if (base::FeatureList::IsEnabled(
+          language_detection::features::kLazyUpdateTranslateModel)) {
+    base::ThreadPool::PostTask(
+        FROM_HERE, {base::TaskPriority::BEST_EFFORT, base::MayBlock()},
+        std::move(update_file));
+  } else {
+    std::move(update_file).Run();
+  }
 }
 
 void LanguageDetectionAgent::WasShown() {
diff --git a/components/language_detection/core/BUILD.gn b/components/language_detection/core/BUILD.gn
index 6bf9e55..d537e48 100644
--- a/components/language_detection/core/BUILD.gn
+++ b/components/language_detection/core/BUILD.gn
@@ -7,6 +7,8 @@
 # instance in each component that uses the library.
 component("language_detection") {
   sources = [
+    "features.cc",
+    "features.h",
     "language_detection_provider.cc",
     "language_detection_provider.h",
   ]
diff --git a/components/language_detection/core/browser/BUILD.gn b/components/language_detection/core/browser/BUILD.gn
new file mode 100644
index 0000000..a01ed5f7
--- /dev/null
+++ b/components/language_detection/core/browser/BUILD.gn
@@ -0,0 +1,19 @@
+# Copyright 2024 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/ui.gni")
+
+static_library("language_detection_model_service") {
+  sources = [
+    "language_detection_model_service.cc",
+    "language_detection_model_service.h",
+  ]
+  deps = [
+    "//base",
+    "//components/keyed_service/core",
+    "//components/optimization_guide/core",
+    "//components/optimization_guide/proto:optimization_guide_proto",
+    "//mojo/public/cpp/bindings",
+  ]
+}
diff --git a/components/language_detection/core/browser/DEPS b/components/language_detection/core/browser/DEPS
new file mode 100644
index 0000000..35b3868
--- /dev/null
+++ b/components/language_detection/core/browser/DEPS
@@ -0,0 +1,5 @@
+include_rules = [
+  "+components/keyed_service/core",
+  "+components/optimization_guide/proto",
+  "+mojo/public/cpp",
+]
diff --git a/components/translate/core/browser/translate_model_service.cc b/components/language_detection/core/browser/language_detection_model_service.cc
similarity index 63%
rename from components/translate/core/browser/translate_model_service.cc
rename to components/language_detection/core/browser/language_detection_model_service.cc
index d14b6149..7870af2 100644
--- a/components/translate/core/browser/translate_model_service.cc
+++ b/components/language_detection/core/browser/language_detection_model_service.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/translate/core/browser/translate_model_service.h"
+#include "components/language_detection/core/browser/language_detection_model_service.h"
 
 #include "base/files/file.h"
 #include "base/files/file_path.h"
@@ -18,20 +18,32 @@
 
 // Load the model file at the provided file path.
 base::File LoadModelFile(const base::FilePath& model_file_path) {
-  if (!base::PathExists(model_file_path))
-    return base::File();
-
   return base::File(model_file_path,
                     base::File::FLAG_OPEN | base::File::FLAG_READ);
 }
 
 // Close the provided model file.
 void CloseModelFile(base::File model_file) {
-  if (!model_file.IsValid())
+  if (!model_file.IsValid()) {
     return;
+  }
   model_file.Close();
 }
 
+void PostGetModelCallback(
+    language_detection::LanguageDetectionModelService::GetModelCallback
+        callback,
+    base::File file) {
+  // Posts to the same task runner as PostTaskAndReply.
+  base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
+      FROM_HERE,
+      base::BindOnce(
+          [](language_detection::LanguageDetectionModelService::GetModelCallback
+                 callback,
+             base::File file) { std::move(callback).Run(std::move(file)); },
+          std::move(callback), std::move(file)));
+}
+
 // Util class for recording the result of loading the detection model. The
 // result is recorded when it goes out of scope and its destructor is called.
 class ScopedModelLoadingResultRecorder {
@@ -48,15 +60,11 @@
   bool was_loaded_ = false;
 };
 
-// The maximum number of pending model requests allowed to be kept
-// by the TranslateModelService.
-constexpr int kMaxPendingRequestsAllowed = 100;
-
 }  // namespace
 
-namespace translate {
+namespace language_detection {
 
-TranslateModelService::TranslateModelService(
+LanguageDetectionModelService::LanguageDetectionModelService(
     optimization_guide::OptimizationGuideModelProvider* opt_guide,
     const scoped_refptr<base::SequencedTaskRunner>& background_task_runner)
     : opt_guide_(opt_guide), background_task_runner_(background_task_runner) {
@@ -65,43 +73,47 @@
       /*model_metadata=*/std::nullopt, this);
 }
 
-TranslateModelService::~TranslateModelService() {
+LanguageDetectionModelService::~LanguageDetectionModelService() {
   opt_guide_->RemoveObserverForOptimizationTargetModel(
       optimization_guide::proto::OPTIMIZATION_TARGET_LANGUAGE_DETECTION, this);
   // Clear any pending requests, no model file is acceptable as shutdown is
   // happening.
-  NotifyModelUpdatesAndClear(false);
+  NotifyModelUpdatesAndClear();
 }
 
-void TranslateModelService::Shutdown() {
+void LanguageDetectionModelService::Shutdown() {
   // This and the optimization guide are keyed services, currently optimization
   // guide is a BrowserContextKeyedService, it will be cleaned first so removing
   // the observer should not be performed.
   UnloadModelFile();
   // Clear any pending requests, no model file is acceptable as shutdown is
   // happening.
-  NotifyModelUpdatesAndClear(false);
+  NotifyModelUpdatesAndClear();
 }
 
-void TranslateModelService::UnloadModelFile() {
+void LanguageDetectionModelService::UnloadModelFile() {
   if (language_detection_model_file_) {
     // If the model file is already loaded, it should be closed on a
     // background thread.
     background_task_runner_->PostTask(
         FROM_HERE, base::BindOnce(&CloseModelFile,
                                   std::move(*language_detection_model_file_)));
+  } else {
+    language_detection_model_file_ = base::File();
   }
 }
 
-void TranslateModelService::NotifyModelUpdatesAndClear(
-    bool is_model_available) {
+void LanguageDetectionModelService::NotifyModelUpdatesAndClear() {
+  // We should always have a (possibly invalid) file by now.
+  CHECK(language_detection_model_file_);
   for (auto& pending_request : pending_model_requests_) {
-    std::move(pending_request).Run(is_model_available);
+    PostGetModelCallback(std::move(pending_request),
+                         language_detection_model_file_->Duplicate());
   }
   pending_model_requests_.clear();
 }
 
-void TranslateModelService::OnModelUpdated(
+void LanguageDetectionModelService::OnModelUpdated(
     optimization_guide::proto::OptimizationTarget optimization_target,
     base::optional_ref<const optimization_guide::ModelInfo> model_info) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -111,44 +123,39 @@
   }
   if (!model_info.has_value()) {
     UnloadModelFile();
-    NotifyModelUpdatesAndClear(false);
+    NotifyModelUpdatesAndClear();
     return;
   }
   background_task_runner_->PostTaskAndReplyWithResult(
       FROM_HERE, base::BindOnce(&LoadModelFile, model_info->GetModelFilePath()),
-      base::BindOnce(&TranslateModelService::OnModelFileLoaded,
+      base::BindOnce(&LanguageDetectionModelService::OnModelFileLoaded,
                      weak_ptr_factory_.GetWeakPtr()));
 }
 
-void TranslateModelService::OnModelFileLoaded(base::File model_file) {
+void LanguageDetectionModelService::OnModelFileLoaded(base::File model_file) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   ScopedModelLoadingResultRecorder result_recorder;
-  if (!model_file.IsValid())
+  if (!model_file.IsValid()) {
     return;
+  }
 
   UnloadModelFile();
   language_detection_model_file_ = std::move(model_file);
   result_recorder.set_was_loaded();
-  NotifyModelUpdatesAndClear(true);
+  NotifyModelUpdatesAndClear();
 }
 
-base::File TranslateModelService::GetLanguageDetectionModelFile() {
-  DCHECK(IsModelAvailable());
-  if (!language_detection_model_file_) {
-    return base::File();
-  }
-  // The model must be valid at this point.
-  DCHECK(language_detection_model_file_->IsValid());
-  return language_detection_model_file_->Duplicate();
-}
-
-void TranslateModelService::NotifyOnModelFileAvailable(
-    NotifyModelAvailableCallback callback) {
-  DCHECK(!IsModelAvailable());
-  if (pending_model_requests_.size() < kMaxPendingRequestsAllowed) {
+void LanguageDetectionModelService::GetLanguageDetectionModelFile(
+    GetModelCallback callback) {
+  if (language_detection_model_file_.has_value()) {
+    PostGetModelCallback(std::move(callback),
+                         language_detection_model_file_->Duplicate());
+    return;
+  } else if (pending_model_requests_.size() < kMaxPendingRequestsAllowed) {
     pending_model_requests_.emplace_back(std::move(callback));
     return;
   }
-  std::move(callback).Run(false);
+
+  PostGetModelCallback(std::move(callback), base::File());
 }
-}  // namespace translate
+}  // namespace language_detection
diff --git a/components/language_detection/core/browser/language_detection_model_service.h b/components/language_detection/core/browser/language_detection_model_service.h
new file mode 100644
index 0000000..91bdaa7
--- /dev/null
+++ b/components/language_detection/core/browser/language_detection_model_service.h
@@ -0,0 +1,97 @@
+// Copyright 2020 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_LANGUAGE_DETECTION_CORE_BROWSER_LANGUAGE_DETECTION_MODEL_SERVICE_H_
+#define COMPONENTS_LANGUAGE_DETECTION_CORE_BROWSER_LANGUAGE_DETECTION_MODEL_SERVICE_H_
+
+#include <memory>
+#include <optional>
+#include <vector>
+
+#include "base/files/file.h"
+#include "base/files/file_path.h"
+#include "base/functional/callback.h"
+#include "base/memory/raw_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/sequence_checker.h"
+#include "base/task/sequenced_task_runner.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "components/optimization_guide/core/optimization_target_model_observer.h"
+
+namespace optimization_guide {
+class OptimizationGuideModelProvider;
+}  // namespace optimization_guide
+
+namespace language_detection {
+
+// The maximum number of pending model requests allowed to be kept
+// by the LanguageDetectionModelService.
+inline constexpr int kMaxPendingRequestsAllowed = 100;
+
+// Service that manages models required to support language detection in the
+// browser. Currently, the service should only be used in the browser as it
+// relies on the Optimization Guide.
+// TODO(crbug.com/40225076): LanguageDetectionModelService should own
+// LanguageDetectionModel.
+class LanguageDetectionModelService
+    : public KeyedService,
+      public optimization_guide::OptimizationTargetModelObserver {
+ public:
+  using GetModelCallback = base::OnceCallback<void(base::File)>;
+
+  LanguageDetectionModelService(
+      optimization_guide::OptimizationGuideModelProvider* opt_guide,
+      const scoped_refptr<base::SequencedTaskRunner>& background_task_runner);
+  ~LanguageDetectionModelService() override;
+
+  // KeyedService implementation:
+  void Shutdown() override;
+
+  // optimization_guide::OptimizationTargetModelObserver implementation:
+  void OnModelUpdated(
+      optimization_guide::proto::OptimizationTarget optimization_target,
+      base::optional_ref<const optimization_guide::ModelInfo> model_info)
+      override;
+
+  // Provides the language detection model file. It will asynchronously call
+  // `callback` with the file when availability is known. The callback is always
+  // asynchronous, even if the model is already available. If the model is
+  // definiteively unavailable or if too many calls to this are
+  // pending, the provided file will be the invalid `base::File()`.
+  void GetLanguageDetectionModelFile(GetModelCallback callback);
+
+ private:
+  // Unloads the model in background task.
+  void UnloadModelFile();
+
+  // Notifies the model update to observers, and clears the observer list.
+  void NotifyModelUpdatesAndClear();
+
+  void OnModelFileLoaded(base::File model_file);
+
+  // Optimization Guide Service that provides model files for this service.
+  // Optimization Guide Service is a BrowserContextKeyedServiceFactory and
+  // should not be used after Shutdown.
+  raw_ptr<optimization_guide::OptimizationGuideModelProvider> opt_guide_;
+
+  // The file that contains the language detection model. Available when the
+  // file path has been provided by the Optimization Guide and has been
+  // successfully loaded.
+  std::optional<base::File> language_detection_model_file_;
+
+  // The set of callbacks associated with requests for the language detection
+  // model. The callback notifies requesters than the model file is now
+  // available and can be safely requested.
+  std::vector<GetModelCallback> pending_model_requests_;
+
+  scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
+
+  SEQUENCE_CHECKER(sequence_checker_);
+
+  base::WeakPtrFactory<LanguageDetectionModelService> weak_ptr_factory_{this};
+};
+
+}  //  namespace language_detection
+
+#endif  // COMPONENTS_LANGUAGE_DETECTION_CORE_BROWSER_LANGUAGE_DETECTION_MODEL_SERVICE_H_
diff --git a/components/language_detection/core/features.cc b/components/language_detection/core/features.cc
new file mode 100644
index 0000000..4943d0a
--- /dev/null
+++ b/components/language_detection/core/features.cc
@@ -0,0 +1,16 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/language_detection/core/features.h"
+
+#include "base/feature_list.h"
+
+namespace language_detection::features {
+
+// If enabled, we lazily initiate `TranslateAgent` in
+// `ChromeRenderFrameObserver` (crbug/361215212).
+BASE_FEATURE(kLazyUpdateTranslateModel,
+             "LazyUpdateTranslateModel",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+}  // namespace language_detection::features
diff --git a/components/language_detection/core/features.h b/components/language_detection/core/features.h
new file mode 100644
index 0000000..e481bb9
--- /dev/null
+++ b/components/language_detection/core/features.h
@@ -0,0 +1,18 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_LANGUAGE_DETECTION_CORE_FEATURES_H_
+#define COMPONENTS_LANGUAGE_DETECTION_CORE_FEATURES_H_
+
+#include "base/component_export.h"
+#include "base/feature_list.h"
+
+namespace language_detection::features {
+
+COMPONENT_EXPORT(LANGUAGE_DETECTION)
+BASE_DECLARE_FEATURE(kLazyUpdateTranslateModel);
+
+}  // namespace language_detection::features
+
+#endif  // COMPONENTS_LANGUAGE_DETECTION_CORE_FEATURES_H_
diff --git a/components/language_detection/ios/browser/BUILD.gn b/components/language_detection/ios/browser/BUILD.gn
new file mode 100644
index 0000000..c31cc57e
--- /dev/null
+++ b/components/language_detection/ios/browser/BUILD.gn
@@ -0,0 +1,21 @@
+# Copyright 2014 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/features.gni")
+import("//ios/web/public/js_messaging/optimize_ts.gni")
+
+source_set("browser") {
+  sources = [
+    "language_detection_model_loader_service_ios.h",
+    "language_detection_model_loader_service_ios.mm",
+  ]
+
+  deps = [
+    "//base",
+    "//components/keyed_service/core",
+    "//components/language_detection/core:language_detection",
+    "//components/language_detection/core/browser:language_detection_model_service",
+    "//components/translate/core/language_detection",
+  ]
+}
diff --git a/components/language_detection/ios/browser/DEPS b/components/language_detection/ios/browser/DEPS
new file mode 100644
index 0000000..8ffe2701
--- /dev/null
+++ b/components/language_detection/ios/browser/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+  "+components/keyed_service/core/keyed_service.h",
+  "+components/translate/core/language_detection",
+]
diff --git a/components/language_detection/ios/browser/language_detection_model_loader_service_ios.h b/components/language_detection/ios/browser/language_detection_model_loader_service_ios.h
new file mode 100644
index 0000000..acb5392
--- /dev/null
+++ b/components/language_detection/ios/browser/language_detection_model_loader_service_ios.h
@@ -0,0 +1,59 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_LANGUAGE_DETECTION_IOS_BROWSER_LANGUAGE_DETECTION_MODEL_LOADER_SERVICE_IOS_H_
+#define COMPONENTS_LANGUAGE_DETECTION_IOS_BROWSER_LANGUAGE_DETECTION_MODEL_LOADER_SERVICE_IOS_H_
+
+#include "base/files/file.h"
+#include "base/memory/raw_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/sequence_checker.h"
+#include "base/task/sequenced_task_runner.h"
+#include "components/keyed_service/core/keyed_service.h"
+
+namespace translate {
+class LanguageDetectionModel;
+}  // namespace translate
+
+namespace language_detection {
+class LanguageDetectionModelContainer;
+class LanguageDetectionModelService;
+
+// A service that contains the LanguageDetectionModel and handles its loading.
+// This is a workaround for crbug/1324530 on iOS where it is mandatory to have
+// LanguageDetectionModel scoped by BrowserState.
+// TODO(crbug.com/40225076): remove this class once
+// LanguageDetectionModelService does this.
+class LanguageDetectionModelLoaderServiceIOS : public KeyedService {
+ public:
+  LanguageDetectionModelLoaderServiceIOS(
+      language_detection::LanguageDetectionModelService*
+          language_detection_model_service,
+      const scoped_refptr<base::SequencedTaskRunner>& background_task_runner);
+  ~LanguageDetectionModelLoaderServiceIOS() override;
+
+  // Get for the actual TFLite language detection model.
+  translate::LanguageDetectionModel* GetLanguageDetectionModel();
+
+  // Utility function to check if the model is already loaded.
+  // |GetLanguageDetectionModel| can be used even if this return false.
+  bool IsModelAvailable();
+
+ private:
+  // Notifies |this| that the translate model service is available for model
+  // requests or is invalidating existing requests specified by |is_available|.
+  void OnLanguageDetectionModelFileReceived(base::File model_file);
+  // The TranslageModelService that will handle the downloading and provide
+  // the file containing the model.
+  raw_ptr<language_detection::LanguageDetectionModelService>
+      language_detection_model_service_;
+  scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
+  scoped_refptr<LanguageDetectionModelContainer> language_detection_model_;
+  base::WeakPtrFactory<LanguageDetectionModelLoaderServiceIOS>
+      weak_ptr_factory_{this};
+};
+
+}  // namespace language_detection
+
+#endif  // COMPONENTS_LANGUAGE_DETECTION_IOS_BROWSER_LANGUAGE_DETECTION_MODEL_LOADER_SERVICE_IOS_H_
diff --git a/components/language_detection/ios/browser/language_detection_model_loader_service_ios.mm b/components/language_detection/ios/browser/language_detection_model_loader_service_ios.mm
new file mode 100644
index 0000000..786aa4e5
--- /dev/null
+++ b/components/language_detection/ios/browser/language_detection_model_loader_service_ios.mm
@@ -0,0 +1,77 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/language_detection/ios/browser/language_detection_model_loader_service_ios.h"
+
+#include <memory>
+
+#import "base/task/sequenced_task_runner.h"
+#include "components/language_detection/core/browser/language_detection_model_service.h"
+#include "components/language_detection/core/language_detection_model.h"
+#include "components/language_detection/core/language_detection_provider.h"
+#include "components/translate/core/language_detection/language_detection_model.h"
+
+namespace language_detection {
+
+class LanguageDetectionModelContainer
+    // TODO(https://crbug.com/356380874): Clarify the thread safety of this
+    // class. The TFLite model should not be accessed from multiple threads,
+    // so it should not be destroyed from another thread.
+    : public base::RefCountedThreadSafe<LanguageDetectionModelContainer>,
+      public translate::LanguageDetectionModel {
+ public:
+  LanguageDetectionModelContainer()
+      : translate::LanguageDetectionModel(
+            &language_detection::GetLanguageDetectionModel()) {}
+
+ private:
+  // Allow destruction by RefCounted<>.
+  friend class RefCountedThreadSafe<LanguageDetectionModelContainer>;
+  // Destructor must be private/protected.
+  ~LanguageDetectionModelContainer() = default;
+};
+
+namespace {
+void SetLanguageDetectionModelModelFile(
+    scoped_refptr<LanguageDetectionModelContainer> language_detection_model,
+    base::File model_file) {
+  language_detection_model->UpdateWithFile(std::move(model_file));
+}
+}  // namespace
+
+LanguageDetectionModelLoaderServiceIOS::LanguageDetectionModelLoaderServiceIOS(
+    language_detection::LanguageDetectionModelService*
+        language_detection_model_service,
+    const scoped_refptr<base::SequencedTaskRunner>& background_task_runner)
+    : language_detection_model_service_(language_detection_model_service),
+      background_task_runner_(background_task_runner),
+      language_detection_model_(
+          base::MakeRefCounted<LanguageDetectionModelContainer>()) {
+  if (language_detection_model_service_) {
+    language_detection_model_service_->GetLanguageDetectionModelFile(
+        base::BindOnce(&LanguageDetectionModelLoaderServiceIOS::
+                           OnLanguageDetectionModelFileReceived,
+                       weak_ptr_factory_.GetWeakPtr()));
+  }
+}
+
+LanguageDetectionModelLoaderServiceIOS::
+    ~LanguageDetectionModelLoaderServiceIOS() {}
+
+translate::LanguageDetectionModel*
+LanguageDetectionModelLoaderServiceIOS::GetLanguageDetectionModel() {
+  return language_detection_model_.get();
+}
+
+bool LanguageDetectionModelLoaderServiceIOS::IsModelAvailable() {
+  return language_detection_model_->IsAvailable();
+}
+
+void LanguageDetectionModelLoaderServiceIOS::
+    OnLanguageDetectionModelFileReceived(base::File model_file) {
+  SetLanguageDetectionModelModelFile(language_detection_model_,
+                                     std::move(model_file));
+}
+
+}  // namespace language_detection
diff --git a/components/manta/BUILD.gn b/components/manta/BUILD.gn
index 83134d7..1d09cc5f 100644
--- a/components/manta/BUILD.gn
+++ b/components/manta/BUILD.gn
@@ -5,12 +5,9 @@
 import("//build/config/chromeos/ui_mode.gni")
 import("//build/config/features.gni")
 
-# TODO(b/358224257): Re-enable when shared_library is properly used.
-# allow_internal = is_chrome_branded
-allow_internal = false
-
 component("manta") {
   sources = [
+    "anchovy/anchovy_proto_helper.cc",
     "anchovy/anchovy_proto_helper.h",
     "anchovy/anchovy_provider.cc",
     "anchovy/anchovy_provider.h",
@@ -28,14 +25,6 @@
     "provider_params.h",
   ]
 
-  if (allow_internal) {
-    sources += [
-      "//components/accessibility/internal/anchovy/anchovy_proto_helper.cc",
-    ]
-  } else {
-    sources += [ "anchovy/anchovy_proto_helper.cc" ]
-  }
-
   defines = [ "IS_MANTA_IMPL" ]
 
   deps = [
diff --git a/components/manta/anchovy/anchovy_proto_helper.cc b/components/manta/anchovy/anchovy_proto_helper.cc
index 193235d3..affd6368 100644
--- a/components/manta/anchovy/anchovy_proto_helper.cc
+++ b/components/manta/anchovy/anchovy_proto_helper.cc
@@ -7,15 +7,52 @@
 #include "base/functional/callback.h"
 #include "base/logging.h"
 #include "components/manta/manta_service_callbacks.h"
+#include "components/manta/proto/anchovy.pb.h"
 
 namespace manta::anchovy {
 
+namespace {
+std::string AnchovyDescriptionTypeToString(
+    proto::AnchovyDescription::Type type) {
+  switch (type) {
+    case proto::AnchovyDescription_Type_ONE:
+    case proto::AnchovyDescription_Type_TWO:
+      return "CAPTION";
+    case proto::AnchovyDescription_Type_THREE:
+      return "LABEL";
+    case proto::AnchovyDescription_Type_FOUR:
+      return "OCR";
+    case proto::AnchovyDescription_Type_UNKNOWN:
+    case proto::AnchovyDescription_Type_FIVE:
+    case proto::
+        AnchovyDescription_Type_AnchovyDescription_Type_INT_MIN_SENTINEL_DO_NOT_USE_:
+    case proto::
+        AnchovyDescription_Type_AnchovyDescription_Type_INT_MAX_SENTINEL_DO_NOT_USE_:
+      return "";
+  }
+}
+}  // namespace
+
+constexpr char kAnchovyDescriptionsContextTypeUrl[] =
+    "type.googleapis.com/image_repository.api.AnchovyDescriptionContext";
+
 proto::Request AnchovyProtoHelper::ComposeRequest(
     const ImageDescriptionRequest& request) {
   proto::Request request_proto;
   request_proto.set_feature_name(
       proto::FeatureName::ACCESSIBILITY_IMAGE_DESCRIPTION);
 
+  proto::AnchovyContext context;
+  context.set_lang_id(request.lang_tag);
+  context.mutable_optional_inputs()->set_input1(true);
+
+  // Add model specific options to the request.
+  request_proto.mutable_request_config()
+      ->mutable_specific_options()
+      ->set_type_url(kAnchovyDescriptionsContextTypeUrl);
+  request_proto.mutable_request_config()->mutable_specific_options()->set_value(
+      context.SerializeAsString());
+
   auto* input_data = request_proto.add_input_data();
   input_data->mutable_image()->set_serialized_bytes(
       std::string(request.image_bytes->begin(), request.image_bytes->end()));
@@ -27,10 +64,38 @@
     MantaGenericCallback callback,
     std::unique_ptr<proto::Response> manta_response,
     MantaStatus manta_status) {
-  LOG(ERROR) << "Using Public Handler.";
-  std::move(callback).Run(base::Value::Dict(),
-                          {MantaStatusCode::kGenericError, std::string()});
-  return;
+  if (manta_status.status_code != MantaStatusCode::kOk) {
+    CHECK(manta_response == nullptr);
+    std::move(callback).Run(base::Value::Dict(), std::move(manta_status));
+    return;
+  }
+
+  CHECK(manta_response);
+
+  // An empty response is still an acceptable response.
+  if (manta_response->output_data_size() < 1 ||
+      !manta_response->output_data(0).has_custom()) {
+    std::move(callback).Run(base::Value::Dict(),
+                            {MantaStatusCode::kOk, std::string()});
+    return;
+  }
+
+  base::Value::List results;
+  for (const auto& data : manta_response->output_data()) {
+    if (data.has_custom()) {
+      proto::AnchovyDescription description;
+      description.ParseFromString(data.custom().value());
+      results.Append(
+          base::Value::Dict()
+              .Set("text", description.text())
+              .Set("type", AnchovyDescriptionTypeToString(description.type()))
+              .Set("score", data.score()));
+    }
+  }
+
+  std::move(callback).Run(
+      base::Value::Dict().Set("results", std::move(results)),
+      std::move(manta_status));
 }
 
 }  // namespace manta::anchovy
diff --git a/components/manta/proto/BUILD.gn b/components/manta/proto/BUILD.gn
index e12f09c8..673f8b9 100644
--- a/components/manta/proto/BUILD.gn
+++ b/components/manta/proto/BUILD.gn
@@ -11,6 +11,7 @@
 proto_library("proto") {
   proto_in_dir = "//"
   sources = [
+    "anchovy.proto",
     "common.proto",
     "manta.proto",
     "rpc_status.proto",
diff --git a/components/manta/proto/anchovy.proto b/components/manta/proto/anchovy.proto
new file mode 100644
index 0000000..2958dce
--- /dev/null
+++ b/components/manta/proto/anchovy.proto
@@ -0,0 +1,40 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+syntax = "proto3";
+option optimize_for = LITE_RUNTIME;
+
+package manta.proto;
+
+message AnchovyDescription {
+  reserved 3, 5;
+
+  enum Type {
+    UNKNOWN = 0;
+    ONE = 1;
+    TWO = 2;
+    THREE = 3;
+    FOUR = 4;
+    FIVE = 5;
+  }
+  optional Type type = 1;
+
+  optional string text = 2;
+  optional string lang_id = 4;
+}
+
+message AnchovyContext {
+  optional string version = 1;
+  optional string lang_id = 2;
+  message OptionalInputs {
+    optional bool input1 = 1;
+    optional bool unused_input2 = 2;
+  }
+  optional OptionalInputs optional_inputs = 3;
+
+  message AnchovyOptions {
+    optional bool unused = 1;
+  }
+  optional AnchovyOptions options = 4;
+}
diff --git a/components/metrics/motherboard.cc b/components/metrics/motherboard.cc
index 790579c..acbf7bd 100644
--- a/components/metrics/motherboard.cc
+++ b/components/metrics/motherboard.cc
@@ -171,7 +171,7 @@
 
 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN)
 Motherboard::Motherboard() {
-  const auto details = ReadMotherboardDetails();
+  auto details = ReadMotherboardDetails();
   manufacturer_ = std::move(details.manufacturer),
   model_ = std::move(details.model),
   bios_manufacturer_ = std::move(details.bios_manufacturer),
diff --git a/components/offline_pages/core/background/request_queue_store.cc b/components/offline_pages/core/background/request_queue_store.cc
index f9b4a9f..59504f8 100644
--- a/components/offline_pages/core/background/request_queue_store.cc
+++ b/components/offline_pages/core/background/request_queue_store.cc
@@ -223,10 +223,9 @@
   const SavePageRequest::RequestState state =
       ToRequestState(statement.ColumnInt64(6));
   const GURL url(statement.ColumnString(7));
-  const ClientId client_id(statement.ColumnString(8),
-                           statement.ColumnString(9));
-  const GURL original_url(statement.ColumnString(10));
-  const std::string request_origin(statement.ColumnString(11));
+  ClientId client_id(statement.ColumnString(8), statement.ColumnString(9));
+  GURL original_url(statement.ColumnString(10));
+  std::string request_origin(statement.ColumnString(11));
 
   DVLOG(2) << "making save page request - id " << id << " url " << url
            << " client_id " << client_id.name_space << "-" << client_id.id
diff --git a/components/optimization_guide/internal b/components/optimization_guide/internal
index b8ec0d2..e3a75e7 160000
--- a/components/optimization_guide/internal
+++ b/components/optimization_guide/internal
@@ -1 +1 @@
-Subproject commit b8ec0d2bf23c43dbf82b8d579c3cbc97a5771df0
+Subproject commit e3a75e7f401aaa2cf290716560fd066072fb2772
diff --git a/components/page_load_metrics/browser/observers/prerender_page_load_metrics_observer.cc b/components/page_load_metrics/browser/observers/prerender_page_load_metrics_observer.cc
index c2915d6..c57a3a2 100644
--- a/components/page_load_metrics/browser/observers/prerender_page_load_metrics_observer.cc
+++ b/components/page_load_metrics/browser/observers/prerender_page_load_metrics_observer.cc
@@ -56,15 +56,6 @@
 const char kPageLoadPrerenderActivatedPageLoaderStatus[] =
     "PageLoad.Internal.Prerender2.ActivatedPageLoaderStatus";
 
-// This metric is used for debugging https://crbug.com/1379491.
-// Intentionally this metric doesn't record observer events per trigger type
-// (e.g., SpeculationRules) because some functions can be called before
-// `PrerenderPageLoadMetricsObserver::trigger_type_` is set (e.g., when
-// `OnComplete()` called from the destructor of PageLoadTracker before
-// prerender activation).
-const char kPageLoadPrerenderObserverEvent[] =
-    "PageLoad.Internal.Prerender2.ObserverEvent";
-
 }  // namespace internal
 
 PrerenderPageLoadMetricsObserver::PrerenderPageLoadMetricsObserver() = default;
@@ -92,10 +83,6 @@
 PrerenderPageLoadMetricsObserver::OnPrerenderStart(
     content::NavigationHandle* navigation_handle,
     const GURL& currently_committed_url) {
-  base::UmaHistogramEnumeration(
-      internal::kPageLoadPrerenderObserverEvent,
-      internal::PageLoadPrerenderObserverEvent::kOnPrerenderStart);
-
   // TODO(crbug.com/40228553): Prerendering pages embedding FencedFrames
   // are not supported.
   DCHECK(navigation_handle->GetNavigatingFrameType() !=
@@ -105,10 +92,6 @@
 
 void PrerenderPageLoadMetricsObserver::DidActivatePrerenderedPage(
     content::NavigationHandle* navigation_handle) {
-  base::UmaHistogramEnumeration(
-      internal::kPageLoadPrerenderObserverEvent,
-      internal::PageLoadPrerenderObserverEvent::kDidActivatePrerenderedPage);
-
   // Copy the trigger type and histogram suffix for an embedder. These data will
   // be lost after NavigationRequest is destroyed.
   DCHECK(!trigger_type_.has_value());
@@ -158,10 +141,6 @@
 
 void PrerenderPageLoadMetricsObserver::OnFirstPaintInPage(
     const page_load_metrics::mojom::PageLoadTiming& timing) {
-  base::UmaHistogramEnumeration(
-      internal::kPageLoadPrerenderObserverEvent,
-      internal::PageLoadPrerenderObserverEvent::kOnFirstPaintInPage);
-
   if (!WasActivatedInForegroundOptionalEventInForeground(
           timing.paint_timing->first_paint, GetDelegate())) {
     return;
@@ -176,10 +155,6 @@
 
 void PrerenderPageLoadMetricsObserver::OnFirstContentfulPaintInPage(
     const page_load_metrics::mojom::PageLoadTiming& timing) {
-  base::UmaHistogramEnumeration(
-      internal::kPageLoadPrerenderObserverEvent,
-      internal::PageLoadPrerenderObserverEvent::kOnFirstContentfulPaintInPage);
-
   if (!WasActivatedInForegroundOptionalEventInForeground(
           timing.paint_timing->first_contentful_paint, GetDelegate())) {
     return;
@@ -199,10 +174,6 @@
 
 void PrerenderPageLoadMetricsObserver::OnFirstInputInPage(
     const page_load_metrics::mojom::PageLoadTiming& timing) {
-  base::UmaHistogramEnumeration(
-      internal::kPageLoadPrerenderObserverEvent,
-      internal::PageLoadPrerenderObserverEvent::kOnFirstInputInPage);
-
   if (!WasActivatedInForegroundOptionalEventInForeground(
           timing.interactive_timing->first_input_timestamp, GetDelegate())) {
     return;
@@ -220,9 +191,6 @@
 
 void PrerenderPageLoadMetricsObserver::OnComplete(
     const page_load_metrics::mojom::PageLoadTiming& timing) {
-  base::UmaHistogramEnumeration(
-      internal::kPageLoadPrerenderObserverEvent,
-      internal::PageLoadPrerenderObserverEvent::kOnComplete);
   RecordSessionEndHistograms(timing);
 }
 
@@ -257,18 +225,12 @@
 page_load_metrics::PageLoadMetricsObserver::ObservePolicy
 PrerenderPageLoadMetricsObserver::FlushMetricsOnAppEnterBackground(
     const page_load_metrics::mojom::PageLoadTiming& timing) {
-  base::UmaHistogramEnumeration(internal::kPageLoadPrerenderObserverEvent,
-                                internal::PageLoadPrerenderObserverEvent::
-                                    kFlushMetricsOnAppEnterBackground);
   RecordSessionEndHistograms(timing);
   return STOP_OBSERVING;
 }
 
 void PrerenderPageLoadMetricsObserver::RecordSessionEndHistograms(
     const page_load_metrics::mojom::PageLoadTiming& main_frame_timing) {
-  base::UmaHistogramEnumeration(
-      internal::kPageLoadPrerenderObserverEvent,
-      internal::PageLoadPrerenderObserverEvent::kRecordSessionEndHistograms);
   MaybeRecordMainResourceLoadStatus();
 
   if (!GetDelegate().WasPrerenderedThenActivatedInForeground() ||
@@ -311,10 +273,6 @@
 
 void PrerenderPageLoadMetricsObserver::RecordLayoutShiftScoreMetrics(
     const page_load_metrics::mojom::PageLoadTiming& main_frame_timing) {
-  base::UmaHistogramEnumeration(
-      internal::kPageLoadPrerenderObserverEvent,
-      internal::PageLoadPrerenderObserverEvent::kRecordLayoutShiftScoreMetrics);
-
   DCHECK(GetDelegate().WasPrerenderedThenActivatedInForeground());
   DCHECK(main_frame_timing.activation_start);
 
@@ -349,10 +307,6 @@
 }
 
 void PrerenderPageLoadMetricsObserver::RecordNormalizedResponsivenessMetrics() {
-  base::UmaHistogramEnumeration(internal::kPageLoadPrerenderObserverEvent,
-                                internal::PageLoadPrerenderObserverEvent::
-                                    kRecordNormalizedResponsivenessMetrics);
-
   DCHECK(GetDelegate().WasPrerenderedThenActivatedInForeground());
 
   const page_load_metrics::ResponsivenessMetricsNormalization&
diff --git a/components/page_load_metrics/browser/observers/prerender_page_load_metrics_observer.h b/components/page_load_metrics/browser/observers/prerender_page_load_metrics_observer.h
index cb5bb73..b2ad9f4 100644
--- a/components/page_load_metrics/browser/observers/prerender_page_load_metrics_observer.h
+++ b/components/page_load_metrics/browser/observers/prerender_page_load_metrics_observer.h
@@ -33,24 +33,6 @@
 extern const char
     kHistogramPrerenderWorstUserInteractionLatencyMaxEventDuration[];
 
-extern const char kPageLoadPrerenderObserverEvent[];
-
-// These values are persisted to logs. Entries should not be renumbered and
-// numeric values should never be reused.
-enum class PageLoadPrerenderObserverEvent {
-  kOnPrerenderStart = 0,
-  kDidActivatePrerenderedPage = 1,
-  kOnFirstPaintInPage = 2,
-  kOnFirstContentfulPaintInPage = 3,
-  kOnFirstInputInPage = 4,
-  kOnComplete = 5,
-  kFlushMetricsOnAppEnterBackground = 6,
-  kRecordSessionEndHistograms = 7,
-  kRecordLayoutShiftScoreMetrics = 8,
-  kRecordNormalizedResponsivenessMetrics = 9,
-  kMaxValue = kRecordNormalizedResponsivenessMetrics,
-};
-
 }  // namespace internal
 
 namespace page_load_metrics {
diff --git a/components/page_load_metrics/browser/observers/use_counter_page_load_metrics_observer.cc b/components/page_load_metrics/browser/observers/use_counter_page_load_metrics_observer.cc
index 80f39ca..7900c5ee 100644
--- a/components/page_load_metrics/browser/observers/use_counter_page_load_metrics_observer.cc
+++ b/components/page_load_metrics/browser/observers/use_counter_page_load_metrics_observer.cc
@@ -437,6 +437,8 @@
           {WebFeature::kModuleDedicatedWorker, WebDXFeature::kJsModulesWorkers},
           {WebFeature::kModuleSharedWorker,
            WebDXFeature::kJsModulesSharedWorkers},
+          {WebFeature::kCssDisplayPropertyMultipleValues,
+           WebDXFeature::kTwoValueDisplay},
       }};
 
   return *kMap;
diff --git a/components/page_load_metrics/browser/page_load_tracker.cc b/components/page_load_metrics/browser/page_load_tracker.cc
index 299ecd4..753bccc 100644
--- a/components/page_load_metrics/browser/page_load_tracker.cc
+++ b/components/page_load_metrics/browser/page_load_tracker.cc
@@ -44,8 +44,6 @@
 
 const char kErrorEvents[] = "PageLoad.Internal.ErrorCode";
 const char kPageLoadPrerender2Event[] = "PageLoad.Internal.Prerender2.Event";
-const char kPageLoadPrerender2VisibilityAtActivation[] =
-    "PageLoad.Internal.Prerender2.VisibilityAtActivation";
 const char kPageLoadTrackerPageType[] = "PageLoad.Internal.PageType";
 }  // namespace internal
 
@@ -563,22 +561,11 @@
 
   switch (GetWebContents()->GetVisibility()) {
     case content::Visibility::HIDDEN:
-      visibility_at_activation_ = PageVisibility::kBackground;
-      base::UmaHistogramEnumeration(
-          internal::kPageLoadPrerender2VisibilityAtActivation,
-          internal::VisibilityAtActivation::kHidden);
-      break;
     case content::Visibility::OCCLUDED:
       visibility_at_activation_ = PageVisibility::kBackground;
-      base::UmaHistogramEnumeration(
-          internal::kPageLoadPrerender2VisibilityAtActivation,
-          internal::VisibilityAtActivation::kOccluded);
       break;
     case content::Visibility::VISIBLE:
       visibility_at_activation_ = PageVisibility::kForeground;
-      base::UmaHistogramEnumeration(
-          internal::kPageLoadPrerender2VisibilityAtActivation,
-          internal::VisibilityAtActivation::kVisible);
       break;
   }
 
diff --git a/components/page_load_metrics/browser/page_load_tracker.h b/components/page_load_metrics/browser/page_load_tracker.h
index c76b6ea..86f36cd 100644
--- a/components/page_load_metrics/browser/page_load_tracker.h
+++ b/components/page_load_metrics/browser/page_load_tracker.h
@@ -68,18 +68,8 @@
 
 extern const char kErrorEvents[];
 extern const char kPageLoadPrerender2Event[];
-extern const char kPageLoadPrerender2VisibilityAtActivation[];
 extern const char kPageLoadTrackerPageType[];
 
-// These values are persisted to logs. Entries should not be renumbered and
-// numeric values should never be reused.
-enum class VisibilityAtActivation {
-  kHidden = 0,
-  kOccluded = 1,
-  kVisible = 2,
-  kMaxValue = kVisible
-};
-
 }  // namespace internal
 
 // These errors are internal to the page_load_metrics subsystem and do not
diff --git a/components/password_manager/core/browser/password_manager_settings_service_impl.cc b/components/password_manager/core/browser/password_manager_settings_service_impl.cc
index 3a26627..0249af8e 100644
--- a/components/password_manager/core/browser/password_manager_settings_service_impl.cc
+++ b/components/password_manager/core/browser/password_manager_settings_service_impl.cc
@@ -26,7 +26,8 @@
     // GMS Core. PasswordManagerSettingsServiceImpl is instantiated only when
     // GMS Core is not in use, so always return false in this case.
     case PasswordManagerSetting::kBiometricReauthBeforePwdFilling:
-#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_ANDROID)
+#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_ANDROID) || \
+    BUILDFLAG(IS_CHROMEOS)
       return pref_service_->GetBoolean(
           password_manager::prefs::kBiometricAuthenticationBeforeFilling);
 #else
diff --git a/components/password_manager/core/browser/password_manager_util.cc b/components/password_manager/core/browser/password_manager_util.cc
index 398c01a..4e219a5e 100644
--- a/components/password_manager/core/browser/password_manager_util.cc
+++ b/components/password_manager/core/browser/password_manager_util.cc
@@ -353,13 +353,15 @@
   return result;
 }
 
-#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
+#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS)
 bool ShouldBiometricAuthenticationForFillingToggleBeVisible(
     const PrefService* local_state) {
   return local_state->GetBoolean(
       password_manager::prefs::kHadBiometricsAvailable);
 }
+#endif  // BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS)
 
+#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
 bool ShouldShowBiometricAuthenticationBeforeFillingPromo(
     password_manager::PasswordManagerClient* client) {
   std::unique_ptr<device_reauth::DeviceAuthenticator> device_authenticator =
diff --git a/components/password_manager/core/browser/password_manager_util.h b/components/password_manager/core/browser/password_manager_util.h
index c6ebc930..7da6e467 100644
--- a/components/password_manager/core/browser/password_manager_util.h
+++ b/components/password_manager/core/browser/password_manager_util.h
@@ -133,13 +133,11 @@
 password_manager::PasswordForm MakeNormalizedBlocklistedForm(
     password_manager::PasswordFormDigest digest);
 
-#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
-bool IsBiometricAuthenticationForFillingEnabled(
-    password_manager::PasswordManagerClient* client);
-
+#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS)
 bool ShouldBiometricAuthenticationForFillingToggleBeVisible(
     const PrefService* local_state);
-
+#endif
+#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
 bool ShouldShowBiometricAuthenticationBeforeFillingPromo(
     password_manager::PasswordManagerClient* client);
 #endif
diff --git a/components/password_manager/core/browser/password_manager_util_unittest.cc b/components/password_manager/core/browser/password_manager_util_unittest.cc
index 8c362b47..51bbee4 100644
--- a/components/password_manager/core/browser/password_manager_util_unittest.cc
+++ b/components/password_manager/core/browser/password_manager_util_unittest.cc
@@ -154,11 +154,13 @@
     pref_service_.registry()->RegisterIntegerPref(
         password_manager::prefs::kPasswordsUseUPMLocalAndSeparateStores, 0);
 #endif
+#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS)
+    pref_service_.registry()->RegisterBooleanPref(
+        password_manager::prefs::kHadBiometricsAvailable, false);
+#endif
 #if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
     pref_service_.registry()->RegisterBooleanPref(
         password_manager::prefs::kBiometricAuthenticationBeforeFilling, false);
-    pref_service_.registry()->RegisterBooleanPref(
-        password_manager::prefs::kHadBiometricsAvailable, false);
     ON_CALL(mock_client_, GetLocalStatePrefs())
         .WillByDefault(Return(&pref_service_));
     ON_CALL(*authenticator_.get(), CanAuthenticateWithBiometrics)
diff --git a/components/plus_addresses/plus_address_service.cc b/components/plus_addresses/plus_address_service.cc
index 2660aeb..f027221 100644
--- a/components/plus_addresses/plus_address_service.cc
+++ b/components/plus_addresses/plus_address_service.cc
@@ -332,9 +332,9 @@
   const bool is_creation_enabled =
       IsPlusAddressCreationEnabled(origin, is_off_the_record);
   std::vector<Suggestion> suggestions =
-      PlusAddressSuggestionGenerator(&setting_service_.get(),
-                                     plus_address_allocator_.get(),
-                                     std::move(origin))
+      PlusAddressSuggestionGenerator(
+          &setting_service_.get(), plus_address_allocator_.get(),
+          std::move(origin), GetPrimaryEmail().value_or(""))
           .GetSuggestions(is_creation_enabled, focused_form_classification,
                           focused_field, trigger_source,
                           std::move(affiliated_profiles));
@@ -589,9 +589,9 @@
         update_suggestions_callback) {
   std::vector<Suggestion> updated_suggestions(current_suggestions.begin(),
                                               current_suggestions.end());
-  PlusAddressSuggestionGenerator(&setting_service_.get(),
-                                 plus_address_allocator_.get(),
-                                 last_committed_primary_main_frame_origin)
+  PlusAddressSuggestionGenerator(
+      &setting_service_.get(), plus_address_allocator_.get(),
+      last_committed_primary_main_frame_origin, GetPrimaryEmail().value_or(""))
       .RefreshPlusAddressForSuggestion(
           updated_suggestions[current_suggestion_index]);
   std::move(update_suggestions_callback)
diff --git a/components/plus_addresses/plus_address_suggestion_generator.cc b/components/plus_addresses/plus_address_suggestion_generator.cc
index eb921708..6daf27a 100644
--- a/components/plus_addresses/plus_address_suggestion_generator.cc
+++ b/components/plus_addresses/plus_address_suggestion_generator.cc
@@ -75,8 +75,11 @@
   return suggestion;
 }
 
+// Returns the labels for a create new plus address suggestion.
+// `forwarding_address` is the email that traffic is forwarded to.
 std::vector<std::vector<Suggestion::Text>> CreateLabelsForCreateSuggestion(
-    bool has_accepted_notice) {
+    bool has_accepted_notice,
+    std::string_view forwarding_address) {
   // On Android, there are no labels since the Keyboard Accessory only allows
   // for single line chips.
   if constexpr (BUILDFLAG(IS_ANDROID)) {
@@ -86,8 +89,21 @@
       base::FeatureList::IsEnabled(features::kPlusAddressSuggestionRedesign)) {
     return {};
   }
-  return {{Suggestion::Text(l10n_util::GetStringUTF16(
-      IDS_PLUS_ADDRESS_CREATE_SUGGESTION_SECONDARY_TEXT))}};
+
+  // On iOS the `forwarding_address` is not shown due to size constraints.
+  if constexpr (BUILDFLAG(IS_IOS)) {
+    return {{Suggestion::Text(l10n_util::GetStringUTF16(
+        IDS_PLUS_ADDRESS_CREATE_SUGGESTION_SECONDARY_TEXT))}};
+  }
+
+  std::u16string label_text =
+      base::FeatureList::IsEnabled(features::kPlusAddressSuggestionRedesign)
+          ? l10n_util::GetStringFUTF16(
+                IDS_PLUS_ADDRESS_CREATE_SUGGESTION_SECONDARY_TEXT_WITH_FORWARDING_INFO,
+                base::UTF8ToUTF16(forwarding_address))
+          : l10n_util::GetStringUTF16(
+                IDS_PLUS_ADDRESS_CREATE_SUGGESTION_SECONDARY_TEXT);
+  return {{Suggestion::Text(std::move(label_text))}};
 }
 
 }  // namespace
@@ -95,10 +111,12 @@
 PlusAddressSuggestionGenerator::PlusAddressSuggestionGenerator(
     const PlusAddressSettingService* setting_service,
     PlusAddressAllocator* allocator,
-    url::Origin origin)
+    url::Origin origin,
+    std::string primary_email)
     : setting_service_(CHECK_DEREF(setting_service)),
       allocator_(CHECK_DEREF(allocator)),
-      origin_(std::move(origin)) {}
+      origin_(std::move(origin)),
+      primary_email_(std::move(primary_email)) {}
 
 PlusAddressSuggestionGenerator::~PlusAddressSuggestionGenerator() = default;
 
@@ -195,7 +213,8 @@
   suggestion.labels = CreateLabelsForCreateSuggestion(
       !base::FeatureList::IsEnabled(
           features::kPlusAddressUserOnboardingEnabled) ||
-      setting_service_->GetHasAcceptedNotice());
+          setting_service_->GetHasAcceptedNotice(),
+      primary_email_);
   suggestion.icon = Suggestion::Icon::kPlusAddress;
   suggestion.feature_for_new_badge = &features::kPlusAddressesEnabled;
   suggestion.feature_for_iph =
@@ -238,8 +257,11 @@
     suggestion.is_loading = Suggestion::IsLoading(true);
   }
   suggestion.icon = Suggestion::Icon::kPlusAddress;
-  suggestion.labels = {{Suggestion::Text(l10n_util::GetStringUTF16(
-      IDS_PLUS_ADDRESS_CREATE_SUGGESTION_SECONDARY_TEXT))}};
+  suggestion.labels = CreateLabelsForCreateSuggestion(
+      !base::FeatureList::IsEnabled(
+          features::kPlusAddressUserOnboardingEnabled) ||
+          setting_service_->GetHasAcceptedNotice(),
+      primary_email_);
   // TODO(crbug.com/362445807): Consider adding IPH and new badge for inline
   // suggestions.
   return suggestion;
diff --git a/components/plus_addresses/plus_address_suggestion_generator.h b/components/plus_addresses/plus_address_suggestion_generator.h
index 8a81597..6f73457 100644
--- a/components/plus_addresses/plus_address_suggestion_generator.h
+++ b/components/plus_addresses/plus_address_suggestion_generator.h
@@ -33,7 +33,8 @@
   PlusAddressSuggestionGenerator(
       const PlusAddressSettingService* setting_service,
       PlusAddressAllocator* allocator,
-      url::Origin origin);
+      url::Origin origin,
+      std::string primary_email);
   ~PlusAddressSuggestionGenerator();
 
   // Returns the suggestions to be offered on the `focused_field` with Password
@@ -84,6 +85,8 @@
   // TODO(crbug.com/362445807): Eliminate this parameter once the allocator
   // no longer needs it.
   const url::Origin origin_;
+  // The primary email address of the user.
+  const std::string primary_email_;
 };
 
 }  // namespace plus_addresses
diff --git a/components/plus_addresses/plus_address_suggestion_generator_unittest.cc b/components/plus_addresses/plus_address_suggestion_generator_unittest.cc
index 25ccde841..5358434 100644
--- a/components/plus_addresses/plus_address_suggestion_generator_unittest.cc
+++ b/components/plus_addresses/plus_address_suggestion_generator_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "components/plus_addresses/plus_address_suggestion_generator.h"
 
+#include <string>
 #include <utility>
 
 #include "base/strings/utf_string_conversions.h"
@@ -94,6 +95,8 @@
  public:
   PlusAddressSuggestionGeneratorTest() = default;
 
+  const std::string kPrimaryEmail = "foo@gmail.com";
+
  protected:
   FakePlusAddressAllocator& allocator() { return allocator_; }
   FakePlusAddressSettingService& setting_service() { return setting_service_; }
@@ -117,7 +120,7 @@
   allocator().set_is_next_allocation_synchronous(false);
   PlusAddressSuggestionGenerator generator(
       &setting_service(), &allocator(),
-      url::Origin::Create(GURL("https://foo.bar")));
+      url::Origin::Create(GURL("https://foo.bar")), kPrimaryEmail);
   EXPECT_THAT(generator.GetSuggestions(
                   /*is_creation_enabled=*/true, PasswordFormClassification(),
                   FormFieldData(),
@@ -137,7 +140,7 @@
   allocator().set_is_next_allocation_synchronous(true);
   PlusAddressSuggestionGenerator generator(
       &setting_service(), &allocator(),
-      url::Origin::Create(GURL("https://foo.bar")));
+      url::Origin::Create(GURL("https://foo.bar")), kPrimaryEmail);
   EXPECT_THAT(generator.GetSuggestions(
                   /*is_creation_enabled=*/true, PasswordFormClassification(),
                   FormFieldData(),
@@ -187,7 +190,7 @@
 
   PlusAddressSuggestionGenerator generator(
       &setting_service(), &allocator(),
-      url::Origin::Create(GURL("https://foo.bar")));
+      url::Origin::Create(GURL("https://foo.bar")), kPrimaryEmail);
   EXPECT_THAT(
       generator.GetSuggestions(
           /*is_creation_enabled=*/true, PasswordFormClassification(),
@@ -198,5 +201,44 @@
                         Field(&Suggestion::labels, IsEmpty()))));
 }
 
+// Tests properties of the label for suggestions for 2nd (and subsequent)
+// create.
+// - On Android, there should be no label.
+// - On iOS, the label should not contain the primary email.
+// - On Desktop, the label should contain the primary email.
+TEST_F(PlusAddressSuggestionGeneratorTest, ProfileInLabel) {
+  base::test::ScopedFeatureList feature_list{
+      features::kPlusAddressSuggestionRedesign};
+  setting_service().set_has_accepted_notice(true);
+
+  PlusAddressSuggestionGenerator generator(
+      &setting_service(), &allocator(),
+      url::Origin::Create(GURL("https://foo.bar")), kPrimaryEmail);
+
+  std::vector<Suggestion> suggestions = generator.GetSuggestions(
+      /*is_creation_enabled=*/true, PasswordFormClassification(),
+      FormFieldData(),
+      AutofillSuggestionTriggerSource::kFormControlElementClicked,
+      /*affiliated_profiles=*/{});
+  ASSERT_EQ(suggestions.size(), 1u);
+
+  if constexpr (BUILDFLAG(IS_ANDROID)) {
+    EXPECT_THAT(suggestions[0].labels, IsEmpty());
+    return;
+  }
+
+  ASSERT_EQ(suggestions[0].labels.size(), 1u);
+  ASSERT_EQ(suggestions[0].labels[0].size(), 1u);
+
+  const bool is_email_in_label =
+      suggestions[0].labels[0][0].value.find(
+          base::UTF8ToUTF16(kPrimaryEmail)) != std::u16string::npos;
+  if constexpr (BUILDFLAG(IS_IOS)) {
+    EXPECT_FALSE(is_email_in_label);
+  } else {
+    EXPECT_TRUE(is_email_in_label);
+  }
+}
+
 }  // namespace
 }  // namespace plus_addresses
diff --git a/components/plus_addresses_strings.grdp b/components/plus_addresses_strings.grdp
index e62c5f6..662ec96 100644
--- a/components/plus_addresses_strings.grdp
+++ b/components/plus_addresses_strings.grdp
@@ -172,6 +172,9 @@
     <message name="IDS_PLUS_ADDRESS_CREATE_SUGGESTION_SECONDARY_TEXT" desc="The secondary text in the Autofill suggestion for create a new plus address." translateable="false">
       Lorem Ipsum
     </message>
+    <message name="IDS_PLUS_ADDRESS_CREATE_SUGGESTION_SECONDARY_TEXT_WITH_FORWARDING_INFO" desc="The secondary text in the Autofill suggestion for creating a new plus address." translateable="false">
+      Lorem Ipsum <ph name="GAIA_EMAIL"><ex>foo@gmail.com</ex>$1</ph>
+    </message>
     <message name="IDS_PLUS_ADDRESS_CREATE_INLINE_REFRESH_A11Y_NAME" desc="The accessible name on the button that allows refreshing plus addresses inside an Autofill popup suggestion." translateable="false">
       Refresh plus address
     </message>
diff --git a/components/reporting/client/report_queue_impl.cc b/components/reporting/client/report_queue_impl.cc
index e2646a7..25e3d77d 100644
--- a/components/reporting/client/report_queue_impl.cc
+++ b/components/reporting/client/report_queue_impl.cc
@@ -74,7 +74,7 @@
                                std::optional<SourceInfo> source_info,
                                ReportQueue::RecordProducer record_producer) {
   // Generate record data.
-  const auto record_result = std::move(record_producer).Run();
+  auto record_result = std::move(record_producer).Run();
   if (!record_result.has_value()) {
     return base::unexpected(record_result.error());
   }
diff --git a/components/segmentation_platform/embedder/input_delegate/tab_rank_dispatcher.cc b/components/segmentation_platform/embedder/input_delegate/tab_rank_dispatcher.cc
index f5e833de..c696ab8 100644
--- a/components/segmentation_platform/embedder/input_delegate/tab_rank_dispatcher.cc
+++ b/components/segmentation_platform/embedder/input_delegate/tab_rank_dispatcher.cc
@@ -119,7 +119,7 @@
     return;
   }
 
-  const RankedTab tab = std::move(candidate_tabs.front());
+  RankedTab tab = std::move(candidate_tabs.front());
   // Fetch tab every time from the `tab_fetcher_` for accessing the tab data
   // since the tab could have been destroyed.
   TabFetcher::Tab fetched_tab = tab_fetcher_->FindTab(tab.tab);
diff --git a/components/sensitive_content/BUILD.gn b/components/sensitive_content/BUILD.gn
index 42422011..a17755e5 100644
--- a/components/sensitive_content/BUILD.gn
+++ b/components/sensitive_content/BUILD.gn
@@ -10,6 +10,12 @@
     "sensitive_content_manager.cc",
     "sensitive_content_manager.h",
   ]
+  if (is_android) {
+    sources += [
+      "android/android_sensitive_content_client.cc",
+      "android/android_sensitive_content_client.h",
+    ]
+  }
   deps = [ "//content/public/browser" ]
   public_deps = [
     ":features",
diff --git a/components/sensitive_content/android/android_sensitive_content_client.cc b/components/sensitive_content/android/android_sensitive_content_client.cc
new file mode 100644
index 0000000..ecc2c12
--- /dev/null
+++ b/components/sensitive_content/android/android_sensitive_content_client.cc
@@ -0,0 +1,29 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/sensitive_content/android/android_sensitive_content_client.h"
+
+#include "base/notreached.h"
+#include "content/public/browser/web_contents.h"
+
+namespace sensitive_content {
+
+AndroidSensitiveContentClient::AndroidSensitiveContentClient(
+    content::WebContents* web_contents,
+    std::string histogram_prefix)
+    : content::WebContentsUserData<AndroidSensitiveContentClient>(
+          *web_contents),
+      manager_(web_contents, this),
+      histogram_prefix_(std::move(histogram_prefix)) {}
+
+AndroidSensitiveContentClient::~AndroidSensitiveContentClient() = default;
+
+void AndroidSensitiveContentClient::SetContentSensitivity(
+    bool content_is_sensitive) {}
+
+std::string_view AndroidSensitiveContentClient::GetHistogramPrefix() {
+  return histogram_prefix_;
+}
+
+}  // namespace sensitive_content
diff --git a/components/sensitive_content/android/android_sensitive_content_client.h b/components/sensitive_content/android/android_sensitive_content_client.h
new file mode 100644
index 0000000..6fafd81
--- /dev/null
+++ b/components/sensitive_content/android/android_sensitive_content_client.h
@@ -0,0 +1,41 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_SENSITIVE_CONTENT_ANDROID_ANDROID_SENSITIVE_CONTENT_CLIENT_H_
+#define COMPONENTS_SENSITIVE_CONTENT_ANDROID_ANDROID_SENSITIVE_CONTENT_CLIENT_H_
+
+#include "components/sensitive_content/sensitive_content_client.h"
+#include "components/sensitive_content/sensitive_content_manager.h"
+#include "content/public/browser/web_contents_user_data.h"
+
+namespace content {
+class WebContents;
+}  // namespace content
+
+namespace sensitive_content {
+
+class AndroidSensitiveContentClient
+    : public SensitiveContentClient,
+      public content::WebContentsUserData<AndroidSensitiveContentClient> {
+ public:
+  AndroidSensitiveContentClient(content::WebContents* web_contents,
+                                std::string histogram_prefix);
+
+  AndroidSensitiveContentClient(const AndroidSensitiveContentClient&) = delete;
+  AndroidSensitiveContentClient& operator=(
+      const AndroidSensitiveContentClient&) = delete;
+  ~AndroidSensitiveContentClient() override;
+
+  // SensitiveContentClient:
+  void SetContentSensitivity(bool content_is_sensitive) override;
+  std::string_view GetHistogramPrefix() override;
+
+ private:
+  SensitiveContentManager manager_;
+  std::string histogram_prefix_;
+};
+
+}  // namespace sensitive_content
+
+#endif  // COMPONENTS_SENSITIVE_CONTENT_ANDROID_ANDROID_SENSITIVE_CONTENT_CLIENT_H_
diff --git a/components/sensitive_content/sensitive_content_manager.cc b/components/sensitive_content/sensitive_content_manager.cc
index 5b43cc8..fe8b72f3 100644
--- a/components/sensitive_content/sensitive_content_manager.cc
+++ b/components/sensitive_content/sensitive_content_manager.cc
@@ -44,7 +44,9 @@
     content::WebContents* web_contents,
     SensitiveContentClient* client)
     : client_(CHECK_DEREF(client)) {
-  autofill_managers_observation_.Observe(web_contents);
+  autofill_managers_observation_.Observe(
+      web_contents, autofill::ScopedAutofillManagersObservation::
+                        InitializationPolicy::kObservePreexistingManagers);
 }
 
 SensitiveContentManager::~SensitiveContentManager() = default;
diff --git a/components/translate/content/browser/BUILD.gn b/components/translate/content/browser/BUILD.gn
index d3226681..50667e5 100644
--- a/components/translate/content/browser/BUILD.gn
+++ b/components/translate/content/browser/BUILD.gn
@@ -27,13 +27,13 @@
   deps = [
     "//components/keyed_service/core",
     "//components/language/core/browser",
+    "//components/language_detection/core/browser:language_detection_model_service",
     "//components/optimization_guide/content/browser",
     "//components/optimization_guide/core",
     "//components/optimization_guide/proto:optimization_guide_proto",
     "//components/search_engines",
     "//components/services/language_detection/public/cpp",
     "//components/services/language_detection/public/mojom",
-    "//components/translate/core/browser:translate_model_service",
     "//components/translate/core/language_detection:language_detection",
     "//components/ukm/content",
     "//content/public/browser",
diff --git a/components/translate/core/browser/BUILD.gn b/components/translate/core/browser/BUILD.gn
index 429c128..34d767df 100644
--- a/components/translate/core/browser/BUILD.gn
+++ b/components/translate/core/browser/BUILD.gn
@@ -88,20 +88,6 @@
   }
 }
 
-static_library("translate_model_service") {
-  sources = [
-    "translate_model_service.cc",
-    "translate_model_service.h",
-  ]
-  deps = [
-    "//base",
-    "//components/keyed_service/core",
-    "//components/optimization_guide/core",
-    "//components/optimization_guide/proto:optimization_guide_proto",
-    "//mojo/public/cpp/bindings",
-  ]
-}
-
 source_set("translate_pref_names") {
   sources = [ "translate_pref_names.h" ]
 }
diff --git a/components/translate/core/browser/translate_model_service.h b/components/translate/core/browser/translate_model_service.h
deleted file mode 100644
index 125ce837..0000000
--- a/components/translate/core/browser/translate_model_service.h
+++ /dev/null
@@ -1,104 +0,0 @@
-// Copyright 2020 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_TRANSLATE_CORE_BROWSER_TRANSLATE_MODEL_SERVICE_H_
-#define COMPONENTS_TRANSLATE_CORE_BROWSER_TRANSLATE_MODEL_SERVICE_H_
-
-#include <memory>
-#include <optional>
-#include <vector>
-
-#include "base/files/file.h"
-#include "base/files/file_path.h"
-#include "base/functional/callback.h"
-#include "base/memory/raw_ptr.h"
-#include "base/memory/weak_ptr.h"
-#include "base/sequence_checker.h"
-#include "base/task/sequenced_task_runner.h"
-#include "components/keyed_service/core/keyed_service.h"
-#include "components/optimization_guide/core/optimization_target_model_observer.h"
-
-namespace optimization_guide {
-class OptimizationGuideModelProvider;
-}  // namespace optimization_guide
-
-namespace translate {
-
-// Service that manages models required to support translation in the browser.
-// Currently, the service should only be used in the browser as it relies on
-// the Optimization Guide.
-// TODO(crbug.com/40225076): TranslateModelService should own
-// LanguageDetectionModel.
-class TranslateModelService
-    : public KeyedService,
-      public optimization_guide::OptimizationTargetModelObserver {
- public:
-  using GetModelCallback = base::OnceCallback<void(base::File)>;
-  using NotifyModelAvailableCallback = base::OnceCallback<void(bool)>;
-
-  TranslateModelService(
-      optimization_guide::OptimizationGuideModelProvider* opt_guide,
-      const scoped_refptr<base::SequencedTaskRunner>& background_task_runner);
-  ~TranslateModelService() override;
-
-  // KeyedService implementation:
-  void Shutdown() override;
-
-  // optimization_guide::OptimizationTargetModelObserver implementation:
-  void OnModelUpdated(
-      optimization_guide::proto::OptimizationTarget optimization_target,
-      base::optional_ref<const optimization_guide::ModelInfo> model_info)
-      override;
-
-  // Returns the language detection model file, should only be called when the
-  // is model file is already available. See the |NotifyOnModelFileAvailable|
-  // for an asynchronous notification of the model being available.
-  base::File GetLanguageDetectionModelFile();
-
-  // Returns whether the language detection model is loaded and available to be
-  // requested.
-  bool IsModelAvailable() { return language_detection_model_file_.has_value(); }
-
-  // If the model file is not available, requestors can ask to be notified, via
-  // |callback|. This enables a two-step approach to relabily get the model file
-  // when it becomes available if the requestor needs the file right when it
-  // becomes available (e.g., the translate driver). This is to ensure that if
-  // the callback becomes empty, only the notification gets dropped, rather than
-  // the model file which has to be closed on a background thread.
-  void NotifyOnModelFileAvailable(NotifyModelAvailableCallback callback);
-
- private:
-  // Unloads the model in background task.
-  void UnloadModelFile();
-
-  // Notifies the model update to observers, and clears the observer list.
-  void NotifyModelUpdatesAndClear(bool is_model_available);
-
-  void OnModelFileLoaded(base::File model_file);
-
-  // Optimization Guide Service that provides model files for this service.
-  // Optimization Guide Service is a BrowserContextKeyedServiceFactory and
-  // should not be used after Shutdown.
-  raw_ptr<optimization_guide::OptimizationGuideModelProvider> opt_guide_;
-
-  // The file that contains the language detection model. Available when the
-  // file path has been provided by the Optimization Guide and has been
-  // successfully loaded.
-  std::optional<base::File> language_detection_model_file_;
-
-  // The set of callbacks associated with requests for the language detection
-  // model. The callback notifies requesters than the model file is now
-  // available and can be safely requested.
-  std::vector<NotifyModelAvailableCallback> pending_model_requests_;
-
-  scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
-
-  SEQUENCE_CHECKER(sequence_checker_);
-
-  base::WeakPtrFactory<TranslateModelService> weak_ptr_factory_{this};
-};
-
-}  //  namespace translate
-
-#endif  // COMPONENTS_TRANSLATE_CORE_BROWSER_TRANSLATE_MODEL_SERVICE_H_
diff --git a/components/translate/ios/browser/BUILD.gn b/components/translate/ios/browser/BUILD.gn
index c9c5e6cc..ff4a52ad 100644
--- a/components/translate/ios/browser/BUILD.gn
+++ b/components/translate/ios/browser/BUILD.gn
@@ -9,8 +9,6 @@
   sources = [
     "ios_translate_driver.h",
     "ios_translate_driver.mm",
-    "language_detection_model_service.h",
-    "language_detection_model_service.mm",
     "translate_controller.h",
     "translate_controller.mm",
     "translate_java_script_feature.h",
@@ -20,12 +18,12 @@
   deps = [
     ":injected_js",
     "//base",
-    "//components/keyed_service/core",
     "//components/language/ios/browser",
     "//components/language_detection/core:language_detection",
+    "//components/language_detection/core/browser:language_detection_model_service",
+    "//components/language_detection/ios/browser",
     "//components/prefs",
     "//components/translate/core/browser",
-    "//components/translate/core/browser:translate_model_service",
     "//components/translate/core/common",
     "//components/translate/core/language_detection",
     "//components/ukm/ios:ukm_url_recorder",
diff --git a/components/translate/ios/browser/DEPS b/components/translate/ios/browser/DEPS
index 92e65249..c79e2151 100644
--- a/components/translate/ios/browser/DEPS
+++ b/components/translate/ios/browser/DEPS
@@ -1,6 +1,6 @@
 include_rules = [
-  "+components/keyed_service/core/keyed_service.h",
   "+components/language/core/browser",
-  "+components/ukm/ios",
   "+components/language_detection/core",
+  "+components/language_detection/ios/browser",
+  "+components/ukm/ios",
 ]
diff --git a/components/translate/ios/browser/ios_translate_driver.h b/components/translate/ios/browser/ios_translate_driver.h
index bcfdb8a..2b9b22e7 100644
--- a/components/translate/ios/browser/ios_translate_driver.h
+++ b/components/translate/ios/browser/ios_translate_driver.h
@@ -22,13 +22,16 @@
 class UrlLanguageHistogram;
 }  // namespace language
 
+namespace language_detection {
+class LanguageDetectionModelLoaderServiceIOS;
+}  // namespace language_detection
+
 namespace web {
 class WebState;
 }
 
 namespace translate {
 
-class LanguageDetectionModelService;
 class TranslateManager;
 
 // Content implementation of TranslateDriver.
@@ -38,9 +41,9 @@
       public web::WebStateObserver,
       public language::IOSLanguageDetectionTabHelper::Observer {
  public:
-  IOSTranslateDriver(
-      web::WebState* web_state,
-      LanguageDetectionModelService* language_detection_model_service);
+  IOSTranslateDriver(web::WebState* web_state,
+                     language_detection::LanguageDetectionModelLoaderServiceIOS*
+                         language_detection_model_service);
 
   IOSTranslateDriver(const IOSTranslateDriver&) = delete;
   IOSTranslateDriver& operator=(const IOSTranslateDriver&) = delete;
@@ -129,8 +132,8 @@
   base::WeakPtr<TranslateManager> translate_manager_;
   std::unique_ptr<TranslateController> translate_controller_;
 
-  raw_ptr<LanguageDetectionModelService> language_detection_model_service_ =
-      nullptr;
+  raw_ptr<language_detection::LanguageDetectionModelLoaderServiceIOS>
+      language_detection_model_service_ = nullptr;
 
   // An ever-increasing sequence number of the current page, used to match up
   // translation requests with responses.
diff --git a/components/translate/ios/browser/ios_translate_driver.mm b/components/translate/ios/browser/ios_translate_driver.mm
index 594ffc1..b58843c 100644
--- a/components/translate/ios/browser/ios_translate_driver.mm
+++ b/components/translate/ios/browser/ios_translate_driver.mm
@@ -10,15 +10,15 @@
 #include "base/strings/sys_string_conversions.h"
 #include "base/task/thread_pool.h"
 #include "base/time/time.h"
+#include "components/language_detection/core/browser/language_detection_model_service.h"
+#include "components/language_detection/ios/browser/language_detection_model_loader_service_ios.h"
 #include "components/translate/core/browser/translate_client.h"
 #include "components/translate/core/browser/translate_manager.h"
-#include "components/translate/core/browser/translate_model_service.h"
 #include "components/translate/core/common/language_detection_details.h"
 #include "components/translate/core/common/translate_constants.h"
 #include "components/translate/core/common/translate_metrics.h"
 #include "components/translate/core/common/translate_util.h"
 #include "components/translate/core/language_detection/language_detection_model.h"
-#include "components/translate/ios/browser/language_detection_model_service.h"
 #import "components/translate/ios/browser/translate_controller.h"
 #include "components/ukm/ios/ukm_url_recorder.h"
 #import "ios/web/public/annotations/annotations_text_manager.h"
@@ -50,7 +50,8 @@
 
 IOSTranslateDriver::IOSTranslateDriver(
     web::WebState* web_state,
-    LanguageDetectionModelService* language_detection_model_service)
+    language_detection::LanguageDetectionModelLoaderServiceIOS*
+        language_detection_model_service)
     : web_state_(web_state),
       language_detection_model_service_(language_detection_model_service),
       page_seq_no_(0),
diff --git a/components/translate/ios/browser/language_detection_model_service.h b/components/translate/ios/browser/language_detection_model_service.h
deleted file mode 100644
index 3eb5148e..0000000
--- a/components/translate/ios/browser/language_detection_model_service.h
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_TRANSLATE_IOS_BROWSER_LANGUAGE_DETECTION_MODEL_SERVICE_H_
-#define COMPONENTS_TRANSLATE_IOS_BROWSER_LANGUAGE_DETECTION_MODEL_SERVICE_H_
-
-#include "base/files/file.h"
-#include "base/memory/raw_ptr.h"
-#include "base/memory/weak_ptr.h"
-#include "base/sequence_checker.h"
-#include "base/task/sequenced_task_runner.h"
-#include "components/keyed_service/core/keyed_service.h"
-
-namespace translate {
-
-class LanguageDetectionModelContainer;
-class LanguageDetectionModel;
-class TranslateModelService;
-
-// A service that contains the LanguageDetectionModel and handles its loading.
-// This is a workaround for crbug/1324530 on iOS where it is mandatory to have
-// LanguageDetectionModel scoped by BrowserState.
-// TODO(crbug.com/40225076): remove this class once TranslateModelService does
-// this.
-class LanguageDetectionModelService : public KeyedService {
- public:
-  LanguageDetectionModelService(
-      TranslateModelService* translate_model_service,
-      const scoped_refptr<base::SequencedTaskRunner>& background_task_runner);
-  ~LanguageDetectionModelService() override;
-
-  // Get for the actual TFLite language detection model.
-  LanguageDetectionModel* GetLanguageDetectionModel();
-
-  // Utility function to check if the model is already loaded.
-  // |GetLanguageDetectionModel| can be used even if this return false.
-  bool IsModelAvailable();
-
- private:
-  // Notifies |this| that the translate model service is available for model
-  // requests or is invalidating existing requests specified by |is_available|.
-  void OnLanguageModelFileAvailabilityChanged(bool available);
-  // The TranslageModelService that will handle the downloading and provide
-  // the file containing the model.
-  raw_ptr<TranslateModelService> translate_model_service_;
-  scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
-  scoped_refptr<LanguageDetectionModelContainer> language_detection_model_;
-  base::WeakPtrFactory<LanguageDetectionModelService> weak_ptr_factory_{this};
-};
-
-}  // namespace translate
-
-#endif  // COMPONENTS_TRANSLATE_IOS_BROWSER_LANGUAGE_DETECTION_MODEL_SERVICE_H_
diff --git a/components/translate/ios/browser/language_detection_model_service.mm b/components/translate/ios/browser/language_detection_model_service.mm
deleted file mode 100644
index c3ab3aa716..0000000
--- a/components/translate/ios/browser/language_detection_model_service.mm
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/translate/ios/browser/language_detection_model_service.h"
-
-#include <memory>
-
-#import "base/task/sequenced_task_runner.h"
-#include "components/language_detection/core/language_detection_model.h"
-#include "components/language_detection/core/language_detection_provider.h"
-#include "components/translate/core/browser/translate_model_service.h"
-#include "components/translate/core/language_detection/language_detection_model.h"
-
-namespace translate {
-
-class LanguageDetectionModelContainer
-    // TODO(https://crbug.com/356380874): Clarify the thread safety of this
-    // class. The TFLite model should not be accessed from multiple threads,
-    // so it should not be destroyed from another thread.
-    : public base::RefCountedThreadSafe<LanguageDetectionModelContainer>,
-      public LanguageDetectionModel {
- public:
-  LanguageDetectionModelContainer()
-      : LanguageDetectionModel(
-            &language_detection::GetLanguageDetectionModel()) {}
-
- private:
-  // Allow destruction by RefCounted<>.
-  friend class RefCountedThreadSafe<LanguageDetectionModelContainer>;
-  // Destructor must be private/protected.
-  ~LanguageDetectionModelContainer() = default;
-};
-
-namespace {
-void SetLanguageDetectionModelModelFile(
-    scoped_refptr<translate::LanguageDetectionModelContainer>
-        language_detection_model,
-    base::File model_file) {
-  language_detection_model->UpdateWithFile(std::move(model_file));
-}
-}  // namespace
-
-LanguageDetectionModelService::LanguageDetectionModelService(
-    TranslateModelService* translate_model_service,
-    const scoped_refptr<base::SequencedTaskRunner>& background_task_runner)
-    : translate_model_service_(translate_model_service),
-      background_task_runner_(background_task_runner),
-      language_detection_model_(
-          base::MakeRefCounted<LanguageDetectionModelContainer>()) {
-  if (translate_model_service_) {
-    if (!language_detection_model_->IsAvailable()) {
-      translate_model_service_->NotifyOnModelFileAvailable(
-          base::BindOnce(&LanguageDetectionModelService::
-                             OnLanguageModelFileAvailabilityChanged,
-                         weak_ptr_factory_.GetWeakPtr()));
-    } else {
-      OnLanguageModelFileAvailabilityChanged(true);
-    }
-  }
-}
-
-LanguageDetectionModelService::~LanguageDetectionModelService() {}
-
-LanguageDetectionModel*
-LanguageDetectionModelService::GetLanguageDetectionModel() {
-  return language_detection_model_.get();
-}
-
-bool LanguageDetectionModelService::IsModelAvailable() {
-  return language_detection_model_->IsAvailable();
-}
-
-void LanguageDetectionModelService::OnLanguageModelFileAvailabilityChanged(
-    bool available) {
-  if (available) {
-    DCHECK(translate_model_service_);
-    base::File model_file =
-        translate_model_service_->GetLanguageDetectionModelFile();
-    background_task_runner_->PostTask(
-        FROM_HERE,
-        base::BindOnce(&SetLanguageDetectionModelModelFile,
-                       language_detection_model_, std::move(model_file)));
-  }
-}
-
-}  // namespace translate
diff --git a/components/url_matcher/url_matcher_unittest.cc b/components/url_matcher/url_matcher_unittest.cc
index b641be9..8b9c4c9c 100644
--- a/components/url_matcher/url_matcher_unittest.cc
+++ b/components/url_matcher/url_matcher_unittest.cc
@@ -76,7 +76,7 @@
 void CreateAndAddCidrBlock(
     const std::string& cidr_block,
     std::vector<URLMatcherCidrBlockFilter::CidrBlock>& blocks) {
-  const auto& block = URLMatcherCidrBlockFilter::CreateCidrBlock(cidr_block);
+  auto block = URLMatcherCidrBlockFilter::CreateCidrBlock(cidr_block);
   ASSERT_TRUE(block.has_value());
   blocks.push_back(std::move(*block));
 }
diff --git a/content/browser/ai/echo_ai_manager_impl.cc b/content/browser/ai/echo_ai_manager_impl.cc
index 2c785572..0af41a0 100644
--- a/content/browser/ai/echo_ai_manager_impl.cc
+++ b/content/browser/ai/echo_ai_manager_impl.cc
@@ -42,6 +42,7 @@
     mojo::PendingReceiver<blink::mojom::AITextSession> receiver,
     blink::mojom::AITextSessionSamplingParamsPtr sampling_params,
     const std::optional<std::string>& system_prompt,
+    std::vector<blink::mojom::AIAssistantInitialPromptPtr> initial_prompts,
     CreateTextSessionCallback callback) {
   mojo::MakeSelfOwnedReceiver(std::make_unique<EchoAITextSession>(),
                               std::move(receiver));
diff --git a/content/browser/ai/echo_ai_manager_impl.h b/content/browser/ai/echo_ai_manager_impl.h
index 53bef73..410408b8 100644
--- a/content/browser/ai/echo_ai_manager_impl.h
+++ b/content/browser/ai/echo_ai_manager_impl.h
@@ -47,6 +47,7 @@
       mojo::PendingReceiver<::blink::mojom::AITextSession> receiver,
       blink::mojom::AITextSessionSamplingParamsPtr sampling_params,
       const std::optional<std::string>& system_prompt,
+      std::vector<blink::mojom::AIAssistantInitialPromptPtr> initial_prompts,
       CreateTextSessionCallback callback) override;
 
   void CanCreateSummarizer(CanCreateSummarizerCallback callback) override;
diff --git a/content/browser/renderer_host/agent_scheduling_group_host.cc b/content/browser/renderer_host/agent_scheduling_group_host.cc
index 2297f457..c2d3384 100644
--- a/content/browser/renderer_host/agent_scheduling_group_host.cc
+++ b/content/browser/renderer_host/agent_scheduling_group_host.cc
@@ -321,6 +321,9 @@
 }
 
 void AgentSchedulingGroupHost::RemoveRoute(int32_t routing_id) {
+  TRACE_EVENT0("navigation", "AgentSchedulingGroupHost::RemoveRoute");
+  base::ScopedUmaHistogramTimer histogram_timer(
+      "Navigation.AgentSchedulingGroupHost.RemoveRoute");
   DCHECK_EQ(state_, LifecycleState::kBound);
   listener_map_.Remove(routing_id);
   process_->RemoveRoute(routing_id);
diff --git a/content/browser/renderer_host/document_associated_data.cc b/content/browser/renderer_host/document_associated_data.cc
index 22a28f01..5b6586b7d 100644
--- a/content/browser/renderer_host/document_associated_data.cc
+++ b/content/browser/renderer_host/document_associated_data.cc
@@ -51,6 +51,9 @@
 }
 
 DocumentAssociatedData::~DocumentAssociatedData() {
+  TRACE_EVENT0("navigation", "DocumentAssociatedData::~DocumentAssociatedData");
+  base::ScopedUmaHistogramTimer histogram_timer(
+      "Navigation.DocumentAssociatedDataDestructor");
   decltype(services_) services;
   std::swap(services_, services);
   for (auto& service : services) {
diff --git a/content/browser/renderer_host/origin_agent_cluster_browsertest.cc b/content/browser/renderer_host/origin_agent_cluster_browsertest.cc
index 3a801906..acf7cb2 100644
--- a/content/browser/renderer_host/origin_agent_cluster_browsertest.cc
+++ b/content/browser/renderer_host/origin_agent_cluster_browsertest.cc
@@ -44,7 +44,6 @@
   OriginAgentClusterBrowserTest()
       : OriginAgentClusterBrowserTest(
             /* origin_cluster_default_enabled */ false,
-            /* origin_cluster_absent_warning */ false,
             /* secure_context */ true) {}
   ~OriginAgentClusterBrowserTest() override = default;
 
@@ -59,11 +58,9 @@
   enum OriginAgentClusterState { kUnset, kSetTrue, kSetFalse, kMalformed };
 
   OriginAgentClusterBrowserTest(bool origin_cluster_default_enabled,
-                                bool origin_cluster_absent_warning,
                                 bool secure_context)
       : server_(net::EmbeddedTestServer::TYPE_HTTPS),
         origin_cluster_default_enabled_(origin_cluster_default_enabled),
-        origin_cluster_absent_warning_(origin_cluster_absent_warning),
         secure_context_(secure_context) {
     server_.AddDefaultHandlers(GetTestDataFilePath());
 
@@ -72,8 +69,6 @@
     std::vector<base::test::FeatureRef> enabled, disabled;
     (origin_cluster_default_enabled_ ? enabled : disabled)
         .push_back(blink::features::kOriginAgentClusterDefaultEnabled);
-    (origin_cluster_absent_warning_ ? enabled : disabled)
-        .push_back(blink::features::kOriginAgentClusterDefaultWarning);
     // TODO(https://crbug.com/40259221): update this test to be parameterized on
     // kOriginKeyedProcessesByDefault, and then make sure all the tests have
     // correct expectations both with and without. This will assist in removing
@@ -198,7 +193,6 @@
   std::unique_ptr<MockContentBrowserClient> browser_client_;
 
   const bool origin_cluster_default_enabled_;
-  const bool origin_cluster_absent_warning_;
   const bool secure_context_;
   base::test::ScopedFeatureList features_;
 };
@@ -211,24 +205,10 @@
   OriginAgentClusterEnabledBrowserTest()
       : OriginAgentClusterBrowserTest(
             /* origin_cluster_default_enabled */ true,
-            /* origin_cluster_absent_warning */ false,
             /* secure_context */ true) {}
   ~OriginAgentClusterEnabledBrowserTest() override = default;
 };
 
-// Test fixture wih the deprecation warning enabled.
-// (blink::features::kOriginAgentClusterDefaultWarning)
-class OriginAgentClusterWarningBrowserTest
-    : public OriginAgentClusterBrowserTest {
- public:
-  OriginAgentClusterWarningBrowserTest()
-      : OriginAgentClusterBrowserTest(
-            /* origin_cluster_default_enabled */ false,
-            /* origin_cluster_absent_warning */ true,
-            /* secure_context */ true) {}
-  ~OriginAgentClusterWarningBrowserTest() override = default;
-};
-
 // Test fixture wih the default behaviour change enabled, but using an insecure
 // context. (blink::features::kOriginAgentClusterDefaultEnabled + http:)
 class OriginAgentClusterInsecureEnabledBrowserTest
@@ -237,7 +217,6 @@
   OriginAgentClusterInsecureEnabledBrowserTest()
       : OriginAgentClusterBrowserTest(
             /* origin_cluster_default_enabled */ true,
-            /* origin_cluster_absent_warning */ false,
             /* secure_context */ false) {}
   ~OriginAgentClusterInsecureEnabledBrowserTest() override = default;
 };
@@ -388,29 +367,6 @@
       CanDocumentDomainMessage("a.domain.test", "domain.test", kMalformed));
 }
 
-IN_PROC_BROWSER_TEST_F(OriginAgentClusterWarningBrowserTest,
-                       WarningMessage_Default) {
-  EXPECT_TRUE(CanDocumentDomainMessage("a.domain.test", "domain.test", kUnset));
-}
-
-IN_PROC_BROWSER_TEST_F(OriginAgentClusterWarningBrowserTest,
-                       WarningMessage_Enabled) {
-  EXPECT_FALSE(
-      CanDocumentDomainMessage("a.domain.test", "domain.test", kSetTrue));
-}
-
-IN_PROC_BROWSER_TEST_F(OriginAgentClusterWarningBrowserTest,
-                       WarningMessage_Disabled) {
-  EXPECT_TRUE(
-      CanDocumentDomainMessage("a.domain.test", "domain.test", kSetFalse));
-}
-
-IN_PROC_BROWSER_TEST_F(OriginAgentClusterWarningBrowserTest,
-                       WarningMessage_Malformed) {
-  EXPECT_TRUE(
-      CanDocumentDomainMessage("a.domain.test", "domain.test", kMalformed));
-}
-
 // Policy: Ensure that the legacy behaviour remains if the appropriate
 // enterprise policy is set.
 //
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index b0fac1d..a28ac1d 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -3826,6 +3826,8 @@
               [&](perfetto::EventContext ctx) {
                 WriteRenderFrameImplDeletion(ctx, this, intent);
               });
+  base::ScopedUmaHistogramTimer histogram_timer(
+      "Navigation.RenderFrameHostImpl.DeleteRenderFrame");
   if (IsPendingDeletion())
     return;
 
@@ -5024,6 +5026,9 @@
 }
 
 void RenderFrameHostImpl::ResetChildren() {
+  TRACE_EVENT("navigation", "RenderFrameHostImpl::ResetChildren",
+              ChromeTrackEvent::kRenderFrameHost, this);
+  base::ScopedUmaHistogramTimer histogram_timer("Navigation.ResetChildren");
   // Remove child nodes from the tree, then delete them. This destruction
   // operation will notify observers. See https://crbug.com/612450 for
   // explanation why we don't just call the std::vector::clear method.
@@ -10877,6 +10882,15 @@
 
 void RenderFrameHostImpl::StartPendingDeletionOnSubtree(
     RenderFrameHostImpl::PendingDeletionReason pending_deletion_reason) {
+  TRACE_EVENT("navigation",
+              "RenderFrameHostImpl::StartPendingDeletionOnSubtree",
+              ChromeTrackEvent::kRenderFrameHost, this);
+  std::string_view histogram_suffix =
+      (pending_deletion_reason == PendingDeletionReason::kFrameDetach)
+          ? "Detach"
+          : "SwappedOut";
+  base::ScopedUmaHistogramTimer histogram_timer(base::StrCat(
+      {"Navigation.StartPendingDeletionOnSubtree.", histogram_suffix}));
   DCHECK(IsPendingDeletion());
 
   if (pending_deletion_reason == PendingDeletionReason::kFrameDetach ||
@@ -10910,6 +10924,8 @@
     subframe->ResetAllNavigationsForFrameDetach();
   }
 
+  base::ScopedUmaHistogramTimer histogram_timer_loop(base::StrCat(
+      {"Navigation.StartPendingDeletionOnSubtree.Loop", histogram_suffix}));
   for (std::unique_ptr<FrameTreeNode>& child_frame : children_) {
     for (FrameTreeNode* node : frame_tree()->SubtreeNodes(child_frame.get())) {
       RenderFrameHostImpl* child = node->current_frame_host();
@@ -10956,6 +10972,12 @@
 }
 
 void RenderFrameHostImpl::PendingDeletionCheckCompletedOnSubtree() {
+  TRACE_EVENT("navigation",
+              "RenderFrameHostImpl::PendingDeletionCheckCompletedOnSubtree",
+              ChromeTrackEvent::kRenderFrameHost, this);
+  base::ScopedUmaHistogramTimer histogram_timer(
+      "Navigation.PendingDeletionCheckCompletedOnSubtree");
+
   if (children_.empty()) {
     PendingDeletionCheckCompleted();  // This might delete |this|.
     // DO NOT add code after this.
diff --git a/content/public/browser/download_manager_delegate.cc b/content/public/browser/download_manager_delegate.cc
index 412f4db..798f45a9 100644
--- a/content/public/browser/download_manager_delegate.cc
+++ b/content/public/browser/download_manager_delegate.cc
@@ -152,6 +152,10 @@
 bool DownloadManagerDelegate::ShouldOpenPdfInline() {
   return false;
 }
+
+bool DownloadManagerDelegate::IsDownloadRestrictedByPolicy() {
+  return false;
+}
 #endif  // BUILDFLAG(IS_ANDROID)
 
 }  // namespace content
diff --git a/content/public/browser/download_manager_delegate.h b/content/public/browser/download_manager_delegate.h
index 5a4538f..d7e9de4 100644
--- a/content/public/browser/download_manager_delegate.h
+++ b/content/public/browser/download_manager_delegate.h
@@ -245,6 +245,9 @@
 
   // Whether to open pdf inline.
   virtual bool ShouldOpenPdfInline();
+
+  // Whether download is restricted by policy.
+  virtual bool IsDownloadRestrictedByPolicy();
 #endif  // BUILDFLAG(IS_ANDROID)
  protected:
   virtual ~DownloadManagerDelegate();
diff --git a/content/renderer/media/gpu/gpu_video_accelerator_factories_impl.cc b/content/renderer/media/gpu/gpu_video_accelerator_factories_impl.cc
index 7245246..32c509a 100644
--- a/content/renderer/media/gpu/gpu_video_accelerator_factories_impl.cc
+++ b/content/renderer/media/gpu/gpu_video_accelerator_factories_impl.cc
@@ -35,6 +35,20 @@
 
 namespace content {
 
+#if BUILDFLAG(IS_WIN)
+namespace {
+
+// Use NV12 as the default video frame output format. Note that NV12 is the
+// preferred 4:2:0 pixel format on Windows according to:
+// https://learn.microsoft.com/en-us/windows-hardware/drivers/display/4-2-0-video-pixel-formats
+// https://learn.microsoft.com/en-us/windows/win32/medfound/recommended-8-bit-yuv-formats-for-video-rendering#nv12
+BASE_FEATURE(kUseNV12OutputFormat,
+             "UseNV12OutputFormat",
+             base::FEATURE_ENABLED_BY_DEFAULT);
+
+}  // namespace
+#endif
+
 // static
 std::unique_ptr<GpuVideoAcceleratorFactoriesImpl>
 GpuVideoAcceleratorFactoriesImpl::Create(
@@ -334,6 +348,12 @@
     }
 #endif  // !BUILDFLAG(IS_WIN)
     if (capabilities.texture_rg) {
+#if BUILDFLAG(IS_WIN)
+      // Use NV12 for Windows platform which has the overlay support.
+      if (base::FeatureList::IsEnabled(kUseNV12OutputFormat)) {
+        return OutputFormat::NV12;
+      }
+#endif
       return OutputFormat::YV12;
     }
     return OutputFormat::UNDEFINED;
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 99b7d711..f63cce8 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -5561,7 +5561,7 @@
     // All frames in a WebUI process must have the same enabled_bindings_, so
     // we can do a per-frame check here rather than a process-wide check.
     bool should_fork = HasWebUIScheme(url) || HasWebUIScheme(old_url) ||
-                       !enabled_bindings_.empty();
+                       enabled_bindings_.HasAny(kWebUIBindingsPolicySet);
     if (should_fork) {
       OpenURL(std::move(info));
       return;  // Suppress the load here.
diff --git a/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt
index 33f10f3..bcae75c9 100644
--- a/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt
@@ -138,7 +138,7 @@
 crbug.com/333426465 [ win intel-0x4680 ] WebCodecs_PerFrameQpEncoding_offscreen_avc1.42001E_prefer-hardware [ Failure ]
 
 crbug.com/337665165 [ angle-d3d11 graphite-disabled nvidia-0x2184 nvidia_lt_31.0.15.4601 passthrough release win ] WebCodecs_ContentHint_avc1.42001E_text [ Failure ]
-crbug.com/337665165 [ angle-d3d11 graphite-disabled nvidia-0x2184 nvidia_lt_31.0.15.4601 passthrough release win ] WebCodecs_ContentHint_avc1.42001E_motion [ Failure ]
+crbug.com/337665165 [ angle-d3d11 graphite-disabled nvidia-0x2184 nvidia_lt_31.0.15.4601 passthrough release-x64 target-cpu-64 win ] WebCodecs_ContentHint_avc1.42001E_motion [ Failure ]
 crbug.com/337665165 [ angle-d3d11 graphite-disabled nvidia-0x2184 nvidia_lt_31.0.15.4601 passthrough release win ] WebCodecs_ContentHint_hvc1.1.6.L123.00_text [ Failure ]
 crbug.com/337665165 [ angle-d3d11 graphite-disabled nvidia-0x2184 nvidia_lt_31.0.15.4601 passthrough release win ] WebCodecs_ContentHint_hvc1.1.6.L123.00_motion [ Failure ]
 crbug.com/337665165 [ angle-d3d11 graphite-disabled nvidia-0x2184 nvidia_lt_31.0.15.4601 passthrough release win ] WebCodecs_ContentHint_hvc1.1.6.L123.00_detail [ Failure ]
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
index c7453c8..458a05d 100644
--- a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
@@ -569,7 +569,7 @@
 
 # Failing on some platforms.
 crbug.com/1175371 [ angle-opengl display-server-x linux passthrough ] conformance/extensions/khr-parallel-shader-compile.html [ Failure ]
-crbug.com/1175371 [ angle-metal mac no-asan oop-c ] conformance/extensions/khr-parallel-shader-compile.html [ Failure ]
+crbug.com/1175371 [ amd-0x7340 angle-metal mac-x86_64 no-asan oop-c sonoma ] conformance/extensions/khr-parallel-shader-compile.html [ Failure ]
 
 # Won't investigate failure on validating command decoder. Remove once it's unshipped.
 crbug.com/angleproject/5499 [ no-passthrough ] conformance/glsl/misc/shaders-with-name-conflicts.html [ Failure ]
@@ -669,33 +669,33 @@
 crbug.com/angleproject/6430 [ mac passthrough angle-metal amd ] deqp/functional/gles3/pixelbufferobject.html [ Failure ]
 crbug.com/angleproject/6430 [ mac passthrough angle-metal amd ] deqp/functional/gles3/shaderpackingfunction.html [ Failure ]
 crbug.com/angleproject/6430 [ amd-0x679e angle-metal monterey passthrough ] deqp/functional/gles3/textureshadow/2d_array_nearest_mipmap_nearest_greater_or_equal.html [ Failure ]
-crbug.com/angleproject/6430 [ angle-metal intel-gen-9 passthrough sonoma ] deqp/functional/gles3/textureshadow/2d_array_nearest_mipmap_nearest_greater_or_equal.html [ Failure ]
+crbug.com/angleproject/6430 [ amd-0x67ef angle-metal passthrough sonoma ] deqp/functional/gles3/textureshadow/2d_array_nearest_mipmap_nearest_greater_or_equal.html [ Failure ]
 crbug.com/angleproject/6430 [ amd-0x679e angle-metal monterey passthrough ] deqp/functional/gles3/textureshadow/2d_array_nearest_mipmap_nearest_greater.html [ Failure ]
-crbug.com/angleproject/6430 [ angle-metal intel-gen-9 passthrough sonoma ] deqp/functional/gles3/textureshadow/2d_array_nearest_mipmap_nearest_greater.html [ Failure ]
+crbug.com/angleproject/6430 [ amd-0x67ef angle-metal passthrough sonoma ] deqp/functional/gles3/textureshadow/2d_array_nearest_mipmap_nearest_greater.html [ Failure ]
 crbug.com/angleproject/6430 [ amd-0x679e angle-metal monterey passthrough ] deqp/functional/gles3/textureshadow/2d_array_nearest_mipmap_nearest_less_or_equal.html [ Failure ]
-crbug.com/angleproject/6430 [ angle-metal intel-gen-9 passthrough sonoma ] deqp/functional/gles3/textureshadow/2d_array_nearest_mipmap_nearest_less_or_equal.html [ Failure ]
+crbug.com/angleproject/6430 [ amd-0x67ef angle-metal passthrough sonoma ] deqp/functional/gles3/textureshadow/2d_array_nearest_mipmap_nearest_less_or_equal.html [ Failure ]
 crbug.com/angleproject/6430 [ amd-0x679e angle-metal monterey passthrough ] deqp/functional/gles3/textureshadow/2d_array_nearest_mipmap_nearest_less.html [ Failure ]
-crbug.com/angleproject/6430 [ angle-metal intel-gen-9 passthrough sonoma ] deqp/functional/gles3/textureshadow/2d_array_nearest_mipmap_nearest_less.html [ Failure ]
+crbug.com/angleproject/6430 [ amd-0x67ef angle-metal passthrough sonoma ] deqp/functional/gles3/textureshadow/2d_array_nearest_mipmap_nearest_less.html [ Failure ]
 crbug.com/angleproject/6430 [ amd-0x679e angle-metal monterey passthrough ] deqp/functional/gles3/textureshadow/2d_linear_mipmap_nearest_greater_or_equal.html [ Failure ]
-crbug.com/angleproject/6430 [ angle-metal intel-gen-9 passthrough sonoma ] deqp/functional/gles3/textureshadow/2d_linear_mipmap_nearest_greater_or_equal.html [ Failure ]
+crbug.com/angleproject/6430 [ amd-0x67ef angle-metal passthrough sonoma ] deqp/functional/gles3/textureshadow/2d_linear_mipmap_nearest_greater_or_equal.html [ Failure ]
 crbug.com/angleproject/6430 [ amd-0x679e angle-metal monterey passthrough ] deqp/functional/gles3/textureshadow/2d_linear_mipmap_nearest_greater.html [ Failure ]
-crbug.com/angleproject/6430 [ angle-metal intel-gen-9 passthrough sonoma ] deqp/functional/gles3/textureshadow/2d_linear_mipmap_nearest_greater.html [ Failure ]
+crbug.com/angleproject/6430 [ amd-0x67ef angle-metal passthrough sonoma ] deqp/functional/gles3/textureshadow/2d_linear_mipmap_nearest_greater.html [ Failure ]
 crbug.com/angleproject/6430 [ amd-0x679e angle-metal monterey passthrough ] deqp/functional/gles3/textureshadow/2d_linear_mipmap_nearest_less_or_equal.html [ Failure ]
-crbug.com/angleproject/6430 [ angle-metal intel-gen-9 passthrough sonoma ] deqp/functional/gles3/textureshadow/2d_linear_mipmap_nearest_less_or_equal.html [ Failure ]
+crbug.com/angleproject/6430 [ amd-0x67ef angle-metal passthrough sonoma ] deqp/functional/gles3/textureshadow/2d_linear_mipmap_nearest_less_or_equal.html [ Failure ]
 crbug.com/angleproject/6430 [ amd-0x679e angle-metal monterey passthrough ] deqp/functional/gles3/textureshadow/2d_linear_mipmap_nearest_less.html [ Failure ]
-crbug.com/angleproject/6430 [ angle-metal intel-gen-9 passthrough sonoma ] deqp/functional/gles3/textureshadow/2d_linear_mipmap_nearest_less.html [ Failure ]
+crbug.com/angleproject/6430 [ amd-0x67ef angle-metal passthrough sonoma ] deqp/functional/gles3/textureshadow/2d_linear_mipmap_nearest_less.html [ Failure ]
 crbug.com/angleproject/6430 [ amd-0x679e angle-metal monterey passthrough ] deqp/functional/gles3/textureshadow/2d_nearest_mipmap_nearest_greater_or_equal.html [ Failure ]
-crbug.com/angleproject/6430 [ angle-metal intel-gen-9 passthrough sonoma ] deqp/functional/gles3/textureshadow/2d_nearest_mipmap_nearest_greater_or_equal.html [ Failure ]
+crbug.com/angleproject/6430 [ amd-0x67ef angle-metal passthrough sonoma ] deqp/functional/gles3/textureshadow/2d_nearest_mipmap_nearest_greater_or_equal.html [ Failure ]
 crbug.com/angleproject/6430 [ amd-0x679e angle-metal monterey passthrough ] deqp/functional/gles3/textureshadow/2d_nearest_mipmap_nearest_greater.html [ Failure ]
-crbug.com/angleproject/6430 [ angle-metal intel-gen-9 passthrough sonoma ] deqp/functional/gles3/textureshadow/2d_nearest_mipmap_nearest_greater.html [ Failure ]
+crbug.com/angleproject/6430 [ amd-0x67ef angle-metal passthrough sonoma ] deqp/functional/gles3/textureshadow/2d_nearest_mipmap_nearest_greater.html [ Failure ]
 crbug.com/angleproject/6430 [ amd-0x679e angle-metal monterey passthrough ] deqp/functional/gles3/textureshadow/2d_nearest_mipmap_nearest_less_or_equal.html [ Failure ]
-crbug.com/angleproject/6430 [ angle-metal intel-gen-9 passthrough sonoma ] deqp/functional/gles3/textureshadow/2d_nearest_mipmap_nearest_less_or_equal.html [ Failure ]
+crbug.com/angleproject/6430 [ amd-0x67ef angle-metal passthrough sonoma ] deqp/functional/gles3/textureshadow/2d_nearest_mipmap_nearest_less_or_equal.html [ Failure ]
 crbug.com/angleproject/6430 [ amd-0x679e angle-metal monterey passthrough ] deqp/functional/gles3/textureshadow/2d_nearest_mipmap_nearest_less.html [ Failure ]
-crbug.com/angleproject/6430 [ angle-metal intel-gen-9 passthrough sonoma ] deqp/functional/gles3/textureshadow/2d_nearest_mipmap_nearest_less.html [ Failure ]
+crbug.com/angleproject/6430 [ amd-0x67ef angle-metal passthrough sonoma ] deqp/functional/gles3/textureshadow/2d_nearest_mipmap_nearest_less.html [ Failure ]
 crbug.com/angleproject/6430 [ amd-0x679e angle-metal monterey passthrough ] deqp/functional/gles3/texturespecification/texstorage2d_format_depth_stencil.html [ Failure ]
-crbug.com/angleproject/6430 [ angle-metal intel-gen-9 passthrough sonoma ] deqp/functional/gles3/texturespecification/texstorage2d_format_depth_stencil.html [ Failure ]
+crbug.com/angleproject/6430 [ amd-0x67ef angle-metal passthrough sonoma ] deqp/functional/gles3/texturespecification/texstorage2d_format_depth_stencil.html [ Failure ]
 crbug.com/angleproject/7425 [ amd-0x679e angle-metal monterey passthrough ] deqp/functional/gles3/texturespecification/texstorage3d_format_depth_stencil.html [ Failure ]
-crbug.com/angleproject/7425 [ angle-metal intel-gen-9 passthrough sonoma ] deqp/functional/gles3/texturespecification/texstorage3d_format_depth_stencil.html [ Failure ]
+crbug.com/angleproject/7425 [ amd-0x67ef angle-metal passthrough sonoma ] deqp/functional/gles3/texturespecification/texstorage3d_format_depth_stencil.html [ Failure ]
 
 
 crbug.com/328100306 [ amd angle-metal graphite-enabled sonoma ] conformance/glsl/bugs/sampler-array-using-loop-index.html [ Failure ]
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt
index 8a4d3ab..06347b2 100644
--- a/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt
@@ -558,7 +558,7 @@
 # crbug.com/735483 [ mac amd release ] conformance/rendering/texture-switch-performance.html [ Failure ]
 
 crbug.com/354627705 [ mac amd-0x7340 angle-opengl ] conformance/context/context-attributes-alpha-depth-stencil-antialias.html [ Failure ]
-crbug.com/354627705 [ angle-metal intel-0x3e9b mac no-clang-coverage release ] conformance/extensions/webgl-polygon-mode.html [ Failure ]
+crbug.com/354627705 [ amd-0x7340 angle-metal mac no-clang-coverage release ] conformance/extensions/webgl-polygon-mode.html [ Failure ]
 crbug.com/354627705 [ mac amd-0x7340 angle-opengl ] conformance/rendering/color-mask-preserved-during-implicit-clears.html [ Failure ]
 
 ## Mac Retina NVidia failures / flakes ##
diff --git a/device/fido/large_blob.cc b/device/fido/large_blob.cc
index ea317d6..4fb564a 100644
--- a/device/fido/large_blob.cc
+++ b/device/fido/large_blob.cc
@@ -53,9 +53,10 @@
          other.original_size == original_size;
 }
 
-LargeBlobArrayFragment::LargeBlobArrayFragment(const std::vector<uint8_t> bytes,
-                                               const size_t offset)
+LargeBlobArrayFragment::LargeBlobArrayFragment(std::vector<uint8_t> bytes,
+                                               size_t offset)
     : bytes(std::move(bytes)), offset(offset) {}
+
 LargeBlobArrayFragment::~LargeBlobArrayFragment() = default;
 LargeBlobArrayFragment::LargeBlobArrayFragment(LargeBlobArrayFragment&&) =
     default;
diff --git a/device/fido/large_blob.h b/device/fido/large_blob.h
index b7fe81a..0a200b2 100644
--- a/device/fido/large_blob.h
+++ b/device/fido/large_blob.h
@@ -69,8 +69,9 @@
   LargeBlobArrayFragment(const LargeBlobArrayFragment&) = delete;
   LargeBlobArrayFragment& operator=(const LargeBlobArrayFragment&) = delete;
   LargeBlobArrayFragment(LargeBlobArrayFragment&&);
-  const std::vector<uint8_t> bytes;
-  const size_t offset;
+
+  std::vector<uint8_t> bytes;
+  size_t offset;
 };
 
 COMPONENT_EXPORT(DEVICE_FIDO)
diff --git a/device/fido/virtual_ctap2_device.cc b/device/fido/virtual_ctap2_device.cc
index 516b5b5..726d43d 100644
--- a/device/fido/virtual_ctap2_device.cc
+++ b/device/fido/virtual_ctap2_device.cc
@@ -160,7 +160,7 @@
 }
 
 std::vector<uint8_t> ConstructMakeCredentialResponse(
-    const std::optional<std::vector<uint8_t>> attestation_certificate,
+    std::optional<std::vector<uint8_t>> attestation_certificate,
     base::span<const uint8_t> signature,
     AuthenticatorData authenticator_data,
     bool enterprise_attestation_requested,
diff --git a/docs/gardener.md b/docs/gardener.md
index 813358e..31279f86 100644
--- a/docs/gardener.md
+++ b/docs/gardener.md
@@ -25,15 +25,18 @@
 
 TBRs were removed in Q1 2021.
 
-For more information on Chromium Trunk Gardeners, including How Tos, Swapping
-Shifts and rotation updates, please see [Chromium Trunk Gardening](https://goto.google.com/chrome-trunk-gardening)
+There are a number of different gardening rotations. For more information on
+gardening, including How Tos, Swapping Shifts and rotation updates, please see
+[Chromium Trunk Gardening](https://goto.google.com/chrome-gardening)
+(Google-internal link).
 
 ## How to be a Gardener
 
 To be a gardener, you must be both a Chromium committer and a Google employee.
 For more detailed gardening instructions, please see the internal documentation
 at
-[go/chrome-gardening-how-to](https://goto.google.com/chrome-gardening-how-to).
+[go/chrome-gardening-how-to](https://goto.google.com/chrome-gardening-how-to)
+(Google-internal link).
 
 ## Contacting the Gardeners
 
diff --git a/docs/windows_build_instructions.md b/docs/windows_build_instructions.md
index 66ed336f..eba49561 100644
--- a/docs/windows_build_instructions.md
+++ b/docs/windows_build_instructions.md
@@ -76,7 +76,7 @@
 For more information on Git for Windows (which is a separate project from Git),
 see https://gitforwindows.org.
 
-Note: if you are a Google employee, see [these instructions](#instructions-for-google-employees).
+Note: if you are a Google employee, see [go/building-chrome-win#install-git](https://goto.google.com/building-chrome-win#install-git).
 
 ### Update git
 
diff --git a/ios/chrome/app/spotlight/bookmark_spotlight_manager_unittest.mm b/ios/chrome/app/spotlight/bookmark_spotlight_manager_unittest.mm
index 038cd4a..a781b8c 100644
--- a/ios/chrome/app/spotlight/bookmark_spotlight_manager_unittest.mm
+++ b/ios/chrome/app/spotlight/bookmark_spotlight_manager_unittest.mm
@@ -153,8 +153,8 @@
   NSMutableArray* folderNames = [manager parentFolderNamesForNode:eNode];
 
   EXPECT_EQ([folderNames count], 2u);
-  EXPECT_TRUE([[folderNames objectAtIndex:0] isEqualToString:@"2"]);
-  EXPECT_TRUE([[folderNames objectAtIndex:1] isEqualToString:@"21"]);
+  EXPECT_NSEQ([folderNames objectAtIndex:0], @"2");
+  EXPECT_NSEQ([folderNames objectAtIndex:1], @"21");
 
   [manager shutdown];
 }
diff --git a/ios/chrome/browser/DEPS b/ios/chrome/browser/DEPS
index 29368ff..a41a3b4f 100644
--- a/ios/chrome/browser/DEPS
+++ b/ios/chrome/browser/DEPS
@@ -117,6 +117,7 @@
   "+components/sync_user_events",
   "+components/tab_groups",
   "+components/translate",
+  "+components/language_detection/core/browser",
   "+components/ui_metrics",
   "+components/ukm",
   "+components/undo",
diff --git a/ios/chrome/browser/autofill/ui_bundled/manual_fill/BUILD.gn b/ios/chrome/browser/autofill/ui_bundled/manual_fill/BUILD.gn
index 26bf19e..6d09b5ca 100644
--- a/ios/chrome/browser/autofill/ui_bundled/manual_fill/BUILD.gn
+++ b/ios/chrome/browser/autofill/ui_bundled/manual_fill/BUILD.gn
@@ -199,6 +199,8 @@
 source_set("unit_tests") {
   testonly = true
   sources = [
+    "address_view_controller_unittest.mm",
+    "card_view_controller_unittest.mm",
     "chip_button_unittest.mm",
     "expanded_manual_fill_view_controller_unittest.mm",
     "fallback_view_controller_unittest.mm",
@@ -214,6 +216,7 @@
     "manual_fill_credit_card_unittest.mm",
     "manual_fill_labeled_chip_unittest.mm",
     "manual_fill_password_mediator_unittest.mm",
+    "password_view_controller_unittest.mm",
   ]
   deps = [
     ":manual_fill",
@@ -250,6 +253,7 @@
     "//ios/chrome/browser/shared/model/web_state_list/test:test_support",
     "//ios/chrome/browser/shared/public/commands",
     "//ios/chrome/browser/shared/public/features",
+    "//ios/chrome/browser/shared/ui/list_model",
     "//ios/chrome/browser/shared/ui/symbols",
     "//ios/chrome/browser/shared/ui/table_view:test_support",
     "//ios/chrome/browser/sync/model",
diff --git a/ios/chrome/browser/autofill/ui_bundled/manual_fill/address_view_controller.mm b/ios/chrome/browser/autofill/ui_bundled/manual_fill/address_view_controller.mm
index a6bf939..d7c75e6 100644
--- a/ios/chrome/browser/autofill/ui_bundled/manual_fill/address_view_controller.mm
+++ b/ios/chrome/browser/autofill/ui_bundled/manual_fill/address_view_controller.mm
@@ -75,6 +75,7 @@
   UMA_HISTOGRAM_COUNTS_100("ManualFallback.PresentedOptions.Profiles",
                            addresses.count);
 
+  self.noRegularDataItemsToShowHeaderItem = nil;
   if (!addresses.count && IsKeyboardAccessoryUpgradeEnabled()) {
     TableViewTextHeaderFooterItem* textHeaderFooterItem =
         [[TableViewTextHeaderFooterItem alloc]
@@ -82,7 +83,7 @@
                              kNoAddressesMessage];
     textHeaderFooterItem.text =
         l10n_util::GetNSString(IDS_IOS_MANUAL_FALLBACK_NO_ADDRESSES);
-    self.noDataItemsToShowHeaderItem = textHeaderFooterItem;
+    self.noRegularDataItemsToShowHeaderItem = textHeaderFooterItem;
   }
 
   if (base::FeatureList::IsEnabled(
diff --git a/ios/chrome/browser/autofill/ui_bundled/manual_fill/address_view_controller_unittest.mm b/ios/chrome/browser/autofill/ui_bundled/manual_fill/address_view_controller_unittest.mm
new file mode 100644
index 0000000..c70d4d3c
--- /dev/null
+++ b/ios/chrome/browser/autofill/ui_bundled/manual_fill/address_view_controller_unittest.mm
@@ -0,0 +1,159 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/autofill/ui_bundled/manual_fill/address_view_controller.h"
+
+#import "base/apple/foundation_util.h"
+#import "base/test/scoped_feature_list.h"
+#import "base/test/with_feature_override.h"
+#import "components/plus_addresses/features.h"
+#import "ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_action_cell.h"
+#import "ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_address_cell.h"
+#import "ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_plus_address_cell.h"
+#import "ios/chrome/browser/shared/public/features/features.h"
+#import "ios/chrome/browser/shared/ui/list_model/list_item+Controller.h"
+#import "ios/chrome/browser/shared/ui/table_view/legacy_chrome_table_view_controller_test.h"
+#import "ui/base/device_form_factor.h"
+
+namespace {
+
+enum ItemType : NSInteger {
+  kItemTypeSampleOne = kItemTypeEnumZero,
+  kItemTypeSampleTwo,
+  kItemTypeSampleThree
+};
+
+}  // namespace
+
+class AddressViewControllerTest : public LegacyChromeTableViewControllerTest,
+                                  public base::test::WithFeatureOverride {
+ public:
+  AddressViewControllerTest()
+      : base::test::WithFeatureOverride(
+            plus_addresses::features::kPlusAddressIOSManualFallbackEnabled) {}
+
+ protected:
+  void SetUp() override {
+    LegacyChromeTableViewControllerTest::SetUp();
+    CreateController();
+    CheckController();
+  }
+
+  LegacyChromeTableViewController* InstantiateController() override {
+    AddressViewController* view_controller =
+        [[AddressViewController alloc] init];
+    [view_controller loadModel];
+    return view_controller;
+  }
+
+  // Returns the header item at `section`.
+  id GetHeaderItem(int section) {
+    return [controller().tableViewModel headerForSectionIndex:section];
+  }
+
+  // Returns the type of the table view item at `item` in `section`.
+  NSInteger GetTableViewItemType(int section, int item) {
+    return base::apple::ObjCCastStrict<TableViewItem>(
+               GetTableViewItem(section, item))
+        .type;
+  }
+};
+
+// Tests the following:
+// 1. "No address items present" message is shown alongside the action items if
+// there are no data items.
+// 2. "No address items present" message is shown irrespective of the plus
+// address items.
+// 3. "No address items present" message is removed once there are address items
+// to be shown in the view.
+TEST_P(AddressViewControllerTest, CheckNoDataItemsMessageRemoved) {
+  if (ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_TABLET) {
+    // TODO(crbug.com/327838014): Fails on iPad.
+    return;
+  }
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(kIOSKeyboardAccessoryUpgrade);
+
+  AddressViewController* address_view_controller =
+      base::apple::ObjCCastStrict<AddressViewController>(controller());
+
+  ManualFillActionItem* action_item =
+      [[ManualFillActionItem alloc] initWithTitle:nil action:nil];
+  action_item.type = kItemTypeSampleOne;
+
+  // First, send no data items so that the "no address items to show" message is
+  // displayed.
+  [address_view_controller presentAddresses:@[]];
+  [address_view_controller presentActions:@[ action_item ]];
+
+  BOOL plusAddressEnabled = base::FeatureList::IsEnabled(
+      plus_addresses::features::kPlusAddressIOSManualFallbackEnabled);
+
+  if (plusAddressEnabled) {
+    [address_view_controller presentPlusAddresses:@[]];
+  }
+
+  // Make sure that the table view content is as expected.
+  EXPECT_EQ(NumberOfSections(), 2);
+  EXPECT_TRUE(GetHeaderItem(/*section=*/0));
+  EXPECT_EQ(NumberOfItemsInSection(0), 0);
+  EXPECT_EQ(NumberOfItemsInSection(1), 1);
+  EXPECT_EQ(GetTableViewItemType(/*section=*/1, /*item=*/0),
+            kItemTypeSampleOne);
+
+  // Add a plus address item to the view.
+  if (plusAddressEnabled) {
+    ManualFillPlusAddressItem* item =
+        [[ManualFillPlusAddressItem alloc] initWithPlusAddress:nil
+                                               contentInjector:nil
+                                                   menuActions:@[]
+                                   cellIndexAccessibilityLabel:nil];
+    [address_view_controller presentPlusAddresses:@[ item ]];
+    // Override the type for the test.
+    item.type = kItemTypeSampleTwo;
+
+    // Ensure that the "no addres items to show" message is presented.
+    EXPECT_EQ(NumberOfSections(), 3);
+    EXPECT_TRUE(GetHeaderItem(/*section=*/1));
+    EXPECT_EQ(NumberOfItemsInSection(0), 1);
+    EXPECT_EQ(NumberOfItemsInSection(1), 0);
+    EXPECT_EQ(NumberOfItemsInSection(2), 1);
+    EXPECT_EQ(GetTableViewItemType(/*section=*/0, /*item=*/0),
+              kItemTypeSampleTwo);
+    EXPECT_EQ(GetTableViewItemType(/*section=*/2, /*item=*/0),
+              kItemTypeSampleOne);
+  }
+
+  // Add an address data item.
+  ManualFillAddressItem* addressItem =
+      [[ManualFillAddressItem alloc] initWithAddress:nil
+                                     contentInjector:nil
+                                         menuActions:@[]
+                                           cellIndex:0
+                         cellIndexAccessibilityLabel:nil
+                              showAutofillFormButton:NO];
+  [address_view_controller presentAddresses:@[ addressItem ]];
+  // Override the type for the test.
+  addressItem.type = kItemTypeSampleThree;
+
+  // Check that the "no address present" message is removed.
+  EXPECT_EQ(NumberOfSections(), plusAddressEnabled ? 3 : 2);
+  EXPECT_FALSE(GetHeaderItem(/*section=*/0));
+  EXPECT_FALSE(GetHeaderItem(/*section=*/1));
+  EXPECT_EQ(NumberOfItemsInSection(0), 1);
+  EXPECT_EQ(NumberOfItemsInSection(1), 1);
+  if (plusAddressEnabled) {
+    EXPECT_EQ(NumberOfItemsInSection(2), 1);
+    EXPECT_EQ(GetTableViewItemType(/*section=*/0, /*item=*/0),
+              kItemTypeSampleTwo);
+  }
+  EXPECT_EQ(
+      GetTableViewItemType(/*section=*/plusAddressEnabled ? 2 : 1, /*item=*/0),
+      kItemTypeSampleOne);
+  EXPECT_EQ(
+      GetTableViewItemType(/*section=*/plusAddressEnabled ? 1 : 0, /*item=*/0),
+      kItemTypeSampleThree);
+}
+
+INSTANTIATE_FEATURE_OVERRIDE_TEST_SUITE(AddressViewControllerTest);
diff --git a/ios/chrome/browser/autofill/ui_bundled/manual_fill/card_view_controller.mm b/ios/chrome/browser/autofill/ui_bundled/manual_fill/card_view_controller.mm
index 0fd3d74..2b29d45b4 100644
--- a/ios/chrome/browser/autofill/ui_bundled/manual_fill/card_view_controller.mm
+++ b/ios/chrome/browser/autofill/ui_bundled/manual_fill/card_view_controller.mm
@@ -38,13 +38,14 @@
   UMA_HISTOGRAM_COUNTS_100("ManualFallback.PresentedOptions.CreditCards",
                            cards.count);
 
+  self.noRegularDataItemsToShowHeaderItem = nil;
   if (!cards.count && IsKeyboardAccessoryUpgradeEnabled()) {
     TableViewTextHeaderFooterItem* textHeaderFooterItem =
         [[TableViewTextHeaderFooterItem alloc]
             initWithType:manual_fill::ManualFallbackItemType::kNoCardsMessage];
     textHeaderFooterItem.text =
         l10n_util::GetNSString(IDS_IOS_MANUAL_FALLBACK_NO_PAYMENT_METHODS);
-    self.noDataItemsToShowHeaderItem = textHeaderFooterItem;
+    self.noRegularDataItemsToShowHeaderItem = textHeaderFooterItem;
   }
 
   [self presentDataItems:(NSArray<TableViewItem*>*)cards];
diff --git a/ios/chrome/browser/autofill/ui_bundled/manual_fill/card_view_controller_unittest.mm b/ios/chrome/browser/autofill/ui_bundled/manual_fill/card_view_controller_unittest.mm
new file mode 100644
index 0000000..05bdf90
--- /dev/null
+++ b/ios/chrome/browser/autofill/ui_bundled/manual_fill/card_view_controller_unittest.mm
@@ -0,0 +1,109 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/autofill/ui_bundled/manual_fill/card_view_controller.h"
+
+#import "base/apple/foundation_util.h"
+#import "base/test/scoped_feature_list.h"
+#import "ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_action_cell.h"
+#import "ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_card_cell.h"
+#import "ios/chrome/browser/shared/public/features/features.h"
+#import "ios/chrome/browser/shared/ui/list_model/list_item+Controller.h"
+#import "ios/chrome/browser/shared/ui/table_view/legacy_chrome_table_view_controller_test.h"
+#import "ui/base/device_form_factor.h"
+
+namespace {
+
+enum ItemType : NSInteger {
+  kItemTypeSampleOne = kItemTypeEnumZero,
+  kItemTypeSampleTwo,
+};
+
+}  // namespace
+
+class CardViewControllerTest : public LegacyChromeTableViewControllerTest {
+ protected:
+  void SetUp() override {
+    LegacyChromeTableViewControllerTest::SetUp();
+    CreateController();
+    CheckController();
+  }
+
+  LegacyChromeTableViewController* InstantiateController() override {
+    CardViewController* view_controller = [[CardViewController alloc] init];
+    [view_controller loadModel];
+    return view_controller;
+  }
+
+  // Returns the header item at `section`.
+  id GetHeaderItem(int section) {
+    return [controller().tableViewModel headerForSectionIndex:section];
+  }
+
+  // Returns the type of the table view item at `item` in `section`.
+  NSInteger GetTableViewItemType(int section, int item) {
+    return base::apple::ObjCCastStrict<TableViewItem>(
+               GetTableViewItem(section, item))
+        .type;
+  }
+};
+
+// Tests the following:
+// 1. "No card items present" message is shown alongside the action items if
+// there are no data items.
+// 2. "No card items present" message is removed once there are card items to be
+// shown in the view.
+TEST_F(CardViewControllerTest, CheckNoDataItemsMessageRemoved) {
+  if (ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_TABLET) {
+    // TODO(crbug.com/327838014): Fails on iPad.
+    return;
+  }
+
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(kIOSKeyboardAccessoryUpgrade);
+
+  CardViewController* card_view_controller =
+      base::apple::ObjCCastStrict<CardViewController>(controller());
+
+  ManualFillActionItem* action_item =
+      [[ManualFillActionItem alloc] initWithTitle:nil action:nil];
+  action_item.type = kItemTypeSampleOne;
+
+  // First, send no data items so that the "no card items to show" message is
+  // displayed.
+  [card_view_controller presentCards:@[]];
+  [card_view_controller presentActions:@[ action_item ]];
+
+  // Make sure that the table view content is as expected.
+  EXPECT_EQ(NumberOfSections(), 2);
+  EXPECT_TRUE(GetHeaderItem(/*section=*/0));
+  EXPECT_EQ(NumberOfItemsInSection(0), 0);
+  EXPECT_EQ(NumberOfItemsInSection(1), 1);
+  EXPECT_EQ(GetTableViewItemType(/*section=*/1, /*item=*/0),
+            kItemTypeSampleOne);
+
+  // Add an card data item.
+  ManualFillCardItem* cardItem =
+      [[ManualFillCardItem alloc] initWithCreditCard:nil
+                                     contentInjector:nil
+                                  navigationDelegate:nil
+                                         menuActions:@[]
+                                           cellIndex:0
+                         cellIndexAccessibilityLabel:nil
+                              showAutofillFormButton:NO];
+  [card_view_controller presentCards:@[ cardItem ]];
+  // Override the type for the test.
+  cardItem.type = kItemTypeSampleTwo;
+
+  // Check that the "no card item present" message is removed.
+  EXPECT_EQ(NumberOfSections(), 2);
+  EXPECT_FALSE(GetHeaderItem(/*section=*/0));
+  EXPECT_FALSE(GetHeaderItem(/*section=*/1));
+  EXPECT_EQ(NumberOfItemsInSection(0), 1);
+  EXPECT_EQ(NumberOfItemsInSection(1), 1);
+  EXPECT_EQ(GetTableViewItemType(/*section=*/0, /*item=*/0),
+            kItemTypeSampleTwo);
+  EXPECT_EQ(GetTableViewItemType(/*section=*/1, /*item=*/0),
+            kItemTypeSampleOne);
+}
diff --git a/ios/chrome/browser/autofill/ui_bundled/manual_fill/fallback_view_controller.h b/ios/chrome/browser/autofill/ui_bundled/manual_fill/fallback_view_controller.h
index 334399b..743c8c0a 100644
--- a/ios/chrome/browser/autofill/ui_bundled/manual_fill/fallback_view_controller.h
+++ b/ios/chrome/browser/autofill/ui_bundled/manual_fill/fallback_view_controller.h
@@ -19,9 +19,11 @@
 // Data source for images.
 @property(nonatomic, weak) id<TableViewFaviconDataSource> imageDataSource;
 
-// Header item displayed when there are no data items to show.
+// Header item displayed when there are no data items to show amongst passwords,
+// cards and addresses and independent of plus address. Needs to be explicitly
+// set to `nil` if should not be shown.
 @property(nonatomic, strong)
-    TableViewTextHeaderFooterItem* noDataItemsToShowHeaderItem;
+    TableViewTextHeaderFooterItem* noRegularDataItemsToShowHeaderItem;
 
 - (instancetype)init NS_DESIGNATED_INITIALIZER;
 
diff --git a/ios/chrome/browser/autofill/ui_bundled/manual_fill/fallback_view_controller.mm b/ios/chrome/browser/autofill/ui_bundled/manual_fill/fallback_view_controller.mm
index 724f3a8..755b0d32 100644
--- a/ios/chrome/browser/autofill/ui_bundled/manual_fill/fallback_view_controller.mm
+++ b/ios/chrome/browser/autofill/ui_bundled/manual_fill/fallback_view_controller.mm
@@ -190,7 +190,7 @@
 
 - (CGFloat)tableView:(UITableView*)tableView
     heightForFooterInSection:(NSInteger)section {
-  if (self.noDataItemsToShowHeaderItem &&
+  if (self.noRegularDataItemsToShowHeaderItem &&
       [self.tableViewModel
           hasSectionForSectionIdentifier:NoDataItemsSectionIdentifier] &&
       section ==
@@ -461,15 +461,16 @@
   }
 }
 
-// Adds or removes the `noDataItemsToShowHeaderItem` if needed. This header item
-// is displayed to let the user know that there are no data items to show.
+// Adds or removes the `noRegularDataItemsToShowHeaderItem` if needed. This
+// header item is displayed to let the user know that there are no data items
+// amongst passwords, cards and addresses to show. However, plus address can
+// still be shown.
 - (void)updateEmptyStateMessage {
   if (!IsKeyboardAccessoryUpgradeEnabled()) {
     return;
   }
 
-  BOOL needsEmptyStateHeader =
-      !self.queuedDataItems.count && self.noDataItemsToShowHeaderItem;
+  BOOL needsEmptyStateHeader = self.noRegularDataItemsToShowHeaderItem;
   BOOL hasEmptyStateSection = [self.tableViewModel
       hasSectionForSectionIdentifier:NoDataItemsSectionIdentifier];
   BOOL hasEmptyStateHeader =
@@ -483,12 +484,12 @@
 
   if (needsEmptyStateHeader) {
     [self.tableViewModel addSectionWithIdentifier:NoDataItemsSectionIdentifier];
-    [self.tableViewModel setHeader:self.noDataItemsToShowHeaderItem
+    [self.tableViewModel setHeader:self.noRegularDataItemsToShowHeaderItem
           forSectionWithIdentifier:NoDataItemsSectionIdentifier];
   } else {
     [self.tableViewModel
         removeSectionWithIdentifier:NoDataItemsSectionIdentifier];
-    self.noDataItemsToShowHeaderItem = nil;
+    self.noRegularDataItemsToShowHeaderItem = nil;
   }
 }
 
diff --git a/ios/chrome/browser/autofill/ui_bundled/manual_fill/fallback_view_controller_unittest.mm b/ios/chrome/browser/autofill/ui_bundled/manual_fill/fallback_view_controller_unittest.mm
index a580613a..a14ce08 100644
--- a/ios/chrome/browser/autofill/ui_bundled/manual_fill/fallback_view_controller_unittest.mm
+++ b/ios/chrome/browser/autofill/ui_bundled/manual_fill/fallback_view_controller_unittest.mm
@@ -162,10 +162,10 @@
 
   NSArray<TableViewItem*>* data_items;
   if (IsKeyboardAccessoryUpgradeEnabled()) {
-    // Set `noDataItemsToShowHeaderItem`.
+    // Set `noRegularDataItemsToShowHeaderItem`.
     TableViewTextHeaderFooterItem* header_item =
         [[TableViewTextHeaderFooterItem alloc] initWithType:ItemTypeSampleOne];
-    fallback_view_controller.noDataItemsToShowHeaderItem = header_item;
+    fallback_view_controller.noRegularDataItemsToShowHeaderItem = header_item;
     data_items = @[];
   } else {
     ManualFillTextItem* empty_credential_item =
@@ -227,10 +227,10 @@
   FallbackViewController* fallback_view_controller =
       GetFallbackViewController();
 
-  // Set `noDataItemsToShowHeaderItem`.
+  // Set `noRegularDataItemsToShowHeaderItem`.
   TableViewTextHeaderFooterItem* header_item =
       [[TableViewTextHeaderFooterItem alloc] initWithType:ItemTypeSampleOne];
-  fallback_view_controller.noDataItemsToShowHeaderItem = header_item;
+  fallback_view_controller.noRegularDataItemsToShowHeaderItem = header_item;
 
   [fallback_view_controller presentDataItems:@[]];
   [fallback_view_controller presentActionItems:@[]];
@@ -245,61 +245,6 @@
   EXPECT_EQ(GetHeaderItemType(/*section=*/0), ItemTypeSampleOne);
 }
 
-// Tests that the "no data items to show" message is removed once there are data
-// items to show.
-TEST_P(FallbackViewControllerTest, CheckNoDataItemsMessageRemoved) {
-  // This test is only relevant when the Keyboard Accessory Upgrade feature is
-  // enabled.
-  if (!IsKeyboardAccessoryUpgradeEnabled()) {
-    return;
-  }
-
-  FallbackViewController* fallback_view_controller =
-      GetFallbackViewController();
-
-  // Set `noDataItemsToShowHeaderItem`.
-  TableViewTextHeaderFooterItem* header_item =
-      [[TableViewTextHeaderFooterItem alloc] initWithType:ItemTypeSampleOne];
-  fallback_view_controller.noDataItemsToShowHeaderItem = header_item;
-
-  TableViewItem* action_item =
-      [[TableViewItem alloc] initWithType:ItemTypeSampleTwo];
-
-  // First, send no data items so that the "no data items to show" message is
-  // displayed.
-  [fallback_view_controller presentDataItems:@[]];
-  [fallback_view_controller presentActionItems:@[ action_item ]];
-
-  // Make sure that the table view content is as expected.
-  EXPECT_EQ(NumberOfSections(), IsKeyboardAccessoryUpgradeEnabled() ? 2 : 1);
-  EXPECT_TRUE(GetHeaderItem(/*section=*/0));
-  EXPECT_EQ(NumberOfItemsInSection(0), !IsKeyboardAccessoryUpgradeEnabled());
-  if (IsKeyboardAccessoryUpgradeEnabled()) {
-    EXPECT_EQ(NumberOfItemsInSection(1), 1);
-  }
-  EXPECT_EQ(GetHeaderItemType(/*section=*/0), ItemTypeSampleOne);
-  EXPECT_EQ(GetTableViewItemType(
-                /*section=*/IsKeyboardAccessoryUpgradeEnabled(), /*item=*/0),
-            ItemTypeSampleTwo);
-
-  // Second, add a data item. This should have the effect of removing the "no
-  // data items to show" message.
-  TableViewItem* data_item =
-      [[TableViewItem alloc] initWithType:ItemTypeSampleThree];
-  [fallback_view_controller presentDataItems:@[ data_item ]];
-
-  // There should now be two sections with one item each.
-  EXPECT_EQ(NumberOfSections(), 2);
-  EXPECT_EQ(NumberOfItemsInSection(0), 1);
-  EXPECT_EQ(NumberOfItemsInSection(1), 1);
-  EXPECT_EQ(GetTableViewItemType(/*section=*/0, /*item=*/0),
-            ItemTypeSampleThree);
-  EXPECT_EQ(GetTableViewItemType(/*section=*/1, /*item=*/0), ItemTypeSampleTwo);
-
-  // The "no data items to show" message shouldn't be present anymore.
-  EXPECT_FALSE(GetHeaderItem(/*section=*/1));
-}
-
 // Tests that the actions are separated by sections if they belong to different
 // types.
 TEST_P(FallbackViewControllerTest,
diff --git a/ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_labeled_chip_unittest.mm b/ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_labeled_chip_unittest.mm
index 71d72b7..4533f71 100644
--- a/ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_labeled_chip_unittest.mm
+++ b/ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_labeled_chip_unittest.mm
@@ -6,6 +6,7 @@
 
 #import "ios/chrome/browser/autofill/ui_bundled/manual_fill/chip_button.h"
 #import "ios/chrome/browser/shared/public/features/features.h"
+#import "testing/gtest_mac.h"
 #import "testing/platform_test.h"
 
 using ManualFillLabeledChipiOSTest = PlatformTest;
@@ -86,8 +87,7 @@
 
   // Confirm the label has the correct text.
   NSArray<UIView*>* chipSubviews = labeledChip.arrangedSubviews;
-  EXPECT_TRUE([((UILabel*)chipSubviews[TOP_LABEL_INDEX]).text
-      isEqualToString:TOP_LABEL_TEXT]);
+  EXPECT_NSEQ(((UILabel*)chipSubviews[TOP_LABEL_INDEX]).text, TOP_LABEL_TEXT);
 
   // Confirm the button has the correct text.
   EXPECT_EQ(ButtonTitle((UIButton*)chipSubviews[BOTTOM_BUTTONS_INDEX]),
@@ -107,8 +107,7 @@
 
   // Confirm the top label has the correct text.
   NSArray<UIView*>* chipSubviews = labeledChip.arrangedSubviews;
-  EXPECT_TRUE([((UILabel*)chipSubviews[TOP_LABEL_INDEX]).text
-      isEqualToString:TOP_LABEL_TEXT]);
+  EXPECT_NSEQ(((UILabel*)chipSubviews[TOP_LABEL_INDEX]).text, TOP_LABEL_TEXT);
 
   // Confirm the bottom button, label and other button have the correct text.
   NSArray<UIView*>* buttonStackViewSubviews =
@@ -136,8 +135,7 @@
 
   // Confirm the label has the correct text.
   NSArray<UIView*>* chipSubviews = labeledChip.arrangedSubviews;
-  EXPECT_TRUE(
-      [((UILabel*)chipSubviews[TOP_LABEL_INDEX]).text isEqualToString:@""]);
+  EXPECT_NSEQ(((UILabel*)chipSubviews[TOP_LABEL_INDEX]).text, @"");
 
   // Confirm the button has the correct text.
   EXPECT_EQ(ButtonTitle((UIButton*)chipSubviews[BOTTOM_BUTTONS_INDEX]), @"");
@@ -159,8 +157,7 @@
 
   // Confirm the top label has the correct text.
   NSArray<UIView*>* chipSubviews = labeledChip.arrangedSubviews;
-  EXPECT_TRUE(
-      [((UILabel*)chipSubviews[TOP_LABEL_INDEX]).text isEqualToString:@""]);
+  EXPECT_NSEQ(((UILabel*)chipSubviews[TOP_LABEL_INDEX]).text, @"");
 
   // Confirm the bottom button, label and other button have the correct text.
   NSArray<UIView*>* buttonStackViewSubviews =
diff --git a/ios/chrome/browser/autofill/ui_bundled/manual_fill/password_view_controller.mm b/ios/chrome/browser/autofill/ui_bundled/manual_fill/password_view_controller.mm
index eabb85bc..7fb6bd59 100644
--- a/ios/chrome/browser/autofill/ui_bundled/manual_fill/password_view_controller.mm
+++ b/ios/chrome/browser/autofill/ui_bundled/manual_fill/password_view_controller.mm
@@ -153,6 +153,8 @@
                              credentials.count);
   }
 
+  self.noRegularDataItemsToShowHeaderItem = nil;
+
   for (ManualFillCredentialItem* credentialItem in credentials) {
     credentialItem.type = manual_fill::ManualFallbackItemType::kCredential;
   }
@@ -167,7 +169,7 @@
                                kNoCredentialsMessage];
       textHeaderFooterItem.text =
           l10n_util::GetNSString(IDS_IOS_MANUAL_FALLBACK_NO_PASSWORDS_FOR_SITE);
-      self.noDataItemsToShowHeaderItem = textHeaderFooterItem;
+      self.noRegularDataItemsToShowHeaderItem = textHeaderFooterItem;
     } else {
       ManualFillTextItem* emptyCredentialItem = [[ManualFillTextItem alloc]
           initWithType:manual_fill::ManualFallbackItemType::
diff --git a/ios/chrome/browser/autofill/ui_bundled/manual_fill/password_view_controller_unittest.mm b/ios/chrome/browser/autofill/ui_bundled/manual_fill/password_view_controller_unittest.mm
new file mode 100644
index 0000000..d1d778bb
--- /dev/null
+++ b/ios/chrome/browser/autofill/ui_bundled/manual_fill/password_view_controller_unittest.mm
@@ -0,0 +1,162 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/autofill/ui_bundled/manual_fill/password_view_controller.h"
+
+#import "base/apple/foundation_util.h"
+#import "base/test/scoped_feature_list.h"
+#import "base/test/with_feature_override.h"
+#import "components/plus_addresses/features.h"
+#import "ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_action_cell.h"
+#import "ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_password_cell.h"
+#import "ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_plus_address_cell.h"
+#import "ios/chrome/browser/shared/public/features/features.h"
+#import "ios/chrome/browser/shared/ui/list_model/list_item+Controller.h"
+#import "ios/chrome/browser/shared/ui/table_view/legacy_chrome_table_view_controller_test.h"
+#import "ui/base/device_form_factor.h"
+
+namespace {
+
+enum ItemType : NSInteger {
+  kItemTypeSampleOne = kItemTypeEnumZero,
+  kItemTypeSampleTwo,
+  kItemTypeSampleThree
+};
+
+}  // namespace
+
+class PasswordViewControllerTest : public LegacyChromeTableViewControllerTest,
+                                   public base::test::WithFeatureOverride {
+ public:
+  PasswordViewControllerTest()
+      : base::test::WithFeatureOverride(
+            plus_addresses::features::kPlusAddressIOSManualFallbackEnabled) {}
+
+ protected:
+  void SetUp() override {
+    LegacyChromeTableViewControllerTest::SetUp();
+    CreateController();
+    CheckController();
+  }
+
+  LegacyChromeTableViewController* InstantiateController() override {
+    PasswordViewController* view_controller =
+        [[PasswordViewController alloc] initWithSearchController:nil];
+    [view_controller loadModel];
+    return view_controller;
+  }
+
+  // Returns the header item at `section`.
+  id GetHeaderItem(int section) {
+    return [controller().tableViewModel headerForSectionIndex:section];
+  }
+
+  // Returns the type of the table view item at `item` in `section`.
+  NSInteger GetTableViewItemType(int section, int item) {
+    return base::apple::ObjCCastStrict<TableViewItem>(
+               GetTableViewItem(section, item))
+        .type;
+  }
+};
+
+// Tests the following:
+// 1. "No password items present" message is shown alongside the action items if
+// there are no data items.
+// 2. "No password items present" message is shown irrespective of the plus
+// address items.
+// 3. "No password items present" message is removed once there are password
+// items to be shown in the view.
+TEST_P(PasswordViewControllerTest, CheckNoDataItemsMessageRemoved) {
+  if (ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_TABLET) {
+    // TODO(crbug.com/327838014): Fails on iPad.
+    return;
+  }
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(kIOSKeyboardAccessoryUpgrade);
+
+  PasswordViewController* password_view_controller =
+      base::apple::ObjCCastStrict<PasswordViewController>(controller());
+
+  ManualFillActionItem* action_item =
+      [[ManualFillActionItem alloc] initWithTitle:nil action:nil];
+  action_item.type = kItemTypeSampleOne;
+
+  // First, send no data items so that the "no password items to show" message
+  // is displayed.
+  [password_view_controller presentCredentials:@[]];
+  [password_view_controller presentActions:@[ action_item ]];
+
+  BOOL plusAddressEnabled = base::FeatureList::IsEnabled(
+      plus_addresses::features::kPlusAddressIOSManualFallbackEnabled);
+
+  if (plusAddressEnabled) {
+    [password_view_controller presentPlusAddresses:@[]];
+  }
+
+  // Make sure that the table view content is as expected.
+  EXPECT_EQ(NumberOfSections(), 2);
+  EXPECT_TRUE(GetHeaderItem(/*section=*/0));
+  EXPECT_EQ(NumberOfItemsInSection(0), 0);
+  EXPECT_EQ(NumberOfItemsInSection(1), 1);
+  EXPECT_EQ(GetTableViewItemType(/*section=*/1, /*item=*/0),
+            kItemTypeSampleOne);
+
+  // Add a plus address item to the view.
+  if (plusAddressEnabled) {
+    ManualFillPlusAddressItem* item =
+        [[ManualFillPlusAddressItem alloc] initWithPlusAddress:nil
+                                               contentInjector:nil
+                                                   menuActions:@[]
+                                   cellIndexAccessibilityLabel:nil];
+    [password_view_controller presentPlusAddresses:@[ item ]];
+    // Override the type for the test.
+    item.type = kItemTypeSampleTwo;
+
+    // Ensure that the "no password items to show" message is presented.
+    EXPECT_EQ(NumberOfSections(), 3);
+    EXPECT_TRUE(GetHeaderItem(/*section=*/1));
+    EXPECT_EQ(NumberOfItemsInSection(0), 1);
+    EXPECT_EQ(NumberOfItemsInSection(1), 0);
+    EXPECT_EQ(NumberOfItemsInSection(2), 1);
+    EXPECT_EQ(GetTableViewItemType(/*section=*/0, /*item=*/0),
+              kItemTypeSampleTwo);
+    EXPECT_EQ(GetTableViewItemType(/*section=*/2, /*item=*/0),
+              kItemTypeSampleOne);
+  }
+
+  // Add an password data item.
+  ManualFillCredentialItem* passwordItem =
+      [[ManualFillCredentialItem alloc] initWithCredential:nil
+                                 isConnectedToPreviousItem:NO
+                                     isConnectedToNextItem:NO
+                                           contentInjector:nil
+                                               menuActions:@[]
+                                                 cellIndex:0
+                               cellIndexAccessibilityLabel:nil
+                                    showAutofillFormButton:NO
+                                   fromAllPasswordsContext:NO];
+  [password_view_controller presentCredentials:@[ passwordItem ]];
+  // Override the type for the test.
+  passwordItem.type = kItemTypeSampleThree;
+
+  // Check that the "no password present" message is removed.
+  EXPECT_EQ(NumberOfSections(), plusAddressEnabled ? 3 : 2);
+  EXPECT_FALSE(GetHeaderItem(/*section=*/0));
+  EXPECT_FALSE(GetHeaderItem(/*section=*/1));
+  EXPECT_EQ(NumberOfItemsInSection(0), 1);
+  EXPECT_EQ(NumberOfItemsInSection(1), 1);
+  if (plusAddressEnabled) {
+    EXPECT_EQ(NumberOfItemsInSection(2), 1);
+    EXPECT_EQ(GetTableViewItemType(/*section=*/0, /*item=*/0),
+              kItemTypeSampleTwo);
+  }
+  EXPECT_EQ(
+      GetTableViewItemType(/*section=*/plusAddressEnabled ? 2 : 1, /*item=*/0),
+      kItemTypeSampleOne);
+  EXPECT_EQ(
+      GetTableViewItemType(/*section=*/plusAddressEnabled ? 1 : 0, /*item=*/0),
+      kItemTypeSampleThree);
+}
+
+INSTANTIATE_FEATURE_OVERRIDE_TEST_SUITE(PasswordViewControllerTest);
diff --git a/ios/chrome/browser/browser_view/ui_bundled/key_commands_provider_unittest.mm b/ios/chrome/browser/browser_view/ui_bundled/key_commands_provider_unittest.mm
index d4bccbd..407fa96 100644
--- a/ios/chrome/browser/browser_view/ui_bundled/key_commands_provider_unittest.mm
+++ b/ios/chrome/browser/browser_view/ui_bundled/key_commands_provider_unittest.mm
@@ -947,14 +947,13 @@
   for (UIKeyCommand* command in provider_.keyCommands) {
     [provider_ validateCommand:command];
     if (command.action == @selector(keyCommand_find)) {
-      EXPECT_TRUE([command.discoverabilityTitle
-          isEqualToString:l10n_util::GetNSStringWithFixup(
-                              IDS_IOS_KEYBOARD_FIND_IN_PAGE)]);
+      EXPECT_NSEQ(
+          command.discoverabilityTitle,
+          l10n_util::GetNSStringWithFixup(IDS_IOS_KEYBOARD_FIND_IN_PAGE));
     }
     if (command.action == @selector(keyCommand_select1)) {
-      EXPECT_TRUE([command.discoverabilityTitle
-          isEqualToString:l10n_util::GetNSStringWithFixup(
-                              IDS_IOS_KEYBOARD_FIRST_TAB)]);
+      EXPECT_NSEQ(command.discoverabilityTitle,
+                  l10n_util::GetNSStringWithFixup(IDS_IOS_KEYBOARD_FIRST_TAB));
     }
   }
 }
diff --git a/ios/chrome/browser/commerce/model/push_notification/commerce_push_notification_client_unittest.mm b/ios/chrome/browser/commerce/model/push_notification/commerce_push_notification_client_unittest.mm
index e9693077..7f3dd83 100644
--- a/ios/chrome/browser/commerce/model/push_notification/commerce_push_notification_client_unittest.mm
+++ b/ios/chrome/browser/commerce/model/push_notification/commerce_push_notification_client_unittest.mm
@@ -44,6 +44,7 @@
 #import "ios/web/public/test/web_task_environment.h"
 #import "testing/gmock/include/gmock/gmock.h"
 #import "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
 #import "testing/platform_test.h"
 
 namespace {
@@ -347,14 +348,11 @@
   EXPECT_EQ(1u, [actionable_notifications count]);
   UNNotificationCategory* notification_category = actionable_notifications[0];
   EXPECT_EQ(2u, [notification_category.actions count]);
-  EXPECT_TRUE([notification_category.actions[0].identifier
-      isEqualToString:kVisitSiteActionId]);
-  EXPECT_TRUE(
-      [notification_category.actions[0].title isEqualToString:kVisitSiteTitle]);
-  EXPECT_TRUE([notification_category.actions[1].identifier
-      isEqualToString:kUntrackPriceActionId]);
-  EXPECT_TRUE([notification_category.actions[1].title
-      isEqualToString:kUntrackPriceTitle]);
+  EXPECT_NSEQ(notification_category.actions[0].identifier, kVisitSiteActionId);
+  EXPECT_NSEQ(notification_category.actions[0].title, kVisitSiteTitle);
+  EXPECT_NSEQ(notification_category.actions[1].identifier,
+              kUntrackPriceActionId);
+  EXPECT_NSEQ(notification_category.actions[1].title, kUntrackPriceTitle);
 }
 
 TEST_F(CommercePushNotificationClientTest, TestUntrackPrice) {
diff --git a/ios/chrome/browser/follow/model/follow_util_unittest.mm b/ios/chrome/browser/follow/model/follow_util_unittest.mm
index fff1a8efb..c4ae56e3 100644
--- a/ios/chrome/browser/follow/model/follow_util_unittest.mm
+++ b/ios/chrome/browser/follow/model/follow_util_unittest.mm
@@ -6,6 +6,7 @@
 
 #import <UIKit/UIKit.h>
 
+#import "testing/gtest_mac.h"
 #import "testing/platform_test.h"
 
 class FollowUtilTest : public PlatformTest {
@@ -77,10 +78,8 @@
   NSArray<NSDictionary*>* updatedArray =
       [defaults objectForKey:kFollowIPHPreviousDisplayEvents];
   EXPECT_EQ(2, (int)updatedArray.count);
-  EXPECT_TRUE([[updatedArray[0] objectForKey:kFollowIPHHost]
-      isEqualToString:@"ghi.com"]);
-  EXPECT_TRUE([[updatedArray[1] objectForKey:kFollowIPHHost]
-      isEqualToString:@"now.com"]);
+  EXPECT_NSEQ([updatedArray[0] objectForKey:kFollowIPHHost], @"ghi.com");
+  EXPECT_NSEQ([updatedArray[1] objectForKey:kFollowIPHHost], @"now.com");
 }
 
 // Tests removing the last follow IPH display event.
@@ -93,8 +92,6 @@
   NSArray<NSDictionary*>* updatedArray =
       [defaults objectForKey:kFollowIPHPreviousDisplayEvents];
   EXPECT_EQ(2, (int)updatedArray.count);
-  EXPECT_TRUE([[updatedArray[0] objectForKey:kFollowIPHHost]
-      isEqualToString:@"abc.com"]);
-  EXPECT_TRUE([[updatedArray[1] objectForKey:kFollowIPHHost]
-      isEqualToString:@"def.com"]);
+  EXPECT_NSEQ([updatedArray[0] objectForKey:kFollowIPHHost], @"abc.com");
+  EXPECT_NSEQ([updatedArray[1] objectForKey:kFollowIPHHost], @"def.com");
 }
diff --git a/ios/chrome/browser/language_detection/model/BUILD.gn b/ios/chrome/browser/language_detection/model/BUILD.gn
new file mode 100644
index 0000000..3ed2c739
--- /dev/null
+++ b/ios/chrome/browser/language_detection/model/BUILD.gn
@@ -0,0 +1,27 @@
+# Copyright 2024 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("model") {
+  sources = [
+    "language_detection_model_loader_service_ios_factory.h",
+    "language_detection_model_loader_service_ios_factory.mm",
+    "language_detection_model_service_factory.h",
+    "language_detection_model_service_factory.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/keyed_service/core",
+    "//components/keyed_service/ios",
+    "//components/language_detection/core/browser:language_detection_model_service",
+    "//components/language_detection/ios/browser",
+    "//components/optimization_guide/core:features",
+    "//components/prefs",
+    "//components/translate/core/common",
+    "//components/translate/core/common",
+    "//ios/chrome/browser/optimization_guide/model",
+    "//ios/chrome/browser/shared/model/browser_state",
+    "//ios/chrome/browser/shared/model/profile",
+    "//ios/chrome/browser/shared/model/profile",
+  ]
+}
diff --git a/ios/chrome/browser/language_detection/model/DEPS b/ios/chrome/browser/language_detection/model/DEPS
new file mode 100644
index 0000000..6930aba
--- /dev/null
+++ b/ios/chrome/browser/language_detection/model/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+  "+components/language_detection/ios/browser",
+  "+ios/chrome/browser/optimization_guide/model",
+]
diff --git a/ios/chrome/browser/language_detection/model/language_detection_model_loader_service_ios_factory.h b/ios/chrome/browser/language_detection/model/language_detection_model_loader_service_ios_factory.h
new file mode 100644
index 0000000..d7f092b7
--- /dev/null
+++ b/ios/chrome/browser/language_detection/model/language_detection_model_loader_service_ios_factory.h
@@ -0,0 +1,48 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_LANGUAGE_DETECTION_MODEL_LANGUAGE_DETECTION_MODEL_LOADER_SERVICE_IOS_FACTORY_H_
+#define IOS_CHROME_BROWSER_LANGUAGE_DETECTION_MODEL_LANGUAGE_DETECTION_MODEL_LOADER_SERVICE_IOS_FACTORY_H_
+
+#import <memory>
+
+#import "base/no_destructor.h"
+#import "components/keyed_service/ios/browser_state_keyed_service_factory.h"
+#import "ios/chrome/browser/shared/model/profile/profile_ios_forward.h"
+
+namespace language_detection {
+class LanguageDetectionModelLoaderServiceIOS;
+}  // namespace language_detection
+
+// This is a workaround for crbug/1324530 on iOS where it is mandatory to have
+// LanguageDetectionModel scoped by BrowserState.
+// TODO(crbug.com/40225076): remove this class once
+// LanguageDetectionModelService does this.
+class LanguageDetectionModelLoaderServiceIOSFactory
+    : public BrowserStateKeyedServiceFactory {
+ public:
+  static language_detection::LanguageDetectionModelLoaderServiceIOS*
+  GetForBrowserState(ChromeBrowserState* browser_state);
+  static LanguageDetectionModelLoaderServiceIOSFactory* GetInstance();
+
+  LanguageDetectionModelLoaderServiceIOSFactory(
+      const LanguageDetectionModelLoaderServiceIOSFactory&) = delete;
+  LanguageDetectionModelLoaderServiceIOSFactory& operator=(
+      const LanguageDetectionModelLoaderServiceIOSFactory&) = delete;
+
+ private:
+  friend class base::NoDestructor<
+      LanguageDetectionModelLoaderServiceIOSFactory>;
+
+  LanguageDetectionModelLoaderServiceIOSFactory();
+  ~LanguageDetectionModelLoaderServiceIOSFactory() override;
+
+  // BrowserStateKeyedServiceFactory implementation.
+  std::unique_ptr<KeyedService> BuildServiceInstanceFor(
+      web::BrowserState* context) const override;
+  web::BrowserState* GetBrowserStateToUse(
+      web::BrowserState* context) const override;
+};
+
+#endif  // IOS_CHROME_BROWSER_LANGUAGE_DETECTION_MODEL_LANGUAGE_DETECTION_MODEL_LOADER_SERVICE_IOS_FACTORY_H_
diff --git a/ios/chrome/browser/language_detection/model/language_detection_model_loader_service_ios_factory.mm b/ios/chrome/browser/language_detection/model/language_detection_model_loader_service_ios_factory.mm
new file mode 100644
index 0000000..5b72947
--- /dev/null
+++ b/ios/chrome/browser/language_detection/model/language_detection_model_loader_service_ios_factory.mm
@@ -0,0 +1,71 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/language_detection/model/language_detection_model_loader_service_ios_factory.h"
+
+#import "base/memory/scoped_refptr.h"
+#import "base/no_destructor.h"
+#import "base/task/sequenced_task_runner.h"
+#import "base/task/task_traits.h"
+#import "base/task/thread_pool.h"
+#import "components/keyed_service/core/keyed_service.h"
+#import "components/keyed_service/ios/browser_state_dependency_manager.h"
+#import "components/language_detection/core/browser/language_detection_model_service.h"
+#import "components/language_detection/ios/browser/language_detection_model_loader_service_ios.h"
+#import "components/translate/core/common/translate_util.h"
+#import "ios/chrome/browser/language_detection/model/language_detection_model_service_factory.h"
+#import "ios/chrome/browser/shared/model/browser_state/browser_state_otr_helper.h"
+#import "ios/chrome/browser/shared/model/profile/profile_ios.h"
+
+// static
+LanguageDetectionModelLoaderServiceIOSFactory*
+LanguageDetectionModelLoaderServiceIOSFactory::GetInstance() {
+  static base::NoDestructor<LanguageDetectionModelLoaderServiceIOSFactory>
+      instance;
+  return instance.get();
+}
+
+// static
+language_detection::LanguageDetectionModelLoaderServiceIOS*
+LanguageDetectionModelLoaderServiceIOSFactory::GetForBrowserState(
+    ChromeBrowserState* state) {
+  return static_cast<
+      language_detection::LanguageDetectionModelLoaderServiceIOS*>(
+      GetInstance()->GetServiceForBrowserState(state, true));
+}
+
+LanguageDetectionModelLoaderServiceIOSFactory::
+    LanguageDetectionModelLoaderServiceIOSFactory()
+    : BrowserStateKeyedServiceFactory(
+          "LanguageDetectionModelLoaderServiceIOS",
+          BrowserStateDependencyManager::GetInstance()) {
+  DependsOn(LanguageDetectionModelServiceFactory::GetInstance());
+}
+
+LanguageDetectionModelLoaderServiceIOSFactory::
+    ~LanguageDetectionModelLoaderServiceIOSFactory() {}
+
+std::unique_ptr<KeyedService>
+LanguageDetectionModelLoaderServiceIOSFactory::BuildServiceInstanceFor(
+    web::BrowserState* context) const {
+  if (!translate::IsTFLiteLanguageDetectionEnabled()) {
+    return nullptr;
+  }
+  ChromeBrowserState* browser_state =
+      ChromeBrowserState::FromBrowserState(context);
+  scoped_refptr<base::SequencedTaskRunner> background_task_runner =
+      base::ThreadPool::CreateSequencedTaskRunner(
+          {base::MayBlock(), base::TaskPriority::BEST_EFFORT});
+  auto* language_detection_model_service =
+      LanguageDetectionModelServiceFactory::GetForBrowserState(browser_state);
+  return std::make_unique<
+      language_detection::LanguageDetectionModelLoaderServiceIOS>(
+      language_detection_model_service, background_task_runner);
+}
+
+web::BrowserState*
+LanguageDetectionModelLoaderServiceIOSFactory::GetBrowserStateToUse(
+    web::BrowserState* context) const {
+  return GetBrowserStateRedirectedInIncognito(context);
+}
diff --git a/ios/chrome/browser/translate/model/language_detection_model_service_factory.h b/ios/chrome/browser/language_detection/model/language_detection_model_service_factory.h
similarity index 67%
rename from ios/chrome/browser/translate/model/language_detection_model_service_factory.h
rename to ios/chrome/browser/language_detection/model/language_detection_model_service_factory.h
index 4282494..0b37d1e48 100644
--- a/ios/chrome/browser/translate/model/language_detection_model_service_factory.h
+++ b/ios/chrome/browser/language_detection/model/language_detection_model_service_factory.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef IOS_CHROME_BROWSER_TRANSLATE_MODEL_LANGUAGE_DETECTION_MODEL_SERVICE_FACTORY_H_
-#define IOS_CHROME_BROWSER_TRANSLATE_MODEL_LANGUAGE_DETECTION_MODEL_SERVICE_FACTORY_H_
+#ifndef IOS_CHROME_BROWSER_LANGUAGE_DETECTION_MODEL_LANGUAGE_DETECTION_MODEL_SERVICE_FACTORY_H_
+#define IOS_CHROME_BROWSER_LANGUAGE_DETECTION_MODEL_LANGUAGE_DETECTION_MODEL_SERVICE_FACTORY_H_
 
 #import <memory>
 
@@ -11,18 +11,14 @@
 #import "components/keyed_service/ios/browser_state_keyed_service_factory.h"
 #import "ios/chrome/browser/shared/model/profile/profile_ios_forward.h"
 
-namespace translate {
+namespace language_detection {
 class LanguageDetectionModelService;
-}  // namespace translate
+}
 
-// This is a workaround for crbug/1324530 on iOS where it is mandatory to have
-// LanguageDetectionModel scoped by BrowserState.
-// TODO(crbug.com/40225076): remove this class once TranslateModelService does
-// this.
 class LanguageDetectionModelServiceFactory
     : public BrowserStateKeyedServiceFactory {
  public:
-  static translate::LanguageDetectionModelService* GetForBrowserState(
+  static language_detection::LanguageDetectionModelService* GetForBrowserState(
       ChromeBrowserState* browser_state);
   static LanguageDetectionModelServiceFactory* GetInstance();
 
@@ -44,4 +40,4 @@
       web::BrowserState* context) const override;
 };
 
-#endif  // IOS_CHROME_BROWSER_TRANSLATE_MODEL_LANGUAGE_DETECTION_MODEL_SERVICE_FACTORY_H_
+#endif  // IOS_CHROME_BROWSER_LANGUAGE_DETECTION_MODEL_LANGUAGE_DETECTION_MODEL_SERVICE_FACTORY_H_
diff --git a/ios/chrome/browser/translate/model/translate_model_service_factory.mm b/ios/chrome/browser/language_detection/model/language_detection_model_service_factory.mm
similarity index 67%
rename from ios/chrome/browser/translate/model/translate_model_service_factory.mm
rename to ios/chrome/browser/language_detection/model/language_detection_model_service_factory.mm
index 04a5908..9539020 100644
--- a/ios/chrome/browser/translate/model/translate_model_service_factory.mm
+++ b/ios/chrome/browser/language_detection/model/language_detection_model_service_factory.mm
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#import "ios/chrome/browser/translate/model/translate_model_service_factory.h"
+#import "ios/chrome/browser/language_detection/model/language_detection_model_service_factory.h"
 
 #import "base/memory/scoped_refptr.h"
 #import "base/no_destructor.h"
@@ -11,9 +11,9 @@
 #import "base/task/thread_pool.h"
 #import "components/keyed_service/core/keyed_service.h"
 #import "components/keyed_service/ios/browser_state_dependency_manager.h"
+#import "components/language_detection/core/browser/language_detection_model_service.h"
 #import "components/optimization_guide/core/optimization_guide_features.h"
 #import "components/prefs/pref_service.h"
-#import "components/translate/core/browser/translate_model_service.h"
 #import "components/translate/core/common/translate_util.h"
 #import "ios/chrome/browser/optimization_guide/model/optimization_guide_service.h"
 #import "ios/chrome/browser/optimization_guide/model/optimization_guide_service_factory.h"
@@ -21,29 +21,31 @@
 #import "ios/chrome/browser/shared/model/profile/profile_ios.h"
 
 // static
-TranslateModelServiceFactory* TranslateModelServiceFactory::GetInstance() {
-  static base::NoDestructor<TranslateModelServiceFactory> instance;
+LanguageDetectionModelServiceFactory*
+LanguageDetectionModelServiceFactory::GetInstance() {
+  static base::NoDestructor<LanguageDetectionModelServiceFactory> instance;
   return instance.get();
 }
 
 // static
-translate::TranslateModelService*
-TranslateModelServiceFactory::GetForBrowserState(ChromeBrowserState* state) {
-  return static_cast<translate::TranslateModelService*>(
+language_detection::LanguageDetectionModelService*
+LanguageDetectionModelServiceFactory::GetForBrowserState(
+    ChromeBrowserState* state) {
+  return static_cast<language_detection::LanguageDetectionModelService*>(
       GetInstance()->GetServiceForBrowserState(state, true));
 }
 
-TranslateModelServiceFactory::TranslateModelServiceFactory()
+LanguageDetectionModelServiceFactory::LanguageDetectionModelServiceFactory()
     : BrowserStateKeyedServiceFactory(
-          "TranslateModelService",
+          "LanguageDetectionModelService",
           BrowserStateDependencyManager::GetInstance()) {
   DependsOn(OptimizationGuideServiceFactory::GetInstance());
 }
 
-TranslateModelServiceFactory::~TranslateModelServiceFactory() {}
+LanguageDetectionModelServiceFactory::~LanguageDetectionModelServiceFactory() {}
 
 std::unique_ptr<KeyedService>
-TranslateModelServiceFactory::BuildServiceInstanceFor(
+LanguageDetectionModelServiceFactory::BuildServiceInstanceFor(
     web::BrowserState* context) const {
   if (!translate::IsTFLiteLanguageDetectionEnabled() ||
       !optimization_guide::features::IsOptimizationTargetPredictionEnabled()) {
@@ -59,13 +61,13 @@
     scoped_refptr<base::SequencedTaskRunner> background_task_runner =
         base::ThreadPool::CreateSequencedTaskRunner(
             {base::MayBlock(), base::TaskPriority::BEST_EFFORT});
-    return std::make_unique<translate::TranslateModelService>(
+    return std::make_unique<language_detection::LanguageDetectionModelService>(
         opt_guide, background_task_runner);
   }
   return nullptr;
 }
 
-web::BrowserState* TranslateModelServiceFactory::GetBrowserStateToUse(
+web::BrowserState* LanguageDetectionModelServiceFactory::GetBrowserStateToUse(
     web::BrowserState* context) const {
   return GetBrowserStateRedirectedInIncognito(context);
 }
diff --git a/ios/chrome/browser/price_insights/ui/price_history.swift b/ios/chrome/browser/price_insights/ui/price_history.swift
index d986933..68237e7 100644
--- a/ios/chrome/browser/price_insights/ui/price_history.swift
+++ b/ios/chrome/browser/price_insights/ui/price_history.swift
@@ -90,6 +90,51 @@
   }
 }
 
+/// A view modifier that conditionally applies different gestures based on the iOS version for the graph.
+struct GraphGesture: ViewModifier {
+  let geometry: GeometryProxy
+  let proxy: ChartProxy
+  let updateSelectionData: (CGPoint, GeometryProxy, ChartProxy) -> Void
+  let updateTooltipPosition: (GeometryProxy, ChartProxy) -> Void
+  let recordGraphInteraction: () -> Void
+
+  func body(content: Content) -> some View {
+    if #available(iOS 18, *) {
+      /// To avoid conflicts between vertical scrolling and horizontal dragging
+      /// to display the tooltip, a long press is necessary. Once a long press
+      /// is detected, the system starts listening for a drag event, which we
+      /// interpret as the user's intent to horizontally drag the tooltip on the graph.
+      /// The heuristic for the long press was chosen after manual testing.
+      content.gesture(
+        LongPressGesture(minimumDuration: 0.07)
+          .sequenced(before: DragGesture())
+          .onChanged { value in
+            if case .second(_, let drag) = value, let drag = drag {
+              updateSelectionData(drag.location, geometry, proxy)
+              updateTooltipPosition(geometry, proxy)
+            }
+          }
+          .onEnded { _ in
+            recordGraphInteraction()
+          }
+      )
+    } else {
+      /// TODO(b/364871144): Investigate a solution that allows for both vertical
+      /// scrolling and horizontal dragging on iOS versions earlier than 18.
+      content.gesture(
+        DragGesture()
+          .onChanged { value in
+            updateSelectionData(value.location, geometry, proxy)
+            updateTooltipPosition(geometry, proxy)
+          }
+          .onEnded { _ in
+            recordGraphInteraction()
+          }
+      )
+    }
+  }
+}
+
 /// Represents a view displaying a historical graph.
 struct HistoryGraph: View {
   /// The price history data consisting of dates and corresponding prices.
@@ -238,24 +283,14 @@
               break
             }
           })
-          .gesture(
-            /// To avoid conflicts between vertical scrolling and horizontal dragging
-            /// to display the tooltip, a long press is necessary. Once a long press
-            /// is detected, the system starts listening for a drag event, which we
-            /// interpret as the user's intent to horizontally drag the tooltip on the graph.
-            /// The heuristic for the long press was chosen after manual testing.
-            LongPressGesture(minimumDuration: 0.07)
-              .sequenced(before: DragGesture())
-              .onChanged { value in
-                if case .second(_, let drag) = value, let drag = drag {
-                  updateSelectionData(location: drag.location, geometry: geometry, chart: proxy)
-                  updateTooltipPosition(geometry: geometry, chart: proxy)
-                }
-              }
-              .onEnded { _ in
-                recordGraphInteraction()
-              }
-          )
+          .modifier(
+            GraphGesture(
+              geometry: geometry,
+              proxy: proxy,
+              updateSelectionData: updateSelectionData,
+              updateTooltipPosition: updateTooltipPosition,
+              recordGraphInteraction: recordGraphInteraction
+            ))
       }
     }
     .overlay(
diff --git a/ios/chrome/browser/profile/model/BUILD.gn b/ios/chrome/browser/profile/model/BUILD.gn
index e8a14a1..bf73bfb 100644
--- a/ios/chrome/browser/profile/model/BUILD.gn
+++ b/ios/chrome/browser/profile/model/BUILD.gn
@@ -165,6 +165,7 @@
     "//ios/chrome/browser/https_upgrades/model",
     "//ios/chrome/browser/invalidation/model",
     "//ios/chrome/browser/language/model",
+    "//ios/chrome/browser/language_detection/model",
     "//ios/chrome/browser/mailto_handler/model:mailto_handler_factory",
     "//ios/chrome/browser/metrics/model",
     "//ios/chrome/browser/metrics/model:google_groups_updater",
diff --git a/ios/chrome/browser/profile/model/DEPS b/ios/chrome/browser/profile/model/DEPS
index 89d11d8..c13e1c3d 100644
--- a/ios/chrome/browser/profile/model/DEPS
+++ b/ios/chrome/browser/profile/model/DEPS
@@ -1,5 +1,6 @@
 include_rules = [
   "+ios/chrome/browser/content_settings/model",
+  "+ios/chrome/browser/language_detection/model",
   "+ios/chrome/browser/net/model",
   "+ios/chrome/browser/policy/model",
   "+ios/chrome/browser/prefs/model",
diff --git a/ios/chrome/browser/profile/model/keyed_service_factories.mm b/ios/chrome/browser/profile/model/keyed_service_factories.mm
index 01587bc..71390338 100644
--- a/ios/chrome/browser/profile/model/keyed_service_factories.mm
+++ b/ios/chrome/browser/profile/model/keyed_service_factories.mm
@@ -63,6 +63,8 @@
 #import "ios/chrome/browser/language/model/accept_languages_service_factory.h"
 #import "ios/chrome/browser/language/model/language_model_manager_factory.h"
 #import "ios/chrome/browser/language/model/url_language_histogram_factory.h"
+#import "ios/chrome/browser/language_detection/model/language_detection_model_loader_service_ios_factory.h"
+#import "ios/chrome/browser/language_detection/model/language_detection_model_service_factory.h"
 #import "ios/chrome/browser/mailto_handler/model/mailto_handler_service_factory.h"
 #import "ios/chrome/browser/metrics/model/google_groups_manager_factory.h"
 #import "ios/chrome/browser/metrics/model/ios_profile_session_durations_service_factory.h"
@@ -141,8 +143,6 @@
 #import "ios/chrome/browser/sync/model/sync_service_factory.h"
 #import "ios/chrome/browser/tabs_search/model/tabs_search_service_factory.h"
 #import "ios/chrome/browser/text_selection/model/text_classifier_model_service_factory.h"
-#import "ios/chrome/browser/translate/model/language_detection_model_service_factory.h"
-#import "ios/chrome/browser/translate/model/translate_model_service_factory.h"
 #import "ios/chrome/browser/translate/model/translate_ranker_factory.h"
 #import "ios/chrome/browser/trusted_vault/model/ios_trusted_vault_service_factory.h"
 #import "ios/chrome/browser/unified_consent/model/unified_consent_service_factory.h"
@@ -266,7 +266,7 @@
   IOSTrustedVaultServiceFactory::GetInstance();
   IOSUserEventServiceFactory::GetInstance();
   JavaScriptConsoleFeatureFactory::GetInstance();
-  LanguageDetectionModelServiceFactory::GetInstance();
+  LanguageDetectionModelLoaderServiceIOSFactory::GetInstance();
   LanguageModelManagerFactory::GetInstance();
   ListFamilyMembersServiceFactory::GetInstance();
   MailtoHandlerServiceFactory::GetInstance();
@@ -307,7 +307,7 @@
   TailoredSecurityServiceFactory::GetInstance();
   TextClassifierModelServiceFactory::GetInstance();
   TextToSpeechPlaybackControllerFactory::GetInstance();
-  TranslateModelServiceFactory::GetInstance();
+  LanguageDetectionModelServiceFactory::GetInstance();
   TrustedVaultClientBackendFactory::GetInstance();
   UnifiedConsentServiceFactory::GetInstance();
   UnitConversionServiceFactory::GetInstance();
diff --git a/ios/chrome/browser/safety_check_notifications/model/safety_check_notification_client_unittest.mm b/ios/chrome/browser/safety_check_notifications/model/safety_check_notification_client_unittest.mm
index b32e9936..8be0d8b 100644
--- a/ios/chrome/browser/safety_check_notifications/model/safety_check_notification_client_unittest.mm
+++ b/ios/chrome/browser/safety_check_notifications/model/safety_check_notification_client_unittest.mm
@@ -38,6 +38,7 @@
 #import "ios/testing/scoped_block_swizzler.h"
 #import "ios/web/public/browser_state.h"
 #import "ios/web/public/test/web_task_environment.h"
+#import "testing/gtest_mac.h"
 #import "testing/platform_test.h"
 #import "third_party/ocmock/OCMock/OCMock.h"
 #import "third_party/ocmock/gtest_support.h"
@@ -136,7 +137,7 @@
   // matching `notification_id`.
   id NotificationRequestArg(NSString* notification_id) {
     return [OCMArg checkWithBlock:^BOOL(UNNotificationRequest* request) {
-      EXPECT_TRUE([request.identifier isEqualToString:notification_id]);
+      EXPECT_NSEQ(request.identifier, notification_id);
       return YES;
     }];
   }
diff --git a/ios/chrome/browser/safety_check_notifications/utils/utils_unittest.mm b/ios/chrome/browser/safety_check_notifications/utils/utils_unittest.mm
index 7ff33844..c0de4d2b 100644
--- a/ios/chrome/browser/safety_check_notifications/utils/utils_unittest.mm
+++ b/ios/chrome/browser/safety_check_notifications/utils/utils_unittest.mm
@@ -13,6 +13,7 @@
 #import "ios/chrome/grit/ios_branded_strings.h"
 #import "ios/chrome/grit/ios_strings.h"
 #import "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
 #import "testing/platform_test.h"
 #import "ui/base/l10n/l10n_util_mac.h"
 
@@ -41,14 +42,12 @@
   NSString* expected_title = l10n_util::GetNSString(
       IDS_IOS_SAFETY_CHECK_NOTIFICATIONS_CHANGE_PASSWORDS);
 
-  EXPECT_TRUE(
-      [expected_title isEqualToString:compromised_password_notification.title]);
+  EXPECT_NSEQ(expected_title, compromised_password_notification.title);
 
   NSString* expected_body = l10n_util::GetPluralNSStringF(
       IDS_IOS_SAFETY_CHECK_NOTIFICATIONS_COMPROMISED_PASSWORD, 3);
 
-  EXPECT_TRUE(
-      [expected_body isEqualToString:compromised_password_notification.body]);
+  EXPECT_NSEQ(expected_body, compromised_password_notification.body);
 }
 
 // Tests if a notification is correctly generated for the weak password state.
@@ -70,13 +69,12 @@
   NSString* expected_title = l10n_util::GetNSString(
       IDS_IOS_SAFETY_CHECK_NOTIFICATIONS_CHANGE_PASSWORDS);
 
-  EXPECT_TRUE(
-      [expected_title isEqualToString:weak_password_notification.title]);
+  EXPECT_NSEQ(expected_title, weak_password_notification.title);
 
   NSString* expected_body = l10n_util::GetPluralNSStringF(
       IDS_IOS_SAFETY_CHECK_NOTIFICATIONS_WEAK_PASSWORD, 4);
 
-  EXPECT_TRUE([expected_body isEqualToString:weak_password_notification.body]);
+  EXPECT_NSEQ(expected_body, weak_password_notification.body);
 }
 
 // Tests if a notification is correctly generated for the reused password state.
@@ -98,14 +96,12 @@
   NSString* expected_title = l10n_util::GetNSString(
       IDS_IOS_SAFETY_CHECK_NOTIFICATIONS_CHANGE_PASSWORDS);
 
-  EXPECT_TRUE(
-      [expected_title isEqualToString:reused_password_notification.title]);
+  EXPECT_NSEQ(expected_title, reused_password_notification.title);
 
   NSString* expected_body = l10n_util::GetPluralNSStringF(
       IDS_IOS_SAFETY_CHECK_NOTIFICATIONS_REUSED_PASSWORD, 5);
 
-  EXPECT_TRUE(
-      [expected_body isEqualToString:reused_password_notification.body]);
+  EXPECT_NSEQ(expected_body, reused_password_notification.body);
 }
 
 // Tests that no notification is generated for the safe password state.
@@ -137,13 +133,12 @@
   NSString* expected_title =
       l10n_util::GetNSString(IDS_IOS_SAFETY_CHECK_NOTIFICATIONS_UPDATE_BROWSER);
 
-  EXPECT_TRUE(
-      [expected_title isEqualToString:update_chrome_notification.title]);
+  EXPECT_NSEQ(expected_title, update_chrome_notification.title);
 
   NSString* expected_body =
       l10n_util::GetNSString(IDS_IOS_SAFETY_CHECK_DESCRIPTION_UPDATE_CHROME);
 
-  EXPECT_TRUE([expected_body isEqualToString:update_chrome_notification.body]);
+  EXPECT_NSEQ(expected_body, update_chrome_notification.body);
 }
 
 // Tests that no notification is generated for the up-to-date Chrome state.
@@ -168,13 +163,12 @@
   NSString* expected_title = l10n_util::GetNSString(
       IDS_IOS_SAFETY_CHECK_NOTIFICATIONS_ADD_BROWSING_PROTECTION);
 
-  EXPECT_TRUE(
-      [expected_title isEqualToString:safe_browsing_notification.title]);
+  EXPECT_NSEQ(expected_title, safe_browsing_notification.title);
 
   NSString* expected_body = l10n_util::GetNSString(
       IDS_IOS_SAFETY_CHECK_NOTIFICATIONS_BROWSING_PROTECTION_OFF);
 
-  EXPECT_TRUE([expected_body isEqualToString:safe_browsing_notification.body]);
+  EXPECT_NSEQ(expected_body, safe_browsing_notification.body);
 }
 
 // Tests that no notification is generated for the safe Safe Browsing state.
diff --git a/ios/chrome/browser/shared/coordinator/scene/scene_controller_unittest.mm b/ios/chrome/browser/shared/coordinator/scene/scene_controller_unittest.mm
index 08c3adf..e3e96021 100644
--- a/ios/chrome/browser/shared/coordinator/scene/scene_controller_unittest.mm
+++ b/ios/chrome/browser/shared/coordinator/scene/scene_controller_unittest.mm
@@ -40,6 +40,7 @@
 #import "ios/web/public/test/web_task_environment.h"
 #import "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
 #import "services/network/test/test_url_loader_factory.h"
+#import "testing/gtest_mac.h"
 #import "testing/platform_test.h"
 #import "third_party/ocmock/OCMock/OCMock.h"
 
@@ -289,7 +290,7 @@
       base::BindRepeating(^(UserFeedbackData* data) {
         EXPECT_EQ(UserFeedbackSender::ToolsMenu, data.origin);
         EXPECT_FALSE(data.currentPageIsIncognito);
-        EXPECT_TRUE([data.familyMemberRole isEqualToString:@"child"]);
+        EXPECT_NSEQ(data.familyMemberRole, @"child");
       }).Then(run_loop.QuitClosure());
 
   [scene_controller_
diff --git a/ios/chrome/browser/shared/ui/elements/text_field_configuration_unittest.mm b/ios/chrome/browser/shared/ui/elements/text_field_configuration_unittest.mm
index 95ace8d9..3ce0d79 100644
--- a/ios/chrome/browser/shared/ui/elements/text_field_configuration_unittest.mm
+++ b/ios/chrome/browser/shared/ui/elements/text_field_configuration_unittest.mm
@@ -19,9 +19,9 @@
       accessibilityIdentifier:@"A11y"
        autocapitalizationType:UITextAutocapitalizationTypeNone
               secureTextEntry:YES];
-  EXPECT_TRUE([configuration.text isEqualToString:@"Text"]);
-  EXPECT_TRUE([configuration.placeholder isEqualToString:@"Placehorder"]);
-  EXPECT_TRUE([configuration.accessibilityIdentifier isEqualToString:@"A11y"]);
+  EXPECT_NSEQ(configuration.text, @"Text");
+  EXPECT_NSEQ(configuration.placeholder, @"Placehorder");
+  EXPECT_NSEQ(configuration.accessibilityIdentifier, @"A11y");
   EXPECT_EQ(UITextAutocapitalizationTypeNone,
             configuration.autocapitalizationType);
   EXPECT_TRUE(configuration.secureTextEntry);
diff --git a/ios/chrome/browser/shared/ui/util/pasteboard_util_unittest.mm b/ios/chrome/browser/shared/ui/util/pasteboard_util_unittest.mm
index d0d2117..8a0e364 100644
--- a/ios/chrome/browser/shared/ui/util/pasteboard_util_unittest.mm
+++ b/ios/chrome/browser/shared/ui/util/pasteboard_util_unittest.mm
@@ -61,10 +61,9 @@
       [text_as_data isEqualToData:[UIPasteboard.generalPasteboard
                                       dataForPasteboardType:plainTextType
                                                   inItemSet:secondIndex][0]]);
-  EXPECT_TRUE([test_text
-      isEqualToString:[UIPasteboard.generalPasteboard
-                          valuesForPasteboardType:UTTypeText.identifier
-                                        inItemSet:secondIndex][0]]);
+  EXPECT_NSEQ(test_text, [UIPasteboard.generalPasteboard
+                             valuesForPasteboardType:UTTypeText.identifier
+                                           inItemSet:secondIndex][0]);
 }
 
 // Tests that clearing the pasteboard does remove pasteboard items.
diff --git a/ios/chrome/browser/translate/model/BUILD.gn b/ios/chrome/browser/translate/model/BUILD.gn
index 57cb80a..22ef981 100644
--- a/ios/chrome/browser/translate/model/BUILD.gn
+++ b/ios/chrome/browser/translate/model/BUILD.gn
@@ -18,13 +18,9 @@
   sources = [
     "chrome_ios_translate_client.h",
     "chrome_ios_translate_client.mm",
-    "language_detection_model_service_factory.h",
-    "language_detection_model_service_factory.mm",
     "language_selection_context.h",
     "language_selection_context.mm",
     "translate_infobar_tags.h",
-    "translate_model_service_factory.h",
-    "translate_model_service_factory.mm",
     "translate_ranker_factory.h",
     "translate_ranker_factory.mm",
     "translate_ranker_metrics_provider.h",
@@ -39,12 +35,13 @@
     "//components/keyed_service/core",
     "//components/keyed_service/ios",
     "//components/language/core/browser",
+    "//components/language_detection/core/browser:language_detection_model_service",
+    "//components/language_detection/ios/browser",
     "//components/metrics",
     "//components/optimization_guide/core:features",
     "//components/prefs",
     "//components/strings",
     "//components/translate/core/browser",
-    "//components/translate/core/browser:translate_model_service",
     "//components/translate/core/common",
     "//components/translate/core/language_detection",
     "//components/translate/ios/browser",
@@ -53,6 +50,7 @@
     "//ios/chrome/browser/infobars/model",
     "//ios/chrome/browser/infobars/model:public",
     "//ios/chrome/browser/language/model",
+    "//ios/chrome/browser/language_detection/model",
     "//ios/chrome/browser/optimization_guide/model",
     "//ios/chrome/browser/shared/model/application_context",
     "//ios/chrome/browser/shared/model/browser_state",
@@ -84,6 +82,7 @@
     "//base/test:test_support",
     "//components/language/core/browser",
     "//components/language/ios/browser",
+    "//components/language_detection/ios/browser",
     "//components/optimization_guide/core:features",
     "//components/optimization_guide/core:prediction",
     "//components/prefs",
@@ -95,6 +94,7 @@
     "//components/translate/ios/browser",
     "//ios/chrome/browser/infobars/model",
     "//ios/chrome/browser/language/model",
+    "//ios/chrome/browser/language_detection/model",
     "//ios/chrome/browser/optimization_guide/model",
     "//ios/chrome/browser/shared/model/profile/test",
     "//ios/chrome/browser/shared/model/url:constants",
diff --git a/ios/chrome/browser/translate/model/DEPS b/ios/chrome/browser/translate/model/DEPS
index 33f7537..2531ecf 100644
--- a/ios/chrome/browser/translate/model/DEPS
+++ b/ios/chrome/browser/translate/model/DEPS
@@ -1,7 +1,9 @@
 include_rules = [
+  "+components/language_detection/ios/browser",
   "+ios/chrome/browser/infobars/model",
   "+ios/chrome/browser/language/model",
   "+ios/chrome/browser/optimization_guide/model",
+  "+ios/chrome/browser/language_detection/model",
 ]
 
 specific_include_rules = {
diff --git a/ios/chrome/browser/translate/model/chrome_ios_translate_client.mm b/ios/chrome/browser/translate/model/chrome_ios_translate_client.mm
index 56761d6..834d5b1 100644
--- a/ios/chrome/browser/translate/model/chrome_ios_translate_client.mm
+++ b/ios/chrome/browser/translate/model/chrome_ios_translate_client.mm
@@ -27,9 +27,9 @@
 #import "ios/chrome/browser/language/model/accept_languages_service_factory.h"
 #import "ios/chrome/browser/language/model/language_model_manager_factory.h"
 #import "ios/chrome/browser/language/model/url_language_histogram_factory.h"
+#import "ios/chrome/browser/language_detection/model/language_detection_model_loader_service_ios_factory.h"
+#import "ios/chrome/browser/language_detection/model/language_detection_model_service_factory.h"
 #import "ios/chrome/browser/shared/model/profile/profile_ios.h"
-#import "ios/chrome/browser/translate/model/language_detection_model_service_factory.h"
-#import "ios/chrome/browser/translate/model/translate_model_service_factory.h"
 #import "ios/chrome/browser/translate/model/translate_ranker_factory.h"
 #import "ios/chrome/browser/translate/model/translate_service_ios.h"
 #import "ios/chrome/grit/ios_theme_resources.h"
@@ -43,7 +43,7 @@
     : web_state_(web_state),
       translate_driver_(
           web_state,
-          LanguageDetectionModelServiceFactory::GetForBrowserState(
+          LanguageDetectionModelLoaderServiceIOSFactory::GetForBrowserState(
               ChromeBrowserState::FromBrowserState(
                   web_state->GetBrowserState()))),
       translate_manager_(std::make_unique<translate::TranslateManager>(
diff --git a/ios/chrome/browser/translate/model/chrome_ios_translate_client_unittest.mm b/ios/chrome/browser/translate/model/chrome_ios_translate_client_unittest.mm
index 02f5ada..db916bd 100644
--- a/ios/chrome/browser/translate/model/chrome_ios_translate_client_unittest.mm
+++ b/ios/chrome/browser/translate/model/chrome_ios_translate_client_unittest.mm
@@ -11,20 +11,20 @@
 #import "base/test/scoped_feature_list.h"
 #import "base/test/task_environment.h"
 #import "base/values.h"
+#import "components/language_detection/ios/browser/language_detection_model_loader_service_ios.h"
 #import "components/optimization_guide/core/optimization_guide_features.h"
 #import "components/translate/core/browser/translate_metrics_logger.h"
 #import "components/translate/core/common/translate_util.h"
 #import "components/translate/core/language_detection/language_detection_model.h"
-#import "components/translate/ios/browser/language_detection_model_service.h"
 #import "components/translate/ios/browser/translate_java_script_feature.h"
 #import "ios/chrome/browser/infobars/model/infobar_manager_impl.h"
 #import "ios/chrome/browser/language/model/language_model_manager_factory.h"
+#import "ios/chrome/browser/language_detection/model/language_detection_model_loader_service_ios_factory.h"
+#import "ios/chrome/browser/language_detection/model/language_detection_model_service_factory.h"
 #import "ios/chrome/browser/optimization_guide/model/ios_chrome_prediction_model_store.h"
 #import "ios/chrome/browser/optimization_guide/model/optimization_guide_service.h"
 #import "ios/chrome/browser/optimization_guide/model/optimization_guide_service_factory.h"
 #import "ios/chrome/browser/shared/model/profile/test/test_profile_ios.h"
-#import "ios/chrome/browser/translate/model/language_detection_model_service_factory.h"
-#import "ios/chrome/browser/translate/model/translate_model_service_factory.h"
 #import "ios/chrome/browser/translate/model/translate_ranker_factory.h"
 #import "ios/chrome/test/ios_chrome_scoped_testing_local_state.h"
 #import "ios/web/public/test/fakes/fake_navigation_context.h"
diff --git a/ios/chrome/browser/translate/model/language_detection_model_service_factory.mm b/ios/chrome/browser/translate/model/language_detection_model_service_factory.mm
deleted file mode 100644
index 2576268..0000000
--- a/ios/chrome/browser/translate/model/language_detection_model_service_factory.mm
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/chrome/browser/translate/model/language_detection_model_service_factory.h"
-
-#import "base/memory/scoped_refptr.h"
-#import "base/no_destructor.h"
-#import "base/task/sequenced_task_runner.h"
-#import "base/task/task_traits.h"
-#import "base/task/thread_pool.h"
-#import "components/keyed_service/core/keyed_service.h"
-#import "components/keyed_service/ios/browser_state_dependency_manager.h"
-#import "components/translate/core/common/translate_util.h"
-#import "components/translate/ios/browser/language_detection_model_service.h"
-#import "ios/chrome/browser/shared/model/browser_state/browser_state_otr_helper.h"
-#import "ios/chrome/browser/shared/model/profile/profile_ios.h"
-#import "ios/chrome/browser/translate/model/translate_model_service_factory.h"
-
-// static
-LanguageDetectionModelServiceFactory*
-LanguageDetectionModelServiceFactory::GetInstance() {
-  static base::NoDestructor<LanguageDetectionModelServiceFactory> instance;
-  return instance.get();
-}
-
-// static
-translate::LanguageDetectionModelService*
-LanguageDetectionModelServiceFactory::GetForBrowserState(
-    ChromeBrowserState* state) {
-  return static_cast<translate::LanguageDetectionModelService*>(
-      GetInstance()->GetServiceForBrowserState(state, true));
-}
-
-LanguageDetectionModelServiceFactory::LanguageDetectionModelServiceFactory()
-    : BrowserStateKeyedServiceFactory(
-          "LanguageDetectionModel",
-          BrowserStateDependencyManager::GetInstance()) {
-  DependsOn(TranslateModelServiceFactory::GetInstance());
-}
-
-LanguageDetectionModelServiceFactory::~LanguageDetectionModelServiceFactory() {}
-
-std::unique_ptr<KeyedService>
-LanguageDetectionModelServiceFactory::BuildServiceInstanceFor(
-    web::BrowserState* context) const {
-  if (!translate::IsTFLiteLanguageDetectionEnabled()) {
-    return nullptr;
-  }
-  ChromeBrowserState* browser_state =
-      ChromeBrowserState::FromBrowserState(context);
-  scoped_refptr<base::SequencedTaskRunner> background_task_runner =
-      base::ThreadPool::CreateSequencedTaskRunner(
-          {base::MayBlock(), base::TaskPriority::BEST_EFFORT});
-  auto* translate_model_service =
-      TranslateModelServiceFactory::GetForBrowserState(browser_state);
-  return std::make_unique<translate::LanguageDetectionModelService>(
-      translate_model_service, background_task_runner);
-}
-
-web::BrowserState* LanguageDetectionModelServiceFactory::GetBrowserStateToUse(
-    web::BrowserState* context) const {
-  return GetBrowserStateRedirectedInIncognito(context);
-}
diff --git a/ios/chrome/browser/translate/model/translate_model_service_factory.h b/ios/chrome/browser/translate/model/translate_model_service_factory.h
deleted file mode 100644
index 52e772e..0000000
--- a/ios/chrome/browser/translate/model/translate_model_service_factory.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_TRANSLATE_MODEL_TRANSLATE_MODEL_SERVICE_FACTORY_H_
-#define IOS_CHROME_BROWSER_TRANSLATE_MODEL_TRANSLATE_MODEL_SERVICE_FACTORY_H_
-
-#import <memory>
-
-#import "base/no_destructor.h"
-#import "components/keyed_service/ios/browser_state_keyed_service_factory.h"
-#import "ios/chrome/browser/shared/model/profile/profile_ios_forward.h"
-
-namespace translate {
-class TranslateModelService;
-}
-
-class TranslateModelServiceFactory : public BrowserStateKeyedServiceFactory {
- public:
-  static translate::TranslateModelService* GetForBrowserState(
-      ChromeBrowserState* browser_state);
-  static TranslateModelServiceFactory* GetInstance();
-
-  TranslateModelServiceFactory(const TranslateModelServiceFactory&) = delete;
-  TranslateModelServiceFactory& operator=(const TranslateModelServiceFactory&) =
-      delete;
-
- private:
-  friend class base::NoDestructor<TranslateModelServiceFactory>;
-
-  TranslateModelServiceFactory();
-  ~TranslateModelServiceFactory() override;
-
-  // BrowserStateKeyedServiceFactory implementation.
-  std::unique_ptr<KeyedService> BuildServiceInstanceFor(
-      web::BrowserState* context) const override;
-  web::BrowserState* GetBrowserStateToUse(
-      web::BrowserState* context) const override;
-};
-
-#endif  // IOS_CHROME_BROWSER_TRANSLATE_MODEL_TRANSLATE_MODEL_SERVICE_FACTORY_H_
diff --git a/ios/chrome/browser/ui/authentication/cells/signin_promo_view_unittest.mm b/ios/chrome/browser/ui/authentication/cells/signin_promo_view_unittest.mm
index 2cb70b54..1f23c7f 100644
--- a/ios/chrome/browser/ui/authentication/cells/signin_promo_view_unittest.mm
+++ b/ios/chrome/browser/ui/authentication/cells/signin_promo_view_unittest.mm
@@ -11,6 +11,7 @@
 #import "ios/chrome/browser/ui/authentication/cells/signin_promo_view_constants.h"
 #import "ios/chrome/common/ui/util/image_util.h"
 #import "ios/public/provider/chrome/browser/signin/signin_resources_api.h"
+#import "testing/gtest_mac.h"
 #import "testing/platform_test.h"
 #import "third_party/ocmock/gtest_support.h"
 
@@ -71,8 +72,7 @@
   view.textLabel.text = promoText;
   NSString* expectedAccessibilityLabel =
       [NSString stringWithFormat:@"%@ %@", promoText, primaryButtonTitle];
-  EXPECT_TRUE(
-      [view.accessibilityLabel isEqualToString:expectedAccessibilityLabel]);
+  EXPECT_NSEQ(view.accessibilityLabel, expectedAccessibilityLabel);
 }
 
 // Tests that signin is created on non-compact layout and that setting compact
diff --git a/ios/chrome/browser/ui/browser_container/browser_container_coordinator_unittest.mm b/ios/chrome/browser/ui/browser_container/browser_container_coordinator_unittest.mm
index 1927a3d..60e6fd4e 100644
--- a/ios/chrome/browser/ui/browser_container/browser_container_coordinator_unittest.mm
+++ b/ios/chrome/browser/ui/browser_container/browser_container_coordinator_unittest.mm
@@ -19,6 +19,7 @@
 #import "ios/chrome/browser/ui/browser_container/edit_menu_alert_delegate.h"
 #import "ios/chrome/grit/ios_strings.h"
 #import "ios/chrome/test/scoped_key_window.h"
+#import "testing/gtest_mac.h"
 #import "testing/platform_test.h"
 #import "third_party/ocmock/OCMock/OCMock.h"
 #import "third_party/ocmock/gtest_support.h"
@@ -110,14 +111,13 @@
 
   // First action should be the OK button.
   UIAlertAction* ok_action = alert_controller.actions[0];
-  EXPECT_TRUE(
-      [l10n_util::GetNSString(IDS_APP_OK) isEqualToString:ok_action.title]);
+  EXPECT_NSEQ(l10n_util::GetNSString(IDS_APP_OK), ok_action.title);
   EXPECT_EQ(UIAlertActionStyleCancel, ok_action.style);
 
   // Second action should the Share button.
   UIAlertAction* share_action = alert_controller.actions[1];
-  EXPECT_TRUE([l10n_util::GetNSString(IDS_IOS_SHARE_PAGE_BUTTON_LABEL)
-      isEqualToString:share_action.title]);
+  EXPECT_NSEQ(l10n_util::GetNSString(IDS_IOS_SHARE_PAGE_BUTTON_LABEL),
+              share_action.title);
   EXPECT_EQ(UIAlertActionStyleDefault, share_action.style);
   [coordinator stop];
 }
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios_unittest.mm b/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios_unittest.mm
index be9378ad..b93d211 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios_unittest.mm
+++ b/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios_unittest.mm
@@ -159,7 +159,7 @@
   EXPECT_TRUE([textfield_ canPerformAction:@selector(copy:) withSender:nil]);
   [delegateMock onCopy];
   [textfield_ copy:nil];
-  EXPECT_TRUE([textfield_.text isEqualToString:testString]);
+  EXPECT_NSEQ(textfield_.text, testString);
   [delegateMock verify];
 }
 
@@ -173,7 +173,7 @@
   EXPECT_TRUE([textfield_ canPerformAction:@selector(cut:) withSender:nil]);
   [delegateMock onCopy];
   [textfield_ cut:nil];
-  EXPECT_TRUE([textfield_.text isEqualToString:@""]);
+  EXPECT_NSEQ(textfield_.text, @"");
   [delegateMock verify];
 }
 
diff --git a/ios/chrome/browser/ui/post_restore_signin/post_restore_signin_view_controller_unittest.mm b/ios/chrome/browser/ui/post_restore_signin/post_restore_signin_view_controller_unittest.mm
index dbec37f4..8108a81c 100644
--- a/ios/chrome/browser/ui/post_restore_signin/post_restore_signin_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/post_restore_signin/post_restore_signin_view_controller_unittest.mm
@@ -60,8 +60,7 @@
     expectedDisclaimer = @"You were signed out as part of your iPhone reset. "
                          @"Tap continue below to sign in.";
   }
-  EXPECT_TRUE(
-      [view_controller_.disclaimerText isEqualToString:expectedDisclaimer]);
+  EXPECT_NSEQ(view_controller_.disclaimerText, expectedDisclaimer);
 }
 
 TEST_F(PostRestoreSignInViewControllerTest, uiStringsWithoutName) {
diff --git a/ios/chrome/browser/ui/price_notifications/price_notifications_table_view_controller_unittest.mm b/ios/chrome/browser/ui/price_notifications/price_notifications_table_view_controller_unittest.mm
index ce210d4..022b0a6 100644
--- a/ios/chrome/browser/ui/price_notifications/price_notifications_table_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/price_notifications/price_notifications_table_view_controller_unittest.mm
@@ -15,6 +15,7 @@
 #import "ios/chrome/browser/ui/price_notifications/price_notifications_consumer.h"
 #import "ios/chrome/browser/ui/price_notifications/test_price_notifications_mutator.h"
 #import "ios/chrome/grit/ios_strings.h"
+#import "testing/gtest_mac.h"
 #import "testing/platform_test.h"
 #import "ui/base/l10n/l10n_util_mac.h"
 
@@ -116,32 +117,31 @@
       GetHeaderItemFromSection<TableViewTextHeaderFooterItem>(
           controller(), SectionIdentifierTrackedItems);
 
-  EXPECT_TRUE([tableHeadingText
-      isEqualToString:
-          l10n_util::GetNSString(
-              IDS_IOS_PRICE_NOTIFICATIONS_PRICE_TRACK_DESCRIPTION_EMPTY_STATE)]);
+  EXPECT_NSEQ(
+      tableHeadingText,
+      l10n_util::GetNSString(
+          IDS_IOS_PRICE_NOTIFICATIONS_PRICE_TRACK_DESCRIPTION_EMPTY_STATE));
   EXPECT_FALSE([controller().tableViewModel
       hasItemForItemType:ItemTypeListItem
        sectionIdentifier:SectionIdentifierTrackableItemsOnCurrentSite]);
-  EXPECT_TRUE([trackableHeaderItem.text
-      isEqualToString:
-          l10n_util::GetNSString(
-              IDS_IOS_PRICE_NOTIFICATIONS_PRICE_TRACK_TRACKABLE_SECTION_HEADER)]);
-  EXPECT_TRUE([trackableHeaderItem.subtitle
-      isEqualToString:
-          l10n_util::GetNSString(
-              IDS_IOS_PRICE_NOTIFICATIONS_PRICE_TRACK_TRACKABLE_EMPTY_LIST)]);
+  EXPECT_NSEQ(
+      trackableHeaderItem.text,
+      l10n_util::GetNSString(
+          IDS_IOS_PRICE_NOTIFICATIONS_PRICE_TRACK_TRACKABLE_SECTION_HEADER));
+  EXPECT_NSEQ(
+      trackableHeaderItem.subtitle,
+      l10n_util::GetNSString(
+          IDS_IOS_PRICE_NOTIFICATIONS_PRICE_TRACK_TRACKABLE_EMPTY_LIST));
   EXPECT_FALSE([controller().tableViewModel
       hasItemForItemType:ItemTypeListItem
        sectionIdentifier:SectionIdentifierTrackedItems]);
-  EXPECT_TRUE([trackedHeaderItem.text
-      isEqualToString:
-          l10n_util::GetNSString(
-              IDS_IOS_PRICE_NOTIFICATIONS_PRICE_TRACK_TRACKED_SECTION_HEADER)]);
-  EXPECT_TRUE([trackedHeaderItem.subtitle
-      isEqualToString:
-          l10n_util::GetNSString(
-              IDS_IOS_PRICE_NOTIFICATIONS_PRICE_TRACK_TRACKING_EMPTY_LIST)]);
+  EXPECT_NSEQ(
+      trackedHeaderItem.text,
+      l10n_util::GetNSString(
+          IDS_IOS_PRICE_NOTIFICATIONS_PRICE_TRACK_TRACKED_SECTION_HEADER));
+  EXPECT_NSEQ(trackedHeaderItem.subtitle,
+              l10n_util::GetNSString(
+                  IDS_IOS_PRICE_NOTIFICATIONS_PRICE_TRACK_TRACKING_EMPTY_LIST));
 }
 
 // Simulates that a trackable item exists and is properly displayed.
@@ -163,7 +163,7 @@
       hasItemForItemType:ItemTypeListItem
        sectionIdentifier:SectionIdentifierTrackableItemsOnCurrentSite]);
   EXPECT_EQ(items.count, 1u);
-  EXPECT_TRUE([items[0].title isEqualToString:item.title]);
+  EXPECT_NSEQ(items[0].title, item.title);
 }
 
 // Simulates that a tracked item exists and is displayed
@@ -183,7 +183,7 @@
       hasItemForItemType:ItemTypeListItem
        sectionIdentifier:SectionIdentifierTrackedItems]);
   EXPECT_EQ(items.count, 1u);
-  EXPECT_TRUE([items[0].title isEqualToString:item.title]);
+  EXPECT_NSEQ(items[0].title, item.title);
 }
 
 // Simulates that a tracked item exists and is displayed when the user is
@@ -209,10 +209,10 @@
       hasItemForItemType:ItemTypeListItem
        sectionIdentifier:SectionIdentifierTrackedItems]);
   EXPECT_EQ(items.count, 1u);
-  EXPECT_TRUE([trackableHeaderItem.subtitle
-      isEqualToString:
-          l10n_util::GetNSString(
-              IDS_IOS_PRICE_NOTIFICAITONS_PRICE_TRACK_TRACKABLE_ITEM_IS_TRACKED)]);
+  EXPECT_NSEQ(
+      trackableHeaderItem.subtitle,
+      l10n_util::GetNSString(
+          IDS_IOS_PRICE_NOTIFICAITONS_PRICE_TRACK_TRACKABLE_ITEM_IS_TRACKED));
 }
 
 // Simulates that a trackable item exists, has been selected to be tracked,
@@ -246,10 +246,10 @@
   EXPECT_EQ(trackedItemCountBeforeStartTracking, 0u);
   EXPECT_EQ(trackableItemCountAfterStartTracking, 0u);
   EXPECT_EQ(trackedItemCountAfterStartTracking, 1u);
-  EXPECT_TRUE([trackableHeaderItem.subtitle
-      isEqualToString:
-          l10n_util::GetNSString(
-              IDS_IOS_PRICE_NOTIFICATIONS_PRICE_TRACK_DESCRIPTION_FOR_TRACKED_ITEM)]);
+  EXPECT_NSEQ(
+      trackableHeaderItem.subtitle,
+      l10n_util::GetNSString(
+          IDS_IOS_PRICE_NOTIFICATIONS_PRICE_TRACK_DESCRIPTION_FOR_TRACKED_ITEM));
 }
 
 // Simulates the user tapping on a tracked item and being redirected to
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_mediator_unittest.mm b/ios/chrome/browser/ui/reading_list/reading_list_mediator_unittest.mm
index ed1ff38..0b8555e 100644
--- a/ios/chrome/browser/ui/reading_list/reading_list_mediator_unittest.mm
+++ b/ios/chrome/browser/ui/reading_list/reading_list_mediator_unittest.mm
@@ -28,6 +28,7 @@
 #import "ios/web/public/test/web_task_environment.h"
 #import "testing/gmock/include/gmock/gmock.h"
 #import "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
 #import "testing/platform_test.h"
 #import "third_party/ocmock/OCMock/OCMock.h"
 
@@ -138,9 +139,9 @@
   EXPECT_EQ(2U, [readArray count]);
   NSArray<ReadingListTableViewItem*>* rlReadArray = [readArray copy];
   NSArray<ReadingListTableViewItem*>* rlUneadArray = [unreadArray copy];
-  EXPECT_TRUE([rlUneadArray[0].title isEqualToString:@""]);
-  EXPECT_TRUE([rlReadArray[0].title isEqualToString:@"read2"]);
-  EXPECT_TRUE([rlReadArray[1].title isEqualToString:@"read1"]);
+  EXPECT_NSEQ(rlUneadArray[0].title, @"");
+  EXPECT_NSEQ(rlReadArray[0].title, @"read2");
+  EXPECT_NSEQ(rlReadArray[1].title, @"read1");
 }
 
 INSTANTIATE_TEST_SUITE_P(
diff --git a/ios/chrome/browser/ui/settings/clear_browsing_data/quick_delete_coordinator.mm b/ios/chrome/browser/ui/settings/clear_browsing_data/quick_delete_coordinator.mm
index 9e35419..24b1ab5 100644
--- a/ios/chrome/browser/ui/settings/clear_browsing_data/quick_delete_coordinator.mm
+++ b/ios/chrome/browser/ui/settings/clear_browsing_data/quick_delete_coordinator.mm
@@ -11,6 +11,7 @@
 #import "ios/chrome/browser/browsing_data/model/browsing_data_remover_factory.h"
 #import "ios/chrome/browser/browsing_data/model/tabs_closure_util.h"
 #import "ios/chrome/browser/discover_feed/model/discover_feed_service_factory.h"
+#import "ios/chrome/browser/shared/coordinator/scene/scene_state.h"
 #import "ios/chrome/browser/shared/model/browser/browser.h"
 #import "ios/chrome/browser/shared/model/profile/profile_ios.h"
 #import "ios/chrome/browser/shared/model/url/chrome_url_constants.h"
@@ -22,6 +23,7 @@
 #import "ios/chrome/browser/shared/public/commands/tabs_animation_commands.h"
 #import "ios/chrome/browser/shared/ui/util/uikit_ui_util.h"
 #import "ios/chrome/browser/signin/model/identity_manager_factory.h"
+#import "ios/chrome/browser/ui/scoped_ui_blocker/scoped_ui_blocker.h"
 #import "ios/chrome/browser/ui/settings/clear_browsing_data/browsing_data_counter_wrapper_producer.h"
 #import "ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_ui_constants.h"
 #import "ios/chrome/browser/ui/settings/clear_browsing_data/quick_delete_browsing_data_coordinator.h"
@@ -41,6 +43,7 @@
   QuickDeleteViewController* _viewController;
   QuickDeleteMediator* _mediator;
   QuickDeleteBrowsingDataCoordinator* _browsingDataCoordinator;
+  std::unique_ptr<ScopedUIBlocker> _windowUIBlocker;
 
   // The tabs closure animation should only be performed if Quick Delete is
   // opened on top of a tab or the tab grid.
@@ -195,6 +198,15 @@
                          completion:dismissCompletionBlock];
 }
 
+- (void)blockOtherWindows {
+  SceneState* sceneState = self.browser->GetSceneState();
+  _windowUIBlocker = std::make_unique<ScopedUIBlocker>(sceneState);
+}
+
+- (void)releaseOtherWindows {
+  _windowUIBlocker.reset();
+}
+
 #pragma mark - UIAdaptivePresentationControllerDelegate
 
 - (void)presentationControllerDidDismiss:
@@ -230,7 +242,8 @@
                     allInactiveTabs:(BOOL)animateAllInactiveTabs
                 browsingDataRemover:(BrowsingDataRemover*)browsingDataRemover {
   base::OnceClosure onRemoverCompletion = base::BindOnce(
-      [](UIWindow* window) {
+      [](UIWindow* window, std::unique_ptr<ScopedUIBlocker> uiBlocker) {
+        uiBlocker.reset();
         window.userInteractionEnabled = YES;
         window.accessibilityElementsHidden = NO;
 
@@ -245,7 +258,7 @@
         // rearrange.
         TriggerHapticFeedbackForNotification(UINotificationFeedbackTypeSuccess);
       },
-      self.baseViewController.view.window);
+      self.baseViewController.view.window, std::move(_windowUIBlocker));
 
   base::OnceClosure onAnimationCompletion = base::BindOnce(
       &BrowsingDataRemover::RemoveInRange, browsingDataRemover->AsWeakPtr(),
@@ -264,6 +277,9 @@
 
 // Disconnects all instances.
 - (void)disconnect {
+  if (_windowUIBlocker) {
+    _windowUIBlocker.reset();
+  }
   _viewController.presentationHandler = nil;
   _viewController.mutator = nil;
   _viewController.presentationController.delegate = nil;
diff --git a/ios/chrome/browser/ui/settings/clear_browsing_data/quick_delete_presentation_commands.h b/ios/chrome/browser/ui/settings/clear_browsing_data/quick_delete_presentation_commands.h
index 3b93c74..4f1d1a8b9 100644
--- a/ios/chrome/browser/ui/settings/clear_browsing_data/quick_delete_presentation_commands.h
+++ b/ios/chrome/browser/ui/settings/clear_browsing_data/quick_delete_presentation_commands.h
@@ -29,6 +29,14 @@
                                   cachedTabsInfo:
                                       (tabs_closure_util::WebStateIDToTime)
                                           cachedTabsInfo;
+
+// Method invoked on deletion in progress to block other windows to avoid having
+// multiple deletions occur concurrently.
+- (void)blockOtherWindows;
+
+// Method invoked on deletion completed to release other blocked windows.
+- (void)releaseOtherWindows;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_SETTINGS_CLEAR_BROWSING_DATA_QUICK_DELETE_PRESENTATION_COMMANDS_H_
diff --git a/ios/chrome/browser/ui/settings/clear_browsing_data/quick_delete_view_controller.mm b/ios/chrome/browser/ui/settings/clear_browsing_data/quick_delete_view_controller.mm
index b73f8cb..c8c33f1 100644
--- a/ios/chrome/browser/ui/settings/clear_browsing_data/quick_delete_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/clear_browsing_data/quick_delete_view_controller.mm
@@ -367,9 +367,11 @@
   // Disable accessibility elements on entire window to avoid Voiceover focusing
   // on new elements during the deletion or the animation.
   self.view.window.accessibilityElementsHidden = YES;
+  [self.presentationHandler blockOtherWindows];
 }
 
 - (void)deletionFinished {
+  [self.presentationHandler releaseOtherWindows];
   // Allow the user to dismiss the bottom sheet, but still not interact with
   // contents of the bottom sheet.
   self.view.userInteractionEnabled = NO;
diff --git a/ios/chrome/browser/ui/sharing/activity_services/activities/bookmark_activity_unittest.mm b/ios/chrome/browser/ui/sharing/activity_services/activities/bookmark_activity_unittest.mm
index ee58d6a..3c3b605 100644
--- a/ios/chrome/browser/ui/sharing/activity_services/activities/bookmark_activity_unittest.mm
+++ b/ios/chrome/browser/ui/sharing/activity_services/activities/bookmark_activity_unittest.mm
@@ -13,6 +13,7 @@
 #import "ios/chrome/browser/shared/public/commands/bookmarks_commands.h"
 #import "ios/chrome/browser/shared/ui/util/url_with_title.h"
 #import "ios/chrome/grit/ios_strings.h"
+#import "testing/gtest_mac.h"
 #import "third_party/ocmock/OCMock/OCMock.h"
 #import "ui/base/l10n/l10n_util_mac.h"
 #import "url/gurl.h"
@@ -94,7 +95,7 @@
 
   NSString* addBookmarkString =
       l10n_util::GetNSString(IDS_IOS_TOOLS_MENU_ADD_TO_BOOKMARKS);
-  EXPECT_TRUE([addBookmarkString isEqualToString:activity.activityTitle]);
+  EXPECT_NSEQ(addBookmarkString, activity.activityTitle);
 }
 
 // Tests that the title of the activity is edit when URL is already bookmarked.
@@ -108,7 +109,7 @@
 
   NSString* editBookmarkString =
       l10n_util::GetNSString(IDS_IOS_TOOLS_MENU_EDIT_BOOKMARK);
-  EXPECT_TRUE([editBookmarkString isEqualToString:activity.activityTitle]);
+  EXPECT_NSEQ(editBookmarkString, activity.activityTitle);
 }
 
 TEST_F(BookmarkActivityTest, PerformActivity_BookmarkAddCommand) {
diff --git a/ios/chrome/browser/ui/sharing/activity_services/activities/copy_activity_unittest.mm b/ios/chrome/browser/ui/sharing/activity_services/activities/copy_activity_unittest.mm
index ec824c98..3dbec93 100644
--- a/ios/chrome/browser/ui/sharing/activity_services/activities/copy_activity_unittest.mm
+++ b/ios/chrome/browser/ui/sharing/activity_services/activities/copy_activity_unittest.mm
@@ -7,6 +7,7 @@
 #import "base/strings/sys_string_conversions.h"
 #import "ios/chrome/browser/shared/ui/util/pasteboard_util.h"
 #import "ios/chrome/browser/ui/sharing/activity_services/data/share_to_data.h"
+#import "testing/gtest_mac.h"
 #import "testing/platform_test.h"
 #import "third_party/ocmock/OCMock/OCMock.h"
 #import "third_party/ocmock/gtest_support.h"
@@ -146,11 +147,9 @@
 
   // The first pasteboard item has both a URL and string representation of the
   // test URL.
-  EXPECT_TRUE(
-      [GetURLString() isEqualToString:UIPasteboard.generalPasteboard.string]);
+  EXPECT_NSEQ(GetURLString(), UIPasteboard.generalPasteboard.string);
   EXPECT_TRUE([GetExpectedURL() isEqual:UIPasteboard.generalPasteboard.URL]);
 
   // The second pasteboard item has the additional text stored as string.
-  EXPECT_TRUE([kTestAdditionaText
-      isEqualToString:UIPasteboard.generalPasteboard.strings[1]]);
+  EXPECT_NSEQ(kTestAdditionaText, UIPasteboard.generalPasteboard.strings[1]);
 }
diff --git a/ios/chrome/browser/ui/sharing/activity_services/activities/request_desktop_or_mobile_site_activity_unittest.mm b/ios/chrome/browser/ui/sharing/activity_services/activities/request_desktop_or_mobile_site_activity_unittest.mm
index 46f76040..ec94248 100644
--- a/ios/chrome/browser/ui/sharing/activity_services/activities/request_desktop_or_mobile_site_activity_unittest.mm
+++ b/ios/chrome/browser/ui/sharing/activity_services/activities/request_desktop_or_mobile_site_activity_unittest.mm
@@ -15,6 +15,7 @@
 #import "ios/web/public/test/fakes/fake_navigation_manager.h"
 #import "ios/web/public/test/fakes/fake_web_state.h"
 #import "ios/web/public/test/web_task_environment.h"
+#import "testing/gtest_mac.h"
 #import "testing/platform_test.h"
 #import "third_party/ocmock/OCMock/OCMock.h"
 #import "third_party/ocmock/gtest_support.h"
@@ -84,7 +85,7 @@
 
   NSString* requestMobileString =
       l10n_util::GetNSString(IDS_IOS_SHARE_MENU_REQUEST_MOBILE_SITE);
-  EXPECT_TRUE([requestMobileString isEqualToString:activity.activityTitle]);
+  EXPECT_NSEQ(requestMobileString, activity.activityTitle);
 
   [activity performActivity];
 
@@ -109,7 +110,7 @@
 
   NSString* requestDesktopString =
       l10n_util::GetNSString(IDS_IOS_SHARE_MENU_REQUEST_DESKTOP_SITE);
-  EXPECT_TRUE([requestDesktopString isEqualToString:activity.activityTitle]);
+  EXPECT_NSEQ(requestDesktopString, activity.activityTitle);
 
   [activity performActivity];
 
diff --git a/ios/chrome/browser/ui/sharing/qr_generator/qr_generator_util_unittest.mm b/ios/chrome/browser/ui/sharing/qr_generator/qr_generator_util_unittest.mm
index cae7d700..adbe349 100644
--- a/ios/chrome/browser/ui/sharing/qr_generator/qr_generator_util_unittest.mm
+++ b/ios/chrome/browser/ui/sharing/qr_generator/qr_generator_util_unittest.mm
@@ -4,6 +4,7 @@
 
 #import "ios/chrome/browser/ui/sharing/qr_generator/qr_generator_util.h"
 
+#import "testing/gtest_mac.h"
 #import "testing/platform_test.h"
 #import "third_party/ocmock/OCMock/OCMock.h"
 
@@ -47,7 +48,7 @@
   ASSERT_EQ(1U, [features count]);
 
   CIQRCodeFeature* qrCodeFeature = (CIQRCodeFeature*)features[0];
-  EXPECT_TRUE([sampleUrl_ isEqualToString:[qrCodeFeature messageString]]);
+  EXPECT_NSEQ(sampleUrl_, [qrCodeFeature messageString]);
 }
 
 // Tests that GenerateQRCode utility function creates a QR code image of the
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/toolbars/tab_grid_toolbars_view_controllers_unittest.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/toolbars/tab_grid_toolbars_view_controllers_unittest.mm
index 8628f99..90285a8 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/toolbars/tab_grid_toolbars_view_controllers_unittest.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/toolbars/tab_grid_toolbars_view_controllers_unittest.mm
@@ -7,6 +7,7 @@
 
 #import "base/test/metrics/user_action_tester.h"
 #import "ios/chrome/grit/ios_strings.h"
+#import "testing/gtest_mac.h"
 #import "testing/platform_test.h"
 #import "ui/base/l10n/l10n_util.h"
 
@@ -113,9 +114,9 @@
   for (UIKeyCommand* command in top_toolbar_.keyCommands) {
     [top_toolbar_ validateCommand:command];
     if (command.action == @selector(keyCommand_find)) {
-      EXPECT_TRUE([command.discoverabilityTitle
-          isEqualToString:l10n_util::GetNSStringWithFixup(
-                              IDS_IOS_KEYBOARD_SEARCH_TABS)]);
+      EXPECT_NSEQ(
+          command.discoverabilityTitle,
+          l10n_util::GetNSStringWithFixup(IDS_IOS_KEYBOARD_SEARCH_TABS));
     }
   }
 }
diff --git a/ios/components/credential_provider_extension/password_util_unittest.mm b/ios/components/credential_provider_extension/password_util_unittest.mm
index e639317..55e60e9 100644
--- a/ios/components/credential_provider_extension/password_util_unittest.mm
+++ b/ios/components/credential_provider_extension/password_util_unittest.mm
@@ -88,24 +88,24 @@
 TEST_F(PasswordUtilKeychainTest, CheckRestoreOfSavedPasswords) {
   AddPasswordForKey(kCredentialKey1, kCredentialPassword1);
   AddPasswordForKey(kCredentialKey2, kCredentialPassword2);
-  ASSERT_TRUE([PasswordWithKeychainIdentifier(KeyWithPrefix(kCredentialKey2))
-      isEqualToString:kCredentialPassword2]);
-  ASSERT_TRUE([PasswordWithKeychainIdentifier(KeyWithPrefix(kCredentialKey1))
-      isEqualToString:kCredentialPassword1]);
+  EXPECT_NSEQ(PasswordWithKeychainIdentifier(KeyWithPrefix(kCredentialKey2)),
+              kCredentialPassword2);
+  EXPECT_NSEQ(PasswordWithKeychainIdentifier(KeyWithPrefix(kCredentialKey1)),
+              kCredentialPassword1);
   RemovePasswordForKey(kCredentialKey1);
-  ASSERT_TRUE([PasswordWithKeychainIdentifier(KeyWithPrefix(kCredentialKey2))
-      isEqualToString:kCredentialPassword2]);
+  EXPECT_NSEQ(PasswordWithKeychainIdentifier(KeyWithPrefix(kCredentialKey2)),
+              kCredentialPassword2);
   RemovePasswordForKey(kCredentialKey2);
 }
 
 // Tests retrieval of saved passwords, using an empty string as arg.
 TEST_F(PasswordUtilKeychainTest, EmptyArgument) {
-  ASSERT_TRUE([PasswordWithKeychainIdentifier(@"") isEqualToString:@""]);
+  EXPECT_NSEQ(PasswordWithKeychainIdentifier(@""), @"");
 }
 
 // Tests retrieval of saved passwords, nil as arg.
 TEST_F(PasswordUtilKeychainTest, NilArgument) {
-  ASSERT_TRUE([PasswordWithKeychainIdentifier(nil) isEqualToString:@""]);
+  EXPECT_NSEQ(PasswordWithKeychainIdentifier(nil), @"");
 }
 
 // Tests storing passwords with StorePassword.
@@ -115,13 +115,13 @@
   EXPECT_TRUE(StorePasswordInKeychain(kCredentialPassword2,
                                       KeyWithPrefix(kCredentialKey2)));
 
-  ASSERT_TRUE([PasswordWithKeychainIdentifier(KeyWithPrefix(kCredentialKey2))
-      isEqualToString:kCredentialPassword2]);
-  ASSERT_TRUE([PasswordWithKeychainIdentifier(KeyWithPrefix(kCredentialKey1))
-      isEqualToString:kCredentialPassword1]);
+  EXPECT_NSEQ(PasswordWithKeychainIdentifier(KeyWithPrefix(kCredentialKey2)),
+              kCredentialPassword2);
+  EXPECT_NSEQ(PasswordWithKeychainIdentifier(KeyWithPrefix(kCredentialKey1)),
+              kCredentialPassword1);
   RemovePasswordForKey(kCredentialKey1);
-  ASSERT_TRUE([PasswordWithKeychainIdentifier(KeyWithPrefix(kCredentialKey2))
-      isEqualToString:kCredentialPassword2]);
+  EXPECT_NSEQ(PasswordWithKeychainIdentifier(KeyWithPrefix(kCredentialKey2)),
+              kCredentialPassword2);
   RemovePasswordForKey(kCredentialKey2);
 }
 
diff --git a/ios/net/cookies/system_cookie_store_unittest_template.h b/ios/net/cookies/system_cookie_store_unittest_template.h
index a627803..a81ffd8 100644
--- a/ios/net/cookies/system_cookie_store_unittest_template.h
+++ b/ios/net/cookies/system_cookie_store_unittest_template.h
@@ -7,18 +7,19 @@
 
 #import <Foundation/Foundation.h>
 
-#include "base/barrier_closure.h"
-#include "base/functional/bind.h"
-#include "base/functional/callback.h"
-#include "base/memory/ptr_util.h"
-#include "base/run_loop.h"
+#import "base/barrier_closure.h"
+#import "base/functional/bind.h"
+#import "base/functional/callback.h"
+#import "base/memory/ptr_util.h"
+#import "base/run_loop.h"
 #import "base/test/ios/wait_util.h"
-#include "ios/net/cookies/cookie_store_ios_test_util.h"
+#import "ios/net/cookies/cookie_store_ios_test_util.h"
 #import "ios/net/cookies/system_cookie_store.h"
 #import "net/base/apple/url_conversions.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-#include "url/gurl.h"
+#import "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
+#import "testing/platform_test.h"
+#import "url/gurl.h"
 
 namespace net {
 
@@ -151,8 +152,8 @@
 
     EXPECT_EQ(1u, result_cookies.count);
     NSHTTPCookie* result_cookie = result_cookies[0];
-    EXPECT_TRUE([input_cookie.name isEqualToString:result_cookie.name]);
-    EXPECT_TRUE([input_cookie.value isEqualToString:result_cookie.value]);
+    EXPECT_NSEQ(input_cookie.name, result_cookie.name);
+    EXPECT_NSEQ(input_cookie.value, result_cookie.value);
   }
 
   // Test GetAllCookies
@@ -169,9 +170,9 @@
     for (NSHTTPCookie* cookie in result_cookies) {
       NSHTTPCookie* existing_cookie = [input_cookies valueForKey:cookie.name];
       EXPECT_TRUE(existing_cookie);
-      EXPECT_TRUE([existing_cookie.name isEqualToString:cookie.name]);
-      EXPECT_TRUE([existing_cookie.value isEqualToString:cookie.value]);
-      EXPECT_TRUE([existing_cookie.domain isEqualToString:cookie.domain]);
+      EXPECT_NSEQ(existing_cookie.name, cookie.name);
+      EXPECT_NSEQ(existing_cookie.value, cookie.value);
+      EXPECT_NSEQ(existing_cookie.domain, cookie.domain);
     }
   }
 }
diff --git a/ios/testing/scoped_block_swizzler_unittest.mm b/ios/testing/scoped_block_swizzler_unittest.mm
index 586412a4..a196122d 100644
--- a/ios/testing/scoped_block_swizzler_unittest.mm
+++ b/ios/testing/scoped_block_swizzler_unittest.mm
@@ -51,8 +51,7 @@
   target.value = kSwizzledInstanceValue;
 
   EXPECT_NSEQ(kOriginalInstanceValue, [target instanceMethodToSwizzle]);
-  EXPECT_FALSE([[target instanceMethodToSwizzle]
-      isEqualToString:kSwizzledInstanceValue]);
+  EXPECT_NSNE([target instanceMethodToSwizzle], kSwizzledInstanceValue);
 
   {
     id block = ^NSString*(id self) {
diff --git a/ios/web_view/internal/translate/web_view_translate_client.mm b/ios/web_view/internal/translate/web_view_translate_client.mm
index 16d524e0..51709c31 100644
--- a/ios/web_view/internal/translate/web_view_translate_client.mm
+++ b/ios/web_view/internal/translate/web_view_translate_client.mm
@@ -47,7 +47,7 @@
     language::AcceptLanguagesService* accept_languages)
     : pref_service_(pref_service),
       translate_driver_(web_state,
-                        /*translate_model_service=*/nullptr),
+                        /*language_detection_model_service=*/nullptr),
       translate_manager_(this, translate_ranker, language_model),
       accept_languages_(accept_languages) {
   DCHECK(pref_service_);
diff --git a/ios_internal b/ios_internal
index cb9d0f30..7a2df94 160000
--- a/ios_internal
+++ b/ios_internal
@@ -1 +1 @@
-Subproject commit cb9d0f308d6dd05d93f35f9e1fd6098fb968839a
+Subproject commit 7a2df944059b4837fd4c2cfabe6b251b3c8c6b47
diff --git a/media/base/offloading_audio_encoder.cc b/media/base/offloading_audio_encoder.cc
index 9a6e0ed..9667ab2 100644
--- a/media/base/offloading_audio_encoder.cc
+++ b/media/base/offloading_audio_encoder.cc
@@ -13,8 +13,8 @@
 
 OffloadingAudioEncoder::OffloadingAudioEncoder(
     std::unique_ptr<AudioEncoder> wrapped_encoder,
-    const scoped_refptr<base::SequencedTaskRunner> work_runner,
-    const scoped_refptr<base::SequencedTaskRunner> callback_runner)
+    scoped_refptr<base::SequencedTaskRunner> work_runner,
+    scoped_refptr<base::SequencedTaskRunner> callback_runner)
     : wrapped_encoder_(std::move(wrapped_encoder)),
       work_runner_(std::move(work_runner)),
       callback_runner_(std::move(callback_runner)) {
diff --git a/media/base/offloading_audio_encoder.h b/media/base/offloading_audio_encoder.h
index af67ffe..4c82cd4 100644
--- a/media/base/offloading_audio_encoder.h
+++ b/media/base/offloading_audio_encoder.h
@@ -27,8 +27,8 @@
   // runner.
   OffloadingAudioEncoder(
       std::unique_ptr<AudioEncoder> wrapped_encoder,
-      const scoped_refptr<base::SequencedTaskRunner> work_runner,
-      const scoped_refptr<base::SequencedTaskRunner> callback_runner);
+      scoped_refptr<base::SequencedTaskRunner> work_runner,
+      scoped_refptr<base::SequencedTaskRunner> callback_runner);
 
   // Uses current task runner for callbacks and asks thread pool for a new task
   // runner to do actual encoding work.
diff --git a/media/video/gpu_memory_buffer_video_frame_pool.cc b/media/video/gpu_memory_buffer_video_frame_pool.cc
index 7af6843f..54696f08 100644
--- a/media/video/gpu_memory_buffer_video_frame_pool.cc
+++ b/media/video/gpu_memory_buffer_video_frame_pool.cc
@@ -478,59 +478,94 @@
 }
 
 void CopyRowsToNV12Buffer(int first_row,
-                          int rows_y,
-                          int rows_uv,
-                          int bytes_per_row_y,
-                          int bytes_per_row_uv,
+                          int rows,
+                          int width,
+                          size_t bit_depth,
                           const VideoFrame* source_frame,
                           uint8_t* dest_y,
                           int dest_stride_y,
                           uint8_t* dest_uv,
                           int dest_stride_uv) {
-  TRACE_EVENT2("media", "CopyRowsToNV12Buffer", "bytes_per_row",
-               bytes_per_row_y, "rows", rows_y);
+  TRACE_EVENT2("media", "CopyRowsToNV12Buffer", "width", width, "rows", rows);
 
   if (!dest_y || !dest_uv)
     return;
 
   DCHECK_NE(dest_stride_y, 0);
   DCHECK_NE(dest_stride_uv, 0);
-  DCHECK_LE(bytes_per_row_y, std::abs(dest_stride_y));
-  DCHECK_LE(bytes_per_row_uv, std::abs(dest_stride_uv));
   DCHECK_EQ(0, first_row % 2);
   DCHECK(source_frame->format() == PIXEL_FORMAT_I420 ||
          source_frame->format() == PIXEL_FORMAT_YV12 ||
-         source_frame->format() == PIXEL_FORMAT_NV12);
-  if (source_frame->format() == PIXEL_FORMAT_NV12) {
-    libyuv::CopyPlane(
+         source_frame->format() == PIXEL_FORMAT_NV12 ||
+         source_frame->format() == PIXEL_FORMAT_YUV420P10);
+
+  if (bit_depth == 8) {
+    const int rows_y =
+        VideoFrame::Rows(VideoFrame::Plane::kY, PIXEL_FORMAT_NV12, rows);
+    const int rows_uv =
+        VideoFrame::Rows(VideoFrame::Plane::kUV, PIXEL_FORMAT_NV12, rows);
+    const int bytes_per_row_y =
+        VideoFrame::RowBytes(VideoFrame::Plane::kY, PIXEL_FORMAT_NV12, width);
+    const int bytes_per_row_uv =
+        VideoFrame::RowBytes(VideoFrame::Plane::kUV, PIXEL_FORMAT_NV12, width);
+    DCHECK_LE(bytes_per_row_y, std::abs(dest_stride_y));
+    DCHECK_LE(bytes_per_row_uv, std::abs(dest_stride_uv));
+
+    if (source_frame->format() == PIXEL_FORMAT_NV12) {
+      libyuv::CopyPlane(
+          source_frame->visible_data(VideoFrame::Plane::kY) +
+              first_row * source_frame->stride(VideoFrame::Plane::kY),
+          source_frame->stride(VideoFrame::Plane::kY),
+          dest_y + first_row * dest_stride_y, dest_stride_y, bytes_per_row_y,
+          rows_y);
+      libyuv::CopyPlane(
+          source_frame->visible_data(VideoFrame::Plane::kUV) +
+              first_row / 2 * source_frame->stride(VideoFrame::Plane::kUV),
+          source_frame->stride(VideoFrame::Plane::kUV),
+          dest_uv + first_row / 2 * dest_stride_uv, dest_stride_uv,
+          bytes_per_row_uv, rows_uv);
+
+      return;
+    }
+
+    libyuv::I420ToNV12(
         source_frame->visible_data(VideoFrame::Plane::kY) +
             first_row * source_frame->stride(VideoFrame::Plane::kY),
         source_frame->stride(VideoFrame::Plane::kY),
-        dest_y + first_row * dest_stride_y, dest_stride_y, bytes_per_row_y,
-        rows_y);
-    libyuv::CopyPlane(
-        source_frame->visible_data(VideoFrame::Plane::kUV) +
-            first_row / 2 * source_frame->stride(VideoFrame::Plane::kUV),
-        source_frame->stride(VideoFrame::Plane::kUV),
+        source_frame->visible_data(VideoFrame::Plane::kU) +
+            first_row / 2 * source_frame->stride(VideoFrame::Plane::kU),
+        source_frame->stride(VideoFrame::Plane::kU),
+        source_frame->visible_data(VideoFrame::Plane::kV) +
+            first_row / 2 * source_frame->stride(VideoFrame::Plane::kV),
+        source_frame->stride(VideoFrame::Plane::kV),
+        dest_y + first_row * dest_stride_y, dest_stride_y,
         dest_uv + first_row / 2 * dest_stride_uv, dest_stride_uv,
-        bytes_per_row_uv, rows_uv);
+        bytes_per_row_y, rows_y);
+  } else {
+    DCHECK_LE(width * 2, source_frame->stride(VideoFrame::Plane::kY));
 
-    return;
+    const uint16_t* y_plane = reinterpret_cast<const uint16_t*>(
+        source_frame->visible_data(VideoFrame::Plane::kY) +
+        first_row * source_frame->stride(VideoFrame::Plane::kY));
+    const size_t y_plane_stride =
+        source_frame->stride(VideoFrame::Plane::kY) / 2;
+    const uint16_t* u_plane = reinterpret_cast<const uint16_t*>(
+        source_frame->visible_data(VideoFrame::Plane::kU) +
+        (first_row / 2) * source_frame->stride(VideoFrame::Plane::kU));
+    const size_t u_plane_stride =
+        source_frame->stride(VideoFrame::Plane::kU) / 2;
+    const uint16_t* v_plane = reinterpret_cast<const uint16_t*>(
+        source_frame->visible_data(VideoFrame::Plane::kV) +
+        (first_row / 2) * source_frame->stride(VideoFrame::Plane::kV));
+    const size_t v_plane_stride =
+        source_frame->stride(VideoFrame::Plane::kV) / 2;
+
+    libyuv::I010ToNV12(y_plane, y_plane_stride, u_plane, u_plane_stride,
+                       v_plane, v_plane_stride,
+                       dest_y + first_row * dest_stride_y, dest_stride_y,
+                       dest_uv + (first_row / 2) * dest_stride_uv,
+                       dest_stride_uv, width, rows);
   }
-
-  libyuv::I420ToNV12(
-      source_frame->visible_data(VideoFrame::Plane::kY) +
-          first_row * source_frame->stride(VideoFrame::Plane::kY),
-      source_frame->stride(VideoFrame::Plane::kY),
-      source_frame->visible_data(VideoFrame::Plane::kU) +
-          first_row / 2 * source_frame->stride(VideoFrame::Plane::kU),
-      source_frame->stride(VideoFrame::Plane::kU),
-      source_frame->visible_data(VideoFrame::Plane::kV) +
-          first_row / 2 * source_frame->stride(VideoFrame::Plane::kV),
-      source_frame->stride(VideoFrame::Plane::kV),
-      dest_y + first_row * dest_stride_y, dest_stride_y,
-      dest_uv + first_row / 2 * dest_stride_uv, dest_stride_uv, bytes_per_row_y,
-      rows_y);
 }
 
 void CopyRowsToRGB10Buffer(bool is_argb,
@@ -1044,25 +1079,14 @@
           scoped_mapping ? scoped_mapping->Stride(1) : buffer->stride(1));
       break;
 
-    case GpuVideoAcceleratorFactories::OutputFormat::NV12: {
-      const size_t rows_to_copy_y = VideoFrame::Rows(
-          VideoFrame::Plane::kY, VideoFormat(output_format), rows_to_copy);
-      const size_t rows_to_copy_uv = VideoFrame::Rows(
-          VideoFrame::Plane::kUV, VideoFormat(output_format), rows_to_copy);
-      const size_t bytes_per_row_y =
-          VideoFrame::RowBytes(VideoFrame::Plane::kY,
-                               VideoFormat(output_format), coded_size.width());
-      const size_t bytes_per_row_uv =
-          VideoFrame::RowBytes(VideoFrame::Plane::kUV,
-                               VideoFormat(output_format), coded_size.width());
+    case GpuVideoAcceleratorFactories::OutputFormat::NV12:
       CopyRowsToNV12Buffer(
-          row, rows_to_copy_y, rows_to_copy_uv, bytes_per_row_y,
-          bytes_per_row_uv, video_frame, memory_ptr0, stride0,
+          row, rows_to_copy, coded_size.width(), video_frame->BitDepth(),
+          video_frame, memory_ptr0, stride0,
           static_cast<uint8_t*>(scoped_mapping ? scoped_mapping->Memory(1)
                                                : buffer->memory(1)),
           scoped_mapping ? scoped_mapping->Stride(1) : buffer->stride(1));
       break;
-    }
 
     case GpuVideoAcceleratorFactories::OutputFormat::XR30:
     case GpuVideoAcceleratorFactories::OutputFormat::XB30: {
diff --git a/net/base/registry_controlled_domains/effective_tld_names.dat b/net/base/registry_controlled_domains/effective_tld_names.dat
index 3e106bd7ee..a78ce52a 100644
--- a/net/base/registry_controlled_domains/effective_tld_names.dat
+++ b/net/base/registry_controlled_domains/effective_tld_names.dat
@@ -22,7 +22,7 @@
 mil.ac
 org.ac
 
-// ad : https://en.wikipedia.org/wiki/.ad
+// ad : https://www.iana.org/domains/root/db/ad.html
 ad
 nom.ad
 
@@ -36,22 +36,30 @@
 gov.ae
 mil.ae
 
-// aero : see https://www.information.aero/index.php?id=66
+// aero : https://information.aero/registration/policies/dmp
 aero
+// 2LDs
+airline.aero
+airport.aero
+// 2LDs (currently not accepting registration, seemingly never have)
+// As of 2024-07, these are marked as reserved for potential 3LD
+// registrations (clause 11 "allocated subdomains" in the 2006 TLD
+// policy), but the relevant industry partners have not opened them up
+// for registration. Current status can be determined from the TLD's
+// policy document: 2LDs that are open for registration must list
+// their policy in the TLD's policy. Any 2LD without such a policy is
+// not open for registrations.
 accident-investigation.aero
 accident-prevention.aero
 aerobatic.aero
 aeroclub.aero
 aerodrome.aero
 agents.aero
-aircraft.aero
-airline.aero
-airport.aero
 air-surveillance.aero
-airtraffic.aero
 air-traffic-control.aero
+aircraft.aero
+airtraffic.aero
 ambulance.aero
-amusement.aero
 association.aero
 author.aero
 ballooning.aero
@@ -82,6 +90,7 @@
 express.aero
 federation.aero
 flight.aero
+freight.aero
 fuel.aero
 gliding.aero
 government.aero
@@ -96,6 +105,7 @@
 logistics.aero
 magazine.aero
 maintenance.aero
+marketplace.aero
 media.aero
 microlight.aero
 modelling.aero
@@ -118,6 +128,7 @@
 skydiving.aero
 software.aero
 student.aero
+taxi.aero
 trader.aero
 trading.aero
 trainer.aero
@@ -165,7 +176,7 @@
 net.am
 org.am
 
-// ao : https://en.wikipedia.org/wiki/.ao
+// ao : https://www.iana.org/domains/root/db/ao.html
 // http://www.dns.ao/REGISTR.DOC
 ao
 ed.ao
@@ -175,7 +186,7 @@
 pb.ao
 it.ao
 
-// aq : https://en.wikipedia.org/wiki/.aq
+// aq : https://www.iana.org/domains/root/db/aq.html
 aq
 
 // ar : https://nic.ar/es/nic-argentina/normativa
@@ -195,7 +206,7 @@
 senasa.ar
 tur.ar
 
-// arpa : https://en.wikipedia.org/wiki/.arpa
+// arpa : https://www.iana.org/domains/root/db/arpa.html
 // Confirmed by registry <iana-questions@icann.org> 2008-06-18
 arpa
 e164.arpa
@@ -205,14 +216,14 @@
 uri.arpa
 urn.arpa
 
-// as : https://en.wikipedia.org/wiki/.as
+// as : https://www.iana.org/domains/root/db/as.html
 as
 gov.as
 
-// asia : https://en.wikipedia.org/wiki/.asia
+// asia : https://www.iana.org/domains/root/db/asia.html
 asia
 
-// at : https://en.wikipedia.org/wiki/.at
+// at : https://www.iana.org/domains/root/db/at.html
 // Confirmed by registry <it@nic.at> 2008-06-17
 at
 ac.at
@@ -221,7 +232,7 @@
 or.at
 sth.ac.at
 
-// au : https://en.wikipedia.org/wiki/.au
+// au : https://www.iana.org/domains/root/db/au.html
 // http://www.auda.org.au/
 au
 // 2LDs
@@ -268,14 +279,14 @@
 // education.tas.edu.au - Removed at the request of the Department of Education Tasmania
 schools.nsw.edu.au
 
-// aw : https://en.wikipedia.org/wiki/.aw
+// aw : https://www.iana.org/domains/root/db/aw.html
 aw
 com.aw
 
-// ax : https://en.wikipedia.org/wiki/.ax
+// ax : https://www.iana.org/domains/root/db/ax.html
 ax
 
-// az : https://en.wikipedia.org/wiki/.az
+// az : https://www.iana.org/domains/root/db/az.html
 az
 com.az
 net.az
@@ -299,7 +310,7 @@
 net.ba
 org.ba
 
-// bb : https://en.wikipedia.org/wiki/.bb
+// bb : https://www.iana.org/domains/root/db/bb.html
 bb
 biz.bb
 co.bb
@@ -312,19 +323,19 @@
 store.bb
 tv.bb
 
-// bd : https://en.wikipedia.org/wiki/.bd
+// bd : https://www.iana.org/domains/root/db/bd.html
 *.bd
 
-// be : https://en.wikipedia.org/wiki/.be
+// be : https://www.iana.org/domains/root/db/be.html
 // Confirmed by registry <tech@dns.be> 2008-06-08
 be
 ac.be
 
-// bf : https://en.wikipedia.org/wiki/.bf
+// bf : https://www.iana.org/domains/root/db/bf.html
 bf
 gov.bf
 
-// bg : https://en.wikipedia.org/wiki/.bg
+// bg : https://www.iana.org/domains/root/db/bg.html
 // https://www.register.bg/user/static/rules/en/index.html
 bg
 a.bg
@@ -364,7 +375,7 @@
 8.bg
 9.bg
 
-// bh : https://en.wikipedia.org/wiki/.bh
+// bh : https://www.iana.org/domains/root/db/bh.html
 bh
 com.bh
 edu.bh
@@ -372,7 +383,7 @@
 org.bh
 gov.bh
 
-// bi : https://en.wikipedia.org/wiki/.bi
+// bi : https://www.iana.org/domains/root/db/bi.html
 // http://whois.nic.bi/
 bi
 co.bi
@@ -381,7 +392,7 @@
 or.bi
 org.bi
 
-// biz : https://en.wikipedia.org/wiki/.biz
+// biz : https://www.iana.org/domains/root/db/biz.html
 biz
 
 // bj : https://nic.bj/bj-suffixes.txt
@@ -650,7 +661,7 @@
 edu.bs
 gov.bs
 
-// bt : https://en.wikipedia.org/wiki/.bt
+// bt : https://www.iana.org/domains/root/db/bt.html
 bt
 com.bt
 edu.bt
@@ -662,14 +673,14 @@
 // Submitted by registry <jarle@uninett.no>
 bv
 
-// bw : https://en.wikipedia.org/wiki/.bw
+// bw : https://www.iana.org/domains/root/db/bw.html
 // http://www.gobin.info/domainname/bw.doc
 // list of other 2nd level tlds ?
 bw
 co.bw
 org.bw
 
-// by : https://en.wikipedia.org/wiki/.by
+// by : https://www.iana.org/domains/root/db/by.html
 // http://tld.by/rules_2006_en.html
 // list of other 2nd level tlds ?
 by
@@ -679,11 +690,10 @@
 // second-level domain, but it's being used as one (see www.google.com.by and
 // www.yahoo.com.by, for example), so we list it here for safety's sake.
 com.by
-
 // http://hoster.by/
 of.by
 
-// bz : https://en.wikipedia.org/wiki/.bz
+// bz : https://www.iana.org/domains/root/db/bz.html
 // http://www.belizenic.bz/
 bz
 com.bz
@@ -692,7 +702,7 @@
 edu.bz
 gov.bz
 
-// ca : https://en.wikipedia.org/wiki/.ca
+// ca : https://www.iana.org/domains/root/db/ca.html
 ca
 // ca geographical names
 ab.ca
@@ -713,27 +723,27 @@
 // see also: http://registry.gc.ca/en/SubdomainFAQ
 gc.ca
 
-// cat : https://en.wikipedia.org/wiki/.cat
+// cat : https://www.iana.org/domains/root/db/cat.html
 cat
 
-// cc : https://en.wikipedia.org/wiki/.cc
+// cc : https://www.iana.org/domains/root/db/cc.html
 cc
 
-// cd : https://en.wikipedia.org/wiki/.cd
+// cd : https://www.iana.org/domains/root/db/cd.html
 // see also: https://www.nic.cd/domain/insertDomain_2.jsp?act=1
 cd
 gov.cd
 
-// cf : https://en.wikipedia.org/wiki/.cf
+// cf : https://www.iana.org/domains/root/db/cf.html
 cf
 
-// cg : https://en.wikipedia.org/wiki/.cg
+// cg : https://www.iana.org/domains/root/db/cg.html
 cg
 
-// ch : https://en.wikipedia.org/wiki/.ch
+// ch : https://www.iana.org/domains/root/db/ch.html
 ch
 
-// ci : https://en.wikipedia.org/wiki/.ci
+// ci : https://www.iana.org/domains/root/db/ci.html
 // http://www.nic.ci/index.php?page=charte
 ci
 org.ci
@@ -752,7 +762,7 @@
 md.ci
 gouv.ci
 
-// ck : https://en.wikipedia.org/wiki/.ck
+// ck : https://www.iana.org/domains/root/db/ck.html
 *.ck
 !www.ck
 
@@ -764,14 +774,14 @@
 gov.cl
 mil.cl
 
-// cm : https://en.wikipedia.org/wiki/.cm plus bug 981927
+// cm : https://www.iana.org/domains/root/db/cm.html plus bug 981927
 cm
 co.cm
 com.cm
 gov.cm
 net.cm
 
-// cn : https://en.wikipedia.org/wiki/.cn
+// cn : https://www.iana.org/domains/root/db/cn.html
 // Submitted by registry <tanyaling@cnnic.cn>
 cn
 ac.cn
@@ -820,7 +830,7 @@
 mo.cn
 tw.cn
 
-// co : https://en.wikipedia.org/wiki/.co
+// co : https://www.iana.org/domains/root/db/co.html
 // Submitted by registry <tecnico@uniandes.edu.co>
 co
 arts.co
@@ -837,10 +847,10 @@
 rec.co
 web.co
 
-// com : https://en.wikipedia.org/wiki/.com
+// com : https://www.iana.org/domains/root/db/com.html
 com
 
-// coop : https://en.wikipedia.org/wiki/.coop
+// coop : https://www.iana.org/domains/root/db/coop.html
 coop
 
 // cr : http://www.nic.cr/niccr_publico/showRegistroDominiosScreen.do
@@ -853,16 +863,18 @@
 or.cr
 sa.cr
 
-// cu : https://en.wikipedia.org/wiki/.cu
+// cu : https://www.iana.org/domains/root/db/cu.html
 cu
 com.cu
 edu.cu
-org.cu
-net.cu
+gob.cu
 gov.cu
 inf.cu
+nat.cu
+net.cu
+org.cu
 
-// cv : https://en.wikipedia.org/wiki/.cv
+// cv : https://www.iana.org/domains/root/db/cv.html
 // cv : http://www.dns.cv/tldcv_portal/do?com=DS;5446457100;111;+PAGE(4000018)+K-CAT-CODIGO(RDOM)+RCNT(100); <- registration rules
 cv
 com.cv
@@ -879,7 +891,7 @@
 net.cw
 org.cw
 
-// cx : https://en.wikipedia.org/wiki/.cx
+// cx : https://www.iana.org/domains/root/db/cx.html
 // list of other 2nd level tlds ?
 cx
 gov.cx
@@ -901,22 +913,22 @@
 pro.cy
 tm.cy
 
-// cz : https://en.wikipedia.org/wiki/.cz
+// cz : https://www.iana.org/domains/root/db/cz.html
 cz
 
-// de : https://en.wikipedia.org/wiki/.de
+// de : https://www.iana.org/domains/root/db/de.html
 // Confirmed by registry <ops@denic.de> (with technical
 // reservations) 2008-07-01
 de
 
-// dj : https://en.wikipedia.org/wiki/.dj
+// dj : https://www.iana.org/domains/root/db/dj.html
 dj
 
-// dk : https://en.wikipedia.org/wiki/.dk
+// dk : https://www.iana.org/domains/root/db/dk.html
 // Confirmed by registry <robert@dk-hostmaster.dk> 2008-06-17
 dk
 
-// dm : https://en.wikipedia.org/wiki/.dm
+// dm : https://www.iana.org/domains/root/db/dm.html
 dm
 com.dm
 net.dm
@@ -924,7 +936,7 @@
 edu.dm
 gov.dm
 
-// do : https://en.wikipedia.org/wiki/.do
+// do : https://www.iana.org/domains/root/db/do.html
 do
 art.do
 com.do
@@ -966,7 +978,7 @@
 gob.ec
 mil.ec
 
-// edu : https://en.wikipedia.org/wiki/.edu
+// edu : https://www.iana.org/domains/root/db/edu.html
 edu
 
 // ee : http://www.eenet.ee/EENet/dom_reeglid.html#lisa_B
@@ -982,7 +994,7 @@
 org.ee
 fie.ee
 
-// eg : https://en.wikipedia.org/wiki/.eg
+// eg : https://www.iana.org/domains/root/db/eg.html
 eg
 com.eg
 edu.eg
@@ -994,7 +1006,7 @@
 org.eg
 sci.eg
 
-// er : https://en.wikipedia.org/wiki/.er
+// er : https://www.iana.org/domains/root/db/er.html
 *.er
 
 // es : https://www.nic.es/site_ingles/ingles/dominios/index.html
@@ -1005,7 +1017,7 @@
 gob.es
 edu.es
 
-// et : https://en.wikipedia.org/wiki/.et
+// et : https://www.iana.org/domains/root/db/et.html
 et
 com.et
 gov.et
@@ -1016,16 +1028,15 @@
 info.et
 net.et
 
-// eu : https://en.wikipedia.org/wiki/.eu
+// eu : https://www.iana.org/domains/root/db/eu.html
 eu
 
-// fi : https://en.wikipedia.org/wiki/.fi
+// fi : https://www.iana.org/domains/root/db/fi.html
 fi
-// aland.fi : https://en.wikipedia.org/wiki/.ax
+// aland.fi : https://www.iana.org/domains/root/db/ax.html
 // This domain is being phased out in favor of .ax. As there are still many
 // domains under aland.fi, we still keep it on the list until aland.fi is
 // completely removed.
-// TODO: Check for updates (expected to be phased out around Q1/2009)
 aland.fi
 
 // fj : http://domains.fj/
@@ -1042,17 +1053,17 @@
 org.fj
 pro.fj
 
-// fk : https://en.wikipedia.org/wiki/.fk
+// fk : https://www.iana.org/domains/root/db/fk.html
 *.fk
 
-// fm : https://en.wikipedia.org/wiki/.fm
+// fm : https://www.iana.org/domains/root/db/fm.html
 com.fm
 edu.fm
 net.fm
 org.fm
 fm
 
-// fo : https://en.wikipedia.org/wiki/.fo
+// fo : https://www.iana.org/domains/root/db/fo.html
 fo
 
 // fr : https://www.afnic.fr/ https://www.afnic.fr/wp-media/uploads/2022/12/afnic-naming-policy-2023-01-01.pdf
@@ -1069,14 +1080,14 @@
 greta.fr
 huissier-justice.fr
 
-// ga : https://en.wikipedia.org/wiki/.ga
+// ga : https://www.iana.org/domains/root/db/ga.html
 ga
 
 // gb : This registry is effectively dormant
 // Submitted by registry <Damien.Shaw@ja.net>
 gb
 
-// gd : https://en.wikipedia.org/wiki/.gd
+// gd : https://www.iana.org/domains/root/db/gd.html
 edu.gd
 gov.gd
 gd
@@ -1091,7 +1102,7 @@
 net.ge
 pvt.ge
 
-// gf : https://en.wikipedia.org/wiki/.gf
+// gf : https://www.iana.org/domains/root/db/gf.html
 gf
 
 // gg : http://www.channelisles.net/register-domains/
@@ -1101,7 +1112,7 @@
 net.gg
 org.gg
 
-// gh : https://en.wikipedia.org/wiki/.gh
+// gh : https://www.iana.org/domains/root/db/gh.html
 // see also: http://www.nic.gh/reg_now.php
 // Although domains directly at second level are not possible at the moment,
 // they have been possible for some time and may come back.
@@ -1121,7 +1132,7 @@
 edu.gi
 org.gi
 
-// gl : https://en.wikipedia.org/wiki/.gl
+// gl : https://www.iana.org/domains/root/db/gl.html
 // http://nic.gl
 gl
 co.gl
@@ -1143,7 +1154,7 @@
 org.gn
 net.gn
 
-// gov : https://en.wikipedia.org/wiki/.gov
+// gov : https://www.iana.org/domains/root/db/gov.html
 gov
 
 // gp : http://www.nic.gp/index.php?lang=en
@@ -1155,7 +1166,7 @@
 org.gp
 asso.gp
 
-// gq : https://en.wikipedia.org/wiki/.gq
+// gq : https://www.iana.org/domains/root/db/gq.html
 gq
 
 // gr : https://grweb.ics.forth.gr/english/1617-B-2005.html
@@ -1167,7 +1178,7 @@
 org.gr
 gov.gr
 
-// gs : https://en.wikipedia.org/wiki/.gs
+// gs : https://www.iana.org/domains/root/db/gs.html
 gs
 
 // gt : https://www.gt/sitio/registration_policy.php?lang=en
@@ -1193,11 +1204,11 @@
 org.gu
 web.gu
 
-// gw : https://en.wikipedia.org/wiki/.gw
+// gw : https://www.iana.org/domains/root/db/gw.html
 // gw : https://nic.gw/regras/
 gw
 
-// gy : https://en.wikipedia.org/wiki/.gy
+// gy : https://www.iana.org/domains/root/db/gy.html
 // http://registry.gy/
 gy
 co.gy
@@ -1232,7 +1243,7 @@
 組織.hk
 組织.hk
 
-// hm : https://en.wikipedia.org/wiki/.hm
+// hm : https://www.iana.org/domains/root/db/hm.html
 hm
 
 // hn : http://www.nic.hn/politicas/ps02,,05.html
@@ -1321,7 +1332,7 @@
 sch.id
 web.id
 
-// ie : https://en.wikipedia.org/wiki/.ie
+// ie : https://www.iana.org/domains/root/db/ie.html
 ie
 gov.ie
 
@@ -1361,7 +1372,7 @@
 tt.im
 tv.im
 
-// in : https://en.wikipedia.org/wiki/.in
+// in : https://www.iana.org/domains/root/db/in.html
 // see also: https://registry.in/policies
 // Please note, that nic.in is not an official eTLD, but used by most
 // government institutions.
@@ -1408,10 +1419,10 @@
 up.in
 us.in
 
-// info : https://en.wikipedia.org/wiki/.info
+// info : https://www.iana.org/domains/root/db/info.html
 info
 
-// int : https://en.wikipedia.org/wiki/.int
+// int : https://www.iana.org/domains/root/db/int.html
 // Confirmed by registry <iana-questions@icann.org> 2008-06-18
 int
 eu.int
@@ -1456,7 +1467,7 @@
 org.is
 int.is
 
-// it : https://en.wikipedia.org/wiki/.it
+// it : https://www.iana.org/domains/root/db/it.html
 it
 gov.it
 edu.it
@@ -1890,10 +1901,10 @@
 mil.jo
 name.jo
 
-// jobs : https://en.wikipedia.org/wiki/.jobs
+// jobs : https://www.iana.org/domains/root/db/jobs.html
 jobs
 
-// jp : https://en.wikipedia.org/wiki/.jp
+// jp : https://www.iana.org/domains/root/db/jp.html
 // http://jprs.co.jp/en/jpdomain.html
 // Submitted by registry <info@jprs.jp>
 jp
@@ -2005,18 +2016,18 @@
 // jp geographic type names
 // http://jprs.jp/doc/rule/saisoku-1.html
 *.kawasaki.jp
-*.kitakyushu.jp
-*.kobe.jp
-*.nagoya.jp
-*.sapporo.jp
-*.sendai.jp
-*.yokohama.jp
 !city.kawasaki.jp
+*.kitakyushu.jp
 !city.kitakyushu.jp
+*.kobe.jp
 !city.kobe.jp
+*.nagoya.jp
 !city.nagoya.jp
+*.sapporo.jp
 !city.sapporo.jp
+*.sendai.jp
 !city.sendai.jp
+*.yokohama.jp
 !city.yokohama.jp
 // 4th level registration
 aisai.aichi.jp
@@ -3727,7 +3738,7 @@
 info.ki
 com.ki
 
-// km : https://en.wikipedia.org/wiki/.km
+// km : https://www.iana.org/domains/root/db/km.html
 // http://www.domaine.km/documents/charte.doc
 km
 org.km
@@ -3740,7 +3751,7 @@
 ass.km
 com.km
 // These are only mentioned as proposed suggestions at domaine.km, but
-// https://en.wikipedia.org/wiki/.km says they're available for registration:
+// https://www.iana.org/domains/root/db/km.html says they're available for registration:
 coop.km
 asso.km
 presse.km
@@ -3750,7 +3761,7 @@
 veterinaire.km
 gouv.km
 
-// kn : https://en.wikipedia.org/wiki/.kn
+// kn : https://www.iana.org/domains/root/db/kn.html
 // http://www.dot.kn/domainRules.html
 kn
 net.kn
@@ -3767,7 +3778,7 @@
 rep.kp
 tra.kp
 
-// kr : https://en.wikipedia.org/wiki/.kr
+// kr : https://www.iana.org/domains/root/db/kr.html
 // see also: http://domain.nida.or.kr/eng/registration.jsp
 kr
 ac.kr
@@ -3820,7 +3831,7 @@
 net.ky
 org.ky
 
-// kz : https://en.wikipedia.org/wiki/.kz
+// kz : https://www.iana.org/domains/root/db/kz.html
 // see also: http://www.nic.kz/rules/index.jsp
 kz
 org.kz
@@ -3830,7 +3841,7 @@
 mil.kz
 com.kz
 
-// la : https://en.wikipedia.org/wiki/.la
+// la : https://www.iana.org/domains/root/db/la.html
 // Submitted by registry <gavin.brown@nic.la>
 la
 int.la
@@ -3842,7 +3853,7 @@
 com.la
 org.la
 
-// lb : https://en.wikipedia.org/wiki/.lb
+// lb : https://www.iana.org/domains/root/db/lb.html
 // Submitted by registry <randy@psg.com>
 lb
 com.lb
@@ -3851,7 +3862,7 @@
 net.lb
 org.lb
 
-// lc : https://en.wikipedia.org/wiki/.lc
+// lc : https://www.iana.org/domains/root/db/lc.html
 // see also: http://www.nic.lc/rules.htm
 lc
 com.lc
@@ -3861,7 +3872,7 @@
 edu.lc
 gov.lc
 
-// li : https://en.wikipedia.org/wiki/.li
+// li : https://www.iana.org/domains/root/db/li.html
 li
 
 // lk : https://www.nic.lk/index.php/domain-registration/lk-domain-naming-structure
@@ -3904,7 +3915,7 @@
 org.ls
 sc.ls
 
-// lt : https://en.wikipedia.org/wiki/.lt
+// lt : https://www.iana.org/domains/root/db/lt.html
 lt
 // gov.lt : http://www.gov.lt/index_en.php
 gov.lt
@@ -3936,7 +3947,7 @@
 org.ly
 id.ly
 
-// ma : https://en.wikipedia.org/wiki/.ma
+// ma : https://www.iana.org/domains/root/db/ma.html
 // http://www.anrt.ma/fr/admin/download/upload/file_fr782.pdf
 ma
 co.ma
@@ -3951,10 +3962,10 @@
 tm.mc
 asso.mc
 
-// md : https://en.wikipedia.org/wiki/.md
+// md : https://www.iana.org/domains/root/db/md.html
 md
 
-// me : https://en.wikipedia.org/wiki/.me
+// me : https://www.iana.org/domains/root/db/me.html
 me
 co.me
 net.me
@@ -3977,13 +3988,13 @@
 com.mg
 co.mg
 
-// mh : https://en.wikipedia.org/wiki/.mh
+// mh : https://www.iana.org/domains/root/db/mh.html
 mh
 
-// mil : https://en.wikipedia.org/wiki/.mil
+// mil : https://www.iana.org/domains/root/db/mil.html
 mil
 
-// mk : https://en.wikipedia.org/wiki/.mk
+// mk : https://www.iana.org/domains/root/db/mk.html
 // see also: http://dns.marnet.net.mk/postapka.php
 mk
 com.mk
@@ -3995,7 +4006,7 @@
 name.mk
 
 // ml : http://www.gobin.info/domainname/ml-template.doc
-// see also: https://en.wikipedia.org/wiki/.ml
+// see also: https://www.iana.org/domains/root/db/ml.html
 ml
 com.ml
 edu.ml
@@ -4005,10 +4016,10 @@
 org.ml
 presse.ml
 
-// mm : https://en.wikipedia.org/wiki/.mm
+// mm : https://www.iana.org/domains/root/db/mm.html
 *.mm
 
-// mn : https://en.wikipedia.org/wiki/.mn
+// mn : https://www.iana.org/domains/root/db/mn.html
 mn
 gov.mn
 edu.mn
@@ -4022,17 +4033,17 @@
 edu.mo
 gov.mo
 
-// mobi : https://en.wikipedia.org/wiki/.mobi
+// mobi : https://www.iana.org/domains/root/db/mobi.html
 mobi
 
 // mp : http://www.dot.mp/
 // Confirmed by registry <dcamacho@saipan.com> 2008-06-17
 mp
 
-// mq : https://en.wikipedia.org/wiki/.mq
+// mq : https://www.iana.org/domains/root/db/mq.html
 mq
 
-// mr : https://en.wikipedia.org/wiki/.mr
+// mr : https://www.iana.org/domains/root/db/mr.html
 mr
 gov.mr
 
@@ -4052,7 +4063,7 @@
 net.mt
 org.mt
 
-// mu : https://en.wikipedia.org/wiki/.mu
+// mu : https://www.iana.org/domains/root/db/mu.html
 mu
 com.mu
 net.mu
@@ -4065,7 +4076,7 @@
 // museum : https://welcome.museum/wp-content/uploads/2018/05/20180525-Registration-Policy-MUSEUM-EN_VF-2.pdf https://welcome.museum/buy-your-dot-museum-2/
 museum
 
-// mv : https://en.wikipedia.org/wiki/.mv
+// mv : https://www.iana.org/domains/root/db/mv.html
 // "mv" included because, contra Wikipedia, google.mv exists.
 mv
 aero.mv
@@ -4159,13 +4170,13 @@
 asso.nc
 nom.nc
 
-// ne : https://en.wikipedia.org/wiki/.ne
+// ne : https://www.iana.org/domains/root/db/ne.html
 ne
 
-// net : https://en.wikipedia.org/wiki/.net
+// net : https://www.iana.org/domains/root/db/net.html
 net
 
-// nf : https://en.wikipedia.org/wiki/.nf
+// nf : https://www.iana.org/domains/root/db/nf.html
 nf
 com.nf
 net.nf
@@ -4208,7 +4219,7 @@
 org.ni
 web.ni
 
-// nl : https://en.wikipedia.org/wiki/.nl
+// nl : https://www.iana.org/domains/root/db/nl.html
 //      https://www.sidn.nl/
 //      ccTLD for the Netherlands
 nl
@@ -4994,10 +5005,10 @@
 net.nr
 com.nr
 
-// nu : https://en.wikipedia.org/wiki/.nu
+// nu : https://www.iana.org/domains/root/db/nu.html
 nu
 
-// nz : https://en.wikipedia.org/wiki/.nz
+// nz : https://www.iana.org/domains/root/db/nz.html
 // Submitted by registry <jay@nzrs.net.nz>
 nz
 ac.nz
@@ -5017,7 +5028,7 @@
 parliament.nz
 school.nz
 
-// om : https://en.wikipedia.org/wiki/.om
+// om : https://www.iana.org/domains/root/db/om.html
 om
 co.om
 com.om
@@ -5032,7 +5043,7 @@
 // onion : https://tools.ietf.org/html/rfc7686
 onion
 
-// org : https://en.wikipedia.org/wiki/.org
+// org : https://www.iana.org/domains/root/db/org.html
 org
 
 // pa : http://www.nic.pa/
@@ -5067,7 +5078,7 @@
 org.pf
 edu.pf
 
-// pg : https://en.wikipedia.org/wiki/.pg
+// pg : https://www.iana.org/domains/root/db/pg.html
 *.pg
 
 // ph : http://www.domains.ph/FAQ2.asp
@@ -5082,22 +5093,27 @@
 mil.ph
 i.ph
 
-// pk : http://pk5.pknic.net.pk/pk5/msgNamepk.PK
+// pk : https://pknic.net.pk
+// pk : http://pk5.pknic.net.pk/pk5/msgNamepk.PK + grandfathered old gon.pk
+// Contact Email: staff@pknic.net.pk    PKNIC .PK Registry
+
 pk
-com.pk
-net.pk
-edu.pk
-org.pk
-fam.pk
+ac.pk
 biz.pk
-web.pk
-gov.pk
+com.pk
+edu.pk
+fam.pk
+gkp.pk
 gob.pk
+gog.pk
 gok.pk
 gon.pk
 gop.pk
 gos.pk
-info.pk
+gov.pk
+net.pk
+org.pk
+web.pk
 
 // pl http://www.dns.pl/english/index.html
 // Submitted by registry
@@ -5325,7 +5341,7 @@
 edu.pn
 net.pn
 
-// post : https://en.wikipedia.org/wiki/.post
+// post : https://www.iana.org/domains/root/db/post.html
 post
 
 // pr : http://www.nic.pr/index.asp?f=1
@@ -5340,7 +5356,7 @@
 biz.pr
 info.pr
 name.pr
-// these aren't mentioned on nic.pr, but on https://en.wikipedia.org/wiki/.pr
+// these aren't mentioned on nic.pr, but on https://www.iana.org/domains/root/db/pr.html
 est.pr
 prof.pr
 ac.pr
@@ -5359,7 +5375,7 @@
 med.pro
 recht.pro
 
-// ps : https://en.wikipedia.org/wiki/.ps
+// ps : https://www.iana.org/domains/root/db/ps.html
 // http://www.nic.ps/registration/policy.html#reg
 ps
 edu.ps
@@ -5381,7 +5397,7 @@
 com.pt
 nome.pt
 
-// pw : https://en.wikipedia.org/wiki/.pw
+// pw : https://www.iana.org/domains/root/db/pw.html
 pw
 co.pw
 ne.pw
@@ -5495,7 +5511,7 @@
 gov.sd
 info.sd
 
-// se : https://en.wikipedia.org/wiki/.se
+// se : https://www.iana.org/domains/root/db/se.html
 // Submitted by registry <patrik.wallstrom@iis.se>
 se
 a.se
@@ -5555,14 +5571,14 @@
 org.sh
 mil.sh
 
-// si : https://en.wikipedia.org/wiki/.si
+// si : https://www.iana.org/domains/root/db/si.html
 si
 
 // sj : No registrations at this time.
 // Submitted by registry <jarle@uninett.no>
 sj
 
-// sk : https://en.wikipedia.org/wiki/.sk
+// sk : https://www.iana.org/domains/root/db/sk.html
 // list of 2nd level domains ?
 sk
 
@@ -5575,10 +5591,10 @@
 gov.sl
 org.sl
 
-// sm : https://en.wikipedia.org/wiki/.sm
+// sm : https://www.iana.org/domains/root/db/sm.html
 sm
 
-// sn : https://en.wikipedia.org/wiki/.sn
+// sn : https://www.iana.org/domains/root/db/sn.html
 sn
 art.sn
 com.sn
@@ -5597,7 +5613,7 @@
 net.so
 org.so
 
-// sr : https://en.wikipedia.org/wiki/.sr
+// sr : https://www.iana.org/domains/root/db/sr.html
 sr
 
 // ss : https://registry.nic.ss/
@@ -5626,7 +5642,7 @@
 saotome.st
 store.st
 
-// su : https://en.wikipedia.org/wiki/.su
+// su : https://www.iana.org/domains/root/db/su.html
 su
 
 // sv : http://www.svnet.org.sv/niveldos.pdf
@@ -5637,12 +5653,12 @@
 org.sv
 red.sv
 
-// sx : https://en.wikipedia.org/wiki/.sx
+// sx : https://www.iana.org/domains/root/db/sx.html
 // Submitted by registry <jcvignes@openregistry.com>
 sx
 gov.sx
 
-// sy : https://en.wikipedia.org/wiki/.sy
+// sy : https://www.iana.org/domains/root/db/sy.html
 // see also: http://www.gobin.info/domainname/sy.doc
 sy
 edu.sy
@@ -5652,31 +5668,31 @@
 com.sy
 org.sy
 
-// sz : https://en.wikipedia.org/wiki/.sz
+// sz : https://www.iana.org/domains/root/db/sz.html
 // http://www.sispa.org.sz/
 sz
 co.sz
 ac.sz
 org.sz
 
-// tc : https://en.wikipedia.org/wiki/.tc
+// tc : https://www.iana.org/domains/root/db/tc.html
 tc
 
-// td : https://en.wikipedia.org/wiki/.td
+// td : https://www.iana.org/domains/root/db/td.html
 td
 
-// tel: https://en.wikipedia.org/wiki/.tel
+// tel: https://www.iana.org/domains/root/db/tel.html
 // http://www.telnic.org/
 tel
 
 // tf : https://www.afnic.fr/wp-media/uploads/2022/12/afnic-naming-policy-2023-01-01.pdf
 tf
 
-// tg : https://en.wikipedia.org/wiki/.tg
+// tg : https://www.iana.org/domains/root/db/tg.html
 // http://www.nic.tg/
 tg
 
-// th : https://en.wikipedia.org/wiki/.th
+// th : https://www.iana.org/domains/root/db/th.html
 // Submitted by registry <krit@thains.co.th>
 th
 ac.th
@@ -5705,10 +5721,10 @@
 test.tj
 web.tj
 
-// tk : https://en.wikipedia.org/wiki/.tk
+// tk : https://www.iana.org/domains/root/db/tk.html
 tk
 
-// tl : https://en.wikipedia.org/wiki/.tl
+// tl : https://www.iana.org/domains/root/db/tl.html
 tl
 gov.tl
 
@@ -5740,7 +5756,7 @@
 perso.tn
 tourism.tn
 
-// to : https://en.wikipedia.org/wiki/.to
+// to : https://www.iana.org/domains/root/db/to.html
 // Submitted by registry <egullich@colo.to>
 to
 com.to
@@ -5800,12 +5816,12 @@
 gov.tt
 edu.tt
 
-// tv : https://en.wikipedia.org/wiki/.tv
+// tv : https://www.iana.org/domains/root/db/tv.html
 // Not listing any 2LDs as reserved since none seem to exist in practice,
 // Wikipedia notwithstanding.
 tv
 
-// tw : https://en.wikipedia.org/wiki/.tw
+// tw : https://www.iana.org/domains/root/db/tw.html
 tw
 edu.tw
 gov.tw
@@ -5934,7 +5950,7 @@
 com.ug
 org.ug
 
-// uk : https://en.wikipedia.org/wiki/.uk
+// uk : https://www.iana.org/domains/root/db/uk.html
 // Submitted by registry <Michael.Daly@nominet.org.uk>
 uk
 ac.uk
@@ -5949,7 +5965,7 @@
 police.uk
 *.sch.uk
 
-// us : https://en.wikipedia.org/wiki/.us
+// us : https://www.iana.org/domains/root/db/us.html
 us
 dni.us
 fed.us
@@ -6217,10 +6233,10 @@
 net.uz
 org.uz
 
-// va : https://en.wikipedia.org/wiki/.va
+// va : https://www.iana.org/domains/root/db/va.html
 va
 
-// vc : https://en.wikipedia.org/wiki/.vc
+// vc : https://www.iana.org/domains/root/db/vc.html
 // Submitted by registry <kshah@ca.afilias.info>
 vc
 com.vc
@@ -6254,7 +6270,7 @@
 tec.ve
 web.ve
 
-// vg : https://en.wikipedia.org/wiki/.vg
+// vg : https://www.iana.org/domains/root/db/vg.html
 vg
 
 // vi : http://www.nic.vi/newdomainform.htm
@@ -6352,7 +6368,7 @@
 vinhphuc.vn
 yenbai.vn
 
-// vu : https://en.wikipedia.org/wiki/.vu
+// vu : https://www.iana.org/domains/root/db/vu.html
 // http://www.vunic.vu/
 vu
 com.vu
@@ -6363,7 +6379,7 @@
 // wf : https://www.afnic.fr/wp-media/uploads/2022/12/afnic-naming-policy-2023-01-01.pdf
 wf
 
-// ws : https://en.wikipedia.org/wiki/.ws
+// ws : https://www.iana.org/domains/root/db/ws.html
 // http://samoanic.ws/index.dhtml
 ws
 com.ws
@@ -6711,10 +6727,9 @@
 mil.zw
 org.zw
 
-
 // newGTLDs
 
-// List of new gTLDs imported from https://www.icann.org/resources/registries/gtlds/v2/gtlds.json on 2024-03-28T15:13:37Z
+// List of new gTLDs imported from https://www.icann.org/resources/registries/gtlds/v2/gtlds.json on 2024-08-25T15:14:38Z
 // This list is auto-generated, don't edit it manually.
 // aaa : American Automobile Association, Inc.
 // https://www.iana.org/domains/root/db/aaa.html
@@ -6900,7 +6915,7 @@
 // https://www.iana.org/domains/root/db/anz.html
 anz
 
-// aol : Oath Inc.
+// aol : Yahoo Inc.
 // https://www.iana.org/domains/root/db/aol.html
 aol
 
@@ -8116,7 +8131,7 @@
 // https://www.iana.org/domains/root/db/forsale.html
 forsale
 
-// forum : Fegistry, LLC
+// forum : Waterford Limited
 // https://www.iana.org/domains/root/db/forum.html
 forum
 
@@ -8980,7 +8995,7 @@
 // https://www.iana.org/domains/root/db/lotto.html
 lotto
 
-// love : Merchant Law Group LLP
+// love : Waterford Limited
 // https://www.iana.org/domains/root/db/love.html
 love
 
@@ -9028,7 +9043,7 @@
 // https://www.iana.org/domains/root/db/makeup.html
 makeup
 
-// man : MAN SE
+// man : MAN Truck & Bus SE
 // https://www.iana.org/domains/root/db/man.html
 man
 
@@ -9232,10 +9247,6 @@
 // https://www.iana.org/domains/root/db/nagoya.html
 nagoya
 
-// natura : NATURA COSMÉTICOS S.A.
-// https://www.iana.org/domains/root/db/natura.html
-natura
-
 // navy : Dog Beach, LLC
 // https://www.iana.org/domains/root/db/navy.html
 navy
@@ -9692,7 +9703,7 @@
 // https://www.iana.org/domains/root/db/realtor.html
 realtor
 
-// realty : Internet Naming Company LLC
+// realty : Waterford Limited
 // https://www.iana.org/domains/root/db/realty.html
 realty
 
@@ -10008,10 +10019,6 @@
 // https://www.iana.org/domains/root/db/sharp.html
 sharp
 
-// shaw : Shaw Cablesystems G.P.
-// https://www.iana.org/domains/root/db/shaw.html
-shaw
-
 // shell : Shell Information Technology International Inc
 // https://www.iana.org/domains/root/db/shell.html
 shell
@@ -10504,7 +10511,7 @@
 // https://www.iana.org/domains/root/db/vacations.html
 vacations
 
-// vana : Internet Naming Company LLC
+// vana : D3 Registry LLC
 // https://www.iana.org/domains/root/db/vana.html
 vana
 
@@ -11124,7 +11131,7 @@
 // https://www.iana.org/domains/root/db/yachts.html
 yachts
 
-// yahoo : Oath Inc.
+// yahoo : Yahoo Inc.
 // https://www.iana.org/domains/root/db/yahoo.html
 yahoo
 
@@ -11184,11 +11191,28 @@
 // https://www.iana.org/domains/root/db/zuerich.html
 zuerich
 
-
 // ===END ICANN DOMAINS===
+
 // ===BEGIN PRIVATE DOMAINS===
+
 // (Note: these are in alphabetical order by company name)
 
+// .KRD : http://nic.krd/data/krd/Registration%20Policy.pdf
+co.krd
+edu.krd
+
+// .pl domains (grandfathered)
+art.pl
+gliwice.pl
+krakow.pl
+poznan.pl
+wroc.pl
+zakopane.pl
+
+// .US
+// Submitted by Ed Moore <Ed.Moore@lib.de.us>
+lib.de.us
+
 // 12CHARS: https://12chars.com
 // Submitted by Kenny Niehage <psl@12chars.com>
 12chars.dev
@@ -11201,7 +11225,7 @@
 inf.ua
 ltd.ua
 
-// 611coin : https://611project.org/
+// 611 blockchain domain name system : https://611project.net/
 611.to
 
 // A2 Hosting
@@ -11209,13 +11233,9 @@
 a2hosted.com
 cpserver.com
 
-// Aaron Marais' Gitlab pages: https://lab.aaronleem.co.za
-// Submitted by Aaron Marais <its_me@aaronleem.co.za>
-graphox.us
-
-// accesso Technology Group, plc. : https://accesso.com/
-// Submitted by accesso Team <accessoecommerce@accesso.com>
-*.devcdnaccesso.com
+// AAA workspace : https://aaa.vodka
+// Submitted by Kirill Rezraf <admin@aaa.vodka>
+aaa.vodka
 
 // Acorn Labs : https://acorn.io
 // Submitted by Craig Jellick <domains@acorn.io>
@@ -11245,6 +11265,10 @@
 adobeio-static.net
 adobeioruntime.net
 
+// Africa.com Web Solutions Ltd : https://registry.africa.com
+// Submitted by Gavin Brown <gavin.brown@centralnic.com>
+africa.com
+
 // Agnat sp. z o.o. : https://domena.pl
 // Submitted by Przemyslaw Plewa <it-admin@domena.pl>
 beep.pl
@@ -11350,23 +11374,30 @@
 
 // Amazon Cognito
 // Submitted by AWS Security <psl-maintainers@amazon.com>
-// Reference: 7bee1013-f456-47df-bfe8-03c78d946d61
+// Reference: cb38c251-c93d-4cda-81ec-e72c4f0fdb72
 auth.af-south-1.amazoncognito.com
+auth.ap-east-1.amazoncognito.com
 auth.ap-northeast-1.amazoncognito.com
 auth.ap-northeast-2.amazoncognito.com
 auth.ap-northeast-3.amazoncognito.com
 auth.ap-south-1.amazoncognito.com
+auth.ap-south-2.amazoncognito.com
 auth.ap-southeast-1.amazoncognito.com
 auth.ap-southeast-2.amazoncognito.com
 auth.ap-southeast-3.amazoncognito.com
+auth.ap-southeast-4.amazoncognito.com
 auth.ca-central-1.amazoncognito.com
+auth.ca-west-1.amazoncognito.com
 auth.eu-central-1.amazoncognito.com
+auth.eu-central-2.amazoncognito.com
 auth.eu-north-1.amazoncognito.com
 auth.eu-south-1.amazoncognito.com
+auth.eu-south-2.amazoncognito.com
 auth.eu-west-1.amazoncognito.com
 auth.eu-west-2.amazoncognito.com
 auth.eu-west-3.amazoncognito.com
 auth.il-central-1.amazoncognito.com
+auth.me-central-1.amazoncognito.com
 auth.me-south-1.amazoncognito.com
 auth.sa-east-1.amazoncognito.com
 auth.us-east-1.amazoncognito.com
@@ -11382,14 +11413,14 @@
 // Amazon EC2
 // Submitted by Luke Wells <psl-maintainers@amazon.com>
 // Reference: 4c38fa71-58ac-4768-99e5-689c1767e537
+*.compute.amazonaws.com.cn
 *.compute.amazonaws.com
 *.compute-1.amazonaws.com
-*.compute.amazonaws.com.cn
 us-east-1.amazonaws.com
 
 // Amazon EMR
 // Submitted by AWS Security <psl-maintainers@amazon.com>
-// Reference: 597f3f8e-9283-4e48-8e32-7ee25a1ff6ab
+// Reference: 82f43f9f-bbb8-400e-8349-854f5a62f20d
 emrappui-prod.cn-north-1.amazonaws.com.cn
 emrnotebooks-prod.cn-north-1.amazonaws.com.cn
 emrstudio-prod.cn-north-1.amazonaws.com.cn
@@ -11414,6 +11445,9 @@
 emrappui-prod.ap-south-1.amazonaws.com
 emrnotebooks-prod.ap-south-1.amazonaws.com
 emrstudio-prod.ap-south-1.amazonaws.com
+emrappui-prod.ap-south-2.amazonaws.com
+emrnotebooks-prod.ap-south-2.amazonaws.com
+emrstudio-prod.ap-south-2.amazonaws.com
 emrappui-prod.ap-southeast-1.amazonaws.com
 emrnotebooks-prod.ap-southeast-1.amazonaws.com
 emrstudio-prod.ap-southeast-1.amazonaws.com
@@ -11423,18 +11457,30 @@
 emrappui-prod.ap-southeast-3.amazonaws.com
 emrnotebooks-prod.ap-southeast-3.amazonaws.com
 emrstudio-prod.ap-southeast-3.amazonaws.com
+emrappui-prod.ap-southeast-4.amazonaws.com
+emrnotebooks-prod.ap-southeast-4.amazonaws.com
+emrstudio-prod.ap-southeast-4.amazonaws.com
 emrappui-prod.ca-central-1.amazonaws.com
 emrnotebooks-prod.ca-central-1.amazonaws.com
 emrstudio-prod.ca-central-1.amazonaws.com
+emrappui-prod.ca-west-1.amazonaws.com
+emrnotebooks-prod.ca-west-1.amazonaws.com
+emrstudio-prod.ca-west-1.amazonaws.com
 emrappui-prod.eu-central-1.amazonaws.com
 emrnotebooks-prod.eu-central-1.amazonaws.com
 emrstudio-prod.eu-central-1.amazonaws.com
+emrappui-prod.eu-central-2.amazonaws.com
+emrnotebooks-prod.eu-central-2.amazonaws.com
+emrstudio-prod.eu-central-2.amazonaws.com
 emrappui-prod.eu-north-1.amazonaws.com
 emrnotebooks-prod.eu-north-1.amazonaws.com
 emrstudio-prod.eu-north-1.amazonaws.com
 emrappui-prod.eu-south-1.amazonaws.com
 emrnotebooks-prod.eu-south-1.amazonaws.com
 emrstudio-prod.eu-south-1.amazonaws.com
+emrappui-prod.eu-south-2.amazonaws.com
+emrnotebooks-prod.eu-south-2.amazonaws.com
+emrstudio-prod.eu-south-2.amazonaws.com
 emrappui-prod.eu-west-1.amazonaws.com
 emrnotebooks-prod.eu-west-1.amazonaws.com
 emrstudio-prod.eu-west-1.amazonaws.com
@@ -11444,6 +11490,9 @@
 emrappui-prod.eu-west-3.amazonaws.com
 emrnotebooks-prod.eu-west-3.amazonaws.com
 emrstudio-prod.eu-west-3.amazonaws.com
+emrappui-prod.il-central-1.amazonaws.com
+emrnotebooks-prod.il-central-1.amazonaws.com
+emrstudio-prod.il-central-1.amazonaws.com
 emrappui-prod.me-central-1.amazonaws.com
 emrnotebooks-prod.me-central-1.amazonaws.com
 emrstudio-prod.me-central-1.amazonaws.com
@@ -11474,23 +11523,37 @@
 
 // Amazon Managed Workflows for Apache Airflow
 // Submitted by AWS Security <psl-maintainers@amazon.com>
-// Reference: 4ab55e6f-90c0-4a8d-b6a0-52ca5dbb1c2e
+// Reference: f5ea5d0a-ec6a-4f23-ac1c-553fbff13f5c
 *.cn-north-1.airflow.amazonaws.com.cn
 *.cn-northwest-1.airflow.amazonaws.com.cn
+*.af-south-1.airflow.amazonaws.com
+*.ap-east-1.airflow.amazonaws.com
 *.ap-northeast-1.airflow.amazonaws.com
 *.ap-northeast-2.airflow.amazonaws.com
+*.ap-northeast-3.airflow.amazonaws.com
 *.ap-south-1.airflow.amazonaws.com
+*.ap-south-2.airflow.amazonaws.com
 *.ap-southeast-1.airflow.amazonaws.com
 *.ap-southeast-2.airflow.amazonaws.com
+*.ap-southeast-3.airflow.amazonaws.com
+*.ap-southeast-4.airflow.amazonaws.com
 *.ca-central-1.airflow.amazonaws.com
+*.ca-west-1.airflow.amazonaws.com
 *.eu-central-1.airflow.amazonaws.com
+*.eu-central-2.airflow.amazonaws.com
 *.eu-north-1.airflow.amazonaws.com
+*.eu-south-1.airflow.amazonaws.com
+*.eu-south-2.airflow.amazonaws.com
 *.eu-west-1.airflow.amazonaws.com
 *.eu-west-2.airflow.amazonaws.com
 *.eu-west-3.airflow.amazonaws.com
+*.il-central-1.airflow.amazonaws.com
+*.me-central-1.airflow.amazonaws.com
+*.me-south-1.airflow.amazonaws.com
 *.sa-east-1.airflow.amazonaws.com
 *.us-east-1.airflow.amazonaws.com
 *.us-east-2.airflow.amazonaws.com
+*.us-west-1.airflow.amazonaws.com
 *.us-west-2.airflow.amazonaws.com
 
 // Amazon S3
@@ -11784,9 +11847,25 @@
 s3-object-lambda.us-west-2.amazonaws.com
 s3-website.us-west-2.amazonaws.com
 
+// Amazon SageMaker Ground Truth
+// Submitted by AWS Security <psl-maintainers@amazon.com>
+// Reference: 98dbfde4-7802-48c3-8751-b60f204e0d9c
+labeling.ap-northeast-1.sagemaker.aws
+labeling.ap-northeast-2.sagemaker.aws
+labeling.ap-south-1.sagemaker.aws
+labeling.ap-southeast-1.sagemaker.aws
+labeling.ap-southeast-2.sagemaker.aws
+labeling.ca-central-1.sagemaker.aws
+labeling.eu-central-1.sagemaker.aws
+labeling.eu-west-1.sagemaker.aws
+labeling.eu-west-2.sagemaker.aws
+labeling.us-east-1.sagemaker.aws
+labeling.us-east-2.sagemaker.aws
+labeling.us-west-2.sagemaker.aws
+
 // Amazon SageMaker Notebook Instances
 // Submitted by AWS Security <psl-maintainers@amazon.com>
-// Reference: ce8ae0b1-0070-496d-be88-37c31837af9d
+// Reference: b5ea56df-669e-43cc-9537-14aa172f5dfc
 notebook.af-south-1.sagemaker.aws
 notebook.ap-east-1.sagemaker.aws
 notebook.ap-northeast-1.sagemaker.aws
@@ -11823,6 +11902,7 @@
 notebook.us-gov-west-1.sagemaker.aws
 notebook-fips.us-gov-west-1.sagemaker.aws
 notebook.us-west-1.sagemaker.aws
+notebook-fips.us-west-1.sagemaker.aws
 notebook.us-west-2.sagemaker.aws
 notebook-fips.us-west-2.sagemaker.aws
 notebook.cn-north-1.sagemaker.com.cn
@@ -11830,7 +11910,7 @@
 
 // Amazon SageMaker Studio
 // Submitted by AWS Security <psl-maintainers@amazon.com>
-// Reference: 057ee397-6bf8-4f20-b807-d7bc145ac980
+// Reference: 69c723d9-6e1a-4bff-a203-48eecd203183
 studio.af-south-1.sagemaker.aws
 studio.ap-east-1.sagemaker.aws
 studio.ap-northeast-1.sagemaker.aws
@@ -11844,6 +11924,7 @@
 studio.eu-central-1.sagemaker.aws
 studio.eu-north-1.sagemaker.aws
 studio.eu-south-1.sagemaker.aws
+studio.eu-south-2.sagemaker.aws
 studio.eu-west-1.sagemaker.aws
 studio.eu-west-2.sagemaker.aws
 studio.eu-west-3.sagemaker.aws
@@ -11862,6 +11943,11 @@
 studio.cn-north-1.sagemaker.com.cn
 studio.cn-northwest-1.sagemaker.com.cn
 
+// Amazon SageMaker with MLflow
+// Submited by: AWS Security <psl-maintainers@amazon.com>
+// Reference: c19f92b3-a82a-452d-8189-831b572eea7e
+*.experiments.sagemaker.aws
+
 // Analytics on AWS
 // Submitted by AWS Security <psl-maintainers@amazon.com>
 // Reference: 955f9f40-a495-4e73-ae85-67b77ac9cadd
@@ -11878,8 +11964,8 @@
 
 // AWS Amplify
 // Submitted by AWS Security <psl-maintainers@amazon.com>
-// Reference: 5ecce854-c033-4fc4-a755-1a9916d9a9bb
-*.amplifyapp.com
+// Reference: c35bed18-6f4f-424f-9298-5756f2f7d72b
+amplifyapp.com
 
 // AWS App Runner
 // Submitted by AWS Security <psl-maintainers@amazon.com>
@@ -11955,6 +12041,11 @@
 vfs.cloud9.us-west-2.amazonaws.com
 webview-assets.cloud9.us-west-2.amazonaws.com
 
+// AWS Directory Service
+// Submitted by AWS Security <psl-maintainers@amazon.com>
+// Reference: a13203e8-42dc-4045-a0d2-2ee67bed1068
+awsapps.com
+
 // AWS Elastic Beanstalk
 // Submitted by AWS Security <psl-maintainers@amazon.com>
 // Reference: bb5a965c-dec3-4967-aa22-e306ad064797
@@ -12011,16 +12102,11 @@
 
 // concludes Amazon
 
-// Amune : https://amune.org/
-// Submitted by Team Amune <cert@amune.org>
-t3l3p0rt.net
-tele.amune.org
-
 // Apigee : https://apigee.com/
 // Submitted by Apigee Security Team <security@apigee.com>
 apigee.io
 
-// Apis Networks: https://apisnetworks.com
+// Apis Networks : https://apisnetworks.com
 // Submitted by Matt Saladna <matt@apisnetworks.com>
 panel.dev
 
@@ -12074,10 +12160,6 @@
 // Submitted by Lukas Reschke <lukas@authentick.net>
 translated.page
 
-// Autocode : https://autocode.com
-// Submitted by Jacob Lee <jacob@autocode.com>
-autocode.dev
-
 // AVM : https://avm.de
 // Submitted by Andreas Weise <a.weise@avm.de>
 myfritz.link
@@ -12092,7 +12174,7 @@
 *.awdev.ca
 *.advisor.ws
 
-// AZ.pl sp. z.o.o: https://az.pl
+// AZ.pl sp. z.o.o : https://az.pl
 // Submitted by Krzysztof Wolski <krzysztof.wolski@home.eu>
 ecommerce-shop.pl
 
@@ -12100,19 +12182,10 @@
 // Submitted by Olivier Benz <olivier.benz@b-data.ch>
 b-data.io
 
-// backplane : https://www.backplane.io
-// Submitted by Anthony Voutas <anthony@backplane.io>
-backplaneapp.io
-
 // Balena : https://www.balena.io
 // Submitted by Petros Angelatos <petrosagg@balena.io>
 balena-devices.com
 
-// University of Banja Luka : https://unibl.org
-// Domains for Republic of Srpska administrative entity.
-// Submitted by Marko Ivanovic <kormang@hotmail.rs>
-rs.ba
-
 // Banzai Cloud
 // Submitted by Janos Matyas <info@banzaicloud.com>
 *.banzai.cloud
@@ -12194,13 +12267,19 @@
 *.s.brave.io
 
 // Brendly : https://brendly.rs
-// Submitted by Dusan Radovanovic <dusan.radovanovic@brendly.rs>
+// Submitted by Dusan Radovanovic <administracija@brendly.rs>
+shop.brendly.hr
 shop.brendly.rs
 
 // BrowserSafetyMark
 // Submitted by Dave Tharp <browsersafetymark.io@quicinc.com>
 browsersafetymark.io
 
+// BRS Media : https://brsmedia.com/
+// Submitted by Gavin Brown <gavin.brown@centralnic.com>
+radio.am
+radio.fm
+
 // Bytemark Hosting : https://www.bytemark.co.uk
 // Submitted by Paul Cammish <paul.cammish@bytemark.co.uk>
 uk0.bigv.io
@@ -12230,71 +12309,42 @@
 crd.co
 ju.mp
 
+// CDDO : https://www.gov.uk/guidance/get-an-api-domain-on-govuk
+// Submitted by Jamie Tanna <jamie.tanna@digital.cabinet-office.gov.uk>
+api.gov.uk
+
+// CDN77.com : http://www.cdn77.com
+// Submitted by Jan Krpes <jan.krpes@cdn77.com>
+cdn77-storage.com
+rsc.contentproxy9.cz
+r.cdn77.net
+cdn77-ssl.net
+c.cdn77.org
+rsc.cdn77.org
+ssl.origin.cdn77-secure.org
+
 // CentralNic : http://www.centralnic.com/names/domains
 // Submitted by registry <gavin.brown@centralnic.com>
-ae.org
+za.bz
 br.com
 cn.com
-com.de
-com.se
 de.com
 eu.com
-gb.net
-hu.net
-jp.net
 jpn.com
 mex.com
 ru.com
 sa.com
-se.net
 uk.com
-uk.net
 us.com
-za.bz
 za.com
-
-// No longer operated by CentralNic, these entries should be adopted and/or removed by current operators
-// Submitted by Gavin Brown <gavin.brown@centralnic.com>
-ar.com
-hu.com
-kr.com
-no.com
-qc.com
-uy.com
-
-// Africa.com Web Solutions Ltd : https://registry.africa.com
-// Submitted by Gavin Brown <gavin.brown@centralnic.com>
-africa.com
-
-// iDOT Services Limited : http://www.domain.gr.com
-// Submitted by Gavin Brown <gavin.brown@centralnic.com>
-gr.com
-
-// Radix FZC : http://domains.in.net
-// Submitted by Gavin Brown <gavin.brown@centralnic.com>
-in.net
-web.in
-
-// US REGISTRY LLC : http://us.org
-// Submitted by Gavin Brown <gavin.brown@centralnic.com>
-us.org
-
-// co.com Registry, LLC : https://registry.co.com
-// Submitted by Gavin Brown <gavin.brown@centralnic.com>
-co.com
-
-// Roar Domains LLC : https://roar.basketball/
-// Submitted by Gavin Brown <gavin.brown@centralnic.com>
-aus.basketball
-nz.basketball
-
-// BRS Media : https://brsmedia.com/
-// Submitted by Gavin Brown <gavin.brown@centralnic.com>
-radio.am
-radio.fm
-
-// c.la : http://www.c.la/
-c.la
+com.de
+gb.net
+hu.net
+jp.net
+se.net
+uk.net
+ae.org
+com.se
 
 // certmgr.org : https://certmgr.org
 // Submitted by B. Blechschmidt <hostmaster@certmgr.org>
@@ -12309,10 +12359,6 @@
 discourse.group
 discourse.team
 
-// Clever Cloud : https://www.clever-cloud.com/
-// Submitted by Quentin Adam <noc@clever-cloud.com>
-cleverapps.io
-
 // Clerk : https://www.clerk.dev
 // Submitted by Colin Sidoti <systems@clerk.dev>
 clerk.app
@@ -12322,67 +12368,17 @@
 *.stg.dev
 *.stgstage.dev
 
+// Clever Cloud : https://www.clever-cloud.com/
+// Submitted by Quentin Adam <noc@clever-cloud.com>
+cleverapps.cc
+*.services.clever-cloud.com
+cleverapps.io
+cleverapps.tech
+
 // ClickRising : https://clickrising.com/
 // Submitted by Umut Gumeli <infrastructure-publicsuffixlist@clickrising.com>
 clickrising.net
 
-// Cloud66 : https://www.cloud66.com/
-// Submitted by Khash Sajadi <khash@cloud66.com>
-c66.me
-cloud66.ws
-cloud66.zone
-
-// CloudAccess.net : https://www.cloudaccess.net/
-// Submitted by Pawel Panek <noc@cloudaccess.net>
-jdevcloud.com
-wpdevcloud.com
-cloudaccess.host
-freesite.host
-cloudaccess.net
-
-// cloudControl : https://www.cloudcontrol.com/
-// Submitted by Tobias Wilken <tw@cloudcontrol.com>
-cloudcontrolled.com
-cloudcontrolapp.com
-
-// Cloudera, Inc. : https://www.cloudera.com/
-// Submitted by Kedarnath Waikar <security@cloudera.com>
-*.cloudera.site
-
-// Cloudflare, Inc. : https://www.cloudflare.com/
-// Submitted by Cloudflare Team <publicsuffixlist@cloudflare.com>
-cf-ipfs.com
-cloudflare-ipfs.com
-trycloudflare.com
-pages.dev
-r2.dev
-workers.dev
-
-// Clovyr : https://clovyr.io
-// Submitted by Patrick Nielsen <patrick@clovyr.io>
-wnext.app
-
-// co.ca : http://registry.co.ca/
-co.ca
-
-// Co & Co : https://co-co.nl/
-// Submitted by Govert Versluis <govert@co-co.nl>
-*.otap.co
-
-// i-registry s.r.o. : http://www.i-registry.cz/
-// Submitted by Martin Semrad <semrad@i-registry.cz>
-co.cz
-
-// CDN77.com : http://www.cdn77.com
-// Submitted by Jan Krpes <jan.krpes@cdn77.com>
-cdn77-storage.com
-rsc.contentproxy9.cz
-cdn77-ssl.net
-r.cdn77.net
-ssl.origin.cdn77-secure.org
-c.cdn77.org
-rsc.cdn77.org
-
 // Cloud DNS Ltd : http://www.cloudns.net
 // Submitted by Aleksander Hristov <noc@cloudns.net> & Boyan Peychev <boyan@cloudns.net>
 cloudns.asia
@@ -12406,10 +12402,63 @@
 cloudns.pw
 cloudns.us
 
+// Cloud66 : https://www.cloud66.com/
+// Submitted by Khash Sajadi <khash@cloud66.com>
+c66.me
+cloud66.ws
+cloud66.zone
+
+// CloudAccess.net : https://www.cloudaccess.net/
+// Submitted by Pawel Panek <noc@cloudaccess.net>
+jdevcloud.com
+wpdevcloud.com
+cloudaccess.host
+freesite.host
+cloudaccess.net
+
+// Cloudera, Inc. : https://www.cloudera.com/
+// Submitted by Kedarnath Waikar <security@cloudera.com>
+*.cloudera.site
+
+// Cloudflare, Inc. : https://www.cloudflare.com/
+// Submitted by Cloudflare Team <publicsuffixlist@cloudflare.com>
+cf-ipfs.com
+cloudflare-ipfs.com
+trycloudflare.com
+pages.dev
+r2.dev
+workers.dev
+cloudflare.net
+cdn.cloudflare.net
+cdn.cloudflareanycast.net
+cdn.cloudflarecn.net
+cdn.cloudflareglobal.net
+
+// cloudscale.ch AG : https://www.cloudscale.ch/
+// Submitted by Gaudenz Steinlin <support@cloudscale.ch>
+cust.cloudscale.ch
+objects.lpg.cloudscale.ch
+objects.rma.cloudscale.ch
+
+// Clovyr : https://clovyr.io
+// Submitted by Patrick Nielsen <patrick@clovyr.io>
+wnext.app
+
 // CNPY : https://cnpy.gdn
 // Submitted by Angelo Gladding <angelo@lahacker.net>
 cnpy.gdn
 
+// Co & Co : https://co-co.nl/
+// Submitted by Govert Versluis <govert@co-co.nl>
+*.otap.co
+
+// co.ca : http://registry.co.ca/
+co.ca
+
+// co.com Registry, LLC : https://registry.co.com
+// Submitted by Gavin Brown <gavin.brown@centralnic.com>
+co.com
+
 // Codeberg e. V. : https://codeberg.org
 // Submitted by Moritz Marquardt <git@momar.de>
 codeberg.page
@@ -12428,6 +12477,10 @@
 webhosting.be
 hosting-cluster.nl
 
+// Contentful GmbH : https://www.contentful.com
+// Submitted by Contentful Developer Experience Team <prd-ecosystem-dx@contentful.com>
+ctfcloud.net
+
 // Convex : https://convex.dev/
 // Submitted by James Cowling <security@convex.dev>
 convex.site
@@ -12444,8 +12497,8 @@
 // COSIMO GmbH : http://www.cosimo.de
 // Submitted by Rene Marticke <rmarticke@cosimo.de>
 dyn.cosidns.de
-dynamisches-dns.de
 dnsupdater.de
+dynamisches-dns.de
 internet-dns.de
 l-o-g-i-n.de
 dynamic-dns.info
@@ -12453,9 +12506,9 @@
 knx-server.net
 static-access.net
 
-// cPanel L.L.C. : https://www.cpanel.net/
-// Submitted by Dustin Scherer <public.suffix@cpanel.net>
-*.cprapid.com
+// Craft Docs Ltd : https://www.craft.do/
+// Submitted by Zsombor Fuszenecker <security@craft.do>
+craft.me
 
 // Craynic, s.r.o. : http://www.craynic.com/
 // Submitted by Ales Krajnik <ales.krajnik@craynic.com>
@@ -12469,28 +12522,13 @@
 // Submitted by Andrew Cady <public-suffix-list@cryptonomic.net>
 *.cryptonomic.net
 
-// Cupcake : https://cupcake.io/
-// Submitted by Jonathan Rudenberg <jonathan@cupcake.io>
-cupcake.is
-
 // Curv UG : https://curv-labs.de/
 // Submitted by Marvin Wiesner <Marvin@curv-labs.de>
 curv.dev
 
-// Customer OCI - Oracle Dyn https://cloud.oracle.com/home https://dyn.com/dns/
-// Submitted by Gregory Drake <support@dyn.com>
-// Note: This is intended to also include customer-oci.com due to wildcards implicitly including the current label
-*.customer-oci.com
-*.oci.customer-oci.com
-*.ocp.customer-oci.com
-*.ocs.customer-oci.com
-
-// Cyclic Software : https://www.cyclic.sh
-// Submitted by Kam Lasater <dns-admin@cyclic.sh>
-cyclic.app
-cyclic.cloud
-cyclic-app.com
-cyclic.co.in
+// cyber_Folks S.A. : https://cyberfolks.pl
+// Submitted by Bartlomiej Kida <security@cyberfolks.pl>
+cfolks.pl
 
 // cyon GmbH : https://www.cyon.ch/
 // Submitted by Dominic Luechinger <dol@cyon.ch>
@@ -12499,23 +12537,9 @@
 
 // Danger Science Group: https://dangerscience.com/
 // Submitted by Skylar MacDonald <skylar@dangerscience.com>
+platform0.app
 fnwk.site
 folionetwork.site
-platform0.app
-
-// Daplie, Inc : https://daplie.com
-// Submitted by AJ ONeal <aj@daplie.com>
-daplie.me
-localhost.daplie.me
-
-// Datto, Inc. : https://www.datto.com/
-// Submitted by Philipp Heckel <ph@datto.com>
-dattolocal.com
-dattorelay.com
-dattoweb.com
-mydatto.com
-dattolocal.net
-mydatto.net
 
 // Dansk.net : http://www.dansk.net/
 // Submitted by Anani Voule <digital@digital.co.dk>
@@ -12525,15 +12549,15 @@
 reg.dk
 store.dk
 
+// Daplie, Inc : https://daplie.com
+// Submitted by AJ ONeal <aj@daplie.com>
+daplie.me
+localhost.daplie.me
+
 // dappnode.io : https://dappnode.io/
 // Submitted by Abel Boldu / DAppNode Team <community@dappnode.io>
 dyndns.dappnode.io
 
-// dapps.earth : https://dapps.earth/
-// Submitted by Daniil Burdakov <icqkill@gmail.com>
-*.dapps.earth
-*.bzz.dapps.earth
-
 // Dark, Inc. : https://darklang.com
 // Submitted by Paul Biggar <ops@darklang.com>
 builtwithdark.com
@@ -12548,14 +12572,40 @@
 // Submitted by Richard Li <secalert@datawire.io>
 edgestack.me
 
+// Datto, Inc. : https://www.datto.com/
+// Submitted by Philipp Heckel <ph@datto.com>
+dattolocal.com
+dattorelay.com
+dattoweb.com
+mydatto.com
+dattolocal.net
+mydatto.net
+
 // DDNS5 : https://ddns5.com
 // Submitted by Cameron Elliott <cameron@cameronelliott.com>
 ddns5.com
 
+// ddnss.de : https://www.ddnss.de/
+// Submitted by Robert Niedziela <webmaster@ddnss.de>
+ddnss.de
+dyn.ddnss.de
+dyndns.ddnss.de
+dyn-ip24.de
+dyndns1.de
+home-webserver.de
+dyn.home-webserver.de
+myhome-server.de
+ddnss.org
+
 // Debian : https://www.debian.org/
 // Submitted by Peter Palfrader / Debian Sysadmin Team <dsa-publicsuffixlist@debian.org>
 debian.net
 
+// Definima : http://www.definima.com/
+// Submitted by Maxence Bitterli <maxence@definima.com>
+definima.io
+definima.net
+
 // Deno Land Inc : https://deno.com/
 // Submitted by Luca Casonato <hostmaster@deno.com>
 deno.dev
@@ -12570,10 +12620,28 @@
 deta.app
 deta.dev
 
+// dhosting.pl Sp. z o.o.: https://dhosting.pl/
+// Submitted by Michal Kokoszkiewicz <bok@dhosting.pl>
+dfirma.pl
+dkonto.pl
+you2.pl
+
+// DigitalOcean App Platform : https://www.digitalocean.com/products/app-platform/
+// Submitted by Braxton Huggins <psl-maintainers@digitalocean.com>
+ondigitalocean.app
+
+// DigitalOcean Spaces : https://www.digitalocean.com/products/spaces/
+// Submitted by Robin H. Johnson <psl-maintainers@digitalocean.com>
+*.digitaloceanspaces.com
+
+// DigitalPlat : https://www.digitalplat.org/
+// Submitted by Edward Hsing <contact@digitalplat.org>
+us.kg
+
 // Diher Solutions : https://diher.solutions
 // Submitted by Didi Hermawan <mail@diher.solutions>
-*.rss.my.id
-*.diher.solutions
+rss.my.id
+diher.solutions
 
 // Discord Inc : https://discord.com
 // Submitted by Sahn Lam <slam@discordapp.com>
@@ -12588,6 +12656,10 @@
 // Submitted by Norbert Auler <mail@dnshome.de>
 dnshome.de
 
+// dnstrace.pro : https://dnstrace.pro/
+// Submitted by Chris Partridge <chris@partridge.tech>
+bci.dnstrace.pro
+
 // DotArai : https://www.dotarai.com/
 // Submitted by Atsadawat Netcharadsang <atsadawat@dotarai.co.th>
 online.th
@@ -12605,6 +12677,10 @@
 // Submitted by Andrew Farmer <andrew.farmer@dreamhost.com>
 dreamhosters.com
 
+// Dreamyoungs, Inc. : https://durumis.com
+// Submitted by Infra Team <infra@durumis.com>
+durumis.com
+
 // Drobo : http://www.drobo.com/
 // Submitted by Ricardo Padilha <rpadilha@drobo.com>
 mydrobo.com
@@ -12618,19 +12694,32 @@
 // Submitted by Richard Harper <richard@duckdns.org>
 duckdns.org
 
-// Bip : https://bip.sh
-// Submitted by Joel Kennedy <joel@bip.sh>
-bip.sh
-
-// bitbridge.net : Submitted by Craig Welch, abeliidev@gmail.com
-bitbridge.net
-
 // dy.fi : http://dy.fi/
 // Submitted by Heikki Hannikainen <hessu@hes.iki.fi>
 dy.fi
 tunk.org
 
 // DynDNS.com : http://www.dyndns.com/services/dns/dyndns/
+dyndns.biz
+for-better.biz
+for-more.biz
+for-some.biz
+for-the.biz
+selfip.biz
+webhop.biz
+ftpaccess.cc
+game-server.cc
+myphotos.cc
+scrapping.cc
+blogdns.com
+cechire.com
+dnsalias.com
+dnsdojo.com
+doesntexist.com
+dontexist.com
+doomdns.com
+dyn-o-saur.com
+dynalias.com
 dyndns-at-home.com
 dyndns-at-work.com
 dyndns-blog.com
@@ -12645,64 +12734,14 @@
 dyndns-web.com
 dyndns-wiki.com
 dyndns-work.com
-dyndns.biz
-dyndns.info
-dyndns.org
-dyndns.tv
-at-band-camp.net
-ath.cx
-barrel-of-knowledge.info
-barrell-of-knowledge.info
-better-than.tv
-blogdns.com
-blogdns.net
-blogdns.org
-blogsite.org
-boldlygoingnowhere.org
-broke-it.net
-buyshouses.net
-cechire.com
-dnsalias.com
-dnsalias.net
-dnsalias.org
-dnsdojo.com
-dnsdojo.net
-dnsdojo.org
-does-it.net
-doesntexist.com
-doesntexist.org
-dontexist.com
-dontexist.net
-dontexist.org
-doomdns.com
-doomdns.org
-dvrdns.org
-dyn-o-saur.com
-dynalias.com
-dynalias.net
-dynalias.org
-dynathome.net
-dyndns.ws
-endofinternet.net
-endofinternet.org
-endoftheinternet.org
 est-a-la-maison.com
 est-a-la-masion.com
 est-le-patron.com
 est-mon-blogueur.com
-for-better.biz
-for-more.biz
-for-our.info
-for-some.biz
-for-the.biz
-forgot.her.name
-forgot.his.name
 from-ak.com
 from-al.com
 from-ar.com
-from-az.net
 from-ca.com
-from-co.net
 from-ct.com
 from-dc.com
 from-de.com
@@ -12715,10 +12754,8 @@
 from-in.com
 from-ks.com
 from-ky.com
-from-la.net
 from-ma.com
 from-md.com
-from-me.org
 from-mi.com
 from-mn.com
 from-mo.com
@@ -12731,7 +12768,6 @@
 from-nj.com
 from-nm.com
 from-nv.com
-from-ny.net
 from-oh.com
 from-ok.com
 from-or.com
@@ -12749,45 +12785,18 @@
 from-wi.com
 from-wv.com
 from-wy.com
-ftpaccess.cc
-fuettertdasnetz.de
-game-host.org
-game-server.cc
 getmyip.com
-gets-it.net
-go.dyndns.org
 gotdns.com
-gotdns.org
-groks-the.info
-groks-this.info
-ham-radio-op.net
-here-for-more.info
 hobby-site.com
-hobby-site.org
-home.dyndns.org
-homedns.org
-homeftp.net
-homeftp.org
-homeip.net
 homelinux.com
-homelinux.net
-homelinux.org
 homeunix.com
-homeunix.net
-homeunix.org
 iamallama.com
-in-the-band.net
 is-a-anarchist.com
 is-a-blogger.com
 is-a-bookkeeper.com
-is-a-bruinsfan.org
 is-a-bulls-fan.com
-is-a-candidate.org
 is-a-caterer.com
-is-a-celticsfan.org
 is-a-chef.com
-is-a-chef.net
-is-a-chef.org
 is-a-conservative.com
 is-a-cpa.com
 is-a-cubicle-slave.com
@@ -12796,31 +12805,25 @@
 is-a-doctor.com
 is-a-financialadvisor.com
 is-a-geek.com
-is-a-geek.net
-is-a-geek.org
 is-a-green.com
 is-a-guru.com
 is-a-hard-worker.com
 is-a-hunter.com
-is-a-knight.org
 is-a-landscaper.com
 is-a-lawyer.com
 is-a-liberal.com
 is-a-libertarian.com
-is-a-linux-user.org
 is-a-llama.com
 is-a-musician.com
 is-a-nascarfan.com
 is-a-nurse.com
 is-a-painter.com
-is-a-patsfan.org
 is-a-personaltrainer.com
 is-a-photographer.com
 is-a-player.com
 is-a-republican.com
 is-a-rockstar.com
 is-a-socialist.com
-is-a-soxfan.org
 is-a-student.com
 is-a-teacher.com
 is-a-techie.com
@@ -12832,113 +12835,150 @@
 is-an-artist.com
 is-an-engineer.com
 is-an-entertainer.com
-is-by.us
 is-certified.com
-is-found.org
 is-gone.com
 is-into-anime.com
 is-into-cars.com
 is-into-cartoons.com
 is-into-games.com
 is-leet.com
-is-lost.org
 is-not-certified.com
-is-saved.org
 is-slick.com
 is-uberleet.com
+is-with-theband.com
+isa-geek.com
+isa-hockeynut.com
+issmarterthanyou.com
+likes-pie.com
+likescandy.com
+neat-url.com
+saves-the-whales.com
+selfip.com
+sells-for-less.com
+sells-for-u.com
+servebbs.com
+simple-url.com
+space-to-rent.com
+teaches-yoga.com
+writesthisblog.com
+ath.cx
+fuettertdasnetz.de
+isteingeek.de
+istmein.de
+lebtimnetz.de
+leitungsen.de
+traeumtgerade.de
+barrel-of-knowledge.info
+barrell-of-knowledge.info
+dyndns.info
+for-our.info
+groks-the.info
+groks-this.info
+here-for-more.info
+knowsitall.info
+selfip.info
+webhop.info
+forgot.her.name
+forgot.his.name
+at-band-camp.net
+blogdns.net
+broke-it.net
+buyshouses.net
+dnsalias.net
+dnsdojo.net
+does-it.net
+dontexist.net
+dynalias.net
+dynathome.net
+endofinternet.net
+from-az.net
+from-co.net
+from-la.net
+from-ny.net
+gets-it.net
+ham-radio-op.net
+homeftp.net
+homeip.net
+homelinux.net
+homeunix.net
+in-the-band.net
+is-a-chef.net
+is-a-geek.net
+isa-geek.net
+kicks-ass.net
+office-on-the.net
+podzone.net
+scrapper-site.net
+selfip.net
+sells-it.net
+servebbs.net
+serveftp.net
+thruhere.net
+webhop.net
+merseine.nu
+mine.nu
+shacknet.nu
+blogdns.org
+blogsite.org
+boldlygoingnowhere.org
+dnsalias.org
+dnsdojo.org
+doesntexist.org
+dontexist.org
+doomdns.org
+dvrdns.org
+dynalias.org
+dyndns.org
+go.dyndns.org
+home.dyndns.org
+endofinternet.org
+endoftheinternet.org
+from-me.org
+game-host.org
+gotdns.org
+hobby-site.org
+homedns.org
+homeftp.org
+homelinux.org
+homeunix.org
+is-a-bruinsfan.org
+is-a-candidate.org
+is-a-celticsfan.org
+is-a-chef.org
+is-a-geek.org
+is-a-knight.org
+is-a-linux-user.org
+is-a-patsfan.org
+is-a-soxfan.org
+is-found.org
+is-lost.org
+is-saved.org
 is-very-bad.org
 is-very-evil.org
 is-very-good.org
 is-very-nice.org
 is-very-sweet.org
-is-with-theband.com
-isa-geek.com
-isa-geek.net
 isa-geek.org
-isa-hockeynut.com
-issmarterthanyou.com
-isteingeek.de
-istmein.de
-kicks-ass.net
 kicks-ass.org
-knowsitall.info
-land-4-sale.us
-lebtimnetz.de
-leitungsen.de
-likes-pie.com
-likescandy.com
-merseine.nu
-mine.nu
 misconfused.org
-mypets.ws
-myphotos.cc
-neat-url.com
-office-on-the.net
-on-the-web.tv
-podzone.net
 podzone.org
 readmyblog.org
-saves-the-whales.com
-scrapper-site.net
-scrapping.cc
-selfip.biz
-selfip.com
-selfip.info
-selfip.net
 selfip.org
-sells-for-less.com
-sells-for-u.com
-sells-it.net
 sellsyourhome.org
-servebbs.com
-servebbs.net
 servebbs.org
-serveftp.net
 serveftp.org
 servegame.org
-shacknet.nu
-simple-url.com
-space-to-rent.com
 stuff-4-sale.org
-stuff-4-sale.us
-teaches-yoga.com
-thruhere.net
-traeumtgerade.de
-webhop.biz
-webhop.info
-webhop.net
 webhop.org
+better-than.tv
+dyndns.tv
+on-the-web.tv
 worse-than.tv
-writesthisblog.com
-
-// ddnss.de : https://www.ddnss.de/
-// Submitted by Robert Niedziela <webmaster@ddnss.de>
-ddnss.de
-dyn.ddnss.de
-dyndns.ddnss.de
-dyndns1.de
-dyn-ip24.de
-home-webserver.de
-dyn.home-webserver.de
-myhome-server.de
-ddnss.org
-
-// Definima : http://www.definima.com/
-// Submitted by Maxence Bitterli <maxence@definima.com>
-definima.net
-definima.io
-
-// DigitalOcean App Platform : https://www.digitalocean.com/products/app-platform/
-// Submitted by Braxton Huggins <psl-maintainers@digitalocean.com>
-ondigitalocean.app
-
-// DigitalOcean Spaces : https://www.digitalocean.com/products/spaces/
-// Submitted by Robin H. Johnson <psl-maintainers@digitalocean.com>
-*.digitaloceanspaces.com
-
-// dnstrace.pro : https://dnstrace.pro/
-// Submitted by Chris Partridge <chris@partridge.tech>
-bci.dnstrace.pro
+is-by.us
+land-4-sale.us
+stuff-4-sale.us
+dyndns.ws
+mypets.ws
 
 // Dynu.com : https://www.dynu.com/
 // Submitted by Sue Ye <sue@dynu.com>
@@ -12958,7 +12998,6 @@
 mywire.org
 webredirect.org
 myddns.rocks
-blogsite.xyz
 
 // dynv6 : https://dynv6.com
 // Submitted by Dominik Menke <dom@digineo.de>
@@ -12977,10 +13016,27 @@
 // Submitted by <infracloudteam@namecheap.com>
 *.ewp.live
 
+// ECG Robotics, Inc : https://ecgrobotics.org
+// Submitted by <frc1533@ecgrobotics.org>
+onred.one
+staging.onred.one
+
+// eDirect Corp. : https://hosting.url.com.tw/
+// Submitted by C.S. chang <cschang@corp.url.com.tw>
+twmail.cc
+twmail.net
+twmail.org
+mymailer.com.tw
+url.tw
+
 // Electromagnetic Field : https://www.emfcamp.org
 // Submitted by <noc@emfcamp.org>
 at.emf.camp
 
+// Elefunc, Inc. : https://elefunc.com
+// Submitted by Cetin Sert <domains@elefunc.com>
+rt.ht
+
 // Elementor : Elementor Ltd.
 // Submitted by Anton Barkan <antonb@elementor.com>
 elementor.cloud
@@ -12991,7 +13047,7 @@
 en-root.fr
 
 // Enalean SAS: https://www.enalean.com
-// Submitted by Thomas Cottier <thomas.cottier@enalean.com>
+// Submitted by Enalean Security Team <security@enalean.com>
 mytuleap.com
 tuleap-partners.com
 
@@ -13000,11 +13056,6 @@
 encr.app
 encoreapi.com
 
-// ECG Robotics, Inc: https://ecgrobotics.org
-// Submitted by <frc1533@ecgrobotics.org>
-onred.one
-staging.onred.one
-
 // encoway GmbH : https://www.encoway.de
 // Submitted by Marcel Daus <cloudops@encoway.de>
 eu.encoway.cloud
@@ -13045,7 +13096,6 @@
 lt.eu.org
 lu.eu.org
 lv.eu.org
-mc.eu.org
 me.eu.org
 mk.eu.org
 mt.eu.org
@@ -13083,13 +13133,15 @@
 us-3.evennode.com
 us-4.evennode.com
 
-// eDirect Corp. : https://hosting.url.com.tw/
-// Submitted by C.S. chang <cschang@corp.url.com.tw>
-twmail.cc
-twmail.net
-twmail.org
-mymailer.com.tw
-url.tw
+// Evervault : https://evervault.com
+// Submitted by Hannah Neary <engineering@evervault.com>
+relay.evervault.app
+relay.evervault.dev
+
+// Expo : https://expo.dev/
+// Submitted by James Ide <psl@expo.dev>
+expo.app
+staging.expo.app
 
 // Fabrica Technologies, Inc. : https://www.fabrica.dev/
 // Submitted by Eric Jiang <eric@fabrica.dev>
@@ -13181,8 +13233,6 @@
 edgecompute.app
 fastly-edge.com
 fastly-terrarium.com
-fastlylb.net
-map.fastlylb.net
 freetls.fastly.net
 map.fastly.net
 a.prod.fastly.net
@@ -13190,6 +13240,8 @@
 a.ssl.fastly.net
 b.ssl.fastly.net
 global.ssl.fastly.net
+fastlylb.net
+map.fastlylb.net
 
 // Fastmail : https://www.fastmail.com/
 // Submitted by Marc Bradshaw <marc@fastmailteam.com>
@@ -13203,6 +13255,12 @@
 fastvps.site
 myfast.space
 
+// FearWorks Media Ltd. : https://fearworksmedia.co.uk
+// submitted by Keith Fairley <domains@fearworksmedia.co.uk>
+conn.uk
+copro.uk
+hosp.uk
+
 // Fedora : https://fedoraproject.org/
 // submitted by Patrick Uiterwijk <puiterwijk@fedoraproject.org>
 fedorainfracloud.org
@@ -13211,12 +13269,6 @@
 app.os.fedoraproject.org
 app.os.stg.fedoraproject.org
 
-// FearWorks Media Ltd. : https://fearworksmedia.co.uk
-// submitted by Keith Fairley <domains@fearworksmedia.co.uk>
-conn.uk
-copro.uk
-hosp.uk
-
 // Fermax : https://fermax.com/
 // submitted by Koen Van Isterdael <k.vanisterdael@fermax.be>
 mydobiss.com
@@ -13228,28 +13280,13 @@
 // Filegear Inc. : https://www.filegear.com
 // Submitted by Jason Zhu <jason@owtware.com>
 filegear.me
-filegear-au.me
-filegear-de.me
-filegear-gb.me
-filegear-ie.me
-filegear-jp.me
-filegear-sg.me
 
 // Firebase, Inc.
 // Submitted by Chris Raynor <chris@firebase.com>
 firebaseapp.com
 
-// Firewebkit : https://www.firewebkit.com
-// Submitted by Majid Qureshi <mqureshi@amrayn.com>
-fireweb.app
-
-// FLAP : https://www.flap.cloud
-// Submitted by Louis Chemineau <louis@chmn.me>
-flap.id
-
 // FlashDrive : https://flashdrive.io
 // Submitted by Eric Chan <support@flashdrive.io>
-onflashdrive.app
 fldrv.com
 
 // FlutterFlow : https://flutterflow.io
@@ -13259,12 +13296,8 @@
 // fly.io: https://fly.io
 // Submitted by Kurt Mackey <kurt@fly.io>
 fly.dev
-edgeapp.net
 shw.io
-
-// Flynn : https://flynn.io
-// Submitted by Jonathan Rudenberg <jonathan@flynn.io>
-flynnhosting.net
+edgeapp.net
 
 // Forgerock : https://www.forgerock.com
 // Submitted by Roderick Parr <roderick.parr@forgerock.com>
@@ -13281,15 +13314,7 @@
 framer.website
 framer.wiki
 
-// Frusky MEDIA&PR : https://www.frusky.de
-// Submitted by Victor Pupynin <hallo@frusky.de>
-*.frusky.de
-
-// RavPage : https://www.ravpage.co.il
-// Submitted by Roni Horowitz <roni@responder.co.il>
-ravpage.co.il
-
-// Frederik Braun https://frederik-braun.com
+// Frederik Braun : https://frederik-braun.com
 // Submitted by Frederik Braun <fb@frederik-braun.com>
 0e.vc
 
@@ -13310,11 +13335,15 @@
 // Submitted by Cadence <contact@freemyip.com>
 freemyip.com
 
+// Frusky MEDIA&PR : https://www.frusky.de
+// Submitted by Victor Pupynin <hallo@frusky.de>
+*.frusky.de
+
 // FunkFeuer - Verein zur Förderung freier Netze : https://www.funkfeuer.at
 // Submitted by Daniel A. Maierhofer <vorstand@funkfeuer.at>
 wien.funkfeuer.at
 
-// Future Versatile Group. :https://www.fvg-on.net/
+// Future Versatile Group. : https://www.fvg-on.net/
 // T.Kabu <webmaster@fvg-on.net>
 daemon.asia
 dix.asia
@@ -13349,6 +13378,8 @@
 
 // GDS : https://www.gov.uk/service-manual/technology/managing-domain-names
 // Submitted by Stephen Ford <hostmaster@digital.cabinet-office.gov.uk>
+campaign.gov.uk
+service.gov.uk
 independent-commission.uk
 independent-inquest.uk
 independent-inquiry.uk
@@ -13356,12 +13387,6 @@
 independent-review.uk
 public-inquiry.uk
 royal-commission.uk
-campaign.gov.uk
-service.gov.uk
-
-// CDDO : https://www.gov.uk/guidance/get-an-api-domain-on-govuk
-// Submitted by Jamie Tanna <jamie.tanna@digital.cabinet-office.gov.uk>
-api.gov.uk
 
 // Gehirn Inc. : https://www.gehirn.co.jp/
 // Submitted by Kohei YOSHIDA <tech@gehirn.co.jp>
@@ -13381,10 +13406,6 @@
 localhostcert.net
 corpnet.work
 
-// Ghost Foundation : https://ghost.org
-// Submitted by Matt Hanley <security@ghost.org>
-ghost.io
-
 // GignoSystemJapan: http://gsj.bz
 // Submitted by GignoSystemJapan <kakutou-ec@gsj.bz>
 gsj.bz
@@ -13531,89 +13552,68 @@
 // Submitted by Rohan Durrant <tldns@registry.godaddy>
 graphic.design
 
-// GOV.UK Platform as a Service : https://www.cloud.service.gov.uk/
-// Submitted by Tom Whitwell <gov-uk-paas-support@digital.cabinet-office.gov.uk>
-cloudapps.digital
-london.cloudapps.digital
-
-// GOV.UK Pay : https://www.payments.service.gov.uk/
-// Submitted by Richard Baker <richard.baker@digital.cabinet-office.gov.uk>
-pymnt.uk
-
-// GlobeHosting, Inc.
-// Submitted by Zoltan Egresi <egresi@globehosting.com>
-ro.im
-
 // GoIP DNS Services : http://www.goip.de
 // Submitted by Christian Poulter <milchstrasse@goip.de>
 goip.de
 
 // Google, Inc.
-// Submitted by Eduardo Vela <evn@google.com>
-*.run.app
-web.app
-*.0emm.com
-appspot.com
-*.r.appspot.com
-codespot.com
-googleapis.com
-googlecode.com
-pagespeedmobilizer.com
-publishproxy.com
-withgoogle.com
-withyoutube.com
-*.gateway.dev
-cloud.goog
-translate.goog
-*.usercontent.goog
-cloudfunctions.net
+// Submitted by Shannon McCabe <public-suffix-editors@google.com>
 blogspot.ae
 blogspot.al
 blogspot.am
+*.hosted.app
+*.run.app
+web.app
+blogspot.com.ar
+blogspot.co.at
+blogspot.com.au
 blogspot.ba
 blogspot.be
 blogspot.bg
 blogspot.bj
+blogspot.com.br
+blogspot.com.by
 blogspot.ca
 blogspot.cf
 blogspot.ch
 blogspot.cl
-blogspot.co.at
-blogspot.co.id
-blogspot.co.il
-blogspot.co.ke
-blogspot.co.nz
-blogspot.co.uk
-blogspot.co.za
-blogspot.com
-blogspot.com.ar
-blogspot.com.au
-blogspot.com.br
-blogspot.com.by
 blogspot.com.co
+*.0emm.com
+appspot.com
+*.r.appspot.com
+blogspot.com
+codespot.com
+googleapis.com
+googlecode.com
+pagespeedmobilizer.com
+withgoogle.com
+withyoutube.com
+blogspot.cv
 blogspot.com.cy
+blogspot.cz
+blogspot.de
+*.gateway.dev
+blogspot.dk
 blogspot.com.ee
 blogspot.com.eg
 blogspot.com.es
-blogspot.com.mt
-blogspot.com.ng
-blogspot.com.tr
-blogspot.com.uy
-blogspot.cv
-blogspot.cz
-blogspot.de
-blogspot.dk
 blogspot.fi
 blogspot.fr
+cloud.goog
+translate.goog
+*.usercontent.goog
 blogspot.gr
 blogspot.hk
 blogspot.hr
 blogspot.hu
+blogspot.co.id
 blogspot.ie
+blogspot.co.il
 blogspot.in
 blogspot.is
 blogspot.it
 blogspot.jp
+blogspot.co.ke
 blogspot.kr
 blogspot.li
 blogspot.lt
@@ -13621,10 +13621,14 @@
 blogspot.md
 blogspot.mk
 blogspot.mr
+blogspot.com.mt
 blogspot.mx
 blogspot.my
+cloudfunctions.net
+blogspot.com.ng
 blogspot.nl
 blogspot.no
+blogspot.co.nz
 blogspot.pe
 blogspot.pt
 blogspot.qa
@@ -13638,14 +13642,27 @@
 blogspot.sk
 blogspot.sn
 blogspot.td
+blogspot.com.tr
 blogspot.tw
 blogspot.ug
+blogspot.co.uk
+blogspot.com.uy
 blogspot.vn
+blogspot.co.za
 
 // Goupile : https://goupile.fr
 // Submitted by Niels Martignene <hello@goupile.fr>
 goupile.fr
 
+// GOV.UK Pay : https://www.payments.service.gov.uk/
+// Submitted by Richard Baker <richard.baker@digital.cabinet-office.gov.uk>
+pymnt.uk
+
+// GOV.UK Platform as a Service : https://www.cloud.service.gov.uk/
+// Submitted by Tom Whitwell <gov-uk-paas-support@digital.cabinet-office.gov.uk>
+cloudapps.digital
+london.cloudapps.digital
+
 // Government of the Netherlands: https://www.government.nl
 // Submitted by <domeinnaam@minaz.nl>
 gov.nl
@@ -13654,10 +13671,6 @@
 // Submitted by Matt Yamkowy <info@grayjaysports.ca>
 grayjayleagues.com
 
-// Group 53, LLC : https://www.group53.com
-// Submitted by Tyler Todd <noc@nova53.net>
-awsmppl.com
-
 // GünstigBestellen : https://günstigbestellen.de
 // Submitted by Furkan Akkoc <info@hendelzon.de>
 günstigbestellen.de
@@ -13671,10 +13684,14 @@
 ua.rs
 conf.se
 
+// Häkkinen.fi
+// Submitted by Eero Häkkinen <Eero+psl@Häkkinen.fi>
+häkkinen.fi
+
 // Handshake : https://handshake.org
 // Submitted by Mike Damm <md@md.vc>
-hs.zone
 hs.run
+hs.zone
 
 // Hashbang : https://hashbang.sh
 hashbang.sh
@@ -13684,10 +13701,23 @@
 hasura.app
 hasura-app.io
 
+// Hatena Co., Ltd. : https://hatena.co.jp
+// Submitted by Masato Nakamura <blog-developers@hatena.ne.jp>
+hatenablog.com
+hatenadiary.com
+hateblo.jp
+hatenablog.jp
+hatenadiary.jp
+hatenadiary.org
+
 // Heilbronn University of Applied Sciences - Faculty Informatics (GitLab Pages): https://www.hs-heilbronn.de
 // Submitted by Richard Zowalla <mi-admin@hs-heilbronn.de>
 pages.it.hs-heilbronn.de
 
+// HeiyuSpace: https://lazycat.cloud
+// Submitted by Xia Bin <admin@lazycat.cloud>
+heiyu.space
+
 // Helio Networks : https://heliohost.org
 // Submitted by Ben Frede <admin@heliohost.org>
 helioho.st
@@ -13727,50 +13757,62 @@
 // Submitted by Danilo De Franco<info@hoplix.shop>
 hoplix.shop
 
-
 // HOSTBIP REGISTRY : https://www.hostbip.com/
 // Submitted by Atanunu Igbunuroghene <publicsuffixlist@hostbip.com>
 orx.biz
 biz.gl
+biz.ng
 col.ng
 firm.ng
 gen.ng
 ltd.ng
 ngo.ng
-edu.scot
-sch.so
+plc.ng
+// Reserved Third Level Subdomains for BIZ.NG
+co.biz.ng
+dl.biz.ng
+go.biz.ng
+lg.biz.ng
+on.biz.ng
 
 // HostFly : https://www.ie.ua
 // Submitted by Bohdan Dub <support@hostfly.com.ua>
 ie.ua
 
-// HostyHosting (hostyhosting.com)
+// HostyHosting : https://hostyhosting.com
 hostyhosting.io
 
-// Häkkinen.fi
-// Submitted by Eero Häkkinen <Eero+psl@Häkkinen.fi>
-häkkinen.fi
+// Hypernode B.V. : https://www.hypernode.com/
+// Submitted by Cipriano Groenendal <security@nl.team.blue>
+hypernode.io
+
+// I-O DATA DEVICE, INC. : http://www.iodata.com/
+// Submitted by Yuji Minagawa <domains-admin@iodata.jp>
+iobb.net
+
+// i-registry s.r.o. : http://www.i-registry.cz/
+// Submitted by Martin Semrad <semrad@i-registry.cz>
+co.cz
 
 // Ici la Lune : http://www.icilalune.com/
 // Submitted by Simon Morvan <simon@icilalune.com>
 *.moonscale.io
 moonscale.net
 
+// iDOT Services Limited : http://www.domain.gr.com
+// Submitted by Gavin Brown <gavin.brown@centralnic.com>
+gr.com
+
 // iki.fi
 // Submitted by Hannu Aronsson <haa@iki.fi>
 iki.fi
 
-// iliad italia: https://www.iliad.it
+// iliad italia : https://www.iliad.it
 // Submitted by Marios Makassikis <mmakassikis@freebox.fr>
 ibxos.it
 iliadboxos.it
 
-// Impertrix Solutions : <https://impertrixcdn.com>
-// Submitted by Zhixiang Zhao <csuite@impertrix.com>
-impertrixcdn.com
-impertrix.com
-
-// Incsub, LLC: https://incsub.com/
+// Incsub, LLC : https://incsub.com/
 // Submitted by Aaron Edwards <sysadmins@incsub.com>
 smushcdn.com
 wphostedmail.com
@@ -13785,10 +13827,10 @@
 in-brb.de
 in-butter.de
 in-dsl.de
-in-dsl.net
-in-dsl.org
 in-vpn.de
+in-dsl.net
 in-vpn.net
+in-dsl.org
 in-vpn.org
 
 // info.at : http://www.info.at/
@@ -13833,10 +13875,19 @@
 // Submitted by Wolfgang Schwarz <admin@intermetrics.de>
 pixolino.com
 
-// Internet-Pro, LLP: https://netangels.ru/
+// Internet-Pro, LLP : https://netangels.ru/
 // Submitted by Vasiliy Sheredeko <piphon@gmail.com>
 na4u.ru
 
+// IONOS SE : https://www.ionos.com/,
+// IONOS Group SE: https://www.ionos-group.com/
+// submitted by Henrik Willert <security@ionos.com>
+apps-1and1.com
+live-website.com
+apps-1and1.net
+websitebuilder.online
+app-ionos.space
+
 // iopsys software solutions AB : https://iopsys.eu/
 // Submitted by Roman Azarenko <roman.azarenko@iopsys.eu>
 iopsys.se
@@ -13845,14 +13896,18 @@
 // Submitted by Matthew Hardeman <mhardeman@ipifony.com>
 ipifony.net
 
-// is-a.dev : https://www.is-a.dev
-// Submitted by William Harrison <admin@maintainers.is-a.dev>
-is-a.dev
-
 // ir.md : https://nic.ir.md
 // Submitted by Ali Soizi <info@nic.ir.md>
 ir.md
 
+// is-a-good.dev : https://is-a-good.dev
+// Submitted by William Harrison <webmaster@is-a-good.dev>
+is-a-good.dev
+
+// is-a.dev : https://www.is-a.dev
+// Submitted by William Harrison <admin@m.is-a.dev>
+is-a.dev
+
 // IServ GmbH : https://iserv.de
 // Submitted by Mario Hoberg <info@iserv.de>
 iservschule.de
@@ -13862,15 +13917,10 @@
 test-iserv.de
 iserv.dev
 
-// I-O DATA DEVICE, INC. : http://www.iodata.com/
-// Submitted by Yuji Minagawa <domains-admin@iodata.jp>
-iobb.net
-
 // Jelastic, Inc. : https://jelastic.com/
 // Submitted by Ihor Kolodyuk <ik@jelastic.com>
 mel.cloudlets.com.au
 cloud.interhostsolutions.be
-mycloud.by
 alp1.ae.flow.ch
 appengine.flow.ch
 es-1.axarnet.cloud
@@ -13892,7 +13942,6 @@
 ch.trendhosting.cloud
 de.trendhosting.cloud
 jele.club
-amscompute.com
 dopaas.com
 paas.hosted-by-previder.com
 rag-cloud.hosteur.com
@@ -13900,10 +13949,8 @@
 jcloud.ik-server.com
 jcloud-ver-jpc.ik-server.com
 demo.jelastic.com
-kilatiron.com
 paas.massivegrid.com
 jed.wafaicloud.com
-lon.wafaicloud.com
 ryd.wafaicloud.com
 j.scaleforce.com.cy
 jelastic.dogado.eu
@@ -13915,18 +13962,14 @@
 paas.beebyte.io
 sekd1.beebyteapp.io
 jele.io
-cloud-fr1.unispace.io
 jc.neen.it
-cloud.jelastic.open.tim.it
 jcloud.kz
-upaas.kazteleport.kz
 cloudjiffy.net
 fra1-de.cloudjiffy.net
 west1-us.cloudjiffy.net
 jls-sto1.elastx.net
 jls-sto2.elastx.net
 jls-sto3.elastx.net
-faststacks.net
 fr-1.paas.massivegrid.net
 lon-1.paas.massivegrid.net
 lon-2.paas.massivegrid.net
@@ -13936,11 +13979,9 @@
 jelastic.saveincloud.net
 nordeste-idc.saveincloud.net
 j.scaleforce.net
-jelastic.tsukaeru.net
 sdscloud.pl
 unicloud.pl
 mircloud.ru
-jelastic.regruhosting.ru
 enscaled.sg
 jele.site
 jelastic.team
@@ -13961,10 +14002,15 @@
 // Submitted by Daniel Fariña <ingenieria@jotelulu.com>
 jotelulu.cloud
 
+// JouwWeb B.V. : https://www.jouwweb.nl
+// Submitted by Camilo Sperberg <tech@webador.com>
+webadorsite.com
+jouwweb.site
+
 // Joyent : https://www.joyent.com/
 // Submitted by Brian Bennett <brian.bennett@joyent.com>
-*.triton.zone
 *.cns.joyent.com
+*.triton.zone
 
 // JS.ORG : http://dns.js.org
 // Submitted by Stefan Keim <admin@js.org>
@@ -13983,6 +14029,11 @@
 // Submitted by Tomi Juntunen <erani@kapsi.fi>
 kapsi.fi
 
+// Katholieke Universiteit Leuven: https://www.kuleuven.be
+// Submitted by Abuse KU Leuven <abuse@kuleuven.be>
+ezproxy.kuleuven.be
+kuleuven.cloud
+
 // Keyweb AG : https://www.keyweb.de
 // Submitted by Martin Dannehl <postmaster@keymachine.de>
 keymachine.de
@@ -14000,24 +14051,15 @@
 // Submitted by Iván Oliva <ivan.oliva@koobin.com>
 koobin.events
 
+// Krellian Ltd. : https://krellian.com
+// Submitted by Ben Francis <ben@krellian.com>
+webthings.io
+krellian.net
+
 // KUROKU LTD : https://kuroku.ltd/
 // Submitted by DisposaBoy <security@oya.to>
 oya.to
 
-// Katholieke Universiteit Leuven: https://www.kuleuven.be
-// Submitted by Abuse KU Leuven <abuse@kuleuven.be>
-kuleuven.cloud
-ezproxy.kuleuven.be
-
-// .KRD : http://nic.krd/data/krd/Registration%20Policy.pdf
-co.krd
-edu.krd
-
-// Krellian Ltd. : https://krellian.com
-// Submitted by Ben Francis <ben@krellian.com>
-krellian.net
-webthings.io
-
 // LCube - Professional hosting e.K. : https://www.lcube-webhosting.de
 // Submitted by Lars Laehn <info@lcube.de>
 git-repos.de
@@ -14034,6 +14076,10 @@
 // Submitted by Lelux Admin <publisuffix@lelux.site>
 lelux.site
 
+// libp2p project : https://libp2p.io
+// Submitted by Interplanetary Shipyard <psl@ipshipyard.com>
+libp2p.direct
+
 // Libre IT Ltd : https://libre.nz
 // Submitted by Tomas Maggio <support@libre.nz>
 runcontainers.dev
@@ -14048,14 +14094,10 @@
 co.place
 co.technology
 
-// Lightmaker Property Manager, Inc. : https://app.lmpm.com/
-// Submitted by Greg Holland <greg.holland@lmpm.com>
-app.lmpm.com
-
 // linkyard ldt: https://www.linkyard.ch/
 // Submitted by Mario Siegenthaler <mario.siegenthaler@linkyard.ch>
-linkyard.cloud
 linkyard-cloud.ch
+linkyard.cloud
 
 // Linode : https://linode.com
 // Submitted by <security@linode.com>
@@ -14068,14 +14110,15 @@
 // Submitted by Victor Velchev <admin@liquidnetlimited.com>
 we.bs
 
+// Listen53 : https://www.l53.net
+// Submitted by Gerry Keh <biz@l53.net>
+filegear-sg.me
+ggff.net
+
 // Localcert : https://localcert.dev
 // Submitted by Lann Martin <security@localcert.dev>
 *.user.localcert.dev
 
-// localzone.xyz
-// Submitted by Kenny Niehage <hello@yahe.sh>
-localzone.xyz
-
 // Log'in Line : https://www.loginline.com/
 // Submitted by Rémi Mach <remi.mach@loginline.com>
 loginline.app
@@ -14084,14 +14127,14 @@
 loginline.services
 loginline.site
 
-// Lokalized : https://lokalized.nl
-// Submitted by Noah Taheij <noah@lokalized.nl>
-servers.run
-
 // Lõhmus Family, The
 // Submitted by Heiki Lõhmus <hostmaster at lohmus dot me>
 lohmus.me
 
+// Lokalized : https://lokalized.nl
+// Submitted by Noah Taheij <noah@lokalized.nl>
+servers.run
+
 // LubMAN UMCS Sp. z o.o : https://lubman.pl/
 // Submitted by Ireneusz Maliszewski <ireneusz.maliszewski@lubman.pl>
 krasnik.pl
@@ -14110,18 +14153,19 @@
 // Lukanet Ltd : https://lukanet.com
 // Submitted by Anton Avramov <register@lukanet.com>
 barsy.bg
-barsy.co.uk
-barsyonline.co.uk
+barsy.club
 barsycenter.com
 barsyonline.com
-barsy.club
 barsy.de
+barsy.dev
 barsy.eu
+barsy.gr
 barsy.in
 barsy.info
 barsy.io
 barsy.me
 barsy.menu
+barsyonline.menu
 barsy.mobi
 barsy.net
 barsy.online
@@ -14129,42 +14173,50 @@
 barsy.pro
 barsy.pub
 barsy.ro
+barsy.rs
 barsy.shop
+barsyonline.shop
 barsy.site
+barsy.store
 barsy.support
 barsy.uk
+barsy.co.uk
+barsyonline.co.uk
 
 // Magento Commerce
 // Submitted by Damien Tournoud <dtournoud@magento.cloud>
 *.magentosite.cloud
 
+// Mail.Ru Group : https://hb.cldmail.ru
+// Submitted by Ilya Zaretskiy <zaretskiy@corp.mail.ru>
+hb.cldmail.ru
+
+// MathWorks : https://www.mathworks.com/
+// Submitted by Emily Reed <psl-maintainers@groups.mathworks.com>
+matlab.cloud
+modelscape.com
+mwcloudnonprod.com
+polyspace.com
+
 // May First - People Link : https://mayfirst.org/
 // Submitted by Jamie McClelland <info@mayfirst.org>
 mayfirst.info
 mayfirst.org
 
-// Mail.Ru Group : https://hb.cldmail.ru
-// Submitted by Ilya Zaretskiy <zaretskiy@corp.mail.ru>
-hb.cldmail.ru
-
-// Mail Transfer Platform : https://www.neupeer.com
-// Submitted by Li Hui <lihui@neupeer.com>
-cn.vu
-
 // Maze Play: https://www.mazeplay.com
 // Submitted by Adam Humpherys <adam@mws.dev>
 mazeplay.com
 
-// mcpe.me : https://mcpe.me
-// Submitted by Noa Heyl <hi@noa.dev>
-mcpe.me
-
 // McHost : https://mchost.ru
 // Submitted by Evgeniy Subbotin <e.subbotin@mchost.ru>
 mcdir.me
 mcdir.ru
-mcpre.ru
 vps.mcdir.ru
+mcpre.ru
+
+// mcpe.me : https://mcpe.me
+// Submitted by Noa Heyl <hi@noa.dev>
+mcpe.me
 
 // Mediatech : https://mediatech.by
 // Submitted by Evgeniy Kozhuhovskiy <ugenk@mediatech.by>
@@ -14212,12 +14264,10 @@
 // Managed by Corporate Domains
 // Microsoft Azure : https://home.azure
 *.azurecontainer.io
-cloudapp.azure.com
 azure-api.net
+azure-mobile.net
 azureedge.net
 azurefd.net
-azurewebsites.net
-azure-mobile.net
 azurestaticapps.net
 1.azurestaticapps.net
 2.azurestaticapps.net
@@ -14231,19 +14281,23 @@
 eastus2.azurestaticapps.net
 westeurope.azurestaticapps.net
 westus2.azurestaticapps.net
+azurewebsites.net
 cloudapp.net
 trafficmanager.net
 blob.core.windows.net
 servicebus.windows.net
 
+// MikroTik: https://mikrotik.com
+// Submitted by MikroTik SysAdmin Team <support@mikrotik.com>
+routingthecloud.com
+sn.mynetname.net
+routingthecloud.net
+routingthecloud.org
+
 // minion.systems : http://minion.systems
 // Submitted by Robert Böttinger <r@minion.systems>
 csx.cc
 
-// Mintere : https://mintere.com/
-// Submitted by Ben Aubin <security@mintere.com>
-mintere.site
-
 // MobileEducation, LLC : https://joinforte.com
 // Submitted by Grayson Martin <grayson.martin@mobileeducation.us>
 forte.id
@@ -14252,10 +14306,6 @@
 // Submitted by Elizabeth Southwell <elizabeth@modx.com>
 modx.dev
 
-// Mozilla Corporation : https://mozilla.com
-// Submitted by Ben Francis <bfrancis@mozilla.com>
-mozilla-iot.org
-
 // Mozilla Foundation : https://mozilla.org/
 // Submitted by glob <glob@mozilla.com>
 bmoattachments.org
@@ -14269,8 +14319,8 @@
 // Mythic Beasts : https://www.mythic-beasts.com
 // Submitted by Paul Cammish <kelduum@mythic-beasts.com>
 hostedpi.com
-customer.mythic-beasts.com
 caracal.mythic-beasts.com
+customer.mythic-beasts.com
 fentiger.mythic-beasts.com
 lynx.mythic-beasts.com
 ocelot.mythic-beasts.com
@@ -14290,6 +14340,10 @@
 // Submitted by Jan Jaeschke <jan.jaeschke@netatwork.de>
 cloud.nospamproxy.com
 
+// Netfy Domains : https://netfy.domains
+// Submitted by Suranga Ranasinghe <security@mavicsoft.com>
+netfy.app
+
 // Netlify : https://www.netlify.com
 // Submitted by Jessica Parsons <jessica@netlify.com>
 netlify.app
@@ -14298,6 +14352,18 @@
 // Submitted by Trung Tran <Trung.Tran@neustar.biz>
 4u.com
 
+// NFSN, Inc. : https://www.NearlyFreeSpeech.NET/
+// Submitted by Jeff Wheelhouse <support@nearlyfreespeech.net>
+nfshost.com
+
+// NFT.Storage : https://nft.storage/
+// Submitted by Vasco Santos <vasco.santos@protocol.ai> or <support@nft.storage>
+ipfs.nftstorage.link
+
+// NGO.US Registry : https://nic.ngo.us
+// Submitted by Alstra Solutions Ltd. Networking Team <admin@alstra.org>
+ngo.us
+
 // ngrok : https://ngrok.com/
 // Submitted by Alan Shreve <alan@ngrok.com>
 ngrok.app
@@ -14323,13 +14389,97 @@
 nh-serv.co.uk
 nimsite.uk
 
-// NFSN, Inc. : https://www.NearlyFreeSpeech.NET/
-// Submitted by Jeff Wheelhouse <support@nearlyfreespeech.net>
-nfshost.com
+// No-IP.com : https://noip.com/
+// Submitted by Deven Reza <publicsuffixlist@noip.com>
+mmafan.biz
+myftp.biz
+no-ip.biz
+no-ip.ca
+fantasyleague.cc
+gotdns.ch
+3utilities.com
+blogsyte.com
+ciscofreak.com
+damnserver.com
+ddnsking.com
+ditchyourip.com
+dnsiskinky.com
+dynns.com
+geekgalaxy.com
+health-carereform.com
+homesecuritymac.com
+homesecuritypc.com
+myactivedirectory.com
+mysecuritycamera.com
+myvnc.com
+net-freaks.com
+onthewifi.com
+point2this.com
+quicksytes.com
+securitytactics.com
+servebeer.com
+servecounterstrike.com
+serveexchange.com
+serveftp.com
+servegame.com
+servehalflife.com
+servehttp.com
+servehumour.com
+serveirc.com
+servemp3.com
+servep2p.com
+servepics.com
+servequake.com
+servesarcasm.com
+stufftoread.com
+unusualperson.com
+workisboring.com
+dvrcam.info
+ilovecollege.info
+no-ip.info
+brasilia.me
+ddns.me
+dnsfor.me
+hopto.me
+loginto.me
+noip.me
+webhop.me
+bounceme.net
+ddns.net
+eating-organic.net
+mydissent.net
+myeffect.net
+mymediapc.net
+mypsx.net
+mysecuritycamera.net
+nhlfan.net
+no-ip.net
+pgafan.net
+privatizehealthinsurance.net
+redirectme.net
+serveblog.net
+serveminecraft.net
+sytes.net
+cable-modem.org
+collegefan.org
+couchpotatofries.org
+hopto.org
+mlbfan.org
+myftp.org
+mysecuritycamera.org
+nflfan.org
+no-ip.org
+read-books.org
+ufcfan.org
+zapto.org
+no-ip.co.uk
+golffan.us
+noip.us
+pointto.us
 
-// NFT.Storage : https://nft.storage/
-// Submitted by Vasco Santos <vasco.santos@protocol.ai> or <support@nft.storage>
-ipfs.nftstorage.link
+// NodeArt : https://nodeart.io
+// Submitted by Konstantin Nosov <Nosov@nodeart.io>
+stage.nodeart.io
 
 // Noop : https://noop.app
 // Submitted by Nathaniel Schweinberg <noop@rearc.io>
@@ -14348,18 +14498,18 @@
 // Submitted by Laurent Pellegrino <security@noticeable.io>
 noticeable.news
 
+// Notion Labs, Inc : https://www.notion.so/
+// Submitted by Jess Yao <trust-core-team@makenotion.com>
+notion.site
+
 // Now-DNS : https://now-dns.com
 // Submitted by Steve Russell <steve@now-dns.com>
 dnsking.ch
 mypi.co
 n4t.co
 001www.com
-ddnslive.com
 myiphost.com
 forumz.info
-16-b.it
-32-b.it
-64-b.it
 soundcast.me
 tcp4.me
 dnsup.net
@@ -14373,123 +14523,30 @@
 now-dns.top
 ntdll.top
 freeddns.us
-crafting.xyz
-zapto.xyz
 
 // nsupdate.info : https://www.nsupdate.info/
 // Submitted by Thomas Waldmann <info@nsupdate.info>
 nsupdate.info
 nerdpol.ovh
 
-// No-IP.com : https://noip.com/
-// Submitted by Deven Reza <publicsuffixlist@noip.com>
-blogsyte.com
-brasilia.me
-cable-modem.org
-ciscofreak.com
-collegefan.org
-couchpotatofries.org
-damnserver.com
-ddns.me
-ditchyourip.com
-dnsfor.me
-dnsiskinky.com
-dvrcam.info
-dynns.com
-eating-organic.net
-fantasyleague.cc
-geekgalaxy.com
-golffan.us
-health-carereform.com
-homesecuritymac.com
-homesecuritypc.com
-hopto.me
-ilovecollege.info
-loginto.me
-mlbfan.org
-mmafan.biz
-myactivedirectory.com
-mydissent.net
-myeffect.net
-mymediapc.net
-mypsx.net
-mysecuritycamera.com
-mysecuritycamera.net
-mysecuritycamera.org
-net-freaks.com
-nflfan.org
-nhlfan.net
-no-ip.ca
-no-ip.co.uk
-no-ip.net
-noip.us
-onthewifi.com
-pgafan.net
-point2this.com
-pointto.us
-privatizehealthinsurance.net
-quicksytes.com
-read-books.org
-securitytactics.com
-serveexchange.com
-servehumour.com
-servep2p.com
-servesarcasm.com
-stufftoread.com
-ufcfan.org
-unusualperson.com
-workisboring.com
-3utilities.com
-bounceme.net
-ddns.net
-ddnsking.com
-gotdns.ch
-hopto.org
-myftp.biz
-myftp.org
-myvnc.com
-no-ip.biz
-no-ip.info
-no-ip.org
-noip.me
-redirectme.net
-servebeer.com
-serveblog.net
-servecounterstrike.com
-serveftp.com
-servegame.com
-servehalflife.com
-servehttp.com
-serveirc.com
-serveminecraft.net
-servemp3.com
-servepics.com
-servequake.com
-sytes.net
-webhop.me
-zapto.org
-
-// NodeArt : https://nodeart.io
-// Submitted by Konstantin Nosov <Nosov@nodeart.io>
-stage.nodeart.io
-
-// Nucleos Inc. : https://nucleos.com
-// Submitted by Piotr Zduniak <piotr@nucleos.com>
-pcloud.host
-
-// NYC.mn : http://www.information.nyc.mn
-// Submitted by Matthew Brown <mattbrown@nyc.mn>
+// NYC.mn : https://dot.nyc.mn/
+// Submitted by NYC.mn Subdomain Service <nyc.mn@mailfence.com>
 nyc.mn
 
+// O3O.Foundation : https://o3o.foundation/
+// Submitted by the prvcy.page Registry Team <psl@registry.prvcy.page>
+prvcy.page
+
+// Obl.ong : <https://obl.ong>
+// Submitted by Reese Armstrong <team@obl.ong>
+obl.ong
+
 // Observable, Inc. : https://observablehq.com
 // Submitted by Mike Bostock <dns@observablehq.com>
+observablehq.cloud
 static.observableusercontent.com
 
-// Octopodal Solutions, LLC. : https://ulterius.io/
-// Submitted by Andrew Sampson <andrew@ulterius.io>
-cya.gg
-
-// OMG.LOL : <https://omg.lol>
+// OMG.LOL : https://omg.lol
 // Submitted by Adam Newbold <adam@omg.lol>
 omg.lol
 
@@ -14503,32 +14560,29 @@
 
 // One.com: https://www.one.com/
 // Submitted by Jacob Bunk Nielsen <jbn@one.com>
-123hjemmeside.dk
-123hjemmeside.no
-123homepage.it
-123kotisivu.fi
-123minsida.se
-123miweb.es
-123paginaweb.pt
-123siteweb.fr
 123webseite.at
-123webseite.de
 123website.be
+simplesite.com.br
 123website.ch
+simplesite.com
+123webseite.de
+123hjemmeside.dk
+123miweb.es
+123kotisivu.fi
+123siteweb.fr
+simplesite.gr
+123homepage.it
 123website.lu
 123website.nl
+123hjemmeside.no
 service.one
-simplesite.com
-simplesite.com.br
-simplesite.gr
 simplesite.pl
-
-// One Fold Media : http://www.onefoldmedia.com/
-// Submitted by Eddie Jones <eddie@onefoldmedia.com>
-nid.io
+123paginaweb.pt
+123minsida.se
 
 // Open Domains : https://open-domains.net
 // Submitted by William Harrison <admin@open-domains.net>
+is-a-fullstack.dev
 is-cool.dev
 is-not-a.dev
 localplayer.dev
@@ -14542,6 +14596,12 @@
 // Submitted by Sven Marnach <sven@opencraft.com>
 opencraft.hosting
 
+// OpenHost : https://registry.openhost.uk
+// Submitted by OpenHost Registry Team <support@openhost.uk>
+16-b.it
+32-b.it
+64-b.it
+
 // OpenResearch GmbH: https://openresearch.com/
 // Submitted by Philipp Schmid <ops@openresearch.com>
 orsites.com
@@ -14550,6 +14610,17 @@
 // Submitted by Yngve Pettersen <yngve@opera.com>
 operaunite.com
 
+// Oracle Dyn : https://cloud.oracle.com/home https://dyn.com/dns/
+// Submitted by Gregory Drake <support@dyn.com>
+// Note: This is intended to also include customer-oci.com due to wildcards implicitly including the current label
+*.customer-oci.com
+*.oci.customer-oci.com
+*.ocp.customer-oci.com
+*.ocs.customer-oci.com
+*.oraclecloudapps.com
+*.oraclegovcloudapps.com
+*.oraclegovcloudapps.uk
+
 // Orange : https://www.orange.com
 // Submitted by Alexandre Linte <alexandre.linte@orange.com>
 tech.orange
@@ -14571,8 +14642,8 @@
 
 // OVHcloud: https://ovhcloud.com
 // Submitted by Vincent Cassé <vincent.casse@ovhcloud.com>
-*.webpaas.ovh.net
 *.hosting.ovh.net
+*.webpaas.ovh.net
 
 // OwnProvider GmbH: http://www.ownprovider.com
 // Submitted by Jan Moennich <jan.moennich@ownprovider.com>
@@ -14595,14 +14666,15 @@
 // Submitted by Derek Myers <derek@pagefog.com>
 pgfog.com
 
-// Pagefront : https://www.pagefronthq.com/
-// Submitted by Jason Kriss <jason@pagefronthq.com>
-pagefrontapp.com
-
 // PageXL : https://pagexl.com
 // Submitted by Yann Guichard <yann@pagexl.com>
 pagexl.com
 
+// Pantheon Systems, Inc. : https://pantheon.io/
+// Submitted by Gary Dylina <gary@pantheon.io>
+gotpantheon.com
+pantheonsite.io
+
 // Paywhirl, Inc : https://paywhirl.com/
 // Submitted by Daniel Netzer <dan@paywhirl.com>
 *.paywhirl.com
@@ -14610,26 +14682,15 @@
 // pcarrier.ca Software Inc: https://pcarrier.ca/
 // Submitted by Pierre Carrier <pc@rrier.ca>
 *.xmit.co
-bar0.net
-bar1.net
-bar2.net
-rdv.to
+xmit.dev
+madethis.site
 srv.us
 gh.srv.us
 gl.srv.us
 
-// .pl domains (grandfathered)
-art.pl
-gliwice.pl
-krakow.pl
-poznan.pl
-wroc.pl
-zakopane.pl
-
-// Pantheon Systems, Inc. : https://pantheon.io/
-// Submitted by Gary Dylina <gary@pantheon.io>
-pantheonsite.io
-gotpantheon.com
+// PE Ulyanov Kirill Sergeevich : https://airy.host
+// Submitted by Kirill Ulyanov <k.ulyanov@airy.host>
+lk3.ru
 
 // Peplink | Pepwave : http://peplink.com/
 // Submitted by Steve Leung <steveleung@peplink.com>
@@ -14639,10 +14700,6 @@
 // Submitted by Kenneth Van Alstyne <kvanalstyne@perspecta.com>
 perspecta.cloud
 
-// PE Ulyanov Kirill Sergeevich : https://airy.host
-// Submitted by Kirill Ulyanov <k.ulyanov@airy.host>
-lk3.ru
-
 // Planet-Work : https://www.planet-work.com/
 // Submitted by Frédéric VANNIÈRE <f.vanniere@planet-work.com>
 on-web.fr
@@ -14663,12 +14720,6 @@
 platter-app.dev
 platterp.us
 
-// Plesk : https://www.plesk.com/
-// Submitted by Anton Akhtyamov <program-managers@plesk.com>
-pdns.page
-plesk.page
-pleskns.com
-
 // Pley AB : https://www.pley.com/
 // Submitted by Henning Pohl <infra@pley.com>
 pley.games
@@ -14692,8 +14743,8 @@
 mock.pstmn.io
 httpbin.org
 
-//prequalifyme.today : https://prequalifyme.today
-//Submitted by DeepakTiwari deepak@ivylead.io
+// prequalifyme.today : https://prequalifyme.today
+// Submitted by DeepakTiwari deepak@ivylead.io
 prequalifyme.today
 
 // prgmr.com : https://prgmr.com/
@@ -14704,10 +14755,6 @@
 // Submitted by registry <lendl@nic.at>
 priv.at
 
-// privacytools.io : https://www.privacytools.io/
-// Submitted by Jonah Aragon <jonah@privacytools.io>
-prvcy.page
-
 // Protocol Labs : https://protocol.ai/
 // Submitted by Michael Burns <noc@protocol.ai>
 *.dweb.link
@@ -14730,40 +14777,6 @@
 pythonanywhere.com
 eu.pythonanywhere.com
 
-// QOTO, Org.
-// Submitted by Jeffrey Phillips Freeman <jeffrey.freeman@qoto.org>
-qoto.io
-
-// Qualifio : https://qualifio.com/
-// Submitted by Xavier De Cock <xdecock@gmail.com>
-qualifioapp.com
-
-// Quality Unit: https://qualityunit.com
-// Submitted by Vasyl Tsalko <vtsalko@qualityunit.com>
-ladesk.com
-
-// QuickBackend: https://www.quickbackend.com
-// Submitted by Dani Biro <dani@pymet.com>
-qbuser.com
-
-// Rad Web Hosting: https://radwebhosting.com
-// Submitted by Scott Claeys <s.claeys@radwebhosting.com>
-cloudsite.builders
-myradweb.net
-servername.us
-
-// Redgate Software: https://red-gate.com
-// Submitted by Andrew Farries <andrew.farries@red-gate.com>
-instances.spawn.cc
-
-// Redstar Consultants : https://www.redstarconsultants.com/
-// Submitted by Jons Slemmer <jons@redstarconsultants.com>
-instantcloud.cn
-
-// Russian Academy of Sciences
-// Submitted by Tech Support <support@rasnet.ru>
-ras.ru
-
 // QA2
 // Submitted by Daniel Dent (https://www.danieldent.com/)
 qa2.com
@@ -14774,11 +14787,30 @@
 *.sys.qcx.io
 
 // QNAP System Inc : https://www.qnap.com
-// Submitted by Nick Chang <nickchang@qnap.com>
-dev-myqnapcloud.com
+// Submitted by Nick Chang <cloudadmin@qnap.com>
+myqnapcloud.cn
 alpha-myqnapcloud.com
+dev-myqnapcloud.com
+mycloudnas.com
+mynascloud.com
 myqnapcloud.com
 
+// QOTO, Org.
+// Submitted by Jeffrey Phillips Freeman <jeffrey.freeman@qoto.org>
+qoto.io
+
+// Qualifio : https://qualifio.com/
+// Submitted by Xavier De Cock <xdecock@gmail.com>
+qualifioapp.com
+
+// Quality Unit : https://qualityunit.com
+// Submitted by Vasyl Tsalko <vtsalko@qualityunit.com>
+ladesk.com
+
+// QuickBackend: https://www.quickbackend.com
+// Submitted by Dani Biro <dani@pymet.com>
+qbuser.com
+
 // Quip : https://quip.com
 // Submitted by Patrick Linehan <plinehan@quip.com>
 *.quipelements.com
@@ -14793,28 +14825,49 @@
 rackmaze.com
 rackmaze.net
 
-// Rakuten Games, Inc : https://dev.viberplay.io
-// Submitted by Joshua Zhang <public-suffix@rgames.jp>
-g.vbrplsbx.io
+// Rad Web Hosting: https://radwebhosting.com
+// Submitted by Scott Claeys <s.claeys@radwebhosting.com>
+cloudsite.builders
+myradweb.net
+servername.us
+
+// Radix FZC : http://domains.in.net
+// Submitted by Gavin Brown <gavin.brown@centralnic.com>
+web.in
+in.net
+
+// Raidboxes GmbH : https://raidboxes.de
+// Submitted by Auke Tembrink <hostmaster@raidboxes.de>
+myrdbx.io
+site.rb-hosting.io
 
 // Rancher Labs, Inc : https://rancher.com
 // Submitted by Vincent Fiduccia <domains@rancher.com>
-*.on-k3s.io
 *.on-rancher.cloud
+*.on-k3s.io
 *.on-rio.io
 
+// RavPage : https://www.ravpage.co.il
+// Submitted by Roni Horowitz <roni@responder.co.il>
+ravpage.co.il
+
 // Read The Docs, Inc : https://www.readthedocs.org
 // Submitted by David Fischer <team@readthedocs.org>
+readthedocs-hosted.com
 readthedocs.io
 
 // Red Hat, Inc. OpenShift : https://openshift.redhat.com/
 // Submitted by Tim Kramer <tkramer@rhcloud.com>
 rhcloud.com
 
+// Redgate Software: https://red-gate.com
+// Submitted by Andrew Farries <andrew.farries@red-gate.com>
+instances.spawn.cc
+
 // Render : https://render.com
 // Submitted by Anurag Goel <dev@render.com>
-app.render.com
 onrender.com
+app.render.com
 
 // Repl.it : https://repl.it
 // Submitted by Lincoln Bergeson <psl@repl.it>
@@ -14862,11 +14915,6 @@
 // Submitted by Chris Kastorff <info@rethinkdb.com>
 hzc.io
 
-// Revitalised Limited : http://www.revitalised.co.uk
-// Submitted by Jack Price <jack@revitalised.co.uk>
-wellbeingzone.eu
-wellbeingzone.co.uk
-
 // Rico Developments Limited : https://adimo.co
 // Submitted by Colin Brown <hello@adimo.co>
 adimo.co.uk
@@ -14875,6 +14923,11 @@
 // Submitted by Micah Anderson <micah@riseup.net>
 itcouldbewor.se
 
+// Roar Domains LLC : https://roar.basketball/
+// Submitted by Gavin Brown <gavin.brown@centralnic.com>
+aus.basketball
+nz.basketball
+
 // Rochester Institute of Technology : http://www.rit.edu/
 // Submitted by Jennifer Herting <jchits@rit.edu>
 git-pages.rit.edu
@@ -14896,6 +14949,14 @@
 спб.рус
 я.рус
 
+// Russian Academy of Sciences
+// Submitted by Tech Support <support@rasnet.ru>
+ras.ru
+
+// Sakura Frp : https://www.natfrp.com
+// Submitted by Bobo Liu <support@natfrp.cloud>
+nyat.app
+
 // SAKURA Internet Inc. : https://www.sakura.ad.jp/
 // Submitted by Internet Service Department <rs-vendor-ml@sakura.ad.jp>
 180r.com
@@ -14947,11 +15008,19 @@
 sakura.tv
 
 // Salesforce.com, Inc. https://salesforce.com/
-// Submitted by Michael Biven <mbiven@salesforce.com> and Aaron Romeo <aaron.romeo@salesforce.com>
+// Submitted by Salesforce Public Suffix List Team <public-suffix-list@salesforce.com>
 *.builder.code.com
 *.dev-builder.code.com
 *.stg-builder.code.com
 *.001.test.code-builder-stg.platform.salesforce.com
+*.d.crm.dev
+*.w.crm.dev
+*.wa.crm.dev
+*.wb.crm.dev
+*.wc.crm.dev
+*.wd.crm.dev
+*.we.crm.dev
+*.wf.crm.dev
 
 // Sandstorm Development Group, Inc. : https://sandcats.io/
 // Submitted by Asheesh Laroia <asheesh@sandstorm.io>
@@ -14959,8 +15028,8 @@
 
 // SBE network solutions GmbH : https://www.sbe.de/
 // Submitted by Norman Meilick <nm@sbe.de>
-logoip.de
 logoip.com
+logoip.de
 
 // Scaleway : https://www.scaleway.com/
 // Submitted by Rémy Léone <rleone@scaleway.com>
@@ -15031,17 +15100,17 @@
 // Submitted by Yuriy Romadin <contact@sellfy.com>
 sellfy.store
 
-// Senseering GmbH : https://www.senseering.de
-// Submitted by Felix Mönckemeyer <f.moenckemeyer@senseering.de>
-senseering.net
-
 // Sendmsg: https://www.sendmsg.co.il
 // Submitted by Assaf Stern <domains@comstar.co.il>
 minisite.ms
 
-// Service Magnet : https://myservicemagnet.com
-// Submitted by Dave Sanders <dave@myservicemagnet.com>
-magnet.page
+// Senseering GmbH : https://www.senseering.de
+// Submitted by Felix Mönckemeyer <f.moenckemeyer@senseering.de>
+senseering.net
+
+// Servebolt AS: https://servebolt.com
+// Submitted by Daniel Kjeserud <cloudops@servebolt.com>
+servebolt.cloud
 
 // Service Online LLC : http://drs.ua/
 // Submitted by Serhii Bulakh <support@drs.ua>
@@ -15049,10 +15118,13 @@
 co.ua
 pp.ua
 
-// Shift Crypto AG : https://shiftcrypto.ch
-// Submitted by alex <alex@shiftcrypto.ch>
-shiftcrypto.dev
-shiftcrypto.io
+// Shanghai Accounting Society : https://www.sasf.org.cn
+// Submitted by Information Administration <info@sasf.org.cn>
+as.sh.cn
+
+// Sheezy.Art : https://sheezy.art
+// Submitted by Nyoom <admin@sheezy.art>
+sheezy.games
 
 // ShiftEdit : https://shiftedit.net/
 // Submitted by Adam Jimenez <adam@shiftcreate.com>
@@ -15096,6 +15168,10 @@
 alpha.bounty-full.com
 beta.bounty-full.com
 
+// Small Technology Foundation : https://small-tech.org
+// Submitted by Aral Balkan <aral@small-tech.org>
+small-web.org
+
 // Smallregistry by Promopixel SARL: https://www.smallregistry.net
 // Former AFNIC's SLDs
 // Submitted by Jérôme Lipowicz <support@promopixel.com>
@@ -15110,10 +15186,6 @@
 port.fr
 veterinaire.fr
 
-// Small Technology Foundation : https://small-tech.org
-// Submitted by Aral Balkan <aral@small-tech.org>
-small-web.org
-
 // Smoove.io : https://www.smoove.io/
 // Submitted by Dan Kozak <dan@smoove.io>
 vp4.me
@@ -15129,55 +15201,18 @@
 // Submitted by Ian Streeter <ian@snowplowanalytics.com>
 try-snowplow.com
 
-// SourceHut : https://sourcehut.org
-// Submitted by Drew DeVault <sir@cmpwn.com>
-srht.site
-
-// StackBlitz : https://stackblitz.com
-// Submitted by Dominic Elm <hello@stackblitz.com>
-w-corp-staticblitz.com
-w-credentialless-staticblitz.com
-w-staticblitz.com
-
-// Stackhero : https://www.stackhero.io
-// Submitted by Adrien Gillon <adrien+public-suffix-list@stackhero.io>
-stackhero-network.com
-
-// STACKIT : https://www.stackit.de/en/
-// Submitted by STACKIT-DNS Team (Simon Stier) <stackit-dns@mail.schwarz>
-runs.onstackit.cloud
-stackit.gg
-stackit.rocks
-stackit.run
-stackit.zone
-
-// Staclar : https://staclar.com
-// Submitted by Q Misell <q@staclar.com>
-musician.io
-// Submitted by Matthias Merkel <matthias.merkel@staclar.com>
-novecore.site
-
-// staticland : https://static.land
-// Submitted by Seth Vincent <sethvincent@gmail.com>
-static.land
-dev.static.land
-sites.static.land
-
-// Storebase : https://www.storebase.io
-// Submitted by Tony Schirmer <tony@storebase.io>
-storebase.store
-
-// Strategic System Consulting (eApps Hosting): https://www.eapps.com/
-// Submitted by Alex Oancea <aoancea@cloudscale365.com>
-vps-host.net
-atl.jelastic.vps-host.net
-njs.jelastic.vps-host.net
-ric.jelastic.vps-host.net
+// Software Consulting Michal Zalewski : https://www.mafelo.com
+// Submitted by Michal Zalewski <security@mafelo.com>
+mafelo.net
 
 // Sony Interactive Entertainment LLC : https://sie.com/
 // Submitted by David Coles <david.coles@sony.com>
 playstation-cloud.com
 
+// SourceHut : https://sourcehut.org
+// Submitted by Drew DeVault <sir@cmpwn.com>
+srht.site
+
 // SourceLair PC : https://www.sourcelair.com
 // Submitted by Antonis Kalipetis <akalipetis@sourcelair.com>
 apps.lair.io
@@ -15187,6 +15222,10 @@
 // Submitted by Reza Akhavan <spacekit.io@gmail.com>
 spacekit.io
 
+// SparrowHost : https://sparrowhost.in/
+// Submitted by Anant Pandey <info@sparrowhost.in>
+ind.mom
+
 // SpeedPartner GmbH: https://www.speedpartner.de/
 // Submitted by Stefan Neufeind <info@speedpartner.de>
 customer.speedpartner.de
@@ -15213,6 +15252,30 @@
 myspreadshop.se
 myspreadshop.co.uk
 
+// StackBlitz : https://stackblitz.com
+// Submitted by Dominic Elm <hello@stackblitz.com>
+w-corp-staticblitz.com
+w-credentialless-staticblitz.com
+w-staticblitz.com
+
+// Stackhero : https://www.stackhero.io
+// Submitted by Adrien Gillon <adrien+public-suffix-list@stackhero.io>
+stackhero-network.com
+
+// STACKIT : https://www.stackit.de/en/
+// Submitted by STACKIT-DNS Team (Simon Stier) <stackit-dns@mail.schwarz>
+runs.onstackit.cloud
+stackit.gg
+stackit.rocks
+stackit.run
+stackit.zone
+
+// Staclar : https://staclar.com
+// Submitted by Q Misell <q@staclar.com>
+// Submitted by Matthias Merkel <matthias.merkel@staclar.com>
+musician.io
+novecore.site
+
 // Standard Library : https://stdlib.com
 // Submitted by Jacob Lee <jacob@stdlib.com>
 api.stdlib.com
@@ -15230,6 +15293,10 @@
 tests.cx
 surveys.so
 
+// Storebase : https://www.storebase.io
+// Submitted by Tony Schirmer <tony@storebase.io>
+storebase.store
+
 // Storipress : https://storipress.com
 // Submitted by Benno Liu <benno@storipress.com>
 storipress.app
@@ -15238,21 +15305,33 @@
 // Submitted by Philip Hutchins <hostmaster@storj.io>
 storj.farm
 
+// Strapi : https://strapi.io/
+// Submitted by Florent Baldino <security@strapi.io>
+strapiapp.com
+media.strapiapp.com
+
+// Strategic System Consulting (eApps Hosting): https://www.eapps.com/
+// Submitted by Alex Oancea <aoancea@cloudscale365.com>
+vps-host.net
+atl.jelastic.vps-host.net
+njs.jelastic.vps-host.net
+ric.jelastic.vps-host.net
+
 // Streak : https://streak.com
 // Submitted by Blake Kadatz <eng@streak.com>
 streak-link.com
 streaklinks.com
 streakusercontent.com
 
-// Studenten Net Twente : http://www.snt.utwente.nl/
-// Submitted by Silke Hofstra <syscom@snt.utwente.nl>
-utwente.io
-
 // Student-Run Computing Facility : https://www.srcf.net/
 // Submitted by Edwin Balani <sysadmins@srcf.net>
 soc.srcf.net
 user.srcf.net
 
+// Studenten Net Twente : http://www.snt.utwente.nl/
+// Submitted by Silke Hofstra <syscom@snt.utwente.nl>
+utwente.io
+
 // Sub 6 Limited: http://www.sub6.com
 // Submitted by Dan Miller <dm@sub6.com>
 temp-dns.com
@@ -15262,12 +15341,11 @@
 supabase.co
 supabase.in
 supabase.net
-su.paba.se
 
 // Symfony, SAS : https://symfony.com/
 // Submitted by Fabien Potencier <fabien@symfony.com>
-*.s5y.io
 *.sensiosite.cloud
+*.s5y.io
 
 // Syncloud : https://syncloud.org
 // Submitted by Boris Rybalkin <syncloud@syncloud.it>
@@ -15289,14 +15367,14 @@
 familyds.net
 dsmynas.org
 familyds.org
-vpnplus.to
 direct.quickconnect.to
+vpnplus.to
 
 // Tabit Technologies Ltd. : https://tabit.cloud/
 // Submitted by Oren Agiv <oren@tabit.cloud>
-tabitorder.co.il
-mytabit.co.il
 mytabit.com
+mytabit.co.il
+tabitorder.co.il
 
 // TAIFUN Software AG : http://taifun-software.de
 // Submitted by Bjoern Henke <dev-server@taifun-software.de>
@@ -15308,13 +15386,18 @@
 ts.net
 *.c.ts.net
 
-// TASK geographical domains (www.task.gda.pl/uslugi/dns)
+// TASK geographical domains (https://www.task.gda.pl/uslugi/dns)
 gda.pl
 gdansk.pl
 gdynia.pl
 med.pl
 sopot.pl
 
+// tawk.to, Inc : https://www.tawk.to
+// Submitted by tawk.to developer team <dev-accounts@tawk.to>
+p.tawk.email
+p.tawkto.email
+
 // team.blue https://team.blue
 // Submitted by Cedric Dubois <cedric.dubois@team.blue>
 site.tb-hosting.com
@@ -15337,11 +15420,11 @@
 reservd.com
 thingdustdata.com
 cust.dev.thingdust.io
+reservd.dev.thingdust.io
 cust.disrec.thingdust.io
+reservd.disrec.thingdust.io
 cust.prod.thingdust.io
 cust.testing.thingdust.io
-reservd.dev.thingdust.io
-reservd.disrec.thingdust.io
 reservd.testing.thingdust.io
 
 // ticket i/O GmbH : https://ticket.io
@@ -15355,7 +15438,7 @@
 tlon.network
 
 // Tor Project, Inc. : https://torproject.org
-// Submitted by Antoine Beaupré <anarcat@torproject.org
+// Submitted by Antoine Beaupré <anarcat@torproject.org>
 torproject.net
 pages.torproject.net
 
@@ -15403,8 +15486,6 @@
 // TwoDNS : https://www.twodns.de/
 // Submitted by TwoDNS-Support <support@two-dns.de>
 dd-dns.de
-diskstation.eu
-diskstation.org
 dray-dns.de
 draydns.de
 dyn-vpn.de
@@ -15415,6 +15496,8 @@
 syno-ds.de
 synology-diskstation.de
 synology-ds.de
+diskstation.eu
+diskstation.org
 
 // Typedream : https://typedream.com
 // Submitted by Putri Karunia <putri@typedream.com>
@@ -15426,15 +15509,15 @@
 
 // Uberspace : https://uberspace.de
 // Submitted by Moritz Werner <mwerner@jonaspasche.com>
-uber.space
 *.uberspace.de
+uber.space
 
 // UDR Limited : http://www.udr.hk.com
 // Submitted by registry <hostmaster@udr.hk.com>
 hk.com
-hk.org
-ltd.hk
 inc.hk
+ltd.hk
+hk.org
 
 // UK Intis Telecom LTD : https://it.com
 // Submitted by ITComdomains <to@it.com>
@@ -15444,6 +15527,11 @@
 // Submitted by Simon Højberg <security@unison.cloud>
 unison-services.cloud
 
+// United Gameserver GmbH : https://united-gameserver.de
+// Submitted by Stefan Schwarz <sysadm@united-gameserver.de>
+virtual-user.de
+virtualuser.de
+
 // UNIVERSAL DOMAIN REGISTRY : https://www.udr.org.yt/
 // see also: whois -h whois.udr.org.yt help
 // Submitted by Atanunu Igbunuroghene <publicsuffixlist@udr.org.yt>
@@ -15453,10 +15541,14 @@
 sch.wf
 org.yt
 
-// United Gameserver GmbH : https://united-gameserver.de
-// Submitted by Stefan Schwarz <sysadm@united-gameserver.de>
-virtualuser.de
-virtual-user.de
+// University of Banja Luka : https://unibl.org
+// Domains for Republic of Srpska administrative entity.
+// Submitted by Marko Ivanovic <kormang@hotmail.rs>
+rs.ba
+
+// University of Bielsko-Biala regional domain: http://dns.bielsko.pl/
+// Submitted by Marcin <dns@ath.bielsko.pl>
+bielsko.pl
 
 // Upli : https://upli.io
 // Submitted by Lenny Bakkalian <lenny.bakkalian@gmail.com>
@@ -15467,13 +15559,18 @@
 urown.cloud
 dnsupdate.info
 
-// .US
-// Submitted by Ed Moore <Ed.Moore@lib.de.us>
-lib.de.us
+// US REGISTRY LLC : http://us.org
+// Submitted by Gavin Brown <gavin.brown@centralnic.com>
+us.org
 
-// VeryPositive SIA : http://very.lv
-// Submitted by Danko Aleksejevs <danko@very.lv>
-2038.io
+// V.UA Domain Administrator : https://domain.v.ua/
+// Submitted by Serhii Rostilo <sergey@rostilo.kiev.ua>
+v.ua
+
+// Val Town, Inc : https://val.town/
+// Submitted by Tom MacWright <security@val.town>
+express.val.run
+web.val.run
 
 // Vercel, Inc : https://vercel.com/
 // Submitted by Connor Davis <security@vercel.com>
@@ -15481,6 +15578,10 @@
 vercel.dev
 now.sh
 
+// VeryPositive SIA : http://very.lv
+// Submitted by Danko Aleksejevs <danko@very.lv>
+2038.io
+
 // Viprinet Europe GmbH : http://www.viprinet.com
 // Submitted by Simon Kissel <hostmaster@viprinet.com>
 router.management
@@ -15493,51 +15594,6 @@
 // Submitted by Nathan van Bakel <info@voorloper.com>
 voorloper.cloud
 
-// Voxel.sh DNS : https://voxel.sh/dns/
-// Submitted by Mia Rehlinger <dns@voxel.sh>
-neko.am
-nyaa.am
-be.ax
-cat.ax
-es.ax
-eu.ax
-gg.ax
-mc.ax
-us.ax
-xy.ax
-nl.ci
-xx.gl
-app.gp
-blog.gt
-de.gt
-to.gt
-be.gy
-cc.hn
-io.kg
-jp.kg
-tv.kg
-uk.kg
-us.kg
-de.ls
-at.md
-de.md
-jp.md
-to.md
-indie.porn
-vxl.sh
-ch.tc
-me.tc
-we.tc
-nyan.to
-at.vg
-blog.vu
-dev.vu
-me.vu
-
-// V.UA Domain Administrator : https://domain.v.ua/
-// Submitted by Serhii Rostilo <sergey@rostilo.kiev.ua>
-v.ua
-
 // Vultr Objects : https://www.vultr.com/products/object-storage/
 // Submitted by Niels Maumenee <storage@vultr.com>
 *.vultrobjects.com
@@ -15551,46 +15607,67 @@
 webflow.io
 webflowtest.io
 
-// WebHare bv: https://www.webhare.com/
+// WebHare bv : https://www.webhare.com/
 // Submitted by Arnold Hendriks <info@webhare.com>
 *.webhare.dev
 
-// WebHotelier Technologies Ltd: https://www.webhotelier.net/
+// WebHotelier Technologies Ltd : https://www.webhotelier.net/
 // Submitted by Apostolos Tsakpinis <apostolos.tsakpinis@gmail.com>
-reserve-online.net
-reserve-online.com
 bookonline.app
 hotelwithflight.com
+reserve-online.com
+reserve-online.net
 
-// WebWaddle Ltd: https://webwaddle.com/
+// WebPros International, LLC : https://webpros.com/
+// Submitted by Nicolas Rochelemagne <public.suffix@webpros.com>
+cprapid.com
+pleskns.com
+wp2.host
+pdns.page
+plesk.page
+wpsquared.site
+
+// WebWaddle Ltd : https://webwaddle.com/
 // Submitted by Merlin Glander <hostmaster@webwaddle.com>
 *.wadl.top
 
-// WeDeploy by Liferay, Inc. : https://www.wedeploy.com
-// Submitted by Henrique Vicente <security@wedeploy.com>
-wedeploy.io
-wedeploy.me
-wedeploy.sh
-
 // Western Digital Technologies, Inc : https://www.wdc.com
 // Submitted by Jung Jin <jungseok.jin@wdc.com>
 remotewd.com
 
+// Whatbox Inc. : https://whatbox.ca/
+// Submitted by Anthony Ryan <servers@whatbox.ca>
+box.ca
+
 // WIARD Enterprises : https://wiardweb.com
 // Submitted by Kidd Hustle <kiddhustle@wiardweb.com>
 pages.wiardweb.com
 
 // Wikimedia Labs : https://wikitech.wikimedia.org
 // Submitted by Arturo Borrero Gonzalez <aborrero@wikimedia.org>
-wmflabs.org
 toolforge.org
 wmcloud.org
+wmflabs.org
+
+// William Harrison : https://wdharrison.com
+// Submitted by William Harrison <publicsuffix@wdharrison.com>
+wdh.app
+preview.wdh.app
+t.hrsn.net
 
 // WISP : https://wisp.gg
 // Submitted by Stepan Fedotov <stepan@wisp.gg>
 panel.gg
 daemon.panel.gg
 
+// Wix.com, Inc. : https://www.wix.com
+// Submitted by Shahar Talmi / Alon Kochba <publicsuffixlist@wix.com>
+wixsite.com
+wixstudio.com
+editorx.io
+wixstudio.io
+wix.run
+
 // Wizard Zines : https://wizardzines.com
 // Submitted by Julia Evans <julia@wizardzines.com>
 messwithdns.com
@@ -15616,13 +15693,6 @@
 wpenginepowered.com
 js.wpenginepowered.com
 
-// Wix.com, Inc. : https://www.wix.com
-// Submitted by Shahar Talmi <shahar@wix.com>
-wixsite.com
-editorx.io
-wixstudio.io
-wix.run
-
 // XenonCloud GbR: https://xenoncloud.net
 // Submitted by Julian Uphoff <publicsuffixlist@xenoncloud.net>
 half.host
@@ -15639,7 +15709,7 @@
 demon.nl
 xs4all.space
 
-// Yandex.Cloud LLC: https://cloud.yandex.com
+// Yandex.Cloud LLC : https://cloud.yandex.com
 // Submitted by Alexander Lodin <security+psl@yandex-team.ru>
 yandexcloud.net
 storage.yandexcloud.net
@@ -15678,6 +15748,10 @@
 // Submitted by Julian Alker <security@zap-hosting.com>
 zap.cloud
 
+// Zeabur : https://zeabur.com/
+// Submitted by Zeabur Team <contact@zeabur.com>
+zeabur.app
+
 // Zine EOOD : https://zine.bg/
 // Submitted by Martin Angelov <martin@zine.bg>
 bss.design
@@ -15688,4 +15762,4 @@
 virtualserver.io
 enterprisecloud.nu
 
-// ===END PRIVATE DOMAINS===
+// ===END PRIVATE DOMAINS===
\ No newline at end of file
diff --git a/net/base/registry_controlled_domains/effective_tld_names.gperf b/net/base/registry_controlled_domains/effective_tld_names.gperf
index 42b9ac7..6c34289 100644
--- a/net/base/registry_controlled_domains/effective_tld_names.gperf
+++ b/net/base/registry_controlled_domains/effective_tld_names.gperf
@@ -85,6 +85,7 @@
 aa.no, 0
 aaa, 0
 aaa.pro, 0
+aaa.vodka, 4
 aarborte.no, 0
 aarp, 0
 ab.ca, 0
@@ -135,6 +136,7 @@
 ac.ni, 0
 ac.nz, 0
 ac.pa, 0
+ac.pk, 0
 ac.pr, 0
 ac.rs, 0
 ac.ru, 4
@@ -199,6 +201,7 @@
 aeroport.fr, 4
 aetna, 0
 af, 0
+af-south-1.airflow.amazonaws.com, 6
 af-south-1.elasticbeanstalk.com, 4
 affinitylottery.org.uk, 4
 afjord.no, 0
@@ -336,10 +339,8 @@
 amica, 0
 amli.no, 0
 amot.no, 0
-amplifyapp.com, 6
-amscompute.com, 4
+amplifyapp.com, 4
 amsterdam, 0
-amusement.aero, 0
 an.it, 0
 analytics, 0
 analytics-gateway.ap-northeast-1.amazonaws.com, 4
@@ -386,19 +387,24 @@
 aosta.it, 0
 aostavalley.it, 0
 aoste.it, 0
+ap-east-1.airflow.amazonaws.com, 6
 ap-east-1.elasticbeanstalk.com, 4
 ap-northeast-1.airflow.amazonaws.com, 6
 ap-northeast-1.elasticbeanstalk.com, 4
 ap-northeast-2.airflow.amazonaws.com, 6
 ap-northeast-2.elasticbeanstalk.com, 4
+ap-northeast-3.airflow.amazonaws.com, 6
 ap-northeast-3.elasticbeanstalk.com, 4
 ap-south-1.airflow.amazonaws.com, 6
 ap-south-1.elasticbeanstalk.com, 4
+ap-south-2.airflow.amazonaws.com, 6
 ap-southeast-1.airflow.amazonaws.com, 6
 ap-southeast-1.elasticbeanstalk.com, 4
 ap-southeast-2.airflow.amazonaws.com, 6
 ap-southeast-2.elasticbeanstalk.com, 4
+ap-southeast-3.airflow.amazonaws.com, 6
 ap-southeast-3.elasticbeanstalk.com, 4
+ap-southeast-4.airflow.amazonaws.com, 6
 ap.gov.br, 0
 ap.gov.pl, 0
 ap.it, 0
@@ -410,10 +416,9 @@
 api.stdlib.com, 4
 apigee.io, 4
 app, 0
+app-ionos.space, 4
 app.banzaicloud.io, 4
 app.br, 0
-app.gp, 4
-app.lmpm.com, 4
 app.os.fedoraproject.org, 4
 app.os.stg.fedoraproject.org, 4
 app.render.com, 4
@@ -421,6 +426,8 @@
 appengine.flow.ch, 4
 apple, 0
 applinzi.com, 4
+apps-1and1.com, 4
+apps-1and1.net, 4
 apps.fbsbx.com, 4
 apps.lair.io, 4
 appspacehosted.com, 4
@@ -432,7 +439,6 @@
 aquarelle, 0
 aquila.it, 0
 ar, 0
-ar.com, 4
 ar.it, 0
 ar.us, 0
 arab, 0
@@ -473,6 +479,7 @@
 arts.ve, 0
 arvo.network, 4
 as, 0
+as.sh.cn, 4
 as.us, 0
 asago.hyogo.jp, 0
 asahi.chiba.jp, 0
@@ -529,8 +536,6 @@
 at.emf.camp, 4
 at.eu.org, 4
 at.it, 0
-at.md, 4
-at.vg, 4
 atami.shizuoka.jp, 0
 ath.cx, 4
 athleta, 0
@@ -564,21 +569,28 @@
 auth-fips.us-west-1.amazoncognito.com, 4
 auth-fips.us-west-2.amazoncognito.com, 4
 auth.af-south-1.amazoncognito.com, 4
+auth.ap-east-1.amazoncognito.com, 4
 auth.ap-northeast-1.amazoncognito.com, 4
 auth.ap-northeast-2.amazoncognito.com, 4
 auth.ap-northeast-3.amazoncognito.com, 4
 auth.ap-south-1.amazoncognito.com, 4
+auth.ap-south-2.amazoncognito.com, 4
 auth.ap-southeast-1.amazoncognito.com, 4
 auth.ap-southeast-2.amazoncognito.com, 4
 auth.ap-southeast-3.amazoncognito.com, 4
+auth.ap-southeast-4.amazoncognito.com, 4
 auth.ca-central-1.amazoncognito.com, 4
+auth.ca-west-1.amazoncognito.com, 4
 auth.eu-central-1.amazoncognito.com, 4
+auth.eu-central-2.amazoncognito.com, 4
 auth.eu-north-1.amazoncognito.com, 4
 auth.eu-south-1.amazoncognito.com, 4
+auth.eu-south-2.amazoncognito.com, 4
 auth.eu-west-1.amazoncognito.com, 4
 auth.eu-west-2.amazoncognito.com, 4
 auth.eu-west-3.amazoncognito.com, 4
 auth.il-central-1.amazoncognito.com, 4
+auth.me-central-1.amazoncognito.com, 4
 auth.me-south-1.amazoncognito.com, 4
 auth.sa-east-1.amazoncognito.com, 4
 auth.us-east-1.amazoncognito.com, 4
@@ -591,7 +603,6 @@
 author.aero, 0
 auto, 0
 auto.pl, 0
-autocode.dev, 4
 autos, 0
 av.it, 0
 av.tr, 0
@@ -606,8 +617,8 @@
 awdev.ca, 6
 aws, 0
 awsapprunner.com, 6
+awsapps.com, 4
 awsglobalaccelerator.com, 4
-awsmppl.com, 4
 ax, 0
 axa, 0
 aya.miyazaki.jp, 0
@@ -643,7 +654,6 @@
 bacgiang.vn, 0
 backan.vn, 0
 backdrop.jp, 4
-backplaneapp.io, 4
 backyards.banzaicloud.io, 6
 baclieu.vn, 0
 bacninh.vn, 0
@@ -673,9 +683,6 @@
 banzai.cloud, 6
 bar, 0
 bar.pro, 0
-bar0.net, 4
-bar1.net, 4
-bar2.net, 4
 barcelona, 0
 barclaycard, 0
 barclays, 0
@@ -693,7 +700,9 @@
 barsy.club, 4
 barsy.co.uk, 4
 barsy.de, 4
+barsy.dev, 4
 barsy.eu, 4
+barsy.gr, 4
 barsy.in, 4
 barsy.info, 4
 barsy.io, 4
@@ -706,13 +715,17 @@
 barsy.pro, 4
 barsy.pub, 4
 barsy.ro, 4
+barsy.rs, 4
 barsy.shop, 4
 barsy.site, 4
+barsy.store, 4
 barsy.support, 4
 barsy.uk, 4
 barsycenter.com, 4
 barsyonline.co.uk, 4
 barsyonline.com, 4
+barsyonline.menu, 4
+barsyonline.shop, 4
 barueri.br, 0
 barum.no, 0
 bas.it, 0
@@ -740,9 +753,7 @@
 bd, 2
 bd.se, 0
 be, 0
-be.ax, 4
 be.eu.org, 4
-be.gy, 4
 beagleboard.io, 4
 bearalvahki.no, 0
 beardu.no, 0
@@ -794,6 +805,7 @@
 biei.hokkaido.jp, 0
 bielawa.pl, 0
 biella.it, 0
+bielsko.pl, 4
 bieszczady.pl, 0
 bievat.no, 0
 bifuka.hokkaido.jp, 0
@@ -809,11 +821,9 @@
 binhthuan.vn, 0
 bio, 0
 bio.br, 0
-bip.sh, 4
 bir.ru, 4
 biratori.hokkaido.jp, 0
 birkenes.no, 0
-bitbridge.net, 4
 bitbucket.io, 4
 bitter.jp, 4
 biz, 0
@@ -832,6 +842,7 @@
 biz.mv, 0
 biz.mw, 0
 biz.my, 0
+biz.ng, 4
 biz.ni, 0
 biz.nr, 0
 biz.pk, 0
@@ -860,13 +871,10 @@
 blog, 0
 blog.bo, 0
 blog.br, 0
-blog.gt, 4
-blog.vu, 4
 blogdns.com, 4
 blogdns.net, 4
 blogdns.org, 4
 blogsite.org, 4
-blogsite.xyz, 4
 blogspot.ae, 4
 blogspot.al, 4
 blogspot.am, 4
@@ -993,6 +1001,7 @@
 boutique, 0
 boutir.com, 4
 box, 0
+box.ca, 4
 boxfuse.io, 4
 boy.jp, 4
 boyfriend.jp, 4
@@ -1064,16 +1073,15 @@
 bz, 0
 bz.it, 0
 bzh, 0
-bzz.dapps.earth, 6
 c.bg, 0
 c.cdn77.org, 4
-c.la, 4
 c.se, 0
 c.ts.net, 6
 c66.me, 4
 ca, 0
 ca-central-1.airflow.amazonaws.com, 6
 ca-central-1.elasticbeanstalk.com, 4
+ca-west-1.airflow.amazonaws.com, 6
 ca.eu.org, 4
 ca.in, 0
 ca.it, 0
@@ -1142,7 +1150,6 @@
 casino, 0
 casino.hu, 0
 cat, 0
-cat.ax, 4
 catania.it, 0
 catanzaro.it, 0
 catering, 0
@@ -1171,7 +1178,6 @@
 cc.ga.us, 0
 cc.gu.us, 0
 cc.hi.us, 0
-cc.hn, 4
 cc.ia.us, 0
 cc.id.us, 0
 cc.il.us, 0
@@ -1219,6 +1225,10 @@
 cd, 0
 cd.eu.org, 4
 cdn-edges.net, 4
+cdn.cloudflare.net, 4
+cdn.cloudflareanycast.net, 4
+cdn.cloudflarecn.net, 4
+cdn.cloudflareglobal.net, 4
 cdn.prod.atlassian-dev.net, 4
 cdn77-ssl.net, 4
 cdn77-storage.com, 4
@@ -1238,11 +1248,11 @@
 cf-ipfs.com, 4
 cfa, 0
 cfd, 0
+cfolks.pl, 4
 cg, 0
 ch, 0
 ch.eu.org, 4
 ch.it, 0
-ch.tc, 4
 ch.trendhosting.cloud, 4
 chambagri.fr, 4
 championship.aero, 0
@@ -1341,7 +1351,9 @@
 cleaning, 0
 clerk.app, 4
 clerkstage.app, 4
+cleverapps.cc, 4
 cleverapps.io, 4
+cleverapps.tech, 4
 click, 0
 clickrising.net, 4
 client.scrypted.io, 4
@@ -1349,24 +1361,20 @@
 clinique, 0
 clothing, 0
 cloud, 0
-cloud-fr1.unispace.io, 4
 cloud.fedoraproject.org, 4
 cloud.goog, 4
 cloud.interhostsolutions.be, 4
-cloud.jelastic.open.tim.it, 4
 cloud.metacentrum.cz, 6
 cloud.nospamproxy.com, 4
 cloud66.ws, 4
 cloud66.zone, 4
 cloudaccess.host, 4
 cloudaccess.net, 4
-cloudapp.azure.com, 4
 cloudapp.net, 4
 cloudapps.digital, 4
-cloudcontrolapp.com, 4
-cloudcontrolled.com, 4
 cloudera.site, 6
 cloudflare-ipfs.com, 4
+cloudflare.net, 4
 cloudfront.net, 4
 cloudfunctions.net, 4
 cloudjiffy.net, 4
@@ -1404,7 +1412,6 @@
 cn.in, 0
 cn.it, 0
 cn.ua, 0
-cn.vu, 4
 cng.br, 0
 cnpy.gdn, 4
 cns.joyent.com, 6
@@ -1417,6 +1424,7 @@
 co.at, 0
 co.bb, 0
 co.bi, 0
+co.biz.ng, 4
 co.bj, 0
 co.bn, 4
 co.business, 4
@@ -1702,13 +1710,13 @@
 coz.br, 0
 cpa, 0
 cpa.pro, 0
-cprapid.com, 6
+cprapid.com, 4
 cpserver.com, 4
 cq.cn, 0
 cr, 0
 cr.it, 0
 cr.ua, 0
-crafting.xyz, 4
+craft.me, 4
 cranky.jp, 4
 crap.jp, 4
 crd.co, 4
@@ -1734,13 +1742,14 @@
 csx.cc, 4
 ct.it, 0
 ct.us, 0
+ctfcloud.net, 4
 cu, 0
 cuiaba.br, 0
 cuisinella, 0
 cuneo.it, 0
-cupcake.is, 4
 curitiba.br, 0
 curv.dev, 4
+cust.cloudscale.ch, 4
 cust.dev.thingdust.io, 4
 cust.disrec.thingdust.io, 4
 cust.prod.thingdust.io, 4
@@ -1758,11 +1767,6 @@
 cx.ua, 4
 cy, 0
 cy.eu.org, 4
-cya.gg, 4
-cyclic-app.com, 4
-cyclic.app, 4
-cyclic.cloud, 4
-cyclic.co.in, 4
 cymru, 0
 cyon.link, 4
 cyon.site, 4
@@ -1773,6 +1777,7 @@
 czeladz.pl, 0
 czest.pl, 0
 d.bg, 0
+d.crm.dev, 6
 d.gv.vc, 4
 d.se, 0
 daa.jp, 4
@@ -1794,7 +1799,6 @@
 danang.vn, 0
 dance, 0
 daplie.me, 4
-dapps.earth, 6
 darklang.io, 4
 data, 0
 database.run, 6
@@ -1821,7 +1825,6 @@
 ddnsfree.com, 4
 ddnsgeek.com, 4
 ddnsking.com, 4
-ddnslive.com, 4
 ddnss.de, 4
 ddnss.org, 4
 dds, 0
@@ -1829,9 +1832,6 @@
 de.com, 4
 de.cool, 4
 de.eu.org, 4
-de.gt, 4
-de.ls, 4
-de.md, 4
 de.trendhosting.cloud, 4
 de.us, 0
 deal, 0
@@ -1879,14 +1879,12 @@
 dev-myqnapcloud.com, 4
 dev.adobeaemcloud.com, 6
 dev.br, 0
-dev.static.land, 4
-dev.vu, 4
-devcdnaccesso.com, 6
 developer.app, 6
 development.run, 4
 devices.resinstaging.io, 4
 df.gov.br, 0
 df.leg.br, 4
+dfirma.pl, 4
 dgca.aero, 0
 dh.bytemark.co.uk, 4
 dhl, 0
@@ -1898,7 +1896,7 @@
 digick.jp, 4
 digital, 0
 digitaloceanspaces.com, 6
-diher.solutions, 6
+diher.solutions, 4
 direct, 0
 direct.quickconnect.cn, 4
 direct.quickconnect.to, 4
@@ -1922,6 +1920,8 @@
 dj, 0
 dk, 0
 dk.eu.org, 4
+dkonto.pl, 4
+dl.biz.ng, 4
 dlugoleka.pl, 0
 dm, 0
 dn.ua, 0
@@ -1996,6 +1996,7 @@
 dunlop, 0
 dupont, 0
 durban, 0
+durumis.com, 4
 dvag, 0
 dvr, 0
 dvrcam.info, 4
@@ -2193,7 +2194,6 @@
 edu.sa, 0
 edu.sb, 0
 edu.sc, 0
-edu.scot, 4
 edu.sd, 0
 edu.sg, 0
 edu.sl, 0
@@ -2264,18 +2264,24 @@
 emrappui-prod.ap-northeast-2.amazonaws.com, 4
 emrappui-prod.ap-northeast-3.amazonaws.com, 4
 emrappui-prod.ap-south-1.amazonaws.com, 4
+emrappui-prod.ap-south-2.amazonaws.com, 4
 emrappui-prod.ap-southeast-1.amazonaws.com, 4
 emrappui-prod.ap-southeast-2.amazonaws.com, 4
 emrappui-prod.ap-southeast-3.amazonaws.com, 4
+emrappui-prod.ap-southeast-4.amazonaws.com, 4
 emrappui-prod.ca-central-1.amazonaws.com, 4
+emrappui-prod.ca-west-1.amazonaws.com, 4
 emrappui-prod.cn-north-1.amazonaws.com.cn, 4
 emrappui-prod.cn-northwest-1.amazonaws.com.cn, 4
 emrappui-prod.eu-central-1.amazonaws.com, 4
+emrappui-prod.eu-central-2.amazonaws.com, 4
 emrappui-prod.eu-north-1.amazonaws.com, 4
 emrappui-prod.eu-south-1.amazonaws.com, 4
+emrappui-prod.eu-south-2.amazonaws.com, 4
 emrappui-prod.eu-west-1.amazonaws.com, 4
 emrappui-prod.eu-west-2.amazonaws.com, 4
 emrappui-prod.eu-west-3.amazonaws.com, 4
+emrappui-prod.il-central-1.amazonaws.com, 4
 emrappui-prod.me-central-1.amazonaws.com, 4
 emrappui-prod.me-south-1.amazonaws.com, 4
 emrappui-prod.sa-east-1.amazonaws.com, 4
@@ -2291,18 +2297,24 @@
 emrnotebooks-prod.ap-northeast-2.amazonaws.com, 4
 emrnotebooks-prod.ap-northeast-3.amazonaws.com, 4
 emrnotebooks-prod.ap-south-1.amazonaws.com, 4
+emrnotebooks-prod.ap-south-2.amazonaws.com, 4
 emrnotebooks-prod.ap-southeast-1.amazonaws.com, 4
 emrnotebooks-prod.ap-southeast-2.amazonaws.com, 4
 emrnotebooks-prod.ap-southeast-3.amazonaws.com, 4
+emrnotebooks-prod.ap-southeast-4.amazonaws.com, 4
 emrnotebooks-prod.ca-central-1.amazonaws.com, 4
+emrnotebooks-prod.ca-west-1.amazonaws.com, 4
 emrnotebooks-prod.cn-north-1.amazonaws.com.cn, 4
 emrnotebooks-prod.cn-northwest-1.amazonaws.com.cn, 4
 emrnotebooks-prod.eu-central-1.amazonaws.com, 4
+emrnotebooks-prod.eu-central-2.amazonaws.com, 4
 emrnotebooks-prod.eu-north-1.amazonaws.com, 4
 emrnotebooks-prod.eu-south-1.amazonaws.com, 4
+emrnotebooks-prod.eu-south-2.amazonaws.com, 4
 emrnotebooks-prod.eu-west-1.amazonaws.com, 4
 emrnotebooks-prod.eu-west-2.amazonaws.com, 4
 emrnotebooks-prod.eu-west-3.amazonaws.com, 4
+emrnotebooks-prod.il-central-1.amazonaws.com, 4
 emrnotebooks-prod.me-central-1.amazonaws.com, 4
 emrnotebooks-prod.me-south-1.amazonaws.com, 4
 emrnotebooks-prod.sa-east-1.amazonaws.com, 4
@@ -2318,18 +2330,24 @@
 emrstudio-prod.ap-northeast-2.amazonaws.com, 4
 emrstudio-prod.ap-northeast-3.amazonaws.com, 4
 emrstudio-prod.ap-south-1.amazonaws.com, 4
+emrstudio-prod.ap-south-2.amazonaws.com, 4
 emrstudio-prod.ap-southeast-1.amazonaws.com, 4
 emrstudio-prod.ap-southeast-2.amazonaws.com, 4
 emrstudio-prod.ap-southeast-3.amazonaws.com, 4
+emrstudio-prod.ap-southeast-4.amazonaws.com, 4
 emrstudio-prod.ca-central-1.amazonaws.com, 4
+emrstudio-prod.ca-west-1.amazonaws.com, 4
 emrstudio-prod.cn-north-1.amazonaws.com.cn, 4
 emrstudio-prod.cn-northwest-1.amazonaws.com.cn, 4
 emrstudio-prod.eu-central-1.amazonaws.com, 4
+emrstudio-prod.eu-central-2.amazonaws.com, 4
 emrstudio-prod.eu-north-1.amazonaws.com, 4
 emrstudio-prod.eu-south-1.amazonaws.com, 4
+emrstudio-prod.eu-south-2.amazonaws.com, 4
 emrstudio-prod.eu-west-1.amazonaws.com, 4
 emrstudio-prod.eu-west-2.amazonaws.com, 4
 emrstudio-prod.eu-west-3.amazonaws.com, 4
+emrstudio-prod.il-central-1.amazonaws.com, 4
 emrstudio-prod.me-central-1.amazonaws.com, 4
 emrstudio-prod.me-south-1.amazonaws.com, 4
 emrstudio-prod.sa-east-1.amazonaws.com, 4
@@ -2377,7 +2395,6 @@
 erotika.hu, 0
 es, 0
 es-1.axarnet.cloud, 4
-es.ax, 4
 es.eu.org, 4
 es.gov.br, 0
 es.kr, 0
@@ -2405,16 +2422,18 @@
 eu-4.evennode.com, 4
 eu-central-1.airflow.amazonaws.com, 6
 eu-central-1.elasticbeanstalk.com, 4
+eu-central-2.airflow.amazonaws.com, 6
 eu-north-1.airflow.amazonaws.com, 6
 eu-north-1.elasticbeanstalk.com, 4
+eu-south-1.airflow.amazonaws.com, 6
 eu-south-1.elasticbeanstalk.com, 4
+eu-south-2.airflow.amazonaws.com, 6
 eu-west-1.airflow.amazonaws.com, 6
 eu-west-1.elasticbeanstalk.com, 4
 eu-west-2.airflow.amazonaws.com, 6
 eu-west-2.elasticbeanstalk.com, 4
 eu-west-3.airflow.amazonaws.com, 6
 eu-west-3.elasticbeanstalk.com, 4
-eu.ax, 4
 eu.com, 4
 eu.encoway.cloud, 4
 eu.int, 0
@@ -2470,11 +2489,14 @@
 execute-api.us-west-1.amazonaws.com, 4
 execute-api.us-west-2.amazonaws.com, 4
 exnet.su, 4
+experiments.sagemaker.aws, 6
 expert, 0
 experts-comptables.fr, 4
+expo.app, 4
 exposed, 0
 express, 0
 express.aero, 0
+express.val.run, 4
 extraspace, 0
 ezproxy.kuleuven.be, 4
 f.bg, 0
@@ -2503,7 +2525,6 @@
 fastly-edge.com, 4
 fastly-terrarium.com, 4
 fastlylb.net, 4
-faststacks.net, 4
 fastvps-server.com, 4
 fastvps.host, 4
 fastvps.site, 4
@@ -2544,11 +2565,6 @@
 fidelity, 0
 fido, 0
 fie.ee, 0
-filegear-au.me, 4
-filegear-de.me, 4
-filegear-gb.me, 4
-filegear-ie.me, 4
-filegear-jp.me, 4
 filegear-sg.me, 4
 filegear.me, 4
 film, 0
@@ -2569,7 +2585,6 @@
 firewall-gateway.de, 4
 firewall-gateway.net, 4
 firewalledreplit.co, 4
-fireweb.app, 4
 firm.co, 0
 firm.dk, 4
 firm.ht, 0
@@ -2592,7 +2607,6 @@
 fl.us, 0
 fla.no, 0
 flakstad.no, 0
-flap.id, 4
 flatanger.no, 0
 fldrv.com, 4
 flekkefjord.no, 0
@@ -2615,7 +2629,6 @@
 flutterflow.app, 4
 fly, 0
 fly.dev, 4
-flynnhosting.net, 4
 fm, 0
 fm.br, 0
 fm.it, 0
@@ -2687,6 +2700,7 @@
 freesite.host, 4
 freetls.fastly.net, 4
 frei.no, 0
+freight.aero, 0
 frenchkiss.jp, 4
 fresenius, 0
 friuli-v-giulia.it, 0
@@ -2836,7 +2850,6 @@
 fyresdal.no, 0
 g.bg, 0
 g.se, 0
-g.vbrplsbx.io, 4
 g12.br, 0
 ga, 0
 ga.us, 0
@@ -2899,12 +2912,11 @@
 gets-it.net, 4
 gf, 0
 gg, 0
-gg.ax, 4
 ggee, 0
 ggf.br, 0
+ggff.net, 4
 gh, 0
 gh.srv.us, 4
-ghost.io, 4
 gi, 0
 gialai.vn, 0
 giehtavuoatna.no, 0
@@ -2935,6 +2947,7 @@
 gjerstad.no, 0
 gjesdal.no, 0
 gjovik.no, 0
+gkp.pk, 0
 gl, 0
 gl.srv.us, 4
 glass, 0
@@ -2960,6 +2973,7 @@
 gmx, 0
 gn, 0
 gniezno.pl, 0
+go.biz.ng, 4
 go.ci, 0
 go.cr, 0
 go.dyndns.org, 4
@@ -2978,6 +2992,7 @@
 gob.ar, 0
 gob.bo, 0
 gob.cl, 0
+gob.cu, 0
 gob.do, 0
 gob.ec, 0
 gob.es, 0
@@ -2993,6 +3008,7 @@
 gobo.wakayama.jp, 0
 godaddy, 0
 godo.gifu.jp, 0
+gog.pk, 0
 goiania.br, 0
 goip.de, 4
 gojome.akita.jp, 0
@@ -3181,7 +3197,6 @@
 granvin.no, 0
 graphic.design, 4
 graphics, 0
-graphox.us, 4
 gratangen.no, 0
 gratis, 0
 grayjayleagues.com, 4
@@ -3332,6 +3347,12 @@
 hasura-app.io, 4
 hasura.app, 4
 hasvik.no, 0
+hateblo.jp, 4
+hatenablog.com, 4
+hatenablog.jp, 4
+hatenadiary.com, 4
+hatenadiary.jp, 4
+hatenadiary.org, 4
 hatinh.vn, 0
 hatogaya.saitama.jp, 0
 hatoyama.saitama.jp, 0
@@ -3356,6 +3377,7 @@
 healthcare, 0
 heavy.jp, 4
 heguri.nara.jp, 0
+heiyu.space, 4
 hekinan.aichi.jp, 0
 helioho.st, 4
 heliohost.us, 4
@@ -3528,6 +3550,7 @@
 hosp.uk, 4
 hospital, 0
 host, 0
+hosted.app, 6
 hostedpi.com, 4
 hosting, 0
 hosting-cluster.nl, 4
@@ -3555,7 +3578,6 @@
 ht, 0
 httpbin.org, 4
 hu, 0
-hu.com, 4
 hu.eu.org, 4
 hu.net, 4
 hughes, 0
@@ -3568,6 +3590,7 @@
 hyatt, 0
 hyllestad.no, 0
 hyogo.jp, 0
+hypernode.io, 4
 hyuga.miyazaki.jp, 0
 hyundai, 0
 hzc.io, 4
@@ -3649,6 +3672,7 @@
 ikoma.nara.jp, 0
 ikusaka.nagano.jp, 0
 il, 0
+il-central-1.airflow.amazonaws.com, 6
 il-central-1.elasticbeanstalk.com, 4
 il.eu.org, 4
 il.us, 0
@@ -3667,8 +3691,6 @@
 immo, 0
 immobilien, 0
 imperia.it, 0
-impertrix.com, 4
-impertrixcdn.com, 4
 in, 0
 in-addr.arpa, 0
 in-berlin.de, 4
@@ -3710,6 +3732,7 @@
 ind.gt, 0
 ind.in, 0
 ind.kw, 0
+ind.mom, 4
 ind.tn, 0
 independent-commission.uk, 4
 independent-inquest.uk, 4
@@ -3717,7 +3740,6 @@
 independent-panel.uk, 4
 independent-review.uk, 4
 inderoy.no, 0
-indie.porn, 4
 indigena.bo, 0
 industria.bo, 0
 industries, 0
@@ -3752,7 +3774,6 @@
 info.nf, 0
 info.ni, 0
 info.nr, 0
-info.pk, 0
 info.pl, 0
 info.pr, 0
 info.ro, 0
@@ -3771,7 +3792,6 @@
 ino.kochi.jp, 0
 instance.datadetect.com, 4
 instances.spawn.cc, 4
-instantcloud.cn, 4
 institute, 0
 insurance, 0
 insurance.aero, 0
@@ -3807,7 +3827,6 @@
 inzai.chiba.jp, 0
 io, 0
 io.in, 0
-io.kg, 4
 io.vn, 0
 iobb.net, 4
 iopsys.se, 4
@@ -3841,9 +3860,11 @@
 is-a-designer.com, 4
 is-a-doctor.com, 4
 is-a-financialadvisor.com, 4
+is-a-fullstack.dev, 4
 is-a-geek.com, 4
 is-a-geek.net, 4
 is-a-geek.org, 4
+is-a-good.dev, 4
 is-a-green.com, 4
 is-a-guru.com, 4
 is-a-hard-worker.com, 4
@@ -4011,10 +4032,8 @@
 jeez.jp, 4
 jeju.kr, 0
 jelastic.dogado.eu, 4
-jelastic.regruhosting.ru, 4
 jelastic.saveincloud.net, 4
 jelastic.team, 4
-jelastic.tsukaeru.net, 4
 jele.cloud, 4
 jele.club, 4
 jele.host, 4
@@ -4057,13 +4076,12 @@
 jotelulu.cloud, 4
 journal.aero, 0
 journalist.aero, 0
+jouwweb.site, 4
 joy, 0
 joyo.kyoto.jp, 0
 jozi.biz, 4
 jp, 0
 jp.eu.org, 4
-jp.kg, 4
-jp.md, 4
 jp.net, 4
 jp.ngrok.io, 4
 jpmorgan, 0
@@ -4336,7 +4354,6 @@
 kikonai.hokkaido.jp, 0
 kikuchi.kumamoto.jp, 0
 kikugawa.shizuoka.jp, 0
-kilatiron.com, 4
 kill.jp, 4
 kilo.jp, 4
 kim, 0
@@ -4474,7 +4491,6 @@
 kpn, 0
 kppsp.gov.pl, 0
 kr, 0
-kr.com, 4
 kr.eu.org, 4
 kr.it, 0
 kr.ua, 0
@@ -4581,6 +4597,18 @@
 la.us, 0
 laakesvuemie.no, 0
 lab.ms, 4
+labeling.ap-northeast-1.sagemaker.aws, 4
+labeling.ap-northeast-2.sagemaker.aws, 4
+labeling.ap-south-1.sagemaker.aws, 4
+labeling.ap-southeast-1.sagemaker.aws, 4
+labeling.ap-southeast-2.sagemaker.aws, 4
+labeling.ca-central-1.sagemaker.aws, 4
+labeling.eu-central-1.sagemaker.aws, 4
+labeling.eu-west-1.sagemaker.aws, 4
+labeling.eu-west-2.sagemaker.aws, 4
+labeling.us-east-1.sagemaker.aws, 4
+labeling.us-east-2.sagemaker.aws, 4
+labeling.us-west-2.sagemaker.aws, 4
 lacaixa, 0
 ladesk.com, 4
 lahppi.no, 0
@@ -4656,6 +4684,7 @@
 levanger.no, 0
 lexus, 0
 lezajsk.pl, 0
+lg.biz.ng, 4
 lg.jp, 0
 lg.ua, 0
 lgbt, 0
@@ -4716,6 +4745,7 @@
 lib.wa.us, 0
 lib.wi.us, 0
 lib.wy.us, 0
+libp2p.direct, 4
 lidl, 0
 lier.no, 0
 lierne.no, 0
@@ -4750,6 +4780,7 @@
 littlestar.jp, 4
 live, 0
 live-on.net, 4
+live-website.com, 4
 living, 0
 livorno.it, 0
 lk, 0
@@ -4765,7 +4796,6 @@
 localhost.daplie.me, 4
 localhostcert.net, 4
 localplayer.dev, 4
-localzone.xyz, 4
 locker, 0
 locus, 0
 lodi.it, 0
@@ -4794,7 +4824,6 @@
 lomza.pl, 0
 lon-1.paas.massivegrid.net, 4
 lon-2.paas.massivegrid.net, 4
-lon.wafaicloud.com, 4
 london, 0
 london.cloudapps.digital, 4
 londrina.br, 0
@@ -4868,11 +4897,12 @@
 maceio.br, 0
 macerata.it, 0
 machida.tokyo.jp, 0
+madethis.site, 4
 madrid, 0
 maebashi.gunma.jp, 0
+mafelo.net, 4
 magazine.aero, 0
 magentosite.cloud, 6
-magnet.page, 4
 maibara.shiga.jp, 0
 maif, 0
 mail-box.ne.jp, 4
@@ -4910,6 +4940,7 @@
 marker.no, 0
 market, 0
 marketing, 0
+marketplace.aero, 0
 markets, 0
 marnardal.no, 0
 marriott, 0
@@ -4927,6 +4958,7 @@
 masuda.shimane.jp, 0
 mat.br, 0
 matera.it, 0
+matlab.cloud, 4
 matrix.jp, 4
 matsubara.osaka.jp, 0
 matsubushi.saitama.jp, 0
@@ -4955,8 +4987,6 @@
 mb.it, 0
 mba, 0
 mc, 0
-mc.ax, 4
-mc.eu.org, 4
 mc.it, 0
 mcdir.me, 4
 mcdir.ru, 4
@@ -4967,6 +4997,8 @@
 md.ci, 0
 md.us, 0
 me, 0
+me-central-1.airflow.amazonaws.com, 6
+me-south-1.airflow.amazonaws.com, 6
 me-south-1.elasticbeanstalk.com, 4
 me.eu.org, 4
 me.in, 0
@@ -4974,11 +5006,9 @@
 me.ke, 0
 me.so, 0
 me.ss, 0
-me.tc, 4
 me.tz, 0
 me.uk, 0
 me.us, 0
-me.vu, 4
 med, 0
 med.br, 0
 med.ec, 0
@@ -4997,6 +5027,7 @@
 media.aero, 0
 media.hu, 0
 media.pl, 0
+media.strapiapp.com, 4
 mediatech.by, 4
 mediatech.dev, 4
 medicina.bo, 0
@@ -5166,7 +5197,6 @@
 minokamo.gifu.jp, 0
 minowa.nagano.jp, 0
 mint, 0
-mintere.site, 4
 mints.ne.jp, 4
 mircloud.host, 4
 mircloud.ru, 4
@@ -5253,6 +5283,7 @@
 moda, 0
 modalen.no, 0
 modelling.aero, 0
+modelscape.com, 4
 modena.it, 0
 mods.jp, 4
 modum.no, 0
@@ -5309,7 +5340,6 @@
 mov, 0
 movie, 0
 movimiento.bo, 0
-mozilla-iot.org, 4
 mp, 0
 mp.br, 0
 mq, 0
@@ -5369,6 +5399,7 @@
 mv, 0
 mw, 0
 mw.gov.pl, 0
+mwcloudnonprod.com, 4
 mx, 0
 mx.na, 0
 my, 0
@@ -5385,7 +5416,7 @@
 myamaze.net, 4
 myasustor.com, 4
 mycd.eu, 4
-mycloud.by, 4
+mycloudnas.com, 4
 mydatto.com, 4
 mydatto.net, 4
 myddns.rocks, 4
@@ -5412,14 +5443,17 @@
 mykolaiv.ua, 0
 mymailer.com.tw, 4
 mymediapc.net, 4
+mynascloud.com, 4
 myoko.niigata.jp, 0
 mypep.link, 4
 mypets.ws, 4
 myphotos.cc, 4
 mypi.co, 4
 mypsx.net, 4
+myqnapcloud.cn, 4
 myqnapcloud.com, 4
 myradweb.net, 4
+myrdbx.io, 4
 mysecuritycamera.com, 4
 mysecuritycamera.net, 4
 mysecuritycamera.org, 4
@@ -5567,10 +5601,10 @@
 narvik.no, 0
 nasu.tochigi.jp, 0
 nasushiobara.tochigi.jp, 0
+nat.cu, 0
 nat.tn, 0
 natal.br, 0
 natori.miyagi.jp, 0
-natura, 0
 natural.bo, 0
 naturbruksgymn.se, 0
 naustdal.no, 0
@@ -5596,7 +5630,6 @@
 neat-url.com, 4
 nec, 0
 nedre-eiker.no, 0
-neko.am, 4
 nemuro.hokkaido.jp, 0
 nerdpol.ovh, 4
 nerima.tokyo.jp, 0
@@ -5747,6 +5780,7 @@
 net.zm, 0
 netbank, 0
 netflix, 0
+netfy.app, 4
 netgamers.jp, 4
 netlify.app, 4
 network, 0
@@ -5770,6 +5804,7 @@
 ngo.lk, 0
 ngo.ng, 4
 ngo.ph, 0
+ngo.us, 4
 ngo.za, 0
 ngrok-free.app, 4
 ngrok-free.dev, 4
@@ -5790,7 +5825,6 @@
 nichinan.miyazaki.jp, 0
 nichinan.tottori.jp, 0
 nico, 0
-nid.io, 4
 nieruchomosci.pl, 0
 niigata.jp, 0
 niigata.niigata.jp, 0
@@ -5846,7 +5880,6 @@
 nl, 0
 nl-ams-1.baremetal.scw.cloud, 4
 nl.ca, 0
-nl.ci, 4
 nl.eu.org, 4
 nl.no, 0
 nm.cn, 0
@@ -5858,7 +5891,6 @@
 no-ip.info, 4
 no-ip.net, 4
 no-ip.org, 4
-no.com, 4
 no.eu.org, 4
 no.it, 0
 nobeoka.miyazaki.jp, 0
@@ -5928,6 +5960,7 @@
 notebook-fips.us-east-2.sagemaker.aws, 4
 notebook-fips.us-gov-east-1.sagemaker.aws, 4
 notebook-fips.us-gov-west-1.sagemaker.aws, 4
+notebook-fips.us-west-1.sagemaker.aws, 4
 notebook-fips.us-west-2.sagemaker.aws, 4
 notebook.af-south-1.sagemaker.aws, 4
 notebook.ap-east-1.sagemaker.aws, 4
@@ -5964,6 +5997,7 @@
 notebook.us-west-2.sagemaker.aws, 4
 noticeable.news, 4
 noticias.bo, 0
+notion.site, 4
 noto.ishikawa.jp, 0
 notodden.no, 0
 notogawa.shiga.jp, 0
@@ -6010,9 +6044,8 @@
 ny-1.paas.massivegrid.net, 4
 ny-2.paas.massivegrid.net, 4
 ny.us, 0
-nyaa.am, 4
-nyan.to, 4
 nyanta.jp, 4
+nyat.app, 4
 nyc, 0
 nyc.mn, 4
 nysa.pl, 0
@@ -6031,7 +6064,11 @@
 obi, 0
 obihiro.hokkaido.jp, 0
 obira.hokkaido.jp, 0
+objects.lpg.cloudscale.ch, 4
+objects.rma.cloudscale.ch, 4
+obl.ong, 4
 obninsk.su, 4
+observablehq.cloud, 4
 observer, 0
 obu.aichi.jp, 0
 obuse.nagano.jp, 0
@@ -6152,6 +6189,7 @@
 on-rio.io, 6
 on-the-web.tv, 4
 on-web.fr, 4
+on.biz.ng, 4
 on.ca, 0
 on.crisp.email, 4
 onagawa.miyagi.jp, 0
@@ -6160,7 +6198,6 @@
 ondigitalocean.app, 4
 one, 0
 onfabrica.com, 4
-onflashdrive.app, 4
 ong, 0
 ong.br, 0
 onga.fukuoka.jp, 0
@@ -6213,6 +6250,9 @@
 or.us, 0
 ora.gunma.jp, 0
 oracle, 0
+oraclecloudapps.com, 6
+oraclegovcloudapps.com, 6
+oraclegovcloudapps.uk, 6
 orange, 0
 orangecloud.tn, 4
 org, 0
@@ -6458,6 +6498,8 @@
 ozu.kumamoto.jp, 0
 p.bg, 0
 p.se, 0
+p.tawk.email, 4
+p.tawkto.email, 4
 pa, 0
 pa.gov.br, 0
 pa.gov.pl, 0
@@ -6471,7 +6513,6 @@
 padova.it, 0
 padua.it, 0
 page, 0
-pagefrontapp.com, 4
 pages.dev, 4
 pages.gay, 4
 pages.it.hs-heilbronn.de, 4
@@ -6512,7 +6553,6 @@
 pc.it, 0
 pc.pl, 0
 pccw, 0
-pcloud.host, 4
 pd.it, 0
 pdns.page, 4
 pe, 0
@@ -6605,6 +6645,7 @@
 playstation-cloud.com, 4
 plc.co.im, 0
 plc.ly, 0
+plc.ng, 4
 plc.uk, 0
 plesk.page, 4
 pleskns.com, 4
@@ -6639,6 +6680,7 @@
 politie, 0
 polkowice.pl, 0
 poltava.ua, 0
+polyspace.com, 4
 pomorskie.pl, 0
 pomorze.pl, 0
 poniatowa.pl, 4
@@ -6684,6 +6726,7 @@
 presse.km, 0
 presse.ml, 0
 preview.csb.app, 4
+preview.wdh.app, 4
 pri.ee, 0
 prime, 0
 primetel.cloud, 4
@@ -6745,7 +6788,6 @@
 pub.sa, 0
 publ.pt, 0
 public-inquiry.uk, 4
-publishproxy.com, 4
 pubtls.org, 4
 pueblo.bo, 0
 pug.it, 0
@@ -6773,7 +6815,6 @@
 qa2.com, 4
 qbuser.com, 4
 qc.ca, 0
-qc.com, 4
 qcx.io, 4
 qh.cn, 0
 qld.au, 0
@@ -6833,7 +6874,6 @@
 ravpage.co.il, 4
 rawa-maz.pl, 0
 rc.it, 0
-rdv.to, 4
 rdy.jp, 4
 re, 0
 re.it, 0
@@ -6841,6 +6881,7 @@
 read, 0
 read-books.org, 4
 readmyblog.org, 4
+readthedocs-hosted.com, 4
 readthedocs.io, 4
 readymade.jp, 4
 realestate, 0
@@ -6876,6 +6917,8 @@
 reklam.hu, 0
 rel.ht, 0
 rel.pl, 0
+relay.evervault.app, 4
+relay.evervault.dev, 4
 reliance, 0
 remotewd.com, 4
 ren, 0
@@ -6956,7 +6999,6 @@
 ro, 0
 ro.eu.org, 4
 ro.gov.br, 0
-ro.im, 4
 ro.it, 0
 ro.leg.br, 4
 roan.no, 0
@@ -6976,6 +7018,9 @@
 rost.no, 0
 rotorcraft.aero, 0
 router.management, 4
+routingthecloud.com, 4
+routingthecloud.net, 4
+routingthecloud.org, 4
 rovigo.it, 0
 rovno.ua, 0
 royal-commission.uk, 4
@@ -6990,8 +7035,9 @@
 rs.webaccel.jp, 4
 rsc.cdn77.org, 4
 rsc.contentproxy9.cz, 4
-rss.my.id, 6
+rss.my.id, 4
 rsvp, 0
+rt.ht, 4
 ru, 0
 ru.com, 4
 ru.eu.org, 4
@@ -7461,7 +7507,6 @@
 sch.ng, 0
 sch.qa, 0
 sch.sa, 0
-sch.so, 4
 sch.ss, 0
 sch.tf, 4
 sch.uk, 2
@@ -7551,6 +7596,7 @@
 servebbs.org, 4
 servebeer.com, 4
 serveblog.net, 4
+servebolt.cloud, 4
 servecounterstrike.com, 4
 serveexchange.com, 4
 serveftp.com, 4
@@ -7577,6 +7623,7 @@
 servicebus.windows.net, 4
 services, 0
 services.aero, 0
+services.clever-cloud.com, 6
 setagaya.tokyo.jp, 0
 seto.aichi.jp, 0
 setouchi.okayama.jp, 0
@@ -7599,7 +7646,7 @@
 shangrila, 0
 shari.hokkaido.jp, 0
 sharp, 0
-shaw, 0
+sheezy.games, 4
 shell, 0
 shia, 0
 shibata.miyagi.jp, 0
@@ -7610,8 +7657,6 @@
 shibuya.tokyo.jp, 0
 shichikashuku.miyagi.jp, 0
 shichinohe.aomori.jp, 0
-shiftcrypto.dev, 4
-shiftcrypto.io, 4
 shiftedit.io, 4
 shiga.jp, 0
 shiiba.miyazaki.jp, 0
@@ -7695,6 +7740,7 @@
 shonai.yamagata.jp, 0
 shoo.okayama.jp, 0
 shop, 0
+shop.brendly.hr, 4
 shop.brendly.rs, 4
 shop.ht, 0
 shop.hu, 0
@@ -7738,10 +7784,10 @@
 sirdal.no, 0
 sisko.replit.dev, 4
 site, 0
+site.rb-hosting.io, 4
 site.tb-hosting.com, 4
 site.transip.me, 4
 siteleaf.net, 4
-sites.static.land, 4
 sj, 0
 sjc.br, 0
 sk, 0
@@ -7788,6 +7834,7 @@
 smushcdn.com, 4
 sn, 0
 sn.cn, 0
+sn.mynetname.net, 4
 snaase.no, 0
 snasa.no, 0
 sncf, 0
@@ -7890,6 +7937,7 @@
 stackit.zone, 4
 stada, 0
 stage.nodeart.io, 4
+staging.expo.app, 4
 staging.onred.one, 4
 staging.replit.dev, 4
 stalowa-wola.pl, 0
@@ -7904,7 +7952,6 @@
 statefarm, 0
 stathelle.no, 0
 static-access.net, 4
-static.land, 4
 static.observableusercontent.com, 4
 statics.cloud, 6
 stavanger.no, 0
@@ -7940,6 +7987,7 @@
 storj.farm, 4
 strand.no, 0
 stranda.no, 0
+strapiapp.com, 4
 streak-link.com, 4
 streaklinks.com, 4
 streakusercontent.com, 4
@@ -7967,6 +8015,7 @@
 studio.eu-central-1.sagemaker.aws, 4
 studio.eu-north-1.sagemaker.aws, 4
 studio.eu-south-1.sagemaker.aws, 4
+studio.eu-south-2.sagemaker.aws, 4
 studio.eu-west-1.sagemaker.aws, 4
 studio.eu-west-2.sagemaker.aws, 4
 studio.eu-west-3.sagemaker.aws, 4
@@ -7986,7 +8035,6 @@
 stufftoread.com, 4
 style, 0
 su, 0
-su.paba.se, 4
 sub.jp, 4
 sucks, 0
 sue.fukuoka.jp, 0
@@ -8063,8 +8111,8 @@
 szex.hu, 0
 szkola.pl, 0
 t.bg, 0
+t.hrsn.net, 4
 t.se, 0
-t3l3p0rt.net, 4
 ta.it, 0
 taa.it, 0
 tab, 0
@@ -8174,6 +8222,7 @@
 tawaramoto.nara.jp, 0
 tax, 0
 taxi, 0
+taxi.aero, 0
 taxi.br, 0
 tayninh.vn, 0
 tc, 0
@@ -8196,7 +8245,6 @@
 tecnologia.bo, 0
 tel, 0
 tel.tr, 0
-tele.amune.org, 4
 telebit.app, 4
 telebit.io, 4
 telebit.xyz, 6
@@ -8282,10 +8330,8 @@
 tn.us, 0
 to, 0
 to.gov.br, 0
-to.gt, 4
 to.it, 0
 to.leg.br, 4
-to.md, 4
 toba.mie.jp, 0
 tobe.ehime.jp, 0
 tobetsu.hokkaido.jp, 0
@@ -8529,7 +8575,6 @@
 tv.im, 0
 tv.in, 0
 tv.it, 0
-tv.kg, 4
 tv.na, 0
 tv.sd, 0
 tv.tr, 0
@@ -8587,7 +8632,6 @@
 uk.com, 4
 uk.eu.org, 4
 uk.in, 0
-uk.kg, 4
 uk.net, 4
 uk.oxa.cloud, 4
 uk.primetel.cloud, 4
@@ -8625,7 +8669,6 @@
 uonuma.niigata.jp, 0
 uozu.toyama.jp, 0
 up.in, 0
-upaas.kazteleport.kz, 4
 upli.io, 4
 upow.gov.pl, 0
 upper.jp, 4
@@ -8659,10 +8702,10 @@
 us-east-2.elasticbeanstalk.com, 4
 us-gov-east-1.elasticbeanstalk.com, 4
 us-gov-west-1.elasticbeanstalk.com, 4
+us-west-1.airflow.amazonaws.com, 6
 us-west-1.elasticbeanstalk.com, 4
 us-west-2.airflow.amazonaws.com, 6
 us-west-2.elasticbeanstalk.com, 4
-us.ax, 4
 us.com, 4
 us.eu.org, 4
 us.gov.pl, 0
@@ -8699,7 +8742,6 @@
 uwajima.ehime.jp, 0
 uwu.ai, 4
 uy, 0
-uy.com, 4
 uz, 0
 uz.ua, 0
 uzhgorod.ua, 0
@@ -8883,13 +8925,14 @@
 vu, 0
 vultrobjects.com, 6
 vv.it, 0
-vxl.sh, 4
 w-corp-staticblitz.com, 4
 w-credentialless-staticblitz.com, 4
 w-staticblitz.com, 4
 w.bg, 0
+w.crm.dev, 6
 w.se, 0
 wa.au, 0
+wa.crm.dev, 6
 wa.edu.au, 0
 wa.gov.au, 0
 wa.us, 0
@@ -8924,8 +8967,12 @@
 watson.jp, 4
 waw.pl, 0
 wazuka.kyoto.jp, 0
+wb.crm.dev, 6
+wc.crm.dev, 6
+wd.crm.dev, 6
+wdh.app, 4
 we.bs, 4
-we.tc, 4
+we.crm.dev, 6
 weather, 0
 weatherchannel, 0
 web.app, 4
@@ -8941,8 +8988,10 @@
 web.pk, 0
 web.tj, 0
 web.tr, 0
+web.val.run, 4
 web.ve, 0
 web.za, 0
+webadorsite.com, 4
 webcam, 0
 weber, 0
 webflow.io, 4
@@ -8959,6 +9008,7 @@
 webredirect.org, 4
 website, 0
 website.yandexcloud.net, 4
+websitebuilder.online, 4
 websozai.jp, 4
 webspace.rocks, 4
 webthings.io, 4
@@ -9007,20 +9057,16 @@
 webview-assets.cloud9.us-west-2.amazonaws.com, 4
 wed, 0
 wedding, 0
-wedeploy.io, 4
-wedeploy.me, 4
-wedeploy.sh, 4
 weeklylottery.org.uk, 4
 wegrow.pl, 0
 weibo, 0
 weir, 0
-wellbeingzone.co.uk, 4
-wellbeingzone.eu, 4
 wesley.replit.dev, 4
 west1-us.cloudjiffy.net, 4
 westeurope.azurestaticapps.net, 4
 westus2.azurestaticapps.net, 4
 wf, 0
+wf.crm.dev, 6
 whitesnow.jp, 4
 whm.fr-par.scw.cloud, 4
 whm.nl-ams.scw.cloud, 4
@@ -9047,6 +9093,7 @@
 wiw.gov.pl, 0
 wix.run, 4
 wixsite.com, 4
+wixstudio.com, 4
 wixstudio.io, 4
 wjg.jp, 4
 wkz.gov.pl, 0
@@ -9071,11 +9118,13 @@
 world, 0
 worse-than.tv, 4
 wow, 0
+wp2.host, 4
 wpdevcloud.com, 4
 wpenginepowered.com, 4
 wphostedmail.com, 4
 wpmucdn.com, 4
 wpmudev.host, 4
+wpsquared.site, 4
 writesthisblog.com, 4
 wroc.pl, 4
 wroclaw.pl, 0
@@ -9106,6 +9155,7 @@
 xin, 0
 xj.cn, 0
 xmit.co, 6
+xmit.dev, 4
 xn--0trq7p7nn.jp, 0
 xn--11b4c3d, 0
 xn--12c1fe0br.xn--o3cw4h, 0
@@ -9567,9 +9617,7 @@
 xn--zfr164b, 0
 xnbay.com, 4
 xs4all.space, 4
-xx.gl, 4
 xxx, 0
-xy.ax, 4
 xyz, 0
 xz.cn, 0
 y.bg, 0
@@ -9681,6 +9729,7 @@
 yoshioka.gunma.jp, 0
 yotsukaido.chiba.jp, 0
 you, 0
+you2.pl, 4
 youtube, 0
 yt, 0
 yuasa.wakayama.jp, 0
@@ -9716,9 +9765,9 @@
 zaporizhzhia.ua, 0
 zappos, 0
 zapto.org, 4
-zapto.xyz, 4
 zara, 0
 zarow.pl, 0
+zeabur.app, 4
 zentsuji.kagawa.jp, 0
 zero, 0
 zgora.pl, 0
diff --git a/net/cert/crl_set.cc b/net/cert/crl_set.cc
index 879477f..6f096421 100644
--- a/net/cert/crl_set.cc
+++ b/net/cert/crl_set.cc
@@ -429,8 +429,8 @@
     crl_set->not_after_ = 1;
 
   if (issuer_spki) {
-    const std::string spki(reinterpret_cast<const char*>(issuer_spki->data),
-                           sizeof(issuer_spki->data));
+    std::string spki(reinterpret_cast<const char*>(issuer_spki->data),
+                     sizeof(issuer_spki->data));
     std::vector<std::string> serials;
     if (!serial_number.empty()) {
       serials.push_back(std::string(serial_number));
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc
index ef56f1f..f1275a88 100644
--- a/net/http/http_network_transaction.cc
+++ b/net/http/http_network_transaction.cc
@@ -951,6 +951,8 @@
   // they can also be disabled when retrying after a QUIC error).
   if (!enable_ip_based_pooling_)
     DCHECK(!enable_alternative_services_);
+
+  create_stream_start_time_ = base::TimeTicks::Now();
   if (ForWebSocketHandshake()) {
     stream_request_ =
         session_->http_stream_factory()->RequestWebSocketHandshakeStream(
@@ -971,6 +973,15 @@
   if (result == OK) {
     next_state_ = STATE_CONNECTED_CALLBACK;
     DCHECK(stream_.get());
+    CHECK(!create_stream_start_time_.is_null());
+    base::UmaHistogramTimes(
+        base::StrCat(
+            {"Net.NetworkTransaction.Create",
+             (ForWebSocketHandshake() ? "WebSocketStreamTime."
+                                      : "HttpStreamTime."),
+             (IsGoogleHostWithAlpnH3(url_.host()) ? "GoogleHost." : ""),
+             NegotiatedProtocolToHistogramSuffix(response_)}),
+        base::TimeTicks::Now() - create_stream_start_time_);
   } else if (result == ERR_HTTP_1_1_REQUIRED ||
              result == ERR_PROXY_HTTP_1_1_REQUIRED) {
     return HandleHttp11Required(result);
diff --git a/net/http/http_network_transaction.h b/net/http/http_network_transaction.h
index 2169a50..93a0a88e 100644
--- a/net/http/http_network_transaction.h
+++ b/net/http/http_network_transaction.h
@@ -443,6 +443,9 @@
   // transaction.
   int64_t total_sent_bytes_ = 0;
 
+  // When the transaction started creating a stream.
+  base::TimeTicks create_stream_start_time_;
+
   // When the transaction started / finished sending the request, including
   // the body, if present. |send_start_time_| is set to |base::TimeTicks()|
   // until |SendRequest()| is called on |stream_|, and reset for auth restarts.
diff --git a/net/http/http_stream_pool_attempt_manager.cc b/net/http/http_stream_pool_attempt_manager.cc
index 104595c..8d6eedf 100644
--- a/net/http/http_stream_pool_attempt_manager.cc
+++ b/net/http/http_stream_pool_attempt_manager.cc
@@ -695,15 +695,19 @@
   const bool using_tls = UsingTls();
   while (IsConnectionAttemptReady()) {
     std::unique_ptr<StreamAttempt> attempt;
+    // Set to non-null if the attempt is a TLS attempt.
+    TlsStreamAttempt* tls_attempt_ptr = nullptr;
     if (using_tls) {
       attempt = std::make_unique<TlsStreamAttempt>(
           pool()->stream_attempt_params(), *ip_endpoint,
           HostPortPair::FromSchemeHostPort(stream_key().destination()),
           /*ssl_config_provider=*/this);
+      tls_attempt_ptr = static_cast<TlsStreamAttempt*>(attempt.get());
     } else {
       attempt = std::make_unique<TcpStreamAttempt>(
           pool()->stream_attempt_params(), *ip_endpoint);
     }
+
     net_log().AddEventReferencingSource(
         NetLogEventType::HTTP_STREAM_POOL_ATTEMPT_MANAGER_ATTEMPT_START,
         attempt->net_log().source());
@@ -741,11 +745,10 @@
           FROM_HERE, kConnectionAttemptDelay,
           base::BindOnce(&AttemptManager::OnInFlightAttemptSlow,
                          base::Unretained(this), raw_attempt));
-      if (using_tls) {
-        static_cast<TlsStreamAttempt*>(raw_attempt->attempt.get())
-            ->SetTcpHandshakeCompletionCallback(base::BindOnce(
-                &AttemptManager::OnInFlightAttemptTcpHandshakeComplete,
-                base::Unretained(this), raw_attempt));
+      if (tls_attempt_ptr && !tls_attempt_ptr->IsTcpHandshakeCompleted()) {
+        tls_attempt_ptr->SetTcpHandshakeCompletionCallback(base::BindOnce(
+            &AttemptManager::OnInFlightAttemptTcpHandshakeComplete,
+            base::Unretained(this), raw_attempt));
       }
     }
 
diff --git a/net/http/http_stream_pool_attempt_manager_unittest.cc b/net/http/http_stream_pool_attempt_manager_unittest.cc
index 74c4a6f4..f0488f4 100644
--- a/net/http/http_stream_pool_attempt_manager_unittest.cc
+++ b/net/http/http_stream_pool_attempt_manager_unittest.cc
@@ -312,6 +312,7 @@
   // HttpStreamRequest::Delegate methods:
   void OnStreamReady(const ProxyInfo& used_proxy_info,
                      std::unique_ptr<HttpStream> stream) override {
+    used_proxy_info_ = used_proxy_info;
     stream_ = std::move(stream);
     SetResult(OK);
   }
@@ -333,6 +334,7 @@
                       const ProxyInfo& used_proxy_info,
                       ResolveErrorInfo resolve_error_info) override {
     net_error_details_ = net_error_details;
+    used_proxy_info_ = used_proxy_info;
     resolve_error_info_ = resolve_error_info;
     SetResult(status);
   }
@@ -383,6 +385,8 @@
     return request_->connection_attempts();
   }
 
+  const ProxyInfo& used_proxy_info() const { return used_proxy_info_; }
+
  private:
   void SetResult(int rv) {
     result_ = rv;
@@ -415,6 +419,7 @@
   ResolveErrorInfo resolve_error_info_;
   SSLInfo cert_error_ssl_info_;
   scoped_refptr<SSLCertRequestInfo> cert_info_;
+  ProxyInfo used_proxy_info_;
 };
 
 constexpr std::string_view kDefaultServerName = "www.example.org";
@@ -832,7 +837,7 @@
   ASSERT_EQ(requester.connection_attempts()[0].result, ERR_FAILED);
 }
 
-TEST_F(HttpStreamPoolAttemptManagerTest, TlsOk) {
+TEST_F(HttpStreamPoolAttemptManagerTest, TlsOkAsync) {
   FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest();
 
   auto data = std::make_unique<SequencedSocketData>();
@@ -850,6 +855,25 @@
   EXPECT_THAT(requester.result(), Optional(IsOk()));
 }
 
+TEST_F(HttpStreamPoolAttemptManagerTest, TcpSyncTlsAsyncOk) {
+  auto data = std::make_unique<SequencedSocketData>();
+  data->set_connect_data(MockConnect(SYNCHRONOUS, OK));
+  socket_factory()->AddSocketDataProvider(data.get());
+  SSLSocketDataProvider ssl(ASYNC, OK);
+  socket_factory()->AddSSLSocketDataProvider(&ssl);
+
+  resolver()
+      ->AddFakeRequest()
+      ->add_endpoint(ServiceEndpointBuilder().add_v4("192.0.2.1").endpoint())
+      .CompleteStartSynchronously(OK);
+
+  StreamRequester requester;
+  requester.set_destination("https://a.test").RequestStream(pool());
+
+  requester.WaitForResult();
+  EXPECT_THAT(requester.result(), Optional(IsOk()));
+}
+
 TEST_F(HttpStreamPoolAttemptManagerTest, TlsCryptoReadyDelayed) {
   FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest();
 
@@ -4096,4 +4120,25 @@
   EXPECT_THAT(it->second.net_error, IsError(ERR_PROXY_CONNECTION_FAILED));
 }
 
+TEST_F(HttpStreamPoolAttemptManagerTest, DirectProxyInfoForIpProtection) {
+  const auto kIpProtectionDirectChain =
+      ProxyChain::ForIpProtection(std::vector<ProxyServer>());
+  ProxyInfo proxy_info;
+  proxy_info.UseProxyChain(kIpProtectionDirectChain);
+
+  resolver()
+      ->AddFakeRequest()
+      ->add_endpoint(ServiceEndpointBuilder().add_v4("192.0.2.1").endpoint())
+      .CompleteStartSynchronously(OK);
+  StaticSocketDataProvider data;
+  socket_factory()->AddSocketDataProvider(&data);
+
+  StreamRequester requester;
+  requester.set_proxy_info(proxy_info).RequestStream(pool());
+  requester.WaitForResult();
+  EXPECT_THAT(requester.result(), Optional(IsOk()));
+  EXPECT_EQ(requester.used_proxy_info().ToDebugString(),
+            proxy_info.ToDebugString());
+}
+
 }  // namespace net
diff --git a/net/http/http_stream_pool_job.h b/net/http/http_stream_pool_job.h
index 2362f11f..cd23443 100644
--- a/net/http/http_stream_pool_job.h
+++ b/net/http/http_stream_pool_job.h
@@ -102,6 +102,8 @@
   // requested a client certificate.
   void OnNeedsClientAuth(SSLCertRequestInfo* cert_info);
 
+  const ProxyInfo& proxy_info() const { return proxy_info_; }
+
   const ConnectionAttempts& connection_attempts() const {
     return connection_attempts_;
   }
diff --git a/net/http/http_stream_pool_job_controller.cc b/net/http/http_stream_pool_job_controller.cc
index ccd490fc..8aeea3b 100644
--- a/net/http/http_stream_pool_job_controller.cc
+++ b/net/http/http_stream_pool_job_controller.cc
@@ -103,7 +103,8 @@
   SetJobResult(job, OK);
   request_->Complete(negotiated_protocol,
                      ALTERNATE_PROTOCOL_USAGE_UNSPECIFIED_REASON);
-  delegate_->OnStreamReady(ProxyInfo::Direct(), std::move(stream));
+  // `job` should not be destroyed yet.
+  delegate_->OnStreamReady(job->proxy_info(), std::move(stream));
 }
 
 void HttpStreamPool::JobController::OnStreamFailed(
@@ -114,7 +115,8 @@
   request_->AddConnectionAttempts(job->connection_attempts());
   SetJobResult(job, status);
   if (AllJobsFinished()) {
-    delegate_->OnStreamFailed(status, net_error_details, ProxyInfo::Direct(),
+    // `job` should not be destroyed yet.
+    delegate_->OnStreamFailed(status, net_error_details, job->proxy_info(),
                               std::move(resolve_error_info));
   }
 }
diff --git a/net/ntlm/ntlm_buffer_writer.h b/net/ntlm/ntlm_buffer_writer.h
index 8898a58..8d07b03 100644
--- a/net/ntlm/ntlm_buffer_writer.h
+++ b/net/ntlm/ntlm_buffer_writer.h
@@ -57,7 +57,7 @@
   size_t GetCursor() const { return cursor_; }
   bool IsEndOfBuffer() const { return cursor_ >= GetLength(); }
   base::span<const uint8_t> GetBuffer() const { return buffer_; }
-  std::vector<uint8_t> Pass() const { return std::move(buffer_); }
+  std::vector<uint8_t> Pass() { return std::move(buffer_); }
 
   // Returns true if there are |len| more bytes between the current cursor
   // position and the end of the buffer.
diff --git a/net/socket/tls_stream_attempt.cc b/net/socket/tls_stream_attempt.cc
index 1b5b315..25da52972 100644
--- a/net/socket/tls_stream_attempt.cc
+++ b/net/socket/tls_stream_attempt.cc
@@ -116,6 +116,7 @@
       nested_attempt_->connect_timing();
   mutable_connect_timing().connect_start = nested_timing.connect_start;
 
+  tcp_handshake_completed_ = true;
   if (tcp_handshake_completion_callback_) {
     std::move(tcp_handshake_completion_callback_).Run(rv);
   }
diff --git a/net/socket/tls_stream_attempt.h b/net/socket/tls_stream_attempt.h
index c3f5187e..0ddd117 100644
--- a/net/socket/tls_stream_attempt.h
+++ b/net/socket/tls_stream_attempt.h
@@ -68,6 +68,8 @@
   // `this` has already completed the TCP handshake.
   void SetTcpHandshakeCompletionCallback(CompletionOnceCallback callback);
 
+  bool IsTcpHandshakeCompleted() { return tcp_handshake_completed_; }
+
   bool IsTlsHandshakeStarted() { return tls_handshake_started_; }
 
  private:
@@ -100,6 +102,7 @@
   std::unique_ptr<TcpStreamAttempt> nested_attempt_;
   CompletionOnceCallback tcp_handshake_completion_callback_;
 
+  bool tcp_handshake_completed_ = false;
   bool tls_handshake_started_ = false;
   base::OneShotTimer tls_handshake_timeout_timer_;
   std::unique_ptr<SSLClientSocket> ssl_socket_;
diff --git a/net/third_party/quiche/src b/net/third_party/quiche/src
index 0b682f33..92bef88 160000
--- a/net/third_party/quiche/src
+++ b/net/third_party/quiche/src
@@ -1 +1 @@
-Subproject commit 0b682f33d185e50cfdf1e417fe6a021162a5fa18
+Subproject commit 92bef88ae524d684ff4e1397853ca51604d1da11
diff --git a/remoting/host/installer/mac/BUILD.gn b/remoting/host/installer/mac/BUILD.gn
index bbb6014c..0b39eeb 100644
--- a/remoting/host/installer/mac/BUILD.gn
+++ b/remoting/host/installer/mac/BUILD.gn
@@ -10,6 +10,7 @@
     "app-entitlements.plist",
     "do_signing.sh",
     "do_signing.props",
+    "me2me-entitlements.plist",
     "ChromotingHost.pkgproj",
     "ChromotingHostService.pkgproj",
     "ChromotingHostUninstaller.pkgproj",
diff --git a/remoting/host/installer/mac/do_signing.sh b/remoting/host/installer/mac/do_signing.sh
index 853b2e92..4283e11 100755
--- a/remoting/host/installer/mac/do_signing.sh
+++ b/remoting/host/installer/mac/do_signing.sh
@@ -54,8 +54,13 @@
   PKGPROJ_HOST_SERVICE="ChromotingHostService.pkgproj"
   PKGPROJ_HOST_UNINSTALLER="ChromotingHostUninstaller.pkgproj"
 
-  # The app entitlements file.
-  APP_ENTITLEMENTS="app-entitlements.plist"
+  # Bundle-specific entitlements which include restricted entitlements. These
+  # can only be used for signing specific bundles with official credentials.
+  ME2ME_ENTITLEMENTS="me2me-entitlements.plist"
+
+  # The default entitlements file. This contains unrestricted entitlements that
+  # can safely be applied for local signing.
+  DEFAULT_ENTITLEMENTS="app-entitlements.plist"
 
   # Final (user-visible) pkg name.
   PKG_FINAL="${HOST_PKG}.pkg"
@@ -118,6 +123,7 @@
   local name="${1}"
   local keychain="${2}"
   local id="${3}"
+  local entitlements="${4:-}"
 
   if [[ ! -e "${name}" ]]; then
     err_exit "Input file doesn't exist: ${name}"
@@ -130,9 +136,11 @@
   # Expanding a zero-size array with "set -u" aborts with "unbound variable".
   local args=(-vv --sign "${id}")
   if [[ -n "${keychain}" ]]; then
-      args+=(--keychain "${keychain}")
+    args+=(--keychain "${keychain}")
   fi
-  args+=(--entitlements "${input_dir}/${APP_ENTITLEMENTS}")
+  if [[ -n "${entitlements}" ]]; then
+    args+=(--entitlements "${input_dir}/${entitlements}")
+  fi
   args+=(--timestamp --options runtime "${name}")
   codesign "${args[@]}"
   codesign -v "${name}"
@@ -151,7 +159,15 @@
     "${UNINSTALLER}" \
   )
   for binary in "${binaries[@]}"; do
-    sign "${input_dir}/${binary}" "${keychain}" "${id}"
+    local entitlements="${DEFAULT_ENTITLEMENTS}"
+
+    # Restricted entitlements must only be claimed for builds signed with
+    # official credentials. Locally-signed development packages do not use any
+    # productsign_id.
+    if [[ -n "${productsign_id}" && "${binary}" == "${ME2ME_HOST}" ]]; then
+      entitlements="${ME2ME_ENTITLEMENTS}"
+    fi
+    sign "${input_dir}/${binary}" "${keychain}" "${id}" "${entitlements}"
   done
 }
 
diff --git a/remoting/host/installer/mac/me2me-entitlements.plist b/remoting/host/installer/mac/me2me-entitlements.plist
new file mode 100644
index 0000000..c71ef10
--- /dev/null
+++ b/remoting/host/installer/mac/me2me-entitlements.plist
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>com.apple.security.device.audio-input</key>
+	<true/>
+	<key>com.apple.developer.persistent-content-capture</key>
+	<true/>
+</dict>
+</plist>
diff --git a/remoting/host/mac/BUILD.gn b/remoting/host/mac/BUILD.gn
index 44afc08..e5dfd4d 100644
--- a/remoting/host/mac/BUILD.gn
+++ b/remoting/host/mac/BUILD.gn
@@ -14,6 +14,13 @@
   }
 }
 
+if (is_chrome_branded && is_official_build) {
+  bundle_data("me2me_provisionprofile") {
+    sources = [ "//remoting/internal/mac/Google_Chrome_Remote_Desktop_Remote_Access.provisionprofile" ]
+    outputs = [ "{{bundle_contents_dir}}/embedded.provisionprofile" ]
+  }
+}
+
 source_set("constants") {
   defines = [
     "HOST_BUNDLE_NAME=\"" + me2me_host_bundle_name + "\"",
@@ -129,6 +136,10 @@
   if (icu_use_data_file) {
     deps += [ ":icu_data" ]
   }
+
+  if (is_chrome_branded && is_official_build) {
+    deps += [ ":me2me_provisionprofile" ]
+  }
 }
 
 foreach(locale, remoting_locales_with_underscores) {
diff --git a/sandbox/policy/features.cc b/sandbox/policy/features.cc
index f4425b079c..fabda3d 100644
--- a/sandbox/policy/features.cc
+++ b/sandbox/policy/features.cc
@@ -123,12 +123,6 @@
 BASE_FEATURE(kWinSboxRestrictCoreSharingOnRenderer,
              "WinSboxRestrictCoreSharingOnRenderer",
              base::FEATURE_DISABLED_BY_DEFAULT);
-
-// Creates an AppContainer policy without registering with the Windows firewall
-// service. See crbug.com/352720904 for details.
-BASE_FEATURE(kWinSboxACProfileWithoutFirewall,
-             "WinSboxACProfileWithoutFirewall",
-             base::FEATURE_DISABLED_BY_DEFAULT);
 #endif  // BUILDFLAG(IS_WIN)
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/sandbox/policy/features.h b/sandbox/policy/features.h
index e0ccc80..1d801ca 100644
--- a/sandbox/policy/features.h
+++ b/sandbox/policy/features.h
@@ -39,7 +39,6 @@
 SANDBOX_POLICY_EXPORT BASE_DECLARE_FEATURE(kWinSboxNoFakeGdiInit);
 SANDBOX_POLICY_EXPORT BASE_DECLARE_FEATURE(
     kWinSboxRestrictCoreSharingOnRenderer);
-SANDBOX_POLICY_EXPORT BASE_DECLARE_FEATURE(kWinSboxACProfileWithoutFirewall);
 #endif  // BUILDFLAG(IS_WIN)
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/sandbox/policy/win/sandbox_win.cc b/sandbox/policy/win/sandbox_win.cc
index 44c0c79..e6a3cd1 100644
--- a/sandbox/policy/win/sandbox_win.cc
+++ b/sandbox/policy/win/sandbox_win.cc
@@ -830,13 +830,8 @@
     return SBOX_ALL_OK;
   std::wstring profile_name =
       GetAppContainerProfileName(appcontainer_id, sandbox_type);
-  const ACProfileRegistration registration =
-      base::FeatureList::IsEnabled(features::kWinSboxACProfileWithoutFirewall)
-          ? ACProfileRegistration::kNoFirewall
-          : ACProfileRegistration::kDefault;
 
-  ResultCode result =
-      config->AddAppContainerProfile(profile_name.c_str(), registration);
+  ResultCode result = config->AddAppContainerProfile(profile_name.c_str());
   if (result != SBOX_ALL_OK)
     return result;
 
diff --git a/sandbox/policy/win/sandbox_win_unittest.cc b/sandbox/policy/win/sandbox_win_unittest.cc
index de7f75a..c43cd33d 100644
--- a/sandbox/policy/win/sandbox_win_unittest.cc
+++ b/sandbox/policy/win/sandbox_win_unittest.cc
@@ -98,9 +98,7 @@
   void AddKernelObjectToClose(HandleToClose handle_info) override {}
   void SetDisconnectCsrss() override {}
 
-  ResultCode AddAppContainerProfile(
-      const wchar_t* package_name,
-      ACProfileRegistration registration) override {
+  ResultCode AddAppContainerProfile(const wchar_t* package_name) override {
     app_container_ = AppContainerBase::Open(package_name);
     if (!app_container_) {
       return SBOX_ERROR_CREATE_APPCONTAINER;
diff --git a/sandbox/win/src/app_container_base.cc b/sandbox/win/src/app_container_base.cc
index 92f32be7..eadfefe 100644
--- a/sandbox/win/src/app_container_base.cc
+++ b/sandbox/win/src/app_container_base.cc
@@ -176,27 +176,6 @@
 // static
 std::unique_ptr<AppContainerBase> AppContainerBase::CreateProfile(
     const wchar_t* package_name,
-    const wchar_t* display_name,
-    const wchar_t* description) {
-  PSID package_sid_ptr = nullptr;
-  HRESULT hr = ::CreateAppContainerProfile(
-      package_name, display_name, description, nullptr, 0, &package_sid_ptr);
-  if (hr == HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS))
-    return Open(package_name);
-
-  if (FAILED(hr))
-    return nullptr;
-  std::unique_ptr<void, FreeSidDeleter> sid_deleter(package_sid_ptr);
-  auto package_sid = base::win::Sid::FromPSID(package_sid_ptr);
-  if (!package_sid)
-    return nullptr;
-  return std::make_unique<AppContainerBase>(
-      package_name, std::move(*package_sid), AppContainerType::kProfile);
-}
-
-// static
-std::unique_ptr<AppContainerBase> AppContainerBase::CreateProfileNoFirewall(
-    const wchar_t* package_name,
     const wchar_t* display_name) {
   auto package_sid = DerivePackageSid(package_name);
   if (!package_sid) {
@@ -260,11 +239,6 @@
 
 // static
 bool AppContainerBase::Delete(const wchar_t* package_name) {
-  return SUCCEEDED(::DeleteAppContainerProfile(package_name));
-}
-
-// static
-bool AppContainerBase::DeleteNoFirewall(const wchar_t* package_name) {
   auto package_sid = DerivePackageSid(package_name);
   if (!package_sid) {
     return false;
diff --git a/sandbox/win/src/app_container_base.h b/sandbox/win/src/app_container_base.h
index 92223ec..74eaa17 100644
--- a/sandbox/win/src/app_container_base.h
+++ b/sandbox/win/src/app_container_base.h
@@ -59,16 +59,6 @@
   // the Delete method if it's no longer required.
   static std::unique_ptr<AppContainerBase> CreateProfile(
       const wchar_t* package_name,
-      const wchar_t* display_name,
-      const wchar_t* description);
-
-  // Creates a new AppContainer object. This will create a new profile
-  // if it doesn't already exist. The profile must be deleted manually using
-  // the `DeleteNoFirewall` method if it's no longer required. This differs from
-  // the `CreateProfile` method in that it doesn't register the profile with the
-  // system firewall which might remove contention and deadlock issues.
-  static std::unique_ptr<AppContainerBase> CreateProfileNoFirewall(
-      const wchar_t* package_name,
       const wchar_t* display_name);
 
   // Opens a derived AppContainer object. No checks will be made on
@@ -86,12 +76,6 @@
   // package doesn't already exist.
   static bool Delete(const wchar_t* package_name);
 
-  // Delete a profile based on name. Returns true if successful, or if the
-  // package doesn't already exist. This differs from the `DeleteProfile`
-  // method in that it doesn't delete the profile with the system firewall
-  // which might remove contention and deadlock issues.
-  static bool DeleteNoFirewall(const wchar_t* package_name);
-
   // Build an impersontion token from an existing token.
   // `token` specify the base token to create the new token from. Must have
   // TOKEN_DUPLICATE access. The token is created with the impersonation
diff --git a/sandbox/win/src/app_container_test.cc b/sandbox/win/src/app_container_test.cc
index 3a823a7..43c7c39 100644
--- a/sandbox/win/src/app_container_test.cc
+++ b/sandbox/win/src/app_container_test.cc
@@ -49,25 +49,6 @@
     L"S-1-15-2-3251537155-1984446955-2931258699-841473695-1938553385-"
     L"924012148-2839372144";
 
-constexpr ACProfileRegistration GetProfileRegistration() {
-#if defined(ARCH_CPU_ARM64)
-  return ACProfileRegistration::kNoFirewall;
-#else
-  return ACProfileRegistration::kDefault;
-#endif  // defined(ARCH_CPU_ARM64)
-}
-
-void DeleteProfile(const wchar_t* package_name) {
-  switch (GetProfileRegistration()) {
-    case ACProfileRegistration::kDefault:
-      AppContainerBase::Delete(package_name);
-      break;
-    case ACProfileRegistration::kNoFirewall:
-      AppContainerBase::DeleteNoFirewall(package_name);
-      break;
-  }
-}
-
 std::wstring GenerateRandomPackageName() {
   return base::ASCIIToWide(base::StringPrintf(
       "%016" PRIX64 "%016" PRIX64, base::RandUint64(), base::RandUint64()));
@@ -177,8 +158,8 @@
 // Adds an app container policy similar to network service.
 ResultCode AddNetworkAppContainerPolicy(TargetPolicy* policy) {
   std::wstring profile_name = GetAppContainerProfileName();
-  ResultCode ret = policy->GetConfig()->AddAppContainerProfile(
-      profile_name.c_str(), GetProfileRegistration());
+  ResultCode ret =
+      policy->GetConfig()->AddAppContainerProfile(profile_name.c_str());
   if (SBOX_ALL_OK != ret)
     return ret;
   ret = policy->GetConfig()->SetTokenLevel(USER_UNPROTECTED, USER_UNPROTECTED);
@@ -217,9 +198,8 @@
     policy_ = broker_services_->CreatePolicy();
     ASSERT_EQ(SBOX_ALL_OK, policy_->GetConfig()->SetProcessMitigations(
                                MITIGATION_HEAP_TERMINATE));
-    ASSERT_EQ(SBOX_ALL_OK,
-              policy_->GetConfig()->AddAppContainerProfile(
-                  package_name_.c_str(), GetProfileRegistration()));
+    ASSERT_EQ(SBOX_ALL_OK, policy_->GetConfig()->AddAppContainerProfile(
+                               package_name_.c_str()));
     created_profile_ = true;
   }
 
@@ -228,7 +208,7 @@
       ::TerminateProcess(scoped_process_info_.process_handle(), 0);
     }
     if (created_profile_) {
-      DeleteProfile(package_name_.c_str());
+      AppContainerBase::Delete(package_name_.c_str());
     }
   }
 
@@ -479,7 +459,7 @@
 
   EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"LoadDLL"));
 
-  DeleteProfile(GetAppContainerProfileName().c_str());
+  AppContainerBase::Delete(GetAppContainerProfileName().c_str());
 }
 
 TEST(AppContainerLaunchTest, IsAppContainer) {
@@ -490,7 +470,7 @@
 
   EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckIsAppContainer"));
 
-  DeleteProfile(GetAppContainerProfileName().c_str());
+  AppContainerBase::Delete(GetAppContainerProfileName().c_str());
 }
 
 TEST(AppContainerLaunchTest, IsNotAppContainer) {
@@ -499,19 +479,6 @@
   EXPECT_EQ(SBOX_TEST_FAILED, runner.RunTest(L"CheckIsAppContainer"));
 }
 
-TEST(AppContainerLaunchTest, IsAppContainerNoFirewall) {
-  if (!features::IsAppContainerSandboxSupported()) {
-    return;
-  }
-  TestRunner runner;
-  std::wstring package_name = GenerateRandomPackageName();
-  ASSERT_EQ(SBOX_ALL_OK,
-            runner.GetPolicy()->GetConfig()->AddAppContainerProfile(
-                package_name.c_str(), ACProfileRegistration::kNoFirewall));
-  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckIsAppContainer"));
-  EXPECT_TRUE(AppContainerBase::DeleteNoFirewall(package_name.c_str()));
-}
-
 SBOX_TESTS_COMMAND int CreateTempFileInAppContainer(int argc, wchar_t** argv) {
   if (!base::IsCurrentProcessInAppContainer()) {
     return SBOX_TEST_FIRST_ERROR;
@@ -523,7 +490,7 @@
   return SBOX_TEST_SUCCEEDED;
 }
 
-TEST(AppContainerLaunchTest, CreateTempFileNoFirewall) {
+TEST(AppContainerLaunchTest, CreateTempFile) {
   if (!features::IsAppContainerSandboxSupported()) {
     return;
   }
@@ -531,13 +498,13 @@
   std::wstring package_name = GenerateRandomPackageName();
   ASSERT_EQ(SBOX_ALL_OK,
             runner.GetPolicy()->GetConfig()->AddAppContainerProfile(
-                package_name.c_str(), ACProfileRegistration::kNoFirewall));
+                package_name.c_str()));
   EXPECT_EQ(SBOX_ALL_OK, runner.GetPolicy()->GetConfig()->SetTokenLevel(
                              USER_UNPROTECTED, USER_UNPROTECTED));
 
   EXPECT_EQ(SBOX_TEST_SUCCEEDED,
             runner.RunTest(L"CreateTempFileInAppContainer"));
-  EXPECT_TRUE(AppContainerBase::DeleteNoFirewall(package_name.c_str()));
+  EXPECT_TRUE(AppContainerBase::Delete(package_name.c_str()));
 }
 
 TEST(LowBoxTest, ChildProcessMitigationLowBox) {
diff --git a/sandbox/win/src/app_container_unittest.cc b/sandbox/win/src/app_container_unittest.cc
index 21d6d078..fd341c5 100644
--- a/sandbox/win/src/app_container_unittest.cc
+++ b/sandbox/win/src/app_container_unittest.cc
@@ -284,24 +284,14 @@
       ValidSecurityCapabilities(&two_capabilities, package_sid, capabilities));
 }
 
-// TODO(crbug/347547524): re-enable the tests once they are passing on
-// Windows ARM64.
-#if BUILDFLAG(IS_WIN) && defined(ARCH_CPU_ARM64)
-#define MAYBE_CreateAndDeleteAppContainerProfile \
-  DISABLED_CreateAndDeleteAppContainerProfile
-#else
-#define MAYBE_CreateAndDeleteAppContainerProfile \
-  CreateAndDeleteAppContainerProfile
-#endif
-TEST(AppContainerTest, MAYBE_CreateAndDeleteAppContainerProfile) {
+TEST(AppContainerTest, CreateAndDeleteAppContainerProfile) {
   if (!features::IsAppContainerSandboxSupported())
     return;
 
   std::wstring package_name = GenerateRandomPackageName();
   EXPECT_FALSE(ProfileExist(package_name));
   std::unique_ptr<AppContainerBase> profile_container =
-      AppContainerBase::CreateProfile(package_name.c_str(), L"Name",
-                                      L"Description");
+      AppContainerBase::CreateProfile(package_name.c_str(), L"Name");
   ASSERT_NE(nullptr, profile_container.get());
   EXPECT_TRUE(ProfileExist(package_name));
   CheckProfileDirectoryLayout(profile_container.get());
@@ -309,22 +299,14 @@
   EXPECT_FALSE(ProfileExist(package_name));
 }
 
-// TODO(crbug/347529039): re-enable the tests once they are passing on
-// Windows ARM64.
-#if BUILDFLAG(IS_WIN) && defined(ARCH_CPU_ARM64)
-#define MAYBE_CreateAndOpenAppContainer DISABLED_CreateAndOpenAppContainer
-#else
-#define MAYBE_CreateAndOpenAppContainer CreateAndOpenAppContainer
-#endif
-TEST(AppContainerTest, MAYBE_CreateAndOpenAppContainer) {
+TEST(AppContainerTest, CreateAndOpenAppContainer) {
   if (!features::IsAppContainerSandboxSupported())
     return;
 
   std::wstring package_name = GenerateRandomPackageName();
   EXPECT_FALSE(ProfileExist(package_name));
   std::unique_ptr<AppContainerBase> profile_container =
-      AppContainerBase::CreateProfile(package_name.c_str(), L"Name",
-                                      L"Description");
+      AppContainerBase::CreateProfile(package_name.c_str(), L"Name");
   ASSERT_NE(nullptr, profile_container.get());
   EXPECT_TRUE(ProfileExist(package_name));
   CheckProfileDirectoryLayout(profile_container.get());
@@ -340,34 +322,19 @@
   EXPECT_FALSE(ProfileExist(package_name));
 }
 
-TEST(AppContainerTest, CreateAndDeleteAppContainerProfileNoFirewall) {
-  if (!features::IsAppContainerSandboxSupported()) {
-    return;
-  }
-  std::wstring package_name = GenerateRandomPackageName();
-  EXPECT_FALSE(AppContainerBase::ProfileExists(package_name.c_str()));
-  std::unique_ptr<AppContainerBase> profile_container =
-      AppContainerBase::CreateProfileNoFirewall(package_name.c_str(), L"Name");
-  ASSERT_NE(nullptr, profile_container.get());
-  EXPECT_TRUE(AppContainerBase::ProfileExists(package_name.c_str()));
-  CheckProfileDirectoryLayout(profile_container.get());
-  EXPECT_TRUE(AppContainerBase::DeleteNoFirewall(package_name.c_str()));
-  EXPECT_FALSE(AppContainerBase::ProfileExists(package_name.c_str()));
-}
-
-TEST(AppContainerTest, ReOpenAppContainerProfileNoFirewall) {
+TEST(AppContainerTest, ReOpenAppContainerProfile) {
   if (!features::IsAppContainerSandboxSupported()) {
     return;
   }
   std::wstring package_name = GenerateRandomPackageName();
   EXPECT_FALSE(ProfileExist(package_name));
   std::unique_ptr<AppContainerBase> profile_container =
-      AppContainerBase::CreateProfileNoFirewall(package_name.c_str(), L"Name");
+      AppContainerBase::CreateProfile(package_name.c_str(), L"Name");
   ASSERT_NE(nullptr, profile_container.get());
   EXPECT_TRUE(ProfileExist(package_name));
   CheckProfileDirectoryLayout(profile_container.get());
   std::unique_ptr<AppContainerBase> open_container =
-      AppContainerBase::CreateProfileNoFirewall(package_name.c_str(), L"Name");
+      AppContainerBase::CreateProfile(package_name.c_str(), L"Name");
   ASSERT_NE(nullptr, open_container.get());
   EXPECT_EQ(profile_container->GetPackageSid(),
             open_container->GetPackageSid());
diff --git a/sandbox/win/src/sandbox_policy.h b/sandbox/win/src/sandbox_policy.h
index ae3aafd2..70c3179e 100644
--- a/sandbox/win/src/sandbox_policy.h
+++ b/sandbox/win/src/sandbox_policy.h
@@ -47,15 +47,6 @@
   kDisconnectCsrss,
 };
 
-// Specifies how to register an AppContainer profile if it doesn't already
-// exist.
-enum class ACProfileRegistration {
-  // Use the default registration.
-  kDefault,
-  // Create the profile without registering with the firewall.
-  kNoFirewall
-};
-
 // Policy configuration that can be shared over multiple targets of the same tag
 // (see BrokerServicesBase::CreatePolicy(tag)). Methods in TargetConfig will
 // only need to be called the first time a TargetPolicy object with a given tag
@@ -227,13 +218,9 @@
   virtual void SetLockdownDefaultDacl() = 0;
 
   // Configure policy to use an AppContainer profile. |package_name| is the
-  // name of the profile to use. Specifying kDefault for |registration| will
-  // use the default mechanism to register the profile if it doesn't already
-  // exist. Specifying kNoFirewall will create the profile without registering
-  // it with the firewall service which reduces system impact.
+  // name of the profile to use.
   [[nodiscard]] virtual ResultCode AddAppContainerProfile(
-      const wchar_t* package_name,
-      ACProfileRegistration registration) = 0;
+      const wchar_t* package_name) = 0;
 
   // Get the configured AppContainer. The returned object lasts only as long as
   // the containing TargetConfig.
diff --git a/sandbox/win/src/sandbox_policy_base.cc b/sandbox/win/src/sandbox_policy_base.cc
index 84092ea..4731c8f 100644
--- a/sandbox/win/src/sandbox_policy_base.cc
+++ b/sandbox/win/src/sandbox_policy_base.cc
@@ -357,9 +357,7 @@
   lockdown_default_dacl_ = true;
 }
 
-ResultCode ConfigBase::AddAppContainerProfile(
-    const wchar_t* package_name,
-    ACProfileRegistration registration) {
+ResultCode ConfigBase::AddAppContainerProfile(const wchar_t* package_name) {
   if (!features::IsAppContainerSandboxSupported())
     return SBOX_ERROR_UNSUPPORTED;
 
@@ -368,17 +366,8 @@
   if (app_container_ || integrity_level_ != INTEGRITY_LEVEL_LAST) {
     return SBOX_ERROR_BAD_PARAMS;
   }
-
-  switch (registration) {
-    case ACProfileRegistration::kDefault:
-      app_container_ = AppContainerBase::CreateProfile(
-          package_name, L"Chrome Sandbox", L"Profile for Chrome Sandbox");
-      break;
-    case ACProfileRegistration::kNoFirewall:
-      app_container_ = AppContainerBase::CreateProfileNoFirewall(
-          package_name, L"Chrome Sandbox");
-      break;
-  }
+  app_container_ =
+      AppContainerBase::CreateProfile(package_name, L"Chrome Sandbox");
 
   if (!app_container_)
     return SBOX_ERROR_CREATE_APPCONTAINER;
diff --git a/sandbox/win/src/sandbox_policy_base.h b/sandbox/win/src/sandbox_policy_base.h
index 1481dc33..daaff50 100644
--- a/sandbox/win/src/sandbox_policy_base.h
+++ b/sandbox/win/src/sandbox_policy_base.h
@@ -75,9 +75,7 @@
   MitigationFlags GetDelayedProcessMitigations() const override;
   void AddRestrictingRandomSid() override;
   void SetLockdownDefaultDacl() override;
-  ResultCode AddAppContainerProfile(
-      const wchar_t* package_name,
-      ACProfileRegistration registration) override;
+  ResultCode AddAppContainerProfile(const wchar_t* package_name) override;
   AppContainer* GetAppContainer() override;
   void AddKernelObjectToClose(HandleToClose handle_info) override;
   void SetDisconnectCsrss() override;
diff --git a/services/network/url_loader.cc b/services/network/url_loader.cc
index 7fb448f..84043fe 100644
--- a/services/network/url_loader.cc
+++ b/services/network/url_loader.cc
@@ -481,6 +481,18 @@
   return header_array;
 }
 
+bool IsMultiplexedConnection(const net::HttpResponseInfo& response_info) {
+  switch (net::HttpConnectionInfoToCoarse(response_info.connection_info)) {
+    case net::HttpConnectionInfoCoarse::kHTTP1:
+      return false;
+    case net::HttpConnectionInfoCoarse::kHTTP2:
+    case net::HttpConnectionInfoCoarse::kQUIC:
+      return true;
+    case net::HttpConnectionInfoCoarse::kOTHER:
+      return false;
+  }
+}
+
 }  // namespace
 
 URLLoader::MaybeSyncURLLoaderClient::MaybeSyncURLLoaderClient(
@@ -3016,10 +3028,7 @@
       "NetworkService", "Requests"};
 
   const net::HttpResponseInfo& response_info = url_request_->response_info();
-  net::HttpConnectionInfoCoarse connection_info =
-      net::HttpConnectionInfoToCoarse(response_info.connection_info);
-  if (connection_info == net::HttpConnectionInfoCoarse::kHTTP2 ||
-      connection_info == net::HttpConnectionInfoCoarse::kQUIC) {
+  if (IsMultiplexedConnection(response_info)) {
     histogram_prefix_pieces.push_back("Multiplexed");
   } else {
     histogram_prefix_pieces.push_back("Simple");
@@ -3068,6 +3077,16 @@
         return name;
       };
 
+  base::UmaHistogramCounts100000(make_histogram_name("TotalUrlSize"),
+                                 url_request_->url().spec().size());
+
+  // HTTP/2 and HTTP/3 requests don't separate request line from headers so no
+  // need to record header metrics separately.
+  if (!IsMultiplexedConnection(response_info)) {
+    base::UmaHistogramCounts100000(make_histogram_name("TotalHeadersSize"),
+                                   raw_request_headers_size_);
+  }
+
   // For HTTP/2 and HTTP/3 the request line is included in the headers, but
   // `raw_request_line_size_` is 0 for these requests, so we can add it
   // unconditionally for all requests.
diff --git a/services/webnn/coreml/graph_builder_coreml.cc b/services/webnn/coreml/graph_builder_coreml.cc
index 03b66a6..98a819c 100644
--- a/services/webnn/coreml/graph_builder_coreml.cc
+++ b/services/webnn/coreml/graph_builder_coreml.cc
@@ -733,6 +733,9 @@
        // corresponding BOOL type. See docs here:
        // https://apple.github.io/coremltools/source/coremltools.converters.mil.mil.ops.defs.html#coremltools.converters.mil.mil.ops.defs.iOS15.tensor_transformation.reshape
        /*reshape_input=*/kFloatsAndInt32,
+       // TODO(crbug.com/363544348): Implement ScatterND.
+       /*scatter_nd_input=*/{},
+       /*scatter_nd_indices=*/{},
        /*sigmoid_input=*/DataTypeConstraint::kFloat16To32,
        // Note that BOOL, INT16, and UINT16 is also supported by CoreML, but
        // WebNN does not have corresponding types. See docs here:
@@ -1008,6 +1011,7 @@
       case mojom::Operation::Tag::kLstmCell:
       case mojom::Operation::Tag::kPrelu:
       case mojom::Operation::Tag::kQuantizeLinear:
+      case mojom::Operation::Tag::kScatterNd:
       case mojom::Operation::Tag::kTile:
       case mojom::Operation::Tag::kTriangular:
         return NewNotSupportedError(NotSupportedOperatorError(*operation));
diff --git a/services/webnn/dml/context_impl_dml.cc b/services/webnn/dml/context_impl_dml.cc
index c7f7146..90ea3cd0 100644
--- a/services/webnn/dml/context_impl_dml.cc
+++ b/services/webnn/dml/context_impl_dml.cc
@@ -72,6 +72,10 @@
       OperandDataType::kFloat16, OperandDataType::kFloat32,
       OperandDataType::kInt8, OperandDataType::kInt32, OperandDataType::kInt64};
 
+  static constexpr SupportedDataTypes kInts8To32{
+      OperandDataType::kInt8, OperandDataType::kUint8, OperandDataType::kInt32,
+      OperandDataType::kUint32};
+
   static constexpr SupportedDataTypes kUint8To32{OperandDataType::kUint8,
                                                  OperandDataType::kUint32};
 
@@ -104,9 +108,9 @@
        /*conv2d_input=*/DataTypeConstraint::kFloat16To32,
        /*conv_transpose2d_input=*/DataTypeConstraint::kFloat16To32,
 
-       // DequantizeLinear is not implemented.
-       /*dequantize_linear_input=*/{},
-       /*dequantize_linear_scale=*/{},
+       // https://learn.microsoft.com/en-us/windows/win32/api/directml/ns-directml-dml_element_wise_dequantize_linear_operator_desc#tensor-support
+       /*dequantize_linear_input=*/kInts8To32,
+       /*dequantize_linear_scale=*/DataTypeConstraint::kFloat32,
 
        // https://learn.microsoft.com/en-us/windows/win32/api/directml/ns-directml-dml_element_wise_add_operator_desc#tensor-support
        /*add_input=*/kFloat16To32Ints32,
@@ -259,9 +263,9 @@
        // https://learn.microsoft.com/en-us/windows/win32/api/directml/ns-directml-dml_activation_parameterized_relu_operator_desc#tensor-support
        /*prelu_input=*/DataTypeConstraint::kFloat16To32,
 
-       // QuantizeLinear is not implemented.
-       /*quantize_linear_input=*/{},
-       /*quantize_linear_zero_point=*/{},
+       // https://learn.microsoft.com/en-us/windows/win32/api/directml/ns-directml-dml_element_wise_quantize_linear_operator_desc#tensor-support
+       /*quantize_linear_input=*/DataTypeConstraint::kFloat32,
+       /*quantize_linear_zero_point=*/DataTypeConstraint::kInts8,
 
        // https://learn.microsoft.com/en-us/windows/win32/api/directml/ns-directml-dml_reduce_operator_desc#tensor-support-according-to-function
        /*reduce_l1_input=*/DataTypeConstraint::kFloat16To32,
@@ -284,6 +288,10 @@
        // Reshape is emulated by identity.
        /*reshape_input=*/kFloat16To32Ints8To32,
 
+       // TODO(crbug.com/363761938): Implement ScatterND.
+       /*scatter_nd_input=*/{},
+       /*scatter_nd_indices=*/{},
+
        // https://learn.microsoft.com/en-us/windows/win32/api/directml/ns-directml-dml_activation_sigmoid_operator_desc#tensor-support
        /*sigmoid_input=*/DataTypeConstraint::kFloat16To32,
 
@@ -387,6 +395,10 @@
 
   if (feature_level >= DML_FEATURE_LEVEL_6_0) {
     properties.data_type_limits.div_input = SupportedDataTypes::All();
+    properties.data_type_limits.dequantize_linear_scale =
+        DataTypeConstraint::kFloat16To32;
+    properties.data_type_limits.quantize_linear_input =
+        DataTypeConstraint::kFloat16To32;
   }
 
   if (feature_level >= DML_FEATURE_LEVEL_6_2) {
diff --git a/services/webnn/dml/graph_impl_dml.cc b/services/webnn/dml/graph_impl_dml.cc
index 1372c89e..fdc1549e 100644
--- a/services/webnn/dml/graph_impl_dml.cc
+++ b/services/webnn/dml/graph_impl_dml.cc
@@ -1054,6 +1054,13 @@
       output_ids = {reshape->output_operand_id};
       break;
     }
+    case Operation::Tag::kScatterNd: {
+      const auto& scatter_nd = operation->get_scatter_nd();
+      input_ids = {scatter_nd->input_operand_id, scatter_nd->indices_operand_id,
+                   scatter_nd->updates_operand_id};
+      output_ids = {scatter_nd->output_operand_id};
+      break;
+    }
     case Operation::Tag::kSigmoid: {
       const auto& sigmoid = operation->get_sigmoid();
       input_ids = {sigmoid->input_operand_id};
@@ -1736,6 +1743,70 @@
                                           inputs, label);
 }
 
+template <typename DML_OPERATOR_DESC, typename DequantizeOrQuantizeLinearPtr>
+  requires(
+      std::is_same_v<DequantizeOrQuantizeLinearPtr,
+                     mojom::DequantizeLinearPtr> ||
+      std::is_same_v<DequantizeOrQuantizeLinearPtr, mojom::QuantizeLinearPtr>)
+void CreateOperatorNodeForDequantizeOrQuantizeLinear(
+    const ContextProperties& context_properties,
+    const IdToOperandMap& id_to_operand_map,
+    const DequantizeOrQuantizeLinearPtr& operation_ptr,
+    GraphBuilderDml& graph_builder,
+    DML_OPERATOR_TYPE operator_type,
+    IdToNodeOutputMap& id_to_node_output_map) {
+  const NodeOutput* input = GetNodeOutputForOperand(
+      id_to_node_output_map, operation_ptr->input_operand_id);
+  const auto& input_tensor_desc = input->GetTensorDesc();
+
+  const NodeOutput* scale = GetNodeOutputForOperand(
+      id_to_node_output_map, operation_ptr->scale_operand_id);
+  auto scale_tensor_desc = scale->GetTensorDesc();
+
+  const NodeOutput* zero_point = GetNodeOutputForOperand(
+      id_to_node_output_map, operation_ptr->zero_point_operand_id);
+  auto zero_point_tensor_desc = zero_point->GetTensorDesc();
+
+  uint64_t output_id = operation_ptr->output_operand_id;
+  const auto output_tensor_desc =
+      CreateOutputTensorDesc(id_to_operand_map, output_id);
+
+  const auto& output_dimensions = output_tensor_desc.GetDimensions();
+  if (scale_tensor_desc.GetDimensions() != output_dimensions) {
+    scale_tensor_desc.BroadcastTo(output_dimensions);
+  }
+  if (zero_point_tensor_desc.GetDimensions() != output_dimensions) {
+    zero_point_tensor_desc.BroadcastTo(output_dimensions);
+  }
+
+  if constexpr (std::is_same_v<DequantizeOrQuantizeLinearPtr,
+                               mojom::DequantizeLinearPtr>) {
+    CHECK(context_properties.data_type_limits.dequantize_linear_input.Has(
+        DmlDataTypeToOperand(input_tensor_desc.GetDataType())));
+    CHECK(context_properties.data_type_limits.dequantize_linear_scale.Has(
+        DmlDataTypeToOperand(scale_tensor_desc.GetDataType())));
+  } else /* `DequantizeOrQuantizeLinearPtr` is `mojom::QuantizeLinearPtr` */ {
+    CHECK(context_properties.data_type_limits.quantize_linear_input.Has(
+        DmlDataTypeToOperand(input_tensor_desc.GetDataType())));
+    CHECK(context_properties.data_type_limits.quantize_linear_zero_point.Has(
+        DmlDataTypeToOperand(zero_point_tensor_desc.GetDataType())));
+  }
+
+  DML_OPERATOR_DESC operator_desc{
+      .InputTensor = &input_tensor_desc.GetDMLTensorDesc(),
+      .ScaleTensor = &scale_tensor_desc.GetDMLTensorDesc(),
+      .ZeroPointTensor = &zero_point_tensor_desc.GetDMLTensorDesc(),
+      .OutputTensor = &output_tensor_desc.GetDMLTensorDesc()};
+  const std::string& label = operation_ptr->label;
+  std::array<const NodeOutput*, 3> inputs = {input, scale, zero_point};
+  const OperatorNode* operator_node = graph_builder.CreateOperatorNode(
+      operator_type, &operator_desc, inputs, label);
+  const NodeOutput* node_output = graph_builder.CreateNodeOutput(
+      operator_node, std::move(output_tensor_desc));
+  // The output id must be unique in the map.
+  CHECK(id_to_node_output_map.try_emplace(output_id, node_output).second);
+}
+
 void CreateOperatorNodeForBinary(
     const ContextProperties& context_properties,
     const IdToOperandMap& id_to_operand_map,
@@ -5706,6 +5777,14 @@
             graph_builder, id_to_node_output_map);
         break;
       }
+      case Operation::Tag::kDequantizeLinear: {
+        CreateOperatorNodeForDequantizeOrQuantizeLinear<
+            DML_ELEMENT_WISE_DEQUANTIZE_LINEAR_OPERATOR_DESC>(
+            context_properties, id_to_operand_map,
+            operation->get_dequantize_linear(), graph_builder,
+            DML_OPERATOR_ELEMENT_WISE_DEQUANTIZE_LINEAR, id_to_node_output_map);
+        break;
+      }
       case mojom::Operation::Tag::kElementWiseBinary: {
         CreateOperatorNodeForBinary(
             context_properties, id_to_operand_map, operation.get(),
@@ -5872,6 +5951,14 @@
                                    id_to_node_output_map);
         break;
       }
+      case Operation::Tag::kQuantizeLinear: {
+        CreateOperatorNodeForDequantizeOrQuantizeLinear<
+            DML_ELEMENT_WISE_QUANTIZE_LINEAR_OPERATOR_DESC>(
+            context_properties, id_to_operand_map,
+            operation->get_quantize_linear(), graph_builder,
+            DML_OPERATOR_ELEMENT_WISE_QUANTIZE_LINEAR, id_to_node_output_map);
+        break;
+      }
       case Operation::Tag::kReduce: {
         CreateOperatorNodeForReduce(context_properties, id_to_operand_map,
                                     operation->get_reduce(), graph_builder,
diff --git a/services/webnn/public/cpp/data_type_limits.cc b/services/webnn/public/cpp/data_type_limits.cc
index a663d0db..ea7e29a 100644
--- a/services/webnn/public/cpp/data_type_limits.cc
+++ b/services/webnn/public/cpp/data_type_limits.cc
@@ -87,6 +87,8 @@
                                SupportedDataTypes relu_input,
                                SupportedDataTypes resample2d_input,
                                SupportedDataTypes reshape_input,
+                               SupportedDataTypes scatter_nd_input,
+                               SupportedDataTypes scatter_nd_indices,
                                SupportedDataTypes sigmoid_input,
                                SupportedDataTypes slice_input,
                                SupportedDataTypes softmax_input,
@@ -178,6 +180,8 @@
       relu_input(relu_input),
       resample2d_input(resample2d_input),
       reshape_input(reshape_input),
+      scatter_nd_input(scatter_nd_input),
+      scatter_nd_indices(scatter_nd_indices),
       sigmoid_input(sigmoid_input),
       slice_input(slice_input),
       softmax_input(softmax_input),
diff --git a/services/webnn/public/cpp/data_type_limits.h b/services/webnn/public/cpp/data_type_limits.h
index 30f4a0d..359651d 100644
--- a/services/webnn/public/cpp/data_type_limits.h
+++ b/services/webnn/public/cpp/data_type_limits.h
@@ -92,6 +92,8 @@
                  SupportedDataTypes relu_input,
                  SupportedDataTypes resample2d_input,
                  SupportedDataTypes reshape_input,
+                 SupportedDataTypes scatter_nd_input,
+                 SupportedDataTypes scatter_nd_indices,
                  SupportedDataTypes sigmoid_input,
                  SupportedDataTypes slice_input,
                  SupportedDataTypes softmax_input,
@@ -194,6 +196,8 @@
   SupportedDataTypes relu_input;
   SupportedDataTypes resample2d_input;
   SupportedDataTypes reshape_input;
+  SupportedDataTypes scatter_nd_input;
+  SupportedDataTypes scatter_nd_indices;
   SupportedDataTypes sigmoid_input;
   SupportedDataTypes slice_input;
   SupportedDataTypes softmax_input;
@@ -289,6 +293,8 @@
          lhs.relu_input == rhs.relu_input &&
          lhs.resample2d_input == rhs.resample2d_input &&
          lhs.reshape_input == rhs.reshape_input &&
+         lhs.scatter_nd_input == rhs.scatter_nd_input &&
+         lhs.scatter_nd_indices == rhs.scatter_nd_indices &&
          lhs.sigmoid_input == rhs.sigmoid_input &&
          lhs.slice_input == rhs.slice_input &&
          lhs.softmax_input == rhs.softmax_input &&
diff --git a/services/webnn/public/cpp/graph_validation_utils.cc b/services/webnn/public/cpp/graph_validation_utils.cc
index 5b53f17..8ca3f8ce 100644
--- a/services/webnn/public/cpp/graph_validation_utils.cc
+++ b/services/webnn/public/cpp/graph_validation_utils.cc
@@ -2413,6 +2413,83 @@
   return OperandDescriptor::Create(input.data_type(), output_shape);
 }
 
+base::expected<OperandDescriptor, std::string> ValidateScatterNDAndInferOutput(
+    const ContextProperties& context_properties,
+    const OperandDescriptor& input,
+    const OperandDescriptor& indices,
+    const OperandDescriptor& updates,
+    std::string_view label) {
+  if (!context_properties.data_type_limits.scatter_nd_input.Has(
+          input.data_type())) {
+    return base::unexpected(ErrorWithLabel(
+        label, NotSupportedInputArgumentTypeError(
+                   input.data_type(),
+                   context_properties.data_type_limits.scatter_nd_input)));
+  }
+
+  static constexpr char kIndicesParam[] = "indices";
+  if (!context_properties.data_type_limits.scatter_nd_indices.Has(
+          indices.data_type())) {
+    return base::unexpected(ErrorWithLabel(
+        label, NotSupportedArgumentTypeError(
+                   kIndicesParam, indices.data_type(),
+                   context_properties.data_type_limits.scatter_nd_indices)));
+  }
+
+  // Updates tensor's data type should be the same as input's.
+  if (input.data_type() != updates.data_type()) {
+    return base::unexpected(
+        ErrorWithLabel(label,
+                       "The updates tensor data type should be the same as "
+                       "input data type."));
+  }
+
+  if (input.Rank() == 0) {
+    return base::unexpected(
+        ErrorWithLabel(label, "The input should not be a scalar."));
+  }
+
+  if (indices.Rank() == 0) {
+    return base::unexpected(
+        ErrorWithLabel(label, "The indices should not be a scalar."));
+  }
+
+  const uint32_t indices_last_dim_size = indices.shape()[indices.Rank() - 1];
+  if (indices_last_dim_size > input.Rank()) {
+    return base::unexpected(ErrorWithLabel(
+        label, base::StringPrintf(
+                   "The size of the last dimension of indices tensor (%u)"
+                   "should not be greater than input rank (%u).",
+                   indices_last_dim_size, input.Rank())));
+  }
+
+  // Validate `updates.shape` =
+  // `indices.shape[:-1]` + `input.shape[indices.shape[-1]:]`, where `+` denotes
+  // the concatenation of shapes.
+  auto checked_updates_rank = base::MakeCheckedNum<uint32_t>(indices.Rank()) -
+                              1 + input.Rank() - indices_last_dim_size;
+  if (!checked_updates_rank.IsValid()) {
+    return base::unexpected(
+        ErrorWithLabel(label, "The expected updates rank is too large."));
+  }
+
+  std::vector<uint32_t> expected_updates_shape;
+  expected_updates_shape.reserve(checked_updates_rank.ValueOrDie());
+  base::ranges::copy(indices.shape().begin(), indices.shape().end() - 1,
+                     std::back_inserter(expected_updates_shape));
+  base::ranges::copy(input.shape().begin() + indices_last_dim_size,
+                     input.shape().end(),
+                     std::back_inserter(expected_updates_shape));
+
+  if (expected_updates_shape != updates.shape()) {
+    return base::unexpected(
+        ErrorWithLabel(label, "The updates tensor shape is invalid."));
+  }
+
+  // The output tensor has the same data type and shape as input's.
+  return input;
+}
+
 base::expected<OperandDescriptor, std::string> ValidateTriangularAndInferOutput(
     const ContextProperties& context_properties,
     const OperandDescriptor& input,
diff --git a/services/webnn/public/cpp/graph_validation_utils.h b/services/webnn/public/cpp/graph_validation_utils.h
index c241174..15cc45b 100644
--- a/services/webnn/public/cpp/graph_validation_utils.h
+++ b/services/webnn/public/cpp/graph_validation_utils.h
@@ -666,6 +666,16 @@
                                  base::span<const uint32_t> axes,
                                  bool keepDimensions = false);
 
+// Validate and infer output information of scatterND operator defined in
+// WebIDL here https://www.w3.org/TR/webnn/#api-mlgraphbuilder-scatternd
+base::expected<OperandDescriptor, std::string> COMPONENT_EXPORT(
+    WEBNN_PUBLIC_CPP)
+    ValidateScatterNDAndInferOutput(const ContextProperties& context_properties,
+                                    const OperandDescriptor& input,
+                                    const OperandDescriptor& indices,
+                                    const OperandDescriptor& updates,
+                                    std::string_view label);
+
 // Validate triangular operator defined in WebIDL here:
 // https://www.w3.org/TR/webnn/#api-mlgraphbuilder-triangular.
 base::expected<OperandDescriptor, std::string> COMPONENT_EXPORT(
diff --git a/services/webnn/public/cpp/supported_data_types.h b/services/webnn/public/cpp/supported_data_types.h
index e78a9ac..6632884 100644
--- a/services/webnn/public/cpp/supported_data_types.h
+++ b/services/webnn/public/cpp/supported_data_types.h
@@ -42,7 +42,7 @@
     OperandDataType::kInt32,   OperandDataType::kUint32,
     OperandDataType::kInt64,   OperandDataType::kUint64};
 
-static constexpr SupportedDataTypes kGatherIndicesSupportedDataTypes = {
+static constexpr SupportedDataTypes kGatherScatterIndicesSupportedDataTypes = {
     OperandDataType::kInt32, OperandDataType::kUint32, OperandDataType::kInt64};
 
 }  // namespace DataTypeConstraint
diff --git a/services/webnn/public/cpp/webnn_errors.h b/services/webnn/public/cpp/webnn_errors.h
index f0e9761..34a15ba 100644
--- a/services/webnn/public/cpp/webnn_errors.h
+++ b/services/webnn/public/cpp/webnn_errors.h
@@ -43,6 +43,7 @@
 inline constexpr char kRelu[] = "relu";
 inline constexpr char kResample2d[] = "resample2d";
 inline constexpr char kReshape[] = "reshape";
+inline constexpr char kScatterND[] = "scatterND";
 inline constexpr char kSigmoid[] = "sigmoid";
 inline constexpr char kSlice[] = "slice";
 inline constexpr char kSoftmax[] = "softmax";
diff --git a/services/webnn/public/mojom/context_properties_mojom_traits_unittest.cc b/services/webnn/public/mojom/context_properties_mojom_traits_unittest.cc
index 1464526..aae66861 100644
--- a/services/webnn/public/mojom/context_properties_mojom_traits_unittest.cc
+++ b/services/webnn/public/mojom/context_properties_mojom_traits_unittest.cc
@@ -92,6 +92,8 @@
        webnn::SupportedDataTypes::All(),
        webnn::SupportedDataTypes::All(),
        webnn::SupportedDataTypes::All(),
+       {webnn::OperandDataType::kFloat16, webnn::OperandDataType::kFloat32},
+       {webnn::OperandDataType::kInt32, webnn::OperandDataType::kUint32},
        webnn::SupportedDataTypes::All(),
        webnn::SupportedDataTypes::All(),
        {webnn::OperandDataType::kFloat16, webnn::OperandDataType::kUint8},
@@ -112,7 +114,7 @@
        {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {},
        {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {},
        {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {},
-       {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}});
+       {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}});
 
   EXPECT_TRUE(
       mojo::test::SerializeAndDeserialize<webnn::mojom::ContextProperties>(
diff --git a/services/webnn/public/mojom/data_type_limits_mojom_traits.h b/services/webnn/public/mojom/data_type_limits_mojom_traits.h
index 5c173f2..7e4873c1 100644
--- a/services/webnn/public/mojom/data_type_limits_mojom_traits.h
+++ b/services/webnn/public/mojom/data_type_limits_mojom_traits.h
@@ -330,6 +330,14 @@
       const webnn::DataTypeLimits& data_type_limits) {
     return data_type_limits.reshape_input;
   }
+  static webnn::SupportedDataTypes scatter_nd_input(
+      const webnn::DataTypeLimits& data_type_limits) {
+    return data_type_limits.scatter_nd_input;
+  }
+  static webnn::SupportedDataTypes scatter_nd_indices(
+      const webnn::DataTypeLimits& data_type_limits) {
+    return data_type_limits.scatter_nd_indices;
+  }
   static webnn::SupportedDataTypes sigmoid_input(
       const webnn::DataTypeLimits& data_type_limits) {
     return data_type_limits.sigmoid_input;
@@ -460,6 +468,8 @@
            data.ReadReluInput(&out->relu_input) &&
            data.ReadResample2dInput(&out->resample2d_input) &&
            data.ReadReshapeInput(&out->reshape_input) &&
+           data.ReadScatterNdInput(&out->scatter_nd_input) &&
+           data.ReadScatterNdIndices(&out->scatter_nd_indices) &&
            data.ReadSigmoidInput(&out->sigmoid_input) &&
            data.ReadSliceInput(&out->slice_input) &&
            data.ReadSoftmaxInput(&out->softmax_input) &&
diff --git a/services/webnn/public/mojom/webnn_context_properties.mojom b/services/webnn/public/mojom/webnn_context_properties.mojom
index 2885004..c281f5a 100644
--- a/services/webnn/public/mojom/webnn_context_properties.mojom
+++ b/services/webnn/public/mojom/webnn_context_properties.mojom
@@ -143,6 +143,11 @@
   SupportedDataTypes relu_input;
   SupportedDataTypes resample2d_input;
   SupportedDataTypes reshape_input;
+
+  // ScatterND.
+  SupportedDataTypes scatter_nd_input;
+  SupportedDataTypes scatter_nd_indices;
+
   SupportedDataTypes sigmoid_input;
   SupportedDataTypes slice_input;
   SupportedDataTypes softmax_input;
diff --git a/services/webnn/public/mojom/webnn_graph.mojom b/services/webnn/public/mojom/webnn_graph.mojom
index fc0b281..d433c3a 100644
--- a/services/webnn/public/mojom/webnn_graph.mojom
+++ b/services/webnn/public/mojom/webnn_graph.mojom
@@ -955,6 +955,72 @@
   string label;
 };
 
+// Represents ScatterND operation that first copies the values of `input` to
+// `output` tensor, and then overwrites the values of `output` tensor to values
+// specified
+// by `updates` tensor at specific index positions specified by `indices`
+// tensor.
+//
+// Its calculation follows the pseudocode:
+// ```
+// output = input
+// // Let `q` denote the rank of `indices` tensor.
+// output[indices[i_{0}, ..., i_{q-2}]] = updates[i_{0}, ..., i_{q-2}]
+// ```
+//
+// The last dimension of `indices` tensor corresponds to indices of elements (if
+// `indices.shape[-1]` == `output.rank`) or slices (if `indices.shape[-1]` <
+// `output.rank`) along dimension `indices.shape[-1]` of `output.shape`.
+// The index value for `i`th dimension (0 <= `i` < `indices.shape[-1]`) must be
+// within the bounds [`-output.shape[i]`, `output.shape[i]` - 1] and a negative
+// index means indexing from the end of the dimension.
+//
+// This operation expects the tensors rank and shape as follows:
+// `input.rank` >= 1.
+// `indices.rank` >= 1, where `indices.shape[-1]` <= `input.rank`.
+// `updates.shape` = `indices.shape[:-1]` + `input.shape[indices.shape[-1]:]`,
+// where `+` denotes the concatenation of shapes.
+// `output.shape` == `input.shape`.
+//
+// Example 1: Insert individual elements in a tensor by index
+// data    = [1, 2, 3, 4, 5, 6, 7, 8]
+// indices = [[4], [3], [1], [7]]
+// updates = [9, 10, 11, 12]
+// output  = [1, 11, 3, 10, 9, 6, 7, 12]
+//
+// Example 2: Insert entire slices of a higher rank tensor
+// data    = [[[1, 2, 3, 4], [5, 6, 7, 8], [8, 7, 6, 5], [4, 3, 2, 1]],
+//            [[1, 2, 3, 4], [5, 6, 7, 8], [8, 7, 6, 5], [4, 3, 2, 1]],
+//            [[8, 7, 6, 5], [4, 3, 2, 1], [1, 2, 3, 4], [5, 6, 7, 8]],
+//            [[8, 7, 6, 5], [4, 3, 2, 1], [1, 2, 3, 4], [5, 6, 7, 8]]]
+// indices = [[0], [2]]
+// updates = [[[5, 5, 5, 5], [6, 6, 6, 6], [7, 7, 7, 7], [8, 8, 8, 8]],
+//             [[1, 1, 1, 1], [2, 2, 2, 2], [3, 3, 3, 3], [4, 4, 4, 4]]]
+// output  = [[[5, 5, 5, 5], [6, 6, 6, 6], [7, 7, 7, 7], [8, 8, 8, 8]],
+//            [[1, 2, 3, 4], [5, 6, 7, 8], [8, 7, 6, 5], [4, 3, 2, 1]],
+//            [[1, 1, 1, 1], [2, 2, 2, 2], [3, 3, 3, 3], [4, 4, 4, 4]],
+//            [[8, 7, 6, 5], [4, 3, 2, 1], [1, 2, 3, 4], [5, 6, 7, 8]]]
+//
+// The values of `indices` tensor aren't known until graph execution, and may
+// cause out-of-bounds write issue. A backend implementation must guarantee the
+// index values do not cause invalid writes outside the output tensor, either by
+// the platform API (e.g. DML) or by introducing a `clamp` operator in the
+// compiled graph.
+// The out-of-bounds `indices` handling is being discussed in WG:
+// https://github.com/webmachinelearning/webnn/issues/486
+struct ScatterND {
+  // The operand id is used to get the `Operand` description from
+  // `GraphInfo.id_to_operand_map`.
+  // The `input`, `indices` and `updates` are scatterND operator input operands.
+  // Their id must be distinct from the output operand id.
+  uint64 input_operand_id;
+  uint64 indices_operand_id;
+  uint64 updates_operand_id;
+  uint64 output_operand_id;
+  // User defined label from MLOperatorOptions.
+  string label;
+};
+
 // Corresponds to `MLOperand sigmoid(MLOperand x)` that compute the sigmoid
 // function of the input tensor following the expression 1 / (exp(-x) + 1).
 struct Sigmoid {
@@ -1182,6 +1248,7 @@
   Relu relu;
   Resample2d resample2d;
   Reshape reshape;
+  ScatterND scatter_nd;
   Sigmoid sigmoid;
   Slice slice;
   Softmax softmax;
diff --git a/services/webnn/tflite/graph_builder_tflite.cc b/services/webnn/tflite/graph_builder_tflite.cc
index 9749636..8458f8e 100644
--- a/services/webnn/tflite/graph_builder_tflite.cc
+++ b/services/webnn/tflite/graph_builder_tflite.cc
@@ -380,7 +380,8 @@
        /*elu_input=*/kFloat32AndInt8,
        /*expand_input=*/kFloat32AndInts8To32AndInt64,
        /*gather_input=*/kFloat32AndInt8To64AndUint8,
-       /*gather_indices=*/DataTypeConstraint::kGatherIndicesSupportedDataTypes,
+       /*gather_indices=*/
+       DataTypeConstraint::kGatherScatterIndicesSupportedDataTypes,
        // GatherElements is not implemented.
        /*gather_elements_input=*/{},
        /*gather_elements_indices=*/{},
@@ -424,6 +425,9 @@
        /*relu_input=*/kFloat32,
        /*resample2d_input=*/kFloat32,
        /*reshape_input=*/SupportedDataTypes::All(),
+       // TODO(crbug.com/363677532): Implement scatterND.
+       /*scatter_nd_input=*/{},
+       /*scatter_nd_indices=*/{},
        /*sigmoid_input=*/kFloat32,
        /*slice_input=*/kFloat32AndInts8To32AndInt64,
        /*softmax_input=*/kFloat32,
@@ -658,6 +662,7 @@
       operator_offset = SerializeWhere(*op.get_where());
       break;
     case mojom::Operation::Tag::kGatherElements:
+    case mojom::Operation::Tag::kScatterNd:
       return base::unexpected(NotSupportedOperatorError(op));
   }
   operators_.emplace_back(operator_offset);
diff --git a/services/webnn/webnn_context_impl.cc b/services/webnn/webnn_context_impl.cc
index 06c2f65..ca507afa 100644
--- a/services/webnn/webnn_context_impl.cc
+++ b/services/webnn/webnn_context_impl.cc
@@ -186,9 +186,9 @@
   backend_context_properties.data_type_limits.elu_input.RetainAll(
       DataTypeConstraint::kFloat16To32);
   backend_context_properties.data_type_limits.gather_indices.RetainAll(
-      DataTypeConstraint::kGatherIndicesSupportedDataTypes);
+      DataTypeConstraint::kGatherScatterIndicesSupportedDataTypes);
   backend_context_properties.data_type_limits.gather_elements_indices.RetainAll(
-      DataTypeConstraint::kGatherIndicesSupportedDataTypes);
+      DataTypeConstraint::kGatherScatterIndicesSupportedDataTypes);
   backend_context_properties.data_type_limits.gelu_input.RetainAll(
       DataTypeConstraint::kFloat16To32);
   backend_context_properties.data_type_limits.gemm_input.RetainAll(
@@ -245,6 +245,8 @@
       DataTypeConstraint::kFloat16To32Int8To32);
   backend_context_properties.data_type_limits.resample2d_input.RetainAll(
       DataTypeConstraint::kFloat16To32);
+  backend_context_properties.data_type_limits.scatter_nd_indices.RetainAll(
+      DataTypeConstraint::kGatherScatterIndicesSupportedDataTypes);
   backend_context_properties.data_type_limits.sigmoid_input.RetainAll(
       DataTypeConstraint::kFloat16To32);
   backend_context_properties.data_type_limits.softmax_input.RetainAll(
diff --git a/services/webnn/webnn_graph_builder_impl.cc b/services/webnn/webnn_graph_builder_impl.cc
index 1fdcce6..3e943ad 100644
--- a/services/webnn/webnn_graph_builder_impl.cc
+++ b/services/webnn/webnn_graph_builder_impl.cc
@@ -1857,6 +1857,42 @@
   return true;
 }
 
+bool ValidateScatterND(const ContextProperties& context_properties,
+                       const IdToOperandMap& id_to_operand_map,
+                       const mojom::ScatterND& scatter_nd,
+                       base::flat_set<uint64_t>& processed_operands) {
+  if (!processed_operands.contains(scatter_nd.input_operand_id) ||
+      !processed_operands.contains(scatter_nd.indices_operand_id) ||
+      !processed_operands.contains(scatter_nd.updates_operand_id)) {
+    return false;
+  }
+  processed_operands.insert(scatter_nd.output_operand_id);
+
+  auto* input = GetMojoOperand(id_to_operand_map, scatter_nd.input_operand_id);
+  auto* indices =
+      GetMojoOperand(id_to_operand_map, scatter_nd.indices_operand_id);
+  auto* updates =
+      GetMojoOperand(id_to_operand_map, scatter_nd.updates_operand_id);
+  auto* output =
+      GetMojoOperand(id_to_operand_map, scatter_nd.output_operand_id);
+  if (!input || !indices || !updates || !output || output == input ||
+      output == indices || output == updates) {
+    return false;
+  }
+
+  auto validated_output = ValidateScatterNDAndInferOutput(
+      context_properties, input->descriptor, indices->descriptor,
+      updates->descriptor, scatter_nd.label);
+  if (!validated_output.has_value()) {
+    return false;
+  }
+  if (validated_output != output->descriptor) {
+    return false;
+  }
+
+  return true;
+}
+
 bool ValidateSlice(const ContextProperties& context_properties,
                    const IdToOperandMap& id_to_operand_map,
                    const mojom::Slice& slice,
@@ -2237,6 +2273,9 @@
       return ValidateUnaryOperation(
           id_to_operand_map, *operation.get_relu(),
           context_properties.data_type_limits.relu_input, processed_operands);
+    case mojom::Operation::Tag::kScatterNd:
+      return ValidateScatterND(context_properties, id_to_operand_map,
+                               *operation.get_scatter_nd(), processed_operands);
     case mojom::Operation::Tag::kSlice:
       return ValidateSlice(context_properties, id_to_operand_map,
                            *operation.get_slice(), processed_operands);
diff --git a/services/webnn/webnn_graph_impl_unittest.cc b/services/webnn/webnn_graph_impl_unittest.cc
index d69d5c59..01f7d40 100644
--- a/services/webnn/webnn_graph_impl_unittest.cc
+++ b/services/webnn/webnn_graph_impl_unittest.cc
@@ -5824,6 +5824,137 @@
         .Test();
   }
 }
+
+struct ScatterNDTester {
+  OperandInfo input;
+  OperandInfo indices;
+  OperandInfo updates;
+  OperandInfo output;
+  bool expected;
+
+  void Test() {
+    auto context_properties = GetContextPropertiesForTesting();
+
+    // Build the graph with mojo type.
+    GraphInfoBuilder builder;
+    uint64_t input_operand_id =
+        builder.BuildInput("input", input.dimensions, input.type);
+    uint64_t indices_operand_id =
+        builder.BuildInput("indices", indices.dimensions, indices.type);
+    uint64_t updates_operand_id =
+        builder.BuildInput("updates", updates.dimensions, updates.type);
+    uint64_t output_operand_id =
+        builder.BuildOutput("output", output.dimensions, output.type);
+    builder.BuildScatterND(input_operand_id, indices_operand_id,
+                           updates_operand_id, output_operand_id);
+    EXPECT_EQ(WebNNGraphBuilderImpl::IsValidForTesting(context_properties,
+                                                       builder.GetGraphInfo()),
+              expected);
+  }
+};
+
+TEST_F(WebNNGraphImplTest, ScatterNDTest) {
+  {
+    // Test a valid scatterND with 3-D input, 2-D indices and 3-D updates.
+    ScatterNDTester{
+        .input = {.type = OperandDataType::kFloat32, .dimensions = {4, 4, 4}},
+        .indices = {.type = OperandDataType::kUint32, .dimensions = {2, 1}},
+        .updates = {.type = OperandDataType::kFloat32, .dimensions = {2, 4, 4}},
+        .output = {.type = OperandDataType::kFloat32, .dimensions = {4, 4, 4}},
+        .expected = true}
+        .Test();
+  }
+  {
+    // Test an invalid scatterND that the updates tensor data type is not the
+    // same as input data type.
+    ScatterNDTester{
+        .input = {.type = OperandDataType::kFloat32, .dimensions = {4, 4, 4}},
+        .indices = {.type = OperandDataType::kUint32, .dimensions = {2, 1}},
+        .updates = {.type = OperandDataType::kFloat16, .dimensions = {2, 4, 4}},
+        .output = {.type = OperandDataType::kFloat32, .dimensions = {4, 4, 4}},
+        .expected = false}
+        .Test();
+  }
+  {
+    // Test an invalid scatterND with scalar input tensor.
+    ScatterNDTester{
+        .input = {.type = OperandDataType::kFloat32, .dimensions = {}},
+        .indices = {.type = OperandDataType::kUint32, .dimensions = {2, 1}},
+        .updates = {.type = OperandDataType::kFloat32, .dimensions = {2, 4, 4}},
+        .output = {.type = OperandDataType::kFloat32, .dimensions = {4, 4, 4}},
+        .expected = false}
+        .Test();
+  }
+  {
+    // Test an invalid scatterND with scalar indices tensor.
+    ScatterNDTester{
+        .input = {.type = OperandDataType::kFloat32, .dimensions = {4, 4, 4}},
+        .indices = {.type = OperandDataType::kUint32, .dimensions = {}},
+        .updates = {.type = OperandDataType::kFloat32, .dimensions = {2, 4, 4}},
+        .output = {.type = OperandDataType::kFloat32, .dimensions = {4, 4, 4}},
+        .expected = false}
+        .Test();
+  }
+  {
+    // Test an invalid scatterND that the size of last dimension of indices
+    // tensor is greater than input rank.
+    ScatterNDTester{
+        .input = {.type = OperandDataType::kFloat32, .dimensions = {4, 4, 4}},
+        .indices = {.type = OperandDataType::kUint32, .dimensions = {2, 4}},
+        .updates = {.type = OperandDataType::kFloat32, .dimensions = {2, 4, 4}},
+        .output = {.type = OperandDataType::kFloat32, .dimensions = {4, 4, 4}},
+        .expected = false}
+        .Test();
+  }
+  {
+    // Test an invalid scatterND whose updates tensor shape is invalid.
+    ScatterNDTester{
+        .input = {.type = OperandDataType::kFloat32, .dimensions = {4, 4, 4}},
+        .indices = {.type = OperandDataType::kUint32, .dimensions = {2, 1}},
+        // Updates tensor shape should be [2, 4, 4].
+        .updates = {.type = OperandDataType::kFloat32, .dimensions = {2, 3, 4}},
+        .output = {.type = OperandDataType::kFloat32, .dimensions = {4, 4, 4}},
+        .expected = false}
+        .Test();
+  }
+  {
+    // Test an invalid scatterND whose output shape is not the same as input.
+    ScatterNDTester{
+        .input = {.type = OperandDataType::kFloat32, .dimensions = {4, 4, 4}},
+        .indices = {.type = OperandDataType::kUint32, .dimensions = {2, 1}},
+        .updates = {.type = OperandDataType::kFloat32, .dimensions = {2, 4, 4}},
+        .output = {.type = OperandDataType::kFloat32, .dimensions = {2, 4, 4}},
+        .expected = false}
+        .Test();
+  }
+  {
+    // Test an invalid scatterND whose output data type is not the same as
+    // input.
+    ScatterNDTester{
+        .input = {.type = OperandDataType::kFloat32, .dimensions = {4, 4, 4}},
+        .indices = {.type = OperandDataType::kUint32, .dimensions = {2, 1}},
+        .updates = {.type = OperandDataType::kFloat32, .dimensions = {2, 4, 4}},
+        .output = {.type = OperandDataType::kFloat16, .dimensions = {4, 4, 4}},
+        .expected = false}
+        .Test();
+  }
+  {
+    // Test an invalid scatterND where the output is the same as the input.
+    auto context_properties = GetContextPropertiesForTesting();
+    GraphInfoBuilder builder;
+    uint64_t input_operand_id =
+        builder.BuildInput("input", {4, 4, 4}, OperandDataType::kFloat32);
+    uint64_t indices_operand_id =
+        builder.BuildInput("indices", {2, 1}, OperandDataType::kUint32);
+    uint64_t updates_operand_id =
+        builder.BuildInput("updates", {2, 4, 4}, OperandDataType::kFloat32);
+    builder.BuildScatterND(input_operand_id, indices_operand_id,
+                           updates_operand_id, input_operand_id);
+    EXPECT_FALSE(WebNNGraphBuilderImpl::IsValidForTesting(
+        context_properties, builder.GetGraphInfo()));
+  }
+}
+
 struct SliceTester {
   struct SliceAttributes {
     std::vector<uint32_t> starts;
diff --git a/services/webnn/webnn_test_utils.cc b/services/webnn/webnn_test_utils.cc
index a9c9ed4..3ec68e3 100644
--- a/services/webnn/webnn_test_utils.cc
+++ b/services/webnn/webnn_test_utils.cc
@@ -359,6 +359,17 @@
       mojom::Operation::NewReshape(std::move(reshape)));
 }
 
+void GraphInfoBuilder::BuildScatterND(uint64_t input_operand_id,
+                                      uint64_t indices_operand_id,
+                                      uint64_t updates_operand_id,
+                                      uint64_t output_operand_id) {
+  mojom::ScatterNDPtr scatter_nd =
+      mojom::ScatterND::New(input_operand_id, indices_operand_id,
+                            updates_operand_id, output_operand_id, "");
+  graph_info_->operations.push_back(
+      mojom::Operation::NewScatterNd(std::move(scatter_nd)));
+}
+
 void GraphInfoBuilder::BuildSigmoid(uint64_t input_operand_id,
                                     uint64_t output_operand_id) {
   mojom::SigmoidPtr sigmoid = mojom::Sigmoid::New();
@@ -575,6 +586,8 @@
        /*relu_input=*/SupportedDataTypes::All(),
        /*resample2d_input=*/SupportedDataTypes::All(),
        /*reshape_input=*/SupportedDataTypes::All(),
+       /*scatter_nd_input=*/SupportedDataTypes::All(),
+       /*scatter_nd_indices=*/SupportedDataTypes::All(),
        /*sigmoid_input=*/SupportedDataTypes::All(),
        /*slice_input=*/SupportedDataTypes::All(),
        /*softmax_input=*/SupportedDataTypes::All(),
diff --git a/services/webnn/webnn_test_utils.h b/services/webnn/webnn_test_utils.h
index 90290998..b2c0a4c 100644
--- a/services/webnn/webnn_test_utils.h
+++ b/services/webnn/webnn_test_utils.h
@@ -485,6 +485,11 @@
 
   void BuildReshape(uint64_t input_operand_id, uint64_t output_operand_id);
 
+  void BuildScatterND(uint64_t input_operand_id,
+                      uint64_t indices_operand_id,
+                      uint64_t updates_operand_id,
+                      uint64_t output_operand_id);
+
   void BuildSigmoid(uint64_t input_operand_id, uint64_t output_operand_id);
 
   void BuildSoftmax(uint64_t input_operand_id,
diff --git a/services/webnn/webnn_utils.cc b/services/webnn/webnn_utils.cc
index 5184f7b..71664980 100644
--- a/services/webnn/webnn_utils.cc
+++ b/services/webnn/webnn_utils.cc
@@ -132,6 +132,8 @@
       return ops::kResample2d;
     case mojom::Operation::Tag::kReshape:
       return ops::kReshape;
+    case mojom::Operation::Tag::kScatterNd:
+      return ops::kScatterND;
     case mojom::Operation::Tag::kSigmoid:
       return ops::kSigmoid;
     case mojom::Operation::Tag::kSlice:
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 96e5760..0d5d11e 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -10956,8 +10956,8 @@
                 {
                     "name": "Enabled",
                     "params": {
-                        "prob": "0.01",
-                        "survey_cycle_length": "90",
+                        "prob": "0.02",
+                        "survey_cycle_length": "30",
                         "survey_start_date_ms": "1721606400000",
                         "trigger_id": "ZMEQmwKYE0jBnuKU19R0Uk7d5aG4"
                     },
@@ -13249,6 +13249,27 @@
             ]
         }
     ],
+    "LazyUpdateTranslateModel": [
+        {
+            "platforms": [
+                "android",
+                "chromeos",
+                "chromeos_lacros",
+                "fuchsia",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "LazyUpdateTranslateModel"
+                    ]
+                }
+            ]
+        }
+    ],
     "LeakSkiaEventTracerAtExit": [
         {
             "platforms": [
@@ -16064,6 +16085,21 @@
             ]
         }
     ],
+    "OverviewSessionInitOptimizations": [
+        {
+            "platforms": [
+                "chromeos"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "OverviewSessionInitOptimizations"
+                    ]
+                }
+            ]
+        }
+    ],
     "OzonePlatformAuto": [
         {
             "platforms": [
@@ -24705,6 +24741,28 @@
             ]
         }
     ],
+    "V8SeparateGCPhases": [
+        {
+            "platforms": [
+                "android",
+                "android_webview",
+                "chromeos",
+                "chromeos_lacros",
+                "fuchsia",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "V8SeparateGCPhases"
+                    ]
+                }
+            ]
+        }
+    ],
     "V8SideStepTransitions": [
         {
             "platforms": [
@@ -26201,26 +26259,6 @@
             ]
         }
     ],
-    "WebUIBubblePersistentRendererStudy": [
-        {
-            "platforms": [
-                "chromeos",
-                "chromeos_lacros",
-                "fuchsia",
-                "linux",
-                "mac",
-                "windows"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "WebUIBubblePerProfilePersistence"
-                    ]
-                }
-            ]
-        }
-    ],
     "WebUICodeCache": [
         {
             "platforms": [
@@ -26625,21 +26663,6 @@
             ]
         }
     ],
-    "WinSboxACProfileWithoutFirewall": [
-        {
-            "platforms": [
-                "windows"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "WinSboxACProfileWithoutFirewall"
-                    ]
-                }
-            ]
-        }
-    ],
     "WinSboxNoFakeGdiInit": [
         {
             "platforms": [
diff --git a/third_party/angle b/third_party/angle
index 10d56e6..c335ddf 160000
--- a/third_party/angle
+++ b/third_party/angle
@@ -1 +1 @@
-Subproject commit 10d56e63f489477d325fd9667861c06b4c5887bc
+Subproject commit c335ddfa1e135806405cad9f1d4cd3e610571ba7
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index 70501a0..1328873 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -1695,18 +1695,6 @@
              "ResourceFetcherStoresStrongReferences",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
-BASE_FEATURE(kMemoryCacheStrongReferenceFilterImages,
-             "MemoryCacheStrongReferenceFilterImages",
-             base::FEATURE_ENABLED_BY_DEFAULT);
-
-BASE_FEATURE(kMemoryCacheStrongReferenceFilterScripts,
-             "MemoryCacheStrongReferenceFilterScripts",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-
-BASE_FEATURE(kMemoryCacheStrongReferenceFilterCrossOriginScripts,
-             "MemoryCacheStrongReferenceFilterCrossOriginScripts",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-
 BASE_FEATURE(kMemoryCacheStrongReference,
              "MemoryCacheStrongReference",
 // Finch study showed no improvement on Android for strong memory cache.
@@ -1717,14 +1705,16 @@
 #endif
 );
 
-const base::FeatureParam<int>
-    kMemoryCacheStrongReferenceTotalSizeThresholdParam{
-        &kMemoryCacheStrongReference,
-        "memory_cache_strong_ref_total_size_threshold", 15 * 1024 * 1024};
-const base::FeatureParam<int>
-    kMemoryCacheStrongReferenceResourceSizeThresholdParam{
-        &kMemoryCacheStrongReference,
-        "memory_cache_strong_ref_resource_size_threshold", 3 * 1024 * 1024};
+BASE_FEATURE_PARAM(int,
+                   kMemoryCacheStrongReferenceTotalSizeThresholdParam,
+                   &kMemoryCacheStrongReference,
+                   "memory_cache_strong_ref_total_size_threshold",
+                   15 * 1024 * 1024);
+BASE_FEATURE_PARAM(int,
+                   kMemoryCacheStrongReferenceResourceSizeThresholdParam,
+                   &kMemoryCacheStrongReference,
+                   "memory_cache_strong_ref_resource_size_threshold",
+                   3 * 1024 * 1024);
 
 // Used to control the collection of anchor element metrics (crbug.com/856683).
 // If kNavigationPredictor is enabled, then metrics of anchor elements
@@ -1763,10 +1753,6 @@
              "OriginAgentClusterDefaultEnable",
              base::FEATURE_ENABLED_BY_DEFAULT);
 
-BASE_FEATURE(kOriginAgentClusterDefaultWarning,
-             "OriginAgentClusterDefaultWarning",
-             base::FEATURE_ENABLED_BY_DEFAULT);
-
 BASE_FEATURE(kOriginTrialStateHostApplyFeatureDiff,
              "OriginTrialStateHostApplyFeatureDiff",
              base::FEATURE_ENABLED_BY_DEFAULT);
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h
index 5eebc32..320a169 100644
--- a/third_party/blink/public/common/features.h
+++ b/third_party/blink/public/common/features.h
@@ -1129,27 +1129,17 @@
 BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kMemoryCacheStrongReference);
 // The threshold for the total decoded size of resources that keep strong
 // references.
-BLINK_COMMON_EXPORT extern const base::FeatureParam<int>
-    kMemoryCacheStrongReferenceTotalSizeThresholdParam;
+BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE_PARAM(
+    int,
+    kMemoryCacheStrongReferenceTotalSizeThresholdParam);
 // The threshold for the decoded size of a resource that can keep a strong
 // reference.
-BLINK_COMMON_EXPORT extern const base::FeatureParam<int>
-    kMemoryCacheStrongReferenceResourceSizeThresholdParam;
+BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE_PARAM(
+    int,
+    kMemoryCacheStrongReferenceResourceSizeThresholdParam);
 // Whether the ResourceFetcher should store strong references too.
 BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(
     kResourceFetcherStoresStrongReferences);
-// Exclude images from the saved strong references for resources.
-// See https://crbug.com/1409349.
-BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(
-    kMemoryCacheStrongReferenceFilterImages);
-// Exclude scripts from the saved strong references for resources.
-// See https://crbug.com/1409349.
-BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(
-    kMemoryCacheStrongReferenceFilterScripts);
-// Exclude cross origin scripts from the saved strong references for resources.
-// See https://crbug.com/1409349.
-BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(
-    kMemoryCacheStrongReferenceFilterCrossOriginScripts);
 
 BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kMixedContentAutoupgrade);
 
@@ -1168,11 +1158,6 @@
 // If enabled, an absent Origin-Agent-Cluster: header is interpreted as
 // requesting an origin agent cluster, but in the same process.
 BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kOriginAgentClusterDefaultEnabled);
-// This flag enables a console warning in cases where document.domain is set
-// without origin agent clustering being explicitly disabled.
-// (This is a transitory behaviour on the road to perma-enabling
-// kOriginAgentClusterDefaultEnabled above.)
-BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kOriginAgentClusterDefaultWarning);
 
 // Kill-switch for any calls to the mojo interface OriginTrialStateHost
 // in the RuntimeFeatureStateOverrideContext class. If
diff --git a/third_party/blink/public/mojom/ai/ai_manager.mojom b/third_party/blink/public/mojom/ai/ai_manager.mojom
index bf40b88..e44b0a0 100644
--- a/third_party/blink/public/mojom/ai/ai_manager.mojom
+++ b/third_party/blink/public/mojom/ai/ai_manager.mojom
@@ -89,6 +89,21 @@
   OnResult(pending_remote<blink.mojom.AISummarizer>? summarizer);
 };
 
+// The enum describes the possible roles in the initial prompt.
+enum AIAssistantInitialPromptRole {
+  kSystem = 0,
+  kUser = 1,
+  kAssistant = 2,
+
+  // Append new line here
+};
+
+// Each initial prompt contains a role and the actual content.
+struct AIAssistantInitialPrompt {
+  AIAssistantInitialPromptRole role;
+  string content;
+};
+
 // The manager that could create a new session for the model.
 interface AIManager {
   // Returns if it is possible to create a text session. For example, when
@@ -105,7 +120,8 @@
   CreateTextSession(
     pending_receiver<blink.mojom.AITextSession> session,
     AITextSessionSamplingParams? sampling_params,
-    string? system_prompt
+    string? system_prompt,
+    array<AIAssistantInitialPrompt> initial_prompts
   ) => (AITextSessionInfo? info);
   // Returns if it is possible to create a summarizer. For example, when
   // the service in charge of model loading and session creation is not
diff --git a/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom b/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom
index 5070cbf..f0a581e 100644
--- a/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom
+++ b/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom
@@ -4471,7 +4471,7 @@
   kV8Window_PopinContextTypesSupported_Method = 5096,
   kV8Window_PopinContextType_Method = 5097,
   kWebAuthentication_AttestationFormats = 5098,
-
+  kCssDisplayPropertyMultipleValues = 5099,
 
   // Add new features immediately above this line. Don't change assigned
   // numbers of any item, and don't reuse removed slots. Also don't add extra
diff --git a/third_party/blink/public/mojom/use_counter/metrics/webdx_feature.mojom b/third_party/blink/public/mojom/use_counter/metrics/webdx_feature.mojom
index b30574c..5a1ad8b 100644
--- a/third_party/blink/public/mojom/use_counter/metrics/webdx_feature.mojom
+++ b/third_party/blink/public/mojom/use_counter/metrics/webdx_feature.mojom
@@ -166,6 +166,7 @@
   kJsModulesServiceWorkers = 108,
   kJsModulesSharedWorkers = 109,
   kJsModulesWorkers = 110,
+  kTwoValueDisplay = 111,
 
   // Add new features immediately above this line. Don't change assigned
   // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/blink/renderer/bindings/core/v8/binding_security.cc b/third_party/blink/renderer/bindings/core/v8/binding_security.cc
index 48bb8b5..294df02d 100644
--- a/third_party/blink/renderer/bindings/core/v8/binding_security.cc
+++ b/third_party/blink/renderer/bindings/core/v8/binding_security.cc
@@ -127,18 +127,6 @@
         accessing_window->document(),
         can_access ? WebFeature::kDocumentDomainEnabledCrossOriginAccess
                    : WebFeature::kDocumentDomainBlockedCrossOriginAccess);
-    // Handle deprecation warnings for OriginAgentCluster default:
-    // If the new default is not (yet) enabled, but warnings are, and
-    // access gets allowed for domain-setting reasons (reasons checked in
-    // the if clause above).
-    if (accessing_window->GetAgent()->IsOriginOrSiteKeyedBasedOnDefault() &&
-        base::FeatureList::IsEnabled(
-            blink::features::kOriginAgentClusterDefaultWarning) &&
-        can_access) {
-      UseCounter::CountDeprecation(
-          accessing_window->document(),
-          WebFeature::kCrossOriginAccessBasedOnDocumentDomain);
-    }
   }
   if (!can_access) {
     // Ensure that if we got a cluster mismatch that it was due to a permissions
diff --git a/third_party/blink/renderer/bindings/generated_in_modules.gni b/third_party/blink/renderer/bindings/generated_in_modules.gni
index d4b1f8f..b07b8f8 100644
--- a/third_party/blink/renderer/bindings/generated_in_modules.gni
+++ b/third_party/blink/renderer/bindings/generated_in_modules.gni
@@ -136,6 +136,10 @@
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_address_errors.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_address_init.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_address_init.h",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_ai_assistant_create_options.cc",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_ai_assistant_create_options.h",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_ai_assistant_initial_prompt.cc",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_ai_assistant_initial_prompt.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_ai_rewriter_rewrite_options.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_ai_rewriter_rewrite_options.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_ai_rewriter_create_options.cc",
@@ -144,8 +148,6 @@
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_ai_summarizer_create_options.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_ai_summarizer_summarize_options.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_ai_summarizer_summarize_options.h",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_ai_text_session_options.cc",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_ai_text_session_options.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_ai_writer_write_options.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_ai_writer_write_options.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_ai_writer_create_options.cc",
@@ -800,6 +802,8 @@
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_ml_prelu_support_limits.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_ml_quantize_dequantize_linear_support_limits.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_ml_quantize_dequantize_linear_support_limits.h",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_ml_scatter_support_limits.cc",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_ml_scatter_support_limits.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_ml_single_input_support_limits.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_ml_single_input_support_limits.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_ml_where_support_limits.cc",
@@ -1342,6 +1346,10 @@
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_aac_bitstream_format.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_ad_signals.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_ad_signals.h",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_ai_assistant_initial_prompt_role.cc",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_ai_assistant_initial_prompt_role.h",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_ai_assistant_prompt_role.cc",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_ai_assistant_prompt_role.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_ai_capability_availability.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_ai_capability_availability.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_ai_rewriter_tone.cc",
diff --git a/third_party/blink/renderer/bindings/idl_in_modules.gni b/third_party/blink/renderer/bindings/idl_in_modules.gni
index b1e61eb..b4548d4 100644
--- a/third_party/blink/renderer/bindings/idl_in_modules.gni
+++ b/third_party/blink/renderer/bindings/idl_in_modules.gni
@@ -18,12 +18,12 @@
   "//third_party/blink/renderer/modules/ad_auction/protected_audience.idl",
   "//third_party/blink/renderer/modules/ai/ai.idl",
   "//third_party/blink/renderer/modules/ai/ai_assistant.idl",
+  "//third_party/blink/renderer/modules/ai/ai_assistant_create_options.idl",
   "//third_party/blink/renderer/modules/ai/ai_assistant_factory.idl",
   "//third_party/blink/renderer/modules/ai/ai_rewriter.idl",
   "//third_party/blink/renderer/modules/ai/ai_rewriter_factory.idl",
   "//third_party/blink/renderer/modules/ai/ai_summarizer.idl",
   "//third_party/blink/renderer/modules/ai/ai_summarizer_factory.idl",
-  "//third_party/blink/renderer/modules/ai/ai_text_session_options.idl",
   "//third_party/blink/renderer/modules/ai/ai_writer.idl",
   "//third_party/blink/renderer/modules/ai/ai_writer_factory.idl",
   "//third_party/blink/renderer/modules/ai/window_or_worker_global_scope_ai.idl",
diff --git a/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
index 65cd935..2f0b4e9 100644
--- a/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
+++ b/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
@@ -3257,6 +3257,7 @@
   if (id != CSSValueID::kInvalid) {
     const CSSIdentifierValue* value = css_parsing_utils::ConsumeIdent(stream);
     if (stream.Peek().Id() != CSSValueID::kInvalid) {
+      context.Count(WebFeature::kCssDisplayPropertyMultipleValues);
       return ParseDisplayMultipleKeywords(stream, value);
     }
 
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index 33285a6..0464f23 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -6334,24 +6334,6 @@
     return;
   }
 
-  // TODO(crbug.com/1259920): Remove this check once the Origin-Agent-Cluster
-  // default behaviour change has been default-enabled.
-  if (base::FeatureList::IsEnabled(
-          blink::features::kOriginAgentClusterDefaultWarning) &&
-      Loader()) {
-    const AtomicString& origin_agent_cluster_header =
-        Loader()->GetResponse().HttpHeaderField(
-            http_names::kOriginAgentCluster);
-    if (origin_agent_cluster_header != "?0" &&
-        origin_agent_cluster_header != "?1") {
-      DCHECK(!dom_window_->GetAgent()->IsOriginKeyed());
-      Deprecation::CountDeprecation(
-          GetExecutionContext(),
-          WebFeature::kDocumentDomainSettingWithoutOriginAgentClusterHeader);
-      // No return; warning only.
-    }
-  }
-
   if (GetFrame()) {
     // This code should never fire for fenced frames because it should be
     // blocked by permission policy.
diff --git a/third_party/blink/renderer/core/editing/finder/find_buffer.cc b/third_party/blink/renderer/core/editing/finder/find_buffer.cc
index 2f2bc62..64dba5a6 100644
--- a/third_party/blink/renderer/core/editing/finder/find_buffer.cc
+++ b/third_party/blink/renderer/core/editing/finder/find_buffer.cc
@@ -181,9 +181,10 @@
 }  // namespace
 
 // FindBuffer implementation.
-FindBuffer::FindBuffer(const EphemeralRangeInFlatTree& range) {
+FindBuffer::FindBuffer(const EphemeralRangeInFlatTree& range,
+                       RubySupport ruby_support) {
   DCHECK(range.IsNotNull() && !range.IsCollapsed()) << range;
-  CollectTextUntilBlockBoundary(range);
+  CollectTextUntilBlockBoundary(range, ruby_support);
 }
 
 bool FindBuffer::IsInvalidMatch(MatchResultICU match) const {
@@ -249,7 +250,8 @@
       break;
 
     FindBuffer buffer(
-        EphemeralRangeInFlatTree(start_position, range.EndPosition()));
+        EphemeralRangeInFlatTree(start_position, range.EndPosition()),
+        RubySupport(options.IsRubySupported()));
     FindResults match_results = buffer.FindMatches(search_text, options);
     if (!match_results.IsEmpty()) {
       if (!options.IsBackwards()) {
@@ -361,12 +363,14 @@
   String search_text_16_bit = search_text;
   search_text_16_bit.Ensure16Bit();
   FoldQuoteMarksAndSoftHyphens(search_text_16_bit);
-  return FindResults(*this, &text_searcher_, buffer_, search_text_16_bit,
-                     options);
+  // TODO(crbug.com/40755728): Provide additional text buffers.
+  return FindResults(*this, &text_searcher_, buffer_,
+                     /* extra_buffers */ nullptr, search_text_16_bit, options);
 }
 
 void FindBuffer::CollectTextUntilBlockBoundary(
-    const EphemeralRangeInFlatTree& range) {
+    const EphemeralRangeInFlatTree& range,
+    RubySupport ruby_support) {
   // Collects text until block boundary located at or after |start_node|
   // to |buffer_|. Saves the next starting node after the block to
   // |node_after_block_|.
diff --git a/third_party/blink/renderer/core/editing/finder/find_buffer.h b/third_party/blink/renderer/core/editing/finder/find_buffer.h
index b746650..5b611637 100644
--- a/third_party/blink/renderer/core/editing/finder/find_buffer.h
+++ b/third_party/blink/renderer/core/editing/finder/find_buffer.h
@@ -28,7 +28,10 @@
   STACK_ALLOCATED();
 
  public:
-  explicit FindBuffer(const EphemeralRangeInFlatTree& range);
+  using RubySupport = base::StrongAlias<class RubySupportTag, bool>;
+
+  explicit FindBuffer(const EphemeralRangeInFlatTree& range,
+                      RubySupport ruby_support = RubySupport(false));
 
   static EphemeralRangeInFlatTree FindMatchInRange(
       const EphemeralRangeInFlatTree& range,
@@ -74,7 +77,8 @@
   // encountered another LayoutBLockFlow, or if the end of |range| is
   // surpassed. Saves the next starting node after the block (first node in
   // another LayoutBlockFlow or after |end_position|) to |node_after_block_|.
-  void CollectTextUntilBlockBoundary(const EphemeralRangeInFlatTree& range);
+  void CollectTextUntilBlockBoundary(const EphemeralRangeInFlatTree& range,
+                                     RubySupport ruby_support);
 
   // Replaces nodes that should be ignored with appropriate char constants.
   void ReplaceNodeWithCharConstants(const Node& node);
diff --git a/third_party/blink/renderer/core/editing/finder/find_options.h b/third_party/blink/renderer/core/editing/finder/find_options.h
index facfb95..1fabd20 100644
--- a/third_party/blink/renderer/core/editing/finder/find_options.h
+++ b/third_party/blink/renderer/core/editing/finder/find_options.h
@@ -76,6 +76,12 @@
     return *this;
   }
 
+  bool IsRubySupported() const { return ruby_supported_; }
+  constexpr FindOptions& SetRubySupported(bool flag) {
+    ruby_supported_ = flag;
+    return *this;
+  }
+
  private:
   bool case_insensitive_ : 1 = false;
   bool backwards_ : 1 = false;
@@ -83,6 +89,7 @@
   bool starting_in_selection_ : 1 = false;
   bool whole_word_ : 1 = false;
   bool find_api_call_ : 1 = false;
+  bool ruby_supported_ : 1 = false;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/editing/finder/find_results.cc b/third_party/blink/renderer/core/editing/finder/find_results.cc
index 495281b..3c98ef6 100644
--- a/third_party/blink/renderer/core/editing/finder/find_results.cc
+++ b/third_party/blink/renderer/core/editing/finder/find_results.cc
@@ -13,6 +13,7 @@
 FindResults::FindResults(const FindBuffer& find_buffer,
                          TextSearcherICU* text_searcher,
                          const Vector<UChar>& buffer,
+                         const Vector<Vector<UChar>>* extra_buffers,
                          const String& search_text,
                          const FindOptions options) {
   // We need to own the |search_text| because |text_searcher_| only has a
@@ -23,6 +24,18 @@
   text_searcher_->SetPattern(search_text_, options);
   text_searcher_->SetText(base::span(buffer));
   text_searcher_->SetOffset(0);
+  if (!RuntimeEnabledFeatures::FindRubyInPageEnabled()) {
+    DCHECK(!extra_buffers || extra_buffers->empty());
+  } else if (extra_buffers) {
+    extra_searchers_.reserve(extra_buffers->size());
+    for (const auto& text : *extra_buffers) {
+      extra_searchers_.push_back(
+          std::make_unique<TextSearcherICU>(TextSearcherICU::kConstructLocal));
+      auto& searcher = extra_searchers_.back();
+      searcher->SetPattern(search_text_, options);
+      searcher->SetText(base::span(text));
+    }
+  }
 }
 
 FindResults::Iterator FindResults::begin() const {
@@ -30,6 +43,9 @@
     return end();
   }
   text_searcher_->SetOffset(0);
+  for (auto& searcher : extra_searchers_) {
+    searcher->SetOffset(0);
+  }
   return Iterator(*find_buffer_, text_searcher_);
 }
 
@@ -66,21 +82,26 @@
                                 TextSearcherICU* text_searcher)
     : find_buffer_(&find_buffer),
       text_searcher_(text_searcher),
+      // Initialize match_ with a value so that IsAtEnd() returns false.
       match_({0u, 0u}) {
   operator++();
 }
 
 const FindResults::BufferMatchResult FindResults::Iterator::operator*() const {
-  DCHECK(match_);
+  DCHECK(!IsAtEnd());
   return FindResults::BufferMatchResult({match_->start, match_->length});
 }
 
 void FindResults::Iterator::operator++() {
-  DCHECK(match_);
+  DCHECK(!IsAtEnd());
   match_ = text_searcher_->NextMatchResult();
   if (match_ && find_buffer_ && find_buffer_->IsInvalidMatch(*match_)) {
     operator++();
   }
 }
 
+bool FindResults::Iterator::IsAtEnd() const {
+  return !match_.has_value();
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/editing/finder/find_results.h b/third_party/blink/renderer/core/editing/finder/find_results.h
index 8a464bd..41b800a8 100644
--- a/third_party/blink/renderer/core/editing/finder/find_results.h
+++ b/third_party/blink/renderer/core/editing/finder/find_results.h
@@ -45,11 +45,11 @@
     Iterator(const FindBuffer& find_buffer, TextSearcherICU* text_searcher);
 
     bool operator==(const Iterator& other) const {
-      return match_.has_value() == other.match_.has_value();
+      return IsAtEnd() == other.IsAtEnd();
     }
 
     bool operator!=(const Iterator& other) const {
-      return match_.has_value() != other.match_.has_value();
+      return IsAtEnd() != other.IsAtEnd();
     }
 
     const BufferMatchResult operator*() const;
@@ -57,6 +57,8 @@
     void operator++();
 
    private:
+    bool IsAtEnd() const;
+
     const FindBuffer* find_buffer_;
     TextSearcherICU* text_searcher_;
     std::optional<MatchResultICU> match_;
@@ -66,6 +68,7 @@
   FindResults(const FindBuffer& find_buffer,
               TextSearcherICU* text_searcher,
               const Vector<UChar>& buffer,
+              const Vector<Vector<UChar>>* extra_buffers,
               const String& search_text,
               const FindOptions options);
 
@@ -83,6 +86,7 @@
   String search_text_;
   const FindBuffer* find_buffer_;
   TextSearcherICU* text_searcher_;
+  Vector<std::unique_ptr<TextSearcherICU>> extra_searchers_;
   bool empty_result_ = false;
 };
 
diff --git a/third_party/blink/renderer/core/editing/finder/text_finder.cc b/third_party/blink/renderer/core/editing/finder/text_finder.cc
index ed7bf92..84ff2208 100644
--- a/third_party/blink/renderer/core/editing/finder/text_finder.cc
+++ b/third_party/blink/renderer/core/editing/finder/text_finder.cc
@@ -247,7 +247,8 @@
                                 .SetBackwards(!options.forward)
                                 .SetCaseInsensitive(!options.match_case)
                                 .SetWrappingAround(wrap_within_frame)
-                                .SetStartingInSelection(options.new_session);
+                                .SetStartingInSelection(options.new_session)
+                                .SetRubySupported(true);
   active_match_ = Editor::FindRangeOfString(
       *OwnerFrame().GetFrame()->GetDocument(), search_text,
       EphemeralRangeInFlatTree(active_match_.Get()), find_options,
diff --git a/third_party/blink/renderer/core/editing/iterators/text_searcher_icu.cc b/third_party/blink/renderer/core/editing/iterators/text_searcher_icu.cc
index 9dfc6cd..cfa0c5d 100644
--- a/third_party/blink/renderer/core/editing/iterators/text_searcher_icu.cc
+++ b/third_party/blink/renderer/core/editing/iterators/text_searcher_icu.cc
@@ -63,12 +63,32 @@
   SearcherFactory(const SearcherFactory&) = delete;
   SearcherFactory& operator=(const SearcherFactory&) = delete;
 
+  // Returns the global instance. If this is called again before calling
+  // ReleaseSearcher(), this function crashes.
   static UStringSearch* AcquireSearcher() {
     Instance().Lock();
     return Instance().searcher_;
   }
+  // Creates a normal instance. We may create instances multiple times with
+  // this function.  A returned pointer should be destructed by
+  // ReleaseSearcher().
+  static UStringSearch* CreateLocal() { return CreateSearcher(); }
 
-  static void ReleaseSearcher() { Instance().Unlock(); }
+  static void ReleaseSearcher(UStringSearch* searcher) {
+    if (searcher == Instance().searcher_) {
+      // Leave the static object pointing to valid strings (pattern=target,
+      // text=buffer). Otherwise, usearch_reset() will results in
+      // 'use-after-free' error.
+      UErrorCode status = U_ZERO_ERROR;
+      usearch_setPattern(searcher, &kNewlineCharacter, 1, &status);
+      DCHECK(U_SUCCESS(status));
+      usearch_setText(searcher, &kNewlineCharacter, 1, &status);
+      DCHECK(U_SUCCESS(status));
+      Instance().Unlock();
+    } else {
+      usearch_close(searcher);
+    }
+  }
 
  private:
   static SearcherFactory& Instance() {
@@ -125,18 +145,14 @@
 }
 
 // Grab the single global searcher.
-// If we ever have a reason to do more than once search buffer at once, we'll
-// have to move to multiple searchers.
 TextSearcherICU::TextSearcherICU()
     : searcher_(SearcherFactory::AcquireSearcher()) {}
 
+TextSearcherICU::TextSearcherICU(ConstructLocalTag)
+    : searcher_(SearcherFactory::CreateLocal()) {}
+
 TextSearcherICU::~TextSearcherICU() {
-  // Leave the static object pointing to valid strings (pattern=target,
-  // text=buffer). Otheriwse, usearch_reset() will results in 'use-after-free'
-  // error.
-  SetPattern(base::span<const UChar>({kNewlineCharacter}));
-  SetText(base::span<const UChar>({kNewlineCharacter}));
-  SearcherFactory::ReleaseSearcher();
+  SearcherFactory::ReleaseSearcher(searcher_);
 }
 
 void TextSearcherICU::SetPattern(const StringView& pattern,
diff --git a/third_party/blink/renderer/core/editing/iterators/text_searcher_icu.h b/third_party/blink/renderer/core/editing/iterators/text_searcher_icu.h
index 555a4fa..9b7513e 100644
--- a/third_party/blink/renderer/core/editing/iterators/text_searcher_icu.h
+++ b/third_party/blink/renderer/core/editing/iterators/text_searcher_icu.h
@@ -24,10 +24,14 @@
 };
 
 class CORE_EXPORT TextSearcherICU {
-  DISALLOW_NEW();
-
  public:
+  enum ConstructLocalTag { kConstructLocal };
+
+  // Instantiate with the global UStringSearch instance.
+  // We can't have multiple instances constructed by this.
   TextSearcherICU();
+  // Instantiate with a local UStringSearch instance.
+  explicit TextSearcherICU(ConstructLocalTag);
   TextSearcherICU(const TextSearcherICU&) = delete;
   TextSearcherICU& operator=(const TextSearcherICU&) = delete;
   ~TextSearcherICU();
diff --git a/third_party/blink/renderer/core/frame/DEPS b/third_party/blink/renderer/core/frame/DEPS
index b897ade..55b3889 100644
--- a/third_party/blink/renderer/core/frame/DEPS
+++ b/third_party/blink/renderer/core/frame/DEPS
@@ -23,6 +23,9 @@
   "dom_timer_test\.cc": [
     "+base/test/scoped_command_line.h",
   ],
+  "frame\.cc": [
+    "+base/metrics/histogram_functions.h",
+  ],
   "frame_view\.cc": [
     "+ui/gfx/transform.h"
   ],
@@ -40,6 +43,7 @@
     "+ui/gfx/transform.h"
   ],
   "local_frame\.cc": [
+    "+base/metrics/histogram_functions.h",
     "+ui/gfx/transform.h"
   ],
   "local_frame_ukm_aggregator\.cc": [
diff --git a/third_party/blink/renderer/core/frame/deprecation/deprecation.json5 b/third_party/blink/renderer/core/frame/deprecation/deprecation.json5
index 85a2f51..f480ab9 100644
--- a/third_party/blink/renderer/core/frame/deprecation/deprecation.json5
+++ b/third_party/blink/renderer/core/frame/deprecation/deprecation.json5
@@ -210,15 +210,6 @@
       milestone: 119,
     },
     {
-      name: "DocumentDomainSettingWithoutOriginAgentClusterHeader",
-      message: "Relaxing the same-origin policy by setting `document.domain` is deprecated, and will be disabled by default. To continue using this feature, please opt-out of origin-keyed agent clusters by sending an `Origin-Agent-Cluster: ?0` header along with the HTTP response for the document and frames. See https://developer.chrome.com/blog/immutable-document-domain/ for more details.",
-      translation_note: "This warning occurs when a script modifies `document.domain` without having set on `Origin-Agent-Cluster` http header. In other words, when a script relies on the default behaviour of `Origin-Agent-Cluster` when setting document.domain.",
-      web_features: [
-        "kDocumentDomainSettingWithoutOriginAgentClusterHeader",
-      ],
-      milestone: 115,
-    },
-    {
       name: "DOMMutationEvents",
       message: "DOM Mutation Events, including `DOMSubtreeModified`, `DOMNodeInserted`, `DOMNodeRemoved`, `DOMNodeRemovedFromDocument`, `DOMNodeInsertedIntoDocument`, and `DOMCharacterDataModified` are deprecated (https://w3c.github.io/uievents/#legacy-event-types) and will be removed. Please use `MutationObserver` instead.",
       translation_note: "Warning displayed to developers when non-standard Mutation Events are used. These are deprecated and will be removed.",
diff --git a/third_party/blink/renderer/core/frame/frame.cc b/third_party/blink/renderer/core/frame/frame.cc
index b4a89874..6210eae 100644
--- a/third_party/blink/renderer/core/frame/frame.cc
+++ b/third_party/blink/renderer/core/frame/frame.cc
@@ -32,6 +32,7 @@
 
 #include <memory>
 
+#include "base/metrics/histogram_functions.h"
 #include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/mojom/fenced_frame/fenced_frame.mojom-blink.h"
 #include "third_party/blink/public/mojom/frame/frame.mojom-blink.h"
@@ -744,6 +745,11 @@
         remote_frame_host,
     mojo::PendingAssociatedReceiver<mojom::blink::RemoteFrame>
         remote_frame_receiver) {
+  TRACE_EVENT0("navigation", "Frame::SwapImpl");
+  std::string_view histogram_suffix =
+      (new_web_frame->IsWebLocalFrame() ? "Local" : "Remote");
+  base::ScopedUmaHistogramTimer histogram_timer(
+      base::StrCat({"Navigation.Frame.SwapImpl.", histogram_suffix}));
   DCHECK(IsAttached());
 
   using std::swap;
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc
index 3748fa2..e3c8563 100644
--- a/third_party/blink/renderer/core/frame/local_frame.cc
+++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -672,6 +672,12 @@
 }
 
 bool LocalFrame::DetachImpl(FrameDetachType type) {
+  TRACE_EVENT1("navigation", "LocalFrame::DetachImpl", "detach_type",
+               static_cast<int>(type));
+  std::string_view histogram_suffix =
+      (type == FrameDetachType::kRemove) ? "Remove" : "Swap";
+  base::ScopedUmaHistogramTimer histogram_timer(
+      base::StrCat({"Navigation.LocalFrame.DetachImpl.", histogram_suffix}));
   absl::Cleanup check_post_condition = [this] {
     // This method must shutdown objects associated with it (such as
     // the `PerformanceMonitor` for local roots).
@@ -3016,6 +3022,8 @@
 }
 
 bool LocalFrame::SwapIn() {
+  TRACE_EVENT0("navigation", "LocalFrame::SwapIn");
+  base::ScopedUmaHistogramTimer histogram_timer("Navigation.LocalFrame.SwapIn");
   DCHECK(IsProvisional());
   WebLocalFrameClient* client = Client()->GetWebFrame()->Client();
   // Swap in `this`, which is a provisional frame to an existing frame.
diff --git a/third_party/blink/renderer/core/html/build.gni b/third_party/blink/renderer/core/html/build.gni
index b993fbb7..5618c6a 100644
--- a/third_party/blink/renderer/core/html/build.gni
+++ b/third_party/blink/renderer/core/html/build.gni
@@ -563,7 +563,6 @@
   "html_collection.h",
   "parser/atomic_html_token.cc",
   "parser/atomic_html_token.h",
-  "parser/atomic_string_cache.h",
   "parser/css_preload_scanner.cc",
   "parser/css_preload_scanner.h",
   "parser/html_attributes_ranges.h",
diff --git a/third_party/blink/renderer/core/html/parser/atomic_html_token.h b/third_party/blink/renderer/core/html/parser/atomic_html_token.h
index 3c1a85f..9e38cc97 100644
--- a/third_party/blink/renderer/core/html/parser/atomic_html_token.h
+++ b/third_party/blink/renderer/core/html/parser/atomic_html_token.h
@@ -34,7 +34,6 @@
 #include "base/notreached.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/dom/attribute.h"
-#include "third_party/blink/renderer/core/html/parser/atomic_string_cache.h"
 #include "third_party/blink/renderer/core/html/parser/html_token.h"
 #include "third_party/blink/renderer/core/html_element_attribute_name_lookup_trie.h"
 #include "third_party/blink/renderer/core/html_element_lookup_trie.h"
@@ -385,9 +384,13 @@
       }
     }
 
-    AtomicString value =
-        HTMLAtomicStringCache::MakeAttributeValue(attribute.ValueBuffer());
-    DCHECK(!value.IsNull()) << "Attribute value should never be null";
+    // The string pointer in |value| is null for attributes with no values, but
+    // the null atom is used to represent absence of attributes; attributes with
+    // no values have the value set to an empty atom instead.
+    AtomicString value(attribute.GetValue());
+    if (value.IsNull()) {
+      value = g_empty_atom;
+    }
     attributes_.UncheckedAppend(Attribute(std::move(name), std::move(value)));
   }
 }
diff --git a/third_party/blink/renderer/core/html/parser/atomic_string_cache.h b/third_party/blink/renderer/core/html/parser/atomic_string_cache.h
deleted file mode 100644
index b78f9c6..0000000
--- a/third_party/blink/renderer/core/html/parser/atomic_string_cache.h
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) 2021 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_PARSER_ATOMIC_STRING_CACHE_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_PARSER_ATOMIC_STRING_CACHE_H_
-
-#include "third_party/blink/renderer/core/html/parser/literal_buffer.h"
-#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
-
-namespace blink {
-
-// HTMLAtomicStringCache provides a fixed size cache of strings that is used
-// during parsing, and specifically for attribute values. The cache lookup is
-// cheap (much cheaper than AtomicString). This benefits parsing when the same
-// attribute values are repeated.
-class HTMLAtomicStringCache {
- public:
-  ALWAYS_INLINE static AtomicString MakeAttributeValue(
-      const UCharLiteralBuffer<32>& string) {
-    return MakeAtomicString(string);
-  }
-
-  ALWAYS_INLINE static AtomicString MakeAttributeValue(
-      base::span<const UChar> string) {
-    return MakeAtomicString(string);
-  }
-
-  ALWAYS_INLINE static AtomicString MakeAttributeValue(
-      base::span<const LChar> string) {
-    return MakeAtomicString(string);
-  }
-
-  ALWAYS_INLINE static void Clear() { Cache().fill({}); }
-
- private:
-  // The value of kMaxStringLengthForCache and kCapacity were chosen
-  // empirically by WebKit:
-  // https://github.com/WebKit/WebKit/blob/main/Source/WebCore/html/parser/HTMLNameCache.h
-  static constexpr auto kMaxStringLengthForCache = 36;
-  static constexpr auto kCapacity = 512;
-  using AtomicStringCache = std::array<AtomicString, kCapacity>;
-
-  template <typename CharacterType>
-  ALWAYS_INLINE static AtomicString MakeAtomicString(
-      base::span<const CharacterType> string) {
-    // If the attribute has no values, the null atom is used to represent
-    // absence of attributes, we set the value to an empty atom.
-    if (string.empty()) {
-      return g_empty_atom;
-    }
-
-    auto length = string.size();
-    if (length > kMaxStringLengthForCache) {
-      return AtomicString(string.data(), static_cast<unsigned>(length));
-    }
-
-    auto first_character = string[0];
-    auto last_character = string[length - 1];
-    auto& slot = AtomicStringCacheSlot(first_character, last_character, length);
-
-    if (!Equal(slot.Impl(), string.data(), static_cast<unsigned>(length))) {
-      AtomicString result(string.data(), static_cast<unsigned>(length));
-      slot = result;
-    }
-
-    return slot;
-  }
-
-  ALWAYS_INLINE static AtomicString MakeAtomicString(
-      const UCharLiteralBuffer<32>& string) {
-    // If the attribute has no values, the null atom is used to represent
-    // absence of attributes, we set the value to an empty atom.
-    if (string.IsEmpty()) {
-      return g_empty_atom;
-    }
-
-    auto length = string.size();
-    if (length > kMaxStringLengthForCache) {
-      return AtomicString(string.data(), length);
-    }
-
-    auto first_character = string[0];
-    auto last_character = string[length - 1];
-    auto& slot = AtomicStringCacheSlot(first_character, last_character, length);
-
-    if (!Equal(slot.Impl(), string.data(), length)) {
-      AtomicString result(string.data(), length);
-      slot = result;
-    }
-
-    return slot;
-  }
-
-  ALWAYS_INLINE static AtomicStringCache& Cache() {
-    DEFINE_STATIC_LOCAL(AtomicStringCache, attribute_value_cache_, ());
-
-    return attribute_value_cache_;
-  }
-
-  // Description from WebCore: the default string hashing algorithm only barely
-  // outperforms this simple hash function on Speedometer (i.e., a cache hit
-  // rate of 99.24% using the default hash algorithm vs. 99.15% using the
-  // "first/last character and length" hash).
-  ALWAYS_INLINE static AtomicString& AtomicStringCacheSlot(
-      UChar first_character,
-      UChar last_character,
-      UChar length) {
-    unsigned hash =
-        (first_character << 6) ^ ((last_character << 14) ^ first_character);
-    hash += (hash >> 14) + (length << 14);
-    hash ^= hash << 14;
-    return Cache()[(hash + (hash >> 6)) % kCapacity];
-  }
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_PARSER_ATOMIC_STRING_CACHE_H_
diff --git a/third_party/blink/renderer/core/html/parser/html_document_parser_fastpath.cc b/third_party/blink/renderer/core/html/parser/html_document_parser_fastpath.cc
index e20acd3a..4319cb7 100644
--- a/third_party/blink/renderer/core/html/parser/html_document_parser_fastpath.cc
+++ b/third_party/blink/renderer/core/html/parser/html_document_parser_fastpath.cc
@@ -1267,14 +1267,20 @@
           name_span.data(), static_cast<unsigned>(name_span.size())));
     }
 
+    // The string pointer in |value| is null for attributes with no values, but
+    // the null atom is used to represent absence of attributes; attributes with
+    // no values have the value set to an empty atom instead.
     AtomicString value;
     if (value_span.second.empty()) {
-      value = HTMLAtomicStringCache::MakeAttributeValue(value_span.first);
+      value = AtomicString(value_span.first.data(),
+                           static_cast<unsigned>(value_span.first.size()));
     } else {
-      value = HTMLAtomicStringCache::MakeAttributeValue(value_span.second);
+      value = AtomicString(value_span.second.data(),
+                           static_cast<unsigned>(value_span.second.size()));
     }
-    DCHECK(!value.IsNull()) << "Attribute value should never be null";
-
+    if (value.IsNull()) {
+      value = g_empty_atom;
+    }
     return Attribute(std::move(name), std::move(value));
   }
 
diff --git a/third_party/blink/renderer/core/html/parser/html_token.h b/third_party/blink/renderer/core/html/parser/html_token.h
index 0830a2e..21801fd 100644
--- a/third_party/blink/renderer/core/html/parser/html_token.h
+++ b/third_party/blink/renderer/core/html/parser/html_token.h
@@ -116,7 +116,6 @@
     AtomicString GetValue() const { return value_.AsAtomicString(); }
 
     const UCharLiteralBuffer<32>& NameBuffer() const { return name_; }
-    const UCharLiteralBuffer<32>& ValueBuffer() const { return value_; }
 
     String NameAttemptStaticStringCreation() const {
       return AttemptStaticStringCreation(name_);
diff --git a/third_party/blink/renderer/core/page/spatial_navigation.cc b/third_party/blink/renderer/core/page/spatial_navigation.cc
index c8f7f5d..171c67ab 100644
--- a/third_party/blink/renderer/core/page/spatial_navigation.cc
+++ b/third_party/blink/renderer/core/page/spatial_navigation.cc
@@ -45,6 +45,7 @@
 #include "third_party/blink/renderer/core/html/html_image_element.h"
 #include "third_party/blink/renderer/core/html_names.h"
 #include "third_party/blink/renderer/core/input/event_handler.h"
+#include "third_party/blink/renderer/core/layout/geometry/physical_offset.h"
 #include "third_party/blink/renderer/core/layout/layout_box.h"
 #include "third_party/blink/renderer/core/layout/layout_inline.h"
 #include "third_party/blink/renderer/core/layout/layout_view.h"
@@ -503,43 +504,33 @@
   return rect;
 }
 
-// This method calculates the exitPoint from the startingRect and the entryPoint
-// into the candidate rect.  The line between those 2 points is the closest
+// This method calculates the exit_point from the starting_rect and the
+// entry_point into the candidate rect, and returns a pair of the entry_point
+// and the exit_point.  The line between those 2 points is the closest
 // distance between the 2 rects.  Takes care of overlapping rects, defining
 // points so that the distance between them is zero where necessary.
-void EntryAndExitPointsForDirection(SpatialNavigationDirection direction,
-                                    const PhysicalRect& starting_rect,
-                                    const PhysicalRect& potential_rect,
-                                    LayoutPoint& exit_point,
-                                    LayoutPoint& entry_point) {
+std::pair<PhysicalOffset, PhysicalOffset> EntryAndExitPointsForDirection(
+    SpatialNavigationDirection direction,
+    const PhysicalRect& starting_rect,
+    const PhysicalRect& potential_rect) {
+  PhysicalOffset exit_point;
+  PhysicalOffset entry_point;
   switch (direction) {
     case SpatialNavigationDirection::kLeft:
-      exit_point.SetX(starting_rect.X());
-      if (potential_rect.Right() < starting_rect.X())
-        entry_point.SetX(potential_rect.Right());
-      else
-        entry_point.SetX(starting_rect.X());
+      exit_point.left = starting_rect.X();
+      entry_point.left = std::min(potential_rect.Right(), starting_rect.X());
       break;
     case SpatialNavigationDirection::kUp:
-      exit_point.SetY(starting_rect.Y());
-      if (potential_rect.Bottom() < starting_rect.Y())
-        entry_point.SetY(potential_rect.Bottom());
-      else
-        entry_point.SetY(starting_rect.Y());
+      exit_point.top = starting_rect.Y();
+      entry_point.top = std::min(potential_rect.Bottom(), starting_rect.Y());
       break;
     case SpatialNavigationDirection::kRight:
-      exit_point.SetX(starting_rect.Right());
-      if (potential_rect.X() > starting_rect.Right())
-        entry_point.SetX(potential_rect.X());
-      else
-        entry_point.SetX(starting_rect.Right());
+      exit_point.left = starting_rect.Right();
+      entry_point.left = std::max(potential_rect.X(), starting_rect.Right());
       break;
     case SpatialNavigationDirection::kDown:
-      exit_point.SetY(starting_rect.Bottom());
-      if (potential_rect.Y() > starting_rect.Bottom())
-        entry_point.SetY(potential_rect.Y());
-      else
-        entry_point.SetY(starting_rect.Bottom());
+      exit_point.top = starting_rect.Bottom();
+      entry_point.top = std::max(potential_rect.Y(), starting_rect.Bottom());
       break;
     default:
       NOTREACHED_IN_MIGRATION();
@@ -549,44 +540,33 @@
     case SpatialNavigationDirection::kLeft:
     case SpatialNavigationDirection::kRight:
       if (Below(starting_rect, potential_rect)) {
-        exit_point.SetY(starting_rect.Y());
-        if (potential_rect.Bottom() < starting_rect.Y())
-          entry_point.SetY(potential_rect.Bottom());
-        else
-          entry_point.SetY(starting_rect.Y());
+        exit_point.top = starting_rect.Y();
+        entry_point.top = std::min(potential_rect.Bottom(), starting_rect.Y());
       } else if (Below(potential_rect, starting_rect)) {
-        exit_point.SetY(starting_rect.Bottom());
-        if (potential_rect.Y() > starting_rect.Bottom())
-          entry_point.SetY(potential_rect.Y());
-        else
-          entry_point.SetY(starting_rect.Bottom());
+        exit_point.top = starting_rect.Bottom();
+        entry_point.top = std::max(potential_rect.Y(), starting_rect.Bottom());
       } else {
-        exit_point.SetY(max(starting_rect.Y(), potential_rect.Y()));
-        entry_point.SetY(exit_point.Y());
+        exit_point.top = std::max(starting_rect.Y(), potential_rect.Y());
+        entry_point.top = exit_point.top;
       }
       break;
     case SpatialNavigationDirection::kUp:
     case SpatialNavigationDirection::kDown:
       if (RightOf(starting_rect, potential_rect)) {
-        exit_point.SetX(starting_rect.X());
-        if (potential_rect.Right() < starting_rect.X())
-          entry_point.SetX(potential_rect.Right());
-        else
-          entry_point.SetX(starting_rect.X());
+        exit_point.left = starting_rect.X();
+        entry_point.left = std::min(potential_rect.Right(), starting_rect.X());
       } else if (RightOf(potential_rect, starting_rect)) {
-        exit_point.SetX(starting_rect.Right());
-        if (potential_rect.X() > starting_rect.Right())
-          entry_point.SetX(potential_rect.X());
-        else
-          entry_point.SetX(starting_rect.Right());
+        exit_point.left = starting_rect.Right();
+        entry_point.left = std::max(potential_rect.X(), starting_rect.Right());
       } else {
-        exit_point.SetX(max(starting_rect.X(), potential_rect.X()));
-        entry_point.SetX(exit_point.X());
+        exit_point.left = std::max(starting_rect.X(), potential_rect.X());
+        entry_point.left = exit_point.left;
       }
       break;
     default:
       NOTREACHED_IN_MIGRATION();
   }
+  return {entry_point, exit_point};
 }
 
 double ProjectedOverlap(SpatialNavigationDirection direction,
@@ -682,13 +662,11 @@
     // win against an "outsider".
   }
 
-  LayoutPoint exit_point;
-  LayoutPoint entry_point;
-  EntryAndExitPointsForDirection(direction, current_rect, node_rect, exit_point,
-                                 entry_point);
+  const auto [entry_point, exit_point] =
+      EntryAndExitPointsForDirection(direction, current_rect, node_rect);
 
-  LayoutUnit x_axis = (exit_point.X() - entry_point.X()).Abs();
-  LayoutUnit y_axis = (exit_point.Y() - entry_point.Y()).Abs();
+  LayoutUnit x_axis = (exit_point.left - entry_point.left).Abs();
+  LayoutUnit y_axis = (exit_point.top - entry_point.top).Abs();
   double euclidian_distance =
       sqrt((x_axis * x_axis + y_axis * y_axis).ToDouble());
   distance += euclidian_distance;
diff --git a/third_party/blink/renderer/core/paint/paint_layer.cc b/third_party/blink/renderer/core/paint/paint_layer.cc
index 4731eb0..0e53d1c 100644
--- a/third_party/blink/renderer/core/paint/paint_layer.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer.cc
@@ -2215,13 +2215,6 @@
   return PaintLayerClipper(this);
 }
 
-bool PaintLayer::ScrollsOverflow() const {
-  if (PaintLayerScrollableArea* scrollable_area = GetScrollableArea())
-    return scrollable_area->ScrollsOverflow();
-
-  return false;
-}
-
 FilterOperations PaintLayer::FilterOperationsIncludingReflection() const {
   const auto& style = GetLayoutObject().StyleRef();
   FilterOperations filter_operations = style.Filter();
diff --git a/third_party/blink/renderer/core/paint/paint_layer.h b/third_party/blink/renderer/core/paint/paint_layer.h
index 7793e48..cb350d7 100644
--- a/third_party/blink/renderer/core/paint/paint_layer.h
+++ b/third_party/blink/renderer/core/paint/paint_layer.h
@@ -268,13 +268,6 @@
                HitTestResult&,
                const PhysicalRect& hit_test_area);
 
-  // Static position is set in parent's coordinate space.
-  LayoutUnit StaticBlockPosition() const { return static_block_position_; }
-
-  void SetStaticBlockPosition(LayoutUnit position) {
-    static_block_position_ = position;
-  }
-
   using InlineEdge = LogicalStaticPosition::InlineEdge;
   using BlockEdge = LogicalStaticPosition::BlockEdge;
   InlineEdge StaticInlineEdge() const {
@@ -400,8 +393,6 @@
 
   PaintLayerClipper Clipper() const;
 
-  bool ScrollsOverflow() const;
-
   bool NeedsVisualOverflowRecalc() const {
     return needs_visual_overflow_recalc_;
   }
@@ -445,11 +436,6 @@
   // stacking contexts.
   bool HasNonIsolatedDescendantWithBlendMode() const;
 
-  CompositingReasons GetCompositingReasons() const {
-    // TODO(pdr): Remove this.
-    return CompositingReason::kNone;
-  }
-
   void UpdateDescendantDependentFlags();
 
   void UpdateSelfPaintingLayer();
@@ -526,7 +512,6 @@
   bool IsReplacedNormalFlowStacking() const;
 
 #if DCHECK_IS_ON()
-  bool IsInStackingParentZOrderLists() const;
   bool LayerListMutationAllowed() const { return layer_list_mutation_allowed_; }
 #endif
 
@@ -560,8 +545,6 @@
   void SetFirstChild(PaintLayer* first) { first_ = first; }
   void SetLastChild(PaintLayer* last) { last_ = last; }
 
-  void UpdateHasSelfPaintingLayerDescendant() const;
-
   void AppendSingleFragmentForHitTesting(
       PaintLayerFragments&,
       const PaintLayerFragment* container_fragment,
diff --git a/third_party/blink/renderer/modules/ai/ai.cc b/third_party/blink/renderer/modules/ai/ai.cc
index 57869228..c1ace65 100644
--- a/third_party/blink/renderer/modules/ai/ai.cc
+++ b/third_party/blink/renderer/modules/ai/ai.cc
@@ -6,25 +6,15 @@
 
 #include "base/functional/bind.h"
 #include "base/functional/callback_forward.h"
-#include "base/metrics/histogram_functions.h"
-#include "third_party/blink/public/mojom/ai/ai_text_session_info.mojom-blink-forward.h"
-#include "third_party/blink/public/mojom/frame/frame.mojom-blink.h"
-#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
-#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_ai_assistant_create_options.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_ai_capability_availability.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_ai_text_session_options.h"
-#include "third_party/blink/renderer/core/dom/dom_exception.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/modules/ai/ai_assistant_factory.h"
-#include "third_party/blink/renderer/modules/ai/ai_metrics.h"
 #include "third_party/blink/renderer/modules/ai/ai_rewriter_factory.h"
+#include "third_party/blink/renderer/modules/ai/ai_summarizer_factory.h"
 #include "third_party/blink/renderer/modules/ai/ai_text_session.h"
 #include "third_party/blink/renderer/modules/ai/ai_writer_factory.h"
-#include "third_party/blink/renderer/modules/ai/exception_helpers.h"
-#include "third_party/blink/renderer/platform/bindings/script_state.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
-#include "third_party/blink/renderer/platform/heap/persistent.h"
-#include "third_party/blink/renderer/platform/wtf/functional.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/modules/ai/ai.h b/third_party/blink/renderer/modules/ai/ai.h
index 86f1d6ea..569e5d7 100644
--- a/third_party/blink/renderer/modules/ai/ai.h
+++ b/third_party/blink/renderer/modules/ai/ai.h
@@ -8,24 +8,20 @@
 #include "base/memory/scoped_refptr.h"
 #include "base/task/sequenced_task_runner.h"
 #include "third_party/blink/public/mojom/ai/ai_manager.mojom-blink.h"
-#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_ai_text_session_options.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
-#include "third_party/blink/renderer/modules/ai/ai_summarizer_factory.h"
-#include "third_party/blink/renderer/modules/ai/ai_text_session_factory.h"
-#include "third_party/blink/renderer/platform/bindings/script_state.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
 
 namespace blink {
 class AIAssistantFactory;
-class AITextSession;
 class AIRewriterFactory;
+class AISummarizerFactory;
+class AITextSessionFactory;
 class AIWriterFactory;
 
-// The class that manages the exposed model APIs that load model assets and
-// create AITextSession.
+// The class is the entry point of all the built-in AI APIs. It provides the
+// getters for the factories of different functionalities.
 class AI final : public ScriptWrappable, public ExecutionContextClient {
   DEFINE_WRAPPERTYPEINFO();
 
diff --git a/third_party/blink/renderer/modules/ai/ai_assistant_create_options.idl b/third_party/blink/renderer/modules/ai/ai_assistant_create_options.idl
new file mode 100644
index 0000000..42e4618
--- /dev/null
+++ b/third_party/blink/renderer/modules/ai/ai_assistant_create_options.idl
@@ -0,0 +1,17 @@
+// Copyright 2024 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/explainers-by-googlers/prompt-api
+
+dictionary AIAssistantInitialPrompt {
+  required AIAssistantInitialPromptRole role;
+  required DOMString content;
+};
+
+dictionary AIAssistantCreateOptions {
+  [EnforceRange] unsigned long topK;
+  float temperature;
+  DOMString systemPrompt;
+  sequence<AIAssistantInitialPrompt> initialPrompts;
+};
diff --git a/third_party/blink/renderer/modules/ai/ai_assistant_factory.cc b/third_party/blink/renderer/modules/ai/ai_assistant_factory.cc
index 06c1da7..5075ccfc 100644
--- a/third_party/blink/renderer/modules/ai/ai_assistant_factory.cc
+++ b/third_party/blink/renderer/modules/ai/ai_assistant_factory.cc
@@ -4,6 +4,9 @@
 
 #include "third_party/blink/renderer/modules/ai/ai_assistant_factory.h"
 
+#include "third_party/blink/public/mojom/ai/ai_manager.mojom-blink-forward.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_ai_assistant_initial_prompt.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_ai_assistant_initial_prompt_role.h"
 #include "third_party/blink/renderer/modules/ai/ai.h"
 #include "third_party/blink/renderer/modules/ai/ai_assistant.h"
 #include "third_party/blink/renderer/modules/ai/ai_assistant_capabilities.h"
@@ -15,6 +18,23 @@
 
 namespace blink {
 
+namespace {
+
+mojom::blink::AIAssistantInitialPromptRole AIAssistantInitialPromptRole(
+    V8AIAssistantInitialPromptRole role) {
+  switch (role.AsEnum()) {
+    case V8AIAssistantInitialPromptRole::Enum::kSystem:
+      return mojom::blink::AIAssistantInitialPromptRole::kSystem;
+    case V8AIAssistantInitialPromptRole::Enum::kUser:
+      return mojom::blink::AIAssistantInitialPromptRole::kUser;
+    case V8AIAssistantInitialPromptRole::Enum::kAssistant:
+      return mojom::blink::AIAssistantInitialPromptRole::kAssistant;
+  }
+  NOTREACHED_IN_MIGRATION();
+}
+
+}  // namespace
+
 AIAssistantFactory::AIAssistantFactory(AI* ai)
     : ExecutionContextClient(ai->GetExecutionContext()),
       ai_(ai),
@@ -79,7 +99,7 @@
 
 ScriptPromise<AIAssistant> AIAssistantFactory::create(
     ScriptState* script_state,
-    const AITextSessionOptions* options,
+    const AIAssistantCreateOptions* options,
     ExceptionState& exception_state) {
   if (!script_state->ContextIsValid()) {
     ThrowInvalidContextException(exception_state);
@@ -91,6 +111,7 @@
   auto promise = resolver->Promise();
   mojom::blink::AITextSessionSamplingParamsPtr sampling_params;
   WTF::String system_prompt;
+  Vector<mojom::blink::AIAssistantInitialPromptPtr> initial_prompts;
   if (options) {
     if (!options->hasTopK() && !options->hasTemperature()) {
       sampling_params = nullptr;
@@ -103,14 +124,47 @@
           DOMException::GetErrorName(DOMExceptionCode::kNotSupportedError)));
       return promise;
     }
+
+    if (options->hasSystemPrompt() && options->hasInitialPrompts()) {
+      // If the `systemPrompt` and `initialPrompts` are both set, reject with a
+      // `TypeError`.
+      resolver->RejectWithTypeError(
+          kExceptionMessageSystemPromptAndInitialPromptsExist);
+      return promise;
+    }
     if (options->hasSystemPrompt()) {
       system_prompt = options->systemPrompt();
+    } else if (options->hasInitialPrompts()) {
+      auto& prompts = options->initialPrompts();
+      if (prompts.size() > 0) {
+        size_t start_index = 0;
+        // Only the first prompt can have a `system` role, so it's handled
+        // separately.
+        auto* first_prompt = prompts.begin()->Get();
+        if (first_prompt->role() ==
+            V8AIAssistantInitialPromptRole::Enum::kSystem) {
+          system_prompt = first_prompt->content();
+          start_index++;
+        }
+        for (size_t index = start_index; index < prompts.size(); ++index) {
+          auto prompt = prompts[index];
+          if (prompt->role() == V8AIAssistantInitialPromptRole::Enum::kSystem) {
+            // If any prompt except the first one has a `system` role, reject
+            // with a `TypeError`.
+            resolver->RejectWithTypeError(
+                kExceptionMessageSystemPromptIsNotTheFirst);
+            return promise;
+          }
+          initial_prompts.push_back(mojom::blink::AIAssistantInitialPrompt::New(
+              AIAssistantInitialPromptRole(prompt->role()), prompt->content()));
+        }
+      }
     }
   }
 
   text_session_factory_->CreateTextSession(
       AIMetrics::AISessionType::kAssistant, std::move(sampling_params),
-      system_prompt,
+      system_prompt, std::move(initial_prompts),
       WTF::BindOnce(
           [](ScriptPromiseResolver<AIAssistant>* resolver,
              AIAssistantFactory* factory,
diff --git a/third_party/blink/renderer/modules/ai/ai_assistant_factory.h b/third_party/blink/renderer/modules/ai/ai_assistant_factory.h
index 16a8e38..7c2eeaf 100644
--- a/third_party/blink/renderer/modules/ai/ai_assistant_factory.h
+++ b/third_party/blink/renderer/modules/ai/ai_assistant_factory.h
@@ -9,7 +9,7 @@
 #include "third_party/blink/public/mojom/ai/ai_text_session_info.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_ai_text_session_options.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_ai_assistant_create_options.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
 #include "third_party/blink/renderer/modules/ai/ai_assistant_capabilities.h"
@@ -34,7 +34,7 @@
 
   // ai_assistant_factory.idl implementation.
   ScriptPromise<AIAssistant> create(ScriptState* script_state,
-                                    const AITextSessionOptions* options,
+                                    const AIAssistantCreateOptions* options,
                                     ExceptionState& exception_state);
   ScriptPromise<AIAssistantCapabilities> capabilities(
       ScriptState* script_state,
diff --git a/third_party/blink/renderer/modules/ai/ai_assistant_factory.idl b/third_party/blink/renderer/modules/ai/ai_assistant_factory.idl
index d23005f..fd24c80 100644
--- a/third_party/blink/renderer/modules/ai/ai_assistant_factory.idl
+++ b/third_party/blink/renderer/modules/ai/ai_assistant_factory.idl
@@ -4,6 +4,9 @@
 
 // https://github.com/explainers-by-googlers/prompt-api
 
+enum AIAssistantInitialPromptRole { "system", "user", "assistant" };
+enum AIAssistantPromptRole { "user", "assistant" };
+
 [
   Exposed=(Window,Worker),
   RuntimeEnabled=AIPromptAPI
@@ -38,6 +41,6 @@
     RaisesException
   ]
   Promise<AIAssistant> create(
-    optional AITextSessionOptions options = {}
+    optional AIAssistantCreateOptions options = {}
   );
 };
diff --git a/third_party/blink/renderer/modules/ai/ai_text_session_factory.cc b/third_party/blink/renderer/modules/ai/ai_text_session_factory.cc
index d9ccb5b..0fd5fe7 100644
--- a/third_party/blink/renderer/modules/ai/ai_text_session_factory.cc
+++ b/third_party/blink/renderer/modules/ai/ai_text_session_factory.cc
@@ -71,6 +71,7 @@
     AIMetrics::AISessionType session_type,
     mojom::blink::AITextSessionSamplingParamsPtr sampling_params,
     const WTF::String& system_prompt,
+    Vector<mojom::blink::AIAssistantInitialPromptPtr> initial_prompts,
     CreateTextSessionCallback callback) {
   base::UmaHistogramEnumeration(
       AIMetrics::GetAIAPIUsageMetricName(session_type),
@@ -84,7 +85,7 @@
       MakeGarbageCollected<AITextSession>(GetExecutionContext(), task_runner_);
   GetAIRemote()->CreateTextSession(
       text_session->GetModelSessionReceiver(), std::move(sampling_params),
-      system_prompt,
+      system_prompt, std::move(initial_prompts),
       WTF::BindOnce(
           [](CreateTextSessionCallback callback, AITextSession* text_session,
              blink::mojom::blink::AITextSessionInfoPtr info) {
diff --git a/third_party/blink/renderer/modules/ai/ai_text_session_factory.h b/third_party/blink/renderer/modules/ai/ai_text_session_factory.h
index 98b08e7..56858445 100644
--- a/third_party/blink/renderer/modules/ai/ai_text_session_factory.h
+++ b/third_party/blink/renderer/modules/ai/ai_text_session_factory.h
@@ -48,6 +48,7 @@
       AIMetrics::AISessionType session_type,
       mojom::blink::AITextSessionSamplingParamsPtr sampling_params,
       const WTF::String& system_prompt,
+      Vector<mojom::blink::AIAssistantInitialPromptPtr> initial_prompts,
       CreateTextSessionCallback callback);
 
  private:
diff --git a/third_party/blink/renderer/modules/ai/ai_text_session_options.idl b/third_party/blink/renderer/modules/ai/ai_text_session_options.idl
deleted file mode 100644
index 3a337b7c..0000000
--- a/third_party/blink/renderer/modules/ai/ai_text_session_options.idl
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright 2024 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// https://github.com/explainers-by-googlers/prompt-api
-
-dictionary AITextSessionOptions {
-  [EnforceRange] unsigned long topK;
-  float temperature;
-  DOMString systemPrompt;
-};
diff --git a/third_party/blink/renderer/modules/ai/exception_helpers.cc b/third_party/blink/renderer/modules/ai/exception_helpers.cc
index 55cb4d6..d336077 100644
--- a/third_party/blink/renderer/modules/ai/exception_helpers.cc
+++ b/third_party/blink/renderer/modules/ai/exception_helpers.cc
@@ -36,6 +36,11 @@
 const char kExceptionMessageUnableToCloneSession[] =
     "The session cannot be cloned.";
 const char kExceptionMessageRequestAborted[] = "The request has been aborted.";
+const char kExceptionMessageSystemPromptAndInitialPromptsExist[] =
+    "The systemPrompt and initialPrompts should not present at the same time.";
+const char kExceptionMessageSystemPromptIsNotTheFirst[] =
+    "The prompt with 'system' role must be placed at the first entry of "
+    "initialPrompts.";
 
 void ThrowInvalidContextException(ExceptionState& exception_state) {
   exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
diff --git a/third_party/blink/renderer/modules/ai/exception_helpers.h b/third_party/blink/renderer/modules/ai/exception_helpers.h
index f6c0c440..5ce6bd06 100644
--- a/third_party/blink/renderer/modules/ai/exception_helpers.h
+++ b/third_party/blink/renderer/modules/ai/exception_helpers.h
@@ -19,6 +19,8 @@
 extern const char kExceptionMessageUnableToCreateSession[];
 extern const char kExceptionMessageUnableToCloneSession[];
 extern const char kExceptionMessageRequestAborted[];
+extern const char kExceptionMessageSystemPromptAndInitialPromptsExist[];
+extern const char kExceptionMessageSystemPromptIsNotTheFirst[];
 
 void ThrowInvalidContextException(ExceptionState& exception_state);
 
diff --git a/third_party/blink/renderer/modules/ml/ml_context.cc b/third_party/blink/renderer/modules/ml/ml_context.cc
index 7a71c545..97c2f9dc 100644
--- a/third_party/blink/renderer/modules/ml/ml_context.cc
+++ b/third_party/blink/renderer/modules/ml/ml_context.cc
@@ -40,6 +40,7 @@
 #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_power_preference.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_prelu_support_limits.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_quantize_dequantize_linear_support_limits.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_ml_scatter_support_limits.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_single_input_support_limits.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_support_limits.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_tensor_descriptor.h"
@@ -791,6 +792,17 @@
       SupportedDataTypesToSupportLimits(data_type_limits.reshape_input));
   op_support_limits->setReshape(reshape);
 
+  MLScatterSupportLimits* scatter_nd = MLScatterSupportLimits::Create();
+  scatter_nd->setInput(
+      SupportedDataTypesToSupportLimits(data_type_limits.scatter_nd_input));
+  scatter_nd->setIndices(
+      SupportedDataTypesToSupportLimits(data_type_limits.scatter_nd_indices));
+  scatter_nd->setUpdates(
+      SupportedDataTypesToSupportLimits(data_type_limits.scatter_nd_input));
+  scatter_nd->setOutput(
+      SupportedDataTypesToSupportLimits(data_type_limits.scatter_nd_input));
+  op_support_limits->setScatterND(scatter_nd);
+
   MLSingleInputSupportLimits* sigmoid = MLSingleInputSupportLimits::Create();
   sigmoid->setInput(
       SupportedDataTypesToSupportLimits(data_type_limits.sigmoid_input));
diff --git a/third_party/blink/renderer/modules/ml/ml_context.idl b/third_party/blink/renderer/modules/ml/ml_context.idl
index ca6c0e7..753c2a15 100644
--- a/third_party/blink/renderer/modules/ml/ml_context.idl
+++ b/third_party/blink/renderer/modules/ml/ml_context.idl
@@ -141,6 +141,13 @@
   MLSupportLimits output;
 };
 
+dictionary MLScatterSupportLimits {
+  MLSupportLimits input;
+  MLSupportLimits indices;
+  MLSupportLimits updates;
+  MLSupportLimits output;
+};
+
 dictionary MLWhereSupportLimits {
   MLSupportLimits condition;
   MLSupportLimits trueValue;
@@ -238,6 +245,7 @@
   MLSingleInputSupportLimits relu;
   MLSingleInputSupportLimits resample2d;
   MLSingleInputSupportLimits reshape;
+  MLScatterSupportLimits scatterND;
   MLSingleInputSupportLimits sigmoid;
   MLSingleInputSupportLimits slice;
   MLSingleInputSupportLimits softmax;
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.cc
index 1c39af2..76ae49d 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.cc
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.cc
@@ -2240,6 +2240,32 @@
   return output;
 }
 
+MLOperand* MLGraphBuilder::scatterND(const MLOperand* input,
+                                     const MLOperand* indices,
+                                     const MLOperand* updates,
+                                     const MLOperatorOptions* options,
+                                     ExceptionState& exception_state) {
+  THROW_AND_RETURN_IF_ERROR(ValidateGraphBuilderState(), nullptr);
+
+  HeapVector<Member<const MLOperand>> inputs = {input, indices, updates};
+  THROW_AND_RETURN_TYPE_IF_ERROR(ValidateInputs(inputs), nullptr);
+
+  ASSIGN_OR_THROW_AND_RETURN_IF_ERROR(
+      webnn::OperandDescriptor output_descriptor,
+      webnn::ValidateScatterNDAndInferOutput(
+          ml_context_->GetProperties(), input->Descriptor(),
+          indices->Descriptor(), updates->Descriptor(),
+          options->label().Utf8()));
+
+  auto* scatter_nd = MakeGarbageCollected<MLOperator>(
+      this, webnn::mojom::blink::Operation::Tag::kScatterNd, options);
+  MLOperand* output =
+      MLOperand::CreateOutput(this, std::move(output_descriptor), scatter_nd);
+
+  scatter_nd->Connect(std::move(inputs), {output});
+  return output;
+}
+
 MLOperand* MLGraphBuilder::sigmoid(const MLOperand* input,
                                    const MLOperatorOptions* options,
                                    ExceptionState& exception_state) {
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.h b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.h
index 81eab85..32b874c 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.h
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.h
@@ -403,6 +403,12 @@
                         const MLResample2dOptions* options,
                         ExceptionState& exception_state);
 
+  MLOperand* scatterND(const MLOperand* input,
+                       const MLOperand* indices,
+                       const MLOperand* updates,
+                       const MLOperatorOptions* options,
+                       ExceptionState& exception_state);
+
   MLOperand* sigmoid(const MLOperand* input,
                      const MLOperatorOptions* options,
                      ExceptionState& exception_state);
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.idl b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.idl
index 3c9bd2d..b446d44 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.idl
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.idl
@@ -341,6 +341,8 @@
     RaisesException
   ] MLOperand resample2d(MLOperand input, optional MLResample2dOptions options = {});
 
+  [RaisesException] MLOperand scatterND(MLOperand input, MLOperand indices, MLOperand updates, optional MLOperatorOptions options = {});
+
   [RaisesException] MLOperand sigmoid(MLOperand input, optional MLOperatorOptions options = {});
 
   [RaisesException] MLOperand slice(MLOperand input, sequence<[EnforceRange] unsigned long> starts, sequence<[EnforceRange] unsigned long> sizes, optional MLOperatorOptions options = {});
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_test.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_test.cc
index 3b543e7b..ec94392 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_test.cc
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_test.cc
@@ -683,6 +683,8 @@
          /*relu_input=*/webnn::SupportedDataTypes::All(),
          /*resample2d_input=*/webnn::SupportedDataTypes::All(),
          /*reshape_input=*/webnn::SupportedDataTypes::All(),
+         /*scatter_nd_input=*/webnn::SupportedDataTypes::All(),
+         /*scatter_nd_indices=*/webnn::SupportedDataTypes::All(),
          /*sigmoid_input=*/webnn::SupportedDataTypes::All(),
          /*slice_input=*/webnn::SupportedDataTypes::All(),
          /*softmax_input=*/webnn::SupportedDataTypes::All(),
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_type_converter.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_type_converter.cc
index 5837cf60..e368b7f1 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_type_converter.cc
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_type_converter.cc
@@ -1504,6 +1504,25 @@
   return blink_mojom::Operation::NewReshape(std::move(reshape_mojo));
 }
 
+OperationPtr CreateScatterNDOperation(const OperandToIdMap& operand_to_id_map,
+                                      const MLOperator* scatter_nd) {
+  auto scatter_nd_mojo = webnn::mojom::blink::ScatterND::New();
+  scatter_nd_mojo->input_operand_id =
+      GetOperatorInputId(scatter_nd, operand_to_id_map, 0);
+  scatter_nd_mojo->indices_operand_id =
+      GetOperatorInputId(scatter_nd, operand_to_id_map, 1);
+  scatter_nd_mojo->updates_operand_id =
+      GetOperatorInputId(scatter_nd, operand_to_id_map, 2);
+  scatter_nd_mojo->output_operand_id =
+      GetOperatorOutputId(scatter_nd, operand_to_id_map);
+
+  const auto* options =
+      static_cast<const blink::MLOperatorOptions*>(scatter_nd->Options());
+  scatter_nd_mojo->label = options->label();
+  return webnn::mojom::blink::Operation::NewScatterNd(
+      std::move(scatter_nd_mojo));
+}
+
 OperationPtr CreateSigmoidOperation(const OperandToIdMap& operand_to_id_map,
                                     const MLOperator* sigmoid) {
   auto sigmoid_mojo = blink_mojom::Sigmoid::New();
@@ -1825,6 +1844,10 @@
       graph_info->operations.push_back(
           CreateReshapeOperation(operand_to_id_map, op));
       break;
+    case blink_mojom::Operation::Tag::kScatterNd:
+      graph_info->operations.push_back(
+          CreateScatterNDOperation(operand_to_id_map, op));
+      break;
     case blink_mojom::Operation::Tag::kSigmoid:
       graph_info->operations.push_back(
           CreateSigmoidOperation(operand_to_id_map, op));
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_operator.cc b/third_party/blink/renderer/modules/ml/webnn/ml_operator.cc
index c83264a..10d2dd5 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_operator.cc
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_operator.cc
@@ -220,6 +220,9 @@
     case webnn::mojom::blink::Operation::Tag::kResample2d:
       CHECK(absl::holds_alternative<absl::monostate>(sub_kind));
       return "resample2d";
+    case webnn::mojom::blink::Operation::Tag::kScatterNd:
+      CHECK(absl::holds_alternative<absl::monostate>(sub_kind));
+      return "scatterND";
     case webnn::mojom::blink::Operation::Tag::kSigmoid:
       CHECK(absl::holds_alternative<absl::monostate>(sub_kind));
       return "sigmoid";
diff --git a/third_party/blink/renderer/platform/fonts/font_platform_data.cc b/third_party/blink/renderer/platform/fonts/font_platform_data.cc
index 2f2681c81..edc5d5f 100644
--- a/third_party/blink/renderer/platform/fonts/font_platform_data.cc
+++ b/third_party/blink/renderer/platform/fonts/font_platform_data.cc
@@ -303,12 +303,11 @@
 
 #if !BUILDFLAG(IS_MAC) && !BUILDFLAG(IS_WIN) && !BUILDFLAG(IS_IOS)
 SkFont FontPlatformData::CreateSkFont(const FontDescription*) const {
-  SkFont font;
+  SkFont font(typeface_);
   style_.ApplyToSkFont(&font);
 
   const float ts = text_size_ >= 0 ? text_size_ : 12;
   font.setSize(SkFloatToScalar(ts));
-  font.setTypeface(typeface_);
   font.setEmbolden(synthetic_bold_);
   font.setSkewX(synthetic_italic_ ? -SK_Scalar1 / 4 : 0);
 
diff --git a/third_party/blink/renderer/platform/fonts/mac/font_platform_data_mac.mm b/third_party/blink/renderer/platform/fonts/mac/font_platform_data_mac.mm
index 600eec65..6c89197 100644
--- a/third_party/blink/renderer/platform/fonts/mac/font_platform_data_mac.mm
+++ b/third_party/blink/renderer/platform/fonts/mac/font_platform_data_mac.mm
@@ -245,7 +245,7 @@
     should_antialias = false;
   }
 
-  SkFont skfont;
+  SkFont skfont(typeface_);
   if (should_antialias && should_smooth_fonts) {
     skfont.setEdging(SkFont::Edging::kSubpixelAntiAlias);
   } else if (should_antialias) {
@@ -256,7 +256,6 @@
   skfont.setEmbeddedBitmaps(false);
   const float ts = text_size_ >= 0 ? text_size_ : 12;
   skfont.setSize(SkFloatToScalar(ts));
-  skfont.setTypeface(typeface_);
   skfont.setEmbolden(synthetic_bold_);
   skfont.setSkewX(synthetic_italic_ ? -SK_Scalar1 / 4 : 0);
   skfont.setSubpixel(should_subpixel_position);
diff --git a/third_party/blink/renderer/platform/fonts/win/font_platform_data_win.cc b/third_party/blink/renderer/platform/fonts/win/font_platform_data_win.cc
index c29bf911..5481dc09 100644
--- a/third_party/blink/renderer/platform/fonts/win/font_platform_data_win.cc
+++ b/third_party/blink/renderer/platform/fonts/win/font_platform_data_win.cc
@@ -41,9 +41,8 @@
 namespace blink {
 
 SkFont FontPlatformData::CreateSkFont(const FontDescription*) const {
-  SkFont font;
+  SkFont font(typeface_);
   font.setSize(SkFloatToScalar(text_size_));
-  font.setTypeface(typeface_);
   font.setEmbolden(synthetic_bold_);
   font.setSkewX(synthetic_italic_ ? -SK_Scalar1 / 4 : 0);
 
diff --git a/third_party/blink/renderer/platform/geometry/layout_point.h b/third_party/blink/renderer/platform/geometry/layout_point.h
index 2264786..b13faa4 100644
--- a/third_party/blink/renderer/platform/geometry/layout_point.h
+++ b/third_party/blink/renderer/platform/geometry/layout_point.h
@@ -68,9 +68,6 @@
   constexpr LayoutUnit X() const { return x_; }
   constexpr LayoutUnit Y() const { return y_; }
 
-  void SetX(LayoutUnit x) { x_ = x; }
-  void SetY(LayoutUnit y) { y_ = y; }
-
   WTF::String ToString() const;
 
  private:
diff --git a/third_party/blink/renderer/platform/geometry/layout_unit.h b/third_party/blink/renderer/platform/geometry/layout_unit.h
index cddf2d31..47e9ba9b 100644
--- a/third_party/blink/renderer/platform/geometry/layout_unit.h
+++ b/third_party/blink/renderer/platform/geometry/layout_unit.h
@@ -203,12 +203,6 @@
 
   // Convert to a `FixedPoint` with a different storage and/or precision.
   template <typename Target>
-    requires(Target::kIntegralBits >= kIntegralBits)
-  constexpr Target To() const {
-    return Target::template FromFixed<kFractionalBits>(RawValue());
-  }
-  template <typename Target>
-    requires(Target::kIntegralBits < kIntegralBits)
   constexpr Target To() const {
     return Target::template FromFixed<kFractionalBits>(RawValue());
   }
diff --git a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc
index 899217d2..ff6d1cbe 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc
@@ -81,11 +81,6 @@
   resource_host_ = host;
 }
 
-void Canvas2DLayerBridge::ResetResourceProvider() {
-  if (resource_host_)
-    resource_host_->ReplaceResourceProvider(nullptr);
-}
-
 // static
 void Canvas2DLayerBridge::HibernateOrLogFailure(
     base::WeakPtr<Canvas2DLayerBridge> bridge,
@@ -105,7 +100,6 @@
   CHECK(resource_host_);
   DCHECK(!IsHibernating());
   DCHECK(hibernation_scheduled_);
-  CHECK(resource_host_);
 
   hibernation_scheduled_ = false;
 
@@ -151,7 +145,7 @@
       std::move(sw_image),
       resource_host_->ResourceProvider()->ReleaseRecorder());
 
-  ResetResourceProvider();
+  resource_host_->ReplaceResourceProvider(nullptr);
   resource_host_->ClearLayerTexture();
 
   // shouldBeDirectComposited() may have changed.
diff --git a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.h b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.h
index c0999c3..e8d5a078 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.h
+++ b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.h
@@ -109,8 +109,6 @@
                                     base::TimeTicks /*idleDeadline*/);
   void Hibernate();
 
-  void ResetResourceProvider();
-
   CanvasHibernationHandler hibernation_handler_;
 
   std::unique_ptr<Logger> logger_;
diff --git a/third_party/blink/renderer/platform/loader/fetch/fetch_api_request_body_mojom_traits.cc b/third_party/blink/renderer/platform/loader/fetch/fetch_api_request_body_mojom_traits.cc
index c0ab2d4..52b1193b 100644
--- a/third_party/blink/renderer/platform/loader/fetch/fetch_api_request_body_mojom_traits.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/fetch_api_request_body_mojom_traits.cc
@@ -24,8 +24,8 @@
                                                        mutable_body) {
   scoped_refptr<network::ResourceRequestBody> network_body;
   if (auto form_body = mutable_body.FormBody()) {
-    CHECK_NE(blink::EncodedFormData::FormDataType::kInvalid,
-             form_body->GetType());
+    DUMP_WILL_BE_CHECK_NE(blink::EncodedFormData::FormDataType::kInvalid,
+                          form_body->GetType());
     // Here we need to keep the original body, because other members such as
     // `identifier` are on the form body.
     network_body =
@@ -115,8 +115,8 @@
     }
   }
 
-  CHECK_NE(blink::EncodedFormData::FormDataType::kInvalid,
-           form_data->GetType());
+  DUMP_WILL_BE_CHECK_NE(blink::EncodedFormData::FormDataType::kInvalid,
+                        form_data->GetType());
   form_data->identifier_ = in.identifier();
   form_data->contains_password_data_ = in.contains_sensitive_info();
   form_data->SetBoundary(
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
index 2787a88d..dffc40d 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
@@ -209,20 +209,7 @@
     const SecurityOrigin* settings_object_origin) {
   // Image, fonts, stylesheets and scripts are the most commonly reused scripts.
 
-  if (base::FeatureList::IsEnabled(
-          features::kMemoryCacheStrongReferenceFilterCrossOriginScripts) &&
-      resource->GetType() == ResourceType::kScript &&
-      !SecurityOrigin::Create(resource->Url())
-           ->IsSameOriginWith(settings_object_origin)) {
-    return false;
-  }
-
-  return (resource->GetType() == ResourceType::kImage &&
-          !base::FeatureList::IsEnabled(
-              features::kMemoryCacheStrongReferenceFilterImages)) ||
-         (resource->GetType() == ResourceType::kScript &&
-          !base::FeatureList::IsEnabled(
-              features::kMemoryCacheStrongReferenceFilterScripts)) ||
+  return resource->GetType() == ResourceType::kScript ||
          resource->GetType() == ResourceType::kFont ||
          resource->GetType() == ResourceType::kCSSStyleSheet ||
          resource->GetType() == ResourceType::kMock;  // For tests.
@@ -3058,9 +3045,9 @@
     return;
   }
 
-  static const size_t total_size_threshold = static_cast<size_t>(
+  const size_t total_size_threshold = static_cast<size_t>(
       features::kMemoryCacheStrongReferenceTotalSizeThresholdParam.Get());
-  static const size_t resource_size_threshold = static_cast<size_t>(
+  const size_t resource_size_threshold = static_cast<size_t>(
       features::kMemoryCacheStrongReferenceResourceSizeThresholdParam.Get());
   const size_t resource_size =
       static_cast<size_t>(resource->GetResponse().DecodedBodyLength());
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 3b259ca..596f32f0 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -1926,6 +1926,11 @@
       status: "experimental",
     },
     {
+      // crbug.com/40755728
+      name: "FindRubyInPage",
+      status: "test",
+    },
+    {
       name: "FindTextInReadonlyTextInput",
       status: "experimental",
     },
diff --git a/third_party/blink/web_tests/NeverFixTests b/third_party/blink/web_tests/NeverFixTests
index 52f5465..2289ade 100644
--- a/third_party/blink/web_tests/NeverFixTests
+++ b/third_party/blink/web_tests/NeverFixTests
@@ -1802,6 +1802,8 @@
 crbug.com/1500120 [ Win10.20h2 ] virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/conv_transpose2d.https.any.worker.html?gpu [ Skip ]
 crbug.com/1500120 [ Win10.20h2 ] virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/conv2d.https.any.html?gpu [ Skip ]
 crbug.com/1500120 [ Win10.20h2 ] virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/conv2d.https.any.worker.html?gpu [ Skip ]
+crbug.com/1500120 [ Win10.20h2 ] virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/dequantizeLinear.https.any.html?gpu [ Skip ]
+crbug.com/1500120 [ Win10.20h2 ] virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/dequantizeLinear.https.any.worker.html?gpu [ Skip ]
 crbug.com/1500120 [ Win10.20h2 ] virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/add.https.any.html?gpu [ Skip ]
 crbug.com/1500120 [ Win10.20h2 ] virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/add.https.any.worker.html?gpu [ Skip ]
 crbug.com/1500120 [ Win10.20h2 ] virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/sub.https.any.html?gpu [ Skip ]
@@ -1902,6 +1904,8 @@
 crbug.com/1500120 [ Win10.20h2 ] virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/pooling.https.any.worker.html?gpu [ Skip ]
 crbug.com/1500120 [ Win10.20h2 ] virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/prelu.https.any.html?gpu [ Skip ]
 crbug.com/1500120 [ Win10.20h2 ] virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/prelu.https.any.worker.html?gpu [ Skip ]
+crbug.com/1500120 [ Win10.20h2 ] virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/quantizeLinear.https.any.html?gpu [ Skip ]
+crbug.com/1500120 [ Win10.20h2 ] virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/quantizeLinear.https.any.worker.html?gpu [ Skip ]
 crbug.com/1500120 [ Win10.20h2 ] virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/reduce_l1.https.any.html?gpu [ Skip ]
 crbug.com/1500120 [ Win10.20h2 ] virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/reduce_l1.https.any.worker.html?gpu [ Skip ]
 crbug.com/1500120 [ Win10.20h2 ] virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/reduce_l2.https.any.html?gpu [ Skip ]
@@ -2042,6 +2046,8 @@
 crbug.com/1500120 [ Win10.20h2 ] virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/resample2d.https.any.worker.html?gpu [ Skip ]
 crbug.com/1500120 [ Win10.20h2 ] virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/reshape.https.any.html?gpu [ Skip ]
 crbug.com/1500120 [ Win10.20h2 ] virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/reshape.https.any.worker.html?gpu [ Skip ]
+crbug.com/1500120 [ Win10.20h2 ] virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/scatterND.https.any.html?gpu [ Skip ]
+crbug.com/1500120 [ Win10.20h2 ] virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/scatterND.https.any.worker.html?gpu [ Skip ]
 crbug.com/1500120 [ Win10.20h2 ] virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/sigmoid.https.any.html?gpu [ Skip ]
 crbug.com/1500120 [ Win10.20h2 ] virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/sigmoid.https.any.worker.html?gpu [ Skip ]
 crbug.com/1500120 [ Win10.20h2 ] virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/slice.https.any.html?gpu [ Skip ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 94b885a4f..f11fb050b 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -2626,9 +2626,8 @@
 
 # ====== New tests from wpt-importer added here ======
 [ Mac15 ] external/wpt/html/browsers/history/the-location-interface/location_hash_set_empty_string.html [ Failure Timeout ]
-[ Win11-arm64 ] external/wpt/html/browsers/history/the-location-interface/location_hash_set_empty_string.html [ Pass Failure Timeout ]
-[ Mac15 ] external/wpt/html/semantics/forms/the-select-element/stylable-select/switch-picker-appearance.tentative.html [ Timeout ]
-[ Linux ] external/wpt/html/semantics/forms/the-select-element/stylable-select/switch-picker-appearance.tentative.html [ Timeout Crash ]
+[ Win11-arm64 ] external/wpt/html/browsers/history/the-location-interface/location_hash_set_empty_string.html [ Failure Pass Timeout ]
+crbug.com/365828864 [ Linux ] external/wpt/html/semantics/forms/the-select-element/stylable-select/switch-picker-appearance.tentative.html [ Crash Timeout ]
 crbug.com/364935894 [ Mac14 ] external/wpt/webrtc-encoded-transform/RTCRtpScriptTransform-encoded-transform.https.html [ Timeout ]
 crbug.com/364935894 [ Mac12 ] external/wpt/webrtc-encoded-transform/RTCRtpScriptTransform-encoded-transform.https.html [ Timeout ]
 [ Linux ] wpt_internal/html/semantics/forms/the-select-element/stylable-select/select-only-picker-opt-in.tentative.html [ Failure ]
@@ -2835,6 +2834,7 @@
 crbug.com/345868498 [ Mac14 ] external/wpt/xhr/send-data-blob.htm [ Timeout ]
 crbug.com/345868498 [ Mac14 ] external/wpt/xhr/send-usp.any.worker.html [ Timeout ]
 crbug.com/358041221 [ Mac14 ] virtual/prefetch-reusable/external/wpt/speculation-rules/prefetch/no-vary-search/prefetch-single-with-hint.https.html?22-22 [ Timeout ]
+crbug.com/358041221 [ Mac14 ] virtual/prefetch-new-wait-loop/external/wpt/speculation-rules/prefetch/no-vary-search/prefetch-single-with-hint.https.html?22-22 [ Timeout ]
 crbug.com/345868499 [ Mac14 ] virtual/scalefactor200/external/wpt/css/filter-effects/effect-reference-lighting-no-light.tentative.html [ Failure Timeout ]
 crbug.com/345868497 [ Mac14 ] virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/concat.https.any.worker.html?cpu [ Skip Timeout ]
 crbug.com/345868497 [ Mac14 ] virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/reshape.https.any.worker.html?gpu [ Skip Timeout ]
@@ -4011,6 +4011,8 @@
 crbug.com/40854799 virtual/prefetch/http/tests/inspector-protocol/prefetch/request-will-be-sent-redirect.https.js [ Failure Pass ]
 crbug.com/40854799 virtual/prefetch-reusable/http/tests/inspector-protocol/prefetch/request-will-be-sent.https.js [ Failure Pass ]
 crbug.com/40854799 virtual/prefetch-reusable/http/tests/inspector-protocol/prefetch/request-will-be-sent-redirect.https.js [ Failure Pass ]
+crbug.com/40854799 virtual/prefetch-new-wait-loop/http/tests/inspector-protocol/prefetch/request-will-be-sent.https.js [ Failure Pass ]
+crbug.com/40854799 virtual/prefetch-new-wait-loop/http/tests/inspector-protocol/prefetch/request-will-be-sent-redirect.https.js [ Failure Pass ]
 crbug.com/40854799 virtual/prerender2-fallback-prefetch-spec-rules-prefetch/http/tests/inspector-protocol/prefetch/request-will-be-sent.https.js [ Failure Pass ]
 crbug.com/40854799 virtual/prerender2-fallback-prefetch-spec-rules-prefetch/http/tests/inspector-protocol/prefetch/request-will-be-sent-redirect.https.js [ Failure Pass ]
 
@@ -5529,15 +5531,7 @@
 # crbug.com/364924718). I anticipate that once the crashes are fixed, the behavior will still be
 # wrong, particularly in the case that `appearance` is changed on the picker once it's open. If
 # so, please file a bug for that case with details.
-crbug.com/364924715 [ Mac11 ] external/wpt/html/semantics/forms/the-select-element/stylable-select/switch-picker-appearance.tentative.html [ Crash ]
-crbug.com/364924715 [ Mac11-arm64 ] external/wpt/html/semantics/forms/the-select-element/stylable-select/switch-picker-appearance.tentative.html [ Crash ]
-crbug.com/364924715 [ Mac12 ] external/wpt/html/semantics/forms/the-select-element/stylable-select/switch-picker-appearance.tentative.html [ Crash ]
-crbug.com/364924715 [ Mac12-arm64 ] external/wpt/html/semantics/forms/the-select-element/stylable-select/switch-picker-appearance.tentative.html [ Crash ]
-crbug.com/364924715 [ Mac13 ] external/wpt/html/semantics/forms/the-select-element/stylable-select/switch-picker-appearance.tentative.html [ Crash ]
-crbug.com/364924715 [ Mac13-arm64 ] external/wpt/html/semantics/forms/the-select-element/stylable-select/switch-picker-appearance.tentative.html [ Crash ]
-crbug.com/364924715 [ Mac14 ] external/wpt/html/semantics/forms/the-select-element/stylable-select/switch-picker-appearance.tentative.html [ Crash ]
-crbug.com/364924715 [ Mac14-arm64 ] external/wpt/html/semantics/forms/the-select-element/stylable-select/switch-picker-appearance.tentative.html [ Crash ]
-crbug.com/364924715 [ Mac15-arm64 ] external/wpt/html/semantics/forms/the-select-element/stylable-select/switch-picker-appearance.tentative.html [ Crash ]
+crbug.com/364924715 [ Mac ] external/wpt/html/semantics/forms/the-select-element/stylable-select/switch-picker-appearance.tentative.html [ Crash ]
 crbug.com/364924715 [ Win ] external/wpt/html/semantics/forms/the-select-element/stylable-select/switch-picker-appearance.tentative.html [ Crash ]
 
 # Sheriff 2022-04-21
@@ -6760,6 +6754,7 @@
 
 crbug.com/1430516 virtual/prefetch/external/wpt/speculation-rules/prefetch/out-of-document-rule-set.https.html?include=* [ Failure Pass Timeout ]
 crbug.com/1430516 virtual/prefetch-reusable/external/wpt/speculation-rules/prefetch/out-of-document-rule-set.https.html?include=* [ Failure Pass Timeout ]
+crbug.com/1430516 virtual/prefetch-new-wait-loop/external/wpt/speculation-rules/prefetch/out-of-document-rule-set.https.html?include=* [ Failure Pass Timeout ]
 
 # Gardener 2023-07-27
 crbug.com/1468169 external/wpt/html/canvas/element/manual/drawing-text-to-the-canvas/canvas.2d.disconnected-font-size-math.html [ Failure Pass ]
@@ -7002,6 +6997,7 @@
 crbug.com/326067001 [ Win11-arm64 ] virtual/fedcm-authz/external/wpt/fedcm/fedcm-authz/fedcm-userinfo-after-resolve.https.html [ Failure Pass Timeout ] # Flaky
 crbug.com/326067598 [ Win11-arm64 ] virtual/fenced-frame-mparch/external/wpt/fenced-frame/set-automatic-beacon.https.html [ Failure Pass Timeout ] # Flaky
 crbug.com/326066872 [ Win11-arm64 ] virtual/prefetch-reusable/external/wpt/speculation-rules/prefetch/navigation-timing-requestStart-responseStart.https.html?prefetch=true [ Failure Pass Timeout ] # Flaky
+crbug.com/326066872 [ Win11-arm64 ] virtual/prefetch-new-wait-loop/external/wpt/speculation-rules/prefetch/navigation-timing-requestStart-responseStart.https.html?prefetch=true [ Failure Pass Timeout ] # Flaky
 crbug.com/40943541 [ Win11-arm64 ] external/wpt/webtransport/echo-large-bidirectional-streams.https.any.html [ Failure Pass Timeout ] # Flaky
 crbug.com/326123178 accessibility/selection-change-notification-on-selection-removed.html [ Failure Pass Timeout ] # Flaky
 crbug.com/326123298 virtual/third-party-cookie-phaseout-enabled/external/wpt/cookies/third-party-cookies/third-party-cookie-heuristics.tentative.https.html [ Failure Pass Timeout ]
@@ -8034,8 +8030,9 @@
 crbug.com/42202153 virtual/shared_array_buffer_on_desktop/external/wpt/wasm/jsapi/memory/type.tentative.any.worker.html [ Failure Pass ]
 
 # Gardener 2024-09-09
-crbug.com/365432212 virtual/prefetch-reusable/http/tests/inspector-protocol/prefetch/request-will-be-sent-redirect-cross-site.https.js [ Failure Pass ]
 crbug.com/365432212 virtual/prefetch/http/tests/inspector-protocol/prefetch/request-will-be-sent-redirect-cross-site.https.js [ Failure Pass ]
+crbug.com/365432212 virtual/prefetch-reusable/http/tests/inspector-protocol/prefetch/request-will-be-sent-redirect-cross-site.https.js [ Failure Pass ]
+crbug.com/365432212 virtual/prefetch-new-wait-loop/http/tests/inspector-protocol/prefetch/request-will-be-sent-redirect-cross-site.https.js [ Failure Pass ]
 crbug.com/365444428 [ Linux ] fast/events/middleClickAutoscroll-event-fired.html [ Failure Pass ]
 crbug.com/365487889 [ Mac13 ] shadow-dom/focus-navigation/focus-scroller-activeElement-on-event.html [ Failure Pass ]
 
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index a57d617..099fe8b 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -1795,20 +1795,6 @@
   },
 
   {
-    "prefix": "origin-agent-cluster-default-warning",
-    "owners": ["vogelheim@chromium.org", "wjmaclean@chromium.org"],
-    "platforms": ["Linux", "Mac", "Win"],
-    "bases": [ "wpt_internal/origin-agent-cluster-default-warning" ],
-    "exclusive_tests": "ALL",
-    "args": [
-      "--enable-features=OriginAgentClusterDefaultWarning",
-      "--disable-features=OriginAgentClusterDefaultEnable,OriginKeyedProcessesByDefault",
-      "--disable-auto-wpt-origin-isolation"
-    ],
-    "expires": "Jul 1, 2024"
-  },
-
-  {
     "prefix": "webauthn-remote-desktop-client-override",
     "owners": ["martinkr@chromium.org"],
     "platforms": ["Linux", "Mac", "Win"],
@@ -1900,6 +1886,21 @@
     "expires": "Oct 1, 2024"
   },
   {
+    "prefix": "prefetch-new-wait-loop",
+    "owners": ["kenoss@chromium.org"],
+    "platforms": ["Linux", "Mac", "Win"],
+    "bases": [
+      "external/wpt/speculation-rules/prefetch",
+      "http/tests/inspector-protocol/prefetch"
+    ],
+    "exclusive_tests": "ALL",
+    "args": [
+      "--enable-features=PrefetchUseContentRefactor:block_until_head_eager_prefetch/true/block_until_head_timeout_eager_prefetch/0,PrefetchCookieIndices,CookieIndicesHeader,PrefetchNewWaitLoop",
+      "--bypass-prefetch-proxy-for-host=not-web-platform.test"
+    ],
+    "expires": "March 9, 2025"
+  },
+  {
     "prefix": "prefetch-no-vary-search",
     "owners": ["jbroman@chromium.org", "liviutinta@chromium.org"],
     "platforms": ["Linux", "Mac", "Win"],
@@ -2436,6 +2437,8 @@
       "external/wpt/webnn/conformance_tests/cos.https.any.worker.html?gpu",
       "external/wpt/webnn/conformance_tests/div.https.any.html?gpu",
       "external/wpt/webnn/conformance_tests/div.https.any.worker.html?gpu",
+      "external/wpt/webnn/conformance_tests/dequantizeLinear.https.any.html?gpu",
+      "external/wpt/webnn/conformance_tests/dequantizeLinear.https.any.worker.html?gpu",
       "external/wpt/webnn/conformance_tests/elu.https.any.html?gpu",
       "external/wpt/webnn/conformance_tests/elu.https.any.worker.html?gpu",
       "external/wpt/webnn/conformance_tests/equal.https.any.html?gpu",
@@ -2512,6 +2515,8 @@
       "external/wpt/webnn/conformance_tests/pow.https.any.worker.html?gpu",
       "external/wpt/webnn/conformance_tests/prelu.https.any.html?gpu",
       "external/wpt/webnn/conformance_tests/prelu.https.any.worker.html?gpu",
+      "external/wpt/webnn/conformance_tests/quantizeLinear.https.any.html?gpu",
+      "external/wpt/webnn/conformance_tests/quantizeLinear.https.any.worker.html?gpu",
       "external/wpt/webnn/conformance_tests/reciprocal.https.any.html?gpu",
       "external/wpt/webnn/conformance_tests/reciprocal.https.any.worker.html?gpu",
       "external/wpt/webnn/conformance_tests/reduce_l1.https.any.html?gpu",
@@ -2666,6 +2671,8 @@
       "external/wpt/webnn/validation_tests/resample2d.https.any.worker.html?gpu",
       "external/wpt/webnn/validation_tests/reshape.https.any.html?gpu",
       "external/wpt/webnn/validation_tests/reshape.https.any.worker.html?gpu",
+      "external/wpt/webnn/validation_tests/scatterND.https.any.html?gpu",
+      "external/wpt/webnn/validation_tests/scatterND.https.any.worker.html?gpu",
       "external/wpt/webnn/validation_tests/sigmoid.https.any.html?gpu",
       "external/wpt/webnn/validation_tests/sigmoid.https.any.worker.html?gpu",
       "external/wpt/webnn/validation_tests/slice.https.any.html?gpu",
@@ -2736,6 +2743,8 @@
       "external/wpt/webnn/conformance_tests/cos.https.any.worker.html?cpu",
       "external/wpt/webnn/conformance_tests/div.https.any.html?cpu",
       "external/wpt/webnn/conformance_tests/div.https.any.worker.html?cpu",
+      "external/wpt/webnn/conformance_tests/dequantizeLinear.https.any.html?cpu",
+      "external/wpt/webnn/conformance_tests/dequantizeLinear.https.any.worker.html?cpu",
       "external/wpt/webnn/conformance_tests/elu.https.any.html?cpu",
       "external/wpt/webnn/conformance_tests/elu.https.any.worker.html?cpu",
       "external/wpt/webnn/conformance_tests/equal.https.any.html?cpu",
@@ -2812,6 +2821,8 @@
       "external/wpt/webnn/conformance_tests/pow.https.any.worker.html?cpu",
       "external/wpt/webnn/conformance_tests/prelu.https.any.html?cpu",
       "external/wpt/webnn/conformance_tests/prelu.https.any.worker.html?cpu",
+      "external/wpt/webnn/conformance_tests/quantizeLinear.https.any.html?cpu",
+      "external/wpt/webnn/conformance_tests/quantizeLinear.https.any.worker.html?cpu",
       "external/wpt/webnn/conformance_tests/reciprocal.https.any.html?cpu",
       "external/wpt/webnn/conformance_tests/reciprocal.https.any.worker.html?cpu",
       "external/wpt/webnn/conformance_tests/reduce_l1.https.any.html?cpu",
@@ -2966,6 +2977,8 @@
       "external/wpt/webnn/validation_tests/resample2d.https.any.worker.html?cpu",
       "external/wpt/webnn/validation_tests/reshape.https.any.html?cpu",
       "external/wpt/webnn/validation_tests/reshape.https.any.worker.html?cpu",
+      "external/wpt/webnn/validation_tests/scatterND.https.any.html?cpu",
+      "external/wpt/webnn/validation_tests/scatterND.https.any.worker.html?cpu",
       "external/wpt/webnn/validation_tests/sigmoid.https.any.html?cpu",
       "external/wpt/webnn/validation_tests/sigmoid.https.any.worker.html?cpu",
       "external/wpt/webnn/validation_tests/slice.https.any.html?cpu",
@@ -3034,6 +3047,8 @@
       "external/wpt/webnn/conformance_tests/cos.https.any.worker.html?npu",
       "external/wpt/webnn/conformance_tests/div.https.any.html?npu",
       "external/wpt/webnn/conformance_tests/div.https.any.worker.html?npu",
+      "external/wpt/webnn/conformance_tests/dequantizeLinear.https.any.html?npu",
+      "external/wpt/webnn/conformance_tests/dequantizeLinear.https.any.worker.html?npu",
       "external/wpt/webnn/conformance_tests/elu.https.any.html?npu",
       "external/wpt/webnn/conformance_tests/elu.https.any.worker.html?npu",
       "external/wpt/webnn/conformance_tests/equal.https.any.html?npu",
@@ -3110,6 +3125,8 @@
       "external/wpt/webnn/conformance_tests/pow.https.any.worker.html?npu",
       "external/wpt/webnn/conformance_tests/prelu.https.any.html?npu",
       "external/wpt/webnn/conformance_tests/prelu.https.any.worker.html?npu",
+      "external/wpt/webnn/conformance_tests/quantizeLinear.https.any.html?npu",
+      "external/wpt/webnn/conformance_tests/quantizeLinear.https.any.worker.html?npu",
       "external/wpt/webnn/conformance_tests/reciprocal.https.any.html?npu",
       "external/wpt/webnn/conformance_tests/reciprocal.https.any.worker.html?npu",
       "external/wpt/webnn/conformance_tests/reduce_l1.https.any.html?npu",
@@ -3264,6 +3281,8 @@
       "external/wpt/webnn/validation_tests/resample2d.https.any.worker.html?npu",
       "external/wpt/webnn/validation_tests/reshape.https.any.html?npu",
       "external/wpt/webnn/validation_tests/reshape.https.any.worker.html?npu",
+      "external/wpt/webnn/validation_tests/scatterND.https.any.html?npu",
+      "external/wpt/webnn/validation_tests/scatterND.https.any.worker.html?npu",
       "external/wpt/webnn/validation_tests/sigmoid.https.any.html?npu",
       "external/wpt/webnn/validation_tests/sigmoid.https.any.worker.html?npu",
       "external/wpt/webnn/validation_tests/slice.https.any.html?npu",
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
index 4389466..2a7e0d9 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -7324,6 +7324,13 @@
         {}
        ]
       ],
+      "popover-hint-crash.tentative.html": [
+       "3de269952624db643f21260ac9a2cb659f5c212c",
+       [
+        null,
+        {}
+       ]
+      ],
       "popover-undefined-remove-crash.html": [
        "3c273ea6f344d179a3d010d20f0779b3721abb40",
        [
@@ -201925,6 +201932,19 @@
         {}
        ]
       ],
+      "break-spaces-with-word-break-001.html": [
+       "ee31fd627130eeb40fd22d0b9bc4fa6e9eb3aca7",
+       [
+        null,
+        [
+         [
+          "/css/reference/ref-filled-green-100px-square.xht",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
       "control-chars-000.html": [
        "b038fe9a90d3b8b9cb3bde7fd46396c7121688c9",
        [
@@ -293959,6 +293979,19 @@
         {}
        ]
       ],
+      "non-scaling-stroke-007.html": [
+       "2b63060466d2e896550e0fa6123c9901a4da3af5",
+       [
+        null,
+        [
+         [
+          "/svg/painting/reftests/non-scaling-stroke-007-ref.html",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
       "paint-context-001.svg": [
        "7be33cb20fb257496cb1357a5481edecf364bc59",
        [
@@ -317261,7 +317294,7 @@
       []
      ],
      "at-scope-parsing-expected.txt": [
-      "3a81a4319e364017b2e0c42fb1dcbdf44f02d19b",
+      "c6367d429aded93ff3f5001169b98f85d8962d70",
       []
      ],
      "at-scope-relative-syntax-expected.txt": [
@@ -317678,7 +317711,7 @@
        []
       ],
       "color-valid-color-function-expected.txt": [
-       "feecea5228320f0eaf354aa372cacace2a641e74",
+       "0f183453e8ce850e92773134ee45d28e567d3138",
        []
       ],
       "color-valid-color-layers-function-expected.txt": [
@@ -317694,7 +317727,7 @@
        []
       ],
       "color-valid-lab-expected.txt": [
-       "63777f48cfb7355b8d5e2ddb6a2cdf5acea67c1f",
+       "b2e65ec2311faa47a862a98f1da4e007b84bcaac",
        []
       ],
       "color-valid-relative-color-expected.txt": [
@@ -317702,7 +317735,7 @@
        []
       ],
       "color-valid-rgb-expected.txt": [
-       "c4fd42d02165b14026174125309c4d1a48492c81",
+       "c56ec0b4d8c756544b7b5751579dfa11ec0f28ab",
        []
       ],
       "opacity-valid-expected.txt": [
@@ -374220,7 +374253,7 @@
        []
       ],
       "gentestutilsunion.py": [
-       "84315af983beb97592d2d8a3e42d3a8b81465292",
+       "183a6f6e3955389b4b783b7287846399fc825e9e",
        []
       ],
       "name2dir-canvas.yaml": [
@@ -394016,7 +394049,7 @@
      []
     ],
     "OWNERS": [
-     "538d4ae006c5e74bb29194eb2394da1019203075",
+     "feb07145694d1fe5d698a9464a77d810f841cf2c",
      []
     ],
     "partitioned-popins.permission-all.tentative.sub.https.window.js.headers": [
@@ -403482,6 +403515,10 @@
       "4b63200cddb0f0884630cfdde99be81ec35c1274",
       []
      ],
+     "WEB_FEATURES.yml": [
+      "f14b4c0f51e47396faad24747bd58015c0c3c262",
+      []
+     ],
      "resources": {
       "cached-resource.txt": [
        "c57eff55ebc0c54973903af5f72bac72762cf4f4",
@@ -404849,6 +404886,10 @@
        "d4cc4a6e4eacfdb2e53072f067adef117461ad64",
        []
       ],
+      "non-scaling-stroke-007-ref.html": [
+       "d0f84d73fc046ee38bcadb098d7b9e135286d761",
+       []
+      ],
       "paint-context-001-ref.svg": [
        "99bd8c44cb78a4b0340ad6456c7e58e4ca397257",
        []
@@ -447582,6 +447623,13 @@
      ]
     },
     "img-src": {
+     "css-filter-blocked.tentative.html": [
+      "2c9c94063cea87af1581db202dd419ac1b4ecf3e",
+      [
+       null,
+       {}
+      ]
+     ],
      "icon-allowed.sub.html": [
       "5c8ecdee1382c57d04af850517f88b588eaeb6d5",
       [
@@ -447658,6 +447706,13 @@
        null,
        {}
       ]
+     ],
+     "svg-use-blocked.tentative.html": [
+      "2c548cf219838e50c366d5f60d3fe967ba79309a",
+      [
+       null,
+       {}
+      ]
      ]
     },
     "inheritance": {
@@ -459136,7 +459191,7 @@
       ]
      ],
      "at-scope-parsing.html": [
-      "e984c1dcc29e1fe1fe199b16f6eafdb5403d1a2b",
+      "18a4b122536f448016e169e989816312103a9cd4",
       [
        null,
        {}
@@ -459499,7 +459554,7 @@
       ]
      ],
      "scope-nesting.html": [
-      "c0fc7150fae00ad279b89c07d3a1be076eec9c5f",
+      "2af8fd1a74e94598ef74649f981edb352101ce1c",
       [
        null,
        {}
@@ -459686,7 +459741,7 @@
        ]
       ],
       "color-computed-relative-color.html": [
-       "83806e23a6afb9e3f24a5aae1b000ea431e61d08",
+       "8407e527017ec0440e90d5cbacfc5bcc0569907d",
        [
         null,
         {}
@@ -459791,7 +459846,7 @@
        ]
       ],
       "color-valid-color-function.html": [
-       "d9202a1bc5e3bc9bdc03264cf6f41d470bcfea2b",
+       "bfc932104e5b26611a2b65a15d58d6d6bc219acf",
        [
         null,
         {}
@@ -459812,21 +459867,21 @@
        ]
       ],
       "color-valid-hsl.html": [
-       "b60cd7446909ce8d7d4252a48bd0838cbc8072c7",
+       "a9d2a7b887015cdbdff8f0268549ae4c197abe0c",
        [
         null,
         {}
        ]
       ],
       "color-valid-hwb.html": [
-       "1f9799eade3d1ee149028a28451aa629fd727c26",
+       "007f4be876f35db8668792f1c32c477e5ba441d0",
        [
         null,
         {}
        ]
       ],
       "color-valid-lab.html": [
-       "ffa3b553882698b9b3f668680613a69cd8683fae",
+       "a085bfb4710ce5bb147e9cc049664ec6805562b8",
        [
         null,
         {}
@@ -459840,7 +459895,7 @@
        ]
       ],
       "color-valid-rgb.html": [
-       "6c9f49d6cd68f8c0ce62d6c9ddf7a5d0b1121bba",
+       "36487c3965aa404a898e0db906b36cb8ca9d4a9d",
        [
         null,
         {}
@@ -464727,6 +464782,13 @@
        {}
       ]
      ],
+     "font-style-sign-function.html": [
+      "977991e365ee655c3bf127516321c20c750fe5a4",
+      [
+       null,
+       {}
+      ]
+     ],
      "font-variant-alternates-parsing.html": [
       "216ed0dba04772c28e4436b4c5f70e9ace2faaa2",
       [
@@ -478012,6 +478074,13 @@
         null,
         {}
        ]
+      ],
+      "sign-function-aspect-ratio.html": [
+       "e5ba1a8321a42918cccee4ee164527fa25078e4f",
+       [
+        null,
+        {}
+       ]
       ]
      },
      "aspect-ratio-affects-container-width-when-height-changes.html": [
@@ -537105,7 +537174,7 @@
    },
    "file-system-access": {
     "getDirectory.https.any.js": [
-     "6921ab6fc3b263db0badf6d8d106d422b4d23dbd",
+     "69fd01597d3f03dde5f86203d6cea144d5a05218",
      [
       "file-system-access/getDirectory.https.any.html",
       {
@@ -610403,7 +610472,7 @@
      ]
     ],
     "idle-detection-detached-frame.https.html": [
-     "062499b54d6ce4fffba9f612ddbf4ed9a81e93c6",
+     "269af145cb76778312a860e62a9c6dc73f6fa1f0",
      [
       null,
       {
@@ -686592,7 +686661,7 @@
      ]
     ],
     "audio-decoder.https.any.js": [
-     "98ed49897d30461ca7e4f0652a69f6690c9ab043",
+     "fd828d481571d80eff7ddd5cc389cf13ffc659dd",
      [
       "webcodecs/audio-decoder.https.any.html",
       {
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/img-src/css-filter-blocked.tentative.html b/third_party/blink/web_tests/external/wpt/content-security-policy/img-src/css-filter-blocked.tentative.html
new file mode 100644
index 0000000..2c9c940
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/content-security-policy/img-src/css-filter-blocked.tentative.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta http-equiv="Content-Security-Policy" content="img-src 'none'">
+    <title>SVG in CSS filter: blocked as img</title>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script>
+      async_test(t => {
+        window.addEventListener('securitypolicyviolation',
+                                t.step_func_done(e => {
+          assert_equals(e.effectiveDirective, "img-src");
+          assert_true(e.blockedURI.endsWith("filter.svg"));
+        }));
+      }, "Blocked CSS filter: SVG");
+    </script>
+    <link rel="stylesheet" href="resources/blue.css">
+</head>
+<body>
+  <style>
+    body {
+      filter: url("filter.svg#bar");
+    }
+  </style>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/img-src/svg-use-blocked.tentative.html b/third_party/blink/web_tests/external/wpt/content-security-policy/img-src/svg-use-blocked.tentative.html
new file mode 100644
index 0000000..2c548cf
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/content-security-policy/img-src/svg-use-blocked.tentative.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta http-equiv="Content-Security-Policy" content="img-src 'none'">
+    <title>SVG use blocked as img</title>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script>
+      async_test(t => {
+        window.addEventListener('securitypolicyviolation',
+                                t.step_func_done(e => {
+          assert_equals(e.effectiveDirective, "img-src");
+          assert_true(e.blockedURI.endsWith("use.svg"));
+        }));
+      }, "Blocked SVG <use> element");
+    </script>
+    <link rel="stylesheet" href="resources/blue.css">
+</head>
+<body>
+  <svg>
+    <use href="use.svg#bar"></use>
+  </svg>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-cascade/at-scope-parsing-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-cascade/at-scope-parsing-expected.txt
index 3a81a43..c6367d42 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-cascade/at-scope-parsing-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/css/css-cascade/at-scope-parsing-expected.txt
@@ -3,21 +3,21 @@
   assert_equals: expected "@scope {\\n}" but got "@scope () {\\n}"
 [FAIL] @scope () to () is valid
   assert_equals: expected "@scope {\\n}" but got "@scope () {\\n}"
-[FAIL] @scope (.c <> .d) is valid
-  assert_equals: expected "@scope (.c <> .d) {\\n}" but got "@scope () {\\n}"
-[FAIL] @scope (.a, .c <> .d) is valid
-  assert_equals: expected "@scope (.a, .c <> .d) {\\n}" but got "@scope (.a) {\\n}"
-[FAIL] @scope (.a <> .b, .c) is valid
-  assert_equals: expected "@scope (.a <> .b, .c) {\\n}" but got "@scope (.c) {\\n}"
-[FAIL] @scope (div::before) is valid
-  assert_equals: expected "@scope (div::before) {\\n}" but got "@scope () {\\n}"
-[FAIL] @scope (div::after) is valid
-  assert_equals: expected "@scope (div::after) {\\n}" but got "@scope () {\\n}"
-[FAIL] @scope (slotted(div)) is valid
-  assert_equals: expected "@scope (slotted(div)) {\\n}" but got "@scope () {\\n}"
-[FAIL] @scope (.a) to (div::before) is valid
-  assert_equals: expected "@scope (.a) to (div::before) {\\n}" but got "@scope (.a) {\\n}"
-[FAIL] @scope (> &) to (>>) is valid
-  assert_equals: expected "@scope (> &) to (>>) {\\n}" but got "@scope (> &) {\\n}"
+[FAIL] @scope (.c <> .d) is not valid
+  assert_equals: expected 0 but got 1
+[FAIL] @scope (.a, .c <> .d) is not valid
+  assert_equals: expected 0 but got 1
+[FAIL] @scope (.a <> .b, .c) is not valid
+  assert_equals: expected 0 but got 1
+[FAIL] @scope (div::before) is not valid
+  assert_equals: expected 0 but got 1
+[FAIL] @scope (div::after) is not valid
+  assert_equals: expected 0 but got 1
+[FAIL] @scope (slotted(div)) is not valid
+  assert_equals: expected 0 but got 1
+[FAIL] @scope (.a) to (div::before) is not valid
+  assert_equals: expected 0 but got 1
+[FAIL] @scope (> &) to (>>) is not valid
+  assert_equals: expected 0 but got 1
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-cascade/at-scope-parsing.html b/third_party/blink/web_tests/external/wpt/css/css-cascade/at-scope-parsing.html
index e984c1d..18a4b12 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-cascade/at-scope-parsing.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-cascade/at-scope-parsing.html
@@ -49,16 +49,14 @@
   test_valid('@scope to ()', '@scope');
   test_valid('@scope () to ()', '@scope');
 
-  // Forgiving behavior (keep invalid selector as-is for the serialization):
-  test_valid('@scope (.c <> .d)');
-  test_valid('@scope (.a, .c <> .d)');
-  test_valid('@scope (.a <> .b, .c)');
-  test_valid('@scope (div::before)');
-  test_valid('@scope (div::after)');
-  test_valid('@scope (slotted(div))');
-  test_valid('@scope (.a) to (div::before)');
-  test_valid('@scope (> &) to (>>)');
-
+  test_invalid('@scope (.c <> .d)');
+  test_invalid('@scope (.a, .c <> .d)');
+  test_invalid('@scope (.a <> .b, .c)');
+  test_invalid('@scope (div::before)');
+  test_invalid('@scope (div::after)');
+  test_invalid('@scope (slotted(div))');
+  test_invalid('@scope (.a) to (div::before)');
+  test_invalid('@scope (> &) to (>>)');
   test_invalid('@scope div');
   test_invalid('@scope (.a) unknown (.c)');
   test_invalid('@scope (.a) to unknown (.c)');
diff --git a/third_party/blink/web_tests/external/wpt/css/css-cascade/scope-nesting.html b/third_party/blink/web_tests/external/wpt/css/css-cascade/scope-nesting.html
index c0fc715..2af8fd1a 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-cascade/scope-nesting.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-cascade/scope-nesting.html
@@ -542,3 +542,37 @@
   assert_equals(getComputedStyle(b_inside).zIndex, '1');
 }, 'Scoped nested group rule');
 </script>
+
+<template id=test_scoped_within_scoped>
+  <div>
+    <style>
+      @scope (.a) {
+        @scope(#descendant) {
+          :scope {
+            z-index: 1;
+          }
+        }
+        @scope (> #child) {
+          :scope {
+            z-index: 1;
+          }
+        }
+      }
+    </style>
+    <div class="a">
+      <div id="descendant">
+      </div>
+      <div id="child">
+      </div>
+    </div>
+</div>
+</template>
+<script>
+test((t) => {
+  t.add_cleanup(() => main.replaceChildren());
+  main.append(test_scoped_within_scoped.content.cloneNode(true));
+
+  assert_equals(getComputedStyle(descendant).zIndex, '1');
+  assert_equals(getComputedStyle(child).zIndex, '1');
+}, 'Scoped nested within another scope');
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-valid-color-function-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-valid-color-function-expected.txt
index feecea5..0f183453 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-valid-color-function-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-valid-color-function-expected.txt
@@ -1,40 +1,94 @@
 This is a testharness.js-based test.
-Found 18 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 45 FAIL, 0 TIMEOUT, 0 NOTRUN.
+[FAIL] e.style['color'] = "color(srgb calc(0.5 + 1) calc(0.5 - 1) calc(0.5) / calc(-0.5 + 1))" should set the property value
+  assert_equals: serialization should be canonical expected "color(srgb calc(1.5) calc(-0.5) calc(0.5) / calc(0.5))" but got "color(srgb 1.5 -0.5 0.5 / 0.5)"
+[FAIL] e.style['color'] = "color(srgb calc(50% * 3) calc(-150% / 3) calc(50%) / calc(-50% * 3))" should set the property value
+  assert_equals: serialization should be canonical expected "color(srgb calc(150%) calc(-50%) calc(50%) / calc(-150%))" but got "color(srgb 1.5 -0.5 0.5 / 0)"
+[FAIL] e.style['color'] = "color(srgb calc(50%) 50% 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "color(srgb calc(50%) 0.5 0.5)" but got "color(srgb 0.5 0.5 0.5)"
 [FAIL] e.style['color'] = "color(srgb calc(50% + (sign(1em - 10px) * 10%)) 0 0 / 0.5)" should set the property value
   assert_equals: serialization should be canonical expected "color(srgb calc(50% + (10% * sign(1em - 10px))) 0 0 / 0.5)" but got "color(srgb 0.4 0 0 / 0.5)"
 [FAIL] e.style['color'] = "color(srgb 0.5 0 0 / calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
   assert_equals: serialization should be canonical expected "color(srgb 0.5 0 0 / calc(50% + (10% * sign(1em - 10px))))" but got "color(srgb 0.5 0 0 / 0.4)"
+[FAIL] e.style['color'] = "color(srgb-linear calc(0.5 + 1) calc(0.5 - 1) calc(0.5) / calc(-0.5 + 1))" should set the property value
+  assert_equals: serialization should be canonical expected "color(srgb-linear calc(1.5) calc(-0.5) calc(0.5) / calc(0.5))" but got "color(srgb-linear 1.5 -0.5 0.5 / 0.5)"
+[FAIL] e.style['color'] = "color(srgb-linear calc(50% * 3) calc(-150% / 3) calc(50%) / calc(-50% * 3))" should set the property value
+  assert_equals: serialization should be canonical expected "color(srgb-linear calc(150%) calc(-50%) calc(50%) / calc(-150%))" but got "color(srgb-linear 1.5 -0.5 0.5 / 0)"
+[FAIL] e.style['color'] = "color(srgb-linear calc(50%) 50% 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "color(srgb-linear calc(50%) 0.5 0.5)" but got "color(srgb-linear 0.5 0.5 0.5)"
 [FAIL] e.style['color'] = "color(srgb-linear calc(50% + (sign(1em - 10px) * 10%)) 0 0 / 0.5)" should set the property value
   assert_equals: serialization should be canonical expected "color(srgb-linear calc(50% + (10% * sign(1em - 10px))) 0 0 / 0.5)" but got "color(srgb-linear 0.4 0 0 / 0.5)"
 [FAIL] e.style['color'] = "color(srgb-linear 0.5 0 0 / calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
   assert_equals: serialization should be canonical expected "color(srgb-linear 0.5 0 0 / calc(50% + (10% * sign(1em - 10px))))" but got "color(srgb-linear 0.5 0 0 / 0.4)"
+[FAIL] e.style['color'] = "color(a98-rgb calc(0.5 + 1) calc(0.5 - 1) calc(0.5) / calc(-0.5 + 1))" should set the property value
+  assert_equals: serialization should be canonical expected "color(a98-rgb calc(1.5) calc(-0.5) calc(0.5) / calc(0.5))" but got "color(a98-rgb 1.5 -0.5 0.5 / 0.5)"
+[FAIL] e.style['color'] = "color(a98-rgb calc(50% * 3) calc(-150% / 3) calc(50%) / calc(-50% * 3))" should set the property value
+  assert_equals: serialization should be canonical expected "color(a98-rgb calc(150%) calc(-50%) calc(50%) / calc(-150%))" but got "color(a98-rgb 1.5 -0.5 0.5 / 0)"
+[FAIL] e.style['color'] = "color(a98-rgb calc(50%) 50% 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "color(a98-rgb calc(50%) 0.5 0.5)" but got "color(a98-rgb 0.5 0.5 0.5)"
 [FAIL] e.style['color'] = "color(a98-rgb calc(50% + (sign(1em - 10px) * 10%)) 0 0 / 0.5)" should set the property value
   assert_equals: serialization should be canonical expected "color(a98-rgb calc(50% + (10% * sign(1em - 10px))) 0 0 / 0.5)" but got "color(a98-rgb 0.4 0 0 / 0.5)"
 [FAIL] e.style['color'] = "color(a98-rgb 0.5 0 0 / calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
   assert_equals: serialization should be canonical expected "color(a98-rgb 0.5 0 0 / calc(50% + (10% * sign(1em - 10px))))" but got "color(a98-rgb 0.5 0 0 / 0.4)"
+[FAIL] e.style['color'] = "color(rec2020 calc(0.5 + 1) calc(0.5 - 1) calc(0.5) / calc(-0.5 + 1))" should set the property value
+  assert_equals: serialization should be canonical expected "color(rec2020 calc(1.5) calc(-0.5) calc(0.5) / calc(0.5))" but got "color(rec2020 1.5 -0.5 0.5 / 0.5)"
+[FAIL] e.style['color'] = "color(rec2020 calc(50% * 3) calc(-150% / 3) calc(50%) / calc(-50% * 3))" should set the property value
+  assert_equals: serialization should be canonical expected "color(rec2020 calc(150%) calc(-50%) calc(50%) / calc(-150%))" but got "color(rec2020 1.5 -0.5 0.5 / 0)"
+[FAIL] e.style['color'] = "color(rec2020 calc(50%) 50% 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "color(rec2020 calc(50%) 0.5 0.5)" but got "color(rec2020 0.5 0.5 0.5)"
 [FAIL] e.style['color'] = "color(rec2020 calc(50% + (sign(1em - 10px) * 10%)) 0 0 / 0.5)" should set the property value
   assert_equals: serialization should be canonical expected "color(rec2020 calc(50% + (10% * sign(1em - 10px))) 0 0 / 0.5)" but got "color(rec2020 0.4 0 0 / 0.5)"
 [FAIL] e.style['color'] = "color(rec2020 0.5 0 0 / calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
   assert_equals: serialization should be canonical expected "color(rec2020 0.5 0 0 / calc(50% + (10% * sign(1em - 10px))))" but got "color(rec2020 0.5 0 0 / 0.4)"
+[FAIL] e.style['color'] = "color(prophoto-rgb calc(0.5 + 1) calc(0.5 - 1) calc(0.5) / calc(-0.5 + 1))" should set the property value
+  assert_equals: serialization should be canonical expected "color(prophoto-rgb calc(1.5) calc(-0.5) calc(0.5) / calc(0.5))" but got "color(prophoto-rgb 1.5 -0.5 0.5 / 0.5)"
+[FAIL] e.style['color'] = "color(prophoto-rgb calc(50% * 3) calc(-150% / 3) calc(50%) / calc(-50% * 3))" should set the property value
+  assert_equals: serialization should be canonical expected "color(prophoto-rgb calc(150%) calc(-50%) calc(50%) / calc(-150%))" but got "color(prophoto-rgb 1.5 -0.5 0.5 / 0)"
+[FAIL] e.style['color'] = "color(prophoto-rgb calc(50%) 50% 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "color(prophoto-rgb calc(50%) 0.5 0.5)" but got "color(prophoto-rgb 0.5 0.5 0.5)"
 [FAIL] e.style['color'] = "color(prophoto-rgb calc(50% + (sign(1em - 10px) * 10%)) 0 0 / 0.5)" should set the property value
   assert_equals: serialization should be canonical expected "color(prophoto-rgb calc(50% + (10% * sign(1em - 10px))) 0 0 / 0.5)" but got "color(prophoto-rgb 0.4 0 0 / 0.5)"
 [FAIL] e.style['color'] = "color(prophoto-rgb 0.5 0 0 / calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
   assert_equals: serialization should be canonical expected "color(prophoto-rgb 0.5 0 0 / calc(50% + (10% * sign(1em - 10px))))" but got "color(prophoto-rgb 0.5 0 0 / 0.4)"
+[FAIL] e.style['color'] = "color(display-p3 calc(0.5 + 1) calc(0.5 - 1) calc(0.5) / calc(-0.5 + 1))" should set the property value
+  assert_equals: serialization should be canonical expected "color(display-p3 calc(1.5) calc(-0.5) calc(0.5) / calc(0.5))" but got "color(display-p3 1.5 -0.5 0.5 / 0.5)"
+[FAIL] e.style['color'] = "color(display-p3 calc(50% * 3) calc(-150% / 3) calc(50%) / calc(-50% * 3))" should set the property value
+  assert_equals: serialization should be canonical expected "color(display-p3 calc(150%) calc(-50%) calc(50%) / calc(-150%))" but got "color(display-p3 1.5 -0.5 0.5 / 0)"
+[FAIL] e.style['color'] = "color(display-p3 calc(50%) 50% 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "color(display-p3 calc(50%) 0.5 0.5)" but got "color(display-p3 0.5 0.5 0.5)"
 [FAIL] e.style['color'] = "color(display-p3 calc(50% + (sign(1em - 10px) * 10%)) 0 0 / 0.5)" should set the property value
   assert_equals: serialization should be canonical expected "color(display-p3 calc(50% + (10% * sign(1em - 10px))) 0 0 / 0.5)" but got "color(display-p3 0.4 0 0 / 0.5)"
 [FAIL] e.style['color'] = "color(display-p3 0.5 0 0 / calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
   assert_equals: serialization should be canonical expected "color(display-p3 0.5 0 0 / calc(50% + (10% * sign(1em - 10px))))" but got "color(display-p3 0.5 0 0 / 0.4)"
-[FAIL] e.style['color'] = "color(xyz calc(0.5 + (sign(1em - 10px) * 0.1)) 0 0 / 0.5)" should set the property value
-  assert_equals: serialization should be canonical expected "color(xyz-d65 calc(0.5 + (0.1 * sign(1em - 10px))) 0 0 / 0.5)" but got "color(xyz-d65 0.4 0 0 / 0.5)"
-[FAIL] e.style['color'] = "color(xyz 0.5 0 0 / calc(0.5 + (sign(1em - 10px) * 0.1)))" should set the property value
-  assert_equals: serialization should be canonical expected "color(xyz-d65 0.5 0 0 / calc(0.5 + (0.1 * sign(1em - 10px))))" but got "color(xyz-d65 0.5 0 0 / 0.4)"
-[FAIL] e.style['color'] = "color(xyz-d50 calc(0.5 + (sign(1em - 10px) * 0.1)) 0 0 / 0.5)" should set the property value
-  assert_equals: serialization should be canonical expected "color(xyz-d50 calc(0.5 + (0.1 * sign(1em - 10px))) 0 0 / 0.5)" but got "color(xyz-d50 0.4 0 0 / 0.5)"
-[FAIL] e.style['color'] = "color(xyz-d50 0.5 0 0 / calc(0.5 + (sign(1em - 10px) * 0.1)))" should set the property value
-  assert_equals: serialization should be canonical expected "color(xyz-d50 0.5 0 0 / calc(0.5 + (0.1 * sign(1em - 10px))))" but got "color(xyz-d50 0.5 0 0 / 0.4)"
-[FAIL] e.style['color'] = "color(xyz-d65 calc(0.5 + (sign(1em - 10px) * 0.1)) 0 0 / 0.5)" should set the property value
-  assert_equals: serialization should be canonical expected "color(xyz-d65 calc(0.5 + (0.1 * sign(1em - 10px))) 0 0 / 0.5)" but got "color(xyz-d65 0.4 0 0 / 0.5)"
-[FAIL] e.style['color'] = "color(xyz-d65 0.5 0 0 / calc(0.5 + (sign(1em - 10px) * 0.1)))" should set the property value
-  assert_equals: serialization should be canonical expected "color(xyz-d65 0.5 0 0 / calc(0.5 + (0.1 * sign(1em - 10px))))" but got "color(xyz-d65 0.5 0 0 / 0.4)"
+[FAIL] e.style['color'] = "color(xyz calc(0.5 + 1) calc(0.5 - 1) calc(0.5) / calc(-0.5 + 1))" should set the property value
+  assert_equals: serialization should be canonical expected "color(xyz-d65 calc(1.5) calc(-0.5) calc(0.5) / calc(0.5))" but got "color(xyz-d65 1.5 -0.5 0.5 / 0.5)"
+[FAIL] e.style['color'] = "color(xyz calc(50% * 3) calc(-150% / 3) calc(50%) / calc(-50% * 3))" should set the property value
+  assert_equals: serialization should be canonical expected "color(xyz-d65 calc(150%) calc(-50%) calc(50%) / calc(-150%))" but got "color(xyz-d65 1.5 -0.5 0.5 / 0)"
+[FAIL] e.style['color'] = "color(xyz calc(50%) 50% 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "color(xyz-d65 calc(50%) 0.5 0.5)" but got "color(xyz-d65 0.5 0.5 0.5)"
+[FAIL] e.style['color'] = "color(xyz calc(50% + (sign(1em - 10px) * 10%)) 0 0 / 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "color(xyz-d65 calc(50% + (10% * sign(1em - 10px))) 0 0 / 0.5)" but got "color(xyz-d65 0.4 0 0 / 0.5)"
+[FAIL] e.style['color'] = "color(xyz 0.5 0 0 / calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
+  assert_equals: serialization should be canonical expected "color(xyz-d65 0.5 0 0 / calc(50% + (10% * sign(1em - 10px))))" but got "color(xyz-d65 0.5 0 0 / 0.4)"
+[FAIL] e.style['color'] = "color(xyz-d50 calc(0.5 + 1) calc(0.5 - 1) calc(0.5) / calc(-0.5 + 1))" should set the property value
+  assert_equals: serialization should be canonical expected "color(xyz-d50 calc(1.5) calc(-0.5) calc(0.5) / calc(0.5))" but got "color(xyz-d50 1.5 -0.5 0.5 / 0.5)"
+[FAIL] e.style['color'] = "color(xyz-d50 calc(50% * 3) calc(-150% / 3) calc(50%) / calc(-50% * 3))" should set the property value
+  assert_equals: serialization should be canonical expected "color(xyz-d50 calc(150%) calc(-50%) calc(50%) / calc(-150%))" but got "color(xyz-d50 1.5 -0.5 0.5 / 0)"
+[FAIL] e.style['color'] = "color(xyz-d50 calc(50%) 50% 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "color(xyz-d50 calc(50%) 0.5 0.5)" but got "color(xyz-d50 0.5 0.5 0.5)"
+[FAIL] e.style['color'] = "color(xyz-d50 calc(50% + (sign(1em - 10px) * 10%)) 0 0 / 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "color(xyz-d50 calc(50% + (10% * sign(1em - 10px))) 0 0 / 0.5)" but got "color(xyz-d50 0.4 0 0 / 0.5)"
+[FAIL] e.style['color'] = "color(xyz-d50 0.5 0 0 / calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
+  assert_equals: serialization should be canonical expected "color(xyz-d50 0.5 0 0 / calc(50% + (10% * sign(1em - 10px))))" but got "color(xyz-d50 0.5 0 0 / 0.4)"
+[FAIL] e.style['color'] = "color(xyz-d65 calc(0.5 + 1) calc(0.5 - 1) calc(0.5) / calc(-0.5 + 1))" should set the property value
+  assert_equals: serialization should be canonical expected "color(xyz-d65 calc(1.5) calc(-0.5) calc(0.5) / calc(0.5))" but got "color(xyz-d65 1.5 -0.5 0.5 / 0.5)"
+[FAIL] e.style['color'] = "color(xyz-d65 calc(50% * 3) calc(-150% / 3) calc(50%) / calc(-50% * 3))" should set the property value
+  assert_equals: serialization should be canonical expected "color(xyz-d65 calc(150%) calc(-50%) calc(50%) / calc(-150%))" but got "color(xyz-d65 1.5 -0.5 0.5 / 0)"
+[FAIL] e.style['color'] = "color(xyz-d65 calc(50%) 50% 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "color(xyz-d65 calc(50%) 0.5 0.5)" but got "color(xyz-d65 0.5 0.5 0.5)"
+[FAIL] e.style['color'] = "color(xyz-d65 calc(50% + (sign(1em - 10px) * 10%)) 0 0 / 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "color(xyz-d65 calc(50% + (10% * sign(1em - 10px))) 0 0 / 0.5)" but got "color(xyz-d65 0.4 0 0 / 0.5)"
+[FAIL] e.style['color'] = "color(xyz-d65 0.5 0 0 / calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
+  assert_equals: serialization should be canonical expected "color(xyz-d65 0.5 0 0 / calc(50% + (10% * sign(1em - 10px))))" but got "color(xyz-d65 0.5 0 0 / 0.4)"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-valid-color-function.html b/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-valid-color-function.html
index d9202a1..bfc9321 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-valid-color-function.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-valid-color-function.html
@@ -12,68 +12,36 @@
 </head>
 <body>
 <script>
-for (const colorSpace of [ "srgb", "srgb-linear", "a98-rgb", "rec2020", "prophoto-rgb", "display-p3" ]) {
-    test_valid_value("color", `color(${colorSpace} 0% 0% 0%)`, `color(${colorSpace} 0 0 0)`);
-    test_valid_value("color", `color(${colorSpace} 10% 10% 10%)`, `color(${colorSpace} 0.1 0.1 0.1)`);
-    test_valid_value("color", `color(${colorSpace} .2 .2 25%)`, `color(${colorSpace} 0.2 0.2 0.25)`);
-    test_valid_value("color", `color(${colorSpace} 0 0 0 / 1)`, `color(${colorSpace} 0 0 0)`);
-    test_valid_value("color", `color(${colorSpace} 0% 0 0 / 0.5)`, `color(${colorSpace} 0 0 0 / 0.5)`);
-    test_valid_value("color", `color(${colorSpace} 20% 0 10/0.5)`, `color(${colorSpace} 0.2 0 10 / 0.5)`);
-    test_valid_value("color", `color(${colorSpace} 20% 0 10/50%)`, `color(${colorSpace} 0.2 0 10 / 0.5)`);
-    test_valid_value("color", `color(${colorSpace} 400% 0 10/50%)`, `color(${colorSpace} 4 0 10 / 0.5)`);
-    test_valid_value("color", `color(${colorSpace} 50% -160 160)`, `color(${colorSpace} 0.5 -160 160)`);
-    test_valid_value("color", `color(${colorSpace} 50% -200 200)`, `color(${colorSpace} 0.5 -200 200)`);
-    test_valid_value("color", `color(${colorSpace} 0 0 0 / -10%)`, `color(${colorSpace} 0 0 0 / 0)`);
-    test_valid_value("color", `color(${colorSpace} 0 0 0 / 110%)`, `color(${colorSpace} 0 0 0)`);
-    test_valid_value("color", `color(${colorSpace} 0 0 0 / 300%)`, `color(${colorSpace} 0 0 0)`);
-    test_valid_value("color", `color(${colorSpace} 200 200 200)`, `color(${colorSpace} 200 200 200)`);
-    test_valid_value("color", `color(${colorSpace} 200 200 200 / 200)`, `color(${colorSpace} 200 200 200)`);
-    test_valid_value("color", `color(${colorSpace} -200 -200 -200)`, `color(${colorSpace} -200 -200 -200)`);
-    test_valid_value("color", `color(${colorSpace} -200 -200 -200 / -200)`, `color(${colorSpace} -200 -200 -200 / 0)`);
-    test_valid_value("color", `color(${colorSpace} 200% 200% 200%)`, `color(${colorSpace} 2 2 2)`);
-    test_valid_value("color", `color(${colorSpace} 200% 200% 200% / 200%)`, `color(${colorSpace} 2 2 2)`);
-    test_valid_value("color", `color(${colorSpace} -200% -200% -200% / -200%)`, `color(${colorSpace} -2 -2 -2 / 0)`);
-    test_valid_value("color", `color(${colorSpace} calc(0.5 + 1) calc(0.5 - 1) calc(0.5) / calc(-0.5 + 1))`, `color(${colorSpace} 1.5 -0.5 0.5 / 0.5)`);
-    test_valid_value("color", `color(${colorSpace} calc(50% * 3) calc(-150% / 3) calc(50%) / calc(-50% * 3))`, `color(${colorSpace} 1.5 -0.5 0.5 / 0)`);
-
-    test_valid_value("color", `color(${colorSpace} none none none / none)`, `color(${colorSpace} none none none / none)`);
-    test_valid_value("color", `color(${colorSpace} none none none)`, `color(${colorSpace} none none none)`);
-    test_valid_value("color", `color(${colorSpace} 10% none none / none)`, `color(${colorSpace} 0.1 none none / none)`);
-    test_valid_value("color", `color(${colorSpace} none none none / 0.5)`, `color(${colorSpace} none none none / 0.5)`);
-    test_valid_value("color", `color(${colorSpace} 0 0 0 / none)`, `color(${colorSpace} 0 0 0 / none)`);
-
-    test_valid_value("color", `color(${colorSpace} 0 calc(infinity) 0)`, `color(${colorSpace} 0 calc(infinity) 0)`);
-    test_valid_value("color", `color(${colorSpace} 0 calc(-infinity) 0)`, `color(${colorSpace} 0 calc(-infinity) 0)`);
-    test_valid_value("color", `color(${colorSpace} calc(NaN) 0 0)`, `color(${colorSpace} calc(NaN) 0 0)`);
-    test_valid_value("color", `color(${colorSpace} calc(0 / 0) 0 0)`, `color(${colorSpace} calc(NaN) 0 0)`);
-
-    // calc(50% + (sign(1em - 10px) * 10%)) cannot be evaluated eagerly because font relative units are not yet known at parse time.
-    test_valid_value("color", `color(${colorSpace} calc(50% + (sign(1em - 10px) * 10%)) 0 0 / 0.5)`, `color(${colorSpace} calc(50% + (10% * sign(1em - 10px))) 0 0 / 0.5)`);
-    test_valid_value("color", `color(${colorSpace} 0.5 0 0 / calc(50% + (sign(1em - 10px) * 10%)))`, `color(${colorSpace} 0.5 0 0 / calc(50% + (10% * sign(1em - 10px))))`);
-}
-
-for (const colorSpace of [ "xyz", "xyz-d50", "xyz-d65" ]) {
+for (const colorSpace of [ "srgb", "srgb-linear", "a98-rgb", "rec2020", "prophoto-rgb", "display-p3", "xyz", "xyz-d50", "xyz-d65" ]) {
     const resultColorSpace = colorSpace == "xyz" ? "xyz-d65" : colorSpace;
 
-    test_valid_value("color", `color(${colorSpace} 0 0 0)`, `color(${resultColorSpace} 0 0 0)`);
+    test_valid_value("color", `color(${colorSpace} 0% 0% 0%)`, `color(${resultColorSpace} 0 0 0)`);
+    test_valid_value("color", `color(${colorSpace} 10% 10% 10%)`, `color(${resultColorSpace} 0.1 0.1 0.1)`);
+    test_valid_value("color", `color(${colorSpace} .2 .2 25%)`, `color(${resultColorSpace} 0.2 0.2 0.25)`);
     test_valid_value("color", `color(${colorSpace} 0 0 0 / 1)`, `color(${resultColorSpace} 0 0 0)`);
-    test_valid_value("color", `color(${colorSpace} 1 1 1)`, `color(${resultColorSpace} 1 1 1)`);
-    test_valid_value("color", `color(${colorSpace} 1 1 1 / 1)`, `color(${resultColorSpace} 1 1 1)`);
-    test_valid_value("color", `color(${colorSpace} -1 -1 -1)`, `color(${resultColorSpace} -1 -1 -1)`);
-    test_valid_value("color", `color(${colorSpace} 0.1 0.1 0.1)`, `color(${resultColorSpace} 0.1 0.1 0.1)`);
-    test_valid_value("color", `color(${colorSpace} 10 10 10)`, `color(${resultColorSpace} 10 10 10)`);
-    test_valid_value("color", `color(${colorSpace} .2 .2 .25)`, `color(${resultColorSpace} 0.2 0.2 0.25)`);
-    test_valid_value("color", `color(${colorSpace} 0 0 0 / 0.5)`, `color(${resultColorSpace} 0 0 0 / 0.5)`);
-    test_valid_value("color", `color(${colorSpace} .20 0 10/0.5)`, `color(${resultColorSpace} 0.2 0 10 / 0.5)`);
-    test_valid_value("color", `color(${colorSpace} .20 0 10/50%)`, `color(${resultColorSpace} 0.2 0 10 / 0.5)`);
+    test_valid_value("color", `color(${colorSpace} 0% 0 0 / 0.5)`, `color(${resultColorSpace} 0 0 0 / 0.5)`);
+    test_valid_value("color", `color(${colorSpace} 20% 0 10/0.5)`, `color(${resultColorSpace} 0.2 0 10 / 0.5)`);
+    test_valid_value("color", `color(${colorSpace} 20% 0 10/50%)`, `color(${resultColorSpace} 0.2 0 10 / 0.5)`);
+    test_valid_value("color", `color(${colorSpace} 400% 0 10/50%)`, `color(${resultColorSpace} 4 0 10 / 0.5)`);
+    test_valid_value("color", `color(${colorSpace} 50% -160 160)`, `color(${resultColorSpace} 0.5 -160 160)`);
+    test_valid_value("color", `color(${colorSpace} 50% -200 200)`, `color(${resultColorSpace} 0.5 -200 200)`);
     test_valid_value("color", `color(${colorSpace} 0 0 0 / -10%)`, `color(${resultColorSpace} 0 0 0 / 0)`);
     test_valid_value("color", `color(${colorSpace} 0 0 0 / 110%)`, `color(${resultColorSpace} 0 0 0)`);
     test_valid_value("color", `color(${colorSpace} 0 0 0 / 300%)`, `color(${resultColorSpace} 0 0 0)`);
-    test_valid_value("color", `color(${colorSpace} calc(0.5 + 1) calc(0.5 - 1) calc(0.5) / calc(-0.5 + 1))`, `color(${resultColorSpace} 1.5 -0.5 0.5 / 0.5)`);
+    test_valid_value("color", `color(${colorSpace} 200 200 200)`, `color(${resultColorSpace} 200 200 200)`);
+    test_valid_value("color", `color(${colorSpace} 200 200 200 / 200)`, `color(${resultColorSpace} 200 200 200)`);
+    test_valid_value("color", `color(${colorSpace} -200 -200 -200)`, `color(${resultColorSpace} -200 -200 -200)`);
+    test_valid_value("color", `color(${colorSpace} -200 -200 -200 / -200)`, `color(${resultColorSpace} -200 -200 -200 / 0)`);
+    test_valid_value("color", `color(${colorSpace} 200% 200% 200%)`, `color(${resultColorSpace} 2 2 2)`);
+    test_valid_value("color", `color(${colorSpace} 200% 200% 200% / 200%)`, `color(${resultColorSpace} 2 2 2)`);
+    test_valid_value("color", `color(${colorSpace} -200% -200% -200% / -200%)`, `color(${resultColorSpace} -2 -2 -2 / 0)`);
+    test_valid_value("color", `color(${colorSpace} calc(0.5 + 1) calc(0.5 - 1) calc(0.5) / calc(-0.5 + 1))`, `color(${resultColorSpace} calc(1.5) calc(-0.5) calc(0.5) / calc(0.5))`);
+    test_valid_value("color", `color(${colorSpace} calc(50% * 3) calc(-150% / 3) calc(50%) / calc(-50% * 3))`, `color(${resultColorSpace} calc(150%) calc(-50%) calc(50%) / calc(-150%))`);
+    test_valid_value("color", `color(${colorSpace} calc(50%) 50% 0.5)`, `color(${resultColorSpace} calc(50%) 0.5 0.5)`);
 
     test_valid_value("color", `color(${colorSpace} none none none / none)`, `color(${resultColorSpace} none none none / none)`);
     test_valid_value("color", `color(${colorSpace} none none none)`, `color(${resultColorSpace} none none none)`);
-    test_valid_value("color", `color(${colorSpace} 0.2 none none / none)`, `color(${resultColorSpace} 0.2 none none / none)`);
+    test_valid_value("color", `color(${colorSpace} 10% none none / none)`, `color(${resultColorSpace} 0.1 none none / none)`);
     test_valid_value("color", `color(${colorSpace} none none none / 0.5)`, `color(${resultColorSpace} none none none / 0.5)`);
     test_valid_value("color", `color(${colorSpace} 0 0 0 / none)`, `color(${resultColorSpace} 0 0 0 / none)`);
 
@@ -83,8 +51,8 @@
     test_valid_value("color", `color(${colorSpace} calc(0 / 0) 0 0)`, `color(${resultColorSpace} calc(NaN) 0 0)`);
 
     // calc(50% + (sign(1em - 10px) * 10%)) cannot be evaluated eagerly because font relative units are not yet known at parse time.
-    test_valid_value("color", `color(${colorSpace} calc(0.5 + (sign(1em - 10px) * 0.1)) 0 0 / 0.5)`, `color(${resultColorSpace} calc(0.5 + (0.1 * sign(1em - 10px))) 0 0 / 0.5)`);
-    test_valid_value("color", `color(${colorSpace} 0.5 0 0 / calc(0.5 + (sign(1em - 10px) * 0.1)))`, `color(${resultColorSpace} 0.5 0 0 / calc(0.5 + (0.1 * sign(1em - 10px))))`);
+    test_valid_value("color", `color(${colorSpace} calc(50% + (sign(1em - 10px) * 10%)) 0 0 / 0.5)`, `color(${resultColorSpace} calc(50% + (10% * sign(1em - 10px))) 0 0 / 0.5)`);
+    test_valid_value("color", `color(${colorSpace} 0.5 0 0 / calc(50% + (sign(1em - 10px) * 10%)))`, `color(${resultColorSpace} 0.5 0 0 / calc(50% + (10% * sign(1em - 10px))))`);
 }
 </script>
 </body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-valid-hsl.html b/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-valid-hsl.html
index b60cd74..a9d2a7b8 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-valid-hsl.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-valid-hsl.html
@@ -63,23 +63,26 @@
     ["hsl(90 50% 50% / calc(0 / 0))", "rgba(128, 191, 64, 0)"], // hsl(90 50% 50% / 0)
 
     // calc(50% + (sign(1em - 10px) * 10%)) cannot be evaluated eagerly because font relative units are not yet known at parse time.
-    ["hsl(calc(50deg + (sign(1em - 10px) * 10deg)), 0%, 0%, 50%)", "hsl(calc(50deg + (10deg * sign(1em - 10px))) 0% 0% / 50%)"],
-    ["hsla(calc(50deg + (sign(1em - 10px) * 10deg)), 0%, 0%, 50%)", "hsl(calc(50deg + (10deg * sign(1em - 10px))) 0% 0% / 50%)"],
-    ["hsl(calc(50 + (sign(1em - 10px) * 10)), 0%, 0%, 50%)", "hsl(calc(50 + (10 * sign(1em - 10px))) 0% 0% / 50%)"],
-    ["hsla(calc(50 + (sign(1em - 10px) * 10)), 0%, 0%, 50%)", "hsl(calc(50 + (10 * sign(1em - 10px))) 0% 0% / 50%)"],
-    ["hsl(0deg, 0%, 0%, calc(50% + (sign(1em - 10px) * 10%)))", "hsl(0deg 0% 0% / calc(50% + (10% * sign(1em - 10px))))"],
-    ["hsla(0deg, 0%, 0%, calc(50% + (sign(1em - 10px) * 10%)))", "hsl(0deg 0% 0% / calc(50% + (10% * sign(1em - 10px))))"],
-    ["hsl(0, 0%, 0%, calc(50% + (sign(1em - 10px) * 10%)))", "hsl(0 0% 0% / calc(50% + (10% * sign(1em - 10px))))"],
-    ["hsla(0, 0%, 0%, calc(50% + (sign(1em - 10px) * 10%)))", "hsl(0 0% 0% / calc(50% + (10% * sign(1em - 10px))))"],
+    ["hsl(calc(50deg + (sign(1em - 10px) * 10deg)), 0%, 0%, 50%)", "hsl(calc(50deg + (10deg * sign(1em - 10px))) 0 0 / 0.5)"],
+    ["hsla(calc(50deg + (sign(1em - 10px) * 10deg)), 0%, 0%, 50%)", "hsl(calc(50deg + (10deg * sign(1em - 10px))) 0 0 / 0.5)"],
+    ["hsl(calc(50 + (sign(1em - 10px) * 10)), 0%, 0%, 50%)", "hsl(calc(50 + (10 * sign(1em - 10px))) 0 0 / 0.5)"],
+    ["hsla(calc(50 + (sign(1em - 10px) * 10)), 0%, 0%, 50%)", "hsl(calc(50 + (10 * sign(1em - 10px))) 0 0 / 0.5)"],
+    ["hsl(0deg, 0%, 0%, calc(50% + (sign(1em - 10px) * 10%)))", "hsl(0 0 0 / calc(50% + (10% * sign(1em - 10px))))"],
+    ["hsla(0deg, 0%, 0%, calc(50% + (sign(1em - 10px) * 10%)))", "hsl(0 0 0 / calc(50% + (10% * sign(1em - 10px))))"],
+    ["hsl(0, 0%, 0%, calc(50% + (sign(1em - 10px) * 10%)))", "hsl(0 0 0 / calc(50% + (10% * sign(1em - 10px))))"],
+    ["hsla(0, 0%, 0%, calc(50% + (sign(1em - 10px) * 10%)))", "hsl(0 0 0 / calc(50% + (10% * sign(1em - 10px))))"],
 
-    ["hsl(calc(50deg + (sign(1em - 10px) * 10deg)) 0% 0% / 50%)", "hsl(calc(50deg + (10deg * sign(1em - 10px))) 0% 0% / 50%)"],
-    ["hsla(calc(50deg + (sign(1em - 10px) * 10deg)) 0% 0% / 50%)", "hsl(calc(50deg + (10deg * sign(1em - 10px))) 0% 0% / 50%)"],
+    ["hsl(calc(50deg + (sign(1em - 10px) * 10deg)) 0% 0% / 50%)", "hsl(calc(50deg + (10deg * sign(1em - 10px))) 0 0 / 0.5)"],
+    ["hsla(calc(50deg + (sign(1em - 10px) * 10deg)) 0% 0% / 50%)", "hsl(calc(50deg + (10deg * sign(1em - 10px))) 0 0 / 0.5)"],
     ["hsl(calc(50 + (sign(1em - 10px) * 10)) 0 0 / 0.5)", "hsl(calc(50 + (10 * sign(1em - 10px))) 0 0 / 0.5)"],
     ["hsla(calc(50 + (sign(1em - 10px) * 10)) 0 0 / 0.5)", "hsl(calc(50 + (10 * sign(1em - 10px))) 0 0 / 0.5)"],
-    ["hsl(0deg 0% 0% / calc(50% + (sign(1em - 10px) * 10%)))", "hsl(0deg 0% 0% / calc(50% + (10% * sign(1em - 10px))))"],
-    ["hsla(0deg 0% 0% / calc(50% + (sign(1em - 10px) * 10%)))", "hsl(0deg 0% 0% / calc(50% + (10% * sign(1em - 10px))))"],
+    ["hsl(0deg 0% 0% / calc(50% + (sign(1em - 10px) * 10%)))", "hsl(0 0 0 / calc(50% + (10% * sign(1em - 10px))))"],
+    ["hsla(0deg 0% 0% / calc(50% + (sign(1em - 10px) * 10%)))", "hsl(0 0 0 / calc(50% + (10% * sign(1em - 10px))))"],
     ["hsl(0 0 0 / calc(0.75 + (sign(1em - 10px) * 0.1)))", "hsl(0 0 0 / calc(0.75 + (0.1 * sign(1em - 10px))))"],
     ["hsla(0 0 0 / calc(0.75 + (sign(1em - 10px) * 0.1)))", "hsl(0 0 0 / calc(0.75 + (0.1 * sign(1em - 10px))))"],
+
+    ["hsla(calc(50deg + (sign(1em - 10px) * 10deg)) -100 300 / 0.5)", "hsl(calc(50deg + (10deg * sign(1em - 10px))) 0 300 / 0.5)"],
+    ["hsla(calc(50deg + (sign(1em - 10px) * 10deg)) -100% 300% / 0.5)", "hsl(calc(50deg + (10deg * sign(1em - 10px))) 0 300 / 0.5)"],
 ];
 
 for (const test of tests) {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-valid-hwb.html b/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-valid-hwb.html
index 1f9799e..007f4be8 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-valid-hwb.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-valid-hwb.html
@@ -58,9 +58,9 @@
     ["hwb(90 20% 10% / calc(0 / 0))", "rgba(140, 230, 51, 0)"], // hwb(90 20% 10% / 0)
 
     // calc(50% + (sign(1em - 10px) * 10%)) cannot be evaluated eagerly because font relative units are not yet known at parse time.
-    ["hwb(calc(110deg + (sign(1em - 10px) * 10deg)) 30% 50% / 50%)", "hwb(calc(110deg + (10deg * sign(1em - 10px))) 30% 50% / 50%)"],
+    ["hwb(calc(110deg + (sign(1em - 10px) * 10deg)) 30% 50% / 50%)", "hwb(calc(110deg + (10deg * sign(1em - 10px))) 30 50 / 0.5)"],
     ["hwb(calc(110 + (sign(1em - 10px) * 10)) 30 50 / 0.5)", "hwb(calc(110 + (10 * sign(1em - 10px))) 30 50 / 0.5)"],
-    ["hwb(120deg 30% 50% / calc(50% + (sign(1em - 10px) * 10%)))", "hwb(120deg 30% 50% / calc(50% + (10% * sign(1em - 10px))))"],
+    ["hwb(120deg 30% 50% / calc(50% + (sign(1em - 10px) * 10%)))", "hwb(120 30 50 / calc(50% + (10% * sign(1em - 10px))))"],
     ["hwb(120 30 50 / calc(0.75 + (sign(1em - 10px) * 0.1)))", "hwb(120 30 50 / calc(0.75 + (0.1 * sign(1em - 10px))))"],
 ];
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-valid-lab-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-valid-lab-expected.txt
index 63777f4..b2e65ec 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-valid-lab-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-valid-lab-expected.txt
@@ -1,20 +1,84 @@
 This is a testharness.js-based test.
-Found 8 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 40 FAIL, 0 TIMEOUT, 0 NOTRUN.
+[FAIL] e.style['color'] = "lab(calc(50 * 3) calc(0.5 - 1) calc(1.5) / calc(-0.5 + 1))" should set the property value
+  assert_equals: serialization should be canonical expected "lab(calc(150) calc(-0.5) calc(1.5) / calc(0.5))" but got "lab(100 -0.5 1.5 / 0.5)"
+[FAIL] e.style['color'] = "lab(calc(-50 * 3) calc(0.5 + 1) calc(-1.5) / calc(-0.5 * 2))" should set the property value
+  assert_equals: serialization should be canonical expected "lab(calc(-150) calc(1.5) calc(-1.5) / calc(-1))" but got "lab(0 1.5 -1.5 / 0)"
+[FAIL] e.style['color'] = "lab(calc(50%) 50% 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "lab(calc(50%) 62.5 0.5)" but got "lab(50 62.5 0.5)"
+[FAIL] e.style['color'] = "lab(200 calc(50%) 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "lab(100 calc(50%) 0.5)" but got "lab(100 62.5 0.5)"
+[FAIL] e.style['color'] = "lab(-200 calc(50%) 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "lab(0 calc(50%) 0.5)" but got "lab(0 62.5 0.5)"
+[FAIL] e.style['color'] = "lab(none 20 calc(0.5))" should set the property value
+  assert_equals: serialization should be canonical expected "lab(none 20 calc(0.5))" but got "lab(none 20 0.5)"
+[FAIL] e.style['color'] = "lab(calc(infinity) 0 0)" should set the property value
+  assert_equals: serialization should be canonical expected "lab(calc(infinity) 0 0)" but got "lab(100 0 0)"
+[FAIL] e.style['color'] = "oklab(calc(0.5 * 3) calc(0.5 - 1) calc(1.5) / calc(-0.5 + 1))" should set the property value
+  assert_equals: serialization should be canonical expected "oklab(calc(1.5) calc(-0.5) calc(1.5) / calc(0.5))" but got "oklab(1 -0.5 1.5 / 0.5)"
+[FAIL] e.style['color'] = "oklab(calc(-0.5 * 3) calc(0.5 + 1) calc(-1.5) / calc(-0.5 * 2))" should set the property value
+  assert_equals: serialization should be canonical expected "oklab(calc(-1.5) calc(1.5) calc(-1.5) / calc(-1))" but got "oklab(0 1.5 -1.5 / 0)"
+[FAIL] e.style['color'] = "oklab(calc(50%) 50% 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "oklab(calc(50%) 0.2 0.5)" but got "oklab(0.5 0.2 0.5)"
+[FAIL] e.style['color'] = "oklab(200 calc(50%) 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "oklab(1 calc(50%) 0.5)" but got "oklab(1 0.2 0.5)"
+[FAIL] e.style['color'] = "oklab(-200 calc(50%) 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "oklab(0 calc(50%) 0.5)" but got "oklab(0 0.2 0.5)"
+[FAIL] e.style['color'] = "oklab(none 0.2 calc(0.5))" should set the property value
+  assert_equals: serialization should be canonical expected "oklab(none 0.2 calc(0.5))" but got "oklab(none 0.2 0.5)"
+[FAIL] e.style['color'] = "oklab(calc(infinity) 0 0)" should set the property value
+  assert_equals: serialization should be canonical expected "oklab(calc(infinity) 0 0)" but got "oklab(1 0 0)"
+[FAIL] e.style['color'] = "lch(calc(50 * 3) calc(0.5 - 1) calc(20deg * 2) / calc(-0.5 + 1))" should set the property value
+  assert_equals: serialization should be canonical expected "lch(calc(150) calc(-0.5) calc(40deg) / calc(0.5))" but got "lch(100 0 40 / 0.5)"
+[FAIL] e.style['color'] = "lch(calc(-50 * 3) calc(0.5 + 1) calc(-20deg * 2) / calc(-0.5 * 2))" should set the property value
+  assert_equals: serialization should be canonical expected "lch(calc(-150) calc(1.5) calc(-40deg) / calc(-1))" but got "lch(0 1.5 320 / 0)"
+[FAIL] e.style['color'] = "lch(calc(50%) 50% 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "lch(calc(50%) 75 0.5)" but got "lch(50 75 0.5)"
+[FAIL] e.style['color'] = "lch(200 calc(50%) 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "lch(100 calc(50%) 0.5)" but got "lch(100 75 0.5)"
+[FAIL] e.style['color'] = "lch(-200 calc(50%) 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "lch(0 calc(50%) 0.5)" but got "lch(0 75 0.5)"
+[FAIL] e.style['color'] = "lch(calc(50%) -100 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "lch(calc(50%) 0 0.5)" but got "lch(50 0 0.5)"
+[FAIL] e.style['color'] = "lch(none 20 calc(0.5))" should set the property value
+  assert_equals: serialization should be canonical expected "lch(none 20 calc(0.5))" but got "lch(none 20 0.5)"
+[FAIL] e.style['color'] = "lch(calc(infinity) 0 0)" should set the property value
+  assert_equals: serialization should be canonical expected "lch(calc(infinity) 0 0)" but got "lch(100 0 0)"
+[FAIL] e.style['color'] = "lch(50 calc(-infinity) 0)" should set the property value
+  assert_equals: serialization should be canonical expected "lch(50 calc(-infinity) 0)" but got "lch(50 0 0)"
+[FAIL] e.style['color'] = "oklch(calc(0.5 * 3) calc(0.5 - 1) calc(20deg * 2) / calc(-0.5 + 1))" should set the property value
+  assert_equals: serialization should be canonical expected "oklch(calc(1.5) calc(-0.5) calc(40deg) / calc(0.5))" but got "oklch(1 0 40 / 0.5)"
+[FAIL] e.style['color'] = "oklch(calc(-0.5 * 3) calc(0.5 + 1) calc(-20deg * 2) / calc(-0.5 * 2))" should set the property value
+  assert_equals: serialization should be canonical expected "oklch(calc(-1.5) calc(1.5) calc(-40deg) / calc(-1))" but got "oklch(0 1.5 320 / 0)"
+[FAIL] e.style['color'] = "oklch(calc(50%) 50% 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "oklch(calc(50%) 0.2 0.5)" but got "oklch(0.5 0.2 0.5)"
+[FAIL] e.style['color'] = "oklch(200 calc(50%) 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "oklch(1 calc(50%) 0.5)" but got "oklch(1 0.2 0.5)"
+[FAIL] e.style['color'] = "oklch(-200 calc(50%) 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "oklch(0 calc(50%) 0.5)" but got "oklch(0 0.2 0.5)"
+[FAIL] e.style['color'] = "oklch(calc(50%) -100 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "oklch(calc(50%) 0 0.5)" but got "oklch(0.5 0 0.5)"
+[FAIL] e.style['color'] = "oklch(none 0.2 calc(0.5))" should set the property value
+  assert_equals: serialization should be canonical expected "oklch(none 0.2 calc(0.5))" but got "oklch(none 0.2 0.5)"
+[FAIL] e.style['color'] = "oklch(calc(infinity) 0 0)" should set the property value
+  assert_equals: serialization should be canonical expected "oklch(calc(infinity) 0 0)" but got "oklch(1 0 0)"
+[FAIL] e.style['color'] = "oklch(0.5 calc(-infinity) 0)" should set the property value
+  assert_equals: serialization should be canonical expected "oklch(0.5 calc(-infinity) 0)" but got "oklch(0.5 0 0)"
 [FAIL] e.style['color'] = "lab(calc(50 + (sign(1em - 10px) * 10)) 30 50 / 50%)" should set the property value
-  assert_equals: serialization should be canonical expected "lab(calc(50 + (10 * sign(1em - 10px))) 30 50 / 50%)" but got "lab(40 30 50 / 0.5)"
+  assert_equals: serialization should be canonical expected "lab(calc(50 + (10 * sign(1em - 10px))) 30 50 / 0.5)" but got "lab(40 30 50 / 0.5)"
 [FAIL] e.style['color'] = "oklab(calc(0.5 + (sign(1em - 10px) * 0.1)) 0.3 0.5 / 50%)" should set the property value
-  assert_equals: serialization should be canonical expected "oklab(calc(0.5 + (0.1 * sign(1em - 10px))) 0.3 0.5 / 50%)" but got "oklab(0.4 0.3 0.5 / 0.5)"
+  assert_equals: serialization should be canonical expected "oklab(calc(0.5 + (0.1 * sign(1em - 10px))) 0.3 0.5 / 0.5)" but got "oklab(0.4 0.3 0.5 / 0.5)"
 [FAIL] e.style['color'] = "lab(60 30 50 / calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
   assert_equals: serialization should be canonical expected "lab(60 30 50 / calc(50% + (10% * sign(1em - 10px))))" but got "lab(60 30 50 / 0.4)"
 [FAIL] e.style['color'] = "oklab(0.6 0.3 0.5 / calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
   assert_equals: serialization should be canonical expected "oklab(0.6 0.3 0.5 / calc(50% + (10% * sign(1em - 10px))))" but got "oklab(0.6 0.3 0.5 / 0.4)"
 [FAIL] e.style['color'] = "lch(calc(50 + (sign(1em - 10px) * 10)) 30 50deg / 50%)" should set the property value
-  assert_equals: serialization should be canonical expected "lch(calc(50 + (10 * sign(1em - 10px))) 30 50deg / 50%)" but got "lch(40 30 50 / 0.5)"
+  assert_equals: serialization should be canonical expected "lch(calc(50 + (10 * sign(1em - 10px))) 30 50 / 0.5)" but got "lch(40 30 50 / 0.5)"
 [FAIL] e.style['color'] = "oklch(calc(0.5 + (sign(1em - 10px) * 0.1)) 0.3 50deg / 50%)" should set the property value
-  assert_equals: serialization should be canonical expected "oklch(calc(0.5 + (0.1 * sign(1em - 10px))) 0.3 50deg / 50%)" but got "oklch(0.4 0.3 50 / 0.5)"
+  assert_equals: serialization should be canonical expected "oklch(calc(0.5 + (0.1 * sign(1em - 10px))) 0.3 50 / 0.5)" but got "oklch(0.4 0.3 50 / 0.5)"
 [FAIL] e.style['color'] = "lch(60 30 50deg / calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
-  assert_equals: serialization should be canonical expected "lch(60 30 50deg / calc(50% + (10% * sign(1em - 10px))))" but got "lch(60 30 50 / 0.4)"
+  assert_equals: serialization should be canonical expected "lch(60 30 50 / calc(50% + (10% * sign(1em - 10px))))" but got "lch(60 30 50 / 0.4)"
 [FAIL] e.style['color'] = "oklch(0.6 0.3 50deg / calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
-  assert_equals: serialization should be canonical expected "oklch(0.6 0.3 50deg / calc(50% + (10% * sign(1em - 10px))))" but got "oklch(0.6 0.3 50 / 0.4)"
+  assert_equals: serialization should be canonical expected "oklch(0.6 0.3 50 / calc(50% + (10% * sign(1em - 10px))))" but got "oklch(0.6 0.3 50 / 0.4)"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-valid-lab.html b/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-valid-lab.html
index ffa3b55..a085bfb47 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-valid-lab.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-valid-lab.html
@@ -30,8 +30,14 @@
     ["lab(-40 0 0)", "lab(0 0 0)"],
     ["lab(50 -20 0)", "lab(50 -20 0)"],
     ["lab(50 0 -20)", "lab(50 0 -20)"],
-    ["lab(calc(50 * 3) calc(0.5 - 1) calc(1.5) / calc(-0.5 + 1))", "lab(100 -0.5 1.5 / 0.5)"],
-    ["lab(calc(-50 * 3) calc(0.5 + 1) calc(-1.5) / calc(-0.5 * 2))", "lab(0 1.5 -1.5 / 0)"],
+    ["lab(50% 50% -20%)", "lab(50 62.5 -25)"],
+    ["lab(50 -20% -20%)", "lab(50 -25 -25)"],
+    ["lab(calc(50 * 3) calc(0.5 - 1) calc(1.5) / calc(-0.5 + 1))", "lab(calc(150) calc(-0.5) calc(1.5) / calc(0.5))"],
+    ["lab(calc(-50 * 3) calc(0.5 + 1) calc(-1.5) / calc(-0.5 * 2))", "lab(calc(-150) calc(1.5) calc(-1.5) / calc(-1))"],
+    ["lab(calc(50%) 50% 0.5)", "lab(calc(50%) 62.5 0.5)"],
+    ["lab(200 calc(50%) 0.5)", "lab(100 calc(50%) 0.5)"],
+    ["lab(-200 calc(50%) 0.5)", "lab(0 calc(50%) 0.5)"],
+    ["lab(none 20 calc(0.5))", "lab(none 20 calc(0.5))"],
 
     ["lab(none none none / none)", "lab(none none none / none)"],
     ["lab(none none none)", "lab(none none none)"],
@@ -39,7 +45,7 @@
     ["lab(none none none / 0.5)", "lab(none none none / 0.5)"],
     ["lab(0 0 0 / none)", "lab(0 0 0 / none)"],
 
-    ["lab(calc(infinity) 0 0)", "lab(100 0 0)"],
+    ["lab(calc(infinity) 0 0)", "lab(calc(infinity) 0 0)"],
     ["lab(50 calc(infinity) 0)", "lab(50 calc(infinity) 0)"],
     ["lab(50 calc(-infinity) 0)", "lab(50 calc(-infinity) 0)"],
     ["lab(calc(NaN) 0 0)", "lab(calc(NaN) 0 0)"],
@@ -60,8 +66,14 @@
     ["oklab(-0.4 0 0)", "oklab(0 0 0)"],
     ["oklab(0.5 -2 0)", "oklab(0.5 -2 0)"],
     ["oklab(0.5 0 -2)", "oklab(0.5 0 -2)"],
-    ["oklab(calc(0.5 * 3) calc(0.5 - 1) calc(1.5) / calc(-0.5 + 1))", "oklab(1 -0.5 1.5 / 0.5)"],
-    ["oklab(calc(-0.5 * 3) calc(0.5 + 1) calc(-1.5) / calc(-0.5 * 2))", "oklab(0 1.5 -1.5 / 0)"],
+    ["oklab(50% 50% -20%)", "oklab(0.5 0.2 -0.08)"],
+    ["oklab(0.5 -20% -20%)", "oklab(0.5 -0.08 -0.08)"],
+    ["oklab(calc(0.5 * 3) calc(0.5 - 1) calc(1.5) / calc(-0.5 + 1))", "oklab(calc(1.5) calc(-0.5) calc(1.5) / calc(0.5))"],
+    ["oklab(calc(-0.5 * 3) calc(0.5 + 1) calc(-1.5) / calc(-0.5 * 2))", "oklab(calc(-1.5) calc(1.5) calc(-1.5) / calc(-1))"],
+    ["oklab(calc(50%) 50% 0.5)", "oklab(calc(50%) 0.2 0.5)"],
+    ["oklab(200 calc(50%) 0.5)", "oklab(1 calc(50%) 0.5)"],
+    ["oklab(-200 calc(50%) 0.5)", "oklab(0 calc(50%) 0.5)"],
+    ["oklab(none 0.2 calc(0.5))", "oklab(none 0.2 calc(0.5))"],
 
     ["oklab(none none none / none)", "oklab(none none none / none)"],
     ["oklab(none none none)", "oklab(none none none)"],
@@ -73,7 +85,7 @@
     ["lab(20% -50% 90%/0.5)", "lab(20 -62.5 112.5 / 0.5)"],
     ["oklab(20% 70% -80%/0.5)", "oklab(0.2 0.28 -0.32 / 0.5)"],
 
-    ["oklab(calc(infinity) 0 0)", "oklab(1 0 0)"],
+    ["oklab(calc(infinity) 0 0)", "oklab(calc(infinity) 0 0)"],
     ["oklab(0.5 calc(infinity) 0)", "oklab(0.5 calc(infinity) 0)"],
     ["oklab(0.5 calc(-infinity) 0)", "oklab(0.5 calc(-infinity) 0)"],
     ["oklab(calc(NaN) 0 0)", "oklab(calc(NaN) 0 0)"],
@@ -98,8 +110,15 @@
     ["lch(0 0 0 / 0.5)", "lch(0 0 0 / 0.5)"],
     ["lch(10 20 20 / 110%)", "lch(10 20 20)"],
     ["lch(10 20 -700)", "lch(10 20 20)"],
-    ["lch(calc(50 * 3) calc(0.5 - 1) calc(20deg * 2) / calc(-0.5 + 1))", "lch(100 0 40 / 0.5)"],
-    ["lch(calc(-50 * 3) calc(0.5 + 1) calc(-20deg * 2) / calc(-0.5 * 2))", "lch(0 1.5 320 / 0)"],
+    ["lch(50% 50% 20)", "lch(50 75 20)"],
+    ["lch(0.5 -20% -20)", "lch(0.5 0 340)"],
+    ["lch(calc(50 * 3) calc(0.5 - 1) calc(20deg * 2) / calc(-0.5 + 1))", "lch(calc(150) calc(-0.5) calc(40deg) / calc(0.5))"],
+    ["lch(calc(-50 * 3) calc(0.5 + 1) calc(-20deg * 2) / calc(-0.5 * 2))", "lch(calc(-150) calc(1.5) calc(-40deg) / calc(-1))"],
+    ["lch(calc(50%) 50% 0.5)", "lch(calc(50%) 75 0.5)"],
+    ["lch(200 calc(50%) 0.5)", "lch(100 calc(50%) 0.5)"],
+    ["lch(-200 calc(50%) 0.5)", "lch(0 calc(50%) 0.5)"],
+    ["lch(calc(50%) -100 0.5)", "lch(calc(50%) 0 0.5)"],
+    ["lch(none 20 calc(0.5))", "lch(none 20 calc(0.5))"],
 
     ["lch(none none none / none)", "lch(none none none / none)"],
     ["lch(none none none)", "lch(none none none)"],
@@ -107,9 +126,9 @@
     ["lch(none none none / 0.5)", "lch(none none none / 0.5)"],
     ["lch(0 0 0 / none)", "lch(0 0 0 / none)"],
 
-    ["lch(calc(infinity) 0 0)", "lch(100 0 0)"],
+    ["lch(calc(infinity) 0 0)", "lch(calc(infinity) 0 0)"],
     ["lch(50 calc(infinity) 0)", "lch(50 calc(infinity) 0)"],
-    ["lch(50 calc(-infinity) 0)", "lch(50 0 0)"],
+    ["lch(50 calc(-infinity) 0)", "lch(50 calc(-infinity) 0)"],
     ["lch(calc(NaN) 0 0)", "lch(calc(NaN) 0 0)"],
     ["lch(calc(0 / 0) 0 0)", "lch(calc(NaN) 0 0)"],
 
@@ -132,8 +151,15 @@
     ["oklch(0 0 0 / 0.5)", "oklch(0 0 0 / 0.5)"],
     ["oklch(0.1 0.2 20 / 110%)", "oklch(0.1 0.2 20)"],
     ["oklch(0.1 0.2 -700)", "oklch(0.1 0.2 20)"],
-    ["oklch(calc(0.5 * 3) calc(0.5 - 1) calc(20deg * 2) / calc(-0.5 + 1))", "oklch(1 0 40 / 0.5)"],
-    ["oklch(calc(-0.5 * 3) calc(0.5 + 1) calc(-20deg * 2) / calc(-0.5 * 2))", "oklch(0 1.5 320 / 0)"],
+    ["oklch(50% 50% 20)", "oklch(0.5 0.2 20)"],
+    ["oklch(0.5 -20% -20)", "oklch(0.5 0 340)"],
+    ["oklch(calc(0.5 * 3) calc(0.5 - 1) calc(20deg * 2) / calc(-0.5 + 1))", "oklch(calc(1.5) calc(-0.5) calc(40deg) / calc(0.5))"],
+    ["oklch(calc(-0.5 * 3) calc(0.5 + 1) calc(-20deg * 2) / calc(-0.5 * 2))", "oklch(calc(-1.5) calc(1.5) calc(-40deg) / calc(-1))"],
+    ["oklch(calc(50%) 50% 0.5)", "oklch(calc(50%) 0.2 0.5)"],
+    ["oklch(200 calc(50%) 0.5)", "oklch(1 calc(50%) 0.5)"],
+    ["oklch(-200 calc(50%) 0.5)", "oklch(0 calc(50%) 0.5)"],
+    ["oklch(calc(50%) -100 0.5)", "oklch(calc(50%) 0 0.5)"],
+    ["oklch(none 0.2 calc(0.5))", "oklch(none 0.2 calc(0.5))"],
 
     ["oklch(none none none / none)", "oklch(none none none / none)"],
     ["oklch(none none none)", "oklch(none none none)"],
@@ -145,22 +171,22 @@
     ["lch(20% 80% 10/0.5)", "lch(20 120 10 / 0.5)"],
     ["oklch(20% 60% 10/0.5)", "oklch(0.2 0.24 10 / 0.5)"],
 
-    ["oklch(calc(infinity) 0 0)", "oklch(1 0 0)"],
+    ["oklch(calc(infinity) 0 0)", "oklch(calc(infinity) 0 0)"],
     ["oklch(0.5 calc(infinity) 0)", "oklch(0.5 calc(infinity) 0)"],
-    ["oklch(0.5 calc(-infinity) 0)", "oklch(0.5 0 0)"],
+    ["oklch(0.5 calc(-infinity) 0)", "oklch(0.5 calc(-infinity) 0)"],
     ["oklch(calc(NaN) 0 0)", "oklch(calc(NaN) 0 0)"],
     ["oklch(calc(0 / 0) 0 0)", "oklch(calc(NaN) 0 0)"],
 
     // calc(50% + (sign(1em - 10px) * 10%)) cannot be evaluated eagerly because font relative units are not yet known at parse time.
-    ["lab(calc(50 + (sign(1em - 10px) * 10)) 30 50 / 50%)", "lab(calc(50 + (10 * sign(1em - 10px))) 30 50 / 50%)"],
-    ["oklab(calc(0.5 + (sign(1em - 10px) * 0.1)) 0.3 0.5 / 50%)", "oklab(calc(0.5 + (0.1 * sign(1em - 10px))) 0.3 0.5 / 50%)"],
+    ["lab(calc(50 + (sign(1em - 10px) * 10)) 30 50 / 50%)", "lab(calc(50 + (10 * sign(1em - 10px))) 30 50 / 0.5)"],
+    ["oklab(calc(0.5 + (sign(1em - 10px) * 0.1)) 0.3 0.5 / 50%)", "oklab(calc(0.5 + (0.1 * sign(1em - 10px))) 0.3 0.5 / 0.5)"],
     ["lab(60 30 50 / calc(50% + (sign(1em - 10px) * 10%)))", "lab(60 30 50 / calc(50% + (10% * sign(1em - 10px))))"],
     ["oklab(0.6 0.3 0.5 / calc(50% + (sign(1em - 10px) * 10%)))", "oklab(0.6 0.3 0.5 / calc(50% + (10% * sign(1em - 10px))))"],
 
-    ["lch(calc(50 + (sign(1em - 10px) * 10)) 30 50deg / 50%)", "lch(calc(50 + (10 * sign(1em - 10px))) 30 50deg / 50%)"],
-    ["oklch(calc(0.5 + (sign(1em - 10px) * 0.1)) 0.3 50deg / 50%)", "oklch(calc(0.5 + (0.1 * sign(1em - 10px))) 0.3 50deg / 50%)"],
-    ["lch(60 30 50deg / calc(50% + (sign(1em - 10px) * 10%)))", "lch(60 30 50deg / calc(50% + (10% * sign(1em - 10px))))"],
-    ["oklch(0.6 0.3 50deg / calc(50% + (sign(1em - 10px) * 10%)))", "oklch(0.6 0.3 50deg / calc(50% + (10% * sign(1em - 10px))))"],
+    ["lch(calc(50 + (sign(1em - 10px) * 10)) 30 50deg / 50%)", "lch(calc(50 + (10 * sign(1em - 10px))) 30 50 / 0.5)"],
+    ["oklch(calc(0.5 + (sign(1em - 10px) * 0.1)) 0.3 50deg / 50%)", "oklch(calc(0.5 + (0.1 * sign(1em - 10px))) 0.3 50 / 0.5)"],
+    ["lch(60 30 50deg / calc(50% + (sign(1em - 10px) * 10%)))", "lch(60 30 50 / calc(50% + (10% * sign(1em - 10px))))"],
+    ["oklch(0.6 0.3 50deg / calc(50% + (sign(1em - 10px) * 10%)))", "oklch(0.6 0.3 50 / calc(50% + (10% * sign(1em - 10px))))"],
 ];
 
 for (const test of tests) {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-valid-rgb-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-valid-rgb-expected.txt
index c4fd42d..c56ec0b 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-valid-rgb-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-valid-rgb-expected.txt
@@ -1,40 +1,48 @@
 This is a testharness.js-based test.
-Found 18 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 22 FAIL, 0 TIMEOUT, 0 NOTRUN.
 [FAIL] e.style['color'] = "rgb(calc(50% + (sign(1em - 10px) * 10%)), 0%, 0%, 50%)" should set the property value
-  assert_equals: serialization should be canonical expected "rgb(calc(50% + (10% * sign(1em - 10px))) 0% 0% / 50%)" but got "rgba(102, 0, 0, 0.5)"
+  assert_equals: serialization should be canonical expected "rgb(calc(50% + (10% * sign(1em - 10px))) 0 0 / 0.5)" but got "rgba(102, 0, 0, 0.5)"
 [FAIL] e.style['color'] = "rgba(calc(50% + (sign(1em - 10px) * 10%)), 0%, 0%, 50%)" should set the property value
-  assert_equals: serialization should be canonical expected "rgb(calc(50% + (10% * sign(1em - 10px))) 0% 0% / 50%)" but got "rgba(102, 0, 0, 0.5)"
+  assert_equals: serialization should be canonical expected "rgb(calc(50% + (10% * sign(1em - 10px))) 0 0 / 0.5)" but got "rgba(102, 0, 0, 0.5)"
 [FAIL] e.style['color'] = "rgb(calc(50 + (sign(1em - 10px) * 10)), 0, 0, 0.5)" should set the property value
   assert_equals: serialization should be canonical expected "rgb(calc(50 + (10 * sign(1em - 10px))) 0 0 / 0.5)" but got "rgba(40, 0, 0, 0.5)"
 [FAIL] e.style['color'] = "rgba(calc(50 + (sign(1em - 10px) * 10)), 0, 0, 0.5)" should set the property value
   assert_equals: serialization should be canonical expected "rgb(calc(50 + (10 * sign(1em - 10px))) 0 0 / 0.5)" but got "rgba(40, 0, 0, 0.5)"
 [FAIL] e.style['color'] = "rgb(0%, 0%, 0%, calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
-  assert_equals: serialization should be canonical expected "rgb(0% 0% 0% / calc(50% + (10% * sign(1em - 10px))))" but got "rgba(0, 0, 0, 0.4)"
+  assert_equals: serialization should be canonical expected "rgb(0 0 0 / calc(50% + (10% * sign(1em - 10px))))" but got "rgba(0, 0, 0, 0.4)"
 [FAIL] e.style['color'] = "rgba(0%, 0%, 0%, calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
-  assert_equals: serialization should be canonical expected "rgb(0% 0% 0% / calc(50% + (10% * sign(1em - 10px))))" but got "rgba(0, 0, 0, 0.4)"
+  assert_equals: serialization should be canonical expected "rgb(0 0 0 / calc(50% + (10% * sign(1em - 10px))))" but got "rgba(0, 0, 0, 0.4)"
 [FAIL] e.style['color'] = "rgb(0, 0, 0, calc(0.75 + (sign(1em - 10px) * 0.1)))" should set the property value
   assert_equals: serialization should be canonical expected "rgb(0 0 0 / calc(0.75 + (0.1 * sign(1em - 10px))))" but got "rgba(0, 0, 0, 0.65)"
 [FAIL] e.style['color'] = "rgba(0, 0, 0, calc(0.75 + (sign(1em - 10px) * 0.1)))" should set the property value
   assert_equals: serialization should be canonical expected "rgb(0 0 0 / calc(0.75 + (0.1 * sign(1em - 10px))))" but got "rgba(0, 0, 0, 0.65)"
 [FAIL] e.style['color'] = "rgb(calc(50% + (sign(1em - 10px) * 10%)) 0% 0% / 50%)" should set the property value
-  assert_equals: serialization should be canonical expected "rgb(calc(50% + (10% * sign(1em - 10px))) 0% 0% / 50%)" but got "rgba(102, 0, 0, 0.5)"
+  assert_equals: serialization should be canonical expected "rgb(calc(50% + (10% * sign(1em - 10px))) 0 0 / 0.5)" but got "rgba(102, 0, 0, 0.5)"
 [FAIL] e.style['color'] = "rgba(calc(50% + (sign(1em - 10px) * 10%)) 0% 0% / 50%)" should set the property value
-  assert_equals: serialization should be canonical expected "rgb(calc(50% + (10% * sign(1em - 10px))) 0% 0% / 50%)" but got "rgba(102, 0, 0, 0.5)"
+  assert_equals: serialization should be canonical expected "rgb(calc(50% + (10% * sign(1em - 10px))) 0 0 / 0.5)" but got "rgba(102, 0, 0, 0.5)"
 [FAIL] e.style['color'] = "rgb(calc(50 + (sign(1em - 10px) * 10)) 0 0 / 0.5)" should set the property value
   assert_equals: serialization should be canonical expected "rgb(calc(50 + (10 * sign(1em - 10px))) 0 0 / 0.5)" but got "rgba(40, 0, 0, 0.5)"
 [FAIL] e.style['color'] = "rgba(calc(50 + (sign(1em - 10px) * 10)) 0 0 / 0.5)" should set the property value
   assert_equals: serialization should be canonical expected "rgb(calc(50 + (10 * sign(1em - 10px))) 0 0 / 0.5)" but got "rgba(40, 0, 0, 0.5)"
 [FAIL] e.style['color'] = "rgb(0% 0% 0% / calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
-  assert_equals: serialization should be canonical expected "rgb(0% 0% 0% / calc(50% + (10% * sign(1em - 10px))))" but got "rgba(0, 0, 0, 0.4)"
+  assert_equals: serialization should be canonical expected "rgb(0 0 0 / calc(50% + (10% * sign(1em - 10px))))" but got "rgba(0, 0, 0, 0.4)"
 [FAIL] e.style['color'] = "rgba(0% 0% 0% / calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
-  assert_equals: serialization should be canonical expected "rgb(0% 0% 0% / calc(50% + (10% * sign(1em - 10px))))" but got "rgba(0, 0, 0, 0.4)"
+  assert_equals: serialization should be canonical expected "rgb(0 0 0 / calc(50% + (10% * sign(1em - 10px))))" but got "rgba(0, 0, 0, 0.4)"
 [FAIL] e.style['color'] = "rgb(0 0 0 / calc(0.75 + (sign(1em - 10px) * 0.1)))" should set the property value
   assert_equals: serialization should be canonical expected "rgb(0 0 0 / calc(0.75 + (0.1 * sign(1em - 10px))))" but got "rgba(0, 0, 0, 0.65)"
 [FAIL] e.style['color'] = "rgba(0 0 0 / calc(0.75 + (sign(1em - 10px) * 0.1)))" should set the property value
   assert_equals: serialization should be canonical expected "rgb(0 0 0 / calc(0.75 + (0.1 * sign(1em - 10px))))" but got "rgba(0, 0, 0, 0.65)"
 [FAIL] e.style['color'] = "rgba(calc(50% + (sign(1em - 10px) * 10%)) 0 0% / 0.5)" should set the property value
-  assert_equals: serialization should be canonical expected "rgb(calc(50% + (10% * sign(1em - 10px))) 0 0% / 0.5)" but got "rgba(102, 0, 0, 0.5)"
+  assert_equals: serialization should be canonical expected "rgb(calc(50% + (10% * sign(1em - 10px))) 0 0 / 0.5)" but got "rgba(102, 0, 0, 0.5)"
 [FAIL] e.style['color'] = "rgba(0% 0 0% / calc(0.75 + (sign(1em - 10px) * 0.1)))" should set the property value
-  assert_equals: serialization should be canonical expected "rgb(0% 0 0% / calc(0.75 + (0.1 * sign(1em - 10px))))" but got "rgba(0, 0, 0, 0.65)"
+  assert_equals: serialization should be canonical expected "rgb(0 0 0 / calc(0.75 + (0.1 * sign(1em - 10px))))" but got "rgba(0, 0, 0, 0.65)"
+[FAIL] e.style['color'] = "rgba(calc(50 + (sign(1em - 10px) * 10)) 400 -400 / 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "rgb(calc(50 + (10 * sign(1em - 10px))) 255 0 / 0.5)" but got "rgba(40, 255, 0, 0.5)"
+[FAIL] e.style['color'] = "rgba(calc(50% + (sign(1em - 10px) * 10%)) 400% -400% / 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "rgb(calc(50% + (10% * sign(1em - 10px))) 255 0 / 0.5)" but got "rgba(102, 255, 0, 0.5)"
+[FAIL] e.style['color'] = "rgba(calc(50 + (sign(1em - 10px) * 10)), 400, -400, 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "rgb(calc(50 + (10 * sign(1em - 10px))) 255 0 / 0.5)" but got "rgba(40, 255, 0, 0.5)"
+[FAIL] e.style['color'] = "rgba(calc(50% + (sign(1em - 10px) * 10%)), 400%, -400%, 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "rgb(calc(50% + (10% * sign(1em - 10px))) 255 0 / 0.5)" but got "rgba(102, 255, 0, 0.5)"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-valid-rgb.html b/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-valid-rgb.html
index 6c9f49d..36487c39 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-valid-rgb.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-valid-rgb.html
@@ -71,26 +71,31 @@
     ["rgba(0, 0, 0, calc(0 / 0))", "rgba(0, 0, 0, 0)"],
 
     // calc(50% + (sign(1em - 10px) * 10%)) cannot be evaluated eagerly because font relative units are not yet known at parse time.
-    ["rgb(calc(50% + (sign(1em - 10px) * 10%)), 0%, 0%, 50%)", "rgb(calc(50% + (10% * sign(1em - 10px))) 0% 0% / 50%)"],
-    ["rgba(calc(50% + (sign(1em - 10px) * 10%)), 0%, 0%, 50%)", "rgb(calc(50% + (10% * sign(1em - 10px))) 0% 0% / 50%)"],
+    ["rgb(calc(50% + (sign(1em - 10px) * 10%)), 0%, 0%, 50%)", "rgb(calc(50% + (10% * sign(1em - 10px))) 0 0 / 0.5)"],
+    ["rgba(calc(50% + (sign(1em - 10px) * 10%)), 0%, 0%, 50%)", "rgb(calc(50% + (10% * sign(1em - 10px))) 0 0 / 0.5)"],
     ["rgb(calc(50 + (sign(1em - 10px) * 10)), 0, 0, 0.5)", "rgb(calc(50 + (10 * sign(1em - 10px))) 0 0 / 0.5)"],
     ["rgba(calc(50 + (sign(1em - 10px) * 10)), 0, 0, 0.5)", "rgb(calc(50 + (10 * sign(1em - 10px))) 0 0 / 0.5)"],
-    ["rgb(0%, 0%, 0%, calc(50% + (sign(1em - 10px) * 10%)))", "rgb(0% 0% 0% / calc(50% + (10% * sign(1em - 10px))))"],
-    ["rgba(0%, 0%, 0%, calc(50% + (sign(1em - 10px) * 10%)))", "rgb(0% 0% 0% / calc(50% + (10% * sign(1em - 10px))))"],
+    ["rgb(0%, 0%, 0%, calc(50% + (sign(1em - 10px) * 10%)))", "rgb(0 0 0 / calc(50% + (10% * sign(1em - 10px))))"],
+    ["rgba(0%, 0%, 0%, calc(50% + (sign(1em - 10px) * 10%)))", "rgb(0 0 0 / calc(50% + (10% * sign(1em - 10px))))"],
     ["rgb(0, 0, 0, calc(0.75 + (sign(1em - 10px) * 0.1)))", "rgb(0 0 0 / calc(0.75 + (0.1 * sign(1em - 10px))))"],
     ["rgba(0, 0, 0, calc(0.75 + (sign(1em - 10px) * 0.1)))", "rgb(0 0 0 / calc(0.75 + (0.1 * sign(1em - 10px))))"],
 
-    ["rgb(calc(50% + (sign(1em - 10px) * 10%)) 0% 0% / 50%)", "rgb(calc(50% + (10% * sign(1em - 10px))) 0% 0% / 50%)"],
-    ["rgba(calc(50% + (sign(1em - 10px) * 10%)) 0% 0% / 50%)", "rgb(calc(50% + (10% * sign(1em - 10px))) 0% 0% / 50%)"],
+    ["rgb(calc(50% + (sign(1em - 10px) * 10%)) 0% 0% / 50%)", "rgb(calc(50% + (10% * sign(1em - 10px))) 0 0 / 0.5)"],
+    ["rgba(calc(50% + (sign(1em - 10px) * 10%)) 0% 0% / 50%)", "rgb(calc(50% + (10% * sign(1em - 10px))) 0 0 / 0.5)"],
     ["rgb(calc(50 + (sign(1em - 10px) * 10)) 0 0 / 0.5)", "rgb(calc(50 + (10 * sign(1em - 10px))) 0 0 / 0.5)"],
     ["rgba(calc(50 + (sign(1em - 10px) * 10)) 0 0 / 0.5)", "rgb(calc(50 + (10 * sign(1em - 10px))) 0 0 / 0.5)"],
-    ["rgb(0% 0% 0% / calc(50% + (sign(1em - 10px) * 10%)))", "rgb(0% 0% 0% / calc(50% + (10% * sign(1em - 10px))))"],
-    ["rgba(0% 0% 0% / calc(50% + (sign(1em - 10px) * 10%)))", "rgb(0% 0% 0% / calc(50% + (10% * sign(1em - 10px))))"],
+    ["rgb(0% 0% 0% / calc(50% + (sign(1em - 10px) * 10%)))", "rgb(0 0 0 / calc(50% + (10% * sign(1em - 10px))))"],
+    ["rgba(0% 0% 0% / calc(50% + (sign(1em - 10px) * 10%)))", "rgb(0 0 0 / calc(50% + (10% * sign(1em - 10px))))"],
     ["rgb(0 0 0 / calc(0.75 + (sign(1em - 10px) * 0.1)))", "rgb(0 0 0 / calc(0.75 + (0.1 * sign(1em - 10px))))"],
     ["rgba(0 0 0 / calc(0.75 + (sign(1em - 10px) * 0.1)))", "rgb(0 0 0 / calc(0.75 + (0.1 * sign(1em - 10px))))"],
 
-    ["rgba(calc(50% + (sign(1em - 10px) * 10%)) 0 0% / 0.5)", "rgb(calc(50% + (10% * sign(1em - 10px))) 0 0% / 0.5)"],
-    ["rgba(0% 0 0% / calc(0.75 + (sign(1em - 10px) * 0.1)))", "rgb(0% 0 0% / calc(0.75 + (0.1 * sign(1em - 10px))))"],
+    ["rgba(calc(50% + (sign(1em - 10px) * 10%)) 0 0% / 0.5)", "rgb(calc(50% + (10% * sign(1em - 10px))) 0 0 / 0.5)"],
+    ["rgba(0% 0 0% / calc(0.75 + (sign(1em - 10px) * 0.1)))", "rgb(0 0 0 / calc(0.75 + (0.1 * sign(1em - 10px))))"],
+
+    ["rgba(calc(50 + (sign(1em - 10px) * 10)) 400 -400 / 0.5)", "rgb(calc(50 + (10 * sign(1em - 10px))) 255 0 / 0.5)"],
+    ["rgba(calc(50% + (sign(1em - 10px) * 10%)) 400% -400% / 0.5)", "rgb(calc(50% + (10% * sign(1em - 10px))) 255 0 / 0.5)"],
+    ["rgba(calc(50 + (sign(1em - 10px) * 10)), 400, -400, 0.5)", "rgb(calc(50 + (10 * sign(1em - 10px))) 255 0 / 0.5)"],
+    ["rgba(calc(50% + (sign(1em - 10px) * 10%)), 400%, -400%, 0.5)", "rgb(calc(50% + (10% * sign(1em - 10px))) 255 0 / 0.5)"],
 ];
 
 for (const test of tests) {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-display/parsing/WEB_FEATURES.yml b/third_party/blink/web_tests/external/wpt/css/css-display/parsing/WEB_FEATURES.yml
new file mode 100644
index 0000000..616accbe
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-display/parsing/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: two-value-display
+  files: "**"
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/webkit-line-clamp-047-ref.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/webkit-line-clamp-047-ref.html
index 83c5ab8..3f1e31ab 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/webkit-line-clamp-047-ref.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/webkit-line-clamp-047-ref.html
@@ -6,7 +6,7 @@
     display: flow-root;
     background-color: yellow;
     padding: 0.5em;
-    font-size: 16px / 32px serif;
+    font: 16px / 32px serif;
     white-space: pre;
   }
   .float {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/webkit-line-clamp-049-ref.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/webkit-line-clamp-049-ref.html
new file mode 100644
index 0000000..7a3591b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/webkit-line-clamp-049-ref.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSS Test Reference</title>
+<style>
+  .no-bottom-margin {
+    margin-bottom: 0;
+  }
+  .clamp {
+    display: flow-root;
+    font: 16px / 32px serif;
+    white-space: pre;
+    background-color: yellow;
+  }
+</style>
+
+<p class="no-bottom-margin"><span>The following yellow box should clamp after 4 lines.</span></p>
+
+<div class="clamp">Line 1
+Line 2
+Line 3
+Line 4…</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-047.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-047.html
index 2e546c8..cb66eb7 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-047.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-047.html
@@ -14,7 +14,7 @@
     /* no overflow: hidden */
     background-color: yellow;
     padding: 0.5em;
-    font-size: 16px / 32px serif;
+    font: 16px / 32px serif;
     white-space: pre;
   }
   .float {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-049.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-049.html
new file mode 100644
index 0000000..807f83e5
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-049.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Overflow: -webkit-line-clamp block in inline</title>
+<link rel="author" title="Andreu Botella" href="mailto:abotella@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-overflow-4/#line-clamp">
+<link rel="match" href="reference/webkit-line-clamp-049-ref.html">
+<meta name="assert" content="If -webkit-line-clamp is a block inside an inline, it works correctly.">
+
+<style>
+p span clamp {
+  display: -webkit-box;
+  -webkit-box-orient: vertical;
+  -webkit-line-clamp: 4;
+  overflow: hidden; /* can be removed once implementations update their old -webkit-line-clamp implementations */
+  font: 16px / 32px serif;
+  white-space: pre;
+  background-color: yellow;
+}
+</style>
+
+<p><span>The following yellow box should clamp after 4 lines.
+
+<!-- Using a <clamp> element rather than e.g. <div class="clamp"> so the parser doesn't close the <p>.-->
+<clamp>Line 1
+Line 2
+Line 3
+Line 4
+Line 5</clamp>
+
+</span></p>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/break-spaces-with-word-break-001.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/break-spaces-with-word-break-001.html
new file mode 100644
index 0000000..ee31fd6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/break-spaces-with-word-break-001.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Text Test: white-space:break-spaces + word-break:keep-all</title>
+<link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-text-4/#valdef-white-space-collapse-break-spaces">
+<link rel="help" href="https://drafts.csswg.org/css-text-4/#valdef-word-break-keep-all">
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+<meta name="assert" content="break-spaces + keep-all does allow a break after space.">
+
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
+<style>
+div {
+  font: 50px/1 Ahem;
+  white-space: break-spaces;
+  word-break: keep-all;
+  width: 100px;
+  height: 100px;
+  background: red;
+  color: green;
+}
+</style>
+
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div>XX XX</div>
diff --git a/third_party/blink/web_tests/external/wpt/svg/painting/reftests/non-scaling-stroke-007-ref.html b/third_party/blink/web_tests/external/wpt/svg/painting/reftests/non-scaling-stroke-007-ref.html
new file mode 100644
index 0000000..d0f84d73
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/svg/painting/reftests/non-scaling-stroke-007-ref.html
@@ -0,0 +1,5 @@
+<!doctype html>
+<title>CSS Test Reference</title>
+<svg width="100" height="100">
+  <path d="M 0 0 L 0 300 L 300 0 z" fill="none" stroke="currentColor" stroke-width="20"></path>
+</svg>
diff --git a/third_party/blink/web_tests/external/wpt/svg/painting/reftests/non-scaling-stroke-007.html b/third_party/blink/web_tests/external/wpt/svg/painting/reftests/non-scaling-stroke-007.html
new file mode 100644
index 0000000..2b63060
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/svg/painting/reftests/non-scaling-stroke-007.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>non-scaling-stroke on a nested SVG</title>
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1917604">
+<link rel="help" href="https://svgwg.org/svg2-draft/painting.html#PaintingVectorEffects">
+<link rel="match" href="non-scaling-stroke-007-ref.html">
+<svg width="100" height="100">
+  <svg width="100%" height="100%" viewBox="0 0 1 1" preserveAspectRatio="none">
+    <path d="M 0 0 L 0 50 L 50 0 z" fill="none" stroke="currentColor" stroke-width="20" vector-effect="non-scaling-stroke"></path>
+  </svg>
+</svg>
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/dequantizeLinear.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/dequantizeLinear.https.any.js
new file mode 100644
index 0000000..2939121
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/dequantizeLinear.https.any.js
@@ -0,0 +1,160 @@
+// META: title=test WebNN API dequantizeLinear operation
+// META: global=window,dedicatedworker
+// META: variant=?cpu
+// META: variant=?gpu
+// META: variant=?npu
+// META: script=../resources/utils.js
+// META: timeout=long
+
+'use strict';
+
+// Calculate a low precision integer operand
+// (typically uint8 with a zero-point bias) to floating point:
+//   output = (input - zeroPoint) * scale.
+//
+// MLOperand dequantizeLinear(
+//     MLOperand input, MLOperand scale, MLOperand zeroPoint,
+//     optional MLOperatorOptions options = {});
+
+
+const getDequantizeLinearPrecisionTolerance = (graphResources) => {
+  const toleranceValueDict = {float32: 1};
+  const expectedDataType =
+      getExpectedDataTypeOfSingleOutput(graphResources.expectedOutputs);
+  return {metricType: 'ULP', value: toleranceValueDict[expectedDataType]};
+};
+
+const dequantizeLinearTests = [
+  {
+    'name': 'dequantizeLinear int8 0D tensor with float32 scalar scale',
+    'graph': {
+      'inputs': {
+        'dequantizeLinearInput': {
+          'data': [123],
+          'descriptor': {'dimensions': [], 'dataType': 'int8'},
+          'constant': true
+        },
+        'dequantizeLinearScale': {
+          'data': [1.1202747821807861],
+          'descriptor': {'dimensions': [], 'dataType': 'float32'},
+          'constant': true
+        },
+        'dequantizeLinearZeroPoint': {
+          'data': [3],
+          'descriptor': {'dimensions': [], 'dataType': 'int8'},
+          'constant': true
+        }
+      },
+      'operators': [{
+        'name': 'dequantizeLinear',
+        'arguments': [
+          {'input': 'dequantizeLinearInput'},
+          {'scale': 'dequantizeLinearScale'},
+          {'zeroPoint': 'dequantizeLinearZeroPoint'}
+        ],
+        'outputs': 'dequantizeLinearOutput'
+      }],
+      'expectedOutputs': {
+        'dequantizeLinearOutput': {
+          'data': [134.43296813964844],
+          'descriptor': {'dimensions': [], 'dataType': 'float32'}
+        }
+      }
+    }
+  },
+  {
+    'name': 'dequantizeLinear uint8 1D constant tensor broadcasting zeroPoint',
+    'graph': {
+      'inputs': {
+        'dequantizeLinearInput': {
+          'data': [12, 24, 35, 123],
+          'descriptor': {'dimensions': [4], 'dataType': 'uint8'},
+          'constant': true
+        },
+        'dequantizeLinearScale': {
+          'data': [
+            9.343092918395996,
+            0.2800687253475189,
+            -4.617084980010986,
+            1.1202747821807861,
+          ],
+          'descriptor': {'dimensions': [4], 'dataType': 'float32'},
+          'constant': true
+        },
+        'dequantizeLinearZeroPoint': {
+          'data': [128],
+          'descriptor': {'dimensions': [], 'dataType': 'uint8'},
+          'constant': true
+        }
+      },
+      'operators': [{
+        'name': 'dequantizeLinear',
+        'arguments': [
+          {'input': 'dequantizeLinearInput'},
+          {'scale': 'dequantizeLinearScale'},
+          {'zeroPoint': 'dequantizeLinearZeroPoint'}
+        ],
+        'outputs': 'dequantizeLinearOutput'
+      }],
+      'expectedOutputs': {
+        'dequantizeLinearOutput': {
+          'data': [
+            -1083.798828125, -29.127147674560547, 429.388916015625,
+            -5.601373672485352
+          ],
+          'descriptor': {'dimensions': [4], 'dataType': 'float32'}
+        }
+      }
+    }
+  },
+  {
+    'name':
+        'dequantizeLinear int8 4D constant tensor broadcasting scale and zeroPoint',
+    'graph': {
+      'inputs': {
+        'dequantizeLinearInput': {
+          'data': [-124, 0, 23, 122],
+          'descriptor': {'dimensions': [1, 1, 2, 2], 'dataType': 'int8'},
+          'constant': true
+        },
+        'dequantizeLinearScale': {
+          'data': [0.2800687253475189, -4.617084980010986],
+          'descriptor': {'dimensions': [2, 1], 'dataType': 'float32'},
+          'constant': true
+        },
+        'dequantizeLinearZeroPoint': {
+          'data': [12],
+          'descriptor': {'dimensions': [], 'dataType': 'int8'},
+          'constant': true
+        }
+      },
+      'operators': [{
+        'name': 'dequantizeLinear',
+        'arguments': [
+          {'input': 'dequantizeLinearInput'},
+          {'scale': 'dequantizeLinearScale'},
+          {'zeroPoint': 'dequantizeLinearZeroPoint'}
+        ],
+        'outputs': 'dequantizeLinearOutput'
+      }],
+      'expectedOutputs': {
+        'dequantizeLinearOutput': {
+          'data': [
+            -38.08934783935547, -3.3608245849609375, -50.787933349609375,
+            -507.87933349609375
+          ],
+          'descriptor': {'dimensions': [1, 1, 2, 2], 'dataType': 'float32'}
+        }
+      }
+    }
+  }
+];
+
+if (navigator.ml) {
+  dequantizeLinearTests.forEach((test) => {
+    webnn_conformance_test(
+        buildGraphAndCompute, getDequantizeLinearPrecisionTolerance, test);
+  });
+} else {
+  test(() => assert_implements(navigator.ml, 'missing navigator.ml'));
+}
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/quantizeLinear.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/quantizeLinear.https.any.js
new file mode 100644
index 0000000..acae378d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/quantizeLinear.https.any.js
@@ -0,0 +1,156 @@
+// META: title=test WebNN API quantizeLinear operation
+// META: global=window,dedicatedworker
+// META: variant=?cpu
+// META: variant=?gpu
+// META: variant=?npu
+// META: script=../resources/utils.js
+// META: timeout=long
+
+'use strict';
+
+// Calculate a floating-point input down to a low-precision integer
+// (typically uint8 with a zero-point bias) following the expression:
+//    output = clamp(roundToNearestEvens(input / scale) + zeroPoint, 0, 255).
+//
+// MLOperand quantizeLinear(
+//     MLOperand input, MLOperand scale, MLOperand zeroPoint,
+//     optional MLOperatorOptions options = {});
+
+
+const getQuantizeLinearPrecisionTolerance = (graphResources) => {
+  const toleranceValueDict = {int8: 1, uint8: 1};
+  const expectedDataType =
+      getExpectedDataTypeOfSingleOutput(graphResources.expectedOutputs);
+  return {metricType: 'ULP', value: toleranceValueDict[expectedDataType]};
+};
+
+const quantizeLinearTests = [
+  {
+    'name':
+        'quantizeLinear float32 0D scalar tensor with int8 scalar zeroPoint',
+    'graph': {
+      'inputs': {
+        'quantizeLinearInput': {
+          'data': [10.794857501983643],
+          'descriptor': {'dimensions': [], 'dataType': 'float32'},
+          'constant': true
+        },
+        'quantizeLinearScale': {
+          'data': [1.1202747821807861],
+          'descriptor': {'dimensions': [], 'dataType': 'float32'},
+          'constant': true
+        },
+        'quantizeLinearZeroPoint': {
+          'data': [1],
+          'descriptor': {'dimensions': [], 'dataType': 'int8'},
+          'constant': true
+        }
+      },
+      'operators': [{
+        'name': 'quantizeLinear',
+        'arguments': [
+          {'input': 'quantizeLinearInput'}, {'scale': 'quantizeLinearScale'},
+          {'zeroPoint': 'quantizeLinearZeroPoint'}
+        ],
+        'outputs': 'quantizeLinearOutput'
+      }],
+      'expectedOutputs': {
+        'quantizeLinearOutput':
+            {'data': [11], 'descriptor': {'dimensions': [], 'dataType': 'int8'}}
+      }
+    }
+  },
+  {
+    'name': 'quantizeLinear float32 1D constant tensor broadcasting zeroPoint',
+    'graph': {
+      'inputs': {
+        'quantizeLinearInput': {
+          'data': [
+            -2.549168109893799, -4.794857501983643, 8.413617134094238,
+            6.108623504638672
+          ],
+          'descriptor': {'dimensions': [4], 'dataType': 'float32'},
+          'constant': true
+        },
+        'quantizeLinearScale': {
+          'data': [
+            9.343092918395996,
+            0.2800687253475189,
+            -4.617084980010986,
+            1.1202747821807861,
+          ],
+          'descriptor': {'dimensions': [4], 'dataType': 'float32'},
+          'constant': true
+        },
+        'quantizeLinearZeroPoint': {
+          'data': [128],
+          'descriptor': {'dimensions': [], 'dataType': 'uint8'},
+          'constant': true
+        }
+      },
+      'operators': [{
+        'name': 'quantizeLinear',
+        'arguments': [
+          {'input': 'quantizeLinearInput'}, {'scale': 'quantizeLinearScale'},
+          {'zeroPoint': 'quantizeLinearZeroPoint'}
+        ],
+        'outputs': 'quantizeLinearOutput'
+      }],
+      'expectedOutputs': {
+        'quantizeLinearOutput': {
+          'data': [128, 111, 126, 133],
+          'descriptor': {'dimensions': [4], 'dataType': 'uint8'}
+        }
+      }
+    }
+  },
+  {
+    'name':
+        'quantizeLinear float32 4D constant tensor broadcasting scale and zeroPoint',
+    'graph': {
+      'inputs': {
+        'quantizeLinearInput': {
+          'data': [
+            -2.549168109893799, -4.794857501983643, 8.413617134094238,
+            6.108623504638672
+          ],
+          'descriptor': {'dimensions': [1, 1, 2, 2], 'dataType': 'float32'},
+          'constant': true
+        },
+        'quantizeLinearScale': {
+          'data': [0.2800687253475189, -4.617084980010986],
+          'descriptor': {'dimensions': [2, 1], 'dataType': 'float32'},
+          'constant': true
+        },
+        'quantizeLinearZeroPoint': {
+          'data': [128],
+          'descriptor': {'dimensions': [], 'dataType': 'uint8'},
+          'constant': true
+        }
+      },
+      'operators': [{
+        'name': 'quantizeLinear',
+        'arguments': [
+          {'input': 'quantizeLinearInput'}, {'scale': 'quantizeLinearScale'},
+          {'zeroPoint': 'quantizeLinearZeroPoint'}
+        ],
+        'outputs': 'quantizeLinearOutput'
+      }],
+      'expectedOutputs': {
+        'quantizeLinearOutput': {
+          'data': [119, 111, 126, 127],
+          'descriptor': {'dimensions': [1, 1, 2, 2], 'dataType': 'uint8'}
+        }
+      }
+    }
+  }
+];
+
+if (navigator.ml) {
+  quantizeLinearTests.forEach((test) => {
+    webnn_conformance_test(
+        buildGraphAndCompute, getQuantizeLinearPrecisionTolerance, test);
+  });
+} else {
+  test(() => assert_implements(navigator.ml, 'missing navigator.ml'));
+}
diff --git a/third_party/blink/web_tests/external/wpt/webnn/resources/utils.js b/third_party/blink/web_tests/external/wpt/webnn/resources/utils.js
index e4a1e89..c6b6010b 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/resources/utils.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/resources/utils.js
@@ -207,6 +207,14 @@
       } else if (dataType === 'int64') {
         actualBitwise = actual[i];
         expectedBitwise = BigInt(expected[i]);
+      } else if (dataType === 'uint64') {
+        actualBitwise = actual[i];
+        expectedBitwise = BigUint64Array(expected[i]);
+      } else if (
+          dataType === 'int8' || dataType === 'uint8' || dataType === 'int32' ||
+          dataType === 'uint32') {
+        actualBitwise = actual[i];
+        expectedBitwise = expected[i];
       }
       distance = actualBitwise - expectedBitwise;
       distance = distance >= 0 ? distance : -distance;
diff --git a/third_party/blink/web_tests/external/wpt/webnn/validation_tests/scatterND.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/validation_tests/scatterND.https.any.js
new file mode 100644
index 0000000..18fcb40
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webnn/validation_tests/scatterND.https.any.js
@@ -0,0 +1,102 @@
+// META: title=validation tests for WebNN API scatterND operation
+// META: global=window,dedicatedworker
+// META: variant=?cpu
+// META: variant=?gpu
+// META: variant=?npu
+// META: script=../resources/utils_validation.js
+
+'use strict';
+
+const tests = [
+  {
+    name: '[scatterND] Test scatterND with valid tensors',
+    input: {dataType: 'float32', dimensions: [4, 4, 4]},
+    indices: {dataType: 'int32', dimensions: [2, 1]},
+    updates: {dataType: 'float32', dimensions: [2, 4, 4]},
+    output: {dataType: 'float32', dimensions: [4, 4, 4]}
+  },
+  {
+    name:
+        '[scatterND] Throw if updates tensor data type is not the same as input data type',
+    input: {dataType: 'float32', dimensions: [4, 4, 4]},
+    indices: {dataType: 'int32', dimensions: [2, 1]},
+    updates: {dataType: 'float16', dimensions: [2, 4, 4]},
+  },
+  {
+    name: '[scatterND] Throw if input is a scalar',
+    input: {dataType: 'float32', dimensions: []},
+    indices: {dataType: 'int32', dimensions: [2, 1]},
+    updates: {dataType: 'float32', dimensions: [2, 4, 4]},
+  },
+  {
+    name: '[scatterND] Throw if indices is a scalar',
+    input: {dataType: 'float32', dimensions: [4, 4, 4]},
+    indices: {dataType: 'int32', dimensions: []},
+    updates: {dataType: 'float32', dimensions: [2, 4, 4]},
+  },
+  {
+    name:
+        '[scatterND] Throw if the size of last dimension of indices tensor is greater than input rank',
+    input: {dataType: 'float32', dimensions: [4, 4, 4]},
+    indices: {dataType: 'int32', dimensions: [2, 4]},
+    updates: {dataType: 'float32', dimensions: [2, 4, 4]},
+  },
+  {
+    name: '[scatterND] Throw if updates tensor shape is invalid.',
+    input: {dataType: 'float32', dimensions: [4, 4, 4]},
+    indices: {dataType: 'int32', dimensions: [2, 1]},
+    // Updates tensor shape should be [2, 4, 4].
+    updates: {dataType: 'float32', dimensions: [2, 3, 4]},
+  }
+];
+
+tests.forEach(test => promise_test(async t => {
+                const builder = new MLGraphBuilder(context);
+                const input = builder.input('input', test.input);
+                const indices = builder.input('indices', test.indices);
+                const updates = builder.input('updates', test.updates);
+
+                if (test.output) {
+                  const output = builder.scatterND(input, indices, updates);
+                  assert_equals(output.dataType(), test.output.dataType);
+                  assert_array_equals(output.shape(), test.output.dimensions);
+                } else {
+                  const label = 'a_scatter_nd'
+                  const options = {label};
+                  const regexp = new RegExp('\\[' + label + '\\]');
+                  assert_throws_with_label(
+                      () => builder.scatterND(input, indices, updates, options),
+                      regexp);
+                }
+              }, test.name));
+
+multi_builder_test(async (t, builder, otherBuilder) => {
+  const input =
+      otherBuilder.input('input', {dataType: 'float32', dimensions: [8]});
+  const indices =
+      builder.input('indices', {dataType: 'int32', dimensions: [4, 1]});
+  const updates =
+      builder.input('indices', {dataType: 'int32', dimensions: [4]});
+
+  assert_throws_js(TypeError, () => builder.scatterND(input, indices, updates));
+}, '[scatterND] Throw if input is from another builder');
+
+multi_builder_test(async (t, builder, otherBuilder) => {
+  const input = builder.input('input', {dataType: 'float32', dimensions: [8]});
+  const indices =
+      otherBuilder.input('indices', {dataType: 'int32', dimensions: [4, 1]});
+  const updates =
+      builder.input('indices', {dataType: 'int32', dimensions: [4]});
+
+  assert_throws_js(TypeError, () => builder.scatterND(input, indices, updates));
+}, '[scatterND] Throw if indcies is from another builder');
+
+multi_builder_test(async (t, builder, otherBuilder) => {
+  const input = builder.input('input', {dataType: 'float32', dimensions: [8]});
+  const indices =
+      builder.input('indices', {dataType: 'int32', dimensions: [4, 1]});
+  const updates =
+      otherBuilder.input('indices', {dataType: 'int32', dimensions: [4]});
+
+  assert_throws_js(TypeError, () => builder.scatterND(input, indices, updates));
+}, '[scatterND] Throw if updates is from another builder');
diff --git a/third_party/blink/web_tests/flag-specific/enable-skia-graphite/external/wpt/css/css-color/parsing/color-valid-color-function-expected.txt b/third_party/blink/web_tests/flag-specific/enable-skia-graphite/external/wpt/css/css-color/parsing/color-valid-color-function-expected.txt
new file mode 100644
index 0000000..feecea5
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-skia-graphite/external/wpt/css/css-color/parsing/color-valid-color-function-expected.txt
@@ -0,0 +1,40 @@
+This is a testharness.js-based test.
+Found 18 FAIL, 0 TIMEOUT, 0 NOTRUN.
+[FAIL] e.style['color'] = "color(srgb calc(50% + (sign(1em - 10px) * 10%)) 0 0 / 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "color(srgb calc(50% + (10% * sign(1em - 10px))) 0 0 / 0.5)" but got "color(srgb 0.4 0 0 / 0.5)"
+[FAIL] e.style['color'] = "color(srgb 0.5 0 0 / calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
+  assert_equals: serialization should be canonical expected "color(srgb 0.5 0 0 / calc(50% + (10% * sign(1em - 10px))))" but got "color(srgb 0.5 0 0 / 0.4)"
+[FAIL] e.style['color'] = "color(srgb-linear calc(50% + (sign(1em - 10px) * 10%)) 0 0 / 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "color(srgb-linear calc(50% + (10% * sign(1em - 10px))) 0 0 / 0.5)" but got "color(srgb-linear 0.4 0 0 / 0.5)"
+[FAIL] e.style['color'] = "color(srgb-linear 0.5 0 0 / calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
+  assert_equals: serialization should be canonical expected "color(srgb-linear 0.5 0 0 / calc(50% + (10% * sign(1em - 10px))))" but got "color(srgb-linear 0.5 0 0 / 0.4)"
+[FAIL] e.style['color'] = "color(a98-rgb calc(50% + (sign(1em - 10px) * 10%)) 0 0 / 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "color(a98-rgb calc(50% + (10% * sign(1em - 10px))) 0 0 / 0.5)" but got "color(a98-rgb 0.4 0 0 / 0.5)"
+[FAIL] e.style['color'] = "color(a98-rgb 0.5 0 0 / calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
+  assert_equals: serialization should be canonical expected "color(a98-rgb 0.5 0 0 / calc(50% + (10% * sign(1em - 10px))))" but got "color(a98-rgb 0.5 0 0 / 0.4)"
+[FAIL] e.style['color'] = "color(rec2020 calc(50% + (sign(1em - 10px) * 10%)) 0 0 / 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "color(rec2020 calc(50% + (10% * sign(1em - 10px))) 0 0 / 0.5)" but got "color(rec2020 0.4 0 0 / 0.5)"
+[FAIL] e.style['color'] = "color(rec2020 0.5 0 0 / calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
+  assert_equals: serialization should be canonical expected "color(rec2020 0.5 0 0 / calc(50% + (10% * sign(1em - 10px))))" but got "color(rec2020 0.5 0 0 / 0.4)"
+[FAIL] e.style['color'] = "color(prophoto-rgb calc(50% + (sign(1em - 10px) * 10%)) 0 0 / 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "color(prophoto-rgb calc(50% + (10% * sign(1em - 10px))) 0 0 / 0.5)" but got "color(prophoto-rgb 0.4 0 0 / 0.5)"
+[FAIL] e.style['color'] = "color(prophoto-rgb 0.5 0 0 / calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
+  assert_equals: serialization should be canonical expected "color(prophoto-rgb 0.5 0 0 / calc(50% + (10% * sign(1em - 10px))))" but got "color(prophoto-rgb 0.5 0 0 / 0.4)"
+[FAIL] e.style['color'] = "color(display-p3 calc(50% + (sign(1em - 10px) * 10%)) 0 0 / 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "color(display-p3 calc(50% + (10% * sign(1em - 10px))) 0 0 / 0.5)" but got "color(display-p3 0.4 0 0 / 0.5)"
+[FAIL] e.style['color'] = "color(display-p3 0.5 0 0 / calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
+  assert_equals: serialization should be canonical expected "color(display-p3 0.5 0 0 / calc(50% + (10% * sign(1em - 10px))))" but got "color(display-p3 0.5 0 0 / 0.4)"
+[FAIL] e.style['color'] = "color(xyz calc(0.5 + (sign(1em - 10px) * 0.1)) 0 0 / 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "color(xyz-d65 calc(0.5 + (0.1 * sign(1em - 10px))) 0 0 / 0.5)" but got "color(xyz-d65 0.4 0 0 / 0.5)"
+[FAIL] e.style['color'] = "color(xyz 0.5 0 0 / calc(0.5 + (sign(1em - 10px) * 0.1)))" should set the property value
+  assert_equals: serialization should be canonical expected "color(xyz-d65 0.5 0 0 / calc(0.5 + (0.1 * sign(1em - 10px))))" but got "color(xyz-d65 0.5 0 0 / 0.4)"
+[FAIL] e.style['color'] = "color(xyz-d50 calc(0.5 + (sign(1em - 10px) * 0.1)) 0 0 / 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "color(xyz-d50 calc(0.5 + (0.1 * sign(1em - 10px))) 0 0 / 0.5)" but got "color(xyz-d50 0.4 0 0 / 0.5)"
+[FAIL] e.style['color'] = "color(xyz-d50 0.5 0 0 / calc(0.5 + (sign(1em - 10px) * 0.1)))" should set the property value
+  assert_equals: serialization should be canonical expected "color(xyz-d50 0.5 0 0 / calc(0.5 + (0.1 * sign(1em - 10px))))" but got "color(xyz-d50 0.5 0 0 / 0.4)"
+[FAIL] e.style['color'] = "color(xyz-d65 calc(0.5 + (sign(1em - 10px) * 0.1)) 0 0 / 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "color(xyz-d65 calc(0.5 + (0.1 * sign(1em - 10px))) 0 0 / 0.5)" but got "color(xyz-d65 0.4 0 0 / 0.5)"
+[FAIL] e.style['color'] = "color(xyz-d65 0.5 0 0 / calc(0.5 + (sign(1em - 10px) * 0.1)))" should set the property value
+  assert_equals: serialization should be canonical expected "color(xyz-d65 0.5 0 0 / calc(0.5 + (0.1 * sign(1em - 10px))))" but got "color(xyz-d65 0.5 0 0 / 0.4)"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/flag-specific/enable-skia-graphite/external/wpt/css/css-color/parsing/color-valid-lab-expected.txt b/third_party/blink/web_tests/flag-specific/enable-skia-graphite/external/wpt/css/css-color/parsing/color-valid-lab-expected.txt
new file mode 100644
index 0000000..63777f4
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-skia-graphite/external/wpt/css/css-color/parsing/color-valid-lab-expected.txt
@@ -0,0 +1,20 @@
+This is a testharness.js-based test.
+Found 8 FAIL, 0 TIMEOUT, 0 NOTRUN.
+[FAIL] e.style['color'] = "lab(calc(50 + (sign(1em - 10px) * 10)) 30 50 / 50%)" should set the property value
+  assert_equals: serialization should be canonical expected "lab(calc(50 + (10 * sign(1em - 10px))) 30 50 / 50%)" but got "lab(40 30 50 / 0.5)"
+[FAIL] e.style['color'] = "oklab(calc(0.5 + (sign(1em - 10px) * 0.1)) 0.3 0.5 / 50%)" should set the property value
+  assert_equals: serialization should be canonical expected "oklab(calc(0.5 + (0.1 * sign(1em - 10px))) 0.3 0.5 / 50%)" but got "oklab(0.4 0.3 0.5 / 0.5)"
+[FAIL] e.style['color'] = "lab(60 30 50 / calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
+  assert_equals: serialization should be canonical expected "lab(60 30 50 / calc(50% + (10% * sign(1em - 10px))))" but got "lab(60 30 50 / 0.4)"
+[FAIL] e.style['color'] = "oklab(0.6 0.3 0.5 / calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
+  assert_equals: serialization should be canonical expected "oklab(0.6 0.3 0.5 / calc(50% + (10% * sign(1em - 10px))))" but got "oklab(0.6 0.3 0.5 / 0.4)"
+[FAIL] e.style['color'] = "lch(calc(50 + (sign(1em - 10px) * 10)) 30 50deg / 50%)" should set the property value
+  assert_equals: serialization should be canonical expected "lch(calc(50 + (10 * sign(1em - 10px))) 30 50deg / 50%)" but got "lch(40 30 50 / 0.5)"
+[FAIL] e.style['color'] = "oklch(calc(0.5 + (sign(1em - 10px) * 0.1)) 0.3 50deg / 50%)" should set the property value
+  assert_equals: serialization should be canonical expected "oklch(calc(0.5 + (0.1 * sign(1em - 10px))) 0.3 50deg / 50%)" but got "oklch(0.4 0.3 50 / 0.5)"
+[FAIL] e.style['color'] = "lch(60 30 50deg / calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
+  assert_equals: serialization should be canonical expected "lch(60 30 50deg / calc(50% + (10% * sign(1em - 10px))))" but got "lch(60 30 50 / 0.4)"
+[FAIL] e.style['color'] = "oklch(0.6 0.3 50deg / calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
+  assert_equals: serialization should be canonical expected "oklch(0.6 0.3 50deg / calc(50% + (10% * sign(1em - 10px))))" but got "oklch(0.6 0.3 50 / 0.4)"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/flag-specific/enable-skia-graphite/external/wpt/css/css-color/parsing/color-valid-rgb-expected.txt b/third_party/blink/web_tests/flag-specific/enable-skia-graphite/external/wpt/css/css-color/parsing/color-valid-rgb-expected.txt
new file mode 100644
index 0000000..c4fd42d
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-skia-graphite/external/wpt/css/css-color/parsing/color-valid-rgb-expected.txt
@@ -0,0 +1,40 @@
+This is a testharness.js-based test.
+Found 18 FAIL, 0 TIMEOUT, 0 NOTRUN.
+[FAIL] e.style['color'] = "rgb(calc(50% + (sign(1em - 10px) * 10%)), 0%, 0%, 50%)" should set the property value
+  assert_equals: serialization should be canonical expected "rgb(calc(50% + (10% * sign(1em - 10px))) 0% 0% / 50%)" but got "rgba(102, 0, 0, 0.5)"
+[FAIL] e.style['color'] = "rgba(calc(50% + (sign(1em - 10px) * 10%)), 0%, 0%, 50%)" should set the property value
+  assert_equals: serialization should be canonical expected "rgb(calc(50% + (10% * sign(1em - 10px))) 0% 0% / 50%)" but got "rgba(102, 0, 0, 0.5)"
+[FAIL] e.style['color'] = "rgb(calc(50 + (sign(1em - 10px) * 10)), 0, 0, 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "rgb(calc(50 + (10 * sign(1em - 10px))) 0 0 / 0.5)" but got "rgba(40, 0, 0, 0.5)"
+[FAIL] e.style['color'] = "rgba(calc(50 + (sign(1em - 10px) * 10)), 0, 0, 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "rgb(calc(50 + (10 * sign(1em - 10px))) 0 0 / 0.5)" but got "rgba(40, 0, 0, 0.5)"
+[FAIL] e.style['color'] = "rgb(0%, 0%, 0%, calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
+  assert_equals: serialization should be canonical expected "rgb(0% 0% 0% / calc(50% + (10% * sign(1em - 10px))))" but got "rgba(0, 0, 0, 0.4)"
+[FAIL] e.style['color'] = "rgba(0%, 0%, 0%, calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
+  assert_equals: serialization should be canonical expected "rgb(0% 0% 0% / calc(50% + (10% * sign(1em - 10px))))" but got "rgba(0, 0, 0, 0.4)"
+[FAIL] e.style['color'] = "rgb(0, 0, 0, calc(0.75 + (sign(1em - 10px) * 0.1)))" should set the property value
+  assert_equals: serialization should be canonical expected "rgb(0 0 0 / calc(0.75 + (0.1 * sign(1em - 10px))))" but got "rgba(0, 0, 0, 0.65)"
+[FAIL] e.style['color'] = "rgba(0, 0, 0, calc(0.75 + (sign(1em - 10px) * 0.1)))" should set the property value
+  assert_equals: serialization should be canonical expected "rgb(0 0 0 / calc(0.75 + (0.1 * sign(1em - 10px))))" but got "rgba(0, 0, 0, 0.65)"
+[FAIL] e.style['color'] = "rgb(calc(50% + (sign(1em - 10px) * 10%)) 0% 0% / 50%)" should set the property value
+  assert_equals: serialization should be canonical expected "rgb(calc(50% + (10% * sign(1em - 10px))) 0% 0% / 50%)" but got "rgba(102, 0, 0, 0.5)"
+[FAIL] e.style['color'] = "rgba(calc(50% + (sign(1em - 10px) * 10%)) 0% 0% / 50%)" should set the property value
+  assert_equals: serialization should be canonical expected "rgb(calc(50% + (10% * sign(1em - 10px))) 0% 0% / 50%)" but got "rgba(102, 0, 0, 0.5)"
+[FAIL] e.style['color'] = "rgb(calc(50 + (sign(1em - 10px) * 10)) 0 0 / 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "rgb(calc(50 + (10 * sign(1em - 10px))) 0 0 / 0.5)" but got "rgba(40, 0, 0, 0.5)"
+[FAIL] e.style['color'] = "rgba(calc(50 + (sign(1em - 10px) * 10)) 0 0 / 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "rgb(calc(50 + (10 * sign(1em - 10px))) 0 0 / 0.5)" but got "rgba(40, 0, 0, 0.5)"
+[FAIL] e.style['color'] = "rgb(0% 0% 0% / calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
+  assert_equals: serialization should be canonical expected "rgb(0% 0% 0% / calc(50% + (10% * sign(1em - 10px))))" but got "rgba(0, 0, 0, 0.4)"
+[FAIL] e.style['color'] = "rgba(0% 0% 0% / calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
+  assert_equals: serialization should be canonical expected "rgb(0% 0% 0% / calc(50% + (10% * sign(1em - 10px))))" but got "rgba(0, 0, 0, 0.4)"
+[FAIL] e.style['color'] = "rgb(0 0 0 / calc(0.75 + (sign(1em - 10px) * 0.1)))" should set the property value
+  assert_equals: serialization should be canonical expected "rgb(0 0 0 / calc(0.75 + (0.1 * sign(1em - 10px))))" but got "rgba(0, 0, 0, 0.65)"
+[FAIL] e.style['color'] = "rgba(0 0 0 / calc(0.75 + (sign(1em - 10px) * 0.1)))" should set the property value
+  assert_equals: serialization should be canonical expected "rgb(0 0 0 / calc(0.75 + (0.1 * sign(1em - 10px))))" but got "rgba(0, 0, 0, 0.65)"
+[FAIL] e.style['color'] = "rgba(calc(50% + (sign(1em - 10px) * 10%)) 0 0% / 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "rgb(calc(50% + (10% * sign(1em - 10px))) 0 0% / 0.5)" but got "rgba(102, 0, 0, 0.5)"
+[FAIL] e.style['color'] = "rgba(0% 0 0% / calc(0.75 + (sign(1em - 10px) * 0.1)))" should set the property value
+  assert_equals: serialization should be canonical expected "rgb(0% 0 0% / calc(0.75 + (0.1 * sign(1em - 10px))))" but got "rgba(0, 0, 0, 0.65)"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/webdriver/tests/bidi/browsing_context/context_destroyed/context_destroyed-expected.txt b/third_party/blink/web_tests/platform/linux/external/wpt/webdriver/tests/bidi/browsing_context/context_destroyed/context_destroyed-expected.txt
deleted file mode 100644
index 4f342d7..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/webdriver/tests/bidi/browsing_context/context_destroyed/context_destroyed-expected.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-This is a wdspec test.
-[FAIL] test_delete_nested_iframes
-  AssertionError: assert 2 == 1
-[FAIL] test_iframe_destroy_parent
-  AssertionError: assert 3 == 1
-Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/webdriver/tests/bidi/script/realm_created/realm_created-expected.txt b/third_party/blink/web_tests/platform/linux/external/wpt/webdriver/tests/bidi/script/realm_created/realm_created-expected.txt
deleted file mode 100644
index c56e363..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/webdriver/tests/bidi/script/realm_created/realm_created-expected.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-This is a wdspec test.
-[FAIL] test_existing_realm[tab]
-  asyncio.exceptions.TimeoutError
-[FAIL] test_existing_realm[window]
-  asyncio.exceptions.TimeoutError
-Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/dequantizeLinear.https.any.worker_gpu-expected.txt b/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/dequantizeLinear.https.any.worker_gpu-expected.txt
similarity index 61%
rename from third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/dequantizeLinear.https.any.worker_gpu-expected.txt
rename to third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/dequantizeLinear.https.any.worker_gpu-expected.txt
index b7347e1..c10e6a9 100644
--- a/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/dequantizeLinear.https.any.worker_gpu-expected.txt
+++ b/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/dequantizeLinear.https.any.worker_gpu-expected.txt
@@ -1,9 +1,9 @@
 This is a testharness.js-based test.
-[FAIL] [dequantizeLinear] Test scale's shape = [3, 2, 5] and zeroPoint's shape = [3, 2, 5] which is the same as input's shape.
+[FAIL] dequantizeLinear int8 0D tensor with float32 scalar scale
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'dequantizeLinear' on 'MLGraphBuilder': Unsupported data type int8 for argument input, must be one of []."
-[FAIL] [dequantizeLinear] Test scale's shape = [5] and zeroPoint's shape = [5] which is unidirectionally broadcastable to input's shape.
-  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'dequantizeLinear' on 'MLGraphBuilder': Unsupported data type int8 for argument input, must be one of []."
-[FAIL] [dequantizeLinear] Test scale's shape = [] and zeroPoint's shape = [] which is unidirectionally broadcastable to input's shape.
+[FAIL] dequantizeLinear uint8 1D constant tensor broadcasting zeroPoint
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'dequantizeLinear' on 'MLGraphBuilder': Unsupported data type uint8 for argument input, must be one of []."
+[FAIL] dequantizeLinear int8 4D constant tensor broadcasting scale and zeroPoint
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'dequantizeLinear' on 'MLGraphBuilder': Unsupported data type int8 for argument input, must be one of []."
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/dequantizeLinear.https.any.worker_gpu-expected.txt b/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/dequantizeLinear.https.any_gpu-expected.txt
similarity index 61%
copy from third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/dequantizeLinear.https.any.worker_gpu-expected.txt
copy to third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/dequantizeLinear.https.any_gpu-expected.txt
index b7347e1..c10e6a9 100644
--- a/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/dequantizeLinear.https.any.worker_gpu-expected.txt
+++ b/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/dequantizeLinear.https.any_gpu-expected.txt
@@ -1,9 +1,9 @@
 This is a testharness.js-based test.
-[FAIL] [dequantizeLinear] Test scale's shape = [3, 2, 5] and zeroPoint's shape = [3, 2, 5] which is the same as input's shape.
+[FAIL] dequantizeLinear int8 0D tensor with float32 scalar scale
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'dequantizeLinear' on 'MLGraphBuilder': Unsupported data type int8 for argument input, must be one of []."
-[FAIL] [dequantizeLinear] Test scale's shape = [5] and zeroPoint's shape = [5] which is unidirectionally broadcastable to input's shape.
-  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'dequantizeLinear' on 'MLGraphBuilder': Unsupported data type int8 for argument input, must be one of []."
-[FAIL] [dequantizeLinear] Test scale's shape = [] and zeroPoint's shape = [] which is unidirectionally broadcastable to input's shape.
+[FAIL] dequantizeLinear uint8 1D constant tensor broadcasting zeroPoint
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'dequantizeLinear' on 'MLGraphBuilder': Unsupported data type uint8 for argument input, must be one of []."
+[FAIL] dequantizeLinear int8 4D constant tensor broadcasting scale and zeroPoint
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'dequantizeLinear' on 'MLGraphBuilder': Unsupported data type int8 for argument input, must be one of []."
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/quantizeLinear.https.any.worker_gpu-expected.txt b/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/quantizeLinear.https.any.worker_gpu-expected.txt
similarity index 62%
rename from third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/quantizeLinear.https.any.worker_gpu-expected.txt
rename to third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/quantizeLinear.https.any.worker_gpu-expected.txt
index 8f1870b3..45996ad 100644
--- a/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/quantizeLinear.https.any.worker_gpu-expected.txt
+++ b/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/quantizeLinear.https.any.worker_gpu-expected.txt
@@ -1,9 +1,9 @@
 This is a testharness.js-based test.
-[FAIL] [quantizeLinear] Test scale's shape = [3, 2, 5] and zeroPoint's shape = [3, 2, 5] which is the same as input's shape.
+[FAIL] quantizeLinear float32 0D scalar tensor with int8 scalar zeroPoint
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'quantizeLinear' on 'MLGraphBuilder': Unsupported data type float32 for argument input, must be one of []."
-[FAIL] [quantizeLinear] Test scale's shape = [5] and zeroPoint's shape = [5] which is unidirectionally broadcastable to input's shape.
+[FAIL] quantizeLinear float32 1D constant tensor broadcasting zeroPoint
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'quantizeLinear' on 'MLGraphBuilder': Unsupported data type float32 for argument input, must be one of []."
-[FAIL] [quantizeLinear] Test scale's shape = [] and zeroPoint's shape = [] which is unidirectionally broadcastable to input's shape.
+[FAIL] quantizeLinear float32 4D constant tensor broadcasting scale and zeroPoint
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'quantizeLinear' on 'MLGraphBuilder': Unsupported data type float32 for argument input, must be one of []."
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/quantizeLinear.https.any.worker_gpu-expected.txt b/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/quantizeLinear.https.any_gpu-expected.txt
similarity index 62%
copy from third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/quantizeLinear.https.any.worker_gpu-expected.txt
copy to third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/quantizeLinear.https.any_gpu-expected.txt
index 8f1870b3..45996ad 100644
--- a/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/quantizeLinear.https.any.worker_gpu-expected.txt
+++ b/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/quantizeLinear.https.any_gpu-expected.txt
@@ -1,9 +1,9 @@
 This is a testharness.js-based test.
-[FAIL] [quantizeLinear] Test scale's shape = [3, 2, 5] and zeroPoint's shape = [3, 2, 5] which is the same as input's shape.
+[FAIL] quantizeLinear float32 0D scalar tensor with int8 scalar zeroPoint
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'quantizeLinear' on 'MLGraphBuilder': Unsupported data type float32 for argument input, must be one of []."
-[FAIL] [quantizeLinear] Test scale's shape = [5] and zeroPoint's shape = [5] which is unidirectionally broadcastable to input's shape.
+[FAIL] quantizeLinear float32 1D constant tensor broadcasting zeroPoint
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'quantizeLinear' on 'MLGraphBuilder': Unsupported data type float32 for argument input, must be one of []."
-[FAIL] [quantizeLinear] Test scale's shape = [] and zeroPoint's shape = [] which is unidirectionally broadcastable to input's shape.
+[FAIL] quantizeLinear float32 4D constant tensor broadcasting scale and zeroPoint
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'quantizeLinear' on 'MLGraphBuilder': Unsupported data type float32 for argument input, must be one of []."
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/dequantizeLinear.https.any_gpu-expected.txt b/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/dequantizeLinear.https.any_gpu-expected.txt
deleted file mode 100644
index b7347e1..0000000
--- a/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/dequantizeLinear.https.any_gpu-expected.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-This is a testharness.js-based test.
-[FAIL] [dequantizeLinear] Test scale's shape = [3, 2, 5] and zeroPoint's shape = [3, 2, 5] which is the same as input's shape.
-  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'dequantizeLinear' on 'MLGraphBuilder': Unsupported data type int8 for argument input, must be one of []."
-[FAIL] [dequantizeLinear] Test scale's shape = [5] and zeroPoint's shape = [5] which is unidirectionally broadcastable to input's shape.
-  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'dequantizeLinear' on 'MLGraphBuilder': Unsupported data type int8 for argument input, must be one of []."
-[FAIL] [dequantizeLinear] Test scale's shape = [] and zeroPoint's shape = [] which is unidirectionally broadcastable to input's shape.
-  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'dequantizeLinear' on 'MLGraphBuilder': Unsupported data type uint8 for argument input, must be one of []."
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/quantizeLinear.https.any_gpu-expected.txt b/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/quantizeLinear.https.any_gpu-expected.txt
deleted file mode 100644
index 8f1870b3..0000000
--- a/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/quantizeLinear.https.any_gpu-expected.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-This is a testharness.js-based test.
-[FAIL] [quantizeLinear] Test scale's shape = [3, 2, 5] and zeroPoint's shape = [3, 2, 5] which is the same as input's shape.
-  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'quantizeLinear' on 'MLGraphBuilder': Unsupported data type float32 for argument input, must be one of []."
-[FAIL] [quantizeLinear] Test scale's shape = [5] and zeroPoint's shape = [5] which is unidirectionally broadcastable to input's shape.
-  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'quantizeLinear' on 'MLGraphBuilder': Unsupported data type float32 for argument input, must be one of []."
-[FAIL] [quantizeLinear] Test scale's shape = [] and zeroPoint's shape = [] which is unidirectionally broadcastable to input's shape.
-  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'quantizeLinear' on 'MLGraphBuilder': Unsupported data type float32 for argument input, must be one of []."
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/win10/external/wpt/css/css-color/parsing/color-valid-color-function-expected.txt b/third_party/blink/web_tests/platform/win10/external/wpt/css/css-color/parsing/color-valid-color-function-expected.txt
new file mode 100644
index 0000000..feecea5
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win10/external/wpt/css/css-color/parsing/color-valid-color-function-expected.txt
@@ -0,0 +1,40 @@
+This is a testharness.js-based test.
+Found 18 FAIL, 0 TIMEOUT, 0 NOTRUN.
+[FAIL] e.style['color'] = "color(srgb calc(50% + (sign(1em - 10px) * 10%)) 0 0 / 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "color(srgb calc(50% + (10% * sign(1em - 10px))) 0 0 / 0.5)" but got "color(srgb 0.4 0 0 / 0.5)"
+[FAIL] e.style['color'] = "color(srgb 0.5 0 0 / calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
+  assert_equals: serialization should be canonical expected "color(srgb 0.5 0 0 / calc(50% + (10% * sign(1em - 10px))))" but got "color(srgb 0.5 0 0 / 0.4)"
+[FAIL] e.style['color'] = "color(srgb-linear calc(50% + (sign(1em - 10px) * 10%)) 0 0 / 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "color(srgb-linear calc(50% + (10% * sign(1em - 10px))) 0 0 / 0.5)" but got "color(srgb-linear 0.4 0 0 / 0.5)"
+[FAIL] e.style['color'] = "color(srgb-linear 0.5 0 0 / calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
+  assert_equals: serialization should be canonical expected "color(srgb-linear 0.5 0 0 / calc(50% + (10% * sign(1em - 10px))))" but got "color(srgb-linear 0.5 0 0 / 0.4)"
+[FAIL] e.style['color'] = "color(a98-rgb calc(50% + (sign(1em - 10px) * 10%)) 0 0 / 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "color(a98-rgb calc(50% + (10% * sign(1em - 10px))) 0 0 / 0.5)" but got "color(a98-rgb 0.4 0 0 / 0.5)"
+[FAIL] e.style['color'] = "color(a98-rgb 0.5 0 0 / calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
+  assert_equals: serialization should be canonical expected "color(a98-rgb 0.5 0 0 / calc(50% + (10% * sign(1em - 10px))))" but got "color(a98-rgb 0.5 0 0 / 0.4)"
+[FAIL] e.style['color'] = "color(rec2020 calc(50% + (sign(1em - 10px) * 10%)) 0 0 / 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "color(rec2020 calc(50% + (10% * sign(1em - 10px))) 0 0 / 0.5)" but got "color(rec2020 0.4 0 0 / 0.5)"
+[FAIL] e.style['color'] = "color(rec2020 0.5 0 0 / calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
+  assert_equals: serialization should be canonical expected "color(rec2020 0.5 0 0 / calc(50% + (10% * sign(1em - 10px))))" but got "color(rec2020 0.5 0 0 / 0.4)"
+[FAIL] e.style['color'] = "color(prophoto-rgb calc(50% + (sign(1em - 10px) * 10%)) 0 0 / 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "color(prophoto-rgb calc(50% + (10% * sign(1em - 10px))) 0 0 / 0.5)" but got "color(prophoto-rgb 0.4 0 0 / 0.5)"
+[FAIL] e.style['color'] = "color(prophoto-rgb 0.5 0 0 / calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
+  assert_equals: serialization should be canonical expected "color(prophoto-rgb 0.5 0 0 / calc(50% + (10% * sign(1em - 10px))))" but got "color(prophoto-rgb 0.5 0 0 / 0.4)"
+[FAIL] e.style['color'] = "color(display-p3 calc(50% + (sign(1em - 10px) * 10%)) 0 0 / 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "color(display-p3 calc(50% + (10% * sign(1em - 10px))) 0 0 / 0.5)" but got "color(display-p3 0.4 0 0 / 0.5)"
+[FAIL] e.style['color'] = "color(display-p3 0.5 0 0 / calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
+  assert_equals: serialization should be canonical expected "color(display-p3 0.5 0 0 / calc(50% + (10% * sign(1em - 10px))))" but got "color(display-p3 0.5 0 0 / 0.4)"
+[FAIL] e.style['color'] = "color(xyz calc(0.5 + (sign(1em - 10px) * 0.1)) 0 0 / 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "color(xyz-d65 calc(0.5 + (0.1 * sign(1em - 10px))) 0 0 / 0.5)" but got "color(xyz-d65 0.4 0 0 / 0.5)"
+[FAIL] e.style['color'] = "color(xyz 0.5 0 0 / calc(0.5 + (sign(1em - 10px) * 0.1)))" should set the property value
+  assert_equals: serialization should be canonical expected "color(xyz-d65 0.5 0 0 / calc(0.5 + (0.1 * sign(1em - 10px))))" but got "color(xyz-d65 0.5 0 0 / 0.4)"
+[FAIL] e.style['color'] = "color(xyz-d50 calc(0.5 + (sign(1em - 10px) * 0.1)) 0 0 / 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "color(xyz-d50 calc(0.5 + (0.1 * sign(1em - 10px))) 0 0 / 0.5)" but got "color(xyz-d50 0.4 0 0 / 0.5)"
+[FAIL] e.style['color'] = "color(xyz-d50 0.5 0 0 / calc(0.5 + (sign(1em - 10px) * 0.1)))" should set the property value
+  assert_equals: serialization should be canonical expected "color(xyz-d50 0.5 0 0 / calc(0.5 + (0.1 * sign(1em - 10px))))" but got "color(xyz-d50 0.5 0 0 / 0.4)"
+[FAIL] e.style['color'] = "color(xyz-d65 calc(0.5 + (sign(1em - 10px) * 0.1)) 0 0 / 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "color(xyz-d65 calc(0.5 + (0.1 * sign(1em - 10px))) 0 0 / 0.5)" but got "color(xyz-d65 0.4 0 0 / 0.5)"
+[FAIL] e.style['color'] = "color(xyz-d65 0.5 0 0 / calc(0.5 + (sign(1em - 10px) * 0.1)))" should set the property value
+  assert_equals: serialization should be canonical expected "color(xyz-d65 0.5 0 0 / calc(0.5 + (0.1 * sign(1em - 10px))))" but got "color(xyz-d65 0.5 0 0 / 0.4)"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/win10/external/wpt/css/css-color/parsing/color-valid-lab-expected.txt b/third_party/blink/web_tests/platform/win10/external/wpt/css/css-color/parsing/color-valid-lab-expected.txt
new file mode 100644
index 0000000..63777f4
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win10/external/wpt/css/css-color/parsing/color-valid-lab-expected.txt
@@ -0,0 +1,20 @@
+This is a testharness.js-based test.
+Found 8 FAIL, 0 TIMEOUT, 0 NOTRUN.
+[FAIL] e.style['color'] = "lab(calc(50 + (sign(1em - 10px) * 10)) 30 50 / 50%)" should set the property value
+  assert_equals: serialization should be canonical expected "lab(calc(50 + (10 * sign(1em - 10px))) 30 50 / 50%)" but got "lab(40 30 50 / 0.5)"
+[FAIL] e.style['color'] = "oklab(calc(0.5 + (sign(1em - 10px) * 0.1)) 0.3 0.5 / 50%)" should set the property value
+  assert_equals: serialization should be canonical expected "oklab(calc(0.5 + (0.1 * sign(1em - 10px))) 0.3 0.5 / 50%)" but got "oklab(0.4 0.3 0.5 / 0.5)"
+[FAIL] e.style['color'] = "lab(60 30 50 / calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
+  assert_equals: serialization should be canonical expected "lab(60 30 50 / calc(50% + (10% * sign(1em - 10px))))" but got "lab(60 30 50 / 0.4)"
+[FAIL] e.style['color'] = "oklab(0.6 0.3 0.5 / calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
+  assert_equals: serialization should be canonical expected "oklab(0.6 0.3 0.5 / calc(50% + (10% * sign(1em - 10px))))" but got "oklab(0.6 0.3 0.5 / 0.4)"
+[FAIL] e.style['color'] = "lch(calc(50 + (sign(1em - 10px) * 10)) 30 50deg / 50%)" should set the property value
+  assert_equals: serialization should be canonical expected "lch(calc(50 + (10 * sign(1em - 10px))) 30 50deg / 50%)" but got "lch(40 30 50 / 0.5)"
+[FAIL] e.style['color'] = "oklch(calc(0.5 + (sign(1em - 10px) * 0.1)) 0.3 50deg / 50%)" should set the property value
+  assert_equals: serialization should be canonical expected "oklch(calc(0.5 + (0.1 * sign(1em - 10px))) 0.3 50deg / 50%)" but got "oklch(0.4 0.3 50 / 0.5)"
+[FAIL] e.style['color'] = "lch(60 30 50deg / calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
+  assert_equals: serialization should be canonical expected "lch(60 30 50deg / calc(50% + (10% * sign(1em - 10px))))" but got "lch(60 30 50 / 0.4)"
+[FAIL] e.style['color'] = "oklch(0.6 0.3 50deg / calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
+  assert_equals: serialization should be canonical expected "oklch(0.6 0.3 50deg / calc(50% + (10% * sign(1em - 10px))))" but got "oklch(0.6 0.3 50 / 0.4)"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/win10/external/wpt/css/css-color/parsing/color-valid-rgb-expected.txt b/third_party/blink/web_tests/platform/win10/external/wpt/css/css-color/parsing/color-valid-rgb-expected.txt
new file mode 100644
index 0000000..c4fd42d
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win10/external/wpt/css/css-color/parsing/color-valid-rgb-expected.txt
@@ -0,0 +1,40 @@
+This is a testharness.js-based test.
+Found 18 FAIL, 0 TIMEOUT, 0 NOTRUN.
+[FAIL] e.style['color'] = "rgb(calc(50% + (sign(1em - 10px) * 10%)), 0%, 0%, 50%)" should set the property value
+  assert_equals: serialization should be canonical expected "rgb(calc(50% + (10% * sign(1em - 10px))) 0% 0% / 50%)" but got "rgba(102, 0, 0, 0.5)"
+[FAIL] e.style['color'] = "rgba(calc(50% + (sign(1em - 10px) * 10%)), 0%, 0%, 50%)" should set the property value
+  assert_equals: serialization should be canonical expected "rgb(calc(50% + (10% * sign(1em - 10px))) 0% 0% / 50%)" but got "rgba(102, 0, 0, 0.5)"
+[FAIL] e.style['color'] = "rgb(calc(50 + (sign(1em - 10px) * 10)), 0, 0, 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "rgb(calc(50 + (10 * sign(1em - 10px))) 0 0 / 0.5)" but got "rgba(40, 0, 0, 0.5)"
+[FAIL] e.style['color'] = "rgba(calc(50 + (sign(1em - 10px) * 10)), 0, 0, 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "rgb(calc(50 + (10 * sign(1em - 10px))) 0 0 / 0.5)" but got "rgba(40, 0, 0, 0.5)"
+[FAIL] e.style['color'] = "rgb(0%, 0%, 0%, calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
+  assert_equals: serialization should be canonical expected "rgb(0% 0% 0% / calc(50% + (10% * sign(1em - 10px))))" but got "rgba(0, 0, 0, 0.4)"
+[FAIL] e.style['color'] = "rgba(0%, 0%, 0%, calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
+  assert_equals: serialization should be canonical expected "rgb(0% 0% 0% / calc(50% + (10% * sign(1em - 10px))))" but got "rgba(0, 0, 0, 0.4)"
+[FAIL] e.style['color'] = "rgb(0, 0, 0, calc(0.75 + (sign(1em - 10px) * 0.1)))" should set the property value
+  assert_equals: serialization should be canonical expected "rgb(0 0 0 / calc(0.75 + (0.1 * sign(1em - 10px))))" but got "rgba(0, 0, 0, 0.65)"
+[FAIL] e.style['color'] = "rgba(0, 0, 0, calc(0.75 + (sign(1em - 10px) * 0.1)))" should set the property value
+  assert_equals: serialization should be canonical expected "rgb(0 0 0 / calc(0.75 + (0.1 * sign(1em - 10px))))" but got "rgba(0, 0, 0, 0.65)"
+[FAIL] e.style['color'] = "rgb(calc(50% + (sign(1em - 10px) * 10%)) 0% 0% / 50%)" should set the property value
+  assert_equals: serialization should be canonical expected "rgb(calc(50% + (10% * sign(1em - 10px))) 0% 0% / 50%)" but got "rgba(102, 0, 0, 0.5)"
+[FAIL] e.style['color'] = "rgba(calc(50% + (sign(1em - 10px) * 10%)) 0% 0% / 50%)" should set the property value
+  assert_equals: serialization should be canonical expected "rgb(calc(50% + (10% * sign(1em - 10px))) 0% 0% / 50%)" but got "rgba(102, 0, 0, 0.5)"
+[FAIL] e.style['color'] = "rgb(calc(50 + (sign(1em - 10px) * 10)) 0 0 / 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "rgb(calc(50 + (10 * sign(1em - 10px))) 0 0 / 0.5)" but got "rgba(40, 0, 0, 0.5)"
+[FAIL] e.style['color'] = "rgba(calc(50 + (sign(1em - 10px) * 10)) 0 0 / 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "rgb(calc(50 + (10 * sign(1em - 10px))) 0 0 / 0.5)" but got "rgba(40, 0, 0, 0.5)"
+[FAIL] e.style['color'] = "rgb(0% 0% 0% / calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
+  assert_equals: serialization should be canonical expected "rgb(0% 0% 0% / calc(50% + (10% * sign(1em - 10px))))" but got "rgba(0, 0, 0, 0.4)"
+[FAIL] e.style['color'] = "rgba(0% 0% 0% / calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
+  assert_equals: serialization should be canonical expected "rgb(0% 0% 0% / calc(50% + (10% * sign(1em - 10px))))" but got "rgba(0, 0, 0, 0.4)"
+[FAIL] e.style['color'] = "rgb(0 0 0 / calc(0.75 + (sign(1em - 10px) * 0.1)))" should set the property value
+  assert_equals: serialization should be canonical expected "rgb(0 0 0 / calc(0.75 + (0.1 * sign(1em - 10px))))" but got "rgba(0, 0, 0, 0.65)"
+[FAIL] e.style['color'] = "rgba(0 0 0 / calc(0.75 + (sign(1em - 10px) * 0.1)))" should set the property value
+  assert_equals: serialization should be canonical expected "rgb(0 0 0 / calc(0.75 + (0.1 * sign(1em - 10px))))" but got "rgba(0, 0, 0, 0.65)"
+[FAIL] e.style['color'] = "rgba(calc(50% + (sign(1em - 10px) * 10%)) 0 0% / 0.5)" should set the property value
+  assert_equals: serialization should be canonical expected "rgb(calc(50% + (10% * sign(1em - 10px))) 0 0% / 0.5)" but got "rgba(102, 0, 0, 0.5)"
+[FAIL] e.style['color'] = "rgba(0% 0 0% / calc(0.75 + (sign(1em - 10px) * 0.1)))" should set the property value
+  assert_equals: serialization should be canonical expected "rgb(0% 0 0% / calc(0.75 + (0.1 * sign(1em - 10px))))" but got "rgba(0, 0, 0, 0.65)"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/origin-agent-cluster-default-warning/README.md b/third_party/blink/web_tests/virtual/origin-agent-cluster-default-warning/README.md
deleted file mode 100644
index 55eba66..0000000
--- a/third_party/blink/web_tests/virtual/origin-agent-cluster-default-warning/README.md
+++ /dev/null
@@ -1,12 +0,0 @@
-Tests for the OriginAgentClusterDefaultWarning feature.
-
-The OriginAgentClusterDefaultWarning feature issues deprecation warnings
-when document.domain is set in order to relax same-site restrictions. This
-supports the deprecation of this mis-feature.
-
-Note: These tests require isolation behaviour as in the actual browser.
-They are therefore incompatible with auto-wpt-origin-isolation, which the test
-runner enabled by default. Hence this virtual test suite enables the
-OriginAgentClusterDefaultWarning feature, and disables
-auto-wpt-origin-isolation. These tests are expected to fail without these
-flags, and are disabled (via NeverFixTests) in the default configuration.
diff --git a/third_party/blink/web_tests/virtual/prefetch-new-wait-loop/README.md b/third_party/blink/web_tests/virtual/prefetch-new-wait-loop/README.md
new file mode 100644
index 0000000..f0adc44
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/prefetch-new-wait-loop/README.md
@@ -0,0 +1 @@
+This directory is for testing kPrefetchNewWaitLoop feature of speculation-rule based prefetch. crbug.com/365467850
diff --git a/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/dequantizeLinear.https.any.worker_gpu-expected.txt b/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/dequantizeLinear.https.any.worker_cpu-expected.txt
similarity index 61%
copy from third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/dequantizeLinear.https.any.worker_gpu-expected.txt
copy to third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/dequantizeLinear.https.any.worker_cpu-expected.txt
index b7347e1..c10e6a9 100644
--- a/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/dequantizeLinear.https.any.worker_gpu-expected.txt
+++ b/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/dequantizeLinear.https.any.worker_cpu-expected.txt
@@ -1,9 +1,9 @@
 This is a testharness.js-based test.
-[FAIL] [dequantizeLinear] Test scale's shape = [3, 2, 5] and zeroPoint's shape = [3, 2, 5] which is the same as input's shape.
+[FAIL] dequantizeLinear int8 0D tensor with float32 scalar scale
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'dequantizeLinear' on 'MLGraphBuilder': Unsupported data type int8 for argument input, must be one of []."
-[FAIL] [dequantizeLinear] Test scale's shape = [5] and zeroPoint's shape = [5] which is unidirectionally broadcastable to input's shape.
-  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'dequantizeLinear' on 'MLGraphBuilder': Unsupported data type int8 for argument input, must be one of []."
-[FAIL] [dequantizeLinear] Test scale's shape = [] and zeroPoint's shape = [] which is unidirectionally broadcastable to input's shape.
+[FAIL] dequantizeLinear uint8 1D constant tensor broadcasting zeroPoint
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'dequantizeLinear' on 'MLGraphBuilder': Unsupported data type uint8 for argument input, must be one of []."
+[FAIL] dequantizeLinear int8 4D constant tensor broadcasting scale and zeroPoint
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'dequantizeLinear' on 'MLGraphBuilder': Unsupported data type int8 for argument input, must be one of []."
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/dequantizeLinear.https.any.worker_gpu-expected.txt b/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/dequantizeLinear.https.any_cpu-expected.txt
similarity index 61%
copy from third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/dequantizeLinear.https.any.worker_gpu-expected.txt
copy to third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/dequantizeLinear.https.any_cpu-expected.txt
index b7347e1..c10e6a9 100644
--- a/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/dequantizeLinear.https.any.worker_gpu-expected.txt
+++ b/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/dequantizeLinear.https.any_cpu-expected.txt
@@ -1,9 +1,9 @@
 This is a testharness.js-based test.
-[FAIL] [dequantizeLinear] Test scale's shape = [3, 2, 5] and zeroPoint's shape = [3, 2, 5] which is the same as input's shape.
+[FAIL] dequantizeLinear int8 0D tensor with float32 scalar scale
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'dequantizeLinear' on 'MLGraphBuilder': Unsupported data type int8 for argument input, must be one of []."
-[FAIL] [dequantizeLinear] Test scale's shape = [5] and zeroPoint's shape = [5] which is unidirectionally broadcastable to input's shape.
-  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'dequantizeLinear' on 'MLGraphBuilder': Unsupported data type int8 for argument input, must be one of []."
-[FAIL] [dequantizeLinear] Test scale's shape = [] and zeroPoint's shape = [] which is unidirectionally broadcastable to input's shape.
+[FAIL] dequantizeLinear uint8 1D constant tensor broadcasting zeroPoint
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'dequantizeLinear' on 'MLGraphBuilder': Unsupported data type uint8 for argument input, must be one of []."
+[FAIL] dequantizeLinear int8 4D constant tensor broadcasting scale and zeroPoint
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'dequantizeLinear' on 'MLGraphBuilder': Unsupported data type int8 for argument input, must be one of []."
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/quantizeLinear.https.any.worker_gpu-expected.txt b/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/quantizeLinear.https.any.worker_cpu-expected.txt
similarity index 62%
copy from third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/quantizeLinear.https.any.worker_gpu-expected.txt
copy to third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/quantizeLinear.https.any.worker_cpu-expected.txt
index 8f1870b3..45996ad 100644
--- a/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/quantizeLinear.https.any.worker_gpu-expected.txt
+++ b/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/quantizeLinear.https.any.worker_cpu-expected.txt
@@ -1,9 +1,9 @@
 This is a testharness.js-based test.
-[FAIL] [quantizeLinear] Test scale's shape = [3, 2, 5] and zeroPoint's shape = [3, 2, 5] which is the same as input's shape.
+[FAIL] quantizeLinear float32 0D scalar tensor with int8 scalar zeroPoint
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'quantizeLinear' on 'MLGraphBuilder': Unsupported data type float32 for argument input, must be one of []."
-[FAIL] [quantizeLinear] Test scale's shape = [5] and zeroPoint's shape = [5] which is unidirectionally broadcastable to input's shape.
+[FAIL] quantizeLinear float32 1D constant tensor broadcasting zeroPoint
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'quantizeLinear' on 'MLGraphBuilder': Unsupported data type float32 for argument input, must be one of []."
-[FAIL] [quantizeLinear] Test scale's shape = [] and zeroPoint's shape = [] which is unidirectionally broadcastable to input's shape.
+[FAIL] quantizeLinear float32 4D constant tensor broadcasting scale and zeroPoint
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'quantizeLinear' on 'MLGraphBuilder': Unsupported data type float32 for argument input, must be one of []."
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/quantizeLinear.https.any.worker_gpu-expected.txt b/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/quantizeLinear.https.any_cpu-expected.txt
similarity index 62%
copy from third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/quantizeLinear.https.any.worker_gpu-expected.txt
copy to third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/quantizeLinear.https.any_cpu-expected.txt
index 8f1870b3..45996ad 100644
--- a/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/quantizeLinear.https.any.worker_gpu-expected.txt
+++ b/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/quantizeLinear.https.any_cpu-expected.txt
@@ -1,9 +1,9 @@
 This is a testharness.js-based test.
-[FAIL] [quantizeLinear] Test scale's shape = [3, 2, 5] and zeroPoint's shape = [3, 2, 5] which is the same as input's shape.
+[FAIL] quantizeLinear float32 0D scalar tensor with int8 scalar zeroPoint
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'quantizeLinear' on 'MLGraphBuilder': Unsupported data type float32 for argument input, must be one of []."
-[FAIL] [quantizeLinear] Test scale's shape = [5] and zeroPoint's shape = [5] which is unidirectionally broadcastable to input's shape.
+[FAIL] quantizeLinear float32 1D constant tensor broadcasting zeroPoint
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'quantizeLinear' on 'MLGraphBuilder': Unsupported data type float32 for argument input, must be one of []."
-[FAIL] [quantizeLinear] Test scale's shape = [] and zeroPoint's shape = [] which is unidirectionally broadcastable to input's shape.
+[FAIL] quantizeLinear float32 4D constant tensor broadcasting scale and zeroPoint
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'quantizeLinear' on 'MLGraphBuilder': Unsupported data type float32 for argument input, must be one of []."
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/validation_tests/scatterND.https.any.worker_cpu-expected.txt b/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/validation_tests/scatterND.https.any.worker_cpu-expected.txt
new file mode 100644
index 0000000..4b12bad
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/validation_tests/scatterND.https.any.worker_cpu-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+[FAIL] [scatterND] Test scatterND with valid tensors
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'scatterND' on 'MLGraphBuilder': Unsupported data type float32 for argument input, must be one of []."
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/validation_tests/scatterND.https.any_cpu-expected.txt b/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/validation_tests/scatterND.https.any_cpu-expected.txt
new file mode 100644
index 0000000..4b12bad
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/validation_tests/scatterND.https.any_cpu-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+[FAIL] [scatterND] Test scatterND with valid tensors
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'scatterND' on 'MLGraphBuilder': Unsupported data type float32 for argument input, must be one of []."
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/dequantizeLinear.https.any.worker_gpu-expected.txt b/third_party/blink/web_tests/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/dequantizeLinear.https.any.worker_npu-expected.txt
similarity index 61%
copy from third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/dequantizeLinear.https.any.worker_gpu-expected.txt
copy to third_party/blink/web_tests/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/dequantizeLinear.https.any.worker_npu-expected.txt
index b7347e1..c10e6a9 100644
--- a/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/dequantizeLinear.https.any.worker_gpu-expected.txt
+++ b/third_party/blink/web_tests/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/dequantizeLinear.https.any.worker_npu-expected.txt
@@ -1,9 +1,9 @@
 This is a testharness.js-based test.
-[FAIL] [dequantizeLinear] Test scale's shape = [3, 2, 5] and zeroPoint's shape = [3, 2, 5] which is the same as input's shape.
+[FAIL] dequantizeLinear int8 0D tensor with float32 scalar scale
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'dequantizeLinear' on 'MLGraphBuilder': Unsupported data type int8 for argument input, must be one of []."
-[FAIL] [dequantizeLinear] Test scale's shape = [5] and zeroPoint's shape = [5] which is unidirectionally broadcastable to input's shape.
-  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'dequantizeLinear' on 'MLGraphBuilder': Unsupported data type int8 for argument input, must be one of []."
-[FAIL] [dequantizeLinear] Test scale's shape = [] and zeroPoint's shape = [] which is unidirectionally broadcastable to input's shape.
+[FAIL] dequantizeLinear uint8 1D constant tensor broadcasting zeroPoint
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'dequantizeLinear' on 'MLGraphBuilder': Unsupported data type uint8 for argument input, must be one of []."
+[FAIL] dequantizeLinear int8 4D constant tensor broadcasting scale and zeroPoint
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'dequantizeLinear' on 'MLGraphBuilder': Unsupported data type int8 for argument input, must be one of []."
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/dequantizeLinear.https.any.worker_gpu-expected.txt b/third_party/blink/web_tests/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/dequantizeLinear.https.any_npu-expected.txt
similarity index 61%
copy from third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/dequantizeLinear.https.any.worker_gpu-expected.txt
copy to third_party/blink/web_tests/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/dequantizeLinear.https.any_npu-expected.txt
index b7347e1..c10e6a9 100644
--- a/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/dequantizeLinear.https.any.worker_gpu-expected.txt
+++ b/third_party/blink/web_tests/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/dequantizeLinear.https.any_npu-expected.txt
@@ -1,9 +1,9 @@
 This is a testharness.js-based test.
-[FAIL] [dequantizeLinear] Test scale's shape = [3, 2, 5] and zeroPoint's shape = [3, 2, 5] which is the same as input's shape.
+[FAIL] dequantizeLinear int8 0D tensor with float32 scalar scale
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'dequantizeLinear' on 'MLGraphBuilder': Unsupported data type int8 for argument input, must be one of []."
-[FAIL] [dequantizeLinear] Test scale's shape = [5] and zeroPoint's shape = [5] which is unidirectionally broadcastable to input's shape.
-  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'dequantizeLinear' on 'MLGraphBuilder': Unsupported data type int8 for argument input, must be one of []."
-[FAIL] [dequantizeLinear] Test scale's shape = [] and zeroPoint's shape = [] which is unidirectionally broadcastable to input's shape.
+[FAIL] dequantizeLinear uint8 1D constant tensor broadcasting zeroPoint
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'dequantizeLinear' on 'MLGraphBuilder': Unsupported data type uint8 for argument input, must be one of []."
+[FAIL] dequantizeLinear int8 4D constant tensor broadcasting scale and zeroPoint
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'dequantizeLinear' on 'MLGraphBuilder': Unsupported data type int8 for argument input, must be one of []."
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/quantizeLinear.https.any.worker_gpu-expected.txt b/third_party/blink/web_tests/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/quantizeLinear.https.any.worker_npu-expected.txt
similarity index 62%
copy from third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/quantizeLinear.https.any.worker_gpu-expected.txt
copy to third_party/blink/web_tests/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/quantizeLinear.https.any.worker_npu-expected.txt
index 8f1870b3..45996ad 100644
--- a/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/quantizeLinear.https.any.worker_gpu-expected.txt
+++ b/third_party/blink/web_tests/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/quantizeLinear.https.any.worker_npu-expected.txt
@@ -1,9 +1,9 @@
 This is a testharness.js-based test.
-[FAIL] [quantizeLinear] Test scale's shape = [3, 2, 5] and zeroPoint's shape = [3, 2, 5] which is the same as input's shape.
+[FAIL] quantizeLinear float32 0D scalar tensor with int8 scalar zeroPoint
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'quantizeLinear' on 'MLGraphBuilder': Unsupported data type float32 for argument input, must be one of []."
-[FAIL] [quantizeLinear] Test scale's shape = [5] and zeroPoint's shape = [5] which is unidirectionally broadcastable to input's shape.
+[FAIL] quantizeLinear float32 1D constant tensor broadcasting zeroPoint
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'quantizeLinear' on 'MLGraphBuilder': Unsupported data type float32 for argument input, must be one of []."
-[FAIL] [quantizeLinear] Test scale's shape = [] and zeroPoint's shape = [] which is unidirectionally broadcastable to input's shape.
+[FAIL] quantizeLinear float32 4D constant tensor broadcasting scale and zeroPoint
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'quantizeLinear' on 'MLGraphBuilder': Unsupported data type float32 for argument input, must be one of []."
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/quantizeLinear.https.any.worker_gpu-expected.txt b/third_party/blink/web_tests/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/quantizeLinear.https.any_npu-expected.txt
similarity index 62%
copy from third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/quantizeLinear.https.any.worker_gpu-expected.txt
copy to third_party/blink/web_tests/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/quantizeLinear.https.any_npu-expected.txt
index 8f1870b3..45996ad 100644
--- a/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/quantizeLinear.https.any.worker_gpu-expected.txt
+++ b/third_party/blink/web_tests/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/quantizeLinear.https.any_npu-expected.txt
@@ -1,9 +1,9 @@
 This is a testharness.js-based test.
-[FAIL] [quantizeLinear] Test scale's shape = [3, 2, 5] and zeroPoint's shape = [3, 2, 5] which is the same as input's shape.
+[FAIL] quantizeLinear float32 0D scalar tensor with int8 scalar zeroPoint
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'quantizeLinear' on 'MLGraphBuilder': Unsupported data type float32 for argument input, must be one of []."
-[FAIL] [quantizeLinear] Test scale's shape = [5] and zeroPoint's shape = [5] which is unidirectionally broadcastable to input's shape.
+[FAIL] quantizeLinear float32 1D constant tensor broadcasting zeroPoint
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'quantizeLinear' on 'MLGraphBuilder': Unsupported data type float32 for argument input, must be one of []."
-[FAIL] [quantizeLinear] Test scale's shape = [] and zeroPoint's shape = [] which is unidirectionally broadcastable to input's shape.
+[FAIL] quantizeLinear float32 4D constant tensor broadcasting scale and zeroPoint
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'quantizeLinear' on 'MLGraphBuilder': Unsupported data type float32 for argument input, must be one of []."
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/webnn-service-on-npu/external/wpt/webnn/validation_tests/scatterND.https.any.worker_npu-expected.txt b/third_party/blink/web_tests/virtual/webnn-service-on-npu/external/wpt/webnn/validation_tests/scatterND.https.any.worker_npu-expected.txt
new file mode 100644
index 0000000..4b12bad
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/webnn-service-on-npu/external/wpt/webnn/validation_tests/scatterND.https.any.worker_npu-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+[FAIL] [scatterND] Test scatterND with valid tensors
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'scatterND' on 'MLGraphBuilder': Unsupported data type float32 for argument input, must be one of []."
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/webnn-service-on-npu/external/wpt/webnn/validation_tests/scatterND.https.any_npu-expected.txt b/third_party/blink/web_tests/virtual/webnn-service-on-npu/external/wpt/webnn/validation_tests/scatterND.https.any_npu-expected.txt
new file mode 100644
index 0000000..4b12bad
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/webnn-service-on-npu/external/wpt/webnn/validation_tests/scatterND.https.any_npu-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+[FAIL] [scatterND] Test scatterND with valid tensors
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'scatterND' on 'MLGraphBuilder': Unsupported data type float32 for argument input, must be one of []."
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/scatterND.https.any.worker_gpu-expected.txt b/third_party/blink/web_tests/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/scatterND.https.any.worker_gpu-expected.txt
new file mode 100644
index 0000000..4b12bad
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/scatterND.https.any.worker_gpu-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+[FAIL] [scatterND] Test scatterND with valid tensors
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'scatterND' on 'MLGraphBuilder': Unsupported data type float32 for argument input, must be one of []."
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/scatterND.https.any_gpu-expected.txt b/third_party/blink/web_tests/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/scatterND.https.any_gpu-expected.txt
new file mode 100644
index 0000000..4b12bad
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/scatterND.https.any_gpu-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+[FAIL] [scatterND] Test scatterND with valid tensors
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'scatterND' on 'MLGraphBuilder': Unsupported data type float32 for argument input, must be one of []."
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/wpt_internal/ai/prompt-api.any.js b/third_party/blink/web_tests/wpt_internal/ai/prompt-api.any.js
index 4bc7db92..9ae50e3 100644
--- a/third_party/blink/web_tests/wpt_internal/ai/prompt-api.any.js
+++ b/third_party/blink/web_tests/wpt_internal/ai/prompt-api.any.js
@@ -6,3 +6,77 @@
   const result = await testPromptAPI();
   assert_true(result.success, result.error);
 });
+
+// Test the creation options.
+promise_test(async t => {
+  // Make sure the prompt api is enabled.
+  assert_true(!!ai);
+  // Make sure the session could be created.
+  const capabilities = await ai.assistant.capabilities();
+  const status = capabilities.available;
+  assert_true(status === 'readily');
+
+  let session;
+  let result;
+
+  // Create a new session with no option.
+  session = await ai.assistant.create();
+  assert_true(!!session);
+
+  // Create a new session with topK and temperature.
+  session = await ai.assistant.create({topK: 3, temperature: 0.6});
+  assert_true(!!session);
+
+  // Create a new session with only topK or temperature, it should fail.
+  result = ai.assistant.create({topK: 3});
+  await promise_rejects_dom(
+      t, 'NotSupportedError', result,
+      'Initializing a new session must either specify both topK and temperature, or neither of them.');
+
+  result = ai.assistant.create({temperature: 0.5});
+  await promise_rejects_dom(
+      t, 'NotSupportedError', result,
+      'Initializing a new session must either specify both topK and temperature, or neither of them.');
+
+  // Create a new session with system prompt.
+  session = await ai.assistant.create({systemPrompt: 'you are a robot'});
+  assert_true(!!session);
+
+  // Create a new session with initial prompts.
+  session = await ai.assistant.create({
+    initialPrompts: [
+      {role: 'system', content: 'you are a robot'},
+      {role: 'user', content: 'hello'}, {role: 'assistant', content: 'hello'}
+    ]
+  });
+  assert_true(!!session);
+
+  // Create a new session with initial prompts without system role.
+  session = await ai.assistant.create({
+    initialPrompts: [
+      {role: 'user', content: 'hello'}, {role: 'assistant', content: 'hello'}
+    ]
+  });
+  assert_true(!!session);
+
+  // Create a new session with initial prompts with system role not placing as
+  // the first element.
+  result = ai.assistant.create({
+    initialPrompts: [
+      {role: 'user', content: 'hello'}, {role: 'assistant', content: 'hello'},
+      {role: 'system', content: 'you are a robot'}
+    ]
+  });
+  await promise_rejects_js(t, TypeError, result);
+
+  // Create a new session with both system prompt and initial prompts, it should
+  // fail.
+  result = ai.assistant.create({
+    systemPrompt: 'you are a robot',
+    initialPrompts: [
+      {role: 'system', content: 'you are a robot'},
+      {role: 'user', content: 'hello'}, {role: 'assistant', content: 'hello'}
+    ]
+  });
+  await promise_rejects_js(t, TypeError, result);
+});
diff --git a/third_party/blink/web_tests/wpt_internal/origin-agent-cluster-default-warning/document-domain-access-navigate.https.sub.html b/third_party/blink/web_tests/wpt_internal/origin-agent-cluster-default-warning/document-domain-access-navigate.https.sub.html
deleted file mode 100644
index a9d7842..0000000
--- a/third_party/blink/web_tests/wpt_internal/origin-agent-cluster-default-warning/document-domain-access-navigate.https.sub.html
+++ /dev/null
@@ -1,69 +0,0 @@
-<!DOCTYPE html>
-<title>Warnings when setting document.domain without Origin-Agent-Cluster header</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<iframe src="about:blank"></iframe>
-<script>
-
-// These tests ensure that deprecation warnings are issued when document.domain
-// is set, and when a cross-origin access based on that document.domain setting
-// is made. This requires the OriginAgentClusterDefaultWarning flag.
-//
-// The ReportingObserver infrastructure seems to coalescs deprecation warnings,
-// so that multiple waring events only result in a single warning. To accomodate
-// this, we'll move each test into a single file, despite this making the test
-// suite somewhat harder to follow.
-
-// Wait for onload event, since that guarantees the iframe has loaded.
-const onload = new Promise((resolve, reject) => {
-  window.onload = _ => { resolve(); };
-});
-
-// Wait for onload event for a given frame.
-function onframeload(frame) {
-  return new Promise((resolve, reject) => {
-    frame.addEventListener("load", _ => { resolve(); }, { once: true });
-  });
-}
-
-// Wait for a message from (any of) our frame(s).
-function onmessage() {
-  return new Promise((resolve, reject) => {
-    window.addEventListener("message", msg => { resolve(msg); },
-                            { once: true });
-  });
-}
-
-// Wait for a ReportingObserver report.
-const onreport = new Promise((resolve, reject) => {
-    new ReportingObserver((reports, observer) => {
-      resolve(reports[reports.length - 1]);
-      observer.takeRecords();
-    }, {buffered: true}).observe();
-  });
-
-// Same as the previous test, but first navigate the target frame.
-promise_test(async t => {
-  await onload;
-
-  // Navigate the frame from about:blink to its final location to ensure that
-  // that code path is covered, too.
-  frames[0].location = "https://{{domains[www1]}}:{{location[port]}}/wpt_internal/origin-agent-cluster-default-warning/resources/frame.html"
-  await onframeload(document.getElementsByTagName("iframe")[0]);
-
-  // Now proceed as above: Tell the frame to relax its same-origin restriction
-  // and then reach into the frame.
-
-  frames[0].postMessage("relax", "*");
-  var msg = await onmessage();
-  assert_equals(msg.data.type, "relaxed");
-  assert_equals(msg.data.body, "{{host}}");
-
-  document.domain = document.domain;
-  frames[0].document.bodyi
-  var report = await onreport;
-  assert_equals(report.type, "deprecation");
-  assert_equals(report.body.id, "CrossOriginAccessBasedOnDocumentDomain");
-}, "Deprecation warning for document-domain mediated cross-origin access, " +
-   "after first navigation the target frame.");
-</script>
diff --git a/third_party/blink/web_tests/wpt_internal/origin-agent-cluster-default-warning/document-domain-access.https.sub.html b/third_party/blink/web_tests/wpt_internal/origin-agent-cluster-default-warning/document-domain-access.https.sub.html
deleted file mode 100644
index 2a50955..0000000
--- a/third_party/blink/web_tests/wpt_internal/origin-agent-cluster-default-warning/document-domain-access.https.sub.html
+++ /dev/null
@@ -1,55 +0,0 @@
-<!DOCTYPE html>
-<title>Warnings when setting document.domain without Origin-Agent-Cluster header</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<iframe src="https://{{domains[www]}}:{{location[port]}}/wpt_internal/origin-agent-cluster-default-warning/resources/frame.html"></iframe>
-<script>
-
-// These tests ensure that deprecation warnings are issued when document.domain
-// is set, and when a cross-origin access based on that document.domain setting
-// is made. This requires the OriginAgentClusterDefaultWarning flag.
-//
-// The ReportingObserver infrastructure seems to coalescs deprecation warnings,
-// so that multiple waring events only result in a single warning. To accomodate
-// this, we'll move each test into a single file, despite this making the test
-// suite somewhat harder to follow.
-
-// Wait for onload event, since that guarantees the iframe has loaded.
-const onload = new Promise((resolve, reject) => {
-  window.onload = _ => { resolve(); };
-});
-
-// Wait for a message from (any of) our frame(s).
-function onmessage() {
-  return new Promise((resolve, reject) => {
-    window.addEventListener("message", msg => { resolve(msg); },
-                            { once: true });
-  });
-}
-
-// Wait for a ReportingObserver report.
-const onreport = new Promise((resolve, reject) => {
-    new ReportingObserver((reports, observer) => {
-      resolve(reports[reports.length - 1]);
-      observer.takeRecords();
-    }, {buffered: true}).observe();
-  });
-
-// Test that reaching into a cross-origin iframe (after document.domain setting)
-// will succeed, but cause a deprecation warning (id
-// kCrossOriginAccessBasedOnDocumentDomain).
-promise_test(async t => {
-  await onload;
-
-  frames[0].postMessage("relax", "*");
-  var msg = await onmessage();
-  assert_equals(msg.data.type, "relaxed");
-  assert_equals(msg.data.body, "{{host}}");
-
-  document.domain = document.domain;
-  frames[0].document.body;
-  var report = await onreport;
-  assert_equals(report.type, "deprecation");
-  assert_equals(report.body.id, "CrossOriginAccessBasedOnDocumentDomain");
-}, "Deprecation warning for document-domain mediated cross-origin access.");
-</script>
diff --git a/third_party/blink/web_tests/wpt_internal/origin-agent-cluster-default-warning/document-domain-setting.https.sub.html b/third_party/blink/web_tests/wpt_internal/origin-agent-cluster-default-warning/document-domain-setting.https.sub.html
deleted file mode 100644
index ac8a6fca..0000000
--- a/third_party/blink/web_tests/wpt_internal/origin-agent-cluster-default-warning/document-domain-setting.https.sub.html
+++ /dev/null
@@ -1,42 +0,0 @@
-<!DOCTYPE html>
-<title>Warnings when setting document.domain without Origin-Agent-Cluster header</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<iframe src="https://{{domains[www]}}:{{location[port]}}/wpt_internal/origin-agent-cluster-default-warning/resources/frame.html"></iframe>
-<script>
-
-// These tests ensure that deprecation warnings are issued when document.domain
-// is set, and when a cross-origin access based on that document.domain setting
-// is made. This requires the OriginAgentClusterDefaultWarning flag.
-//
-// The ReportingObserver infrastructure seems to coalescs deprecation warnings,
-// so that multiple waring events only result in a single warning. To accomodate
-// this, we'll move each test into a single file, despite this making the test
-// suite somewhat harder to follow.
-
-// Wait for onload event, since that guarantees the iframe has loaded.
-const onload = new Promise((resolve, reject) => {
-  window.onload = _ => { resolve(); };
-});
-// Wait for a message from (any of) our frame(s).
-function onmessage() {
-  return new Promise((resolve, reject) => {
-    window.addEventListener("message", msg => { resolve(msg); },
-                            { once: true });
-  });
-}
-
-// Test that setting document.domain (without an Origin-Agent-Cluster header)
-// will issue a deprecation warning (with id
-// kDocumentDomainSettingWithoutOriginAgentClusterHeader).
-promise_test(async t => {
-  await onload;
-  frames[0].postMessage("relax", "*");
-  var msg = await onmessage();
-  assert_equals(msg.data.type, "relaxed");
-  assert_equals(msg.data.body, "{{host}}");
-  msg = await onmessage();
-  assert_equals(msg.data.type, "deprecation");
-  assert_equals(msg.data.id, "DocumentDomainSettingWithoutOriginAgentClusterHeader");
-}, "Deprecation warning for setting document.domain");
-</script>
diff --git a/third_party/blink/web_tests/wpt_internal/origin-agent-cluster-default-warning/resources/frame.html b/third_party/blink/web_tests/wpt_internal/origin-agent-cluster-default-warning/resources/frame.html
deleted file mode 100644
index ab53fc2a..0000000
--- a/third_party/blink/web_tests/wpt_internal/origin-agent-cluster-default-warning/resources/frame.html
+++ /dev/null
@@ -1,37 +0,0 @@
-<!DOCTYPE html>
-<title>Frame content to load from document-domain.https.html</title>
-<script>
-
-// Pass all deprecation reports on to our parent window.
-new ReportingObserver((reports, observer) => {
-  for (report of reports) {
-    window.parent.postMessage({
-      type: report.type,
-      url: report.url,
-      id: report.body.id,
-      body: report.body.toJSON(),
-    }, "*");
-  }
-}).observe();
-
-window.addEventListener("message", event => {
-  var result;
-  if (event.data == "relax") {
-    // Relax same-origin restrictions by setting document.domain.
-    try {
-      const dd = document.domain;
-      document.domain = dd.substring(1 + dd.indexOf("."));
-    } catch {};
-    window.parent.postMessage({
-      type: "relaxed",
-      body: document.domain,
-    }, "*");
-  } else {
-    // For debugging: We received a message we can't process.
-    window.parent.postMessage({
-      type: "unknown",
-      body: event.data,
-    }, "*");
-  }
-}, false);
-</script>
diff --git a/third_party/boringssl/src b/third_party/boringssl/src
index 604868d..40ec347 160000
--- a/third_party/boringssl/src
+++ b/third_party/boringssl/src
@@ -1 +1 @@
-Subproject commit 604868d748c06d2c5c03505915e125ec5131eca0
+Subproject commit 40ec347196a939bd4fd1f801df896b2f4e2205dc
diff --git a/third_party/dawn b/third_party/dawn
index bc56248..ca2e375 160000
--- a/third_party/dawn
+++ b/third_party/dawn
@@ -1 +1 @@
-Subproject commit bc562481f3a6eb08ddc4b20ae2a2bb70f0a15409
+Subproject commit ca2e3757ae7c8e8236ac780a2f10f75fdc9da156
diff --git a/third_party/depot_tools b/third_party/depot_tools
index c36eb43..1ad5b6c 160000
--- a/third_party/depot_tools
+++ b/third_party/depot_tools
@@ -1 +1 @@
-Subproject commit c36eb432d9887c0872ba39e582a97dd3b76c0c22
+Subproject commit 1ad5b6c0df87d570420c9f833c0c024fa863853b
diff --git a/third_party/devtools-frontend-internal b/third_party/devtools-frontend-internal
index 660f366..f13f620 160000
--- a/third_party/devtools-frontend-internal
+++ b/third_party/devtools-frontend-internal
@@ -1 +1 @@
-Subproject commit 660f3660a28aaf564aeff5015f013cec4f17f72c
+Subproject commit f13f62055a86f13f3f560fb10ea9c5cd6ecaf62a
diff --git a/third_party/devtools-frontend/src b/third_party/devtools-frontend/src
index b20e8d5..b5ed0ccf 160000
--- a/third_party/devtools-frontend/src
+++ b/third_party/devtools-frontend/src
@@ -1 +1 @@
-Subproject commit b20e8d5ddd78f6d04a0b1fd4147aaa821f1bb6a2
+Subproject commit b5ed0ccf1e934c3b15df0239c022f4282dd5a3a5
diff --git a/third_party/skia b/third_party/skia
index 618beab..320dccf 160000
--- a/third_party/skia
+++ b/third_party/skia
@@ -1 +1 @@
-Subproject commit 618beab475b6ee5b33a4c3040dc330359b960eab
+Subproject commit 320dccf1a32dbc4d477fdb194515f75731903a6a
diff --git a/third_party/vulkan-deps b/third_party/vulkan-deps
index 3b92cef..49bb428 160000
--- a/third_party/vulkan-deps
+++ b/third_party/vulkan-deps
@@ -1 +1 @@
-Subproject commit 3b92cef97febae53dc21de79c51ec3ddf2d4390e
+Subproject commit 49bb428cd4514a34c4626a7589e2251d5b50dced
diff --git a/third_party/vulkan-validation-layers/src b/third_party/vulkan-validation-layers/src
index 99de3c1..50910c0 160000
--- a/third_party/vulkan-validation-layers/src
+++ b/third_party/vulkan-validation-layers/src
@@ -1 +1 @@
-Subproject commit 99de3c17fbc2db6b6da0347916c9e01a383c2758
+Subproject commit 50910c05fdc909aba59cc71e6320b0c5908912cd
diff --git a/third_party/webgpu-cts/src b/third_party/webgpu-cts/src
index 7568697..e42b1f6 160000
--- a/third_party/webgpu-cts/src
+++ b/third_party/webgpu-cts/src
@@ -1 +1 @@
-Subproject commit 7568697695ffd3e4eebee494d833feb99f65494b
+Subproject commit e42b1f6ef712353f416f4528267a37895631180c
diff --git a/third_party/webgpu-cts/ts_sources.txt b/third_party/webgpu-cts/ts_sources.txt
index c54fdd37..1dedd41 100644
--- a/third_party/webgpu-cts/ts_sources.txt
+++ b/third_party/webgpu-cts/ts_sources.txt
@@ -266,7 +266,6 @@
 src/webgpu/api/validation/capability_checks/limits/maxComputeWorkgroupsPerDimension.spec.ts
 src/webgpu/api/validation/capability_checks/limits/maxDynamicStorageBuffersPerPipelineLayout.spec.ts
 src/webgpu/api/validation/capability_checks/limits/maxDynamicUniformBuffersPerPipelineLayout.spec.ts
-src/webgpu/api/validation/capability_checks/limits/maxInterStageShaderComponents.spec.ts
 src/webgpu/api/validation/capability_checks/limits/maxInterStageShaderVariables.spec.ts
 src/webgpu/api/validation/capability_checks/limits/maxSampledTexturesPerShaderStage.spec.ts
 src/webgpu/api/validation/capability_checks/limits/maxSamplersPerShaderStage.spec.ts
diff --git a/third_party/webrtc b/third_party/webrtc
index e922cd1..47d48a2 160000
--- a/third_party/webrtc
+++ b/third_party/webrtc
@@ -1 +1 @@
-Subproject commit e922cd12628e32b37c06c2be4d23e4f8a1452e80
+Subproject commit 47d48a2089ab765a3ef1177c5c1456eb3d67aa8a
diff --git a/tools/clang/spanify/Spanifier.cpp b/tools/clang/spanify/Spanifier.cpp
index 88a581c9..020e674 100644
--- a/tools/clang/spanify/Spanifier.cpp
+++ b/tools/clang/spanify/Spanifier.cpp
@@ -6,6 +6,7 @@
 
 #include <map>
 #include <set>
+#include <sstream>
 #include <string>
 #include <vector>
 
@@ -14,6 +15,7 @@
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Basic/SourceManager.h"
+#include "clang/Rewrite/Core/Rewriter.h"
 #include "clang/Tooling/CommonOptionsParser.h"
 #include "clang/Tooling/Refactoring.h"
 #include "llvm/Support/FormatVariadic.h"
@@ -190,29 +192,71 @@
 // raw pointer type to a base::span type. It handles preservation of
 // const/volatile qualifiers and uses a specific printing policy to format the
 // underlying pointee type.
-std::string GenerateSpanType(const clang::ASTContext& ast_context,
-                             const clang::QualType& pointer_type) {
-  std::string result;
+// This functions generates a string representing the converted type from a
+// raw pointer type to a base::span type. It handles preservation of
+// const/volatile qualifiers and uses a specific printing policy to format the
+// underlying pointee type.
+std::string GenerateSpanType(clang::SourceManager& source_manager,
+                             const clang::ASTContext& ast_context,
+                             const clang::DeclaratorDecl& decl) {
+  // Preserve qualifiers.
+  const clang::QualType& pointer_type = decl.getType();
+  std::ostringstream qualifiers;
+  qualifiers << (pointer_type.isConstQualified() ? "const " : "")
+             << (pointer_type.isVolatileQualified() ? "volatile " : "");
 
+  // If `pointer_type` not "auto", getContainedAutoType() returns nullptr.
+  if (!pointer_type->getContainedAutoType()) {
+    // Strategy: Use the original text as much as possible when its isn't
+    // "auto". So for example, if we see `uint16_t` and so on, we can keep
+    // `uint16_t`, instead of `unsigned short`.
+    clang::Rewriter rewriter(source_manager, ast_context.getLangOpts());
+
+    // The range of the type specifier, including the qualifiers:
+    //
+    //                       const int* array[32] = ...;
+    //                       |     |   |
+    // getOuterLocStart()----+     |   |
+    // getTypeSpecStartLoc()-------+   |
+    // getTypeSpecEndLoc()-------------+
+    //
+    clang::SourceRange source_with_qualifiers(
+        decl.getOuterLocStart(),  // Include the qualifiers.
+        decl.getTypeSpecEndLoc());
+    std::string type_with_qualifiers =
+        rewriter.getRewrittenText(source_with_qualifiers);
+    // Because of `pointer_type`, the last character of `type_spec_text` is '*'.
+    size_t pos = type_with_qualifiers.find_last_of('*');
+
+    // If the `pointer_type` is a pointer of array or a pointer of a function,
+    // E.g. int (*array)[32], int (*func)(int, ...), ...
+    // `pos` is not equal to length()-1.
+    if (pos == type_with_qualifiers.length() - 1) {
+      // Remove '*' from `type_with_qualifiers` to obtain
+      // `pointee_type_as_string`.
+      std::string type = type_with_qualifiers.substr(0, pos);
+      return qualifiers.str() + llvm::formatv("base::span<{0}>", type).str();
+    }
+  }
+
+  // If the original type cannot be recovered from the source, we need to
+  // consult the clang deduced type.
+  //
+  // Please note that the deduced type may not be the same as the original type.
+  // For example, if we have the following code:
+  //   const auto* p = get_buffer<uint16_t>();
+  // we will get:`unsigned short` instead of `uint16_t`.
   clang::QualType pointee_type = pointer_type->getPointeeType();
 
-  // Preserve qualifiers.
-  if (pointer_type.isConstQualified()) {
-    result += "const ";
-  }
-  if (pointer_type.isVolatileQualified()) {
-    result += "volatile ";
-  }
-
-  // Convert pointee type to string.
   clang::PrintingPolicy printing_policy(ast_context.getLangOpts());
-  printing_policy.SuppressScope = 1;
+  printing_policy.SuppressScope = 0;
+  printing_policy.SuppressUnwrittenScope = 1;
+  printing_policy.SuppressInlineNamespace = 1;
+  printing_policy.SuppressDefaultTemplateArgs = 1;
   printing_policy.PrintCanonicalTypes = 1;
-  std::string pointee_type_as_string =
-      pointee_type.getAsString(printing_policy);
-  result += llvm::formatv("base::span<{0}>", pointee_type_as_string);
 
-  return result;
+  std::string type = pointee_type.getAsString(printing_policy);
+  return qualifiers.str() + llvm::formatv("base::span<{0}>", type).str();
 }
 
 // It is intentional that this function ignores cast expressions and applies
@@ -341,12 +385,11 @@
 
 static Node getNodeFromDecl(const clang::DeclaratorDecl* decl,
                             const MatchFinder::MatchResult& result) {
-  const clang::SourceManager& source_manager = *result.SourceManager;
+  clang::SourceManager& source_manager = *result.SourceManager;
   const clang::ASTContext& ast_context = *result.Context;
   clang::SourceRange replacement_range{decl->getBeginLoc(),
                                        decl->getLocation()};
-  auto pointer_type = decl->getType();
-  auto replacement_text = GenerateSpanType(ast_context, pointer_type);
+  auto replacement_text = GenerateSpanType(source_manager, ast_context, *decl);
   auto replacement_and_include_pair = GetReplacementAndIncludeDirectives(
       replacement_range, replacement_text, source_manager);
   Node n;
diff --git a/tools/clang/spanify/tests/basics-expected.cc b/tools/clang/spanify/tests/basics-expected.cc
index 1bcbd0c..b9dbbeda 100644
--- a/tools/clang/spanify/tests/basics-expected.cc
+++ b/tools/clang/spanify/tests/basics-expected.cc
@@ -4,6 +4,7 @@
 #include <stdlib.h>
 
 #include <array>
+#include <cstdint>
 #include <cstring>
 #include <vector>
 
@@ -196,6 +197,11 @@
   buf2[1] = 'a';
 
   // Expected rewrite:
+  // base::span<unsigned short> buf2 = get_buffer<uint16_t>();
+  base::span<unsigned short> buf3 = get_buffer<uint16_t>();
+  buf3[1] = 256;
+
+  // Expected rewrite:
   // memcpy(buf2.data(), buf.data(), 10
   memcpy(buf2.data(), buf.data(), 10);
 
@@ -230,3 +236,20 @@
   buf[index] = 11;
 }
 }  // namespace buffers_into_arrays
+
+namespace namespace_stuff {
+namespace ns1 {
+struct B {
+  int b = 0;
+};
+}  // namespace ns1
+
+void fct() {
+  // Expected rewrite:
+  // base::span<namespace_stuff::ns1::B> ptr = new ns1::B[32];
+  base::span<namespace_stuff::ns1::B> buf = new ns1::B[32];
+  // However since there is no viable conversion from `B*` into
+  // `base::span<ns1::B>`, the rewrite will cause compile error.
+  buf[0].b = -1;
+}
+}  // namespace namespace_stuff
diff --git a/tools/clang/spanify/tests/basics-original.cc b/tools/clang/spanify/tests/basics-original.cc
index accc71d..8e90039a 100644
--- a/tools/clang/spanify/tests/basics-original.cc
+++ b/tools/clang/spanify/tests/basics-original.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 #include <stdlib.h>
 
+#include <cstdint>
 #include <cstring>
 #include <vector>
 
@@ -194,6 +195,11 @@
   buf2[1] = 'a';
 
   // Expected rewrite:
+  // base::span<unsigned short> buf2 = get_buffer<uint16_t>();
+  auto* buf3 = get_buffer<uint16_t>();
+  buf3[1] = 256;
+
+  // Expected rewrite:
   // memcpy(buf2.data(), buf.data(), 10
   memcpy(buf2, buf, 10);
 
@@ -228,3 +234,20 @@
   buf[index] = 11;
 }
 }  // namespace buffers_into_arrays
+
+namespace namespace_stuff {
+namespace ns1 {
+struct B {
+  int b = 0;
+};
+}  // namespace ns1
+
+void fct() {
+  // Expected rewrite:
+  // base::span<namespace_stuff::ns1::B> ptr = new ns1::B[32];
+  auto* buf = new ns1::B[32];
+  // However since there is no viable conversion from `B*` into
+  // `base::span<ns1::B>`, the rewrite will cause compile error.
+  buf[0].b = -1;
+}
+}  // namespace namespace_stuff
diff --git a/tools/clang/spanify/tests/operator-bool-expected.cc b/tools/clang/spanify/tests/operator-bool-expected.cc
index b6e07dc..1df79229 100644
--- a/tools/clang/spanify/tests/operator-bool-expected.cc
+++ b/tools/clang/spanify/tests/operator-bool-expected.cc
@@ -11,8 +11,8 @@
 using Handle = int;
 
 // Expected rewrite:
-// void f(const base::span<int>& handles, size_t num_handles) {
-void f(base::span<int> handles, size_t num_handles) {
+// void f(const base::span<Handle>& handles, size_t num_handles) {
+void f(base::span<Handle> handles, size_t num_handles) {
   // TODO(358306232) operator bool() is not supported by base::span.
   if (!handles || !num_handles) {
     return;
diff --git a/tools/clang/spanify/tests/operator-bool-original.cc b/tools/clang/spanify/tests/operator-bool-original.cc
index 45da75e..ad360f1af 100644
--- a/tools/clang/spanify/tests/operator-bool-original.cc
+++ b/tools/clang/spanify/tests/operator-bool-original.cc
@@ -9,7 +9,7 @@
 using Handle = int;
 
 // Expected rewrite:
-// void f(const base::span<int>& handles, size_t num_handles) {
+// void f(const base::span<Handle>& handles, size_t num_handles) {
 void f(Handle* handles, size_t num_handles) {
   // TODO(358306232) operator bool() is not supported by base::span.
   if (!handles || !num_handles) {
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index ed0b66e..e5db74a7 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -10906,6 +10906,7 @@
   <int value="5096" label="V8Window_PopinContextTypesSupported_Method"/>
   <int value="5097" label="V8Window_PopinContextType_Method"/>
   <int value="5098" label="WebAuthentication_AttestationFormats"/>
+  <int value="5099" label="CssDisplayPropertyMultipleValues"/>
 </enum>
 
 <!-- LINT.ThenChange(//third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom:WebFeature) -->
@@ -16147,6 +16148,7 @@
   <int value="-1880355454" label="disable-topchrome-md"/>
   <int value="-1879877238" label="disable-cancel-all-touches"/>
   <int value="-1878958319" label="ScrollableTabStripButtons:disabled"/>
+  <int value="-1878244826" label="LensOverlayTranslateButton:disabled"/>
   <int value="-1877422414" label="FlexFirmwareUpdate:disabled"/>
   <int value="-1877005823" label="ZeroSuggestInMemoryCaching:enabled"/>
   <int value="-1876955850" label="EnablePciguardUi:enabled"/>
@@ -22348,6 +22350,7 @@
   <int value="709850261" label="disable-touch-editing"/>
   <int value="710700286" label="ImmersiveFullscreen:disabled"/>
   <int value="711424932" label="enable-cloud-print-xps"/>
+  <int value="711627544" label="ImeSwitchCheckConnectionStatus:enabled"/>
   <int value="713216521" label="NtpMostRelevantTabResumptionModule:disabled"/>
   <int value="713946324" label="OmniboxSearchReadyIncognito:disabled"/>
   <int value="714714531" label="VcControlsUi:enabled"/>
@@ -23572,6 +23575,7 @@
       label="kAutofillRationalizeRepeatedServerPredictions:enabled"/>
   <int value="1222309415" label="SplitCacheByNetworkIsolationKey:enabled"/>
   <int value="1222808563" label="DisableInitialMostVisitedFadeIn:disabled"/>
+  <int value="1224660785" label="ImeSwitchCheckConnectionStatus:disabled"/>
   <int value="1224806430" label="ConsumerAutoUpdateToggleAllowed:enabled"/>
   <int value="1226624874" label="Mus:disabled"/>
   <int value="1226676061" label="PageInfoV2Desktop:enabled"/>
@@ -24053,6 +24057,7 @@
   <int value="1419984081"
       label="DesktopPWAsFlashAppNameInsteadOfOrigin:enabled"/>
   <int value="1420007919" label="SyncTrustedVaultPassphrasePromo:disabled"/>
+  <int value="1420438813" label="LensOverlayTranslateButton:enabled"/>
   <int value="1421267643" label="HoldingSpaceRefresh:disabled"/>
   <int value="1421620678" label="simple-clear-browsing-data-support-string"/>
   <int value="1422421509" label="SetTimeoutWithoutClamp:disabled"/>
@@ -34250,6 +34255,7 @@
   <int value="108" label="JsModulesServiceWorkers"/>
   <int value="109" label="JsModulesSharedWorkers"/>
   <int value="110" label="JsModulesWorkers"/>
+  <int value="111" label="TwoValueDisplay"/>
 </enum>
 
 <!-- LINT.ThenChange(//third_party/blink/public/mojom/use_counter/metrics/webdx_feature.mojom:WebDXFeature) -->
diff --git a/tools/metrics/histograms/metadata/ash/histograms.xml b/tools/metrics/histograms/metadata/ash/histograms.xml
index 3c3ac77..0b96df6 100644
--- a/tools/metrics/histograms/metadata/ash/histograms.xml
+++ b/tools/metrics/histograms/metadata/ash/histograms.xml
@@ -4133,18 +4133,6 @@
   </summary>
 </histogram>
 
-<histogram name="Ash.FocusMode.StartSession.HasSelectedTask" enum="Boolean"
-    expires_after="2025-02-01">
-  <owner>hongyulong@chromium.org</owner>
-  <owner>richui@chromium.org</owner>
-  <owner>nupurjain@google.com</owner>
-  <owner>chromeos-wms@google.com</owner>
-  <summary>
-    Emits true when a task is selected on a session start; otherwise, emits
-    false.
-  </summary>
-</histogram>
-
 <histogram name="Ash.FocusMode.StartSession.InitialDuration" units="minutes"
     expires_after="2024-12-31">
   <owner>hongyulong@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/cros/enums.xml b/tools/metrics/histograms/metadata/cros/enums.xml
index 4e61fa9..2c0f3222 100644
--- a/tools/metrics/histograms/metadata/cros/enums.xml
+++ b/tools/metrics/histograms/metadata/cros/enums.xml
@@ -399,6 +399,7 @@
 </enum>
 
 <enum name="DaemonError">
+  <int value="0" label="OK"/>
   <int value="132" label="SIGILL">
     MINIJAIL_ERR_SIG_BASE (128) + SIGILL (4) from libminijail
   </int>
diff --git a/tools/metrics/histograms/metadata/cros/histograms.xml b/tools/metrics/histograms/metadata/cros/histograms.xml
index e370c43..8111a5d 100644
--- a/tools/metrics/histograms/metadata/cros/histograms.xml
+++ b/tools/metrics/histograms/metadata/cros/histograms.xml
@@ -64,14 +64,14 @@
   </summary>
   <token key="FileSystem">
     <variant name="archive"/>
-    <variant name="drivefs"/>
-    <variant name="fuseblk.exfat"/>
-    <variant name="fuseblk.ntfs"/>
+    <variant name="drivefs" summary="DriveFS"/>
+    <variant name="fuseblk.exfat" summary="FUSE-exFAT"/>
+    <variant name="fuseblk.ntfs" summary="FUSE-NTFS"/>
     <variant name="fusebox"/>
-    <variant name="rar"/>
+    <variant name="rar" summary="RAR"/>
     <variant name="smbfs"/>
-    <variant name="sshfs"/>
-    <variant name="zip"/>
+    <variant name="sshfs" summary="SSHFS"/>
+    <variant name="zip" summary="ZIP"/>
   </token>
 </histogram>
 
@@ -80,17 +80,16 @@
   <owner>fdegros@chromium.org</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
-    Error returned by the program performing the {Action} action on a partition
-    with the {FileSystem} filesystem.
+    Error returned by the program {Action} {FileSystem} partition.
   </summary>
   <token key="Action">
-    <variant name="Format"/>
-    <variant name="Rename"/>
+    <variant name="Format" summary="formatting"/>
+    <variant name="Rename" summary="renaming"/>
   </token>
   <token key="FileSystem">
-    <variant name="exfat"/>
-    <variant name="ntfs"/>
-    <variant name="vfat"/>
+    <variant name="exfat" summary="an exFAT"/>
+    <variant name="ntfs" summary="an NTFS"/>
+    <variant name="vfat" summary="a FAT"/>
   </token>
 </histogram>
 
@@ -99,34 +98,34 @@
   <owner>fdegros@chromium.org</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
-    Error returned by the `{SysCall}` system call when the ChromeOS cros-disks
-    daemon deals with a `{FileSystem}` filesystem.
+    Error encountered by the ChromeOS cros-disks daemon when it tried to
+    {SysCall} a {FileSystem} filesystem.
   </summary>
   <token key="SysCall">
     <variant name="mount"/>
-    <variant name="syncfs"/>
-    <variant name="umount"/>
-    <variant name="umount2"/>
+    <variant name="syncfs" summary="flush"/>
+    <variant name="umount" summary="unmount"/>
+    <variant name="umount2" summary="detach"/>
   </token>
   <token key="FileSystem">
     <variant name="archive"/>
-    <variant name="drivefs"/>
-    <variant name="exfat"/>
+    <variant name="drivefs" summary="DriveFS"/>
+    <variant name="exfat" summary="exFAT"/>
     <variant name="ext2"/>
     <variant name="ext3"/>
     <variant name="ext4"/>
-    <variant name="fuseblk.exfat"/>
-    <variant name="fuseblk.ntfs"/>
+    <variant name="fuseblk.exfat" summary="FUSE-exFAT"/>
+    <variant name="fuseblk.ntfs" summary="FUSE-NTFS"/>
     <variant name="fusebox"/>
-    <variant name="hfsplus"/>
-    <variant name="iso9660"/>
-    <variant name="ntfs3"/>
-    <variant name="rar"/>
+    <variant name="hfsplus" summary="HFS+"/>
+    <variant name="iso9660" summary="ISO 9660"/>
+    <variant name="ntfs3" summary="NTFS"/>
+    <variant name="rar" summary="RAR"/>
     <variant name="smbfs"/>
-    <variant name="sshfs"/>
-    <variant name="udf"/>
-    <variant name="vfat"/>
-    <variant name="zip"/>
+    <variant name="sshfs" summary="SSHFS"/>
+    <variant name="udf" summary="UDF"/>
+    <variant name="vfat" summary="FAT"/>
+    <variant name="zip" summary="ZIP"/>
   </token>
 </histogram>
 
@@ -192,14 +191,14 @@
   </summary>
   <token key="FileSystem">
     <variant name="archive"/>
-    <variant name="drivefs"/>
-    <variant name="fuseblk.exfat"/>
-    <variant name="fuseblk.ntfs"/>
+    <variant name="drivefs" summary="DriveFS"/>
+    <variant name="fuseblk.exfat" summary="FUSE-exFAT"/>
+    <variant name="fuseblk.ntfs" summary="FUSE-NTFS"/>
     <variant name="fusebox"/>
-    <variant name="rar"/>
+    <variant name="rar" summary="RAR"/>
     <variant name="smbfs"/>
-    <variant name="sshfs"/>
-    <variant name="zip"/>
+    <variant name="sshfs" summary="SSHFS"/>
+    <variant name="zip" summary="ZIP"/>
   </token>
 </histogram>
 
@@ -207,18 +206,15 @@
     expires_after="2025-03-01">
   <owner>fdegros@chromium.org</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
-  <summary>
-    Time taken by the program performing the {Action} action on a partition with
-    the {FileSystem} filesystem.
-  </summary>
+  <summary>Time taken by the program {Action} {FileSystem} partition.</summary>
   <token key="Action">
-    <variant name="Format"/>
-    <variant name="Rename"/>
+    <variant name="Format" summary="formatting"/>
+    <variant name="Rename" summary="renaming"/>
   </token>
   <token key="FileSystem">
-    <variant name="exfat"/>
-    <variant name="ntfs"/>
-    <variant name="vfat"/>
+    <variant name="exfat" summary="an exFAT"/>
+    <variant name="ntfs" summary="an NTFS"/>
+    <variant name="vfat" summary="a FAT"/>
   </token>
 </histogram>
 
@@ -227,34 +223,34 @@
   <owner>fdegros@chromium.org</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
-    Time taken by the `{SysCall}` system call when the ChromeOS cros-disks
-    daemon deals with a `{FileSystem}` filesystem.
+    Time taken by the ChromeOS cros-disks daemon when it tried to {SysCall} a
+    {FileSystem} filesystem.
   </summary>
   <token key="SysCall">
     <variant name="mount"/>
-    <variant name="syncfs"/>
-    <variant name="umount"/>
-    <variant name="umount2"/>
+    <variant name="syncfs" summary="flush"/>
+    <variant name="umount" summary="unmount"/>
+    <variant name="umount2" summary="detach"/>
   </token>
   <token key="FileSystem">
     <variant name="archive"/>
-    <variant name="drivefs"/>
-    <variant name="exfat"/>
+    <variant name="drivefs" summary="DriveFS"/>
+    <variant name="exfat" summary="exFAT"/>
     <variant name="ext2"/>
     <variant name="ext3"/>
     <variant name="ext4"/>
-    <variant name="fuseblk.exfat"/>
-    <variant name="fuseblk.ntfs"/>
+    <variant name="fuseblk.exfat" summary="FUSE-exFAT"/>
+    <variant name="fuseblk.ntfs" summary="FUSE-NTFS"/>
     <variant name="fusebox"/>
-    <variant name="hfsplus"/>
-    <variant name="iso9660"/>
-    <variant name="ntfs3"/>
-    <variant name="rar"/>
+    <variant name="hfsplus" summary="HFS+"/>
+    <variant name="iso9660" summary="ISO 9660"/>
+    <variant name="ntfs3" summary="NTFS"/>
+    <variant name="rar" summary="RAR"/>
     <variant name="smbfs"/>
-    <variant name="sshfs"/>
-    <variant name="udf"/>
-    <variant name="vfat"/>
-    <variant name="zip"/>
+    <variant name="sshfs" summary="SSHFS"/>
+    <variant name="udf" summary="UDF"/>
+    <variant name="vfat" summary="FAT"/>
+    <variant name="zip" summary="ZIP"/>
   </token>
 </histogram>
 
diff --git a/tools/metrics/histograms/metadata/cryptohome/histograms.xml b/tools/metrics/histograms/metadata/cryptohome/histograms.xml
index 86b92b7..57fe34e6 100644
--- a/tools/metrics/histograms/metadata/cryptohome/histograms.xml
+++ b/tools/metrics/histograms/metadata/cryptohome/histograms.xml
@@ -87,7 +87,7 @@
 </histogram>
 
 <histogram name="Cryptohome.DeletedUserProfiles" units="profiles"
-    expires_after="2024-09-20">
+    expires_after="2025-09-20">
   <owner>simmonsjosh@google.com</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/navigation/histograms.xml b/tools/metrics/histograms/metadata/navigation/histograms.xml
index c5b9019..1568211a4 100644
--- a/tools/metrics/histograms/metadata/navigation/histograms.xml
+++ b/tools/metrics/histograms/metadata/navigation/histograms.xml
@@ -74,6 +74,36 @@
   <variant name="SameSite"/>
 </variants>
 
+<variants name="TracedMethod">
+  <variant name="AgentSchedulingGroupHost.RemoveRoute"
+      summary="AgentSchedulingGroupHost::RemoveRoute()"/>
+  <variant name="DocumentAssociatedDataDestructor"
+      summary="DocumentAssociatedData destructor"/>
+  <variant name="Frame.SwapImpl" summary="Frame::SwapImpl()"/>
+  <variant name="LocalFrame.DetachImpl.Remove"
+      summary="LocalFrame::DetachImpl() for removal"/>
+  <variant name="LocalFrame.DetachImpl.Swap"
+      summary="LocalFrame::DetachImpl() for swapping"/>
+  <variant name="LocalFrame.SwapIn" summary="LocalFrame::SwapIn()"/>
+  <variant name="PendingDeletionCheckCompletedOnSubtree"
+      summary="RenderFrameHostImpl::PendingDeletionCheckCompletedOnSubtree()"/>
+  <variant name="RenderFrameHostImpl.DeleteRenderFrame"
+      summary="RenderFrameHostImpl::DeleteRenderFrame()"/>
+  <variant name="ResetChildren" summary="RenderFrameHostImpl::ResetChildren()"/>
+  <variant name="StartPendingDeletionOnSubtree.Detach"
+      summary="RenderFrameHostImpl::StartPendingDeletionOnSubtree() for
+               detaching"/>
+  <variant name="StartPendingDeletionOnSubtree.Loop.Detach"
+      summary="RenderFrameHostImpl::StartPendingDeletionOnSubtree() for
+               swapping, children looping part"/>
+  <variant name="StartPendingDeletionOnSubtree.Loop.SwappedOut"
+      summary="RenderFrameHostImpl::StartPendingDeletionOnSubtree() for
+               detaching, children looping part"/>
+  <variant name="StartPendingDeletionOnSubtree.SwappedOut"
+      summary="RenderFrameHostImpl::StartPendingDeletionOnSubtree() for
+               swapping"/>
+</variants>
+
 <histogram name="BackForwardCache.AllSites.EvictedAfterDocumentRestoredReason"
     enum="BackForwardCacheEvictedAfterDocumentRestoredReason"
     expires_after="2024-07-07">
@@ -2223,6 +2253,16 @@
   <token key="Stage" variants="NavigationStage"/>
 </histogram>
 
+<histogram name="Navigation.{TracedMethod}" units="ms"
+    expires_after="2025-02-23">
+  <owner>rakina@chromium.org</owner>
+  <owner>chrome-security-architecture@google.com</owner>
+  <summary>
+    The time it takes to run {TracedMethod}. Recorded everytime {TracedMethod}
+    is triggered.
+  </summary>
+</histogram>
+
 <histogram name="NavigationSuggestion.Event2" enum="NavigationSuggestionEvent"
     expires_after="2024-12-08">
   <owner>meacer@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/net/histograms.xml b/tools/metrics/histograms/metadata/net/histograms.xml
index cd8b115..52e0eb8 100644
--- a/tools/metrics/histograms/metadata/net/histograms.xml
+++ b/tools/metrics/histograms/metadata/net/histograms.xml
@@ -2256,6 +2256,24 @@
 </histogram>
 
 <histogram
+    name="Net.NetworkTransaction.Create{StreamType}Time.{HostType}.{Protocol}"
+    units="ms" expires_after="2025-03-08">
+  <owner>bashi@chromium.org</owner>
+  <owner>src/net/OWNERS</owner>
+  <summary>
+    The time taken for creating a(n) {StreamType}. Recorded in
+    HttpNetworkTransaction::DoCreateStreamComplete when the stream creation
+    completes successfully.
+  </summary>
+  <token key="StreamType">
+    <variant name="HttpStream"/>
+    <variant name="WebSocketStream"/>
+  </token>
+  <token key="HostType" variants="NetworkTransactionBlockedHostType"/>
+  <token key="Protocol" variants="NetworkTransactionBlockedProtocol"/>
+</histogram>
+
+<histogram
     name="Net.NetworkTransaction.GenerateProxyAuthTokenBlocked{HostType}.{Protocol}"
     enum="Boolean" expires_after="2025-03-02">
   <owner>bashi@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/network/histograms.xml b/tools/metrics/histograms/metadata/network/histograms.xml
index 764d325..037c09e 100644
--- a/tools/metrics/histograms/metadata/network/histograms.xml
+++ b/tools/metrics/histograms/metadata/network/histograms.xml
@@ -49,6 +49,25 @@
   <variant name="WiFi.SecurityPasswordProtected"/>
 </variants>
 
+<variants name="HTTPRequestConnectionProtocol">
+  <variant name="Multiplexed"/>
+  <variant name="Simple"/>
+</variants>
+
+<variants name="HTTPRequestMethod">
+  <variant name="Get"/>
+</variants>
+
+<variants name="HTTPRequestResult">
+  <variant name="ClientError"/>
+  <variant name="ServerError"/>
+  <variant name="Success"/>
+</variants>
+
+<variants name="HTTPRequestType">
+  <variant name="MainFrame"/>
+</variants>
+
 <variants name="IPsecVPNType">
   <variant name="Ikev2" summary="IKEv2"/>
   <variant name="L2tpIpsec" summary="L2TP/IPsec"/>
@@ -5199,6 +5218,23 @@
 </histogram>
 
 <histogram
+    name="NetworkService.Requests.{Multiplexed}.{RequestType}.{Method}.{Result}.TotalHeadersSize"
+    units="bytes" expires_after="2025-08-01">
+  <owner>ortuno@chromium.org</owner>
+  <owner>navtracking-team@google.com</owner>
+  <summary>
+    The total size of request headers. Many servers reject requests where
+    headers exceed a certain size, which can cause cross-site leaks. This
+    metrics helps us understand what those header sizes are. Recorded at the
+    start of a request's response.
+  </summary>
+  <token key="Multiplexed" variants="HTTPRequestConnectionProtocol"/>
+  <token key="RequestType" variants="HTTPRequestType"/>
+  <token key="Method" variants="HTTPRequestMethod"/>
+  <token key="Result" variants="HTTPRequestResult"/>
+</histogram>
+
+<histogram
     name="NetworkService.Requests.{Multiplexed}.{RequestType}.{Method}.{Result}.TotalRequestSize"
     units="bytes" expires_after="2025-08-01">
   <owner>ortuno@chromium.org</owner>
@@ -5206,23 +5242,30 @@
   <summary>
     The total size of network requests. Many servers reject requests that exceed
     a certain size, which can cause cross-site leaks. This metrics helps us
-    understand what those sizes are.
+    understand what those sizes are. Recorded at the start of a request's
+    response.
   </summary>
-  <token key="Multiplexed">
-    <variant name="Multiplexed"/>
-    <variant name="Simple"/>
-  </token>
-  <token key="RequestType">
-    <variant name="MainFrame"/>
-  </token>
-  <token key="Method">
-    <variant name="Get"/>
-  </token>
-  <token key="Result">
-    <variant name="ClientError"/>
-    <variant name="ServerError"/>
-    <variant name="Success"/>
-  </token>
+  <token key="Multiplexed" variants="HTTPRequestConnectionProtocol"/>
+  <token key="RequestType" variants="HTTPRequestType"/>
+  <token key="Method" variants="HTTPRequestMethod"/>
+  <token key="Result" variants="HTTPRequestResult"/>
+</histogram>
+
+<histogram
+    name="NetworkService.Requests.{Multiplexed}.{RequestType}.{Method}.{Result}.TotalUrlSize"
+    units="bytes" expires_after="2025-08-01">
+  <owner>ortuno@chromium.org</owner>
+  <owner>navtracking-team@google.com</owner>
+  <summary>
+    The total size of the requested URL. Many servers reject requests that
+    exceed a certain size, which can cause cross-site leaks. This metrics helps
+    us understand how much URLs contribute to that size. Recorded at the start
+    of a request's response.
+  </summary>
+  <token key="Multiplexed" variants="HTTPRequestConnectionProtocol"/>
+  <token key="RequestType" variants="HTTPRequestType"/>
+  <token key="Method" variants="HTTPRequestMethod"/>
+  <token key="Result" variants="HTTPRequestResult"/>
 </histogram>
 
 <histogram name="NetworkService.SlopBucket.DisabledReason"
diff --git a/tools/metrics/histograms/metadata/page/enums.xml b/tools/metrics/histograms/metadata/page/enums.xml
index 31d5e1d76..e2932ab0 100644
--- a/tools/metrics/histograms/metadata/page/enums.xml
+++ b/tools/metrics/histograms/metadata/page/enums.xml
@@ -293,25 +293,6 @@
   <int value="1" label="Prerender Activation Navigation"/>
 </enum>
 
-<enum name="PageLoadPrerenderObserverEvent">
-  <int value="0" label="OnPrerenderStart"/>
-  <int value="1" label="DidActivatePrerenderedPage"/>
-  <int value="2" label="OnFirstPaintInPage"/>
-  <int value="3" label="OnFirstContentfulPaintInPage"/>
-  <int value="4" label="OnFirstInputInPage"/>
-  <int value="5" label="OnComplete"/>
-  <int value="6" label="FlushMetricsOnAppEnterBackground"/>
-  <int value="7" label="RecordSessionEndHistograms"/>
-  <int value="8" label="RecordLayoutShiftScoreMetrics"/>
-  <int value="9" label="RecordNormalizedResponsivenessMetrics"/>
-</enum>
-
-<enum name="PageLoadPrerenderVisibilityAtActivation">
-  <int value="0" label="Hidden"/>
-  <int value="1" label="Occluded"/>
-  <int value="2" label="Visible"/>
-</enum>
-
 <!-- LINT.IfChange(PageLoadTimingStatus) -->
 
 <enum name="PageLoadTimingStatus">
diff --git a/tools/metrics/histograms/metadata/page/histograms.xml b/tools/metrics/histograms/metadata/page/histograms.xml
index 228e65d5..08f6d15 100644
--- a/tools/metrics/histograms/metadata/page/histograms.xml
+++ b/tools/metrics/histograms/metadata/page/histograms.xml
@@ -3403,27 +3403,6 @@
   </summary>
 </histogram>
 
-<histogram name="PageLoad.Internal.Prerender2.ObserverEvent"
-    enum="PageLoadPrerenderObserverEvent" expires_after="2024-09-15">
-  <owner>nhiroki@chromium.org</owner>
-  <owner>src/content/browser/preloading/prerender/OWNERS</owner>
-  <summary>
-    Counts page load observer events related to Prerender2, like
-    FirstContentfulPaint. Recorded when those events are observed in
-    PrerenderPageLoaderMetricsObserver.
-  </summary>
-</histogram>
-
-<histogram name="PageLoad.Internal.Prerender2.VisibilityAtActivation"
-    enum="PageLoadPrerenderVisibilityAtActivation" expires_after="2024-02-04">
-  <owner>nhiroki@chromium.org</owner>
-  <owner>src/content/browser/preloading/prerender/OWNERS</owner>
-  <summary>
-    Records the visibility of an initiator page in PageLoadTracker when a
-    prerendered page gets activated.
-  </summary>
-</histogram>
-
 <histogram name="PageLoad.Internal.SoftNavigationOutcome"
     enum="SoftNavigationOutcome" expires_after="2025-02-23">
   <owner>iclelland@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/signin/enums.xml b/tools/metrics/histograms/metadata/signin/enums.xml
index bad5b43..950da9e 100644
--- a/tools/metrics/histograms/metadata/signin/enums.xml
+++ b/tools/metrics/histograms/metadata/signin/enums.xml
@@ -237,6 +237,15 @@
   <int value="7" label="Required credential field missing"/>
 </enum>
 
+<enum name="CctAccountMismatchType">
+  <int value="0" label="Signed out of both Chrome and 1P app"/>
+  <int value="1" label="Signed in to Chrome and 1P app with same account"/>
+  <int value="2" label="Signed out of 1P app but signed in to Chrome"/>
+  <int value="3" label="Signed out of Chrome but signed in to 1P app"/>
+  <int value="4"
+      label="Signed in to 1P app and Chrome with different accounts"/>
+</enum>
+
 <enum name="ChromeSigninSettingModification">
   <int value="0" label="No modifications"/>
   <int value="1" label="Modified to always ask"/>
diff --git a/tools/metrics/histograms/metadata/signin/histograms.xml b/tools/metrics/histograms/metadata/signin/histograms.xml
index 2dad9c3d..fca6e4c 100644
--- a/tools/metrics/histograms/metadata/signin/histograms.xml
+++ b/tools/metrics/histograms/metadata/signin/histograms.xml
@@ -893,6 +893,19 @@
   </summary>
 </histogram>
 
+<histogram name="Signin.CctAccountMismatch" enum="CctAccountMismatchType"
+    expires_after="2025-02-10">
+  <owner>samarchehade@google.com</owner>
+  <owner>chrome-signin-team@google.com</owner>
+  <summary>
+    When CCT is launched by AGA, records whether there is a mismatch between the
+    account signed in to Chrome and the account signed in to the app that
+    launched Chrome. This can happen if the user is signed in to Chrome but not
+    the 1P app, or vice-versa, or if the user is signed in to both apps but with
+    different accounts.
+  </summary>
+</histogram>
+
 <histogram name="Signin.ChromeSignoutConfirmationPrompt.{Variant}"
     enum="ChromeSignoutConfirmationChoice" expires_after="2025-02-10">
   <owner>droger@chromium.org</owner>
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index 3e375b2c..628d457 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -6,7 +6,7 @@
         },
         "win": {
             "hash": "125266f5f5cf85ec29dd380485af0bc49a44fe3a",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/4eb5915c04991f3c8db021120a5638c3c0742604/trace_processor_shell.exe"
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/2e577c61f31b9bca076afe1585b1e3b0192deef6/trace_processor_shell.exe"
         },
         "linux_arm": {
             "hash": "53f993fc3201982cd949c5b8de884682bb56de83",
diff --git a/ui/display/types/display_config.h b/ui/display/types/display_config.h
index 14457ee..d2b66e4 100644
--- a/ui/display/types/display_config.h
+++ b/ui/display/types/display_config.h
@@ -21,10 +21,12 @@
 
   std::vector<DisplayGeometry> display_geometries;
   float primary_scale = 1.0f;
+  float font_scale = 1.0f;
 
   bool operator==(const DisplayConfig& other) const {
     return display_geometries == other.display_geometries &&
-           primary_scale == other.primary_scale;
+           primary_scale == other.primary_scale &&
+           font_scale == other.font_scale;
   }
 };
 
diff --git a/ui/file_manager/image_loader/manifest.json b/ui/file_manager/image_loader/manifest.json
index e174325e..da5f48a 100644
--- a/ui/file_manager/image_loader/manifest.json
+++ b/ui/file_manager/image_loader/manifest.json
@@ -2,7 +2,7 @@
   // chrome-extension://pmfjbimdmchhbnneeidfognadeopoehp
   "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDowC9B4+K6zbl4PnALNyOUgra/MPdD8gZ39Fk/IAJWt03qrN7vz1gd/mmrBg0EEIsyLRmUmfyVEfvcIUOZxFqn4A9D2aaRSvNHy9qkasZMBDEql8Nt2iNZm/kGS7sizidDV6Bc/vyLNiH1gKOXBQ42JIxKjgtrmnhGV2giw2vJGwIDAQAB",
   "name": "Image loader",
-  "version": "0.3",
+  "version": "0.3.1",
   "description": "Image loader",
   "incognito" : "split",
   "manifest_version": 3,
diff --git a/ui/file_manager/integration_tests/file_manager/file_display.ts b/ui/file_manager/integration_tests/file_manager/file_display.ts
index bfc96c2..b699940 100644
--- a/ui/file_manager/integration_tests/file_manager/file_display.ts
+++ b/ui/file_manager/integration_tests/file_manager/file_display.ts
@@ -595,10 +595,11 @@
   const directoryTree = await DirectoryTreePageObject.create(appId);
   await directoryTree.selectGroupRootItemByType('drive');
 
-  // The fake Google Drive should be empty.
+  // The fake Google Drive should be empty and read only label should show.
   await remoteCall.waitForFiles(appId, []);
+  await remoteCall.waitForElement(appId, '#read-only-indicator:not([hidden])');
 
-  // Remount Drive. The curent directory should be changed from the Google
+  // Remount Drive. The current directory should be changed from the Google
   // Drive FakeItem to My Drive.
   await sendTestMessage({name: 'mountDrive'});
 
@@ -608,8 +609,11 @@
   // Add an entry to Drive.
   await addEntries(['drive'], [ENTRIES.newlyAdded]);
 
-  // Wait for "My Drive" files to display in the file list.
+  // Wait for "My Drive" files to display in the file list and read only label
+  // should hide.
+  await remoteCall.waitUntilCurrentDirectoryIsChanged(appId, '/My Drive');
   await remoteCall.waitForFiles(appId, [ENTRIES.newlyAdded.getExpectedRow()]);
+  await remoteCall.waitForElement(appId, '#read-only-indicator[hidden]');
 }
 
 /**
diff --git a/ui/gtk/gtk_ui.cc b/ui/gtk/gtk_ui.cc
index 1d41088..d215ab07 100644
--- a/ui/gtk/gtk_ui.cc
+++ b/ui/gtk/gtk_ui.cc
@@ -1021,6 +1021,7 @@
   }
   config.primary_scale =
       std::max(1, gdk_monitor_get_scale_factor(primary)) * font_scale;
+  config.font_scale = font_scale;
   config.display_geometries.reserve(monitors.size());
   for (GdkMonitor* monitor : monitors) {
     GdkRectangle geometry;
diff --git a/ui/ozone/platform/wayland/host/wayland_screen.cc b/ui/ozone/platform/wayland/host/wayland_screen.cc
index 5c275cd6..3cb9400 100644
--- a/ui/ozone/platform/wayland/host/wayland_screen.cc
+++ b/ui/ozone/platform/wayland/host/wayland_screen.cc
@@ -46,6 +46,10 @@
 #include "ui/ozone/platform/wayland/host/org_gnome_mutter_idle_monitor.h"
 #endif
 
+#if BUILDFLAG(IS_LINUX)
+#include "ui/linux/linux_ui.h"
+#endif
+
 namespace ui {
 namespace {
 
@@ -128,6 +132,13 @@
 #if BUILDFLAG(IS_CHROMEOS_LACROS)
   tablet_state_ = connection_->GetTabletState();
 #endif
+
+#if BUILDFLAG(IS_LINUX)
+  if (auto* linux_ui = ui::LinuxUi::instance()) {
+    OnDeviceScaleFactorChanged();
+    display_scale_factor_observer_.Observe(linux_ui);
+  }
+#endif
 }
 
 WaylandScreen::~WaylandScreen() = default;
@@ -595,6 +606,20 @@
   return true;
 }
 
+#if BUILDFLAG(IS_LINUX)
+void WaylandScreen::OnDeviceScaleFactorChanged() {
+  if (const auto* linux_ui = ui::LinuxUi::instance()) {
+    const float new_font_scale = linux_ui->display_config().font_scale;
+    if (new_font_scale != font_scale_) {
+      font_scale_ = new_font_scale;
+      for (auto* window : connection_->window_manager()->GetAllWindows()) {
+        window->OnFontScaleFactorChanged(new_font_scale);
+      }
+    }
+  }
+}
+#endif  // BUILDFLAG(IS_LINUX)
+
 void WaylandScreen::DumpState(std::ostream& out) const {
   out << "WaylandScreen:" << std::endl;
   for (const auto& display : display_list_.displays()) {
diff --git a/ui/ozone/platform/wayland/host/wayland_screen.h b/ui/ozone/platform/wayland/host/wayland_screen.h
index e8212f2..9dc42fc 100644
--- a/ui/ozone/platform/wayland/host/wayland_screen.h
+++ b/ui/ozone/platform/wayland/host/wayland_screen.h
@@ -24,6 +24,12 @@
 #include "ui/ozone/platform/wayland/host/wayland_output.h"
 #include "ui/ozone/public/platform_screen.h"
 
+#if BUILDFLAG(IS_LINUX)
+#include "base/scoped_observation.h"
+#include "ui/linux/device_scale_factor_observer.h"
+#include "ui/linux/linux_ui.h"
+#endif
+
 namespace gfx {
 class Rect;
 }
@@ -37,7 +43,12 @@
 #endif
 
 // A PlatformScreen implementation for Wayland.
-class WaylandScreen : public PlatformScreen {
+class WaylandScreen : public PlatformScreen
+#if BUILDFLAG(IS_LINUX)
+    ,
+                      public DeviceScaleFactorObserver
+#endif
+{
  public:
   explicit WaylandScreen(WaylandConnection* connection);
   WaylandScreen(const WaylandScreen&) = delete;
@@ -85,6 +96,11 @@
   display::TabletState GetTabletState() const override;
 #endif
 
+#if BUILDFLAG(IS_LINUX)
+  // DeviceScaleFactorObserver:
+  void OnDeviceScaleFactorChanged() override;
+#endif
+
   void DumpState(std::ostream& out) const;
 
   // True if the internal representations for output objects is consistent for
@@ -142,6 +158,13 @@
   display::TabletState tablet_state_;
 #endif
 
+#if BUILDFLAG(IS_LINUX)
+  float font_scale_ = 1.0f;
+
+  base::ScopedObservation<ui::LinuxUi, DeviceScaleFactorObserver>
+      display_scale_factor_observer_{this};
+#endif
+
   base::WeakPtrFactory<WaylandScreen> weak_factory_;
 };
 
diff --git a/ui/ozone/platform/wayland/host/wayland_window.cc b/ui/ozone/platform/wayland/host/wayland_window.cc
index 78f377e..9d671da2 100644
--- a/ui/ozone/platform/wayland/host/wayland_window.cc
+++ b/ui/ozone/platform/wayland/host/wayland_window.cc
@@ -17,6 +17,7 @@
 #include "base/containers/contains.h"
 #include "base/functional/bind.h"
 #include "base/memory/scoped_refptr.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/ranges/algorithm.h"
@@ -428,6 +429,11 @@
                                      std::move(subsurfaces_to_overlays)));
 }
 
+// TODO(crbug.com/40856031): Implement ui scaling.
+void WaylandWindow::OnFontScaleFactorChanged(float new_font_scale) {
+  NOTIMPLEMENTED_LOG_ONCE();
+}
+
 void WaylandWindow::DumpState(std::ostream& out) const {
   constexpr auto kWindowTypeToString =
       base::MakeFixedFlatMap<PlatformWindowType, const char*>(
diff --git a/ui/ozone/platform/wayland/host/wayland_window.h b/ui/ozone/platform/wayland/host/wayland_window.h
index aa7a920..b56a010 100644
--- a/ui/ozone/platform/wayland/host/wayland_window.h
+++ b/ui/ozone/platform/wayland/host/wayland_window.h
@@ -417,6 +417,10 @@
   // destroyed.
   void OnChannelDestroyed();
 
+  // Triggers window UI resize and relayout in reaction to system-wide font
+  // scale changes, eg: accessibility's "large text" setting.
+  void OnFontScaleFactorChanged(float new_font_scale);
+
   virtual void DumpState(std::ostream& out) const;
 
 #if DCHECK_IS_ON()
diff --git a/v8 b/v8
index 7264a6e..07f299f 160000
--- a/v8
+++ b/v8
@@ -1 +1 @@
-Subproject commit 7264a6ecc7eb4ccbcef3acf035ab962f987fa4ea
+Subproject commit 07f299fcadd1e0c201ce1f82d0c39d5b43a5e275