diff --git a/.eslintrc.js b/.eslintrc.js
index 2b0dd2c186b..28d26696cb1 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -271,6 +271,7 @@ module.exports = {
             },
             rules: {
                 "react-hooks/rules-of-hooks": ["off"],
+                "@typescript-eslint/no-floating-promises": ["error"],
             },
         },
         {
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index af52a6b77d1..b31ec5e3bf9 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -3,17 +3,21 @@
 /package.json             @element-hq/element-web-team
 /yarn.lock                @element-hq/element-web-team
 
-/src/SecurityManager.ts                           @element-hq/element-crypto-web-reviewers
-/test/SecurityManager-test.ts                     @element-hq/element-crypto-web-reviewers
-/src/async-components/views/dialogs/security/     @element-hq/element-crypto-web-reviewers
-/src/components/views/dialogs/security/           @element-hq/element-crypto-web-reviewers
-/test/components/views/dialogs/security/          @element-hq/element-crypto-web-reviewers
-/src/stores/SetupEncryptionStore.ts               @element-hq/element-crypto-web-reviewers
-/test/stores/SetupEncryptionStore-test.ts         @element-hq/element-crypto-web-reviewers
+/src/SecurityManager.ts                                                 @element-hq/element-crypto-web-reviewers
+/test/SecurityManager-test.ts                                           @element-hq/element-crypto-web-reviewers
+/src/async-components/views/dialogs/security/                           @element-hq/element-crypto-web-reviewers
+/src/components/views/dialogs/security/                                 @element-hq/element-crypto-web-reviewers
+/test/components/views/dialogs/security/                                @element-hq/element-crypto-web-reviewers
+/src/stores/SetupEncryptionStore.ts                                     @element-hq/element-crypto-web-reviewers
+/test/stores/SetupEncryptionStore-test.ts                               @element-hq/element-crypto-web-reviewers
+/src/components/views/settings/tabs/user/EncryptionUserSettingsTab.tsx   @element-hq/element-crypto-web-reviewers
+/src/src/components/views/settings/encryption/                          @element-hq/element-crypto-web-reviewers
+/test/unit-tests/components/views/settings/encryption/                  @element-hq/element-crypto-web-reviewers
+/playwright/e2e/settings/encryption-user-tab/                            @element-hq/element-crypto-web-reviewers
 
 # Ignore translations as those will be updated by GHA for Localazy download
 /src/i18n/strings
 /src/i18n/strings/en_EN.json  @element-hq/element-web-reviewers
 # Ignore the synapse plugin as this is updated by GHA for docker image updating
-/playwright/plugins/homeserver/synapse/index.ts
+/playwright/testcontainers/synapse.ts
 
diff --git a/.github/labels.yml b/.github/labels.yml
index 80c5408c1e3..f8adbe8e53a 100644
--- a/.github/labels.yml
+++ b/.github/labels.yml
@@ -210,6 +210,9 @@
 - name: "X-Upcoming-Release-Blocker"
   description: "This does not affect the current release cycle but will affect the next one"
   color: "e99695"
+- name: "X-Run-All-Tests"
+  description: "When applied to PRs, it'll run the full gamut of end-to-end tests on the PR"
+  color: "ff7979"
 - name: "Z-Actions"
   color: "ededed"
 - name: "Z-Cache-Confusion"
@@ -232,6 +235,15 @@
 - name: "Z-Flaky-Test"
   description: "A test is raising false alarms"
   color: "ededed"
+- name: "Z-Flaky-Test-Chrome"
+  description: "Flaky playwright test in Chrome"
+  color: "ededed"
+- name: "Z-Flaky-Test-Firefox"
+  description: "Flaky playwright test in Firefox"
+  color: "ededed"
+- name: "Z-Flaky-Test-Webkit"
+  description: "Flaky playwright test in Webkit"
+  color: "ededed"
 - name: "Z-Flaky-Jest-Test"
   description: "A Jest test is raising false alarms"
   color: "ededed"
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 381755b6067..21a6b0e7ab8 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -5,6 +5,9 @@ on:
         branches: [develop, master]
     merge_group:
         types: [checks_requested]
+concurrency:
+    group: ${{ github.workflow }}-${{ github.head_ref || github.sha }}
+    cancel-in-progress: ${{ github.event_name == 'pull_request' }}
 # develop pushes and repository_dispatch handled in build_develop.yaml
 env:
     # These must be set for fetchdep.sh to get the right branch
@@ -24,10 +27,17 @@ jobs:
                     - macos-14
                 isDevelop:
                     - ${{ github.event_name == 'push' && github.ref_name == 'develop' }}
+                isPullRequest:
+                    - ${{ github.event_name == 'pull_request' }}
                 # Skip the ubuntu-24.04 build for the develop branch as the dedicated CD build_develop workflow handles that
+                # Skip the non-linux builds for pull requests as Windows is awfully slow, so run in merge queue only
                 exclude:
                     - isDevelop: true
                       image: ubuntu-24.04
+                    - isPullRequest: true
+                      image: windows-2022
+                    - isPullRequest: true
+                      image: macos-14
         runs-on: ${{ matrix.image }}
         defaults:
             run:
@@ -37,14 +47,38 @@ jobs:
 
             - uses: actions/setup-node@v4
               with:
-                  cache: "yarn"
+                  # Disable cache on Windows as it is slower than not caching
+                  # https://github.com/actions/setup-node/issues/975
+                  cache: ${{ runner.os != 'Windows' && 'yarn' || '' }}
                   node-version: "lts/*"
 
             # Workaround for yarn install timeouts, especially on Windows
             - run: yarn config set network-timeout 300000
 
-            - name: Install Dependencies
-              run: "./scripts/layered.sh"
+            - name: Fetch layered build
+              id: layered_build
+              env:
+                  # tell layered.sh to check out the right sha of the JS-SDK & EW, if they were given one
+                  JS_SDK_GITHUB_BASE_REF: ${{ inputs.matrix-js-sdk-sha }}
+              run: |
+                  scripts/layered.sh
+                  JSSDK_SHA=$(git -C matrix-js-sdk rev-parse --short=12 HEAD)
+                  VECTOR_SHA=$(git rev-parse --short=12 HEAD)
+                  echo "VERSION=$VECTOR_SHA--js-$JSSDK_SHA" >> $GITHUB_OUTPUT
+
+            - name: Copy config
+              run: cp element.io/develop/config.json config.json
 
             - name: Build
-              run: "yarn build"
+              env:
+                  CI_PACKAGE: true
+                  VERSION: "${{ steps.layered_build.outputs.VERSION }}"
+              run: |
+                  yarn build
+
+            - name: Upload Artifact
+              uses: actions/upload-artifact@v4
+              with:
+                  name: webapp-${{ matrix.image }}
+                  path: webapp
+                  retention-days: 1
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index daac3bfed85..2b3603549df 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -16,6 +16,11 @@ on:
                 options:
                     - staging.element.io
                     - app.element.io
+            skip-checks:
+                description: Skip CI on the tagged commit
+                required: true
+                default: false
+                type: boolean
 concurrency: ${{ inputs.site || 'staging.element.io' }}
 permissions: {}
 jobs:
@@ -75,6 +80,7 @@ jobs:
 
             - name: Wait for other steps to succeed
               uses: t3chguy/wait-on-check-action@18541021811b56544d90e0f073401c2b99e249d6 # fork
+              if: inputs.skip-checks != true
               with:
                   ref: ${{ github.sha }}
                   running-workflow-name: "Deploy to Cloudflare Pages"
diff --git a/.github/workflows/dockerhub.yaml b/.github/workflows/dockerhub.yaml
index 8dae6cf5ab2..6cf8b44876e 100644
--- a/.github/workflows/dockerhub.yaml
+++ b/.github/workflows/dockerhub.yaml
@@ -24,10 +24,10 @@ jobs:
               uses: sigstore/cosign-installer@dc72c7d5c4d10cd6bcb8cf6e3fd625a9e5e537da # v3
 
             - name: Set up QEMU
-              uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf # v3
+              uses: docker/setup-qemu-action@53851d14592bedcffcf25ea515637cff71ef929a # v3
 
             - name: Set up Docker Buildx
-              uses: docker/setup-buildx-action@c47758b77c9736f4b2ef4073d4d51994fabfe349 # v3
+              uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3
               with:
                   install: true
 
@@ -51,7 +51,7 @@ jobs:
 
             - name: Build and push
               id: build-and-push
-              uses: docker/build-push-action@48aba3b46d1b1fec4febb7c5d0c644b249a11355 # v6
+              uses: docker/build-push-action@b32b51a8eda65d6793cd0494a773d4f6bcef32dc # v6
               with:
                   context: .
                   push: true
diff --git a/.github/workflows/end-to-end-tests.yaml b/.github/workflows/end-to-end-tests.yaml
index 5a75040866b..bd7872ee120 100644
--- a/.github/workflows/end-to-end-tests.yaml
+++ b/.github/workflows/end-to-end-tests.yaml
@@ -3,6 +3,9 @@
 # as an artifact and run end-to-end tests.
 name: End to End Tests
 on:
+    # CRON to run all Projects at 6am UTC
+    schedule:
+        - cron: "0 6 * * *"
     pull_request: {}
     merge_group:
         types: [checks_requested]
@@ -32,6 +35,8 @@ concurrency:
 env:
     # fetchdep.sh needs to know our PR number
     PR_NUMBER: ${{ github.event.pull_request.number }}
+    # Use 6 runners in the default case, but 4 when running on a schedule where we run all 5 projects (20 runners total)
+    NUM_RUNNERS: ${{ github.event_name == 'schedule' && 4 || 6 }}
 
 permissions: {} # No permissions required
 
@@ -40,6 +45,9 @@ jobs:
         name: "Build Element-Web"
         runs-on: ubuntu-24.04
         if: inputs.skip != true
+        outputs:
+            num-runners: ${{ env.NUM_RUNNERS }}
+            runners-matrix: ${{ steps.runner-vars.outputs.matrix }}
         steps:
             - name: Checkout code
               uses: actions/checkout@v4
@@ -79,8 +87,17 @@ jobs:
                   path: webapp
                   retention-days: 1
 
+            - name: Calculate runner variables
+              id: runner-vars
+              uses: actions/github-script@v7
+              with:
+                  script: |
+                      const numRunners = parseInt(process.env.NUM_RUNNERS, 10);
+                      const matrix = Array.from({ length: numRunners }, (_, i) => i + 1);
+                      core.setOutput("matrix", JSON.stringify(matrix));
+
     playwright:
-        name: "Run Tests ${{ matrix.runner }}/${{ strategy.job-total }}"
+        name: "Run Tests [${{ matrix.project }}] ${{ matrix.runner }}/${{ needs.build.outputs.num-runners }}"
         needs: build
         if: inputs.skip != true
         runs-on: ubuntu-24.04
@@ -92,7 +109,25 @@ jobs:
             fail-fast: false
             matrix:
                 # Run multiple instances in parallel to speed up the tests
-                runner: [1, 2, 3, 4, 5, 6]
+                runner: ${{ fromJSON(needs.build.outputs.runners-matrix) }}
+                project:
+                    - Chrome
+                    - Firefox
+                    - WebKit
+                    - Dendrite
+                    - Pinecone
+                runAllTests:
+                    - ${{ github.event_name == 'schedule' || contains(github.event.pull_request.labels.*.name, 'X-Run-All-Tests') }}
+                # Skip the Firefox & Safari runs unless this was a cron trigger or PR has X-Run-All-Tests label
+                exclude:
+                    - runAllTests: false
+                      project: Firefox
+                    - runAllTests: false
+                      project: WebKit
+                    - runAllTests: false
+                      project: Dendrite
+                    - runAllTests: false
+                      project: Pinecone
         steps:
             - uses: actions/checkout@v4
               with:
@@ -124,24 +159,30 @@ jobs:
               with:
                   path: |
                       ~/.cache/ms-playwright
-                  key: ${{ runner.os }}-playwright-${{ steps.playwright.outputs.version }}-chromium
+                  key: ${{ runner.os }}-playwright-${{ steps.playwright.outputs.version }}
 
-            - name: Install Playwright browser
+            - name: Install Playwright browsers
               if: steps.playwright-cache.outputs.cache-hit != 'true'
-              run: yarn playwright install --with-deps --no-shell chromium
+              run: yarn playwright install --with-deps --no-shell
+
+            - name: Install system dependencies for WebKit
+              # Some WebKit dependencies seem to lay outside the cache and will need to be installed separately
+              if: matrix.project == 'WebKit' && steps.playwright-cache.outputs.cache-hit == 'true'
+              run: yarn playwright install-deps webkit
 
             # We skip tests tagged with @mergequeue when running on PRs, but run them in MQ and everywhere else
             - name: Run Playwright tests
               run: |
                   yarn playwright test \
-                      --shard "${{ matrix.runner }}/${{ strategy.job-total }}" \
-                      ${{ github.event_name == 'pull_request' && '--grep-invert @mergequeue' || '' }}
+                      --shard "${{ matrix.runner }}/${{ needs.build.outputs.num-runners }}" \
+                      --project="${{ matrix.project }}" \
+                      ${{ (github.event_name == 'pull_request' && matrix.runAllTests == false ) && '--grep-invert @mergequeue' || '' }}
 
             - name: Upload blob report to GitHub Actions Artifacts
               if: always()
               uses: actions/upload-artifact@v4
               with:
-                  name: all-blob-reports-${{ matrix.runner }}
+                  name: all-blob-reports-${{ matrix.project }}-${{ matrix.runner }}
                   path: blob-report
                   retention-days: 1
 
diff --git a/.github/workflows/localazy_download.yaml b/.github/workflows/localazy_download.yaml
index 435b8154ba5..b8e948d45e5 100644
--- a/.github/workflows/localazy_download.yaml
+++ b/.github/workflows/localazy_download.yaml
@@ -3,7 +3,8 @@ on:
     workflow_dispatch: {}
     schedule:
         - cron: "0 6 * * 1,3,5" # Every Monday, Wednesday and Friday at 6am UTC
-permissions: {} # We use ELEMENT_BOT_TOKEN instead
+permissions:
+    pull-requests: write # needed to auto-approve PRs
 jobs:
     download:
         uses: matrix-org/matrix-web-i18n/.github/workflows/localazy_download.yaml@main
diff --git a/.github/workflows/netlify.yaml b/.github/workflows/netlify.yaml
index 63bac7d33f5..cd03ca5140f 100644
--- a/.github/workflows/netlify.yaml
+++ b/.github/workflows/netlify.yaml
@@ -3,7 +3,7 @@
 name: Upload Preview Build to Netlify
 on:
     workflow_run:
-        workflows: ["End to End Tests"]
+        workflows: ["Build"]
         types:
             - completed
 jobs:
@@ -32,7 +32,7 @@ jobs:
               with:
                   github-token: ${{ secrets.GITHUB_TOKEN }}
                   run-id: ${{ github.event.workflow_run.id }}
-                  name: webapp
+                  name: webapp-ubuntu-24.04
                   path: webapp
 
             - name: 📤 Deploy to Netlify
diff --git a/.github/workflows/playwright-image-updates.yaml b/.github/workflows/playwright-image-updates.yaml
index 1613b42dfb7..e5e2f739c09 100644
--- a/.github/workflows/playwright-image-updates.yaml
+++ b/.github/workflows/playwright-image-updates.yaml
@@ -17,13 +17,13 @@ jobs:
                   docker pull "$IMAGE"
                   INSPECT=$(docker inspect --format='{{index .RepoDigests 0}}' "$IMAGE")
                   DIGEST=${INSPECT#*@}
-                  sed -i "s/const DOCKER_TAG.*/const DOCKER_TAG = \"develop@$DIGEST\";/" playwright/plugins/homeserver/synapse/index.ts
+                  sed -i "s/const TAG.*/const TAG = \"develop@$DIGEST\";/" playwright/testcontainers/synapse.ts
               env:
                   IMAGE: ghcr.io/element-hq/synapse:develop
 
             - name: Create Pull Request
               id: cpr
-              uses: peter-evans/create-pull-request@5e914681df9dc83aa4e4905692ca88beb2f9e91f # v7
+              uses: peter-evans/create-pull-request@67ccf781d68cd99b580ae25a5c18a1cc84ffff1f # v7
               with:
                   token: ${{ secrets.ELEMENT_BOT_TOKEN }}
                   branch: actions/playwright-image-updates
diff --git a/.github/workflows/static_analysis.yaml b/.github/workflows/static_analysis.yaml
index b7c02c3f2e9..ee731b3ac38 100644
--- a/.github/workflows/static_analysis.yaml
+++ b/.github/workflows/static_analysis.yaml
@@ -132,9 +132,3 @@ jobs:
 
             - name: Run linter
               run: "yarn run lint:knip"
-
-            - name: Install Deps
-              run: "scripts/layered.sh"
-
-            - name: Dead Code Analysis
-              run: "yarn run analyse:unused-exports"
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 35803a60f1a..dfb92e8ba02 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -104,7 +104,7 @@ jobs:
 
             - name: Skip SonarCloud in merge queue
               if: github.event_name == 'merge_group' || inputs.disable_coverage == 'true'
-              uses: guibranco/github-status-action-v2@d469d49426f5a7b8a1fbcac20ad274d3e4892321
+              uses: guibranco/github-status-action-v2@56cd38caf0615dd03f49d42ed301f1469911ac61
               with:
                   authToken: ${{ secrets.GITHUB_TOKEN }}
                   state: success
diff --git a/.github/workflows/triage-stale-flaky-tests.yml b/.github/workflows/triage-stale-flaky-tests.yml
index 90ba7c40f75..3d3bcb0b13c 100644
--- a/.github/workflows/triage-stale-flaky-tests.yml
+++ b/.github/workflows/triage-stale-flaky-tests.yml
@@ -1,5 +1,6 @@
 name: Close stale flaky issues
 on:
+    workflow_dispatch: {}
     schedule:
         - cron: "30 1 * * *"
 permissions: {}
@@ -17,3 +18,4 @@ jobs:
                   days-before-close: 0
                   close-issue-message: "This flaky test issue has not been updated in 14 days. It is being closed as presumed resolved."
                   exempt-issue-labels: "Z-Flaky-Test-Disabled"
+                  operations-per-run: 100
diff --git a/.github/workflows/update-jitsi.yml b/.github/workflows/update-jitsi.yml
index bf0414e73a4..a3abcb002f5 100644
--- a/.github/workflows/update-jitsi.yml
+++ b/.github/workflows/update-jitsi.yml
@@ -23,7 +23,7 @@ jobs:
               run: "yarn update:jitsi"
 
             - name: Create Pull Request
-              uses: peter-evans/create-pull-request@5e914681df9dc83aa4e4905692ca88beb2f9e91f # v7
+              uses: peter-evans/create-pull-request@67ccf781d68cd99b580ae25a5c18a1cc84ffff1f # v7
               with:
                   token: ${{ secrets.ELEMENT_BOT_TOKEN }}
                   branch: actions/jitsi-update
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 17d5f5f13e5..5411b67428c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,31 @@
+Changes in [1.11.90](https://github.com/element-hq/element-web/releases/tag/v1.11.90) (2025-01-14)
+==================================================================================================
+## ✨ Features
+
+* Docker: run as non-root ([#28849](https://github.com/element-hq/element-web/pull/28849)). Contributed by @richvdh.
+* Docker: allow configuration of HTTP listen port via env var ([#28840](https://github.com/element-hq/element-web/pull/28840)). Contributed by @richvdh.
+* Update matrix-wysiwyg to consume WASM asset ([#28838](https://github.com/element-hq/element-web/pull/28838)). Contributed by @t3chguy.
+* OIDC settings tweaks ([#28787](https://github.com/element-hq/element-web/pull/28787)). Contributed by @t3chguy.
+* Delabs native OIDC support ([#28615](https://github.com/element-hq/element-web/pull/28615)). Contributed by @t3chguy.
+* Move room header info button to right-most position ([#28754](https://github.com/element-hq/element-web/pull/28754)). Contributed by @t3chguy.
+* Enable key backup by default ([#28691](https://github.com/element-hq/element-web/pull/28691)). Contributed by @dbkr.
+
+## 🐛 Bug Fixes
+
+* Fix building the automations mermaid diagram ([#28881](https://github.com/element-hq/element-web/pull/28881)). Contributed by @dbkr.
+* Playwright: wait for the network listener on the postgres db ([#28808](https://github.com/element-hq/element-web/pull/28808)). Contributed by @dbkr.
+
+
+Changes in [1.11.89](https://github.com/element-hq/element-web/releases/tag/v1.11.89) (2024-12-18)
+==================================================================================================
+This is a patch release to fix a bug which could prevent loading stored crypto state from storage, and also to fix URL previews when switching back to a room.
+
+## 🐛 Bug Fixes
+
+* Upgrade matrix-sdk-crypto-wasm to 1.11.0 (https://github.com/matrix-org/matrix-js-sdk/pull/4593)
+* Fix url preview display ([#28766](https://github.com/element-hq/element-web/pull/28766)).
+
+
 Changes in [1.11.88](https://github.com/element-hq/element-web/releases/tag/v1.11.88) (2024-12-17)
 ==================================================================================================
 ## ✨ Features
diff --git a/Dockerfile b/Dockerfile
index 908c05520cc..93d7c676d9f 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,20 +1,17 @@
 # Builder
-FROM --platform=$BUILDPLATFORM node:22-bullseye as builder
+FROM --platform=$BUILDPLATFORM node:22-bullseye AS builder
 
 # Support custom branch of the js-sdk. This also helps us build images of element-web develop.
 ARG USE_CUSTOM_SDKS=false
 ARG JS_SDK_REPO="https://github.com/matrix-org/matrix-js-sdk.git"
 ARG JS_SDK_BRANCH="master"
 
-RUN apt-get update && apt-get install -y git dos2unix
-
 WORKDIR /src
 
 COPY . /src
-RUN dos2unix /src/scripts/docker-link-repos.sh && bash /src/scripts/docker-link-repos.sh
+RUN /src/scripts/docker-link-repos.sh
 RUN yarn --network-timeout=200000 install
-
-RUN dos2unix /src/scripts/docker-package.sh /src/scripts/get-version-from-git.sh /src/scripts/normalize-version.sh && bash /src/scripts/docker-package.sh
+RUN /src/scripts/docker-package.sh
 
 # Copy the config now so that we don't create another layer in the app image
 RUN cp /src/config.sample.json /src/webapp/config.json
@@ -24,8 +21,22 @@ FROM nginx:alpine-slim
 
 COPY --from=builder /src/webapp /app
 
-# Override default nginx config
-COPY /nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf
+# Override default nginx config. Templates in `/etc/nginx/templates` are passed
+# through `envsubst` by the nginx docker image entry point.
+COPY /docker/nginx-templates/* /etc/nginx/templates/
+
+# Tell nginx to put its pidfile elsewhere, so it can run as non-root
+RUN sed -i -e 's,/var/run/nginx.pid,/tmp/nginx.pid,' /etc/nginx/nginx.conf
+
+# nginx user must own the cache and etc directory to write cache and tweak the nginx config
+RUN chown -R nginx:0 /var/cache/nginx /etc/nginx
+RUN chmod -R g+w /var/cache/nginx /etc/nginx
 
 RUN rm -rf /usr/share/nginx/html \
   && ln -s /app /usr/share/nginx/html
+
+# Run as nginx user by default
+USER nginx
+
+# HTTP listen port
+ENV ELEMENT_WEB_PORT=80
diff --git a/LICENSE-COMMERCIAL b/LICENSE-COMMERCIAL
new file mode 100644
index 00000000000..173e03e0c03
--- /dev/null
+++ b/LICENSE-COMMERCIAL
@@ -0,0 +1,6 @@
+Licensees holding a valid commercial license with Element may use this
+software in accordance with the terms contained in a written agreement
+between you and Element.
+
+To purchase a commercial license please contact our sales team at
+licensing@element.io
diff --git a/README.md b/README.md
index 87e451c9ffa..5924f934981 100644
--- a/README.md
+++ b/README.md
@@ -311,3 +311,18 @@ For a developer guide, see the [translating dev doc](docs/translating-dev.md).
 Issues are triaged by community members and the Web App Team, following the [triage process](https://github.com/element-hq/element-meta/wiki/Triage-process).
 
 We use [issue labels](https://github.com/element-hq/element-meta/wiki/Issue-labelling) to sort all incoming issues.
+
+## Copyright & License
+
+Copyright (c) 2014-2017 OpenMarket Ltd
+Copyright (c) 2017 Vector Creations Ltd
+Copyright (c) 2017-2025 New Vector Ltd
+
+This software is multi licensed by New Vector Ltd (Element). It can be used either:
+
+(1) for free under the terms of the GNU Affero General Public License (as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version); OR
+
+(2) for free under the terms of the GNU General Public License (as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version); OR
+
+(3) under the terms of a paid-for Element Commercial License agreement between you and Element (the terms of which may vary depending on what you and Element have agreed to).
+Unless required by applicable law or agreed to in writing, software distributed under the Licenses is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the Licenses for the specific language governing permissions and limitations under the Licenses.
diff --git a/__mocks__/maplibre-gl.js b/__mocks__/maplibre-gl.js
index c410e4f24c5..cac71db330b 100644
--- a/__mocks__/maplibre-gl.js
+++ b/__mocks__/maplibre-gl.js
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/__mocks__/workerFactoryMock.js b/__mocks__/workerFactoryMock.js
index 956f5b04acf..a6f04ce0861 100644
--- a/__mocks__/workerFactoryMock.js
+++ b/__mocks__/workerFactoryMock.js
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/contribute.json b/contribute.json
index 5c7fc79d398..fdd84bd8a04 100644
--- a/contribute.json
+++ b/contribute.json
@@ -3,7 +3,7 @@
     "description": "A glossy Matrix collaboration client for the web.",
     "repository": {
         "url": "https://github.com/element-hq/element-web",
-        "license": "AGPL-3.0-only OR GPL-3.0-only"
+        "license": "AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial"
     },
     "bugs": {
         "list": "https://github.com/element-hq/element-web/issues",
diff --git a/nginx/conf.d/default.conf b/docker/nginx-templates/default.conf.template
similarity index 90%
rename from nginx/conf.d/default.conf
rename to docker/nginx-templates/default.conf.template
index 0ae57903744..06f33e08dd2 100644
--- a/nginx/conf.d/default.conf
+++ b/docker/nginx-templates/default.conf.template
@@ -1,6 +1,6 @@
 server {
-    listen       80;
-    listen  [::]:80;
+    listen       ${ELEMENT_WEB_PORT};
+    listen  [::]:${ELEMENT_WEB_PORT};
     server_name  localhost;
 
     root   /usr/share/nginx/html;
diff --git a/docs/install.md b/docs/install.md
index 1c182cdd34c..f6bd98611cb 100644
--- a/docs/install.md
+++ b/docs/install.md
@@ -60,6 +60,22 @@ would be:
 docker run --rm -p 127.0.0.1:80:80 -v /etc/element-web/config.json:/app/config.json vectorim/element-web
 ```
 
+The Docker image is configured to run as an unprivileged (non-root) user by
+default. This should be fine on modern Docker runtimes, but binding to port 80
+on other runtimes may require root privileges. To resolve this, either run the
+image as root (`docker run --user 0`) or, better, change the port that nginx
+listens on via the `ELEMENT_WEB_PORT` environment variable.
+
+The behaviour of the docker image can be customised via the following
+environment variables:
+
+- `ELEMENT_WEB_PORT`
+
+    The port to listen on (within the docker container) for HTTP
+    traffic. Defaults to `80`.
+
+### Building the docker image
+
 To build the image yourself:
 
 ```bash
diff --git a/docs/oidc.md b/docs/oidc.md
index 34387f92413..bf10792d0ca 100644
--- a/docs/oidc.md
+++ b/docs/oidc.md
@@ -1,29 +1,9 @@
 # OIDC and delegated authentication
 
-## Compatibility/OIDC-aware mode
-
-[MSC2965: OIDC provider discovery](https://github.com/matrix-org/matrix-spec-proposals/pull/2965)
-[MSC3824: OIDC aware clients](https://github.com/matrix-org/matrix-spec-proposals/pull/3824)
-This mode uses an SSO flow to gain a `loginToken` from the authentication provider, then continues with SSO login.
-Element Web uses [MSC2965: OIDC provider discovery](https://github.com/matrix-org/matrix-spec-proposals/pull/2965) to discover the configured provider.
-Wherever valid MSC2965 configuration is discovered, OIDC-aware login flow will be the only option offered.
-
-## (🧪Experimental) OIDC-native flow
-
-Can be enabled by a config-level-only setting in `config.json`
-
-```json
-{
-    "features": {
-        "feature_oidc_native_flow": true
-    }
-}
-```
-
 See https://areweoidcyet.com/client-implementation-guide/ for implementation details.
 
 Element Web uses [MSC2965: OIDC provider discovery](https://github.com/matrix-org/matrix-spec-proposals/pull/2965) to discover the configured provider.
-Where OIDC native login flow is enabled and valid MSC2965 configuration is discovered, OIDC native login flow will be the only login option offered.
+Where a valid MSC2965 configuration is discovered, OIDC native login flow will be the only login option offered.
 Element Web will attempt to [dynamically register](https://openid.net/specs/openid-connect-registration-1_0.html) with the configured OP.
 Then, authentication will be completed [as described here](https://areweoidcyet.com/client-implementation-guide/).
 
diff --git a/docs/playwright.md b/docs/playwright.md
index 4af3194220a..e03d1f5f8da 100644
--- a/docs/playwright.md
+++ b/docs/playwright.md
@@ -23,21 +23,19 @@ element-web project is fine: leave it running it a different terminal as you wou
 when developing. Alternatively if you followed the development set up from element-web then
 Playwright will be capable of running the webserver on its own if it isn't already running.
 
-The tests use Docker to launch Homeserver (Synapse or Dendrite) instances to test against, so you'll also
-need to have Docker installed and working in order to run the Playwright tests.
+The tests use [testcontainers](https://node.testcontainers.org/) to launch Homeserver (Synapse or Dendrite)
+instances to test against, so you'll also need to one of the
+[supported container runtimes](#supporter-container-runtimes)
+installed and working in order to run the Playwright tests.
 
 There are a few different ways to run the tests yourself. The simplest is to run:
 
 ```shell
-docker pull ghcr.io/element-hq/synapse:develop
 yarn run test:playwright
 ```
 
 This will run the Playwright tests once, non-interactively.
 
-Note: you don't need to run the `docker pull` command every time, but you should
-do it regularly to ensure you are running against an up-to-date Synapse.
-
 You can also run individual tests this way too, as you'd expect:
 
 ```shell
@@ -53,41 +51,36 @@ yarn run test:playwright:open --headed --debug
 
 See more command line options at <https://playwright.dev/docs/test-cli>.
 
-### Running with Rust cryptography
+## Projects
 
-`matrix-js-sdk` is currently in the
-[process](https://github.com/vector-im/element-web/issues/21972) of being
-updated to replace its end-to-end encryption implementation to use the [Matrix
-Rust SDK](https://github.com/matrix-org/matrix-rust-sdk). This is not currently
-enabled by default, but it is possible to have Playwright configure Element to use
-the Rust crypto implementation by passing `--project="Rust Crypto"` or using
-the top left options in open mode.
+By default, Playwright will run all "Projects", this means tests will run against Chrome, Firefox and "Safari" (Webkit).
+We only run tests against Chrome in pull request CI, but all projects in the merge queue.
+Some tests are excluded from running on certain browsers due to incompatibilities in the test harness.
 
 ## How the Tests Work
 
-Everything Playwright-related lives in the `playwright/` subdirectory of react-sdk
+Everything Playwright-related lives in the `playwright/` subdirectory
 as is typical for Playwright tests. Likewise, tests live in `playwright/e2e`.
 
-`playwright/plugins/homeservers` contains Playwright plugins that starts instances
-of Synapse/Dendrite in Docker containers. These servers are what Element-web runs
-against in the tests.
+`playwright/testcontainers` contains the testcontainers which start instances
+of Synapse/Dendrite. These servers are what Element-web runs against in the tests.
 
 Synapse can be launched with different configurations in order to test element
-in different configurations. `playwright/plugins/homeserver/synapse/templates`
-contains template configuration files for each different configuration.
-
-Each test suite can then launch whatever Synapse instances it needs in whatever
-configurations.
+in different configurations. You can specify `synapseConfig` as such:
 
-Note that although tests should stop the Homeserver instances after running and the
-plugin also stop any remaining instances after all tests have run, it is possible
-to be left with some stray containers if, for example, you terminate a test such
-that the `after()` does not run and also exit Playwright uncleanly. All the containers
-it starts are prefixed, so they are easy to recognise. They can be removed safely.
+```typescript
+test.use({
+    synapseConfig: {
+        // The config options to pass to the Synapse instance
+    },
+});
+```
 
-After each test run, logs from the Synapse instances are saved in `playwright/logs/synapse`
-with each instance in a separate directory named after its ID. These logs are removed
-at the start of each test run.
+The appropriate homeserver will be launched by the Playwright worker and reused for all tests which match the worker configuration.
+Due to homeservers being reused between tests, please use unique names for any rooms put into the room directory as
+they may be visible from other tests, the suggested approach is to use `testInfo.testId` within the name or lodash's uniqueId.
+We remove public rooms from the room directory between tests but deleting users doesn't have a homeserver agnostic solution.
+The logs from testcontainers will be attached to any reports output from Playwright.
 
 ## Writing Tests
 
@@ -117,25 +110,6 @@ Homeserver instances should be reasonably cheap to start (you may see the first
 while as it pulls the Docker image).
 You do not need to explicitly clean up the instance as it will be cleaned up by the fixture.
 
-### Synapse Config Templates
-
-When a Synapse instance is started, it's given a config generated from one of the config
-templates in `playwright/plugins/homeserver/synapse/templates`. There are a couple of special files
-in these templates:
-
-- `homeserver.yaml`:
-  Template substitution happens in this file. Template variables are:
-    - `REGISTRATION_SECRET`: The secret used to register users via the REST API.
-    - `MACAROON_SECRET_KEY`: Generated each time for security
-    - `FORM_SECRET`: Generated each time for security
-    - `PUBLIC_BASEURL`: The localhost url + port combination the synapse is accessible at
-- `localhost.signing.key`: A signing key is auto-generated and saved to this file.
-  Config templates should not contain a signing key and instead assume that one will exist
-  in this file.
-
-All other files in the template are copied recursively to `/data/`, so the file `foo.html`
-in a template can be referenced in the config as `/data/foo.html`.
-
 ### Logging In
 
 We again heavily leverage the magic of [Playwright fixtures](https://playwright.dev/docs/test-fixtures).
@@ -224,3 +198,20 @@ We use test tags to categorise tests for running subsets more efficiently.
 
 - `@mergequeue`: Tests that are slow or flaky and cover areas of the app we update seldom, should not be run on every PR commit but will be run in the Merge Queue.
 - `@screenshot`: Tests that use `toMatchScreenshot` to speed up a run of `test:playwright:screenshots`. A test with this tag must not also have the `@mergequeue` tag as this would cause false positives in the stale screenshot detection.
+- `@no-$project`: Tests which are unsupported in $Project. These tests will be skipped when running in $Project.
+
+Anything testing Matrix media will need to have `@no-firefox` and `@no-webkit` as those rely on the service worker which
+has to be disabled in Playwright on Firefox & Webkit to retain routing functionality.
+Anything testing VoIP/microphone will need to have `@no-webkit` as fake microphone functionality is not available
+there at this time.
+
+If you wish to run all tests in a PR, you can give it the label `X-Run-All-Tests`.
+
+## Supporter container runtimes
+
+We use testcontainers to spin up various instances of Synapse, Matrix Authentication Service, and more.
+It supports Docker out of the box but also has support for Podman, Colima, Rancher, you just need to follow some instructions to achieve it:
+https://node.testcontainers.org/supported-container-runtimes/
+
+If you are running under Colima, you may need to set the environment variable `TMPDIR` to `/tmp/colima` or a path
+within `$HOME` to allow bind mounting temporary directories into the Docker containers.
diff --git a/jest.config.ts b/jest.config.ts
index 326f2040d97..b70b21bc979 100644
--- a/jest.config.ts
+++ b/jest.config.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -14,6 +14,8 @@ const config: Config = {
     testEnvironment: "jsdom",
     testEnvironmentOptions: {
         url: "http://localhost/",
+        // This is needed to be able to load dual CJS/ESM WASM packages e.g. rust crypto & matrix-wywiwyg
+        customExportConditions: ["browser", "node"],
     },
     testMatch: ["<rootDir>/test/**/*-test.[tj]s?(x)"],
     globalSetup: "<rootDir>/test/globalSetup.ts",
diff --git a/knip.ts b/knip.ts
index 247f9d97894..17ad531332a 100644
--- a/knip.ts
+++ b/knip.ts
@@ -10,13 +10,13 @@ export default {
         "playwright/**",
         "test/**",
         "res/decoder-ring/**",
-    ],
-    project: ["**/*.{js,ts,jsx,tsx}"],
-    ignore: [
-        "docs/**",
         "res/jitsi_external_api.min.js",
+        "docs/**",
         // Used by jest
         "__mocks__/maplibre-gl.js",
+    ],
+    project: ["**/*.{js,ts,jsx,tsx}"],
+    ignore: [
         // Keep for now
         "src/hooks/useLocalStorageState.ts",
         "src/components/views/elements/InfoTooltip.tsx",
@@ -37,13 +37,8 @@ export default {
         // False positive
         "sw.js",
         // Used by webpack
-        "buffer",
         "process",
         "util",
-        // Used by workflows
-        "ts-prune",
-        // Required due to bug in bloom-filters https://github.com/Callidon/bloom-filters/issues/75
-        "@types/seedrandom",
     ],
     ignoreBinaries: [
         // Used in scripts & workflows
diff --git a/module_system/BuildConfig.ts b/module_system/BuildConfig.ts
index 8cf83dea8b4..cfb805840d7 100644
--- a/module_system/BuildConfig.ts
+++ b/module_system/BuildConfig.ts
@@ -1,7 +1,7 @@
 /*
 Copyright 2022-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/module_system/installer.ts b/module_system/installer.ts
index e681bb1673f..4e677b7d674 100644
--- a/module_system/installer.ts
+++ b/module_system/installer.ts
@@ -1,7 +1,7 @@
 /*
 Copyright 2022-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/module_system/scripts/install.ts b/module_system/scripts/install.ts
index 57a2f9fce3c..0b6d2e1c29f 100644
--- a/module_system/scripts/install.ts
+++ b/module_system/scripts/install.ts
@@ -1,7 +1,7 @@
 /*
 Copyright 2022-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/package.json b/package.json
index 6d082f95865..d79de6e081a 100644
--- a/package.json
+++ b/package.json
@@ -1,13 +1,13 @@
 {
     "name": "element-web",
-    "version": "1.11.88",
+    "version": "1.11.90",
     "description": "A feature-rich client for Matrix.org",
     "author": "New Vector Ltd.",
     "repository": {
         "type": "git",
         "url": "https://github.com/element-hq/element-web"
     },
-    "license": "AGPL-3.0-only OR GPL-3.0-only",
+    "license": "SEE LICENSE IN README.md",
     "files": [
         "lib",
         "res",
@@ -64,16 +64,17 @@
         "test:playwright:open": "yarn test:playwright --ui",
         "test:playwright:screenshots": "yarn test:playwright:screenshots:build && yarn test:playwright:screenshots:run",
         "test:playwright:screenshots:build": "docker build playwright -t element-web-playwright",
-        "test:playwright:screenshots:run": "docker run --rm --network host -e BASE_URL -e CI -v $(pwd):/work/ -v $(node -e 'console.log(require(`path`).dirname(require.resolve(`matrix-js-sdk/package.json`)))'):/work/node_modules/matrix-js-sdk -v /var/run/docker.sock:/var/run/docker.sock -v /tmp/:/tmp/ -it element-web-playwright --grep @screenshot",
+        "test:playwright:screenshots:run": "docker run --rm --network host -e BASE_URL -e CI -v $(pwd):/work/ -v $(node -e 'console.log(require(`path`).dirname(require.resolve(`matrix-js-sdk/package.json`)))'):/work/node_modules/matrix-js-sdk -v /var/run/docker.sock:/var/run/docker.sock -v /tmp/:/tmp/ -it element-web-playwright --grep @screenshot --project=Chrome",
         "coverage": "yarn test --coverage",
-        "analyse:unused-exports": "ts-node ./scripts/analyse_unused_exports.ts",
         "analyse:webpack-bundles": "webpack-bundle-analyzer webpack-stats.json webapp",
         "update:jitsi": "curl -s https://meet.element.io/libs/external_api.min.js > ./res/jitsi_external_api.min.js"
     },
     "resolutions": {
+        "@types/react": "18.3.18",
+        "@types/react-dom": "18.3.5",
         "oidc-client-ts": "3.1.0",
         "jwt-decode": "4.0.0",
-        "caniuse-lite": "1.0.30001684",
+        "caniuse-lite": "1.0.30001690",
         "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0",
         "wrap-ansi": "npm:wrap-ansi@^7.0.0"
     },
@@ -87,9 +88,11 @@
         "@matrix-org/react-sdk-module-api": "^2.4.0",
         "@matrix-org/spec": "^1.7.0",
         "@sentry/browser": "^8.0.0",
-        "@vector-im/compound-design-tokens": "^2.0.1",
+        "@types/png-chunks-extract": "^1.0.2",
+        "@types/react-virtualized": "^9.21.30",
+        "@vector-im/compound-design-tokens": "^2.1.0",
         "@vector-im/compound-web": "^7.5.0",
-        "@vector-im/matrix-wysiwyg": "2.37.13",
+        "@vector-im/matrix-wysiwyg": "2.38.0",
         "@zxcvbn-ts/core": "^3.0.4",
         "@zxcvbn-ts/language-common": "^3.0.4",
         "@zxcvbn-ts/language-en": "^3.0.2",
@@ -121,7 +124,7 @@
         "linkify-string": "4.2.0",
         "linkifyjs": "4.2.0",
         "lodash": "^4.17.21",
-        "maplibre-gl": "^4.0.0",
+        "maplibre-gl": "^5.0.0",
         "matrix-encrypt-attachment": "^1.0.3",
         "matrix-events-sdk": "0.0.1",
         "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#develop",
@@ -134,16 +137,17 @@
         "png-chunks-extract": "^1.0.0",
         "posthog-js": "1.157.2",
         "qrcode": "1.5.4",
-        "re-resizable": "6.10.1",
+        "re-resizable": "6.10.3",
         "react": "^18.3.1",
         "react-beautiful-dnd": "^13.1.0",
         "react-blurhash": "^0.3.0",
         "react-dom": "^18.3.1",
         "react-focus-lock": "^2.5.1",
         "react-transition-group": "^4.4.1",
+        "react-virtualized": "^9.22.5",
         "rfc4648": "^1.4.0",
         "sanitize-filename": "^1.6.3",
-        "sanitize-html": "2.13.1",
+        "sanitize-html": "2.14.0",
         "tar-js": "^0.3.0",
         "temporal-polyfill": "^0.2.5",
         "ua-parser-js": "^1.0.2",
@@ -177,6 +181,7 @@
         "@sentry/webpack-plugin": "^2.7.1",
         "@stylistic/eslint-plugin": "^2.9.0",
         "@svgr/webpack": "^8.0.0",
+        "@testcontainers/postgresql": "^10.16.0",
         "@testing-library/dom": "^10.4.0",
         "@testing-library/jest-dom": "^6.4.8",
         "@testing-library/react": "^16.0.0",
@@ -188,7 +193,6 @@
         "@types/escape-html": "^1.0.1",
         "@types/express": "^5.0.0",
         "@types/file-saver": "^2.0.3",
-        "@types/fs-extra": "^11.0.0",
         "@types/glob-to-regexp": "^0.4.1",
         "@types/jest": "29.5.12",
         "@types/jitsi-meet": "^2.0.2",
@@ -201,17 +205,17 @@
         "@types/node-fetch": "^2.6.2",
         "@types/pako": "^2.0.0",
         "@types/qrcode": "^1.3.5",
-        "@types/react": "18.3.3",
+        "@types/react": "18.3.18",
         "@types/react-beautiful-dnd": "^13.0.0",
-        "@types/react-dom": "18.3.1",
+        "@types/react-dom": "18.3.5",
         "@types/react-transition-group": "^4.4.0",
         "@types/sanitize-html": "2.13.0",
         "@types/semver": "^7.5.8",
         "@types/tar-js": "^0.3.5",
         "@types/ua-parser-js": "^0.7.36",
         "@types/uuid": "^10.0.0",
-        "@typescript-eslint/eslint-plugin": "^8.0.0",
-        "@typescript-eslint/parser": "^8.0.0",
+        "@typescript-eslint/eslint-plugin": "^8.19.0",
+        "@typescript-eslint/parser": "^8.19.0",
         "babel-jest": "^29.0.0",
         "babel-loader": "^9.0.0",
         "babel-plugin-jsx-remove-data-test-id": "^3.0.0",
@@ -240,7 +244,6 @@
         "fetch-mock": "9.11.0",
         "fetch-mock-jest": "^1.5.1",
         "file-loader": "^6.0.0",
-        "fs-extra": "^11.0.0",
         "glob": "^11.0.0",
         "html-webpack-plugin": "^5.5.3",
         "husky": "^9.0.0",
@@ -254,12 +257,12 @@
         "lint-staged": "^15.0.2",
         "mailhog": "^4.16.0",
         "matrix-web-i18n": "^3.2.1",
-        "mini-css-extract-plugin": "2.9.0",
+        "mini-css-extract-plugin": "2.9.2",
         "minimist": "^1.2.6",
         "modernizr": "^3.12.0",
         "node-fetch": "^2.6.7",
         "playwright-core": "^1.45.1",
-        "postcss": "8.4.38",
+        "postcss": "8.4.46",
         "postcss-easings": "^4.0.0",
         "postcss-hexrgba": "2.1.0",
         "postcss-import": "16.1.0",
@@ -275,20 +278,22 @@
         "rimraf": "^6.0.0",
         "semver": "^7.5.2",
         "source-map-loader": "^5.0.0",
+        "strip-ansi": "^7.1.0",
         "stylelint": "^16.1.0",
         "stylelint-config-standard": "^36.0.0",
         "stylelint-scss": "^6.0.0",
         "stylelint-value-no-unknown-custom-properties": "^6.0.1",
         "terser-webpack-plugin": "^5.3.9",
+        "testcontainers": "^10.16.0",
         "ts-node": "^10.9.1",
-        "ts-prune": "^0.10.3",
-        "typescript": "5.6.3",
+        "typescript": "5.7.2",
         "util": "^0.12.5",
         "web-streams-polyfill": "^4.0.0",
         "webpack": "^5.89.0",
         "webpack-bundle-analyzer": "^4.8.0",
-        "webpack-cli": "^5.0.0",
+        "webpack-cli": "^6.0.0",
         "webpack-dev-server": "^5.0.0",
+        "webpack-retry-chunk-load-plugin": "^3.1.1",
         "webpack-version-file-plugin": "^0.5.0",
         "yaml": "^2.3.3"
     },
diff --git a/playwright.config.ts b/playwright.config.ts
index 06c1b05322d..09bd07bb3b8 100644
--- a/playwright.config.ts
+++ b/playwright.config.ts
@@ -2,25 +2,80 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 import { defineConfig, devices } from "@playwright/test";
 
+import { Options } from "./playwright/services";
+
 const baseURL = process.env["BASE_URL"] ?? "http://localhost:8080";
 
-export default defineConfig({
-    projects: [{ name: "Chrome", use: { ...devices["Desktop Chrome"], channel: "chromium" } }],
+const chromeProject = {
+    ...devices["Desktop Chrome"],
+    channel: "chromium",
+    permissions: ["clipboard-write", "clipboard-read", "microphone"],
+    launchOptions: {
+        args: ["--use-fake-ui-for-media-stream", "--use-fake-device-for-media-stream", "--mute-audio"],
+    },
+};
+
+export default defineConfig<Options>({
+    projects: [
+        {
+            name: "Chrome",
+            use: {
+                ...chromeProject,
+            },
+        },
+        {
+            name: "Firefox",
+            use: {
+                ...devices["Desktop Firefox"],
+                launchOptions: {
+                    firefoxUserPrefs: {
+                        "permissions.default.microphone": 1,
+                    },
+                },
+                // This is needed to work around an issue between Playwright routes, Firefox, and Service workers
+                // https://github.com/microsoft/playwright/issues/33561#issuecomment-2471642120
+                serviceWorkers: "block",
+            },
+            ignoreSnapshots: true,
+        },
+        {
+            name: "WebKit",
+            use: {
+                ...devices["Desktop Safari"],
+                // Seemingly WebKit has the same issue as Firefox in Playwright routes not working
+                // https://playwright.dev/docs/network#missing-network-events-and-service-workers
+                serviceWorkers: "block",
+            },
+            ignoreSnapshots: true,
+        },
+        {
+            name: "Dendrite",
+            use: {
+                ...chromeProject,
+                homeserverType: "dendrite",
+            },
+            ignoreSnapshots: true,
+        },
+        {
+            name: "Pinecone",
+            use: {
+                ...chromeProject,
+                homeserverType: "pinecone",
+            },
+            ignoreSnapshots: true,
+        },
+    ],
     use: {
         viewport: { width: 1280, height: 720 },
         ignoreHTTPSErrors: true,
         video: "retain-on-failure",
         baseURL,
-        permissions: ["clipboard-write", "clipboard-read", "microphone"],
-        launchOptions: {
-            args: ["--use-fake-ui-for-media-stream", "--use-fake-device-for-media-stream", "--mute-audio"],
-        },
         trace: "on-first-retry",
     },
     webServer: {
diff --git a/playwright/@types/playwright-core.d.ts b/playwright/@types/playwright-core.d.ts
index 9701b2ddac0..244f3c91d46 100644
--- a/playwright/@types/playwright-core.d.ts
+++ b/playwright/@types/playwright-core.d.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/playwright/e2e/accessibility/keyboard-navigation.spec.ts b/playwright/e2e/accessibility/keyboard-navigation.spec.ts
index 87cee4e05c3..e22664c8985 100644
--- a/playwright/e2e/accessibility/keyboard-navigation.spec.ts
+++ b/playwright/e2e/accessibility/keyboard-navigation.spec.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -123,7 +123,7 @@ test.describe("Landmark navigation tests", () => {
         await expect(page.getByText("Bob joined the room")).toBeVisible();
 
         // Close the room
-        page.goto("/#/home");
+        await page.goto("/#/home");
 
         // Pressing Control+F6 will first focus the space button
         await page.keyboard.press("ControlOrMeta+F6");
diff --git a/playwright/e2e/app-loading/feature-detection.spec.ts b/playwright/e2e/app-loading/feature-detection.spec.ts
index ee61fb56628..0d11e4a31a9 100644
--- a/playwright/e2e/app-loading/feature-detection.spec.ts
+++ b/playwright/e2e/app-loading/feature-detection.spec.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/playwright/e2e/app-loading/guest-registration.spec.ts b/playwright/e2e/app-loading/guest-registration.spec.ts
index 4455baed230..960b6a66927 100644
--- a/playwright/e2e/app-loading/guest-registration.spec.ts
+++ b/playwright/e2e/app-loading/guest-registration.spec.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -13,13 +13,8 @@ Please see LICENSE files in the repository root for full details.
 import { expect, test } from "../../element-web-test";
 
 test.use({
-    startHomeserverOpts: "guest-enabled",
-    config: async ({ homeserver }, use) => {
-        await use({
-            default_server_config: {
-                "m.homeserver": { base_url: homeserver.config.baseUrl },
-            },
-        });
+    synapseConfig: {
+        allow_guest_access: true,
     },
 });
 
diff --git a/playwright/e2e/app-loading/stored-credentials.spec.ts b/playwright/e2e/app-loading/stored-credentials.spec.ts
index 34cbb5aea4c..7e1bb29ce71 100644
--- a/playwright/e2e/app-loading/stored-credentials.spec.ts
+++ b/playwright/e2e/app-loading/stored-credentials.spec.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/playwright/e2e/audio-player/audio-player.spec.ts b/playwright/e2e/audio-player/audio-player.spec.ts
index 2bb9ab0be45..a6d920dcb84 100644
--- a/playwright/e2e/audio-player/audio-player.spec.ts
+++ b/playwright/e2e/audio-player/audio-player.spec.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2023 Suguru Hirahara
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -13,7 +13,7 @@ import { SettingLevel } from "../../../src/settings/SettingLevel";
 import { Layout } from "../../../src/settings/enums/Layout";
 import { ElementAppPage } from "../../pages/ElementAppPage";
 
-test.describe("Audio player", () => {
+test.describe("Audio player", { tag: ["@no-firefox", "@no-webkit"] }, () => {
     test.use({
         displayName: "Hanako",
     });
@@ -253,7 +253,6 @@ test.describe("Audio player", () => {
 
             // Find and click "Reply" button
             const clickButtonReply = async () => {
-                await tile.scrollIntoViewIfNeeded();
                 await tile.hover();
                 await tile.getByRole("button", { name: "Reply", exact: true }).click();
             };
diff --git a/playwright/e2e/chat-export/html-export.spec.ts b/playwright/e2e/chat-export/html-export.spec.ts
index f914cccd96b..760d3cc5f1c 100644
--- a/playwright/e2e/chat-export/html-export.spec.ts
+++ b/playwright/e2e/chat-export/html-export.spec.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -95,7 +95,7 @@ test.describe("HTML Export", () => {
         async ({ page, app, room }) => {
             // Set a fixed time rather than masking off the line with the time in it: we don't need to worry
             // about the width changing and we can actually test this line looks correct.
-            page.clock.setSystemTime(new Date("2024-01-01T00:00:00Z"));
+            await page.clock.setSystemTime(new Date("2024-01-01T00:00:00Z"));
 
             // Send a bunch of messages to populate the room
             for (let i = 1; i < 10; i++) {
diff --git a/playwright/e2e/composer/CIDER.spec.ts b/playwright/e2e/composer/CIDER.spec.ts
index 2052b9683dd..03fc59cd0f1 100644
--- a/playwright/e2e/composer/CIDER.spec.ts
+++ b/playwright/e2e/composer/CIDER.spec.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022, 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/playwright/e2e/composer/RTE.spec.ts b/playwright/e2e/composer/RTE.spec.ts
index 91a56afb8ad..e88dd827fcc 100644
--- a/playwright/e2e/composer/RTE.spec.ts
+++ b/playwright/e2e/composer/RTE.spec.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022, 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -79,9 +79,8 @@ test.describe("Composer", () => {
                     // Enter some more text, then send the message
                     await page.getByRole("textbox").pressSequentially("this is the spoiler text ");
                     await page.getByRole("button", { name: "Send message" }).click();
-                    // Check that a spoiler item has appeared in the timeline and locator the spoiler command text
-                    await expect(page.locator("button.mx_EventTile_spoiler")).toBeVisible();
-                    await expect(page.getByText("this is the spoiler text")).toBeVisible();
+                    // Check that a spoiler item has appeared in the timeline and contains the spoiler text
+                    await expect(page.locator("button.mx_EventTile_spoiler")).toHaveText("this is the spoiler text");
                 });
             });
         });
@@ -166,7 +165,7 @@ test.describe("Composer", () => {
             // Type another
             await page.locator("div[contenteditable=true]").pressSequentially("my message 1");
             // Send message
-            page.locator("div[contenteditable=true]").press("Enter");
+            await page.locator("div[contenteditable=true]").press("Enter");
             // It was sent
             await expect(page.locator(".mx_EventTile_last .mx_EventTile_body").getByText("my message 1")).toBeVisible();
         });
diff --git a/playwright/e2e/create-room/create-room.spec.ts b/playwright/e2e/create-room/create-room.spec.ts
index 51a135ca03f..087a89e68dc 100644
--- a/playwright/e2e/create-room/create-room.spec.ts
+++ b/playwright/e2e/create-room/create-room.spec.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022, 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -27,7 +27,7 @@ test.describe("Create Room", () => {
         // Submit
         await dialog.getByRole("button", { name: "Create room" }).click();
 
-        await expect(page).toHaveURL(/\/#\/room\/#test-room-1:localhost/);
+        await expect(page).toHaveURL(new RegExp(`/#/room/#test-room-1:${user.homeServer}`));
         const header = page.locator(".mx_RoomHeader");
         await expect(header).toContainText(name);
     });
diff --git a/playwright/e2e/crypto/backups-mas.spec.ts b/playwright/e2e/crypto/backups-mas.spec.ts
new file mode 100644
index 00000000000..a6f4fb93907
--- /dev/null
+++ b/playwright/e2e/crypto/backups-mas.spec.ts
@@ -0,0 +1,95 @@
+/*
+Copyright 2024 New Vector Ltd.
+Copyright 2023 The Matrix.org Foundation C.I.C.
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+Please see LICENSE files in the repository root for full details.
+*/
+
+import { test, expect } from "../../element-web-test";
+import { registerAccountMas } from "../oidc";
+import { isDendrite } from "../../plugins/homeserver/dendrite";
+import { TestClientServerAPI } from "../csAPI";
+import { masHomeserver } from "../../plugins/homeserver/synapse/masHomeserver.ts";
+
+// These tests register an account with MAS because then we go through the "normal" registration flow
+// and crypto gets set up. Using the 'user' fixture create a user and synthesizes an existing login,
+// which is faster but leaves us without crypto set up.
+test.use(masHomeserver);
+test.describe("Encryption state after registration", () => {
+    test.skip(isDendrite, "does not yet support MAS");
+
+    test("Key backup is enabled by default", async ({ page, mailhogClient, app }, testInfo) => {
+        await page.goto("/#/login");
+        await page.getByRole("button", { name: "Continue" }).click();
+        await registerAccountMas(page, mailhogClient, `alice_${testInfo.testId}`, "alice@email.com", "Pa$sW0rD!");
+
+        await app.settings.openUserSettings("Security & Privacy");
+        await expect(page.getByText("This session is backing up your keys.")).toBeVisible();
+    });
+
+    test("user is prompted to set up recovery", async ({ page, mailhogClient, app }, testInfo) => {
+        await page.goto("/#/login");
+        await page.getByRole("button", { name: "Continue" }).click();
+        await registerAccountMas(page, mailhogClient, `alice_${testInfo.testId}`, "alice@email.com", "Pa$sW0rD!");
+
+        await page.getByRole("button", { name: "Add room" }).click();
+        await page.getByRole("menuitem", { name: "New room" }).click();
+        await page.getByRole("textbox", { name: "Name" }).fill("test room");
+        await page.getByRole("button", { name: "Create room" }).click();
+
+        await expect(page.getByRole("heading", { name: "Set up recovery" })).toBeVisible();
+    });
+});
+
+test.describe("Key backup reset from elsewhere", () => {
+    test.skip(isDendrite, "does not yet support MAS");
+
+    test("Key backup is disabled when reset from elsewhere", async ({
+        page,
+        mailhogClient,
+        request,
+        homeserver,
+    }, testInfo) => {
+        const testUsername = `alice_${testInfo.testId}`;
+        const testPassword = "Pa$sW0rD!";
+
+        // there's a delay before keys are uploaded so the error doesn't appear immediately: use a fake
+        // clock so we can skip the delay
+        await page.clock.install();
+
+        await page.goto("/#/login");
+        await page.getByRole("button", { name: "Continue" }).click();
+        await registerAccountMas(page, mailhogClient, testUsername, "alice@email.com", testPassword);
+
+        await page.getByRole("button", { name: "Add room" }).click();
+        await page.getByRole("menuitem", { name: "New room" }).click();
+        await page.getByRole("textbox", { name: "Name" }).fill("test room");
+        await page.getByRole("button", { name: "Create room" }).click();
+
+        const accessToken = await page.evaluate(() => window.mxMatrixClientPeg.get().getAccessToken());
+
+        const csAPI = new TestClientServerAPI(request, homeserver, accessToken);
+
+        const backupInfo = await csAPI.getCurrentBackupInfo();
+
+        await csAPI.deleteBackupVersion(backupInfo.version);
+
+        await page.getByRole("textbox", { name: "Send an encrypted message…" }).fill("/discardsession");
+        await page.getByRole("button", { name: "Send message" }).click();
+
+        await page.getByRole("textbox", { name: "Send an encrypted message…" }).fill("Message with broken key backup");
+        await page.getByRole("button", { name: "Send message" }).click();
+
+        // Should be the message we sent plus the room creation event
+        await expect(page.locator(".mx_EventTile")).toHaveCount(2);
+        await expect(
+            page.locator(".mx_RoomView_MessageList > .mx_EventTile_last .mx_EventTile_receiptSent"),
+        ).toBeVisible();
+
+        // Wait for it to try uploading the key
+        await page.clock.fastForward(20000);
+
+        await expect(page.getByRole("heading", { level: 1, name: "New Recovery Method" })).toBeVisible();
+    });
+});
diff --git a/playwright/e2e/crypto/backups.spec.ts b/playwright/e2e/crypto/backups.spec.ts
index d174cc89e5a..95bf708122e 100644
--- a/playwright/e2e/crypto/backups.spec.ts
+++ b/playwright/e2e/crypto/backups.spec.ts
@@ -2,14 +2,13 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 import { type Page } from "@playwright/test";
 
 import { test, expect } from "../../element-web-test";
-import { test as masTest, registerAccountMas } from "../oidc";
 import { isDendrite } from "../../plugins/homeserver/dendrite";
 
 async function expectBackupVersionToBe(page: Page, version: string) {
@@ -20,121 +19,100 @@ async function expectBackupVersionToBe(page: Page, version: string) {
     await expect(page.locator(".mx_SecureBackupPanel_statusList tr:nth-child(6) td")).toHaveText(version);
 }
 
-masTest.describe("Encryption state after registration", () => {
-    masTest.skip(isDendrite, "does not yet support MAS");
-
-    masTest("Key backup is enabled by default", async ({ page, mailhog, app }) => {
-        await page.goto("/#/login");
-        await page.getByRole("button", { name: "Continue" }).click();
-        await registerAccountMas(page, mailhog.api, "alice", "alice@email.com", "Pa$sW0rD!");
-
-        await app.settings.openUserSettings("Security & Privacy");
-        expect(page.getByText("This session is backing up your keys.")).toBeVisible();
-    });
-
-    masTest("user is prompted to set up recovery", async ({ page, mailhog, app }) => {
-        await page.goto("/#/login");
-        await page.getByRole("button", { name: "Continue" }).click();
-        await registerAccountMas(page, mailhog.api, "alice", "alice@email.com", "Pa$sW0rD!");
-
-        await page.getByRole("button", { name: "Add room" }).click();
-        await page.getByRole("menuitem", { name: "New room" }).click();
-        await page.getByRole("textbox", { name: "Name" }).fill("test room");
-        await page.getByRole("button", { name: "Create room" }).click();
-
-        await expect(page.getByRole("heading", { name: "Set up recovery" })).toBeVisible();
-    });
-});
-
 test.describe("Backups", () => {
+    test.skip(isDendrite, "Dendrite lacks support for MSC3967 so requires additional auth here");
     test.use({
         displayName: "Hanako",
     });
 
-    test("Create, delete and recreate a keys backup", async ({ page, user, app }, workerInfo) => {
-        // Create a backup
-        const securityTab = await app.settings.openUserSettings("Security & Privacy");
-
-        await expect(securityTab.getByRole("heading", { name: "Secure Backup" })).toBeVisible();
-        await securityTab.getByRole("button", { name: "Set up", exact: true }).click();
-
-        const currentDialogLocator = page.locator(".mx_Dialog");
-
-        // It's the first time and secure storage is not set up, so it will create one
-        await expect(currentDialogLocator.getByRole("heading", { name: "Set up Secure Backup" })).toBeVisible();
-        await currentDialogLocator.getByRole("button", { name: "Continue", exact: true }).click();
-        await expect(currentDialogLocator.getByRole("heading", { name: "Save your Security Key" })).toBeVisible();
-        await currentDialogLocator.getByRole("button", { name: "Copy", exact: true }).click();
-        // copy the recovery key to use it later
-        const securityKey = await app.getClipboard();
-        await currentDialogLocator.getByRole("button", { name: "Continue", exact: true }).click();
-
-        await expect(currentDialogLocator.getByRole("heading", { name: "Secure Backup successful" })).toBeVisible();
-        await currentDialogLocator.getByRole("button", { name: "Done", exact: true }).click();
-
-        // Open the settings again
-        await app.settings.openUserSettings("Security & Privacy");
-        await expect(securityTab.getByRole("heading", { name: "Secure Backup" })).toBeVisible();
-
-        // expand the advanced section to see the active version in the reports
-        await page
-            .locator(".mx_Dialog .mx_SettingsSubsection_content details .mx_SecureBackupPanel_advanced")
-            .locator("..")
-            .click();
-
-        await expectBackupVersionToBe(page, "1");
-
-        await securityTab.getByRole("button", { name: "Delete Backup", exact: true }).click();
-        await expect(currentDialogLocator.getByRole("heading", { name: "Delete Backup" })).toBeVisible();
-        // Delete it
-        await currentDialogLocator.getByTestId("dialog-primary-button").click(); // Click "Delete Backup"
-
-        // Create another
-        await securityTab.getByRole("button", { name: "Set up", exact: true }).click();
-        await expect(currentDialogLocator.getByRole("heading", { name: "Security Key" })).toBeVisible();
-        await currentDialogLocator.getByLabel("Security Key").fill(securityKey);
-        await currentDialogLocator.getByRole("button", { name: "Continue", exact: true }).click();
-
-        // Should be successful
-        await expect(currentDialogLocator.getByRole("heading", { name: "Success!" })).toBeVisible();
-        await currentDialogLocator.getByRole("button", { name: "OK", exact: true }).click();
-
-        // Open the settings again
-        await app.settings.openUserSettings("Security & Privacy");
-        await expect(securityTab.getByRole("heading", { name: "Secure Backup" })).toBeVisible();
-
-        // expand the advanced section to see the active version in the reports
-        await page
-            .locator(".mx_Dialog .mx_SettingsSubsection_content details .mx_SecureBackupPanel_advanced")
-            .locator("..")
-            .click();
-
-        await expectBackupVersionToBe(page, "2");
-
-        // ==
-        // Ensure that if you don't have the secret storage passphrase the backup won't be created
-        // ==
-
-        // First delete version 2
-        await securityTab.getByRole("button", { name: "Delete Backup", exact: true }).click();
-        await expect(currentDialogLocator.getByRole("heading", { name: "Delete Backup" })).toBeVisible();
-        // Click "Delete Backup"
-        await currentDialogLocator.getByTestId("dialog-primary-button").click();
-
-        // Try to create another
-        await securityTab.getByRole("button", { name: "Set up", exact: true }).click();
-        await expect(currentDialogLocator.getByRole("heading", { name: "Security Key" })).toBeVisible();
-        // But cancel the security key dialog, to simulate not having the secret storage passphrase
-        await currentDialogLocator.getByTestId("dialog-cancel-button").click();
-
-        await expect(currentDialogLocator.getByRole("heading", { name: "Starting backup…" })).toBeVisible();
-        // check that it failed
-        await expect(currentDialogLocator.getByText("Unable to create key backup")).toBeVisible();
-        // cancel
-        await currentDialogLocator.getByTestId("dialog-cancel-button").click();
-
-        // go back to the settings to check that no backup was created (the setup button should still be there)
-        await app.settings.openUserSettings("Security & Privacy");
-        await expect(securityTab.getByRole("button", { name: "Set up", exact: true })).toBeVisible();
-    });
+    test(
+        "Create, delete and recreate a keys backup",
+        { tag: "@no-webkit" },
+        async ({ page, user, app }, workerInfo) => {
+            // Create a backup
+            const securityTab = await app.settings.openUserSettings("Security & Privacy");
+
+            await expect(securityTab.getByRole("heading", { name: "Secure Backup" })).toBeVisible();
+            await securityTab.getByRole("button", { name: "Set up", exact: true }).click();
+
+            const currentDialogLocator = page.locator(".mx_Dialog");
+
+            // It's the first time and secure storage is not set up, so it will create one
+            await expect(currentDialogLocator.getByRole("heading", { name: "Set up Secure Backup" })).toBeVisible();
+            await currentDialogLocator.getByRole("button", { name: "Continue", exact: true }).click();
+            await expect(currentDialogLocator.getByRole("heading", { name: "Save your Security Key" })).toBeVisible();
+            await currentDialogLocator.getByRole("button", { name: "Copy", exact: true }).click();
+            // copy the recovery key to use it later
+            const securityKey = await app.getClipboard();
+            await currentDialogLocator.getByRole("button", { name: "Continue", exact: true }).click();
+
+            await expect(currentDialogLocator.getByRole("heading", { name: "Secure Backup successful" })).toBeVisible();
+            await currentDialogLocator.getByRole("button", { name: "Done", exact: true }).click();
+
+            // Open the settings again
+            await app.settings.openUserSettings("Security & Privacy");
+            await expect(securityTab.getByRole("heading", { name: "Secure Backup" })).toBeVisible();
+
+            // expand the advanced section to see the active version in the reports
+            await page
+                .locator(".mx_Dialog .mx_SettingsSubsection_content details .mx_SecureBackupPanel_advanced")
+                .locator("..")
+                .click();
+
+            await expectBackupVersionToBe(page, "1");
+
+            await securityTab.getByRole("button", { name: "Delete Backup", exact: true }).click();
+            await expect(currentDialogLocator.getByRole("heading", { name: "Delete Backup" })).toBeVisible();
+            // Delete it
+            await currentDialogLocator.getByTestId("dialog-primary-button").click(); // Click "Delete Backup"
+
+            // Create another
+            await securityTab.getByRole("button", { name: "Set up", exact: true }).click();
+            await expect(currentDialogLocator.getByRole("heading", { name: "Security Key" })).toBeVisible();
+            await currentDialogLocator.getByLabel("Security Key").fill(securityKey);
+            await currentDialogLocator.getByRole("button", { name: "Continue", exact: true }).click();
+
+            // Should be successful
+            await expect(currentDialogLocator.getByRole("heading", { name: "Success!" })).toBeVisible();
+            await currentDialogLocator.getByRole("button", { name: "OK", exact: true }).click();
+
+            // Open the settings again
+            await app.settings.openUserSettings("Security & Privacy");
+            await expect(securityTab.getByRole("heading", { name: "Secure Backup" })).toBeVisible();
+
+            // expand the advanced section to see the active version in the reports
+            await page
+                .locator(".mx_Dialog .mx_SettingsSubsection_content details .mx_SecureBackupPanel_advanced")
+                .locator("..")
+                .click();
+
+            await expectBackupVersionToBe(page, "2");
+
+            // ==
+            // Ensure that if you don't have the secret storage passphrase the backup won't be created
+            // ==
+
+            // First delete version 2
+            await securityTab.getByRole("button", { name: "Delete Backup", exact: true }).click();
+            await expect(currentDialogLocator.getByRole("heading", { name: "Delete Backup" })).toBeVisible();
+            // Click "Delete Backup"
+            await currentDialogLocator.getByTestId("dialog-primary-button").click();
+
+            // Try to create another
+            await securityTab.getByRole("button", { name: "Set up", exact: true }).click();
+            await expect(currentDialogLocator.getByRole("heading", { name: "Security Key" })).toBeVisible();
+            // But cancel the security key dialog, to simulate not having the secret storage passphrase
+            await currentDialogLocator.getByTestId("dialog-cancel-button").click();
+
+            await expect(currentDialogLocator.getByRole("heading", { name: "Starting backup…" })).toBeVisible();
+            // check that it failed
+            await expect(currentDialogLocator.getByText("Unable to create key backup")).toBeVisible();
+            // cancel
+            await currentDialogLocator.getByTestId("dialog-cancel-button").click();
+
+            // go back to the settings to check that no backup was created (the setup button should still be there)
+            await app.settings.openUserSettings("Security & Privacy");
+            await expect(securityTab.getByRole("button", { name: "Set up", exact: true })).toBeVisible();
+        },
+    );
 });
diff --git a/playwright/e2e/crypto/complete-security.spec.ts b/playwright/e2e/crypto/complete-security.spec.ts
index e5c5f8e9a3f..d4c303fae44 100644
--- a/playwright/e2e/crypto/complete-security.spec.ts
+++ b/playwright/e2e/crypto/complete-security.spec.ts
@@ -2,14 +2,16 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 import { test, expect } from "../../element-web-test";
 import { logIntoElement } from "./utils";
+import { isDendrite } from "../../plugins/homeserver/dendrite";
 
 test.describe("Complete security", () => {
+    test.skip(isDendrite, "Dendrite lacks support for MSC3967 so requires additional auth here");
     test.use({
         displayName: "Jeff",
     });
@@ -19,9 +21,9 @@ test.describe("Complete security", () => {
         homeserver,
         credentials,
     }) => {
-        await logIntoElement(page, homeserver, credentials);
+        await logIntoElement(page, credentials);
         await expect(page.getByText("Welcome Jeff", { exact: true })).toBeVisible();
     });
 
-    // see also "Verify device during login with SAS" in `verifiction.spec.ts`.
+    // see also "Verify device during login with SAS" in `verification.spec.ts`.
 });
diff --git a/playwright/e2e/crypto/crypto.spec.ts b/playwright/e2e/crypto/crypto.spec.ts
index 668c17d931d..f99a7a64588 100644
--- a/playwright/e2e/crypto/crypto.spec.ts
+++ b/playwright/e2e/crypto/crypto.spec.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022-2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -11,6 +11,7 @@ import { expect, test } from "../../element-web-test";
 import { autoJoin, copyAndContinue, createSharedRoomWithUser, enableKeyBackup, verify } from "./utils";
 import { Bot } from "../../pages/bot";
 import { ElementAppPage } from "../../pages/ElementAppPage";
+import { isDendrite } from "../../plugins/homeserver/dendrite";
 
 const checkDMRoom = async (page: Page) => {
     const body = page.locator(".mx_RoomView_body");
@@ -67,6 +68,7 @@ const bobJoin = async (page: Page, bob: Bot) => {
 };
 
 test.describe("Cryptography", function () {
+    test.skip(isDendrite, "Dendrite lacks support for MSC3967 so requires additional auth here");
     test.use({
         displayName: "Alice",
         botCreateOpts: {
@@ -81,7 +83,7 @@ test.describe("Cryptography", function () {
              * Verify that the `m.cross_signing.${keyType}` key is available on the account data on the server
              * @param keyType
              */
-            async function verifyKey(app: ElementAppPage, keyType: string) {
+            async function verifyKey(app: ElementAppPage, keyType: "master" | "self_signing" | "user_signing") {
                 const accountData: { encrypted: Record<string, Record<string, string>> } = await app.client.evaluate(
                     (cli, keyType) => cli.getAccountDataFromServer(`m.cross_signing.${keyType}`),
                     keyType,
diff --git a/playwright/e2e/crypto/decryption-failure-messages.spec.ts b/playwright/e2e/crypto/decryption-failure-messages.spec.ts
index b2a1209a70a..529251b223b 100644
--- a/playwright/e2e/crypto/decryption-failure-messages.spec.ts
+++ b/playwright/e2e/crypto/decryption-failure-messages.spec.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022-2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -28,6 +28,8 @@ test.describe("Cryptography", function () {
     });
 
     test.describe("decryption failure messages", () => {
+        test.skip(isDendrite, "Dendrite lacks support for MSC3967 so requires additional auth here");
+
         test("should handle device-relative historical messages", async ({
             homeserver,
             page,
@@ -45,7 +47,7 @@ test.describe("Cryptography", function () {
             await logOutOfElement(page, true);
 
             // Log in again, and see how the message looks.
-            await logIntoElement(page, homeserver, credentials);
+            await logIntoElement(page, credentials);
             await app.viewRoomByName("Test room");
             const lastTile = page.locator(".mx_EventTile").last();
             await expect(lastTile).toContainText("Historical messages are not available on this device");
@@ -62,7 +64,7 @@ test.describe("Cryptography", function () {
 
             // Finally, log out again, and back in, skipping verification for now, and see what we see.
             await logOutOfElement(page);
-            await logIntoElement(page, homeserver, credentials);
+            await logIntoElement(page, credentials);
             await page.locator(".mx_AuthPage").getByRole("button", { name: "Skip verification for now" }).click();
             await page.locator(".mx_AuthPage").getByRole("button", { name: "I'll verify later" }).click();
             await app.viewRoomByName("Test room");
diff --git a/playwright/e2e/crypto/dehydration.spec.ts b/playwright/e2e/crypto/dehydration.spec.ts
index 590ab774b50..9beb0539328 100644
--- a/playwright/e2e/crypto/dehydration.spec.ts
+++ b/playwright/e2e/crypto/dehydration.spec.ts
@@ -2,26 +2,34 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 import { Locator, type Page } from "@playwright/test";
 
-import { test as base, expect } from "../../element-web-test";
+import { test, expect } from "../../element-web-test";
 import { viewRoomSummaryByName } from "../right-panel/utils";
 import { isDendrite } from "../../plugins/homeserver/dendrite";
 
-const test = base.extend({
-    // eslint-disable-next-line no-empty-pattern
-    startHomeserverOpts: async ({}, use) => {
-        await use("dehydration");
+const ROOM_NAME = "Test room";
+const NAME = "Alice";
+
+function getMemberTileByName(page: Page, name: string): Locator {
+    return page.locator(`.mx_MemberTileView, [title="${name}"]`);
+}
+
+test.use({
+    displayName: NAME,
+    synapseConfig: {
+        experimental_features: {
+            msc2697_enabled: false,
+            msc3814_enabled: true,
+        },
     },
-    config: async ({ homeserver, context }, use) => {
+    config: async ({ config, context }, use) => {
         const wellKnown = {
-            "m.homeserver": {
-                base_url: homeserver.config.baseUrl,
-            },
+            ...config.default_server_config,
             "org.matrix.msc3814": true,
         };
 
@@ -29,29 +37,14 @@ const test = base.extend({
             await route.fulfill({ json: wellKnown });
         });
 
-        await use({
-            default_server_config: wellKnown,
-        });
+        await use(config);
     },
 });
 
-const ROOM_NAME = "Test room";
-const NAME = "Alice";
-
-function getMemberTileByName(page: Page, name: string): Locator {
-    return page.locator(`.mx_EntityTile, [title="${name}"]`);
-}
-
 test.describe("Dehydration", () => {
     test.skip(isDendrite, "does not yet support dehydration v2");
 
-    test.use({
-        displayName: NAME,
-    });
-
     test("Create dehydrated device", async ({ page, user, app }, workerInfo) => {
-        test.skip(workerInfo.project.name === "Legacy Crypto", "This test only works with Rust crypto.");
-
         // Create a backup (which will create SSSS, and dehydrated device)
 
         const securityTab = await app.settings.openUserSettings("Security & Privacy");
@@ -95,7 +88,7 @@ test.describe("Dehydration", () => {
         await viewRoomSummaryByName(page, app, ROOM_NAME);
 
         await page.locator(".mx_RightPanel").getByRole("menuitem", { name: "People" }).click();
-        await expect(page.locator(".mx_MemberList")).toBeVisible();
+        await expect(page.locator(".mx_MemberListView")).toBeVisible();
 
         await getMemberTileByName(page, NAME).click();
         await page.locator(".mx_UserInfo_devices .mx_UserInfo_expand").click();
diff --git a/playwright/e2e/crypto/device-verification.spec.ts b/playwright/e2e/crypto/device-verification.spec.ts
index 83a81c260cd..4091b1e6761 100644
--- a/playwright/e2e/crypto/device-verification.spec.ts
+++ b/playwright/e2e/crypto/device-verification.spec.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -15,42 +15,23 @@ import {
     awaitVerifier,
     checkDeviceIsConnectedKeyBackup,
     checkDeviceIsCrossSigned,
+    createBot,
     doTwoWaySasVerification,
     logIntoElement,
     waitForVerificationRequest,
 } from "./utils";
 import { Bot } from "../../pages/bot";
 
-test.describe("Device verification", () => {
+test.describe("Device verification", { tag: "@no-webkit" }, () => {
     let aliceBotClient: Bot;
 
     /** The backup version that was set up by the bot client. */
     let expectedBackupVersion: string;
 
     test.beforeEach(async ({ page, homeserver, credentials }) => {
-        // Visit the login page of the app, to load the matrix sdk
-        await page.goto("/#/login");
-
-        // wait for the page to load
-        await page.waitForSelector(".mx_AuthPage", { timeout: 30000 });
-
-        // Create a new device for alice
-        aliceBotClient = new Bot(page, homeserver, {
-            bootstrapCrossSigning: true,
-            bootstrapSecretStorage: true,
-        });
-        aliceBotClient.setCredentials(credentials);
-
-        // Backup is prepared in the background. Poll until it is ready.
-        const botClientHandle = await aliceBotClient.prepareClient();
-        await expect
-            .poll(async () => {
-                expectedBackupVersion = await botClientHandle.evaluate((cli) =>
-                    cli.getCrypto()!.getActiveSessionBackupVersion(),
-                );
-                return expectedBackupVersion;
-            })
-            .not.toBe(null);
+        const res = await createBot(page, homeserver, credentials);
+        aliceBotClient = res.botClient;
+        expectedBackupVersion = res.expectedBackupVersion;
     });
 
     // Click the "Verify with another device" button, and have the bot client auto-accept it.
@@ -66,7 +47,7 @@ test.describe("Device verification", () => {
     }
 
     test("Verify device with SAS during login", async ({ page, app, credentials, homeserver }) => {
-        await logIntoElement(page, homeserver, credentials);
+        await logIntoElement(page, credentials);
 
         // Launch the verification request between alice and the bot
         const verificationRequest = await initiateAliceVerificationRequest(page);
@@ -93,7 +74,7 @@ test.describe("Device verification", () => {
 
     test("Verify device with QR code during login", async ({ page, app, credentials, homeserver }) => {
         // A mode 0x02 verification: "self-verifying in which the current device does not yet trust the master key"
-        await logIntoElement(page, homeserver, credentials);
+        await logIntoElement(page, credentials);
 
         // Launch the verification request between alice and the bot
         const verificationRequest = await initiateAliceVerificationRequest(page);
@@ -137,7 +118,7 @@ test.describe("Device verification", () => {
     });
 
     test("Verify device with Security Phrase during login", async ({ page, app, credentials, homeserver }) => {
-        await logIntoElement(page, homeserver, credentials);
+        await logIntoElement(page, credentials);
 
         // Select the security phrase
         await page.locator(".mx_AuthPage").getByRole("button", { name: "Verify with Security Key or Phrase" }).click();
@@ -158,7 +139,7 @@ test.describe("Device verification", () => {
     });
 
     test("Verify device with Security Key during login", async ({ page, app, credentials, homeserver }) => {
-        await logIntoElement(page, homeserver, credentials);
+        await logIntoElement(page, credentials);
 
         // Select the security phrase
         await page.locator(".mx_AuthPage").getByRole("button", { name: "Verify with Security Key or Phrase" }).click();
@@ -181,7 +162,7 @@ test.describe("Device verification", () => {
     });
 
     test("Handle incoming verification request with SAS", async ({ page, credentials, homeserver, toasts }) => {
-        await logIntoElement(page, homeserver, credentials);
+        await logIntoElement(page, credentials);
 
         /* Dismiss "Verify this device" */
         const authPage = page.locator(".mx_AuthPage");
@@ -212,16 +193,17 @@ test.describe("Device verification", () => {
         /* on the bot side, wait for the verifier to exist ... */
         const verifier = await awaitVerifier(botVerificationRequest);
         // ... confirm ...
-        botVerificationRequest.evaluate((verificationRequest) => verificationRequest.verifier.verify());
+        void botVerificationRequest.evaluate((verificationRequest) => verificationRequest.verifier.verify());
         // ... and then check the emoji match
         await doTwoWaySasVerification(page, verifier);
 
         /* And we're all done! */
         const infoDialog = page.locator(".mx_InfoDialog");
         await infoDialog.getByRole("button", { name: "They match" }).click();
-        await expect(
-            infoDialog.getByText(`You've successfully verified (${aliceBotClient.credentials.deviceId})!`),
-        ).toBeVisible();
+        // We don't assert the full string as the device name is unset on Synapse but set to the user ID on Dendrite
+        await expect(infoDialog.getByText(`You've successfully verified`)).toContainText(
+            `(${aliceBotClient.credentials.deviceId})`,
+        );
         await infoDialog.getByRole("button", { name: "Got it" }).click();
     });
 });
diff --git a/playwright/e2e/crypto/event-shields.spec.ts b/playwright/e2e/crypto/event-shields.spec.ts
index 0beb8e36500..3811c2819e5 100644
--- a/playwright/e2e/crypto/event-shields.spec.ts
+++ b/playwright/e2e/crypto/event-shields.spec.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022-2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -53,6 +53,8 @@ test.describe("Cryptography", function () {
 
             // Even though Alice has seen Bob's join event, Bob may not have done so yet. Wait for the sync to arrive.
             await bob.awaitRoomMembership(testRoomId);
+
+            await app.client.network.setupRoute();
         });
 
         test("should show the correct shield on e2e events", async ({
@@ -133,8 +135,7 @@ test.describe("Cryptography", function () {
                 "Encrypted by a device not verified by its owner.",
             );
 
-            /* In legacy crypto: should show a grey padlock for a message from a deleted device.
-             * In rust crypto: should show a red padlock for a message from an unverified device.
+            /* Should show a red padlock for a message from an unverified device.
              * Rust crypto remembers the verification state of the sending device, so it will know that the device was
              * unverified, even if it gets deleted. */
             // bob deletes his second device
@@ -168,9 +169,7 @@ test.describe("Cryptography", function () {
             await expect(lastE2eIcon).toHaveClass(/mx_EventTile_e2eIcon_warning/);
             await lastE2eIcon.focus();
             await expect(await app.getTooltipForElement(lastE2eIcon)).toContainText(
-                workerInfo.project.name === "Legacy Crypto"
-                    ? "Encrypted by an unknown or deleted device."
-                    : "Encrypted by a device not verified by its owner.",
+                "Encrypted by a device not verified by its owner.",
             );
         });
 
@@ -208,7 +207,7 @@ test.describe("Cryptography", function () {
                 window.localStorage.clear();
             });
             await page.reload();
-            await logIntoElement(page, homeserver, aliceCredentials, securityKey);
+            await logIntoElement(page, aliceCredentials, securityKey);
 
             /* go back to the test room and find Bob's message again */
             await app.viewRoomById(testRoomId);
diff --git a/playwright/e2e/crypto/invisible-crypto.spec.ts b/playwright/e2e/crypto/invisible-crypto.spec.ts
index f207d2c6bb3..198abdac6d9 100644
--- a/playwright/e2e/crypto/invisible-crypto.spec.ts
+++ b/playwright/e2e/crypto/invisible-crypto.spec.ts
@@ -1,7 +1,7 @@
 /*
 Copyright 2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -11,6 +11,7 @@ import { bootstrapCrossSigningForClient } from "../../pages/client.ts";
 
 /** Tests for the "invisible crypto" behaviour -- i.e., when the "exclude insecure devices" setting is enabled */
 test.describe("Invisible cryptography", () => {
+    test.slow();
     test.use({
         displayName: "Alice",
         botCreateOpts: { displayName: "Bob" },
diff --git a/playwright/e2e/crypto/logout.spec.ts b/playwright/e2e/crypto/logout.spec.ts
index b88ae0de734..faaf1e6a1e3 100644
--- a/playwright/e2e/crypto/logout.spec.ts
+++ b/playwright/e2e/crypto/logout.spec.ts
@@ -2,16 +2,18 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 import { test, expect } from "../../element-web-test";
 import { createRoom, enableKeyBackup, logIntoElement, sendMessageInCurrentRoom } from "./utils";
+import { isDendrite } from "../../plugins/homeserver/dendrite";
 
 test.describe("Logout tests", () => {
+    test.skip(isDendrite, "Dendrite lacks support for MSC3967 so requires additional auth here");
     test.beforeEach(async ({ page, homeserver, credentials }) => {
-        await logIntoElement(page, homeserver, credentials);
+        await logIntoElement(page, credentials);
     });
 
     test("Ask to set up recovery on logout if not setup", async ({ page, app }) => {
diff --git a/playwright/e2e/crypto/migration.spec.ts b/playwright/e2e/crypto/migration.spec.ts
index 048b39f06a5..86072fccc07 100644
--- a/playwright/e2e/crypto/migration.spec.ts
+++ b/playwright/e2e/crypto/migration.spec.ts
@@ -2,34 +2,33 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023, 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 import path from "path";
 import { readFile } from "node:fs/promises";
 
-import { expect, test as base } from "../../element-web-test";
+import { expect, test } from "../../element-web-test";
 
-const test = base.extend({
-    // Replace the `user` fixture with one which populates the indexeddb data before starting the app.
-    user: async ({ context, pageWithCredentials: page, credentials }, use) => {
-        await page.route(`/test_indexeddb_cryptostore_dump/*`, async (route, request) => {
-            const resourcePath = path.join(__dirname, new URL(request.url()).pathname);
-            const body = await readFile(resourcePath, { encoding: "utf-8" });
-            await route.fulfill({ body });
-        });
-        await page.goto("/test_indexeddb_cryptostore_dump/index.html");
+test.describe("migration", { tag: "@no-webkit" }, function () {
+    test.use({
+        displayName: "Alice",
 
-        await use(credentials);
-    },
-});
+        // Replace the `user` fixture with one which populates the indexeddb data before starting the app.
+        user: async ({ context, pageWithCredentials: page, credentials }, use) => {
+            await page.route(`/test_indexeddb_cryptostore_dump/*`, async (route, request) => {
+                const resourcePath = path.join(__dirname, new URL(request.url()).pathname);
+                const body = await readFile(resourcePath, { encoding: "utf-8" });
+                await route.fulfill({ body });
+            });
+            await page.goto("/test_indexeddb_cryptostore_dump/index.html");
 
-test.describe("migration", function () {
-    test.use({ displayName: "Alice" });
+            await use(credentials);
+        },
+    });
 
     test("Should support migration from legacy crypto", async ({ context, user, page }, workerInfo) => {
-        test.skip(workerInfo.project.name === "Legacy Crypto", "This test only works with Rust crypto.");
         test.slow();
 
         // We should see a migration progress bar
diff --git a/playwright/e2e/crypto/test_indexeddb_cryptostore_dump/load.js b/playwright/e2e/crypto/test_indexeddb_cryptostore_dump/load.js
index 4f5090b55d2..73c1b21b229 100644
--- a/playwright/e2e/crypto/test_indexeddb_cryptostore_dump/load.js
+++ b/playwright/e2e/crypto/test_indexeddb_cryptostore_dump/load.js
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023, 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/playwright/e2e/crypto/user-verification.spec.ts b/playwright/e2e/crypto/user-verification.spec.ts
index bd3d8595267..175c8d5fdfd 100644
--- a/playwright/e2e/crypto/user-verification.spec.ts
+++ b/playwright/e2e/crypto/user-verification.spec.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -74,7 +74,7 @@ test.describe("User verification", () => {
         /* on the bot side, wait for the verifier to exist ... */
         const botVerifier = await awaitVerifier(bobVerificationRequest);
         // ... confirm ...
-        botVerifier.evaluate((verifier) => verifier.verify());
+        void botVerifier.evaluate((verifier) => verifier.verify());
         // ... and then check the emoji match
         await doTwoWaySasVerification(page, botVerifier);
 
diff --git a/playwright/e2e/crypto/utils.ts b/playwright/e2e/crypto/utils.ts
index 94b1933977e..c880961964f 100644
--- a/playwright/e2e/crypto/utils.ts
+++ b/playwright/e2e/crypto/utils.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -12,6 +12,7 @@ import type { ICreateRoomOpts, MatrixClient } from "matrix-js-sdk/src/matrix";
 import type {
     CryptoEvent,
     EmojiMapping,
+    GeneratedSecretStorageKey,
     ShowSasCallbacks,
     VerificationRequest,
     Verifier,
@@ -22,6 +23,46 @@ import { Client } from "../../pages/client";
 import { ElementAppPage } from "../../pages/ElementAppPage";
 import { Bot } from "../../pages/bot";
 
+/**
+ * Create a bot client using the supplied credentials, and wait for the key backup to be ready.
+ * @param page - the playwright `page` fixture
+ * @param homeserver - the homeserver to use
+ * @param credentials - the credentials to use for the bot client
+ */
+export async function createBot(
+    page: Page,
+    homeserver: HomeserverInstance,
+    credentials: Credentials,
+): Promise<{ botClient: Bot; recoveryKey: GeneratedSecretStorageKey; expectedBackupVersion: string }> {
+    // Visit the login page of the app, to load the matrix sdk
+    await page.goto("/#/login");
+
+    // wait for the page to load
+    await page.waitForSelector(".mx_AuthPage", { timeout: 30000 });
+
+    // Create a new bot client
+    const botClient = new Bot(page, homeserver, {
+        bootstrapCrossSigning: true,
+        bootstrapSecretStorage: true,
+    });
+    botClient.setCredentials(credentials);
+    // Backup is prepared in the background. Poll until it is ready.
+    const botClientHandle = await botClient.prepareClient();
+    let expectedBackupVersion: string;
+    await expect
+        .poll(async () => {
+            expectedBackupVersion = await botClientHandle.evaluate((cli) =>
+                cli.getCrypto()!.getActiveSessionBackupVersion(),
+            );
+            return expectedBackupVersion;
+        })
+        .not.toBe(null);
+
+    const recoveryKey = await botClient.getRecoveryKey();
+
+    return { botClient, recoveryKey, expectedBackupVersion };
+}
+
 /**
  * wait for the given client to receive an incoming verification request, and automatically accept it
  *
@@ -59,7 +100,7 @@ export function handleSasVerification(verifier: JSHandle<Verifier>): Promise<Emo
         return new Promise<EmojiMapping[]>((resolve) => {
             const onShowSas = (event: ShowSasCallbacks) => {
                 verifier.off("show_sas" as VerifierEvent, onShowSas);
-                event.confirm();
+                void event.confirm();
                 resolve(event.sas.emoji);
             };
 
@@ -138,22 +179,9 @@ export async function checkDeviceIsConnectedKeyBackup(
  *
  * If a `securityKey` is given, verifies the new device using the key.
  */
-export async function logIntoElement(
-    page: Page,
-    homeserver: HomeserverInstance,
-    credentials: Credentials,
-    securityKey?: string,
-) {
+export async function logIntoElement(page: Page, credentials: Credentials, securityKey?: string) {
     await page.goto("/#/login");
 
-    // select homeserver
-    await page.getByRole("button", { name: "Edit" }).click();
-    await page.getByRole("textbox", { name: "Other homeserver" }).fill(homeserver.config.baseUrl);
-    await page.getByRole("button", { name: "Continue", exact: true }).click();
-
-    // wait for the dialog to go away
-    await expect(page.locator(".mx_ServerPickerDialog")).not.toBeVisible();
-
     await page.getByRole("textbox", { name: "Username" }).fill(credentials.userId);
     await page.getByPlaceholder("Password").fill(credentials.password);
     await page.getByRole("button", { name: "Sign in" }).click();
@@ -220,11 +248,7 @@ export async function doTwoWaySasVerification(page: Page, verifier: JSHandle<Ver
     for (let i = 0; i < emojis.length; i++) {
         const emoji = emojis[i];
         const emojiBlock = emojiBlocks.nth(i);
-        const textContent = await emojiBlock.textContent();
-        // VerificationShowSas munges the case of the emoji descriptions returned by the js-sdk before
-        // displaying them. Once we drop support for legacy crypto, that code can go away, and so can the
-        // case-munging here.
-        expect(textContent.toLowerCase()).toEqual(emoji[0] + emoji[1].toLowerCase());
+        await expect(emojiBlock).toHaveText(emoji[0] + emoji[1]);
     }
 }
 
@@ -330,7 +354,7 @@ export async function autoJoin(client: Client) {
     await client.evaluate((cli) => {
         cli.on(window.matrixcs.RoomMemberEvent.Membership, (event, member) => {
             if (member.membership === "invite" && member.userId === cli.getUserId()) {
-                cli.joinRoom(member.roomId);
+                void cli.joinRoom(member.roomId);
             }
         });
     });
diff --git a/playwright/e2e/csAPI.ts b/playwright/e2e/csAPI.ts
new file mode 100644
index 00000000000..4153d09199c
--- /dev/null
+++ b/playwright/e2e/csAPI.ts
@@ -0,0 +1,39 @@
+/*
+Copyright 2024 New Vector Ltd.
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+Please see LICENSE files in the repository root for full details.
+*/
+
+import { APIRequestContext } from "playwright-core";
+import { KeyBackupInfo } from "matrix-js-sdk/src/crypto-api";
+
+import { HomeserverInstance } from "../plugins/homeserver";
+import { ClientServerApi } from "../plugins/utils/api.ts";
+
+/**
+ * A small subset of the Client-Server API used to manipulate the state of the
+ * account on the homeserver independently of the client under test.
+ */
+export class TestClientServerAPI extends ClientServerApi {
+    public constructor(
+        request: APIRequestContext,
+        homeserver: HomeserverInstance,
+        private accessToken: string,
+    ) {
+        super(homeserver.baseUrl);
+        this.setRequest(request);
+    }
+
+    public async getCurrentBackupInfo(): Promise<KeyBackupInfo | null> {
+        return this.request("GET", `/v3/room_keys/version`, this.accessToken);
+    }
+
+    /**
+     * Calls the API directly to delete the given backup version
+     * @param version The version to delete
+     */
+    public async deleteBackupVersion(version: string): Promise<void> {
+        await this.request("DELETE", `/v3/room_keys/version/${version}`, this.accessToken);
+    }
+}
diff --git a/playwright/e2e/editing/editing.spec.ts b/playwright/e2e/editing/editing.spec.ts
index e22ec250b98..934c4aa42ec 100644
--- a/playwright/e2e/editing/editing.spec.ts
+++ b/playwright/e2e/editing/editing.spec.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -12,6 +12,7 @@ import type { EventType, IContent, ISendEventResponse, MsgType, Visibility } fro
 import { expect, test } from "../../element-web-test";
 import { ElementAppPage } from "../../pages/ElementAppPage";
 import { SettingLevel } from "../../../src/settings/SettingLevel";
+import { isDendrite } from "../../plugins/homeserver/dendrite";
 
 async function sendEvent(app: ElementAppPage, roomId: string): Promise<ISendEventResponse> {
     return app.client.sendEvent(roomId, null, "m.room.message" as EventType, {
@@ -31,6 +32,8 @@ function mkPadding(n: number): IContent {
 }
 
 test.describe("Editing", () => {
+    test.skip(isDendrite, "due to a Dendrite bug https://github.com/element-hq/dendrite/issues/3488");
+
     // Edit "Message"
     const editLastMessage = async (page: Page, edit: string) => {
         const eventTile = page.locator(".mx_RoomView_MessageList .mx_EventTile_last");
diff --git a/playwright/e2e/file-upload/image-upload.spec.ts b/playwright/e2e/file-upload/image-upload.spec.ts
index 76782e90e8b..ad445ab1d96 100644
--- a/playwright/e2e/file-upload/image-upload.spec.ts
+++ b/playwright/e2e/file-upload/image-upload.spec.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/playwright/e2e/forgot-password/forgot-password.spec.ts b/playwright/e2e/forgot-password/forgot-password.spec.ts
index 0a12514d9ec..af4e6def7ed 100644
--- a/playwright/e2e/forgot-password/forgot-password.spec.ts
+++ b/playwright/e2e/forgot-password/forgot-password.spec.ts
@@ -2,29 +2,44 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
-import { expect, test } from "../../element-web-test";
+import { expect, test as base } from "../../element-web-test";
 import { selectHomeserver } from "../utils";
+import { emailHomeserver } from "../../plugins/homeserver/synapse/emailHomeserver.ts";
+import { isDendrite } from "../../plugins/homeserver/dendrite";
+import { Credentials } from "../../plugins/homeserver";
 
-const username = "user1234";
-// this has to be password-like enough to please zxcvbn. Needless to say it's just from pwgen.
-const password = "oETo7MPf0o";
 const email = "user@nowhere.dummy";
 
+const test = base.extend<{ credentials: Pick<Credentials, "username" | "password"> }>({
+    // eslint-disable-next-line no-empty-pattern
+    credentials: async ({}, use, testInfo) => {
+        await use({
+            username: `user_${testInfo.testId}`,
+            // this has to be password-like enough to please zxcvbn. Needless to say it's just from pwgen.
+            password: "oETo7MPf0o",
+        });
+    },
+});
+
+test.use(emailHomeserver);
+test.use({
+    config: {
+        // The only thing that we really *need* (otherwise Element refuses to load) is a default homeserver.
+        // We point that to a guaranteed-invalid domain.
+        default_server_config: {
+            "m.homeserver": {
+                base_url: "https://server.invalid",
+            },
+        },
+    },
+});
+
 test.describe("Forgot Password", () => {
-    test.use({
-        startHomeserverOpts: ({ mailhog }, use) =>
-            use({
-                template: "email",
-                variables: {
-                    SMTP_HOST: "host.containers.internal",
-                    SMTP_PORT: mailhog.instance.smtpPort,
-                },
-            }),
-    });
+    test.skip(isDendrite, "not yet wired up");
 
     test("renders properly", { tag: "@screenshot" }, async ({ page, homeserver }) => {
         await page.goto("/");
@@ -32,38 +47,42 @@ test.describe("Forgot Password", () => {
         await page.getByRole("link", { name: "Sign in" }).click();
 
         // need to select a homeserver at this stage, before entering the forgot password flow
-        await selectHomeserver(page, homeserver.config.baseUrl);
+        await selectHomeserver(page, homeserver.baseUrl);
 
         await page.getByRole("button", { name: "Forgot password?" }).click();
 
         await expect(page.getByRole("main")).toMatchScreenshot("forgot-password.png");
     });
 
-    test("renders email verification dialog properly", { tag: "@screenshot" }, async ({ page, homeserver }) => {
-        const user = await homeserver.registerUser(username, password);
+    test(
+        "renders email verification dialog properly",
+        { tag: "@screenshot" },
+        async ({ page, homeserver, credentials }) => {
+            const user = await homeserver.registerUser(credentials.username, credentials.password);
 
-        await homeserver.setThreepid(user.userId, "email", email);
+            await homeserver.setThreepid(user.userId, "email", email);
 
-        await page.goto("/");
+            await page.goto("/");
 
-        await page.getByRole("link", { name: "Sign in" }).click();
-        await selectHomeserver(page, homeserver.config.baseUrl);
+            await page.getByRole("link", { name: "Sign in" }).click();
+            await selectHomeserver(page, homeserver.baseUrl);
 
-        await page.getByRole("button", { name: "Forgot password?" }).click();
+            await page.getByRole("button", { name: "Forgot password?" }).click();
 
-        await page.getByRole("textbox", { name: "Email address" }).fill(email);
+            await page.getByRole("textbox", { name: "Email address" }).fill(email);
 
-        await page.getByRole("button", { name: "Send email" }).click();
+            await page.getByRole("button", { name: "Send email" }).click();
 
-        await page.getByRole("button", { name: "Next" }).click();
+            await page.getByRole("button", { name: "Next" }).click();
 
-        await page.getByRole("textbox", { name: "New Password", exact: true }).fill(password);
-        await page.getByRole("textbox", { name: "Confirm new password", exact: true }).fill(password);
+            await page.getByRole("textbox", { name: "New Password", exact: true }).fill(credentials.password);
+            await page.getByRole("textbox", { name: "Confirm new password", exact: true }).fill(credentials.password);
 
-        await page.getByRole("button", { name: "Reset password" }).click();
+            await page.getByRole("button", { name: "Reset password" }).click();
 
-        await expect(page.getByRole("button", { name: "Resend" })).toBeInViewport();
+            await expect(page.getByRole("button", { name: "Resend" })).toBeInViewport();
 
-        await expect(page.locator(".mx_Dialog")).toMatchScreenshot("forgot-password-verify-email.png");
-    });
+            await expect(page.locator(".mx_Dialog")).toMatchScreenshot("forgot-password-verify-email.png");
+        },
+    );
 });
diff --git a/playwright/e2e/integration-manager/get-openid-token.spec.ts b/playwright/e2e/integration-manager/get-openid-token.spec.ts
index 48d52d35fa4..38da5c3de5d 100644
--- a/playwright/e2e/integration-manager/get-openid-token.spec.ts
+++ b/playwright/e2e/integration-manager/get-openid-token.spec.ts
@@ -2,13 +2,14 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022, 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 import type { Page } from "@playwright/test";
 import { test, expect } from "../../element-web-test";
 import { openIntegrationManager } from "./utils";
+import type { UserWidget } from "../../../src/utils/WidgetUtils-types.ts";
 
 const ROOM_NAME = "Integration Manager Test";
 
@@ -92,7 +93,7 @@ test.describe("Integration Manager: Get OpenID Token", () => {
                     },
                 },
                 id: "integration-manager",
-            },
+            } as unknown as UserWidget,
         });
 
         // Succeed when checking the token is valid
diff --git a/playwright/e2e/integration-manager/kick.spec.ts b/playwright/e2e/integration-manager/kick.spec.ts
index 59c2703a18d..b1aa9eff526 100644
--- a/playwright/e2e/integration-manager/kick.spec.ts
+++ b/playwright/e2e/integration-manager/kick.spec.ts
@@ -2,13 +2,14 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022, 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 import type { Page } from "@playwright/test";
 import { test, expect } from "../../element-web-test";
 import { openIntegrationManager } from "./utils";
+import type { UserWidget } from "../../../src/utils/WidgetUtils-types.ts";
 
 const ROOM_NAME = "Integration Manager Test";
 const USER_DISPLAY_NAME = "Alice";
@@ -68,29 +69,13 @@ async function sendActionFromIntegrationManager(
     await iframe.getByRole("button", { name: "Press to send action" }).click();
 }
 
-async function clickUntilGone(page: Page, selector: string, attempt = 0) {
-    if (attempt === 11) {
-        throw new Error("clickUntilGone attempt count exceeded");
-    }
-
-    await page.locator(selector).last().click();
-
-    const count = await page.locator(selector).count();
-    if (count > 0) {
-        return clickUntilGone(page, selector, ++attempt);
-    }
-}
-
 async function expectKickedMessage(page: Page, shouldExist: boolean) {
-    // Expand any event summaries, we can't use a click multiple here because clicking one might de-render others
-    // This is quite horrible but seems the most stable way of clicking 0-N buttons,
-    // one at a time with a full re-evaluation after each click
-    await clickUntilGone(page, ".mx_GenericEventListSummary_toggle[aria-expanded=false]");
-
-    // Check for the event message (or lack thereof)
-    await expect(page.getByText(`${USER_DISPLAY_NAME} removed ${BOT_DISPLAY_NAME}: ${KICK_REASON}`)).toBeVisible({
-        visible: shouldExist,
-    });
+    await expect(async () => {
+        await page.locator(".mx_GenericEventListSummary_toggle[aria-expanded=false]").last().click();
+        await expect(page.getByText(`${USER_DISPLAY_NAME} removed ${BOT_DISPLAY_NAME}: ${KICK_REASON}`)).toBeVisible({
+            visible: shouldExist,
+        });
+    }).toPass();
 }
 
 test.describe("Integration Manager: Kick", () => {
@@ -136,7 +121,7 @@ test.describe("Integration Manager: Kick", () => {
                     },
                 },
                 id: "integration-manager",
-            },
+            } as unknown as UserWidget,
         });
 
         // Succeed when checking the token is valid
diff --git a/playwright/e2e/integration-manager/read_events.spec.ts b/playwright/e2e/integration-manager/read_events.spec.ts
index 791d5bd725b..6375f3c7a22 100644
--- a/playwright/e2e/integration-manager/read_events.spec.ts
+++ b/playwright/e2e/integration-manager/read_events.spec.ts
@@ -2,13 +2,14 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022, 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 import type { Page } from "@playwright/test";
 import { test, expect } from "../../element-web-test";
 import { openIntegrationManager } from "./utils";
+import type { UserWidget } from "../../../src/utils/WidgetUtils-types.ts";
 
 const ROOM_NAME = "Integration Manager Test";
 
@@ -107,7 +108,7 @@ test.describe("Integration Manager: Read Events", () => {
                     },
                 },
                 id: "integration-manager",
-            },
+            } as unknown as UserWidget,
         });
 
         // Succeed when checking the token is valid
diff --git a/playwright/e2e/integration-manager/send_event.spec.ts b/playwright/e2e/integration-manager/send_event.spec.ts
index 363719d8f14..7edcf9812b8 100644
--- a/playwright/e2e/integration-manager/send_event.spec.ts
+++ b/playwright/e2e/integration-manager/send_event.spec.ts
@@ -2,13 +2,14 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022, 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 import type { Page } from "@playwright/test";
 import { test, expect } from "../../element-web-test";
 import { openIntegrationManager } from "./utils";
+import type { UserWidget } from "../../../src/utils/WidgetUtils-types.ts";
 
 const ROOM_NAME = "Integration Manager Test";
 
@@ -113,7 +114,7 @@ test.describe("Integration Manager: Send Event", () => {
                     },
                 },
                 id: "integration-manager",
-            },
+            } as unknown as UserWidget,
         });
 
         // Succeed when checking the token is valid
diff --git a/playwright/e2e/integration-manager/utils.ts b/playwright/e2e/integration-manager/utils.ts
index a6a11473e3a..07acb3c9c10 100644
--- a/playwright/e2e/integration-manager/utils.ts
+++ b/playwright/e2e/integration-manager/utils.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022, 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/playwright/e2e/invite/invite-dialog.spec.ts b/playwright/e2e/invite/invite-dialog.spec.ts
index eb434eb5b56..73238f8c3dc 100644
--- a/playwright/e2e/invite/invite-dialog.spec.ts
+++ b/playwright/e2e/invite/invite-dialog.spec.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2023 Suguru Hirahara
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/playwright/e2e/knock/create-knock-room.spec.ts b/playwright/e2e/knock/create-knock-room.spec.ts
index 12a5a666eba..29733481ddc 100644
--- a/playwright/e2e/knock/create-knock-room.spec.ts
+++ b/playwright/e2e/knock/create-knock-room.spec.ts
@@ -2,15 +2,17 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022, 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 import { test, expect } from "../../element-web-test";
 import { waitForRoom } from "../utils";
 import { Filter } from "../../pages/Spotlight";
+import { isDendrite } from "../../plugins/homeserver/dendrite";
 
 test.describe("Create Knock Room", () => {
+    test.skip(isDendrite, "Dendrite does not have support for knocking");
     test.use({
         displayName: "Alice",
         labsFlags: ["feature_ask_to_join"],
diff --git a/playwright/e2e/knock/knock-into-room.spec.ts b/playwright/e2e/knock/knock-into-room.spec.ts
index e04806f84c3..9c2f1ee76be 100644
--- a/playwright/e2e/knock/knock-into-room.spec.ts
+++ b/playwright/e2e/knock/knock-into-room.spec.ts
@@ -4,7 +4,7 @@ Copyright 2023 Mikhail Aheichyk
 Copyright 2023 Nordeck IT + Consulting GmbH.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -13,8 +13,10 @@ import { type Visibility } from "matrix-js-sdk/src/matrix";
 import { test, expect } from "../../element-web-test";
 import { waitForRoom } from "../utils";
 import { Filter } from "../../pages/Spotlight";
+import { isDendrite } from "../../plugins/homeserver/dendrite";
 
 test.describe("Knock Into Room", () => {
+    test.skip(isDendrite, "Dendrite does not have support for knocking");
     test.use({
         displayName: "Alice",
         labsFlags: ["feature_ask_to_join"],
diff --git a/playwright/e2e/knock/manage-knocks.spec.ts b/playwright/e2e/knock/manage-knocks.spec.ts
index b2e1fc9a398..3f4c9616caf 100644
--- a/playwright/e2e/knock/manage-knocks.spec.ts
+++ b/playwright/e2e/knock/manage-knocks.spec.ts
@@ -4,14 +4,16 @@ Copyright 2023 Mikhail Aheichyk
 Copyright 2023 Nordeck IT + Consulting GmbH.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 import { test, expect } from "../../element-web-test";
 import { waitForRoom } from "../utils";
+import { isDendrite } from "../../plugins/homeserver/dendrite";
 
 test.describe("Manage Knocks", () => {
+    test.skip(isDendrite, "Dendrite does not have support for knocking");
     test.use({
         displayName: "Alice",
         labsFlags: ["feature_ask_to_join"],
@@ -50,7 +52,7 @@ test.describe("Manage Knocks", () => {
     });
 
     test("should deny knock using bar", async ({ page, app, bot, room }) => {
-        bot.knockRoom(room.roomId);
+        await bot.knockRoom(room.roomId);
 
         const roomKnocksBar = page.locator(".mx_RoomKnocksBar");
         await expect(roomKnocksBar.getByRole("heading", { name: "Asking to join" })).toBeVisible();
diff --git a/playwright/e2e/lazy-loading/lazy-loading.spec.ts b/playwright/e2e/lazy-loading/lazy-loading.spec.ts
index c931bcfb1ff..06fb0b3a71e 100644
--- a/playwright/e2e/lazy-loading/lazy-loading.spec.ts
+++ b/playwright/e2e/lazy-loading/lazy-loading.spec.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -10,8 +10,12 @@ import { Bot } from "../../pages/bot";
 import type { Locator, Page } from "@playwright/test";
 import type { ElementAppPage } from "../../pages/ElementAppPage";
 import { test, expect } from "../../element-web-test";
+import { Credentials } from "../../plugins/homeserver";
+import { isDendrite } from "../../plugins/homeserver/dendrite";
 
 test.describe("Lazy Loading", () => {
+    test.skip(isDendrite, "due to a Dendrite bug https://github.com/element-hq/dendrite/issues/3488");
+
     const charlies: Bot[] = [];
 
     test.use({
@@ -25,21 +29,28 @@ test.describe("Lazy Loading", () => {
         });
     });
 
-    test.beforeEach(async ({ page, homeserver, user, bot }) => {
+    test.beforeEach(async ({ page, homeserver, user, bot, app }) => {
         for (let i = 1; i <= 10; i++) {
             const displayName = `Charly #${i}`;
             const bot = new Bot(page, homeserver, { displayName, startClient: false, autoAcceptInvites: false });
             charlies.push(bot);
         }
+        await app.client.network.setupRoute();
     });
 
     const name = "Lazy Loading Test";
-    const alias = "#lltest:localhost";
     const charlyMsg1 = "hi bob!";
     const charlyMsg2 = "how's it going??";
     let roomId: string;
 
-    async function setupRoomWithBobAliceAndCharlies(page: Page, app: ElementAppPage, bob: Bot, charlies: Bot[]) {
+    async function setupRoomWithBobAliceAndCharlies(
+        page: Page,
+        app: ElementAppPage,
+        user: Credentials,
+        bob: Bot,
+        charlies: Bot[],
+    ) {
+        const alias = `#lltest:${user.homeServer}`;
         const visibility = await page.evaluate(() => (window as any).matrixcs.Visibility.Public);
         roomId = await bob.createRoom({
             name,
@@ -77,7 +88,7 @@ test.describe("Lazy Loading", () => {
     }
 
     function getMemberInMemberlist(page: Page, name: string): Locator {
-        return page.locator(".mx_MemberList .mx_EntityTile_name").filter({ hasText: name });
+        return page.locator(".mx_MemberListView .mx_MemberTileView_name").filter({ hasText: name });
     }
 
     async function checkMemberList(page: Page, charlies: Bot[]) {
@@ -94,7 +105,13 @@ test.describe("Lazy Loading", () => {
         }
     }
 
-    async function joinCharliesWhileAliceIsOffline(page: Page, app: ElementAppPage, charlies: Bot[]) {
+    async function joinCharliesWhileAliceIsOffline(
+        page: Page,
+        app: ElementAppPage,
+        user: Credentials,
+        charlies: Bot[],
+    ) {
+        const alias = `#lltest:${user.homeServer}`;
         await app.client.network.goOffline();
         for (const charly of charlies) {
             await charly.joinRoom(alias);
@@ -106,19 +123,19 @@ test.describe("Lazy Loading", () => {
         await app.client.waitForNextSync();
     }
 
-    test("should handle lazy loading properly even when offline", async ({ page, app, bot }) => {
+    test("should handle lazy loading properly even when offline", async ({ page, app, bot, user }) => {
         test.slow();
         const charly1to5 = charlies.slice(0, 5);
         const charly6to10 = charlies.slice(5);
 
         // Set up room with alice, bob & charlies 1-5
-        await setupRoomWithBobAliceAndCharlies(page, app, bot, charly1to5);
+        await setupRoomWithBobAliceAndCharlies(page, app, user, bot, charly1to5);
         // Alice should see 2 messages from every charly with the correct display name
         await checkPaginatedDisplayNames(app, charly1to5);
 
         await openMemberlist(app);
         await checkMemberList(page, charly1to5);
-        await joinCharliesWhileAliceIsOffline(page, app, charly6to10);
+        await joinCharliesWhileAliceIsOffline(page, app, user, charly6to10);
         await checkMemberList(page, charly6to10);
 
         for (const charly of charlies) {
diff --git a/playwright/e2e/left-panel/left-panel.spec.ts b/playwright/e2e/left-panel/left-panel.spec.ts
index 649302d7bd9..3850df5cd07 100644
--- a/playwright/e2e/left-panel/left-panel.spec.ts
+++ b/playwright/e2e/left-panel/left-panel.spec.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 Suguru Hirahara
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/playwright/e2e/location/location.spec.ts b/playwright/e2e/location/location.spec.ts
index e0c23d6c22f..6f4db3ae72d 100644
--- a/playwright/e2e/location/location.spec.ts
+++ b/playwright/e2e/location/location.spec.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -10,7 +10,8 @@ import { Locator, Page } from "@playwright/test";
 
 import { test, expect } from "../../element-web-test";
 
-test.describe("Location sharing", () => {
+// Firefox headless lacks WebGL support https://bugzilla.mozilla.org/show_bug.cgi?id=1375585
+test.describe("Location sharing", { tag: "@no-firefox" }, () => {
     const selectLocationShareTypeOption = (page: Page, shareType: string): Locator => {
         return page.getByTestId(`share-location-option-${shareType}`);
     };
diff --git a/playwright/e2e/login/consent.spec.ts b/playwright/e2e/login/consent.spec.ts
index 4d8dd821e0c..aab190298fa 100644
--- a/playwright/e2e/login/consent.spec.ts
+++ b/playwright/e2e/login/consent.spec.ts
@@ -2,18 +2,19 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 import { test, expect } from "../../element-web-test";
+import { consentHomeserver } from "../../plugins/homeserver/synapse/consentHomeserver.ts";
 
-test.describe("Consent", () => {
-    test.use({
-        startHomeserverOpts: "consent",
-        displayName: "Bob",
-    });
+test.use(consentHomeserver);
+test.use({
+    displayName: "Bob",
+});
 
+test.describe("Consent", () => {
     test("should prompt the user to consent to terms when server deems it necessary", async ({
         context,
         page,
diff --git a/playwright/e2e/login/login.spec.ts b/playwright/e2e/login/login-consent.spec.ts
similarity index 65%
rename from playwright/e2e/login/login.spec.ts
rename to playwright/e2e/login/login-consent.spec.ts
index e1307f7402d..d92b427b931 100644
--- a/playwright/e2e/login/login.spec.ts
+++ b/playwright/e2e/login/login-consent.spec.ts
@@ -2,18 +2,19 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 import { Page } from "playwright-core";
 
 import { expect, test } from "../../element-web-test";
-import { doTokenRegistration } from "./utils";
-import { isDendrite } from "../../plugins/homeserver/dendrite";
 import { selectHomeserver } from "../utils";
 import { Credentials, HomeserverInstance } from "../../plugins/homeserver";
+import { consentHomeserver } from "../../plugins/homeserver/synapse/consentHomeserver.ts";
+import { isDendrite } from "../../plugins/homeserver/dendrite";
 
+// This test requires fixed credentials for the device signing keys below to work
 const username = "user1234";
 const password = "p4s5W0rD";
 
@@ -68,26 +69,55 @@ const DEVICE_SIGNING_KEYS_BODY = {
     },
 };
 
-async function login(page: Page, homeserver: HomeserverInstance) {
+async function login(page: Page, homeserver: HomeserverInstance, credentials: Credentials) {
     await page.getByRole("link", { name: "Sign in" }).click();
-    await selectHomeserver(page, homeserver.config.baseUrl);
+    await selectHomeserver(page, homeserver.baseUrl);
 
-    await page.getByRole("textbox", { name: "Username" }).fill(username);
-    await page.getByPlaceholder("Password").fill(password);
+    await page.getByRole("textbox", { name: "Username" }).fill(credentials.username);
+    await page.getByPlaceholder("Password").fill(credentials.password);
     await page.getByRole("button", { name: "Sign in" }).click();
 }
 
-test.describe("Login", () => {
-    test.describe("Password login", () => {
-        test.use({ startHomeserverOpts: "consent" });
+// This test suite uses the same userId for all tests in the suite
+// due to DEVICE_SIGNING_KEYS_BODY being specific to that userId,
+// so we restart the Synapse container to make it forget everything.
+test.use(consentHomeserver);
+test.use({
+    config: {
+        // The only thing that we really *need* (otherwise Element refuses to load) is a default homeserver.
+        // We point that to a guaranteed-invalid domain.
+        default_server_config: {
+            "m.homeserver": {
+                base_url: "https://server.invalid",
+            },
+        },
+    },
+    context: async ({ context, homeserver }, use) => {
+        // Restart the homeserver to wipe its in-memory db so we can reuse the same user ID without cross-signing prompts
+        await homeserver.restart();
+        await use(context);
+    },
+    credentials: async ({ context, homeserver }, use) => {
+        const displayName = "Dave";
+        const credentials = await homeserver.registerUser(username, password, displayName);
+        console.log(`Registered test user @user:localhost with displayname ${displayName}`);
+
+        await use({
+            ...credentials,
+            displayName,
+        });
 
-        let creds: Credentials;
+        // Restart the homeserver to wipe its in-memory db so we can reuse the same user ID without cross-signing prompts
+        await homeserver.restart();
+    },
+});
 
-        test.beforeEach(async ({ homeserver }) => {
-            creds = await homeserver.registerUser(username, password);
-        });
+test.describe("Login", () => {
+    test.describe("Password login", () => {
+        test.skip(isDendrite, "Dendrite lacks support for MSC3967 so requires additional auth here");
 
         test("Loads the welcome page by default; then logs in with an existing account and lands on the home screen", async ({
+            credentials,
             page,
             homeserver,
             checkA11y,
@@ -101,7 +131,7 @@ test.describe("Login", () => {
             await page.getByRole("link", { name: "Sign in" }).click();
 
             // first pick the homeserver, as otherwise the user picker won't be visible
-            await selectHomeserver(page, homeserver.config.baseUrl);
+            await selectHomeserver(page, homeserver.baseUrl);
 
             await page.getByRole("button", { name: "Edit" }).click();
 
@@ -114,23 +144,23 @@ test.describe("Login", () => {
             await expect(page.locator(".mx_ServerPicker_server")).toHaveText("server.invalid");
 
             // switch back to the custom homeserver
-            await selectHomeserver(page, homeserver.config.baseUrl);
+            await selectHomeserver(page, homeserver.baseUrl);
 
             await expect(page.getByRole("textbox", { name: "Username" })).toBeVisible();
             // Disabled because flaky - see https://github.com/vector-im/element-web/issues/24688
             // cy.percySnapshot("Login");
             await checkA11y();
 
-            await page.getByRole("textbox", { name: "Username" }).fill(username);
-            await page.getByPlaceholder("Password").fill(password);
+            await page.getByRole("textbox", { name: "Username" }).fill(credentials.username);
+            await page.getByPlaceholder("Password").fill(credentials.password);
             await page.getByRole("button", { name: "Sign in" }).click();
 
             await expect(page).toHaveURL(/\/#\/home$/);
         });
 
-        test("Follows the original link after login", async ({ page, homeserver }) => {
+        test("Follows the original link after login", async ({ page, homeserver, credentials }) => {
             await page.goto("/#/room/!room:id"); // should redirect to the welcome page
-            await login(page, homeserver);
+            await login(page, homeserver, credentials);
 
             await expect(page).toHaveURL(/\/#\/room\/!room:id$/);
             await expect(page.getByRole("button", { name: "Join the discussion" })).toBeVisible();
@@ -141,18 +171,19 @@ test.describe("Login", () => {
                 page,
                 homeserver,
                 request,
+                credentials,
             }) => {
-                const res = await request.post(
-                    `${homeserver.config.baseUrl}/_matrix/client/v3/keys/device_signing/upload`,
-                    { headers: { Authorization: `Bearer ${creds.accessToken}` }, data: DEVICE_SIGNING_KEYS_BODY },
-                );
+                const res = await request.post(`${homeserver.baseUrl}/_matrix/client/v3/keys/device_signing/upload`, {
+                    headers: { Authorization: `Bearer ${credentials.accessToken}` },
+                    data: DEVICE_SIGNING_KEYS_BODY,
+                });
                 if (res.status() / 100 !== 2) {
                     console.log("Uploading dummy keys failed", await res.json());
                 }
                 expect(res.status() / 100).toEqual(2);
 
                 await page.goto("/");
-                await login(page, homeserver);
+                await login(page, homeserver, credentials);
 
                 await expect(page.getByRole("heading", { name: "Verify this device", level: 1 })).toBeVisible();
 
@@ -170,10 +201,14 @@ test.describe("Login", () => {
                     page,
                     homeserver,
                     request,
+                    credentials,
                 }) => {
                     const res = await request.post(
-                        `${homeserver.config.baseUrl}/_matrix/client/v3/keys/device_signing/upload`,
-                        { headers: { Authorization: `Bearer ${creds.accessToken}` }, data: DEVICE_SIGNING_KEYS_BODY },
+                        `${homeserver.baseUrl}/_matrix/client/v3/keys/device_signing/upload`,
+                        {
+                            headers: { Authorization: `Bearer ${credentials.accessToken}` },
+                            data: DEVICE_SIGNING_KEYS_BODY,
+                        },
                     );
                     if (res.status() / 100 !== 2) {
                         console.log("Uploading dummy keys failed", await res.json());
@@ -181,7 +216,7 @@ test.describe("Login", () => {
                     expect(res.status() / 100).toEqual(2);
 
                     await page.goto("/");
-                    await login(page, homeserver);
+                    await login(page, homeserver, credentials);
 
                     await expect(page.getByRole("heading", { name: "Verify this device", level: 1 })).toBeVisible();
 
@@ -200,11 +235,15 @@ test.describe("Login", () => {
                     page,
                     homeserver,
                     request,
+                    credentials,
                 }) => {
-                    console.log(`uid ${creds.userId} body`, DEVICE_SIGNING_KEYS_BODY);
+                    console.log(`uid ${credentials.userId} body`, DEVICE_SIGNING_KEYS_BODY);
                     const res = await request.post(
-                        `${homeserver.config.baseUrl}/_matrix/client/v3/keys/device_signing/upload`,
-                        { headers: { Authorization: `Bearer ${creds.accessToken}` }, data: DEVICE_SIGNING_KEYS_BODY },
+                        `${homeserver.baseUrl}/_matrix/client/v3/keys/device_signing/upload`,
+                        {
+                            headers: { Authorization: `Bearer ${credentials.accessToken}` },
+                            data: DEVICE_SIGNING_KEYS_BODY,
+                        },
                     );
                     if (res.status() / 100 !== 2) {
                         console.log("Uploading dummy keys failed", await res.json());
@@ -212,9 +251,9 @@ test.describe("Login", () => {
                     expect(res.status() / 100).toEqual(2);
 
                     await page.goto("/");
-                    await login(page, homeserver);
+                    await login(page, homeserver, credentials);
 
-                    const h1 = await page.getByRole("heading", { name: "Verify this device", level: 1 });
+                    const h1 = page.getByRole("heading", { name: "Verify this device", level: 1 });
                     await expect(h1).toBeVisible();
 
                     await expect(h1.locator(".mx_CompleteSecurity_skip")).toHaveCount(0);
@@ -223,32 +262,7 @@ test.describe("Login", () => {
         });
     });
 
-    // tests for old-style SSO login, in which we exchange tokens with Synapse, and Synapse talks to an auth server
-    test.describe("SSO login", () => {
-        test.skip(isDendrite, "does not yet support SSO");
-
-        test.use({
-            startHomeserverOpts: ({ oAuthServer }, use) =>
-                use({
-                    template: "default",
-                    oAuthServerPort: oAuthServer.port,
-                }),
-        });
-
-        test("logs in with SSO and lands on the home screen", async ({ page, homeserver }) => {
-            // If this test fails with a screen showing "Timeout connecting to remote server", it is most likely due to
-            // your firewall settings: Synapse is unable to reach the OIDC server.
-            //
-            // If you are using ufw, try something like:
-            //    sudo ufw allow in on docker0
-            //
-            await doTokenRegistration(page, homeserver);
-        });
-    });
-
     test.describe("logout", () => {
-        test.use({ startHomeserverOpts: "consent" });
-
         test("should go to login page on logout", async ({ page, user }) => {
             await page.getByRole("button", { name: "User menu" }).click();
             await expect(page.getByText(user.displayName, { exact: true })).toBeVisible();
@@ -260,29 +274,4 @@ test.describe("Login", () => {
             await expect(page).toHaveURL(/\/#\/login$/);
         });
     });
-
-    test.describe("logout with logout_redirect_url", () => {
-        test.use({
-            startHomeserverOpts: "consent",
-            config: {
-                // We redirect to decoder-ring because it's a predictable page that isn't Element itself.
-                // We could use example.org, matrix.org, or something else, however this puts dependency of external
-                // infrastructure on our tests. In the same vein, we don't really want to figure out how to ship a
-                // `test-landing.html` page when running with an uncontrolled Element (via `yarn start`).
-                // Using the decoder-ring is just as fine, and we can search for strategic names.
-                logout_redirect_url: "/decoder-ring/",
-            },
-        });
-
-        test("should respect logout_redirect_url", async ({ page, user }) => {
-            await page.getByRole("button", { name: "User menu" }).click();
-            await expect(page.getByText(user.displayName, { exact: true })).toBeVisible();
-
-            // give a change for the outstanding requests queue to settle before logging out
-            await page.waitForTimeout(2000);
-
-            await page.locator(".mx_UserMenu_contextMenu").getByRole("menuitem", { name: "Sign out" }).click();
-            await expect(page).toHaveURL(/\/decoder-ring\/$/);
-        });
-    });
 });
diff --git a/playwright/e2e/login/login-sso.spec.ts b/playwright/e2e/login/login-sso.spec.ts
new file mode 100644
index 00000000000..22428af5028
--- /dev/null
+++ b/playwright/e2e/login/login-sso.spec.ts
@@ -0,0 +1,29 @@
+/*
+Copyright 2024 New Vector Ltd.
+Copyright 2023 The Matrix.org Foundation C.I.C.
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+Please see LICENSE files in the repository root for full details.
+*/
+
+import { test } from "../../element-web-test";
+import { doTokenRegistration } from "./utils";
+import { isDendrite } from "../../plugins/homeserver/dendrite";
+import { legacyOAuthHomeserver } from "../../plugins/homeserver/synapse/legacyOAuthHomeserver.ts";
+
+test.use(legacyOAuthHomeserver);
+
+// tests for old-style SSO login, in which we exchange tokens with Synapse, and Synapse talks to an auth server
+test.describe("SSO login", () => {
+    test.skip(isDendrite, "does not yet support SSO");
+
+    test("logs in with SSO and lands on the home screen", async ({ page, homeserver }, testInfo) => {
+        // If this test fails with a screen showing "Timeout connecting to remote server", it is most likely due to
+        // your firewall settings: Synapse is unable to reach the OIDC server.
+        //
+        // If you are using ufw, try something like:
+        //    sudo ufw allow in on docker0
+        //
+        await doTokenRegistration(page, homeserver, testInfo);
+    });
+});
diff --git a/playwright/e2e/login/logout_redirect_url.spec.ts b/playwright/e2e/login/logout_redirect_url.spec.ts
new file mode 100644
index 00000000000..c27acf96bec
--- /dev/null
+++ b/playwright/e2e/login/logout_redirect_url.spec.ts
@@ -0,0 +1,35 @@
+/*
+Copyright 2024 New Vector Ltd.
+Copyright 2023 The Matrix.org Foundation C.I.C.
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+Please see LICENSE files in the repository root for full details.
+*/
+
+import { expect, test } from "../../element-web-test";
+import { consentHomeserver } from "../../plugins/homeserver/synapse/consentHomeserver.ts";
+
+test.use(consentHomeserver);
+test.use({
+    config: {
+        // We redirect to decoder-ring because it's a predictable page that isn't Element itself.
+        // We could use example.org, matrix.org, or something else, however this puts dependency of external
+        // infrastructure on our tests. In the same vein, we don't really want to figure out how to ship a
+        // `test-landing.html` page when running with an uncontrolled Element (via `yarn start`).
+        // Using the decoder-ring is just as fine, and we can search for strategic names.
+        logout_redirect_url: "/decoder-ring/",
+    },
+});
+
+test.describe("logout with logout_redirect_url", () => {
+    test("should respect logout_redirect_url", async ({ page, user }) => {
+        await page.getByRole("button", { name: "User menu" }).click();
+        await expect(page.getByText(user.displayName, { exact: true })).toBeVisible();
+
+        // give a change for the outstanding requests queue to settle before logging out
+        await page.waitForTimeout(2000);
+
+        await page.locator(".mx_UserMenu_contextMenu").getByRole("menuitem", { name: "Sign out" }).click();
+        await expect(page).toHaveURL(/\/decoder-ring\/$/);
+    });
+});
diff --git a/playwright/e2e/login/overwrite_login.spec.ts b/playwright/e2e/login/overwrite_login.spec.ts
index 6d06bbc4290..4beed00d120 100644
--- a/playwright/e2e/login/overwrite_login.spec.ts
+++ b/playwright/e2e/login/overwrite_login.spec.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -13,7 +13,7 @@ test.describe("Overwrite login action", () => {
     // This seems terminally flakey: https://github.com/element-hq/element-web/issues/27363
     // I tried verious things to try & deflake it, to no avail: https://github.com/matrix-org/matrix-react-sdk/pull/12506
     test.skip("Try replace existing login with new one", async ({ page, app, credentials, homeserver }) => {
-        await logIntoElement(page, homeserver, credentials);
+        await logIntoElement(page, credentials);
 
         const userMenu = await app.openUserMenu();
         await expect(userMenu.getByText(credentials.userId)).toBeVisible();
@@ -24,7 +24,7 @@ test.describe("Overwrite login action", () => {
         expect(credentials.userId).not.toBe(bobRegister.userId);
 
         const clientCredentials /* IMatrixClientCreds */ = {
-            homeserverUrl: homeserver.config.baseUrl,
+            homeserverUrl: homeserver.baseUrl,
             ...bobRegister,
         };
 
diff --git a/playwright/e2e/login/soft_logout.spec.ts b/playwright/e2e/login/soft_logout.spec.ts
index ca0c11132a3..2c9325e7571 100644
--- a/playwright/e2e/login/soft_logout.spec.ts
+++ b/playwright/e2e/login/soft_logout.spec.ts
@@ -2,121 +2,42 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
-import { Page } from "@playwright/test";
-
 import { test, expect } from "../../element-web-test";
-import { doTokenRegistration } from "./utils";
-import { Credentials } from "../../plugins/homeserver";
-import { isDendrite } from "../../plugins/homeserver/dendrite";
-
-test.describe("Soft logout", () => {
-    test.use({
-        displayName: "Alice",
-        startHomeserverOpts: ({ oAuthServer }, use) =>
-            use({
-                template: "default",
-                oAuthServerPort: oAuthServer.port,
-            }),
-    });
-
-    test.describe("with password user", () => {
-        test("shows the soft-logout page when a request fails, and allows a re-login", async ({ page, user }) => {
-            await interceptRequestsWithSoftLogout(page, user);
-            await expect(page.getByText("You're signed out")).toBeVisible();
-            await page.getByPlaceholder("Password").fill(user.password);
-            await page.getByPlaceholder("Password").press("Enter");
-
-            // back to the welcome page
-            await expect(page).toHaveURL(/\/#\/home/);
-            await expect(page.getByRole("heading", { name: `Welcome ${user.userId}`, exact: true })).toBeVisible();
-        });
-
-        test("still shows the soft-logout page when the page is reloaded after a soft-logout", async ({
-            page,
-            user,
-        }) => {
-            await interceptRequestsWithSoftLogout(page, user);
-            await expect(page.getByText("You're signed out")).toBeVisible();
-            await page.reload();
-            await expect(page.getByText("You're signed out")).toBeVisible();
-        });
-    });
-
-    test.describe("with SSO user", () => {
-        test.skip(isDendrite, "does not yet support SSO");
-
-        test.use({
-            user: async ({ page, homeserver }, use) => {
-                const user = await doTokenRegistration(page, homeserver);
-
-                // Eventually, we should end up at the home screen.
-                await expect(page).toHaveURL(/\/#\/home$/);
-                await expect(page.getByRole("heading", { name: "Welcome Alice", exact: true })).toBeVisible();
-
-                await use(user);
+import { interceptRequestsWithSoftLogout } from "./utils";
+
+test.use({
+    displayName: "Alice",
+    config: {
+        // The only thing that we really *need* (otherwise Element refuses to load) is a default homeserver.
+        // We point that to a guaranteed-invalid domain.
+        default_server_config: {
+            "m.homeserver": {
+                base_url: "https://server.invalid",
             },
-        });
-
-        test("shows the soft-logout page when a request fails, and allows a re-login", async ({ page, user }) => {
-            await expect(page.getByRole("heading", { name: "Welcome Alice", exact: true })).toBeVisible();
-
-            await interceptRequestsWithSoftLogout(page, user);
-
-            await expect(page.getByText("You're signed out")).toBeVisible();
-            await page.getByRole("button", { name: "Continue with OAuth test" }).click();
-
-            // click the submit button
-            await page.getByRole("button", { name: "Submit" }).click();
-
-            // Synapse prompts us to grant permission to Element
-            await expect(page.getByRole("heading", { name: "Continue to your account" })).toBeVisible();
-            await page.getByRole("link", { name: "Continue" }).click();
-
-            // back to the welcome page
-            await expect(page).toHaveURL(/\/#\/home$/);
-            await expect(page.getByRole("heading", { name: "Welcome Alice", exact: true })).toBeVisible();
-        });
-    });
+        },
+    },
 });
 
-/**
- * Intercept calls to /sync and have them fail with a soft-logout
- *
- * Any further requests to /sync with the same access token are blocked.
- */
-async function interceptRequestsWithSoftLogout(page: Page, user: Credentials): Promise<void> {
-    await page.route("**/_matrix/client/*/sync*", async (route, req) => {
-        const accessToken = await req.headerValue("Authorization");
-
-        // now, if the access token on this request matches the expired one, block it
-        if (accessToken === `Bearer ${user.accessToken}`) {
-            console.log("Intercepting request with soft-logged-out access token");
-            await route.fulfill({
-                status: 401,
-                json: {
-                    errcode: "M_UNKNOWN_TOKEN",
-                    error: "Soft logout",
-                    soft_logout: true,
-                },
-            });
-            return;
-        }
+test.describe("Soft logout with password user", () => {
+    test("shows the soft-logout page when a request fails, and allows a re-login", async ({ page, user }) => {
+        await interceptRequestsWithSoftLogout(page, user);
+        await expect(page.getByText("You're signed out")).toBeVisible();
+        await page.getByPlaceholder("Password").fill(user.password);
+        await page.getByPlaceholder("Password").press("Enter");
 
-        // otherwise, pass through as normal
-        await route.continue();
+        // back to the welcome page
+        await expect(page).toHaveURL(/\/#\/home/);
+        await expect(page.getByRole("heading", { name: "Now, let's help you get started", exact: true })).toBeVisible();
     });
 
-    const promise = page.waitForResponse((resp) => resp.url().includes("/sync") && resp.status() === 401);
-
-    // do something to make the active /sync return: create a new room
-    await page.evaluate(() => {
-        // don't wait for this to complete: it probably won't, because of the broken sync
-        window.mxMatrixClientPeg.get().createRoom({});
+    test("still shows the soft-logout page when the page is reloaded after a soft-logout", async ({ page, user }) => {
+        await interceptRequestsWithSoftLogout(page, user);
+        await expect(page.getByText("You're signed out")).toBeVisible();
+        await page.reload();
+        await expect(page.getByText("You're signed out")).toBeVisible();
     });
-
-    await promise;
-}
+});
diff --git a/playwright/e2e/login/soft_logout_oauth.spec.ts b/playwright/e2e/login/soft_logout_oauth.spec.ts
new file mode 100644
index 00000000000..f6814d0cf4a
--- /dev/null
+++ b/playwright/e2e/login/soft_logout_oauth.spec.ts
@@ -0,0 +1,59 @@
+/*
+Copyright 2024 New Vector Ltd.
+Copyright 2023 The Matrix.org Foundation C.I.C.
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+Please see LICENSE files in the repository root for full details.
+*/
+
+import { test, expect } from "../../element-web-test";
+import { doTokenRegistration, interceptRequestsWithSoftLogout } from "./utils";
+import { legacyOAuthHomeserver } from "../../plugins/homeserver/synapse/legacyOAuthHomeserver.ts";
+
+test.use({
+    displayName: "Alice",
+    config: {
+        // The only thing that we really *need* (otherwise Element refuses to load) is a default homeserver.
+        // We point that to a guaranteed-invalid domain.
+        default_server_config: {
+            "m.homeserver": {
+                base_url: "https://server.invalid",
+            },
+        },
+    },
+});
+
+test.use(legacyOAuthHomeserver);
+test.describe("Soft logout with SSO user", () => {
+    test.use({
+        user: async ({ page, homeserver }, use, testInfo) => {
+            const user = await doTokenRegistration(page, homeserver, testInfo);
+
+            // Eventually, we should end up at the home screen.
+            await expect(page).toHaveURL(/\/#\/home$/);
+            await expect(page.getByRole("heading", { name: "Welcome Alice", exact: true })).toBeVisible();
+
+            await use(user);
+        },
+    });
+
+    test("shows the soft-logout page when a request fails, and allows a re-login", async ({ page, user }) => {
+        await expect(page.getByRole("heading", { name: "Welcome Alice", exact: true })).toBeVisible();
+
+        await interceptRequestsWithSoftLogout(page, user);
+
+        await expect(page.getByText("You're signed out")).toBeVisible();
+        await page.getByRole("button", { name: "Continue with OAuth test" }).click();
+
+        // click the submit button
+        await page.getByRole("button", { name: "Submit" }).click();
+
+        // Synapse prompts us to grant permission to Element
+        await expect(page.getByRole("heading", { name: "Continue to your account" })).toBeVisible();
+        await page.getByRole("link", { name: "Continue" }).click();
+
+        // back to the welcome page
+        await expect(page).toHaveURL(/\/#\/home$/);
+        await expect(page.getByRole("heading", { name: "Welcome Alice", exact: true })).toBeVisible();
+    });
+});
diff --git a/playwright/e2e/login/utils.ts b/playwright/e2e/login/utils.ts
index dc856d586fe..59a5c330f30 100644
--- a/playwright/e2e/login/utils.ts
+++ b/playwright/e2e/login/utils.ts
@@ -2,11 +2,11 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
-import { Page, expect } from "@playwright/test";
+import { Page, expect, TestInfo } from "@playwright/test";
 
 import { Credentials, HomeserverInstance } from "../../plugins/homeserver";
 
@@ -15,12 +15,13 @@ import { Credentials, HomeserverInstance } from "../../plugins/homeserver";
 export async function doTokenRegistration(
     page: Page,
     homeserver: HomeserverInstance,
+    testInfo: TestInfo,
 ): Promise<Credentials & { displayName: string }> {
     await page.goto("/#/login");
 
     await page.getByRole("button", { name: "Edit" }).click();
-    await page.getByRole("textbox", { name: "Other homeserver" }).fill(homeserver.config.baseUrl);
-    await page.getByRole("button", { name: "Continue" }).click();
+    await page.getByRole("textbox", { name: "Other homeserver" }).fill(homeserver.baseUrl);
+    await page.getByRole("button", { name: "Continue", exact: true }).click();
     // wait for the dialog to go away
     await expect(page.locator(".mx_ServerPickerDialog")).toHaveCount(0);
 
@@ -35,7 +36,7 @@ export async function doTokenRegistration(
 
     // Synapse prompts us to pick a user ID
     await expect(page.getByRole("heading", { name: "Create your account" })).toBeVisible();
-    await page.getByRole("textbox", { name: "Username (required)" }).fill("alice");
+    await page.getByRole("textbox", { name: "Username (required)" }).fill(`alice_${testInfo.testId}`);
 
     // wait for username validation to start, and complete
     await expect(page.locator("#field-username-output")).toHaveText("");
@@ -56,5 +57,44 @@ export async function doTokenRegistration(
         homeServer: window.mxMatrixClientPeg.get().getHomeserverUrl(),
         password: null,
         displayName: "Alice",
+        username: window.mxMatrixClientPeg.get().getUserIdLocalpart(),
     }));
 }
+
+/**
+ * Intercept calls to /sync and have them fail with a soft-logout
+ *
+ * Any further requests to /sync with the same access token are blocked.
+ */
+export async function interceptRequestsWithSoftLogout(page: Page, user: Credentials): Promise<void> {
+    await page.route("**/_matrix/client/*/sync*", async (route, req) => {
+        const accessToken = await req.headerValue("Authorization");
+
+        // now, if the access token on this request matches the expired one, block it
+        if (accessToken === `Bearer ${user.accessToken}`) {
+            console.log("Intercepting request with soft-logged-out access token");
+            await route.fulfill({
+                status: 401,
+                json: {
+                    errcode: "M_UNKNOWN_TOKEN",
+                    error: "Soft logout",
+                    soft_logout: true,
+                },
+            });
+            return;
+        }
+
+        // otherwise, pass through as normal
+        await route.continue();
+    });
+
+    const promise = page.waitForResponse((resp) => resp.url().includes("/sync") && resp.status() === 401);
+
+    // do something to make the active /sync return: create a new room
+    await page.evaluate(() => {
+        // don't wait for this to complete: it probably won't, because of the broken sync
+        void window.mxMatrixClientPeg.get().createRoom({});
+    });
+
+    await promise;
+}
diff --git a/playwright/e2e/messages/messages.spec.ts b/playwright/e2e/messages/messages.spec.ts
index 1c518199a00..03c93d2620f 100644
--- a/playwright/e2e/messages/messages.spec.ts
+++ b/playwright/e2e/messages/messages.spec.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/playwright/e2e/oidc/index.ts b/playwright/e2e/oidc/index.ts
index 9403406d80c..bfd49b496a0 100644
--- a/playwright/e2e/oidc/index.ts
+++ b/playwright/e2e/oidc/index.ts
@@ -2,68 +2,14 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 import { API, Messages } from "mailhog";
 import { Page } from "@playwright/test";
 
-import { test as base, expect } from "../../element-web-test";
-import { MatrixAuthenticationService } from "../../plugins/matrix-authentication-service";
-import { StartHomeserverOpts } from "../../plugins/homeserver";
-
-export const test = base.extend<{
-    masPrepare: MatrixAuthenticationService;
-    mas: MatrixAuthenticationService;
-}>({
-    // There's a bit of a chicken and egg problem between MAS & Synapse where they each need to know how to reach each other
-    // so spinning up a MAS is split into the prepare & start stage: prepare mas -> homeserver -> start mas to disentangle this.
-    masPrepare: async ({ context }, use) => {
-        const mas = new MatrixAuthenticationService(context);
-        await mas.prepare();
-        await use(mas);
-    },
-    mas: [
-        async ({ masPrepare: mas, homeserver, mailhog }, use, testInfo) => {
-            await mas.start(homeserver, mailhog.instance);
-            await use(mas);
-            await mas.stop(testInfo);
-        },
-        { auto: true },
-    ],
-    startHomeserverOpts: async ({ masPrepare }, use) => {
-        await use({
-            template: "mas-oidc",
-            variables: {
-                MAS_PORT: masPrepare.port,
-            },
-        });
-    },
-    config: async ({ homeserver, startHomeserverOpts, context }, use) => {
-        const issuer = `http://localhost:${(startHomeserverOpts as StartHomeserverOpts).variables["MAS_PORT"]}/`;
-        const wellKnown = {
-            "m.homeserver": {
-                base_url: homeserver.config.baseUrl,
-            },
-            "org.matrix.msc2965.authentication": {
-                issuer,
-                account: `${issuer}account`,
-            },
-        };
-
-        // Ensure org.matrix.msc2965.authentication is in well-known
-        await context.route("https://localhost/.well-known/matrix/client", async (route) => {
-            await route.fulfill({ json: wellKnown });
-        });
-
-        await use({
-            default_server_config: wellKnown,
-        });
-    },
-});
-
-export { expect };
+import { expect } from "../../element-web-test";
 
 export async function registerAccountMas(
     page: Page,
@@ -87,7 +33,7 @@ export async function registerAccountMas(
         expect(messages.items).toHaveLength(1);
     }).toPass();
     expect(messages.items[0].to).toEqual(`${username} <${email}>`);
-    const [code] = messages.items[0].text.match(/(\d{6})/);
+    const [, code] = messages.items[0].text.match(/Your verification code to confirm this email address is: (\d{6})/);
 
     await page.getByRole("textbox", { name: "6-digit code" }).fill(code);
     await page.getByRole("button", { name: "Continue" }).click();
diff --git a/playwright/e2e/oidc/oidc-aware.spec.ts b/playwright/e2e/oidc/oidc-aware.spec.ts
deleted file mode 100644
index a2f1e62714c..00000000000
--- a/playwright/e2e/oidc/oidc-aware.spec.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2023 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
-Please see LICENSE files in the repository root for full details.
-*/
-
-import { test, expect, registerAccountMas } from ".";
-import { isDendrite } from "../../plugins/homeserver/dendrite";
-
-test.describe("OIDC Aware", () => {
-    test.skip(isDendrite, "does not yet support MAS");
-    test.slow(); // trace recording takes a while here
-
-    test("can register an account and manage it", async ({ context, page, homeserver, mailhog, app }) => {
-        await page.goto("/#/login");
-        await page.getByRole("button", { name: "Continue" }).click();
-        await registerAccountMas(page, mailhog.api, "alice", "alice@email.com", "Pa$sW0rD!");
-
-        // Eventually, we should end up at the home screen.
-        await expect(page).toHaveURL(/\/#\/home$/, { timeout: 10000 });
-        await expect(page.getByRole("heading", { name: "Welcome alice", exact: true })).toBeVisible();
-
-        // Open settings and navigate to account management
-        await app.settings.openUserSettings("Account");
-        const newPagePromise = context.waitForEvent("page");
-        await page.getByRole("button", { name: "Manage account" }).click();
-
-        // Assert new tab opened
-        const newPage = await newPagePromise;
-        await expect(newPage.getByText("Primary email")).toBeVisible();
-    });
-});
diff --git a/playwright/e2e/oidc/oidc-native.spec.ts b/playwright/e2e/oidc/oidc-native.spec.ts
index 3309826b634..4d7fc7538d3 100644
--- a/playwright/e2e/oidc/oidc-native.spec.ts
+++ b/playwright/e2e/oidc/oidc-native.spec.ts
@@ -2,35 +2,43 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
-import { test, expect, registerAccountMas } from ".";
-import { isDendrite } from "../../plugins/homeserver/dendrite";
+import { test, expect } from "../../element-web-test.ts";
+import { registerAccountMas } from ".";
 import { ElementAppPage } from "../../pages/ElementAppPage.ts";
+import { masHomeserver } from "../../plugins/homeserver/synapse/masHomeserver.ts";
 
-test.describe("OIDC Native", () => {
-    test.skip(isDendrite, "does not yet support MAS");
+test.use(masHomeserver);
+test.describe("OIDC Native", { tag: ["@no-firefox", "@no-webkit"] }, () => {
     test.slow(); // trace recording takes a while here
 
-    test.use({
-        labsFlags: ["feature_oidc_native_flow"],
-    });
+    test("can register the oauth2 client and an account", async ({
+        context,
+        page,
+        homeserver,
+        mailhogClient,
+        mas,
+    }, testInfo) => {
+        await page.clock.install();
 
-    test("can register the oauth2 client and an account", async ({ context, page, homeserver, mailhog, mas }) => {
-        const tokenUri = `http://localhost:${mas.port}/oauth2/token`;
+        const tokenUri = `${mas.baseUrl}/oauth2/token`;
         const tokenApiPromise = page.waitForRequest(
             (request) => request.url() === tokenUri && request.postDataJSON()["grant_type"] === "authorization_code",
         );
 
         await page.goto("/#/login");
         await page.getByRole("button", { name: "Continue" }).click();
-        await registerAccountMas(page, mailhog.api, "alice", "alice@email.com", "Pa$sW0rD!");
+
+        const userId = `alice_${testInfo.testId}`;
+        await registerAccountMas(page, mailhogClient, userId, "alice@email.com", "Pa$sW0rD!");
 
         // Eventually, we should end up at the home screen.
         await expect(page).toHaveURL(/\/#\/home$/, { timeout: 10000 });
-        await expect(page.getByRole("heading", { name: "Welcome alice", exact: true })).toBeVisible();
+        await expect(page.getByRole("heading", { name: `Welcome ${userId}`, exact: true })).toBeVisible();
+        await page.clock.runFor(20000); // run the timer so we see the token request
 
         const tokenApiRequest = await tokenApiPromise;
         expect(tokenApiRequest.postDataJSON()["grant_type"]).toBe("authorization_code");
@@ -45,15 +53,15 @@ test.describe("OIDC Native", () => {
 
         // Assert MAS sees the session as OIDC Native
         const newPage = await newPagePromise;
-        await newPage.getByText("Sessions").click();
+        await newPage.getByText("Devices").click();
         await newPage.getByText(deviceId).click();
         await expect(newPage.getByText("Element")).toBeVisible();
-        await expect(newPage.getByText("oauth2_session:")).toBeVisible();
         await expect(newPage.getByText("http://localhost:8080/")).toBeVisible();
+        await expect(newPage).toHaveURL(/\/oauth2_session/);
         await newPage.close();
 
         // Assert logging out revokes both tokens
-        const revokeUri = `http://localhost:${mas.port}/oauth2/revoke`;
+        const revokeUri = `${mas.baseUrl}/oauth2/revoke`;
         const revokeAccessTokenPromise = page.waitForRequest(
             (request) => request.url() === revokeUri && request.postDataJSON()["token_type_hint"] === "access_token",
         );
diff --git a/playwright/e2e/one-to-one-chat/one-to-one-chat.spec.ts b/playwright/e2e/one-to-one-chat/one-to-one-chat.spec.ts
index 1e59a9a9b23..d03767205a5 100644
--- a/playwright/e2e/one-to-one-chat/one-to-one-chat.spec.ts
+++ b/playwright/e2e/one-to-one-chat/one-to-one-chat.spec.ts
@@ -3,22 +3,25 @@ Copyright 2024 New Vector Ltd.
 Copyright 2023 Ahmad Kadri
 Copyright 2023 Nordeck IT + Consulting GmbH.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 import { test as base, expect } from "../../element-web-test";
 import { Credentials } from "../../plugins/homeserver";
+import { isDendrite } from "../../plugins/homeserver/dendrite";
 
 const test = base.extend<{
     user2?: Credentials;
 }>({});
 
 test.describe("1:1 chat room", () => {
+    test.skip(isDendrite, "due to a Dendrite bug https://github.com/element-hq/dendrite/issues/3492");
+
     test.use({
         displayName: "Jeff",
-        user2: async ({ homeserver }, use) => {
-            const credentials = await homeserver.registerUser("user1234", "p4s5W0rD", "Timmy");
+        user2: async ({ homeserver }, use, testInfo) => {
+            const credentials = await homeserver.registerUser(`user2_${testInfo.testId}`, "p4s5W0rD", "Timmy");
             await use(credentials);
         },
     });
diff --git a/playwright/e2e/permalinks/permalinks.spec.ts b/playwright/e2e/permalinks/permalinks.spec.ts
index 746e15d2880..e7657b13946 100644
--- a/playwright/e2e/permalinks/permalinks.spec.ts
+++ b/playwright/e2e/permalinks/permalinks.spec.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -31,7 +31,7 @@ test.describe("permalinks", () => {
         await charlotte.prepareClient();
 
         // We don't use a bot for danielle as we want a stable MXID.
-        const danielleId = "@danielle:localhost";
+        const danielleId = `@danielle:${user.homeServer}`;
 
         const room1Id = await app.client.createRoom({ name: room1Name });
         const room2Id = await app.client.createRoom({ name: room2Name });
diff --git a/playwright/e2e/pinned-messages/index.ts b/playwright/e2e/pinned-messages/index.ts
index 545d0e34389..bb65f316277 100644
--- a/playwright/e2e/pinned-messages/index.ts
+++ b/playwright/e2e/pinned-messages/index.ts
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2024 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
@@ -13,6 +13,8 @@ import { Client } from "../../pages/client";
 import { ElementAppPage } from "../../pages/ElementAppPage";
 import { Bot } from "../../pages/bot";
 
+type RoomRef = { name: string; roomId: string };
+
 /**
  * Set up for pinned message tests.
  */
@@ -47,7 +49,7 @@ export class Helpers {
      * @param room - the name of the room to send messages into
      * @param messages - the list of messages to send, these can be strings or implementations of MessageSpec like `editOf`
      */
-    async receiveMessages(room: string | { name: string }, messages: string[]) {
+    async receiveMessages(room: RoomRef, messages: string[]) {
         await this.sendMessageAsClient(this.bot, room, messages);
     }
 
@@ -55,9 +57,8 @@ export class Helpers {
      * Use the supplied client to send messages or perform actions as specified by
      * the supplied {@link Message} items.
      */
-    private async sendMessageAsClient(cli: Client, roomName: string | { name: string }, messages: string[]) {
-        const room = await this.findRoomByName(typeof roomName === "string" ? roomName : roomName.name);
-        const roomId = await room.evaluate((room) => room.roomId);
+    private async sendMessageAsClient(cli: Client, room: RoomRef, messages: string[]) {
+        const roomId = room.roomId;
 
         for (const message of messages) {
             await cli.sendMessage(roomId, { body: message, msgtype: "m.text" });
@@ -73,22 +74,11 @@ export class Helpers {
         }
     }
 
-    /**
-     * Find a room by its name
-     * @param roomName
-     * @private
-     */
-    private async findRoomByName(roomName: string) {
-        return this.app.client.evaluateHandle((cli, roomName) => {
-            return cli.getRooms().find((r) => r.name === roomName);
-        }, roomName);
-    }
-
     /**
      * Open the room with the supplied name.
      */
-    async goTo(room: string | { name: string }) {
-        await this.app.viewRoomByName(typeof room === "string" ? room : room.name);
+    async goTo(room: RoomRef) {
+        await this.app.viewRoomByName(room.name);
     }
 
     /**
diff --git a/playwright/e2e/pinned-messages/pinned-messages.spec.ts b/playwright/e2e/pinned-messages/pinned-messages.spec.ts
index 06d6db80580..bb72c026107 100644
--- a/playwright/e2e/pinned-messages/pinned-messages.spec.ts
+++ b/playwright/e2e/pinned-messages/pinned-messages.spec.ts
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2024 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/playwright/e2e/polls/pollHistory.spec.ts b/playwright/e2e/polls/pollHistory.spec.ts
index b9250baceae..319a08cda91 100644
--- a/playwright/e2e/polls/pollHistory.spec.ts
+++ b/playwright/e2e/polls/pollHistory.spec.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 import { test, expect } from "../../element-web-test";
@@ -134,7 +134,7 @@ test.describe("Poll history", () => {
 
         await expect(dialog.getByText(pollParams2.title)).toBeAttached();
         await expect(dialog.getByText(pollParams1.title)).toBeAttached();
-        dialog.getByText("Active polls").click();
+        await dialog.getByText("Active polls").click();
 
         // no more active polls
         await expect(page.getByText("There are no active polls in this room")).toBeAttached();
diff --git a/playwright/e2e/polls/polls.spec.ts b/playwright/e2e/polls/polls.spec.ts
index e1d3ebe7e36..fc49906b47c 100644
--- a/playwright/e2e/polls/polls.spec.ts
+++ b/playwright/e2e/polls/polls.spec.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -11,8 +11,11 @@ import { Bot } from "../../pages/bot";
 import { SettingLevel } from "../../../src/settings/SettingLevel";
 import { Layout } from "../../../src/settings/enums/Layout";
 import type { Locator, Page } from "@playwright/test";
+import { isDendrite } from "../../plugins/homeserver/dendrite";
 
 test.describe("Polls", () => {
+    test.skip(isDendrite, "due to a Dendrite bug https://github.com/element-hq/dendrite/issues/3492");
+
     type CreatePollOptions = {
         title: string;
         options: string[];
diff --git a/playwright/e2e/presence/presence.spec.ts b/playwright/e2e/presence/presence.spec.ts
index 47b3440e6ed..684fd8a5bf3 100644
--- a/playwright/e2e/presence/presence.spec.ts
+++ b/playwright/e2e/presence/presence.spec.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/playwright/e2e/read-receipts/editing-messages-in-threads.spec.ts b/playwright/e2e/read-receipts/editing-messages-in-threads.spec.ts
index 42191831c80..4fa204bacea 100644
--- a/playwright/e2e/read-receipts/editing-messages-in-threads.spec.ts
+++ b/playwright/e2e/read-receipts/editing-messages-in-threads.spec.ts
@@ -2,15 +2,18 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 /* See readme.md for tips on writing these tests. */
 
 import { test } from ".";
+import { isDendrite } from "../../plugins/homeserver/dendrite";
 
 test.describe("Read receipts", { tag: "@mergequeue" }, () => {
+    test.skip(isDendrite, "due to Dendrite bug https://github.com/element-hq/dendrite/issues/2970");
+
     test.describe("editing messages", () => {
         test.describe("in threads", () => {
             test("An edit of a threaded message makes the room unread", async ({
diff --git a/playwright/e2e/read-receipts/editing-messages-main-timeline.spec.ts b/playwright/e2e/read-receipts/editing-messages-main-timeline.spec.ts
index a4648223050..6c9596a5b2b 100644
--- a/playwright/e2e/read-receipts/editing-messages-main-timeline.spec.ts
+++ b/playwright/e2e/read-receipts/editing-messages-main-timeline.spec.ts
@@ -2,15 +2,18 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 /* See readme.md for tips on writing these tests. */
 
 import { test } from ".";
+import { isDendrite } from "../../plugins/homeserver/dendrite";
 
 test.describe("Read receipts", { tag: "@mergequeue" }, () => {
+    test.skip(isDendrite, "due to Dendrite bug https://github.com/element-hq/dendrite/issues/2970");
+
     test.describe("editing messages", () => {
         test.describe("in the main timeline", () => {
             test("Editing a message leaves a room read", async ({ roomAlpha: room1, roomBeta: room2, util, msg }) => {
diff --git a/playwright/e2e/read-receipts/editing-messages-thread-roots.spec.ts b/playwright/e2e/read-receipts/editing-messages-thread-roots.spec.ts
index 506ed603bda..9cd158430a8 100644
--- a/playwright/e2e/read-receipts/editing-messages-thread-roots.spec.ts
+++ b/playwright/e2e/read-receipts/editing-messages-thread-roots.spec.ts
@@ -2,15 +2,18 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 /* See readme.md for tips on writing these tests. */
 
 import { test } from ".";
+import { isDendrite } from "../../plugins/homeserver/dendrite";
 
 test.describe("Read receipts", { tag: "@mergequeue" }, () => {
+    test.skip(isDendrite, "due to Dendrite bug https://github.com/element-hq/dendrite/issues/2970");
+
     test.describe("editing messages", () => {
         test.describe("thread roots", () => {
             test("An edit of a thread root leaves the room read", async ({
diff --git a/playwright/e2e/read-receipts/high-level.spec.ts b/playwright/e2e/read-receipts/high-level.spec.ts
index 457cf994814..a723928c57a 100644
--- a/playwright/e2e/read-receipts/high-level.spec.ts
+++ b/playwright/e2e/read-receipts/high-level.spec.ts
@@ -2,15 +2,19 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 /* See readme.md for tips on writing these tests. */
 
 import { customEvent, many, test } from ".";
+import { isDendrite } from "../../plugins/homeserver/dendrite";
 
 test.describe("Read receipts", { tag: "@mergequeue" }, () => {
+    test.skip(isDendrite, "due to Dendrite bug https://github.com/element-hq/dendrite/issues/2970");
+    test.slow();
+
     test.describe("Ignored events", () => {
         test("If all events after receipt are unimportant, the room is read", async ({
             roomAlpha: room1,
@@ -120,7 +124,7 @@ test.describe("Read receipts", { tag: "@mergequeue" }, () => {
             await util.assertUnread(room2, 40);
 
             // When I jump to a message in the middle and page up
-            await msg.jumpTo(room2.name, "x\ny\nz\nMsg0020");
+            await msg.jumpTo(room2, "x\ny\nz\nMsg0020");
             await util.pageUp();
 
             // Then the room is still unread
diff --git a/playwright/e2e/read-receipts/index.ts b/playwright/e2e/read-receipts/index.ts
index 49a0195fd72..eab261042e7 100644
--- a/playwright/e2e/read-receipts/index.ts
+++ b/playwright/e2e/read-receipts/index.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -13,6 +13,8 @@ import { Bot } from "../../pages/bot";
 import { Client } from "../../pages/client";
 import { ElementAppPage } from "../../pages/ElementAppPage";
 
+type RoomRef = { name: string; roomId: string };
+
 /**
  * Set up for a read receipt test:
  * - Create a user with the supplied name
@@ -22,9 +24,9 @@ import { ElementAppPage } from "../../pages/ElementAppPage";
  */
 export const test = base.extend<{
     roomAlphaName?: string;
-    roomAlpha: { name: string; roomId: string };
+    roomAlpha: RoomRef;
     roomBetaName?: string;
-    roomBeta: { name: string; roomId: string };
+    roomBeta: RoomRef;
     msg: MessageBuilder;
     util: Helpers;
 }>({
@@ -248,12 +250,13 @@ export class MessageBuilder {
     /**
      * Find and display a message.
      *
-     * @param roomName the name of the room to look inside
+     * @param roomRef the ref of the room to look inside
      * @param message the content of the message to fine
      * @param includeThreads look for messages inside threads, not just the main timeline
      */
-    async jumpTo(roomName: string, message: string, includeThreads = false) {
-        const room = await this.helpers.findRoomByName(roomName);
+    async jumpTo(roomRef: RoomRef, message: string, includeThreads = false) {
+        const room = await this.helpers.findRoomById(roomRef.roomId);
+        expect(room).toBeTruthy();
         const foundMessage = await this.getMessage(room, message, includeThreads);
         const roomId = await room.evaluate((room) => room.roomId);
         const foundMessageId = await foundMessage.evaluate((ev) => ev.getId());
@@ -333,9 +336,10 @@ class Helpers {
      * Use the supplied client to send messages or perform actions as specified by
      * the supplied {@link Message} items.
      */
-    async sendMessageAsClient(cli: Client, roomName: string | { name: string }, messages: Message[]) {
-        const room = await this.findRoomByName(typeof roomName === "string" ? roomName : roomName.name);
-        const roomId = await room.evaluate((room) => room.roomId);
+    async sendMessageAsClient(cli: Client, roomRef: RoomRef, messages: Message[]) {
+        const roomId = roomRef.roomId;
+        const room = await this.findRoomById(roomId);
+        expect(room).toBeTruthy();
 
         for (const message of messages) {
             if (typeof message === "string") {
@@ -359,7 +363,7 @@ class Helpers {
     /**
      * Open the room with the supplied name.
      */
-    async goTo(room: string | { name: string }) {
+    async goTo(room: RoomRef) {
         await this.app.viewRoomByName(typeof room === "string" ? room : room.name);
     }
 
@@ -423,17 +427,16 @@ class Helpers {
         });
     }
 
-    getRoomListTile(room: string | { name: string }) {
-        const roomName = typeof room === "string" ? room : room.name;
-        return this.page.getByRole("treeitem", { name: new RegExp("^" + roomName) });
+    getRoomListTile(label: string) {
+        return this.page.getByRole("treeitem", { name: new RegExp("^" + label) });
     }
 
     /**
      * Click the "Mark as Read" context menu item on the room with the supplied name
      * in the room list.
      */
-    async markAsRead(room: string | { name: string }) {
-        await this.getRoomListTile(room).click({ button: "right" });
+    async markAsRead(room: RoomRef) {
+        await this.getRoomListTile(room.name).click({ button: "right" });
         await this.page.getByText("Mark as read").click();
     }
 
@@ -441,8 +444,8 @@ class Helpers {
      * Assert that the room with the supplied name is "read" in the room list - i.g.
      * has not dot or count of unread messages.
      */
-    async assertRead(room: string | { name: string }) {
-        const tile = this.getRoomListTile(room);
+    async assertRead(room: RoomRef) {
+        const tile = this.getRoomListTile(room.name);
         await expect(tile.locator(".mx_NotificationBadge_dot")).not.toBeVisible();
         await expect(tile.locator(".mx_NotificationBadge_count")).not.toBeVisible();
     }
@@ -452,7 +455,7 @@ class Helpers {
      * (In practice, this just waits a short while to allow any unread marker to
      * appear, and then asserts that the room is read.)
      */
-    async assertStillRead(room: string | { name: string }) {
+    async assertStillRead(room: RoomRef) {
         await this.page.waitForTimeout(200);
         await this.assertRead(room);
     }
@@ -462,8 +465,8 @@ class Helpers {
      * @param room - the name of the room to check
      * @param count - the numeric count to assert, or if "." specified then a bold/dot (no count) state is asserted
      */
-    async assertUnread(room: string | { name: string }, count: number | ".") {
-        const tile = this.getRoomListTile(room);
+    async assertUnread(room: RoomRef, count: number | ".") {
+        const tile = this.getRoomListTile(room.name);
         if (count === ".") {
             await expect(tile.locator(".mx_NotificationBadge_dot")).toBeVisible();
         } else {
@@ -478,8 +481,8 @@ class Helpers {
      * @param room - the name of the room to check
      * @param lessThan - the number of unread messages that is too many
      */
-    async assertUnreadLessThan(room: string | { name: string }, lessThan: number) {
-        const tile = this.getRoomListTile(room);
+    async assertUnreadLessThan(room: RoomRef, lessThan: number) {
+        const tile = this.getRoomListTile(room.name);
         // https://playwright.dev/docs/test-assertions#expectpoll
         // .toBeLessThan doesn't have a retry mechanism, so we use .poll
         await expect
@@ -496,8 +499,8 @@ class Helpers {
      * @param room - the name of the room to check
      * @param greaterThan - the number of unread messages that is too few
      */
-    async assertUnreadGreaterThan(room: string | { name: string }, greaterThan: number) {
-        const tile = this.getRoomListTile(room);
+    async assertUnreadGreaterThan(room: RoomRef, greaterThan: number) {
+        const tile = this.getRoomListTile(room.name);
         // https://playwright.dev/docs/test-assertions#expectpoll
         // .toBeGreaterThan doesn't have a retry mechanism, so we use .poll
         await expect
@@ -531,10 +534,10 @@ class Helpers {
         });
     }
 
-    async findRoomByName(roomName: string): Promise<JSHandle<Room>> {
-        return this.app.client.evaluateHandle((cli, roomName) => {
-            return cli.getRooms().find((r) => r.name === roomName);
-        }, roomName);
+    async findRoomById(roomId: string): Promise<JSHandle<Room>> {
+        return this.app.client.evaluateHandle((cli, roomId) => {
+            return cli.getRooms().find((r) => r.roomId === roomId);
+        }, roomId);
     }
 
     private async getThreadListTile(rootMessage: string) {
@@ -578,7 +581,7 @@ class Helpers {
      * @param room - the name of the room to send messages into
      * @param messages - the list of messages to send, these can be strings or implementations of MessageSpec like `editOf`
      */
-    async receiveMessages(room: string | { name: string }, messages: Message[]) {
+    async receiveMessages(room: RoomRef, messages: Message[]) {
         await this.sendMessageAsClient(this.bot, room, messages);
     }
 
diff --git a/playwright/e2e/read-receipts/message-ordering.spec.ts b/playwright/e2e/read-receipts/message-ordering.spec.ts
index d7f77fae5f5..59a56e6c50b 100644
--- a/playwright/e2e/read-receipts/message-ordering.spec.ts
+++ b/playwright/e2e/read-receipts/message-ordering.spec.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/playwright/e2e/read-receipts/missing-referents.spec.ts b/playwright/e2e/read-receipts/missing-referents.spec.ts
index a1741851e2c..a953aae448d 100644
--- a/playwright/e2e/read-receipts/missing-referents.spec.ts
+++ b/playwright/e2e/read-receipts/missing-referents.spec.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/playwright/e2e/read-receipts/new-messages-in-threads.spec.ts b/playwright/e2e/read-receipts/new-messages-in-threads.spec.ts
index 5407f3cb44a..2f3c153f201 100644
--- a/playwright/e2e/read-receipts/new-messages-in-threads.spec.ts
+++ b/playwright/e2e/read-receipts/new-messages-in-threads.spec.ts
@@ -2,15 +2,18 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 /* See readme.md for tips on writing these tests. */
 
 import { many, test } from ".";
+import { isDendrite } from "../../plugins/homeserver/dendrite";
 
 test.describe("Read receipts", { tag: "@mergequeue" }, () => {
+    test.skip(isDendrite, "due to Dendrite bug https://github.com/element-hq/dendrite/issues/2970");
+
     test.describe("new messages", () => {
         test.describe("in threads", () => {
             test("Receiving a message makes a room unread", async ({
@@ -101,7 +104,7 @@ test.describe("Read receipts", { tag: "@mergequeue" }, () => {
                 await util.goTo(room1);
 
                 // When I read an older message in the thread
-                await msg.jumpTo(room2.name, "InThread0000", true);
+                await msg.jumpTo(room2, "InThread0000", true);
 
                 // Then the thread is still marked as unread
                 await util.backToThreadsList();
diff --git a/playwright/e2e/read-receipts/new-messages-main-timeline.spec.ts b/playwright/e2e/read-receipts/new-messages-main-timeline.spec.ts
index 92f7b10cdd7..16c8132378a 100644
--- a/playwright/e2e/read-receipts/new-messages-main-timeline.spec.ts
+++ b/playwright/e2e/read-receipts/new-messages-main-timeline.spec.ts
@@ -2,15 +2,18 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 /* See readme.md for tips on writing these tests. */
 
 import { many, test } from ".";
+import { isDendrite } from "../../plugins/homeserver/dendrite";
 
 test.describe("Read receipts", { tag: "@mergequeue" }, () => {
+    test.skip(isDendrite, "due to Dendrite bug https://github.com/element-hq/dendrite/issues/2970");
+
     test.describe("new messages", () => {
         test.describe("in the main timeline", () => {
             test("Receiving a message makes a room unread", async ({
@@ -59,7 +62,7 @@ test.describe("Read receipts", { tag: "@mergequeue" }, () => {
                 await util.assertUnread(room2, 30);
 
                 // When I jump to one of the older messages
-                await msg.jumpTo(room2.name, "Msg0001");
+                await msg.jumpTo(room2, "Msg0001");
 
                 // Then the room is still unread, but some messages were read
                 await util.assertUnreadLessThan(room2, 30);
diff --git a/playwright/e2e/read-receipts/new-messages-thread-roots.spec.ts b/playwright/e2e/read-receipts/new-messages-thread-roots.spec.ts
index 3c8ed7849f4..a711d889a16 100644
--- a/playwright/e2e/read-receipts/new-messages-thread-roots.spec.ts
+++ b/playwright/e2e/read-receipts/new-messages-thread-roots.spec.ts
@@ -2,15 +2,18 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 /* See readme.md for tips on writing these tests. */
 
 import { many, test } from ".";
+import { isDendrite } from "../../plugins/homeserver/dendrite";
 
 test.describe("Read receipts", { tag: "@mergequeue" }, () => {
+    test.skip(isDendrite, "due to Dendrite bug https://github.com/element-hq/dendrite/issues/2970");
+
     test.describe("new messages", () => {
         test.describe("thread roots", () => {
             test("Reading a thread root does not mark the thread as read", async ({
@@ -49,7 +52,7 @@ test.describe("Read receipts", { tag: "@mergequeue" }, () => {
                 await util.assertUnread(room2, 61); // Sanity
 
                 // When I jump to an old message and read the thread
-                await msg.jumpTo(room2.name, "beforeThread0000");
+                await msg.jumpTo(room2, "beforeThread0000");
                 // When the thread is opened, the timeline is scrolled until the thread root reached the center
                 await util.openThread("ThreadRoot");
 
diff --git a/playwright/e2e/read-receipts/notifications.spec.ts b/playwright/e2e/read-receipts/notifications.spec.ts
index 46edc9a7a32..93f5515eeb7 100644
--- a/playwright/e2e/read-receipts/notifications.spec.ts
+++ b/playwright/e2e/read-receipts/notifications.spec.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/playwright/e2e/read-receipts/reactions-in-threads.spec.ts b/playwright/e2e/read-receipts/reactions-in-threads.spec.ts
index 45b5e071ecc..b2cd2e554aa 100644
--- a/playwright/e2e/read-receipts/reactions-in-threads.spec.ts
+++ b/playwright/e2e/read-receipts/reactions-in-threads.spec.ts
@@ -2,15 +2,18 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 /* See readme.md for tips on writing these tests. */
 
 import { test, expect } from ".";
+import { isDendrite } from "../../plugins/homeserver/dendrite";
 
 test.describe("Read receipts", { tag: "@mergequeue" }, () => {
+    test.skip(isDendrite, "due to Dendrite bug https://github.com/element-hq/dendrite/issues/2970");
+
     test.describe("reactions", () => {
         test.describe("in threads", () => {
             test("A reaction to a threaded message does not make the room unread", async ({
@@ -70,11 +73,7 @@ test.describe("Read receipts", { tag: "@mergequeue" }, () => {
                 // Given a thread exists and I have marked it as read
                 await util.goTo(room1);
                 await util.assertRead(room2);
-                await util.receiveMessages(room2, [
-                    "Msg1",
-                    msg.threadedOff("Msg1", "Reply1"),
-                    msg.reactionTo("Reply1", "🪿"),
-                ]);
+                await util.receiveMessages(room2, ["Msg1", msg.threadedOff("Msg1", "Reply1")]);
                 await util.assertUnread(room2, 1);
                 await util.markAsRead(room2);
                 await util.assertRead(room2);
diff --git a/playwright/e2e/read-receipts/reactions-main-timeline.spec.ts b/playwright/e2e/read-receipts/reactions-main-timeline.spec.ts
index 16d5c92eca0..77ed8cd5823 100644
--- a/playwright/e2e/read-receipts/reactions-main-timeline.spec.ts
+++ b/playwright/e2e/read-receipts/reactions-main-timeline.spec.ts
@@ -2,15 +2,18 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 /* See readme.md for tips on writing these tests. */
 
 import { test } from ".";
+import { isDendrite } from "../../plugins/homeserver/dendrite";
 
 test.describe("Read receipts", { tag: "@mergequeue" }, () => {
+    test.skip(isDendrite, "due to Dendrite bug https://github.com/element-hq/dendrite/issues/2970");
+
     test.describe("reactions", () => {
         test.describe("in the main timeline", () => {
             test("Receiving a reaction to a message does not make a room unread", async ({
diff --git a/playwright/e2e/read-receipts/reactions-thread-roots.spec.ts b/playwright/e2e/read-receipts/reactions-thread-roots.spec.ts
index 817597a27e0..a6d21cb34ed 100644
--- a/playwright/e2e/read-receipts/reactions-thread-roots.spec.ts
+++ b/playwright/e2e/read-receipts/reactions-thread-roots.spec.ts
@@ -2,15 +2,17 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 /* See readme.md for tips on writing these tests. */
 
 import { test } from ".";
+import { isDendrite } from "../../plugins/homeserver/dendrite";
 
 test.describe("Read receipts", { tag: "@mergequeue" }, () => {
+    test.skip(isDendrite, "due to Dendrite bug https://github.com/element-hq/dendrite/issues/2970");
     test.describe("reactions", () => {
         test.describe("thread roots", () => {
             test("A reaction to a thread root does not make the room unread", async ({
diff --git a/playwright/e2e/read-receipts/read-receipts.spec.ts b/playwright/e2e/read-receipts/read-receipts.spec.ts
index f6515361f23..6b9415e7ba6 100644
--- a/playwright/e2e/read-receipts/read-receipts.spec.ts
+++ b/playwright/e2e/read-receipts/read-receipts.spec.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -12,8 +12,10 @@ import { expect } from "../../element-web-test";
 import { ElementAppPage } from "../../pages/ElementAppPage";
 import { Bot } from "../../pages/bot";
 import { test } from ".";
+import { isDendrite } from "../../plugins/homeserver/dendrite";
 
 test.describe("Read receipts", { tag: "@mergequeue" }, () => {
+    test.skip(isDendrite, "due to Dendrite bug https://github.com/element-hq/dendrite/issues/2970");
     test.use({
         displayName: "Mae",
         botCreateOpts: { displayName: "Other User" },
@@ -100,12 +102,7 @@ test.describe("Read receipts", { tag: "@mergequeue" }, () => {
         await page.goto(`/#/room/${selectedRoomId}`);
     });
 
-    // Disabled due to flakiness: https://github.com/element-hq/element-web/issues/26895
-    test.skip("With sync accumulator, considers main thread and unthreaded receipts #24629", async ({
-        page,
-        app,
-        bot,
-    }) => {
+    test("With sync accumulator, considers main thread and unthreaded receipts #24629", async ({ page, app, bot }) => {
         // Details are in https://github.com/vector-im/element-web/issues/24629
         // This proves we've fixed one of the "stuck unreads" issues.
 
@@ -196,7 +193,7 @@ test.describe("Read receipts", { tag: "@mergequeue" }, () => {
         await sendThreadedReadReceipt(app, thread1a, main1);
 
         // Then the room has only one unread - the one in the thread
-        await util.goTo(otherRoomName);
+        await util.goTo({ name: otherRoomName, roomId: otherRoomId });
         await util.assertUnreadThread("Message 1");
     });
 
@@ -214,7 +211,7 @@ test.describe("Read receipts", { tag: "@mergequeue" }, () => {
 
         // Then the room has no unreads
         await expect(page.getByLabel(`${otherRoomName}`)).toBeVisible();
-        await util.goTo(otherRoomName);
+        await util.goTo({ name: otherRoomName, roomId: otherRoomId });
         await util.assertReadThread("Message 1");
     });
 
@@ -239,7 +236,7 @@ test.describe("Read receipts", { tag: "@mergequeue" }, () => {
         // receipt is for a later event. The room should therefore be
         // read, and the thread unread.
         await expect(page.getByLabel(`${otherRoomName}`)).toBeVisible();
-        await util.goTo(otherRoomName);
+        await util.goTo({ name: otherRoomName, roomId: otherRoomId });
         await util.assertUnreadThread("Message 1");
     });
 
diff --git a/playwright/e2e/read-receipts/redactions-in-threads.spec.ts b/playwright/e2e/read-receipts/redactions-in-threads.spec.ts
index 25c19a4f975..4e8b6bef5a3 100644
--- a/playwright/e2e/read-receipts/redactions-in-threads.spec.ts
+++ b/playwright/e2e/read-receipts/redactions-in-threads.spec.ts
@@ -2,15 +2,18 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 /* See readme.md for tips on writing these tests. */
 
 import { test } from ".";
+import { isDendrite } from "../../plugins/homeserver/dendrite";
 
 test.describe("Read receipts", { tag: "@mergequeue" }, () => {
+    test.skip(isDendrite, "due to Dendrite bug https://github.com/element-hq/dendrite/issues/2970");
+
     test.describe("redactions", () => {
         test.describe("in threads", () => {
             test("Redacting the threaded message pointed to by my receipt leaves the room read", async ({
diff --git a/playwright/e2e/read-receipts/redactions-main-timeline.spec.ts b/playwright/e2e/read-receipts/redactions-main-timeline.spec.ts
index 143d9685d8f..203cbb997f8 100644
--- a/playwright/e2e/read-receipts/redactions-main-timeline.spec.ts
+++ b/playwright/e2e/read-receipts/redactions-main-timeline.spec.ts
@@ -2,15 +2,18 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 /* See readme.md for tips on writing these tests. */
 
 import { test } from ".";
+import { isDendrite } from "../../plugins/homeserver/dendrite";
 
 test.describe("Read receipts", { tag: "@mergequeue" }, () => {
+    test.skip(isDendrite, "due to Dendrite bug https://github.com/element-hq/dendrite/issues/2970");
+
     test.describe("redactions", () => {
         test.describe("in the main timeline", () => {
             test("Redacting the message pointed to by my receipt leaves the room read", async ({
diff --git a/playwright/e2e/read-receipts/redactions-thread-roots.spec.ts b/playwright/e2e/read-receipts/redactions-thread-roots.spec.ts
index 01f296075c9..108e61df34e 100644
--- a/playwright/e2e/read-receipts/redactions-thread-roots.spec.ts
+++ b/playwright/e2e/read-receipts/redactions-thread-roots.spec.ts
@@ -2,15 +2,18 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 /* See readme.md for tips on writing these tests. */
 
 import { test } from ".";
+import { isDendrite } from "../../plugins/homeserver/dendrite";
 
 test.describe("Read receipts", { tag: "@mergequeue" }, () => {
+    test.skip(isDendrite, "due to Dendrite bug https://github.com/element-hq/dendrite/issues/2970");
+
     test.describe("redactions", () => {
         test.describe("thread roots", () => {
             test("Redacting a thread root after it was read leaves the room read", async ({
diff --git a/playwright/e2e/read-receipts/room-list-order.spec.ts b/playwright/e2e/read-receipts/room-list-order.spec.ts
index 80dda202a3a..e940c45b878 100644
--- a/playwright/e2e/read-receipts/room-list-order.spec.ts
+++ b/playwright/e2e/read-receipts/room-list-order.spec.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/playwright/e2e/register/email.spec.ts b/playwright/e2e/register/email.spec.ts
index 665e20ef01f..cd990f9eafd 100644
--- a/playwright/e2e/register/email.spec.ts
+++ b/playwright/e2e/register/email.spec.ts
@@ -2,46 +2,39 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 import { test, expect } from "../../element-web-test";
+import { emailHomeserver } from "../../plugins/homeserver/synapse/emailHomeserver.ts";
 import { isDendrite } from "../../plugins/homeserver/dendrite";
 
+test.use(emailHomeserver);
+test.use({
+    config: ({ config }, use) =>
+        use({
+            ...config,
+            default_server_config: {
+                ...config.default_server_config,
+                "m.identity_server": {
+                    base_url: "https://server.invalid",
+                },
+            },
+        }),
+});
+
 test.describe("Email Registration", async () => {
     test.skip(isDendrite, "not yet wired up");
 
-    test.use({
-        startHomeserverOpts: ({ mailhog }, use) =>
-            use({
-                template: "email",
-                variables: {
-                    SMTP_HOST: "host.containers.internal",
-                    SMTP_PORT: mailhog.instance.smtpPort,
-                },
-            }),
-        config: ({ homeserver }, use) =>
-            use({
-                default_server_config: {
-                    "m.homeserver": {
-                        base_url: homeserver.config.baseUrl,
-                    },
-                    "m.identity_server": {
-                        base_url: "https://server.invalid",
-                    },
-                },
-            }),
-    });
-
-    test.beforeEach(async ({ page }) => {
+    test.beforeEach(async ({ homeserver, page }) => {
         await page.goto("/#/register");
     });
 
     test(
-        "registers an account and lands on the use case selection screen",
+        "registers an account and lands on the home page",
         { tag: "@screenshot" },
-        async ({ page, mailhog, request, checkA11y }) => {
+        async ({ page, mailhogClient, request, checkA11y }) => {
             await expect(page.getByRole("textbox", { name: "Username" })).toBeVisible();
             // Hide the server text as it contains the randomly allocated Homeserver port
             const screenshotOptions = { mask: [page.locator(".mx_ServerPicker_server")] };
@@ -58,13 +51,13 @@ test.describe("Email Registration", async () => {
 
             await expect(page.getByText("An error was encountered when sending the email")).not.toBeVisible();
 
-            const messages = await mailhog.api.messages();
+            const messages = await mailhogClient.messages();
             expect(messages.items).toHaveLength(1);
             expect(messages.items[0].to).toEqual("alice@email.com");
             const [emailLink] = messages.items[0].text.match(/http.+/);
             await request.get(emailLink); // "Click" the link in the email
 
-            await expect(page.locator(".mx_UseCaseSelection_skip")).toBeVisible();
+            await expect(page.getByText("Welcome alice")).toBeVisible();
         },
     );
 });
diff --git a/playwright/e2e/register/register.spec.ts b/playwright/e2e/register/register.spec.ts
index 19608ee174d..3df1d016785 100644
--- a/playwright/e2e/register/register.spec.ts
+++ b/playwright/e2e/register/register.spec.ts
@@ -2,14 +2,29 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 import { test, expect } from "../../element-web-test";
+import { consentHomeserver } from "../../plugins/homeserver/synapse/consentHomeserver.ts";
+import { isDendrite } from "../../plugins/homeserver/dendrite";
+
+test.use(consentHomeserver);
+test.use({
+    config: {
+        // The only thing that we really *need* (otherwise Element refuses to load) is a default homeserver.
+        // We point that to a guaranteed-invalid domain.
+        default_server_config: {
+            "m.homeserver": {
+                base_url: "https://server.invalid",
+            },
+        },
+    },
+});
 
 test.describe("Registration", () => {
-    test.use({ startHomeserverOpts: "consent" });
+    test.skip(isDendrite, "Dendrite lacks support for MSC3967 so requires additional auth here");
 
     test.beforeEach(async ({ page }) => {
         await page.goto("/#/register");
@@ -25,7 +40,7 @@ test.describe("Registration", () => {
             await expect(page.locator(".mx_Dialog")).toMatchScreenshot("server-picker.png");
             await checkA11y();
 
-            await page.getByRole("textbox", { name: "Other homeserver" }).fill(homeserver.config.baseUrl);
+            await page.getByRole("textbox", { name: "Other homeserver" }).fill(homeserver.baseUrl);
             await page.getByRole("button", { name: "Continue", exact: true }).click();
             // wait for the dialog to go away
             await expect(page.getByRole("dialog")).not.toBeVisible();
@@ -59,12 +74,6 @@ test.describe("Registration", () => {
             await expect(termsPolicy.getByLabel("Privacy Policy")).toBeVisible();
 
             await page.getByRole("button", { name: "Accept", exact: true }).click();
-
-            await expect(page.locator(".mx_UseCaseSelection_skip")).toBeVisible();
-            await expect(page).toMatchScreenshot("use-case-selection.png", screenshotOptions);
-            await checkA11y();
-            await page.getByRole("button", { name: "Skip", exact: true }).click();
-
             await expect(page).toHaveURL(/\/#\/home$/);
 
             /*
@@ -86,7 +95,7 @@ test.describe("Registration", () => {
     test("should require username to fulfil requirements and be available", async ({ homeserver, page }) => {
         await page.getByRole("button", { name: "Edit", exact: true }).click();
         await expect(page.getByRole("button", { name: "Continue", exact: true })).toBeVisible();
-        await page.getByRole("textbox", { name: "Other homeserver" }).fill(homeserver.config.baseUrl);
+        await page.getByRole("textbox", { name: "Other homeserver" }).fill(homeserver.baseUrl);
         await page.getByRole("button", { name: "Continue", exact: true }).click();
         // wait for the dialog to go away
         await expect(page.getByRole("dialog")).not.toBeVisible();
diff --git a/playwright/e2e/regression-tests/pills-click-in-app.spec.ts b/playwright/e2e/regression-tests/pills-click-in-app.spec.ts
index f19e8c896e7..7486af70337 100644
--- a/playwright/e2e/regression-tests/pills-click-in-app.spec.ts
+++ b/playwright/e2e/regression-tests/pills-click-in-app.spec.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/playwright/e2e/release-announcement/index.ts b/playwright/e2e/release-announcement/index.ts
index 59db80c3c6d..e20dfb85b4a 100644
--- a/playwright/e2e/release-announcement/index.ts
+++ b/playwright/e2e/release-announcement/index.ts
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2024 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/playwright/e2e/release-announcement/releaseAnnouncement.spec.ts b/playwright/e2e/release-announcement/releaseAnnouncement.spec.ts
index e18d72ddba9..c2ebd5b8539 100644
--- a/playwright/e2e/release-announcement/releaseAnnouncement.spec.ts
+++ b/playwright/e2e/release-announcement/releaseAnnouncement.spec.ts
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2024 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/playwright/e2e/right-panel/file-panel.spec.ts b/playwright/e2e/right-panel/file-panel.spec.ts
index c535bcdfbb6..1c936f43b89 100644
--- a/playwright/e2e/right-panel/file-panel.spec.ts
+++ b/playwright/e2e/right-panel/file-panel.spec.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 Suguru Hirahara
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -10,6 +10,7 @@ import { Download, type Page } from "@playwright/test";
 
 import { test, expect } from "../../element-web-test";
 import { viewRoomSummaryByName } from "./utils";
+import { isDendrite } from "../../plugins/homeserver/dendrite";
 
 const ROOM_NAME = "Test room";
 const NAME = "Alice";
@@ -39,7 +40,7 @@ test.describe("FilePanel", () => {
         await expect(page.locator(".mx_FilePanel")).toBeVisible();
     });
 
-    test.describe("render", () => {
+    test.describe("render", { tag: ["@no-firefox", "@no-webkit"] }, () => {
         test("should render empty state", { tag: "@screenshot" }, async ({ page }) => {
             // Wait until the information about the empty state is rendered
             await expect(page.locator(".mx_EmptyState")).toBeVisible();
@@ -181,6 +182,8 @@ test.describe("FilePanel", () => {
     });
 
     test.describe("download", () => {
+        test.skip(isDendrite, "due to a Dendrite sending Content-Disposition inline");
+
         test("should download an image via the link on the panel", async ({ page, context }) => {
             // Upload an image file
             await uploadFile(page, "playwright/sample-files/riot.png");
diff --git a/playwright/e2e/right-panel/memberlist.spec.ts b/playwright/e2e/right-panel/memberlist.spec.ts
new file mode 100644
index 00000000000..25d5f346631
--- /dev/null
+++ b/playwright/e2e/right-panel/memberlist.spec.ts
@@ -0,0 +1,48 @@
+/*
+Copyright 2024 New Vector Ltd.
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+Please see LICENSE files in the repository root for full details.
+*/
+
+import { test, expect } from "../../element-web-test";
+import { Bot } from "../../pages/bot";
+
+const ROOM_NAME = "Test room";
+const NAME = "Alice";
+
+test.use({
+    synapseConfig: {
+        presence: {
+            enabled: false,
+            include_offline_users_on_sync: false,
+        },
+    },
+    displayName: NAME,
+    disablePresence: true,
+});
+
+test.describe("Memberlist", () => {
+    test.beforeEach(async ({ app, user, page, homeserver }, testInfo) => {
+        testInfo.setTimeout(testInfo.timeout + 30_000);
+        const id = await app.client.createRoom({ name: ROOM_NAME });
+        const newBots: Bot[] = [];
+        const names = ["Bob", "Bob", "Susan"];
+        for (let i = 0; i < 3; i++) {
+            const displayName = names[i];
+            const autoAcceptInvites = displayName !== "Susan";
+            const bot = new Bot(page, homeserver, { displayName, startClient: true, autoAcceptInvites });
+            await bot.prepareClient();
+            await app.client.inviteUser(id, bot.credentials?.userId);
+            newBots.push(bot);
+        }
+    });
+
+    test("Renders correctly", { tag: "@screenshot" }, async ({ page, app }) => {
+        await app.viewRoomByName(ROOM_NAME);
+        const memberlist = await app.toggleMemberlistPanel();
+        await expect(memberlist.locator(".mx_MemberTileView")).toHaveCount(4);
+        await expect(memberlist.getByText("(Invited)")).toHaveCount(1);
+        await expect(page.locator(".mx_MemberListView")).toMatchScreenshot("with-four-members.png");
+    });
+});
diff --git a/playwright/e2e/right-panel/notification-panel.spec.ts b/playwright/e2e/right-panel/notification-panel.spec.ts
index 55a6be04505..6786d8bf8d5 100644
--- a/playwright/e2e/right-panel/notification-panel.spec.ts
+++ b/playwright/e2e/right-panel/notification-panel.spec.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 Suguru Hirahara
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/playwright/e2e/right-panel/right-panel.spec.ts b/playwright/e2e/right-panel/right-panel.spec.ts
index 1e9b8ebe1d4..de86d6bfe62 100644
--- a/playwright/e2e/right-panel/right-panel.spec.ts
+++ b/playwright/e2e/right-panel/right-panel.spec.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -24,7 +24,7 @@ const ROOM_ADDRESS_LONG =
     "loremIpsumDolorSitAmetConsecteturAdipisicingElitSedDoEiusmodTemporIncididuntUtLaboreEtDoloreMagnaAliqua";
 
 function getMemberTileByName(page: Page, name: string): Locator {
-    return page.locator(`.mx_EntityTile, [title="${name}"]`);
+    return page.locator(`.mx_MemberTileView, [title="${name}"]`);
 }
 
 test.describe("RightPanel", () => {
@@ -38,29 +38,34 @@ test.describe("RightPanel", () => {
     });
 
     test.describe("in rooms", () => {
-        test("should handle long room address and long room name", { tag: "@screenshot" }, async ({ page, app }) => {
-            await app.client.createRoom({ name: ROOM_NAME_LONG });
-            await viewRoomSummaryByName(page, app, ROOM_NAME_LONG);
-
-            await app.settings.openRoomSettings();
-
-            // Set a local room address
-            const localAddresses = page.locator(".mx_SettingsFieldset", { hasText: "Local Addresses" });
-            await localAddresses.getByRole("textbox").fill(ROOM_ADDRESS_LONG);
-            await localAddresses.getByRole("button", { name: "Add" }).click();
-            await expect(localAddresses.getByText(`#${ROOM_ADDRESS_LONG}:localhost`)).toHaveClass(
-                "mx_EditableItem_item",
-            );
-
-            await app.closeDialog();
-
-            // Close and reopen the right panel to render the room address
-            await app.toggleRoomInfoPanel();
-            await expect(page.locator(".mx_RightPanel")).not.toBeVisible();
-            await app.toggleRoomInfoPanel();
-
-            await expect(page.locator(".mx_RightPanel")).toMatchScreenshot("with-name-and-address.png");
-        });
+        test(
+            "should handle long room address and long room name",
+            { tag: "@screenshot" },
+            async ({ page, app, user }) => {
+                await app.client.createRoom({ name: ROOM_NAME_LONG });
+                await viewRoomSummaryByName(page, app, ROOM_NAME_LONG);
+
+                await app.settings.openRoomSettings();
+
+                // Set a local room address
+                const localAddresses = page.locator(".mx_SettingsFieldset", { hasText: "Local Addresses" });
+                await localAddresses.getByRole("textbox").fill(ROOM_ADDRESS_LONG);
+                await expect(page.getByText("This address is available to use")).toBeVisible();
+                await localAddresses.getByRole("button", { name: "Add" }).click();
+                await expect(localAddresses.getByText(`#${ROOM_ADDRESS_LONG}:${user.homeServer}`)).toHaveClass(
+                    "mx_EditableItem_item",
+                );
+
+                await app.closeDialog();
+
+                // Close and reopen the right panel to render the room address
+                await app.toggleRoomInfoPanel();
+                await expect(page.locator(".mx_RightPanel")).not.toBeVisible();
+                await app.toggleRoomInfoPanel();
+
+                await expect(page.locator(".mx_RightPanel")).toMatchScreenshot("with-name-and-address.png");
+            },
+        );
 
         test("should handle clicking add widgets", async ({ page, app }) => {
             await viewRoomSummaryByName(page, app, ROOM_NAME);
@@ -107,14 +112,14 @@ test.describe("RightPanel", () => {
             await viewRoomSummaryByName(page, app, ROOM_NAME);
 
             await page.locator(".mx_RightPanel").getByRole("menuitem", { name: "People" }).click();
-            await expect(page.locator(".mx_MemberList")).toBeVisible();
+            await expect(page.locator(".mx_MemberListView")).toBeVisible();
 
             await getMemberTileByName(page, NAME).click();
             await expect(page.locator(".mx_UserInfo")).toBeVisible();
             await expect(page.locator(".mx_UserInfo_profile").getByText(NAME)).toBeVisible();
 
             await page.getByTestId("base-card-back-button").click();
-            await expect(page.locator(".mx_MemberList")).toBeVisible();
+            await expect(page.locator(".mx_MemberListView")).toBeVisible();
 
             await page.getByLabel("Room info").nth(1).click();
             await checkRoomSummaryCard(page, ROOM_NAME);
@@ -130,14 +135,14 @@ test.describe("RightPanel", () => {
                 .locator(".mx_RoomInfoLine_private")
                 .getByRole("button", { name: /\d member/ })
                 .click();
-            await expect(page.locator(".mx_MemberList")).toBeVisible();
+            await expect(page.locator(".mx_MemberListView")).toBeVisible();
 
             await getMemberTileByName(page, NAME).click();
             await expect(page.locator(".mx_UserInfo")).toBeVisible();
             await expect(page.locator(".mx_UserInfo_profile").getByText(NAME)).toBeVisible();
 
             await page.getByTestId("base-card-back-button").click();
-            await expect(page.locator(".mx_MemberList")).toBeVisible();
+            await expect(page.locator(".mx_MemberListView")).toBeVisible();
         });
     });
 });
diff --git a/playwright/e2e/right-panel/utils.ts b/playwright/e2e/right-panel/utils.ts
index b82698b93eb..0f57178f50a 100644
--- a/playwright/e2e/right-panel/utils.ts
+++ b/playwright/e2e/right-panel/utils.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/playwright/e2e/room-directory/room-directory.spec.ts b/playwright/e2e/room-directory/room-directory.spec.ts
index f299a929bb7..8f90ef4b7ef 100644
--- a/playwright/e2e/room-directory/room-directory.spec.ts
+++ b/playwright/e2e/room-directory/room-directory.spec.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -10,42 +10,50 @@ import type { Preset, Visibility } from "matrix-js-sdk/src/matrix";
 import { test, expect } from "../../element-web-test";
 
 test.describe("Room Directory", () => {
+    test.skip(({ homeserverType }) => homeserverType === "pinecone", "Pinecone's /publicRooms API takes forever");
     test.use({
         displayName: "Ray",
         botCreateOpts: { displayName: "Paul" },
     });
 
-    test("should allow admin to add alias & publish room to directory", async ({ page, app, user, bot }) => {
-        const roomId = await app.client.createRoom({
-            name: "Gaming",
-            preset: "public_chat" as Preset,
-        });
-
-        await app.viewRoomByName("Gaming");
-        await app.settings.openRoomSettings();
-
-        // First add a local address `gaming`
-        const localAddresses = page.locator(".mx_SettingsFieldset", { hasText: "Local Addresses" });
-        await localAddresses.getByRole("textbox").fill("gaming");
-        await localAddresses.getByRole("button", { name: "Add" }).click();
-        await expect(localAddresses.getByText("#gaming:localhost")).toHaveClass("mx_EditableItem_item");
-
-        // Publish into the public rooms directory
-        const publishedAddresses = page.locator(".mx_SettingsFieldset", { hasText: "Published Addresses" });
-        await expect(publishedAddresses.locator("#canonicalAlias")).toHaveValue("#gaming:localhost");
-        const checkbox = publishedAddresses
-            .locator(".mx_SettingsFlag", { hasText: "Publish this room to the public in localhost's room directory?" })
-            .getByRole("switch");
-        await checkbox.check();
-        await expect(checkbox).toBeChecked();
-
-        await app.closeDialog();
-
-        const resp = await bot.publicRooms({});
-        expect(resp.total_room_count_estimate).toEqual(1);
-        expect(resp.chunk).toHaveLength(1);
-        expect(resp.chunk[0].room_id).toEqual(roomId);
-    });
+    test(
+        "should allow admin to add alias & publish room to directory",
+        { tag: "@no-webkit" },
+        async ({ page, app, user, bot }) => {
+            const roomId = await app.client.createRoom({
+                name: "Gaming",
+                preset: "public_chat" as Preset,
+            });
+
+            await app.viewRoomByName("Gaming");
+            await app.settings.openRoomSettings();
+
+            // First add a local address `gaming`
+            const localAddresses = page.locator(".mx_SettingsFieldset", { hasText: "Local Addresses" });
+            await localAddresses.getByRole("textbox").fill("gaming");
+            await expect(page.getByText("This address is available to use")).toBeVisible();
+            await localAddresses.getByRole("button", { name: "Add" }).click();
+            await expect(localAddresses.getByText(`#gaming:${user.homeServer}`)).toHaveClass("mx_EditableItem_item");
+
+            // Publish into the public rooms directory
+            const publishedAddresses = page.locator(".mx_SettingsFieldset", { hasText: "Published Addresses" });
+            await expect(publishedAddresses.locator("#canonicalAlias")).toHaveValue(`#gaming:${user.homeServer}`);
+            const checkbox = publishedAddresses
+                .locator(".mx_SettingsFlag", {
+                    hasText: `Publish this room to the public in ${user.homeServer}'s room directory?`,
+                })
+                .getByRole("switch");
+            await checkbox.check();
+            await expect(checkbox).toBeChecked();
+
+            await app.closeDialog();
+
+            const resp = await bot.publicRooms({});
+            expect(resp.total_room_count_estimate).toEqual(1);
+            expect(resp.chunk).toHaveLength(1);
+            expect(resp.chunk[0].room_id).toEqual(roomId);
+        },
+    );
 
     test(
         "should allow finding published rooms in directory",
@@ -80,7 +88,7 @@ test.describe("Room Directory", () => {
                 .getByRole("button", { name: "Join" })
                 .click();
 
-            await expect(page).toHaveURL("/#/room/#test1234:localhost");
+            await expect(page).toHaveURL(`/#/room/#test1234:${user.homeServer}`);
         },
     );
 });
diff --git a/playwright/e2e/room/room-header.spec.ts b/playwright/e2e/room/room-header.spec.ts
index 971508b25bb..7fe0cb3d476 100644
--- a/playwright/e2e/room/room-header.spec.ts
+++ b/playwright/e2e/room/room-header.spec.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 Suguru Hirahara
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -71,7 +71,9 @@ test.describe("Room Header", () => {
 
                 // Assert the size of buttons on RoomHeader are specified and the buttons are not compressed
                 // Note these assertions do not check the size of mx_LegacyRoomHeader_name button
-                const buttons = header.locator(".mx_Flex").getByRole("button");
+                const buttons = header.getByRole("button").filter({
+                    has: page.locator("svg"),
+                });
                 await expect(buttons).toHaveCount(5);
 
                 for (const button of await buttons.all()) {
diff --git a/playwright/e2e/room/room.spec.ts b/playwright/e2e/room/room.spec.ts
index 76fa64a6488..6181333e871 100644
--- a/playwright/e2e/room/room.spec.ts
+++ b/playwright/e2e/room/room.spec.ts
@@ -2,11 +2,11 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
-import type { EventType } from "matrix-js-sdk/src/matrix";
+import type { AccountDataEvents } from "matrix-js-sdk/src/matrix";
 import { test, expect } from "../../element-web-test";
 import { Bot } from "../../pages/bot";
 
@@ -28,7 +28,7 @@ test.describe("Room Directory", () => {
                 const charlieRoom = await cli.createRoom({ is_direct: true });
                 await cli.invite(bobRoom.room_id, bob);
                 await cli.invite(charlieRoom.room_id, charlie);
-                await cli.setAccountData("m.direct" as EventType, {
+                await cli.setAccountData("m.direct" as keyof AccountDataEvents, {
                     [bob]: [bobRoom.room_id],
                     [charlie]: [charlieRoom.room_id],
                 });
diff --git a/playwright/e2e/room_options/marked_unread.spec.ts b/playwright/e2e/room_options/marked_unread.spec.ts
index ec5b1d36798..2817bbc921a 100644
--- a/playwright/e2e/room_options/marked_unread.spec.ts
+++ b/playwright/e2e/room_options/marked_unread.spec.ts
@@ -2,15 +2,18 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 import { test, expect } from "../../element-web-test";
+import { isDendrite } from "../../plugins/homeserver/dendrite";
 
 const TEST_ROOM_NAME = "The mark unread test room";
 
 test.describe("Mark as Unread", () => {
+    test.skip(isDendrite, "due to Dendrite bug https://github.com/element-hq/dendrite/issues/2970");
+
     test.use({
         displayName: "Tom",
         botCreateOpts: {
@@ -48,6 +51,6 @@ test.describe("Mark as Unread", () => {
         await roomTile.getByRole("button", { name: "Room options" }).click();
         await page.getByRole("menuitem", { name: "Mark as unread" }).click();
 
-        expect(page.getByLabel(TEST_ROOM_NAME + " Unread messages.")).toBeVisible();
+        await expect(page.getByLabel(TEST_ROOM_NAME + " Unread messages.")).toBeVisible();
     });
 });
diff --git a/playwright/e2e/settings/account-user-settings-tab.spec.ts b/playwright/e2e/settings/account-user-settings-tab.spec.ts
index 7390ccfd8d1..df011bdc4e5 100644
--- a/playwright/e2e/settings/account-user-settings-tab.spec.ts
+++ b/playwright/e2e/settings/account-user-settings-tab.spec.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 Suguru Hirahara
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -34,14 +34,14 @@ test.describe("Account user settings tab", () => {
         await expect(profile.getByRole("textbox", { name: "Display Name" })).toHaveValue(USER_NAME);
 
         // Assert that a userId is rendered
-        expect(uut.getByLabel("Username")).toHaveText(user.userId);
+        await expect(uut.getByLabel("Username")).toHaveText(user.userId);
 
         // Wait until spinners disappear
         await expect(uut.getByTestId("accountSection").locator(".mx_Spinner")).not.toBeVisible();
         await expect(uut.getByTestId("discoverySection").locator(".mx_Spinner")).not.toBeVisible();
 
         const accountSection = uut.getByTestId("accountSection");
-        accountSection.scrollIntoViewIfNeeded();
+        await accountSection.scrollIntoViewIfNeeded();
         // Assert that input areas for changing a password exists
         await expect(accountSection.getByLabel("Current password")).toBeVisible();
         await expect(accountSection.getByLabel("New Password")).toBeVisible();
diff --git a/playwright/e2e/settings/appearance-user-settings-tab/appearance-user-settings-tab.spec.ts b/playwright/e2e/settings/appearance-user-settings-tab/appearance-user-settings-tab.spec.ts
index c60ecb99d25..b4eeed7728f 100644
--- a/playwright/e2e/settings/appearance-user-settings-tab/appearance-user-settings-tab.spec.ts
+++ b/playwright/e2e/settings/appearance-user-settings-tab/appearance-user-settings-tab.spec.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 Suguru Hirahara
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/playwright/e2e/settings/appearance-user-settings-tab/index.ts b/playwright/e2e/settings/appearance-user-settings-tab/index.ts
index d2810b021bf..be609edf9f5 100644
--- a/playwright/e2e/settings/appearance-user-settings-tab/index.ts
+++ b/playwright/e2e/settings/appearance-user-settings-tab/index.ts
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2024 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/playwright/e2e/settings/appearance-user-settings-tab/message-layout-panel.spec.ts b/playwright/e2e/settings/appearance-user-settings-tab/message-layout-panel.spec.ts
index 157942a5853..ce0d614d905 100644
--- a/playwright/e2e/settings/appearance-user-settings-tab/message-layout-panel.spec.ts
+++ b/playwright/e2e/settings/appearance-user-settings-tab/message-layout-panel.spec.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 Suguru Hirahara
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/playwright/e2e/settings/appearance-user-settings-tab/theme-choice-panel.spec.ts b/playwright/e2e/settings/appearance-user-settings-tab/theme-choice-panel.spec.ts
index 63b53caa23e..1fad16948d2 100644
--- a/playwright/e2e/settings/appearance-user-settings-tab/theme-choice-panel.spec.ts
+++ b/playwright/e2e/settings/appearance-user-settings-tab/theme-choice-panel.spec.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 Suguru Hirahara
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/playwright/e2e/settings/device-management.spec.ts b/playwright/e2e/settings/device-management.spec.ts
index cc7d033d6c1..949ce582e3a 100644
--- a/playwright/e2e/settings/device-management.spec.ts
+++ b/playwright/e2e/settings/device-management.spec.ts
@@ -2,12 +2,15 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 import { test, expect } from "../../element-web-test";
+import { uiaLongSessionTimeoutHomeserver } from "../../plugins/homeserver/synapse/uiaLongSessionTimeoutHomeserver.ts";
 
+// This is needed to not get stopped by UIA when deleting other devices
+test.use(uiaLongSessionTimeoutHomeserver);
 test.describe("Device manager", () => {
     test.use({
         displayName: "Alice",
diff --git a/playwright/e2e/settings/encryption-user-tab/index.ts b/playwright/e2e/settings/encryption-user-tab/index.ts
new file mode 100644
index 00000000000..f8adbb2e336
--- /dev/null
+++ b/playwright/e2e/settings/encryption-user-tab/index.ts
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2024 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+import { Page } from "@playwright/test";
+import { GeneratedSecretStorageKey } from "matrix-js-sdk/src/crypto-api";
+
+import { ElementAppPage } from "../../../pages/ElementAppPage";
+import { test as base, expect } from "../../../element-web-test";
+export { expect };
+
+/**
+ * Set up for the encryption tab test
+ */
+export const test = base.extend<{
+    util: Helpers;
+}>({
+    util: async ({ page, app, bot }, use) => {
+        await use(new Helpers(page, app));
+    },
+});
+
+class Helpers {
+    constructor(
+        private page: Page,
+        private app: ElementAppPage,
+    ) {}
+
+    /**
+     * Open the encryption tab
+     */
+    openEncryptionTab() {
+        return this.app.settings.openUserSettings("Encryption");
+    }
+
+    /**
+     * Go through the device verification flow using the recovery key.
+     */
+    async verifyDevice(recoveryKey: GeneratedSecretStorageKey) {
+        // Select the security phrase
+        await this.page.getByRole("button", { name: "Verify with Security Key or Phrase" }).click();
+        await this.enterRecoveryKey(recoveryKey);
+        await this.page.getByRole("button", { name: "Done" }).click();
+    }
+
+    /**
+     * Fill the recovery key in the dialog
+     * @param recoveryKey
+     */
+    async enterRecoveryKey(recoveryKey: GeneratedSecretStorageKey) {
+        // Select to use recovery key
+        await this.page.getByRole("button", { name: "use your Security Key" }).click();
+
+        // Fill the recovery key
+        const dialog = this.page.locator(".mx_Dialog");
+        await dialog.getByRole("textbox").fill(recoveryKey.encodedPrivateKey);
+        await dialog.getByRole("button", { name: "Continue" }).click();
+    }
+
+    /**
+     * Get the encryption tab content
+     */
+    getEncryptionTabContent() {
+        return this.page.getByTestId("encryptionTab");
+    }
+
+    /**
+     * Set the default key id of the secret storage to `null`
+     */
+    async removeSecretStorageDefaultKeyId() {
+        const client = await this.app.client.prepareClient();
+        await client.evaluate(async (client) => {
+            await client.secretStorage.setDefaultKeyId(null);
+        });
+    }
+
+    /**
+     * Get the security key from the clipboard and fill in the input field
+     * Then click on the finish button
+     * @param title - The title of the dialog
+     * @param confirmButtonLabel - The label of the confirm button
+     * @param screenshot
+     */
+    async confirmRecoveryKey(title: string, confirmButtonLabel: string, screenshot: `${string}.png`) {
+        const dialog = this.getEncryptionTabContent();
+        await expect(dialog.getByText(title, { exact: true })).toBeVisible();
+        await expect(dialog).toMatchScreenshot(screenshot);
+
+        const handle = await this.page.evaluateHandle(() => navigator.clipboard.readText());
+        const clipboardContent = await handle.jsonValue();
+        await dialog.getByRole("textbox").fill(clipboardContent);
+        await dialog.getByRole("button", { name: confirmButtonLabel }).click();
+        await expect(dialog).toMatchScreenshot("default-recovery.png");
+    }
+}
diff --git a/playwright/e2e/settings/encryption-user-tab/recovery.spec.ts b/playwright/e2e/settings/encryption-user-tab/recovery.spec.ts
new file mode 100644
index 00000000000..e6812cd450b
--- /dev/null
+++ b/playwright/e2e/settings/encryption-user-tab/recovery.spec.ts
@@ -0,0 +1,178 @@
+/*
+ * Copyright 2024 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+import { GeneratedSecretStorageKey } from "matrix-js-sdk/src/crypto-api";
+import { Page } from "@playwright/test";
+
+import { test, expect } from ".";
+import {
+    checkDeviceIsConnectedKeyBackup,
+    checkDeviceIsCrossSigned,
+    createBot,
+    verifySession,
+} from "../../crypto/utils";
+
+test.describe("Recovery section in Encryption tab", () => {
+    test.use({
+        displayName: "Alice",
+    });
+
+    let recoveryKey: GeneratedSecretStorageKey;
+    let expectedBackupVersion: string;
+
+    test.beforeEach(async ({ page, homeserver, credentials }) => {
+        const res = await createBot(page, homeserver, credentials);
+        recoveryKey = res.recoveryKey;
+        expectedBackupVersion = res.expectedBackupVersion;
+    });
+
+    test("should verify the device", { tag: "@screenshot" }, async ({ page, app, util }) => {
+        const dialog = await util.openEncryptionTab();
+
+        // The user's device is in an unverified state, therefore the only option available to them here is to verify it
+        const verifyButton = dialog.getByRole("button", { name: "Verify this device" });
+        await expect(verifyButton).toBeVisible();
+        await expect(util.getEncryptionTabContent()).toMatchScreenshot("verify-device-encryption-tab.png");
+        await verifyButton.click();
+
+        await util.verifyDevice(recoveryKey);
+        await expect(util.getEncryptionTabContent()).toMatchScreenshot("default-recovery.png");
+
+        // Check that our device is now cross-signed
+        await checkDeviceIsCrossSigned(app);
+
+        // Check that the current device is connected to key backup
+        // The backup decryption key should be in cache also, as we got it directly from the 4S
+        await app.closeDialog();
+        await checkDeviceIsConnectedKeyBackup(page, expectedBackupVersion, true);
+    });
+
+    test(
+        "should change the recovery key",
+        { tag: "@screenshot" },
+        async ({ page, app, homeserver, credentials, util, context }) => {
+            await verifySession(app, "new passphrase");
+            const dialog = await util.openEncryptionTab();
+
+            // The user can only change the recovery key
+            const changeButton = dialog.getByRole("button", { name: "Change recovery key" });
+            await expect(changeButton).toBeVisible();
+            await expect(util.getEncryptionTabContent()).toMatchScreenshot("default-recovery.png");
+            await changeButton.click();
+
+            // Display the new recovery key and click on the copy button
+            await expect(dialog.getByText("Change recovery key?")).toBeVisible();
+            await expect(util.getEncryptionTabContent()).toMatchScreenshot("change-key-1-encryption-tab.png", {
+                mask: [dialog.getByTestId("recoveryKey")],
+            });
+            await dialog.getByRole("button", { name: "Copy" }).click();
+            await dialog.getByRole("button", { name: "Continue" }).click();
+
+            // Confirm the recovery key
+            await util.confirmRecoveryKey(
+                "Enter your new recovery key",
+                "Confirm new recovery key",
+                "change-key-2-encryption-tab.png",
+            );
+        },
+    );
+
+    test("should setup the recovery key", { tag: "@screenshot" }, async ({ page, app, util }) => {
+        await verifySession(app, "new passphrase");
+        await util.removeSecretStorageDefaultKeyId();
+
+        // The key backup is deleted and the user needs to set it up
+        const dialog = await util.openEncryptionTab();
+        const setupButton = dialog.getByRole("button", { name: "Set up recovery" });
+        await expect(setupButton).toBeVisible();
+        await expect(util.getEncryptionTabContent()).toMatchScreenshot("set-up-recovery.png");
+        await setupButton.click();
+
+        // Display an informative panel about the recovery key
+        await expect(dialog.getByRole("heading", { name: "Set up recovery" })).toBeVisible();
+        await expect(util.getEncryptionTabContent()).toMatchScreenshot("set-up-key-1-encryption-tab.png");
+        await dialog.getByRole("button", { name: "Continue" }).click();
+
+        // Display the new recovery key and click on the copy button
+        await expect(dialog.getByText("Save your recovery key somewhere safe")).toBeVisible();
+        await expect(util.getEncryptionTabContent()).toMatchScreenshot("set-up-key-2-encryption-tab.png", {
+            mask: [dialog.getByTestId("recoveryKey")],
+        });
+        await dialog.getByRole("button", { name: "Copy" }).click();
+        await dialog.getByRole("button", { name: "Continue" }).click();
+
+        // Confirm the recovery key
+        await util.confirmRecoveryKey(
+            "Enter your recovery key to confirm",
+            "Finish set up",
+            "set-up-key-3-encryption-tab.png",
+        );
+
+        // The recovery key is now set up and the user can change it
+        await expect(dialog.getByRole("button", { name: "Change recovery key" })).toBeVisible();
+
+        await app.closeDialog();
+        // Check that the current device is connected to key backup and the backup version is the expected one
+        await checkDeviceIsConnectedKeyBackup(page, "1", true);
+    });
+
+    // Test what happens if the cross-signing secrets are in secret storage but are not cached in the local DB.
+    //
+    // This can happen if we verified another device and secret-gossiping failed, or the other device itself lacked the secrets.
+    // We simulate this case by deleting the cached secrets in the indexedDB.
+    test(
+        "should enter the recovery key when the secrets are not cached",
+        { tag: "@screenshot" },
+        async ({ page, app, util }) => {
+            await verifySession(app, "new passphrase");
+            // We need to delete the cached secrets
+            await deleteCachedSecrets(page);
+
+            await util.openEncryptionTab();
+            // We ask the user to enter the recovery key
+            const dialog = util.getEncryptionTabContent();
+            const enterKeyButton = dialog.getByRole("button", { name: "Enter recovery key" });
+            await expect(enterKeyButton).toBeVisible();
+            await expect(dialog).toMatchScreenshot("out-of-sync-recovery.png");
+            await enterKeyButton.click();
+
+            // Fill the recovery key
+            await util.enterRecoveryKey(recoveryKey);
+            await expect(dialog).toMatchScreenshot("default-recovery.png");
+
+            // Check that our device is now cross-signed
+            await checkDeviceIsCrossSigned(app);
+
+            // Check that the current device is connected to key backup
+            // The backup decryption key should be in cache also, as we got it directly from the 4S
+            await app.closeDialog();
+            await checkDeviceIsConnectedKeyBackup(page, expectedBackupVersion, true);
+        },
+    );
+});
+
+/**
+ * Remove the cached secrets from the indexedDB
+ * This is a workaround to simulate the case where the secrets are not cached.
+ */
+async function deleteCachedSecrets(page: Page) {
+    await page.evaluate(async () => {
+        const removeCachedSecrets = new Promise((resolve) => {
+            const request = window.indexedDB.open("matrix-js-sdk::matrix-sdk-crypto");
+            request.onsuccess = async (event: Event & { target: { result: IDBDatabase } }) => {
+                const db = event.target.result;
+                const request = db.transaction("core", "readwrite").objectStore("core").delete("private_identity");
+                request.onsuccess = () => {
+                    db.close();
+                    resolve(undefined);
+                };
+            };
+        });
+        await removeCachedSecrets;
+    });
+    await page.reload();
+}
diff --git a/playwright/e2e/settings/general-room-settings-tab.spec.ts b/playwright/e2e/settings/general-room-settings-tab.spec.ts
index 828ba5285bb..376412914a0 100644
--- a/playwright/e2e/settings/general-room-settings-tab.spec.ts
+++ b/playwright/e2e/settings/general-room-settings-tab.spec.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 Suguru Hirahara
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -36,15 +36,16 @@ test.describe("General room settings tab", () => {
         await expect(settings.getByText("Show more")).toBeVisible();
     });
 
-    test("long address should not cause dialog to overflow", async ({ page, app }) => {
+    test("long address should not cause dialog to overflow", { tag: "@no-webkit" }, async ({ page, app, user }) => {
         const settings = await app.settings.openRoomSettings("General");
         // 1. Set the room-address to be a really long string
         const longString = "abcasdhjasjhdaj1jh1asdhasjdhajsdhjavhjksd".repeat(4);
         await settings.locator("#roomAliases input[label='Room address']").fill(longString);
+        await expect(page.getByText("This address is available to use")).toBeVisible();
         await settings.locator("#roomAliases").getByText("Add", { exact: true }).click();
 
         // 2. wait for the new setting to apply ...
-        await expect(settings.locator("#canonicalAlias")).toHaveValue(`#${longString}:localhost`);
+        await expect(settings.locator("#canonicalAlias")).toHaveValue(`#${longString}:${user.homeServer}`);
 
         // 3. Check if the dialog overflows
         const dialogBoundingBox = await page.locator(".mx_Dialog").boundingBox();
diff --git a/playwright/e2e/settings/preferences-user-settings-tab.spec.ts b/playwright/e2e/settings/preferences-user-settings-tab.spec.ts
index 8dc2570b426..5c7c9efffb8 100644
--- a/playwright/e2e/settings/preferences-user-settings-tab.spec.ts
+++ b/playwright/e2e/settings/preferences-user-settings-tab.spec.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 Copyright 2023 Suguru Hirahara
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -24,14 +24,14 @@ test.describe("Preferences user settings tab", () => {
     });
 
     test("should be rendered properly", { tag: "@screenshot" }, async ({ app, page, user }) => {
-        page.setViewportSize({ width: 1024, height: 3300 });
+        await page.setViewportSize({ width: 1024, height: 3300 });
         const tab = await app.settings.openUserSettings("Preferences");
         // Assert that the top heading is rendered
         await expect(tab.getByRole("heading", { name: "Preferences" })).toBeVisible();
         await expect(tab).toMatchScreenshot("Preferences-user-settings-tab-should-be-rendered-properly-1.png");
     });
 
-    test("should be able to change the app language", async ({ uut, user }) => {
+    test("should be able to change the app language", { tag: ["@no-firefox", "@no-webkit"] }, async ({ uut, user }) => {
         // Check language and region setting dropdown
         const languageInput = uut.getByRole("button", { name: "Language Dropdown" });
         await languageInput.scrollIntoViewIfNeeded();
@@ -61,7 +61,7 @@ test.describe("Preferences user settings tab", () => {
         // Click the button to display the dropdown menu
         await timezoneInput.getByRole("button", { name: "Set timezone" }).click();
         // Select a different value
-        timezoneInput.getByRole("option", { name: /Africa\/Abidjan/ }).click();
+        await timezoneInput.getByRole("option", { name: /Africa\/Abidjan/ }).click();
         // Check the new value
         await expect(timezoneValue.getByText("Africa/Abidjan")).toBeVisible();
     });
diff --git a/playwright/e2e/settings/roles-permissions-room-settings-tab.spec.ts b/playwright/e2e/settings/roles-permissions-room-settings-tab.spec.ts
index b9fc7c10eff..1193afe135c 100644
--- a/playwright/e2e/settings/roles-permissions-room-settings-tab.spec.ts
+++ b/playwright/e2e/settings/roles-permissions-room-settings-tab.spec.ts
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2024 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
@@ -37,7 +37,9 @@ test.describe("Roles & Permissions room settings tab", () => {
         // Change the role of Alice to Moderator (50)
         await combobox.selectOption("Moderator");
         await expect(combobox).toHaveValue("50");
+        const respPromise = page.waitForRequest("**/state/**");
         await applyButton.click();
+        await respPromise;
 
         // Reload and check Alice is still Moderator (50)
         await page.reload();
diff --git a/playwright/e2e/settings/security-user-settings-tab.spec.ts b/playwright/e2e/settings/security-user-settings-tab.spec.ts
index e7562698c33..b723d1398fe 100644
--- a/playwright/e2e/settings/security-user-settings-tab.spec.ts
+++ b/playwright/e2e/settings/security-user-settings-tab.spec.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 Copyright 2023 Suguru Hirahara
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/playwright/e2e/share-dialog/share-dialog.spec.ts b/playwright/e2e/share-dialog/share-dialog.spec.ts
index e0993dd1bc4..58574a46ffe 100644
--- a/playwright/e2e/share-dialog/share-dialog.spec.ts
+++ b/playwright/e2e/share-dialog/share-dialog.spec.ts
@@ -1,7 +1,7 @@
 /*
  * Copyright 2024 New Vector Ltd.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
@@ -23,7 +23,7 @@ test.describe("Share dialog", () => {
 
         const dialog = page.getByRole("dialog", { name: "Share room" });
         await expect(dialog.getByText(`https://matrix.to/#/${room.roomId}`)).toBeVisible();
-        expect(dialog).toMatchScreenshot("share-dialog-room.png", {
+        await expect(dialog).toMatchScreenshot("share-dialog-room.png", {
             // QRCode and url changes at every run
             mask: [page.locator(".mx_QRCode"), page.locator(".mx_ShareDialog_top > span")],
         });
@@ -40,7 +40,7 @@ test.describe("Share dialog", () => {
 
         const dialog = page.getByRole("dialog", { name: "Share User" });
         await expect(dialog.getByText(`https://matrix.to/#/${user.userId}`)).toBeVisible();
-        expect(dialog).toMatchScreenshot("share-dialog-user.png", {
+        await expect(dialog).toMatchScreenshot("share-dialog-user.png", {
             // QRCode changes at every run
             mask: [page.locator(".mx_QRCode")],
         });
@@ -57,7 +57,7 @@ test.describe("Share dialog", () => {
 
         const dialog = page.getByRole("dialog", { name: "Share Room Message" });
         await expect(dialog.getByRole("checkbox", { name: "Link to selected message" })).toBeChecked();
-        expect(dialog).toMatchScreenshot("share-dialog-event.png", {
+        await expect(dialog).toMatchScreenshot("share-dialog-event.png", {
             // QRCode and url changes at every run
             mask: [page.locator(".mx_QRCode"), page.locator(".mx_ShareDialog_top > span")],
         });
diff --git a/playwright/e2e/sliding-sync/sliding-sync.spec.ts b/playwright/e2e/sliding-sync/sliding-sync.spec.ts
index 885948980e7..0e7d9cac28e 100644
--- a/playwright/e2e/sliding-sync/sliding-sync.spec.ts
+++ b/playwright/e2e/sliding-sync/sliding-sync.spec.ts
@@ -2,22 +2,77 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 import { Page, Request } from "@playwright/test";
+import { GenericContainer, StartedTestContainer, Wait } from "testcontainers";
 
-import { test, expect } from "../../element-web-test";
+import { test as base, expect } from "../../element-web-test";
 import type { ElementAppPage } from "../../pages/ElementAppPage";
 import type { Bot } from "../../pages/bot";
 
-test.describe("Sliding Sync", () => {
-    let roomId: string;
+const test = base.extend<{
+    slidingSyncProxy: StartedTestContainer;
+    testRoom: { roomId: string; name: string };
+    joinedBot: Bot;
+}>({
+    slidingSyncProxy: async ({ logger, network, postgres, page, homeserver }, use, testInfo) => {
+        const container = await new GenericContainer("ghcr.io/matrix-org/sliding-sync:v0.99.3")
+            .withNetwork(network)
+            .withExposedPorts(8008)
+            .withLogConsumer(logger.getConsumer("sliding-sync-proxy"))
+            .withWaitStrategy(Wait.forHttp("/client/server.json", 8008))
+            .withEnvironment({
+                SYNCV3_SECRET: "bwahahaha",
+                SYNCV3_DB: `user=${postgres.getUsername()} dbname=postgres password=${postgres.getPassword()} host=postgres sslmode=disable`,
+                SYNCV3_SERVER: `http://homeserver:8008`,
+            })
+            .start();
+
+        const proxyAddress = `http://${container.getHost()}:${container.getMappedPort(8008)}`;
+        await page.addInitScript((proxyAddress) => {
+            window.localStorage.setItem(
+                "mx_local_settings",
+                JSON.stringify({
+                    feature_sliding_sync_proxy_url: proxyAddress,
+                }),
+            );
+            window.localStorage.setItem("mx_labs_feature_feature_sliding_sync", "true");
+        }, proxyAddress);
+        await use(container);
+        await container.stop();
+    },
+    // Ensure slidingSyncProxy is set up before the user fixture as it relies on an init script
+    credentials: async ({ slidingSyncProxy, credentials }, use) => {
+        await use(credentials);
+    },
+    testRoom: async ({ user, app }, use) => {
+        const name = "Test Room";
+        const roomId = await app.client.createRoom({ name });
+        await use({ roomId, name });
+    },
+    joinedBot: async ({ app, bot, testRoom }, use) => {
+        const roomId = testRoom.roomId;
+        await bot.prepareClient();
+        const bobUserId = await bot.evaluate((client) => client.getUserId());
+        await app.client.evaluate(
+            async (client, { bobUserId, roomId }) => {
+                await client.invite(roomId, bobUserId);
+            },
+            { bobUserId, roomId },
+        );
+        await bot.joinRoom(roomId);
+        await use(bot);
+    },
+});
 
-    test.beforeEach(async ({ slidingSyncProxy, page, user, app }) => {
-        roomId = await app.client.createRoom({ name: "Test Room" });
-    });
+test.describe("Sliding Sync", () => {
+    test.skip(
+        ({ homeserverType }) => homeserverType === "pinecone",
+        "due to a bug in Pinecone https://github.com/element-hq/dendrite/issues/3490",
+    );
 
     const checkOrder = async (wantOrder: string[], page: Page) => {
         await expect(page.getByRole("group", { name: "Rooms" }).locator(".mx_RoomTile_title")).toHaveText(wantOrder);
@@ -32,22 +87,13 @@ test.describe("Sliding Sync", () => {
         });
     };
 
-    const createAndJoinBot = async (app: ElementAppPage, bot: Bot): Promise<Bot> => {
-        await bot.prepareClient();
-        const bobUserId = await bot.evaluate((client) => client.getUserId());
-        await app.client.evaluate(
-            async (client, { bobUserId, roomId }) => {
-                await client.invite(roomId, bobUserId);
-            },
-            { bobUserId, roomId },
-        );
-        await bot.joinRoom(roomId);
-        return bot;
-    };
+    // Load the user fixture for all tests
+    test.beforeEach(({ user }) => {});
 
-    test.skip("should render the Rooms list in reverse chronological order by default and allowing sorting A-Z", async ({
+    test("should render the Rooms list in reverse chronological order by default and allowing sorting A-Z", async ({
         page,
         app,
+        testRoom,
     }) => {
         // create rooms and check room names are correct
         for (const fruit of ["Apple", "Pineapple", "Orange"]) {
@@ -55,7 +101,7 @@ test.describe("Sliding Sync", () => {
             await expect(page.getByRole("treeitem", { name: fruit })).toBeVisible();
         }
 
-        // Check count, 3 fruits + 1 room created in beforeEach = 4
+        // Check count, 3 fruits + 1 testRoom = 4
         await expect(page.locator(".mx_RoomSublist_tiles").getByRole("treeitem")).toHaveCount(4);
         await checkOrder(["Orange", "Pineapple", "Apple", "Test Room"], page);
 
@@ -67,11 +113,10 @@ test.describe("Sliding Sync", () => {
         await page.getByRole("menuitemradio", { name: "A-Z" }).dispatchEvent("click");
         await expect(page.locator(".mx_StyledRadioButton_checked").getByText("A-Z")).toBeVisible();
 
-        await page.pause();
         await checkOrder(["Apple", "Orange", "Pineapple", "Test Room"], page);
     });
 
-    test.skip("should move rooms around as new events arrive", async ({ page, app }) => {
+    test("should move rooms around as new events arrive", async ({ page, app, testRoom }) => {
         // create rooms and check room names are correct
         const roomIds: string[] = [];
         for (const fruit of ["Apple", "Pineapple", "Orange"]) {
@@ -94,7 +139,7 @@ test.describe("Sliding Sync", () => {
         await checkOrder(["Pineapple", "Orange", "Apple", "Test Room"], page);
     });
 
-    test.skip("should not move the selected room: it should be sticky", async ({ page, app }) => {
+    test("should not move the selected room: it should be sticky", async ({ page, app, testRoom }) => {
         // create rooms and check room names are correct
         const roomIds: string[] = [];
         for (const fruit of ["Apple", "Pineapple", "Orange"]) {
@@ -122,11 +167,9 @@ test.describe("Sliding Sync", () => {
         await checkOrder(["Apple", "Orange", "Pineapple", "Test Room"], page);
     });
 
-    test.skip("should show the right unread notifications", async ({ page, app, user, bot }) => {
-        const bob = await createAndJoinBot(app, bot);
-
+    test.skip("should show the right unread notifications", async ({ page, user, joinedBot: bob, testRoom }) => {
         // send a message in the test room: unread notification count should increment
-        await bob.sendMessage(roomId, "Hello World");
+        await bob.sendMessage(testRoom.roomId, "Hello World");
 
         const treeItemLocator1 = page.getByRole("treeitem", { name: "Test Room 1 unread message." });
         await expect(treeItemLocator1.locator(".mx_NotificationBadge_count")).toHaveText("1");
@@ -136,7 +179,7 @@ test.describe("Sliding Sync", () => {
         );
 
         // send an @mention: highlight count (red) should be 2.
-        await bob.sendMessage(roomId, `Hello ${user.displayName}`);
+        await bob.sendMessage(testRoom.roomId, `Hello ${user.displayName}`);
         const treeItemLocator2 = page.getByRole("treeitem", {
             name: "Test Room 2 unread messages including mentions.",
         });
@@ -150,9 +193,8 @@ test.describe("Sliding Sync", () => {
         ).not.toBeAttached();
     });
 
-    test.skip("should not show unread indicators", async ({ page, app, bot }) => {
+    test("should not show unread indicators", async ({ page, app, joinedBot: bot, testRoom }) => {
         // TODO: for now. Later we should.
-        await createAndJoinBot(app, bot);
 
         // disable notifs in this room (TODO: CS API call?)
         const locator = page.getByRole("treeitem", { name: "Test Room" });
@@ -165,7 +207,7 @@ test.describe("Sliding Sync", () => {
 
         await checkOrder(["Dummy", "Test Room"], page);
 
-        await bot.sendMessage(roomId, "Do you read me?");
+        await bot.sendMessage(testRoom.roomId, "Do you read me?");
 
         // wait for this message to arrive, tell by the room list resorting
         await checkOrder(["Test Room", "Dummy"], page);
@@ -178,15 +220,18 @@ test.describe("Sliding Sync", () => {
     test("should update user settings promptly", async ({ page, app }) => {
         await app.settings.openUserSettings("Preferences");
         const locator = page.locator(".mx_SettingsFlag").filter({ hasText: "Show timestamps in 12 hour format" });
-        expect(locator).toBeVisible();
-        expect(locator.locator(".mx_ToggleSwitch_on")).not.toBeAttached();
+        await expect(locator).toBeVisible();
+        await expect(locator.locator(".mx_ToggleSwitch_on")).not.toBeAttached();
         await locator.locator(".mx_ToggleSwitch_ball").click();
-        expect(locator.locator(".mx_ToggleSwitch_on")).toBeAttached();
+        await expect(locator.locator(".mx_ToggleSwitch_on")).toBeAttached();
     });
 
-    test.skip("should show and be able to accept/reject/rescind invites", async ({ page, app, bot }) => {
-        await createAndJoinBot(app, bot);
-
+    test("should show and be able to accept/reject/rescind invites", async ({
+        page,
+        app,
+        joinedBot: bot,
+        testRoom,
+    }) => {
         const clientUserId = await app.client.evaluate((client) => client.getUserId());
 
         // invite bot into 3 rooms:
@@ -235,7 +280,7 @@ test.describe("Sliding Sync", () => {
         // now rescind the invite
         await bot.evaluate(
             async (client, { roomRescind, clientUserId }) => {
-                client.kick(roomRescind, clientUserId);
+                await client.kick(roomRescind, clientUserId);
             },
             { roomRescind, clientUserId },
         );
@@ -254,7 +299,7 @@ test.describe("Sliding Sync", () => {
             is_direct: true,
         });
         await app.client.evaluate(async (client, roomId) => {
-            client.setRoomTag(roomId, "m.favourite", { order: 0.5 });
+            await client.setRoomTag(roomId, "m.favourite", { order: 0.5 });
         }, roomId);
         await expect(page.getByRole("group", { name: "Favourites" }).getByText("Favourite DM")).toBeVisible();
         await expect(page.getByRole("group", { name: "People" }).getByText("Favourite DM")).not.toBeAttached();
@@ -262,10 +307,10 @@ test.describe("Sliding Sync", () => {
 
     // Regression test for a bug in SS mode, but would be useful to have in non-SS mode too.
     // This ensures we are setting RoomViewStore state correctly.
-    test.skip("should clear the reply to field when swapping rooms", async ({ page, app }) => {
+    test("should clear the reply to field when swapping rooms", async ({ page, app, testRoom }) => {
         await app.client.createRoom({ name: "Other Room" });
         await expect(page.getByRole("treeitem", { name: "Other Room" })).toBeVisible();
-        await app.client.sendMessage(roomId, "Hello world");
+        await app.client.sendMessage(testRoom.roomId, "Hello world");
 
         // select the room
         await page.getByRole("treeitem", { name: "Test Room" }).click();
@@ -294,11 +339,11 @@ test.describe("Sliding Sync", () => {
     });
 
     // Regression test for https://github.com/vector-im/element-web/issues/21462
-    test.skip("should not cancel replies when permalinks are clicked", async ({ page, app }) => {
+    test("should not cancel replies when permalinks are clicked", async ({ page, app, testRoom }) => {
         // we require a first message as you cannot click the permalink text with the avatar in the way
-        await app.client.sendMessage(roomId, "First message");
-        await app.client.sendMessage(roomId, "Permalink me");
-        await app.client.sendMessage(roomId, "Reply to me");
+        await app.client.sendMessage(testRoom.roomId, "First message");
+        await app.client.sendMessage(testRoom.roomId, "Permalink me");
+        await app.client.sendMessage(testRoom.roomId, "Reply to me");
 
         // select the room
         await page.getByRole("treeitem", { name: "Test Room" }).click();
@@ -322,7 +367,7 @@ test.describe("Sliding Sync", () => {
         await expect(page.locator(".mx_ReplyPreview")).toBeVisible();
     });
 
-    test.skip("should send unsubscribe_rooms for every room switch", async ({ page, app }) => {
+    test("should send unsubscribe_rooms for every room switch", async ({ page, app }) => {
         // create rooms and check room names are correct
         const roomIds: string[] = [];
         for (const fruit of ["Apple", "Pineapple", "Orange"]) {
@@ -330,37 +375,42 @@ test.describe("Sliding Sync", () => {
             roomIds.push(id);
             await expect(page.getByRole("treeitem", { name: fruit })).toBeVisible();
         }
-        const [roomAId, roomPId] = roomIds;
+        const [roomAId, roomPId, roomOId] = roomIds;
 
-        const assertUnsubExists = (request: Request, subRoomId: string, unsubRoomId: string) => {
+        const matchRoomSubRequest = (subRoomId: string) => (request: Request) => {
+            if (!request.url().includes("/sync")) return false;
             const body = request.postDataJSON();
-            // There may be a request without a txn_id, ignore it, as there won't be any subscription changes
-            if (body.txn_id === undefined) {
-                return;
-            }
-            expect(body.unsubscribe_rooms).toEqual([unsubRoomId]);
-            expect(body.room_subscriptions).not.toHaveProperty(unsubRoomId);
-            expect(body.room_subscriptions).toHaveProperty(subRoomId);
+            return body.txn_id && body.room_subscriptions?.[subRoomId];
+        };
+        const matchRoomUnsubRequest = (unsubRoomId: string) => (request: Request) => {
+            if (!request.url().includes("/sync")) return false;
+            const body = request.postDataJSON();
+            return (
+                body.txn_id && body.unsubscribe_rooms?.includes(unsubRoomId) && !body.room_subscriptions?.[unsubRoomId]
+            );
         };
 
-        let promise = page.waitForRequest(/sync/);
-
-        // Select the Test Room
-        await page.getByRole("treeitem", { name: "Apple", exact: true }).click();
-
-        // and wait for playwright to get the request
-        const roomSubscriptions = (await promise).postDataJSON().room_subscriptions;
+        // Select the Test Room and wait for playwright to get the request
+        const [request] = await Promise.all([
+            page.waitForRequest(matchRoomSubRequest(roomAId)),
+            page.getByRole("treeitem", { name: "Apple", exact: true }).click(),
+        ]);
+        const roomSubscriptions = request.postDataJSON().room_subscriptions;
         expect(roomSubscriptions, "room_subscriptions is object").toBeDefined();
 
-        // Switch to another room
-        promise = page.waitForRequest(/sync/);
-        await page.getByRole("treeitem", { name: "Pineapple", exact: true }).click();
-        assertUnsubExists(await promise, roomPId, roomAId);
-
-        // And switch to even another room
-        promise = page.waitForRequest(/sync/);
-        await page.getByRole("treeitem", { name: "Apple", exact: true }).click();
-        assertUnsubExists(await promise, roomPId, roomAId);
+        // Switch to another room and wait for playwright to get the request
+        await Promise.all([
+            page.waitForRequest(matchRoomSubRequest(roomPId)),
+            page.waitForRequest(matchRoomUnsubRequest(roomAId)),
+            page.getByRole("treeitem", { name: "Pineapple", exact: true }).click(),
+        ]);
+
+        // And switch to even another room and wait for playwright to get the request
+        await Promise.all([
+            page.waitForRequest(matchRoomSubRequest(roomOId)),
+            page.waitForRequest(matchRoomUnsubRequest(roomPId)),
+            page.getByRole("treeitem", { name: "Orange", exact: true }).click(),
+        ]);
 
         // TODO: Add tests for encrypted rooms
     });
diff --git a/playwright/e2e/spaces/spaces.spec.ts b/playwright/e2e/spaces/spaces.spec.ts
index 233cdee3b4b..5acb3a672fe 100644
--- a/playwright/e2e/spaces/spaces.spec.ts
+++ b/playwright/e2e/spaces/spaces.spec.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -10,6 +10,7 @@ import type { Locator, Page } from "@playwright/test";
 import { test, expect } from "../../element-web-test";
 import type { Preset, ICreateRoomOpts } from "matrix-js-sdk/src/matrix";
 import { ElementAppPage } from "../../pages/ElementAppPage";
+import { isDendrite } from "../../plugins/homeserver/dendrite";
 
 async function openSpaceCreateMenu(page: Page): Promise<Locator> {
     await page.getByRole("button", { name: "Create a space" }).click();
@@ -50,43 +51,50 @@ function spaceChildInitialState(roomId: string): ICreateRoomOpts["initial_state"
 }
 
 test.describe("Spaces", () => {
+    test.skip(isDendrite, "due to a Dendrite bug https://github.com/element-hq/dendrite/issues/3488");
     test.use({
         displayName: "Sue",
         botCreateOpts: { displayName: "BotBob" },
     });
 
-    test("should allow user to create public space", { tag: "@screenshot" }, async ({ page, app, user }) => {
-        const contextMenu = await openSpaceCreateMenu(page);
-        await expect(contextMenu).toMatchScreenshot("space-create-menu.png");
-
-        await contextMenu.getByRole("button", { name: /Public/ }).click();
-
-        await contextMenu
-            .locator('.mx_SpaceBasicSettings_avatarContainer input[type="file"]')
-            .setInputFiles("playwright/sample-files/riot.png");
-        await contextMenu.getByRole("textbox", { name: "Name" }).fill("Let's have a Riot");
-        await expect(contextMenu.getByRole("textbox", { name: "Address" })).toHaveValue("lets-have-a-riot");
-        await contextMenu.getByRole("textbox", { name: "Description" }).fill("This is a space to reminisce Riot.im!");
-        await contextMenu.getByRole("button", { name: "Create" }).click();
-
-        // Create the default General & Random rooms, as well as a custom "Jokes" room
-        await expect(page.getByPlaceholder("General")).toBeVisible();
-        await expect(page.getByPlaceholder("Random")).toBeVisible();
-        await page.getByPlaceholder("Support").fill("Jokes");
-        await page.getByRole("button", { name: "Continue" }).click();
-
-        // Copy matrix.to link
-        await page.getByRole("button", { name: "Share invite link" }).click();
-        expect(await app.getClipboardText()).toEqual("https://matrix.to/#/#lets-have-a-riot:localhost");
-
-        // Go to space home
-        await page.getByRole("button", { name: "Go to my first room" }).click();
-
-        // Assert rooms exist in the room list
-        await expect(page.getByRole("treeitem", { name: "General" })).toBeVisible();
-        await expect(page.getByRole("treeitem", { name: "Random" })).toBeVisible();
-        await expect(page.getByRole("treeitem", { name: "Jokes" })).toBeVisible();
-    });
+    test(
+        "should allow user to create public space",
+        { tag: ["@screenshot", "@no-webkit"] },
+        async ({ page, app, user }) => {
+            const contextMenu = await openSpaceCreateMenu(page);
+            await expect(contextMenu).toMatchScreenshot("space-create-menu.png");
+
+            await contextMenu.getByRole("button", { name: /Public/ }).click();
+
+            await contextMenu
+                .locator('.mx_SpaceBasicSettings_avatarContainer input[type="file"]')
+                .setInputFiles("playwright/sample-files/riot.png");
+            await contextMenu.getByRole("textbox", { name: "Name" }).fill("Let's have a Riot");
+            await expect(contextMenu.getByRole("textbox", { name: "Address" })).toHaveValue("lets-have-a-riot");
+            await contextMenu
+                .getByRole("textbox", { name: "Description" })
+                .fill("This is a space to reminisce Riot.im!");
+            await contextMenu.getByRole("button", { name: "Create" }).click();
+
+            // Create the default General & Random rooms, as well as a custom "Jokes" room
+            await expect(page.getByPlaceholder("General")).toBeVisible();
+            await expect(page.getByPlaceholder("Random")).toBeVisible();
+            await page.getByPlaceholder("Support").fill("Jokes");
+            await page.getByRole("button", { name: "Continue" }).click();
+
+            // Copy matrix.to link
+            await page.getByRole("button", { name: "Share invite link" }).click();
+            expect(await app.getClipboardText()).toEqual(`https://matrix.to/#/#lets-have-a-riot:${user.homeServer}`);
+
+            // Go to space home
+            await page.getByRole("button", { name: "Go to my first room" }).click();
+
+            // Assert rooms exist in the room list
+            await expect(page.getByRole("treeitem", { name: "General" })).toBeVisible();
+            await expect(page.getByRole("treeitem", { name: "Random" })).toBeVisible();
+            await expect(page.getByRole("treeitem", { name: "Jokes" })).toBeVisible();
+        },
+    );
 
     test("should allow user to create private space", { tag: "@screenshot" }, async ({ page, app, user }) => {
         const menu = await openSpaceCreateMenu(page);
@@ -157,19 +165,19 @@ test.describe("Spaces", () => {
         ).toBeVisible();
     });
 
-    test("should allow user to invite another to a space", async ({ page, app, user, bot }) => {
+    test("should allow user to invite another to a space", { tag: "@no-webkit" }, async ({ page, app, user, bot }) => {
         await app.client.createSpace({
             visibility: "public" as any,
             room_alias_name: "space",
         });
 
-        const menu = await openSpaceContextMenu(page, app, "#space:localhost");
+        const menu = await openSpaceContextMenu(page, app, `#space:${user.homeServer}`);
         await menu.getByRole("menuitem", { name: "Invite" }).click();
 
         const shareDialog = page.locator(".mx_SpacePublicShare");
         // Copy link first
         await shareDialog.getByRole("button", { name: "Share invite link" }).click();
-        expect(await app.getClipboardText()).toEqual("https://matrix.to/#/#space:localhost");
+        expect(await app.getClipboardText()).toEqual(`https://matrix.to/#/#space:${user.homeServer}`);
         // Start Matrix invite flow
         await shareDialog.getByRole("button", { name: "Invite people" }).click();
 
diff --git a/playwright/e2e/spaces/threads-activity-centre/index.ts b/playwright/e2e/spaces/threads-activity-centre/index.ts
index b2b8473640e..d3d3cb352b4 100644
--- a/playwright/e2e/spaces/threads-activity-centre/index.ts
+++ b/playwright/e2e/spaces/threads-activity-centre/index.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -13,6 +13,9 @@ import { test as base, expect } from "../../../element-web-test";
 import { Bot } from "../../../pages/bot";
 import { Client } from "../../../pages/client";
 import { ElementAppPage } from "../../../pages/ElementAppPage";
+import { Credentials } from "../../../plugins/homeserver";
+
+type RoomRef = { name: string; roomId: string };
 
 /**
  * Set up for a read receipt test:
@@ -181,9 +184,10 @@ export class Helpers {
      * Use the supplied client to send messages or perform actions as specified by
      * the supplied {@link Message} items.
      */
-    async sendMessageAsClient(cli: Client, roomName: string | { name: string }, messages: Message[]) {
-        const room = await this.findRoomByName(typeof roomName === "string" ? roomName : roomName.name);
-        const roomId = await room.evaluate((room) => room.roomId);
+    async sendMessageAsClient(cli: Client, roomRef: RoomRef, messages: Message[]) {
+        const roomId = roomRef.roomId;
+        const room = await this.findRoomById(roomId);
+        expect(room).toBeTruthy();
 
         for (const message of messages) {
             if (typeof message === "string") {
@@ -205,7 +209,7 @@ export class Helpers {
     /**
      * Open the room with the supplied name.
      */
-    async goTo(room: string | { name: string }) {
+    async goTo(room: RoomRef) {
         await this.app.viewRoomByName(typeof room === "string" ? room : room.name);
     }
 
@@ -220,10 +224,10 @@ export class Helpers {
         await expect(this.page.locator(".mx_ThreadView_timelinePanelWrapper")).toBeVisible();
     }
 
-    async findRoomByName(roomName: string): Promise<JSHandle<Room>> {
-        return this.app.client.evaluateHandle((cli, roomName) => {
-            return cli.getRooms().find((r) => r.name === roomName);
-        }, roomName);
+    async findRoomById(roomId: string): Promise<JSHandle<Room | undefined>> {
+        return this.app.client.evaluateHandle((cli, roomId) => {
+            return cli.getRooms().find((r) => r.roomId === roomId);
+        }, roomId);
     }
 
     /**
@@ -231,7 +235,7 @@ export class Helpers {
      * @param room - the name of the room to send messages into
      * @param messages - the list of messages to send, these can be strings or implementations of MessageSpec like `editOf`
      */
-    async receiveMessages(room: string | { name: string }, messages: Message[]) {
+    async receiveMessages(room: RoomRef, messages: Message[]) {
         await this.sendMessageAsClient(this.bot, room, messages);
     }
 
@@ -333,12 +337,14 @@ export class Helpers {
      * @param room1
      * @param room2
      * @param msg - MessageBuilder
+     * @param user - the user to mention in the first message
      * @param hasMention - whether to include a mention in the first message
      */
     async populateThreads(
         room1: { name: string; roomId: string },
         room2: { name: string; roomId: string },
         msg: MessageBuilder,
+        user: Credentials,
         hasMention = true,
     ) {
         if (hasMention) {
@@ -347,9 +353,9 @@ export class Helpers {
                 msg.threadedOff("Msg1", {
                     "body": "User",
                     "format": "org.matrix.custom.html",
-                    "formatted_body": "<a href='https://matrix.to/#/@user:localhost'>User</a>",
+                    "formatted_body": `<a href="https://matrix.to/#/${user.userId}">User</a>`,
                     "m.mentions": {
-                        user_ids: ["@user:localhost"],
+                        user_ids: [user.userId],
                     },
                 }),
             ]);
diff --git a/playwright/e2e/spaces/threads-activity-centre/threadsActivityCentre.spec.ts b/playwright/e2e/spaces/threads-activity-centre/threadsActivityCentre.spec.ts
index ecf458c0600..683577dce41 100644
--- a/playwright/e2e/spaces/threads-activity-centre/threadsActivityCentre.spec.ts
+++ b/playwright/e2e/spaces/threads-activity-centre/threadsActivityCentre.spec.ts
@@ -2,14 +2,20 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2024 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
 import { expect, test } from ".";
 import { CommandOrControl } from "../../utils";
+import { isDendrite } from "../../../plugins/homeserver/dendrite";
+
+test.describe("Threads Activity Centre", { tag: "@no-firefox" }, () => {
+    test.skip(
+        isDendrite,
+        "due to Dendrite lacking full threads support https://github.com/element-hq/dendrite/issues/3283",
+    );
 
-test.describe("Threads Activity Centre", () => {
     test.use({
         displayName: "Alice",
         botCreateOpts: { displayName: "Other User" },
@@ -46,16 +52,21 @@ test.describe("Threads Activity Centre", () => {
         await util.assertNotificationTac();
     });
 
-    test("should show a highlight indicator when there is a mention in a thread", async ({ room1, util, msg }) => {
+    test("should show a highlight indicator when there is a mention in a thread", async ({
+        room1,
+        util,
+        msg,
+        user,
+    }) => {
         await util.goTo(room1);
         await util.receiveMessages(room1, [
             "Msg1",
             msg.threadedOff("Msg1", {
                 "body": "User",
                 "format": "org.matrix.custom.html",
-                "formatted_body": "<a href='https://matrix.to/#/@user:localhost'>User</a>",
+                "formatted_body": `<a href="https://matrix.to/#/${user.userId}">User</a>`,
                 "m.mentions": {
-                    user_ids: ["@user:localhost"],
+                    user_ids: [user.userId],
                 },
             }),
         ]);
@@ -64,26 +75,30 @@ test.describe("Threads Activity Centre", () => {
         await util.assertHighlightIndicator();
     });
 
-    test("should show the rooms with unread threads", { tag: "@screenshot" }, async ({ room1, room2, util, msg }) => {
-        await util.goTo(room2);
-        await util.populateThreads(room1, room2, msg);
-        // The indicator should be shown
-        await util.assertHighlightIndicator();
-
-        // Verify that we have the expected rooms in the TAC
-        await util.openTac();
-        await util.assertRoomsInTac([
-            { room: room2.name, notificationLevel: "highlight" },
-            { room: room1.name, notificationLevel: "notification" },
-        ]);
-
-        // Verify that we don't have a visual regression
-        await expect(util.getTacPanel()).toMatchScreenshot("tac-panel-mix-unread.png");
-    });
+    test(
+        "should show the rooms with unread threads",
+        { tag: "@screenshot" },
+        async ({ room1, room2, util, msg, user }) => {
+            await util.goTo(room2);
+            await util.populateThreads(room1, room2, msg, user);
+            // The indicator should be shown
+            await util.assertHighlightIndicator();
+
+            // Verify that we have the expected rooms in the TAC
+            await util.openTac();
+            await util.assertRoomsInTac([
+                { room: room2.name, notificationLevel: "highlight" },
+                { room: room1.name, notificationLevel: "notification" },
+            ]);
+
+            // Verify that we don't have a visual regression
+            await expect(util.getTacPanel()).toMatchScreenshot("tac-panel-mix-unread.png");
+        },
+    );
 
-    test("should update with a thread is read", { tag: "@screenshot" }, async ({ room1, room2, util, msg }) => {
+    test("should update with a thread is read", { tag: "@screenshot" }, async ({ room1, room2, util, msg, user }) => {
         await util.goTo(room2);
-        await util.populateThreads(room1, room2, msg);
+        await util.populateThreads(room1, room2, msg, user);
 
         // Click on the first room in TAC
         await util.openTac();
@@ -104,9 +119,9 @@ test.describe("Threads Activity Centre", () => {
         await expect(util.getTacPanel()).toMatchScreenshot("tac-panel-notification-unread.png");
     });
 
-    test("should order by recency after notification level", async ({ room1, room2, util, msg }) => {
+    test("should order by recency after notification level", async ({ room1, room2, util, msg, user }) => {
         await util.goTo(room2);
-        await util.populateThreads(room1, room2, msg, false);
+        await util.populateThreads(room1, room2, msg, user, false);
 
         await util.openTac();
         await util.assertRoomsInTac([
diff --git a/playwright/e2e/spotlight/spotlight.spec.ts b/playwright/e2e/spotlight/spotlight.spec.ts
index 22513ca47a7..7a5f7d4ea85 100644
--- a/playwright/e2e/spotlight/spotlight.spec.ts
+++ b/playwright/e2e/spotlight/spotlight.spec.ts
@@ -2,15 +2,17 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
-import { test, expect } from "../../element-web-test";
+import type { AccountDataEvents, Visibility } from "matrix-js-sdk/src/matrix";
+import { test as base, expect } from "../../element-web-test";
 import { Filter } from "../../pages/Spotlight";
 import { Bot } from "../../pages/bot";
 import type { Locator, Page } from "@playwright/test";
 import type { ElementAppPage } from "../../pages/ElementAppPage";
+import { isDendrite } from "../../plugins/homeserver/dendrite";
 
 function roomHeaderName(page: Page): Locator {
     return page.locator(".mx_RoomHeader_heading");
@@ -37,41 +39,37 @@ async function startDM(app: ElementAppPage, page: Page, name: string): Promise<v
     await expect(page.getByRole("group", { name: "People" }).getByText(name)).toBeAttached();
 }
 
-test.describe("Spotlight", () => {
-    const bot1Name = "BotBob";
-    let bot1: Bot;
-
-    const bot2Name = "ByteBot";
-    let bot2: Bot;
-
-    const room1Name = "247";
-    let room1Id: string;
-
-    const room2Name = "Lounge";
-    let room2Id: string;
-
-    const room3Name = "Public";
-    let room3Id: string;
-
-    test.use({
-        displayName: "Jim",
-    });
-
-    test.beforeEach(async ({ page, homeserver, app, user }) => {
-        bot1 = new Bot(page, homeserver, { displayName: bot1Name, autoAcceptInvites: true });
-        bot2 = new Bot(page, homeserver, { displayName: bot2Name, autoAcceptInvites: true });
-        const Visibility = await page.evaluate(() => (window as any).matrixcs.Visibility);
-
-        room1Id = await app.client.createRoom({ name: room1Name, visibility: Visibility.Public });
-
-        await bot1.joinRoom(room1Id);
-        const bot1UserId = await bot1.evaluate((client) => client.getUserId());
-        room2Id = await bot2.createRoom({ name: room2Name, visibility: Visibility.Public });
-        await bot2.inviteUser(room2Id, bot1UserId);
-
-        room3Id = await bot2.createRoom({
-            name: room3Name,
-            visibility: Visibility.Public,
+type RoomRef = { name: string; roomId: string };
+const test = base.extend<{
+    bot1: Bot;
+    bot2: Bot;
+    room1: RoomRef;
+    room2: RoomRef;
+    room3: RoomRef;
+}>({
+    bot1: async ({ page, homeserver }, use, testInfo) => {
+        const bot = new Bot(page, homeserver, { displayName: `BotBob_${testInfo.testId}`, autoAcceptInvites: true });
+        await use(bot);
+    },
+    bot2: async ({ page, homeserver }, use, testInfo) => {
+        const bot = new Bot(page, homeserver, { displayName: `ByteBot_${testInfo.testId}`, autoAcceptInvites: true });
+        await use(bot);
+    },
+    room1: async ({ app }, use) => {
+        const name = "247";
+        const roomId = await app.client.createRoom({ name, visibility: "public" as Visibility });
+        await use({ name, roomId });
+    },
+    room2: async ({ bot2 }, use) => {
+        const name = "Lounge";
+        const roomId = await bot2.createRoom({ name, visibility: "public" as Visibility });
+        await use({ name, roomId });
+    },
+    room3: async ({ bot2 }, use) => {
+        const name = "Public";
+        const roomId = await bot2.createRoom({
+            name,
+            visibility: "public" as Visibility,
             initial_state: [
                 {
                     type: "m.room.history_visibility",
@@ -82,9 +80,27 @@ test.describe("Spotlight", () => {
                 },
             ],
         });
-        await bot2.inviteUser(room3Id, bot1UserId);
+        await use({ name, roomId });
+    },
+    context: async ({ context, homeserver }, use) => {
+        // Restart the homeserver to wipe its in-memory db so we can reuse the same user ID without cross-signing prompts
+        await homeserver.restart();
+        await use(context);
+    },
+});
+
+test.describe("Spotlight", () => {
+    test.skip(isDendrite, "due to a Dendrite bug https://github.com/element-hq/dendrite/issues/3488");
+    test.use({
+        displayName: "Jim",
+    });
+
+    test.beforeEach(async ({ page, user, bot1, bot2, room1, room2, room3 }) => {
+        await bot1.joinRoom(room1.roomId);
+        await bot2.inviteUser(room2.roomId, bot1.credentials.userId);
+        await bot2.inviteUser(room3.roomId, bot1.credentials.userId);
 
-        await page.goto("/#/room/" + room1Id);
+        await page.goto(`/#/room/${room1.roomId}`);
         await expect(page.locator(".mx_RoomSublist_skeletonUI")).not.toBeAttached();
     });
 
@@ -116,69 +132,69 @@ test.describe("Spotlight", () => {
         await expect(spotlight.dialog.locator(".mx_SpotlightDialog_filter")).not.toBeAttached();
     });
 
-    test("should find joined rooms", async ({ page, app }) => {
+    test("should find joined rooms", async ({ page, app, room1 }) => {
         const spotlight = await app.openSpotlight();
         await page.waitForTimeout(500); // wait for the dialog to settle
-        await spotlight.search(room1Name);
+        await spotlight.search(room1.name);
         const resultLocator = spotlight.results;
         await expect(resultLocator).toHaveCount(1);
-        await expect(resultLocator.first()).toContainText(room1Name);
+        await expect(resultLocator.first()).toContainText(room1.name);
         await resultLocator.first().click();
-        expect(page.url()).toContain(room1Id);
-        await expect(roomHeaderName(page)).toContainText(room1Name);
+        await expect(page).toHaveURL(new RegExp(`#/room/${room1.roomId}`));
+        await expect(roomHeaderName(page)).toContainText(room1.name);
     });
 
-    test("should find known public rooms", async ({ page, app }) => {
+    test("should find known public rooms", async ({ page, app, room1 }) => {
         const spotlight = await app.openSpotlight();
         await page.waitForTimeout(500); // wait for the dialog to settle
         await spotlight.filter(Filter.PublicRooms);
-        await spotlight.search(room1Name);
+        await spotlight.search(room1.name);
         const resultLocator = spotlight.results;
         await expect(resultLocator).toHaveCount(1);
-        await expect(resultLocator.first()).toContainText(room1Name);
+        await expect(resultLocator.first()).toContainText(room1.name);
         await expect(resultLocator.first()).toContainText("View");
         await resultLocator.first().click();
-        expect(page.url()).toContain(room1Id);
-        await expect(roomHeaderName(page)).toContainText(room1Name);
+        await expect(page).toHaveURL(new RegExp(`#/room/${room1.roomId}`));
+        await expect(roomHeaderName(page)).toContainText(room1.name);
     });
 
-    test("should find unknown public rooms", async ({ page, app }) => {
+    test("should find unknown public rooms", async ({ page, app, room2 }) => {
         const spotlight = await app.openSpotlight();
         await page.waitForTimeout(500); // wait for the dialog to settle
         await spotlight.filter(Filter.PublicRooms);
-        await spotlight.search(room2Name);
+        await spotlight.search(room2.name);
         const resultLocator = spotlight.results;
         await expect(resultLocator).toHaveCount(1);
-        await expect(resultLocator.first()).toContainText(room2Name);
+        await expect(resultLocator.first()).toContainText(room2.name);
         await expect(resultLocator.first()).toContainText("Join");
         await resultLocator.first().click();
-        expect(page.url()).toContain(room2Id);
+        await expect(page).toHaveURL(new RegExp(`#/room/${room2.roomId}`));
         await expect(page.locator(".mx_RoomView_MessageList")).toHaveCount(1);
-        await expect(roomHeaderName(page)).toContainText(room2Name);
+        await expect(roomHeaderName(page)).toContainText(room2.name);
     });
 
-    test("should find unknown public world readable rooms", async ({ page, app }) => {
+    test("should find unknown public world readable rooms", async ({ page, app, room3 }) => {
         const spotlight = await app.openSpotlight();
         await page.waitForTimeout(500); // wait for the dialog to settle
         await spotlight.filter(Filter.PublicRooms);
-        await spotlight.search(room3Name);
+        await spotlight.search(room3.name);
         const resultLocator = spotlight.results;
         await expect(resultLocator).toHaveCount(1);
-        await expect(resultLocator.first()).toContainText(room3Name);
+        await expect(resultLocator.first()).toContainText(room3.name);
         await expect(resultLocator.first()).toContainText("View");
         await resultLocator.first().click();
-        expect(page.url()).toContain(room3Id);
+        await expect(page).toHaveURL(new RegExp(`#/room/${room3.roomId}`));
         await page.getByRole("button", { name: "Join the discussion" }).click();
-        await expect(roomHeaderName(page)).toHaveText(room3Name);
+        await expect(roomHeaderName(page)).toHaveText(room3.name);
     });
 
     // TODO: We currently can’t test finding rooms on other homeservers/other protocols
     // We obviously don’t have federation or bridges in local e2e tests
-    test.skip("should find unknown public rooms on other homeservers", async ({ page, app }) => {
+    test.skip("should find unknown public rooms on other homeservers", async ({ page, app, room3 }) => {
         const spotlight = await app.openSpotlight();
         await page.waitForTimeout(500); // wait for the dialog to settle
         await spotlight.filter(Filter.PublicRooms);
-        await spotlight.search(room3Name);
+        await spotlight.search(room3.name);
         await page.locator("[aria-haspopup=true][role=button]").click();
 
         await page
@@ -193,20 +209,20 @@ test.describe("Spotlight", () => {
 
         const resultLocator = spotlight.results;
         await expect(resultLocator).toHaveCount(1);
-        await expect(resultLocator.first()).toContainText(room3Name);
-        await expect(resultLocator.first()).toContainText(room3Id);
+        await expect(resultLocator.first()).toContainText(room3.name);
+        await expect(resultLocator.first()).toContainText(room3.roomId);
     });
 
-    test("should find known people", async ({ page, app }) => {
+    test("should find known people", async ({ page, app, bot1 }) => {
         const spotlight = await app.openSpotlight();
         await page.waitForTimeout(500); // wait for the dialog to settle
         await spotlight.filter(Filter.People);
-        await spotlight.search(bot1Name);
+        await spotlight.search(bot1.credentials.displayName);
         const resultLocator = spotlight.results;
         await expect(resultLocator).toHaveCount(1);
-        await expect(resultLocator.first()).toContainText(bot1Name);
+        await expect(resultLocator.first()).toContainText(bot1.credentials.displayName);
         await resultLocator.first().click();
-        await expect(roomHeaderName(page)).toHaveText(bot1Name);
+        await expect(roomHeaderName(page)).toHaveText(bot1.credentials.displayName);
     });
 
     /**
@@ -216,59 +232,59 @@ test.describe("Spotlight", () => {
      *
      * https://github.com/matrix-org/synapse/issues/16472
      */
-    test("should find unknown people", async ({ page, app }) => {
+    test("should find unknown people", async ({ page, app, bot2 }) => {
         const spotlight = await app.openSpotlight();
         await page.waitForTimeout(500); // wait for the dialog to settle
         await spotlight.filter(Filter.People);
-        await spotlight.search(bot2Name);
+        await spotlight.search(bot2.credentials.displayName);
         const resultLocator = spotlight.results;
         await expect(resultLocator).toHaveCount(1);
-        await expect(resultLocator.first()).toContainText(bot2Name);
+        await expect(resultLocator.first()).toContainText(bot2.credentials.displayName);
         await resultLocator.first().click();
-        await expect(roomHeaderName(page)).toHaveText(bot2Name);
+        await expect(roomHeaderName(page)).toHaveText(bot2.credentials.displayName);
     });
 
-    test("should find group DMs by usernames or user ids", async ({ page, app }) => {
+    test("should find group DMs by usernames or user ids", async ({ page, app, bot1, bot2, room1 }) => {
         // First we want to share a room with both bots to ensure we’ve got their usernames cached
-        const bot2UserId = await bot2.evaluate((client) => client.getUserId());
-        await app.client.inviteUser(room1Id, bot2UserId);
+        await app.client.inviteUser(room1.roomId, bot2.credentials.userId);
 
         // Starting a DM with ByteBot (will be turned into a group dm later)
         let spotlight = await app.openSpotlight();
         await page.waitForTimeout(500); // wait for the dialog to settle
         await spotlight.filter(Filter.People);
-        await spotlight.search(bot2Name);
+        await spotlight.search(bot2.credentials.displayName);
         let resultLocator = spotlight.results;
         await expect(resultLocator).toHaveCount(1);
-        await expect(resultLocator.first()).toContainText(bot2Name);
+        await expect(resultLocator.first()).toContainText(bot2.credentials.displayName);
         await resultLocator.first().click();
 
         // Send first message to actually start DM
-        await expect(roomHeaderName(page)).toHaveText(bot2Name);
+        await expect(roomHeaderName(page)).toHaveText(bot2.credentials.displayName);
         const locator = page.getByRole("textbox", { name: "Send a message…" });
         await locator.fill("Hey!");
         await locator.press("Enter");
 
         // Assert DM exists by checking for the first message and the room being in the room list
         await expect(page.locator(".mx_EventTile_body").filter({ hasText: "Hey!" })).toBeAttached({ timeout: 3000 });
-        await expect(page.getByRole("group", { name: "People" })).toContainText(bot2Name);
+        await expect(page.getByRole("group", { name: "People" })).toContainText(bot2.credentials.displayName);
 
         // Invite BotBob into existing DM with ByteBot
         const dmRooms = await app.client.evaluate((client, userId) => {
-            const map = client.getAccountData("m.direct")?.getContent<Record<string, string[]>>();
+            const map = client
+                .getAccountData("m.direct" as keyof AccountDataEvents)
+                ?.getContent<Record<string, string[]>>();
             return map[userId] ?? [];
-        }, bot2UserId);
+        }, bot2.credentials.userId);
         expect(dmRooms).toHaveLength(1);
         const groupDmName = await app.client.evaluate((client, id) => client.getRoom(id).name, dmRooms[0]);
-        const bot1UserId = await bot1.evaluate((client) => client.getUserId());
-        await app.client.inviteUser(dmRooms[0], bot1UserId);
+        await app.client.inviteUser(dmRooms[0], bot1.credentials.userId);
         await expect(roomHeaderName(page).first()).toContainText(groupDmName);
         await expect(page.getByRole("group", { name: "People" }).first()).toContainText(groupDmName);
 
         // Search for BotBob by id, should return group DM and user
         spotlight = await app.openSpotlight();
         await spotlight.filter(Filter.People);
-        await spotlight.search(bot1UserId);
+        await spotlight.search(bot1.credentials.userId);
         await page.waitForTimeout(1000); // wait for the dialog to settle
         resultLocator = spotlight.results;
         await expect(resultLocator).toHaveCount(2);
@@ -281,7 +297,7 @@ test.describe("Spotlight", () => {
         // Search for ByteBot by id, should return group DM and user
         spotlight = await app.openSpotlight();
         await spotlight.filter(Filter.People);
-        await spotlight.search(bot2UserId);
+        await spotlight.search(bot2.credentials.userId);
         await page.waitForTimeout(1000); // wait for the dialog to settle
         resultLocator = spotlight.results;
         await expect(resultLocator).toHaveCount(2);
@@ -294,11 +310,10 @@ test.describe("Spotlight", () => {
     });
 
     // Test against https://github.com/vector-im/element-web/issues/22851
-    test("should show each person result only once", async ({ page, app }) => {
+    test("should show each person result only once", async ({ page, app, bot1 }) => {
         const spotlight = await app.openSpotlight();
         await page.waitForTimeout(500); // wait for the dialog to settle
         await spotlight.filter(Filter.People);
-        const bot1UserId = await bot1.evaluate((client) => client.getUserId());
 
         // 2 rounds of search to simulate the bug conditions. Specifically, the first search
         // should have 1 result (not 2) and the second search should also have 1 result (instead
@@ -307,24 +322,24 @@ test.describe("Spotlight", () => {
         // We search for user ID to trigger the profile lookup within the dialog.
         for (let i = 0; i < 2; i++) {
             console.log("Iteration: " + i);
-            await spotlight.search(bot1UserId);
+            await spotlight.search(bot1.credentials.userId);
             await page.waitForTimeout(1000); // wait for the dialog to settle
             const resultLocator = spotlight.results;
             await expect(resultLocator).toHaveCount(1);
-            await expect(resultLocator.first()).toContainText(bot1UserId);
+            await expect(resultLocator.first()).toContainText(bot1.credentials.userId);
         }
     });
 
-    test("should allow opening group chat dialog", async ({ page, app }) => {
+    test("should allow opening group chat dialog", async ({ page, app, bot2 }) => {
         const spotlight = await app.openSpotlight();
         await page.waitForTimeout(500); // wait for the dialog to settle
         await spotlight.filter(Filter.People);
-        await spotlight.search(bot2Name);
+        await spotlight.search(bot2.credentials.displayName);
         await page.waitForTimeout(3000); // wait for the dialog to settle
 
         const resultLocator = spotlight.results;
         await expect(resultLocator).toHaveCount(1);
-        await expect(resultLocator.first()).toContainText(bot2Name);
+        await expect(resultLocator.first()).toContainText(bot2.credentials.displayName);
 
         await expect(spotlight.dialog.locator(".mx_SpotlightDialog_startGroupChat")).toContainText(
             "Start a group chat",
@@ -333,18 +348,18 @@ test.describe("Spotlight", () => {
         await expect(page.getByRole("dialog")).toContainText("Direct Messages");
     });
 
-    test("should close spotlight after starting a DM", async ({ page, app }) => {
-        await startDM(app, page, bot1Name);
+    test("should close spotlight after starting a DM", async ({ page, app, bot1 }) => {
+        await startDM(app, page, bot1.credentials.displayName);
         await expect(page.locator(".mx_SpotlightDialog")).toHaveCount(0);
     });
 
-    test("should show the same user only once", async ({ page, app }) => {
-        await startDM(app, page, bot1Name);
+    test("should show the same user only once", async ({ page, app, bot1 }) => {
+        await startDM(app, page, bot1.credentials.displayName);
         await page.goto("/#/home");
         const spotlight = await app.openSpotlight();
         await page.waitForTimeout(500); // wait for the dialog to settle
         await spotlight.filter(Filter.People);
-        await spotlight.search(bot1Name);
+        await spotlight.search(bot1.credentials.displayName);
         await page.waitForTimeout(3000); // wait for the dialog to settle
         await expect(spotlight.dialog.locator(".mx_Spinner")).not.toBeAttached();
         const resultLocator = spotlight.results;
diff --git a/playwright/e2e/threads/threads.spec.ts b/playwright/e2e/threads/threads.spec.ts
index 06ec57653c7..89cfe418ba9 100644
--- a/playwright/e2e/threads/threads.spec.ts
+++ b/playwright/e2e/threads/threads.spec.ts
@@ -2,14 +2,16 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 import { SettingLevel } from "../../../src/settings/SettingLevel";
 import { Layout } from "../../../src/settings/enums/Layout";
 import { test, expect } from "../../element-web-test";
+import { isDendrite } from "../../plugins/homeserver/dendrite";
 
 test.describe("Threads", () => {
+    test.skip(isDendrite, "due to a Dendrite bug https://github.com/element-hq/dendrite/issues/3489");
     test.use({
         displayName: "Tom",
         botCreateOpts: {
@@ -24,8 +26,7 @@ test.describe("Threads", () => {
         });
     });
 
-    // Flaky: https://github.com/vector-im/element-web/issues/26452
-    test.skip("should be usable for a conversation", { tag: "@screenshot" }, async ({ page, app, bot }) => {
+    test("should be usable for a conversation", { tag: "@screenshot" }, async ({ page, app, bot }) => {
         const roomId = await app.client.createRoom({});
         await app.client.inviteUser(roomId, bot.credentials.userId);
         await bot.joinRoom(roomId);
@@ -76,7 +77,7 @@ test.describe("Threads", () => {
             mask: mask,
         });
         await app.settings.setValue("layout", null, SettingLevel.DEVICE, Layout.Bubble);
-        await expect(page.locator(".mx_ThreadView .mx_EventTile[data-layout='bubble']")).toBeVisible();
+        await expect(page.locator(".mx_ThreadView .mx_EventTile[data-layout='bubble']")).toHaveCount(2);
 
         await expect(page.locator(".mx_ThreadView")).toMatchScreenshot("Initial_ThreadView_on_bubble_layout.png", {
             mask: mask,
@@ -136,8 +137,8 @@ test.describe("Threads", () => {
         await page.getByRole("gridcell", { name: "👋" }).click();
 
         locator = page.locator(".mx_ThreadView");
-        // Make sure the CSS style for spacing is applied to mx_ReactionsRow on group/modern layout
-        await expect(locator.locator(".mx_EventTile[data-layout=group] .mx_ReactionsRow")).toHaveCSS(
+        // Make sure the CSS style for spacing is applied to mx_EventTile_footer on group/modern layout
+        await expect(locator.locator(".mx_EventTile[data-layout=group] .mx_EventTile_footer")).toHaveCSS(
             "margin-inline-start",
             ThreadViewGroupSpacingStart,
         );
@@ -164,7 +165,7 @@ test.describe("Threads", () => {
         locator = page.locator(
             ".mx_ThreadView .mx_GenericEventListSummary[data-layout=bubble] .mx_EventTile_info.mx_EventTile_last",
         );
-        expect(locator.locator(".mx_EventTile_line .mx_EventTile_content"))
+        await expect(locator.locator(".mx_EventTile_line .mx_EventTile_content"))
             // 76px: ThreadViewGroupSpacingStart + 14px + 6px
             // 14px: avatar width
             // See: _EventTile.pcss
@@ -202,12 +203,14 @@ test.describe("Threads", () => {
         await locator.click();
 
         // Wait until the response is redacted
-        await expect(
-            page.locator(".mx_ThreadView").locator(".mx_EventTile_last .mx_EventTile_receiptSent"),
-        ).toBeVisible();
+        // XXX: one would expect this redaction to be shown in the thread the message was in, but due to redactions
+        // stripping the thread_id, it is instead shown in the main timeline
+        await expect(page.locator(".mx_MainSplit_timeline").locator(".mx_EventTile_last")).toContainText(
+            "Message deleted",
+        );
 
         // Take snapshots in group layout and bubble layout (IRC layout is not available on ThreadView)
-        await expect(page.locator(".mx_ThreadView .mx_EventTile[data-layout='group']")).toBeVisible();
+        await expect(page.locator(".mx_ThreadView .mx_EventTile[data-layout='group']")).toHaveCount(2);
         await expect(page.locator(".mx_ThreadView")).toMatchScreenshot(
             "ThreadView_with_redacted_messages_on_group_layout.png",
             {
@@ -215,7 +218,7 @@ test.describe("Threads", () => {
             },
         );
         await app.settings.setValue("layout", null, SettingLevel.DEVICE, Layout.Bubble);
-        await expect(page.locator(".mx_ThreadView .mx_EventTile[data-layout='bubble']")).toBeVisible();
+        await expect(page.locator(".mx_ThreadView .mx_EventTile[data-layout='bubble']")).toHaveCount(2);
         await expect(page.locator(".mx_ThreadView")).toMatchScreenshot(
             "ThreadView_with_redacted_messages_on_bubble_layout.png",
             {
@@ -233,8 +236,8 @@ test.describe("Threads", () => {
 
         // User closes right panel after clicking back to thread list
         locator = page.locator(".mx_ThreadPanel");
-        locator.getByRole("button", { name: "Threads" }).click();
-        locator.getByRole("button", { name: "Close" }).click();
+        await locator.getByRole("button", { name: "Threads" }).click();
+        await locator.getByRole("button", { name: "Close" }).click();
 
         // Bot responds to thread
         await bot.sendMessage(roomId, "How are things?", threadId);
@@ -243,9 +246,8 @@ test.describe("Threads", () => {
         await expect(locator.locator(".mx_ThreadSummary_sender").getByText("BotBob")).toBeAttached();
         await expect(locator.locator(".mx_ThreadSummary_content").getByText("How are things?")).toBeAttached();
 
-        locator = page.getByRole("button", { name: "Threads" });
-        await expect(locator).toHaveAttribute("data-indicator", "default"); // User asserts thread list unread indicator
-        // await expect(locator).toHaveClass(/mx_LegacyRoomHeader_button--unread/);
+        locator = page.getByRole("banner").getByRole("button", { name: "Threads" });
+        await expect(locator).toHaveAttribute("data-indicator", "success"); // User asserts thread list unread indicator
         await locator.click(); // User opens thread list
 
         // User asserts thread with correct root & latest events & unread dot
@@ -273,20 +275,18 @@ test.describe("Threads", () => {
         await expect(locator.getByText("Great!")).toBeAttached();
         await locator.locator(".mx_EventTile_line").hover();
         await locator.locator(".mx_EventTile_line").getByRole("button", { name: "Edit" }).click();
-        await locator.getByRole("textbox").fill(" How about yourself?{enter}");
+        await locator.getByRole("textbox").pressSequentially(" How about yourself?"); // fill would overwrite the original text
         await locator.getByRole("textbox").press("Enter");
 
         locator = page.locator(".mx_RoomView_body .mx_ThreadSummary");
         await expect(locator.locator(".mx_ThreadSummary_sender").getByText("Tom")).toBeAttached();
-        await expect(
-            locator.locator(".mx_ThreadSummary_content").getByText("Great! How about yourself?"),
-        ).toBeAttached();
+        await expect(locator.locator(".mx_ThreadSummary_content")).toHaveText("Great! How about yourself?");
 
         // User closes right panel
         await page.locator(".mx_ThreadPanel").getByRole("button", { name: "Close" }).click();
 
         // Bot responds to thread and saves the id of their message to @eventId
-        const { event_id: eventId } = await bot.sendMessage(roomId, threadId, "I'm very good thanks");
+        const { event_id: eventId } = await bot.sendMessage(roomId, "I'm very good thanks", threadId);
 
         // User asserts
         locator = page.locator(".mx_RoomView_body .mx_ThreadSummary");
@@ -324,7 +324,7 @@ test.describe("Threads", () => {
             });
         });
 
-        test("can send voice messages", async ({ page, app, user }) => {
+        test("can send voice messages", { tag: ["@no-firefox", "@no-webkit"] }, async ({ page, app, user }) => {
             // Increase right-panel size, so that voice messages fit
             await page.evaluate(() => {
                 window.localStorage.setItem("mx_rhs_size", "600");
@@ -344,7 +344,7 @@ test.describe("Threads", () => {
 
             await expect(page.locator(".mx_ThreadView_timelinePanelWrapper")).toHaveCount(1);
 
-            (await app.openMessageComposerOptions(true)).getByRole("menuitem", { name: "Voice Message" }).click();
+            await (await app.openMessageComposerOptions(true)).getByRole("menuitem", { name: "Voice Message" }).click();
             await page.waitForTimeout(3000);
             await app.getComposer(true).getByRole("button", { name: "Send voice message" }).click();
             await expect(page.locator(".mx_ThreadView .mx_MVoiceMessageBody")).toHaveCount(1);
@@ -353,7 +353,7 @@ test.describe("Threads", () => {
 
     test(
         "should send location and reply to the location on ThreadView",
-        { tag: "@screenshot" },
+        { tag: ["@screenshot", "@no-firefox"] },
         async ({ page, app, bot }) => {
             const roomId = await app.client.createRoom({});
             await app.client.inviteUser(roomId, bot.credentials.userId);
diff --git a/playwright/e2e/timeline/timeline.spec.ts b/playwright/e2e/timeline/timeline.spec.ts
index 7aaabb9759d..885c15d90f4 100644
--- a/playwright/e2e/timeline/timeline.spec.ts
+++ b/playwright/e2e/timeline/timeline.spec.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022, 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -90,7 +90,7 @@ test.describe("Timeline", () => {
     let oldAvatarUrl: string;
     let newAvatarUrl: string;
 
-    test.describe("useOnlyCurrentProfiles", () => {
+    test.describe("useOnlyCurrentProfiles", { tag: ["@no-firefox", "@no-webkit"] }, () => {
         test.beforeEach(async ({ app, user }) => {
             ({ content_uri: oldAvatarUrl } = await app.client.uploadContent(OLD_AVATAR, { type: "image/png" }));
             await app.client.setAvatarUrl(oldAvatarUrl);
@@ -590,10 +590,6 @@ test.describe("Timeline", () => {
             "should set inline start padding to a hidden event line",
             { tag: "@screenshot" },
             async ({ page, app, room }) => {
-                test.skip(
-                    true,
-                    "Disabled due to screenshot test being flaky - https://github.com/element-hq/element-web/issues/26890",
-                );
                 await sendEvent(app.client, room.roomId);
                 await page.goto(`/#/room/${room.roomId}`);
                 await app.settings.setValue("showHiddenEventsInTimeline", null, SettingLevel.DEVICE, true);
@@ -607,7 +603,12 @@ test.describe("Timeline", () => {
                 await messageEdit(page);
 
                 // Click timestamp to highlight hidden event line
-                await page.locator(".mx_RoomView_body .mx_EventTile_info .mx_MessageTimestamp").click();
+                const timestamp = page.locator(".mx_RoomView_body .mx_EventTile_info a", {
+                    has: page.locator(".mx_MessageTimestamp"),
+                });
+                // wait for the remote echo otherwise we get an error modal due to a 404 on the /event/ API
+                await expect(timestamp).not.toHaveAttribute("href", /~!/);
+                await timestamp.locator(".mx_MessageTimestamp").click();
 
                 // should not add inline start padding to a hidden event line on IRC layout
                 await app.settings.setValue("layout", null, SettingLevel.DEVICE, Layout.IRC);
@@ -876,7 +877,7 @@ test.describe("Timeline", () => {
         });
     });
 
-    test.describe("message sending", () => {
+    test.describe("message sending", { tag: ["@no-firefox", "@no-webkit"] }, () => {
         const MESSAGE = "Hello world";
         const reply = "Reply";
         const viewRoomSendMessageAndSetupReply = async (page: Page, app: ElementAppPage, roomId: string) => {
@@ -914,7 +915,6 @@ test.describe("Timeline", () => {
         });
 
         test("can reply with a voice message", async ({ page, app, room, context }) => {
-            await context.grantPermissions(["microphone"]);
             await viewRoomSendMessageAndSetupReply(page, app, room.roomId);
 
             const composerOptions = await app.openMessageComposerOptions();
diff --git a/playwright/e2e/toasts/analytics-toast.spec.ts b/playwright/e2e/toasts/analytics-toast.spec.ts
index b1faf7a7794..ff106298725 100644
--- a/playwright/e2e/toasts/analytics-toast.spec.ts
+++ b/playwright/e2e/toasts/analytics-toast.spec.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/playwright/e2e/update/update.spec.ts b/playwright/e2e/update/update.spec.ts
index d073a334333..a5febc55974 100644
--- a/playwright/e2e/update/update.spec.ts
+++ b/playwright/e2e/update/update.spec.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/playwright/e2e/user-menu/user-menu.spec.ts b/playwright/e2e/user-menu/user-menu.spec.ts
index 268da00f30f..1f67aa0be65 100644
--- a/playwright/e2e/user-menu/user-menu.spec.ts
+++ b/playwright/e2e/user-menu/user-menu.spec.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/playwright/e2e/user-onboarding/user-onboarding-new.spec.ts b/playwright/e2e/user-onboarding/user-onboarding-new.spec.ts
deleted file mode 100644
index b89fa3ac70a..00000000000
--- a/playwright/e2e/user-onboarding/user-onboarding-new.spec.ts
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2022 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
-Please see LICENSE files in the repository root for full details.
-*/
-
-import { test, expect } from "../../element-web-test";
-
-test.describe("User Onboarding (new user)", () => {
-    test.use({
-        displayName: "Jane Doe",
-    });
-
-    // This first beforeEach happens before the `user` fixture runs
-    test.beforeEach(async ({ page }) => {
-        await page.addInitScript(() => {
-            window.localStorage.setItem("mx_registration_time", "1656633601");
-        });
-    });
-
-    test.beforeEach(async ({ page, user }) => {
-        await expect(page.locator(".mx_UserOnboardingPage")).toBeVisible();
-        await expect(page.getByRole("button", { name: "Welcome" })).toBeVisible();
-        await expect(page.locator(".mx_UserOnboardingList")).toBeVisible();
-    });
-
-    test("page is shown and preference exists", { tag: "@screenshot" }, async ({ page, app }) => {
-        await expect(page.locator(".mx_UserOnboardingPage")).toMatchScreenshot(
-            "User-Onboarding-new-user-page-is-shown-and-preference-exists-1.png",
-        );
-        await app.settings.openUserSettings("Preferences");
-        await expect(page.getByText("Show shortcut to welcome checklist above the room list")).toBeVisible();
-    });
-
-    test("app download dialog", { tag: "@screenshot" }, async ({ page }) => {
-        await page.getByRole("button", { name: "Download apps" }).click();
-        await expect(
-            page.getByRole("dialog").getByRole("heading", { level: 1, name: "Download Element" }),
-        ).toBeVisible();
-        await expect(page.locator(".mx_Dialog")).toMatchScreenshot(
-            "User-Onboarding-new-user-app-download-dialog-1.png",
-            {
-                // Set a constant bg behind the modal to ensure screenshot stability
-                css: `
-                    .mx_AppDownloadDialog_wrapper {
-                        background: black;
-                    }
-                `,
-            },
-        );
-    });
-
-    test("using find friends action should increase progress", async ({ page, homeserver }) => {
-        const bot = await homeserver.registerUser("botbob", "password", "BotBob");
-
-        const oldProgress = parseFloat(await page.getByRole("progressbar").getAttribute("value"));
-        await page.getByRole("button", { name: "Find friends" }).click();
-        await page.locator(".mx_InviteDialog_editor").getByRole("textbox").fill(bot.userId);
-        await page.getByRole("button", { name: "Go" }).click();
-        await expect(page.locator(".mx_InviteDialog_buttonAndSpinner")).not.toBeVisible();
-
-        const message = "Hi!";
-        const composer = page.getByRole("textbox", { name: "Send a message…" });
-        await composer.fill(`${message}`);
-        await composer.press("Enter");
-        await expect(page.locator(".mx_MTextBody.mx_EventTile_content", { hasText: message })).toBeVisible();
-
-        await page.goto("/#/home");
-        await expect(page.locator(".mx_UserOnboardingPage")).toBeVisible();
-        await expect(page.getByRole("button", { name: "Welcome" })).toBeVisible();
-        await expect(page.locator(".mx_UserOnboardingList")).toBeVisible();
-
-        await page.waitForTimeout(500); // await progress bar animation
-        const progress = parseFloat(await page.getByRole("progressbar").getAttribute("value"));
-        expect(progress).toBeGreaterThan(oldProgress);
-    });
-});
diff --git a/playwright/e2e/user-onboarding/user-onboarding-old.spec.ts b/playwright/e2e/user-onboarding/user-onboarding-old.spec.ts
deleted file mode 100644
index e1454311c8e..00000000000
--- a/playwright/e2e/user-onboarding/user-onboarding-old.spec.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2022 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
-Please see LICENSE files in the repository root for full details.
-*/
-
-import { test, expect } from "../../element-web-test";
-
-test.describe("User Onboarding (old user)", () => {
-    test.use({
-        displayName: "Jane Doe",
-    });
-
-    test.beforeEach(async ({ page }) => {
-        await page.addInitScript(() => {
-            window.localStorage.setItem("mx_registration_time", "2");
-        });
-    });
-
-    test("page and preference are hidden", async ({ page, user, app }) => {
-        await expect(page.locator(".mx_UserOnboardingPage")).not.toBeVisible();
-        await expect(page.locator(".mx_UserOnboardingButton")).not.toBeVisible();
-        await app.settings.openUserSettings("Preferences");
-        await expect(page.getByText("Show shortcut to welcome checklist above the room list")).not.toBeVisible();
-    });
-});
diff --git a/playwright/e2e/user-view/user-view.spec.ts b/playwright/e2e/user-view/user-view.spec.ts
index ff8e9684e93..f3745e78595 100644
--- a/playwright/e2e/user-view/user-view.spec.ts
+++ b/playwright/e2e/user-view/user-view.spec.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/playwright/e2e/utils.ts b/playwright/e2e/utils.ts
index a2bcc0f29ae..49e7577bf6d 100644
--- a/playwright/e2e/utils.ts
+++ b/playwright/e2e/utils.ts
@@ -4,7 +4,7 @@ Copyright 2023 Mikhail Aheichyk
 Copyright 2023 Nordeck IT + Consulting GmbH.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/playwright/e2e/widgets/events.spec.ts b/playwright/e2e/widgets/events.spec.ts
index c2c8c8d3049..7553ec4b469 100644
--- a/playwright/e2e/widgets/events.spec.ts
+++ b/playwright/e2e/widgets/events.spec.ts
@@ -4,7 +4,7 @@ Copyright 2023 The Matrix.org Foundation C.I.C.
 Copyright 2022 Mikhail Aheichyk
 Copyright 2022 Nordeck IT + Consulting GmbH.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/playwright/e2e/widgets/layout.spec.ts b/playwright/e2e/widgets/layout.spec.ts
index c80ea44078e..61332aecb4f 100644
--- a/playwright/e2e/widgets/layout.spec.ts
+++ b/playwright/e2e/widgets/layout.spec.ts
@@ -4,7 +4,7 @@ Copyright 2023 The Matrix.org Foundation C.I.C.
 Copyright 2022 Oliver Sand
 Copyright 2022 Nordeck IT + Consulting GmbH.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/playwright/e2e/widgets/stickers.spec.ts b/playwright/e2e/widgets/stickers.spec.ts
index 318f7129616..601dcd8b796 100644
--- a/playwright/e2e/widgets/stickers.spec.ts
+++ b/playwright/e2e/widgets/stickers.spec.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022, 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -12,6 +12,7 @@ import type { Page } from "@playwright/test";
 import { test, expect } from "../../element-web-test";
 import { ElementAppPage } from "../../pages/ElementAppPage";
 import { Credentials } from "../../plugins/homeserver";
+import type { UserWidget } from "../../../src/utils/WidgetUtils-types.ts";
 
 const STICKER_PICKER_WIDGET_ID = "fake-sticker-picker";
 const STICKER_PICKER_WIDGET_NAME = "Fake Stickers";
@@ -87,7 +88,7 @@ async function sendStickerFromPicker(page: Page) {
     await expect(page.locator(".mx_AppTileFullWidth#stickers")).not.toBeVisible();
 }
 
-async function expectTimelineSticker(page: Page, roomId: string, contentUri: string) {
+async function expectTimelineSticker(page: Page, serverName: string, roomId: string, contentUri: string) {
     const contentId = contentUri.split("/").slice(-1)[0];
     // Make sure it's in the right room
     await expect(page.locator(".mx_EventTile_sticker > a")).toHaveAttribute("href", new RegExp(`/${roomId}/`));
@@ -97,7 +98,7 @@ async function expectTimelineSticker(page: Page, roomId: string, contentUri: str
     // download URL.
     await expect(page.locator(`img[alt="${STICKER_NAME}"]`)).toHaveAttribute(
         "src",
-        new RegExp(`/localhost/${contentId}`),
+        new RegExp(`/${serverName}/${contentId}`),
     );
 }
 
@@ -123,11 +124,11 @@ async function setWidgetAccountData(
             state_key: STICKER_PICKER_WIDGET_ID,
             type: "m.widget",
             id: STICKER_PICKER_WIDGET_ID,
-        },
+        } as unknown as UserWidget,
     });
 }
 
-test.describe("Stickers", () => {
+test.describe("Stickers", { tag: ["@no-firefox", "@no-webkit"] }, () => {
     test.use({
         displayName: "Sally",
         room: async ({ app }, use) => {
@@ -149,13 +150,13 @@ test.describe("Stickers", () => {
         const { content_uri: contentUri } = await app.client.uploadContent(STICKER_IMAGE, { type: "image/png" });
         const widgetHtml = getWidgetHtml(contentUri, "image/png");
         stickerPickerUrl = webserver.start(widgetHtml);
-        setWidgetAccountData(app, user, stickerPickerUrl);
+        await setWidgetAccountData(app, user, stickerPickerUrl);
 
         await app.viewRoomByName(ROOM_NAME_1);
         await expect(page).toHaveURL(`/#/room/${room.roomId}`);
         await openStickerPicker(app);
         await sendStickerFromPicker(page);
-        await expectTimelineSticker(page, room.roomId, contentUri);
+        await expectTimelineSticker(page, user.homeServer, room.roomId, contentUri);
 
         // Ensure that when we switch to a different room that the sticker
         // goes to the right place
@@ -163,7 +164,7 @@ test.describe("Stickers", () => {
         await expect(page).toHaveURL(`/#/room/${roomId2}`);
         await openStickerPicker(app);
         await sendStickerFromPicker(page);
-        await expectTimelineSticker(page, roomId2, contentUri);
+        await expectTimelineSticker(page, user.homeServer, roomId2, contentUri);
     });
 
     test("should handle a sticker picker widget missing creatorUserId", async ({
@@ -176,13 +177,13 @@ test.describe("Stickers", () => {
         const { content_uri: contentUri } = await app.client.uploadContent(STICKER_IMAGE, { type: "image/png" });
         const widgetHtml = getWidgetHtml(contentUri, "image/png");
         stickerPickerUrl = webserver.start(widgetHtml);
-        setWidgetAccountData(app, user, stickerPickerUrl, false);
+        await setWidgetAccountData(app, user, stickerPickerUrl, false);
 
         await app.viewRoomByName(ROOM_NAME_1);
         await expect(page).toHaveURL(`/#/room/${room.roomId}`);
         await openStickerPicker(app);
         await sendStickerFromPicker(page);
-        await expectTimelineSticker(page, room.roomId, contentUri);
+        await expectTimelineSticker(page, user.homeServer, room.roomId, contentUri);
     });
 
     test("should render invalid mimetype as a file", async ({ webserver, page, app, user, room }) => {
@@ -191,7 +192,7 @@ test.describe("Stickers", () => {
         });
         const widgetHtml = getWidgetHtml(contentUri, "application/octet-stream");
         stickerPickerUrl = webserver.start(widgetHtml);
-        setWidgetAccountData(app, user, stickerPickerUrl);
+        await setWidgetAccountData(app, user, stickerPickerUrl);
 
         await app.viewRoomByName(ROOM_NAME_1);
         await expect(page).toHaveURL(`/#/room/${room.roomId}`);
diff --git a/playwright/e2e/widgets/widget-pip-close.spec.ts b/playwright/e2e/widgets/widget-pip-close.spec.ts
index 1ee2246a2a5..ec3184ed6c2 100644
--- a/playwright/e2e/widgets/widget-pip-close.spec.ts
+++ b/playwright/e2e/widgets/widget-pip-close.spec.ts
@@ -4,7 +4,7 @@ Copyright 2023 The Matrix.org Foundation C.I.C.
 Copyright 2022 Mikhail Aheichyk
 Copyright 2022 Nordeck IT + Consulting GmbH.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/playwright/element-web-test.ts b/playwright/element-web-test.ts
index 76e57e33f70..9468ddeec37 100644
--- a/playwright/element-web-test.ts
+++ b/playwright/element-web-test.ts
@@ -2,46 +2,39 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
-import { test as base, expect as baseExpect, Locator, Page, ExpectMatcherState, ElementHandle } from "@playwright/test";
+import {
+    expect as baseExpect,
+    Locator,
+    Page,
+    ExpectMatcherState,
+    ElementHandle,
+    PlaywrightTestArgs,
+    Fixtures as _Fixtures,
+} from "@playwright/test";
 import { sanitizeForFilePath } from "playwright-core/lib/utils";
 import AxeBuilder from "@axe-core/playwright";
 import _ from "lodash";
-import { basename, extname } from "node:path";
+import { extname } from "node:path";
 
-import type mailhog from "mailhog";
 import type { IConfigOptions } from "../src/IConfigOptions";
-import { Credentials, Homeserver, HomeserverInstance, StartHomeserverOpts } from "./plugins/homeserver";
-import { Synapse } from "./plugins/homeserver/synapse";
-import { Dendrite, Pinecone } from "./plugins/homeserver/dendrite";
-import { Instance, MailHogServer } from "./plugins/mailhog";
+import { Credentials } from "./plugins/homeserver";
 import { ElementAppPage } from "./pages/ElementAppPage";
-import { OAuthServer } from "./plugins/oauth_server";
 import { Crypto } from "./pages/crypto";
 import { Toasts } from "./pages/toasts";
 import { Bot, CreateBotOpts } from "./pages/bot";
-import { ProxyInstance, SlidingSyncProxy } from "./plugins/sliding-sync-proxy";
 import { Webserver } from "./plugins/webserver";
+import { Options, Services, test as base } from "./services.ts";
 
 // Enable experimental service worker support
 // See https://playwright.dev/docs/service-workers-experimental#how-to-enable
 process.env["PW_EXPERIMENTAL_SERVICE_WORKER_NETWORK_EVENTS"] = "1";
 
+// This is deliberately quite a minimal config.json, so that we can test that the default settings actually work.
 const CONFIG_JSON: Partial<IConfigOptions> = {
-    // This is deliberately quite a minimal config.json, so that we can test that the default settings
-    // actually work.
-    //
-    // The only thing that we really *need* (otherwise Element refuses to load) is a default homeserver.
-    // We point that to a guaranteed-invalid domain.
-    default_server_config: {
-        "m.homeserver": {
-            base_url: "https://server.invalid",
-        },
-    },
-
     // The default language is set here for test consistency
     setting_defaults: {
         language: "en-GB",
@@ -56,11 +49,11 @@ const CONFIG_JSON: Partial<IConfigOptions> = {
     },
 };
 
-interface CredentialsWithDisplayName extends Credentials {
+export interface CredentialsWithDisplayName extends Credentials {
     displayName: string;
 }
 
-export const test = base.extend<{
+export interface TestFixtures {
     axe: AxeBuilder;
     checkA11y: () => Promise<void>;
 
@@ -69,14 +62,6 @@ export const test = base.extend<{
      */
     config: typeof CONFIG_JSON;
 
-    /**
-     * The options with which to run the {@link #homeserver} fixture.
-     */
-    startHomeserverOpts: StartHomeserverOpts | string;
-
-    homeserver: HomeserverInstance;
-    oAuthServer: { port: number };
-
     /**
      * The displayname to use for the user registered in {@link #credentials}.
      *
@@ -114,21 +99,42 @@ export const test = base.extend<{
      */
     app: ElementAppPage;
 
-    mailhog: { api: mailhog.API; instance: Instance };
     crypto: Crypto;
     room?: { roomId: string };
     toasts: Toasts;
     uut?: Locator; // Unit Under Test, useful place to refer a prepared locator
     botCreateOpts: CreateBotOpts;
     bot: Bot;
-    slidingSyncProxy: ProxyInstance;
     labsFlags: string[];
     webserver: Webserver;
-}>({
-    config: CONFIG_JSON,
-    page: async ({ context, page, config, labsFlags }, use) => {
+    disablePresence: boolean;
+}
+
+type CombinedTestFixtures = PlaywrightTestArgs & TestFixtures;
+export type Fixtures = _Fixtures<CombinedTestFixtures, Services & Options, CombinedTestFixtures>;
+export const test = base.extend<TestFixtures>({
+    context: async ({ context }, use, testInfo) => {
+        // We skip tests instead of using grep-invert to still surface the counts in the html report
+        test.skip(
+            testInfo.tags.includes(`@no-${testInfo.project.name.toLowerCase()}`),
+            `Test does not work on ${testInfo.project.name}`,
+        );
+        await use(context);
+    },
+    disablePresence: false,
+    config: {}, // We merge this atop the default CONFIG_JSON in the page fixture to make extending it easier
+    page: async ({ homeserver, context, page, config, labsFlags, disablePresence }, use) => {
         await context.route(`http://localhost:8080/config.json*`, async (route) => {
-            const json = { ...CONFIG_JSON, ...config };
+            const json = {
+                ...CONFIG_JSON,
+                ...config,
+                default_server_config: {
+                    "m.homeserver": {
+                        base_url: homeserver.baseUrl,
+                    },
+                    ...config.default_server_config,
+                },
+            };
             json["features"] = {
                 ...json["features"],
                 // Enable the lab features
@@ -137,58 +143,24 @@ export const test = base.extend<{
                     return obj;
                 }, {}),
             };
+            if (disablePresence) {
+                json["enable_presence_by_hs_url"] = {
+                    [homeserver.baseUrl]: false,
+                };
+            }
             await route.fulfill({ json });
         });
         await use(page);
     },
 
-    startHomeserverOpts: "default",
-    homeserver: async ({ request, startHomeserverOpts: opts }, use, testInfo) => {
-        if (typeof opts === "string") {
-            opts = { template: opts };
-        }
-
-        let server: Homeserver;
-        const homeserverName = process.env["PLAYWRIGHT_HOMESERVER"];
-        switch (homeserverName) {
-            case "dendrite":
-                server = new Dendrite(request);
-                break;
-            case "pinecone":
-                server = new Pinecone(request);
-                break;
-            default:
-                server = new Synapse(request);
-        }
-
-        await use(await server.start(opts));
-        const logs = await server.stop();
-
-        if (testInfo.status !== "passed") {
-            for (const path of logs) {
-                await testInfo.attach(`homeserver-${basename(path)}`, {
-                    path,
-                    contentType: "text/plain",
-                });
-            }
-        }
-    },
-    // eslint-disable-next-line no-empty-pattern
-    oAuthServer: async ({}, use) => {
-        const server = new OAuthServer();
-        const port = server.start();
-        await use({ port });
-        server.stop();
-    },
-
     displayName: undefined,
-    credentials: async ({ homeserver, displayName: testDisplayName }, use) => {
+    credentials: async ({ context, homeserver, displayName: testDisplayName }, use, testInfo) => {
         const names = ["Alice", "Bob", "Charlie", "Daniel", "Eve", "Frank", "Grace", "Hannah", "Isaac", "Judy"];
         const password = _.uniqueId("password_");
         const displayName = testDisplayName ?? _.sample(names)!;
 
-        const credentials = await homeserver.registerUser("user", password, displayName);
-        console.log(`Registered test user @user:localhost with displayname ${displayName}`);
+        const credentials = await homeserver.registerUser(`user_${testInfo.testId}`, password, displayName);
+        console.log(`Registered test user ${credentials.userId} with displayname ${displayName}`);
 
         await use({
             ...credentials,
@@ -209,10 +181,17 @@ export const test = base.extend<{
                 window.localStorage.setItem("mx_has_pickle_key", "false");
                 window.localStorage.setItem("mx_has_access_token", "true");
 
-                // Ensure the language is set to a consistent value
-                window.localStorage.setItem("mx_local_settings", '{"language":"en"}');
+                window.localStorage.setItem(
+                    "mx_local_settings",
+                    JSON.stringify({
+                        // Retain any other settings which may have already been set
+                        ...JSON.parse(window.localStorage.getItem("mx_local_settings") || "{}"),
+                        // Ensure the language is set to a consistent value
+                        language: "en",
+                    }),
+                );
             },
-            { baseUrl: homeserver.config.baseUrl, credentials },
+            { baseUrl: homeserver.baseUrl, credentials },
         );
         await use(page);
     },
@@ -241,6 +220,7 @@ export const test = base.extend<{
     app: async ({ page }, use) => {
         const app = new ElementAppPage(page);
         await use(app);
+        await app.cleanup();
     },
     crypto: async ({ page, homeserver, request }, use) => {
         await use(new Crypto(page, homeserver, request));
@@ -256,33 +236,6 @@ export const test = base.extend<{
         await use(bot);
     },
 
-    // eslint-disable-next-line no-empty-pattern
-    mailhog: async ({}, use) => {
-        const mailhog = new MailHogServer();
-        const instance = await mailhog.start();
-        await use(instance);
-        await mailhog.stop();
-    },
-
-    slidingSyncProxy: async ({ page, user, homeserver }, use) => {
-        const proxy = new SlidingSyncProxy(homeserver.config.dockerUrl);
-        const proxyInstance = await proxy.start();
-        const proxyAddress = `http://localhost:${proxyInstance.port}`;
-        await page.addInitScript((proxyAddress) => {
-            window.localStorage.setItem(
-                "mx_local_settings",
-                JSON.stringify({
-                    feature_sliding_sync_proxy_url: proxyAddress,
-                }),
-            );
-            window.localStorage.setItem("mx_labs_feature_feature_sliding_sync", "true");
-        }, proxyAddress);
-        await page.goto("/");
-        await page.waitForSelector(".mx_MatrixChat", { timeout: 30000 });
-        await use(proxyInstance);
-        await proxy.stop();
-    },
-
     // eslint-disable-next-line no-empty-pattern
     webserver: async ({}, use) => {
         const webserver = new Webserver();
diff --git a/playwright/flaky-reporter.ts b/playwright/flaky-reporter.ts
index 243699ebab3..770633decb7 100644
--- a/playwright/flaky-reporter.ts
+++ b/playwright/flaky-reporter.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -25,12 +25,17 @@ type PaginationLinks = {
 };
 
 class FlakyReporter implements Reporter {
-    private flakes = new Set<string>();
+    private flakes = new Map<string, TestCase[]>();
 
     public onTestEnd(test: TestCase): void {
+        // Ignores flakes on Dendrite and Pinecone as they have their own flakes we do not track
+        if (["Dendrite", "Pinecone"].includes(test.parent.project()?.name)) return;
         const title = `${test.location.file.split("playwright/e2e/")[1]}: ${test.title}`;
         if (test.outcome() === "flaky") {
-            this.flakes.add(title);
+            if (!this.flakes.has(title)) {
+                this.flakes.set(title, []);
+            }
+            this.flakes.get(title).push(test);
         }
     }
 
@@ -97,12 +102,14 @@ class FlakyReporter implements Reporter {
         if (!GITHUB_TOKEN) return;
 
         const issues = await this.getAllIssues();
-        for (const flake of this.flakes) {
+        for (const [flake, results] of this.flakes) {
             const title = ISSUE_TITLE_PREFIX + "`" + flake + "`";
             const existingIssue = issues.find((issue) => issue.title === title);
             const headers = { Authorization: `Bearer ${GITHUB_TOKEN}` };
             const body = `${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}`;
 
+            const labels = [LABEL, ...results.map((test) => `${LABEL}-${test.parent.project()?.name}`)];
+
             if (existingIssue) {
                 console.log(`Found issue ${existingIssue.number} for ${flake}, adding comment...`);
                 // Ensure that the test is open
@@ -111,6 +118,11 @@ class FlakyReporter implements Reporter {
                     headers,
                     body: JSON.stringify({ state: "open" }),
                 });
+                await fetch(`${existingIssue.url}/labels`, {
+                    method: "POST",
+                    headers,
+                    body: JSON.stringify({ labels }),
+                });
                 await fetch(`${existingIssue.url}/comments`, {
                     method: "POST",
                     headers,
@@ -124,7 +136,7 @@ class FlakyReporter implements Reporter {
                     body: JSON.stringify({
                         title,
                         body,
-                        labels: [LABEL],
+                        labels: [...labels],
                     }),
                 });
             }
diff --git a/playwright/global.d.ts b/playwright/global.d.ts
index 0ff5bc84dc6..30875bd5778 100644
--- a/playwright/global.d.ts
+++ b/playwright/global.d.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/playwright/logger.ts b/playwright/logger.ts
new file mode 100644
index 00000000000..857faaca69f
--- /dev/null
+++ b/playwright/logger.ts
@@ -0,0 +1,63 @@
+/*
+Copyright 2024 New Vector Ltd.
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+Please see LICENSE files in the repository root for full details.
+*/
+
+import { BrowserContext, Page, TestInfo } from "@playwright/test";
+import { Readable } from "stream";
+import stripAnsi from "strip-ansi";
+
+export class Logger {
+    private pages: Page[] = [];
+    private logs: Record<string, string> = {};
+
+    public getConsumer(container: string) {
+        this.logs[container] = "";
+        return (stream: Readable) => {
+            stream.on("data", (chunk) => {
+                this.logs[container] += chunk.toString();
+            });
+            stream.on("err", (chunk) => {
+                this.logs[container] += "ERR " + chunk.toString();
+            });
+        };
+    }
+
+    public async onTestStarted(context: BrowserContext) {
+        this.pages = [];
+        for (const id in this.logs) {
+            if (id.startsWith("page-")) {
+                delete this.logs[id];
+            } else {
+                this.logs[id] = "";
+            }
+        }
+
+        context.on("console", (msg) => {
+            const page = msg.page();
+            let pageIdx = this.pages.indexOf(page);
+            if (pageIdx === -1) {
+                this.pages.push(page);
+                pageIdx = this.pages.length - 1;
+                this.logs[`page-${pageIdx}`] = `Console logs for page with URL: ${page.url()}\n\n`;
+            }
+            const type = msg.type();
+            const text = msg.text();
+            this.logs[`page-${pageIdx}`] += `${type}: ${text}\n`;
+        });
+    }
+
+    public async onTestFinished(testInfo: TestInfo) {
+        if (testInfo.status !== "passed") {
+            for (const id in this.logs) {
+                if (!this.logs[id]) continue;
+                await testInfo.attach(id, {
+                    body: stripAnsi(this.logs[id]),
+                    contentType: "text/plain",
+                });
+            }
+        }
+    }
+}
diff --git a/playwright/pages/ElementAppPage.ts b/playwright/pages/ElementAppPage.ts
index 4cff3c72eac..98d0bf30fba 100644
--- a/playwright/pages/ElementAppPage.ts
+++ b/playwright/pages/ElementAppPage.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -37,6 +37,10 @@ export class ElementAppPage {
         return this._timeline;
     }
 
+    public async cleanup() {
+        await this._client?.cleanup();
+    }
+
     /**
      * Open the top left user menu, returning a Locator to the resulting context menu.
      */
@@ -173,6 +177,18 @@ export class ElementAppPage {
         return this.page.locator(".mx_RightPanel");
     }
 
+    /**
+     * Opens/closes the memberlist panel
+     * @returns locator to the memberlist panel
+     */
+    public async toggleMemberlistPanel(): Promise<Locator> {
+        const locator = this.page.locator(".mx_FacePile");
+        await locator.click();
+        const memberlist = this.page.locator(".mx_MemberListView");
+        await memberlist.waitFor();
+        return memberlist;
+    }
+
     /**
      * Get a locator for the tooltip associated with an element
      * @param e The element with the tooltip
diff --git a/playwright/pages/Spotlight.ts b/playwright/pages/Spotlight.ts
index a5f1318de27..5f3c8ef6b9b 100644
--- a/playwright/pages/Spotlight.ts
+++ b/playwright/pages/Spotlight.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/playwright/pages/bot.ts b/playwright/pages/bot.ts
index d50a0e84ee1..435e4a1cbbb 100644
--- a/playwright/pages/bot.ts
+++ b/playwright/pages/bot.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -97,7 +97,7 @@ export class Bot extends Client {
     private async buildClient(): Promise<JSHandle<ExtendedMatrixClient>> {
         const credentials = await this.getCredentials();
         const clientHandle = await this.page.evaluateHandle(
-            async ({ homeserver, credentials, opts }) => {
+            async ({ baseUrl, credentials, opts }) => {
                 function getLogger(loggerName: string): Logger {
                     const logger = {
                         getChild: (namespace: string) => getLogger(`${loggerName}:${namespace}`),
@@ -121,7 +121,7 @@ export class Bot extends Client {
                     return logger as unknown as Logger;
                 }
 
-                const logger = getLogger(`cypress bot ${credentials.userId}`);
+                const logger = getLogger(`bot ${credentials.userId}`);
 
                 const keys = {};
 
@@ -157,7 +157,7 @@ export class Bot extends Client {
                 };
 
                 const cli = new window.matrixcs.MatrixClient({
-                    baseUrl: homeserver.baseUrl,
+                    baseUrl,
                     userId: credentials.userId,
                     deviceId: credentials.deviceId,
                     accessToken: credentials.accessToken,
@@ -171,7 +171,7 @@ export class Bot extends Client {
                 if (opts.autoAcceptInvites) {
                     cli.on(window.matrixcs.RoomMemberEvent.Membership, (event, member) => {
                         if (member.membership === "invite" && member.userId === cli.getUserId()) {
-                            cli.joinRoom(member.roomId);
+                            void cli.joinRoom(member.roomId);
                         }
                     });
                 }
@@ -179,7 +179,7 @@ export class Bot extends Client {
                 return cli;
             },
             {
-                homeserver: this.homeserver.config,
+                baseUrl: this.homeserver.baseUrl,
                 credentials,
                 opts: this.opts,
             },
diff --git a/playwright/pages/client.ts b/playwright/pages/client.ts
index 2dfe7484f5d..362915ce71f 100644
--- a/playwright/pages/client.ts
+++ b/playwright/pages/client.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -25,6 +25,7 @@ import type {
     Upload,
     StateEvents,
     TimelineEvents,
+    AccountDataEvents,
 } from "matrix-js-sdk/src/matrix";
 import type { RoomMessageEventContent } from "matrix-js-sdk/src/types";
 import { Credentials } from "../plugins/homeserver";
@@ -51,6 +52,10 @@ export class Client {
         this.network = new Network(page, this);
     }
 
+    public async cleanup() {
+        await this.network.destroyRoute();
+    }
+
     public evaluate<R, Arg, O extends MatrixClient = MatrixClient>(
         pageFunction: PageFunctionOn<O, Arg, R>,
         arg: Arg,
@@ -174,8 +179,7 @@ export class Client {
     public async createRoom(options: ICreateRoomOpts): Promise<string> {
         const client = await this.prepareClient();
         return await client.evaluate(async (cli, options) => {
-            const resp = await cli.createRoom(options);
-            const roomId = resp.room_id;
+            const { room_id: roomId } = await cli.createRoom(options);
             if (!cli.getRoom(roomId)) {
                 await new Promise<void>((resolve) => {
                     const onRoom = (room: Room) => {
@@ -439,11 +443,14 @@ export class Client {
      * @param type The type of account data to set
      * @param content The content to set
      */
-    public async setAccountData(type: string, content: IContent): Promise<void> {
+    public async setAccountData<T extends keyof AccountDataEvents>(
+        type: T,
+        content: AccountDataEvents[T],
+    ): Promise<void> {
         const client = await this.prepareClient();
         return client.evaluate(
             async (client, { type, content }) => {
-                await client.setAccountData(type, content);
+                await client.setAccountData(type as T, content as AccountDataEvents[T]);
             },
             { type, content },
         );
diff --git a/playwright/pages/crypto.ts b/playwright/pages/crypto.ts
index f221412a7ce..c31e7fbedb3 100644
--- a/playwright/pages/crypto.ts
+++ b/playwright/pages/crypto.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -27,7 +27,7 @@ export class Crypto {
             accessToken: window.mxMatrixClientPeg.get().getAccessToken(),
         }));
 
-        const res = await this.request.post(`${this.homeserver.config.baseUrl}/_matrix/client/v3/keys/query`, {
+        const res = await this.request.post(`${this.homeserver.baseUrl}/_matrix/client/v3/keys/query`, {
             headers: { Authorization: `Bearer ${accessToken}` },
             data: { device_keys: { [userId]: [] } },
         });
diff --git a/playwright/pages/network.ts b/playwright/pages/network.ts
index 8a2692543a0..3296fc8779b 100644
--- a/playwright/pages/network.ts
+++ b/playwright/pages/network.ts
@@ -2,23 +2,26 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
-import type { Page, Request } from "@playwright/test";
+import type { Page, Request, Route } from "@playwright/test";
 import type { Client } from "./client";
 
+/**
+ * Utility class to simulate offline mode by blocking all requests to the homeserver.
+ * Will not affect any requests before `setupRoute` is called,
+ * which happens implicitly using the goOffline/goOnline methods.
+ */
 export class Network {
     private isOffline = false;
-    private readonly setupPromise: Promise<void>;
+    private setupPromise?: Promise<void>;
 
     constructor(
         private page: Page,
         private client: Client,
-    ) {
-        this.setupPromise = this.setupRoute();
-    }
+    ) {}
 
     /**
      * Checks if the request is from the client associated with this network object.
@@ -30,25 +33,47 @@ export class Network {
         return authHeader === `Bearer ${accessToken}`;
     }
 
-    private async setupRoute() {
-        await this.page.route("**/_matrix/**", async (route) => {
-            if (this.isOffline && (await this.isRequestFromOurClient(route.request()))) {
-                route.abort();
-            } else {
-                route.continue();
-            }
-        });
+    private handler = async (route: Route) => {
+        if (this.isOffline && (await this.isRequestFromOurClient(route.request()))) {
+            await route.abort();
+        } else {
+            await route.continue();
+        }
+    };
+
+    /**
+     * Intercept all /_matrix/ networking requests for client ready to continue/abort them based on offline status
+     * which is set by the goOffline/goOnline methods
+     */
+    public async setupRoute() {
+        if (!this.setupPromise) {
+            this.setupPromise = this.page.route("**/_matrix/**", this.handler);
+        }
+        await this.setupPromise;
     }
 
-    // Intercept all /_matrix/ networking requests for client and fail them
+    /**
+     * Cease intercepting all /_matrix/ networking requests for client
+     */
+    public async destroyRoute() {
+        if (!this.setupPromise) return;
+        await this.page.unroute("**/_matrix/**", this.handler);
+        this.setupPromise = undefined;
+    }
+
+    /**
+     * Reject all /_matrix/ networking requests for client
+     */
     async goOffline(): Promise<void> {
-        await this.setupPromise;
+        await this.setupRoute();
         this.isOffline = true;
     }
 
-    // Remove intercept on all /_matrix/ networking requests for this client
+    /**
+     * Continue all /_matrix/ networking requests for this client
+     */
     async goOnline(): Promise<void> {
-        await this.setupPromise;
+        await this.setupRoute();
         this.isOffline = false;
     }
 }
diff --git a/playwright/pages/settings.ts b/playwright/pages/settings.ts
index 6a1caf1559f..7dbd183233c 100644
--- a/playwright/pages/settings.ts
+++ b/playwright/pages/settings.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/playwright/pages/timeline.ts b/playwright/pages/timeline.ts
index baf8306a7cf..ca9965a63ec 100644
--- a/playwright/pages/timeline.ts
+++ b/playwright/pages/timeline.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/playwright/pages/toasts.ts b/playwright/pages/toasts.ts
index a90e18251db..4fadfb9a9b3 100644
--- a/playwright/pages/toasts.ts
+++ b/playwright/pages/toasts.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/playwright/plugins/docker/index.ts b/playwright/plugins/docker/index.ts
deleted file mode 100644
index 895a7d0f123..00000000000
--- a/playwright/plugins/docker/index.ts
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2023 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
-Please see LICENSE files in the repository root for full details.
-*/
-
-import * as os from "os";
-import * as crypto from "crypto";
-import * as childProcess from "child_process";
-import * as fse from "fs-extra";
-
-/**
- * @param cmd - command to execute
- * @param args - arguments to pass to executed command
- * @param suppressOutput - whether to suppress the stdout and stderr resulting from this command.
- * @return Promise which resolves to an object containing the string value of what was
- *         written to stdout and stderr by the executed command.
- */
-const exec = (cmd: string, args: string[], suppressOutput = false): Promise<{ stdout: string; stderr: string }> => {
-    return new Promise((resolve, reject) => {
-        if (!suppressOutput) {
-            const log = ["Running command:", cmd, ...args, "\n"].join(" ");
-            // When in CI mode we combine reports from multiple runners into a single HTML report
-            // which has separate files for stdout and stderr, so we print the executed command to both
-            process.stdout.write(log);
-            if (process.env.CI) process.stderr.write(log);
-        }
-        const { stdout, stderr } = childProcess.execFile(cmd, args, { encoding: "utf8" }, (err, stdout, stderr) => {
-            if (err) reject(err);
-            resolve({ stdout, stderr });
-            if (!suppressOutput) {
-                process.stdout.write("\n");
-                if (process.env.CI) process.stderr.write("\n");
-            }
-        });
-        if (!suppressOutput) {
-            stdout.pipe(process.stdout);
-            stderr.pipe(process.stderr);
-        }
-    });
-};
-
-export class Docker {
-    public id: string;
-
-    async run(opts: { image: string; containerName: string; params?: string[]; cmd?: string[] }): Promise<string> {
-        const userInfo = os.userInfo();
-        const params = opts.params ?? [];
-
-        const isPodman = await Docker.isPodman();
-        if (params.includes("-v") && userInfo.uid >= 0) {
-            // Run the docker container as our uid:gid to prevent problems with permissions.
-            if (isPodman) {
-                // Note: this setup is for podman rootless containers.
-
-                // In podman, run as root in the container, which maps to the current
-                // user on the host. This is probably the default since Synapse's
-                // Dockerfile doesn't specify, but we're being explicit here
-                // because it's important for the permissions to work.
-                params.push("-u", "0:0");
-
-                // Tell Synapse not to switch UID
-                params.push("-e", "UID=0");
-                params.push("-e", "GID=0");
-            } else {
-                params.push("-u", `${userInfo.uid}:${userInfo.gid}`);
-            }
-        }
-
-        // Make host.containers.internal work to allow the container to talk to other services via host ports.
-        if (isPodman) {
-            params.push("--network");
-            params.push("slirp4netns:allow_host_loopback=true");
-        } else {
-            // Docker for Desktop includes a host-gateway mapping on host.docker.internal but to simplify the config
-            // we use the Podman variant host.containers.internal in all environments.
-            params.push("--add-host");
-            params.push("host.containers.internal:host-gateway");
-        }
-
-        // Provided we are not running in CI, add a `--rm` parameter.
-        // There is no need to remove containers in CI (since they are automatically removed anyway), and
-        // `--rm` means that if a container crashes this means its logs are wiped out.
-        if (!process.env.CI) params.unshift("--rm");
-
-        const args = [
-            "run",
-            "--name",
-            `${opts.containerName}-${crypto.randomBytes(4).toString("hex")}`,
-            "-d",
-            ...params,
-            opts.image,
-        ];
-
-        if (opts.cmd) args.push(...opts.cmd);
-
-        const { stdout } = await exec("docker", args);
-        this.id = stdout.trim();
-        return this.id;
-    }
-
-    async stop(): Promise<void> {
-        try {
-            await exec("docker", ["stop", this.id]);
-        } catch (err) {
-            console.error(`Failed to stop docker container`, this.id, err);
-        }
-    }
-
-    /**
-     * @param params - list of parameters to pass to `docker exec`
-     * @param suppressOutput - whether to suppress the stdout and stderr resulting from this command.
-     */
-    async exec(params: string[], suppressOutput = true): Promise<void> {
-        await exec("docker", ["exec", this.id, ...params], suppressOutput);
-    }
-
-    async getContainerIp(): Promise<string> {
-        const { stdout } = await exec("docker", ["inspect", "-f", "{{ .NetworkSettings.IPAddress }}", this.id]);
-        return stdout.trim();
-    }
-
-    async persistLogsToFile(args: { stdoutFile?: string; stderrFile?: string }): Promise<void> {
-        const stdoutFile = args.stdoutFile ? await fse.open(args.stdoutFile, "w") : "ignore";
-        const stderrFile = args.stderrFile ? await fse.open(args.stderrFile, "w") : "ignore";
-        await new Promise<void>((resolve) => {
-            childProcess
-                .spawn("docker", ["logs", this.id], {
-                    stdio: ["ignore", stdoutFile, stderrFile],
-                })
-                .once("close", resolve);
-        });
-        if (args.stdoutFile) await fse.close(<number>stdoutFile);
-        if (args.stderrFile) await fse.close(<number>stderrFile);
-    }
-
-    /**
-     * Detects whether the docker command is actually podman.
-     * To do this, it looks for "podman" in the output of "docker --help".
-     */
-    static async isPodman(): Promise<boolean> {
-        const { stdout } = await exec("docker", ["--help"], true);
-        return stdout.toLowerCase().includes("podman");
-    }
-}
diff --git a/playwright/plugins/homeserver/dendrite/index.ts b/playwright/plugins/homeserver/dendrite/index.ts
index 0886dc1586d..fb3537f4170 100644
--- a/playwright/plugins/homeserver/dendrite/index.ts
+++ b/playwright/plugins/homeserver/dendrite/index.ts
@@ -2,147 +2,12 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
-import * as path from "node:path";
-import * as os from "node:os";
-import * as fse from "fs-extra";
+import { Options } from "../../../services.ts";
 
-import { getFreePort } from "../../utils/port";
-import { Homeserver, HomeserverConfig, HomeserverInstance, StartHomeserverOpts } from "../";
-import { randB64Bytes } from "../../utils/rand";
-import { Synapse } from "../synapse";
-import { Docker } from "../../docker";
-
-const dockerConfigDir = "/etc/dendrite/";
-const dendriteConfigFile = "dendrite.yaml";
-
-// Surprisingly, Dendrite implements the same register user Admin API Synapse, so we can just extend it
-export class Dendrite extends Synapse implements Homeserver, HomeserverInstance {
-    protected image = "matrixdotorg/dendrite-monolith:main";
-    protected entrypoint = "/usr/bin/dendrite";
-
-    /**
-     * Start a dendrite instance: the template must be the name of one of the templates
-     * in the playwright/plugins/dendritedocker/templates directory
-     * @param opts
-     */
-    public async start(opts: StartHomeserverOpts): Promise<HomeserverInstance> {
-        const denCfg = await cfgDirFromTemplate(this.image, opts);
-
-        console.log(`Starting dendrite with config dir ${denCfg.configDir}...`);
-
-        const dendriteId = await this.docker.run({
-            image: this.image,
-            params: [
-                "-v",
-                `${denCfg.configDir}:` + dockerConfigDir,
-                "-p",
-                `${denCfg.port}:8008/tcp`,
-                "--entrypoint",
-                this.entrypoint,
-            ],
-            containerName: `react-sdk-playwright-dendrite`,
-            cmd: ["--config", dockerConfigDir + dendriteConfigFile, "--really-enable-open-registration", "true", "run"],
-        });
-
-        console.log(`Started dendrite with id ${dendriteId} on port ${denCfg.port}.`);
-
-        // Await Dendrite healthcheck
-        await this.docker.exec([
-            "curl",
-            "--connect-timeout",
-            "30",
-            "--retry",
-            "30",
-            "--retry-delay",
-            "1",
-            "--retry-all-errors",
-            "--silent",
-            "http://localhost:8008/_matrix/client/versions",
-        ]);
-
-        const dockerUrl = `http://${await this.docker.getContainerIp()}:8008`;
-        this.config = {
-            ...denCfg,
-            serverId: dendriteId,
-            dockerUrl,
-        };
-        return this;
-    }
-
-    public async stop(): Promise<string[]> {
-        if (!this.config) throw new Error("Missing existing dendrite instance, did you call stop() before start()?");
-
-        const dendriteLogsPath = path.join("playwright", "dendritelogs", this.config.serverId);
-        await fse.ensureDir(dendriteLogsPath);
-
-        await this.docker.persistLogsToFile({
-            stdoutFile: path.join(dendriteLogsPath, "stdout.log"),
-            stderrFile: path.join(dendriteLogsPath, "stderr.log"),
-        });
-
-        await this.docker.stop();
-
-        await fse.remove(this.config.configDir);
-
-        console.log(`Stopped dendrite id ${this.config.serverId}.`);
-
-        return [path.join(dendriteLogsPath, "stdout.log"), path.join(dendriteLogsPath, "stderr.log")];
-    }
-}
-
-export class Pinecone extends Dendrite {
-    protected image = "matrixdotorg/dendrite-demo-pinecone:main";
-    protected entrypoint = "/usr/bin/dendrite-demo-pinecone";
-}
-
-async function cfgDirFromTemplate(
-    dendriteImage: string,
-    opts: StartHomeserverOpts,
-): Promise<Omit<HomeserverConfig, "dockerUrl">> {
-    const template = "default"; // XXX: for now we only have one template
-    const templateDir = path.join(__dirname, "templates", template);
-
-    const stats = await fse.stat(templateDir);
-    if (!stats?.isDirectory) {
-        throw new Error(`No such template: ${template}`);
-    }
-    const tempDir = await fse.mkdtemp(path.join(os.tmpdir(), "react-sdk-dendritedocker-"));
-
-    // copy the contents of the template dir, omitting homeserver.yaml as we'll template that
-    console.log(`Copy ${templateDir} -> ${tempDir}`);
-    await fse.copy(templateDir, tempDir, { filter: (f) => path.basename(f) !== dendriteConfigFile });
-
-    const registrationSecret = randB64Bytes(16);
-
-    const port = await getFreePort();
-    const baseUrl = `http://localhost:${port}`;
-
-    // now copy homeserver.yaml, applying substitutions
-    console.log(`Gen ${path.join(templateDir, dendriteConfigFile)}`);
-    let hsYaml = await fse.readFile(path.join(templateDir, dendriteConfigFile), "utf8");
-    hsYaml = hsYaml.replace(/{{REGISTRATION_SECRET}}/g, registrationSecret);
-    await fse.writeFile(path.join(tempDir, dendriteConfigFile), hsYaml);
-
-    const docker = new Docker();
-    await docker.run({
-        image: dendriteImage,
-        params: ["--entrypoint=", "-v", `${tempDir}:/mnt`],
-        containerName: `react-sdk-playwright-dendrite-keygen`,
-        cmd: ["/usr/bin/generate-keys", "-private-key", "/mnt/matrix_key.pem"],
-    });
-
-    return {
-        port,
-        baseUrl,
-        configDir: tempDir,
-        registrationSecret,
-    };
-}
-
-export function isDendrite(): boolean {
-    return process.env["PLAYWRIGHT_HOMESERVER"] === "dendrite" || process.env["PLAYWRIGHT_HOMESERVER"] === "pinecone";
-}
+export const isDendrite = ({ homeserverType }: Options): boolean => {
+    return homeserverType === "dendrite" || homeserverType === "pinecone";
+};
diff --git a/playwright/plugins/homeserver/dendrite/templates/default/dendrite.yaml b/playwright/plugins/homeserver/dendrite/templates/default/dendrite.yaml
deleted file mode 100644
index 634cebbc876..00000000000
--- a/playwright/plugins/homeserver/dendrite/templates/default/dendrite.yaml
+++ /dev/null
@@ -1,378 +0,0 @@
-# This is the Dendrite configuration file.
-#
-# The configuration is split up into sections - each Dendrite component has a
-# configuration section, in addition to the "global" section which applies to
-# all components.
-
-# The version of the configuration file.
-version: 2
-
-# Global Matrix configuration. This configuration applies to all components.
-global:
-    # The domain name of this homeserver.
-    server_name: localhost
-
-    # The path to the signing private key file, used to sign requests and events.
-    # Note that this is NOT the same private key as used for TLS! To generate a
-    # signing key, use "./bin/generate-keys --private-key matrix_key.pem".
-    private_key: matrix_key.pem
-
-    # The paths and expiry timestamps (as a UNIX timestamp in millisecond precision)
-    # to old signing keys that were formerly in use on this domain name. These
-    # keys will not be used for federation request or event signing, but will be
-    # provided to any other homeserver that asks when trying to verify old events.
-    old_private_keys:
-    #  If the old private key file is available:
-    #  - private_key: old_matrix_key.pem
-    #    expired_at: 1601024554498
-    #  If only the public key (in base64 format) and key ID are known:
-    #  - public_key: mn59Kxfdq9VziYHSBzI7+EDPDcBS2Xl7jeUdiiQcOnM=
-    #    key_id: ed25519:mykeyid
-    #    expired_at: 1601024554498
-
-    # How long a remote server can cache our server signing key before requesting it
-    # again. Increasing this number will reduce the number of requests made by other
-    # servers for our key but increases the period that a compromised key will be
-    # considered valid by other homeservers.
-    key_validity_period: 168h0m0s
-
-    # Global database connection pool, for PostgreSQL monolith deployments only. If
-    # this section is populated then you can omit the "database" blocks in all other
-    # sections. For polylith deployments, or monolith deployments using SQLite databases,
-    # you must configure the "database" block for each component instead.
-    # database:
-    #   connection_string: postgresql://username:password@hostname/dendrite?sslmode=disable
-    #   max_open_conns: 90
-    #   max_idle_conns: 5
-    #   conn_max_lifetime: -1
-
-    # Configuration for in-memory caches. Caches can often improve performance by
-    # keeping frequently accessed items (like events, identifiers etc.) in memory
-    # rather than having to read them from the database.
-    cache:
-        # The estimated maximum size for the global cache in bytes, or in terabytes,
-        # gigabytes, megabytes or kilobytes when the appropriate 'tb', 'gb', 'mb' or
-        # 'kb' suffix is specified. Note that this is not a hard limit, nor is it a
-        # memory limit for the entire process. A cache that is too small may ultimately
-        # provide little or no benefit.
-        max_size_estimated: 1gb
-
-        # The maximum amount of time that a cache entry can live for in memory before
-        # it will be evicted and/or refreshed from the database. Lower values result in
-        # easier admission of new cache entries but may also increase database load in
-        # comparison to higher values, so adjust conservatively. Higher values may make
-        # it harder for new items to make it into the cache, e.g. if new rooms suddenly
-        # become popular.
-        max_age: 1h
-
-    # The server name to delegate server-server communications to, with optional port
-    # e.g. localhost:443
-    well_known_server_name: ""
-
-    # The server name to delegate client-server communications to, with optional port
-    # e.g. localhost:443
-    well_known_client_name: ""
-
-    # Lists of domains that the server will trust as identity servers to verify third
-    # party identifiers such as phone numbers and email addresses.
-    trusted_third_party_id_servers:
-        - matrix.org
-        - vector.im
-
-    # Disables federation. Dendrite will not be able to communicate with other servers
-    # in the Matrix federation and the federation API will not be exposed.
-    disable_federation: false
-
-    # Configures the handling of presence events. Inbound controls whether we receive
-    # presence events from other servers, outbound controls whether we send presence
-    # events for our local users to other servers.
-    presence:
-        enable_inbound: false
-        enable_outbound: false
-
-    # Configures phone-home statistics reporting. These statistics contain the server
-    # name, number of active users and some information on your deployment config.
-    # We use this information to understand how Dendrite is being used in the wild.
-    report_stats:
-        enabled: false
-        endpoint: https://matrix.org/report-usage-stats/push
-
-    # Server notices allows server admins to send messages to all users on the server.
-    server_notices:
-        enabled: false
-        # The local part, display name and avatar URL (as a mxc:// URL) for the user that
-        # will send the server notices. These are visible to all users on the deployment.
-        local_part: "_server"
-        display_name: "Server Alerts"
-        avatar_url: ""
-        # The room name to be used when sending server notices. This room name will
-        # appear in user clients.
-        room_name: "Server Alerts"
-
-    # Configuration for NATS JetStream
-    jetstream:
-        # A list of NATS Server addresses to connect to. If none are specified, an
-        # internal NATS server will be started automatically when running Dendrite in
-        # monolith mode. For polylith deployments, it is required to specify the address
-        # of at least one NATS Server node.
-        addresses:
-        # - localhost:4222
-
-        # Disable the validation of TLS certificates of NATS. This is
-        # not recommended in production since it may allow NATS traffic
-        # to be sent to an insecure endpoint.
-        disable_tls_validation: false
-
-        # Persistent directory to store JetStream streams in. This directory should be
-        # preserved across Dendrite restarts.
-        storage_path: ./
-
-        # The prefix to use for stream names for this homeserver - really only useful
-        # if you are running more than one Dendrite server on the same NATS deployment.
-        topic_prefix: Dendrite
-
-    # Configuration for Prometheus metric collection.
-    metrics:
-        enabled: false
-        basic_auth:
-            username: metrics
-            password: metrics
-
-    # Optional DNS cache. The DNS cache may reduce the load on DNS servers if there
-    # is no local caching resolver available for use.
-    dns_cache:
-        enabled: false
-        cache_size: 256
-        cache_lifetime: "5m" # 5 minutes; https://pkg.go.dev/time@master#ParseDuration
-
-# Configuration for the Appservice API.
-app_service_api:
-    # Disable the validation of TLS certificates of appservices. This is
-    # not recommended in production since it may allow appservice traffic
-    # to be sent to an insecure endpoint.
-    disable_tls_validation: false
-
-    # Appservice configuration files to load into this homeserver.
-    config_files:
-    #  - /path/to/appservice_registration.yaml
-
-# Configuration for the Client API.
-client_api:
-    # Prevents new users from being able to register on this homeserver, except when
-    # using the registration shared secret below.
-    registration_disabled: false
-
-    # Prevents new guest accounts from being created. Guest registration is also
-    # disabled implicitly by setting 'registration_disabled' above.
-    guests_disabled: true
-
-    # If set, allows registration by anyone who knows the shared secret, regardless
-    # of whether registration is otherwise disabled.
-    registration_shared_secret: "{{REGISTRATION_SECRET}}"
-
-    # Whether to require reCAPTCHA for registration. If you have enabled registration
-    # then this is HIGHLY RECOMMENDED to reduce the risk of your homeserver being used
-    # for coordinated spam attacks.
-    enable_registration_captcha: false
-
-    # Settings for ReCAPTCHA.
-    recaptcha_public_key: ""
-    recaptcha_private_key: ""
-    recaptcha_bypass_secret: ""
-
-    # To use hcaptcha.com instead of ReCAPTCHA, set the following parameters, otherwise just keep them empty.
-    # recaptcha_siteverify_api: "https://hcaptcha.com/siteverify"
-    # recaptcha_api_js_url: "https://js.hcaptcha.com/1/api.js"
-    # recaptcha_form_field: "h-captcha-response"
-    # recaptcha_sitekey_class: "h-captcha"
-
-    # TURN server information that this homeserver should send to clients.
-    turn:
-        turn_user_lifetime: "5m"
-        turn_uris:
-        #  - turn:turn.server.org?transport=udp
-        #  - turn:turn.server.org?transport=tcp
-        turn_shared_secret: ""
-        # If your TURN server requires static credentials, then you will need to enter
-        # them here instead of supplying a shared secret. Note that these credentials
-        # will be visible to clients!
-        # turn_username: ""
-        # turn_password: ""
-
-    # Settings for rate-limited endpoints. Rate limiting kicks in after the threshold
-    # number of "slots" have been taken by requests from a specific host. Each "slot"
-    # will be released after the cooloff time in milliseconds. Server administrators
-    # and appservice users are exempt from rate limiting by default.
-    rate_limiting:
-        enabled: true
-        threshold: 20
-        cooloff_ms: 500
-        exempt_user_ids:
-        #  - "@user:domain.com"
-
-# Configuration for the Federation API.
-federation_api:
-    # How many times we will try to resend a failed transaction to a specific server. The
-    # backoff is 2**x seconds, so 1 = 2 seconds, 2 = 4 seconds, 3 = 8 seconds etc. Once
-    # the max retries are exceeded, Dendrite will no longer try to send transactions to
-    # that server until it comes back to life and connects to us again.
-    send_max_retries: 16
-
-    # Disable the validation of TLS certificates of remote federated homeservers. Do not
-    # enable this option in production as it presents a security risk!
-    disable_tls_validation: false
-
-    # Disable HTTP keepalives, which also prevents connection reuse. Dendrite will typically
-    # keep HTTP connections open to remote hosts for 5 minutes as they can be reused much
-    # more quickly than opening new connections each time. Disabling keepalives will close
-    # HTTP connections immediately after a successful request but may result in more CPU and
-    # memory being used on TLS handshakes for each new connection instead.
-    disable_http_keepalives: false
-
-    # Perspective keyservers to use as a backup when direct key fetches fail. This may
-    # be required to satisfy key requests for servers that are no longer online when
-    # joining some rooms.
-    key_perspectives:
-        - server_name: matrix.org
-          keys:
-              - key_id: ed25519:auto
-                public_key: Noi6WqcDj0QmPxCNQqgezwTlBKrfqehY1u2FyWP9uYw
-              - key_id: ed25519:a_RXGa
-                public_key: l8Hft5qXKn1vfHrg3p4+W8gELQVo8N13JkluMfmn2sQ
-
-    # This option will control whether Dendrite will prefer to look up keys directly
-    # or whether it should try perspective servers first, using direct fetches as a
-    # last resort.
-    prefer_direct_fetch: false
-
-    database:
-        connection_string: file:dendrite-federationapi.db
-
-# Configuration for the Media API.
-media_api:
-    # Storage path for uploaded media. May be relative or absolute.
-    base_path: ./media_store
-
-    # The maximum allowed file size (in bytes) for media uploads to this homeserver
-    # (0 = unlimited). If using a reverse proxy, ensure it allows requests at least
-    #this large (e.g. the client_max_body_size setting in nginx).
-    max_file_size_bytes: 10485760
-
-    # Whether to dynamically generate thumbnails if needed.
-    dynamic_thumbnails: false
-
-    # The maximum number of simultaneous thumbnail generators to run.
-    max_thumbnail_generators: 10
-
-    # A list of thumbnail sizes to be generated for media content.
-    thumbnail_sizes:
-        - width: 32
-          height: 32
-          method: crop
-        - width: 96
-          height: 96
-          method: crop
-        - width: 640
-          height: 480
-          method: scale
-
-    database:
-        connection_string: file:dendrite-mediaapi.db
-
-# Configuration for enabling experimental MSCs on this homeserver.
-mscs:
-    mscs:
-    #  - msc2836  # (Threading, see https://github.com/matrix-org/matrix-doc/pull/2836)
-    #  - msc2946  # (Spaces Summary, see https://github.com/matrix-org/matrix-doc/pull/2946)
-
-    database:
-        connection_string: file:dendrite-msc.db
-
-# Configuration for the Sync API.
-sync_api:
-    # This option controls which HTTP header to inspect to find the real remote IP
-    # address of the client. This is likely required if Dendrite is running behind
-    # a reverse proxy server.
-    # real_ip_header: X-Real-IP
-
-    # Configuration for the full-text search engine.
-    search:
-        # Whether or not search is enabled.
-        enabled: false
-
-        # The path where the search index will be created in.
-        index_path: "./searchindex"
-
-        # The language most likely to be used on the server - used when indexing, to
-        # ensure the returned results match expectations. A full list of possible languages
-        # can be found at https://github.com/blevesearch/bleve/tree/master/analysis/lang
-        language: "en"
-
-    database:
-        connection_string: file:dendrite-syncapi.db
-
-# Configuration for the User API.
-user_api:
-    # The cost when hashing passwords on registration/login. Default: 10. Min: 4, Max: 31
-    # See https://pkg.go.dev/golang.org/x/crypto/bcrypt for more information.
-    # Setting this lower makes registration/login consume less CPU resources at the cost
-    # of security should the database be compromised. Setting this higher makes registration/login
-    # consume more CPU resources but makes it harder to brute force password hashes. This value
-    # can be lowered if performing tests or on embedded Dendrite instances (e.g WASM builds).
-    bcrypt_cost: 10
-
-    # The length of time that a token issued for a relying party from
-    # /_matrix/client/r0/user/{userId}/openid/request_token endpoint
-    # is considered to be valid in milliseconds.
-    # The default lifetime is 3600000ms (60 minutes).
-    # openid_token_lifetime_ms: 3600000
-
-    # Users who register on this homeserver will automatically be joined to the rooms listed under "auto_join_rooms" option.
-    # By default, any room aliases included in this list will be created as a publicly joinable room
-    # when the first user registers for the homeserver. If the room already exists,
-    # make certain it is a publicly joinable room, i.e. the join rule of the room must be set to 'public'.
-    # As Spaces are just rooms under the hood, Space aliases may also be used.
-    auto_join_rooms:
-    #  - "#main:matrix.org"
-
-    account_database:
-        connection_string: file:dendrite-userapi.db
-
-room_server:
-    database:
-        connection_string: file:dendrite-roomserverapi.db
-
-key_server:
-    database:
-        connection_string: file:dendrite-keyserverapi.db
-
-relay_api:
-    database:
-        connection_string: file:dendrite-relayapi.db
-
-# Configuration for Opentracing.
-# See https://github.com/matrix-org/dendrite/tree/master/docs/tracing for information on
-# how this works and how to set it up.
-tracing:
-    enabled: false
-    jaeger:
-        serviceName: ""
-        disabled: false
-        rpc_metrics: false
-        tags: []
-        sampler: null
-        reporter: null
-        headers: null
-        baggage_restrictions: null
-        throttler: null
-
-# Logging configuration. The "std" logging type controls the logs being sent to
-# stdout. The "file" logging type controls logs being written to a log folder on
-# the disk. Supported log levels are "debug", "info", "warn", "error".
-logging:
-    - type: std
-      level: debug
-    - type: file
-      level: debug
-      params:
-          path: ./logs
diff --git a/playwright/plugins/homeserver/index.ts b/playwright/plugins/homeserver/index.ts
index c17ea15f554..e5359ad4543 100644
--- a/playwright/plugins/homeserver/index.ts
+++ b/playwright/plugins/homeserver/index.ts
@@ -2,20 +2,15 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
-export interface HomeserverConfig {
-    readonly configDir: string;
-    readonly baseUrl: string;
-    readonly port: number;
-    readonly registrationSecret: string;
-    readonly dockerUrl: string;
-}
+import { ClientServerApi } from "../utils/api.ts";
 
 export interface HomeserverInstance {
-    readonly config: HomeserverConfig;
+    readonly baseUrl: string;
+    readonly csApi: ClientServerApi;
 
     /**
      * Register a user on the given Homeserver using the shared registration secret.
@@ -42,27 +37,6 @@ export interface HomeserverInstance {
     setThreepid(userId: string, medium: string, address: string): Promise<void>;
 }
 
-export interface StartHomeserverOpts {
-    /** path to template within playwright/plugins/{homeserver}docker/template/ directory. */
-    template: string;
-
-    /** Port of an OAuth server to configure the homeserver to use */
-    oAuthServerPort?: number;
-
-    /** Additional variables to inject into the configuration template **/
-    variables?: Record<string, string | number>;
-}
-
-export interface Homeserver {
-    start(opts: StartHomeserverOpts): Promise<HomeserverInstance>;
-    /**
-     * Stop this test homeserver instance.
-     *
-     * @returns A list of paths relative to the cwd for logfiles generated during this test run.
-     */
-    stop(): Promise<string[]>;
-}
-
 export interface Credentials {
     accessToken: string;
     userId: string;
@@ -70,4 +44,7 @@ export interface Credentials {
     homeServer: string;
     password: string | null; // null for password-less users
     displayName?: string;
+    username: string; // the localpart of the userId
 }
+
+export type HomeserverType = "synapse" | "dendrite" | "pinecone";
diff --git a/playwright/plugins/homeserver/synapse/consentHomeserver.ts b/playwright/plugins/homeserver/synapse/consentHomeserver.ts
new file mode 100644
index 00000000000..e714e8a9c11
--- /dev/null
+++ b/playwright/plugins/homeserver/synapse/consentHomeserver.ts
@@ -0,0 +1,62 @@
+/*
+Copyright 2024 New Vector Ltd.
+Copyright 2023 The Matrix.org Foundation C.I.C.
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+Please see LICENSE files in the repository root for full details.
+*/
+
+import { Fixtures } from "../../../element-web-test.ts";
+
+export const consentHomeserver: Fixtures = {
+    _homeserver: [
+        async ({ _homeserver: container, mailhog }, use) => {
+            container
+                .withCopyDirectoriesToContainer([
+                    { source: "playwright/plugins/homeserver/synapse/res", target: "/data/res" },
+                ])
+                .withConfig({
+                    email: {
+                        enable_notifs: false,
+                        smtp_host: "mailhog",
+                        smtp_port: 1025,
+                        smtp_user: "username",
+                        smtp_pass: "password",
+                        require_transport_security: false,
+                        notif_from: "Your Friendly %(app)s homeserver <noreply@example.com>",
+                        app_name: "Matrix",
+                        notif_template_html: "notif_mail.html",
+                        notif_template_text: "notif_mail.txt",
+                        notif_for_new_users: true,
+                        client_base_url: "http://localhost/element",
+                    },
+                    user_consent: {
+                        template_dir: "/data/res/templates/privacy",
+                        version: "1.0",
+                        server_notice_content: {
+                            msgtype: "m.text",
+                            body: "To continue using this homeserver you must review and agree to the terms and conditions at %(consent_uri)s",
+                        },
+                        send_server_notice_to_guests: true,
+                        block_events_error:
+                            "To continue using this homeserver you must review and agree to the terms and conditions at %(consent_uri)s",
+                        require_at_registration: true,
+                    },
+                    server_notices: {
+                        system_mxid_localpart: "notices",
+                        system_mxid_display_name: "Server Notices",
+                        system_mxid_avatar_url: "mxc://localhost/oumMVlgDnLYFaPVkExemNVVZ",
+                        room_name: "Server Notices",
+                    },
+                })
+                .withConfigField("listeners[0].resources[0].names", ["client", "consent"]);
+            await use(container);
+        },
+        { scope: "worker" },
+    ],
+
+    context: async ({ homeserverType, context }, use, testInfo) => {
+        testInfo.skip(homeserverType !== "synapse", "does not yet support MAS");
+        await use(context);
+    },
+};
diff --git a/playwright/plugins/homeserver/synapse/emailHomeserver.ts b/playwright/plugins/homeserver/synapse/emailHomeserver.ts
new file mode 100644
index 00000000000..f7dee7b01a9
--- /dev/null
+++ b/playwright/plugins/homeserver/synapse/emailHomeserver.ts
@@ -0,0 +1,34 @@
+/*
+Copyright 2024 New Vector Ltd.
+Copyright 2023 The Matrix.org Foundation C.I.C.
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+Please see LICENSE files in the repository root for full details.
+*/
+
+import { Fixtures } from "../../../element-web-test.ts";
+
+export const emailHomeserver: Fixtures = {
+    _homeserver: [
+        async ({ _homeserver: container, mailhog }, use) => {
+            container.withConfig({
+                enable_registration_without_verification: undefined,
+                disable_msisdn_registration: undefined,
+                registrations_require_3pid: ["email"],
+                email: {
+                    smtp_host: "mailhog",
+                    smtp_port: 1025,
+                    notif_from: "Your Friendly %(app)s homeserver <noreply@example.com>",
+                    app_name: "my_branded_matrix_server",
+                },
+            });
+            await use(container);
+        },
+        { scope: "worker" },
+    ],
+
+    context: async ({ homeserverType, context }, use, testInfo) => {
+        testInfo.skip(homeserverType !== "synapse", "does not yet support MAS");
+        await use(context);
+    },
+};
diff --git a/playwright/plugins/homeserver/synapse/index.ts b/playwright/plugins/homeserver/synapse/index.ts
deleted file mode 100644
index fc09b6a22b2..00000000000
--- a/playwright/plugins/homeserver/synapse/index.ts
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2023 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
-Please see LICENSE files in the repository root for full details.
-*/
-
-import * as path from "node:path";
-import * as os from "node:os";
-import * as crypto from "node:crypto";
-import * as fse from "fs-extra";
-import { APIRequestContext } from "@playwright/test";
-
-import { getFreePort } from "../../utils/port";
-import { Docker } from "../../docker";
-import { HomeserverConfig, HomeserverInstance, Homeserver, StartHomeserverOpts, Credentials } from "..";
-import { randB64Bytes } from "../../utils/rand";
-
-// Docker tag to use for synapse docker image.
-// We target a specific digest as every now and then a Synapse update will break our CI.
-// This digest is updated by the playwright-image-updates.yaml workflow periodically.
-const DOCKER_TAG = "develop@sha256:ef3d491214fa380918c736d9aa720992fb58829ce5c06fa3ca36d357fa1df75d";
-
-async function cfgDirFromTemplate(opts: StartHomeserverOpts): Promise<Omit<HomeserverConfig, "dockerUrl">> {
-    const templateDir = path.join(__dirname, "templates", opts.template);
-
-    const stats = await fse.stat(templateDir);
-    if (!stats?.isDirectory) {
-        throw new Error(`No such template: ${opts.template}`);
-    }
-    const tempDir = await fse.mkdtemp(path.join(os.tmpdir(), "react-sdk-synapsedocker-"));
-
-    // copy the contents of the template dir, omitting homeserver.yaml as we'll template that
-    console.log(`Copy ${templateDir} -> ${tempDir}`);
-    await fse.copy(templateDir, tempDir, { filter: (f) => path.basename(f) !== "homeserver.yaml" });
-
-    const registrationSecret = randB64Bytes(16);
-    const macaroonSecret = randB64Bytes(16);
-    const formSecret = randB64Bytes(16);
-
-    const port = await getFreePort();
-    const baseUrl = `http://localhost:${port}`;
-
-    // now copy homeserver.yaml, applying substitutions
-    const templateHomeserver = path.join(templateDir, "homeserver.yaml");
-    const outputHomeserver = path.join(tempDir, "homeserver.yaml");
-    console.log(`Gen ${templateHomeserver} -> ${outputHomeserver}`);
-    let hsYaml = await fse.readFile(templateHomeserver, "utf8");
-    hsYaml = hsYaml.replace(/{{REGISTRATION_SECRET}}/g, registrationSecret);
-    hsYaml = hsYaml.replace(/{{MACAROON_SECRET_KEY}}/g, macaroonSecret);
-    hsYaml = hsYaml.replace(/{{FORM_SECRET}}/g, formSecret);
-    hsYaml = hsYaml.replace(/{{PUBLIC_BASEURL}}/g, baseUrl);
-    if (opts.oAuthServerPort) {
-        hsYaml = hsYaml.replace(/{{OAUTH_SERVER_PORT}}/g, opts.oAuthServerPort.toString());
-    }
-    if (opts.variables) {
-        for (const key in opts.variables) {
-            hsYaml = hsYaml.replace(new RegExp("%" + key + "%", "g"), String(opts.variables[key]));
-        }
-    }
-
-    await fse.writeFile(outputHomeserver, hsYaml);
-
-    // now generate a signing key (we could use synapse's config generation for
-    // this, or we could just do this...)
-    // NB. This assumes the homeserver.yaml specifies the key in this location
-    const signingKey = randB64Bytes(32);
-    const outputSigningKey = path.join(tempDir, "localhost.signing.key");
-    console.log(`Gen -> ${outputSigningKey}`);
-    await fse.writeFile(outputSigningKey, `ed25519 x ${signingKey}`);
-
-    // Allow anyone to read, write and execute in the /temp/react-sdk-synapsedocker-xxx directory
-    // so that the DIND setup that we use to update the playwright screenshots work without any issues.
-    await fse.chmod(tempDir, 0o757);
-
-    return {
-        port,
-        baseUrl,
-        configDir: tempDir,
-        registrationSecret,
-    };
-}
-
-export class Synapse implements Homeserver, HomeserverInstance {
-    protected docker: Docker = new Docker();
-    public config: HomeserverConfig & { serverId: string };
-
-    private adminToken?: string;
-
-    public constructor(private readonly request: APIRequestContext) {}
-
-    /**
-     * Start a synapse instance: the template must be the name of
-     * one of the templates in the playwright/plugins/synapsedocker/templates
-     * directory.
-     */
-    public async start(opts: StartHomeserverOpts): Promise<HomeserverInstance> {
-        if (this.config) await this.stop();
-
-        const synCfg = await cfgDirFromTemplate(opts);
-        console.log(`Starting synapse with config dir ${synCfg.configDir}...`);
-        const dockerSynapseParams = ["-v", `${synCfg.configDir}:/data`, "-p", `${synCfg.port}:8008/tcp`];
-        const synapseId = await this.docker.run({
-            image: `ghcr.io/element-hq/synapse:${DOCKER_TAG}`,
-            containerName: `react-sdk-playwright-synapse`,
-            params: dockerSynapseParams,
-            cmd: ["run"],
-        });
-        console.log(`Started synapse with id ${synapseId} on port ${synCfg.port}.`);
-        // Await Synapse healthcheck
-        await this.docker.exec([
-            "curl",
-            "--connect-timeout",
-            "30",
-            "--retry",
-            "30",
-            "--retry-delay",
-            "1",
-            "--retry-all-errors",
-            "--silent",
-            "http://localhost:8008/health",
-        ]);
-        const dockerUrl = `http://${await this.docker.getContainerIp()}:8008`;
-        this.config = {
-            ...synCfg,
-            serverId: synapseId,
-            dockerUrl,
-        };
-        return this;
-    }
-
-    public async stop(): Promise<string[]> {
-        if (!this.config) throw new Error("Missing existing synapse instance, did you call stop() before start()?");
-        const id = this.config.serverId;
-        const synapseLogsPath = path.join("playwright", "logs", "synapse", id);
-        await fse.ensureDir(synapseLogsPath);
-        await this.docker.persistLogsToFile({
-            stdoutFile: path.join(synapseLogsPath, "stdout.log"),
-            stderrFile: path.join(synapseLogsPath, "stderr.log"),
-        });
-        await this.docker.stop();
-        await fse.remove(this.config.configDir);
-        console.log(`Stopped synapse id ${id}.`);
-
-        return [path.join(synapseLogsPath, "stdout.log"), path.join(synapseLogsPath, "stderr.log")];
-    }
-
-    private async registerUserInternal(
-        username: string,
-        password: string,
-        displayName?: string,
-        admin = false,
-    ): Promise<Credentials> {
-        const url = `${this.config.baseUrl}/_synapse/admin/v1/register`;
-        const { nonce } = await this.request.get(url).then((r) => r.json());
-        const mac = crypto
-            .createHmac("sha1", this.config.registrationSecret)
-            .update(`${nonce}\0${username}\0${password}\0${admin ? "" : "not"}admin`)
-            .digest("hex");
-        const res = await this.request.post(url, {
-            data: {
-                nonce,
-                username,
-                password,
-                mac,
-                admin,
-                displayname: displayName,
-            },
-        });
-
-        if (!res.ok()) {
-            throw await res.json();
-        }
-
-        const data = await res.json();
-        return {
-            homeServer: data.home_server,
-            accessToken: data.access_token,
-            userId: data.user_id,
-            deviceId: data.device_id,
-            password,
-            displayName,
-        };
-    }
-
-    public registerUser(username: string, password: string, displayName?: string): Promise<Credentials> {
-        return this.registerUserInternal(username, password, displayName, false);
-    }
-
-    public async loginUser(userId: string, password: string): Promise<Credentials> {
-        const url = `${this.config.baseUrl}/_matrix/client/v3/login`;
-        const res = await this.request.post(url, {
-            data: {
-                type: "m.login.password",
-                identifier: {
-                    type: "m.id.user",
-                    user: userId,
-                },
-                password: password,
-            },
-        });
-        const json = await res.json();
-
-        return {
-            password,
-            accessToken: json.access_token,
-            userId: json.user_id,
-            deviceId: json.device_id,
-            homeServer: json.home_server,
-        };
-    }
-
-    public async setThreepid(userId: string, medium: string, address: string): Promise<void> {
-        if (this.adminToken === undefined) {
-            const result = await this.registerUserInternal("admin", "totalyinsecureadminpassword", undefined, true);
-            this.adminToken = result.accessToken;
-        }
-
-        const url = `${this.config.baseUrl}/_synapse/admin/v2/users/${userId}`;
-        const res = await this.request.put(url, {
-            data: {
-                threepids: [
-                    {
-                        medium,
-                        address,
-                    },
-                ],
-            },
-            headers: {
-                Authorization: `Bearer ${this.adminToken}`,
-            },
-        });
-
-        if (!res.ok()) {
-            throw await res.json();
-        }
-    }
-}
diff --git a/playwright/plugins/homeserver/synapse/legacyOAuthHomeserver.ts b/playwright/plugins/homeserver/synapse/legacyOAuthHomeserver.ts
new file mode 100644
index 00000000000..7414fdb0152
--- /dev/null
+++ b/playwright/plugins/homeserver/synapse/legacyOAuthHomeserver.ts
@@ -0,0 +1,62 @@
+/*
+Copyright 2024 New Vector Ltd.
+Copyright 2023 The Matrix.org Foundation C.I.C.
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+Please see LICENSE files in the repository root for full details.
+*/
+
+import { TestContainers } from "testcontainers";
+
+import { OAuthServer } from "../../oauth_server";
+import { Fixtures } from "../../../element-web-test.ts";
+
+export const legacyOAuthHomeserver: Fixtures = {
+    oAuthServer: [
+        // eslint-disable-next-line no-empty-pattern
+        async ({}, use) => {
+            const server = new OAuthServer();
+            await use(server);
+            server.stop();
+        },
+        { scope: "worker" },
+    ],
+    context: async ({ homeserverType, context, oAuthServer }, use, testInfo) => {
+        testInfo.skip(homeserverType !== "synapse", "does not yet support OIDC");
+        oAuthServer.onTestStarted(testInfo);
+        await use(context);
+    },
+    _homeserver: [
+        async ({ oAuthServer, _homeserver: homeserver }, use) => {
+            const port = oAuthServer.start();
+            await TestContainers.exposeHostPorts(port);
+            homeserver.withConfig({
+                oidc_providers: [
+                    {
+                        idp_id: "test",
+                        idp_name: "OAuth test",
+                        issuer: `http://localhost:${port}/oauth`,
+                        authorization_endpoint: `http://localhost:${port}/oauth/auth.html`,
+                        // the token endpoint receives requests from synapse,
+                        // rather than the webapp, so needs to escape the docker container.
+                        token_endpoint: `http://host.testcontainers.internal:${port}/oauth/token`,
+                        userinfo_endpoint: `http://host.testcontainers.internal:${port}/oauth/userinfo`,
+                        client_id: "synapse",
+                        discover: false,
+                        scopes: ["profile"],
+                        skip_verification: true,
+                        client_auth_method: "none",
+                        user_mapping_provider: {
+                            config: {
+                                display_name_template: "{{ user.name }}",
+                            },
+                        },
+                    },
+                ],
+            });
+
+            await use(homeserver);
+        },
+        { scope: "worker" },
+    ],
+};
diff --git a/playwright/plugins/homeserver/synapse/masHomeserver.ts b/playwright/plugins/homeserver/synapse/masHomeserver.ts
new file mode 100644
index 00000000000..d52c446e9bd
--- /dev/null
+++ b/playwright/plugins/homeserver/synapse/masHomeserver.ts
@@ -0,0 +1,87 @@
+/*
+Copyright 2024 New Vector Ltd.
+Copyright 2023 The Matrix.org Foundation C.I.C.
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+Please see LICENSE files in the repository root for full details.
+*/
+
+import { MatrixAuthenticationServiceContainer } from "../../../testcontainers/mas.ts";
+import { Fixtures } from "../../../element-web-test.ts";
+
+export const masHomeserver: Fixtures = {
+    mas: [
+        async ({ _homeserver: homeserver, logger, network, postgres, mailhog }, use) => {
+            const config = {
+                clients: [
+                    {
+                        client_id: "0000000000000000000SYNAPSE",
+                        client_auth_method: "client_secret_basic",
+                        client_secret: "SomeRandomSecret",
+                    },
+                ],
+                matrix: {
+                    homeserver: "localhost",
+                    secret: "AnotherRandomSecret",
+                    endpoint: "http://homeserver:8008",
+                },
+            };
+
+            const container = await new MatrixAuthenticationServiceContainer(postgres)
+                .withNetwork(network)
+                .withNetworkAliases("mas")
+                .withLogConsumer(logger.getConsumer("mas"))
+                .withConfig(config)
+                .start();
+
+            homeserver.withConfig({
+                enable_registration: undefined,
+                enable_registration_without_verification: undefined,
+                disable_msisdn_registration: undefined,
+                password_config: undefined,
+                experimental_features: {
+                    msc3861: {
+                        enabled: true,
+                        issuer: `http://mas:8080/`,
+                        introspection_endpoint: "http://mas:8080/oauth2/introspect",
+                        client_id: config.clients[0].client_id,
+                        client_auth_method: config.clients[0].client_auth_method,
+                        client_secret: config.clients[0].client_secret,
+                        admin_token: config.matrix.secret,
+                    },
+                },
+            });
+
+            await use(container);
+            await container.stop();
+        },
+        { scope: "worker" },
+    ],
+
+    config: async ({ homeserver, context, mas }, use) => {
+        const issuer = `${mas.baseUrl}/`;
+        const wellKnown = {
+            "m.homeserver": {
+                base_url: homeserver.baseUrl,
+            },
+            "org.matrix.msc2965.authentication": {
+                issuer,
+                account: `${issuer}account`,
+            },
+        };
+
+        // Ensure org.matrix.msc2965.authentication is in well-known
+        await context.route("https://localhost/.well-known/matrix/client", async (route) => {
+            await route.fulfill({ json: wellKnown });
+        });
+
+        await use({
+            default_server_config: wellKnown,
+        });
+    },
+
+    context: async ({ homeserverType, context }, use, testInfo) => {
+        testInfo.skip(homeserverType !== "synapse", "does not yet support MAS");
+        await use(context);
+    },
+};
diff --git a/playwright/plugins/homeserver/synapse/templates/consent/res/templates/privacy/en/1.0.html b/playwright/plugins/homeserver/synapse/res/templates/privacy/en/1.0.html
similarity index 100%
rename from playwright/plugins/homeserver/synapse/templates/consent/res/templates/privacy/en/1.0.html
rename to playwright/plugins/homeserver/synapse/res/templates/privacy/en/1.0.html
diff --git a/playwright/plugins/homeserver/synapse/templates/consent/res/templates/privacy/en/success.html b/playwright/plugins/homeserver/synapse/res/templates/privacy/en/success.html
similarity index 100%
rename from playwright/plugins/homeserver/synapse/templates/consent/res/templates/privacy/en/success.html
rename to playwright/plugins/homeserver/synapse/res/templates/privacy/en/success.html
diff --git a/playwright/plugins/homeserver/synapse/templates/COPYME/README.md b/playwright/plugins/homeserver/synapse/templates/COPYME/README.md
deleted file mode 100644
index df1ed89e6e4..00000000000
--- a/playwright/plugins/homeserver/synapse/templates/COPYME/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# Meta-template for synapse templates
-
-To make another template, you can copy this directory
diff --git a/playwright/plugins/homeserver/synapse/templates/COPYME/homeserver.yaml b/playwright/plugins/homeserver/synapse/templates/COPYME/homeserver.yaml
deleted file mode 100644
index cb58dc86615..00000000000
--- a/playwright/plugins/homeserver/synapse/templates/COPYME/homeserver.yaml
+++ /dev/null
@@ -1,72 +0,0 @@
-server_name: "localhost"
-pid_file: /data/homeserver.pid
-# XXX: This won't actually be right: it lets docker allocate an ephemeral port,
-# so we have a chicken-and-egg problem
-public_baseurl: http://localhost:8008/
-# Listener is always port 8008 (configured in the container)
-listeners:
-    - port: 8008
-      tls: false
-      bind_addresses: ["::"]
-      type: http
-      x_forwarded: true
-
-      resources:
-          - names: [client, federation, consent]
-            compress: false
-
-# An sqlite in-memory database is fast & automatically wipes each time
-database:
-    name: "sqlite3"
-    args:
-        database: ":memory:"
-
-# Needs to be configured to log to the console like a good docker process
-log_config: "/data/log.config"
-
-rc_messages_per_second: 10000
-rc_message_burst_count: 10000
-rc_registration:
-    per_second: 10000
-    burst_count: 10000
-
-rc_login:
-    address:
-        per_second: 10000
-        burst_count: 10000
-    account:
-        per_second: 10000
-        burst_count: 10000
-    failed_attempts:
-        per_second: 10000
-        burst_count: 10000
-
-media_store_path: "/data/media_store"
-uploads_path: "/data/uploads"
-enable_registration: true
-enable_registration_without_verification: true
-disable_msisdn_registration: false
-# These placeholders will be be replaced with values generated at start
-registration_shared_secret: "{{REGISTRATION_SECRET}}"
-report_stats: false
-macaroon_secret_key: "{{MACAROON_SECRET_KEY}}"
-form_secret: "{{FORM_SECRET}}"
-# Signing key must be here: it will be generated to this file
-signing_key_path: "/data/localhost.signing.key"
-email:
-    enable_notifs: false
-    smtp_host: "localhost"
-    smtp_port: 25
-    smtp_user: "exampleusername"
-    smtp_pass: "examplepassword"
-    require_transport_security: False
-    notif_from: "Your Friendly %(app)s homeserver <noreply@example.com>"
-    app_name: Matrix
-    notif_template_html: notif_mail.html
-    notif_template_text: notif_mail.txt
-    notif_for_new_users: True
-    client_base_url: "http://localhost/element"
-
-trusted_key_servers:
-    - server_name: "matrix.org"
-suppress_key_server_warning: true
diff --git a/playwright/plugins/homeserver/synapse/templates/COPYME/log.config b/playwright/plugins/homeserver/synapse/templates/COPYME/log.config
deleted file mode 100644
index ac232762da3..00000000000
--- a/playwright/plugins/homeserver/synapse/templates/COPYME/log.config
+++ /dev/null
@@ -1,50 +0,0 @@
-# Log configuration for Synapse.
-#
-# This is a YAML file containing a standard Python logging configuration
-# dictionary. See [1] for details on the valid settings.
-#
-# Synapse also supports structured logging for machine readable logs which can
-# be ingested by ELK stacks. See [2] for details.
-#
-# [1]: https://docs.python.org/3.7/library/logging.config.html#configuration-dictionary-schema
-# [2]: https://matrix-org.github.io/synapse/latest/structured_logging.html
-
-version: 1
-
-formatters:
-    precise:
-        format: '%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s'
-
-handlers:
-    # A handler that writes logs to stderr. Unused by default, but can be used
-    # instead of "buffer" and "file" in the logger handlers.
-    console:
-        class: logging.StreamHandler
-        formatter: precise
-
-loggers:
-    synapse.storage.SQL:
-        # beware: increasing this to DEBUG will make synapse log sensitive
-        # information such as access tokens.
-        level: INFO
-
-    twisted:
-        # We send the twisted logging directly to the file handler,
-        # to work around https://github.com/matrix-org/synapse/issues/3471
-        # when using "buffer" logger. Use "console" to log to stderr instead.
-        handlers: [console]
-        propagate: false
-
-root:
-    level: INFO
-
-    # Write logs to the `buffer` handler, which will buffer them together in memory,
-    # then write them to a file.
-    #
-    # Replace "buffer" with "console" to log to stderr instead. (Note that you'll
-    # also need to update the configuration for the `twisted` logger above, in
-    # this case.)
-    #
-    handlers: [console]
-
-disable_existing_loggers: false
diff --git a/playwright/plugins/homeserver/synapse/templates/consent/README.md b/playwright/plugins/homeserver/synapse/templates/consent/README.md
deleted file mode 100644
index 713e55f9d51..00000000000
--- a/playwright/plugins/homeserver/synapse/templates/consent/README.md
+++ /dev/null
@@ -1 +0,0 @@
-A synapse configured with user privacy consent enabled
diff --git a/playwright/plugins/homeserver/synapse/templates/consent/homeserver.yaml b/playwright/plugins/homeserver/synapse/templates/consent/homeserver.yaml
deleted file mode 100644
index d3a4fa520ca..00000000000
--- a/playwright/plugins/homeserver/synapse/templates/consent/homeserver.yaml
+++ /dev/null
@@ -1,84 +0,0 @@
-server_name: "localhost"
-pid_file: /data/homeserver.pid
-public_baseurl: "{{PUBLIC_BASEURL}}"
-listeners:
-    - port: 8008
-      tls: false
-      bind_addresses: ["::"]
-      type: http
-      x_forwarded: true
-
-      resources:
-          - names: [client, federation, consent]
-            compress: false
-
-database:
-    name: "sqlite3"
-    args:
-        database: ":memory:"
-
-log_config: "/data/log.config"
-
-rc_messages_per_second: 10000
-rc_message_burst_count: 10000
-rc_registration:
-    per_second: 10000
-    burst_count: 10000
-
-rc_login:
-    address:
-        per_second: 10000
-        burst_count: 10000
-    account:
-        per_second: 10000
-        burst_count: 10000
-    failed_attempts:
-        per_second: 10000
-        burst_count: 10000
-
-media_store_path: "/data/media_store"
-uploads_path: "/data/uploads"
-enable_registration: true
-enable_registration_without_verification: true
-disable_msisdn_registration: false
-registration_shared_secret: "{{REGISTRATION_SECRET}}"
-report_stats: false
-macaroon_secret_key: "{{MACAROON_SECRET_KEY}}"
-form_secret: "{{FORM_SECRET}}"
-signing_key_path: "/data/localhost.signing.key"
-email:
-    enable_notifs: false
-    smtp_host: "localhost"
-    smtp_port: 25
-    smtp_user: "exampleusername"
-    smtp_pass: "examplepassword"
-    require_transport_security: False
-    notif_from: "Your Friendly %(app)s homeserver <noreply@example.com>"
-    app_name: Matrix
-    notif_template_html: notif_mail.html
-    notif_template_text: notif_mail.txt
-    notif_for_new_users: True
-    client_base_url: "http://localhost/element"
-
-user_consent:
-    template_dir: /data/res/templates/privacy
-    version: 1.0
-    server_notice_content:
-        msgtype: m.text
-        body: >-
-            To continue using this homeserver you must review and agree to the
-            terms and conditions at %(consent_uri)s
-    send_server_notice_to_guests: True
-    block_events_error: >-
-        To continue using this homeserver you must review and agree to the
-        terms and conditions at %(consent_uri)s
-    require_at_registration: true
-
-server_notices:
-    system_mxid_localpart: notices
-    system_mxid_display_name: "Server Notices"
-    system_mxid_avatar_url: "mxc://localhost:5005/oumMVlgDnLYFaPVkExemNVVZ"
-    room_name: "Server Notices"
-trusted_key_servers:
-    - server_name: "matrix.org"
-suppress_key_server_warning: true
diff --git a/playwright/plugins/homeserver/synapse/templates/consent/log.config b/playwright/plugins/homeserver/synapse/templates/consent/log.config
deleted file mode 100644
index b9123d0f5b9..00000000000
--- a/playwright/plugins/homeserver/synapse/templates/consent/log.config
+++ /dev/null
@@ -1,50 +0,0 @@
-# Log configuration for Synapse.
-#
-# This is a YAML file containing a standard Python logging configuration
-# dictionary. See [1] for details on the valid settings.
-#
-# Synapse also supports structured logging for machine readable logs which can
-# be ingested by ELK stacks. See [2] for details.
-#
-# [1]: https://docs.python.org/3.7/library/logging.config.html#configuration-dictionary-schema
-# [2]: https://matrix-org.github.io/synapse/latest/structured_logging.html
-
-version: 1
-
-formatters:
-    precise:
-        format: '%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s'
-
-handlers:
-    # A handler that writes logs to stderr. Unused by default, but can be used
-    # instead of "buffer" and "file" in the logger handlers.
-    console:
-        class: logging.StreamHandler
-        formatter: precise
-
-loggers:
-    synapse.storage.SQL:
-        # beware: increasing this to DEBUG will make synapse log sensitive
-        # information such as access tokens.
-        level: DEBUG
-
-    twisted:
-        # We send the twisted logging directly to the file handler,
-        # to work around https://github.com/matrix-org/synapse/issues/3471
-        # when using "buffer" logger. Use "console" to log to stderr instead.
-        handlers: [console]
-        propagate: false
-
-root:
-    level: DEBUG
-
-    # Write logs to the `buffer` handler, which will buffer them together in memory,
-    # then write them to a file.
-    #
-    # Replace "buffer" with "console" to log to stderr instead. (Note that you'll
-    # also need to update the configuration for the `twisted` logger above, in
-    # this case.)
-    #
-    handlers: [console]
-
-disable_existing_loggers: false
diff --git a/playwright/plugins/homeserver/synapse/templates/default/README.md b/playwright/plugins/homeserver/synapse/templates/default/README.md
deleted file mode 100644
index 8f6b11f999b..00000000000
--- a/playwright/plugins/homeserver/synapse/templates/default/README.md
+++ /dev/null
@@ -1 +0,0 @@
-A synapse configured with user privacy consent disabled
diff --git a/playwright/plugins/homeserver/synapse/templates/default/homeserver.yaml b/playwright/plugins/homeserver/synapse/templates/default/homeserver.yaml
deleted file mode 100644
index 539a917b200..00000000000
--- a/playwright/plugins/homeserver/synapse/templates/default/homeserver.yaml
+++ /dev/null
@@ -1,106 +0,0 @@
-server_name: "localhost"
-pid_file: /data/homeserver.pid
-public_baseurl: "{{PUBLIC_BASEURL}}"
-listeners:
-    - port: 8008
-      tls: false
-      bind_addresses: ["::"]
-      type: http
-      x_forwarded: true
-
-      resources:
-          - names: [client]
-            compress: false
-
-database:
-    name: "sqlite3"
-    args:
-        database: ":memory:"
-
-log_config: "/data/log.config"
-
-rc_messages_per_second: 10000
-rc_message_burst_count: 10000
-rc_registration:
-    per_second: 10000
-    burst_count: 10000
-rc_joins:
-    local:
-        per_second: 9999
-        burst_count: 9999
-    remote:
-        per_second: 9999
-        burst_count: 9999
-rc_joins_per_room:
-    per_second: 9999
-    burst_count: 9999
-rc_3pid_validation:
-    per_second: 1000
-    burst_count: 1000
-
-rc_invites:
-    per_room:
-        per_second: 1000
-        burst_count: 1000
-    per_user:
-        per_second: 1000
-        burst_count: 1000
-
-rc_login:
-    address:
-        per_second: 10000
-        burst_count: 10000
-    account:
-        per_second: 10000
-        burst_count: 10000
-    failed_attempts:
-        per_second: 10000
-        burst_count: 10000
-
-media_store_path: "/data/media_store"
-uploads_path: "/data/uploads"
-enable_registration: true
-enable_registration_without_verification: true
-disable_msisdn_registration: false
-registration_shared_secret: "{{REGISTRATION_SECRET}}"
-report_stats: false
-macaroon_secret_key: "{{MACAROON_SECRET_KEY}}"
-form_secret: "{{FORM_SECRET}}"
-signing_key_path: "/data/localhost.signing.key"
-
-trusted_key_servers:
-    - server_name: "matrix.org"
-suppress_key_server_warning: true
-
-ui_auth:
-    session_timeout: "300s"
-
-oidc_providers:
-    - idp_id: test
-      idp_name: "OAuth test"
-      issuer: "http://localhost:{{OAUTH_SERVER_PORT}}/oauth"
-      authorization_endpoint: "http://localhost:{{OAUTH_SERVER_PORT}}/oauth/auth.html"
-      # the token endpoint receives requests from synapse, rather than the webapp, so needs to escape the docker container.
-      token_endpoint: "http://host.containers.internal:{{OAUTH_SERVER_PORT}}/oauth/token"
-      userinfo_endpoint: "http://host.containers.internal:{{OAUTH_SERVER_PORT}}/oauth/userinfo"
-      client_id: "synapse"
-      discover: false
-      scopes: ["profile"]
-      skip_verification: true
-      client_auth_method: none
-      user_mapping_provider:
-          config:
-              display_name_template: "{{ user.name }}"
-
-# Inhibit background updates as this Synapse isn't long-lived
-background_updates:
-    min_batch_size: 100000
-    sleep_duration_ms: 100000
-
-experimental_features:
-    # Needed for e2e/crypto/crypto.spec.ts > Cryptography > decryption failure
-    # messages > non-joined historical messages.
-    # Can be removed after Synapse enables it by default
-    msc4115_membership_on_events: true
-
-enable_authenticated_media: true
diff --git a/playwright/plugins/homeserver/synapse/templates/default/log.config b/playwright/plugins/homeserver/synapse/templates/default/log.config
deleted file mode 100644
index b9123d0f5b9..00000000000
--- a/playwright/plugins/homeserver/synapse/templates/default/log.config
+++ /dev/null
@@ -1,50 +0,0 @@
-# Log configuration for Synapse.
-#
-# This is a YAML file containing a standard Python logging configuration
-# dictionary. See [1] for details on the valid settings.
-#
-# Synapse also supports structured logging for machine readable logs which can
-# be ingested by ELK stacks. See [2] for details.
-#
-# [1]: https://docs.python.org/3.7/library/logging.config.html#configuration-dictionary-schema
-# [2]: https://matrix-org.github.io/synapse/latest/structured_logging.html
-
-version: 1
-
-formatters:
-    precise:
-        format: '%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s'
-
-handlers:
-    # A handler that writes logs to stderr. Unused by default, but can be used
-    # instead of "buffer" and "file" in the logger handlers.
-    console:
-        class: logging.StreamHandler
-        formatter: precise
-
-loggers:
-    synapse.storage.SQL:
-        # beware: increasing this to DEBUG will make synapse log sensitive
-        # information such as access tokens.
-        level: DEBUG
-
-    twisted:
-        # We send the twisted logging directly to the file handler,
-        # to work around https://github.com/matrix-org/synapse/issues/3471
-        # when using "buffer" logger. Use "console" to log to stderr instead.
-        handlers: [console]
-        propagate: false
-
-root:
-    level: DEBUG
-
-    # Write logs to the `buffer` handler, which will buffer them together in memory,
-    # then write them to a file.
-    #
-    # Replace "buffer" with "console" to log to stderr instead. (Note that you'll
-    # also need to update the configuration for the `twisted` logger above, in
-    # this case.)
-    #
-    handlers: [console]
-
-disable_existing_loggers: false
diff --git a/playwright/plugins/homeserver/synapse/templates/dehydration/README.md b/playwright/plugins/homeserver/synapse/templates/dehydration/README.md
deleted file mode 100644
index 18f7923e6d2..00000000000
--- a/playwright/plugins/homeserver/synapse/templates/dehydration/README.md
+++ /dev/null
@@ -1 +0,0 @@
-A synapse configured with device dehydration v2 enabled
diff --git a/playwright/plugins/homeserver/synapse/templates/dehydration/homeserver.yaml b/playwright/plugins/homeserver/synapse/templates/dehydration/homeserver.yaml
deleted file mode 100644
index c3ac5d6536c..00000000000
--- a/playwright/plugins/homeserver/synapse/templates/dehydration/homeserver.yaml
+++ /dev/null
@@ -1,102 +0,0 @@
-server_name: "localhost"
-pid_file: /data/homeserver.pid
-public_baseurl: "{{PUBLIC_BASEURL}}"
-listeners:
-    - port: 8008
-      tls: false
-      bind_addresses: ["::"]
-      type: http
-      x_forwarded: true
-
-      resources:
-          - names: [client]
-            compress: false
-
-database:
-    name: "sqlite3"
-    args:
-        database: ":memory:"
-
-log_config: "/data/log.config"
-
-rc_messages_per_second: 10000
-rc_message_burst_count: 10000
-rc_registration:
-    per_second: 10000
-    burst_count: 10000
-rc_joins:
-    local:
-        per_second: 9999
-        burst_count: 9999
-    remote:
-        per_second: 9999
-        burst_count: 9999
-rc_joins_per_room:
-    per_second: 9999
-    burst_count: 9999
-rc_3pid_validation:
-    per_second: 1000
-    burst_count: 1000
-
-rc_invites:
-    per_room:
-        per_second: 1000
-        burst_count: 1000
-    per_user:
-        per_second: 1000
-        burst_count: 1000
-
-rc_login:
-    address:
-        per_second: 10000
-        burst_count: 10000
-    account:
-        per_second: 10000
-        burst_count: 10000
-    failed_attempts:
-        per_second: 10000
-        burst_count: 10000
-
-media_store_path: "/data/media_store"
-uploads_path: "/data/uploads"
-enable_registration: true
-enable_registration_without_verification: true
-disable_msisdn_registration: false
-registration_shared_secret: "{{REGISTRATION_SECRET}}"
-report_stats: false
-macaroon_secret_key: "{{MACAROON_SECRET_KEY}}"
-form_secret: "{{FORM_SECRET}}"
-signing_key_path: "/data/localhost.signing.key"
-
-trusted_key_servers:
-    - server_name: "matrix.org"
-suppress_key_server_warning: true
-
-ui_auth:
-    session_timeout: "300s"
-
-oidc_providers:
-    - idp_id: test
-      idp_name: "OAuth test"
-      issuer: "http://localhost:{{OAUTH_SERVER_PORT}}/oauth"
-      authorization_endpoint: "http://localhost:{{OAUTH_SERVER_PORT}}/oauth/auth.html"
-      # the token endpoint receives requests from synapse, rather than the webapp, so needs to escape the docker container.
-      token_endpoint: "http://host.containers.internal:{{OAUTH_SERVER_PORT}}/oauth/token"
-      userinfo_endpoint: "http://host.containers.internal:{{OAUTH_SERVER_PORT}}/oauth/userinfo"
-      client_id: "synapse"
-      discover: false
-      scopes: ["profile"]
-      skip_verification: true
-      client_auth_method: none
-      user_mapping_provider:
-          config:
-              display_name_template: "{{ user.name }}"
-
-# Inhibit background updates as this Synapse isn't long-lived
-background_updates:
-    min_batch_size: 100000
-    sleep_duration_ms: 100000
-
-experimental_features:
-    msc2697_enabled: false
-    msc3814_enabled: true
diff --git a/playwright/plugins/homeserver/synapse/templates/dehydration/log.config b/playwright/plugins/homeserver/synapse/templates/dehydration/log.config
deleted file mode 100644
index b9123d0f5b9..00000000000
--- a/playwright/plugins/homeserver/synapse/templates/dehydration/log.config
+++ /dev/null
@@ -1,50 +0,0 @@
-# Log configuration for Synapse.
-#
-# This is a YAML file containing a standard Python logging configuration
-# dictionary. See [1] for details on the valid settings.
-#
-# Synapse also supports structured logging for machine readable logs which can
-# be ingested by ELK stacks. See [2] for details.
-#
-# [1]: https://docs.python.org/3.7/library/logging.config.html#configuration-dictionary-schema
-# [2]: https://matrix-org.github.io/synapse/latest/structured_logging.html
-
-version: 1
-
-formatters:
-    precise:
-        format: '%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s'
-
-handlers:
-    # A handler that writes logs to stderr. Unused by default, but can be used
-    # instead of "buffer" and "file" in the logger handlers.
-    console:
-        class: logging.StreamHandler
-        formatter: precise
-
-loggers:
-    synapse.storage.SQL:
-        # beware: increasing this to DEBUG will make synapse log sensitive
-        # information such as access tokens.
-        level: DEBUG
-
-    twisted:
-        # We send the twisted logging directly to the file handler,
-        # to work around https://github.com/matrix-org/synapse/issues/3471
-        # when using "buffer" logger. Use "console" to log to stderr instead.
-        handlers: [console]
-        propagate: false
-
-root:
-    level: DEBUG
-
-    # Write logs to the `buffer` handler, which will buffer them together in memory,
-    # then write them to a file.
-    #
-    # Replace "buffer" with "console" to log to stderr instead. (Note that you'll
-    # also need to update the configuration for the `twisted` logger above, in
-    # this case.)
-    #
-    handlers: [console]
-
-disable_existing_loggers: false
diff --git a/playwright/plugins/homeserver/synapse/templates/email/README.md b/playwright/plugins/homeserver/synapse/templates/email/README.md
deleted file mode 100644
index 40c23ba0be4..00000000000
--- a/playwright/plugins/homeserver/synapse/templates/email/README.md
+++ /dev/null
@@ -1 +0,0 @@
-A synapse configured to require an email for registration
diff --git a/playwright/plugins/homeserver/synapse/templates/email/homeserver.yaml b/playwright/plugins/homeserver/synapse/templates/email/homeserver.yaml
deleted file mode 100644
index fc20641ab40..00000000000
--- a/playwright/plugins/homeserver/synapse/templates/email/homeserver.yaml
+++ /dev/null
@@ -1,44 +0,0 @@
-server_name: "localhost"
-pid_file: /data/homeserver.pid
-public_baseurl: "{{PUBLIC_BASEURL}}"
-listeners:
-    - port: 8008
-      tls: false
-      bind_addresses: ["::"]
-      type: http
-      x_forwarded: true
-
-      resources:
-          - names: [client]
-            compress: false
-
-database:
-    name: "sqlite3"
-    args:
-        database: ":memory:"
-
-log_config: "/data/log.config"
-
-media_store_path: "/data/media_store"
-uploads_path: "/data/uploads"
-enable_registration: true
-registrations_require_3pid:
-    - email
-registration_shared_secret: "{{REGISTRATION_SECRET}}"
-report_stats: false
-macaroon_secret_key: "{{MACAROON_SECRET_KEY}}"
-form_secret: "{{FORM_SECRET}}"
-signing_key_path: "/data/localhost.signing.key"
-
-trusted_key_servers:
-    - server_name: "matrix.org"
-suppress_key_server_warning: true
-
-ui_auth:
-    session_timeout: "300s"
-
-email:
-    smtp_host: "%SMTP_HOST%"
-    smtp_port: %SMTP_PORT%
-    notif_from: "Your Friendly %(app)s homeserver <noreply@example.com>"
-    app_name: my_branded_matrix_server
diff --git a/playwright/plugins/homeserver/synapse/templates/email/log.config b/playwright/plugins/homeserver/synapse/templates/email/log.config
deleted file mode 100644
index ac232762da3..00000000000
--- a/playwright/plugins/homeserver/synapse/templates/email/log.config
+++ /dev/null
@@ -1,50 +0,0 @@
-# Log configuration for Synapse.
-#
-# This is a YAML file containing a standard Python logging configuration
-# dictionary. See [1] for details on the valid settings.
-#
-# Synapse also supports structured logging for machine readable logs which can
-# be ingested by ELK stacks. See [2] for details.
-#
-# [1]: https://docs.python.org/3.7/library/logging.config.html#configuration-dictionary-schema
-# [2]: https://matrix-org.github.io/synapse/latest/structured_logging.html
-
-version: 1
-
-formatters:
-    precise:
-        format: '%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s'
-
-handlers:
-    # A handler that writes logs to stderr. Unused by default, but can be used
-    # instead of "buffer" and "file" in the logger handlers.
-    console:
-        class: logging.StreamHandler
-        formatter: precise
-
-loggers:
-    synapse.storage.SQL:
-        # beware: increasing this to DEBUG will make synapse log sensitive
-        # information such as access tokens.
-        level: INFO
-
-    twisted:
-        # We send the twisted logging directly to the file handler,
-        # to work around https://github.com/matrix-org/synapse/issues/3471
-        # when using "buffer" logger. Use "console" to log to stderr instead.
-        handlers: [console]
-        propagate: false
-
-root:
-    level: INFO
-
-    # Write logs to the `buffer` handler, which will buffer them together in memory,
-    # then write them to a file.
-    #
-    # Replace "buffer" with "console" to log to stderr instead. (Note that you'll
-    # also need to update the configuration for the `twisted` logger above, in
-    # this case.)
-    #
-    handlers: [console]
-
-disable_existing_loggers: false
diff --git a/playwright/plugins/homeserver/synapse/templates/guest-enabled/README.md b/playwright/plugins/homeserver/synapse/templates/guest-enabled/README.md
deleted file mode 100644
index e1fef0b9d41..00000000000
--- a/playwright/plugins/homeserver/synapse/templates/guest-enabled/README.md
+++ /dev/null
@@ -1 +0,0 @@
-A synapse configured with guest registration enabled.
diff --git a/playwright/plugins/homeserver/synapse/templates/guest-enabled/homeserver.yaml b/playwright/plugins/homeserver/synapse/templates/guest-enabled/homeserver.yaml
deleted file mode 100644
index 1faa39c3a74..00000000000
--- a/playwright/plugins/homeserver/synapse/templates/guest-enabled/homeserver.yaml
+++ /dev/null
@@ -1,105 +0,0 @@
-server_name: "localhost"
-pid_file: /data/homeserver.pid
-public_baseurl: "{{PUBLIC_BASEURL}}"
-listeners:
-    - port: 8008
-      tls: false
-      bind_addresses: ["::"]
-      type: http
-      x_forwarded: true
-
-      resources:
-          - names: [client]
-            compress: false
-
-database:
-    name: "sqlite3"
-    args:
-        database: ":memory:"
-
-log_config: "/data/log.config"
-
-rc_messages_per_second: 10000
-rc_message_burst_count: 10000
-rc_registration:
-    per_second: 10000
-    burst_count: 10000
-rc_joins:
-    local:
-        per_second: 9999
-        burst_count: 9999
-    remote:
-        per_second: 9999
-        burst_count: 9999
-rc_joins_per_room:
-    per_second: 9999
-    burst_count: 9999
-rc_3pid_validation:
-    per_second: 1000
-    burst_count: 1000
-
-rc_invites:
-    per_room:
-        per_second: 1000
-        burst_count: 1000
-    per_user:
-        per_second: 1000
-        burst_count: 1000
-
-rc_login:
-    address:
-        per_second: 10000
-        burst_count: 10000
-    account:
-        per_second: 10000
-        burst_count: 10000
-    failed_attempts:
-        per_second: 10000
-        burst_count: 10000
-
-media_store_path: "/data/media_store"
-uploads_path: "/data/uploads"
-allow_guest_access: true
-enable_registration: true
-enable_registration_without_verification: true
-disable_msisdn_registration: false
-registration_shared_secret: "{{REGISTRATION_SECRET}}"
-report_stats: false
-macaroon_secret_key: "{{MACAROON_SECRET_KEY}}"
-form_secret: "{{FORM_SECRET}}"
-signing_key_path: "/data/localhost.signing.key"
-
-trusted_key_servers:
-    - server_name: "matrix.org"
-suppress_key_server_warning: true
-
-ui_auth:
-    session_timeout: "300s"
-
-oidc_providers:
-    - idp_id: test
-      idp_name: "OAuth test"
-      issuer: "http://localhost:{{OAUTH_SERVER_PORT}}/oauth"
-      authorization_endpoint: "http://localhost:{{OAUTH_SERVER_PORT}}/oauth/auth.html"
-      # the token endpoint receives requests from synapse, rather than the webapp, so needs to escape the docker container.
-      token_endpoint: "http://host.containers.internal:{{OAUTH_SERVER_PORT}}/oauth/token"
-      userinfo_endpoint: "http://host.containers.internal:{{OAUTH_SERVER_PORT}}/oauth/userinfo"
-      client_id: "synapse"
-      discover: false
-      scopes: ["profile"]
-      skip_verification: true
-      client_auth_method: none
-      user_mapping_provider:
-          config:
-              display_name_template: "{{ user.name }}"
-
-# Inhibit background updates as this Synapse isn't long-lived
-background_updates:
-    min_batch_size: 100000
-    sleep_duration_ms: 100000
-
-experimental_features:
-    # Needed for e2e/crypto/crypto.spec.ts > Cryptography > decryption failure
-    # messages > non-joined historical messages.
-    # Can be removed after Synapse enables it by default
-    msc4115_membership_on_events: true
diff --git a/playwright/plugins/homeserver/synapse/templates/guest-enabled/log.config b/playwright/plugins/homeserver/synapse/templates/guest-enabled/log.config
deleted file mode 100644
index ac232762da3..00000000000
--- a/playwright/plugins/homeserver/synapse/templates/guest-enabled/log.config
+++ /dev/null
@@ -1,50 +0,0 @@
-# Log configuration for Synapse.
-#
-# This is a YAML file containing a standard Python logging configuration
-# dictionary. See [1] for details on the valid settings.
-#
-# Synapse also supports structured logging for machine readable logs which can
-# be ingested by ELK stacks. See [2] for details.
-#
-# [1]: https://docs.python.org/3.7/library/logging.config.html#configuration-dictionary-schema
-# [2]: https://matrix-org.github.io/synapse/latest/structured_logging.html
-
-version: 1
-
-formatters:
-    precise:
-        format: '%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s'
-
-handlers:
-    # A handler that writes logs to stderr. Unused by default, but can be used
-    # instead of "buffer" and "file" in the logger handlers.
-    console:
-        class: logging.StreamHandler
-        formatter: precise
-
-loggers:
-    synapse.storage.SQL:
-        # beware: increasing this to DEBUG will make synapse log sensitive
-        # information such as access tokens.
-        level: INFO
-
-    twisted:
-        # We send the twisted logging directly to the file handler,
-        # to work around https://github.com/matrix-org/synapse/issues/3471
-        # when using "buffer" logger. Use "console" to log to stderr instead.
-        handlers: [console]
-        propagate: false
-
-root:
-    level: INFO
-
-    # Write logs to the `buffer` handler, which will buffer them together in memory,
-    # then write them to a file.
-    #
-    # Replace "buffer" with "console" to log to stderr instead. (Note that you'll
-    # also need to update the configuration for the `twisted` logger above, in
-    # this case.)
-    #
-    handlers: [console]
-
-disable_existing_loggers: false
diff --git a/playwright/plugins/homeserver/synapse/templates/mas-oidc/README.md b/playwright/plugins/homeserver/synapse/templates/mas-oidc/README.md
deleted file mode 100644
index 223ff436a8d..00000000000
--- a/playwright/plugins/homeserver/synapse/templates/mas-oidc/README.md
+++ /dev/null
@@ -1 +0,0 @@
-A synapse configured with auth delegated to via matrix authentication service
diff --git a/playwright/plugins/homeserver/synapse/templates/mas-oidc/homeserver.yaml b/playwright/plugins/homeserver/synapse/templates/mas-oidc/homeserver.yaml
deleted file mode 100644
index 802d97acade..00000000000
--- a/playwright/plugins/homeserver/synapse/templates/mas-oidc/homeserver.yaml
+++ /dev/null
@@ -1,194 +0,0 @@
-server_name: "localhost"
-pid_file: /data/homeserver.pid
-public_baseurl: "{{PUBLIC_BASEURL}}"
-listeners:
-    - port: 8008
-      tls: false
-      bind_addresses: ["::"]
-      type: http
-      x_forwarded: true
-
-      resources:
-          - names: [client]
-            compress: false
-
-database:
-    name: "sqlite3"
-    args:
-        database: ":memory:"
-
-log_config: "/data/log.config"
-
-rc_messages_per_second: 10000
-rc_message_burst_count: 10000
-rc_registration:
-    per_second: 10000
-    burst_count: 10000
-rc_joins:
-    local:
-        per_second: 9999
-        burst_count: 9999
-    remote:
-        per_second: 9999
-        burst_count: 9999
-rc_joins_per_room:
-    per_second: 9999
-    burst_count: 9999
-rc_3pid_validation:
-    per_second: 1000
-    burst_count: 1000
-
-rc_invites:
-    per_room:
-        per_second: 1000
-        burst_count: 1000
-    per_user:
-        per_second: 1000
-        burst_count: 1000
-
-rc_login:
-    address:
-        per_second: 10000
-        burst_count: 10000
-    account:
-        per_second: 10000
-        burst_count: 10000
-    failed_attempts:
-        per_second: 10000
-        burst_count: 10000
-
-media_store_path: "/data/media_store"
-uploads_path: "/data/uploads"
-registration_shared_secret: "{{REGISTRATION_SECRET}}"
-report_stats: false
-macaroon_secret_key: "{{MACAROON_SECRET_KEY}}"
-form_secret: "{{FORM_SECRET}}"
-signing_key_path: "/data/localhost.signing.key"
-
-trusted_key_servers:
-    - server_name: "matrix.org"
-suppress_key_server_warning: true
-
-ui_auth:
-    session_timeout: "300s"
-
-# Inhibit background updates as this Synapse isn't long-lived
-background_updates:
-    min_batch_size: 100000
-    sleep_duration_ms: 100000
-
-serve_server_wellknown: true
-experimental_features:
-    msc3861:
-        enabled: true
-
-        issuer: http://localhost:%MAS_PORT%/
-        # We have to bake in the metadata here as we need to override `introspection_endpoint`
-        issuer_metadata: {
-                "issuer": "http://localhost:%MAS_PORT%/",
-                "authorization_endpoint": "http://localhost:%MAS_PORT%/authorize",
-                "token_endpoint": "http://localhost:%MAS_PORT%/oauth2/token",
-                "jwks_uri": "http://localhost:%MAS_PORT%/oauth2/keys.json",
-                "registration_endpoint": "http://localhost:%MAS_PORT%/oauth2/registration",
-                "scopes_supported": ["openid", "email"],
-                "response_types_supported": ["code", "id_token", "code id_token"],
-                "response_modes_supported": ["form_post", "query", "fragment"],
-                "grant_types_supported":
-                    [
-                        "authorization_code",
-                        "refresh_token",
-                        "client_credentials",
-                        "urn:ietf:params:oauth:grant-type:device_code",
-                    ],
-                "token_endpoint_auth_methods_supported":
-                    ["client_secret_basic", "client_secret_post", "client_secret_jwt", "private_key_jwt", "none"],
-                "token_endpoint_auth_signing_alg_values_supported":
-                    [
-                        "HS256",
-                        "HS384",
-                        "HS512",
-                        "RS256",
-                        "RS384",
-                        "RS512",
-                        "PS256",
-                        "PS384",
-                        "PS512",
-                        "ES256",
-                        "ES384",
-                        "ES256K",
-                    ],
-                "revocation_endpoint": "http://localhost:%MAS_PORT%/oauth2/revoke",
-                "revocation_endpoint_auth_methods_supported":
-                    ["client_secret_basic", "client_secret_post", "client_secret_jwt", "private_key_jwt", "none"],
-                "revocation_endpoint_auth_signing_alg_values_supported":
-                    [
-                        "HS256",
-                        "HS384",
-                        "HS512",
-                        "RS256",
-                        "RS384",
-                        "RS512",
-                        "PS256",
-                        "PS384",
-                        "PS512",
-                        "ES256",
-                        "ES384",
-                        "ES256K",
-                    ],
-                # This is the only changed value
-                "introspection_endpoint": "http://host.containers.internal:%MAS_PORT%/oauth2/introspect",
-                "introspection_endpoint_auth_methods_supported":
-                    ["client_secret_basic", "client_secret_post", "client_secret_jwt", "private_key_jwt", "none"],
-                "introspection_endpoint_auth_signing_alg_values_supported":
-                    [
-                        "HS256",
-                        "HS384",
-                        "HS512",
-                        "RS256",
-                        "RS384",
-                        "RS512",
-                        "PS256",
-                        "PS384",
-                        "PS512",
-                        "ES256",
-                        "ES384",
-                        "ES256K",
-                    ],
-                "code_challenge_methods_supported": ["plain", "S256"],
-                "userinfo_endpoint": "http://localhost:%MAS_PORT%/oauth2/userinfo",
-                "subject_types_supported": ["public"],
-                "id_token_signing_alg_values_supported":
-                    ["RS256", "RS384", "RS512", "ES256", "ES384", "PS256", "PS384", "PS512", "ES256K"],
-                "userinfo_signing_alg_values_supported":
-                    ["RS256", "RS384", "RS512", "ES256", "ES384", "PS256", "PS384", "PS512", "ES256K"],
-                "display_values_supported": ["page"],
-                "claim_types_supported": ["normal"],
-                "claims_supported": ["iss", "sub", "aud", "iat", "exp", "nonce", "auth_time", "at_hash", "c_hash"],
-                "claims_parameter_supported": false,
-                "request_parameter_supported": false,
-                "request_uri_parameter_supported": false,
-                "prompt_values_supported": ["none", "login", "create"],
-                "device_authorization_endpoint": "http://localhost:%MAS_PORT%/oauth2/device",
-                "org.matrix.matrix-authentication-service.graphql_endpoint": "http://localhost:%MAS_PORT%/graphql",
-                "account_management_uri": "http://localhost:%MAS_PORT%/account/",
-                "account_management_actions_supported":
-                    [
-                        "org.matrix.profile",
-                        "org.matrix.sessions_list",
-                        "org.matrix.session_view",
-                        "org.matrix.session_end",
-                    ],
-            }
-
-        # Matches the `client_id` in the auth service config
-        client_id: 0000000000000000000SYNAPSE
-        # Matches the `client_auth_method` in the auth service config
-        client_auth_method: client_secret_basic
-        # Matches the `client_secret` in the auth service config
-        client_secret: "SomeRandomSecret"
-
-        # Matches the `matrix.secret` in the auth service config
-        admin_token: "AnotherRandomSecret"
-
-        # URL to advertise to clients where users can self-manage their account
-        account_management_url: "http://localhost:%MAS_PORT%/account"
diff --git a/playwright/plugins/homeserver/synapse/templates/mas-oidc/log.config b/playwright/plugins/homeserver/synapse/templates/mas-oidc/log.config
deleted file mode 100644
index b9123d0f5b9..00000000000
--- a/playwright/plugins/homeserver/synapse/templates/mas-oidc/log.config
+++ /dev/null
@@ -1,50 +0,0 @@
-# Log configuration for Synapse.
-#
-# This is a YAML file containing a standard Python logging configuration
-# dictionary. See [1] for details on the valid settings.
-#
-# Synapse also supports structured logging for machine readable logs which can
-# be ingested by ELK stacks. See [2] for details.
-#
-# [1]: https://docs.python.org/3.7/library/logging.config.html#configuration-dictionary-schema
-# [2]: https://matrix-org.github.io/synapse/latest/structured_logging.html
-
-version: 1
-
-formatters:
-    precise:
-        format: '%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s'
-
-handlers:
-    # A handler that writes logs to stderr. Unused by default, but can be used
-    # instead of "buffer" and "file" in the logger handlers.
-    console:
-        class: logging.StreamHandler
-        formatter: precise
-
-loggers:
-    synapse.storage.SQL:
-        # beware: increasing this to DEBUG will make synapse log sensitive
-        # information such as access tokens.
-        level: DEBUG
-
-    twisted:
-        # We send the twisted logging directly to the file handler,
-        # to work around https://github.com/matrix-org/synapse/issues/3471
-        # when using "buffer" logger. Use "console" to log to stderr instead.
-        handlers: [console]
-        propagate: false
-
-root:
-    level: DEBUG
-
-    # Write logs to the `buffer` handler, which will buffer them together in memory,
-    # then write them to a file.
-    #
-    # Replace "buffer" with "console" to log to stderr instead. (Note that you'll
-    # also need to update the configuration for the `twisted` logger above, in
-    # this case.)
-    #
-    handlers: [console]
-
-disable_existing_loggers: false
diff --git a/playwright/plugins/homeserver/synapse/uiaLongSessionTimeoutHomeserver.ts b/playwright/plugins/homeserver/synapse/uiaLongSessionTimeoutHomeserver.ts
new file mode 100644
index 00000000000..87d2a0f752d
--- /dev/null
+++ b/playwright/plugins/homeserver/synapse/uiaLongSessionTimeoutHomeserver.ts
@@ -0,0 +1,22 @@
+/*
+Copyright 2024 New Vector Ltd.
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+Please see LICENSE files in the repository root for full details.
+*/
+
+import { Fixtures } from "../../../element-web-test.ts";
+
+export const uiaLongSessionTimeoutHomeserver: Fixtures = {
+    synapseConfig: [
+        async ({ synapseConfig }, use) => {
+            await use({
+                ...synapseConfig,
+                ui_auth: {
+                    session_timeout: "300s",
+                },
+            });
+        },
+        { scope: "worker" },
+    ],
+};
diff --git a/playwright/plugins/mailhog/index.ts b/playwright/plugins/mailhog/index.ts
deleted file mode 100644
index e9e5f08b717..00000000000
--- a/playwright/plugins/mailhog/index.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2023 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
-Please see LICENSE files in the repository root for full details.
-*/
-
-import mailhog from "mailhog";
-
-import { getFreePort } from "../utils/port";
-import { Docker } from "../docker";
-
-export interface Instance {
-    host: string;
-    smtpPort: number;
-    httpPort: number;
-    containerId: string;
-}
-
-export class MailHogServer {
-    private readonly docker: Docker = new Docker();
-    private instance?: Instance;
-
-    async start(): Promise<{ api: mailhog.API; instance: Instance }> {
-        if (this.instance) throw new Error("Mailhog server is already running!");
-        const smtpPort = await getFreePort();
-        const httpPort = await getFreePort();
-        console.log(`Starting mailhog...`);
-        const containerId = await this.docker.run({
-            image: "mailhog/mailhog:latest",
-            containerName: `react-sdk-playwright-mailhog`,
-            params: ["-p", `${smtpPort}:1025/tcp`, "-p", `${httpPort}:8025/tcp`],
-        });
-        console.log(`Started mailhog on ports smtp=${smtpPort} http=${httpPort}.`);
-        const host = await this.docker.getContainerIp();
-        this.instance = { smtpPort, httpPort, containerId, host };
-        return { api: mailhog({ host: "localhost", port: httpPort }), instance: this.instance };
-    }
-
-    async stop(): Promise<void> {
-        if (!this.instance) throw new Error("Missing existing mailhog instance, did you call stop() before start()?");
-        await this.docker.stop();
-        console.log(`Stopped mailhog id ${this.instance.containerId}.`);
-        this.instance = undefined;
-    }
-}
diff --git a/playwright/plugins/matrix-authentication-service/config.yaml b/playwright/plugins/matrix-authentication-service/config.yaml
deleted file mode 100644
index e7ab83e736e..00000000000
--- a/playwright/plugins/matrix-authentication-service/config.yaml
+++ /dev/null
@@ -1,153 +0,0 @@
-clients:
-    - client_id: 0000000000000000000SYNAPSE
-      client_auth_method: client_secret_basic
-      client_secret: "SomeRandomSecret"
-http:
-    listeners:
-        - name: web
-          resources:
-              - name: discovery
-              - name: human
-              - name: oauth
-              - name: compat
-              - name: graphql
-                playground: true
-              - name: assets
-                path: /usr/local/share/mas-cli/assets/
-          binds:
-              - address: "[::]:8080"
-          proxy_protocol: false
-        - name: internal
-          resources:
-              - name: health
-          binds:
-              - host: localhost
-                port: 8081
-          proxy_protocol: false
-    trusted_proxies:
-        - 192.128.0.0/16
-        - 172.16.0.0/12
-        - 10.0.0.0/10
-        - 127.0.0.1/8
-        - fd00::/8
-        - ::1/128
-    public_base: "http://localhost:{{MAS_PORT}}/"
-    issuer: http://localhost:{{MAS_PORT}}/
-database:
-    host: "{{POSTGRES_HOST}}"
-    port: 5432
-    database: postgres
-    username: postgres
-    password: "{{POSTGRES_PASSWORD}}"
-    max_connections: 10
-    min_connections: 0
-    connect_timeout: 30
-    idle_timeout: 600
-    max_lifetime: 1800
-telemetry:
-    tracing:
-        exporter: none
-        propagators: []
-    metrics:
-        exporter: none
-    sentry:
-        dsn: null
-templates:
-    path: /usr/local/share/mas-cli/templates/
-    assets_manifest: /usr/local/share/mas-cli/manifest.json
-    translations_path: /usr/local/share/mas-cli/translations/
-email:
-    from: '"Authentication Service" <root@localhost>'
-    reply_to: '"Authentication Service" <root@localhost>'
-    transport: smtp
-    mode: plain
-    hostname: "host.containers.internal"
-    port: %{{SMTP_PORT}}
-    username: username
-    password: password
-
-secrets:
-    encryption: 984b18e207c55ad5fbb2a49b217481a722917ee87b2308d4cf314c83fed8e3b5
-    keys:
-        - kid: YEAhzrKipJ
-          key: |
-              -----BEGIN RSA PRIVATE KEY-----
-              MIIEowIBAAKCAQEAuIV+AW5vx52I4CuumgSxp6yvKfIAnRdALeZZCoFkIGxUli1B
-              S79NJ3ls46oLh1pSD9RrhaMp6HTNoi4K3hnP9Q9v77pD7KwdFKG3UdG1zksIB0s/
-              +/Ey/DmX4LPluwBBS7r/LkQ1jk745lENA++oiDqZf2D/uP8jCHlvaSNyVKTqi1ki
-              OXPd4T4xBUjzuas9ze5jQVSYtfOidgnv1EzUipbIxgvH1jNt4raRlmP8mOq7xEnW
-              R+cF5x6n/g17PdSEfrwO4kz6aKGZuMP5lVlDEEnMHKabFSQDBl7+Mpok6jXutbtA
-              uiBnsKEahF9eoj4na4fpbRNPdIVyoaN5eGvm5wIDAQABAoIBAApyFCYEmHNWaa83
-              CdVSOrRhRDE9r+c0r79pcNT1ajOjrk4qFa4yEC4R46YntCtfY5Hd1pBkIjU0l4d8
-              z8Su9WTMEOwjQUEepS7L0NLi6kXZXYT8L40VpGs+32grBvBFHW0qEtQNrHJ36gMv
-              x2rXoFTF7HaXiSJx3wvVxAbRqOE9tBXLsmNHaWaAdWQG5o77V9+zvMri3cAeEg2w
-              VkKokb0dza7es7xG3tqS26k69SrwGeeuKo7qCHPH2cfyWmY5Yhv8iOoA59JzzbiK
-              UdxyzCHskrPSpRKVkVVwmY3RBt282TmSRG7td7e5ESSj50P2e5BI5uu1Hp/dvU4F
-              vYjV7kECgYEA6WqYoUpVsgQiqhvJwJIc/8gRm0mUy8TenI36z4Iim01Nt7fibWH7
-              XnsFqLGjXtYNVWvBcCrUl9doEnRbJeG2eRGbGKYAWVrOeFvwM4fYvw9GoOiJdDj4
-              cgWDe7eHbHE+UTqR7Nnr/UBfipoNWDh6X68HRBuXowh0Q6tOfxsrRFECgYEAyl/V
-              4b8bFp3pKZZCb+KPSYsQf793cRmrBexPcLWcDPYbMZQADEZ/VLjbrNrpTOWxUWJT
-              hr8MrWswnHO+l5AFu5CNO+QgV2dHLk+2w8qpdpFRPJCfXfo2D3wZ0c4cv3VCwv1V
-              5y7f6XWVjDWZYV4wj6c3shxZJjZ+9Hbhf3/twbcCgYA6fuRRR3fCbRbi2qPtBrEN
-              yO3gpMgNaQEA6vP4HPzfPrhDWmn8T5nXS61XYW03zxz4U1De81zj0K/cMBzHmZFJ
-              NghQXQmpWwBzWVcREvJWr1Vb7erEnaJlsMwKrSvbGWYspSj82oAxr3hCG+lMOpsw
-              b4S6pM+TpAK/EqdRY1WsgQKBgQCGoMaaTRXqL9bC0bEU2XVVCWxKb8c3uEmrwQ7/
-              /fD4NmjUzI5TnDps1CVfkqoNe+hAKddDFqmKXHqUOfOaxDbsFje+lf5l5tDVoDYH
-              fjTKKdYPIm7CiAeauYY7qpA5Vfq52Opixy4yEwUPp0CII67OggFtPaqY3zwJyWQt
-              +57hdQKBgGCXM/KKt7ceUDcNJxSGjvu0zD9D5Sv2ihYlEBT/JLaTCCJdvzREevaJ
-              1d+mpUAt0Lq6A8NWOMq8HPaxAik3rMQ0WtM5iG+XgsUqvTSb7NcshArDLuWGnW3m
-              MC4rM0UBYAS4QweduUSH1imrwH/1Gu5+PxbiecceRMMggWpzu0Bq
-              -----END RSA PRIVATE KEY-----
-        - kid: 8J1AxrlNZT
-          key: |
-              -----BEGIN EC PRIVATE KEY-----
-              MHcCAQEEIF1cjfIOEdy3BXJ72x6fKpEB8WP1ddZAUJAaqqr/6CpToAoGCCqGSM49
-              AwEHoUQDQgAEfHdNuI1Yeh3/uOq2PlnW2vymloOVpwBYebbw4VVsna9xhnutIdQW
-              dE8hkX8Yb0pIDasrDiwllVLzSvsWJAI0Kw==
-              -----END EC PRIVATE KEY-----
-        - kid: 3BW6un1EBi
-          key: |
-              -----BEGIN EC PRIVATE KEY-----
-              MIGkAgEBBDA+3ZV17r8TsiMdw1cpbTSNbyEd5SMy3VS1Mk/kz6O2Ev/3QZut8GE2
-              q3eGtLBoVQigBwYFK4EEACKhZANiAASs8Wxjk/uRimRKXnPr2/wDaXkN9wMDjYQK
-              mZULb+0ZP1/cXmuXuri8hUGhQvIU8KWY9PkpV+LMPEdpE54mHPKSLjq5CDXoSZ/P
-              9f7cdRaOZ000KQPZfIFR9ujJTtDN7Vs=
-              -----END EC PRIVATE KEY-----
-        - kid: pkZ0pTKK0X
-          key: |
-              -----BEGIN EC PRIVATE KEY-----
-              MHQCAQEEIHenfsXYPc5yzjZKUfvmydDR1YRwdsfZYvwHf/2wsYxooAcGBSuBBAAK
-              oUQDQgAEON1x7Vlu+nA0KvC5vYSOHhDUkfLYNZwYSLPFVT02h9E13yFFMIJegIBl
-              Aer+6PMZpPc8ycyeH9N+U9NAyliBhQ==
-              -----END EC PRIVATE KEY-----
-passwords:
-    enabled: true
-    schemes:
-        - version: 1
-          algorithm: argon2id
-matrix:
-    homeserver: localhost
-    secret: AnotherRandomSecret
-    endpoint: "{{SYNAPSE_URL}}"
-policy:
-    wasm_module: /usr/local/share/mas-cli/policy.wasm
-    client_registration_entrypoint: client_registration/violation
-    register_entrypoint: register/violation
-    authorization_grant_entrypoint: authorization_grant/violation
-    password_entrypoint: password/violation
-    email_entrypoint: email/violation
-    data:
-        client_registration:
-            allow_insecure_uris: true # allow non-SSL and localhost URIs
-            allow_missing_contacts: true # EW doesn't have contacts at this time
-upstream_oauth2:
-    providers: []
-branding:
-    service_name: null
-    policy_uri: null
-    tos_uri: null
-    imprint: null
-    logo_uri: null
-experimental:
-    access_token_ttl: 300
-    compat_token_ttl: 300
diff --git a/playwright/plugins/matrix-authentication-service/index.ts b/playwright/plugins/matrix-authentication-service/index.ts
deleted file mode 100644
index eaad350b829..00000000000
--- a/playwright/plugins/matrix-authentication-service/index.ts
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2023 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
-Please see LICENSE files in the repository root for full details.
-*/
-
-import path, { basename } from "node:path";
-import os from "node:os";
-import * as fse from "fs-extra";
-import { BrowserContext, TestInfo } from "@playwright/test";
-
-import { getFreePort } from "../utils/port";
-import { Docker } from "../docker";
-import { PG_PASSWORD, PostgresDocker } from "../postgres";
-import { HomeserverInstance } from "../homeserver";
-import { Instance as MailhogInstance } from "../mailhog";
-
-// Docker tag to use for `ghcr.io/matrix-org/matrix-authentication-service` image.
-// We use a debug tag so that we have a shell and can run all 3 necessary commands in one run.
-const TAG = "0.8.0-debug";
-
-export interface ProxyInstance {
-    containerId: string;
-    postgresId: string;
-    configDir: string;
-    port: number;
-}
-
-async function cfgDirFromTemplate(opts: {
-    postgresHost: string;
-    synapseUrl: string;
-    masPort: string;
-    smtpPort: string;
-}): Promise<{
-    configDir: string;
-}> {
-    const configPath = path.join(__dirname, "config.yaml");
-    const tempDir = await fse.mkdtemp(path.join(os.tmpdir(), "react-sdk-mas-"));
-
-    const outputHomeserver = path.join(tempDir, "config.yaml");
-    console.log(`Gen ${configPath} -> ${outputHomeserver}`);
-    let config = await fse.readFile(configPath, "utf8");
-    config = config.replace(/{{MAS_PORT}}/g, opts.masPort);
-    config = config.replace(/{{POSTGRES_HOST}}/g, opts.postgresHost);
-    config = config.replace(/{{POSTGRES_PASSWORD}}/g, PG_PASSWORD);
-    config = config.replace(/%{{SMTP_PORT}}/g, opts.smtpPort);
-    config = config.replace(/{{SYNAPSE_URL}}/g, opts.synapseUrl);
-
-    await fse.writeFile(outputHomeserver, config);
-
-    // Allow anyone to read, write and execute in the temp directory
-    // so that the DIND setup that we use to update the playwright screenshots work without any issues.
-    await fse.chmod(tempDir, 0o757);
-
-    return {
-        configDir: tempDir,
-    };
-}
-
-export class MatrixAuthenticationService {
-    private readonly masDocker = new Docker();
-    private readonly postgresDocker = new PostgresDocker("mas");
-    private instance: ProxyInstance;
-    public port: number;
-
-    constructor(private context: BrowserContext) {}
-
-    async prepare(): Promise<{ port: number }> {
-        this.port = await getFreePort();
-        return { port: this.port };
-    }
-
-    async start(homeserver: HomeserverInstance, mailhog: MailhogInstance): Promise<ProxyInstance> {
-        console.log(new Date(), "Starting mas...");
-
-        if (!this.port) await this.prepare();
-        const port = this.port;
-        const { containerId: postgresId, ipAddress: postgresIp } = await this.postgresDocker.start();
-        const { configDir } = await cfgDirFromTemplate({
-            masPort: port.toString(),
-            postgresHost: postgresIp,
-            synapseUrl: homeserver.config.dockerUrl,
-            smtpPort: mailhog.smtpPort.toString(),
-        });
-
-        console.log(new Date(), "starting mas container...", TAG);
-        const containerId = await this.masDocker.run({
-            image: "ghcr.io/matrix-org/matrix-authentication-service:" + TAG,
-            containerName: "react-sdk-playwright-mas",
-            params: ["-p", `${port}:8080/tcp`, "-v", `${configDir}:/config`, "--entrypoint", "sh"],
-            cmd: [
-                "-c",
-                "mas-cli database migrate --config /config/config.yaml && " +
-                    "mas-cli config sync --config /config/config.yaml && " +
-                    "mas-cli server --config /config/config.yaml",
-            ],
-        });
-        console.log(new Date(), "started!");
-
-        // Set up redirects
-        const baseUrl = `http://localhost:${port}`;
-        for (const path of [
-            "**/_matrix/client/*/login",
-            "**/_matrix/client/*/login/**",
-            "**/_matrix/client/*/logout",
-            "**/_matrix/client/*/refresh",
-        ]) {
-            await this.context.route(path, async (route) => {
-                await route.continue({
-                    url: new URL(route.request().url().split("/").slice(3).join("/"), baseUrl).href,
-                });
-            });
-        }
-
-        this.instance = { containerId, postgresId, port, configDir };
-        return this.instance;
-    }
-
-    async stop(testInfo: TestInfo): Promise<void> {
-        if (!this.instance) return; // nothing to stop
-        const id = this.instance.containerId;
-        const logPath = path.join("playwright", "logs", "matrix-authentication-service", id);
-        await fse.ensureDir(logPath);
-        await this.masDocker.persistLogsToFile({
-            stdoutFile: path.join(logPath, "stdout.log"),
-            stderrFile: path.join(logPath, "stderr.log"),
-        });
-
-        await this.masDocker.stop();
-        await this.postgresDocker.stop();
-
-        if (testInfo.status !== "passed") {
-            const logs = [path.join(logPath, "stdout.log"), path.join(logPath, "stderr.log")];
-            for (const path of logs) {
-                await testInfo.attach(`mas-${basename(path)}`, {
-                    path,
-                    contentType: "text/plain",
-                });
-            }
-            await testInfo.attach("mas-config.yaml", {
-                path: path.join(this.instance.configDir, "config.yaml"),
-                contentType: "text/plain",
-            });
-        }
-
-        await fse.remove(this.instance.configDir);
-        console.log(new Date(), "Stopped mas.");
-    }
-}
diff --git a/playwright/plugins/oauth_server/index.ts b/playwright/plugins/oauth_server/index.ts
index 4f855d3dc4f..df5ee0f461b 100644
--- a/playwright/plugins/oauth_server/index.ts
+++ b/playwright/plugins/oauth_server/index.ts
@@ -2,19 +2,28 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 import http from "http";
 import express from "express";
 import { AddressInfo } from "net";
+import { TestInfo } from "@playwright/test";
+
+import { randB64Bytes } from "../utils/rand.ts";
 
 export class OAuthServer {
     private server?: http.Server;
+    private sub?: string;
+
+    public onTestStarted(testInfo: TestInfo): void {
+        this.sub = testInfo.testId;
+    }
 
     public start(): number {
         if (this.server) this.stop();
+        const token = randB64Bytes(16);
 
         const app = express();
 
@@ -28,7 +37,7 @@ export class OAuthServer {
             const code = req.body.code;
             if (code === "valid_auth_code") {
                 res.send({
-                    access_token: "oauth_access_token",
+                    access_token: token,
                     token_type: "Bearer",
                     expires_in: "3600",
                 });
@@ -43,7 +52,7 @@ export class OAuthServer {
 
             // return an OAuth2 user info object
             res.send({
-                sub: "alice",
+                sub: this.sub,
                 name: "Alice",
             });
         });
diff --git a/playwright/plugins/postgres/index.ts b/playwright/plugins/postgres/index.ts
deleted file mode 100644
index bb63016c7a1..00000000000
--- a/playwright/plugins/postgres/index.ts
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2023 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
-Please see LICENSE files in the repository root for full details.
-*/
-
-import { Docker } from "../docker";
-
-export const PG_PASSWORD = "p4S5w0rD";
-
-/**
- * Class to manage a postgres database in docker
- */
-export class PostgresDocker extends Docker {
-    /**
-     * @param key an opaque string to use when naming the docker containers instantiated by this class
-     */
-    public constructor(private key: string) {
-        super();
-    }
-
-    private async waitForPostgresReady(): Promise<void> {
-        const waitTimeMillis = 30000;
-        const startTime = new Date().getTime();
-        let lastErr: Error | null = null;
-        while (new Date().getTime() - startTime < waitTimeMillis) {
-            try {
-                await this.exec(["pg_isready", "-U", "postgres"], true);
-                lastErr = null;
-                break;
-            } catch (err) {
-                console.log("pg_isready: failed");
-                lastErr = err;
-            }
-        }
-        if (lastErr) {
-            console.log("rethrowing");
-            throw lastErr;
-        }
-    }
-
-    public async start(): Promise<{
-        ipAddress: string;
-        containerId: string;
-    }> {
-        console.log(new Date(), "starting postgres container");
-        const containerId = await this.run({
-            image: "postgres",
-            containerName: `react-sdk-playwright-postgres-${this.key}`,
-            params: ["--tmpfs=/pgtmpfs", "-e", "PGDATA=/pgtmpfs", "-e", `POSTGRES_PASSWORD=${PG_PASSWORD}`],
-            // Optimise for testing - https://www.postgresql.org/docs/current/non-durability.html
-            cmd: ["-c", `fsync=off`, "-c", `synchronous_commit=off`, "-c", `full_page_writes=off`],
-        });
-
-        const ipAddress = await this.getContainerIp();
-        console.log(new Date(), "postgres container up");
-
-        await this.waitForPostgresReady();
-        console.log(new Date(), "postgres container ready");
-        return { ipAddress, containerId };
-    }
-}
diff --git a/playwright/plugins/sliding-sync-proxy/index.ts b/playwright/plugins/sliding-sync-proxy/index.ts
deleted file mode 100644
index 3a1075339d0..00000000000
--- a/playwright/plugins/sliding-sync-proxy/index.ts
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2023 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
-Please see LICENSE files in the repository root for full details.
-*/
-
-import { getFreePort } from "../utils/port";
-import { Docker } from "../docker";
-import { PG_PASSWORD, PostgresDocker } from "../postgres";
-
-// Docker tag to use for `ghcr.io/matrix-org/sliding-sync` image.
-const SLIDING_SYNC_PROXY_TAG = "v0.99.3";
-
-export interface ProxyInstance {
-    containerId: string;
-    postgresId: string;
-    port: number;
-}
-
-export class SlidingSyncProxy {
-    private readonly proxyDocker = new Docker();
-    private readonly postgresDocker = new PostgresDocker("sliding-sync");
-    private instance: ProxyInstance;
-
-    constructor(private synapseIp: string) {}
-
-    async start(): Promise<ProxyInstance> {
-        console.log(new Date(), "Starting sliding sync proxy...");
-
-        const { ipAddress: postgresIp, containerId: postgresId } = await this.postgresDocker.start();
-
-        const port = await getFreePort();
-        console.log(new Date(), "starting proxy container...", SLIDING_SYNC_PROXY_TAG);
-        const containerId = await this.proxyDocker.run({
-            image: "ghcr.io/matrix-org/sliding-sync:" + SLIDING_SYNC_PROXY_TAG,
-            containerName: "react-sdk-playwright-sliding-sync-proxy",
-            params: [
-                "-p",
-                `${port}:8008/tcp`,
-                "-e",
-                "SYNCV3_SECRET=bwahahaha",
-                "-e",
-                `SYNCV3_SERVER=${this.synapseIp}`,
-                "-e",
-                `SYNCV3_DB=user=postgres dbname=postgres password=${PG_PASSWORD} host=${postgresIp} sslmode=disable`,
-            ],
-        });
-        console.log(new Date(), "started!");
-
-        this.instance = { containerId, postgresId, port };
-        return this.instance;
-    }
-
-    async stop(): Promise<void> {
-        await this.postgresDocker.stop();
-        await this.proxyDocker.stop();
-        console.log(new Date(), "Stopped sliding sync proxy.");
-    }
-}
diff --git a/playwright/plugins/utils/api.ts b/playwright/plugins/utils/api.ts
new file mode 100644
index 00000000000..40dade13027
--- /dev/null
+++ b/playwright/plugins/utils/api.ts
@@ -0,0 +1,76 @@
+/*
+Copyright 2025 New Vector Ltd.
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+Please see LICENSE files in the repository root for full details.
+*/
+
+import { APIRequestContext } from "@playwright/test";
+
+import { Credentials } from "../homeserver";
+
+export type Verb = "GET" | "POST" | "PUT" | "DELETE";
+
+export class Api {
+    private _request?: APIRequestContext;
+
+    constructor(private readonly baseUrl: string) {}
+
+    public setRequest(request: APIRequestContext): void {
+        this._request = request;
+    }
+
+    public async request<R extends {}>(verb: "GET", path: string, token?: string, data?: never): Promise<R>;
+    public async request<R extends {}>(verb: Verb, path: string, token?: string, data?: object): Promise<R>;
+    public async request<R extends {}>(verb: Verb, path: string, token?: string, data?: object): Promise<R> {
+        const url = `${this.baseUrl}${path}`;
+        const res = await this._request.fetch(url, {
+            data,
+            method: verb,
+            headers: token
+                ? {
+                      Authorization: `Bearer ${token}`,
+                  }
+                : undefined,
+        });
+
+        if (!res.ok()) {
+            throw new Error(
+                `Request to ${url} failed with status ${res.status()}: ${JSON.stringify(await res.json())}`,
+            );
+        }
+
+        return res.json();
+    }
+}
+
+export class ClientServerApi extends Api {
+    constructor(baseUrl: string) {
+        super(`${baseUrl}/_matrix/client`);
+    }
+
+    public async loginUser(userId: string, password: string): Promise<Credentials> {
+        const json = await this.request<{
+            access_token: string;
+            user_id: string;
+            device_id: string;
+            home_server: string;
+        }>("POST", "/v3/login", undefined, {
+            type: "m.login.password",
+            identifier: {
+                type: "m.id.user",
+                user: userId,
+            },
+            password: password,
+        });
+
+        return {
+            password,
+            accessToken: json.access_token,
+            userId: json.user_id,
+            deviceId: json.device_id,
+            homeServer: json.home_server || json.user_id.split(":").slice(1).join(":"),
+            username: userId.slice(1).split(":")[0],
+        };
+    }
+}
diff --git a/playwright/plugins/utils/object.ts b/playwright/plugins/utils/object.ts
new file mode 100644
index 00000000000..bfb92fecec2
--- /dev/null
+++ b/playwright/plugins/utils/object.ts
@@ -0,0 +1,16 @@
+/*
+Copyright 2024 New Vector Ltd.
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+Please see LICENSE files in the repository root for full details.
+*/
+
+/**
+ * Deep copy the given object. The object MUST NOT have circular references and
+ * MUST NOT have functions.
+ * @param obj - The object to deep copy.
+ * @returns A copy of the object without any references to the original.
+ */
+export function deepCopy<T>(obj: T): T {
+    return JSON.parse(JSON.stringify(obj));
+}
diff --git a/playwright/plugins/utils/port.ts b/playwright/plugins/utils/port.ts
index 8ab5fddd9b4..b54e251f2f2 100644
--- a/playwright/plugins/utils/port.ts
+++ b/playwright/plugins/utils/port.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/playwright/plugins/utils/rand.ts b/playwright/plugins/utils/rand.ts
index 2560da2dc99..94f723f0a6c 100644
--- a/playwright/plugins/utils/rand.ts
+++ b/playwright/plugins/utils/rand.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/playwright/plugins/webserver/index.ts b/playwright/plugins/webserver/index.ts
index 3a3b77b4d5a..7645e9cff3d 100644
--- a/playwright/plugins/webserver/index.ts
+++ b/playwright/plugins/webserver/index.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/playwright/services.ts b/playwright/services.ts
new file mode 100644
index 00000000000..c15d63bd025
--- /dev/null
+++ b/playwright/services.ts
@@ -0,0 +1,169 @@
+/*
+Copyright 2024 New Vector Ltd.
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+Please see LICENSE files in the repository root for full details.
+*/
+
+import { test as base } from "@playwright/test";
+import mailhog from "mailhog";
+import { Network, StartedNetwork } from "testcontainers";
+import { PostgreSqlContainer, StartedPostgreSqlContainer } from "@testcontainers/postgresql";
+
+import { SynapseConfig, SynapseContainer } from "./testcontainers/synapse.ts";
+import { Logger } from "./logger.ts";
+import { StartedMatrixAuthenticationServiceContainer } from "./testcontainers/mas.ts";
+import { HomeserverContainer, StartedHomeserverContainer } from "./testcontainers/HomeserverContainer.ts";
+import { MailhogContainer, StartedMailhogContainer } from "./testcontainers/mailhog.ts";
+import { OAuthServer } from "./plugins/oauth_server";
+import { DendriteContainer, PineconeContainer } from "./testcontainers/dendrite.ts";
+import { HomeserverType } from "./plugins/homeserver";
+
+export interface TestFixtures {
+    mailhogClient: mailhog.API;
+}
+
+export interface Services {
+    logger: Logger;
+
+    network: StartedNetwork;
+    postgres: StartedPostgreSqlContainer;
+    mailhog: StartedMailhogContainer;
+
+    synapseConfig: SynapseConfig;
+    _homeserver: HomeserverContainer<any>;
+    homeserver: StartedHomeserverContainer;
+    // Set in masHomeserver only
+    mas?: StartedMatrixAuthenticationServiceContainer;
+    // Set in legacyOAuthHomeserver only
+    oAuthServer?: OAuthServer;
+}
+
+export interface Options {
+    homeserverType: HomeserverType;
+}
+
+export const test = base.extend<TestFixtures, Services & Options>({
+    logger: [
+        // eslint-disable-next-line no-empty-pattern
+        async ({}, use) => {
+            const logger = new Logger();
+            await use(logger);
+        },
+        { scope: "worker" },
+    ],
+    network: [
+        // eslint-disable-next-line no-empty-pattern
+        async ({}, use) => {
+            const network = await new Network().start();
+            await use(network);
+            await network.stop();
+        },
+        { scope: "worker" },
+    ],
+    postgres: [
+        async ({ logger, network }, use) => {
+            const container = await new PostgreSqlContainer()
+                .withNetwork(network)
+                .withNetworkAliases("postgres")
+                .withLogConsumer(logger.getConsumer("postgres"))
+                .withTmpFs({
+                    "/dev/shm/pgdata/data": "",
+                })
+                .withEnvironment({
+                    PG_DATA: "/dev/shm/pgdata/data",
+                })
+                .withCommand([
+                    "-c",
+                    "shared_buffers=128MB",
+                    "-c",
+                    `fsync=off`,
+                    "-c",
+                    `synchronous_commit=off`,
+                    "-c",
+                    "full_page_writes=off",
+                ])
+                .start();
+            await use(container);
+            await container.stop();
+        },
+        { scope: "worker" },
+    ],
+
+    mailhog: [
+        async ({ logger, network }, use) => {
+            const container = await new MailhogContainer()
+                .withNetwork(network)
+                .withNetworkAliases("mailhog")
+                .withLogConsumer(logger.getConsumer("mailhog"))
+                .start();
+            await use(container);
+            await container.stop();
+        },
+        { scope: "worker" },
+    ],
+    mailhogClient: async ({ mailhog: container }, use) => {
+        await container.client.deleteAll();
+        await use(container.client);
+    },
+
+    synapseConfig: [{}, { scope: "worker" }],
+    homeserverType: ["synapse", { option: true, scope: "worker" }],
+    _homeserver: [
+        async ({ homeserverType }, use) => {
+            let container: HomeserverContainer<any>;
+            switch (homeserverType) {
+                case "synapse":
+                    container = new SynapseContainer();
+                    break;
+                case "dendrite":
+                    container = new DendriteContainer();
+                    break;
+                case "pinecone":
+                    container = new PineconeContainer();
+                    break;
+            }
+
+            await use(container);
+        },
+        { scope: "worker" },
+    ],
+    homeserver: [
+        async ({ homeserverType, logger, network, _homeserver: homeserver, synapseConfig, mas }, use) => {
+            if (homeserver instanceof SynapseContainer) {
+                homeserver.withConfig(synapseConfig);
+            }
+            const container = await homeserver
+                .withNetwork(network)
+                .withNetworkAliases("homeserver")
+                .withLogConsumer(logger.getConsumer(homeserverType))
+                .withMatrixAuthenticationService(mas)
+                .start();
+
+            await use(container);
+            await container.stop();
+        },
+        { scope: "worker" },
+    ],
+    mas: [
+        // eslint-disable-next-line no-empty-pattern
+        async ({}, use) => {
+            // we stub the mas fixture to allow `homeserver` to depend on it to ensure
+            // when it is specified by `masHomeserver` it is started before the homeserver
+            await use(undefined);
+        },
+        { scope: "worker" },
+    ],
+
+    context: async ({ homeserverType, synapseConfig, logger, context, request, homeserver }, use, testInfo) => {
+        testInfo.skip(
+            !(homeserver instanceof SynapseContainer) && Object.keys(synapseConfig).length > 0,
+            `Test specifies Synapse config options so is unsupported with ${homeserverType}`,
+        );
+        homeserver.setRequest(request);
+        await logger.onTestStarted(context);
+        await use(context);
+        await logger.onTestFinished(testInfo);
+        await homeserver.onTestFinished(testInfo);
+    },
+});
diff --git a/playwright/snapshots/chat-export/html-export.spec.ts/html-export-linux.png b/playwright/snapshots/chat-export/html-export.spec.ts/html-export-linux.png
index 465e58ca39e..7a108b441c8 100644
Binary files a/playwright/snapshots/chat-export/html-export.spec.ts/html-export-linux.png and b/playwright/snapshots/chat-export/html-export.spec.ts/html-export-linux.png differ
diff --git a/playwright/snapshots/invite/invite-dialog.spec.ts/invite-dialog-dm-with-user-pill-linux.png b/playwright/snapshots/invite/invite-dialog.spec.ts/invite-dialog-dm-with-user-pill-linux.png
index cc64e8bf781..c66606efcda 100644
Binary files a/playwright/snapshots/invite/invite-dialog.spec.ts/invite-dialog-dm-with-user-pill-linux.png and b/playwright/snapshots/invite/invite-dialog.spec.ts/invite-dialog-dm-with-user-pill-linux.png differ
diff --git a/playwright/snapshots/invite/invite-dialog.spec.ts/invite-dialog-dm-without-user-linux.png b/playwright/snapshots/invite/invite-dialog.spec.ts/invite-dialog-dm-without-user-linux.png
index a634e876bc6..02cbff0e3fb 100644
Binary files a/playwright/snapshots/invite/invite-dialog.spec.ts/invite-dialog-dm-without-user-linux.png and b/playwright/snapshots/invite/invite-dialog.spec.ts/invite-dialog-dm-without-user-linux.png differ
diff --git a/playwright/snapshots/invite/invite-dialog.spec.ts/invite-dialog-room-with-user-pill-linux.png b/playwright/snapshots/invite/invite-dialog.spec.ts/invite-dialog-room-with-user-pill-linux.png
index d01aae804c9..fa3cf904303 100644
Binary files a/playwright/snapshots/invite/invite-dialog.spec.ts/invite-dialog-room-with-user-pill-linux.png and b/playwright/snapshots/invite/invite-dialog.spec.ts/invite-dialog-room-with-user-pill-linux.png differ
diff --git a/playwright/snapshots/invite/invite-dialog.spec.ts/invite-dialog-room-without-user-linux.png b/playwright/snapshots/invite/invite-dialog.spec.ts/invite-dialog-room-without-user-linux.png
index 6e8e2fbddff..910040e20f4 100644
Binary files a/playwright/snapshots/invite/invite-dialog.spec.ts/invite-dialog-room-without-user-linux.png and b/playwright/snapshots/invite/invite-dialog.spec.ts/invite-dialog-room-without-user-linux.png differ
diff --git a/playwright/snapshots/register/register.spec.ts/use-case-selection-linux.png b/playwright/snapshots/register/register.spec.ts/use-case-selection-linux.png
deleted file mode 100644
index 1dd98b51e15..00000000000
Binary files a/playwright/snapshots/register/register.spec.ts/use-case-selection-linux.png and /dev/null differ
diff --git a/playwright/snapshots/right-panel/memberlist.spec.ts/with-four-members-linux.png b/playwright/snapshots/right-panel/memberlist.spec.ts/with-four-members-linux.png
new file mode 100644
index 00000000000..f0e14ee55cf
Binary files /dev/null and b/playwright/snapshots/right-panel/memberlist.spec.ts/with-four-members-linux.png differ
diff --git a/playwright/snapshots/room/room-header.spec.ts/room-header-linux.png b/playwright/snapshots/room/room-header.spec.ts/room-header-linux.png
index afc5d53fab3..4ba22a52209 100644
Binary files a/playwright/snapshots/room/room-header.spec.ts/room-header-linux.png and b/playwright/snapshots/room/room-header.spec.ts/room-header-linux.png differ
diff --git a/playwright/snapshots/room/room-header.spec.ts/room-header-long-name-linux.png b/playwright/snapshots/room/room-header.spec.ts/room-header-long-name-linux.png
index ce15e3e1516..ef6112da1de 100644
Binary files a/playwright/snapshots/room/room-header.spec.ts/room-header-long-name-linux.png and b/playwright/snapshots/room/room-header.spec.ts/room-header-long-name-linux.png differ
diff --git a/playwright/snapshots/room/room-header.spec.ts/room-header-video-room-linux.png b/playwright/snapshots/room/room-header.spec.ts/room-header-video-room-linux.png
index bd31e502d7f..ed8c75104f1 100644
Binary files a/playwright/snapshots/room/room-header.spec.ts/room-header-video-room-linux.png and b/playwright/snapshots/room/room-header.spec.ts/room-header-video-room-linux.png differ
diff --git a/playwright/snapshots/settings/account-user-settings-tab.spec.ts/account-linux.png b/playwright/snapshots/settings/account-user-settings-tab.spec.ts/account-linux.png
index c641f2a0aaf..12fd5c79d32 100644
Binary files a/playwright/snapshots/settings/account-user-settings-tab.spec.ts/account-linux.png and b/playwright/snapshots/settings/account-user-settings-tab.spec.ts/account-linux.png differ
diff --git a/playwright/snapshots/settings/account-user-settings-tab.spec.ts/account-smallscreen-linux.png b/playwright/snapshots/settings/account-user-settings-tab.spec.ts/account-smallscreen-linux.png
index b9d81c5d5a8..ac6f86e81c4 100644
Binary files a/playwright/snapshots/settings/account-user-settings-tab.spec.ts/account-smallscreen-linux.png and b/playwright/snapshots/settings/account-user-settings-tab.spec.ts/account-smallscreen-linux.png differ
diff --git a/playwright/snapshots/settings/appearance-user-settings-tab/appearance-user-settings-tab.spec.ts/appearance-tab-linux.png b/playwright/snapshots/settings/appearance-user-settings-tab/appearance-user-settings-tab.spec.ts/appearance-tab-linux.png
index 75a4852f9b9..a8b3ae3ea77 100644
Binary files a/playwright/snapshots/settings/appearance-user-settings-tab/appearance-user-settings-tab.spec.ts/appearance-tab-linux.png and b/playwright/snapshots/settings/appearance-user-settings-tab/appearance-user-settings-tab.spec.ts/appearance-tab-linux.png differ
diff --git a/playwright/snapshots/settings/appearance-user-settings-tab/appearance-user-settings-tab.spec.ts/window-12px-linux.png b/playwright/snapshots/settings/appearance-user-settings-tab/appearance-user-settings-tab.spec.ts/window-12px-linux.png
index 41ffca6c93d..5307b7400a3 100644
Binary files a/playwright/snapshots/settings/appearance-user-settings-tab/appearance-user-settings-tab.spec.ts/window-12px-linux.png and b/playwright/snapshots/settings/appearance-user-settings-tab/appearance-user-settings-tab.spec.ts/window-12px-linux.png differ
diff --git a/playwright/snapshots/settings/encryption-user-tab/recovery.spec.ts/change-key-1-encryption-tab-linux.png b/playwright/snapshots/settings/encryption-user-tab/recovery.spec.ts/change-key-1-encryption-tab-linux.png
new file mode 100644
index 00000000000..b2083a5dd47
Binary files /dev/null and b/playwright/snapshots/settings/encryption-user-tab/recovery.spec.ts/change-key-1-encryption-tab-linux.png differ
diff --git a/playwright/snapshots/settings/encryption-user-tab/recovery.spec.ts/change-key-2-encryption-tab-linux.png b/playwright/snapshots/settings/encryption-user-tab/recovery.spec.ts/change-key-2-encryption-tab-linux.png
new file mode 100644
index 00000000000..02945494593
Binary files /dev/null and b/playwright/snapshots/settings/encryption-user-tab/recovery.spec.ts/change-key-2-encryption-tab-linux.png differ
diff --git a/playwright/snapshots/settings/encryption-user-tab/recovery.spec.ts/default-recovery-linux.png b/playwright/snapshots/settings/encryption-user-tab/recovery.spec.ts/default-recovery-linux.png
new file mode 100644
index 00000000000..971745c4128
Binary files /dev/null and b/playwright/snapshots/settings/encryption-user-tab/recovery.spec.ts/default-recovery-linux.png differ
diff --git a/playwright/snapshots/settings/encryption-user-tab/recovery.spec.ts/out-of-sync-recovery-linux.png b/playwright/snapshots/settings/encryption-user-tab/recovery.spec.ts/out-of-sync-recovery-linux.png
new file mode 100644
index 00000000000..e6664a5f79b
Binary files /dev/null and b/playwright/snapshots/settings/encryption-user-tab/recovery.spec.ts/out-of-sync-recovery-linux.png differ
diff --git a/playwright/snapshots/settings/encryption-user-tab/recovery.spec.ts/set-up-key-1-encryption-tab-linux.png b/playwright/snapshots/settings/encryption-user-tab/recovery.spec.ts/set-up-key-1-encryption-tab-linux.png
new file mode 100644
index 00000000000..1a413094ae1
Binary files /dev/null and b/playwright/snapshots/settings/encryption-user-tab/recovery.spec.ts/set-up-key-1-encryption-tab-linux.png differ
diff --git a/playwright/snapshots/settings/encryption-user-tab/recovery.spec.ts/set-up-key-2-encryption-tab-linux.png b/playwright/snapshots/settings/encryption-user-tab/recovery.spec.ts/set-up-key-2-encryption-tab-linux.png
new file mode 100644
index 00000000000..099c0c549e0
Binary files /dev/null and b/playwright/snapshots/settings/encryption-user-tab/recovery.spec.ts/set-up-key-2-encryption-tab-linux.png differ
diff --git a/playwright/snapshots/settings/encryption-user-tab/recovery.spec.ts/set-up-key-3-encryption-tab-linux.png b/playwright/snapshots/settings/encryption-user-tab/recovery.spec.ts/set-up-key-3-encryption-tab-linux.png
new file mode 100644
index 00000000000..6cc32cc4311
Binary files /dev/null and b/playwright/snapshots/settings/encryption-user-tab/recovery.spec.ts/set-up-key-3-encryption-tab-linux.png differ
diff --git a/playwright/snapshots/settings/encryption-user-tab/recovery.spec.ts/set-up-recovery-linux.png b/playwright/snapshots/settings/encryption-user-tab/recovery.spec.ts/set-up-recovery-linux.png
new file mode 100644
index 00000000000..78dcd14aeab
Binary files /dev/null and b/playwright/snapshots/settings/encryption-user-tab/recovery.spec.ts/set-up-recovery-linux.png differ
diff --git a/playwright/snapshots/settings/encryption-user-tab/recovery.spec.ts/verify-device-encryption-tab-linux.png b/playwright/snapshots/settings/encryption-user-tab/recovery.spec.ts/verify-device-encryption-tab-linux.png
new file mode 100644
index 00000000000..643fe46a1df
Binary files /dev/null and b/playwright/snapshots/settings/encryption-user-tab/recovery.spec.ts/verify-device-encryption-tab-linux.png differ
diff --git a/playwright/snapshots/settings/preferences-user-settings-tab.spec.ts/Preferences-user-settings-tab-should-be-rendered-properly-1-linux.png b/playwright/snapshots/settings/preferences-user-settings-tab.spec.ts/Preferences-user-settings-tab-should-be-rendered-properly-1-linux.png
index 7d952052519..62a8c5b8d17 100644
Binary files a/playwright/snapshots/settings/preferences-user-settings-tab.spec.ts/Preferences-user-settings-tab-should-be-rendered-properly-1-linux.png and b/playwright/snapshots/settings/preferences-user-settings-tab.spec.ts/Preferences-user-settings-tab-should-be-rendered-properly-1-linux.png differ
diff --git a/playwright/snapshots/share-dialog/share-dialog.spec.ts/share-dialog-event-linux.png b/playwright/snapshots/share-dialog/share-dialog.spec.ts/share-dialog-event-linux.png
index 541eaa2fa55..6a55618c78d 100644
Binary files a/playwright/snapshots/share-dialog/share-dialog.spec.ts/share-dialog-event-linux.png and b/playwright/snapshots/share-dialog/share-dialog.spec.ts/share-dialog-event-linux.png differ
diff --git a/playwright/snapshots/share-dialog/share-dialog.spec.ts/share-dialog-user-linux.png b/playwright/snapshots/share-dialog/share-dialog.spec.ts/share-dialog-user-linux.png
index 2fb39b9f5f0..28483d5815c 100644
Binary files a/playwright/snapshots/share-dialog/share-dialog.spec.ts/share-dialog-user-linux.png and b/playwright/snapshots/share-dialog/share-dialog.spec.ts/share-dialog-user-linux.png differ
diff --git a/playwright/snapshots/threads/threads.spec.ts/Initial-ThreadView-on-bubble-layout-linux.png b/playwright/snapshots/threads/threads.spec.ts/Initial-ThreadView-on-bubble-layout-linux.png
new file mode 100644
index 00000000000..60d6dc9e189
Binary files /dev/null and b/playwright/snapshots/threads/threads.spec.ts/Initial-ThreadView-on-bubble-layout-linux.png differ
diff --git a/playwright/snapshots/threads/threads.spec.ts/Initial-ThreadView-on-group-layout-linux.png b/playwright/snapshots/threads/threads.spec.ts/Initial-ThreadView-on-group-layout-linux.png
new file mode 100644
index 00000000000..301201c1f6a
Binary files /dev/null and b/playwright/snapshots/threads/threads.spec.ts/Initial-ThreadView-on-group-layout-linux.png differ
diff --git a/playwright/snapshots/threads/threads.spec.ts/ThreadView-with-reaction-and-a-hidden-event-on-bubble-layout-linux.png b/playwright/snapshots/threads/threads.spec.ts/ThreadView-with-reaction-and-a-hidden-event-on-bubble-layout-linux.png
new file mode 100644
index 00000000000..cff1b27bd3d
Binary files /dev/null and b/playwright/snapshots/threads/threads.spec.ts/ThreadView-with-reaction-and-a-hidden-event-on-bubble-layout-linux.png differ
diff --git a/playwright/snapshots/threads/threads.spec.ts/ThreadView-with-reaction-and-a-hidden-event-on-group-layout-linux.png b/playwright/snapshots/threads/threads.spec.ts/ThreadView-with-reaction-and-a-hidden-event-on-group-layout-linux.png
new file mode 100644
index 00000000000..67414d1e7bc
Binary files /dev/null and b/playwright/snapshots/threads/threads.spec.ts/ThreadView-with-reaction-and-a-hidden-event-on-group-layout-linux.png differ
diff --git a/playwright/snapshots/threads/threads.spec.ts/ThreadView-with-redacted-messages-on-bubble-layout-linux.png b/playwright/snapshots/threads/threads.spec.ts/ThreadView-with-redacted-messages-on-bubble-layout-linux.png
new file mode 100644
index 00000000000..c92780196d5
Binary files /dev/null and b/playwright/snapshots/threads/threads.spec.ts/ThreadView-with-redacted-messages-on-bubble-layout-linux.png differ
diff --git a/playwright/snapshots/threads/threads.spec.ts/ThreadView-with-redacted-messages-on-group-layout-linux.png b/playwright/snapshots/threads/threads.spec.ts/ThreadView-with-redacted-messages-on-group-layout-linux.png
new file mode 100644
index 00000000000..4b779aa7888
Binary files /dev/null and b/playwright/snapshots/threads/threads.spec.ts/ThreadView-with-redacted-messages-on-group-layout-linux.png differ
diff --git a/playwright/snapshots/timeline/timeline.spec.ts/collapsed-gels-and-messages-irc-layout-linux.png b/playwright/snapshots/timeline/timeline.spec.ts/collapsed-gels-and-messages-irc-layout-linux.png
index 348db69cfc3..00b271004eb 100644
Binary files a/playwright/snapshots/timeline/timeline.spec.ts/collapsed-gels-and-messages-irc-layout-linux.png and b/playwright/snapshots/timeline/timeline.spec.ts/collapsed-gels-and-messages-irc-layout-linux.png differ
diff --git a/playwright/snapshots/timeline/timeline.spec.ts/collapsed-gels-bubble-layout-linux.png b/playwright/snapshots/timeline/timeline.spec.ts/collapsed-gels-bubble-layout-linux.png
index 42ee5a0acb3..8f11c831dbd 100644
Binary files a/playwright/snapshots/timeline/timeline.spec.ts/collapsed-gels-bubble-layout-linux.png and b/playwright/snapshots/timeline/timeline.spec.ts/collapsed-gels-bubble-layout-linux.png differ
diff --git a/playwright/snapshots/timeline/timeline.spec.ts/configured-room-irc-layout-linux.png b/playwright/snapshots/timeline/timeline.spec.ts/configured-room-irc-layout-linux.png
index 92532e3d9c8..63655439479 100644
Binary files a/playwright/snapshots/timeline/timeline.spec.ts/configured-room-irc-layout-linux.png and b/playwright/snapshots/timeline/timeline.spec.ts/configured-room-irc-layout-linux.png differ
diff --git a/playwright/snapshots/timeline/timeline.spec.ts/event-line-inline-start-margin-irc-layout-linux.png b/playwright/snapshots/timeline/timeline.spec.ts/event-line-inline-start-margin-irc-layout-linux.png
index 1e50cd3c0fb..d8a5ae40569 100644
Binary files a/playwright/snapshots/timeline/timeline.spec.ts/event-line-inline-start-margin-irc-layout-linux.png and b/playwright/snapshots/timeline/timeline.spec.ts/event-line-inline-start-margin-irc-layout-linux.png differ
diff --git a/playwright/snapshots/timeline/timeline.spec.ts/event-tiles-bubble-layout-linux.png b/playwright/snapshots/timeline/timeline.spec.ts/event-tiles-bubble-layout-linux.png
index b0960a11887..58c844a54d3 100644
Binary files a/playwright/snapshots/timeline/timeline.spec.ts/event-tiles-bubble-layout-linux.png and b/playwright/snapshots/timeline/timeline.spec.ts/event-tiles-bubble-layout-linux.png differ
diff --git a/playwright/snapshots/timeline/timeline.spec.ts/event-tiles-compact-modern-layout-linux.png b/playwright/snapshots/timeline/timeline.spec.ts/event-tiles-compact-modern-layout-linux.png
index a7637b6b94d..d8e6da9f8fe 100644
Binary files a/playwright/snapshots/timeline/timeline.spec.ts/event-tiles-compact-modern-layout-linux.png and b/playwright/snapshots/timeline/timeline.spec.ts/event-tiles-compact-modern-layout-linux.png differ
diff --git a/playwright/snapshots/timeline/timeline.spec.ts/event-tiles-irc-layout-linux.png b/playwright/snapshots/timeline/timeline.spec.ts/event-tiles-irc-layout-linux.png
index a609a4cd0df..e1a4e6ef068 100644
Binary files a/playwright/snapshots/timeline/timeline.spec.ts/event-tiles-irc-layout-linux.png and b/playwright/snapshots/timeline/timeline.spec.ts/event-tiles-irc-layout-linux.png differ
diff --git a/playwright/snapshots/timeline/timeline.spec.ts/event-tiles-modern-layout-linux.png b/playwright/snapshots/timeline/timeline.spec.ts/event-tiles-modern-layout-linux.png
index fe50abef0cc..032a8c11188 100644
Binary files a/playwright/snapshots/timeline/timeline.spec.ts/event-tiles-modern-layout-linux.png and b/playwright/snapshots/timeline/timeline.spec.ts/event-tiles-modern-layout-linux.png differ
diff --git a/playwright/snapshots/timeline/timeline.spec.ts/expanded-gels-and-messages-irc-layout-linux.png b/playwright/snapshots/timeline/timeline.spec.ts/expanded-gels-and-messages-irc-layout-linux.png
index ac6dadc9625..b31eae03f64 100644
Binary files a/playwright/snapshots/timeline/timeline.spec.ts/expanded-gels-and-messages-irc-layout-linux.png and b/playwright/snapshots/timeline/timeline.spec.ts/expanded-gels-and-messages-irc-layout-linux.png differ
diff --git a/playwright/snapshots/timeline/timeline.spec.ts/expanded-gels-bubble-layout-linux.png b/playwright/snapshots/timeline/timeline.spec.ts/expanded-gels-bubble-layout-linux.png
index 8e833be3085..1c7265ca62d 100644
Binary files a/playwright/snapshots/timeline/timeline.spec.ts/expanded-gels-bubble-layout-linux.png and b/playwright/snapshots/timeline/timeline.spec.ts/expanded-gels-bubble-layout-linux.png differ
diff --git a/playwright/snapshots/timeline/timeline.spec.ts/expanded-gels-emote-irc-layout-linux.png b/playwright/snapshots/timeline/timeline.spec.ts/expanded-gels-emote-irc-layout-linux.png
index 3e9e78ca997..33ef04df3cf 100644
Binary files a/playwright/snapshots/timeline/timeline.spec.ts/expanded-gels-emote-irc-layout-linux.png and b/playwright/snapshots/timeline/timeline.spec.ts/expanded-gels-emote-irc-layout-linux.png differ
diff --git a/playwright/snapshots/timeline/timeline.spec.ts/expanded-gels-irc-layout-linux.png b/playwright/snapshots/timeline/timeline.spec.ts/expanded-gels-irc-layout-linux.png
index 1e50cd3c0fb..d8a5ae40569 100644
Binary files a/playwright/snapshots/timeline/timeline.spec.ts/expanded-gels-irc-layout-linux.png and b/playwright/snapshots/timeline/timeline.spec.ts/expanded-gels-irc-layout-linux.png differ
diff --git a/playwright/snapshots/timeline/timeline.spec.ts/expanded-gels-modern-layout-linux.png b/playwright/snapshots/timeline/timeline.spec.ts/expanded-gels-modern-layout-linux.png
index b81a9d68a86..608b17051dd 100644
Binary files a/playwright/snapshots/timeline/timeline.spec.ts/expanded-gels-modern-layout-linux.png and b/playwright/snapshots/timeline/timeline.spec.ts/expanded-gels-modern-layout-linux.png differ
diff --git a/playwright/snapshots/timeline/timeline.spec.ts/expanded-gels-redaction-placeholder-linux.png b/playwright/snapshots/timeline/timeline.spec.ts/expanded-gels-redaction-placeholder-linux.png
index 58ba6c57033..06aa02cdf8c 100644
Binary files a/playwright/snapshots/timeline/timeline.spec.ts/expanded-gels-redaction-placeholder-linux.png and b/playwright/snapshots/timeline/timeline.spec.ts/expanded-gels-redaction-placeholder-linux.png differ
diff --git a/playwright/snapshots/timeline/timeline.spec.ts/hidden-event-line-padding-modern-layout-linux.png b/playwright/snapshots/timeline/timeline.spec.ts/hidden-event-line-padding-modern-layout-linux.png
new file mode 100644
index 00000000000..efcbba43f95
Binary files /dev/null and b/playwright/snapshots/timeline/timeline.spec.ts/hidden-event-line-padding-modern-layout-linux.png differ
diff --git a/playwright/snapshots/timeline/timeline.spec.ts/hidden-event-line-zero-padding-irc-layout-linux.png b/playwright/snapshots/timeline/timeline.spec.ts/hidden-event-line-zero-padding-irc-layout-linux.png
new file mode 100644
index 00000000000..00c697f9a61
Binary files /dev/null and b/playwright/snapshots/timeline/timeline.spec.ts/hidden-event-line-zero-padding-irc-layout-linux.png differ
diff --git a/playwright/snapshots/user-menu/user-menu.spec.ts/user-menu-linux.png b/playwright/snapshots/user-menu/user-menu.spec.ts/user-menu-linux.png
index bfaa18d4c3e..e2c6718a930 100644
Binary files a/playwright/snapshots/user-menu/user-menu.spec.ts/user-menu-linux.png and b/playwright/snapshots/user-menu/user-menu.spec.ts/user-menu-linux.png differ
diff --git a/playwright/snapshots/user-onboarding/user-onboarding-new.spec.ts/User-Onboarding-new-user-app-download-dialog-1-linux.png b/playwright/snapshots/user-onboarding/user-onboarding-new.spec.ts/User-Onboarding-new-user-app-download-dialog-1-linux.png
deleted file mode 100644
index 024886d01e6..00000000000
Binary files a/playwright/snapshots/user-onboarding/user-onboarding-new.spec.ts/User-Onboarding-new-user-app-download-dialog-1-linux.png and /dev/null differ
diff --git a/playwright/snapshots/user-onboarding/user-onboarding-new.spec.ts/User-Onboarding-new-user-page-is-shown-and-preference-exists-1-linux.png b/playwright/snapshots/user-onboarding/user-onboarding-new.spec.ts/User-Onboarding-new-user-page-is-shown-and-preference-exists-1-linux.png
deleted file mode 100644
index 1042d92e764..00000000000
Binary files a/playwright/snapshots/user-onboarding/user-onboarding-new.spec.ts/User-Onboarding-new-user-page-is-shown-and-preference-exists-1-linux.png and /dev/null differ
diff --git a/playwright/stale-screenshot-reporter.ts b/playwright/stale-screenshot-reporter.ts
index e5fe7edc990..36aba56a071 100644
--- a/playwright/stale-screenshot-reporter.ts
+++ b/playwright/stale-screenshot-reporter.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -20,9 +20,13 @@ const snapshotRoot = path.join(__dirname, "snapshots");
 
 class StaleScreenshotReporter implements Reporter {
     private screenshots = new Set<string>();
+    private failing = false;
     private success = true;
 
     public onTestEnd(test: TestCase): void {
+        if (!test.ok()) {
+            this.failing = true;
+        }
         for (const annotation of test.annotations) {
             if (annotation.type === "_screenshot") {
                 this.screenshots.add(annotation.description);
@@ -39,6 +43,7 @@ class StaleScreenshotReporter implements Reporter {
     }
 
     public async onExit(): Promise<void> {
+        if (this.failing) return;
         const screenshotFiles = new Set(await glob(`**/*.png`, { cwd: snapshotRoot }));
         for (const screenshot of screenshotFiles) {
             if (screenshot.split("-").at(-1) !== "linux.png") {
diff --git a/playwright/testcontainers/HomeserverContainer.ts b/playwright/testcontainers/HomeserverContainer.ts
new file mode 100644
index 00000000000..259ecb7fe0a
--- /dev/null
+++ b/playwright/testcontainers/HomeserverContainer.ts
@@ -0,0 +1,24 @@
+/*
+Copyright 2024 New Vector Ltd.
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+Please see LICENSE files in the repository root for full details.
+*/
+
+import { AbstractStartedContainer, GenericContainer } from "testcontainers";
+import { APIRequestContext, TestInfo } from "@playwright/test";
+
+import { HomeserverInstance } from "../plugins/homeserver";
+import { StartedMatrixAuthenticationServiceContainer } from "./mas.ts";
+
+export interface HomeserverContainer<Config> extends GenericContainer {
+    withConfigField(key: string, value: any): this;
+    withConfig(config: Partial<Config>): this;
+    withMatrixAuthenticationService(mas?: StartedMatrixAuthenticationServiceContainer): this;
+    start(): Promise<StartedHomeserverContainer>;
+}
+
+export interface StartedHomeserverContainer extends AbstractStartedContainer, HomeserverInstance {
+    setRequest(request: APIRequestContext): void;
+    onTestFinished(testInfo: TestInfo): Promise<void>;
+}
diff --git a/playwright/testcontainers/dendrite.ts b/playwright/testcontainers/dendrite.ts
new file mode 100644
index 00000000000..58ab844a7ca
--- /dev/null
+++ b/playwright/testcontainers/dendrite.ts
@@ -0,0 +1,274 @@
+/*
+Copyright 2024 New Vector Ltd.
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+Please see LICENSE files in the repository root for full details.
+*/
+
+import { GenericContainer, Wait } from "testcontainers";
+import * as YAML from "yaml";
+import { set } from "lodash";
+
+import { randB64Bytes } from "../plugins/utils/rand.ts";
+import { StartedSynapseContainer } from "./synapse.ts";
+import { deepCopy } from "../plugins/utils/object.ts";
+import { HomeserverContainer } from "./HomeserverContainer.ts";
+import { StartedMatrixAuthenticationServiceContainer } from "./mas.ts";
+
+const DEFAULT_CONFIG = {
+    version: 2,
+    global: {
+        server_name: "localhost",
+        private_key: "matrix_key.pem",
+        old_private_keys: null,
+        key_validity_period: "168h0m0s",
+        cache: {
+            max_size_estimated: "1gb",
+            max_age: "1h",
+        },
+        well_known_server_name: "",
+        well_known_client_name: "",
+        trusted_third_party_id_servers: ["matrix.org", "vector.im"],
+        disable_federation: false,
+        presence: {
+            enable_inbound: false,
+            enable_outbound: false,
+        },
+        report_stats: {
+            enabled: false,
+            endpoint: "https://matrix.org/report-usage-stats/push",
+        },
+        server_notices: {
+            enabled: false,
+            local_part: "_server",
+            display_name: "Server Alerts",
+            avatar_url: "",
+            room_name: "Server Alerts",
+        },
+        jetstream: {
+            addresses: null,
+            disable_tls_validation: false,
+            storage_path: "./",
+            topic_prefix: "Dendrite",
+        },
+        metrics: {
+            enabled: false,
+            basic_auth: {
+                username: "metrics",
+                password: "metrics",
+            },
+        },
+        dns_cache: {
+            enabled: false,
+            cache_size: 256,
+            cache_lifetime: "5m",
+        },
+    },
+    app_service_api: {
+        disable_tls_validation: false,
+        config_files: null,
+    },
+    client_api: {
+        registration_disabled: false,
+        guests_disabled: true,
+        registration_shared_secret: "secret",
+        enable_registration_captcha: false,
+        recaptcha_public_key: "",
+        recaptcha_private_key: "",
+        recaptcha_bypass_secret: "",
+        turn: {
+            turn_user_lifetime: "5m",
+            turn_uris: null,
+            turn_shared_secret: "",
+        },
+        rate_limiting: {
+            enabled: true,
+            threshold: 20,
+            cooloff_ms: 500,
+            exempt_user_ids: null,
+        },
+    },
+    federation_api: {
+        send_max_retries: 16,
+        disable_tls_validation: false,
+        disable_http_keepalives: false,
+        key_perspectives: [
+            {
+                server_name: "matrix.org",
+                keys: [
+                    {
+                        key_id: "ed25519:auto",
+                        public_key: "Noi6WqcDj0QmPxCNQqgezwTlBKrfqehY1u2FyWP9uYw",
+                    },
+                    {
+                        key_id: "ed25519:a_RXGa",
+                        public_key: "l8Hft5qXKn1vfHrg3p4+W8gELQVo8N13JkluMfmn2sQ",
+                    },
+                ],
+            },
+        ],
+        prefer_direct_fetch: false,
+        database: {
+            connection_string: "file:dendrite-federationapi.db",
+        },
+    },
+    media_api: {
+        base_path: "./media_store",
+        max_file_size_bytes: 10485760,
+        dynamic_thumbnails: false,
+        max_thumbnail_generators: 10,
+        thumbnail_sizes: [
+            {
+                width: 32,
+                height: 32,
+                method: "crop",
+            },
+            {
+                width: 96,
+                height: 96,
+                method: "crop",
+            },
+            {
+                width: 640,
+                height: 480,
+                method: "scale",
+            },
+        ],
+        database: {
+            connection_string: "file:dendrite-mediaapi.db",
+        },
+    },
+    mscs: {
+        mscs: null,
+        database: {
+            connection_string: "file:dendrite-msc.db",
+        },
+    },
+    sync_api: {
+        search: {
+            enabled: false,
+            index_path: "./searchindex",
+            language: "en",
+        },
+        database: {
+            connection_string: "file:dendrite-syncapi.db",
+        },
+    },
+    user_api: {
+        bcrypt_cost: 10,
+        auto_join_rooms: null,
+        account_database: {
+            connection_string: "file:dendrite-userapi.db",
+        },
+    },
+    room_server: {
+        database: {
+            connection_string: "file:dendrite-roomserverapi.db",
+        },
+    },
+    key_server: {
+        database: {
+            connection_string: "file:dendrite-keyserverapi.db",
+        },
+    },
+    relay_api: {
+        database: {
+            connection_string: "file:dendrite-relayapi.db",
+        },
+    },
+    tracing: {
+        enabled: false,
+        jaeger: {
+            serviceName: "",
+            disabled: false,
+            rpc_metrics: false,
+            tags: [],
+            sampler: null,
+            reporter: null,
+            headers: null,
+            baggage_restrictions: null,
+            throttler: null,
+        },
+    },
+    logging: [
+        {
+            type: "std",
+            level: "debug",
+        },
+        {
+            type: "file",
+            level: "debug",
+            params: {
+                path: "./logs",
+            },
+        },
+    ],
+};
+
+export class DendriteContainer extends GenericContainer implements HomeserverContainer<typeof DEFAULT_CONFIG> {
+    private config: typeof DEFAULT_CONFIG;
+
+    constructor(image = "matrixdotorg/dendrite-monolith:main", binary = "/usr/bin/dendrite") {
+        super(image);
+
+        this.config = deepCopy(DEFAULT_CONFIG);
+        this.config.client_api.registration_shared_secret = randB64Bytes(16);
+
+        this.withEntrypoint(["/bin/sh"])
+            .withCommand([
+                "-c",
+                `/usr/bin/generate-keys -private-key /etc/dendrite/matrix_key.pem && ${binary} --config /etc/dendrite/dendrite.yaml --really-enable-open-registration true run`,
+            ])
+            .withExposedPorts(8008)
+            .withWaitStrategy(Wait.forHttp("/_matrix/client/versions", 8008));
+    }
+
+    public withConfigField(key: string, value: any): this {
+        set(this.config, key, value);
+        return this;
+    }
+
+    public withConfig(config: Partial<typeof DEFAULT_CONFIG>): this {
+        this.config = {
+            ...this.config,
+            ...config,
+        };
+        return this;
+    }
+
+    // Dendrite does not support MAS at this time
+    public withMatrixAuthenticationService(mas?: StartedMatrixAuthenticationServiceContainer): this {
+        return this;
+    }
+
+    public override async start(): Promise<StartedDendriteContainer> {
+        this.withCopyContentToContainer([
+            {
+                target: "/etc/dendrite/dendrite.yaml",
+                content: YAML.stringify(this.config),
+            },
+        ]);
+
+        const container = await super.start();
+        return new StartedDendriteContainer(
+            container,
+            `http://${container.getHost()}:${container.getMappedPort(8008)}`,
+            this.config.client_api.registration_shared_secret,
+        );
+    }
+}
+
+export class PineconeContainer extends DendriteContainer {
+    constructor() {
+        super("matrixdotorg/dendrite-demo-pinecone:main", "/usr/bin/dendrite-demo-pinecone");
+    }
+}
+
+// Surprisingly, Dendrite implements the same register user Synapse Admin API, so we can just extend it
+export class StartedDendriteContainer extends StartedSynapseContainer {
+    protected async deletePublicRooms(): Promise<void> {
+        // Dendrite does not support admin users managing the room directory
+        // https://github.com/element-hq/dendrite/blob/main/clientapi/routing/directory.go#L365
+        return;
+    }
+}
diff --git a/playwright/testcontainers/mailhog.ts b/playwright/testcontainers/mailhog.ts
new file mode 100644
index 00000000000..c3305607d89
--- /dev/null
+++ b/playwright/testcontainers/mailhog.ts
@@ -0,0 +1,30 @@
+/*
+Copyright 2024 New Vector Ltd.
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+Please see LICENSE files in the repository root for full details.
+*/
+
+import { AbstractStartedContainer, GenericContainer, StartedTestContainer, Wait } from "testcontainers";
+import mailhog from "mailhog";
+
+export class MailhogContainer extends GenericContainer {
+    constructor() {
+        super("mailhog/mailhog:latest");
+
+        this.withExposedPorts(8025).withWaitStrategy(Wait.forListeningPorts());
+    }
+
+    public override async start(): Promise<StartedMailhogContainer> {
+        return new StartedMailhogContainer(await super.start());
+    }
+}
+
+export class StartedMailhogContainer extends AbstractStartedContainer {
+    public readonly client: mailhog.API;
+
+    constructor(container: StartedTestContainer) {
+        super(container);
+        this.client = mailhog({ host: container.getHost(), port: container.getMappedPort(8025) });
+    }
+}
diff --git a/playwright/testcontainers/mas.ts b/playwright/testcontainers/mas.ts
new file mode 100644
index 00000000000..9b05b521bac
--- /dev/null
+++ b/playwright/testcontainers/mas.ts
@@ -0,0 +1,340 @@
+/*
+Copyright 2024 New Vector Ltd.
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+Please see LICENSE files in the repository root for full details.
+*/
+
+import { AbstractStartedContainer, GenericContainer, StartedTestContainer, Wait, ExecResult } from "testcontainers";
+import { StartedPostgreSqlContainer } from "@testcontainers/postgresql";
+import * as YAML from "yaml";
+
+import { getFreePort } from "../plugins/utils/port.ts";
+import { deepCopy } from "../plugins/utils/object.ts";
+import { Credentials } from "../plugins/homeserver";
+
+const DEFAULT_CONFIG = {
+    http: {
+        listeners: [
+            {
+                name: "web",
+                resources: [
+                    { name: "discovery" },
+                    { name: "human" },
+                    { name: "oauth" },
+                    { name: "compat" },
+                    {
+                        name: "graphql",
+                        playground: true,
+                    },
+                    {
+                        name: "assets",
+                        path: "/usr/local/share/mas-cli/assets/",
+                    },
+                ],
+                binds: [
+                    {
+                        address: "[::]:8080",
+                    },
+                ],
+                proxy_protocol: false,
+            },
+            {
+                name: "internal",
+                resources: [
+                    {
+                        name: "health",
+                    },
+                ],
+                binds: [
+                    {
+                        address: "[::]:8081",
+                    },
+                ],
+                proxy_protocol: false,
+            },
+        ],
+        trusted_proxies: ["192.128.0.0/16", "172.16.0.0/12", "10.0.0.0/10", "127.0.0.1/8", "fd00::/8", "::1/128"],
+        public_base: "", // Needs to be set
+        issuer: "", // Needs to be set
+    },
+    database: {
+        host: "postgres",
+        port: 5432,
+        database: "postgres",
+        username: "postgres",
+        password: "p4S5w0rD",
+        max_connections: 10,
+        min_connections: 0,
+        connect_timeout: 30,
+        idle_timeout: 600,
+        max_lifetime: 1800,
+    },
+    telemetry: {
+        tracing: {
+            exporter: "none",
+            propagators: [],
+        },
+        metrics: {
+            exporter: "none",
+        },
+        sentry: {
+            dsn: null,
+        },
+    },
+    templates: {
+        path: "/usr/local/share/mas-cli/templates/",
+        assets_manifest: "/usr/local/share/mas-cli/manifest.json",
+        translations_path: "/usr/local/share/mas-cli/translations/",
+    },
+    email: {
+        from: '"Authentication Service" <root@localhost>',
+        reply_to: '"Authentication Service" <root@localhost>',
+        transport: "smtp",
+        mode: "plain",
+        hostname: "mailhog",
+        port: 1025,
+        username: "username",
+        password: "password",
+    },
+    secrets: {
+        encryption: "984b18e207c55ad5fbb2a49b217481a722917ee87b2308d4cf314c83fed8e3b5",
+        keys: [
+            {
+                kid: "YEAhzrKipJ",
+                key: "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEAuIV+AW5vx52I4CuumgSxp6yvKfIAnRdALeZZCoFkIGxUli1B\nS79NJ3ls46oLh1pSD9RrhaMp6HTNoi4K3hnP9Q9v77pD7KwdFKG3UdG1zksIB0s/\n+/Ey/DmX4LPluwBBS7r/LkQ1jk745lENA++oiDqZf2D/uP8jCHlvaSNyVKTqi1ki\nOXPd4T4xBUjzuas9ze5jQVSYtfOidgnv1EzUipbIxgvH1jNt4raRlmP8mOq7xEnW\nR+cF5x6n/g17PdSEfrwO4kz6aKGZuMP5lVlDEEnMHKabFSQDBl7+Mpok6jXutbtA\nuiBnsKEahF9eoj4na4fpbRNPdIVyoaN5eGvm5wIDAQABAoIBAApyFCYEmHNWaa83\nCdVSOrRhRDE9r+c0r79pcNT1ajOjrk4qFa4yEC4R46YntCtfY5Hd1pBkIjU0l4d8\nz8Su9WTMEOwjQUEepS7L0NLi6kXZXYT8L40VpGs+32grBvBFHW0qEtQNrHJ36gMv\nx2rXoFTF7HaXiSJx3wvVxAbRqOE9tBXLsmNHaWaAdWQG5o77V9+zvMri3cAeEg2w\nVkKokb0dza7es7xG3tqS26k69SrwGeeuKo7qCHPH2cfyWmY5Yhv8iOoA59JzzbiK\nUdxyzCHskrPSpRKVkVVwmY3RBt282TmSRG7td7e5ESSj50P2e5BI5uu1Hp/dvU4F\nvYjV7kECgYEA6WqYoUpVsgQiqhvJwJIc/8gRm0mUy8TenI36z4Iim01Nt7fibWH7\nXnsFqLGjXtYNVWvBcCrUl9doEnRbJeG2eRGbGKYAWVrOeFvwM4fYvw9GoOiJdDj4\ncgWDe7eHbHE+UTqR7Nnr/UBfipoNWDh6X68HRBuXowh0Q6tOfxsrRFECgYEAyl/V\n4b8bFp3pKZZCb+KPSYsQf793cRmrBexPcLWcDPYbMZQADEZ/VLjbrNrpTOWxUWJT\nhr8MrWswnHO+l5AFu5CNO+QgV2dHLk+2w8qpdpFRPJCfXfo2D3wZ0c4cv3VCwv1V\n5y7f6XWVjDWZYV4wj6c3shxZJjZ+9Hbhf3/twbcCgYA6fuRRR3fCbRbi2qPtBrEN\nyO3gpMgNaQEA6vP4HPzfPrhDWmn8T5nXS61XYW03zxz4U1De81zj0K/cMBzHmZFJ\nNghQXQmpWwBzWVcREvJWr1Vb7erEnaJlsMwKrSvbGWYspSj82oAxr3hCG+lMOpsw\nb4S6pM+TpAK/EqdRY1WsgQKBgQCGoMaaTRXqL9bC0bEU2XVVCWxKb8c3uEmrwQ7/\n/fD4NmjUzI5TnDps1CVfkqoNe+hAKddDFqmKXHqUOfOaxDbsFje+lf5l5tDVoDYH\nfjTKKdYPIm7CiAeauYY7qpA5Vfq52Opixy4yEwUPp0CII67OggFtPaqY3zwJyWQt\n+57hdQKBgGCXM/KKt7ceUDcNJxSGjvu0zD9D5Sv2ihYlEBT/JLaTCCJdvzREevaJ\n1d+mpUAt0Lq6A8NWOMq8HPaxAik3rMQ0WtM5iG+XgsUqvTSb7NcshArDLuWGnW3m\nMC4rM0UBYAS4QweduUSH1imrwH/1Gu5+PxbiecceRMMggWpzu0Bq\n-----END RSA PRIVATE KEY-----\n",
+            },
+            {
+                kid: "8J1AxrlNZT",
+                key: "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIF1cjfIOEdy3BXJ72x6fKpEB8WP1ddZAUJAaqqr/6CpToAoGCCqGSM49\nAwEHoUQDQgAEfHdNuI1Yeh3/uOq2PlnW2vymloOVpwBYebbw4VVsna9xhnutIdQW\ndE8hkX8Yb0pIDasrDiwllVLzSvsWJAI0Kw==\n-----END EC PRIVATE KEY-----\n",
+            },
+            {
+                kid: "3BW6un1EBi",
+                key: "-----BEGIN EC PRIVATE KEY-----\nMIGkAgEBBDA+3ZV17r8TsiMdw1cpbTSNbyEd5SMy3VS1Mk/kz6O2Ev/3QZut8GE2\nq3eGtLBoVQigBwYFK4EEACKhZANiAASs8Wxjk/uRimRKXnPr2/wDaXkN9wMDjYQK\nmZULb+0ZP1/cXmuXuri8hUGhQvIU8KWY9PkpV+LMPEdpE54mHPKSLjq5CDXoSZ/P\n9f7cdRaOZ000KQPZfIFR9ujJTtDN7Vs=\n-----END EC PRIVATE KEY-----\n",
+            },
+            {
+                kid: "pkZ0pTKK0X",
+                key: "-----BEGIN EC PRIVATE KEY-----\nMHQCAQEEIHenfsXYPc5yzjZKUfvmydDR1YRwdsfZYvwHf/2wsYxooAcGBSuBBAAK\noUQDQgAEON1x7Vlu+nA0KvC5vYSOHhDUkfLYNZwYSLPFVT02h9E13yFFMIJegIBl\nAer+6PMZpPc8ycyeH9N+U9NAyliBhQ==\n-----END EC PRIVATE KEY-----\n",
+            },
+        ],
+    },
+    passwords: {
+        enabled: true,
+        schemes: [
+            {
+                version: 1,
+                algorithm: "argon2id",
+            },
+        ],
+        minimum_complexity: 0,
+    },
+    policy: {
+        wasm_module: "/usr/local/share/mas-cli/policy.wasm",
+        client_registration_entrypoint: "client_registration/violation",
+        register_entrypoint: "register/violation",
+        authorization_grant_entrypoint: "authorization_grant/violation",
+        password_entrypoint: "password/violation",
+        email_entrypoint: "email/violation",
+        data: {
+            client_registration: {
+                // allow non-SSL and localhost URIs
+                allow_insecure_uris: true,
+                // EW doesn't have contacts at this time
+                allow_missing_contacts: true,
+            },
+        },
+    },
+    upstream_oauth2: {
+        providers: [],
+    },
+    branding: {
+        service_name: null,
+        policy_uri: null,
+        tos_uri: null,
+        imprint: null,
+        logo_uri: null,
+    },
+    account: {
+        password_registration_enabled: true,
+    },
+    experimental: {
+        access_token_ttl: 300,
+        compat_token_ttl: 300,
+    },
+    rate_limiting: {
+        login: {
+            burst: 10,
+            per_second: 1,
+        },
+        registration: {
+            burst: 10,
+            per_second: 1,
+        },
+    },
+};
+
+export class MatrixAuthenticationServiceContainer extends GenericContainer {
+    private config: typeof DEFAULT_CONFIG;
+    private readonly args = ["-c", "/config/config.yaml"];
+
+    constructor(db: StartedPostgreSqlContainer) {
+        // We rely on `mas-cli manage add-email` which isn't in a release yet
+        // https://github.com/element-hq/matrix-authentication-service/pull/3235
+        super("ghcr.io/element-hq/matrix-authentication-service:sha-0b90c33");
+
+        this.config = deepCopy(DEFAULT_CONFIG);
+        this.config.database.username = db.getUsername();
+        this.config.database.password = db.getPassword();
+
+        this.withExposedPorts(8080, 8081)
+            .withWaitStrategy(Wait.forHttp("/health", 8081))
+            .withCommand(["server", ...this.args]);
+    }
+
+    public withConfig(config: object): this {
+        this.config = {
+            ...this.config,
+            ...config,
+        };
+        return this;
+    }
+
+    public override async start(): Promise<StartedMatrixAuthenticationServiceContainer> {
+        // MAS config issuer needs to know what URL it'll be accessed from, so we have to map the port manually
+        const port = await getFreePort();
+
+        this.config.http.public_base = `http://localhost:${port}/`;
+        this.config.http.issuer = `http://localhost:${port}/`;
+
+        this.withExposedPorts({
+            container: 8080,
+            host: port,
+        }).withCopyContentToContainer([
+            {
+                target: "/config/config.yaml",
+                content: YAML.stringify(this.config),
+            },
+        ]);
+
+        return new StartedMatrixAuthenticationServiceContainer(
+            await super.start(),
+            `http://localhost:${port}`,
+            this.args,
+        );
+    }
+}
+
+export class StartedMatrixAuthenticationServiceContainer extends AbstractStartedContainer {
+    private adminTokenPromise?: Promise<string>;
+
+    constructor(
+        container: StartedTestContainer,
+        public readonly baseUrl: string,
+        private readonly args: string[],
+    ) {
+        super(container);
+    }
+
+    public async getAdminToken(): Promise<string> {
+        if (this.adminTokenPromise === undefined) {
+            this.adminTokenPromise = this.registerUserInternal(
+                "admin",
+                "totalyinsecureadminpassword",
+                undefined,
+                true,
+            ).then((res) => res.accessToken);
+        }
+        return this.adminTokenPromise;
+    }
+
+    private async manage(cmd: string, ...args: string[]): Promise<ExecResult> {
+        const result = await this.exec(["mas-cli", "manage", cmd, ...this.args, ...args]);
+        if (result.exitCode !== 0) {
+            throw new Error(`Failed mas-cli manage ${cmd}: ${result.output}`);
+        }
+        return result;
+    }
+
+    private async manageRegisterUser(
+        username: string,
+        password: string,
+        displayName?: string,
+        admin = false,
+    ): Promise<string> {
+        const args: string[] = [];
+        if (admin) args.push("-a");
+        const result = await this.manage(
+            "register-user",
+            ...args,
+            "-y",
+            "-p",
+            password,
+            "-d",
+            displayName ?? "",
+            username,
+        );
+
+        const registerLines = result.output.trim().split("\n");
+        const userId = registerLines
+            .find((line) => line.includes("Matrix ID: "))
+            ?.split(": ")
+            .pop();
+
+        if (!userId) {
+            throw new Error(`Failed to register user: ${result.output}`);
+        }
+
+        return userId;
+    }
+
+    private async manageIssueCompatibilityToken(
+        username: string,
+        admin = false,
+    ): Promise<{ accessToken: string; deviceId: string }> {
+        const args: string[] = [];
+        if (admin) args.push("--yes-i-want-to-grant-synapse-admin-privileges");
+        const result = await this.manage("issue-compatibility-token", ...args, username);
+
+        const parts = result.output.trim().split(/\s+/);
+        const accessToken = parts.find((part) => part.startsWith("mct_"));
+        const deviceId = parts.find((part) => part.startsWith("compat_session.device="))?.split("=")[1];
+
+        if (!accessToken || !deviceId) {
+            throw new Error(`Failed to issue compatibility token: ${result.output}`);
+        }
+
+        return { accessToken, deviceId };
+    }
+
+    private async registerUserInternal(
+        username: string,
+        password: string,
+        displayName?: string,
+        admin = false,
+    ): Promise<Credentials> {
+        const userId = await this.manageRegisterUser(username, password, displayName, admin);
+        const { deviceId, accessToken } = await this.manageIssueCompatibilityToken(username, admin);
+
+        return {
+            userId,
+            accessToken,
+            deviceId,
+            homeServer: userId.slice(1).split(":").slice(1).join(":"),
+            displayName,
+            username,
+            password,
+        };
+    }
+
+    public async registerUser(username: string, password: string, displayName?: string): Promise<Credentials> {
+        return this.registerUserInternal(username, password, displayName, false);
+    }
+
+    public async setThreepid(username: string, medium: string, address: string): Promise<void> {
+        if (medium !== "email") {
+            throw new Error("Only email threepids are supported by MAS");
+        }
+
+        await this.manage("add-email", username, address);
+    }
+}
diff --git a/playwright/testcontainers/synapse.ts b/playwright/testcontainers/synapse.ts
new file mode 100644
index 00000000000..72715b666b0
--- /dev/null
+++ b/playwright/testcontainers/synapse.ts
@@ -0,0 +1,388 @@
+/*
+Copyright 2024 New Vector Ltd.
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+Please see LICENSE files in the repository root for full details.
+*/
+
+import { AbstractStartedContainer, GenericContainer, RestartOptions, StartedTestContainer, Wait } from "testcontainers";
+import { APIRequestContext, TestInfo } from "@playwright/test";
+import crypto from "node:crypto";
+import * as YAML from "yaml";
+import { set } from "lodash";
+
+import { getFreePort } from "../plugins/utils/port.ts";
+import { randB64Bytes } from "../plugins/utils/rand.ts";
+import { Credentials } from "../plugins/homeserver";
+import { deepCopy } from "../plugins/utils/object.ts";
+import { HomeserverContainer, StartedHomeserverContainer } from "./HomeserverContainer.ts";
+import { StartedMatrixAuthenticationServiceContainer } from "./mas.ts";
+import { Api, ClientServerApi, Verb } from "../plugins/utils/api.ts";
+
+const TAG = "develop@sha256:436278578c6b396d3a581f6af020edaff37dd7c3d26d20362de9e05e4a70cee8";
+
+const DEFAULT_CONFIG = {
+    server_name: "localhost",
+    public_baseurl: "", // set by start method
+    pid_file: "/homeserver.pid",
+    web_client: false,
+    soft_file_limit: 0,
+    // Needs to be configured to log to the console like a good docker process
+    log_config: "/data/log.config",
+    listeners: [
+        {
+            // Listener is always port 8008 (configured in the container)
+            port: 8008,
+            tls: false,
+            bind_addresses: ["::"],
+            type: "http",
+            x_forwarded: true,
+            resources: [
+                {
+                    names: ["client"],
+                    compress: false,
+                },
+            ],
+        },
+    ],
+    database: {
+        // An sqlite in-memory database is fast & automatically wipes each time
+        name: "sqlite3",
+        args: {
+            database: ":memory:",
+        },
+    },
+    rc_messages_per_second: 10000,
+    rc_message_burst_count: 10000,
+    rc_registration: {
+        per_second: 10000,
+        burst_count: 10000,
+    },
+    rc_joins: {
+        local: {
+            per_second: 9999,
+            burst_count: 9999,
+        },
+        remote: {
+            per_second: 9999,
+            burst_count: 9999,
+        },
+    },
+    rc_joins_per_room: {
+        per_second: 9999,
+        burst_count: 9999,
+    },
+    rc_3pid_validation: {
+        per_second: 1000,
+        burst_count: 1000,
+    },
+    rc_invites: {
+        per_room: {
+            per_second: 1000,
+            burst_count: 1000,
+        },
+        per_user: {
+            per_second: 1000,
+            burst_count: 1000,
+        },
+    },
+    rc_login: {
+        address: {
+            per_second: 10000,
+            burst_count: 10000,
+        },
+        account: {
+            per_second: 10000,
+            burst_count: 10000,
+        },
+        failed_attempts: {
+            per_second: 10000,
+            burst_count: 10000,
+        },
+    },
+    media_store_path: "/tmp/media_store",
+    max_upload_size: "50M",
+    max_image_pixels: "32M",
+    dynamic_thumbnails: false,
+    enable_registration: true,
+    enable_registration_without_verification: true,
+    disable_msisdn_registration: false,
+    registrations_require_3pid: [],
+    enable_metrics: false,
+    report_stats: false,
+    // These placeholders will be replaced with values generated at start
+    registration_shared_secret: "secret",
+    macaroon_secret_key: "secret",
+    form_secret: "secret",
+    // Signing key must be here: it will be generated to this file
+    signing_key_path: "/data/localhost.signing.key",
+    trusted_key_servers: [],
+    password_config: {
+        enabled: true,
+    },
+    ui_auth: {},
+    background_updates: {
+        // Inhibit background updates as this Synapse isn't long-lived
+        min_batch_size: 100000,
+        sleep_duration_ms: 100000,
+    },
+    enable_authenticated_media: true,
+    email: undefined,
+    user_consent: undefined,
+    server_notices: undefined,
+    allow_guest_access: false,
+    experimental_features: {},
+    oidc_providers: [],
+    serve_server_wellknown: true,
+    presence: {
+        enabled: true,
+        include_offline_users_on_sync: true,
+    },
+};
+
+export type SynapseConfig = Partial<typeof DEFAULT_CONFIG>;
+
+export class SynapseContainer extends GenericContainer implements HomeserverContainer<typeof DEFAULT_CONFIG> {
+    private config: typeof DEFAULT_CONFIG;
+    private mas?: StartedMatrixAuthenticationServiceContainer;
+
+    constructor() {
+        super(`ghcr.io/element-hq/synapse:${TAG}`);
+
+        this.config = deepCopy(DEFAULT_CONFIG);
+        this.config.registration_shared_secret = randB64Bytes(16);
+        this.config.macaroon_secret_key = randB64Bytes(16);
+        this.config.form_secret = randB64Bytes(16);
+
+        const signingKey = randB64Bytes(32);
+        this.withWaitStrategy(Wait.forHttp("/health", 8008)).withCopyContentToContainer([
+            { target: this.config.signing_key_path, content: `ed25519 x ${signingKey}` },
+            {
+                target: this.config.log_config,
+                content: YAML.stringify({
+                    version: 1,
+                    formatters: {
+                        precise: {
+                            format: "%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s",
+                        },
+                    },
+                    handlers: {
+                        console: {
+                            class: "logging.StreamHandler",
+                            formatter: "precise",
+                        },
+                    },
+                    loggers: {
+                        "synapse.storage.SQL": {
+                            level: "DEBUG",
+                        },
+                        "twisted": {
+                            handlers: ["console"],
+                            propagate: false,
+                        },
+                    },
+                    root: {
+                        level: "DEBUG",
+                        handlers: ["console"],
+                    },
+                    disable_existing_loggers: false,
+                }),
+            },
+        ]);
+    }
+
+    public withConfigField(key: string, value: any): this {
+        set(this.config, key, value);
+        return this;
+    }
+
+    public withConfig(config: Partial<typeof DEFAULT_CONFIG>): this {
+        this.config = {
+            ...this.config,
+            ...config,
+        };
+        return this;
+    }
+
+    public withMatrixAuthenticationService(mas?: StartedMatrixAuthenticationServiceContainer): this {
+        this.mas = mas;
+        return this;
+    }
+
+    public override async start(): Promise<StartedSynapseContainer> {
+        // Synapse config public_baseurl needs to know what URL it'll be accessed from, so we have to map the port manually
+        const port = await getFreePort();
+
+        this.withExposedPorts({
+            container: 8008,
+            host: port,
+        })
+            .withConfig({
+                public_baseurl: `http://localhost:${port}`,
+            })
+            .withCopyContentToContainer([
+                {
+                    target: "/data/homeserver.yaml",
+                    content: YAML.stringify(this.config),
+                },
+            ]);
+
+        const container = await super.start();
+        const baseUrl = `http://localhost:${port}`;
+        if (this.mas) {
+            return new StartedSynapseWithMasContainer(
+                container,
+                baseUrl,
+                this.config.registration_shared_secret,
+                this.mas,
+            );
+        }
+
+        return new StartedSynapseContainer(container, baseUrl, this.config.registration_shared_secret);
+    }
+}
+
+export class StartedSynapseContainer extends AbstractStartedContainer implements StartedHomeserverContainer {
+    protected adminTokenPromise?: Promise<string>;
+    protected readonly adminApi: Api;
+    public readonly csApi: ClientServerApi;
+
+    constructor(
+        container: StartedTestContainer,
+        public readonly baseUrl: string,
+        private readonly registrationSharedSecret: string,
+    ) {
+        super(container);
+        this.adminApi = new Api(`${this.baseUrl}/_synapse/admin`);
+        this.csApi = new ClientServerApi(this.baseUrl);
+    }
+
+    public restart(options?: Partial<RestartOptions>): Promise<void> {
+        this.adminTokenPromise = undefined;
+        return super.restart(options);
+    }
+
+    public setRequest(request: APIRequestContext): void {
+        this.csApi.setRequest(request);
+        this.adminApi.setRequest(request);
+    }
+
+    public async onTestFinished(testInfo: TestInfo): Promise<void> {
+        // Clean up the server to prevent rooms leaking between tests
+        await this.deletePublicRooms();
+    }
+
+    protected async deletePublicRooms(): Promise<void> {
+        const token = await this.getAdminToken();
+        // We hide the rooms from the room directory to save time between tests and for portability between homeservers
+        const { chunk: rooms } = await this.csApi.request<{
+            chunk: { room_id: string }[];
+        }>("GET", "/v3/publicRooms", token, {});
+        await Promise.all(
+            rooms.map((room) =>
+                this.csApi.request("PUT", `/v3/directory/list/room/${room.room_id}`, token, { visibility: "private" }),
+            ),
+        );
+    }
+
+    private async registerUserInternal(
+        username: string,
+        password: string,
+        displayName?: string,
+        admin = false,
+    ): Promise<Credentials> {
+        const path = "/v1/register";
+        const { nonce } = await this.adminApi.request<{ nonce: string }>("GET", path, undefined, {});
+        const mac = crypto
+            .createHmac("sha1", this.registrationSharedSecret)
+            .update(`${nonce}\0${username}\0${password}\0${admin ? "" : "not"}admin`)
+            .digest("hex");
+        const data = await this.adminApi.request<{
+            home_server: string;
+            access_token: string;
+            user_id: string;
+            device_id: string;
+        }>("POST", path, undefined, {
+            nonce,
+            username,
+            password,
+            mac,
+            admin,
+            displayname: displayName,
+        });
+
+        return {
+            homeServer: data.home_server || data.user_id.split(":").slice(1).join(":"),
+            accessToken: data.access_token,
+            userId: data.user_id,
+            deviceId: data.device_id,
+            password,
+            displayName,
+            username,
+        };
+    }
+
+    protected async getAdminToken(): Promise<string> {
+        if (this.adminTokenPromise === undefined) {
+            this.adminTokenPromise = this.registerUserInternal(
+                "admin",
+                "totalyinsecureadminpassword",
+                undefined,
+                true,
+            ).then((res) => res.accessToken);
+        }
+        return this.adminTokenPromise;
+    }
+
+    private async adminRequest<R extends {}>(verb: "GET", path: string, data?: never): Promise<R>;
+    private async adminRequest<R extends {}>(verb: Verb, path: string, data?: object): Promise<R>;
+    private async adminRequest<R extends {}>(verb: Verb, path: string, data?: object): Promise<R> {
+        const adminToken = await this.getAdminToken();
+        return this.adminApi.request(verb, path, adminToken, data);
+    }
+
+    public registerUser(username: string, password: string, displayName?: string): Promise<Credentials> {
+        return this.registerUserInternal(username, password, displayName, false);
+    }
+
+    public async loginUser(userId: string, password: string): Promise<Credentials> {
+        return this.csApi.loginUser(userId, password);
+    }
+
+    public async setThreepid(userId: string, medium: string, address: string): Promise<void> {
+        await this.adminRequest("PUT", `/v2/users/${userId}`, {
+            threepids: [
+                {
+                    medium,
+                    address,
+                },
+            ],
+        });
+    }
+}
+
+export class StartedSynapseWithMasContainer extends StartedSynapseContainer {
+    constructor(
+        container: StartedTestContainer,
+        baseUrl: string,
+        registrationSharedSecret: string,
+        private readonly mas: StartedMatrixAuthenticationServiceContainer,
+    ) {
+        super(container, baseUrl, registrationSharedSecret);
+    }
+
+    protected async getAdminToken(): Promise<string> {
+        if (this.adminTokenPromise === undefined) {
+            this.adminTokenPromise = this.mas.getAdminToken();
+        }
+        return this.adminTokenPromise;
+    }
+
+    public registerUser(username: string, password: string, displayName?: string): Promise<Credentials> {
+        return this.mas.registerUser(username, password, displayName);
+    }
+
+    public async setThreepid(userId: string, medium: string, address: string): Promise<void> {
+        return this.mas.setThreepid(userId, medium, address);
+    }
+}
diff --git a/recorder-worklet-loader.js b/recorder-worklet-loader.js
index 41fe8b3b4e9..1717166ae06 100644
--- a/recorder-worklet-loader.js
+++ b/recorder-worklet-loader.js
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/_animations.pcss b/res/css/_animations.pcss
index f78d8143f5f..97fd0443313 100644
--- a/res/css/_animations.pcss
+++ b/res/css/_animations.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/_common.pcss b/res/css/_common.pcss
index 74328af39b2..fe8eff22860 100644
--- a/res/css/_common.pcss
+++ b/res/css/_common.pcss
@@ -5,7 +5,7 @@ Copyright 2017-2019 New Vector Ltd
 Copyright 2017 Vector Creations Ltd
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -596,7 +596,9 @@ legend {
 .mx_Dialog
     button:not(.mx_Dialog_nonDialogButton):not([class|="maplibregl"]):not(.mx_AccessibleButton):not(
         .mx_UserProfileSettings button
-    ):not(.mx_ThemeChoicePanel_CustomTheme button):not(.mx_UnpinAllDialog button):not(.mx_ShareDialog button),
+    ):not(.mx_ThemeChoicePanel_CustomTheme button):not(.mx_UnpinAllDialog button):not(.mx_ShareDialog button):not(
+        .mx_EncryptionUserSettingsTab button
+    ),
 .mx_Dialog input[type="submit"],
 .mx_Dialog_buttons button:not(.mx_Dialog_nonDialogButton):not(.mx_AccessibleButton),
 .mx_Dialog_buttons input[type="submit"] {
@@ -616,8 +618,8 @@ legend {
 .mx_Dialog
     button:not(.mx_Dialog_nonDialogButton):not([class|="maplibregl"]):not(.mx_AccessibleButton):not(
         .mx_UserProfileSettings button
-    ):not(.mx_ThemeChoicePanel_CustomTheme button):not(.mx_UnpinAllDialog button):not(
-        .mx_ShareDialog button
+    ):not(.mx_ThemeChoicePanel_CustomTheme button):not(.mx_UnpinAllDialog button):not(.mx_ShareDialog button):not(
+        .mx_EncryptionUserSettingsTab button
     ):last-child {
     margin-right: 0px;
 }
@@ -625,7 +627,9 @@ legend {
 .mx_Dialog
     button:not(.mx_Dialog_nonDialogButton):not([class|="maplibregl"]):not(.mx_AccessibleButton):not(
         .mx_UserProfileSettings button
-    ):not(.mx_ThemeChoicePanel_CustomTheme button):not(.mx_UnpinAllDialog button):not(.mx_ShareDialog button):focus,
+    ):not(.mx_ThemeChoicePanel_CustomTheme button):not(.mx_UnpinAllDialog button):not(.mx_ShareDialog button):not(
+        .mx_EncryptionUserSettingsTab button
+    ):focus,
 .mx_Dialog input[type="submit"]:focus,
 .mx_Dialog_buttons button:not(.mx_Dialog_nonDialogButton):not(.mx_AccessibleButton):focus,
 .mx_Dialog_buttons input[type="submit"]:focus {
@@ -637,7 +641,9 @@ legend {
 .mx_Dialog_buttons
     button.mx_Dialog_primary:not(.mx_Dialog_nonDialogButton):not(.mx_AccessibleButton):not(
         .mx_UserProfileSettings button
-    ):not(.mx_ThemeChoicePanel_CustomTheme button):not(.mx_UnpinAllDialog button):not(.mx_ShareDialog button),
+    ):not(.mx_ThemeChoicePanel_CustomTheme button):not(.mx_UnpinAllDialog button):not(.mx_ShareDialog button):not(
+        .mx_EncryptionUserSettingsTab button
+    ),
 .mx_Dialog_buttons input[type="submit"].mx_Dialog_primary {
     color: var(--cpd-color-text-on-solid-primary);
     background-color: var(--cpd-color-bg-action-primary-rest);
@@ -650,7 +656,7 @@ legend {
 .mx_Dialog_buttons
     button.danger:not(.mx_Dialog_nonDialogButton):not(.mx_AccessibleButton):not(.mx_UserProfileSettings button):not(
         .mx_ThemeChoicePanel_CustomTheme button
-    ):not(.mx_UnpinAllDialog button):not(.mx_ShareDialog button),
+    ):not(.mx_UnpinAllDialog button):not(.mx_ShareDialog button):not(.mx_EncryptionUserSettingsTab button),
 .mx_Dialog_buttons input[type="submit"].danger {
     background-color: var(--cpd-color-bg-critical-primary);
     border: solid 1px var(--cpd-color-bg-critical-primary);
@@ -666,7 +672,9 @@ legend {
 .mx_Dialog
     button:not(.mx_Dialog_nonDialogButton):not([class|="maplibregl"]):not(.mx_AccessibleButton):not(
         .mx_UserProfileSettings button
-    ):not(.mx_ThemeChoicePanel_CustomTheme button):not(.mx_UnpinAllDialog button):not(.mx_ShareDialog button):disabled,
+    ):not(.mx_ThemeChoicePanel_CustomTheme button):not(.mx_UnpinAllDialog button):not(.mx_ShareDialog button):not(
+        .mx_EncryptionUserSettingsTab button
+    ):disabled,
 .mx_Dialog input[type="submit"]:disabled,
 .mx_Dialog_buttons button:not(.mx_Dialog_nonDialogButton):not(.mx_AccessibleButton):disabled,
 .mx_Dialog_buttons input[type="submit"]:disabled {
diff --git a/res/css/_components.pcss b/res/css/_components.pcss
index e9a53cd43cc..e0f9a5788de 100644
--- a/res/css/_components.pcss
+++ b/res/css/_components.pcss
@@ -126,7 +126,6 @@
 @import "./views/context_menus/_RoomNotificationContextMenu.pcss";
 @import "./views/dialogs/_AddExistingToSpaceDialog.pcss";
 @import "./views/dialogs/_AnalyticsLearnMoreDialog.pcss";
-@import "./views/dialogs/_AppDownloadDialog.pcss";
 @import "./views/dialogs/_BugReportDialog.pcss";
 @import "./views/dialogs/_BulkRedactDialog.pcss";
 @import "./views/dialogs/_ChangelogDialog.pcss";
@@ -217,8 +216,6 @@
 @import "./views/elements/_TagComposer.pcss";
 @import "./views/elements/_TextWithTooltip.pcss";
 @import "./views/elements/_ToggleSwitch.pcss";
-@import "./views/elements/_UseCaseSelection.pcss";
-@import "./views/elements/_UseCaseSelectionButton.pcss";
 @import "./views/elements/_Validation.pcss";
 @import "./views/emojipicker/_EmojiPicker.pcss";
 @import "./views/location/_LocationPicker.pcss";
@@ -278,9 +275,9 @@
 @import "./views/rooms/_CallGuestLinkButton.pcss";
 @import "./views/rooms/_DecryptionFailureBar.pcss";
 @import "./views/rooms/_E2EIcon.pcss";
+@import "./views/rooms/_E2EIconView.pcss";
 @import "./views/rooms/_EditMessageComposer.pcss";
 @import "./views/rooms/_EmojiButton.pcss";
-@import "./views/rooms/_EntityTile.pcss";
 @import "./views/rooms/_EventBubbleTile.pcss";
 @import "./views/rooms/_EventPreview.pcss";
 @import "./views/rooms/_EventTile.pcss";
@@ -290,13 +287,17 @@
 @import "./views/rooms/_LinkPreviewGroup.pcss";
 @import "./views/rooms/_LinkPreviewWidget.pcss";
 @import "./views/rooms/_LiveContentSummary.pcss";
-@import "./views/rooms/_MemberList.pcss";
+@import "./views/rooms/_MemberListHeaderView.pcss";
+@import "./views/rooms/_MemberListView.pcss";
+@import "./views/rooms/_MemberTileView.pcss";
 @import "./views/rooms/_MessageComposer.pcss";
 @import "./views/rooms/_MessageComposerFormatBar.pcss";
 @import "./views/rooms/_NewRoomIntro.pcss";
 @import "./views/rooms/_NotificationBadge.pcss";
+@import "./views/rooms/_OverflowTile.pcss";
 @import "./views/rooms/_PinnedEventTile.pcss";
 @import "./views/rooms/_PinnedMessageBanner.pcss";
+@import "./views/rooms/_PresenceIconView.pcss";
 @import "./views/rooms/_PresenceLabel.pcss";
 @import "./views/rooms/_ReadReceiptGroup.pcss";
 @import "./views/rooms/_ReplyPreview.pcss";
@@ -346,10 +347,14 @@
 @import "./views/settings/_SetIdServer.pcss";
 @import "./views/settings/_SetIntegrationManager.pcss";
 @import "./views/settings/_SettingsFieldset.pcss";
+@import "./views/settings/_SettingsHeader.pcss";
+@import "./views/settings/_SettingsSubheader.pcss";
 @import "./views/settings/_SpellCheckLanguages.pcss";
 @import "./views/settings/_ThemeChoicePanel.pcss";
 @import "./views/settings/_UpdateCheckButton.pcss";
 @import "./views/settings/_UserProfileSettings.pcss";
+@import "./views/settings/encryption/_ChangeRecoveryKey.pcss";
+@import "./views/settings/encryption/_EncryptionCard.pcss";
 @import "./views/settings/tabs/_SettingsBanner.pcss";
 @import "./views/settings/tabs/_SettingsIndent.pcss";
 @import "./views/settings/tabs/_SettingsSection.pcss";
@@ -375,11 +380,6 @@
 @import "./views/toasts/_IncomingLegacyCallToast.pcss";
 @import "./views/toasts/_NonUrgentEchoFailureToast.pcss";
 @import "./views/typography/_Heading.pcss";
-@import "./views/user-onboarding/_UserOnboardingButton.pcss";
-@import "./views/user-onboarding/_UserOnboardingHeader.pcss";
-@import "./views/user-onboarding/_UserOnboardingList.pcss";
-@import "./views/user-onboarding/_UserOnboardingPage.pcss";
-@import "./views/user-onboarding/_UserOnboardingTask.pcss";
 @import "./views/verification/_VerificationShowSas.pcss";
 @import "./views/voip/LegacyCallView/_LegacyCallViewButtons.pcss";
 @import "./views/voip/_CallDuration.pcss";
diff --git a/res/css/_font-sizes.pcss b/res/css/_font-sizes.pcss
index eb6ac362a67..528cc3c4621 100644
--- a/res/css/_font-sizes.pcss
+++ b/res/css/_font-sizes.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/_spacing.pcss b/res/css/_spacing.pcss
index 2fbc380e6a4..5887204c31c 100644
--- a/res/css/_spacing.pcss
+++ b/res/css/_spacing.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/beacon/_BeaconListItem.pcss b/res/css/components/views/beacon/_BeaconListItem.pcss
index 8090f55ca3e..9b3d0dd88fd 100644
--- a/res/css/components/views/beacon/_BeaconListItem.pcss
+++ b/res/css/components/views/beacon/_BeaconListItem.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/beacon/_BeaconStatus.pcss b/res/css/components/views/beacon/_BeaconStatus.pcss
index 7dfd401aa96..52d27bea614 100644
--- a/res/css/components/views/beacon/_BeaconStatus.pcss
+++ b/res/css/components/views/beacon/_BeaconStatus.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/beacon/_BeaconStatusTooltip.pcss b/res/css/components/views/beacon/_BeaconStatusTooltip.pcss
index e5ee11ee5e3..8b5ef93eb13 100644
--- a/res/css/components/views/beacon/_BeaconStatusTooltip.pcss
+++ b/res/css/components/views/beacon/_BeaconStatusTooltip.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/beacon/_BeaconViewDialog.pcss b/res/css/components/views/beacon/_BeaconViewDialog.pcss
index 71a276a62f7..8883aa4f091 100644
--- a/res/css/components/views/beacon/_BeaconViewDialog.pcss
+++ b/res/css/components/views/beacon/_BeaconViewDialog.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/beacon/_DialogOwnBeaconStatus.pcss b/res/css/components/views/beacon/_DialogOwnBeaconStatus.pcss
index 3e71001ebd2..b9b02c284ea 100644
--- a/res/css/components/views/beacon/_DialogOwnBeaconStatus.pcss
+++ b/res/css/components/views/beacon/_DialogOwnBeaconStatus.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/beacon/_DialogSidebar.pcss b/res/css/components/views/beacon/_DialogSidebar.pcss
index 577a8f19c18..7c882c2da8f 100644
--- a/res/css/components/views/beacon/_DialogSidebar.pcss
+++ b/res/css/components/views/beacon/_DialogSidebar.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/beacon/_LeftPanelLiveShareWarning.pcss b/res/css/components/views/beacon/_LeftPanelLiveShareWarning.pcss
index 83fd0f3fe44..4a8fce98f6a 100644
--- a/res/css/components/views/beacon/_LeftPanelLiveShareWarning.pcss
+++ b/res/css/components/views/beacon/_LeftPanelLiveShareWarning.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/beacon/_LiveTimeRemaining.pcss b/res/css/components/views/beacon/_LiveTimeRemaining.pcss
index a91fa29bc1a..4fe954e6a49 100644
--- a/res/css/components/views/beacon/_LiveTimeRemaining.pcss
+++ b/res/css/components/views/beacon/_LiveTimeRemaining.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/beacon/_OwnBeaconStatus.pcss b/res/css/components/views/beacon/_OwnBeaconStatus.pcss
index e94e07c50c6..331c404d1d3 100644
--- a/res/css/components/views/beacon/_OwnBeaconStatus.pcss
+++ b/res/css/components/views/beacon/_OwnBeaconStatus.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/beacon/_ShareLatestLocation.pcss b/res/css/components/views/beacon/_ShareLatestLocation.pcss
index aed3bc7cb97..ada69fddc12 100644
--- a/res/css/components/views/beacon/_ShareLatestLocation.pcss
+++ b/res/css/components/views/beacon/_ShareLatestLocation.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/beacon/_StyledLiveBeaconIcon.pcss b/res/css/components/views/beacon/_StyledLiveBeaconIcon.pcss
index 89c35791ffb..9a1d84bf43c 100644
--- a/res/css/components/views/beacon/_StyledLiveBeaconIcon.pcss
+++ b/res/css/components/views/beacon/_StyledLiveBeaconIcon.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/context_menus/_KebabContextMenu.pcss b/res/css/components/views/context_menus/_KebabContextMenu.pcss
index 21136d01e3b..18a01f0f6aa 100644
--- a/res/css/components/views/context_menus/_KebabContextMenu.pcss
+++ b/res/css/components/views/context_menus/_KebabContextMenu.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/dialogs/polls/_PollDetailHeader.pcss b/res/css/components/views/dialogs/polls/_PollDetailHeader.pcss
index 0b31b700e23..56c11740ef0 100644
--- a/res/css/components/views/dialogs/polls/_PollDetailHeader.pcss
+++ b/res/css/components/views/dialogs/polls/_PollDetailHeader.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/dialogs/polls/_PollListItem.pcss b/res/css/components/views/dialogs/polls/_PollListItem.pcss
index 568d1ad7127..6cb46a21d2d 100644
--- a/res/css/components/views/dialogs/polls/_PollListItem.pcss
+++ b/res/css/components/views/dialogs/polls/_PollListItem.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/dialogs/polls/_PollListItemEnded.pcss b/res/css/components/views/dialogs/polls/_PollListItemEnded.pcss
index 05734c1e773..772b47c9a49 100644
--- a/res/css/components/views/dialogs/polls/_PollListItemEnded.pcss
+++ b/res/css/components/views/dialogs/polls/_PollListItemEnded.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/elements/_AppPermission.pcss b/res/css/components/views/elements/_AppPermission.pcss
index 0891d25221b..fb7f2a7b707 100644
--- a/res/css/components/views/elements/_AppPermission.pcss
+++ b/res/css/components/views/elements/_AppPermission.pcss
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019-2023 The Matrix.org Foundation C.I.C.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/elements/_AppWarning.pcss b/res/css/components/views/elements/_AppWarning.pcss
index 9cba3020d5e..099d35ce4af 100644
--- a/res/css/components/views/elements/_AppWarning.pcss
+++ b/res/css/components/views/elements/_AppWarning.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 Suguru Hirahara
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/elements/_FilterDropdown.pcss b/res/css/components/views/elements/_FilterDropdown.pcss
index ed9f78e1bea..a2682213c66 100644
--- a/res/css/components/views/elements/_FilterDropdown.pcss
+++ b/res/css/components/views/elements/_FilterDropdown.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/elements/_FilterTabGroup.pcss b/res/css/components/views/elements/_FilterTabGroup.pcss
index da469ca65a8..e2b2aba2652 100644
--- a/res/css/components/views/elements/_FilterTabGroup.pcss
+++ b/res/css/components/views/elements/_FilterTabGroup.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/elements/_LearnMore.pcss b/res/css/components/views/elements/_LearnMore.pcss
index 388a8254ded..e6fb16ec65e 100644
--- a/res/css/components/views/elements/_LearnMore.pcss
+++ b/res/css/components/views/elements/_LearnMore.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/location/_EnableLiveShare.pcss b/res/css/components/views/location/_EnableLiveShare.pcss
index 4799dda0d2b..9e56fa8dc52 100644
--- a/res/css/components/views/location/_EnableLiveShare.pcss
+++ b/res/css/components/views/location/_EnableLiveShare.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/location/_LiveDurationDropdown.pcss b/res/css/components/views/location/_LiveDurationDropdown.pcss
index 0166109943c..fa292918773 100644
--- a/res/css/components/views/location/_LiveDurationDropdown.pcss
+++ b/res/css/components/views/location/_LiveDurationDropdown.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/location/_LocationShareMenu.pcss b/res/css/components/views/location/_LocationShareMenu.pcss
index e1c10401f2c..d34578830fa 100644
--- a/res/css/components/views/location/_LocationShareMenu.pcss
+++ b/res/css/components/views/location/_LocationShareMenu.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/location/_MapError.pcss b/res/css/components/views/location/_MapError.pcss
index 176ab9a2a11..61227f75a35 100644
--- a/res/css/components/views/location/_MapError.pcss
+++ b/res/css/components/views/location/_MapError.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/location/_MapFallback.pcss b/res/css/components/views/location/_MapFallback.pcss
index 68500eb31d2..160480ff256 100644
--- a/res/css/components/views/location/_MapFallback.pcss
+++ b/res/css/components/views/location/_MapFallback.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/location/_Marker.pcss b/res/css/components/views/location/_Marker.pcss
index e8f321f601b..5a8fef91992 100644
--- a/res/css/components/views/location/_Marker.pcss
+++ b/res/css/components/views/location/_Marker.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/location/_ShareDialogButtons.pcss b/res/css/components/views/location/_ShareDialogButtons.pcss
index 947ac1de1cd..d0c419accbe 100644
--- a/res/css/components/views/location/_ShareDialogButtons.pcss
+++ b/res/css/components/views/location/_ShareDialogButtons.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/location/_ShareType.pcss b/res/css/components/views/location/_ShareType.pcss
index 304ecd0086f..fd99be3317d 100644
--- a/res/css/components/views/location/_ShareType.pcss
+++ b/res/css/components/views/location/_ShareType.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/location/_ZoomButtons.pcss b/res/css/components/views/location/_ZoomButtons.pcss
index 4e9d3b124b1..f98c7bf1b0b 100644
--- a/res/css/components/views/location/_ZoomButtons.pcss
+++ b/res/css/components/views/location/_ZoomButtons.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/messages/_MBeaconBody.pcss b/res/css/components/views/messages/_MBeaconBody.pcss
index 18d7c4b2b3d..054db68feae 100644
--- a/res/css/components/views/messages/_MBeaconBody.pcss
+++ b/res/css/components/views/messages/_MBeaconBody.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/messages/shared/_MediaProcessingError.pcss b/res/css/components/views/messages/shared/_MediaProcessingError.pcss
index de6915f8e2b..39bbbde3894 100644
--- a/res/css/components/views/messages/shared/_MediaProcessingError.pcss
+++ b/res/css/components/views/messages/shared/_MediaProcessingError.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/pips/_WidgetPip.pcss b/res/css/components/views/pips/_WidgetPip.pcss
index db38238a7d6..e515e3eec08 100644
--- a/res/css/components/views/pips/_WidgetPip.pcss
+++ b/res/css/components/views/pips/_WidgetPip.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/polls/_PollOption.pcss b/res/css/components/views/polls/_PollOption.pcss
index 4ef6c225224..42ec7c8dac6 100644
--- a/res/css/components/views/polls/_PollOption.pcss
+++ b/res/css/components/views/polls/_PollOption.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/settings/_AddRemoveThreepids.pcss b/res/css/components/views/settings/_AddRemoveThreepids.pcss
index a67a790c035..b16298f94cb 100644
--- a/res/css/components/views/settings/_AddRemoveThreepids.pcss
+++ b/res/css/components/views/settings/_AddRemoveThreepids.pcss
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 Copyright 2019 New Vector Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/settings/devices/_CurrentDeviceSection.pcss b/res/css/components/views/settings/devices/_CurrentDeviceSection.pcss
index 30d6c752f7a..051b974de2b 100644
--- a/res/css/components/views/settings/devices/_CurrentDeviceSection.pcss
+++ b/res/css/components/views/settings/devices/_CurrentDeviceSection.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/settings/devices/_DeviceDetailHeading.pcss b/res/css/components/views/settings/devices/_DeviceDetailHeading.pcss
index 6ae233ba9c6..789efa9e7f8 100644
--- a/res/css/components/views/settings/devices/_DeviceDetailHeading.pcss
+++ b/res/css/components/views/settings/devices/_DeviceDetailHeading.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/settings/devices/_DeviceDetails.pcss b/res/css/components/views/settings/devices/_DeviceDetails.pcss
index a6c567ad2aa..d3635710f3a 100644
--- a/res/css/components/views/settings/devices/_DeviceDetails.pcss
+++ b/res/css/components/views/settings/devices/_DeviceDetails.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/settings/devices/_DeviceExpandDetailsButton.pcss b/res/css/components/views/settings/devices/_DeviceExpandDetailsButton.pcss
index 8ad786c4baf..5526f07241a 100644
--- a/res/css/components/views/settings/devices/_DeviceExpandDetailsButton.pcss
+++ b/res/css/components/views/settings/devices/_DeviceExpandDetailsButton.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/settings/devices/_DeviceSecurityCard.pcss b/res/css/components/views/settings/devices/_DeviceSecurityCard.pcss
index ff596309ab7..7ac20c076fc 100644
--- a/res/css/components/views/settings/devices/_DeviceSecurityCard.pcss
+++ b/res/css/components/views/settings/devices/_DeviceSecurityCard.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/settings/devices/_DeviceTile.pcss b/res/css/components/views/settings/devices/_DeviceTile.pcss
index 1bc301efadb..e4096329d6a 100644
--- a/res/css/components/views/settings/devices/_DeviceTile.pcss
+++ b/res/css/components/views/settings/devices/_DeviceTile.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/settings/devices/_DeviceTypeIcon.pcss b/res/css/components/views/settings/devices/_DeviceTypeIcon.pcss
index 1c0a453f912..0d459b3473b 100644
--- a/res/css/components/views/settings/devices/_DeviceTypeIcon.pcss
+++ b/res/css/components/views/settings/devices/_DeviceTypeIcon.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/settings/devices/_FilteredDeviceList.pcss b/res/css/components/views/settings/devices/_FilteredDeviceList.pcss
index 8508122fcd9..aac5986280e 100644
--- a/res/css/components/views/settings/devices/_FilteredDeviceList.pcss
+++ b/res/css/components/views/settings/devices/_FilteredDeviceList.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/settings/devices/_FilteredDeviceListHeader.pcss b/res/css/components/views/settings/devices/_FilteredDeviceListHeader.pcss
index ce0fe84b60e..eb50e097c1b 100644
--- a/res/css/components/views/settings/devices/_FilteredDeviceListHeader.pcss
+++ b/res/css/components/views/settings/devices/_FilteredDeviceListHeader.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/settings/devices/_SecurityRecommendations.pcss b/res/css/components/views/settings/devices/_SecurityRecommendations.pcss
index e40e6048d37..20c9343cdaf 100644
--- a/res/css/components/views/settings/devices/_SecurityRecommendations.pcss
+++ b/res/css/components/views/settings/devices/_SecurityRecommendations.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/settings/devices/_SelectableDeviceTile.pcss b/res/css/components/views/settings/devices/_SelectableDeviceTile.pcss
index 9a5ad5d2abe..927a53937f6 100644
--- a/res/css/components/views/settings/devices/_SelectableDeviceTile.pcss
+++ b/res/css/components/views/settings/devices/_SelectableDeviceTile.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/settings/shared/_SettingsSubsection.pcss b/res/css/components/views/settings/shared/_SettingsSubsection.pcss
index ec20b86d98e..0d03a12b1db 100644
--- a/res/css/components/views/settings/shared/_SettingsSubsection.pcss
+++ b/res/css/components/views/settings/shared/_SettingsSubsection.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/settings/shared/_SettingsSubsectionHeading.pcss b/res/css/components/views/settings/shared/_SettingsSubsectionHeading.pcss
index fad1a51337e..eab923faa2c 100644
--- a/res/css/components/views/settings/shared/_SettingsSubsectionHeading.pcss
+++ b/res/css/components/views/settings/shared/_SettingsSubsectionHeading.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/spaces/_QuickThemeSwitcher.pcss b/res/css/components/views/spaces/_QuickThemeSwitcher.pcss
index 0c7ca8363d0..b84bb636e6f 100644
--- a/res/css/components/views/spaces/_QuickThemeSwitcher.pcss
+++ b/res/css/components/views/spaces/_QuickThemeSwitcher.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/typography/_Caption.pcss b/res/css/components/views/typography/_Caption.pcss
index 1aebc077b01..5ddede46b03 100644
--- a/res/css/components/views/typography/_Caption.pcss
+++ b/res/css/components/views/typography/_Caption.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/utils/_Box.pcss b/res/css/components/views/utils/_Box.pcss
index d6063c21f43..5721e326336 100644
--- a/res/css/components/views/utils/_Box.pcss
+++ b/res/css/components/views/utils/_Box.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/components/views/utils/_Flex.pcss b/res/css/components/views/utils/_Flex.pcss
index 7d6ad089ac3..a7f3688466d 100644
--- a/res/css/components/views/utils/_Flex.pcss
+++ b/res/css/components/views/utils/_Flex.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/compound/_Icon.pcss b/res/css/compound/_Icon.pcss
index bbe2f7c89b6..488e919dee5 100644
--- a/res/css/compound/_Icon.pcss
+++ b/res/css/compound/_Icon.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/compound/_SuccessDialog.pcss b/res/css/compound/_SuccessDialog.pcss
index 040c3064051..951eceda99b 100644
--- a/res/css/compound/_SuccessDialog.pcss
+++ b/res/css/compound/_SuccessDialog.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/structures/ErrorView.pcss b/res/css/structures/ErrorView.pcss
index 7267425ae85..cf09ac02afd 100644
--- a/res/css/structures/ErrorView.pcss
+++ b/res/css/structures/ErrorView.pcss
@@ -1,7 +1,7 @@
 /*
 Copyright 2020-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/structures/_AutoHideScrollbar.pcss b/res/css/structures/_AutoHideScrollbar.pcss
index 610e63e5377..48d34b8e2f7 100644
--- a/res/css/structures/_AutoHideScrollbar.pcss
+++ b/res/css/structures/_AutoHideScrollbar.pcss
@@ -1,7 +1,7 @@
 /*
 Copyright 2018-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/structures/_AutocompleteInput.pcss b/res/css/structures/_AutocompleteInput.pcss
index 409d67ceea9..15050264245 100644
--- a/res/css/structures/_AutocompleteInput.pcss
+++ b/res/css/structures/_AutocompleteInput.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/structures/_BackdropPanel.pcss b/res/css/structures/_BackdropPanel.pcss
index ee2fcf943d5..ee12886880b 100644
--- a/res/css/structures/_BackdropPanel.pcss
+++ b/res/css/structures/_BackdropPanel.pcss
@@ -1,7 +1,7 @@
 /*
 Copyright 2021-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/structures/_ContextualMenu.pcss b/res/css/structures/_ContextualMenu.pcss
index ac4af849397..9e6be31ac05 100644
--- a/res/css/structures/_ContextualMenu.pcss
+++ b/res/css/structures/_ContextualMenu.pcss
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/structures/_ErrorMessage.pcss b/res/css/structures/_ErrorMessage.pcss
index 820d8820d9c..aaf2dc3b514 100644
--- a/res/css/structures/_ErrorMessage.pcss
+++ b/res/css/structures/_ErrorMessage.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/structures/_FileDropTarget.pcss b/res/css/structures/_FileDropTarget.pcss
index bfaa7259cf2..88712e5c1a0 100644
--- a/res/css/structures/_FileDropTarget.pcss
+++ b/res/css/structures/_FileDropTarget.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/structures/_FilePanel.pcss b/res/css/structures/_FilePanel.pcss
index ba6a6235760..fff90832dad 100644
--- a/res/css/structures/_FilePanel.pcss
+++ b/res/css/structures/_FilePanel.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/structures/_GenericDropdownMenu.pcss b/res/css/structures/_GenericDropdownMenu.pcss
index bf0098b4ed2..dd9dc0ade14 100644
--- a/res/css/structures/_GenericDropdownMenu.pcss
+++ b/res/css/structures/_GenericDropdownMenu.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/structures/_HomePage.pcss b/res/css/structures/_HomePage.pcss
index 2c7e665e713..4999bae3fec 100644
--- a/res/css/structures/_HomePage.pcss
+++ b/res/css/structures/_HomePage.pcss
@@ -3,7 +3,7 @@ Copyright 2019-2024 New Vector Ltd.
 Copyright 2017 Vector Creations Ltd
 Copyright 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/structures/_LargeLoader.pcss b/res/css/structures/_LargeLoader.pcss
index c18d67a0572..0e861c67ff4 100644
--- a/res/css/structures/_LargeLoader.pcss
+++ b/res/css/structures/_LargeLoader.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/structures/_LeftPanel.pcss b/res/css/structures/_LeftPanel.pcss
index d6d23bbcf28..cf2845b1730 100644
--- a/res/css/structures/_LeftPanel.pcss
+++ b/res/css/structures/_LeftPanel.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/structures/_MainSplit.pcss b/res/css/structures/_MainSplit.pcss
index f334e34b931..750ab37108f 100644
--- a/res/css/structures/_MainSplit.pcss
+++ b/res/css/structures/_MainSplit.pcss
@@ -1,7 +1,7 @@
 /*
 Copyright 2019-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/structures/_MatrixChat.pcss b/res/css/structures/_MatrixChat.pcss
index 39cc8c467d2..284c411013b 100644
--- a/res/css/structures/_MatrixChat.pcss
+++ b/res/css/structures/_MatrixChat.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/structures/_MessagePanel.pcss b/res/css/structures/_MessagePanel.pcss
index f35abed5904..fb2830bce7d 100644
--- a/res/css/structures/_MessagePanel.pcss
+++ b/res/css/structures/_MessagePanel.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/structures/_NonUrgentToastContainer.pcss b/res/css/structures/_NonUrgentToastContainer.pcss
index 05c019e0fcc..daccc88600c 100644
--- a/res/css/structures/_NonUrgentToastContainer.pcss
+++ b/res/css/structures/_NonUrgentToastContainer.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/structures/_QuickSettingsButton.pcss b/res/css/structures/_QuickSettingsButton.pcss
index 234042105a8..44e0ded064c 100644
--- a/res/css/structures/_QuickSettingsButton.pcss
+++ b/res/css/structures/_QuickSettingsButton.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/structures/_RightPanel.pcss b/res/css/structures/_RightPanel.pcss
index 0f796dbc96d..f96f8b72322 100644
--- a/res/css/structures/_RightPanel.pcss
+++ b/res/css/structures/_RightPanel.pcss
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/structures/_RoomSearch.pcss b/res/css/structures/_RoomSearch.pcss
index b3e084e2963..8c82f73ea49 100644
--- a/res/css/structures/_RoomSearch.pcss
+++ b/res/css/structures/_RoomSearch.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/structures/_RoomStatusBar.pcss b/res/css/structures/_RoomStatusBar.pcss
index 0f30401a6b1..19bcc4cb975 100644
--- a/res/css/structures/_RoomStatusBar.pcss
+++ b/res/css/structures/_RoomStatusBar.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/structures/_RoomView.pcss b/res/css/structures/_RoomView.pcss
index 65ea555ce18..478bf548caa 100644
--- a/res/css/structures/_RoomView.pcss
+++ b/res/css/structures/_RoomView.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/structures/_SearchBox.pcss b/res/css/structures/_SearchBox.pcss
index 316294462da..dcb7bbb85e9 100644
--- a/res/css/structures/_SearchBox.pcss
+++ b/res/css/structures/_SearchBox.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/structures/_SpaceHierarchy.pcss b/res/css/structures/_SpaceHierarchy.pcss
index ccbeef07347..31dad9413f1 100644
--- a/res/css/structures/_SpaceHierarchy.pcss
+++ b/res/css/structures/_SpaceHierarchy.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/structures/_SpacePanel.pcss b/res/css/structures/_SpacePanel.pcss
index 7ea717554b2..31dab1ee8dd 100644
--- a/res/css/structures/_SpacePanel.pcss
+++ b/res/css/structures/_SpacePanel.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/structures/_SpaceRoomView.pcss b/res/css/structures/_SpaceRoomView.pcss
index d756d51d65b..3f981ba2dee 100644
--- a/res/css/structures/_SpaceRoomView.pcss
+++ b/res/css/structures/_SpaceRoomView.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/structures/_SplashPage.pcss b/res/css/structures/_SplashPage.pcss
index ec5e5defc84..6f976ba5753 100644
--- a/res/css/structures/_SplashPage.pcss
+++ b/res/css/structures/_SplashPage.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/structures/_TabbedView.pcss b/res/css/structures/_TabbedView.pcss
index 687eaf06ff4..60fe2f72115 100644
--- a/res/css/structures/_TabbedView.pcss
+++ b/res/css/structures/_TabbedView.pcss
@@ -4,7 +4,7 @@ Copyright 2021 The Matrix.org Foundation C.I.C.
 Copyright 2019 New Vector Ltd
 Copyright 2017 Travis Ralston
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/structures/_ThreadsActivityCentre.pcss b/res/css/structures/_ThreadsActivityCentre.pcss
index c159ee11146..a1472108ac9 100644
--- a/res/css/structures/_ThreadsActivityCentre.pcss
+++ b/res/css/structures/_ThreadsActivityCentre.pcss
@@ -1,9 +1,9 @@
 /*
-* Copyright 2024 New Vector Ltd.
-* Copyright 2024 The Matrix.org Foundation C.I.C.
-*
-* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
-* Please see LICENSE files in the repository root for full details.
+ * Copyright 2024 New Vector Ltd.
+ * Copyright 2024 The Matrix.org Foundation C.I.C.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
  */
 
 .mx_ThreadsActivityCentre_container {
diff --git a/res/css/structures/_ToastContainer.pcss b/res/css/structures/_ToastContainer.pcss
index 0a12bec3bf3..6022c01c999 100644
--- a/res/css/structures/_ToastContainer.pcss
+++ b/res/css/structures/_ToastContainer.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/structures/_UploadBar.pcss b/res/css/structures/_UploadBar.pcss
index f28b2fe23a6..8bc341c057b 100644
--- a/res/css/structures/_UploadBar.pcss
+++ b/res/css/structures/_UploadBar.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015, 2016 , 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/structures/_UserMenu.pcss b/res/css/structures/_UserMenu.pcss
index d24a6e4ac7a..50e93d23693 100644
--- a/res/css/structures/_UserMenu.pcss
+++ b/res/css/structures/_UserMenu.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/structures/_ViewSource.pcss b/res/css/structures/_ViewSource.pcss
index 68bb123cce6..b01f8de8bd9 100644
--- a/res/css/structures/_ViewSource.pcss
+++ b/res/css/structures/_ViewSource.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/structures/auth/_CompleteSecurity.pcss b/res/css/structures/auth/_CompleteSecurity.pcss
index cd540793517..f0bca3f39cc 100644
--- a/res/css/structures/auth/_CompleteSecurity.pcss
+++ b/res/css/structures/auth/_CompleteSecurity.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/structures/auth/_ConfirmSessionLockTheftView.pcss b/res/css/structures/auth/_ConfirmSessionLockTheftView.pcss
index f06da60328b..5a4a427fdf7 100644
--- a/res/css/structures/auth/_ConfirmSessionLockTheftView.pcss
+++ b/res/css/structures/auth/_ConfirmSessionLockTheftView.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/structures/auth/_Login.pcss b/res/css/structures/auth/_Login.pcss
index 49b2faf19d0..a7192b1f0d9 100644
--- a/res/css/structures/auth/_Login.pcss
+++ b/res/css/structures/auth/_Login.pcss
@@ -2,7 +2,7 @@
 Copyright 2019-2024 New Vector Ltd.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/structures/auth/_LoginSplashView.pcss b/res/css/structures/auth/_LoginSplashView.pcss
index 413cda35a2e..89e94b38917 100644
--- a/res/css/structures/auth/_LoginSplashView.pcss
+++ b/res/css/structures/auth/_LoginSplashView.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015-2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/structures/auth/_MobileRegistration.pcss b/res/css/structures/auth/_MobileRegistration.pcss
index e2ba1cba285..77c4b78e14c 100644
--- a/res/css/structures/auth/_MobileRegistration.pcss
+++ b/res/css/structures/auth/_MobileRegistration.pcss
@@ -1,7 +1,7 @@
 /*
 Copyright 2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/structures/auth/_Registration.pcss b/res/css/structures/auth/_Registration.pcss
index 7742f256a67..409767e1da7 100644
--- a/res/css/structures/auth/_Registration.pcss
+++ b/res/css/structures/auth/_Registration.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/structures/auth/_SessionLockStolenView.pcss b/res/css/structures/auth/_SessionLockStolenView.pcss
index 046e5c6ebda..a17206ecfd5 100644
--- a/res/css/structures/auth/_SessionLockStolenView.pcss
+++ b/res/css/structures/auth/_SessionLockStolenView.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/structures/auth/_SetupEncryptionBody.pcss b/res/css/structures/auth/_SetupEncryptionBody.pcss
index c7836b96d35..ac6384313c7 100644
--- a/res/css/structures/auth/_SetupEncryptionBody.pcss
+++ b/res/css/structures/auth/_SetupEncryptionBody.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/audio_messages/_AudioPlayer.pcss b/res/css/views/audio_messages/_AudioPlayer.pcss
index 5a81e266dfa..51e97611f5a 100644
--- a/res/css/views/audio_messages/_AudioPlayer.pcss
+++ b/res/css/views/audio_messages/_AudioPlayer.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/audio_messages/_PlayPauseButton.pcss b/res/css/views/audio_messages/_PlayPauseButton.pcss
index a47399090b5..e932c282e33 100644
--- a/res/css/views/audio_messages/_PlayPauseButton.pcss
+++ b/res/css/views/audio_messages/_PlayPauseButton.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/audio_messages/_PlaybackContainer.pcss b/res/css/views/audio_messages/_PlaybackContainer.pcss
index f1dc1d1ec8b..21980b67e6c 100644
--- a/res/css/views/audio_messages/_PlaybackContainer.pcss
+++ b/res/css/views/audio_messages/_PlaybackContainer.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021, 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/audio_messages/_SeekBar.pcss b/res/css/views/audio_messages/_SeekBar.pcss
index fb781811f1f..980595905c3 100644
--- a/res/css/views/audio_messages/_SeekBar.pcss
+++ b/res/css/views/audio_messages/_SeekBar.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/audio_messages/_Waveform.pcss b/res/css/views/audio_messages/_Waveform.pcss
index 237352f18f0..cb548f7694c 100644
--- a/res/css/views/audio_messages/_Waveform.pcss
+++ b/res/css/views/audio_messages/_Waveform.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/auth/_AuthBody.pcss b/res/css/views/auth/_AuthBody.pcss
index 00db5581a0c..d86089e3311 100644
--- a/res/css/views/auth/_AuthBody.pcss
+++ b/res/css/views/auth/_AuthBody.pcss
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 Copyright 2019 New Vector Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/auth/_AuthFooter.pcss b/res/css/views/auth/_AuthFooter.pcss
index c3fac570744..96b41406ad3 100644
--- a/res/css/views/auth/_AuthFooter.pcss
+++ b/res/css/views/auth/_AuthFooter.pcss
@@ -1,7 +1,7 @@
 /*
 Copyright 2019-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/auth/_AuthHeader.pcss b/res/css/views/auth/_AuthHeader.pcss
index ef7d4dbff7d..c9133ed8cfe 100644
--- a/res/css/views/auth/_AuthHeader.pcss
+++ b/res/css/views/auth/_AuthHeader.pcss
@@ -1,7 +1,7 @@
 /*
 Copyright 2019-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/auth/_AuthHeaderLogo.pcss b/res/css/views/auth/_AuthHeaderLogo.pcss
index 8bc9e16640f..431d77e163b 100644
--- a/res/css/views/auth/_AuthHeaderLogo.pcss
+++ b/res/css/views/auth/_AuthHeaderLogo.pcss
@@ -1,7 +1,7 @@
 /*
 Copyright 2019-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/auth/_AuthPage.pcss b/res/css/views/auth/_AuthPage.pcss
index e73d679c462..469bca50539 100644
--- a/res/css/views/auth/_AuthPage.pcss
+++ b/res/css/views/auth/_AuthPage.pcss
@@ -1,7 +1,7 @@
 /*
 Copyright 2019-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/auth/_CompleteSecurityBody.pcss b/res/css/views/auth/_CompleteSecurityBody.pcss
index 189d97dd52d..f0701290051 100644
--- a/res/css/views/auth/_CompleteSecurityBody.pcss
+++ b/res/css/views/auth/_CompleteSecurityBody.pcss
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 Copyright 2019 New Vector Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/auth/_CountryDropdown.pcss b/res/css/views/auth/_CountryDropdown.pcss
index 51376fb4e3f..aed6ab71d8b 100644
--- a/res/css/views/auth/_CountryDropdown.pcss
+++ b/res/css/views/auth/_CountryDropdown.pcss
@@ -1,7 +1,7 @@
 /*
 Copyright 2019-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/auth/_InteractiveAuthEntryComponents.pcss b/res/css/views/auth/_InteractiveAuthEntryComponents.pcss
index fb0bbfad8b1..cd458ee57ed 100644
--- a/res/css/views/auth/_InteractiveAuthEntryComponents.pcss
+++ b/res/css/views/auth/_InteractiveAuthEntryComponents.pcss
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 Copyright 2017 Vector Creations Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/auth/_LanguageSelector.pcss b/res/css/views/auth/_LanguageSelector.pcss
index f76f4d6a795..d5002d00b26 100644
--- a/res/css/views/auth/_LanguageSelector.pcss
+++ b/res/css/views/auth/_LanguageSelector.pcss
@@ -1,7 +1,7 @@
 /*
 Copyright 2019-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/auth/_LoginWithQR.pcss b/res/css/views/auth/_LoginWithQR.pcss
index 9d4744a3894..e4e41d496e4 100644
--- a/res/css/views/auth/_LoginWithQR.pcss
+++ b/res/css/views/auth/_LoginWithQR.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/auth/_PassphraseField.pcss b/res/css/views/auth/_PassphraseField.pcss
index 293a81cbe2a..146d501516f 100644
--- a/res/css/views/auth/_PassphraseField.pcss
+++ b/res/css/views/auth/_PassphraseField.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/auth/_Welcome.pcss b/res/css/views/auth/_Welcome.pcss
index 71f607a8f91..490b6490f6f 100644
--- a/res/css/views/auth/_Welcome.pcss
+++ b/res/css/views/auth/_Welcome.pcss
@@ -1,7 +1,7 @@
 /*
 Copyright 2019-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/avatars/_BaseAvatar.pcss b/res/css/views/avatars/_BaseAvatar.pcss
index 84875215241..f1d6e0390e5 100644
--- a/res/css/views/avatars/_BaseAvatar.pcss
+++ b/res/css/views/avatars/_BaseAvatar.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/avatars/_DecoratedRoomAvatar.pcss b/res/css/views/avatars/_DecoratedRoomAvatar.pcss
index 72fd1e4e2b2..6ac5d684965 100644
--- a/res/css/views/avatars/_DecoratedRoomAvatar.pcss
+++ b/res/css/views/avatars/_DecoratedRoomAvatar.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/avatars/_WidgetAvatar.pcss b/res/css/views/avatars/_WidgetAvatar.pcss
index 6e2b77d0eb2..564c9fefc28 100644
--- a/res/css/views/avatars/_WidgetAvatar.pcss
+++ b/res/css/views/avatars/_WidgetAvatar.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/avatars/_WithPresenceIndicator.pcss b/res/css/views/avatars/_WithPresenceIndicator.pcss
index 1dd779cc5c3..7fe328dc602 100644
--- a/res/css/views/avatars/_WithPresenceIndicator.pcss
+++ b/res/css/views/avatars/_WithPresenceIndicator.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/beta/_BetaCard.pcss b/res/css/views/beta/_BetaCard.pcss
index 33f566ae691..c5d02538615 100644
--- a/res/css/views/beta/_BetaCard.pcss
+++ b/res/css/views/beta/_BetaCard.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/context_menus/_DeviceContextMenu.pcss b/res/css/views/context_menus/_DeviceContextMenu.pcss
index a234f8f5df7..d70b5eb0438 100644
--- a/res/css/views/context_menus/_DeviceContextMenu.pcss
+++ b/res/css/views/context_menus/_DeviceContextMenu.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/context_menus/_IconizedContextMenu.pcss b/res/css/views/context_menus/_IconizedContextMenu.pcss
index f57237223f6..853d97c9354 100644
--- a/res/css/views/context_menus/_IconizedContextMenu.pcss
+++ b/res/css/views/context_menus/_IconizedContextMenu.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020-2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/context_menus/_LegacyCallContextMenu.pcss b/res/css/views/context_menus/_LegacyCallContextMenu.pcss
index 6b83f2af958..e6ec26c8fba 100644
--- a/res/css/views/context_menus/_LegacyCallContextMenu.pcss
+++ b/res/css/views/context_menus/_LegacyCallContextMenu.pcss
@@ -1,7 +1,7 @@
 /*
 Copyright 2020-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/context_menus/_MessageContextMenu.pcss b/res/css/views/context_menus/_MessageContextMenu.pcss
index a73dab9982c..f365c4a293c 100644
--- a/res/css/views/context_menus/_MessageContextMenu.pcss
+++ b/res/css/views/context_menus/_MessageContextMenu.pcss
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2021 Michael Weimann <mail@michael-weimann.eu>
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/_AddExistingToSpaceDialog.pcss b/res/css/views/dialogs/_AddExistingToSpaceDialog.pcss
index 1656ca7e676..7dc25d68113 100644
--- a/res/css/views/dialogs/_AddExistingToSpaceDialog.pcss
+++ b/res/css/views/dialogs/_AddExistingToSpaceDialog.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/_AnalyticsLearnMoreDialog.pcss b/res/css/views/dialogs/_AnalyticsLearnMoreDialog.pcss
index 456b28d88a5..ace00603437 100644
--- a/res/css/views/dialogs/_AnalyticsLearnMoreDialog.pcss
+++ b/res/css/views/dialogs/_AnalyticsLearnMoreDialog.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/_AppDownloadDialog.pcss b/res/css/views/dialogs/_AppDownloadDialog.pcss
deleted file mode 100644
index e0591ed7e91..00000000000
--- a/res/css/views/dialogs/_AppDownloadDialog.pcss
+++ /dev/null
@@ -1,77 +0,0 @@
-.mx_AppDownloadDialog {
-    display: flex;
-    flex-direction: column;
-    gap: $spacing-32;
-    color: $primary-content;
-
-    &.mx_Dialog_fixedWidth {
-        width: 640px;
-    }
-
-    .mx_AppDownloadDialog_desktop {
-        display: flex;
-        flex-direction: column;
-        align-items: center;
-        gap: $spacing-16;
-    }
-
-    .mx_AppDownloadDialog_mobile {
-        display: flex;
-        flex-direction: row;
-        gap: $spacing-24;
-
-        .mx_AppDownloadDialog_app {
-            display: flex;
-            flex-direction: column;
-            flex-grow: 1;
-            flex-basis: 50%;
-            align-items: center;
-            gap: $spacing-16;
-
-            .mx_QRCode {
-                /* intentionally hardcoded color to ensure the QR code is readable in any situation */
-                background: #ffffff;
-
-                padding: $spacing-24;
-                border: 1px solid $quinary-content;
-                border-radius: 4px;
-                align-self: stretch;
-                display: flex;
-                align-items: center;
-                flex-direction: column;
-
-                .mx_VerificationQRCode {
-                    height: 144px;
-                    width: 144px;
-                    image-rendering: pixelated;
-                    border-radius: 0;
-                }
-            }
-
-            .mx_AppDownloadDialog_info {
-                font-size: $font-12px;
-                color: $tertiary-content;
-            }
-
-            .mx_AppDownloadDialog_links {
-                display: flex;
-                flex-direction: row;
-                gap: $spacing-8;
-
-                .mx_AccessibleButton {
-                    svg {
-                        height: 40px;
-                    }
-                }
-            }
-        }
-    }
-
-    .mx_AppDownloadDialog_legal {
-        p {
-            margin: 0;
-            font-size: $font-12px;
-            color: $tertiary-content;
-        }
-    }
-}
diff --git a/res/css/views/dialogs/_BugReportDialog.pcss b/res/css/views/dialogs/_BugReportDialog.pcss
index 7c1750bc40f..8f825a97571 100644
--- a/res/css/views/dialogs/_BugReportDialog.pcss
+++ b/res/css/views/dialogs/_BugReportDialog.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/_BulkRedactDialog.pcss b/res/css/views/dialogs/_BulkRedactDialog.pcss
index 5d8e9d6ef41..3e274798eba 100644
--- a/res/css/views/dialogs/_BulkRedactDialog.pcss
+++ b/res/css/views/dialogs/_BulkRedactDialog.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 Robin Townsend <robin@robin.town>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/_ChangelogDialog.pcss b/res/css/views/dialogs/_ChangelogDialog.pcss
index 81c6b2683f5..b5c1398062d 100644
--- a/res/css/views/dialogs/_ChangelogDialog.pcss
+++ b/res/css/views/dialogs/_ChangelogDialog.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2016 Aviral Dasgupta
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/_CompoundDialog.pcss b/res/css/views/dialogs/_CompoundDialog.pcss
index 789184d47c4..b43fa1f14e8 100644
--- a/res/css/views/dialogs/_CompoundDialog.pcss
+++ b/res/css/views/dialogs/_CompoundDialog.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/_ConfirmSpaceUserActionDialog.pcss b/res/css/views/dialogs/_ConfirmSpaceUserActionDialog.pcss
index 3b91eddc8b8..1921ef24570 100644
--- a/res/css/views/dialogs/_ConfirmSpaceUserActionDialog.pcss
+++ b/res/css/views/dialogs/_ConfirmSpaceUserActionDialog.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/_ConfirmUserActionDialog.pcss b/res/css/views/dialogs/_ConfirmUserActionDialog.pcss
index b1810dff09b..fbd67f89f41 100644
--- a/res/css/views/dialogs/_ConfirmUserActionDialog.pcss
+++ b/res/css/views/dialogs/_ConfirmUserActionDialog.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2017 Vector Creations Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/_CreateRoomDialog.pcss b/res/css/views/dialogs/_CreateRoomDialog.pcss
index 86aa5d0f4d4..a96b9ba4724 100644
--- a/res/css/views/dialogs/_CreateRoomDialog.pcss
+++ b/res/css/views/dialogs/_CreateRoomDialog.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2017 Michael Telatynski <7t3chguy@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/_CreateSubspaceDialog.pcss b/res/css/views/dialogs/_CreateSubspaceDialog.pcss
index 4977ee883df..300fc4ba2ab 100644
--- a/res/css/views/dialogs/_CreateSubspaceDialog.pcss
+++ b/res/css/views/dialogs/_CreateSubspaceDialog.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/_DeactivateAccountDialog.pcss b/res/css/views/dialogs/_DeactivateAccountDialog.pcss
index d1a899158f0..f28cbde8894 100644
--- a/res/css/views/dialogs/_DeactivateAccountDialog.pcss
+++ b/res/css/views/dialogs/_DeactivateAccountDialog.pcss
@@ -1,7 +1,7 @@
 /*
 Copyright 2018-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/_DevtoolsDialog.pcss b/res/css/views/dialogs/_DevtoolsDialog.pcss
index 8b86233b962..3a706345c92 100644
--- a/res/css/views/dialogs/_DevtoolsDialog.pcss
+++ b/res/css/views/dialogs/_DevtoolsDialog.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2017 Michael Telatynski <7t3chguy@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/_ExportDialog.pcss b/res/css/views/dialogs/_ExportDialog.pcss
index 9a5bc58344b..46c0c578c65 100644
--- a/res/css/views/dialogs/_ExportDialog.pcss
+++ b/res/css/views/dialogs/_ExportDialog.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/_FeedbackDialog.pcss b/res/css/views/dialogs/_FeedbackDialog.pcss
index dde15b4e0f0..a9e7d97920c 100644
--- a/res/css/views/dialogs/_FeedbackDialog.pcss
+++ b/res/css/views/dialogs/_FeedbackDialog.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/_ForwardDialog.pcss b/res/css/views/dialogs/_ForwardDialog.pcss
index 40be3f2292d..ecbc19d5339 100644
--- a/res/css/views/dialogs/_ForwardDialog.pcss
+++ b/res/css/views/dialogs/_ForwardDialog.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 Robin Townsend <robin@robin.town>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/_GenericFeatureFeedbackDialog.pcss b/res/css/views/dialogs/_GenericFeatureFeedbackDialog.pcss
index cc41e691313..655f7f95e8d 100644
--- a/res/css/views/dialogs/_GenericFeatureFeedbackDialog.pcss
+++ b/res/css/views/dialogs/_GenericFeatureFeedbackDialog.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/_IncomingSasDialog.pcss b/res/css/views/dialogs/_IncomingSasDialog.pcss
index a455f144f7b..0fb0c9a4168 100644
--- a/res/css/views/dialogs/_IncomingSasDialog.pcss
+++ b/res/css/views/dialogs/_IncomingSasDialog.pcss
@@ -1,7 +1,7 @@
 /*
 Copyright 2019-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/_InviteDialog.pcss b/res/css/views/dialogs/_InviteDialog.pcss
index e5c00cef18e..70a8cdc6087 100644
--- a/res/css/views/dialogs/_InviteDialog.pcss
+++ b/res/css/views/dialogs/_InviteDialog.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/_JoinRuleDropdown.pcss b/res/css/views/dialogs/_JoinRuleDropdown.pcss
index 6fd00168858..3f72b095832 100644
--- a/res/css/views/dialogs/_JoinRuleDropdown.pcss
+++ b/res/css/views/dialogs/_JoinRuleDropdown.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/_LeaveSpaceDialog.pcss b/res/css/views/dialogs/_LeaveSpaceDialog.pcss
index b3e38782766..d9884666536 100644
--- a/res/css/views/dialogs/_LeaveSpaceDialog.pcss
+++ b/res/css/views/dialogs/_LeaveSpaceDialog.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/_LocationViewDialog.pcss b/res/css/views/dialogs/_LocationViewDialog.pcss
index 118897b923e..f25541520bc 100644
--- a/res/css/views/dialogs/_LocationViewDialog.pcss
+++ b/res/css/views/dialogs/_LocationViewDialog.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/_LogoutDialog.pcss b/res/css/views/dialogs/_LogoutDialog.pcss
index 0161c00d329..8f11f8c7c27 100644
--- a/res/css/views/dialogs/_LogoutDialog.pcss
+++ b/res/css/views/dialogs/_LogoutDialog.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 Manan Sadana <manancodes.dev@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/_ManageRestrictedJoinRuleDialog.pcss b/res/css/views/dialogs/_ManageRestrictedJoinRuleDialog.pcss
index a6b9fe03045..f77ebf7b6b9 100644
--- a/res/css/views/dialogs/_ManageRestrictedJoinRuleDialog.pcss
+++ b/res/css/views/dialogs/_ManageRestrictedJoinRuleDialog.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/_MessageEditHistoryDialog.pcss b/res/css/views/dialogs/_MessageEditHistoryDialog.pcss
index b1c820e16be..8105833830c 100644
--- a/res/css/views/dialogs/_MessageEditHistoryDialog.pcss
+++ b/res/css/views/dialogs/_MessageEditHistoryDialog.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/_ModalWidgetDialog.pcss b/res/css/views/dialogs/_ModalWidgetDialog.pcss
index 6b3e475a842..423e4c26ecc 100644
--- a/res/css/views/dialogs/_ModalWidgetDialog.pcss
+++ b/res/css/views/dialogs/_ModalWidgetDialog.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/_PollCreateDialog.pcss b/res/css/views/dialogs/_PollCreateDialog.pcss
index b0d89c4676a..0689938a24e 100644
--- a/res/css/views/dialogs/_PollCreateDialog.pcss
+++ b/res/css/views/dialogs/_PollCreateDialog.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/_RegistrationEmailPromptDialog.pcss b/res/css/views/dialogs/_RegistrationEmailPromptDialog.pcss
index eea733fa69e..98bf9e9cd9c 100644
--- a/res/css/views/dialogs/_RegistrationEmailPromptDialog.pcss
+++ b/res/css/views/dialogs/_RegistrationEmailPromptDialog.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/_RoomSettingsDialog.pcss b/res/css/views/dialogs/_RoomSettingsDialog.pcss
index 544512d02aa..7593a72bd9f 100644
--- a/res/css/views/dialogs/_RoomSettingsDialog.pcss
+++ b/res/css/views/dialogs/_RoomSettingsDialog.pcss
@@ -1,7 +1,7 @@
 /*
 Copyright 2019-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/_RoomSettingsDialogBridges.pcss b/res/css/views/dialogs/_RoomSettingsDialogBridges.pcss
index 36fb34e8b1f..5633130b649 100644
--- a/res/css/views/dialogs/_RoomSettingsDialogBridges.pcss
+++ b/res/css/views/dialogs/_RoomSettingsDialogBridges.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/_RoomUpgradeDialog.pcss b/res/css/views/dialogs/_RoomUpgradeDialog.pcss
index 82bce661edb..b64c11bcf71 100644
--- a/res/css/views/dialogs/_RoomUpgradeDialog.pcss
+++ b/res/css/views/dialogs/_RoomUpgradeDialog.pcss
@@ -1,7 +1,7 @@
 /*
 Copyright 2018-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/_RoomUpgradeWarningDialog.pcss b/res/css/views/dialogs/_RoomUpgradeWarningDialog.pcss
index 79b3228cb38..d988c34077a 100644
--- a/res/css/views/dialogs/_RoomUpgradeWarningDialog.pcss
+++ b/res/css/views/dialogs/_RoomUpgradeWarningDialog.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/_ServerOfflineDialog.pcss b/res/css/views/dialogs/_ServerOfflineDialog.pcss
index 0dcd0dbfa72..96a4aa9bfb0 100644
--- a/res/css/views/dialogs/_ServerOfflineDialog.pcss
+++ b/res/css/views/dialogs/_ServerOfflineDialog.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/_ServerPickerDialog.pcss b/res/css/views/dialogs/_ServerPickerDialog.pcss
index 445d5aad6f7..b1346ff73f5 100644
--- a/res/css/views/dialogs/_ServerPickerDialog.pcss
+++ b/res/css/views/dialogs/_ServerPickerDialog.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/_SetEmailDialog.pcss b/res/css/views/dialogs/_SetEmailDialog.pcss
index 1be983eaab2..718618c9232 100644
--- a/res/css/views/dialogs/_SetEmailDialog.pcss
+++ b/res/css/views/dialogs/_SetEmailDialog.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2017 Vector Creations Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/_SettingsDialog.pcss b/res/css/views/dialogs/_SettingsDialog.pcss
index 05be3b54f46..186a82c0f5d 100644
--- a/res/css/views/dialogs/_SettingsDialog.pcss
+++ b/res/css/views/dialogs/_SettingsDialog.pcss
@@ -1,7 +1,7 @@
 /*
 Copyright 2019-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/_ShareDialog.pcss b/res/css/views/dialogs/_ShareDialog.pcss
index cfede43aae7..e8ac18f0be0 100644
--- a/res/css/views/dialogs/_ShareDialog.pcss
+++ b/res/css/views/dialogs/_ShareDialog.pcss
@@ -1,7 +1,7 @@
 /*
 Copyright 2018-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/_SlashCommandHelpDialog.pcss b/res/css/views/dialogs/_SlashCommandHelpDialog.pcss
index 8efa89e1cf8..445b2d02d50 100644
--- a/res/css/views/dialogs/_SlashCommandHelpDialog.pcss
+++ b/res/css/views/dialogs/_SlashCommandHelpDialog.pcss
@@ -1,7 +1,7 @@
 /*
 Copyright 2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/_SpacePreferencesDialog.pcss b/res/css/views/dialogs/_SpacePreferencesDialog.pcss
index af75b7866f9..709c9267600 100644
--- a/res/css/views/dialogs/_SpacePreferencesDialog.pcss
+++ b/res/css/views/dialogs/_SpacePreferencesDialog.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/_SpaceSettingsDialog.pcss b/res/css/views/dialogs/_SpaceSettingsDialog.pcss
index d1990b5973a..6c48e34b758 100644
--- a/res/css/views/dialogs/_SpaceSettingsDialog.pcss
+++ b/res/css/views/dialogs/_SpaceSettingsDialog.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/_SpotlightDialog.pcss b/res/css/views/dialogs/_SpotlightDialog.pcss
index c4f94bfde9d..d00acd6786d 100644
--- a/res/css/views/dialogs/_SpotlightDialog.pcss
+++ b/res/css/views/dialogs/_SpotlightDialog.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/_TermsDialog.pcss b/res/css/views/dialogs/_TermsDialog.pcss
index 268432f441f..b6a8170f787 100644
--- a/res/css/views/dialogs/_TermsDialog.pcss
+++ b/res/css/views/dialogs/_TermsDialog.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/_UnpinAllDialog.pcss b/res/css/views/dialogs/_UnpinAllDialog.pcss
index 596f9926963..e3a4c413827 100644
--- a/res/css/views/dialogs/_UnpinAllDialog.pcss
+++ b/res/css/views/dialogs/_UnpinAllDialog.pcss
@@ -1,9 +1,9 @@
 /*
-* Copyright 2024 New Vector Ltd.
-* Copyright 2024 The Matrix.org Foundation C.I.C.
-*
-* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
-* Please see LICENSE files in the repository root for full details.
+ * Copyright 2024 New Vector Ltd.
+ * Copyright 2024 The Matrix.org Foundation C.I.C.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
  */
 
 .mx_UnpinAllDialog {
diff --git a/res/css/views/dialogs/_UntrustedDeviceDialog.pcss b/res/css/views/dialogs/_UntrustedDeviceDialog.pcss
index af7d4863b65..8fb74319009 100644
--- a/res/css/views/dialogs/_UntrustedDeviceDialog.pcss
+++ b/res/css/views/dialogs/_UntrustedDeviceDialog.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/_UploadConfirmDialog.pcss b/res/css/views/dialogs/_UploadConfirmDialog.pcss
index fc633b9b699..f50bf5e7d50 100644
--- a/res/css/views/dialogs/_UploadConfirmDialog.pcss
+++ b/res/css/views/dialogs/_UploadConfirmDialog.pcss
@@ -1,7 +1,7 @@
 /*
 Copyright 2019-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/_UserSettingsDialog.pcss b/res/css/views/dialogs/_UserSettingsDialog.pcss
index 4f91ea2ddbd..7f307afe2f4 100644
--- a/res/css/views/dialogs/_UserSettingsDialog.pcss
+++ b/res/css/views/dialogs/_UserSettingsDialog.pcss
@@ -1,7 +1,7 @@
 /*
 Copyright 2019-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/_VerifyEMailDialog.pcss b/res/css/views/dialogs/_VerifyEMailDialog.pcss
index ec2449517bd..32fc8189e9d 100644
--- a/res/css/views/dialogs/_VerifyEMailDialog.pcss
+++ b/res/css/views/dialogs/_VerifyEMailDialog.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/_WidgetCapabilitiesPromptDialog.pcss b/res/css/views/dialogs/_WidgetCapabilitiesPromptDialog.pcss
index 3cc14396220..9e1024b9a49 100644
--- a/res/css/views/dialogs/_WidgetCapabilitiesPromptDialog.pcss
+++ b/res/css/views/dialogs/_WidgetCapabilitiesPromptDialog.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/security/_AccessSecretStorageDialog.pcss b/res/css/views/dialogs/security/_AccessSecretStorageDialog.pcss
index e5abc1e48bc..da71b4462b0 100644
--- a/res/css/views/dialogs/security/_AccessSecretStorageDialog.pcss
+++ b/res/css/views/dialogs/security/_AccessSecretStorageDialog.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2018, 2019 , 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/security/_CreateCrossSigningDialog.pcss b/res/css/views/dialogs/security/_CreateCrossSigningDialog.pcss
index e543d089209..9cc7e98243d 100644
--- a/res/css/views/dialogs/security/_CreateCrossSigningDialog.pcss
+++ b/res/css/views/dialogs/security/_CreateCrossSigningDialog.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/security/_CreateKeyBackupDialog.pcss b/res/css/views/dialogs/security/_CreateKeyBackupDialog.pcss
index 4460abd35dc..9bd85398818 100644
--- a/res/css/views/dialogs/security/_CreateKeyBackupDialog.pcss
+++ b/res/css/views/dialogs/security/_CreateKeyBackupDialog.pcss
@@ -1,7 +1,7 @@
 /*
 Copyright 2018-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/security/_CreateSecretStorageDialog.pcss b/res/css/views/dialogs/security/_CreateSecretStorageDialog.pcss
index 02d98902706..e40458f48fc 100644
--- a/res/css/views/dialogs/security/_CreateSecretStorageDialog.pcss
+++ b/res/css/views/dialogs/security/_CreateSecretStorageDialog.pcss
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
 Copyright 2018 New Vector Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/security/_KeyBackupFailedDialog.pcss b/res/css/views/dialogs/security/_KeyBackupFailedDialog.pcss
index 604e948a349..b02964f64ba 100644
--- a/res/css/views/dialogs/security/_KeyBackupFailedDialog.pcss
+++ b/res/css/views/dialogs/security/_KeyBackupFailedDialog.pcss
@@ -1,7 +1,7 @@
 /*
 Copyright 2018-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/dialogs/security/_RestoreKeyBackupDialog.pcss b/res/css/views/dialogs/security/_RestoreKeyBackupDialog.pcss
index 832619c5881..c8c7c3355dd 100644
--- a/res/css/views/dialogs/security/_RestoreKeyBackupDialog.pcss
+++ b/res/css/views/dialogs/security/_RestoreKeyBackupDialog.pcss
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 Copyright 2018 New Vector Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/directory/_NetworkDropdown.pcss b/res/css/views/directory/_NetworkDropdown.pcss
index df82d175552..47180e3c2f5 100644
--- a/res/css/views/directory/_NetworkDropdown.pcss
+++ b/res/css/views/directory/_NetworkDropdown.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/elements/_AccessibleButton.pcss b/res/css/views/elements/_AccessibleButton.pcss
index 27219d06b56..c67a7441be3 100644
--- a/res/css/views/elements/_AccessibleButton.pcss
+++ b/res/css/views/elements/_AccessibleButton.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2017 Vector Creations Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/elements/_CopyableText.pcss b/res/css/views/elements/_CopyableText.pcss
index 7c98d5911d4..2764fea46c3 100644
--- a/res/css/views/elements/_CopyableText.pcss
+++ b/res/css/views/elements/_CopyableText.pcss
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2022 Šimon Brandner <simon.bra.ag@gmail.com>
 Copyright 2019 New Vector Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/elements/_DesktopCapturerSourcePicker.pcss b/res/css/views/elements/_DesktopCapturerSourcePicker.pcss
index 1281c74a4d1..136dada34a7 100644
--- a/res/css/views/elements/_DesktopCapturerSourcePicker.pcss
+++ b/res/css/views/elements/_DesktopCapturerSourcePicker.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/elements/_DialPadBackspaceButton.pcss b/res/css/views/elements/_DialPadBackspaceButton.pcss
index 020c4ee5781..4e305999ff2 100644
--- a/res/css/views/elements/_DialPadBackspaceButton.pcss
+++ b/res/css/views/elements/_DialPadBackspaceButton.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/elements/_Dropdown.pcss b/res/css/views/elements/_Dropdown.pcss
index b91af285fd6..355d79d569d 100644
--- a/res/css/views/elements/_Dropdown.pcss
+++ b/res/css/views/elements/_Dropdown.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2017 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/elements/_EditableItemList.pcss b/res/css/views/elements/_EditableItemList.pcss
index 8a85f615d86..82aa4923838 100644
--- a/res/css/views/elements/_EditableItemList.pcss
+++ b/res/css/views/elements/_EditableItemList.pcss
@@ -1,7 +1,7 @@
 /*
 Copyright 2017-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/elements/_ErrorBoundary.pcss b/res/css/views/elements/_ErrorBoundary.pcss
index 74fe0792e1a..0ed1f7b6382 100644
--- a/res/css/views/elements/_ErrorBoundary.pcss
+++ b/res/css/views/elements/_ErrorBoundary.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/elements/_ExternalLink.pcss b/res/css/views/elements/_ExternalLink.pcss
index 7a2c51bcaef..c103207ab03 100644
--- a/res/css/views/elements/_ExternalLink.pcss
+++ b/res/css/views/elements/_ExternalLink.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/elements/_FacePile.pcss b/res/css/views/elements/_FacePile.pcss
index b063f5900e6..1e4acb75e8d 100644
--- a/res/css/views/elements/_FacePile.pcss
+++ b/res/css/views/elements/_FacePile.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/elements/_Field.pcss b/res/css/views/elements/_Field.pcss
index 21a0a0208aa..90cb1762515 100644
--- a/res/css/views/elements/_Field.pcss
+++ b/res/css/views/elements/_Field.pcss
@@ -1,7 +1,7 @@
 /*
 Copyright 2019-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/elements/_GenericEventListSummary.pcss b/res/css/views/elements/_GenericEventListSummary.pcss
index c13f8194396..f4aa0e6f0fa 100644
--- a/res/css/views/elements/_GenericEventListSummary.pcss
+++ b/res/css/views/elements/_GenericEventListSummary.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/elements/_ImageView.pcss b/res/css/views/elements/_ImageView.pcss
index c1fa7373952..d6649d15da3 100644
--- a/res/css/views/elements/_ImageView.pcss
+++ b/res/css/views/elements/_ImageView.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/elements/_InfoTooltip.pcss b/res/css/views/elements/_InfoTooltip.pcss
index dcec1410f1e..5229b7d9f59 100644
--- a/res/css/views/elements/_InfoTooltip.pcss
+++ b/res/css/views/elements/_InfoTooltip.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/elements/_InlineSpinner.pcss b/res/css/views/elements/_InlineSpinner.pcss
index f22a0552cbc..9f7ae2ab523 100644
--- a/res/css/views/elements/_InlineSpinner.pcss
+++ b/res/css/views/elements/_InlineSpinner.pcss
@@ -1,7 +1,7 @@
 /*
 Copyright 2017-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/elements/_InteractiveTooltip.pcss b/res/css/views/elements/_InteractiveTooltip.pcss
index 71d9fa4e299..e53282b203c 100644
--- a/res/css/views/elements/_InteractiveTooltip.pcss
+++ b/res/css/views/elements/_InteractiveTooltip.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/elements/_InviteReason.pcss b/res/css/views/elements/_InviteReason.pcss
index c57c59ae1f8..509e6cfaf90 100644
--- a/res/css/views/elements/_InviteReason.pcss
+++ b/res/css/views/elements/_InviteReason.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/elements/_LabelledCheckbox.pcss b/res/css/views/elements/_LabelledCheckbox.pcss
index 00eb2053039..add8f14998c 100644
--- a/res/css/views/elements/_LabelledCheckbox.pcss
+++ b/res/css/views/elements/_LabelledCheckbox.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/elements/_LanguageDropdown.pcss b/res/css/views/elements/_LanguageDropdown.pcss
index 2ba7188e967..cd35d6bd5bd 100644
--- a/res/css/views/elements/_LanguageDropdown.pcss
+++ b/res/css/views/elements/_LanguageDropdown.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/elements/_MiniAvatarUploader.pcss b/res/css/views/elements/_MiniAvatarUploader.pcss
index d997118e88b..6fbe209ac97 100644
--- a/res/css/views/elements/_MiniAvatarUploader.pcss
+++ b/res/css/views/elements/_MiniAvatarUploader.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/elements/_Pill.pcss b/res/css/views/elements/_Pill.pcss
index ccf82ff6d62..055a524c5a1 100644
--- a/res/css/views/elements/_Pill.pcss
+++ b/res/css/views/elements/_Pill.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/elements/_PowerSelector.pcss b/res/css/views/elements/_PowerSelector.pcss
index f400e10764d..eded483376b 100644
--- a/res/css/views/elements/_PowerSelector.pcss
+++ b/res/css/views/elements/_PowerSelector.pcss
@@ -1,7 +1,7 @@
 /*
 Copyright 2019-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/elements/_ProgressBar.pcss b/res/css/views/elements/_ProgressBar.pcss
index 062770f77f0..aea2902e128 100644
--- a/res/css/views/elements/_ProgressBar.pcss
+++ b/res/css/views/elements/_ProgressBar.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020, 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/elements/_QRCode.pcss b/res/css/views/elements/_QRCode.pcss
index 59586427081..5af0fd5c203 100644
--- a/res/css/views/elements/_QRCode.pcss
+++ b/res/css/views/elements/_QRCode.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/elements/_ReplyChain.pcss b/res/css/views/elements/_ReplyChain.pcss
index 27d8429b6b1..2b1e7f9b57b 100644
--- a/res/css/views/elements/_ReplyChain.pcss
+++ b/res/css/views/elements/_ReplyChain.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2018 Vector Creations Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/elements/_ResizeHandle.pcss b/res/css/views/elements/_ResizeHandle.pcss
index a237662f8bf..65827d4fb9c 100644
--- a/res/css/views/elements/_ResizeHandle.pcss
+++ b/res/css/views/elements/_ResizeHandle.pcss
@@ -1,7 +1,7 @@
 /*
 Copyright 2018-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/elements/_RoomAliasField.pcss b/res/css/views/elements/_RoomAliasField.pcss
index 71cc32c386f..c1fb066ed5b 100644
--- a/res/css/views/elements/_RoomAliasField.pcss
+++ b/res/css/views/elements/_RoomAliasField.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/elements/_SSOButtons.pcss b/res/css/views/elements/_SSOButtons.pcss
index b69c5f99d49..7b4d2c973f2 100644
--- a/res/css/views/elements/_SSOButtons.pcss
+++ b/res/css/views/elements/_SSOButtons.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/elements/_SearchWarning.pcss b/res/css/views/elements/_SearchWarning.pcss
index 03be05a1b10..52aadb56948 100644
--- a/res/css/views/elements/_SearchWarning.pcss
+++ b/res/css/views/elements/_SearchWarning.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/elements/_ServerPicker.pcss b/res/css/views/elements/_ServerPicker.pcss
index f525f65df10..fa0b46599fa 100644
--- a/res/css/views/elements/_ServerPicker.pcss
+++ b/res/css/views/elements/_ServerPicker.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/elements/_SettingsFlag.pcss b/res/css/views/elements/_SettingsFlag.pcss
index 604b42fd9ac..dbef5fcb2b6 100644
--- a/res/css/views/elements/_SettingsFlag.pcss
+++ b/res/css/views/elements/_SettingsFlag.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/elements/_Spinner.pcss b/res/css/views/elements/_Spinner.pcss
index f5f5d47070a..1280cc888ce 100644
--- a/res/css/views/elements/_Spinner.pcss
+++ b/res/css/views/elements/_Spinner.pcss
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/elements/_StyledCheckbox.pcss b/res/css/views/elements/_StyledCheckbox.pcss
index 986889c6dc1..77382d711c9 100644
--- a/res/css/views/elements/_StyledCheckbox.pcss
+++ b/res/css/views/elements/_StyledCheckbox.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/elements/_StyledRadioButton.pcss b/res/css/views/elements/_StyledRadioButton.pcss
index 1df1c453a59..13bcf309e74 100644
--- a/res/css/views/elements/_StyledRadioButton.pcss
+++ b/res/css/views/elements/_StyledRadioButton.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/elements/_SyntaxHighlight.pcss b/res/css/views/elements/_SyntaxHighlight.pcss
index 03ad526754b..8472d3cf602 100644
--- a/res/css/views/elements/_SyntaxHighlight.pcss
+++ b/res/css/views/elements/_SyntaxHighlight.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2017 Michael Telatynski <7t3chguy@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/elements/_TagComposer.pcss b/res/css/views/elements/_TagComposer.pcss
index 1e758a2c3c7..a85d24d1219 100644
--- a/res/css/views/elements/_TagComposer.pcss
+++ b/res/css/views/elements/_TagComposer.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/elements/_TextWithTooltip.pcss b/res/css/views/elements/_TextWithTooltip.pcss
index 99221582358..ce6cb1cc659 100644
--- a/res/css/views/elements/_TextWithTooltip.pcss
+++ b/res/css/views/elements/_TextWithTooltip.pcss
@@ -1,7 +1,7 @@
 /*
 Copyright 2019-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 .mx_TextWithTooltip_target {
diff --git a/res/css/views/elements/_ToggleSwitch.pcss b/res/css/views/elements/_ToggleSwitch.pcss
index 5ff2f461073..6f197e1c77c 100644
--- a/res/css/views/elements/_ToggleSwitch.pcss
+++ b/res/css/views/elements/_ToggleSwitch.pcss
@@ -1,7 +1,7 @@
 /*
 Copyright 2019-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/elements/_UseCaseSelection.pcss b/res/css/views/elements/_UseCaseSelection.pcss
deleted file mode 100644
index 070a8a243bb..00000000000
--- a/res/css/views/elements/_UseCaseSelection.pcss
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2022 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
-Please see LICENSE files in the repository root for full details.
-*/
-
-.mx_UseCaseSelection {
-    display: grid;
-    grid-template-rows: 1fr 1fr max-content 2fr;
-    height: 100%;
-    grid-gap: $spacing-40;
-
-    .mx_UseCaseSelection_title {
-        display: flex;
-        flex-direction: column;
-        justify-content: flex-end;
-
-        h1 {
-            font-weight: var(--cpd-font-weight-semibold);
-            font-size: $font-32px;
-            text-align: center;
-        }
-    }
-
-    .mx_UseCaseSelection_info {
-        display: flex;
-        flex-direction: column;
-        gap: $spacing-8;
-        align-self: flex-end;
-
-        h2 {
-            margin: 0;
-            font-weight: 500;
-            font-size: $font-24px;
-            text-align: center;
-        }
-
-        h3 {
-            margin: 0;
-            font-weight: 400;
-            font-size: $font-16px;
-            color: $secondary-content;
-            text-align: center;
-        }
-    }
-
-    .mx_UseCaseSelection_options {
-        display: grid;
-        grid-template-columns: repeat(auto-fit, 232px);
-        gap: $spacing-32;
-        align-self: stretch;
-        justify-content: center;
-    }
-
-    .mx_UseCaseSelection_skip {
-        display: flex;
-        flex-direction: column;
-        align-self: flex-start;
-    }
-}
-
-.mx_UseCaseSelection_slideIn {
-    animation-delay: 800ms;
-    animation-duration: 300ms;
-    animation-timing-function: cubic-bezier(0, 0, 0.58, 1);
-    animation-name: mx_UseCaseSelection_slideInLong;
-    animation-fill-mode: backwards;
-    will-change: opacity;
-}
-
-.mx_UseCaseSelection_slideInDelayed {
-    animation-delay: 1500ms;
-    animation-duration: 300ms;
-    animation-timing-function: cubic-bezier(0, 0, 0.58, 1);
-    animation-name: mx_UseCaseSelection_slideInShort;
-    animation-fill-mode: backwards;
-    will-change: transform, opacity;
-}
-
-.mx_UseCaseSelection_selected {
-    .mx_UseCaseSelection_slideIn,
-    .mx_UseCaseSelection_slideInDelayed {
-        animation-delay: 800ms;
-        animation-duration: 300ms;
-        animation-fill-mode: forwards;
-        animation-name: mx_UseCaseSelection_fadeOut;
-        will-change: opacity;
-    }
-}
-
-@keyframes mx_UseCaseSelection_slideInLong {
-    0% {
-        transform: translate(0, 20px);
-        opacity: 0;
-    }
-    100% {
-        transform: translate(0, 0);
-        opacity: 1;
-    }
-}
-
-@keyframes mx_UseCaseSelection_slideInShort {
-    0% {
-        transform: translate(0, 8px);
-        opacity: 0;
-    }
-    100% {
-        transform: translate(0, 0);
-        opacity: 1;
-    }
-}
-
-@keyframes mx_UseCaseSelection_fadeOut {
-    0% {
-        opacity: 1;
-    }
-    100% {
-        opacity: 0;
-    }
-}
diff --git a/res/css/views/elements/_UseCaseSelectionButton.pcss b/res/css/views/elements/_UseCaseSelectionButton.pcss
deleted file mode 100644
index f8c001714f9..00000000000
--- a/res/css/views/elements/_UseCaseSelectionButton.pcss
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2022 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
-Please see LICENSE files in the repository root for full details.
-*/
-
-.mx_UseCaseSelectionButton {
-    display: flex;
-    flex-direction: column;
-    align-items: center;
-    padding: $spacing-24 $spacing-16;
-    background: $background;
-    border: 1px solid $quinary-content;
-    border-radius: 8px;
-    text-align: center;
-    position: relative;
-    transition-property: box-shadow, transform;
-    transition-duration: 300ms;
-
-    .mx_UseCaseSelectionButton_icon {
-        /* workaround: design expects a layering of two colors */
-        background: linear-gradient(0deg, rgba(172, 59, 168, 0.15), rgba(172, 59, 168, 0.15)), #ffffff;
-        border-radius: 14px;
-        padding: $spacing-8;
-        margin-bottom: $spacing-16;
-
-        &::before {
-            content: "";
-            display: block;
-            /* this has to remain the same color across all themes,
-               as its background has a fixed color as well */
-            background: #1e1e1e;
-            mask-position: center;
-            mask-repeat: no-repeat;
-            mask-size: contain;
-            width: 22px;
-            height: 22px;
-        }
-
-        &.mx_UseCaseSelectionButton_messaging::before {
-            mask-image: url("$(res)/img/element-icons/chat-bubble.svg");
-        }
-
-        &.mx_UseCaseSelectionButton_work::before {
-            mask-image: url("$(res)/img/element-icons/view-community.svg");
-        }
-
-        &.mx_UseCaseSelectionButton_community::before {
-            mask-image: url("@vector-im/compound-design-tokens/icons/public.svg");
-            mask-size: 24px;
-        }
-    }
-
-    &:hover,
-    &:focus {
-        box-shadow: 0 $spacing-4 $spacing-8 rgba(0, 0, 0, 0.08);
-        transform: translate(0, -$spacing-8);
-    }
-
-    .mx_UseCaseSelectionButton_selectedIcon {
-        right: -12px;
-        top: -12px;
-        position: absolute;
-        border-radius: 24px;
-        background: $accent;
-        padding: 6px;
-        transition-property: opacity, transform;
-        transition-duration: 150ms;
-        opacity: 0;
-        transform: scale(0.6);
-
-        &::before {
-            content: "";
-            display: block;
-            background: $background;
-            mask-position: center;
-            mask-repeat: no-repeat;
-            mask-size: contain;
-            width: 12px;
-            height: 12px;
-
-            mask-image: url("@vector-im/compound-design-tokens/icons/check.svg");
-        }
-    }
-
-    &.mx_UseCaseSelectionButton_selected {
-        border: 2px solid $accent;
-        padding: calc($spacing-24 - 1px) calc($spacing-16 - 1px);
-        box-shadow: 0 $spacing-4 $spacing-8 rgba(0, 0, 0, 0.08);
-
-        .mx_UseCaseSelectionButton_selectedIcon {
-            opacity: 1;
-            transform: scale(1);
-        }
-    }
-}
diff --git a/res/css/views/elements/_Validation.pcss b/res/css/views/elements/_Validation.pcss
index 5bf8dfb7944..28ea95c0b00 100644
--- a/res/css/views/elements/_Validation.pcss
+++ b/res/css/views/elements/_Validation.pcss
@@ -1,7 +1,7 @@
 /*
 Copyright 2019-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/emojipicker/_EmojiPicker.pcss b/res/css/views/emojipicker/_EmojiPicker.pcss
index d4ae92172d6..c1a666a672e 100644
--- a/res/css/views/emojipicker/_EmojiPicker.pcss
+++ b/res/css/views/emojipicker/_EmojiPicker.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 Tulir Asokan <tulir@maunium.net>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/location/_LocationPicker.pcss b/res/css/views/location/_LocationPicker.pcss
index 872017546ea..9384411cf80 100644
--- a/res/css/views/location/_LocationPicker.pcss
+++ b/res/css/views/location/_LocationPicker.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/messages/_CallEvent.pcss b/res/css/views/messages/_CallEvent.pcss
index 45be948b41b..1797c283ce3 100644
--- a/res/css/views/messages/_CallEvent.pcss
+++ b/res/css/views/messages/_CallEvent.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/messages/_CreateEvent.pcss b/res/css/views/messages/_CreateEvent.pcss
index 7f76d07613d..0c8a003dcd4 100644
--- a/res/css/views/messages/_CreateEvent.pcss
+++ b/res/css/views/messages/_CreateEvent.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2018-2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/messages/_DateSeparator.pcss b/res/css/views/messages/_DateSeparator.pcss
index aa6f88eaaa5..fe134125610 100644
--- a/res/css/views/messages/_DateSeparator.pcss
+++ b/res/css/views/messages/_DateSeparator.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2017 Vector Creations Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/messages/_DecryptionFailureBody.pcss b/res/css/views/messages/_DecryptionFailureBody.pcss
index 516e7bcc89f..4a4940abe33 100644
--- a/res/css/views/messages/_DecryptionFailureBody.pcss
+++ b/res/css/views/messages/_DecryptionFailureBody.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/messages/_DisambiguatedProfile.pcss b/res/css/views/messages/_DisambiguatedProfile.pcss
index 25a28971d41..3f10c07abe3 100644
--- a/res/css/views/messages/_DisambiguatedProfile.pcss
+++ b/res/css/views/messages/_DisambiguatedProfile.pcss
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -21,8 +21,29 @@ Please see LICENSE files in the repository root for full details.
     }
 
     .mx_DisambiguatedProfile_mxid {
-        margin-inline-start: 5px;
         color: $secondary-content;
         font-size: var(--cpd-font-size-body-sm);
+        margin-inline-start: 5px;
+    }
+}
+
+/** Disambiguated profile needs to have a different layout in the member tile */
+.mx_MemberTileView .mx_DisambiguatedProfile {
+    display: flex;
+    flex-direction: column;
+
+    .mx_DisambiguatedProfile_mxid {
+        margin-inline-start: 0;
+        font: var(--cpd-font-body-sm-regular);
+    }
+
+    span:not(.mx_DisambiguatedProfile_mxid) {
+        /**
+        In a member tile, this span element is a flex child and so
+        we need the following for text overflow to work.
+        **/
+        overflow: hidden;
+        text-overflow: ellipsis;
+        white-space: nowrap;
     }
 }
diff --git a/res/css/views/messages/_EventTileBubble.pcss b/res/css/views/messages/_EventTileBubble.pcss
index 16d48185fb6..4b47c8b78e2 100644
--- a/res/css/views/messages/_EventTileBubble.pcss
+++ b/res/css/views/messages/_EventTileBubble.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/messages/_HiddenBody.pcss b/res/css/views/messages/_HiddenBody.pcss
index 05c8df1b030..672cd262b20 100644
--- a/res/css/views/messages/_HiddenBody.pcss
+++ b/res/css/views/messages/_HiddenBody.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/messages/_JumpToDatePicker.pcss b/res/css/views/messages/_JumpToDatePicker.pcss
index b65091aa4c2..b4b0244be56 100644
--- a/res/css/views/messages/_JumpToDatePicker.pcss
+++ b/res/css/views/messages/_JumpToDatePicker.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/messages/_LegacyCallEvent.pcss b/res/css/views/messages/_LegacyCallEvent.pcss
index 54ebb957667..c79279b7633 100644
--- a/res/css/views/messages/_LegacyCallEvent.pcss
+++ b/res/css/views/messages/_LegacyCallEvent.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/messages/_MEmoteBody.pcss b/res/css/views/messages/_MEmoteBody.pcss
index 4d90af68fa0..ad7abb01766 100644
--- a/res/css/views/messages/_MEmoteBody.pcss
+++ b/res/css/views/messages/_MEmoteBody.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2017 Vector Creations Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/messages/_MFileBody.pcss b/res/css/views/messages/_MFileBody.pcss
index 2ce13320efc..c8361f1d296 100644
--- a/res/css/views/messages/_MFileBody.pcss
+++ b/res/css/views/messages/_MFileBody.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/messages/_MImageBody.pcss b/res/css/views/messages/_MImageBody.pcss
index 6a6f31948a7..5942bb44b3d 100644
--- a/res/css/views/messages/_MImageBody.pcss
+++ b/res/css/views/messages/_MImageBody.pcss
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/messages/_MImageReplyBody.pcss b/res/css/views/messages/_MImageReplyBody.pcss
index 58621c78767..9576e75fd81 100644
--- a/res/css/views/messages/_MImageReplyBody.pcss
+++ b/res/css/views/messages/_MImageReplyBody.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 Tulir Asokan <tulir@maunium.net>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/messages/_MJitsiWidgetEvent.pcss b/res/css/views/messages/_MJitsiWidgetEvent.pcss
index 6375c99d5b2..252681f6848 100644
--- a/res/css/views/messages/_MJitsiWidgetEvent.pcss
+++ b/res/css/views/messages/_MJitsiWidgetEvent.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/messages/_MLocationBody.pcss b/res/css/views/messages/_MLocationBody.pcss
index c388a58ee7b..ad597c42aa3 100644
--- a/res/css/views/messages/_MLocationBody.pcss
+++ b/res/css/views/messages/_MLocationBody.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/messages/_MNoticeBody.pcss b/res/css/views/messages/_MNoticeBody.pcss
index 92647ba90fe..f82c2b8fcc9 100644
--- a/res/css/views/messages/_MNoticeBody.pcss
+++ b/res/css/views/messages/_MNoticeBody.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/messages/_MPollBody.pcss b/res/css/views/messages/_MPollBody.pcss
index 7b272d7aa87..33144083ea9 100644
--- a/res/css/views/messages/_MPollBody.pcss
+++ b/res/css/views/messages/_MPollBody.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/messages/_MPollEndBody.pcss b/res/css/views/messages/_MPollEndBody.pcss
index 59787818bbd..655f444e357 100644
--- a/res/css/views/messages/_MPollEndBody.pcss
+++ b/res/css/views/messages/_MPollEndBody.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/messages/_MStickerBody.pcss b/res/css/views/messages/_MStickerBody.pcss
index 7db1c396c0e..d6331fce599 100644
--- a/res/css/views/messages/_MStickerBody.pcss
+++ b/res/css/views/messages/_MStickerBody.pcss
@@ -1,7 +1,7 @@
 /*
 Copyright 2018-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/messages/_MTextBody.pcss b/res/css/views/messages/_MTextBody.pcss
index 9d17fc4f005..973fd3a3540 100644
--- a/res/css/views/messages/_MTextBody.pcss
+++ b/res/css/views/messages/_MTextBody.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/messages/_MVideoBody.pcss b/res/css/views/messages/_MVideoBody.pcss
index bc384754ab7..0727a8dc443 100644
--- a/res/css/views/messages/_MVideoBody.pcss
+++ b/res/css/views/messages/_MVideoBody.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020, 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/messages/_MediaBody.pcss b/res/css/views/messages/_MediaBody.pcss
index aeafe0f0ee3..d3eb02ca651 100644
--- a/res/css/views/messages/_MediaBody.pcss
+++ b/res/css/views/messages/_MediaBody.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/messages/_MessageActionBar.pcss b/res/css/views/messages/_MessageActionBar.pcss
index cdfc3693d53..61897bb34f7 100644
--- a/res/css/views/messages/_MessageActionBar.pcss
+++ b/res/css/views/messages/_MessageActionBar.pcss
@@ -2,7 +2,7 @@
 Copyright 2019-2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/messages/_MessageTimestamp.pcss b/res/css/views/messages/_MessageTimestamp.pcss
index 2bb90033e3e..2cca6a3aaf4 100644
--- a/res/css/views/messages/_MessageTimestamp.pcss
+++ b/res/css/views/messages/_MessageTimestamp.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/messages/_MjolnirBody.pcss b/res/css/views/messages/_MjolnirBody.pcss
index 5c9a749c064..825eb36af67 100644
--- a/res/css/views/messages/_MjolnirBody.pcss
+++ b/res/css/views/messages/_MjolnirBody.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/messages/_PinnedMessageBadge.pcss b/res/css/views/messages/_PinnedMessageBadge.pcss
index 99770a70378..69b592d7898 100644
--- a/res/css/views/messages/_PinnedMessageBadge.pcss
+++ b/res/css/views/messages/_PinnedMessageBadge.pcss
@@ -1,9 +1,8 @@
 /*
  * Copyright 2024 New Vector Ltd.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
- *
  */
 
 .mx_PinnedMessageBadge {
diff --git a/res/css/views/messages/_ReactionsRow.pcss b/res/css/views/messages/_ReactionsRow.pcss
index e07b529ef44..e787e505173 100644
--- a/res/css/views/messages/_ReactionsRow.pcss
+++ b/res/css/views/messages/_ReactionsRow.pcss
@@ -1,7 +1,7 @@
 /*
 Copyright 2019-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/messages/_ReactionsRowButton.pcss b/res/css/views/messages/_ReactionsRowButton.pcss
index dd9d7ddb479..917bcfbb843 100644
--- a/res/css/views/messages/_ReactionsRowButton.pcss
+++ b/res/css/views/messages/_ReactionsRowButton.pcss
@@ -1,7 +1,7 @@
 /*
 Copyright 2019-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/messages/_RedactedBody.pcss b/res/css/views/messages/_RedactedBody.pcss
index 7939cc6d098..7b114b1866b 100644
--- a/res/css/views/messages/_RedactedBody.pcss
+++ b/res/css/views/messages/_RedactedBody.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/messages/_RoomAvatarEvent.pcss b/res/css/views/messages/_RoomAvatarEvent.pcss
index f8ff857c822..340c5a87bd7 100644
--- a/res/css/views/messages/_RoomAvatarEvent.pcss
+++ b/res/css/views/messages/_RoomAvatarEvent.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2017 Vector Creations Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/messages/_TextualEvent.pcss b/res/css/views/messages/_TextualEvent.pcss
index 2a27efccc65..bf7061f2ba9 100644
--- a/res/css/views/messages/_TextualEvent.pcss
+++ b/res/css/views/messages/_TextualEvent.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/messages/_TimelineSeparator.pcss b/res/css/views/messages/_TimelineSeparator.pcss
index fcf41e9f05a..aab77d4e032 100644
--- a/res/css/views/messages/_TimelineSeparator.pcss
+++ b/res/css/views/messages/_TimelineSeparator.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2017 Vector Creations Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/messages/_UnknownBody.pcss b/res/css/views/messages/_UnknownBody.pcss
index 2b768052157..9583f55734e 100644
--- a/res/css/views/messages/_UnknownBody.pcss
+++ b/res/css/views/messages/_UnknownBody.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/messages/_ViewSourceEvent.pcss b/res/css/views/messages/_ViewSourceEvent.pcss
index 6b497719d93..02dce05bbbf 100644
--- a/res/css/views/messages/_ViewSourceEvent.pcss
+++ b/res/css/views/messages/_ViewSourceEvent.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/messages/_common_CryptoEvent.pcss b/res/css/views/messages/_common_CryptoEvent.pcss
index ef0177c2d2e..ba18f4f2ae3 100644
--- a/res/css/views/messages/_common_CryptoEvent.pcss
+++ b/res/css/views/messages/_common_CryptoEvent.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/polls/pollHistory/_PollHistory.pcss b/res/css/views/polls/pollHistory/_PollHistory.pcss
index a68e6ffaf9e..ee28f01b652 100644
--- a/res/css/views/polls/pollHistory/_PollHistory.pcss
+++ b/res/css/views/polls/pollHistory/_PollHistory.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/polls/pollHistory/_PollHistoryList.pcss b/res/css/views/polls/pollHistory/_PollHistoryList.pcss
index 4ac97a70d52..95d54192f91 100644
--- a/res/css/views/polls/pollHistory/_PollHistoryList.pcss
+++ b/res/css/views/polls/pollHistory/_PollHistoryList.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/right_panel/_BaseCard.pcss b/res/css/views/right_panel/_BaseCard.pcss
index d09a280dfab..83e1fc28d48 100644
--- a/res/css/views/right_panel/_BaseCard.pcss
+++ b/res/css/views/right_panel/_BaseCard.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/right_panel/_EmptyState.pcss b/res/css/views/right_panel/_EmptyState.pcss
index 8ac6ac2555f..05bc2882b8d 100644
--- a/res/css/views/right_panel/_EmptyState.pcss
+++ b/res/css/views/right_panel/_EmptyState.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/right_panel/_EncryptionInfo.pcss b/res/css/views/right_panel/_EncryptionInfo.pcss
index e9fbc736813..9abc23ef70d 100644
--- a/res/css/views/right_panel/_EncryptionInfo.pcss
+++ b/res/css/views/right_panel/_EncryptionInfo.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/right_panel/_ExtensionsCard.pcss b/res/css/views/right_panel/_ExtensionsCard.pcss
index ee3984537ba..65dc23f6671 100644
--- a/res/css/views/right_panel/_ExtensionsCard.pcss
+++ b/res/css/views/right_panel/_ExtensionsCard.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/right_panel/_PinnedMessagesCard.pcss b/res/css/views/right_panel/_PinnedMessagesCard.pcss
index 731af8b1475..6a156533980 100644
--- a/res/css/views/right_panel/_PinnedMessagesCard.pcss
+++ b/res/css/views/right_panel/_PinnedMessagesCard.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/right_panel/_RoomSummaryCard.pcss b/res/css/views/right_panel/_RoomSummaryCard.pcss
index 8dcbfe2e0a9..fb1d6f7d9cd 100644
--- a/res/css/views/right_panel/_RoomSummaryCard.pcss
+++ b/res/css/views/right_panel/_RoomSummaryCard.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/right_panel/_ThreadPanel.pcss b/res/css/views/right_panel/_ThreadPanel.pcss
index 1f9d1e0562d..b21eb17f033 100644
--- a/res/css/views/right_panel/_ThreadPanel.pcss
+++ b/res/css/views/right_panel/_ThreadPanel.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021-2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/right_panel/_TimelineCard.pcss b/res/css/views/right_panel/_TimelineCard.pcss
index adaf20f2861..cbd373c7f5c 100644
--- a/res/css/views/right_panel/_TimelineCard.pcss
+++ b/res/css/views/right_panel/_TimelineCard.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021, 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/right_panel/_UserInfo.pcss b/res/css/views/right_panel/_UserInfo.pcss
index d381d03867d..0af5585d1a2 100644
--- a/res/css/views/right_panel/_UserInfo.pcss
+++ b/res/css/views/right_panel/_UserInfo.pcss
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/right_panel/_VerificationPanel.pcss b/res/css/views/right_panel/_VerificationPanel.pcss
index f743724b591..40b6de32668 100644
--- a/res/css/views/right_panel/_VerificationPanel.pcss
+++ b/res/css/views/right_panel/_VerificationPanel.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/right_panel/_WidgetCard.pcss b/res/css/views/right_panel/_WidgetCard.pcss
index 6fcc3e9963e..cba86194ce4 100644
--- a/res/css/views/right_panel/_WidgetCard.pcss
+++ b/res/css/views/right_panel/_WidgetCard.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/room_settings/_AliasSettings.pcss b/res/css/views/room_settings/_AliasSettings.pcss
index ca2c24b2964..821a6543031 100644
--- a/res/css/views/room_settings/_AliasSettings.pcss
+++ b/res/css/views/room_settings/_AliasSettings.pcss
@@ -1,7 +1,7 @@
 /*
 Copyright 2019-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/rooms/_AppsDrawer.pcss b/res/css/views/rooms/_AppsDrawer.pcss
index baf967b7deb..e8baa1257b7 100644
--- a/res/css/views/rooms/_AppsDrawer.pcss
+++ b/res/css/views/rooms/_AppsDrawer.pcss
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/rooms/_AuxPanel.pcss b/res/css/views/rooms/_AuxPanel.pcss
index f1440fd98a9..c2477287b03 100644
--- a/res/css/views/rooms/_AuxPanel.pcss
+++ b/res/css/views/rooms/_AuxPanel.pcss
@@ -1,7 +1,7 @@
 /*
 Copyright 2018-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/rooms/_BasicMessageComposer.pcss b/res/css/views/rooms/_BasicMessageComposer.pcss
index 499ce870ecc..5729c22075c 100644
--- a/res/css/views/rooms/_BasicMessageComposer.pcss
+++ b/res/css/views/rooms/_BasicMessageComposer.pcss
@@ -2,7 +2,7 @@
 Copyright 2019-2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/rooms/_DecryptionFailureBar.pcss b/res/css/views/rooms/_DecryptionFailureBar.pcss
index d38d753e0b0..ca6709b24b7 100644
--- a/res/css/views/rooms/_DecryptionFailureBar.pcss
+++ b/res/css/views/rooms/_DecryptionFailureBar.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/rooms/_E2EIcon.pcss b/res/css/views/rooms/_E2EIcon.pcss
index 0d9e7cf7e3d..f3aaf8a8833 100644
--- a/res/css/views/rooms/_E2EIcon.pcss
+++ b/res/css/views/rooms/_E2EIcon.pcss
@@ -1,7 +1,7 @@
 /*
 Copyright 2019-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/rooms/_E2EIconView.pcss b/res/css/views/rooms/_E2EIconView.pcss
new file mode 100644
index 00000000000..3e2b1d95802
--- /dev/null
+++ b/res/css/views/rooms/_E2EIconView.pcss
@@ -0,0 +1,20 @@
+/*
+Copyright 2024 New Vector Ltd.
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+Please see LICENSE files in the repository root for full details.
+*/
+
+.mx_E2EIconView {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+}
+
+.mx_E2EIconView_warning {
+    color: var(--cpd-color-icon-critical-primary);
+}
+
+.mx_E2EIconView_verified {
+    color: var(--cpd-color-icon-success-primary);
+}
diff --git a/res/css/views/rooms/_EditMessageComposer.pcss b/res/css/views/rooms/_EditMessageComposer.pcss
index 0fcc8345e65..dbc7aad4fd4 100644
--- a/res/css/views/rooms/_EditMessageComposer.pcss
+++ b/res/css/views/rooms/_EditMessageComposer.pcss
@@ -2,7 +2,7 @@
 Copyright 2019-2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/rooms/_EmojiButton.pcss b/res/css/views/rooms/_EmojiButton.pcss
index 8efdbb7dd23..16281046464 100644
--- a/res/css/views/rooms/_EmojiButton.pcss
+++ b/res/css/views/rooms/_EmojiButton.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/rooms/_EntityTile.pcss b/res/css/views/rooms/_EntityTile.pcss
deleted file mode 100644
index 979d5bb5d43..00000000000
--- a/res/css/views/rooms/_EntityTile.pcss
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2020 The Matrix.org Foundation C.I.C.
-Copyright 2015, 2016 OpenMarket Ltd
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
-Please see LICENSE files in the repository root for full details.
-*/
-
-.mx_EntityTile {
-    display: flex;
-    align-items: center;
-    color: $primary-content;
-    cursor: pointer;
-
-    .mx_E2EIcon {
-        margin: 0;
-        position: absolute;
-        bottom: 2px;
-        right: 7px;
-    }
-}
-
-.mx_EntityTile:hover {
-    padding-right: 30px;
-    position: relative; /* to keep the chevron aligned */
-}
-
-.mx_EntityTile:hover::before {
-    content: "";
-    position: absolute;
-    top: calc(50% - 8px); /* center */
-    right: -8px;
-    mask: url("@vector-im/compound-design-tokens/icons/chevron-right.svg");
-    mask-repeat: no-repeat;
-    mask-position: center;
-    width: 16px;
-    height: 16px;
-    background-color: $header-panel-text-primary-color;
-}
-
-.mx_EntityTile:not(.mx_EntityTile_unreachable) .mx_PresenceLabel {
-    display: none;
-}
-
-.mx_EntityTile:hover .mx_PresenceLabel {
-    display: block;
-}
-
-.mx_EntityTile_invite {
-    display: table-cell;
-    vertical-align: middle;
-    margin-left: 10px;
-    width: 26px;
-}
-
-.mx_EntityTile_avatar {
-    padding-left: 3px;
-    padding-right: 12px;
-    padding-top: 4px;
-    padding-bottom: 4px;
-    position: relative;
-    line-height: 0;
-}
-
-.mx_EntityTile_name {
-    flex: 1 1 0;
-    overflow: hidden;
-    font: var(--cpd-font-body-md-regular);
-    text-overflow: ellipsis;
-    white-space: nowrap;
-}
-
-.mx_EntityTile_details {
-    overflow: hidden;
-    flex: 1;
-}
-
-.mx_EntityTile_ellipsis .mx_EntityTile_name {
-    font-style: italic;
-    color: $primary-content;
-}
-
-.mx_EntityTile_invitePlaceholder .mx_EntityTile_name {
-    font-style: italic;
-    color: $primary-content;
-}
-
-.mx_EntityTile_unavailable .mx_EntityTile_avatar,
-.mx_EntityTile_unavailable .mx_EntityTile_name,
-.mx_EntityTile_offline_beenactive .mx_EntityTile_avatar,
-.mx_EntityTile_offline_beenactive .mx_EntityTile_name {
-    opacity: 0.5;
-}
-
-.mx_EntityTile_offline_neveractive .mx_EntityTile_avatar,
-.mx_EntityTile_offline_neveractive .mx_EntityTile_name {
-    opacity: 0.25;
-}
-
-.mx_EntityTile_unknown .mx_EntityTile_avatar,
-.mx_EntityTile_unknown .mx_EntityTile_name,
-.mx_EntityTile_unreachable .mx_EntityTile_avatar,
-.mx_EntityTile_unreachable .mx_EntityTile_name {
-    opacity: 0.25;
-}
-
-.mx_EntityTile_subtext {
-    font-size: $font-11px;
-    opacity: 0.5;
-    overflow: hidden;
-    white-space: nowrap;
-    text-overflow: clip;
-}
-
-.mx_EntityTile_power {
-    padding-inline-start: 6px;
-    font-size: $font-10px;
-    color: $secondary-content;
-    max-width: 6em;
-    overflow: hidden;
-    text-overflow: ellipsis;
-    white-space: nowrap;
-}
-
-.mx_EntityTile:hover .mx_EntityTile_power {
-    display: none;
-}
diff --git a/res/css/views/rooms/_EventBubbleTile.pcss b/res/css/views/rooms/_EventBubbleTile.pcss
index 7b1af0c771d..c25cbfcec41 100644
--- a/res/css/views/rooms/_EventBubbleTile.pcss
+++ b/res/css/views/rooms/_EventBubbleTile.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/rooms/_EventPreview.pcss b/res/css/views/rooms/_EventPreview.pcss
index 0639c76d98d..6999810abfc 100644
--- a/res/css/views/rooms/_EventPreview.pcss
+++ b/res/css/views/rooms/_EventPreview.pcss
@@ -1,9 +1,9 @@
 /*
-* Copyright 2024 New Vector Ltd.
-* Copyright 2024 The Matrix.org Foundation C.I.C.
-*
-* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
-* Please see LICENSE files in the repository root for full details.
+ * Copyright 2024 New Vector Ltd.
+ * Copyright 2024 The Matrix.org Foundation C.I.C.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
  */
 
 .mx_EventPreview {
diff --git a/res/css/views/rooms/_EventTile.pcss b/res/css/views/rooms/_EventTile.pcss
index d405381db1c..5b86e3f7532 100644
--- a/res/css/views/rooms/_EventTile.pcss
+++ b/res/css/views/rooms/_EventTile.pcss
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2020, 2021 The Matrix.org Foundation C.I.C.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/rooms/_HistoryTile.pcss b/res/css/views/rooms/_HistoryTile.pcss
index 659ccdaef29..09a75c3e4a5 100644
--- a/res/css/views/rooms/_HistoryTile.pcss
+++ b/res/css/views/rooms/_HistoryTile.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 Robin Townsend <robin@robin.town>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/rooms/_IRCLayout.pcss b/res/css/views/rooms/_IRCLayout.pcss
index ecf1c257168..953a0c941fd 100644
--- a/res/css/views/rooms/_IRCLayout.pcss
+++ b/res/css/views/rooms/_IRCLayout.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/rooms/_JumpToBottomButton.pcss b/res/css/views/rooms/_JumpToBottomButton.pcss
index 89aac3c58b5..912dda0f671 100644
--- a/res/css/views/rooms/_JumpToBottomButton.pcss
+++ b/res/css/views/rooms/_JumpToBottomButton.pcss
@@ -1,7 +1,7 @@
 /*
 Copyright 2019-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/rooms/_LinkPreviewGroup.pcss b/res/css/views/rooms/_LinkPreviewGroup.pcss
index 751a394c442..a98966bc209 100644
--- a/res/css/views/rooms/_LinkPreviewGroup.pcss
+++ b/res/css/views/rooms/_LinkPreviewGroup.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/rooms/_LinkPreviewWidget.pcss b/res/css/views/rooms/_LinkPreviewWidget.pcss
index 03134ce7336..99f4418c31a 100644
--- a/res/css/views/rooms/_LinkPreviewWidget.pcss
+++ b/res/css/views/rooms/_LinkPreviewWidget.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/rooms/_LiveContentSummary.pcss b/res/css/views/rooms/_LiveContentSummary.pcss
index 03f62d975f1..0736f0dd45b 100644
--- a/res/css/views/rooms/_LiveContentSummary.pcss
+++ b/res/css/views/rooms/_LiveContentSummary.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/rooms/_MemberList.pcss b/res/css/views/rooms/_MemberList.pcss
deleted file mode 100644
index e3fe819ab65..00000000000
--- a/res/css/views/rooms/_MemberList.pcss
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2015, 2016 OpenMarket Ltd
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
-Please see LICENSE files in the repository root for full details.
-*/
-
-.mx_MemberList {
-    flex: 1;
-    display: flex;
-    flex-direction: column;
-    min-height: 0;
-
-    .mx_Spinner {
-        flex: 1 0 auto;
-    }
-
-    .mx_SearchBox {
-        margin-bottom: 5px;
-    }
-
-    h2 {
-        text-transform: uppercase;
-        color: $h3-color;
-        font-weight: var(--cpd-font-weight-semibold);
-        font-size: $font-13px;
-        padding-left: 3px;
-        padding-right: 12px;
-        margin-top: 8px;
-        margin-bottom: 4px;
-    }
-
-    .mx_AutoHideScrollbar {
-        flex: 1 1 0;
-        margin-top: var(--cpd-space-3x);
-    }
-}
-
-.mx_MemberList_chevron {
-    position: absolute;
-    right: 35px;
-    margin-top: -15px;
-}
-
-.mx_MemberList_border {
-    overflow-y: auto;
-
-    order: 1;
-    flex: 1 1 0px;
-}
-
-.mx_MemberList_query {
-    height: 16px;
-
-    /* stricter rule to override the one in _common.pcss */
-    &[type="text"] {
-        font-size: $font-12px;
-    }
-}
-
-.mx_MemberList_wrapper {
-    padding: 10px;
-}
-
-.mx_MemberList_invite {
-    margin: 0 var(--cpd-space-2x);
-    width: calc(100% - var(--cpd-space-4x));
-}
diff --git a/res/css/views/rooms/_MemberListHeaderView.pcss b/res/css/views/rooms/_MemberListHeaderView.pcss
new file mode 100644
index 00000000000..326cf84dd6c
--- /dev/null
+++ b/res/css/views/rooms/_MemberListHeaderView.pcss
@@ -0,0 +1,37 @@
+/*
+Copyright 2024 New Vector Ltd.
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+Please see LICENSE files in the repository root for full details.
+*/
+
+.mx_MemberListHeaderView {
+    border-bottom: var(--cpd-border-width-1) solid var(--cpd-color-gray-400);
+    max-height: 112px;
+
+    .mx_MemberListHeaderView_container {
+        margin-top: var(--cpd-space-6x);
+        width: 100%;
+    }
+
+    .mx_MemberListHeaderView_invite_small {
+        margin-left: var(--cpd-space-3x);
+    }
+
+    .mx_MemberListHeaderView_invite_large {
+        width: 288px;
+        height: 36px;
+    }
+
+    .mx_MemberListHeaderView_label {
+        padding: var(--cpd-space-6x) 0 var(--cpd-space-2x) var(--cpd-space-4x);
+        box-sizing: border-box;
+        width: 100%;
+        color: var(--cpd-color-text-secondary);
+        font: var(--cpd-font-body-sm-semibold);
+    }
+
+    .mx_MemberListHeaderView_search {
+        width: 240px;
+    }
+}
diff --git a/res/css/views/rooms/_MemberListView.pcss b/res/css/views/rooms/_MemberListView.pcss
new file mode 100644
index 00000000000..e13b17b226e
--- /dev/null
+++ b/res/css/views/rooms/_MemberListView.pcss
@@ -0,0 +1,17 @@
+/*
+Copyright 2024 New Vector Ltd.
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+Please see LICENSE files in the repository root for full details.
+*/
+
+.mx_MemberListView {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    min-height: 0;
+
+    .mx_MemberListView_container {
+        height: 100%;
+    }
+}
diff --git a/res/css/views/rooms/_MemberTileView.pcss b/res/css/views/rooms/_MemberTileView.pcss
new file mode 100644
index 00000000000..702edd8f9d2
--- /dev/null
+++ b/res/css/views/rooms/_MemberTileView.pcss
@@ -0,0 +1,58 @@
+/*
+Copyright 2024 New Vector Ltd.
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+Please see LICENSE files in the repository root for full details.
+*/
+
+.mx_MemberTileView {
+    display: flex;
+    padding: var(--cpd-space-3x) var(--cpd-space-3x) var(--cpd-space-3x) var(--cpd-space-4x);
+    box-sizing: border-box;
+    height: 56px;
+    border-bottom: var(--cpd-border-width-1) solid var(--cpd-color-gray-300);
+
+    .mx_MemberTileView_left,
+    .mx_MemberTileView_right {
+        display: flex;
+        align-items: center;
+        gap: var(--cpd-space-2x);
+    }
+
+    .mx_MemberTileView_left {
+        flex-basis: 209px;
+        flex-grow: 1;
+        min-width: 0;
+    }
+
+    .mx_MemberTileView_name {
+        font: var(--cpd-font-body-md-medium);
+        font-size: 15px;
+        min-width: 0;
+    }
+
+    .mx_MemberTileView_user_label {
+        font: var(--cpd-font-body-sm-regular);
+        font-size: 13px;
+    }
+
+    .mx_MemberTileView_avatar {
+        position: relative;
+        height: 32px;
+        width: 32px;
+    }
+
+    .mx_E2EIconView {
+        display: flex;
+        justify-content: center;
+        align-items: center;
+    }
+
+    .mx_E2EIconView_warning {
+        color: var(--cpd-color-icon-critical-primary);
+    }
+
+    .mx_E2EIconView_verified {
+        color: var(--cpd-color-icon-success-primary);
+    }
+}
diff --git a/res/css/views/rooms/_MessageComposer.pcss b/res/css/views/rooms/_MessageComposer.pcss
index 73ac15c9c9e..8b92b682ec1 100644
--- a/res/css/views/rooms/_MessageComposer.pcss
+++ b/res/css/views/rooms/_MessageComposer.pcss
@@ -2,7 +2,7 @@
 Copyright 2018-2024 New Vector Ltd.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/rooms/_MessageComposerFormatBar.pcss b/res/css/views/rooms/_MessageComposerFormatBar.pcss
index 36bfe477d78..233fda1affc 100644
--- a/res/css/views/rooms/_MessageComposerFormatBar.pcss
+++ b/res/css/views/rooms/_MessageComposerFormatBar.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/rooms/_NewRoomIntro.pcss b/res/css/views/rooms/_NewRoomIntro.pcss
index 84fa5aead00..4f704facd91 100644
--- a/res/css/views/rooms/_NewRoomIntro.pcss
+++ b/res/css/views/rooms/_NewRoomIntro.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/rooms/_NotificationBadge.pcss b/res/css/views/rooms/_NotificationBadge.pcss
index 1e708fc8473..2066b81f0a2 100644
--- a/res/css/views/rooms/_NotificationBadge.pcss
+++ b/res/css/views/rooms/_NotificationBadge.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/rooms/_OverflowTile.pcss b/res/css/views/rooms/_OverflowTile.pcss
new file mode 100644
index 00000000000..a0ac5bb4f61
--- /dev/null
+++ b/res/css/views/rooms/_OverflowTile.pcss
@@ -0,0 +1,51 @@
+/*
+Copyright 2024 New Vector Ltd.
+Copyright 2020 The Matrix.org Foundation C.I.C.
+Copyright 2015, 2016 OpenMarket Ltd
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+Please see LICENSE files in the repository root for full details.
+*/
+
+.mx_OverflowTileView {
+    display: flex;
+    align-items: center;
+    color: $primary-content;
+    cursor: pointer;
+}
+
+.mx_OverflowTileView_text {
+    flex: 1 1 0;
+    overflow: hidden;
+    font: var(--cpd-font-body-md-regular);
+    text-overflow: ellipsis;
+    white-space: nowrap;
+    font-style: italic;
+}
+
+.mx_OverflowTileView:hover {
+    padding-right: 30px;
+    position: relative; /* to keep the chevron aligned */
+}
+
+.mx_OverflowTileView:hover::before {
+    content: "";
+    position: absolute;
+    top: calc(50% - 8px); /* center */
+    right: -8px;
+    mask: url("@vector-im/compound-design-tokens/icons/chevron-right.svg");
+    mask-repeat: no-repeat;
+    mask-position: center;
+    width: 16px;
+    height: 16px;
+    background-color: $header-panel-text-primary-color;
+}
+
+.mx_OverflowTileView_icon {
+    padding-left: 3px;
+    padding-right: 12px;
+    padding-top: 4px;
+    padding-bottom: 4px;
+    position: relative;
+    line-height: 0;
+}
diff --git a/res/css/views/rooms/_PinnedEventTile.pcss b/res/css/views/rooms/_PinnedEventTile.pcss
index f58645ee8f9..a39a7603db6 100644
--- a/res/css/views/rooms/_PinnedEventTile.pcss
+++ b/res/css/views/rooms/_PinnedEventTile.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2017 Travis Ralston
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/rooms/_PinnedMessageBanner.pcss b/res/css/views/rooms/_PinnedMessageBanner.pcss
index 27c79718338..da9b75b17d1 100644
--- a/res/css/views/rooms/_PinnedMessageBanner.pcss
+++ b/res/css/views/rooms/_PinnedMessageBanner.pcss
@@ -1,9 +1,9 @@
 /*
-* Copyright 2024 New Vector Ltd.
-* Copyright 2024 The Matrix.org Foundation C.I.C.
-*
-* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
-* Please see LICENSE files in the repository root for full details.
+ * Copyright 2024 New Vector Ltd.
+ * Copyright 2024 The Matrix.org Foundation C.I.C.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
  */
 
 .mx_PinnedMessageBanner {
diff --git a/res/css/views/rooms/_PresenceIconView.pcss b/res/css/views/rooms/_PresenceIconView.pcss
new file mode 100644
index 00000000000..e09fbdf2fa1
--- /dev/null
+++ b/res/css/views/rooms/_PresenceIconView.pcss
@@ -0,0 +1,32 @@
+/*
+Copyright 2024 New Vector Ltd.
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+Please see LICENSE files in the repository root for full details.
+*/
+
+.mx_PresenceIconView {
+    position: absolute;
+    top: 24px;
+    left: 24px;
+    width: 12px;
+    height: 12px;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    background: var(--cpd-color-bg-canvas-default);
+    border-radius: 100%;
+
+    .mx_PresenceIconView_online {
+        color: var(--cpd-color-icon-accent-primary);
+    }
+
+    .mx_PresenceIconView_offline,
+    .mx_PresenceIconView_dnd {
+        color: var(--cpd-color-icon-tertiary);
+    }
+
+    .mx_PresenceIconView_unavailable {
+        color: var(--cpd-color-icon-quaternary);
+    }
+}
diff --git a/res/css/views/rooms/_PresenceLabel.pcss b/res/css/views/rooms/_PresenceLabel.pcss
index c9c610c221d..7f7f6dbfaf6 100644
--- a/res/css/views/rooms/_PresenceLabel.pcss
+++ b/res/css/views/rooms/_PresenceLabel.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/rooms/_ReadReceiptGroup.pcss b/res/css/views/rooms/_ReadReceiptGroup.pcss
index 743f38459ec..1b6c1b4b440 100644
--- a/res/css/views/rooms/_ReadReceiptGroup.pcss
+++ b/res/css/views/rooms/_ReadReceiptGroup.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/rooms/_ReplyPreview.pcss b/res/css/views/rooms/_ReplyPreview.pcss
index 2aef45ef717..9e48e6656b9 100644
--- a/res/css/views/rooms/_ReplyPreview.pcss
+++ b/res/css/views/rooms/_ReplyPreview.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2018 Vector Creations Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/rooms/_ReplyTile.pcss b/res/css/views/rooms/_ReplyTile.pcss
index 82cdd59ccf4..803e38c67f6 100644
--- a/res/css/views/rooms/_ReplyTile.pcss
+++ b/res/css/views/rooms/_ReplyTile.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 Tulir Asokan <tulir@maunium.net>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/rooms/_RoomBreadcrumbs.pcss b/res/css/views/rooms/_RoomBreadcrumbs.pcss
index 8aadb3061f5..7dd150cd27b 100644
--- a/res/css/views/rooms/_RoomBreadcrumbs.pcss
+++ b/res/css/views/rooms/_RoomBreadcrumbs.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/rooms/_RoomCallBanner.pcss b/res/css/views/rooms/_RoomCallBanner.pcss
index 2596d220f80..0be3abe26f7 100644
--- a/res/css/views/rooms/_RoomCallBanner.pcss
+++ b/res/css/views/rooms/_RoomCallBanner.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/rooms/_RoomHeader.pcss b/res/css/views/rooms/_RoomHeader.pcss
index a53d06fd1c0..32eb055f07e 100644
--- a/res/css/views/rooms/_RoomHeader.pcss
+++ b/res/css/views/rooms/_RoomHeader.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/rooms/_RoomInfoLine.pcss b/res/css/views/rooms/_RoomInfoLine.pcss
index 0c49b63c633..16127b1c6d0 100644
--- a/res/css/views/rooms/_RoomInfoLine.pcss
+++ b/res/css/views/rooms/_RoomInfoLine.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/rooms/_RoomKnocksBar.pcss b/res/css/views/rooms/_RoomKnocksBar.pcss
index 4fc1ab9a71f..2661bb069ae 100644
--- a/res/css/views/rooms/_RoomKnocksBar.pcss
+++ b/res/css/views/rooms/_RoomKnocksBar.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 Nordeck IT + Consulting GmbH
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/rooms/_RoomList.pcss b/res/css/views/rooms/_RoomList.pcss
index 97b1e76cef8..74e2e86ed1d 100644
--- a/res/css/views/rooms/_RoomList.pcss
+++ b/res/css/views/rooms/_RoomList.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/rooms/_RoomListHeader.pcss b/res/css/views/rooms/_RoomListHeader.pcss
index fa0e0b24eb3..396aa4a61a7 100644
--- a/res/css/views/rooms/_RoomListHeader.pcss
+++ b/res/css/views/rooms/_RoomListHeader.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/rooms/_RoomPreviewBar.pcss b/res/css/views/rooms/_RoomPreviewBar.pcss
index e0528383771..39df898c1ac 100644
--- a/res/css/views/rooms/_RoomPreviewBar.pcss
+++ b/res/css/views/rooms/_RoomPreviewBar.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015-2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/rooms/_RoomPreviewCard.pcss b/res/css/views/rooms/_RoomPreviewCard.pcss
index f96b705cc2b..bad3a9ad05c 100644
--- a/res/css/views/rooms/_RoomPreviewCard.pcss
+++ b/res/css/views/rooms/_RoomPreviewCard.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/rooms/_RoomSearchAuxPanel.pcss b/res/css/views/rooms/_RoomSearchAuxPanel.pcss
index 91ed8fe9f17..3e66f7103c7 100644
--- a/res/css/views/rooms/_RoomSearchAuxPanel.pcss
+++ b/res/css/views/rooms/_RoomSearchAuxPanel.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/rooms/_RoomSublist.pcss b/res/css/views/rooms/_RoomSublist.pcss
index a8041344301..f5d0e4ed913 100644
--- a/res/css/views/rooms/_RoomSublist.pcss
+++ b/res/css/views/rooms/_RoomSublist.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/rooms/_RoomTile.pcss b/res/css/views/rooms/_RoomTile.pcss
index 53f9c10f1b3..798f3bfa462 100644
--- a/res/css/views/rooms/_RoomTile.pcss
+++ b/res/css/views/rooms/_RoomTile.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020-2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/rooms/_RoomUpgradeWarningBar.pcss b/res/css/views/rooms/_RoomUpgradeWarningBar.pcss
index 240132dd70d..d561a9b81bd 100644
--- a/res/css/views/rooms/_RoomUpgradeWarningBar.pcss
+++ b/res/css/views/rooms/_RoomUpgradeWarningBar.pcss
@@ -1,7 +1,7 @@
 /*
 Copyright 2018-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/rooms/_SendMessageComposer.pcss b/res/css/views/rooms/_SendMessageComposer.pcss
index b88bb394715..a0fc1e81329 100644
--- a/res/css/views/rooms/_SendMessageComposer.pcss
+++ b/res/css/views/rooms/_SendMessageComposer.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/rooms/_ThirdPartyMemberInfo.pcss b/res/css/views/rooms/_ThirdPartyMemberInfo.pcss
index c645a0ba385..96aadc895e1 100644
--- a/res/css/views/rooms/_ThirdPartyMemberInfo.pcss
+++ b/res/css/views/rooms/_ThirdPartyMemberInfo.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/rooms/_ThreadSummary.pcss b/res/css/views/rooms/_ThreadSummary.pcss
index 118ee512831..0e30cd3fedd 100644
--- a/res/css/views/rooms/_ThreadSummary.pcss
+++ b/res/css/views/rooms/_ThreadSummary.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/rooms/_TopUnreadMessagesBar.pcss b/res/css/views/rooms/_TopUnreadMessagesBar.pcss
index dafe192e763..d80bc129160 100644
--- a/res/css/views/rooms/_TopUnreadMessagesBar.pcss
+++ b/res/css/views/rooms/_TopUnreadMessagesBar.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/rooms/_UserIdentityWarning.pcss b/res/css/views/rooms/_UserIdentityWarning.pcss
index b294b3fc8cf..e5d14eb4726 100644
--- a/res/css/views/rooms/_UserIdentityWarning.pcss
+++ b/res/css/views/rooms/_UserIdentityWarning.pcss
@@ -1,7 +1,7 @@
 /*
 Copyright 2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/rooms/_VoiceRecordComposerTile.pcss b/res/css/views/rooms/_VoiceRecordComposerTile.pcss
index 9e51dbea6c2..8dabc06fe58 100644
--- a/res/css/views/rooms/_VoiceRecordComposerTile.pcss
+++ b/res/css/views/rooms/_VoiceRecordComposerTile.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/rooms/_WhoIsTypingTile.pcss b/res/css/views/rooms/_WhoIsTypingTile.pcss
index a126a8baf28..eb604155c5d 100644
--- a/res/css/views/rooms/_WhoIsTypingTile.pcss
+++ b/res/css/views/rooms/_WhoIsTypingTile.pcss
@@ -1,7 +1,7 @@
 /*
 Copyright 2018-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/rooms/wysiwyg_composer/_EditWysiwygComposer.pcss b/res/css/views/rooms/wysiwyg_composer/_EditWysiwygComposer.pcss
index 4f40280c246..a27f7b9b777 100644
--- a/res/css/views/rooms/wysiwyg_composer/_EditWysiwygComposer.pcss
+++ b/res/css/views/rooms/wysiwyg_composer/_EditWysiwygComposer.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/rooms/wysiwyg_composer/_SendWysiwygComposer.pcss b/res/css/views/rooms/wysiwyg_composer/_SendWysiwygComposer.pcss
index b629088dac1..5ad59dd8e5b 100644
--- a/res/css/views/rooms/wysiwyg_composer/_SendWysiwygComposer.pcss
+++ b/res/css/views/rooms/wysiwyg_composer/_SendWysiwygComposer.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/rooms/wysiwyg_composer/components/_Editor.pcss b/res/css/views/rooms/wysiwyg_composer/components/_Editor.pcss
index 34c2a4d626e..4de58b123bc 100644
--- a/res/css/views/rooms/wysiwyg_composer/components/_Editor.pcss
+++ b/res/css/views/rooms/wysiwyg_composer/components/_Editor.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/rooms/wysiwyg_composer/components/_FormattingButtons.pcss b/res/css/views/rooms/wysiwyg_composer/components/_FormattingButtons.pcss
index 42047531664..f43f313b088 100644
--- a/res/css/views/rooms/wysiwyg_composer/components/_FormattingButtons.pcss
+++ b/res/css/views/rooms/wysiwyg_composer/components/_FormattingButtons.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/rooms/wysiwyg_composer/components/_LinkModal.pcss b/res/css/views/rooms/wysiwyg_composer/components/_LinkModal.pcss
index 77848421fd9..346e05efc37 100644
--- a/res/css/views/rooms/wysiwyg_composer/components/_LinkModal.pcss
+++ b/res/css/views/rooms/wysiwyg_composer/components/_LinkModal.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/settings/_AvatarSetting.pcss b/res/css/views/settings/_AvatarSetting.pcss
index fcab16a98ee..b928522820e 100644
--- a/res/css/views/settings/_AvatarSetting.pcss
+++ b/res/css/views/settings/_AvatarSetting.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/settings/_CrossSigningPanel.pcss b/res/css/views/settings/_CrossSigningPanel.pcss
index 7a68fcddf5c..e9b2aa0c293 100644
--- a/res/css/views/settings/_CrossSigningPanel.pcss
+++ b/res/css/views/settings/_CrossSigningPanel.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/settings/_CryptographyPanel.pcss b/res/css/views/settings/_CryptographyPanel.pcss
index dfef7285d2a..9c174ceaab7 100644
--- a/res/css/views/settings/_CryptographyPanel.pcss
+++ b/res/css/views/settings/_CryptographyPanel.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/settings/_FontScalingPanel.pcss b/res/css/views/settings/_FontScalingPanel.pcss
index e66c2205337..56e90bd9b82 100644
--- a/res/css/views/settings/_FontScalingPanel.pcss
+++ b/res/css/views/settings/_FontScalingPanel.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/settings/_ImageSizePanel.pcss b/res/css/views/settings/_ImageSizePanel.pcss
index 8456d16d9ca..174f5a262ad 100644
--- a/res/css/views/settings/_ImageSizePanel.pcss
+++ b/res/css/views/settings/_ImageSizePanel.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/settings/_IntegrationManager.pcss b/res/css/views/settings/_IntegrationManager.pcss
index 2bc8e9440e2..15b7ef4b0de 100644
--- a/res/css/views/settings/_IntegrationManager.pcss
+++ b/res/css/views/settings/_IntegrationManager.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/settings/_JoinRuleSettings.pcss b/res/css/views/settings/_JoinRuleSettings.pcss
index 965db9fb45f..485434f0da5 100644
--- a/res/css/views/settings/_JoinRuleSettings.pcss
+++ b/res/css/views/settings/_JoinRuleSettings.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/settings/_KeyboardShortcut.pcss b/res/css/views/settings/_KeyboardShortcut.pcss
index 826935eb1a8..b35629c98f6 100644
--- a/res/css/views/settings/_KeyboardShortcut.pcss
+++ b/res/css/views/settings/_KeyboardShortcut.pcss
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/settings/_LayoutSwitcher.pcss b/res/css/views/settings/_LayoutSwitcher.pcss
index 07da23389b0..8d50fa25d39 100644
--- a/res/css/views/settings/_LayoutSwitcher.pcss
+++ b/res/css/views/settings/_LayoutSwitcher.pcss
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
 Copyright 2020, 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/settings/_NotificationPusherSettings.pcss b/res/css/views/settings/_NotificationPusherSettings.pcss
index 78c2e9f1794..a8fc8f7e7d2 100644
--- a/res/css/views/settings/_NotificationPusherSettings.pcss
+++ b/res/css/views/settings/_NotificationPusherSettings.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/settings/_NotificationSettings2.pcss b/res/css/views/settings/_NotificationSettings2.pcss
index a56326ac323..d579c22b95b 100644
--- a/res/css/views/settings/_NotificationSettings2.pcss
+++ b/res/css/views/settings/_NotificationSettings2.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/settings/_Notifications.pcss b/res/css/views/settings/_Notifications.pcss
index a7f38507ccf..e4e450fd581 100644
--- a/res/css/views/settings/_Notifications.pcss
+++ b/res/css/views/settings/_Notifications.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/settings/_PhoneNumbers.pcss b/res/css/views/settings/_PhoneNumbers.pcss
index e6de1320f4f..9a5f1e49499 100644
--- a/res/css/views/settings/_PhoneNumbers.pcss
+++ b/res/css/views/settings/_PhoneNumbers.pcss
@@ -2,7 +2,7 @@
 Copyright 2019-2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/settings/_PowerLevelSelector.pcss b/res/css/views/settings/_PowerLevelSelector.pcss
index 6d5cf0a78f7..64c862742bb 100644
--- a/res/css/views/settings/_PowerLevelSelector.pcss
+++ b/res/css/views/settings/_PowerLevelSelector.pcss
@@ -1,9 +1,9 @@
 /*
-* Copyright 2024 New Vector Ltd.
-* Copyright 2024 The Matrix.org Foundation C.I.C.
-*
-* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
-* Please see LICENSE files in the repository root for full details.
+ * Copyright 2024 New Vector Ltd.
+ * Copyright 2024 The Matrix.org Foundation C.I.C.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
  */
 
 .mx_PowerLevelSelector_Button {
diff --git a/res/css/views/settings/_RoomProfileSettings.pcss b/res/css/views/settings/_RoomProfileSettings.pcss
index 14251ff291f..5b196a44b4f 100644
--- a/res/css/views/settings/_RoomProfileSettings.pcss
+++ b/res/css/views/settings/_RoomProfileSettings.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019, 2020 , 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/settings/_SecureBackupPanel.pcss b/res/css/views/settings/_SecureBackupPanel.pcss
index ed77fcad4f6..6e571af3391 100644
--- a/res/css/views/settings/_SecureBackupPanel.pcss
+++ b/res/css/views/settings/_SecureBackupPanel.pcss
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
 Copyright 2018 New Vector Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/settings/_SetIdServer.pcss b/res/css/views/settings/_SetIdServer.pcss
index da752b17f32..377292451ff 100644
--- a/res/css/views/settings/_SetIdServer.pcss
+++ b/res/css/views/settings/_SetIdServer.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/settings/_SetIntegrationManager.pcss b/res/css/views/settings/_SetIntegrationManager.pcss
index acdff690266..a046ce0fffa 100644
--- a/res/css/views/settings/_SetIntegrationManager.pcss
+++ b/res/css/views/settings/_SetIntegrationManager.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/settings/_SettingsFieldset.pcss b/res/css/views/settings/_SettingsFieldset.pcss
index d45671f37f0..2b013da4b1e 100644
--- a/res/css/views/settings/_SettingsFieldset.pcss
+++ b/res/css/views/settings/_SettingsFieldset.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/settings/_SettingsHeader.pcss b/res/css/views/settings/_SettingsHeader.pcss
new file mode 100644
index 00000000000..a705deda6cf
--- /dev/null
+++ b/res/css/views/settings/_SettingsHeader.pcss
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2024 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+.mx_SettingsHeader {
+    display: flex;
+    align-items: center;
+    gap: var(--cpd-space-2x);
+    /* Override margin from common.pcss */
+    margin: 0;
+
+    > span {
+        font: var(--cpd-font-body-sm-medium);
+        color: var(--cpd-color-text-action-accent);
+    }
+}
diff --git a/res/css/views/settings/_SettingsSubheader.pcss b/res/css/views/settings/_SettingsSubheader.pcss
new file mode 100644
index 00000000000..276421e5be5
--- /dev/null
+++ b/res/css/views/settings/_SettingsSubheader.pcss
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2024 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+.mx_SettingsSubheader {
+    display: flex;
+    flex-direction: column;
+    gap: var(--cpd-space-2x);
+
+    > span {
+        display: flex;
+        align-items: center;
+        gap: var(--cpd-space-2x);
+        font: var(--cpd-font-body-sm-medium);
+    }
+
+    .mx_SettingsSubheader_success {
+        color: var(--cpd-color-text-success-primary);
+    }
+
+    .mx_SettingsSubheader_error {
+        color: var(--cpd-color-text-critical-primary);
+    }
+}
diff --git a/res/css/views/settings/_SpellCheckLanguages.pcss b/res/css/views/settings/_SpellCheckLanguages.pcss
index afd506d49d0..42b247b747f 100644
--- a/res/css/views/settings/_SpellCheckLanguages.pcss
+++ b/res/css/views/settings/_SpellCheckLanguages.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/settings/_ThemeChoicePanel.pcss b/res/css/views/settings/_ThemeChoicePanel.pcss
index 33a4b0d17fa..e61671f4f5a 100644
--- a/res/css/views/settings/_ThemeChoicePanel.pcss
+++ b/res/css/views/settings/_ThemeChoicePanel.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/settings/_UpdateCheckButton.pcss b/res/css/views/settings/_UpdateCheckButton.pcss
index 6b81efec8a7..e0cab2ad5a9 100644
--- a/res/css/views/settings/_UpdateCheckButton.pcss
+++ b/res/css/views/settings/_UpdateCheckButton.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/settings/_UserProfileSettings.pcss b/res/css/views/settings/_UserProfileSettings.pcss
index a46972e582d..9f05851e294 100644
--- a/res/css/views/settings/_UserProfileSettings.pcss
+++ b/res/css/views/settings/_UserProfileSettings.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019, 2020 , 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/settings/encryption/_ChangeRecoveryKey.pcss b/res/css/views/settings/encryption/_ChangeRecoveryKey.pcss
new file mode 100644
index 00000000000..d6577431404
--- /dev/null
+++ b/res/css/views/settings/encryption/_ChangeRecoveryKey.pcss
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2024 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+.mx_ChangeRecoveryKey {
+    .mx_InformationPanel_description {
+        text-align: center;
+    }
+
+    .mx_ChangeRecoveryKey_Form {
+        display: flex;
+        flex-direction: column;
+        gap: var(--cpd-space-8x);
+
+        .mx_ChangeRecoveryKey_footer {
+            display: flex;
+            flex-direction: column;
+            gap: var(--cpd-space-4x);
+            justify-content: center;
+        }
+    }
+
+    .mx_KeyPanel {
+        display: grid;
+        grid-template:
+            "header button" auto
+            "content button" auto / 1fr;
+
+        column-gap: var(--cpd-space-3x);
+        row-gap: var(--cpd-space-1x);
+        align-items: center;
+
+        > span {
+            grid-area: header;
+        }
+
+        > div {
+            grid-area: content;
+            display: flex;
+            flex-direction: column;
+            gap: var(--cpd-space-2x);
+            color: var(--cpd-color-text-secondary);
+
+            .mx_KeyPanel_key {
+                font-family: Inconsolata, monospace;
+                /*
+                 * From figma https://www.figma.com/design/qTWRfItpO3RdCjnTKPu4mL/Settings?node-id=375-77471&t=t7lozYrSI1AVZZ3U-4
+                 */
+                height: 70px;
+                box-sizing: border-box;
+                border-radius: var(--cpd-space-2x);
+                padding: var(--cpd-space-3x) var(--cpd-space-4x);
+                background-color: var(--cpd-color-bg-subtle-secondary);
+            }
+        }
+
+        > button {
+            margin: 0 var(--cpd-space-1x);
+            grid-area: button;
+            color: var(--cpd-color-icon-secondary-alpha);
+        }
+    }
+
+    .mx_KeyForm {
+        display: flex;
+        flex-direction: column;
+        gap: var(--cpd-space-8x);
+    }
+
+    .mx_ChangeRecoveryKey_footer {
+        display: flex;
+        flex-direction: column;
+        gap: var(--cpd-space-4x);
+        justify-content: center;
+    }
+}
diff --git a/res/css/views/settings/encryption/_EncryptionCard.pcss b/res/css/views/settings/encryption/_EncryptionCard.pcss
new file mode 100644
index 00000000000..f125aea1764
--- /dev/null
+++ b/res/css/views/settings/encryption/_EncryptionCard.pcss
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2024 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+.mx_EncryptionCard {
+    display: flex;
+    flex-direction: column;
+    gap: var(--cpd-space-8x);
+    padding: var(--cpd-space-10x);
+    border-radius: var(--cpd-space-4x);
+    /* From figma */
+    box-shadow: 0 1.2px 2.4px 0 rgba(27, 29, 34, 0.15);
+    border: 1px solid var(--cpd-color-gray-400);
+
+    .mx_EncryptionCard_header {
+        display: flex;
+        flex-direction: column;
+        gap: var(--cpd-space-4x);
+        align-items: center;
+
+        > h2 {
+            margin: 0;
+        }
+
+        > span {
+            color: var(--cpd-color-text-secondary);
+            text-align: center;
+        }
+    }
+}
diff --git a/res/css/views/settings/tabs/_SettingsBanner.pcss b/res/css/views/settings/tabs/_SettingsBanner.pcss
index d1adf2889fc..70a19da146e 100644
--- a/res/css/views/settings/tabs/_SettingsBanner.pcss
+++ b/res/css/views/settings/tabs/_SettingsBanner.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/settings/tabs/_SettingsIndent.pcss b/res/css/views/settings/tabs/_SettingsIndent.pcss
index 65dd95bee8e..96e8245a863 100644
--- a/res/css/views/settings/tabs/_SettingsIndent.pcss
+++ b/res/css/views/settings/tabs/_SettingsIndent.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/settings/tabs/_SettingsSection.pcss b/res/css/views/settings/tabs/_SettingsSection.pcss
index a00350c082c..997343190dc 100644
--- a/res/css/views/settings/tabs/_SettingsSection.pcss
+++ b/res/css/views/settings/tabs/_SettingsSection.pcss
@@ -1,7 +1,7 @@
 /*
 Copyright 2023, 2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -15,6 +15,20 @@ Please see LICENSE files in the repository root for full details.
     a {
         color: $links;
     }
+
+    &.mx_SettingsSection_newUi {
+        display: flex;
+        flex-direction: column;
+        gap: var(--cpd-space-6x);
+        align-items: start;
+    }
+
+    .mx_SettingsSection_header {
+        display: flex;
+        flex-direction: column;
+        gap: var(--cpd-space-3x);
+        color: var(--cpd-color-text-secondary);
+    }
 }
 
 .mx_SettingsSection_subSections {
diff --git a/res/css/views/settings/tabs/_SettingsTab.pcss b/res/css/views/settings/tabs/_SettingsTab.pcss
index 43a5a8fd104..e0abf08e83b 100644
--- a/res/css/views/settings/tabs/_SettingsTab.pcss
+++ b/res/css/views/settings/tabs/_SettingsTab.pcss
@@ -1,7 +1,7 @@
 /*
 Copyright 2019-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -14,7 +14,7 @@ Please see LICENSE files in the repository root for full details.
         color: $links;
     }
 
-    form {
+    form:not(.mx_EncryptionUserSettingsTab form) {
         display: flex;
         flex-direction: column;
         gap: $spacing-8;
diff --git a/res/css/views/settings/tabs/room/_NotificationSettingsTab.pcss b/res/css/views/settings/tabs/room/_NotificationSettingsTab.pcss
index a36cc92fbab..38609c7fd49 100644
--- a/res/css/views/settings/tabs/room/_NotificationSettingsTab.pcss
+++ b/res/css/views/settings/tabs/room/_NotificationSettingsTab.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/settings/tabs/room/_PeopleRoomSettingsTab.pcss b/res/css/views/settings/tabs/room/_PeopleRoomSettingsTab.pcss
index 5a2700e71aa..5d649fe2d4d 100644
--- a/res/css/views/settings/tabs/room/_PeopleRoomSettingsTab.pcss
+++ b/res/css/views/settings/tabs/room/_PeopleRoomSettingsTab.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 Nordeck IT + Consulting GmbH
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/settings/tabs/room/_RolesRoomSettingsTab.pcss b/res/css/views/settings/tabs/room/_RolesRoomSettingsTab.pcss
index 018beed3519..390efb48cd8 100644
--- a/res/css/views/settings/tabs/room/_RolesRoomSettingsTab.pcss
+++ b/res/css/views/settings/tabs/room/_RolesRoomSettingsTab.pcss
@@ -1,7 +1,7 @@
 /*
 Copyright 2019-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/settings/tabs/room/_SecurityRoomSettingsTab.pcss b/res/css/views/settings/tabs/room/_SecurityRoomSettingsTab.pcss
index dfd3817be1f..5ae0d5854cb 100644
--- a/res/css/views/settings/tabs/room/_SecurityRoomSettingsTab.pcss
+++ b/res/css/views/settings/tabs/room/_SecurityRoomSettingsTab.pcss
@@ -1,7 +1,7 @@
 /*
 Copyright 2019-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/settings/tabs/user/_AppearanceUserSettingsTab.pcss b/res/css/views/settings/tabs/user/_AppearanceUserSettingsTab.pcss
index 614bfa00986..dd899389ef0 100644
--- a/res/css/views/settings/tabs/user/_AppearanceUserSettingsTab.pcss
+++ b/res/css/views/settings/tabs/user/_AppearanceUserSettingsTab.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020, 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/settings/tabs/user/_HelpUserSettingsTab.pcss b/res/css/views/settings/tabs/user/_HelpUserSettingsTab.pcss
index e3b4c1cf61b..972d0d7ede8 100644
--- a/res/css/views/settings/tabs/user/_HelpUserSettingsTab.pcss
+++ b/res/css/views/settings/tabs/user/_HelpUserSettingsTab.pcss
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2022 Šimon Brandner <simon.bra.ag@gmail.com>
 Copyright 2019 New Vector Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/settings/tabs/user/_KeyboardUserSettingsTab.pcss b/res/css/views/settings/tabs/user/_KeyboardUserSettingsTab.pcss
index b9eda93b2e0..b3251f3e3c1 100644
--- a/res/css/views/settings/tabs/user/_KeyboardUserSettingsTab.pcss
+++ b/res/css/views/settings/tabs/user/_KeyboardUserSettingsTab.pcss
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/settings/tabs/user/_MjolnirUserSettingsTab.pcss b/res/css/views/settings/tabs/user/_MjolnirUserSettingsTab.pcss
index 83e2b45c7ff..3caec3d08f3 100644
--- a/res/css/views/settings/tabs/user/_MjolnirUserSettingsTab.pcss
+++ b/res/css/views/settings/tabs/user/_MjolnirUserSettingsTab.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/settings/tabs/user/_PreferencesUserSettingsTab.pcss b/res/css/views/settings/tabs/user/_PreferencesUserSettingsTab.pcss
index 3dadcb56255..f5b580a14ea 100644
--- a/res/css/views/settings/tabs/user/_PreferencesUserSettingsTab.pcss
+++ b/res/css/views/settings/tabs/user/_PreferencesUserSettingsTab.pcss
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 Copyright 2019 New Vector Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/settings/tabs/user/_SecurityUserSettingsTab.pcss b/res/css/views/settings/tabs/user/_SecurityUserSettingsTab.pcss
index 55052144cf0..cb5d1fbc94b 100644
--- a/res/css/views/settings/tabs/user/_SecurityUserSettingsTab.pcss
+++ b/res/css/views/settings/tabs/user/_SecurityUserSettingsTab.pcss
@@ -1,7 +1,7 @@
 /*
 Copyright 2019-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/settings/tabs/user/_SidebarUserSettingsTab.pcss b/res/css/views/settings/tabs/user/_SidebarUserSettingsTab.pcss
index 445af105226..cb360cc898f 100644
--- a/res/css/views/settings/tabs/user/_SidebarUserSettingsTab.pcss
+++ b/res/css/views/settings/tabs/user/_SidebarUserSettingsTab.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/spaces/_SpaceBasicSettings.pcss b/res/css/views/spaces/_SpaceBasicSettings.pcss
index 786b041e501..76c58e1f5c2 100644
--- a/res/css/views/spaces/_SpaceBasicSettings.pcss
+++ b/res/css/views/spaces/_SpaceBasicSettings.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/spaces/_SpaceChildrenPicker.pcss b/res/css/views/spaces/_SpaceChildrenPicker.pcss
index 2deeadf5f26..abc51e5dddc 100644
--- a/res/css/views/spaces/_SpaceChildrenPicker.pcss
+++ b/res/css/views/spaces/_SpaceChildrenPicker.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/spaces/_SpaceCreateMenu.pcss b/res/css/views/spaces/_SpaceCreateMenu.pcss
index 7ab0fdd234f..ca2a2c8fc1e 100644
--- a/res/css/views/spaces/_SpaceCreateMenu.pcss
+++ b/res/css/views/spaces/_SpaceCreateMenu.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/spaces/_SpacePublicShare.pcss b/res/css/views/spaces/_SpacePublicShare.pcss
index ddda97b4931..b55c0e685ca 100644
--- a/res/css/views/spaces/_SpacePublicShare.pcss
+++ b/res/css/views/spaces/_SpacePublicShare.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/terms/_InlineTermsAgreement.pcss b/res/css/views/terms/_InlineTermsAgreement.pcss
index bd738ca7c5f..d2895010912 100644
--- a/res/css/views/terms/_InlineTermsAgreement.pcss
+++ b/res/css/views/terms/_InlineTermsAgreement.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/toasts/_AnalyticsToast.pcss b/res/css/views/toasts/_AnalyticsToast.pcss
index 2ffaf257a1c..4b6225f06e4 100644
--- a/res/css/views/toasts/_AnalyticsToast.pcss
+++ b/res/css/views/toasts/_AnalyticsToast.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/toasts/_IncomingCallToast.pcss b/res/css/views/toasts/_IncomingCallToast.pcss
index 3f11cf12f48..2aafff6b04e 100644
--- a/res/css/views/toasts/_IncomingCallToast.pcss
+++ b/res/css/views/toasts/_IncomingCallToast.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/toasts/_IncomingLegacyCallToast.pcss b/res/css/views/toasts/_IncomingLegacyCallToast.pcss
index 8fe94e9ba36..257cfbe370e 100644
--- a/res/css/views/toasts/_IncomingLegacyCallToast.pcss
+++ b/res/css/views/toasts/_IncomingLegacyCallToast.pcss
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/toasts/_NonUrgentEchoFailureToast.pcss b/res/css/views/toasts/_NonUrgentEchoFailureToast.pcss
index e1fc0b80c4d..a4044302049 100644
--- a/res/css/views/toasts/_NonUrgentEchoFailureToast.pcss
+++ b/res/css/views/toasts/_NonUrgentEchoFailureToast.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/typography/_Heading.pcss b/res/css/views/typography/_Heading.pcss
index 6082c60614f..a6204e869da 100644
--- a/res/css/views/typography/_Heading.pcss
+++ b/res/css/views/typography/_Heading.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021-2023 x The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/user-onboarding/_UserOnboardingButton.pcss b/res/css/views/user-onboarding/_UserOnboardingButton.pcss
deleted file mode 100644
index 01e27aa1430..00000000000
--- a/res/css/views/user-onboarding/_UserOnboardingButton.pcss
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2022 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
-Please see LICENSE files in the repository root for full details.
-*/
-
-.mx_UserOnboardingButton {
-    display: flex;
-    flex-direction: column;
-    align-content: stretch;
-    align-items: stretch;
-    border-radius: 8px;
-    margin: $spacing-8 $spacing-8 0;
-    padding: $spacing-12;
-
-    &.mx_UserOnboardingButton_selected,
-    &:hover,
-    &:focus-within {
-        background-color: $panel-actions;
-    }
-
-    .mx_UserOnboardingButton_content {
-        display: flex;
-        flex-direction: row;
-        gap: 5px;
-        align-items: center;
-
-        .mx_Heading_h4 {
-            margin-right: auto;
-            font: var(--cpd-font-body-md-regular);
-            color: $primary-content;
-        }
-
-        .mx_UserOnboardingButton_percentage {
-            font-size: $font-12px;
-            color: $secondary-content;
-        }
-
-        .mx_UserOnboardingButton_close {
-            position: relative;
-            box-sizing: border-box;
-            width: 14px;
-            height: 14px;
-            border-radius: 7px;
-            border: 1px solid $secondary-content;
-            flex-shrink: 0;
-
-            &::before {
-                background-color: $secondary-content;
-                content: "";
-                mask-repeat: no-repeat;
-                mask-position: center;
-                mask-size: 12px;
-                width: inherit;
-                height: inherit;
-                position: absolute;
-                left: -1px;
-                top: -1px;
-                mask-image: url("@vector-im/compound-design-tokens/icons/close.svg");
-            }
-        }
-    }
-
-    .mx_ProgressBar {
-        width: auto;
-        margin-top: $spacing-8;
-        background: $background;
-    }
-
-    &.mx_UserOnboardingButton_completed .mx_ProgressBar {
-        display: none;
-    }
-}
diff --git a/res/css/views/user-onboarding/_UserOnboardingHeader.pcss b/res/css/views/user-onboarding/_UserOnboardingHeader.pcss
deleted file mode 100644
index 5a659ec173c..00000000000
--- a/res/css/views/user-onboarding/_UserOnboardingHeader.pcss
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2022 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
-Please see LICENSE files in the repository root for full details.
-*/
-
-.mx_UserOnboardingHeader {
-    display: flex;
-    flex-direction: row;
-    padding: $spacing-32;
-    border-radius: 16px;
-    background: $system;
-    gap: $spacing-64;
-
-    animation-delay: 1500ms;
-    animation-duration: 300ms;
-    animation-timing-function: cubic-bezier(0, 0, 0.58, 1);
-    animation-name: mx_UserOnboardingHeader_slideIn;
-    animation-fill-mode: backwards;
-    will-change: opacity, transform;
-
-    @media (max-width: 1280px) {
-        margin: $spacing-32;
-    }
-
-    .mx_UserOnboardingHeader_dot {
-        color: $accent;
-    }
-
-    .mx_UserOnboardingHeader_content {
-        display: flex;
-        flex-direction: column;
-        flex-basis: 50%;
-        flex-shrink: 1;
-        flex-grow: 1;
-        min-width: 0;
-        gap: $spacing-24;
-        margin-right: auto;
-
-        p {
-            margin: 0;
-        }
-
-        .mx_AccessibleButton {
-            margin-top: auto;
-            align-self: flex-start;
-            padding: $spacing-12 $spacing-24;
-        }
-    }
-
-    .mx_UserOnboardingHeader_image {
-        flex-basis: 30%;
-        flex-shrink: 1;
-        flex-grow: 1;
-        align-self: center;
-        height: calc(100% + $spacing-64 + $spacing-64);
-        aspect-ratio: 4 / 3;
-        object-fit: contain;
-        min-width: 0;
-        min-height: 0;
-        margin-top: -$spacing-64;
-        margin-bottom: -$spacing-64;
-
-        animation-delay: 1500ms;
-        animation-duration: 300ms;
-        animation-timing-function: cubic-bezier(0, 0, 0.58, 1);
-        animation-name: mx_UserOnboardingHeader_slideInLong;
-        animation-fill-mode: backwards;
-        will-change: opacity, transform;
-    }
-}
-
-@keyframes mx_UserOnboardingHeader_slideIn {
-    0% {
-        transform: translate(0, 8px);
-        opacity: 0;
-    }
-    100% {
-        transform: translate(0, 0);
-        opacity: 1;
-    }
-}
-
-@keyframes mx_UserOnboardingHeader_slideInLong {
-    0% {
-        transform: translate(0, 32px);
-    }
-    100% {
-        transform: translate(0, 0);
-    }
-}
diff --git a/res/css/views/user-onboarding/_UserOnboardingList.pcss b/res/css/views/user-onboarding/_UserOnboardingList.pcss
deleted file mode 100644
index 689048793cd..00000000000
--- a/res/css/views/user-onboarding/_UserOnboardingList.pcss
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2022 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
-Please see LICENSE files in the repository root for full details.
-*/
-
-.mx_UserOnboardingList {
-    display: flex;
-    flex-direction: column;
-    margin: 0 $spacing-32;
-
-    animation-duration: 300ms;
-    animation-timing-function: cubic-bezier(0, 0, 0.58, 1);
-    animation-name: mx_UserOnboardingList_slideIn;
-    animation-fill-mode: backwards;
-    will-change: opacity;
-
-    .mx_UserOnboardingList_header {
-        display: flex;
-        flex-direction: row;
-        gap: 12px;
-        align-items: center;
-
-        .mx_UserOnboardingList_hint {
-            color: $secondary-content;
-        }
-    }
-
-    .mx_UserOnboardingList_progress {
-        display: flex;
-        flex-direction: column;
-        counter-reset: user-onboarding;
-
-        .mx_ProgressBar {
-            width: auto;
-            margin-top: $spacing-16;
-            height: 16px;
-
-            @mixin ProgressBarBorderRadius 16px;
-        }
-    }
-
-    .mx_UserOnboardingList_list {
-        display: grid;
-        grid-template-columns: max-content 1fr max-content;
-
-        appearance: none;
-        list-style: none;
-        margin: $spacing-32 0 0;
-        padding: 0;
-
-        grid-gap: $spacing-24;
-    }
-}
-
-@keyframes mx_UserOnboardingList_slideIn {
-    0% {
-        transform: translate(0, 8px);
-        opacity: 0;
-    }
-    100% {
-        transform: translate(0, 0);
-        opacity: 1;
-    }
-}
diff --git a/res/css/views/user-onboarding/_UserOnboardingPage.pcss b/res/css/views/user-onboarding/_UserOnboardingPage.pcss
deleted file mode 100644
index 638bc4b3578..00000000000
--- a/res/css/views/user-onboarding/_UserOnboardingPage.pcss
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2022 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
-Please see LICENSE files in the repository root for full details.
-*/
-
-.mx_UserOnboardingPage {
-    width: 100%;
-    height: 100%;
-
-    align-self: stretch;
-    max-width: 1200px;
-    margin: 0 auto auto;
-
-    display: flex;
-    flex-direction: column;
-    box-sizing: border-box;
-
-    gap: $spacing-64;
-    padding: $spacing-64 100px;
-
-    @media (max-width: 1280px) {
-        padding: $spacing-48 $spacing-32;
-    }
-}
diff --git a/res/css/views/user-onboarding/_UserOnboardingTask.pcss b/res/css/views/user-onboarding/_UserOnboardingTask.pcss
deleted file mode 100644
index 4056d45d02e..00000000000
--- a/res/css/views/user-onboarding/_UserOnboardingTask.pcss
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2022 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
-Please see LICENSE files in the repository root for full details.
-*/
-
-.mx_UserOnboardingTask {
-    display: contents;
-
-    .mx_UserOnboardingTask_number {
-        counter-increment: user-onboarding;
-        grid-column: 1;
-        color: $secondary-content;
-        width: 32px;
-        height: 32px;
-        text-align: center;
-        border: 2px solid $quinary-content;
-        border-radius: 32px;
-        line-height: 32px;
-        align-self: center;
-        position: relative;
-
-        &::before {
-            content: counter(user-onboarding);
-        }
-    }
-
-    .mx_UserOnboardingTask_content {
-        grid-column: 2;
-        display: flex;
-        flex-direction: column;
-        flex-grow: 1;
-        flex-shrink: 1;
-
-        transition: all 500ms;
-
-        .mx_UserOnboardingTask_title {
-            font: var(--cpd-font-body-md-medium);
-        }
-
-        .mx_UserOnboardingTask_description {
-            font-size: $font-12px;
-        }
-    }
-
-    .mx_UserOnboardingTask_action.mx_AccessibleButton {
-        grid-column: 3;
-        min-width: 180px;
-
-        @media (max-width: 800px) {
-            grid-column: 2;
-            margin-top: -16px;
-        }
-    }
-
-    &.mx_UserOnboardingTask_completed {
-        .mx_UserOnboardingTask_number {
-            &::before {
-                content: "";
-                position: absolute;
-                inset: -2px;
-                background: var(--cpd-color-icon-accent-tertiary);
-                border-radius: 32px;
-
-                animation-duration: 300ms;
-                animation-fill-mode: both;
-                animation-name: mx_UserOnboardingTask_spring;
-                will-change: opacity, transform;
-            }
-
-            &::after {
-                background-color: var(--cpd-color-icon-on-solid-primary);
-                content: "";
-                mask-repeat: no-repeat;
-                mask-position: center;
-                mask-size: 24px;
-                width: inherit;
-                height: inherit;
-                position: absolute;
-                left: 0;
-                top: 0;
-                mask-image: url("@vector-im/compound-design-tokens/icons/check.svg");
-
-                animation-duration: 300ms;
-                animation-fill-mode: both;
-                animation-name: mx_UserOnboardingTask_spring;
-                will-change: opacity, transform;
-            }
-        }
-
-        .mx_UserOnboardingTask_content {
-            opacity: 0.6;
-        }
-    }
-}
-
-@keyframes mx_UserOnboardingTask_spring {
-    0% {
-        opacity: 0;
-        transform: scale(0.6);
-    }
-    50% {
-        opacity: 1;
-        transform: scale(1.2);
-    }
-    100% {
-        opacity: 1;
-        transform: scale(1);
-    }
-}
diff --git a/res/css/views/verification/_VerificationShowSas.pcss b/res/css/views/verification/_VerificationShowSas.pcss
index 74cb4d439b5..5e007ed2343 100644
--- a/res/css/views/verification/_VerificationShowSas.pcss
+++ b/res/css/views/verification/_VerificationShowSas.pcss
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 Copyright 2019 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/voip/LegacyCallView/_LegacyCallViewButtons.pcss b/res/css/views/voip/LegacyCallView/_LegacyCallViewButtons.pcss
index a96fe20ec26..9849e9c560d 100644
--- a/res/css/views/voip/LegacyCallView/_LegacyCallViewButtons.pcss
+++ b/res/css/views/voip/LegacyCallView/_LegacyCallViewButtons.pcss
@@ -4,7 +4,7 @@ Copyright 2021, 2022 Šimon Brandner <simon.bra.ag@gmail.com>
 Copyright 2020, 2021 The Matrix.org Foundation C.I.C.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/voip/_CallDuration.pcss b/res/css/views/voip/_CallDuration.pcss
index e38f90a0c2b..f991f897fd8 100644
--- a/res/css/views/voip/_CallDuration.pcss
+++ b/res/css/views/voip/_CallDuration.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/voip/_CallView.pcss b/res/css/views/voip/_CallView.pcss
index 6a6f9757106..1acccda595b 100644
--- a/res/css/views/voip/_CallView.pcss
+++ b/res/css/views/voip/_CallView.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/voip/_DialPad.pcss b/res/css/views/voip/_DialPad.pcss
index 18867c3862e..e39620fd64a 100644
--- a/res/css/views/voip/_DialPad.pcss
+++ b/res/css/views/voip/_DialPad.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/voip/_DialPadContextMenu.pcss b/res/css/views/voip/_DialPadContextMenu.pcss
index feee0a5fb77..76311836bb6 100644
--- a/res/css/views/voip/_DialPadContextMenu.pcss
+++ b/res/css/views/voip/_DialPadContextMenu.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/voip/_DialPadModal.pcss b/res/css/views/voip/_DialPadModal.pcss
index 46b68fed756..7b979f18f96 100644
--- a/res/css/views/voip/_DialPadModal.pcss
+++ b/res/css/views/voip/_DialPadModal.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/voip/_LegacyCallPreview.pcss b/res/css/views/voip/_LegacyCallPreview.pcss
index 526fb59823e..3a8bf5af9f6 100644
--- a/res/css/views/voip/_LegacyCallPreview.pcss
+++ b/res/css/views/voip/_LegacyCallPreview.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/voip/_LegacyCallView.pcss b/res/css/views/voip/_LegacyCallView.pcss
index 45873face1e..007e8b50005 100644
--- a/res/css/views/voip/_LegacyCallView.pcss
+++ b/res/css/views/voip/_LegacyCallView.pcss
@@ -4,7 +4,7 @@ Copyright 2021, 2022 Šimon Brandner <simon.bra.ag@gmail.com>
 Copyright 2020, 2021 The Matrix.org Foundation C.I.C.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/voip/_LegacyCallViewForRoom.pcss b/res/css/views/voip/_LegacyCallViewForRoom.pcss
index 53b08648f80..18cba049511 100644
--- a/res/css/views/voip/_LegacyCallViewForRoom.pcss
+++ b/res/css/views/voip/_LegacyCallViewForRoom.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/voip/_LegacyCallViewHeader.pcss b/res/css/views/voip/_LegacyCallViewHeader.pcss
index 361c505acfb..c69add3ba0d 100644
--- a/res/css/views/voip/_LegacyCallViewHeader.pcss
+++ b/res/css/views/voip/_LegacyCallViewHeader.pcss
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2021, 2022 Šimon Brandner <simon.bra.ag@gmail.com>
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/voip/_LegacyCallViewSidebar.pcss b/res/css/views/voip/_LegacyCallViewSidebar.pcss
index fa8c552eff3..efc06cb9d22 100644
--- a/res/css/views/voip/_LegacyCallViewSidebar.pcss
+++ b/res/css/views/voip/_LegacyCallViewSidebar.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021, 2022 Šimon Brandner <simon.bra.ag@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/css/views/voip/_VideoFeed.pcss b/res/css/views/voip/_VideoFeed.pcss
index c0f13c3e780..6abe3901268 100644
--- a/res/css/views/voip/_VideoFeed.pcss
+++ b/res/css/views/voip/_VideoFeed.pcss
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2021, 2022 Šimon Brandner <simon.bra.ag@gmail.com>
 Copyright 2015, 2016 , 2020, 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/res/img/badges/f-droid.svg b/res/img/badges/f-droid.svg
deleted file mode 100644
index d97143c42be..00000000000
--- a/res/img/badges/f-droid.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg viewBox="0 0 564 168" xmlns="http://www.w3.org/2000/svg"><defs><radialGradient id="a" cx="113" cy="-12.89" r="59.662" gradientTransform="matrix(0 1.9611 -1.9778 0 5.51 -198.6)" gradientUnits="userSpaceOnUse"><stop stop-color="#fff" stop-opacity=".098" offset="0"/><stop stop-color="#fff" stop-opacity="0" offset="1"/></radialGradient></defs><path d="M22 2h520c11.08 0 20 8.92 20 20v124c0 11.08-8.92 20-20 20H22c-11.08 0-20-8.92-20-20V22C2 10.92 10.92 2 22 2z" stroke="#a6a6a6" stroke-width="4"/><path d="M199.26 45.46v-6.682h-5.499v-2.766h8.831v10.681q-1.949 1.383-4.299 2.1-2.349.7-5.015.7-5.832 0-9.131-3.4-3.283-3.415-3.283-9.497 0-6.099 3.283-9.498 3.3-3.416 9.131-3.416 2.433 0 4.616.6 2.2.6 4.049 1.766v3.583q-1.867-1.583-3.966-2.383-2.1-.8-4.416-.8-4.565 0-6.865 2.55-2.283 2.549-2.283 7.598 0 5.032 2.283 7.581 2.3 2.55 6.865 2.55 1.783 0 3.183-.3 1.4-.317 2.516-.967zm9.48-21.33h15.729v2.833h-12.364v7.365h11.847v2.832h-11.847v9.015h12.664v2.832H208.74zm18.12 0h21.045v2.833h-8.831v22.045h-3.383V26.963h-8.83zm35.14 0h3.366v24.877H262zm6.61 0h21.045v2.833h-8.831v22.045h-3.383V26.963h-8.83zm45.24 2.28q-3.666 0-5.832 2.733-2.15 2.732-2.15 7.448 0 4.699 2.15 7.431 2.166 2.733 5.832 2.733t5.799-2.733q2.15-2.732 2.15-7.431 0-4.716-2.15-7.448-2.133-2.733-5.799-2.733zm0-2.733q5.232 0 8.365 3.516 3.132 3.5 3.132 9.398 0 5.882-3.132 9.397-3.133 3.5-8.365 3.5-5.249 0-8.398-3.5-3.132-3.499-3.132-9.397t3.132-9.398q3.15-3.516 8.398-3.516zm16.76.453h4.532l11.031 20.812V24.13h3.266v24.877h-4.532l-11.031-20.812v20.812h-3.266z" fill="#fff" aria-label="GET IT ON"/><path d="M180.81 136v-8.118l7.19-1.391V78.017l-7.19-1.392v-8.164h53.762v18.508h-10.391l-.603-8.071h-22.034v18.6h23.657v10.438h-23.657v18.555l7.236 1.391V136zm62.16-23.66v-10.437h26.162v10.437zM277.29 136v-8.118l7.283-1.53v-48.15l-7.283-1.577v-8.164h29.641q9.045 0 15.957 4.268 6.912 4.221 10.762 11.736 3.897 7.468 3.897 17.163v1.252q0 9.602-3.85 17.117-3.804 7.468-10.67 11.736-6.865 4.268-15.91 4.268zm20.828-10.344h8.303q5.613 0 9.51-2.922 3.896-2.97 5.937-8.118 2.087-5.149 2.087-11.736v-1.299q0-6.68-2.087-11.782-2.041-5.149-5.938-8.025-3.896-2.922-9.509-2.922h-8.303zM344.79 136v-8.118l6.494-1.391V95.366l-7.19-1.392V85.81h19.807l.51 6.216.093 1.113q1.856-4.082 4.593-6.17 2.736-2.087 6.54-2.087 1.206 0 2.644.232 1.438.186 2.551.51l-1.438 12.478-6.726-.37q-2.876-.14-4.685.974-1.763 1.113-3.154 3.2v24.585l6.494 1.392V136zm63.08.98q-7.422 0-12.756-3.247t-8.164-9q-2.83-5.797-2.83-13.312v-.974q0-7.469 2.83-13.22 2.83-5.799 8.118-9.046 5.334-3.293 12.71-3.293 7.468 0 12.756 3.293 5.288 3.247 8.117 9t2.83 13.266v.974q0 7.515-2.83 13.313-2.83 5.752-8.117 9-5.289 3.247-12.664 3.247zm0-10.391q3.525 0 5.752-1.902t3.293-5.288q1.067-3.433 1.067-7.979v-.974q0-4.453-1.067-7.839-1.066-3.433-3.34-5.335-2.226-1.948-5.798-1.948-3.479 0-5.752 1.948-2.273 1.902-3.34 5.335-1.02 3.386-1.02 7.84v.973q0 4.546 1.02 7.979 1.067 3.433 3.34 5.334 2.273 1.856 5.845 1.856zM437.1 136v-8.118l6.54-1.391V95.366l-7.236-1.392V85.81h20.781v40.681l6.494 1.392V136zm6.077-60.813v-11.55h14.009v11.55zm44.293 61.793q-5.984 0-10.298-3.062-4.268-3.107-6.54-8.627-2.273-5.567-2.273-12.988v-.975q0-7.932 2.273-13.87 2.319-5.937 6.586-9.23 4.268-3.34 10.205-3.34 4.129 0 7.237 1.67 3.108 1.623 5.38 4.638V73.198l-7.236-1.391v-8.164h20.781v62.854l6.494 1.391v8.118h-18.23l-1.02-6.123q-2.366 3.479-5.66 5.288-3.246 1.81-7.7 1.81zm4.036-10.53q2.83 0 4.963-1.206 2.134-1.206 3.572-3.479v-21.292q-1.392-2.412-3.526-3.71-2.133-1.346-4.917-1.346-3.386 0-5.566 2.04-2.134 1.995-3.154 5.567-.974 3.572-.974 8.303v.975q0 6.587 2.226 10.39 2.227 3.758 7.376 3.758z" fill="#fff" aria-label="F-Droid"/><path d="m146.34 25.898-11.184 14.474" fill="#8ab000" stroke="#769616" stroke-linecap="round" stroke-width="6.579"/><path d="M146.29 22.477c1.192.032 2.003.497 2.579 1.182-5.332 6.34-6.232 7.344-13.513 16.37-2.684 3.472-5.479 1.677-2.795-1.794l11.184-14.474a3.26 3.26 0 0 1 2.545-1.284z" color="#000" fill="#fff" fill-opacity=".298"/><path d="M148.89 23.793a3.29 3.29 0 0 1 .058 4.095l-11.184 14.474c-2.684 3.474-3.026-1.61-3.026-1.61s9.829-11.87 14.153-16.959z" color="#000" fill="#263238" fill-opacity=".2"/><path d="M147 23.003c1.153 0 2.526.374 2.168 2.103-.27 1.318-12.263 15.984-12.263 15.984-2.684 3.47-6.563 1.779-3.879-1.693l11.142-14.4c.685-.763 1.603-1.957 2.832-1.994z" color="#000" fill="#8ab000"/><path d="m33.653 25.898 11.184 14.474" fill="#8ab000" stroke="#769616" stroke-linecap="round" stroke-width="6.579"/><path d="M33.711 22.477c-1.192.032-2.003.497-2.579 1.182 5.332 6.34 6.232 7.344 13.513 16.37 2.684 3.472 5.479 1.677 2.795-1.794L36.256 23.76a3.26 3.26 0 0 0-2.545-1.284z" color="#000" fill="#fff" fill-opacity=".298"/><path d="M31.108 23.793a3.29 3.29 0 0 0-.058 4.095l11.184 14.474c2.684 3.474 3.026-1.61 3.026-1.61s-9.829-11.87-14.153-16.959z" color="#000" fill="#263238" fill-opacity=".2"/><path d="M32.993 23.003c-1.153 0-2.526.374-2.168 2.103.27 1.318 12.263 15.984 12.263 15.984 2.684 3.47 6.563 1.779 3.879-1.693l-11.142-14.4c-.685-.763-1.603-1.957-2.832-1.994z" color="#000" fill="#8ab000"/><path d="M47.893 35.109h84.211a7.878 7.878 0 0 1 7.895 7.894v18.211a7.878 7.878 0 0 1-7.895 7.895H47.893a7.878 7.878 0 0 1-7.895-7.895v-18.21a7.878 7.878 0 0 1 7.895-7.895z" fill="#aeea00"/><path d="M47.893 42.74h84.211a7.878 7.878 0 0 1 7.895 7.895v10.526a7.878 7.878 0 0 1-7.895 7.895H47.893a7.878 7.878 0 0 1-7.895-7.895V50.635a7.878 7.878 0 0 1 7.895-7.895z" fill="#263238" fill-opacity=".2"/><path d="M47.893 35.109h84.211a7.878 7.878 0 0 1 7.895 7.894V53.53a7.878 7.878 0 0 1-7.895 7.895H47.893a7.878 7.878 0 0 1-7.895-7.895V43.003a7.878 7.878 0 0 1 7.895-7.894z" fill="#fff" fill-opacity=".298"/><path d="M47.893 38.003h84.211c4.374 0 7.895 2.883 7.895 6.462v15.079c0 3.58-3.521 6.462-7.895 6.462H47.893c-4.374 0-7.895-2.882-7.895-6.462V44.465c0-3.58 3.521-6.462 7.895-6.462z" fill="#aeea00"/><path d="M47.893 71.944h84.211a7.878 7.878 0 0 1 7.895 7.895v52.211a7.878 7.878 0 0 1-7.895 7.895H47.893a7.878 7.878 0 0 1-7.895-7.895V79.839a7.878 7.878 0 0 1 7.895-7.895z" fill="#1976d2"/><path d="M47.893 105.89h84.211a7.878 7.878 0 0 1 7.895 7.895v18.42a7.878 7.878 0 0 1-7.895 7.896H47.893a7.878 7.878 0 0 1-7.895-7.895v-18.421a7.878 7.878 0 0 1 7.895-7.895z" fill="#263238" fill-opacity=".2"/><path d="M47.893 71.681h84.211a7.878 7.878 0 0 1 7.895 7.895v18.421a7.878 7.878 0 0 1-7.895 7.895H47.893a7.878 7.878 0 0 1-7.895-7.895V79.576a7.878 7.878 0 0 1 7.895-7.895z" fill="#fff" fill-opacity=".2"/><path d="M47.893 75.102h84.211c4.374 0 7.895 3.19 7.895 7.154v47.693c0 3.963-3.521 7.153-7.895 7.153H47.893c-4.374 0-7.895-3.19-7.895-7.153V82.256c0-3.963 3.521-7.154 7.895-7.154z" fill="#1976d2"/><path d="M89.998 89.714c-7.579 0-14 5.224-15.876 12.237h8.455a8.46 8.46 0 0 1 7.421-4.342 8.495 8.495 0 0 1 8.553 8.553 8.495 8.495 0 0 1-8.553 8.552 8.471 8.471 0 0 1-7.71-4.868h-8.3c1.69 7.279 8.242 12.763 16.01 12.763 9.038 0 16.449-7.41 16.449-16.448 0-9.037-7.41-16.448-16.448-16.448z" color="#000" fill="#0d47a1"/><path d="M115.13 106.16a25.132 25.132 0 0 1-25.132 25.132 25.132 25.132 0 0 1-25.131-25.132 25.132 25.132 0 0 1 25.131-25.132 25.132 25.132 0 0 1 25.132 25.132z" fill="none" stroke="#0d47a1" stroke-linecap="round" stroke-width="5"/><path d="M73.55 52.477a8.882 10.197 0 0 1-8.88 10.198 8.882 10.197 0 0 1-8.882-10.198 8.882 10.197 0 0 1 8.881-10.197 8.882 10.197 0 0 1 8.882 10.197z" fill="#263238" fill-opacity=".2"/><path d="M73.55 53.793a8.882 8.882 0 0 1-8.88 8.882 8.882 8.882 0 0 1-8.882-8.882 8.882 8.882 0 0 1 8.881-8.882 8.882 8.882 0 0 1 8.882 8.882z" fill="#fff"/><path d="M124.87 52.477a8.882 10.197 0 0 1-8.882 10.198 8.882 10.197 0 0 1-8.881-10.198 8.882 10.197 0 0 1 8.881-10.197 8.882 10.197 0 0 1 8.882 10.197z" fill="#263238" fill-opacity=".2"/><path d="M124.87 53.793a8.882 8.882 0 0 1-8.882 8.882 8.882 8.882 0 0 1-8.881-8.882 8.882 8.882 0 0 1 8.881-8.882 8.882 8.882 0 0 1 8.882 8.882z" fill="#fff"/><path d="M33.71 22.47a3.29 3.29 0 0 0-2.662 5.336l9.474 12.262a7.894 7.894 0 0 0-.527 2.824v18.211a7.877 7.877 0 0 0 7.895 7.895h84.21a7.877 7.877 0 0 0 7.895-7.895v-18.21c0-1-.19-1.95-.525-2.827l9.472-12.26a3.29 3.29 0 0 0-2.433-5.334 3.29 3.29 0 0 0-2.772 1.31l-9.013 11.666a7.91 7.91 0 0 0-2.623-.45H47.89c-.922 0-1.8.163-2.621.45l-9.016-11.666a3.29 3.29 0 0 0-2.543-1.312zm14.18 49.527a7.877 7.877 0 0 0-7.894 7.894v52.211a7.877 7.877 0 0 0 7.894 7.895h84.211a7.877 7.877 0 0 0 7.894-7.895v-52.21a7.877 7.877 0 0 0-7.894-7.895z" color="#000" fill="url(#a)" fill-rule="evenodd"/></svg>
diff --git a/res/img/badges/google-play.svg b/res/img/badges/google-play.svg
deleted file mode 100644
index 973d9d3afc5..00000000000
--- a/res/img/badges/google-play.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg viewBox="0 0 180 53.332" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><defs><linearGradient id="a" x2="1" gradientTransform="scale(-31.64 31.64) rotate(45 -.903 -.925)" gradientUnits="userSpaceOnUse"><stop stop-color="#00a0ff" offset="0"/><stop stop-color="#00a1ff" offset=".007"/><stop stop-color="#00beff" offset=".26"/><stop stop-color="#00d2ff" offset=".512"/><stop stop-color="#00dfff" offset=".76"/><stop stop-color="#00e3ff" offset="1"/></linearGradient><linearGradient id="b" x2="1" gradientTransform="matrix(-32.255 0 0 32.255 45.098 26.675)" gradientUnits="userSpaceOnUse"><stop stop-color="#ffe000" offset="0"/><stop stop-color="#ffbd00" offset=".409"/><stop stop-color="orange" offset=".775"/><stop stop-color="#ff9c00" offset="1"/></linearGradient><linearGradient id="c" x2="1" gradientTransform="scale(-42.903 42.903) rotate(45 -1.222 -.585)" gradientUnits="userSpaceOnUse"><stop stop-color="#ff3a44" offset="0"/><stop stop-color="#c31162" offset="1"/></linearGradient><linearGradient id="d" x2="1" gradientTransform="scale(19.156 -19.156) rotate(-44.998 .238 -.62)" gradientUnits="userSpaceOnUse"><stop stop-color="#32a071" offset="0"/><stop stop-color="#2da771" offset=".069"/><stop stop-color="#15cf74" offset=".476"/><stop stop-color="#06e775" offset=".801"/><stop stop-color="#00f076" offset="1"/></linearGradient><linearGradient id="e" x2="1" gradientTransform="matrix(-32.255 0 0 32.255 45.098 26.675)" gradientUnits="userSpaceOnUse"><stop stop-color="#ccb300" offset="0"/><stop stop-color="#cc9700" offset=".409"/><stop stop-color="#cc8400" offset=".775"/><stop stop-color="#cc7d00" offset="1"/></linearGradient><linearGradient id="f" x2="1" gradientTransform="scale(-42.903 42.903) rotate(45 -1.222 -.585)" gradientUnits="userSpaceOnUse"><stop stop-color="#cc2e36" offset="0"/><stop stop-color="#9c0e4e" offset="1"/></linearGradient><linearGradient id="g" x2="1" gradientTransform="scale(-31.64 31.64) rotate(45 -.903 -.925)" gradientUnits="userSpaceOnUse"><stop stop-color="#008de0" offset="0"/><stop stop-color="#008de0" offset=".007"/><stop stop-color="#00a7e0" offset=".26"/><stop stop-color="#00b8e0" offset=".512"/><stop stop-color="#00c4e0" offset=".76"/><stop stop-color="#00c7e0" offset="1"/></linearGradient><linearGradient id="h" x2="1" gradientTransform="scale(-42.903 42.903) rotate(45 -1.222 -.585)" gradientUnits="userSpaceOnUse"><stop stop-color="#e0333c" offset="0"/><stop stop-color="#ab0f56" offset="1"/></linearGradient><linearGradient id="i" x2="1" gradientTransform="matrix(-32.255 0 0 32.255 45.098 26.675)" gradientUnits="userSpaceOnUse"><stop stop-color="#e0c500" offset="0"/><stop stop-color="#e0a600" offset=".409"/><stop stop-color="#e09100" offset=".775"/><stop stop-color="#e08900" offset="1"/></linearGradient><linearGradient id="j" x2="1" gradientTransform="matrix(-32.255 0 0 32.255 45.098 26.675)" gradientUnits="userSpaceOnUse"><stop stop-color="#ffe840" offset="0"/><stop stop-color="#ffce40" offset=".409"/><stop stop-color="#ffbc40" offset=".775"/><stop stop-color="#ffb540" offset="1"/></linearGradient><linearGradient id="k" x2="1" gradientTransform="scale(-31.64 31.64) rotate(45 -.903 -.925)" gradientUnits="userSpaceOnUse"><stop stop-color="#40b8ff" offset="0"/><stop stop-color="#40b9ff" offset=".007"/><stop stop-color="#40ceff" offset=".26"/><stop stop-color="#40ddff" offset=".512"/><stop stop-color="#40e7ff" offset=".76"/><stop stop-color="#40eaff" offset="1"/></linearGradient><linearGradient id="l" x2="1" gradientTransform="scale(19.156 -19.156) rotate(-44.998 .238 -.62)" gradientUnits="userSpaceOnUse"><stop stop-color="#65b895" offset="0"/><stop stop-color="#62bd95" offset=".069"/><stop stop-color="#50db97" offset=".476"/><stop stop-color="#44ed98" offset=".801"/><stop stop-color="#40f498" offset="1"/></linearGradient></defs><path d="M173.33 53.332H6.67c-3.667 0-6.667-3-6.667-6.667V6.668c0-3.667 3-6.667 6.667-6.667h166.66c3.667 0 6.667 3 6.667 6.667v39.997c0 3.666-3 6.666-6.667 6.666"/><path d="M101.93 17.465v-5.118l-.044-1.544-.202.074 4.107 6.588h1.28V9.199h-1.295v4.816l.044 1.544.202-.074-3.927-6.286h-1.458v8.266" fill="#fff"/><path d="M173.33 0H6.67C3.003 0 .003 3 .003 6.666v40c0 3.666 3 6.666 6.667 6.666h166.66c3.667 0 6.667-3 6.667-6.667V6.668c0-3.667-3-6.667-6.667-6.667m0 1.067c3.088 0 5.6 2.512 5.6 5.6v39.997c0 3.087-2.512 5.6-5.6 5.6H6.67a5.607 5.607 0 0 1-5.6-5.6v-40c0-3.087 2.512-5.6 5.6-5.6h166.66" fill="#a6a6a6"/><path d="M63.356 13.657c0-.203-.02-.41-.058-.628l-.02-.11h-4.121v1.229h3.038v-.134l-.133-.011c-.058.67-.272 1.176-.632 1.537-.573.571-1.276.853-2.14.854-.81 0-1.499-.28-2.092-.85-.587-.568-.88-1.294-.881-2.212.001-.917.294-1.643.881-2.21.593-.571 1.281-.85 2.092-.851.902.002 1.582.3 2.088.901l.094.112.806-.807.086-.087-.079-.093c-.327-.39-.764-.7-1.3-.93a4.259 4.259 0 0 0-1.695-.347c-1.185-.001-2.208.416-3.038 1.24-.833.823-1.252 1.857-1.251 3.072-.001 1.215.418 2.25 1.252 3.073.829.824 1.852 1.24 3.037 1.24 1.234 0 2.258-.41 3.036-1.226l-.003.002c.691-.69 1.034-1.622 1.033-2.764M69.502 9.2h-4.937v8.265h4.937v-1.25h-3.643v-2.27h3.286v-1.227h-3.286v-2.27h3.643m4.335 0h2.234v-1.25h-5.764v1.25h2.235v7.017h1.295m7.239 0V9.199h-1.294v8.266m5.853-7.017h2.235v-1.25h-5.764v1.25h2.234v7.017h1.295m6.652-4.132c0-.903.284-1.627.85-2.203.57-.575 1.252-.858 2.078-.86.825.002 1.509.285 2.078.86.566.576.85 1.3.85 2.203s-.284 1.627-.85 2.202c-.57.576-1.253.858-2.078.86-.826-.002-1.508-.284-2.076-.86s-.852-1.3-.852-2.202zm5.957 3.058c.808-.83 1.217-1.86 1.216-3.058 0-1.193-.41-2.22-1.221-3.054-.813-.837-1.83-1.26-3.024-1.259-1.2-.001-2.221.42-3.028 1.254-.81.83-1.217 1.86-1.216 3.059-.001 1.199.406 2.228 1.214 3.06s1.83 1.253 3.03 1.251c1.2.002 2.22-.419 3.029-1.253m-7.387 12.612c-3.136 0-5.693 2.384-5.693 5.67 0 3.266 2.557 5.67 5.693 5.67s5.691-2.405 5.691-5.67c0-3.287-2.555-5.67-5.691-5.67zm0 2.232c1.719 0 3.2 1.397 3.2 3.438 0 2.019-1.481 3.435-3.2 3.435-1.718 0-3.201-1.416-3.201-3.435 0-2.041 1.483-3.438 3.201-3.438zm-12.422-2.232c-3.136 0-5.693 2.384-5.693 5.67 0 3.266 2.557 5.67 5.693 5.67s5.693-2.405 5.693-5.67c0-3.287-2.557-5.67-5.693-5.67zm0 2.232c1.718 0 3.201 1.397 3.201 3.438 0 2.019-1.483 3.435-3.201 3.435-1.719 0-3.2-1.416-3.2-3.435 0-2.041 1.481-3.438 3.2-3.438zm-14.772-.494v2.407h5.757c-.172 1.353-.623 2.34-1.31 3.028-.838.838-2.148 1.762-4.447 1.762-3.544 0-6.315-2.857-6.315-6.401s2.771-6.402 6.315-6.402c1.912 0 3.308.752 4.34 1.719l1.696-1.697c-1.439-1.375-3.35-2.427-6.036-2.427-4.854 0-8.935 3.952-8.935 8.807s4.08 8.806 8.935 8.806c2.621 0 4.597-.859 6.143-2.47 1.59-1.59 2.084-3.823 2.084-5.627 0-.56-.043-1.074-.129-1.504zm55.554-1.74c-2.921 0-5.348 2.3-5.348 5.672 0 3.179 2.405 5.67 5.627 5.67 2.6 0 4.105-1.59 4.727-2.514l-1.934-1.287c-.644.946-1.525 1.566-2.793 1.566-1.267 0-2.17-.578-2.75-1.716l7.582-3.137-.256-.645c-.472-1.268-1.912-3.609-4.855-3.609zm.086 2.191c.989 0 1.826.495 2.105 1.203l-5.068 2.106c-.065-2.191 1.696-3.309 2.963-3.309zm-9.126 8.807h2.493V23.332h-2.492zm-7.15-10.996c-2.835 0-5.434 2.49-5.434 5.691 0 3.18 2.599 5.65 5.434 5.65 1.353 0 2.428-.602 2.986-1.29h.086v.816c0 2.17-1.16 3.33-3.03 3.33-1.524 0-2.47-1.095-2.856-2.02l-2.17.903c.624 1.504 2.278 3.352 5.027 3.352 2.921 0 5.39-1.72 5.39-5.908v-10.18h-2.36v.921h-.087c-.558-.666-1.633-1.265-2.986-1.265zm.215 2.232c1.697 0 3.03 1.461 3.03 3.46 0 1.975-1.333 3.414-3.03 3.414-1.72 0-3.158-1.439-3.158-3.415 0-1.997 1.44-3.459 3.158-3.459zm26.545-7.904v16.668h2.486v-6.315h3.475c2.758 0 5.469-1.997 5.469-5.177s-2.711-5.176-5.47-5.176zm2.486 2.32h3.54c1.86 0 2.915 1.54 2.915 2.858 0 1.29-1.056 2.855-2.916 2.855h-3.539zm18.914 3.321c-1.8 0-3.667.792-4.44 2.55l2.21.923c.472-.922 1.349-1.223 2.273-1.223 1.286 0 2.594.773 2.615 2.144v.172c-.45-.257-1.414-.642-2.594-.642-2.38 0-4.804 1.308-4.804 3.752 0 2.23 1.951 3.668 4.138 3.668 1.673 0 2.596-.751 3.176-1.631h.084v1.287h2.402v-6.39c0-2.96-2.208-4.61-5.06-4.61zm.385 5.938c1.095 0 1.608.236 2.273.558-.193 1.544-1.52 2.639-2.957 2.639l-.002-.002c-.815 0-1.951-.405-1.951-1.414 0-1.286 1.416-1.781 2.637-1.781zm13.415-5.575-2.852 7.227h-.085l-2.96-7.227h-2.68l4.438 10.1-2.53 5.619h2.596l6.84-15.719zm-22.4 10.664h2.488V23.331h-2.488z" fill="#fff"/><path d="m14.007 43.191-.099-.095c-.388-.41-.617-1.047-.617-1.873v.194V11.93v.203c0-.894.267-1.567.714-1.97l16.516 16.515-16.515 16.515m-.71-31.48v-.004.003m0-.01" fill="url(#a)"/><path d="m36.025 32.378.126-.071 6.522-3.706c.622-.354 1.036-.782 1.243-1.236-.206.454-.621.883-1.243 1.236l-6.522 3.706-.126.071m.002-.195-5.506-5.507 5.505-5.506 6.647 3.776c.844.48 1.318 1.098 1.397 1.73v.002c-.08.63-.553 1.248-1.397 1.728l-6.646 3.777" fill="url(#b)"/><path d="M15.184 43.819c-.461 0-.864-.15-1.178-.433.315.283.718.433 1.18.433a2.515 2.515 0 0 0-.002 0m0-.195c-.46 0-.863-.15-1.177-.433l16.515-16.516 5.506 5.507L16.68 43.176c-.536.304-1.043.447-1.494.447m-1.182-.241a1.814 1.814 0 0 1-.086-.084l.086.084" fill="url(#c)"/><path d="M30.52 26.676 14.004 10.16a1.716 1.716 0 0 1 1.177-.433c.452 0 .96.145 1.496.449L36.025 21.17l-5.506 5.506m5.63-5.63L16.677 9.98c-.536-.304-1.044-.448-1.496-.448h-.005.007c.451 0 .959.144 1.494.448L36.15 21.045" fill="url(#d)"/><path d="M15.313 43.811c.42-.024.883-.168 1.371-.445l19.353-10.995-19.353 10.994c-.487.277-.952.42-1.371.445m-1.301-.43-.004-.004a.038.038 0 0 1 .004.004m-.09-.088-.009-.008c.004.002.006.006.009.008"/><path d="m36.025 32.378.126-.071-.126.071" fill="url(#e)"/><path d="M15.185 43.819c-.461 0-.864-.15-1.178-.434a.038.038 0 0 0-.005-.003l-.086-.084-.008-.008.099-.1c.314.284.716.434 1.177.434.451 0 .958-.144 1.494-.448l19.348-10.994.124.124-.126.072L16.677 43.37c-.488.276-.952.42-1.37.444a2.515 2.515 0 0 1-.123.004" fill="url(#f)"/><path d="M13.914 43.285c-.388-.411-.617-1.049-.617-1.874 0 .825.23 1.462.617 1.873"/><path d="M13.908 43.29c-.388-.41-.617-1.047-.617-1.873v-.194c0 .825.23 1.462.617 1.873l.099.095-.099.099" fill="url(#g)"/><path d="m13.908 43.29.099-.1v.001l-.099.099" fill="url(#h)"/><path d="m36.151 32.307-.124-.124 6.646-3.777c.844-.48 1.318-1.098 1.397-1.728 0 .231-.051.463-.154.688-.207.453-.62.882-1.243 1.235l-6.522 3.706" fill="url(#i)"/><path d="M44.083 26.667c0-.698-.467-1.395-1.398-1.924l-6.523-3.707 6.523 3.706c.932.53 1.399 1.228 1.398 1.925" fill="#404040"/><path d="M44.07 26.675c-.08-.632-.553-1.25-1.397-1.73l-6.647-3.775.124-.124 6.523 3.706c.93.529 1.397 1.226 1.397 1.923" fill="url(#j)"/><path d="M13.297 11.917v-.002.002m.006-.217v-.003.003m0-.006v-.006.006m0-.008c.077-1.37.822-2.16 1.876-2.165a1.715 1.715 0 0 0-1.166.433l-.004.003c-.033.03-.064.061-.095.093-.35.37-.57.925-.61 1.636" fill="#404040"/><path d="M13.291 12.132v-.204c0-.073.002-.145.006-.215V11.7c.04-.71.261-1.265.61-1.635l.098.097c-.447.404-.714 1.077-.714 1.97m.712-2.16.003-.004-.003.003" fill="url(#k)"/><path d="M15.178 9.521h.004-.004" fill="#404040"/><path d="M36.025 21.17 16.677 10.176c-.536-.304-1.044-.448-1.496-.448-.46 0-.863.15-1.177.432l-.097-.097a1.78 1.78 0 0 1 .095-.094l.003-.003c.312-.28.71-.43 1.166-.433h.01c.452 0 .96.144 1.496.448l19.472 11.064-.125.125" fill="url(#l)"/></svg>
\ No newline at end of file
diff --git a/res/img/badges/ios.svg b/res/img/badges/ios.svg
deleted file mode 100644
index e723d1cc046..00000000000
--- a/res/img/badges/ios.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg viewBox="0 0 159.55 53.333" xmlns="http://www.w3.org/2000/svg"><path d="M146.84.001H12.71c-.489 0-.972 0-1.46.003-.407.002-.812.01-1.224.016-.888.023-1.786.077-2.672.236a8.876 8.876 0 0 0-2.535.836A8.58 8.58 0 0 0 1.09 4.825a8.782 8.782 0 0 0-.833 2.538c-.16.883-.216 1.776-.24 2.669-.012.409-.013.82-.02 1.228v30.818c.007.414.008.815.02 1.23.024.893.08 1.786.24 2.669.155.893.418 1.73.833 2.539a8.28 8.28 0 0 0 1.571 2.152 8.356 8.356 0 0 0 2.158 1.571 8.95 8.95 0 0 0 2.535.842c.886.158 1.784.21 2.672.235.412.01.817.015 1.225.015.488.002.97.002 1.46.002h134.13c.48 0 .966 0 1.445-.002.408 0 .824-.006 1.23-.015.894-.025 1.79-.077 2.667-.235a9.083 9.083 0 0 0 2.544-.842 8.417 8.417 0 0 0 2.157-1.57 8.556 8.556 0 0 0 1.573-2.153c.41-.809.676-1.646.826-2.54.165-.882.216-1.775.249-2.669.004-.414.004-.815.004-1.229.01-.484.01-.966.01-1.458V12.715c0-.488 0-.972-.01-1.455 0-.409 0-.82-.004-1.228-.033-.893-.084-1.786-.25-2.67a8.763 8.763 0 0 0-.825-2.537 8.626 8.626 0 0 0-1.573-2.162 8.641 8.641 0 0 0-2.157-1.57 9.02 9.02 0 0 0-2.544-.837c-.877-.159-1.773-.213-2.667-.236-.406-.006-.822-.014-1.23-.016C147.807 0 147.322 0 146.84 0" fill="#b2b1b1"/><path d="M11.267 52.166c-.407 0-.803-.005-1.206-.014-.745-.021-1.63-.062-2.492-.217a7.847 7.847 0 0 1-2.21-.731 7.214 7.214 0 0 1-1.862-1.355 7.092 7.092 0 0 1-1.36-1.862 7.616 7.616 0 0 1-.724-2.21c-.163-.897-.205-1.807-.222-2.5-.01-.28-.02-1.217-.02-1.217v-30.8s.012-.922.02-1.193c.017-.698.059-1.607.22-2.495.143-.818.38-1.54.725-2.216.354-.7.808-1.325 1.353-1.864a7.423 7.423 0 0 1 1.87-1.363 7.762 7.762 0 0 1 2.204-.726c.898-.16 1.808-.2 2.5-.219l1.204-.016h137.02l1.217.017c.684.017 1.595.057 2.48.217.802.14 1.53.38 2.227.73.684.35 1.31.808 1.855 1.354a7.38 7.38 0 0 1 1.365 1.873c.344.681.577 1.403.715 2.198.153.841.2 1.705.23 2.517.004.377.004.783.004 1.187.012.5.012.975.012 1.455V40.62c0 .485 0 .957-.012 1.434 0 .434 0 .831-.005 1.24-.028.785-.076 1.648-.228 2.47a7.664 7.664 0 0 1-.72 2.228 7.297 7.297 0 0 1-1.353 1.847 7.268 7.268 0 0 1-1.866 1.363 7.855 7.855 0 0 1-2.225.733c-.853.155-1.737.197-2.492.218-.39.009-.8.014-1.197.014l-1.445.003-135.58-.003" fill="#040403"/><path d="M33.032 27.068c-.034-3.668 3.002-5.452 3.141-5.536-1.72-2.507-4.385-2.85-5.321-2.877-2.239-.235-4.41 1.34-5.551 1.34-1.162 0-2.92-1.317-4.81-1.278-2.436.038-4.715 1.448-5.964 3.638-2.579 4.464-.656 11.026 1.814 14.633 1.236 1.769 2.68 3.742 4.57 3.672 1.85-.077 2.54-1.18 4.773-1.18 2.212 0 2.86 1.18 4.788 1.135 1.984-.032 3.235-1.775 4.427-3.559 1.428-2.026 2.002-4.02 2.024-4.123-.046-.016-3.854-1.469-3.891-5.865m-3.643-10.786c.994-1.244 1.675-2.936 1.486-4.654-1.44.064-3.24.995-4.276 2.213-.918 1.072-1.738 2.83-1.526 4.481 1.618.12 3.278-.816 4.316-2.04m21.362 17.839h5.002l-2.466-7.261h-.068zm5.658 2.066h-6.312l-1.515 4.475h-2.673l5.977-16.557h2.778l5.977 16.557h-2.718l-1.514-4.475m14.596-1.56c0-2.444-1.263-4.05-3.19-4.05-1.893 0-3.166 1.64-3.166 4.05 0 2.432 1.273 4.061 3.166 4.061 1.927 0 3.19-1.595 3.19-4.061zm2.547 0c0 3.751-2.008 6.161-5.038 6.161-1.72 0-3.086-.77-3.798-2.112h-.057v5.98h-2.478V28.591h2.398v2.007h.046c.689-1.295 2.157-2.134 3.844-2.134 3.063 0 5.083 2.422 5.083 6.162m10.738.001c0-2.444-1.263-4.05-3.19-4.05-1.893 0-3.166 1.64-3.166 4.05 0 2.432 1.273 4.061 3.166 4.061 1.927 0 3.19-1.595 3.19-4.061zm2.547 0c0 3.751-2.008 6.161-5.038 6.161-1.72 0-3.086-.77-3.798-2.112h-.057v5.98h-2.478V28.591h2.398v2.007h.046c.689-1.295 2.157-2.134 3.844-2.134 3.063 0 5.083 2.422 5.083 6.162m8.78 1.422c.184 1.642 1.78 2.72 3.96 2.72 2.088 0 3.59-1.078 3.59-2.558 0-1.285-.906-2.055-3.052-2.582l-2.146-.517c-3.04-.735-4.451-2.157-4.451-4.463 0-2.857 2.489-4.82 6.024-4.82 3.499 0 5.897 1.963 5.978 4.82h-2.501c-.15-1.653-1.516-2.65-3.512-2.65s-3.362 1.01-3.362 2.477c0 1.171.873 1.86 3.007 2.387l1.824.448c3.397.804 4.808 2.168 4.808 4.59 0 3.097-2.467 5.038-6.392 5.038-3.671 0-6.15-1.895-6.31-4.89h2.536m15.514-10.314v2.857h2.296v1.962h-2.296v6.655c0 1.034.46 1.515 1.469 1.515.253 0 .655-.035.815-.057v1.95c-.274.07-.826.115-1.376.115-2.444 0-3.397-.918-3.397-3.26v-6.918h-1.755V28.59h1.755v-2.857h2.49m12.551 8.894c0-2.605-1.194-4.143-3.202-4.143-2.007 0-3.2 1.55-3.2 4.143 0 2.616 1.193 4.142 3.2 4.142 2.008 0 3.202-1.526 3.202-4.142zm-8.927 0c0-3.798 2.237-6.184 5.725-6.184 3.5 0 5.727 2.386 5.727 6.184 0 3.809-2.215 6.185-5.727 6.185-3.51 0-5.725-2.376-5.725-6.185m13.495-6.036h2.363v2.055h.058c.378-1.367 1.48-2.182 2.903-2.182.356 0 .653.047.85.093v2.318c-.197-.082-.633-.15-1.114-.15-1.595 0-2.582 1.079-2.582 2.777v7.16h-2.478V28.591m9.218 4.922h6.035c-.058-1.847-1.239-3.064-2.96-3.064-1.71 0-2.948 1.24-3.075 3.064zm8.376 3.603c-.333 2.192-2.467 3.696-5.197 3.696-3.512 0-5.692-2.353-5.692-6.128 0-3.786 2.192-6.242 5.588-6.242 3.34 0 5.44 2.294 5.44 5.954v.85h-8.527v.15c0 2.064 1.298 3.418 3.248 3.418 1.376 0 2.456-.654 2.788-1.698h2.352M48.803 18.473h1.5c1.664 0 2.623-1.037 2.623-2.862 0-1.797-.975-2.845-2.623-2.845h-1.5zm1.638-6.831c2.36 0 3.744 1.45 3.744 3.953 0 2.542-1.374 4.003-3.744 4.003h-2.873v-7.956h2.873m9.583 4.951c0-1.301-.584-2.062-1.61-2.062-1.03 0-1.61.76-1.61 2.062 0 1.312.58 2.067 1.61 2.067 1.026 0 1.61-.76 1.61-2.067zm-4.443 0c0-1.936 1.08-3.115 2.833-3.115 1.748 0 2.829 1.18 2.829 3.115 0 1.946-1.076 3.12-2.83 3.12-1.758 0-2.832-1.174-2.832-3.12m13.188 3.005H67.54l-1.24-4.422h-.095l-1.235 4.422h-1.218l-1.654-6.004h1.201l1.076 4.581h.088l1.234-4.58h1.138l1.234 4.58h.094l1.07-4.58h1.185l-1.649 6.003m3.042-6.004h1.14v.954h.089c.291-.667.888-1.07 1.791-1.07 1.34 0 2.078.805 2.078 2.233v3.887h-1.184v-3.59c0-.965-.42-1.444-1.296-1.444s-1.434.585-1.434 1.522v3.512h-1.184v-6.004m6.986-2.344h1.185v8.347h-1.185V11.25m7.276 5.343c0-1.301-.585-2.062-1.61-2.062-1.03 0-1.61.76-1.61 2.062 0 1.312.58 2.067 1.61 2.067 1.025 0 1.61-.76 1.61-2.067zm-4.444 0c0-1.936 1.08-3.115 2.833-3.115 1.749 0 2.83 1.18 2.83 3.115 0 1.946-1.076 3.12-2.83 3.12-1.758 0-2.833-1.174-2.833-3.12m10.769.794v-.501l-1.466.093c-.827.056-1.202.337-1.202.866 0 .54.47.855 1.113.855.894 0 1.555-.569 1.555-1.313zm-3.86.513c0-1.08.805-1.703 2.234-1.792l1.626-.094v-.518c0-.634-.42-.992-1.23-.992-.66 0-1.119.243-1.25.667h-1.147c.12-1.031 1.09-1.693 2.453-1.693 1.505 0 2.354.75 2.354 2.018v4.102h-1.14v-.844h-.095c-.357.601-1.014.943-1.803.943-1.158 0-2.001-.7-2.001-1.797m7.82-1.307c0 1.273.6 2.04 1.604 2.04 1 0 1.617-.778 1.617-2.035 0-1.251-.624-2.04-1.617-2.04-.997 0-1.604.772-1.604 2.035zm-1.224 0c0-1.897.976-3.1 2.492-3.1.822 0 1.516.392 1.842 1.054h.088V11.25h1.185v8.347h-1.135v-.948h-.094c-.358.656-1.058 1.047-1.886 1.047-1.527 0-2.492-1.201-2.492-3.103m14.953 0c0-1.301-.584-2.062-1.61-2.062-1.03 0-1.61.76-1.61 2.062 0 1.312.58 2.067 1.61 2.067 1.026 0 1.61-.76 1.61-2.067zm-4.443 0c0-1.936 1.08-3.115 2.833-3.115 1.748 0 2.829 1.18 2.829 3.115 0 1.946-1.076 3.12-2.83 3.12-1.757 0-2.832-1.174-2.832-3.12m7.252-2.999h1.141v.954h.089c.291-.667.888-1.07 1.791-1.07 1.34 0 2.078.805 2.078 2.233v3.887h-1.184v-3.59c0-.965-.42-1.444-1.296-1.444s-1.434.585-1.434 1.522v3.512h-1.184v-6.004m11.793-1.494v1.521h1.3v.999h-1.3v3.087c0 .629.258.904.849.904.182 0 .286-.011.451-.027v.987c-.193.032-.414.06-.644.06-1.318 0-1.843-.464-1.843-1.621v-3.39h-.953v-.999h.953V12.1h1.187m2.919-.85h1.175v3.308h.094c.291-.673.925-1.075 1.83-1.075 1.279 0 2.068.81 2.068 2.238v3.876h-1.186v-3.583c0-.96-.447-1.445-1.284-1.445-.972 0-1.512.612-1.512 1.522v3.506h-1.185V11.25m7.914 4.792h3.033c-.028-.943-.601-1.555-1.479-1.555-.876 0-1.488.617-1.554 1.555zm4.168 1.935c-.27 1.075-1.23 1.737-2.602 1.737-1.72 0-2.773-1.18-2.773-3.1 0-1.918 1.076-3.136 2.768-3.136 1.67 0 2.679 1.142 2.679 3.026v.414h-4.24v.067c.04 1.052.652 1.72 1.598 1.72.719 0 1.21-.26 1.43-.728h1.14" fill="#fff"/></svg>
diff --git a/res/img/user-onboarding/CommunityMessaging.png b/res/img/user-onboarding/CommunityMessaging.png
deleted file mode 100644
index ec13eef8d66..00000000000
Binary files a/res/img/user-onboarding/CommunityMessaging.png and /dev/null differ
diff --git a/res/img/user-onboarding/PersonalMessaging.png b/res/img/user-onboarding/PersonalMessaging.png
deleted file mode 100644
index 8dce18ad909..00000000000
Binary files a/res/img/user-onboarding/PersonalMessaging.png and /dev/null differ
diff --git a/res/img/user-onboarding/WorkMessaging.png b/res/img/user-onboarding/WorkMessaging.png
deleted file mode 100644
index 7c3b813a84a..00000000000
Binary files a/res/img/user-onboarding/WorkMessaging.png and /dev/null differ
diff --git a/res/themes/light-custom/css/_custom.pcss b/res/themes/light-custom/css/_custom.pcss
index 0dfb38da98b..043de30191a 100644
--- a/res/themes/light-custom/css/_custom.pcss
+++ b/res/themes/light-custom/css/_custom.pcss
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/scripts/analyse_unused_exports.ts b/scripts/analyse_unused_exports.ts
index 46e594d2b74..fd0e762d943 100755
--- a/scripts/analyse_unused_exports.ts
+++ b/scripts/analyse_unused_exports.ts
@@ -19,6 +19,11 @@ ignore.push("/OpenSpotlightPayload.ts");
 ignore.push("/PinnedMessageBadge.tsx");
 ignore.push("/editor/mock.ts");
 ignore.push("DeviceIsolationModeController.ts");
+ignore.push("urls.ts");
+ignore.push("/json.ts");
+ignore.push("/ReleaseAnnouncementStore.ts");
+ignore.push("/WidgetLayoutStore.ts");
+ignore.push("/common.ts");
 
 // We ignore js-sdk by default as it may export for other non element-web projects
 if (!includeJSSDK) ignore.push("matrix-js-sdk");
diff --git a/scripts/copy-res.ts b/scripts/copy-res.ts
index 956dedc2a3f..905372cb0ae 100755
--- a/scripts/copy-res.ts
+++ b/scripts/copy-res.ts
@@ -19,9 +19,9 @@ const argv = parseArgs(process.argv.slice(2), {});
 const watch = argv.w;
 const verbose = argv.v;
 
-function errCheck(err?: Error): void {
+function errCheck(err: unknown): void {
     if (err) {
-        console.error(err.message);
+        console.error(err instanceof Error ? err.message : err);
         process.exit(1);
     }
 }
diff --git a/scripts/gen-workflow-mermaid.ts b/scripts/gen-workflow-mermaid.ts
index 1376323e84d..c33398268f4 100755
--- a/scripts/gen-workflow-mermaid.ts
+++ b/scripts/gen-workflow-mermaid.ts
@@ -573,7 +573,10 @@ components.forEach((graph) => {
 
                     let variations = cartesianProduct(
                         Object.keys(job.strategy.matrix)
-                            .filter((key) => key !== "include" && key !== "exclude")
+                            .filter(
+                                (key) =>
+                                    key !== "include" && key !== "exclude" && Array.isArray(job.strategy!.matrix[key]),
+                            )
                             .map((matrixKey) => {
                                 return job.strategy!.matrix[matrixKey].map((value) => ({ [matrixKey]: value }));
                             }),
diff --git a/src/@types/common.ts b/src/@types/common.ts
index f80b66a6322..cdf969a698a 100644
--- a/src/@types/common.ts
+++ b/src/@types/common.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -44,3 +44,11 @@ type DeepReadonlyObject<T> = {
 };
 
 export type AtLeastOne<T, U = { [K in keyof T]: Pick<T, K> }> = Partial<T> & U[keyof U];
+
+/**
+ * Returns a union type of the keys of the input Object type whose values are assignable to the given Item type.
+ * Based on https://stackoverflow.com/a/57862073
+ */
+export type Assignable<Object, Item> = {
+    [Key in keyof Object]: Object[Key] extends Item ? Key : never;
+}[keyof Object];
diff --git a/src/@types/commonmark.ts b/src/@types/commonmark.ts
index d773b736a19..2d3be1b2438 100644
--- a/src/@types/commonmark.ts
+++ b/src/@types/commonmark.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/@types/diff-dom.d.ts b/src/@types/diff-dom.d.ts
index 0ee966ad24c..986a84dc0b1 100644
--- a/src/@types/diff-dom.d.ts
+++ b/src/@types/diff-dom.d.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/@types/electron-to-chromium.d.ts b/src/@types/electron-to-chromium.d.ts
index b8dea3f83d7..7f723ffad51 100644
--- a/src/@types/electron-to-chromium.d.ts
+++ b/src/@types/electron-to-chromium.d.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/@types/global.d.ts b/src/@types/global.d.ts
index f921cd291f3..c76c43f8298 100644
--- a/src/@types/global.d.ts
+++ b/src/@types/global.d.ts
@@ -2,7 +2,7 @@
 Copyright 2020-2024 New Vector Ltd.
 Copyright 2020, 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/@types/jitsi-meet.d.ts b/src/@types/jitsi-meet.d.ts
index f2fac3ee5dc..a5dfe8230b4 100644
--- a/src/@types/jitsi-meet.d.ts
+++ b/src/@types/jitsi-meet.d.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/@types/json.ts b/src/@types/json.ts
new file mode 100644
index 00000000000..33af49a19ff
--- /dev/null
+++ b/src/@types/json.ts
@@ -0,0 +1,13 @@
+/*
+Copyright 2024 New Vector Ltd.
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+Please see LICENSE files in the repository root for full details.
+*/
+
+export type JsonValue = null | string | number | boolean;
+export type JsonArray = Array<JsonValue | JsonObject | JsonArray>;
+export interface JsonObject {
+    [key: string]: JsonObject | JsonArray | JsonValue;
+}
+export type Json = JsonArray | JsonObject;
diff --git a/src/@types/matrix-js-sdk.d.ts b/src/@types/matrix-js-sdk.d.ts
index 41ccfcbb3b2..6ffa09dd4f8 100644
--- a/src/@types/matrix-js-sdk.d.ts
+++ b/src/@types/matrix-js-sdk.d.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -11,6 +11,8 @@ import type { BLURHASH_FIELD } from "../utils/image-media";
 import type { JitsiCallMemberEventType, JitsiCallMemberContent } from "../call-types";
 import type { ILayoutStateEvent, WIDGET_LAYOUT_EVENT_TYPE } from "../stores/widgets/types";
 import type { EncryptedFile } from "matrix-js-sdk/src/types";
+import type { DeviceClientInformation } from "../utils/device/types.ts";
+import type { UserWidget } from "../utils/WidgetUtils-types.ts";
 
 // Extend Matrix JS SDK types via Typescript declaration merging to support unspecced event fields and types
 declare module "matrix-js-sdk/src/types" {
@@ -57,6 +59,35 @@ declare module "matrix-js-sdk/src/types" {
         };
     }
 
+    export interface AccountDataEvents {
+        // Analytics account data event
+        "im.vector.analytics": {
+            id: string;
+            pseudonymousAnalyticsOptIn?: boolean;
+        };
+        // Device client information account data event
+        [key: `io.element.matrix_client_information.${string}`]: DeviceClientInformation;
+        // Element settings account data events
+        "im.vector.setting.breadcrumbs": { recent_rooms: string[] };
+        "io.element.recent_emoji": { recent_emoji: string[] };
+        "im.vector.setting.integration_provisioning": { enabled: boolean };
+        "im.vector.riot.breadcrumb_rooms": { recent_rooms: string[] };
+        "im.vector.web.settings": Record<string, any>;
+
+        // URL preview account data event
+        "org.matrix.preview_urls": { disable: boolean };
+
+        // This is not yet in the Matrix spec yet is being used as if it was
+        "m.widgets": {
+            [widgetId: string]: UserWidget;
+        };
+
+        // This is not in the Matrix spec yet seems to use an `m.` prefix
+        "m.accepted_terms": {
+            accepted: string[];
+        };
+    }
+
     export interface AudioContent {
         // MSC1767 + Ideals of MSC2516 as MSC3245
         // https://github.com/matrix-org/matrix-doc/pull/3245
diff --git a/src/@types/opus-recorder.d.ts b/src/@types/opus-recorder.d.ts
index 8b4605a24a2..8d103bedfd9 100644
--- a/src/@types/opus-recorder.d.ts
+++ b/src/@types/opus-recorder.d.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/@types/png-chunks-extract.d.ts b/src/@types/png-chunks-extract.d.ts
deleted file mode 100644
index c767b40655b..00000000000
--- a/src/@types/png-chunks-extract.d.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2021 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
-Please see LICENSE files in the repository root for full details.
-*/
-
-declare module "png-chunks-extract" {
-    interface IChunk {
-        name: string;
-        data: Uint8Array;
-    }
-
-    function extractPngChunks(data: Uint8Array): IChunk[];
-
-    export default extractPngChunks;
-}
diff --git a/src/@types/polyfill.ts b/src/@types/polyfill.ts
index 1e10b173035..5e08725889f 100644
--- a/src/@types/polyfill.ts
+++ b/src/@types/polyfill.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/@types/raw-loader.d.ts b/src/@types/raw-loader.d.ts
index 902a257a124..b9ab4445a41 100644
--- a/src/@types/raw-loader.d.ts
+++ b/src/@types/raw-loader.d.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/@types/react.d.ts b/src/@types/react.d.ts
index ba97b2bba6f..2573bc0ab94 100644
--- a/src/@types/react.d.ts
+++ b/src/@types/react.d.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/@types/sanitize-html.d.ts b/src/@types/sanitize-html.d.ts
deleted file mode 100644
index 34474fc655a..00000000000
--- a/src/@types/sanitize-html.d.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2020 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
-Please see LICENSE files in the repository root for full details.
-*/
-
-import sanitizeHtml from "sanitize-html";
-
-export interface IExtendedSanitizeOptions extends sanitizeHtml.IOptions {
-    // This option only exists in 2.x RCs so far, so not yet present in the
-    // separate type definition module.
-    nestingLimit?: number;
-}
diff --git a/src/@types/svg.d.ts b/src/@types/svg.d.ts
index f0491a594ec..8a8990645b6 100644
--- a/src/@types/svg.d.ts
+++ b/src/@types/svg.d.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/@types/worker-loader.d.ts b/src/@types/worker-loader.d.ts
index 39734725e6e..7bc6436367e 100644
--- a/src/@types/worker-loader.d.ts
+++ b/src/@types/worker-loader.d.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/AddThreepid.ts b/src/AddThreepid.ts
index 5232132535c..757ea181805 100644
--- a/src/AddThreepid.ts
+++ b/src/AddThreepid.ts
@@ -4,7 +4,7 @@ Copyright 2019 The Matrix.org Foundation C.I.C.
 Copyright 2017 Vector Creations Ltd
 Copyright 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/AsyncWrapper.tsx b/src/AsyncWrapper.tsx
index 2a04d804b77..e1b80c9d5a2 100644
--- a/src/AsyncWrapper.tsx
+++ b/src/AsyncWrapper.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/Avatar.ts b/src/Avatar.ts
index a78aa4d03b3..a6725710d1d 100644
--- a/src/Avatar.ts
+++ b/src/Avatar.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/BasePlatform.ts b/src/BasePlatform.ts
index 0017d00dacb..db4802d4bba 100644
--- a/src/BasePlatform.ts
+++ b/src/BasePlatform.ts
@@ -5,7 +5,7 @@ Copyright 2018 New Vector Ltd
 Copyright 2016 Aviral Dasgupta
 Copyright 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/BlurhashEncoder.ts b/src/BlurhashEncoder.ts
index 9cd386894f6..aef0746dbe0 100644
--- a/src/BlurhashEncoder.ts
+++ b/src/BlurhashEncoder.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/ContentMessages.ts b/src/ContentMessages.ts
index 344a2f112c3..060c8ab994d 100644
--- a/src/ContentMessages.ts
+++ b/src/ContentMessages.ts
@@ -4,7 +4,7 @@ Copyright 2020 The Matrix.org Foundation C.I.C.
 Copyright 2019 New Vector Ltd
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/CreateCrossSigning.ts b/src/CreateCrossSigning.ts
index c38f1a3dd57..0c043d9d2bb 100644
--- a/src/CreateCrossSigning.ts
+++ b/src/CreateCrossSigning.ts
@@ -3,64 +3,29 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
 Copyright 2018, 2019 New Vector Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
-import { logger } from "matrix-js-sdk/src/logger";
-import { AuthDict, CrossSigningKeys, MatrixClient, MatrixError, UIAFlow, UIAResponse } from "matrix-js-sdk/src/matrix";
+import { AuthDict, MatrixClient, MatrixError, UIAResponse } from "matrix-js-sdk/src/matrix";
 
 import { SSOAuthEntry } from "./components/views/auth/InteractiveAuthEntryComponents";
 import Modal from "./Modal";
 import { _t } from "./languageHandler";
 import InteractiveAuthDialog from "./components/views/dialogs/InteractiveAuthDialog";
 
-/**
- * Determine if the homeserver allows uploading device keys with only password auth, or with no auth at
- * all (ie. if the homeserver supports MSC3967).
- * @param cli The Matrix Client to use
- * @returns True if the homeserver allows uploading device keys with only password auth or with no auth
- * at all, otherwise false
- */
-async function canUploadKeysWithPasswordOnly(cli: MatrixClient): Promise<boolean> {
-    try {
-        await cli.uploadDeviceSigningKeys(undefined, {} as CrossSigningKeys);
-        // If we get here, it's because the server is allowing us to upload keys without
-        // auth the first time due to MSC3967. Therefore, yes, we can upload keys
-        // (with or without password, technically, but that's fine).
-        return true;
-    } catch (error) {
-        if (!(error instanceof MatrixError) || !error.data || !error.data.flows) {
-            logger.log("uploadDeviceSigningKeys advertised no flows!");
-            return false;
-        }
-        const canUploadKeysWithPasswordOnly = error.data.flows.some((f: UIAFlow) => {
-            return f.stages.length === 1 && f.stages[0] === "m.login.password";
-        });
-        return canUploadKeysWithPasswordOnly;
-    }
-}
-
 /**
  * Ensures that cross signing keys are created and uploaded for the user.
  * The homeserver may require user-interactive auth to upload the keys, in
- * which case the user will be prompted to authenticate. If the homeserver
- * allows uploading keys with just an account password and one is provided,
- * the keys will be uploaded without user interaction.
+ * which case the user will be prompted to authenticate.
  *
  * This function does not set up backups of the created cross-signing keys
  * (or message keys): the cross-signing keys are stored locally and will be
  * lost requiring a crypto reset, if the user logs out or loses their session.
  *
  * @param cli The Matrix Client to use
- * @param isTokenLogin True if the user logged in via a token login, otherwise false
- * @param accountPassword The password that the user logged in with
  */
-export async function createCrossSigning(
-    cli: MatrixClient,
-    isTokenLogin: boolean,
-    accountPassword?: string,
-): Promise<void> {
+export async function createCrossSigning(cli: MatrixClient): Promise<void> {
     const cryptoApi = cli.getCrypto();
     if (!cryptoApi) {
         throw new Error("No crypto API found!");
@@ -69,19 +34,14 @@ export async function createCrossSigning(
     const doBootstrapUIAuth = async (
         makeRequest: (authData: AuthDict) => Promise<UIAResponse<void>>,
     ): Promise<void> => {
-        if (accountPassword && (await canUploadKeysWithPasswordOnly(cli))) {
-            await makeRequest({
-                type: "m.login.password",
-                identifier: {
-                    type: "m.id.user",
-                    user: cli.getUserId(),
-                },
-                password: accountPassword,
-            });
-        } else if (isTokenLogin) {
-            // We are hoping the grace period is active
+        try {
             await makeRequest({});
-        } else {
+        } catch (error) {
+            if (!(error instanceof MatrixError) || !error.data || !error.data.flows) {
+                // Not a UIA response
+                throw error;
+            }
+
             const dialogAesthetics = {
                 [SSOAuthEntry.PHASE_PREAUTH]: {
                     title: _t("auth|uia|sso_title"),
diff --git a/src/DateUtils.ts b/src/DateUtils.ts
index 0710e0b8679..7c7b7dd7e6c 100644
--- a/src/DateUtils.ts
+++ b/src/DateUtils.ts
@@ -4,7 +4,7 @@ Copyright 2022 The Matrix.org Foundation C.I.C.
 Copyright 2017 Vector Creations Ltd
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/DecryptionFailureTracker.ts b/src/DecryptionFailureTracker.ts
index bfcd126eeaa..6a226ad3fe6 100644
--- a/src/DecryptionFailureTracker.ts
+++ b/src/DecryptionFailureTracker.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2018-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/DeviceListener.ts b/src/DeviceListener.ts
index e34af95962c..28bb5f655e0 100644
--- a/src/DeviceListener.ts
+++ b/src/DeviceListener.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/DraftCleaner.ts b/src/DraftCleaner.ts
index 48a3523f616..6adae6b8f45 100644
--- a/src/DraftCleaner.ts
+++ b/src/DraftCleaner.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/Editing.ts b/src/Editing.ts
index 1d0cd26ab7e..3b8d2d393aa 100644
--- a/src/Editing.ts
+++ b/src/Editing.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/HtmlUtils.tsx b/src/HtmlUtils.tsx
index 3146a9eb078..d635b23221f 100644
--- a/src/HtmlUtils.tsx
+++ b/src/HtmlUtils.tsx
@@ -5,12 +5,12 @@ Copyright 2019 The Matrix.org Foundation C.I.C.
 Copyright 2017, 2018 New Vector Ltd
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 import React, { LegacyRef, ReactNode } from "react";
-import sanitizeHtml from "sanitize-html";
+import sanitizeHtml, { IOptions } from "sanitize-html";
 import classNames from "classnames";
 import katex from "katex";
 import { decode } from "html-entities";
@@ -19,7 +19,6 @@ import { Optional } from "matrix-events-sdk";
 import escapeHtml from "escape-html";
 import { getEmojiFromUnicode } from "@matrix-org/emojibase-bindings";
 
-import { IExtendedSanitizeOptions } from "./@types/sanitize-html";
 import SettingsStore from "./settings/SettingsStore";
 import { stripHTMLReply, stripPlainReply } from "./utils/Reply";
 import { PERMITTED_URL_SCHEMES } from "./utils/UrlUtils";
@@ -126,7 +125,7 @@ export function isUrlPermitted(inputUrl: string): boolean {
 }
 
 // this is the same as the above except with less rewriting
-const composerSanitizeHtmlParams: IExtendedSanitizeOptions = {
+const composerSanitizeHtmlParams: IOptions = {
     ...sanitizeHtmlParams,
     transformTags: {
         "code": transformTags["code"],
@@ -135,7 +134,7 @@ const composerSanitizeHtmlParams: IExtendedSanitizeOptions = {
 };
 
 // reduced set of allowed tags to avoid turning topics into Myspace
-const topicSanitizeHtmlParams: IExtendedSanitizeOptions = {
+const topicSanitizeHtmlParams: IOptions = {
     ...sanitizeHtmlParams,
     allowedTags: [
         "font", // custom to matrix for IRC-style font coloring
diff --git a/src/IConfigOptions.ts b/src/IConfigOptions.ts
index 5dd500402d4..bbb377e07b7 100644
--- a/src/IConfigOptions.ts
+++ b/src/IConfigOptions.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019-2022 The Matrix.org Foundation C.I.C.
 Copyright 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/IdentityAuthClient.tsx b/src/IdentityAuthClient.tsx
index 8963b6bcf25..ce20bc92edb 100644
--- a/src/IdentityAuthClient.tsx
+++ b/src/IdentityAuthClient.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/ImageUtils.ts b/src/ImageUtils.ts
index 0b5ed28d21d..94715f4f7c1 100644
--- a/src/ImageUtils.ts
+++ b/src/ImageUtils.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015, 2016 , 2020 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/KeyBindingsDefaults.ts b/src/KeyBindingsDefaults.ts
index 10d89ecfda3..3a4412c5dbb 100644
--- a/src/KeyBindingsDefaults.ts
+++ b/src/KeyBindingsDefaults.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2022 Šimon Brandner <simon.bra.ag@gmail.com>
 Copyright 2021 Clemens Zeidler
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/KeyBindingsManager.ts b/src/KeyBindingsManager.ts
index 007b6abf17f..5c8bccbfd06 100644
--- a/src/KeyBindingsManager.ts
+++ b/src/KeyBindingsManager.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2022 Šimon Brandner <simon.bra.ag@gmail.com>
 Copyright 2021 Clemens Zeidler
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/Keyboard.ts b/src/Keyboard.ts
index 5688ac2a20b..59c6bf77cf3 100644
--- a/src/Keyboard.ts
+++ b/src/Keyboard.ts
@@ -4,7 +4,7 @@ Copyright 2019 The Matrix.org Foundation C.I.C.
 Copyright 2017 New Vector Ltd
 Copyright 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/LegacyCallHandler.tsx b/src/LegacyCallHandler.tsx
index b804ca0084d..c2df066fa23 100644
--- a/src/LegacyCallHandler.tsx
+++ b/src/LegacyCallHandler.tsx
@@ -5,7 +5,7 @@ Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
 Copyright 2017, 2018 New Vector Ltd
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/Lifecycle.ts b/src/Lifecycle.ts
index 89faa9e0e9a..80b08c8840f 100644
--- a/src/Lifecycle.ts
+++ b/src/Lifecycle.ts
@@ -5,7 +5,7 @@ Copyright 2018 New Vector Ltd
 Copyright 2017 Vector Creations Ltd
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -110,7 +110,6 @@ dis.register((payload) => {
 let sessionLockStolen = false;
 
 // this is exposed solely for unit tests.
-// ts-prune-ignore-next
 export function setSessionLockNotStolen(): void {
     sessionLockStolen = false;
 }
@@ -1050,9 +1049,9 @@ async function clearStorage(opts?: { deleteEverything?: boolean }): Promise<void
         window.localStorage.clear();
 
         try {
-            await StorageAccess.idbDelete("account", ACCESS_TOKEN_STORAGE_KEY);
+            await StorageAccess.idbClear("account");
         } catch (e) {
-            logger.error("idbDelete failed for account:mx_access_token", e);
+            logger.error("idbClear failed for account", e);
         }
 
         // now restore those invites, registration time and previously set device language
diff --git a/src/Linkify.tsx b/src/Linkify.tsx
index d980c496c4f..db4c70228a1 100644
--- a/src/Linkify.tsx
+++ b/src/Linkify.tsx
@@ -2,12 +2,12 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 import React, { ReactElement } from "react";
-import sanitizeHtml from "sanitize-html";
+import sanitizeHtml, { IOptions } from "sanitize-html";
 import { merge } from "lodash";
 import _Linkify from "linkify-react";
 
@@ -17,7 +17,6 @@ import {
     ELEMENT_URL_PATTERN,
     options as linkifyMatrixOptions,
 } from "./linkify-matrix";
-import { IExtendedSanitizeOptions } from "./@types/sanitize-html";
 import SettingsStore from "./settings/SettingsStore";
 import { tryTransformPermalinkToLocalHref } from "./utils/permalinks/Permalinks";
 import { mediaFromMxc } from "./customisations/Media";
@@ -26,7 +25,7 @@ import { PERMITTED_URL_SCHEMES } from "./utils/UrlUtils";
 const COLOR_REGEX = /^#[0-9a-fA-F]{6}$/;
 const MEDIA_API_MXC_REGEX = /\/_matrix\/media\/r0\/(?:download|thumbnail)\/(.+?)\/(.+?)(?:[?/]|$)/;
 
-export const transformTags: NonNullable<IExtendedSanitizeOptions["transformTags"]> = {
+export const transformTags: NonNullable<IOptions["transformTags"]> = {
     // custom to matrix
     // add blank targets to all hyperlinks except vector URLs
     "a": function (tagName: string, attribs: sanitizeHtml.Attributes) {
@@ -137,7 +136,7 @@ export const transformTags: NonNullable<IExtendedSanitizeOptions["transformTags"
     },
 };
 
-export const sanitizeHtmlParams: IExtendedSanitizeOptions = {
+export const sanitizeHtmlParams: IOptions = {
     allowedTags: [
         // These tags are suggested by the spec https://spec.matrix.org/v1.10/client-server-api/#mroommessage-msgtypes
         "font", // custom to matrix for IRC-style font coloring
diff --git a/src/Livestream.ts b/src/Livestream.ts
index ffa59282e3d..9cda793385a 100644
--- a/src/Livestream.ts
+++ b/src/Livestream.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/Login.ts b/src/Login.ts
index 5e1b1d1a353..aa84ad3c86b 100644
--- a/src/Login.ts
+++ b/src/Login.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2015-2021 The Matrix.org Foundation C.I.C.
 Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/Markdown.ts b/src/Markdown.ts
index 9a346bf2f6d..6f0e3e0c5e0 100644
--- a/src/Markdown.ts
+++ b/src/Markdown.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 Copyright 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/MatrixClientPeg.ts b/src/MatrixClientPeg.ts
index ce879531185..ab952c56334 100644
--- a/src/MatrixClientPeg.ts
+++ b/src/MatrixClientPeg.ts
@@ -5,7 +5,7 @@ Copyright 2017, 2018 , 2019 New Vector Ltd
 Copyright 2017 Vector Creations Ltd.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/MediaDeviceHandler.ts b/src/MediaDeviceHandler.ts
index 147cabb7c5b..7a50024d1aa 100644
--- a/src/MediaDeviceHandler.ts
+++ b/src/MediaDeviceHandler.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
 Copyright 2017 Michael Telatynski <7t3chguy@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/Modal.tsx b/src/Modal.tsx
index 2aefdccb462..31ad6b9bfcf 100644
--- a/src/Modal.tsx
+++ b/src/Modal.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/NodeAnimator.tsx b/src/NodeAnimator.tsx
index 3ca098311fc..16c5a716ff7 100644
--- a/src/NodeAnimator.tsx
+++ b/src/NodeAnimator.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/Notifier.ts b/src/Notifier.ts
index c724c4780cd..377559a6fc7 100644
--- a/src/Notifier.ts
+++ b/src/Notifier.ts
@@ -5,7 +5,7 @@ Copyright 2017 Vector Creations Ltd
 Copyright 2017 New Vector Ltd
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -176,7 +176,7 @@ class NotifierClass extends TypedEventEmitter<keyof EmittedEvents, EmittedEvents
         url: string;
         name: string;
         type: string;
-        size: string;
+        size: number;
     } | null {
         // We do no caching here because the SDK caches setting
         // and the browser will cache the sound.
diff --git a/src/PageTypes.ts b/src/PageTypes.ts
index 1ebb824303a..3e7f2471a35 100644
--- a/src/PageTypes.ts
+++ b/src/PageTypes.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2017 Vector Creations Ltd
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/PasswordReset.ts b/src/PasswordReset.ts
index b5ca039d7cd..f23d14799bc 100644
--- a/src/PasswordReset.ts
+++ b/src/PasswordReset.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019-2022 The Matrix.org Foundation C.I.C.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/PlatformPeg.ts b/src/PlatformPeg.ts
index 87c3b174886..493fde8f848 100644
--- a/src/PlatformPeg.ts
+++ b/src/PlatformPeg.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 Copyright 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/PlaybackEncoder.ts b/src/PlaybackEncoder.ts
index 10a539799de..dc212e6a28c 100644
--- a/src/PlaybackEncoder.ts
+++ b/src/PlaybackEncoder.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/PosthogAnalytics.ts b/src/PosthogAnalytics.ts
index 6217d9b7dd6..91208e253d5 100644
--- a/src/PosthogAnalytics.ts
+++ b/src/PosthogAnalytics.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/PosthogTrackers.ts b/src/PosthogTrackers.ts
index 5d7c793f627..02faa6b5ec5 100644
--- a/src/PosthogTrackers.ts
+++ b/src/PosthogTrackers.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -24,7 +24,6 @@ const notLoggedInMap: Record<Exclude<Views, Views.LOGGED_IN>, ScreenName> = {
     [Views.WELCOME]: "Welcome",
     [Views.LOGIN]: "Login",
     [Views.REGISTER]: "Register",
-    [Views.USE_CASE_SELECTION]: "UseCaseSelection",
     [Views.FORGOT_PASSWORD]: "ForgotPassword",
     [Views.COMPLETE_SECURITY]: "CompleteSecurity",
     [Views.E2E_SETUP]: "E2ESetup",
diff --git a/src/Presence.ts b/src/Presence.ts
index af06d4a1d6c..8057a0f7378 100644
--- a/src/Presence.ts
+++ b/src/Presence.ts
@@ -4,7 +4,7 @@ Copyright 2019 The Matrix.org Foundation C.I.C.
 Copyright 2018 New Vector Ltd
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/Registration.tsx b/src/Registration.tsx
index bbb6295f7db..ea0264fab35 100644
--- a/src/Registration.tsx
+++ b/src/Registration.tsx
@@ -1,7 +1,7 @@
 /*
 Copyright 2018-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/Resend.ts b/src/Resend.ts
index 064bebf93ac..109aea632fb 100644
--- a/src/Resend.ts
+++ b/src/Resend.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/Roles.ts b/src/Roles.ts
index 38b6d7465e3..06433c507ba 100644
--- a/src/Roles.ts
+++ b/src/Roles.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2017 Vector Creations Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/RoomAliasCache.ts b/src/RoomAliasCache.ts
index 81a85b4a0b4..fd611a7559f 100644
--- a/src/RoomAliasCache.ts
+++ b/src/RoomAliasCache.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/RoomInvite.tsx b/src/RoomInvite.tsx
index 07a24dd384c..91ea459230e 100644
--- a/src/RoomInvite.tsx
+++ b/src/RoomInvite.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2016-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/RoomNotifs.ts b/src/RoomNotifs.ts
index 7c281d0d2d8..e6064d26914 100644
--- a/src/RoomNotifs.ts
+++ b/src/RoomNotifs.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2016-2019 , 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/Rooms.ts b/src/Rooms.ts
index d24f008b56c..347316c4c94 100644
--- a/src/Rooms.ts
+++ b/src/Rooms.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/ScalarAuthClient.ts b/src/ScalarAuthClient.ts
index de1bf2943bd..094bb6fe593 100644
--- a/src/ScalarAuthClient.ts
+++ b/src/ScalarAuthClient.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2016-2019 , 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/ScalarMessaging.ts b/src/ScalarMessaging.ts
index 82846b9abf4..003d02f2ddb 100644
--- a/src/ScalarMessaging.ts
+++ b/src/ScalarMessaging.ts
@@ -3,7 +3,7 @@ Copyright 2018-2024 New Vector Ltd.
 Copyright 2017 Vector Creations Ltd
 Copyright 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/SdkConfig.ts b/src/SdkConfig.ts
index c9a0010b0ff..ee1c4eab8a9 100644
--- a/src/SdkConfig.ts
+++ b/src/SdkConfig.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019-2022 The Matrix.org Foundation C.I.C.
 Copyright 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/Searching.ts b/src/Searching.ts
index 252d4378ade..dea724fbdf0 100644
--- a/src/Searching.ts
+++ b/src/Searching.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/SecurityManager.ts b/src/SecurityManager.ts
index e8122b2dbf2..6af8dd5f184 100644
--- a/src/SecurityManager.ts
+++ b/src/SecurityManager.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -191,8 +191,6 @@ export interface AccessSecretStorageOpts {
     forceReset?: boolean;
     /** Create new cross-signing keys. Only applicable if `forceReset` is `true`. */
     resetCrossSigning?: boolean;
-    /** The cached account password, if available. */
-    accountPassword?: string;
 }
 
 /**
diff --git a/src/SendHistoryManager.ts b/src/SendHistoryManager.ts
index 07da60ef6ba..517e1b45e36 100644
--- a/src/SendHistoryManager.ts
+++ b/src/SendHistoryManager.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2017 Aviral Dasgupta
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/SlashCommands.tsx b/src/SlashCommands.tsx
index b739cec12fc..08ecd0562b7 100644
--- a/src/SlashCommands.tsx
+++ b/src/SlashCommands.tsx
@@ -5,7 +5,7 @@ Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
 Copyright 2018 New Vector Ltd
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/SlidingSyncManager.ts b/src/SlidingSyncManager.ts
index 11872d059ee..b9922e2290f 100644
--- a/src/SlidingSyncManager.ts
+++ b/src/SlidingSyncManager.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/SupportedBrowser.ts b/src/SupportedBrowser.ts
index 099648a936c..0527ed829f0 100644
--- a/src/SupportedBrowser.ts
+++ b/src/SupportedBrowser.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/Terms.ts b/src/Terms.ts
index 868e2428c67..02b67545da1 100644
--- a/src/Terms.ts
+++ b/src/Terms.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/TextForEvent.tsx b/src/TextForEvent.tsx
index 49d8b739b73..bdb7e8cbe0e 100644
--- a/src/TextForEvent.tsx
+++ b/src/TextForEvent.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015-2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/TimezoneHandler.ts b/src/TimezoneHandler.ts
index c7c603b5fe2..eb1bacef5f4 100644
--- a/src/TimezoneHandler.ts
+++ b/src/TimezoneHandler.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/Typeguards.ts b/src/Typeguards.ts
index 4d39847dcb3..138accbb95c 100644
--- a/src/Typeguards.ts
+++ b/src/Typeguards.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/Unread.ts b/src/Unread.ts
index 06d2344938b..e79a9cb75f9 100644
--- a/src/Unread.ts
+++ b/src/Unread.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015-2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/UserActivity.ts b/src/UserActivity.ts
index a1a090ca0e1..c63b595b418 100644
--- a/src/UserActivity.ts
+++ b/src/UserActivity.ts
@@ -2,7 +2,7 @@
 Copyright 2019-2024 New Vector Ltd.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/UserAddress.ts b/src/UserAddress.ts
index 4f576d0762c..1ba84a5ab38 100644
--- a/src/UserAddress.ts
+++ b/src/UserAddress.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2017-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/Views.ts b/src/Views.ts
index 68e1feb2303..6c0df53a661 100644
--- a/src/Views.ts
+++ b/src/Views.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -33,9 +33,6 @@ enum Views {
     // flow to setup SSSS / cross-signing on this account
     E2E_SETUP,
 
-    // screen that allows users to select which use case they’ll use matrix for
-    USE_CASE_SELECTION,
-
     // we are logged in with an active matrix client. The logged_in state also
     // includes guests users as they too are logged in at the client level.
     LOGGED_IN,
diff --git a/src/VoipUserMapper.ts b/src/VoipUserMapper.ts
index 41e0ab3df4a..a0290a3eb18 100644
--- a/src/VoipUserMapper.ts
+++ b/src/VoipUserMapper.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/WhoIsTyping.ts b/src/WhoIsTyping.ts
index 9a0b279c32f..c209253206a 100644
--- a/src/WhoIsTyping.ts
+++ b/src/WhoIsTyping.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2017 Vector Creations Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/WorkerManager.ts b/src/WorkerManager.ts
index 1878769c248..089463dc915 100644
--- a/src/WorkerManager.ts
+++ b/src/WorkerManager.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/accessibility/KeyboardShortcutUtils.ts b/src/accessibility/KeyboardShortcutUtils.ts
index 6b049ab41cc..4eafb80f36a 100644
--- a/src/accessibility/KeyboardShortcutUtils.ts
+++ b/src/accessibility/KeyboardShortcutUtils.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 Šimon Brandner <simon.bra.ag@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/accessibility/KeyboardShortcuts.ts b/src/accessibility/KeyboardShortcuts.ts
index bdc0123ee7d..1e8febb0bbc 100644
--- a/src/accessibility/KeyboardShortcuts.ts
+++ b/src/accessibility/KeyboardShortcuts.ts
@@ -4,7 +4,7 @@ Copyright 2022 The Matrix.org Foundation C.I.C.
 Copyright 2021, 2022 Šimon Brandner <simon.bra.ag@gmail.com>
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/accessibility/LandmarkNavigation.ts b/src/accessibility/LandmarkNavigation.ts
index 68c9e0b118b..1c6fe543450 100644
--- a/src/accessibility/LandmarkNavigation.ts
+++ b/src/accessibility/LandmarkNavigation.ts
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2024 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/src/accessibility/RovingTabIndex.tsx b/src/accessibility/RovingTabIndex.tsx
index d35a0291c3e..dada99b3e7f 100644
--- a/src/accessibility/RovingTabIndex.tsx
+++ b/src/accessibility/RovingTabIndex.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/accessibility/Toolbar.tsx b/src/accessibility/Toolbar.tsx
index 7d4b1f936d4..317ff8b9363 100644
--- a/src/accessibility/Toolbar.tsx
+++ b/src/accessibility/Toolbar.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/accessibility/context_menu/ContextMenuButton.tsx b/src/accessibility/context_menu/ContextMenuButton.tsx
index 9d8b5585e3b..e326e087b97 100644
--- a/src/accessibility/context_menu/ContextMenuButton.tsx
+++ b/src/accessibility/context_menu/ContextMenuButton.tsx
@@ -4,7 +4,7 @@ Copyright 2019 The Matrix.org Foundation C.I.C.
 Copyright 2018 New Vector Ltd
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/accessibility/context_menu/ContextMenuTooltipButton.tsx b/src/accessibility/context_menu/ContextMenuTooltipButton.tsx
index 80023680838..7a4230ddf78 100644
--- a/src/accessibility/context_menu/ContextMenuTooltipButton.tsx
+++ b/src/accessibility/context_menu/ContextMenuTooltipButton.tsx
@@ -4,7 +4,7 @@ Copyright 2019 The Matrix.org Foundation C.I.C.
 Copyright 2018 New Vector Ltd
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/accessibility/context_menu/MenuItem.tsx b/src/accessibility/context_menu/MenuItem.tsx
index f30fd64f72b..6aef5498706 100644
--- a/src/accessibility/context_menu/MenuItem.tsx
+++ b/src/accessibility/context_menu/MenuItem.tsx
@@ -4,7 +4,7 @@ Copyright 2019 The Matrix.org Foundation C.I.C.
 Copyright 2018 New Vector Ltd
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/accessibility/context_menu/MenuItemCheckbox.tsx b/src/accessibility/context_menu/MenuItemCheckbox.tsx
index 2e383393e4a..7ee62875139 100644
--- a/src/accessibility/context_menu/MenuItemCheckbox.tsx
+++ b/src/accessibility/context_menu/MenuItemCheckbox.tsx
@@ -4,7 +4,7 @@ Copyright 2019 The Matrix.org Foundation C.I.C.
 Copyright 2018 New Vector Ltd
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/accessibility/context_menu/MenuItemRadio.tsx b/src/accessibility/context_menu/MenuItemRadio.tsx
index 69e690f83f4..8094e984e7d 100644
--- a/src/accessibility/context_menu/MenuItemRadio.tsx
+++ b/src/accessibility/context_menu/MenuItemRadio.tsx
@@ -4,7 +4,7 @@ Copyright 2019 The Matrix.org Foundation C.I.C.
 Copyright 2018 New Vector Ltd
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/accessibility/context_menu/StyledMenuItemCheckbox.tsx b/src/accessibility/context_menu/StyledMenuItemCheckbox.tsx
index af49288d0ff..472e7bcae2a 100644
--- a/src/accessibility/context_menu/StyledMenuItemCheckbox.tsx
+++ b/src/accessibility/context_menu/StyledMenuItemCheckbox.tsx
@@ -4,7 +4,7 @@ Copyright 2019 The Matrix.org Foundation C.I.C.
 Copyright 2018 New Vector Ltd
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/accessibility/context_menu/StyledMenuItemRadio.tsx b/src/accessibility/context_menu/StyledMenuItemRadio.tsx
index a6a6993e77c..5bf6d4706c0 100644
--- a/src/accessibility/context_menu/StyledMenuItemRadio.tsx
+++ b/src/accessibility/context_menu/StyledMenuItemRadio.tsx
@@ -4,7 +4,7 @@ Copyright 2019 The Matrix.org Foundation C.I.C.
 Copyright 2018 New Vector Ltd
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/accessibility/roving/RovingAccessibleButton.tsx b/src/accessibility/roving/RovingAccessibleButton.tsx
index b53221e1c99..70e569e3351 100644
--- a/src/accessibility/roving/RovingAccessibleButton.tsx
+++ b/src/accessibility/roving/RovingAccessibleButton.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/accessibility/roving/RovingTabIndexWrapper.tsx b/src/accessibility/roving/RovingTabIndexWrapper.tsx
index b44f44b92f1..a47c1cb3efc 100644
--- a/src/accessibility/roving/RovingTabIndexWrapper.tsx
+++ b/src/accessibility/roving/RovingTabIndexWrapper.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/accessibility/roving/types.ts b/src/accessibility/roving/types.ts
index 98b498844b3..3cf8cdf6c0c 100644
--- a/src/accessibility/roving/types.ts
+++ b/src/accessibility/roving/types.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/actions/MatrixActionCreators.ts b/src/actions/MatrixActionCreators.ts
index 6f32220ee33..ccda4853f6d 100644
--- a/src/actions/MatrixActionCreators.ts
+++ b/src/actions/MatrixActionCreators.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2017-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/actions/RoomListActions.ts b/src/actions/RoomListActions.ts
index 578226986d7..7418ec2cdd1 100644
--- a/src/actions/RoomListActions.ts
+++ b/src/actions/RoomListActions.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 Copyright 2018 New Vector Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/actions/actionCreators.ts b/src/actions/actionCreators.ts
index 55a6ec729ce..f3a097d06f0 100644
--- a/src/actions/actionCreators.ts
+++ b/src/actions/actionCreators.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 Copyright 2017 New Vector Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/actions/handlers/viewUserDeviceSettings.ts b/src/actions/handlers/viewUserDeviceSettings.ts
index 56083dd4e88..d7cfe73d86c 100644
--- a/src/actions/handlers/viewUserDeviceSettings.ts
+++ b/src/actions/handlers/viewUserDeviceSettings.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/async-components/structures/ErrorView.tsx b/src/async-components/structures/ErrorView.tsx
index 5e60b8e67cb..cee6c6345bd 100644
--- a/src/async-components/structures/ErrorView.tsx
+++ b/src/async-components/structures/ErrorView.tsx
@@ -1,7 +1,7 @@
 /*
 Copyright 2020-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.tsx b/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.tsx
index 90b0ee29914..f84d6827843 100644
--- a/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.tsx
+++ b/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.tsx b/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.tsx
index 01b7e8227c9..a7405235490 100644
--- a/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.tsx
+++ b/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020, 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/async-components/views/dialogs/security/CreateKeyBackupDialog.tsx b/src/async-components/views/dialogs/security/CreateKeyBackupDialog.tsx
index 9608abc4bcd..30d04baec1d 100644
--- a/src/async-components/views/dialogs/security/CreateKeyBackupDialog.tsx
+++ b/src/async-components/views/dialogs/security/CreateKeyBackupDialog.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
 Copyright 2018, 2019 New Vector Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/async-components/views/dialogs/security/CreateSecretStorageDialog.tsx b/src/async-components/views/dialogs/security/CreateSecretStorageDialog.tsx
index 932f6d7fcf8..235f73fc8e6 100644
--- a/src/async-components/views/dialogs/security/CreateSecretStorageDialog.tsx
+++ b/src/async-components/views/dialogs/security/CreateSecretStorageDialog.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019, 2020 , 2023 The Matrix.org Foundation C.I.C.
 Copyright 2018, 2019 New Vector Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/async-components/views/dialogs/security/ExportE2eKeysDialog.tsx b/src/async-components/views/dialogs/security/ExportE2eKeysDialog.tsx
index 673ff5e3990..18dd507b5a5 100644
--- a/src/async-components/views/dialogs/security/ExportE2eKeysDialog.tsx
+++ b/src/async-components/views/dialogs/security/ExportE2eKeysDialog.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 Copyright 2017 Vector Creations Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/async-components/views/dialogs/security/ImportE2eKeysDialog.tsx b/src/async-components/views/dialogs/security/ImportE2eKeysDialog.tsx
index d08259f2cb5..16d50640f56 100644
--- a/src/async-components/views/dialogs/security/ImportE2eKeysDialog.tsx
+++ b/src/async-components/views/dialogs/security/ImportE2eKeysDialog.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 Copyright 2017 Vector Creations Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/async-components/views/dialogs/security/NewRecoveryMethodDialog.tsx b/src/async-components/views/dialogs/security/NewRecoveryMethodDialog.tsx
index 69fc4b4814b..bec708e6645 100644
--- a/src/async-components/views/dialogs/security/NewRecoveryMethodDialog.tsx
+++ b/src/async-components/views/dialogs/security/NewRecoveryMethodDialog.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 Copyright 2018, 2019 New Vector Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/async-components/views/dialogs/security/RecoveryMethodRemovedDialog.tsx b/src/async-components/views/dialogs/security/RecoveryMethodRemovedDialog.tsx
index b1a6ebafc79..7e82ff722b9 100644
--- a/src/async-components/views/dialogs/security/RecoveryMethodRemovedDialog.tsx
+++ b/src/async-components/views/dialogs/security/RecoveryMethodRemovedDialog.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 Copyright 2019 New Vector Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/audio/BackgroundAudio.ts b/src/audio/BackgroundAudio.ts
index 7bb6ebb5082..c90016eef91 100644
--- a/src/audio/BackgroundAudio.ts
+++ b/src/audio/BackgroundAudio.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/audio/ManagedPlayback.ts b/src/audio/ManagedPlayback.ts
index cab2142c28f..0f0b420d1ed 100644
--- a/src/audio/ManagedPlayback.ts
+++ b/src/audio/ManagedPlayback.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/audio/Playback.ts b/src/audio/Playback.ts
index f0155574cad..af777a8c011 100644
--- a/src/audio/Playback.ts
+++ b/src/audio/Playback.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/audio/PlaybackClock.ts b/src/audio/PlaybackClock.ts
index a0f1b3b5bbf..ceb06987c88 100644
--- a/src/audio/PlaybackClock.ts
+++ b/src/audio/PlaybackClock.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/audio/PlaybackManager.ts b/src/audio/PlaybackManager.ts
index d33b31ea7a9..80d28f11960 100644
--- a/src/audio/PlaybackManager.ts
+++ b/src/audio/PlaybackManager.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/audio/PlaybackQueue.ts b/src/audio/PlaybackQueue.ts
index bc3b3c692d6..f84f6add3cc 100644
--- a/src/audio/PlaybackQueue.ts
+++ b/src/audio/PlaybackQueue.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021, 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/audio/RecorderWorklet.ts b/src/audio/RecorderWorklet.ts
index 509dac09cb4..acf23f4dcd0 100644
--- a/src/audio/RecorderWorklet.ts
+++ b/src/audio/RecorderWorklet.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/audio/VoiceMessageRecording.ts b/src/audio/VoiceMessageRecording.ts
index 8824206b850..2dac4ac9c3c 100644
--- a/src/audio/VoiceMessageRecording.ts
+++ b/src/audio/VoiceMessageRecording.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/audio/VoiceRecording.ts b/src/audio/VoiceRecording.ts
index 692f731c2d7..0a48c27e06a 100644
--- a/src/audio/VoiceRecording.ts
+++ b/src/audio/VoiceRecording.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/audio/compat.ts b/src/audio/compat.ts
index bce98874aac..7af6ef68b23 100644
--- a/src/audio/compat.ts
+++ b/src/audio/compat.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/audio/consts.ts b/src/audio/consts.ts
index bf6405a035a..e8910fa8ed3 100644
--- a/src/audio/consts.ts
+++ b/src/audio/consts.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/audio/recorderWorkletFactory.ts b/src/audio/recorderWorkletFactory.ts
index 460f325957f..3290e118a4d 100644
--- a/src/audio/recorderWorkletFactory.ts
+++ b/src/audio/recorderWorkletFactory.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/autocomplete/AutocompleteProvider.tsx b/src/autocomplete/AutocompleteProvider.tsx
index 8c755cc950c..0161a64dce4 100644
--- a/src/autocomplete/AutocompleteProvider.tsx
+++ b/src/autocomplete/AutocompleteProvider.tsx
@@ -3,7 +3,7 @@ Copyright 2017-2024 New Vector Ltd.
 Copyright 2017 Vector Creations Ltd
 Copyright 2016 Aviral Dasgupta
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/autocomplete/Autocompleter.ts b/src/autocomplete/Autocompleter.ts
index b2a2b1e13e3..7ac11e95390 100644
--- a/src/autocomplete/Autocompleter.ts
+++ b/src/autocomplete/Autocompleter.ts
@@ -2,7 +2,7 @@
 Copyright 2017-2024 New Vector Ltd.
 Copyright 2016 Aviral Dasgupta
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/autocomplete/CommandProvider.tsx b/src/autocomplete/CommandProvider.tsx
index e5737751867..d2b9f18f152 100644
--- a/src/autocomplete/CommandProvider.tsx
+++ b/src/autocomplete/CommandProvider.tsx
@@ -5,7 +5,7 @@ Copyright 2017 Vector Creations Ltd
 Copyright 2017 New Vector Ltd
 Copyright 2016 Aviral Dasgupta
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/autocomplete/Components.tsx b/src/autocomplete/Components.tsx
index 0dcfd467e26..ebbc1732e2f 100644
--- a/src/autocomplete/Components.tsx
+++ b/src/autocomplete/Components.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2016 Aviral Dasgupta
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/autocomplete/EmojiProvider.tsx b/src/autocomplete/EmojiProvider.tsx
index f25b94f9981..f976fd37db2 100644
--- a/src/autocomplete/EmojiProvider.tsx
+++ b/src/autocomplete/EmojiProvider.tsx
@@ -6,7 +6,7 @@ Copyright 2017, 2018 New Vector Ltd
 Copyright 2017 Vector Creations Ltd
 Copyright 2016 Aviral Dasgupta
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/autocomplete/NotifProvider.tsx b/src/autocomplete/NotifProvider.tsx
index 0d9741276f9..49190455789 100644
--- a/src/autocomplete/NotifProvider.tsx
+++ b/src/autocomplete/NotifProvider.tsx
@@ -1,7 +1,7 @@
 /*
 Copyright 2017-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/autocomplete/QueryMatcher.ts b/src/autocomplete/QueryMatcher.ts
index 24266214231..985ca3a516d 100644
--- a/src/autocomplete/QueryMatcher.ts
+++ b/src/autocomplete/QueryMatcher.ts
@@ -4,7 +4,7 @@ Copyright 2018 Michael Telatynski <7t3chguy@gmail.com>
 Copyright 2018 New Vector Ltd
 Copyright 2017 Aviral Dasgupta
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/autocomplete/RoomProvider.tsx b/src/autocomplete/RoomProvider.tsx
index 94763486e85..84a4a8a0234 100644
--- a/src/autocomplete/RoomProvider.tsx
+++ b/src/autocomplete/RoomProvider.tsx
@@ -4,7 +4,7 @@ Copyright 2017-2023 The Matrix.org Foundation C.I.C.
 Copyright 2018 Michael Telatynski <7t3chguy@gmail.com>
 Copyright 2016 Aviral Dasgupta
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/autocomplete/SpaceProvider.tsx b/src/autocomplete/SpaceProvider.tsx
index 88bc9f3d123..273d9ace000 100644
--- a/src/autocomplete/SpaceProvider.tsx
+++ b/src/autocomplete/SpaceProvider.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/autocomplete/UserProvider.tsx b/src/autocomplete/UserProvider.tsx
index a8f50ceccbe..673bee7bf21 100644
--- a/src/autocomplete/UserProvider.tsx
+++ b/src/autocomplete/UserProvider.tsx
@@ -5,7 +5,7 @@ Copyright 2017, 2018 New Vector Ltd
 Copyright 2017 Vector Creations Ltd
 Copyright 2016 Aviral Dasgupta
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/boundThreepids.ts b/src/boundThreepids.ts
index 4417f3daafc..b7c749a0207 100644
--- a/src/boundThreepids.ts
+++ b/src/boundThreepids.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/call-types.ts b/src/call-types.ts
index 2384c85e5ec..2a263174efb 100644
--- a/src/call-types.ts
+++ b/src/call-types.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/AutoHideScrollbar.tsx b/src/components/structures/AutoHideScrollbar.tsx
index 549fbf4592b..764a712d442 100644
--- a/src/components/structures/AutoHideScrollbar.tsx
+++ b/src/components/structures/AutoHideScrollbar.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 Copyright 2018 New Vector Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/AutocompleteInput.tsx b/src/components/structures/AutocompleteInput.tsx
index 5e930d5f1b0..b25e93bc75d 100644
--- a/src/components/structures/AutocompleteInput.tsx
+++ b/src/components/structures/AutocompleteInput.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/BackdropPanel.tsx b/src/components/structures/BackdropPanel.tsx
index 32c75a936e3..64b2ab0fce8 100644
--- a/src/components/structures/BackdropPanel.tsx
+++ b/src/components/structures/BackdropPanel.tsx
@@ -1,7 +1,7 @@
 /*
 Copyright 2021-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/ContextMenu.tsx b/src/components/structures/ContextMenu.tsx
index 2c7a864db5d..3d0c1692670 100644
--- a/src/components/structures/ContextMenu.tsx
+++ b/src/components/structures/ContextMenu.tsx
@@ -4,7 +4,7 @@ Copyright 2019 The Matrix.org Foundation C.I.C.
 Copyright 2018 New Vector Ltd
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/EmbeddedPage.tsx b/src/components/structures/EmbeddedPage.tsx
index c471565d912..2833f796265 100644
--- a/src/components/structures/EmbeddedPage.tsx
+++ b/src/components/structures/EmbeddedPage.tsx
@@ -3,7 +3,7 @@ Copyright 2019-2024 New Vector Ltd.
 Copyright 2017 Vector Creations Ltd
 Copyright 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/ErrorMessage.tsx b/src/components/structures/ErrorMessage.tsx
index 58c523272b1..ce4788c0fa2 100644
--- a/src/components/structures/ErrorMessage.tsx
+++ b/src/components/structures/ErrorMessage.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/FileDropTarget.tsx b/src/components/structures/FileDropTarget.tsx
index 5bc16e2ee42..dcf4a2fdb11 100644
--- a/src/components/structures/FileDropTarget.tsx
+++ b/src/components/structures/FileDropTarget.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/FilePanel.tsx b/src/components/structures/FilePanel.tsx
index 4c580cb9fe3..32e5bbc5194 100644
--- a/src/components/structures/FilePanel.tsx
+++ b/src/components/structures/FilePanel.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019-2022 The Matrix.org Foundation C.I.C.
 Copyright 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/GenericDropdownMenu.tsx b/src/components/structures/GenericDropdownMenu.tsx
index b323d9b8ade..5c617e8015a 100644
--- a/src/components/structures/GenericDropdownMenu.tsx
+++ b/src/components/structures/GenericDropdownMenu.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/HomePage.tsx b/src/components/structures/HomePage.tsx
index 31deb381ddd..f8dcc7b70d8 100644
--- a/src/components/structures/HomePage.tsx
+++ b/src/components/structures/HomePage.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/IndicatorScrollbar.tsx b/src/components/structures/IndicatorScrollbar.tsx
index 2c1db504b1c..1d0a90a14e1 100644
--- a/src/components/structures/IndicatorScrollbar.tsx
+++ b/src/components/structures/IndicatorScrollbar.tsx
@@ -1,7 +1,7 @@
 /*
 Copyright 2018-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/InteractiveAuth.tsx b/src/components/structures/InteractiveAuth.tsx
index 4b0f0609524..08aa4eeafa8 100644
--- a/src/components/structures/InteractiveAuth.tsx
+++ b/src/components/structures/InteractiveAuth.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2017-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/LargeLoader.tsx b/src/components/structures/LargeLoader.tsx
index 4a83d58cac5..57f0f949e93 100644
--- a/src/components/structures/LargeLoader.tsx
+++ b/src/components/structures/LargeLoader.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/LeftPanel.tsx b/src/components/structures/LeftPanel.tsx
index 49d0f570a5c..92e612a477b 100644
--- a/src/components/structures/LeftPanel.tsx
+++ b/src/components/structures/LeftPanel.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -35,7 +35,6 @@ import { UIComponent } from "../../settings/UIFeature";
 import AccessibleButton, { ButtonEvent } from "../views/elements/AccessibleButton";
 import PosthogTrackers from "../../PosthogTrackers";
 import PageType from "../../PageTypes";
-import { UserOnboardingButton } from "../views/user-onboarding/UserOnboardingButton";
 import { Landmark, LandmarkNavigation } from "../../accessibility/LandmarkNavigation";
 
 interface IProps {
@@ -398,10 +397,6 @@ export default class LeftPanel extends React.Component<IProps, IState> {
                     {shouldShowComponent(UIComponent.FilterContainer) && this.renderSearchDialExplore()}
                     {this.renderBreadcrumbs()}
                     {!this.props.isMinimized && <RoomListHeader onVisibilityChange={this.refreshStickyHeaders} />}
-                    <UserOnboardingButton
-                        selected={this.props.pageType === PageType.HomePage}
-                        minimized={this.props.isMinimized}
-                    />
                     <nav className="mx_LeftPanel_roomListWrapper" aria-label={_t("common|rooms")}>
                         <div
                             className={roomListClasses}
diff --git a/src/components/structures/LegacyCallEventGrouper.ts b/src/components/structures/LegacyCallEventGrouper.ts
index 3eefbdbb871..96471589213 100644
--- a/src/components/structures/LegacyCallEventGrouper.ts
+++ b/src/components/structures/LegacyCallEventGrouper.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/LoggedInView.tsx b/src/components/structures/LoggedInView.tsx
index 019f9cd1a84..fa1cb17ebe7 100644
--- a/src/components/structures/LoggedInView.tsx
+++ b/src/components/structures/LoggedInView.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015-2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -16,6 +16,7 @@ import {
     IUsageLimit,
     SyncStateData,
     SyncState,
+    EventType,
 } from "matrix-js-sdk/src/matrix";
 import { MatrixCall } from "matrix-js-sdk/src/webrtc/call";
 import classNames from "classnames";
@@ -60,7 +61,7 @@ import { TimelineRenderingType } from "../../contexts/RoomContext";
 import { KeyBindingAction } from "../../accessibility/KeyboardShortcuts";
 import { SwitchSpacePayload } from "../../dispatcher/payloads/SwitchSpacePayload";
 import LeftPanelLiveShareWarning from "../views/beacon/LeftPanelLiveShareWarning";
-import { UserOnboardingPage } from "../views/user-onboarding/UserOnboardingPage";
+import HomePage from "./HomePage";
 import { PipContainer } from "./PipContainer";
 import { monitorSyncedPushRules } from "../../utils/pushRules/monitorSyncedPushRules";
 import { ConfigOptions } from "../../SdkConfig";
@@ -161,7 +162,7 @@ class LoggedInView extends React.Component<IProps, IState> {
 
         this._matrixClient.on(ClientEvent.AccountData, this.onAccountData);
         // check push rules on start up as well
-        monitorSyncedPushRules(this._matrixClient.getAccountData("m.push_rules"), this._matrixClient);
+        monitorSyncedPushRules(this._matrixClient.getAccountData(EventType.PushRules), this._matrixClient);
         this._matrixClient.on(ClientEvent.Sync, this.onSync);
         // Call `onSync` with the current state as well
         this.onSync(this._matrixClient.getSyncState(), null, this._matrixClient.getSyncStateData() ?? undefined);
@@ -245,7 +246,7 @@ class LoggedInView extends React.Component<IProps, IState> {
         } else {
             backgroundImage = OwnProfileStore.instance.getHttpAvatarUrl();
         }
-        this.setState({ backgroundImage });
+        this.setState({ backgroundImage: backgroundImage ?? undefined });
     };
 
     public canResetTimelineInRoom = (roomId: string): boolean => {
@@ -677,7 +678,7 @@ class LoggedInView extends React.Component<IProps, IState> {
                 break;
 
             case PageTypes.HomePage:
-                pageElement = <UserOnboardingPage justRegistered={this.props.justRegistered} />;
+                pageElement = <HomePage justRegistered={this.props.justRegistered} />;
                 break;
 
             case PageTypes.UserView:
diff --git a/src/components/structures/MainSplit.tsx b/src/components/structures/MainSplit.tsx
index 54aa2203549..540aec251f0 100644
--- a/src/components/structures/MainSplit.tsx
+++ b/src/components/structures/MainSplit.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 Copyright 2018 New Vector Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -99,7 +99,7 @@ export default class MainSplit extends React.Component<IProps> {
                 <Resizable
                     key={this.props.sizeKey}
                     defaultSize={this.loadSidePanelSize()}
-                    minWidth={264}
+                    minWidth={320}
                     maxWidth="50%"
                     enable={{
                         top: false,
diff --git a/src/components/structures/MatrixChat.tsx b/src/components/structures/MatrixChat.tsx
index ee120c430ae..9d3114c67cb 100644
--- a/src/components/structures/MatrixChat.tsx
+++ b/src/components/structures/MatrixChat.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015-2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -55,7 +55,6 @@ import { FontWatcher } from "../../settings/watchers/FontWatcher";
 import { storeRoomAliasInCache } from "../../RoomAliasCache";
 import ToastStore from "../../stores/ToastStore";
 import * as StorageManager from "../../utils/StorageManager";
-import { UseCase } from "../../settings/enums/UseCase";
 import type LoggedInViewType from "./LoggedInView";
 import LoggedInView from "./LoggedInView";
 import { Action } from "../../dispatcher/actions";
@@ -114,7 +113,6 @@ import { ShowThreadPayload } from "../../dispatcher/payloads/ShowThreadPayload";
 import { RightPanelPhases } from "../../stores/right-panel/RightPanelStorePhases";
 import RightPanelStore from "../../stores/right-panel/RightPanelStore";
 import { TimelineRenderingType } from "../../contexts/RoomContext";
-import { UseCaseSelection } from "../views/elements/UseCaseSelection";
 import { ValidatedServerConfig } from "../../utils/ValidatedServerConfig";
 import { isLocalRoom } from "../../utils/localRoom/isLocalRoom";
 import { SDKContext, SdkContextClass } from "../../contexts/SDKContext";
@@ -431,8 +429,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
             // if cross-signing is not yet set up, do so now if possible.
             InitialCryptoSetupStore.sharedInstance().startInitialCryptoSetup(
                 cli,
-                Boolean(this.tokenLogin),
-                this.stores,
                 this.onCompleteSecurityE2eSetupFinished,
             );
             this.setStateForNewView({ view: Views.E2E_SETUP });
@@ -504,8 +500,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
         UIStore.destroy();
         this.state.resizeNotifier.removeListener("middlePanelResized", this.dispatchTimelineResize);
         window.removeEventListener("resize", this.onWindowResized);
-
-        this.stores.accountPasswordStore.clearPassword();
     }
 
     private onWindowResized = (): void => {
@@ -870,8 +864,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
                     this.state.view !== Views.LOGIN &&
                     this.state.view !== Views.REGISTER &&
                     this.state.view !== Views.COMPLETE_SECURITY &&
-                    this.state.view !== Views.E2E_SETUP &&
-                    this.state.view !== Views.USE_CASE_SELECTION
+                    this.state.view !== Views.E2E_SETUP
                 ) {
                     this.onLoggedIn();
                 }
@@ -1363,12 +1356,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
         await this.onShowPostLoginScreen();
     }
 
-    private async onShowPostLoginScreen(useCase?: UseCase): Promise<void> {
-        if (useCase) {
-            PosthogAnalytics.instance.setProperty("ftueUseCaseSelection", useCase);
-            SettingsStore.setValue("FTUE.useCaseSelection", null, SettingLevel.ACCOUNT, useCase);
-        }
-
+    private async onShowPostLoginScreen(): Promise<void> {
         this.setStateForNewView({ view: Views.LOGGED_IN });
         // If a specific screen is set to be shown after login, show that above
         // all else, as it probably means the user clicked on something already.
@@ -1935,8 +1923,8 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
         this.showScreen("forgot_password");
     };
 
-    private onRegisterFlowComplete = (credentials: IMatrixClientCreds, password: string): Promise<void> => {
-        return this.onUserCompletedLoginFlow(credentials, password);
+    private onRegisterFlowComplete = (credentials: IMatrixClientCreds): Promise<void> => {
+        return this.onUserCompletedLoginFlow(credentials);
     };
 
     // returns a promise which resolves to the new MatrixClient
@@ -2003,9 +1991,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
      * Note: SSO users (and any others using token login) currently do not pass through
      * this, as they instead jump straight into the app after `attemptTokenLogin`.
      */
-    private onUserCompletedLoginFlow = async (credentials: IMatrixClientCreds, password: string): Promise<void> => {
-        this.stores.accountPasswordStore.setPassword(password);
-
+    private onUserCompletedLoginFlow = async (credentials: IMatrixClientCreds): Promise<void> => {
         // Create and start the client
         await Lifecycle.setLoggedIn(credentials);
         await this.postLoginSetup();
@@ -2016,33 +2002,10 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
 
     // complete security / e2e setup has finished
     private onCompleteSecurityE2eSetupFinished = (): void => {
-        if (MatrixClientPeg.currentUserIsJustRegistered() && SettingsStore.getValue("FTUE.useCaseSelection") === null) {
-            this.setStateForNewView({ view: Views.USE_CASE_SELECTION });
-
-            // Listen to changes in settings and hide the use case screen if appropriate - this is necessary because
-            // account settings can still be changing at this point in app init (due to the initial sync being cached,
-            // then subsequent syncs being received from the server)
-            //
-            // This seems unlikely for something that should happen directly after registration, but if a user does
-            // their initial login on another device/browser than they registered on, we want to avoid asking this
-            // question twice
-            //
-            // initPosthogAnalyticsToast pioneered this technique, we’re just reusing it here.
-            SettingsStore.watchSetting(
-                "FTUE.useCaseSelection",
-                null,
-                (originalSettingName, changedInRoomId, atLevel, newValueAtLevel, newValue) => {
-                    if (newValue !== null && this.state.view === Views.USE_CASE_SELECTION) {
-                        this.onShowPostLoginScreen();
-                    }
-                },
-            );
-        } else {
-            // This is async but we makign this function async to wait for it isn't useful
-            this.onShowPostLoginScreen().catch((e) => {
-                logger.error("Exception showing post-login screen", e);
-            });
-        }
+        // This is async but we making this function async to wait for it isn't useful
+        this.onShowPostLoginScreen().catch((e) => {
+            logger.error("Exception showing post-login screen", e);
+        });
     };
 
     private getFragmentAfterLogin(): string {
@@ -2162,8 +2125,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
                     fragmentAfterLogin={fragmentAfterLogin}
                 />
             );
-        } else if (this.state.view === Views.USE_CASE_SELECTION) {
-            view = <UseCaseSelection onFinished={(useCase): Promise<void> => this.onShowPostLoginScreen(useCase)} />;
         } else if (this.state.view === Views.LOCK_STOLEN) {
             view = <SessionLockStolenView />;
         } else {
diff --git a/src/components/structures/MatrixClientContextProvider.tsx b/src/components/structures/MatrixClientContextProvider.tsx
index 384a8fa8ac1..edd0daaaba8 100644
--- a/src/components/structures/MatrixClientContextProvider.tsx
+++ b/src/components/structures/MatrixClientContextProvider.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/MessagePanel.tsx b/src/components/structures/MessagePanel.tsx
index d2133f4f130..67c1b98d68b 100644
--- a/src/components/structures/MessagePanel.tsx
+++ b/src/components/structures/MessagePanel.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2016-2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/NonUrgentToastContainer.tsx b/src/components/structures/NonUrgentToastContainer.tsx
index d01bf789590..aa445a54982 100644
--- a/src/components/structures/NonUrgentToastContainer.tsx
+++ b/src/components/structures/NonUrgentToastContainer.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/NotificationPanel.tsx b/src/components/structures/NotificationPanel.tsx
index 236da25409b..af772f7ce28 100644
--- a/src/components/structures/NotificationPanel.tsx
+++ b/src/components/structures/NotificationPanel.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2016-2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/PictureInPictureDragger.tsx b/src/components/structures/PictureInPictureDragger.tsx
index fe8badd99d2..ffdf1fd7c88 100644
--- a/src/components/structures/PictureInPictureDragger.tsx
+++ b/src/components/structures/PictureInPictureDragger.tsx
@@ -1,7 +1,7 @@
 /*
 Copyright 2021-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/PipContainer.tsx b/src/components/structures/PipContainer.tsx
index c9fabfe0c9e..c68aa561d83 100644
--- a/src/components/structures/PipContainer.tsx
+++ b/src/components/structures/PipContainer.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2017-2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/ReleaseAnnouncement.tsx b/src/components/structures/ReleaseAnnouncement.tsx
index b8fc42d9158..cc21407c605 100644
--- a/src/components/structures/ReleaseAnnouncement.tsx
+++ b/src/components/structures/ReleaseAnnouncement.tsx
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2024 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/src/components/structures/RightPanel.tsx b/src/components/structures/RightPanel.tsx
index a1f20162430..b5cf0529b56 100644
--- a/src/components/structures/RightPanel.tsx
+++ b/src/components/structures/RightPanel.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2015-2022 The Matrix.org Foundation C.I.C.
 Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -17,7 +17,6 @@ import RightPanelStore from "../../stores/right-panel/RightPanelStore";
 import MatrixClientContext from "../../contexts/MatrixClientContext";
 import RoomSummaryCard from "../views/right_panel/RoomSummaryCard";
 import WidgetCard from "../views/right_panel/WidgetCard";
-import MemberList from "../views/rooms/MemberList";
 import UserInfo from "../views/right_panel/UserInfo";
 import ThirdPartyMemberInfo from "../views/rooms/ThirdPartyMemberInfo";
 import FilePanel from "./FilePanel";
@@ -34,6 +33,7 @@ import { IRightPanelCard, IRightPanelCardState } from "../../stores/right-panel/
 import { Action } from "../../dispatcher/actions";
 import { XOR } from "../../@types/common";
 import ExtensionsCard from "../views/right_panel/ExtensionsCard";
+import MemberListView from "../views/rooms/MemberList/MemberListView";
 
 interface BaseProps {
     overwriteCard?: IRightPanelCard; // used to display a custom card and ignoring the RightPanelStore (used for UserView)
@@ -57,7 +57,6 @@ type Props = XOR<RoomlessProps, RoomProps>;
 
 interface IState {
     phase?: RightPanelPhases;
-    searchQuery: string;
     cardState?: IRightPanelCardState;
 }
 
@@ -67,10 +66,6 @@ export default class RightPanel extends React.Component<Props, IState> {
 
     public constructor(props: Props, context: React.ContextType<typeof MatrixClientContext>) {
         super(props, context);
-
-        this.state = {
-            searchQuery: "",
-        };
     }
 
     private readonly delayedUpdate = throttle(
@@ -147,10 +142,6 @@ export default class RightPanel extends React.Component<Props, IState> {
         }
     };
 
-    private onSearchQueryChanged = (searchQuery: string): void => {
-        this.setState({ searchQuery });
-    };
-
     public render(): React.ReactNode {
         let card = <div />;
         const roomId = this.props.room?.roomId;
@@ -159,15 +150,7 @@ export default class RightPanel extends React.Component<Props, IState> {
         switch (phase) {
             case RightPanelPhases.MemberList:
                 if (!!roomId) {
-                    card = (
-                        <MemberList
-                            roomId={roomId}
-                            key={roomId}
-                            onClose={this.onClose}
-                            searchQuery={this.state.searchQuery}
-                            onSearchQueryChanged={this.onSearchQueryChanged}
-                        />
-                    );
+                    card = <MemberListView roomId={roomId} onClose={this.onClose} />;
                 }
                 break;
 
diff --git a/src/components/structures/RoomSearch.tsx b/src/components/structures/RoomSearch.tsx
index 35751ef35f1..1e36dc84dba 100644
--- a/src/components/structures/RoomSearch.tsx
+++ b/src/components/structures/RoomSearch.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020, 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/RoomSearchView.tsx b/src/components/structures/RoomSearchView.tsx
index 82146bcc5e0..ca67ca6bbf4 100644
--- a/src/components/structures/RoomSearchView.tsx
+++ b/src/components/structures/RoomSearchView.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015-2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/RoomStatusBar.tsx b/src/components/structures/RoomStatusBar.tsx
index 3bd69148aee..095c359566e 100644
--- a/src/components/structures/RoomStatusBar.tsx
+++ b/src/components/structures/RoomStatusBar.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/RoomStatusBarUnsentMessages.tsx b/src/components/structures/RoomStatusBarUnsentMessages.tsx
index ab356405b25..8cb80c894c0 100644
--- a/src/components/structures/RoomStatusBarUnsentMessages.tsx
+++ b/src/components/structures/RoomStatusBarUnsentMessages.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/RoomView.tsx b/src/components/structures/RoomView.tsx
index 772d5698a30..78d14d39dfb 100644
--- a/src/components/structures/RoomView.tsx
+++ b/src/components/structures/RoomView.tsx
@@ -5,7 +5,7 @@ Copyright 2018, 2019 New Vector Ltd
 Copyright 2017 Vector Creations Ltd
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/ScrollPanel.tsx b/src/components/structures/ScrollPanel.tsx
index b354f6b0055..413d081746c 100644
--- a/src/components/structures/ScrollPanel.tsx
+++ b/src/components/structures/ScrollPanel.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015-2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/SearchBox.tsx b/src/components/structures/SearchBox.tsx
index 323d3c855d0..a5bbb7865ea 100644
--- a/src/components/structures/SearchBox.tsx
+++ b/src/components/structures/SearchBox.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/SpaceHierarchy.tsx b/src/components/structures/SpaceHierarchy.tsx
index 80193fd3383..362fe82dce1 100644
--- a/src/components/structures/SpaceHierarchy.tsx
+++ b/src/components/structures/SpaceHierarchy.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021-2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/SpaceRoomView.tsx b/src/components/structures/SpaceRoomView.tsx
index bf0ddb1fe2a..1424df2c98a 100644
--- a/src/components/structures/SpaceRoomView.tsx
+++ b/src/components/structures/SpaceRoomView.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021, 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/SplashPage.tsx b/src/components/structures/SplashPage.tsx
index 6ca20fdb3cb..1ce0724dabe 100644
--- a/src/components/structures/SplashPage.tsx
+++ b/src/components/structures/SplashPage.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/TabbedView.tsx b/src/components/structures/TabbedView.tsx
index 7678dbf7845..71161fec525 100644
--- a/src/components/structures/TabbedView.tsx
+++ b/src/components/structures/TabbedView.tsx
@@ -4,7 +4,7 @@ Copyright 2019, 2020 , 2024 The Matrix.org Foundation C.I.C.
 Copyright 2019 New Vector Ltd
 Copyright 2017 Travis Ralston
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/ThreadPanel.tsx b/src/components/structures/ThreadPanel.tsx
index 0e82baa28b8..7aee8554b1d 100644
--- a/src/components/structures/ThreadPanel.tsx
+++ b/src/components/structures/ThreadPanel.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021-2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/ThreadView.tsx b/src/components/structures/ThreadView.tsx
index bc1e26d087a..0fa9b9fed68 100644
--- a/src/components/structures/ThreadView.tsx
+++ b/src/components/structures/ThreadView.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021-2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/TimelinePanel.tsx b/src/components/structures/TimelinePanel.tsx
index a28089c9895..31ce65cfa76 100644
--- a/src/components/structures/TimelinePanel.tsx
+++ b/src/components/structures/TimelinePanel.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2016-2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/ToastContainer.tsx b/src/components/structures/ToastContainer.tsx
index 3e5b4a4474b..02db99a0e05 100644
--- a/src/components/structures/ToastContainer.tsx
+++ b/src/components/structures/ToastContainer.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/UploadBar.tsx b/src/components/structures/UploadBar.tsx
index 01ecae96dce..76188627984 100644
--- a/src/components/structures/UploadBar.tsx
+++ b/src/components/structures/UploadBar.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015, 2016 , 2019, 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/UserMenu.tsx b/src/components/structures/UserMenu.tsx
index c5f8ef841d3..e2663523935 100644
--- a/src/components/structures/UserMenu.tsx
+++ b/src/components/structures/UserMenu.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020, 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/UserView.tsx b/src/components/structures/UserView.tsx
index ba905099ba5..7325f607ad8 100644
--- a/src/components/structures/UserView.tsx
+++ b/src/components/structures/UserView.tsx
@@ -2,7 +2,7 @@
 Copyright 2019-2024 New Vector Ltd.
 Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -17,7 +17,7 @@ import RightPanel from "./RightPanel";
 import Spinner from "../views/elements/Spinner";
 import ResizeNotifier from "../../utils/ResizeNotifier";
 import { RightPanelPhases } from "../../stores/right-panel/RightPanelStorePhases";
-import { UserOnboardingPage } from "../views/user-onboarding/UserOnboardingPage";
+import HomePage from "./HomePage.tsx";
 import MatrixClientContext from "../../contexts/MatrixClientContext";
 
 interface IProps {
@@ -93,7 +93,7 @@ export default class UserView extends React.Component<IProps, IState> {
                     defaultSize={420}
                     analyticsRoomType="user_profile"
                 >
-                    <UserOnboardingPage />
+                    <HomePage />
                 </MainSplit>
             );
         } else {
diff --git a/src/components/structures/ViewSource.tsx b/src/components/structures/ViewSource.tsx
index 3aba3be472f..eca37842d7f 100644
--- a/src/components/structures/ViewSource.tsx
+++ b/src/components/structures/ViewSource.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
 Copyright 2015, 2016 , 2019, 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/WaitingForThirdPartyRoomView.tsx b/src/components/structures/WaitingForThirdPartyRoomView.tsx
index cabe92a53d3..7787a03bf26 100644
--- a/src/components/structures/WaitingForThirdPartyRoomView.tsx
+++ b/src/components/structures/WaitingForThirdPartyRoomView.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/auth/CompleteSecurity.tsx b/src/components/structures/auth/CompleteSecurity.tsx
index ec65a62cefa..a0f2be88367 100644
--- a/src/components/structures/auth/CompleteSecurity.tsx
+++ b/src/components/structures/auth/CompleteSecurity.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/auth/ConfirmSessionLockTheftView.tsx b/src/components/structures/auth/ConfirmSessionLockTheftView.tsx
index 38d0d4efcc5..b71b627a5a6 100644
--- a/src/components/structures/auth/ConfirmSessionLockTheftView.tsx
+++ b/src/components/structures/auth/ConfirmSessionLockTheftView.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/auth/E2eSetup.tsx b/src/components/structures/auth/E2eSetup.tsx
index 3b064d61346..0fcacca66ac 100644
--- a/src/components/structures/auth/E2eSetup.tsx
+++ b/src/components/structures/auth/E2eSetup.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/auth/ForgotPassword.tsx b/src/components/structures/auth/ForgotPassword.tsx
index 0cc6fbd04d0..ecf888f6e9d 100644
--- a/src/components/structures/auth/ForgotPassword.tsx
+++ b/src/components/structures/auth/ForgotPassword.tsx
@@ -4,7 +4,7 @@ Copyright 2019 The Matrix.org Foundation C.I.C.
 Copyright 2017, 2018 , 2019 New Vector Ltd
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/auth/Login.tsx b/src/components/structures/auth/Login.tsx
index 0a14450e63a..b4b41f0515f 100644
--- a/src/components/structures/auth/Login.tsx
+++ b/src/components/structures/auth/Login.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -30,7 +30,6 @@ import AuthHeader from "../../views/auth/AuthHeader";
 import AccessibleButton, { ButtonEvent } from "../../views/elements/AccessibleButton";
 import { ValidatedServerConfig } from "../../../utils/ValidatedServerConfig";
 import { filterBoolean } from "../../../utils/arrays";
-import { Features } from "../../../settings/Settings";
 import { startOidcLogin } from "../../../utils/oidc/authorize";
 
 interface IProps {
@@ -48,10 +47,7 @@ interface IProps {
 
     // Called when the user has logged in. Params:
     // - The object returned by the login API
-    // - The user's password, if applicable, (may be cached in memory for a
-    //   short time so the user is not required to re-enter their password
-    //   for operations like uploading cross-signing keys).
-    onLoggedIn(data: IMatrixClientCreds, password: string): void;
+    onLoggedIn(data: IMatrixClientCreds): void;
 
     // login shouldn't know or care how registration, password recovery, etc is done.
     onRegisterClick(): void;
@@ -93,7 +89,6 @@ type OnPasswordLogin = {
  */
 export default class LoginComponent extends React.PureComponent<IProps, IState> {
     private unmounted = false;
-    private oidcNativeFlowEnabled = false;
     private loginLogic!: Login;
 
     private readonly stepRendererMap: Record<string, () => ReactNode>;
@@ -101,9 +96,6 @@ export default class LoginComponent extends React.PureComponent<IProps, IState>
     public constructor(props: IProps) {
         super(props);
 
-        // only set on a config level, so we don't need to watch
-        this.oidcNativeFlowEnabled = SettingsStore.getValue(Features.OidcNativeFlow);
-
         this.state = {
             busy: false,
             errorText: null,
@@ -199,7 +191,7 @@ export default class LoginComponent extends React.PureComponent<IProps, IState>
         this.loginLogic.loginViaPassword(username, phoneCountry, phoneNumber, password).then(
             (data) => {
                 this.setState({ serverIsAlive: true }); // it must be, we logged in.
-                this.props.onLoggedIn(data, password);
+                this.props.onLoggedIn(data);
             },
             (error) => {
                 if (this.unmounted) return;
@@ -361,10 +353,7 @@ export default class LoginComponent extends React.PureComponent<IProps, IState>
 
         const loginLogic = new Login(hsUrl, isUrl, fallbackHsUrl, {
             defaultDeviceDisplayName: this.props.defaultDeviceDisplayName,
-            // if native OIDC is enabled in the client pass the server's delegated auth settings
-            delegatedAuthentication: this.oidcNativeFlowEnabled
-                ? this.props.serverConfig.delegatedAuthentication
-                : undefined,
+            delegatedAuthentication: this.props.serverConfig.delegatedAuthentication,
         });
         this.loginLogic = loginLogic;
 
diff --git a/src/components/structures/auth/LoginSplashView.tsx b/src/components/structures/auth/LoginSplashView.tsx
index a75cc142618..3d68a12e8d4 100644
--- a/src/components/structures/auth/LoginSplashView.tsx
+++ b/src/components/structures/auth/LoginSplashView.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015-2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/auth/Registration.tsx b/src/components/structures/auth/Registration.tsx
index 0ae5c933460..1dc6f57bc71 100644
--- a/src/components/structures/auth/Registration.tsx
+++ b/src/components/structures/auth/Registration.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -44,7 +44,6 @@ import { AuthHeaderDisplay } from "./header/AuthHeaderDisplay";
 import { AuthHeaderProvider } from "./header/AuthHeaderProvider";
 import SettingsStore from "../../../settings/SettingsStore";
 import { ValidatedServerConfig } from "../../../utils/ValidatedServerConfig";
-import { Features } from "../../../settings/Settings";
 import { startOidcLogin } from "../../../utils/oidc/authorize";
 
 const debuglog = (...args: any[]): void => {
@@ -72,10 +71,7 @@ interface IProps {
     mobileRegister?: boolean;
     // Called when the user has logged in. Params:
     // - object with userId, deviceId, homeserverUrl, identityServerUrl, accessToken
-    // - The user's password, if available and applicable (may be cached in memory
-    //   for a short time so the user is not required to re-enter their password
-    //   for operations like uploading cross-signing keys).
-    onLoggedIn(params: IMatrixClientCreds, password: string): Promise<void>;
+    onLoggedIn(params: IMatrixClientCreds): Promise<void>;
     // registration shouldn't know or care how login is done.
     onLoginClick(): void;
     onServerConfigChange(config: ValidatedServerConfig): void;
@@ -133,8 +129,6 @@ export default class Registration extends React.Component<IProps, IState> {
     private readonly loginLogic: Login;
     // `replaceClient` tracks latest serverConfig to spot when it changes under the async method which fetches flows
     private latestServerConfig?: ValidatedServerConfig;
-    // cache value from settings store
-    private oidcNativeFlowEnabled = false;
 
     public constructor(props: IProps) {
         super(props);
@@ -153,14 +147,10 @@ export default class Registration extends React.Component<IProps, IState> {
             serverDeadError: "",
         };
 
-        // only set on a config level, so we don't need to watch
-        this.oidcNativeFlowEnabled = SettingsStore.getValue(Features.OidcNativeFlow);
-
         const { hsUrl, isUrl, delegatedAuthentication } = this.props.serverConfig;
         this.loginLogic = new Login(hsUrl, isUrl, null, {
             defaultDeviceDisplayName: "Element login check", // We shouldn't ever be used
-            // if native OIDC is enabled in the client pass the server's delegated auth settings
-            delegatedAuthentication: this.oidcNativeFlowEnabled ? delegatedAuthentication : undefined,
+            delegatedAuthentication,
         });
     }
 
@@ -230,10 +220,7 @@ export default class Registration extends React.Component<IProps, IState> {
 
         this.loginLogic.setHomeserverUrl(hsUrl);
         this.loginLogic.setIdentityServerUrl(isUrl);
-        // if native OIDC is enabled in the client pass the server's delegated auth settings
-        const delegatedAuthentication = this.oidcNativeFlowEnabled ? serverConfig.delegatedAuthentication : undefined;
-
-        this.loginLogic.setDelegatedAuthentication(delegatedAuthentication);
+        this.loginLogic.setDelegatedAuthentication(serverConfig.delegatedAuthentication);
 
         let ssoFlow: SSOFlow | undefined;
         let oidcNativeFlow: OidcNativeFlow | undefined;
@@ -431,16 +418,13 @@ export default class Registration extends React.Component<IProps, IState> {
                 newState.busy = false;
                 newState.completedNoSignin = true;
             } else {
-                await this.props.onLoggedIn(
-                    {
-                        userId,
-                        deviceId: (response as RegisterResponse).device_id!,
-                        homeserverUrl: this.state.matrixClient.getHomeserverUrl(),
-                        identityServerUrl: this.state.matrixClient.getIdentityServerUrl(),
-                        accessToken,
-                    },
-                    this.state.formVals.password!,
-                );
+                await this.props.onLoggedIn({
+                    userId,
+                    deviceId: (response as RegisterResponse).device_id!,
+                    homeserverUrl: this.state.matrixClient.getHomeserverUrl(),
+                    identityServerUrl: this.state.matrixClient.getIdentityServerUrl(),
+                    accessToken,
+                });
 
                 this.setupPushers();
             }
diff --git a/src/components/structures/auth/SessionLockStolenView.tsx b/src/components/structures/auth/SessionLockStolenView.tsx
index edb20188a61..01193440fc0 100644
--- a/src/components/structures/auth/SessionLockStolenView.tsx
+++ b/src/components/structures/auth/SessionLockStolenView.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/auth/SetupEncryptionBody.tsx b/src/components/structures/auth/SetupEncryptionBody.tsx
index 32528fc7e39..1ff0ad41207 100644
--- a/src/components/structures/auth/SetupEncryptionBody.tsx
+++ b/src/components/structures/auth/SetupEncryptionBody.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020, 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/auth/SoftLogout.tsx b/src/components/structures/auth/SoftLogout.tsx
index 9c7a900643e..696edc0ad2e 100644
--- a/src/components/structures/auth/SoftLogout.tsx
+++ b/src/components/structures/auth/SoftLogout.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/auth/forgot-password/CheckEmail.tsx b/src/components/structures/auth/forgot-password/CheckEmail.tsx
index dbc667c07ee..428bc170269 100644
--- a/src/components/structures/auth/forgot-password/CheckEmail.tsx
+++ b/src/components/structures/auth/forgot-password/CheckEmail.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/auth/forgot-password/EnterEmail.tsx b/src/components/structures/auth/forgot-password/EnterEmail.tsx
index 98af5aef47a..d50040552da 100644
--- a/src/components/structures/auth/forgot-password/EnterEmail.tsx
+++ b/src/components/structures/auth/forgot-password/EnterEmail.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/auth/forgot-password/VerifyEmailModal.tsx b/src/components/structures/auth/forgot-password/VerifyEmailModal.tsx
index 24caa2b13dc..cb2c5b3b850 100644
--- a/src/components/structures/auth/forgot-password/VerifyEmailModal.tsx
+++ b/src/components/structures/auth/forgot-password/VerifyEmailModal.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/auth/header/AuthHeaderContext.tsx b/src/components/structures/auth/header/AuthHeaderContext.tsx
index 97d587f40bd..4c9d436f0c2 100644
--- a/src/components/structures/auth/header/AuthHeaderContext.tsx
+++ b/src/components/structures/auth/header/AuthHeaderContext.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/auth/header/AuthHeaderDisplay.tsx b/src/components/structures/auth/header/AuthHeaderDisplay.tsx
index 479e982c9b8..f1289a1c999 100644
--- a/src/components/structures/auth/header/AuthHeaderDisplay.tsx
+++ b/src/components/structures/auth/header/AuthHeaderDisplay.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/auth/header/AuthHeaderModifier.tsx b/src/components/structures/auth/header/AuthHeaderModifier.tsx
index 05313cda3c8..d3b3d648e7f 100644
--- a/src/components/structures/auth/header/AuthHeaderModifier.tsx
+++ b/src/components/structures/auth/header/AuthHeaderModifier.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/auth/header/AuthHeaderProvider.tsx b/src/components/structures/auth/header/AuthHeaderProvider.tsx
index 0bf50282748..0189b692124 100644
--- a/src/components/structures/auth/header/AuthHeaderProvider.tsx
+++ b/src/components/structures/auth/header/AuthHeaderProvider.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/grouper/BaseGrouper.ts b/src/components/structures/grouper/BaseGrouper.ts
index fd8e3a59e2b..a685582a2c7 100644
--- a/src/components/structures/grouper/BaseGrouper.ts
+++ b/src/components/structures/grouper/BaseGrouper.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/grouper/CreationGrouper.tsx b/src/components/structures/grouper/CreationGrouper.tsx
index 84982066c36..5009b14baff 100644
--- a/src/components/structures/grouper/CreationGrouper.tsx
+++ b/src/components/structures/grouper/CreationGrouper.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/grouper/LateEventGrouper.ts b/src/components/structures/grouper/LateEventGrouper.ts
index a248d13143f..87cf6549b2e 100644
--- a/src/components/structures/grouper/LateEventGrouper.ts
+++ b/src/components/structures/grouper/LateEventGrouper.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/grouper/MainGrouper.tsx b/src/components/structures/grouper/MainGrouper.tsx
index 72fd3fcdf04..84d0be26742 100644
--- a/src/components/structures/grouper/MainGrouper.tsx
+++ b/src/components/structures/grouper/MainGrouper.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/structures/static-page-vars.ts b/src/components/structures/static-page-vars.ts
index aaabfafa6dd..e27a449546f 100644
--- a/src/components/structures/static-page-vars.ts
+++ b/src/components/structures/static-page-vars.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/utils/Box.tsx b/src/components/utils/Box.tsx
index b48b13aa0fb..c81c9bafed2 100644
--- a/src/components/utils/Box.tsx
+++ b/src/components/utils/Box.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/utils/Flex.tsx b/src/components/utils/Flex.tsx
index 852ebb7e40b..ae5704d2479 100644
--- a/src/components/utils/Flex.tsx
+++ b/src/components/utils/Flex.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/viewmodels/memberlist/MemberListViewModel.tsx b/src/components/viewmodels/memberlist/MemberListViewModel.tsx
new file mode 100644
index 00000000000..4a1a2d59f19
--- /dev/null
+++ b/src/components/viewmodels/memberlist/MemberListViewModel.tsx
@@ -0,0 +1,263 @@
+/*
+Copyright 2024 New Vector Ltd.
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+Please see LICENSE files in the repository root for full details.
+*/
+
+import {
+    ClientEvent,
+    EventType,
+    MatrixEvent,
+    Room,
+    RoomEvent,
+    RoomMemberEvent,
+    RoomState,
+    RoomStateEvent,
+    RoomMember as SdkRoomMember,
+    User,
+    UserEvent,
+} from "matrix-js-sdk/src/matrix";
+import { KnownMembership } from "matrix-js-sdk/src/types";
+import { useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
+import { throttle } from "lodash";
+
+import { RoomMember } from "../../../models/rooms/RoomMember";
+import { mediaFromMxc } from "../../../customisations/Media";
+import UserIdentifierCustomisations from "../../../customisations/UserIdentifier";
+import { shouldShowComponent } from "../../../customisations/helpers/UIComponents";
+import { UIComponent } from "../../../settings/UIFeature";
+import { PresenceState } from "../../../models/rooms/PresenceState";
+import { useMatrixClientContext } from "../../../contexts/MatrixClientContext";
+import { SDKContext } from "../../../contexts/SDKContext";
+import PosthogTrackers from "../../../PosthogTrackers";
+import { ButtonEvent } from "../../views/elements/AccessibleButton";
+import { inviteToRoom } from "../../../utils/room/inviteToRoom";
+import { canInviteTo } from "../../../utils/room/canInviteTo";
+import { isValid3pidInvite } from "../../../RoomInvite";
+import { ThreePIDInvite } from "../../../models/rooms/ThreePIDInvite";
+import { XOR } from "../../../@types/common";
+import { useTypedEventEmitter } from "../../../hooks/useEventEmitter";
+
+type Member = XOR<{ member: RoomMember }, { threePidInvite: ThreePIDInvite }>;
+
+export function getPending3PidInvites(room: Room, searchQuery?: string): Member[] {
+    // include 3pid invites (m.room.third_party_invite) state events.
+    // The HS may have already converted these into m.room.member invites so
+    // we shouldn't add them if the 3pid invite state key (token) is in the
+    // member invite (content.third_party_invite.signed.token)
+    const inviteEvents = room.currentState.getStateEvents("m.room.third_party_invite").filter(function (e) {
+        if (!isValid3pidInvite(e)) return false;
+        if (searchQuery && !(e.getContent().display_name as string)?.includes(searchQuery)) return false;
+
+        // discard all invites which have a m.room.member event since we've
+        // already added them.
+        const memberEvent = room.currentState.getInviteForThreePidToken(e.getStateKey()!);
+        if (memberEvent) return false;
+        return true;
+    });
+    const invites: Member[] = inviteEvents.map((e) => {
+        return {
+            threePidInvite: {
+                event: e,
+            },
+        };
+    });
+    return invites;
+}
+
+export function sdkRoomMemberToRoomMember(member: SdkRoomMember): Member {
+    const displayUserId =
+        UserIdentifierCustomisations.getDisplayUserIdentifier(member.userId, {
+            roomId: member.roomId,
+        }) ?? member.userId;
+
+    const mxcAvatarURL = member.getMxcAvatarUrl();
+    const avatarThumbnailUrl =
+        (mxcAvatarURL && mediaFromMxc(mxcAvatarURL).getThumbnailOfSourceHttp(96, 96, "crop")) ?? undefined;
+
+    const user = member.user;
+    let presenceState: PresenceState | undefined;
+    if (user) {
+        presenceState = (user.presence as PresenceState) || undefined;
+    }
+
+    return {
+        member: {
+            roomId: member.roomId,
+            userId: member.userId,
+            displayUserId: displayUserId,
+            name: member.name,
+            rawDisplayName: member.rawDisplayName,
+            disambiguate: member.disambiguate,
+            avatarThumbnailUrl: avatarThumbnailUrl,
+            powerLevel: member.powerLevel,
+            lastModifiedTime: member.getLastModifiedTime(),
+            presenceState,
+            isInvite: member.membership === KnownMembership.Invite,
+        },
+    };
+}
+
+export interface MemberListViewState {
+    members: Member[];
+    search: (searchQuery: string) => void;
+    isPresenceEnabled: boolean;
+    shouldShowInvite: boolean;
+    shouldShowSearch: boolean;
+    isLoading: boolean;
+    canInvite: boolean;
+    onInviteButtonClick: (ev: ButtonEvent) => void;
+}
+export function useMemberListViewModel(roomId: string): MemberListViewState {
+    const cli = useMatrixClientContext();
+
+    const room = useMemo(() => cli.getRoom(roomId), [roomId, cli]);
+    if (!room) {
+        throw new Error(`Room with id ${roomId} does not exist!`);
+    }
+
+    const sdkContext = useContext(SDKContext);
+    const [memberMap, setMemberMap] = useState<Map<string, Member>>(new Map());
+    const [isLoading, setIsLoading] = useState<boolean>(true);
+
+    // This is the last known total number of members in this room.
+    const totalMemberCount = useRef<number>(0);
+
+    const searchQuery = useRef("");
+
+    const loadMembers = useMemo(
+        () =>
+            throttle(
+                async (): Promise<void> => {
+                    const { joined: joinedSdk, invited: invitedSdk } = await sdkContext.memberListStore.loadMemberList(
+                        roomId,
+                        searchQuery.current,
+                    );
+                    const newMemberMap = new Map<string, Member>();
+                    // First add the invited room members
+                    for (const member of invitedSdk) {
+                        const roomMember = sdkRoomMemberToRoomMember(member);
+                        newMemberMap.set(member.userId, roomMember);
+                    }
+                    // Then add the third party invites
+                    const threePidInvited = getPending3PidInvites(room, searchQuery.current);
+                    for (const invited of threePidInvited) {
+                        const key = invited.threePidInvite!.event.getContent().display_name;
+                        newMemberMap.set(key, invited);
+                    }
+                    // Finally add the joined room members
+                    for (const member of joinedSdk) {
+                        const roomMember = sdkRoomMemberToRoomMember(member);
+                        newMemberMap.set(member.userId, roomMember);
+                    }
+                    setMemberMap(newMemberMap);
+                    if (!searchQuery.current) {
+                        /**
+                         * Since searching for members only gives you the relevant
+                         * members matching the query, do not update the totalMemberCount!
+                         **/
+                        totalMemberCount.current = newMemberMap.size;
+                    }
+                },
+                500,
+                { leading: true, trailing: true },
+            ),
+        [roomId, sdkContext.memberListStore, room],
+    );
+
+    const search = useCallback(
+        (query: string) => {
+            searchQuery.current = query;
+            loadMembers();
+        },
+        [loadMembers],
+    );
+
+    const isPresenceEnabled = useMemo(
+        () => sdkContext.memberListStore.isPresenceEnabled(),
+        [sdkContext.memberListStore],
+    );
+
+    // Determines whether the rendered invite button is enabled or disabled
+    const getCanUserInviteToThisRoom = useCallback((): boolean => !!room && canInviteTo(room), [room]);
+    const [canInvite, setCanInvite] = useState<boolean>(getCanUserInviteToThisRoom());
+
+    // Determines whether the invite button should be shown or not.
+    const getShouldShowInvite = useCallback(
+        (): boolean => room?.getMyMembership() === KnownMembership.Join && shouldShowComponent(UIComponent.InviteUsers),
+        [room],
+    );
+    const [shouldShowInvite, setShouldShowInvite] = useState<boolean>(getShouldShowInvite());
+
+    const onInviteButtonClick = (ev: ButtonEvent): void => {
+        PosthogTrackers.trackInteraction("WebRightPanelMemberListInviteButton", ev);
+        ev.preventDefault();
+        inviteToRoom(room);
+    };
+
+    useTypedEventEmitter(cli, RoomStateEvent.Events, (event: MatrixEvent) => {
+        if (event.getRoomId() === roomId && event.getType() === EventType.RoomThirdPartyInvite) {
+            loadMembers();
+            const newCanInvite = getCanUserInviteToThisRoom();
+            setCanInvite(newCanInvite);
+        }
+    });
+
+    useTypedEventEmitter(cli, RoomStateEvent.Update, (state: RoomState) => {
+        if (state.roomId === roomId) loadMembers();
+    });
+
+    useTypedEventEmitter(cli, RoomMemberEvent.Name, (_: MatrixEvent, member: SdkRoomMember) => {
+        if (member.roomId === roomId) loadMembers();
+    });
+
+    useTypedEventEmitter(cli, ClientEvent.Room, (room: Room) => {
+        // We listen for room events because when we accept an invite
+        // we need to wait till the room is fully populated with state
+        // before refreshing the member list else we get a stale list.
+        if (room.roomId === roomId) loadMembers();
+    });
+
+    useTypedEventEmitter(cli, RoomEvent.MyMembership, (room: Room, membership: string, oldMembership?: string) => {
+        if (room.roomId !== roomId) return;
+        if (membership === KnownMembership.Join && oldMembership !== KnownMembership.Join) {
+            // we just joined the room, load the member list
+            loadMembers();
+            const newShouldShowInvite = getShouldShowInvite();
+            setShouldShowInvite(newShouldShowInvite);
+        }
+    });
+
+    useTypedEventEmitter(cli, UserEvent.Presence, (_: MatrixEvent | undefined, user: User) => {
+        if (memberMap.has(user.userId)) loadMembers();
+    });
+
+    useTypedEventEmitter(cli, UserEvent.CurrentlyActive, (_: MatrixEvent | undefined, user: User) => {
+        if (memberMap.has(user.userId)) loadMembers();
+    });
+
+    // Initial load of the memberlist
+    useEffect(() => {
+        (async () => {
+            await loadMembers();
+            /**
+             * isLoading is used to render a spinner on initial call.
+             * Further calls need not mutate this state since it's perfectly fine to
+             * show the existing memberlist until the new one loads.
+             */
+            setIsLoading(false);
+        })();
+    }, [loadMembers]);
+
+    return {
+        members: Array.from(memberMap.values()),
+        search,
+        shouldShowInvite,
+        isPresenceEnabled,
+        isLoading,
+        onInviteButtonClick,
+        shouldShowSearch: totalMemberCount.current >= 20,
+        canInvite,
+    };
+}
diff --git a/src/components/viewmodels/memberlist/tiles/MemberTileViewModel.tsx b/src/components/viewmodels/memberlist/tiles/MemberTileViewModel.tsx
new file mode 100644
index 00000000000..367064e3ffd
--- /dev/null
+++ b/src/components/viewmodels/memberlist/tiles/MemberTileViewModel.tsx
@@ -0,0 +1,160 @@
+/*
+Copyright 2024 New Vector Ltd.
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+Please see LICENSE files in the repository root for full details.
+*/
+
+import { useEffect, useMemo, useState } from "react";
+import { RoomStateEvent, MatrixEvent, EventType } from "matrix-js-sdk/src/matrix";
+import { UserVerificationStatus, CryptoEvent } from "matrix-js-sdk/src/crypto-api";
+
+import dis from "../../../../dispatcher/dispatcher";
+import { MatrixClientPeg } from "../../../../MatrixClientPeg";
+import { Action } from "../../../../dispatcher/actions";
+import { asyncSome } from "../../../../utils/arrays";
+import { getUserDeviceIds } from "../../../../utils/crypto/deviceInfo";
+import { RoomMember } from "../../../../models/rooms/RoomMember";
+import { _t, _td, TranslationKey } from "../../../../languageHandler";
+import UserIdentifierCustomisations from "../../../../customisations/UserIdentifier";
+import { E2EStatus } from "../../../../utils/ShieldUtils";
+
+interface MemberTileViewModelProps {
+    member: RoomMember;
+    showPresence?: boolean;
+}
+
+export interface MemberTileViewState extends MemberTileViewModelProps {
+    e2eStatus?: E2EStatus;
+    name: string;
+    onClick: () => void;
+    title?: string;
+    userLabel?: string;
+}
+
+export enum PowerStatus {
+    Admin = "admin",
+    Moderator = "moderator",
+}
+
+const PowerLabel: Record<PowerStatus, TranslationKey> = {
+    [PowerStatus.Admin]: _td("power_level|admin"),
+    [PowerStatus.Moderator]: _td("power_level|moderator"),
+};
+
+export function useMemberTileViewModel(props: MemberTileViewModelProps): MemberTileViewState {
+    const [e2eStatus, setE2eStatus] = useState<E2EStatus | undefined>();
+
+    useEffect(() => {
+        const cli = MatrixClientPeg.safeGet();
+
+        const updateE2EStatus = async (): Promise<void> => {
+            const { userId } = props.member;
+            const isMe = userId === cli.getUserId();
+            const userTrust = await cli.getCrypto()?.getUserVerificationStatus(userId);
+            if (!userTrust?.isCrossSigningVerified()) {
+                setE2eStatus(userTrust?.wasCrossSigningVerified() ? E2EStatus.Warning : E2EStatus.Normal);
+                return;
+            }
+
+            const deviceIDs = await getUserDeviceIds(cli, userId);
+            const anyDeviceUnverified = await asyncSome(deviceIDs, async (deviceId) => {
+                // For your own devices, we use the stricter check of cross-signing
+                // verification to encourage everyone to trust their own devices via
+                // cross-signing so that other users can then safely trust you.
+                // For other people's devices, the more general verified check that
+                // includes locally verified devices can be used.
+                const deviceTrust = await cli.getCrypto()?.getDeviceVerificationStatus(userId, deviceId);
+                return !deviceTrust || (isMe ? !deviceTrust.crossSigningVerified : !deviceTrust.isVerified());
+            });
+            setE2eStatus(anyDeviceUnverified ? E2EStatus.Warning : E2EStatus.Verified);
+        };
+
+        const onRoomStateEvents = (ev: MatrixEvent): void => {
+            if (ev.getType() !== EventType.RoomEncryption) return;
+            const { roomId } = props.member;
+            if (ev.getRoomId() !== roomId) return;
+
+            // The room is encrypted now.
+            cli.removeListener(RoomStateEvent.Events, onRoomStateEvents);
+            updateE2EStatus();
+        };
+
+        const onUserTrustStatusChanged = (userId: string, trustStatus: UserVerificationStatus): void => {
+            if (userId !== props.member.userId) return;
+            updateE2EStatus();
+        };
+
+        const { roomId } = props.member;
+        if (roomId) {
+            const isRoomEncrypted = cli.isRoomEncrypted(roomId);
+            if (isRoomEncrypted) {
+                cli.on(CryptoEvent.UserTrustStatusChanged, onUserTrustStatusChanged);
+                updateE2EStatus();
+            } else {
+                // Listen for room to become encrypted
+                cli.on(RoomStateEvent.Events, onRoomStateEvents);
+            }
+        }
+
+        return () => {
+            if (cli) {
+                cli.removeListener(RoomStateEvent.Events, onRoomStateEvents);
+                cli.removeListener(CryptoEvent.UserTrustStatusChanged, onUserTrustStatusChanged);
+            }
+        };
+    }, [props.member]);
+
+    const onClick = (): void => {
+        dis.dispatch({
+            action: Action.ViewUser,
+            member: props.member,
+            push: true,
+        });
+    };
+
+    const member = props.member;
+    const name = props.member.name;
+
+    const powerStatusMap = new Map([
+        [100, PowerStatus.Admin],
+        [50, PowerStatus.Moderator],
+    ]);
+
+    // Find the nearest power level with a badge
+    let powerLevel = props.member.powerLevel;
+    for (const [pl] of powerStatusMap) {
+        if (props.member.powerLevel >= pl) {
+            powerLevel = pl;
+            break;
+        }
+    }
+
+    const title = useMemo(() => {
+        return _t("member_list|power_label", {
+            userName: UserIdentifierCustomisations.getDisplayUserIdentifier(member.userId, {
+                roomId: member.roomId,
+            }),
+            powerLevelNumber: member.powerLevel,
+        }).trim();
+    }, [member.powerLevel, member.roomId, member.userId]);
+
+    let userLabel;
+    const powerStatus = powerStatusMap.get(powerLevel);
+    if (powerStatus) {
+        userLabel = _t(PowerLabel[powerStatus]);
+    }
+    if (props.member.isInvite) {
+        userLabel = `(${_t("member_list|invited_label")})`;
+    }
+
+    return {
+        title,
+        member,
+        name,
+        onClick,
+        e2eStatus,
+        showPresence: props.showPresence,
+        userLabel,
+    };
+}
diff --git a/src/components/viewmodels/memberlist/tiles/ThreePidTileViewModel.tsx b/src/components/viewmodels/memberlist/tiles/ThreePidTileViewModel.tsx
new file mode 100644
index 00000000000..daeb8d899f4
--- /dev/null
+++ b/src/components/viewmodels/memberlist/tiles/ThreePidTileViewModel.tsx
@@ -0,0 +1,35 @@
+/*
+Copyright 2024 New Vector Ltd.
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+Please see LICENSE files in the repository root for full details.
+*/
+
+import dis from "../../../../dispatcher/dispatcher";
+import { Action } from "../../../../dispatcher/actions";
+import { ThreePIDInvite } from "../../../../models/rooms/ThreePIDInvite";
+
+interface ThreePidTileViewModelProps {
+    threePidInvite: ThreePIDInvite;
+}
+
+export interface ThreePidTileViewState {
+    name: string;
+    onClick: () => void;
+}
+
+export function useThreePidTileViewModel(props: ThreePidTileViewModelProps): ThreePidTileViewState {
+    const invite = props.threePidInvite;
+    const name = invite.event.getContent().display_name;
+    const onClick = (): void => {
+        dis.dispatch({
+            action: Action.View3pidInvite,
+            event: invite.event,
+        });
+    };
+
+    return {
+        name,
+        onClick,
+    };
+}
diff --git a/src/components/views/audio_messages/AudioPlayer.tsx b/src/components/views/audio_messages/AudioPlayer.tsx
index 885b1ecb805..63c77108e37 100644
--- a/src/components/views/audio_messages/AudioPlayer.tsx
+++ b/src/components/views/audio_messages/AudioPlayer.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021-2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/audio_messages/AudioPlayerBase.tsx b/src/components/views/audio_messages/AudioPlayerBase.tsx
index 601611e4223..97cbad0fc2e 100644
--- a/src/components/views/audio_messages/AudioPlayerBase.tsx
+++ b/src/components/views/audio_messages/AudioPlayerBase.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021, 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/audio_messages/Clock.tsx b/src/components/views/audio_messages/Clock.tsx
index ca72d29a057..c8f27c3f9ca 100644
--- a/src/components/views/audio_messages/Clock.tsx
+++ b/src/components/views/audio_messages/Clock.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021-2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/audio_messages/DurationClock.tsx b/src/components/views/audio_messages/DurationClock.tsx
index 3794ab9a4f0..1a84a159553 100644
--- a/src/components/views/audio_messages/DurationClock.tsx
+++ b/src/components/views/audio_messages/DurationClock.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/audio_messages/LiveRecordingClock.tsx b/src/components/views/audio_messages/LiveRecordingClock.tsx
index 9569e9c11a7..bd8b8d5d235 100644
--- a/src/components/views/audio_messages/LiveRecordingClock.tsx
+++ b/src/components/views/audio_messages/LiveRecordingClock.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/audio_messages/LiveRecordingWaveform.tsx b/src/components/views/audio_messages/LiveRecordingWaveform.tsx
index 6fdb7230158..18c1ca1aa25 100644
--- a/src/components/views/audio_messages/LiveRecordingWaveform.tsx
+++ b/src/components/views/audio_messages/LiveRecordingWaveform.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/audio_messages/PlayPauseButton.tsx b/src/components/views/audio_messages/PlayPauseButton.tsx
index 1cd2d168b4a..1b197c6bad7 100644
--- a/src/components/views/audio_messages/PlayPauseButton.tsx
+++ b/src/components/views/audio_messages/PlayPauseButton.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/audio_messages/PlaybackClock.tsx b/src/components/views/audio_messages/PlaybackClock.tsx
index b3d736758be..999b5398b15 100644
--- a/src/components/views/audio_messages/PlaybackClock.tsx
+++ b/src/components/views/audio_messages/PlaybackClock.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021-2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/audio_messages/PlaybackWaveform.tsx b/src/components/views/audio_messages/PlaybackWaveform.tsx
index 0f95f7084bf..a5113dd042d 100644
--- a/src/components/views/audio_messages/PlaybackWaveform.tsx
+++ b/src/components/views/audio_messages/PlaybackWaveform.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/audio_messages/RecordingPlayback.tsx b/src/components/views/audio_messages/RecordingPlayback.tsx
index 7b00c59a1c5..4c030f81efc 100644
--- a/src/components/views/audio_messages/RecordingPlayback.tsx
+++ b/src/components/views/audio_messages/RecordingPlayback.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021, 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/audio_messages/SeekBar.tsx b/src/components/views/audio_messages/SeekBar.tsx
index f56bfee9afb..1a79f5be069 100644
--- a/src/components/views/audio_messages/SeekBar.tsx
+++ b/src/components/views/audio_messages/SeekBar.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/audio_messages/Waveform.tsx b/src/components/views/audio_messages/Waveform.tsx
index e0a440f5051..83d02b81fd0 100644
--- a/src/components/views/audio_messages/Waveform.tsx
+++ b/src/components/views/audio_messages/Waveform.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/auth/AuthBody.tsx b/src/components/views/auth/AuthBody.tsx
index ea4deb4f127..b83955fcd99 100644
--- a/src/components/views/auth/AuthBody.tsx
+++ b/src/components/views/auth/AuthBody.tsx
@@ -1,7 +1,7 @@
 /*
 Copyright 2019-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/auth/AuthFooter.tsx b/src/components/views/auth/AuthFooter.tsx
index a792896a886..472ff53f09f 100644
--- a/src/components/views/auth/AuthFooter.tsx
+++ b/src/components/views/auth/AuthFooter.tsx
@@ -3,7 +3,7 @@ Copyright 2019-2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/auth/AuthHeader.tsx b/src/components/views/auth/AuthHeader.tsx
index a3a34d8e5f5..de16e11defa 100644
--- a/src/components/views/auth/AuthHeader.tsx
+++ b/src/components/views/auth/AuthHeader.tsx
@@ -2,7 +2,7 @@
 Copyright 2019-2024 New Vector Ltd.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/auth/AuthHeaderLogo.tsx b/src/components/views/auth/AuthHeaderLogo.tsx
index 07cc2f978a1..35d35bc3a59 100644
--- a/src/components/views/auth/AuthHeaderLogo.tsx
+++ b/src/components/views/auth/AuthHeaderLogo.tsx
@@ -2,7 +2,7 @@
 Copyright 2019-2024 New Vector Ltd.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/auth/AuthPage.tsx b/src/components/views/auth/AuthPage.tsx
index 2782d0a641b..dd3facaa79a 100644
--- a/src/components/views/auth/AuthPage.tsx
+++ b/src/components/views/auth/AuthPage.tsx
@@ -3,7 +3,7 @@ Copyright 2019-2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/auth/CaptchaForm.tsx b/src/components/views/auth/CaptchaForm.tsx
index f216f004fd4..d019ba234cf 100644
--- a/src/components/views/auth/CaptchaForm.tsx
+++ b/src/components/views/auth/CaptchaForm.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/auth/CompleteSecurityBody.tsx b/src/components/views/auth/CompleteSecurityBody.tsx
index 8c6d77a0498..77808ec71c7 100644
--- a/src/components/views/auth/CompleteSecurityBody.tsx
+++ b/src/components/views/auth/CompleteSecurityBody.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/auth/CountryDropdown.tsx b/src/components/views/auth/CountryDropdown.tsx
index a4bf6592bf1..7e8d669d15d 100644
--- a/src/components/views/auth/CountryDropdown.tsx
+++ b/src/components/views/auth/CountryDropdown.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2017 Vector Creations Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/auth/EmailField.tsx b/src/components/views/auth/EmailField.tsx
index 1a72872b953..ddc20c0bd1d 100644
--- a/src/components/views/auth/EmailField.tsx
+++ b/src/components/views/auth/EmailField.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/auth/InteractiveAuthEntryComponents.tsx b/src/components/views/auth/InteractiveAuthEntryComponents.tsx
index ae5c07e3483..d493e5c3cac 100644
--- a/src/components/views/auth/InteractiveAuthEntryComponents.tsx
+++ b/src/components/views/auth/InteractiveAuthEntryComponents.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2016-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/auth/LanguageSelector.tsx b/src/components/views/auth/LanguageSelector.tsx
index c15189b88d7..a3be10eeecc 100644
--- a/src/components/views/auth/LanguageSelector.tsx
+++ b/src/components/views/auth/LanguageSelector.tsx
@@ -1,7 +1,7 @@
 /*
 Copyright 2018-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/auth/LoginWithQR-types.ts b/src/components/views/auth/LoginWithQR-types.ts
index 2f041a7ced4..8e1d58515d3 100644
--- a/src/components/views/auth/LoginWithQR-types.ts
+++ b/src/components/views/auth/LoginWithQR-types.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/auth/LoginWithQR.tsx b/src/components/views/auth/LoginWithQR.tsx
index 76475e1dd35..ecf107cfbd3 100644
--- a/src/components/views/auth/LoginWithQR.tsx
+++ b/src/components/views/auth/LoginWithQR.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/auth/LoginWithQRFlow.tsx b/src/components/views/auth/LoginWithQRFlow.tsx
index 33d51f6952a..663dc1acfff 100644
--- a/src/components/views/auth/LoginWithQRFlow.tsx
+++ b/src/components/views/auth/LoginWithQRFlow.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022-2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/auth/PassphraseConfirmField.tsx b/src/components/views/auth/PassphraseConfirmField.tsx
index 2b27d3ecaf9..0337c803593 100644
--- a/src/components/views/auth/PassphraseConfirmField.tsx
+++ b/src/components/views/auth/PassphraseConfirmField.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/auth/PassphraseField.tsx b/src/components/views/auth/PassphraseField.tsx
index 90201d1ec13..8fc56cc68cf 100644
--- a/src/components/views/auth/PassphraseField.tsx
+++ b/src/components/views/auth/PassphraseField.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/auth/PasswordLogin.tsx b/src/components/views/auth/PasswordLogin.tsx
index c2c1e9382df..e13af99f6f0 100644
--- a/src/components/views/auth/PasswordLogin.tsx
+++ b/src/components/views/auth/PasswordLogin.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015, 2016 , 2017, 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/auth/RegistrationForm.tsx b/src/components/views/auth/RegistrationForm.tsx
index 540e5905a35..ef2c83d3bef 100644
--- a/src/components/views/auth/RegistrationForm.tsx
+++ b/src/components/views/auth/RegistrationForm.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
 Copyright 2015, 2016 , 2017, 2018, 2019, 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/auth/Welcome.tsx b/src/components/views/auth/Welcome.tsx
index 13755f6ca1b..39d5f95a8d1 100644
--- a/src/components/views/auth/Welcome.tsx
+++ b/src/components/views/auth/Welcome.tsx
@@ -1,7 +1,7 @@
 /*
 Copyright 2019-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/avatars/BaseAvatar.tsx b/src/components/views/avatars/BaseAvatar.tsx
index 766eb561ec8..942650c65a9 100644
--- a/src/components/views/avatars/BaseAvatar.tsx
+++ b/src/components/views/avatars/BaseAvatar.tsx
@@ -5,7 +5,7 @@ Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
 Copyright 2018 New Vector Ltd
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/avatars/DecoratedRoomAvatar.tsx b/src/components/views/avatars/DecoratedRoomAvatar.tsx
index df8a6c00d80..5a11e0f6b27 100644
--- a/src/components/views/avatars/DecoratedRoomAvatar.tsx
+++ b/src/components/views/avatars/DecoratedRoomAvatar.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/avatars/MemberAvatar.tsx b/src/components/views/avatars/MemberAvatar.tsx
index 19df06a249d..641fe4a7838 100644
--- a/src/components/views/avatars/MemberAvatar.tsx
+++ b/src/components/views/avatars/MemberAvatar.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019-2022 The Matrix.org Foundation C.I.C.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/avatars/RoomAvatar.tsx b/src/components/views/avatars/RoomAvatar.tsx
index c839761fee4..e1d71ac1aa7 100644
--- a/src/components/views/avatars/RoomAvatar.tsx
+++ b/src/components/views/avatars/RoomAvatar.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/avatars/SearchResultAvatar.tsx b/src/components/views/avatars/SearchResultAvatar.tsx
index ad2b3dd6681..c50c4d81b2a 100644
--- a/src/components/views/avatars/SearchResultAvatar.tsx
+++ b/src/components/views/avatars/SearchResultAvatar.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/avatars/WidgetAvatar.tsx b/src/components/views/avatars/WidgetAvatar.tsx
index bbb673a2955..f6d73e7d1cb 100644
--- a/src/components/views/avatars/WidgetAvatar.tsx
+++ b/src/components/views/avatars/WidgetAvatar.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/avatars/WithPresenceIndicator.tsx b/src/components/views/avatars/WithPresenceIndicator.tsx
index 519575d0d5b..9d10f8dce6e 100644
--- a/src/components/views/avatars/WithPresenceIndicator.tsx
+++ b/src/components/views/avatars/WithPresenceIndicator.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/beacon/BeaconListItem.tsx b/src/components/views/beacon/BeaconListItem.tsx
index 972a91c392e..01a7f9364aa 100644
--- a/src/components/views/beacon/BeaconListItem.tsx
+++ b/src/components/views/beacon/BeaconListItem.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/beacon/BeaconMarker.tsx b/src/components/views/beacon/BeaconMarker.tsx
index 5f8f76ecfeb..01d74e72b13 100644
--- a/src/components/views/beacon/BeaconMarker.tsx
+++ b/src/components/views/beacon/BeaconMarker.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/beacon/BeaconStatus.tsx b/src/components/views/beacon/BeaconStatus.tsx
index 08c3797d32d..1415dc229cd 100644
--- a/src/components/views/beacon/BeaconStatus.tsx
+++ b/src/components/views/beacon/BeaconStatus.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/beacon/BeaconStatusTooltip.tsx b/src/components/views/beacon/BeaconStatusTooltip.tsx
index e69e1c6b85c..1dc1b05e611 100644
--- a/src/components/views/beacon/BeaconStatusTooltip.tsx
+++ b/src/components/views/beacon/BeaconStatusTooltip.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/beacon/BeaconViewDialog.tsx b/src/components/views/beacon/BeaconViewDialog.tsx
index ec737baffb4..27f9f2e520e 100644
--- a/src/components/views/beacon/BeaconViewDialog.tsx
+++ b/src/components/views/beacon/BeaconViewDialog.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/beacon/DialogOwnBeaconStatus.tsx b/src/components/views/beacon/DialogOwnBeaconStatus.tsx
index 56ffb5a1a65..e6b35d92477 100644
--- a/src/components/views/beacon/DialogOwnBeaconStatus.tsx
+++ b/src/components/views/beacon/DialogOwnBeaconStatus.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/beacon/DialogSidebar.tsx b/src/components/views/beacon/DialogSidebar.tsx
index 824d772bce7..9fcca26dde4 100644
--- a/src/components/views/beacon/DialogSidebar.tsx
+++ b/src/components/views/beacon/DialogSidebar.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/beacon/LeftPanelLiveShareWarning.tsx b/src/components/views/beacon/LeftPanelLiveShareWarning.tsx
index ac80067fad6..0c3f26f91ef 100644
--- a/src/components/views/beacon/LeftPanelLiveShareWarning.tsx
+++ b/src/components/views/beacon/LeftPanelLiveShareWarning.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/beacon/LiveTimeRemaining.tsx b/src/components/views/beacon/LiveTimeRemaining.tsx
index 89052b5df2b..c0730938ee9 100644
--- a/src/components/views/beacon/LiveTimeRemaining.tsx
+++ b/src/components/views/beacon/LiveTimeRemaining.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/beacon/OwnBeaconStatus.tsx b/src/components/views/beacon/OwnBeaconStatus.tsx
index e84fa6d0b97..7d0f277786d 100644
--- a/src/components/views/beacon/OwnBeaconStatus.tsx
+++ b/src/components/views/beacon/OwnBeaconStatus.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/beacon/RoomCallBanner.tsx b/src/components/views/beacon/RoomCallBanner.tsx
index b5626da95be..a9f25e7e6c4 100644
--- a/src/components/views/beacon/RoomCallBanner.tsx
+++ b/src/components/views/beacon/RoomCallBanner.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/beacon/ShareLatestLocation.tsx b/src/components/views/beacon/ShareLatestLocation.tsx
index 74e253a0bbe..5300a819000 100644
--- a/src/components/views/beacon/ShareLatestLocation.tsx
+++ b/src/components/views/beacon/ShareLatestLocation.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/beacon/StyledLiveBeaconIcon.tsx b/src/components/views/beacon/StyledLiveBeaconIcon.tsx
index b60d9c60702..c73931918fa 100644
--- a/src/components/views/beacon/StyledLiveBeaconIcon.tsx
+++ b/src/components/views/beacon/StyledLiveBeaconIcon.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/beacon/displayStatus.ts b/src/components/views/beacon/displayStatus.ts
index ad92e0f0fb9..e11b0018ba0 100644
--- a/src/components/views/beacon/displayStatus.ts
+++ b/src/components/views/beacon/displayStatus.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/beacon/index.tsx b/src/components/views/beacon/index.tsx
index 782a69f98eb..871e7cb07e4 100644
--- a/src/components/views/beacon/index.tsx
+++ b/src/components/views/beacon/index.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/beta/BetaCard.tsx b/src/components/views/beta/BetaCard.tsx
index 8cd9122e909..93d69dffce5 100644
--- a/src/components/views/beta/BetaCard.tsx
+++ b/src/components/views/beta/BetaCard.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -20,12 +20,13 @@ import SettingsFlag from "../elements/SettingsFlag";
 import { useFeatureEnabled } from "../../../hooks/useSettings";
 import InlineSpinner from "../elements/InlineSpinner";
 import { shouldShowFeedback } from "../../../utils/Feedback";
+import { FeatureSettingKey } from "../../../settings/Settings.tsx";
 
 // XXX: Keep this around for re-use in future Betas
 
 interface IProps {
     title?: string;
-    featureId: string;
+    featureId: FeatureSettingKey;
 }
 
 interface IBetaPillProps {
diff --git a/src/components/views/context_menus/DeveloperToolsOption.tsx b/src/components/views/context_menus/DeveloperToolsOption.tsx
index ce673f52857..fc77a2e284e 100644
--- a/src/components/views/context_menus/DeveloperToolsOption.tsx
+++ b/src/components/views/context_menus/DeveloperToolsOption.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/context_menus/DeviceContextMenu.tsx b/src/components/views/context_menus/DeviceContextMenu.tsx
index efe1b33e47c..5d71049fb40 100644
--- a/src/components/views/context_menus/DeviceContextMenu.tsx
+++ b/src/components/views/context_menus/DeviceContextMenu.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/context_menus/DialpadContextMenu.tsx b/src/components/views/context_menus/DialpadContextMenu.tsx
index 72e7e048175..c4d0d737866 100644
--- a/src/components/views/context_menus/DialpadContextMenu.tsx
+++ b/src/components/views/context_menus/DialpadContextMenu.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/context_menus/GenericElementContextMenu.tsx b/src/components/views/context_menus/GenericElementContextMenu.tsx
index afb39d6ebe2..b6d3304c428 100644
--- a/src/components/views/context_menus/GenericElementContextMenu.tsx
+++ b/src/components/views/context_menus/GenericElementContextMenu.tsx
@@ -1,7 +1,7 @@
 /*
 Copyright 2017-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/context_menus/IconizedContextMenu.tsx b/src/components/views/context_menus/IconizedContextMenu.tsx
index f621d8af87f..17a38055132 100644
--- a/src/components/views/context_menus/IconizedContextMenu.tsx
+++ b/src/components/views/context_menus/IconizedContextMenu.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/context_menus/KebabContextMenu.tsx b/src/components/views/context_menus/KebabContextMenu.tsx
index 7e2077473ce..e65f0389ffe 100644
--- a/src/components/views/context_menus/KebabContextMenu.tsx
+++ b/src/components/views/context_menus/KebabContextMenu.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/context_menus/LegacyCallContextMenu.tsx b/src/components/views/context_menus/LegacyCallContextMenu.tsx
index e6bb191df8c..bc3deab7a1d 100644
--- a/src/components/views/context_menus/LegacyCallContextMenu.tsx
+++ b/src/components/views/context_menus/LegacyCallContextMenu.tsx
@@ -1,7 +1,7 @@
 /*
 Copyright 2020-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/context_menus/MessageContextMenu.tsx b/src/components/views/context_menus/MessageContextMenu.tsx
index 711ffbe70f9..0af3604fcae 100644
--- a/src/components/views/context_menus/MessageContextMenu.tsx
+++ b/src/components/views/context_menus/MessageContextMenu.tsx
@@ -4,7 +4,7 @@ Copyright 2015-2023 The Matrix.org Foundation C.I.C.
 Copyright 2021, 2022 Šimon Brandner <simon.bra.ag@gmail.com>
 Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/context_menus/RoomGeneralContextMenu.tsx b/src/components/views/context_menus/RoomGeneralContextMenu.tsx
index 714f97ed988..c54aa1e4652 100644
--- a/src/components/views/context_menus/RoomGeneralContextMenu.tsx
+++ b/src/components/views/context_menus/RoomGeneralContextMenu.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021-2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -282,7 +282,7 @@ export const RoomGeneralContextMenu: React.FC<RoomGeneralContextMenuProps> = ({
         }
     })();
 
-    const developerModeEnabled = useSettingValue<boolean>("developerMode");
+    const developerModeEnabled = useSettingValue("developerMode");
     const developerToolsOption = developerModeEnabled ? (
         <DeveloperToolsOption onFinished={onFinished} roomId={room.roomId} />
     ) : null;
diff --git a/src/components/views/context_menus/RoomNotificationContextMenu.tsx b/src/components/views/context_menus/RoomNotificationContextMenu.tsx
index b43f4e41121..ea638807625 100644
--- a/src/components/views/context_menus/RoomNotificationContextMenu.tsx
+++ b/src/components/views/context_menus/RoomNotificationContextMenu.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/context_menus/SpaceContextMenu.tsx b/src/components/views/context_menus/SpaceContextMenu.tsx
index 2d407214daf..11a1364d6d3 100644
--- a/src/components/views/context_menus/SpaceContextMenu.tsx
+++ b/src/components/views/context_menus/SpaceContextMenu.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/context_menus/ThreadListContextMenu.tsx b/src/components/views/context_menus/ThreadListContextMenu.tsx
index 0d30e7174ad..eea98159546 100644
--- a/src/components/views/context_menus/ThreadListContextMenu.tsx
+++ b/src/components/views/context_menus/ThreadListContextMenu.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/context_menus/WidgetContextMenu.tsx b/src/components/views/context_menus/WidgetContextMenu.tsx
index 46052de9ff2..894e8f8c7d4 100644
--- a/src/components/views/context_menus/WidgetContextMenu.tsx
+++ b/src/components/views/context_menus/WidgetContextMenu.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -71,7 +71,7 @@ const showDeleteButton = (canModify: boolean, onDeleteClick: undefined | (() =>
 
 const showSnapshotButton = (widgetMessaging: ClientWidgetApi | undefined): boolean => {
     return (
-        SettingsStore.getValue<boolean>("enableWidgetScreenshots") &&
+        SettingsStore.getValue("enableWidgetScreenshots") &&
         !!widgetMessaging?.hasCapability(MatrixCapabilities.Screenshots)
     );
 };
diff --git a/src/components/views/dialogs/AddExistingSubspaceDialog.tsx b/src/components/views/dialogs/AddExistingSubspaceDialog.tsx
index e76c42c2bd0..d7311244b7f 100644
--- a/src/components/views/dialogs/AddExistingSubspaceDialog.tsx
+++ b/src/components/views/dialogs/AddExistingSubspaceDialog.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/AddExistingToSpaceDialog.tsx b/src/components/views/dialogs/AddExistingToSpaceDialog.tsx
index 31162b45f41..3cc62f41554 100644
--- a/src/components/views/dialogs/AddExistingToSpaceDialog.tsx
+++ b/src/components/views/dialogs/AddExistingToSpaceDialog.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -131,7 +131,7 @@ export const AddExistingToSpace: React.FC<IAddExistingToSpaceProps> = ({
     onFinished,
 }) => {
     const cli = useContext(MatrixClientContext);
-    const msc3946ProcessDynamicPredecessor = useSettingValue<boolean>("feature_dynamic_room_predecessors");
+    const msc3946ProcessDynamicPredecessor = useSettingValue("feature_dynamic_room_predecessors");
     const visibleRooms = useMemo(
         () =>
             cli
diff --git a/src/components/views/dialogs/AnalyticsLearnMoreDialog.tsx b/src/components/views/dialogs/AnalyticsLearnMoreDialog.tsx
index 98e2921a604..5396d1e9a78 100644
--- a/src/components/views/dialogs/AnalyticsLearnMoreDialog.tsx
+++ b/src/components/views/dialogs/AnalyticsLearnMoreDialog.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/AppDownloadDialog.tsx b/src/components/views/dialogs/AppDownloadDialog.tsx
deleted file mode 100644
index 4faeb083876..00000000000
--- a/src/components/views/dialogs/AppDownloadDialog.tsx
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2022 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
-Please see LICENSE files in the repository root for full details.
-*/
-
-import React, { FC } from "react";
-
-import { Icon as FDroidBadge } from "../../../../res/img/badges/f-droid.svg";
-import { Icon as GooglePlayBadge } from "../../../../res/img/badges/google-play.svg";
-import { Icon as IOSBadge } from "../../../../res/img/badges/ios.svg";
-import { _t } from "../../../languageHandler";
-import SdkConfig from "../../../SdkConfig";
-import AccessibleButton from "../elements/AccessibleButton";
-import QRCode from "../elements/QRCode";
-import Heading from "../typography/Heading";
-import BaseDialog from "./BaseDialog";
-
-interface Props {
-    onFinished(): void;
-}
-
-export const showAppDownloadDialogPrompt = (): boolean => {
-    const desktopBuilds = SdkConfig.getObject("desktop_builds");
-    const mobileBuilds = SdkConfig.getObject("mobile_builds");
-
-    return (
-        !!desktopBuilds?.get("available") ||
-        !!mobileBuilds?.get("ios") ||
-        !!mobileBuilds?.get("android") ||
-        !!mobileBuilds?.get("fdroid")
-    );
-};
-
-export const AppDownloadDialog: FC<Props> = ({ onFinished }) => {
-    const brand = SdkConfig.get("brand");
-    const desktopBuilds = SdkConfig.getObject("desktop_builds");
-    const mobileBuilds = SdkConfig.getObject("mobile_builds");
-
-    const urlAppStore = mobileBuilds?.get("ios");
-
-    const urlGooglePlay = mobileBuilds?.get("android");
-    const urlFDroid = mobileBuilds?.get("fdroid");
-    const urlAndroid = urlGooglePlay ?? urlFDroid;
-
-    return (
-        <BaseDialog
-            title={_t("onboarding|download_brand", { brand })}
-            className="mx_AppDownloadDialog"
-            fixedWidth
-            onFinished={onFinished}
-        >
-            {desktopBuilds?.get("available") && (
-                <div className="mx_AppDownloadDialog_desktop">
-                    <Heading size="3">{_t("onboarding|download_brand_desktop", { brand })}</Heading>
-                    <AccessibleButton
-                        kind="primary"
-                        element="a"
-                        href={desktopBuilds?.get("url")}
-                        target="_blank"
-                        onClick={() => {}}
-                    >
-                        {_t("onboarding|download_brand_desktop", { brand })}
-                    </AccessibleButton>
-                </div>
-            )}
-            <div className="mx_AppDownloadDialog_mobile">
-                {urlAppStore && (
-                    <div className="mx_AppDownloadDialog_app">
-                        <Heading size="3">{_t("common|ios")}</Heading>
-                        <QRCode data={urlAppStore} margin={0} width={172} />
-                        <div className="mx_AppDownloadDialog_info">
-                            {_t("onboarding|qr_or_app_links", {
-                                appLinks: "",
-                                qrCode: "",
-                            })}
-                        </div>
-                        <div className="mx_AppDownloadDialog_links">
-                            <AccessibleButton
-                                element="a"
-                                href={urlAppStore}
-                                target="_blank"
-                                aria-label={_t("onboarding|download_app_store")}
-                                onClick={() => {}}
-                            >
-                                <IOSBadge />
-                            </AccessibleButton>
-                        </div>
-                    </div>
-                )}
-                {urlAndroid && (
-                    <div className="mx_AppDownloadDialog_app">
-                        <Heading size="3">{_t("common|android")}</Heading>
-                        <QRCode data={urlAndroid} margin={0} width={172} />
-                        <div className="mx_AppDownloadDialog_info">
-                            {_t("onboarding|qr_or_app_links", {
-                                appLinks: "",
-                                qrCode: "",
-                            })}
-                        </div>
-                        <div className="mx_AppDownloadDialog_links">
-                            {urlGooglePlay && (
-                                <AccessibleButton
-                                    element="a"
-                                    href={urlGooglePlay}
-                                    target="_blank"
-                                    aria-label={_t("onboarding|download_google_play")}
-                                    onClick={() => {}}
-                                >
-                                    <GooglePlayBadge />
-                                </AccessibleButton>
-                            )}
-                            {urlFDroid && (
-                                <AccessibleButton
-                                    element="a"
-                                    href={urlFDroid}
-                                    target="_blank"
-                                    aria-label={_t("onboarding|download_f_droid")}
-                                    onClick={() => {}}
-                                >
-                                    <FDroidBadge />
-                                </AccessibleButton>
-                            )}
-                        </div>
-                    </div>
-                )}
-            </div>
-            <div className="mx_AppDownloadDialog_legal">
-                <p>{_t("onboarding|apple_trademarks")}</p>
-                <p>{_t("onboarding|google_trademarks")}</p>
-            </div>
-        </BaseDialog>
-    );
-};
diff --git a/src/components/views/dialogs/AskInviteAnywayDialog.tsx b/src/components/views/dialogs/AskInviteAnywayDialog.tsx
index de8fc5eb3c2..b18d70df112 100644
--- a/src/components/views/dialogs/AskInviteAnywayDialog.tsx
+++ b/src/components/views/dialogs/AskInviteAnywayDialog.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 Copyright 2019 New Vector Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/BaseDialog.tsx b/src/components/views/dialogs/BaseDialog.tsx
index ccb162e1cba..39afb2e6213 100644
--- a/src/components/views/dialogs/BaseDialog.tsx
+++ b/src/components/views/dialogs/BaseDialog.tsx
@@ -4,7 +4,7 @@ Copyright 2019 The Matrix.org Foundation C.I.C.
 Copyright 2018, 2019 New Vector Ltd
 Copyright 2017 Vector Creations Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/BetaFeedbackDialog.tsx b/src/components/views/dialogs/BetaFeedbackDialog.tsx
index 9f4852cf2ac..2c13ae00060 100644
--- a/src/components/views/dialogs/BetaFeedbackDialog.tsx
+++ b/src/components/views/dialogs/BetaFeedbackDialog.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -15,11 +15,12 @@ import defaultDispatcher from "../../../dispatcher/dispatcher";
 import { Action } from "../../../dispatcher/actions";
 import { UserTab } from "./UserTab";
 import GenericFeatureFeedbackDialog from "./GenericFeatureFeedbackDialog";
+import { SettingKey } from "../../../settings/Settings.tsx";
 
 // XXX: Keep this around for re-use in future Betas
 
 interface IProps {
-    featureId: string;
+    featureId: SettingKey;
     onFinished(sendFeedback?: boolean): void;
 }
 
@@ -35,7 +36,7 @@ const BetaFeedbackDialog: React.FC<IProps> = ({ featureId, onFinished }) => {
             rageshakeLabel={info.feedbackLabel}
             rageshakeData={Object.fromEntries(
                 (SettingsStore.getBetaInfo(featureId)?.extraSettings || []).map((k) => {
-                    return SettingsStore.getValue(k);
+                    return [k, SettingsStore.getValue(k)];
                 }),
             )}
         >
diff --git a/src/components/views/dialogs/BugReportDialog.tsx b/src/components/views/dialogs/BugReportDialog.tsx
index 373f30d3aeb..013f9ecb061 100644
--- a/src/components/views/dialogs/BugReportDialog.tsx
+++ b/src/components/views/dialogs/BugReportDialog.tsx
@@ -5,7 +5,7 @@ Copyright 2019 The Matrix.org Foundation C.I.C.
 Copyright 2018 New Vector Ltd
 Copyright 2017 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/BulkRedactDialog.tsx b/src/components/views/dialogs/BulkRedactDialog.tsx
index 33fa8250918..d766c6c9732 100644
--- a/src/components/views/dialogs/BulkRedactDialog.tsx
+++ b/src/components/views/dialogs/BulkRedactDialog.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/ChangelogDialog.tsx b/src/components/views/dialogs/ChangelogDialog.tsx
index ae3c157c788..087beaf6a82 100644
--- a/src/components/views/dialogs/ChangelogDialog.tsx
+++ b/src/components/views/dialogs/ChangelogDialog.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
 Copyright 2016 Aviral Dasgupta
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/src/components/views/dialogs/ConfirmAndWaitRedactDialog.tsx b/src/components/views/dialogs/ConfirmAndWaitRedactDialog.tsx
index 5771181951c..2d7500e72c5 100644
--- a/src/components/views/dialogs/ConfirmAndWaitRedactDialog.tsx
+++ b/src/components/views/dialogs/ConfirmAndWaitRedactDialog.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/ConfirmRedactDialog.tsx b/src/components/views/dialogs/ConfirmRedactDialog.tsx
index f4258c9d6d4..7733d83585b 100644
--- a/src/components/views/dialogs/ConfirmRedactDialog.tsx
+++ b/src/components/views/dialogs/ConfirmRedactDialog.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2017 Vector Creations Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/ConfirmSpaceUserActionDialog.tsx b/src/components/views/dialogs/ConfirmSpaceUserActionDialog.tsx
index cb79f27a2f3..9c21b469e4a 100644
--- a/src/components/views/dialogs/ConfirmSpaceUserActionDialog.tsx
+++ b/src/components/views/dialogs/ConfirmSpaceUserActionDialog.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/ConfirmUserActionDialog.tsx b/src/components/views/dialogs/ConfirmUserActionDialog.tsx
index ffe8c778f4d..f79601f855e 100644
--- a/src/components/views/dialogs/ConfirmUserActionDialog.tsx
+++ b/src/components/views/dialogs/ConfirmUserActionDialog.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2017 Vector Creations Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/ConfirmWipeDeviceDialog.tsx b/src/components/views/dialogs/ConfirmWipeDeviceDialog.tsx
index 1fa8f4f0c54..695219a54bd 100644
--- a/src/components/views/dialogs/ConfirmWipeDeviceDialog.tsx
+++ b/src/components/views/dialogs/ConfirmWipeDeviceDialog.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/CreateRoomDialog.tsx b/src/components/views/dialogs/CreateRoomDialog.tsx
index 4d36d016235..d77ec145787 100644
--- a/src/components/views/dialogs/CreateRoomDialog.tsx
+++ b/src/components/views/dialogs/CreateRoomDialog.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2020, 2021 The Matrix.org Foundation C.I.C.
 Copyright 2017 Michael Telatynski <7t3chguy@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/CreateSubspaceDialog.tsx b/src/components/views/dialogs/CreateSubspaceDialog.tsx
index 6add8127931..6af128ef646 100644
--- a/src/components/views/dialogs/CreateSubspaceDialog.tsx
+++ b/src/components/views/dialogs/CreateSubspaceDialog.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/DeactivateAccountDialog.tsx b/src/components/views/dialogs/DeactivateAccountDialog.tsx
index d68c931cc16..52140b2967b 100644
--- a/src/components/views/dialogs/DeactivateAccountDialog.tsx
+++ b/src/components/views/dialogs/DeactivateAccountDialog.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
 Copyright 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/DevtoolsDialog.tsx b/src/components/views/dialogs/DevtoolsDialog.tsx
index 7dc683469a8..e9e2c9a3344 100644
--- a/src/components/views/dialogs/DevtoolsDialog.tsx
+++ b/src/components/views/dialogs/DevtoolsDialog.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2018-2023 The Matrix.org Foundation C.I.C.
 Copyright 2022 Michael Telatynski <7t3chguy@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/EndPollDialog.tsx b/src/components/views/dialogs/EndPollDialog.tsx
index 92c98190fed..03d9c7f7f5e 100644
--- a/src/components/views/dialogs/EndPollDialog.tsx
+++ b/src/components/views/dialogs/EndPollDialog.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/ErrorDialog.tsx b/src/components/views/dialogs/ErrorDialog.tsx
index 2e7cd753fcf..5f800e53df1 100644
--- a/src/components/views/dialogs/ErrorDialog.tsx
+++ b/src/components/views/dialogs/ErrorDialog.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/ExportDialog.tsx b/src/components/views/dialogs/ExportDialog.tsx
index 54c58fe2e4a..bd7ad24bca3 100644
--- a/src/components/views/dialogs/ExportDialog.tsx
+++ b/src/components/views/dialogs/ExportDialog.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/FeedbackDialog.tsx b/src/components/views/dialogs/FeedbackDialog.tsx
index 1e391d80026..27de6259209 100644
--- a/src/components/views/dialogs/FeedbackDialog.tsx
+++ b/src/components/views/dialogs/FeedbackDialog.tsx
@@ -1,7 +1,7 @@
 /*
 Copyright 2018-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/ForwardDialog.tsx b/src/components/views/dialogs/ForwardDialog.tsx
index 0a0a70d1b5b..a831acc5d18 100644
--- a/src/components/views/dialogs/ForwardDialog.tsx
+++ b/src/components/views/dialogs/ForwardDialog.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 Robin Townsend <robin@robin.town>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -23,8 +23,6 @@ import {
     TimelineEvents,
 } from "matrix-js-sdk/src/matrix";
 import { KnownMembership } from "matrix-js-sdk/src/types";
-// eslint-disable-next-line no-restricted-imports
-import OverflowHorizontalSvg from "@vector-im/compound-design-tokens/icons/overflow-horizontal.svg";
 
 import { _t } from "../../../languageHandler";
 import dis from "../../../dispatcher/dispatcher";
@@ -42,8 +40,6 @@ import { RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks";
 import { sortRooms } from "../../../stores/room-list/algorithms/tag-sorting/RecentAlgorithm";
 import QueryMatcher from "../../../autocomplete/QueryMatcher";
 import TruncatedList from "../elements/TruncatedList";
-import EntityTile from "../rooms/EntityTile";
-import BaseAvatar from "../avatars/BaseAvatar";
 import { Action } from "../../../dispatcher/actions";
 import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
 import AccessibleButton, { ButtonEvent } from "../elements/AccessibleButton";
@@ -60,6 +56,7 @@ import {
 } from "../../../accessibility/RovingTabIndex";
 import { getKeyBindingsManager } from "../../../KeyBindingsManager";
 import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts";
+import { OverflowTileView } from "../rooms/OverflowTileView";
 
 const AVATAR_SIZE = 30;
 
@@ -253,8 +250,8 @@ const ForwardDialog: React.FC<IProps> = ({ matrixClient: cli, event, permalinkCr
     const [query, setQuery] = useState("");
     const lcQuery = query.toLowerCase();
 
-    const previewLayout = useSettingValue<Layout>("layout");
-    const msc3946DynamicRoomPredecessors = useSettingValue<boolean>("feature_dynamic_room_predecessors");
+    const previewLayout = useSettingValue("layout");
+    const msc3946DynamicRoomPredecessors = useSettingValue("feature_dynamic_room_predecessors");
 
     let rooms = useMemo(
         () =>
@@ -275,17 +272,9 @@ const ForwardDialog: React.FC<IProps> = ({ matrixClient: cli, event, permalinkCr
     }
 
     const [truncateAt, setTruncateAt] = useState(20);
+
     function overflowTile(overflowCount: number, totalCount: number): JSX.Element {
-        const text = _t("common|and_n_others", { count: overflowCount });
-        return (
-            <EntityTile
-                className="mx_EntityTile_ellipsis"
-                avatarJsx={<BaseAvatar url={OverflowHorizontalSvg} name="..." size="36px" />}
-                name={text}
-                showPresence={false}
-                onClick={() => setTruncateAt(totalCount)}
-            />
-        );
+        return <OverflowTileView remaining={overflowCount} onClick={() => setTruncateAt(totalCount)} />;
     }
 
     const onKeyDown = (ev: React.KeyboardEvent, state: IState): void => {
diff --git a/src/components/views/dialogs/GenericFeatureFeedbackDialog.tsx b/src/components/views/dialogs/GenericFeatureFeedbackDialog.tsx
index 489e4c7bce5..1ea187361eb 100644
--- a/src/components/views/dialogs/GenericFeatureFeedbackDialog.tsx
+++ b/src/components/views/dialogs/GenericFeatureFeedbackDialog.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/IncomingSasDialog.tsx b/src/components/views/dialogs/IncomingSasDialog.tsx
index 4e273f62f72..e5df3a35b1f 100644
--- a/src/components/views/dialogs/IncomingSasDialog.tsx
+++ b/src/components/views/dialogs/IncomingSasDialog.tsx
@@ -1,7 +1,7 @@
 /*
 Copyright 2019-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/InfoDialog.tsx b/src/components/views/dialogs/InfoDialog.tsx
index 1f5449a3277..20fb51a7d09 100644
--- a/src/components/views/dialogs/InfoDialog.tsx
+++ b/src/components/views/dialogs/InfoDialog.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2015-2021 The Matrix.org Foundation C.I.C.
 Copyright 2019 Bastian Masanek, Noxware IT <matrix@noxware.de>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/IntegrationsDisabledDialog.tsx b/src/components/views/dialogs/IntegrationsDisabledDialog.tsx
index 44fea65d53d..ad0f7654136 100644
--- a/src/components/views/dialogs/IntegrationsDisabledDialog.tsx
+++ b/src/components/views/dialogs/IntegrationsDisabledDialog.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/IntegrationsImpossibleDialog.tsx b/src/components/views/dialogs/IntegrationsImpossibleDialog.tsx
index a17b25bf231..625854a36a9 100644
--- a/src/components/views/dialogs/IntegrationsImpossibleDialog.tsx
+++ b/src/components/views/dialogs/IntegrationsImpossibleDialog.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/InteractiveAuthDialog.tsx b/src/components/views/dialogs/InteractiveAuthDialog.tsx
index 305534e6db8..beb27573c6b 100644
--- a/src/components/views/dialogs/InteractiveAuthDialog.tsx
+++ b/src/components/views/dialogs/InteractiveAuthDialog.tsx
@@ -4,7 +4,7 @@ Copyright 2020 The Matrix.org Foundation C.I.C.
 Copyright 2017 Vector Creations Ltd
 Copyright 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/InviteDialog.tsx b/src/components/views/dialogs/InviteDialog.tsx
index 35e04fb12e2..d72baae5235 100644
--- a/src/components/views/dialogs/InviteDialog.tsx
+++ b/src/components/views/dialogs/InviteDialog.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/InviteDialogTypes.ts b/src/components/views/dialogs/InviteDialogTypes.ts
index 97a71408f31..535693faaed 100644
--- a/src/components/views/dialogs/InviteDialogTypes.ts
+++ b/src/components/views/dialogs/InviteDialogTypes.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/LeaveSpaceDialog.tsx b/src/components/views/dialogs/LeaveSpaceDialog.tsx
index 50821694db0..72ad5f478ff 100644
--- a/src/components/views/dialogs/LeaveSpaceDialog.tsx
+++ b/src/components/views/dialogs/LeaveSpaceDialog.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/LogoutDialog.tsx b/src/components/views/dialogs/LogoutDialog.tsx
index af8f91533e7..460871fb367 100644
--- a/src/components/views/dialogs/LogoutDialog.tsx
+++ b/src/components/views/dialogs/LogoutDialog.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2020-2022 The Matrix.org Foundation C.I.C.
 Copyright 2018, 2019 New Vector Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/ManageRestrictedJoinRuleDialog.tsx b/src/components/views/dialogs/ManageRestrictedJoinRuleDialog.tsx
index d124d97456c..7a2e3b35ef0 100644
--- a/src/components/views/dialogs/ManageRestrictedJoinRuleDialog.tsx
+++ b/src/components/views/dialogs/ManageRestrictedJoinRuleDialog.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/MessageEditHistoryDialog.tsx b/src/components/views/dialogs/MessageEditHistoryDialog.tsx
index 48564e2411a..3008e2d16cb 100644
--- a/src/components/views/dialogs/MessageEditHistoryDialog.tsx
+++ b/src/components/views/dialogs/MessageEditHistoryDialog.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/ModalWidgetDialog.tsx b/src/components/views/dialogs/ModalWidgetDialog.tsx
index 7df9130a7aa..58c6c92a5e0 100644
--- a/src/components/views/dialogs/ModalWidgetDialog.tsx
+++ b/src/components/views/dialogs/ModalWidgetDialog.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020, 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/ModuleUiDialog.tsx b/src/components/views/dialogs/ModuleUiDialog.tsx
index 7cdb0190d0c..89ef4ad0ea7 100644
--- a/src/components/views/dialogs/ModuleUiDialog.tsx
+++ b/src/components/views/dialogs/ModuleUiDialog.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/PollHistoryDialog.tsx b/src/components/views/dialogs/PollHistoryDialog.tsx
index 50774425ccd..528b44f3322 100644
--- a/src/components/views/dialogs/PollHistoryDialog.tsx
+++ b/src/components/views/dialogs/PollHistoryDialog.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/QuestionDialog.tsx b/src/components/views/dialogs/QuestionDialog.tsx
index 109599ee084..1539bbe365f 100644
--- a/src/components/views/dialogs/QuestionDialog.tsx
+++ b/src/components/views/dialogs/QuestionDialog.tsx
@@ -2,7 +2,7 @@
 Copyright 2017-2024 New Vector Ltd.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/RegistrationEmailPromptDialog.tsx b/src/components/views/dialogs/RegistrationEmailPromptDialog.tsx
index a02098d3ed6..a7748e3d69c 100644
--- a/src/components/views/dialogs/RegistrationEmailPromptDialog.tsx
+++ b/src/components/views/dialogs/RegistrationEmailPromptDialog.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/ReportEventDialog.tsx b/src/components/views/dialogs/ReportEventDialog.tsx
index 3234c2be35b..5c1e409ca5a 100644
--- a/src/components/views/dialogs/ReportEventDialog.tsx
+++ b/src/components/views/dialogs/ReportEventDialog.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/RoomSettingsDialog.tsx b/src/components/views/dialogs/RoomSettingsDialog.tsx
index cb804b8e004..a4c8dd91b2e 100644
--- a/src/components/views/dialogs/RoomSettingsDialog.tsx
+++ b/src/components/views/dialogs/RoomSettingsDialog.tsx
@@ -4,7 +4,7 @@ Copyright 2023 The Matrix.org Foundation C.I.C.
 Copyright 2019 New Vector Ltd
 Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/RoomUpgradeDialog.tsx b/src/components/views/dialogs/RoomUpgradeDialog.tsx
index 337c1a334ca..fdb0a9f0a67 100644
--- a/src/components/views/dialogs/RoomUpgradeDialog.tsx
+++ b/src/components/views/dialogs/RoomUpgradeDialog.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2018-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/RoomUpgradeWarningDialog.tsx b/src/components/views/dialogs/RoomUpgradeWarningDialog.tsx
index 48d0bef28cf..c15db4a5df1 100644
--- a/src/components/views/dialogs/RoomUpgradeWarningDialog.tsx
+++ b/src/components/views/dialogs/RoomUpgradeWarningDialog.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/ScrollableBaseModal.tsx b/src/components/views/dialogs/ScrollableBaseModal.tsx
index 564c773975d..2f9c94f66fb 100644
--- a/src/components/views/dialogs/ScrollableBaseModal.tsx
+++ b/src/components/views/dialogs/ScrollableBaseModal.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/ServerOfflineDialog.tsx b/src/components/views/dialogs/ServerOfflineDialog.tsx
index d48097b0604..b4d03c4c126 100644
--- a/src/components/views/dialogs/ServerOfflineDialog.tsx
+++ b/src/components/views/dialogs/ServerOfflineDialog.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/ServerPickerDialog.tsx b/src/components/views/dialogs/ServerPickerDialog.tsx
index 3fc74ec80a5..9fd5002138c 100644
--- a/src/components/views/dialogs/ServerPickerDialog.tsx
+++ b/src/components/views/dialogs/ServerPickerDialog.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020, 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/SeshatResetDialog.tsx b/src/components/views/dialogs/SeshatResetDialog.tsx
index 3e257fd94fd..247d6f9b04c 100644
--- a/src/components/views/dialogs/SeshatResetDialog.tsx
+++ b/src/components/views/dialogs/SeshatResetDialog.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/SessionRestoreErrorDialog.tsx b/src/components/views/dialogs/SessionRestoreErrorDialog.tsx
index 84832cb1f22..26baef9f2a7 100644
--- a/src/components/views/dialogs/SessionRestoreErrorDialog.tsx
+++ b/src/components/views/dialogs/SessionRestoreErrorDialog.tsx
@@ -4,7 +4,7 @@ Copyright 2020 The Matrix.org Foundation C.I.C.
 Copyright 2018 New Vector Ltd
 Copyright 2017 Vector Creations Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/SetEmailDialog.tsx b/src/components/views/dialogs/SetEmailDialog.tsx
index 2b1798e3879..57d8ed12d44 100644
--- a/src/components/views/dialogs/SetEmailDialog.tsx
+++ b/src/components/views/dialogs/SetEmailDialog.tsx
@@ -2,7 +2,7 @@
 Copyright 2018-2024 New Vector Ltd.
 Copyright 2017 Vector Creations Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/ShareDialog.tsx b/src/components/views/dialogs/ShareDialog.tsx
index 1796b79239e..3feff26f8f7 100644
--- a/src/components/views/dialogs/ShareDialog.tsx
+++ b/src/components/views/dialogs/ShareDialog.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 Copyright 2018 New Vector Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -100,8 +100,8 @@ type ShareDialogProps = XOR<Props, EventProps>;
  * A dialog to share a link to a room, user, room member or a matrix event.
  */
 export function ShareDialog({ target, customTitle, onFinished, permalinkCreator }: ShareDialogProps): JSX.Element {
-    const showQrCode = useSettingValue<boolean>(UIFeature.ShareQRCode);
-    const showSocials = useSettingValue<boolean>(UIFeature.ShareSocial);
+    const showQrCode = useSettingValue(UIFeature.ShareQRCode);
+    const showSocials = useSettingValue(UIFeature.ShareSocial);
 
     const timeoutIdRef = useRef<number>();
     const [isCopied, setIsCopied] = useState(false);
diff --git a/src/components/views/dialogs/SlashCommandHelpDialog.tsx b/src/components/views/dialogs/SlashCommandHelpDialog.tsx
index b5e01bf41ee..1c087567c36 100644
--- a/src/components/views/dialogs/SlashCommandHelpDialog.tsx
+++ b/src/components/views/dialogs/SlashCommandHelpDialog.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/SpacePreferencesDialog.tsx b/src/components/views/dialogs/SpacePreferencesDialog.tsx
index 1361b2728fe..a5f30f0d641 100644
--- a/src/components/views/dialogs/SpacePreferencesDialog.tsx
+++ b/src/components/views/dialogs/SpacePreferencesDialog.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/SpaceSettingsDialog.tsx b/src/components/views/dialogs/SpaceSettingsDialog.tsx
index fd415c78973..5ea4ea3418e 100644
--- a/src/components/views/dialogs/SpaceSettingsDialog.tsx
+++ b/src/components/views/dialogs/SpaceSettingsDialog.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/StorageEvictedDialog.tsx b/src/components/views/dialogs/StorageEvictedDialog.tsx
index 3e62d85a9a8..bdacbcbb514 100644
--- a/src/components/views/dialogs/StorageEvictedDialog.tsx
+++ b/src/components/views/dialogs/StorageEvictedDialog.tsx
@@ -1,7 +1,7 @@
 /*
 Copyright 2019-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/TermsDialog.tsx b/src/components/views/dialogs/TermsDialog.tsx
index 4d66e41b5a6..c71a77c85b1 100644
--- a/src/components/views/dialogs/TermsDialog.tsx
+++ b/src/components/views/dialogs/TermsDialog.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/TextInputDialog.tsx b/src/components/views/dialogs/TextInputDialog.tsx
index 811b79100ff..9d68668413f 100644
--- a/src/components/views/dialogs/TextInputDialog.tsx
+++ b/src/components/views/dialogs/TextInputDialog.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/UnpinAllDialog.tsx b/src/components/views/dialogs/UnpinAllDialog.tsx
index 4d66a339ce9..f2390a978cc 100644
--- a/src/components/views/dialogs/UnpinAllDialog.tsx
+++ b/src/components/views/dialogs/UnpinAllDialog.tsx
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2024 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/src/components/views/dialogs/UntrustedDeviceDialog.tsx b/src/components/views/dialogs/UntrustedDeviceDialog.tsx
index 4b37032207b..ad1b2df7dc7 100644
--- a/src/components/views/dialogs/UntrustedDeviceDialog.tsx
+++ b/src/components/views/dialogs/UntrustedDeviceDialog.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019, 2020 , 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -11,10 +11,11 @@ import { User } from "matrix-js-sdk/src/matrix";
 
 import { _t } from "../../../languageHandler";
 import { MatrixClientPeg } from "../../../MatrixClientPeg";
-import E2EIcon, { E2EState } from "../rooms/E2EIcon";
+import E2EIcon from "../rooms/E2EIcon";
 import AccessibleButton from "../elements/AccessibleButton";
 import BaseDialog from "./BaseDialog";
 import { IDevice } from "../right_panel/UserInfo";
+import { E2EStatus } from "../../../utils/ShieldUtils";
 
 interface IProps {
     /**
@@ -54,7 +55,7 @@ const UntrustedDeviceDialog: React.FC<IProps> = ({ device, user, onFinished }) =
             className="mx_UntrustedDeviceDialog"
             title={
                 <>
-                    <E2EIcon status={E2EState.Warning} isUser size={24} hideTooltip={true} />
+                    <E2EIcon status={E2EStatus.Warning} isUser size={24} hideTooltip={true} />
                     {_t("encryption|udd|title")}
                 </>
             }
diff --git a/src/components/views/dialogs/UploadConfirmDialog.tsx b/src/components/views/dialogs/UploadConfirmDialog.tsx
index 7fdb601c44b..83459c7ed73 100644
--- a/src/components/views/dialogs/UploadConfirmDialog.tsx
+++ b/src/components/views/dialogs/UploadConfirmDialog.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019-2021 The Matrix.org Foundation C.I.C.
 Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/UploadFailureDialog.tsx b/src/components/views/dialogs/UploadFailureDialog.tsx
index ca7b1c14fdc..7e98fb24b32 100644
--- a/src/components/views/dialogs/UploadFailureDialog.tsx
+++ b/src/components/views/dialogs/UploadFailureDialog.tsx
@@ -1,7 +1,7 @@
 /*
 Copyright 2019-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/UserSettingsDialog.tsx b/src/components/views/dialogs/UserSettingsDialog.tsx
index 8ae7a302ac4..75739a7f454 100644
--- a/src/components/views/dialogs/UserSettingsDialog.tsx
+++ b/src/components/views/dialogs/UserSettingsDialog.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019-2024 The Matrix.org Foundation C.I.C.
 Copyright 2019 New Vector Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -15,6 +15,7 @@ import VisibilityOnIcon from "@vector-im/compound-design-tokens/assets/web/icons
 import NotificationsIcon from "@vector-im/compound-design-tokens/assets/web/icons/notifications";
 import PreferencesIcon from "@vector-im/compound-design-tokens/assets/web/icons/preferences";
 import KeyboardIcon from "@vector-im/compound-design-tokens/assets/web/icons/keyboard";
+import KeyIcon from "@vector-im/compound-design-tokens/assets/web/icons/key";
 import SidebarIcon from "@vector-im/compound-design-tokens/assets/web/icons/sidebar";
 import MicOnIcon from "@vector-im/compound-design-tokens/assets/web/icons/mic-on";
 import LockIcon from "@vector-im/compound-design-tokens/assets/web/icons/lock";
@@ -44,6 +45,7 @@ import { NonEmptyArray } from "../../../@types/common";
 import { SDKContext, SdkContextClass } from "../../../contexts/SDKContext";
 import { useSettingValue } from "../../../hooks/useSettings";
 import { ToastContext, useActiveToast } from "../../../contexts/ToastContext";
+import { EncryptionUserSettingsTab } from "../settings/tabs/user/EncryptionUserSettingsTab";
 
 interface IProps {
     initialTabId?: UserTab;
@@ -75,6 +77,8 @@ function titleForTabID(tabId: UserTab): React.ReactNode {
             return _t("settings|voip|dialog_title", undefined, subs);
         case UserTab.Security:
             return _t("settings|security|dialog_title", undefined, subs);
+        case UserTab.Encryption:
+            return _t("settings|encryption|dialog_title", undefined, subs);
         case UserTab.Labs:
             return _t("settings|labs|dialog_title", undefined, subs);
         case UserTab.Mjolnir:
@@ -85,8 +89,8 @@ function titleForTabID(tabId: UserTab): React.ReactNode {
 }
 
 export default function UserSettingsDialog(props: IProps): JSX.Element {
-    const voipEnabled = useSettingValue<boolean>(UIFeature.Voip);
-    const mjolnirEnabled = useSettingValue<boolean>("feature_mjolnir");
+    const voipEnabled = useSettingValue(UIFeature.Voip);
+    const mjolnirEnabled = useSettingValue("feature_mjolnir");
     // store this prop in state as changing tabs back and forth should clear it
     const [showMsc4108QrCode, setShowMsc4108QrCode] = useState(props.showMsc4108QrCode);
 
@@ -179,6 +183,10 @@ export default function UserSettingsDialog(props: IProps): JSX.Element {
             ),
         );
 
+        tabs.push(
+            new Tab(UserTab.Encryption, _td("settings|encryption|title"), <KeyIcon />, <EncryptionUserSettingsTab />),
+        );
+
         if (showLabsFlags() || SettingsStore.getFeatureSettingNames().some((k) => SettingsStore.getBetaInfo(k))) {
             tabs.push(
                 new Tab(UserTab.Labs, _td("common|labs"), <LabsIcon />, <LabsUserSettingsTab />, "UserSettingsLabs"),
diff --git a/src/components/views/dialogs/UserTab.ts b/src/components/views/dialogs/UserTab.ts
index 467a67cd9f6..323fc1e330c 100644
--- a/src/components/views/dialogs/UserTab.ts
+++ b/src/components/views/dialogs/UserTab.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -15,6 +15,7 @@ export enum UserTab {
     Sidebar = "USER_SIDEBAR_TAB",
     Voice = "USER_VOICE_TAB",
     Security = "USER_SECURITY_TAB",
+    Encryption = "USER_ENCRYPTION_TAB",
     Labs = "USER_LABS_TAB",
     Mjolnir = "USER_MJOLNIR_TAB",
     Help = "USER_HELP_TAB",
diff --git a/src/components/views/dialogs/VerificationRequestDialog.tsx b/src/components/views/dialogs/VerificationRequestDialog.tsx
index d2ea83f2af8..bb49abbf15a 100644
--- a/src/components/views/dialogs/VerificationRequestDialog.tsx
+++ b/src/components/views/dialogs/VerificationRequestDialog.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020, 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/WidgetCapabilitiesPromptDialog.tsx b/src/components/views/dialogs/WidgetCapabilitiesPromptDialog.tsx
index 1a94f0a9fd9..7e57d957086 100644
--- a/src/components/views/dialogs/WidgetCapabilitiesPromptDialog.tsx
+++ b/src/components/views/dialogs/WidgetCapabilitiesPromptDialog.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020, 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/WidgetOpenIDPermissionsDialog.tsx b/src/components/views/dialogs/WidgetOpenIDPermissionsDialog.tsx
index 263f5127b7d..4c1e8a9d326 100644
--- a/src/components/views/dialogs/WidgetOpenIDPermissionsDialog.tsx
+++ b/src/components/views/dialogs/WidgetOpenIDPermissionsDialog.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 Copyright 2019 Travis Ralston
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/devtools/AccountData.tsx b/src/components/views/dialogs/devtools/AccountData.tsx
index f1fc081b009..402aa396d15 100644
--- a/src/components/views/dialogs/devtools/AccountData.tsx
+++ b/src/components/views/dialogs/devtools/AccountData.tsx
@@ -3,12 +3,12 @@ Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 Copyright 2022 Michael Telatynski <7t3chguy@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 import React, { useContext, useMemo, useState } from "react";
-import { IContent, MatrixEvent } from "matrix-js-sdk/src/matrix";
+import { AccountDataEvents, IContent, MatrixEvent } from "matrix-js-sdk/src/matrix";
 
 import BaseTool, { DevtoolsContext, IDevtoolsProps } from "./BaseTool";
 import MatrixClientContext from "../../../../contexts/MatrixClientContext";
@@ -21,7 +21,7 @@ export const AccountDataEventEditor: React.FC<IEditorProps> = ({ mxEvent, onBack
 
     const fields = useMemo(() => [eventTypeField(mxEvent?.getType())], [mxEvent]);
 
-    const onSend = async ([eventType]: string[], content?: IContent): Promise<void> => {
+    const onSend = async ([eventType]: Array<keyof AccountDataEvents>, content?: IContent): Promise<void> => {
         await cli.setAccountData(eventType, content || {});
     };
 
diff --git a/src/components/views/dialogs/devtools/BaseTool.tsx b/src/components/views/dialogs/devtools/BaseTool.tsx
index 88dd2ea1785..adc13d2eab8 100644
--- a/src/components/views/dialogs/devtools/BaseTool.tsx
+++ b/src/components/views/dialogs/devtools/BaseTool.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 Copyright 2022 Michael Telatynski <7t3chguy@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/devtools/Event.tsx b/src/components/views/dialogs/devtools/Event.tsx
index f9fc68da221..a0f7bfece54 100644
--- a/src/components/views/dialogs/devtools/Event.tsx
+++ b/src/components/views/dialogs/devtools/Event.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 Copyright 2022 Michael Telatynski <7t3chguy@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/devtools/FilteredList.tsx b/src/components/views/dialogs/devtools/FilteredList.tsx
index 400c646958c..0f0c52df94f 100644
--- a/src/components/views/dialogs/devtools/FilteredList.tsx
+++ b/src/components/views/dialogs/devtools/FilteredList.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 Copyright 2022 Michael Telatynski <7t3chguy@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/devtools/RoomNotifications.tsx b/src/components/views/dialogs/devtools/RoomNotifications.tsx
index 1bcff784879..a7c8bb7dde8 100644
--- a/src/components/views/dialogs/devtools/RoomNotifications.tsx
+++ b/src/components/views/dialogs/devtools/RoomNotifications.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/devtools/RoomState.tsx b/src/components/views/dialogs/devtools/RoomState.tsx
index a331a19147e..8831ccc8056 100644
--- a/src/components/views/dialogs/devtools/RoomState.tsx
+++ b/src/components/views/dialogs/devtools/RoomState.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 Copyright 2022 Michael Telatynski <7t3chguy@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/devtools/ServerInfo.tsx b/src/components/views/dialogs/devtools/ServerInfo.tsx
index 337ed421770..85780b8fd93 100644
--- a/src/components/views/dialogs/devtools/ServerInfo.tsx
+++ b/src/components/views/dialogs/devtools/ServerInfo.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 Michael Telatynski <7t3chguy@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/devtools/ServersInRoom.tsx b/src/components/views/dialogs/devtools/ServersInRoom.tsx
index fdb4a2f0702..e7b90c97944 100644
--- a/src/components/views/dialogs/devtools/ServersInRoom.tsx
+++ b/src/components/views/dialogs/devtools/ServersInRoom.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 Copyright 2022 Michael Telatynski <7t3chguy@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/devtools/SettingExplorer.tsx b/src/components/views/dialogs/devtools/SettingExplorer.tsx
index ae37fa3e1c9..b9919973ebf 100644
--- a/src/components/views/dialogs/devtools/SettingExplorer.tsx
+++ b/src/components/views/dialogs/devtools/SettingExplorer.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2018-2023 The Matrix.org Foundation C.I.C.
 Copyright 2022 Michael Telatynski <7t3chguy@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -15,11 +15,11 @@ import BaseTool, { DevtoolsContext, IDevtoolsProps } from "./BaseTool";
 import AccessibleButton from "../../elements/AccessibleButton";
 import SettingsStore, { LEVEL_ORDER } from "../../../../settings/SettingsStore";
 import { SettingLevel } from "../../../../settings/SettingLevel";
-import { SETTINGS } from "../../../../settings/Settings";
+import { SettingKey, SETTINGS, SettingValueType } from "../../../../settings/Settings";
 import Field from "../../elements/Field";
 
 const SettingExplorer: React.FC<IDevtoolsProps> = ({ onBack }) => {
-    const [setting, setSetting] = useState<string | null>(null);
+    const [setting, setSetting] = useState<SettingKey | null>(null);
     const [editing, setEditing] = useState(false);
 
     if (setting && editing) {
@@ -36,10 +36,10 @@ const SettingExplorer: React.FC<IDevtoolsProps> = ({ onBack }) => {
         };
         return <ViewSetting setting={setting} onBack={onBack} onEdit={onEdit} />;
     } else {
-        const onView = (setting: string): void => {
+        const onView = (setting: SettingKey): void => {
             setSetting(setting);
         };
-        const onEdit = (setting: string): void => {
+        const onEdit = (setting: SettingKey): void => {
             setSetting(setting);
             setEditing(true);
         };
@@ -50,7 +50,7 @@ const SettingExplorer: React.FC<IDevtoolsProps> = ({ onBack }) => {
 export default SettingExplorer;
 
 interface ICanEditLevelFieldProps {
-    setting: string;
+    setting: SettingKey;
     level: SettingLevel;
     roomId?: string;
 }
@@ -65,8 +65,8 @@ const CanEditLevelField: React.FC<ICanEditLevelFieldProps> = ({ setting, roomId,
     );
 };
 
-function renderExplicitSettingValues(setting: string, roomId?: string): string {
-    const vals: Record<string, number | null> = {};
+function renderExplicitSettingValues(setting: SettingKey, roomId?: string): string {
+    const vals: Record<string, SettingValueType> = {};
     for (const level of LEVEL_ORDER) {
         try {
             vals[level] = SettingsStore.getValueAt(level, setting, roomId, true, true);
@@ -81,7 +81,7 @@ function renderExplicitSettingValues(setting: string, roomId?: string): string {
 }
 
 interface IEditSettingProps extends Pick<IDevtoolsProps, "onBack"> {
-    setting: string;
+    setting: SettingKey;
 }
 
 const EditSetting: React.FC<IEditSettingProps> = ({ setting, onBack }) => {
@@ -191,7 +191,7 @@ const EditSetting: React.FC<IEditSettingProps> = ({ setting, onBack }) => {
 };
 
 interface IViewSettingProps extends Pick<IDevtoolsProps, "onBack"> {
-    setting: string;
+    setting: SettingKey;
     onEdit(): Promise<void>;
 }
 
@@ -258,7 +258,7 @@ const SettingsList: React.FC<ISettingsListProps> = ({ onBack, onView, onEdit })
     const [query, setQuery] = useState("");
 
     const allSettings = useMemo(() => {
-        let allSettings = Object.keys(SETTINGS);
+        let allSettings = Object.keys(SETTINGS) as SettingKey[];
         if (query) {
             const lcQuery = query.toLowerCase();
             allSettings = allSettings.filter((setting) => setting.toLowerCase().includes(lcQuery));
diff --git a/src/components/views/dialogs/devtools/WidgetExplorer.tsx b/src/components/views/dialogs/devtools/WidgetExplorer.tsx
index 6fad8980317..5bcae191417 100644
--- a/src/components/views/dialogs/devtools/WidgetExplorer.tsx
+++ b/src/components/views/dialogs/devtools/WidgetExplorer.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 Copyright 2022 Michael Telatynski <7t3chguy@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/oidc/OidcLogoutDialog.tsx b/src/components/views/dialogs/oidc/OidcLogoutDialog.tsx
deleted file mode 100644
index 83bcd8736f8..00000000000
--- a/src/components/views/dialogs/oidc/OidcLogoutDialog.tsx
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2023 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
-Please see LICENSE files in the repository root for full details.
-*/
-
-import React, { useState } from "react";
-
-import { _t } from "../../../../languageHandler";
-import BaseDialog from "../BaseDialog";
-import { getOidcLogoutUrl } from "../../../../utils/oidc/getOidcLogoutUrl";
-import AccessibleButton from "../../elements/AccessibleButton";
-
-export interface OidcLogoutDialogProps {
-    delegatedAuthAccountUrl: string;
-    deviceId: string;
-    onFinished(ok?: boolean): void;
-}
-
-/**
- * Handle logout of OIDC sessions other than the current session
- * - ask for user confirmation to open the delegated auth provider
- * - open the auth provider in a new tab
- * - wait for the user to return and close the modal, we assume the user has completed sign out of the session in auth provider UI
- *        and trigger a refresh of the session list
- */
-export const OidcLogoutDialog: React.FC<OidcLogoutDialogProps> = ({
-    delegatedAuthAccountUrl,
-    deviceId,
-    onFinished,
-}) => {
-    const [hasOpenedLogoutLink, setHasOpenedLogoutLink] = useState(false);
-    const logoutUrl = getOidcLogoutUrl(delegatedAuthAccountUrl, deviceId);
-
-    return (
-        <BaseDialog onFinished={onFinished} title={_t("action|sign_out")} contentId="mx_Dialog_content">
-            <div className="mx_Dialog_content" id="mx_Dialog_content">
-                {_t("auth|oidc|logout_redirect_warning")}
-            </div>
-            <div className="mx_Dialog_buttons">
-                {hasOpenedLogoutLink ? (
-                    <AccessibleButton kind="primary" onClick={() => onFinished(true)}>
-                        {_t("action|close")}
-                    </AccessibleButton>
-                ) : (
-                    <>
-                        <AccessibleButton kind="secondary" onClick={() => onFinished(false)}>
-                            {_t("action|cancel")}
-                        </AccessibleButton>
-                        <AccessibleButton
-                            element="a"
-                            onClick={() => setHasOpenedLogoutLink(true)}
-                            kind="primary"
-                            href={logoutUrl}
-                            target="_blank"
-                        >
-                            {_t("action|continue")}
-                        </AccessibleButton>
-                    </>
-                )}
-            </div>
-        </BaseDialog>
-    );
-};
diff --git a/src/components/views/dialogs/security/AccessSecretStorageDialog.tsx b/src/components/views/dialogs/security/AccessSecretStorageDialog.tsx
index d9c97261dd3..a6d81ae2cef 100644
--- a/src/components/views/dialogs/security/AccessSecretStorageDialog.tsx
+++ b/src/components/views/dialogs/security/AccessSecretStorageDialog.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2018-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/security/ConfirmDestroyCrossSigningDialog.tsx b/src/components/views/dialogs/security/ConfirmDestroyCrossSigningDialog.tsx
index fbcc2bef115..5e3136c5ad6 100644
--- a/src/components/views/dialogs/security/ConfirmDestroyCrossSigningDialog.tsx
+++ b/src/components/views/dialogs/security/ConfirmDestroyCrossSigningDialog.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/security/InitialCryptoSetupDialog.tsx b/src/components/views/dialogs/security/InitialCryptoSetupDialog.tsx
index 22635662ce5..bda09f02a61 100644
--- a/src/components/views/dialogs/security/InitialCryptoSetupDialog.tsx
+++ b/src/components/views/dialogs/security/InitialCryptoSetupDialog.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
 Copyright 2018, 2019 New Vector Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/security/RestoreKeyBackupDialog.tsx b/src/components/views/dialogs/security/RestoreKeyBackupDialog.tsx
index fddba10948b..ca0a5e877e9 100644
--- a/src/components/views/dialogs/security/RestoreKeyBackupDialog.tsx
+++ b/src/components/views/dialogs/security/RestoreKeyBackupDialog.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 Copyright 2018, 2019 New Vector Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/security/SetupEncryptionDialog.tsx b/src/components/views/dialogs/security/SetupEncryptionDialog.tsx
index c0dc8b4915e..2f845b627a9 100644
--- a/src/components/views/dialogs/security/SetupEncryptionDialog.tsx
+++ b/src/components/views/dialogs/security/SetupEncryptionDialog.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/spotlight/Filter.ts b/src/components/views/dialogs/spotlight/Filter.ts
index fa4359db479..944b55a1fe5 100644
--- a/src/components/views/dialogs/spotlight/Filter.ts
+++ b/src/components/views/dialogs/spotlight/Filter.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021-2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/spotlight/Option.tsx b/src/components/views/dialogs/spotlight/Option.tsx
index 6de93d05125..ac568afe26c 100644
--- a/src/components/views/dialogs/spotlight/Option.tsx
+++ b/src/components/views/dialogs/spotlight/Option.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/spotlight/PublicRoomResultDetails.tsx b/src/components/views/dialogs/spotlight/PublicRoomResultDetails.tsx
index d2003473b9f..3e1025a81f8 100644
--- a/src/components/views/dialogs/spotlight/PublicRoomResultDetails.tsx
+++ b/src/components/views/dialogs/spotlight/PublicRoomResultDetails.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/spotlight/RoomResultContextMenus.tsx b/src/components/views/dialogs/spotlight/RoomResultContextMenus.tsx
index 667cc7980a7..f7b8311f983 100644
--- a/src/components/views/dialogs/spotlight/RoomResultContextMenus.tsx
+++ b/src/components/views/dialogs/spotlight/RoomResultContextMenus.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021, 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/spotlight/SpotlightDialog.tsx b/src/components/views/dialogs/spotlight/SpotlightDialog.tsx
index a87b7341e7d..e4f9b11e676 100644
--- a/src/components/views/dialogs/spotlight/SpotlightDialog.tsx
+++ b/src/components/views/dialogs/spotlight/SpotlightDialog.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021-2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/dialogs/spotlight/TooltipOption.tsx b/src/components/views/dialogs/spotlight/TooltipOption.tsx
index ebb0b4cf06e..26d0dcada84 100644
--- a/src/components/views/dialogs/spotlight/TooltipOption.tsx
+++ b/src/components/views/dialogs/spotlight/TooltipOption.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/directory/NetworkDropdown.tsx b/src/components/views/directory/NetworkDropdown.tsx
index a1b1986f471..c2a7a11b98b 100644
--- a/src/components/views/directory/NetworkDropdown.tsx
+++ b/src/components/views/directory/NetworkDropdown.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -26,6 +26,7 @@ import {
 import TextInputDialog from "../dialogs/TextInputDialog";
 import AccessibleButton from "../elements/AccessibleButton";
 import withValidation from "../elements/Validation";
+import { SettingKey, Settings } from "../../../settings/Settings.tsx";
 
 const SETTING_NAME = "room_directory_servers";
 
@@ -67,15 +68,32 @@ const validServer = withValidation<undefined, { error?: unknown }>({
     memoize: true,
 });
 
-function useSettingsValueWithSetter<T>(
-    settingName: string,
+function useSettingsValueWithSetter<S extends SettingKey>(
+    settingName: S,
+    level: SettingLevel,
+    roomId: string | null,
+    excludeDefault: true,
+): [Settings[S]["default"] | undefined, (value: Settings[S]["default"]) => Promise<void>];
+function useSettingsValueWithSetter<S extends SettingKey>(
+    settingName: S,
+    level: SettingLevel,
+    roomId?: string | null,
+    excludeDefault?: false,
+): [Settings[S]["default"], (value: Settings[S]["default"]) => Promise<void>];
+function useSettingsValueWithSetter<S extends SettingKey>(
+    settingName: S,
     level: SettingLevel,
     roomId: string | null = null,
     excludeDefault = false,
-): [T, (value: T) => Promise<void>] {
-    const [value, setValue] = useState(SettingsStore.getValue<T>(settingName, roomId ?? undefined, excludeDefault));
+): [Settings[S]["default"] | undefined, (value: Settings[S]["default"]) => Promise<void>] {
+    const [value, setValue] = useState(
+        // XXX: This seems naff but is needed to convince TypeScript that the overload is fine
+        excludeDefault
+            ? SettingsStore.getValue(settingName, roomId, excludeDefault)
+            : SettingsStore.getValue(settingName, roomId, excludeDefault),
+    );
     const setter = useCallback(
-        async (value: T): Promise<void> => {
+        async (value: Settings[S]["default"]): Promise<void> => {
             setValue(value);
             SettingsStore.setValue(settingName, roomId, level, value);
         },
@@ -84,7 +102,12 @@ function useSettingsValueWithSetter<T>(
 
     useEffect(() => {
         const ref = SettingsStore.watchSetting(settingName, roomId, () => {
-            setValue(SettingsStore.getValue<T>(settingName, roomId, excludeDefault));
+            setValue(
+                // XXX: This seems naff but is needed to convince TypeScript that the overload is fine
+                excludeDefault
+                    ? SettingsStore.getValue(settingName, roomId, excludeDefault)
+                    : SettingsStore.getValue(settingName, roomId, excludeDefault),
+            );
         });
         // clean-up
         return () => {
@@ -109,10 +132,7 @@ function removeAll<T>(target: Set<T>, ...toRemove: T[]): void {
 }
 
 function useServers(): ServerList {
-    const [userDefinedServers, setUserDefinedServers] = useSettingsValueWithSetter<string[]>(
-        SETTING_NAME,
-        SettingLevel.ACCOUNT,
-    );
+    const [userDefinedServers, setUserDefinedServers] = useSettingsValueWithSetter(SETTING_NAME, SettingLevel.ACCOUNT);
 
     const homeServer = MatrixClientPeg.safeGet().getDomain()!;
     const configServers = new Set<string>(SdkConfig.getObject("room_directory")?.get("servers") ?? []);
diff --git a/src/components/views/elements/AccessibleButton.tsx b/src/components/views/elements/AccessibleButton.tsx
index 8b58f251c36..f12b36359b6 100644
--- a/src/components/views/elements/AccessibleButton.tsx
+++ b/src/components/views/elements/AccessibleButton.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2016 Jani Mustonen
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/src/components/views/elements/AppPermission.tsx b/src/components/views/elements/AppPermission.tsx
index 846cc2625a7..c6ac9d2f50c 100644
--- a/src/components/views/elements/AppPermission.tsx
+++ b/src/components/views/elements/AppPermission.tsx
@@ -4,7 +4,7 @@ Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
 Copyright 2018, 2019 New Vector Ltd
 Copyright 2017 Vector Creations Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/AppTile.tsx b/src/components/views/elements/AppTile.tsx
index 56754f14a6b..8af4a95f93a 100644
--- a/src/components/views/elements/AppTile.tsx
+++ b/src/components/views/elements/AppTile.tsx
@@ -5,7 +5,7 @@ Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
 Copyright 2018 New Vector Ltd
 Copyright 2017 Vector Creations Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/AppWarning.tsx b/src/components/views/elements/AppWarning.tsx
index 4e43ca9c1ac..9f8a26e6cd8 100644
--- a/src/components/views/elements/AppWarning.tsx
+++ b/src/components/views/elements/AppWarning.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/CopyableText.tsx b/src/components/views/elements/CopyableText.tsx
index c7b0df06793..02c1b145637 100644
--- a/src/components/views/elements/CopyableText.tsx
+++ b/src/components/views/elements/CopyableText.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2022 Šimon Brandner <simon.bra.ag@gmail.com>
 Copyright 2019-2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/DesktopCapturerSourcePicker.tsx b/src/components/views/elements/DesktopCapturerSourcePicker.tsx
index e1f1def8360..2e100e767c0 100644
--- a/src/components/views/elements/DesktopCapturerSourcePicker.tsx
+++ b/src/components/views/elements/DesktopCapturerSourcePicker.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/DialPadBackspaceButton.tsx b/src/components/views/elements/DialPadBackspaceButton.tsx
index 4165b9077d6..7ebf9694b39 100644
--- a/src/components/views/elements/DialPadBackspaceButton.tsx
+++ b/src/components/views/elements/DialPadBackspaceButton.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/DialogButtons.tsx b/src/components/views/elements/DialogButtons.tsx
index 7b49c9af5ab..defee130bc7 100644
--- a/src/components/views/elements/DialogButtons.tsx
+++ b/src/components/views/elements/DialogButtons.tsx
@@ -4,7 +4,7 @@ Copyright 2019 The Matrix.org Foundation C.I.C.
 Copyright 2018 New Vector Ltd.
 Copyright 2017 Aidan Gauland
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/Draggable.tsx b/src/components/views/elements/Draggable.tsx
index 69209f383ee..959ed8ff983 100644
--- a/src/components/views/elements/Draggable.tsx
+++ b/src/components/views/elements/Draggable.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/Dropdown.tsx b/src/components/views/elements/Dropdown.tsx
index a7ce84163c7..b4d0df69dfb 100644
--- a/src/components/views/elements/Dropdown.tsx
+++ b/src/components/views/elements/Dropdown.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2017-2021 The Matrix.org Foundation C.I.C.
 Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/EditableItemList.tsx b/src/components/views/elements/EditableItemList.tsx
index ad2d9aceee7..134c6151947 100644
--- a/src/components/views/elements/EditableItemList.tsx
+++ b/src/components/views/elements/EditableItemList.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2017-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/EditableText.tsx b/src/components/views/elements/EditableText.tsx
index f31660854e8..1e1d00d14c2 100644
--- a/src/components/views/elements/EditableText.tsx
+++ b/src/components/views/elements/EditableText.tsx
@@ -2,7 +2,7 @@
 Copyright 2018-2024 New Vector Ltd.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/EffectsOverlay.tsx b/src/components/views/elements/EffectsOverlay.tsx
index 3e5a5ead60a..68733b4ceb1 100644
--- a/src/components/views/elements/EffectsOverlay.tsx
+++ b/src/components/views/elements/EffectsOverlay.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2020 Nurjin Jafar
 Copyright 2020 Nordeck IT + Consulting GmbH.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
  */
 import React, { FunctionComponent, useEffect, useRef } from "react";
diff --git a/src/components/views/elements/ErrorBoundary.tsx b/src/components/views/elements/ErrorBoundary.tsx
index 98e38350fdf..6ea625cec0e 100644
--- a/src/components/views/elements/ErrorBoundary.tsx
+++ b/src/components/views/elements/ErrorBoundary.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/EventListSummary.tsx b/src/components/views/elements/EventListSummary.tsx
index 776908375a1..79d89aed0d0 100644
--- a/src/components/views/elements/EventListSummary.tsx
+++ b/src/components/views/elements/EventListSummary.tsx
@@ -4,13 +4,14 @@ Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
 Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
 Copyright 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 import React, { ComponentProps, ReactNode } from "react";
-import { MatrixEvent, RoomMember, EventType } from "matrix-js-sdk/src/matrix";
+import { EventType, MatrixEvent, MatrixEventEvent, RoomMember } from "matrix-js-sdk/src/matrix";
 import { KnownMembership } from "matrix-js-sdk/src/types";
+import { throttle } from "lodash";
 
 import { _t } from "../../../languageHandler";
 import { formatList } from "../../../utils/FormattingUtils";
@@ -22,6 +23,8 @@ import { Layout } from "../../../settings/enums/Layout";
 import RightPanelStore from "../../../stores/right-panel/RightPanelStore";
 import AccessibleButton from "./AccessibleButton";
 import RoomContext from "../../../contexts/RoomContext";
+import { arrayHasDiff } from "../../../utils/arrays.ts";
+import { objectHasDiff } from "../../../utils/objects.ts";
 
 const onPinnedMessagesClick = (): void => {
     RightPanelStore.instance.setCard({ phase: RightPanelPhases.PinnedMessages }, false);
@@ -69,9 +72,14 @@ enum TransitionType {
 
 const SEP = ",";
 
-export default class EventListSummary extends React.Component<
-    IProps & Required<Pick<IProps, "summaryLength" | "threshold" | "avatarsMaxLength" | "layout">>
-> {
+type Props = IProps & Required<Pick<IProps, "summaryLength" | "threshold" | "avatarsMaxLength" | "layout">>;
+
+interface State {
+    userEvents: Record<string, IUserEvents[]>;
+    summaryMembers: RoomMember[];
+}
+
+export default class EventListSummary extends React.Component<Props, State> {
     public static contextType = RoomContext;
     declare public context: React.ContextType<typeof RoomContext>;
 
@@ -82,15 +90,122 @@ export default class EventListSummary extends React.Component<
         layout: Layout.Group,
     };
 
-    public shouldComponentUpdate(nextProps: IProps): boolean {
+    public constructor(props: Props) {
+        super(props);
+
+        this.state = this.generateState();
+    }
+
+    private generateState(): State {
+        const eventsToRender = this.props.events;
+
+        // Map user IDs to latest Avatar Member. ES6 Maps are ordered by when the key was created,
+        // so this works perfectly for us to match event order whilst storing the latest Avatar Member
+        const latestUserAvatarMember = new Map<string, RoomMember>();
+
+        // Object mapping user IDs to an array of IUserEvents
+        const userEvents: Record<string, IUserEvents[]> = {};
+        eventsToRender.forEach((e, index) => {
+            const type = e.getType();
+
+            let userKey = e.getSender()!;
+            if (e.isState() && type === EventType.RoomThirdPartyInvite) {
+                userKey = e.getContent().display_name;
+            } else if (e.isState() && type === EventType.RoomMember) {
+                userKey = e.getStateKey()!;
+            } else if (e.isRedacted() && e.getUnsigned()?.redacted_because) {
+                userKey = e.getUnsigned().redacted_because!.sender;
+            }
+
+            // Initialise a user's events
+            if (!userEvents[userKey]) {
+                userEvents[userKey] = [];
+            }
+
+            let displayName = userKey;
+            if (e.isRedacted()) {
+                const sender = this.context?.room?.getMember(userKey);
+                if (sender) {
+                    displayName = sender.name;
+                    latestUserAvatarMember.set(userKey, sender);
+                }
+            } else if (e.target && TARGET_AS_DISPLAY_NAME_EVENTS.includes(type as EventType)) {
+                displayName = e.target.name;
+                latestUserAvatarMember.set(userKey, e.target);
+            } else if (e.sender && type !== EventType.RoomThirdPartyInvite) {
+                displayName = e.sender.name;
+                latestUserAvatarMember.set(userKey, e.sender);
+            }
+
+            userEvents[userKey].push({
+                mxEvent: e,
+                displayName,
+                index: index,
+            });
+        });
+
+        return {
+            userEvents,
+            summaryMembers: Array.from(latestUserAvatarMember.values()),
+        };
+    }
+
+    public componentDidMount(): void {
+        this.bindSentinelListeners(this.props.events);
+    }
+
+    public componentDidUpdate(prevProps: Readonly<Props>): void {
+        if (prevProps.events !== this.props.events) {
+            this.unbindSentinelListeners(prevProps.events);
+            this.bindSentinelListeners(this.props.events);
+            this.setState(this.generateState());
+        }
+    }
+
+    public componentWillUnmount(): void {
+        this.unbindSentinelListeners(this.props.events);
+    }
+
+    private bindSentinelListeners(events: MatrixEvent[]): void {
+        for (const event of events) {
+            event.on(MatrixEventEvent.SentinelUpdated, this.onEventSentinelUpdated);
+        }
+    }
+
+    private unbindSentinelListeners(events: MatrixEvent[]): void {
+        for (const event of events) {
+            event.on(MatrixEventEvent.SentinelUpdated, this.onEventSentinelUpdated);
+        }
+    }
+
+    private onEventSentinelUpdated = throttle(
+        (): void => {
+            console.log("@@ SENTINEL UPDATED");
+            this.setState(this.generateState());
+        },
+        500,
+        { leading: true, trailing: true },
+    );
+
+    public shouldComponentUpdate(nextProps: Props, nextState: State): boolean {
         // Update if
         //  - The number of summarised events has changed
         //  - or if the summary is about to toggle to become collapsed
         //  - or if there are fewEvents, meaning the child eventTiles are shown as-is
+        //  - or if the summary members have changed
+        //  - or if the one of IUserEvents within userEvents have changed
         return (
             nextProps.events.length !== this.props.events.length ||
             nextProps.events.length < this.props.threshold ||
-            nextProps.layout !== this.props.layout
+            nextProps.layout !== this.props.layout ||
+            arrayHasDiff(nextState.summaryMembers, this.state.summaryMembers) ||
+            arrayHasDiff(Object.values(nextState.userEvents), Object.values(this.state.userEvents)) ||
+            Object.keys(nextState.userEvents).length !== Object.keys(this.state.userEvents).length ||
+            Object.keys(nextState.userEvents).some((userId) =>
+                nextState.userEvents[userId].some((event, i) =>
+                    objectHasDiff(event, this.state.userEvents[userId]?.[i] ?? {}),
+                ),
+            )
         );
     }
 
@@ -492,54 +607,7 @@ export default class EventListSummary extends React.Component<
     }
 
     public render(): React.ReactNode {
-        const eventsToRender = this.props.events;
-
-        // Map user IDs to latest Avatar Member. ES6 Maps are ordered by when the key was created,
-        // so this works perfectly for us to match event order whilst storing the latest Avatar Member
-        const latestUserAvatarMember = new Map<string, RoomMember>();
-
-        // Object mapping user IDs to an array of IUserEvents
-        const userEvents: Record<string, IUserEvents[]> = {};
-        eventsToRender.forEach((e, index) => {
-            const type = e.getType();
-
-            let userKey = e.getSender()!;
-            if (e.isState() && type === EventType.RoomThirdPartyInvite) {
-                userKey = e.getContent().display_name;
-            } else if (e.isState() && type === EventType.RoomMember) {
-                userKey = e.getStateKey()!;
-            } else if (e.isRedacted() && e.getUnsigned()?.redacted_because) {
-                userKey = e.getUnsigned().redacted_because!.sender;
-            }
-
-            // Initialise a user's events
-            if (!userEvents[userKey]) {
-                userEvents[userKey] = [];
-            }
-
-            let displayName = userKey;
-            if (e.isRedacted()) {
-                const sender = this.context?.room?.getMember(userKey);
-                if (sender) {
-                    displayName = sender.name;
-                    latestUserAvatarMember.set(userKey, sender);
-                }
-            } else if (e.target && TARGET_AS_DISPLAY_NAME_EVENTS.includes(type as EventType)) {
-                displayName = e.target.name;
-                latestUserAvatarMember.set(userKey, e.target);
-            } else if (e.sender && type !== EventType.RoomThirdPartyInvite) {
-                displayName = e.sender.name;
-                latestUserAvatarMember.set(userKey, e.sender);
-            }
-
-            userEvents[userKey].push({
-                mxEvent: e,
-                displayName,
-                index: index,
-            });
-        });
-
-        const aggregate = this.getAggregate(userEvents);
+        const aggregate = this.getAggregate(this.state.userEvents);
 
         // Sort types by order of lowest event index within sequence
         const orderedTransitionSequences = Object.keys(aggregate.names).sort(
@@ -554,7 +622,7 @@ export default class EventListSummary extends React.Component<
                 onToggle={this.props.onToggle}
                 startExpanded={this.props.startExpanded}
                 children={this.props.children}
-                summaryMembers={[...latestUserAvatarMember.values()]}
+                summaryMembers={this.state.summaryMembers}
                 layout={this.props.layout}
                 summaryText={this.generateSummary(aggregate.names, orderedTransitionSequences)}
             />
diff --git a/src/components/views/elements/EventTilePreview.tsx b/src/components/views/elements/EventTilePreview.tsx
index bc9a16283c9..dc276858bd9 100644
--- a/src/components/views/elements/EventTilePreview.tsx
+++ b/src/components/views/elements/EventTilePreview.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/ExternalLink.tsx b/src/components/views/elements/ExternalLink.tsx
index 4b56841eb18..8c30f6e2bd2 100644
--- a/src/components/views/elements/ExternalLink.tsx
+++ b/src/components/views/elements/ExternalLink.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/FacePile.tsx b/src/components/views/elements/FacePile.tsx
index 74a857953ce..49416a8d381 100644
--- a/src/components/views/elements/FacePile.tsx
+++ b/src/components/views/elements/FacePile.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/Field.tsx b/src/components/views/elements/Field.tsx
index 26e76bb0145..ea41582d620 100644
--- a/src/components/views/elements/Field.tsx
+++ b/src/components/views/elements/Field.tsx
@@ -1,7 +1,7 @@
 /*
 Copyright 2019-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/FilterDropdown.tsx b/src/components/views/elements/FilterDropdown.tsx
index 9a66ffcea14..63e0fca2432 100644
--- a/src/components/views/elements/FilterDropdown.tsx
+++ b/src/components/views/elements/FilterDropdown.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/FilterTabGroup.tsx b/src/components/views/elements/FilterTabGroup.tsx
index 6129cd12195..b63d96bdd33 100644
--- a/src/components/views/elements/FilterTabGroup.tsx
+++ b/src/components/views/elements/FilterTabGroup.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/GenericEventListSummary.tsx b/src/components/views/elements/GenericEventListSummary.tsx
index ae20d186ba1..11da97f76bb 100644
--- a/src/components/views/elements/GenericEventListSummary.tsx
+++ b/src/components/views/elements/GenericEventListSummary.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/IRCTimelineProfileResizer.tsx b/src/components/views/elements/IRCTimelineProfileResizer.tsx
index d653361e3e1..625ea2cb530 100644
--- a/src/components/views/elements/IRCTimelineProfileResizer.tsx
+++ b/src/components/views/elements/IRCTimelineProfileResizer.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/ImageView.tsx b/src/components/views/elements/ImageView.tsx
index 711a221994f..3a3006edc57 100644
--- a/src/components/views/elements/ImageView.tsx
+++ b/src/components/views/elements/ImageView.tsx
@@ -4,7 +4,7 @@ Copyright 2020, 2021 Šimon Brandner <simon.bra.ag@gmail.com>
 Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/InfoTooltip.tsx b/src/components/views/elements/InfoTooltip.tsx
index e840100f21d..7d62b81cb38 100644
--- a/src/components/views/elements/InfoTooltip.tsx
+++ b/src/components/views/elements/InfoTooltip.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/InlineSpinner.tsx b/src/components/views/elements/InlineSpinner.tsx
index 868bdb5d6a6..7c1bde36b48 100644
--- a/src/components/views/elements/InlineSpinner.tsx
+++ b/src/components/views/elements/InlineSpinner.tsx
@@ -1,7 +1,7 @@
 /*
 Copyright 2017-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/InviteReason.tsx b/src/components/views/elements/InviteReason.tsx
index ea79f33e5d7..fd44b5a4185 100644
--- a/src/components/views/elements/InviteReason.tsx
+++ b/src/components/views/elements/InviteReason.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/JoinRuleDropdown.tsx b/src/components/views/elements/JoinRuleDropdown.tsx
index 19afdc828c9..7e678b02e67 100644
--- a/src/components/views/elements/JoinRuleDropdown.tsx
+++ b/src/components/views/elements/JoinRuleDropdown.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/LabelledCheckbox.tsx b/src/components/views/elements/LabelledCheckbox.tsx
index f46de7f1629..ea7b5d2b04d 100644
--- a/src/components/views/elements/LabelledCheckbox.tsx
+++ b/src/components/views/elements/LabelledCheckbox.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/LabelledToggleSwitch.tsx b/src/components/views/elements/LabelledToggleSwitch.tsx
index 34c08c252fe..bbc1344efd4 100644
--- a/src/components/views/elements/LabelledToggleSwitch.tsx
+++ b/src/components/views/elements/LabelledToggleSwitch.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/LanguageDropdown.tsx b/src/components/views/elements/LanguageDropdown.tsx
index 27b4b2b31ce..743e0df1f70 100644
--- a/src/components/views/elements/LanguageDropdown.tsx
+++ b/src/components/views/elements/LanguageDropdown.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2017 Marcel Radzio (MTRNord)
 Copyright 2017 Vector Creations Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -105,7 +105,7 @@ export default class LanguageDropdown extends React.Component<IProps, IState> {
 
         // default value here too, otherwise we need to handle null / undefined
         // values between mounting and the initial value propagating
-        let language = SettingsStore.getValue<string | undefined>("language", null, /*excludeDefault:*/ true);
+        let language = SettingsStore.getValue("language", null, /*excludeDefault:*/ true);
         let value: string | undefined;
         if (language) {
             value = this.props.value || language;
diff --git a/src/components/views/elements/LazyRenderList.tsx b/src/components/views/elements/LazyRenderList.tsx
index 996a3981cec..c4a928ef666 100644
--- a/src/components/views/elements/LazyRenderList.tsx
+++ b/src/components/views/elements/LazyRenderList.tsx
@@ -1,7 +1,7 @@
 /*
 Copyright 2019-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/LearnMore.tsx b/src/components/views/elements/LearnMore.tsx
index 02e685de382..ac7ec099542 100644
--- a/src/components/views/elements/LearnMore.tsx
+++ b/src/components/views/elements/LearnMore.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/LinkWithTooltip.tsx b/src/components/views/elements/LinkWithTooltip.tsx
index 016297d9f1c..6265910bd8e 100644
--- a/src/components/views/elements/LinkWithTooltip.tsx
+++ b/src/components/views/elements/LinkWithTooltip.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/src/components/views/elements/Measured.tsx b/src/components/views/elements/Measured.tsx
index e2f9d14ddee..6a4abae2de0 100644
--- a/src/components/views/elements/Measured.tsx
+++ b/src/components/views/elements/Measured.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/MiniAvatarUploader.tsx b/src/components/views/elements/MiniAvatarUploader.tsx
index 452b206bef3..f5e22ecfab0 100644
--- a/src/components/views/elements/MiniAvatarUploader.tsx
+++ b/src/components/views/elements/MiniAvatarUploader.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/PersistedElement.tsx b/src/components/views/elements/PersistedElement.tsx
index 3feb8561453..410b96d037d 100644
--- a/src/components/views/elements/PersistedElement.tsx
+++ b/src/components/views/elements/PersistedElement.tsx
@@ -1,7 +1,7 @@
 /*
 Copyright 2018-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/PersistentApp.tsx b/src/components/views/elements/PersistentApp.tsx
index 5f720dc85e8..bd49b32dff0 100644
--- a/src/components/views/elements/PersistentApp.tsx
+++ b/src/components/views/elements/PersistentApp.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019-2022 The Matrix.org Foundation C.I.C.
 Copyright 2018 New Vector Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/Pill.tsx b/src/components/views/elements/Pill.tsx
index 14093587ad3..266312124a1 100644
--- a/src/components/views/elements/Pill.tsx
+++ b/src/components/views/elements/Pill.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2017-2019 , 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/PollCreateDialog.tsx b/src/components/views/elements/PollCreateDialog.tsx
index eb6a762bf39..37139ec0d0c 100644
--- a/src/components/views/elements/PollCreateDialog.tsx
+++ b/src/components/views/elements/PollCreateDialog.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021, 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/PowerSelector.tsx b/src/components/views/elements/PowerSelector.tsx
index 385d932b870..6c7c1889d42 100644
--- a/src/components/views/elements/PowerSelector.tsx
+++ b/src/components/views/elements/PowerSelector.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/ProgressBar.tsx b/src/components/views/elements/ProgressBar.tsx
index b0f4ccd9c57..eb16724d3ec 100644
--- a/src/components/views/elements/ProgressBar.tsx
+++ b/src/components/views/elements/ProgressBar.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020-2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/QRCode.tsx b/src/components/views/elements/QRCode.tsx
index 4eea8dc55e8..a60d5e66259 100644
--- a/src/components/views/elements/QRCode.tsx
+++ b/src/components/views/elements/QRCode.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/ReplyChain.tsx b/src/components/views/elements/ReplyChain.tsx
index 8e10ca3af90..d2b9cf079f5 100644
--- a/src/components/views/elements/ReplyChain.tsx
+++ b/src/components/views/elements/ReplyChain.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2017-2023 The Matrix.org Foundation C.I.C.
 Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/ResizeHandle.tsx b/src/components/views/elements/ResizeHandle.tsx
index 48909216636..a04f223e036 100644
--- a/src/components/views/elements/ResizeHandle.tsx
+++ b/src/components/views/elements/ResizeHandle.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/RoomAliasField.tsx b/src/components/views/elements/RoomAliasField.tsx
index faa0ccf1a64..e87d26a340b 100644
--- a/src/components/views/elements/RoomAliasField.tsx
+++ b/src/components/views/elements/RoomAliasField.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/RoomFacePile.tsx b/src/components/views/elements/RoomFacePile.tsx
index 642af48c070..9b65fb98ae8 100644
--- a/src/components/views/elements/RoomFacePile.tsx
+++ b/src/components/views/elements/RoomFacePile.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021, 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/RoomName.tsx b/src/components/views/elements/RoomName.tsx
index 169671f0571..9228a71cf06 100644
--- a/src/components/views/elements/RoomName.tsx
+++ b/src/components/views/elements/RoomName.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/RoomTopic.tsx b/src/components/views/elements/RoomTopic.tsx
index a23f396be51..4e71a65c4d6 100644
--- a/src/components/views/elements/RoomTopic.tsx
+++ b/src/components/views/elements/RoomTopic.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021, 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/SSOButtons.tsx b/src/components/views/elements/SSOButtons.tsx
index e2fd92e97bd..39355b18894 100644
--- a/src/components/views/elements/SSOButtons.tsx
+++ b/src/components/views/elements/SSOButtons.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/SearchWarning.tsx b/src/components/views/elements/SearchWarning.tsx
index e7c651c8020..6c6c4d82b1f 100644
--- a/src/components/views/elements/SearchWarning.tsx
+++ b/src/components/views/elements/SearchWarning.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/ServerPicker.tsx b/src/components/views/elements/ServerPicker.tsx
index e6d899dff52..b433aa5150b 100644
--- a/src/components/views/elements/ServerPicker.tsx
+++ b/src/components/views/elements/ServerPicker.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020, 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/SettingsFlag.tsx b/src/components/views/elements/SettingsFlag.tsx
index 07fa3fd7fd2..f3472f38893 100644
--- a/src/components/views/elements/SettingsFlag.tsx
+++ b/src/components/views/elements/SettingsFlag.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 Copyright 2017 Travis Ralston
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -15,11 +15,11 @@ import { _t } from "../../../languageHandler";
 import ToggleSwitch from "./ToggleSwitch";
 import StyledCheckbox from "./StyledCheckbox";
 import { SettingLevel } from "../../../settings/SettingLevel";
-import { defaultWatchManager } from "../../../settings/Settings";
+import { BooleanSettingKey, defaultWatchManager } from "../../../settings/Settings";
 
 interface IProps {
     // The setting must be a boolean
-    name: string;
+    name: BooleanSettingKey;
     level: SettingLevel;
     roomId?: string; // for per-room settings
     label?: string;
diff --git a/src/components/views/elements/SpellCheckLanguagesDropdown.tsx b/src/components/views/elements/SpellCheckLanguagesDropdown.tsx
index ce521c959a1..9d250831ff0 100644
--- a/src/components/views/elements/SpellCheckLanguagesDropdown.tsx
+++ b/src/components/views/elements/SpellCheckLanguagesDropdown.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -107,7 +107,7 @@ export default class SpellCheckLanguagesDropdown extends React.Component<
 
         // default value here too, otherwise we need to handle null / undefined;
         // values between mounting and the initial value propagating
-        let language = SettingsStore.getValue<string | undefined>("language", null, /*excludeDefault:*/ true);
+        let language = SettingsStore.getValue("language", null, /*excludeDefault:*/ true);
         let value: string | undefined;
         if (language) {
             value = this.props.value || language;
diff --git a/src/components/views/elements/Spinner.tsx b/src/components/views/elements/Spinner.tsx
index 0a080693e2b..ab23135a883 100644
--- a/src/components/views/elements/Spinner.tsx
+++ b/src/components/views/elements/Spinner.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/Spoiler.tsx b/src/components/views/elements/Spoiler.tsx
index 031700948d9..588da46c6f9 100644
--- a/src/components/views/elements/Spoiler.tsx
+++ b/src/components/views/elements/Spoiler.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 Sorunome
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/src/components/views/elements/StyledCheckbox.tsx b/src/components/views/elements/StyledCheckbox.tsx
index 83409b8f680..49d173cd7c5 100644
--- a/src/components/views/elements/StyledCheckbox.tsx
+++ b/src/components/views/elements/StyledCheckbox.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/StyledRadioButton.tsx b/src/components/views/elements/StyledRadioButton.tsx
index 01c30c837b9..01e4de1dad8 100644
--- a/src/components/views/elements/StyledRadioButton.tsx
+++ b/src/components/views/elements/StyledRadioButton.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/StyledRadioGroup.tsx b/src/components/views/elements/StyledRadioGroup.tsx
index 7e527aade57..b93a697bfb1 100644
--- a/src/components/views/elements/StyledRadioGroup.tsx
+++ b/src/components/views/elements/StyledRadioGroup.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/SyntaxHighlight.tsx b/src/components/views/elements/SyntaxHighlight.tsx
index 7570ea22ed4..d8c50e5789b 100644
--- a/src/components/views/elements/SyntaxHighlight.tsx
+++ b/src/components/views/elements/SyntaxHighlight.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 Copyright 2017 Michael Telatynski <7t3chguy@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/Tag.tsx b/src/components/views/elements/Tag.tsx
index b9f87806281..0c1676794eb 100644
--- a/src/components/views/elements/Tag.tsx
+++ b/src/components/views/elements/Tag.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022, 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/TagComposer.tsx b/src/components/views/elements/TagComposer.tsx
index 39dd85f814a..55071964bcd 100644
--- a/src/components/views/elements/TagComposer.tsx
+++ b/src/components/views/elements/TagComposer.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021-2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/TextWithTooltip.tsx b/src/components/views/elements/TextWithTooltip.tsx
index b589ce3635c..42d436ced41 100644
--- a/src/components/views/elements/TextWithTooltip.tsx
+++ b/src/components/views/elements/TextWithTooltip.tsx
@@ -1,7 +1,7 @@
 /*
 Copyright 2019-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/src/components/views/elements/ToggleSwitch.tsx b/src/components/views/elements/ToggleSwitch.tsx
index a6ed4fb4f1c..3ef4981d55b 100644
--- a/src/components/views/elements/ToggleSwitch.tsx
+++ b/src/components/views/elements/ToggleSwitch.tsx
@@ -2,7 +2,7 @@
 Copyright 2019-2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/TruncatedList.tsx b/src/components/views/elements/TruncatedList.tsx
index 073d5a91e43..8e7abc11047 100644
--- a/src/components/views/elements/TruncatedList.tsx
+++ b/src/components/views/elements/TruncatedList.tsx
@@ -2,7 +2,7 @@
 Copyright 2017-2024 New Vector Ltd.
 Copyright 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/UseCaseSelection.tsx b/src/components/views/elements/UseCaseSelection.tsx
deleted file mode 100644
index 2c64c2903af..00000000000
--- a/src/components/views/elements/UseCaseSelection.tsx
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2022 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
-Please see LICENSE files in the repository root for full details.
-*/
-
-import classNames from "classnames";
-import React, { useEffect, useState } from "react";
-
-import { _t } from "../../../languageHandler";
-import { UseCase } from "../../../settings/enums/UseCase";
-import SplashPage from "../../structures/SplashPage";
-import AccessibleButton from "../elements/AccessibleButton";
-import { UseCaseSelectionButton } from "./UseCaseSelectionButton";
-
-interface Props {
-    onFinished: (useCase: UseCase) => void;
-}
-
-const TIMEOUT = 1500;
-
-export function UseCaseSelection({ onFinished }: Props): JSX.Element {
-    const [selection, setSelected] = useState<UseCase | null>(null);
-
-    // Call onFinished 1.5s after `selection` becomes truthy, to give time for the animation to run
-    useEffect(() => {
-        if (selection) {
-            let handler: number | null = window.setTimeout(() => {
-                handler = null;
-                onFinished(selection);
-            }, TIMEOUT);
-            return () => {
-                if (handler !== null) clearTimeout(handler);
-                handler = null;
-            };
-        }
-    }, [selection, onFinished]);
-
-    return (
-        <SplashPage
-            className={classNames("mx_UseCaseSelection", {
-                mx_UseCaseSelection_selected: selection !== null,
-            })}
-        >
-            <div className="mx_UseCaseSelection_title mx_UseCaseSelection_slideIn">
-                <h1>{_t("onboarding|use_case_heading1")}</h1>
-            </div>
-            <div className="mx_UseCaseSelection_info mx_UseCaseSelection_slideInDelayed">
-                <h2>{_t("onboarding|use_case_heading2")}</h2>
-                <h3>{_t("onboarding|use_case_heading3")}</h3>
-            </div>
-            <div className="mx_UseCaseSelection_options mx_UseCaseSelection_slideInDelayed">
-                <UseCaseSelectionButton
-                    useCase={UseCase.PersonalMessaging}
-                    selected={selection === UseCase.PersonalMessaging}
-                    onClick={setSelected}
-                />
-                <UseCaseSelectionButton
-                    useCase={UseCase.WorkMessaging}
-                    selected={selection === UseCase.WorkMessaging}
-                    onClick={setSelected}
-                />
-                <UseCaseSelectionButton
-                    useCase={UseCase.CommunityMessaging}
-                    selected={selection === UseCase.CommunityMessaging}
-                    onClick={setSelected}
-                />
-            </div>
-            <div className="mx_UseCaseSelection_skip mx_UseCaseSelection_slideInDelayed">
-                <AccessibleButton kind="link" onClick={async () => setSelected(UseCase.Skip)}>
-                    {_t("action|skip")}
-                </AccessibleButton>
-            </div>
-        </SplashPage>
-    );
-}
diff --git a/src/components/views/elements/UseCaseSelectionButton.tsx b/src/components/views/elements/UseCaseSelectionButton.tsx
deleted file mode 100644
index 2899a1ee502..00000000000
--- a/src/components/views/elements/UseCaseSelectionButton.tsx
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2022 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
-Please see LICENSE files in the repository root for full details.
-*/
-
-import classNames from "classnames";
-import React from "react";
-
-import { _t } from "../../../languageHandler";
-import { UseCase } from "../../../settings/enums/UseCase";
-import AccessibleButton from "./AccessibleButton";
-
-interface Props {
-    useCase: UseCase;
-    selected: boolean;
-    onClick: (useCase: UseCase) => void;
-}
-
-export function UseCaseSelectionButton({ useCase, onClick, selected }: Props): JSX.Element {
-    let label: string | undefined;
-    switch (useCase) {
-        case UseCase.PersonalMessaging:
-            label = _t("onboarding|use_case_personal_messaging");
-            break;
-        case UseCase.WorkMessaging:
-            label = _t("onboarding|use_case_work_messaging");
-            break;
-        case UseCase.CommunityMessaging:
-            label = _t("onboarding|use_case_community_messaging");
-            break;
-    }
-
-    return (
-        <AccessibleButton
-            className={classNames("mx_UseCaseSelectionButton", {
-                mx_UseCaseSelectionButton_selected: selected,
-            })}
-            onClick={async () => onClick(useCase)}
-        >
-            <div
-                className={classNames("mx_UseCaseSelectionButton_icon", {
-                    mx_UseCaseSelectionButton_messaging: useCase === UseCase.PersonalMessaging,
-                    mx_UseCaseSelectionButton_work: useCase === UseCase.WorkMessaging,
-                    mx_UseCaseSelectionButton_community: useCase === UseCase.CommunityMessaging,
-                })}
-            />
-            <span>{label}</span>
-            <div className="mx_UseCaseSelectionButton_selectedIcon" />
-        </AccessibleButton>
-    );
-}
diff --git a/src/components/views/elements/Validation.tsx b/src/components/views/elements/Validation.tsx
index f859c00bebf..2420945c6eb 100644
--- a/src/components/views/elements/Validation.tsx
+++ b/src/components/views/elements/Validation.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 Copyright 2019 New Vector Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/elements/crypto/VerificationQRCode.tsx b/src/components/views/elements/crypto/VerificationQRCode.tsx
index 021457bc006..22acd41a747 100644
--- a/src/components/views/elements/crypto/VerificationQRCode.tsx
+++ b/src/components/views/elements/crypto/VerificationQRCode.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/emojipicker/Category.tsx b/src/components/views/emojipicker/Category.tsx
index 4c9fbc2d89e..397778e0afc 100644
--- a/src/components/views/emojipicker/Category.tsx
+++ b/src/components/views/emojipicker/Category.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 Copyright 2019 Tulir Asokan <tulir@maunium.net>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/emojipicker/Emoji.tsx b/src/components/views/emojipicker/Emoji.tsx
index a852122b750..3b74947f04d 100644
--- a/src/components/views/emojipicker/Emoji.tsx
+++ b/src/components/views/emojipicker/Emoji.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 Copyright 2019 Tulir Asokan <tulir@maunium.net>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/emojipicker/EmojiPicker.tsx b/src/components/views/emojipicker/EmojiPicker.tsx
index e2470d188d3..0c10d778a60 100644
--- a/src/components/views/emojipicker/EmojiPicker.tsx
+++ b/src/components/views/emojipicker/EmojiPicker.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 Copyright 2019 Tulir Asokan <tulir@maunium.net>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/emojipicker/Header.tsx b/src/components/views/emojipicker/Header.tsx
index b66f0dbaa90..53607e28618 100644
--- a/src/components/views/emojipicker/Header.tsx
+++ b/src/components/views/emojipicker/Header.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 Copyright 2019 Tulir Asokan <tulir@maunium.net>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/emojipicker/Preview.tsx b/src/components/views/emojipicker/Preview.tsx
index 8856a9f56e6..a5112510280 100644
--- a/src/components/views/emojipicker/Preview.tsx
+++ b/src/components/views/emojipicker/Preview.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 Copyright 2019 Tulir Asokan <tulir@maunium.net>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/emojipicker/QuickReactions.tsx b/src/components/views/emojipicker/QuickReactions.tsx
index d261171867d..7a8511f997d 100644
--- a/src/components/views/emojipicker/QuickReactions.tsx
+++ b/src/components/views/emojipicker/QuickReactions.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 Copyright 2019 Tulir Asokan <tulir@maunium.net>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/emojipicker/ReactionPicker.tsx b/src/components/views/emojipicker/ReactionPicker.tsx
index bd166344904..ea1a502942d 100644
--- a/src/components/views/emojipicker/ReactionPicker.tsx
+++ b/src/components/views/emojipicker/ReactionPicker.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 Copyright 2019 Tulir Asokan <tulir@maunium.net>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/emojipicker/Search.tsx b/src/components/views/emojipicker/Search.tsx
index bce045cb8c6..bc560c46431 100644
--- a/src/components/views/emojipicker/Search.tsx
+++ b/src/components/views/emojipicker/Search.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 Copyright 2019 Tulir Asokan <tulir@maunium.net>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/location/EnableLiveShare.tsx b/src/components/views/location/EnableLiveShare.tsx
index 1daeef044fd..18fc6025d30 100644
--- a/src/components/views/location/EnableLiveShare.tsx
+++ b/src/components/views/location/EnableLiveShare.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/location/LiveDurationDropdown.tsx b/src/components/views/location/LiveDurationDropdown.tsx
index f0a85b842a7..1bdf93a8e68 100644
--- a/src/components/views/location/LiveDurationDropdown.tsx
+++ b/src/components/views/location/LiveDurationDropdown.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/location/LocationButton.tsx b/src/components/views/location/LocationButton.tsx
index 654a3b69f5f..3a4460bec47 100644
--- a/src/components/views/location/LocationButton.tsx
+++ b/src/components/views/location/LocationButton.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/location/LocationPicker.tsx b/src/components/views/location/LocationPicker.tsx
index e812f1c6bd9..fe0838c166a 100644
--- a/src/components/views/location/LocationPicker.tsx
+++ b/src/components/views/location/LocationPicker.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/location/LocationShareMenu.tsx b/src/components/views/location/LocationShareMenu.tsx
index 4f64a116cc0..546ab4f3735 100644
--- a/src/components/views/location/LocationShareMenu.tsx
+++ b/src/components/views/location/LocationShareMenu.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/location/LocationViewDialog.tsx b/src/components/views/location/LocationViewDialog.tsx
index 93016bb9a42..d35f0b75e2b 100644
--- a/src/components/views/location/LocationViewDialog.tsx
+++ b/src/components/views/location/LocationViewDialog.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/location/Map.tsx b/src/components/views/location/Map.tsx
index 6ba25662e81..3af8b795792 100644
--- a/src/components/views/location/Map.tsx
+++ b/src/components/views/location/Map.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/location/MapError.tsx b/src/components/views/location/MapError.tsx
index 319223d3f93..93c7dab4066 100644
--- a/src/components/views/location/MapError.tsx
+++ b/src/components/views/location/MapError.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/location/MapFallback.tsx b/src/components/views/location/MapFallback.tsx
index 101a5d80663..94829d3bc00 100644
--- a/src/components/views/location/MapFallback.tsx
+++ b/src/components/views/location/MapFallback.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/location/Marker.tsx b/src/components/views/location/Marker.tsx
index 58e1ce30fb0..13239240f16 100644
--- a/src/components/views/location/Marker.tsx
+++ b/src/components/views/location/Marker.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/location/ShareDialogButtons.tsx b/src/components/views/location/ShareDialogButtons.tsx
index 867309f8f2a..8b9bf011997 100644
--- a/src/components/views/location/ShareDialogButtons.tsx
+++ b/src/components/views/location/ShareDialogButtons.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/location/ShareType.tsx b/src/components/views/location/ShareType.tsx
index 0aa31b7bd4b..923cd265724 100644
--- a/src/components/views/location/ShareType.tsx
+++ b/src/components/views/location/ShareType.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/location/SmartMarker.tsx b/src/components/views/location/SmartMarker.tsx
index 50e927b96db..4ec42468a61 100644
--- a/src/components/views/location/SmartMarker.tsx
+++ b/src/components/views/location/SmartMarker.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/location/ZoomButtons.tsx b/src/components/views/location/ZoomButtons.tsx
index 1b370744ded..8926fa20c78 100644
--- a/src/components/views/location/ZoomButtons.tsx
+++ b/src/components/views/location/ZoomButtons.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/location/index.tsx b/src/components/views/location/index.tsx
index d51d6c58f36..3f308f38124 100644
--- a/src/components/views/location/index.tsx
+++ b/src/components/views/location/index.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/location/shareLocation.ts b/src/components/views/location/shareLocation.ts
index 8d4349735e9..5aed9ec37e9 100644
--- a/src/components/views/location/shareLocation.ts
+++ b/src/components/views/location/shareLocation.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/messages/CallEvent.tsx b/src/components/views/messages/CallEvent.tsx
index fa8d14f5f6d..5d2e56c4e8a 100644
--- a/src/components/views/messages/CallEvent.tsx
+++ b/src/components/views/messages/CallEvent.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/messages/CodeBlock.tsx b/src/components/views/messages/CodeBlock.tsx
index 80619914058..fd623eea018 100644
--- a/src/components/views/messages/CodeBlock.tsx
+++ b/src/components/views/messages/CodeBlock.tsx
@@ -1,7 +1,7 @@
 /*
 Copyright 2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -36,9 +36,9 @@ const ExpandCollapseButton: React.FC<{
 };
 
 const CodeBlock: React.FC<Props> = ({ children, onHeightChanged }) => {
-    const enableSyntaxHighlightLanguageDetection = useSettingValue<boolean>("enableSyntaxHighlightLanguageDetection");
-    const showCodeLineNumbers = useSettingValue<boolean>("showCodeLineNumbers");
-    const expandCodeByDefault = useSettingValue<boolean>("expandCodeByDefault");
+    const enableSyntaxHighlightLanguageDetection = useSettingValue("enableSyntaxHighlightLanguageDetection");
+    const showCodeLineNumbers = useSettingValue("showCodeLineNumbers");
+    const expandCodeByDefault = useSettingValue("expandCodeByDefault");
     const [expanded, setExpanded] = useState(expandCodeByDefault);
 
     let expandCollapseButton: JSX.Element | undefined;
diff --git a/src/components/views/messages/DateSeparator.tsx b/src/components/views/messages/DateSeparator.tsx
index 98f397eb459..e8515b9347b 100644
--- a/src/components/views/messages/DateSeparator.tsx
+++ b/src/components/views/messages/DateSeparator.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2015-2021 The Matrix.org Foundation C.I.C.
 Copyright 2018 Michael Telatynski <7t3chguy@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/messages/DecryptionFailureBody.tsx b/src/components/views/messages/DecryptionFailureBody.tsx
index 108ec45b03e..f3c02d4c0c1 100644
--- a/src/components/views/messages/DecryptionFailureBody.tsx
+++ b/src/components/views/messages/DecryptionFailureBody.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022-2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/messages/DisambiguatedProfile.tsx b/src/components/views/messages/DisambiguatedProfile.tsx
index 0e7d2e046eb..660a832d373 100644
--- a/src/components/views/messages/DisambiguatedProfile.tsx
+++ b/src/components/views/messages/DisambiguatedProfile.tsx
@@ -3,20 +3,26 @@ Copyright 2024 New Vector Ltd.
 Copyright 2022, 2023 The Matrix.org Foundation C.I.C.
 Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 import React from "react";
-import { RoomMember } from "matrix-js-sdk/src/matrix";
 import classNames from "classnames";
 
 import { _t } from "../../../languageHandler";
 import { getUserNameColorClass } from "../../../utils/FormattingUtils";
 import UserIdentifier from "../../../customisations/UserIdentifier";
 
+interface MemberInfo {
+    userId: string;
+    roomId: string;
+    rawDisplayName?: string;
+    disambiguate: boolean;
+}
+
 interface IProps {
-    member?: RoomMember | null;
+    member?: MemberInfo | null;
     fallbackName: string;
     onClick?(): void;
     colored?: boolean;
diff --git a/src/components/views/messages/DownloadActionButton.tsx b/src/components/views/messages/DownloadActionButton.tsx
index 2940dab2922..e85389f2e79 100644
--- a/src/components/views/messages/DownloadActionButton.tsx
+++ b/src/components/views/messages/DownloadActionButton.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/messages/EditHistoryMessage.tsx b/src/components/views/messages/EditHistoryMessage.tsx
index fb6f04c08f0..1e6333807dc 100644
--- a/src/components/views/messages/EditHistoryMessage.tsx
+++ b/src/components/views/messages/EditHistoryMessage.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/messages/EncryptionEvent.tsx b/src/components/views/messages/EncryptionEvent.tsx
index bc6680d3000..090881aa02e 100644
--- a/src/components/views/messages/EncryptionEvent.tsx
+++ b/src/components/views/messages/EncryptionEvent.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/messages/EventTileBubble.tsx b/src/components/views/messages/EventTileBubble.tsx
index 05c8a66f995..4ba159089f9 100644
--- a/src/components/views/messages/EventTileBubble.tsx
+++ b/src/components/views/messages/EventTileBubble.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/messages/HiddenBody.tsx b/src/components/views/messages/HiddenBody.tsx
index 9bde6adefc5..5485d2fd6ec 100644
--- a/src/components/views/messages/HiddenBody.tsx
+++ b/src/components/views/messages/HiddenBody.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/messages/IBodyProps.ts b/src/components/views/messages/IBodyProps.ts
index e48ba96b56f..c8f6820e23b 100644
--- a/src/components/views/messages/IBodyProps.ts
+++ b/src/components/views/messages/IBodyProps.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/messages/IMediaBody.ts b/src/components/views/messages/IMediaBody.ts
index c8f7f5b95db..4025f4e6316 100644
--- a/src/components/views/messages/IMediaBody.ts
+++ b/src/components/views/messages/IMediaBody.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/messages/JumpToDatePicker.tsx b/src/components/views/messages/JumpToDatePicker.tsx
index 4f4f0a6e050..28814d1f77b 100644
--- a/src/components/views/messages/JumpToDatePicker.tsx
+++ b/src/components/views/messages/JumpToDatePicker.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/messages/LegacyCallEvent.tsx b/src/components/views/messages/LegacyCallEvent.tsx
index 3f24459b5b6..fe52a83fb77 100644
--- a/src/components/views/messages/LegacyCallEvent.tsx
+++ b/src/components/views/messages/LegacyCallEvent.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/messages/MAudioBody.tsx b/src/components/views/messages/MAudioBody.tsx
index bf0cc9ee541..9c2bc9583b6 100644
--- a/src/components/views/messages/MAudioBody.tsx
+++ b/src/components/views/messages/MAudioBody.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/messages/MBeaconBody.tsx b/src/components/views/messages/MBeaconBody.tsx
index 8b250fa0d50..43f7bbd7d34 100644
--- a/src/components/views/messages/MBeaconBody.tsx
+++ b/src/components/views/messages/MBeaconBody.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/messages/MFileBody.tsx b/src/components/views/messages/MFileBody.tsx
index 1235b73b4bd..20a27b9744e 100644
--- a/src/components/views/messages/MFileBody.tsx
+++ b/src/components/views/messages/MFileBody.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/messages/MImageBody.tsx b/src/components/views/messages/MImageBody.tsx
index c3aeee1a54a..86bc59fdbd1 100644
--- a/src/components/views/messages/MImageBody.tsx
+++ b/src/components/views/messages/MImageBody.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2015-2021 The Matrix.org Foundation C.I.C.
 Copyright 2018, 2019 Michael Telatynski <7t3chguy@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/messages/MImageReplyBody.tsx b/src/components/views/messages/MImageReplyBody.tsx
index c1ba78fbf75..4ba5fc23f26 100644
--- a/src/components/views/messages/MImageReplyBody.tsx
+++ b/src/components/views/messages/MImageReplyBody.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020, 2021 Tulir Asokan <tulir@maunium.net>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/messages/MJitsiWidgetEvent.tsx b/src/components/views/messages/MJitsiWidgetEvent.tsx
index bec4f56164b..2b785b60b44 100644
--- a/src/components/views/messages/MJitsiWidgetEvent.tsx
+++ b/src/components/views/messages/MJitsiWidgetEvent.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/messages/MKeyVerificationRequest.tsx b/src/components/views/messages/MKeyVerificationRequest.tsx
index 56e7b1c39c4..fb929f79a2e 100644
--- a/src/components/views/messages/MKeyVerificationRequest.tsx
+++ b/src/components/views/messages/MKeyVerificationRequest.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019, 2020 , 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/messages/MLocationBody.tsx b/src/components/views/messages/MLocationBody.tsx
index 7735e64b031..006b35bb9b5 100644
--- a/src/components/views/messages/MLocationBody.tsx
+++ b/src/components/views/messages/MLocationBody.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/messages/MPollBody.tsx b/src/components/views/messages/MPollBody.tsx
index ba3962779f3..17c7a577df2 100644
--- a/src/components/views/messages/MPollBody.tsx
+++ b/src/components/views/messages/MPollBody.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/messages/MPollEndBody.tsx b/src/components/views/messages/MPollEndBody.tsx
index 1129b3538ed..7df0e8ad581 100644
--- a/src/components/views/messages/MPollEndBody.tsx
+++ b/src/components/views/messages/MPollEndBody.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/messages/MStickerBody.tsx b/src/components/views/messages/MStickerBody.tsx
index b1638d5b314..0864ecfcfeb 100644
--- a/src/components/views/messages/MStickerBody.tsx
+++ b/src/components/views/messages/MStickerBody.tsx
@@ -1,7 +1,7 @@
 /*
 Copyright 2018-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/messages/MVideoBody.tsx b/src/components/views/messages/MVideoBody.tsx
index 822d2c3f593..c513925acd8 100644
--- a/src/components/views/messages/MVideoBody.tsx
+++ b/src/components/views/messages/MVideoBody.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/messages/MVoiceMessageBody.tsx b/src/components/views/messages/MVoiceMessageBody.tsx
index 690537b2e1e..cc0e030c786 100644
--- a/src/components/views/messages/MVoiceMessageBody.tsx
+++ b/src/components/views/messages/MVoiceMessageBody.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/messages/MVoiceOrAudioBody.tsx b/src/components/views/messages/MVoiceOrAudioBody.tsx
index cfbeaa820bb..af7eb6f84a4 100644
--- a/src/components/views/messages/MVoiceOrAudioBody.tsx
+++ b/src/components/views/messages/MVoiceOrAudioBody.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/messages/MessageActionBar.tsx b/src/components/views/messages/MessageActionBar.tsx
index 579db054e9e..1476249c2b2 100644
--- a/src/components/views/messages/MessageActionBar.tsx
+++ b/src/components/views/messages/MessageActionBar.tsx
@@ -4,7 +4,7 @@ Copyright 2019-2023 The Matrix.org Foundation C.I.C.
 Copyright 2019 New Vector Ltd
 Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/messages/MessageEvent.tsx b/src/components/views/messages/MessageEvent.tsx
index d1a1c59141d..6fb239069f8 100644
--- a/src/components/views/messages/MessageEvent.tsx
+++ b/src/components/views/messages/MessageEvent.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/messages/MessageTimestamp.tsx b/src/components/views/messages/MessageTimestamp.tsx
index 2e0535be5ce..34c25303ed9 100644
--- a/src/components/views/messages/MessageTimestamp.tsx
+++ b/src/components/views/messages/MessageTimestamp.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2018 Michael Telatynski <7t3chguy@gmail.com>
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/messages/MjolnirBody.tsx b/src/components/views/messages/MjolnirBody.tsx
index 678671d42ed..20587f879e0 100644
--- a/src/components/views/messages/MjolnirBody.tsx
+++ b/src/components/views/messages/MjolnirBody.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/messages/PinnedMessageBadge.tsx b/src/components/views/messages/PinnedMessageBadge.tsx
index cdf22390c0e..7f4c132087f 100644
--- a/src/components/views/messages/PinnedMessageBadge.tsx
+++ b/src/components/views/messages/PinnedMessageBadge.tsx
@@ -1,9 +1,8 @@
 /*
  * Copyright 2024 New Vector Ltd.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
- *
  */
 
 import React, { JSX } from "react";
diff --git a/src/components/views/messages/ReactionsRow.tsx b/src/components/views/messages/ReactionsRow.tsx
index 605e6a7dfe0..504bf1b244d 100644
--- a/src/components/views/messages/ReactionsRow.tsx
+++ b/src/components/views/messages/ReactionsRow.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/messages/ReactionsRowButton.tsx b/src/components/views/messages/ReactionsRowButton.tsx
index 709edeffd82..9e3763e4390 100644
--- a/src/components/views/messages/ReactionsRowButton.tsx
+++ b/src/components/views/messages/ReactionsRowButton.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/messages/ReactionsRowButtonTooltip.tsx b/src/components/views/messages/ReactionsRowButtonTooltip.tsx
index 5f407e2e208..84fb95f210e 100644
--- a/src/components/views/messages/ReactionsRowButtonTooltip.tsx
+++ b/src/components/views/messages/ReactionsRowButtonTooltip.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/messages/RedactedBody.tsx b/src/components/views/messages/RedactedBody.tsx
index 7da9eef03d2..dd311c8f5e9 100644
--- a/src/components/views/messages/RedactedBody.tsx
+++ b/src/components/views/messages/RedactedBody.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020, 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/messages/RoomAvatarEvent.tsx b/src/components/views/messages/RoomAvatarEvent.tsx
index 295d2b06806..1d3f9172cab 100644
--- a/src/components/views/messages/RoomAvatarEvent.tsx
+++ b/src/components/views/messages/RoomAvatarEvent.tsx
@@ -4,7 +4,7 @@ Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
 Copyright 2019 The Matrix.org Foundation C.I.C.
 Copyright 2017 Vector Creations Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/messages/RoomPredecessorTile.tsx b/src/components/views/messages/RoomPredecessorTile.tsx
index afc81422345..3b2de5d67dd 100644
--- a/src/components/views/messages/RoomPredecessorTile.tsx
+++ b/src/components/views/messages/RoomPredecessorTile.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019-2023 The Matrix.org Foundation C.I.C.
 Copyright 2018 New Vector Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/messages/SenderProfile.tsx b/src/components/views/messages/SenderProfile.tsx
index 7c239d0500a..8e99e45e756 100644
--- a/src/components/views/messages/SenderProfile.tsx
+++ b/src/components/views/messages/SenderProfile.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/src/components/views/messages/TextualBody.tsx b/src/components/views/messages/TextualBody.tsx
index ae99754cbad..5aa8581f507 100644
--- a/src/components/views/messages/TextualBody.tsx
+++ b/src/components/views/messages/TextualBody.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -128,7 +128,8 @@ export default class TextualBody extends React.Component<IBodyProps, IState> {
         if (!this.props.editState) {
             const stoppedEditing = prevProps.editState && !this.props.editState;
             const messageWasEdited = prevProps.replacingEventId !== this.props.replacingEventId;
-            if (messageWasEdited || stoppedEditing) {
+            const urlPreviewChanged = prevProps.showUrlPreview !== this.props.showUrlPreview;
+            if (messageWasEdited || stoppedEditing || urlPreviewChanged) {
                 this.applyFormatting();
             }
         }
@@ -425,7 +426,7 @@ export default class TextualBody extends React.Component<IBodyProps, IState> {
         const stripReply = !mxEvent.replacingEvent() && !!getParentEventId(mxEvent);
 
         const htmlOpts = {
-            disableBigEmoji: isEmote || !SettingsStore.getValue<boolean>("TextualBody.enableBigEmoji"),
+            disableBigEmoji: isEmote || !SettingsStore.getValue("TextualBody.enableBigEmoji"),
             // Part of Replies fallback support
             stripReplyFallback: stripReply,
         };
diff --git a/src/components/views/messages/TextualEvent.tsx b/src/components/views/messages/TextualEvent.tsx
index 1c54963f76f..41a8fdf1154 100644
--- a/src/components/views/messages/TextualEvent.tsx
+++ b/src/components/views/messages/TextualEvent.tsx
@@ -2,12 +2,12 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 import React from "react";
-import { MatrixEvent } from "matrix-js-sdk/src/matrix";
+import { MatrixEvent, MatrixEventEvent } from "matrix-js-sdk/src/matrix";
 
 import RoomContext from "../../../contexts/RoomContext";
 import * as TextForEvent from "../../../TextForEvent";
@@ -21,6 +21,19 @@ export default class TextualEvent extends React.Component<IProps> {
     public static contextType = RoomContext;
     declare public context: React.ContextType<typeof RoomContext>;
 
+    public componentDidMount(): void {
+        this.props.mxEvent.on(MatrixEventEvent.SentinelUpdated, this.onEventSentinelUpdated);
+    }
+    public componentWillUnmount(): void {
+        this.props.mxEvent.off(MatrixEventEvent.SentinelUpdated, this.onEventSentinelUpdated);
+    }
+
+    private onEventSentinelUpdated = (): void => {
+        // XXX: this is crap, but we don't have a better way to force a re-render
+        // Many TextForEvent handlers render parts of `event.sender` and `event.target` so ensure they are updated
+        this.forceUpdate();
+    };
+
     public render(): React.ReactNode {
         const text = TextForEvent.textForEvent(
             this.props.mxEvent,
diff --git a/src/components/views/messages/TileErrorBoundary.tsx b/src/components/views/messages/TileErrorBoundary.tsx
index b1cc53f2671..33d82e538af 100644
--- a/src/components/views/messages/TileErrorBoundary.tsx
+++ b/src/components/views/messages/TileErrorBoundary.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020-2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/messages/TimelineSeparator.tsx b/src/components/views/messages/TimelineSeparator.tsx
index 5657ca7e6a7..f89ba642925 100644
--- a/src/components/views/messages/TimelineSeparator.tsx
+++ b/src/components/views/messages/TimelineSeparator.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/messages/UnknownBody.tsx b/src/components/views/messages/UnknownBody.tsx
index ce9355b4b4b..2e804a221c6 100644
--- a/src/components/views/messages/UnknownBody.tsx
+++ b/src/components/views/messages/UnknownBody.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/messages/ViewSourceEvent.tsx b/src/components/views/messages/ViewSourceEvent.tsx
index 8352f0f7e2b..3489921729f 100644
--- a/src/components/views/messages/ViewSourceEvent.tsx
+++ b/src/components/views/messages/ViewSourceEvent.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/messages/shared/MediaProcessingError.tsx b/src/components/views/messages/shared/MediaProcessingError.tsx
index 39c0017f571..95a65b4538c 100644
--- a/src/components/views/messages/shared/MediaProcessingError.tsx
+++ b/src/components/views/messages/shared/MediaProcessingError.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/pips/WidgetPip.tsx b/src/components/views/pips/WidgetPip.tsx
index a556d3b93ce..13df6dbfadf 100644
--- a/src/components/views/pips/WidgetPip.tsx
+++ b/src/components/views/pips/WidgetPip.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/polls/PollOption.tsx b/src/components/views/polls/PollOption.tsx
index c84653c2a12..07c6d141bb8 100644
--- a/src/components/views/polls/PollOption.tsx
+++ b/src/components/views/polls/PollOption.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/polls/pollHistory/PollDetail.tsx b/src/components/views/polls/pollHistory/PollDetail.tsx
index fbc09ffcedd..67da1526cc4 100644
--- a/src/components/views/polls/pollHistory/PollDetail.tsx
+++ b/src/components/views/polls/pollHistory/PollDetail.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/polls/pollHistory/PollDetailHeader.tsx b/src/components/views/polls/pollHistory/PollDetailHeader.tsx
index 0b175629aee..429f1740a75 100644
--- a/src/components/views/polls/pollHistory/PollDetailHeader.tsx
+++ b/src/components/views/polls/pollHistory/PollDetailHeader.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/polls/pollHistory/PollHistory.tsx b/src/components/views/polls/pollHistory/PollHistory.tsx
index 4d145f3054b..01fcedd8eec 100644
--- a/src/components/views/polls/pollHistory/PollHistory.tsx
+++ b/src/components/views/polls/pollHistory/PollHistory.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/polls/pollHistory/PollHistoryList.tsx b/src/components/views/polls/pollHistory/PollHistoryList.tsx
index 466ad2d58f5..ed0b935050e 100644
--- a/src/components/views/polls/pollHistory/PollHistoryList.tsx
+++ b/src/components/views/polls/pollHistory/PollHistoryList.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/polls/pollHistory/PollListItem.tsx b/src/components/views/polls/pollHistory/PollListItem.tsx
index 544af0a6820..3a631c4242d 100644
--- a/src/components/views/polls/pollHistory/PollListItem.tsx
+++ b/src/components/views/polls/pollHistory/PollListItem.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/polls/pollHistory/PollListItemEnded.tsx b/src/components/views/polls/pollHistory/PollListItemEnded.tsx
index e2f80e8eba5..17a9f9ae3ec 100644
--- a/src/components/views/polls/pollHistory/PollListItemEnded.tsx
+++ b/src/components/views/polls/pollHistory/PollListItemEnded.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/polls/pollHistory/fetchPastPolls.ts b/src/components/views/polls/pollHistory/fetchPastPolls.ts
index d4d58948c3e..2e6c7075940 100644
--- a/src/components/views/polls/pollHistory/fetchPastPolls.ts
+++ b/src/components/views/polls/pollHistory/fetchPastPolls.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/polls/pollHistory/types.ts b/src/components/views/polls/pollHistory/types.ts
index 75b02f0fcaa..0b9b98900ec 100644
--- a/src/components/views/polls/pollHistory/types.ts
+++ b/src/components/views/polls/pollHistory/types.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/polls/pollHistory/usePollHistory.ts b/src/components/views/polls/pollHistory/usePollHistory.ts
index 6594cfbb41a..fbc57158427 100644
--- a/src/components/views/polls/pollHistory/usePollHistory.ts
+++ b/src/components/views/polls/pollHistory/usePollHistory.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/right_panel/BaseCard.tsx b/src/components/views/right_panel/BaseCard.tsx
index 30ec02a247a..d7d6129960d 100644
--- a/src/components/views/right_panel/BaseCard.tsx
+++ b/src/components/views/right_panel/BaseCard.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/right_panel/EmptyState.tsx b/src/components/views/right_panel/EmptyState.tsx
index 3d7c9a89a6b..1c7713a5d8a 100644
--- a/src/components/views/right_panel/EmptyState.tsx
+++ b/src/components/views/right_panel/EmptyState.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/right_panel/EncryptionInfo.tsx b/src/components/views/right_panel/EncryptionInfo.tsx
index 588d2d910ed..a2fb6e8f243 100644
--- a/src/components/views/right_panel/EncryptionInfo.tsx
+++ b/src/components/views/right_panel/EncryptionInfo.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/right_panel/EncryptionPanel.tsx b/src/components/views/right_panel/EncryptionPanel.tsx
index 47fb995c20c..3ccd07cfc2c 100644
--- a/src/components/views/right_panel/EncryptionPanel.tsx
+++ b/src/components/views/right_panel/EncryptionPanel.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/right_panel/ExtensionsCard.tsx b/src/components/views/right_panel/ExtensionsCard.tsx
index 0c6b3ecde09..0e0ca12d67b 100644
--- a/src/components/views/right_panel/ExtensionsCard.tsx
+++ b/src/components/views/right_panel/ExtensionsCard.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/right_panel/PinnedMessagesCard.tsx b/src/components/views/right_panel/PinnedMessagesCard.tsx
index d6161e9434d..2ce514c97ae 100644
--- a/src/components/views/right_panel/PinnedMessagesCard.tsx
+++ b/src/components/views/right_panel/PinnedMessagesCard.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/right_panel/RoomSummaryCard.tsx b/src/components/views/right_panel/RoomSummaryCard.tsx
index c8dd0b97387..0abdba5276e 100644
--- a/src/components/views/right_panel/RoomSummaryCard.tsx
+++ b/src/components/views/right_panel/RoomSummaryCard.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/right_panel/TimelineCard.tsx b/src/components/views/right_panel/TimelineCard.tsx
index f62319f3cda..49b313ca445 100644
--- a/src/components/views/right_panel/TimelineCard.tsx
+++ b/src/components/views/right_panel/TimelineCard.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021, 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/right_panel/UserInfo.tsx b/src/components/views/right_panel/UserInfo.tsx
index 591e2327ae4..4e8968afaa9 100644
--- a/src/components/views/right_panel/UserInfo.tsx
+++ b/src/components/views/right_panel/UserInfo.tsx
@@ -5,7 +5,7 @@ Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
 Copyright 2017, 2018 Vector Creations Ltd
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/right_panel/VerificationPanel.tsx b/src/components/views/right_panel/VerificationPanel.tsx
index 6f8295dece2..2a1d8ce3c0a 100644
--- a/src/components/views/right_panel/VerificationPanel.tsx
+++ b/src/components/views/right_panel/VerificationPanel.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -23,11 +23,12 @@ import { MatrixClientPeg } from "../../../MatrixClientPeg";
 import VerificationQRCode from "../elements/crypto/VerificationQRCode";
 import { _t } from "../../../languageHandler";
 import SdkConfig from "../../../SdkConfig";
-import E2EIcon, { E2EState } from "../rooms/E2EIcon";
+import E2EIcon from "../rooms/E2EIcon";
 import Spinner from "../elements/Spinner";
 import AccessibleButton from "../elements/AccessibleButton";
 import VerificationShowSas from "../verification/VerificationShowSas";
 import { getDeviceCryptoInfo } from "../../../utils/crypto/deviceInfo";
+import { E2EStatus } from "../../../utils/ShieldUtils";
 
 interface IProps {
     layout: string;
@@ -233,7 +234,7 @@ export default class VerificationPanel extends React.PureComponent<IProps, IStat
             body = (
                 <React.Fragment>
                     <p>{description}</p>
-                    <E2EIcon isUser={true} status={E2EState.Verified} size={128} hideTooltip={true} />
+                    <E2EIcon isUser={true} status={E2EStatus.Verified} size={128} hideTooltip={true} />
                     <div className="mx_VerificationPanel_reciprocateButtons">
                         <AccessibleButton
                             kind="danger"
@@ -302,7 +303,7 @@ export default class VerificationPanel extends React.PureComponent<IProps, IStat
         return (
             <div className="mx_UserInfo_container mx_VerificationPanel_verified_section">
                 <p>{description}</p>
-                <E2EIcon isUser={true} status={E2EState.Verified} size={128} hideTooltip={true} />
+                <E2EIcon isUser={true} status={E2EStatus.Verified} size={128} hideTooltip={true} />
                 {text ? <p>{text}</p> : null}
                 <AccessibleButton kind="primary" className="mx_UserInfo_wideButton" onClick={this.props.onClose}>
                     {_t("action|got_it")}
diff --git a/src/components/views/right_panel/WidgetCard.tsx b/src/components/views/right_panel/WidgetCard.tsx
index 887ecb61908..b1488aefb43 100644
--- a/src/components/views/right_panel/WidgetCard.tsx
+++ b/src/components/views/right_panel/WidgetCard.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/right_panel/context.ts b/src/components/views/right_panel/context.ts
index b0d979ea03e..ba289c87f7d 100644
--- a/src/components/views/right_panel/context.ts
+++ b/src/components/views/right_panel/context.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/right_panel/types.ts b/src/components/views/right_panel/types.ts
index f390dfcb7de..09965a2a101 100644
--- a/src/components/views/right_panel/types.ts
+++ b/src/components/views/right_panel/types.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/room_settings/AliasSettings.tsx b/src/components/views/room_settings/AliasSettings.tsx
index 0bb29b7f895..e76c8a2cd55 100644
--- a/src/components/views/room_settings/AliasSettings.tsx
+++ b/src/components/views/room_settings/AliasSettings.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2016-2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/room_settings/RoomProfileSettings.tsx b/src/components/views/room_settings/RoomProfileSettings.tsx
index 73d345847e7..8789ea48fc7 100644
--- a/src/components/views/room_settings/RoomProfileSettings.tsx
+++ b/src/components/views/room_settings/RoomProfileSettings.tsx
@@ -1,7 +1,7 @@
 /*
 Copyright 2019-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/room_settings/RoomPublishSetting.tsx b/src/components/views/room_settings/RoomPublishSetting.tsx
index 9690e9c0ebb..5147945c364 100644
--- a/src/components/views/room_settings/RoomPublishSetting.tsx
+++ b/src/components/views/room_settings/RoomPublishSetting.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020, 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/room_settings/UrlPreviewSettings.tsx b/src/components/views/room_settings/UrlPreviewSettings.tsx
index 4ca63fd4a0d..9c7dcabbc64 100644
--- a/src/components/views/room_settings/UrlPreviewSettings.tsx
+++ b/src/components/views/room_settings/UrlPreviewSettings.tsx
@@ -5,7 +5,7 @@ Copyright 2018, 2019 New Vector Ltd
 Copyright 2017 Travis Ralston
 Copyright 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/AppsDrawer.tsx b/src/components/views/rooms/AppsDrawer.tsx
index c02bfe8cf28..36df51f4cbb 100644
--- a/src/components/views/rooms/AppsDrawer.tsx
+++ b/src/components/views/rooms/AppsDrawer.tsx
@@ -2,7 +2,7 @@
 Copyright 2018-2024 New Vector Ltd.
 Copyright 2017 Vector Creations Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/Autocomplete.tsx b/src/components/views/rooms/Autocomplete.tsx
index 3ffd6648ea8..f77f394d8cc 100644
--- a/src/components/views/rooms/Autocomplete.tsx
+++ b/src/components/views/rooms/Autocomplete.tsx
@@ -2,7 +2,7 @@
 Copyright 2017-2024 New Vector Ltd.
 Copyright 2016 Aviral Dasgupta
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/AuxPanel.tsx b/src/components/views/rooms/AuxPanel.tsx
index 5763a281547..67a25d433db 100644
--- a/src/components/views/rooms/AuxPanel.tsx
+++ b/src/components/views/rooms/AuxPanel.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015-2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/BasicMessageComposer.tsx b/src/components/views/rooms/BasicMessageComposer.tsx
index 5f033de2380..ffa5e99f927 100644
--- a/src/components/views/rooms/BasicMessageComposer.tsx
+++ b/src/components/views/rooms/BasicMessageComposer.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/CollapsibleButton.tsx b/src/components/views/rooms/CollapsibleButton.tsx
index 27589ec58c1..f1387a7a1ba 100644
--- a/src/components/views/rooms/CollapsibleButton.tsx
+++ b/src/components/views/rooms/CollapsibleButton.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/E2EIcon.tsx b/src/components/views/rooms/E2EIcon.tsx
index 29899e85ba9..8542ad4b4bd 100644
--- a/src/components/views/rooms/E2EIcon.tsx
+++ b/src/components/views/rooms/E2EIcon.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 Copyright 2019 New Vector Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -14,23 +14,16 @@ import { Tooltip } from "@vector-im/compound-web";
 import { _t, _td, TranslationKey } from "../../../languageHandler";
 import AccessibleButton from "../elements/AccessibleButton";
 import { E2EStatus } from "../../../utils/ShieldUtils";
-import { XOR } from "../../../@types/common";
 
-export enum E2EState {
-    Verified = "verified",
-    Warning = "warning",
-    Normal = "normal",
-}
-
-const crossSigningUserTitles: { [key in E2EState]?: TranslationKey } = {
-    [E2EState.Warning]: _td("encryption|cross_signing_user_warning"),
-    [E2EState.Normal]: _td("encryption|cross_signing_user_normal"),
-    [E2EState.Verified]: _td("encryption|cross_signing_user_verified"),
+export const crossSigningUserTitles: { [key in E2EStatus]?: TranslationKey } = {
+    [E2EStatus.Warning]: _td("encryption|cross_signing_user_warning"),
+    [E2EStatus.Normal]: _td("encryption|cross_signing_user_normal"),
+    [E2EStatus.Verified]: _td("encryption|cross_signing_user_verified"),
 };
-const crossSigningRoomTitles: { [key in E2EState]?: TranslationKey } = {
-    [E2EState.Warning]: _td("encryption|cross_signing_room_warning"),
-    [E2EState.Normal]: _td("encryption|cross_signing_room_normal"),
-    [E2EState.Verified]: _td("encryption|cross_signing_room_verified"),
+const crossSigningRoomTitles: { [key in E2EStatus]?: TranslationKey } = {
+    [E2EStatus.Warning]: _td("encryption|cross_signing_room_warning"),
+    [E2EStatus.Normal]: _td("encryption|cross_signing_room_normal"),
+    [E2EStatus.Verified]: _td("encryption|cross_signing_room_verified"),
 };
 
 interface Props {
@@ -40,19 +33,11 @@ interface Props {
     hideTooltip?: boolean;
     tooltipPlacement?: ComponentProps<typeof Tooltip>["placement"];
     bordered?: boolean;
-}
-
-interface UserProps extends Props {
-    isUser: true;
-    status: E2EState | E2EStatus;
-}
-
-interface RoomProps extends Props {
-    isUser?: false;
     status: E2EStatus;
+    isUser?: boolean;
 }
 
-const E2EIcon: React.FC<XOR<UserProps, RoomProps>> = ({
+const E2EIcon: React.FC<Props> = ({
     isUser,
     status,
     className,
@@ -66,9 +51,9 @@ const E2EIcon: React.FC<XOR<UserProps, RoomProps>> = ({
         {
             mx_E2EIcon: true,
             mx_E2EIcon_bordered: bordered,
-            mx_E2EIcon_warning: status === E2EState.Warning,
-            mx_E2EIcon_normal: status === E2EState.Normal,
-            mx_E2EIcon_verified: status === E2EState.Verified,
+            mx_E2EIcon_warning: status === E2EStatus.Warning,
+            mx_E2EIcon_normal: status === E2EStatus.Normal,
+            mx_E2EIcon_verified: status === E2EStatus.Verified,
         },
         className,
     );
diff --git a/src/components/views/rooms/EditMessageComposer.tsx b/src/components/views/rooms/EditMessageComposer.tsx
index f4b5c3698eb..dcae2153528 100644
--- a/src/components/views/rooms/EditMessageComposer.tsx
+++ b/src/components/views/rooms/EditMessageComposer.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/EmojiButton.tsx b/src/components/views/rooms/EmojiButton.tsx
index de64b3d42c7..79184486b14 100644
--- a/src/components/views/rooms/EmojiButton.tsx
+++ b/src/components/views/rooms/EmojiButton.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/EntityTile.tsx b/src/components/views/rooms/EntityTile.tsx
deleted file mode 100644
index 946a5cd46b4..00000000000
--- a/src/components/views/rooms/EntityTile.tsx
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2020 The Matrix.org Foundation C.I.C.
-Copyright 2018 New Vector Ltd
-Copyright 2015, 2016 OpenMarket Ltd
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
-Please see LICENSE files in the repository root for full details.
-*/
-
-import React from "react";
-import classNames from "classnames";
-
-import AccessibleButton from "../elements/AccessibleButton";
-import { _t, _td, TranslationKey } from "../../../languageHandler";
-import E2EIcon, { E2EState } from "./E2EIcon";
-import BaseAvatar from "../avatars/BaseAvatar";
-import PresenceLabel from "./PresenceLabel";
-
-export enum PowerStatus {
-    Admin = "admin",
-    Moderator = "moderator",
-}
-
-const PowerLabel: Record<PowerStatus, TranslationKey> = {
-    [PowerStatus.Admin]: _td("power_level|admin"),
-    [PowerStatus.Moderator]: _td("power_level|mod"),
-};
-
-export type PresenceState = "offline" | "online" | "unavailable" | "io.element.unreachable";
-
-const PRESENCE_CLASS: Record<PresenceState, string> = {
-    "offline": "mx_EntityTile_offline",
-    "online": "mx_EntityTile_online",
-    "unavailable": "mx_EntityTile_unavailable",
-    "io.element.unreachable": "mx_EntityTile_unreachable",
-};
-
-function presenceClassForMember(presenceState?: PresenceState, lastActiveAgo?: number, showPresence?: boolean): string {
-    if (showPresence === false) {
-        return "mx_EntityTile_online_beenactive";
-    }
-
-    // offline is split into two categories depending on whether we have
-    // a last_active_ago for them.
-    if (presenceState === "offline") {
-        if (lastActiveAgo) {
-            return PRESENCE_CLASS["offline"] + "_beenactive";
-        } else {
-            return PRESENCE_CLASS["offline"] + "_neveractive";
-        }
-    } else if (presenceState) {
-        return PRESENCE_CLASS[presenceState];
-    } else {
-        return PRESENCE_CLASS["offline"] + "_neveractive";
-    }
-}
-
-interface IProps {
-    name?: string;
-    nameJSX?: JSX.Element;
-    title?: string;
-    avatarJsx?: JSX.Element; // <BaseAvatar />
-    className?: string;
-    presenceState: PresenceState;
-    presenceLastActiveAgo: number;
-    presenceLastTs: number;
-    presenceCurrentlyActive?: boolean;
-    onClick(): void;
-    showPresence: boolean;
-    subtextLabel?: string;
-    e2eStatus?: E2EState;
-    powerStatus?: PowerStatus;
-}
-
-interface IState {
-    hover: boolean;
-}
-
-export default class EntityTile extends React.PureComponent<IProps, IState> {
-    public static defaultProps = {
-        onClick: () => {},
-        presenceState: "offline",
-        presenceLastActiveAgo: 0,
-        presenceLastTs: 0,
-        showInviteButton: false,
-        showPresence: true,
-    };
-
-    public constructor(props: IProps) {
-        super(props);
-
-        this.state = {
-            hover: false,
-        };
-    }
-
-    /**
-     * Creates the PresenceLabel component if needed
-     * @returns The PresenceLabel component if we need to render it, undefined otherwise
-     */
-    private getPresenceLabel(): JSX.Element | undefined {
-        if (!this.props.showPresence) return;
-        const activeAgo = this.props.presenceLastActiveAgo
-            ? Date.now() - (this.props.presenceLastTs - this.props.presenceLastActiveAgo)
-            : -1;
-        return (
-            <PresenceLabel
-                activeAgo={activeAgo}
-                currentlyActive={this.props.presenceCurrentlyActive}
-                presenceState={this.props.presenceState}
-            />
-        );
-    }
-
-    public render(): React.ReactNode {
-        const mainClassNames: Record<string, boolean> = {
-            mx_EntityTile: true,
-        };
-        if (this.props.className) mainClassNames[this.props.className] = true;
-
-        const presenceClass = presenceClassForMember(
-            this.props.presenceState,
-            this.props.presenceLastActiveAgo,
-            this.props.showPresence,
-        );
-        mainClassNames[presenceClass] = true;
-
-        const name = this.props.nameJSX || this.props.name;
-        const nameAndPresence = (
-            <div className="mx_EntityTile_details">
-                <div className="mx_EntityTile_name">{name}</div>
-                {this.getPresenceLabel()}
-            </div>
-        );
-
-        let powerLabel;
-        const powerStatus = this.props.powerStatus;
-        if (powerStatus) {
-            const powerText = _t(PowerLabel[powerStatus]);
-            powerLabel = <div className="mx_EntityTile_power">{powerText}</div>;
-        }
-
-        let e2eIcon;
-        const { e2eStatus } = this.props;
-        if (e2eStatus) {
-            e2eIcon = <E2EIcon status={e2eStatus} isUser={true} bordered={true} />;
-        }
-
-        const av = this.props.avatarJsx || <BaseAvatar name={this.props.name} size="36px" aria-hidden="true" />;
-
-        // The wrapping div is required to make the magic mouse listener work, for some reason.
-        return (
-            <div>
-                <AccessibleButton
-                    className={classNames(mainClassNames)}
-                    title={this.props.title}
-                    onClick={this.props.onClick}
-                >
-                    <div className="mx_EntityTile_avatar">
-                        {av}
-                        {e2eIcon}
-                    </div>
-                    {nameAndPresence}
-                    {powerLabel}
-                </AccessibleButton>
-            </div>
-        );
-    }
-}
diff --git a/src/components/views/rooms/EventPreview.tsx b/src/components/views/rooms/EventPreview.tsx
index e02c2f152fe..8e7f53a3301 100644
--- a/src/components/views/rooms/EventPreview.tsx
+++ b/src/components/views/rooms/EventPreview.tsx
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2024 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/src/components/views/rooms/EventTile.tsx b/src/components/views/rooms/EventTile.tsx
index 8c755f00bda..1d2983dd030 100644
--- a/src/components/views/rooms/EventTile.tsx
+++ b/src/components/views/rooms/EventTile.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2015-2023 The Matrix.org Foundation C.I.C.
 Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/EventTile/EventTileThreadToolbar.tsx b/src/components/views/rooms/EventTile/EventTileThreadToolbar.tsx
index ad1a6ce9a61..29f3a43633e 100644
--- a/src/components/views/rooms/EventTile/EventTileThreadToolbar.tsx
+++ b/src/components/views/rooms/EventTile/EventTileThreadToolbar.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/ExtraTile.tsx b/src/components/views/rooms/ExtraTile.tsx
index 8f94264623c..d33db33e16d 100644
--- a/src/components/views/rooms/ExtraTile.tsx
+++ b/src/components/views/rooms/ExtraTile.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020-2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/HistoryTile.tsx b/src/components/views/rooms/HistoryTile.tsx
index 3aa74b8b0c7..a004aaeab97 100644
--- a/src/components/views/rooms/HistoryTile.tsx
+++ b/src/components/views/rooms/HistoryTile.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 Robin Townsend <robin@robin.town>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/JumpToBottomButton.tsx b/src/components/views/rooms/JumpToBottomButton.tsx
index 7111a14e76d..a33fa7857ba 100644
--- a/src/components/views/rooms/JumpToBottomButton.tsx
+++ b/src/components/views/rooms/JumpToBottomButton.tsx
@@ -1,7 +1,7 @@
 /*
 Copyright 2019-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/LinkPreviewGroup.tsx b/src/components/views/rooms/LinkPreviewGroup.tsx
index cbbd2a3d7bf..4ba64cee8c8 100644
--- a/src/components/views/rooms/LinkPreviewGroup.tsx
+++ b/src/components/views/rooms/LinkPreviewGroup.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/LinkPreviewWidget.tsx b/src/components/views/rooms/LinkPreviewWidget.tsx
index 91fb0608aaf..07d41ea534f 100644
--- a/src/components/views/rooms/LinkPreviewWidget.tsx
+++ b/src/components/views/rooms/LinkPreviewWidget.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2016-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/LiveContentSummary.tsx b/src/components/views/rooms/LiveContentSummary.tsx
index 0d921194119..3ffcc6c0ec0 100644
--- a/src/components/views/rooms/LiveContentSummary.tsx
+++ b/src/components/views/rooms/LiveContentSummary.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/MemberList.tsx b/src/components/views/rooms/MemberList.tsx
deleted file mode 100644
index 5587b56bf82..00000000000
--- a/src/components/views/rooms/MemberList.tsx
+++ /dev/null
@@ -1,450 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
-Copyright 2017, 2018 New Vector Ltd
-Copyright 2017 Vector Creations Ltd
-Copyright 2015, 2016 OpenMarket Ltd
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
-Please see LICENSE files in the repository root for full details.
-*/
-
-import React from "react";
-import {
-    MatrixEvent,
-    Room,
-    RoomEvent,
-    RoomMember,
-    RoomMemberEvent,
-    RoomState,
-    RoomStateEvent,
-    User,
-    UserEvent,
-    EventType,
-    ClientEvent,
-} from "matrix-js-sdk/src/matrix";
-import { KnownMembership } from "matrix-js-sdk/src/types";
-import { throttle } from "lodash";
-import { Button, Tooltip } from "@vector-im/compound-web";
-import UserAddIcon from "@vector-im/compound-design-tokens/assets/web/icons/user-add-solid";
-// eslint-disable-next-line no-restricted-imports
-import OverflowHorizontalSvg from "@vector-im/compound-design-tokens/icons/overflow-horizontal.svg";
-
-import { _t } from "../../../languageHandler";
-import dis from "../../../dispatcher/dispatcher";
-import { isValid3pidInvite } from "../../../RoomInvite";
-import { MatrixClientPeg } from "../../../MatrixClientPeg";
-import BaseCard from "../right_panel/BaseCard";
-import TruncatedList from "../elements/TruncatedList";
-import Spinner from "../elements/Spinner";
-import SearchBox from "../../structures/SearchBox";
-import { ButtonEvent } from "../elements/AccessibleButton";
-import EntityTile from "./EntityTile";
-import MemberTile from "./MemberTile";
-import BaseAvatar from "../avatars/BaseAvatar";
-import { shouldShowComponent } from "../../../customisations/helpers/UIComponents";
-import { UIComponent } from "../../../settings/UIFeature";
-import PosthogTrackers from "../../../PosthogTrackers";
-import { SDKContext } from "../../../contexts/SDKContext";
-import { canInviteTo } from "../../../utils/room/canInviteTo";
-import { inviteToRoom } from "../../../utils/room/inviteToRoom";
-import { Action } from "../../../dispatcher/actions";
-
-const INITIAL_LOAD_NUM_MEMBERS = 30;
-const INITIAL_LOAD_NUM_INVITED = 5;
-const SHOW_MORE_INCREMENT = 100;
-
-interface IProps {
-    roomId: string;
-    searchQuery: string;
-    onClose(): void;
-    onSearchQueryChanged: (query: string) => void;
-}
-
-interface IState {
-    loading: boolean;
-    filteredJoinedMembers: Array<RoomMember>;
-    filteredInvitedMembers: Array<RoomMember | MatrixEvent>;
-    canInvite: boolean;
-    truncateAtJoined: number;
-    truncateAtInvited: number;
-}
-
-export default class MemberList extends React.Component<IProps, IState> {
-    private readonly showPresence: boolean;
-    private unmounted = false;
-
-    public static contextType = SDKContext;
-    declare public context: React.ContextType<typeof SDKContext>;
-    private tiles: Map<string, MemberTile> = new Map();
-
-    public constructor(props: IProps, context: React.ContextType<typeof SDKContext>) {
-        super(props, context);
-        this.state = this.getMembersState([], []);
-        this.showPresence = context?.memberListStore.isPresenceEnabled() ?? true;
-    }
-
-    private listenForMembersChanges(): void {
-        const cli = MatrixClientPeg.safeGet();
-        cli.on(RoomStateEvent.Update, this.onRoomStateUpdate);
-        cli.on(RoomMemberEvent.Name, this.onRoomMemberName);
-        cli.on(RoomStateEvent.Events, this.onRoomStateEvent);
-        // We listen for changes to the lastPresenceTs which is essentially
-        // listening for all presence events (we display most of not all of
-        // the information contained in presence events).
-        cli.on(UserEvent.LastPresenceTs, this.onUserPresenceChange);
-        cli.on(UserEvent.Presence, this.onUserPresenceChange);
-        cli.on(UserEvent.CurrentlyActive, this.onUserPresenceChange);
-        cli.on(ClientEvent.Room, this.onRoom); // invites & joining after peek
-        cli.on(RoomEvent.MyMembership, this.onMyMembership);
-    }
-
-    public componentDidMount(): void {
-        this.unmounted = false;
-        this.listenForMembersChanges();
-        this.updateListNow(true);
-    }
-
-    public componentWillUnmount(): void {
-        this.unmounted = true;
-        const cli = MatrixClientPeg.get();
-        if (cli) {
-            cli.removeListener(RoomStateEvent.Update, this.onRoomStateUpdate);
-            cli.removeListener(RoomMemberEvent.Name, this.onRoomMemberName);
-            cli.removeListener(RoomEvent.MyMembership, this.onMyMembership);
-            cli.removeListener(RoomStateEvent.Events, this.onRoomStateEvent);
-            cli.removeListener(ClientEvent.Room, this.onRoom);
-            cli.removeListener(UserEvent.LastPresenceTs, this.onUserPresenceChange);
-            cli.removeListener(UserEvent.Presence, this.onUserPresenceChange);
-            cli.removeListener(UserEvent.CurrentlyActive, this.onUserPresenceChange);
-        }
-
-        // cancel any pending calls to the rate_limited_funcs
-        this.updateList.cancel();
-    }
-
-    private get canInvite(): boolean {
-        const cli = MatrixClientPeg.safeGet();
-        const room = cli.getRoom(this.props.roomId);
-
-        return !!room && canInviteTo(room);
-    }
-
-    private getMembersState(invitedMembers: Array<RoomMember>, joinedMembers: Array<RoomMember>): IState {
-        return {
-            loading: false,
-            filteredJoinedMembers: joinedMembers,
-            filteredInvitedMembers: invitedMembers,
-            canInvite: this.canInvite,
-
-            // ideally we'd size this to the page height, but
-            // in practice I find that a little constraining
-            truncateAtJoined: INITIAL_LOAD_NUM_MEMBERS,
-            truncateAtInvited: INITIAL_LOAD_NUM_INVITED,
-        };
-    }
-
-    private onUserPresenceChange = (event: MatrixEvent | undefined, user: User): void => {
-        // Attach a SINGLE listener for global presence changes then locate the
-        // member tile and re-render it. This is more efficient than every tile
-        // ever attaching their own listener.
-        const tile = this.tiles.get(user.userId);
-        if (tile) {
-            this.updateList(); // reorder the membership list
-        }
-    };
-
-    private onRoom = (room: Room): void => {
-        if (room.roomId !== this.props.roomId) {
-            return;
-        }
-        // We listen for room events because when we accept an invite
-        // we need to wait till the room is fully populated with state
-        // before refreshing the member list else we get a stale list.
-        this.updateListNow(true);
-    };
-
-    private onMyMembership = (room: Room, membership: string, oldMembership?: string): void => {
-        if (
-            room.roomId === this.props.roomId &&
-            membership === KnownMembership.Join &&
-            oldMembership !== KnownMembership.Join
-        ) {
-            // we just joined the room, load the member list
-            this.updateListNow(true);
-        }
-    };
-
-    private onRoomStateUpdate = (state: RoomState): void => {
-        if (state.roomId !== this.props.roomId) return;
-        this.updateList();
-    };
-
-    private onRoomMemberName = (ev: MatrixEvent, member: RoomMember): void => {
-        if (member.roomId !== this.props.roomId) {
-            return;
-        }
-        this.updateList();
-    };
-
-    private onRoomStateEvent = (event: MatrixEvent): void => {
-        if (event.getRoomId() === this.props.roomId && event.getType() === EventType.RoomThirdPartyInvite) {
-            this.updateList();
-        }
-
-        if (this.canInvite !== this.state.canInvite) this.setState({ canInvite: this.canInvite });
-    };
-
-    private updateList = throttle(
-        () => {
-            this.updateListNow(false);
-        },
-        500,
-        { leading: true, trailing: true },
-    );
-
-    // XXX: exported for tests
-    public async updateListNow(showLoadingSpinner?: boolean): Promise<void> {
-        if (this.unmounted) {
-            return;
-        }
-        if (showLoadingSpinner) {
-            this.setState({ loading: true });
-        }
-        const { joined, invited } = await this.context.memberListStore.loadMemberList(
-            this.props.roomId,
-            this.props.searchQuery,
-        );
-        if (this.unmounted) {
-            return;
-        }
-        this.setState({
-            loading: false,
-            filteredJoinedMembers: joined,
-            filteredInvitedMembers: invited,
-        });
-    }
-
-    private createOverflowTileJoined = (overflowCount: number, totalCount: number): JSX.Element => {
-        return this.createOverflowTile(overflowCount, totalCount, this.showMoreJoinedMemberList);
-    };
-
-    private createOverflowTileInvited = (overflowCount: number, totalCount: number): JSX.Element => {
-        return this.createOverflowTile(overflowCount, totalCount, this.showMoreInvitedMemberList);
-    };
-
-    private createOverflowTile = (overflowCount: number, totalCount: number, onClick: () => void): JSX.Element => {
-        // For now we'll pretend this is any entity. It should probably be a separate tile.
-        const text = _t("common|and_n_others", { count: overflowCount });
-        return (
-            <EntityTile
-                className="mx_EntityTile_ellipsis"
-                avatarJsx={<BaseAvatar url={OverflowHorizontalSvg} name="..." size="36px" />}
-                name={text}
-                showPresence={false}
-                onClick={onClick}
-            />
-        );
-    };
-
-    private showMoreJoinedMemberList = (): void => {
-        this.setState({
-            truncateAtJoined: this.state.truncateAtJoined + SHOW_MORE_INCREMENT,
-        });
-    };
-
-    private showMoreInvitedMemberList = (): void => {
-        this.setState({
-            truncateAtInvited: this.state.truncateAtInvited + SHOW_MORE_INCREMENT,
-        });
-    };
-
-    public componentDidUpdate(prevProps: Readonly<IProps>, prevState: Readonly<IState>, snapshot?: any): void {
-        if (prevProps.searchQuery !== this.props.searchQuery) {
-            this.updateListNow(false);
-        }
-    }
-
-    private onSearchQueryChanged = (searchQuery: string): void => {
-        this.props.onSearchQueryChanged(searchQuery);
-    };
-
-    private onPending3pidInviteClick = (inviteEvent: MatrixEvent): void => {
-        dis.dispatch({
-            action: Action.View3pidInvite,
-            event: inviteEvent,
-        });
-    };
-
-    private getPending3PidInvites(): MatrixEvent[] {
-        // include 3pid invites (m.room.third_party_invite) state events.
-        // The HS may have already converted these into m.room.member invites so
-        // we shouldn't add them if the 3pid invite state key (token) is in the
-        // member invite (content.third_party_invite.signed.token)
-        const room = MatrixClientPeg.safeGet().getRoom(this.props.roomId);
-
-        if (room) {
-            return room.currentState.getStateEvents("m.room.third_party_invite").filter(function (e) {
-                if (!isValid3pidInvite(e)) return false;
-
-                // discard all invites which have a m.room.member event since we've
-                // already added them.
-                const memberEvent = room.currentState.getInviteForThreePidToken(e.getStateKey()!);
-                if (memberEvent) return false;
-                return true;
-            });
-        }
-
-        return [];
-    }
-
-    private makeMemberTiles(members: Array<RoomMember | MatrixEvent>): JSX.Element[] {
-        return members.map((m) => {
-            if (m instanceof RoomMember) {
-                // Is a Matrix invite
-                return (
-                    <MemberTile
-                        key={m.userId}
-                        member={m}
-                        ref={(tile) => {
-                            if (tile) this.tiles.set(m.userId, tile);
-                            else this.tiles.delete(m.userId);
-                        }}
-                        showPresence={this.showPresence}
-                    />
-                );
-            } else {
-                // Is a 3pid invite
-                return (
-                    <EntityTile
-                        key={m.getStateKey()}
-                        name={m.getContent().display_name}
-                        showPresence={false}
-                        onClick={() => this.onPending3pidInviteClick(m)}
-                    />
-                );
-            }
-        });
-    }
-
-    private getChildrenJoined = (start: number, end: number): Array<JSX.Element> => {
-        return this.makeMemberTiles(this.state.filteredJoinedMembers.slice(start, end));
-    };
-
-    private getChildCountJoined = (): number => this.state.filteredJoinedMembers.length;
-
-    private getChildrenInvited = (start: number, end: number): Array<JSX.Element> => {
-        let targets = this.state.filteredInvitedMembers;
-        if (end > this.state.filteredInvitedMembers.length) {
-            targets = targets.concat(this.getPending3PidInvites());
-        }
-
-        return this.makeMemberTiles(targets.slice(start, end));
-    };
-
-    private getChildCountInvited = (): number => {
-        return this.state.filteredInvitedMembers.length + (this.getPending3PidInvites() || []).length;
-    };
-
-    public render(): React.ReactNode {
-        if (this.state.loading) {
-            return (
-                <BaseCard
-                    id="memberlist-panel"
-                    className="mx_MemberList"
-                    ariaLabelledBy="memberlist-panel-tab"
-                    role="tabpanel"
-                    header={_t("common|people")}
-                    onClose={this.props.onClose}
-                >
-                    <Spinner />
-                </BaseCard>
-            );
-        }
-
-        const cli = MatrixClientPeg.safeGet();
-        const room = cli.getRoom(this.props.roomId);
-        let inviteButton: JSX.Element | undefined;
-
-        if (room?.getMyMembership() === KnownMembership.Join && shouldShowComponent(UIComponent.InviteUsers)) {
-            const inviteButtonText = room.isSpaceRoom() ? _t("space|invite_this_space") : _t("room|invite_this_room");
-
-            const button = (
-                <Button
-                    size="sm"
-                    kind="secondary"
-                    className="mx_MemberList_invite"
-                    onClick={this.onInviteButtonClick}
-                    disabled={!this.state.canInvite}
-                >
-                    <UserAddIcon width="1em" height="1em" />
-                    {inviteButtonText}
-                </Button>
-            );
-
-            if (this.state.canInvite) {
-                inviteButton = button;
-            } else {
-                inviteButton = <Tooltip label={_t("member_list|invite_button_no_perms_tooltip")}>{button}</Tooltip>;
-            }
-        }
-
-        let invitedHeader;
-        let invitedSection;
-        if (this.getChildCountInvited() > 0) {
-            invitedHeader = <h2>{_t("member_list|invited_list_heading")}</h2>;
-            invitedSection = (
-                <TruncatedList
-                    className="mx_MemberList_section mx_MemberList_invited"
-                    truncateAt={this.state.truncateAtInvited}
-                    createOverflowElement={this.createOverflowTileInvited}
-                    getChildren={this.getChildrenInvited}
-                    getChildCount={this.getChildCountInvited}
-                />
-            );
-        }
-
-        const footer = (
-            <SearchBox
-                className="mx_MemberList_query mx_textinput_icon mx_textinput_search"
-                placeholder={_t("member_list|filter_placeholder")}
-                onSearch={this.onSearchQueryChanged}
-                initialValue={this.props.searchQuery}
-            />
-        );
-
-        return (
-            <BaseCard
-                id="memberlist-panel"
-                className="mx_MemberList"
-                ariaLabelledBy="memberlist-panel-tab"
-                role="tabpanel"
-                header={_t("common|people")}
-                footer={footer}
-                onClose={this.props.onClose}
-            >
-                {inviteButton}
-                <div className="mx_MemberList_wrapper">
-                    <TruncatedList
-                        className="mx_MemberList_section mx_MemberList_joined"
-                        truncateAt={this.state.truncateAtJoined}
-                        createOverflowElement={this.createOverflowTileJoined}
-                        getChildren={this.getChildrenJoined}
-                        getChildCount={this.getChildCountJoined}
-                    />
-                    {invitedHeader}
-                    {invitedSection}
-                </div>
-            </BaseCard>
-        );
-    }
-
-    private onInviteButtonClick = (ev: ButtonEvent): void => {
-        PosthogTrackers.trackInteraction("WebRightPanelMemberListInviteButton", ev);
-
-        const cli = MatrixClientPeg.safeGet();
-        const room = cli.getRoom(this.props.roomId)!;
-
-        inviteToRoom(room);
-    };
-}
diff --git a/src/components/views/rooms/MemberList/MemberListHeaderView.tsx b/src/components/views/rooms/MemberList/MemberListHeaderView.tsx
new file mode 100644
index 00000000000..7b7531b1e9b
--- /dev/null
+++ b/src/components/views/rooms/MemberList/MemberListHeaderView.tsx
@@ -0,0 +1,137 @@
+/*
+Copyright 2024 New Vector Ltd.
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+Please see LICENSE files in the repository root for full details.
+*/
+
+import { Search, Text, Button, Tooltip, InlineSpinner } from "@vector-im/compound-web";
+import React from "react";
+import InviteIcon from "@vector-im/compound-design-tokens/assets/web/icons/user-add-solid";
+import { UserAddIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
+
+import { Flex } from "../../../utils/Flex";
+import { MemberListViewState } from "../../../viewmodels/memberlist/MemberListViewModel";
+import { _t } from "../../../../languageHandler";
+
+interface TooltipProps {
+    canInvite: boolean;
+    children: React.ReactNode;
+}
+
+const OptionalTooltip: React.FC<TooltipProps> = ({ canInvite, children }) => {
+    if (canInvite) return children;
+    // If the user isn't allowed to invite others to this room, wrap with a relevant tooltip.
+    return <Tooltip description={_t("member_list|invite_button_no_perms_tooltip")}>{children}</Tooltip>;
+};
+
+interface Props {
+    vm: MemberListViewState;
+}
+
+const InviteButton: React.FC<Props> = ({ vm }) => {
+    const shouldShowInvite = vm.shouldShowInvite;
+    const shouldShowSearch = vm.shouldShowSearch;
+    const disabled = !vm.canInvite;
+
+    if (!shouldShowInvite) {
+        // In this case, invite button should not be rendered.
+        return null;
+    }
+
+    if (shouldShowSearch) {
+        /// When rendered alongside a search box, the invite button is just an icon.
+        return (
+            <OptionalTooltip canInvite={vm.canInvite}>
+                <Button
+                    className="mx_MemberListHeaderView_invite_small"
+                    kind="primary"
+                    onClick={vm.onInviteButtonClick}
+                    size="sm"
+                    iconOnly={true}
+                    Icon={InviteIcon}
+                    disabled={disabled}
+                    aria-label={_t("action|invite")}
+                />
+            </OptionalTooltip>
+        );
+    }
+
+    // Without a search box, invite button is a full size button.
+    return (
+        <OptionalTooltip canInvite={vm.canInvite}>
+            <Button
+                kind="secondary"
+                size="sm"
+                Icon={UserAddIcon}
+                className="mx_MemberListHeaderView_invite_large"
+                disabled={!vm.canInvite}
+                onClick={vm.onInviteButtonClick}
+            >
+                {_t("action|invite")}
+            </Button>
+        </OptionalTooltip>
+    );
+};
+
+/**
+ * This should be:
+ * A loading text with spinner while the memberlist loads.
+ * Member count of the room when there's nothing in the search field.
+ * Number of matching members during search or 'No result' if search found nothing.
+ */
+function getHeaderLabelJSX(vm: MemberListViewState): React.ReactNode {
+    if (vm.isLoading) {
+        return (
+            <Flex align="center" gap="8px">
+                <InlineSpinner /> {_t("common|loading")}
+            </Flex>
+        );
+    }
+
+    const filteredMemberCount = vm.members.length;
+    if (filteredMemberCount === 0) {
+        return _t("member_list|no_matches");
+    }
+    return _t("member_list|count", { count: filteredMemberCount });
+}
+
+export const MemberListHeaderView: React.FC<Props> = (props: Props) => {
+    const vm = props.vm;
+
+    let contentJSX: React.ReactNode;
+
+    if (vm.shouldShowSearch) {
+        // When we need to show the search box
+        contentJSX = (
+            <Flex justify="center" className="mx_MemberListHeaderView_container">
+                <Search
+                    className="mx_MemberListHeaderView_search mx_no_textinput"
+                    name="searchMembers"
+                    placeholder={_t("member_list|filter_placeholder")}
+                    onChange={(e) => vm.search((e as React.ChangeEvent<HTMLInputElement>).target.value)}
+                />
+                <InviteButton vm={vm} />
+            </Flex>
+        );
+    } else if (!vm.shouldShowSearch && vm.shouldShowInvite) {
+        // When we don't need to show the search box but still need an invite button
+        contentJSX = (
+            <Flex justify="center" className="mx_MemberListHeaderView_container">
+                <InviteButton vm={vm} />
+            </Flex>
+        );
+    } else {
+        // No search box and no invite icon, so nothing to render!
+        contentJSX = null;
+    }
+
+    return (
+        <Flex className="mx_MemberListHeaderView" as="header" align="center" justify="space-between" direction="column">
+            {!vm.isLoading && contentJSX}
+            <Text as="div" size="sm" weight="semibold" className="mx_MemberListHeaderView_label">
+                {getHeaderLabelJSX(vm)}
+            </Text>
+        </Flex>
+    );
+};
diff --git a/src/components/views/rooms/MemberList/MemberListView.tsx b/src/components/views/rooms/MemberList/MemberListView.tsx
new file mode 100644
index 00000000000..8dd0a0995b5
--- /dev/null
+++ b/src/components/views/rooms/MemberList/MemberListView.tsx
@@ -0,0 +1,82 @@
+/*
+Copyright 2024 New Vector Ltd.
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+Please see LICENSE files in the repository root for full details.
+*/
+
+import { Form } from "@vector-im/compound-web";
+import React from "react";
+import { List, ListRowProps } from "react-virtualized/dist/commonjs/List";
+import { AutoSizer } from "react-virtualized";
+
+import { Flex } from "../../../utils/Flex";
+import { useMemberListViewModel } from "../../../viewmodels/memberlist/MemberListViewModel";
+import { RoomMemberTileView } from "./tiles/RoomMemberTileView";
+import { ThreePidInviteTileView } from "./tiles/ThreePidInviteTileView";
+import { MemberListHeaderView } from "./MemberListHeaderView";
+import BaseCard from "../../right_panel/BaseCard";
+import { _t } from "../../../../languageHandler";
+
+interface IProps {
+    roomId: string;
+    onClose: () => void;
+}
+
+const MemberListView: React.FC<IProps> = (props: IProps) => {
+    const vm = useMemberListViewModel(props.roomId);
+
+    const memberCount = vm.members.length;
+
+    const rowRenderer = ({ key, index, style }: ListRowProps): React.JSX.Element => {
+        if (index === memberCount) {
+            // We've rendered all the members,
+            // now we render an empty div to add some space to the end of the list.
+            return <div key={key} style={style} />;
+        }
+        const item = vm.members[index];
+        return (
+            <div key={key} style={style}>
+                {item.member ? (
+                    <RoomMemberTileView member={item.member} showPresence={vm.isPresenceEnabled} />
+                ) : (
+                    <ThreePidInviteTileView threePidInvite={item.threePidInvite} />
+                )}
+            </div>
+        );
+    };
+
+    return (
+        <BaseCard
+            id="memberlist-panel"
+            className="mx_MemberListView"
+            ariaLabelledBy="memberlist-panel-tab"
+            role="tabpanel"
+            header={_t("common|people")}
+            onClose={props.onClose}
+        >
+            <Flex align="stretch" direction="column" className="mx_MemberListView_container">
+                <Form.Root>
+                    <MemberListHeaderView vm={vm} />
+                </Form.Root>
+                <AutoSizer>
+                    {({ height, width }) => (
+                        <List
+                            rowRenderer={rowRenderer}
+                            // All the member tiles will have a height of 56px.
+                            // The additional empty div at the end of the list should have a height of 32px.
+                            rowHeight={({ index }) => (index === memberCount ? 32 : 56)}
+                            // The +1 refers to the additional empty div that we render at the end of the list.
+                            rowCount={memberCount + 1}
+                            // Subtract the height of MemberlistHeaderView so that the parent div does not overflow.
+                            height={height - 113}
+                            width={width}
+                        />
+                    )}
+                </AutoSizer>
+            </Flex>
+        </BaseCard>
+    );
+};
+
+export default MemberListView;
diff --git a/src/components/views/rooms/MemberList/tiles/RoomMemberTileView.tsx b/src/components/views/rooms/MemberList/tiles/RoomMemberTileView.tsx
new file mode 100644
index 00000000000..c0109e619bc
--- /dev/null
+++ b/src/components/views/rooms/MemberList/tiles/RoomMemberTileView.tsx
@@ -0,0 +1,67 @@
+/*
+Copyright 2024 New Vector Ltd.
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+Please see LICENSE files in the repository root for full details.
+*/
+
+import React from "react";
+
+import DisambiguatedProfile from "../../../messages/DisambiguatedProfile";
+import { RoomMember } from "../../../../../models/rooms/RoomMember";
+import { useMemberTileViewModel } from "../../../../viewmodels/memberlist/tiles/MemberTileViewModel";
+import { E2EIconView } from "./common/E2EIconView";
+import AvatarPresenceIconView from "./common/PresenceIconView";
+import BaseAvatar from "../../../avatars/BaseAvatar";
+import { _t } from "../../../../../languageHandler";
+import { MemberTileLayout } from "./common/MemberTileLayout";
+
+interface IProps {
+    member: RoomMember;
+    showPresence?: boolean;
+}
+
+export function RoomMemberTileView(props: IProps): JSX.Element {
+    const vm = useMemberTileViewModel(props);
+    const member = vm.member;
+    const av = (
+        <BaseAvatar
+            size="32px"
+            name={member.name}
+            idName={member.userId}
+            title={member.displayUserId}
+            url={member.avatarThumbnailUrl}
+            altText={_t("common|user_avatar")}
+        />
+    );
+    const name = vm.name;
+    const nameJSX = <DisambiguatedProfile member={member} fallbackName={name || ""} />;
+
+    const presenceState = member.presenceState;
+    let presenceJSX: JSX.Element | undefined;
+    if (vm.showPresence && presenceState) {
+        presenceJSX = <AvatarPresenceIconView presenceState={presenceState} />;
+    }
+
+    let userLabelJSX;
+    if (vm.userLabel) {
+        userLabelJSX = <div className="mx_MemberTileView_user_label">{vm.userLabel}</div>;
+    }
+
+    let e2eIcon;
+    if (vm.e2eStatus) {
+        e2eIcon = <E2EIconView status={vm.e2eStatus} />;
+    }
+
+    return (
+        <MemberTileLayout
+            title={vm.title}
+            onClick={vm.onClick}
+            avatarJsx={av}
+            presenceJsx={presenceJSX}
+            nameJsx={nameJSX}
+            userLabelJsx={userLabelJSX}
+            e2eIconJsx={e2eIcon}
+        />
+    );
+}
diff --git a/src/components/views/rooms/MemberList/tiles/ThreePidInviteTileView.tsx b/src/components/views/rooms/MemberList/tiles/ThreePidInviteTileView.tsx
new file mode 100644
index 00000000000..f6890cc034f
--- /dev/null
+++ b/src/components/views/rooms/MemberList/tiles/ThreePidInviteTileView.tsx
@@ -0,0 +1,23 @@
+/*
+Copyright 2024 New Vector Ltd.
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+Please see LICENSE files in the repository root for full details.
+*/
+
+import React from "react";
+
+import { useThreePidTileViewModel } from "../../../../viewmodels/memberlist/tiles/ThreePidTileViewModel";
+import { ThreePIDInvite } from "../../../../../models/rooms/ThreePIDInvite";
+import BaseAvatar from "../../../avatars/BaseAvatar";
+import { MemberTileLayout } from "./common/MemberTileLayout";
+
+interface Props {
+    threePidInvite: ThreePIDInvite;
+}
+
+export function ThreePidInviteTileView(props: Props): JSX.Element {
+    const vm = useThreePidTileViewModel(props);
+    const av = <BaseAvatar name={vm.name} size="32px" aria-hidden="true" />;
+    return <MemberTileLayout nameJsx={vm.name} avatarJsx={av} onClick={vm.onClick} />;
+}
diff --git a/src/components/views/rooms/MemberList/tiles/common/E2EIconView.tsx b/src/components/views/rooms/MemberList/tiles/common/E2EIconView.tsx
new file mode 100644
index 00000000000..a1f37e5185c
--- /dev/null
+++ b/src/components/views/rooms/MemberList/tiles/common/E2EIconView.tsx
@@ -0,0 +1,44 @@
+/*
+Copyright 2024 New Vector Ltd.
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+Please see LICENSE files in the repository root for full details.
+*/
+
+import React from "react";
+import { Tooltip } from "@vector-im/compound-web";
+import VerifiedIcon from "@vector-im/compound-design-tokens/assets/web/icons/verified";
+import ErrorIcon from "@vector-im/compound-design-tokens/assets/web/icons/error";
+
+import { _t } from "../../../../../../languageHandler";
+import { E2EStatus } from "../../../../../../utils/ShieldUtils";
+import { crossSigningUserTitles } from "../../../E2EIcon";
+
+function getIconFromStatus(status: E2EStatus): React.JSX.Element | undefined {
+    switch (status) {
+        case E2EStatus.Normal:
+            return undefined;
+        case E2EStatus.Verified:
+            return <VerifiedIcon height="16px" width="16px" className="mx_E2EIconView_verified" />;
+        case E2EStatus.Warning:
+            return <ErrorIcon height="16px" width="16px" className="mx_E2EIconView_warning" />;
+    }
+}
+
+interface Props {
+    status: E2EStatus;
+}
+
+export const E2EIconView: React.FC<Props> = ({ status }) => {
+    const e2eTitle = crossSigningUserTitles[status];
+    const label = e2eTitle ? _t(e2eTitle) : "";
+
+    const icon = getIconFromStatus(status);
+    if (!icon) return null;
+
+    return (
+        <Tooltip label={label}>
+            <div className="mx_E2EIconView">{icon}</div>
+        </Tooltip>
+    );
+};
diff --git a/src/components/views/rooms/MemberList/tiles/common/MemberTileLayout.tsx b/src/components/views/rooms/MemberList/tiles/common/MemberTileLayout.tsx
new file mode 100644
index 00000000000..ae1cf78b3c3
--- /dev/null
+++ b/src/components/views/rooms/MemberList/tiles/common/MemberTileLayout.tsx
@@ -0,0 +1,40 @@
+/*
+Copyright 2024 New Vector Ltd.
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+Please see LICENSE files in the repository root for full details.
+*/
+
+import React from "react";
+
+import AccessibleButton from "../../../../elements/AccessibleButton";
+
+interface Props {
+    avatarJsx: JSX.Element;
+    nameJsx: JSX.Element | string;
+    onClick: () => void;
+    title?: string;
+    presenceJsx?: JSX.Element;
+    userLabelJsx?: JSX.Element;
+    e2eIconJsx?: JSX.Element;
+}
+
+export function MemberTileLayout(props: Props): JSX.Element {
+    return (
+        // The wrapping div is required to make the magic mouse listener work, for some reason.
+        <div>
+            <AccessibleButton className="mx_MemberTileView" title={props.title} onClick={props.onClick}>
+                <div className="mx_MemberTileView_left">
+                    <div className="mx_MemberTileView_avatar">
+                        {props.avatarJsx} {props.presenceJsx}
+                    </div>
+                    <div className="mx_MemberTileView_name">{props.nameJsx}</div>
+                </div>
+                <div className="mx_MemberTileView_right">
+                    {props.userLabelJsx}
+                    {props.e2eIconJsx}
+                </div>
+            </AccessibleButton>
+        </div>
+    );
+}
diff --git a/src/components/views/rooms/MemberList/tiles/common/PresenceIconView.tsx b/src/components/views/rooms/MemberList/tiles/common/PresenceIconView.tsx
new file mode 100644
index 00000000000..855aecf626f
--- /dev/null
+++ b/src/components/views/rooms/MemberList/tiles/common/PresenceIconView.tsx
@@ -0,0 +1,44 @@
+/*
+Copyright 2024 New Vector Ltd.
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+Please see LICENSE files in the repository root for full details.
+*/
+
+import React from "react";
+import OnlineOrUnavailableIcon from "@vector-im/compound-design-tokens/assets/web/icons/presence-solid-8x8";
+import OfflineIcon from "@vector-im/compound-design-tokens/assets/web/icons/presence-outline-8x8";
+import DNDIcon from "@vector-im/compound-design-tokens/assets/web/icons/presence-strikethrough-8x8";
+import classNames from "classnames";
+import { UnstableValue } from "matrix-js-sdk/src/NamespacedValue";
+
+interface Props {
+    className?: string;
+    presenceState: string;
+}
+
+export const BUSY_PRESENCE_NAME = new UnstableValue("busy", "org.matrix.msc3026.busy");
+
+function getIconForPresenceState(state: string): React.JSX.Element {
+    switch (state) {
+        case "online":
+            return <OnlineOrUnavailableIcon height="8px" width="8px" className="mx_PresenceIconView_online" />;
+        case "offline":
+            return <OfflineIcon height="8px" width="8px" className="mx_PresenceIconView_offline" />;
+        case "unavailable":
+        case "io.element.unreachable":
+            return <OnlineOrUnavailableIcon height="8px" width="8px" className="mx_PresenceIconView_unavailable" />;
+        case BUSY_PRESENCE_NAME.name:
+        case BUSY_PRESENCE_NAME.altName:
+            return <DNDIcon height="8px" width="8px" className="mx_PresenceIconView_dnd" />;
+        default:
+            throw new Error(`Presence state "${state}" is unknown.`);
+    }
+}
+
+const AvatarPresenceIconView: React.FC<Props> = ({ className, presenceState }) => {
+    const names = classNames("mx_PresenceIconView", className);
+    return <div className={names}>{getIconForPresenceState(presenceState)}</div>;
+};
+
+export default AvatarPresenceIconView;
diff --git a/src/components/views/rooms/MemberTile.tsx b/src/components/views/rooms/MemberTile.tsx
deleted file mode 100644
index acb2e5153ba..00000000000
--- a/src/components/views/rooms/MemberTile.tsx
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
-Copyright 2015, 2016 OpenMarket Ltd
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
-Please see LICENSE files in the repository root for full details.
-*/
-
-import React from "react";
-import { RoomMember, RoomStateEvent, MatrixEvent, EventType } from "matrix-js-sdk/src/matrix";
-import { CryptoEvent, UserVerificationStatus } from "matrix-js-sdk/src/crypto-api";
-
-import dis from "../../../dispatcher/dispatcher";
-import { _t } from "../../../languageHandler";
-import { MatrixClientPeg } from "../../../MatrixClientPeg";
-import { Action } from "../../../dispatcher/actions";
-import EntityTile, { PowerStatus, PresenceState } from "./EntityTile";
-import MemberAvatar from "./../avatars/MemberAvatar";
-import DisambiguatedProfile from "../messages/DisambiguatedProfile";
-import UserIdentifierCustomisations from "../../../customisations/UserIdentifier";
-import { E2EState } from "./E2EIcon";
-import { asyncSome } from "../../../utils/arrays";
-import { getUserDeviceIds } from "../../../utils/crypto/deviceInfo";
-
-interface IProps {
-    member: RoomMember;
-    showPresence?: boolean;
-}
-
-interface IState {
-    isRoomEncrypted: boolean;
-    e2eStatus?: E2EState;
-}
-
-export default class MemberTile extends React.Component<IProps, IState> {
-    private userLastModifiedTime?: number;
-    private memberLastModifiedTime?: number;
-
-    public static defaultProps = {
-        showPresence: true,
-    };
-
-    public constructor(props: IProps) {
-        super(props);
-
-        this.state = {
-            isRoomEncrypted: false,
-        };
-    }
-
-    public componentDidMount(): void {
-        const cli = MatrixClientPeg.safeGet();
-
-        const { roomId } = this.props.member;
-        if (roomId) {
-            const isRoomEncrypted = cli.isRoomEncrypted(roomId);
-            this.setState({
-                isRoomEncrypted,
-            });
-            if (isRoomEncrypted) {
-                cli.on(CryptoEvent.UserTrustStatusChanged, this.onUserTrustStatusChanged);
-                this.updateE2EStatus();
-            } else {
-                // Listen for room to become encrypted
-                cli.on(RoomStateEvent.Events, this.onRoomStateEvents);
-            }
-        }
-    }
-
-    public componentWillUnmount(): void {
-        const cli = MatrixClientPeg.get();
-
-        if (cli) {
-            cli.removeListener(RoomStateEvent.Events, this.onRoomStateEvents);
-            cli.removeListener(CryptoEvent.UserTrustStatusChanged, this.onUserTrustStatusChanged);
-        }
-    }
-
-    private onRoomStateEvents = (ev: MatrixEvent): void => {
-        if (ev.getType() !== EventType.RoomEncryption) return;
-        const { roomId } = this.props.member;
-        if (ev.getRoomId() !== roomId) return;
-
-        // The room is encrypted now.
-        const cli = MatrixClientPeg.safeGet();
-        cli.removeListener(RoomStateEvent.Events, this.onRoomStateEvents);
-        this.setState({
-            isRoomEncrypted: true,
-        });
-        this.updateE2EStatus();
-    };
-
-    private onUserTrustStatusChanged = (userId: string, trustStatus: UserVerificationStatus): void => {
-        if (userId !== this.props.member.userId) return;
-        this.updateE2EStatus();
-    };
-
-    private async updateE2EStatus(): Promise<void> {
-        const cli = MatrixClientPeg.safeGet();
-        const { userId } = this.props.member;
-        const isMe = userId === cli.getUserId();
-        const userTrust = await cli.getCrypto()?.getUserVerificationStatus(userId);
-        if (!userTrust?.isCrossSigningVerified()) {
-            this.setState({
-                e2eStatus: userTrust?.wasCrossSigningVerified() ? E2EState.Warning : E2EState.Normal,
-            });
-            return;
-        }
-
-        const deviceIDs = await getUserDeviceIds(cli, userId);
-        const anyDeviceUnverified = await asyncSome(deviceIDs, async (deviceId) => {
-            // For your own devices, we use the stricter check of cross-signing
-            // verification to encourage everyone to trust their own devices via
-            // cross-signing so that other users can then safely trust you.
-            // For other people's devices, the more general verified check that
-            // includes locally verified devices can be used.
-            const deviceTrust = await cli.getCrypto()?.getDeviceVerificationStatus(userId, deviceId);
-            return !deviceTrust || (isMe ? !deviceTrust.crossSigningVerified : !deviceTrust.isVerified());
-        });
-        this.setState({
-            e2eStatus: anyDeviceUnverified ? E2EState.Warning : E2EState.Verified,
-        });
-    }
-
-    public shouldComponentUpdate(nextProps: IProps, nextState: IState): boolean {
-        if (
-            this.memberLastModifiedTime === undefined ||
-            this.memberLastModifiedTime < nextProps.member.getLastModifiedTime()
-        ) {
-            return true;
-        }
-        if (
-            nextProps.member.user &&
-            (this.userLastModifiedTime === undefined ||
-                this.userLastModifiedTime < nextProps.member.user.getLastModifiedTime())
-        ) {
-            return true;
-        }
-        if (nextState.isRoomEncrypted !== this.state.isRoomEncrypted || nextState.e2eStatus !== this.state.e2eStatus) {
-            return true;
-        }
-        return false;
-    }
-
-    private onClick = (): void => {
-        dis.dispatch({
-            action: Action.ViewUser,
-            member: this.props.member,
-            push: true,
-        });
-    };
-
-    private getDisplayName(): string {
-        return this.props.member.name;
-    }
-
-    private getPowerLabel(): string {
-        return _t("member_list|power_label", {
-            userName: UserIdentifierCustomisations.getDisplayUserIdentifier(this.props.member.userId, {
-                roomId: this.props.member.roomId,
-            }),
-            powerLevelNumber: this.props.member.powerLevel,
-        }).trim();
-    }
-
-    public render(): React.ReactNode {
-        const member = this.props.member;
-        const name = this.getDisplayName();
-        const presenceState = member.user?.presence as PresenceState | undefined;
-
-        const av = <MemberAvatar member={member} size="36px" aria-hidden="true" />;
-
-        if (member.user) {
-            this.userLastModifiedTime = member.user.getLastModifiedTime();
-        }
-        this.memberLastModifiedTime = member.getLastModifiedTime();
-
-        const powerStatusMap = new Map([
-            [100, PowerStatus.Admin],
-            [50, PowerStatus.Moderator],
-        ]);
-
-        // Find the nearest power level with a badge
-        let powerLevel = this.props.member.powerLevel;
-        for (const [pl] of powerStatusMap) {
-            if (this.props.member.powerLevel >= pl) {
-                powerLevel = pl;
-                break;
-            }
-        }
-
-        const powerStatus = powerStatusMap.get(powerLevel);
-
-        let e2eStatus: E2EState | undefined;
-        if (this.state.isRoomEncrypted) {
-            e2eStatus = this.state.e2eStatus;
-        }
-
-        const nameJSX = <DisambiguatedProfile member={member} fallbackName={name || ""} />;
-
-        return (
-            <EntityTile
-                {...this.props}
-                presenceState={presenceState}
-                presenceLastActiveAgo={member.user ? member.user.lastActiveAgo : 0}
-                presenceLastTs={member.user ? member.user.lastPresenceTs : 0}
-                presenceCurrentlyActive={member.user ? member.user.currentlyActive : false}
-                avatarJsx={av}
-                title={this.getPowerLabel()}
-                name={name}
-                nameJSX={nameJSX}
-                powerStatus={powerStatus}
-                showPresence={this.props.showPresence}
-                e2eStatus={e2eStatus}
-                onClick={this.onClick}
-            />
-        );
-    }
-}
diff --git a/src/components/views/rooms/MessageComposer.tsx b/src/components/views/rooms/MessageComposer.tsx
index f5716d728b6..3cab66201a0 100644
--- a/src/components/views/rooms/MessageComposer.tsx
+++ b/src/components/views/rooms/MessageComposer.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015-2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -128,7 +128,7 @@ export class MessageComposer extends React.Component<IProps, IState> {
         super(props, context);
         this.context = context; // otherwise React will only set it prior to render due to type def above
 
-        const isWysiwygLabEnabled = SettingsStore.getValue<boolean>("feature_wysiwyg_composer");
+        const isWysiwygLabEnabled = SettingsStore.getValue("feature_wysiwyg_composer");
         let isRichTextEnabled = true;
         let initialComposerContent = "";
         if (isWysiwygLabEnabled) {
diff --git a/src/components/views/rooms/MessageComposerButtons.tsx b/src/components/views/rooms/MessageComposerButtons.tsx
index 19b86834dd7..b70c39fb024 100644
--- a/src/components/views/rooms/MessageComposerButtons.tsx
+++ b/src/components/views/rooms/MessageComposerButtons.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -54,7 +54,7 @@ const MessageComposerButtons: React.FC<IProps> = (props: IProps) => {
     const matrixClient = useContext(MatrixClientContext);
     const { room, narrow } = useScopedRoomContext("room", "narrow");
 
-    const isWysiwygLabEnabled = useSettingValue<boolean>("feature_wysiwyg_composer");
+    const isWysiwygLabEnabled = useSettingValue("feature_wysiwyg_composer");
 
     if (!matrixClient || !room || props.haveRecording) {
         return null;
diff --git a/src/components/views/rooms/MessageComposerFormatBar.tsx b/src/components/views/rooms/MessageComposerFormatBar.tsx
index 0ab359d9ddd..855c7c1d40c 100644
--- a/src/components/views/rooms/MessageComposerFormatBar.tsx
+++ b/src/components/views/rooms/MessageComposerFormatBar.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/NewRoomIntro.tsx b/src/components/views/rooms/NewRoomIntro.tsx
index a5577ee372f..cb15917e37f 100644
--- a/src/components/views/rooms/NewRoomIntro.tsx
+++ b/src/components/views/rooms/NewRoomIntro.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020, 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/NotificationBadge.tsx b/src/components/views/rooms/NotificationBadge.tsx
index 6825ea8e43f..f2fe9b08868 100644
--- a/src/components/views/rooms/NotificationBadge.tsx
+++ b/src/components/views/rooms/NotificationBadge.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/NotificationBadge/StatelessNotificationBadge.tsx b/src/components/views/rooms/NotificationBadge/StatelessNotificationBadge.tsx
index 597f6d599bb..7031814607f 100644
--- a/src/components/views/rooms/NotificationBadge/StatelessNotificationBadge.tsx
+++ b/src/components/views/rooms/NotificationBadge/StatelessNotificationBadge.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/NotificationBadge/UnreadNotificationBadge.tsx b/src/components/views/rooms/NotificationBadge/UnreadNotificationBadge.tsx
index dee861f11c2..1c75b34704b 100644
--- a/src/components/views/rooms/NotificationBadge/UnreadNotificationBadge.tsx
+++ b/src/components/views/rooms/NotificationBadge/UnreadNotificationBadge.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/OverflowTileView.tsx b/src/components/views/rooms/OverflowTileView.tsx
new file mode 100644
index 00000000000..c8254069046
--- /dev/null
+++ b/src/components/views/rooms/OverflowTileView.tsx
@@ -0,0 +1,32 @@
+/*
+Copyright 2024 New Vector Ltd.
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+Please see LICENSE files in the repository root for full details.
+*/
+
+import React from "react";
+import Icon from "@vector-im/compound-design-tokens/assets/web/icons/overflow-horizontal";
+
+import { _t } from "../../../languageHandler";
+import AccessibleButton from "../elements/AccessibleButton";
+
+interface Props {
+    // The number of remaining items
+    remaining: number;
+    onClick(): void;
+}
+
+/**
+ * @deprecated Only used in ForwardDialog component; newer designs have moved away from this.
+ */
+export const OverflowTileView: React.FC<Props> = ({ remaining, onClick }) => {
+    return (
+        <AccessibleButton onClick={onClick} className="mx_OverflowTileView">
+            <div className="mx_OverflowTileView_icon">
+                <Icon height="36px" width="36px" />
+            </div>
+            <div className="mx_OverflowTileView_text">{_t("common|and_n_others", { count: remaining })}</div>
+        </AccessibleButton>
+    );
+};
diff --git a/src/components/views/rooms/PinnedEventTile.tsx b/src/components/views/rooms/PinnedEventTile.tsx
index 217571df95f..42cc21026f5 100644
--- a/src/components/views/rooms/PinnedEventTile.tsx
+++ b/src/components/views/rooms/PinnedEventTile.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 Copyright 2017 Travis Ralston
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/PinnedMessageBanner.tsx b/src/components/views/rooms/PinnedMessageBanner.tsx
index 32000d57925..4ba9e0a40c6 100644
--- a/src/components/views/rooms/PinnedMessageBanner.tsx
+++ b/src/components/views/rooms/PinnedMessageBanner.tsx
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2024 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/src/components/views/rooms/PresenceLabel.tsx b/src/components/views/rooms/PresenceLabel.tsx
index de7a46c6666..17197abce3a 100644
--- a/src/components/views/rooms/PresenceLabel.tsx
+++ b/src/components/views/rooms/PresenceLabel.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/ReadReceiptGroup.tsx b/src/components/views/rooms/ReadReceiptGroup.tsx
index ea60518f4b2..e97171493dd 100644
--- a/src/components/views/rooms/ReadReceiptGroup.tsx
+++ b/src/components/views/rooms/ReadReceiptGroup.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/ReadReceiptMarker.tsx b/src/components/views/rooms/ReadReceiptMarker.tsx
index edfad13fc27..9d4feb10c40 100644
--- a/src/components/views/rooms/ReadReceiptMarker.tsx
+++ b/src/components/views/rooms/ReadReceiptMarker.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 Copyright 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/ReplyPreview.tsx b/src/components/views/rooms/ReplyPreview.tsx
index 7851f7914d6..f426a924b87 100644
--- a/src/components/views/rooms/ReplyPreview.tsx
+++ b/src/components/views/rooms/ReplyPreview.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2017-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/ReplyTile.tsx b/src/components/views/rooms/ReplyTile.tsx
index 6841d984dea..73352a806e5 100644
--- a/src/components/views/rooms/ReplyTile.tsx
+++ b/src/components/views/rooms/ReplyTile.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020, 2021 Tulir Asokan <tulir@maunium.net>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/RoomBreadcrumbs.tsx b/src/components/views/rooms/RoomBreadcrumbs.tsx
index bb787d509a9..40290358f54 100644
--- a/src/components/views/rooms/RoomBreadcrumbs.tsx
+++ b/src/components/views/rooms/RoomBreadcrumbs.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/RoomContextDetails.tsx b/src/components/views/rooms/RoomContextDetails.tsx
index d341c6fbbf0..cd6ca327c06 100644
--- a/src/components/views/rooms/RoomContextDetails.tsx
+++ b/src/components/views/rooms/RoomContextDetails.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/RoomHeader.tsx b/src/components/views/rooms/RoomHeader.tsx
index d133587fc92..afe68ee5bec 100644
--- a/src/components/views/rooms/RoomHeader.tsx
+++ b/src/components/views/rooms/RoomHeader.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -310,78 +310,78 @@ export default function RoomHeader({
                         </BodyText>
                     </Box>
                 </button>
-                <Flex align="center" gap="var(--cpd-space-2x)">
-                    {additionalButtons?.map((props) => {
-                        const label = props.label();
 
-                        return (
-                            <Tooltip label={label} key={props.id}>
-                                <IconButton
-                                    aria-label={label}
-                                    onClick={(event) => {
-                                        event.stopPropagation();
-                                        props.onClick();
-                                    }}
-                                >
-                                    {typeof props.icon === "function" ? props.icon() : props.icon}
-                                </IconButton>
-                            </Tooltip>
-                        );
-                    })}
+                {additionalButtons?.map((props) => {
+                    const label = props.label();
 
-                    {isViewingCall && <CallGuestLinkButton room={room} />}
-
-                    {hasActiveCallSession && !isConnectedToCall && !isViewingCall ? (
-                        joinCallButton
-                    ) : (
-                        <>
-                            {!isVideoRoom && videoCallButton}
-                            {!useElementCallExclusively && !isVideoRoom && voiceCallButton}
-                        </>
-                    )}
+                    return (
+                        <Tooltip label={label} key={props.id}>
+                            <IconButton
+                                aria-label={label}
+                                onClick={(event) => {
+                                    event.stopPropagation();
+                                    props.onClick();
+                                }}
+                            >
+                                {typeof props.icon === "function" ? props.icon() : props.icon}
+                            </IconButton>
+                        </Tooltip>
+                    );
+                })}
+
+                {isViewingCall && <CallGuestLinkButton room={room} />}
+
+                {hasActiveCallSession && !isConnectedToCall && !isViewingCall ? (
+                    joinCallButton
+                ) : (
+                    <>
+                        {!isVideoRoom && videoCallButton}
+                        {!useElementCallExclusively && !isVideoRoom && voiceCallButton}
+                    </>
+                )}
 
-                    <Tooltip label={_t("right_panel|room_summary_card|title")}>
+                {showChatButton && <VideoRoomChatButton room={room} />}
+
+                <Tooltip label={_t("common|threads")}>
+                    <IconButton
+                        indicator={notificationLevelToIndicator(threadNotifications)}
+                        onClick={(evt) => {
+                            evt.stopPropagation();
+                            RightPanelStore.instance.showOrHidePhase(RightPanelPhases.ThreadPanel);
+                            PosthogTrackers.trackInteraction("WebRoomHeaderButtonsThreadsButton", evt);
+                        }}
+                        aria-label={_t("common|threads")}
+                    >
+                        <ThreadsIcon />
+                    </IconButton>
+                </Tooltip>
+                {notificationsEnabled && (
+                    <Tooltip label={_t("notifications|enable_prompt_toast_title")}>
                         <IconButton
+                            indicator={notificationLevelToIndicator(globalNotificationState.level)}
                             onClick={(evt) => {
                                 evt.stopPropagation();
-                                RightPanelStore.instance.showOrHidePhase(RightPanelPhases.RoomSummary);
+                                RightPanelStore.instance.showOrHidePhase(RightPanelPhases.NotificationPanel);
                             }}
-                            aria-label={_t("right_panel|room_summary_card|title")}
+                            aria-label={_t("notifications|enable_prompt_toast_title")}
                         >
-                            <RoomInfoIcon />
+                            <NotificationsIcon />
                         </IconButton>
                     </Tooltip>
+                )}
 
-                    {showChatButton && <VideoRoomChatButton room={room} />}
+                <Tooltip label={_t("right_panel|room_summary_card|title")}>
+                    <IconButton
+                        onClick={(evt) => {
+                            evt.stopPropagation();
+                            RightPanelStore.instance.showOrHidePhase(RightPanelPhases.RoomSummary);
+                        }}
+                        aria-label={_t("right_panel|room_summary_card|title")}
+                    >
+                        <RoomInfoIcon />
+                    </IconButton>
+                </Tooltip>
 
-                    <Tooltip label={_t("common|threads")}>
-                        <IconButton
-                            indicator={notificationLevelToIndicator(threadNotifications)}
-                            onClick={(evt) => {
-                                evt.stopPropagation();
-                                RightPanelStore.instance.showOrHidePhase(RightPanelPhases.ThreadPanel);
-                                PosthogTrackers.trackInteraction("WebRoomHeaderButtonsThreadsButton", evt);
-                            }}
-                            aria-label={_t("common|threads")}
-                        >
-                            <ThreadsIcon />
-                        </IconButton>
-                    </Tooltip>
-                    {notificationsEnabled && (
-                        <Tooltip label={_t("notifications|enable_prompt_toast_title")}>
-                            <IconButton
-                                indicator={notificationLevelToIndicator(globalNotificationState.level)}
-                                onClick={(evt) => {
-                                    evt.stopPropagation();
-                                    RightPanelStore.instance.showOrHidePhase(RightPanelPhases.NotificationPanel);
-                                }}
-                                aria-label={_t("notifications|enable_prompt_toast_title")}
-                            >
-                                <NotificationsIcon />
-                            </IconButton>
-                        </Tooltip>
-                    )}
-                </Flex>
                 {!isDirectMessage && (
                     <BodyText as="div" size="sm" weight="medium">
                         <FacePile
diff --git a/src/components/views/rooms/RoomHeader/CallGuestLinkButton.tsx b/src/components/views/rooms/RoomHeader/CallGuestLinkButton.tsx
index 8c000bdf3bc..76e91cada6c 100644
--- a/src/components/views/rooms/RoomHeader/CallGuestLinkButton.tsx
+++ b/src/components/views/rooms/RoomHeader/CallGuestLinkButton.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 import ExternalLinkIcon from "@vector-im/compound-design-tokens/assets/web/icons/link";
diff --git a/src/components/views/rooms/RoomHeader/VideoRoomChatButton.tsx b/src/components/views/rooms/RoomHeader/VideoRoomChatButton.tsx
index af664f68411..0dbf62dfda3 100644
--- a/src/components/views/rooms/RoomHeader/VideoRoomChatButton.tsx
+++ b/src/components/views/rooms/RoomHeader/VideoRoomChatButton.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/RoomInfoLine.tsx b/src/components/views/rooms/RoomInfoLine.tsx
index 1487bfe15b7..438b804d88d 100644
--- a/src/components/views/rooms/RoomInfoLine.tsx
+++ b/src/components/views/rooms/RoomInfoLine.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/RoomKnocksBar.tsx b/src/components/views/rooms/RoomKnocksBar.tsx
index 0ff9ce3e275..64d69566258 100644
--- a/src/components/views/rooms/RoomKnocksBar.tsx
+++ b/src/components/views/rooms/RoomKnocksBar.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 Nordeck IT + Consulting GmbH
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/RoomList.tsx b/src/components/views/rooms/RoomList.tsx
index f3bde66af97..fed1826bbb8 100644
--- a/src/components/views/rooms/RoomList.tsx
+++ b/src/components/views/rooms/RoomList.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015-2018 , 2020, 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/RoomListHeader.tsx b/src/components/views/rooms/RoomListHeader.tsx
index 9ce1d7524fb..aa41c1f2baa 100644
--- a/src/components/views/rooms/RoomListHeader.tsx
+++ b/src/components/views/rooms/RoomListHeader.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021, 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/RoomPreviewBar.tsx b/src/components/views/rooms/RoomPreviewBar.tsx
index b69b01177e3..7b1791d0cdd 100644
--- a/src/components/views/rooms/RoomPreviewBar.tsx
+++ b/src/components/views/rooms/RoomPreviewBar.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/RoomPreviewCard.tsx b/src/components/views/rooms/RoomPreviewCard.tsx
index 2c816e4743e..bce6fc22b30 100644
--- a/src/components/views/rooms/RoomPreviewCard.tsx
+++ b/src/components/views/rooms/RoomPreviewCard.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/RoomSearchAuxPanel.tsx b/src/components/views/rooms/RoomSearchAuxPanel.tsx
index e317e6161b3..1c3ec238b25 100644
--- a/src/components/views/rooms/RoomSearchAuxPanel.tsx
+++ b/src/components/views/rooms/RoomSearchAuxPanel.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/RoomSublist.tsx b/src/components/views/rooms/RoomSublist.tsx
index 34961c08530..dac72994b0b 100644
--- a/src/components/views/rooms/RoomSublist.tsx
+++ b/src/components/views/rooms/RoomSublist.tsx
@@ -4,7 +4,7 @@ Copyright 2020 The Matrix.org Foundation C.I.C.
 Copyright 2017, 2018 Vector Creations Ltd
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/RoomTile.tsx b/src/components/views/rooms/RoomTile.tsx
index 7953c5068db..cbeb5620777 100644
--- a/src/components/views/rooms/RoomTile.tsx
+++ b/src/components/views/rooms/RoomTile.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2018 Michael Telatynski <7t3chguy@gmail.com>
 Copyright 2015-2017 , 2019-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/RoomTileCallSummary.tsx b/src/components/views/rooms/RoomTileCallSummary.tsx
index d97ae1b71e8..8c1db5f34ba 100644
--- a/src/components/views/rooms/RoomTileCallSummary.tsx
+++ b/src/components/views/rooms/RoomTileCallSummary.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/RoomTileSubtitle.tsx b/src/components/views/rooms/RoomTileSubtitle.tsx
index 479b9c4f717..883dc5db0d2 100644
--- a/src/components/views/rooms/RoomTileSubtitle.tsx
+++ b/src/components/views/rooms/RoomTileSubtitle.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/RoomUpgradeWarningBar.tsx b/src/components/views/rooms/RoomUpgradeWarningBar.tsx
index e92be96cb20..3b5685c2299 100644
--- a/src/components/views/rooms/RoomUpgradeWarningBar.tsx
+++ b/src/components/views/rooms/RoomUpgradeWarningBar.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2018-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/SearchResultTile.tsx b/src/components/views/rooms/SearchResultTile.tsx
index 94f5e6da9db..825a5d235f9 100644
--- a/src/components/views/rooms/SearchResultTile.tsx
+++ b/src/components/views/rooms/SearchResultTile.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019-2023 The Matrix.org Foundation C.I.C.
 Copyright 2015 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/SendMessageComposer.tsx b/src/components/views/rooms/SendMessageComposer.tsx
index b3767cbd2a0..d12a84e0c27 100644
--- a/src/components/views/rooms/SendMessageComposer.tsx
+++ b/src/components/views/rooms/SendMessageComposer.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/Stickerpicker.tsx b/src/components/views/rooms/Stickerpicker.tsx
index ad1b11f3688..448e05ac551 100644
--- a/src/components/views/rooms/Stickerpicker.tsx
+++ b/src/components/views/rooms/Stickerpicker.tsx
@@ -1,7 +1,7 @@
 /*
 Copyright 2018-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/ThirdPartyMemberInfo.tsx b/src/components/views/rooms/ThirdPartyMemberInfo.tsx
index df008199cdf..cee38fc078a 100644
--- a/src/components/views/rooms/ThirdPartyMemberInfo.tsx
+++ b/src/components/views/rooms/ThirdPartyMemberInfo.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/ThreadSummary.tsx b/src/components/views/rooms/ThreadSummary.tsx
index ac23331f66d..1ec6a56e78f 100644
--- a/src/components/views/rooms/ThreadSummary.tsx
+++ b/src/components/views/rooms/ThreadSummary.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/TopUnreadMessagesBar.tsx b/src/components/views/rooms/TopUnreadMessagesBar.tsx
index b90c69f8573..f9053cc31a2 100644
--- a/src/components/views/rooms/TopUnreadMessagesBar.tsx
+++ b/src/components/views/rooms/TopUnreadMessagesBar.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2016-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/UserIdentityWarning.tsx b/src/components/views/rooms/UserIdentityWarning.tsx
index dbb6d3d0499..cb2f1e792d6 100644
--- a/src/components/views/rooms/UserIdentityWarning.tsx
+++ b/src/components/views/rooms/UserIdentityWarning.tsx
@@ -1,7 +1,7 @@
 /*
 Copyright 2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/VoiceRecordComposerTile.tsx b/src/components/views/rooms/VoiceRecordComposerTile.tsx
index a8335a9902b..486c9475bc2 100644
--- a/src/components/views/rooms/VoiceRecordComposerTile.tsx
+++ b/src/components/views/rooms/VoiceRecordComposerTile.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021, 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/WhoIsTypingTile.tsx b/src/components/views/rooms/WhoIsTypingTile.tsx
index 85cf4f6dd67..7c0c53c7a2e 100644
--- a/src/components/views/rooms/WhoIsTypingTile.tsx
+++ b/src/components/views/rooms/WhoIsTypingTile.tsx
@@ -2,7 +2,7 @@
 Copyright 2017-2024 New Vector Ltd.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/wysiwyg_composer/ComposerContext.ts b/src/components/views/rooms/wysiwyg_composer/ComposerContext.ts
index 3babdfb9378..cfd8e6fa802 100644
--- a/src/components/views/rooms/wysiwyg_composer/ComposerContext.ts
+++ b/src/components/views/rooms/wysiwyg_composer/ComposerContext.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/wysiwyg_composer/DynamicImportWysiwygComposer.tsx b/src/components/views/rooms/wysiwyg_composer/DynamicImportWysiwygComposer.tsx
index 46210949f5c..f713832d92e 100644
--- a/src/components/views/rooms/wysiwyg_composer/DynamicImportWysiwygComposer.tsx
+++ b/src/components/views/rooms/wysiwyg_composer/DynamicImportWysiwygComposer.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -12,20 +12,16 @@ import { ISendEventResponse } from "matrix-js-sdk/src/matrix";
 // we need to import the types for TS, but do not import the sendMessage
 // function to avoid importing from "@vector-im/matrix-wysiwyg"
 import { SendMessageParams } from "./utils/message";
-import { retry } from "../../../../utils/promise";
 
-// Due to issues such as https://github.com/vector-im/element-web/issues/25277, we add retry
-// attempts to all of the dynamic imports in this file
-const RETRY_COUNT = 3;
-const SendComposer = lazy(() => retry(() => import("./SendWysiwygComposer"), RETRY_COUNT));
-const EditComposer = lazy(() => retry(() => import("./EditWysiwygComposer"), RETRY_COUNT));
+const SendComposer = lazy(() => import("./SendWysiwygComposer"));
+const EditComposer = lazy(() => import("./EditWysiwygComposer"));
 
 export const dynamicImportSendMessage = async (
     message: string,
     isHTML: boolean,
     params: SendMessageParams,
 ): Promise<ISendEventResponse | undefined> => {
-    const { sendMessage } = await retry(() => import("./utils/message"), RETRY_COUNT);
+    const { sendMessage } = await import("./utils/message");
 
     return sendMessage(message, isHTML, params);
 };
@@ -55,7 +51,7 @@ export const dynamicImportConversionFunctions = async (): Promise<{
      */
     plainToRich(plain: string, inMessageFormat: boolean): Promise<string>;
 }> => {
-    const { richToPlain, plainToRich } = await retry(() => import("@vector-im/matrix-wysiwyg"), RETRY_COUNT);
+    const { richToPlain, plainToRich } = await import("@vector-im/matrix-wysiwyg");
 
     return { richToPlain, plainToRich };
 };
diff --git a/src/components/views/rooms/wysiwyg_composer/EditWysiwygComposer.tsx b/src/components/views/rooms/wysiwyg_composer/EditWysiwygComposer.tsx
index 98597c73609..25822b91766 100644
--- a/src/components/views/rooms/wysiwyg_composer/EditWysiwygComposer.tsx
+++ b/src/components/views/rooms/wysiwyg_composer/EditWysiwygComposer.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/wysiwyg_composer/SendWysiwygComposer.tsx b/src/components/views/rooms/wysiwyg_composer/SendWysiwygComposer.tsx
index 7f790978f63..64785669695 100644
--- a/src/components/views/rooms/wysiwyg_composer/SendWysiwygComposer.tsx
+++ b/src/components/views/rooms/wysiwyg_composer/SendWysiwygComposer.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/wysiwyg_composer/components/EditionButtons.tsx b/src/components/views/rooms/wysiwyg_composer/components/EditionButtons.tsx
index fccd4b7f242..0a6a78210c3 100644
--- a/src/components/views/rooms/wysiwyg_composer/components/EditionButtons.tsx
+++ b/src/components/views/rooms/wysiwyg_composer/components/EditionButtons.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/wysiwyg_composer/components/Editor.tsx b/src/components/views/rooms/wysiwyg_composer/components/Editor.tsx
index 7e3d0f4d65a..79bc19445ca 100644
--- a/src/components/views/rooms/wysiwyg_composer/components/Editor.tsx
+++ b/src/components/views/rooms/wysiwyg_composer/components/Editor.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/wysiwyg_composer/components/Emoji.tsx b/src/components/views/rooms/wysiwyg_composer/components/Emoji.tsx
index 9ab3d210abc..94d7603c6b4 100644
--- a/src/components/views/rooms/wysiwyg_composer/components/Emoji.tsx
+++ b/src/components/views/rooms/wysiwyg_composer/components/Emoji.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/wysiwyg_composer/components/FormattingButtons.tsx b/src/components/views/rooms/wysiwyg_composer/components/FormattingButtons.tsx
index f02f1a4c6b1..e541d17e0dd 100644
--- a/src/components/views/rooms/wysiwyg_composer/components/FormattingButtons.tsx
+++ b/src/components/views/rooms/wysiwyg_composer/components/FormattingButtons.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/wysiwyg_composer/components/LinkModal.tsx b/src/components/views/rooms/wysiwyg_composer/components/LinkModal.tsx
index 3b5bfb7ad4e..31f153dbec8 100644
--- a/src/components/views/rooms/wysiwyg_composer/components/LinkModal.tsx
+++ b/src/components/views/rooms/wysiwyg_composer/components/LinkModal.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/wysiwyg_composer/components/PlainTextComposer.tsx b/src/components/views/rooms/wysiwyg_composer/components/PlainTextComposer.tsx
index 787f0dd889d..c826bbc98b5 100644
--- a/src/components/views/rooms/wysiwyg_composer/components/PlainTextComposer.tsx
+++ b/src/components/views/rooms/wysiwyg_composer/components/PlainTextComposer.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -45,7 +45,7 @@ export function PlainTextComposer({
     rightComponent,
     eventRelation,
 }: PlainTextComposerProps): JSX.Element {
-    const isAutoReplaceEmojiEnabled = useSettingValue<boolean>("MessageComposerInput.autoReplaceEmoji");
+    const isAutoReplaceEmojiEnabled = useSettingValue("MessageComposerInput.autoReplaceEmoji");
     const {
         ref: editorRef,
         autocompleteRef,
diff --git a/src/components/views/rooms/wysiwyg_composer/components/WysiwygAutocomplete.tsx b/src/components/views/rooms/wysiwyg_composer/components/WysiwygAutocomplete.tsx
index 4d06adcd4e7..b006ec2d352 100644
--- a/src/components/views/rooms/wysiwyg_composer/components/WysiwygAutocomplete.tsx
+++ b/src/components/views/rooms/wysiwyg_composer/components/WysiwygAutocomplete.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/wysiwyg_composer/components/WysiwygComposer.tsx b/src/components/views/rooms/wysiwyg_composer/components/WysiwygComposer.tsx
index f1e42ce091f..e7dd0213a4c 100644
--- a/src/components/views/rooms/wysiwyg_composer/components/WysiwygComposer.tsx
+++ b/src/components/views/rooms/wysiwyg_composer/components/WysiwygComposer.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -61,7 +61,7 @@ export const WysiwygComposer = memo(function WysiwygComposer({
 
     const inputEventProcessor = useInputEventProcessor(onSend, autocompleteRef, initialContent, eventRelation);
 
-    const isAutoReplaceEmojiEnabled = useSettingValue<boolean>("MessageComposerInput.autoReplaceEmoji");
+    const isAutoReplaceEmojiEnabled = useSettingValue("MessageComposerInput.autoReplaceEmoji");
     const emojiSuggestions = useMemo(() => getEmojiSuggestions(isAutoReplaceEmojiEnabled), [isAutoReplaceEmojiEnabled]);
 
     const { ref, isWysiwygReady, content, actionStates, wysiwyg, suggestion, messageContent } = useWysiwyg({
diff --git a/src/components/views/rooms/wysiwyg_composer/hooks/useComposerFunctions.ts b/src/components/views/rooms/wysiwyg_composer/hooks/useComposerFunctions.ts
index aa7c672af3a..f5219c6543d 100644
--- a/src/components/views/rooms/wysiwyg_composer/hooks/useComposerFunctions.ts
+++ b/src/components/views/rooms/wysiwyg_composer/hooks/useComposerFunctions.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/wysiwyg_composer/hooks/useEditing.ts b/src/components/views/rooms/wysiwyg_composer/hooks/useEditing.ts
index 20f394e8a3e..8fbd856200a 100644
--- a/src/components/views/rooms/wysiwyg_composer/hooks/useEditing.ts
+++ b/src/components/views/rooms/wysiwyg_composer/hooks/useEditing.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/wysiwyg_composer/hooks/useInitialContent.ts b/src/components/views/rooms/wysiwyg_composer/hooks/useInitialContent.ts
index 3a3799496b8..25afcd431f1 100644
--- a/src/components/views/rooms/wysiwyg_composer/hooks/useInitialContent.ts
+++ b/src/components/views/rooms/wysiwyg_composer/hooks/useInitialContent.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/wysiwyg_composer/hooks/useInputEventProcessor.ts b/src/components/views/rooms/wysiwyg_composer/hooks/useInputEventProcessor.ts
index cab3bdefb85..26a72f4b96f 100644
--- a/src/components/views/rooms/wysiwyg_composer/hooks/useInputEventProcessor.ts
+++ b/src/components/views/rooms/wysiwyg_composer/hooks/useInputEventProcessor.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -36,7 +36,7 @@ export function useInputEventProcessor(
     const roomContext = useScopedRoomContext("liveTimeline", "room", "replyToEvent", "timelineRenderingType");
     const composerContext = useComposerContext();
     const mxClient = useMatrixClientContext();
-    const isCtrlEnterToSend = useSettingValue<boolean>("MessageComposerInput.ctrlEnterToSend");
+    const isCtrlEnterToSend = useSettingValue("MessageComposerInput.ctrlEnterToSend");
 
     return useCallback(
         (event: WysiwygEvent, composer: Wysiwyg, editor: HTMLElement) => {
diff --git a/src/components/views/rooms/wysiwyg_composer/hooks/useIsExpanded.ts b/src/components/views/rooms/wysiwyg_composer/hooks/useIsExpanded.ts
index 09e47d7b0c1..9941dda7bb7 100644
--- a/src/components/views/rooms/wysiwyg_composer/hooks/useIsExpanded.ts
+++ b/src/components/views/rooms/wysiwyg_composer/hooks/useIsExpanded.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/wysiwyg_composer/hooks/useIsFocused.ts b/src/components/views/rooms/wysiwyg_composer/hooks/useIsFocused.ts
index de9f758dc66..13919397131 100644
--- a/src/components/views/rooms/wysiwyg_composer/hooks/useIsFocused.ts
+++ b/src/components/views/rooms/wysiwyg_composer/hooks/useIsFocused.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/wysiwyg_composer/hooks/usePlainTextInitialization.ts b/src/components/views/rooms/wysiwyg_composer/hooks/usePlainTextInitialization.ts
index 6adf43d9a42..52613b6b2ae 100644
--- a/src/components/views/rooms/wysiwyg_composer/hooks/usePlainTextInitialization.ts
+++ b/src/components/views/rooms/wysiwyg_composer/hooks/usePlainTextInitialization.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/wysiwyg_composer/hooks/usePlainTextListeners.ts b/src/components/views/rooms/wysiwyg_composer/hooks/usePlainTextListeners.ts
index 1dc23cc274a..6dfae53efed 100644
--- a/src/components/views/rooms/wysiwyg_composer/hooks/usePlainTextListeners.ts
+++ b/src/components/views/rooms/wysiwyg_composer/hooks/usePlainTextListeners.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -128,7 +128,7 @@ export function usePlainTextListeners(
         [eventRelation, mxClient, onInput, roomContext],
     );
 
-    const enterShouldSend = !useSettingValue<boolean>("MessageComposerInput.ctrlEnterToSend");
+    const enterShouldSend = !useSettingValue("MessageComposerInput.ctrlEnterToSend");
     const onKeyDown = useCallback(
         (event: KeyboardEvent<HTMLDivElement>) => {
             // we need autocomplete to take priority when it is open for using enter to select
diff --git a/src/components/views/rooms/wysiwyg_composer/hooks/useSelection.ts b/src/components/views/rooms/wysiwyg_composer/hooks/useSelection.ts
index aa541afa568..0689c466f65 100644
--- a/src/components/views/rooms/wysiwyg_composer/hooks/useSelection.ts
+++ b/src/components/views/rooms/wysiwyg_composer/hooks/useSelection.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/wysiwyg_composer/hooks/useSetCursorPosition.ts b/src/components/views/rooms/wysiwyg_composer/hooks/useSetCursorPosition.ts
index 01d42378a8a..8fd39111ff6 100644
--- a/src/components/views/rooms/wysiwyg_composer/hooks/useSetCursorPosition.ts
+++ b/src/components/views/rooms/wysiwyg_composer/hooks/useSetCursorPosition.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/wysiwyg_composer/hooks/useSuggestion.ts b/src/components/views/rooms/wysiwyg_composer/hooks/useSuggestion.ts
index 5b4957a9c58..6e4473f4545 100644
--- a/src/components/views/rooms/wysiwyg_composer/hooks/useSuggestion.ts
+++ b/src/components/views/rooms/wysiwyg_composer/hooks/useSuggestion.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/wysiwyg_composer/hooks/useWysiwygEditActionHandler.ts b/src/components/views/rooms/wysiwyg_composer/hooks/useWysiwygEditActionHandler.ts
index eb76d77af5d..8761b8addb5 100644
--- a/src/components/views/rooms/wysiwyg_composer/hooks/useWysiwygEditActionHandler.ts
+++ b/src/components/views/rooms/wysiwyg_composer/hooks/useWysiwygEditActionHandler.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/wysiwyg_composer/hooks/useWysiwygSendActionHandler.ts b/src/components/views/rooms/wysiwyg_composer/hooks/useWysiwygSendActionHandler.ts
index d11f3498fd7..cef635ef5b2 100644
--- a/src/components/views/rooms/wysiwyg_composer/hooks/useWysiwygSendActionHandler.ts
+++ b/src/components/views/rooms/wysiwyg_composer/hooks/useWysiwygSendActionHandler.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/wysiwyg_composer/hooks/utils.ts b/src/components/views/rooms/wysiwyg_composer/hooks/utils.ts
index 3345c9f474a..52a61ac0e3d 100644
--- a/src/components/views/rooms/wysiwyg_composer/hooks/utils.ts
+++ b/src/components/views/rooms/wysiwyg_composer/hooks/utils.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/wysiwyg_composer/index.ts b/src/components/views/rooms/wysiwyg_composer/index.ts
index 82d7d2a9046..281ea634f80 100644
--- a/src/components/views/rooms/wysiwyg_composer/index.ts
+++ b/src/components/views/rooms/wysiwyg_composer/index.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/wysiwyg_composer/types.ts b/src/components/views/rooms/wysiwyg_composer/types.ts
index d38704f3460..f6ce2619094 100644
--- a/src/components/views/rooms/wysiwyg_composer/types.ts
+++ b/src/components/views/rooms/wysiwyg_composer/types.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/wysiwyg_composer/utils/autocomplete.ts b/src/components/views/rooms/wysiwyg_composer/utils/autocomplete.ts
index d97b07adee7..529f15cff39 100644
--- a/src/components/views/rooms/wysiwyg_composer/utils/autocomplete.ts
+++ b/src/components/views/rooms/wysiwyg_composer/utils/autocomplete.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/wysiwyg_composer/utils/createMessageContent.ts b/src/components/views/rooms/wysiwyg_composer/utils/createMessageContent.ts
index 58d09b3d128..5778faa61a4 100644
--- a/src/components/views/rooms/wysiwyg_composer/utils/createMessageContent.ts
+++ b/src/components/views/rooms/wysiwyg_composer/utils/createMessageContent.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -66,7 +66,7 @@ export async function createMessageContent(
 
     // TODO markdown support
 
-    const isMarkdownEnabled = SettingsStore.getValue<boolean>("MessageComposerInput.useMarkdown");
+    const isMarkdownEnabled = SettingsStore.getValue("MessageComposerInput.useMarkdown");
     const formattedBody = isHTML ? message : isMarkdownEnabled ? await plainToRich(message, true) : null;
 
     if (formattedBody) {
diff --git a/src/components/views/rooms/wysiwyg_composer/utils/editing.ts b/src/components/views/rooms/wysiwyg_composer/utils/editing.ts
index 462763b8f46..fd5c7d1997b 100644
--- a/src/components/views/rooms/wysiwyg_composer/utils/editing.ts
+++ b/src/components/views/rooms/wysiwyg_composer/utils/editing.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/wysiwyg_composer/utils/event.ts b/src/components/views/rooms/wysiwyg_composer/utils/event.ts
index 45c6b1cac34..5860ae9ec6b 100644
--- a/src/components/views/rooms/wysiwyg_composer/utils/event.ts
+++ b/src/components/views/rooms/wysiwyg_composer/utils/event.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/wysiwyg_composer/utils/isContentModified.ts b/src/components/views/rooms/wysiwyg_composer/utils/isContentModified.ts
index 6ffbb9b69a3..3821ca3512f 100644
--- a/src/components/views/rooms/wysiwyg_composer/utils/isContentModified.ts
+++ b/src/components/views/rooms/wysiwyg_composer/utils/isContentModified.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/wysiwyg_composer/utils/message.ts b/src/components/views/rooms/wysiwyg_composer/utils/message.ts
index b7fca8ecb4a..8f95bf8da14 100644
--- a/src/components/views/rooms/wysiwyg_composer/utils/message.ts
+++ b/src/components/views/rooms/wysiwyg_composer/utils/message.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022, 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/rooms/wysiwyg_composer/utils/selection.ts b/src/components/views/rooms/wysiwyg_composer/utils/selection.ts
index f526675213a..95da5ef66bf 100644
--- a/src/components/views/rooms/wysiwyg_composer/utils/selection.ts
+++ b/src/components/views/rooms/wysiwyg_composer/utils/selection.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/AddPrivilegedUsers.tsx b/src/components/views/settings/AddPrivilegedUsers.tsx
index c19c8fdddc8..5276e825fd7 100644
--- a/src/components/views/settings/AddPrivilegedUsers.tsx
+++ b/src/components/views/settings/AddPrivilegedUsers.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/AddRemoveThreepids.tsx b/src/components/views/settings/AddRemoveThreepids.tsx
index 8b2b61bb9ac..704f2a12927 100644
--- a/src/components/views/settings/AddRemoveThreepids.tsx
+++ b/src/components/views/settings/AddRemoveThreepids.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/AvatarSetting.tsx b/src/components/views/settings/AvatarSetting.tsx
index ee47094cf93..2ed4d065687 100644
--- a/src/components/views/settings/AvatarSetting.tsx
+++ b/src/components/views/settings/AvatarSetting.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/BridgeTile.tsx b/src/components/views/settings/BridgeTile.tsx
index 6ae860aa0aa..ad9088116cc 100644
--- a/src/components/views/settings/BridgeTile.tsx
+++ b/src/components/views/settings/BridgeTile.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020-2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/ChangePassword.tsx b/src/components/views/settings/ChangePassword.tsx
index 9461f20d8a0..07a13cd3476 100644
--- a/src/components/views/settings/ChangePassword.tsx
+++ b/src/components/views/settings/ChangePassword.tsx
@@ -2,7 +2,7 @@
 Copyright 2018-2024 New Vector Ltd.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/CrossSigningPanel.tsx b/src/components/views/settings/CrossSigningPanel.tsx
index a91238848e9..9ec9e9f6c18 100644
--- a/src/components/views/settings/CrossSigningPanel.tsx
+++ b/src/components/views/settings/CrossSigningPanel.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/CryptographyPanel.tsx b/src/components/views/settings/CryptographyPanel.tsx
index fbd696f243f..beb08ab1e92 100644
--- a/src/components/views/settings/CryptographyPanel.tsx
+++ b/src/components/views/settings/CryptographyPanel.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/EventIndexPanel.tsx b/src/components/views/settings/EventIndexPanel.tsx
index 0051c4dc3a0..41845eb94ea 100644
--- a/src/components/views/settings/EventIndexPanel.tsx
+++ b/src/components/views/settings/EventIndexPanel.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020, 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -214,7 +214,7 @@ export default class EventIndexPanel extends React.Component<{}, IState> {
                     <SettingsSubsectionText>
                         {this.state.enabling ? <InlineSpinner /> : _t("settings|security|message_search_failed")}
                     </SettingsSubsectionText>
-                    {EventIndexPeg.error && (
+                    {EventIndexPeg.error ? (
                         <SettingsSubsectionText>
                             <details>
                                 <summary>{_t("common|advanced")}</summary>
@@ -230,7 +230,7 @@ export default class EventIndexPanel extends React.Component<{}, IState> {
                                 </p>
                             </details>
                         </SettingsSubsectionText>
-                    )}
+                    ) : undefined}
                 </>
             );
         }
diff --git a/src/components/views/settings/FontScalingPanel.tsx b/src/components/views/settings/FontScalingPanel.tsx
index edc6c66645e..e1a7f4902fe 100644
--- a/src/components/views/settings/FontScalingPanel.tsx
+++ b/src/components/views/settings/FontScalingPanel.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021-2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -47,7 +47,7 @@ export default class FontScalingPanel extends React.Component<IProps, IState> {
         super(props);
 
         this.state = {
-            fontSizeDelta: SettingsStore.getValue<number>("fontSizeDelta", null),
+            fontSizeDelta: SettingsStore.getValue("fontSizeDelta", null),
             browserFontSize: FontWatcher.getBrowserDefaultFontSize(),
             useCustomFontSize: SettingsStore.getValue("useCustomFontSize"),
             layout: SettingsStore.getValue("layout"),
diff --git a/src/components/views/settings/ImageSizePanel.tsx b/src/components/views/settings/ImageSizePanel.tsx
index dca21d89e2f..8079ea16543 100644
--- a/src/components/views/settings/ImageSizePanel.tsx
+++ b/src/components/views/settings/ImageSizePanel.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/IntegrationManager.tsx b/src/components/views/settings/IntegrationManager.tsx
index 3a31a9e9c85..28a5130b25b 100644
--- a/src/components/views/settings/IntegrationManager.tsx
+++ b/src/components/views/settings/IntegrationManager.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/JoinRuleSettings.tsx b/src/components/views/settings/JoinRuleSettings.tsx
index a6c1e91241c..023b68c282c 100644
--- a/src/components/views/settings/JoinRuleSettings.tsx
+++ b/src/components/views/settings/JoinRuleSettings.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/KeyboardShortcut.tsx b/src/components/views/settings/KeyboardShortcut.tsx
index 4f0973b1027..f84c89208ae 100644
--- a/src/components/views/settings/KeyboardShortcut.tsx
+++ b/src/components/views/settings/KeyboardShortcut.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 Šimon Brandner <simon.bra.ag@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/LayoutSwitcher.tsx b/src/components/views/settings/LayoutSwitcher.tsx
index bbf090aa383..075c92fce77 100644
--- a/src/components/views/settings/LayoutSwitcher.tsx
+++ b/src/components/views/settings/LayoutSwitcher.tsx
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2024 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
@@ -70,7 +70,7 @@ interface LayoutRadioProps {
  * @param label
  */
 function LayoutRadio({ layout, label }: LayoutRadioProps): JSX.Element {
-    const currentLayout = useSettingValue<Layout>("layout");
+    const currentLayout = useSettingValue("layout");
     const eventTileInfo = useEventTileInfo();
 
     return (
@@ -134,8 +134,8 @@ function useEventTileInfo(): EventTileInfo {
  * A toggleable setting to enable or disable the compact layout.
  */
 function ToggleCompactLayout(): JSX.Element {
-    const compactLayoutEnabled = useSettingValue<boolean>("useCompactLayout");
-    const layout = useSettingValue<Layout>("layout");
+    const compactLayoutEnabled = useSettingValue("useCompactLayout");
+    const layout = useSettingValue("layout");
 
     return (
         <Root
diff --git a/src/components/views/settings/Notifications.tsx b/src/components/views/settings/Notifications.tsx
index 4ac5e2069b0..6cf4f8abea9 100644
--- a/src/components/views/settings/Notifications.tsx
+++ b/src/components/views/settings/Notifications.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2016-2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/PowerLevelSelector.tsx b/src/components/views/settings/PowerLevelSelector.tsx
index a2de6791d78..5bc2da9f92b 100644
--- a/src/components/views/settings/PowerLevelSelector.tsx
+++ b/src/components/views/settings/PowerLevelSelector.tsx
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2024 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/src/components/views/settings/SecureBackupPanel.tsx b/src/components/views/settings/SecureBackupPanel.tsx
index 05c78296441..3d245678320 100644
--- a/src/components/views/settings/SecureBackupPanel.tsx
+++ b/src/components/views/settings/SecureBackupPanel.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
 Copyright 2018 New Vector Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/SetIdServer.tsx b/src/components/views/settings/SetIdServer.tsx
index 6dc3ae48a2c..9345d87e825 100644
--- a/src/components/views/settings/SetIdServer.tsx
+++ b/src/components/views/settings/SetIdServer.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/SetIntegrationManager.tsx b/src/components/views/settings/SetIntegrationManager.tsx
index c129d0e2e1c..01dab795470 100644
--- a/src/components/views/settings/SetIntegrationManager.tsx
+++ b/src/components/views/settings/SetIntegrationManager.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/SettingsFieldset.tsx b/src/components/views/settings/SettingsFieldset.tsx
index 1ff40bcf71d..3316b657e61 100644
--- a/src/components/views/settings/SettingsFieldset.tsx
+++ b/src/components/views/settings/SettingsFieldset.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/SettingsHeader.tsx b/src/components/views/settings/SettingsHeader.tsx
new file mode 100644
index 00000000000..9a83ba1d929
--- /dev/null
+++ b/src/components/views/settings/SettingsHeader.tsx
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2024 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+import React, { JSX } from "react";
+import { Heading } from "@vector-im/compound-web";
+
+import { _t } from "../../../languageHandler";
+
+/**
+ * The heading for a settings section.
+ */
+interface SettingsHeaderProps {
+    /**
+     * Whether the user has a recommended tag.
+     */
+    hasRecommendedTag?: boolean;
+    /**
+     * The label for the header.
+     */
+    label: string;
+}
+
+export function SettingsHeader({ hasRecommendedTag = false, label }: SettingsHeaderProps): JSX.Element {
+    return (
+        <Heading className="mx_SettingsHeader" as="h2" size="sm" weight="semibold">
+            {label} {hasRecommendedTag && <span>{_t("common|recommended")}</span>}
+        </Heading>
+    );
+}
diff --git a/src/components/views/settings/SettingsSubheader.tsx b/src/components/views/settings/SettingsSubheader.tsx
new file mode 100644
index 00000000000..90b8a41b7ae
--- /dev/null
+++ b/src/components/views/settings/SettingsSubheader.tsx
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2024 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+import React, { JSX } from "react";
+import CheckCircleIcon from "@vector-im/compound-design-tokens/assets/web/icons/check-circle-solid";
+import ErrorIcon from "@vector-im/compound-design-tokens/assets/web/icons/error";
+import classNames from "classnames";
+
+interface SettingsSubheaderProps {
+    /**
+     * The subheader text.
+     */
+    label?: string;
+    /**
+     * The state of the subheader.
+     */
+    state: "success" | "error";
+    /**
+     * The message to display next to the state icon.
+     */
+    stateMessage: string;
+}
+
+/**
+ * A styled subheader for settings.
+ */
+export function SettingsSubheader({ label, state, stateMessage }: SettingsSubheaderProps): JSX.Element {
+    return (
+        <div className="mx_SettingsSubheader">
+            {label}
+            <span
+                className={classNames({
+                    mx_SettingsSubheader_success: state === "success",
+                    mx_SettingsSubheader_error: state === "error",
+                })}
+            >
+                {state === "success" ? (
+                    <CheckCircleIcon width="20px" height="20px" />
+                ) : (
+                    <ErrorIcon width="20px" height="20px" />
+                )}
+                {stateMessage}
+            </span>
+        </div>
+    );
+}
diff --git a/src/components/views/settings/SpellCheckSettings.tsx b/src/components/views/settings/SpellCheckSettings.tsx
index 13f542b7491..1ec8e0adce9 100644
--- a/src/components/views/settings/SpellCheckSettings.tsx
+++ b/src/components/views/settings/SpellCheckSettings.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/ThemeChoicePanel.tsx b/src/components/views/settings/ThemeChoicePanel.tsx
index 83f17a2f7be..0e3926d7e8e 100644
--- a/src/components/views/settings/ThemeChoicePanel.tsx
+++ b/src/components/views/settings/ThemeChoicePanel.tsx
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2024 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
@@ -40,7 +40,7 @@ import { useSettingValue } from "../../../hooks/useSettings";
 export function ThemeChoicePanel(): JSX.Element {
     const themeState = useTheme();
     const themeWatcher = useRef(new ThemeWatcher());
-    const customThemeEnabled = useSettingValue<boolean>("feature_custom_themes");
+    const customThemeEnabled = useSettingValue("feature_custom_themes");
 
     return (
         <SettingsSubsection heading={_t("common|theme")} legacy={false} data-testid="themePanel">
@@ -159,7 +159,7 @@ function ThemeSelectors({ theme, disabled }: ThemeSelectorProps): JSX.Element {
  * Return all the available themes
  */
 function useThemes(): Array<ITheme & { isDark: boolean }> {
-    const customThemes = useSettingValue<CustomThemeType[] | undefined>("custom_themes");
+    const customThemes = useSettingValue("custom_themes");
     return useMemo(() => {
         // Put the custom theme into a map
         // To easily find the theme by name when going through the themes list
@@ -239,8 +239,7 @@ function CustomTheme({ theme }: CustomThemeProps): JSX.Element {
 
                     // Get the custom themes and do a cheap clone
                     // To avoid to mutate the original array in the settings
-                    const currentThemes =
-                        SettingsStore.getValue<CustomThemeType[]>("custom_themes").map((t) => t) || [];
+                    const currentThemes = SettingsStore.getValue("custom_themes").map((t) => t) || [];
 
                     try {
                         const r = await fetch(customTheme);
@@ -294,7 +293,7 @@ interface CustomThemeListProps {
  * List of the custom themes
  */
 function CustomThemeList({ theme: currentTheme }: CustomThemeListProps): JSX.Element {
-    const customThemes = useSettingValue<CustomThemeType[]>("custom_themes") || [];
+    const customThemes = useSettingValue("custom_themes") || [];
 
     return (
         <ul className="mx_ThemeChoicePanel_CustomThemeList">
@@ -309,8 +308,7 @@ function CustomThemeList({ theme: currentTheme }: CustomThemeListProps): JSX.Ele
                             onClick={async () => {
                                 // Get the custom themes and do a cheap clone
                                 // To avoid to mutate the original array in the settings
-                                const currentThemes =
-                                    SettingsStore.getValue<CustomThemeType[]>("custom_themes").map((t) => t) || [];
+                                const currentThemes = SettingsStore.getValue("custom_themes").map((t) => t) || [];
 
                                 // Remove the theme from the list
                                 const newThemes = currentThemes.filter((t) => t.name !== theme.name);
diff --git a/src/components/views/settings/UpdateCheckButton.tsx b/src/components/views/settings/UpdateCheckButton.tsx
index 3b2c9bfa681..e283373eb99 100644
--- a/src/components/views/settings/UpdateCheckButton.tsx
+++ b/src/components/views/settings/UpdateCheckButton.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/UserPersonalInfoSettings.tsx b/src/components/views/settings/UserPersonalInfoSettings.tsx
index e33aa87781d..c08c0f636fe 100644
--- a/src/components/views/settings/UserPersonalInfoSettings.tsx
+++ b/src/components/views/settings/UserPersonalInfoSettings.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/UserProfileSettings.tsx b/src/components/views/settings/UserProfileSettings.tsx
index 83a00c122d4..5fba36ad015 100644
--- a/src/components/views/settings/UserProfileSettings.tsx
+++ b/src/components/views/settings/UserProfileSettings.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/devices/CurrentDeviceSection.tsx b/src/components/views/settings/devices/CurrentDeviceSection.tsx
index 153a9c5d4bd..245c244c90f 100644
--- a/src/components/views/settings/devices/CurrentDeviceSection.tsx
+++ b/src/components/views/settings/devices/CurrentDeviceSection.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -34,6 +34,7 @@ interface Props {
     onSignOutCurrentDevice: () => void;
     signOutAllOtherSessions?: () => void;
     saveDeviceName: (deviceName: string) => Promise<void>;
+    delegatedAuthAccountUrl?: string;
 }
 
 type CurrentDeviceSectionHeadingProps = Pick<
@@ -90,6 +91,7 @@ const CurrentDeviceSection: React.FC<Props> = ({
     onSignOutCurrentDevice,
     signOutAllOtherSessions,
     saveDeviceName,
+    delegatedAuthAccountUrl,
 }) => {
     const [isExpanded, setIsExpanded] = useState(false);
 
@@ -126,6 +128,8 @@ const CurrentDeviceSection: React.FC<Props> = ({
                             onSignOutDevice={onSignOutCurrentDevice}
                             saveDeviceName={saveDeviceName}
                             className="mx_CurrentDeviceSection_deviceDetails"
+                            delegatedAuthAccountUrl={delegatedAuthAccountUrl}
+                            isCurrentDevice
                         />
                     ) : (
                         <>
diff --git a/src/components/views/settings/devices/DeviceDetailHeading.tsx b/src/components/views/settings/devices/DeviceDetailHeading.tsx
index 86c9b929cf9..945f5f204af 100644
--- a/src/components/views/settings/devices/DeviceDetailHeading.tsx
+++ b/src/components/views/settings/devices/DeviceDetailHeading.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/devices/DeviceDetails.tsx b/src/components/views/settings/devices/DeviceDetails.tsx
index 1a418f5dd52..a97a1b1bfe8 100644
--- a/src/components/views/settings/devices/DeviceDetails.tsx
+++ b/src/components/views/settings/devices/DeviceDetails.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -18,6 +18,7 @@ import ToggleSwitch from "../../elements/ToggleSwitch";
 import { DeviceDetailHeading } from "./DeviceDetailHeading";
 import { DeviceVerificationStatusCard } from "./DeviceVerificationStatusCard";
 import { ExtendedDevice } from "./types";
+import { getManageDeviceUrl } from "../../../../utils/oidc/urls.ts";
 
 interface Props {
     device: ExtendedDevice;
@@ -31,6 +32,7 @@ interface Props {
     supportsMSC3881?: boolean;
     className?: string;
     isCurrentDevice?: boolean;
+    delegatedAuthAccountUrl?: string;
 }
 
 interface MetadataTable {
@@ -39,6 +41,22 @@ interface MetadataTable {
     values: { label: string; value?: string | React.ReactNode }[];
 }
 
+function isPushNotificationsEnabled(pusher?: IPusher, notificationSettings?: LocalNotificationSettings): boolean {
+    if (pusher) return !!pusher[PUSHER_ENABLED.name];
+    if (notificationSettings) return !notificationSettings.is_silenced;
+    return true;
+}
+
+function isCheckboxDisabled(
+    pusher?: IPusher,
+    notificationSettings?: LocalNotificationSettings,
+    supportsMSC3881?: boolean,
+): boolean {
+    if (notificationSettings) return false;
+    if (pusher && !supportsMSC3881) return true;
+    return false;
+}
+
 const DeviceDetails: React.FC<Props> = ({
     device,
     pusher,
@@ -51,6 +69,7 @@ const DeviceDetails: React.FC<Props> = ({
     supportsMSC3881,
     className,
     isCurrentDevice,
+    delegatedAuthAccountUrl,
 }) => {
     const metadata: MetadataTable[] = [
         {
@@ -95,18 +114,6 @@ const DeviceDetails: React.FC<Props> = ({
 
     const showPushNotificationSection = !!pusher || !!localNotificationSettings;
 
-    function isPushNotificationsEnabled(pusher?: IPusher, notificationSettings?: LocalNotificationSettings): boolean {
-        if (pusher) return !!pusher[PUSHER_ENABLED.name];
-        if (localNotificationSettings) return !localNotificationSettings.is_silenced;
-        return true;
-    }
-
-    function isCheckboxDisabled(pusher?: IPusher, notificationSettings?: LocalNotificationSettings): boolean {
-        if (localNotificationSettings) return false;
-        if (pusher && !supportsMSC3881) return true;
-        return false;
-    }
-
     return (
         <div className={classNames("mx_DeviceDetails", className)} data-testid={`device-detail-${device.device_id}`}>
             <section className="mx_DeviceDetails_section">
@@ -117,32 +124,34 @@ const DeviceDetails: React.FC<Props> = ({
                     isCurrentDevice={isCurrentDevice}
                 />
             </section>
-            <section className="mx_DeviceDetails_section">
-                <p className="mx_DeviceDetails_sectionHeading">{_t("settings|sessions|details_heading")}</p>
-                {metadata.map(({ heading, values, id }, index) => (
-                    <table
-                        className="mx_DeviceDetails_metadataTable"
-                        key={index}
-                        data-testid={`device-detail-metadata-${id}`}
-                    >
-                        {heading && (
-                            <thead>
-                                <tr>
-                                    <th>{heading}</th>
-                                </tr>
-                            </thead>
-                        )}
-                        <tbody>
-                            {values.map(({ label, value }) => (
-                                <tr key={label}>
-                                    <td className="mxDeviceDetails_metadataLabel">{label}</td>
-                                    <td className="mxDeviceDetails_metadataValue">{value}</td>
-                                </tr>
-                            ))}
-                        </tbody>
-                    </table>
-                ))}
-            </section>
+            {!delegatedAuthAccountUrl && (
+                <section className="mx_DeviceDetails_section">
+                    <p className="mx_DeviceDetails_sectionHeading">{_t("settings|sessions|details_heading")}</p>
+                    {metadata.map(({ heading, values, id }, index) => (
+                        <table
+                            className="mx_DeviceDetails_metadataTable"
+                            key={index}
+                            data-testid={`device-detail-metadata-${id}`}
+                        >
+                            {heading && (
+                                <thead>
+                                    <tr>
+                                        <th>{heading}</th>
+                                    </tr>
+                                </thead>
+                            )}
+                            <tbody>
+                                {values.map(({ label, value }) => (
+                                    <tr key={label}>
+                                        <td className="mxDeviceDetails_metadataLabel">{label}</td>
+                                        <td className="mxDeviceDetails_metadataValue">{value}</td>
+                                    </tr>
+                                ))}
+                            </tbody>
+                        </table>
+                    ))}
+                </section>
+            )}
             {showPushNotificationSection && (
                 <section
                     className="mx_DeviceDetails_section mx_DeviceDetails_pushNotifications"
@@ -152,7 +161,7 @@ const DeviceDetails: React.FC<Props> = ({
                         // For backwards compatibility, if `enabled` is missing
                         // default to `true`
                         checked={isPushNotificationsEnabled(pusher, localNotificationSettings)}
-                        disabled={isCheckboxDisabled(pusher, localNotificationSettings)}
+                        disabled={isCheckboxDisabled(pusher, localNotificationSettings, supportsMSC3881)}
                         onChange={(checked) => setPushNotifications?.(device.device_id, checked)}
                         title={_t("settings|sessions|push_toggle")}
                         data-testid="device-detail-push-notification-checkbox"
@@ -166,17 +175,30 @@ const DeviceDetails: React.FC<Props> = ({
                 </section>
             )}
             <section className="mx_DeviceDetails_section">
-                <AccessibleButton
-                    onClick={onSignOutDevice}
-                    kind="danger_inline"
-                    disabled={isSigningOut}
-                    data-testid="device-detail-sign-out-cta"
-                >
-                    <span className="mx_DeviceDetails_signOutButtonContent">
-                        {_t("settings|sessions|sign_out")}
-                        {isSigningOut && <Spinner w={16} h={16} />}
-                    </span>
-                </AccessibleButton>
+                {delegatedAuthAccountUrl && !isCurrentDevice ? (
+                    <AccessibleButton
+                        element="a"
+                        onClick={null}
+                        kind="link_inline"
+                        href={getManageDeviceUrl(delegatedAuthAccountUrl, device.device_id)}
+                        target="_blank"
+                        data-testid="device-detail-sign-out-cta"
+                    >
+                        <span className="mx_DeviceDetails_signOutButtonContent">{_t("settings|sessions|manage")}</span>
+                    </AccessibleButton>
+                ) : (
+                    <AccessibleButton
+                        onClick={onSignOutDevice}
+                        kind="danger_inline"
+                        disabled={isSigningOut}
+                        data-testid="device-detail-sign-out-cta"
+                    >
+                        <span className="mx_DeviceDetails_signOutButtonContent">
+                            {_t("settings|sessions|sign_out")}
+                            {isSigningOut && <Spinner w={16} h={16} />}
+                        </span>
+                    </AccessibleButton>
+                )}
             </section>
         </div>
     );
diff --git a/src/components/views/settings/devices/DeviceExpandDetailsButton.tsx b/src/components/views/settings/devices/DeviceExpandDetailsButton.tsx
index a04430a0c23..b227ea38143 100644
--- a/src/components/views/settings/devices/DeviceExpandDetailsButton.tsx
+++ b/src/components/views/settings/devices/DeviceExpandDetailsButton.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/devices/DeviceMetaData.tsx b/src/components/views/settings/devices/DeviceMetaData.tsx
index 08d22968f0f..be7bd119963 100644
--- a/src/components/views/settings/devices/DeviceMetaData.tsx
+++ b/src/components/views/settings/devices/DeviceMetaData.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/devices/DeviceSecurityCard.tsx b/src/components/views/settings/devices/DeviceSecurityCard.tsx
index 1f47135b00a..2de343d51be 100644
--- a/src/components/views/settings/devices/DeviceSecurityCard.tsx
+++ b/src/components/views/settings/devices/DeviceSecurityCard.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/devices/DeviceSecurityLearnMore.tsx b/src/components/views/settings/devices/DeviceSecurityLearnMore.tsx
index bc2e0be43e2..6a2ca55d430 100644
--- a/src/components/views/settings/devices/DeviceSecurityLearnMore.tsx
+++ b/src/components/views/settings/devices/DeviceSecurityLearnMore.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/devices/DeviceTile.tsx b/src/components/views/settings/devices/DeviceTile.tsx
index 6463af48ce1..79d0c720df3 100644
--- a/src/components/views/settings/devices/DeviceTile.tsx
+++ b/src/components/views/settings/devices/DeviceTile.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022, 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/devices/DeviceTypeIcon.tsx b/src/components/views/settings/devices/DeviceTypeIcon.tsx
index b9ab535e27d..c685c4c8956 100644
--- a/src/components/views/settings/devices/DeviceTypeIcon.tsx
+++ b/src/components/views/settings/devices/DeviceTypeIcon.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/devices/DeviceVerificationStatusCard.tsx b/src/components/views/settings/devices/DeviceVerificationStatusCard.tsx
index 8989400e711..d57231076b3 100644
--- a/src/components/views/settings/devices/DeviceVerificationStatusCard.tsx
+++ b/src/components/views/settings/devices/DeviceVerificationStatusCard.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/devices/FilteredDeviceList.tsx b/src/components/views/settings/devices/FilteredDeviceList.tsx
index e5f1a6a9a3b..bf37b095486 100644
--- a/src/components/views/settings/devices/FilteredDeviceList.tsx
+++ b/src/components/views/settings/devices/FilteredDeviceList.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -41,10 +41,12 @@ interface Props {
     setSelectedDeviceIds: (deviceIds: ExtendedDevice["device_id"][]) => void;
     supportsMSC3881?: boolean | undefined;
     /**
-     * Only allow sessions to be signed out individually
+     * If the user's account is managed externally then sessions must be signed out individually
      * Removes checkboxes and multi selection header
+     * Removes session info as that can be seen in the account management
+     * Changes sign out button to be a manage button
      */
-    disableMultipleSignout?: boolean;
+    delegatedAuthAccountUrl?: string;
 }
 
 const isDeviceSelected = (
@@ -172,6 +174,7 @@ const DeviceListItem: React.FC<{
     setPushNotifications: (deviceId: string, enabled: boolean) => Promise<void>;
     supportsMSC3881?: boolean | undefined;
     isSelectDisabled?: boolean;
+    delegatedAuthAccountUrl?: string;
 }> = ({
     device,
     pusher,
@@ -187,6 +190,7 @@ const DeviceListItem: React.FC<{
     toggleSelected,
     supportsMSC3881,
     isSelectDisabled,
+    delegatedAuthAccountUrl,
 }) => {
     const tileContent = (
         <>
@@ -222,6 +226,7 @@ const DeviceListItem: React.FC<{
                     setPushNotifications={setPushNotifications}
                     supportsMSC3881={supportsMSC3881}
                     className="mx_FilteredDeviceList_deviceDetails"
+                    delegatedAuthAccountUrl={delegatedAuthAccountUrl}
                 />
             )}
         </li>
@@ -250,7 +255,7 @@ export const FilteredDeviceList = forwardRef(
             setPushNotifications,
             setSelectedDeviceIds,
             supportsMSC3881,
-            disableMultipleSignout,
+            delegatedAuthAccountUrl,
         }: Props,
         ref: ForwardedRef<HTMLDivElement>,
     ) => {
@@ -311,7 +316,7 @@ export const FilteredDeviceList = forwardRef(
                     selectedDeviceCount={selectedDeviceIds.length}
                     isAllSelected={isAllSelected}
                     toggleSelectAll={toggleSelectAll}
-                    isSelectDisabled={disableMultipleSignout}
+                    isSelectDisabled={!!delegatedAuthAccountUrl}
                 >
                     {selectedDeviceIds.length ? (
                         <>
@@ -361,7 +366,7 @@ export const FilteredDeviceList = forwardRef(
                             isExpanded={expandedDeviceIds.includes(device.device_id)}
                             isSigningOut={signingOutDeviceIds.includes(device.device_id)}
                             isSelected={isDeviceSelected(device.device_id, selectedDeviceIds)}
-                            isSelectDisabled={disableMultipleSignout}
+                            isSelectDisabled={!!delegatedAuthAccountUrl}
                             onDeviceExpandToggle={() => onDeviceExpandToggle(device.device_id)}
                             onSignOutDevice={() => onSignOutDevices([device.device_id])}
                             saveDeviceName={(deviceName: string) => saveDeviceName(device.device_id, deviceName)}
@@ -373,6 +378,7 @@ export const FilteredDeviceList = forwardRef(
                             setPushNotifications={setPushNotifications}
                             toggleSelected={() => toggleSelection(device.device_id)}
                             supportsMSC3881={supportsMSC3881}
+                            delegatedAuthAccountUrl={delegatedAuthAccountUrl}
                         />
                     ))}
                 </ol>
diff --git a/src/components/views/settings/devices/FilteredDeviceListHeader.tsx b/src/components/views/settings/devices/FilteredDeviceListHeader.tsx
index 9cd5a285d5a..28fcec67158 100644
--- a/src/components/views/settings/devices/FilteredDeviceListHeader.tsx
+++ b/src/components/views/settings/devices/FilteredDeviceListHeader.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/devices/LoginWithQRSection.tsx b/src/components/views/settings/devices/LoginWithQRSection.tsx
index 033aa8e32ab..4043d28c805 100644
--- a/src/components/views/settings/devices/LoginWithQRSection.tsx
+++ b/src/components/views/settings/devices/LoginWithQRSection.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/devices/OtherSessionsSectionHeading.tsx b/src/components/views/settings/devices/OtherSessionsSectionHeading.tsx
index b5ba0cb4c47..4615c39daf2 100644
--- a/src/components/views/settings/devices/OtherSessionsSectionHeading.tsx
+++ b/src/components/views/settings/devices/OtherSessionsSectionHeading.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/devices/SecurityRecommendations.tsx b/src/components/views/settings/devices/SecurityRecommendations.tsx
index c0fc8e26b80..599c3bd5b3e 100644
--- a/src/components/views/settings/devices/SecurityRecommendations.tsx
+++ b/src/components/views/settings/devices/SecurityRecommendations.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/devices/SelectableDeviceTile.tsx b/src/components/views/settings/devices/SelectableDeviceTile.tsx
index 4c8747a634d..b83b2c58705 100644
--- a/src/components/views/settings/devices/SelectableDeviceTile.tsx
+++ b/src/components/views/settings/devices/SelectableDeviceTile.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/devices/deleteDevices.tsx b/src/components/views/settings/devices/deleteDevices.tsx
index 4b8bc19d763..16fdca9219c 100644
--- a/src/components/views/settings/devices/deleteDevices.tsx
+++ b/src/components/views/settings/devices/deleteDevices.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/devices/filter.ts b/src/components/views/settings/devices/filter.ts
index 0b252e7cde0..ba7f6f5c216 100644
--- a/src/components/views/settings/devices/filter.ts
+++ b/src/components/views/settings/devices/filter.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/devices/types.ts b/src/components/views/settings/devices/types.ts
index e46e43ab039..3891f6be32b 100644
--- a/src/components/views/settings/devices/types.ts
+++ b/src/components/views/settings/devices/types.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/devices/useOwnDevices.ts b/src/components/views/settings/devices/useOwnDevices.ts
index 51a05f6242d..8cb3f9dbc18 100644
--- a/src/components/views/settings/devices/useOwnDevices.ts
+++ b/src/components/views/settings/devices/useOwnDevices.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -116,7 +116,7 @@ export const useOwnDevices = (): DevicesState => {
 
             const notificationSettings = new Map<string, LocalNotificationSettings>();
             Object.keys(devices).forEach((deviceId) => {
-                const eventType = `${LOCAL_NOTIFICATION_SETTINGS_PREFIX.name}.${deviceId}`;
+                const eventType = `${LOCAL_NOTIFICATION_SETTINGS_PREFIX.name}.${deviceId}` as const;
                 const event = matrixClient.getAccountData(eventType);
                 if (event) {
                     notificationSettings.set(deviceId, event.getContent());
diff --git a/src/components/views/settings/discovery/DiscoverySettings.tsx b/src/components/views/settings/discovery/DiscoverySettings.tsx
index f96b79fe8dc..28913f289d1 100644
--- a/src/components/views/settings/discovery/DiscoverySettings.tsx
+++ b/src/components/views/settings/discovery/DiscoverySettings.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/encryption/ChangeRecoveryKey.tsx b/src/components/views/settings/encryption/ChangeRecoveryKey.tsx
new file mode 100644
index 00000000000..7e02d7debde
--- /dev/null
+++ b/src/components/views/settings/encryption/ChangeRecoveryKey.tsx
@@ -0,0 +1,352 @@
+/*
+ * Copyright 2024 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+import React, { FormEventHandler, JSX, MouseEventHandler, useState } from "react";
+import {
+    Breadcrumb,
+    Button,
+    ErrorMessage,
+    Field,
+    IconButton,
+    Label,
+    Root,
+    Text,
+    TextControl,
+} from "@vector-im/compound-web";
+import CopyIcon from "@vector-im/compound-design-tokens/assets/web/icons/copy";
+import { logger } from "matrix-js-sdk/src/logger";
+
+import { _t } from "../../../../languageHandler";
+import { EncryptionCard } from "./EncryptionCard";
+import { useMatrixClientContext } from "../../../../contexts/MatrixClientContext";
+import { useAsyncMemo } from "../../../../hooks/useAsyncMemo";
+import { copyPlaintext } from "../../../../utils/strings";
+import { withSecretStorageKeyCache } from "../../../../SecurityManager";
+
+/**
+ * The possible states of the component.
+ * - `inform_user`: The user is informed about the recovery key.
+ * - `save_key_setup_flow`: The user is asked to save the new recovery key during the setup flow.
+ * - `save_key_change_flow`: The user is asked to save the new recovery key during the change key flow.
+ * - `confirm_key_setup_flow`: The user is asked to confirm the new recovery key during the set up flow.
+ * - `confirm_key_change_flow`: The user is asked to confirm the new recovery key during the change key flow.
+ */
+type State =
+    | "inform_user"
+    | "save_key_setup_flow"
+    | "save_key_change_flow"
+    | "confirm_key_setup_flow"
+    | "confirm_key_change_flow";
+
+interface ChangeRecoveryKeyProps {
+    /**
+     * If true, the component will display the flow to change the recovery key.
+     * If false,the component will display the flow to set up a new recovery key.
+     */
+    userHasRecoveryKey: boolean;
+    /**
+     * Called when the recovery key is successfully changed.
+     */
+    onFinish: () => void;
+    /**
+     * Called when the cancel button is clicked or when we go back in the breadcrumbs.
+     */
+    onCancelClick: () => void;
+}
+
+/**
+ * A component to set up or change the recovery key.
+ */
+export function ChangeRecoveryKey({
+    userHasRecoveryKey,
+    onFinish,
+    onCancelClick,
+}: ChangeRecoveryKeyProps): JSX.Element | null {
+    const matrixClient = useMatrixClientContext();
+
+    // If the user is setting up recovery for the first time, we first show them a panel explaining what
+    // "recovery" is about. Otherwise, we jump straight to showing the user the new key.
+    const [state, setState] = useState<State>(userHasRecoveryKey ? "save_key_change_flow" : "inform_user");
+
+    // We create a new recovery key, the recovery key will be displayed to the user
+    const recoveryKey = useAsyncMemo(() => matrixClient.getCrypto()!.createRecoveryKeyFromPassphrase(), []);
+    // Waiting for the recovery key to be generated
+    if (!recoveryKey) return null;
+
+    let content: JSX.Element;
+    switch (state) {
+        case "inform_user":
+            // Show a panel explaining what "recovery" is for, and what a recovery key does.
+            content = (
+                <InformationPanel
+                    onContinueClick={() => setState("save_key_setup_flow")}
+                    onCancelClick={onCancelClick}
+                />
+            );
+            break;
+        case "save_key_setup_flow":
+        case "save_key_change_flow":
+            // Show a generated recovery key and ask the user to save it.
+            content = (
+                <KeyPanel
+                    // encodedPrivateKey is always defined, the optional typing is incorrect
+                    recoveryKey={recoveryKey.encodedPrivateKey!}
+                    onConfirmClick={() =>
+                        setState((currentState) =>
+                            currentState === "save_key_change_flow"
+                                ? "confirm_key_change_flow"
+                                : "confirm_key_setup_flow",
+                        )
+                    }
+                    onCancelClick={onCancelClick}
+                />
+            );
+            break;
+        case "confirm_key_setup_flow":
+        case "confirm_key_change_flow":
+            // Ask the user to enter the recovery key they just saved to confirm it.
+            content = (
+                <KeyForm
+                    // encodedPrivateKey is always defined, the optional typing is incorrect
+                    recoveryKey={recoveryKey.encodedPrivateKey!}
+                    onCancelClick={onCancelClick}
+                    onSubmit={async () => {
+                        const crypto = matrixClient.getCrypto();
+                        if (!crypto) return onFinish();
+
+                        try {
+                            // We need to enable the cache to avoid to prompt the user to enter the new key
+                            // when we will try to access the secret storage during the bootstrap
+                            await withSecretStorageKeyCache(() =>
+                                crypto.bootstrapSecretStorage({
+                                    setupNewSecretStorage: true,
+                                    createSecretStorageKey: async () => recoveryKey,
+                                }),
+                            );
+                            onFinish();
+                        } catch (e) {
+                            logger.error("Failed to bootstrap secret storage", e);
+                        }
+                    }}
+                    submitButtonLabel={
+                        state === "confirm_key_setup_flow"
+                            ? _t("settings|encryption|recovery|set_up_recovery_confirm_button")
+                            : _t("settings|encryption|recovery|change_recovery_confirm_button")
+                    }
+                />
+            );
+    }
+
+    const pages = [
+        _t("settings|encryption|title"),
+        userHasRecoveryKey
+            ? _t("settings|encryption|recovery|change_recovery_key")
+            : _t("settings|encryption|recovery|set_up_recovery"),
+    ];
+    const labels = getLabels(state);
+
+    return (
+        <>
+            <Breadcrumb
+                backLabel={_t("action|back")}
+                onBackClick={onCancelClick}
+                pages={pages}
+                onPageClick={onCancelClick}
+            />
+            <EncryptionCard title={labels.title} description={labels.description} className="mx_ChangeRecoveryKey">
+                {content}
+            </EncryptionCard>
+        </>
+    );
+}
+
+type Labels = {
+    /**
+     * The title of the card.
+     */
+    title: string;
+    /**
+     * The description of the card.
+     */
+    description: string;
+};
+
+/**
+ * Get the header title and description for the given state.
+ * @param state
+ */
+function getLabels(state: State): Labels {
+    switch (state) {
+        case "inform_user":
+            return {
+                title: _t("settings|encryption|recovery|set_up_recovery"),
+                description: _t("settings|encryption|recovery|set_up_recovery_description", {
+                    changeRecoveryKeyButton: _t("settings|encryption|recovery|change_recovery_key"),
+                }),
+            };
+        case "save_key_setup_flow":
+            return {
+                title: _t("settings|encryption|recovery|set_up_recovery_save_key_title"),
+                description: _t("settings|encryption|recovery|set_up_recovery_save_key_description"),
+            };
+        case "save_key_change_flow":
+            return {
+                title: _t("settings|encryption|recovery|change_recovery_key_title"),
+                description: _t("settings|encryption|recovery|change_recovery_key_description"),
+            };
+        case "confirm_key_setup_flow":
+            return {
+                title: _t("settings|encryption|recovery|set_up_recovery_confirm_title"),
+                description: _t("settings|encryption|recovery|set_up_recovery_confirm_description"),
+            };
+        case "confirm_key_change_flow":
+            return {
+                title: _t("settings|encryption|recovery|change_recovery_confirm_title"),
+                description: _t("settings|encryption|recovery|change_recovery_confirm_description"),
+            };
+    }
+}
+
+interface InformationPanelProps {
+    /**
+     * Called when the continue button is clicked.
+     */
+    onContinueClick: MouseEventHandler<HTMLButtonElement>;
+    /**
+     * Called when the cancel button is clicked.
+     */
+    onCancelClick: MouseEventHandler<HTMLButtonElement>;
+}
+
+/**
+ * The panel to display information about the recovery key.
+ */
+function InformationPanel({ onContinueClick, onCancelClick }: InformationPanelProps): JSX.Element {
+    return (
+        <>
+            <Text as="span" weight="medium" className="mx_InformationPanel_description">
+                {_t("settings|encryption|recovery|set_up_recovery_secondary_description")}
+            </Text>
+            <div className="mx_ChangeRecoveryKey_footer">
+                <Button onClick={onContinueClick}>{_t("action|continue")}</Button>
+                <Button kind="tertiary" onClick={onCancelClick}>
+                    {_t("action|cancel")}
+                </Button>
+            </div>
+        </>
+    );
+}
+
+interface KeyPanelProps {
+    /**
+     * Called when the confirm button is clicked.
+     */
+    onConfirmClick: MouseEventHandler;
+    /**
+     * Called when the cancel button is clicked.
+     */
+    onCancelClick: MouseEventHandler;
+    /**
+     * The recovery key to display.
+     */
+    recoveryKey: string;
+}
+
+/**
+ * The panel to display the recovery key.
+ */
+function KeyPanel({ recoveryKey, onConfirmClick, onCancelClick }: KeyPanelProps): JSX.Element {
+    return (
+        <>
+            <div className="mx_KeyPanel">
+                <Text as="span" weight="medium">
+                    {_t("settings|encryption|recovery|save_key_title")}
+                </Text>
+                <div>
+                    <Text as="span" className="mx_KeyPanel_key" data-testid="recoveryKey">
+                        {recoveryKey}
+                    </Text>
+                    <Text as="span" size="sm">
+                        {_t("settings|encryption|recovery|save_key_description")}
+                    </Text>
+                </div>
+                <IconButton aria-label={_t("action|copy")} size="28px" onClick={() => copyPlaintext(recoveryKey)}>
+                    <CopyIcon />
+                </IconButton>
+            </div>
+            <div className="mx_ChangeRecoveryKey_footer">
+                <Button onClick={onConfirmClick}>{_t("action|continue")}</Button>
+                <Button kind="tertiary" onClick={onCancelClick}>
+                    {_t("action|cancel")}
+                </Button>
+            </div>
+        </>
+    );
+}
+
+interface KeyFormProps {
+    /**
+     * Called when the cancel button is clicked.
+     */
+    onCancelClick: MouseEventHandler;
+    /**
+     * Called when the form is submitted.
+     */
+    onSubmit: FormEventHandler;
+    /**
+     * The recovery key to confirm.
+     */
+    recoveryKey: string;
+    /**
+     * The label for the submit button.
+     */
+    submitButtonLabel: string;
+}
+
+/**
+ * The form to confirm the recovery key.
+ * The finish button is disabled until the key is filled and valid.
+ * The entered key is valid if it matches the recovery key.
+ */
+function KeyForm({ onCancelClick, onSubmit, recoveryKey, submitButtonLabel }: KeyFormProps): JSX.Element {
+    // Undefined by default, as the key is not filled yet
+    const [isKeyValid, setIsKeyValid] = useState<boolean>();
+    const isKeyInvalidAndFilled = isKeyValid === false;
+
+    return (
+        <Root
+            className="mx_KeyForm"
+            onSubmit={(evt) => {
+                evt.preventDefault();
+                onSubmit(evt);
+            }}
+            onChange={async (evt) => {
+                evt.preventDefault();
+                evt.stopPropagation();
+
+                // We don't have any file in the form, we can cast it as string safely
+                const filledKey = new FormData(evt.currentTarget).get("recoveryKey") as string | "";
+                setIsKeyValid(filledKey.trim() === recoveryKey);
+            }}
+        >
+            <Field name="recoveryKey" serverInvalid={isKeyInvalidAndFilled}>
+                <Label>{_t("settings|encryption|recovery|enter_recovery_key")}</Label>
+
+                <TextControl required={true} />
+                {isKeyInvalidAndFilled && (
+                    <ErrorMessage>{_t("settings|encryption|recovery|enter_key_error")}</ErrorMessage>
+                )}
+            </Field>
+            <div className="mx_ChangeRecoveryKey_footer">
+                <Button disabled={!isKeyValid}>{submitButtonLabel}</Button>
+                <Button kind="tertiary" onClick={onCancelClick}>
+                    {_t("action|cancel")}
+                </Button>
+            </div>
+        </Root>
+    );
+}
diff --git a/src/components/views/settings/encryption/EncryptionCard.tsx b/src/components/views/settings/encryption/EncryptionCard.tsx
new file mode 100644
index 00000000000..8a10802cc3e
--- /dev/null
+++ b/src/components/views/settings/encryption/EncryptionCard.tsx
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2024 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+import React, { JSX, PropsWithChildren } from "react";
+import { BigIcon, Heading } from "@vector-im/compound-web";
+import KeyIcon from "@vector-im/compound-design-tokens/assets/web/icons/key-solid";
+import classNames from "classnames";
+
+interface EncryptionCardProps {
+    /**
+     * CSS class name to apply to the card.
+     */
+    className?: string;
+    /**
+     * The title of the card.
+     */
+    title: string;
+    /**
+     * The description of the card.
+     */
+    description: string;
+}
+
+/**
+ * A styled card for encryption settings.
+ */
+export function EncryptionCard({
+    title,
+    description,
+    className,
+    children,
+}: PropsWithChildren<EncryptionCardProps>): JSX.Element {
+    return (
+        <div className={classNames("mx_EncryptionCard", className)}>
+            <div className="mx_EncryptionCard_header">
+                <BigIcon>
+                    <KeyIcon />
+                </BigIcon>
+                <Heading as="h2" size="sm" weight="semibold">
+                    {title}
+                </Heading>
+                <span>{description}</span>
+            </div>
+            {children}
+        </div>
+    );
+}
diff --git a/src/components/views/settings/encryption/RecoveryPanel.tsx b/src/components/views/settings/encryption/RecoveryPanel.tsx
new file mode 100644
index 00000000000..19d81668eb8
--- /dev/null
+++ b/src/components/views/settings/encryption/RecoveryPanel.tsx
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2024 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+import React, { JSX, useCallback, useEffect, useState } from "react";
+import { Button, InlineSpinner } from "@vector-im/compound-web";
+import KeyIcon from "@vector-im/compound-design-tokens/assets/web/icons/key";
+
+import { SettingsSection } from "../shared/SettingsSection";
+import { _t } from "../../../../languageHandler";
+import { useMatrixClientContext } from "../../../../contexts/MatrixClientContext";
+import { SettingsHeader } from "../SettingsHeader";
+import { accessSecretStorage } from "../../../../SecurityManager";
+import { SettingsSubheader } from "../SettingsSubheader";
+
+/**
+ * The possible states of the recovery panel.
+ * - `loading`: We are checking the recovery key and the secrets.
+ * - `missing_recovery_key`: The user has no recovery key.
+ * - `secrets_not_cached`: The user has a recovery key but the secrets are not cached.
+ *                         This can happen if we verified another device and secret-gossiping failed, or the other device itself lacked the secrets.
+ * - `good`: The user has a recovery key and the secrets are cached.
+ */
+type State = "loading" | "missing_recovery_key" | "secrets_not_cached" | "good";
+
+interface RecoveryPanelProps {
+    /**
+     * Callback for when the user wants to set up or change their recovery key.
+     *
+     * @param setupNewKey - set if the user does not already have a recovery key (and has therefore clicked on
+     *                      "Set up recovery" rather than "Change recovery key").
+     */
+    onChangeRecoveryKeyClick: (setupNewKey: boolean) => void;
+}
+
+/**
+ * This component allows the user to set up or change their recovery key.
+ */
+export function RecoveryPanel({ onChangeRecoveryKeyClick }: RecoveryPanelProps): JSX.Element {
+    const [state, setState] = useState<State>("loading");
+    const isMissingRecoveryKey = state === "missing_recovery_key";
+
+    const matrixClient = useMatrixClientContext();
+
+    const checkEncryption = useCallback(async () => {
+        const crypto = matrixClient.getCrypto()!;
+
+        // Check if the user has a recovery key
+        const hasRecoveryKey = Boolean(await matrixClient.secretStorage.getDefaultKeyId());
+        if (!hasRecoveryKey) return setState("missing_recovery_key");
+
+        // Check if the secrets are cached
+        const cachedSecrets = (await crypto.getCrossSigningStatus()).privateKeysCachedLocally;
+        const secretsOk = cachedSecrets.masterKey && cachedSecrets.selfSigningKey && cachedSecrets.userSigningKey;
+        if (!secretsOk) return setState("secrets_not_cached");
+
+        setState("good");
+    }, [matrixClient]);
+
+    useEffect(() => {
+        checkEncryption();
+    }, [checkEncryption]);
+
+    let content: JSX.Element;
+    switch (state) {
+        case "loading":
+            content = <InlineSpinner aria-label={_t("common|loading")} />;
+            break;
+        case "missing_recovery_key":
+            content = (
+                <Button size="sm" kind="primary" Icon={KeyIcon} onClick={() => onChangeRecoveryKeyClick(true)}>
+                    {_t("settings|encryption|recovery|set_up_recovery")}
+                </Button>
+            );
+            break;
+        case "secrets_not_cached":
+            content = (
+                <Button
+                    size="sm"
+                    kind="primary"
+                    Icon={KeyIcon}
+                    onClick={async () => await accessSecretStorage(checkEncryption)}
+                >
+                    {_t("settings|encryption|recovery|enter_recovery_key")}
+                </Button>
+            );
+            break;
+        case "good":
+            content = (
+                <Button size="sm" kind="secondary" Icon={KeyIcon} onClick={() => onChangeRecoveryKeyClick(false)}>
+                    {_t("settings|encryption|recovery|change_recovery_key")}
+                </Button>
+            );
+    }
+
+    return (
+        <SettingsSection
+            legacy={false}
+            heading={
+                <SettingsHeader
+                    hasRecommendedTag={isMissingRecoveryKey}
+                    label={_t("settings|encryption|recovery|title")}
+                />
+            }
+            subHeading={<Subheader state={state} />}
+        >
+            {content}
+        </SettingsSection>
+    );
+}
+
+interface SubheaderProps {
+    /**
+     * The state of the recovery panel.
+     */
+    state: State;
+}
+
+/**
+ * The subheader for the recovery panel.
+ */
+function Subheader({ state }: SubheaderProps): JSX.Element {
+    // If the secrets are not cached, we display a warning message.
+    if (state !== "secrets_not_cached") return <>{_t("settings|encryption|recovery|description")}</>;
+
+    return (
+        <SettingsSubheader
+            label={_t("settings|encryption|recovery|description")}
+            state="error"
+            stateMessage={_t("settings|encryption|recovery|key_storage_warning")}
+        />
+    );
+}
diff --git a/src/components/views/settings/notifications/NotificationPusherSettings.tsx b/src/components/views/settings/notifications/NotificationPusherSettings.tsx
index 9e17e7b829d..d5506f7b957 100644
--- a/src/components/views/settings/notifications/NotificationPusherSettings.tsx
+++ b/src/components/views/settings/notifications/NotificationPusherSettings.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/notifications/NotificationSettings2.tsx b/src/components/views/settings/notifications/NotificationSettings2.tsx
index 5f91c3874c7..babc4c8bd56 100644
--- a/src/components/views/settings/notifications/NotificationSettings2.tsx
+++ b/src/components/views/settings/notifications/NotificationSettings2.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -70,9 +70,9 @@ function useHasUnreadNotifications(): boolean {
 export default function NotificationSettings2(): JSX.Element {
     const cli = useMatrixClientContext();
 
-    const desktopNotifications = useSettingValue<boolean>("notificationsEnabled");
-    const desktopShowBody = useSettingValue<boolean>("notificationBodyEnabled");
-    const audioNotifications = useSettingValue<boolean>("audioNotificationsEnabled");
+    const desktopNotifications = useSettingValue("notificationsEnabled");
+    const desktopShowBody = useSettingValue("notificationBodyEnabled");
+    const audioNotifications = useSettingValue("audioNotificationsEnabled");
 
     const { model, hasPendingChanges, reconcile } = useNotificationSettings(cli);
 
diff --git a/src/components/views/settings/shared/SettingsBanner.tsx b/src/components/views/settings/shared/SettingsBanner.tsx
index c35703bf16a..a5b0ac2a36a 100644
--- a/src/components/views/settings/shared/SettingsBanner.tsx
+++ b/src/components/views/settings/shared/SettingsBanner.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/shared/SettingsIndent.tsx b/src/components/views/settings/shared/SettingsIndent.tsx
index ee7e570d1a0..7c280311c26 100644
--- a/src/components/views/settings/shared/SettingsIndent.tsx
+++ b/src/components/views/settings/shared/SettingsIndent.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/shared/SettingsSection.tsx b/src/components/views/settings/shared/SettingsSection.tsx
index a42a2a9b788..4763c51e564 100644
--- a/src/components/views/settings/shared/SettingsSection.tsx
+++ b/src/components/views/settings/shared/SettingsSection.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022, 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -10,19 +10,24 @@ import classnames from "classnames";
 import React, { HTMLAttributes } from "react";
 
 import Heading from "../../typography/Heading";
+import { SettingsHeader } from "../SettingsHeader";
 
 export interface SettingsSectionProps extends HTMLAttributes<HTMLDivElement> {
     heading?: string | React.ReactNode;
+    subHeading?: string | React.ReactNode;
     children?: React.ReactNode;
+    legacy?: boolean;
 }
 
-function renderHeading(heading: string | React.ReactNode | undefined): React.ReactNode | undefined {
+function renderHeading(heading: string | React.ReactNode | undefined, legacy: boolean): React.ReactNode | undefined {
     switch (typeof heading) {
         case "string":
-            return (
+            return legacy ? (
                 <Heading as="h2" size="3">
                     {heading}
                 </Heading>
+            ) : (
+                <SettingsHeader label={heading} />
             );
         case "undefined":
             return undefined;
@@ -48,9 +53,29 @@ function renderHeading(heading: string | React.ReactNode | undefined): React.Rea
  * </SettingsTab>
  * ```
  */
-export const SettingsSection: React.FC<SettingsSectionProps> = ({ className, heading, children, ...rest }) => (
-    <div {...rest} className={classnames("mx_SettingsSection", className)}>
-        {renderHeading(heading)}
-        <div className="mx_SettingsSection_subSections">{children}</div>
+export const SettingsSection: React.FC<SettingsSectionProps> = ({
+    className,
+    heading,
+    subHeading,
+    legacy = true,
+    children,
+    ...rest
+}) => (
+    <div
+        {...rest}
+        className={classnames("mx_SettingsSection", className, {
+            mx_SettingsSection_newUi: !legacy,
+        })}
+    >
+        {heading &&
+            (subHeading ? (
+                <div className="mx_SettingsSection_header">
+                    {renderHeading(heading, legacy)}
+                    {subHeading}
+                </div>
+            ) : (
+                renderHeading(heading, legacy)
+            ))}
+        {legacy ? <div className="mx_SettingsSection_subSections">{children}</div> : children}
     </div>
 );
diff --git a/src/components/views/settings/shared/SettingsSubsection.tsx b/src/components/views/settings/shared/SettingsSubsection.tsx
index ba8d9aba6d4..cbb20f771b5 100644
--- a/src/components/views/settings/shared/SettingsSubsection.tsx
+++ b/src/components/views/settings/shared/SettingsSubsection.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/shared/SettingsSubsectionHeading.tsx b/src/components/views/settings/shared/SettingsSubsectionHeading.tsx
index 8c51eac0c27..61c29642a9c 100644
--- a/src/components/views/settings/shared/SettingsSubsectionHeading.tsx
+++ b/src/components/views/settings/shared/SettingsSubsectionHeading.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/tabs/SettingsTab.tsx b/src/components/views/settings/tabs/SettingsTab.tsx
index 7472da22e78..ed0b1367f6f 100644
--- a/src/components/views/settings/tabs/SettingsTab.tsx
+++ b/src/components/views/settings/tabs/SettingsTab.tsx
@@ -2,13 +2,18 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 import React, { HTMLAttributes } from "react";
+import classNames from "classnames";
 
-export interface SettingsTabProps extends Omit<HTMLAttributes<HTMLDivElement>, "className"> {
+export interface SettingsTabProps extends HTMLAttributes<HTMLDivElement> {
     children?: React.ReactNode;
+    /**
+     * Added to the classList of the root element
+     */
+    className?: string;
 }
 
 /**
@@ -29,8 +34,8 @@ export interface SettingsTabProps extends Omit<HTMLAttributes<HTMLDivElement>, "
  * </SettingsTab>
  * ```
  */
-const SettingsTab: React.FC<SettingsTabProps> = ({ children, ...rest }) => (
-    <div {...rest} className="mx_SettingsTab">
+const SettingsTab: React.FC<SettingsTabProps> = ({ children, className, ...rest }) => (
+    <div {...rest} className={classNames("mx_SettingsTab", className)}>
         <div className="mx_SettingsTab_sections">{children}</div>
     </div>
 );
diff --git a/src/components/views/settings/tabs/room/AdvancedRoomSettingsTab.tsx b/src/components/views/settings/tabs/room/AdvancedRoomSettingsTab.tsx
index 5798771e678..dbd2a635056 100644
--- a/src/components/views/settings/tabs/room/AdvancedRoomSettingsTab.tsx
+++ b/src/components/views/settings/tabs/room/AdvancedRoomSettingsTab.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/tabs/room/BridgeSettingsTab.tsx b/src/components/views/settings/tabs/room/BridgeSettingsTab.tsx
index 0da257607ee..ed80cc31e83 100644
--- a/src/components/views/settings/tabs/room/BridgeSettingsTab.tsx
+++ b/src/components/views/settings/tabs/room/BridgeSettingsTab.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/tabs/room/GeneralRoomSettingsTab.tsx b/src/components/views/settings/tabs/room/GeneralRoomSettingsTab.tsx
index 31c361de1bd..590b54218f7 100644
--- a/src/components/views/settings/tabs/room/GeneralRoomSettingsTab.tsx
+++ b/src/components/views/settings/tabs/room/GeneralRoomSettingsTab.tsx
@@ -1,7 +1,7 @@
 /*
 Copyright 2019-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/tabs/room/NotificationSettingsTab.tsx b/src/components/views/settings/tabs/room/NotificationSettingsTab.tsx
index 9aabf1edb0d..17e2498ae71 100644
--- a/src/components/views/settings/tabs/room/NotificationSettingsTab.tsx
+++ b/src/components/views/settings/tabs/room/NotificationSettingsTab.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/tabs/room/PeopleRoomSettingsTab.tsx b/src/components/views/settings/tabs/room/PeopleRoomSettingsTab.tsx
index 768d35890a2..b374f36de1b 100644
--- a/src/components/views/settings/tabs/room/PeopleRoomSettingsTab.tsx
+++ b/src/components/views/settings/tabs/room/PeopleRoomSettingsTab.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 Nordeck IT + Consulting GmbH
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/tabs/room/PollHistoryTab.tsx b/src/components/views/settings/tabs/room/PollHistoryTab.tsx
index 830da280aa5..a33e132e135 100644
--- a/src/components/views/settings/tabs/room/PollHistoryTab.tsx
+++ b/src/components/views/settings/tabs/room/PollHistoryTab.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/tabs/room/RolesRoomSettingsTab.tsx b/src/components/views/settings/tabs/room/RolesRoomSettingsTab.tsx
index baf4b412539..e2de5c3e698 100644
--- a/src/components/views/settings/tabs/room/RolesRoomSettingsTab.tsx
+++ b/src/components/views/settings/tabs/room/RolesRoomSettingsTab.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/tabs/room/SecurityRoomSettingsTab.tsx b/src/components/views/settings/tabs/room/SecurityRoomSettingsTab.tsx
index ece6a7deafc..f90dd9821d0 100644
--- a/src/components/views/settings/tabs/room/SecurityRoomSettingsTab.tsx
+++ b/src/components/views/settings/tabs/room/SecurityRoomSettingsTab.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/tabs/room/VoipRoomSettingsTab.tsx b/src/components/views/settings/tabs/room/VoipRoomSettingsTab.tsx
index 783ea1bce3b..2a8425823b0 100644
--- a/src/components/views/settings/tabs/room/VoipRoomSettingsTab.tsx
+++ b/src/components/views/settings/tabs/room/VoipRoomSettingsTab.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/tabs/user/AccountUserSettingsTab.tsx b/src/components/views/settings/tabs/user/AccountUserSettingsTab.tsx
index cd52b2a76b2..c94eef6d2c6 100644
--- a/src/components/views/settings/tabs/user/AccountUserSettingsTab.tsx
+++ b/src/components/views/settings/tabs/user/AccountUserSettingsTab.tsx
@@ -3,7 +3,7 @@ Copyright 2019-2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -186,7 +186,9 @@ const AccountUserSettingsTab: React.FC<IProps> = ({ closeSettingsFn }) => {
                     canSetDisplayName={canSetDisplayName}
                     canSetAvatar={canSetAvatar}
                 />
-                <UserPersonalInfoSettings canMake3pidChanges={canMake3pidChanges} />
+                {(!isAccountManagedExternally || canMake3pidChanges) && (
+                    <UserPersonalInfoSettings canMake3pidChanges={canMake3pidChanges} />
+                )}
                 <AccountSection
                     canChangePassword={canChangePassword}
                     onPasswordChanged={onPasswordChanged}
diff --git a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx
index f220803f723..4586191db14 100644
--- a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx
+++ b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019-2021 The Matrix.org Foundation C.I.C.
 Copyright 2019 New Vector Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/tabs/user/EncryptionUserSettingsTab.tsx b/src/components/views/settings/tabs/user/EncryptionUserSettingsTab.tsx
new file mode 100644
index 00000000000..d4304eb4d41
--- /dev/null
+++ b/src/components/views/settings/tabs/user/EncryptionUserSettingsTab.tsx
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2024 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+import React, { JSX, useCallback, useEffect, useState } from "react";
+import { Button, InlineSpinner } from "@vector-im/compound-web";
+import ComputerIcon from "@vector-im/compound-design-tokens/assets/web/icons/computer";
+
+import SettingsTab from "../SettingsTab";
+import { RecoveryPanel } from "../../encryption/RecoveryPanel";
+import { ChangeRecoveryKey } from "../../encryption/ChangeRecoveryKey";
+import { useMatrixClientContext } from "../../../../../contexts/MatrixClientContext";
+import { _t } from "../../../../../languageHandler";
+import Modal from "../../../../../Modal";
+import SetupEncryptionDialog from "../../../dialogs/security/SetupEncryptionDialog";
+import { SettingsSection } from "../../shared/SettingsSection";
+import { SettingsSubheader } from "../../SettingsSubheader";
+
+/**
+ * The state in the encryption settings tab.
+ *  - "loading": We are checking if the device is verified.
+ *  - "main": The main panel with all the sections (Key storage, recovery, advanced).
+ *  - "set_up_encryption": The panel to show when the user is setting up their encryption.
+ *                         This happens when the user doesn't have cross-signing enabled, or their current device is not verified.
+ *  - "change_recovery_key": The panel to show when the user is changing their recovery key.
+ *                           This happens when the user has a recovery key and the user clicks on "Change recovery key" button of the RecoveryPanel.
+ *  - "set_recovery_key": The panel to show when the user is setting up their recovery key.
+ *                        This happens when the user doesn't have a key a recovery key and the user clicks on "Set up recovery key" button of the RecoveryPanel.
+ */
+type State = "loading" | "main" | "set_up_encryption" | "change_recovery_key" | "set_recovery_key";
+
+export function EncryptionUserSettingsTab(): JSX.Element {
+    const [state, setState] = useState<State>("loading");
+    const setUpEncryptionRequired = useSetUpEncryptionRequired(setState);
+
+    let content: JSX.Element;
+    switch (state) {
+        case "loading":
+            content = <InlineSpinner aria-label={_t("common|loading")} />;
+            break;
+        case "set_up_encryption":
+            content = <SetUpEncryptionPanel onFinish={setUpEncryptionRequired} />;
+            break;
+        case "main":
+            content = (
+                <RecoveryPanel
+                    onChangeRecoveryKeyClick={(setupNewKey) =>
+                        setupNewKey ? setState("set_recovery_key") : setState("change_recovery_key")
+                    }
+                />
+            );
+            break;
+        case "change_recovery_key":
+        case "set_recovery_key":
+            content = (
+                <ChangeRecoveryKey
+                    userHasRecoveryKey={state === "change_recovery_key"}
+                    onCancelClick={() => setState("main")}
+                    onFinish={() => setState("main")}
+                />
+            );
+            break;
+    }
+
+    return (
+        <SettingsTab className="mx_EncryptionUserSettingsTab" data-testid="encryptionTab">
+            {content}
+        </SettingsTab>
+    );
+}
+
+/**
+ * Hook to check if the user needs to go through the SetupEncryption flow.
+ * If the user needs to set up the encryption, the state will be set to "set_up_encryption".
+ * Otherwise, the state will be set to "main".
+ *
+ * The state is set once when the component is first mounted.
+ * Also returns a callback function which can be called to re-run the logic.
+ *
+ * @param setState - callback passed from the EncryptionUserSettingsTab to set the current `State`.
+ * @returns a callback function, which will re-run the logic and update the state.
+ */
+function useSetUpEncryptionRequired(setState: (state: State) => void): () => Promise<void> {
+    const matrixClient = useMatrixClientContext();
+
+    const setUpEncryptionRequired = useCallback(async () => {
+        const crypto = matrixClient.getCrypto()!;
+        const isCrossSigningReady = await crypto.isCrossSigningReady();
+        if (isCrossSigningReady) setState("main");
+        else setState("set_up_encryption");
+    }, [matrixClient, setState]);
+
+    // Initialise the state when the component is mounted
+    useEffect(() => {
+        setUpEncryptionRequired();
+    }, [setUpEncryptionRequired]);
+
+    // Also return the callback so that the component can re-run the logic.
+    return setUpEncryptionRequired;
+}
+
+interface SetUpEncryptionPanelProps {
+    /**
+     * Callback to call when the user has finished setting up encryption.
+     */
+    onFinish: () => void;
+}
+
+/**
+ * Panel to show when the user needs to go through the SetupEncryption flow.
+ */
+function SetUpEncryptionPanel({ onFinish }: SetUpEncryptionPanelProps): JSX.Element {
+    // Strictly speaking, the SetupEncryptionDialog may make the user do things other than
+    // verify their device (in particular, if they manage to get here without cross-signing keys existing);
+    // however the common case is that they will be asked to verify, so we just show buttons and headings
+    // that talk about verification.
+    return (
+        <SettingsSection
+            legacy={false}
+            heading={_t("settings|encryption|device_not_verified_title")}
+            subHeading={
+                <SettingsSubheader
+                    stateMessage={_t("settings|encryption|device_not_verified_description")}
+                    state="error"
+                />
+            }
+        >
+            <Button
+                size="sm"
+                Icon={ComputerIcon}
+                onClick={() => Modal.createDialog(SetupEncryptionDialog, { onFinished: onFinish })}
+            >
+                {_t("settings|encryption|device_not_verified_button")}
+            </Button>
+        </SettingsSection>
+    );
+}
diff --git a/src/components/views/settings/tabs/user/HelpUserSettingsTab.tsx b/src/components/views/settings/tabs/user/HelpUserSettingsTab.tsx
index f19343be206..d28c820d206 100644
--- a/src/components/views/settings/tabs/user/HelpUserSettingsTab.tsx
+++ b/src/components/views/settings/tabs/user/HelpUserSettingsTab.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/tabs/user/KeyboardUserSettingsTab.tsx b/src/components/views/settings/tabs/user/KeyboardUserSettingsTab.tsx
index f4dd3de0ff5..b6d2d24c96a 100644
--- a/src/components/views/settings/tabs/user/KeyboardUserSettingsTab.tsx
+++ b/src/components/views/settings/tabs/user/KeyboardUserSettingsTab.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2021, 2022 Šimon Brandner <simon.bra.ag@gmail.com>
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/tabs/user/LabsUserSettingsTab.tsx b/src/components/views/settings/tabs/user/LabsUserSettingsTab.tsx
index 54995415e2e..5cee63b48e4 100644
--- a/src/components/views/settings/tabs/user/LabsUserSettingsTab.tsx
+++ b/src/components/views/settings/tabs/user/LabsUserSettingsTab.tsx
@@ -1,7 +1,7 @@
 /*
 Copyright 2019-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -14,7 +14,7 @@ import { SettingLevel } from "../../../../../settings/SettingLevel";
 import SdkConfig from "../../../../../SdkConfig";
 import BetaCard from "../../../beta/BetaCard";
 import SettingsFlag from "../../../elements/SettingsFlag";
-import { LabGroup, labGroupNames } from "../../../../../settings/Settings";
+import { FeatureSettingKey, LabGroup, labGroupNames } from "../../../../../settings/Settings";
 import { EnhancedMap } from "../../../../../utils/maps";
 import { SettingsSection } from "../../shared/SettingsSection";
 import { SettingsSubsection, SettingsSubsectionText } from "../../shared/SettingsSubsection";
@@ -25,8 +25,8 @@ export const showLabsFlags = (): boolean => {
 };
 
 export default class LabsUserSettingsTab extends React.Component<{}> {
-    private readonly labs: string[];
-    private readonly betas: string[];
+    private readonly labs: FeatureSettingKey[];
+    private readonly betas: FeatureSettingKey[];
 
     public constructor(props: {}) {
         super(props);
@@ -34,10 +34,10 @@ export default class LabsUserSettingsTab extends React.Component<{}> {
         const features = SettingsStore.getFeatureSettingNames();
         const [labs, betas] = features.reduce(
             (arr, f) => {
-                arr[SettingsStore.getBetaInfo(f) ? 1 : 0].push(f);
+                arr[SettingsStore.getBetaInfo(f) ? 1 : 0].push(f as FeatureSettingKey);
                 return arr;
             },
-            [[], []] as [string[], string[]],
+            [[], []] as [FeatureSettingKey[], FeatureSettingKey[]],
         );
 
         this.labs = labs;
diff --git a/src/components/views/settings/tabs/user/MjolnirUserSettingsTab.tsx b/src/components/views/settings/tabs/user/MjolnirUserSettingsTab.tsx
index 3e86d779ff3..9b71244e554 100644
--- a/src/components/views/settings/tabs/user/MjolnirUserSettingsTab.tsx
+++ b/src/components/views/settings/tabs/user/MjolnirUserSettingsTab.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/tabs/user/NotificationUserSettingsTab.tsx b/src/components/views/settings/tabs/user/NotificationUserSettingsTab.tsx
index 5b70d908cce..b63e7907365 100644
--- a/src/components/views/settings/tabs/user/NotificationUserSettingsTab.tsx
+++ b/src/components/views/settings/tabs/user/NotificationUserSettingsTab.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.tsx b/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.tsx
index 8cb662a9f02..8ad00f350fc 100644
--- a/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.tsx
+++ b/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019-2023 The Matrix.org Foundation C.I.C.
 Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -11,7 +11,6 @@ import React, { ReactElement, useCallback, useEffect, useState } from "react";
 
 import { NonEmptyArray } from "../../../../../@types/common";
 import { _t, getCurrentLanguage } from "../../../../../languageHandler";
-import { UseCase } from "../../../../../settings/enums/UseCase";
 import SettingsStore from "../../../../../settings/SettingsStore";
 import Field from "../../../elements/Field";
 import Dropdown from "../../../elements/Dropdown";
@@ -23,7 +22,6 @@ import { UserTab } from "../../../dialogs/UserTab";
 import { OpenToTabPayload } from "../../../../../dispatcher/payloads/OpenToTabPayload";
 import { Action } from "../../../../../dispatcher/actions";
 import SdkConfig from "../../../../../SdkConfig";
-import { showUserOnboardingPage } from "../../../user-onboarding/UserOnboardingPage";
 import { SettingsSubsection } from "../../shared/SettingsSubsection";
 import SettingsTab from "../SettingsTab";
 import { SettingsSection } from "../../shared/SettingsSection";
@@ -33,6 +31,7 @@ import { IS_MAC } from "../../../../../Keyboard";
 import SpellCheckSettings from "../../SpellCheckSettings";
 import LabelledToggleSwitch from "../../../elements/LabelledToggleSwitch";
 import * as TimezoneHandler from "../../../../../TimezoneHandler";
+import { BooleanSettingKey } from "../../../../../settings/Settings.tsx";
 
 interface IProps {
     closeSettingsFn(success: boolean): void;
@@ -117,15 +116,15 @@ const SpellCheckSection: React.FC = () => {
 };
 
 export default class PreferencesUserSettingsTab extends React.Component<IProps, IState> {
-    private static ROOM_LIST_SETTINGS = ["breadcrumbs", "FTUE.userOnboardingButton"];
+    private static ROOM_LIST_SETTINGS: BooleanSettingKey[] = ["breadcrumbs"];
 
-    private static SPACES_SETTINGS = ["Spaces.allRoomsInHome"];
+    private static SPACES_SETTINGS: BooleanSettingKey[] = ["Spaces.allRoomsInHome"];
 
-    private static KEYBINDINGS_SETTINGS = ["ctrlFForSearch"];
+    private static KEYBINDINGS_SETTINGS: BooleanSettingKey[] = ["ctrlFForSearch"];
 
-    private static PRESENCE_SETTINGS = ["sendReadReceipts", "sendTypingNotifications"];
+    private static PRESENCE_SETTINGS: BooleanSettingKey[] = ["sendReadReceipts", "sendTypingNotifications"];
 
-    private static COMPOSER_SETTINGS = [
+    private static COMPOSER_SETTINGS: BooleanSettingKey[] = [
         "MessageComposerInput.autoReplaceEmoji",
         "MessageComposerInput.useMarkdown",
         "MessageComposerInput.suggestEmoji",
@@ -135,17 +134,22 @@ export default class PreferencesUserSettingsTab extends React.Component<IProps,
         "MessageComposerInput.insertTrailingColon",
     ];
 
-    private static TIME_SETTINGS = ["showTwelveHourTimestamps", "alwaysShowTimestamps"];
+    private static TIME_SETTINGS: BooleanSettingKey[] = ["showTwelveHourTimestamps", "alwaysShowTimestamps"];
 
-    private static CODE_BLOCKS_SETTINGS = [
+    private static CODE_BLOCKS_SETTINGS: BooleanSettingKey[] = [
         "enableSyntaxHighlightLanguageDetection",
         "expandCodeByDefault",
         "showCodeLineNumbers",
     ];
 
-    private static IMAGES_AND_VIDEOS_SETTINGS = ["urlPreviewsEnabled", "autoplayGifs", "autoplayVideo", "showImages"];
+    private static IMAGES_AND_VIDEOS_SETTINGS: BooleanSettingKey[] = [
+        "urlPreviewsEnabled",
+        "autoplayGifs",
+        "autoplayVideo",
+        "showImages",
+    ];
 
-    private static TIMELINE_SETTINGS = [
+    private static TIMELINE_SETTINGS: BooleanSettingKey[] = [
         "showTypingNotifications",
         "showRedactions",
         "showReadReceipts",
@@ -159,9 +163,9 @@ export default class PreferencesUserSettingsTab extends React.Component<IProps,
         "useOnlyCurrentProfiles",
     ];
 
-    private static ROOM_DIRECTORY_SETTINGS = ["SpotlightSearch.showNsfwPublicRooms"];
+    private static ROOM_DIRECTORY_SETTINGS: BooleanSettingKey[] = ["SpotlightSearch.showNsfwPublicRooms"];
 
-    private static GENERAL_SETTINGS = [
+    private static GENERAL_SETTINGS: BooleanSettingKey[] = [
         "promptBeforeInviteUnknownUsers",
         // Start automatically after startup (electron-only)
         // Autocomplete delay (niche text box)
@@ -220,7 +224,7 @@ export default class PreferencesUserSettingsTab extends React.Component<IProps,
         SettingsStore.setValue("readMarkerOutOfViewThresholdMs", null, SettingLevel.DEVICE, e.target.value);
     };
 
-    private renderGroup(settingIds: string[], level = SettingLevel.ACCOUNT): React.ReactNodeArray {
+    private renderGroup(settingIds: BooleanSettingKey[], level = SettingLevel.ACCOUNT): React.ReactNodeArray {
         return settingIds.map((i) => <SettingsFlag key={i} name={i} level={level} />);
     }
 
@@ -232,10 +236,7 @@ export default class PreferencesUserSettingsTab extends React.Component<IProps,
     };
 
     public render(): React.ReactNode {
-        const useCase = SettingsStore.getValue<UseCase | null>("FTUE.useCaseSelection");
-        const roomListSettings = PreferencesUserSettingsTab.ROOM_LIST_SETTINGS
-            // Only show the user onboarding setting if the user should see the user onboarding page
-            .filter((it) => it !== "FTUE.userOnboardingButton" || showUserOnboardingPage(useCase));
+        const roomListSettings = PreferencesUserSettingsTab.ROOM_LIST_SETTINGS;
 
         const browserTimezoneLabel: string = _t("settings|preferences|default_timezone", {
             timezone: TimezoneHandler.shortBrowserTimezone(),
diff --git a/src/components/views/settings/tabs/user/SecurityUserSettingsTab.tsx b/src/components/views/settings/tabs/user/SecurityUserSettingsTab.tsx
index 7d5e27580cc..13fc695c3a7 100644
--- a/src/components/views/settings/tabs/user/SecurityUserSettingsTab.tsx
+++ b/src/components/views/settings/tabs/user/SecurityUserSettingsTab.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/settings/tabs/user/SessionManagerTab.tsx b/src/components/views/settings/tabs/user/SessionManagerTab.tsx
index 5e9445bb995..bc4355652b6 100644
--- a/src/components/views/settings/tabs/user/SessionManagerTab.tsx
+++ b/src/components/views/settings/tabs/user/SessionManagerTab.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -31,7 +31,7 @@ import QuestionDialog from "../../../dialogs/QuestionDialog";
 import { FilterVariation } from "../../devices/filter";
 import { OtherSessionsSectionHeading } from "../../devices/OtherSessionsSectionHeading";
 import { SettingsSection } from "../../shared/SettingsSection";
-import { OidcLogoutDialog } from "../../../dialogs/oidc/OidcLogoutDialog";
+import { getManageDeviceUrl } from "../../../../../utils/oidc/urls.ts";
 import { SDKContext } from "../../../../../contexts/SDKContext";
 import Spinner from "../../../elements/Spinner";
 
@@ -58,16 +58,6 @@ const confirmSignOut = async (sessionsToSignOutCount: number): Promise<boolean>
     return !!confirmed;
 };
 
-const confirmDelegatedAuthSignOut = async (delegatedAuthAccountUrl: string, deviceId: string): Promise<boolean> => {
-    const { finished } = Modal.createDialog(OidcLogoutDialog, {
-        deviceId,
-        delegatedAuthAccountUrl,
-    });
-    const [confirmed] = await finished;
-
-    return !!confirmed;
-};
-
 const useSignOut = (
     matrixClient: MatrixClient,
     onSignoutResolvedCallback: () => Promise<void>,
@@ -93,20 +83,10 @@ const useSignOut = (
         if (!deviceIds.length) {
             return;
         }
-        // we can only sign out exactly one OIDC-aware device at a time
-        // we should not encounter this
-        if (delegatedAuthAccountUrl && deviceIds.length !== 1) {
-            logger.warn("Unexpectedly tried to sign out multiple OIDC-aware devices.");
-            return;
-        }
 
-        // delegated auth logout flow confirms and signs out together
-        // so only confirm if we are NOT doing a delegated auth sign out
-        if (!delegatedAuthAccountUrl) {
-            const userConfirmedSignout = await confirmSignOut(deviceIds.length);
-            if (!userConfirmedSignout) {
-                return;
-            }
+        const userConfirmedSignout = await confirmSignOut(deviceIds.length);
+        if (!userConfirmedSignout) {
+            return;
         }
 
         let success = false;
@@ -115,11 +95,8 @@ const useSignOut = (
 
             if (delegatedAuthAccountUrl) {
                 const [deviceId] = deviceIds;
-                try {
-                    success = await confirmDelegatedAuthSignOut(delegatedAuthAccountUrl, deviceId);
-                } catch (error) {
-                    logger.error("Error deleting OIDC-aware sessions", error);
-                }
+                const url = getManageDeviceUrl(delegatedAuthAccountUrl, deviceId);
+                window.open(url, "_blank");
             } else {
                 const deferredSuccess = defer<boolean>();
                 await deleteDevicesWithInteractiveAuth(matrixClient, deviceIds, async (success) => {
@@ -323,6 +300,7 @@ const SessionManagerTab: React.FC<{
                     onSignOutCurrentDevice={onSignOutCurrentDevice}
                     signOutAllOtherSessions={signOutAllOtherSessions}
                     otherSessionsCount={otherSessionsCount}
+                    delegatedAuthAccountUrl={delegatedAuthAccountUrl}
                 />
                 {shouldShowOtherSessions && (
                     <SettingsSubsection
@@ -356,7 +334,7 @@ const SessionManagerTab: React.FC<{
                             setPushNotifications={setPushNotifications}
                             ref={filteredDeviceListRef}
                             supportsMSC3881={supportsMSC3881}
-                            disableMultipleSignout={disableMultipleSignout}
+                            delegatedAuthAccountUrl={delegatedAuthAccountUrl}
                         />
                     </SettingsSubsection>
                 )}
diff --git a/src/components/views/settings/tabs/user/SidebarUserSettingsTab.tsx b/src/components/views/settings/tabs/user/SidebarUserSettingsTab.tsx
index 0971ece699f..d7b6283aa45 100644
--- a/src/components/views/settings/tabs/user/SidebarUserSettingsTab.tsx
+++ b/src/components/views/settings/tabs/user/SidebarUserSettingsTab.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021-2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -58,8 +58,8 @@ const SidebarUserSettingsTab: React.FC = () => {
         [MetaSpace.People]: peopleEnabled,
         [MetaSpace.Orphans]: orphansEnabled,
         [MetaSpace.VideoRooms]: videoRoomsEnabled,
-    } = useSettingValue<Record<MetaSpace, boolean>>("Spaces.enabledMetaSpaces");
-    const allRoomsInHome = useSettingValue<boolean>("Spaces.allRoomsInHome");
+    } = useSettingValue("Spaces.enabledMetaSpaces");
+    const allRoomsInHome = useSettingValue("Spaces.allRoomsInHome");
     const guestSpaUrl = useMemo(() => {
         return SdkConfig.get("element_call").guest_spa_url;
     }, []);
diff --git a/src/components/views/settings/tabs/user/VoiceUserSettingsTab.tsx b/src/components/views/settings/tabs/user/VoiceUserSettingsTab.tsx
index 9711159a10e..a52a232cd5f 100644
--- a/src/components/views/settings/tabs/user/VoiceUserSettingsTab.tsx
+++ b/src/components/views/settings/tabs/user/VoiceUserSettingsTab.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 Copyright 2019 New Vector Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/spaces/QuickSettingsButton.tsx b/src/components/views/spaces/QuickSettingsButton.tsx
index 161290fca88..21e2fda3013 100644
--- a/src/components/views/spaces/QuickSettingsButton.tsx
+++ b/src/components/views/spaces/QuickSettingsButton.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021-2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -36,10 +36,10 @@ const QuickSettingsButton: React.FC<{
     const [menuDisplayed, handle, openMenu, closeMenu] = useContextMenu<HTMLDivElement>();
 
     const { [MetaSpace.Favourites]: favouritesEnabled, [MetaSpace.People]: peopleEnabled } =
-        useSettingValue<Record<MetaSpace, boolean>>("Spaces.enabledMetaSpaces");
+        useSettingValue("Spaces.enabledMetaSpaces");
 
     const currentRoomId = SdkContextClass.instance.roomViewStore.getRoomId();
-    const developerModeEnabled = useSettingValue<boolean>("developerMode");
+    const developerModeEnabled = useSettingValue("developerMode");
 
     let contextMenu: JSX.Element | undefined;
     if (menuDisplayed && handle.current) {
diff --git a/src/components/views/spaces/QuickThemeSwitcher.tsx b/src/components/views/spaces/QuickThemeSwitcher.tsx
index 195fcb98991..1eff342ac39 100644
--- a/src/components/views/spaces/QuickThemeSwitcher.tsx
+++ b/src/components/views/spaces/QuickThemeSwitcher.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/spaces/SpaceBasicSettings.tsx b/src/components/views/spaces/SpaceBasicSettings.tsx
index 63a70a97cd4..4832da50b3a 100644
--- a/src/components/views/spaces/SpaceBasicSettings.tsx
+++ b/src/components/views/spaces/SpaceBasicSettings.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/spaces/SpaceChildrenPicker.tsx b/src/components/views/spaces/SpaceChildrenPicker.tsx
index f6bbe969474..49f873fcf5f 100644
--- a/src/components/views/spaces/SpaceChildrenPicker.tsx
+++ b/src/components/views/spaces/SpaceChildrenPicker.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/spaces/SpaceCreateMenu.tsx b/src/components/views/spaces/SpaceCreateMenu.tsx
index 764417e0b2c..e964894502c 100644
--- a/src/components/views/spaces/SpaceCreateMenu.tsx
+++ b/src/components/views/spaces/SpaceCreateMenu.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/spaces/SpacePanel.tsx b/src/components/views/spaces/SpacePanel.tsx
index 73bb66af380..3dd46abb8d4 100644
--- a/src/components/views/spaces/SpacePanel.tsx
+++ b/src/components/views/spaces/SpacePanel.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021, 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -88,7 +88,7 @@ export const HomeButtonContextMenu: React.FC<ComponentProps<typeof SpaceContextM
     hideHeader,
     ...props
 }) => {
-    const allRoomsInHome = useSettingValue<boolean>("Spaces.allRoomsInHome");
+    const allRoomsInHome = useSettingValue("Spaces.allRoomsInHome");
 
     return (
         <IconizedContextMenu {...props} onFinished={onFinished} className="mx_SpacePanel_contextMenu" compact>
diff --git a/src/components/views/spaces/SpacePublicShare.tsx b/src/components/views/spaces/SpacePublicShare.tsx
index 8b649e0b32e..8e148567ac7 100644
--- a/src/components/views/spaces/SpacePublicShare.tsx
+++ b/src/components/views/spaces/SpacePublicShare.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021-2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/spaces/SpaceSettingsGeneralTab.tsx b/src/components/views/spaces/SpaceSettingsGeneralTab.tsx
index 8d80f85c581..09f14ec2e13 100644
--- a/src/components/views/spaces/SpaceSettingsGeneralTab.tsx
+++ b/src/components/views/spaces/SpaceSettingsGeneralTab.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/spaces/SpaceSettingsVisibilityTab.tsx b/src/components/views/spaces/SpaceSettingsVisibilityTab.tsx
index 47f4fe8ce9f..3612f668c9c 100644
--- a/src/components/views/spaces/SpaceSettingsVisibilityTab.tsx
+++ b/src/components/views/spaces/SpaceSettingsVisibilityTab.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021-2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/spaces/SpaceTreeLevel.tsx b/src/components/views/spaces/SpaceTreeLevel.tsx
index 38329c39b73..d85e5ff2a91 100644
--- a/src/components/views/spaces/SpaceTreeLevel.tsx
+++ b/src/components/views/spaces/SpaceTreeLevel.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021-2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/spaces/threads-activity-centre/ThreadsActivityCentre.tsx b/src/components/views/spaces/threads-activity-centre/ThreadsActivityCentre.tsx
index c8e5ef1424b..562019a33f8 100644
--- a/src/components/views/spaces/threads-activity-centre/ThreadsActivityCentre.tsx
+++ b/src/components/views/spaces/threads-activity-centre/ThreadsActivityCentre.tsx
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2024 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
@@ -44,7 +44,7 @@ export function ThreadsActivityCentre({ displayButtonLabel }: ThreadsActivityCen
     const [open, setOpen] = useState(false);
     const roomsAndNotifications = useUnreadThreadRooms(open);
     const isReleaseAnnouncementOpen = useIsReleaseAnnouncementOpen("threadsActivityCentre");
-    const settingTACOnlyNotifs = useSettingValue<boolean>("Notifications.tac_only_notifications");
+    const settingTACOnlyNotifs = useSettingValue("Notifications.tac_only_notifications");
 
     const emptyCaption = settingTACOnlyNotifs
         ? _t("threads_activity_centre|no_rooms_with_threads_notifs")
diff --git a/src/components/views/spaces/threads-activity-centre/ThreadsActivityCentreButton.tsx b/src/components/views/spaces/threads-activity-centre/ThreadsActivityCentreButton.tsx
index 801a6050c34..123b8a072eb 100644
--- a/src/components/views/spaces/threads-activity-centre/ThreadsActivityCentreButton.tsx
+++ b/src/components/views/spaces/threads-activity-centre/ThreadsActivityCentreButton.tsx
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2024 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/src/components/views/spaces/threads-activity-centre/index.ts b/src/components/views/spaces/threads-activity-centre/index.ts
index 98aa767866d..f900a805708 100644
--- a/src/components/views/spaces/threads-activity-centre/index.ts
+++ b/src/components/views/spaces/threads-activity-centre/index.ts
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2024 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/src/components/views/spaces/threads-activity-centre/useUnreadThreadRooms.ts b/src/components/views/spaces/threads-activity-centre/useUnreadThreadRooms.ts
index 110c9d51f83..94486fdf76e 100644
--- a/src/components/views/spaces/threads-activity-centre/useUnreadThreadRooms.ts
+++ b/src/components/views/spaces/threads-activity-centre/useUnreadThreadRooms.ts
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2024 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
@@ -32,8 +32,8 @@ type Result = {
  * @returns {Result}
  */
 export function useUnreadThreadRooms(forceComputation: boolean): Result {
-    const msc3946ProcessDynamicPredecessor = useSettingValue<boolean>("feature_dynamic_room_predecessors");
-    const settingTACOnlyNotifs = useSettingValue<boolean>("Notifications.tac_only_notifications");
+    const msc3946ProcessDynamicPredecessor = useSettingValue("feature_dynamic_room_predecessors");
+    const settingTACOnlyNotifs = useSettingValue("Notifications.tac_only_notifications");
     const mxClient = useMatrixClientContext();
 
     const [result, setResult] = useState<Result>({ greatestNotificationLevel: NotificationLevel.None, rooms: [] });
diff --git a/src/components/views/terms/InlineTermsAgreement.tsx b/src/components/views/terms/InlineTermsAgreement.tsx
index 350c408d750..2e4f48712ff 100644
--- a/src/components/views/terms/InlineTermsAgreement.tsx
+++ b/src/components/views/terms/InlineTermsAgreement.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/toasts/GenericExpiringToast.tsx b/src/components/views/toasts/GenericExpiringToast.tsx
index 0809eae92c2..b019babaf23 100644
--- a/src/components/views/toasts/GenericExpiringToast.tsx
+++ b/src/components/views/toasts/GenericExpiringToast.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/toasts/GenericToast.tsx b/src/components/views/toasts/GenericToast.tsx
index 76c74993c03..0e249cecdcb 100644
--- a/src/components/views/toasts/GenericToast.tsx
+++ b/src/components/views/toasts/GenericToast.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020, 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/toasts/NonUrgentEchoFailureToast.tsx b/src/components/views/toasts/NonUrgentEchoFailureToast.tsx
index 069d5ee88c0..490b251adec 100644
--- a/src/components/views/toasts/NonUrgentEchoFailureToast.tsx
+++ b/src/components/views/toasts/NonUrgentEchoFailureToast.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/toasts/VerificationRequestToast.tsx b/src/components/views/toasts/VerificationRequestToast.tsx
index 7d31aa67640..f235b8f488b 100644
--- a/src/components/views/toasts/VerificationRequestToast.tsx
+++ b/src/components/views/toasts/VerificationRequestToast.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/typography/Caption.tsx b/src/components/views/typography/Caption.tsx
index 3bf57476883..0ce9fbb65c1 100644
--- a/src/components/views/typography/Caption.tsx
+++ b/src/components/views/typography/Caption.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/typography/Heading.tsx b/src/components/views/typography/Heading.tsx
index 70ade1a516a..c367c5d4457 100644
--- a/src/components/views/typography/Heading.tsx
+++ b/src/components/views/typography/Heading.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/user-onboarding/UserOnboardingButton.tsx b/src/components/views/user-onboarding/UserOnboardingButton.tsx
deleted file mode 100644
index d1e420d4ac7..00000000000
--- a/src/components/views/user-onboarding/UserOnboardingButton.tsx
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2022 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
-Please see LICENSE files in the repository root for full details.
-*/
-
-import classNames from "classnames";
-import React, { useCallback } from "react";
-
-import { Action } from "../../../dispatcher/actions";
-import defaultDispatcher from "../../../dispatcher/dispatcher";
-import { useSettingValue } from "../../../hooks/useSettings";
-import { _t } from "../../../languageHandler";
-import PosthogTrackers from "../../../PosthogTrackers";
-import { UseCase } from "../../../settings/enums/UseCase";
-import { SettingLevel } from "../../../settings/SettingLevel";
-import SettingsStore from "../../../settings/SettingsStore";
-import AccessibleButton, { ButtonEvent } from "../../views/elements/AccessibleButton";
-import Heading from "../../views/typography/Heading";
-import { showUserOnboardingPage } from "./UserOnboardingPage";
-
-interface Props {
-    selected: boolean;
-    minimized: boolean;
-}
-
-export function UserOnboardingButton({ selected, minimized }: Props): JSX.Element {
-    const useCase = useSettingValue<UseCase | null>("FTUE.useCaseSelection");
-    const visible = useSettingValue<boolean>("FTUE.userOnboardingButton");
-
-    if (!visible || minimized || !showUserOnboardingPage(useCase)) {
-        return <></>;
-    }
-
-    return <UserOnboardingButtonInternal selected={selected} minimized={minimized} />;
-}
-
-function UserOnboardingButtonInternal({ selected, minimized }: Props): JSX.Element {
-    const onDismiss = useCallback((ev: ButtonEvent) => {
-        ev.preventDefault();
-        ev.stopPropagation();
-
-        PosthogTrackers.trackInteraction("WebRoomListUserOnboardingIgnoreButton", ev);
-        SettingsStore.setValue("FTUE.userOnboardingButton", null, SettingLevel.ACCOUNT, false);
-    }, []);
-
-    const onClick = useCallback((ev: ButtonEvent) => {
-        ev.preventDefault();
-        ev.stopPropagation();
-
-        PosthogTrackers.trackInteraction("WebRoomListUserOnboardingButton", ev);
-        defaultDispatcher.fire(Action.ViewHomePage);
-    }, []);
-
-    return (
-        <AccessibleButton
-            className={classNames("mx_UserOnboardingButton", {
-                mx_UserOnboardingButton_selected: selected,
-                mx_UserOnboardingButton_minimized: minimized,
-            })}
-            onClick={onClick}
-        >
-            {!minimized && (
-                <>
-                    <div className="mx_UserOnboardingButton_content">
-                        <Heading size="4" className="mx_Heading_h4">
-                            {_t("common|welcome")}
-                        </Heading>
-                        <AccessibleButton
-                            className="mx_UserOnboardingButton_close"
-                            onClick={onDismiss}
-                            aria-label={_t("action|dismiss")}
-                        />
-                    </div>
-                </>
-            )}
-        </AccessibleButton>
-    );
-}
diff --git a/src/components/views/user-onboarding/UserOnboardingHeader.tsx b/src/components/views/user-onboarding/UserOnboardingHeader.tsx
deleted file mode 100644
index 1f6edbff1da..00000000000
--- a/src/components/views/user-onboarding/UserOnboardingHeader.tsx
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2022 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
-Please see LICENSE files in the repository root for full details.
-*/
-
-import * as React from "react";
-
-import defaultDispatcher from "../../../dispatcher/dispatcher";
-import { _t } from "../../../languageHandler";
-import PosthogTrackers from "../../../PosthogTrackers";
-import SdkConfig from "../../../SdkConfig";
-import { UseCase } from "../../../settings/enums/UseCase";
-import AccessibleButton, { ButtonEvent } from "../../views/elements/AccessibleButton";
-import Heading from "../../views/typography/Heading";
-
-const onClickSendDm = (ev: ButtonEvent): void => {
-    PosthogTrackers.trackInteraction("WebUserOnboardingHeaderSendDm", ev);
-    defaultDispatcher.dispatch({ action: "view_create_chat" });
-};
-
-interface Props {
-    useCase: UseCase | null;
-}
-
-export function UserOnboardingHeader({ useCase }: Props): JSX.Element {
-    let title: string;
-    let description = _t("onboarding|free_e2ee_messaging_unlimited_voip", {
-        brand: SdkConfig.get("brand"),
-    });
-    let image: string;
-    let actionLabel: string;
-
-    switch (useCase) {
-        /* eslint-disable @typescript-eslint/no-require-imports */
-        case UseCase.PersonalMessaging:
-            title = _t("onboarding|personal_messaging_title");
-            image = require("../../../../res/img/user-onboarding/PersonalMessaging.png");
-            actionLabel = _t("onboarding|personal_messaging_action");
-            break;
-        case UseCase.WorkMessaging:
-            title = _t("onboarding|work_messaging_title");
-            description = _t("onboarding|free_e2ee_messaging_unlimited_voip", {
-                brand: SdkConfig.get("brand"),
-            });
-            image = require("../../../../res/img/user-onboarding/WorkMessaging.png");
-            actionLabel = _t("onboarding|work_messaging_action");
-            break;
-        case UseCase.CommunityMessaging:
-            title = _t("onboarding|community_messaging_title");
-            description = _t("onboarding|community_messaging_description");
-            image = require("../../../../res/img/user-onboarding/CommunityMessaging.png");
-            actionLabel = _t("onboarding|community_messaging_action");
-            break;
-        default:
-            title = _t("onboarding|welcome_to_brand", {
-                brand: SdkConfig.get("brand"),
-            });
-            image = require("../../../../res/img/user-onboarding/PersonalMessaging.png");
-            actionLabel = _t("onboarding|personal_messaging_action");
-            break;
-        /* eslint-enable @typescript-eslint/no-require-imports */
-    }
-
-    return (
-        <div className="mx_UserOnboardingHeader">
-            <div className="mx_UserOnboardingHeader_content">
-                <Heading size="1">
-                    {title}
-                    <span className="mx_UserOnboardingHeader_dot">.</span>
-                </Heading>
-                <p>{description}</p>
-                <AccessibleButton onClick={onClickSendDm} kind="primary">
-                    {actionLabel}
-                </AccessibleButton>
-            </div>
-            <img className="mx_UserOnboardingHeader_image" src={image} alt="" />
-        </div>
-    );
-}
diff --git a/src/components/views/user-onboarding/UserOnboardingList.tsx b/src/components/views/user-onboarding/UserOnboardingList.tsx
deleted file mode 100644
index c6c03527cb5..00000000000
--- a/src/components/views/user-onboarding/UserOnboardingList.tsx
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2022 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
-Please see LICENSE files in the repository root for full details.
-*/
-
-import * as React from "react";
-
-import { UserOnboardingTaskWithResolvedCompletion } from "../../../hooks/useUserOnboardingTasks";
-import { _t } from "../../../languageHandler";
-import SdkConfig from "../../../SdkConfig";
-import ProgressBar from "../../views/elements/ProgressBar";
-import Heading from "../../views/typography/Heading";
-import { UserOnboardingTask } from "./UserOnboardingTask";
-
-export const getUserOnboardingCounters = (
-    tasks: UserOnboardingTaskWithResolvedCompletion[],
-): {
-    completed: number;
-    waiting: number;
-    total: number;
-} => {
-    const completed = tasks.filter((task) => task.completed === true).length;
-    const waiting = tasks.filter((task) => task.completed === false).length;
-
-    return {
-        completed: completed,
-        waiting: waiting,
-        total: completed + waiting,
-    };
-};
-
-interface Props {
-    tasks: UserOnboardingTaskWithResolvedCompletion[];
-}
-
-export function UserOnboardingList({ tasks }: Props): JSX.Element {
-    const { completed, waiting, total } = getUserOnboardingCounters(tasks);
-
-    return (
-        <div className="mx_UserOnboardingList" data-testid="user-onboarding-list">
-            <div className="mx_UserOnboardingList_header">
-                <Heading size="3" className="mx_UserOnboardingList_title">
-                    {waiting > 0
-                        ? _t("onboarding|only_n_steps_to_go", {
-                              count: waiting,
-                          })
-                        : _t("onboarding|you_did_it")}
-                </Heading>
-                <div className="mx_UserOnboardingList_hint">
-                    {_t("onboarding|complete_these", {
-                        brand: SdkConfig.get("brand"),
-                    })}
-                </div>
-            </div>
-            <div className="mx_UserOnboardingList_progress">
-                <ProgressBar value={completed} max={total} animated />
-            </div>
-            <ol className="mx_UserOnboardingList_list">
-                {tasks.map((task) => (
-                    <UserOnboardingTask key={task.id} completed={task.completed} task={task} />
-                ))}
-            </ol>
-        </div>
-    );
-}
diff --git a/src/components/views/user-onboarding/UserOnboardingPage.tsx b/src/components/views/user-onboarding/UserOnboardingPage.tsx
deleted file mode 100644
index ebb9b9565e3..00000000000
--- a/src/components/views/user-onboarding/UserOnboardingPage.tsx
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2020-2022 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
-Please see LICENSE files in the repository root for full details.
-*/
-
-import { useEffect, useState } from "react";
-import * as React from "react";
-
-import { useInitialSyncComplete } from "../../../hooks/useIsInitialSyncComplete";
-import { useSettingValue } from "../../../hooks/useSettings";
-import { useUserOnboardingContext } from "../../../hooks/useUserOnboardingContext";
-import { useUserOnboardingTasks } from "../../../hooks/useUserOnboardingTasks";
-import { MatrixClientPeg } from "../../../MatrixClientPeg";
-import SdkConfig from "../../../SdkConfig";
-import { UseCase } from "../../../settings/enums/UseCase";
-import { getHomePageUrl } from "../../../utils/pages";
-import AutoHideScrollbar from "../../structures/AutoHideScrollbar";
-import EmbeddedPage from "../../structures/EmbeddedPage";
-import HomePage from "../../structures/HomePage";
-import { UserOnboardingHeader } from "./UserOnboardingHeader";
-import { UserOnboardingList } from "./UserOnboardingList";
-import { useMatrixClientContext } from "../../../contexts/MatrixClientContext";
-
-interface Props {
-    justRegistered?: boolean;
-}
-
-// We decided to only show the new user onboarding page to new users
-// For now, that means we set the cutoff at 2022-07-01 00:00 UTC
-const USER_ONBOARDING_CUTOFF_DATE = new Date(1_656_633_600);
-export function showUserOnboardingPage(useCase: UseCase | null): boolean {
-    return useCase !== null || MatrixClientPeg.userRegisteredAfter(USER_ONBOARDING_CUTOFF_DATE);
-}
-
-const ANIMATION_DURATION = 2800;
-export function UserOnboardingPage({ justRegistered = false }: Props): JSX.Element {
-    const cli = useMatrixClientContext();
-    const config = SdkConfig.get();
-    const pageUrl = getHomePageUrl(config, cli);
-
-    const useCase = useSettingValue<UseCase | null>("FTUE.useCaseSelection");
-    const context = useUserOnboardingContext();
-    const tasks = useUserOnboardingTasks(context);
-
-    const initialSyncComplete = useInitialSyncComplete();
-    const [showList, setShowList] = useState<boolean>(false);
-    useEffect(() => {
-        if (initialSyncComplete) {
-            const handler = window.setTimeout(() => {
-                setShowList(true);
-            }, ANIMATION_DURATION);
-            return () => {
-                clearTimeout(handler);
-            };
-        } else {
-            setShowList(false);
-        }
-    }, [initialSyncComplete, setShowList]);
-
-    // Only show new onboarding list to users who registered after a given date or have chosen a use case
-    if (!showUserOnboardingPage(useCase)) {
-        return <HomePage justRegistered={justRegistered} />;
-    }
-
-    if (pageUrl) {
-        return <EmbeddedPage className="mx_HomePage" url={pageUrl} scrollbar={true} />;
-    }
-
-    return (
-        <AutoHideScrollbar className="mx_UserOnboardingPage">
-            <UserOnboardingHeader useCase={useCase} />
-            {showList && <UserOnboardingList tasks={tasks} />}
-        </AutoHideScrollbar>
-    );
-}
diff --git a/src/components/views/user-onboarding/UserOnboardingTask.tsx b/src/components/views/user-onboarding/UserOnboardingTask.tsx
deleted file mode 100644
index add9db1b35e..00000000000
--- a/src/components/views/user-onboarding/UserOnboardingTask.tsx
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2022 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
-Please see LICENSE files in the repository root for full details.
-*/
-
-import classNames from "classnames";
-import * as React from "react";
-
-import { UserOnboardingTaskWithResolvedCompletion } from "../../../hooks/useUserOnboardingTasks";
-import AccessibleButton from "../../views/elements/AccessibleButton";
-import Heading from "../../views/typography/Heading";
-
-interface Props {
-    task: UserOnboardingTaskWithResolvedCompletion;
-    completed?: boolean;
-}
-
-export function UserOnboardingTask({ task, completed = false }: Props): JSX.Element {
-    const title = typeof task.title === "function" ? task.title() : task.title;
-    const description = typeof task.description === "function" ? task.description() : task.description;
-
-    return (
-        <li
-            data-testid="user-onboarding-task"
-            className={classNames("mx_UserOnboardingTask", {
-                mx_UserOnboardingTask_completed: completed,
-            })}
-        >
-            <div
-                className="mx_UserOnboardingTask_number"
-                role="checkbox"
-                aria-disabled="true"
-                aria-checked={completed}
-                aria-labelledby={`mx_UserOnboardingTask_${task.id}`}
-            />
-            <div id={`mx_UserOnboardingTask_${task.id}`} className="mx_UserOnboardingTask_content">
-                <Heading size="4" className="mx_UserOnboardingTask_title">
-                    {title}
-                </Heading>
-                <div className="mx_UserOnboardingTask_description">{description}</div>
-            </div>
-            {task.action && (!task.action.hideOnComplete || !completed) && (
-                <AccessibleButton
-                    element="a"
-                    className="mx_UserOnboardingTask_action"
-                    kind="primary_outline"
-                    href={task.action.href}
-                    target="_blank"
-                    onClick={task.action.onClick ?? null}
-                >
-                    {task.action.label}
-                </AccessibleButton>
-            )}
-        </li>
-    );
-}
diff --git a/src/components/views/verification/VerificationCancelled.tsx b/src/components/views/verification/VerificationCancelled.tsx
index d1a84742b19..41fae925f62 100644
--- a/src/components/views/verification/VerificationCancelled.tsx
+++ b/src/components/views/verification/VerificationCancelled.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 Vector Creations Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/verification/VerificationComplete.tsx b/src/components/views/verification/VerificationComplete.tsx
index 3760b2df703..0bbb2d39de3 100644
--- a/src/components/views/verification/VerificationComplete.tsx
+++ b/src/components/views/verification/VerificationComplete.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 Vector Creations Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/verification/VerificationShowSas.tsx b/src/components/views/verification/VerificationShowSas.tsx
index 1e053a7e99e..df9ddba8921 100644
--- a/src/components/views/verification/VerificationShowSas.tsx
+++ b/src/components/views/verification/VerificationShowSas.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 Vector Creations Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/voip/AudioFeed.tsx b/src/components/views/voip/AudioFeed.tsx
index 88f1463bb5b..36a02c21cd7 100644
--- a/src/components/views/voip/AudioFeed.tsx
+++ b/src/components/views/voip/AudioFeed.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/voip/AudioFeedArrayForLegacyCall.tsx b/src/components/views/voip/AudioFeedArrayForLegacyCall.tsx
index b135bb02798..5b2a0d0c87f 100644
--- a/src/components/views/voip/AudioFeedArrayForLegacyCall.tsx
+++ b/src/components/views/voip/AudioFeedArrayForLegacyCall.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/voip/CallDuration.tsx b/src/components/views/voip/CallDuration.tsx
index 3dba4bfc17b..34f5d0ba608 100644
--- a/src/components/views/voip/CallDuration.tsx
+++ b/src/components/views/voip/CallDuration.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/voip/CallView.tsx b/src/components/views/voip/CallView.tsx
index e51d1c0253b..b7b15c2f715 100644
--- a/src/components/views/voip/CallView.tsx
+++ b/src/components/views/voip/CallView.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/voip/DialPad.tsx b/src/components/views/voip/DialPad.tsx
index 9dda9468d84..a23c89fdef8 100644
--- a/src/components/views/voip/DialPad.tsx
+++ b/src/components/views/voip/DialPad.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/voip/DialPadModal.tsx b/src/components/views/voip/DialPadModal.tsx
index b4b7cdf6472..172a9cbaa57 100644
--- a/src/components/views/voip/DialPadModal.tsx
+++ b/src/components/views/voip/DialPadModal.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/voip/LegacyCallView.tsx b/src/components/views/voip/LegacyCallView.tsx
index aba3d60743d..9c5246b912f 100644
--- a/src/components/views/voip/LegacyCallView.tsx
+++ b/src/components/views/voip/LegacyCallView.tsx
@@ -4,7 +4,7 @@ Copyright 2021, 2022 Šimon Brandner <simon.bra.ag@gmail.com>
 Copyright 2019-2021 The Matrix.org Foundation C.I.C.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/voip/LegacyCallView/LegacyCallViewButtons.tsx b/src/components/views/voip/LegacyCallView/LegacyCallViewButtons.tsx
index 105736d04e2..7788cb0e78e 100644
--- a/src/components/views/voip/LegacyCallView/LegacyCallViewButtons.tsx
+++ b/src/components/views/voip/LegacyCallView/LegacyCallViewButtons.tsx
@@ -4,7 +4,7 @@ Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
 Copyright 2019-2021 The Matrix.org Foundation C.I.C.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/voip/LegacyCallView/LegacyCallViewHeader.tsx b/src/components/views/voip/LegacyCallView/LegacyCallViewHeader.tsx
index bb81527ef0f..b443636d85a 100644
--- a/src/components/views/voip/LegacyCallView/LegacyCallViewHeader.tsx
+++ b/src/components/views/voip/LegacyCallView/LegacyCallViewHeader.tsx
@@ -1,7 +1,7 @@
 /*
 Copyright 2021-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/voip/LegacyCallViewForRoom.tsx b/src/components/views/voip/LegacyCallViewForRoom.tsx
index defee6b97c9..ed55f908be2 100644
--- a/src/components/views/voip/LegacyCallViewForRoom.tsx
+++ b/src/components/views/voip/LegacyCallViewForRoom.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020-2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/voip/LegacyCallViewSidebar.tsx b/src/components/views/voip/LegacyCallViewSidebar.tsx
index d0c328f8bec..3dcf3c644d5 100644
--- a/src/components/views/voip/LegacyCallViewSidebar.tsx
+++ b/src/components/views/voip/LegacyCallViewSidebar.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/components/views/voip/VideoFeed.tsx b/src/components/views/voip/VideoFeed.tsx
index 6931027ddf4..80ea27223c7 100644
--- a/src/components/views/voip/VideoFeed.tsx
+++ b/src/components/views/voip/VideoFeed.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2021, 2022 Šimon Brandner <simon.bra.ag@gmail.com>
 Copyright 2015, 2016 , 2019, 2020, 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/contexts/LocalDeviceVerificationStateContext.ts b/src/contexts/LocalDeviceVerificationStateContext.ts
index 43527e100be..df5af672529 100644
--- a/src/contexts/LocalDeviceVerificationStateContext.ts
+++ b/src/contexts/LocalDeviceVerificationStateContext.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/contexts/MatrixClientContext.tsx b/src/contexts/MatrixClientContext.tsx
index ec804f881bc..79ce5e50094 100644
--- a/src/contexts/MatrixClientContext.tsx
+++ b/src/contexts/MatrixClientContext.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/contexts/RoomContext.ts b/src/contexts/RoomContext.ts
index 4303c46a34e..19f87d9471c 100644
--- a/src/contexts/RoomContext.ts
+++ b/src/contexts/RoomContext.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/contexts/SDKContext.ts b/src/contexts/SDKContext.ts
index fe736615545..184bea4cfaa 100644
--- a/src/contexts/SDKContext.ts
+++ b/src/contexts/SDKContext.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -13,7 +13,6 @@ import defaultDispatcher from "../dispatcher/dispatcher";
 import LegacyCallHandler from "../LegacyCallHandler";
 import { PosthogAnalytics } from "../PosthogAnalytics";
 import { SlidingSyncManager } from "../SlidingSyncManager";
-import { AccountPasswordStore } from "../stores/AccountPasswordStore";
 import { MemberListStore } from "../stores/MemberListStore";
 import { RoomNotificationStateStore } from "../stores/notifications/RoomNotificationStateStore";
 import RightPanelStore from "../stores/right-panel/RightPanelStore";
@@ -63,7 +62,6 @@ export class SdkContextClass {
     protected _SpaceStore?: SpaceStoreClass;
     protected _LegacyCallHandler?: LegacyCallHandler;
     protected _TypingStore?: TypingStore;
-    protected _AccountPasswordStore?: AccountPasswordStore;
     protected _UserProfilesStore?: UserProfilesStore;
     protected _OidcClientStore?: OidcClientStore;
 
@@ -149,13 +147,6 @@ export class SdkContextClass {
         return this._TypingStore;
     }
 
-    public get accountPasswordStore(): AccountPasswordStore {
-        if (!this._AccountPasswordStore) {
-            this._AccountPasswordStore = new AccountPasswordStore();
-        }
-        return this._AccountPasswordStore;
-    }
-
     public get userProfilesStore(): UserProfilesStore {
         if (!this.client) {
             throw new Error("Unable to create UserProfilesStore without a client");
diff --git a/src/contexts/ScopedRoomContext.tsx b/src/contexts/ScopedRoomContext.tsx
index 1222443d290..2b1827952d8 100644
--- a/src/contexts/ScopedRoomContext.tsx
+++ b/src/contexts/ScopedRoomContext.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/contexts/ToastContext.tsx b/src/contexts/ToastContext.tsx
index 4ae4875c96b..100eb6add09 100644
--- a/src/contexts/ToastContext.tsx
+++ b/src/contexts/ToastContext.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/createRoom.ts b/src/createRoom.ts
index 1a09eecfe9b..45f071aac7d 100644
--- a/src/createRoom.ts
+++ b/src/createRoom.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/customisations/Alias.ts b/src/customisations/Alias.ts
index 58be28ced8a..6e5c60be586 100644
--- a/src/customisations/Alias.ts
+++ b/src/customisations/Alias.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/customisations/ChatExport.ts b/src/customisations/ChatExport.ts
index a4c6c70b33c..ae979d4273c 100644
--- a/src/customisations/ChatExport.ts
+++ b/src/customisations/ChatExport.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/customisations/ComponentVisibility.ts b/src/customisations/ComponentVisibility.ts
index 44464169f5d..c69b6ee185b 100644
--- a/src/customisations/ComponentVisibility.ts
+++ b/src/customisations/ComponentVisibility.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/customisations/Directory.ts b/src/customisations/Directory.ts
index 445863eaece..c5536801258 100644
--- a/src/customisations/Directory.ts
+++ b/src/customisations/Directory.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/customisations/Lifecycle.ts b/src/customisations/Lifecycle.ts
index d76275e23ab..2873093414e 100644
--- a/src/customisations/Lifecycle.ts
+++ b/src/customisations/Lifecycle.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/customisations/Media.ts b/src/customisations/Media.ts
index f9e7766b00b..d7b367c5843 100644
--- a/src/customisations/Media.ts
+++ b/src/customisations/Media.ts
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2021 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/src/customisations/RoomList.ts b/src/customisations/RoomList.ts
index e2c2088dad8..a62e1bf6fca 100644
--- a/src/customisations/RoomList.ts
+++ b/src/customisations/RoomList.ts
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2020 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/src/customisations/UserIdentifier.ts b/src/customisations/UserIdentifier.ts
index 7e291bdad86..cc36a1d8c7f 100644
--- a/src/customisations/UserIdentifier.ts
+++ b/src/customisations/UserIdentifier.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/customisations/WidgetPermissions.ts b/src/customisations/WidgetPermissions.ts
index fa46e032dc0..9734fee9d01 100644
--- a/src/customisations/WidgetPermissions.ts
+++ b/src/customisations/WidgetPermissions.ts
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2020 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/src/customisations/WidgetVariables.ts b/src/customisations/WidgetVariables.ts
index a6235b721be..6a6651dd102 100644
--- a/src/customisations/WidgetVariables.ts
+++ b/src/customisations/WidgetVariables.ts
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2021 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/src/customisations/helpers/UIComponents.ts b/src/customisations/helpers/UIComponents.ts
index 4cbc9a88a98..1c710f112dc 100644
--- a/src/customisations/helpers/UIComponents.ts
+++ b/src/customisations/helpers/UIComponents.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/customisations/models/IMediaEventContent.ts b/src/customisations/models/IMediaEventContent.ts
index 15dae2eb677..607fc012ad5 100644
--- a/src/customisations/models/IMediaEventContent.ts
+++ b/src/customisations/models/IMediaEventContent.ts
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2021 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/src/dispatcher/actions.ts b/src/dispatcher/actions.ts
index 718f592e6a2..5205e5badf3 100644
--- a/src/dispatcher/actions.ts
+++ b/src/dispatcher/actions.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/dispatcher/dispatcher.ts b/src/dispatcher/dispatcher.ts
index f50e2bfe007..8b093e2e4a8 100644
--- a/src/dispatcher/dispatcher.ts
+++ b/src/dispatcher/dispatcher.ts
@@ -4,7 +4,7 @@ Copyright 2020 The Matrix.org Foundation C.I.C.
 Copyright 2017 New Vector Ltd
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/dispatcher/payloads.ts b/src/dispatcher/payloads.ts
index eb177e8b569..114f1e55150 100644
--- a/src/dispatcher/payloads.ts
+++ b/src/dispatcher/payloads.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/dispatcher/payloads/ActiveRoomChangedPayload.ts b/src/dispatcher/payloads/ActiveRoomChangedPayload.ts
index e24a523e8cb..bb1c0e4afb4 100644
--- a/src/dispatcher/payloads/ActiveRoomChangedPayload.ts
+++ b/src/dispatcher/payloads/ActiveRoomChangedPayload.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/dispatcher/payloads/AfterLeaveRoomPayload.ts b/src/dispatcher/payloads/AfterLeaveRoomPayload.ts
index bb2cd0825cb..5a74dce7bee 100644
--- a/src/dispatcher/payloads/AfterLeaveRoomPayload.ts
+++ b/src/dispatcher/payloads/AfterLeaveRoomPayload.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/dispatcher/payloads/CancelAskToJoinPayload.ts b/src/dispatcher/payloads/CancelAskToJoinPayload.ts
index a35d76d1e80..d9ca8d291e9 100644
--- a/src/dispatcher/payloads/CancelAskToJoinPayload.ts
+++ b/src/dispatcher/payloads/CancelAskToJoinPayload.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 Nordeck IT + Consulting GmbH
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/dispatcher/payloads/CheckUpdatesPayload.ts b/src/dispatcher/payloads/CheckUpdatesPayload.ts
index e1f8c948a50..b588193b4ff 100644
--- a/src/dispatcher/payloads/CheckUpdatesPayload.ts
+++ b/src/dispatcher/payloads/CheckUpdatesPayload.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/dispatcher/payloads/ComposerInsertPayload.ts b/src/dispatcher/payloads/ComposerInsertPayload.ts
index d0652f431a9..941f8c135ce 100644
--- a/src/dispatcher/payloads/ComposerInsertPayload.ts
+++ b/src/dispatcher/payloads/ComposerInsertPayload.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/dispatcher/payloads/DoAfterSyncPreparedPayload.ts b/src/dispatcher/payloads/DoAfterSyncPreparedPayload.ts
index c55b62bbc8c..2f2ed06f661 100644
--- a/src/dispatcher/payloads/DoAfterSyncPreparedPayload.ts
+++ b/src/dispatcher/payloads/DoAfterSyncPreparedPayload.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/dispatcher/payloads/FocusComposerPayload.ts b/src/dispatcher/payloads/FocusComposerPayload.ts
index 9db1ba9b1cb..6ec62e47589 100644
--- a/src/dispatcher/payloads/FocusComposerPayload.ts
+++ b/src/dispatcher/payloads/FocusComposerPayload.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/dispatcher/payloads/JoinRoomErrorPayload.ts b/src/dispatcher/payloads/JoinRoomErrorPayload.ts
index 7db3102fd60..1112674f21d 100644
--- a/src/dispatcher/payloads/JoinRoomErrorPayload.ts
+++ b/src/dispatcher/payloads/JoinRoomErrorPayload.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/dispatcher/payloads/JoinRoomPayload.ts b/src/dispatcher/payloads/JoinRoomPayload.ts
index c7fccaebc19..d4d0f5ca99c 100644
--- a/src/dispatcher/payloads/JoinRoomPayload.ts
+++ b/src/dispatcher/payloads/JoinRoomPayload.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/dispatcher/payloads/JoinRoomReadyPayload.ts b/src/dispatcher/payloads/JoinRoomReadyPayload.ts
index bd47e13f4ad..5eaa9e3c8d7 100644
--- a/src/dispatcher/payloads/JoinRoomReadyPayload.ts
+++ b/src/dispatcher/payloads/JoinRoomReadyPayload.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/dispatcher/payloads/OpenAddExistingToSpaceDialogPayload.ts b/src/dispatcher/payloads/OpenAddExistingToSpaceDialogPayload.ts
index 33b3000ed47..ebcddb36c8c 100644
--- a/src/dispatcher/payloads/OpenAddExistingToSpaceDialogPayload.ts
+++ b/src/dispatcher/payloads/OpenAddExistingToSpaceDialogPayload.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/dispatcher/payloads/OpenForwardDialogPayload.ts b/src/dispatcher/payloads/OpenForwardDialogPayload.ts
index d6688575a00..cc1bffa21ec 100644
--- a/src/dispatcher/payloads/OpenForwardDialogPayload.ts
+++ b/src/dispatcher/payloads/OpenForwardDialogPayload.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/dispatcher/payloads/OpenInviteDialogPayload.ts b/src/dispatcher/payloads/OpenInviteDialogPayload.ts
index c8a3522f16a..1d275078217 100644
--- a/src/dispatcher/payloads/OpenInviteDialogPayload.ts
+++ b/src/dispatcher/payloads/OpenInviteDialogPayload.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/dispatcher/payloads/OpenReportEventDialogPayload.ts b/src/dispatcher/payloads/OpenReportEventDialogPayload.ts
index 238adeaeb52..a4b355e9849 100644
--- a/src/dispatcher/payloads/OpenReportEventDialogPayload.ts
+++ b/src/dispatcher/payloads/OpenReportEventDialogPayload.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/dispatcher/payloads/OpenSpacePreferencesPayload.ts b/src/dispatcher/payloads/OpenSpacePreferencesPayload.ts
index 5bc1abb5577..ea068054db2 100644
--- a/src/dispatcher/payloads/OpenSpacePreferencesPayload.ts
+++ b/src/dispatcher/payloads/OpenSpacePreferencesPayload.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/dispatcher/payloads/OpenSpaceSettingsPayload.ts b/src/dispatcher/payloads/OpenSpaceSettingsPayload.ts
index b7691d44f8f..9a1feae34d8 100644
--- a/src/dispatcher/payloads/OpenSpaceSettingsPayload.ts
+++ b/src/dispatcher/payloads/OpenSpaceSettingsPayload.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/dispatcher/payloads/OpenSpotlightPayload.ts b/src/dispatcher/payloads/OpenSpotlightPayload.ts
index bad5ab0f7d2..ec2a630d073 100644
--- a/src/dispatcher/payloads/OpenSpotlightPayload.ts
+++ b/src/dispatcher/payloads/OpenSpotlightPayload.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/dispatcher/payloads/OpenToTabPayload.ts b/src/dispatcher/payloads/OpenToTabPayload.ts
index dfe10f65a5f..872ae626656 100644
--- a/src/dispatcher/payloads/OpenToTabPayload.ts
+++ b/src/dispatcher/payloads/OpenToTabPayload.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/dispatcher/payloads/OverwriteLoginPayload.ts b/src/dispatcher/payloads/OverwriteLoginPayload.ts
index 6ba5d33ecf8..dd53b0b7f9b 100644
--- a/src/dispatcher/payloads/OverwriteLoginPayload.ts
+++ b/src/dispatcher/payloads/OverwriteLoginPayload.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/dispatcher/payloads/PlatformSetPayload.ts b/src/dispatcher/payloads/PlatformSetPayload.ts
index 9b844b6d190..69dc79121c1 100644
--- a/src/dispatcher/payloads/PlatformSetPayload.ts
+++ b/src/dispatcher/payloads/PlatformSetPayload.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/dispatcher/payloads/RecheckThemePayload.ts b/src/dispatcher/payloads/RecheckThemePayload.ts
index 9281a56eb6a..87419465ae1 100644
--- a/src/dispatcher/payloads/RecheckThemePayload.ts
+++ b/src/dispatcher/payloads/RecheckThemePayload.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/dispatcher/payloads/SettingUpdatedPayload.ts b/src/dispatcher/payloads/SettingUpdatedPayload.ts
index 17cad170420..16c8d505909 100644
--- a/src/dispatcher/payloads/SettingUpdatedPayload.ts
+++ b/src/dispatcher/payloads/SettingUpdatedPayload.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/dispatcher/payloads/ShowThreadPayload.ts b/src/dispatcher/payloads/ShowThreadPayload.ts
index 5dbc575e3c4..700758af94b 100644
--- a/src/dispatcher/payloads/ShowThreadPayload.ts
+++ b/src/dispatcher/payloads/ShowThreadPayload.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/dispatcher/payloads/SubmitAskToJoinPayload.ts b/src/dispatcher/payloads/SubmitAskToJoinPayload.ts
index ec1414c22a1..40334fab8d8 100644
--- a/src/dispatcher/payloads/SubmitAskToJoinPayload.ts
+++ b/src/dispatcher/payloads/SubmitAskToJoinPayload.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 Nordeck IT + Consulting GmbH
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/dispatcher/payloads/SwitchSpacePayload.ts b/src/dispatcher/payloads/SwitchSpacePayload.ts
index 63677af658c..7ad22a7b2d0 100644
--- a/src/dispatcher/payloads/SwitchSpacePayload.ts
+++ b/src/dispatcher/payloads/SwitchSpacePayload.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/dispatcher/payloads/ThreadPayload.ts b/src/dispatcher/payloads/ThreadPayload.ts
index c09519e2e7c..2f21576c334 100644
--- a/src/dispatcher/payloads/ThreadPayload.ts
+++ b/src/dispatcher/payloads/ThreadPayload.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/dispatcher/payloads/UpdateFontSizeDeltaPayload.ts b/src/dispatcher/payloads/UpdateFontSizeDeltaPayload.ts
index b4ef6823a57..40495615b52 100644
--- a/src/dispatcher/payloads/UpdateFontSizeDeltaPayload.ts
+++ b/src/dispatcher/payloads/UpdateFontSizeDeltaPayload.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/dispatcher/payloads/UpdateSystemFontPayload.ts b/src/dispatcher/payloads/UpdateSystemFontPayload.ts
index 0061f20e2c1..91951244a9f 100644
--- a/src/dispatcher/payloads/UpdateSystemFontPayload.ts
+++ b/src/dispatcher/payloads/UpdateSystemFontPayload.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/dispatcher/payloads/UploadPayload.ts b/src/dispatcher/payloads/UploadPayload.ts
index afc4ca6c24e..6d26a4dd2be 100644
--- a/src/dispatcher/payloads/UploadPayload.ts
+++ b/src/dispatcher/payloads/UploadPayload.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/dispatcher/payloads/ViewHomePagePayload.ts b/src/dispatcher/payloads/ViewHomePagePayload.ts
index 923635e3a8d..8743569bdf6 100644
--- a/src/dispatcher/payloads/ViewHomePagePayload.ts
+++ b/src/dispatcher/payloads/ViewHomePagePayload.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/dispatcher/payloads/ViewRoomDeltaPayload.ts b/src/dispatcher/payloads/ViewRoomDeltaPayload.ts
index e28f26f2e11..fefe5ec5446 100644
--- a/src/dispatcher/payloads/ViewRoomDeltaPayload.ts
+++ b/src/dispatcher/payloads/ViewRoomDeltaPayload.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/dispatcher/payloads/ViewRoomErrorPayload.ts b/src/dispatcher/payloads/ViewRoomErrorPayload.ts
index 4657a3581ed..fd85b9af09b 100644
--- a/src/dispatcher/payloads/ViewRoomErrorPayload.ts
+++ b/src/dispatcher/payloads/ViewRoomErrorPayload.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/dispatcher/payloads/ViewRoomPayload.ts b/src/dispatcher/payloads/ViewRoomPayload.ts
index 549e8d2c97a..95affe573e6 100644
--- a/src/dispatcher/payloads/ViewRoomPayload.ts
+++ b/src/dispatcher/payloads/ViewRoomPayload.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/dispatcher/payloads/ViewStartChatOrReusePayload.ts b/src/dispatcher/payloads/ViewStartChatOrReusePayload.ts
index 619d96c67ae..0c988d917a7 100644
--- a/src/dispatcher/payloads/ViewStartChatOrReusePayload.ts
+++ b/src/dispatcher/payloads/ViewStartChatOrReusePayload.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/dispatcher/payloads/ViewUserPayload.ts b/src/dispatcher/payloads/ViewUserPayload.ts
index 405820b8c81..497ebf5671e 100644
--- a/src/dispatcher/payloads/ViewUserPayload.ts
+++ b/src/dispatcher/payloads/ViewUserPayload.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/editor/autocomplete.ts b/src/editor/autocomplete.ts
index 542a2bbea51..ff1e89b1f16 100644
--- a/src/editor/autocomplete.ts
+++ b/src/editor/autocomplete.ts
@@ -2,7 +2,7 @@
 Copyright 2019-2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/editor/caret.ts b/src/editor/caret.ts
index 316c3a052fd..7db2c59b770 100644
--- a/src/editor/caret.ts
+++ b/src/editor/caret.ts
@@ -2,7 +2,7 @@
 Copyright 2019-2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/editor/commands.tsx b/src/editor/commands.tsx
index 2930efe86fe..cb38f88d0de 100644
--- a/src/editor/commands.tsx
+++ b/src/editor/commands.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/editor/deserialize.ts b/src/editor/deserialize.ts
index 91afe4bd340..77ca729febd 100644
--- a/src/editor/deserialize.ts
+++ b/src/editor/deserialize.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
 Copyright 2019 New Vector Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/editor/diff.ts b/src/editor/diff.ts
index 90429018f8d..dfc654996e6 100644
--- a/src/editor/diff.ts
+++ b/src/editor/diff.ts
@@ -2,7 +2,7 @@
 Copyright 2019-2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/editor/dom.ts b/src/editor/dom.ts
index bb8372a0976..b0fd9b47e9c 100644
--- a/src/editor/dom.ts
+++ b/src/editor/dom.ts
@@ -2,7 +2,7 @@
 Copyright 2019-2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/editor/history.ts b/src/editor/history.ts
index 2485b3ceee3..ca5a39bb77d 100644
--- a/src/editor/history.ts
+++ b/src/editor/history.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/editor/model.ts b/src/editor/model.ts
index efe294cd214..c583c93972f 100644
--- a/src/editor/model.ts
+++ b/src/editor/model.ts
@@ -2,7 +2,7 @@
 Copyright 2019-2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/editor/offset.ts b/src/editor/offset.ts
index 7216dac2953..143fcdd0f05 100644
--- a/src/editor/offset.ts
+++ b/src/editor/offset.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/editor/operations.ts b/src/editor/operations.ts
index 3a2b7d8fb36..6ee663968d4 100644
--- a/src/editor/operations.ts
+++ b/src/editor/operations.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/editor/parts.ts b/src/editor/parts.ts
index bfdc3d29fb2..907758e39ad 100644
--- a/src/editor/parts.ts
+++ b/src/editor/parts.ts
@@ -2,7 +2,7 @@
 Copyright 2019-2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/editor/position.ts b/src/editor/position.ts
index 439b991887b..2b728b22b4e 100644
--- a/src/editor/position.ts
+++ b/src/editor/position.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/editor/range.ts b/src/editor/range.ts
index c3ec67e674d..6441e92d049 100644
--- a/src/editor/range.ts
+++ b/src/editor/range.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/editor/render.ts b/src/editor/render.ts
index 22ad40beb57..4ac2fc54b31 100644
--- a/src/editor/render.ts
+++ b/src/editor/render.ts
@@ -2,7 +2,7 @@
 Copyright 2019-2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/editor/serialize.ts b/src/editor/serialize.ts
index 36e2b97b094..8b05063b4ec 100644
--- a/src/editor/serialize.ts
+++ b/src/editor/serialize.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
 Copyright 2019 New Vector Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/effects/ICanvasEffect.ts b/src/effects/ICanvasEffect.ts
index ef36b862bf4..6fe8be9dc0f 100644
--- a/src/effects/ICanvasEffect.ts
+++ b/src/effects/ICanvasEffect.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2020 Nurjin Jafar
 Copyright 2020 Nordeck IT + Consulting GmbH.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/src/effects/confetti/index.ts b/src/effects/confetti/index.ts
index 28f37a53203..4c9046f8df0 100644
--- a/src/effects/confetti/index.ts
+++ b/src/effects/confetti/index.ts
@@ -4,7 +4,7 @@ Copyright 2023 The Matrix.org Foundation C.I.C.
 Copyright 2020 Nurjin Jafar
 Copyright 2020 Nordeck IT + Consulting GmbH.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
  */
 import ICanvasEffect from "../ICanvasEffect";
diff --git a/src/effects/effect.ts b/src/effects/effect.ts
index 2f1ad651b80..6a8ae5d8ba5 100644
--- a/src/effects/effect.ts
+++ b/src/effects/effect.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2020 Nurjin Jafar
 Copyright 2020 Nordeck IT + Consulting GmbH.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/src/effects/fireworks/index.ts b/src/effects/fireworks/index.ts
index 00b77582865..13f6e6408b4 100644
--- a/src/effects/fireworks/index.ts
+++ b/src/effects/fireworks/index.ts
@@ -4,7 +4,7 @@ Copyright 2023 The Matrix.org Foundation C.I.C.
 Copyright 2020 Nurjin Jafar
 Copyright 2020 Nordeck IT + Consulting GmbH.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/src/effects/hearts/index.ts b/src/effects/hearts/index.ts
index 608ceaa783b..00082049ebf 100644
--- a/src/effects/hearts/index.ts
+++ b/src/effects/hearts/index.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2021-2023 The Matrix.org Foundation C.I.C.
 Copyright 2022 Arseny Uskov
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
  */
 import ICanvasEffect from "../ICanvasEffect";
diff --git a/src/effects/index.ts b/src/effects/index.ts
index 42f8aea7855..1ed7d2c3a3d 100644
--- a/src/effects/index.ts
+++ b/src/effects/index.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2020 Nurjin Jafar
 Copyright 2020 Nordeck IT + Consulting GmbH.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
  */
 import { _t, _td } from "../languageHandler";
diff --git a/src/effects/rainfall/index.ts b/src/effects/rainfall/index.ts
index 8fe3ea54ebd..9fac36d6158 100644
--- a/src/effects/rainfall/index.ts
+++ b/src/effects/rainfall/index.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2020-2023 The Matrix.org Foundation C.I.C.
 Copyright 2021 Josias Allestad
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
  */
 import ICanvasEffect from "../ICanvasEffect";
diff --git a/src/effects/snowfall/index.ts b/src/effects/snowfall/index.ts
index b25aebf598c..bfc690d1a40 100644
--- a/src/effects/snowfall/index.ts
+++ b/src/effects/snowfall/index.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020-2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
  */
 import ICanvasEffect from "../ICanvasEffect";
diff --git a/src/effects/spaceinvaders/index.ts b/src/effects/spaceinvaders/index.ts
index ca90c921e4c..49aeb26e8d6 100644
--- a/src/effects/spaceinvaders/index.ts
+++ b/src/effects/spaceinvaders/index.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021-2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
  */
 import ICanvasEffect from "../ICanvasEffect";
diff --git a/src/effects/utils.ts b/src/effects/utils.ts
index 62d3046fde1..1479b6f5cd5 100644
--- a/src/effects/utils.ts
+++ b/src/effects/utils.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2020 Nurjin Jafar
 Copyright 2020 Nordeck IT + Consulting GmbH.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/src/email.ts b/src/email.ts
index dfdd3250026..ca606a0dc7f 100644
--- a/src/email.ts
+++ b/src/email.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 Copyright 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/emojipicker/recent.ts b/src/emojipicker/recent.ts
index f95e440cc7c..05c1321716b 100644
--- a/src/emojipicker/recent.ts
+++ b/src/emojipicker/recent.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 Copyright 2019 Tulir Asokan <tulir@maunium.net>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -17,7 +17,7 @@ interface ILegacyFormat {
 }
 
 // New format tries to be more space efficient for synchronization. Ordered by Date descending.
-type Format = [string, number][]; // [emoji, count]
+export type RecentEmojiData = [emoji: string, count: number][];
 
 const SETTING_NAME = "recent_emoji";
 
@@ -33,7 +33,7 @@ function migrate(): void {
     SettingsStore.setValue(SETTING_NAME, null, SettingLevel.ACCOUNT, newFormat.slice(0, STORAGE_LIMIT));
 }
 
-function getRecentEmoji(): Format {
+function getRecentEmoji(): RecentEmojiData {
     return SettingsStore.getValue(SETTING_NAME) || [];
 }
 
diff --git a/src/events/EventTileFactory.tsx b/src/events/EventTileFactory.tsx
index ec1651872af..3079e45abf2 100644
--- a/src/events/EventTileFactory.tsx
+++ b/src/events/EventTileFactory.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/events/RelationsHelper.ts b/src/events/RelationsHelper.ts
index 79b4ee77702..e063395c9a6 100644
--- a/src/events/RelationsHelper.ts
+++ b/src/events/RelationsHelper.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/events/forward/getForwardableEvent.ts b/src/events/forward/getForwardableEvent.ts
index 2d37ebf6e97..151da1e8af2 100644
--- a/src/events/forward/getForwardableEvent.ts
+++ b/src/events/forward/getForwardableEvent.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/events/index.ts b/src/events/index.ts
index 7e1651927df..2fbbc1c600c 100644
--- a/src/events/index.ts
+++ b/src/events/index.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/events/location/getShareableLocationEvent.ts b/src/events/location/getShareableLocationEvent.ts
index ef57464935d..e5c9a0f3a11 100644
--- a/src/events/location/getShareableLocationEvent.ts
+++ b/src/events/location/getShareableLocationEvent.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/favicon.ts b/src/favicon.ts
index 112bfca7bf6..e109c734602 100644
--- a/src/favicon.ts
+++ b/src/favicon.ts
@@ -1,7 +1,7 @@
 /*
 Copyright 2020-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/hooks/room/useGuestAccessInformation.ts b/src/hooks/room/useGuestAccessInformation.ts
index 6f53e0d554f..bf49d434ef3 100644
--- a/src/hooks/room/useGuestAccessInformation.ts
+++ b/src/hooks/room/useGuestAccessInformation.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/hooks/room/useRoomCall.tsx b/src/hooks/room/useRoomCall.tsx
index e1db9f92489..74a518b2170 100644
--- a/src/hooks/room/useRoomCall.tsx
+++ b/src/hooks/room/useRoomCall.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/hooks/room/useRoomMemberProfile.ts b/src/hooks/room/useRoomMemberProfile.ts
index b8bb44c50de..123e6f09917 100644
--- a/src/hooks/room/useRoomMemberProfile.ts
+++ b/src/hooks/room/useRoomMemberProfile.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/hooks/room/useRoomThreadNotifications.ts b/src/hooks/room/useRoomThreadNotifications.ts
index 356af140fb2..2740a016f76 100644
--- a/src/hooks/room/useRoomThreadNotifications.ts
+++ b/src/hooks/room/useRoomThreadNotifications.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/hooks/room/useTopic.ts b/src/hooks/room/useTopic.ts
index e9d98da972f..3f8de87e39a 100644
--- a/src/hooks/room/useTopic.ts
+++ b/src/hooks/room/useTopic.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/hooks/spotlight/useDebouncedCallback.ts b/src/hooks/spotlight/useDebouncedCallback.ts
index dbb6a3d2098..26edb3c68c8 100644
--- a/src/hooks/spotlight/useDebouncedCallback.ts
+++ b/src/hooks/spotlight/useDebouncedCallback.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/hooks/spotlight/useRecentSearches.ts b/src/hooks/spotlight/useRecentSearches.ts
index 1ce092a45de..7f7ec89c194 100644
--- a/src/hooks/spotlight/useRecentSearches.ts
+++ b/src/hooks/spotlight/useRecentSearches.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -17,7 +17,7 @@ import { filterBoolean } from "../../utils/arrays";
 export const useRecentSearches = (): [Room[], () => void] => {
     const [rooms, setRooms] = useState(() => {
         const cli = MatrixClientPeg.safeGet();
-        const recents = SettingsStore.getValue<string[]>("SpotlightSearch.recentSearches", null);
+        const recents = SettingsStore.getValue("SpotlightSearch.recentSearches", null);
         return filterBoolean(recents.map((r) => cli.getRoom(r)));
     });
 
diff --git a/src/hooks/useAccountData.ts b/src/hooks/useAccountData.ts
index 0f55969e29a..7cbc77d525f 100644
--- a/src/hooks/useAccountData.ts
+++ b/src/hooks/useAccountData.ts
@@ -2,19 +2,19 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 import { useCallback, useState } from "react";
-import { ClientEvent, MatrixClient, MatrixEvent } from "matrix-js-sdk/src/matrix";
+import { AccountDataEvents, ClientEvent, MatrixClient, MatrixEvent } from "matrix-js-sdk/src/matrix";
 
 import { useTypedEventEmitter } from "./useEventEmitter";
 
 const tryGetContent = <T extends {}>(ev?: MatrixEvent): T | undefined => ev?.getContent<T>();
 
 // Hook to simplify listening to Matrix account data
-export const useAccountData = <T extends {}>(cli: MatrixClient, eventType: string): T => {
+export const useAccountData = <T extends {}>(cli: MatrixClient, eventType: keyof AccountDataEvents): T => {
     const [value, setValue] = useState<T | undefined>(() => tryGetContent<T>(cli.getAccountData(eventType)));
 
     const handler = useCallback(
diff --git a/src/hooks/useAnimation.ts b/src/hooks/useAnimation.ts
index a02bed70832..f5da36123e9 100644
--- a/src/hooks/useAnimation.ts
+++ b/src/hooks/useAnimation.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/hooks/useAsyncMemo.ts b/src/hooks/useAsyncMemo.ts
index ee3eb7bf6e0..49925d0c747 100644
--- a/src/hooks/useAsyncMemo.ts
+++ b/src/hooks/useAsyncMemo.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/hooks/useAsyncRefreshMemo.ts b/src/hooks/useAsyncRefreshMemo.ts
index 122b7cdb20d..646217bb63a 100644
--- a/src/hooks/useAsyncRefreshMemo.ts
+++ b/src/hooks/useAsyncRefreshMemo.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/hooks/useCall.ts b/src/hooks/useCall.ts
index 5a913f84ad9..63f5cd87ada 100644
--- a/src/hooks/useCall.ts
+++ b/src/hooks/useCall.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/hooks/useDispatcher.ts b/src/hooks/useDispatcher.ts
index b9b22c41377..2072e318240 100644
--- a/src/hooks/useDispatcher.ts
+++ b/src/hooks/useDispatcher.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/hooks/useEncryptionStatus.ts b/src/hooks/useEncryptionStatus.ts
index ed8cceb9f81..32238aa4421 100644
--- a/src/hooks/useEncryptionStatus.ts
+++ b/src/hooks/useEncryptionStatus.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/hooks/useEventEmitter.ts b/src/hooks/useEventEmitter.ts
index e3020384e91..b7c35081cd5 100644
--- a/src/hooks/useEventEmitter.ts
+++ b/src/hooks/useEventEmitter.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/hooks/useFocus.ts b/src/hooks/useFocus.ts
index b03ed479990..cbbea28d07b 100644
--- a/src/hooks/useFocus.ts
+++ b/src/hooks/useFocus.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/hooks/useGlobalNotificationState.ts b/src/hooks/useGlobalNotificationState.ts
index 755ffbf06db..fd2f0b70637 100644
--- a/src/hooks/useGlobalNotificationState.ts
+++ b/src/hooks/useGlobalNotificationState.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/hooks/useHover.ts b/src/hooks/useHover.ts
index bbba5549dd8..1a8aecd942f 100644
--- a/src/hooks/useHover.ts
+++ b/src/hooks/useHover.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/hooks/useIsEncrypted.ts b/src/hooks/useIsEncrypted.ts
index c9d3ed3bc80..7cdfcc68a13 100644
--- a/src/hooks/useIsEncrypted.ts
+++ b/src/hooks/useIsEncrypted.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/hooks/useIsInitialSyncComplete.ts b/src/hooks/useIsInitialSyncComplete.ts
deleted file mode 100644
index b0131213a7d..00000000000
--- a/src/hooks/useIsInitialSyncComplete.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2022 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
-Please see LICENSE files in the repository root for full details.
-*/
-
-import { ClientEvent } from "matrix-js-sdk/src/matrix";
-
-import { useEventEmitterState } from "./useEventEmitter";
-import { useMatrixClientContext } from "../contexts/MatrixClientContext";
-
-export function useInitialSyncComplete(): boolean {
-    const cli = useMatrixClientContext();
-    return useEventEmitterState(cli, ClientEvent.Sync, () => cli.isInitialSyncComplete());
-}
diff --git a/src/hooks/useIsReleaseAnnouncementOpen.ts b/src/hooks/useIsReleaseAnnouncementOpen.ts
index b4a46568e27..68ab65f97a4 100644
--- a/src/hooks/useIsReleaseAnnouncementOpen.ts
+++ b/src/hooks/useIsReleaseAnnouncementOpen.ts
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2024 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/src/hooks/useLatestResult.ts b/src/hooks/useLatestResult.ts
index 9776103ab33..632a0f7714e 100644
--- a/src/hooks/useLatestResult.ts
+++ b/src/hooks/useLatestResult.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/hooks/useLocalEcho.ts b/src/hooks/useLocalEcho.ts
index bbb978e5d4b..baa967031f7 100644
--- a/src/hooks/useLocalEcho.ts
+++ b/src/hooks/useLocalEcho.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/hooks/useLocalStorageState.ts b/src/hooks/useLocalStorageState.ts
index b926033e475..5efec21035f 100644
--- a/src/hooks/useLocalStorageState.ts
+++ b/src/hooks/useLocalStorageState.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/hooks/useNotificationSettings.tsx b/src/hooks/useNotificationSettings.tsx
index bf4290a0683..3036a8122c2 100644
--- a/src/hooks/useNotificationSettings.tsx
+++ b/src/hooks/useNotificationSettings.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/hooks/usePermalink.ts b/src/hooks/usePermalink.ts
index 18c5ed6b980..f9174654fce 100644
--- a/src/hooks/usePermalink.ts
+++ b/src/hooks/usePermalink.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/hooks/usePermalinkEvent.ts b/src/hooks/usePermalinkEvent.ts
index ff77f15238c..12844d73bb4 100644
--- a/src/hooks/usePermalinkEvent.ts
+++ b/src/hooks/usePermalinkEvent.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/hooks/usePermalinkMember.ts b/src/hooks/usePermalinkMember.ts
index 1fc144c9f67..787062ca3a5 100644
--- a/src/hooks/usePermalinkMember.ts
+++ b/src/hooks/usePermalinkMember.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/hooks/usePermalinkTargetRoom.ts b/src/hooks/usePermalinkTargetRoom.ts
index e5f46cc496a..7a3a40ae521 100644
--- a/src/hooks/usePermalinkTargetRoom.ts
+++ b/src/hooks/usePermalinkTargetRoom.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/hooks/usePinnedEvents.ts b/src/hooks/usePinnedEvents.ts
index a29c65625c5..b065edc83f7 100644
--- a/src/hooks/usePinnedEvents.ts
+++ b/src/hooks/usePinnedEvents.ts
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2024 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
@@ -154,7 +154,7 @@ async function fetchPinnedEvent(room: Room, pinnedEventId: string, cli: MatrixCl
         const senderUserId = event.getSender();
         if (senderUserId && PinningUtils.isUnpinnable(event)) {
             // Inject sender information
-            event.sender = room.getMember(senderUserId);
+            event.setMetadata(room.currentState, false);
             // Also inject any edits we've found
             if (edit) event.makeReplaced(edit);
 
diff --git a/src/hooks/useProfileInfo.ts b/src/hooks/useProfileInfo.ts
index bc57f271603..45500fac692 100644
--- a/src/hooks/useProfileInfo.ts
+++ b/src/hooks/useProfileInfo.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/hooks/usePublicRoomDirectory.ts b/src/hooks/usePublicRoomDirectory.ts
index 339ee9ad6dc..2e8cfb21b62 100644
--- a/src/hooks/usePublicRoomDirectory.ts
+++ b/src/hooks/usePublicRoomDirectory.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -55,7 +55,7 @@ export const usePublicRoomDirectory = (): {
 
     const [updateQuery, updateResult] = useLatestResult<IRoomDirectoryOptions, IPublicRoomsChunkRoom[]>(setPublicRooms);
 
-    const showNsfwPublicRooms = useSettingValue<boolean>("SpotlightSearch.showNsfwPublicRooms");
+    const showNsfwPublicRooms = useSettingValue("SpotlightSearch.showNsfwPublicRooms");
 
     async function initProtocols(): Promise<void> {
         if (!MatrixClientPeg.get()) {
diff --git a/src/hooks/usePushers.ts b/src/hooks/usePushers.ts
index 38c36ebc888..8dc62832913 100644
--- a/src/hooks/usePushers.ts
+++ b/src/hooks/usePushers.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/hooks/useRoomMembers.ts b/src/hooks/useRoomMembers.ts
index 51aa7b46406..7a37d693dfb 100644
--- a/src/hooks/useRoomMembers.ts
+++ b/src/hooks/useRoomMembers.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/hooks/useRoomName.ts b/src/hooks/useRoomName.ts
index b1f25b7ca29..201cc088de6 100644
--- a/src/hooks/useRoomName.ts
+++ b/src/hooks/useRoomName.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/hooks/useRoomNotificationState.ts b/src/hooks/useRoomNotificationState.ts
index 46dd4e5524e..c964501aa9f 100644
--- a/src/hooks/useRoomNotificationState.ts
+++ b/src/hooks/useRoomNotificationState.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/hooks/useRoomState.ts b/src/hooks/useRoomState.ts
index 8c0c5596100..24c4609b12a 100644
--- a/src/hooks/useRoomState.ts
+++ b/src/hooks/useRoomState.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/hooks/useSettings.ts b/src/hooks/useSettings.ts
index 169fccb7c0e..7fbf5231fa1 100644
--- a/src/hooks/useSettings.ts
+++ b/src/hooks/useSettings.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -10,14 +10,39 @@ import { useEffect, useState } from "react";
 
 import SettingsStore from "../settings/SettingsStore";
 import { SettingLevel } from "../settings/SettingLevel";
+import { FeatureSettingKey, SettingKey, Settings } from "../settings/Settings.tsx";
 
 // Hook to fetch the value of a setting and dynamically update when it changes
-export const useSettingValue = <T>(settingName: string, roomId: string | null = null, excludeDefault = false): T => {
-    const [value, setValue] = useState(SettingsStore.getValue<T>(settingName, roomId, excludeDefault));
+export function useSettingValue<S extends SettingKey>(
+    settingName: S,
+    roomId: string | null,
+    excludeDefault: true,
+): Settings[S]["default"] | undefined;
+export function useSettingValue<S extends SettingKey>(
+    settingName: S,
+    roomId?: string | null,
+    excludeDefault?: false,
+): Settings[S]["default"];
+export function useSettingValue<S extends SettingKey>(
+    settingName: S,
+    roomId: string | null = null,
+    excludeDefault = false,
+): Settings[S]["default"] | undefined {
+    const [value, setValue] = useState(
+        // XXX: This seems naff but is needed to convince TypeScript that the overload is fine
+        excludeDefault
+            ? SettingsStore.getValue(settingName, roomId, excludeDefault)
+            : SettingsStore.getValue(settingName, roomId, excludeDefault),
+    );
 
     useEffect(() => {
         const ref = SettingsStore.watchSetting(settingName, roomId, () => {
-            setValue(SettingsStore.getValue<T>(settingName, roomId, excludeDefault));
+            setValue(
+                // XXX: This seems naff but is needed to convince TypeScript that the overload is fine
+                excludeDefault
+                    ? SettingsStore.getValue(settingName, roomId, excludeDefault)
+                    : SettingsStore.getValue(settingName, roomId, excludeDefault),
+            );
         });
         // clean-up
         return () => {
@@ -26,7 +51,7 @@ export const useSettingValue = <T>(settingName: string, roomId: string | null =
     }, [settingName, roomId, excludeDefault]);
 
     return value;
-};
+}
 
 /**
  * Hook to fetch the value of a setting at a specific level and dynamically update when it changes
@@ -37,20 +62,18 @@ export const useSettingValue = <T>(settingName: string, roomId: string | null =
  * @param explicit
  * @param excludeDefault
  */
-export const useSettingValueAt = <T>(
+export const useSettingValueAt = <S extends SettingKey>(
     level: SettingLevel,
-    settingName: string,
+    settingName: S,
     roomId: string | null = null,
     explicit = false,
     excludeDefault = false,
-): T => {
-    const [value, setValue] = useState(
-        SettingsStore.getValueAt<T>(level, settingName, roomId, explicit, excludeDefault),
-    );
+): Settings[S]["default"] => {
+    const [value, setValue] = useState(SettingsStore.getValueAt(level, settingName, roomId, explicit, excludeDefault));
 
     useEffect(() => {
         const ref = SettingsStore.watchSetting(settingName, roomId, () => {
-            setValue(SettingsStore.getValueAt<T>(level, settingName, roomId, explicit, excludeDefault));
+            setValue(SettingsStore.getValueAt(level, settingName, roomId, explicit, excludeDefault));
         });
         // clean-up
         return () => {
@@ -62,8 +85,8 @@ export const useSettingValueAt = <T>(
 };
 
 // Hook to fetch whether a feature is enabled and dynamically update when that changes
-export const useFeatureEnabled = (featureName: string, roomId: string | null = null): boolean => {
-    const [enabled, setEnabled] = useState(SettingsStore.getValue<boolean>(featureName, roomId));
+export const useFeatureEnabled = (featureName: FeatureSettingKey, roomId: string | null = null): boolean => {
+    const [enabled, setEnabled] = useState(SettingsStore.getValue(featureName, roomId));
 
     useEffect(() => {
         const ref = SettingsStore.watchSetting(featureName, roomId, () => {
diff --git a/src/hooks/useSlidingSyncRoomSearch.ts b/src/hooks/useSlidingSyncRoomSearch.ts
index bd8529bfd97..079d11d7e7a 100644
--- a/src/hooks/useSlidingSyncRoomSearch.ts
+++ b/src/hooks/useSlidingSyncRoomSearch.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/hooks/useSmoothAnimation.ts b/src/hooks/useSmoothAnimation.ts
index df62a4d3d5e..dd157911b3f 100644
--- a/src/hooks/useSmoothAnimation.ts
+++ b/src/hooks/useSmoothAnimation.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/hooks/useSpaceResults.ts b/src/hooks/useSpaceResults.ts
index 75a0a119a97..3c4698cb667 100644
--- a/src/hooks/useSpaceResults.ts
+++ b/src/hooks/useSpaceResults.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/hooks/useStateArray.ts b/src/hooks/useStateArray.ts
index 3db3f5fe7fe..1b57a29652b 100644
--- a/src/hooks/useStateArray.ts
+++ b/src/hooks/useStateArray.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/hooks/useStateCallback.ts b/src/hooks/useStateCallback.ts
index 661898c9f64..ec46d0151f5 100644
--- a/src/hooks/useStateCallback.ts
+++ b/src/hooks/useStateCallback.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/hooks/useStateToggle.ts b/src/hooks/useStateToggle.ts
index c5f24c5db67..d808d9b133e 100644
--- a/src/hooks/useStateToggle.ts
+++ b/src/hooks/useStateToggle.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/hooks/useTheme.ts b/src/hooks/useTheme.ts
index e459e68011a..31b01dc2e3b 100644
--- a/src/hooks/useTheme.ts
+++ b/src/hooks/useTheme.ts
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2024 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
@@ -16,10 +16,10 @@ export function useTheme(): { theme: string; systemThemeActivated: boolean } {
     // We have to mirror the logic from ThemeWatcher.getEffectiveTheme so we
     // show the right values for things.
 
-    const themeChoice = useSettingValue<string>("theme");
-    const systemThemeExplicit = useSettingValueAt<string>(SettingLevel.DEVICE, "use_system_theme", null, false, true);
-    const themeExplicit = useSettingValueAt<string>(SettingLevel.DEVICE, "theme", null, false, true);
-    const systemThemeActivated = useSettingValue<boolean>("use_system_theme");
+    const themeChoice = useSettingValue("theme");
+    const systemThemeExplicit = useSettingValueAt(SettingLevel.DEVICE, "use_system_theme", null, false, true);
+    const themeExplicit = useSettingValueAt(SettingLevel.DEVICE, "theme", null, false, true);
+    const systemThemeActivated = useSettingValue("use_system_theme");
 
     // If the user has enabled system theme matching, use that.
     if (systemThemeExplicit) {
diff --git a/src/hooks/useThreepids.ts b/src/hooks/useThreepids.ts
index 7e9f2cc52b0..32884bc7cc1 100644
--- a/src/hooks/useThreepids.ts
+++ b/src/hooks/useThreepids.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/hooks/useTimeout.ts b/src/hooks/useTimeout.ts
index c88de82c0f0..64343cbfadb 100644
--- a/src/hooks/useTimeout.ts
+++ b/src/hooks/useTimeout.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/hooks/useTimeoutToggle.ts b/src/hooks/useTimeoutToggle.ts
index 83f1bc333bb..c67af845dbc 100644
--- a/src/hooks/useTimeoutToggle.ts
+++ b/src/hooks/useTimeoutToggle.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/hooks/useTransition.ts b/src/hooks/useTransition.ts
index 853354e1001..e583ba85573 100644
--- a/src/hooks/useTransition.ts
+++ b/src/hooks/useTransition.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/hooks/useUnreadNotifications.ts b/src/hooks/useUnreadNotifications.ts
index 47e4e6b8110..7697524da50 100644
--- a/src/hooks/useUnreadNotifications.ts
+++ b/src/hooks/useUnreadNotifications.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022, 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/hooks/useUserDirectory.ts b/src/hooks/useUserDirectory.ts
index 09b55f21afe..8599b2488ab 100644
--- a/src/hooks/useUserDirectory.ts
+++ b/src/hooks/useUserDirectory.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/hooks/useUserOnboardingContext.ts b/src/hooks/useUserOnboardingContext.ts
deleted file mode 100644
index 8bd93603d44..00000000000
--- a/src/hooks/useUserOnboardingContext.ts
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2022 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
-Please see LICENSE files in the repository root for full details.
-*/
-
-import { logger } from "matrix-js-sdk/src/logger";
-import { ClientEvent, MatrixClient } from "matrix-js-sdk/src/matrix";
-import { useCallback, useEffect, useMemo, useRef, useState } from "react";
-
-import { Notifier, NotifierEvent } from "../Notifier";
-import DMRoomMap from "../utils/DMRoomMap";
-import { useMatrixClientContext } from "../contexts/MatrixClientContext";
-import { useSettingValue } from "./useSettings";
-import { useEventEmitter, useTypedEventEmitter } from "./useEventEmitter";
-
-export interface UserOnboardingContext {
-    hasAvatar: boolean;
-    hasDevices: boolean;
-    hasDmRooms: boolean;
-    showNotificationsPrompt: boolean;
-}
-
-const USER_ONBOARDING_CONTEXT_INTERVAL = 5000;
-
-/**
- * Returns a persistent, non-changing reference to a function
- * This function proxies all its calls to the current value of the given input callback
- *
- * This allows you to use the current value of e.g., a state in a callback that’s used by e.g., a useEventEmitter or
- * similar hook without re-registering the hook when the state changes
- * @param value changing callback
- */
-function useRefOf<T extends any[], R>(value: (...values: T) => R): (...values: T) => R {
-    const ref = useRef(value);
-    ref.current = value;
-    return useCallback((...values: T) => ref.current(...values), []);
-}
-
-function useUserOnboardingContextValue<T>(defaultValue: T, callback: (cli: MatrixClient) => Promise<T>): T {
-    const [value, setValue] = useState<T>(defaultValue);
-    const cli = useMatrixClientContext();
-
-    const handler = useRefOf(callback);
-
-    useEffect(() => {
-        if (value) {
-            return;
-        }
-
-        let handle: number | null = null;
-        let enabled = true;
-        const repeater = async (): Promise<void> => {
-            if (handle !== null) {
-                clearTimeout(handle);
-                handle = null;
-            }
-            setValue(await handler(cli));
-            if (enabled) {
-                handle = window.setTimeout(repeater, USER_ONBOARDING_CONTEXT_INTERVAL);
-            }
-        };
-        repeater().catch((err) => logger.warn("could not update user onboarding context", err));
-        cli.on(ClientEvent.AccountData, repeater);
-        return () => {
-            enabled = false;
-            cli.off(ClientEvent.AccountData, repeater);
-            if (handle !== null) {
-                clearTimeout(handle);
-                handle = null;
-            }
-        };
-    }, [cli, handler, value]);
-    return value;
-}
-
-function useShowNotificationsPrompt(): boolean {
-    const client = useMatrixClientContext();
-
-    const [value, setValue] = useState<boolean>(client.pushRules ? Notifier.shouldShowPrompt() : true);
-
-    const updateValue = useCallback(() => {
-        setValue(client.pushRules ? Notifier.shouldShowPrompt() : true);
-    }, [client]);
-
-    useEventEmitter(Notifier, NotifierEvent.NotificationHiddenChange, () => {
-        updateValue();
-    });
-
-    const setting = useSettingValue("notificationsEnabled");
-    useEffect(() => {
-        updateValue();
-    }, [setting, updateValue]);
-
-    // shouldShowPrompt is dependent on the client having push rules. There isn't an event for the client
-    // fetching its push rules, but we'll know it has them by the time it sync, so we update this on sync.
-    useTypedEventEmitter(client, ClientEvent.Sync, updateValue);
-
-    return value;
-}
-
-export function useUserOnboardingContext(): UserOnboardingContext {
-    const hasAvatar = useUserOnboardingContextValue(false, async (cli) => {
-        const profile = await cli.getProfileInfo(cli.getUserId()!);
-        return Boolean(profile?.avatar_url);
-    });
-    const hasDevices = useUserOnboardingContextValue(false, async (cli) => {
-        const myDevice = cli.getDeviceId();
-        const devices = await cli.getDevices();
-        return Boolean(devices.devices.find((device) => device.device_id !== myDevice));
-    });
-    const hasDmRooms = useUserOnboardingContextValue(false, async () => {
-        const dmRooms = DMRoomMap.shared().getUniqueRoomsWithIndividuals() ?? {};
-        return Boolean(Object.keys(dmRooms).length);
-    });
-    const showNotificationsPrompt = useShowNotificationsPrompt();
-
-    return useMemo(
-        () => ({ hasAvatar, hasDevices, hasDmRooms, showNotificationsPrompt }),
-        [hasAvatar, hasDevices, hasDmRooms, showNotificationsPrompt],
-    );
-}
diff --git a/src/hooks/useUserOnboardingTasks.ts b/src/hooks/useUserOnboardingTasks.ts
deleted file mode 100644
index 2ede7076cbd..00000000000
--- a/src/hooks/useUserOnboardingTasks.ts
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2022 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
-Please see LICENSE files in the repository root for full details.
-*/
-
-import { useMemo } from "react";
-
-import { AppDownloadDialog, showAppDownloadDialogPrompt } from "../components/views/dialogs/AppDownloadDialog";
-import { UserTab } from "../components/views/dialogs/UserTab";
-import { ButtonEvent } from "../components/views/elements/AccessibleButton";
-import { Action } from "../dispatcher/actions";
-import defaultDispatcher from "../dispatcher/dispatcher";
-import { _t } from "../languageHandler";
-import Modal from "../Modal";
-import { Notifier } from "../Notifier";
-import PosthogTrackers from "../PosthogTrackers";
-import SdkConfig from "../SdkConfig";
-import { UseCase } from "../settings/enums/UseCase";
-import { useSettingValue } from "./useSettings";
-import { UserOnboardingContext } from "./useUserOnboardingContext";
-
-interface UserOnboardingTask {
-    id: string;
-    title: string | (() => string);
-    description: string | (() => string);
-    relevant?: UseCase[];
-    action?: {
-        label: string;
-        onClick?: (ev: ButtonEvent) => void;
-        href?: string;
-        hideOnComplete?: boolean;
-    };
-    completed: (ctx: UserOnboardingContext) => boolean;
-    disabled?(): boolean;
-}
-
-export interface UserOnboardingTaskWithResolvedCompletion extends Omit<UserOnboardingTask, "completed"> {
-    completed: boolean;
-}
-
-const onClickStartDm = (ev: ButtonEvent): void => {
-    PosthogTrackers.trackInteraction("WebUserOnboardingTaskSendDm", ev);
-    defaultDispatcher.dispatch({ action: "view_create_chat" });
-};
-
-const tasks: UserOnboardingTask[] = [
-    {
-        id: "create-account",
-        title: _t("auth|create_account_title"),
-        description: _t("onboarding|you_made_it"),
-        completed: () => true,
-    },
-    {
-        id: "find-friends",
-        title: _t("onboarding|find_friends"),
-        description: _t("onboarding|find_friends_description"),
-        completed: (ctx: UserOnboardingContext) => ctx.hasDmRooms,
-        relevant: [UseCase.PersonalMessaging, UseCase.Skip],
-        action: {
-            label: _t("onboarding|find_friends_action"),
-            onClick: onClickStartDm,
-        },
-    },
-    {
-        id: "find-coworkers",
-        title: _t("onboarding|find_coworkers"),
-        description: _t("onboarding|get_stuff_done"),
-        completed: (ctx: UserOnboardingContext) => ctx.hasDmRooms,
-        relevant: [UseCase.WorkMessaging],
-        action: {
-            label: _t("onboarding|find_people"),
-            onClick: onClickStartDm,
-        },
-    },
-    {
-        id: "find-community-members",
-        title: _t("onboarding|find_community_members"),
-        description: _t("onboarding|get_stuff_done"),
-        completed: (ctx: UserOnboardingContext) => ctx.hasDmRooms,
-        relevant: [UseCase.CommunityMessaging],
-        action: {
-            label: _t("onboarding|find_people"),
-            onClick: onClickStartDm,
-        },
-    },
-    {
-        id: "download-apps",
-        title: () =>
-            _t("onboarding|download_app", {
-                brand: SdkConfig.get("brand"),
-            }),
-        description: () =>
-            _t("onboarding|download_app_description", {
-                brand: SdkConfig.get("brand"),
-            }),
-        completed: (ctx: UserOnboardingContext) => ctx.hasDevices,
-        action: {
-            label: _t("onboarding|download_app_action"),
-            onClick: (ev: ButtonEvent) => {
-                PosthogTrackers.trackInteraction("WebUserOnboardingTaskDownloadApps", ev);
-                Modal.createDialog(AppDownloadDialog, {}, "mx_AppDownloadDialog_wrapper", false, true);
-            },
-        },
-        disabled(): boolean {
-            return !showAppDownloadDialogPrompt();
-        },
-    },
-    {
-        id: "setup-profile",
-        title: _t("onboarding|set_up_profile"),
-        description: _t("onboarding|set_up_profile_description"),
-        completed: (ctx: UserOnboardingContext) => ctx.hasAvatar,
-        action: {
-            label: _t("onboarding|set_up_profile_action"),
-            onClick: (ev: ButtonEvent) => {
-                PosthogTrackers.trackInteraction("WebUserOnboardingTaskSetupProfile", ev);
-                defaultDispatcher.dispatch({
-                    action: Action.ViewUserSettings,
-                    initialTabId: UserTab.Account,
-                });
-            },
-        },
-    },
-    {
-        id: "permission-notifications",
-        title: _t("onboarding|enable_notifications"),
-        description: _t("onboarding|enable_notifications_description"),
-        completed: (ctx: UserOnboardingContext) => !ctx.showNotificationsPrompt,
-        action: {
-            label: _t("onboarding|enable_notifications_action"),
-            onClick: (ev: ButtonEvent) => {
-                PosthogTrackers.trackInteraction("WebUserOnboardingTaskEnableNotifications", ev);
-                defaultDispatcher.dispatch({
-                    action: Action.ViewUserSettings,
-                    initialTabId: UserTab.Notifications,
-                });
-                Notifier.setPromptHidden(true);
-            },
-            hideOnComplete: !Notifier.isPossible(),
-        },
-    },
-];
-
-export function useUserOnboardingTasks(context: UserOnboardingContext): UserOnboardingTaskWithResolvedCompletion[] {
-    const useCase = useSettingValue<UseCase | null>("FTUE.useCaseSelection") ?? UseCase.Skip;
-
-    return useMemo<UserOnboardingTaskWithResolvedCompletion[]>(() => {
-        return tasks
-            .filter((task) => {
-                if (task.disabled?.()) return false;
-                return !task.relevant || task.relevant.includes(useCase);
-            })
-            .map((task) => ({
-                ...task,
-                completed: task.completed(context),
-            }));
-    }, [context, useCase]);
-}
diff --git a/src/hooks/useUserTimezone.ts b/src/hooks/useUserTimezone.ts
index 686679bb90f..c6c98483ddf 100644
--- a/src/hooks/useUserTimezone.ts
+++ b/src/hooks/useUserTimezone.ts
@@ -1,17 +1,8 @@
 /*
-Copyright 2024 New Vector Ltd
+Copyright 2024 New Vector Ltd.
 
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+Please see LICENSE files in the repository root for full details.
 */
 import { useEffect, useState } from "react";
 import { MatrixClient, MatrixError } from "matrix-js-sdk/src/matrix";
diff --git a/src/hooks/useWindowWidth.ts b/src/hooks/useWindowWidth.ts
index 0b952ffce84..ddf64bbd9b4 100644
--- a/src/hooks/useWindowWidth.ts
+++ b/src/hooks/useWindowWidth.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/i18n/strings/cs.json b/src/i18n/strings/cs.json
index df8a243c730..0acb4727af0 100644
--- a/src/i18n/strings/cs.json
+++ b/src/i18n/strings/cs.json
@@ -235,7 +235,6 @@
         "oidc": {
             "error_title": "Nemohli jsme vás přihlásit",
             "generic_auth_error": "Během autentizace se něco pokazilo. Přejděte na přihlašovací stránku a zkuste to znovu.",
-            "logout_redirect_warning": "Budete přesměrováni na poskytovatele ověřování vašeho serveru, kde dokončíte odhlášení.",
             "missing_or_invalid_stored_state": "Požádali jsme prohlížeč, aby si zapamatoval, který domovský server používáte k přihlášení, ale váš prohlížeč to bohužel zapomněl. Přejděte na přihlašovací stránku a zkuste to znovu."
         },
         "password_field_keep_going_prompt": "Pokračujte…",
@@ -419,7 +418,6 @@
             "other": "a %(count)s další...",
             "one": "a někdo další..."
         },
-        "android": "Android",
         "appearance": "Vzhled",
         "application": "Aplikace",
         "are_you_sure": "Opravdu?",
@@ -458,7 +456,6 @@
         "identity_server": "Server identit",
         "image": "Obrázek",
         "integration_manager": "Správce integrací",
-        "ios": "iOS",
         "joined": "Připojeno",
         "labs": "Experimentální funkce",
         "legal": "Právní informace",
@@ -548,8 +545,7 @@
         "video": "Video",
         "video_room": "Video místnost",
         "view_message": "Zobrazit zprávu",
-        "warning": "Upozornění",
-        "welcome": "Vítejte"
+        "warning": "Upozornění"
     },
     "composer": {
         "autocomplete": {
@@ -1391,8 +1387,6 @@
         "notification_settings_beta_caption": "Představujeme jednodušší způsob, jak změnit nastavení oznámení. Přizpůsobte svůj %(brand)s přesně tak, jak se vám líbí.",
         "notification_settings_beta_title": "Nastavení oznámení",
         "notifications": "Zapnout panel oznámení v záhlaví místnosti",
-        "oidc_native_flow": "Nativní autentizace OIDC",
-        "oidc_native_flow_description": "⚠ VAROVÁNÍ: Experimentální. Použijte nativní ověřování OIDC, pokud je serverem podporováno.",
         "render_reaction_images": "Vykreslování vlastních obrázků v reakcích",
         "render_reaction_images_description": "Někdy se označují jako \"vlastní emoji\".",
         "report_to_moderators": "Nahlásit moderátorům",
@@ -1511,7 +1505,6 @@
     "member_list": {
         "filter_placeholder": "Najít člena místnosti",
         "invite_button_no_perms_tooltip": "Nemáte oprávnění zvát uživatele",
-        "invited_list_heading": "Pozvaní",
         "power_label": "%(userName)s (oprávnění %(powerLevelNumber)s)"
     },
     "member_list_back_action_label": "Členové místnosti",
@@ -1558,61 +1551,15 @@
         "m.key.verification.request": "%(name)s žádá o ověření"
     },
     "onboarding": {
-        "apple_trademarks": "App Store® a logo Apple® jsou ochranné známky společnosti Apple Inc.",
-        "community_messaging_action": "Najděte své lidi",
-        "community_messaging_description": "Zachovejte si vlastnictví a kontrolu nad komunitní diskusí.\nPodpora milionů uživatelů s účinným moderováním a interoperabilitou.",
-        "community_messaging_title": "Vlastnictví komunity",
-        "complete_these": "Dokončete následující, abyste z %(brand)s získali co nejvíce",
         "create_room": "Vytvořit skupinový chat",
-        "download_app": "Stáhnout %(brand)s",
-        "download_app_action": "Stáhnout aplikace",
-        "download_app_description": "Vezměte si %(brand)s s sebou a nic vám neunikne",
-        "download_app_store": "Stáhnout v App Store",
-        "download_brand": "Stáhnout %(brand)s",
-        "download_brand_desktop": "Stáhnout %(brand)s Desktop",
-        "download_f_droid": "Získat na F-Droid",
-        "download_google_play": "Získat na Google Play",
-        "enable_notifications": "Zapnout oznámení",
-        "enable_notifications_action": "Povolit oznámení",
-        "enable_notifications_description": "Nepropásněte odpověď nebo důležitou zprávu",
         "explore_rooms": "Prozkoumat veřejné místnosti",
-        "find_community_members": "Najděte a pozvěte členy vaší komunity",
-        "find_coworkers": "Najít a pozvat své spolupracovníky",
-        "find_friends": "Najděte a pozvěte své přátele",
-        "find_friends_action": "Najít přátele",
-        "find_friends_description": "Kvůli tomu jste tady, tak se do toho pusťte",
-        "find_people": "Najít lidi",
-        "free_e2ee_messaging_unlimited_voip": "Díky bezplatným šifrovaným zprávám a neomezeným hlasovým a videohovorům je služba %(brand)s skvělým způsobem, jak zůstat v kontaktu.",
-        "get_stuff_done": "Vyřešte věci tím, že najdete své týmové kolegy",
-        "google_trademarks": "Google Play a logo Google Play jsou ochranné známky společnosti Google LLC.",
         "has_avatar_label": "Skvělé, to pomůže lidem zjistit, že jste to vy",
         "intro_byline": "Vlastněte svoje konverzace.",
         "intro_welcome": "Vítá vás %(appName)s",
         "no_avatar_label": "Přidejte fotku, aby lidé věděli, že jste to vy.",
-        "only_n_steps_to_go": {
-            "one": "Zbývá už jen %(count)s krok",
-            "other": "Zbývá už jen %(count)s kroků"
-        },
-        "personal_messaging_action": "Začněte svůj první chat",
-        "personal_messaging_title": "Zabezpečené zasílání zpráv pro přátele a rodinu",
-        "qr_or_app_links": "%(qrCode)s nebo %(appLinks)s",
         "send_dm": "Poslat přímou zprávu",
-        "set_up_profile": "Nastavte si svůj profil",
-        "set_up_profile_action": "Váš profil",
-        "set_up_profile_description": "Ujistěte se, že lidé poznají, že jste to opravdu vy",
-        "use_case_community_messaging": "Členové online komunity",
-        "use_case_heading1": "Jste přihlášeni",
-        "use_case_heading2": "S kým si budete povídat nejčastěji?",
-        "use_case_heading3": "Pomůžeme vám připojit se.",
-        "use_case_personal_messaging": "Přátelé a rodina",
-        "use_case_work_messaging": "Spolupracovníci a týmy",
         "welcome_detail": "Nyní vám pomůžeme začít",
-        "welcome_to_brand": "Vítejte v aplikaci %(brand)s",
-        "welcome_user": "Vítejte %(name)s",
-        "work_messaging_action": "Najděte své spolupracovníky",
-        "work_messaging_title": "Zabezpečené zasílání pracovních zpráv",
-        "you_did_it": "Dokázali jste to!",
-        "you_made_it": "Zvládli jste to!"
+        "welcome_user": "Vítejte %(name)s"
     },
     "pill": {
         "permalink_other_room": "Zpráva v %(room)s",
@@ -1664,7 +1611,6 @@
         "custom_level": "Vlastní úroveň",
         "default": "Výchozí",
         "label": "Úroveň oprávnění",
-        "mod": "Moderátor",
         "moderator": "Moderátor",
         "restricted": "Omezené"
     },
@@ -2535,7 +2481,6 @@
             "room_directory_heading": "Adresář místností",
             "room_list_heading": "Seznam místností",
             "show_avatars_pills": "Zobrazovat avatary ve zmínkách o uživatelích, místnostech a událostech",
-            "show_checklist_shortcuts": "Zobrazit zástupce na uvítací kontrolní seznam nad seznamem místností",
             "show_polls_button": "Zobrazit tlačítko hlasování",
             "surround_text": "Ohraničit označený text při psaní speciálních znaků",
             "time_heading": "Zobrazování času"
@@ -2900,7 +2845,6 @@
         "invite": "Pozvat lidi",
         "invite_description": "Pozvěte e-mailem nebo uživatelským jménem",
         "invite_link": "Sdílet odkaz na pozvánku",
-        "invite_this_space": "Pozvat do tohoto prostoru",
         "joining_space": "Připojování",
         "landing_welcome": "Vítejte v <name/>",
         "leave_dialog_action": "Opusit prostor",
diff --git a/src/i18n/strings/de_DE.json b/src/i18n/strings/de_DE.json
index 5a4a6043fbc..ef68cf7eab6 100644
--- a/src/i18n/strings/de_DE.json
+++ b/src/i18n/strings/de_DE.json
@@ -129,7 +129,7 @@
         "try_again": "Erneut versuchen",
         "unban": "Verbannung aufheben",
         "unignore": "Freigeben",
-        "unpin": "Nicht mehr anheften",
+        "unpin": "Loslösen",
         "unsubscribe": "Deabonnieren",
         "update": "Aktualisieren",
         "upgrade": "Aktualisieren",
@@ -238,7 +238,6 @@
         "oidc": {
             "error_title": "Wir konnten dich nicht anmelden",
             "generic_auth_error": "Etwas ist während der Authentifizierung schiefgelaufen. Geh zurück zur Anmeldeseite und probiere es erneut.",
-            "logout_redirect_warning": "Sie werden zum Server Authentifizierungsanbieter weitergeleitet, um die Abmeldung abzuschließen.",
             "missing_or_invalid_stored_state": "Wir haben deinen Browser gebeten, sich zu merken, bei welchem Heim-Server du dich anmeldest, aber dein Browser hat dies leider vergessen. Gehe zur Anmeldeseite und versuche es erneut."
         },
         "password_field_keep_going_prompt": "Fortfahren …",
@@ -452,7 +451,6 @@
             "other": "und %(count)s weitere …",
             "one": "und ein weiterer …"
         },
-        "android": "Android",
         "appearance": "Erscheinungsbild",
         "application": "Anwendung",
         "are_you_sure": "Bist du sicher?",
@@ -492,7 +490,6 @@
         "identity_server": "Identitäts-Server",
         "image": "Bild",
         "integration_manager": "Integrationsverwaltung",
-        "ios": "iOS",
         "joined": "Beigetreten",
         "labs": "Labor",
         "legal": "Rechtliches",
@@ -567,7 +564,7 @@
         "system_alerts": "Systembenachrichtigung",
         "theme": "Design",
         "thread": "Thema",
-        "threads": "Themen",
+        "threads": "Threads",
         "timeline": "Verlauf",
         "trusted": "Vertrauenswürdig",
         "unavailable": "Nicht verfügbar",
@@ -586,8 +583,7 @@
         "video": "Video",
         "video_room": "Videoraum",
         "view_message": "Nachricht anzeigen",
-        "warning": "Warnung",
-        "welcome": "Willkommen"
+        "warning": "Warnung"
     },
     "composer": {
         "autocomplete": {
@@ -914,6 +910,9 @@
             "warning": "Wenn du die Wiederherstellungsmethode nicht gelöscht hast, kann ein Angreifer versuchen, Zugang zu deinem Konto zu bekommen. Ändere dein Passwort und richte sofort eine neue Wiederherstellungsmethode in den Einstellungen ein."
         },
         "reset_all_button": "Hast du alle Wiederherstellungsmethoden vergessen? <a>Setze sie hier zurück</a>",
+        "set_up_recovery": "Wiederherstellung einrichten",
+        "set_up_recovery_later": "Nicht jetzt",
+        "set_up_recovery_toast_description": "Generieren Sie einen Wiederherstellungsschlüssel, damit Sie Ihren verschlüsselten Nachrichtenverlauf wiederherstellen können, falls Sie den Zugriff auf Ihre Geräte verlieren.",
         "set_up_toast_description": "Schütze dich vor dem Verlust verschlüsselter Nachrichten und Daten",
         "set_up_toast_title": "Schlüsselsicherung einrichten",
         "setup_secure_backup": {
@@ -1274,7 +1273,7 @@
         "error_already_invited_space": "Die Person wurde bereits eingeladen",
         "error_already_joined_room": "Die Person ist bereits im Raum",
         "error_already_joined_space": "Die Person ist bereits im Space",
-        "error_bad_state": "Verbannte Nutzer können nicht eingeladen werden.",
+        "error_bad_state": "Gesperrte Benutzer können nicht eingeladen werden.",
         "error_dm": "Wir konnten deine Direktnachricht nicht erstellen.",
         "error_find_room": "Beim Einladen der Nutzer lief etwas schief.",
         "error_find_user_description": "Folgende Nutzer konnten nicht eingeladen werden, da sie nicht existieren oder ungültig sind: %(csvNames)s",
@@ -1315,7 +1314,7 @@
         "unable_find_profiles_invite_label_default": "Dennoch einladen",
         "unable_find_profiles_invite_never_warn_label_default": "Trotzdem einladen und mich nicht mehr warnen",
         "unable_find_profiles_title": "Eventuell existieren folgende Benutzer nicht",
-        "unban_first_title": "Benutzer kann nicht eingeladen werden, solange er nicht entbannt ist"
+        "unban_first_title": "Benutzer kann nicht eingeladen werden, solange die Sperre nicht aufgehoben worden ist."
     },
     "inviting_user1_and_user2": "Lade %(user1)s und %(user2)s ein",
     "inviting_user_and_n_others": {
@@ -1391,7 +1390,7 @@
         "space": "Leertaste",
         "switch_to_space": "Mit Nummer zu Leerzeichen springen",
         "toggle_hidden_events": "Sichtbarkeit versteckter Ereignisse umschalten",
-        "toggle_microphone_mute": "Mikrofon an-/ausschalten",
+        "toggle_microphone_mute": "Mikrofon ein-/ausschalten",
         "toggle_right_panel": "Rechtes Panel ein-/ausblenden",
         "toggle_space_panel": "Space-Panel ein/aus",
         "toggle_top_left_menu": "Menü oben links ein-/ausblenden",
@@ -1458,8 +1457,6 @@
         "notification_settings_beta_caption": "Einen einfacheren Weg um die Einstellungen für Benachrichtigungen zu ändern vorstellen. Passe Deine %(brand)s so an wie Du willst.",
         "notification_settings_beta_title": "Benachrichtigungseinstellungen",
         "notifications": "Benachrichtigungen in der Kopfleiste des Raums anschalten",
-        "oidc_native_flow": "Native OIDC Authentifizierung",
-        "oidc_native_flow_description": "⚠ Warnung: Experimentell. Nutze OIDC native Authentifizierung wenn dies vom Server unterstützt wird.",
         "release_announcement": "Release Ankündigung",
         "render_reaction_images": "Benutzerdefinierte Bilder in Reaktionen anzeigen",
         "render_reaction_images_description": "Werden manchmal auch als „benutzerdefinierte Emojis“ bezeichnet.",
@@ -1579,9 +1576,14 @@
         "toggle_attribution": "Info ein-/ausblenden"
     },
     "member_list": {
+        "count": {
+            "one": "%(count)s Mitglied",
+            "other": "%(count)s Mitglieder"
+        },
         "filter_placeholder": "Raummitglieder filtern",
         "invite_button_no_perms_tooltip": "Du bist nicht berechtigt, Benutzer einzuladen",
-        "invited_list_heading": "Eingeladen",
+        "invited_label": "Eingeladen",
+        "no_matches": "Keine Treffer",
         "power_label": "%(userName)s (Berechtigungslevel %(powerLevelNumber)s)"
     },
     "member_list_back_action_label": "Raummitglieder",
@@ -1628,61 +1630,15 @@
         "m.key.verification.request": "%(name)s fordert eine Verifizierung an"
     },
     "onboarding": {
-        "apple_trademarks": "App Store® und das Apple Logo® sind eingetragene Markenzeichen von Apple Inc.",
-        "community_messaging_action": "Finde deine Leute",
-        "community_messaging_description": "Verfüge und behalte die Kontrolle über Gespräche deiner Gemeinschaft.\nSkalierbar für Millionen von Nutzenden, mit mächtigen Moderationswerkzeugen und Interoperabilität.",
-        "community_messaging_title": "In gemeinschaftlicher Hand",
-        "complete_these": "Vervollständige sie für die beste %(brand)s-Erfahrung",
         "create_room": "Gruppenraum erstellen",
-        "download_app": "%(brand)s herunterladen",
-        "download_app_action": "Apps herunterladen",
-        "download_app_description": "Nimm %(brand)s mit, um nichts mehr zu verpassen",
-        "download_app_store": "Im App Store herunterladen",
-        "download_brand": "%(brand)s herunterladen",
-        "download_brand_desktop": "%(brand)s Desktop herunterladen",
-        "download_f_droid": "In F-Droid erhältlich",
-        "download_google_play": "In Google Play erhältlich",
-        "enable_notifications": "Desktopbenachrichtigungen einschalten",
-        "enable_notifications_action": "Einstellungen öffnen",
-        "enable_notifications_description": "Verpasse keine Antworten oder wichtigen Nachrichten",
         "explore_rooms": "Öffentliche Räume erkunden",
-        "find_community_members": "Finde deine Community-Mitglieder und lade sie ein",
-        "find_coworkers": "Finde deine Kollegen und lade sie ein",
-        "find_friends": "Finde deine Freunde und lade sie ein",
-        "find_friends_action": "Freunde finden",
-        "find_friends_description": "Dafür bist du hier, also dann mal los",
-        "find_people": "Finde Personen",
-        "free_e2ee_messaging_unlimited_voip": "Dank freien, Ende-zu-Ende verschlüsselter Kommunikation und unbegrenzten Sprach- und Videoanrufen ist %(brand)s eine großartige Möglichkeit, um in Kontakt zu bleiben.",
-        "get_stuff_done": "Finde dein Team und werdet produktiv",
-        "google_trademarks": "Google Play und das Google Play Logo sind eingetragene Markenzeichen von Google LLC.",
         "has_avatar_label": "Großartig, das wird anderen helfen, dich zu erkennen",
         "intro_byline": "Besitze deine Unterhaltungen.",
         "intro_welcome": "Willkommen bei %(appName)s",
         "no_avatar_label": "Füge ein Bild hinzu, damit andere dich erkennen können.",
-        "only_n_steps_to_go": {
-            "one": "Nur noch %(count)s Schritt",
-            "other": "Nur noch %(count)s Schritte"
-        },
-        "personal_messaging_action": "Beginne eine Unterhaltung",
-        "personal_messaging_title": "Sichere Kommunikation für Freunde und Familie",
-        "qr_or_app_links": "%(qrCode)s oder %(appLinks)s",
         "send_dm": "Direkt­­nachricht senden",
-        "set_up_profile": "Richte dein Profil ein",
-        "set_up_profile_action": "Dein Profil",
-        "set_up_profile_description": "Lass andere wissen, dass du es wirklich bist",
-        "use_case_community_messaging": "Online Community-Mitglieder",
-        "use_case_heading1": "Los gehts",
-        "use_case_heading2": "Mit wem wirst du am meisten schreiben?",
-        "use_case_heading3": "Wir helfen dir, dich zu vernetzen.",
-        "use_case_personal_messaging": "Freunde und Familie",
-        "use_case_work_messaging": "Kollegen und Gruppen",
         "welcome_detail": "Nun, lassen Sie uns Ihnen den Einstieg erleichtern",
-        "welcome_to_brand": "Willkommen bei %(brand)s",
-        "welcome_user": "Willkommen %(name)s",
-        "work_messaging_action": "Finde deine Kollegen",
-        "work_messaging_title": "Sichere Kommunikation für die Arbeit",
-        "you_did_it": "Geschafft!",
-        "you_made_it": "Geschafft!"
+        "welcome_user": "Willkommen %(name)s"
     },
     "pill": {
         "permalink_other_room": "Nachricht in %(room)s",
@@ -1734,7 +1690,6 @@
         "custom_level": "Selbstdefiniertes Berechtigungslevel",
         "default": "Standard",
         "label": "Berechtigungsstufe",
-        "mod": "Moderator",
         "moderator": "Moderator",
         "restricted": "Eingeschränkt"
     },
@@ -1846,9 +1801,9 @@
             },
             "reply_thread": "Auf <link>Nachricht im Thread</link> antworten",
             "unpin_all": {
-                "button": "Alle Nachrichten lösen",
+                "button": "Alle Nachrichten loslösen",
                 "content": "Stellen Sie sicher, dass Sie wirklich alle angehefteten Nachrichten entfernen möchten. Diese Aktion kann nicht rückgängig gemacht werden.",
-                "title": "Alle Nachrichten lösen?"
+                "title": "Alle Nachrichten loslösen?"
             },
             "view": "Im Nachrichtenverlauf ansehen"
         },
@@ -2032,7 +1987,7 @@
             "button_view_all": "Alle anzeigen",
             "description": "In diesem Raum sind Nachrichten angeheftet. Klicken Sie hier, um sie anzusehen.",
             "go_to_message": "Fixierte Nachrichten im Nachrichtenverlauf anzeigen.",
-            "title": "<bold>%(index)s of %(length)s</bold> Angeheftete Nachrichten"
+            "title": "<bold>%(index)s of %(length)s</bold> Fixierte Nachrichten"
         },
         "read_topic": "Klicke, um das Thema zu lesen",
         "rejecting": "Lehne Einladung ab …",
@@ -2417,7 +2372,7 @@
     },
     "settings": {
         "account": {
-            "dialog_title": "<strong>Einstellunge:</strong> Konto",
+            "dialog_title": "<strong>Einstellungen:</strong> Konto",
             "title": "Konto"
         },
         "all_rooms_home": "Alle Räume auf Startseite anzeigen",
@@ -2603,7 +2558,7 @@
             "title": "Tastatur"
         },
         "labs": {
-            "dialog_title": "<strong>Einstellungen:</strong> Labore"
+            "dialog_title": "<strong>Einstellungen:</strong> Labor"
         },
         "labs_mjolnir": {
             "dialog_title": "<strong>Einstellungen:</strong> Blockierte Benutzer"
@@ -2685,7 +2640,6 @@
             "room_directory_heading": "Raumverzeichnis",
             "room_list_heading": "Raumliste",
             "show_avatars_pills": "Profilbilder in Benutzer-, Raum- und Ereigniserwähnungen anzeigen",
-            "show_checklist_shortcuts": "Verknüpfung zu ersten Schritten (Willkommen) anzeigen",
             "show_polls_button": "Zeige Pol button",
             "surround_text": "Sonderzeichen automatisch vor und hinter Textauswahl setzen",
             "time_heading": "Zeitanzeige",
@@ -2819,6 +2773,7 @@
             "inactive_sessions_list_description": "Erwäge, dich aus alten (%(inactiveAgeDays)s Tage oder mehr), nicht mehr verwendeten Sitzungen abzumelden.",
             "ip": "IP-Adresse",
             "last_activity": "Neueste Aktivität",
+            "manage": "Diese Sitzung verwalten",
             "mobile_session": "Mobil-Sitzung",
             "n_sessions_selected": {
                 "one": "%(count)s Sitzung ausgewählt",
@@ -3014,7 +2969,7 @@
         "topic_room_error": "Thema des Raums konnte nicht ermittelt werden: Raum kann nicht gefunden werden (%(roomId)s",
         "tovirtual": "Zum virtuellen Raum dieses Raums wechseln, sofern vorhanden",
         "tovirtual_not_found": "Kein virtueller Raum für diesen Raum",
-        "unban": "Entbannt den Benutzer mit der angegebenen ID",
+        "unban": "Entsperrt den Benutzer mit der angegebenen ID",
         "unflip": "Stellt ┬──┬ ノ( ゜-゜ノ) einer Klartextnachricht voran",
         "unholdcall": "Beendet das Halten des Anrufs",
         "unignore": "Benutzer freigeben und ihre neuen Nachrichten wieder anzeigen",
@@ -3064,7 +3019,6 @@
         "invite": "Personen einladen",
         "invite_description": "Personen mit E-Mail oder Benutzernamen einladen",
         "invite_link": "Einladungslink teilen",
-        "invite_this_space": "In diesen Space einladen",
         "joining_space": "Trete bei",
         "landing_welcome": "Willkommen bei <name/>",
         "leave_dialog_action": "Space verlassen",
@@ -3413,7 +3367,7 @@
             "remove_name": "%(senderName)s hat den alten Anzeigenamen %(oldDisplayName)s entfernt",
             "set_avatar": "%(senderName)s hat das Profilbild gesetzt",
             "set_name": "%(senderName)s hat den Anzeigenamen zu %(displayName)s geändert",
-            "unban": "%(senderName)s hat %(targetName)s entbannt",
+            "unban": "%(senderName)s hat die Verbannung von %(targetName)s aufgehoben",
             "withdrew_invite": "%(senderName)s hat die Einladung für %(targetName)s zurückgezogen",
             "withdrew_invite_reason": "%(senderName)s hat die Einladung für %(targetName)s zurückgezogen: %(reason)s"
         },
@@ -3731,8 +3685,8 @@
         "ban_button_room": "Bannen",
         "ban_button_space": "Bannen",
         "ban_room_confirm_title": "Aus %(roomName)s verbannen",
-        "ban_space_everything": "Überall wo ich die Rechte dazu habe bannen",
-        "ban_space_specific": "In ausgewählten Räumen und Spaces bannen",
+        "ban_space_everything": "Überall sperren, wo ich die Rechte dazu habe",
+        "ban_space_specific": "Sperre sie in ausgewählten Chatrooms und Spaces",
         "count_of_sessions": {
             "other": "%(count)s Sitzungen",
             "one": "%(count)s Sitzung"
@@ -3797,11 +3751,11 @@
         "room_unencrypted_detail": "Nachrichten in verschlüsselten Räumen können nur von dir und vom Empfänger gelesen werden.",
         "send_message": "Nachricht senden",
         "share_button": "Profil teilen",
-        "unban_button_room": "Entbannen",
-        "unban_button_space": "Entbannen",
-        "unban_room_confirm_title": "Von %(roomName)s entbannen",
-        "unban_space_everything": "Überall wo ich die Rechte dazu habe, entbannen",
-        "unban_space_specific": "In ausgewählten Räumen und Spaces entbannen",
+        "unban_button_room": "Sperrung für den Chatroom aufheben",
+        "unban_button_space": "Sperrung aus Space aufheben",
+        "unban_room_confirm_title": "Sperrung für %(roomName)s aufheben",
+        "unban_space_everything": "Die Verbannung überall aufheben wo ich die Rechte dazu habe",
+        "unban_space_specific": "In ausgewählten Chatrooms und Spaces die Sperrung für sie aufheben",
         "unban_space_warning": "Die Person wird keinen Zutritt zu Bereichen haben, in denen du nicht administrierst.",
         "unignore_button": "Nicht mehr ignorieren",
         "verify_button": "Nutzer verifizieren",
diff --git a/src/i18n/strings/el.json b/src/i18n/strings/el.json
index 808aeb02eb2..1aca5d07767 100644
--- a/src/i18n/strings/el.json
+++ b/src/i18n/strings/el.json
@@ -1227,7 +1227,6 @@
     },
     "member_list": {
         "filter_placeholder": "Φιλτράρισμα μελών",
-        "invited_list_heading": "Προσκλήθηκε",
         "power_label": "%(userName)s (δύναμη %(powerLevelNumber)s)"
     },
     "member_list_back_action_label": "Μέλη δωματίου",
@@ -1322,7 +1321,6 @@
         "custom_level": "Προσαρμοσμένο επίπεδο",
         "default": "Προεπιλογή",
         "label": "Επίπεδο ισχύος",
-        "mod": "Συντονιστής",
         "moderator": "Συντονιστής",
         "restricted": "Περιορισμένο/η"
     },
@@ -2274,7 +2272,6 @@
         "invite": "Προσκαλέστε άτομα",
         "invite_description": "Πρόσκληση με email ή όνομα χρήστη",
         "invite_link": "Κοινή χρήση συνδέσμου πρόσκλησης",
-        "invite_this_space": "Πρόσκληση σε αυτό το χώρο",
         "joining_space": "Συνδέετε",
         "landing_welcome": "Καλώς ήρθατε στο <name/>",
         "leave_dialog_action": "Αποχώρηση από τον χώρο",
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index f3c514fca38..37a739a62e9 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -238,7 +238,6 @@
         "oidc": {
             "error_title": "We couldn't log you in",
             "generic_auth_error": "Something went wrong during authentication. Go to the sign in page and try again.",
-            "logout_redirect_warning": "You will be redirected to your server's authentication provider to complete sign out.",
             "missing_or_invalid_stored_state": "We asked the browser to remember which homeserver you use to let you sign in, but unfortunately your browser has forgotten it. Go to the sign in page and try again."
         },
         "password_field_keep_going_prompt": "Keep going…",
@@ -452,7 +451,6 @@
             "one": "and one other...",
             "other": "and %(count)s others..."
         },
-        "android": "Android",
         "appearance": "Appearance",
         "application": "Application",
         "are_you_sure": "Are you sure?",
@@ -492,7 +490,6 @@
         "identity_server": "Identity server",
         "image": "Image",
         "integration_manager": "Integration manager",
-        "ios": "iOS",
         "joined": "Joined",
         "labs": "Labs",
         "legal": "Legal",
@@ -542,6 +539,7 @@
         "qr_code": "QR Code",
         "random": "Random",
         "reactions": "Reactions",
+        "recommended": "Recommended",
         "report_a_bug": "Report a bug",
         "room": "Room",
         "room_name": "Room name",
@@ -586,8 +584,7 @@
         "video": "Video",
         "video_room": "Video room",
         "view_message": "View message",
-        "warning": "Warning",
-        "welcome": "Welcome"
+        "warning": "Warning"
     },
     "composer": {
         "autocomplete": {
@@ -1461,8 +1458,6 @@
         "notification_settings_beta_caption": "Introducing a simpler way to change your notification settings. Customize your %(brand)s, just the way you like.",
         "notification_settings_beta_title": "Notification Settings",
         "notifications": "Enable the notifications panel in the room header",
-        "oidc_native_flow": "OIDC native authentication",
-        "oidc_native_flow_description": "⚠ WARNING: Experimental. Use OIDC native authentication when supported by the server.",
         "release_announcement": "Release announcement",
         "render_reaction_images": "Render custom images in reactions",
         "render_reaction_images_description": "Sometimes referred to as \"custom emojis\".",
@@ -1582,9 +1577,14 @@
         "toggle_attribution": "Toggle attribution"
     },
     "member_list": {
+        "count": {
+            "one": "%(count)s Member",
+            "other": "%(count)s Members"
+        },
         "filter_placeholder": "Filter room members",
         "invite_button_no_perms_tooltip": "You do not have permission to invite users",
-        "invited_list_heading": "Invited",
+        "invited_label": "Invited",
+        "no_matches": "No matches",
         "power_label": "%(userName)s (power %(powerLevelNumber)s)"
     },
     "member_list_back_action_label": "Room members",
@@ -1631,61 +1631,15 @@
         "m.key.verification.request": "%(name)s is requesting verification"
     },
     "onboarding": {
-        "apple_trademarks": "App Store® and the Apple logo® are trademarks of Apple Inc.",
-        "community_messaging_action": "Find your people",
-        "community_messaging_description": "Keep ownership and control of community discussion.\nScale to support millions, with powerful moderation and interoperability.",
-        "community_messaging_title": "Community ownership",
-        "complete_these": "Complete these to get the most out of %(brand)s",
         "create_room": "Create a Group Chat",
-        "download_app": "Download %(brand)s",
-        "download_app_action": "Download apps",
-        "download_app_description": "Don’t miss a thing by taking %(brand)s with you",
-        "download_app_store": "Download on the App Store",
-        "download_brand": "Download %(brand)s",
-        "download_brand_desktop": "Download %(brand)s Desktop",
-        "download_f_droid": "Get it on F-Droid",
-        "download_google_play": "Get it on Google Play",
-        "enable_notifications": "Turn on desktop notifications",
-        "enable_notifications_action": "Open settings",
-        "enable_notifications_description": "Don’t miss a reply or important message",
         "explore_rooms": "Explore Public Rooms",
-        "find_community_members": "Find and invite your community members",
-        "find_coworkers": "Find and invite your co-workers",
-        "find_friends": "Find and invite your friends",
-        "find_friends_action": "Find friends",
-        "find_friends_description": "It’s what you’re here for, so lets get to it",
-        "find_people": "Find people",
-        "free_e2ee_messaging_unlimited_voip": "With free end-to-end encrypted messaging, and unlimited voice and video calls, %(brand)s is a great way to stay in touch.",
-        "get_stuff_done": "Get stuff done by finding your teammates",
-        "google_trademarks": "Google Play and the Google Play logo are trademarks of Google LLC.",
         "has_avatar_label": "Great, that'll help people know it's you",
         "intro_byline": "Own your conversations.",
         "intro_welcome": "Welcome to %(appName)s",
         "no_avatar_label": "Add a photo so people know it's you.",
-        "only_n_steps_to_go": {
-            "one": "Only %(count)s step to go",
-            "other": "Only %(count)s steps to go"
-        },
-        "personal_messaging_action": "Start your first chat",
-        "personal_messaging_title": "Secure messaging for friends and family",
-        "qr_or_app_links": "%(qrCode)s or %(appLinks)s",
         "send_dm": "Send a Direct Message",
-        "set_up_profile": "Set up your profile",
-        "set_up_profile_action": "Your profile",
-        "set_up_profile_description": "Make sure people know it’s really you",
-        "use_case_community_messaging": "Online community members",
-        "use_case_heading1": "You're in",
-        "use_case_heading2": "Who will you chat to the most?",
-        "use_case_heading3": "We'll help you get connected.",
-        "use_case_personal_messaging": "Friends and family",
-        "use_case_work_messaging": "Coworkers and teams",
         "welcome_detail": "Now, let's help you get started",
-        "welcome_to_brand": "Welcome to %(brand)s",
-        "welcome_user": "Welcome %(name)s",
-        "work_messaging_action": "Find your co-workers",
-        "work_messaging_title": "Secure messaging for work",
-        "you_did_it": "You did it!",
-        "you_made_it": "You made it!"
+        "welcome_user": "Welcome %(name)s"
     },
     "pill": {
         "permalink_other_room": "Message in %(room)s",
@@ -1737,7 +1691,6 @@
         "custom_level": "Custom level",
         "default": "Default",
         "label": "Power level",
-        "mod": "Mod",
         "moderator": "Moderator",
         "restricted": "Restricted"
     },
@@ -2464,6 +2417,36 @@
         "emoji_autocomplete": "Enable Emoji suggestions while typing",
         "enable_markdown": "Enable Markdown",
         "enable_markdown_description": "Start messages with <code>/plain</code> to send without markdown.",
+        "encryption": {
+            "device_not_verified_button": "Verify this device",
+            "device_not_verified_description": "You need to verify this device in order to view your encryption settings.",
+            "device_not_verified_title": "Device not verified",
+            "dialog_title": "<strong>Settings:</strong> Encryption",
+            "recovery": {
+                "change_recovery_confirm_button": "Confirm new recovery key",
+                "change_recovery_confirm_description": "Enter your new recovery key below to finish. Your old one will no longer work.",
+                "change_recovery_confirm_title": "Enter your new recovery key",
+                "change_recovery_key": "Change recovery key",
+                "change_recovery_key_description": "Write down this new recovery key somewhere safe. Then click Continue to confirm the change.",
+                "change_recovery_key_title": "Change recovery key?",
+                "description": "Recover your cryptographic identity and message history with a recovery key if you’ve lost all your existing devices.",
+                "enter_key_error": "The recovery key you entered is not correct.",
+                "enter_recovery_key": "Enter recovery key",
+                "key_storage_warning": "Your key storage is out of sync. Click the button below to fix the problem.",
+                "save_key_description": "Do not share this with anyone!",
+                "save_key_title": "Recovery key",
+                "set_up_recovery": "Set up recovery",
+                "set_up_recovery_confirm_button": "Finish set up",
+                "set_up_recovery_confirm_description": "Enter the recovery key shown on the previous screen to finish setting up recovery.",
+                "set_up_recovery_confirm_title": "Enter your recovery key to confirm",
+                "set_up_recovery_description": "Your key storage is protected by a recovery key. If you need a new recovery key after setup, you can recreate it by selecting ‘%(changeRecoveryKeyButton)s’.",
+                "set_up_recovery_save_key_description": "Write down this recovery key somewhere safe, like a password manager, encrypted note, or a physical safe.",
+                "set_up_recovery_save_key_title": "Save your recovery key somewhere safe",
+                "set_up_recovery_secondary_description": "After clicking continue, we’ll generate a recovery key for you.",
+                "title": "Recovery"
+            },
+            "title": "Encryption"
+        },
         "general": {
             "account_management_section": "Account management",
             "account_section": "Account",
@@ -2689,7 +2672,6 @@
             "room_directory_heading": "Room directory",
             "room_list_heading": "Room list",
             "show_avatars_pills": "Show avatars in user, room and event mentions",
-            "show_checklist_shortcuts": "Show shortcut to welcome checklist above the room list",
             "show_polls_button": "Show polls button",
             "surround_text": "Surround selected text when typing special characters",
             "time_heading": "Displaying time",
@@ -2823,6 +2805,7 @@
             "inactive_sessions_list_description": "Consider signing out from old sessions (%(inactiveAgeDays)s days or older) you don't use anymore.",
             "ip": "IP address",
             "last_activity": "Last activity",
+            "manage": "Manage this session",
             "mobile_session": "Mobile session",
             "n_sessions_selected": {
                 "one": "%(count)s session selected",
@@ -3068,7 +3051,6 @@
         "invite": "Invite people",
         "invite_description": "Invite with email or username",
         "invite_link": "Share invite link",
-        "invite_this_space": "Invite to this space",
         "joining_space": "Joining",
         "landing_welcome": "Welcome to <name/>",
         "leave_dialog_action": "Leave space",
diff --git a/src/i18n/strings/eo.json b/src/i18n/strings/eo.json
index 88694a3a580..91a5a024446 100644
--- a/src/i18n/strings/eo.json
+++ b/src/i18n/strings/eo.json
@@ -1125,7 +1125,6 @@
     },
     "member_list": {
         "filter_placeholder": "Filtri ĉambranojn",
-        "invited_list_heading": "Invititaj",
         "power_label": "%(userName)s (povnivelo je %(powerLevelNumber)s)"
     },
     "message_edit_dialog_title": "Redaktoj de mesaĝoj",
@@ -1193,7 +1192,6 @@
         "custom_level": "Propra nivelo",
         "default": "Ordinara",
         "label": "Povnivelo",
-        "mod": "Reguligisto",
         "moderator": "Ĉambrestro",
         "restricted": "Limigita"
     },
@@ -2070,7 +2068,6 @@
         "invite": "Inviti personojn",
         "invite_description": "Inviti per retpoŝtadreso aŭ uzantonomo",
         "invite_link": "Diskonigi invitan ligilon",
-        "invite_this_space": "Inviti al ĉi tiu aro",
         "landing_welcome": "Bonvenu al <name/>",
         "leave_dialog_action": "Forlasi aron",
         "leave_dialog_description": "Vi foriros de <spaceName/>.",
diff --git a/src/i18n/strings/es.json b/src/i18n/strings/es.json
index 0f54ccca700..c0dbba66a42 100644
--- a/src/i18n/strings/es.json
+++ b/src/i18n/strings/es.json
@@ -21,6 +21,7 @@
         "add_people": "Añadir gente",
         "apply": "Aplicar",
         "approve": "Aprobar",
+        "ask_to_join": "Pedir acceso",
         "back": "Volver",
         "call": "Llamar",
         "cancel": "Cancelar",
@@ -40,6 +41,7 @@
         "create_account": "Crear cuenta",
         "decline": "Rechazar",
         "delete": "Borrar",
+        "deny": "Denegar",
         "disable": "Desactivar",
         "disconnect": "Desconectarse",
         "dismiss": "Omitir",
@@ -76,10 +78,13 @@
         "new_room": "Nueva sala",
         "new_video_room": "Nueva sala de vídeo",
         "next": "Siguiente",
+        "no": "No",
         "ok": "Vale",
         "open": "Abrir",
         "pause": "Pausar",
+        "pin": "Fijar",
         "play": "Reproducir",
+        "proceed": "Continuar",
         "quote": "Citar",
         "react": "Reaccionar",
         "refresh": "Refrescar",
@@ -395,6 +400,7 @@
         "attachment": "Adjunto",
         "authentication": "Autenticación",
         "avatar": "Imagen de perfil",
+        "beta": "Beta",
         "camera": "Cámara",
         "cameras": "Cámaras",
         "capabilities": "Funcionalidades",
@@ -409,6 +415,7 @@
         "email_address": "Dirección de correo electrónico",
         "encrypted": "Cifrado",
         "encryption_enabled": "El cifrado está activado",
+        "error": "Error",
         "faq": "Preguntas frecuentes",
         "favourites": "Favoritos",
         "feedback": "Danos tu opinión",
@@ -429,6 +436,7 @@
         "loading": "Cargando…",
         "location": "Ubicación",
         "low_priority": "Prioridad baja",
+        "matrix": "Matrix",
         "message": "Mensaje",
         "message_layout": "Diseño del mensaje",
         "microphone": "Micrófono",
@@ -508,8 +516,7 @@
         "video": "Vídeo",
         "video_room": "Sala de vídeo",
         "view_message": "Ver mensaje",
-        "warning": "Advertencia",
-        "welcome": "Te damos la bienvenida"
+        "warning": "Advertencia"
     },
     "composer": {
         "autocomplete": {
@@ -1012,7 +1019,10 @@
         "format": "Formato",
         "from_the_beginning": "Desde el principio",
         "generating_zip": "Generar un archivo ZIP",
+        "html": "HTML",
+        "html_title": "Datos exportados",
         "include_attachments": "Incluir archivos adjuntos",
+        "json": "JSON",
         "media_omitted": "Archivo omitido",
         "media_omitted_file_size": "Archivo omitido - supera el límite de tamaño",
         "messages": "Mensajes",
@@ -1171,6 +1181,7 @@
     },
     "keyboard": {
         "activate_button": "Activar botón seleccionado",
+        "alt": "Alt",
         "autocomplete_cancel": "Cancelar autocompletar",
         "autocomplete_force": "Forzar a que termine",
         "autocomplete_navigate_next": "Sugerencia siguiente",
@@ -1194,8 +1205,11 @@
         "composer_toggle_link": "Alternar enlace",
         "composer_toggle_quote": "Alternar cita",
         "composer_undo": "Deshacer edición",
+        "control": "Ctrl",
         "dismiss_read_marker_and_jump_bottom": "Descartar el marcador de lectura y saltar al final",
         "end": "Fin",
+        "enter": "Intro",
+        "escape": "Esc",
         "go_home_view": "Ir a la vista de inicio",
         "home": "Inicio",
         "jump_first_message": "Ir al primer mensaje",
@@ -1224,6 +1238,7 @@
         "scroll_up_timeline": "Subir en la línea de tiempo",
         "search": "Buscar (si está activado)",
         "send_sticker": "Enviar una pegatina",
+        "shift": "Mayús",
         "space": "Espacio",
         "switch_to_space": "Ir a un espacio por número",
         "toggle_hidden_events": "Alternar visibilidad del evento oculto",
@@ -1281,7 +1296,6 @@
         "location_share_live_description": "Implementación temporal. Las ubicaciones persisten en el historial de la sala.",
         "mjolnir": "Nuevas maneras de ignorar a otras personas",
         "msc3531_hide_messages_pending_moderation": "Permitir a los moderadores ocultar mensajes a la espera de revisión.",
-        "oidc_native_flow": "Activar flujos de OIDC nativos (en desarrollo)",
         "report_to_moderators": "Denunciar ante los moderadores",
         "report_to_moderators_description": "En las salas que sean compatible con la moderación, el botón de «Denunciar» avisará a los moderadores de la sala.",
         "sliding_sync": "Modo de sincronización progresiva",
@@ -1394,7 +1408,6 @@
     "member_list": {
         "filter_placeholder": "Filtrar miembros de la sala",
         "invite_button_no_perms_tooltip": "No tienes permisos para invitar usuarios",
-        "invited_list_heading": "Invitado",
         "power_label": "%(userName)s (nivel de permisos %(powerLevelNumber)s)"
     },
     "member_list_back_action_label": "Miembros de la sala",
@@ -1434,61 +1447,15 @@
         "m.key.verification.request": "%(name)s solicita verificación"
     },
     "onboarding": {
-        "apple_trademarks": "App Store® y el logo de Apple® son marcas registradas de Apple Inc.",
-        "community_messaging_action": "Encuentra a tus contactos",
-        "community_messaging_description": "Mantén el control de las conversaciones.\nCrece hasta tener millones de mensajes, con potente moderación e interoperabilidad.",
-        "community_messaging_title": "Propiedad de la comunidad",
-        "complete_these": "Complétalos para sacar el máximo partido a %(brand)s",
         "create_room": "Crea un grupo",
-        "download_app": "Descargar %(brand)s",
-        "download_app_action": "Descargar apps",
-        "download_app_description": "No te pierdas nada llevándote %(brand)s contigo",
-        "download_app_store": "Descargar en la App Store",
-        "download_brand": "Descargar %(brand)s",
-        "download_brand_desktop": "Descargar %(brand)s para escritorio",
-        "download_f_droid": "Disponible en F-Droid",
-        "download_google_play": "Disponible en Google Play",
-        "enable_notifications": "Activar notificaciones",
-        "enable_notifications_action": "Activar notificaciones",
-        "enable_notifications_description": "No te pierdas ninguna respuesta ni mensaje importante",
         "explore_rooms": "Explora las salas públicas",
-        "find_community_members": "Encuentra e invita a las personas de tu comunidad",
-        "find_coworkers": "Encuentra o invita a tus compañeros",
-        "find_friends": "Encuentra e invita a tus amigos",
-        "find_friends_action": "Encontrar amigos",
-        "find_friends_description": "Es para lo que estás aquí, así que vamos a ello",
-        "find_people": "Encontrar gente",
-        "free_e2ee_messaging_unlimited_voip": "Gracias a la mensajería cifrada de extremo a extremo, y a las llamadas de voz y vídeo sin límite, %(brand)s es una buena manera de mantenerte en contacto.",
-        "get_stuff_done": "Empieza a trabajar añadiendo a tus compañeros",
-        "google_trademarks": "Google Play y el logo de Google Play son marcas registradas de Google LLC.",
         "has_avatar_label": "Genial, ayudará a que la gente sepa que eres tú",
         "intro_byline": "Toma el control de tus conversaciones.",
         "intro_welcome": "Te damos la bienvenida a %(appName)s",
         "no_avatar_label": "Añade una imagen para que la gente sepa que eres tú.",
-        "only_n_steps_to_go": {
-            "one": "Solo queda %(count)s paso",
-            "other": "Quedan solo %(count)s pasos"
-        },
-        "personal_messaging_action": "Empieza tu primera conversación",
-        "personal_messaging_title": "Mensajería segura para amigos y familia",
-        "qr_or_app_links": "%(qrCode)s o %(appLinks)s",
         "send_dm": "Envía un mensaje directo",
-        "set_up_profile": "Completar perfil",
-        "set_up_profile_action": "Tu perfil",
-        "set_up_profile_description": "Asegúrate de que la gente sepa que eres tú de verdad",
-        "use_case_community_messaging": "Miembros de comunidades online",
-        "use_case_heading1": "Estás en",
-        "use_case_heading2": "¿Con quién hablarás más?",
-        "use_case_heading3": "Te ayudamos a conectar.",
-        "use_case_personal_messaging": "Familia y amigos",
-        "use_case_work_messaging": "Compañeros de trabajo y equipos",
         "welcome_detail": "Vamos a empezar",
-        "welcome_to_brand": "Te damos la bienvenida a %(brand)s",
-        "welcome_user": "Te damos la bienvenida, %(name)s",
-        "work_messaging_action": "Encuentra a tus compañeros",
-        "work_messaging_title": "Mensajería segura para el trabajo",
-        "you_did_it": "¡Ya está!",
-        "you_made_it": "¡Ya está!"
+        "welcome_user": "Te damos la bienvenida, %(name)s"
     },
     "pill": {
         "permalink_other_room": "Mensaje en %(room)s",
@@ -2305,7 +2272,6 @@
             "room_directory_heading": "Directorio de salas",
             "room_list_heading": "Lista de salas",
             "show_avatars_pills": "Mostrar fotos de perfil en las menciones de usuarios, salas y eventos",
-            "show_checklist_shortcuts": "Mostrar un atajo a los pasos de bienvenida encima de la lista de salas",
             "show_polls_button": "Mostrar botón de encuestas",
             "surround_text": "Rodear texto seleccionado al escribir caracteres especiales",
             "time_heading": "Fecha y hora"
@@ -2637,7 +2603,6 @@
         "invite": "Invitar gente",
         "invite_description": "Invitar correos electrónicos o nombres de usuario",
         "invite_link": "Compartir enlace de invitación",
-        "invite_this_space": "Invitar al espacio",
         "joining_space": "Uniéndote",
         "landing_welcome": "Te damos la bienvenida a <name/>",
         "leave_dialog_action": "Salir del espacio",
@@ -2780,8 +2745,11 @@
         "n_minutes_ago": "hace %(num)s minutos",
         "seconds_left": "%(seconds)ss restantes",
         "short_days": "%(value)s d",
+        "short_days_hours_minutes_seconds": "%(days)sd %(hours)sh %(minutes)sm %(seconds)ss",
         "short_hours": "%(value)s h",
+        "short_hours_minutes_seconds": "%(hours)sh %(minutes)sm %(seconds)ss",
         "short_minutes": "%(value)s min",
+        "short_minutes_seconds": "%(minutes)sm %(seconds)ss",
         "short_seconds": "%(value)s s"
     },
     "timeline": {
diff --git a/src/i18n/strings/et.json b/src/i18n/strings/et.json
index 093dcf861ef..c61df1d0030 100644
--- a/src/i18n/strings/et.json
+++ b/src/i18n/strings/et.json
@@ -235,7 +235,6 @@
         "oidc": {
             "error_title": "Meil ei õnnestunud sind sisse logida",
             "generic_auth_error": "Autentimisel läks midagi valesti. Mine sisselogimise lehele ja proovi uuesti.",
-            "logout_redirect_warning": "Sind suunatakse välja logimise lõpuleviimiseks ümber oma serveri autentimise teenusepakkujale.",
             "missing_or_invalid_stored_state": "Me sättisime nii, et sinu veebibrauser jätaks järgmiseks sisselogimiseks meelde sinu koduserveri, kuid kahjuks on ta selle unustanud. Palun mine sisselogimise lehele ja proovi uuesti."
         },
         "password_field_keep_going_prompt": "Jätka…",
@@ -419,7 +418,6 @@
             "other": "ja %(count)s muud...",
             "one": "ja üks muu..."
         },
-        "android": "Android",
         "appearance": "Välimus",
         "application": "Rakendus",
         "are_you_sure": "Kas sa oled kindel?",
@@ -458,7 +456,6 @@
         "identity_server": "Isikutuvastusserver",
         "image": "Pilt",
         "integration_manager": "Lõiminguhaldur",
-        "ios": "iOS",
         "joined": "Liitunud",
         "labs": "Katsed",
         "legal": "Juriidiline teave",
@@ -547,8 +544,7 @@
         "video": "Video",
         "video_room": "Videotuba",
         "view_message": "Vaata sõnumit",
-        "warning": "Hoiatus",
-        "welcome": "Tere tulemast"
+        "warning": "Hoiatus"
     },
     "composer": {
         "autocomplete": {
@@ -1387,8 +1383,6 @@
         "notification_settings": "Uued teavituste seadistused",
         "notification_settings_beta_title": "Teavituste seadistused",
         "notifications": "Kasuta jututoa päises teavituste riba",
-        "oidc_native_flow": "OIDC-põhine autentimine",
-        "oidc_native_flow_description": "⚠ HOIATUS: Kasuta OIDC liidestust, kui server seda võimaldab (aktiivselt arendamisel).",
         "report_to_moderators": "Teata moderaatoritele",
         "report_to_moderators_description": "Kui jututoas on modereerimine kasutusel, siis nupust „Teata sisust“ avaneva vormi abil saad jututoa reegleid rikkuvast sisust teatada moderaatoritele.",
         "sliding_sync": "Järkjärgulise sünkroniseerimise režiim",
@@ -1503,7 +1497,6 @@
     "member_list": {
         "filter_placeholder": "Filtreeri jututoa liikmeid",
         "invite_button_no_perms_tooltip": "Sul pole õigusi kutse saatmiseks teistele kasutajatele",
-        "invited_list_heading": "Kutsutud",
         "power_label": "%(userName)s (õigused %(powerLevelNumber)s)"
     },
     "member_list_back_action_label": "Jututoa liikmed",
@@ -1546,61 +1539,15 @@
         "m.key.verification.request": "%(name)s soovib verifitseerimist"
     },
     "onboarding": {
-        "apple_trademarks": "App Store® ja Apple logo® on Apple Inc kaubamärgid.",
-        "community_messaging_action": "Leia oma kaasteelisi",
-        "community_messaging_description": "Halda ja kontrolli suhtlust oma kogukonnas.\nSobib ka miljonitele kasutajatele ning võimaldab mitmekesist modereerimist kui liidestust.",
-        "community_messaging_title": "Kogukonnad, mida te ise haldate",
-        "complete_these": "Kasutamaks kõiki %(brand)s'i võimalusi tee läbi alljärgnev",
         "create_room": "Loo rühmavestlus",
-        "download_app": "Laadi alla %(brand)s",
-        "download_app_action": "Laadi alla rakendusi",
-        "download_app_description": "Võta %(brand)s nutiseadmesse kaasa ning ära jäta suhtlemist vahele",
-        "download_app_store": "Laadi alla App Store'st",
-        "download_brand": "Laadi alla %(brand)s",
-        "download_brand_desktop": "Laadi alla %(brand)s töölaua rakendusena",
-        "download_f_droid": "Laadi alla F-Droid'ist",
-        "download_google_play": "Laadi alla Google Play'st",
-        "enable_notifications": "Lülita seadistused välja",
-        "enable_notifications_action": "Võta teavitused kasutusele",
-        "enable_notifications_description": "Ära jäta vahele vastuseid ega olulisi sõnumeid",
         "explore_rooms": "Sirvi avalikke jututubasid",
-        "find_community_members": "Leia ja saada kutse oma kogukonna liikmetele",
-        "find_coworkers": "Leia kolleege ja saada neile kutse",
-        "find_friends": "Leia sõpru ja saada neile kutse",
-        "find_friends_action": "Leia sõpru",
-        "find_friends_description": "Selleks sa oled ju siin, alustame siis nüüd",
-        "find_people": "Leia muid suhtluspartnereid",
-        "free_e2ee_messaging_unlimited_voip": "%(brand)s on parim viis suhtluseks - siin on tasuta läbiv krüptimine kui piiramatult heli- ja videokõnesid.",
-        "get_stuff_done": "Saa tööd tehtud üheskoos oma kaasteelistega",
-        "google_trademarks": "Google Play ja Google Play logo on Google LLC kaubamärgid.",
         "has_avatar_label": "Suurepärane, nüüd teised teavad et tegemist on sinuga",
         "intro_byline": "Vestlused, mida sa tegelikult ka omad.",
         "intro_welcome": "Tere tulemast suhtlusrakenduse %(appName)s kasutajaks",
         "no_avatar_label": "Enda tutvustamiseks lisa foto.",
-        "only_n_steps_to_go": {
-            "one": "Ainult %(count)s samm veel",
-            "other": "Ainult %(count)s sammu veel"
-        },
-        "personal_messaging_action": "Alusta oma esimest vestlust",
-        "personal_messaging_title": "Turvaline suhtlus pere ja sõprade jaoks",
-        "qr_or_app_links": "%(qrCode)s või %(appLinks)s",
         "send_dm": "Saada otsesõnum",
-        "set_up_profile": "Seadista oma profiili",
-        "set_up_profile_action": "Sinu profiil",
-        "set_up_profile_description": "Taga, et sinu suhtluspartnerid võivad selles kindlad olla, et tegemist on sinuga",
-        "use_case_community_messaging": "Võrgupõhise kogukonna liikmed",
-        "use_case_heading1": "Kõik on tehtud",
-        "use_case_heading2": "Kellega sa kõige rohkem vestled?",
-        "use_case_heading3": "Me aitame sind Matrix'i võrgu kasutamisel.",
-        "use_case_personal_messaging": "Perekond ja sõbrad",
-        "use_case_work_messaging": "Kolleegid ja töörühmad",
         "welcome_detail": "Nüüd näitame sulle, mida saad järgmiseks teha",
-        "welcome_to_brand": "Tere tulemast %(brand)s'i kasutajaks",
-        "welcome_user": "Tere tulemast, %(name)s",
-        "work_messaging_action": "Leia oma kolleege",
-        "work_messaging_title": "Turvalised sõnumid töökeskkonna jaoks",
-        "you_did_it": "Valmis!",
-        "you_made_it": "Sa said valmis!"
+        "welcome_user": "Tere tulemast, %(name)s"
     },
     "pill": {
         "permalink_other_room": "Sõnum jututoas %(room)s",
@@ -1652,7 +1599,6 @@
         "custom_level": "Kohandatud õigused",
         "default": "Tavaline",
         "label": "Õiguste tase",
-        "mod": "Moderaator",
         "moderator": "Moderaator",
         "restricted": "Piiratud õigustega kasutaja"
     },
@@ -2498,7 +2444,6 @@
             "room_directory_heading": "Jututubade loend",
             "room_list_heading": "Jututubade loend",
             "show_avatars_pills": "Näita tunnuspilte kasutajate, jututubade ja sündmuste mainimistes",
-            "show_checklist_shortcuts": "Näita viidet jututubade loendi kohal",
             "show_polls_button": "Näita küsitluste nuppu",
             "surround_text": "Erimärkide sisestamisel märgista valitud tekst",
             "time_heading": "Aegade kuvamine"
@@ -2851,7 +2796,6 @@
         "invite": "Kutsu teisi kasutajaid",
         "invite_description": "Kutsu e-posti aadressi või kasutajanime alusel",
         "invite_link": "Jaga kutse linki",
-        "invite_this_space": "Kutsu siia kogukonnakeskusesse",
         "joining_space": "Liitun",
         "landing_welcome": "Tete tulemast <name/> liikmeks",
         "leave_dialog_action": "Lahku kogukonnakeskusest",
diff --git a/src/i18n/strings/fa.json b/src/i18n/strings/fa.json
index 4fc031ac43d..39ea21eb581 100644
--- a/src/i18n/strings/fa.json
+++ b/src/i18n/strings/fa.json
@@ -428,8 +428,7 @@
         "verification_cancelled": "تأیید هویت لغو شد",
         "video": "ویدئو",
         "view_message": "مشاهده پیام",
-        "warning": "هشدار",
-        "welcome": "خوش آمدید"
+        "warning": "هشدار"
     },
     "composer": {
         "autocomplete": {
@@ -1037,7 +1036,6 @@
     },
     "member_list": {
         "filter_placeholder": "فیلتر کردن اعضای اتاق",
-        "invited_list_heading": "دعوت شد",
         "power_label": "%(userName)s (سطح قدرت %(powerLevelNumber)s)"
     },
     "member_list_back_action_label": "اعضای اتاق",
@@ -1091,7 +1089,6 @@
         "custom_level": "سطح دلخواه",
         "default": "پیشفرض",
         "label": "سطح قدرت",
-        "mod": "معاون",
         "moderator": "معاون",
         "restricted": "ممنوع"
     },
@@ -1823,7 +1820,6 @@
         "invite": "دعوت کاربران",
         "invite_description": "دعوت با ایمیل یا نام‌کاربری",
         "invite_link": "به اشتراک‌گذاری لینک دعوت",
-        "invite_this_space": "به این فضای کاری دعوت کنید",
         "landing_welcome": "به <name/> خوش‌آمدید",
         "leave_dialog_action": "ترک محیط",
         "mark_suggested": "علامت‌گذاری به عنوان پیشنهاد‌شده",
diff --git a/src/i18n/strings/fi.json b/src/i18n/strings/fi.json
index 48fc132f002..f42a1af5696 100644
--- a/src/i18n/strings/fi.json
+++ b/src/i18n/strings/fi.json
@@ -508,8 +508,7 @@
         "version": "Versio",
         "video_room": "Videohuone",
         "view_message": "Näytä viesti",
-        "warning": "Varoitus",
-        "welcome": "Tervetuloa"
+        "warning": "Varoitus"
     },
     "composer": {
         "autocomplete": {
@@ -1309,7 +1308,6 @@
     "member_list": {
         "filter_placeholder": "Suodata huoneen jäseniä",
         "invite_button_no_perms_tooltip": "Sinulla ei ole lupaa kutsua käyttäjiä",
-        "invited_list_heading": "Kutsuttu",
         "power_label": "%(userName)s (oikeustaso %(powerLevelNumber)s)"
     },
     "member_list_back_action_label": "Huoneen jäsenet",
@@ -1349,59 +1347,15 @@
         "m.key.verification.request": "%(name)s pyytää varmennusta"
     },
     "onboarding": {
-        "apple_trademarks": "App Store® ja Apple logo® ovat Apple Inc.:n tavaramerkkejä",
-        "community_messaging_action": "Löydä ihmiset",
-        "community_messaging_description": "Pidä yhteisön keskustelu hallussa. Skaalautuu miljooniin käyttäjiin ja\ntarjoaa tehokkaan moderoinnin ja yhteentoimivuuden.",
-        "community_messaging_title": "Yhteisön omistajuus",
         "create_room": "Luo huone",
-        "download_app": "Lataa %(brand)s",
-        "download_app_action": "Lataa sovellukset",
-        "download_app_description": "Älä jää mistään paitsi, ota %(brand)s mukaasi",
-        "download_app_store": "Lataa App Storesta",
-        "download_brand": "Lataa %(brand)s",
-        "download_brand_desktop": "Lataa %(brand)sin työpöytäversio",
-        "download_f_droid": "Hanki F-Droidista",
-        "download_google_play": "Hanki Google Playsta",
-        "enable_notifications": "Ota ilmoitukset käyttöön",
-        "enable_notifications_action": "Käytä ilmoituksia",
-        "enable_notifications_description": "Älä anna vastauksen tai tärkeän viestin jäädä huomiotta",
         "explore_rooms": "Selaa julkisia huoneita",
-        "find_community_members": "Etsi ja kutsu yhteisöjäseniä",
-        "find_coworkers": "Etsi ja kutsu työkavereita",
-        "find_friends": "Etsi ja kutsu ystäviä",
-        "find_friends_action": "Etsi kavereita",
-        "find_friends_description": "Sen vuoksi olet täällä, joten aloitetaan",
-        "find_people": "Etsi ihmisiä",
-        "free_e2ee_messaging_unlimited_voip": "Ilmaisen päästä päähän -salauksen sekä rajoittamattomien ääni- ja videopuhelujen myötä %(brand)s on oiva tapa pysyä yhteydessä.",
-        "get_stuff_done": "Saa asiat hoidetuksi löytämällä tiimikaverisi",
-        "google_trademarks": "Google Play ja the Google Play -logo ovat Google LLC.:n tavaramerkkejä",
         "has_avatar_label": "Hienoa, tämä auttaa ihmisiä tietämään, että se olet sinä",
         "intro_byline": "Omista keskustelusi.",
         "intro_welcome": "Tervetuloa %(appName)s-sovellukseen",
         "no_avatar_label": "Lisää kuva, jotta ihmiset tietävät, että se olet sinä.",
-        "only_n_steps_to_go": {
-            "one": "Vain %(count)s vaihe jäljellä",
-            "other": "Vain %(count)s vaihetta jäljellä"
-        },
-        "personal_messaging_action": "Aloita ensimmäinen keskustelu",
-        "personal_messaging_title": "Turvallista viestintää kavereiden ja perheen kanssa",
-        "qr_or_app_links": "%(qrCode)s tai %(appLinks)s",
         "send_dm": "Lähetä yksityisviesti",
-        "set_up_profile": "Aseta profiilisi",
-        "set_up_profile_action": "Profiilisi",
-        "set_up_profile_description": "Varmista että ihmiset tietävät, että se todella olet sinä",
-        "use_case_community_messaging": "Verkkoyhteisöjen jäsenet",
-        "use_case_heading2": "Kenen kanssa keskustelet eniten?",
-        "use_case_heading3": "Autamme sinua yhteyden muodostamisen kanssa.",
-        "use_case_personal_messaging": "Kaverit ja perhe",
-        "use_case_work_messaging": "Työkaverit ja tiimit",
         "welcome_detail": "Autetaanpa sinut alkuun",
-        "welcome_to_brand": "Tervetuloa, tämä on %(brand)s",
-        "welcome_user": "Tervetuloa, %(name)s",
-        "work_messaging_action": "Löydä työkaverisi",
-        "work_messaging_title": "Turvallista viestintää työelämään",
-        "you_did_it": "Teit sen!",
-        "you_made_it": "Onnistui!"
+        "welcome_user": "Tervetuloa, %(name)s"
     },
     "pill": {
         "permalink_other_room": "Viesti huoneessa %(room)s",
@@ -1452,7 +1406,6 @@
         "custom_level": "Mukautettu taso",
         "default": "Oletus",
         "label": "Oikeuksien taso",
-        "mod": "Valvoja",
         "moderator": "Valvoja",
         "restricted": "Rajoitettu"
     },
@@ -2521,7 +2474,6 @@
         "invite": "Kutsu ihmisiä",
         "invite_description": "Kutsu sähköpostiosoitteella tai käyttäjänimellä",
         "invite_link": "Jaa kutsulinkki",
-        "invite_this_space": "Kutsu tähän avaruuteen",
         "joining_space": "Liitytään",
         "landing_welcome": "Tervetuloa, tämä on <name/>",
         "leave_dialog_action": "Poistu avaruudesta",
diff --git a/src/i18n/strings/fr.json b/src/i18n/strings/fr.json
index 08348ba29d6..1614ec3c562 100644
--- a/src/i18n/strings/fr.json
+++ b/src/i18n/strings/fr.json
@@ -238,7 +238,6 @@
         "oidc": {
             "error_title": "Nous n’avons pas pu vous connecter",
             "generic_auth_error": "Une erreur s’est produite lors de l’authentification. Allez à la page de connexion et réessayez.",
-            "logout_redirect_warning": "Vous allez être redirigé vers le fournisseur d’authentification de votre serveur pour terminer la déconnexion.",
             "missing_or_invalid_stored_state": "Nous avons demandé à votre navigateur de mémoriser votre serveur d’accueil, mais il semble l’avoir oublié. Rendez-vous à la page de connexion et réessayez."
         },
         "password_field_keep_going_prompt": "En cours…",
@@ -452,7 +451,6 @@
             "other": "et %(count)s autres…",
             "one": "et un autre…"
         },
-        "android": "Android",
         "appearance": "Apparence",
         "application": "Application",
         "are_you_sure": "Êtes-vous sûr ?",
@@ -492,7 +490,6 @@
         "identity_server": "Serveur d’identité",
         "image": "Image",
         "integration_manager": "Gestionnaire d’intégration",
-        "ios": "iOS",
         "joined": "Rejoint",
         "labs": "Expérimental",
         "legal": "Légal",
@@ -586,8 +583,7 @@
         "video": "Vidéo",
         "video_room": "Salon vidéo",
         "view_message": "Afficher le message",
-        "warning": "Attention",
-        "welcome": "Bienvenue"
+        "warning": "Attention"
     },
     "composer": {
         "autocomplete": {
@@ -905,7 +901,7 @@
             "warning": "Si vous n’avez pas activé de nouvelle méthode de récupération, un attaquant essaye peut-être d’accéder à votre compte. Changez immédiatement le mot de passe de votre compte et configurez une nouvelle méthode de récupération dans les paramètres."
         },
         "not_supported": "<non pris en charge>",
-        "pinned_identity_changed": "%(displayName)sL'identité de (<b>%(userId)s</b>) semble avoir changé. <a>En savoir plus </a>",
+        "pinned_identity_changed": "L'identité de %(displayName)s (<b>%(userId)s</b>) semble avoir changé. <a>En savoir plus</a>",
         "pinned_identity_changed_no_displayname": "<b>%(userId)s</b>semble avoir changé d'identité. <a>En savoir plus</a>",
         "recovery_method_removed": {
             "description_1": "Cette session a détecté que votre phrase secrète et clé de sécurité pour les messages sécurisés ont été supprimées.",
@@ -1458,8 +1454,6 @@
         "notification_settings_beta_caption": "Introduit une manière plus simple de changer vos préférences de notifications. Customisez %(brand)s, comme ça vous convient.",
         "notification_settings_beta_title": "Paramètres de notification",
         "notifications": "Active le panneau de notifications dans l’en-tête du salon",
-        "oidc_native_flow": "Authentification native OIDC",
-        "oidc_native_flow_description": "⚠ ATTENTION : Expérimental. Utilise l’authentification OIDC native lorsqu’elle est prise en charge par le serveur.",
         "release_announcement": "Annonce de sortie",
         "render_reaction_images": "Afficher les images personnalisées des réactions",
         "render_reaction_images_description": "Parfois appelés « émojis personnalisés ».",
@@ -1581,7 +1575,6 @@
     "member_list": {
         "filter_placeholder": "Filtrer les membres du salon",
         "invite_button_no_perms_tooltip": "Vous n’avez pas la permission d’inviter des utilisateurs",
-        "invited_list_heading": "Invités",
         "power_label": "%(userName)s (rang %(powerLevelNumber)s)"
     },
     "member_list_back_action_label": "Membres du salon",
@@ -1628,61 +1621,15 @@
         "m.key.verification.request": "%(name)s demande une vérification"
     },
     "onboarding": {
-        "apple_trademarks": "App Store® et le logo Apple® sont des marques déposées de Apple Inc.",
-        "community_messaging_action": "Trouvez vos contacts",
-        "community_messaging_description": "Gardez le contrôle sur la discussion de votre communauté.\nPrend en charge des millions de messages, avec une interopérabilité et une modération efficace.",
-        "community_messaging_title": "Propriété de la communauté",
-        "complete_these": "Terminez-les pour obtenir le maximum de %(brand)s",
         "create_room": "Créez une discussion de groupe",
-        "download_app": "Télécharger %(brand)s",
-        "download_app_action": "Télécharger les applications",
-        "download_app_description": "Ne ratez pas une miette en emportant %(brand)s avec vous",
-        "download_app_store": "Télécharger sur l’App Store",
-        "download_brand": "Télécharger %(brand)s",
-        "download_brand_desktop": "Télécharger %(brand)s Desktop",
-        "download_f_droid": "Récupérez-le sur F-Droid",
-        "download_google_play": "Récupérez-le sur Google Play",
-        "enable_notifications": "Activer les notifications",
-        "enable_notifications_action": "Ouvrir les paramètres",
-        "enable_notifications_description": "Ne ratez pas une réponse ou un message important",
         "explore_rooms": "Explorez les salons publics",
-        "find_community_members": "Trouvez et invitez les membres de votre communauté",
-        "find_coworkers": "Trouvez et invitez vos collègues",
-        "find_friends": "Trouvez et invitez vos amis",
-        "find_friends_action": "Trouver des amis",
-        "find_friends_description": "Vous êtes là pour ça, alors allons-y",
-        "find_people": "Trouver des personnes",
-        "free_e2ee_messaging_unlimited_voip": "Grâce à la messagerie chiffrée de bout en bout gratuite, ainsi que des appels audio et vidéo illimités, %(brand)s est un excellent moyen de rester en contact.",
-        "get_stuff_done": "Faites votre job en trouvant vos coéquipiers",
-        "google_trademarks": "Google Play et le logo Google Play sont des marques déposées de Google LLC.",
         "has_avatar_label": "Super, ceci aidera des personnes à confirmer qu’il s’agit bien de vous",
         "intro_byline": "Contrôlez vos conversations.",
         "intro_welcome": "Bienvenue sur %(appName)s",
         "no_avatar_label": "Ajoutez une photo pour que les gens sachent qu’il s’agit de vous.",
-        "only_n_steps_to_go": {
-            "one": "Plus que %(count)s étape",
-            "other": "Plus que %(count)s étapes"
-        },
-        "personal_messaging_action": "Démarrer votre première conversation",
-        "personal_messaging_title": "Messagerie sécurisée pour les amis et la famille",
-        "qr_or_app_links": "%(qrCode)s ou %(appLinks)s",
         "send_dm": "Envoyez un message privé",
-        "set_up_profile": "Paramétrer votre profil",
-        "set_up_profile_action": "Votre profil",
-        "set_up_profile_description": "Faites en sorte que les gens sachent que c’est vous",
-        "use_case_community_messaging": "Membres de la communauté en ligne",
-        "use_case_heading1": "Vous y êtes",
-        "use_case_heading2": "À qui allez-vous le plus parler ?",
-        "use_case_heading3": "Nous allons vous aider à vous connecter.",
-        "use_case_personal_messaging": "Famille et amis",
-        "use_case_work_messaging": "Collègues et équipes",
         "welcome_detail": "Maintenant, laissez-nous vous aider à démarrer",
-        "welcome_to_brand": "Bienvenue sur %(brand)s",
-        "welcome_user": "Bienvenue %(name)s",
-        "work_messaging_action": "Trouver vos collègues",
-        "work_messaging_title": "Messagerie sécurisée pour le travail",
-        "you_did_it": "Vous l’avez fait !",
-        "you_made_it": "Vous avez réussi !"
+        "welcome_user": "Bienvenue %(name)s"
     },
     "pill": {
         "permalink_other_room": "Message dans %(room)s",
@@ -1734,7 +1681,6 @@
         "custom_level": "Rang personnalisé",
         "default": "Par défaut",
         "label": "Rang",
-        "mod": "Modérateur",
         "moderator": "Modérateur",
         "restricted": "Restreint"
     },
@@ -2685,7 +2631,6 @@
             "room_directory_heading": "Répertoire des salons",
             "room_list_heading": "Liste de salons",
             "show_avatars_pills": "Afficher les avatars dans les mentions d'utilisateur, de salon et d’évènements",
-            "show_checklist_shortcuts": "Afficher le raccourci vers la liste de vérification de bienvenue au-dessus de la liste des salons",
             "show_polls_button": "Afficher le bouton des sondages",
             "surround_text": "Entourer le texte sélectionné lors de la saisie de certains caractères",
             "time_heading": "Affichage de l’heure",
@@ -3064,7 +3009,6 @@
         "invite": "Inviter des personnes",
         "invite_description": "Inviter par e-mail ou nom d’utilisateur",
         "invite_link": "Partager le lien d’invitation",
-        "invite_this_space": "Inviter dans cet espace",
         "joining_space": "En train de rejoindre",
         "landing_welcome": "Bienvenue dans <name/>",
         "leave_dialog_action": "Quitter l’espace",
diff --git a/src/i18n/strings/gl.json b/src/i18n/strings/gl.json
index 50c551d6a2d..55f5afb2a50 100644
--- a/src/i18n/strings/gl.json
+++ b/src/i18n/strings/gl.json
@@ -474,8 +474,7 @@
         "video": "Vídeo",
         "video_room": "Sala de vídeo",
         "view_message": "Ver mensaxe",
-        "warning": "Aviso",
-        "welcome": "Benvida"
+        "warning": "Aviso"
     },
     "composer": {
         "autocomplete": {
@@ -1287,7 +1286,6 @@
     },
     "member_list": {
         "filter_placeholder": "Filtrar os participantes da conversa",
-        "invited_list_heading": "Convidada",
         "power_label": "%(userName)s (permiso %(powerLevelNumber)s)"
     },
     "member_list_back_action_label": "Membros da sala",
@@ -1327,61 +1325,15 @@
         "m.key.verification.request": "%(name)s está pedindo a verificación"
     },
     "onboarding": {
-        "apple_trademarks": "App Store® e o Apple logo® son marcas de Apple Inc.",
-        "community_messaging_action": "Atopa a persoas",
-        "community_messaging_description": "Mantén o control e a propiedade sobre as conversas da comunidade.\nPodendo xestionar millóns de contas, con ferramentas para a moderación e a interoperabilidade.",
-        "community_messaging_title": "Propiedade da comunidade",
-        "complete_these": "Completa esto para sacarlle partido a %(brand)s",
         "create_room": "Crear unha Conversa en Grupo",
-        "download_app": "Descargar %(brand)s",
-        "download_app_action": "Descargar apps",
-        "download_app_description": "Non perdas nada e leva %(brand)s contigo",
-        "download_app_store": "Descargar na App Store",
-        "download_brand": "Descargar %(brand)s",
-        "download_brand_desktop": "Descargar %(brand)s Desktop",
-        "download_f_droid": "Descargar desde F-Droid",
-        "download_google_play": "Descargar desde Google Play",
-        "enable_notifications": "Activa as notificacións",
-        "enable_notifications_action": "Activa as notificacións",
-        "enable_notifications_description": "Non perdas as respostas e mensaxes importantes",
         "explore_rooms": "Explorar Salas Públicas",
-        "find_community_members": "Atopar e convidar a persoas da túa comunidade",
-        "find_coworkers": "Atopa e convida a colegas de traballo",
-        "find_friends": "Atopa e convida ás túas amizades",
-        "find_friends_action": "Atopar amizades",
-        "find_friends_description": "É a razón de que estés aquí, asi que imos",
-        "find_people": "Atopar persoas",
-        "free_e2ee_messaging_unlimited_voip": "%(brand)s é xenial para estar en contacto con amizades e familia, con mensaxes gratuítas cifradas de extremo-a-extremo e chamadas ilimintadas de voz e vídeo.",
-        "get_stuff_done": "Ponte ao choio e atopa a colegas de traballo",
-        "google_trademarks": "Google Play e o logo de Google Play son marcas de Google LLC.",
         "has_avatar_label": "Moi ben, así axudarás a que outras persoas te recoñezan",
         "intro_byline": "As túas conversas son túas.",
         "intro_welcome": "Benvida a %(appName)s",
         "no_avatar_label": "Engade unha foto así a xente recoñecerate.",
-        "only_n_steps_to_go": {
-            "one": "A só %(count)s paso de comezar",
-            "other": "Só %(count)s para comezar"
-        },
-        "personal_messaging_action": "Inicia o teu primeiro chat",
-        "personal_messaging_title": "Mensaxería segura para amizades e familia",
-        "qr_or_app_links": "%(qrCode)s ou %(appLinks)s",
         "send_dm": "Envía unha Mensaxe Directa",
-        "set_up_profile": "Configura o perfil",
-        "set_up_profile_action": "O teu perfil",
-        "set_up_profile_description": "Facilita que a xente saiba que es ti",
-        "use_case_community_messaging": "Membros de comunidades en liña",
-        "use_case_heading1": "Estás dentro",
-        "use_case_heading2": "Con quen vas falar máis a miúdo?",
-        "use_case_heading3": "Axudarémosche a atopalos.",
-        "use_case_personal_messaging": "Amizades e familia",
-        "use_case_work_messaging": "Persoas e equipos do traballo",
         "welcome_detail": "Ímosche axudar neste comezo",
-        "welcome_to_brand": "Benvida a %(brand)s",
-        "welcome_user": "Benvida %(name)s",
-        "work_messaging_action": "Atopa aos teus colegas",
-        "work_messaging_title": "Mensaxería segura para o traballo",
-        "you_did_it": "Xa está!",
-        "you_made_it": "Conseguíchelo!"
+        "welcome_user": "Benvida %(name)s"
     },
     "poll": {
         "create_poll_action": "Crear Enquisa",
@@ -2139,7 +2091,6 @@
             "rm_lifetime": "Duración do marcador de lectura (ms)",
             "rm_lifetime_offscreen": "Duración do marcador de lectura fóra de pantall (ms)",
             "room_list_heading": "Listaxe de Salas",
-            "show_checklist_shortcuts": "Mostrar atallo á lista de comprobacións de benvida sobre a lista de salas",
             "show_polls_button": "Mostrar botón de enquisas",
             "surround_text": "Rodea o texto seleccionado ao escribir caracteres especiais",
             "time_heading": "Mostrar hora"
@@ -2422,7 +2373,6 @@
         "invite": "Convidar persoas",
         "invite_description": "Convida con email ou nome de usuaria",
         "invite_link": "Compartir ligazón do convite",
-        "invite_this_space": "Convidar a este espazo",
         "joining_space": "Uníndote",
         "landing_welcome": "Benvida a <name/>",
         "leave_dialog_action": "Saír do espazo",
diff --git a/src/i18n/strings/he.json b/src/i18n/strings/he.json
index 724e17efd91..36f05ead73c 100644
--- a/src/i18n/strings/he.json
+++ b/src/i18n/strings/he.json
@@ -332,7 +332,6 @@
             "one": "ועוד אחד אחר...",
             "other": "ו %(count)s אחרים..."
         },
-        "android": "אנדרויד",
         "appearance": "מראה",
         "are_you_sure": "האם אתם בטוחים?",
         "attachment": "נספחים",
@@ -1069,7 +1068,6 @@
     },
     "member_list": {
         "filter_placeholder": "סינון חברי חדר",
-        "invited_list_heading": "מוזמן",
         "power_label": "%(userName)s (רמת הרשאה %(powerLevelNumber)s)"
     },
     "member_list_back_action_label": "חברי החדר",
@@ -1114,7 +1112,6 @@
         "intro_welcome": "ברוכים הבאים אל %(appName)s",
         "no_avatar_label": "הוסף תמונה כדי שאנשים יידעו שאתה זה.",
         "send_dm": "שלח הודעה ישירה",
-        "use_case_personal_messaging": "חברים ומשפחה",
         "welcome_detail": "עכשיו, בואו נעזור לכם להתחיל",
         "welcome_user": "ברוכים הבאים %(name)s"
     },
@@ -1152,7 +1149,6 @@
         "custom_level": "דרגה מותאמת",
         "default": "ברירת מחדל",
         "label": "דרגת מנהל",
-        "mod": "ממתן",
         "moderator": "מנהל",
         "restricted": "מחוץ לתחום"
     },
@@ -1973,7 +1969,6 @@
         "incompatible_server_hierarchy": "השרת שלכם אינו תומך בהצגת היררכית חללי עבודה.",
         "invite": "הזמן אנשים",
         "invite_link": "שתף קישור להזמנה",
-        "invite_this_space": "הזמינו למרחב עבודה זה",
         "landing_welcome": "ברוכים הבאים אל <name/>",
         "no_search_result_hint": "אולי תרצו לנסות חיפוש אחר או לבדוק אם יש שגיאות הקלדה.",
         "search_children": "חיפוש %(spaceName)s",
diff --git a/src/i18n/strings/hu.json b/src/i18n/strings/hu.json
index 349c4a39cdb..b3e9db9cf45 100644
--- a/src/i18n/strings/hu.json
+++ b/src/i18n/strings/hu.json
@@ -229,7 +229,6 @@
         "no_hs_url_provided": "Nincs megadva a Matrix-kiszolgáló webcíme",
         "oidc": {
             "error_title": "Sajnos nem tudtuk bejelentkeztetni",
-            "logout_redirect_warning": "Át lesz irányítva a kiszolgáló hitelesítésszolgáltatójához a kijelentkezés befejezéséhez.",
             "missing_or_invalid_stored_state": "A böngészőt arra kértük, hogy jegyezze meg, melyik Matrix-kiszolgálót használta a bejelentkezéshez, de sajnos a böngészője elfelejtette. Navigáljon a bejelentkezési oldalra, és próbálja újra."
         },
         "password_field_keep_going_prompt": "Így tovább…",
@@ -412,7 +411,6 @@
             "other": "és még: %(count)s ...",
             "one": "és még egy..."
         },
-        "android": "Android",
         "appearance": "Megjelenítés",
         "application": "Alkalmazás",
         "are_you_sure": "Biztos?",
@@ -451,7 +449,6 @@
         "identity_server": "Azonosítási kiszolgáló",
         "image": "Kép",
         "integration_manager": "Integrációkezelő",
-        "ios": "iOS",
         "joined": "Csatlakozott",
         "labs": "Labor",
         "legal": "Jogi feltételek",
@@ -540,8 +537,7 @@
         "video": "Videó",
         "video_room": "Videó szoba",
         "view_message": "Üzenet megjelenítése",
-        "warning": "Figyelmeztetés",
-        "welcome": "Üdvözöljük"
+        "warning": "Figyelmeztetés"
     },
     "composer": {
         "autocomplete": {
@@ -1479,7 +1475,6 @@
     },
     "member_list": {
         "filter_placeholder": "Szoba tagság szűrése",
-        "invited_list_heading": "Meghívva",
         "power_label": "%(userName)s (szint: %(powerLevelNumber)s)"
     },
     "member_list_back_action_label": "Szobatagok",
@@ -1518,61 +1513,15 @@
         "m.key.verification.request": "%(name)s ellenőrzést kér"
     },
     "onboarding": {
-        "apple_trademarks": "Az App Store® és az Apple logo® az Apple Inc. védjegyei.",
-        "community_messaging_action": "Találja meg az embereket",
-        "community_messaging_description": "Tartsa meg a közösségi beszélgetések feletti irányítást.\nAkár milliók támogatásával, hatékony moderációs és együttműködési lehetőségekkel.",
-        "community_messaging_title": "Közösségi tulajdon",
-        "complete_these": "Ezen lépések befejezésével hozhatja ki a legtöbbet a(z) %(brand)s használatából",
         "create_room": "Készíts csoportos beszélgetést",
-        "download_app": "A(z) %(brand)s letöltése",
-        "download_app_action": "Alkalmazások letöltése",
-        "download_app_description": "Ne maradjon le semmiről, legyen Önnél a(z) %(brand)s",
-        "download_app_store": "Letöltés az App Store-ból",
-        "download_brand": "A(z) %(brand)s letöltése",
-        "download_brand_desktop": "Asztali %(brand)s letöltése",
-        "download_f_droid": "Letöltés az F-Droidról",
-        "download_google_play": "Letöltés a Google Play-ből",
-        "enable_notifications": "Értesítések bekapcsolása",
-        "enable_notifications_action": "Értesítések bekapcsolása",
-        "enable_notifications_description": "Ne maradjon le a válaszról vagy egy fontos üzenetről",
         "explore_rooms": "Nyilvános szobák felfedezése",
-        "find_community_members": "Közösség tagjainak keresése és meghívása",
-        "find_coworkers": "Munkatársak keresése és meghívása",
-        "find_friends": "Keresse meg és hívja meg barátait",
-        "find_friends_action": "Barátok keresése",
-        "find_friends_description": "Kezdjünk neki, ezért van itt",
-        "find_people": "Emberek keresése",
-        "free_e2ee_messaging_unlimited_voip": "Az ingyenes, végpontok közti titkosítással rendelkező üzenetküldéssel, a korlátlan hang- és videóhívással, a(z) %(brand)s használata nagyszerű módja a kapcsolattartásnak.",
-        "get_stuff_done": "Fejezzen be dolgokat a csapattagjai megtalálásával",
-        "google_trademarks": "A Google Play és a Google Play logó a Google LLC védjegye.",
         "has_avatar_label": "Nagyszerű, ez segíteni eldönteni másoknak, hogy tényleg Ön az",
         "intro_byline": "Az ön beszélgetései csak az öné.",
         "intro_welcome": "Üdvözli a(z) %(appName)s",
         "no_avatar_label": "Állítson be egy fényképet, hogy tudják mások, hogy Ön az.",
-        "only_n_steps_to_go": {
-            "one": "Még %(count)s lépés",
-            "other": "Még %(count)s lépés"
-        },
-        "personal_messaging_action": "Kezdje el az első csevegését",
-        "personal_messaging_title": "Biztonságos üzenetküldés barátokkal, családdal",
-        "qr_or_app_links": "%(qrCode)s vagy %(appLinks)s",
         "send_dm": "Közvetlen üzenet küldése",
-        "set_up_profile": "Saját profil beállítása",
-        "set_up_profile_action": "Saját profil",
-        "set_up_profile_description": "Biztosítsa a többieket arról, hogy valóban Ön az",
-        "use_case_community_messaging": "Online közösségek tagjai",
-        "use_case_heading1": "Itt van:",
-        "use_case_heading2": "Kivel beszélget a legtöbbet?",
-        "use_case_heading3": "Segítünk a kapcsolatteremtésben.",
-        "use_case_personal_messaging": "Barátok és család",
-        "use_case_work_messaging": "Munkatársak és csoportok",
         "welcome_detail": "És most segítünk az indulásban",
-        "welcome_to_brand": "Üdvözli a(z) %(brand)s",
-        "welcome_user": "Üdv %(name)s",
-        "work_messaging_action": "Találja meg a munkatársait",
-        "work_messaging_title": "Biztonságos üzenetküldés munkához",
-        "you_did_it": "Kész!",
-        "you_made_it": "Megcsinálta!"
+        "welcome_user": "Üdv %(name)s"
     },
     "pill": {
         "permalink_other_room": "Üzenet itt: %(room)s",
@@ -1624,7 +1573,6 @@
         "custom_level": "Egyedi szint",
         "default": "Alapértelmezett",
         "label": "Hozzáférési szint",
-        "mod": "Moderátor",
         "moderator": "Moderátor",
         "restricted": "Korlátozott"
     },
@@ -2458,7 +2406,6 @@
             "room_directory_heading": "Szobalista",
             "room_list_heading": "Szobalista",
             "show_avatars_pills": "Profilképek megjelenítése a felhasználók, szobák és események megemlítésénél",
-            "show_checklist_shortcuts": "Kezdő lépések elvégzésének hivatkozásának megjelenítése a szobalista fölött",
             "show_polls_button": "Szavazások gomb megjelenítése",
             "surround_text": "Kijelölt szöveg körülvétele speciális karakterek beírásakor",
             "time_heading": "Idő megjelenítése"
@@ -2820,7 +2767,6 @@
         "invite": "Emberek meghívása",
         "invite_description": "Meghívás e-mail-címmel vagy felhasználónévvel",
         "invite_link": "Meghívási hivatkozás megosztása",
-        "invite_this_space": "Meghívás a térbe",
         "joining_space": "Belépés",
         "landing_welcome": "Üdvözöl a(z) <name/>",
         "leave_dialog_action": "Tér elhagyása",
diff --git a/src/i18n/strings/id.json b/src/i18n/strings/id.json
index 9eade90bc21..baa2e5abb25 100644
--- a/src/i18n/strings/id.json
+++ b/src/i18n/strings/id.json
@@ -229,7 +229,6 @@
         "no_hs_url_provided": "Tidak ada URL homeserver yang disediakan",
         "oidc": {
             "error_title": "Kami tidak dapat memasukkan Anda",
-            "logout_redirect_warning": "Anda akan diarahkan ke penyedia autentikasi server Anda untuk menyelesaikan proses keluar.",
             "missing_or_invalid_stored_state": "Kami menanyakan browser ini untuk mengingat homeserver apa yang Anda gunakan untuk membantu Anda masuk, tetapi sayangnya browser ini melupakannya. Pergi ke halaman masuk dan coba lagi."
         },
         "password_field_keep_going_prompt": "Lanjutkan…",
@@ -412,7 +411,6 @@
             "one": "dan satu lainnya...",
             "other": "dan %(count)s lainnya..."
         },
-        "android": "Android",
         "appearance": "Tampilan",
         "application": "Aplikasi",
         "are_you_sure": "Apakah Anda yakin?",
@@ -451,7 +449,6 @@
         "identity_server": "Server identitas",
         "image": "Gambar",
         "integration_manager": "Manajer integrasi",
-        "ios": "iOS",
         "joined": "Tergabung",
         "labs": "Uji Coba",
         "legal": "Hukum",
@@ -540,8 +537,7 @@
         "video": "Video",
         "video_room": "Ruangan video",
         "view_message": "Tampilkan pesan",
-        "warning": "Peringatan",
-        "welcome": "Selamat datang"
+        "warning": "Peringatan"
     },
     "composer": {
         "autocomplete": {
@@ -1368,7 +1364,6 @@
         "notification_settings_beta_caption": "Perkenalkan cara yang lebih sederhana untuk mengubah pengaturan notifikasi Anda. Sesuaikan %(brand)s Anda, sesuai keinginan Anda.",
         "notification_settings_beta_title": "Pengaturan Notifikasi",
         "notifications": "Aktifkan panel notifikasi di tajuk ruangan",
-        "oidc_native_flow": "Autentikasi asli OIDC",
         "render_reaction_images": "Render gambar khusus dalam reaksi",
         "render_reaction_images_description": "Terkadang disebut sebagai \"emoji khusus\".",
         "report_to_moderators": "Laporkan ke moderator",
@@ -1487,7 +1482,6 @@
     "member_list": {
         "filter_placeholder": "Saring anggota ruangan",
         "invite_button_no_perms_tooltip": "Anda tidak memiliki izin untuk mengundang pengguna",
-        "invited_list_heading": "Diundang",
         "power_label": "%(userName)s (tingkat daya %(powerLevelNumber)s)"
     },
     "member_list_back_action_label": "Anggota ruangan",
@@ -1527,61 +1521,15 @@
         "m.key.verification.request": "%(name)s meminta verifikasi"
     },
     "onboarding": {
-        "apple_trademarks": "App Store® dan logo Apple® adalah merek dagang Apple Inc.",
-        "community_messaging_action": "Temukan orang-orang Anda",
-        "community_messaging_description": "Tetap miliki kemilikan dan kendali atas diskusi komunitas.\nBesar untuk mendukung jutaan anggota, dengan moderasi dan interoperabilitas berdaya.",
-        "community_messaging_title": "Kemilikan komunitas",
-        "complete_these": "Selesaikan untuk mendapatkan hasil yang maksimal dari %(brand)s",
         "create_room": "Buat sebuah Obrolan Grup",
-        "download_app": "Unduh %(brand)s",
-        "download_app_action": "Unduh aplikasi",
-        "download_app_description": "Jangan lewatkan hal-hal dengan membawa %(brand)s dengan Anda",
-        "download_app_store": "Unduh di App Store",
-        "download_brand": "Unduh %(brand)s",
-        "download_brand_desktop": "Unduh %(brand)s Desktop",
-        "download_f_droid": "Dapatkan di F-Droid",
-        "download_google_play": "Dapatkan di Google Play",
-        "enable_notifications": "Nyalakan notifikasi",
-        "enable_notifications_action": "Nyalakan notifikasi",
-        "enable_notifications_description": "Jangan lewatkan sebuah balasan atau pesan yang penting",
         "explore_rooms": "Jelajahi Ruangan Publik",
-        "find_community_members": "Temukan dan undang anggota komunitas Anda",
-        "find_coworkers": "Temukan dan undang rekan kerja Anda",
-        "find_friends": "Temukan dan undang teman Anda",
-        "find_friends_action": "Temukan teman-teman",
-        "find_friends_description": "Untuk itulah Anda di sini, jadi mari kita lakukan",
-        "find_people": "Temukan orang-orang",
-        "free_e2ee_messaging_unlimited_voip": "Dengan perpesanan terenkripsi ujung ke ujung gratis, dan panggilan suara & video tidak terbatas, %(brand)s adalah cara yang baik untuk tetap terhubung.",
-        "get_stuff_done": "Selesaikan hal-hal dengan menemukan rekan setim Anda",
-        "google_trademarks": "Google Play dan logo Google Play adalah merek dagang Google LLC.",
         "has_avatar_label": "Hebat, itu akan membantu orang-orang tahu bahwa itu Anda",
         "intro_byline": "Miliki percakapan Anda.",
         "intro_welcome": "Selamat datang di %(appName)s",
         "no_avatar_label": "Tambahkan sebuah foto supaya orang-orang tahu bahwa itu Anda.",
-        "only_n_steps_to_go": {
-            "one": "Hanya %(count)s langkah lagi untuk dilalui",
-            "other": "Hanya %(count)s langkah lagi untuk dilalui"
-        },
-        "personal_messaging_action": "Mulai obrolan pertama Anda",
-        "personal_messaging_title": "Perpesanan aman untuk teman dan keluarga",
-        "qr_or_app_links": "%(qrCode)s atau %(appLinks)s",
         "send_dm": "Kirim sebuah Pesan Langsung",
-        "set_up_profile": "Siapkan profil Anda",
-        "set_up_profile_action": "Profil Anda",
-        "set_up_profile_description": "Pastikan orang-orang tahu bahwa itu memang Anda",
-        "use_case_community_messaging": "Anggota komunitas daring",
-        "use_case_heading1": "Anda telah masuk",
-        "use_case_heading2": "Siapa saja yang sering Anda obrol?",
-        "use_case_heading3": "Kami akan membantu Anda untuk terhubung.",
-        "use_case_personal_messaging": "Teman dan keluarga",
-        "use_case_work_messaging": "Teman kerja dan tim",
         "welcome_detail": "Sekarang, mari bantu Anda memulai",
-        "welcome_to_brand": "Selamat datang di %(brand)s",
-        "welcome_user": "Selamat datang %(name)s",
-        "work_messaging_action": "Temukan rekan kerja Anda",
-        "work_messaging_title": "Perpesanan aman untuk berkerja",
-        "you_did_it": "Anda berhasil!",
-        "you_made_it": "Anda berhasil!"
+        "welcome_user": "Selamat datang %(name)s"
     },
     "pill": {
         "permalink_other_room": "Pesan dalam %(room)s",
@@ -1633,7 +1581,6 @@
         "custom_level": "Tingkat kustom",
         "default": "Bawaan",
         "label": "Tingkat daya",
-        "mod": "Mod",
         "moderator": "Moderator",
         "restricted": "Dibatasi"
     },
@@ -2490,7 +2437,6 @@
             "room_directory_heading": "Direktori ruangan",
             "room_list_heading": "Daftar ruangan",
             "show_avatars_pills": "Tampilkan avatar di sebutan pengguna, ruangan, dan peristiwa",
-            "show_checklist_shortcuts": "Tampilkan pintasan ke daftar centang selamat datang di atas daftar ruangan",
             "show_polls_button": "Tampilkan tombol pemungutan suara",
             "surround_text": "Kelilingi teks yang dipilih saat mengetik karakter khusus",
             "time_heading": "Tampilkan waktu"
@@ -2852,7 +2798,6 @@
         "invite": "Undang pengguna",
         "invite_description": "Undang dengan email atau nama pengguna",
         "invite_link": "Bagikan tautan undangan",
-        "invite_this_space": "Undang ke space ini",
         "joining_space": "Bergabung",
         "landing_welcome": "Selamat datang di <name/>",
         "leave_dialog_action": "Tinggalkan space",
diff --git a/src/i18n/strings/is.json b/src/i18n/strings/is.json
index 21ff743f2db..e1695b2cc06 100644
--- a/src/i18n/strings/is.json
+++ b/src/i18n/strings/is.json
@@ -480,8 +480,7 @@
         "video": "Myndskeið",
         "video_room": "Myndspjallrás",
         "view_message": "Sjá skilaboð",
-        "warning": "Aðvörun",
-        "welcome": "Velkomin/n"
+        "warning": "Aðvörun"
     },
     "composer": {
         "autocomplete": {
@@ -1237,7 +1236,6 @@
     },
     "member_list": {
         "filter_placeholder": "Sía meðlimi spjallrásar",
-        "invited_list_heading": "Boðið",
         "power_label": "%(userName)s (með völd sem %(powerLevelNumber)s)"
     },
     "member_list_back_action_label": "Meðlimir spjallrásar",
@@ -1277,59 +1275,15 @@
         "m.key.verification.request": "%(name)s biður um sannvottun"
     },
     "onboarding": {
-        "apple_trademarks": "App Store® og Apple logo® eru vörumerki í eigu Apple Inc.",
-        "community_messaging_action": "Finndu fólkið þitt",
-        "community_messaging_title": "Samfélagslegt eignarhald",
-        "complete_these": "Kláraðu þetta til að fá sem mest út úr %(brand)s",
         "create_room": "Búa til hópspjall",
-        "download_app": "Sækja %(brand)s",
-        "download_app_action": "Sækja forrit",
-        "download_app_description": "Ekki missa af neinu og taktu %(brand)s með þér",
-        "download_app_store": "Sækja á App Store forritasafni",
-        "download_brand": "Sækja %(brand)s",
-        "download_brand_desktop": "Sækja %(brand)s Desktop fyrir vinnutölvur",
-        "download_f_droid": "Ná í á F-Droid",
-        "download_google_play": "Ná í á Google Play",
-        "enable_notifications": "Kveikja á tilkynningum",
-        "enable_notifications_action": "Virkja tilkynningar",
-        "enable_notifications_description": "Ekki missa af svari eða áríðandi skilaboðum",
         "explore_rooms": "Kanna almenningsspjallrásir",
-        "find_community_members": "Finndu og bjóddu meðlimum í samfélaginu þínu",
-        "find_coworkers": "Finndu og bjóddu samstarfsaðilum þínum",
-        "find_friends": "Finndu og bjóddu vinum þínum",
-        "find_friends_action": "Finna vini",
-        "find_friends_description": "Það er nú einusinni það sem þú komst hingað til að gera, þannug að við skulum skella okkur í málið",
-        "find_people": "Finna fólk",
-        "get_stuff_done": "Komdu hlutum í verk með því að finna félaga í teyminu þínu",
-        "google_trademarks": "Google Play og Google Play táknmerkið eru vörumerki í eigu Google LLC.",
         "has_avatar_label": "Frábært, það mun hjálpa fólki að vita að þetta sért þú",
         "intro_byline": "Eigðu samtölin þín.",
         "intro_welcome": "Velkomin í %(appName)s",
         "no_avatar_label": "Bættu við mynd, svo fólk viti að þetta sért þú.",
-        "only_n_steps_to_go": {
-            "one": "Aðeins %(count)s skref í viðbót",
-            "other": "Aðeins %(count)s skref í viðbót"
-        },
-        "personal_messaging_action": "Byrjaðu fyrsta spjallið þitt",
-        "personal_messaging_title": "Örugg skilaboð fyrir vini og fjölskyldu",
-        "qr_or_app_links": "%(qrCode)s eða %(appLinks)s",
         "send_dm": "Senda bein skilaboð",
-        "set_up_profile": "Settu upp notandasniðið þitt",
-        "set_up_profile_action": "Notandasnið þitt",
-        "set_up_profile_description": "Láttu fólk vita að þetta sért þú",
-        "use_case_community_messaging": "Meðlimi samfélags á netinu",
-        "use_case_heading1": "Þú ert inni",
-        "use_case_heading2": "Við hverja muntu helst spjalla?",
-        "use_case_heading3": "Við munum hjálpa þér að tengjast.",
-        "use_case_personal_messaging": "Vinir og fjölskylda",
-        "use_case_work_messaging": "Samstarfsmenn og teymi",
         "welcome_detail": "Hefjumst handa við að koma þér í gang",
-        "welcome_to_brand": "Velkomin í %(brand)s",
-        "welcome_user": "Velkomin/n %(name)s",
-        "work_messaging_action": "Finndu samstarfsaðilana þína",
-        "work_messaging_title": "Örugg skilaboð í vinnunni",
-        "you_did_it": "Þú kláraðir þetta!",
-        "you_made_it": "Þú hafðir það!"
+        "welcome_user": "Velkomin/n %(name)s"
     },
     "poll": {
         "create_poll_action": "Búa til könnun",
@@ -1375,7 +1329,6 @@
         "custom_level": "Sérsniðið stig",
         "default": "Sjálfgefið",
         "label": "Stig valda",
-        "mod": "Umsjón",
         "moderator": "Umsjónarmaður",
         "restricted": "Takmarkað"
     },
@@ -2341,7 +2294,6 @@
         "invite": "Bjóða fólki",
         "invite_description": "Bjóða með tölvupóstfangi eða notandanafni",
         "invite_link": "Deila boðstengli",
-        "invite_this_space": "Bjóða inn á þetta svæði",
         "joining_space": "Geng í hópinn",
         "landing_welcome": "Velkomin í <name/>",
         "leave_dialog_action": "Yfirgefa svæði",
diff --git a/src/i18n/strings/it.json b/src/i18n/strings/it.json
index 1ddf88e8327..a67adfda7a6 100644
--- a/src/i18n/strings/it.json
+++ b/src/i18n/strings/it.json
@@ -235,7 +235,6 @@
         "oidc": {
             "error_title": "Non abbiamo potuto farti accedere",
             "generic_auth_error": "Qualcosa è andato storto durante l'autenticazione. Vai alla pagina di accesso e riprova.",
-            "logout_redirect_warning": "Verrai reindirizzato al fornitore di autenticazione del tuo server per completare la disconnessione.",
             "missing_or_invalid_stored_state": "Abbiamo chiesto al browser di ricordare quale homeserver usi per farti accedere, ma sfortunatamente l'ha dimenticato. Vai alla pagina di accesso e riprova."
         },
         "password_field_keep_going_prompt": "Continua…",
@@ -419,7 +418,6 @@
             "other": "e altri %(count)s ...",
             "one": "e un altro..."
         },
-        "android": "Android",
         "appearance": "Aspetto",
         "application": "Applicazione",
         "are_you_sure": "Sei sicuro?",
@@ -458,7 +456,6 @@
         "identity_server": "Server di identità",
         "image": "Immagine",
         "integration_manager": "Gestore di integrazioni",
-        "ios": "iOS",
         "joined": "Entrato/a",
         "labs": "Laboratori",
         "legal": "Informazioni legali",
@@ -548,8 +545,7 @@
         "video": "Video",
         "video_room": "Stanza video",
         "view_message": "Vedi messaggio",
-        "warning": "Attenzione",
-        "welcome": "Benvenuti"
+        "warning": "Attenzione"
     },
     "composer": {
         "autocomplete": {
@@ -1390,8 +1386,6 @@
         "notification_settings_beta_caption": "Ti presentiamo un modo più semplice per modificare le impostazioni delle notifiche. Personalizza il tuo %(brand)s, proprio come piace a te.",
         "notification_settings_beta_title": "Impostazioni di notifica",
         "notifications": "Attiva il pannello delle notifiche nell'intestazione della stanza",
-        "oidc_native_flow": "Autenticazione nativa OIDC",
-        "oidc_native_flow_description": "⚠ ATTENZIONE: sperimentale. Usa l'autenticazione nativa OIDC se supportata dal server.",
         "render_reaction_images": "Mostra immagini personalizzate nelle reazioni",
         "render_reaction_images_description": "A volte chiamati \"emoji personalizzati\".",
         "report_to_moderators": "Segnala ai moderatori",
@@ -1510,7 +1504,6 @@
     "member_list": {
         "filter_placeholder": "Filtra membri della stanza",
         "invite_button_no_perms_tooltip": "Non hai l'autorizzazione per invitare utenti",
-        "invited_list_heading": "Invitato/a",
         "power_label": "%(userName)s (poteri %(powerLevelNumber)s)"
     },
     "member_list_back_action_label": "Membri stanza",
@@ -1557,61 +1550,15 @@
         "m.key.verification.request": "%(name)s sta richiedendo la verifica"
     },
     "onboarding": {
-        "apple_trademarks": "App Store® e il logo Apple® sono marchi registrati di Apple Inc.",
-        "community_messaging_action": "Trova la tua gente",
-        "community_messaging_description": "Mantieni il possesso e il controllo delle discussioni nella comunità.\nScalabile per supportarne milioni, con solida moderazione e interoperabilità.",
-        "community_messaging_title": "Possesso della comunità",
-        "complete_these": "Completa questi per ottenere il meglio da %(brand)s",
         "create_room": "Crea una chat di gruppo",
-        "download_app": "Scarica %(brand)s",
-        "download_app_action": "Scarica app",
-        "download_app_description": "Non perderti niente portando %(brand)s con te",
-        "download_app_store": "Scarica dall'App Store",
-        "download_brand": "Scarica %(brand)s",
-        "download_brand_desktop": "Scarica %(brand)s Desktop",
-        "download_f_droid": "Ottienilo su F-Droid",
-        "download_google_play": "Ottienilo su Google Play",
-        "enable_notifications": "Attiva le notifiche",
-        "enable_notifications_action": "Attiva le notifiche",
-        "enable_notifications_description": "Non perderti una risposta o un messaggio importante",
         "explore_rooms": "Esplora le stanze pubbliche",
-        "find_community_members": "Trova e invita i membri della tua comunità",
-        "find_coworkers": "Trova e invita i tuoi colleghi",
-        "find_friends": "Trova e invita i tuoi amici",
-        "find_friends_action": "Trova amici",
-        "find_friends_description": "Sei qui per questo, quindi facciamolo",
-        "find_people": "Trova persone",
-        "free_e2ee_messaging_unlimited_voip": "Con messaggi gratis cifrati end-to-end e chiamate voce e video illimitate, %(brand)s è un ottimo modo per restare in contatto.",
-        "get_stuff_done": "Porta a termine il lavoro trovando i tuoi colleghi",
-        "google_trademarks": "Google Play e il logo Google Play sono marchi registrati di Google LLC.",
         "has_avatar_label": "Ottimo, ciò aiuterà le persone a capire che sei tu",
         "intro_byline": "Prendi il controllo delle tue conversazioni.",
         "intro_welcome": "Benvenuti su %(appName)s",
         "no_avatar_label": "Aggiungi una foto in modo che le persone ti riconoscano.",
-        "only_n_steps_to_go": {
-            "one": "Solo %(count)s passo per iniziare",
-            "other": "Solo %(count)s passi per iniziare"
-        },
-        "personal_messaging_action": "Inizia la prima conversazione",
-        "personal_messaging_title": "Messaggi sicuri per amici e famiglia",
-        "qr_or_app_links": "%(qrCode)s o %(appLinks)s",
         "send_dm": "Invia un messaggio diretto",
-        "set_up_profile": "Imposta il tuo profilo",
-        "set_up_profile_action": "Il tuo profilo",
-        "set_up_profile_description": "Assicurati che le persone sappiano che sei veramente tu",
-        "use_case_community_messaging": "Membri di comunità online",
-        "use_case_heading1": "Sei dentro",
-        "use_case_heading2": "Con chi parlerai di più?",
-        "use_case_heading3": "Vi aiuteremo a connettervi.",
-        "use_case_personal_messaging": "Amici e famiglia",
-        "use_case_work_messaging": "Colleghi e squadre",
         "welcome_detail": "Alcuni consigli per iniziare",
-        "welcome_to_brand": "Benvenuti in %(brand)s",
-        "welcome_user": "Benvenuto/a %(name)s",
-        "work_messaging_action": "Trova i tuoi colleghi",
-        "work_messaging_title": "Messaggi sicuri per il lavoro",
-        "you_did_it": "Ce l'hai fatta!",
-        "you_made_it": "Ce l'hai fatta!"
+        "welcome_user": "Benvenuto/a %(name)s"
     },
     "pill": {
         "permalink_other_room": "Messaggio in %(room)s",
@@ -1663,7 +1610,6 @@
         "custom_level": "Livello personalizzato",
         "default": "Predefinito",
         "label": "Livello poteri",
-        "mod": "Moderatore",
         "moderator": "Moderatore",
         "restricted": "Limitato"
     },
@@ -2531,7 +2477,6 @@
             "room_directory_heading": "Elenco delle stanze",
             "room_list_heading": "Elenco stanze",
             "show_avatars_pills": "Mostra gli avatar nelle citazioni di utenti, stanze ed eventi",
-            "show_checklist_shortcuts": "Mostra scorciatoia per l'elenco di benvenuto sopra la lista stanze",
             "show_polls_button": "Mostra pulsante sondaggi",
             "surround_text": "Circonda il testo selezionato quando si digitano caratteri speciali",
             "time_heading": "Visualizzazione dell'ora"
@@ -2893,7 +2838,6 @@
         "invite": "Invita persone",
         "invite_description": "Invita con email o nome utente",
         "invite_link": "Condividi collegamento di invito",
-        "invite_this_space": "Invita in questo spazio",
         "joining_space": "Entrata in corso",
         "landing_welcome": "Ti diamo il benvenuto in <name/>",
         "leave_dialog_action": "Esci dallo spazio",
diff --git a/src/i18n/strings/ja.json b/src/i18n/strings/ja.json
index 4ac7672e4c8..b4e7e0a931b 100644
--- a/src/i18n/strings/ja.json
+++ b/src/i18n/strings/ja.json
@@ -522,8 +522,7 @@
         "video": "動画",
         "video_room": "ビデオ通話ルーム",
         "view_message": "メッセージを表示",
-        "warning": "警告",
-        "welcome": "ようこそ"
+        "warning": "警告"
     },
     "composer": {
         "autocomplete": {
@@ -1403,7 +1402,6 @@
     },
     "member_list": {
         "filter_placeholder": "ルームのメンバーを絞り込む",
-        "invited_list_heading": "招待済",
         "power_label": "%(userName)s(権限レベル:%(powerLevelNumber)s)"
     },
     "member_list_back_action_label": "ルームのメンバー",
@@ -1445,61 +1443,15 @@
         "m.key.verification.request": "%(name)sは認証を要求しています"
     },
     "onboarding": {
-        "apple_trademarks": "App Store®とAppleロゴ®はApple Incの商標です。",
-        "community_messaging_action": "知人を見つける",
-        "community_messaging_description": "コミュニティーの会話の所有権とコントロールを維持しましょう。\n強力なモデレートと相互運用性で、数百万人のユーザーまでサポートできます。",
-        "community_messaging_title": "コミュニティーの手に",
-        "complete_these": "以下を完了し、%(brand)sを最大限に活用しましょう",
         "create_room": "グループチャットを作成",
-        "download_app": "%(brand)sをダウンロード",
-        "download_app_action": "アプリをダウンロード",
-        "download_app_description": "%(brand)sを持ち歩いて、情報を見逃さないようにしましょう",
-        "download_app_store": "App Storeでダウンロード",
-        "download_brand": "%(brand)sをダウンロード",
-        "download_brand_desktop": "%(brand)sデスクトップをダウンロード",
-        "download_f_droid": "F-Droidで入手",
-        "download_google_play": "Google Playで入手",
-        "enable_notifications": "通知を有効にする",
-        "enable_notifications_action": "通知を有効にする",
-        "enable_notifications_description": "返信または重要なメッセージを見逃さないようにしましょう",
         "explore_rooms": "公開ルームを探す",
-        "find_community_members": "コミュニティの参加者を探して招待しましょう",
-        "find_coworkers": "同僚を探して招待しましょう",
-        "find_friends": "友達を探して招待しましょう",
-        "find_friends_action": "友達を見つける",
-        "find_friends_description": "友達を見つけて、チャットを開始しましょう",
-        "find_people": "知人を見つける",
-        "free_e2ee_messaging_unlimited_voip": "自由なエンドツーエンド暗号化のメッセージのやり取りと音声・ビデオ通話で、%(brand)sは連絡を取るのに最適な手段です。",
-        "get_stuff_done": "同僚を見つけて、仕事を片付けましょう",
-        "google_trademarks": "Google PlayとGoogle PlayロゴはGoogle LLC.の商標です。",
         "has_avatar_label": "すばらしい、他の人があなただと気づく助けになるでしょう",
         "intro_byline": "自分の会話は、自分のもの。",
         "intro_welcome": "%(appName)sにようこそ",
         "no_avatar_label": "写真を追加して、あなただとわかるようにしましょう。",
-        "only_n_steps_to_go": {
-            "one": "あと%(count)sつのステップです",
-            "other": "あと%(count)sつのステップです"
-        },
-        "personal_messaging_action": "最初のチャットを始めましょう",
-        "personal_messaging_title": "友達や家族と安全なメッセージングを",
-        "qr_or_app_links": "%(qrCode)sまたは%(appLinks)s",
         "send_dm": "ダイレクトメッセージを送信",
-        "set_up_profile": "プロフィールの設定",
-        "set_up_profile_action": "あなたのプロフィール",
-        "set_up_profile_description": "相手に自分だと分かるようにしましょう",
-        "use_case_community_messaging": "オンラインコミュニティーのメンバー",
-        "use_case_heading1": "始めましょう",
-        "use_case_heading2": "誰と最もよく会話しますか?",
-        "use_case_heading3": "みんなと繋がる手助けをいたします。",
-        "use_case_personal_messaging": "友達と家族",
-        "use_case_work_messaging": "同僚とチーム",
         "welcome_detail": "何をしたいですか?",
-        "welcome_to_brand": "%(brand)sにようこそ",
-        "welcome_user": "ようこそ、%(name)s",
-        "work_messaging_action": "同僚を見つける",
-        "work_messaging_title": "仕事で安全なメッセージングを",
-        "you_did_it": "完了しました!",
-        "you_made_it": "完了しました!"
+        "welcome_user": "ようこそ、%(name)s"
     },
     "poll": {
         "create_poll_action": "アンケートを作成",
@@ -1546,7 +1498,6 @@
         "custom_level": "ユーザー定義のレベル",
         "default": "既定値",
         "label": "権限レベル",
-        "mod": "モデレーター",
         "moderator": "モデレーター",
         "restricted": "制限"
     },
@@ -2290,7 +2241,6 @@
             "rm_lifetime_offscreen": "既読マーカーを動かすまでの時間(画面オフ時)(ミリ秒)",
             "room_list_heading": "ルーム一覧",
             "show_avatars_pills": "アバターをユーザー、ルーム、イベントのメンションに表示",
-            "show_checklist_shortcuts": "ルームの一覧の上に、最初に設定すべき項目のチェックリストのショートカットを表示",
             "show_polls_button": "アンケートのボタンを表示",
             "surround_text": "特殊な文字の入力中に、選択した文章を囲む",
             "time_heading": "表示時刻"
@@ -2633,7 +2583,6 @@
         "invite": "連絡先を招待",
         "invite_description": "メールアドレスまたはユーザー名で招待",
         "invite_link": "招待リンクを共有",
-        "invite_this_space": "このスペースに招待",
         "joining_space": "参加しています",
         "landing_welcome": "<name/>にようこそ",
         "leave_dialog_action": "スペースから退出",
diff --git a/src/i18n/strings/lo.json b/src/i18n/strings/lo.json
index ddbe3d17f83..b9d5104172a 100644
--- a/src/i18n/strings/lo.json
+++ b/src/i18n/strings/lo.json
@@ -1249,8 +1249,7 @@
         "share_type_prompt": "ທ່ານຕ້ອງການແບ່ງປັນສະຖານທີ່ປະເພດໃດ?"
     },
     "member_list": {
-        "filter_placeholder": "ການກັ່ນຕອງສະມາຊິກຫ້ອງ",
-        "invited_list_heading": "ເຊີນ"
+        "filter_placeholder": "ການກັ່ນຕອງສະມາຊິກຫ້ອງ"
     },
     "member_list_back_action_label": "ສະມາຊິກຫ້ອງ",
     "message_edit_dialog_title": "ແກ້ໄຂຂໍ້ຄວາມ",
@@ -1345,7 +1344,6 @@
         "custom_level": "ລະດັບທີ່ກໍາຫນົດເອງ",
         "default": "ຄ່າເລີ່ມຕົ້ນ",
         "label": "ລະດັບພະລັງງານ",
-        "mod": "ກາປັບປ່ຽນ",
         "moderator": "ຜູ້ດຳເນິນລາຍການ",
         "restricted": "ຖືກຈຳກັດ"
     },
@@ -2301,7 +2299,6 @@
         "invite": "ເຊີນຜູ້ຄົນ",
         "invite_description": "ເຊີນດ້ວຍອີເມລ໌ ຫຼື ຊື່ຜູ້ໃຊ້",
         "invite_link": "ແບ່ງປັນລິ້ງເຊີນ",
-        "invite_this_space": "ເຊີນໄປບ່ອນນີ້",
         "joining_space": "ເຂົ້າຮ່ວມ",
         "landing_welcome": "ຍິນດີຕ້ອນຮັບສູ່ <name/>",
         "leave_dialog_action": "ອອກຈາກພື້ນທີ່",
diff --git a/src/i18n/strings/lt.json b/src/i18n/strings/lt.json
index 1e0679bae48..7e568f3360c 100644
--- a/src/i18n/strings/lt.json
+++ b/src/i18n/strings/lt.json
@@ -394,8 +394,7 @@
         "video": "Vaizdo įrašas",
         "video_room": "Vaizdo kambarys",
         "view_message": "Žiūrėti žinutę",
-        "warning": "Įspėjimas",
-        "welcome": "Sveiki atvykę"
+        "warning": "Įspėjimas"
     },
     "composer": {
         "autocomplete": {
@@ -923,7 +922,6 @@
     },
     "member_list": {
         "filter_placeholder": "Filtruoti kambario dalyvius",
-        "invited_list_heading": "Pakviesta",
         "power_label": "%(userName)s (galia %(powerLevelNumber)s)"
     },
     "member_list_back_action_label": "Kambario nariai",
@@ -959,43 +957,10 @@
         "m.key.verification.request": "%(name)s prašo patvirtinimo"
     },
     "onboarding": {
-        "community_messaging_action": "Rasti savo žmones",
-        "community_messaging_description": "Išlaikykite bendruomenės diskusijų nuosavybę ir kontrolę.\nPlėskitės ir palaikykite milijonus žmonių, naudodami galingą moderavimą ir sąveiką.",
-        "community_messaging_title": "Bendruomenės nuosavybė",
-        "complete_these": "Užbaikite šiuos žingsnius, kad gautumėte daugiausiai iš %(brand)s",
         "create_room": "Sukurti grupės pokalbį",
-        "download_app": "Atsisiųsti %(brand)s",
-        "download_app_action": "Atsisiųsti programėles",
-        "download_app_description": "Nepraleiskite nieko, jei su savimi pasiimsite %(brand)s",
-        "download_brand": "Atsisiųsti %(brand)s",
-        "enable_notifications": "Įjungti pranešimus",
-        "enable_notifications_action": "Įjungti pranešimus",
-        "enable_notifications_description": "Nepraleiskite atsakymo ar svarbios žinutės",
         "explore_rooms": "Žvalgyti viešus kambarius",
-        "find_community_members": "Rasti ir pakviesti savo bendruomenės narius",
-        "find_coworkers": "Rasti ir pakviesti bendradarbius",
-        "find_friends": "Rasti ir pakviesti draugus",
-        "find_friends_action": "Rasti draugus",
-        "find_friends_description": "Dėl to čia ir esate, todėl imkimės to",
-        "find_people": "Rasti žmones",
-        "free_e2ee_messaging_unlimited_voip": "%(brand)s - tai puikus būdas palaikyti ryšį: nemokamos visapusiškai šifruotos žinutės ir neriboti balso bei vaizdo skambučiai.",
-        "get_stuff_done": "Atlikite darbus suradę komandos draugus",
         "intro_welcome": "Sveiki prisijungę į %(appName)s",
-        "only_n_steps_to_go": {
-            "one": "Liko tik %(count)s žingsnis",
-            "other": "Liko tik %(count)s žingsniai"
-        },
-        "personal_messaging_action": "Pradėkite pirmąjį pokalbį",
-        "personal_messaging_title": "Saugūs pokalbiai draugams ir šeimai",
-        "send_dm": "Siųsti tiesioginę žinutę",
-        "set_up_profile": "Nustatykite savo profilį",
-        "set_up_profile_action": "Jūsų profilis",
-        "set_up_profile_description": "Įsitikinkite, kad žmonės žino, jog tai tikrai jūs",
-        "welcome_to_brand": "Sveiki atvykę į %(brand)s",
-        "work_messaging_action": "Rasti savo bendradarbius",
-        "work_messaging_title": "Saugūs pokalbiai darbui",
-        "you_did_it": "Jums pavyko!",
-        "you_made_it": "Jums pavyko!"
+        "send_dm": "Siųsti tiesioginę žinutę"
     },
     "power_level": {
         "admin": "Administratorius",
@@ -1003,7 +968,6 @@
         "custom_level": "Pritaikytas lygis",
         "default": "Numatytas",
         "label": "Galios lygis",
-        "mod": "Moderatorius",
         "moderator": "Moderatorius",
         "restricted": "Apribotas"
     },
@@ -1867,7 +1831,6 @@
         "invite": "Pakviesti žmonių",
         "invite_description": "Pakviesti su el. paštu arba naudotojo vardu",
         "invite_link": "Bendrinti pakvietimo nuorodą",
-        "invite_this_space": "Pakviesti į šią erdvę",
         "search_children": "Ieškoti %(spaceName)s"
     },
     "spaces": {
diff --git a/src/i18n/strings/nl.json b/src/i18n/strings/nl.json
index ebc2f396232..07380f4b984 100644
--- a/src/i18n/strings/nl.json
+++ b/src/i18n/strings/nl.json
@@ -381,7 +381,6 @@
             "other": "en %(count)s anderen…",
             "one": "en één andere…"
         },
-        "android": "Android",
         "appearance": "Weergave",
         "application": "Toepassing",
         "are_you_sure": "Weet je het zeker?",
@@ -419,7 +418,6 @@
         "identity_server": "Identiteitsserver",
         "image": "Afbeelding",
         "integration_manager": "Integratiebeheerder",
-        "ios": "iOS",
         "joined": "Toegetreden",
         "labs": "Labs",
         "legal": "Juridisch",
@@ -505,8 +503,7 @@
         "video": "Video",
         "video_room": "Video kamer",
         "view_message": "Bericht bekijken",
-        "warning": "Let op",
-        "welcome": "Welkom"
+        "warning": "Let op"
     },
     "composer": {
         "autocomplete": {
@@ -1300,7 +1297,6 @@
     },
     "member_list": {
         "filter_placeholder": "Kamerleden filteren",
-        "invited_list_heading": "Uitgenodigd",
         "power_label": "%(userName)s (macht %(powerLevelNumber)s)"
     },
     "member_list_back_action_label": "Kamerleden",
@@ -1341,61 +1337,15 @@
         "m.key.verification.request": "%(name)s verzoekt om verificatie"
     },
     "onboarding": {
-        "apple_trademarks": "App Store® en het Apple logo® zijn handelsmerken van Apple Inc.",
-        "community_messaging_action": "Vind je mensen",
-        "community_messaging_description": "Houd het eigendom en de controle over de discussie in de gemeenschap.\nSchaal om miljoenen te ondersteunen, met krachtige beheersbaarheid en interoperabiliteit.",
-        "community_messaging_title": "Gemeenschapseigendom",
-        "complete_these": "Voltooi deze om het meeste uit %(brand)s te halen",
         "create_room": "Maak een groepsgesprek",
-        "download_app": "%(brand)s downloaden",
-        "download_app_action": "Apps downloaden",
-        "download_app_description": "Mis niets door %(brand)s mee te nemen",
-        "download_app_store": "Te downloaden in de App Store",
-        "download_brand": "%(brand)s downloaden",
-        "download_brand_desktop": "%(brand)s Desktop downloaden",
-        "download_f_droid": "Download het op F-Droid",
-        "download_google_play": "Verkrijg het via Google Play",
-        "enable_notifications": "Meldingen aanzetten",
-        "enable_notifications_action": "Meldingen inschakelen",
-        "enable_notifications_description": "Mis geen antwoord of belangrijk bericht",
         "explore_rooms": "Publieke kamers ontdekken",
-        "find_community_members": "Vind en nodig je communityleden uit",
-        "find_coworkers": "Vind en nodig je collega's uit",
-        "find_friends": "Zoek je vrienden en nodig ze uit",
-        "find_friends_action": "Zoek vrienden",
-        "find_friends_description": "Daar ben je voor, dus laten we beginnen",
-        "find_people": "Zoek mensen",
-        "free_e2ee_messaging_unlimited_voip": "Met gratis eind-tot-eind versleutelde berichten en onbeperkte spraak- en video-oproepen, is %(brand)s een geweldige manier om in contact te blijven.",
-        "get_stuff_done": "Krijg dingen gedaan door je teamgenoten te vinden",
-        "google_trademarks": "Google Play en het Google Play-logo zijn handelsmerken van Google LLC.",
         "has_avatar_label": "Geweldig, dan zullen personen weten dat jij het bent",
         "intro_byline": "Gesprekken die helemaal van jou zijn.",
         "intro_welcome": "Welkom bij %(appName)s",
         "no_avatar_label": "Voeg een foto toe zodat personen weten dat jij het bent.",
-        "only_n_steps_to_go": {
-            "one": "Nog maar %(count)s stap te gaan",
-            "other": "Nog maar %(count)s stappen te gaan"
-        },
-        "personal_messaging_action": "Start je eerste chat",
-        "personal_messaging_title": "Veilig berichten versturen voor vrienden en familie",
-        "qr_or_app_links": "%(qrCode)s of %(appLinks)s",
         "send_dm": "Start een direct gesprek",
-        "set_up_profile": "Stel je profiel in",
-        "set_up_profile_action": "Jouw profiel",
-        "set_up_profile_description": "Zorg ervoor dat mensen weten dat je het echt bent",
-        "use_case_community_messaging": "Leden van online gemeenschap",
-        "use_case_heading1": "Je bent binnen",
-        "use_case_heading2": "Met wie ga je het meest chatten?",
-        "use_case_heading3": "We helpen je om verbinding te maken.",
-        "use_case_personal_messaging": "Vrienden en familie",
-        "use_case_work_messaging": "Collega's en teams",
         "welcome_detail": "Laten we je helpen om te beginnen",
-        "welcome_to_brand": "Welkom bij %(brand)s",
-        "welcome_user": "Welkom %(name)s",
-        "work_messaging_action": "Vind je collega's",
-        "work_messaging_title": "Veilig berichten versturen voor werk",
-        "you_did_it": "Het is je gelukt!",
-        "you_made_it": "Het is je gelukt!"
+        "welcome_user": "Welkom %(name)s"
     },
     "poll": {
         "create_poll_action": "Poll aanmaken",
@@ -2161,7 +2111,6 @@
             "rm_lifetime": "Levensduur van leesbevestigingen (ms)",
             "rm_lifetime_offscreen": "Levensduur van levensbevestigingen, niet op scherm (ms)",
             "room_list_heading": "Kamerslijst",
-            "show_checklist_shortcuts": "Toon snelkoppeling naar welkomstchecklist boven de kamer gids",
             "show_polls_button": "Toon polls-knop",
             "surround_text": "Geselecteerde tekst omsluiten bij het typen van speciale tekens",
             "time_heading": "Tijdsweergave"
@@ -2469,7 +2418,6 @@
         "invite": "Personen uitnodigen",
         "invite_description": "Uitnodigen per e-mail of inlognaam",
         "invite_link": "Deel uitnodigingskoppeling",
-        "invite_this_space": "Voor deze Space uitnodigen",
         "joining_space": "Toetreden",
         "landing_welcome": "Welkom in <name/>",
         "leave_dialog_action": "Space verlaten",
diff --git a/src/i18n/strings/pl.json b/src/i18n/strings/pl.json
index 66ac8070804..3103c622486 100644
--- a/src/i18n/strings/pl.json
+++ b/src/i18n/strings/pl.json
@@ -238,7 +238,6 @@
         "oidc": {
             "error_title": "Nie mogliśmy Cię zalogować",
             "generic_auth_error": "Coś poszło nie tak podczas uwierzytelniania. Przejdź do strony logowania i spróbuj ponownie.",
-            "logout_redirect_warning": "Zostaniesz przekierowany do dostawcy uwierzytelniania Twojego serwera w celu zakończenia wylogowania.",
             "missing_or_invalid_stored_state": "Poprosiliśmy przeglądarkę, aby zapamiętała za pomocą jakiego serwera domowego się logujesz, lecz niestety go zapomniała. Przejdź do strony logowania i spróbuj ponownie."
         },
         "password_field_keep_going_prompt": "Kontynuuj…",
@@ -453,7 +452,6 @@
             "few": "i %(count)s innych...",
             "many": "i %(count)s innych..."
         },
-        "android": "Android",
         "appearance": "Wygląd",
         "application": "Aplikacja",
         "are_you_sure": "Czy jesteś pewien?",
@@ -493,7 +491,6 @@
         "identity_server": "Serwer tożsamości",
         "image": "Obraz",
         "integration_manager": "Menedżer integracji",
-        "ios": "iOS",
         "joined": "Dołączono",
         "labs": "Laboratoria",
         "legal": "Zasoby prawne",
@@ -588,8 +585,7 @@
         "video": "Wideo",
         "video_room": "Pokój wideo",
         "view_message": "Wyświetl wiadomość",
-        "warning": "Ostrzeżenie",
-        "welcome": "Witaj"
+        "warning": "Ostrzeżenie"
     },
     "composer": {
         "autocomplete": {
@@ -918,6 +914,9 @@
             "warning": "Jeśli nie usunąłeś metody odzyskiwania, atakujący może próbować dostać się na Twoje konto. Zmień hasło konta i natychmiast ustaw nową metodę odzyskiwania w Ustawieniach."
         },
         "reset_all_button": "Zapomniałeś lub straciłeś wszystkie opcje odzyskiwania? <a>Resetuj wszystko</a>",
+        "set_up_recovery": "Skonfiguruj przywracanie",
+        "set_up_recovery_later": "Nie teraz",
+        "set_up_recovery_toast_description": "Wygeneruj klucz przywracania, którego można użyć do przywrócenia zaszyfrowanej historii wiadomości w przypadku utraty dostępu do swoich urządzeń.",
         "set_up_toast_description": "Zabezpiecz się przed utratą dostępu do szyfrowanych wiadomości i danych",
         "set_up_toast_title": "Skonfiguruj bezpieczną kopię zapasową",
         "setup_secure_backup": {
@@ -1468,8 +1467,6 @@
         "notification_settings_beta_caption": "Przedstawiamy prostszy sposób zmiany ustawień powiadomień. Dostosuj %(brand)s wedle swojego upodobania.",
         "notification_settings_beta_title": "Ustawienia powiadomień",
         "notifications": "Włącz panel powiadomień w nagłówku pokoju.",
-        "oidc_native_flow": "Uwierzytelnianie natywne OIDC",
-        "oidc_native_flow_description": "⚠ OSTRZEŻENIE: Funkcja eksperymentalna. Użyj uwierzytelniania natywnego OIDC, gdy jest wspierane przez serwer.",
         "release_announcement": "Ogłoszenie o wydaniu",
         "render_reaction_images": "Renderuj niestandardowe obrazy w reakcjach",
         "render_reaction_images_description": "Czasami określane jako \"emoji niestandardowe\".",
@@ -1591,7 +1588,6 @@
     "member_list": {
         "filter_placeholder": "Filtruj członków pokoju",
         "invite_button_no_perms_tooltip": "Nie posiadasz uprawnień, aby zapraszać użytkowników",
-        "invited_list_heading": "Zaproszeni",
         "power_label": "%(userName)s (moc uprawnień administratorskich %(powerLevelNumber)s)"
     },
     "member_list_back_action_label": "Członkowie pokoju",
@@ -1638,62 +1634,15 @@
         "m.key.verification.request": "%(name)s prosi o weryfikację"
     },
     "onboarding": {
-        "apple_trademarks": "App Store® i logo Apple® są znakami towarowymi Apple Inc.",
-        "community_messaging_action": "Znajdź swoich ludzi",
-        "community_messaging_description": "Zatrzymaj własność i kontroluj dyskusję społeczności.\nRozwijaj się, aby wspierać miliony za pomocą potężnych narzędzi moderatorskich i interoperacyjnością.",
-        "community_messaging_title": "Własność społeczności",
-        "complete_these": "Wykonaj je, aby jak najlepiej wykorzystać %(brand)s",
         "create_room": "Utwórz czat grupowy",
-        "download_app": "Pobierz %(brand)s",
-        "download_app_action": "Pobierz aplikacje",
-        "download_app_description": "Nie przegap niczego zabierając %(brand)s ze sobą",
-        "download_app_store": "Pobierz w App Store",
-        "download_brand": "Pobierz %(brand)s",
-        "download_brand_desktop": "Pobierz %(brand)s Desktop",
-        "download_f_droid": "Pobierz w F-Droid",
-        "download_google_play": "Pobierz w Google Play",
-        "enable_notifications": "Włącz powiadomienia na pulpicie",
-        "enable_notifications_action": "Otwórz ustawienia",
-        "enable_notifications_description": "Nie przegap odpowiedzi lub ważnej wiadomości",
         "explore_rooms": "Przeglądaj pokoje publiczne",
-        "find_community_members": "Znajdź i zaproś członków swojej społeczności",
-        "find_coworkers": "Znajdź i zaproś swoich współpracowników",
-        "find_friends": "Znajdź i zaproś swoich znajomych",
-        "find_friends_action": "Znajdź znajomych",
-        "find_friends_description": "Po to tu jesteś, więc bierzmy się do roboty",
-        "find_people": "Znajdź osoby",
-        "free_e2ee_messaging_unlimited_voip": "Za pomocą darmowych wiadomości szyfrowanych end-to-end i nielimitowanymi rozmowami głosowymi i wideo, %(brand)s jest świetnym sposobem, aby pozostać w kontakcie.",
-        "get_stuff_done": "Załatwiaj sprawy znajdując swoich znajomych",
-        "google_trademarks": "Google Play i logo Google Play są znakami towarowymi Google LLC.",
         "has_avatar_label": "Świetnie, pomoże to innym Cię rozpoznać",
         "intro_byline": "Bądź właścicielem swoich konwersacji.",
         "intro_welcome": "Witamy w %(appName)s",
         "no_avatar_label": "Dodaj zdjęcie, aby inni mogli Cię rozpoznać.",
-        "only_n_steps_to_go": {
-            "one": "Jeszcze tylko %(count)s krok",
-            "few": "Jeszcze tylko %(count)s kroki",
-            "many": "Jeszcze tylko %(count)s kroków"
-        },
-        "personal_messaging_action": "Zacznij swoją pierwszą rozmowę",
-        "personal_messaging_title": "Bezpieczna komunikacja dla znajomych i rodziny",
-        "qr_or_app_links": "%(qrCode)s lub %(appLinks)s",
         "send_dm": "Wyślij wiadomość prywatną",
-        "set_up_profile": "Utwórz swój profil",
-        "set_up_profile_action": "Twój profil",
-        "set_up_profile_description": "Upewnij się, że osoby wiedzą, że to naprawdę ty",
-        "use_case_community_messaging": "Członkowie społeczności online",
-        "use_case_heading1": "Wszedłeś",
-        "use_case_heading2": "Z kim będziesz najczęściej rozmawiał?",
-        "use_case_heading3": "Pomożemy Ci pozostać w kontakcie.",
-        "use_case_personal_messaging": "Przyjaciele i rodzina",
-        "use_case_work_messaging": "Współpracownicy i drużyny",
         "welcome_detail": "Teraz pomożemy Ci zacząć",
-        "welcome_to_brand": "Witaj w %(brand)s",
-        "welcome_user": "Witaj, %(name)s",
-        "work_messaging_action": "Znajdź swoich współpracowników",
-        "work_messaging_title": "Bezpieczna komunikacja w pracy",
-        "you_did_it": "Udało ci się!",
-        "you_made_it": "Udało ci się!"
+        "welcome_user": "Witaj, %(name)s"
     },
     "pill": {
         "permalink_other_room": "Wiadomość w %(room)s",
@@ -1745,7 +1694,6 @@
         "custom_level": "Własny poziom",
         "default": "Domyślne",
         "label": "Poziom uprawnień",
-        "mod": "Moderator",
         "moderator": "Moderator",
         "restricted": "Ograniczony"
     },
@@ -2115,7 +2063,8 @@
         "show_less": "Pokaż mniej",
         "show_n_more": {
             "one": "Pokaż %(count)s więcej",
-            "other": "Pokaż %(count)s więcej"
+            "few": "Pokaż %(count)s więcej",
+            "many": "Pokaż %(count)s więcej"
         },
         "show_previews": "Pokazuj podgląd wiadomości",
         "sort_by": "Sortuj według",
@@ -2512,8 +2461,8 @@
             "discovery_email_empty": "Opcje odkrywania pojawią się, gdy dodasz adres e-mail.",
             "discovery_email_verification_instructions": "Zweryfikuj link w swojej skrzynce odbiorczej",
             "discovery_msisdn_empty": "Opcje odkrywania pojawią się, gdy dodasz numer telefonu.",
-            "discovery_needs_terms": "Wyrażasz zgodę na warunki użytkowania serwera%(serverName)s aby pozwolić na odkrywanie Ciebie za pomocą adresu e-mail oraz numeru telefonu.",
-            "discovery_needs_terms_title": "Pozwól ludziom Cię znaleźć",
+            "discovery_needs_terms": "Musisz wyrazić zgodę na warunki świadczenia usług serwera (%(serverName)s), aby umożliwić odkrywanie Cię za pomocą adresu e-mail oraz numeru telefonu.",
+            "discovery_needs_terms_title": "Zezwól ludziom na znalezienie Cię",
             "display_name": "Wyświetlana nazwa",
             "display_name_error": "Nie można ustawić wyświetlanej nazwy",
             "email_address_in_use": "Podany adres e-mail jest już w użyciu",
@@ -2699,7 +2648,6 @@
             "room_directory_heading": "Katalog pokoju",
             "room_list_heading": "Lista pokojów",
             "show_avatars_pills": "Pokaż awatary w wzmiankach użytkownika, pokoju i wydarzenia",
-            "show_checklist_shortcuts": "Pokaż skrót do listy powitalnej nad listą pokojów",
             "show_polls_button": "Pokaż przycisk ankiet",
             "surround_text": "Otocz zaznaczony tekst podczas wpisywania specjalnych znaków",
             "time_heading": "Wyświetlanie czasu",
@@ -3078,7 +3026,6 @@
         "invite": "Zaproś osoby",
         "invite_description": "Zaproś przy użyciu adresu email lub nazwy użytkownika",
         "invite_link": "Udostępnij link zaproszenia",
-        "invite_this_space": "Zaproś do tej przestrzeni",
         "joining_space": "Dołączanie",
         "landing_welcome": "Witamy w <name/>",
         "leave_dialog_action": "Opuść przestrzeń",
@@ -3175,7 +3122,7 @@
         "identity_server_no_terms_description_1": "Ta czynność wymaga dostępu do domyślnego serwera tożsamości <server /> do walidacji adresu e-mail, czy numeru telefonu, ale serwer nie określa warunków korzystania z usługi.",
         "identity_server_no_terms_description_2": "Kontynuj tylko wtedy, gdy ufasz właścicielowi serwera.",
         "identity_server_no_terms_title": "Serwer tożsamości nie posiada warunków użytkowania",
-        "inline_intro_text": "Zaakceptuj <policyLink /> aby kontynuować:",
+        "inline_intro_text": "Zaakceptuj <policyLink />, aby kontynuować:",
         "integration_manager": "Używaj botów, mostków, widżetów i zestawów naklejek",
         "intro": "Aby kontynuować, musisz zaakceptować zasady użytkowania.",
         "summary_identity_server_1": "Odnajdź innych z użyciem numeru telefonu lub adresu e-mail",
@@ -3689,7 +3636,8 @@
             "close": "Zamknij podgląd",
             "show_n_more": {
                 "one": "Pokaż %(count)s inny podgląd",
-                "other": "Pokaż %(count)s innych podglądów"
+                "few": "Pokaż %(count)s inne podglądy",
+                "many": "Pokaż %(count)s innych podglądów"
             }
         }
     },
diff --git a/src/i18n/strings/pt.json b/src/i18n/strings/pt.json
new file mode 100644
index 00000000000..d8d9857c6db
--- /dev/null
+++ b/src/i18n/strings/pt.json
@@ -0,0 +1,3940 @@
+{
+    "a11y": {
+        "emoji_picker": "Selecionador de emojis",
+        "jump_first_invite": "Salta para o primeiro convite.",
+        "message_composer": "Compositor de mensagens",
+        "n_unread_messages": {
+            "one": "1 mensagem não lida.",
+            "other": "%(count)s mensagens não lidas."
+        },
+        "n_unread_messages_mentions": {
+            "one": "1 menção não lida.",
+            "other": "%(count)s mensagens não lidas, incluindo menções."
+        },
+        "recent_rooms": "Salas recentes",
+        "room_name": "Sala %(name)s",
+        "room_status_bar": "Barra de estado da sala",
+        "seek_bar_label": "Barra de procura de áudio",
+        "unread_messages": "Mensagens não lidas",
+        "user_menu": "Menu do utilizador"
+    },
+    "a11y_jump_first_unread_room": "Salta para a primeira sala não lida.",
+    "action": {
+        "accept": "Aceitar",
+        "add": "Adicionar",
+        "add_existing_room": "Adicionar sala existente",
+        "add_people": "Adicionar pessoas",
+        "apply": "Aplicar",
+        "approve": "Aprovar",
+        "ask_to_join": "Pedir para participar",
+        "back": "Voltar",
+        "call": "Ligar",
+        "cancel": "Cancelar",
+        "change": "Alterar",
+        "clear": "Limpar",
+        "click": "Clica",
+        "click_to_copy": "Clica para copiar",
+        "close": "Fechar",
+        "collapse": "Colapsar",
+        "complete": "Completo",
+        "confirm": "Confirmar",
+        "continue": "Continuar",
+        "copy": "Copiar",
+        "copy_link": "Copiar Link",
+        "create": "Criar",
+        "create_a_room": "Criar uma sala",
+        "decline": "Recusar",
+        "delete": "Apagar",
+        "deny": "Negar",
+        "disable": "Desativar",
+        "disconnect": "Desconectar",
+        "dismiss": "Descartar",
+        "done": "Concluído",
+        "download": "Descarregar",
+        "edit": "Editar",
+        "enable": "Ativar",
+        "enter_fullscreen": "Entra no ecrã completo",
+        "exit_fullscreeen": "Sai do ecrã completo",
+        "expand": "Expandir",
+        "explore_public_rooms": "Explorar salas públicas",
+        "explore_rooms": "Explorar rooms",
+        "export": "Exportar",
+        "forward": "Encaminhar",
+        "go": "Ir",
+        "go_back": "Voltar",
+        "got_it": "Entendi",
+        "hide_advanced": "Ocultar avançado",
+        "hold": "Espera",
+        "ignore": "Ignorar",
+        "import": "Importar",
+        "invite": "Convidar",
+        "invite_to_space": "Convida para o espaço",
+        "invites_list": "Convidar",
+        "join": "Participar",
+        "learn_more": "Saiba mais",
+        "leave": "Sair",
+        "leave_room": "Sair da sala",
+        "logout": "Sair",
+        "manage": "Gerir",
+        "maximise": "Maximizar",
+        "mention": "Mencionar",
+        "minimise": "Minimizar",
+        "new_room": "Nova sala",
+        "new_video_room": "Nova sala de vídeo",
+        "next": "Próximo",
+        "no": "Não",
+        "ok": "OK",
+        "pause": "Pausar",
+        "pin": "Fixar",
+        "play": "Reproduzir",
+        "proceed": "Prosseguir",
+        "quote": "Citar",
+        "react": "Reagir",
+        "refresh": "Atualizar",
+        "register": "Registar",
+        "reject": "Rejeitar",
+        "reload": "Recarregar",
+        "remove": "Remover",
+        "rename": "Renomear",
+        "reply": "Responder",
+        "reply_in_thread": "Responder no tópico",
+        "report_content": "Denunciar conteúdo",
+        "resend": "Reenviar",
+        "reset": "Redefinir",
+        "resume": "Retoma",
+        "retry": "Tentar novamente",
+        "review": "Rever",
+        "revoke": "Revogar",
+        "save": "Salvar",
+        "search": "Pesquisar",
+        "send_report": "Enviar relatório",
+        "set_avatar": "Definir foto de perfil",
+        "share": "Partilhar",
+        "show": "Mostrar",
+        "show_advanced": "Mostrar avançado",
+        "show_all": "Mostrar tudo",
+        "sign_in": "Entrar",
+        "sign_out": "Sair",
+        "skip": "Saltar",
+        "start": "Iniciar",
+        "start_chat": "Iniciar conversa",
+        "start_new_chat": "Inicia um novo chat",
+        "stop": "Parar",
+        "submit": "Enviar",
+        "subscribe": "Subscrever",
+        "transfer": "Transfere",
+        "trust": "Confiar",
+        "try_again": "Tente novamente",
+        "unban": "Desfazer banimento",
+        "unignore": "Deixar de ignorar",
+        "unpin": "Desafixar",
+        "unsubscribe": "Cancelar subscrição",
+        "update": "Atualizar",
+        "upgrade": "Atualizar",
+        "upload": "Carregar",
+        "upload_file": "Carregar ficheiro",
+        "verify": "Verificar",
+        "view": "Ver",
+        "view_all": "Ver tudo",
+        "view_list": "Ver lista",
+        "view_message": "Ver mensagem",
+        "view_source": "Ver a fonte",
+        "yes": "Sim",
+        "zoom_in": "Ampliar",
+        "zoom_out": "Reduzir"
+    },
+    "analytics": {
+        "accept_button": "Não faz mal",
+        "bullet_1": "Nós <Bold>não</Bold> registamos nem traçamos o perfil de quaisquer dados da conta",
+        "bullet_2": "Nós <Bold>não</Bold> partilhamos informações com terceiros",
+        "consent_migration": "Anteriormente, tinhas consentido em partilhar connosco dados de utilização anónimos. Estamos a atualizar a forma como isso funciona.",
+        "disable_prompt": "Podes desativar esta opção em qualquer altura nas definições",
+        "enable_prompt": "Ajuda a melhorar %(analyticsOwner)s",
+        "learn_more": "Partilha dados anónimos para nos ajudar a identificar problemas. Nada de pessoal. Não há terceiros. <LearnMoreLink>Aprende mais</LearnMoreLink>",
+        "privacy_policy": "Podes ler todos os nossos termos <PrivacyPolicyUrl>aqui</PrivacyPolicyUrl>",
+        "pseudonymous_usage_data": "Ajuda-nos a identificar problemas e a melhorar o %(analyticsOwner)s, partilhando dados de utilização anónimos. Para compreender como as pessoas utilizam vários dispositivos, geraremos um identificador aleatório, partilhado pelos teus dispositivos.",
+        "shared_data_heading": "Pode ser partilhado qualquer um dos seguintes dados:"
+    },
+    "auth": {
+        "3pid_in_use": "Esse endereço de e-mail ou número de telefone já está a ser utilizado.",
+        "account_clash": "A tua nova conta (%(newAccountId)s) está registada, mas já estás ligado a uma conta diferente (%(loggedInUserId)s).",
+        "account_clash_previous_account": "Continua com a conta anterior",
+        "account_deactivated": "Esta conta foi desativada.",
+        "autodiscovery_generic_failure": "Falha ao obter a configuração de descoberta automática do servidor",
+        "autodiscovery_hs_incompatible": "O teu servidor doméstico é demasiado antigo e não suporta a versão mínima da API necessária. Contata o proprietário do teu servidor ou atualiza o teu servidor.",
+        "autodiscovery_invalid": "Resposta de descoberta de servidor doméstico inválida",
+        "autodiscovery_invalid_hs": "O URL do servidor doméstico não parece ser um servidor doméstico Matrix válido",
+        "autodiscovery_invalid_hs_base_url": "Base_url inválida para m.homeserver",
+        "autodiscovery_invalid_is": "O URL do servidor de identidade não parece ser um servidor de identidade válido",
+        "autodiscovery_invalid_is_base_url": "Base_url inválido para m.identity_server",
+        "autodiscovery_invalid_is_response": "Resposta de descoberta de servidor de identidade inválida",
+        "autodiscovery_invalid_json": "JSON inválido",
+        "autodiscovery_no_well_known": "Não foi encontrado nenhum ficheiro JSON .well-known",
+        "autodiscovery_unexpected_error_hs": "Erro inesperado ao resolver a configuração do servidor doméstico",
+        "autodiscovery_unexpected_error_is": "Erro inesperado ao resolver a configuração do servidor de identidade",
+        "captcha_description": "Este servidor doméstico gostaria de ter a certeza de que não és um robô.",
+        "change_password_action": "Alterar Palavra-Passe",
+        "change_password_confirm_invalid": "As palavras-passe não coincidem",
+        "change_password_confirm_label": "Confirmar palavra-passe",
+        "change_password_current_label": "Palavra-passe atual",
+        "change_password_empty": "As palavras-passe não podem estar vazias",
+        "change_password_error": "Erro ao alterar a palavra-passe: %(error)s",
+        "change_password_mismatch": "As novas palavras-passe não coincidem",
+        "change_password_new_label": "Nova Palavra-Passe",
+        "check_email_explainer": "Segue as instruções enviadas para <b>%(email)s</b>",
+        "check_email_resend_prompt": "Não recebeste?",
+        "check_email_resend_tooltip": "E-mail com link de verificação reenviado!",
+        "check_email_wrong_email_button": "Volta a introduzir o endereço de e-mail",
+        "check_email_wrong_email_prompt": "Endereço de e-mail errado?",
+        "continue_with_idp": "Continuar com %(provider)s",
+        "continue_with_sso": "Continua com %(ssoButtons)s",
+        "country_dropdown": "Lista suspensa de países",
+        "create_account_prompt": "Novo aqui? <a>Crie uma conta</a>",
+        "create_account_title": "Criar conta",
+        "email_discovery_text": "Use email para, opcionalmente, ser detectável por contactos existentes.",
+        "email_field_label": "E-mail",
+        "email_field_label_invalid": "Não parece ser um endereço de correio eletrónico válido",
+        "email_field_label_required": "Insere o endereço de e-mail",
+        "email_help_text": "Adicione um email para poder repôr a palavra-passe.",
+        "email_phone_discovery_text": "Use email ou telefone para, opcionalmente, ser detectável por contactos existentes.",
+        "enter_email_explainer": "<b>%(homeserver)s</b> enviar-te-á uma link de verificação para que possas redefinir a tua palavra-passe.",
+        "enter_email_heading": "Introduz o teu e-mail para redefinir a palavra-passe",
+        "failed_connect_identity_server": "Não é possível aceder o servidor de identidade",
+        "failed_connect_identity_server_other": "Podes iniciar sessão, mas algumas funcionalidades estarão indisponíveis até o servidor de identidade estar novamente online. Se continuares a ver este aviso, verifica a tua configuração ou contacta um administrador do servidor.",
+        "failed_connect_identity_server_register": "Podes registar-te, mas algumas funcionalidades não estarão disponíveis até que o servidor de identidade esteja novamente online. Se continuares a ver este aviso, verifica a tua configuração ou contacta um administrador do servidor.",
+        "failed_connect_identity_server_reset_password": "Podes repor a tua palavra-passe, mas algumas funcionalidades ficarão indisponíveis até o servidor de identidade estar novamente online. Se continuares a ver este aviso, verifica a tua configuração ou contacta um administrador do servidor.",
+        "failed_homeserver_discovery": "Falha na descoberta do servidor doméstico",
+        "failed_query_registration_methods": "Não é possível consultar os métodos de registo suportados.",
+        "failed_soft_logout_auth": "Falha ao autenticar novamente",
+        "failed_soft_logout_homeserver": "Falha ao autenticar novamente devido a um problema no servidor doméstico",
+        "forgot_password_email_invalid": "O endereço de e-mail não parece ser válido.",
+        "forgot_password_email_required": "O endereço de email relacionado a sua conta precisa ser informado.",
+        "forgot_password_prompt": "Esqueceste-te da tua palavra-passe?",
+        "forgot_password_send_email": "Enviar e-mail",
+        "identifier_label": "Quero entrar",
+        "incorrect_credentials": "Nome de utilizador e/ou palavra-passe incorreta.",
+        "incorrect_credentials_detail": "Tem em atenção que estás a iniciar sessão no servidor %(hs)s e não em matrix.org.",
+        "incorrect_password": "Palavra-passe incorreta",
+        "log_in_new_account": "<a>Inicia sessão em</a> na tua nova conta.",
+        "logout_dialog": {
+            "description": "Tens a certeza que queres encerrar a sessão?",
+            "megolm_export": "Exportação manual de chaves",
+            "setup_key_backup_title": "Perderás o acesso às tuas mensagens encriptadas",
+            "setup_secure_backup_description_1": "As mensagens encriptadas são protegidas com encriptação de ponta a ponta. Só tu e o(s) destinatário(s) têm as chaves para ler estas mensagens.",
+            "setup_secure_backup_description_2": "Quando terminares a sessão, estas chaves serão eliminadas deste dispositivo, o que significa que não poderás ler mensagens encriptadas, a menos que tenhas as chaves para elas nos teus outros dispositivos ou tenhas feito uma cópia de segurança das mesmas no servidor.",
+            "skip_key_backup": "Não quero as minhas mensagens encriptadas",
+            "use_key_backup": "Começa a utilizar a Cópia de Segurança das Chaves"
+        },
+        "misconfigured_body": "Pede ao teu administrador %(brand)s para verificar <a>a tua configuração</a> para ver se há entradas incorretas ou duplicadas.",
+        "misconfigured_title": "O teu %(brand)s está mal configurado",
+        "msisdn_field_description": "Outros utilizadores podem convidar-te para salas utilizando os teus dados de contacto",
+        "msisdn_field_label": "Telefone",
+        "msisdn_field_number_invalid": "Este número de telefone não parece estar correto, por favor verifica e tenta novamente",
+        "msisdn_field_required_invalid": "Introduz o número de telefone",
+        "no_hs_url_provided": "Nenhum URL de servidor doméstico fornecido",
+        "oidc": {
+            "error_title": "Não foi possível fazer login",
+            "generic_auth_error": "Algo correu mal durante a autenticação. Vai à página de início de sessão e tenta novamente.",
+            "missing_or_invalid_stored_state": "Pedimos ao navegador que se lembrasse do homeserver que usa para permitir o início de sessão, mas infelizmente o seu navegador esqueceu. Aceda à página de início de sessão e tente novamente."
+        },
+        "password_field_keep_going_prompt": "Continua...",
+        "password_field_label": "Introduz a palavra-passe",
+        "password_field_strong_label": "Uma palavra-passe boa e forte!",
+        "password_field_weak_label": "A palavra-passe é permitida, mas não é segura",
+        "phone_label": "Telefone",
+        "phone_optional_label": "Telefone (opcional)",
+        "qr_code_login": {
+            "check_code_explainer": "Isto irá verificar se a ligação ao teu outro dispositivo é segura.",
+            "check_code_heading": "Introduz o número que aparece no teu outro dispositivo",
+            "check_code_input_label": "Código de 2 dígitos",
+            "check_code_mismatch": "Os números não correspondem",
+            "completing_setup": "A concluir a configuração do teu novo dispositivo",
+            "error_etag_missing": "Ocorreu um erro inesperado. Isso pode ser devido a uma extensão do navegador, servidor proxy ou configuração incorreta do servidor.",
+            "error_expired": "O teu login expirou. Por favor, tenta novamente.",
+            "error_expired_title": "O início de sessão não foi concluído a tempo",
+            "error_insecure_channel_detected": "Não foi possível estabelecer uma ligação segura com o novo dispositivo. Os teus dispositivos existentes continuam seguros e não precisas de te preocupar com eles.",
+            "error_insecure_channel_detected_instructions": "E agora?",
+            "error_insecure_channel_detected_instructions_1": "Tenta iniciar sessão no outro dispositivo novamente com um código QR, caso se trate de um problema de rede",
+            "error_insecure_channel_detected_instructions_2": "Se tiveres o mesmo problema, experimenta uma rede Wi-Fi diferente ou utiliza os teus dados móveis em vez da rede Wi-Fi",
+            "error_insecure_channel_detected_instructions_3": "Se isso não funcionar, inicia sessão manualmente",
+            "error_insecure_channel_detected_title": "Ligação não segura",
+            "error_other_device_already_signed_in": "Não precisas de fazer mais nada.",
+            "error_other_device_already_signed_in_title": "O teu outro dispositivo já tem sessão iniciada",
+            "error_rate_limited": "Demasiadas tentativas num curto espaço de tempo. Espera algum tempo antes de tentares novamente.",
+            "error_unexpected": "Ocorreu um erro inesperado.",
+            "error_unsupported_protocol": "Este dispositivo não suporta o início de sessão no outro dispositivo com um código QR.",
+            "error_unsupported_protocol_title": "Outro dispositivo não compatível",
+            "error_user_cancelled": "O início de sessão foi cancelado no outro dispositivo.",
+            "error_user_cancelled_title": "Pedido de início de sessão cancelado",
+            "error_user_declined": "Tu ou o fornecedor da conta recusaram o pedido de início de sessão.",
+            "error_user_declined_title": "Inicio de sessão recusado",
+            "follow_remaining_instructions": "Segue as restantes instruções para verificar o teu outro dispositivo",
+            "open_element_other_device": "Abre a %(brand)s no teu outro dispositivo",
+            "point_the_camera": "Aponta a câmara para o código QR mostrado aqui",
+            "scan_code_instruction": "Lê o código QR com outro dispositivo",
+            "scan_qr_code": "Ler código QR",
+            "security_code": "Código de segurança",
+            "security_code_prompt": "Se solicitado, insira o código abaixo no seu outro dispositivo.",
+            "select_qr_code": "Seleciona \"%(scanQRCode)s\"",
+            "waiting_for_device": "A aguardar que o dispositivo inicie sessão"
+        },
+        "register_action": "Criar conta",
+        "registration": {
+            "continue_without_email_description": "Apenas um aviso, se não adicionar um email e depois esquecer a sua palavra-passe, poderá <b>perder permanentemente o acesso à sua conta</b>.",
+            "continue_without_email_field_label": "E-mail (opcional)",
+            "continue_without_email_title": "Continuando sem e-mail"
+        },
+        "registration_disabled": "O registo foi desativado neste servidor doméstico.",
+        "registration_msisdn_field_required_invalid": "Introduz o número de telefone (obrigatório neste servidor doméstico)",
+        "registration_successful": "Registo efetuado com êxito!",
+        "registration_username_in_use": "Alguém já tem esse nome de utilizador. Tente outro ou, se fores tu, inicia sessão em baixo.",
+        "registration_username_unable_check": "Não foi possível verificar se o nome de utilizador já foi usado. Tente novamente mais tarde.",
+        "registration_username_validation": "Utiliza apenas letras minúsculas, números, travessões e sublinhados",
+        "reset_password": {
+            "confirm_new_password": "Confirmar nova palavra-passe",
+            "devices_logout_success": "Saíste de todos os dispositivos e já não receberás notificações push. Para voltar a ativar as notificações, inicia sessão novamente em cada dispositivo.",
+            "other_devices_logout_warning_1": "Terminares a sessão dos teus dispositivos, elimina as chaves de encriptação de mensagens armazenadas nos mesmos, tornando ilegível o histórico de conversações encriptadas.",
+            "other_devices_logout_warning_2": "Se quiseres manter o acesso ao teu histórico de conversação em salas encriptadas, configura a Cópia de segurança das chaves ou exporta as chaves das mensagens de um dos teus outros dispositivos antes de prosseguires.",
+            "password_not_entered": "Deve ser introduzida uma nova palavra-passe.",
+            "passwords_mismatch": "Novas palavras-passe devem coincidir.",
+            "rate_limit_error": "Demasiadas tentativas num curto espaço de tempo. Espera algum tempo antes de tentares novamente.",
+            "rate_limit_error_with_time": "Demasiadas tentativas num curto espaço de tempo. Volta a tentar depois de %(timeout)s.",
+            "reset_successful": "A tua palavra-passe foi redefinida.",
+            "return_to_login": "Retornar à tela de login",
+            "sign_out_other_devices": "Termina a sessão em todos os dispositivos"
+        },
+        "reset_password_action": "Repor a palavra-passe",
+        "reset_password_button": "Esqueceste-te da palavra-passe?",
+        "reset_password_email_field_description": "Usar um endereço de email para recuperar a sua conta",
+        "reset_password_email_field_required_invalid": "Insere o endereço de e-mail (obrigatório neste servidor doméstico)",
+        "reset_password_email_not_associated": "O seu endereço de email não parece estar associado a um Matrix ID neste homeserver.",
+        "reset_password_email_not_found_title": "Este endereço de email não foi encontrado",
+        "reset_password_title": "Redefine a tua palavra-passe",
+        "server_picker_custom": "Outro servidor doméstico",
+        "server_picker_description": "Podes utilizar as opções personalizadas do servidor para iniciar sessão noutros servidores Matrix, especificando um URL de servidor doméstico diferente. Isto permite-te usar %(brand)s com uma conta Matrix existente num servidor doméstico diferente.",
+        "server_picker_description_matrix.org": "Junte-se a milhões gratuitamente no maior servidor público",
+        "server_picker_dialog_title": "Decide onde a tua conta está alojada",
+        "server_picker_explainer": "Usa o teu servidor doméstico Matrix preferido, se tiveres um, ou aloja o teu próprio servidor.",
+        "server_picker_failed_validate_homeserver": "Não foi possível validar o servidor doméstico",
+        "server_picker_intro": "Chamamos aos locais onde podes alojar a tua conta 'servidores domésticos'.",
+        "server_picker_invalid_url": "URL inválido",
+        "server_picker_learn_more": "Sobre servidores domésticos",
+        "server_picker_matrix.org": "Matrix.org é o maior servidor doméstico público do mundo, por isso é um bom lugar para muitos.",
+        "server_picker_required": "Especifica um servidor doméstico",
+        "server_picker_title": "Hospedar conta em",
+        "server_picker_title_default": "Opções de servidor",
+        "server_picker_title_registration": "Hospedar conta em",
+        "session_logged_out_description": "Por questões de segurança, esta sessão foi encerrada. Por gentileza conecte-se novamente.",
+        "session_logged_out_title": "Deslogar",
+        "set_email": {
+            "description": "Isto irá permitir-lhe redefinir a sua palavra-passe e receber notificações.",
+            "verification_pending_description": "Por favor verifique seu email e clique no link enviado. Quando finalizar este processo, clique para continuar.",
+            "verification_pending_title": "Verificação pendente"
+        },
+        "set_email_prompt": "Deseja definir um endereço de e-mail?",
+        "sign_in_description": "Use a sua conta para continuar.",
+        "sign_in_instead": "Já tem uma conta? <a>Entre aqui</a>",
+        "sign_in_instead_prompt": "Já tem uma conta? <a>Entre aqui</a>",
+        "sign_in_or_register": "Iniciar Sessão ou Criar Conta",
+        "sign_in_or_register_description": "Use a sua conta ou crie uma nova conta para continuar.",
+        "sign_in_prompt": "Tens uma conta? <a>Inicia sessão</a>",
+        "sign_in_with_sso": "Inicia sessão com o início de sessão único",
+        "signing_in": "A iniciar sessão...",
+        "soft_logout": {
+            "clear_data_button": "Limpa todos os dados",
+            "clear_data_description": "Limpa todos os dados desta sessão de forma permanente. As mensagens encriptadas perder-se-ão, a não ser que tenhas feito uma cópia de segurança das suas chaves.",
+            "clear_data_title": "Limpar todos os dados nesta sessão?"
+        },
+        "soft_logout_heading": "Estás desconectado",
+        "soft_logout_intro_password": "Introduz a tua palavra-passe para iniciar sessão e recuperar o acesso à tua conta.",
+        "soft_logout_intro_sso": "Inicia sessão e recupera o acesso à tua conta.",
+        "soft_logout_intro_unsupported_auth": "Não é possível iniciar sessão na tua conta. Contacta o administrador do teu servidor doméstico para obteres mais informações.",
+        "soft_logout_subheading": "Limpar dados pessoais",
+        "soft_logout_warning": "Aviso: os teus dados pessoais (incluindo chaves de encriptação) ainda estão armazenados nesta sessão. Limpa-a se já tiveres terminado de utilizar esta sessão ou se quiseres iniciar sessão noutra conta.",
+        "sso": "Registo único",
+        "sso_failed_missing_storage": "Pedimos ao navegador que se lembrasse do homeserver que usa para permitir o início de sessão, mas infelizmente o seu navegador esqueceu. Aceda à página de início de sessão e tente novamente.",
+        "sso_or_username_password": "%(ssoButtons)s Ou %(usernamePassword)s",
+        "sync_footer_subtitle": "Se já te juntaste a muitas salas, isto pode demorar um pouco",
+        "syncing": "A sincronizar...",
+        "uia": {
+            "code": "Código",
+            "email": "Para criar a sua conta, abra a ligação no email que acabámos de enviar para %(emailAddress)s.",
+            "email_auth_header": "Verifica o teu e-mail para continuar",
+            "email_resend_prompt": "Não o recebeste? <a>Reenvia-o</a>",
+            "email_resent": "Reenviado!",
+            "fallback_button": "Iniciar autenticação",
+            "msisdn": "Foi enviada uma mensagem de texto para %(msisdn)s",
+            "msisdn_token_incorrect": "Token incorreto",
+            "msisdn_token_prompt": "Por favor, entre com o código que está na mensagem:",
+            "password_prompt": "Confirma a tua identidade introduzindo a palavra-passe da tua conta abaixo.",
+            "recaptcha_missing_params": "Falta a chave pública do captcha na configuração do servidor doméstico. Por favor, informa o administrador do teu servidor doméstico.",
+            "registration_token_label": "Ficha de registo",
+            "registration_token_prompt": "Introduz um token de registo fornecido pelo administrador do servidor doméstico.",
+            "sso_body": "Confirme adicionar este endereço de email usando Single Sign On para provar a sua identidade.",
+            "sso_failed": "Algo correu mal ao confirmar a tua identidade. Cancela e tenta novamente.",
+            "sso_postauth_body": "Clica no botão abaixo para confirmar a tua identidade.",
+            "sso_postauth_title": "Confirma para continuar",
+            "sso_preauth_body": "Para continuar, utiliza o início de sessão único para provar a tua identidade.",
+            "sso_title": "Use Single Sign On para continuar",
+            "terms": "Por favor, revê e aceita as políticas deste servidor doméstico:",
+            "terms_invalid": "Revê e aceita todas as políticas do servidor doméstico"
+        },
+        "unsupported_auth": "Este servidor doméstico não oferece nenhum fluxo de início de sessão que seja suportado por este cliente.",
+        "unsupported_auth_email": "Este servidor doméstico não suporta o início de sessão utilizando endereço de e-mail.",
+        "unsupported_auth_msisdn": "Este servidor não permite a autenticação através de números de telefone.",
+        "username_field_required_invalid": "Introduza um nome de utilizador",
+        "username_in_use": "Alguém já tem esse nome de utilizador, tente outro por favor.",
+        "verify_email_explainer": "Precisamos de saber se és tu antes de redefinir a tua palavra-passe. Clica no link do e-mail que acabámos de enviar para <b>%(email)s</b>",
+        "verify_email_heading": "Verifica o teu e-mail para continuar"
+    },
+    "bug_reporting": {
+        "additional_context": "Se houver algum contexto adicional que possa ajudar a analisar o problema, como o que estavas a fazer na altura, IDs de salas, IDs de utilizadores, etc., inclui-o aqui.",
+        "before_submitting": "Antes de enviar os registos, deves <a>criar um problema no GitHub</a> para descrever o teu problema.",
+        "collecting_information": "A recolher informação da versão da app",
+        "collecting_logs": "A recolher logs",
+        "create_new_issue": "Por favor <newIssueLink>cria um novo problema</newIssueLink> no GitHub para que possamos investigar este erro.",
+        "description": "Os registos de depuração contêm dados de utilização da aplicação, incluindo o seu nome de utilizador, os IDs ou pseudónimos das salas que visitou, os últimos elementos da IU com que interagiu e os nomes de utilizador de outros utilizadores. No entanto não contêm mensagens.",
+        "download_logs": "Descarrega os registos",
+        "downloading_logs": "Descarregando registos",
+        "error_empty": "Diz-nos o que correu mal ou, melhor ainda, cria uma questão no GitHub que descreva o problema.",
+        "failed_send_logs": "Falha ao enviar registos: ",
+        "github_issue": "Problema no GitHub",
+        "introduction": "Se submeteste um erro através do GitHub, os registos de depuração podem ajudar-nos a localizar o problema. ",
+        "log_request": "Para nos ajudar a evitar esta situação no futuro, envia-nos os registos para <a></a> .",
+        "logs_sent": "Registos enviados",
+        "matrix_security_issue": "Para comunicar um problema de segurança relacionado com o Matrix, lê a Política de Divulgação de Segurança do Matrix.org <a></a> .",
+        "preparing_download": "Preparar para descarregar registos",
+        "preparing_logs": "Prepara o envio de registos",
+        "send_logs": "Enviar relatórios de erro",
+        "submit_debug_logs": "Envia registos de depuração",
+        "textarea_label": "Notas",
+        "thank_you": "Obrigado!",
+        "title": "Relatório de erros",
+        "unsupported_browser": "Lembrete: O teu browser não é suportado, pelo que a tua experiência pode ser imprevisível.",
+        "uploading_logs": "Carregando registos",
+        "waiting_for_server": "À espera de resposta do servidor"
+    },
+    "cannot_invite_without_identity_server": "Não é possível convidar um utilizador por email sem um servidor de identidade. Pode ligar-se a um em \"Definições\".",
+    "cannot_reach_homeserver": "Não é possível acessar o servidor doméstico",
+    "cannot_reach_homeserver_detail": "Certifica-te de que tens uma ligação estável à Internet ou entra em contacto com o administrador do servidor",
+    "cant_load_page": "Não foi possível carregar a página",
+    "chat_card_back_action_label": "Volta ao chat",
+    "chat_effects": {
+        "confetti_description": "Envia a mensagem dada com confetes",
+        "confetti_message": "envia confetes",
+        "fireworks_description": "Envia a mensagem dada com fogo de artifício",
+        "fireworks_message": "envia fogo de artifício",
+        "hearts_description": "Envia a mensagem dada com corações",
+        "hearts_message": "envia corações",
+        "rainfall_description": "Envia a mensagem dada com chuva",
+        "rainfall_message": "envia chuva",
+        "snowfall_description": "Envia a mensagem dada com queda de neve",
+        "snowfall_message": "envia queda de neve",
+        "spaceinvaders_description": "Envia a mensagem dada com um efeito temático espacial",
+        "spaceinvaders_message": "envia invasores do espaço"
+    },
+    "common": {
+        "access_token": "Token de acesso",
+        "accessibility": "Acessibilidade",
+        "advanced": "Avançado",
+        "all_rooms": "Todas as salas",
+        "analytics": "Análise",
+        "and_n_others": {
+            "other": "e %(count)s outros...",
+            "one": "e um outro..."
+        },
+        "appearance": "Aparência",
+        "application": "Aplicação",
+        "are_you_sure": "Você tem certeza?",
+        "attachment": "Anexo",
+        "authentication": "Autenticação",
+        "avatar": "Avatar",
+        "beta": "Beta",
+        "camera": "Câmera de vídeo",
+        "cameras": "Câmaras",
+        "cancel": "Cancelar",
+        "capabilities": "Capacidades",
+        "copied": "Copiado!",
+        "credits": "Créditos",
+        "cross_signing": "Assinatura cruzada",
+        "dark": "Escuro",
+        "description": "Descrição",
+        "deselect_all": "Desmarcar todos",
+        "device": "Dispositivo",
+        "edited": "editado",
+        "email_address": "Endereço de email",
+        "emoji": "Emoji",
+        "encrypted": "Encriptado",
+        "encryption_enabled": "Encriptação ativada",
+        "error": "Erro",
+        "faq": "Perguntas frequentes",
+        "favourites": "Favoritos",
+        "feedback": "Comentários",
+        "filter_results": "Filtrar resultados",
+        "forward_message": "Encaminhar mensagem",
+        "general": "Geral",
+        "go_to_settings": "Ir para as definições",
+        "guest": "Convidado",
+        "help": "Ajuda",
+        "historical": "Histórico",
+        "home": "Início",
+        "homeserver": "Servidor doméstico",
+        "identity_server": "Servidor de identidade",
+        "image": "Imagem",
+        "integration_manager": "Gestor de integração",
+        "joined": "Aderiu",
+        "labs": "Laboratório",
+        "legal": "Legal",
+        "light": "Claro",
+        "loading": "A carregar…",
+        "lobby": "Átrio",
+        "location": "Localização",
+        "low_priority": "Baixa prioridade",
+        "matrix": "Matrix",
+        "message": "Mensagem",
+        "message_layout": "Disposição da mensagem",
+        "microphone": "Microfone",
+        "model": "Modelo",
+        "modern": "Moderno",
+        "mute": "Silenciar",
+        "n_members": {
+            "one": "%(count)smembro",
+            "other": "%(count)smembros"
+        },
+        "n_rooms": {
+            "one": "%(count)s sala",
+            "other": "%(count)s salas"
+        },
+        "name": "Nome",
+        "no_results": "Sem resultados",
+        "no_results_found": "Nenhum resultado encontrado",
+        "not_trusted": "Não confiável",
+        "off": "Desativado",
+        "offline": "Offline",
+        "on": "Ativado",
+        "options": "Opções",
+        "orphan_rooms": "Outras salas",
+        "password": "Palavra-Passe",
+        "people": "Pessoas",
+        "preferences": "Preferências",
+        "presence": "Presença",
+        "preview_message": "Olá para ti. És o melhor!",
+        "privacy": "Privacidade",
+        "private": "Privado",
+        "private_room": "Sala privada",
+        "private_space": "Espaço privado",
+        "profile": "Perfil",
+        "public": "Público",
+        "public_room": "Sala pública",
+        "public_space": "Espaço público",
+        "qr_code": "Código QR",
+        "random": "Aleatório",
+        "reactions": "Reações",
+        "report_a_bug": "Comunicar falha",
+        "room": "Sala",
+        "room_name": "Nome da sala",
+        "rooms": "Salas",
+        "save": "Gravar",
+        "saved": "Guardado",
+        "saving": "A guardar…",
+        "secure_backup": "Cópia de segurança segura",
+        "security": "Segurança",
+        "select_all": "Selecionar tudo",
+        "server": "Servidor",
+        "settings": "Configurações",
+        "setup_secure_messages": "Configurar mensagens seguras",
+        "show_more": "Mostrar mais",
+        "someone": "Alguém",
+        "space": "Espaço",
+        "spaces": "Espaços",
+        "sticker": "Autocolante",
+        "stickerpack": "Pacote de autocolantes",
+        "success": "Sucesso",
+        "suggestions": "Sugestões",
+        "support": "Suporte",
+        "system_alerts": "Alertas do sistema",
+        "theme": "Tema",
+        "thread": "Tópico",
+        "threads": "Tópicos",
+        "timeline": "Cronologia",
+        "trusted": "Confiável",
+        "unavailable": "indisponível",
+        "unencrypted": "Não encriptado",
+        "unmute": "Tirar do mudo",
+        "unnamed_room": "Sala sem nome",
+        "unnamed_space": "Espaço sem nome",
+        "unverified": "Não verificado",
+        "updating": "Atualizando...",
+        "user": "Utilizador",
+        "user_avatar": "Foto do perfil",
+        "username": "Nome de utilizador",
+        "verification_cancelled": "Verificação cancelada",
+        "verified": "Verificado",
+        "version": "Versão",
+        "video": "Vídeo",
+        "video_room": "Sala de vídeo",
+        "view_message": "Ver mensagem",
+        "warning": "Aviso"
+    },
+    "composer": {
+        "autocomplete": {
+            "@room_description": "Notifica toda a sala",
+            "command_a11y": "Preenchimento automático de comando",
+            "command_description": "Comandos",
+            "emoji_a11y": "Preenchimento automático de emojis",
+            "notification_a11y": "Preenchimento automático de notificações",
+            "notification_description": "Notificação de sala",
+            "room_a11y": "Preenchimento automático da sala",
+            "space_a11y": "Preenchimento automático de espaço",
+            "user_a11y": "Preenchimento automático do utilizador",
+            "user_description": "Usuários"
+        },
+        "close_sticker_picker": "Esconde os autocolantes",
+        "edit_composer_label": "Editar mensagem",
+        "format_bold": "Negrito",
+        "format_code_block": "Bloco de Código",
+        "format_decrease_indent": "Diminuição do recuo",
+        "format_increase_indent": "Aumento do recuo",
+        "format_inline_code": "Código",
+        "format_insert_link": "Inserir link",
+        "format_italic": "Itálico",
+        "format_italics": "Itálico",
+        "format_link": "Ligação",
+        "format_ordered_list": "Lista numerada",
+        "format_strikethrough": "Rasurado",
+        "format_underline": "Sublinhado",
+        "format_unordered_list": "Lista com marcadores",
+        "formatting_toolbar_label": "Formatação",
+        "link_modal": {
+            "link_field_label": "Ligação",
+            "text_field_label": "Texto",
+            "title_create": "Crie um link",
+            "title_edit": "Editar link"
+        },
+        "mode_plain": "Ocultar formatação",
+        "mode_rich_text": "Mostrar formatação",
+        "no_perms_notice": "Você não tem permissão de postar nesta sala",
+        "placeholder": "Envia uma mensagem...",
+        "placeholder_encrypted": "Envia uma mensagem encriptada...",
+        "placeholder_reply": "Envia uma resposta...",
+        "placeholder_reply_encrypted": "Envia uma resposta encriptada...",
+        "placeholder_thread": "Responde ao tópico...",
+        "placeholder_thread_encrypted": "Responde a tópico encriptado...",
+        "poll_button": "Sondagem",
+        "poll_button_no_perms_description": "Não tens autorização para iniciar sondagens nesta sala.",
+        "poll_button_no_perms_title": "Permissão Requerida",
+        "replying_title": "A responder",
+        "room_upgraded_link": "A conversa continua aqui.",
+        "room_upgraded_notice": "Esta sala foi substituída e já não está ativa.",
+        "send_button_title": "Enviar mensagem",
+        "send_button_voice_message": "Enviar mensagem de voz",
+        "send_voice_message": "Envia mensagem de voz",
+        "stop_voice_message": "Pára a gravação",
+        "voice_message_button": "Mensagem de voz"
+    },
+    "console_dev_note": "Se sabes o que estás a fazer, a Element é de código aberto, não te esqueças de consultar o nosso GitHub (https://github.com/vector-im/element-web/) e contribuir!",
+    "console_scam_warning": "Se alguém te disse para copiar/colar algo aqui, há uma grande probabilidade de estares a ser enganado!",
+    "console_wait": "Espera!",
+    "create_room": {
+        "action_create_room": "Criar uma sala",
+        "action_create_video_room": "Cria uma sala de vídeo",
+        "encrypted_video_room_warning": "Não podes desativar isto mais tarde. A sala será encriptada, mas a chamada incorporada não.",
+        "encrypted_warning": "Não podes desativar isto mais tarde. As pontes e a maioria dos bots ainda não funcionarão.",
+        "encryption_forced": "O teu servidor requer que a encriptação seja activada em salas privadas.",
+        "encryption_label": "Ativar a encriptação de ponta a ponta",
+        "error_title": "Não foi possível criar a sala",
+        "generic_error": "O servidor pode estar indisponível ou sobrecarregado, ou então você encontrou uma falha no sistema.",
+        "join_rule_change_notice": "Podes alterar isto em qualquer altura a partir das definições da sala.",
+        "join_rule_invite": "Sala privada (só para convidados)",
+        "join_rule_invite_label": "Apenas as pessoas convidadas poderão encontrar e entrar nesta sala.",
+        "join_rule_knock_label": "Qualquer pessoa pode pedir para entrar, mas os administradores ou moderadores têm de conceder acesso. Podes alterar isto mais tarde.",
+        "join_rule_public_label": "Qualquer pessoa pode encontrar e entrar nesta sala.",
+        "join_rule_public_parent_space_label": "Qualquer pessoa poderá encontrar e juntar-se a esta sala, não apenas os membros de <SpaceName/>.",
+        "join_rule_restricted": "Visível para os membros do espaço",
+        "join_rule_restricted_label": "Todos em <SpaceName/> poderão encontrar e juntar-se a esta sala.",
+        "name_validation_required": "Introduz um nome para a sala",
+        "room_visibility_label": "Visibilidade da sala",
+        "title_private_room": "Cria uma sala privada",
+        "title_public_room": "Cria uma sala pública",
+        "title_video_room": "Cria uma sala de vídeo",
+        "topic_label": "Tópico (opcional)",
+        "unfederated": "Bloqueia qualquer pessoa que não faça parte de %(serverName)s de entrar nesta sala.",
+        "unfederated_label_default_off": "Podes ativar esta opção se a sala for usada apenas para colaborar com equipas internas no teu servidor doméstico. Isto não pode ser alterado mais tarde.",
+        "unfederated_label_default_on": "Podes desativar esta opção se a sala for utilizada para colaborar com equipas externas que tenham o seu próprio servidor doméstico. Isto não pode ser alterado mais tarde.",
+        "unsupported_version": "O servidor não suporta a versão especificada da sala."
+    },
+    "create_space": {
+        "add_details_prompt": "Acrescenta alguns pormenores para que as pessoas o reconheçam.",
+        "add_details_prompt_2": "Podes alterar isto em qualquer altura.",
+        "add_existing_rooms_description": "Escolhe salas ou conversas para adicionar. Este é apenas um espaço para ti, ninguém será informado. Podes adicionar mais depois.",
+        "add_existing_rooms_heading": "O que queres organizar?",
+        "address_label": "Endereço",
+        "address_placeholder": "por exemplo, meu-espaço",
+        "creating": "A criar...",
+        "creating_rooms": "A criar salas...",
+        "done_action": "Vai ao meu espaço",
+        "done_action_first_room": "Vai para a minha primeira sala",
+        "explainer": "Os espaços são uma nova forma de agrupar divisões e pessoas. Que tipo de Espaço queres criar? Podes alterar isto mais tarde.",
+        "failed_create_initial_rooms": "Falha na criação de salas de espaço iniciais",
+        "failed_invite_users": "Falha ao convidar os seguintes utilizadores para o teu espaço: %(csvUsers)s",
+        "invite_teammates_by_username": "Convidar por nome de utilizador",
+        "invite_teammates_description": "Certifica-te de que as pessoas certas têm acesso. Podes convidar mais pessoas mais tarde.",
+        "invite_teammates_heading": "Convida os teus colegas de equipa",
+        "inviting_users": "A convidar...",
+        "label": "Cria um espaço",
+        "name_required": "Introduz um nome para o espaço",
+        "personal_space": "Apenas eu",
+        "personal_space_description": "Um espaço privado para organizares as tuas salas",
+        "private_description": "Só para convidados, melhor para ti ou para equipas",
+        "private_heading": "O teu espaço privado",
+        "private_personal_description": "Certifica-te de que as pessoas certas têm acesso a %(name)s",
+        "private_personal_heading": "Com quem estás a trabalhar?",
+        "private_space": "Eu e os meus colegas de equipa",
+        "private_space_description": "Um espaço privado para ti e para os teus colegas de equipa",
+        "public_description": "Espaço aberto para todos, melhor para as comunidades",
+        "public_heading": "O teu espaço público",
+        "search_public_button": "Procura espaços públicos",
+        "setup_rooms_community_description": "Vamos criar uma sala para cada um deles.",
+        "setup_rooms_community_heading": "Quais são algumas das coisas que queres discutir em %(spaceName)s?",
+        "setup_rooms_description": "Também podes acrescentar mais tarde, incluindo os já existentes.",
+        "setup_rooms_private_description": "Criaremos salas para cada um deles.",
+        "setup_rooms_private_heading": "Em que projectos está a tua equipa a trabalhar?",
+        "share_description": "Neste momento és só tu, mas será ainda melhor com outros.",
+        "share_heading": "Partilha %(name)s",
+        "skip_action": "Pular por agora",
+        "subspace_adding": "A adicionar...",
+        "subspace_beta_notice": "Adiciona um espaço a um espaço que geres.",
+        "subspace_dropdown_title": "Cria um espaço",
+        "subspace_existing_space_prompt": "Queres acrescentar um espaço existente?",
+        "subspace_join_rule_invite_description": "Apenas as pessoas convidadas poderão encontrar e juntar-se a este espaço.",
+        "subspace_join_rule_invite_only": "Espaço privado (só para convidados)",
+        "subspace_join_rule_label": "Visibilidade do espaço",
+        "subspace_join_rule_public_description": "Qualquer pessoa poderá encontrar e aderir a este espaço, não apenas os membros de <SpaceName/>.",
+        "subspace_join_rule_restricted_description": "Qualquer pessoa em <SpaceName/> poderá encontrar e aderir."
+    },
+    "credits": {
+        "default_cover_photo": "A fotografia de capa predefinida <photo></photo> é © <author>Jesús Roncero</author> utilizada nos termos de <terms>CC-BY-SA 4.0</terms>.",
+        "twemoji": "A arte do emoji <twemoji>Twemoji</twemoji> é © <author>Twitter, Inc e outros colaboradores</author> utilizada ao abrigo dos termos de <terms>CC-BY 4.0</terms>.",
+        "twemoji_colr": "O tipo de letra <colr>twemoji-colr</colr> é © <author>Mozilla Foundation</author> utilizado nos termos de <terms>Apache 2.0</terms>."
+    },
+    "devtools": {
+        "active_widgets": "Widgets ativos",
+        "category_other": "Outros",
+        "category_room": "Sala",
+        "caution_colon": "Atenção:",
+        "client_versions": "Versões de cliente",
+        "developer_mode": "Modo de desenvolvedor",
+        "developer_tools": "Ferramentas de desenvolvedor",
+        "edit_setting": "Editar configuração",
+        "edit_values": "Editar valores",
+        "empty_string": "<empty string>",
+        "event_content": "Conteúdo do evento",
+        "event_id": "ID do evento: %(eventId)s",
+        "event_sent": "Evento enviado!",
+        "event_type": "Tipo de evento",
+        "explore_account_data": "Explora os dados da conta",
+        "explore_room_account_data": "Explora os dados da conta da sala",
+        "explore_room_state": "Explora o estado da sala",
+        "failed_to_find_widget": "Houve um erro ao encontrar este widget.",
+        "failed_to_load": "Falhou ao carregar.",
+        "failed_to_save": "Falhou ao salvar as configurações.",
+        "failed_to_send": "Falha ao enviar evento!",
+        "id": "ID: ",
+        "invalid_json": "Não parece ser um JSON válido.",
+        "level": "Nível",
+        "low_bandwidth_mode": "Modo de baixa largura de banda",
+        "low_bandwidth_mode_description": "Requer um servidor doméstico compatível.",
+        "main_timeline": "Linha cronológica principal",
+        "no_receipt_found": "Nenhum recibo encontrado",
+        "notification_state": "O estado da notificação é <strong>%(notificationState)s</strong>",
+        "notifications_debug": "Depuração de notificações",
+        "number_of_users": "Número de utilizadores",
+        "original_event_source": "Fonte original do evento",
+        "room_encrypted": "A sala está <strong>encriptada ✅</strong>",
+        "room_id": "ID da sala:%(roomId)s",
+        "room_not_encrypted": "A sala <strong>não está encriptada🚨</strong>",
+        "room_notifications_dot": "Ponto: ",
+        "room_notifications_highlight": "Destaque: ",
+        "room_notifications_last_event": "Último evento:",
+        "room_notifications_sender": "Remetente: ",
+        "room_notifications_thread_id": "ID do tópico: ",
+        "room_notifications_total": "Total: ",
+        "room_notifications_type": "Escreve:",
+        "room_status": "Estado da sala",
+        "room_unread_status_count": {
+            "one": "Estado não lido da sala: <strong>%(status)s</strong>, contagem: <strong>%(count)s</strong>",
+            "other": "Estado não lido da sala: <strong>%(status)s</strong>, contagem: <strong>%(count)s</strong>"
+        },
+        "save_setting_values": "Guarda os valores de configuração",
+        "see_history": "Ver histórico",
+        "send_custom_account_data_event": "Enviar evento de dados de conta personalizado",
+        "send_custom_room_account_data_event": "Envia um evento personalizado de dados de conta de sala",
+        "send_custom_state_event": "Envia um evento de estado personalizado",
+        "send_custom_timeline_event": "Envia evento de cronograma personalizado",
+        "server_info": "Informação do servidor",
+        "server_versions": "Versões de servidor",
+        "settable_global": "Configurável em global",
+        "settable_room": "Configurável na sala",
+        "setting_colon": "Configuração:",
+        "setting_definition": "Definição de configuração:",
+        "setting_id": "ID de configuração",
+        "settings_explorer": "Explorador de definições",
+        "show_hidden_events": "Mostra eventos ocultos na linha do tempo",
+        "spaces": {
+            "one": "<space>",
+            "other": "<%(count)s spaces>"
+        },
+        "state_key": "Chave de estado",
+        "thread_root_id": "ID da raiz do tópico: %(threadRootId)s",
+        "threads_timeline": "Cronograma de tópicos",
+        "title": "Ferramentas de desenvolvedor",
+        "toggle_event": "alternar evento",
+        "toolbox": "Caixa de ferramentas",
+        "use_at_own_risk": "Esta interface de utilizador NÃO verifica os tipos dos valores. Utiliza-a por tua conta e risco.",
+        "user_read_up_to": "O utilizador leu até: ",
+        "user_read_up_to_ignore_synthetic": "O utilizador leu até (ignoreSynthetic): ",
+        "user_read_up_to_private": "O utilizador leu até (m.read.private): ",
+        "user_read_up_to_private_ignore_synthetic": "O utilizador lê até (m.read.private;ignoreSynthetic): ",
+        "value": "Valor",
+        "value_colon": "Valor:",
+        "value_in_this_room": "Valor nesta sala",
+        "value_this_room_colon": "Valor nesta sala:",
+        "values_explicit": "Valores a níveis explícitos",
+        "values_explicit_colon": "Valores a níveis explícitos:",
+        "values_explicit_room": "Valores em níveis explícitos nesta sala",
+        "values_explicit_this_room_colon": "Valores a níveis explícitos nesta sala:",
+        "view_servers_in_room": "Vê os servidores na sala",
+        "view_source_decrypted_event_source": "Fonte do evento desencriptado",
+        "view_source_decrypted_event_source_unavailable": "Fonte desencriptada indisponível",
+        "widget_screenshots": "Ativar capturas de ecrã de widgets em widgets suportados"
+    },
+    "dialog_close_label": "Fechar diálogo",
+    "emoji": {
+        "categories": "Categorias",
+        "category_activities": "Atividades",
+        "category_animals_nature": "Animais e Natureza",
+        "category_flags": "Bandeiras",
+        "category_food_drink": "Comida e Bebida",
+        "category_frequently_used": "Frequentemente utilizado",
+        "category_objects": "Objetos",
+        "category_smileys_people": "Carinhas Sorridentes e Pessoas",
+        "category_symbols": "Símbolos",
+        "category_travel_places": "Viagens e Locais",
+        "quick_reactions": "Reações rápidas"
+    },
+    "emoji_picker": {
+        "cancel_search_label": "Cancelar pesquisa"
+    },
+    "empty_room": "Sala vazia",
+    "empty_room_was_name": "Sala vazia (era %(oldName)s)",
+    "encryption": {
+        "access_secret_storage_dialog": {
+            "enter_phrase_or_key_prompt": "Introduz a tua frase de segurança ou <button>utiliza a tua chave de segurança</button> para continuar.",
+            "key_validation_text": {
+                "invalid_security_key": "Chave de segurança inválida",
+                "recovery_key_is_correct": "Parece bom!",
+                "wrong_file_type": "Tipo de ficheiro errado",
+                "wrong_security_key": "Chave de segurança errada"
+            },
+            "reset_title": "Repor tudo",
+            "reset_warning_1": "Faz isto apenas se não tiveres outro dispositivo para completar a verificação.",
+            "reset_warning_2": "Se reiniciares tudo, irás reiniciar sem sessões de confiança, sem utilizadores de confiança e poderás não conseguir ver mensagens anteriores.",
+            "restoring": "Restaurar chaves a partir de uma cópia de segurança",
+            "security_key_title": "Chave de segurança",
+            "security_phrase_incorrect_error": "Não é possível aceder ao armazenamento secreto. Verifica se introduziste a frase de segurança correcta.",
+            "security_phrase_title": "Frase de segurança",
+            "separator": "%(securityKey)s ou %(recoveryFile)s",
+            "use_security_key_prompt": "Utiliza a tua chave de segurança para continuar."
+        },
+        "bootstrap_title": "A configurar chaves",
+        "cancel_entering_passphrase_description": "Tem a certeza que quer cancelar a introdução da frase-passe?",
+        "cancel_entering_passphrase_title": "Cancelar a introdução da frase-passe?",
+        "confirm_encryption_setup_body": "Clica no botão abaixo para confirmar a configuração da encriptação.",
+        "confirm_encryption_setup_title": "Confirma a configuração da encriptação",
+        "cross_signing_not_ready": "A assinatura cruzada não está configurada.",
+        "cross_signing_ready": "A assinatura cruzada está pronta a ser utilizada.",
+        "cross_signing_ready_no_backup": "A assinatura cruzada está pronta, mas as chaves não têm cópia de segurança.",
+        "cross_signing_room_normal": "Esta sala é encriptada de ponta a ponta",
+        "cross_signing_room_verified": "Toda a gente nesta sala é verificada",
+        "cross_signing_room_warning": "Alguém está a utilizar uma sessão desconhecida",
+        "cross_signing_unsupported": "O teu servidor doméstico não suporta assinatura cruzada.",
+        "cross_signing_untrusted": "A tua conta tem uma identidade de assinatura cruzada no armazenamento secreto, mas ainda não é de confiança para esta sessão.",
+        "cross_signing_user_normal": "Não verificaste este utilizador.",
+        "cross_signing_user_verified": "Verificaste este utilizador. Este utilizador verificou todas as suas sessões.",
+        "cross_signing_user_warning": "Este utilizador não verificou todas as suas sessões.",
+        "destroy_cross_signing_dialog": {
+            "primary_button_text": "Chaves de assinatura cruzada claras",
+            "title": "Destrói as chaves de assinatura cruzada?",
+            "warning": "A eliminação das chaves de assinatura cruzada é permanente. Qualquer pessoa com quem tenhas feito a verificação verá alertas de segurança. É quase certo que não vais querer fazer isto, a menos que tenhas perdido todos os dispositivos a partir dos quais podes fazer a assinatura cruzada."
+        },
+        "event_shield_reason_authenticity_not_guaranteed": "A autenticidade desta mensagem encriptada não pode ser garantida neste dispositivo.",
+        "event_shield_reason_mismatched_sender_key": "Encriptado por uma sessão não verificada",
+        "event_shield_reason_unknown_device": "Encriptado por um dispositivo desconhecido ou apagado.",
+        "event_shield_reason_unsigned_device": "Encriptado por um dispositivo não verificado pelo seu proprietário.",
+        "event_shield_reason_unverified_identity": "Encriptado por um utilizador não verificado.",
+        "export_unsupported": "O seu navegador não suporta as extensões de criptografia necessárias",
+        "import_invalid_keyfile": "Não é um ficheiro de chaves %(brand)s válido",
+        "import_invalid_passphrase": "Erro de autenticação: palavra-passe incorreta?",
+        "messages_not_secure": {
+            "cause_1": "O teu servidor doméstico",
+            "cause_2": "O servidor doméstico ao qual o utilizador que estás a verificar está ligado",
+            "cause_3": "A tua ligação à Internet ou a dos outros utilizadores",
+            "cause_4": "A tua sessão, ou a dos outros utilizadores",
+            "heading": "Um dos seguintes elementos pode estar comprometido:",
+            "title": "As tuas mensagens não são seguras"
+        },
+        "new_recovery_method_detected": {
+            "description_1": "Foi detectada uma nova frase de segurança e uma nova chave para as mensagens seguras.",
+            "description_2": "Esta sessão está a encriptar o histórico utilizando o novo método de recuperação.",
+            "title": "Novo método de recuperação",
+            "warning": "Se não tiveres definido o novo método de recuperação, um atacante pode estar a tentar aceder à tua conta. Altera a palavra-passe da tua conta e define imediatamente um novo método de recuperação nas Definições."
+        },
+        "not_supported": "<não suportado>",
+        "recovery_method_removed": {
+            "description_1": "Esta sessão detectou que a tua frase de segurança e a chave para as mensagens seguras foram removidas.",
+            "description_2": "Se o fizeste acidentalmente, podes configurar as Mensagens seguras nesta sessão, o que criptografará novamente o histórico de mensagens desta sessão com um novo método de recuperação.",
+            "title": "Método de recuperação Removido",
+            "warning": "Se não tiveres removido o método de recuperação, um atacante pode estar a tentar aceder à tua conta. Altera a palavra-passe da tua conta e define imediatamente um novo método de recuperação nas Definições."
+        },
+        "reset_all_button": "Esqueceste-te ou perdeste todos os métodos de recuperação? <a>Repor tudo</a>",
+        "set_up_toast_description": "Protege-te contra a perda de acesso a mensagens e dados encriptados",
+        "set_up_toast_title": "Configura uma cópia de segurança segura",
+        "setup_secure_backup": {
+            "explainer": "Guarda as tuas chaves antes de saíres para evitar perdê-las.",
+            "title": "Configurar"
+        },
+        "udd": {
+            "interactive_verification_button": "Verifica interactivamente por emoji",
+            "other_ask_verify_text": "Pede a este utilizador para verificar a sua sessão ou verifica-a manualmente abaixo.",
+            "other_new_session_text": "%(name)s(%(userId)s ) entrou numa nova sessão sem verificá-la:",
+            "own_ask_verify_text": "Verifica a tua outra sessão utilizando uma das opções abaixo.",
+            "own_new_session_text": "Entraste numa nova sessão sem a verificar:",
+            "title": "Não é confiável"
+        },
+        "unable_to_setup_keys_error": "Não é possível configurar as chaves",
+        "unsupported": "Este cliente não suporta encriptação de ponta a ponta.",
+        "verification": {
+            "accepting": "Aceitando...",
+            "after_new_login": {
+                "device_verified": "Dispositivo verificado",
+                "reset_confirmation": "Repõe mesmo as chaves de verificação?",
+                "skip_verification": "Ignora a verificação por enquanto",
+                "unable_to_verify": "Não é possível verificar este dispositivo",
+                "verify_this_device": "Verifica este dispositivo"
+            },
+            "cancelled": "Cancelaste a verificação.",
+            "cancelled_self": "Cancelaste a verificação no teu outro dispositivo.",
+            "cancelled_user": "%(displayName)sverificação cancelada.",
+            "cancelling": "A cancelar…",
+            "complete_action": "Entendi",
+            "complete_description": "Verificaste este utilizador com sucesso.",
+            "complete_title": "Verificado!",
+            "error_starting_description": "Não foi possível iniciar uma conversa com o outro utilizador.",
+            "error_starting_title": "Erro ao iniciar a verificação",
+            "explainer": "As mensagens seguras com este utilizador são encriptadas de ponta a ponta e não podem ser lidas por terceiros.",
+            "in_person": "Para teres segurança, fá-lo pessoalmente ou utiliza um meio de comunicação de confiança.",
+            "incoming_sas_device_dialog_text_1": "Verifica este dispositivo para o marcar como fiável. Confiar neste dispositivo dá-te a ti e a outros utilizadores uma tranquilidade extra ao utilizarem mensagens encriptadas de ponta a ponta.",
+            "incoming_sas_device_dialog_text_2": "A verificação deste dispositivo irá marcá-lo como fiável e os utilizadores que tiverem verificado contigo irão confiar neste dispositivo.",
+            "incoming_sas_dialog_title": "Pedido de verificação recebido",
+            "incoming_sas_dialog_waiting": "Aguarda a confirmação do parceiro...",
+            "incoming_sas_user_dialog_text_1": "Verifica este utilizador para o marcar como fiável. A confiança nos utilizadores dá-te uma tranquilidade extra quando utilizas mensagens encriptadas de ponta a ponta.",
+            "incoming_sas_user_dialog_text_2": "A verificação deste utilizador marcará a sua sessão como sendo de confiança e também marcará a tua sessão como sendo de confiança para ele.",
+            "no_key_or_device": "Parece que não tens uma chave de segurança ou quaisquer outros dispositivos que possam ser verificados.  Este dispositivo não poderá aceder a mensagens encriptadas antigas. Para verificares a tua identidade neste dispositivo, terás de repor as tuas chaves de verificação.",
+            "no_support_qr_emoji": "O dispositivo que estás a tentar verificar não suporta a leitura de um código QR nem a verificação de emoji, os dois métodos suportados pela %(brand)s. Tenta com um cliente diferente.",
+            "other_party_cancelled": "A outra parte cancelou a verificação.",
+            "prompt_encrypted": "Verifica todos os utilizadores de uma sala para garantir a sua segurança.",
+            "prompt_self": "Inicia novamente a verificação a partir da notificação.",
+            "prompt_unencrypted": "Em salas encriptadas, verifica todos os utilizadores para garantir a segurança.",
+            "prompt_user": "Recomeça a verificação a partir do perfil.",
+            "qr_or_sas": "%(qrCode)s ou %(emojiCompare)s",
+            "qr_or_sas_header": "Verifica este dispositivo completando uma das seguintes opções:",
+            "qr_prompt": "Lê este código único",
+            "qr_reciprocate_same_shield_device": "Estás quase lá! O teu outro dispositivo está a mostrar o mesmo escudo?",
+            "qr_reciprocate_same_shield_user": "Estás quase lá! O %(displayName)s tem o mesmo escudo?",
+            "request_toast_accept": "Verifica a sessão",
+            "request_toast_accept_user": "Verificar utilizador",
+            "request_toast_decline_counter": "Ignora (%(counter)s)",
+            "request_toast_detail": "%(deviceId)s de %(ip)s",
+            "reset_proceed_prompt": "Procede à reposição",
+            "sas_caption_self": "Verifica este dispositivo, confirmando que o número seguinte aparece no ecrã.",
+            "sas_caption_user": "Verifica este utilizador, confirmando que o seguinte número aparece no ecrã deles.",
+            "sas_description": "Compara um conjunto único de emojis se não tiveres uma câmara em nenhum dos dispositivos",
+            "sas_emoji_caption_self": "Confirma se os emojis abaixo são apresentados em ambos os dispositivos, pela mesma ordem:",
+            "sas_emoji_caption_user": "Verifica este utilizador confirmando que o seguinte emoji aparece no seu ecrã.",
+            "sas_match": "Correspondem",
+            "sas_no_match": "Não correspondem",
+            "sas_prompt": "Compara emojis únicos",
+            "scan_qr": "Verifica através da leitura de um código",
+            "scan_qr_explainer": "Pede a %(displayName)s para ler o teu código:",
+            "self_verification_hint": "Para continuar, aceita o pedido de verificação no teu outro dispositivo.",
+            "start_button": "Iniciar Verificação",
+            "successful_device": "Verificaste com sucesso %(deviceName)s (%(deviceId)s)!",
+            "successful_own_device": "Verificaste o teu dispositivo com sucesso!",
+            "successful_user": "Verificaste com sucesso %(displayName)s!",
+            "timed_out": "A verificação expirou.",
+            "unsupported_method": "Não foi possível encontrar um método de verificação compatível.",
+            "unverified_session_toast_accept": "Sim, fui eu",
+            "unverified_session_toast_title": "Novo login. Foste tu?",
+            "unverified_sessions_toast_description": "Revê para garantir que a tua conta está segura",
+            "unverified_sessions_toast_reject": "Mais tarde",
+            "unverified_sessions_toast_title": "Tens sessões não verificadas",
+            "verification_description": "Verifica a tua identidade para acederes a mensagens encriptadas e provares a tua identidade a outros.",
+            "verification_dialog_title_device": "Verifica o outro dispositivo",
+            "verification_dialog_title_user": "Pedido de verificação",
+            "verification_skip_warning": "Sem a verificação, não terás acesso a todas as tuas mensagens e poderás parecer pouco fiável aos olhos dos outros.",
+            "verification_success_with_backup": "O teu novo dispositivo está agora verificado. Tem acesso às tuas mensagens encriptadas e os outros utilizadores vão considerá-lo de confiança.",
+            "verification_success_without_backup": "O teu novo dispositivo está agora verificado. Outros utilizadores irão vê-lo como sendo de confiança.",
+            "verify_emoji": "Verifica por emoji",
+            "verify_emoji_prompt": "Verifica comparando o emoji único.",
+            "verify_emoji_prompt_qr": "Se não conseguires ler o código acima, verifica-o comparando emojis.",
+            "verify_later": "Verificarei mais tarde",
+            "verify_reset_warning_1": "A reposição das tuas chaves de verificação não pode ser anulada. Após a reposição, não terás acesso a mensagens encriptadas antigas e todos os amigos que te tenham verificado anteriormente verão avisos de segurança até voltares a verificar com eles.",
+            "verify_reset_warning_2": "Só avances se tiveres a certeza de que perdeste todos os teus outros dispositivos e a tua chave de segurança.",
+            "verify_using_device": "Verifica com outro dispositivo",
+            "verify_using_key": "Verifica com a chave de segurança",
+            "verify_using_key_or_phrase": "Verifica com a chave ou frase de segurança",
+            "waiting_for_user_accept": "À espera de %(displayName)s para aceitar...",
+            "waiting_other_device": "À espera que verifiques no teu outro dispositivo...",
+            "waiting_other_device_details": "À espera que verifiques no teu outro dispositivo, %(deviceName)s (%(deviceId)s)...",
+            "waiting_other_user": "À espera de %(displayName)s para verificar..."
+        },
+        "verification_requested_toast_title": "Verificação solicitada",
+        "verify_toast_description": "Outros utilizadores podem não confiar nisto",
+        "verify_toast_title": "Verifica esta sessão"
+    },
+    "error": {
+        "admin_contact": "Por favor, <a>contacta o teu administrador de serviços</a> para continuares a utilizar este serviço.",
+        "admin_contact_short": "Contacta o teu administrador do servidor <a></a> .",
+        "connection": "Houve um problema de comunicação com o servidor doméstico, por favor tenta novamente mais tarde.",
+        "dialog_description_default": "Ocorreu um erro.",
+        "download_media": "Falha ao transferir o media de origem, não foi encontrado nenhum url de origem",
+        "edit_history_unsupported": "O teu servidor doméstico não parece suportar esta funcionalidade.",
+        "failed_copy": "Falha ao copiar",
+        "hs_blocked": "Este servidor doméstico foi bloqueado pelo seu administrador.",
+        "mau": "Este servidor doméstico atingiu o seu limite mensal de utilizadores activos.",
+        "mixed_content": "Não consigo conectar ao servidor padrão através de HTTP quando uma URL HTTPS está na barra de endereços do seu navegador. Use HTTPS ou então <a>habilite scripts não seguros no seu navegador</a>.",
+        "non_urgent_echo_failure_toast": "O teu servidor não está a responder a alguns pedidos <a></a> .",
+        "resource_limits": "Este servidor doméstico excedeu um dos seus limites de recursos.",
+        "session_restore": {
+            "clear_storage_button": "Limpa o armazenamento e encerra a sessão",
+            "clear_storage_description": "Termina a sessão e remove as chaves de encriptação?",
+            "description_1": "Encontrámos um erro ao tentar restaurar a tua sessão anterior.",
+            "description_2": "Se você já usou antes uma versão mais recente do %(brand)s, a sua sessão pode ser incompatível com esta versão. Feche esta janela e tente abrir com a versão mais recente.",
+            "description_3": "Limpar o armazenamento do teu browser pode resolver o problema, mas irá desconectar-te e fazer com que qualquer histórico de conversação encriptado se torne ilegível.",
+            "title": "Não foi possível restaurar a sessão"
+        },
+        "something_went_wrong": "Algo deu errado!",
+        "storage_evicted_description_1": "Alguns dados da sessão, incluindo chaves de mensagens encriptadas, estão em falta. Termina a sessão e inicia sessão para corrigir esta situação, restaurando as chaves a partir da cópia de segurança.",
+        "storage_evicted_description_2": "É provável que o teu browser tenha removido estes dados quando ficou com pouco espaço em disco.",
+        "storage_evicted_title": "Dados da sessão em falta",
+        "sync": "Não é possível ligar ao servidor doméstico. Tenta novamente...",
+        "tls": "Não foi possível conectar ao Servidor de Base. Por favor, confira sua conectividade à internet, garanta que o <a>certificado SSL do Servidor de Base</a> é confiável, e que uma extensão do navegador não esteja bloqueando as requisições de rede.",
+        "unknown": "Erro desconhecido",
+        "unknown_error_code": "código de erro desconhecido",
+        "update_power_level": "Não foi possível mudar o nível de permissões"
+    },
+    "error_app_open_in_another_tab": "Muda para o outro separador para te ligares a %(brand)s. Este separador pode agora ser fechado.",
+    "error_app_open_in_another_tab_title": "%(brand)s está ligado noutro separador",
+    "error_app_opened_in_another_window": "%(brand)s está aberto noutra janela. Clica em \"%(label)s\" para utilizares %(brand)s aqui e desligares a outra janela.",
+    "error_database_closed_description": {
+        "for_desktop": "O teu disco pode estar cheio. Limpa algum espaço e volta a carregar.",
+        "for_web": "Se limpaste os dados de navegação, esta mensagem é esperada. %(brand)s também pode estar aberto noutro separador ou o teu disco está cheio. Limpa algum espaço e volta a carregar"
+    },
+    "error_database_closed_title": "Base de dados fechada inesperadamente",
+    "error_dialog": {
+        "copy_room_link_failed": {
+            "description": "Não é possível copiar uma ligação à sala para a área de transferência.",
+            "title": "Não é possível copiar o link da sala"
+        },
+        "error_loading_user_profile": "Não foi possível carregar o perfil do utilizador",
+        "forget_room_failed": "Falha ao esquecer a sala %(errCode)s",
+        "search_failed": {
+            "server_unavailable": "O servidor pode estar indisponível, sobrecarregado, ou a busca ultrapassou o tempo limite :(",
+            "title": "Busca falhou"
+        }
+    },
+    "error_user_not_logged_in": "Utilizador não tem sessão iniciada",
+    "event_preview": {
+        "m.call.answer": {
+            "dm": "Chamada em curso",
+            "user": "%(senderName)s entrou na chamada",
+            "you": "Entraste na chamada"
+        },
+        "m.call.hangup": {
+            "user": "%(senderName)s terminou a chamada",
+            "you": "Terminaste a chamada"
+        },
+        "m.call.invite": {
+            "dm_receive": "%(senderName)s está a chamar",
+            "dm_send": "Aguarda a resposta",
+            "user": "%(senderName)s iniciou uma chamada",
+            "you": "Começaste uma chamada"
+        },
+        "m.emote": "* %(senderName)s %(emote)s",
+        "m.reaction": {
+            "user": "%(sender)s reagiu %(reaction)s a %(message)s",
+            "you": "Reagiste %(reaction)s a %(message)s"
+        },
+        "m.sticker": "%(senderName)s: %(stickerName)s",
+        "m.text": "%(senderName)s: %(message)s"
+    },
+    "export_chat": {
+        "cancelled": "Exportação cancelada",
+        "cancelled_detail": "A exportação foi cancelada com sucesso",
+        "confirm_stop": "Tens a certeza de que queres deixar de exportar os teus dados? Se tiveres, terás de começar de novo.",
+        "creating_html": "Gerando HTML…",
+        "creating_output": "Criando resultados...",
+        "creator_summary": "%(creatorName)s criou esta sala.",
+        "current_timeline": "Cronologia Atual",
+        "enter_number_between_min_max": "Introduz um número entre %(min)s e %(max)s",
+        "error_fetching_file": "Erro ao obter ficheiro",
+        "export_info": "Este é o início da exportação de <roomName/>. Exportado por <exporterDetails/> a %(exportDate)s.",
+        "export_successful": "Exportação bem sucedida!",
+        "exported_n_events_in_time": {
+            "one": "%(count)s evento exportado em %(seconds)s segundos",
+            "other": "%(count)s eventos exportados em %(seconds)s segundos"
+        },
+        "exporting_your_data": "Exportar os teus dados",
+        "fetched_n_events": {
+            "one": "Obteve %(count)s evento até agora",
+            "other": "Obteve %(count)s eventos até agora"
+        },
+        "fetched_n_events_in_time": {
+            "one": "%(count)s evento obtido em %(seconds)ss",
+            "other": "%(count)s eventos obtidos em %(seconds)ss"
+        },
+        "fetched_n_events_with_total": {
+            "one": "Obteve %(count)s evento de %(total)s",
+            "other": "Obteve %(count)s eventos de %(total)s"
+        },
+        "fetching_events": "Obtendo eventos...",
+        "file_attached": "Ficheiro anexo",
+        "format": "Formato",
+        "from_the_beginning": "Desde o início",
+        "generating_zip": "A gerar um ZIP",
+        "html": "HTML",
+        "html_title": "Dados Exportados",
+        "include_attachments": "Incluir anexos",
+        "json": "JSON",
+        "media_omitted": "Meios de comunicação omitidos",
+        "media_omitted_file_size": "Meios de comunicação omitidos - limite do tamanho do ficheiro excedido",
+        "messages": "Mensagens",
+        "next_page": "Próximo grupo de mensagens",
+        "num_messages": "Número de mensagens",
+        "num_messages_min_max": "O número de mensagens só pode ser um número entre %(min)s e %(max)s",
+        "number_of_messages": "Especifique um número de mensagens",
+        "previous_page": "Mensagens anteriores do grupo",
+        "processing": "Processando…",
+        "processing_event_n": "Evento de processamento %(number)s de %(total)s",
+        "select_option": "Selecciona uma das opções abaixo para exportar conversas da tua linha de tempo",
+        "size_limit": "Limite de tamanho",
+        "size_limit_min_max": "O tamanho só pode ser um número entre %(min)s MB e %(max)s MB",
+        "size_limit_postfix": "MB",
+        "starting_export": "Iniciando exportação...",
+        "successful": "Exportação bem-sucedida",
+        "successful_detail": "A tua exportação foi bem sucedida. Encontra-o na tua pasta de Transferências.",
+        "text": "Texto Simples",
+        "title": "Exportar Chat",
+        "topic": "Tópico: %(topic)s",
+        "unload_confirm": "Tem a certeza de que pretende sair durante esta exportação?"
+    },
+    "failed_load_async_component": "Impossível carregar! Verifique a sua ligação de rede e tente novamente.",
+    "feedback": {
+        "can_contact_label": "Podes contactar-me se tiveres alguma questão complementar",
+        "comment_label": "Comente",
+        "existing_issue_link": "Por favor, vê primeiro <existingIssuesLink>bugs existentes no Github</existingIssuesLink>. Não encontras nada? <newIssueLink>Inicia um novo</newIssueLink>.",
+        "may_contact_label": "Podes contactar-me se quiseres fazer um seguimento ou para me deixares testar ideias futuras",
+        "platform_username": "A sua plataforma e o seu nome de utilizador serão anotados para nos ajudar a utilizar o seu feedback da melhor forma possível.",
+        "pro_type": "DICA PRO: Se iniciares um bug, envia <debugLogsLink>debug logs</debugLogsLink> para nos ajudar a localizar o problema.",
+        "send_feedback_action": "Enviar comentários",
+        "sent": "Enviaste o teu feedback! Obrigado, agradecemos-te!"
+    },
+    "file_panel": {
+        "empty_description": "Anexa ficheiros a partir do chat ou arrasta-os e larga-os em qualquer parte da sala.",
+        "empty_heading": "Não há ficheiros visíveis nesta sala",
+        "guest_note": "Você deve <a>se registrar</a> para poder usar esta funcionalidade",
+        "peek_note": "Você precisa ingressar na sala para ver seus arquivos"
+    },
+    "forward": {
+        "filter_placeholder": "Procura salas ou pessoas",
+        "message_preview_heading": "Pré-visualização da mensagem",
+        "no_perms_title": "Não tens autorização para fazer isto",
+        "open_room": "Sala aberta",
+        "send_label": "Enviar",
+        "sending": "A enviar…",
+        "sent": "Enviado"
+    },
+    "identity_server": {
+        "change": "Altera o servidor de identidade",
+        "change_prompt": "Desligar do servidor de identidade <current /> e ligar a <new /> em vez disso?",
+        "change_server_prompt": "Se não pretenderes utilizar <server /> para descobrir e ser descoberto pelos contactos existentes que conheces, introduz outro servidor de identidade abaixo.",
+        "checking": "A verificar o servidor",
+        "description_connected": "Atualmente, estás a utilizar <server></server> para descobrires e seres descoberto pelos contactos existentes que conheces. Podes alterar o teu servidor de identidade abaixo.",
+        "description_disconnected": "Atualmente, não estás a utilizar um servidor de identidade. Para descobrires e seres descoberto pelos contactos existentes que conheces, adiciona um abaixo.",
+        "description_optional": "A utilização de um servidor de identidade é opcional. Se optares por não utilizar um servidor de identidade, não poderás ser descoberto por outros utilizadores e não poderás convidar outras pessoas por correio eletrónico ou telefone.",
+        "disconnect": "Desliga o servidor de identidade",
+        "disconnect_anyway": "Desliga de qualquer maneira",
+        "disconnect_offline_warning": "Deves <b>remover os teus dados pessoais</b> do servidor de identidade <idserver /> antes de te desconectares. Infelizmente, o servidor de identidade <idserver /> está atualmente offline ou não pode ser contactado.",
+        "disconnect_personal_data_warning_1": "Continuas a <b>partilhar os teus dados pessoais</b> no servidor de identidade <idserver />.",
+        "disconnect_personal_data_warning_2": "Recomendamos que remova seus endereços de email e números de telefone do servidor de identidade antes de se desconectar.",
+        "disconnect_server": "Desliga do servidor de identidade <idserver />?",
+        "disconnect_warning": "Se te desligares do teu servidor de identidade, não poderás ser descoberto por outros utilizadores e não poderás convidar outras pessoas por e-mail ou telefone.",
+        "do_not_use": "Não utilizes um servidor de identidade",
+        "error_connection": "Não foi possível ligar ao servidor de identidade",
+        "error_invalid": "Servidor de Identidade inválido (código de status %(code)s)",
+        "error_invalid_or_terms": "Os termos de serviço não foram aceites ou o servidor de identidade é inválido.",
+        "no_terms": "O servidor de identidade que escolheste não tem quaisquer termos de serviço.",
+        "suggestions": "Tu deves:",
+        "suggestions_1": "verifica se os plug-ins do teu browser não têm nada que possa bloquear o servidor de identidade (como o Privacy Badger)",
+        "suggestions_2": "contacta os administradores do servidor de identidade <idserver />",
+        "suggestions_3": "espera e tenta novamente mais tarde",
+        "url": "Servidor de identidade (%(server)s)",
+        "url_field_label": "Introduz um novo servidor de identidade",
+        "url_not_https": "O link do servidor de identidade deve começar com HTTPS"
+    },
+    "in_space": "Em %(spaceName)s.",
+    "in_space1_and_space2": "Nos espaços %(space1Name)s e %(space2Name)s.",
+    "in_space_and_n_other_spaces": {
+        "one": "Em %(spaceName)s e noutro espaço.",
+        "other": "Em %(spaceName)s e %(count)s outros espaços."
+    },
+    "info_tooltip_title": "Informação",
+    "integration_manager": {
+        "connecting": "Conectando ao gerenciador de integração…",
+        "error_connecting": "O gestor de integração está offline ou não consegue aceder ao teu servidor doméstico.",
+        "error_connecting_heading": "Não é possível conectar-se ao gerenciador de integração",
+        "explainer": "Os gestores de integração recebem dados de configuração e podem modificar widgets, enviar convites para salas e definir níveis de potência em teu nome.",
+        "manage_title": "Gere as integrações",
+        "use_im": "Utiliza um gestor de integração para gerir bots, widgets e pacotes de autocolantes.",
+        "use_im_default": "Utiliza um gestor de integração <b>(%(serverName)s)</b> para gerir bots, widgets e pacotes de autocolantes."
+    },
+    "integrations": {
+        "disabled_dialog_description": "Para isso, ativa '%(manageIntegrations)s' nas Definições.",
+        "disabled_dialog_title": "As integrações estão desativadas",
+        "impossible_dialog_description": "O teu %(brand)s não te permite utilizar um gestor de integração para o fazer. Contacta um administrador.",
+        "impossible_dialog_title": "Integrações não permitidas"
+    },
+    "invite": {
+        "ask_anyway_description": "Não foi possível encontrar perfis para os IDs de Matrix listados abaixo - gostarias de iniciar uma MD na mesma?",
+        "ask_anyway_label": "Começa a MD na mesma",
+        "ask_anyway_never_warn_label": "Começa a MD na mesma e não me avises mais",
+        "email_caption": "Convida por e-mail",
+        "email_limit_one": "Os convites por e-mail só podem ser enviados um de cada vez",
+        "email_use_default_is": "Utiliza um servidor de identidade para convidar por e-mail. <default>Utiliza a predefinição (%(defaultIdentityServerName)s)</default> ou gere em <settings>Definições</settings>.",
+        "email_use_is": "Utiliza um servidor de identidade para convidar por e-mail. Gere em <settings>Definições</settings>.",
+        "error_already_invited_room": "O utilizador já foi convidado para a sala",
+        "error_already_invited_space": "O utilizador já está convidado para o espaço",
+        "error_already_joined_room": "O utilizador já está na sala",
+        "error_already_joined_space": "O utilizador já se encontra no espaço",
+        "error_bad_state": "O utilizador tem de deixar de ser banido antes de poder ser convidado.",
+        "error_dm": "Não foi possível criar a tua DM.",
+        "error_find_room": "Algo correu mal ao tentar convidar os utilizadores.",
+        "error_find_user_description": "Os seguintes utilizadores podem não existir ou são inválidos e não podem ser convidados: %(csvNames)s",
+        "error_find_user_title": "Falha ao encontrar os seguintes utilizadores",
+        "error_invite": "Não foi possível convidar esses utilizadores. Verifica os utilizadores que pretendes convidar e tenta novamente.",
+        "error_permissions_room": "Não tens permissão para convidar pessoas para esta sala.",
+        "error_permissions_space": "Não tens permissão para convidar pessoas para este espaço.",
+        "error_profile_undisclosed": "O utilizador pode ou não existir",
+        "error_transfer_multiple_target": "Uma chamada só pode ser transferida para um único utilizador.",
+        "error_unfederated_room": "Esta sala não é federada. Não podes convidar pessoas de servidores externos.",
+        "error_unfederated_space": "Este espaço não está federado. Não podes convidar pessoas de servidores externos.",
+        "error_unknown": "Erro de servidor desconhecido",
+        "error_user_not_found": "O utilizador não existe",
+        "error_version_unsupported_room": "O servidor doméstico do utilizador não suporta a versão da sala.",
+        "error_version_unsupported_space": "O servidor doméstico do utilizador não suporta a versão do espaço.",
+        "failed_generic": "A operação falhou",
+        "failed_title": "Falha ao enviar o convite",
+        "invalid_address": "Endereço não reconhecido",
+        "name_email_mxid_share_room": "Convide alguém a partir do nome, email ou nome de utilizador (como <userId/>) ou <a>partilhe esta sala</a>.",
+        "name_email_mxid_share_space": "Convide alguém a partir do nome, endereço de email, nome de utilizador (como <userId/>) ou <a>partilhe este espaço</a>.",
+        "name_mxid_share_room": "Convida alguém utilizando o seu nome, nome de utilizador (como <userId/>) ou <a>partilha esta sala</a>.",
+        "name_mxid_share_space": "Convide alguém a partir do nome, nome de utilizador (como <userId/>) ou <a>partilhe este espaço</a>.",
+        "recents_section": "Conversas recentes",
+        "room_failed_partial": "Enviámos os outros, mas as pessoas abaixo não puderam ser convidadas para <RoomName/>",
+        "room_failed_partial_title": "Alguns convites não puderam ser enviados",
+        "room_failed_title": "Falha ao convidar utilizadores para %(roomName)s",
+        "send_link_prompt": "Ou envia o link de convite",
+        "start_conversation_name_email_mxid_prompt": "Comece uma conversa com alguém a partir do nome, endereço de email ou nome de utilizador (por exemplo: <userId/>).",
+        "start_conversation_name_mxid_prompt": "Comece uma conversa com alguém a partir do nome ou nome de utilizador (por exemplo: <userId/>).",
+        "suggestions_disclaimer": "Algumas sugestões podem estar ocultas por motivos de privacidade.",
+        "suggestions_disclaimer_prompt": "Se não conseguires ver quem procuras, envia-lhe o teu convite através do link abaixo.",
+        "suggestions_section": "Mensagens directas recentes",
+        "to_room": "Convida para %(roomName)s",
+        "to_space": "Convida para %(spaceName)s",
+        "transfer_dial_pad_tab": "Teclado numérico",
+        "transfer_user_directory_tab": "Diretório de utilizadores",
+        "unable_find_profiles_description_default": "Não foi possível encontrar perfis para os IDs de Matrix listados abaixo - gostarias de os convidar na mesma?",
+        "unable_find_profiles_invite_label_default": "Convida na mesma",
+        "unable_find_profiles_invite_never_warn_label_default": "Convida na mesma e nunca mais me avises",
+        "unable_find_profiles_title": "Os seguintes utilizadores podem não existir",
+        "unban_first_title": "O utilizador não pode ser convidado enquanto não for desbanido"
+    },
+    "inviting_user1_and_user2": "Convidando %(user1)s e %(user2)s",
+    "inviting_user_and_n_others": {
+        "other": "Convidando %(user)s e %(count)s outros",
+        "one": "Convidando %(user)s e 1 outro"
+    },
+    "items_and_n_others": {
+        "one": "<Items/>e um outro",
+        "other": "<Items/>e %(count)s outros"
+    },
+    "keyboard": {
+        "activate_button": "Ativar o botão selecionado",
+        "alt": "Alt",
+        "autocomplete_cancel": "Cancelar preenchimento automático",
+        "autocomplete_force": "Forçar a conclusão",
+        "autocomplete_navigate_next": "Próxima sugestão de preenchimento automático",
+        "autocomplete_navigate_prev": "Sugestão anterior de preenchimento automático",
+        "backspace": "Retrocesso",
+        "cancel_reply": "Cancelar a resposta a uma mensagem",
+        "category_autocomplete": "Preenchimento automático",
+        "category_calls": "Chamadas",
+        "category_navigation": "Navegação",
+        "category_room_list": "Lista de salas",
+        "close_dialog_menu": "Fecha a caixa de diálogo ou o menu de contexto",
+        "composer_jump_end": "Salta para o fim do compositor",
+        "composer_jump_start": "Salta para o início do compositor",
+        "composer_navigate_next_history": "Navega para a mensagem seguinte no histórico do compositor",
+        "composer_navigate_prev_history": "Navega para a mensagem anterior no histórico do compositor",
+        "composer_new_line": "Nova linha",
+        "composer_redo": "Refazer edição",
+        "composer_toggle_bold": "Alternar negrito",
+        "composer_toggle_code_block": "Alternar bloco de código",
+        "composer_toggle_italics": "Alternar itálico",
+        "composer_toggle_link": "Alternar link",
+        "composer_toggle_quote": "Alternar cotação",
+        "composer_undo": "Desfazer edição",
+        "control": "Ctrl",
+        "dismiss_read_marker_and_jump_bottom": "Ignora o marcador de leitura e salta para o fundo",
+        "end": "Fim",
+        "enter": "Entrar",
+        "escape": "Esc",
+        "go_home_view": "Vai para a Vista Inicial",
+        "home": "Início",
+        "jump_first_message": "Salta para a primeira mensagem",
+        "jump_last_message": "Salta para a última mensagem",
+        "jump_room_search": "Ir para a pesquisa de salas",
+        "jump_to_read_marker": "Salta para a mensagem mais antiga não lida",
+        "keyboard_shortcuts_tab": "Abre este separador de definições",
+        "navigate_next_history": "Próxima sala ou espaço visitado recentemente",
+        "navigate_next_message_edit": "Navega até à próxima mensagem para editar",
+        "navigate_prev_history": "Sala ou espaço anteriormente visitado recentemente",
+        "navigate_prev_message_edit": "Navega até à mensagem anterior para editar",
+        "next_landmark": "Vai para o próximo ponto de referência",
+        "next_room": "Próxima sala ou DM",
+        "next_unread_room": "Próxima sala não lida ou DM",
+        "number": "[número]",
+        "open_user_settings": "Abre as definições do utilizador",
+        "page_down": "Página para baixo",
+        "page_up": "Página para cima",
+        "prev_landmark": "Vai para o ponto de referência anterior",
+        "prev_room": "Sala anterior ou DM",
+        "prev_unread_room": "Sala anterior não lida ou DM",
+        "room_list_collapse_section": "Colapsar a secção da lista de salas",
+        "room_list_expand_section": "Expande a secção da lista de salas",
+        "room_list_navigate_down": "Navega para baixo na lista de salas",
+        "room_list_navigate_up": "Navega para cima na lista de salas",
+        "room_list_select_room": "Seleciona a sala na lista de salas",
+        "scroll_down_timeline": "Desloca-te para baixo na linha de tempo",
+        "scroll_up_timeline": "Desloca-te para cima na linha de tempo",
+        "search": "Pesquisa (deve estar ativada)",
+        "send_sticker": "Envia um autocolante",
+        "shift": "Muda",
+        "space": "Espaço",
+        "switch_to_space": "Passa para o espaço por número",
+        "toggle_hidden_events": "Alternar visibilidade de eventos ocultos",
+        "toggle_microphone_mute": "Alternar microfone mudo",
+        "toggle_right_panel": "Alternar painel direito",
+        "toggle_space_panel": "Alternar painel de espaço",
+        "toggle_top_left_menu": "Alternar o menu superior esquerdo",
+        "toggle_webcam_mute": "Ativar/desativar a webcam",
+        "upload_file": "Carrega um ficheiro"
+    },
+    "labs": {
+        "allow_screen_share_only_mode": "Permitir o modo de partilha de ecrã apenas",
+        "ask_to_join": "Permitir pedir para participar",
+        "automatic_debug_logs": "Envia automaticamente registos de depuração em qualquer erro",
+        "automatic_debug_logs_decryption": "Envia automaticamente registos de depuração em caso de erros de desencriptação",
+        "automatic_debug_logs_key_backup": "Envia automaticamente registos de depuração quando a cópia de segurança das chaves não está a funcionar",
+        "beta_description": "O que vais fazer a seguir em %(brand)s? Os laboratórios são a melhor forma de obteres informações antecipadas, testares novas funcionalidades e ajudares a moldá-las antes do seu lançamento efetivo.",
+        "beta_feature": "Esta é uma funcionalidade beta",
+        "beta_feedback_leave_button": "Para sair da versão beta, visita as tuas definições.",
+        "beta_feedback_title": "%(featureName)s Comentários sobre a versão beta",
+        "beta_section": "Próximas funcionalidades",
+        "bridge_state": "Mostrar informações sobre pontes nas definições da sala",
+        "bridge_state_channel": "Canal: <channelLink/>",
+        "bridge_state_creator": "Esta ponte foi fornecida por <user />.",
+        "bridge_state_manager": "Esta ponte é gerida por <user />.",
+        "bridge_state_workspace": "Espaço de trabalho: <networkLink/>",
+        "click_for_info": "Clica para mais informações",
+        "currently_experimental": "Atualmente experimental.",
+        "custom_themes": "Suporte a adicionar temas personalizados",
+        "dynamic_room_predecessors": "Antecessores de sala dinâmica",
+        "dynamic_room_predecessors_description": "Ativar MSC3946 (para suportar arquivos de salas que chegam tarde)",
+        "element_call_video_rooms": "Salas de Chamada de vídeo Element",
+        "experimental_description": "Estás a sentir-te experimental? Experimenta as nossas ideias mais recentes em desenvolvimento. Estas funcionalidades não estão finalizadas; podem ser instáveis, podem ser alteradas ou podem ser completamente abandonadas. <a>Sabe mais em</a>.",
+        "experimental_section": "Pré-visualizações antecipadas",
+        "feature_disable_call_per_sender_encryption": "Desativar a cifragem por remetente na Element Call",
+        "feature_wysiwyg_composer_description": "Utiliza texto rico em vez de Markdown no compositor de mensagens.",
+        "group_calls": "Nova experiência de chamada de grupo",
+        "group_developer": "Desenvolvedor",
+        "group_encryption": "Encriptação",
+        "group_experimental": "Experimental",
+        "group_messaging": "Mensagens",
+        "group_moderation": "Moderação",
+        "group_profile": "Perfil",
+        "group_rooms": "Salas",
+        "group_spaces": "Espaços",
+        "group_themes": "Temas",
+        "group_threads": "Tópicos",
+        "group_ui": "Interface do utilizador",
+        "group_voip": "Voz e vídeo",
+        "group_widgets": "Widgets",
+        "hidebold": "Ocultar o ponto de notificação (mostrar apenas os emblemas dos contadores)",
+        "html_topic": "Mostrar a representação HTML dos tópicos da sala",
+        "join_beta": "Junta-te à versão beta",
+        "join_beta_reload": "Se entrares na versão beta, recarregas o site %(brand)s.",
+        "jump_to_date": "Saltar para a data (adiciona cabeçalhos /jumptodate e saltar para a data)",
+        "jump_to_date_msc_support": "Requer que o seu servidor suporte o MSC3030",
+        "latex_maths": "Renderiza matemática LaTeX em mensagens",
+        "leave_beta": "Deixa a versão beta",
+        "leave_beta_reload": "Ao saíres da versão beta, recarregas o site %(brand)s.",
+        "location_share_live": "Partilha de localização em tempo real",
+        "location_share_live_description": "Implementação temporária. As localizações permanecem no histórico da sala.",
+        "mjolnir": "Novas formas de ignorar pessoas",
+        "msc3531_hide_messages_pending_moderation": "Permitir que os moderadores ocultem mensagens pendentes de moderação.",
+        "notification_settings": "Novas Definições de Notificação",
+        "notification_settings_beta_caption": "Apresentamos uma forma mais simples de alterar as tuas definições de notificação. Personaliza o teu %(brand)s, tal como gostas.",
+        "notification_settings_beta_title": "Definições de Notificação",
+        "notifications": "Ativar o painel de notificações no cabeçalho da sala",
+        "release_announcement": "Anúncio de lançamento",
+        "render_reaction_images": "Renderizar imagens personalizadas em reações",
+        "render_reaction_images_description": "Por vezes designados por \"emojis personalizados\".",
+        "report_to_moderators": "Denunciar aos moderadores",
+        "report_to_moderators_description": "Nas salas que suportam moderação, o botão \"Denunciar\" permite-te denunciar abusos aos moderadores da sala.",
+        "sliding_sync": "Modo Sliding Sync",
+        "sliding_sync_description": "Em desenvolvimento ativo, não pode ser desativado.",
+        "sliding_sync_disabled_notice": "Termina a sessão e volta a entrar para desativar",
+        "sliding_sync_server_no_support": "O teu servidor não tem suporte nativo",
+        "under_active_development": "Em desenvolvimento ativo.",
+        "unrealiable_e2e": "Não é fiável em salas encriptadas",
+        "video_rooms": "Salas de vídeo",
+        "video_rooms_a_new_way_to_chat": "Uma nova forma de conversar por voz e vídeo em %(brand)s.",
+        "video_rooms_always_on_voip_channels": "As salas de vídeo são canais VoIP sempre ativos incorporados numa sala em %(brand)s.",
+        "video_rooms_beta": "As salas de vídeo são uma funcionalidade beta",
+        "video_rooms_faq1_answer": "Utilize o botão \"+\" na secção da sala do painel esquerdo.",
+        "video_rooms_faq1_question": "Como posso criar uma sala de vídeo?",
+        "video_rooms_faq2_answer": "Sim, a linha de tempo da conversa é exibida ao lado do vídeo.",
+        "video_rooms_faq2_question": "Posso usar a conversa por texto juntamente com a videochamada?",
+        "video_rooms_feedbackSubheading": "Obrigado por experimentares a versão beta. Por favor, dá-nos o máximo de detalhes possível para podermos melhorá-la.",
+        "wysiwyg_composer": "Editor de texto rico"
+    },
+    "labs_mjolnir": {
+        "advanced_warning": "⚠ Estas definições destinam-se a utilizadores avançados.",
+        "ban_reason": "Ignorado/Bloqueado",
+        "error_adding_ignore": "Erro ao adicionar utilizador/servidor ignorado",
+        "error_adding_list_description": "Verifica a ID ou o endereço da sala e tenta novamente.",
+        "error_adding_list_title": "Erro ao subscrever a lista",
+        "error_removing_ignore": "Erro ao remover utilizador/servidor ignorado",
+        "error_removing_list_description": "Tenta novamente ou vê a tua consola para obteres sugestões.",
+        "error_removing_list_title": "Erro ao cancelar a subscrição da lista",
+        "explainer_1": "Adiciona aqui utilizadores e servidores que pretendes ignorar. Utiliza asteriscos para que %(brand)s corresponda a quaisquer caracteres. Por exemplo, <code>@bot:*</code> ignoraria todos os utilizadores que têm o nome 'bot' em qualquer servidor.",
+        "explainer_2": "Ignorar pessoas é feito através de listas de banimento que contêm regras para quem deve ser banido. A subscrição de uma lista de proibições significa que os utilizadores/servidores bloqueados por essa lista serão ocultados de ti.",
+        "lists": "Estás atualmente inscrito em:",
+        "lists_description_1": "Ao subscreveres uma lista de proibições, vais juntar-te a ela!",
+        "lists_description_2": "Se não é isto que pretendes, utiliza uma ferramenta diferente para ignorar utilizadores.",
+        "lists_heading": "Listas subscritas",
+        "lists_new_label": "ID da sala ou endereço da lista de proibições",
+        "no_lists": "Não estás inscrito em nenhuma lista",
+        "personal_description": "A tua lista pessoal de banimento contém todos os utilizadores/servidores dos quais tu pessoalmente não queres ver mensagens. Depois de ignorares o teu primeiro utilizador/servidor, uma nova sala aparecerá na tua lista de salas com o nome '%(myBanList)s' - fica nesta sala para manteres a lista de banimentos em efeito.",
+        "personal_empty": "Não ignoraste ninguém.",
+        "personal_heading": "Lista de proibições pessoais",
+        "personal_new_label": "ID do servidor ou do utilizador a ignorar",
+        "personal_new_placeholder": "Ex: @bot:* ou exemplo.org",
+        "personal_section": "Atualmente estás a ignorar:",
+        "room_name": "A minha lista de proibições",
+        "room_topic": "Esta é a tua lista de utilizadores/servidores que bloqueaste - não saias da sala!",
+        "rules_empty": "Nenhum",
+        "rules_server": "Regras do servidor",
+        "rules_title": "Regras da lista de proibições - %(roomName)s",
+        "rules_user": "Regras de utilização",
+        "something_went_wrong": "Algo correu mal. Tenta novamente ou vê a tua consola para obteres sugestões.",
+        "title": "Utilizadores ignorados",
+        "view_rules": "Ver regras"
+    },
+    "language_dropdown_label": "Lista suspensa de idiomas",
+    "leave_room_dialog": {
+        "last_person_warning": "Tu és a única pessoa aqui. Se te fores embora, ninguém poderá juntar-se a nós no futuro, incluindo tu.",
+        "leave_room_question": "Você tem certeza que deseja sair da sala '%(roomName)s'?",
+        "leave_space_question": "Tens a certeza de que queres deixar o espaço '%(spaceName)s'?",
+        "room_leave_admin_warning": "És o único administrador nesta sala. Se saíres, ninguém poderá alterar as definições da sala ou realizar outras ações importantes.",
+        "room_leave_mod_warning": "És o único moderador nesta sala. Se saíres, ninguém poderá alterar as definições da sala ou realizar outras ações importantes.",
+        "room_rejoin_warning": "Esta sala não é pública. Não poderás voltar a entrar sem um convite.",
+        "space_rejoin_warning": "Este espaço não é público. Não poderás voltar a entrar sem um convite."
+    },
+    "left_panel": {
+        "open_dial_pad": "Abre o teclado de marcação"
+    },
+    "lightbox": {
+        "rotate_left": "Rodar à esquerda",
+        "rotate_right": "Rodar à direita",
+        "title": "Visualização da imagem"
+    },
+    "location_sharing": {
+        "MapStyleUrlNotConfigured": "Este servidor doméstico não está configurado para mostrar mapas.",
+        "MapStyleUrlNotReachable": "Este servidor doméstico não está configurado corretamente para apresentar mapas, ou o servidor de mapas configurado pode não estar acessível.",
+        "WebGLNotEnabled": "É necessário WebGL para visualizar os mapas, por isso ativa-o nas definições do teu browser.",
+        "click_drop_pin": "Clica para deixar cair um alfinete",
+        "click_move_pin": "Clica para mover o pino",
+        "close_sidebar": "Fechar barra lateral",
+        "error_fetch_location": "Não foi possível obter a localização",
+        "error_no_perms_description": "Tens de ter as permissões correctas para partilhar locais nesta sala.",
+        "error_no_perms_title": "Não tens autorização para partilhar localizações",
+        "error_send_description": "%(brand)s não foi possível enviar a tua localização. Por favor, tenta novamente mais tarde.",
+        "error_send_title": "Não foi possível enviar a tua localização",
+        "error_sharing_live_location": "Ocorreu um erro ao partilhar a tua localização ao vivo",
+        "error_stopping_live_location": "Ocorreu um erro ao parar a tua localização em direto",
+        "expand_map": "Expande o mapa",
+        "failed_generic": "Não foi possível obter a tua localização. Por favor, tenta novamente mais tarde.",
+        "failed_load_map": "Não é possível carregar o mapa",
+        "failed_permission": "%(brand)s foi negada a permissão para obter a tua localização. Permite o acesso à localização nas definições do teu browser.",
+        "failed_timeout": "O tempo esgotou-se ao tentar obter a tua localização. Por favor, tenta novamente mais tarde.",
+        "failed_unknown": "Erro desconhecido ao procurar a localização. Tenta novamente mais tarde.",
+        "find_my_location": "Encontra a minha localização",
+        "live_description": "localização ao vivo de %(displayName)s",
+        "live_enable_description": "Tem em atenção: esta é uma funcionalidade de laboratório com uma implementação temporária. Isto significa que não poderás apagar o teu histórico de localização e que os utilizadores avançados poderão ver o teu histórico de localização mesmo depois de deixares de partilhar a tua localização em direto com esta sala.",
+        "live_enable_heading": "Partilha de localização em direto",
+        "live_location_active": "Estás a partilhar a tua localização ao vivo",
+        "live_location_enabled": "Localização em direto activada",
+        "live_location_ended": "A localização em direto terminou",
+        "live_location_error": "Erro de localização ao vivo",
+        "live_locations_empty": "Não há locais ao vivo",
+        "live_share_button": "Partilhar por %(duration)s",
+        "live_toggle_label": "Ativar a partilha de localização em direto",
+        "live_until": "Ao vivo até %(expiryTime)s",
+        "live_update_time": "Atualizado %(humanizedUpdateTime)s",
+        "loading_live_location": "Carregando localização ao vivo...",
+        "location_not_available": "Localização não disponível",
+        "map_feedback": "Feedback do mapa",
+        "mapbox_logo": "Logótipo da Mapbox",
+        "reset_bearing": "Reposiciona o rumo para norte",
+        "share_button": "Partilhar localização",
+        "share_type_live": "A minha localização ao vivo",
+        "share_type_own": "A minha localização atual",
+        "share_type_pin": "Larga um alfinete",
+        "share_type_prompt": "Que tipo de localização pretendes partilhar?",
+        "toggle_attribution": "Alterna a atribuição"
+    },
+    "member_list": {
+        "filter_placeholder": "Filtrar integrantes da sala",
+        "invite_button_no_perms_tooltip": "Não tens permissão para convidar utilizadores",
+        "power_label": "%(userName)s (nível de permissão %(powerLevelNumber)s)"
+    },
+    "member_list_back_action_label": "Membros da sala",
+    "message_edit_dialog_title": "Edições de mensagens",
+    "migrating_crypto": "Aguenta firme. Estamos a atualizar o Element para tornar a encriptação mais rápida e mais fiável.",
+    "mobile_guide": {
+        "toast_accept": "Utiliza a aplicação",
+        "toast_description": "%(brand)s é experimental num navegador da Web móvel. Para obteres uma melhor experiência e as funcionalidades mais recentes, utiliza a nossa aplicação nativa gratuita.",
+        "toast_title": "Utiliza a aplicação para uma melhor experiência"
+    },
+    "name_and_id": "%(name)s (%(userId)s)",
+    "no_more_results": "Não há mais resultados",
+    "notif_panel": {
+        "empty_description": "Não tens notificações visíveis.",
+        "empty_heading": "Já estás a par de tudo"
+    },
+    "notifications": {
+        "all_messages": "Todas as mensagens",
+        "all_messages_description": "Recebe notificações de todas as mensagens",
+        "class_global": "Global",
+        "class_other": "Outros",
+        "default": "Padrão",
+        "email_pusher_app_display_name": "Notificações de e-mail",
+        "enable_prompt_toast_description": "Ativar as notificações do ambiente de trabalho",
+        "enable_prompt_toast_title": "Notificações",
+        "enable_prompt_toast_title_from_message_send": "Não percas uma resposta",
+        "error_change_title": "Altera as definições de notificação",
+        "keyword": "Palavra-chave",
+        "keyword_new": "Nova palavra-chave",
+        "level_activity": "Atividade",
+        "level_highlight": "Destaque",
+        "level_muted": "Silenciado",
+        "level_none": "Nenhum",
+        "level_notification": "Notificação",
+        "level_unsent": "Não enviado",
+        "mark_all_read": "Marcar todas como lidas",
+        "mentions_and_keywords": "@menções e palavras-chave",
+        "mentions_and_keywords_description": "Recebe notificações apenas com menções e palavras-chave, conforme definido nas tuas definições de <a></a>",
+        "mentions_keywords": "Menções e palavras-chave",
+        "message_didnt_send": "A mensagem não foi enviada. Clica para obteres informações.",
+        "mute_description": "Não receberás quaisquer notificações"
+    },
+    "notifier": {
+        "m.key.verification.request": "%(name)s está a pedir verificação"
+    },
+    "onboarding": {
+        "create_room": "Cria um chat de grupo",
+        "explore_rooms": "Explora as salas públicas",
+        "has_avatar_label": "Ótimo, isso vai ajudar as pessoas a saberem que és tu",
+        "intro_byline": "Torna-te dono das tuas conversas.",
+        "intro_welcome": "Bem-vindo(a) a(ao) %(appName)s",
+        "no_avatar_label": "Adiciona uma fotografia para que as pessoas saibam que és tu.",
+        "send_dm": "Envia uma mensagem direta",
+        "welcome_detail": "Agora, vamos ajudar-te a começar",
+        "welcome_user": "Bem-vindo(a) %(name)s"
+    },
+    "pill": {
+        "permalink_other_room": "Mensagem em %(room)s",
+        "permalink_this_room": "Mensagem de %(user)s"
+    },
+    "poll": {
+        "create_poll_action": "Criar sondagem",
+        "create_poll_title": "Criar sondagem",
+        "disclosed_notes": "Os eleitores vêem os resultados assim que votam",
+        "edit_poll_title": "Editar sondagem",
+        "end_description": "Tens a certeza de que queres acabar com esta sondagem? Isto irá mostrar os resultados finais da sondagem e impedir que as pessoas possam votar.",
+        "end_message": "A sondagem terminou. Resposta principal: %(topAnswer)s",
+        "end_message_no_votes": "A sondagem terminou. Não houve votos.",
+        "end_title": "Fim da sondagem",
+        "error_ending_description": "Desculpa, a sondagem não terminou. Por favor, tenta novamente.",
+        "error_ending_title": "Falha ao encerrar a sondagem",
+        "error_voting_description": "Desculpa, o teu voto não foi registado. Por favor, tenta novamente.",
+        "error_voting_title": "Voto não registado",
+        "failed_send_poll_description": "Desculpa, mas a sondagem que tentaste criar não foi publicada.",
+        "failed_send_poll_title": "Não conseguiste publicar a sondagem",
+        "notes": "Os resultados só são revelados quando terminas a sondagem",
+        "options_add_button": "Adiciona opção",
+        "options_heading": "Cria opções",
+        "options_label": "Opção %(number)s",
+        "options_placeholder": "Escreve uma opção",
+        "topic_heading": "Qual é a pergunta ou o tema da tua sondagem?",
+        "topic_label": "Pergunta ou tópico",
+        "topic_placeholder": "Escreve qualquer coisa...",
+        "total_decryption_errors": "Devido a erros de descodificação, alguns votos podem não ser contados",
+        "total_n_votes": {
+            "one": "%(count)s voto lançado. Vota para ver os resultados",
+            "other": "%(count)s votos lançados. Vota para ver os resultados"
+        },
+        "total_n_votes_voted": {
+            "one": "Baseado em %(count)s voto",
+            "other": "Baseado em %(count)s votos"
+        },
+        "total_no_votes": "Nenhum voto lançado",
+        "total_not_ended": "Os resultados serão visíveis quando a sondagem terminar",
+        "type_closed": "Sondagem fechada",
+        "type_heading": "Tipo de sondagem",
+        "type_open": "Abrir sondagem",
+        "unable_edit_description": "Desculpa, mas não podes editar uma sondagem depois de os votos terem sido expressos.",
+        "unable_edit_title": "Não é possível editar a sondagem"
+    },
+    "power_level": {
+        "admin": "Administrador",
+        "custom": "Personalizado (%(level)s)",
+        "custom_level": "Nível personalizado",
+        "default": "Padrão",
+        "label": "Nível de potência",
+        "moderator": "Moderador/a",
+        "restricted": "Restrito"
+    },
+    "presence": {
+        "away": "Ausente",
+        "busy": "Ocupado",
+        "idle": "Ocioso",
+        "idle_for": "Inativo por%(duration)s",
+        "offline": "Ausente",
+        "offline_for": "Ausente por %(duration)s",
+        "online": "Disponível",
+        "online_for": "Online por %(duration)s",
+        "unknown": "Desconhecido",
+        "unknown_for": "Desconhecido por %(duration)s",
+        "unreachable": "O servidor do utilizador não pode ser alcançado"
+    },
+    "quick_settings": {
+        "all_settings": "Todas as definições",
+        "metaspace_section": "Fixar na barra lateral",
+        "sidebar_settings": "Mais opções",
+        "title": "Definições rápidas"
+    },
+    "quit_warning": {
+        "call_in_progress": "Parece que você está em uma chamada. Tem certeza que quer sair?",
+        "file_upload_in_progress": "Parece que você está enviando arquivos. Tem certeza que quer sair?"
+    },
+    "redact": {
+        "confirm_button": "Confirmar Remoção",
+        "confirm_description": "Tens a certeza de que pretendes remover (apagar) este evento?",
+        "confirm_description_state": "Tem em atenção que a remoção de alterações de sala como esta pode anular a alteração.",
+        "error": "Não pode apagar esta mensagem. (%(code)s)",
+        "ongoing": "A remover...",
+        "reason_label": "Motivo (opcional)"
+    },
+    "reject_invitation_dialog": {
+        "confirmation": "Você tem certeza que deseja rejeitar este convite?",
+        "failed": "Falha ao tentar rejeitar convite",
+        "title": "Rejeitar convite"
+    },
+    "report_content": {
+        "description": "Ao reportar esta mensagem, envias o seu \"ID de evento\" único para o administrador do teu servidor. Se as mensagens nesta sala estiverem cifradas, o administrador não poderá ler o texto ou ver quaisquer ficheiros ou imagens.",
+        "disagree": "Não concordo",
+        "error_create_room_moderation_bot": "Não é possível criar uma sala com o bot de moderação",
+        "hide_messages_from_user": "Verifica se pretendes ocultar todas as mensagens actuais e futuras deste utilizador.",
+        "ignore_user": "Ignora o utilizador",
+        "illegal_content": "Conteúdo ilegal",
+        "missing_reason": "Por favor, indica o motivo da tua denúncia.",
+        "nature": "Escolhe uma natureza e descreve o que torna esta mensagem abusiva.",
+        "nature_disagreement": "O que este utilizador está a escrever está errado.\nIsto será reportado aos moderadores da sala.",
+        "nature_illegal": "Este utilizador está a demonstrar um comportamento ilegal, por exemplo, ao fazer \"doxing\" a pessoas ou ao ameaçar com violência.\nEsta situação será comunicada aos moderadores da sala, que podem encaminhar o caso para as autoridades legais.",
+        "nature_nonstandard_admin": "Esta sala é dedicada a conteúdos ilegais ou tóxicos, ou os moderadores não conseguem moderar conteúdos ilegais ou tóxicos.\nIsto será comunicado aos administradores da %(homeserver)s.",
+        "nature_nonstandard_admin_encrypted": "Esta sala é dedicada a conteúdos ilegais ou tóxicos ou os moderadores não conseguem moderar conteúdos ilegais ou tóxicos.\nIsto será comunicado aos administradores da %(homeserver)s. Os administradores NÃO poderão ler o conteúdo cifrado desta sala.",
+        "nature_other": "Qualquer outro motivo. Descreve o problema.\nEste problema será comunicado aos moderadores da sala.",
+        "nature_spam": "Este utilizador está a enviar spam para a sala através de anúncios, ligações para anúncios ou propaganda.\nIsto será comunicado aos moderadores da sala.",
+        "nature_toxic": "Este utilizador está a demonstrar um comportamento tóxico, por exemplo, insultando outros utilizadores ou partilhando conteúdos só para adultos numa sala familiar ou violando as regras desta sala.\nEste comportamento será comunicado aos moderadores da sala.",
+        "other_label": "Outros",
+        "report_content_to_homeserver": "Denuncia conteúdo ao administrador do teu servidor doméstico",
+        "report_entire_room": "Denuncia a sala inteira",
+        "spam_or_propaganda": "Spam ou propaganda",
+        "toxic_behaviour": "Comportamento tóxico"
+    },
+    "restore_key_backup_dialog": {
+        "count_of_decryption_failures": "Falha ao descriptografar%(failedCount)s sessões!",
+        "count_of_successfully_restored_keys": "%(sessionCount)s Chaves restauradas com sucesso",
+        "enter_key_description": "Acede ao teu histórico de mensagens seguras e configura o envio seguro de mensagens introduzindo a tua chave de segurança.",
+        "enter_key_title": "Introduzir chave de segurança",
+        "enter_phrase_description": "Acede ao teu histórico de mensagens seguras e configura o envio de mensagens seguras introduzindo a tua frase de segurança.",
+        "enter_phrase_title": "Introduzir frase de segurança",
+        "incorrect_security_phrase_dialog": "Não foi possível desencriptar a cópia de segurança com esta frase de segurança: verifica se introduziste a frase de segurança correcta.",
+        "incorrect_security_phrase_title": "Frase de segurança incorreta",
+        "key_backup_warning": "<b>Aviso</b>: só deves configurar a cópia de segurança das chaves a partir de um computador de confiança.",
+        "key_fetch_in_progress": "A obter chaves do servidor…",
+        "key_forgotten_text": "Se te esqueceste da tua chave de segurança, podes <button>configurar novas opções de recuperação</button>",
+        "key_is_invalid": "Não é uma chave de segurança válida",
+        "key_is_valid": "Isto parece ser uma chave de segurança válida!",
+        "keys_restored_title": "Chaves restauradas",
+        "load_error_content": "Não foi possível carregar o estado da cópia de segurança",
+        "load_keys_progress": "%(completed)s de %(total)s chaves restauradas",
+        "no_backup_error": "Nenhuma cópia de segurança encontrada!",
+        "phrase_forgotten_text": "Se te esqueceste da tua Frase de Segurança, podes <button1>utilizar a tua Chave de Segurança</button1> ou <button2>definir novas opções de recuperação</button2>",
+        "recovery_key_mismatch_description": "A cópia de segurança não pôde ser desencriptada com esta chave de segurança: verifica se introduziste a chave de segurança correcta.",
+        "recovery_key_mismatch_title": "Incompatibilidade da chave de segurança",
+        "restore_failed_error": "Não foi possível restaurar a cópia de segurança"
+    },
+    "right_panel": {
+        "add_integrations": "Adiciona widgets, pontes e bots",
+        "add_topic": "Adicionar descrição",
+        "extensions_empty_description": "Seleciona \"%(addIntegrations)s\" para procurar e adicionar extensões a esta sala",
+        "extensions_empty_title": "Aumenta a produtividade com mais ferramentas, widgets e bots",
+        "files_button": "Ficheiros",
+        "pinned_messages": {
+            "empty_description": "Selecione uma mensagem e escolha \"%(pinAction)s\" para incluir aqui.",
+            "empty_title": "Fixa mensagens importantes para que possam ser facilmente descobertas",
+            "header": {
+                "one": "1 mensagem fixada",
+                "other": "%(count)s Mensagens fixadas"
+            },
+            "limits": {
+                "one": "",
+                "other": "Só podes fixar até %(count)s widgets"
+            },
+            "menu": "Abrir o menu",
+            "unpin_all": {
+                "button": "Desafixa todas as mensagens"
+            }
+        },
+        "pinned_messages_button": "Fixado",
+        "poll": {
+            "active_heading": "Sondagens ativas",
+            "empty_active": "Não há sondagens ativas nesta sala",
+            "empty_active_load_more": "Não existem sondagens ativas. Carrega mais sondagens para ver as sondagens dos meses anteriores",
+            "empty_active_load_more_n_days": {
+                "one": "Não há sondagens ativas para o dia anterior. Carrega mais sondagens para ver as sondagens dos meses anteriores",
+                "other": "Não existem sondagens ativas para os últimos %(count)s dias. Carrega mais sondagens para veres as sondagens dos meses anteriores"
+            },
+            "empty_past": "Não há sondagens anteriores nesta sala",
+            "empty_past_load_more": "Não existem sondagens anteriores. Carrega mais sondagens para ver as sondagens dos meses anteriores",
+            "empty_past_load_more_n_days": {
+                "one": "Não existem sondagens anteriores para o dia anterior. Carrega mais sondagens para ver as sondagens dos meses anteriores",
+                "other": "Não existem sondagens anteriores para os últimos %(count)s dias. Carrega mais sondagens para ver as sondagens dos meses anteriores"
+            },
+            "final_result": {
+                "one": "Resultado final baseado em %(count)s voto",
+                "other": "Resultado final baseado em %(count)s votos"
+            },
+            "load_more": "Carrega mais sondagens",
+            "loading": "Carregando sondagens",
+            "past_heading": "Sondagens anteriores",
+            "view_in_timeline": "Ver sondagem na linha do tempo",
+            "view_poll": "Ver sondagem"
+        },
+        "polls_button": "História da sondagem",
+        "room_summary_card": {
+            "title": "Informação da sala"
+        },
+        "thread_list": {
+            "context_menu_label": "Opções de tópico"
+        },
+        "video_room_chat": {
+            "title": "Conversa"
+        }
+    },
+    "room": {
+        "3pid_invite_email_not_found_account": "Este convite foi enviado para %(email)s que não está associado à tua conta",
+        "3pid_invite_email_not_found_account_room": "Este convite para %(roomName)s foi enviado para %(email)s que não está associado à tua conta",
+        "3pid_invite_error_description": "Ocorreu um erro (%(errcode)s) ao tentar validar o teu convite. Podes tentar transmitir esta informação à pessoa que te convidou.",
+        "3pid_invite_error_invite_action": "Tenta entrar na mesma",
+        "3pid_invite_error_invite_subtitle": "Só te podes juntar com um convite válido.",
+        "3pid_invite_error_public_subtitle": "Ainda podes aderir aqui.",
+        "3pid_invite_error_title": "Algo correu mal com o teu convite.",
+        "3pid_invite_error_title_room": "Algo correu mal com o teu convite para %(roomName)s",
+        "3pid_invite_no_is_subtitle": "Utiliza um servidor de identidade nas Definições para receber convites diretamente em %(brand)s.",
+        "banned_by": "Foste banido por %(memberName)s",
+        "banned_from_room_by": "Foste banido de %(roomName)s por %(memberName)s",
+        "context_menu": {
+            "copy_link": "Copiar link da sala",
+            "favourite": "Favorito",
+            "forget": "Esquecer a sala",
+            "low_priority": "Baixa prioridade",
+            "mark_read": "Marcar como lido",
+            "mark_unread": "Marcar como não lido",
+            "notifications_default": "Corresponde à predefinição",
+            "notifications_mute": "Silenciar sala",
+            "title": "Opções de sala",
+            "unfavourite": "Favorito"
+        },
+        "creating_room_text": "Estamos a criar uma sala com %(names)s",
+        "dm_invite_action": "Começar a conversar",
+        "dm_invite_subtitle": "<userName/> quer falar",
+        "dm_invite_title": "Queres conversar com %(user)s?",
+        "drop_file_prompt": "Arraste um arquivo aqui para enviar",
+        "edit_topic": "Editar tópico",
+        "error_3pid_invite_email_lookup": "Não é possível encontrar o utilizador por e-mail",
+        "error_cancel_knock_title": "Falha ao cancelar",
+        "error_join_403": "Precisas de um convite para aceder a esta sala.",
+        "error_join_404_1": "Tentaste juntar-te usando um ID de sala sem fornecer uma lista de servidores através dos quais te podes juntar. Os IDs de sala são identificadores internos e não podem ser utilizados para aceder a uma sala sem informações adicionais.",
+        "error_join_404_2": "Se souberes o endereço de uma sala, tenta juntar-te a ela através desse endereço.",
+        "error_join_404_invite": "A pessoa que te convidou já se foi embora ou o seu servidor está offline.",
+        "error_join_404_invite_same_hs": "A pessoa que te convidou já se foi embora.",
+        "error_join_connection": "Houve um erro ao juntares-te.",
+        "error_join_incompatible_version_1": "Desculpa, o teu servidor doméstico é demasiado antigo para participar aqui.",
+        "error_join_incompatible_version_2": "Contacta o administrador do teu servidor doméstico.",
+        "error_join_title": "Não conseguiste aderir",
+        "error_jump_to_date": "O servidor devolveu %(statusCode)s com o código de erro %(errorCode)s",
+        "error_jump_to_date_connection": "Ocorreu um erro de rede ao tentares encontrar e saltar para a data indicada. O teu servidor doméstico pode estar em baixo ou houve apenas um problema temporário com a tua ligação à Internet. Tenta novamente. Se o problema persistir, contacta o administrador do teu servidor doméstico.",
+        "error_jump_to_date_details": "Detalhes do erro",
+        "error_jump_to_date_not_found": "Não foi possível encontrar um evento com vista para o futuro em %(dateString)s. Tenta escolher uma data anterior.",
+        "error_jump_to_date_send_logs_prompt": "Envia <debugLogsLink>debug logs</debugLogsLink> para nos ajudar a localizar o problema.",
+        "error_jump_to_date_title": "Não foi possível encontrar o evento nessa data",
+        "face_pile_summary": {
+            "one": "%(count)s uma pessoa que conheces já aderiu",
+            "other": "%(count)s pessoas que sabes que já aderiram"
+        },
+        "face_pile_tooltip_label": {
+            "one": "Ver 1 membro",
+            "other": "Vê todos os membros de %(count)s "
+        },
+        "face_pile_tooltip_shortcut": "Incluindo %(commaSeparatedMembers)s",
+        "face_pile_tooltip_shortcut_joined": "Incluindo tu, %(commaSeparatedMembers)s",
+        "failed_reject_invite": "Não foi possível rejeitar o convite",
+        "forget_room": "Esquece esta sala",
+        "forget_space": "Esquece este espaço",
+        "header": {
+            "n_people_asking_to_join": {
+                "one": "Pedir para aderir",
+                "other": "%(count)s pessoas a pedir para aderir"
+            },
+            "room_is_public": "Esta sala é pública"
+        },
+        "header_face_pile_tooltip": "Alternar lista de membros",
+        "header_untrusted_label": "Não confiável",
+        "inaccessible": "De momento, esta sala ou espaço não está acessível.",
+        "inaccessible_name": "%(roomName)s não está acessível neste momento.",
+        "inaccessible_subtitle_1": "Tenta novamente mais tarde ou pede a um administrador de sala ou espaço para verificar se tens acesso.",
+        "inaccessible_subtitle_2": "%(errcode)s foi devolvido ao tentares aceder à sala ou ao espaço. Se achas que estás a ver esta mensagem por engano, por favor <issueLink>envia um relatório de erro</issueLink>.",
+        "intro": {
+            "dm_caption": "Só vocês os dois estão nesta conversa, a não ser que um de vocês convide alguém para participar.",
+            "enable_encryption_prompt": "Ativa a encriptação nas definições.",
+            "encrypted_3pid_dm_pending_join": "Quando todos tiverem aderido, poderás conversar",
+            "no_avatar_label": "Adiciona uma fotografia para que as pessoas possam identificar facilmente o teu quarto.",
+            "no_topic": "<a>Adiciona um tópico</a> para ajudar as pessoas a saberem do que se trata.",
+            "private_unencrypted_warning": "As tuas mensagens privadas são normalmente encriptadas, mas esta sala não o é. Normalmente, isto deve-se à utilização de um dispositivo ou método não suportado, como convites por correio eletrónico.",
+            "room_invite": "Convida apenas para esta sala",
+            "send_message_start_dm": "Envia a tua primeira mensagem para convidar <displayName/> para conversar",
+            "start_of_dm_history": "Este é o início do teu histórico de mensagens directas com <displayName/>.",
+            "start_of_room": "Este é o início de <roomName/>.",
+            "topic": "Tópico: %(topic)s",
+            "topic_edit": "Tópico: %(topic)s (<a>edita</a>)",
+            "unencrypted_warning": "A encriptação de ponta a ponta não está ativada",
+            "user_created": "%(displayName)s criou esta sala.",
+            "you_created": "Tu criaste esta sala."
+        },
+        "invite_email_mismatch_suggestion": "Partilha este e-mail nas Definições para receberes convites diretamente em %(brand)s.",
+        "invite_reject_ignore": "Rejeitar e ignorar o utilizador",
+        "invite_sent_to_email": "Este convite foi enviado para %(email)s",
+        "invite_sent_to_email_room": "Este convite para %(roomName)s foi enviado para %(email)s",
+        "invite_subtitle": "<userName/> convidou-o",
+        "invite_this_room": "Convidar para esta sala",
+        "invite_title": "Queres juntar-te a %(roomName)s?",
+        "inviter_unknown": "Desconhecido",
+        "invites_you_text": "<inviter/> convida-te",
+        "join_button_account": "Inscrição",
+        "join_failed_needs_invite": "Para veres %(roomName)s, precisas de um convite",
+        "join_the_discussion": "Participa no debate",
+        "join_title": "Junta-te à sala para participares",
+        "join_title_account": "Junta-te à conversa com uma conta",
+        "joining": "Entrando...",
+        "joining_room": "Entrando na sala…",
+        "joining_space": "Junta-te ao espaço...",
+        "jump_read_marker": "Ir diretamente para a primeira das mensagens não lidas.",
+        "jump_to_bottom_button": "Percorre as mensagens mais recentes",
+        "jump_to_date": "Salta para a data",
+        "jump_to_date_beginning": "O início da sala",
+        "jump_to_date_prompt": "Escolhe uma data para onde saltar",
+        "kick_reason": "Motivo: %(reason)s",
+        "kicked_by": "Foste removido por %(memberName)s",
+        "kicked_from_room_by": "Foste retirado de %(roomName)s por %(memberName)s",
+        "knock_cancel_action": "Cancelar pedido",
+        "knock_denied_subtitle": "Como te foi negado o acesso, não podes voltar a entrar a não ser que sejas convidado pelo administrador ou moderador do grupo.",
+        "knock_denied_title": "Foi-te negado o acesso",
+        "knock_message_field_placeholder": "Mensagem (opcional)",
+        "knock_prompt": "Pedir para participar?",
+        "knock_prompt_name": "Pedir para participar%(roomName)s?",
+        "knock_send_action": "Solicitar acesso",
+        "knock_sent": "Pedido de adesão enviado",
+        "knock_sent_subtitle": "O teu pedido de adesão está pendente.",
+        "knock_subtitle": "Tens de ter acesso a esta sala para veres ou participares na conversa. Podes enviar um pedido de participação abaixo.",
+        "leave_error_title": "Erro ao sair da sala",
+        "leave_server_notices_description": "Esta sala é usada para mensagens importantes do Servidor Doméstico, por isso não podes sair dela.",
+        "leave_server_notices_title": "Não podes sair da sala de avisos do servidor",
+        "leave_unexpected_error": "Erro inesperado do servidor ao tentares sair da sala",
+        "link_email_to_receive_3pid_invite": "Associa este e-mail à tua conta nas Definições para receberes convites diretamente em %(brand)s.",
+        "loading_preview": "A carregar a pré-visualização...",
+        "no_peek_join_prompt": "%(roomName)s não pode ser pré-visualizado. Queres juntar-te?",
+        "no_peek_no_name_join_prompt": "Não há pré-visualização, gostarias de te juntar?",
+        "not_found_subtitle": "Tens a certeza que estás no sítio certo?",
+        "not_found_title": "Esta sala ou espaço não existe.",
+        "not_found_title_name": "%(roomName)s não existe.",
+        "peek_join_prompt": "Estás a visualizar %(roomName)s. Queres juntar-te a ele?",
+        "read_topic": "Clica para ler o tópico",
+        "rejecting": "Rejeitando o convite...",
+        "rejoin_button": "Junta-te novamente",
+        "search": {
+            "all_rooms_button": "Pesquisar todas as salas",
+            "placeholder": "Pesquisar mensagens...",
+            "summary": {
+                "one": "1 resultado encontrado para \"<query/>\"",
+                "other": "%(count)s resultados encontrados para \"<query/>\""
+            },
+            "this_room_button": "Pesquisar esta sala"
+        },
+        "status_bar": {
+            "delete_all": "Eliminar tudo",
+            "exceeded_resource_limit": "A tua mensagem não foi enviada porque este servidor doméstico excedeu um limite de recursos. Por favor, <a>contacta o teu administrador de serviço</a> para continuares a utilizar o serviço.",
+            "homeserver_blocked": "A tua mensagem não foi enviada porque este servidor doméstico foi bloqueado pelo seu administrador. Por favor, <a>contacta o teu administrador de serviço</a> para continuares a usar o serviço.",
+            "monthly_user_limit_reached": "A tua mensagem não foi enviada porque este servidor atingiu o limite mensal de utilizadores activos. Por favor <a>contacta o teu administrador de serviço</a> para continuares a usar o serviço.",
+            "requires_consent_agreement": "Não podes enviar quaisquer mensagens até reveres e concordares com <consentLink>os nossos termos e condições</consentLink>.",
+            "retry_all": "Tentar tudo de novo",
+            "select_messages_to_retry": "Podes selecionar todas as mensagens ou mensagens individuais para repetir ou apagar",
+            "server_connectivity_lost_description": "Imagens enviadas ficarão armazenadas até que sua conexão seja reestabelecida.",
+            "server_connectivity_lost_title": "A conexão com o servidor foi perdida. Verifique sua conexão de internet.",
+            "some_messages_not_sent": "Algumas das tuas mensagens não foram enviadas"
+        },
+        "unknown_status_code_for_timeline_jump": "código de estado desconhecido",
+        "unread_notifications_predecessor": {
+            "one": "Tens %(count)s uma notificação não lida numa versão anterior desta sala.",
+            "other": "Tens %(count)s notificações não lidas numa versão anterior desta sala."
+        },
+        "upgrade_error_description": "Verifica se o teu servidor suporta a versão da sala escolhida e tenta novamente.",
+        "upgrade_error_title": "Erro ao atualizar o quarto",
+        "upgrade_warning_bar": "Ao atualizar este quarto, encerra a instância atual do quarto e cria um quarto atualizado com o mesmo nome.",
+        "upgrade_warning_bar_admins": "Apenas os administradores da sala verão este aviso",
+        "upgrade_warning_bar_unstable": "Esta sala está executando a versão da sala<roomVersion /> , que este servidor doméstico marcou como<i> instável</i> .",
+        "upgrade_warning_bar_upgraded": "Este quarto já foi atualizado.",
+        "upload": {
+            "uploading_multiple_file": {
+                "one": "Enviando o arquivo %(filename)s e %(count)s outros arquivos",
+                "other": "Enviando o arquivo %(filename)s e %(count)s outros arquivos"
+            },
+            "uploading_single_file": "Enviando o arquivo %(filename)s"
+        },
+        "waiting_for_join_subtitle": "Quando os utilizadores convidados tiverem aderido a %(brand)s, poderás conversar e a sala será encriptada de ponta a ponta",
+        "waiting_for_join_title": "Aguarda a adesão dos utilizadores %(brand)s"
+    },
+    "room_list": {
+        "add_room_label": "Adicionar sala",
+        "add_space_label": "Adiciona espaço",
+        "breadcrumbs_empty": "Nenhuma sala visitada recentemente",
+        "breadcrumbs_label": "Salas visitadas recentemente",
+        "failed_add_tag": "Falha ao adicionar %(tagName)s à sala",
+        "failed_remove_tag": "Não foi possível remover a marcação %(tagName)s desta sala",
+        "failed_set_dm_tag": "Falha ao definir a etiqueta de mensagem direta",
+        "home_menu_label": "Opções de casa",
+        "join_public_room_label": "Participa na sala pública",
+        "joining_rooms_status": {
+            "one": "Atualmente ingressando%(count)s sala",
+            "other": "Atualmente ingressando%(count)s salas"
+        },
+        "notification_options": "Opções de notificação",
+        "redacting_messages_status": {
+            "one": "Atualmente removendo mensagens na %(count)s sala",
+            "other": "Atualmente removendo mensagens em %(count)s salas"
+        },
+        "show_less": "Mostrar menos",
+        "show_n_more": {
+            "one": "Mostrar %(count)s mais",
+            "other": "Mostrar %(count)s mais"
+        },
+        "show_previews": "Mostra pré-visualizações de mensagens",
+        "sort_by": "Ordenar por",
+        "sort_by_activity": "Atividade",
+        "sort_by_alphabet": "A-Z",
+        "sort_unread_first": "Mostra primeiro as salas com mensagens não lidas",
+        "space_menu_label": "%(spaceName)s menu",
+        "sublist_options": "Lista de opções",
+        "suggested_rooms_heading": "Salas sugeridas"
+    },
+    "room_settings": {
+        "access": {
+            "description_space": "Decide quem pode ver e participar em %(spaceName)s.",
+            "title": "Acesso"
+        },
+        "advanced": {
+            "error_upgrade_description": "A atualização da sala não pôde ser concluída",
+            "error_upgrade_title": "Falha ao atualizar a sala",
+            "information_section_room": "Informações sobre a sala",
+            "information_section_space": "Informações sobre o espaço",
+            "room_id": "ID interno da sala",
+            "room_predecessor": "Vê as mensagens mais antigas em %(roomName)s.",
+            "room_upgrade_button": "Atualiza este quarto para a versão de quarto recomendada",
+            "room_upgrade_warning": "<b>Aviso</b>: a atualização de uma sala <i>não irá migrar automaticamente os membros da sala para a nova versão da sala.</i> Colocaremos um link para a nova sala na versão antiga da sala - os membros da sala terão de clicar nesse link para se juntarem à nova sala.",
+            "room_version": "Versão da sala:",
+            "room_version_section": "Versão de sala",
+            "space_predecessor": "Vê a versão anterior de %(spaceName)s.",
+            "space_upgrade_button": "Atualiza este espaço para a versão de quarto recomendada",
+            "unfederated": "Esta sala não é acessível para servidores Matrix remotos",
+            "upgrade_button": "Atualize esta sala para a versão %(version)s",
+            "upgrade_dialog_description": "Para atualizar esta sala, é necessário encerrar a instância atual da sala e criar uma nova sala no seu lugar. Para dar aos membros da sala a melhor experiência possível, nós iremos:",
+            "upgrade_dialog_description_1": "Cria uma nova sala com o mesmo nome, descrição e avatar",
+            "upgrade_dialog_description_2": "Atualiza todos os nomes locais para apontarem para a nova sala",
+            "upgrade_dialog_description_3": "Impede os utilizadores de falarem na versão antiga da sala e publica uma mensagem a aconselhar os utilizadores a mudarem-se para a nova sala",
+            "upgrade_dialog_description_4": "Coloca um link para a sala antiga no início da nova sala para que as pessoas possam ver as mensagens antigas",
+            "upgrade_dialog_title": "Atualizar a versão da sala",
+            "upgrade_dwarning_ialog_title_public": "Atualizar sala pública",
+            "upgrade_warning_dialog_description": "A atualização de uma divisão é uma ação avançada e é normalmente recomendada quando uma divisão está instável devido a erros, funcionalidades em falta ou vulnerabilidades de segurança.",
+            "upgrade_warning_dialog_explainer": "<b>Tem em atenção que a atualização fará uma nova versão da sala</b>. Todas as mensagens actuais permanecerão nesta sala arquivada.",
+            "upgrade_warning_dialog_footer": "Actualizarás este quarto de <oldVersion /> para <newVersion />.",
+            "upgrade_warning_dialog_invite_label": "Convida automaticamente os membros desta sala para a nova sala",
+            "upgrade_warning_dialog_report_bug_prompt": "Normalmente, isto só afecta a forma como a sala é processada no servidor. Se estiveres a ter problemas com o teu %(brand)s, por favor reporta um erro.",
+            "upgrade_warning_dialog_report_bug_prompt_link": "Normalmente, isto apenas afecta a forma como a sala é processada no servidor. Se estiveres a ter problemas com o teu %(brand)s, por favor <a>reporta um bug</a>.",
+            "upgrade_warning_dialog_title": "Atualizar sala",
+            "upgrade_warning_dialog_title_private": "Atualiza a sala privada"
+        },
+        "alias_not_specified": "não especificado",
+        "bridges": {
+            "description": "Esta sala está a transmitir mensagens para as seguintes plataformas. <a>Aprende mais.</a>",
+            "empty": "Esta sala não está a transmitir mensagens para nenhuma plataforma. <a>Sabe mais.</a>",
+            "title": "Pontes"
+        },
+        "delete_avatar_label": "Apagar avatar",
+        "general": {
+            "alias_field_has_domain_invalid": "Separador de domínio ausente, por exemplo (:domain .org)",
+            "alias_field_has_localpart_invalid": "Falta o nome da sala ou o separador, por exemplo, (minha-sala:domain.org)",
+            "alias_field_matches_invalid": "Este endereço não aponta para esta sala",
+            "alias_field_placeholder_default": "por exemplo, minha-sala",
+            "alias_field_required_invalid": "Fornece um endereço",
+            "alias_field_safe_localpart_invalid": "Alguns caracteres não são permitidos",
+            "alias_field_taken_invalid": "Este endereço tem um servidor inválido ou já está a ser utilizado",
+            "alias_field_taken_invalid_domain": "Este endereço já está a ser utilizado",
+            "alias_field_taken_valid": "Este endereço está disponível para utilização",
+            "alias_heading": "Endereço da sala",
+            "aliases_items_label": "Outros endereços publicados:",
+            "aliases_no_items_label": "Ainda não existem outros endereços publicados, adiciona um abaixo",
+            "aliases_section": "Endereços de salas",
+            "avatar_field_label": "Avatar da sala",
+            "canonical_alias_field_label": "Endereço principal",
+            "default_url_previews_off": "As pré-visualizações de URL estão desactivadas por predefinição para os participantes nesta sala.",
+            "default_url_previews_on": "As pré-visualizações de URL estão activadas por predefinição para os participantes nesta sala.",
+            "description_space": "Edita as definições relativas ao teu espaço.",
+            "error_creating_alias_description": "Ocorreu um erro ao criares esse endereço. Pode não ser permitido pelo servidor ou ocorreu uma falha temporária.",
+            "error_creating_alias_title": "Erro ao criar o endereço",
+            "error_deleting_alias_description": "Ocorreu um erro ao removeres esse endereço. Pode já não existir ou ocorreu um erro temporário.",
+            "error_deleting_alias_description_forbidden": "Não tens autorização para apagar o endereço.",
+            "error_deleting_alias_title": "Erro ao remover o endereço",
+            "error_save_space_settings": "Não conseguiste guardar as definições de espaço.",
+            "error_updating_alias_description": "Ocorreu um erro ao atualizar os endereços alternativos da sala. Pode não ser permitido pelo servidor ou ocorreu uma falha temporária.",
+            "error_updating_canonical_alias_description": "Ocorreu um erro ao atualizar o endereço principal da sala. Pode não ser permitido pelo servidor ou ocorreu uma falha temporária.",
+            "error_updating_canonical_alias_title": "Erro ao atualizar o endereço principal",
+            "leave_space": "Deixe espaço",
+            "local_alias_field_label": "Endereço local",
+            "local_aliases_explainer_room": "Define endereços para esta sala para que os utilizadores possam encontrar esta sala através do teu servidor doméstico (%(localDomain)s)",
+            "local_aliases_explainer_space": "Define endereços para este espaço para que os utilizadores possam encontrar este espaço através do teu servidor doméstico (%(localDomain)s)",
+            "local_aliases_section": "Endereços locais",
+            "name_field_label": "Nome da sala",
+            "new_alias_placeholder": "Novo endereço publicado (por exemplo, #alias:server)",
+            "no_aliases_room": "Esta sala não tem endereços locais",
+            "no_aliases_space": "Este espaço não tem endereços locais",
+            "other_section": "Outros",
+            "publish_toggle": "Publicar esta sala ao público no diretório de salas de %(domain)s's?",
+            "published_aliases_description": "Para publicares um endereço, este tem de ser primeiro definido como um endereço local.",
+            "published_aliases_explainer_room": "Os endereços publicados podem ser usados por qualquer pessoa em qualquer servidor para entrar na tua sala.",
+            "published_aliases_explainer_space": "Os endereços publicados podem ser usados por qualquer pessoa em qualquer servidor para se juntar ao teu espaço.",
+            "published_aliases_section": "Endereços publicados",
+            "save": "Salvar Alterações",
+            "topic_field_label": "Tópico da sala",
+            "url_preview_encryption_warning": "Em salas encriptadas, como esta, as pré-visualizações de URL são desactivadas por predefinição para garantir que o teu servidor doméstico (onde as pré-visualizações são geradas) não pode recolher informações sobre as ligações que vês nesta sala.",
+            "url_preview_explainer": "Quando alguém coloca um URL na sua mensagem, pode ser mostrada uma pré-visualização do URL para dar mais informações sobre essa ligação, como o título, a descrição e uma imagem do sítio Web.",
+            "url_previews_section": "Pré-visualização de links",
+            "user_url_previews_default_off": "Você <a>desabilitou</a> pré-visualizações de links por padrão.",
+            "user_url_previews_default_on": "Você <a>habilitou</a> pré-visualizações de links por padrão."
+        },
+        "notifications": {
+            "browse_button": "Navegar",
+            "custom_sound_prompt": "Define um novo som personalizado",
+            "notification_sound": "Som de notificação",
+            "settings_link": "Recebe notificações conforme definido nas tuas definições de <a></a>",
+            "sounds_section": "Sons",
+            "upload_sound_label": "Carrega um som personalizado",
+            "uploaded_sound": "Som carregado"
+        },
+        "people": {
+            "knock_empty": "Nenhum pedido",
+            "knock_section": "Pedir para aderir",
+            "see_less": "Ver menos",
+            "see_more": "Ver mais"
+        },
+        "permissions": {
+            "add_privileged_user_description": "Concede mais privilégios a um ou vários utilizadores desta sala",
+            "add_privileged_user_filter_placeholder": "Procura utilizadores nesta sala...",
+            "add_privileged_user_heading": "Adiciona utilizadores privilegiados",
+            "ban": "Banir utilizadores",
+            "ban_reason": "Razão",
+            "banned_by": "Banido por %(displayName)s",
+            "banned_users_section": "Usuárias/os banidas/os",
+            "error_changing_pl_description": "Ocorreu um erro ao alterar o nível de potência do utilizador. Certifica-te de que tens permissões suficientes e tenta novamente.",
+            "error_changing_pl_reqs_description": "Ocorreu um erro ao alterares os requisitos de nível de potência da sala. Certifica-te de que tens permissões suficientes e tenta novamente.",
+            "error_changing_pl_reqs_title": "Erro ao alterar o requisito do nível de potência",
+            "error_changing_pl_title": "Erro ao alterar o nível de potência",
+            "error_unbanning": "Não foi possível desfazer o banimento",
+            "events_default": "Envia mensagens",
+            "invite": "Convidar utilizadores",
+            "kick": "Remover utilizadores",
+            "m.call": "Inicia chamadas %(brand)s",
+            "m.call.member": "Participa em chamadas %(brand)s",
+            "m.reaction": "Envia reações",
+            "m.room.avatar": "Altera o avatar da sala",
+            "m.room.avatar_space": "Altera o avatar espacial",
+            "m.room.canonical_alias": "Altera o endereço principal para a sala",
+            "m.room.canonical_alias_space": "Altera o endereço principal do espaço",
+            "m.room.encryption": "Ativar a encriptação da sala",
+            "m.room.history_visibility": "Altera a visibilidade do histórico",
+            "m.room.name": "Altera o nome da sala",
+            "m.room.name_space": "Altera o nome do espaço",
+            "m.room.pinned_events": "Gerir eventos fixados",
+            "m.room.power_levels": "Altera as permissões",
+            "m.room.redaction": "Remove mensagens enviadas por mim",
+            "m.room.server_acl": "Altera as ACLs do servidor",
+            "m.room.tombstone": "Atualiza a sala",
+            "m.room.topic": "Altera o tópico",
+            "m.room.topic_space": "Altera a descrição",
+            "m.space.child": "Gere as salas neste espaço",
+            "m.widget": "Modifica os widgets",
+            "muted_users_section": "Utilizadores silenciados",
+            "no_privileged_users": "Nenhum/a usuário/a possui privilégios específicos nesta sala",
+            "notifications.room": "Notifica todos",
+            "permissions_section": "Permissões",
+            "permissions_section_description_room": "Selecione as funções necessárias para alterar várias partes da sala",
+            "permissions_section_description_space": "Selecciona as funções necessárias para alterar as várias partes do espaço",
+            "privileged_users_section": "Usuárias/os privilegiadas/os",
+            "redact": "Remove mensagens enviadas por outros",
+            "send_event_type": "Envia eventos %(eventType)s ",
+            "state_default": "Alterar definições",
+            "title": "Funções e permissões",
+            "users_default": "Papel predefinido"
+        },
+        "security": {
+            "enable_encryption_confirm_description": "Uma vez activada, a encriptação de uma sala não pode ser desactivada. As mensagens enviadas numa sala encriptada não podem ser vistas pelo servidor, apenas pelos participantes da sala. A ativação da encriptação pode impedir que muitos bots e pontes funcionem corretamente. <a>Sabe mais sobre a encriptação.</a>",
+            "enable_encryption_confirm_title": "Ativar a encriptação?",
+            "enable_encryption_public_room_confirm_description_1": "<b>Não é recomendável adicionar encriptação a salas públicas.</b> Qualquer pessoa pode encontrar e entrar em salas públicas, pelo que qualquer pessoa pode ler as mensagens nelas contidas. Não obterás nenhum dos benefícios da encriptação e não poderás desactivá-la mais tarde. A encriptação de mensagens numa sala pública tornará a receção e o envio de mensagens mais lento.",
+            "enable_encryption_public_room_confirm_description_2": "Para evitar estes problemas, cria uma <a>nova sala encriptada</a> para a conversa que pretendes ter.",
+            "enable_encryption_public_room_confirm_title": "Tens a certeza de que queres adicionar encriptação a esta sala pública?",
+            "encrypted_room_public_confirm_description_1": "<b>Não é recomendável tornar públicas as salas encriptadas.</b> Isso significa que qualquer pessoa pode encontrar e entrar na sala, pelo que qualquer pessoa pode ler as mensagens. Não terás nenhum dos benefícios da encriptação. Encriptar mensagens numa sala pública tornará a receção e o envio de mensagens mais lento.",
+            "encrypted_room_public_confirm_description_2": "Para evitar estes problemas, cria uma <a>nova sala pública</a> para a conversa que pretendes ter.",
+            "encrypted_room_public_confirm_title": "Tens a certeza de que queres tornar pública esta sala encriptada?",
+            "encryption_forced": "O teu servidor requer que a encriptação seja desactivada.",
+            "encryption_permanent": "Uma vez activada, a encriptação não pode ser desactivada.",
+            "error_join_rule_change_title": "Falha ao atualizar as regras de adesão",
+            "error_join_rule_change_unknown": "Falha desconhecida",
+            "guest_access_warning": "As pessoas com clientes apoiados poderão juntar-se à sala sem terem uma conta registada.",
+            "history_visibility_invited": "Apenas membros (desde que tenham sido convidados)",
+            "history_visibility_joined": "Apenas membros (desde que aderiram)",
+            "history_visibility_legend": "Quem pode ler o histórico da sala?",
+            "history_visibility_shared": "Apenas membros (desde o momento em que seleccionas esta opção)",
+            "history_visibility_warning": "As alterações a quem pode ler o histórico só se aplicam a mensagens futuras nesta sala. A visibilidade do histórico existente permanecerá inalterada.",
+            "history_visibility_world_readable": "Qualquer pessoa",
+            "join_rule_description": "Decide quem pode aderir a %(roomName)s.",
+            "join_rule_invite": "Privado (só por convite)",
+            "join_rule_invite_description": "Apenas pessoas convidadas podem participar.",
+            "join_rule_knock": "Pede para aderir",
+            "join_rule_knock_description": "As pessoas só podem aderir se o acesso for concedido.",
+            "join_rule_public_description": "Qualquer pessoa pode encontrar e aderir.",
+            "join_rule_restricted": "Membros do espaço",
+            "join_rule_restricted_description": "Qualquer pessoa num espaço pode encontrar e aderir. <a>Edita quais os espaços que podem aceder aqui.</a>",
+            "join_rule_restricted_description_active_space": "Qualquer pessoa em <spaceName/> pode encontrar e aderir. Também podes selecionar outros espaços.",
+            "join_rule_restricted_description_prompt": "Qualquer pessoa num espaço pode encontrar e aderir. Podes selecionar vários espaços.",
+            "join_rule_restricted_description_spaces": "Espaços com acesso",
+            "join_rule_restricted_dialog_description": "Decide quais os espaços que podem aceder a esta sala. Se um espaço for selecionado, os seus membros podem encontrar e juntar-se a <RoomName/>.",
+            "join_rule_restricted_dialog_empty_warning": "Estás a remover todos os espaços. O acesso será por defeito apenas para convidados",
+            "join_rule_restricted_dialog_filter_placeholder": "Procura espaços",
+            "join_rule_restricted_dialog_heading_known": "Outros espaços que conheces",
+            "join_rule_restricted_dialog_heading_other": "Outros espaços ou salas que talvez não conheças",
+            "join_rule_restricted_dialog_heading_room": "Espaços que conheces e que contêm esta sala",
+            "join_rule_restricted_dialog_heading_space": "Espaços que conheces que contêm este espaço",
+            "join_rule_restricted_dialog_heading_unknown": "É provável que outros administradores de salas façam parte delas.",
+            "join_rule_restricted_dialog_title": "Selecionar espaços",
+            "join_rule_restricted_n_more": {
+                "one": "e %(count)s mais",
+                "other": "e %(count)s mais"
+            },
+            "join_rule_restricted_summary": {
+                "one": "Atualmente, um espaço tem acesso",
+                "other": "Atualmente,%(count)s espaços têm acesso"
+            },
+            "join_rule_restricted_upgrade_description": "Esta atualização permitirá aos membros de espaços seleccionados aceder a esta sala sem convite.",
+            "join_rule_restricted_upgrade_warning": "Esta sala está em alguns espaços dos quais não és administrador. Nesses espaços, a sala antiga continuará a ser mostrada, mas as pessoas serão convidadas a juntar-se à nova.",
+            "join_rule_upgrade_awaiting_room": "Carregando nova sala",
+            "join_rule_upgrade_required": "Atualização necessária",
+            "join_rule_upgrade_sending_invites": {
+                "one": "Enviando convite...",
+                "other": "Enviando convites... (%(progress)sfora de%(count)s)"
+            },
+            "join_rule_upgrade_updating_spaces": {
+                "one": "Atualizando espaço...",
+                "other": "Atualizando espaços... (%(progress)sfora de%(count)s)"
+            },
+            "join_rule_upgrade_upgrading_room": "Atualização da sala",
+            "public_without_alias_warning": "Para estabelecer uma ligação a esta sala, adiciona um endereço.",
+            "publish_room": "Torna esta sala visível no diretório público de salas.",
+            "publish_space": "Torna este espaço visível no diretório de salas públicas.",
+            "strict_encryption": "Nunca envia mensagens encriptadas para sessões não verificadas nesta sala a partir desta sessão",
+            "title": "Segurança e privacidade"
+        },
+        "title": "Configurações da sala -%(roomName)s",
+        "upload_avatar_label": "Enviar icone de perfil de usuário",
+        "visibility": {
+            "alias_section": "Endereço",
+            "error_failed_save": "Falha ao atualizar a visibilidade deste espaço",
+            "error_update_guest_access": "Falha ao atualizar o acesso de convidado deste espaço",
+            "error_update_history_visibility": "Falha ao atualizar a visibilidade do histórico deste espaço",
+            "guest_access_explainer": "Os convidados podem juntar-se a um espaço sem terem uma conta.",
+            "guest_access_explainer_public_space": "Isto pode ser útil para espaços públicos.",
+            "guest_access_label": "Ativar o acesso de convidados",
+            "history_visibility_anyone_space": "Espaço de pré-visualização",
+            "history_visibility_anyone_space_description": "Permite que as pessoas visualizem o teu espaço antes de aderirem.",
+            "history_visibility_anyone_space_recommendation": "Recomendado para espaços públicos.",
+            "title": "Visibilidade"
+        },
+        "voip": {
+            "call_type_section": "Tipo de chamada",
+            "enable_element_call_caption": "%(brand)s é encriptado de ponta a ponta, mas está atualmente limitado a um pequeno número de utilizadores.",
+            "enable_element_call_label": "Ativa %(brand)s como uma opção de chamada adicional nesta sala",
+            "enable_element_call_no_permissions_tooltip": "Não tens permissões suficientes para alterar isto."
+        }
+    },
+    "room_summary_card_back_action_label": "Informações da sala",
+    "scalar": {
+        "error_create": "Não foi possível criar o widget.",
+        "error_membership": "Não se encontra nesta sala.",
+        "error_missing_room_id": "Falta ID de Sala.",
+        "error_missing_room_id_request": "Faltou o id da sala na requisição",
+        "error_missing_user_id_request": "Faltou o id de usuário na requisição",
+        "error_permission": "Não tem permissão para fazer isso nesta sala.",
+        "error_power_level_invalid": "O nível de permissões tem que ser um número inteiro e positivo.",
+        "error_room_not_visible": "A sala %(roomId)s não está visível",
+        "error_room_unknown": "Esta sala não é reconhecida.",
+        "error_send_request": "Não foi possível mandar requisição.",
+        "failed_read_event": "Falha ao ler eventos",
+        "failed_send_event": "Falha no envio do evento"
+    },
+    "server_offline": {
+        "description": "O teu servidor não está a responder a alguns dos teus pedidos. Abaixo estão algumas das razões mais prováveis.",
+        "description_1": "O servidor (%(serverName)s) demorou muito tempo a responder.",
+        "description_2": "A tua firewall ou antivírus está a bloquear o pedido.",
+        "description_3": "Uma extensão do browser está a impedir o pedido.",
+        "description_4": "O servidor está offline.",
+        "description_5": "O servidor recusou o teu pedido.",
+        "description_6": "A tua área está a ter dificuldades em ligar-se à Internet.",
+        "description_7": "Ocorreu um erro de ligação ao tentar contactar o servidor.",
+        "description_8": "O servidor não está configurado para indicar qual é o problema (CORS).",
+        "empty_timeline": "Já estás a par de tudo.",
+        "recent_changes_heading": "Alterações recentes que ainda não foram recebidas",
+        "title": "O servidor não está a responder"
+    },
+    "seshat": {
+        "error_initialising": "A inicialização da pesquisa de mensagens falhou, consulta <a>as tuas definições</a> para mais informações",
+        "reset_button": "Reinicia o armazenamento de eventos",
+        "reset_description": "O mais provável é que não queiras repor o teu armazenamento de índices de eventos",
+        "reset_explainer": "Se o fizeres, tem em atenção que nenhuma das tuas mensagens será eliminada, mas a experiência de pesquisa poderá ser prejudicada durante alguns momentos enquanto o índice é recriado",
+        "reset_title": "Reiniciar o armazenamento de eventos?",
+        "warning_kind_files": "Esta versão de %(brand)s não suporta a visualização de alguns ficheiros encriptados",
+        "warning_kind_files_app": "Utiliza a aplicação <a>Desktop</a> para ver todos os ficheiros encriptados",
+        "warning_kind_search": "Esta versão de %(brand)s não suporta a pesquisa de mensagens encriptadas",
+        "warning_kind_search_app": "Utiliza a aplicação <a>Desktop</a> para pesquisar mensagens encriptadas"
+    },
+    "setting": {
+        "help_about": {
+            "access_token_detail": "O teu token de acesso dá acesso total à tua conta. Não o partilhes com ninguém.",
+            "brand_version": "versão do %(brand)s:",
+            "clear_cache_reload": "Limpa a cache e volta a carregar",
+            "crypto_version": "Versão criptográfica:",
+            "dialog_title": "<strong>Definições:</strong> Ajuda e Acerca",
+            "help_link": "Para obter ajuda sobre como utilizar %(brand)s, clica em <a>aqui</a>.",
+            "homeserver": "O servidor doméstico é <code>%(homeserverUrl)s</code>",
+            "identity_server": "O servidor de identidade é <code>%(identityServerUrl)s</code>",
+            "title": "Ajuda e sobre",
+            "versions": "Versões"
+        }
+    },
+    "settings": {
+        "account": {
+            "dialog_title": "<strong>Configurações:</strong> Conta",
+            "title": "Conta"
+        },
+        "all_rooms_home": "Mostrar todas as salas na Página Inicial",
+        "all_rooms_home_description": "Todas as salas em que te encontras aparecerão em Casa.",
+        "always_show_message_timestamps": "Sempre mostrar as datas das mensagens",
+        "appearance": {
+            "bundled_emoji_font": "Utiliza o tipo de letra de emoji incluído",
+            "compact_layout": "Mostrar texto e mensagens compactas",
+            "compact_layout_description": "O layout moderno deve ser selecionado para usar esse recurso.",
+            "custom_font": "Utiliza um tipo de letra do sistema",
+            "custom_font_description": "Define o nome de um tipo de letra instalado no teu sistema e o %(brand)s tentará utilizá-lo.",
+            "custom_font_name": "Nome do tipo de letra do sistema",
+            "custom_font_size": "Utiliza tamanho personalizado",
+            "custom_theme_add": "Adicionar tema personalizado",
+            "custom_theme_downloading": "A transferir tema personalizado...",
+            "custom_theme_error_downloading": "Erro ao descarregar informações do tema.",
+            "custom_theme_help": "Introduz o URL de um tema personalizado que pretendes aplicar.",
+            "custom_theme_invalid": "Esquema de tema inválido.",
+            "dialog_title": "<strong>Configurações:</strong> Aparência",
+            "font_size": "Tamanho de letra",
+            "font_size_default": "%(fontSize)s (padrão)",
+            "high_contrast": "Alto contraste",
+            "image_size_default": "Padrão",
+            "image_size_large": "Grande",
+            "layout_bubbles": "Bolhas de mensagem",
+            "layout_irc": "IRC (Experimental)",
+            "match_system_theme": "Corresponde ao tema do sistema",
+            "timeline_image_size": "Tamanho da imagem na cronologia"
+        },
+        "automatic_language_detection_syntax_highlight": "Ativar deteção automática da linguagem para realce da sintaxe",
+        "autoplay_gifs": "GIFs de reprodução automática",
+        "autoplay_videos": "Vídeos de reprodução automática",
+        "big_emoji": "Permitir o emoji grande no chat",
+        "code_block_expand_default": "Expandir blocos de código por defeito",
+        "code_block_line_numbers": "Mostrar números de linha em blocos de código",
+        "disable_historical_profile": "Mostrar a imagem e o nome atuais do perfil dos utilizadores no histórico de mensagens",
+        "discovery": {
+            "title": "Como te encontrar"
+        },
+        "emoji_autocomplete": "Permitir sugestões de Emoji durante a escrita",
+        "enable_markdown": "Ativar Markdown",
+        "enable_markdown_description": "Inicia as mensagens com <code>/plain</code> para enviar sem marcação.",
+        "general": {
+            "account_management_section": "Gestão de conta",
+            "account_section": "Conta",
+            "add_email_dialog_title": "Adicione adresso de e-mail",
+            "add_email_failed_verification": "Não foi possível verificar o endereço de email: verifique se você realmente clicou no link que está no seu email",
+            "add_email_instructions": "Enviámos-lhe um email para confirmar o seu endereço. Por favor siga as instruções no email e depois clique no botão abaixo.",
+            "add_msisdn_confirm_body": "Pressione o botão abaixo para confirmar a adição este número de telefone.",
+            "add_msisdn_confirm_button": "Confirme que quer adicionar o número de telefone",
+            "add_msisdn_confirm_sso_button": "Confirme que quer adicionar este número de telefone usando Single Sign On para provar a sua identidade.",
+            "add_msisdn_dialog_title": "Adicione número de telefone",
+            "add_msisdn_instructions": "Foi enviada uma mensagem de texto para +%(msisdn)s. Introduz o código de verificação que contém.",
+            "add_msisdn_misconfigured": "A junção / vinculo com o fluxo MSISDN está mal configurado",
+            "allow_spellcheck": "Permitir verificação ortográfica",
+            "application_language": "Língua de aplicação",
+            "application_language_reload_hint": "O aplicativo será recarregado depois de selecionar outro idioma",
+            "avatar_remove_progress": "Removendo a imagem...",
+            "avatar_save_progress": "A carregar imagem...",
+            "avatar_upload_error_text": "O formato de arquivo não é suportado ou a imagem é maior que %(size)s.",
+            "avatar_upload_error_text_generic": "O formato de ficheiro poderá não ser suportado.",
+            "avatar_upload_error_title": "Não foi possível carregar a imagem do avatar",
+            "confirm_adding_email_body": "Pressione o botão abaixo para confirmar se quer adicionar este endereço de email.",
+            "confirm_adding_email_title": "Confirmar adição de email",
+            "deactivate_confirm_body": "Tens a certeza de que queres desativar a tua conta? Isto é irreversível.",
+            "deactivate_confirm_body_sso": "Confirma a desativação da tua conta utilizando o início de sessão único para provar a tua identidade.",
+            "deactivate_confirm_content": "Confirma que pretendes desativar a tua conta. Se prosseguires:",
+            "deactivate_confirm_content_1": "Não poderás reativar a tua conta",
+            "deactivate_confirm_content_2": "Já não poderás iniciar sessão",
+            "deactivate_confirm_content_3": "Ninguém poderá reutilizar o seu nome de utilizador (MXID), incluindo o próprio: este nome de utilizador permanecerá indisponível",
+            "deactivate_confirm_content_4": "Abandonarás todas as salas e mensagens diretas em que te encontras",
+            "deactivate_confirm_content_5": "Serás removido do servidor de identidade: os teus amigos deixarão de poder encontrar-te com o teu e-mail ou número de telefone",
+            "deactivate_confirm_content_6": "As tuas mensagens antigas continuarão a ser visíveis para as pessoas que as receberam, tal como os e-mails que enviaste no passado. Queres ocultar as tuas mensagens enviadas das pessoas que se juntarem às salas no futuro?",
+            "deactivate_confirm_continue": "Confirma a desativação da conta",
+            "deactivate_confirm_erase_label": "Esconde as minhas mensagens dos novos aderentes",
+            "deactivate_section": "Desativar conta",
+            "deactivate_warning": "A desativação da tua conta é uma ação permanente - tem cuidado!",
+            "discovery_email_empty": "As opções de descoberta vão aparecer assim que adicione um e-mail acima.",
+            "discovery_email_verification_instructions": "Verifica o link na tua caixa de entrada",
+            "discovery_msisdn_empty": "As opções de descoberta aparecerão quando tiveres adicionado um número de telefone acima.",
+            "discovery_needs_terms": "Concorda com os Termos de Serviço do servidor de identidade (%(serverName)s) para que possas ser descoberto através do teu endereço de e-mail ou número de telefone.",
+            "discovery_needs_terms_title": "Deixa que as pessoas te encontrem",
+            "display_name": "Nome de exibição",
+            "display_name_error": "Não é possível definir o nome para exibição",
+            "email_address_in_use": "Este endereço de email já está sendo usado",
+            "email_address_label": "Endereço de e-mail",
+            "email_not_verified": "O teu endereço de e-mail ainda não foi verificado",
+            "email_verification_instructions": "Clica no link do e-mail que recebeste para verificar e, de seguida, clica novamente em continuar.",
+            "emails_heading": "Endereços de e-mail",
+            "error_add_email": "Não foi possível adicionar endereço de email",
+            "error_deactivate_communication": "Houve um problema de comunicação com o servidor. Por favor, tenta novamente.",
+            "error_deactivate_invalid_auth": "O servidor não devolveu informações de autenticação válidas.",
+            "error_deactivate_no_auth": "O servidor não exigiu qualquer autenticação",
+            "error_email_verification": "Não foi possível verificar o endereço de email.",
+            "error_invalid_email": "Endereço de email inválido",
+            "error_invalid_email_detail": "Este não aparenta ser um endereço de email válido",
+            "error_msisdn_verification": "Não foi possível verificar o número de telefone.",
+            "error_password_change_403": "Falha ao alterar a palavra-passe. A sua palavra-passe está correta?",
+            "error_password_change_http": "%(errorMessage)s (Estado HTTP %(httpStatus)s)",
+            "error_password_change_title": "Erro ao alterar a palavra-passe",
+            "error_password_change_unknown": "Erro de alteração de senha desconhecido (%(stringifiedError)s)",
+            "error_remove_3pid": "Não foi possível remover informação de contato",
+            "error_revoke_email_discovery": "Não é possível revogar a partilha do endereço de e-mail",
+            "error_revoke_msisdn_discovery": "Não é possível revogar a partilha do número de telefone",
+            "error_share_email_discovery": "Não é possível partilhar o endereço de e-mail",
+            "error_share_msisdn_discovery": "Não é possível partilhar o número de telefone",
+            "identity_server_no_token": "Nenhum token de identidade de acesso encontrado",
+            "identity_server_not_set": "Servidor de identidade não definido",
+            "language_section": "Idioma e região",
+            "msisdn_in_use": "Este número de telefone já está sendo usado",
+            "msisdn_label": "Número de Telefone",
+            "msisdn_verification_field_label": "Código de verificação",
+            "msisdn_verification_instructions": "Introduz o código de verificação enviado por mensagem de texto.",
+            "msisdns_heading": "Números de telefone",
+            "oidc_manage_button": "Gerir conta",
+            "password_change_section": "Define uma nova palavra-passe para a conta...",
+            "password_change_success": "A tua palavra-passe foi alterada com sucesso.",
+            "personal_info": "Informação pessoal",
+            "profile_subtitle": "É assim que você aparece para outras pessoas no aplicativo.",
+            "profile_subtitle_oidc": "A tua conta é gerida separadamente por um fornecedor de identidade, pelo que algumas das tuas informações pessoais não podem ser alteradas aqui.",
+            "remove_email_prompt": "Remove %(email)s?",
+            "remove_msisdn_prompt": "Remove %(phone)s?",
+            "spell_check_locale_placeholder": "Escolhe um local",
+            "unable_to_load_emails": "Não é possível carregar endereços de e-mail",
+            "unable_to_load_msisdns": "Não é possível carregar números de telefone",
+            "username": "Nome de utilizador"
+        },
+        "image_thumbnails": "Mostrar pré-visualizações/miniaturas de imagens",
+        "inline_url_previews_default": "Ativar pré-visualizações de URL embutidas por predefinição",
+        "inline_url_previews_room": "Ativar pré-visualizações de URL por defeito para os participantes nesta sala",
+        "inline_url_previews_room_account": "Ativar pré-visualizações URL para esta sala (só te afeta a ti)",
+        "insert_trailing_colon_mentions": "Insere dois pontos após as menções do utilizador no início de uma mensagem",
+        "jump_to_bottom_on_send": "Salta para o fundo da linha de tempo quando enviar uma mensagem",
+        "key_backup": {
+            "backup_in_progress": "Está a ser feita uma cópia de segurança das tuas chaves (a primeira cópia de segurança pode demorar alguns minutos).",
+            "backup_starting": "Iniciar cópia de segurança...",
+            "backup_success": "Sucesso!",
+            "cannot_create_backup": "Não é possível criar uma cópia de segurança da chave",
+            "create_title": "Cria uma cópia de segurança da chave",
+            "setup_secure_backup": {
+                "backup_setup_success_description": "As tuas chaves estão agora a ser copiadas a partir deste dispositivo.",
+                "backup_setup_success_title": "Backup seguro bem-sucedido",
+                "cancel_warning": "Se cancelares agora, podes perder mensagens e dados encriptados se perderes o acesso aos teus logins.",
+                "confirm_security_phrase": "Confirma a tua frase de segurança",
+                "description": "Protege-te contra a perda de acesso a mensagens e dados encriptados fazendo uma cópia de segurança das chaves de encriptação no teu servidor.",
+                "download_or_copy": "%(downloadButton)s ou %(copyButton)s",
+                "enter_phrase_description": "Introduz uma frase de segurança que só tu conheças, pois é utilizada para proteger os teus dados. Para estares seguro, não deves reutilizar a palavra-passe da tua conta.",
+                "enter_phrase_title": "Introduzir uma frase de segurança",
+                "enter_phrase_to_confirm": "Introduz a tua frase de segurança uma segunda vez para a confirmar.",
+                "generate_security_key_description": "Iremos gerar uma chave de segurança para guardares num local seguro, como um gestor de palavras-passe ou um cofre.",
+                "generate_security_key_title": "Gera uma chave de segurança",
+                "pass_phrase_match_failed": "Isso não combina.",
+                "pass_phrase_match_success": "Isso combina!",
+                "phrase_strong_enough": "Ótimo! Esta frase de segurança parece suficientemente forte.",
+                "secret_storage_query_failure": "Não é possível consultar o estado do armazenamento secreto",
+                "security_key_safety_reminder": "Guarda a tua chave de segurança num local seguro, como um gestor de palavras-passe ou um cofre, uma vez que é utilizada para proteger os teus dados encriptados.",
+                "set_phrase_again": "Volta atrás para o definir novamente.",
+                "settings_reminder": "Também podes configurar a Cópia de segurança segura e gerir as tuas chaves nas Definições.",
+                "title_confirm_phrase": "Confirma a frase de segurança",
+                "title_save_key": "Guarda a tua chave de segurança",
+                "title_set_phrase": "Define uma frase de segurança",
+                "unable_to_setup": "Não é possível configurar o armazenamento secreto",
+                "use_different_passphrase": "Utiliza uma frase-chave diferente?",
+                "use_phrase_only_you_know": "Utiliza uma frase secreta que só tu sabes e, opcionalmente, guarda uma chave de segurança para utilizar como cópia de segurança."
+            }
+        },
+        "key_export_import": {
+            "confirm_passphrase": "Confirmar frase-passe",
+            "enter_passphrase": "Introduza a frase-passe",
+            "export_description_1": "Este processo permite que você exporte as chaves para mensagens que você recebeu em salas criptografadas para um arquivo local. Você poderá então importar o arquivo para outro cliente Matrix no futuro, de modo que este cliente também poderá descriptografar suas mensagens.",
+            "export_description_2": "O ficheiro exportado permitirá a qualquer pessoa que o possa ler desencriptar quaisquer mensagens encriptadas que possas ver, por isso deves ter o cuidado de o manter seguro. Para isso, deves introduzir uma frase-chave única abaixo, que só será utilizada para encriptar os dados exportados. Só poderás importar os dados se utilizares a mesma frase-chave.",
+            "export_title": "Exportar chaves de sala",
+            "file_to_import": "Arquivo para importar",
+            "import_description_1": "Este processo faz com que você possa importar as chaves de criptografia que tinha previamente exportado de outro cliente Matrix. Você poderá então descriptografar todas as mensagens que o outro cliente pôde criptografar.",
+            "import_description_2": "O ficheiro de exportação será protegido com uma frase-passe. Deve introduzir a frase-passe aqui, para desencriptar o ficheiro.",
+            "import_title": "Importar chaves de sala",
+            "phrase_cannot_be_empty": "A frase-passe não pode estar vazia",
+            "phrase_must_match": "As frases-passe devem coincidir",
+            "phrase_strong_enough": "Ótimo! Esta frase-passe parece suficientemente forte"
+        },
+        "keyboard": {
+            "dialog_title": "<strong>Configurações:</strong> Teclado",
+            "title": "Teclado"
+        },
+        "labs": {
+            "dialog_title": "<strong>Configurações:</strong> Laboratórios"
+        },
+        "labs_mjolnir": {
+            "dialog_title": "<strong>Configurações:</strong> Utilizadores ignorados"
+        },
+        "notifications": {
+            "default_setting_description": "Esta definição será aplicada por defeito a todas as tuas salas.",
+            "default_setting_section": "Quero ser notificado de (Predefinição)",
+            "desktop_notification_message_preview": "Mostra a pré-visualização da mensagem na notificação do ambiente de trabalho",
+            "dialog_title": "<strong>Definições:</strong> Notificações",
+            "email_description": "Recebe um resumo por e-mail das notificações perdidas",
+            "email_section": "Resumo do e-mail",
+            "email_select": "Selecciona os e-mails para os quais pretendes enviar resumos. Gere os teus e-mails em <button>Geral</button>.",
+            "enable_audible_notifications_session": "Ativar as notificações sonoras para esta sessão",
+            "enable_desktop_notifications_session": "Ativar as notificações de ambiente de trabalho para esta sessão",
+            "enable_email_notifications": "Ativar notificações de e-mail para %(email)s",
+            "enable_notifications_account": "Ativar as notificações para esta conta",
+            "enable_notifications_account_detail": "Desliga para desativar as notificações em todos os teus dispositivos e sessões",
+            "enable_notifications_device": "Ativa as notificações para este dispositivo",
+            "error_loading": "Ocorreu um erro ao carregar as tuas definições de notificação.",
+            "error_permissions_denied": "%(brand)s não tem permissões para enviar notificações a você - por favor, verifique as configurações do seu navegador",
+            "error_permissions_missing": "%(brand)s não tem permissões para enviar notificações a você - por favor, tente novamente",
+            "error_saving": "Erro ao guardar as preferências de notificação",
+            "error_saving_detail": "Ocorreu um erro ao guardar as tuas preferências de notificação.",
+            "error_title": "Não foi possível ativar as notificações",
+            "error_updating": "Ocorreu um erro ao atualizar as tuas preferências de notificação. Tenta alternar a tua opção novamente.",
+            "invites": "Convidado para uma sala",
+            "keywords": "Mostra um crachá <badge/> quando são utilizadas palavras-chave numa sala.",
+            "keywords_prompt": "Introduz aqui palavras-chave ou utiliza variações ortográficas ou alcunhas",
+            "labs_notice_prompt": "<strong>Atualização:</strong>Simplificámos as Definições de Notificações para tornar as opções mais fáceis de encontrar. Algumas definições personalizadas que escolheste no passado não são mostradas aqui, mas continuam ativas. Se prosseguires, algumas das tuas definições poderão ser alteradas. <a>Saber mais</a>",
+            "mentions_keywords": "Menções e Palavras-chave",
+            "mentions_keywords_only": "Apenas menções e palavras-chave",
+            "messages_containing_keywords": "Mensagens que contêm palavras-chave",
+            "noisy": "Barulhento",
+            "notices": "Mensagens enviadas por bots",
+            "notify_at_room": "Notifica quando alguém menciona a utilização de @sala",
+            "notify_keyword": "Notifica quando alguém utiliza uma palavra-chave",
+            "notify_mention": "Notifica quando alguém faz uma menção utilizando @nome_de_apresentação ou %(mxid)s",
+            "other_section": "Outras coisas que pensamos que te podem interessar:",
+            "people_mentions_keywords": "Pessoas, menções e palavras-chave",
+            "play_sound_for_description": "Aplicado por defeito a todas as salas em todos os dispositivos.",
+            "play_sound_for_section": "Toca um som para",
+            "push_targets": "Alvos de notificação",
+            "quick_actions_mark_all_read": "Marca todas as mensagens como lidas",
+            "quick_actions_reset": "Repor as predefinições",
+            "quick_actions_section": "Ações Rápidas",
+            "room_activity": "Ocorrem mensagens de nova atividade na sala, actualizações e estado",
+            "rule_call": "Convite para chamada",
+            "rule_contains_display_name": "Mensagens contendo o meu nome público",
+            "rule_contains_user_name": "Mensagens contendo o meu nome de utilizador",
+            "rule_encrypted": "Mensagens encriptadas em conversas de grupo",
+            "rule_encrypted_room_one_to_one": "Mensagens encriptadas em conversas de um para um",
+            "rule_invite_for_me": "Quando sou convidado para uma sala",
+            "rule_message": "Mensagens em salas",
+            "rule_room_one_to_one": "Mensagens em conversas pessoais",
+            "rule_roomnotif": "Mensagens contendo @sala",
+            "rule_suppress_notices": "Mensagens enviadas por bots",
+            "rule_tombstone": "Quando as salas são atualizadas",
+            "show_message_desktop_notification": "Mostra a mensagem na notificação do ambiente de trabalho",
+            "voip": "Chamadas de áudio e vídeo"
+        },
+        "preferences": {
+            "Electron.enableHardwareAcceleration": "Ativa a aceleração por hardware (reinicia %(appName)s para surtir efeito)",
+            "always_show_menu_bar": "Mostra sempre a barra de menu da janela",
+            "autocomplete_delay": "Atraso do preenchimento automático (ms)",
+            "code_blocks_heading": "Blocos de código",
+            "compact_modern": "Utiliza um layout \"moderno\" mais compacto",
+            "composer_heading": "Compositor",
+            "dialog_title": "<strong>Definições:</strong> Preferências",
+            "enable_hardware_acceleration": "Ativar a aceleração de hardware",
+            "enable_tray_icon": "Mostra o ícone do tabuleiro e minimiza a janela ao fechar",
+            "keyboard_heading": "Atalhos do teclado",
+            "keyboard_view_shortcuts_button": "Para ver todos os atalhos de teclado, <a>clica aqui</a>.",
+            "media_heading": "Imagens, GIFs e vídeos",
+            "presence_description": "Partilha a tua atividade e o teu estado com outros.",
+            "rm_lifetime": "Vida útil do marcador de leitura (ms)",
+            "rm_lifetime_offscreen": "Vida útil do marcador de leitura fora do ecrã (ms)",
+            "room_directory_heading": "Diretório de salas",
+            "room_list_heading": "Lista de salas",
+            "show_avatars_pills": "Mostra os avatares nas menções de utilizadores, salas e eventos",
+            "show_polls_button": "Mostrar botão de sondagens",
+            "surround_text": "Rodeia o texto selecionado ao escrever caracteres especiais",
+            "time_heading": "Mostra a hora"
+        },
+        "prompt_invite": "Avisa antes de enviar convites para IDs de matrix potencialmente inválidos",
+        "replace_plain_emoji": "Substituir Emoji de texto automaticamente",
+        "security": {
+            "4s_public_key_in_account_data": "nos dados da conta",
+            "4s_public_key_status": "Chave pública de armazenamento secreto:",
+            "analytics_description": "Partilha dados anónimos para nos ajudar a identificar problemas. Nada de pessoal. Sem terceiros.",
+            "backup_key_cached_status": "Chave de backup armazenada em cache:",
+            "backup_key_stored_status": "Chave de backup armazenada:",
+            "backup_key_unexpected_type": "tipo inesperado",
+            "backup_key_well_formed": "bem formado",
+            "backup_keys_description": "Faz uma cópia de segurança das tuas chaves de encriptação com os dados da tua conta para o caso de perderes o acesso às tuas sessões. As tuas chaves serão protegidas com uma chave de segurança única.",
+            "bulk_options_accept_all_invites": "Aceita todos os convites de %(invitedRooms)s ",
+            "bulk_options_reject_all_invites": "Rejeitar todos os %(invitedRooms)s convites",
+            "bulk_options_section": "Opções em massa",
+            "cross_signing_cached": "armazenado em cache localmente",
+            "cross_signing_homeserver_support": "Suporte a recursos de servidor doméstico:",
+            "cross_signing_homeserver_support_exists": "existe",
+            "cross_signing_in_4s": "em armazenamento secreto",
+            "cross_signing_in_memory": "na memória",
+            "cross_signing_master_private_Key": "Chave mestra privada:",
+            "cross_signing_not_cached": "não encontrado localmente",
+            "cross_signing_not_found": "não encontrado",
+            "cross_signing_not_in_4s": "não encontrado no armazenamento",
+            "cross_signing_not_stored": "não armazenado",
+            "cross_signing_private_keys": "Assinatura cruzada de chaves privadas:",
+            "cross_signing_public_keys": "Assinatura cruzada de chaves públicas:",
+            "cross_signing_self_signing_private_key": "Chave privada com assinatura automática:",
+            "cross_signing_user_signing_private_key": "Chave privada de assinatura do utilizador:",
+            "cryptography_section": "Criptografia",
+            "dehydrated_device_description": "A funcionalidade de dispositivo offline permite-te receber mensagens encriptadas mesmo quando não tens sessão iniciada em nenhum dispositivo",
+            "dehydrated_device_enabled": "Dispositivo offline ativado",
+            "delete_backup": "Eliminar cópia de segurança",
+            "delete_backup_confirm_description": "Tens a certeza? Perderás as tuas mensagens encriptadas se as tuas chaves não forem guardadas corretamente.",
+            "dialog_title": "<strong>Definições:</strong> Segurança e privacidade",
+            "e2ee_default_disabled_warning": "O administrador do teu servidor desactivou a encriptação de ponta a ponta por defeito nas salas privadas e nas Mensagens directas.",
+            "enable_message_search": "Ativar a pesquisa de mensagens em salas encriptadas",
+            "encryption_section": "Encriptação",
+            "error_loading_key_backup_status": "Não é possível carregar o estado da cópia de segurança da chave",
+            "export_megolm_keys": "Exportar chaves ponta-a-ponta da sala",
+            "ignore_users_empty": "Não tens utilizadores ignorados.",
+            "ignore_users_section": "Utilizadores ignorados",
+            "import_megolm_keys": "Importar chave de criptografia ponta-a-ponta (E2E) da sala",
+            "key_backup_active": "Esta sessão está a realizar as cópias de segurança das tuas chaves.",
+            "key_backup_active_version": "Versão de cópia de segurança ativa:",
+            "key_backup_active_version_none": "Nenhum",
+            "key_backup_algorithm": "Algoritmo:",
+            "key_backup_can_be_restored": "Esta cópia de segurança pode ser restaurada nesta sessão",
+            "key_backup_complete": "Cópia de segurança de todas as chaves realizada",
+            "key_backup_connect": "Liga esta sessão à cópia de segurança das chaves",
+            "key_backup_connect_prompt": "Liga esta sessão à cópia de segurança de chaves antes de terminares a sessão para evitar perderes quaisquer chaves que possam estar apenas nesta sessão.",
+            "key_backup_in_progress": "Fazendo backup das chaves de %(sessionsRemaining)s...",
+            "key_backup_inactive": "Esta sessão não <b>está a realizar as cópias de segurança das tuas chaves</b>, mas tens uma cópia de segurança existente a partir da qual podes restaurar e adicionar mais.",
+            "key_backup_inactive_warning": "As tuas chaves <b>não estão a ser copiadas em segurança a partir desta sessão</b>.",
+            "key_backup_latest_version": "Versão mais recente da cópia de segurança no servidor:",
+            "message_search_disable_warning": "Se estiver desactivada, as mensagens de salas encriptadas não aparecerão nos resultados da pesquisa.",
+            "message_search_disabled": "Armazena em cache de forma segura as mensagens encriptadas localmente para que apareçam nos resultados de pesquisa.",
+            "message_search_enabled": {
+                "one": "Coloca em cache de forma segura mensagens encriptadas localmente para que apareçam nos resultados de pesquisa, utilizando %(size)s para armazenar mensagens da sala %(rooms)s.",
+                "other": "Coloca em cache de forma segura mensagens encriptadas localmente para que apareçam nos resultados de pesquisa, utilizando %(size)s para armazenar mensagens de salas %(rooms)s."
+            },
+            "message_search_failed": "Falha na inicialização da pesquisa de mensagens",
+            "message_search_indexed_messages": "Mensagens indexadas:",
+            "message_search_indexed_rooms": "Salas indexadas:",
+            "message_search_indexing": "Atualmente a indexar: %(currentRoom)s",
+            "message_search_indexing_idle": "No momento, não estamos indexando mensagens de nenhuma sala.",
+            "message_search_intro": "%(brand)s está a armazenar em segurança mensagens encriptadas localmente para que apareçam nos resultados da pesquisa:",
+            "message_search_room_progress": "%(doneRooms)s fora de %(totalRooms)s",
+            "message_search_section": "Pesquisa de mensagens",
+            "message_search_sleep_time": "A que velocidade as mensagens devem ser descarregadas.",
+            "message_search_space_used": "Espaço utilizado:",
+            "message_search_unsupported": "%(brand)s não tem alguns componentes necessários para guardar mensagens encriptadas localmente de forma segura. Se quiseres experimentar esta funcionalidade, constrói um ambiente de trabalho %(brand)s personalizado com <nativeLink>componentes de pesquisa adicionados</nativeLink>.",
+            "message_search_unsupported_web": "%(brand)s não é possível armazenar mensagens encriptadas em cache com segurança localmente durante a execução num navegador da Web. Usa <desktopLink>%(brand)s Desktop</desktopLink> para que as mensagens encriptadas apareçam nos resultados da pesquisa.",
+            "record_session_details": "Grava o nome do cliente, a versão e o URL para reconhecer mais facilmente as sessões no gestor de sessões",
+            "restore_key_backup": "Restaurar a partir da cópia de segurança",
+            "secret_storage_not_ready": "não está pronto",
+            "secret_storage_ready": "pronto",
+            "secret_storage_status": "Armazenamento secreto:",
+            "send_analytics": "Envia dados analíticos",
+            "session_id": "Identificação de sessão:",
+            "session_key": "Chave da sessão:",
+            "strict_encryption": "Nunca envies mensagens encriptadas para sessões não verificadas a partir desta sessão"
+        },
+        "send_read_receipts": "Enviar recibos lidos",
+        "send_read_receipts_unsupported": "O teu servidor não suporta a desativação do envio de recibos de leitura.",
+        "send_typing_notifications": "Enviar notificações de digitação",
+        "sessions": {
+            "best_security_note": "Para maior segurança, verifica as tuas sessões e termina a sessão de qualquer sessão que já não reconheças ou utilizes.",
+            "browser": "Navegador",
+            "confirm_sign_out": {
+                "one": "Confirma a saída deste dispositivo",
+                "other": "Confirma a saída destes dispositivos"
+            },
+            "confirm_sign_out_body": {
+                "one": "Clica no botão abaixo para confirmar a saída deste dispositivo.",
+                "other": "Clica no botão abaixo para confirmar a saída destes dispositivos."
+            },
+            "confirm_sign_out_continue": {
+                "one": "Dispositivo de desconexão",
+                "other": "Dispositivos de desconexão"
+            },
+            "confirm_sign_out_sso": {
+                "one": "Confirma a saída deste dispositivo utilizando o o início de sessão único para provar a tua identidade.",
+                "other": "Confirma a saída destes dispositivos utilizando o início de sessão único para provar a tua identidade."
+            },
+            "current_session": "Sessão atual",
+            "desktop_session": "Sessão de ambiente de trabalho",
+            "details_heading": "Detalhes da sessão",
+            "device_unverified_description": "Verifica ou termina a sessão para maior segurança e fiabilidade.",
+            "device_unverified_description_current": "Verifica a tua sessão atual para mensagens seguras melhoradas.",
+            "device_verified_description": "Esta sessão está pronta para o envio de mensagens seguras.",
+            "device_verified_description_current": "A tua sessão atual está pronta para o envio seguro de mensagens.",
+            "dialog_title": "<strong>Configurações:</strong> Sessões",
+            "error_pusher_state": "Falha ao definir o estado do empurrador",
+            "error_set_name": "Falha ao definir o nome da sessão",
+            "filter_all": "Tudo",
+            "filter_inactive": "Inativo",
+            "filter_inactive_description": "Inativo por %(inactiveAgeDays)s dias ou mais",
+            "filter_label": "Dispositivos de filtragem",
+            "filter_unverified_description": "Não está pronto para mensagens seguras",
+            "filter_verified_description": "Pronto para mensagens seguras",
+            "hide_details": "Ocultar detalhes",
+            "inactive_days": "Inativo por mais de %(inactiveAgeDays)s dias",
+            "inactive_sessions": "Sessões inativas",
+            "inactive_sessions_explainer_1": "As sessões inativas são sessões que não utilizas há algum tempo, mas que continuam a receber chaves de encriptação.",
+            "inactive_sessions_explainer_2": "A remoção de sessões inativas melhora a segurança e o desempenho e facilita a identificação de uma nova sessão suspeita.",
+            "inactive_sessions_list_description": "Considera a possibilidade de sair de sessões antigas (%(inactiveAgeDays)s dias ou mais) que já não utilizas.",
+            "ip": "Endereço IP",
+            "last_activity": "Última atividade",
+            "mobile_session": "Sessão móvel",
+            "n_sessions_selected": {
+                "one": "%(count)s sessão selecionada",
+                "other": "%(count)s sessões seleccionadas"
+            },
+            "no_inactive_sessions": "Nenhuma sessão inativa foi encontrada.",
+            "no_sessions": "Nenhuma sessão encontrada",
+            "no_unverified_sessions": "Nenhuma sessão não verificada foi encontrada.",
+            "no_verified_sessions": "Nenhuma sessão verificada foi encontrada.",
+            "os": "Sistema operativo",
+            "other_sessions_heading": "Outras sessões",
+            "push_heading": "Notificações push",
+            "push_subheading": "Recebe notificações push sobre esta sessão.",
+            "push_toggle": "Alterna as notificações push nesta sessão.",
+            "rename_form_caption": "Tem em atenção que os nomes das sessões também são visíveis para as pessoas com quem comunicas.",
+            "rename_form_heading": "Mudar o nome da sessão",
+            "rename_form_learn_more": "Renomear sessões",
+            "rename_form_learn_more_description_1": "Outros utilizadores nas mensagens diretas e nas salas em que participas podem ver uma lista completa das tuas sessões.",
+            "rename_form_learn_more_description_2": "Isto dá-lhes a certeza de que estão realmente a falar contigo, mas também significa que podem ver o nome da sessão que introduzires aqui.",
+            "security_recommendations": "Recomendações de segurança",
+            "security_recommendations_description": "Melhora a segurança da tua conta seguindo estas recomendações.",
+            "session_id": "Identificador de sessão",
+            "show_details": "Mostrar detalhes",
+            "sign_in_with_qr": "Ligar novo dispositivo",
+            "sign_in_with_qr_button": "Mostrar código QR",
+            "sign_in_with_qr_description": "Utiliza um código QR para iniciar sessão noutro dispositivo e configurar as mensagens seguras.",
+            "sign_out": "Sair desta sessão",
+            "sign_out_all_other_sessions": "Sair de todas as outras sessões (%(otherSessionsCount)s)",
+            "sign_out_confirm_description": {
+                "one": "Tens a certeza de que queres sair da sessão %(count)s?",
+                "other": "Tens a certeza de que queres sair das sessões de %(count)s?"
+            },
+            "sign_out_n_sessions": {
+                "one": "Sai da sessão %(count)s ",
+                "other": "Sai das sessões %(count)s "
+            },
+            "title": "Sessões",
+            "unknown_session": "Tipo de sessão desconhecido",
+            "unverified_session": "Sessão não verificada",
+            "unverified_session_explainer_1": "Esta sessão não suporta encriptação e, por isso, não pode ser verificada.",
+            "unverified_session_explainer_2": "Não poderás participar em salas onde a encriptação está activada quando utilizares esta sessão.",
+            "unverified_session_explainer_3": "Para maior segurança e privacidade, recomenda-se a utilização de clientes Matrix que suportem encriptação.",
+            "unverified_sessions": "Sessões não verificadas",
+            "unverified_sessions_explainer_1": "As sessões não verificadas são aquelas em que iniciaram sessão com as tuas credenciais, mas que não foram objeto de verificação cruzada.",
+            "unverified_sessions_explainer_2": "Deves certificar-te de que reconheces estas sessões, pois podem representar uma utilização não autorizada da tua conta.",
+            "unverified_sessions_list_description": "Verifica as tuas sessões para obteres mensagens seguras melhoradas ou termina a sessão das que já não reconheces ou utilizas.",
+            "url": "URL",
+            "verified_session": "Sessão verificada",
+            "verified_sessions": "Sessões verificadas",
+            "verified_sessions_explainer_1": "As sessões verificadas são qualquer lugar onde estejas a utilizar esta conta depois de introduzires a tua frase-chave ou confirmares a tua identidade com outra sessão verificada.",
+            "verified_sessions_explainer_2": "Isto significa que tens todas as chaves necessárias para desbloquear as tuas mensagens encriptadas e confirmar aos outros utilizadores que confias nesta sessão.",
+            "verified_sessions_list_description": "Para maior segurança, termina a sessão de qualquer sessão que já não reconheças ou utilizes.",
+            "verify_session": "Verificar sessão",
+            "web_session": "Sessão Web"
+        },
+        "show_avatar_changes": "Mostrar alterações de imagem de perfil",
+        "show_breadcrumbs": "Mostrar atalhos para salas recentemente visualizadas acima da lista de salas",
+        "show_chat_effects": "Mostrar efeitos de conversação (animações ao receber, por exemplo, confetes)",
+        "show_displayname_changes": "Mostrar alterações no nome de exibição",
+        "show_join_leave": "Mostra as mensagens de entrada/saída (convites/remoções/proibições não afetados)",
+        "show_nsfw_content": "Mostrar conteúdo NSFW",
+        "show_read_receipts": "Mostrar recibos de leitura enviados por outros usuários",
+        "show_redaction_placeholder": "Mostrar um marcador de posição para mensagens removidas",
+        "show_stickers_button": "Mostrar botão de stickers",
+        "show_typing_notifications": "Mostrar notificações de digitação",
+        "showbold": "Mostra toda a atividade na lista de salas (pontos ou número de mensagens não lidas)",
+        "sidebar": {
+            "dialog_title": "<strong>Configurações:</strong> Barra lateral",
+            "metaspaces_favourites_description": "Agrupa todas as tuas salas e pessoas favoritas num único local.",
+            "metaspaces_home_all_rooms": "Mostra todas as salas",
+            "metaspaces_home_all_rooms_description": "Mostra todos as tuas salas na Página Inicial, mesmo que estejam num espaço.",
+            "metaspaces_home_description": "A página inicial é útil para obter uma visão geral de tudo.",
+            "metaspaces_orphans": "Salas fora de um espaço",
+            "metaspaces_orphans_description": "Agrupa todas as tuas salas que não fazem parte de um espaço num único local.",
+            "metaspaces_people_description": "Agrupa todas as tuas pessoas num único local.",
+            "metaspaces_subsection": "Espaços para mostrar",
+            "metaspaces_video_rooms": "Salas de vídeo e conferências",
+            "metaspaces_video_rooms_description": "Agrupa todas as salas de vídeo privadas e conferências.",
+            "metaspaces_video_rooms_description_invite_extension": "Nas conferências, podes convidar pessoas fora do Matrix",
+            "spaces_explainer": "Os espaços são formas de agrupar divisões e pessoas. Para além dos espaços em que te encontras, também podes utilizar alguns espaços pré-construídos.",
+            "title": "Barra lateral"
+        },
+        "start_automatically": "Iniciar automaticamente ao iniciar o sistema",
+        "tac_only_notifications": "Mostra apenas as notificações no centro de actividades do tópico",
+        "use_12_hour_format": "Mostrar os horários em formato de 12h (p.ex: 2:30pm)",
+        "use_command_enter_send_message": "Utiliza Command + Enter para enviar uma mensagem",
+        "use_command_f_search": "Utiliza Command + F para pesquisar a cronologia",
+        "use_control_enter_send_message": "Utiliza Ctrl + Enter para enviar uma mensagem",
+        "use_control_f_search": "Usa Ctrl + F para pesquisar a cronologia",
+        "voip": {
+            "allow_p2p": "Permitir chamadas ponto a ponto para chamadas individuais",
+            "allow_p2p_description": "Quando ativado, a outra parte poderá ver o teu endereço IP",
+            "audio_input_empty": "Não foi detetado nenhum microfone",
+            "audio_output": "Saída de áudio",
+            "audio_output_empty": "Não foram detectadas saídas de áudio",
+            "auto_gain_control": "Controlo automático de ganho",
+            "connection_section": "Ligação",
+            "dialog_title": "<strong>Definições:</strong> Voz e vídeo",
+            "echo_cancellation": "Cancelamento de eco",
+            "enable_fallback_ice_server": "Permite o servidor de assistência a chamadas de recurso (%(server)s)",
+            "enable_fallback_ice_server_description": "Só se aplica se o teu servidor doméstico não oferecer um. O teu endereço IP será partilhado durante uma chamada.",
+            "mirror_local_feed": "Espelha o feed de vídeo local",
+            "missing_permissions_prompt": "Se faltarem permissões para os meios de comunicação, clica no botão abaixo para as solicitar.",
+            "noise_suppression": "Supressão de ruído",
+            "request_permissions": "Pedir permissões para os meios de comunicação social",
+            "title": "Voz e vídeo",
+            "video_input_empty": "Não foi detetada nenhuma Webcam",
+            "video_section": "Definições de vídeo",
+            "voice_agc": "Ajusta automaticamente o volume do microfone",
+            "voice_processing": "Processamento de voz",
+            "voice_section": "Definições de voz"
+        },
+        "warn_quit": "Avisa antes de desistir",
+        "warning": "<w>AVISO:</w><description/>"
+    },
+    "share": {
+        "permalink_message": "Link para a mensagem selecionada",
+        "permalink_most_recent": "Link para a mensagem mais recente",
+        "share_call": "Link de convite para conferência",
+        "share_call_subtitle": "Link para usuários externos ingressarem na chamada sem uma conta matrix:",
+        "title_link": "Partilhar ligação",
+        "title_message": "Partilhar mensagem da sala",
+        "title_room": "Partilhar sala",
+        "title_user": "Partilhar utilizador"
+    },
+    "slash_command": {
+        "addwidget": "Adiciona um widget personalizado por URL à sala",
+        "addwidget_iframe_missing_src": "o iframe não tem atributo src",
+        "addwidget_invalid_protocol": "Fornece um URL do widget https:// ou http://",
+        "addwidget_missing_url": "Fornece um URL de widget ou código de incorporação",
+        "addwidget_no_permissions": "Não podes modificar widgets nesta sala.",
+        "ban": "Banir usuários com o identificador informado",
+        "category_actions": "Ações",
+        "category_admin": "Administrador",
+        "category_advanced": "Avançado",
+        "category_effects": "Ações",
+        "category_messages": "Mensagens",
+        "category_other": "Outros",
+        "command_error": "Erro de comando",
+        "converttodm": "Converte a sala numa DM",
+        "converttoroom": "Converte a DM numa sala",
+        "could_not_find_room": "Não foi possível encontrar a sala",
+        "deop": "Retirar função de moderador do usuário com o identificador informado",
+        "devtools": "Abre o diálogo das Ferramentas do desenvolvedor",
+        "discardsession": "Força a rejeição da atual sessão de grupo de saída numa sala encriptada",
+        "error_invalid_rendering_type": "Erro de comando: Não foi possível encontrar o tipo de renderização(%(renderingType)s)",
+        "error_invalid_room": "Falha no comando: Não foi possível encontrar a sala (%(roomId)s)",
+        "error_invalid_runfn": "Erro de comando: Não foi possível lidar com o comando de barra.",
+        "error_invalid_user_in_room": "Não foi possível encontrar o utilizador na sala",
+        "help": "Apresenta uma lista de comandos com utilizações e descrições",
+        "help_dialog_title": "Ajuda do comando",
+        "holdcall": "Coloca a chamada na sala atual em espera",
+        "html": "Envia uma mensagem como html, sem a interpretar como markdown",
+        "ignore": "Ignora um utilizador, deixando de mostrar as mensagens dele",
+        "ignore_dialog_description": "Está agora a ignorar %(userId)s",
+        "ignore_dialog_title": "Utilizador ignorado",
+        "invite": "Convidar usuários com um dado identificador para esta sala",
+        "invite_3pid_needs_is_error": "Utiliza um servidor de identidade para convidar por e-mail. Faz a gestão nas Definições.",
+        "invite_3pid_use_default_is_title": "Utiliza um servidor de identidade",
+        "invite_3pid_use_default_is_title_description": "Utiliza um servidor de identidade para convidar por e-mail. Clica em continuar para utilizar o servidor de identidades predefinido (%(defaultIdentityServerName)s) ou em gerir nas Definições.",
+        "invite_failed": "O utilizador (%(user)s) não acabou por ser convidado para %(roomId)s mas o utilitário de convite não deu qualquer erro",
+        "join": "Entra na sala com o endereço indicado",
+        "jumptodate": "Salta para a data indicada na linha de tempo",
+        "jumptodate_invalid_input": "Não foi possível compreender a data indicada (%(inputDate)s). Tenta utilizar o formato AAAA-MM-DD.",
+        "lenny": "Pré-anexa ( ͡° ͜ʖ ͡°) a uma mensagem de texto simples",
+        "me": "Visualizar atividades",
+        "msg": "Envia uma mensagem para o utilizador indicado",
+        "myavatar": "Muda a sua foto de perfil em todas as salas",
+        "myroomavatar": "Altera a tua imagem de perfil apenas nesta sala atual",
+        "myroomnick": "Altera a tua alcunha de apresentação apenas na sala atual",
+        "nick": "Troca o seu apelido",
+        "no_active_call": "Não há nenhuma chamada ativa nesta sala",
+        "op": "Definir o nível de privilégios de um utilizador",
+        "part_unknown_alias": "Endereço de sala não reconhecido: %(roomAlias)s",
+        "plain": "Envia uma mensagem como texto simples, sem a interpretar como markdown",
+        "query": "Abre o chat com o utilizador indicado",
+        "query_not_found_phone_number": "Não é possível encontrar o ID de Matrix para o número de telefone",
+        "rageshake": "Envia um relatório de erro com registos",
+        "rainbow": "Envia a mensagem colorida como o arco-íris",
+        "rainbowme": "Envia a emote colorida como o arco-íris",
+        "remove": "Remove o utilizador com o id indicado desta sala",
+        "roomavatar": "Altera o avatar da sala atual",
+        "roomname": "Define o nome da sala",
+        "server_error": "Erro no servidor",
+        "server_error_detail": "O servidor pode estar indisponível, sobrecarregado, ou alguma outra coisa não funcionou.",
+        "shrug": "Pré-anexa ¯ \\ _ (ツ) _ / ¯ a uma mensagem de texto simples",
+        "spoiler": "Envia a mensagem como um spoiler",
+        "tableflip": "Pré-anexa (╯°□°)╯︵ ┻━┻ a uma mensagem de texto simples",
+        "topic": "Obtém ou define o tópico da sala",
+        "topic_none": "Esta sala não tem tópico.",
+        "topic_room_error": "Falha ao obter o tópico da sala: Não foi possível encontrar a sala (%(roomId)s",
+        "tovirtual": "Muda para a sala virtual desta sala, se houver uma",
+        "tovirtual_not_found": "Não há sala virtual para esta sala",
+        "unban": "Cancela o utilizador com um determinado ID",
+        "unflip": "Pré-anexa ┬──┬ ノ( ゜-゜ノ) a uma mensagem de texto simples",
+        "unholdcall": "Tira a chamada da sala atual da espera",
+        "unignore": "Deixa de ignorar um utilizador, mostrando as suas mensagens daqui para a frente",
+        "unignore_dialog_description": "%(userId)s já não é ignorado",
+        "unignore_dialog_title": "Utilizador não ignorado",
+        "unknown_command": "Comando desconhecido",
+        "unknown_command_button": "Enviar como mensagem",
+        "unknown_command_detail": "Comando não reconhecido: %(commandText)s",
+        "unknown_command_help": "Podes utilizar <code>/help</code> para listar os comandos disponíveis. Querias enviar isto como uma mensagem?",
+        "unknown_command_hint": "Dica: Começa a tua mensagem com <code>//</code> para a iniciares com uma barra.",
+        "upgraderoom": "Atualiza uma sala para uma nova versão",
+        "upgraderoom_permission_error": "Não tens as permissões necessárias para utilizar este comando.",
+        "usage": "Uso",
+        "view": "Visualiza a sala com o endereço indicado",
+        "whois": "Apresenta informações sobre um utilizador"
+    },
+    "space": {
+        "add_existing_room_space": {
+            "create": "Queres acrescentar uma nova sala em vez disso?",
+            "create_prompt": "Crie uma nova sala",
+            "dm_heading": "Mensagens diretas",
+            "error_heading": "Nem todos os seleccionados foram adicionados",
+            "progress_text": {
+                "one": "Adicionando sala...",
+                "other": "Adicionando salas... (%(progress)s fora de%(count)s )"
+            },
+            "space_dropdown_label": "Seleção de espaço",
+            "space_dropdown_title": "Adicionar salas existentes",
+            "subspace_moved_note": "A adição de espaços foi movida."
+        },
+        "add_existing_subspace": {
+            "create_button": "Cria um novo espaço",
+            "create_prompt": "Queres acrescentar um novo espaço em vez disso?",
+            "filter_placeholder": "Procura espaços",
+            "space_dropdown_title": "Acrescenta um espaço existente"
+        },
+        "context_menu": {
+            "devtools_open_timeline": "Vê a cronologia da sala (devtools)",
+            "explore": "Explorar rooms",
+            "home": "Espaço em casa",
+            "manage_and_explore": "Gere e explora as salas",
+            "options": "Opções de espaço"
+        },
+        "failed_load_rooms": "Falha ao carregar a lista de salas.",
+        "failed_remove_rooms": "Falha ao remover algumas salas. Tenta novamente mais tarde",
+        "incompatible_server_hierarchy": "O teu servidor não suporta a apresentação de hierarquias espaciais.",
+        "invite": "Convida pessoas",
+        "invite_description": "Convidar com email ou nome de utilizador",
+        "invite_link": "Partilhar a ligação de convite",
+        "joining_space": "Entrando...",
+        "landing_welcome": "Bem-vindo(a) a(ao) <name/>",
+        "leave_dialog_action": "Deixa espaço",
+        "leave_dialog_description": "Estás prestes a sair de <spaceName/>.",
+        "leave_dialog_only_admin_room_warning": "És o único administrador de algumas das salas ou espaços que desejas abandonar. Se os deixares, ficarão sem administradores.",
+        "leave_dialog_only_admin_warning": "És o único administrador deste espaço. Se o deixares, ninguém terá controlo sobre ele.",
+        "leave_dialog_option_all": "Sai de todos os quartos",
+        "leave_dialog_option_intro": "Gostarias de deixar as salas neste espaço?",
+        "leave_dialog_option_none": "Não deixes nenhum quarto",
+        "leave_dialog_option_specific": "Deixa alguns quartos",
+        "leave_dialog_public_rejoin_warning": "Só poderás voltar a participar se fores convidado novamente.",
+        "leave_dialog_title": "Sair %(spaceName)s",
+        "mark_suggested": "Marca como sugerido",
+        "no_search_result_hint": "Talvez queiras tentar uma pesquisa diferente ou verificar se há erros de digitação.",
+        "preferences": {
+            "sections_section": "Secções para mostrar",
+            "show_people_in_space": "Isto agrupa as tuas conversas com membros deste espaço. Se desactivares esta opção, ocultas essas conversas da tua vista de %(spaceName)s."
+        },
+        "room_filter_placeholder": "Pesquisar por salas",
+        "search_children": "Pesquisar %(spaceName)s",
+        "search_placeholder": "Pesquisar nomes e descrições",
+        "select_room_below": "Seleciona primeiro uma das salas abaixo",
+        "share_public": "Partilha o teu espaço público",
+        "suggested": "Sugerido",
+        "suggested_tooltip": "Esta sala é sugerida como uma boa sala para te juntares",
+        "title_when_query_available": "Resultados",
+        "title_when_query_unavailable": "Salas e espaços",
+        "unmark_suggested": "Marca como não sugerido",
+        "user_lacks_permission": "Não tens permissão"
+    },
+    "space_settings": {
+        "title": "Configurações - %(spaceName)s"
+    },
+    "spaces": {
+        "error_no_permission_add_room": "Não tens permissões para adicionar salas a este espaço",
+        "error_no_permission_add_space": "Não tens permissões para adicionar espaços a este espaço",
+        "error_no_permission_create_room": "Não tens permissões para criar novas salas neste espaço",
+        "error_no_permission_invite": "Não tens permissões para convidar pessoas para este espaço"
+    },
+    "spotlight": {
+        "public_rooms": {
+            "network_dropdown_add_dialog_description": "Introduz o nome de um novo servidor que pretendes explorar.",
+            "network_dropdown_add_dialog_placeholder": "Nome do servidor",
+            "network_dropdown_add_dialog_title": "Adiciona um novo servidor",
+            "network_dropdown_add_server_option": "Adiciona um novo servidor...",
+            "network_dropdown_available_invalid": "Não foi possível encontrar este servidor ou a sua lista de salas",
+            "network_dropdown_available_invalid_forbidden": "Não tens permissão para ver a lista de salas deste servidor",
+            "network_dropdown_available_valid": "Parece-me bem!",
+            "network_dropdown_remove_server_adornment": "Remove o servidor \"%(roomServer)s\"",
+            "network_dropdown_required_invalid": "Introduz um nome de servidor",
+            "network_dropdown_selected_label": "Mostrar: Salas Matrix",
+            "network_dropdown_selected_label_instance": "Mostrar: %(instance)s salas (%(server)s)",
+            "network_dropdown_your_server_description": "O teu servidor"
+        }
+    },
+    "spotlight_dialog": {
+        "cant_find_person_helpful_hint": "Se não conseguires ver quem procuras, envia-lhe o teu link de convite.",
+        "cant_find_room_helpful_hint": "Se não encontrares a sala que procuras, pede um convite ou cria uma nova sala.",
+        "copy_link_text": "Copiar link de convite",
+        "count_of_members": {
+            "one": "%(count)s membro",
+            "other": "%(count)s membros"
+        },
+        "create_new_room_button": "Criar nova sala",
+        "failed_querying_public_rooms": "Falha ao consultar as salas públicas",
+        "failed_querying_public_spaces": "Falha na consulta de espaços públicos",
+        "group_chat_section_title": "Outras opções",
+        "heading_with_query": "Utiliza \"%(query)s\" para pesquisar",
+        "heading_without_query": "Pesquisar por",
+        "join_button_text": "Aderir %(roomAddress)s",
+        "keyboard_scroll_hint": "Utiliza <arrows/> para te deslocares",
+        "message_search_section_title": "Outras pesquisas",
+        "other_rooms_in_space": "Outras salas em %(spaceName)s",
+        "public_rooms_label": "Salas públicas",
+        "public_spaces_label": "Espaços públicos",
+        "recent_searches_section_title": "Pesquisas recentes",
+        "recently_viewed_section_title": "Visto recentemente",
+        "remove_filter": "Remove o filtro de pesquisa para %(filter)s",
+        "result_may_be_hidden_privacy_warning": "Alguns resultados podem estar ocultos por motivos de privacidade",
+        "result_may_be_hidden_warning": "Alguns resultados podem estar ocultos",
+        "search_dialog": "Diálogo de pesquisa",
+        "search_messages_hint": "Para procurar mensagens, procura este ícone na parte superior de uma sala <icon/>",
+        "spaces_title": "Espaços em que te encontras",
+        "start_group_chat_button": "Inicia uma conversa de grupo"
+    },
+    "stickers": {
+        "empty": "Atualmente não tens nenhum pacote de autocolantes ativado",
+        "empty_add_prompt": "Adiciona alguns agora"
+    },
+    "terms": {
+        "column_document": "Documento",
+        "column_service": "Serviço",
+        "column_summary": "Resumo",
+        "identity_server_no_terms_description_1": "Esta acção requer acesso ao servidor de identidade padrão <server /> para validar um endereço de email ou número de telefone, mas o servidor não tem quaisquer termos de serviço.",
+        "identity_server_no_terms_description_2": "Continue apenas se confia no dono do servidor.",
+        "identity_server_no_terms_title": "O servidor de identidade não tem termos de serviço",
+        "inline_intro_text": "Aceita <policyLink /> para continuar:",
+        "integration_manager": "Utiliza bots, pontes, widgets e pacotes de autocolantes",
+        "intro": "Para continuar, tens de aceitar as condições deste serviço.",
+        "summary_identity_server_1": "Encontra outras pessoas por telefone ou e-mail",
+        "summary_identity_server_2": "Ser encontrado por telefone ou e-mail",
+        "tac_button": "Revê os termos e condições",
+        "tac_description": "Para continuar a usar o servidor doméstico %(homeserverDomain)s tens de rever e concordar com os nossos termos e condições.",
+        "tac_title": "Termos e Condições",
+        "tos": "Termos do serviço"
+    },
+    "theme": {
+        "light_high_contrast": "Alto contraste claro",
+        "match_system": "Sistema de correspondência"
+    },
+    "thread_view_back_action_label": "Volta ao tópico",
+    "threads": {
+        "all_threads": "Todos os tópicos",
+        "all_threads_description": "Mostra todos os tópicos da sala atual",
+        "count_of_reply": {
+            "one": "%(count)s resposta",
+            "other": "%(count)s respostas"
+        },
+        "empty_description": "Utiliza \"%(replyInThread)s\" quando passares o cursor sobre uma mensagem.",
+        "empty_title": "Os tópicos ajudam a manter as tuas conversas dentro do tópico e são fáceis de seguir.",
+        "error_start_thread_existing_relation": "Não é possível criar um tópico a partir de um evento com uma relação existente",
+        "mark_all_read": "Marcar tudo como lido",
+        "my_threads": "Os meus tópicos",
+        "my_threads_description": "Mostra todos os tópicos em que participaste",
+        "open_thread": "Abrir tópico",
+        "show_thread_filter": "Mostrar:"
+    },
+    "threads_activity_centre": {
+        "header": "Atividade de tópicos",
+        "no_rooms_with_threads_notifs": "Ainda não tens salas com notificações de tópicos.",
+        "no_rooms_with_unread_threads": "Ainda não tens salas com tópicos não lidos.",
+        "release_announcement_description": "As notificações de tópicos foram movidas, encontre-as aqui a partir de agora.",
+        "release_announcement_header": "Centro de Actividades Tópicos"
+    },
+    "time": {
+        "about_day_ago": "há cerca de um dia",
+        "about_hour_ago": "há cerca de uma hora",
+        "about_minute_ago": "há cerca de um minuto",
+        "date_at_time": "%(date)s às %(time)s",
+        "few_seconds_ago": "há alguns segundos atrás",
+        "hours_minutes_seconds_left": "%(hours)sh %(minutes)sm %(seconds)ss restantes",
+        "in_about_day": "daqui a um dia",
+        "in_about_hour": "daqui a uma hora",
+        "in_about_minute": "daqui a um minuto",
+        "in_few_seconds": "daqui a alguns segundos",
+        "in_n_days": "daqui a %(num)s dias",
+        "in_n_hours": "daqui a %(num)s horas",
+        "in_n_minutes": "daqui a %(num)s minutos",
+        "left": "%(timeRemaining)s ainda",
+        "minutes_seconds_left": "%(minutes)sm %(seconds)ss restantes",
+        "n_days_ago": "%(num)s dias atrás",
+        "n_hours_ago": "%(num)s horas atrás",
+        "n_minutes_ago": "%(num)s minutos atrás",
+        "seconds_left": "%(seconds)ss restantes",
+        "short_days": "%(value)sd",
+        "short_days_hours_minutes_seconds": "%(days)sd %(hours)sh %(minutes)sm %(seconds)ss",
+        "short_hours": "%(value)sh",
+        "short_hours_minutes_seconds": "%(hours)sh %(minutes)sm %(seconds)ss",
+        "short_minutes": "%(value)sm",
+        "short_minutes_seconds": "%(minutes)sm %(seconds)ss",
+        "short_seconds": "%(value)ss"
+    },
+    "timeline": {
+        "context_menu": {
+            "collapse_reply_thread": "Recolher tópico de resposta",
+            "external_url": "URL fonte",
+            "open_in_osm": "Abre no OpenStreetMap",
+            "report": "Relatório",
+            "resent_unsent_reactions": "Reenvia %(unsentCount)s reação(ões)",
+            "show_url_preview": "Mostrar pré-visualização",
+            "view_related_event": "Ver evento relacionado",
+            "view_source": "Ver fonte"
+        },
+        "creation_summary_dm": "%(creator)s criou esta DM.",
+        "creation_summary_room": "%(creator)s criou e configurou a sala.",
+        "decryption_failure": {
+            "blocked": "O remetente impediu-te de receber esta mensagem porque o teu dispositivo não foi verificado",
+            "historical_event_no_key_backup": "As mensagens históricas não estão disponíveis neste dispositivo",
+            "historical_event_unverified_device": "Tens de verificar este dispositivo para acederes às mensagens históricas",
+            "historical_event_user_not_joined": "Não tens acesso a esta mensagem",
+            "unable_to_decrypt": "Não é possível desencriptar a mensagem"
+        },
+        "disambiguated_profile": "%(displayName)s (%(matrixId)s)",
+        "download_action_decrypting": "Descriptografando",
+        "download_action_downloading": "A transferir…",
+        "download_failed": "A transferência falhou",
+        "download_failed_description": "Ocorreu um erro ao transferir este ficheiro",
+        "edits": {
+            "tooltip_label": "Editado em %(date)s. Clica para ver as edições.",
+            "tooltip_sub": "Clica para ver as edições",
+            "tooltip_title": "Editado em %(date)s"
+        },
+        "error_no_renderer": "Este evento não pôde ser exibido",
+        "error_rendering_message": "Não é possível carregar esta mensagem",
+        "historical_messages_unavailable": "Não consegues ver as mensagens anteriores",
+        "in_room_name": " em <strong>%(room)s</strong>",
+        "io.element.widgets.layout": "%(senderName)s atualizou a disposição da sala",
+        "late_event_separator": "Enviado originalmente %(dateTime)s",
+        "load_error": {
+            "no_permission": "Tentei carregar um ponto específico na linha do tempo desta sala, mas parece que você não tem permissões para ver a mensagem em questão.",
+            "title": "Não foi possível carregar a posição na linha do tempo",
+            "unable_to_find": "Tentei carregar um ponto específico na linha do tempo desta sala, mas não o encontrei."
+        },
+        "m.audio": {
+            "error_downloading_audio": "Erro ao descarregar áudio",
+            "error_processing_audio": "Erro no processamento da mensagem de áudio",
+            "error_processing_voice_message": "Erro no processamento da mensagem de voz",
+            "unnamed_audio": "Áudio sem nome"
+        },
+        "m.beacon_info": {
+            "view_live_location": "Vê a localização ao vivo"
+        },
+        "m.call": {
+            "video_call_ended": "Chamada de vídeo terminada",
+            "video_call_started": "A videochamada começou em %(roomName)s.",
+            "video_call_started_text": "%(name)s iniciou uma videochamada",
+            "video_call_started_unsupported": "A videochamada começou em%(roomName)s . (não suportada por este navegador)"
+        },
+        "m.call.hangup": {
+            "dm": "Chamada terminada"
+        },
+        "m.call.invite": {
+            "answered_elsewhere": "Respondido noutro local",
+            "call_back_prompt": "Retornar a chamada",
+            "declined": "Chamada recusada",
+            "failed_connect_media": "Não foi possível conectar a mídia",
+            "failed_connection": "Falha na conexão",
+            "failed_opponent_media": "O teu dispositivo não conseguia ligar a câmara ou o microfone",
+            "missed_call": "Chamada perdida",
+            "no_answer": "Não Atende",
+            "unknown_error": "Ocorreu um erro desconhecido",
+            "unknown_failure": "Falha desconhecida: %(reason)s",
+            "unknown_state": "A chamada está num estado desconhecido!",
+            "video_call": "%(senderName)s faz uma chamada de vídeo.",
+            "video_call_unsupported": "%(senderName)s fez uma videochamada. (não suportada por este navegador)",
+            "voice_call": "%(senderName)s faz uma chamada de voz.",
+            "voice_call_unsupported": "%(senderName)s fez uma chamada de voz. (não suportada por este navegador)"
+        },
+        "m.file": {
+            "error_decrypting": "Erro ao descriptografar o anexo",
+            "error_invalid": "Arquivo inválido %(extra)s"
+        },
+        "m.image": {
+            "error": "Não é possível mostrar a imagem devido a um erro",
+            "error_decrypting": "Erro ao descriptografar a imagem",
+            "error_downloading": "Erro ao descarregar a imagem",
+            "sent": "%(senderDisplayName)s enviou uma imagem.",
+            "show_image": "Mostra a imagem"
+        },
+        "m.key.verification.request": {
+            "user_wants_to_verify": "%(name)s quer verificar",
+            "you_started": "Enviaste um pedido de verificação"
+        },
+        "m.location": {
+            "full": "%(senderName)s partilhou a sua localização",
+            "location": "Partilhou um local: ",
+            "self_location": "Partilhou a sua localização: "
+        },
+        "m.poll": {
+            "count_of_votes": {
+                "one": "%(count)svoto",
+                "other": "%(count)svotos"
+            }
+        },
+        "m.poll.end": {
+            "ended": "Terminou uma sondagem",
+            "sender_ended": "%(senderName)s encerrou uma sondagem"
+        },
+        "m.poll.start": "%(senderName)s iniciou uma sondagem - %(pollQuestion)s",
+        "m.room.avatar": {
+            "changed": "%(senderDisplayName)s mudaste o avatar da sala.",
+            "changed_img": "%(senderDisplayName)s alterou a imagem da sala para <img/>",
+            "lightbox_title": "%(senderDisplayName)s alterou a imagem da sala %(roomName)s",
+            "removed": "%(senderDisplayName)s removeu a imagem da sala."
+        },
+        "m.room.canonical_alias": {
+            "alt_added": {
+                "one": "%(senderName)s Adiciona um endereço alternativo %(addresses)s para esta sala.",
+                "other": "%(senderName)s adicionou os endereços alternativos %(addresses)s para esta sala."
+            },
+            "alt_removed": {
+                "one": "%(senderName)s Removeu o endereço alternativo %(addresses)s para esta sala.",
+                "other": "%(senderName)s Removeu os endereços alternativos %(addresses)s para esta sala."
+            },
+            "changed": "%(senderName)s alterou os endereços desta sala.",
+            "changed_alternative": "%(senderName)s alterou o endereço alternativo desta sala.",
+            "changed_main_and_alternative": "%(senderName)s alterou o endereço principal e alternativo desta sala.",
+            "removed": "%(senderName)s removeu o endereço principal desta sala.",
+            "set": "%(senderName)s definiu o endereço principal desta sala como %(address)s."
+        },
+        "m.room.create": {
+            "continuation": "Esta sala é a continuação de outra conversa.",
+            "see_older_messages": "Clica aqui para veres mensagens mais antigas.",
+            "unknown_predecessor": "Não é possível encontrar a versão antiga desta sala (ID da sala: %(roomId)s), e não nos foi fornecido o 'via_servers' para a procurar.",
+            "unknown_predecessor_guess_server": "Não consegues encontrar a versão antiga desta sala (ID da sala: %(roomId)s), e não nos foi fornecido o 'via_servers' para a procurar. É possível que adivinhes o servidor a partir do ID da sala. Se quiseres tentar, clica neste link:"
+        },
+        "m.room.encryption": {
+            "disable_attempt": "Tentativa ignorada de desativar a encriptação",
+            "disabled": "Encriptação não ativada",
+            "enabled": "As mensagens nesta sala são encriptadas de ponta a ponta. Quando as pessoas se juntam a nós, podes verificá-las no seu perfil, basta tocares na fotografia de perfil.",
+            "enabled_dm": "As mensagens aqui são encriptadas de ponta a ponta. Verifica %(displayName)s no seu perfil - toca na fotografia de perfil.",
+            "enabled_local": "As mensagens neste chat serão encriptadas de ponta a ponta.",
+            "parameters_changed": "Alguns parâmetros de encriptação foram alterados.",
+            "unsupported": "A encriptação utilizada por esta sala não é suportada."
+        },
+        "m.room.guest_access": {
+            "can_join": "%(senderDisplayName)s permitiu que convidados entram na sala.",
+            "forbidden": "%(senderDisplayName)s bloqueou que convidados entrem na sala.",
+            "unknown": "%(senderDisplayName)s alterou o acesso de convidados para %(rule)s"
+        },
+        "m.room.history_visibility": {
+            "invited": "%(senderName)s deixou o histórico futuro da sala visível para todos os membros da sala, a partir de quando foram convidados.",
+            "joined": "%(senderName)s deixou o histórico futuro da sala visível para todos os membros da sala, a partir de quando entraram.",
+            "shared": "%(senderName)s deixou o histórico futuro da sala visível para todas as pessoas da sala.",
+            "unknown": "%(senderName)s deixou o histórico futuro da sala visível para desconhecido (%(visibility)s).",
+            "world_readable": "%(senderName)s deixou o histórico futuro da sala visível para qualquer pessoa."
+        },
+        "m.room.join_rules": {
+            "invite": "%(senderDisplayName)s fechou a sala para apenas utilizadores com convites.",
+            "knock": "%(senderDisplayName)s alterou a regra de entrada para \"pedir para entrar\".",
+            "public": "%(senderDisplayName)s tornou a sala pública para quem tiver o link.",
+            "restricted": "%(senderDisplayName)s mudou quem pode entrar na sala.",
+            "restricted_settings": "%(senderDisplayName)s mudou quem pode entrar na sala. <a>Ver definições</a>.",
+            "unknown": "%(senderDisplayName)s alterou a regra de entrada para %(rule)s"
+        },
+        "m.room.member": {
+            "accepted_3pid_invite": "%(targetName)s aceitou o convite para %(displayName)s",
+            "accepted_invite": "%(targetName)saceitou um convite",
+            "ban": "%(senderName)s baniu %(targetName)s",
+            "ban_reason": "%(senderName)s baniu %(targetName)s: %(reason)s",
+            "change_avatar": "%(senderName)s mudou a sua foto de perfil",
+            "change_name": "%(oldDisplayName)s mudou o seu nome de apresentação para %(displayName)s",
+            "change_name_avatar": "%(oldDisplayName)s alterou o seu nome de apresentação e a sua fotografia de perfil",
+            "invite": "%(senderName)s convidou %(targetName)s",
+            "join": "%(targetName)s entrou na sala",
+            "kick": "%(senderName)s removeu %(targetName)s",
+            "kick_reason": "%(senderName)s removeu %(targetName)s: %(reason)s",
+            "left": "%(targetName)s saiu da sala",
+            "left_reason": "%(targetName)s saiu da sala:%(reason)s",
+            "no_change": "%(senderName)s não fez nenhuma alteração",
+            "reject_invite": "%(targetName)s rejeitou o convite",
+            "remove_avatar": "%(senderName)s removeu a sua fotografia de perfil",
+            "remove_name": "%(senderName)s removeu o seu nome de apresentação (%(oldDisplayName)s)",
+            "set_avatar": "%(senderName)s colocou uma foto de perfil",
+            "set_name": "%(senderName)s colocou o seu nome como %(displayName)s",
+            "unban": "%(senderName)s desbaniu %(targetName)s",
+            "withdrew_invite": "%(senderName)s revogou o convite de %(targetName)s",
+            "withdrew_invite_reason": "%(senderName)s revogou o convite de %(targetName)s: %(reason)s"
+        },
+        "m.room.name": {
+            "change": "%(senderDisplayName)s mudou o nome da sala de %(oldRoomName)s para %(newRoomName)s.",
+            "remove": "%(senderDisplayName)s apagou o nome da sala.",
+            "set": "%(senderDisplayName)s alterou o nome da sala para %(roomName)s."
+        },
+        "m.room.pinned_events": {
+            "changed": "%(senderName)s alterou as mensagens fixadas para a sala.",
+            "changed_link": "%(senderName)s alterou as <a>mensagens fixadas</a> para a sala.",
+            "pinned": "%(senderName)s fixou uma mensagem nesta sala. Ver todas as mensagens fixadas.",
+            "pinned_link": "%(senderName)s fixou <a>uma mensagem</a> nesta sala. Ver todas as <b>mensagens fixadas</b>.",
+            "unpinned": "%(senderName)s desafixou uma mensagem desta sala. Ver todas as mensagens fixadas.",
+            "unpinned_link": "%(senderName)s desafixou <a>uma messagem</a> desta sala. Ver todas as <b>mensagens fixadas</b>."
+        },
+        "m.room.power_levels": {
+            "changed": "%(senderName)s alterou o nível de permissões de %(powerLevelDiffText)s.",
+            "user_from_to": "%(userId)s de %(fromPowerLevel)s para %(toPowerLevel)s"
+        },
+        "m.room.server_acl": {
+            "all_servers_banned": "🎉 Todos os servidores foram banidos de participar! Esta sala ficou inutilizável.",
+            "changed": "%(senderDisplayName)s mudou a lista de controlo de acessos de servidores desta sala.",
+            "set": "%(senderDisplayName)s definir a lista de controlo de acessos de servidores para esta sala."
+        },
+        "m.room.third_party_invite": {
+            "revoked": "%(senderName)s revocou o convite a %(targetDisplayName)s para se juntar à sala.",
+            "sent": "%(senderName)s enviou um convite para %(targetDisplayName)s entrar na sala."
+        },
+        "m.room.tombstone": "%(senderDisplayName)s atualizou a sala.",
+        "m.room.topic": "%(senderDisplayName)s mudou o tópico para \"%(topic)s\".",
+        "m.sticker": "%(senderDisplayName)s enviou um sticker.",
+        "m.video": {
+            "error_decrypting": "Erro ao descriptografar o vídeo"
+        },
+        "m.widget": {
+            "added": "Widget %(widgetName)s adicionado por %(senderName)s",
+            "jitsi_ended": "A videoconferência terminada por %(senderName)s",
+            "jitsi_join_right_prompt": "Participa na conferência a partir do cartão de informação da sala à direita",
+            "jitsi_join_top_prompt": "Junta-te à conferência no topo desta sala",
+            "jitsi_started": "Videoconferência iniciada por %(senderName)s",
+            "jitsi_updated": "Videoconferência atualizada por %(senderName)s",
+            "modified": "Widget %(widgetName)s modificado por %(senderName)s",
+            "removed": "Widget %(widgetName)s removido por %(senderName)s"
+        },
+        "mab": {
+            "collapse_reply_chain": "Recolher citações",
+            "copy_link_thread": "Copia o link para o tópico",
+            "expand_reply_chain": "Expandir cotações",
+            "label": "Acções de mensagens",
+            "view_in_room": "Vista na sala"
+        },
+        "message_timestamp_received_at": "Recebido em: %(dateTime)s",
+        "message_timestamp_sent_at": "Enviado em:%(dateTime)s",
+        "mjolnir": {
+            "changed_rule_glob": "%(senderName)s atualizou uma regra de banimento que correspondia a %(oldGlob)s à correspondência %(newGlob)s devido a %(reason)s",
+            "changed_rule_rooms": "%(senderName)s alterou uma regra que proibia salas correspondentes a %(oldGlob)s para correspondência %(newGlob)s devido a %(reason)s",
+            "changed_rule_servers": "%(senderName)s alterou uma regra que proibia servidores correspondentes a %(oldGlob)s para correspondência %(newGlob)s devido a %(reason)s",
+            "changed_rule_users": "%(senderName)s alterou uma regra que proibia usuários que correspondessem %(oldGlob)s para corresponder a %(newGlob)s devido a %(reason)s",
+            "created_rule": "%(senderName)s criou uma regra de banimento correspondente a %(glob)s devido a %(reason)s",
+            "created_rule_rooms": "%(senderName)s criou uma regra que bane salas que correspondam a %(glob)s porque %(reason)s",
+            "created_rule_servers": "%(senderName)s criou uma regra proibindo servidores correspondentes a %(glob)s para %(reason)s",
+            "created_rule_users": "%(senderName)s criou uma regra que bane os utilizadores que correspondam a %(glob)s porque %(reason)s",
+            "message_hidden": "Ignoraste este utilizador, por isso a sua mensagem está oculta. <a>Mostra de qualquer forma.</a>",
+            "removed_rule": "%(senderName)sremoveu uma regra de proibição correspondente %(glob)s",
+            "removed_rule_rooms": "%(senderName)s eliminou a regra que proibia a correspondência de salas %(glob)s",
+            "removed_rule_servers": "%(senderName)s eliminou a regra que bania os servidores que correspondessem a %(glob)s",
+            "removed_rule_users": "%(senderName)s eliminou a regra que bania os utilizadores que correspondessem a %(glob)s",
+            "updated_invalid_rule": "%(senderName)satualizou uma regra de proibição inválida",
+            "updated_rule": "%(senderName)s atualizou uma regra de proibição que corresponde a %(glob)s por %(reason)s",
+            "updated_rule_rooms": "%(senderName)satualizou a regra que proíbe salas correspondentes %(glob)s por %(reason)s",
+            "updated_rule_servers": "%(senderName)s actualizou a regra que proíbe os servidores que correspondem a %(glob)s por %(reason)s",
+            "updated_rule_users": "%(senderName)s atualizou a regra que proíbe os utilizadores que correspondam a %(glob)s para %(reason)s"
+        },
+        "no_permission_messages_before_invite": "Não tens permissão para ver mensagens anteriores ao convite.",
+        "no_permission_messages_before_join": "Não tens permissão para ver mensagens anteriores à tua adesão.",
+        "pending_moderation": "Mensagem pendente de moderação",
+        "pending_moderation_reason": "Mensagem pendente de moderação: %(reason)s",
+        "reactions": {
+            "add_reaction_prompt": "Adicionar reação",
+            "custom_reaction_fallback_label": "Reação personalizada",
+            "label": "%(reactors)s reagiu com %(content)s",
+            "tooltip_caption": "reagiu com %(shortName)s"
+        },
+        "read_receipt_title": {
+            "one": "Visto por %(count)s pessoa",
+            "other": "Visto por %(count)s pessoas"
+        },
+        "read_receipts_label": "Recibos de leitura",
+        "redacted": {
+            "tooltip": "Mensagem apagada em %(date)s"
+        },
+        "redaction": "Mensagem apagada por %(name)s",
+        "reply": {
+            "error_loading": "Não foi possível carregar o evento ao qual se respondeu, ou ele não existe ou não tens permissão para o ver.",
+            "in_reply_to": "<a>Em resposta a</a> <pill>",
+            "in_reply_to_for_export": "Em resposta a <a>esta mensagem</a>"
+        },
+        "scalar_starter_link": {
+            "dialog_description": "Você será levado agora a um site de terceiros para poder autenticar a sua conta para uso com o serviço %(integrationsUrl)s. Você quer continuar?",
+            "dialog_title": "Adicionar uma integração"
+        },
+        "self_redaction": "Mensagem apagada",
+        "send_state_encrypting": "A encriptar a tua mensagem...",
+        "send_state_failed": "Falha ao enviar",
+        "send_state_sending": "A enviar a tua mensagem...",
+        "send_state_sent": "A tua mensagem foi enviada",
+        "summary": {
+            "banned": {
+                "one": "foi banido",
+                "other": "foi banido %(count)s vezes"
+            },
+            "banned_multiple": {
+                "one": "foram banidos",
+                "other": "foram banidos %(count)s vezes"
+            },
+            "changed_avatar": {
+                "one": "%(oneUser)s mudou a sua foto de perfil",
+                "other": "%(oneUser)s mudou a sua foto de perfil %(count)s vezes"
+            },
+            "changed_avatar_multiple": {
+                "one": "%(severalUsers)s mudou a sua foto de perfil",
+                "other": "%(severalUsers)s mudou a sua foto de perfil %(count)s vezes"
+            },
+            "changed_name": {
+                "one": "%(oneUser)s mudou de nome",
+                "other": "%(oneUser)s mudou de nome %(count)s vezes"
+            },
+            "changed_name_multiple": {
+                "one": "%(severalUsers)s mudou de nome",
+                "other": "%(severalUsers)s mudou de nome %(count)s vezes"
+            },
+            "format": "%(nameList)s %(transitionList)s",
+            "hidden_event": {
+                "one": "%(oneUser)s enviou uma mensagem oculta",
+                "other": "%(oneUser)s enviou %(count)s mensagens ocultas"
+            },
+            "hidden_event_multiple": {
+                "one": "%(severalUsers)s enviaram uma mensagem oculta",
+                "other": "%(severalUsers)s enviaram %(count)s mensagens ocultas"
+            },
+            "invite_withdrawn": {
+                "one": "%(oneUser)s teve o seu convite retirado",
+                "other": "%(oneUser)s teve o seu convite retirado %(count)s vezes"
+            },
+            "invite_withdrawn_multiple": {
+                "one": "%(severalUsers)s tiveram os seus convites retirados",
+                "other": "%(severalUsers)s tiveram os seus convites retirados %(count)s vezes"
+            },
+            "invited": {
+                "one": "foi convidado",
+                "other": "foi convidado %(count)s vezes"
+            },
+            "invited_multiple": {
+                "one": "foram convidados",
+                "other": "foram convidados %(count)s vezes"
+            },
+            "joined": {
+                "one": "%(oneUser)s aderiu",
+                "other": "%(oneUser)s aderiu %(count)s vezes"
+            },
+            "joined_and_left": {
+                "one": "%(oneUser)s entrou e saiu",
+                "other": "%(oneUser)s entrou e saiu %(count)s vezes"
+            },
+            "joined_and_left_multiple": {
+                "one": "%(severalUsers)s aderiu e saiu",
+                "other": "%(severalUsers)s aderiu e saiu %(count)s vezes"
+            },
+            "joined_multiple": {
+                "one": "%(severalUsers)s aderiu",
+                "other": "%(severalUsers)s aderiu %(count)s vezes"
+            },
+            "kicked": {
+                "one": "foi removido",
+                "other": "foi removido %(count)s vezes"
+            },
+            "kicked_multiple": {
+                "one": "foram removidos",
+                "other": "foram removidos %(count)s vezes"
+            },
+            "left": {
+                "one": "%(oneUser)s saiu",
+                "other": "%(oneUser)s saiu %(count)s vezes"
+            },
+            "left_multiple": {
+                "one": "%(severalUsers)s saiu",
+                "other": "%(severalUsers)s saiu %(count)s vezes"
+            },
+            "no_change": {
+                "one": "%(oneUser)snão fez alterações",
+                "other": "%(oneUser)s não fez alterações %(count)s vezes"
+            },
+            "no_change_multiple": {
+                "one": "%(severalUsers)s não fizeram alterações",
+                "other": "%(severalUsers)s não fizeram alterações %(count)s vezes"
+            },
+            "pinned_events": {
+                "one": "%(oneUser)s alterou as mensagens <a> fixadas </a> para a sala",
+                "other": "%(oneUser)s alterou as mensagens <a> fixadas </a> para a sala %(count)s vezes"
+            },
+            "pinned_events_multiple": {
+                "one": "%(severalUsers)s alteraram as mensagens <a> fixadas </a> para a sala",
+                "other": "%(severalUsers)s alteraram as mensagens <a> fixadas </a> para a sala %(count)s vezes"
+            },
+            "redacted": {
+                "one": "%(oneUser)s removeu uma mensagem",
+                "other": "%(oneUser)s removeu %(count)s mensagens"
+            },
+            "redacted_multiple": {
+                "one": "%(severalUsers)s removeram uma mensagem",
+                "other": "%(severalUsers)s removeram %(count)s mensagens"
+            },
+            "rejected_invite": {
+                "one": "%(oneUser)s rejeitou o convite deles",
+                "other": "%(oneUser)s rejeitou o convite deles %(count)s vezes"
+            },
+            "rejected_invite_multiple": {
+                "one": "%(severalUsers)s rejeitaram os convites deles",
+                "other": "%(severalUsers)s rejeitaram os convites deles %(count)s vezes"
+            },
+            "rejoined": {
+                "one": "%(oneUser)s saiu e voltou",
+                "other": "%(oneUser)s saiu e voltou %(count)s vezes"
+            },
+            "rejoined_multiple": {
+                "one": "%(severalUsers)s aderiram e saíram",
+                "other": "%(severalUsers)s aderiram e saíram %(count)s vezes"
+            },
+            "server_acls": {
+                "one": "%(oneUser)salterou as ACLs do servidor",
+                "other": "%(oneUser)salterou as ACLs do servidor %(count)s vezes"
+            },
+            "server_acls_multiple": {
+                "one": "%(severalUsers)salterou as ACLs do servidor",
+                "other": "%(severalUsers)salterou as ACLs do servidor %(count)s vezes"
+            },
+            "unbanned": {
+                "one": "foi não banido",
+                "other": "foi não banido %(count)s vezes"
+            },
+            "unbanned_multiple": {
+                "one": "foram não banidos",
+                "other": "foram não banidos %(count)s vezes"
+            }
+        },
+        "thread_info_basic": "De um tópico",
+        "typing_indicator": {
+            "more_users": {
+                "one": "%(names)s e um outro está a escrever...",
+                "other": "%(names)s e %(count)s outros estão a escrever"
+            },
+            "one_user": "%(displayName)s está a escrever ...",
+            "two_users": "%(names)s e %(lastPerson)s estão a escrever …"
+        },
+        "undecryptable_tooltip": "Esta mensagem não pôde ser desencriptada",
+        "url_preview": {
+            "close": "Fechar pré-visualização",
+            "show_n_more": {
+                "one": "Mostra %(count)s outra pré-visualização",
+                "other": "Mostra %(count)s outras pré-visualizações"
+            }
+        }
+    },
+    "truncated_list_n_more": {
+        "one": "",
+        "other": "E %(count)s mais..."
+    },
+    "unsupported_browser": {
+        "description": "Se continuares, algumas funcionalidades podem deixar de funcionar e existe o risco de perderes dados no futuro. Actualiza o teu browser para continuares a utilizar %(brand)s.",
+        "title": "%(brand)s não suporta este browser"
+    },
+    "unsupported_server_description": "Este servidor está a utilizar uma versão mais antiga do Matrix. Atualiza para Matrix %(version)s para utilizares %(brand)s sem erros.",
+    "unsupported_server_title": "O teu servidor não é suportado",
+    "update": {
+        "changelog": "Histórico de alterações",
+        "check_action": "Procurar atualizações",
+        "checking": "A procurar atualizações…",
+        "downloading": "A descarregar a atualização...",
+        "error_encountered": "Erro encontrado (%(errorDetail)s).",
+        "error_unable_load_commit": "Não é possível carregar os detalhes do commit: %(msg)s",
+        "new_version_available": "Nova versão disponível. <a>Atualiza agora.</a>",
+        "no_update": "Nenhuma atualização disponível.",
+        "release_notes_toast_title": "Novidades",
+        "see_changes_button": "O que há de novo?",
+        "toast_description": "Nova versão de%(brand)s está disponível",
+        "toast_title": "Atualizar%(brand)s",
+        "unavailable": "Indisponível"
+    },
+    "update_room_access_modal": {
+        "description": "Para criar uma ligação de partilha, tens de permitir que os convidados entrem nesta sala. Isto pode tornar a sala menos segura. Quando terminares a chamada, podes tornar a sala privada novamente.",
+        "dont_change_description": "Em alternativa, podes manter a chamada numa sala separada.",
+        "no_change": "Não quero alterar o nível de acesso.",
+        "title": "Alterar o nível de acesso à sala"
+    },
+    "upload_failed_generic": "O carregamento do ficheiro '%(fileName)s' falhou.",
+    "upload_failed_size": "O ficheiro '%(fileName)s' excede o tamanho limite deste homeserver para carregamentos",
+    "upload_failed_title": "O envio falhou",
+    "upload_file": {
+        "cancel_all_button": "Cancelar tudo",
+        "error_file_too_large": "Este ficheiro é <b>demasiado grande</b> para carregar. O limite de tamanho do ficheiro é %(limit)s mas este ficheiro é %(sizeOfThisFile)s.",
+        "error_files_too_large": "Estes ficheiros são <b>demasiado grandes</b> para serem carregados. O limite de tamanho do ficheiro é %(limit)s.",
+        "error_some_files_too_large": "Alguns ficheiros são <b>demasiado grandes</b> para serem carregados. O limite de tamanho dos ficheiros é %(limit)s.",
+        "error_title": "Erro de carregamento",
+        "title": "Carregar ficheiros",
+        "title_progress": "Carrega ficheiros (%(current)s de %(total)s)",
+        "upload_all_button": "Carregar tudo",
+        "upload_n_others_button": {
+            "one": "Carrega %(count)s outro ficheiro",
+            "other": "Carrega %(count)s outros ficheiros"
+        }
+    },
+    "user_info": {
+        "admin_tools_section": "Ferramentas de Administração",
+        "ban_button_room": "Banir da sala",
+        "ban_button_space": "Banir do espaço",
+        "ban_room_confirm_title": "Banir de %(roomName)s",
+        "ban_space_everything": "Baní-los de tudo que eu estiver autorizado",
+        "ban_space_specific": "Bani-los de coisas específicas que estou autorizado",
+        "count_of_sessions": {
+            "one": "%(count)s sessão",
+            "other": "%(count)s sessões"
+        },
+        "count_of_verified_sessions": {
+            "one": "1 sessão verificada",
+            "other": "%(count)s sessões verificadas"
+        },
+        "deactivate_confirm_action": "Desativar utilizador",
+        "deactivate_confirm_description": "Se desactivares este utilizador, ele sairá da tua conta e não poderá voltar a entrar. Além disso, sai de todas as salas em que se encontra. Esta ação não pode ser revertida. Tens a certeza de que queres desativar este utilizador?",
+        "deactivate_confirm_title": "Desativar utilizador?",
+        "dehydrated_device_enabled": "Dispositivo offline ativado",
+        "demote_button": "Despromove",
+        "demote_self_confirm_description_space": "Não poderás desfazer esta alteração, uma vez que te estás a despromover. Se fores o último utilizador privilegiado no espaço, será impossível recuperar os privilégios.",
+        "demote_self_confirm_room": "Não poderás desfazer esta alteração, uma vez que te estás a despromover. Se fores o último utilizador privilegiado na sala, será impossível recuperar os privilégios.",
+        "demote_self_confirm_title": "Despromover-se a si próprio ?",
+        "disinvite_button_room": "Desconvidar da sala",
+        "disinvite_button_room_name": "Desconvidar de %(roomName)s",
+        "disinvite_button_space": "Desconvidar do espaço",
+        "edit_own_devices": "Editar dispositivos",
+        "error_ban_user": "Não foi possível banir o/a usuário/a",
+        "error_deactivate": "Falha ao desativar o utilizador",
+        "error_kicking_user": "Falha ao remover o utilizador",
+        "error_mute_user": "Não foi possível remover notificações da/do usuária/o",
+        "error_revoke_3pid_invite_description": "Não foi possível revogar o convite. O servidor pode estar com um problema temporário ou não tens permissões suficientes para revogar o convite.",
+        "error_revoke_3pid_invite_title": "Falha ao revogar o convite",
+        "hide_sessions": "Ocultar sessões",
+        "hide_verified_sessions": "Ocultar sessões verificadas",
+        "ignore_button": "Ignorar",
+        "ignore_confirm_description": "Todas as mensagens e convites deste utilizador serão ocultados. Tens a certeza de que queres ignorá-los?",
+        "ignore_confirm_title": "Ignora %(user)s",
+        "invited_by": "Convidado por %(sender)s",
+        "jump_to_rr_button": "Salta para ler o recibo",
+        "kick_button_room": "Remover da sala",
+        "kick_button_room_name": "Remover de %(roomName)s",
+        "kick_button_space": "Remover do espaço",
+        "kick_button_space_everything": "Retira-os de tudo o que eu puder",
+        "kick_space_specific": "Retira-os de coisas específicas que eu sou capaz de fazer",
+        "kick_space_warning": "Continuam a poder aceder a tudo o que não és administrador.",
+        "promote_warning": "Você não poderá desfazer esta mudança, pois estará dando a este(a) usuário(a) o mesmo nível de permissões que você.",
+        "redact": {
+            "confirm_button": {
+                "one": "Remover 1 mensagem",
+                "other": "Remove %(count)s mensagens"
+            },
+            "confirm_description_1": {
+                "one": "Estás prestes a remover a mensagem %(count)s por %(user)s. Isto irá removê-las permanentemente para todos os participantes na conversa. Queres continuar?",
+                "other": "Estás prestes a remover as mensagens %(count)s por %(user)s. Isto irá removê-las permanentemente para todos os participantes na conversa. Queres continuar?"
+            },
+            "confirm_description_2": "Para uma grande quantidade de mensagens, isto pode demorar algum tempo. Entretanto, não actualizes o teu cliente.",
+            "confirm_keep_state_explainer": "Desmarca se também quiseres remover mensagens do sistema sobre este utilizador (por exemplo, mudança de membro, mudança de perfil...)",
+            "confirm_keep_state_label": "Preserva as mensagens do sistema",
+            "confirm_title": "Remove as mensagens recentes de %(user)s",
+            "no_recent_messages_description": "Tenta deslocar-te para cima na linha do tempo para ver se há alguma anterior.",
+            "no_recent_messages_title": "Não foram encontradas mensagens recentes de %(user)s "
+        },
+        "redact_button": "Remover mensagens recentes",
+        "revoke_invite": "Revogar convite",
+        "room_encrypted": "As mensagens nesta sala são encriptadas de ponta a ponta.",
+        "room_encrypted_detail": "As tuas mensagens estão protegidas e só tu e o destinatário têm as chaves únicas para as desbloquear.",
+        "room_unencrypted": "As mensagens nesta sala não são encriptadas de ponta a ponta.",
+        "room_unencrypted_detail": "Nas salas encriptadas, as tuas mensagens estão seguras e só tu e o destinatário têm as chaves únicas para as desbloquear.",
+        "send_message": "Enviar mensagem",
+        "share_button": "Partilhar ligação com o utilizador",
+        "unban_button_room": "Desbanimento da sala",
+        "unban_button_space": "Desbanir do espaço",
+        "unban_room_confirm_title": "Desbanir de %(roomName)s",
+        "unban_space_everything": "Desbani-los de tudo que eu estiver autorizado",
+        "unban_space_specific": "Desbani-los de coisas específicas que estou autorizado",
+        "unban_space_warning": "Não poderão aceder a nada que não seja administrado por ti.",
+        "unignore_button": "Designorar",
+        "verify_button": "Verificar utilizador",
+        "verify_explainer": "Para maior segurança, verifica este utilizador através de um código de utilização única em ambos os dispositivos."
+    },
+    "user_menu": {
+        "link_new_device": "Vincular novo dispositivo",
+        "settings": "Todas as definições",
+        "switch_theme_dark": "Mudar para o modo escuro",
+        "switch_theme_light": "Mudar para o modo claro"
+    },
+    "voip": {
+        "already_in_call": "Já em chamada",
+        "already_in_call_person": "Já está em chamada com esta pessoa.",
+        "answered_elsewhere": "Atendida noutro lado",
+        "answered_elsewhere_description": "A chamada foi atendida noutro dispositivo.",
+        "call_failed": "A chamada falhou",
+        "call_failed_description": "Não foi possível estabelecer a chamada",
+        "call_failed_media": "A chamada falhou porque não foi possível aceder à câmera ou microfone. Verifique se:",
+        "call_failed_media_applications": "Nenhuma outra aplicação está a utilizar a câmera",
+        "call_failed_media_connected": "Um microfone e uma câmera estão conectados e configurados corretamente",
+        "call_failed_media_permissions": "É concedida autorização para utilizar a câmera",
+        "call_failed_microphone": "A chamada falhou porque o microfone não está acessível. Verifique que tem um microfone ligado e correctamente configurado.",
+        "call_held": "%(peerName)s reteve a chamada",
+        "call_held_resume": "Aguentaste a chamada <a>Resume</a>",
+        "call_held_switch": "Mantiveste a chamada <a>Switch</a>",
+        "call_toast_unknown_room": "Sala desconhecida",
+        "camera_disabled": "A tua câmara está desligada",
+        "camera_enabled": "A tua câmara ainda está ativada",
+        "cannot_call_yourself_description": "Você não pode iniciar uma chamada.",
+        "close_lobby": "Fechar lobby",
+        "connecting": "A conectar",
+        "connection_lost": "A conexão ao servidor foi perdida",
+        "connection_lost_description": "Não pode fazer chamadas sem uma conexão ao servidor.",
+        "consulting": "Consultando com %(transferTarget)s. <a>Transferir para %(transferee)s </a>",
+        "default_device": "Dispositivo padrão",
+        "dial": "Discar",
+        "dialpad": "Teclado de discagem",
+        "disable_camera": "Desliga a câmara",
+        "disable_microphone": "Silenciar Microfone",
+        "disabled_no_one_here": "Não há ninguém aqui para ligar",
+        "disabled_no_perms_start_video_call": "Não tens autorização para iniciar chamadas de vídeo",
+        "disabled_no_perms_start_voice_call": "Não tens autorização para iniciar chamadas de voz",
+        "disabled_ongoing_call": "Chamada em curso",
+        "element_call": "Element Call",
+        "enable_camera": "Liga a câmara",
+        "enable_microphone": "Ativar Som do Microfone",
+        "expand": "Volta à chamada",
+        "get_call_link": "Partilhar a ligação de chamada",
+        "hangup": "Desligar",
+        "hide_sidebar_button": "Ocultar barra lateral",
+        "input_devices": "Dispositivos de entrada",
+        "jitsi_call": "Conferência Jitsi",
+        "join_button_tooltip_call_full": "Desculpa, neste momento, esta chamada está cheia",
+        "join_button_tooltip_connecting": "A conectar...",
+        "legacy_call": "Chamada Legacy",
+        "maximise": "Preenche o ecrã",
+        "maximise_call": "Maximiza a chamada",
+        "metaspace_video_rooms": {
+            "conference_room_section": "Conferências"
+        },
+        "minimise_call": "Minimiza a chamada",
+        "misconfigured_server": "Chamada falhada devido a um erro de configuração do servidor",
+        "misconfigured_server_description": "Peça ao administrador do seu servidor inicial (<code>%(homeserverDomain)s</code>) de configurar um servidor TURN para que as chamadas funcionem fiavelmente.",
+        "misconfigured_server_fallback": "Em alternativa, pode tentar utilizar o servidor público em <server/>, mas não será tão fiável e irá partilhar o seu endereço IP com esse servidor. Também pode gerir isto nas Definições.",
+        "misconfigured_server_fallback_accept": "Tente usar %(server)s",
+        "more_button": "Mais",
+        "msisdn_lookup_failed": "Não foi possível procurar o número de telefone",
+        "msisdn_lookup_failed_description": "Ocorreu um erro ao procurar o número de telefone",
+        "msisdn_transfer_failed": "Não foi possível transferir a chamada",
+        "n_people_joined": {
+            "one": "%(count)spessoa aderiu",
+            "other": "%(count)spessoas aderiram"
+        },
+        "no_audio_input_description": "Não encontrámos um microfone no teu dispositivo. Verifica as tuas definições e tenta novamente.",
+        "no_audio_input_title": "Nenhum microfone encontrado",
+        "no_media_perms_description": "Você talvez precise autorizar manualmente que o %(brand)s acesse seu microfone e webcam",
+        "no_media_perms_title": "Não há permissões para o uso de vídeo/áudio no seu navegador",
+        "no_permission_conference": "Permissão Requerida",
+        "no_permission_conference_description": "Não tem autorização para iniciar uma chamada de conferência nesta sala",
+        "on_hold": "%(name)s em espera",
+        "output_devices": "Dispositivos de saída",
+        "screenshare_monitor": "Partilha todo o ecrã",
+        "screenshare_title": "Partilhar conteúdo",
+        "screenshare_window": "Janela da aplicação",
+        "show_sidebar_button": "Mostrar barra lateral",
+        "silence": "Chamada de silêncio",
+        "silenced": "Notificações silenciadas",
+        "start_screenshare": "Começa a partilhar o teu ecrã",
+        "stop_screenshare": "Pára de partilhar o teu ecrã",
+        "too_many_calls": "Demasiadas Chamadas",
+        "too_many_calls_description": "Atingiu o número máximo de chamadas em simultâneo.",
+        "transfer_consult_first_label": "Consulta primeiro",
+        "transfer_failed": "A Transferência Falhou",
+        "transfer_failed_description": "Falha ao transferir chamada",
+        "unable_to_access_audio_input_description": "Não foi possível aceder ao teu microfone. Verifica as definições do teu browser e tenta novamente.",
+        "unable_to_access_audio_input_title": "Não é possível aceder ao teu microfone",
+        "unable_to_access_media": "Não é possível aceder à câmera / microfone",
+        "unable_to_access_microphone": "Não é possível aceder ao microfone",
+        "unknown_caller": "Chamada não identificada",
+        "unknown_person": "pessoa desconhecida",
+        "unsilence": "Som ligado",
+        "unsupported": "Chamadas não são suportadas",
+        "unsupported_browser": "Não pode fazer chamadas neste navegador.",
+        "user_busy": "Utilizador ocupado",
+        "user_busy_description": "O utilizador para o qual tentou ligar está ocupado.",
+        "user_is_presenting": "%(sharerName)s está apresentando",
+        "video_call": "Chamada de vídeo",
+        "video_call_started": "Chamada de vídeo iniciada",
+        "video_call_using": "Video-chamada usando:",
+        "voice_call": "Chamada de voz",
+        "you_are_presenting": "Estás a apresentar"
+    },
+    "widget": {
+        "added_by": "Widget adicionado por",
+        "capabilities_dialog": {
+            "content_starting_text": "Este widget gostaria de:",
+            "decline_all_permission": "Recusar Todos",
+            "remember_Selection": "Lembra-te da minha seleção para este widget",
+            "title": "Aprova as permissões do widget"
+        },
+        "capability": {
+            "always_on_screen_generic": "Permanece no teu ecrã durante a execução",
+            "always_on_screen_viewing_another_room": "Permanece no teu ecrã quando estás a ver outra sala, ao executar",
+            "any_room": "O acima, mas em qualquer sala onde te juntes ou sejas convidado",
+            "byline_empty_state_key": "com uma chave de estado vazia",
+            "byline_state_key": "com a chave de estado %(stateKey)s",
+            "capability": "A capacidade do <b>%(capability)s</b> ",
+            "change_avatar_active_room": "Altera o avatar da tua sala ativa",
+            "change_avatar_this_room": "Altera o avatar desta sala",
+            "change_name_active_room": "Altera o nome da tua sala ativa",
+            "change_name_this_room": "Altera o nome desta sala",
+            "change_topic_active_room": "Altera o tópico da tua sala ativa",
+            "change_topic_this_room": "Altera o tópico desta sala",
+            "receive_membership_active_room": "Vê quando as pessoas entram, saem ou são convidadas para a tua sala ativa",
+            "receive_membership_this_room": "Vê quando as pessoas entram, saem ou são convidadas para esta sala",
+            "remove_ban_invite_leave_active_room": "Remover, banir ou convidar pessoas para a tua sala ativa e obrigar-te a sair",
+            "remove_ban_invite_leave_this_room": "Remover, banir ou convidar pessoas para esta sala e obrigar-te a sair",
+            "see_avatar_change_active_room": "Vê quando o avatar muda na tua sala ativa",
+            "see_avatar_change_this_room": "Vê quando o avatar muda nesta sala",
+            "see_event_type_sent_active_room": "Vê eventos <b>%(eventType)s</b> publicados na tua sala ativa",
+            "see_event_type_sent_this_room": "Vê os eventos <b>%(eventType)s</b> publicados nesta sala",
+            "see_images_sent_active_room": "Vê imagens publicadas na tua sala ativa",
+            "see_images_sent_this_room": "Vê as imagens publicadas nesta sala",
+            "see_messages_sent_active_room": "Vê mensagens publicadas na tua sala ativa",
+            "see_messages_sent_this_room": "Vê mensagens enviadas para esta sala",
+            "see_msgtype_sent_active_room": "Vê mensagens <b>%(msgtype)s</b> publicadas na tua sala ativa",
+            "see_msgtype_sent_this_room": "Vê mensagens <b>%(msgtype)s</b> publicadas nesta sala",
+            "see_name_change_active_room": "Vê quando o nome muda na tua sala ativa",
+            "see_name_change_this_room": "Vê quando o nome muda nesta sala",
+            "see_sent_emotes_active_room": "Vê os gestos publicados na tua sala ativa",
+            "see_sent_emotes_this_room": "Vê os emotes publicados nesta sala",
+            "see_sent_files_active_room": "Vê ficheiros gerais publicados na tua sala ativa",
+            "see_sent_files_this_room": "Vê ficheiros gerais colocados nesta sala",
+            "see_sticker_posted_active_room": "Vê quando alguém coloca um autocolante na tua sala ativa",
+            "see_sticker_posted_this_room": "Vê quando um autocolante é publicado nesta sala",
+            "see_text_messages_sent_active_room": "Vê mensagens de texto publicadas na tua sala ativa",
+            "see_text_messages_sent_this_room": "Vê as mensagens de texto publicadas nesta sala",
+            "see_topic_change_active_room": "Vê quando o tópico muda na tua sala ativa",
+            "see_topic_change_this_room": "Vê quando o tópico muda nesta sala",
+            "see_videos_sent_active_room": "Vê vídeos publicados na tua sala ativa",
+            "see_videos_sent_this_room": "Vê os vídeos publicados nesta sala",
+            "send_emotes_active_room": "Envia gestos como tu na tua sala ativa",
+            "send_emotes_this_room": "Envia gestos como tu nesta sala",
+            "send_event_type_active_room": "Envia eventos <b>%(eventType)s</b> como tu na tua sala ativa",
+            "send_event_type_this_room": "Envia <b>%(eventType)s</b> eventos como tu nesta sala",
+            "send_files_active_room": "Envia ficheiros gerais como tu na tua sala ativa",
+            "send_files_this_room": "Envia ficheiros gerais como tu nesta sala",
+            "send_images_active_room": "Envia imagens como tu na tua sala ativa",
+            "send_images_this_room": "Envia imagens como tu nesta sala",
+            "send_messages_active_room": "Envia mensagens como tu na tua sala ativa",
+            "send_messages_this_room": "Envia mensagens como tu nesta sala",
+            "send_msgtype_active_room": "Envia mensagens <b>%(msgtype)s</b> como tu na tua sala ativa",
+            "send_msgtype_this_room": "Envia <b>%(msgtype)s</b> mensagens como tu nesta sala",
+            "send_stickers_active_room": "Envia autocolantes para a tua sala ativa",
+            "send_stickers_active_room_as_you": "Envia autocolantes para a tua sala ativa enquanto tu próprio",
+            "send_stickers_this_room": "Envia autocolantes para esta sala",
+            "send_stickers_this_room_as_you": "Envia autocolantes para esta sala enquanto tu próprio",
+            "send_text_messages_active_room": "Envia mensagens de texto como tu na tua sala ativa",
+            "send_text_messages_this_room": "Envia mensagens de texto como tu nesta sala",
+            "send_videos_active_room": "Envia vídeos como tu na tua sala ativa",
+            "send_videos_this_room": "Envia vídeos como tu nesta sala",
+            "specific_room": "O acima referido, mas também em <Room /> ",
+            "switch_room": "Altera a sala que estás a ver",
+            "switch_room_message_user": "Altera a sala, a mensagem ou o utilizador que estás a ver"
+        },
+        "close_to_view_right_panel": "Fecha este widget para o veres neste painel",
+        "context_menu": {
+            "delete": "Apagar widget",
+            "delete_warning": "A eliminação de um widget remove-o para todos os utilizadores desta sala. Tens a certeza de que queres apagar este widget?",
+            "move_left": "Mover para a esquerda",
+            "move_right": "Mover para a direita",
+            "remove": "Remover para todos",
+            "revoke": "Revogar permissões",
+            "screenshot": "Tira uma fotografia",
+            "start_audio_stream": "Iniciar transmissão de áudio"
+        },
+        "cookie_warning": "Este widget pode utilizar cookies.",
+        "error_hangup_description": "Foste desligado da chamada. (Erro: %(message)s)",
+        "error_hangup_title": "Conexão perdida",
+        "error_loading": "Erro ao carregar o Widget",
+        "error_mixed_content": "Erro - Conteúdo misto",
+        "error_need_invite_permission": "Para fazer isso, você tem que ter permissão para convidar outras pessoas.",
+        "error_need_kick_permission": "Precisa ter permissão de expulsar utilizadores para fazer isso.",
+        "error_need_to_be_logged_in": "Você tem que estar logado.",
+        "error_unable_start_audio_stream_description": "Não é possível iniciar a transmissão de áudio.",
+        "error_unable_start_audio_stream_title": "Falha ao iniciar a transmissão ao vivo",
+        "modal_data_warning": "Os dados neste ecrã são partilhados com %(widgetDomain)s",
+        "modal_title_default": "Widget Modal",
+        "no_name": "Aplicação desconhecida",
+        "open_id_permissions_dialog": {
+            "remember_selection": "Lembra-te disto",
+            "starting_text": "O widget verificará o teu ID de utilizador, mas não poderá executar ações por ti:",
+            "title": "Permite que este widget verifique a tua identidade"
+        },
+        "popout": "Widget de popout",
+        "set_room_layout": "Define a disposição do meu quarto para todos",
+        "shared_data_avatar": "URL da tua imagem de perfil",
+        "shared_data_device_id": "O teu ID de dispositivo",
+        "shared_data_lang": "A tua língua",
+        "shared_data_mxid": "O teu ID de utilizador",
+        "shared_data_name": "O teu nome de exibição",
+        "shared_data_room_id": "ID da sala",
+        "shared_data_theme": "O teu tema",
+        "shared_data_url": "%(brand)s URL",
+        "shared_data_warning": "A utilização deste widget pode partilhar dados <helpIcon /> com %(widgetDomain)s.",
+        "shared_data_warning_im": "A utilização deste widget pode partilhar dados <helpIcon /> com %(widgetDomain)s e o teu gestor de integração.",
+        "shared_data_widget_id": "ID do widget",
+        "unencrypted_warning": "Os widgets não utilizam encriptação de mensagens.",
+        "unmaximise": "Não maximizar",
+        "unpin_to_view_right_panel": "Desfixa este widget para o veres neste painel"
+    },
+    "zxcvbn": {
+        "suggestions": {
+            "allUppercase": "As maiúsculas são quase tão fáceis de adivinhar como as minúsculas",
+            "anotherWord": "Acrescentar mais uma ou duas palavras. Palavras invulgares são melhores.",
+            "associatedYears": "Evita os anos que estão associados a ti",
+            "capitalization": "A capitalização não ajuda muito",
+            "dates": "Evita datas e anos que estejam associados a ti",
+            "l33t": "As substituições previsíveis como \"@\" em vez de \"a\" não ajudam muito",
+            "longerKeyboardPattern": "Utiliza um padrão de teclado mais longo com mais voltas",
+            "noNeed": "Não precisas de símbolos, dígitos ou letras maiúsculas",
+            "pwned": "Se utilizares esta palavra-passe noutro local, deves alterá-la.",
+            "recentYears": "Evita anos recentes",
+            "repeated": "Evita palavras e caracteres repetidos",
+            "reverseWords": "As palavras invertidas não são muito mais difíceis de adivinhar",
+            "sequences": "Evita as sequências",
+            "useWords": "Usa poucas palavras, evita frases comuns"
+        },
+        "warnings": {
+            "common": "Esta é uma palavra-passe muito comum",
+            "commonNames": "Os nomes comuns e os apelidos são fáceis de adivinhar",
+            "dates": "As datas são muitas vezes fáceis de adivinhar",
+            "extendedRepeat": "Repetições como \"abcabcabc\" são apenas ligeiramente mais difíceis de adivinhar do que \"abc\"",
+            "keyPattern": "Os padrões curtos do teclado são fáceis de adivinhar",
+            "namesByThemselves": "Os nomes e apelidos por si só são fáceis de adivinhar",
+            "pwned": "A tua palavra-passe foi exposta por uma violação de dados na Internet.",
+            "recentYears": "Anos recentes são fáceis de adivinhar.",
+            "sequences": "Sequências como abc ou 6543 são fáceis de adivinhar",
+            "similarToCommon": "Isto é semelhante a uma palavra-passe comummente utilizada",
+            "simpleRepeat": "Repetições como \"aaa\" são fáceis de adivinhar",
+            "straightRow": "As linhas rectas de teclas são fáceis de adivinhar",
+            "topHundred": "Esta é uma das 100 palavras-passe mais comuns",
+            "topTen": "Esta é uma das 10 palavras-passe mais comuns",
+            "userInputs": "Não deve haver quaisquer dados pessoais ou relacionados com a página.",
+            "wordByItself": "Uma palavra por si só é fácil de adivinhar"
+        }
+    }
+}
diff --git a/src/i18n/strings/pt_BR.json b/src/i18n/strings/pt_BR.json
index 7813d6146c0..efee2781b06 100644
--- a/src/i18n/strings/pt_BR.json
+++ b/src/i18n/strings/pt_BR.json
@@ -431,8 +431,7 @@
         "video": "Vídeo",
         "video_room": "Sala de vídeo",
         "view_message": "Ver mensagem",
-        "warning": "Atenção",
-        "welcome": "Boas-vindas"
+        "warning": "Atenção"
     },
     "composer": {
         "autocomplete": {
@@ -1038,7 +1037,6 @@
     },
     "member_list": {
         "filter_placeholder": "Pesquisar participantes da sala",
-        "invited_list_heading": "Convidada(o)",
         "power_label": "%(userName)s (nível de permissão %(powerLevelNumber)s)"
     },
     "member_list_back_action_label": "Membros da sala",
@@ -1077,17 +1075,11 @@
     "onboarding": {
         "create_room": "Criar um chat de grupo",
         "explore_rooms": "Explorar salas públicas",
-        "find_people": "Encontrar pessoas",
         "has_avatar_label": "Ótimo, agora as pessoas identificarão você",
         "intro_welcome": "Boas-vindas ao %(appName)s",
         "no_avatar_label": "Adicione uma foto para as pessoas identificarem você.",
-        "qr_or_app_links": "%(qrCode)s ou %(appLinks)s",
         "send_dm": "Enviar uma mensagem",
-        "set_up_profile": "Configure seu perfil",
-        "set_up_profile_action": "Seu perfil",
-        "set_up_profile_description": "Certifique-se de que as pessoas saibam que é realmente você",
         "welcome_detail": "Agora, vamos começar",
-        "welcome_to_brand": "Bem-vindo a %(brand)s",
         "welcome_user": "Boas-vindas, %(name)s"
     },
     "poll": {
@@ -1110,7 +1102,6 @@
         "custom_level": "Nível personalizado",
         "default": "Padrão",
         "label": "Nível de permissão",
-        "mod": "Moderador",
         "moderator": "Moderador/a",
         "restricted": "Restrito"
     },
@@ -1983,7 +1974,6 @@
         "invite": "Convidar pessoas",
         "invite_description": "Convidar com email ou nome de usuário",
         "invite_link": "Compartilhar link de convite",
-        "invite_this_space": "Convidar para este espaço",
         "landing_welcome": "Boas-vindas ao <name/>",
         "leave_dialog_action": "Sair do espaço",
         "leave_dialog_option_all": "Sair de todas as salas",
diff --git a/src/i18n/strings/ru.json b/src/i18n/strings/ru.json
index 555cb3d1f9b..d58f87c0045 100644
--- a/src/i18n/strings/ru.json
+++ b/src/i18n/strings/ru.json
@@ -230,7 +230,6 @@
         "oidc": {
             "error_title": "Нам не удалось войти в систему",
             "generic_auth_error": "Во время аутентификации что-то пошло не так. Перейдите на страницу входа и попробуйте еще раз.",
-            "logout_redirect_warning": "Вы будете перенаправлены к поставщику аутентификации вашего сервера для завершения выхода из системы.",
             "missing_or_invalid_stored_state": "Мы попросили браузер запомнить, какой домашний сервер вы используете для входа в систему, но, к сожалению, ваш браузер забыл об этом. Перейдите на страницу входа и попробуйте ещё раз."
         },
         "password_field_keep_going_prompt": "Продолжить",
@@ -413,7 +412,6 @@
             "other": "и %(count)s других...",
             "one": "и ещё кто-то..."
         },
-        "android": "Android",
         "appearance": "Внешний вид",
         "application": "Приложение",
         "are_you_sure": "Вы уверены?",
@@ -452,7 +450,6 @@
         "identity_server": "Идентификационный сервер",
         "image": "Изображение",
         "integration_manager": "Менеджер интеграции",
-        "ios": "iOS",
         "joined": "Присоединился",
         "labs": "Лаборатория",
         "legal": "Правовая информация",
@@ -541,8 +538,7 @@
         "video": "Видео",
         "video_room": "Видеокомната",
         "view_message": "Посмотреть сообщение",
-        "warning": "Внимание",
-        "welcome": "Добро пожаловать"
+        "warning": "Внимание"
     },
     "composer": {
         "autocomplete": {
@@ -1380,8 +1376,6 @@
         "notification_settings_beta_caption": "Представляем вам более простой способ изменения настроек уведомлений. Настройте свои настройки так %(brand)s, как вам удобно.",
         "notification_settings_beta_title": "Настройки уведомлений",
         "notifications": "Включить панель уведомлений в заголовке комнаты",
-        "oidc_native_flow": "Встроенная аутентификация OIDC",
-        "oidc_native_flow_description": "⚠ ВНИМАНИЕ: Экспериментально. Используйте встроенную аутентификацию OIDC, если она поддерживается сервером.",
         "render_reaction_images": "Обработка пользовательских изображений в реакциях",
         "render_reaction_images_description": "Иногда их называют \"пользовательскими эмодзи\".",
         "report_to_moderators": "Пожаловаться модераторам",
@@ -1500,7 +1494,6 @@
     "member_list": {
         "filter_placeholder": "Поиск по участникам",
         "invite_button_no_perms_tooltip": "У вас нет разрешения приглашать пользователей",
-        "invited_list_heading": "Приглашены",
         "power_label": "%(userName)s (уровень прав %(powerLevelNumber)s)"
     },
     "member_list_back_action_label": "Участники комнаты",
@@ -1540,61 +1533,15 @@
         "m.key.verification.request": "%(name)s запрашивает проверку"
     },
     "onboarding": {
-        "apple_trademarks": "App Store® и Логотип Apple® являются товарными знаками Apple Inc.",
-        "community_messaging_action": "Найдите людей",
-        "community_messaging_description": "Сохраняйте право над владением и контроль над обсуждением в сообществе.\nМасштабируйте, чтобы поддерживать миллионы, с мощной модерацией и функциональной совместимостью.",
-        "community_messaging_title": "Владение сообществом",
-        "complete_these": "Выполните их, чтобы получить максимальную отдачу от %(brand)s",
         "create_room": "Создать комнату",
-        "download_app": "Скачать %(brand)s",
-        "download_app_action": "Скачать приложения",
-        "download_app_description": "Не пропустите ничего, взяв %(brand)s с тобой",
-        "download_app_store": "Скачать в App Store",
-        "download_brand": "Скачать %(brand)s",
-        "download_brand_desktop": "Скачать %(brand)s Desktop",
-        "download_f_droid": "Скачать на F-Droid",
-        "download_google_play": "Скачать в Google Play",
-        "enable_notifications": "Включить уведомления",
-        "enable_notifications_action": "Включить уведомления",
-        "enable_notifications_description": "Не пропустите ответ или важное сообщение",
         "explore_rooms": "Просмотреть публичные комнаты",
-        "find_community_members": "Найдите и пригласите участников сообщества",
-        "find_coworkers": "Найдите и пригласите своих коллег",
-        "find_friends": "Найдите и пригласите своих друзей",
-        "find_friends_action": "Найти друзей",
-        "find_friends_description": "Это то, для чего вы здесь, так что давайте приступим к делу",
-        "find_people": "Найти людей",
-        "free_e2ee_messaging_unlimited_voip": "Благодаря бесплатному сквозному шифрованному обмену сообщениями и неограниченным голосовым и видеозвонкам, %(brand)s это отличный способ оставаться на связи.",
-        "get_stuff_done": "Добейтесь успеха, найдя своих товарищей по команде",
-        "google_trademarks": "Google Play и Логотип Google Play являются торговыми знаками Google LLC.",
         "has_avatar_label": "Отлично, это поможет людям узнать, что это ты",
         "intro_byline": "Владейте своими разговорами.",
         "intro_welcome": "Добро пожаловать в %(appName)s",
         "no_avatar_label": "Добавьте фото, чтобы люди знали, что это вы.",
-        "only_n_steps_to_go": {
-            "one": "Осталось всего %(count)s шагов до конца",
-            "other": "Осталось всего %(count)s шагов"
-        },
-        "personal_messaging_action": "Начните свою первую беседу",
-        "personal_messaging_title": "Безопасный обмен сообщениями для друзей и семьи",
-        "qr_or_app_links": "%(qrCode)s или %(appLinks)s",
         "send_dm": "Отправить личное сообщение",
-        "set_up_profile": "Настройте свой профиль",
-        "set_up_profile_action": "Ваш профиль",
-        "set_up_profile_description": "Убедитесь, что люди знают, что это действительно вы",
-        "use_case_community_messaging": "Участники сообщества в сети",
-        "use_case_heading1": "Вы в",
-        "use_case_heading2": "С кем вы будете общаться чаще всего?",
-        "use_case_heading3": "Мы поможем вам подключиться.",
-        "use_case_personal_messaging": "Друзья и семья",
-        "use_case_work_messaging": "Коллеги и команды",
         "welcome_detail": "Теперь давайте поможем вам начать",
-        "welcome_to_brand": "Добро пожаловать в %(brand)s",
-        "welcome_user": "Добро пожаловать, %(name)s",
-        "work_messaging_action": "Найдите коллег",
-        "work_messaging_title": "Безопасный обмен сообщениями для работы",
-        "you_did_it": "Вы сделали это!",
-        "you_made_it": "Вы сделали это!"
+        "welcome_user": "Добро пожаловать, %(name)s"
     },
     "pill": {
         "permalink_other_room": "Сообщение в %(room)s",
@@ -1646,7 +1593,6 @@
         "custom_level": "Специальные права",
         "default": "По умолчанию",
         "label": "Уровень прав",
-        "mod": "Модератор",
         "moderator": "Модератор",
         "restricted": "Ограниченный пользователь"
     },
@@ -2516,7 +2462,6 @@
             "room_directory_heading": "Каталог комнат",
             "room_list_heading": "Список комнат",
             "show_avatars_pills": "Показывать аватары в упоминаниях пользователей, комнатах и событиях",
-            "show_checklist_shortcuts": "Показывать ярлык приветственного проверенного списка над списком комнат",
             "show_polls_button": "Показывать кнопку опроса",
             "surround_text": "Обводить выделенный текст при вводе специальных символов",
             "time_heading": "Отображение времени"
@@ -2879,7 +2824,6 @@
         "invite": "Пригласить людей",
         "invite_description": "Пригласить по электронной почте или имени пользователя",
         "invite_link": "Поделиться ссылкой на приглашение",
-        "invite_this_space": "Пригласить в это пространство",
         "joining_space": "Присоединение",
         "landing_welcome": "Добро пожаловать в <name/>",
         "leave_dialog_action": "Покинуть пространство",
diff --git a/src/i18n/strings/sk.json b/src/i18n/strings/sk.json
index eab25be92bb..a5868cf5701 100644
--- a/src/i18n/strings/sk.json
+++ b/src/i18n/strings/sk.json
@@ -230,7 +230,6 @@
         "oidc": {
             "error_title": "Nemohli sme vás prihlásiť",
             "generic_auth_error": "Počas overenia sa niečo pokazilo. Prejdite na stránku prihlásenia a skúste to znova.",
-            "logout_redirect_warning": "Na dokončenie odhlásenia budete presmerovaní na vášho poskytovateľa autentifikácie servera.",
             "missing_or_invalid_stored_state": "Požiadali sme prehliadač, aby si zapamätal, ktorý domovský server používate na prihlásenie, ale bohužiaľ váš prehliadač to zabudol. Prejdite na stránku prihlásenia a skúste to znova."
         },
         "password_field_keep_going_prompt": "Pokračujte…",
@@ -413,7 +412,6 @@
             "other": "a ďalších %(count)s…",
             "one": "a jeden ďalší…"
         },
-        "android": "Android",
         "appearance": "Vzhľad",
         "application": "Aplikácia",
         "are_you_sure": "Ste si istí?",
@@ -452,7 +450,6 @@
         "identity_server": "Server totožností",
         "image": "Obrázok",
         "integration_manager": "Správca integrácie",
-        "ios": "iOS",
         "joined": "Ste pripojený",
         "labs": "Experimenty",
         "legal": "Právne informácie",
@@ -541,8 +538,7 @@
         "video": "Video",
         "video_room": "Video miestnosť",
         "view_message": "Zobraziť správu",
-        "warning": "Upozornenie",
-        "welcome": "Vitajte"
+        "warning": "Upozornenie"
     },
     "composer": {
         "autocomplete": {
@@ -1385,8 +1381,6 @@
         "notification_settings_beta_caption": "Predstavujeme jednoduchší spôsob zmeny nastavení oznámení. Prispôsobte si svoju aplikáciu %(brand)s, presne podľa svojich predstáv.",
         "notification_settings_beta_title": "Nastavenia oznámení",
         "notifications": "Povolenie panelu oznámení v záhlaví miestnosti",
-        "oidc_native_flow": "Povoliť nové natívne toky OIDC (v štádiu aktívneho vývoja)",
-        "oidc_native_flow_description": "⚠ VAROVANIE: Experimentálne. Použite natívne overenie OIDC, ak je podporované serverom.",
         "render_reaction_images": "Vykresľovať vlastné obrázky v reakciách",
         "render_reaction_images_description": "Niekedy sa označujú ako „vlastné emotikony“.",
         "report_to_moderators": "Nahlásiť moderátorom",
@@ -1505,7 +1499,6 @@
     "member_list": {
         "filter_placeholder": "Filtrovať členov v miestnosti",
         "invite_button_no_perms_tooltip": "Nemáte oprávnenie pozývať používateľov",
-        "invited_list_heading": "Pozvaní",
         "power_label": "%(userName)s (oprávnenie %(powerLevelNumber)s)"
     },
     "member_list_back_action_label": "Členovia miestnosti",
@@ -1545,62 +1538,15 @@
         "m.key.verification.request": "%(name)s žiada o overenie"
     },
     "onboarding": {
-        "apple_trademarks": "App Store® a logo Apple® sú ochranné známky spoločnosti Apple Inc.",
-        "community_messaging_action": "Nájdite svojich ľudí",
-        "community_messaging_description": "Zachovajte si vlastníctvo a kontrolu nad komunitnou diskusiou.\nPodpora pre milióny ľudí s výkonným moderovaním a interoperabilitou.",
-        "community_messaging_title": "Vlastníctvo komunity",
-        "complete_these": "Dokončite to, aby ste získali čo najviac z aplikácie %(brand)s",
         "create_room": "Vytvoriť skupinovú konverzáciu",
-        "download_app": "Stiahnuť %(brand)s",
-        "download_app_action": "Stiahnite si aplikácie",
-        "download_app_description": "Nezmeškáte nič, ak so sebou vezmete %(brand)s",
-        "download_app_store": "Stiahnuť v obchode App Store",
-        "download_brand": "Stiahnuť %(brand)s",
-        "download_brand_desktop": "Stiahnuť %(brand)s Desktop",
-        "download_f_droid": "Získajte ho v službe F-Droid",
-        "download_google_play": "Získajte ho v službe Google Play",
-        "enable_notifications": "Zapnúť oznámenia",
-        "enable_notifications_action": "Povoliť oznámenia",
-        "enable_notifications_description": "Nezmeškajte odpoveď alebo dôležitú správu",
         "explore_rooms": "Preskúmať verejné miestnosti",
-        "find_community_members": "Nájdite a pozvite členov vašej komunity",
-        "find_coworkers": "Vyhľadajte a pozvite svojich spolupracovníkov",
-        "find_friends": "Nájdite a pozvite svojich priateľov",
-        "find_friends_action": "Nájsť priateľov",
-        "find_friends_description": "Kvôli tomu ste tu, tak sa do toho pustite",
-        "find_people": "Nájsť ľudí",
-        "free_e2ee_messaging_unlimited_voip": "Vďaka bezplatnému end-to-end šifrovaniu správ a neobmedzenými hlasovými a video hovormi je aplikácia %(brand)s skvelým spôsobom, ako zostať v kontakte.",
-        "get_stuff_done": "Vyriešte veci tým, že nájdete svojich tímových kolegov",
-        "google_trademarks": "Google Play a logo Google Play sú ochranné známky spoločnosti Google LLC.",
         "has_avatar_label": "Skvelé, to pomôže ľuďom zistiť, že ste to vy",
         "intro_byline": "Vlastnite svoje konverzácie.",
         "intro_welcome": "Vitajte v %(appName)s",
         "no_avatar_label": "Pridajte fotografiu, aby ľudia vedeli, že ste to vy.",
-        "only_n_steps_to_go": {
-            "one": "Zostáva už len %(count)s krok",
-            "few": "Zostávajú už len %(count)s kroky",
-            "other": "Zostáva už len %(count)s krokov"
-        },
-        "personal_messaging_action": "Spustite svoju prvú konverzáciu",
-        "personal_messaging_title": "Zabezpečené zasielanie správ pre priateľov a rodinu",
-        "qr_or_app_links": "%(qrCode)s alebo %(appLinks)s",
         "send_dm": "Poslať priamu správu",
-        "set_up_profile": "Nastavte si svoj profil",
-        "set_up_profile_action": "Váš profil",
-        "set_up_profile_description": "Uistite sa, že ľudia vedia, že ste to naozaj vy",
-        "use_case_community_messaging": "Členovia online komunity",
-        "use_case_heading1": "Ste v",
-        "use_case_heading2": "S kým budete komunikovať najčastejšie?",
-        "use_case_heading3": "Pomôžeme vám nadviazať kontakty.",
-        "use_case_personal_messaging": "Priatelia a rodina",
-        "use_case_work_messaging": "Spolupracovníci a tímy",
         "welcome_detail": "Teraz vám pomôžeme začať",
-        "welcome_to_brand": "Vitajte v aplikácii %(brand)s",
-        "welcome_user": "Vitajte %(name)s",
-        "work_messaging_action": "Nájdite svojich spolupracovníkov",
-        "work_messaging_title": "Zabezpečené posielanie správ pre prácu",
-        "you_did_it": "Dokázali ste to!",
-        "you_made_it": "Zvládli ste to!"
+        "welcome_user": "Vitajte %(name)s"
     },
     "pill": {
         "permalink_other_room": "Správa v %(room)s",
@@ -1652,7 +1598,6 @@
         "custom_level": "Vlastná úroveň",
         "default": "Predvolené",
         "label": "Úroveň oprávnenia",
-        "mod": "Moderátor",
         "moderator": "Moderátor",
         "restricted": "Obmedzené"
     },
@@ -2519,7 +2464,6 @@
             "room_directory_heading": "Adresár miestností",
             "room_list_heading": "Zoznam miestností",
             "show_avatars_pills": "Zobraziť obrázky profilov v zmienkach o používateľoch, miestnostiach a udalostiach",
-            "show_checklist_shortcuts": "Zobraziť skratku na uvítací kontrolný zoznam nad zoznamom miestností",
             "show_polls_button": "Zobraziť tlačidlo ankiet",
             "surround_text": "Obklopiť vybraný text pri písaní špeciálnych znakov",
             "time_heading": "Zobrazovanie času"
@@ -2881,7 +2825,6 @@
         "invite": "Pozvať ľudí",
         "invite_description": "Pozvať pomocou e-mailu alebo používateľského mena",
         "invite_link": "Zdieľať odkaz na pozvánku",
-        "invite_this_space": "Pozvať do tohto priestoru",
         "joining_space": "Pripájanie sa",
         "landing_welcome": "Vitajte v <name/>",
         "leave_dialog_action": "Opustiť priestor",
diff --git a/src/i18n/strings/sq.json b/src/i18n/strings/sq.json
index 356480535fd..63c72802965 100644
--- a/src/i18n/strings/sq.json
+++ b/src/i18n/strings/sq.json
@@ -515,8 +515,7 @@
         "verified": "I verifikuar",
         "video_room": "Dhomë me video",
         "view_message": "Shihni mesazh",
-        "warning": "Sinjalizim",
-        "welcome": "Mirë se vini"
+        "warning": "Sinjalizim"
     },
     "composer": {
         "autocomplete": {
@@ -1415,7 +1414,6 @@
     "member_list": {
         "filter_placeholder": "Filtroni anëtarë dhome",
         "invite_button_no_perms_tooltip": "S’keni leje të ftoni përdorues",
-        "invited_list_heading": "I ftuar",
         "power_label": "%(userName)s (pushtet %(powerLevelNumber)si)"
     },
     "member_list_back_action_label": "Anëtarë dhome",
@@ -1455,61 +1453,15 @@
         "m.key.verification.request": "%(name)s po kërkon verifikim"
     },
     "onboarding": {
-        "apple_trademarks": "App Store® dhee Apple logo® janë shenja tregtare të Apple Inc.",
-        "community_messaging_action": "Gjeni njerëzit tuaj",
-        "community_messaging_description": "Ruani pronësinë dhe kontrollin e diskutimit në bashkësi.\nPërshkallëzojeni për të mbuluar miliona, me moderim dhe ndërveprueshmëri të fuqishme.",
-        "community_messaging_title": "Pronësi e bashkësisë",
-        "complete_these": "Plotësoni këto, që të përfitoni maksimumin prej %(brand)s",
         "create_room": "Krijoni një Fjalosje Grupi",
-        "download_app": "Shkarko %(brand)s",
-        "download_app_action": "Shkarko aplikacione",
-        "download_app_description": "Mos humbni asgjë, duke e marrë %(brand)s-in me vete",
-        "download_app_store": "Shkarkoje nga App Store",
-        "download_brand": "Shkarko %(brand)s",
-        "download_brand_desktop": "Shkarko %(brand)s Desktop",
-        "download_f_droid": "Merreni në F-Droid",
-        "download_google_play": "Merreni nga Google Play",
-        "enable_notifications": "Aktivizo njoftimet",
-        "enable_notifications_action": "Aktivizo njoftimet",
-        "enable_notifications_description": "Mos humbni përgjigje apo mesazh të rëndësishëm",
         "explore_rooms": "Eksploroni Dhoma Publike",
-        "find_community_members": "Gjeni dhe ftoni anëtarë të bashkësisë tuaj",
-        "find_coworkers": "Gjeni dhe ftoni kolegë tuajt",
-        "find_friends": "Gjeni dhe ftoni shokët tuaj",
-        "find_friends_action": "Gjeni shokë",
-        "find_friends_description": "Kjo është ajo pse erdhët, ndaj ta bëjmë",
-        "find_people": "Gjeni persona",
-        "free_e2ee_messaging_unlimited_voip": "Me shkëmbim mesazhesh të fshehtëzuar skaj-më-skaj dhe thirrje pa kufi me zë dhe video, %(brand)s është një rrugë e fuqishme për të mbajtur lidhjet.",
-        "get_stuff_done": "Kryeni punët, duke gjetur kolegët e ekipit",
-        "google_trademarks": "Google Play dhe stema Google Play janë shenja tregtare të Google LLC.",
         "has_avatar_label": "Bukur, kjo do t’i ndihmojë njerëzit ta dinë se jeni ju",
         "intro_byline": "Jini zot i bisedave tuaja.",
         "intro_welcome": "Mirë se vini te %(appName)s",
         "no_avatar_label": "Shtoni një foto, që njerëzit ta dinë se jeni ju.",
-        "only_n_steps_to_go": {
-            "one": "Vetëm %(count)s hap për t’u bërë",
-            "other": "Vetëm %(count)s hapa për t’u bërë"
-        },
-        "personal_messaging_action": "Filloni fjalosjen tuaj të parë",
-        "personal_messaging_title": "Shkëmbim i sigurt mesazhesh për shokë dhe familje",
-        "qr_or_app_links": "%(qrCode)s ose %(appLinks)s",
         "send_dm": "Dërgoni Mesazh të Drejtpërdrejtë",
-        "set_up_profile": "Ujdisni profilin tuaj",
-        "set_up_profile_action": "Profili juaj",
-        "set_up_profile_description": "Bëni të mundur që njerëzit ta dinë se vërtet jeni ju",
-        "use_case_community_messaging": "Anëtarë bashkësie internetore",
-        "use_case_heading1": "Kaq qe",
-        "use_case_heading2": "Me kë do të bisedoni më të shumtën?",
-        "use_case_heading3": "Do t’ju ndihmojmë të lidheni.",
-        "use_case_personal_messaging": "Shokë dhe familje",
-        "use_case_work_messaging": "Kolegë dhe ekipe",
         "welcome_detail": "Tani, le t’ju ndihmojmë për t’ia filluar",
-        "welcome_to_brand": "Mirë se vini te %(brand)s",
-        "welcome_user": "Mirë se vini %(name)s",
-        "work_messaging_action": "Gjeni kolegë tuajt",
-        "work_messaging_title": "Shkëmbim i sigurt mesazhesh për në punë",
-        "you_did_it": "Ia dolët!",
-        "you_made_it": "E bëtë!"
+        "welcome_user": "Mirë se vini %(name)s"
     },
     "pill": {
         "permalink_other_room": "Mesazh në %(room)s",
@@ -1561,7 +1513,6 @@
         "custom_level": "Nivel vetjak",
         "default": "Parazgjedhje",
         "label": "Shkallë pushteti",
-        "mod": "Moderator",
         "restricted": "E kufizuar"
     },
     "powered_by_matrix": "Bazuar në Matrix",
@@ -2356,7 +2307,6 @@
             "room_directory_heading": "Drejtori dhomash",
             "room_list_heading": "Listë dhomash",
             "show_avatars_pills": "Shfaq avatarë në përmendje përdoruesish, dhomash dhe aktesh",
-            "show_checklist_shortcuts": "Shhkurtoren e listës së hapave të mirëseardhjes shfaqe mbi listën e dhomave",
             "show_polls_button": "Shfaq buton pyetësorësh",
             "surround_text": "Rrethoje tekstin e përzgjedhur, kur shtypen shenja speciale",
             "time_heading": "Kohë shfaqjeje"
@@ -2703,7 +2653,6 @@
         "invite": "Ftoni njerëz",
         "invite_description": "Ftoni përmes email-i ose emri përdoruesi",
         "invite_link": "Jepuni lidhje ftese",
-        "invite_this_space": "Ftoni në këtë hapësirë",
         "joining_space": "Po hyhet",
         "landing_welcome": "Mirë se vini te <name/>",
         "leave_dialog_action": "Braktiseni hapësirën",
diff --git a/src/i18n/strings/sv.json b/src/i18n/strings/sv.json
index e24878b5316..e8df5df5dae 100644
--- a/src/i18n/strings/sv.json
+++ b/src/i18n/strings/sv.json
@@ -110,6 +110,7 @@
         "save": "Spara",
         "search": "Sök",
         "send_report": "Skicka rapport",
+        "set_avatar": "Ställ in profilbild",
         "share": "Dela",
         "show": "Visa",
         "show_advanced": "Visa avancerat",
@@ -133,6 +134,7 @@
         "update": "Uppdatera",
         "upgrade": "Uppgradera",
         "upload": "Ladda upp",
+        "upload_file": "Ladda upp fil",
         "verify": "Verifiera",
         "view": "Visa",
         "view_all": "Visa alla",
@@ -227,6 +229,7 @@
         },
         "misconfigured_body": "Be din %(brand)s-administratör att kolla <a>din konfiguration</a> efter felaktiga eller duplicerade poster.",
         "misconfigured_title": "Din %(brand)s är felkonfigurerad",
+        "mobile_create_account_title": "Du håller på att skapa ett konto på%(hsName)s",
         "msisdn_field_description": "Andra användare kan bjuda in dig till rum med dina kontaktuppgifter",
         "msisdn_field_label": "Telefon",
         "msisdn_field_number_invalid": "Det telefonnumret ser inte korrekt ut, vänligen kolla det och försök igen",
@@ -235,7 +238,6 @@
         "oidc": {
             "error_title": "Vi kunde inte logga in dig",
             "generic_auth_error": "Något gick fel under autentiseringen. Gå till inloggningssidan och försök igen.",
-            "logout_redirect_warning": "Du kommer att omdirigeras till din servers autentiseringsleverantör för att slutföra utloggningen.",
             "missing_or_invalid_stored_state": "Vi bad webbläsaren att komma ihåg vilken hemserver du använder för att logga in, men tyvärr har din webbläsare glömt det. Gå till inloggningssidan och försök igen."
         },
         "password_field_keep_going_prompt": "Fortsätter …",
@@ -245,12 +247,40 @@
         "phone_label": "Telefon",
         "phone_optional_label": "Telefon (valfritt)",
         "qr_code_login": {
+            "check_code_explainer": "Detta kommer att verifiera att anslutningen till din andra enhet är säker.",
+            "check_code_heading": "Ange numret som visas på din andra enhet",
+            "check_code_input_label": "2-siffrig kod",
+            "check_code_mismatch": "Siffrorna stämmer inte överens",
             "completing_setup": "Slutför inställning av din nya enhet",
+            "error_etag_missing": "Ett oväntat fel inträffade. Detta kan bero på felkonfiguration av webbläsartillägg, proxyserver eller server.",
+            "error_expired": "Inloggningen har upphört att gälla. Försök igen.",
+            "error_expired_title": "Inloggningen slutfördes inte i tid",
+            "error_insecure_channel_detected": "En säker anslutning kunde inte göras till den nya enheten. Dina befintliga enheter är fortfarande säkra och du behöver inte oroa dig för dem.",
+            "error_insecure_channel_detected_instructions": "Vad händer nu?",
+            "error_insecure_channel_detected_instructions_1": "Försök logga in på den andra enheten igen med en QR-kod om detta var ett nätverksproblem",
+            "error_insecure_channel_detected_instructions_2": "Om du stöter på samma problem, prova ett annat wifi-nätverk eller använd din mobildata istället för wifi",
+            "error_insecure_channel_detected_instructions_3": "Om det inte fungerar loggar du in manuellt",
+            "error_insecure_channel_detected_title": "Anslutningen är inte säker",
+            "error_other_device_already_signed_in": "Du behöver inte göra något mer.",
+            "error_other_device_already_signed_in_title": "Din andra enhet är redan inloggad",
             "error_rate_limited": "För många försök under för kort tid. Vänta ett tag innan du försöker igen.",
-            "error_unexpected": "Ett oväntade fel inträffade.",
-            "scan_code_instruction": "Skanna QR-koden nedan med din andra enhet som är utloggad.",
-            "scan_qr_code": "Skanna QR-kod",
-            "select_qr_code": "Välj '%(scanQRCode)s'",
+            "error_unexpected": "Ett oväntat fel inträffade. Begäran om att ansluta din andra enhet har avbrutits.",
+            "error_unsupported_protocol": "Den här enheten stöder inte inloggning på den andra enheten med en QR-kod.",
+            "error_unsupported_protocol_title": "Annan enhet är inte kompatibel",
+            "error_user_cancelled": "Inloggningen avbröts på den andra enheten.",
+            "error_user_cancelled_title": "Inloggningsbegäran avbröts",
+            "error_user_declined": "Du eller kontoleverantören har avvisat inloggningsbegäran.",
+            "error_user_declined_title": "Inloggningen nekades",
+            "follow_remaining_instructions": "Följ de återstående instruktionerna",
+            "open_element_other_device": "Öppna %(brand)s på din andra enhet",
+            "point_the_camera": "Skanna QR-koden som visas här",
+            "scan_code_instruction": "Skanna QR-koden med en annan enhet",
+            "scan_qr_code": "Logga in med QR-kod",
+            "security_code": "Säkerhetskod",
+            "security_code_prompt": "Om du blir ombedd anger du koden nedan på din andra enhet.",
+            "select_qr_code": "Välj \"%(scanQRCode)s”",
+            "unsupported_explainer": "Din kontoleverantör stöder inte inloggning på en ny enhet med en QR-kod.",
+            "unsupported_heading": "QR-kod stöds inte",
             "waiting_for_device": "Väntar på att enheter loggar in"
         },
         "register_action": "Skapa konto",
@@ -339,6 +369,8 @@
             "email_resend_prompt": "Fick du inte den? <a>Skicka igen</a>",
             "email_resent": "Skickade igen!",
             "fallback_button": "Starta autentisering",
+            "mas_cross_signing_reset_cta": "Gå till ditt konto",
+            "mas_cross_signing_reset_description": "Återställ din identitet via din kontoleverantör och kom sedan tillbaka och klicka på ”Försök igen”.",
             "msisdn": "Ett SMS har skickats till %(msisdn)s",
             "msisdn_token_incorrect": "Felaktig token",
             "msisdn_token_prompt": "Vänligen ange koden det innehåller:",
@@ -419,7 +451,6 @@
             "other": "och %(count)s andra…",
             "one": "och en annan…"
         },
-        "android": "Android",
         "appearance": "Utseende",
         "application": "Applikation",
         "are_you_sure": "Är du säker?",
@@ -429,6 +460,7 @@
         "beta": "Beta",
         "camera": "Kamera",
         "cameras": "Kameror",
+        "cancel": "Avbryt",
         "capabilities": "Förmågor",
         "copied": "Kopierat!",
         "credits": "Medverkande",
@@ -458,7 +490,6 @@
         "identity_server": "Identitetsserver",
         "image": "Bild",
         "integration_manager": "Integrationshanterare",
-        "ios": "iOS",
         "joined": "Gick med",
         "labs": "Experiment",
         "legal": "Juridiskt",
@@ -470,6 +501,7 @@
         "matrix": "Matrix",
         "message": "Meddelande",
         "message_layout": "Meddelandearrangemang",
+        "message_timestamp_invalid": "Ogiltig tidsstämpel",
         "microphone": "Mikrofon",
         "model": "Modell",
         "modern": "Modernt",
@@ -511,6 +543,8 @@
         "room": "Rum",
         "room_name": "Rumsnamn",
         "rooms": "Rum",
+        "save": "Spara",
+        "saved": "Sparat",
         "saving": "Sparar …",
         "secure_backup": "Säker säkerhetskopiering",
         "security": "Säkerhet",
@@ -539,6 +573,7 @@
         "unnamed_room": "Namnlöst rum",
         "unnamed_space": "Namnlöst utrymme",
         "unverified": "Overifierad",
+        "updating": "Uppdaterar...",
         "user": "Användare",
         "user_avatar": "Profilbild",
         "username": "Användarnamn",
@@ -548,8 +583,7 @@
         "video": "Video",
         "video_room": "Videorum",
         "view_message": "Visa meddelande",
-        "warning": "Varning",
-        "welcome": "Välkommen"
+        "warning": "Varning"
     },
     "composer": {
         "autocomplete": {
@@ -867,6 +901,8 @@
             "warning": "Om du inte har ställt in den nya återställningsmetoden kan en angripare försöka komma åt ditt konto. Byt ditt kontolösenord och ställ in en ny återställningsmetod omedelbart i inställningarna."
         },
         "not_supported": "<stöds inte>",
+        "pinned_identity_changed": "%(displayName)ss (<b>%(userId)s</b> ) identitet verkar ha ändrats.<a> Läs mer</a>",
+        "pinned_identity_changed_no_displayname": "<b>%(userId)s</b>:s identitet verkar ha ändrats. <a>Läs mer</a>",
         "recovery_method_removed": {
             "description_1": "Den här sessionen har detekterat att din säkerhetsfras och -nyckel för säkra meddelanden har tagits bort.",
             "description_2": "Om du gjorde det av misstag kan du ställa in säkra meddelanden på den här sessionen som krypterar sessionens meddelandehistorik igen med en ny återställningsmetod.",
@@ -929,6 +965,7 @@
             "qr_reciprocate_same_shield_device": "Nästan klar! Visar din andra enhet samma sköld?",
             "qr_reciprocate_same_shield_user": "Nästan klar! Visar %(displayName)s samma sköld?",
             "request_toast_accept": "Verifiera session",
+            "request_toast_accept_user": "Verifiera användare",
             "request_toast_decline_counter": "Ignorera (%(counter)s)",
             "request_toast_detail": "%(deviceId)s från %(ip)s",
             "reset_proceed_prompt": "Fortsätt återställning",
@@ -1060,7 +1097,15 @@
             "you": "Du reagerade med %(reaction)s till %(message)s"
         },
         "m.sticker": "%(senderName)s: %(stickerName)s",
-        "m.text": "%(senderName)s: %(message)s"
+        "m.text": "%(senderName)s: %(message)s",
+        "prefix": {
+            "audio": "Ljud",
+            "file": "Fil",
+            "image": "Bild",
+            "poll": "Omröstning",
+            "video": "Video"
+        },
+        "preview": "<bold>%(prefix)s: </bold> %(preview)s"
     },
     "export_chat": {
         "cancelled": "Exportering avbruten",
@@ -1183,7 +1228,19 @@
         "other": "I %(spaceName)s och %(count)s andra utrymmen."
     },
     "incompatible_browser": {
-        "title": "Webbläsaren stöds ej"
+        "continue": "Fortsätt ändå",
+        "description": "%(brand)sanvänder vissa webbläsarfunktioner som inte är tillgängliga i din nuvarande webbläsare. %(detail)s",
+        "detail_can_continue": "Om du fortsätter kan vissa funktioner sluta fungera och det finns en risk att du kan förlora data i framtiden.",
+        "detail_no_continue": "Försök uppdatera den här webbläsaren om du inte använder den senaste versionen och försök igen.",
+        "learn_more": "Läs mer",
+        "linux": "Linux",
+        "macos": "Mac",
+        "supported_browsers": "För bästa upplevelse, använd <Chrome>Chrome</Chrome>, <Firefox>Firefox</Firefox>, <Edge>Edge</Edge>, eller <Safari>Safari</Safari>.",
+        "title": "Webbläsaren stöds ej",
+        "use_desktop_heading": "Använd %(brand)s skrivbord istället",
+        "use_mobile_heading": "Använd %(brand)s på mobilen istället",
+        "use_mobile_heading_after_desktop": "Eller använd vår mobilapp",
+        "windows": "Windows (%(bits)s -bit)"
     },
     "info_tooltip_title": "Information",
     "integration_manager": {
@@ -1307,12 +1364,14 @@
         "navigate_next_message_edit": "Navigera till nästa meddelande att redigera",
         "navigate_prev_history": "Föregående nyligen besökta rum eller utrymme",
         "navigate_prev_message_edit": "Navigera till förra meddelandet att redigera",
+        "next_landmark": "Gå till nästa landmärke",
         "next_room": "Nästa rum eller DM",
         "next_unread_room": "Nästa olästa rum eller DM",
         "number": "[nummer]",
         "open_user_settings": "Öppna användarinställningar",
         "page_down": "Page Down",
         "page_up": "Page Up",
+        "prev_landmark": "Gå till föregående landmärke",
         "prev_room": "Förra rummet eller DM:en",
         "prev_unread_room": "Förra olästa rummet eller DM:en",
         "room_list_collapse_section": "Kollapsa rumslistsektionen",
@@ -1357,8 +1416,11 @@
         "dynamic_room_predecessors": "Dynamiska rumsföregångare",
         "dynamic_room_predecessors_description": "Aktivera MSC3946 (för att stöda sen-ankomna rumsarkiv)",
         "element_call_video_rooms": "Element Call videorum",
+        "exclude_insecure_devices": "Uteslut osäkra enheter när du skickar/tar emot meddelanden",
+        "exclude_insecure_devices_description": "När det här läget är aktiverat delas inte krypterade meddelanden med obekräftade enheter, och meddelanden från obekräftade enheter visas som ett fel. Observera att om du aktiverar det här läget kanske du inte kan kommunicera med användare som inte har verifierat sina enheter.",
         "experimental_description": "Känner du dig äventyrlig? Pröva våra senaste idéer under utveckling. Dessa funktioner är inte slutförda; de kan vara instabila, kan ändras, eller kan tas bort helt. <a>Läs mer</a>.",
         "experimental_section": "Tidiga förhandstittar",
+        "extended_profiles_msc_support": "Kräver att din server har stöd för MSC4133",
         "feature_disable_call_per_sender_encryption": "Inaktivera kryptering per avsändare för Element Call",
         "feature_wysiwyg_composer_description": "Använd rik text istället för Markdown i meddelanderedigeraren.",
         "group_calls": "Ny gruppsamtalsupplevelse",
@@ -1372,6 +1434,7 @@
         "group_spaces": "Utrymmen",
         "group_themes": "Teman",
         "group_threads": "Trådar",
+        "group_ui": "Användargränssnitt",
         "group_voip": "Röst & video",
         "group_widgets": "Widgets",
         "hidebold": "Dölj aviseringspunkt (visa bara räknarmärken)",
@@ -1391,8 +1454,7 @@
         "notification_settings_beta_caption": "Vi introducerar ett enklare sätt att ändra dina aviseringsinställningar. Anpassa din %(brand)s precis som du vill ha den.",
         "notification_settings_beta_title": "Aviseringsinställningar",
         "notifications": "Aktivera aviseringspanelen i rumshuvudet",
-        "oidc_native_flow": "Inbyggd OIDC-autentisering",
-        "oidc_native_flow_description": "⚠ VARNING: Experimentellt. Använd inbyggd OIDC-autentisering när den stöds av servern.",
+        "release_announcement": "Releasemeddelande",
         "render_reaction_images": "Återge anpassade bilder i reaktioner",
         "render_reaction_images_description": "Ibland kallat för ”anpassade emojis”.",
         "report_to_moderators": "Rapportera till moderatorer",
@@ -1400,7 +1462,7 @@
         "sliding_sync": "Sliding sync-läge",
         "sliding_sync_description": "Under aktiv utveckling, kan inte inaktiveras.",
         "sliding_sync_disabled_notice": "Logga ut och in igen för att inaktivera",
-        "sliding_sync_server_no_support": "Din server saknar nativt stöd",
+        "sliding_sync_server_no_support": "Din server saknar support",
         "under_active_development": "Under aktiv utveckling.",
         "unrealiable_e2e": "Otillförlitlig i krypterade rum",
         "video_rooms": "Videorum",
@@ -1452,6 +1514,8 @@
         "last_person_warning": "Du är den enda personen här. Om du lämnar så kommer ingen kunna gå med igen, inklusive du.",
         "leave_room_question": "Vill du lämna rummet '%(roomName)s'?",
         "leave_space_question": "Är du säker på att du vill lämna utrymmet '%(spaceName)s'?",
+        "room_leave_admin_warning": "Du är den enda administratören i det här rummet. Om du lämnar kommer ingen att kunna ändra rumsinställningar eller vidta andra viktiga åtgärder.",
+        "room_leave_mod_warning": "Du är den enda moderatorn i det här rummet. Om du lämnar kommer ingen att kunna ändra rumsinställningar eller vidta andra viktiga åtgärder.",
         "room_rejoin_warning": "Det här rummet är inte offentligt. Du kommer inte kunna gå med igen utan en inbjudan.",
         "space_rejoin_warning": "Det här utrymmet är inte offentligt. Du kommer inte kunna gå med igen utan en inbjudan."
     },
@@ -1511,12 +1575,11 @@
     "member_list": {
         "filter_placeholder": "Filtrera rumsmedlemmar",
         "invite_button_no_perms_tooltip": "Du är inte behörig att bjuda in användare",
-        "invited_list_heading": "Inbjuden",
         "power_label": "%(userName)s (behörighet %(powerLevelNumber)s)"
     },
     "member_list_back_action_label": "Rumsmedlemmar",
     "message_edit_dialog_title": "Meddelanderedigeringar",
-    "migrating_crypto": "Häng kvar. Vi uppdaterar Element för att göra kryptering snabbare och mer tillförlitlig.",
+    "migrating_crypto": "Häng kvar. Vi håller på att uppdatera%(brand)s för att göra kryptering snabbare och mer tillförlitlig.",
     "mobile_guide": {
         "toast_accept": "Använd app",
         "toast_description": "%(brand)s är experimentell i mobila webbläsare. För en bättre upplevelse och de senaste funktionerna använd våran nativa app.",
@@ -1558,61 +1621,15 @@
         "m.key.verification.request": "%(name)s begär verifiering"
     },
     "onboarding": {
-        "apple_trademarks": "App Store® och Apple-loggan® är varumärken som tillhör Apple Inc.",
-        "community_messaging_action": "Hitta ditt folk",
-        "community_messaging_description": "Håll ägandeskap och kontroll över gemenskapsdiskussioner.\nSkala för att stöda miljoner, med kraftfull moderering och interoperabilitet.",
-        "community_messaging_title": "Ägandeskap i gemenskap",
-        "complete_these": "Gör dessa för att få ut så mycket som möjligt av %(brand)s",
         "create_room": "Skapa en gruppchatt",
-        "download_app": "Ladda ner %(brand)s",
-        "download_app_action": "Ladda ner appar",
-        "download_app_description": "Missa inget genom att ta med dig %(brand)s",
-        "download_app_store": "Ladda ner på App Store",
-        "download_brand": "Ladda ner %(brand)s",
-        "download_brand_desktop": "Ladda ner %(brand)s skrivbord",
-        "download_f_droid": "Hämta den på F-Droid",
-        "download_google_play": "Hämta den på Google Play",
-        "enable_notifications": "Sätt på aviseringar",
-        "enable_notifications_action": "Aktivera aviseringar",
-        "enable_notifications_description": "Missa inget svar eller viktigt meddelande",
         "explore_rooms": "Utforska offentliga rum",
-        "find_community_members": "Hitta och bjud in dina gemenskapsmedlemmar",
-        "find_coworkers": "Hitta och bjud in dina medarbetare",
-        "find_friends": "Hitta och bjud in dina vänner",
-        "find_friends_action": "Hitta vänner",
-        "find_friends_description": "Det är det du är här för, så låt oss komma i gång",
-        "find_people": "Hitta folk",
-        "free_e2ee_messaging_unlimited_voip": "Med gratis totalsträckskrypterade meddelanden och obegränsade röst och videosamtal så är %(brand)s ett jättebra sätt att hålla kontakten.",
-        "get_stuff_done": "Få saker gjorda genom att hitta dina lagkamrater",
-        "google_trademarks": "Google Play och Google Play-loggan är varumärken som tillhör Google LLC.",
         "has_avatar_label": "Fantastiskt, det kommer att hjälpa folk att veta att det är du",
         "intro_byline": "Äg dina konversationer.",
         "intro_welcome": "Välkommen till %(appName)s",
         "no_avatar_label": "Lägg till en bild för att folk ska veta att det är du.",
-        "only_n_steps_to_go": {
-            "one": "Bara %(count)s steg kvar",
-            "other": "Bara %(count)s steg kvar"
-        },
-        "personal_messaging_action": "Starta din första chatt",
-        "personal_messaging_title": "Säkra meddelanden för vänner och familj",
-        "qr_or_app_links": "%(qrCode)s eller %(appLinks)s",
         "send_dm": "Skicka ett direktmeddelande",
-        "set_up_profile": "Ställ in din profil",
-        "set_up_profile_action": "Din profil",
-        "set_up_profile_description": "Se till att folk vet att det verkligen är du",
-        "use_case_community_messaging": "Online-gemenskapsmedlemmar",
-        "use_case_heading1": "Du är inne",
-        "use_case_heading2": "Vem vill du chatta med mest?",
-        "use_case_heading3": "Vi kommer att hjälpa dig få kontakt.",
-        "use_case_personal_messaging": "Vänner och familj",
-        "use_case_work_messaging": "Jobbkamrater och lag",
         "welcome_detail": "Låt oss hjälpa dig komma igång",
-        "welcome_to_brand": "Välkommen till %(brand)s",
-        "welcome_user": "Välkommen %(name)s",
-        "work_messaging_action": "Hitta dina medarbetare",
-        "work_messaging_title": "Säkra meddelanden för jobbet",
-        "you_did_it": "Du klarade det!",
-        "you_made_it": "Du klarade det!"
+        "welcome_user": "Välkommen %(name)s"
     },
     "pill": {
         "permalink_other_room": "Meddelande i rum %(room)s",
@@ -1664,7 +1681,6 @@
         "custom_level": "Anpassad nivå",
         "default": "Standard",
         "label": "Behörighetsnivå",
-        "mod": "Mod",
         "moderator": "Moderator",
         "restricted": "Begränsad"
     },
@@ -1752,14 +1768,37 @@
         "restore_failed_error": "Kunde inte återställa säkerhetskopia"
     },
     "right_panel": {
-        "add_integrations": "Lägg till widgets, bryggor och bottar",
+        "add_integrations": "Lägg till tillägg",
+        "add_topic": "Lägg till ämne",
+        "extensions_button": "Tillägg",
+        "extensions_empty_description": "Välj &quot;%(addIntegrations)s ” för att bläddra och lägga till tillägg till det här rummet",
+        "extensions_empty_title": "Öka produktiviteten med fler verktyg, widgets och botar",
         "files_button": "Filer",
         "pinned_messages": {
+            "empty_description": "Välj ett meddelande och välj ”%(pinAction)s” för att inkludera det här.",
+            "empty_title": "Fäst viktiga meddelanden så att de lätt kan upptäckas",
+            "header": {
+                "one": "1 Fäst meddelande",
+                "other": "%(count)sFästa meddelanden"
+            },
             "limits": {
                 "other": "Du kan bara fästa upp till %(count)s widgets"
-            }
+            },
+            "menu": "Öppna menyn",
+            "release_announcement": {
+                "close": "OK",
+                "description": "Du hittar alla fästa meddelanden här. För muspekaren över ett meddelande och välj \"Fäst\" för att lägga till det.",
+                "title": "Alla nya fästa meddelanden"
+            },
+            "reply_thread": "Svara på ett <link> trådmeddelande </link>",
+            "unpin_all": {
+                "button": "Lossa alla meddelanden",
+                "content": "Se till att du verkligen vill ta bort alla fästa meddelanden. Den här åtgärden kan inte ångras.",
+                "title": "Lossa alla meddelanden?"
+            },
+            "view": "Visa i tidslinjen"
         },
-        "pinned_messages_button": "Fäst",
+        "pinned_messages_button": "Fästa meddelanden",
         "poll": {
             "active_heading": "Aktiva omröstningar",
             "empty_active": "Det finns inga aktiva omröstningar i det här rummet",
@@ -1784,7 +1823,7 @@
             "view_in_timeline": "Se omröstningen i tidslinjen",
             "view_poll": "Visa omröstning"
         },
-        "polls_button": "Omröstningshistorik",
+        "polls_button": "Omröstningar",
         "room_summary_card": {
             "title": "Rumsinfo"
         },
@@ -1813,6 +1852,7 @@
             "forget": "Glöm rum",
             "low_priority": "Låg prioritet",
             "mark_read": "Markera som läst",
+            "mark_unread": "Markera som oläst",
             "notifications_default": "Matcha förvalsinställning",
             "notifications_mute": "Tysta rum",
             "title": "Rumsinställningar",
@@ -1861,7 +1901,8 @@
             },
             "room_is_public": "Det här rummet är offentligt"
         },
-        "header_face_pile_tooltip": "Växla medlemslista",
+        "header_avatar_open_settings_label": "Öppna rumsinställningar",
+        "header_face_pile_tooltip": "Människor",
         "header_untrusted_label": "Ej betrodd",
         "inaccessible": "Det är rummet eller utrymmet är inte åtkomligt för tillfället.",
         "inaccessible_name": "%(roomName)s är inte tillgängligt för tillfället.",
@@ -1888,7 +1929,7 @@
         "invite_reject_ignore": "Avvisa och ignorera användare",
         "invite_sent_to_email": "Denna inbjudan skickades till %(email)s",
         "invite_sent_to_email_room": "Denna inbjudan till %(roomName)s skickades till %(email)s",
-        "invite_subtitle": "<userName/> bjöd in dig",
+        "invite_subtitle": "Inbjuden av <userName/>",
         "invite_this_room": "Bjud in till rummet",
         "invite_title": "Vill du gå med i %(roomName)s?",
         "inviter_unknown": "Okänt",
@@ -1931,11 +1972,24 @@
         "not_found_title": "Det här rummet eller utrymmet finns inte.",
         "not_found_title_name": "%(roomName)s finns inte.",
         "peek_join_prompt": "Du förhandsgranskar %(roomName)s. Vill du gå med i det?",
+        "pinned_message_badge": "Fäst meddelande",
+        "pinned_message_banner": {
+            "button_close_list": "Stäng listan",
+            "button_view_all": "Visa alla",
+            "description": "Det här rummet har fästa meddelanden. Klicka för att se dem.",
+            "go_to_message": "Visa det fästa meddelandet på tidslinjen.",
+            "title": "<bold>%(index)s av %(length)s</bold> fästa meddelanden"
+        },
         "read_topic": "Klicka för att läsa ämne",
         "rejecting": "Nekar inbjudan …",
         "rejoin_button": "Gå med igen",
         "search": {
             "all_rooms_button": "Sök i alla rum",
+            "placeholder": "Sök meddelanden...",
+            "summary": {
+                "one": "1 resultat hittades för ”<query/>”",
+                "other": "%(count)sResultat hittades för ”<query/>”"
+            },
             "this_room_button": "Sök i det här rummet"
         },
         "status_bar": {
@@ -2071,6 +2125,8 @@
             "error_deleting_alias_description": "Ett fel inträffade vid borttagning av adressen. Den kanske inte längre existerar, eller så inträffade ett tillfälligt fel.",
             "error_deleting_alias_description_forbidden": "Du har inte behörighet att radera den där adressen.",
             "error_deleting_alias_title": "Fel vi borttagning av adress",
+            "error_publishing": "Det gick inte att publicera rummet",
+            "error_publishing_detail": "Det uppstod ett fel när det här rummet skulle publiceras",
             "error_save_space_settings": "Misslyckades att spara utrymmesinställningar.",
             "error_updating_alias_description": "Ett fel inträffade vid uppdatering av rummets alternativa adresser. Det kanske inte tillåts av servern, eller så inträffade ett tillfälligt fel.",
             "error_updating_canonical_alias_description": "Ett fel inträffade vid uppdatering av rummets huvudadress. Det kanske inte tillåts av servern, eller så inträffade ett tillfälligt fel.",
@@ -2297,6 +2353,7 @@
             "brand_version": "%(brand)s-version:",
             "clear_cache_reload": "Rensa cache och ladda om",
             "crypto_version": "Kryptoversion:",
+            "dialog_title": "<strong>Inställningar: </strong> Hjälp & Om",
             "help_link": "För hjälp med att använda %(brand)s, klicka <a>här</a>.",
             "homeserver": "Hemservern är <code>%(homeserverUrl)s</code>",
             "identity_server": "Identitetsservern är <code>%(identityServerUrl)s</code>",
@@ -2305,18 +2362,30 @@
         }
     },
     "settings": {
+        "account": {
+            "dialog_title": "<strong>Inställningar: </strong> Konto",
+            "title": "Konto"
+        },
         "all_rooms_home": "Visa alla rum i Hem",
         "all_rooms_home_description": "Alla rum du är in kommer att visas i Hem.",
         "always_show_message_timestamps": "Visa alltid tidsstämplar för meddelanden",
         "appearance": {
             "bundled_emoji_font": "Använd medföljande emoji-teckensnitt",
+            "compact_layout": "Visa kompakta texter och meddelanden",
+            "compact_layout_description": "Modern layout måste väljas för att använda den här funktionen.",
             "custom_font": "Använd systemets teckensnitt",
             "custom_font_description": "Sätt namnet för ett teckensnitt installerat på ditt system så kommer %(brand)s att försöka använda det.",
             "custom_font_name": "Namn på systemets teckensnitt",
             "custom_font_size": "Använd anpassad storlek",
-            "custom_theme_error_downloading": "Fel vid nedladdning av temainformation.",
+            "custom_theme_add": "Lägg till anpassat tema",
+            "custom_theme_downloading": "Laddar ned anpassat tema...",
+            "custom_theme_error_downloading": "Fel vid nedladdning av tema",
+            "custom_theme_help": "Ange webbadressen till ett anpassat tema som du vill använda.",
             "custom_theme_invalid": "Ogiltigt temaschema.",
+            "dialog_title": "<strong>Inställningar:</strong> Utseende",
             "font_size": "Teckenstorlek",
+            "font_size_default": "%(fontSize)s(standard)",
+            "high_contrast": "Hög kontrast",
             "image_size_default": "Standard",
             "image_size_large": "Stor",
             "layout_bubbles": "Meddelandebubblor",
@@ -2331,6 +2400,9 @@
         "code_block_expand_default": "Expandera kodblock för förval",
         "code_block_line_numbers": "Visa radnummer i kodblock",
         "disable_historical_profile": "Visa nuvarande profilbild och namn för användare i meddelandehistoriken",
+        "discovery": {
+            "title": "Hur man hittar dig"
+        },
         "emoji_autocomplete": "Aktivera emojiförslag medan du skriver",
         "enable_markdown": "Aktivera Markdown",
         "enable_markdown_description": "Börja meddelanden med <code>/plain</code> för att skicka utan markdown.",
@@ -2346,6 +2418,14 @@
             "add_msisdn_dialog_title": "Lägg till telefonnummer",
             "add_msisdn_instructions": "Ett SMS har skickats till +%(msisdn)s. Ange verifieringskoden som det innehåller.",
             "add_msisdn_misconfigured": "Flöde för tilläggning/bindning med MSISDN är felkonfigurerat",
+            "allow_spellcheck": "Tillåt stavningskontroll",
+            "application_language": "Språk för ansökan",
+            "application_language_reload_hint": "Appen laddas om efter att ha valt ett annat språk",
+            "avatar_remove_progress": "Tar bort bild...",
+            "avatar_save_progress": "Laddar upp bild...",
+            "avatar_upload_error_text": "Filformatet stöds inte eller bilden är större än%(size)s.",
+            "avatar_upload_error_text_generic": "Filformatet kanske inte stöds.",
+            "avatar_upload_error_title": "Det gick inte att ladda upp avatarbilden",
             "confirm_adding_email_body": "Klicka på knappen nedan för att bekräfta tilläggning av e-postadressen.",
             "confirm_adding_email_title": "Bekräfta tilläggning av e-postadressen",
             "deactivate_confirm_body": "Är du säker på att du vill inaktivera ditt konto? Detta är oåterkalleligt.",
@@ -2361,10 +2441,13 @@
             "deactivate_confirm_erase_label": "Dölj mina meddelanden för nya som går med",
             "deactivate_section": "Inaktivera konto",
             "deactivate_warning": "Avaktivering av ditt konto är en permanent handling — var försiktig!",
-            "discovery_email_empty": "Upptäcktsalternativ kommer att visas när du har lagt till en e-postadress ovan.",
+            "discovery_email_empty": "När du har lagt till en e-postadress visas alternativ för att upptäcka den.",
             "discovery_email_verification_instructions": "Verifiera länken i din inkorg",
-            "discovery_msisdn_empty": "Upptäcktsalternativ kommer att visas när du har lagt till ett telefonnummer ovan.",
+            "discovery_msisdn_empty": "När du har lagt till ett telefonnummer visas alternativ för att upptäcka det.",
             "discovery_needs_terms": "Samtyck till identitetsserverns (%(serverName)s) användarvillkor för att låta dig själv vara upptäckbar med e-postadress eller telefonnummer.",
+            "discovery_needs_terms_title": "Låt andra hitta dig",
+            "display_name": "Visningsnamn",
+            "display_name_error": "Det gick inte att ställa in visningsnamn",
             "email_address_in_use": "Den här e-postadressen används redan",
             "email_address_label": "E-postadress",
             "email_not_verified": "Din e-postadress har inte verifierats än",
@@ -2389,7 +2472,7 @@
             "error_share_msisdn_discovery": "Kunde inte dela telefonnummer",
             "identity_server_no_token": "Ingen identitetsåtkomsttoken hittades",
             "identity_server_not_set": "Identitetsserver inte inställd",
-            "language_section": "Språk och region",
+            "language_section": "Språk",
             "msisdn_in_use": "Detta telefonnummer används redan",
             "msisdn_label": "Telefonnummer",
             "msisdn_verification_field_label": "Verifieringskod",
@@ -2398,9 +2481,15 @@
             "oidc_manage_button": "Hantera konto",
             "password_change_section": "Sätt ett nytt kontolösenord …",
             "password_change_success": "Ditt lösenord byttes framgångsrikt.",
+            "personal_info": "Personlig information",
+            "profile_subtitle": "Så här visas du för andra i appen.",
+            "profile_subtitle_oidc": "Ditt konto hanteras separat av en identitetsleverantör och därför kan vissa av dina personuppgifter inte ändras här.",
             "remove_email_prompt": "Ta bort %(email)s?",
             "remove_msisdn_prompt": "Ta bort %(phone)s?",
-            "spell_check_locale_placeholder": "Välj en lokalisering"
+            "spell_check_locale_placeholder": "Välj en lokalisering",
+            "unable_to_load_emails": "Det gick inte att ladda e-postadresser",
+            "unable_to_load_msisdns": "Det går inte att läsa in telefonnummer",
+            "username": "Användarnamn"
         },
         "image_thumbnails": "Visa förhandsgranskning/miniatyr för bilder",
         "inline_url_previews_default": "Aktivera inbäddad URL-förhandsgranskning som standard",
@@ -2456,12 +2545,20 @@
             "phrase_strong_enough": "Bra! Den här lösenfrasen ser tillräckligt stark ut"
         },
         "keyboard": {
+            "dialog_title": "<strong>Inställningar: </strong> Tangentbord",
             "title": "Tangentbord"
         },
+        "labs": {
+            "dialog_title": "<strong>Inställningar: </strong> Labs"
+        },
+        "labs_mjolnir": {
+            "dialog_title": "<strong>Inställningar:</strong> Ignorerade användare"
+        },
         "notifications": {
             "default_setting_description": "Denna inställning kommer att tillämpas som standard för alla dina rum.",
             "default_setting_section": "Jag vill bli meddelad för (Standardinställning)",
             "desktop_notification_message_preview": "Visa förhandsgranskning av meddelanden i skrivbordsmeddelanden",
+            "dialog_title": "<strong>Inställningar:</strong> Aviseringar",
             "email_description": "Få en sammanfattning av missade aviseringar via e-post",
             "email_section": "E-postsammanfattning",
             "email_select": "Välj vilka e-postadresser du vill skicka sammanfattningar till. Hantera dina e-postadresser i <button>Allmänt</button>.",
@@ -2520,21 +2617,24 @@
             "code_blocks_heading": "Kodblock",
             "compact_modern": "Använd ett mer kompakt 'modernt' arrangemang",
             "composer_heading": "Meddelandefält",
+            "default_timezone": "Webbläsarens standard (%(timezone)s)",
+            "dialog_title": "<strong>Inställningar:</strong> Alternativ",
             "enable_hardware_acceleration": "Aktivera hårdvaruaccelerering",
             "enable_tray_icon": "Visa ikon i systembrickan och minimera programmet till den när fönstret stängs",
             "keyboard_heading": "Tangentbordsgenvägar",
             "keyboard_view_shortcuts_button": "För att se alla tangentbordsgenvägar, <a>klicka här</a>.",
             "media_heading": "Bilder, GIF:ar och videor",
             "presence_description": "Dela din aktivitet och status med andra.",
+            "publish_timezone": "Publicera tidszon på offentlig profil",
             "rm_lifetime": "Läsmarkörens livstid (ms)",
             "rm_lifetime_offscreen": "Läsmarkörens livstid utanför skärmen (ms)",
             "room_directory_heading": "Rumskatalog",
             "room_list_heading": "Rumslista",
             "show_avatars_pills": "Visa avatarer i användar-, rums- och händelseomnämnanden",
-            "show_checklist_shortcuts": "Visa genväg till välkomstchecklistan ovanför rumslistan",
             "show_polls_button": "Visa omröstningsknapp",
             "surround_text": "Inneslut valt text vid skrivning av specialtecken",
-            "time_heading": "Tidvisning"
+            "time_heading": "Tidvisning",
+            "user_timezone": "Ange tidszon"
         },
         "prompt_invite": "Fråga innan inbjudningar skickas till potentiellt ogiltiga Matrix-ID:n",
         "replace_plain_emoji": "Ersätt automatiskt textemotikoner med emojier",
@@ -2565,8 +2665,11 @@
             "cross_signing_self_signing_private_key": "Privat nyckel för självsignering:",
             "cross_signing_user_signing_private_key": "Privat nyckel för användarsignering:",
             "cryptography_section": "Kryptografi",
+            "dehydrated_device_description": "Funktionen offlineenhet låter dig ta emot krypterade meddelanden även när du inte är inloggad på någon enhet",
+            "dehydrated_device_enabled": "Offlineenhet aktiverad",
             "delete_backup": "Radera säkerhetskopia",
             "delete_backup_confirm_description": "Är du säker? Du kommer att förlora dina krypterade meddelanden om dina nycklar inte säkerhetskopieras ordentligt.",
+            "dialog_title": "<strong>Inställningar:</strong> Säkerhet och integritet",
             "e2ee_default_disabled_warning": "Din serveradministratör har inaktiverat totalsträckskryptering som förval för privata rum och direktmeddelanden.",
             "enable_message_search": "Aktivera meddelandesökning i krypterade rum",
             "encryption_section": "Kryptering",
@@ -2644,6 +2747,7 @@
             "device_unverified_description_current": "Verifiera din nuvarande session för förbättrade säkra meddelanden.",
             "device_verified_description": "Den här sessionen är redo för säkra meddelanden.",
             "device_verified_description_current": "Din nuvarande session är redo för säkra meddelanden.",
+            "dialog_title": "<strong>Inställningar: </strong> Sessioner",
             "error_pusher_state": "Misslyckades att sätta pusharläge",
             "error_set_name": "Misslyckades att ange sessionsnamn",
             "filter_all": "Alla",
@@ -2683,9 +2787,10 @@
             "security_recommendations_description": "Förbättra din kontosäkerhet genom att följa dessa rekommendationer.",
             "session_id": "Sessions-ID",
             "show_details": "Visa detaljer",
-            "sign_in_with_qr": "Logga in med QR-kod",
+            "sign_in_with_qr": "Länka ny enhet",
             "sign_in_with_qr_button": "Visa QR-kod",
-            "sign_in_with_qr_description": "Du kan använda den här enheten för att logga in en ny enhet med en QR-kod. Du kommer behöva skanna QR-koden som visas på den här enheten med din enhet som är utloggad.",
+            "sign_in_with_qr_description": "Använd en QR-kod för att logga in på en annan enhet och konfigurera säkra meddelanden.",
+            "sign_in_with_qr_unsupported": "Stöds inte av din kontoleverantör",
             "sign_out": "Logga ut den här sessionen",
             "sign_out_all_other_sessions": "Logga ut ur alla andra sessioner (%(otherSessionsCount)s)",
             "sign_out_confirm_description": {
@@ -2725,7 +2830,9 @@
         "show_redaction_placeholder": "Visa en platshållare för borttagna meddelanden",
         "show_stickers_button": "Visa dekalknapp",
         "show_typing_notifications": "Visa \"skriver\"-statusar",
+        "showbold": "Visa all aktivitet i rumslistan (prickar eller antal olästa meddelanden)",
         "sidebar": {
+            "dialog_title": "<strong>Inställningar:</strong> Sidofält",
             "metaspaces_favourites_description": "Gruppera alla dina favoritrum och -personer på ett ställe.",
             "metaspaces_home_all_rooms": "Visa alla rum",
             "metaspaces_home_all_rooms_description": "Visa alla dina rum i Hem, även om de är i ett utrymme.",
@@ -2734,10 +2841,14 @@
             "metaspaces_orphans_description": "Gruppera alla dina rum som inte är en del av ett utrymme på ett ställe.",
             "metaspaces_people_description": "Gruppera alla dina personer på ett ställe.",
             "metaspaces_subsection": "Utrymmen att visa",
+            "metaspaces_video_rooms": "Videorum och konferenser",
+            "metaspaces_video_rooms_description": "Gruppera alla privata videorum och konferenser.",
+            "metaspaces_video_rooms_description_invite_extension": "I konferenser kan du bjuda in personer utanför Matrix.",
             "spaces_explainer": "Utrymmen är sätt att gruppera rum och personer. Vid sidan av de utrymmen du befinner dig i kan du också använda några förbyggda.",
             "title": "Sidofält"
         },
         "start_automatically": "Starta automatiskt vid systeminloggning",
+        "tac_only_notifications": "Visa endast notiser i aktivitetscentret för trådar",
         "use_12_hour_format": "Visa tidsstämplar i 12-timmarsformat (t.ex. 2:30em)",
         "use_command_enter_send_message": "Använd Kommando + Enter för att skicka ett meddelande",
         "use_command_f_search": "Använd Kommando + F för att söka på tidslinjen",
@@ -2751,6 +2862,7 @@
             "audio_output_empty": "Inga ljudutgångar hittades",
             "auto_gain_control": "Automatisk förstärkningskontroll",
             "connection_section": "Anslutning",
+            "dialog_title": "<strong>Inställningar: </strong> Röst och video",
             "echo_cancellation": "Ekoreducering",
             "enable_fallback_ice_server": "Tillåt reservserver för samtalsassistans (%(server)s)",
             "enable_fallback_ice_server_description": "Gäller endast om din hemserver inte erbjuder en. Din IP-adress delas under samtal.",
@@ -2769,8 +2881,12 @@
         "warning": "<w>VARNING:</w> <description/>"
     },
     "share": {
+        "link_copied": "Länken kopierad",
         "permalink_message": "Länk till valt meddelande",
         "permalink_most_recent": "Länk till senaste meddelandet",
+        "share_call": "Länk till konferensinbjudan",
+        "share_call_subtitle": "Länk för externa användare att gå med i samtalet utan ett Matrixkonto:",
+        "title_link": "Dela länk",
         "title_message": "Dela rumsmeddelande",
         "title_room": "Dela rum",
         "title_user": "Dela användare"
@@ -2893,7 +3009,6 @@
         "invite": "Bjud in folk",
         "invite_description": "Bjud in med e-postadress eller användarnamn",
         "invite_link": "Skapa inbjudningslänk",
-        "invite_this_space": "Bjud in till det här utrymmet",
         "joining_space": "Går med",
         "landing_welcome": "Välkommen till <name/>",
         "leave_dialog_action": "Lämna utrymmet",
@@ -3012,14 +3127,21 @@
             "one": "%(count)s svar",
             "other": "%(count)s svar"
         },
+        "empty_description": "Använd ”%(replyInThread)s” när du håller muspekaren över ett meddelande.",
+        "empty_title": "Trådar underlättar för att hålla konversationer till ämnet och gör dem lättare att följa.",
         "error_start_thread_existing_relation": "Kan inte skapa tråd från en händelse med en existerande relation",
+        "mark_all_read": "Markera allt som läst",
         "my_threads": "Mina trådar",
         "my_threads_description": "Visar alla trådar du har medverkat i",
         "open_thread": "Öppna tråd",
         "show_thread_filter": "Visa:"
     },
     "threads_activity_centre": {
-        "header": "Aktivitet för trådar"
+        "header": "Aktivitet för trådar",
+        "no_rooms_with_threads_notifs": "Du har inga rum med trådaviseringar ännu.",
+        "no_rooms_with_unread_threads": "Du har inga rum med olästa trådar än.",
+        "release_announcement_description": "Meddelanden om trådar har flyttats, du hittar dem här från och med nu.",
+        "release_announcement_header": "Aktivitetscenter för Trådar"
     },
     "time": {
         "about_day_ago": "cirka en dag sedan",
@@ -3062,9 +3184,21 @@
         },
         "creation_summary_dm": "%(creator)s skapade den här DM:en.",
         "creation_summary_room": "%(creator)s skapade och konfigurerade rummet.",
+        "decryption_failure": {
+            "blocked": "Avsändaren har blockerat dig från att ta emot det här meddelandet eftersom din enhet inte är verifierad",
+            "historical_event_no_key_backup": "Historiska meddelanden är inte tillgängliga på den här enheten",
+            "historical_event_unverified_device": "Du måste verifiera den här enheten för att få åtkomst till historiska meddelanden",
+            "historical_event_user_not_joined": "Du har inte tillgång till det här meddelandet",
+            "sender_identity_previously_verified": "Avsändarens verifierade identitet har ändrats",
+            "sender_unsigned_device": "Skickat från en osäker enhet.",
+            "unable_to_decrypt": "Det gick inte att dekryptera meddelandet"
+        },
         "disambiguated_profile": "%(displayName)s (%(matrixId)s)",
         "download_action_decrypting": "Avkrypterar",
         "download_action_downloading": "Laddar ner",
+        "download_failed": "Nedladdning misslyckades",
+        "download_failed_description": "Ett fel uppstod när den här filen laddades ned",
+        "e2e_state": "Tillståndet för end-to-end-krypteringen",
         "edits": {
             "tooltip_label": "Redigerat vid %(date)s. Klicka för att visa redigeringar.",
             "tooltip_sub": "Klicka för att visa redigeringar",
@@ -3118,7 +3252,7 @@
         },
         "m.file": {
             "error_decrypting": "Fel vid avkryptering av bilagan",
-            "error_invalid": "Felaktig fil%(extra)s"
+            "error_invalid": "Ogiltig fil"
         },
         "m.image": {
             "error": "Kunde inte visa bild på grund av fel",
@@ -3305,7 +3439,8 @@
         "reactions": {
             "add_reaction_prompt": "Lägg till reaktion",
             "custom_reaction_fallback_label": "Anpassad reaktion",
-            "label": "%(reactors)s reagerade med %(content)s"
+            "label": "%(reactors)s reagerade med %(content)s",
+            "tooltip_caption": "reagerade med %(shortName)s"
         },
         "read_receipt_title": {
             "one": "Sedd av %(count)s person",
@@ -3490,6 +3625,10 @@
     "truncated_list_n_more": {
         "other": "Och %(count)s till…"
     },
+    "unsupported_browser": {
+        "description": "Om du fortsätter kan vissa funktioner sluta fungera och det finns en risk att du kan förlora data i framtiden. Uppdatera din webbläsare för att fortsätta använda%(brand)s.",
+        "title": "%(brand)sstöder inte den här webbläsaren"
+    },
     "unsupported_server_description": "Servern använder en äldre version av Matrix. Uppgradera till Matrix %(version)s för att använda %(brand)s utan fel.",
     "unsupported_server_title": "Din server stöds inte",
     "update": {
@@ -3507,6 +3646,12 @@
         "toast_title": "Uppdatera %(brand)s",
         "unavailable": "Otillgänglig"
     },
+    "update_room_access_modal": {
+        "description": "För att skapa en delningslänk måste du tillåta gäster att gå med i det här rummet. Detta kan göra rummet mindre säkert. När du är klar med samtalet kan du göra rummet privat igen.",
+        "dont_change_description": "Alternativt kan du hålla samtalet i ett separat rum.",
+        "no_change": "Jag vill inte ändra åtkomstnivån.",
+        "title": "Ändra åtkomstnivå för rummet"
+    },
     "upload_failed_generic": "Filen '%(fileName)s' kunde inte laddas upp.",
     "upload_failed_size": "Filen '%(fileName)s' överstiger denna hemserverns storleksgräns för uppladdningar",
     "upload_failed_title": "Uppladdning misslyckades",
@@ -3516,6 +3661,7 @@
         "error_files_too_large": "Dessa filer är <b>för stora</b> för att laddas upp. Filstorleksgränsen är %(limit)s.",
         "error_some_files_too_large": "Vissa filer är <b>för stora</b> för att laddas upp. Filstorleksgränsen är %(limit)s.",
         "error_title": "Uppladdningsfel",
+        "not_image": "Filen du har valt är inte en giltig bildfil.",
         "title": "Ladda upp filer",
         "title_progress": "Ladda upp filer (%(current)s av %(total)s)",
         "upload_all_button": "Ladda upp alla",
@@ -3542,6 +3688,7 @@
         "deactivate_confirm_action": "Inaktivera användaren",
         "deactivate_confirm_description": "Vid inaktivering av användare loggas den ut och förhindras från att logga in igen. Den kommer dessutom att lämna alla rum den befinner sig i. Den här åtgärden kan inte ångras. Är du säker på att du vill inaktivera den här användaren?",
         "deactivate_confirm_title": "Inaktivera användare?",
+        "dehydrated_device_enabled": "Offlineenhet aktiverad",
         "demote_button": "Degradera",
         "demote_self_confirm_description_space": "Du kommer inte kunna ångra den här ändringen eftersom du degraderar dig själv, och om du är den sista privilegierade användaren i utrymmet så kommer det att vara omöjligt att återfå utrymmet.",
         "demote_self_confirm_room": "Du kommer inte att kunna ångra den här ändringen eftersom du degraderar dig själv. Om du är den sista privilegierade användaren i rummet blir det omöjligt att återfå behörigheter.",
@@ -3558,6 +3705,7 @@
         "error_revoke_3pid_invite_title": "Misslyckades att återkalla inbjudan",
         "hide_sessions": "Dölj sessioner",
         "hide_verified_sessions": "Dölj verifierade sessioner",
+        "ignore_button": "Ignorera",
         "ignore_confirm_description": "Alla meddelanden och inbjudningar från den här användaren kommer att döljas. Är du säker på att du vill ignorera denne?",
         "ignore_confirm_title": "Ignorera %(user)s",
         "invited_by": "Inbjuden av %(sender)s",
@@ -3585,23 +3733,26 @@
             "no_recent_messages_description": "Pröva att skrolla upp i tidslinjen för att se om det finns några tidigare.",
             "no_recent_messages_title": "Inga nyliga meddelanden från %(user)s hittades"
         },
-        "redact_button": "Ta bort nyliga meddelanden",
+        "redact_button": "Ta bort meddelanden",
         "revoke_invite": "Återkalla inbjudan",
         "room_encrypted": "Meddelanden i det här rummet är totalsträckskrypterade.",
         "room_encrypted_detail": "Dina meddelanden är säkrade och endast du och mottagaren har de unika nycklarna för att låsa upp dem.",
         "room_unencrypted": "Meddelanden i detta rum är inte totalsträckskrypterade.",
         "room_unencrypted_detail": "I krypterade rum är dina meddelanden säkrade och endast du och mottagaren har de unika nycklarna för att låsa upp dem.",
-        "share_button": "Dela länk till användare",
+        "send_message": "Skicka meddelande",
+        "share_button": "Dela profil",
         "unban_button_room": "Avbanna i rum",
         "unban_button_space": "Avbanna i utrymme",
         "unban_room_confirm_title": "Avbanna från %(roomName)s",
         "unban_space_everything": "Avbanna dem från allt jag kan",
         "unban_space_specific": "Avbanna dem från specifika saker jag kan",
         "unban_space_warning": "Personen kommer inte kunna komma åt saker du inte är admin för.",
+        "unignore_button": "Avignorera",
         "verify_button": "Verifiera användare",
         "verify_explainer": "För extra säkerhet, verifiera den här användaren genom att kolla en engångskod på båda era enheter."
     },
     "user_menu": {
+        "link_new_device": "Länka ny enhet",
         "settings": "Alla inställningar",
         "switch_theme_dark": "Byt till mörkt läge",
         "switch_theme_light": "Byt till ljust läge"
@@ -3643,15 +3794,19 @@
         "enable_camera": "Sätt på kamera",
         "enable_microphone": "Slå på mikrofonen",
         "expand": "Återgå till samtal",
+        "get_call_link": "Dela samtalslänk",
         "hangup": "Lägg på",
         "hide_sidebar_button": "Göm sidopanel",
         "input_devices": "Ingångsenheter",
         "jitsi_call": "Jitsi-gruppsamtal",
         "join_button_tooltip_call_full": "Tyvärr - det här samtalet är för närvarande fullt",
         "join_button_tooltip_connecting": "Ansluter",
-        "legacy_call": "Gammal samtalsfunktion",
+        "legacy_call": "Standardsamtal",
         "maximise": "Fyll skärmen",
         "maximise_call": "Maximera samtal",
+        "metaspace_video_rooms": {
+            "conference_room_section": "Konferenser"
+        },
         "minimise_call": "Minimera samtal",
         "misconfigured_server": "Anrop misslyckades på grund av felkonfigurerad server",
         "misconfigured_server_description": "Be administratören för din hemserver (<code>%(homeserverDomain)s</code>) att konfigurera en TURN-server för att samtal ska fungera pålitligt.",
@@ -3809,7 +3964,7 @@
             "title": "Tillåt att den här widgeten verifierar din identitet"
         },
         "popout": "Poppa ut widget",
-        "set_room_layout": "Sätt mitt rumsarrangemang för alla",
+        "set_room_layout": "Ställ in layout för alla",
         "shared_data_avatar": "URL för din profilbild",
         "shared_data_device_id": "Ditt enhets-ID",
         "shared_data_lang": "Ditt språk",
diff --git a/src/i18n/strings/uk.json b/src/i18n/strings/uk.json
index 8af8d0b2ea2..7522d01e559 100644
--- a/src/i18n/strings/uk.json
+++ b/src/i18n/strings/uk.json
@@ -448,7 +448,6 @@
         "identity_server": "Сервер ідентифікації",
         "image": "Зображення",
         "integration_manager": "Менеджер інтеграцій",
-        "ios": "iOS",
         "joined": "Приєднано",
         "labs": "Лабораторія",
         "legal": "Правові положення",
@@ -536,8 +535,7 @@
         "video": "Відео",
         "video_room": "Відеокімната",
         "view_message": "Переглянути повідомлення",
-        "warning": "Попередження",
-        "welcome": "Вітаємо"
+        "warning": "Попередження"
     },
     "composer": {
         "autocomplete": {
@@ -1349,7 +1347,6 @@
         "msc3531_hide_messages_pending_moderation": "Дозволити модераторам ховати повідомлення у черзі модерування.",
         "notification_settings": "Нові налаштування сповіщень",
         "notification_settings_beta_title": "Налаштування сповіщень",
-        "oidc_native_flow": "Увімкнути нові вбудовані потоки OIDC (в активній розробці)",
         "report_to_moderators": "Поскаржитись модераторам",
         "report_to_moderators_description": "У кімнатах, які підтримують модерацію, кнопка «Поскаржитися» дає змогу повідомити про зловживання модераторам кімнати.",
         "sliding_sync": "Режим ковзної синхронізації",
@@ -1464,7 +1461,6 @@
     "member_list": {
         "filter_placeholder": "Відфільтрувати учасників кімнати",
         "invite_button_no_perms_tooltip": "У вас немає дозволу запрошувати користувачів",
-        "invited_list_heading": "Запрошено",
         "power_label": "%(userName)s (повноваження %(powerLevelNumber)s)"
     },
     "member_list_back_action_label": "Учасники кімнати",
@@ -1506,61 +1502,15 @@
         "m.key.verification.request": "%(name)s робить запит на звірення"
     },
     "onboarding": {
-        "apple_trademarks": "App Store® і логотип Apple® є товарними знаками Apple Inc.",
-        "community_messaging_action": "Знайдіть своїх людей",
-        "community_messaging_description": "Зберігайте право власності та контроль над обговоренням спільноти.\nМасштабуйте для підтримки мільйонів завдяки потужній модерації та сумісності.",
-        "community_messaging_title": "Громадська власність",
-        "complete_these": "Виконайте їх, щоб отримати максимальну віддачу від %(brand)s",
         "create_room": "Створити групову бесіду",
-        "download_app": "Завантажити %(brand)s",
-        "download_app_action": "Завантажуйте застосунки",
-        "download_app_description": "Не пропускайте нічого, взявши з собою %(brand)s",
-        "download_app_store": "Завантажити з App Store",
-        "download_brand": "Завантажити %(brand)s",
-        "download_brand_desktop": "Завантажити %(brand)s для компʼютера",
-        "download_f_droid": "Отримати з F-Droid",
-        "download_google_play": "Отримати з Google Play",
-        "enable_notifications": "Увімкніть сповіщення",
-        "enable_notifications_action": "Увімкнути сповіщення",
-        "enable_notifications_description": "Не пропустіть відповідь або важливе повідомлення",
         "explore_rooms": "Переглянути загальнодоступні кімнати",
-        "find_community_members": "Знайдіть і запросіть учасників своєї спільноти",
-        "find_coworkers": "Знайдіть і запросіть своїх колег",
-        "find_friends": "Знайдіть і запросіть своїх друзів",
-        "find_friends_action": "Знайдіть друзів",
-        "find_friends_description": "Це те, заради чого ви тут, тож перейдемо до цього",
-        "find_people": "Шукайте людей",
-        "free_e2ee_messaging_unlimited_voip": "Завдяки безплатному обміну повідомленнями з наскрізним шифруванням і необмеженим голосовим і відеовикликами, %(brand)s — це чудовий спосіб залишатися на зв’язку.",
-        "get_stuff_done": "Виконуйте завдання, знаходячи своїх товаришів по команді",
-        "google_trademarks": "Google Play і логотип Google Play є товарними знаками Google LLC.",
         "has_avatar_label": "Чудово, це допоможе людям дізнатися, що це ви",
         "intro_byline": "Володійте своїми розмовами.",
         "intro_welcome": "Вітаємо в %(appName)s",
         "no_avatar_label": "Додайте світлину, щоб люди могли вас розпізнавати.",
-        "only_n_steps_to_go": {
-            "one": "Лише %(count)s крок для налаштування",
-            "other": "Лише %(count)s кроків для налаштування"
-        },
-        "personal_messaging_action": "Розпочніть свою першу бесіду",
-        "personal_messaging_title": "Безпечний обмін повідомленнями з друзями та родиною",
-        "qr_or_app_links": "%(qrCode)s або %(appLinks)s",
         "send_dm": "Надіслати особисте повідомлення",
-        "set_up_profile": "Налаштуйте свій профіль",
-        "set_up_profile_action": "Ваш профіль",
-        "set_up_profile_description": "Переконайтеся, що люди знають, що це справді ви",
-        "use_case_community_messaging": "Учасники онлайн-спільноти",
-        "use_case_heading1": "Ви увійшли",
-        "use_case_heading2": "З ким ви спілкуватиметеся найбільше?",
-        "use_case_heading3": "Ми допоможемо вам з'єднатися.",
-        "use_case_personal_messaging": "Друзі та родина",
-        "use_case_work_messaging": "Співробітники та команди",
         "welcome_detail": "Тепер допоможімо вам почати",
-        "welcome_to_brand": "Вітаємо в %(brand)s",
-        "welcome_user": "Вітаємо, %(name)s",
-        "work_messaging_action": "Знайдіть своїх колег",
-        "work_messaging_title": "Безпечний обмін повідомленнями для роботи",
-        "you_did_it": "Ви це зробили!",
-        "you_made_it": "Ви це зробили!"
+        "welcome_user": "Вітаємо, %(name)s"
     },
     "pill": {
         "permalink_other_room": "Повідомлення в %(room)s",
@@ -1612,7 +1562,6 @@
         "custom_level": "Власний рівень",
         "default": "Типовий",
         "label": "Рівень повноважень",
-        "mod": "Модератор",
         "moderator": "Модератор",
         "restricted": "Обмежено"
     },
@@ -2457,7 +2406,6 @@
             "room_directory_heading": "Каталог кімнат",
             "room_list_heading": "Перелік кімнат",
             "show_avatars_pills": "Показувати аватари у згадках користувачів, кімнат і подій",
-            "show_checklist_shortcuts": "Показати ярлик контрольного списку привітання над списком кімнат",
             "show_polls_button": "Показувати кнопку опитування",
             "surround_text": "Обгортати виділений текст при введенні спеціальних символів",
             "time_heading": "Формат часу"
@@ -2816,7 +2764,6 @@
         "invite": "Запросити людей",
         "invite_description": "Запросити за допомогою е-пошти або імені користувача",
         "invite_link": "Надіслати запрошувальне посилання",
-        "invite_this_space": "Запросити до цього простору",
         "joining_space": "Приєднання",
         "landing_welcome": "Вітаємо у <name/>",
         "leave_dialog_action": "Вийти з простору",
diff --git a/src/i18n/strings/vi.json b/src/i18n/strings/vi.json
index 3e1eaeaec14..1769b5896c2 100644
--- a/src/i18n/strings/vi.json
+++ b/src/i18n/strings/vi.json
@@ -377,7 +377,6 @@
             "one": "và một cái khác…",
             "other": "và %(count)s khác…"
         },
-        "android": "Android",
         "appearance": "Giao diện",
         "application": "Ứng dụng",
         "are_you_sure": "Bạn có chắc không?",
@@ -414,7 +413,6 @@
         "identity_server": "Máy chủ định danh",
         "image": "Hình ảnh",
         "integration_manager": "Quản lý tích hợp",
-        "ios": "iOS",
         "joined": "Đã tham gia",
         "labs": "Chức năng thí nghiệm",
         "legal": "Pháp lý",
@@ -503,8 +501,7 @@
         "video": "Truyền hình",
         "video_room": "Phòng truyền hình",
         "view_message": "Xem tin nhăn",
-        "warning": "Cảnh báo",
-        "welcome": "Chào mừng"
+        "warning": "Cảnh báo"
     },
     "composer": {
         "autocomplete": {
@@ -1349,7 +1346,6 @@
     "member_list": {
         "filter_placeholder": "Lọc thành viên phòng",
         "invite_button_no_perms_tooltip": "Bạn không có quyền mời người khác",
-        "invited_list_heading": "Đã mời",
         "power_label": "%(userName)s (chỉ số %(powerLevelNumber)s)"
     },
     "member_list_back_action_label": "Thành viên phòng",
@@ -1391,53 +1387,15 @@
         "m.key.verification.request": "%(name)s đang yêu cầu xác thực"
     },
     "onboarding": {
-        "community_messaging_action": "Tìm người thân",
-        "community_messaging_description": "Giữ quyền sở hữu và kiểm soát thảo luận cộng đồng.\nMở rộng quy mô để hỗ trợ hàng triệu người, bằng khả năng kiểm duyệt và tương tác mạnh mẽ.",
-        "community_messaging_title": "Làm chủ cộng đồng",
-        "complete_these": "Hoàn thành những việc sau để tận dụng tất cả của %(brand)s",
         "create_room": "Tạo một cuộc trò chuyện nhóm",
-        "download_app": "Tải xuống %(brand)s",
-        "download_app_action": "Tải ứng dụng",
-        "download_app_description": "Không bỏ lỡ gì bằng cách mang %(brand)s bên bạn",
-        "download_app_store": "Tải trên App Store",
-        "download_brand": "Tải xuống %(brand)s",
-        "download_f_droid": "Tải trên F-Droid",
-        "download_google_play": "Tải trên CH Play",
-        "enable_notifications": "Bật thông báo",
-        "enable_notifications_action": "Kích hoạt thông báo",
-        "enable_notifications_description": "Đừng bỏ lỡ một tin nhắn trả lời hay tin nhắn quan trọng",
         "explore_rooms": "Khám phá các phòng chung",
-        "find_community_members": "Tìm và mời các thành viên của cộng đồng bạn",
-        "find_coworkers": "Tìm và mời các đồng nghiệp của bạn",
-        "find_friends": "Tìm và mời bạn bè",
-        "find_friends_action": "Tìm bạn bè",
-        "find_friends_description": "Đó là lí do bạn ở đây, vậy nên hãy bắt đầu nào",
-        "find_people": "Tìm mọi người",
-        "free_e2ee_messaging_unlimited_voip": "Với mã hóa đầu cuối miễn phí, cuộc gọi thoại và truyền hình không giới hạn, %(brand)s là cách tuyệt vời để giữ liên lạc.",
         "has_avatar_label": "Tuyệt vời, điều đó sẽ giúp mọi người biết đó là bạn",
         "intro_byline": "Sở hữu các cuộc trò chuyện của bạn.",
         "intro_welcome": "Chào mừng bạn đến với %(appName)s",
         "no_avatar_label": "Thêm ảnh để mọi người biết đó là bạn.",
-        "only_n_steps_to_go": {
-            "one": "Chỉ %(count)s bước nữa thôi",
-            "other": "Chỉ %(count)s bước nữa thôi"
-        },
-        "personal_messaging_action": "Bắt đầu cuộc trò chuyện đầu tiên",
-        "personal_messaging_title": "Tin nhắn bảo mật cho bạn bè và gia đình",
         "send_dm": "Gửi tin nhắn trực tiếp",
-        "set_up_profile": "Thiết lập hồ sơ của bạn",
-        "set_up_profile_action": "Hồ sơ",
-        "set_up_profile_description": "Đảm bảo mọi người nhận ra bạn",
-        "use_case_community_messaging": "Thành viên cộng đồng trực tuyến",
-        "use_case_personal_messaging": "Bạn bè và gia đình",
-        "use_case_work_messaging": "Đồng nghiệp và nhóm",
         "welcome_detail": "Bây giờ, hãy giúp bạn bắt đầu",
-        "welcome_to_brand": "Chào mừng bạn tới %(brand)s",
-        "welcome_user": "Chào mừng %(name)s",
-        "work_messaging_action": "Tìm các đồng nghiệp của bạn",
-        "work_messaging_title": "Tin nhắn bảo mật cho công việc",
-        "you_did_it": "Hoàn thành rồi!",
-        "you_made_it": "Bạn làm rồi!"
+        "welcome_user": "Chào mừng %(name)s"
     },
     "pill": {
         "permalink_other_room": "Tin nhắn trong %(room)s",
@@ -1482,7 +1440,6 @@
         "custom_level": "Cấp độ tùy chọn",
         "default": "Mặc định",
         "label": "Cấp độ sức mạnh",
-        "mod": "Người quản trị",
         "moderator": "Điều phối viên",
         "restricted": "Bị hạn chế"
     },
@@ -2603,7 +2560,6 @@
         "invite": "Mời mọi người",
         "invite_description": "Mời bằng thư điện tử hoặc tên người dùng",
         "invite_link": "Chia sẻ liên kết mời",
-        "invite_this_space": "Mời vào space này",
         "joining_space": "Đang tham gia",
         "landing_welcome": "Chào mừng đến với <name />",
         "leave_dialog_action": "Rời space",
diff --git a/src/i18n/strings/zh_Hans.json b/src/i18n/strings/zh_Hans.json
index 1ddb47fcc44..0ef859e5484 100644
--- a/src/i18n/strings/zh_Hans.json
+++ b/src/i18n/strings/zh_Hans.json
@@ -230,7 +230,6 @@
         "oidc": {
             "error_title": "我们无法使你登入",
             "generic_auth_error": "验证时出了问题。前往登录页面并重试。",
-            "logout_redirect_warning": "你将被重定向到服务器的验证提供者以完成登出。",
             "missing_or_invalid_stored_state": "我们已要求浏览器记住你使用的家服务器,但不幸的是你的浏览器已忘记。请前往登录页面重试。"
         },
         "password_field_keep_going_prompt": "继续前进……",
@@ -396,7 +395,6 @@
             "other": "和其他%(count)s个人……",
             "one": "和其它一个..."
         },
-        "android": "安卓",
         "appearance": "外观",
         "application": "应用",
         "are_you_sure": "你确定吗?",
@@ -435,7 +433,6 @@
         "identity_server": "身份服务器",
         "image": "图片",
         "integration_manager": "集成管理器",
-        "ios": "ios",
         "joined": "已加入",
         "labs": "实验室",
         "legal": "法律信息",
@@ -522,8 +519,7 @@
         "video": "视频",
         "video_room": "视频房间",
         "view_message": "查看消息",
-        "warning": "警告",
-        "welcome": "欢迎"
+        "warning": "警告"
     },
     "composer": {
         "autocomplete": {
@@ -1382,7 +1378,6 @@
     },
     "member_list": {
         "filter_placeholder": "过滤房间成员",
-        "invited_list_heading": "已邀请",
         "power_label": "%(userName)s(权力 %(powerLevelNumber)s)"
     },
     "member_list_back_action_label": "房间成员",
@@ -1421,57 +1416,15 @@
         "m.key.verification.request": "%(name)s 正在请求验证"
     },
     "onboarding": {
-        "apple_trademarks": "App Store®和Apple logo®是Apple Inc.的商标",
-        "community_messaging_action": "寻找你的人",
-        "community_messaging_description": "保持对社区讨论的所有权和控制权。\n可扩展至支持数百万人,具有强大的管理审核功能和互操作性。",
-        "community_messaging_title": "社群所有权",
-        "complete_these": "完成这些步骤以充分利用%(brand)s",
         "create_room": "创建一个群聊",
-        "download_app": "下载%(brand)s",
-        "download_app_action": "下载应用",
-        "download_app_description": "随身携带%(brand)s,不错过任何事情",
-        "download_app_store": "在App Store下载",
-        "download_brand": "下载%(brand)s",
-        "download_brand_desktop": "下载%(brand)s桌面版",
-        "enable_notifications": "打开通知",
-        "enable_notifications_action": "启用通知",
-        "enable_notifications_description": "不要错过回复或重要消息",
         "explore_rooms": "探索公共房间",
-        "find_community_members": "发现并邀请你的社群成员",
-        "find_coworkers": "发现并邀请你的同事",
-        "find_friends": "发现并邀请你的朋友",
-        "find_friends_action": "发现朋友",
-        "find_friends_description": "这就是你来这里的目的,所以让我们开始吧",
-        "find_people": "找人",
-        "free_e2ee_messaging_unlimited_voip": "%(brand)s提供免费的端到端加密消息传递以及无限制的语音和视频通话,是保持联系的绝佳方式。",
-        "get_stuff_done": "找到队友,完成任务",
-        "google_trademarks": "Google Play及其logo是Google LLC的商标。",
         "has_avatar_label": "很好,这样大家就知道是你了",
         "intro_byline": "拥有您的对话。",
         "intro_welcome": "欢迎来到 %(appName)s",
         "no_avatar_label": "添加照片,让人们知道这是你。",
-        "only_n_steps_to_go": {
-            "other": "仅需%(count)s步",
-            "one": "仅需%(count)s步"
-        },
-        "personal_messaging_action": "开始你的第一个聊天",
-        "personal_messaging_title": "和朋友家人安全地收发消息",
-        "qr_or_app_links": "%(qrCode)s或%(appLinks)s",
         "send_dm": "发送私聊",
-        "set_up_profile": "设置你的用户资料",
-        "set_up_profile_action": "你的用户资料",
-        "set_up_profile_description": "确保人们知道这真的是你",
-        "use_case_community_messaging": "在线社群成员",
-        "use_case_heading2": "你会和谁聊得最多?",
-        "use_case_personal_messaging": "朋友和家人",
-        "use_case_work_messaging": "同事和团队",
         "welcome_detail": "现在,让我们协助你开始",
-        "welcome_to_brand": "欢迎来到%(brand)s",
-        "welcome_user": "欢迎 %(name)s",
-        "work_messaging_action": "找到你的同事",
-        "work_messaging_title": "用于工作的安全的消息传送",
-        "you_did_it": "你做到了!",
-        "you_made_it": "你做到了!"
+        "welcome_user": "欢迎 %(name)s"
     },
     "poll": {
         "create_poll_action": "创建投票",
@@ -1517,7 +1470,6 @@
         "custom_level": "自定义级别",
         "default": "默认",
         "label": "权力级别",
-        "mod": "管理员",
         "moderator": "协管员",
         "restricted": "受限"
     },
@@ -2259,7 +2211,6 @@
             "rm_lifetime": "已读标记生存期(毫秒)",
             "rm_lifetime_offscreen": "已读标记屏幕外生存期(毫秒)",
             "room_list_heading": "房间列表",
-            "show_checklist_shortcuts": "在房间列表上方显示欢迎清单的捷径",
             "show_polls_button": "显示投票按钮",
             "surround_text": "输入特殊字符时圈出选定的文本",
             "time_heading": "显示的时间戳"
@@ -2568,7 +2519,6 @@
         "invite": "邀请人们",
         "invite_description": "使用邮箱或者用户名邀请",
         "invite_link": "分享邀请链接",
-        "invite_this_space": "邀请至此空间",
         "joining_space": "加入中",
         "landing_welcome": "欢迎来到 <name/>",
         "leave_dialog_action": "离开空间",
diff --git a/src/i18n/strings/zh_Hant.json b/src/i18n/strings/zh_Hant.json
index 584852748b1..bb63ce99e8f 100644
--- a/src/i18n/strings/zh_Hant.json
+++ b/src/i18n/strings/zh_Hant.json
@@ -410,7 +410,6 @@
             "other": "與另 %(count)s 個人…",
             "one": "與另 1 個人…"
         },
-        "android": "安卓",
         "appearance": "外觀",
         "application": "應用程式",
         "are_you_sure": "您確定嗎?",
@@ -448,7 +447,6 @@
         "identity_server": "身分伺服器",
         "image": "圖片",
         "integration_manager": "整合管理員",
-        "ios": "iOS",
         "joined": "已加入",
         "labs": "實驗室",
         "legal": "法律",
@@ -536,8 +534,7 @@
         "video": "影片",
         "video_room": "視訊聊天室",
         "view_message": "檢視訊息",
-        "warning": "警告",
-        "welcome": "歡迎"
+        "warning": "警告"
     },
     "composer": {
         "autocomplete": {
@@ -1352,7 +1349,6 @@
         "msc3531_hide_messages_pending_moderation": "讓版主能夠隱藏待審核的訊息。",
         "notification_settings": "新通知設定",
         "notification_settings_beta_title": "通知設定",
-        "oidc_native_flow": "啟用新的原生 OIDC 流程(正在積極開發中)",
         "report_to_moderators": "回報給版主",
         "report_to_moderators_description": "在支援審核的聊天室中,「回報」按鈕讓您可以回報濫用行為給聊天室管理員。",
         "sliding_sync": "滑動同步模式",
@@ -1467,7 +1463,6 @@
     "member_list": {
         "filter_placeholder": "過濾聊天室成員",
         "invite_button_no_perms_tooltip": "您沒有權限邀請使用者",
-        "invited_list_heading": "已邀請",
         "power_label": "%(userName)s(權限等級 %(powerLevelNumber)s)"
     },
     "member_list_back_action_label": "聊天室成員",
@@ -1509,61 +1504,15 @@
         "m.key.verification.request": "%(name)s 正在要求驗證"
     },
     "onboarding": {
-        "apple_trademarks": "App Store® 與 Apple logo® 是 Apple Inc 的註冊商標。",
-        "community_messaging_action": "尋找您的夥伴",
-        "community_messaging_description": "保持對社群討論的所有權與控制權。\n具有強大的審核工具與互操作性,可擴充至支援數百萬人。",
-        "community_messaging_title": "社群所有權",
-        "complete_these": "完成這些步驟以充分利用 %(brand)s",
         "create_room": "建立群組聊天",
-        "download_app": "下載 %(brand)s",
-        "download_app_action": "下載應用程式",
-        "download_app_description": "隨身攜帶 %(brand)s,不錯過任何事情",
-        "download_app_store": "在 App Store 上下載",
-        "download_brand": "下載 %(brand)s",
-        "download_brand_desktop": "下載 %(brand)s 桌面版",
-        "download_f_droid": "在 F-Droid 上取得",
-        "download_google_play": "在 Google Play 上取得",
-        "enable_notifications": "開啟通知",
-        "enable_notifications_action": "啟用通知",
-        "enable_notifications_description": "不要錯過回覆或重要訊息",
         "explore_rooms": "探索公開聊天室",
-        "find_community_members": "尋找並邀請您的社群成員",
-        "find_coworkers": "尋找並邀請您的同事",
-        "find_friends": "尋找並邀請您的朋友",
-        "find_friends_action": "尋找朋友",
-        "find_friends_description": "這就是您來這裡的目的,所以讓我們開始吧",
-        "find_people": "尋找夥伴",
-        "free_e2ee_messaging_unlimited_voip": "%(brand)s 提供免費的端對端加密通訊,以及無限制的語音及視訊通話,是維持聯絡的絕佳方式。",
-        "get_stuff_done": "透過找到您的團隊成員來完成工作",
-        "google_trademarks": "Google Play 與 Google Play 圖示是 Google LLC 的註冊商標。",
         "has_avatar_label": "太好了,這會讓人們知道是您",
         "intro_byline": "擁有您的對話。",
         "intro_welcome": "歡迎使用 %(appName)s",
         "no_avatar_label": "新增照片以讓其他人知道是您。",
-        "only_n_steps_to_go": {
-            "one": "僅需 %(count)s 步",
-            "other": "僅需 %(count)s 步"
-        },
-        "personal_messaging_action": "開始您的第一個聊天",
-        "personal_messaging_title": "為朋友與家人提供的安全訊息",
-        "qr_or_app_links": "%(qrCode)s 或 %(appLinks)s",
         "send_dm": "傳送私人訊息",
-        "set_up_profile": "設定您的個人檔案",
-        "set_up_profile_action": "您的個人檔案",
-        "set_up_profile_description": "確保人們知道這真的是您",
-        "use_case_community_messaging": "線上社群成員",
-        "use_case_heading1": "加入成功!",
-        "use_case_heading2": "您最常與誰聊天?",
-        "use_case_heading3": "我們將會協助您建立聯繫。",
-        "use_case_personal_messaging": "朋友與家人",
-        "use_case_work_messaging": "同事與團隊",
         "welcome_detail": "現在,讓我們協助您開始",
-        "welcome_to_brand": "歡迎使用 %(brand)s",
-        "welcome_user": "歡迎 %(name)s",
-        "work_messaging_action": "尋找您的同事",
-        "work_messaging_title": "工作用的安全通訊",
-        "you_did_it": "您做到了!",
-        "you_made_it": "您做到了!"
+        "welcome_user": "歡迎 %(name)s"
     },
     "pill": {
         "permalink_other_room": "%(room)s 中的訊息",
@@ -1615,7 +1564,6 @@
         "custom_level": "自訂等級",
         "default": "預設",
         "label": "權限等級",
-        "mod": "版主",
         "moderator": "版主",
         "restricted": "已限制"
     },
@@ -2458,7 +2406,6 @@
             "room_directory_heading": "聊天室目錄",
             "room_list_heading": "聊天室清單",
             "show_avatars_pills": "在使用者、聊天室與事件提及中顯示大頭貼",
-            "show_checklist_shortcuts": "在聊天室清單上方顯示歡迎新人檢核表的捷徑",
             "show_polls_button": "顯示投票按鈕",
             "surround_text": "輸入特殊字元時,圍繞選取的文字",
             "time_heading": "顯示時間"
@@ -2811,7 +2758,6 @@
         "invite": "邀請夥伴",
         "invite_description": "使用電子郵件或使用者名稱邀請",
         "invite_link": "分享邀請連結",
-        "invite_this_space": "邀請加入此聊天空間",
         "joining_space": "正在加入",
         "landing_welcome": "歡迎加入 <name/>",
         "leave_dialog_action": "離開聊天空間",
diff --git a/src/identifiers.ts b/src/identifiers.ts
index 88f3c265925..db342ed0463 100644
--- a/src/identifiers.ts
+++ b/src/identifiers.ts
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2021 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/src/index.ts b/src/index.ts
index e1fe9c01036..7988f32dad5 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/indexing/BaseEventIndexManager.ts b/src/indexing/BaseEventIndexManager.ts
index efdc64e36a5..0088a796832 100644
--- a/src/indexing/BaseEventIndexManager.ts
+++ b/src/indexing/BaseEventIndexManager.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/indexing/EventIndex.ts b/src/indexing/EventIndex.ts
index da2eee995cd..7a126b2ffb6 100644
--- a/src/indexing/EventIndex.ts
+++ b/src/indexing/EventIndex.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/indexing/EventIndexPeg.ts b/src/indexing/EventIndexPeg.ts
index 73acfff857d..f33cbcc74ca 100644
--- a/src/indexing/EventIndexPeg.ts
+++ b/src/indexing/EventIndexPeg.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/integrations/IntegrationManagerInstance.ts b/src/integrations/IntegrationManagerInstance.ts
index 4516922fb5c..d74b380bfdb 100644
--- a/src/integrations/IntegrationManagerInstance.ts
+++ b/src/integrations/IntegrationManagerInstance.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/integrations/IntegrationManagers.ts b/src/integrations/IntegrationManagers.ts
index 86c1b2db8c9..a8fe8a33dc3 100644
--- a/src/integrations/IntegrationManagers.ts
+++ b/src/integrations/IntegrationManagers.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/languageHandler.tsx b/src/languageHandler.tsx
index c30ca949229..937a6c18670 100644
--- a/src/languageHandler.tsx
+++ b/src/languageHandler.tsx
@@ -5,7 +5,7 @@ Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
 Copyright 2017 MTRNord and Cooperative EITA
 Copyright 2017 Vector Creations Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -438,6 +438,7 @@ export function replaceByRegexes(text: string, mapping: IVariables | Tags): stri
     if (shouldWrapInSpan) {
         return React.createElement("span", null, ...(output as Array<number | string | React.ReactNode>));
     } else {
+        // eslint-disable-next-line @typescript-eslint/no-base-to-string
         return output.join("");
     }
 }
diff --git a/src/linkify-matrix.ts b/src/linkify-matrix.ts
index 0d129ff9526..198d5982c16 100644
--- a/src/linkify-matrix.ts
+++ b/src/linkify-matrix.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/mjolnir/BanList.ts b/src/mjolnir/BanList.ts
index 7e31b652da3..617b37d77af 100644
--- a/src/mjolnir/BanList.ts
+++ b/src/mjolnir/BanList.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/mjolnir/ListRule.ts b/src/mjolnir/ListRule.ts
index 0261ec2ef9a..6c9389bd336 100644
--- a/src/mjolnir/ListRule.ts
+++ b/src/mjolnir/ListRule.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/mjolnir/Mjolnir.ts b/src/mjolnir/Mjolnir.ts
index 9dacc0d41ff..cea128e5efa 100644
--- a/src/mjolnir/Mjolnir.ts
+++ b/src/mjolnir/Mjolnir.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/models/Call.ts b/src/models/Call.ts
index 4beb5fccc1e..03645ed47ee 100644
--- a/src/models/Call.ts
+++ b/src/models/Call.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -688,7 +688,7 @@ export class ElementCall extends Call {
 
         // Set custom fonts
         if (SettingsStore.getValue("useSystemFont")) {
-            SettingsStore.getValue<string>("systemFont")
+            SettingsStore.getValue("systemFont")
                 .split(",")
                 .map((font) => {
                     // Strip whitespace and quotes
diff --git a/src/models/LocalRoom.ts b/src/models/LocalRoom.ts
index f1f8dde1cd7..4a233f976f8 100644
--- a/src/models/LocalRoom.ts
+++ b/src/models/LocalRoom.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/models/RoomUpload.ts b/src/models/RoomUpload.ts
index 569f59e0166..61add9c7f5a 100644
--- a/src/models/RoomUpload.ts
+++ b/src/models/RoomUpload.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/models/notificationsettings/NotificationSettings.ts b/src/models/notificationsettings/NotificationSettings.ts
index 533afe2d04a..3ebd6811f46 100644
--- a/src/models/notificationsettings/NotificationSettings.ts
+++ b/src/models/notificationsettings/NotificationSettings.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/models/notificationsettings/PushRuleDiff.ts b/src/models/notificationsettings/PushRuleDiff.ts
index 82c4a4d4b50..11d8ce0522e 100644
--- a/src/models/notificationsettings/PushRuleDiff.ts
+++ b/src/models/notificationsettings/PushRuleDiff.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/models/notificationsettings/PushRuleMap.ts b/src/models/notificationsettings/PushRuleMap.ts
index bf217d16ffb..8c7ede293cf 100644
--- a/src/models/notificationsettings/PushRuleMap.ts
+++ b/src/models/notificationsettings/PushRuleMap.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/models/notificationsettings/reconcileNotificationSettings.ts b/src/models/notificationsettings/reconcileNotificationSettings.ts
index da052b4475f..ce67d25d343 100644
--- a/src/models/notificationsettings/reconcileNotificationSettings.ts
+++ b/src/models/notificationsettings/reconcileNotificationSettings.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/models/notificationsettings/toNotificationSettings.ts b/src/models/notificationsettings/toNotificationSettings.ts
index 7f7f5798b83..33ed4b5e4ac 100644
--- a/src/models/notificationsettings/toNotificationSettings.ts
+++ b/src/models/notificationsettings/toNotificationSettings.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/models/rooms/PresenceState.ts b/src/models/rooms/PresenceState.ts
new file mode 100644
index 00000000000..54c1c0a568b
--- /dev/null
+++ b/src/models/rooms/PresenceState.ts
@@ -0,0 +1,8 @@
+/*
+Copyright 2024 New Vector Ltd.
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+Please see LICENSE files in the repository root for full details.
+*/
+
+export type PresenceState = "offline" | "online" | "unavailable" | "io.element.unreachable";
diff --git a/src/models/rooms/RoomMember.ts b/src/models/rooms/RoomMember.ts
new file mode 100644
index 00000000000..850ae368b18
--- /dev/null
+++ b/src/models/rooms/RoomMember.ts
@@ -0,0 +1,22 @@
+/*
+Copyright 2024 New Vector Ltd.
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+Please see LICENSE files in the repository root for full details.
+*/
+
+import { PresenceState } from "./PresenceState";
+
+export type RoomMember = {
+    roomId: string;
+    userId: string;
+    displayUserId: string;
+    name: string;
+    rawDisplayName?: string;
+    disambiguate: boolean;
+    avatarThumbnailUrl?: string;
+    powerLevel: number;
+    lastModifiedTime: number;
+    presenceState?: PresenceState;
+    isInvite: boolean;
+};
diff --git a/src/models/rooms/ThreePIDInvite.ts b/src/models/rooms/ThreePIDInvite.ts
new file mode 100644
index 00000000000..4fabd6e0972
--- /dev/null
+++ b/src/models/rooms/ThreePIDInvite.ts
@@ -0,0 +1,12 @@
+/*
+Copyright 2024 New Vector Ltd.
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+Please see LICENSE files in the repository root for full details.
+*/
+
+import { MatrixEvent } from "matrix-js-sdk/src/matrix";
+
+export type ThreePIDInvite = {
+    event: MatrixEvent;
+};
diff --git a/src/modules/AppModule.ts b/src/modules/AppModule.ts
index 3904efe6f27..b7585fd2c66 100644
--- a/src/modules/AppModule.ts
+++ b/src/modules/AppModule.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/modules/ModuleComponents.tsx b/src/modules/ModuleComponents.tsx
index 25a5092a21c..53ab415603c 100644
--- a/src/modules/ModuleComponents.tsx
+++ b/src/modules/ModuleComponents.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/modules/ModuleFactory.ts b/src/modules/ModuleFactory.ts
index 42d5c0f4a62..9d72a18d6b2 100644
--- a/src/modules/ModuleFactory.ts
+++ b/src/modules/ModuleFactory.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/modules/ModuleRunner.ts b/src/modules/ModuleRunner.ts
index 06a17b43b4d..c01015206dd 100644
--- a/src/modules/ModuleRunner.ts
+++ b/src/modules/ModuleRunner.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/modules/ProxiedModuleApi.ts b/src/modules/ProxiedModuleApi.ts
index 34735afe0ff..7aa6ccd3b85 100644
--- a/src/modules/ProxiedModuleApi.ts
+++ b/src/modules/ProxiedModuleApi.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/notifications/ContentRules.ts b/src/notifications/ContentRules.ts
index 0f0fcc21e1d..bfe3bed6c29 100644
--- a/src/notifications/ContentRules.ts
+++ b/src/notifications/ContentRules.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2016-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/notifications/NotificationUtils.ts b/src/notifications/NotificationUtils.ts
index 37f58d839f1..0504ba41f7c 100644
--- a/src/notifications/NotificationUtils.ts
+++ b/src/notifications/NotificationUtils.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2016-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/notifications/PushRuleVectorState.ts b/src/notifications/PushRuleVectorState.ts
index 1a6559df606..eeed5ca99c2 100644
--- a/src/notifications/PushRuleVectorState.ts
+++ b/src/notifications/PushRuleVectorState.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2016-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/notifications/StandardActions.ts b/src/notifications/StandardActions.ts
index 17d8454e33b..21dad0e6555 100644
--- a/src/notifications/StandardActions.ts
+++ b/src/notifications/StandardActions.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 Copyright 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/notifications/VectorPushRulesDefinitions.ts b/src/notifications/VectorPushRulesDefinitions.ts
index 4149a8efb90..77311edcecc 100644
--- a/src/notifications/VectorPushRulesDefinitions.ts
+++ b/src/notifications/VectorPushRulesDefinitions.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2016-2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/notifications/index.ts b/src/notifications/index.ts
index 332c8ef698e..17f1b249a98 100644
--- a/src/notifications/index.ts
+++ b/src/notifications/index.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 Copyright 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/performance/entry-names.ts b/src/performance/entry-names.ts
index 13953ebf324..fcdd0621e16 100644
--- a/src/performance/entry-names.ts
+++ b/src/performance/entry-names.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/performance/index.ts b/src/performance/index.ts
index 4d26f02b28e..468181e0c1b 100644
--- a/src/performance/index.ts
+++ b/src/performance/index.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/phonenumber.ts b/src/phonenumber.ts
index 185287ff6f3..dbf49e65b93 100644
--- a/src/phonenumber.ts
+++ b/src/phonenumber.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2017 Vector Creations Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/rageshake/rageshake.ts b/src/rageshake/rageshake.ts
index c68fa8503c7..2d8ec572d5a 100644
--- a/src/rageshake/rageshake.ts
+++ b/src/rageshake/rageshake.ts
@@ -4,7 +4,7 @@ Copyright 2019 The Matrix.org Foundation C.I.C.
 Copyright 2018 New Vector Ltd
 Copyright 2017 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/rageshake/submit-rageshake.ts b/src/rageshake/submit-rageshake.ts
index 0c00cc777a2..05f8a49b43e 100644
--- a/src/rageshake/submit-rageshake.ts
+++ b/src/rageshake/submit-rageshake.ts
@@ -4,7 +4,7 @@ Copyright 2019 The Matrix.org Foundation C.I.C.
 Copyright 2018 New Vector Ltd
 Copyright 2017 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/resizer/distributors/collapse.ts b/src/resizer/distributors/collapse.ts
index 172ece19c32..a4693e8e14f 100644
--- a/src/resizer/distributors/collapse.ts
+++ b/src/resizer/distributors/collapse.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/resizer/distributors/fixed.ts b/src/resizer/distributors/fixed.ts
index 06535771fc8..609df1deae1 100644
--- a/src/resizer/distributors/fixed.ts
+++ b/src/resizer/distributors/fixed.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/resizer/distributors/percentage.ts b/src/resizer/distributors/percentage.ts
index 3c487fcd0fc..f8a00107870 100644
--- a/src/resizer/distributors/percentage.ts
+++ b/src/resizer/distributors/percentage.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/resizer/index.ts b/src/resizer/index.ts
index 11b81013387..b73b368361e 100644
--- a/src/resizer/index.ts
+++ b/src/resizer/index.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/resizer/item.ts b/src/resizer/item.ts
index e715a1a25c2..9eeea86fd6f 100644
--- a/src/resizer/item.ts
+++ b/src/resizer/item.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/resizer/resizer.ts b/src/resizer/resizer.ts
index 1b24ee00e6a..826b017d569 100644
--- a/src/resizer/resizer.ts
+++ b/src/resizer/resizer.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2018-2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/resizer/sizer.ts b/src/resizer/sizer.ts
index 046e13fd6b5..2284781c9df 100644
--- a/src/resizer/sizer.ts
+++ b/src/resizer/sizer.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2018-2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/sendTimePerformanceMetrics.ts b/src/sendTimePerformanceMetrics.ts
index d5fc46241ea..c57ed3771be 100644
--- a/src/sendTimePerformanceMetrics.ts
+++ b/src/sendTimePerformanceMetrics.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/sentry.ts b/src/sentry.ts
index c70201679c0..90ce39d671e 100644
--- a/src/sentry.ts
+++ b/src/sentry.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/serviceworker/index.ts b/src/serviceworker/index.ts
index f15c880cf57..8c522ede596 100644
--- a/src/serviceworker/index.ts
+++ b/src/serviceworker/index.ts
@@ -1,7 +1,7 @@
 /*
 Copyright 2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/settings/SettingLevel.ts b/src/settings/SettingLevel.ts
index 88be8f381c9..2904350d4d8 100644
--- a/src/settings/SettingLevel.ts
+++ b/src/settings/SettingLevel.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/settings/Settings.tsx b/src/settings/Settings.tsx
index 6cd5b15a515..48a271a9a96 100644
--- a/src/settings/Settings.tsx
+++ b/src/settings/Settings.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2018-2024 The Matrix.org Foundation C.I.C.
 Copyright 2017 Travis Ralston
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -38,6 +38,12 @@ import { WatchManager } from "./WatchManager";
 import { CustomTheme } from "../theme";
 import AnalyticsController from "./controllers/AnalyticsController";
 import FallbackIceServerController from "./controllers/FallbackIceServerController";
+import { IRightPanelForRoomStored } from "../stores/right-panel/RightPanelStoreIPanelState.ts";
+import { ILayoutSettings } from "../stores/widgets/WidgetLayoutStore.ts";
+import { ReleaseAnnouncementData } from "../stores/ReleaseAnnouncementStore.ts";
+import { Json, JsonValue } from "../@types/json.ts";
+import { RecentEmojiData } from "../emojipicker/recent.ts";
+import { Assignable } from "../@types/common.ts";
 
 export const defaultWatchManager = new WatchManager();
 
@@ -86,7 +92,6 @@ export enum LabGroup {
 
 export enum Features {
     NotificationSettings2 = "feature_notification_settings2",
-    OidcNativeFlow = "feature_oidc_native_flow",
     ReleaseAnnouncement = "feature_release_announcement",
 }
 
@@ -107,15 +112,7 @@ export const labGroupNames: Record<LabGroup, TranslationKey> = {
     [LabGroup.Ui]: _td("labs|group_ui"),
 };
 
-export type SettingValueType =
-    | boolean
-    | number
-    | string
-    | number[]
-    | string[]
-    | Record<string, unknown>
-    | Record<string, unknown>[]
-    | null;
+export type SettingValueType = Json | JsonValue | Record<string, unknown> | Record<string, unknown>[];
 
 export interface IBaseSetting<T extends SettingValueType = SettingValueType> {
     isFeature?: false | undefined;
@@ -165,7 +162,7 @@ export interface IBaseSetting<T extends SettingValueType = SettingValueType> {
         image?: string; // require(...)
         feedbackSubheading?: TranslationKey;
         feedbackLabel?: string;
-        extraSettings?: string[];
+        extraSettings?: BooleanSettingKey[];
         requiresRefresh?: boolean;
     };
 
@@ -182,7 +179,177 @@ export interface IFeature extends Omit<IBaseSetting<boolean>, "isFeature"> {
 // Type using I-identifier for backwards compatibility from before it became a discriminated union
 export type ISetting = IBaseSetting | IFeature;
 
-export const SETTINGS: { [setting: string]: ISetting } = {
+export interface Settings {
+    [settingName: `UIFeature.${string}`]: IBaseSetting<boolean>;
+
+    // We can't use the following type because of `feature_sliding_sync_proxy_url` & `feature_hidebold` being in the namespace incorrectly
+    // [settingName: `feature_${string}`]: IFeature;
+    "feature_video_rooms": IFeature;
+    [Features.NotificationSettings2]: IFeature;
+    [Features.ReleaseAnnouncement]: IFeature;
+    "feature_msc3531_hide_messages_pending_moderation": IFeature;
+    "feature_report_to_moderators": IFeature;
+    "feature_latex_maths": IFeature;
+    "feature_wysiwyg_composer": IFeature;
+    "feature_mjolnir": IFeature;
+    "feature_custom_themes": IFeature;
+    "feature_exclude_insecure_devices": IFeature;
+    "feature_html_topic": IFeature;
+    "feature_bridge_state": IFeature;
+    "feature_jump_to_date": IFeature;
+    "feature_sliding_sync": IFeature;
+    "feature_element_call_video_rooms": IFeature;
+    "feature_group_calls": IFeature;
+    "feature_disable_call_per_sender_encryption": IFeature;
+    "feature_allow_screen_share_only_mode": IFeature;
+    "feature_location_share_live": IFeature;
+    "feature_dynamic_room_predecessors": IFeature;
+    "feature_render_reaction_images": IFeature;
+    "feature_ask_to_join": IFeature;
+    "feature_notifications": IFeature;
+    // These are in the feature namespace but aren't actually features
+    "feature_sliding_sync_proxy_url": IBaseSetting<string>;
+    "feature_hidebold": IBaseSetting<boolean>;
+
+    "useOnlyCurrentProfiles": IBaseSetting<boolean>;
+    "mjolnirRooms": IBaseSetting<string[]>;
+    "mjolnirPersonalRoom": IBaseSetting<string | null>;
+    "RoomList.backgroundImage": IBaseSetting<string | null>;
+    "sendReadReceipts": IBaseSetting<boolean>;
+    "baseFontSize": IBaseSetting<"" | number>;
+    "baseFontSizeV2": IBaseSetting<"" | number>;
+    "fontSizeDelta": IBaseSetting<number>;
+    "useCustomFontSize": IBaseSetting<boolean>;
+    "MessageComposerInput.suggestEmoji": IBaseSetting<boolean>;
+    "MessageComposerInput.showStickersButton": IBaseSetting<boolean>;
+    "MessageComposerInput.showPollsButton": IBaseSetting<boolean>;
+    "MessageComposerInput.insertTrailingColon": IBaseSetting<boolean>;
+    "Notifications.alwaysShowBadgeCounts": IBaseSetting<boolean>;
+    "Notifications.showbold": IBaseSetting<boolean>;
+    "Notifications.tac_only_notifications": IBaseSetting<boolean>;
+    "useCompactLayout": IBaseSetting<boolean>;
+    "showRedactions": IBaseSetting<boolean>;
+    "showJoinLeaves": IBaseSetting<boolean>;
+    "showAvatarChanges": IBaseSetting<boolean>;
+    "showDisplaynameChanges": IBaseSetting<boolean>;
+    "showReadReceipts": IBaseSetting<boolean>;
+    "showTwelveHourTimestamps": IBaseSetting<boolean>;
+    "alwaysShowTimestamps": IBaseSetting<boolean>;
+    "userTimezone": IBaseSetting<string>;
+    "userTimezonePublish": IBaseSetting<boolean>;
+    "autoplayGifs": IBaseSetting<boolean>;
+    "autoplayVideo": IBaseSetting<boolean>;
+    "enableSyntaxHighlightLanguageDetection": IBaseSetting<boolean>;
+    "expandCodeByDefault": IBaseSetting<boolean>;
+    "showCodeLineNumbers": IBaseSetting<boolean>;
+    "scrollToBottomOnMessageSent": IBaseSetting<boolean>;
+    "Pill.shouldShowPillAvatar": IBaseSetting<boolean>;
+    "TextualBody.enableBigEmoji": IBaseSetting<boolean>;
+    "MessageComposerInput.isRichTextEnabled": IBaseSetting<boolean>;
+    "MessageComposer.showFormatting": IBaseSetting<boolean>;
+    "sendTypingNotifications": IBaseSetting<boolean>;
+    "showTypingNotifications": IBaseSetting<boolean>;
+    "ctrlFForSearch": IBaseSetting<boolean>;
+    "MessageComposerInput.ctrlEnterToSend": IBaseSetting<boolean>;
+    "MessageComposerInput.surroundWith": IBaseSetting<boolean>;
+    "MessageComposerInput.autoReplaceEmoji": IBaseSetting<boolean>;
+    "MessageComposerInput.useMarkdown": IBaseSetting<boolean>;
+    "VideoView.flipVideoHorizontally": IBaseSetting<boolean>;
+    "theme": IBaseSetting<string>;
+    "custom_themes": IBaseSetting<CustomTheme[]>;
+    "use_system_theme": IBaseSetting<boolean>;
+    "useBundledEmojiFont": IBaseSetting<boolean>;
+    "useSystemFont": IBaseSetting<boolean>;
+    "systemFont": IBaseSetting<string>;
+    "webRtcAllowPeerToPeer": IBaseSetting<boolean>;
+    "webrtc_audiooutput": IBaseSetting<string>;
+    "webrtc_audioinput": IBaseSetting<string>;
+    "webrtc_videoinput": IBaseSetting<string>;
+    "webrtc_audio_autoGainControl": IBaseSetting<boolean>;
+    "webrtc_audio_echoCancellation": IBaseSetting<boolean>;
+    "webrtc_audio_noiseSuppression": IBaseSetting<boolean>;
+    "language": IBaseSetting<string>;
+    "breadcrumb_rooms": IBaseSetting<string[]>;
+    "recent_emoji": IBaseSetting<RecentEmojiData>;
+    "SpotlightSearch.recentSearches": IBaseSetting<string[]>;
+    "SpotlightSearch.showNsfwPublicRooms": IBaseSetting<boolean>;
+    "room_directory_servers": IBaseSetting<string[]>;
+    "integrationProvisioning": IBaseSetting<boolean>;
+    "allowedWidgets": IBaseSetting<{ [eventId: string]: boolean }>;
+    "analyticsOptIn": IBaseSetting<boolean>;
+    "pseudonymousAnalyticsOptIn": IBaseSetting<boolean | null>;
+    "deviceClientInformationOptIn": IBaseSetting<boolean>;
+    "Registration.mobileRegistrationHelper": IBaseSetting<boolean>;
+    "autocompleteDelay": IBaseSetting<number>;
+    "readMarkerInViewThresholdMs": IBaseSetting<number>;
+    "readMarkerOutOfViewThresholdMs": IBaseSetting<number>;
+    "blacklistUnverifiedDevices": IBaseSetting<boolean>;
+    "urlPreviewsEnabled": IBaseSetting<boolean>;
+    "urlPreviewsEnabled_e2ee": IBaseSetting<boolean>;
+    "notificationsEnabled": IBaseSetting<boolean>;
+    "deviceNotificationsEnabled": IBaseSetting<boolean>;
+    "notificationSound": IBaseSetting<
+        | {
+              name: string;
+              type: string;
+              size: number;
+              url: string;
+          }
+        | false
+    >;
+    "notificationBodyEnabled": IBaseSetting<boolean>;
+    "audioNotificationsEnabled": IBaseSetting<boolean>;
+    "enableWidgetScreenshots": IBaseSetting<boolean>;
+    "promptBeforeInviteUnknownUsers": IBaseSetting<boolean>;
+    "widgetOpenIDPermissions": IBaseSetting<{
+        allow?: string[];
+        deny?: string[];
+    }>;
+    "breadcrumbs": IBaseSetting<boolean>;
+    "showHiddenEventsInTimeline": IBaseSetting<boolean>;
+    "lowBandwidth": IBaseSetting<boolean>;
+    "fallbackICEServerAllowed": IBaseSetting<boolean | null>;
+    "showImages": IBaseSetting<boolean>;
+    "RightPanel.phasesGlobal": IBaseSetting<IRightPanelForRoomStored | null>;
+    "RightPanel.phases": IBaseSetting<IRightPanelForRoomStored | null>;
+    "enableEventIndexing": IBaseSetting<boolean>;
+    "crawlerSleepTime": IBaseSetting<number>;
+    "showCallButtonsInComposer": IBaseSetting<boolean>;
+    "ircDisplayNameWidth": IBaseSetting<number>;
+    "layout": IBaseSetting<Layout>;
+    "Images.size": IBaseSetting<ImageSize>;
+    "showChatEffects": IBaseSetting<boolean>;
+    "Performance.addSendMessageTimingMetadata": IBaseSetting<boolean>;
+    "Widgets.pinned": IBaseSetting<{ [widgetId: string]: boolean }>;
+    "Widgets.layout": IBaseSetting<ILayoutSettings | null>;
+    "Spaces.allRoomsInHome": IBaseSetting<boolean>;
+    "Spaces.enabledMetaSpaces": IBaseSetting<Partial<Record<MetaSpace, boolean>>>;
+    "Spaces.showPeopleInSpace": IBaseSetting<boolean>;
+    "developerMode": IBaseSetting<boolean>;
+    "automaticErrorReporting": IBaseSetting<boolean>;
+    "automaticDecryptionErrorReporting": IBaseSetting<boolean>;
+    "automaticKeyBackNotEnabledReporting": IBaseSetting<boolean>;
+    "debug_scroll_panel": IBaseSetting<boolean>;
+    "debug_timeline_panel": IBaseSetting<boolean>;
+    "debug_registration": IBaseSetting<boolean>;
+    "debug_animation": IBaseSetting<boolean>;
+    "debug_legacy_call_handler": IBaseSetting<boolean>;
+    "audioInputMuted": IBaseSetting<boolean>;
+    "videoInputMuted": IBaseSetting<boolean>;
+    "activeCallRoomIds": IBaseSetting<string[]>;
+    "releaseAnnouncementData": IBaseSetting<ReleaseAnnouncementData>;
+    "Electron.autoLaunch": IBaseSetting<boolean>;
+    "Electron.warnBeforeExit": IBaseSetting<boolean>;
+    "Electron.alwaysShowMenuBar": IBaseSetting<boolean>;
+    "Electron.showTrayIcon": IBaseSetting<boolean>;
+    "Electron.enableHardwareAcceleration": IBaseSetting<boolean>;
+}
+
+export type SettingKey = keyof Settings;
+export type FeatureSettingKey = Assignable<Settings, IFeature>;
+export type BooleanSettingKey = Assignable<Settings, IBaseSetting<boolean>> | FeatureSettingKey;
+
+export const SETTINGS: Settings = {
     "feature_video_rooms": {
         isFeature: true,
         labsGroup: LabGroup.VoiceAndVideo,
@@ -438,15 +605,6 @@ export const SETTINGS: { [setting: string]: ISetting } = {
         shouldWarn: true,
         default: false,
     },
-    [Features.OidcNativeFlow]: {
-        isFeature: true,
-        labsGroup: LabGroup.Developer,
-        supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG_PRIORITISED,
-        supportedLevelsAreOrdered: true,
-        displayName: _td("labs|oidc_native_flow"),
-        description: _td("labs|oidc_native_flow_description"),
-        default: false,
-    },
     /**
      * @deprecated in favor of {@link fontSizeDelta}
      */
@@ -720,7 +878,7 @@ export const SETTINGS: { [setting: string]: ISetting } = {
     },
     "custom_themes": {
         supportedLevels: LEVELS_ACCOUNT_SETTINGS,
-        default: [] as CustomTheme[],
+        default: [],
     },
     "use_system_theme": {
         supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS,
@@ -831,10 +989,6 @@ export const SETTINGS: { [setting: string]: ISetting } = {
         displayName: _td("settings|security|record_session_details"),
         default: false,
     },
-    "FTUE.useCaseSelection": {
-        supportedLevels: LEVELS_ACCOUNT_SETTINGS,
-        default: null,
-    },
     "Registration.mobileRegistrationHelper": {
         supportedLevels: [SettingLevel.CONFIG],
         default: false,
@@ -925,11 +1079,6 @@ export const SETTINGS: { [setting: string]: ISetting } = {
         displayName: _td("settings|show_breadcrumbs"),
         default: true,
     },
-    "FTUE.userOnboardingButton": {
-        supportedLevels: LEVELS_ACCOUNT_SETTINGS,
-        displayName: _td("settings|preferences|show_checklist_shortcuts"),
-        default: true,
-    },
     "showHiddenEventsInTimeline": {
         displayName: _td("devtools|show_hidden_events"),
         supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS,
diff --git a/src/settings/SettingsStore.ts b/src/settings/SettingsStore.ts
index 98ae347a0ab..f0b74de15ae 100644
--- a/src/settings/SettingsStore.ts
+++ b/src/settings/SettingsStore.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
 Copyright 2017 Travis Ralston
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -20,7 +20,7 @@ import RoomSettingsHandler from "./handlers/RoomSettingsHandler";
 import ConfigSettingsHandler from "./handlers/ConfigSettingsHandler";
 import { _t } from "../languageHandler";
 import dis from "../dispatcher/dispatcher";
-import { IFeature, ISetting, LabGroup, SETTINGS, defaultWatchManager } from "./Settings";
+import { IFeature, ISetting, LabGroup, SETTINGS, defaultWatchManager, SettingKey, Settings } from "./Settings";
 import LocalEchoWrapper from "./handlers/LocalEchoWrapper";
 import { CallbackFn as WatchCallbackFn } from "./WatchManager";
 import { SettingLevel } from "./SettingLevel";
@@ -34,11 +34,11 @@ import { MatrixClientPeg } from "../MatrixClientPeg";
 // Convert the settings to easier to manage objects for the handlers
 const defaultSettings: Record<string, any> = {};
 const invertedDefaultSettings: Record<string, boolean> = {};
-const featureNames: string[] = [];
+const featureNames: SettingKey[] = [];
 for (const key in SETTINGS) {
-    const setting = SETTINGS[key];
+    const setting = SETTINGS[key as SettingKey];
     defaultSettings[key] = setting.default;
-    if (setting.isFeature) featureNames.push(key);
+    if (setting.isFeature) featureNames.push(key as SettingKey);
     if (setting.invertedSettingName) {
         // Invert now so that the rest of the system will invert it back to what was intended.
         invertedDefaultSettings[setting.invertedSettingName] = !setting.default;
@@ -80,7 +80,7 @@ function getLevelOrder(setting: ISetting): SettingLevel[] {
 }
 
 export type CallbackFn = (
-    settingName: string,
+    settingName: SettingKey,
     roomId: string | null,
     atLevel: SettingLevel,
     newValAtLevel: any,
@@ -138,8 +138,8 @@ export default class SettingsStore {
      * Gets all the feature-style setting names.
      * @returns {string[]} The names of the feature settings.
      */
-    public static getFeatureSettingNames(): string[] {
-        return Object.keys(SETTINGS).filter((n) => SettingsStore.isFeature(n));
+    public static getFeatureSettingNames(): SettingKey[] {
+        return (Object.keys(SETTINGS) as SettingKey[]).filter((n) => SettingsStore.isFeature(n));
     }
 
     /**
@@ -158,33 +158,30 @@ export default class SettingsStore {
      * if the change in value is worthwhile enough to react upon.
      * @returns {string} A reference to the watcher that was employed.
      */
-    public static watchSetting(settingName: string, roomId: string | null, callbackFn: CallbackFn): string {
+    public static watchSetting(settingName: SettingKey, roomId: string | null, callbackFn: CallbackFn): string {
         const setting = SETTINGS[settingName];
-        const originalSettingName = settingName;
         if (!setting) throw new Error(`${settingName} is not a setting`);
 
-        if (setting.invertedSettingName) {
-            settingName = setting.invertedSettingName;
-        }
+        const finalSettingName: string = setting.invertedSettingName ?? settingName;
 
-        const watcherId = `${new Date().getTime()}_${SettingsStore.watcherCount++}_${settingName}_${roomId}`;
+        const watcherId = `${new Date().getTime()}_${SettingsStore.watcherCount++}_${finalSettingName}_${roomId}`;
 
         const localizedCallback = (changedInRoomId: string | null, atLevel: SettingLevel, newValAtLevel: any): void => {
-            if (!SettingsStore.doesSettingSupportLevel(originalSettingName, atLevel)) {
+            if (!SettingsStore.doesSettingSupportLevel(settingName, atLevel)) {
                 logger.warn(
                     `Setting handler notified for an update of an invalid setting level: ` +
-                        `${originalSettingName}@${atLevel} - this likely means a weird setting value ` +
+                        `${settingName}@${atLevel} - this likely means a weird setting value ` +
                         `made it into the level's storage. The notification will be ignored.`,
                 );
                 return;
             }
-            const newValue = SettingsStore.getValue(originalSettingName);
-            const newValueAtLevel = SettingsStore.getValueAt(atLevel, originalSettingName) ?? newValAtLevel;
-            callbackFn(originalSettingName, changedInRoomId, atLevel, newValueAtLevel, newValue);
+            const newValue = SettingsStore.getValue(settingName);
+            const newValueAtLevel = SettingsStore.getValueAt(atLevel, settingName) ?? newValAtLevel;
+            callbackFn(settingName, changedInRoomId, atLevel, newValueAtLevel, newValue);
         };
 
         SettingsStore.watchers.set(watcherId, localizedCallback);
-        defaultWatchManager.watchSetting(settingName, roomId, localizedCallback);
+        defaultWatchManager.watchSetting(finalSettingName, roomId, localizedCallback);
 
         return watcherId;
     }
@@ -214,7 +211,7 @@ export default class SettingsStore {
      * @param {string} settingName The setting name to monitor.
      * @param {String} roomId The room ID to monitor for changes in. Use null for all rooms.
      */
-    public static monitorSetting(settingName: string, roomId: string | null): void {
+    public static monitorSetting(settingName: SettingKey, roomId: string | null): void {
         roomId = roomId || null; // the thing wants null specifically to work, so appease it.
 
         if (!this.monitors.has(settingName)) this.monitors.set(settingName, new Map());
@@ -262,7 +259,7 @@ export default class SettingsStore {
      * The level to get the display name for; Defaults to 'default'.
      * @return {String} The display name for the setting, or null if not found.
      */
-    public static getDisplayName(settingName: string, atLevel = SettingLevel.DEFAULT): string | null {
+    public static getDisplayName(settingName: SettingKey, atLevel = SettingLevel.DEFAULT): string | null {
         if (!SETTINGS[settingName] || !SETTINGS[settingName].displayName) return null;
 
         const displayName = SETTINGS[settingName].displayName;
@@ -285,7 +282,7 @@ export default class SettingsStore {
      * @param {string} settingName The setting to look up.
      * @return {String} The description for the setting, or null if not found.
      */
-    public static getDescription(settingName: string): string | ReactNode {
+    public static getDescription(settingName: SettingKey): string | ReactNode {
         const description = SETTINGS[settingName]?.description;
         if (!description) return null;
         if (typeof description !== "string") return description();
@@ -297,7 +294,7 @@ export default class SettingsStore {
      * @param {string} settingName The setting to look up.
      * @return {boolean} True if the setting is a feature.
      */
-    public static isFeature(settingName: string): boolean {
+    public static isFeature(settingName: SettingKey): boolean {
         if (!SETTINGS[settingName]) return false;
         return !!SETTINGS[settingName].isFeature;
     }
@@ -307,12 +304,12 @@ export default class SettingsStore {
      * @param {string} settingName The setting to look up.
      * @return {boolean} True if the setting should have a warning sign.
      */
-    public static shouldHaveWarning(settingName: string): boolean {
+    public static shouldHaveWarning(settingName: SettingKey): boolean {
         if (!SETTINGS[settingName]) return false;
         return SETTINGS[settingName].shouldWarn ?? false;
     }
 
-    public static getBetaInfo(settingName: string): ISetting["betaInfo"] {
+    public static getBetaInfo(settingName: SettingKey): ISetting["betaInfo"] {
         // consider a beta disabled if the config is explicitly set to false, in which case treat as normal Labs flag
         if (
             SettingsStore.isFeature(settingName) &&
@@ -327,7 +324,7 @@ export default class SettingsStore {
         }
     }
 
-    public static getLabGroup(settingName: string): LabGroup | undefined {
+    public static getLabGroup(settingName: SettingKey): LabGroup | undefined {
         if (SettingsStore.isFeature(settingName)) {
             return (<IFeature>SETTINGS[settingName]).labsGroup;
         }
@@ -340,7 +337,7 @@ export default class SettingsStore {
      * @param {string} settingName The setting to look up.
      * @return {string} The reason the setting is disabled.
      */
-    public static disabledMessage(settingName: string): string | undefined {
+    public static disabledMessage(settingName: SettingKey): string | undefined {
         const disabled = SETTINGS[settingName].controller?.settingDisabled;
         return typeof disabled === "string" ? disabled : undefined;
     }
@@ -353,7 +350,21 @@ export default class SettingsStore {
      * @param {boolean} excludeDefault True to disable using the default value.
      * @return {*} The value, or null if not found
      */
-    public static getValue<T = any>(settingName: string, roomId: string | null = null, excludeDefault = false): T {
+    public static getValue<S extends SettingKey>(
+        settingName: S,
+        roomId: string | null,
+        excludeDefault: true,
+    ): Settings[S]["default"] | undefined;
+    public static getValue<S extends SettingKey>(
+        settingName: S,
+        roomId?: string | null,
+        excludeDefault?: false,
+    ): Settings[S]["default"];
+    public static getValue<S extends SettingKey>(
+        settingName: S,
+        roomId: string | null = null,
+        excludeDefault = false,
+    ): Settings[S]["default"] | undefined {
         // Verify that the setting is actually a setting
         if (!SETTINGS[settingName]) {
             throw new Error("Setting '" + settingName + "' does not appear to be a setting.");
@@ -362,7 +373,7 @@ export default class SettingsStore {
         const setting = SETTINGS[settingName];
         const levelOrder = getLevelOrder(setting);
 
-        return SettingsStore.getValueAt<T>(levelOrder[0], settingName, roomId, false, excludeDefault);
+        return SettingsStore.getValueAt(levelOrder[0], settingName, roomId, false, excludeDefault);
     }
 
     /**
@@ -376,13 +387,13 @@ export default class SettingsStore {
      * @param {boolean} excludeDefault True to disable using the default value.
      * @return {*} The value, or null if not found.
      */
-    public static getValueAt<T = any>(
+    public static getValueAt<S extends SettingKey>(
         level: SettingLevel,
-        settingName: string,
+        settingName: S,
         roomId: string | null = null,
         explicit = false,
         excludeDefault = false,
-    ): T {
+    ): Settings[S]["default"] {
         // Verify that the setting is actually a setting
         const setting = SETTINGS[settingName];
         if (!setting) {
@@ -399,9 +410,10 @@ export default class SettingsStore {
 
         // Check if we need to invert the setting at all. Do this after we get the setting
         // handlers though, otherwise we'll fail to read the value.
+        let finalSettingName: string = settingName;
         if (setting.invertedSettingName) {
             //console.warn(`Inverting ${settingName} to be ${setting.invertedSettingName} - legacy setting`);
-            settingName = setting.invertedSettingName;
+            finalSettingName = setting.invertedSettingName;
         }
 
         if (explicit) {
@@ -409,7 +421,7 @@ export default class SettingsStore {
             if (!handler) {
                 return SettingsStore.getFinalValue(setting, level, roomId, null, null);
             }
-            const value = handler.getValue(settingName, roomId);
+            const value = handler.getValue(finalSettingName, roomId);
             return SettingsStore.getFinalValue(setting, level, roomId, value, level);
         }
 
@@ -418,7 +430,7 @@ export default class SettingsStore {
             if (!handler) continue;
             if (excludeDefault && levelOrder[i] === "default") continue;
 
-            const value = handler.getValue(settingName, roomId);
+            const value = handler.getValue(finalSettingName, roomId);
             if (value === null || value === undefined) continue;
             return SettingsStore.getFinalValue(setting, level, roomId, value, levelOrder[i]);
         }
@@ -432,7 +444,7 @@ export default class SettingsStore {
      * @param {String} roomId The room ID to read the setting value in, may be null.
      * @return {*} The default value
      */
-    public static getDefaultValue(settingName: string): any {
+    public static getDefaultValue(settingName: SettingKey): any {
         // Verify that the setting is actually a setting
         if (!SETTINGS[settingName]) {
             throw new Error("Setting '" + settingName + "' does not appear to be a setting.");
@@ -474,7 +486,7 @@ export default class SettingsStore {
 
     /* eslint-enable valid-jsdoc */
     public static async setValue(
-        settingName: string,
+        settingName: SettingKey,
         roomId: string | null,
         level: SettingLevel,
         value: any,
@@ -490,24 +502,25 @@ export default class SettingsStore {
             throw new Error("Setting " + settingName + " does not have a handler for " + level);
         }
 
+        let finalSettingName: string = settingName;
         if (setting.invertedSettingName) {
             // Note: We can't do this when the `level` is "default", however we also
             // know that the user can't possible change the default value through this
             // function so we don't bother checking it.
             //console.warn(`Inverting ${settingName} to be ${setting.invertedSettingName} - legacy setting`);
-            settingName = setting.invertedSettingName;
+            finalSettingName = setting.invertedSettingName;
             value = !value;
         }
 
-        if (!handler.canSetValue(settingName, roomId)) {
-            throw new Error("User cannot set " + settingName + " at " + level + " in " + roomId);
+        if (!handler.canSetValue(finalSettingName, roomId)) {
+            throw new Error("User cannot set " + finalSettingName + " at " + level + " in " + roomId);
         }
 
         if (setting.controller && !(await setting.controller.beforeChange(level, roomId, value))) {
             return; // controller says no
         }
 
-        await handler.setValue(settingName, roomId, value);
+        await handler.setValue(finalSettingName, roomId, value);
 
         setting.controller?.onChange(level, roomId, value);
     }
@@ -530,7 +543,7 @@ export default class SettingsStore {
      * @param {SettingLevel} level The level to check at.
      * @return {boolean} True if the user may set the setting, false otherwise.
      */
-    public static canSetValue(settingName: string, roomId: string | null, level: SettingLevel): boolean {
+    public static canSetValue(settingName: SettingKey, roomId: string | null, level: SettingLevel): boolean {
         const setting = SETTINGS[settingName];
         // Verify that the setting is actually a setting
         if (!setting) {
@@ -563,7 +576,7 @@ export default class SettingsStore {
      * @returns
      */
     public static settingIsOveriddenAtConfigLevel(
-        settingName: string,
+        settingName: SettingKey,
         roomId: string | null,
         level: SettingLevel,
     ): boolean {
@@ -597,7 +610,7 @@ export default class SettingsStore {
      * the level itself can be supported by the runtime (ie: you will need to call #isLevelSupported()
      * on your own).
      */
-    public static doesSettingSupportLevel(settingName: string, level: SettingLevel): boolean {
+    public static doesSettingSupportLevel(settingName: SettingKey, level: SettingLevel): boolean {
         const setting = SETTINGS[settingName];
         if (!setting) {
             throw new Error("Setting '" + settingName + "' does not appear to be a setting.");
@@ -612,7 +625,7 @@ export default class SettingsStore {
      * @param {string} settingName The setting name.
      * @return {SettingLevel}
      */
-    public static firstSupportedLevel(settingName: string): SettingLevel | null {
+    public static firstSupportedLevel(settingName: SettingKey): SettingLevel | null {
         // Verify that the setting is actually a setting
         const setting = SETTINGS[settingName];
         if (!setting) {
@@ -699,7 +712,7 @@ export default class SettingsStore {
      * @param {string} realSettingName The setting name to try and read.
      * @param {string} roomId Optional room ID to test the setting in.
      */
-    public static debugSetting(realSettingName: string, roomId: string): void {
+    public static debugSetting(realSettingName: SettingKey, roomId: string): void {
         logger.log(`--- DEBUG ${realSettingName}`);
 
         // Note: we intentionally use JSON.stringify here to avoid the console masking the
@@ -711,7 +724,7 @@ export default class SettingsStore {
         logger.log(`--- default level order: ${JSON.stringify(LEVEL_ORDER)}`);
         logger.log(`--- registered handlers: ${JSON.stringify(Object.keys(LEVEL_HANDLERS))}`);
 
-        const doChecks = (settingName: string): void => {
+        const doChecks = (settingName: SettingKey): void => {
             for (const handlerName of Object.keys(LEVEL_HANDLERS)) {
                 const handler = LEVEL_HANDLERS[handlerName as SettingLevel];
 
@@ -803,19 +816,19 @@ export default class SettingsStore {
         if (def.invertedSettingName) {
             logger.log(`--- TESTING INVERTED SETTING NAME`);
             logger.log(`--- inverted: ${def.invertedSettingName}`);
-            doChecks(def.invertedSettingName);
+            doChecks(def.invertedSettingName as SettingKey);
         }
 
         logger.log(`--- END DEBUG`);
     }
 
-    private static getHandler(settingName: string, level: SettingLevel): SettingsHandler | null {
+    private static getHandler(settingName: SettingKey, level: SettingLevel): SettingsHandler | null {
         const handlers = SettingsStore.getHandlers(settingName);
         if (!handlers[level]) return null;
         return handlers[level]!;
     }
 
-    private static getHandlers(settingName: string): HandlerMap {
+    private static getHandlers(settingName: SettingKey): HandlerMap {
         if (!SETTINGS[settingName]) return {};
 
         const handlers: Partial<Record<SettingLevel, SettingsHandler>> = {};
diff --git a/src/settings/UIFeature.ts b/src/settings/UIFeature.ts
index 238e8a233fc..4aef725d4a8 100644
--- a/src/settings/UIFeature.ts
+++ b/src/settings/UIFeature.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/settings/WatchManager.ts b/src/settings/WatchManager.ts
index 52403136c15..fd38ae3637f 100644
--- a/src/settings/WatchManager.ts
+++ b/src/settings/WatchManager.ts
@@ -1,7 +1,7 @@
 /*
 Copyright 2019-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/settings/controllers/AnalyticsController.ts b/src/settings/controllers/AnalyticsController.ts
index 9272753e51a..f2b432ef5b5 100644
--- a/src/settings/controllers/AnalyticsController.ts
+++ b/src/settings/controllers/AnalyticsController.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/settings/controllers/DeviceIsolationModeController.ts b/src/settings/controllers/DeviceIsolationModeController.ts
index fe932d0deb8..bbdca789cee 100644
--- a/src/settings/controllers/DeviceIsolationModeController.ts
+++ b/src/settings/controllers/DeviceIsolationModeController.ts
@@ -1,6 +1,7 @@
 /*
 Copyright 2024 New Vector Ltd.
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/settings/controllers/FallbackIceServerController.ts b/src/settings/controllers/FallbackIceServerController.ts
index 5fd8bee322d..e433b64ba3d 100644
--- a/src/settings/controllers/FallbackIceServerController.ts
+++ b/src/settings/controllers/FallbackIceServerController.ts
@@ -1,7 +1,7 @@
 /*
 Copyright 2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/settings/controllers/FontSizeController.ts b/src/settings/controllers/FontSizeController.ts
index d4b23b96cbc..762e18011e7 100644
--- a/src/settings/controllers/FontSizeController.ts
+++ b/src/settings/controllers/FontSizeController.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/settings/controllers/IncompatibleController.ts b/src/settings/controllers/IncompatibleController.ts
index 3dcce19c895..37100271f6b 100644
--- a/src/settings/controllers/IncompatibleController.ts
+++ b/src/settings/controllers/IncompatibleController.ts
@@ -2,13 +2,14 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 import SettingController from "./SettingController";
 import { SettingLevel } from "../SettingLevel";
 import SettingsStore from "../SettingsStore";
+import { BooleanSettingKey } from "../Settings.tsx";
 
 /**
  * Enforces that a boolean setting cannot be enabled if the incompatible setting
@@ -17,7 +18,7 @@ import SettingsStore from "../SettingsStore";
  */
 export default class IncompatibleController extends SettingController {
     public constructor(
-        private settingName: string,
+        private settingName: BooleanSettingKey,
         private forcedValue: any = false,
         private incompatibleValue: any | ((v: any) => boolean) = true,
     ) {
diff --git a/src/settings/controllers/MatrixClientBackedController.ts b/src/settings/controllers/MatrixClientBackedController.ts
index 15cc58e25ae..ab0ca82093a 100644
--- a/src/settings/controllers/MatrixClientBackedController.ts
+++ b/src/settings/controllers/MatrixClientBackedController.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/settings/controllers/NotificationControllers.ts b/src/settings/controllers/NotificationControllers.ts
index da3ef6d859f..effb7aee59a 100644
--- a/src/settings/controllers/NotificationControllers.ts
+++ b/src/settings/controllers/NotificationControllers.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 Copyright 2017 Travis Ralston
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/settings/controllers/ReducedMotionController.ts b/src/settings/controllers/ReducedMotionController.ts
index 11207fe3039..38d2477fc3e 100644
--- a/src/settings/controllers/ReducedMotionController.ts
+++ b/src/settings/controllers/ReducedMotionController.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/settings/controllers/ReloadOnChangeController.ts b/src/settings/controllers/ReloadOnChangeController.ts
index 2e1bb15b778..ace6d108d2a 100644
--- a/src/settings/controllers/ReloadOnChangeController.ts
+++ b/src/settings/controllers/ReloadOnChangeController.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/settings/controllers/ServerSupportUnstableFeatureController.ts b/src/settings/controllers/ServerSupportUnstableFeatureController.ts
index f2ca2c0b07c..9da9e3befca 100644
--- a/src/settings/controllers/ServerSupportUnstableFeatureController.ts
+++ b/src/settings/controllers/ServerSupportUnstableFeatureController.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -10,6 +10,7 @@ import { SettingLevel } from "../SettingLevel";
 import MatrixClientBackedController from "./MatrixClientBackedController";
 import { WatchManager } from "../WatchManager";
 import SettingsStore from "../SettingsStore";
+import { SettingKey } from "../Settings.tsx";
 
 /**
  * Disables a given setting if the server unstable feature it requires is not supported
@@ -28,7 +29,7 @@ export default class ServerSupportUnstableFeatureController extends MatrixClient
      * the features in the group are supported (all features in a group are required).
      */
     public constructor(
-        private readonly settingName: string,
+        private readonly settingName: SettingKey,
         private readonly watchers: WatchManager,
         private readonly unstableFeatureGroups: string[][],
         private readonly stableVersion?: string,
diff --git a/src/settings/controllers/SettingController.ts b/src/settings/controllers/SettingController.ts
index 63922f64a8e..821b3d20321 100644
--- a/src/settings/controllers/SettingController.ts
+++ b/src/settings/controllers/SettingController.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 Copyright 2017 Travis Ralston
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/settings/controllers/SlidingSyncController.ts b/src/settings/controllers/SlidingSyncController.ts
index eccff0ab906..11ae1a2ba02 100644
--- a/src/settings/controllers/SlidingSyncController.ts
+++ b/src/settings/controllers/SlidingSyncController.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2024 Ed Geraghty <ed@geraghty.family>
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/settings/controllers/SystemFontController.ts b/src/settings/controllers/SystemFontController.ts
index d1cc107ca1b..70fab9eda9c 100644
--- a/src/settings/controllers/SystemFontController.ts
+++ b/src/settings/controllers/SystemFontController.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/settings/controllers/ThemeController.ts b/src/settings/controllers/ThemeController.ts
index 69f091c4361..a192a4d0801 100644
--- a/src/settings/controllers/ThemeController.ts
+++ b/src/settings/controllers/ThemeController.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
 Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/settings/controllers/UIFeatureController.ts b/src/settings/controllers/UIFeatureController.ts
index e6548909dea..5371751a3c0 100644
--- a/src/settings/controllers/UIFeatureController.ts
+++ b/src/settings/controllers/UIFeatureController.ts
@@ -2,13 +2,14 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 import SettingController from "./SettingController";
 import { SettingLevel } from "../SettingLevel";
 import SettingsStore from "../SettingsStore";
+import { SettingKey } from "../Settings.tsx";
 
 /**
  * Enforces that a boolean setting cannot be enabled if the corresponding
@@ -19,7 +20,7 @@ import SettingsStore from "../SettingsStore";
  */
 export default class UIFeatureController extends SettingController {
     public constructor(
-        private uiFeatureName: string,
+        private uiFeatureName: SettingKey,
         private forcedValue = false,
     ) {
         super();
diff --git a/src/settings/enums/ImageSize.ts b/src/settings/enums/ImageSize.ts
index 1ce293a5362..394ee6b4fe9 100644
--- a/src/settings/enums/ImageSize.ts
+++ b/src/settings/enums/ImageSize.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/settings/enums/Layout.ts b/src/settings/enums/Layout.ts
index 9054dd55822..1bf560a8fd0 100644
--- a/src/settings/enums/Layout.ts
+++ b/src/settings/enums/Layout.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
 Copyright 2021 Quirin Götz <codeworks@supercable.onl>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/settings/enums/UseCase.tsx b/src/settings/enums/UseCase.tsx
deleted file mode 100644
index 07b24f90283..00000000000
--- a/src/settings/enums/UseCase.tsx
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2022 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
-Please see LICENSE files in the repository root for full details.
-*/
-
-export enum UseCase {
-    PersonalMessaging = "PersonalMessaging",
-    WorkMessaging = "WorkMessaging",
-    CommunityMessaging = "CommunityMessaging",
-    Skip = "Skip",
-}
diff --git a/src/settings/handlers/AbstractLocalStorageSettingsHandler.ts b/src/settings/handlers/AbstractLocalStorageSettingsHandler.ts
index 70cdedffe15..e6e2288319b 100644
--- a/src/settings/handlers/AbstractLocalStorageSettingsHandler.ts
+++ b/src/settings/handlers/AbstractLocalStorageSettingsHandler.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/settings/handlers/AccountSettingsHandler.ts b/src/settings/handlers/AccountSettingsHandler.ts
index 051e6fc7a61..05005569316 100644
--- a/src/settings/handlers/AccountSettingsHandler.ts
+++ b/src/settings/handlers/AccountSettingsHandler.ts
@@ -3,11 +3,11 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
 Copyright 2017 Travis Ralston
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
-import { ClientEvent, MatrixClient, MatrixEvent } from "matrix-js-sdk/src/matrix";
+import { AccountDataEvents, ClientEvent, MatrixClient, MatrixEvent } from "matrix-js-sdk/src/matrix";
 import { defer } from "matrix-js-sdk/src/utils";
 import { isEqual } from "lodash";
 
@@ -140,11 +140,11 @@ export default class AccountSettingsHandler extends MatrixClientBackedSettingsHa
     }
 
     // helper function to set account data then await it being echoed back
-    private async setAccountData(
-        eventType: string,
-        field: string,
-        value: any,
-        legacyEventType?: string,
+    private async setAccountData<K extends keyof AccountDataEvents, F extends keyof AccountDataEvents[K]>(
+        eventType: K,
+        field: F,
+        value: AccountDataEvents[K][F],
+        legacyEventType?: keyof AccountDataEvents,
     ): Promise<void> {
         let content = this.getSettings(eventType);
         if (legacyEventType && !content?.[field]) {
@@ -161,7 +161,8 @@ export default class AccountSettingsHandler extends MatrixClientBackedSettingsHa
         // which race between different lines.
         const deferred = defer<void>();
         const handler = (event: MatrixEvent): void => {
-            if (event.getType() !== eventType || !isEqual(event.getContent()[field], value)) return;
+            if (event.getType() !== eventType || !isEqual(event.getContent<AccountDataEvents[K]>()[field], value))
+                return;
             this.client.off(ClientEvent.AccountData, handler);
             deferred.resolve();
         };
@@ -212,7 +213,7 @@ export default class AccountSettingsHandler extends MatrixClientBackedSettingsHa
         return this.client && !this.client.isGuest();
     }
 
-    private getSettings(eventType = "im.vector.web.settings"): any {
+    private getSettings(eventType: keyof AccountDataEvents = "im.vector.web.settings"): any {
         // TODO: [TS] Types on return
         if (!this.client) return null;
 
diff --git a/src/settings/handlers/ConfigSettingsHandler.ts b/src/settings/handlers/ConfigSettingsHandler.ts
index 06e694bc38c..1dd0e19dc5b 100644
--- a/src/settings/handlers/ConfigSettingsHandler.ts
+++ b/src/settings/handlers/ConfigSettingsHandler.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
 Copyright 2017 Travis Ralston
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/settings/handlers/DefaultSettingsHandler.ts b/src/settings/handlers/DefaultSettingsHandler.ts
index 758a8c0c0d1..a005525b4cb 100644
--- a/src/settings/handlers/DefaultSettingsHandler.ts
+++ b/src/settings/handlers/DefaultSettingsHandler.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
 Copyright 2017 Travis Ralston
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/settings/handlers/DeviceSettingsHandler.ts b/src/settings/handlers/DeviceSettingsHandler.ts
index 0fe5ef74112..5feb0c1db38 100644
--- a/src/settings/handlers/DeviceSettingsHandler.ts
+++ b/src/settings/handlers/DeviceSettingsHandler.ts
@@ -4,7 +4,7 @@ Copyright 2019-2022 The Matrix.org Foundation C.I.C.
 Copyright 2019 New Vector Ltd.
 Copyright 2017 Travis Ralston
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/settings/handlers/LocalEchoWrapper.ts b/src/settings/handlers/LocalEchoWrapper.ts
index 7d5050c9b8e..2c44fca8a4e 100644
--- a/src/settings/handlers/LocalEchoWrapper.ts
+++ b/src/settings/handlers/LocalEchoWrapper.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
 Copyright 2017 Travis Ralston
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/settings/handlers/MatrixClientBackedSettingsHandler.ts b/src/settings/handlers/MatrixClientBackedSettingsHandler.ts
index 86b3071a0ea..84d56dcecf2 100644
--- a/src/settings/handlers/MatrixClientBackedSettingsHandler.ts
+++ b/src/settings/handlers/MatrixClientBackedSettingsHandler.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/settings/handlers/PlatformSettingsHandler.ts b/src/settings/handlers/PlatformSettingsHandler.ts
index 2ea350fdd8a..fb16b182fe2 100644
--- a/src/settings/handlers/PlatformSettingsHandler.ts
+++ b/src/settings/handlers/PlatformSettingsHandler.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/settings/handlers/RoomAccountSettingsHandler.ts b/src/settings/handlers/RoomAccountSettingsHandler.ts
index 7e7242b62bf..73a83d4575e 100644
--- a/src/settings/handlers/RoomAccountSettingsHandler.ts
+++ b/src/settings/handlers/RoomAccountSettingsHandler.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
 Copyright 2017 Travis Ralston
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/settings/handlers/RoomDeviceSettingsHandler.ts b/src/settings/handlers/RoomDeviceSettingsHandler.ts
index 6e4324fad8d..cf7c17ced68 100644
--- a/src/settings/handlers/RoomDeviceSettingsHandler.ts
+++ b/src/settings/handlers/RoomDeviceSettingsHandler.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019, 2020 - 2022 The Matrix.org Foundation C.I.C.
 Copyright 2017 Travis Ralston
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/settings/handlers/RoomSettingsHandler.ts b/src/settings/handlers/RoomSettingsHandler.ts
index d67acf5d0f5..dd6bc48a012 100644
--- a/src/settings/handlers/RoomSettingsHandler.ts
+++ b/src/settings/handlers/RoomSettingsHandler.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
 Copyright 2017 Travis Ralston
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/settings/handlers/SettingsHandler.ts b/src/settings/handlers/SettingsHandler.ts
index 158e45847e2..43ec57cc135 100644
--- a/src/settings/handlers/SettingsHandler.ts
+++ b/src/settings/handlers/SettingsHandler.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
 Copyright 2017 Travis Ralston
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/settings/watchers/FontWatcher.ts b/src/settings/watchers/FontWatcher.ts
index 64a6a27f581..6be4b925819 100644
--- a/src/settings/watchers/FontWatcher.ts
+++ b/src/settings/watchers/FontWatcher.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020-2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -57,7 +57,7 @@ export class FontWatcher implements IWatcher {
      * @private
      */
     private async migrateBaseFontV1toFontSizeDelta(): Promise<void> {
-        const legacyBaseFontSize = SettingsStore.getValue<number>("baseFontSize");
+        const legacyBaseFontSize = SettingsStore.getValue("baseFontSize");
         // No baseFontV1 found, nothing to migrate
         if (!legacyBaseFontSize) return;
 
@@ -82,7 +82,7 @@ export class FontWatcher implements IWatcher {
      * @private
      */
     private async migrateBaseFontV2toFontSizeDelta(): Promise<void> {
-        const legacyBaseFontV2Size = SettingsStore.getValue<number>("baseFontSizeV2");
+        const legacyBaseFontV2Size = SettingsStore.getValue("baseFontSizeV2");
         // No baseFontV2 found, nothing to migrate
         if (!legacyBaseFontV2Size) return;
 
@@ -140,7 +140,7 @@ export class FontWatcher implements IWatcher {
      * @returns {number} the default font size of the browser
      */
     public static getBrowserDefaultFontSize(): number {
-        return this.getRootFontSize() - SettingsStore.getValue<number>("fontSizeDelta");
+        return this.getRootFontSize() - SettingsStore.getValue("fontSizeDelta");
     }
 
     public stop(): void {
@@ -148,7 +148,7 @@ export class FontWatcher implements IWatcher {
     }
 
     private updateFont(): void {
-        this.setRootFontSize(SettingsStore.getValue<number>("fontSizeDelta"));
+        this.setRootFontSize(SettingsStore.getValue("fontSizeDelta"));
         this.setSystemFont({
             useBundledEmojiFont: SettingsStore.getValue("useBundledEmojiFont"),
             useSystemFont: SettingsStore.getValue("useSystemFont"),
diff --git a/src/settings/watchers/ThemeWatcher.ts b/src/settings/watchers/ThemeWatcher.ts
index d0f00c52d9a..4d0c4a7171f 100644
--- a/src/settings/watchers/ThemeWatcher.ts
+++ b/src/settings/watchers/ThemeWatcher.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
 Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/settings/watchers/Watcher.ts b/src/settings/watchers/Watcher.ts
index 9a5b37b3d6d..903db56ac3a 100644
--- a/src/settings/watchers/Watcher.ts
+++ b/src/settings/watchers/Watcher.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/shouldHideEvent.ts b/src/shouldHideEvent.ts
index 7948bfb9f92..e97afd0fbdd 100644
--- a/src/shouldHideEvent.ts
+++ b/src/shouldHideEvent.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2017 Michael Telatynski <7t3chguy@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
  */
 
@@ -11,6 +11,7 @@ import { KnownMembership } from "matrix-js-sdk/src/types";
 
 import SettingsStore from "./settings/SettingsStore";
 import { IRoomState } from "./components/structures/RoomView";
+import { SettingKey } from "./settings/Settings.tsx";
 
 interface IDiff {
     isMemberEvent: boolean;
@@ -53,7 +54,7 @@ export default function shouldHideEvent(ev: MatrixEvent, ctx?: IRoomState): bool
     // so we should prefer using cached values if a RoomContext is available
     const isEnabled = ctx
         ? (name: keyof IRoomState) => ctx[name]
-        : (name: string) => SettingsStore.getValue(name, ev.getRoomId());
+        : (name: SettingKey) => SettingsStore.getValue(name, ev.getRoomId());
 
     // Hide redacted events
     // Deleted events with a thread are always shown regardless of user preference
diff --git a/src/slash-commands/command.ts b/src/slash-commands/command.ts
index 22ab875894f..01c62277239 100644
--- a/src/slash-commands/command.ts
+++ b/src/slash-commands/command.ts
@@ -5,7 +5,7 @@ Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
 Copyright 2018 New Vector Ltd
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/slash-commands/interface.ts b/src/slash-commands/interface.ts
index 43d3cc7e27b..6f1f0c8af42 100644
--- a/src/slash-commands/interface.ts
+++ b/src/slash-commands/interface.ts
@@ -5,7 +5,7 @@ Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
 Copyright 2018 New Vector Ltd
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/slash-commands/join.ts b/src/slash-commands/join.ts
index 886e17e2303..de548cba5f1 100644
--- a/src/slash-commands/join.ts
+++ b/src/slash-commands/join.ts
@@ -5,7 +5,7 @@ Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
 Copyright 2018 New Vector Ltd
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/slash-commands/op.ts b/src/slash-commands/op.ts
index ff575575b04..77084bc7a07 100644
--- a/src/slash-commands/op.ts
+++ b/src/slash-commands/op.ts
@@ -5,7 +5,7 @@ Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
 Copyright 2018 New Vector Ltd
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/slash-commands/utils.ts b/src/slash-commands/utils.ts
index 073820364ec..8bdade9cf12 100644
--- a/src/slash-commands/utils.ts
+++ b/src/slash-commands/utils.ts
@@ -5,7 +5,7 @@ Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
 Copyright 2018 New Vector Ltd
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/AccountPasswordStore.ts b/src/stores/AccountPasswordStore.ts
deleted file mode 100644
index 85bb7359e19..00000000000
--- a/src/stores/AccountPasswordStore.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2023 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
-Please see LICENSE files in the repository root for full details.
-*/
-
-const PASSWORD_TIMEOUT = 5 * 60 * 1000; // five minutes
-
-/**
- * Store for the account password.
- * This password can be used for a short time after login
- * to avoid requestin the password all the time for instance during e2ee setup.
- */
-export class AccountPasswordStore {
-    private password?: string;
-    private passwordTimeoutId?: ReturnType<typeof setTimeout>;
-
-    public setPassword(password: string): void {
-        this.password = password;
-        clearTimeout(this.passwordTimeoutId);
-        this.passwordTimeoutId = setTimeout(this.clearPassword, PASSWORD_TIMEOUT);
-    }
-
-    public getPassword(): string | undefined {
-        return this.password;
-    }
-
-    public clearPassword = (): void => {
-        clearTimeout(this.passwordTimeoutId);
-        this.passwordTimeoutId = undefined;
-        this.password = undefined;
-    };
-}
diff --git a/src/stores/ActiveWidgetStore.ts b/src/stores/ActiveWidgetStore.ts
index c3db7888fde..8d591552248 100644
--- a/src/stores/ActiveWidgetStore.ts
+++ b/src/stores/ActiveWidgetStore.ts
@@ -1,7 +1,7 @@
 /*
 Copyright 2018-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/AsyncStore.ts b/src/stores/AsyncStore.ts
index 4baf8072473..8f73bdb10a2 100644
--- a/src/stores/AsyncStore.ts
+++ b/src/stores/AsyncStore.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/AsyncStoreWithClient.ts b/src/stores/AsyncStoreWithClient.ts
index a131614c7c1..598594ca3b9 100644
--- a/src/stores/AsyncStoreWithClient.ts
+++ b/src/stores/AsyncStoreWithClient.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/AutoRageshakeStore.ts b/src/stores/AutoRageshakeStore.ts
index 284c3e24a4d..a972099473a 100644
--- a/src/stores/AutoRageshakeStore.ts
+++ b/src/stores/AutoRageshakeStore.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/BreadcrumbsStore.ts b/src/stores/BreadcrumbsStore.ts
index 9859f240154..c02d1181fe7 100644
--- a/src/stores/BreadcrumbsStore.ts
+++ b/src/stores/BreadcrumbsStore.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020, 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -127,7 +127,7 @@ export class BreadcrumbsStore extends AsyncStoreWithClient<IState> {
     };
 
     private async updateRooms(): Promise<void> {
-        let roomIds = SettingsStore.getValue<string[]>("breadcrumb_rooms");
+        let roomIds = SettingsStore.getValue("breadcrumb_rooms");
         if (!roomIds || roomIds.length === 0) roomIds = [];
 
         const rooms = filterBoolean(roomIds.map((r) => this.matrixClient?.getRoom(r)));
diff --git a/src/stores/CallStore.ts b/src/stores/CallStore.ts
index 115a56aced2..d667e0b811b 100644
--- a/src/stores/CallStore.ts
+++ b/src/stores/CallStore.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -61,7 +61,7 @@ export class CallStore extends AsyncStoreWithClient<{}> {
         // If the room ID of a previously connected call is still in settings at
         // this time, that's a sign that we failed to disconnect from it
         // properly, and need to clean up after ourselves
-        const uncleanlyDisconnectedRoomIds = SettingsStore.getValue<string[]>("activeCallRoomIds");
+        const uncleanlyDisconnectedRoomIds = SettingsStore.getValue("activeCallRoomIds");
         if (uncleanlyDisconnectedRoomIds.length) {
             await Promise.all([
                 ...uncleanlyDisconnectedRoomIds.map(async (uncleanlyDisconnectedRoomId): Promise<void> => {
diff --git a/src/stores/InitialCryptoSetupStore.ts b/src/stores/InitialCryptoSetupStore.ts
index 5554a15d260..593b9c1108e 100644
--- a/src/stores/InitialCryptoSetupStore.ts
+++ b/src/stores/InitialCryptoSetupStore.ts
@@ -1,7 +1,7 @@
 /*
 Copyright 2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -11,7 +11,6 @@ import { logger } from "matrix-js-sdk/src/logger";
 import { useEffect, useState } from "react";
 
 import { createCrossSigning } from "../CreateCrossSigning";
-import { SdkContextClass } from "../contexts/SDKContext";
 
 type Status = "in_progress" | "complete" | "error" | undefined;
 
@@ -45,8 +44,6 @@ export class InitialCryptoSetupStore extends EventEmitter {
     private status: Status = undefined;
 
     private client?: MatrixClient;
-    private isTokenLogin?: boolean;
-    private stores?: SdkContextClass;
     private onFinished?: (success: boolean) => void;
 
     public static sharedInstance(): InitialCryptoSetupStore {
@@ -62,18 +59,9 @@ export class InitialCryptoSetupStore extends EventEmitter {
      * Start the initial crypto setup process.
      *
      * @param {MatrixClient} client The client to use for the setup
-     * @param {boolean} isTokenLogin True if the user logged in via a token login, otherwise false
-     * @param {SdkContextClass} stores The stores to use for the setup
      */
-    public startInitialCryptoSetup(
-        client: MatrixClient,
-        isTokenLogin: boolean,
-        stores: SdkContextClass,
-        onFinished: (success: boolean) => void,
-    ): void {
+    public startInitialCryptoSetup(client: MatrixClient, onFinished: (success: boolean) => void): void {
         this.client = client;
-        this.isTokenLogin = isTokenLogin;
-        this.stores = stores;
         this.onFinished = onFinished;
 
         // We just start this process: it's progress is tracked by the events rather
@@ -89,7 +77,7 @@ export class InitialCryptoSetupStore extends EventEmitter {
      * @returns {boolean} True if a retry was initiated, otherwise false
      */
     public retry(): boolean {
-        if (this.client === undefined || this.isTokenLogin === undefined || this.stores == undefined) return false;
+        if (this.client === undefined) return false;
 
         this.doSetup().catch(() => logger.error("Initial crypto setup failed"));
 
@@ -98,12 +86,10 @@ export class InitialCryptoSetupStore extends EventEmitter {
 
     private reset(): void {
         this.client = undefined;
-        this.isTokenLogin = undefined;
-        this.stores = undefined;
     }
 
     private async doSetup(): Promise<void> {
-        if (this.client === undefined || this.isTokenLogin === undefined || this.stores == undefined) {
+        if (this.client === undefined) {
             throw new Error("No setup is in progress");
         }
 
@@ -115,7 +101,7 @@ export class InitialCryptoSetupStore extends EventEmitter {
 
         try {
             // Create the user's cross-signing keys
-            await createCrossSigning(this.client, this.isTokenLogin, this.stores.accountPasswordStore.getPassword());
+            await createCrossSigning(this.client);
 
             // Check for any existing backup and enable key backup if there isn't one
             const currentKeyBackup = await cryptoApi.checkKeyBackupAndEnable();
@@ -129,16 +115,6 @@ export class InitialCryptoSetupStore extends EventEmitter {
             this.emit("update");
             this.onFinished?.(true);
         } catch (e) {
-            if (this.isTokenLogin) {
-                // ignore any failures, we are relying on grace period here
-                this.reset();
-
-                this.status = "complete";
-                this.emit("update");
-                this.onFinished?.(true);
-
-                return;
-            }
             logger.error("Error bootstrapping cross-signing", e);
             this.status = "error";
             this.emit("update");
diff --git a/src/stores/LifecycleStore.ts b/src/stores/LifecycleStore.ts
index a918814abd1..8a369cb51e4 100644
--- a/src/stores/LifecycleStore.ts
+++ b/src/stores/LifecycleStore.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2017-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/MemberListStore.ts b/src/stores/MemberListStore.ts
index e500dec84c6..12878c4ec9c 100644
--- a/src/stores/MemberListStore.ts
+++ b/src/stores/MemberListStore.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/ModalWidgetStore.ts b/src/stores/ModalWidgetStore.ts
index 59437db403c..9f5ddca25d4 100644
--- a/src/stores/ModalWidgetStore.ts
+++ b/src/stores/ModalWidgetStore.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/NonUrgentToastStore.ts b/src/stores/NonUrgentToastStore.ts
index fc05fb02cd9..97a4bbdfdf6 100644
--- a/src/stores/NonUrgentToastStore.ts
+++ b/src/stores/NonUrgentToastStore.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/OwnBeaconStore.ts b/src/stores/OwnBeaconStore.ts
index ccd4bf33a3d..72c67c3635f 100644
--- a/src/stores/OwnBeaconStore.ts
+++ b/src/stores/OwnBeaconStore.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/OwnProfileStore.ts b/src/stores/OwnProfileStore.ts
index be8c72aa230..ef721ee4aa3 100644
--- a/src/stores/OwnProfileStore.ts
+++ b/src/stores/OwnProfileStore.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/ReadyWatchingStore.ts b/src/stores/ReadyWatchingStore.ts
index 922e8b83936..cb99cf12688 100644
--- a/src/stores/ReadyWatchingStore.ts
+++ b/src/stores/ReadyWatchingStore.ts
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2021, 2022 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/src/stores/ReleaseAnnouncementStore.ts b/src/stores/ReleaseAnnouncementStore.ts
index ba6a79fec0f..05362dde5a9 100644
--- a/src/stores/ReleaseAnnouncementStore.ts
+++ b/src/stores/ReleaseAnnouncementStore.ts
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2024 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
@@ -26,7 +26,9 @@ export type Feature = (typeof FEATURES)[number];
  * The stored settings for the release announcements.
  * The boolean is at true when the user has viewed the feature
  */
-type StoredSettings = Record<Feature, boolean>;
+type StoredSettings = Partial<Record<Feature, boolean>>;
+
+export type ReleaseAnnouncementData = StoredSettings;
 
 /**
  * The events emitted by the ReleaseAnnouncementStore.
@@ -82,7 +84,7 @@ export class ReleaseAnnouncementStore extends TypedEventEmitter<ReleaseAnnouncem
      */
     private getViewedReleaseAnnouncements(): StoredSettings {
         // Clone the settings to avoid to mutate the internal stored value in the SettingsStore
-        return cloneDeep(SettingsStore.getValue<StoredSettings>("releaseAnnouncementData"));
+        return cloneDeep(SettingsStore.getValue("releaseAnnouncementData"));
     }
 
     /**
@@ -90,7 +92,7 @@ export class ReleaseAnnouncementStore extends TypedEventEmitter<ReleaseAnnouncem
      * @private
      */
     private isReleaseAnnouncementEnabled(): boolean {
-        return SettingsStore.getValue<boolean>(Features.ReleaseAnnouncement);
+        return SettingsStore.getValue(Features.ReleaseAnnouncement);
     }
 
     /**
diff --git a/src/stores/RoomScrollStateStore.ts b/src/stores/RoomScrollStateStore.ts
index 21ffb03be62..b072200e024 100644
--- a/src/stores/RoomScrollStateStore.ts
+++ b/src/stores/RoomScrollStateStore.ts
@@ -1,7 +1,7 @@
 /*
 Copyright 2017-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/RoomViewStore.tsx b/src/stores/RoomViewStore.tsx
index 66644c06a1f..822a6a9dd1f 100644
--- a/src/stores/RoomViewStore.tsx
+++ b/src/stores/RoomViewStore.tsx
@@ -4,7 +4,7 @@ Copyright 2019-2022 The Matrix.org Foundation C.I.C.
 Copyright 2017, 2018 New Vector Ltd
 Copyright 2017 Vector Creations Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/SetupEncryptionStore.ts b/src/stores/SetupEncryptionStore.ts
index a13ba26f722..3aa6ad18661 100644
--- a/src/stores/SetupEncryptionStore.ts
+++ b/src/stores/SetupEncryptionStore.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020-2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -19,7 +19,6 @@ import { Device, SecretStorage } from "matrix-js-sdk/src/matrix";
 
 import { MatrixClientPeg } from "../MatrixClientPeg";
 import { AccessCancelledError, accessSecretStorage } from "../SecurityManager";
-import { SdkContextClass } from "../contexts/SDKContext";
 import { asyncSome } from "../utils/arrays";
 import { initialiseDehydration } from "../utils/device/dehydration";
 
@@ -239,7 +238,6 @@ export class SetupEncryptionStore extends EventEmitter {
                 {
                     forceReset: true,
                     resetCrossSigning: true,
-                    accountPassword: SdkContextClass.instance.accountPasswordStore.getPassword(),
                 },
             );
         } catch (e) {
diff --git a/src/stores/ThreepidInviteStore.ts b/src/stores/ThreepidInviteStore.ts
index bdb1c8faa26..92fa7d5bd8d 100644
--- a/src/stores/ThreepidInviteStore.ts
+++ b/src/stores/ThreepidInviteStore.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/ToastStore.ts b/src/stores/ToastStore.ts
index e2f9a61f3d9..3ebb0d945cc 100644
--- a/src/stores/ToastStore.ts
+++ b/src/stores/ToastStore.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/TypingStore.ts b/src/stores/TypingStore.ts
index f836bda0453..26fd4967e7b 100644
--- a/src/stores/TypingStore.ts
+++ b/src/stores/TypingStore.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/UIStore.ts b/src/stores/UIStore.ts
index c058cda8a37..0792bb206d1 100644
--- a/src/stores/UIStore.ts
+++ b/src/stores/UIStore.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/UserProfilesStore.ts b/src/stores/UserProfilesStore.ts
index cc122498d83..eb3c25a3090 100644
--- a/src/stores/UserProfilesStore.ts
+++ b/src/stores/UserProfilesStore.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/VoiceRecordingStore.ts b/src/stores/VoiceRecordingStore.ts
index 7cbb8ac120a..b94301f62cc 100644
--- a/src/stores/VoiceRecordingStore.ts
+++ b/src/stores/VoiceRecordingStore.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021, 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/WidgetEchoStore.ts b/src/stores/WidgetEchoStore.ts
index 255ce1932f9..ef81ec10d76 100644
--- a/src/stores/WidgetEchoStore.ts
+++ b/src/stores/WidgetEchoStore.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2018-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/WidgetStore.ts b/src/stores/WidgetStore.ts
index cfb92360a0d..8c697709303 100644
--- a/src/stores/WidgetStore.ts
+++ b/src/stores/WidgetStore.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -17,17 +17,11 @@ import WidgetEchoStore from "../stores/WidgetEchoStore";
 import ActiveWidgetStore from "../stores/ActiveWidgetStore";
 import WidgetUtils from "../utils/WidgetUtils";
 import { UPDATE_EVENT } from "./AsyncStore";
+import { IApp } from "../utils/WidgetUtils-types";
 
 interface IState {}
 
-export interface IApp extends IWidget {
-    "roomId": string;
-    "eventId"?: string; // not present on virtual widgets
-    // eslint-disable-next-line camelcase
-    "avatar_url"?: string; // MSC2765 https://github.com/matrix-org/matrix-doc/pull/2765
-    // Whether the widget was created from `widget_build_url` and thus is a call widget of some kind
-    "io.element.managed_hybrid"?: boolean;
-}
+export type { IApp };
 
 export function isAppWidget(widget: IWidget | IApp): widget is IApp {
     return "roomId" in widget && typeof widget.roomId === "string";
diff --git a/src/stores/local-echo/EchoChamber.ts b/src/stores/local-echo/EchoChamber.ts
index 11292df9e9a..1cc9bd981ed 100644
--- a/src/stores/local-echo/EchoChamber.ts
+++ b/src/stores/local-echo/EchoChamber.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/local-echo/EchoContext.ts b/src/stores/local-echo/EchoContext.ts
index a51b5022aed..17ba5710d4f 100644
--- a/src/stores/local-echo/EchoContext.ts
+++ b/src/stores/local-echo/EchoContext.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/local-echo/EchoStore.ts b/src/stores/local-echo/EchoStore.ts
index 956eacb929a..c38995cd4e8 100644
--- a/src/stores/local-echo/EchoStore.ts
+++ b/src/stores/local-echo/EchoStore.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/local-echo/EchoTransaction.ts b/src/stores/local-echo/EchoTransaction.ts
index 0293c0d548c..421e334ad03 100644
--- a/src/stores/local-echo/EchoTransaction.ts
+++ b/src/stores/local-echo/EchoTransaction.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/local-echo/GenericEchoChamber.ts b/src/stores/local-echo/GenericEchoChamber.ts
index e287561fe37..3bda937d3c7 100644
--- a/src/stores/local-echo/GenericEchoChamber.ts
+++ b/src/stores/local-echo/GenericEchoChamber.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/local-echo/RoomEchoChamber.ts b/src/stores/local-echo/RoomEchoChamber.ts
index 9298d5ffed2..e3188752265 100644
--- a/src/stores/local-echo/RoomEchoChamber.ts
+++ b/src/stores/local-echo/RoomEchoChamber.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/local-echo/RoomEchoContext.ts b/src/stores/local-echo/RoomEchoContext.ts
index 20eb0cf6534..ae8573c9224 100644
--- a/src/stores/local-echo/RoomEchoContext.ts
+++ b/src/stores/local-echo/RoomEchoContext.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/notifications/ListNotificationState.ts b/src/stores/notifications/ListNotificationState.ts
index 77bd174f09a..f6af7d35c77 100644
--- a/src/stores/notifications/ListNotificationState.ts
+++ b/src/stores/notifications/ListNotificationState.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020-2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/notifications/NotificationLevel.ts b/src/stores/notifications/NotificationLevel.ts
index 7b370ef658a..8d28e19503f 100644
--- a/src/stores/notifications/NotificationLevel.ts
+++ b/src/stores/notifications/NotificationLevel.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/notifications/NotificationState.ts b/src/stores/notifications/NotificationState.ts
index 6f4044d57b8..9c72c9fef03 100644
--- a/src/stores/notifications/NotificationState.ts
+++ b/src/stores/notifications/NotificationState.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/notifications/RoomNotificationState.ts b/src/stores/notifications/RoomNotificationState.ts
index 3a66a051aec..c4f677130d2 100644
--- a/src/stores/notifications/RoomNotificationState.ts
+++ b/src/stores/notifications/RoomNotificationState.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020-2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/notifications/RoomNotificationStateStore.ts b/src/stores/notifications/RoomNotificationStateStore.ts
index 87fb276c101..c58125b0bab 100644
--- a/src/stores/notifications/RoomNotificationStateStore.ts
+++ b/src/stores/notifications/RoomNotificationStateStore.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020-2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/notifications/SpaceNotificationState.ts b/src/stores/notifications/SpaceNotificationState.ts
index ead72d15b46..e5aedf63179 100644
--- a/src/stores/notifications/SpaceNotificationState.ts
+++ b/src/stores/notifications/SpaceNotificationState.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021, 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/notifications/StaticNotificationState.ts b/src/stores/notifications/StaticNotificationState.ts
index b554d0483fe..293c6f45e33 100644
--- a/src/stores/notifications/StaticNotificationState.ts
+++ b/src/stores/notifications/StaticNotificationState.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/notifications/SummarizedNotificationState.ts b/src/stores/notifications/SummarizedNotificationState.ts
index e859fd6070e..0d223834e6e 100644
--- a/src/stores/notifications/SummarizedNotificationState.ts
+++ b/src/stores/notifications/SummarizedNotificationState.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/oidc/OidcClientStore.ts b/src/stores/oidc/OidcClientStore.ts
index e0cc8702347..f814b1a6cc2 100644
--- a/src/stores/oidc/OidcClientStore.ts
+++ b/src/stores/oidc/OidcClientStore.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/right-panel/RightPanelStore.ts b/src/stores/right-panel/RightPanelStore.ts
index 99b2d7fe507..ea9b722071d 100644
--- a/src/stores/right-panel/RightPanelStore.ts
+++ b/src/stores/right-panel/RightPanelStore.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -252,10 +252,13 @@ export default class RightPanelStore extends ReadyWatchingStore {
             const room = this.mxClient?.getRoom(this.viewedRoomId);
             if (!!room) {
                 this.global =
-                    this.global ?? convertToStatePanel(SettingsStore.getValue("RightPanel.phasesGlobal"), room);
+                    this.global ??
+                    convertToStatePanel(SettingsStore.getValue("RightPanel.phasesGlobal"), room) ??
+                    undefined;
                 this.byRoom[this.viewedRoomId] =
                     this.byRoom[this.viewedRoomId] ??
-                    convertToStatePanel(SettingsStore.getValue("RightPanel.phases", this.viewedRoomId), room);
+                    convertToStatePanel(SettingsStore.getValue("RightPanel.phases", this.viewedRoomId), room) ??
+                    undefined;
             } else {
                 logger.warn(
                     "Could not restore the right panel after load because there was no associated room object.",
diff --git a/src/stores/right-panel/RightPanelStoreIPanelState.ts b/src/stores/right-panel/RightPanelStoreIPanelState.ts
index 0d205abd2fa..1ee5f2a95de 100644
--- a/src/stores/right-panel/RightPanelStoreIPanelState.ts
+++ b/src/stores/right-panel/RightPanelStoreIPanelState.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -57,10 +57,10 @@ export interface IRightPanelForRoom {
     history: Array<IRightPanelCard>;
 }
 
-interface IRightPanelForRoomStored {
+export type IRightPanelForRoomStored = {
     isOpen: boolean;
     history: Array<IRightPanelCardStored>;
-}
+};
 
 export function convertToStorePanel(cacheRoom?: IRightPanelForRoom): IRightPanelForRoomStored | undefined {
     if (!cacheRoom) return undefined;
@@ -68,7 +68,7 @@ export function convertToStorePanel(cacheRoom?: IRightPanelForRoom): IRightPanel
     return { isOpen: cacheRoom.isOpen, history: storeHistory };
 }
 
-export function convertToStatePanel(storeRoom: IRightPanelForRoomStored, room: Room): IRightPanelForRoom {
+export function convertToStatePanel(storeRoom: IRightPanelForRoomStored | null, room: Room): IRightPanelForRoom | null {
     if (!storeRoom) return storeRoom;
     const stateHistory = [...storeRoom.history].map((panelStateStore) => convertStoreToCard(panelStateStore, room));
     return { history: stateHistory, isOpen: storeRoom.isOpen };
diff --git a/src/stores/right-panel/RightPanelStorePhases.ts b/src/stores/right-panel/RightPanelStorePhases.ts
index 9e7a5697bfa..ea47f2ba839 100644
--- a/src/stores/right-panel/RightPanelStorePhases.ts
+++ b/src/stores/right-panel/RightPanelStorePhases.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/right-panel/action-handlers/View3pidInvite.ts b/src/stores/right-panel/action-handlers/View3pidInvite.ts
index 0f6661819f6..8a54c56c994 100644
--- a/src/stores/right-panel/action-handlers/View3pidInvite.ts
+++ b/src/stores/right-panel/action-handlers/View3pidInvite.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/right-panel/action-handlers/index.ts b/src/stores/right-panel/action-handlers/index.ts
index 287d3a9324d..5a612f9830d 100644
--- a/src/stores/right-panel/action-handlers/index.ts
+++ b/src/stores/right-panel/action-handlers/index.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/room-list/Interface.ts b/src/stores/room-list/Interface.ts
index bba230f7d46..f9e32b6f40a 100644
--- a/src/stores/room-list/Interface.ts
+++ b/src/stores/room-list/Interface.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/room-list/ListLayout.ts b/src/stores/room-list/ListLayout.ts
index ff60309e087..e85703fa5f3 100644
--- a/src/stores/room-list/ListLayout.ts
+++ b/src/stores/room-list/ListLayout.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/room-list/MessagePreviewStore.ts b/src/stores/room-list/MessagePreviewStore.ts
index 2577b2ba235..3f1614df702 100644
--- a/src/stores/room-list/MessagePreviewStore.ts
+++ b/src/stores/room-list/MessagePreviewStore.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/room-list/RoomListLayoutStore.ts b/src/stores/room-list/RoomListLayoutStore.ts
index ea85860554c..90461a581c0 100644
--- a/src/stores/room-list/RoomListLayoutStore.ts
+++ b/src/stores/room-list/RoomListLayoutStore.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/room-list/RoomListStore.ts b/src/stores/room-list/RoomListStore.ts
index 53377e0a01f..0b179f7db54 100644
--- a/src/stores/room-list/RoomListStore.ts
+++ b/src/stores/room-list/RoomListStore.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2018-2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/room-list/SlidingRoomListStore.ts b/src/stores/room-list/SlidingRoomListStore.ts
index 26d3291625c..ba585f32181 100644
--- a/src/stores/room-list/SlidingRoomListStore.ts
+++ b/src/stores/room-list/SlidingRoomListStore.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/room-list/SpaceWatcher.ts b/src/stores/room-list/SpaceWatcher.ts
index c3fa57f706c..1757637c706 100644
--- a/src/stores/room-list/SpaceWatcher.ts
+++ b/src/stores/room-list/SpaceWatcher.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/room-list/algorithms/Algorithm.ts b/src/stores/room-list/algorithms/Algorithm.ts
index c3450d70cf6..2ae3a1ff995 100644
--- a/src/stores/room-list/algorithms/Algorithm.ts
+++ b/src/stores/room-list/algorithms/Algorithm.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020, 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/room-list/algorithms/list-ordering/ImportanceAlgorithm.ts b/src/stores/room-list/algorithms/list-ordering/ImportanceAlgorithm.ts
index 829251a24f1..492e9ed4e70 100644
--- a/src/stores/room-list/algorithms/list-ordering/ImportanceAlgorithm.ts
+++ b/src/stores/room-list/algorithms/list-ordering/ImportanceAlgorithm.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 Copyright 2018, 2019 New Vector Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/room-list/algorithms/list-ordering/NaturalAlgorithm.ts b/src/stores/room-list/algorithms/list-ordering/NaturalAlgorithm.ts
index e6d743605f3..f44b0e1aec2 100644
--- a/src/stores/room-list/algorithms/list-ordering/NaturalAlgorithm.ts
+++ b/src/stores/room-list/algorithms/list-ordering/NaturalAlgorithm.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/room-list/algorithms/list-ordering/OrderingAlgorithm.ts b/src/stores/room-list/algorithms/list-ordering/OrderingAlgorithm.ts
index 67ee1ca0843..5cf7631cfeb 100644
--- a/src/stores/room-list/algorithms/list-ordering/OrderingAlgorithm.ts
+++ b/src/stores/room-list/algorithms/list-ordering/OrderingAlgorithm.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/room-list/algorithms/list-ordering/index.ts b/src/stores/room-list/algorithms/list-ordering/index.ts
index 7bd8441d9d3..aae3242a09a 100644
--- a/src/stores/room-list/algorithms/list-ordering/index.ts
+++ b/src/stores/room-list/algorithms/list-ordering/index.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/room-list/algorithms/models.ts b/src/stores/room-list/algorithms/models.ts
index 9c14e29c38d..7cc9bd1c17e 100644
--- a/src/stores/room-list/algorithms/models.ts
+++ b/src/stores/room-list/algorithms/models.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/room-list/algorithms/tag-sorting/AlphabeticAlgorithm.ts b/src/stores/room-list/algorithms/tag-sorting/AlphabeticAlgorithm.ts
index 17fecee2628..77f530bad43 100644
--- a/src/stores/room-list/algorithms/tag-sorting/AlphabeticAlgorithm.ts
+++ b/src/stores/room-list/algorithms/tag-sorting/AlphabeticAlgorithm.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/room-list/algorithms/tag-sorting/IAlgorithm.ts b/src/stores/room-list/algorithms/tag-sorting/IAlgorithm.ts
index 4aec903922c..eea3db1db35 100644
--- a/src/stores/room-list/algorithms/tag-sorting/IAlgorithm.ts
+++ b/src/stores/room-list/algorithms/tag-sorting/IAlgorithm.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/room-list/algorithms/tag-sorting/ManualAlgorithm.ts b/src/stores/room-list/algorithms/tag-sorting/ManualAlgorithm.ts
index 41a4422e0ec..7dd28695060 100644
--- a/src/stores/room-list/algorithms/tag-sorting/ManualAlgorithm.ts
+++ b/src/stores/room-list/algorithms/tag-sorting/ManualAlgorithm.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/room-list/algorithms/tag-sorting/RecentAlgorithm.ts b/src/stores/room-list/algorithms/tag-sorting/RecentAlgorithm.ts
index d30703d2886..2c6375e7dfe 100644
--- a/src/stores/room-list/algorithms/tag-sorting/RecentAlgorithm.ts
+++ b/src/stores/room-list/algorithms/tag-sorting/RecentAlgorithm.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/room-list/algorithms/tag-sorting/index.ts b/src/stores/room-list/algorithms/tag-sorting/index.ts
index 2536dbb41de..912ae5d167f 100644
--- a/src/stores/room-list/algorithms/tag-sorting/index.ts
+++ b/src/stores/room-list/algorithms/tag-sorting/index.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/room-list/filters/IFilterCondition.ts b/src/stores/room-list/filters/IFilterCondition.ts
index 9600ed73fb3..00248ff7405 100644
--- a/src/stores/room-list/filters/IFilterCondition.ts
+++ b/src/stores/room-list/filters/IFilterCondition.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020, 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/room-list/filters/SpaceFilterCondition.ts b/src/stores/room-list/filters/SpaceFilterCondition.ts
index 8f652a35fb6..7c4316ff21a 100644
--- a/src/stores/room-list/filters/SpaceFilterCondition.ts
+++ b/src/stores/room-list/filters/SpaceFilterCondition.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/room-list/filters/VisibilityProvider.ts b/src/stores/room-list/filters/VisibilityProvider.ts
index bf8c515fc96..4332ba0f98b 100644
--- a/src/stores/room-list/filters/VisibilityProvider.ts
+++ b/src/stores/room-list/filters/VisibilityProvider.ts
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2020 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/src/stores/room-list/models.ts b/src/stores/room-list/models.ts
index 50cecda6650..78823cbc421 100644
--- a/src/stores/room-list/models.ts
+++ b/src/stores/room-list/models.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/room-list/previews/IPreview.ts b/src/stores/room-list/previews/IPreview.ts
index b737044f684..6defb8bfd85 100644
--- a/src/stores/room-list/previews/IPreview.ts
+++ b/src/stores/room-list/previews/IPreview.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/room-list/previews/LegacyCallAnswerEventPreview.ts b/src/stores/room-list/previews/LegacyCallAnswerEventPreview.ts
index 54c46e5541d..eaf2de5e169 100644
--- a/src/stores/room-list/previews/LegacyCallAnswerEventPreview.ts
+++ b/src/stores/room-list/previews/LegacyCallAnswerEventPreview.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/room-list/previews/LegacyCallHangupEvent.ts b/src/stores/room-list/previews/LegacyCallHangupEvent.ts
index b213160b669..58487db6508 100644
--- a/src/stores/room-list/previews/LegacyCallHangupEvent.ts
+++ b/src/stores/room-list/previews/LegacyCallHangupEvent.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/room-list/previews/LegacyCallInviteEventPreview.ts b/src/stores/room-list/previews/LegacyCallInviteEventPreview.ts
index 1b9f33b5b17..4b3d20e6db0 100644
--- a/src/stores/room-list/previews/LegacyCallInviteEventPreview.ts
+++ b/src/stores/room-list/previews/LegacyCallInviteEventPreview.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/room-list/previews/MessageEventPreview.ts b/src/stores/room-list/previews/MessageEventPreview.ts
index 20631f1425b..fe63ee1c1bb 100644
--- a/src/stores/room-list/previews/MessageEventPreview.ts
+++ b/src/stores/room-list/previews/MessageEventPreview.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/room-list/previews/PollStartEventPreview.ts b/src/stores/room-list/previews/PollStartEventPreview.ts
index 7548cf12f71..09679335c48 100644
--- a/src/stores/room-list/previews/PollStartEventPreview.ts
+++ b/src/stores/room-list/previews/PollStartEventPreview.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/room-list/previews/ReactionEventPreview.ts b/src/stores/room-list/previews/ReactionEventPreview.ts
index 0aa0cdcd4d9..cee18dda2be 100644
--- a/src/stores/room-list/previews/ReactionEventPreview.ts
+++ b/src/stores/room-list/previews/ReactionEventPreview.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/room-list/previews/StickerEventPreview.ts b/src/stores/room-list/previews/StickerEventPreview.ts
index 33bf1e6f6d0..a368e675e36 100644
--- a/src/stores/room-list/previews/StickerEventPreview.ts
+++ b/src/stores/room-list/previews/StickerEventPreview.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/room-list/previews/utils.ts b/src/stores/room-list/previews/utils.ts
index 7857ad75a9b..ffb1602829b 100644
--- a/src/stores/room-list/previews/utils.ts
+++ b/src/stores/room-list/previews/utils.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/room-list/utils/roomMute.ts b/src/stores/room-list/utils/roomMute.ts
index 9269cd1461a..df3dbb59149 100644
--- a/src/stores/room-list/utils/roomMute.ts
+++ b/src/stores/room-list/utils/roomMute.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/spaces/SpaceStore.ts b/src/stores/spaces/SpaceStore.ts
index 90358f3310d..50aa7748a55 100644
--- a/src/stores/spaces/SpaceStore.ts
+++ b/src/stores/spaces/SpaceStore.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021, 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -239,7 +239,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
         if (!isMetaSpace(space)) {
             cliSpace = this.matrixClient.getRoom(space);
             if (!cliSpace?.isSpaceRoom()) return;
-        } else if (!this.enabledMetaSpaces.includes(space as MetaSpace)) {
+        } else if (!this.enabledMetaSpaces.includes(space)) {
             return;
         }
 
@@ -1178,7 +1178,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
         }
 
         // restore selected state from last session if any and still valid
-        const lastSpaceId = window.localStorage.getItem(ACTIVE_SPACE_LS_KEY);
+        const lastSpaceId = window.localStorage.getItem(ACTIVE_SPACE_LS_KEY) as MetaSpace;
         const valid =
             lastSpaceId &&
             (!isMetaSpace(lastSpaceId) ? this.matrixClient.getRoom(lastSpaceId) : enabledMetaSpaces[lastSpaceId]);
diff --git a/src/stores/spaces/SpaceTreeLevelLayoutStore.ts b/src/stores/spaces/SpaceTreeLevelLayoutStore.ts
index 59385a92e64..f32d685e2de 100644
--- a/src/stores/spaces/SpaceTreeLevelLayoutStore.ts
+++ b/src/stores/spaces/SpaceTreeLevelLayoutStore.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/spaces/flattenSpaceHierarchy.ts b/src/stores/spaces/flattenSpaceHierarchy.ts
index 2a3356a7c43..15d583617d8 100644
--- a/src/stores/spaces/flattenSpaceHierarchy.ts
+++ b/src/stores/spaces/flattenSpaceHierarchy.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/stores/spaces/index.ts b/src/stores/spaces/index.ts
index 848fc008d3c..b8853d606ef 100644
--- a/src/stores/spaces/index.ts
+++ b/src/stores/spaces/index.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -48,7 +48,7 @@ export interface ISuggestedRoom extends HierarchyRoom {
     viaServers: string[];
 }
 
-export function isMetaSpace(spaceKey?: SpaceKey): boolean {
+export function isMetaSpace(spaceKey?: SpaceKey): spaceKey is MetaSpace {
     return (
         spaceKey === MetaSpace.Home ||
         spaceKey === MetaSpace.Favourites ||
diff --git a/src/stores/widgets/ElementWidgetActions.ts b/src/stores/widgets/ElementWidgetActions.ts
index ac1cee00efe..8e4142f77d1 100644
--- a/src/stores/widgets/ElementWidgetActions.ts
+++ b/src/stores/widgets/ElementWidgetActions.ts
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2020-2022 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/src/stores/widgets/ElementWidgetCapabilities.ts b/src/stores/widgets/ElementWidgetCapabilities.ts
index c5db7f77722..1cad4e14f76 100644
--- a/src/stores/widgets/ElementWidgetCapabilities.ts
+++ b/src/stores/widgets/ElementWidgetCapabilities.ts
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2020 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/src/stores/widgets/StopGapWidget.ts b/src/stores/widgets/StopGapWidget.ts
index 75dd158566a..97482cfa7b2 100644
--- a/src/stores/widgets/StopGapWidget.ts
+++ b/src/stores/widgets/StopGapWidget.ts
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2020-2022 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/src/stores/widgets/StopGapWidgetDriver.ts b/src/stores/widgets/StopGapWidgetDriver.ts
index e08a207c244..b99b69c40e0 100644
--- a/src/stores/widgets/StopGapWidgetDriver.ts
+++ b/src/stores/widgets/StopGapWidgetDriver.ts
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2020-2023 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/src/stores/widgets/WidgetLayoutStore.ts b/src/stores/widgets/WidgetLayoutStore.ts
index f0d3cafc83c..5e587c54871 100644
--- a/src/stores/widgets/WidgetLayoutStore.ts
+++ b/src/stores/widgets/WidgetLayoutStore.ts
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2021, 2022 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
@@ -25,9 +25,9 @@ import { Container, IStoredLayout, ILayoutStateEvent, WIDGET_LAYOUT_EVENT_TYPE,
 export type { IStoredLayout, ILayoutStateEvent };
 export { Container, WIDGET_LAYOUT_EVENT_TYPE };
 
-interface ILayoutSettings extends ILayoutStateEvent {
+export type ILayoutSettings = Partial<ILayoutStateEvent> & {
     overrides?: string; // event ID for layout state event, if present
-}
+};
 
 // Dev note: "Pinned" widgets are ones in the top container.
 export const MAX_PINNED = 3;
@@ -149,7 +149,7 @@ export class WidgetLayoutStore extends ReadyWatchingStore {
 
         const layoutEv = room.currentState.getStateEvents(WIDGET_LAYOUT_EVENT_TYPE, "");
         const legacyPinned = SettingsStore.getValue("Widgets.pinned", room.roomId);
-        let userLayout = SettingsStore.getValue<ILayoutSettings | null>("Widgets.layout", room.roomId);
+        let userLayout = SettingsStore.getValue("Widgets.layout", room.roomId);
 
         if (layoutEv && userLayout && userLayout.overrides !== layoutEv.getId()) {
             // For some other layout that we don't really care about. The user can reset this
diff --git a/src/stores/widgets/WidgetMessagingStore.ts b/src/stores/widgets/WidgetMessagingStore.ts
index 0388aeacb4c..f73fd15c513 100644
--- a/src/stores/widgets/WidgetMessagingStore.ts
+++ b/src/stores/widgets/WidgetMessagingStore.ts
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2020 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/src/stores/widgets/WidgetPermissionStore.ts b/src/stores/widgets/WidgetPermissionStore.ts
index ecae4f9c009..482704b65f3 100644
--- a/src/stores/widgets/WidgetPermissionStore.ts
+++ b/src/stores/widgets/WidgetPermissionStore.ts
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2020 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
@@ -53,10 +53,7 @@ export class WidgetPermissionStore {
     public setOIDCState(widget: Widget, kind: WidgetKind, roomId: string | undefined, newState: OIDCState): void {
         const settingsKey = this.packSettingKey(widget, kind, roomId);
 
-        let currentValues = SettingsStore.getValue<{
-            allow?: string[];
-            deny?: string[];
-        }>("widgetOpenIDPermissions");
+        let currentValues = SettingsStore.getValue("widgetOpenIDPermissions");
         if (!currentValues) {
             currentValues = {};
         }
diff --git a/src/stores/widgets/types.ts b/src/stores/widgets/types.ts
index 5627731c78b..b91edd5c350 100644
--- a/src/stores/widgets/types.ts
+++ b/src/stores/widgets/types.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/theme.ts b/src/theme.ts
index 94ae7cb6e40..de384021aaa 100644
--- a/src/theme.ts
+++ b/src/theme.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -263,9 +263,9 @@ export function getCustomTheme(themeName: string): CustomTheme {
     if (!customThemes) {
         throw new Error(`No custom themes set, can't set custom theme "${themeName}"`);
     }
-    const customTheme = customThemes.find((t: ITheme) => t.name === themeName);
+    const customTheme = customThemes.find((t: CustomTheme) => t.name === themeName);
     if (!customTheme) {
-        const knownNames = customThemes.map((t: ITheme) => t.name).join(", ");
+        const knownNames = customThemes.map((t: CustomTheme) => t.name).join(", ");
         throw new Error(`Can't find custom theme "${themeName}", only know ${knownNames}`);
     }
     return customTheme;
diff --git a/src/toasts/AnalyticsToast.tsx b/src/toasts/AnalyticsToast.tsx
index c9cd218b49e..8ac0c4710ae 100644
--- a/src/toasts/AnalyticsToast.tsx
+++ b/src/toasts/AnalyticsToast.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/toasts/BulkUnverifiedSessionsToast.ts b/src/toasts/BulkUnverifiedSessionsToast.ts
index 944ca9b7281..9df70cfb9d7 100644
--- a/src/toasts/BulkUnverifiedSessionsToast.ts
+++ b/src/toasts/BulkUnverifiedSessionsToast.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/toasts/DesktopNotificationsToast.ts b/src/toasts/DesktopNotificationsToast.ts
index ee801bdad8c..8d88d209fb7 100644
--- a/src/toasts/DesktopNotificationsToast.ts
+++ b/src/toasts/DesktopNotificationsToast.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/toasts/IncomingCallToast.tsx b/src/toasts/IncomingCallToast.tsx
index 58e6980733e..197c70186c8 100644
--- a/src/toasts/IncomingCallToast.tsx
+++ b/src/toasts/IncomingCallToast.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/toasts/IncomingLegacyCallToast.tsx b/src/toasts/IncomingLegacyCallToast.tsx
index bed46a00751..a8e96681980 100644
--- a/src/toasts/IncomingLegacyCallToast.tsx
+++ b/src/toasts/IncomingLegacyCallToast.tsx
@@ -5,7 +5,7 @@ Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
 Copyright 2018 New Vector Ltd
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/toasts/MobileGuideToast.ts b/src/toasts/MobileGuideToast.ts
index 5b8a617ac52..566ea6aa932 100644
--- a/src/toasts/MobileGuideToast.ts
+++ b/src/toasts/MobileGuideToast.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/toasts/ServerLimitToast.tsx b/src/toasts/ServerLimitToast.tsx
index f2ce2fb057f..d24f7c692cb 100644
--- a/src/toasts/ServerLimitToast.tsx
+++ b/src/toasts/ServerLimitToast.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/toasts/SetupEncryptionToast.ts b/src/toasts/SetupEncryptionToast.ts
index 406b51cf167..ecbf99f4b21 100644
--- a/src/toasts/SetupEncryptionToast.ts
+++ b/src/toasts/SetupEncryptionToast.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/toasts/UnverifiedSessionToast.tsx b/src/toasts/UnverifiedSessionToast.tsx
index b7eb963dee9..76d961233c2 100644
--- a/src/toasts/UnverifiedSessionToast.tsx
+++ b/src/toasts/UnverifiedSessionToast.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/toasts/UpdateToast.tsx b/src/toasts/UpdateToast.tsx
index 786b6263174..0abc95c066e 100644
--- a/src/toasts/UpdateToast.tsx
+++ b/src/toasts/UpdateToast.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/usercontent/index.ts b/src/usercontent/index.ts
index ceedf5e27a8..e780ea1ac1c 100644
--- a/src/usercontent/index.ts
+++ b/src/usercontent/index.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/AnimationUtils.ts b/src/utils/AnimationUtils.ts
index 31bd9d184ce..f88e0ce3034 100644
--- a/src/utils/AnimationUtils.ts
+++ b/src/utils/AnimationUtils.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/AutoDiscoveryUtils.tsx b/src/utils/AutoDiscoveryUtils.tsx
index 61e2f84f4da..efc8f285cfd 100644
--- a/src/utils/AutoDiscoveryUtils.tsx
+++ b/src/utils/AutoDiscoveryUtils.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/BrowserWorkarounds.ts b/src/utils/BrowserWorkarounds.ts
index 77127183d71..8a83d67d037 100644
--- a/src/utils/BrowserWorkarounds.ts
+++ b/src/utils/BrowserWorkarounds.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/DMRoomMap.ts b/src/utils/DMRoomMap.ts
index 0b595b54db5..77b4c655459 100644
--- a/src/utils/DMRoomMap.ts
+++ b/src/utils/DMRoomMap.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2016-2019 , 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/DecryptFile.ts b/src/utils/DecryptFile.ts
index acf5f551e76..25ea5838196 100644
--- a/src/utils/DecryptFile.ts
+++ b/src/utils/DecryptFile.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2016-2018 , 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/DialogOpener.ts b/src/utils/DialogOpener.ts
index 721f8d5c927..c7b2212a21b 100644
--- a/src/utils/DialogOpener.ts
+++ b/src/utils/DialogOpener.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/DirectoryUtils.ts b/src/utils/DirectoryUtils.ts
index f074dc3462e..ff2407f256a 100644
--- a/src/utils/DirectoryUtils.ts
+++ b/src/utils/DirectoryUtils.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2018-2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/EditorStateTransfer.ts b/src/utils/EditorStateTransfer.ts
index 908da8b8a38..e104a5244c4 100644
--- a/src/utils/EditorStateTransfer.ts
+++ b/src/utils/EditorStateTransfer.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/ErrorUtils.tsx b/src/utils/ErrorUtils.tsx
index 630243e3135..997dd568403 100644
--- a/src/utils/ErrorUtils.tsx
+++ b/src/utils/ErrorUtils.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2018-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/EventRenderingUtils.ts b/src/utils/EventRenderingUtils.ts
index ed8d4af1012..0bef43df122 100644
--- a/src/utils/EventRenderingUtils.ts
+++ b/src/utils/EventRenderingUtils.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/EventUtils.ts b/src/utils/EventUtils.ts
index d57cefa1b53..2ed3bceb0d7 100644
--- a/src/utils/EventUtils.ts
+++ b/src/utils/EventUtils.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/Feedback.ts b/src/utils/Feedback.ts
index ac219349712..2c2e55fb417 100644
--- a/src/utils/Feedback.ts
+++ b/src/utils/Feedback.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/FileDownloader.ts b/src/utils/FileDownloader.ts
index 19a159642b1..749b781f0a8 100644
--- a/src/utils/FileDownloader.ts
+++ b/src/utils/FileDownloader.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/FileUtils.ts b/src/utils/FileUtils.ts
index 2fb095d53c7..6792ad254e9 100644
--- a/src/utils/FileUtils.ts
+++ b/src/utils/FileUtils.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
 Copyright 2015-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/FixedRollingArray.ts b/src/utils/FixedRollingArray.ts
index aef4c3f3e40..e702f252c93 100644
--- a/src/utils/FixedRollingArray.ts
+++ b/src/utils/FixedRollingArray.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/FormattingUtils.ts b/src/utils/FormattingUtils.ts
index d16ced944a5..ae92cf61049 100644
--- a/src/utils/FormattingUtils.ts
+++ b/src/utils/FormattingUtils.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
 Copyright 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/IDestroyable.ts b/src/utils/IDestroyable.ts
index 6d9a8466f87..e5b9d19fbb9 100644
--- a/src/utils/IDestroyable.ts
+++ b/src/utils/IDestroyable.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/IdentityServerUtils.ts b/src/utils/IdentityServerUtils.ts
index 6fb2a100e6d..fd3de6b2f40 100644
--- a/src/utils/IdentityServerUtils.ts
+++ b/src/utils/IdentityServerUtils.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -20,7 +20,7 @@ export function setToDefaultIdentityServer(matrixClient: MatrixClient): void {
     const url = getDefaultIdentityServerUrl();
     // Account data change will update localstorage, client, etc through dispatcher
     matrixClient.setAccountData("m.identity_server", {
-        base_url: url,
+        base_url: url ?? null,
     });
 }
 
diff --git a/src/utils/Image.ts b/src/utils/Image.ts
index cb3b65169d2..eed70bdf32a 100644
--- a/src/utils/Image.ts
+++ b/src/utils/Image.ts
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2022 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/src/utils/JSON.ts b/src/utils/JSON.ts
index 815e5c0cb33..0d7493514a6 100644
--- a/src/utils/JSON.ts
+++ b/src/utils/JSON.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/KeyVerificationStateObserver.ts b/src/utils/KeyVerificationStateObserver.ts
index 3dfc4f3a5cd..64f50ab2011 100644
--- a/src/utils/KeyVerificationStateObserver.ts
+++ b/src/utils/KeyVerificationStateObserver.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/LazyValue.ts b/src/utils/LazyValue.ts
index 5f2d97c0efb..fdd4ab78f8a 100644
--- a/src/utils/LazyValue.ts
+++ b/src/utils/LazyValue.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/LruCache.ts b/src/utils/LruCache.ts
index d4ef27e6b59..bfff80d5d53 100644
--- a/src/utils/LruCache.ts
+++ b/src/utils/LruCache.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/MarkedExecution.ts b/src/utils/MarkedExecution.ts
index e20b66c9734..b27481d5169 100644
--- a/src/utils/MarkedExecution.ts
+++ b/src/utils/MarkedExecution.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/MatrixGlob.ts b/src/utils/MatrixGlob.ts
index 4150147293f..d22e398381b 100644
--- a/src/utils/MatrixGlob.ts
+++ b/src/utils/MatrixGlob.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/MediaEventHelper.ts b/src/utils/MediaEventHelper.ts
index ecb1250e280..118b5baadb7 100644
--- a/src/utils/MediaEventHelper.ts
+++ b/src/utils/MediaEventHelper.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/MegolmExportEncryption.ts b/src/utils/MegolmExportEncryption.ts
index fab3c7f7101..60d4a687cf6 100644
--- a/src/utils/MegolmExportEncryption.ts
+++ b/src/utils/MegolmExportEncryption.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 Copyright 2017 Vector Creations Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/MessageDiffUtils.tsx b/src/utils/MessageDiffUtils.tsx
index ff30b12cac1..08af2379e66 100644
--- a/src/utils/MessageDiffUtils.tsx
+++ b/src/utils/MessageDiffUtils.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2021 , 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/Mouse.ts b/src/utils/Mouse.ts
index a2716c68d0c..56fb8bfee73 100644
--- a/src/utils/Mouse.ts
+++ b/src/utils/Mouse.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/MultiInviter.ts b/src/utils/MultiInviter.ts
index b58663ebf06..1350eb94a43 100644
--- a/src/utils/MultiInviter.ts
+++ b/src/utils/MultiInviter.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2016-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/NativeEventUtils.ts b/src/utils/NativeEventUtils.ts
index 768e1baa528..eebd2fcb515 100644
--- a/src/utils/NativeEventUtils.ts
+++ b/src/utils/NativeEventUtils.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/PasswordScorer.ts b/src/utils/PasswordScorer.ts
index 7e68ccfa4dc..876461920cd 100644
--- a/src/utils/PasswordScorer.ts
+++ b/src/utils/PasswordScorer.ts
@@ -1,7 +1,7 @@
 /*
 Copyright 2018-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/PhasedRolloutFeature.ts b/src/utils/PhasedRolloutFeature.ts
index bf2c8ed810d..dd94ee5c897 100644
--- a/src/utils/PhasedRolloutFeature.ts
+++ b/src/utils/PhasedRolloutFeature.ts
@@ -1,7 +1,7 @@
 /*
 Copyright 2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/PinningUtils.ts b/src/utils/PinningUtils.ts
index a06a7da06b7..a1304598f7c 100644
--- a/src/utils/PinningUtils.ts
+++ b/src/utils/PinningUtils.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2017 Travis Ralston
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/PreferredRoomVersions.ts b/src/utils/PreferredRoomVersions.ts
index d6b3677005a..d3dac768560 100644
--- a/src/utils/PreferredRoomVersions.ts
+++ b/src/utils/PreferredRoomVersions.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/ReactUtils.tsx b/src/utils/ReactUtils.tsx
index ee7469945a3..2180aa81ae2 100644
--- a/src/utils/ReactUtils.tsx
+++ b/src/utils/ReactUtils.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/Reply.ts b/src/utils/Reply.ts
index a1baffa2c99..fee65a7b556 100644
--- a/src/utils/Reply.ts
+++ b/src/utils/Reply.ts
@@ -3,7 +3,7 @@
  * Copyright 2023 The Matrix.org Foundation C.I.C.
  * Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/src/utils/ResizeNotifier.ts b/src/utils/ResizeNotifier.ts
index 339c90b7efd..02b4848c2fa 100644
--- a/src/utils/ResizeNotifier.ts
+++ b/src/utils/ResizeNotifier.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/RoomUpgrade.ts b/src/utils/RoomUpgrade.ts
index 18b136b7095..8979b1f0c8c 100644
--- a/src/utils/RoomUpgrade.ts
+++ b/src/utils/RoomUpgrade.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/SearchInput.ts b/src/utils/SearchInput.ts
index a186ed3e2ac..34fd0575cd3 100644
--- a/src/utils/SearchInput.ts
+++ b/src/utils/SearchInput.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 Boluwatife Omosowon <boluomosowon@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/SessionLock.ts b/src/utils/SessionLock.ts
index e3d9d5ecc88..861c87ead55 100644
--- a/src/utils/SessionLock.ts
+++ b/src/utils/SessionLock.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/ShieldUtils.ts b/src/utils/ShieldUtils.ts
index 2b50a93f4ce..d1466609e47 100644
--- a/src/utils/ShieldUtils.ts
+++ b/src/utils/ShieldUtils.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/Singleflight.ts b/src/utils/Singleflight.ts
index 24581832085..f34c268bbd7 100644
--- a/src/utils/Singleflight.ts
+++ b/src/utils/Singleflight.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/SnakedObject.ts b/src/utils/SnakedObject.ts
index d5487a7b0c4..b376d33e4b3 100644
--- a/src/utils/SnakedObject.ts
+++ b/src/utils/SnakedObject.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/SortMembers.ts b/src/utils/SortMembers.ts
index f22c6e92346..2c76bb6ed49 100644
--- a/src/utils/SortMembers.ts
+++ b/src/utils/SortMembers.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/StorageAccess.ts b/src/utils/StorageAccess.ts
index bf6e5590226..90bf5e74a50 100644
--- a/src/utils/StorageAccess.ts
+++ b/src/utils/StorageAccess.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2021 , 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -44,6 +44,27 @@ async function idbInit(): Promise<void> {
     });
 }
 
+async function idbTransaction(
+    table: string,
+    mode: IDBTransactionMode,
+    fn: (objectStore: IDBObjectStore) => IDBRequest<any>,
+): Promise<any> {
+    if (!idb) {
+        await idbInit();
+    }
+    return new Promise((resolve, reject) => {
+        const txn = idb!.transaction([table], mode);
+        txn.onerror = reject;
+
+        const objectStore = txn.objectStore(table);
+        const request = fn(objectStore);
+        request.onerror = reject;
+        request.onsuccess = (): void => {
+            resolve(request.result);
+        };
+    });
+}
+
 /**
  * Loads an item from an IndexedDB table within the underlying `matrix-react-sdk` database.
  *
@@ -57,17 +78,7 @@ export async function idbLoad(table: string, key: string | string[]): Promise<an
     if (!idb) {
         await idbInit();
     }
-    return new Promise((resolve, reject) => {
-        const txn = idb!.transaction([table], "readonly");
-        txn.onerror = reject;
-
-        const objectStore = txn.objectStore(table);
-        const request = objectStore.get(key);
-        request.onerror = reject;
-        request.onsuccess = (event): void => {
-            resolve(request.result);
-        };
-    });
+    return idbTransaction(table, "readonly", (objectStore) => objectStore.get(key));
 }
 
 /**
@@ -84,17 +95,7 @@ export async function idbSave(table: string, key: string | string[], data: any):
     if (!idb) {
         await idbInit();
     }
-    return new Promise((resolve, reject) => {
-        const txn = idb!.transaction([table], "readwrite");
-        txn.onerror = reject;
-
-        const objectStore = txn.objectStore(table);
-        const request = objectStore.put(data, key);
-        request.onerror = reject;
-        request.onsuccess = (event): void => {
-            resolve();
-        };
-    });
+    return idbTransaction(table, "readwrite", (objectStore) => objectStore.put(data, key));
 }
 
 /**
@@ -110,15 +111,20 @@ export async function idbDelete(table: string, key: string | string[]): Promise<
     if (!idb) {
         await idbInit();
     }
-    return new Promise((resolve, reject) => {
-        const txn = idb!.transaction([table], "readwrite");
-        txn.onerror = reject;
+    return idbTransaction(table, "readwrite", (objectStore) => objectStore.delete(key));
+}
 
-        const objectStore = txn.objectStore(table);
-        const request = objectStore.delete(key);
-        request.onerror = reject;
-        request.onsuccess = (): void => {
-            resolve();
-        };
-    });
+/**
+ * Clears all records from an IndexedDB table within the underlying `matrix-react-sdk` database.
+ *
+ * If IndexedDB access is not supported in the environment, an error is thrown.
+ *
+ * @param {string} table The name of the object store where the records are stored.
+ * @returns {Promise<void>} A Promise that resolves when the record(s) have been successfully deleted.
+ */
+export async function idbClear(table: string): Promise<void> {
+    if (!idb) {
+        await idbInit();
+    }
+    return idbTransaction(table, "readwrite", (objectStore) => objectStore.clear());
 }
diff --git a/src/utils/StorageManager.ts b/src/utils/StorageManager.ts
index e4b0e627995..3b63f0a6366 100644
--- a/src/utils/StorageManager.ts
+++ b/src/utils/StorageManager.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/Timer.ts b/src/utils/Timer.ts
index 7db0476f7a5..ee05e39b347 100644
--- a/src/utils/Timer.ts
+++ b/src/utils/Timer.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2018-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/UrlUtils.ts b/src/utils/UrlUtils.ts
index f76855f6ef9..d256e655c2e 100644
--- a/src/utils/UrlUtils.ts
+++ b/src/utils/UrlUtils.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/ValidatedServerConfig.ts b/src/utils/ValidatedServerConfig.ts
index c5ab3d91492..a464514317e 100644
--- a/src/utils/ValidatedServerConfig.ts
+++ b/src/utils/ValidatedServerConfig.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/WellKnownUtils.ts b/src/utils/WellKnownUtils.ts
index 26bf6c287be..5634a94b59f 100644
--- a/src/utils/WellKnownUtils.ts
+++ b/src/utils/WellKnownUtils.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/Whenable.ts b/src/utils/Whenable.ts
index 51e4bfff46f..c584c4aa4c1 100644
--- a/src/utils/Whenable.ts
+++ b/src/utils/Whenable.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/WidgetUtils-types.ts b/src/utils/WidgetUtils-types.ts
new file mode 100644
index 00000000000..734a4d002ea
--- /dev/null
+++ b/src/utils/WidgetUtils-types.ts
@@ -0,0 +1,32 @@
+/*
+Copyright 2024 New Vector Ltd.
+Copyright 2017-2020 The Matrix.org Foundation C.I.C.
+Copyright 2019 Travis Ralston
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+Please see LICENSE files in the repository root for full details.
+*/
+
+import { IWidget } from "matrix-widget-api";
+
+export interface IApp extends IWidget {
+    "roomId": string;
+    "eventId"?: string; // not present on virtual widgets
+    // eslint-disable-next-line camelcase
+    "avatar_url"?: string; // MSC2765 https://github.com/matrix-org/matrix-doc/pull/2765
+    // Whether the widget was created from `widget_build_url` and thus is a call widget of some kind
+    "io.element.managed_hybrid"?: boolean;
+}
+
+export interface IWidgetEvent {
+    id: string;
+    type: string;
+    sender: string;
+    // eslint-disable-next-line camelcase
+    state_key: string;
+    content: IApp;
+}
+
+export interface UserWidget extends Omit<IWidgetEvent, "content"> {
+    content: IWidget & Partial<IApp>;
+}
diff --git a/src/utils/WidgetUtils.ts b/src/utils/WidgetUtils.ts
index ad2ed63ba16..d9de59e4013 100644
--- a/src/utils/WidgetUtils.ts
+++ b/src/utils/WidgetUtils.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2017-2020 The Matrix.org Foundation C.I.C.
 Copyright 2019 Travis Ralston
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -29,23 +29,13 @@ import WidgetStore, { IApp, isAppWidget } from "../stores/WidgetStore";
 import { parseUrl } from "./UrlUtils";
 import { useEventEmitter } from "../hooks/useEventEmitter";
 import { WidgetLayoutStore } from "../stores/widgets/WidgetLayoutStore";
+import { IWidgetEvent, UserWidget } from "./WidgetUtils-types";
 
 // How long we wait for the state event echo to come back from the server
 // before waitFor[Room/User]Widget rejects its promise
 const WIDGET_WAIT_TIME = 20000;
 
-export interface IWidgetEvent {
-    id: string;
-    type: string;
-    sender: string;
-    // eslint-disable-next-line camelcase
-    state_key: string;
-    content: IApp;
-}
-
-export interface UserWidget extends Omit<IWidgetEvent, "content"> {
-    content: IWidget & Partial<IApp>;
-}
+export type { IWidgetEvent, UserWidget };
 
 export default class WidgetUtils {
     /**
diff --git a/src/utils/arrays.ts b/src/utils/arrays.ts
index da8157adce1..b54e0949f21 100644
--- a/src/utils/arrays.ts
+++ b/src/utils/arrays.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020, 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -49,7 +49,6 @@ export function arrayFastResample(input: number[], points: number): number[] {
  * @param {number} points The number of samples to end up with.
  * @returns {number[]} The resampled array.
  */
-// ts-prune-ignore-next
 export function arraySmoothingResample(input: number[], points: number): number[] {
     if (input.length === points) return input; // short-circuit a complicated call
 
@@ -92,7 +91,6 @@ export function arraySmoothingResample(input: number[], points: number): number[
  * @param {number} newMax The maximum value to scale to.
  * @returns {number[]} The rescaled array.
  */
-// ts-prune-ignore-next
 export function arrayRescale(input: number[], newMin: number, newMax: number): number[] {
     const min: number = Math.min(...input);
     const max: number = Math.max(...input);
diff --git a/src/utils/beacon/bounds.ts b/src/utils/beacon/bounds.ts
index 7ce20182e0f..a23e3367da7 100644
--- a/src/utils/beacon/bounds.ts
+++ b/src/utils/beacon/bounds.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/beacon/duration.ts b/src/utils/beacon/duration.ts
index 2d5e4b52231..d967bb52172 100644
--- a/src/utils/beacon/duration.ts
+++ b/src/utils/beacon/duration.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/beacon/geolocation.ts b/src/utils/beacon/geolocation.ts
index f9d81c13c7f..8fbc15c8ca9 100644
--- a/src/utils/beacon/geolocation.ts
+++ b/src/utils/beacon/geolocation.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/beacon/getShareableLocation.ts b/src/utils/beacon/getShareableLocation.ts
index 01162d7399c..4a141ec969b 100644
--- a/src/utils/beacon/getShareableLocation.ts
+++ b/src/utils/beacon/getShareableLocation.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/beacon/index.ts b/src/utils/beacon/index.ts
index 7d956399957..19208f515e9 100644
--- a/src/utils/beacon/index.ts
+++ b/src/utils/beacon/index.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/beacon/timeline.ts b/src/utils/beacon/timeline.ts
index af8def8ac92..25e0e9c008d 100644
--- a/src/utils/beacon/timeline.ts
+++ b/src/utils/beacon/timeline.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/beacon/useBeacon.ts b/src/utils/beacon/useBeacon.ts
index a6d6ea9225e..80fe14abcd9 100644
--- a/src/utils/beacon/useBeacon.ts
+++ b/src/utils/beacon/useBeacon.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/beacon/useLiveBeacons.ts b/src/utils/beacon/useLiveBeacons.ts
index f465fd76d4f..c99faeb72f6 100644
--- a/src/utils/beacon/useLiveBeacons.ts
+++ b/src/utils/beacon/useLiveBeacons.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/beacon/useOwnLiveBeacons.ts b/src/utils/beacon/useOwnLiveBeacons.ts
index ff0890792ca..37387fda98b 100644
--- a/src/utils/beacon/useOwnLiveBeacons.ts
+++ b/src/utils/beacon/useOwnLiveBeacons.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/blobs.ts b/src/utils/blobs.ts
index 112bbfbcbd5..70ba54a0303 100644
--- a/src/utils/blobs.ts
+++ b/src/utils/blobs.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/colour.ts b/src/utils/colour.ts
index a96b68e12ed..40690060832 100644
--- a/src/utils/colour.ts
+++ b/src/utils/colour.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/connection.ts b/src/utils/connection.ts
index c11d1def682..9c2866d3051 100644
--- a/src/utils/connection.ts
+++ b/src/utils/connection.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/createMatrixClient.ts b/src/utils/createMatrixClient.ts
index 32274cdc44b..ad156b8ab42 100644
--- a/src/utils/createMatrixClient.ts
+++ b/src/utils/createMatrixClient.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2017-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 import {
diff --git a/src/utils/createVoiceMessageContent.ts b/src/utils/createVoiceMessageContent.ts
index f7b638fbcc4..eb40406dbca 100644
--- a/src/utils/createVoiceMessageContent.ts
+++ b/src/utils/createVoiceMessageContent.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/crypto/deviceInfo.ts b/src/utils/crypto/deviceInfo.ts
index 4392f7c5833..dda634545d3 100644
--- a/src/utils/crypto/deviceInfo.ts
+++ b/src/utils/crypto/deviceInfo.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/crypto/index.ts b/src/utils/crypto/index.ts
index f1b5c610732..d72702f8bd0 100644
--- a/src/utils/crypto/index.ts
+++ b/src/utils/crypto/index.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/crypto/shouldForceDisableEncryption.ts b/src/utils/crypto/shouldForceDisableEncryption.ts
index 8a59d9313ff..c30f58636e1 100644
--- a/src/utils/crypto/shouldForceDisableEncryption.ts
+++ b/src/utils/crypto/shouldForceDisableEncryption.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/crypto/shouldSkipSetupEncryption.ts b/src/utils/crypto/shouldSkipSetupEncryption.ts
index d4dbb27d1b2..c431833b76c 100644
--- a/src/utils/crypto/shouldSkipSetupEncryption.ts
+++ b/src/utils/crypto/shouldSkipSetupEncryption.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/device/clientInformation.ts b/src/utils/device/clientInformation.ts
index 500bfdd5508..a8e2383bfdf 100644
--- a/src/utils/device/clientInformation.ts
+++ b/src/utils/device/clientInformation.ts
@@ -2,21 +2,18 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
-import { MatrixClient } from "matrix-js-sdk/src/matrix";
+import { AccountDataEvents, MatrixClient } from "matrix-js-sdk/src/matrix";
 
 import BasePlatform from "../../BasePlatform";
 import { IConfigOptions } from "../../IConfigOptions";
 import { DeepReadonly } from "../../@types/common";
+import { DeviceClientInformation } from "./types";
 
-export type DeviceClientInformation = {
-    name?: string;
-    version?: string;
-    url?: string;
-};
+export type { DeviceClientInformation };
 
 const formatUrl = (): string | undefined => {
     // don't record url for electron clients
@@ -34,7 +31,8 @@ const formatUrl = (): string | undefined => {
 };
 
 const clientInformationEventPrefix = "io.element.matrix_client_information.";
-export const getClientInformationEventType = (deviceId: string): string => `${clientInformationEventPrefix}${deviceId}`;
+export const getClientInformationEventType = (deviceId: string): `${typeof clientInformationEventPrefix}${string}` =>
+    `${clientInformationEventPrefix}${deviceId}`;
 
 /**
  * Record extra client information for the current device
@@ -70,7 +68,7 @@ export const pruneClientInformation = (validDeviceIds: string[], matrixClient: M
         }
         const [, deviceId] = event.getType().split(clientInformationEventPrefix);
         if (deviceId && !validDeviceIds.includes(deviceId)) {
-            matrixClient.deleteAccountData(event.getType());
+            matrixClient.deleteAccountData(event.getType() as keyof AccountDataEvents);
         }
     });
 };
diff --git a/src/utils/device/dehydration.ts b/src/utils/device/dehydration.ts
index b27b3c54c26..d87d43e13a7 100644
--- a/src/utils/device/dehydration.ts
+++ b/src/utils/device/dehydration.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/device/isDeviceVerified.ts b/src/utils/device/isDeviceVerified.ts
index 1205225e7ca..0eacb4d54ea 100644
--- a/src/utils/device/isDeviceVerified.ts
+++ b/src/utils/device/isDeviceVerified.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/device/parseUserAgent.ts b/src/utils/device/parseUserAgent.ts
index 6dda013d09e..de21b2e0057 100644
--- a/src/utils/device/parseUserAgent.ts
+++ b/src/utils/device/parseUserAgent.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/device/snoozeBulkUnverifiedDeviceReminder.ts b/src/utils/device/snoozeBulkUnverifiedDeviceReminder.ts
index effc2a348b7..e4c8b649a02 100644
--- a/src/utils/device/snoozeBulkUnverifiedDeviceReminder.ts
+++ b/src/utils/device/snoozeBulkUnverifiedDeviceReminder.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/device/types.ts b/src/utils/device/types.ts
new file mode 100644
index 00000000000..e79b0ea2044
--- /dev/null
+++ b/src/utils/device/types.ts
@@ -0,0 +1,13 @@
+/*
+Copyright 2024 New Vector Ltd.
+Copyright 2022 The Matrix.org Foundation C.I.C.
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+Please see LICENSE files in the repository root for full details.
+*/
+
+export type DeviceClientInformation = {
+    name?: string;
+    version?: string;
+    url?: string;
+};
diff --git a/src/utils/direct-messages.ts b/src/utils/direct-messages.ts
index eee02f965ec..ef80016962e 100644
--- a/src/utils/direct-messages.ts
+++ b/src/utils/direct-messages.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/dm/createDmLocalRoom.ts b/src/utils/dm/createDmLocalRoom.ts
index 0a3d3123686..60dbf216b0f 100644
--- a/src/utils/dm/createDmLocalRoom.ts
+++ b/src/utils/dm/createDmLocalRoom.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/dm/filterValidMDirect.ts b/src/utils/dm/filterValidMDirect.ts
index 33fe922560d..5c7593dd99a 100644
--- a/src/utils/dm/filterValidMDirect.ts
+++ b/src/utils/dm/filterValidMDirect.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/dm/findDMForUser.ts b/src/utils/dm/findDMForUser.ts
index 0bdb23354dc..b5e13aebaaa 100644
--- a/src/utils/dm/findDMForUser.ts
+++ b/src/utils/dm/findDMForUser.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/dm/findDMRoom.ts b/src/utils/dm/findDMRoom.ts
index 466f8f24561..52c35ec084c 100644
--- a/src/utils/dm/findDMRoom.ts
+++ b/src/utils/dm/findDMRoom.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/dm/startDm.ts b/src/utils/dm/startDm.ts
index bb72925c41f..44b7b1d3d88 100644
--- a/src/utils/dm/startDm.ts
+++ b/src/utils/dm/startDm.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/enums.ts b/src/utils/enums.ts
index 0abc10da4bf..f138ce4cac1 100644
--- a/src/utils/enums.ts
+++ b/src/utils/enums.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020, 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/event/getSenderName.ts b/src/utils/event/getSenderName.ts
index bf87c71bdeb..450edd8f20c 100644
--- a/src/utils/event/getSenderName.ts
+++ b/src/utils/event/getSenderName.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/exportUtils/Exporter.ts b/src/utils/exportUtils/Exporter.ts
index 37757d8752a..0c549038b47 100644
--- a/src/utils/exportUtils/Exporter.ts
+++ b/src/utils/exportUtils/Exporter.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021, 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -110,12 +110,7 @@ export default abstract class Exporter {
     }
 
     protected setEventMetadata(event: MatrixEvent): MatrixEvent {
-        const roomState = this.room.currentState;
-        const sender = event.getSender();
-        event.sender = (!!sender && roomState?.getSentinelMember(sender)) || null;
-        if (event.getType() === "m.room.member") {
-            event.target = roomState?.getSentinelMember(event.getStateKey()!) ?? null;
-        }
+        event.setMetadata(this.room.currentState, false);
         return event;
     }
 
diff --git a/src/utils/exportUtils/HtmlExport.tsx b/src/utils/exportUtils/HtmlExport.tsx
index e5b4667fc22..9bd88dbd45e 100644
--- a/src/utils/exportUtils/HtmlExport.tsx
+++ b/src/utils/exportUtils/HtmlExport.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021-2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/exportUtils/JSONExport.ts b/src/utils/exportUtils/JSONExport.ts
index cae450f7437..bcd5c5cdc20 100644
--- a/src/utils/exportUtils/JSONExport.ts
+++ b/src/utils/exportUtils/JSONExport.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021, 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/exportUtils/PlainTextExport.ts b/src/utils/exportUtils/PlainTextExport.ts
index e36c57decc0..48354d6f2ac 100644
--- a/src/utils/exportUtils/PlainTextExport.ts
+++ b/src/utils/exportUtils/PlainTextExport.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021, 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/exportUtils/exportCSS.ts b/src/utils/exportUtils/exportCSS.ts
index dc21141d8b9..ade56edb3e4 100644
--- a/src/utils/exportUtils/exportCSS.ts
+++ b/src/utils/exportUtils/exportCSS.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/exportUtils/exportCustomCSS.css b/src/utils/exportUtils/exportCustomCSS.css
index b3fa8e81d38..fc94fef90b4 100644
--- a/src/utils/exportUtils/exportCustomCSS.css
+++ b/src/utils/exportUtils/exportCustomCSS.css
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/exportUtils/exportJS.js b/src/utils/exportUtils/exportJS.js
index 61807b55968..bae73e4f3a5 100644
--- a/src/utils/exportUtils/exportJS.js
+++ b/src/utils/exportUtils/exportJS.js
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/exportUtils/exportUtils.ts b/src/utils/exportUtils/exportUtils.ts
index caff440ca00..e765f91faf3 100644
--- a/src/utils/exportUtils/exportUtils.ts
+++ b/src/utils/exportUtils/exportUtils.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/humanize.ts b/src/utils/humanize.ts
index d1fcfa07edc..616ee937813 100644
--- a/src/utils/humanize.ts
+++ b/src/utils/humanize.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020, 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/i18n-helpers.ts b/src/utils/i18n-helpers.ts
index d02ecc061aa..195d3afd7a6 100644
--- a/src/utils/i18n-helpers.ts
+++ b/src/utils/i18n-helpers.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/image-media.ts b/src/utils/image-media.ts
index 5c013c7b1ac..2192297bdee 100644
--- a/src/utils/image-media.ts
+++ b/src/utils/image-media.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/iterables.ts b/src/utils/iterables.ts
index d6091f3f574..5afd1f284c8 100644
--- a/src/utils/iterables.ts
+++ b/src/utils/iterables.ts
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2020 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/src/utils/leave-behaviour.ts b/src/utils/leave-behaviour.ts
index 016887b5cd0..8924c3693b2 100644
--- a/src/utils/leave-behaviour.ts
+++ b/src/utils/leave-behaviour.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/local-room.ts b/src/utils/local-room.ts
index e4e922688d7..304471e93a3 100644
--- a/src/utils/local-room.ts
+++ b/src/utils/local-room.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/localRoom/isLocalRoom.ts b/src/utils/localRoom/isLocalRoom.ts
index e73ba51edc6..6888c9aafdc 100644
--- a/src/utils/localRoom/isLocalRoom.ts
+++ b/src/utils/localRoom/isLocalRoom.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/localRoom/isRoomReady.ts b/src/utils/localRoom/isRoomReady.ts
index e31f6ae4fb8..8d84f3abe84 100644
--- a/src/utils/localRoom/isRoomReady.ts
+++ b/src/utils/localRoom/isRoomReady.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/location/LocationShareErrors.ts b/src/utils/location/LocationShareErrors.ts
index 477c5e1b00c..f4174ea5ace 100644
--- a/src/utils/location/LocationShareErrors.ts
+++ b/src/utils/location/LocationShareErrors.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/location/findMapStyleUrl.ts b/src/utils/location/findMapStyleUrl.ts
index 9e5a19d8aa1..10915a9c336 100644
--- a/src/utils/location/findMapStyleUrl.ts
+++ b/src/utils/location/findMapStyleUrl.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/location/index.ts b/src/utils/location/index.ts
index cf71850b844..053c938d809 100644
--- a/src/utils/location/index.ts
+++ b/src/utils/location/index.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/location/isSelfLocation.ts b/src/utils/location/isSelfLocation.ts
index fbc7957228a..17d9e9ea94d 100644
--- a/src/utils/location/isSelfLocation.ts
+++ b/src/utils/location/isSelfLocation.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/location/links.ts b/src/utils/location/links.ts
index 0d10dc96eba..cf957af3e8f 100644
--- a/src/utils/location/links.ts
+++ b/src/utils/location/links.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/location/locationEventGeoUri.ts b/src/utils/location/locationEventGeoUri.ts
index 1de85defafc..171952b07bb 100644
--- a/src/utils/location/locationEventGeoUri.ts
+++ b/src/utils/location/locationEventGeoUri.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/location/map.ts b/src/utils/location/map.ts
index 22d11c2e306..22ceb998d5b 100644
--- a/src/utils/location/map.ts
+++ b/src/utils/location/map.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/location/parseGeoUri.ts b/src/utils/location/parseGeoUri.ts
index 5187d970c10..85a4474be50 100644
--- a/src/utils/location/parseGeoUri.ts
+++ b/src/utils/location/parseGeoUri.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/location/positionFailureMessage.ts b/src/utils/location/positionFailureMessage.ts
index 44b88f48ae9..cb53d931b76 100644
--- a/src/utils/location/positionFailureMessage.ts
+++ b/src/utils/location/positionFailureMessage.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/location/useMap.ts b/src/utils/location/useMap.ts
index 308aedc205c..e859559a527 100644
--- a/src/utils/location/useMap.ts
+++ b/src/utils/location/useMap.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/login.ts b/src/utils/login.ts
index cc6a6e0adfa..8f5d93ffae2 100644
--- a/src/utils/login.ts
+++ b/src/utils/login.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/maps.ts b/src/utils/maps.ts
index ea6d4fb37a9..48de6f8be35 100644
--- a/src/utils/maps.ts
+++ b/src/utils/maps.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/media/requestMediaPermissions.tsx b/src/utils/media/requestMediaPermissions.tsx
index 10a2fc0ca60..3b9e04ccd2e 100644
--- a/src/utils/media/requestMediaPermissions.tsx
+++ b/src/utils/media/requestMediaPermissions.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/membership.ts b/src/utils/membership.ts
index 27d281a76ea..79a1771e661 100644
--- a/src/utils/membership.ts
+++ b/src/utils/membership.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020-2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/notifications.ts b/src/utils/notifications.ts
index 30d29483802..9119ef9bcb7 100644
--- a/src/utils/notifications.ts
+++ b/src/utils/notifications.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -20,6 +20,7 @@ import { IndicatorIcon } from "@vector-im/compound-web";
 import SettingsStore from "../settings/SettingsStore";
 import { NotificationLevel } from "../stores/notifications/NotificationLevel";
 import { doesRoomHaveUnreadMessages } from "../Unread";
+import { SettingKey } from "../settings/Settings.tsx";
 
 // MSC2867 is not yet spec at time of writing. We read from both stable
 // and unstable prefixes and accept the risk that the format may change,
@@ -34,13 +35,15 @@ export const MARKED_UNREAD_TYPE_UNSTABLE = "com.famedly.marked_unread";
  */
 export const MARKED_UNREAD_TYPE_STABLE = "m.marked_unread";
 
-export const deviceNotificationSettingsKeys = [
+export const deviceNotificationSettingsKeys: SettingKey[] = [
     "notificationsEnabled",
     "notificationBodyEnabled",
     "audioNotificationsEnabled",
 ];
 
-export function getLocalNotificationAccountDataEventType(deviceId: string | null): string {
+export function getLocalNotificationAccountDataEventType(
+    deviceId: string | null,
+): `${typeof LOCAL_NOTIFICATION_SETTINGS_PREFIX.name}.${string}` {
     return `${LOCAL_NOTIFICATION_SETTINGS_PREFIX.name}.${deviceId}`;
 }
 
diff --git a/src/utils/numbers.ts b/src/utils/numbers.ts
index 80d964b5a63..87e5ced83ff 100644
--- a/src/utils/numbers.ts
+++ b/src/utils/numbers.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/objects.ts b/src/utils/objects.ts
index 65ce8d34f5f..a919699eac6 100644
--- a/src/utils/objects.ts
+++ b/src/utils/objects.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020, 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/oidc/TokenRefresher.ts b/src/utils/oidc/TokenRefresher.ts
index a41d3669a92..7c6848e39e7 100644
--- a/src/utils/oidc/TokenRefresher.ts
+++ b/src/utils/oidc/TokenRefresher.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/oidc/authorize.ts b/src/utils/oidc/authorize.ts
index 7dcdc6e6caa..50c9e07228b 100644
--- a/src/utils/oidc/authorize.ts
+++ b/src/utils/oidc/authorize.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/oidc/error.ts b/src/utils/oidc/error.ts
index 41c6fd4cc36..94313648a25 100644
--- a/src/utils/oidc/error.ts
+++ b/src/utils/oidc/error.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/oidc/getOidcLogoutUrl.ts b/src/utils/oidc/getOidcLogoutUrl.ts
deleted file mode 100644
index be632b815ae..00000000000
--- a/src/utils/oidc/getOidcLogoutUrl.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2023 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
-Please see LICENSE files in the repository root for full details.
-*/
-
-/**
- * Create a delegated auth account management URL with logout params as per MSC3824 and MSC2965
- * https://github.com/matrix-org/matrix-spec-proposals/blob/hughns/sso-redirect-action/proposals/3824-oidc-aware-clients.md#definition-of-oidc-aware
- * https://github.com/sandhose/matrix-doc/blob/msc/sandhose/oidc-discovery/proposals/2965-oidc-discovery.md#account-management-url-parameters
- */
-export const getOidcLogoutUrl = (delegatedAuthAccountUrl: string, deviceId: string): string => {
-    const logoutUrl = new URL(delegatedAuthAccountUrl);
-    logoutUrl.searchParams.set("action", "session_end");
-    logoutUrl.searchParams.set("device_id", deviceId);
-
-    return logoutUrl.toString();
-};
diff --git a/src/utils/oidc/isUserRegistrationSupported.ts b/src/utils/oidc/isUserRegistrationSupported.ts
index 4633f2a966c..8c91ee543b9 100644
--- a/src/utils/oidc/isUserRegistrationSupported.ts
+++ b/src/utils/oidc/isUserRegistrationSupported.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/oidc/persistOidcSettings.ts b/src/utils/oidc/persistOidcSettings.ts
index d508d0192cd..6ca1295e036 100644
--- a/src/utils/oidc/persistOidcSettings.ts
+++ b/src/utils/oidc/persistOidcSettings.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/oidc/registerClient.ts b/src/utils/oidc/registerClient.ts
index 7d64969bd32..61ec4ee3f29 100644
--- a/src/utils/oidc/registerClient.ts
+++ b/src/utils/oidc/registerClient.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/oidc/urls.ts b/src/utils/oidc/urls.ts
new file mode 100644
index 00000000000..fe364441a17
--- /dev/null
+++ b/src/utils/oidc/urls.ts
@@ -0,0 +1,32 @@
+/*
+Copyright 2024 New Vector Ltd.
+Copyright 2023 The Matrix.org Foundation C.I.C.
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+Please see LICENSE files in the repository root for full details.
+*/
+
+enum Action {
+    Profile = "org.matrix.profile",
+    SessionsList = "org.matrix.sessions_list",
+    SessionView = "org.matrix.session_view",
+    SessionEnd = "org.matrix.session_end",
+    AccountDeactivate = "org.matrix.account_deactivate",
+    CrossSigningReset = "org.matrix.cross_signing_reset",
+}
+
+const getUrl = (authUrl: string, action: Action): URL => {
+    const url = new URL(authUrl);
+    url.searchParams.set("action", action);
+    return url;
+};
+
+/**
+ * Create a delegated auth account management URL with logout params as per MSC4191
+ * https://github.com/matrix-org/matrix-spec-proposals/blob/quenting/account-deeplink/proposals/4191-account-deeplink.md#possible-actions
+ */
+export const getManageDeviceUrl = (delegatedAuthAccountUrl: string, deviceId: string): string => {
+    const url = getUrl(delegatedAuthAccountUrl, Action.SessionView);
+    url.searchParams.set("device_id", deviceId);
+    return url.toString();
+};
diff --git a/src/utils/pages.ts b/src/utils/pages.ts
index 83ed40895a2..efa25c803e7 100644
--- a/src/utils/pages.ts
+++ b/src/utils/pages.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/permalinks/ElementPermalinkConstructor.ts b/src/utils/permalinks/ElementPermalinkConstructor.ts
index 7240a0add50..37880d34999 100644
--- a/src/utils/permalinks/ElementPermalinkConstructor.ts
+++ b/src/utils/permalinks/ElementPermalinkConstructor.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/permalinks/MatrixSchemePermalinkConstructor.ts b/src/utils/permalinks/MatrixSchemePermalinkConstructor.ts
index beefc4f4f49..d6f42e33469 100644
--- a/src/utils/permalinks/MatrixSchemePermalinkConstructor.ts
+++ b/src/utils/permalinks/MatrixSchemePermalinkConstructor.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/permalinks/MatrixToPermalinkConstructor.ts b/src/utils/permalinks/MatrixToPermalinkConstructor.ts
index d5b51abfbac..77b4830e192 100644
--- a/src/utils/permalinks/MatrixToPermalinkConstructor.ts
+++ b/src/utils/permalinks/MatrixToPermalinkConstructor.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/permalinks/PermalinkConstructor.ts b/src/utils/permalinks/PermalinkConstructor.ts
index 9868b4e0d31..296ae668fa0 100644
--- a/src/utils/permalinks/PermalinkConstructor.ts
+++ b/src/utils/permalinks/PermalinkConstructor.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/permalinks/Permalinks.ts b/src/utils/permalinks/Permalinks.ts
index 9ecbf00b683..64411894978 100644
--- a/src/utils/permalinks/Permalinks.ts
+++ b/src/utils/permalinks/Permalinks.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/permalinks/navigator.ts b/src/utils/permalinks/navigator.ts
index 711bf9a1b0b..053dec10c5c 100644
--- a/src/utils/permalinks/navigator.ts
+++ b/src/utils/permalinks/navigator.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/pillify.tsx b/src/utils/pillify.tsx
index 1859e90fd6b..efcc9937467 100644
--- a/src/utils/pillify.tsx
+++ b/src/utils/pillify.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -83,9 +83,8 @@ export function pillifyLinks(
                     </StrictMode>
                 );
 
-                pills.render(pill, pillContainer);
-
-                node.parentNode?.replaceChild(pillContainer, node);
+                pills.render(pill, pillContainer, node);
+                node.replaceWith(pillContainer);
                 // Pills within pills aren't going to go well, so move on
                 pillified = true;
 
@@ -147,8 +146,8 @@ export function pillifyLinks(
                             </StrictMode>
                         );
 
-                        pills.render(pill, pillContainer);
-                        roomNotifTextNode.parentNode?.replaceChild(pillContainer, roomNotifTextNode);
+                        pills.render(pill, pillContainer, roomNotifTextNode);
+                        roomNotifTextNode.replaceWith(pillContainer);
                     }
                     // Nothing else to do for a text node (and we don't need to advance
                     // the loop pointer because we did it above)
diff --git a/src/utils/presence.ts b/src/utils/presence.ts
index 0930739bd52..798efdde5dc 100644
--- a/src/utils/presence.ts
+++ b/src/utils/presence.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/promise.ts b/src/utils/promise.ts
index 58dfdc8cd9a..919b925a5bc 100644
--- a/src/utils/promise.ts
+++ b/src/utils/promise.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/pushRules/monitorSyncedPushRules.ts b/src/utils/pushRules/monitorSyncedPushRules.ts
index 346e96431ec..fcc41aae82a 100644
--- a/src/utils/pushRules/monitorSyncedPushRules.ts
+++ b/src/utils/pushRules/monitorSyncedPushRules.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/pushRules/updatePushRuleActions.ts b/src/utils/pushRules/updatePushRuleActions.ts
index 5e305a52c47..e7ce8f7e8ea 100644
--- a/src/utils/pushRules/updatePushRuleActions.ts
+++ b/src/utils/pushRules/updatePushRuleActions.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/react.tsx b/src/utils/react.tsx
index b78f574fa97..435485214d5 100644
--- a/src/utils/react.tsx
+++ b/src/utils/react.tsx
@@ -1,7 +1,7 @@
 /*
 Copyright 2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -15,7 +15,7 @@ import { createRoot, Root } from "react-dom/client";
 export class ReactRootManager {
     private roots: Root[] = [];
     private rootElements: Element[] = [];
-    private revertElements: Array<null | Element> = [];
+    private revertElements: Array<Node | null> = [];
 
     public get elements(): Element[] {
         return this.rootElements;
@@ -26,12 +26,13 @@ export class ReactRootManager {
      * @param children the React component to render
      * @param rootElement the root element to render the component into
      * @param revertElement the element to replace the root element with when unmounting
+     *     needed to support double-rendering in React 18 Strict Dev mode
      */
-    public render(children: ReactNode, rootElement: Element, revertElement?: Element): void {
+    public render(children: ReactNode, rootElement: Element, revertElement: Node | null): void {
         const root = createRoot(rootElement);
         this.roots.push(root);
         this.rootElements.push(rootElement);
-        this.revertElements.push(revertElement ?? null);
+        this.revertElements.push(revertElement);
         root.render(children);
     }
 
diff --git a/src/utils/read-receipts.ts b/src/utils/read-receipts.ts
index 2a52b0bb739..51a4d6705e9 100644
--- a/src/utils/read-receipts.ts
+++ b/src/utils/read-receipts.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/room/canInviteTo.ts b/src/utils/room/canInviteTo.ts
index 89ce47a35b4..3d0b0c8f50f 100644
--- a/src/utils/room/canInviteTo.ts
+++ b/src/utils/room/canInviteTo.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/room/getFunctionalMembers.ts b/src/utils/room/getFunctionalMembers.ts
index 018e7854274..f107fc0d1ae 100644
--- a/src/utils/room/getFunctionalMembers.ts
+++ b/src/utils/room/getFunctionalMembers.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/room/getJoinedNonFunctionalMembers.ts b/src/utils/room/getJoinedNonFunctionalMembers.ts
index 855a87a2dcf..b8434987532 100644
--- a/src/utils/room/getJoinedNonFunctionalMembers.ts
+++ b/src/utils/room/getJoinedNonFunctionalMembers.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/room/inviteToRoom.ts b/src/utils/room/inviteToRoom.ts
index 10c84e9a9e6..c7010ec9474 100644
--- a/src/utils/room/inviteToRoom.ts
+++ b/src/utils/room/inviteToRoom.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/room/placeCall.ts b/src/utils/room/placeCall.ts
index 13b0de23c4c..04043fc3d31 100644
--- a/src/utils/room/placeCall.ts
+++ b/src/utils/room/placeCall.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/room/shouldEncryptRoomWithSingle3rdPartyInvite.ts b/src/utils/room/shouldEncryptRoomWithSingle3rdPartyInvite.ts
index 444bd0a303a..4192f0af1ad 100644
--- a/src/utils/room/shouldEncryptRoomWithSingle3rdPartyInvite.ts
+++ b/src/utils/room/shouldEncryptRoomWithSingle3rdPartyInvite.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/room/tagRoom.ts b/src/utils/room/tagRoom.ts
index 8b8f99e9913..7ed707d8741 100644
--- a/src/utils/room/tagRoom.ts
+++ b/src/utils/room/tagRoom.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/rooms.ts b/src/utils/rooms.ts
index 96495735bdc..d32e2e933f1 100644
--- a/src/utils/rooms.ts
+++ b/src/utils/rooms.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/sets.ts b/src/utils/sets.ts
index d6b28a9e41b..0d871f6b26e 100644
--- a/src/utils/sets.ts
+++ b/src/utils/sets.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/space.tsx b/src/utils/space.tsx
index a1bf1b5bb2c..9c3e0bc40c7 100644
--- a/src/utils/space.tsx
+++ b/src/utils/space.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/stringOrderField.ts b/src/utils/stringOrderField.ts
index e50501344bb..b6ba8410e3a 100644
--- a/src/utils/stringOrderField.ts
+++ b/src/utils/stringOrderField.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/strings.ts b/src/utils/strings.ts
index e7c99adbb8d..292c66cb034 100644
--- a/src/utils/strings.ts
+++ b/src/utils/strings.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 /**
diff --git a/src/utils/threepids.ts b/src/utils/threepids.ts
index a53bce6bcc6..5882c51c189 100644
--- a/src/utils/threepids.ts
+++ b/src/utils/threepids.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/tokens/pickling.ts b/src/utils/tokens/pickling.ts
index 5fc82c16a5c..3284d3f9cf9 100644
--- a/src/utils/tokens/pickling.ts
+++ b/src/utils/tokens/pickling.ts
@@ -5,7 +5,7 @@ Copyright 2018 New Vector Ltd
 Copyright 2016 Aviral Dasgupta
 Copyright 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/tokens/tokens.ts b/src/utils/tokens/tokens.ts
index 901da3a9a88..a25117beb8d 100644
--- a/src/utils/tokens/tokens.ts
+++ b/src/utils/tokens/tokens.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/tooltipify.tsx b/src/utils/tooltipify.tsx
index fc319b2024c..26d43cf0330 100644
--- a/src/utils/tooltipify.tsx
+++ b/src/utils/tooltipify.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -66,7 +66,7 @@ export function tooltipifyLinks(
                 </StrictMode>
             );
 
-            tooltips.render(tooltip, node);
+            tooltips.render(tooltip, node, null);
         } else if (node.childNodes?.length) {
             tooltipifyLinks(node.childNodes as NodeListOf<Element>, ignoredNodes, tooltips);
         }
diff --git a/src/utils/units.ts b/src/utils/units.ts
index d2ceb262bbc..1c509ece4b1 100644
--- a/src/utils/units.ts
+++ b/src/utils/units.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/validate/index.ts b/src/utils/validate/index.ts
index 946bb79575c..367641232df 100644
--- a/src/utils/validate/index.ts
+++ b/src/utils/validate/index.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/validate/numberInRange.ts b/src/utils/validate/numberInRange.ts
index cbdabad5477..ece657c9c77 100644
--- a/src/utils/validate/numberInRange.ts
+++ b/src/utils/validate/numberInRange.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/utils/video-rooms.ts b/src/utils/video-rooms.ts
index a0003d59d90..1da34142947 100644
--- a/src/utils/video-rooms.ts
+++ b/src/utils/video-rooms.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/vector/app.tsx b/src/vector/app.tsx
index 426163db0bb..2ae9e6fa03f 100644
--- a/src/vector/app.tsx
+++ b/src/vector/app.tsx
@@ -6,7 +6,7 @@ Copyright 2018, 2019 New Vector Ltd
 Copyright 2017 Vector Creations Ltd
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/vector/getconfig.ts b/src/vector/getconfig.ts
index 4a137b0c383..1f2e4956f4a 100644
--- a/src/vector/getconfig.ts
+++ b/src/vector/getconfig.ts
@@ -1,7 +1,7 @@
 /*
 Copyright 2018-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/vector/index.ts b/src/vector/index.ts
index 42b69af70e5..c398c0b7886 100644
--- a/src/vector/index.ts
+++ b/src/vector/index.ts
@@ -6,7 +6,7 @@ Copyright 2018, 2019 New Vector Ltd
 Copyright 2017 Vector Creations Ltd
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/vector/init.tsx b/src/vector/init.tsx
index a3d5624cb46..34f5b9fc08c 100644
--- a/src/vector/init.tsx
+++ b/src/vector/init.tsx
@@ -4,7 +4,7 @@ Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
 Copyright 2017 Vector Creations Ltd
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/vector/jitsi/index.pcss b/src/vector/jitsi/index.pcss
index 5bebaaccadb..09299f1b7f5 100644
--- a/src/vector/jitsi/index.pcss
+++ b/src/vector/jitsi/index.pcss
@@ -1,7 +1,7 @@
 /*
 Copyright 2020-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/vector/jitsi/index.ts b/src/vector/jitsi/index.ts
index 84096dfaae1..273e80488c6 100644
--- a/src/vector/jitsi/index.ts
+++ b/src/vector/jitsi/index.ts
@@ -1,7 +1,7 @@
 /*
 Copyright 2020-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/vector/localstorage-fix.ts b/src/vector/localstorage-fix.ts
index 31373d9c49c..14b95aca787 100644
--- a/src/vector/localstorage-fix.ts
+++ b/src/vector/localstorage-fix.ts
@@ -1,7 +1,7 @@
 /*
 Copyright 2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/vector/mobile_guide/index.ts b/src/vector/mobile_guide/index.ts
index 6f6602a6bea..ae769039a8e 100644
--- a/src/vector/mobile_guide/index.ts
+++ b/src/vector/mobile_guide/index.ts
@@ -1,7 +1,7 @@
 /*
 Copyright 2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/vector/platform/ElectronPlatform.tsx b/src/vector/platform/ElectronPlatform.tsx
index ac6e7a7feb1..6a6409ea42f 100644
--- a/src/vector/platform/ElectronPlatform.tsx
+++ b/src/vector/platform/ElectronPlatform.tsx
@@ -6,7 +6,7 @@ Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
 Copyright 2016 Aviral Dasgupta
 Copyright 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/vector/platform/IPCManager.ts b/src/vector/platform/IPCManager.ts
index 690deb6e3e1..7d329b8b2cb 100644
--- a/src/vector/platform/IPCManager.ts
+++ b/src/vector/platform/IPCManager.ts
@@ -1,7 +1,7 @@
 /*
 Copyright 2022-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/vector/platform/PWAPlatform.ts b/src/vector/platform/PWAPlatform.ts
index 616eaf5c8c6..5334c8e70f0 100644
--- a/src/vector/platform/PWAPlatform.ts
+++ b/src/vector/platform/PWAPlatform.ts
@@ -1,7 +1,7 @@
 /*
 Copyright 2020-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/vector/platform/SeshatIndexManager.ts b/src/vector/platform/SeshatIndexManager.ts
index e4ba4dea107..2f281812f67 100644
--- a/src/vector/platform/SeshatIndexManager.ts
+++ b/src/vector/platform/SeshatIndexManager.ts
@@ -1,7 +1,7 @@
 /*
 Copyright 2022-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/vector/platform/WebPlatform.ts b/src/vector/platform/WebPlatform.ts
index bb573c89c0f..ff575cb7b36 100644
--- a/src/vector/platform/WebPlatform.ts
+++ b/src/vector/platform/WebPlatform.ts
@@ -3,7 +3,7 @@ Copyright 2017-2024 New Vector Ltd.
 Copyright 2016 Aviral Dasgupta
 Copyright 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/vector/rageshakesetup.ts b/src/vector/rageshakesetup.ts
index d089ca3e4de..ef104e9a5b2 100644
--- a/src/vector/rageshakesetup.ts
+++ b/src/vector/rageshakesetup.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 Copyright 2018 New Vector Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/vector/routing.ts b/src/vector/routing.ts
index 216f3ac63b4..98da8817365 100644
--- a/src/vector/routing.ts
+++ b/src/vector/routing.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/vector/url_utils.ts b/src/vector/url_utils.ts
index 6ac6a60c146..82430a10c87 100644
--- a/src/vector/url_utils.ts
+++ b/src/vector/url_utils.ts
@@ -1,7 +1,7 @@
 /*
 Copyright 2018-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/verification.ts b/src/verification.ts
index 9f774964998..90dacbf6ac2 100644
--- a/src/verification.ts
+++ b/src/verification.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019, 2020 , 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/widgets/CapabilityText.tsx b/src/widgets/CapabilityText.tsx
index 28ba1175774..ea910c21c0e 100644
--- a/src/widgets/CapabilityText.tsx
+++ b/src/widgets/CapabilityText.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020, 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/widgets/Jitsi.ts b/src/widgets/Jitsi.ts
index ba54eda5e13..e76e86157d8 100644
--- a/src/widgets/Jitsi.ts
+++ b/src/widgets/Jitsi.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/widgets/ManagedHybrid.ts b/src/widgets/ManagedHybrid.ts
index a904bbab086..b4ef4cba8b3 100644
--- a/src/widgets/ManagedHybrid.ts
+++ b/src/widgets/ManagedHybrid.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/widgets/WidgetType.ts b/src/widgets/WidgetType.ts
index 58b836a13d9..7040de4cfec 100644
--- a/src/widgets/WidgetType.ts
+++ b/src/widgets/WidgetType.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/workers/blurhash.worker.ts b/src/workers/blurhash.worker.ts
index 00656ca8108..9d9c2fbf52e 100644
--- a/src/workers/blurhash.worker.ts
+++ b/src/workers/blurhash.worker.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/workers/blurhashWorkerFactory.ts b/src/workers/blurhashWorkerFactory.ts
index ab16ecb3fcb..669ab0a084d 100644
--- a/src/workers/blurhashWorkerFactory.ts
+++ b/src/workers/blurhashWorkerFactory.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/workers/indexeddb.worker.ts b/src/workers/indexeddb.worker.ts
index 5b71a08ef28..c712999d327 100644
--- a/src/workers/indexeddb.worker.ts
+++ b/src/workers/indexeddb.worker.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2017 Vector Creations Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/workers/indexeddbWorkerFactory.ts b/src/workers/indexeddbWorkerFactory.ts
index 1d78d9fb354..3ff1e82bf89 100644
--- a/src/workers/indexeddbWorkerFactory.ts
+++ b/src/workers/indexeddbWorkerFactory.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/workers/playback.worker.ts b/src/workers/playback.worker.ts
index 45789ffba3d..47479e6adb0 100644
--- a/src/workers/playback.worker.ts
+++ b/src/workers/playback.worker.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/workers/playbackWorkerFactory.ts b/src/workers/playbackWorkerFactory.ts
index 4d1aedddc2c..7986184b3ca 100644
--- a/src/workers/playbackWorkerFactory.ts
+++ b/src/workers/playbackWorkerFactory.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/src/workers/worker.ts b/src/workers/worker.ts
index fa2a45c850f..d96a53a324a 100644
--- a/src/workers/worker.ts
+++ b/src/workers/worker.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/@types/common.ts b/test/@types/common.ts
index 865a34fd475..8203ff1dd3d 100644
--- a/test/@types/common.ts
+++ b/test/@types/common.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/CreateCrossSigning-test.ts b/test/CreateCrossSigning-test.ts
index e1762bb5040..6863b0500ec 100644
--- a/test/CreateCrossSigning-test.ts
+++ b/test/CreateCrossSigning-test.ts
@@ -2,11 +2,11 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2018-2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
-import { MatrixClient, MatrixError } from "matrix-js-sdk/src/matrix";
+import { HTTPError, MatrixClient, MatrixError } from "matrix-js-sdk/src/matrix";
 import { mocked } from "jest-mock";
 
 import { createCrossSigning } from "../src/CreateCrossSigning";
@@ -21,14 +21,14 @@ describe("CreateCrossSigning", () => {
     });
 
     it("should call bootstrapCrossSigning with an authUploadDeviceSigningKeys function", async () => {
-        await createCrossSigning(client, false, "password");
+        await createCrossSigning(client);
 
         expect(client.getCrypto()?.bootstrapCrossSigning).toHaveBeenCalledWith({
             authUploadDeviceSigningKeys: expect.any(Function),
         });
     });
 
-    it("should upload with password auth if possible", async () => {
+    it("should upload", async () => {
         client.uploadDeviceSigningKeys = jest.fn().mockRejectedValueOnce(
             new MatrixError({
                 flows: [
@@ -39,24 +39,7 @@ describe("CreateCrossSigning", () => {
             }),
         );
 
-        await createCrossSigning(client, false, "password");
-
-        const { authUploadDeviceSigningKeys } = mocked(client.getCrypto()!).bootstrapCrossSigning.mock.calls[0][0];
-
-        const makeRequest = jest.fn();
-        await authUploadDeviceSigningKeys!(makeRequest);
-        expect(makeRequest).toHaveBeenCalledWith({
-            type: "m.login.password",
-            identifier: {
-                type: "m.id.user",
-                user: client.getUserId(),
-            },
-            password: "password",
-        });
-    });
-
-    it("should attempt to upload keys without auth if using token login", async () => {
-        await createCrossSigning(client, true, undefined);
+        await createCrossSigning(client);
 
         const { authUploadDeviceSigningKeys } = mocked(client.getCrypto()!).bootstrapCrossSigning.mock.calls[0][0];
 
@@ -65,7 +48,7 @@ describe("CreateCrossSigning", () => {
         expect(makeRequest).toHaveBeenCalledWith({});
     });
 
-    it("should prompt user if password upload not possible", async () => {
+    it("should prompt user if upload failed with UIA", async () => {
         const createDialog = jest.spyOn(Modal, "createDialog").mockReturnValue({
             finished: Promise.resolve([true]),
             close: jest.fn(),
@@ -81,13 +64,32 @@ describe("CreateCrossSigning", () => {
             }),
         );
 
-        await createCrossSigning(client, false, "password");
+        await createCrossSigning(client);
 
         const { authUploadDeviceSigningKeys } = mocked(client.getCrypto()!).bootstrapCrossSigning.mock.calls[0][0];
 
-        const makeRequest = jest.fn();
+        const makeRequest = jest.fn().mockRejectedValue(
+            new MatrixError({
+                flows: [
+                    {
+                        stages: ["dummy.mystery_flow_nobody_knows"],
+                    },
+                ],
+            }),
+        );
         await authUploadDeviceSigningKeys!(makeRequest);
         expect(makeRequest).not.toHaveBeenCalledWith();
         expect(createDialog).toHaveBeenCalled();
     });
+
+    it("should throw error if server fails with something other than UIA", async () => {
+        await createCrossSigning(client);
+
+        const { authUploadDeviceSigningKeys } = mocked(client.getCrypto()!).bootstrapCrossSigning.mock.calls[0][0];
+
+        const error = new HTTPError("Internal Server Error", 500);
+        const makeRequest = jest.fn().mockRejectedValue(error);
+        await expect(authUploadDeviceSigningKeys!(makeRequest)).rejects.toThrow(error);
+        expect(makeRequest).not.toHaveBeenCalledWith();
+    });
 });
diff --git a/test/app-tests/server-config-test.ts b/test/app-tests/server-config-test.ts
index 7e04e6ca24f..50a2de08a81 100644
--- a/test/app-tests/server-config-test.ts
+++ b/test/app-tests/server-config-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 Yorusaka Miyabi <shadowrz@disroot.org>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/app-tests/wrapper-test.tsx b/test/app-tests/wrapper-test.tsx
index af42426f0a1..47e2ad2ce1d 100644
--- a/test/app-tests/wrapper-test.tsx
+++ b/test/app-tests/wrapper-test.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2023 Mikhail Aheichyk
 Copyright 2023 Nordeck IT + Consulting GmbH.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/components/views/dialogs/security/InitialCryptoSetupDialog-test.tsx b/test/components/views/dialogs/security/InitialCryptoSetupDialog-test.tsx
index a589b55289b..0e333da30aa 100644
--- a/test/components/views/dialogs/security/InitialCryptoSetupDialog-test.tsx
+++ b/test/components/views/dialogs/security/InitialCryptoSetupDialog-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2018-2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/globalSetup.ts b/test/globalSetup.ts
index 36868124e54..c00ca3abf86 100644
--- a/test/globalSetup.ts
+++ b/test/globalSetup.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/jest-mocks.ts b/test/jest-mocks.ts
index 7241595c071..f742d141984 100644
--- a/test/jest-mocks.ts
+++ b/test/jest-mocks.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020-2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/setup/mocks.ts b/test/setup/mocks.ts
index 86c2f4bafc6..ffc349293e4 100644
--- a/test/setup/mocks.ts
+++ b/test/setup/mocks.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/setup/setupConfig.ts b/test/setup/setupConfig.ts
index 64f2f748438..c56a6444f46 100644
--- a/test/setup/setupConfig.ts
+++ b/test/setup/setupConfig.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/setup/setupLanguage.ts b/test/setup/setupLanguage.ts
index 1843f83241a..347f38edfc5 100644
--- a/test/setup/setupLanguage.ts
+++ b/test/setup/setupLanguage.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/setup/setupManualMocks.ts b/test/setup/setupManualMocks.ts
index 8064048baa0..7c49b33e033 100644
--- a/test/setup/setupManualMocks.ts
+++ b/test/setup/setupManualMocks.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/setupTests.ts b/test/setupTests.ts
index f0067a5d23b..5d1740f5f49 100644
--- a/test/setupTests.ts
+++ b/test/setupTests.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/slowReporter.cjs b/test/slowReporter.cjs
index 9c884c8114f..e25938753c4 100644
--- a/test/slowReporter.cjs
+++ b/test/slowReporter.cjs
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/test-utils/audio.ts b/test/test-utils/audio.ts
index c0888ad2aaf..5de94b529d8 100644
--- a/test/test-utils/audio.ts
+++ b/test/test-utils/audio.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/test-utils/beacon.ts b/test/test-utils/beacon.ts
index 538528cd51b..aca294546f1 100644
--- a/test/test-utils/beacon.ts
+++ b/test/test-utils/beacon.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/test-utils/call.ts b/test/test-utils/call.ts
index df87fcaa559..04b46f15979 100644
--- a/test/test-utils/call.ts
+++ b/test/test-utils/call.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/test-utils/client.ts b/test/test-utils/client.ts
index a2347f90588..f1b2cf967ca 100644
--- a/test/test-utils/client.ts
+++ b/test/test-utils/client.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/test-utils/composer.ts b/test/test-utils/composer.ts
index 9e970fca40b..73a3d990cf0 100644
--- a/test/test-utils/composer.ts
+++ b/test/test-utils/composer.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/test-utils/console.ts b/test/test-utils/console.ts
index 16c9ecf83d8..690357778b4 100644
--- a/test/test-utils/console.ts
+++ b/test/test-utils/console.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/test-utils/date.ts b/test/test-utils/date.ts
index d9c10ef972a..00b187446b9 100644
--- a/test/test-utils/date.ts
+++ b/test/test-utils/date.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/test-utils/events.ts b/test/test-utils/events.ts
index ab5c372a1c5..3e1ebadda6d 100644
--- a/test/test-utils/events.ts
+++ b/test/test-utils/events.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/test-utils/index.ts b/test/test-utils/index.ts
index 1486ade2834..0fd5797b3f7 100644
--- a/test/test-utils/index.ts
+++ b/test/test-utils/index.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2016-2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/test-utils/jest-matrix-react.tsx b/test/test-utils/jest-matrix-react.tsx
index 2aad5d45ffc..765f84a5c95 100644
--- a/test/test-utils/jest-matrix-react.tsx
+++ b/test/test-utils/jest-matrix-react.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/test-utils/location.ts b/test/test-utils/location.ts
index 1f099717346..0b558b5b8c5 100644
--- a/test/test-utils/location.ts
+++ b/test/test-utils/location.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/test-utils/oidc.ts b/test/test-utils/oidc.ts
index 1bacd5f3e52..72cdad04ef1 100644
--- a/test/test-utils/oidc.ts
+++ b/test/test-utils/oidc.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/test-utils/platform.ts b/test/test-utils/platform.ts
index 07a80873109..e360bb5e0ca 100644
--- a/test/test-utils/platform.ts
+++ b/test/test-utils/platform.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/test-utils/poll.ts b/test/test-utils/poll.ts
index 276730c2ff3..b7fea582599 100644
--- a/test/test-utils/poll.ts
+++ b/test/test-utils/poll.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/test-utils/predictableRandom.ts b/test/test-utils/predictableRandom.ts
index 10b2a38cb48..3e0c07ccdd3 100644
--- a/test/test-utils/predictableRandom.ts
+++ b/test/test-utils/predictableRandom.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/test-utils/pushRules.ts b/test/test-utils/pushRules.ts
index b0af6b72917..15796f8a096 100644
--- a/test/test-utils/pushRules.ts
+++ b/test/test-utils/pushRules.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/test-utils/relations.ts b/test/test-utils/relations.ts
index e48715ca9b2..1acf16af008 100644
--- a/test/test-utils/relations.ts
+++ b/test/test-utils/relations.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/test-utils/room.ts b/test/test-utils/room.ts
index bfd1f9004c0..21c82c9ae3a 100644
--- a/test/test-utils/room.ts
+++ b/test/test-utils/room.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/test-utils/test-utils.ts b/test/test-utils/test-utils.ts
index 39852f049ee..1809fa91c8c 100644
--- a/test/test-utils/test-utils.ts
+++ b/test/test-utils/test-utils.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022, 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -105,6 +105,7 @@ export function createTestClient(): MatrixClient {
             isStored: jest.fn().mockReturnValue(false),
             checkKey: jest.fn().mockResolvedValue(false),
             hasKey: jest.fn().mockReturnValue(false),
+            getDefaultKeyId: jest.fn().mockResolvedValue(null),
         },
 
         store: {
@@ -127,7 +128,10 @@ export function createTestClient(): MatrixClient {
             bootstrapCrossSigning: jest.fn(),
             getActiveSessionBackupVersion: jest.fn().mockResolvedValue(null),
             isKeyBackupTrusted: jest.fn().mockResolvedValue({}),
-            createRecoveryKeyFromPassphrase: jest.fn().mockResolvedValue({}),
+            createRecoveryKeyFromPassphrase: jest.fn().mockResolvedValue({
+                privateKey: new Uint8Array(32),
+                encodedPrivateKey: "encoded private key",
+            }),
             bootstrapSecretStorage: jest.fn(),
             isDehydrationSupported: jest.fn().mockResolvedValue(false),
             restoreKeyBackup: jest.fn(),
@@ -137,6 +141,16 @@ export function createTestClient(): MatrixClient {
             checkKeyBackupAndEnable: jest.fn().mockResolvedValue(null),
             getKeyBackupInfo: jest.fn().mockResolvedValue(null),
             getEncryptionInfoForEvent: jest.fn().mockResolvedValue(null),
+            getCrossSigningStatus: jest.fn().mockResolvedValue({
+                publicKeysOnDevice: false,
+                privateKeysInSecretStorage: false,
+                privateKeysCachedLocally: {
+                    masterKey: false,
+                    selfSigningKey: false,
+                    userSigningKey: false,
+                },
+            }),
+            isCrossSigningReady: jest.fn().mockResolvedValue(false),
         }),
 
         getPushActionsForEvent: jest.fn(),
@@ -800,6 +814,8 @@ export const mkThirdPartyInviteEvent = (user: string, displayName: string, room:
         type: EventType.RoomThirdPartyInvite,
         content: {
             display_name: displayName,
+            public_key: "foo",
+            key_validity_url: "bar",
         },
         skey: "test" + Math.random(),
         user,
diff --git a/test/test-utils/threads.ts b/test/test-utils/threads.ts
index 83313b1b8de..12b0575ba71 100644
--- a/test/test-utils/threads.ts
+++ b/test/test-utils/threads.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/test-utils/utilities.ts b/test/test-utils/utilities.ts
index 5285a840b25..e43f3561615 100644
--- a/test/test-utils/utilities.ts
+++ b/test/test-utils/utilities.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/test-utils/wrappers.tsx b/test/test-utils/wrappers.tsx
index 1e324c9d7d9..8b582ccf00f 100644
--- a/test/test-utils/wrappers.tsx
+++ b/test/test-utils/wrappers.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/Avatar-test.ts b/test/unit-tests/Avatar-test.ts
index 1b3506bc184..c068b8e4652 100644
--- a/test/unit-tests/Avatar-test.ts
+++ b/test/unit-tests/Avatar-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/ContentMessages-test.ts b/test/unit-tests/ContentMessages-test.ts
index 7e95973423a..67ab5825111 100644
--- a/test/unit-tests/ContentMessages-test.ts
+++ b/test/unit-tests/ContentMessages-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/DecryptionFailureTracker-test.ts b/test/unit-tests/DecryptionFailureTracker-test.ts
index 898816923fa..adadcc39737 100644
--- a/test/unit-tests/DecryptionFailureTracker-test.ts
+++ b/test/unit-tests/DecryptionFailureTracker-test.ts
@@ -1,7 +1,7 @@
 /*
 Copyright 2018-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/DeviceListener-test.ts b/test/unit-tests/DeviceListener-test.ts
index 1c8fe1a1c73..b63896c64dd 100644
--- a/test/unit-tests/DeviceListener-test.ts
+++ b/test/unit-tests/DeviceListener-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/HtmlUtils-test.tsx b/test/unit-tests/HtmlUtils-test.tsx
index a13c04af039..e4fccb185ba 100644
--- a/test/unit-tests/HtmlUtils-test.tsx
+++ b/test/unit-tests/HtmlUtils-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/Image-test.ts b/test/unit-tests/Image-test.ts
index 10285a5371d..149ee0ff26f 100644
--- a/test/unit-tests/Image-test.ts
+++ b/test/unit-tests/Image-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/KeyBindingsManager-test.ts b/test/unit-tests/KeyBindingsManager-test.ts
index 1d68abd4466..91adfc0effd 100644
--- a/test/unit-tests/KeyBindingsManager-test.ts
+++ b/test/unit-tests/KeyBindingsManager-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 Clemens Zeidler
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/LegacyCallHandler-test.ts b/test/unit-tests/LegacyCallHandler-test.ts
index 476d89a1f0f..1aee2d22317 100644
--- a/test/unit-tests/LegacyCallHandler-test.ts
+++ b/test/unit-tests/LegacyCallHandler-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/Lifecycle-test.ts b/test/unit-tests/Lifecycle-test.ts
index 04c3459bdf6..ba5885c414c 100644
--- a/test/unit-tests/Lifecycle-test.ts
+++ b/test/unit-tests/Lifecycle-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -143,6 +143,11 @@ describe("Lifecycle", () => {
                 const table = mockStore[tableKey];
                 delete table?.[key as string];
             });
+        jest.spyOn(StorageAccess, "idbClear")
+            .mockClear()
+            .mockImplementation(async (tableKey: string) => {
+                mockStore[tableKey] = {};
+            });
     };
 
     const homeserverUrl = "https://server.org";
@@ -613,7 +618,7 @@ describe("Lifecycle", () => {
             it("should clear stores", async () => {
                 await setLoggedIn(credentials);
 
-                expect(StorageAccess.idbDelete).toHaveBeenCalledWith("account", "mx_access_token");
+                expect(StorageAccess.idbClear).toHaveBeenCalledWith("account");
                 expect(sessionStorage.clear).toHaveBeenCalled();
                 expect(mockClient.clearStores).toHaveBeenCalled();
             });
diff --git a/test/unit-tests/Markdown-test.ts b/test/unit-tests/Markdown-test.ts
index 623061d182d..4cfb165ea99 100644
--- a/test/unit-tests/Markdown-test.ts
+++ b/test/unit-tests/Markdown-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/MatrixClientPeg-test.ts b/test/unit-tests/MatrixClientPeg-test.ts
index 46533405744..c46edad55cf 100644
--- a/test/unit-tests/MatrixClientPeg-test.ts
+++ b/test/unit-tests/MatrixClientPeg-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/MediaDeviceHandler-test.ts b/test/unit-tests/MediaDeviceHandler-test.ts
index e2e154abe10..975a3853db7 100644
--- a/test/unit-tests/MediaDeviceHandler-test.ts
+++ b/test/unit-tests/MediaDeviceHandler-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/Modal-test.ts b/test/unit-tests/Modal-test.ts
index d122f2b8552..d542fa38434 100644
--- a/test/unit-tests/Modal-test.ts
+++ b/test/unit-tests/Modal-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/Notifier-test.ts b/test/unit-tests/Notifier-test.ts
index f94f50724d0..3335b297873 100644
--- a/test/unit-tests/Notifier-test.ts
+++ b/test/unit-tests/Notifier-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 import { mocked, MockedObject } from "jest-mock";
@@ -16,6 +16,7 @@ import {
     IContent,
     MatrixEvent,
     SyncState,
+    AccountDataEvents,
 } from "matrix-js-sdk/src/matrix";
 import { waitFor } from "jest-matrix-react";
 import { CallMembership, MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc";
@@ -69,7 +70,7 @@ describe("Notifier", () => {
     let MockPlatform: MockedObject<BasePlatform>;
     let mockClient: MockedObject<MatrixClient>;
     let testRoom: Room;
-    let accountDataEventKey: string;
+    let accountDataEventKey: keyof AccountDataEvents;
     let accountDataStore: Record<string, MatrixEvent | undefined> = {};
 
     let mockSettings: Record<string, boolean> = {};
@@ -342,7 +343,7 @@ describe("Notifier", () => {
 
     describe("getSoundForRoom", () => {
         it("should not explode if given invalid url", () => {
-            jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string) => {
+            jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string): any => {
                 return { url: { content_uri: "foobar" } };
             });
             expect(Notifier.getSoundForRoom("!roomId:server")).toBeNull();
diff --git a/test/unit-tests/PosthogAnalytics-test.ts b/test/unit-tests/PosthogAnalytics-test.ts
index f754e3a80cc..27552bbba6c 100644
--- a/test/unit-tests/PosthogAnalytics-test.ts
+++ b/test/unit-tests/PosthogAnalytics-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/PreferredRoomVersions-test.ts b/test/unit-tests/PreferredRoomVersions-test.ts
index 8711494ac39..17d457632d6 100644
--- a/test/unit-tests/PreferredRoomVersions-test.ts
+++ b/test/unit-tests/PreferredRoomVersions-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/Reply-test.ts b/test/unit-tests/Reply-test.ts
index d9e1b02a021..be354632d48 100644
--- a/test/unit-tests/Reply-test.ts
+++ b/test/unit-tests/Reply-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/RoomNotifs-test.ts b/test/unit-tests/RoomNotifs-test.ts
index 65089eba94c..1452306de66 100644
--- a/test/unit-tests/RoomNotifs-test.ts
+++ b/test/unit-tests/RoomNotifs-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022, 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/Rooms-test.ts b/test/unit-tests/Rooms-test.ts
index 45424c6ec2c..32b5513f822 100644
--- a/test/unit-tests/Rooms-test.ts
+++ b/test/unit-tests/Rooms-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/ScalarAuthClient-test.ts b/test/unit-tests/ScalarAuthClient-test.ts
index 9d117d70af4..bbf29a8652f 100644
--- a/test/unit-tests/ScalarAuthClient-test.ts
+++ b/test/unit-tests/ScalarAuthClient-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/SdkConfig-test.ts b/test/unit-tests/SdkConfig-test.ts
index 19d0eec9c30..5595a7d5842 100644
--- a/test/unit-tests/SdkConfig-test.ts
+++ b/test/unit-tests/SdkConfig-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/SecurityManager-test.ts b/test/unit-tests/SecurityManager-test.ts
index 574549d8b24..4575223a50c 100644
--- a/test/unit-tests/SecurityManager-test.ts
+++ b/test/unit-tests/SecurityManager-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/SlashCommands-test.tsx b/test/unit-tests/SlashCommands-test.tsx
index 9305f0956ec..c2b3da7f2da 100644
--- a/test/unit-tests/SlashCommands-test.tsx
+++ b/test/unit-tests/SlashCommands-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/SlidingSyncManager-test.ts b/test/unit-tests/SlidingSyncManager-test.ts
index 9929102580b..66f4c48c255 100644
--- a/test/unit-tests/SlidingSyncManager-test.ts
+++ b/test/unit-tests/SlidingSyncManager-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -309,7 +309,7 @@ describe("SlidingSyncManager", () => {
         });
         it("uses the legacy `feature_sliding_sync_proxy_url` if it was set", async () => {
             jest.spyOn(manager, "getProxyFromWellKnown").mockResolvedValue("https://proxy/");
-            jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string) => {
+            jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string): any => {
                 if (name === "feature_sliding_sync_proxy_url") return "legacy-proxy";
             });
             await manager.setup(client);
diff --git a/test/unit-tests/SupportedBrowser-test.ts b/test/unit-tests/SupportedBrowser-test.ts
index a116ab1f9fd..d3fa2803eab 100644
--- a/test/unit-tests/SupportedBrowser-test.ts
+++ b/test/unit-tests/SupportedBrowser-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -61,21 +61,22 @@ describe("SupportedBrowser", () => {
         testUserAgentFactory("Browser unsupported, unsupported user agent"),
     );
 
+    // Grabbed from https://www.whatismybrowser.com/guides/the-latest-user-agent/
     it.each([
         // Safari 18.0 on macOS Sonoma
         "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Safari/605.1.15",
-        // Firefox 131 on macOS Sonoma
-        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:131.0) Gecko/20100101 Firefox/131.0",
+        // Latest Firefox on macOS Sonoma
+        "Mozilla/5.0 (Macintosh; Intel Mac OS X 14.7; rv:133.0) Gecko/20100101 Firefox/133.0",
         // Edge 131 on Windows
         "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.2903.70",
         // Edge 131 on macOS
         "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.2903.70",
-        // Firefox 131 on Windows
-        "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:131.0) Gecko/20100101 Firefox/131.0",
-        // Firefox 131 on Linux
-        "Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:131.0) Gecko/20100101 Firefox/131.0",
-        // Chrome 130 on Windows
-        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36",
+        // Latest Firefox on Windows
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:133.0) Gecko/20100101 Firefox/133.0",
+        // Latest Firefox on Linux
+        "Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:133.0) Gecko/20100101 Firefox/133.0",
+        // Latest Chrome on Windows
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
     ])("should not warn for supported browsers", testUserAgentFactory());
 
     it.each([
diff --git a/test/unit-tests/Terms-test.tsx b/test/unit-tests/Terms-test.tsx
index b6c2564d025..9fc29bde9a9 100644
--- a/test/unit-tests/Terms-test.tsx
+++ b/test/unit-tests/Terms-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/TestSdkContext.ts b/test/unit-tests/TestSdkContext.ts
index f60b083beff..1a8f9565a81 100644
--- a/test/unit-tests/TestSdkContext.ts
+++ b/test/unit-tests/TestSdkContext.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/TextForEvent-test.ts b/test/unit-tests/TextForEvent-test.ts
index cdef54a391e..4dfccbb93e9 100644
--- a/test/unit-tests/TextForEvent-test.ts
+++ b/test/unit-tests/TextForEvent-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/TimezoneHandler-test.ts b/test/unit-tests/TimezoneHandler-test.ts
index 74432129831..be7628712ae 100644
--- a/test/unit-tests/TimezoneHandler-test.ts
+++ b/test/unit-tests/TimezoneHandler-test.ts
@@ -4,7 +4,7 @@ Copyright 2022 The Matrix.org Foundation C.I.C.
 Copyright 2017 Vector Creations Ltd
 Copyright 2015, 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/Unread-test.ts b/test/unit-tests/Unread-test.ts
index 15d3dab8f5e..9686760ddfe 100644
--- a/test/unit-tests/Unread-test.ts
+++ b/test/unit-tests/Unread-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/UserActivity-test.ts b/test/unit-tests/UserActivity-test.ts
index 106541b460c..0c3fd1ca498 100644
--- a/test/unit-tests/UserActivity-test.ts
+++ b/test/unit-tests/UserActivity-test.ts
@@ -1,7 +1,7 @@
 /*
 Copyright 2019-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/WorkerManager-test.ts b/test/unit-tests/WorkerManager-test.ts
index 9b5dcecc773..f8d85fcda44 100644
--- a/test/unit-tests/WorkerManager-test.ts
+++ b/test/unit-tests/WorkerManager-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/accessibility/KeyboardShortcutUtils-test.ts b/test/unit-tests/accessibility/KeyboardShortcutUtils-test.ts
index 9361a85d74f..f53d578b678 100644
--- a/test/unit-tests/accessibility/KeyboardShortcutUtils-test.ts
+++ b/test/unit-tests/accessibility/KeyboardShortcutUtils-test.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2022 Šimon Brandner <simon.bra.ag@gmail.com>
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/accessibility/LandmarkNavigation-test.tsx b/test/unit-tests/accessibility/LandmarkNavigation-test.tsx
index 77a42fbd8ad..ad160e88663 100644
--- a/test/unit-tests/accessibility/LandmarkNavigation-test.tsx
+++ b/test/unit-tests/accessibility/LandmarkNavigation-test.tsx
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2024 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/test/unit-tests/accessibility/RovingTabIndex-test.tsx b/test/unit-tests/accessibility/RovingTabIndex-test.tsx
index 520103bca11..e0efaf6b1b1 100644
--- a/test/unit-tests/accessibility/RovingTabIndex-test.tsx
+++ b/test/unit-tests/accessibility/RovingTabIndex-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020, 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/actions/handlers/viewUserDeviceSettings-test.ts b/test/unit-tests/actions/handlers/viewUserDeviceSettings-test.ts
index eba8e12b0b3..f76c5cee204 100644
--- a/test/unit-tests/actions/handlers/viewUserDeviceSettings-test.ts
+++ b/test/unit-tests/actions/handlers/viewUserDeviceSettings-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/async-components/dialogs/security/NewRecoveryMethodDialog-test.tsx b/test/unit-tests/async-components/dialogs/security/NewRecoveryMethodDialog-test.tsx
index f6d9a59b510..cca65265823 100644
--- a/test/unit-tests/async-components/dialogs/security/NewRecoveryMethodDialog-test.tsx
+++ b/test/unit-tests/async-components/dialogs/security/NewRecoveryMethodDialog-test.tsx
@@ -1,7 +1,7 @@
 /*
  * Copyright 2024 New Vector Ltd.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/test/unit-tests/async-components/dialogs/security/RecoveryMethodRemovedDialog-test.tsx b/test/unit-tests/async-components/dialogs/security/RecoveryMethodRemovedDialog-test.tsx
index e3515244270..ec5e7142867 100644
--- a/test/unit-tests/async-components/dialogs/security/RecoveryMethodRemovedDialog-test.tsx
+++ b/test/unit-tests/async-components/dialogs/security/RecoveryMethodRemovedDialog-test.tsx
@@ -1,7 +1,7 @@
 /*
  * Copyright 2024 New Vector Ltd.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/test/unit-tests/async-components/structures/ErrorView-test.tsx b/test/unit-tests/async-components/structures/ErrorView-test.tsx
index 95cc75bcfa7..da4ff9c8e0f 100644
--- a/test/unit-tests/async-components/structures/ErrorView-test.tsx
+++ b/test/unit-tests/async-components/structures/ErrorView-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/audio/Playback-test.ts b/test/unit-tests/audio/Playback-test.ts
index 47b24b494a7..0aeea5c8322 100644
--- a/test/unit-tests/audio/Playback-test.ts
+++ b/test/unit-tests/audio/Playback-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/audio/VoiceMessageRecording-test.ts b/test/unit-tests/audio/VoiceMessageRecording-test.ts
index f76de288101..8cb1ac3afbd 100644
--- a/test/unit-tests/audio/VoiceMessageRecording-test.ts
+++ b/test/unit-tests/audio/VoiceMessageRecording-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/audio/VoiceRecording-test.ts b/test/unit-tests/audio/VoiceRecording-test.ts
index 4a9b0115927..eb14b9364af 100644
--- a/test/unit-tests/audio/VoiceRecording-test.ts
+++ b/test/unit-tests/audio/VoiceRecording-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/autocomplete/EmojiProvider-test.ts b/test/unit-tests/autocomplete/EmojiProvider-test.ts
index c78d25f0bee..81fd832e643 100644
--- a/test/unit-tests/autocomplete/EmojiProvider-test.ts
+++ b/test/unit-tests/autocomplete/EmojiProvider-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 Ryan Browne <code@commonlawfeature.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/autocomplete/QueryMatcher-test.ts b/test/unit-tests/autocomplete/QueryMatcher-test.ts
index 9da49b653ff..22ae71004c7 100644
--- a/test/unit-tests/autocomplete/QueryMatcher-test.ts
+++ b/test/unit-tests/autocomplete/QueryMatcher-test.ts
@@ -1,7 +1,7 @@
 /*
 Copyright 2018-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/autocomplete/RoomProvider-test.ts b/test/unit-tests/autocomplete/RoomProvider-test.ts
index e76b256428a..80b92511343 100644
--- a/test/unit-tests/autocomplete/RoomProvider-test.ts
+++ b/test/unit-tests/autocomplete/RoomProvider-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/autocomplete/SpaceProvider-test.ts b/test/unit-tests/autocomplete/SpaceProvider-test.ts
index 3dd45c48895..789a3bd4a6b 100644
--- a/test/unit-tests/autocomplete/SpaceProvider-test.ts
+++ b/test/unit-tests/autocomplete/SpaceProvider-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/structures/AutocompleteInput-test.tsx b/test/unit-tests/components/structures/AutocompleteInput-test.tsx
index da03e15adee..d34c521f971 100644
--- a/test/unit-tests/components/structures/AutocompleteInput-test.tsx
+++ b/test/unit-tests/components/structures/AutocompleteInput-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/structures/ContextMenu-test.ts b/test/unit-tests/components/structures/ContextMenu-test.ts
index 9ce3d41325d..ae9ff3a1abe 100644
--- a/test/unit-tests/components/structures/ContextMenu-test.ts
+++ b/test/unit-tests/components/structures/ContextMenu-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/structures/FilePanel-test.tsx b/test/unit-tests/components/structures/FilePanel-test.tsx
index 25bdd996768..e81b15d95a9 100644
--- a/test/unit-tests/components/structures/FilePanel-test.tsx
+++ b/test/unit-tests/components/structures/FilePanel-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/structures/LargeLoader-test.tsx b/test/unit-tests/components/structures/LargeLoader-test.tsx
index 6de7af6b842..889ec2f50d3 100644
--- a/test/unit-tests/components/structures/LargeLoader-test.tsx
+++ b/test/unit-tests/components/structures/LargeLoader-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/structures/LeftPanel-test.tsx b/test/unit-tests/components/structures/LeftPanel-test.tsx
index 0c74516c0af..93f014567c8 100644
--- a/test/unit-tests/components/structures/LeftPanel-test.tsx
+++ b/test/unit-tests/components/structures/LeftPanel-test.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2023 Mikhail Aheichyk
 Copyright 2023 Nordeck IT + Consulting GmbH.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/structures/LegacyCallEventGrouper-test.ts b/test/unit-tests/components/structures/LegacyCallEventGrouper-test.ts
index 5714505cf21..22fb5d300c5 100644
--- a/test/unit-tests/components/structures/LegacyCallEventGrouper-test.ts
+++ b/test/unit-tests/components/structures/LegacyCallEventGrouper-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/structures/LoggedInView-test.tsx b/test/unit-tests/components/structures/LoggedInView-test.tsx
index cb667f68c38..b4df9e29263 100644
--- a/test/unit-tests/components/structures/LoggedInView-test.tsx
+++ b/test/unit-tests/components/structures/LoggedInView-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2015-2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/structures/MainSplit-test.tsx b/test/unit-tests/components/structures/MainSplit-test.tsx
index 6853d9d1f51..1b9501ee27c 100644
--- a/test/unit-tests/components/structures/MainSplit-test.tsx
+++ b/test/unit-tests/components/structures/MainSplit-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/structures/MatrixChat-test.tsx b/test/unit-tests/components/structures/MatrixChat-test.tsx
index d5db4f190a2..a29834d51f7 100644
--- a/test/unit-tests/components/structures/MatrixChat-test.tsx
+++ b/test/unit-tests/components/structures/MatrixChat-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -1114,19 +1114,6 @@ describe("<MatrixChat />", () => {
                 // set up keys screen is rendered
                 expect(screen.getByText("Setting up keys")).toBeInTheDocument();
             });
-
-            it("should go to use case selection if user just registered", async () => {
-                loginClient.doesServerSupportUnstableFeature.mockResolvedValue(true);
-                MatrixClientPeg.setJustRegisteredUserId(userId);
-
-                await getComponentAndLogin();
-
-                bootstrapDeferred.resolve();
-
-                await expect(
-                    screen.findByRole("heading", { name: "You're in", level: 1 }),
-                ).resolves.toBeInTheDocument();
-            });
         });
     });
 
@@ -1493,7 +1480,7 @@ describe("<MatrixChat />", () => {
         };
 
         const enabledMobileRegistration = (): void => {
-            jest.spyOn(SettingsStore, "getValue").mockImplementation((settingName: string) => {
+            jest.spyOn(SettingsStore, "getValue").mockImplementation((settingName): any => {
                 if (settingName === "Registration.mobileRegistrationHelper") return true;
                 if (settingName === UIFeature.Registration) return true;
             });
diff --git a/test/unit-tests/components/structures/MatrixClientContextProvider-test.tsx b/test/unit-tests/components/structures/MatrixClientContextProvider-test.tsx
index b8c3949619b..e5ae9d97699 100644
--- a/test/unit-tests/components/structures/MatrixClientContextProvider-test.tsx
+++ b/test/unit-tests/components/structures/MatrixClientContextProvider-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/structures/MessagePanel-test.tsx b/test/unit-tests/components/structures/MessagePanel-test.tsx
index dbb83da3124..c8818239037 100644
--- a/test/unit-tests/components/structures/MessagePanel-test.tsx
+++ b/test/unit-tests/components/structures/MessagePanel-test.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019-2021 , 2022 The Matrix.org Foundation C.I.C.
 Copyright 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/structures/PictureInPictureDragger-test.tsx b/test/unit-tests/components/structures/PictureInPictureDragger-test.tsx
index 7b2309b6051..6cbf0842a9c 100644
--- a/test/unit-tests/components/structures/PictureInPictureDragger-test.tsx
+++ b/test/unit-tests/components/structures/PictureInPictureDragger-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/structures/PipContainer-test.tsx b/test/unit-tests/components/structures/PipContainer-test.tsx
index f573b0a0cde..06cad2a290b 100644
--- a/test/unit-tests/components/structures/PipContainer-test.tsx
+++ b/test/unit-tests/components/structures/PipContainer-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/structures/ReleaseAnnouncement-test.tsx b/test/unit-tests/components/structures/ReleaseAnnouncement-test.tsx
index ff1eff74eb9..c68d755a3a8 100644
--- a/test/unit-tests/components/structures/ReleaseAnnouncement-test.tsx
+++ b/test/unit-tests/components/structures/ReleaseAnnouncement-test.tsx
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2024 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/test/unit-tests/components/structures/RightPanel-test.tsx b/test/unit-tests/components/structures/RightPanel-test.tsx
index ad29791ee9f..83f79665a91 100644
--- a/test/unit-tests/components/structures/RightPanel-test.tsx
+++ b/test/unit-tests/components/structures/RightPanel-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -124,7 +124,7 @@ describe("RightPanel", () => {
         await waitFor(() => expect(screen.queryByTestId("spinner")).not.toBeInTheDocument());
 
         // room one will be in the MemberList phase - confirm this is rendered
-        expect(container.getElementsByClassName("mx_MemberList")).toHaveLength(1);
+        expect(container.getElementsByClassName("mx_MemberListView")).toHaveLength(1);
 
         // wait for RPS room 2 updates to fire, then rerender
         const _rpsUpdated = waitForRpsUpdate();
@@ -146,7 +146,7 @@ describe("RightPanel", () => {
         // the correct right panel state for whichever room we are showing, so we
         // confirm we do not have the MemberList class on the page and that we have
         // the expected room title
-        expect(container.getElementsByClassName("mx_MemberList")).toHaveLength(0);
+        expect(container.getElementsByClassName("mx_MemberListView")).toHaveLength(0);
         expect(screen.getByRole("heading", { name: "r2" })).toBeInTheDocument();
     });
 });
diff --git a/test/unit-tests/components/structures/RoomSearchView-test.tsx b/test/unit-tests/components/structures/RoomSearchView-test.tsx
index 72ab58bf4ae..56f19b830eb 100644
--- a/test/unit-tests/components/structures/RoomSearchView-test.tsx
+++ b/test/unit-tests/components/structures/RoomSearchView-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/structures/RoomStatusBar-test.tsx b/test/unit-tests/components/structures/RoomStatusBar-test.tsx
index ae84ac154ee..5d130b0205a 100644
--- a/test/unit-tests/components/structures/RoomStatusBar-test.tsx
+++ b/test/unit-tests/components/structures/RoomStatusBar-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/structures/RoomStatusBarUnsentMessages-test.tsx b/test/unit-tests/components/structures/RoomStatusBarUnsentMessages-test.tsx
index 09d374e41e7..d608cb06276 100644
--- a/test/unit-tests/components/structures/RoomStatusBarUnsentMessages-test.tsx
+++ b/test/unit-tests/components/structures/RoomStatusBarUnsentMessages-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/structures/RoomView-test.tsx b/test/unit-tests/components/structures/RoomView-test.tsx
index 385204c01b3..eabfe0c85ce 100644
--- a/test/unit-tests/components/structures/RoomView-test.tsx
+++ b/test/unit-tests/components/structures/RoomView-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/structures/SpaceHierarchy-test.tsx b/test/unit-tests/components/structures/SpaceHierarchy-test.tsx
index 1d2d913771a..c2b71e304f9 100644
--- a/test/unit-tests/components/structures/SpaceHierarchy-test.tsx
+++ b/test/unit-tests/components/structures/SpaceHierarchy-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/structures/SpaceRoomView-test.tsx b/test/unit-tests/components/structures/SpaceRoomView-test.tsx
index fb246032834..156f2d1cdbe 100644
--- a/test/unit-tests/components/structures/SpaceRoomView-test.tsx
+++ b/test/unit-tests/components/structures/SpaceRoomView-test.tsx
@@ -1,7 +1,7 @@
 /*
 Copyright 2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/structures/TabbedView-test.tsx b/test/unit-tests/components/structures/TabbedView-test.tsx
index 5c6c6b4271d..9c30bc443ae 100644
--- a/test/unit-tests/components/structures/TabbedView-test.tsx
+++ b/test/unit-tests/components/structures/TabbedView-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/structures/ThreadPanel-test.tsx b/test/unit-tests/components/structures/ThreadPanel-test.tsx
index 20fc7081032..c58194f0b9c 100644
--- a/test/unit-tests/components/structures/ThreadPanel-test.tsx
+++ b/test/unit-tests/components/structures/ThreadPanel-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021-2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/structures/ThreadView-test.tsx b/test/unit-tests/components/structures/ThreadView-test.tsx
index ee4afff525b..f67e2f28a35 100644
--- a/test/unit-tests/components/structures/ThreadView-test.tsx
+++ b/test/unit-tests/components/structures/ThreadView-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022, 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/structures/TimelinePanel-test.tsx b/test/unit-tests/components/structures/TimelinePanel-test.tsx
index 442ed1c1d28..2e10f74a694 100644
--- a/test/unit-tests/components/structures/TimelinePanel-test.tsx
+++ b/test/unit-tests/components/structures/TimelinePanel-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022, 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -303,8 +303,8 @@ describe("TimelinePanel", () => {
                     client.isVersionSupported.mockResolvedValue(true);
                     client.doesServerSupportUnstableFeature.mockResolvedValue(true);
 
-                    jest.spyOn(SettingsStore, "getValue").mockImplementation((setting: string) => {
-                        if (setting === "sendReadReceipt") return false;
+                    jest.spyOn(SettingsStore, "getValue").mockImplementation((setting: string): any => {
+                        if (setting === "sendReadReceipts") return false;
 
                         return undefined;
                     });
diff --git a/test/unit-tests/components/structures/UploadBar-test.tsx b/test/unit-tests/components/structures/UploadBar-test.tsx
index 6f6c038414c..f9920115301 100644
--- a/test/unit-tests/components/structures/UploadBar-test.tsx
+++ b/test/unit-tests/components/structures/UploadBar-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/structures/UserMenu-test.tsx b/test/unit-tests/components/structures/UserMenu-test.tsx
index 907bf664b7f..b6eb1bef5d1 100644
--- a/test/unit-tests/components/structures/UserMenu-test.tsx
+++ b/test/unit-tests/components/structures/UserMenu-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -19,9 +19,6 @@ import { TestSdkContext } from "../../TestSdkContext";
 import defaultDispatcher from "../../../../src/dispatcher/dispatcher";
 import LogoutDialog from "../../../../src/components/views/dialogs/LogoutDialog";
 import Modal from "../../../../src/Modal";
-import SettingsStore from "../../../../src/settings/SettingsStore";
-import { Features } from "../../../../src/settings/Settings";
-import { SettingLevel } from "../../../../src/settings/SettingLevel";
 import { mockOpenIdConfiguration } from "../../../test-utils/oidc";
 import { Action } from "../../../../src/dispatcher/actions";
 import { UserTab } from "../../../../src/components/views/dialogs/UserTab";
@@ -137,7 +134,6 @@ describe("<UserMenu>", () => {
             isCrossSigningReady: jest.fn().mockResolvedValue(true),
             exportSecretsBundle: jest.fn().mockResolvedValue({}),
         } as unknown as CryptoApi);
-        await SettingsStore.setValue(Features.OidcNativeFlow, null, SettingLevel.DEVICE, true);
         const spy = jest.spyOn(defaultDispatcher, "dispatch");
 
         const UserMenu = wrapInSdkContext(UnwrappedUserMenu, sdkContext);
diff --git a/test/unit-tests/components/structures/ViewSource-test.tsx b/test/unit-tests/components/structures/ViewSource-test.tsx
index 2cc195242fd..0d14e524414 100644
--- a/test/unit-tests/components/structures/ViewSource-test.tsx
+++ b/test/unit-tests/components/structures/ViewSource-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/structures/__snapshots__/MainSplit-test.tsx.snap b/test/unit-tests/components/structures/__snapshots__/MainSplit-test.tsx.snap
index 94f5b236049..8f7800c82be 100644
--- a/test/unit-tests/components/structures/__snapshots__/MainSplit-test.tsx.snap
+++ b/test/unit-tests/components/structures/__snapshots__/MainSplit-test.tsx.snap
@@ -14,7 +14,7 @@ exports[`<MainSplit/> renders 1`] = `
     </div>
     <div
       class="mx_RightPanel_ResizeWrapper"
-      style="position: relative; user-select: auto; width: 320px; height: 100%; max-width: 50%; min-width: 264px; box-sizing: border-box; flex-shrink: 0;"
+      style="position: relative; user-select: auto; width: 320px; height: 100%; max-width: 50%; min-width: 320px; box-sizing: border-box; flex-shrink: 0;"
     >
       <div>
         Right panel
@@ -44,7 +44,7 @@ exports[`<MainSplit/> respects defaultSize prop 1`] = `
     </div>
     <div
       class="mx_RightPanel_ResizeWrapper"
-      style="position: relative; user-select: auto; width: 500px; height: 100%; max-width: 50%; min-width: 264px; box-sizing: border-box; flex-shrink: 0;"
+      style="position: relative; user-select: auto; width: 500px; height: 100%; max-width: 50%; min-width: 320px; box-sizing: border-box; flex-shrink: 0;"
     >
       <div>
         Right panel
diff --git a/test/unit-tests/components/structures/__snapshots__/RoomView-test.tsx.snap b/test/unit-tests/components/structures/__snapshots__/RoomView-test.tsx.snap
index 1e0ed2248b0..65a755058bf 100644
--- a/test/unit-tests/components/structures/__snapshots__/RoomView-test.tsx.snap
+++ b/test/unit-tests/components/structures/__snapshots__/RoomView-test.tsx.snap
@@ -45,113 +45,108 @@ exports[`RoomView for a local room in state CREATING should match the snapshot 1
           </div>
         </div>
       </button>
-      <div
-        class="mx_Flex"
-        style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: var(--cpd-space-2x);"
+      <button
+        aria-disabled="false"
+        aria-label="Video call"
+        class="_icon-button_bh2qc_17"
+        role="button"
+        style="--cpd-icon-button-size: 32px;"
+        tabindex="0"
       >
-        <button
-          aria-disabled="false"
-          aria-label="Video call"
-          class="_icon-button_bh2qc_17"
-          role="button"
-          style="--cpd-icon-button-size: 32px;"
-          tabindex="0"
+        <div
+          class="_indicator-icon_133tf_26"
+          style="--cpd-icon-button-size: 100%;"
         >
-          <div
-            class="_indicator-icon_133tf_26"
-            style="--cpd-icon-button-size: 100%;"
+          <svg
+            aria-labelledby=":rg4:"
+            fill="currentColor"
+            height="1em"
+            viewBox="0 0 24 24"
+            width="1em"
+            xmlns="http://www.w3.org/2000/svg"
           >
-            <svg
-              aria-labelledby=":rg4:"
-              fill="currentColor"
-              height="1em"
-              viewBox="0 0 24 24"
-              width="1em"
-              xmlns="http://www.w3.org/2000/svg"
-            >
-              <path
-                d="M6 4h10a2 2 0 0 1 2 2v4.286l3.35-2.871a1 1 0 0 1 1.65.76v7.65a1 1 0 0 1-1.65.76L18 13.715V18a2 2 0 0 1-2 2H6a4 4 0 0 1-4-4V8a4 4 0 0 1 4-4Z"
-              />
-            </svg>
-          </div>
-        </button>
-        <button
-          aria-disabled="false"
-          aria-label="Voice call"
-          aria-labelledby=":rg9:"
-          class="_icon-button_bh2qc_17"
-          role="button"
-          style="--cpd-icon-button-size: 32px;"
-          tabindex="0"
+            <path
+              d="M6 4h10a2 2 0 0 1 2 2v4.286l3.35-2.871a1 1 0 0 1 1.65.76v7.65a1 1 0 0 1-1.65.76L18 13.715V18a2 2 0 0 1-2 2H6a4 4 0 0 1-4-4V8a4 4 0 0 1 4-4Z"
+            />
+          </svg>
+        </div>
+      </button>
+      <button
+        aria-disabled="false"
+        aria-label="Voice call"
+        aria-labelledby=":rg9:"
+        class="_icon-button_bh2qc_17"
+        role="button"
+        style="--cpd-icon-button-size: 32px;"
+        tabindex="0"
+      >
+        <div
+          class="_indicator-icon_133tf_26"
+          style="--cpd-icon-button-size: 100%;"
         >
-          <div
-            class="_indicator-icon_133tf_26"
-            style="--cpd-icon-button-size: 100%;"
+          <svg
+            fill="currentColor"
+            height="1em"
+            viewBox="0 0 24 24"
+            width="1em"
+            xmlns="http://www.w3.org/2000/svg"
           >
-            <svg
-              fill="currentColor"
-              height="1em"
-              viewBox="0 0 24 24"
-              width="1em"
-              xmlns="http://www.w3.org/2000/svg"
-            >
-              <path
-                d="m20.958 16.374.039 3.527c0 .285-.11.537-.33.756-.22.22-.472.33-.756.33a15.97 15.97 0 0 1-6.57-1.105 16.223 16.223 0 0 1-5.563-3.663 16.084 16.084 0 0 1-3.653-5.573 16.313 16.313 0 0 1-1.115-6.56c0-.285.11-.537.33-.757.22-.22.471-.329.755-.329l3.528.039a1.069 1.069 0 0 1 1.085.93l.543 3.954c.026.181.013.349-.039.504a1.088 1.088 0 0 1-.271.426l-1.64 1.64c.337.672.721 1.308 1.154 1.909.433.6 1.444 1.696 1.444 1.696s1.095 1.01 1.696 1.444c.6.433 1.237.817 1.909 1.153l1.64-1.64a1.08 1.08 0 0 1 .426-.27c.155-.052.323-.065.504-.04l3.954.543a1.069 1.069 0 0 1 .93 1.085Z"
-              />
-            </svg>
-          </div>
-        </button>
-        <button
-          aria-label="Room info"
-          aria-labelledby=":rge:"
-          class="_icon-button_bh2qc_17"
-          role="button"
-          style="--cpd-icon-button-size: 32px;"
-          tabindex="0"
+            <path
+              d="m20.958 16.374.039 3.527c0 .285-.11.537-.33.756-.22.22-.472.33-.756.33a15.97 15.97 0 0 1-6.57-1.105 16.223 16.223 0 0 1-5.563-3.663 16.084 16.084 0 0 1-3.653-5.573 16.313 16.313 0 0 1-1.115-6.56c0-.285.11-.537.33-.757.22-.22.471-.329.755-.329l3.528.039a1.069 1.069 0 0 1 1.085.93l.543 3.954c.026.181.013.349-.039.504a1.088 1.088 0 0 1-.271.426l-1.64 1.64c.337.672.721 1.308 1.154 1.909.433.6 1.444 1.696 1.444 1.696s1.095 1.01 1.696 1.444c.6.433 1.237.817 1.909 1.153l1.64-1.64a1.08 1.08 0 0 1 .426-.27c.155-.052.323-.065.504-.04l3.954.543a1.069 1.069 0 0 1 .93 1.085Z"
+            />
+          </svg>
+        </div>
+      </button>
+      <button
+        aria-label="Threads"
+        aria-labelledby=":rge:"
+        class="_icon-button_bh2qc_17"
+        role="button"
+        style="--cpd-icon-button-size: 32px;"
+        tabindex="0"
+      >
+        <div
+          class="_indicator-icon_133tf_26"
+          style="--cpd-icon-button-size: 100%;"
         >
-          <div
-            class="_indicator-icon_133tf_26"
-            style="--cpd-icon-button-size: 100%;"
+          <svg
+            fill="currentColor"
+            height="1em"
+            viewBox="0 0 24 24"
+            width="1em"
+            xmlns="http://www.w3.org/2000/svg"
           >
-            <svg
-              fill="currentColor"
-              height="1em"
-              viewBox="0 0 24 24"
-              width="1em"
-              xmlns="http://www.w3.org/2000/svg"
-            >
-              <path
-                d="M12 17a.97.97 0 0 0 .713-.288A.968.968 0 0 0 13 16v-4a.968.968 0 0 0-.287-.713A.968.968 0 0 0 12 11a.968.968 0 0 0-.713.287A.968.968 0 0 0 11 12v4c0 .283.096.52.287.712.192.192.43.288.713.288Zm0-8c.283 0 .52-.096.713-.287A.967.967 0 0 0 13 8a.967.967 0 0 0-.287-.713A.968.968 0 0 0 12 7a.968.968 0 0 0-.713.287A.967.967 0 0 0 11 8c0 .283.096.52.287.713.192.191.43.287.713.287Zm0 13a9.738 9.738 0 0 1-3.9-.788 10.099 10.099 0 0 1-3.175-2.137c-.9-.9-1.612-1.958-2.137-3.175A9.738 9.738 0 0 1 2 12a9.74 9.74 0 0 1 .788-3.9 10.099 10.099 0 0 1 2.137-3.175c.9-.9 1.958-1.612 3.175-2.137A9.738 9.738 0 0 1 12 2a9.74 9.74 0 0 1 3.9.788 10.098 10.098 0 0 1 3.175 2.137c.9.9 1.613 1.958 2.137 3.175A9.738 9.738 0 0 1 22 12a9.738 9.738 0 0 1-.788 3.9 10.098 10.098 0 0 1-2.137 3.175c-.9.9-1.958 1.613-3.175 2.137A9.738 9.738 0 0 1 12 22Z"
-              />
-            </svg>
-          </div>
-        </button>
-        <button
-          aria-label="Threads"
-          aria-labelledby=":rgj:"
-          class="_icon-button_bh2qc_17"
-          role="button"
-          style="--cpd-icon-button-size: 32px;"
-          tabindex="0"
+            <path
+              d="M4 3h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H6l-2.293 2.293c-.63.63-1.707.184-1.707-.707V5a2 2 0 0 1 2-2Zm3 7h10a.97.97 0 0 0 .712-.287A.967.967 0 0 0 18 9a.967.967 0 0 0-.288-.713A.968.968 0 0 0 17 8H7a.968.968 0 0 0-.713.287A.968.968 0 0 0 6 9c0 .283.096.52.287.713.192.191.43.287.713.287Zm0 4h6c.283 0 .52-.096.713-.287A.968.968 0 0 0 14 13a.968.968 0 0 0-.287-.713A.968.968 0 0 0 13 12H7a.967.967 0 0 0-.713.287A.968.968 0 0 0 6 13c0 .283.096.52.287.713.192.191.43.287.713.287Z"
+            />
+          </svg>
+        </div>
+      </button>
+      <button
+        aria-label="Room info"
+        aria-labelledby=":rgj:"
+        class="_icon-button_bh2qc_17"
+        role="button"
+        style="--cpd-icon-button-size: 32px;"
+        tabindex="0"
+      >
+        <div
+          class="_indicator-icon_133tf_26"
+          style="--cpd-icon-button-size: 100%;"
         >
-          <div
-            class="_indicator-icon_133tf_26"
-            style="--cpd-icon-button-size: 100%;"
+          <svg
+            fill="currentColor"
+            height="1em"
+            viewBox="0 0 24 24"
+            width="1em"
+            xmlns="http://www.w3.org/2000/svg"
           >
-            <svg
-              fill="currentColor"
-              height="1em"
-              viewBox="0 0 24 24"
-              width="1em"
-              xmlns="http://www.w3.org/2000/svg"
-            >
-              <path
-                d="M4 3h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H6l-2.293 2.293c-.63.63-1.707.184-1.707-.707V5a2 2 0 0 1 2-2Zm3 7h10a.97.97 0 0 0 .712-.287A.967.967 0 0 0 18 9a.967.967 0 0 0-.288-.713A.968.968 0 0 0 17 8H7a.968.968 0 0 0-.713.287A.968.968 0 0 0 6 9c0 .283.096.52.287.713.192.191.43.287.713.287Zm0 4h6c.283 0 .52-.096.713-.287A.968.968 0 0 0 14 13a.968.968 0 0 0-.287-.713A.968.968 0 0 0 13 12H7a.967.967 0 0 0-.713.287A.968.968 0 0 0 6 13c0 .283.096.52.287.713.192.191.43.287.713.287Z"
-              />
-            </svg>
-          </div>
-        </button>
-      </div>
+            <path
+              d="M12 17a.97.97 0 0 0 .713-.288A.968.968 0 0 0 13 16v-4a.968.968 0 0 0-.287-.713A.968.968 0 0 0 12 11a.968.968 0 0 0-.713.287A.968.968 0 0 0 11 12v4c0 .283.096.52.287.712.192.192.43.288.713.288Zm0-8c.283 0 .52-.096.713-.287A.967.967 0 0 0 13 8a.967.967 0 0 0-.287-.713A.968.968 0 0 0 12 7a.968.968 0 0 0-.713.287A.967.967 0 0 0 11 8c0 .283.096.52.287.713.192.191.43.287.713.287Zm0 13a9.738 9.738 0 0 1-3.9-.788 10.099 10.099 0 0 1-3.175-2.137c-.9-.9-1.612-1.958-2.137-3.175A9.738 9.738 0 0 1 2 12a9.74 9.74 0 0 1 .788-3.9 10.099 10.099 0 0 1 2.137-3.175c.9-.9 1.958-1.612 3.175-2.137A9.738 9.738 0 0 1 12 2a9.74 9.74 0 0 1 3.9.788 10.098 10.098 0 0 1 3.175 2.137c.9.9 1.613 1.958 2.137 3.175A9.738 9.738 0 0 1 22 12a9.738 9.738 0 0 1-.788 3.9 10.098 10.098 0 0 1-2.137 3.175c-.9.9-1.958 1.613-3.175 2.137A9.738 9.738 0 0 1 12 22Z"
+            />
+          </svg>
+        </div>
+      </button>
       <div
         class="_typography_yh5dq_162 _font-body-sm-medium_yh5dq_50"
       >
@@ -263,113 +258,108 @@ exports[`RoomView for a local room in state ERROR should match the snapshot 1`]
           </div>
         </div>
       </button>
-      <div
-        class="mx_Flex"
-        style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: var(--cpd-space-2x);"
+      <button
+        aria-disabled="false"
+        aria-label="Video call"
+        class="_icon-button_bh2qc_17"
+        role="button"
+        style="--cpd-icon-button-size: 32px;"
+        tabindex="0"
       >
-        <button
-          aria-disabled="false"
-          aria-label="Video call"
-          class="_icon-button_bh2qc_17"
-          role="button"
-          style="--cpd-icon-button-size: 32px;"
-          tabindex="0"
+        <div
+          class="_indicator-icon_133tf_26"
+          style="--cpd-icon-button-size: 100%;"
         >
-          <div
-            class="_indicator-icon_133tf_26"
-            style="--cpd-icon-button-size: 100%;"
+          <svg
+            aria-labelledby=":rh2:"
+            fill="currentColor"
+            height="1em"
+            viewBox="0 0 24 24"
+            width="1em"
+            xmlns="http://www.w3.org/2000/svg"
           >
-            <svg
-              aria-labelledby=":rh2:"
-              fill="currentColor"
-              height="1em"
-              viewBox="0 0 24 24"
-              width="1em"
-              xmlns="http://www.w3.org/2000/svg"
-            >
-              <path
-                d="M6 4h10a2 2 0 0 1 2 2v4.286l3.35-2.871a1 1 0 0 1 1.65.76v7.65a1 1 0 0 1-1.65.76L18 13.715V18a2 2 0 0 1-2 2H6a4 4 0 0 1-4-4V8a4 4 0 0 1 4-4Z"
-              />
-            </svg>
-          </div>
-        </button>
-        <button
-          aria-disabled="false"
-          aria-label="Voice call"
-          aria-labelledby=":rh7:"
-          class="_icon-button_bh2qc_17"
-          role="button"
-          style="--cpd-icon-button-size: 32px;"
-          tabindex="0"
+            <path
+              d="M6 4h10a2 2 0 0 1 2 2v4.286l3.35-2.871a1 1 0 0 1 1.65.76v7.65a1 1 0 0 1-1.65.76L18 13.715V18a2 2 0 0 1-2 2H6a4 4 0 0 1-4-4V8a4 4 0 0 1 4-4Z"
+            />
+          </svg>
+        </div>
+      </button>
+      <button
+        aria-disabled="false"
+        aria-label="Voice call"
+        aria-labelledby=":rh7:"
+        class="_icon-button_bh2qc_17"
+        role="button"
+        style="--cpd-icon-button-size: 32px;"
+        tabindex="0"
+      >
+        <div
+          class="_indicator-icon_133tf_26"
+          style="--cpd-icon-button-size: 100%;"
         >
-          <div
-            class="_indicator-icon_133tf_26"
-            style="--cpd-icon-button-size: 100%;"
+          <svg
+            fill="currentColor"
+            height="1em"
+            viewBox="0 0 24 24"
+            width="1em"
+            xmlns="http://www.w3.org/2000/svg"
           >
-            <svg
-              fill="currentColor"
-              height="1em"
-              viewBox="0 0 24 24"
-              width="1em"
-              xmlns="http://www.w3.org/2000/svg"
-            >
-              <path
-                d="m20.958 16.374.039 3.527c0 .285-.11.537-.33.756-.22.22-.472.33-.756.33a15.97 15.97 0 0 1-6.57-1.105 16.223 16.223 0 0 1-5.563-3.663 16.084 16.084 0 0 1-3.653-5.573 16.313 16.313 0 0 1-1.115-6.56c0-.285.11-.537.33-.757.22-.22.471-.329.755-.329l3.528.039a1.069 1.069 0 0 1 1.085.93l.543 3.954c.026.181.013.349-.039.504a1.088 1.088 0 0 1-.271.426l-1.64 1.64c.337.672.721 1.308 1.154 1.909.433.6 1.444 1.696 1.444 1.696s1.095 1.01 1.696 1.444c.6.433 1.237.817 1.909 1.153l1.64-1.64a1.08 1.08 0 0 1 .426-.27c.155-.052.323-.065.504-.04l3.954.543a1.069 1.069 0 0 1 .93 1.085Z"
-              />
-            </svg>
-          </div>
-        </button>
-        <button
-          aria-label="Room info"
-          aria-labelledby=":rhc:"
-          class="_icon-button_bh2qc_17"
-          role="button"
-          style="--cpd-icon-button-size: 32px;"
-          tabindex="0"
+            <path
+              d="m20.958 16.374.039 3.527c0 .285-.11.537-.33.756-.22.22-.472.33-.756.33a15.97 15.97 0 0 1-6.57-1.105 16.223 16.223 0 0 1-5.563-3.663 16.084 16.084 0 0 1-3.653-5.573 16.313 16.313 0 0 1-1.115-6.56c0-.285.11-.537.33-.757.22-.22.471-.329.755-.329l3.528.039a1.069 1.069 0 0 1 1.085.93l.543 3.954c.026.181.013.349-.039.504a1.088 1.088 0 0 1-.271.426l-1.64 1.64c.337.672.721 1.308 1.154 1.909.433.6 1.444 1.696 1.444 1.696s1.095 1.01 1.696 1.444c.6.433 1.237.817 1.909 1.153l1.64-1.64a1.08 1.08 0 0 1 .426-.27c.155-.052.323-.065.504-.04l3.954.543a1.069 1.069 0 0 1 .93 1.085Z"
+            />
+          </svg>
+        </div>
+      </button>
+      <button
+        aria-label="Threads"
+        aria-labelledby=":rhc:"
+        class="_icon-button_bh2qc_17"
+        role="button"
+        style="--cpd-icon-button-size: 32px;"
+        tabindex="0"
+      >
+        <div
+          class="_indicator-icon_133tf_26"
+          style="--cpd-icon-button-size: 100%;"
         >
-          <div
-            class="_indicator-icon_133tf_26"
-            style="--cpd-icon-button-size: 100%;"
+          <svg
+            fill="currentColor"
+            height="1em"
+            viewBox="0 0 24 24"
+            width="1em"
+            xmlns="http://www.w3.org/2000/svg"
           >
-            <svg
-              fill="currentColor"
-              height="1em"
-              viewBox="0 0 24 24"
-              width="1em"
-              xmlns="http://www.w3.org/2000/svg"
-            >
-              <path
-                d="M12 17a.97.97 0 0 0 .713-.288A.968.968 0 0 0 13 16v-4a.968.968 0 0 0-.287-.713A.968.968 0 0 0 12 11a.968.968 0 0 0-.713.287A.968.968 0 0 0 11 12v4c0 .283.096.52.287.712.192.192.43.288.713.288Zm0-8c.283 0 .52-.096.713-.287A.967.967 0 0 0 13 8a.967.967 0 0 0-.287-.713A.968.968 0 0 0 12 7a.968.968 0 0 0-.713.287A.967.967 0 0 0 11 8c0 .283.096.52.287.713.192.191.43.287.713.287Zm0 13a9.738 9.738 0 0 1-3.9-.788 10.099 10.099 0 0 1-3.175-2.137c-.9-.9-1.612-1.958-2.137-3.175A9.738 9.738 0 0 1 2 12a9.74 9.74 0 0 1 .788-3.9 10.099 10.099 0 0 1 2.137-3.175c.9-.9 1.958-1.612 3.175-2.137A9.738 9.738 0 0 1 12 2a9.74 9.74 0 0 1 3.9.788 10.098 10.098 0 0 1 3.175 2.137c.9.9 1.613 1.958 2.137 3.175A9.738 9.738 0 0 1 22 12a9.738 9.738 0 0 1-.788 3.9 10.098 10.098 0 0 1-2.137 3.175c-.9.9-1.958 1.613-3.175 2.137A9.738 9.738 0 0 1 12 22Z"
-              />
-            </svg>
-          </div>
-        </button>
-        <button
-          aria-label="Threads"
-          aria-labelledby=":rhh:"
-          class="_icon-button_bh2qc_17"
-          role="button"
-          style="--cpd-icon-button-size: 32px;"
-          tabindex="0"
+            <path
+              d="M4 3h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H6l-2.293 2.293c-.63.63-1.707.184-1.707-.707V5a2 2 0 0 1 2-2Zm3 7h10a.97.97 0 0 0 .712-.287A.967.967 0 0 0 18 9a.967.967 0 0 0-.288-.713A.968.968 0 0 0 17 8H7a.968.968 0 0 0-.713.287A.968.968 0 0 0 6 9c0 .283.096.52.287.713.192.191.43.287.713.287Zm0 4h6c.283 0 .52-.096.713-.287A.968.968 0 0 0 14 13a.968.968 0 0 0-.287-.713A.968.968 0 0 0 13 12H7a.967.967 0 0 0-.713.287A.968.968 0 0 0 6 13c0 .283.096.52.287.713.192.191.43.287.713.287Z"
+            />
+          </svg>
+        </div>
+      </button>
+      <button
+        aria-label="Room info"
+        aria-labelledby=":rhh:"
+        class="_icon-button_bh2qc_17"
+        role="button"
+        style="--cpd-icon-button-size: 32px;"
+        tabindex="0"
+      >
+        <div
+          class="_indicator-icon_133tf_26"
+          style="--cpd-icon-button-size: 100%;"
         >
-          <div
-            class="_indicator-icon_133tf_26"
-            style="--cpd-icon-button-size: 100%;"
+          <svg
+            fill="currentColor"
+            height="1em"
+            viewBox="0 0 24 24"
+            width="1em"
+            xmlns="http://www.w3.org/2000/svg"
           >
-            <svg
-              fill="currentColor"
-              height="1em"
-              viewBox="0 0 24 24"
-              width="1em"
-              xmlns="http://www.w3.org/2000/svg"
-            >
-              <path
-                d="M4 3h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H6l-2.293 2.293c-.63.63-1.707.184-1.707-.707V5a2 2 0 0 1 2-2Zm3 7h10a.97.97 0 0 0 .712-.287A.967.967 0 0 0 18 9a.967.967 0 0 0-.288-.713A.968.968 0 0 0 17 8H7a.968.968 0 0 0-.713.287A.968.968 0 0 0 6 9c0 .283.096.52.287.713.192.191.43.287.713.287Zm0 4h6c.283 0 .52-.096.713-.287A.968.968 0 0 0 14 13a.968.968 0 0 0-.287-.713A.968.968 0 0 0 13 12H7a.967.967 0 0 0-.713.287A.968.968 0 0 0 6 13c0 .283.096.52.287.713.192.191.43.287.713.287Z"
-              />
-            </svg>
-          </div>
-        </button>
-      </div>
+            <path
+              d="M12 17a.97.97 0 0 0 .713-.288A.968.968 0 0 0 13 16v-4a.968.968 0 0 0-.287-.713A.968.968 0 0 0 12 11a.968.968 0 0 0-.713.287A.968.968 0 0 0 11 12v4c0 .283.096.52.287.712.192.192.43.288.713.288Zm0-8c.283 0 .52-.096.713-.287A.967.967 0 0 0 13 8a.967.967 0 0 0-.287-.713A.968.968 0 0 0 12 7a.968.968 0 0 0-.713.287A.967.967 0 0 0 11 8c0 .283.096.52.287.713.192.191.43.287.713.287Zm0 13a9.738 9.738 0 0 1-3.9-.788 10.099 10.099 0 0 1-3.175-2.137c-.9-.9-1.612-1.958-2.137-3.175A9.738 9.738 0 0 1 2 12a9.74 9.74 0 0 1 .788-3.9 10.099 10.099 0 0 1 2.137-3.175c.9-.9 1.958-1.612 3.175-2.137A9.738 9.738 0 0 1 12 2a9.74 9.74 0 0 1 3.9.788 10.098 10.098 0 0 1 3.175 2.137c.9.9 1.613 1.958 2.137 3.175A9.738 9.738 0 0 1 22 12a9.738 9.738 0 0 1-.788 3.9 10.098 10.098 0 0 1-2.137 3.175c-.9.9-1.958 1.613-3.175 2.137A9.738 9.738 0 0 1 12 22Z"
+            />
+          </svg>
+        </div>
+      </button>
       <div
         class="_typography_yh5dq_162 _font-body-sm-medium_yh5dq_50"
       >
@@ -566,113 +556,108 @@ exports[`RoomView for a local room in state NEW should match the snapshot 1`] =
           </div>
         </div>
       </button>
-      <div
-        class="mx_Flex"
-        style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: var(--cpd-space-2x);"
+      <button
+        aria-disabled="false"
+        aria-label="Video call"
+        class="_icon-button_bh2qc_17"
+        role="button"
+        style="--cpd-icon-button-size: 32px;"
+        tabindex="0"
       >
-        <button
-          aria-disabled="false"
-          aria-label="Video call"
-          class="_icon-button_bh2qc_17"
-          role="button"
-          style="--cpd-icon-button-size: 32px;"
-          tabindex="0"
+        <div
+          class="_indicator-icon_133tf_26"
+          style="--cpd-icon-button-size: 100%;"
         >
-          <div
-            class="_indicator-icon_133tf_26"
-            style="--cpd-icon-button-size: 100%;"
+          <svg
+            aria-labelledby=":rbo:"
+            fill="currentColor"
+            height="1em"
+            viewBox="0 0 24 24"
+            width="1em"
+            xmlns="http://www.w3.org/2000/svg"
           >
-            <svg
-              aria-labelledby=":rbo:"
-              fill="currentColor"
-              height="1em"
-              viewBox="0 0 24 24"
-              width="1em"
-              xmlns="http://www.w3.org/2000/svg"
-            >
-              <path
-                d="M6 4h10a2 2 0 0 1 2 2v4.286l3.35-2.871a1 1 0 0 1 1.65.76v7.65a1 1 0 0 1-1.65.76L18 13.715V18a2 2 0 0 1-2 2H6a4 4 0 0 1-4-4V8a4 4 0 0 1 4-4Z"
-              />
-            </svg>
-          </div>
-        </button>
-        <button
-          aria-disabled="false"
-          aria-label="Voice call"
-          aria-labelledby=":rbt:"
-          class="_icon-button_bh2qc_17"
-          role="button"
-          style="--cpd-icon-button-size: 32px;"
-          tabindex="0"
+            <path
+              d="M6 4h10a2 2 0 0 1 2 2v4.286l3.35-2.871a1 1 0 0 1 1.65.76v7.65a1 1 0 0 1-1.65.76L18 13.715V18a2 2 0 0 1-2 2H6a4 4 0 0 1-4-4V8a4 4 0 0 1 4-4Z"
+            />
+          </svg>
+        </div>
+      </button>
+      <button
+        aria-disabled="false"
+        aria-label="Voice call"
+        aria-labelledby=":rbt:"
+        class="_icon-button_bh2qc_17"
+        role="button"
+        style="--cpd-icon-button-size: 32px;"
+        tabindex="0"
+      >
+        <div
+          class="_indicator-icon_133tf_26"
+          style="--cpd-icon-button-size: 100%;"
         >
-          <div
-            class="_indicator-icon_133tf_26"
-            style="--cpd-icon-button-size: 100%;"
+          <svg
+            fill="currentColor"
+            height="1em"
+            viewBox="0 0 24 24"
+            width="1em"
+            xmlns="http://www.w3.org/2000/svg"
           >
-            <svg
-              fill="currentColor"
-              height="1em"
-              viewBox="0 0 24 24"
-              width="1em"
-              xmlns="http://www.w3.org/2000/svg"
-            >
-              <path
-                d="m20.958 16.374.039 3.527c0 .285-.11.537-.33.756-.22.22-.472.33-.756.33a15.97 15.97 0 0 1-6.57-1.105 16.223 16.223 0 0 1-5.563-3.663 16.084 16.084 0 0 1-3.653-5.573 16.313 16.313 0 0 1-1.115-6.56c0-.285.11-.537.33-.757.22-.22.471-.329.755-.329l3.528.039a1.069 1.069 0 0 1 1.085.93l.543 3.954c.026.181.013.349-.039.504a1.088 1.088 0 0 1-.271.426l-1.64 1.64c.337.672.721 1.308 1.154 1.909.433.6 1.444 1.696 1.444 1.696s1.095 1.01 1.696 1.444c.6.433 1.237.817 1.909 1.153l1.64-1.64a1.08 1.08 0 0 1 .426-.27c.155-.052.323-.065.504-.04l3.954.543a1.069 1.069 0 0 1 .93 1.085Z"
-              />
-            </svg>
-          </div>
-        </button>
-        <button
-          aria-label="Room info"
-          aria-labelledby=":rc2:"
-          class="_icon-button_bh2qc_17"
-          role="button"
-          style="--cpd-icon-button-size: 32px;"
-          tabindex="0"
+            <path
+              d="m20.958 16.374.039 3.527c0 .285-.11.537-.33.756-.22.22-.472.33-.756.33a15.97 15.97 0 0 1-6.57-1.105 16.223 16.223 0 0 1-5.563-3.663 16.084 16.084 0 0 1-3.653-5.573 16.313 16.313 0 0 1-1.115-6.56c0-.285.11-.537.33-.757.22-.22.471-.329.755-.329l3.528.039a1.069 1.069 0 0 1 1.085.93l.543 3.954c.026.181.013.349-.039.504a1.088 1.088 0 0 1-.271.426l-1.64 1.64c.337.672.721 1.308 1.154 1.909.433.6 1.444 1.696 1.444 1.696s1.095 1.01 1.696 1.444c.6.433 1.237.817 1.909 1.153l1.64-1.64a1.08 1.08 0 0 1 .426-.27c.155-.052.323-.065.504-.04l3.954.543a1.069 1.069 0 0 1 .93 1.085Z"
+            />
+          </svg>
+        </div>
+      </button>
+      <button
+        aria-label="Threads"
+        aria-labelledby=":rc2:"
+        class="_icon-button_bh2qc_17"
+        role="button"
+        style="--cpd-icon-button-size: 32px;"
+        tabindex="0"
+      >
+        <div
+          class="_indicator-icon_133tf_26"
+          style="--cpd-icon-button-size: 100%;"
         >
-          <div
-            class="_indicator-icon_133tf_26"
-            style="--cpd-icon-button-size: 100%;"
+          <svg
+            fill="currentColor"
+            height="1em"
+            viewBox="0 0 24 24"
+            width="1em"
+            xmlns="http://www.w3.org/2000/svg"
           >
-            <svg
-              fill="currentColor"
-              height="1em"
-              viewBox="0 0 24 24"
-              width="1em"
-              xmlns="http://www.w3.org/2000/svg"
-            >
-              <path
-                d="M12 17a.97.97 0 0 0 .713-.288A.968.968 0 0 0 13 16v-4a.968.968 0 0 0-.287-.713A.968.968 0 0 0 12 11a.968.968 0 0 0-.713.287A.968.968 0 0 0 11 12v4c0 .283.096.52.287.712.192.192.43.288.713.288Zm0-8c.283 0 .52-.096.713-.287A.967.967 0 0 0 13 8a.967.967 0 0 0-.287-.713A.968.968 0 0 0 12 7a.968.968 0 0 0-.713.287A.967.967 0 0 0 11 8c0 .283.096.52.287.713.192.191.43.287.713.287Zm0 13a9.738 9.738 0 0 1-3.9-.788 10.099 10.099 0 0 1-3.175-2.137c-.9-.9-1.612-1.958-2.137-3.175A9.738 9.738 0 0 1 2 12a9.74 9.74 0 0 1 .788-3.9 10.099 10.099 0 0 1 2.137-3.175c.9-.9 1.958-1.612 3.175-2.137A9.738 9.738 0 0 1 12 2a9.74 9.74 0 0 1 3.9.788 10.098 10.098 0 0 1 3.175 2.137c.9.9 1.613 1.958 2.137 3.175A9.738 9.738 0 0 1 22 12a9.738 9.738 0 0 1-.788 3.9 10.098 10.098 0 0 1-2.137 3.175c-.9.9-1.958 1.613-3.175 2.137A9.738 9.738 0 0 1 12 22Z"
-              />
-            </svg>
-          </div>
-        </button>
-        <button
-          aria-label="Threads"
-          aria-labelledby=":rc7:"
-          class="_icon-button_bh2qc_17"
-          role="button"
-          style="--cpd-icon-button-size: 32px;"
-          tabindex="0"
+            <path
+              d="M4 3h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H6l-2.293 2.293c-.63.63-1.707.184-1.707-.707V5a2 2 0 0 1 2-2Zm3 7h10a.97.97 0 0 0 .712-.287A.967.967 0 0 0 18 9a.967.967 0 0 0-.288-.713A.968.968 0 0 0 17 8H7a.968.968 0 0 0-.713.287A.968.968 0 0 0 6 9c0 .283.096.52.287.713.192.191.43.287.713.287Zm0 4h6c.283 0 .52-.096.713-.287A.968.968 0 0 0 14 13a.968.968 0 0 0-.287-.713A.968.968 0 0 0 13 12H7a.967.967 0 0 0-.713.287A.968.968 0 0 0 6 13c0 .283.096.52.287.713.192.191.43.287.713.287Z"
+            />
+          </svg>
+        </div>
+      </button>
+      <button
+        aria-label="Room info"
+        aria-labelledby=":rc7:"
+        class="_icon-button_bh2qc_17"
+        role="button"
+        style="--cpd-icon-button-size: 32px;"
+        tabindex="0"
+      >
+        <div
+          class="_indicator-icon_133tf_26"
+          style="--cpd-icon-button-size: 100%;"
         >
-          <div
-            class="_indicator-icon_133tf_26"
-            style="--cpd-icon-button-size: 100%;"
+          <svg
+            fill="currentColor"
+            height="1em"
+            viewBox="0 0 24 24"
+            width="1em"
+            xmlns="http://www.w3.org/2000/svg"
           >
-            <svg
-              fill="currentColor"
-              height="1em"
-              viewBox="0 0 24 24"
-              width="1em"
-              xmlns="http://www.w3.org/2000/svg"
-            >
-              <path
-                d="M4 3h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H6l-2.293 2.293c-.63.63-1.707.184-1.707-.707V5a2 2 0 0 1 2-2Zm3 7h10a.97.97 0 0 0 .712-.287A.967.967 0 0 0 18 9a.967.967 0 0 0-.288-.713A.968.968 0 0 0 17 8H7a.968.968 0 0 0-.713.287A.968.968 0 0 0 6 9c0 .283.096.52.287.713.192.191.43.287.713.287Zm0 4h6c.283 0 .52-.096.713-.287A.968.968 0 0 0 14 13a.968.968 0 0 0-.287-.713A.968.968 0 0 0 13 12H7a.967.967 0 0 0-.713.287A.968.968 0 0 0 6 13c0 .283.096.52.287.713.192.191.43.287.713.287Z"
-              />
-            </svg>
-          </div>
-        </button>
-      </div>
+            <path
+              d="M12 17a.97.97 0 0 0 .713-.288A.968.968 0 0 0 13 16v-4a.968.968 0 0 0-.287-.713A.968.968 0 0 0 12 11a.968.968 0 0 0-.713.287A.968.968 0 0 0 11 12v4c0 .283.096.52.287.712.192.192.43.288.713.288Zm0-8c.283 0 .52-.096.713-.287A.967.967 0 0 0 13 8a.967.967 0 0 0-.287-.713A.968.968 0 0 0 12 7a.968.968 0 0 0-.713.287A.967.967 0 0 0 11 8c0 .283.096.52.287.713.192.191.43.287.713.287Zm0 13a9.738 9.738 0 0 1-3.9-.788 10.099 10.099 0 0 1-3.175-2.137c-.9-.9-1.612-1.958-2.137-3.175A9.738 9.738 0 0 1 2 12a9.74 9.74 0 0 1 .788-3.9 10.099 10.099 0 0 1 2.137-3.175c.9-.9 1.958-1.612 3.175-2.137A9.738 9.738 0 0 1 12 2a9.74 9.74 0 0 1 3.9.788 10.098 10.098 0 0 1 3.175 2.137c.9.9 1.613 1.958 2.137 3.175A9.738 9.738 0 0 1 22 12a9.738 9.738 0 0 1-.788 3.9 10.098 10.098 0 0 1-2.137 3.175c-.9.9-1.958 1.613-3.175 2.137A9.738 9.738 0 0 1 12 22Z"
+            />
+          </svg>
+        </div>
+      </button>
       <div
         class="_typography_yh5dq_162 _font-body-sm-medium_yh5dq_50"
       >
@@ -946,113 +931,108 @@ exports[`RoomView for a local room in state NEW that is encrypted should match t
           </div>
         </div>
       </button>
-      <div
-        class="mx_Flex"
-        style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: var(--cpd-space-2x);"
+      <button
+        aria-disabled="false"
+        aria-label="Video call"
+        class="_icon-button_bh2qc_17"
+        role="button"
+        style="--cpd-icon-button-size: 32px;"
+        tabindex="0"
       >
-        <button
-          aria-disabled="false"
-          aria-label="Video call"
-          class="_icon-button_bh2qc_17"
-          role="button"
-          style="--cpd-icon-button-size: 32px;"
-          tabindex="0"
+        <div
+          class="_indicator-icon_133tf_26"
+          style="--cpd-icon-button-size: 100%;"
         >
-          <div
-            class="_indicator-icon_133tf_26"
-            style="--cpd-icon-button-size: 100%;"
+          <svg
+            aria-labelledby=":rdu:"
+            fill="currentColor"
+            height="1em"
+            viewBox="0 0 24 24"
+            width="1em"
+            xmlns="http://www.w3.org/2000/svg"
           >
-            <svg
-              aria-labelledby=":rdu:"
-              fill="currentColor"
-              height="1em"
-              viewBox="0 0 24 24"
-              width="1em"
-              xmlns="http://www.w3.org/2000/svg"
-            >
-              <path
-                d="M6 4h10a2 2 0 0 1 2 2v4.286l3.35-2.871a1 1 0 0 1 1.65.76v7.65a1 1 0 0 1-1.65.76L18 13.715V18a2 2 0 0 1-2 2H6a4 4 0 0 1-4-4V8a4 4 0 0 1 4-4Z"
-              />
-            </svg>
-          </div>
-        </button>
-        <button
-          aria-disabled="false"
-          aria-label="Voice call"
-          aria-labelledby=":re3:"
-          class="_icon-button_bh2qc_17"
-          role="button"
-          style="--cpd-icon-button-size: 32px;"
-          tabindex="0"
+            <path
+              d="M6 4h10a2 2 0 0 1 2 2v4.286l3.35-2.871a1 1 0 0 1 1.65.76v7.65a1 1 0 0 1-1.65.76L18 13.715V18a2 2 0 0 1-2 2H6a4 4 0 0 1-4-4V8a4 4 0 0 1 4-4Z"
+            />
+          </svg>
+        </div>
+      </button>
+      <button
+        aria-disabled="false"
+        aria-label="Voice call"
+        aria-labelledby=":re3:"
+        class="_icon-button_bh2qc_17"
+        role="button"
+        style="--cpd-icon-button-size: 32px;"
+        tabindex="0"
+      >
+        <div
+          class="_indicator-icon_133tf_26"
+          style="--cpd-icon-button-size: 100%;"
         >
-          <div
-            class="_indicator-icon_133tf_26"
-            style="--cpd-icon-button-size: 100%;"
+          <svg
+            fill="currentColor"
+            height="1em"
+            viewBox="0 0 24 24"
+            width="1em"
+            xmlns="http://www.w3.org/2000/svg"
           >
-            <svg
-              fill="currentColor"
-              height="1em"
-              viewBox="0 0 24 24"
-              width="1em"
-              xmlns="http://www.w3.org/2000/svg"
-            >
-              <path
-                d="m20.958 16.374.039 3.527c0 .285-.11.537-.33.756-.22.22-.472.33-.756.33a15.97 15.97 0 0 1-6.57-1.105 16.223 16.223 0 0 1-5.563-3.663 16.084 16.084 0 0 1-3.653-5.573 16.313 16.313 0 0 1-1.115-6.56c0-.285.11-.537.33-.757.22-.22.471-.329.755-.329l3.528.039a1.069 1.069 0 0 1 1.085.93l.543 3.954c.026.181.013.349-.039.504a1.088 1.088 0 0 1-.271.426l-1.64 1.64c.337.672.721 1.308 1.154 1.909.433.6 1.444 1.696 1.444 1.696s1.095 1.01 1.696 1.444c.6.433 1.237.817 1.909 1.153l1.64-1.64a1.08 1.08 0 0 1 .426-.27c.155-.052.323-.065.504-.04l3.954.543a1.069 1.069 0 0 1 .93 1.085Z"
-              />
-            </svg>
-          </div>
-        </button>
-        <button
-          aria-label="Room info"
-          aria-labelledby=":re8:"
-          class="_icon-button_bh2qc_17"
-          role="button"
-          style="--cpd-icon-button-size: 32px;"
-          tabindex="0"
+            <path
+              d="m20.958 16.374.039 3.527c0 .285-.11.537-.33.756-.22.22-.472.33-.756.33a15.97 15.97 0 0 1-6.57-1.105 16.223 16.223 0 0 1-5.563-3.663 16.084 16.084 0 0 1-3.653-5.573 16.313 16.313 0 0 1-1.115-6.56c0-.285.11-.537.33-.757.22-.22.471-.329.755-.329l3.528.039a1.069 1.069 0 0 1 1.085.93l.543 3.954c.026.181.013.349-.039.504a1.088 1.088 0 0 1-.271.426l-1.64 1.64c.337.672.721 1.308 1.154 1.909.433.6 1.444 1.696 1.444 1.696s1.095 1.01 1.696 1.444c.6.433 1.237.817 1.909 1.153l1.64-1.64a1.08 1.08 0 0 1 .426-.27c.155-.052.323-.065.504-.04l3.954.543a1.069 1.069 0 0 1 .93 1.085Z"
+            />
+          </svg>
+        </div>
+      </button>
+      <button
+        aria-label="Threads"
+        aria-labelledby=":re8:"
+        class="_icon-button_bh2qc_17"
+        role="button"
+        style="--cpd-icon-button-size: 32px;"
+        tabindex="0"
+      >
+        <div
+          class="_indicator-icon_133tf_26"
+          style="--cpd-icon-button-size: 100%;"
         >
-          <div
-            class="_indicator-icon_133tf_26"
-            style="--cpd-icon-button-size: 100%;"
+          <svg
+            fill="currentColor"
+            height="1em"
+            viewBox="0 0 24 24"
+            width="1em"
+            xmlns="http://www.w3.org/2000/svg"
           >
-            <svg
-              fill="currentColor"
-              height="1em"
-              viewBox="0 0 24 24"
-              width="1em"
-              xmlns="http://www.w3.org/2000/svg"
-            >
-              <path
-                d="M12 17a.97.97 0 0 0 .713-.288A.968.968 0 0 0 13 16v-4a.968.968 0 0 0-.287-.713A.968.968 0 0 0 12 11a.968.968 0 0 0-.713.287A.968.968 0 0 0 11 12v4c0 .283.096.52.287.712.192.192.43.288.713.288Zm0-8c.283 0 .52-.096.713-.287A.967.967 0 0 0 13 8a.967.967 0 0 0-.287-.713A.968.968 0 0 0 12 7a.968.968 0 0 0-.713.287A.967.967 0 0 0 11 8c0 .283.096.52.287.713.192.191.43.287.713.287Zm0 13a9.738 9.738 0 0 1-3.9-.788 10.099 10.099 0 0 1-3.175-2.137c-.9-.9-1.612-1.958-2.137-3.175A9.738 9.738 0 0 1 2 12a9.74 9.74 0 0 1 .788-3.9 10.099 10.099 0 0 1 2.137-3.175c.9-.9 1.958-1.612 3.175-2.137A9.738 9.738 0 0 1 12 2a9.74 9.74 0 0 1 3.9.788 10.098 10.098 0 0 1 3.175 2.137c.9.9 1.613 1.958 2.137 3.175A9.738 9.738 0 0 1 22 12a9.738 9.738 0 0 1-.788 3.9 10.098 10.098 0 0 1-2.137 3.175c-.9.9-1.958 1.613-3.175 2.137A9.738 9.738 0 0 1 12 22Z"
-              />
-            </svg>
-          </div>
-        </button>
-        <button
-          aria-label="Threads"
-          aria-labelledby=":red:"
-          class="_icon-button_bh2qc_17"
-          role="button"
-          style="--cpd-icon-button-size: 32px;"
-          tabindex="0"
+            <path
+              d="M4 3h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H6l-2.293 2.293c-.63.63-1.707.184-1.707-.707V5a2 2 0 0 1 2-2Zm3 7h10a.97.97 0 0 0 .712-.287A.967.967 0 0 0 18 9a.967.967 0 0 0-.288-.713A.968.968 0 0 0 17 8H7a.968.968 0 0 0-.713.287A.968.968 0 0 0 6 9c0 .283.096.52.287.713.192.191.43.287.713.287Zm0 4h6c.283 0 .52-.096.713-.287A.968.968 0 0 0 14 13a.968.968 0 0 0-.287-.713A.968.968 0 0 0 13 12H7a.967.967 0 0 0-.713.287A.968.968 0 0 0 6 13c0 .283.096.52.287.713.192.191.43.287.713.287Z"
+            />
+          </svg>
+        </div>
+      </button>
+      <button
+        aria-label="Room info"
+        aria-labelledby=":red:"
+        class="_icon-button_bh2qc_17"
+        role="button"
+        style="--cpd-icon-button-size: 32px;"
+        tabindex="0"
+      >
+        <div
+          class="_indicator-icon_133tf_26"
+          style="--cpd-icon-button-size: 100%;"
         >
-          <div
-            class="_indicator-icon_133tf_26"
-            style="--cpd-icon-button-size: 100%;"
+          <svg
+            fill="currentColor"
+            height="1em"
+            viewBox="0 0 24 24"
+            width="1em"
+            xmlns="http://www.w3.org/2000/svg"
           >
-            <svg
-              fill="currentColor"
-              height="1em"
-              viewBox="0 0 24 24"
-              width="1em"
-              xmlns="http://www.w3.org/2000/svg"
-            >
-              <path
-                d="M4 3h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H6l-2.293 2.293c-.63.63-1.707.184-1.707-.707V5a2 2 0 0 1 2-2Zm3 7h10a.97.97 0 0 0 .712-.287A.967.967 0 0 0 18 9a.967.967 0 0 0-.288-.713A.968.968 0 0 0 17 8H7a.968.968 0 0 0-.713.287A.968.968 0 0 0 6 9c0 .283.096.52.287.713.192.191.43.287.713.287Zm0 4h6c.283 0 .52-.096.713-.287A.968.968 0 0 0 14 13a.968.968 0 0 0-.287-.713A.968.968 0 0 0 13 12H7a.967.967 0 0 0-.713.287A.968.968 0 0 0 6 13c0 .283.096.52.287.713.192.191.43.287.713.287Z"
-              />
-            </svg>
-          </div>
-        </button>
-      </div>
+            <path
+              d="M12 17a.97.97 0 0 0 .713-.288A.968.968 0 0 0 13 16v-4a.968.968 0 0 0-.287-.713A.968.968 0 0 0 12 11a.968.968 0 0 0-.713.287A.968.968 0 0 0 11 12v4c0 .283.096.52.287.712.192.192.43.288.713.288Zm0-8c.283 0 .52-.096.713-.287A.967.967 0 0 0 13 8a.967.967 0 0 0-.287-.713A.968.968 0 0 0 12 7a.968.968 0 0 0-.713.287A.967.967 0 0 0 11 8c0 .283.096.52.287.713.192.191.43.287.713.287Zm0 13a9.738 9.738 0 0 1-3.9-.788 10.099 10.099 0 0 1-3.175-2.137c-.9-.9-1.612-1.958-2.137-3.175A9.738 9.738 0 0 1 2 12a9.74 9.74 0 0 1 .788-3.9 10.099 10.099 0 0 1 2.137-3.175c.9-.9 1.958-1.612 3.175-2.137A9.738 9.738 0 0 1 12 2a9.74 9.74 0 0 1 3.9.788 10.098 10.098 0 0 1 3.175 2.137c.9.9 1.613 1.958 2.137 3.175A9.738 9.738 0 0 1 22 12a9.738 9.738 0 0 1-.788 3.9 10.098 10.098 0 0 1-2.137 3.175c-.9.9-1.958 1.613-3.175 2.137A9.738 9.738 0 0 1 12 22Z"
+            />
+          </svg>
+        </div>
+      </button>
       <div
         class="_typography_yh5dq_162 _font-body-sm-medium_yh5dq_50"
       >
@@ -1334,113 +1314,108 @@ exports[`RoomView should not display the timeline when the room encryption is lo
               </div>
             </div>
           </button>
-          <div
-            class="mx_Flex"
-            style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: var(--cpd-space-2x);"
+          <button
+            aria-disabled="true"
+            aria-label="There's no one here to call"
+            class="_icon-button_bh2qc_17"
+            role="button"
+            style="--cpd-icon-button-size: 32px;"
+            tabindex="0"
           >
-            <button
-              aria-disabled="true"
-              aria-label="There's no one here to call"
-              class="_icon-button_bh2qc_17"
-              role="button"
-              style="--cpd-icon-button-size: 32px;"
-              tabindex="0"
+            <div
+              class="_indicator-icon_133tf_26"
+              style="--cpd-icon-button-size: 100%; --cpd-color-icon-tertiary: var(--cpd-color-icon-disabled);"
             >
-              <div
-                class="_indicator-icon_133tf_26"
-                style="--cpd-icon-button-size: 100%; --cpd-color-icon-tertiary: var(--cpd-color-icon-disabled);"
+              <svg
+                aria-labelledby=":r2c:"
+                fill="currentColor"
+                height="1em"
+                viewBox="0 0 24 24"
+                width="1em"
+                xmlns="http://www.w3.org/2000/svg"
               >
-                <svg
-                  aria-labelledby=":r2c:"
-                  fill="currentColor"
-                  height="1em"
-                  viewBox="0 0 24 24"
-                  width="1em"
-                  xmlns="http://www.w3.org/2000/svg"
-                >
-                  <path
-                    d="M6 4h10a2 2 0 0 1 2 2v4.286l3.35-2.871a1 1 0 0 1 1.65.76v7.65a1 1 0 0 1-1.65.76L18 13.715V18a2 2 0 0 1-2 2H6a4 4 0 0 1-4-4V8a4 4 0 0 1 4-4Z"
-                  />
-                </svg>
-              </div>
-            </button>
-            <button
-              aria-disabled="true"
-              aria-label="There's no one here to call"
-              aria-labelledby=":r2h:"
-              class="_icon-button_bh2qc_17"
-              role="button"
-              style="--cpd-icon-button-size: 32px;"
-              tabindex="0"
+                <path
+                  d="M6 4h10a2 2 0 0 1 2 2v4.286l3.35-2.871a1 1 0 0 1 1.65.76v7.65a1 1 0 0 1-1.65.76L18 13.715V18a2 2 0 0 1-2 2H6a4 4 0 0 1-4-4V8a4 4 0 0 1 4-4Z"
+                />
+              </svg>
+            </div>
+          </button>
+          <button
+            aria-disabled="true"
+            aria-label="There's no one here to call"
+            aria-labelledby=":r2h:"
+            class="_icon-button_bh2qc_17"
+            role="button"
+            style="--cpd-icon-button-size: 32px;"
+            tabindex="0"
+          >
+            <div
+              class="_indicator-icon_133tf_26"
+              style="--cpd-icon-button-size: 100%; --cpd-color-icon-tertiary: var(--cpd-color-icon-disabled);"
             >
-              <div
-                class="_indicator-icon_133tf_26"
-                style="--cpd-icon-button-size: 100%; --cpd-color-icon-tertiary: var(--cpd-color-icon-disabled);"
+              <svg
+                fill="currentColor"
+                height="1em"
+                viewBox="0 0 24 24"
+                width="1em"
+                xmlns="http://www.w3.org/2000/svg"
               >
-                <svg
-                  fill="currentColor"
-                  height="1em"
-                  viewBox="0 0 24 24"
-                  width="1em"
-                  xmlns="http://www.w3.org/2000/svg"
-                >
-                  <path
-                    d="m20.958 16.374.039 3.527c0 .285-.11.537-.33.756-.22.22-.472.33-.756.33a15.97 15.97 0 0 1-6.57-1.105 16.223 16.223 0 0 1-5.563-3.663 16.084 16.084 0 0 1-3.653-5.573 16.313 16.313 0 0 1-1.115-6.56c0-.285.11-.537.33-.757.22-.22.471-.329.755-.329l3.528.039a1.069 1.069 0 0 1 1.085.93l.543 3.954c.026.181.013.349-.039.504a1.088 1.088 0 0 1-.271.426l-1.64 1.64c.337.672.721 1.308 1.154 1.909.433.6 1.444 1.696 1.444 1.696s1.095 1.01 1.696 1.444c.6.433 1.237.817 1.909 1.153l1.64-1.64a1.08 1.08 0 0 1 .426-.27c.155-.052.323-.065.504-.04l3.954.543a1.069 1.069 0 0 1 .93 1.085Z"
-                  />
-                </svg>
-              </div>
-            </button>
-            <button
-              aria-label="Room info"
-              aria-labelledby=":r2m:"
-              class="_icon-button_bh2qc_17"
-              role="button"
-              style="--cpd-icon-button-size: 32px;"
-              tabindex="0"
+                <path
+                  d="m20.958 16.374.039 3.527c0 .285-.11.537-.33.756-.22.22-.472.33-.756.33a15.97 15.97 0 0 1-6.57-1.105 16.223 16.223 0 0 1-5.563-3.663 16.084 16.084 0 0 1-3.653-5.573 16.313 16.313 0 0 1-1.115-6.56c0-.285.11-.537.33-.757.22-.22.471-.329.755-.329l3.528.039a1.069 1.069 0 0 1 1.085.93l.543 3.954c.026.181.013.349-.039.504a1.088 1.088 0 0 1-.271.426l-1.64 1.64c.337.672.721 1.308 1.154 1.909.433.6 1.444 1.696 1.444 1.696s1.095 1.01 1.696 1.444c.6.433 1.237.817 1.909 1.153l1.64-1.64a1.08 1.08 0 0 1 .426-.27c.155-.052.323-.065.504-.04l3.954.543a1.069 1.069 0 0 1 .93 1.085Z"
+                />
+              </svg>
+            </div>
+          </button>
+          <button
+            aria-label="Threads"
+            aria-labelledby=":r2m:"
+            class="_icon-button_bh2qc_17"
+            role="button"
+            style="--cpd-icon-button-size: 32px;"
+            tabindex="0"
+          >
+            <div
+              class="_indicator-icon_133tf_26"
+              style="--cpd-icon-button-size: 100%;"
             >
-              <div
-                class="_indicator-icon_133tf_26"
-                style="--cpd-icon-button-size: 100%;"
+              <svg
+                fill="currentColor"
+                height="1em"
+                viewBox="0 0 24 24"
+                width="1em"
+                xmlns="http://www.w3.org/2000/svg"
               >
-                <svg
-                  fill="currentColor"
-                  height="1em"
-                  viewBox="0 0 24 24"
-                  width="1em"
-                  xmlns="http://www.w3.org/2000/svg"
-                >
-                  <path
-                    d="M12 17a.97.97 0 0 0 .713-.288A.968.968 0 0 0 13 16v-4a.968.968 0 0 0-.287-.713A.968.968 0 0 0 12 11a.968.968 0 0 0-.713.287A.968.968 0 0 0 11 12v4c0 .283.096.52.287.712.192.192.43.288.713.288Zm0-8c.283 0 .52-.096.713-.287A.967.967 0 0 0 13 8a.967.967 0 0 0-.287-.713A.968.968 0 0 0 12 7a.968.968 0 0 0-.713.287A.967.967 0 0 0 11 8c0 .283.096.52.287.713.192.191.43.287.713.287Zm0 13a9.738 9.738 0 0 1-3.9-.788 10.099 10.099 0 0 1-3.175-2.137c-.9-.9-1.612-1.958-2.137-3.175A9.738 9.738 0 0 1 2 12a9.74 9.74 0 0 1 .788-3.9 10.099 10.099 0 0 1 2.137-3.175c.9-.9 1.958-1.612 3.175-2.137A9.738 9.738 0 0 1 12 2a9.74 9.74 0 0 1 3.9.788 10.098 10.098 0 0 1 3.175 2.137c.9.9 1.613 1.958 2.137 3.175A9.738 9.738 0 0 1 22 12a9.738 9.738 0 0 1-.788 3.9 10.098 10.098 0 0 1-2.137 3.175c-.9.9-1.958 1.613-3.175 2.137A9.738 9.738 0 0 1 12 22Z"
-                  />
-                </svg>
-              </div>
-            </button>
-            <button
-              aria-label="Threads"
-              aria-labelledby=":r2r:"
-              class="_icon-button_bh2qc_17"
-              role="button"
-              style="--cpd-icon-button-size: 32px;"
-              tabindex="0"
+                <path
+                  d="M4 3h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H6l-2.293 2.293c-.63.63-1.707.184-1.707-.707V5a2 2 0 0 1 2-2Zm3 7h10a.97.97 0 0 0 .712-.287A.967.967 0 0 0 18 9a.967.967 0 0 0-.288-.713A.968.968 0 0 0 17 8H7a.968.968 0 0 0-.713.287A.968.968 0 0 0 6 9c0 .283.096.52.287.713.192.191.43.287.713.287Zm0 4h6c.283 0 .52-.096.713-.287A.968.968 0 0 0 14 13a.968.968 0 0 0-.287-.713A.968.968 0 0 0 13 12H7a.967.967 0 0 0-.713.287A.968.968 0 0 0 6 13c0 .283.096.52.287.713.192.191.43.287.713.287Z"
+                />
+              </svg>
+            </div>
+          </button>
+          <button
+            aria-label="Room info"
+            aria-labelledby=":r2r:"
+            class="_icon-button_bh2qc_17"
+            role="button"
+            style="--cpd-icon-button-size: 32px;"
+            tabindex="0"
+          >
+            <div
+              class="_indicator-icon_133tf_26"
+              style="--cpd-icon-button-size: 100%;"
             >
-              <div
-                class="_indicator-icon_133tf_26"
-                style="--cpd-icon-button-size: 100%;"
+              <svg
+                fill="currentColor"
+                height="1em"
+                viewBox="0 0 24 24"
+                width="1em"
+                xmlns="http://www.w3.org/2000/svg"
               >
-                <svg
-                  fill="currentColor"
-                  height="1em"
-                  viewBox="0 0 24 24"
-                  width="1em"
-                  xmlns="http://www.w3.org/2000/svg"
-                >
-                  <path
-                    d="M4 3h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H6l-2.293 2.293c-.63.63-1.707.184-1.707-.707V5a2 2 0 0 1 2-2Zm3 7h10a.97.97 0 0 0 .712-.287A.967.967 0 0 0 18 9a.967.967 0 0 0-.288-.713A.968.968 0 0 0 17 8H7a.968.968 0 0 0-.713.287A.968.968 0 0 0 6 9c0 .283.096.52.287.713.192.191.43.287.713.287Zm0 4h6c.283 0 .52-.096.713-.287A.968.968 0 0 0 14 13a.968.968 0 0 0-.287-.713A.968.968 0 0 0 13 12H7a.967.967 0 0 0-.713.287A.968.968 0 0 0 6 13c0 .283.096.52.287.713.192.191.43.287.713.287Z"
-                  />
-                </svg>
-              </div>
-            </button>
-          </div>
+                <path
+                  d="M12 17a.97.97 0 0 0 .713-.288A.968.968 0 0 0 13 16v-4a.968.968 0 0 0-.287-.713A.968.968 0 0 0 12 11a.968.968 0 0 0-.713.287A.968.968 0 0 0 11 12v4c0 .283.096.52.287.712.192.192.43.288.713.288Zm0-8c.283 0 .52-.096.713-.287A.967.967 0 0 0 13 8a.967.967 0 0 0-.287-.713A.968.968 0 0 0 12 7a.968.968 0 0 0-.713.287A.967.967 0 0 0 11 8c0 .283.096.52.287.713.192.191.43.287.713.287Zm0 13a9.738 9.738 0 0 1-3.9-.788 10.099 10.099 0 0 1-3.175-2.137c-.9-.9-1.612-1.958-2.137-3.175A9.738 9.738 0 0 1 2 12a9.74 9.74 0 0 1 .788-3.9 10.099 10.099 0 0 1 2.137-3.175c.9-.9 1.958-1.612 3.175-2.137A9.738 9.738 0 0 1 12 2a9.74 9.74 0 0 1 3.9.788 10.098 10.098 0 0 1 3.175 2.137c.9.9 1.613 1.958 2.137 3.175A9.738 9.738 0 0 1 22 12a9.738 9.738 0 0 1-.788 3.9 10.098 10.098 0 0 1-2.137 3.175c-.9.9-1.958 1.613-3.175 2.137A9.738 9.738 0 0 1 12 22Z"
+                />
+              </svg>
+            </div>
+          </button>
           <div
             class="_typography_yh5dq_162 _font-body-sm-medium_yh5dq_50"
           >
@@ -1545,113 +1520,108 @@ exports[`RoomView should not display the timeline when the room encryption is lo
               </div>
             </div>
           </button>
-          <div
-            class="mx_Flex"
-            style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: var(--cpd-space-2x);"
+          <button
+            aria-disabled="true"
+            aria-label="There's no one here to call"
+            class="_icon-button_bh2qc_17"
+            role="button"
+            style="--cpd-icon-button-size: 32px;"
+            tabindex="0"
           >
-            <button
-              aria-disabled="true"
-              aria-label="There's no one here to call"
-              class="_icon-button_bh2qc_17"
-              role="button"
-              style="--cpd-icon-button-size: 32px;"
-              tabindex="0"
+            <div
+              class="_indicator-icon_133tf_26"
+              style="--cpd-icon-button-size: 100%; --cpd-color-icon-tertiary: var(--cpd-color-icon-disabled);"
             >
-              <div
-                class="_indicator-icon_133tf_26"
-                style="--cpd-icon-button-size: 100%; --cpd-color-icon-tertiary: var(--cpd-color-icon-disabled);"
+              <svg
+                aria-labelledby=":r2c:"
+                fill="currentColor"
+                height="1em"
+                viewBox="0 0 24 24"
+                width="1em"
+                xmlns="http://www.w3.org/2000/svg"
               >
-                <svg
-                  aria-labelledby=":r2c:"
-                  fill="currentColor"
-                  height="1em"
-                  viewBox="0 0 24 24"
-                  width="1em"
-                  xmlns="http://www.w3.org/2000/svg"
-                >
-                  <path
-                    d="M6 4h10a2 2 0 0 1 2 2v4.286l3.35-2.871a1 1 0 0 1 1.65.76v7.65a1 1 0 0 1-1.65.76L18 13.715V18a2 2 0 0 1-2 2H6a4 4 0 0 1-4-4V8a4 4 0 0 1 4-4Z"
-                  />
-                </svg>
-              </div>
-            </button>
-            <button
-              aria-disabled="true"
-              aria-label="There's no one here to call"
-              aria-labelledby=":r2h:"
-              class="_icon-button_bh2qc_17"
-              role="button"
-              style="--cpd-icon-button-size: 32px;"
-              tabindex="0"
+                <path
+                  d="M6 4h10a2 2 0 0 1 2 2v4.286l3.35-2.871a1 1 0 0 1 1.65.76v7.65a1 1 0 0 1-1.65.76L18 13.715V18a2 2 0 0 1-2 2H6a4 4 0 0 1-4-4V8a4 4 0 0 1 4-4Z"
+                />
+              </svg>
+            </div>
+          </button>
+          <button
+            aria-disabled="true"
+            aria-label="There's no one here to call"
+            aria-labelledby=":r2h:"
+            class="_icon-button_bh2qc_17"
+            role="button"
+            style="--cpd-icon-button-size: 32px;"
+            tabindex="0"
+          >
+            <div
+              class="_indicator-icon_133tf_26"
+              style="--cpd-icon-button-size: 100%; --cpd-color-icon-tertiary: var(--cpd-color-icon-disabled);"
             >
-              <div
-                class="_indicator-icon_133tf_26"
-                style="--cpd-icon-button-size: 100%; --cpd-color-icon-tertiary: var(--cpd-color-icon-disabled);"
+              <svg
+                fill="currentColor"
+                height="1em"
+                viewBox="0 0 24 24"
+                width="1em"
+                xmlns="http://www.w3.org/2000/svg"
               >
-                <svg
-                  fill="currentColor"
-                  height="1em"
-                  viewBox="0 0 24 24"
-                  width="1em"
-                  xmlns="http://www.w3.org/2000/svg"
-                >
-                  <path
-                    d="m20.958 16.374.039 3.527c0 .285-.11.537-.33.756-.22.22-.472.33-.756.33a15.97 15.97 0 0 1-6.57-1.105 16.223 16.223 0 0 1-5.563-3.663 16.084 16.084 0 0 1-3.653-5.573 16.313 16.313 0 0 1-1.115-6.56c0-.285.11-.537.33-.757.22-.22.471-.329.755-.329l3.528.039a1.069 1.069 0 0 1 1.085.93l.543 3.954c.026.181.013.349-.039.504a1.088 1.088 0 0 1-.271.426l-1.64 1.64c.337.672.721 1.308 1.154 1.909.433.6 1.444 1.696 1.444 1.696s1.095 1.01 1.696 1.444c.6.433 1.237.817 1.909 1.153l1.64-1.64a1.08 1.08 0 0 1 .426-.27c.155-.052.323-.065.504-.04l3.954.543a1.069 1.069 0 0 1 .93 1.085Z"
-                  />
-                </svg>
-              </div>
-            </button>
-            <button
-              aria-label="Room info"
-              aria-labelledby=":r2m:"
-              class="_icon-button_bh2qc_17"
-              role="button"
-              style="--cpd-icon-button-size: 32px;"
-              tabindex="0"
+                <path
+                  d="m20.958 16.374.039 3.527c0 .285-.11.537-.33.756-.22.22-.472.33-.756.33a15.97 15.97 0 0 1-6.57-1.105 16.223 16.223 0 0 1-5.563-3.663 16.084 16.084 0 0 1-3.653-5.573 16.313 16.313 0 0 1-1.115-6.56c0-.285.11-.537.33-.757.22-.22.471-.329.755-.329l3.528.039a1.069 1.069 0 0 1 1.085.93l.543 3.954c.026.181.013.349-.039.504a1.088 1.088 0 0 1-.271.426l-1.64 1.64c.337.672.721 1.308 1.154 1.909.433.6 1.444 1.696 1.444 1.696s1.095 1.01 1.696 1.444c.6.433 1.237.817 1.909 1.153l1.64-1.64a1.08 1.08 0 0 1 .426-.27c.155-.052.323-.065.504-.04l3.954.543a1.069 1.069 0 0 1 .93 1.085Z"
+                />
+              </svg>
+            </div>
+          </button>
+          <button
+            aria-label="Threads"
+            aria-labelledby=":r2m:"
+            class="_icon-button_bh2qc_17"
+            role="button"
+            style="--cpd-icon-button-size: 32px;"
+            tabindex="0"
+          >
+            <div
+              class="_indicator-icon_133tf_26"
+              style="--cpd-icon-button-size: 100%;"
             >
-              <div
-                class="_indicator-icon_133tf_26"
-                style="--cpd-icon-button-size: 100%;"
+              <svg
+                fill="currentColor"
+                height="1em"
+                viewBox="0 0 24 24"
+                width="1em"
+                xmlns="http://www.w3.org/2000/svg"
               >
-                <svg
-                  fill="currentColor"
-                  height="1em"
-                  viewBox="0 0 24 24"
-                  width="1em"
-                  xmlns="http://www.w3.org/2000/svg"
-                >
-                  <path
-                    d="M12 17a.97.97 0 0 0 .713-.288A.968.968 0 0 0 13 16v-4a.968.968 0 0 0-.287-.713A.968.968 0 0 0 12 11a.968.968 0 0 0-.713.287A.968.968 0 0 0 11 12v4c0 .283.096.52.287.712.192.192.43.288.713.288Zm0-8c.283 0 .52-.096.713-.287A.967.967 0 0 0 13 8a.967.967 0 0 0-.287-.713A.968.968 0 0 0 12 7a.968.968 0 0 0-.713.287A.967.967 0 0 0 11 8c0 .283.096.52.287.713.192.191.43.287.713.287Zm0 13a9.738 9.738 0 0 1-3.9-.788 10.099 10.099 0 0 1-3.175-2.137c-.9-.9-1.612-1.958-2.137-3.175A9.738 9.738 0 0 1 2 12a9.74 9.74 0 0 1 .788-3.9 10.099 10.099 0 0 1 2.137-3.175c.9-.9 1.958-1.612 3.175-2.137A9.738 9.738 0 0 1 12 2a9.74 9.74 0 0 1 3.9.788 10.098 10.098 0 0 1 3.175 2.137c.9.9 1.613 1.958 2.137 3.175A9.738 9.738 0 0 1 22 12a9.738 9.738 0 0 1-.788 3.9 10.098 10.098 0 0 1-2.137 3.175c-.9.9-1.958 1.613-3.175 2.137A9.738 9.738 0 0 1 12 22Z"
-                  />
-                </svg>
-              </div>
-            </button>
-            <button
-              aria-label="Threads"
-              aria-labelledby=":r2r:"
-              class="_icon-button_bh2qc_17"
-              role="button"
-              style="--cpd-icon-button-size: 32px;"
-              tabindex="0"
+                <path
+                  d="M4 3h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H6l-2.293 2.293c-.63.63-1.707.184-1.707-.707V5a2 2 0 0 1 2-2Zm3 7h10a.97.97 0 0 0 .712-.287A.967.967 0 0 0 18 9a.967.967 0 0 0-.288-.713A.968.968 0 0 0 17 8H7a.968.968 0 0 0-.713.287A.968.968 0 0 0 6 9c0 .283.096.52.287.713.192.191.43.287.713.287Zm0 4h6c.283 0 .52-.096.713-.287A.968.968 0 0 0 14 13a.968.968 0 0 0-.287-.713A.968.968 0 0 0 13 12H7a.967.967 0 0 0-.713.287A.968.968 0 0 0 6 13c0 .283.096.52.287.713.192.191.43.287.713.287Z"
+                />
+              </svg>
+            </div>
+          </button>
+          <button
+            aria-label="Room info"
+            aria-labelledby=":r2r:"
+            class="_icon-button_bh2qc_17"
+            role="button"
+            style="--cpd-icon-button-size: 32px;"
+            tabindex="0"
+          >
+            <div
+              class="_indicator-icon_133tf_26"
+              style="--cpd-icon-button-size: 100%;"
             >
-              <div
-                class="_indicator-icon_133tf_26"
-                style="--cpd-icon-button-size: 100%;"
+              <svg
+                fill="currentColor"
+                height="1em"
+                viewBox="0 0 24 24"
+                width="1em"
+                xmlns="http://www.w3.org/2000/svg"
               >
-                <svg
-                  fill="currentColor"
-                  height="1em"
-                  viewBox="0 0 24 24"
-                  width="1em"
-                  xmlns="http://www.w3.org/2000/svg"
-                >
-                  <path
-                    d="M4 3h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H6l-2.293 2.293c-.63.63-1.707.184-1.707-.707V5a2 2 0 0 1 2-2Zm3 7h10a.97.97 0 0 0 .712-.287A.967.967 0 0 0 18 9a.967.967 0 0 0-.288-.713A.968.968 0 0 0 17 8H7a.968.968 0 0 0-.713.287A.968.968 0 0 0 6 9c0 .283.096.52.287.713.192.191.43.287.713.287Zm0 4h6c.283 0 .52-.096.713-.287A.968.968 0 0 0 14 13a.968.968 0 0 0-.287-.713A.968.968 0 0 0 13 12H7a.967.967 0 0 0-.713.287A.968.968 0 0 0 6 13c0 .283.096.52.287.713.192.191.43.287.713.287Z"
-                  />
-                </svg>
-              </div>
-            </button>
-          </div>
+                <path
+                  d="M12 17a.97.97 0 0 0 .713-.288A.968.968 0 0 0 13 16v-4a.968.968 0 0 0-.287-.713A.968.968 0 0 0 12 11a.968.968 0 0 0-.713.287A.968.968 0 0 0 11 12v4c0 .283.096.52.287.712.192.192.43.288.713.288Zm0-8c.283 0 .52-.096.713-.287A.967.967 0 0 0 13 8a.967.967 0 0 0-.287-.713A.968.968 0 0 0 12 7a.968.968 0 0 0-.713.287A.967.967 0 0 0 11 8c0 .283.096.52.287.713.192.191.43.287.713.287Zm0 13a9.738 9.738 0 0 1-3.9-.788 10.099 10.099 0 0 1-3.175-2.137c-.9-.9-1.612-1.958-2.137-3.175A9.738 9.738 0 0 1 2 12a9.74 9.74 0 0 1 .788-3.9 10.099 10.099 0 0 1 2.137-3.175c.9-.9 1.958-1.612 3.175-2.137A9.738 9.738 0 0 1 12 2a9.74 9.74 0 0 1 3.9.788 10.098 10.098 0 0 1 3.175 2.137c.9.9 1.613 1.958 2.137 3.175A9.738 9.738 0 0 1 22 12a9.738 9.738 0 0 1-.788 3.9 10.098 10.098 0 0 1-2.137 3.175c-.9.9-1.958 1.613-3.175 2.137A9.738 9.738 0 0 1 12 22Z"
+                />
+              </svg>
+            </div>
+          </button>
           <div
             class="_typography_yh5dq_162 _font-body-sm-medium_yh5dq_50"
           >
@@ -1929,86 +1899,81 @@ exports[`RoomView video rooms should render joined video room view 1`] = `
               </div>
             </div>
           </button>
-          <div
-            class="mx_Flex"
-            style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: var(--cpd-space-2x);"
+          <button
+            aria-label="Chat"
+            aria-labelledby=":r7c:"
+            class="_icon-button_bh2qc_17"
+            role="button"
+            style="--cpd-icon-button-size: 32px;"
+            tabindex="0"
           >
-            <button
-              aria-label="Room info"
-              aria-labelledby=":r7c:"
-              class="_icon-button_bh2qc_17"
-              role="button"
-              style="--cpd-icon-button-size: 32px;"
-              tabindex="0"
+            <div
+              class="_indicator-icon_133tf_26"
+              style="--cpd-icon-button-size: 100%;"
             >
-              <div
-                class="_indicator-icon_133tf_26"
-                style="--cpd-icon-button-size: 100%;"
+              <svg
+                fill="currentColor"
+                height="1em"
+                viewBox="0 0 24 24"
+                width="1em"
+                xmlns="http://www.w3.org/2000/svg"
               >
-                <svg
-                  fill="currentColor"
-                  height="1em"
-                  viewBox="0 0 24 24"
-                  width="1em"
-                  xmlns="http://www.w3.org/2000/svg"
-                >
-                  <path
-                    d="M12 17a.97.97 0 0 0 .713-.288A.968.968 0 0 0 13 16v-4a.968.968 0 0 0-.287-.713A.968.968 0 0 0 12 11a.968.968 0 0 0-.713.287A.968.968 0 0 0 11 12v4c0 .283.096.52.287.712.192.192.43.288.713.288Zm0-8c.283 0 .52-.096.713-.287A.967.967 0 0 0 13 8a.967.967 0 0 0-.287-.713A.968.968 0 0 0 12 7a.968.968 0 0 0-.713.287A.967.967 0 0 0 11 8c0 .283.096.52.287.713.192.191.43.287.713.287Zm0 13a9.738 9.738 0 0 1-3.9-.788 10.099 10.099 0 0 1-3.175-2.137c-.9-.9-1.612-1.958-2.137-3.175A9.738 9.738 0 0 1 2 12a9.74 9.74 0 0 1 .788-3.9 10.099 10.099 0 0 1 2.137-3.175c.9-.9 1.958-1.612 3.175-2.137A9.738 9.738 0 0 1 12 2a9.74 9.74 0 0 1 3.9.788 10.098 10.098 0 0 1 3.175 2.137c.9.9 1.613 1.958 2.137 3.175A9.738 9.738 0 0 1 22 12a9.738 9.738 0 0 1-.788 3.9 10.098 10.098 0 0 1-2.137 3.175c-.9.9-1.958 1.613-3.175 2.137A9.738 9.738 0 0 1 12 22Z"
-                  />
-                </svg>
-              </div>
-            </button>
-            <button
-              aria-label="Chat"
-              aria-labelledby=":r7h:"
-              class="_icon-button_bh2qc_17"
-              role="button"
-              style="--cpd-icon-button-size: 32px;"
-              tabindex="0"
+                <path
+                  d="M2.95 16.3 1.5 21.25a.936.936 0 0 0 .25 1 .936.936 0 0 0 1 .25l4.95-1.45a10.23 10.23 0 0 0 2.1.712c.717.159 1.45.238 2.2.238a9.737 9.737 0 0 0 3.9-.788 10.098 10.098 0 0 0 3.175-2.137c.9-.9 1.613-1.958 2.137-3.175A9.738 9.738 0 0 0 22 12a9.738 9.738 0 0 0-.788-3.9 10.099 10.099 0 0 0-2.137-3.175c-.9-.9-1.958-1.612-3.175-2.137A9.737 9.737 0 0 0 12 2a9.737 9.737 0 0 0-3.9.788 10.099 10.099 0 0 0-3.175 2.137c-.9.9-1.612 1.958-2.137 3.175A9.738 9.738 0 0 0 2 12a10.179 10.179 0 0 0 .95 4.3Z"
+                />
+              </svg>
+            </div>
+          </button>
+          <button
+            aria-label="Threads"
+            aria-labelledby=":r7h:"
+            class="_icon-button_bh2qc_17"
+            role="button"
+            style="--cpd-icon-button-size: 32px;"
+            tabindex="0"
+          >
+            <div
+              class="_indicator-icon_133tf_26"
+              style="--cpd-icon-button-size: 100%;"
             >
-              <div
-                class="_indicator-icon_133tf_26"
-                style="--cpd-icon-button-size: 100%;"
+              <svg
+                fill="currentColor"
+                height="1em"
+                viewBox="0 0 24 24"
+                width="1em"
+                xmlns="http://www.w3.org/2000/svg"
               >
-                <svg
-                  fill="currentColor"
-                  height="1em"
-                  viewBox="0 0 24 24"
-                  width="1em"
-                  xmlns="http://www.w3.org/2000/svg"
-                >
-                  <path
-                    d="M2.95 16.3 1.5 21.25a.936.936 0 0 0 .25 1 .936.936 0 0 0 1 .25l4.95-1.45a10.23 10.23 0 0 0 2.1.712c.717.159 1.45.238 2.2.238a9.737 9.737 0 0 0 3.9-.788 10.098 10.098 0 0 0 3.175-2.137c.9-.9 1.613-1.958 2.137-3.175A9.738 9.738 0 0 0 22 12a9.738 9.738 0 0 0-.788-3.9 10.099 10.099 0 0 0-2.137-3.175c-.9-.9-1.958-1.612-3.175-2.137A9.737 9.737 0 0 0 12 2a9.737 9.737 0 0 0-3.9.788 10.099 10.099 0 0 0-3.175 2.137c-.9.9-1.612 1.958-2.137 3.175A9.738 9.738 0 0 0 2 12a10.179 10.179 0 0 0 .95 4.3Z"
-                  />
-                </svg>
-              </div>
-            </button>
-            <button
-              aria-label="Threads"
-              aria-labelledby=":r7m:"
-              class="_icon-button_bh2qc_17"
-              role="button"
-              style="--cpd-icon-button-size: 32px;"
-              tabindex="0"
+                <path
+                  d="M4 3h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H6l-2.293 2.293c-.63.63-1.707.184-1.707-.707V5a2 2 0 0 1 2-2Zm3 7h10a.97.97 0 0 0 .712-.287A.967.967 0 0 0 18 9a.967.967 0 0 0-.288-.713A.968.968 0 0 0 17 8H7a.968.968 0 0 0-.713.287A.968.968 0 0 0 6 9c0 .283.096.52.287.713.192.191.43.287.713.287Zm0 4h6c.283 0 .52-.096.713-.287A.968.968 0 0 0 14 13a.968.968 0 0 0-.287-.713A.968.968 0 0 0 13 12H7a.967.967 0 0 0-.713.287A.968.968 0 0 0 6 13c0 .283.096.52.287.713.192.191.43.287.713.287Z"
+                />
+              </svg>
+            </div>
+          </button>
+          <button
+            aria-label="Room info"
+            aria-labelledby=":r7m:"
+            class="_icon-button_bh2qc_17"
+            role="button"
+            style="--cpd-icon-button-size: 32px;"
+            tabindex="0"
+          >
+            <div
+              class="_indicator-icon_133tf_26"
+              style="--cpd-icon-button-size: 100%;"
             >
-              <div
-                class="_indicator-icon_133tf_26"
-                style="--cpd-icon-button-size: 100%;"
+              <svg
+                fill="currentColor"
+                height="1em"
+                viewBox="0 0 24 24"
+                width="1em"
+                xmlns="http://www.w3.org/2000/svg"
               >
-                <svg
-                  fill="currentColor"
-                  height="1em"
-                  viewBox="0 0 24 24"
-                  width="1em"
-                  xmlns="http://www.w3.org/2000/svg"
-                >
-                  <path
-                    d="M4 3h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H6l-2.293 2.293c-.63.63-1.707.184-1.707-.707V5a2 2 0 0 1 2-2Zm3 7h10a.97.97 0 0 0 .712-.287A.967.967 0 0 0 18 9a.967.967 0 0 0-.288-.713A.968.968 0 0 0 17 8H7a.968.968 0 0 0-.713.287A.968.968 0 0 0 6 9c0 .283.096.52.287.713.192.191.43.287.713.287Zm0 4h6c.283 0 .52-.096.713-.287A.968.968 0 0 0 14 13a.968.968 0 0 0-.287-.713A.968.968 0 0 0 13 12H7a.967.967 0 0 0-.713.287A.968.968 0 0 0 6 13c0 .283.096.52.287.713.192.191.43.287.713.287Z"
-                  />
-                </svg>
-              </div>
-            </button>
-          </div>
+                <path
+                  d="M12 17a.97.97 0 0 0 .713-.288A.968.968 0 0 0 13 16v-4a.968.968 0 0 0-.287-.713A.968.968 0 0 0 12 11a.968.968 0 0 0-.713.287A.968.968 0 0 0 11 12v4c0 .283.096.52.287.712.192.192.43.288.713.288Zm0-8c.283 0 .52-.096.713-.287A.967.967 0 0 0 13 8a.967.967 0 0 0-.287-.713A.968.968 0 0 0 12 7a.968.968 0 0 0-.713.287A.967.967 0 0 0 11 8c0 .283.096.52.287.713.192.191.43.287.713.287Zm0 13a9.738 9.738 0 0 1-3.9-.788 10.099 10.099 0 0 1-3.175-2.137c-.9-.9-1.612-1.958-2.137-3.175A9.738 9.738 0 0 1 2 12a9.74 9.74 0 0 1 .788-3.9 10.099 10.099 0 0 1 2.137-3.175c.9-.9 1.958-1.612 3.175-2.137A9.738 9.738 0 0 1 12 2a9.74 9.74 0 0 1 3.9.788 10.098 10.098 0 0 1 3.175 2.137c.9.9 1.613 1.958 2.137 3.175A9.738 9.738 0 0 1 22 12a9.738 9.738 0 0 1-.788 3.9 10.098 10.098 0 0 1-2.137 3.175c-.9.9-1.958 1.613-3.175 2.137A9.738 9.738 0 0 1 12 22Z"
+                />
+              </svg>
+            </div>
+          </button>
           <div
             class="_typography_yh5dq_162 _font-body-sm-medium_yh5dq_50"
           >
@@ -2029,7 +1994,7 @@ exports[`RoomView video rooms should render joined video room view 1`] = `
       </div>
       <div
         class="mx_RightPanel_ResizeWrapper"
-        style="position: relative; user-select: auto; width: 420px; height: 100%; max-width: 50%; min-width: 264px; box-sizing: border-box; flex-shrink: 0;"
+        style="position: relative; user-select: auto; width: 420px; height: 100%; max-width: 50%; min-width: 320px; box-sizing: border-box; flex-shrink: 0;"
       >
         <aside
           class="mx_RightPanel"
diff --git a/test/unit-tests/components/structures/auth/CompleteSecurity-test.tsx b/test/unit-tests/components/structures/auth/CompleteSecurity-test.tsx
index 250decbdfcc..1c9cd97ce21 100644
--- a/test/unit-tests/components/structures/auth/CompleteSecurity-test.tsx
+++ b/test/unit-tests/components/structures/auth/CompleteSecurity-test.tsx
@@ -1,7 +1,7 @@
 /*
 Copyright 2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/structures/auth/ForgotPassword-test.tsx b/test/unit-tests/components/structures/auth/ForgotPassword-test.tsx
index d57c4c6e776..b55fd2c99c3 100644
--- a/test/unit-tests/components/structures/auth/ForgotPassword-test.tsx
+++ b/test/unit-tests/components/structures/auth/ForgotPassword-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/structures/auth/Login-test.tsx b/test/unit-tests/components/structures/auth/Login-test.tsx
index 7105de4d223..3b1a85b3e9b 100644
--- a/test/unit-tests/components/structures/auth/Login-test.tsx
+++ b/test/unit-tests/components/structures/auth/Login-test.tsx
@@ -1,7 +1,7 @@
 /*
 Copyright 2019-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -19,7 +19,6 @@ import { mkServerConfig, mockPlatformPeg, unmockPlatformPeg } from "../../../../
 import Login from "../../../../../src/components/structures/auth/Login";
 import BasePlatform from "../../../../../src/BasePlatform";
 import SettingsStore from "../../../../../src/settings/SettingsStore";
-import { Features } from "../../../../../src/settings/Settings";
 import * as registerClientUtils from "../../../../../src/utils/oidc/registerClient";
 import { makeDelegatedAuthConfig } from "../../../../test-utils/oidc";
 
@@ -371,9 +370,6 @@ describe("Login", function () {
         const delegatedAuth = makeDelegatedAuthConfig(issuer);
         beforeEach(() => {
             jest.spyOn(logger, "error");
-            jest.spyOn(SettingsStore, "getValue").mockImplementation(
-                (settingName) => settingName === Features.OidcNativeFlow,
-            );
         });
 
         afterEach(() => {
diff --git a/test/unit-tests/components/structures/auth/LoginSplashView-test.tsx b/test/unit-tests/components/structures/auth/LoginSplashView-test.tsx
index 2fcbcbb2b52..17582167303 100644
--- a/test/unit-tests/components/structures/auth/LoginSplashView-test.tsx
+++ b/test/unit-tests/components/structures/auth/LoginSplashView-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/structures/auth/Registration-test.tsx b/test/unit-tests/components/structures/auth/Registration-test.tsx
index 526008a7e6a..82ac0b666cd 100644
--- a/test/unit-tests/components/structures/auth/Registration-test.tsx
+++ b/test/unit-tests/components/structures/auth/Registration-test.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 Copyright 2019 New Vector Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -22,8 +22,6 @@ import {
 } from "../../../../test-utils";
 import Registration from "../../../../../src/components/structures/auth/Registration";
 import { makeDelegatedAuthConfig } from "../../../../test-utils/oidc";
-import SettingsStore from "../../../../../src/settings/SettingsStore";
-import { Features } from "../../../../../src/settings/Settings";
 import { startOidcLogin } from "../../../../../src/utils/oidc/authorize";
 
 jest.mock("../../../../../src/utils/oidc/authorize", () => ({
@@ -180,49 +178,29 @@ describe("Registration", function () {
             fetchMock.get(authConfig.metadata.jwks_uri!, { keys: [] });
         });
 
-        describe("when oidc native flow is not enabled in settings", () => {
-            beforeEach(() => {
-                jest.spyOn(SettingsStore, "getValue").mockReturnValue(false);
-            });
+        it("should display oidc-native continue button", async () => {
+            const { container } = getComponent(defaultHsUrl, defaultIsUrl, authConfig);
+            await waitForElementToBeRemoved(() => screen.queryAllByLabelText("Loading…"));
+            // no form
+            expect(container.querySelector("form")).toBeFalsy();
 
-            it("should display user/pass registration form", async () => {
-                const { container } = getComponent(defaultHsUrl, defaultIsUrl, authConfig);
-                await waitForElementToBeRemoved(() => screen.queryAllByLabelText("Loading…"));
-                expect(container.querySelector("form")).toBeTruthy();
-                expect(mockClient.loginFlows).toHaveBeenCalled();
-                expect(mockClient.registerRequest).toHaveBeenCalled();
-            });
+            expect(await screen.findByText("Continue")).toBeTruthy();
         });
 
-        describe("when oidc native flow is enabled in settings", () => {
-            beforeEach(() => {
-                jest.spyOn(SettingsStore, "getValue").mockImplementation((key) => key === Features.OidcNativeFlow);
-            });
+        it("should start OIDC login flow as registration on button click", async () => {
+            getComponent(defaultHsUrl, defaultIsUrl, authConfig);
+            await waitForElementToBeRemoved(() => screen.queryAllByLabelText("Loading…"));
 
-            it("should display oidc-native continue button", async () => {
-                const { container } = getComponent(defaultHsUrl, defaultIsUrl, authConfig);
-                await waitForElementToBeRemoved(() => screen.queryAllByLabelText("Loading…"));
-                // no form
-                expect(container.querySelector("form")).toBeFalsy();
-
-                expect(await screen.findByText("Continue")).toBeTruthy();
-            });
+            fireEvent.click(await screen.findByText("Continue"));
 
-            it("should start OIDC login flow as registration on button click", async () => {
-                getComponent(defaultHsUrl, defaultIsUrl, authConfig);
-                await waitForElementToBeRemoved(() => screen.queryAllByLabelText("Loading…"));
-
-                fireEvent.click(await screen.findByText("Continue"));
-
-                expect(startOidcLogin).toHaveBeenCalledWith(
-                    authConfig,
-                    clientId,
-                    defaultHsUrl,
-                    defaultIsUrl,
-                    // isRegistration
-                    true,
-                );
-            });
+            expect(startOidcLogin).toHaveBeenCalledWith(
+                authConfig,
+                clientId,
+                defaultHsUrl,
+                defaultIsUrl,
+                // isRegistration
+                true,
+            );
         });
 
         describe("when is mobile registeration", () => {
diff --git a/test/unit-tests/components/views/Validation-test.ts b/test/unit-tests/components/views/Validation-test.ts
index 381c6620c4d..7682213d667 100644
--- a/test/unit-tests/components/views/Validation-test.ts
+++ b/test/unit-tests/components/views/Validation-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/VerificationShowSas-test.tsx b/test/unit-tests/components/views/VerificationShowSas-test.tsx
index b720c90d6b5..3e29e2098c9 100644
--- a/test/unit-tests/components/views/VerificationShowSas-test.tsx
+++ b/test/unit-tests/components/views/VerificationShowSas-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/audio_messages/RecordingPlayback-test.tsx b/test/unit-tests/components/views/audio_messages/RecordingPlayback-test.tsx
index 419357e5c84..6c96aacb8e8 100644
--- a/test/unit-tests/components/views/audio_messages/RecordingPlayback-test.tsx
+++ b/test/unit-tests/components/views/audio_messages/RecordingPlayback-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/audio_messages/SeekBar-test.tsx b/test/unit-tests/components/views/audio_messages/SeekBar-test.tsx
index 2ea445b499e..95aaa7ada88 100644
--- a/test/unit-tests/components/views/audio_messages/SeekBar-test.tsx
+++ b/test/unit-tests/components/views/audio_messages/SeekBar-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/auth/AuthFooter-test.tsx b/test/unit-tests/components/views/auth/AuthFooter-test.tsx
index f8d0d8fd5ea..f92a304299a 100644
--- a/test/unit-tests/components/views/auth/AuthFooter-test.tsx
+++ b/test/unit-tests/components/views/auth/AuthFooter-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/auth/AuthHeaderLogo-test.tsx b/test/unit-tests/components/views/auth/AuthHeaderLogo-test.tsx
index ce187805e41..706e4d5d396 100644
--- a/test/unit-tests/components/views/auth/AuthHeaderLogo-test.tsx
+++ b/test/unit-tests/components/views/auth/AuthHeaderLogo-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/auth/AuthPage-test.tsx b/test/unit-tests/components/views/auth/AuthPage-test.tsx
index 836b08f20b8..543342661e4 100644
--- a/test/unit-tests/components/views/auth/AuthPage-test.tsx
+++ b/test/unit-tests/components/views/auth/AuthPage-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/auth/CountryDropdown-test.tsx b/test/unit-tests/components/views/auth/CountryDropdown-test.tsx
index d443f6db5a4..5f3ee8c9087 100644
--- a/test/unit-tests/components/views/auth/CountryDropdown-test.tsx
+++ b/test/unit-tests/components/views/auth/CountryDropdown-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/auth/InteractiveAuthEntryComponents-test.tsx b/test/unit-tests/components/views/auth/InteractiveAuthEntryComponents-test.tsx
index ee6375a1f6d..41408edd198 100644
--- a/test/unit-tests/components/views/auth/InteractiveAuthEntryComponents-test.tsx
+++ b/test/unit-tests/components/views/auth/InteractiveAuthEntryComponents-test.tsx
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2024 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/test/unit-tests/components/views/auth/RegistrationToken-test.tsx b/test/unit-tests/components/views/auth/RegistrationToken-test.tsx
index 7a01d5dc334..cf9f8268a03 100644
--- a/test/unit-tests/components/views/auth/RegistrationToken-test.tsx
+++ b/test/unit-tests/components/views/auth/RegistrationToken-test.tsx
@@ -4,7 +4,7 @@ Copyright 2022 The Matrix.org Foundation C.I.C.
 Copyright 2022 Callum Brown
 Copyright 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/avatars/DecoratedRoomAvatar-test.tsx b/test/unit-tests/components/views/avatars/DecoratedRoomAvatar-test.tsx
index 1ef28a887f7..c1c6a2ce982 100644
--- a/test/unit-tests/components/views/avatars/DecoratedRoomAvatar-test.tsx
+++ b/test/unit-tests/components/views/avatars/DecoratedRoomAvatar-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/avatars/MemberAvatar-test.tsx b/test/unit-tests/components/views/avatars/MemberAvatar-test.tsx
index 1c5bf3a44fd..1239d7e5adb 100644
--- a/test/unit-tests/components/views/avatars/MemberAvatar-test.tsx
+++ b/test/unit-tests/components/views/avatars/MemberAvatar-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/avatars/RoomAvatar-test.tsx b/test/unit-tests/components/views/avatars/RoomAvatar-test.tsx
index 2c9db7b0494..e3e8715cfba 100644
--- a/test/unit-tests/components/views/avatars/RoomAvatar-test.tsx
+++ b/test/unit-tests/components/views/avatars/RoomAvatar-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/avatars/WithPresenceIndicator-test.tsx b/test/unit-tests/components/views/avatars/WithPresenceIndicator-test.tsx
index e6a677861d3..f5c26aa7efa 100644
--- a/test/unit-tests/components/views/avatars/WithPresenceIndicator-test.tsx
+++ b/test/unit-tests/components/views/avatars/WithPresenceIndicator-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/beacon/BeaconListItem-test.tsx b/test/unit-tests/components/views/beacon/BeaconListItem-test.tsx
index 406923a6bec..f44a1d72db3 100644
--- a/test/unit-tests/components/views/beacon/BeaconListItem-test.tsx
+++ b/test/unit-tests/components/views/beacon/BeaconListItem-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/beacon/BeaconMarker-test.tsx b/test/unit-tests/components/views/beacon/BeaconMarker-test.tsx
index 9852655e3da..625d61b1c3e 100644
--- a/test/unit-tests/components/views/beacon/BeaconMarker-test.tsx
+++ b/test/unit-tests/components/views/beacon/BeaconMarker-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/beacon/BeaconStatus-test.tsx b/test/unit-tests/components/views/beacon/BeaconStatus-test.tsx
index 2cdb91de32f..b5ebce9a076 100644
--- a/test/unit-tests/components/views/beacon/BeaconStatus-test.tsx
+++ b/test/unit-tests/components/views/beacon/BeaconStatus-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/beacon/BeaconViewDialog-test.tsx b/test/unit-tests/components/views/beacon/BeaconViewDialog-test.tsx
index 0ad67a4b9b6..2c879468d61 100644
--- a/test/unit-tests/components/views/beacon/BeaconViewDialog-test.tsx
+++ b/test/unit-tests/components/views/beacon/BeaconViewDialog-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/beacon/DialogSidebar-test.tsx b/test/unit-tests/components/views/beacon/DialogSidebar-test.tsx
index 7ec495e65b2..ca76d6fd59a 100644
--- a/test/unit-tests/components/views/beacon/DialogSidebar-test.tsx
+++ b/test/unit-tests/components/views/beacon/DialogSidebar-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/beacon/LeftPanelLiveShareWarning-test.tsx b/test/unit-tests/components/views/beacon/LeftPanelLiveShareWarning-test.tsx
index 03cc6153076..aa83fefb9a9 100644
--- a/test/unit-tests/components/views/beacon/LeftPanelLiveShareWarning-test.tsx
+++ b/test/unit-tests/components/views/beacon/LeftPanelLiveShareWarning-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/beacon/OwnBeaconStatus-test.tsx b/test/unit-tests/components/views/beacon/OwnBeaconStatus-test.tsx
index beaa314a215..055394f582a 100644
--- a/test/unit-tests/components/views/beacon/OwnBeaconStatus-test.tsx
+++ b/test/unit-tests/components/views/beacon/OwnBeaconStatus-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/beacon/RoomCallBanner-test.tsx b/test/unit-tests/components/views/beacon/RoomCallBanner-test.tsx
index 2929b0adfa5..e8fefe05712 100644
--- a/test/unit-tests/components/views/beacon/RoomCallBanner-test.tsx
+++ b/test/unit-tests/components/views/beacon/RoomCallBanner-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/beacon/ShareLatestLocation-test.tsx b/test/unit-tests/components/views/beacon/ShareLatestLocation-test.tsx
index 61160238110..9c4b9da9454 100644
--- a/test/unit-tests/components/views/beacon/ShareLatestLocation-test.tsx
+++ b/test/unit-tests/components/views/beacon/ShareLatestLocation-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/beacon/StyledLiveBeaconIcon-test.tsx b/test/unit-tests/components/views/beacon/StyledLiveBeaconIcon-test.tsx
index f4357bd5d9f..30c2bf5d76d 100644
--- a/test/unit-tests/components/views/beacon/StyledLiveBeaconIcon-test.tsx
+++ b/test/unit-tests/components/views/beacon/StyledLiveBeaconIcon-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/beta/BetaCard-test.tsx b/test/unit-tests/components/views/beta/BetaCard-test.tsx
index 7d721d14877..42efb1cd348 100644
--- a/test/unit-tests/components/views/beta/BetaCard-test.tsx
+++ b/test/unit-tests/components/views/beta/BetaCard-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -14,13 +14,14 @@ import { shouldShowFeedback } from "../../../../../src/utils/Feedback";
 import BetaCard from "../../../../../src/components/views/beta/BetaCard";
 import SettingsStore from "../../../../../src/settings/SettingsStore";
 import { TranslationKey } from "../../../../../src/languageHandler";
+import { FeatureSettingKey } from "../../../../../src/settings/Settings.tsx";
 
 jest.mock("../../../../../src/utils/Feedback");
 jest.mock("../../../../../src/settings/SettingsStore");
 
 describe("<BetaCard />", () => {
     describe("Feedback prompt", () => {
-        const featureId = "featureId";
+        const featureId = "featureId" as FeatureSettingKey;
 
         beforeEach(() => {
             mocked(SettingsStore).getBetaInfo.mockReturnValue({
diff --git a/test/unit-tests/components/views/context_menus/ContextMenu-test.tsx b/test/unit-tests/components/views/context_menus/ContextMenu-test.tsx
index 75f33e66ddb..bbc4e4d112c 100644
--- a/test/unit-tests/components/views/context_menus/ContextMenu-test.tsx
+++ b/test/unit-tests/components/views/context_menus/ContextMenu-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/context_menus/EmbeddedPage-test.tsx b/test/unit-tests/components/views/context_menus/EmbeddedPage-test.tsx
index f895e517ba2..17409635830 100644
--- a/test/unit-tests/components/views/context_menus/EmbeddedPage-test.tsx
+++ b/test/unit-tests/components/views/context_menus/EmbeddedPage-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/context_menus/MessageContextMenu-test.tsx b/test/unit-tests/components/views/context_menus/MessageContextMenu-test.tsx
index 142840fd5a5..1cfc1a03f65 100644
--- a/test/unit-tests/components/views/context_menus/MessageContextMenu-test.tsx
+++ b/test/unit-tests/components/views/context_menus/MessageContextMenu-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/context_menus/RoomGeneralContextMenu-test.tsx b/test/unit-tests/components/views/context_menus/RoomGeneralContextMenu-test.tsx
index 7ef2062d87d..10aade5b54b 100644
--- a/test/unit-tests/components/views/context_menus/RoomGeneralContextMenu-test.tsx
+++ b/test/unit-tests/components/views/context_menus/RoomGeneralContextMenu-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022, 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/context_menus/SpaceContextMenu-test.tsx b/test/unit-tests/components/views/context_menus/SpaceContextMenu-test.tsx
index 42860e061ec..8b8a565aa48 100644
--- a/test/unit-tests/components/views/context_menus/SpaceContextMenu-test.tsx
+++ b/test/unit-tests/components/views/context_menus/SpaceContextMenu-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/context_menus/ThreadListContextMenu-test.tsx b/test/unit-tests/components/views/context_menus/ThreadListContextMenu-test.tsx
index c09b4986e85..0ef43d1b801 100644
--- a/test/unit-tests/components/views/context_menus/ThreadListContextMenu-test.tsx
+++ b/test/unit-tests/components/views/context_menus/ThreadListContextMenu-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/context_menus/WidgetContextMenu-test.tsx b/test/unit-tests/components/views/context_menus/WidgetContextMenu-test.tsx
index 1a830656329..37dd1925258 100644
--- a/test/unit-tests/components/views/context_menus/WidgetContextMenu-test.tsx
+++ b/test/unit-tests/components/views/context_menus/WidgetContextMenu-test.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2023 Mikhail Aheichyk
 Copyright 2023 Nordeck IT + Consulting GmbH.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/dialogs/AccessSecretStorageDialog-test.tsx b/test/unit-tests/components/views/dialogs/AccessSecretStorageDialog-test.tsx
index f5b0b1e0742..cb877d8a11d 100644
--- a/test/unit-tests/components/views/dialogs/AccessSecretStorageDialog-test.tsx
+++ b/test/unit-tests/components/views/dialogs/AccessSecretStorageDialog-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020-2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/dialogs/AppDownloadDialog-test.tsx b/test/unit-tests/components/views/dialogs/AppDownloadDialog-test.tsx
deleted file mode 100644
index 4ff9becc1d7..00000000000
--- a/test/unit-tests/components/views/dialogs/AppDownloadDialog-test.tsx
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2023 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
-Please see LICENSE files in the repository root for full details.
-*/
-
-import React from "react";
-import { render, screen } from "jest-matrix-react";
-
-import { AppDownloadDialog } from "../../../../../src/components/views/dialogs/AppDownloadDialog";
-import SdkConfig, { ConfigOptions } from "../../../../../src/SdkConfig";
-
-describe("AppDownloadDialog", () => {
-    afterEach(() => {
-        SdkConfig.reset();
-    });
-
-    it("should render with desktop, ios, android, fdroid buttons by default", () => {
-        const { asFragment } = render(<AppDownloadDialog onFinished={jest.fn()} />);
-        expect(screen.queryByRole("button", { name: "Download Element Desktop" })).toBeInTheDocument();
-        expect(screen.queryByRole("button", { name: "Download on the App Store" })).toBeInTheDocument();
-        expect(screen.queryByRole("button", { name: "Get it on Google Play" })).toBeInTheDocument();
-        expect(screen.queryByRole("button", { name: "Get it on F-Droid" })).toBeInTheDocument();
-        expect(asFragment()).toMatchSnapshot();
-    });
-
-    it("should allow disabling fdroid build", () => {
-        SdkConfig.add({
-            mobile_builds: {
-                fdroid: null,
-            },
-        } as ConfigOptions);
-        const { asFragment } = render(<AppDownloadDialog onFinished={jest.fn()} />);
-        expect(screen.queryByRole("button", { name: "Download Element Desktop" })).toBeInTheDocument();
-        expect(screen.queryByRole("button", { name: "Download on the App Store" })).toBeInTheDocument();
-        expect(screen.queryByRole("button", { name: "Get it on Google Play" })).toBeInTheDocument();
-        expect(screen.queryByRole("button", { name: "Get it on F-Droid" })).not.toBeInTheDocument();
-        expect(asFragment()).toMatchSnapshot();
-    });
-
-    it("should allow disabling desktop build", () => {
-        SdkConfig.add({
-            desktop_builds: {
-                available: false,
-            },
-        } as ConfigOptions);
-        const { asFragment } = render(<AppDownloadDialog onFinished={jest.fn()} />);
-        expect(screen.queryByRole("button", { name: "Download Element Desktop" })).not.toBeInTheDocument();
-        expect(screen.queryByRole("button", { name: "Download on the App Store" })).toBeInTheDocument();
-        expect(screen.queryByRole("button", { name: "Get it on Google Play" })).toBeInTheDocument();
-        expect(screen.queryByRole("button", { name: "Get it on F-Droid" })).toBeInTheDocument();
-        expect(asFragment()).toMatchSnapshot();
-    });
-
-    it("should allow disabling mobile builds", () => {
-        SdkConfig.add({
-            mobile_builds: {
-                ios: null,
-                android: null,
-                fdroid: null,
-            },
-        } as ConfigOptions);
-        const { asFragment } = render(<AppDownloadDialog onFinished={jest.fn()} />);
-        expect(screen.queryByRole("button", { name: "Download Element Desktop" })).toBeInTheDocument();
-        expect(screen.queryByRole("button", { name: "Download on the App Store" })).not.toBeInTheDocument();
-        expect(screen.queryByRole("button", { name: "Get it on Google Play" })).not.toBeInTheDocument();
-        expect(screen.queryByRole("button", { name: "Get it on F-Droid" })).not.toBeInTheDocument();
-        expect(asFragment()).toMatchSnapshot();
-    });
-});
diff --git a/test/unit-tests/components/views/dialogs/AskInviteAnywayDialog-test.tsx b/test/unit-tests/components/views/dialogs/AskInviteAnywayDialog-test.tsx
index 3c39a6d91ac..713d90a3ef6 100644
--- a/test/unit-tests/components/views/dialogs/AskInviteAnywayDialog-test.tsx
+++ b/test/unit-tests/components/views/dialogs/AskInviteAnywayDialog-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/dialogs/ChangelogDialog-test.tsx b/test/unit-tests/components/views/dialogs/ChangelogDialog-test.tsx
index 547534d207b..fd7b82c5903 100644
--- a/test/unit-tests/components/views/dialogs/ChangelogDialog-test.tsx
+++ b/test/unit-tests/components/views/dialogs/ChangelogDialog-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/dialogs/ConfirmRedactDialog-test.tsx b/test/unit-tests/components/views/dialogs/ConfirmRedactDialog-test.tsx
index ed5b545ed5d..9ba84b58e4b 100644
--- a/test/unit-tests/components/views/dialogs/ConfirmRedactDialog-test.tsx
+++ b/test/unit-tests/components/views/dialogs/ConfirmRedactDialog-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/dialogs/ConfirmUserActionDialog-test.tsx b/test/unit-tests/components/views/dialogs/ConfirmUserActionDialog-test.tsx
index e1e3c7a2f7b..cea45930802 100644
--- a/test/unit-tests/components/views/dialogs/ConfirmUserActionDialog-test.tsx
+++ b/test/unit-tests/components/views/dialogs/ConfirmUserActionDialog-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/dialogs/CreateRoomDialog-test.tsx b/test/unit-tests/components/views/dialogs/CreateRoomDialog-test.tsx
index 6add6cfc740..ad3dcd58e9a 100644
--- a/test/unit-tests/components/views/dialogs/CreateRoomDialog-test.tsx
+++ b/test/unit-tests/components/views/dialogs/CreateRoomDialog-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/dialogs/DevtoolsDialog-test.tsx b/test/unit-tests/components/views/dialogs/DevtoolsDialog-test.tsx
index e203fdad54a..89dde08393e 100644
--- a/test/unit-tests/components/views/dialogs/DevtoolsDialog-test.tsx
+++ b/test/unit-tests/components/views/dialogs/DevtoolsDialog-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/dialogs/ExportDialog-test.tsx b/test/unit-tests/components/views/dialogs/ExportDialog-test.tsx
index 9d516759de9..8417ffedb61 100644
--- a/test/unit-tests/components/views/dialogs/ExportDialog-test.tsx
+++ b/test/unit-tests/components/views/dialogs/ExportDialog-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/dialogs/FeedbackDialog-test.tsx b/test/unit-tests/components/views/dialogs/FeedbackDialog-test.tsx
index d7ee119010c..8d54a860315 100644
--- a/test/unit-tests/components/views/dialogs/FeedbackDialog-test.tsx
+++ b/test/unit-tests/components/views/dialogs/FeedbackDialog-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/dialogs/ForwardDialog-test.tsx b/test/unit-tests/components/views/dialogs/ForwardDialog-test.tsx
index 7307417b074..9aa842ee2c3 100644
--- a/test/unit-tests/components/views/dialogs/ForwardDialog-test.tsx
+++ b/test/unit-tests/components/views/dialogs/ForwardDialog-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 Robin Townsend <robin@robin.town>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/dialogs/IncomingSasDialog-test.tsx b/test/unit-tests/components/views/dialogs/IncomingSasDialog-test.tsx
index d3e7c56d0de..644b4e0f8b5 100644
--- a/test/unit-tests/components/views/dialogs/IncomingSasDialog-test.tsx
+++ b/test/unit-tests/components/views/dialogs/IncomingSasDialog-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/dialogs/InteractiveAuthDialog-test.tsx b/test/unit-tests/components/views/dialogs/InteractiveAuthDialog-test.tsx
index f99b5bd5b58..7354cde5294 100644
--- a/test/unit-tests/components/views/dialogs/InteractiveAuthDialog-test.tsx
+++ b/test/unit-tests/components/views/dialogs/InteractiveAuthDialog-test.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 Copyright 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/dialogs/InviteDialog-test.tsx b/test/unit-tests/components/views/dialogs/InviteDialog-test.tsx
index 7ed57a7d70a..0a319cc8455 100644
--- a/test/unit-tests/components/views/dialogs/InviteDialog-test.tsx
+++ b/test/unit-tests/components/views/dialogs/InviteDialog-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/dialogs/LogoutDialog-test.tsx b/test/unit-tests/components/views/dialogs/LogoutDialog-test.tsx
index 98f758ebbd6..6c1315d5ac5 100644
--- a/test/unit-tests/components/views/dialogs/LogoutDialog-test.tsx
+++ b/test/unit-tests/components/views/dialogs/LogoutDialog-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/dialogs/ManageRestrictedJoinRuleDialog-test.tsx b/test/unit-tests/components/views/dialogs/ManageRestrictedJoinRuleDialog-test.tsx
index 73bbe0bd7b6..7321f36b7a4 100644
--- a/test/unit-tests/components/views/dialogs/ManageRestrictedJoinRuleDialog-test.tsx
+++ b/test/unit-tests/components/views/dialogs/ManageRestrictedJoinRuleDialog-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/dialogs/MessageEditHistoryDialog-test.tsx b/test/unit-tests/components/views/dialogs/MessageEditHistoryDialog-test.tsx
index 0b63929c13f..1969867bcd9 100644
--- a/test/unit-tests/components/views/dialogs/MessageEditHistoryDialog-test.tsx
+++ b/test/unit-tests/components/views/dialogs/MessageEditHistoryDialog-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/dialogs/RoomSettingsDialog-test.tsx b/test/unit-tests/components/views/dialogs/RoomSettingsDialog-test.tsx
index 3ca21500134..73654cfc5fd 100644
--- a/test/unit-tests/components/views/dialogs/RoomSettingsDialog-test.tsx
+++ b/test/unit-tests/components/views/dialogs/RoomSettingsDialog-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/dialogs/ServerPickerDialog-test.tsx b/test/unit-tests/components/views/dialogs/ServerPickerDialog-test.tsx
index c893dba45ed..b4a4b6e756b 100644
--- a/test/unit-tests/components/views/dialogs/ServerPickerDialog-test.tsx
+++ b/test/unit-tests/components/views/dialogs/ServerPickerDialog-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/dialogs/ShareDialog-test.tsx b/test/unit-tests/components/views/dialogs/ShareDialog-test.tsx
index c1d9883b7f6..93beaec711d 100644
--- a/test/unit-tests/components/views/dialogs/ShareDialog-test.tsx
+++ b/test/unit-tests/components/views/dialogs/ShareDialog-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/dialogs/SpotlightDialog-test.tsx b/test/unit-tests/components/views/dialogs/SpotlightDialog-test.tsx
index 54d21e147b5..776aaff17db 100644
--- a/test/unit-tests/components/views/dialogs/SpotlightDialog-test.tsx
+++ b/test/unit-tests/components/views/dialogs/SpotlightDialog-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022, 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/dialogs/UnpinAllDialog-test.tsx b/test/unit-tests/components/views/dialogs/UnpinAllDialog-test.tsx
index 742bffcb089..9c736446fae 100644
--- a/test/unit-tests/components/views/dialogs/UnpinAllDialog-test.tsx
+++ b/test/unit-tests/components/views/dialogs/UnpinAllDialog-test.tsx
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2024 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/test/unit-tests/components/views/dialogs/UntrustedDeviceDialog-test.tsx b/test/unit-tests/components/views/dialogs/UntrustedDeviceDialog-test.tsx
index 3bfafa394bf..f0a3fdfb8be 100644
--- a/test/unit-tests/components/views/dialogs/UntrustedDeviceDialog-test.tsx
+++ b/test/unit-tests/components/views/dialogs/UntrustedDeviceDialog-test.tsx
@@ -1,7 +1,7 @@
 /*
  * Copyright 2024 New Vector Ltd.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/test/unit-tests/components/views/dialogs/UserSettingsDialog-test.tsx b/test/unit-tests/components/views/dialogs/UserSettingsDialog-test.tsx
index 2b71256f0d2..c6c3eeb1427 100644
--- a/test/unit-tests/components/views/dialogs/UserSettingsDialog-test.tsx
+++ b/test/unit-tests/components/views/dialogs/UserSettingsDialog-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -27,6 +27,7 @@ import {
 import { UIFeature } from "../../../../../src/settings/UIFeature";
 import { SettingLevel } from "../../../../../src/settings/SettingLevel";
 import { SdkContextClass } from "../../../../../src/contexts/SDKContext";
+import { FeatureSettingKey } from "../../../../../src/settings/Settings.tsx";
 
 mockPlatformPeg({
     supportsSpellCheckSettings: jest.fn().mockReturnValue(false),
@@ -111,13 +112,13 @@ describe("<UserSettingsDialog />", () => {
     });
 
     it("renders ignored users tab when feature_mjolnir is enabled", () => {
-        mockSettingsStore.getValue.mockImplementation((settingName): any => settingName === "feature_mjolnir");
+        mockSettingsStore.getValue.mockImplementation((settingName) => settingName === "feature_mjolnir");
         const { getByTestId } = render(getComponent());
         expect(getByTestId(`settings-tab-${UserTab.Mjolnir}`)).toBeTruthy();
     });
 
     it("renders voip tab when voip is enabled", () => {
-        mockSettingsStore.getValue.mockImplementation((settingName): any => settingName === UIFeature.Voip);
+        mockSettingsStore.getValue.mockImplementation((settingName: any): any => settingName === UIFeature.Voip);
         const { getByTestId } = render(getComponent());
         expect(getByTestId(`settings-tab-${UserTab.Voice}`)).toBeTruthy();
     });
@@ -165,7 +166,7 @@ describe("<UserSettingsDialog />", () => {
 
     it("renders with voip tab selected", () => {
         useMockMediaDevices();
-        mockSettingsStore.getValue.mockImplementation((settingName): any => settingName === UIFeature.Voip);
+        mockSettingsStore.getValue.mockImplementation((settingName: any): any => settingName === UIFeature.Voip);
         const { container } = render(getComponent({ initialTabId: UserTab.Voice }));
 
         expect(getActiveTabLabel(container)).toEqual("Voice & Video");
@@ -212,8 +213,11 @@ describe("<UserSettingsDialog />", () => {
     });
 
     it("renders labs tab when some feature is in beta", () => {
-        mockSettingsStore.getFeatureSettingNames.mockReturnValue(["feature_beta_setting", "feature_just_normal_labs"]);
-        mockSettingsStore.getBetaInfo.mockImplementation((settingName) =>
+        mockSettingsStore.getFeatureSettingNames.mockReturnValue([
+            "feature_beta_setting",
+            "feature_just_normal_labs",
+        ] as unknown[] as FeatureSettingKey[]);
+        mockSettingsStore.getBetaInfo.mockImplementation((settingName: any) =>
             settingName === "feature_beta_setting" ? ({} as any) : undefined,
         );
         const { getByTestId } = render(getComponent());
diff --git a/test/unit-tests/components/views/dialogs/__snapshots__/AppDownloadDialog-test.tsx.snap b/test/unit-tests/components/views/dialogs/__snapshots__/AppDownloadDialog-test.tsx.snap
deleted file mode 100644
index 6d4e827c474..00000000000
--- a/test/unit-tests/components/views/dialogs/__snapshots__/AppDownloadDialog-test.tsx.snap
+++ /dev/null
@@ -1,540 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`AppDownloadDialog should allow disabling desktop build 1`] = `
-<DocumentFragment>
-  <div
-    data-focus-guard="true"
-    style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"
-    tabindex="0"
-  />
-  <div
-    aria-labelledby="mx_BaseDialog_title"
-    class="mx_AppDownloadDialog mx_Dialog_fixedWidth"
-    data-focus-lock-disabled="false"
-    role="dialog"
-  >
-    <div
-      class="mx_Dialog_header"
-    >
-      <h1
-        class="mx_Heading_h3 mx_Dialog_title"
-        id="mx_BaseDialog_title"
-      >
-        Download Element
-      </h1>
-    </div>
-    <div
-      class="mx_AppDownloadDialog_mobile"
-    >
-      <div
-        class="mx_AppDownloadDialog_app"
-      >
-        <h3
-          class="mx_Heading_h3"
-        >
-          iOS
-        </h3>
-        <div
-          class="mx_QRCode"
-        >
-          <div
-            class="mx_Spinner"
-          >
-            <div
-              aria-label="Loading…"
-              class="mx_Spinner_icon"
-              data-testid="spinner"
-              role="progressbar"
-              style="width: 32px; height: 32px;"
-            />
-          </div>
-        </div>
-        <div
-          class="mx_AppDownloadDialog_info"
-        >
-           or 
-        </div>
-        <div
-          class="mx_AppDownloadDialog_links"
-        >
-          <a
-            aria-label="Download on the App Store"
-            class="mx_AccessibleButton"
-            href="https://apps.apple.com/app/vector/id1083446067"
-            role="button"
-            tabindex="0"
-            target="_blank"
-          >
-            <div />
-          </a>
-        </div>
-      </div>
-      <div
-        class="mx_AppDownloadDialog_app"
-      >
-        <h3
-          class="mx_Heading_h3"
-        >
-          Android
-        </h3>
-        <div
-          class="mx_QRCode"
-        >
-          <div
-            class="mx_Spinner"
-          >
-            <div
-              aria-label="Loading…"
-              class="mx_Spinner_icon"
-              data-testid="spinner"
-              role="progressbar"
-              style="width: 32px; height: 32px;"
-            />
-          </div>
-        </div>
-        <div
-          class="mx_AppDownloadDialog_info"
-        >
-           or 
-        </div>
-        <div
-          class="mx_AppDownloadDialog_links"
-        >
-          <a
-            aria-label="Get it on Google Play"
-            class="mx_AccessibleButton"
-            href="https://play.google.com/store/apps/details?id=im.vector.app"
-            role="button"
-            tabindex="0"
-            target="_blank"
-          >
-            <div />
-          </a>
-          <a
-            aria-label="Get it on F-Droid"
-            class="mx_AccessibleButton"
-            href="https://f-droid.org/repository/browse/?fdid=im.vector.app"
-            role="button"
-            tabindex="0"
-            target="_blank"
-          >
-            <div />
-          </a>
-        </div>
-      </div>
-    </div>
-    <div
-      class="mx_AppDownloadDialog_legal"
-    >
-      <p>
-        App Store® and the Apple logo® are trademarks of Apple Inc.
-      </p>
-      <p>
-        Google Play and the Google Play logo are trademarks of Google LLC.
-      </p>
-    </div>
-    <div
-      aria-label="Close dialog"
-      class="mx_AccessibleButton mx_Dialog_cancelButton"
-      role="button"
-      tabindex="0"
-    />
-  </div>
-  <div
-    data-focus-guard="true"
-    style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"
-    tabindex="0"
-  />
-</DocumentFragment>
-`;
-
-exports[`AppDownloadDialog should allow disabling fdroid build 1`] = `
-<DocumentFragment>
-  <div
-    data-focus-guard="true"
-    style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"
-    tabindex="0"
-  />
-  <div
-    aria-labelledby="mx_BaseDialog_title"
-    class="mx_AppDownloadDialog mx_Dialog_fixedWidth"
-    data-focus-lock-disabled="false"
-    role="dialog"
-  >
-    <div
-      class="mx_Dialog_header"
-    >
-      <h1
-        class="mx_Heading_h3 mx_Dialog_title"
-        id="mx_BaseDialog_title"
-      >
-        Download Element
-      </h1>
-    </div>
-    <div
-      class="mx_AppDownloadDialog_desktop"
-    >
-      <h3
-        class="mx_Heading_h3"
-      >
-        Download Element Desktop
-      </h3>
-      <a
-        class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary"
-        href="https://element.io/download"
-        role="button"
-        tabindex="0"
-        target="_blank"
-      >
-        Download Element Desktop
-      </a>
-    </div>
-    <div
-      class="mx_AppDownloadDialog_mobile"
-    >
-      <div
-        class="mx_AppDownloadDialog_app"
-      >
-        <h3
-          class="mx_Heading_h3"
-        >
-          iOS
-        </h3>
-        <div
-          class="mx_QRCode"
-        >
-          <div
-            class="mx_Spinner"
-          >
-            <div
-              aria-label="Loading…"
-              class="mx_Spinner_icon"
-              data-testid="spinner"
-              role="progressbar"
-              style="width: 32px; height: 32px;"
-            />
-          </div>
-        </div>
-        <div
-          class="mx_AppDownloadDialog_info"
-        >
-           or 
-        </div>
-        <div
-          class="mx_AppDownloadDialog_links"
-        >
-          <a
-            aria-label="Download on the App Store"
-            class="mx_AccessibleButton"
-            href="https://apps.apple.com/app/vector/id1083446067"
-            role="button"
-            tabindex="0"
-            target="_blank"
-          >
-            <div />
-          </a>
-        </div>
-      </div>
-      <div
-        class="mx_AppDownloadDialog_app"
-      >
-        <h3
-          class="mx_Heading_h3"
-        >
-          Android
-        </h3>
-        <div
-          class="mx_QRCode"
-        >
-          <div
-            class="mx_Spinner"
-          >
-            <div
-              aria-label="Loading…"
-              class="mx_Spinner_icon"
-              data-testid="spinner"
-              role="progressbar"
-              style="width: 32px; height: 32px;"
-            />
-          </div>
-        </div>
-        <div
-          class="mx_AppDownloadDialog_info"
-        >
-           or 
-        </div>
-        <div
-          class="mx_AppDownloadDialog_links"
-        >
-          <a
-            aria-label="Get it on Google Play"
-            class="mx_AccessibleButton"
-            href="https://play.google.com/store/apps/details?id=im.vector.app"
-            role="button"
-            tabindex="0"
-            target="_blank"
-          >
-            <div />
-          </a>
-        </div>
-      </div>
-    </div>
-    <div
-      class="mx_AppDownloadDialog_legal"
-    >
-      <p>
-        App Store® and the Apple logo® are trademarks of Apple Inc.
-      </p>
-      <p>
-        Google Play and the Google Play logo are trademarks of Google LLC.
-      </p>
-    </div>
-    <div
-      aria-label="Close dialog"
-      class="mx_AccessibleButton mx_Dialog_cancelButton"
-      role="button"
-      tabindex="0"
-    />
-  </div>
-  <div
-    data-focus-guard="true"
-    style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"
-    tabindex="0"
-  />
-</DocumentFragment>
-`;
-
-exports[`AppDownloadDialog should allow disabling mobile builds 1`] = `
-<DocumentFragment>
-  <div
-    data-focus-guard="true"
-    style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"
-    tabindex="0"
-  />
-  <div
-    aria-labelledby="mx_BaseDialog_title"
-    class="mx_AppDownloadDialog mx_Dialog_fixedWidth"
-    data-focus-lock-disabled="false"
-    role="dialog"
-  >
-    <div
-      class="mx_Dialog_header"
-    >
-      <h1
-        class="mx_Heading_h3 mx_Dialog_title"
-        id="mx_BaseDialog_title"
-      >
-        Download Element
-      </h1>
-    </div>
-    <div
-      class="mx_AppDownloadDialog_desktop"
-    >
-      <h3
-        class="mx_Heading_h3"
-      >
-        Download Element Desktop
-      </h3>
-      <a
-        class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary"
-        href="https://element.io/download"
-        role="button"
-        tabindex="0"
-        target="_blank"
-      >
-        Download Element Desktop
-      </a>
-    </div>
-    <div
-      class="mx_AppDownloadDialog_mobile"
-    />
-    <div
-      class="mx_AppDownloadDialog_legal"
-    >
-      <p>
-        App Store® and the Apple logo® are trademarks of Apple Inc.
-      </p>
-      <p>
-        Google Play and the Google Play logo are trademarks of Google LLC.
-      </p>
-    </div>
-    <div
-      aria-label="Close dialog"
-      class="mx_AccessibleButton mx_Dialog_cancelButton"
-      role="button"
-      tabindex="0"
-    />
-  </div>
-  <div
-    data-focus-guard="true"
-    style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"
-    tabindex="0"
-  />
-</DocumentFragment>
-`;
-
-exports[`AppDownloadDialog should render with desktop, ios, android, fdroid buttons by default 1`] = `
-<DocumentFragment>
-  <div
-    data-focus-guard="true"
-    style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"
-    tabindex="0"
-  />
-  <div
-    aria-labelledby="mx_BaseDialog_title"
-    class="mx_AppDownloadDialog mx_Dialog_fixedWidth"
-    data-focus-lock-disabled="false"
-    role="dialog"
-  >
-    <div
-      class="mx_Dialog_header"
-    >
-      <h1
-        class="mx_Heading_h3 mx_Dialog_title"
-        id="mx_BaseDialog_title"
-      >
-        Download Element
-      </h1>
-    </div>
-    <div
-      class="mx_AppDownloadDialog_desktop"
-    >
-      <h3
-        class="mx_Heading_h3"
-      >
-        Download Element Desktop
-      </h3>
-      <a
-        class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary"
-        href="https://element.io/download"
-        role="button"
-        tabindex="0"
-        target="_blank"
-      >
-        Download Element Desktop
-      </a>
-    </div>
-    <div
-      class="mx_AppDownloadDialog_mobile"
-    >
-      <div
-        class="mx_AppDownloadDialog_app"
-      >
-        <h3
-          class="mx_Heading_h3"
-        >
-          iOS
-        </h3>
-        <div
-          class="mx_QRCode"
-        >
-          <div
-            class="mx_Spinner"
-          >
-            <div
-              aria-label="Loading…"
-              class="mx_Spinner_icon"
-              data-testid="spinner"
-              role="progressbar"
-              style="width: 32px; height: 32px;"
-            />
-          </div>
-        </div>
-        <div
-          class="mx_AppDownloadDialog_info"
-        >
-           or 
-        </div>
-        <div
-          class="mx_AppDownloadDialog_links"
-        >
-          <a
-            aria-label="Download on the App Store"
-            class="mx_AccessibleButton"
-            href="https://apps.apple.com/app/vector/id1083446067"
-            role="button"
-            tabindex="0"
-            target="_blank"
-          >
-            <div />
-          </a>
-        </div>
-      </div>
-      <div
-        class="mx_AppDownloadDialog_app"
-      >
-        <h3
-          class="mx_Heading_h3"
-        >
-          Android
-        </h3>
-        <div
-          class="mx_QRCode"
-        >
-          <div
-            class="mx_Spinner"
-          >
-            <div
-              aria-label="Loading…"
-              class="mx_Spinner_icon"
-              data-testid="spinner"
-              role="progressbar"
-              style="width: 32px; height: 32px;"
-            />
-          </div>
-        </div>
-        <div
-          class="mx_AppDownloadDialog_info"
-        >
-           or 
-        </div>
-        <div
-          class="mx_AppDownloadDialog_links"
-        >
-          <a
-            aria-label="Get it on Google Play"
-            class="mx_AccessibleButton"
-            href="https://play.google.com/store/apps/details?id=im.vector.app"
-            role="button"
-            tabindex="0"
-            target="_blank"
-          >
-            <div />
-          </a>
-          <a
-            aria-label="Get it on F-Droid"
-            class="mx_AccessibleButton"
-            href="https://f-droid.org/repository/browse/?fdid=im.vector.app"
-            role="button"
-            tabindex="0"
-            target="_blank"
-          >
-            <div />
-          </a>
-        </div>
-      </div>
-    </div>
-    <div
-      class="mx_AppDownloadDialog_legal"
-    >
-      <p>
-        App Store® and the Apple logo® are trademarks of Apple Inc.
-      </p>
-      <p>
-        Google Play and the Google Play logo are trademarks of Google LLC.
-      </p>
-    </div>
-    <div
-      aria-label="Close dialog"
-      class="mx_AccessibleButton mx_Dialog_cancelButton"
-      role="button"
-      tabindex="0"
-    />
-  </div>
-  <div
-    data-focus-guard="true"
-    style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"
-    tabindex="0"
-  />
-</DocumentFragment>
-`;
diff --git a/test/unit-tests/components/views/dialogs/__snapshots__/UserSettingsDialog-test.tsx.snap b/test/unit-tests/components/views/dialogs/__snapshots__/UserSettingsDialog-test.tsx.snap
index 871d9376810..de47330ddfc 100644
--- a/test/unit-tests/components/views/dialogs/__snapshots__/UserSettingsDialog-test.tsx.snap
+++ b/test/unit-tests/components/views/dialogs/__snapshots__/UserSettingsDialog-test.tsx.snap
@@ -225,6 +225,32 @@ NodeList [
       Security & Privacy
     </span>
   </li>,
+  <li
+    aria-controls="mx_tabpanel_USER_ENCRYPTION_TAB"
+    aria-selected="false"
+    class="mx_AccessibleButton mx_TabbedView_tabLabel"
+    data-testid="settings-tab-USER_ENCRYPTION_TAB"
+    role="tab"
+    tabindex="-1"
+  >
+    <svg
+      fill="currentColor"
+      height="1em"
+      viewBox="0 0 24 24"
+      width="1em"
+      xmlns="http://www.w3.org/2000/svg"
+    >
+      <path
+        d="M7 14c-.55 0-1.02-.196-1.412-.588A1.926 1.926 0 0 1 5 12c0-.55.196-1.02.588-1.412A1.926 1.926 0 0 1 7 10c.55 0 1.02.196 1.412.588.392.391.588.862.588 1.412 0 .55-.196 1.02-.588 1.412A1.926 1.926 0 0 1 7 14Zm0 4c-1.667 0-3.083-.583-4.25-1.75C1.583 15.083 1 13.667 1 12c0-1.667.583-3.083 1.75-4.25C3.917 6.583 5.333 6 7 6c1.117 0 2.13.275 3.037.825A6.212 6.212 0 0 1 12.2 9h8.375a1.033 1.033 0 0 1 .725.3l2 2c.1.1.17.208.212.325.042.117.063.242.063.375s-.02.258-.063.375a.877.877 0 0 1-.212.325l-3.175 3.175a.946.946 0 0 1-.3.2c-.117.05-.233.083-.35.1a.832.832 0 0 1-.35-.025.884.884 0 0 1-.325-.175L17.5 15l-1.425 1.075a.945.945 0 0 1-.887.15.859.859 0 0 1-.288-.15L13.375 15H12.2a6.212 6.212 0 0 1-2.162 2.175C9.128 17.725 8.117 18 7 18Zm0-2c.933 0 1.754-.283 2.463-.85A4.032 4.032 0 0 0 10.875 13H14l1.45 1.025L17.5 12.5l1.775 1.375L21.15 12l-1-1h-9.275a4.032 4.032 0 0 0-1.412-2.15C8.754 8.283 7.933 8 7 8c-1.1 0-2.042.392-2.825 1.175C3.392 9.958 3 10.9 3 12s.392 2.042 1.175 2.825C4.958 15.608 5.9 16 7 16Z"
+      />
+    </svg>
+    <span
+      class="mx_TabbedView_tabLabel_text"
+      id="mx_tabpanel_USER_ENCRYPTION_TAB_label"
+    >
+      Encryption
+    </span>
+  </li>,
   <li
     aria-controls="mx_tabpanel_USER_LABS_TAB"
     aria-selected="false"
diff --git a/test/unit-tests/components/views/dialogs/devtools/Event-test.tsx b/test/unit-tests/components/views/dialogs/devtools/Event-test.tsx
index 60bf7919129..330d52b0b1c 100644
--- a/test/unit-tests/components/views/dialogs/devtools/Event-test.tsx
+++ b/test/unit-tests/components/views/dialogs/devtools/Event-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/dialogs/devtools/RoomNotifications-test.tsx b/test/unit-tests/components/views/dialogs/devtools/RoomNotifications-test.tsx
index 9b600acc3b5..eeaa7dbb1f2 100644
--- a/test/unit-tests/components/views/dialogs/devtools/RoomNotifications-test.tsx
+++ b/test/unit-tests/components/views/dialogs/devtools/RoomNotifications-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/dialogs/security/CreateKeyBackupDialog-test.tsx b/test/unit-tests/components/views/dialogs/security/CreateKeyBackupDialog-test.tsx
index 6e0542448b1..b5f965cfa2f 100644
--- a/test/unit-tests/components/views/dialogs/security/CreateKeyBackupDialog-test.tsx
+++ b/test/unit-tests/components/views/dialogs/security/CreateKeyBackupDialog-test.tsx
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2023 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/test/unit-tests/components/views/dialogs/security/CreateSecretStorageDialog-test.tsx b/test/unit-tests/components/views/dialogs/security/CreateSecretStorageDialog-test.tsx
index 814fe8a9543..1da0bc7be8c 100644
--- a/test/unit-tests/components/views/dialogs/security/CreateSecretStorageDialog-test.tsx
+++ b/test/unit-tests/components/views/dialogs/security/CreateSecretStorageDialog-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/dialogs/security/ExportE2eKeysDialog-test.tsx b/test/unit-tests/components/views/dialogs/security/ExportE2eKeysDialog-test.tsx
index df95482850d..e4dc75062c0 100644
--- a/test/unit-tests/components/views/dialogs/security/ExportE2eKeysDialog-test.tsx
+++ b/test/unit-tests/components/views/dialogs/security/ExportE2eKeysDialog-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/dialogs/security/ImportE2eKeysDialog-test.tsx b/test/unit-tests/components/views/dialogs/security/ImportE2eKeysDialog-test.tsx
index 57f374c2523..f9dcc177373 100644
--- a/test/unit-tests/components/views/dialogs/security/ImportE2eKeysDialog-test.tsx
+++ b/test/unit-tests/components/views/dialogs/security/ImportE2eKeysDialog-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/dialogs/security/RestoreKeyBackupDialog-test.tsx b/test/unit-tests/components/views/dialogs/security/RestoreKeyBackupDialog-test.tsx
index c19010a0893..4fc42f58932 100644
--- a/test/unit-tests/components/views/dialogs/security/RestoreKeyBackupDialog-test.tsx
+++ b/test/unit-tests/components/views/dialogs/security/RestoreKeyBackupDialog-test.tsx
@@ -1,9 +1,8 @@
 /*
  * Copyright 2024 New Vector Ltd.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
- *
  */
 
 import React from "react";
diff --git a/test/unit-tests/components/views/dialogs/security/__snapshots__/CreateSecretStorageDialog-test.tsx.snap b/test/unit-tests/components/views/dialogs/security/__snapshots__/CreateSecretStorageDialog-test.tsx.snap
index 5ad35904225..a39ce29439d 100644
--- a/test/unit-tests/components/views/dialogs/security/__snapshots__/CreateSecretStorageDialog-test.tsx.snap
+++ b/test/unit-tests/components/views/dialogs/security/__snapshots__/CreateSecretStorageDialog-test.tsx.snap
@@ -165,7 +165,9 @@ exports[`CreateSecretStorageDialog handles the happy path 2`] = `
             <div
               class="mx_CreateSecretStorageDialog_recoveryKey"
             >
-              <code />
+              <code>
+                encoded private key
+              </code>
             </div>
             <div
               class="mx_CreateSecretStorageDialog_recoveryKeyButtons"
diff --git a/test/unit-tests/components/views/dialogs/spotlight/PublicRoomResultDetails-test.tsx b/test/unit-tests/components/views/dialogs/spotlight/PublicRoomResultDetails-test.tsx
index db653636072..c5cda731bee 100644
--- a/test/unit-tests/components/views/dialogs/spotlight/PublicRoomResultDetails-test.tsx
+++ b/test/unit-tests/components/views/dialogs/spotlight/PublicRoomResultDetails-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/dialogs/spotlight/RoomResultContextMenus-test.tsx b/test/unit-tests/components/views/dialogs/spotlight/RoomResultContextMenus-test.tsx
index d7cc2964f99..209ad32727f 100644
--- a/test/unit-tests/components/views/dialogs/spotlight/RoomResultContextMenus-test.tsx
+++ b/test/unit-tests/components/views/dialogs/spotlight/RoomResultContextMenus-test.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2023 Mikhail Aheichyk
 Copyright 2023 Nordeck IT + Consulting GmbH.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/elements/AccessibleButton-test.tsx b/test/unit-tests/components/views/elements/AccessibleButton-test.tsx
index 8d501b6ab49..0d30c5734fd 100644
--- a/test/unit-tests/components/views/elements/AccessibleButton-test.tsx
+++ b/test/unit-tests/components/views/elements/AccessibleButton-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/elements/AppTile-test.tsx b/test/unit-tests/components/views/elements/AppTile-test.tsx
index 12363f56f04..7a2acb3ace4 100644
--- a/test/unit-tests/components/views/elements/AppTile-test.tsx
+++ b/test/unit-tests/components/views/elements/AppTile-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/elements/DesktopCapturerSourcePicker-test.tsx b/test/unit-tests/components/views/elements/DesktopCapturerSourcePicker-test.tsx
index f647dfdaee6..7fc739fafb5 100644
--- a/test/unit-tests/components/views/elements/DesktopCapturerSourcePicker-test.tsx
+++ b/test/unit-tests/components/views/elements/DesktopCapturerSourcePicker-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/elements/EffectsOverlay-test.tsx b/test/unit-tests/components/views/elements/EffectsOverlay-test.tsx
index d17139511c5..e2ccbc87246 100644
--- a/test/unit-tests/components/views/elements/EffectsOverlay-test.tsx
+++ b/test/unit-tests/components/views/elements/EffectsOverlay-test.tsx
@@ -1,9 +1,8 @@
 /*
  * Copyright 2024 New Vector Ltd.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
- *
  */
 
 import React from "react";
diff --git a/test/unit-tests/components/views/elements/EventListSummary-test.tsx b/test/unit-tests/components/views/elements/EventListSummary-test.tsx
index 485a69289f2..f1140352b85 100644
--- a/test/unit-tests/components/views/elements/EventListSummary-test.tsx
+++ b/test/unit-tests/components/views/elements/EventListSummary-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/elements/ExternalLink-test.tsx b/test/unit-tests/components/views/elements/ExternalLink-test.tsx
index bdc1a9e7b3d..012dae5477a 100644
--- a/test/unit-tests/components/views/elements/ExternalLink-test.tsx
+++ b/test/unit-tests/components/views/elements/ExternalLink-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/elements/FacePile-test.tsx b/test/unit-tests/components/views/elements/FacePile-test.tsx
index b9ff911df11..9ec71f45d8c 100644
--- a/test/unit-tests/components/views/elements/FacePile-test.tsx
+++ b/test/unit-tests/components/views/elements/FacePile-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/elements/Field-test.tsx b/test/unit-tests/components/views/elements/Field-test.tsx
index 95445595871..8db645bf852 100644
--- a/test/unit-tests/components/views/elements/Field-test.tsx
+++ b/test/unit-tests/components/views/elements/Field-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/elements/FilterDropdown-test.tsx b/test/unit-tests/components/views/elements/FilterDropdown-test.tsx
index a1c30688a59..112d0ed650c 100644
--- a/test/unit-tests/components/views/elements/FilterDropdown-test.tsx
+++ b/test/unit-tests/components/views/elements/FilterDropdown-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/elements/FilterTabGroup-test.tsx b/test/unit-tests/components/views/elements/FilterTabGroup-test.tsx
index 5067b9b95db..49091d80175 100644
--- a/test/unit-tests/components/views/elements/FilterTabGroup-test.tsx
+++ b/test/unit-tests/components/views/elements/FilterTabGroup-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/elements/ImageView-test.tsx b/test/unit-tests/components/views/elements/ImageView-test.tsx
index 4a23d847cbf..e9ba7cdd69c 100644
--- a/test/unit-tests/components/views/elements/ImageView-test.tsx
+++ b/test/unit-tests/components/views/elements/ImageView-test.tsx
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2024 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/test/unit-tests/components/views/elements/InfoTooltip-test.tsx b/test/unit-tests/components/views/elements/InfoTooltip-test.tsx
index f4d80e179ee..53b4c696c5b 100644
--- a/test/unit-tests/components/views/elements/InfoTooltip-test.tsx
+++ b/test/unit-tests/components/views/elements/InfoTooltip-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/elements/LabelledCheckbox-test.tsx b/test/unit-tests/components/views/elements/LabelledCheckbox-test.tsx
index 2877740bf81..6fccc366423 100644
--- a/test/unit-tests/components/views/elements/LabelledCheckbox-test.tsx
+++ b/test/unit-tests/components/views/elements/LabelledCheckbox-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/elements/LearnMore-test.tsx b/test/unit-tests/components/views/elements/LearnMore-test.tsx
index 00393759d7a..959affc4492 100644
--- a/test/unit-tests/components/views/elements/LearnMore-test.tsx
+++ b/test/unit-tests/components/views/elements/LearnMore-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/elements/MiniAvatarUploader-test.tsx b/test/unit-tests/components/views/elements/MiniAvatarUploader-test.tsx
index cf6ed6ae624..5b451c44b4e 100644
--- a/test/unit-tests/components/views/elements/MiniAvatarUploader-test.tsx
+++ b/test/unit-tests/components/views/elements/MiniAvatarUploader-test.tsx
@@ -1,7 +1,7 @@
 /*
 Copyright 2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/elements/Pill-test.tsx b/test/unit-tests/components/views/elements/Pill-test.tsx
index db075b3b6f5..b2ea507790e 100644
--- a/test/unit-tests/components/views/elements/Pill-test.tsx
+++ b/test/unit-tests/components/views/elements/Pill-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/elements/PollCreateDialog-test.tsx b/test/unit-tests/components/views/elements/PollCreateDialog-test.tsx
index 0ee90969165..cf50181bb8c 100644
--- a/test/unit-tests/components/views/elements/PollCreateDialog-test.tsx
+++ b/test/unit-tests/components/views/elements/PollCreateDialog-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/elements/PowerSelector-test.tsx b/test/unit-tests/components/views/elements/PowerSelector-test.tsx
index 72fbbaf09f3..ef35cf75a01 100644
--- a/test/unit-tests/components/views/elements/PowerSelector-test.tsx
+++ b/test/unit-tests/components/views/elements/PowerSelector-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/elements/ProgressBar-test.tsx b/test/unit-tests/components/views/elements/ProgressBar-test.tsx
index 4e95987f136..aedfebef3fc 100644
--- a/test/unit-tests/components/views/elements/ProgressBar-test.tsx
+++ b/test/unit-tests/components/views/elements/ProgressBar-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/elements/QRCode-test.tsx b/test/unit-tests/components/views/elements/QRCode-test.tsx
index c53390e610c..ec688b286ba 100644
--- a/test/unit-tests/components/views/elements/QRCode-test.tsx
+++ b/test/unit-tests/components/views/elements/QRCode-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/elements/ReplyChain-test.tsx b/test/unit-tests/components/views/elements/ReplyChain-test.tsx
index 4eebcf67b90..38f5684eb70 100644
--- a/test/unit-tests/components/views/elements/ReplyChain-test.tsx
+++ b/test/unit-tests/components/views/elements/ReplyChain-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/elements/RoomFacePile-test.tsx b/test/unit-tests/components/views/elements/RoomFacePile-test.tsx
index 8e934fb7e1c..b21c3afc1bc 100644
--- a/test/unit-tests/components/views/elements/RoomFacePile-test.tsx
+++ b/test/unit-tests/components/views/elements/RoomFacePile-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/elements/RoomTopic-test.tsx b/test/unit-tests/components/views/elements/RoomTopic-test.tsx
index 0fe833fe4e1..47bc39fdd7d 100644
--- a/test/unit-tests/components/views/elements/RoomTopic-test.tsx
+++ b/test/unit-tests/components/views/elements/RoomTopic-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/elements/SearchWarning-test.tsx b/test/unit-tests/components/views/elements/SearchWarning-test.tsx
index f0b17106854..117870d7e90 100644
--- a/test/unit-tests/components/views/elements/SearchWarning-test.tsx
+++ b/test/unit-tests/components/views/elements/SearchWarning-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/elements/SpellCheckLanguagesDropdown-test.tsx b/test/unit-tests/components/views/elements/SpellCheckLanguagesDropdown-test.tsx
index e0c4af03922..66f37e2927b 100644
--- a/test/unit-tests/components/views/elements/SpellCheckLanguagesDropdown-test.tsx
+++ b/test/unit-tests/components/views/elements/SpellCheckLanguagesDropdown-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/elements/StyledRadioGroup-test.tsx b/test/unit-tests/components/views/elements/StyledRadioGroup-test.tsx
index bf6e37b5350..1f8894457cb 100644
--- a/test/unit-tests/components/views/elements/StyledRadioGroup-test.tsx
+++ b/test/unit-tests/components/views/elements/StyledRadioGroup-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/elements/SyntaxHighlight-test.tsx b/test/unit-tests/components/views/elements/SyntaxHighlight-test.tsx
index ff18022a8ce..5983e7b0f22 100644
--- a/test/unit-tests/components/views/elements/SyntaxHighlight-test.tsx
+++ b/test/unit-tests/components/views/elements/SyntaxHighlight-test.tsx
@@ -1,8 +1,7 @@
-/* eslint @typescript-eslint/no-unused-vars: ["error", { "varsIgnorePattern": "^_" }] */
 // Copyright 2024 New Vector Ltd.
 // Copyright 2023 The Matrix.org Foundation C.I.C.
 //
-// SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+// SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 // Please see LICENSE files in the repository root for full details.
 
 import { render, waitFor } from "jest-matrix-react";
@@ -24,7 +23,7 @@ describe("<SyntaxHighlight />", () => {
         const { container } = render(<SyntaxHighlight language={lang}>// Hello, World</SyntaxHighlight>);
         await waitFor(() => expect(container.querySelector(`.language-${lang}`)).toBeTruthy());
 
-        const [_lang, opts] = mock.mock.lastCall!;
+        const [, opts] = mock.mock.lastCall!;
         expect((opts as unknown as HighlightOptions)["language"]).toBe(lang);
     });
 });
diff --git a/test/unit-tests/components/views/elements/crypto/VerificationQRCode-test.tsx b/test/unit-tests/components/views/elements/crypto/VerificationQRCode-test.tsx
index a0db4bfdadc..8e7acf742ec 100644
--- a/test/unit-tests/components/views/elements/crypto/VerificationQRCode-test.tsx
+++ b/test/unit-tests/components/views/elements/crypto/VerificationQRCode-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/emojipicker/EmojiPicker-test.tsx b/test/unit-tests/components/views/emojipicker/EmojiPicker-test.tsx
index e67334ca61d..a7dcadc9f7f 100644
--- a/test/unit-tests/components/views/emojipicker/EmojiPicker-test.tsx
+++ b/test/unit-tests/components/views/emojipicker/EmojiPicker-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/location/LiveDurationDropdown-test.tsx b/test/unit-tests/components/views/location/LiveDurationDropdown-test.tsx
index 4f08f635417..a0f9aa984fb 100644
--- a/test/unit-tests/components/views/location/LiveDurationDropdown-test.tsx
+++ b/test/unit-tests/components/views/location/LiveDurationDropdown-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/location/LocationPicker-test.tsx b/test/unit-tests/components/views/location/LocationPicker-test.tsx
index 16a40532b04..93acbdf18a9 100644
--- a/test/unit-tests/components/views/location/LocationPicker-test.tsx
+++ b/test/unit-tests/components/views/location/LocationPicker-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/location/LocationShareMenu-test.tsx b/test/unit-tests/components/views/location/LocationShareMenu-test.tsx
index 84c5e91ea00..7f95b5564d2 100644
--- a/test/unit-tests/components/views/location/LocationShareMenu-test.tsx
+++ b/test/unit-tests/components/views/location/LocationShareMenu-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/location/LocationViewDialog-test.tsx b/test/unit-tests/components/views/location/LocationViewDialog-test.tsx
index eb4eb6aa3cb..1993215cf80 100644
--- a/test/unit-tests/components/views/location/LocationViewDialog-test.tsx
+++ b/test/unit-tests/components/views/location/LocationViewDialog-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/location/Map-test.tsx b/test/unit-tests/components/views/location/Map-test.tsx
index 7771c6190ae..eb45a536eb6 100644
--- a/test/unit-tests/components/views/location/Map-test.tsx
+++ b/test/unit-tests/components/views/location/Map-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/location/MapError-test.tsx b/test/unit-tests/components/views/location/MapError-test.tsx
index 75597a253f4..423a4645dcf 100644
--- a/test/unit-tests/components/views/location/MapError-test.tsx
+++ b/test/unit-tests/components/views/location/MapError-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/location/Marker-test.tsx b/test/unit-tests/components/views/location/Marker-test.tsx
index 3b00c37e7f8..e92738e9d46 100644
--- a/test/unit-tests/components/views/location/Marker-test.tsx
+++ b/test/unit-tests/components/views/location/Marker-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/location/SmartMarker-test.tsx b/test/unit-tests/components/views/location/SmartMarker-test.tsx
index 489d707fbf2..d1280c7a74c 100644
--- a/test/unit-tests/components/views/location/SmartMarker-test.tsx
+++ b/test/unit-tests/components/views/location/SmartMarker-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/location/ZoomButtons-test.tsx b/test/unit-tests/components/views/location/ZoomButtons-test.tsx
index ee4bdd596b4..7e6fcb2eabe 100644
--- a/test/unit-tests/components/views/location/ZoomButtons-test.tsx
+++ b/test/unit-tests/components/views/location/ZoomButtons-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022, 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/location/shareLocation-test.ts b/test/unit-tests/components/views/location/shareLocation-test.ts
index bdd0f7ab5cf..498df43ee18 100644
--- a/test/unit-tests/components/views/location/shareLocation-test.ts
+++ b/test/unit-tests/components/views/location/shareLocation-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/messages/CallEvent-test.tsx b/test/unit-tests/components/views/messages/CallEvent-test.tsx
index c76b2ec8266..b092cf84f64 100644
--- a/test/unit-tests/components/views/messages/CallEvent-test.tsx
+++ b/test/unit-tests/components/views/messages/CallEvent-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/messages/DateSeparator-test.tsx b/test/unit-tests/components/views/messages/DateSeparator-test.tsx
index 9b5b32cfcae..3177fd513da 100644
--- a/test/unit-tests/components/views/messages/DateSeparator-test.tsx
+++ b/test/unit-tests/components/views/messages/DateSeparator-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/messages/DecryptionFailureBody-test.tsx b/test/unit-tests/components/views/messages/DecryptionFailureBody-test.tsx
index 94495c4349a..5d5e3badc47 100644
--- a/test/unit-tests/components/views/messages/DecryptionFailureBody-test.tsx
+++ b/test/unit-tests/components/views/messages/DecryptionFailureBody-test.tsx
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2023 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/test/unit-tests/components/views/messages/DownloadActionButton-test.tsx b/test/unit-tests/components/views/messages/DownloadActionButton-test.tsx
index 0d770a30d94..a0cbe2c620c 100644
--- a/test/unit-tests/components/views/messages/DownloadActionButton-test.tsx
+++ b/test/unit-tests/components/views/messages/DownloadActionButton-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/messages/EncryptionEvent-test.tsx b/test/unit-tests/components/views/messages/EncryptionEvent-test.tsx
index 5788daebc0f..7ea9de76bc8 100644
--- a/test/unit-tests/components/views/messages/EncryptionEvent-test.tsx
+++ b/test/unit-tests/components/views/messages/EncryptionEvent-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/messages/JumpToDatePicker-test.tsx b/test/unit-tests/components/views/messages/JumpToDatePicker-test.tsx
index 971ec1ac29e..1b5c4dbd211 100644
--- a/test/unit-tests/components/views/messages/JumpToDatePicker-test.tsx
+++ b/test/unit-tests/components/views/messages/JumpToDatePicker-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/messages/LegacyCallEvent-test.tsx b/test/unit-tests/components/views/messages/LegacyCallEvent-test.tsx
index afff6b37303..f345b58a1c1 100644
--- a/test/unit-tests/components/views/messages/LegacyCallEvent-test.tsx
+++ b/test/unit-tests/components/views/messages/LegacyCallEvent-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/messages/MBeaconBody-test.tsx b/test/unit-tests/components/views/messages/MBeaconBody-test.tsx
index b95a6541062..6827d45df06 100644
--- a/test/unit-tests/components/views/messages/MBeaconBody-test.tsx
+++ b/test/unit-tests/components/views/messages/MBeaconBody-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/messages/MFileBody-test.tsx b/test/unit-tests/components/views/messages/MFileBody-test.tsx
index e124e3a2ffa..6d7f491bbef 100644
--- a/test/unit-tests/components/views/messages/MFileBody-test.tsx
+++ b/test/unit-tests/components/views/messages/MFileBody-test.tsx
@@ -1,7 +1,7 @@
 /*
 Copyright 2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/messages/MImageBody-test.tsx b/test/unit-tests/components/views/messages/MImageBody-test.tsx
index c15f2ea849b..f9ba25d7a96 100644
--- a/test/unit-tests/components/views/messages/MImageBody-test.tsx
+++ b/test/unit-tests/components/views/messages/MImageBody-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/messages/MKeyVerificationRequest-test.tsx b/test/unit-tests/components/views/messages/MKeyVerificationRequest-test.tsx
index 3ab9a98921b..2f08a8bf936 100644
--- a/test/unit-tests/components/views/messages/MKeyVerificationRequest-test.tsx
+++ b/test/unit-tests/components/views/messages/MKeyVerificationRequest-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/messages/MLocationBody-test.tsx b/test/unit-tests/components/views/messages/MLocationBody-test.tsx
index 17fabc17d16..f0f7bae8a75 100644
--- a/test/unit-tests/components/views/messages/MLocationBody-test.tsx
+++ b/test/unit-tests/components/views/messages/MLocationBody-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/messages/MPollBody-test.tsx b/test/unit-tests/components/views/messages/MPollBody-test.tsx
index 982fadad204..86849a1069e 100644
--- a/test/unit-tests/components/views/messages/MPollBody-test.tsx
+++ b/test/unit-tests/components/views/messages/MPollBody-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021, 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/messages/MPollEndBody-test.tsx b/test/unit-tests/components/views/messages/MPollEndBody-test.tsx
index 7bd2ad0a085..cc27c8a4d96 100644
--- a/test/unit-tests/components/views/messages/MPollEndBody-test.tsx
+++ b/test/unit-tests/components/views/messages/MPollEndBody-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/messages/MStickerBody-test.tsx b/test/unit-tests/components/views/messages/MStickerBody-test.tsx
index e5fe3ef450f..cf94a6d0c8a 100644
--- a/test/unit-tests/components/views/messages/MStickerBody-test.tsx
+++ b/test/unit-tests/components/views/messages/MStickerBody-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/messages/MVideoBody-test.tsx b/test/unit-tests/components/views/messages/MVideoBody-test.tsx
index 3f4289fea47..e445dc1711e 100644
--- a/test/unit-tests/components/views/messages/MVideoBody-test.tsx
+++ b/test/unit-tests/components/views/messages/MVideoBody-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/messages/MessageActionBar-test.tsx b/test/unit-tests/components/views/messages/MessageActionBar-test.tsx
index dda5b348a9a..1f28f1d008a 100644
--- a/test/unit-tests/components/views/messages/MessageActionBar-test.tsx
+++ b/test/unit-tests/components/views/messages/MessageActionBar-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022, 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/messages/MessageEvent-test.tsx b/test/unit-tests/components/views/messages/MessageEvent-test.tsx
index 4ff574f752b..63e00134fae 100644
--- a/test/unit-tests/components/views/messages/MessageEvent-test.tsx
+++ b/test/unit-tests/components/views/messages/MessageEvent-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/messages/MessageTimestamp-test.tsx b/test/unit-tests/components/views/messages/MessageTimestamp-test.tsx
index 8d1348c0dde..8840cad1dba 100644
--- a/test/unit-tests/components/views/messages/MessageTimestamp-test.tsx
+++ b/test/unit-tests/components/views/messages/MessageTimestamp-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/messages/PinnedMessageBadge-test.tsx b/test/unit-tests/components/views/messages/PinnedMessageBadge-test.tsx
index 824e3385633..884a78fd6c8 100644
--- a/test/unit-tests/components/views/messages/PinnedMessageBadge-test.tsx
+++ b/test/unit-tests/components/views/messages/PinnedMessageBadge-test.tsx
@@ -1,9 +1,8 @@
 /*
  * Copyright 2024 New Vector Ltd.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
- *
  */
 
 import React from "react";
diff --git a/test/unit-tests/components/views/messages/ReactionsRowButton-test.tsx b/test/unit-tests/components/views/messages/ReactionsRowButton-test.tsx
index c29dcd60a44..d00237e5d20 100644
--- a/test/unit-tests/components/views/messages/ReactionsRowButton-test.tsx
+++ b/test/unit-tests/components/views/messages/ReactionsRowButton-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 Beeper
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/messages/RoomPredecessorTile-test.tsx b/test/unit-tests/components/views/messages/RoomPredecessorTile-test.tsx
index 3ed7d7eb2b2..7b21f89584b 100644
--- a/test/unit-tests/components/views/messages/RoomPredecessorTile-test.tsx
+++ b/test/unit-tests/components/views/messages/RoomPredecessorTile-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/messages/TextualBody-test.tsx b/test/unit-tests/components/views/messages/TextualBody-test.tsx
index c7ffc4ed933..1e526e346b8 100644
--- a/test/unit-tests/components/views/messages/TextualBody-test.tsx
+++ b/test/unit-tests/components/views/messages/TextualBody-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -375,55 +375,73 @@ describe("<TextualBody />", () => {
         });
     });
 
-    it("renders url previews correctly", () => {
-        languageHandler.setMissingEntryGenerator((key) => key.split("|", 2)[1]);
+    describe("url preview", () => {
+        let matrixClient: MatrixClient;
 
-        const matrixClient = getMockClientWithEventEmitter({
-            getRoom: () => mkStubRoom("room_id", "room name", undefined),
-            getAccountData: (): MatrixClient | undefined => undefined,
-            getUrlPreview: (url: string) => new Promise(() => {}),
-            isGuest: () => false,
-            mxcUrlToHttp: (s: string) => s,
+        beforeEach(() => {
+            languageHandler.setMissingEntryGenerator((key) => key.split("|", 2)[1]);
+            matrixClient = getMockClientWithEventEmitter({
+                getRoom: () => mkStubRoom("room_id", "room name", undefined),
+                getAccountData: (): MatrixClient | undefined => undefined,
+                getUrlPreview: (url: string) => new Promise(() => {}),
+                isGuest: () => false,
+                mxcUrlToHttp: (s: string) => s,
+            });
+            DMRoomMap.makeShared(defaultMatrixClient);
         });
-        DMRoomMap.makeShared(defaultMatrixClient);
 
-        const ev = mkRoomTextMessage("Visit https://matrix.org/");
-        const { container, rerender } = getComponent(
-            { mxEvent: ev, showUrlPreview: true, onHeightChanged: jest.fn() },
-            matrixClient,
-        );
+        it("renders url previews correctly", () => {
+            const ev = mkRoomTextMessage("Visit https://matrix.org/");
+            const { container, rerender } = getComponent(
+                { mxEvent: ev, showUrlPreview: true, onHeightChanged: jest.fn() },
+                matrixClient,
+            );
 
-        expect(container).toHaveTextContent(ev.getContent().body);
-        expect(container.querySelector("a")).toHaveAttribute("href", "https://matrix.org/");
+            expect(container).toHaveTextContent(ev.getContent().body);
+            expect(container.querySelector("a")).toHaveAttribute("href", "https://matrix.org/");
 
-        // simulate an event edit and check the transition from the old URL preview to the new one
-        const ev2 = mkEvent({
-            type: "m.room.message",
-            room: "room_id",
-            user: "sender",
-            content: {
-                "m.new_content": {
-                    body: "Visit https://vector.im/ and https://riot.im/",
-                    msgtype: "m.text",
+            // simulate an event edit and check the transition from the old URL preview to the new one
+            const ev2 = mkEvent({
+                type: "m.room.message",
+                room: "room_id",
+                user: "sender",
+                content: {
+                    "m.new_content": {
+                        body: "Visit https://vector.im/ and https://riot.im/",
+                        msgtype: "m.text",
+                    },
                 },
-            },
-            event: true,
+                event: true,
+            });
+            jest.spyOn(ev, "replacingEventDate").mockReturnValue(new Date(1993, 7, 3));
+            ev.makeReplaced(ev2);
+
+            getComponent(
+                { mxEvent: ev, showUrlPreview: true, onHeightChanged: jest.fn(), replacingEventId: ev.getId() },
+                matrixClient,
+                rerender,
+            );
+
+            expect(container).toHaveTextContent(ev2.getContent()["m.new_content"].body + "(edited)");
+
+            const links = ["https://vector.im/", "https://riot.im/"];
+            const anchorNodes = container.querySelectorAll("a");
+            Array.from(anchorNodes).forEach((node, index) => {
+                expect(node).toHaveAttribute("href", links[index]);
+            });
         });
-        jest.spyOn(ev, "replacingEventDate").mockReturnValue(new Date(1993, 7, 3));
-        ev.makeReplaced(ev2);
 
-        getComponent(
-            { mxEvent: ev, showUrlPreview: true, onHeightChanged: jest.fn(), replacingEventId: ev.getId() },
-            matrixClient,
-            rerender,
-        );
+        it("should listen to showUrlPreview change", () => {
+            const ev = mkRoomTextMessage("Visit https://matrix.org/");
 
-        expect(container).toHaveTextContent(ev2.getContent()["m.new_content"].body + "(edited)");
+            const { container, rerender } = getComponent(
+                { mxEvent: ev, showUrlPreview: false, onHeightChanged: jest.fn() },
+                matrixClient,
+            );
+            expect(container.querySelector(".mx_LinkPreviewGroup")).toBeNull();
 
-        const links = ["https://vector.im/", "https://riot.im/"];
-        const anchorNodes = container.querySelectorAll("a");
-        Array.from(anchorNodes).forEach((node, index) => {
-            expect(node).toHaveAttribute("href", links[index]);
+            getComponent({ mxEvent: ev, showUrlPreview: true, onHeightChanged: jest.fn() }, matrixClient, rerender);
+            expect(container.querySelector(".mx_LinkPreviewGroup")).toBeTruthy();
         });
     });
 });
diff --git a/test/unit-tests/components/views/messages/shared/MediaProcessingError-test.tsx b/test/unit-tests/components/views/messages/shared/MediaProcessingError-test.tsx
index 3767e7f9855..dba0f28fa75 100644
--- a/test/unit-tests/components/views/messages/shared/MediaProcessingError-test.tsx
+++ b/test/unit-tests/components/views/messages/shared/MediaProcessingError-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/polls/pollHistory/PollHistory-test.tsx b/test/unit-tests/components/views/polls/pollHistory/PollHistory-test.tsx
index 1e0f0a658c6..55dcdda1633 100644
--- a/test/unit-tests/components/views/polls/pollHistory/PollHistory-test.tsx
+++ b/test/unit-tests/components/views/polls/pollHistory/PollHistory-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/polls/pollHistory/PollListItem-test.tsx b/test/unit-tests/components/views/polls/pollHistory/PollListItem-test.tsx
index 7c4cc6009f4..0bbacf9400b 100644
--- a/test/unit-tests/components/views/polls/pollHistory/PollListItem-test.tsx
+++ b/test/unit-tests/components/views/polls/pollHistory/PollListItem-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/polls/pollHistory/PollListItemEnded-test.tsx b/test/unit-tests/components/views/polls/pollHistory/PollListItemEnded-test.tsx
index a1d833c2b5b..492a86f679a 100644
--- a/test/unit-tests/components/views/polls/pollHistory/PollListItemEnded-test.tsx
+++ b/test/unit-tests/components/views/polls/pollHistory/PollListItemEnded-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/right_panel/BaseCard-test.tsx b/test/unit-tests/components/views/right_panel/BaseCard-test.tsx
index 72db04acf3d..3764f534929 100644
--- a/test/unit-tests/components/views/right_panel/BaseCard-test.tsx
+++ b/test/unit-tests/components/views/right_panel/BaseCard-test.tsx
@@ -1,7 +1,7 @@
 /*
 Copyright 2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/right_panel/ExtensionsCard-test.tsx b/test/unit-tests/components/views/right_panel/ExtensionsCard-test.tsx
index 932d75dd0d1..2b74276f28a 100644
--- a/test/unit-tests/components/views/right_panel/ExtensionsCard-test.tsx
+++ b/test/unit-tests/components/views/right_panel/ExtensionsCard-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/right_panel/PinnedMessagesCard-test.tsx b/test/unit-tests/components/views/right_panel/PinnedMessagesCard-test.tsx
index a8f7c653f9b..b63b84c7e61 100644
--- a/test/unit-tests/components/views/right_panel/PinnedMessagesCard-test.tsx
+++ b/test/unit-tests/components/views/right_panel/PinnedMessagesCard-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/right_panel/RoomSummaryCard-test.tsx b/test/unit-tests/components/views/right_panel/RoomSummaryCard-test.tsx
index 80d2609577e..48ba88d88a6 100644
--- a/test/unit-tests/components/views/right_panel/RoomSummaryCard-test.tsx
+++ b/test/unit-tests/components/views/right_panel/RoomSummaryCard-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -338,19 +338,18 @@ describe("<RoomSummaryCard />", () => {
         });
 
         it("does not show public room label for a DM", async () => {
-            mockClient.getAccountData.mockImplementation(
-                (eventType) =>
-                    ({
-                        [EventType.Direct]: new MatrixEvent({
-                            type: EventType.Direct,
-                            content: {
-                                "@bob:sesame.st": ["some-room-id"],
-                                // this room is a DM with ernie
-                                "@ernie:sesame.st": ["some-other-room-id", room.roomId],
-                            },
-                        }),
-                    })[eventType],
-            );
+            mockClient.getAccountData.mockImplementation((eventType) => {
+                if (eventType === EventType.Direct) {
+                    return new MatrixEvent({
+                        type: EventType.Direct,
+                        content: {
+                            "@bob:sesame.st": ["some-room-id"],
+                            // this room is a DM with ernie
+                            "@ernie:sesame.st": ["some-other-room-id", room.roomId],
+                        },
+                    });
+                }
+            });
             getComponent();
 
             await flushPromises();
diff --git a/test/unit-tests/components/views/right_panel/UserInfo-test.tsx b/test/unit-tests/components/views/right_panel/UserInfo-test.tsx
index 172b04a77c7..db7af71c242 100644
--- a/test/unit-tests/components/views/right_panel/UserInfo-test.tsx
+++ b/test/unit-tests/components/views/right_panel/UserInfo-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/right_panel/VerificationPanel-test.tsx b/test/unit-tests/components/views/right_panel/VerificationPanel-test.tsx
index 2adfc1eeb6c..4d1252ac3ad 100644
--- a/test/unit-tests/components/views/right_panel/VerificationPanel-test.tsx
+++ b/test/unit-tests/components/views/right_panel/VerificationPanel-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/right_panel/__snapshots__/PinnedMessagesCard-test.tsx.snap b/test/unit-tests/components/views/right_panel/__snapshots__/PinnedMessagesCard-test.tsx.snap
index 1ffef77d9c0..4a4ac6d6d63 100644
--- a/test/unit-tests/components/views/right_panel/__snapshots__/PinnedMessagesCard-test.tsx.snap
+++ b/test/unit-tests/components/views/right_panel/__snapshots__/PinnedMessagesCard-test.tsx.snap
@@ -145,6 +145,7 @@ exports[`<PinnedMessagesCard /> should show two pinned messages 1`] = `
               data-type="round"
               role="presentation"
               style="--cpd-avatar-size: 32px;"
+              title="@alice:example.org"
             >
               a
             </span>
@@ -222,6 +223,7 @@ exports[`<PinnedMessagesCard /> should show two pinned messages 1`] = `
               data-type="round"
               role="presentation"
               style="--cpd-avatar-size: 32px;"
+              title="@alice:example.org"
             >
               a
             </span>
@@ -364,6 +366,7 @@ exports[`<PinnedMessagesCard /> unpin all should not allow to unpinall 1`] = `
               data-type="round"
               role="presentation"
               style="--cpd-avatar-size: 32px;"
+              title="@alice:example.org"
             >
               a
             </span>
@@ -441,6 +444,7 @@ exports[`<PinnedMessagesCard /> unpin all should not allow to unpinall 1`] = `
               data-type="round"
               role="presentation"
               style="--cpd-avatar-size: 32px;"
+              title="@alice:example.org"
             >
               a
             </span>
diff --git a/test/unit-tests/components/views/room_settings/RoomProfileSettings-test.tsx b/test/unit-tests/components/views/room_settings/RoomProfileSettings-test.tsx
index 87065ba4104..a6af82d94b8 100644
--- a/test/unit-tests/components/views/room_settings/RoomProfileSettings-test.tsx
+++ b/test/unit-tests/components/views/room_settings/RoomProfileSettings-test.tsx
@@ -1,7 +1,7 @@
 /*
 Copyright 2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/room_settings/UrlPreviewSettings-test.tsx b/test/unit-tests/components/views/room_settings/UrlPreviewSettings-test.tsx
index cbd5410599a..fa4f34aa34b 100644
--- a/test/unit-tests/components/views/room_settings/UrlPreviewSettings-test.tsx
+++ b/test/unit-tests/components/views/room_settings/UrlPreviewSettings-test.tsx
@@ -1,7 +1,7 @@
 /*
  * Copyright 2024 New Vector Ltd.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/test/unit-tests/components/views/rooms/AppsDrawer-test.tsx b/test/unit-tests/components/views/rooms/AppsDrawer-test.tsx
index bb989b0937d..71e69bd91bc 100644
--- a/test/unit-tests/components/views/rooms/AppsDrawer-test.tsx
+++ b/test/unit-tests/components/views/rooms/AppsDrawer-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/rooms/BasicMessageComposer-test.tsx b/test/unit-tests/components/views/rooms/BasicMessageComposer-test.tsx
index d256c7c43e0..b8864624e59 100644
--- a/test/unit-tests/components/views/rooms/BasicMessageComposer-test.tsx
+++ b/test/unit-tests/components/views/rooms/BasicMessageComposer-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/rooms/EditMessageComposer-test.tsx b/test/unit-tests/components/views/rooms/EditMessageComposer-test.tsx
index beac0c8e1de..cdc961f73c3 100644
--- a/test/unit-tests/components/views/rooms/EditMessageComposer-test.tsx
+++ b/test/unit-tests/components/views/rooms/EditMessageComposer-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/rooms/EventTile-test.tsx b/test/unit-tests/components/views/rooms/EventTile-test.tsx
index 93445efbe30..057d93ee514 100644
--- a/test/unit-tests/components/views/rooms/EventTile-test.tsx
+++ b/test/unit-tests/components/views/rooms/EventTile-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022, 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/rooms/EventTile/EventTileThreadToolbar-test.tsx b/test/unit-tests/components/views/rooms/EventTile/EventTileThreadToolbar-test.tsx
index 7281bd4a12e..f08dbc4042d 100644
--- a/test/unit-tests/components/views/rooms/EventTile/EventTileThreadToolbar-test.tsx
+++ b/test/unit-tests/components/views/rooms/EventTile/EventTileThreadToolbar-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/rooms/ExtraTile-test.tsx b/test/unit-tests/components/views/rooms/ExtraTile-test.tsx
index 70097a47ee6..6330b5bbc8f 100644
--- a/test/unit-tests/components/views/rooms/ExtraTile-test.tsx
+++ b/test/unit-tests/components/views/rooms/ExtraTile-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/rooms/MemberList-test.tsx b/test/unit-tests/components/views/rooms/MemberList-test.tsx
deleted file mode 100644
index 34c37d2ba58..00000000000
--- a/test/unit-tests/components/views/rooms/MemberList-test.tsx
+++ /dev/null
@@ -1,452 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2022 The Matrix.org Foundation C.I.C.
-Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
-Please see LICENSE files in the repository root for full details.
-*/
-
-import React from "react";
-import {
-    act,
-    fireEvent,
-    render,
-    RenderResult,
-    screen,
-    waitFor,
-    waitForElementToBeRemoved,
-    cleanup,
-} from "jest-matrix-react";
-import { Room, MatrixClient, RoomState, RoomMember, User, MatrixEvent } from "matrix-js-sdk/src/matrix";
-import { KnownMembership } from "matrix-js-sdk/src/types";
-import { mocked, MockedObject } from "jest-mock";
-
-import { MatrixClientPeg } from "../../../../../src/MatrixClientPeg";
-import * as TestUtils from "../../../../test-utils";
-import MemberList from "../../../../../src/components/views/rooms/MemberList";
-import { SDKContext } from "../../../../../src/contexts/SDKContext";
-import { TestSdkContext } from "../../../TestSdkContext";
-import {
-    filterConsole,
-    flushPromises,
-    getMockClientWithEventEmitter,
-    mockClientMethodsRooms,
-    mockClientMethodsUser,
-} from "../../../../test-utils";
-import { shouldShowComponent } from "../../../../../src/customisations/helpers/UIComponents";
-import defaultDispatcher from "../../../../../src/dispatcher/dispatcher";
-
-jest.mock("../../../../../src/customisations/helpers/UIComponents", () => ({
-    shouldShowComponent: jest.fn(),
-}));
-
-function generateRoomId() {
-    return "!" + Math.random().toString().slice(2, 10) + ":domain";
-}
-
-describe("MemberList", () => {
-    filterConsole(
-        "Age for event was not available, using `now - origin_server_ts` as a fallback. If the device clock is not correct issues might occur.",
-    );
-    function createRoom(opts = {}) {
-        const room = new Room(generateRoomId(), client, client.getUserId()!);
-        if (opts) {
-            Object.assign(room, opts);
-        }
-        return room;
-    }
-
-    let client: MatrixClient;
-    let root: RenderResult;
-    let memberListRoom: Room;
-    let memberList: MemberList;
-
-    let adminUsers: RoomMember[] = [];
-    let moderatorUsers: RoomMember[] = [];
-    let defaultUsers: RoomMember[] = [];
-
-    function memberString(member: RoomMember): string {
-        if (!member) {
-            return "(null)";
-        } else {
-            const u = member.user;
-            return (
-                "(" +
-                member.name +
-                ", " +
-                member.powerLevel +
-                ", " +
-                (u ? u.lastActiveAgo : "<null>") +
-                ", " +
-                (u ? u.getLastActiveTs() : "<null>") +
-                ", " +
-                (u ? u.currentlyActive : "<null>") +
-                ", " +
-                (u ? u.presence : "<null>") +
-                ")"
-            );
-        }
-    }
-
-    function expectOrderedByPresenceAndPowerLevel(memberTiles: NodeListOf<Element>, isPresenceEnabled: boolean) {
-        let prevMember: RoomMember | undefined;
-        for (const tile of memberTiles) {
-            const memberA = prevMember;
-            const memberB = memberListRoom.currentState.members[tile.getAttribute("aria-label")!.split(" ")[0]];
-            prevMember = memberB; // just in case an expect fails, set this early
-            if (!memberA) {
-                continue;
-            }
-
-            console.log("COMPARING A VS B:", memberString(memberA), memberString(memberB));
-
-            const userA = memberA.user!;
-            const userB = memberB.user!;
-
-            let groupChange = false;
-
-            if (isPresenceEnabled) {
-                const convertPresence = (p: string) => (p === "unavailable" ? "online" : p);
-                const presenceIndex = (p: string) => {
-                    const order = ["active", "online", "offline"];
-                    const idx = order.indexOf(convertPresence(p));
-                    return idx === -1 ? order.length : idx; // unknown states at the end
-                };
-
-                const idxA = presenceIndex(userA.currentlyActive ? "active" : userA.presence);
-                const idxB = presenceIndex(userB.currentlyActive ? "active" : userB.presence);
-                console.log("Comparing presence groups...");
-                expect(idxB).toBeGreaterThanOrEqual(idxA);
-                groupChange = idxA !== idxB;
-            } else {
-                console.log("Skipped presence groups");
-            }
-
-            if (!groupChange) {
-                console.log("Comparing power levels...");
-                expect(memberA.powerLevel).toBeGreaterThanOrEqual(memberB.powerLevel);
-                groupChange = memberA.powerLevel !== memberB.powerLevel;
-            } else {
-                console.log("Skipping power level check due to group change");
-            }
-
-            if (!groupChange) {
-                if (isPresenceEnabled) {
-                    console.log("Comparing last active timestamp...");
-                    expect(userB.getLastActiveTs()).toBeLessThanOrEqual(userA.getLastActiveTs());
-                    groupChange = userA.getLastActiveTs() !== userB.getLastActiveTs();
-                } else {
-                    console.log("Skipping last active timestamp");
-                }
-            } else {
-                console.log("Skipping last active timestamp check due to group change");
-            }
-
-            if (!groupChange) {
-                const nameA = memberA.name[0] === "@" ? memberA.name.slice(1) : memberA.name;
-                const nameB = memberB.name[0] === "@" ? memberB.name.slice(1) : memberB.name;
-                const collator = new Intl.Collator();
-                const nameCompare = collator.compare(nameB, nameA);
-                console.log("Comparing name");
-                expect(nameCompare).toBeGreaterThanOrEqual(0);
-            } else {
-                console.log("Skipping name check due to group change");
-            }
-        }
-    }
-
-    function renderMemberList(enablePresence: boolean): void {
-        TestUtils.stubClient();
-        client = MatrixClientPeg.safeGet();
-        client.hasLazyLoadMembersEnabled = () => false;
-
-        // Make room
-        memberListRoom = createRoom();
-        expect(memberListRoom.roomId).toBeTruthy();
-
-        // Make users
-        adminUsers = [];
-        moderatorUsers = [];
-        defaultUsers = [];
-        const usersPerLevel = 2;
-        for (let i = 0; i < usersPerLevel; i++) {
-            const adminUser = new RoomMember(memberListRoom.roomId, `@admin${i}:localhost`);
-            adminUser.membership = KnownMembership.Join;
-            adminUser.powerLevel = 100;
-            adminUser.user = User.createUser(adminUser.userId, client);
-            adminUser.user.currentlyActive = true;
-            adminUser.user.presence = "online";
-            adminUser.user.lastPresenceTs = 1000;
-            adminUser.user.lastActiveAgo = 10;
-            adminUsers.push(adminUser);
-
-            const moderatorUser = new RoomMember(memberListRoom.roomId, `@moderator${i}:localhost`);
-            moderatorUser.membership = KnownMembership.Join;
-            moderatorUser.powerLevel = 50;
-            moderatorUser.user = User.createUser(moderatorUser.userId, client);
-            moderatorUser.user.currentlyActive = true;
-            moderatorUser.user.presence = "online";
-            moderatorUser.user.lastPresenceTs = 1000;
-            moderatorUser.user.lastActiveAgo = 10;
-            moderatorUsers.push(moderatorUser);
-
-            const defaultUser = new RoomMember(memberListRoom.roomId, `@default${i}:localhost`);
-            defaultUser.membership = KnownMembership.Join;
-            defaultUser.powerLevel = 0;
-            defaultUser.user = User.createUser(defaultUser.userId, client);
-            defaultUser.user.currentlyActive = true;
-            defaultUser.user.presence = "online";
-            defaultUser.user.lastPresenceTs = 1000;
-            defaultUser.user.lastActiveAgo = 10;
-            defaultUsers.push(defaultUser);
-        }
-
-        client.getRoom = (roomId) => {
-            if (roomId === memberListRoom.roomId) return memberListRoom;
-            else return null;
-        };
-        memberListRoom.currentState = {
-            members: {},
-            getMember: jest.fn(),
-            getStateEvents: ((eventType, stateKey) =>
-                stateKey === undefined ? [] : null) as RoomState["getStateEvents"], // ignore 3pid invites
-        } as unknown as RoomState;
-        for (const member of [...adminUsers, ...moderatorUsers, ...defaultUsers]) {
-            memberListRoom.currentState.members[member.userId] = member;
-        }
-
-        const gatherWrappedRef = (r: MemberList) => {
-            memberList = r;
-        };
-        const context = new TestSdkContext();
-        context.client = client;
-        context.memberListStore.isPresenceEnabled = jest.fn().mockReturnValue(enablePresence);
-        root = render(
-            <SDKContext.Provider value={context}>
-                <MemberList
-                    searchQuery=""
-                    onClose={jest.fn()}
-                    onSearchQueryChanged={jest.fn()}
-                    roomId={memberListRoom.roomId}
-                    ref={gatherWrappedRef}
-                />
-            </SDKContext.Provider>,
-        );
-    }
-
-    describe.each([false, true])("does order members correctly (presence %s)", (enablePresence) => {
-        beforeEach(function () {
-            renderMemberList(enablePresence);
-        });
-
-        describe("does order members correctly", () => {
-            // Note: even if presence is disabled, we still expect that the presence
-            // tests will pass. All expectOrderedByPresenceAndPowerLevel does is ensure
-            // the order is perceived correctly, regardless of what we did to the members.
-
-            // Each of the 4 tests here is done to prove that the member list can meet
-            // all 4 criteria independently. Together, they should work.
-
-            it("by presence state", async () => {
-                // Intentionally pick users that will confuse the power level sorting
-                const activeUsers = [defaultUsers[0]];
-                const onlineUsers = [adminUsers[0]];
-                const offlineUsers = [...moderatorUsers, ...adminUsers.slice(1), ...defaultUsers.slice(1)];
-                activeUsers.forEach((u) => {
-                    u.user!.currentlyActive = true;
-                    u.user!.presence = "online";
-                });
-                onlineUsers.forEach((u) => {
-                    u.user!.currentlyActive = false;
-                    u.user!.presence = "online";
-                });
-                offlineUsers.forEach((u) => {
-                    u.user!.currentlyActive = false;
-                    u.user!.presence = "offline";
-                });
-
-                // Bypass all the event listeners and skip to the good part
-                await act(() => memberList.updateListNow(true));
-
-                const tiles = root.container.querySelectorAll(".mx_EntityTile");
-                expectOrderedByPresenceAndPowerLevel(tiles, enablePresence);
-            });
-
-            it("by power level", async () => {
-                // We already have admin, moderator, and default users so leave them alone
-
-                // Bypass all the event listeners and skip to the good part
-                await act(() => memberList.updateListNow(true));
-
-                const tiles = root.container.querySelectorAll(".mx_EntityTile");
-                expectOrderedByPresenceAndPowerLevel(tiles, enablePresence);
-            });
-
-            it("by last active timestamp", async () => {
-                // Intentionally pick users that will confuse the power level sorting
-                // lastActiveAgoTs == lastPresenceTs - lastActiveAgo
-                const activeUsers = [defaultUsers[0]];
-                const semiActiveUsers = [adminUsers[0]];
-                const inactiveUsers = [...moderatorUsers, ...adminUsers.slice(1), ...defaultUsers.slice(1)];
-                activeUsers.forEach((u) => {
-                    u.powerLevel = 100; // set everyone to the same PL to avoid running that check
-                    u.user!.lastPresenceTs = 1000;
-                    u.user!.lastActiveAgo = 0;
-                });
-                semiActiveUsers.forEach((u) => {
-                    u.powerLevel = 100;
-                    u.user!.lastPresenceTs = 1000;
-                    u.user!.lastActiveAgo = 50;
-                });
-                inactiveUsers.forEach((u) => {
-                    u.powerLevel = 100;
-                    u.user!.lastPresenceTs = 1000;
-                    u.user!.lastActiveAgo = 100;
-                });
-
-                // Bypass all the event listeners and skip to the good part
-                await act(() => memberList.updateListNow(true));
-
-                const tiles = root.container.querySelectorAll(".mx_EntityTile");
-                expectOrderedByPresenceAndPowerLevel(tiles, enablePresence);
-            });
-
-            it("by name", async () => {
-                // Intentionally put everyone on the same level to force a name comparison
-                const allUsers = [...adminUsers, ...moderatorUsers, ...defaultUsers];
-                allUsers.forEach((u) => {
-                    u.user!.currentlyActive = true;
-                    u.user!.presence = "online";
-                    u.user!.lastPresenceTs = 1000;
-                    u.user!.lastActiveAgo = 0;
-                    u.powerLevel = 100;
-                });
-
-                // Bypass all the event listeners and skip to the good part
-                await act(() => memberList.updateListNow(true));
-
-                const tiles = root.container.querySelectorAll(".mx_EntityTile");
-                expectOrderedByPresenceAndPowerLevel(tiles, enablePresence);
-            });
-        });
-    });
-
-    describe("memberlist is rendered correctly", () => {
-        beforeEach(function () {
-            renderMemberList(true);
-        });
-
-        it("memberlist is re-rendered on unreachable presence event", async () => {
-            defaultUsers[0].user?.setPresenceEvent(
-                new MatrixEvent({
-                    type: "m.presence",
-                    sender: defaultUsers[0].userId,
-                    content: {
-                        presence: "io.element.unreachable",
-                        currently_active: false,
-                    },
-                }),
-            );
-            expect(await screen.findByText(/User's server unreachable/)).toBeInTheDocument();
-        });
-
-        describe("Invite button", () => {
-            const roomId = "!room:server.org";
-            let client!: MockedObject<MatrixClient>;
-            let room!: Room;
-
-            beforeEach(function () {
-                mocked(shouldShowComponent).mockReturnValue(true);
-                client = getMockClientWithEventEmitter({
-                    ...mockClientMethodsUser(),
-                    ...mockClientMethodsRooms(),
-                    getRoom: jest.fn(),
-                    hasLazyLoadMembersEnabled: jest.fn(),
-                });
-                room = new Room(roomId, client, client.getSafeUserId());
-                client.getRoom.mockReturnValue(room);
-            });
-
-            afterEach(() => {
-                jest.restoreAllMocks();
-                cleanup();
-            });
-
-            const renderComponent = () => {
-                const context = new TestSdkContext();
-                context.client = client;
-                return render(
-                    <SDKContext.Provider value={context}>
-                        <MemberList
-                            searchQuery=""
-                            onClose={jest.fn()}
-                            onSearchQueryChanged={jest.fn()}
-                            roomId={room.roomId}
-                        />
-                    </SDKContext.Provider>,
-                );
-            };
-
-            it("does not render invite button when current user is not a member", async () => {
-                renderComponent();
-                await flushPromises();
-
-                expect(screen.queryByText("Invite to this room")).not.toBeInTheDocument();
-            });
-
-            it("does not render invite button UI customisation hides invites", async () => {
-                mocked(shouldShowComponent).mockReturnValue(false);
-                renderComponent();
-                await flushPromises();
-
-                expect(screen.queryByText("Invite to this room")).not.toBeInTheDocument();
-            });
-
-            it("renders disabled invite button when current user is a member but does not have rights to invite", async () => {
-                jest.spyOn(room, "getMyMembership").mockReturnValue(KnownMembership.Join);
-                jest.spyOn(room, "canInvite").mockReturnValue(false);
-
-                const { findByLabelText } = renderComponent();
-
-                // button rendered but disabled
-                await expect(findByLabelText("You do not have permission to invite users")).resolves.toHaveAttribute(
-                    "aria-disabled",
-                    "true",
-                );
-            });
-
-            it("renders enabled invite button when current user is a member and has rights to invite", async () => {
-                jest.spyOn(room, "getMyMembership").mockReturnValue(KnownMembership.Join);
-                jest.spyOn(room, "canInvite").mockReturnValue(true);
-
-                const { findByText } = renderComponent();
-
-                await expect(findByText("Invite to this room")).resolves.not.toBeDisabled();
-            });
-
-            it("opens room inviter on button click", async () => {
-                jest.spyOn(defaultDispatcher, "dispatch");
-                jest.spyOn(room, "getMyMembership").mockReturnValue(KnownMembership.Join);
-                jest.spyOn(room, "canInvite").mockReturnValue(true);
-
-                const { getByRole } = renderComponent();
-                await waitForElementToBeRemoved(() => screen.queryAllByRole("progressbar"));
-
-                await waitFor(() =>
-                    expect(getByRole("button", { name: "Invite to this room" })).not.toHaveAttribute(
-                        "aria-disabled",
-                        "true",
-                    ),
-                );
-
-                fireEvent.click(getByRole("button", { name: "Invite to this room" }));
-
-                expect(defaultDispatcher.dispatch).toHaveBeenCalledWith({
-                    action: "view_invite",
-                    roomId,
-                });
-            });
-        });
-    });
-});
diff --git a/test/unit-tests/components/views/rooms/MemberTile-test.tsx b/test/unit-tests/components/views/rooms/MemberTile-test.tsx
deleted file mode 100644
index cf829c2927e..00000000000
--- a/test/unit-tests/components/views/rooms/MemberTile-test.tsx
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright 2024 New Vector Ltd.
- * Copyright 2023 The Matrix.org Foundation C.I.C.
- *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
- * Please see LICENSE files in the repository root for full details.
- */
-
-import React from "react";
-import { render, screen, waitFor } from "jest-matrix-react";
-import { MatrixClient, RoomMember, Device } from "matrix-js-sdk/src/matrix";
-import { UserVerificationStatus, DeviceVerificationStatus } from "matrix-js-sdk/src/crypto-api";
-import { mocked } from "jest-mock";
-import userEvent from "@testing-library/user-event";
-
-import * as TestUtils from "../../../../test-utils";
-import MemberTile from "../../../../../src/components/views/rooms/MemberTile";
-
-describe("MemberTile", () => {
-    let matrixClient: MatrixClient;
-    let member: RoomMember;
-
-    beforeEach(() => {
-        matrixClient = TestUtils.stubClient();
-        mocked(matrixClient.isRoomEncrypted).mockReturnValue(true);
-        member = new RoomMember("roomId", matrixClient.getUserId()!);
-    });
-
-    it("should not display an E2EIcon when the e2E status = normal", () => {
-        const { container } = render(<MemberTile member={member} />);
-
-        expect(container).toMatchSnapshot();
-    });
-
-    it("should display an warning E2EIcon when the e2E status = Warning", async () => {
-        mocked(matrixClient.getCrypto()!.getUserVerificationStatus).mockResolvedValue({
-            isCrossSigningVerified: jest.fn().mockReturnValue(false),
-            wasCrossSigningVerified: jest.fn().mockReturnValue(true),
-        } as unknown as UserVerificationStatus);
-
-        const { container } = render(<MemberTile member={member} />);
-
-        expect(container).toMatchSnapshot();
-        await waitFor(async () => {
-            await userEvent.hover(container.querySelector(".mx_E2EIcon")!);
-            expect(screen.getByText("This user has not verified all of their sessions.")).toBeInTheDocument();
-        });
-    });
-
-    it("should display an verified E2EIcon when the e2E status = Verified", async () => {
-        // Mock all the required crypto methods
-        const deviceMap = new Map<string, Map<string, Device>>();
-        deviceMap.set(member.userId, new Map([["deviceId", {} as Device]]));
-        // Return a DeviceMap = Map<string, Map<string, Device>>
-        mocked(matrixClient.getCrypto()!.getUserDeviceInfo).mockResolvedValue(deviceMap);
-        mocked(matrixClient.getCrypto()!.getUserVerificationStatus).mockResolvedValue({
-            isCrossSigningVerified: jest.fn().mockReturnValue(true),
-        } as unknown as UserVerificationStatus);
-        mocked(matrixClient.getCrypto()!.getDeviceVerificationStatus).mockResolvedValue({
-            crossSigningVerified: true,
-        } as DeviceVerificationStatus);
-
-        const { container } = render(<MemberTile member={member} />);
-
-        expect(container).toMatchSnapshot();
-        await waitFor(async () => {
-            await userEvent.hover(container.querySelector(".mx_E2EIcon")!);
-            expect(
-                screen.getByText("You have verified this user. This user has verified all of their sessions."),
-            ).toBeInTheDocument();
-        });
-    });
-});
diff --git a/test/unit-tests/components/views/rooms/MessageComposer-test.tsx b/test/unit-tests/components/views/rooms/MessageComposer-test.tsx
index 6849612fee5..895b5f09a77 100644
--- a/test/unit-tests/components/views/rooms/MessageComposer-test.tsx
+++ b/test/unit-tests/components/views/rooms/MessageComposer-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -10,6 +10,7 @@ import * as React from "react";
 import { EventType, MatrixEvent, RoomMember, THREAD_RELATION_TYPE } from "matrix-js-sdk/src/matrix";
 import { act, fireEvent, render, screen, waitFor } from "jest-matrix-react";
 import userEvent from "@testing-library/user-event";
+import { initOnce } from "@vector-im/matrix-wysiwyg";
 
 import {
     clearAllModals,
@@ -52,6 +53,8 @@ const expectVoiceMessageRecordingTriggered = (): void => {
     expect(screen.getByText("No microphone found")).toBeInTheDocument();
 };
 
+beforeAll(initOnce, 10000);
+
 describe("MessageComposer", () => {
     stubClient();
     const cli = createTestClient();
@@ -66,11 +69,13 @@ describe("MessageComposer", () => {
 
         // restore settings
         act(() => {
-            [
-                "MessageComposerInput.showStickersButton",
-                "MessageComposerInput.showPollsButton",
-                "feature_wysiwyg_composer",
-            ].forEach((setting: string): void => {
+            (
+                [
+                    "MessageComposerInput.showStickersButton",
+                    "MessageComposerInput.showPollsButton",
+                    "feature_wysiwyg_composer",
+                ] as const
+            ).forEach((setting): void => {
                 SettingsStore.setValue(setting, null, SettingLevel.DEVICE, SettingsStore.getDefaultValue(setting));
             });
         });
@@ -188,11 +193,11 @@ describe("MessageComposer", () => {
         // test button display depending on settings
         [
             {
-                setting: "MessageComposerInput.showStickersButton",
+                setting: "MessageComposerInput.showStickersButton" as const,
                 buttonLabel: "Sticker",
             },
             {
-                setting: "MessageComposerInput.showPollsButton",
+                setting: "MessageComposerInput.showPollsButton" as const,
                 buttonLabel: "Poll",
             },
         ].forEach(({ setting, buttonLabel }) => {
diff --git a/test/unit-tests/components/views/rooms/MessageComposerButtons-test.tsx b/test/unit-tests/components/views/rooms/MessageComposerButtons-test.tsx
index c2f56dc968d..fffb852ebfe 100644
--- a/test/unit-tests/components/views/rooms/MessageComposerButtons-test.tsx
+++ b/test/unit-tests/components/views/rooms/MessageComposerButtons-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/rooms/NewRoomIntro-test.tsx b/test/unit-tests/components/views/rooms/NewRoomIntro-test.tsx
index a1cd4526107..a5d598e1b4b 100644
--- a/test/unit-tests/components/views/rooms/NewRoomIntro-test.tsx
+++ b/test/unit-tests/components/views/rooms/NewRoomIntro-test.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2015-2022 The Matrix.org Foundation C.I.C.
 Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/rooms/NotificationBadge/NotificationBadge-test.tsx b/test/unit-tests/components/views/rooms/NotificationBadge/NotificationBadge-test.tsx
index e4ff88c2363..bcbb4ab7126 100644
--- a/test/unit-tests/components/views/rooms/NotificationBadge/NotificationBadge-test.tsx
+++ b/test/unit-tests/components/views/rooms/NotificationBadge/NotificationBadge-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/rooms/NotificationBadge/StatelessNotificationBadge-test.tsx b/test/unit-tests/components/views/rooms/NotificationBadge/StatelessNotificationBadge-test.tsx
index 8f3b5879138..4b335cb631e 100644
--- a/test/unit-tests/components/views/rooms/NotificationBadge/StatelessNotificationBadge-test.tsx
+++ b/test/unit-tests/components/views/rooms/NotificationBadge/StatelessNotificationBadge-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/rooms/NotificationBadge/UnreadNotificationBadge-test.tsx b/test/unit-tests/components/views/rooms/NotificationBadge/UnreadNotificationBadge-test.tsx
index 5b2dddc73ae..6628889dc7e 100644
--- a/test/unit-tests/components/views/rooms/NotificationBadge/UnreadNotificationBadge-test.tsx
+++ b/test/unit-tests/components/views/rooms/NotificationBadge/UnreadNotificationBadge-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022, 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/rooms/PinnedEventTile-test.tsx b/test/unit-tests/components/views/rooms/PinnedEventTile-test.tsx
index a0725a50075..9031d238a82 100644
--- a/test/unit-tests/components/views/rooms/PinnedEventTile-test.tsx
+++ b/test/unit-tests/components/views/rooms/PinnedEventTile-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/rooms/PinnedMessageBanner-test.tsx b/test/unit-tests/components/views/rooms/PinnedMessageBanner-test.tsx
index 8717762e0da..66e0e32f386 100644
--- a/test/unit-tests/components/views/rooms/PinnedMessageBanner-test.tsx
+++ b/test/unit-tests/components/views/rooms/PinnedMessageBanner-test.tsx
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2024 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/test/unit-tests/components/views/rooms/PresenceLabel-test.tsx b/test/unit-tests/components/views/rooms/PresenceLabel-test.tsx
index 88a0e346bff..a8af6f768c8 100644
--- a/test/unit-tests/components/views/rooms/PresenceLabel-test.tsx
+++ b/test/unit-tests/components/views/rooms/PresenceLabel-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/rooms/ReadReceiptGroup-test.tsx b/test/unit-tests/components/views/rooms/ReadReceiptGroup-test.tsx
index 13500f9b1f9..ec9884591f0 100644
--- a/test/unit-tests/components/views/rooms/ReadReceiptGroup-test.tsx
+++ b/test/unit-tests/components/views/rooms/ReadReceiptGroup-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/rooms/ReadReceiptMarker-test.tsx b/test/unit-tests/components/views/rooms/ReadReceiptMarker-test.tsx
index f7dc843f395..68b7bc9799f 100644
--- a/test/unit-tests/components/views/rooms/ReadReceiptMarker-test.tsx
+++ b/test/unit-tests/components/views/rooms/ReadReceiptMarker-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/rooms/RoomHeader-test.tsx b/test/unit-tests/components/views/rooms/RoomHeader-test.tsx
index 8b9b0d98481..633100eec4c 100644
--- a/test/unit-tests/components/views/rooms/RoomHeader-test.tsx
+++ b/test/unit-tests/components/views/rooms/RoomHeader-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -176,7 +176,7 @@ describe("RoomHeader", () => {
     });
 
     it("opens the notifications panel", async () => {
-        jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string) => {
+        jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string): any => {
             if (name === "feature_notifications") return true;
         });
 
diff --git a/test/unit-tests/components/views/rooms/RoomHeader/CallGuestLinkButton-test.tsx b/test/unit-tests/components/views/rooms/RoomHeader/CallGuestLinkButton-test.tsx
index c77114fa96e..a89058d7301 100644
--- a/test/unit-tests/components/views/rooms/RoomHeader/CallGuestLinkButton-test.tsx
+++ b/test/unit-tests/components/views/rooms/RoomHeader/CallGuestLinkButton-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/rooms/RoomHeader/VideoRoomChatButton-test.tsx b/test/unit-tests/components/views/rooms/RoomHeader/VideoRoomChatButton-test.tsx
index c080fa8659f..9a1466a2617 100644
--- a/test/unit-tests/components/views/rooms/RoomHeader/VideoRoomChatButton-test.tsx
+++ b/test/unit-tests/components/views/rooms/RoomHeader/VideoRoomChatButton-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/rooms/RoomKnocksBar-test.tsx b/test/unit-tests/components/views/rooms/RoomKnocksBar-test.tsx
index 54a9177fbf5..4f1ad97bca1 100644
--- a/test/unit-tests/components/views/rooms/RoomKnocksBar-test.tsx
+++ b/test/unit-tests/components/views/rooms/RoomKnocksBar-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 Nordeck IT + Consulting GmbH
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/rooms/RoomList-test.tsx b/test/unit-tests/components/views/rooms/RoomList-test.tsx
index cb824bcdf9a..4ee68deb216 100644
--- a/test/unit-tests/components/views/rooms/RoomList-test.tsx
+++ b/test/unit-tests/components/views/rooms/RoomList-test.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2023 Mikhail Aheichyk
 Copyright 2023 Nordeck IT + Consulting GmbH.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/rooms/RoomListHeader-test.tsx b/test/unit-tests/components/views/rooms/RoomListHeader-test.tsx
index c44c3a501bf..ade08b8f956 100644
--- a/test/unit-tests/components/views/rooms/RoomListHeader-test.tsx
+++ b/test/unit-tests/components/views/rooms/RoomListHeader-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/rooms/RoomPreviewBar-test.tsx b/test/unit-tests/components/views/rooms/RoomPreviewBar-test.tsx
index fb531bb3bd9..112b088709c 100644
--- a/test/unit-tests/components/views/rooms/RoomPreviewBar-test.tsx
+++ b/test/unit-tests/components/views/rooms/RoomPreviewBar-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/rooms/RoomPreviewCard-test.tsx b/test/unit-tests/components/views/rooms/RoomPreviewCard-test.tsx
index 274c79002c7..b80ce4bb5b6 100644
--- a/test/unit-tests/components/views/rooms/RoomPreviewCard-test.tsx
+++ b/test/unit-tests/components/views/rooms/RoomPreviewCard-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -44,7 +44,7 @@ describe("RoomPreviewCard", () => {
         client.reEmitter.reEmit(room, [RoomStateEvent.Events]);
 
         enabledFeatures = [];
-        jest.spyOn(SettingsStore, "getValue").mockImplementation((settingName) =>
+        jest.spyOn(SettingsStore, "getValue").mockImplementation((settingName): any =>
             enabledFeatures.includes(settingName) ? true : undefined,
         );
     });
diff --git a/test/unit-tests/components/views/rooms/RoomSearchAuxPanel-test.tsx b/test/unit-tests/components/views/rooms/RoomSearchAuxPanel-test.tsx
index 0c720bf40ea..6a46be23534 100644
--- a/test/unit-tests/components/views/rooms/RoomSearchAuxPanel-test.tsx
+++ b/test/unit-tests/components/views/rooms/RoomSearchAuxPanel-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/rooms/RoomTile-test.tsx b/test/unit-tests/components/views/rooms/RoomTile-test.tsx
index c14c699699f..e5169d91214 100644
--- a/test/unit-tests/components/views/rooms/RoomTile-test.tsx
+++ b/test/unit-tests/components/views/rooms/RoomTile-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/rooms/SearchResultTile-test.tsx b/test/unit-tests/components/views/rooms/SearchResultTile-test.tsx
index 358c36d2fba..c12aa15eaeb 100644
--- a/test/unit-tests/components/views/rooms/SearchResultTile-test.tsx
+++ b/test/unit-tests/components/views/rooms/SearchResultTile-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022, 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/rooms/SendMessageComposer-test.tsx b/test/unit-tests/components/views/rooms/SendMessageComposer-test.tsx
index c372819ce21..ad0ec2afdf2 100644
--- a/test/unit-tests/components/views/rooms/SendMessageComposer-test.tsx
+++ b/test/unit-tests/components/views/rooms/SendMessageComposer-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/rooms/ThirdPartyMemberInfo-test.tsx b/test/unit-tests/components/views/rooms/ThirdPartyMemberInfo-test.tsx
index 958ebf7d1fe..60541cd30a2 100644
--- a/test/unit-tests/components/views/rooms/ThirdPartyMemberInfo-test.tsx
+++ b/test/unit-tests/components/views/rooms/ThirdPartyMemberInfo-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/rooms/UserIdentityWarning-test.tsx b/test/unit-tests/components/views/rooms/UserIdentityWarning-test.tsx
index 9a70a887688..eef25269125 100644
--- a/test/unit-tests/components/views/rooms/UserIdentityWarning-test.tsx
+++ b/test/unit-tests/components/views/rooms/UserIdentityWarning-test.tsx
@@ -1,7 +1,7 @@
 /*
 Copyright 2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/rooms/VoiceRecordComposerTile-test.tsx b/test/unit-tests/components/views/rooms/VoiceRecordComposerTile-test.tsx
index a8d4b022a6b..06d314b5884 100644
--- a/test/unit-tests/components/views/rooms/VoiceRecordComposerTile-test.tsx
+++ b/test/unit-tests/components/views/rooms/VoiceRecordComposerTile-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/rooms/__snapshots__/MemberTile-test.tsx.snap b/test/unit-tests/components/views/rooms/__snapshots__/MemberTile-test.tsx.snap
deleted file mode 100644
index b5d7b87a7ea..00000000000
--- a/test/unit-tests/components/views/rooms/__snapshots__/MemberTile-test.tsx.snap
+++ /dev/null
@@ -1,160 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`MemberTile should display an verified E2EIcon when the e2E status = Verified 1`] = `
-<div>
-  <div>
-    <div
-      aria-label="@userId:matrix.org (power 0)"
-      class="mx_AccessibleButton mx_EntityTile mx_EntityTile_offline_neveractive"
-      role="button"
-      tabindex="0"
-    >
-      <div
-        class="mx_EntityTile_avatar"
-      >
-        <span
-          aria-hidden="true"
-          class="_avatar_mcap2_17 mx_BaseAvatar _avatar-imageless_mcap2_61"
-          data-color="2"
-          data-testid="avatar-img"
-          data-type="round"
-          role="presentation"
-          style="--cpd-avatar-size: 36px;"
-          title="@userId:matrix.org"
-        >
-          u
-        </span>
-      </div>
-      <div
-        class="mx_EntityTile_details"
-      >
-        <div
-          class="mx_EntityTile_name"
-        >
-          <div
-            class="mx_DisambiguatedProfile"
-          >
-            <span
-              class=""
-              dir="auto"
-            >
-              @userId:matrix.org
-            </span>
-          </div>
-        </div>
-        <div
-          class="mx_PresenceLabel"
-        >
-          Offline
-        </div>
-      </div>
-    </div>
-  </div>
-</div>
-`;
-
-exports[`MemberTile should display an warning E2EIcon when the e2E status = Warning 1`] = `
-<div>
-  <div>
-    <div
-      aria-label="@userId:matrix.org (power 0)"
-      class="mx_AccessibleButton mx_EntityTile mx_EntityTile_offline_neveractive"
-      role="button"
-      tabindex="0"
-    >
-      <div
-        class="mx_EntityTile_avatar"
-      >
-        <span
-          aria-hidden="true"
-          class="_avatar_mcap2_17 mx_BaseAvatar _avatar-imageless_mcap2_61"
-          data-color="2"
-          data-testid="avatar-img"
-          data-type="round"
-          role="presentation"
-          style="--cpd-avatar-size: 36px;"
-          title="@userId:matrix.org"
-        >
-          u
-        </span>
-      </div>
-      <div
-        class="mx_EntityTile_details"
-      >
-        <div
-          class="mx_EntityTile_name"
-        >
-          <div
-            class="mx_DisambiguatedProfile"
-          >
-            <span
-              class=""
-              dir="auto"
-            >
-              @userId:matrix.org
-            </span>
-          </div>
-        </div>
-        <div
-          class="mx_PresenceLabel"
-        >
-          Offline
-        </div>
-      </div>
-    </div>
-  </div>
-</div>
-`;
-
-exports[`MemberTile should not display an E2EIcon when the e2E status = normal 1`] = `
-<div>
-  <div>
-    <div
-      aria-label="@userId:matrix.org (power 0)"
-      class="mx_AccessibleButton mx_EntityTile mx_EntityTile_offline_neveractive"
-      role="button"
-      tabindex="0"
-    >
-      <div
-        class="mx_EntityTile_avatar"
-      >
-        <span
-          aria-hidden="true"
-          class="_avatar_mcap2_17 mx_BaseAvatar _avatar-imageless_mcap2_61"
-          data-color="2"
-          data-testid="avatar-img"
-          data-type="round"
-          role="presentation"
-          style="--cpd-avatar-size: 36px;"
-          title="@userId:matrix.org"
-        >
-          u
-        </span>
-      </div>
-      <div
-        class="mx_EntityTile_details"
-      >
-        <div
-          class="mx_EntityTile_name"
-        >
-          <div
-            class="mx_DisambiguatedProfile"
-          >
-            <span
-              class=""
-              dir="auto"
-            >
-              @userId:matrix.org
-            </span>
-          </div>
-        </div>
-        <div
-          class="mx_PresenceLabel"
-        >
-          Offline
-        </div>
-      </div>
-    </div>
-  </div>
-</div>
-`;
diff --git a/test/unit-tests/components/views/rooms/__snapshots__/RoomHeader-test.tsx.snap b/test/unit-tests/components/views/rooms/__snapshots__/RoomHeader-test.tsx.snap
index a6f412a3acb..3db3fb67fbf 100644
--- a/test/unit-tests/components/views/rooms/__snapshots__/RoomHeader-test.tsx.snap
+++ b/test/unit-tests/components/views/rooms/__snapshots__/RoomHeader-test.tsx.snap
@@ -42,111 +42,106 @@ exports[`RoomHeader dm does not show the face pile for DMs 1`] = `
         </div>
       </div>
     </button>
-    <div
-      class="mx_Flex"
-      style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: var(--cpd-space-2x);"
+    <button
+      aria-labelledby=":r16c:"
+      class="_icon-button_bh2qc_17"
+      role="button"
+      style="--cpd-icon-button-size: 32px;"
+      tabindex="0"
     >
-      <button
-        aria-labelledby=":r16c:"
-        class="_icon-button_bh2qc_17"
-        role="button"
-        style="--cpd-icon-button-size: 32px;"
-        tabindex="0"
+      <div
+        class="_indicator-icon_133tf_26"
+        style="--cpd-icon-button-size: 100%;"
       >
-        <div
-          class="_indicator-icon_133tf_26"
-          style="--cpd-icon-button-size: 100%;"
+        <svg
+          fill="currentColor"
+          height="1em"
+          viewBox="0 0 24 24"
+          width="1em"
+          xmlns="http://www.w3.org/2000/svg"
         >
-          <svg
-            fill="currentColor"
-            height="1em"
-            viewBox="0 0 24 24"
-            width="1em"
-            xmlns="http://www.w3.org/2000/svg"
-          >
-            <path
-              d="M6.293 6.293a1 1 0 0 1 1.414 0L12 10.586l4.293-4.293a1 1 0 1 1 1.414 1.414L13.414 12l4.293 4.293a1 1 0 0 1-1.414 1.414L12 13.414l-4.293 4.293a1 1 0 0 1-1.414-1.414L10.586 12 6.293 7.707a1 1 0 0 1 0-1.414Z"
-            />
-          </svg>
-        </div>
-      </button>
-      <button
-        aria-disabled="true"
-        aria-label="There's no one here to call"
-        aria-labelledby=":r16h:"
-        class="_icon-button_bh2qc_17"
-        role="button"
-        style="--cpd-icon-button-size: 32px;"
-        tabindex="0"
+          <path
+            d="M6.293 6.293a1 1 0 0 1 1.414 0L12 10.586l4.293-4.293a1 1 0 1 1 1.414 1.414L13.414 12l4.293 4.293a1 1 0 0 1-1.414 1.414L12 13.414l-4.293 4.293a1 1 0 0 1-1.414-1.414L10.586 12 6.293 7.707a1 1 0 0 1 0-1.414Z"
+          />
+        </svg>
+      </div>
+    </button>
+    <button
+      aria-disabled="true"
+      aria-label="There's no one here to call"
+      aria-labelledby=":r16h:"
+      class="_icon-button_bh2qc_17"
+      role="button"
+      style="--cpd-icon-button-size: 32px;"
+      tabindex="0"
+    >
+      <div
+        class="_indicator-icon_133tf_26"
+        style="--cpd-icon-button-size: 100%; --cpd-color-icon-tertiary: var(--cpd-color-icon-disabled);"
       >
-        <div
-          class="_indicator-icon_133tf_26"
-          style="--cpd-icon-button-size: 100%; --cpd-color-icon-tertiary: var(--cpd-color-icon-disabled);"
+        <svg
+          fill="currentColor"
+          height="1em"
+          viewBox="0 0 24 24"
+          width="1em"
+          xmlns="http://www.w3.org/2000/svg"
         >
-          <svg
-            fill="currentColor"
-            height="1em"
-            viewBox="0 0 24 24"
-            width="1em"
-            xmlns="http://www.w3.org/2000/svg"
-          >
-            <path
-              d="m20.958 16.374.039 3.527c0 .285-.11.537-.33.756-.22.22-.472.33-.756.33a15.97 15.97 0 0 1-6.57-1.105 16.223 16.223 0 0 1-5.563-3.663 16.084 16.084 0 0 1-3.653-5.573 16.313 16.313 0 0 1-1.115-6.56c0-.285.11-.537.33-.757.22-.22.471-.329.755-.329l3.528.039a1.069 1.069 0 0 1 1.085.93l.543 3.954c.026.181.013.349-.039.504a1.088 1.088 0 0 1-.271.426l-1.64 1.64c.337.672.721 1.308 1.154 1.909.433.6 1.444 1.696 1.444 1.696s1.095 1.01 1.696 1.444c.6.433 1.237.817 1.909 1.153l1.64-1.64a1.08 1.08 0 0 1 .426-.27c.155-.052.323-.065.504-.04l3.954.543a1.069 1.069 0 0 1 .93 1.085Z"
-            />
-          </svg>
-        </div>
-      </button>
-      <button
-        aria-label="Room info"
-        aria-labelledby=":r16m:"
-        class="_icon-button_bh2qc_17"
-        role="button"
-        style="--cpd-icon-button-size: 32px;"
-        tabindex="0"
+          <path
+            d="m20.958 16.374.039 3.527c0 .285-.11.537-.33.756-.22.22-.472.33-.756.33a15.97 15.97 0 0 1-6.57-1.105 16.223 16.223 0 0 1-5.563-3.663 16.084 16.084 0 0 1-3.653-5.573 16.313 16.313 0 0 1-1.115-6.56c0-.285.11-.537.33-.757.22-.22.471-.329.755-.329l3.528.039a1.069 1.069 0 0 1 1.085.93l.543 3.954c.026.181.013.349-.039.504a1.088 1.088 0 0 1-.271.426l-1.64 1.64c.337.672.721 1.308 1.154 1.909.433.6 1.444 1.696 1.444 1.696s1.095 1.01 1.696 1.444c.6.433 1.237.817 1.909 1.153l1.64-1.64a1.08 1.08 0 0 1 .426-.27c.155-.052.323-.065.504-.04l3.954.543a1.069 1.069 0 0 1 .93 1.085Z"
+          />
+        </svg>
+      </div>
+    </button>
+    <button
+      aria-label="Threads"
+      aria-labelledby=":r16m:"
+      class="_icon-button_bh2qc_17"
+      role="button"
+      style="--cpd-icon-button-size: 32px;"
+      tabindex="0"
+    >
+      <div
+        class="_indicator-icon_133tf_26"
+        style="--cpd-icon-button-size: 100%;"
       >
-        <div
-          class="_indicator-icon_133tf_26"
-          style="--cpd-icon-button-size: 100%;"
+        <svg
+          fill="currentColor"
+          height="1em"
+          viewBox="0 0 24 24"
+          width="1em"
+          xmlns="http://www.w3.org/2000/svg"
         >
-          <svg
-            fill="currentColor"
-            height="1em"
-            viewBox="0 0 24 24"
-            width="1em"
-            xmlns="http://www.w3.org/2000/svg"
-          >
-            <path
-              d="M12 17a.97.97 0 0 0 .713-.288A.968.968 0 0 0 13 16v-4a.968.968 0 0 0-.287-.713A.968.968 0 0 0 12 11a.968.968 0 0 0-.713.287A.968.968 0 0 0 11 12v4c0 .283.096.52.287.712.192.192.43.288.713.288Zm0-8c.283 0 .52-.096.713-.287A.967.967 0 0 0 13 8a.967.967 0 0 0-.287-.713A.968.968 0 0 0 12 7a.968.968 0 0 0-.713.287A.967.967 0 0 0 11 8c0 .283.096.52.287.713.192.191.43.287.713.287Zm0 13a9.738 9.738 0 0 1-3.9-.788 10.099 10.099 0 0 1-3.175-2.137c-.9-.9-1.612-1.958-2.137-3.175A9.738 9.738 0 0 1 2 12a9.74 9.74 0 0 1 .788-3.9 10.099 10.099 0 0 1 2.137-3.175c.9-.9 1.958-1.612 3.175-2.137A9.738 9.738 0 0 1 12 2a9.74 9.74 0 0 1 3.9.788 10.098 10.098 0 0 1 3.175 2.137c.9.9 1.613 1.958 2.137 3.175A9.738 9.738 0 0 1 22 12a9.738 9.738 0 0 1-.788 3.9 10.098 10.098 0 0 1-2.137 3.175c-.9.9-1.958 1.613-3.175 2.137A9.738 9.738 0 0 1 12 22Z"
-            />
-          </svg>
-        </div>
-      </button>
-      <button
-        aria-label="Threads"
-        aria-labelledby=":r16r:"
-        class="_icon-button_bh2qc_17"
-        role="button"
-        style="--cpd-icon-button-size: 32px;"
-        tabindex="0"
+          <path
+            d="M4 3h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H6l-2.293 2.293c-.63.63-1.707.184-1.707-.707V5a2 2 0 0 1 2-2Zm3 7h10a.97.97 0 0 0 .712-.287A.967.967 0 0 0 18 9a.967.967 0 0 0-.288-.713A.968.968 0 0 0 17 8H7a.968.968 0 0 0-.713.287A.968.968 0 0 0 6 9c0 .283.096.52.287.713.192.191.43.287.713.287Zm0 4h6c.283 0 .52-.096.713-.287A.968.968 0 0 0 14 13a.968.968 0 0 0-.287-.713A.968.968 0 0 0 13 12H7a.967.967 0 0 0-.713.287A.968.968 0 0 0 6 13c0 .283.096.52.287.713.192.191.43.287.713.287Z"
+          />
+        </svg>
+      </div>
+    </button>
+    <button
+      aria-label="Room info"
+      aria-labelledby=":r16r:"
+      class="_icon-button_bh2qc_17"
+      role="button"
+      style="--cpd-icon-button-size: 32px;"
+      tabindex="0"
+    >
+      <div
+        class="_indicator-icon_133tf_26"
+        style="--cpd-icon-button-size: 100%;"
       >
-        <div
-          class="_indicator-icon_133tf_26"
-          style="--cpd-icon-button-size: 100%;"
+        <svg
+          fill="currentColor"
+          height="1em"
+          viewBox="0 0 24 24"
+          width="1em"
+          xmlns="http://www.w3.org/2000/svg"
         >
-          <svg
-            fill="currentColor"
-            height="1em"
-            viewBox="0 0 24 24"
-            width="1em"
-            xmlns="http://www.w3.org/2000/svg"
-          >
-            <path
-              d="M4 3h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H6l-2.293 2.293c-.63.63-1.707.184-1.707-.707V5a2 2 0 0 1 2-2Zm3 7h10a.97.97 0 0 0 .712-.287A.967.967 0 0 0 18 9a.967.967 0 0 0-.288-.713A.968.968 0 0 0 17 8H7a.968.968 0 0 0-.713.287A.968.968 0 0 0 6 9c0 .283.096.52.287.713.192.191.43.287.713.287Zm0 4h6c.283 0 .52-.096.713-.287A.968.968 0 0 0 14 13a.968.968 0 0 0-.287-.713A.968.968 0 0 0 13 12H7a.967.967 0 0 0-.713.287A.968.968 0 0 0 6 13c0 .283.096.52.287.713.192.191.43.287.713.287Z"
-            />
-          </svg>
-        </div>
-      </button>
-    </div>
+          <path
+            d="M12 17a.97.97 0 0 0 .713-.288A.968.968 0 0 0 13 16v-4a.968.968 0 0 0-.287-.713A.968.968 0 0 0 12 11a.968.968 0 0 0-.713.287A.968.968 0 0 0 11 12v4c0 .283.096.52.287.712.192.192.43.288.713.288Zm0-8c.283 0 .52-.096.713-.287A.967.967 0 0 0 13 8a.967.967 0 0 0-.287-.713A.968.968 0 0 0 12 7a.968.968 0 0 0-.713.287A.967.967 0 0 0 11 8c0 .283.096.52.287.713.192.191.43.287.713.287Zm0 13a9.738 9.738 0 0 1-3.9-.788 10.099 10.099 0 0 1-3.175-2.137c-.9-.9-1.612-1.958-2.137-3.175A9.738 9.738 0 0 1 2 12a9.74 9.74 0 0 1 .788-3.9 10.099 10.099 0 0 1 2.137-3.175c.9-.9 1.958-1.612 3.175-2.137A9.738 9.738 0 0 1 12 2a9.74 9.74 0 0 1 3.9.788 10.098 10.098 0 0 1 3.175 2.137c.9.9 1.613 1.958 2.137 3.175A9.738 9.738 0 0 1 22 12a9.738 9.738 0 0 1-.788 3.9 10.098 10.098 0 0 1-2.137 3.175c-.9.9-1.958 1.613-3.175 2.137A9.738 9.738 0 0 1 12 22Z"
+          />
+        </svg>
+      </div>
+    </button>
   </header>
 </DocumentFragment>
 `;
diff --git a/test/unit-tests/components/views/rooms/memberlist/MemberListHeaderView-test.tsx b/test/unit-tests/components/views/rooms/memberlist/MemberListHeaderView-test.tsx
new file mode 100644
index 00000000000..28d4c105a46
--- /dev/null
+++ b/test/unit-tests/components/views/rooms/memberlist/MemberListHeaderView-test.tsx
@@ -0,0 +1,120 @@
+/*
+Copyright 2024 New Vector Ltd.
+Copyright 2022 The Matrix.org Foundation C.I.C.
+Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+Please see LICENSE files in the repository root for full details.
+*/
+
+import React from "react";
+import { act, fireEvent, screen, waitFor } from "jest-matrix-react";
+import { RoomMember, User, RoomEvent } from "matrix-js-sdk/src/matrix";
+import { KnownMembership } from "matrix-js-sdk/src/types";
+import { mocked } from "jest-mock";
+
+import { shouldShowComponent } from "../../../../../../src/customisations/helpers/UIComponents";
+import defaultDispatcher from "../../../../../../src/dispatcher/dispatcher";
+import { Rendered, renderMemberList } from "./common";
+
+jest.mock("../../../../../../src/customisations/helpers/UIComponents", () => ({
+    shouldShowComponent: jest.fn(),
+}));
+
+type Children = (args: { height: number; width: number }) => React.JSX.Element;
+jest.mock("react-virtualized", () => {
+    const ReactVirtualized = jest.requireActual("react-virtualized");
+    return {
+        ...ReactVirtualized,
+        AutoSizer: ({ children }: { children: Children }) => children({ height: 1000, width: 1000 }),
+    };
+});
+jest.spyOn(HTMLElement.prototype, "offsetHeight", "get").mockReturnValue(1500);
+jest.spyOn(HTMLElement.prototype, "offsetWidth", "get").mockReturnValue(1500);
+
+describe("Does not render invite button in memberlist header", () => {
+    it("when user is not a member", async () => {
+        await renderMemberList(true, (room) => room.updateMyMembership(KnownMembership.Leave));
+        expect(screen.queryByRole("button", { name: "Invite" })).toBeNull();
+    });
+
+    it("when UI customisation hides invites", async () => {
+        mocked(shouldShowComponent).mockReturnValue(false);
+        const { client, memberListRoom } = await renderMemberList(true);
+        // Needs this specific event...
+        act(() => {
+            client.emit(RoomEvent.MyMembership, memberListRoom, KnownMembership.Join, KnownMembership.Invite);
+        });
+        await waitFor(() => expect(screen.queryByRole("button", { name: "Invite" })).toBeNull());
+    });
+});
+
+describe("MemberListHeaderView", () => {
+    let rendered: Rendered;
+
+    beforeEach(async function () {
+        mocked(shouldShowComponent).mockReturnValue(true);
+        rendered = await renderMemberList(true);
+    });
+
+    it("Shows the correct member count", async () => {
+        expect(await screen.findByText("6 Members")).toBeVisible();
+    });
+
+    it("Does not show search box when there's less than 20 members", async () => {
+        expect(screen.queryByPlaceholderText("Filter room members")).toBeNull();
+    });
+
+    it("Shows search box when there's more than 20 members", async () => {
+        const { memberListRoom, client, reRender } = rendered;
+        // Memberlist already has 6 members, add 14 more to make the total 20
+        for (let i = 0; i < 14; ++i) {
+            const newMember = new RoomMember(memberListRoom.roomId, `@new${i}:localhost`);
+            newMember.membership = KnownMembership.Join;
+            newMember.powerLevel = 0;
+            newMember.user = User.createUser(newMember.userId, client);
+            newMember.user.currentlyActive = true;
+            newMember.user.presence = "online";
+            newMember.user.lastPresenceTs = 1000;
+            newMember.user.lastActiveAgo = 10;
+            memberListRoom.currentState.members[newMember.userId] = newMember;
+        }
+        await reRender();
+        expect(screen.queryByPlaceholderText("Filter room members")).toBeVisible();
+    });
+
+    describe("Invite button functionality", () => {
+        afterEach(() => {
+            jest.restoreAllMocks();
+        });
+
+        it("Renders disabled invite button when current user is a member but does not have rights to invite", async () => {
+            const { memberListRoom, reRender } = rendered;
+            jest.spyOn(memberListRoom, "getMyMembership").mockReturnValue(KnownMembership.Join);
+            jest.spyOn(memberListRoom, "canInvite").mockReturnValue(false);
+            await reRender();
+            expect(screen.getByRole("button", { name: "Invite" })).toHaveAttribute("aria-disabled", "true");
+        });
+
+        it("Renders enabled invite button when current user is a member and has rights to invite", async () => {
+            const { memberListRoom, reRender } = rendered;
+            jest.spyOn(memberListRoom, "getMyMembership").mockReturnValue(KnownMembership.Join);
+            jest.spyOn(memberListRoom, "canInvite").mockReturnValue(true);
+            await reRender();
+            expect(screen.getByRole("button", { name: "Invite" })).not.toHaveAttribute("aria-disabled", "true");
+        });
+
+        it("Opens room inviter on button click", async () => {
+            const { memberListRoom, reRender } = rendered;
+            jest.spyOn(defaultDispatcher, "dispatch");
+            jest.spyOn(memberListRoom, "canInvite").mockReturnValue(true);
+            await reRender();
+
+            fireEvent.click(screen.getByRole("button", { name: "Invite" }));
+            expect(defaultDispatcher.dispatch).toHaveBeenCalledWith({
+                action: "view_invite",
+                roomId: memberListRoom.roomId,
+            });
+        });
+    });
+});
diff --git a/test/unit-tests/components/views/rooms/memberlist/MemberListView-test.tsx b/test/unit-tests/components/views/rooms/memberlist/MemberListView-test.tsx
new file mode 100644
index 00000000000..518ed4f690d
--- /dev/null
+++ b/test/unit-tests/components/views/rooms/memberlist/MemberListView-test.tsx
@@ -0,0 +1,255 @@
+/*
+Copyright 2024 New Vector Ltd.
+Copyright 2022 The Matrix.org Foundation C.I.C.
+Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+Please see LICENSE files in the repository root for full details.
+*/
+
+import React, { act } from "react";
+import { waitFor } from "jest-matrix-react";
+import { Room, RoomMember, MatrixEvent } from "matrix-js-sdk/src/matrix";
+
+import { filterConsole } from "../../../../../test-utils";
+import { Rendered, renderMemberList } from "./common";
+
+jest.mock("../../../../../../src/customisations/helpers/UIComponents", () => ({
+    shouldShowComponent: jest.fn(),
+}));
+
+type Children = (args: { height: number; width: number }) => React.JSX.Element;
+jest.mock("react-virtualized", () => {
+    const ReactVirtualized = jest.requireActual("react-virtualized");
+    return {
+        ...ReactVirtualized,
+        AutoSizer: ({ children }: { children: Children }) => children({ height: 1000, width: 1000 }),
+    };
+});
+jest.spyOn(HTMLElement.prototype, "offsetHeight", "get").mockReturnValue(1500);
+jest.spyOn(HTMLElement.prototype, "offsetWidth", "get").mockReturnValue(1500);
+
+describe("MemberListView and MemberlistHeaderView", () => {
+    filterConsole(
+        "Age for event was not available, using `now - origin_server_ts` as a fallback. If the device clock is not correct issues might occur.",
+    );
+
+    function memberString(member: RoomMember): string {
+        if (!member) {
+            return "(null)";
+        } else {
+            const u = member.user;
+            return (
+                "(" +
+                member.name +
+                ", " +
+                member.powerLevel +
+                ", " +
+                (u ? u.lastActiveAgo : "<null>") +
+                ", " +
+                (u ? u.getLastActiveTs() : "<null>") +
+                ", " +
+                (u ? u.currentlyActive : "<null>") +
+                ", " +
+                (u ? u.presence : "<null>") +
+                ")"
+            );
+        }
+    }
+
+    function expectOrderedByPresenceAndPowerLevel(
+        memberListRoom: Room,
+        memberTiles: NodeListOf<Element>,
+        isPresenceEnabled: boolean,
+    ) {
+        let prevMember: RoomMember | undefined;
+        for (const tile of memberTiles) {
+            const memberA = prevMember;
+            const memberB = memberListRoom.currentState.members[tile.getAttribute("aria-label")!.split(" ")[0]];
+            prevMember = memberB; // just in case an expect fails, set this early
+            if (!memberA) {
+                continue;
+            }
+
+            console.log("COMPARING A VS B:", memberString(memberA), memberString(memberB));
+
+            const userA = memberA.user!;
+            const userB = memberB.user!;
+
+            let groupChange = false;
+
+            if (isPresenceEnabled) {
+                const convertPresence = (p: string) => (p === "unavailable" ? "online" : p);
+                const presenceIndex = (p: string) => {
+                    const order = ["active", "online", "offline"];
+                    const idx = order.indexOf(convertPresence(p));
+                    return idx === -1 ? order.length : idx; // unknown states at the end
+                };
+
+                const idxA = presenceIndex(userA.currentlyActive ? "active" : userA.presence);
+                const idxB = presenceIndex(userB.currentlyActive ? "active" : userB.presence);
+                console.log("Comparing presence groups...");
+                expect(idxB).toBeGreaterThanOrEqual(idxA);
+                groupChange = idxA !== idxB;
+            } else {
+                console.log("Skipped presence groups");
+            }
+
+            if (!groupChange) {
+                console.log("Comparing power levels...");
+                expect(memberA.powerLevel).toBeGreaterThanOrEqual(memberB.powerLevel);
+                groupChange = memberA.powerLevel !== memberB.powerLevel;
+            } else {
+                console.log("Skipping power level check due to group change");
+            }
+
+            if (!groupChange) {
+                if (isPresenceEnabled) {
+                    console.log("Comparing last active timestamp...");
+                    expect(userB.getLastActiveTs()).toBeLessThanOrEqual(userA.getLastActiveTs());
+                    groupChange = userA.getLastActiveTs() !== userB.getLastActiveTs();
+                } else {
+                    console.log("Skipping last active timestamp");
+                }
+            } else {
+                console.log("Skipping last active timestamp check due to group change");
+            }
+
+            if (!groupChange) {
+                const nameA = memberA.name[0] === "@" ? memberA.name.slice(1) : memberA.name;
+                const nameB = memberB.name[0] === "@" ? memberB.name.slice(1) : memberB.name;
+                const collator = new Intl.Collator();
+                const nameCompare = collator.compare(nameB, nameA);
+                console.log("Comparing name");
+                expect(nameCompare).toBeGreaterThanOrEqual(0);
+            } else {
+                console.log("Skipping name check due to group change");
+            }
+        }
+    }
+
+    describe("MemberListView", () => {
+        let rendered: Rendered;
+
+        beforeEach(async function () {
+            rendered = await renderMemberList(true);
+        });
+
+        it("Memberlist is re-rendered on unreachable presence event", async () => {
+            const { root, defaultUsers } = rendered;
+            await act(async () => {
+                defaultUsers[0].user?.setPresenceEvent(
+                    new MatrixEvent({
+                        type: "m.presence",
+                        sender: defaultUsers[0].userId,
+                        content: {
+                            presence: "io.element.unreachable",
+                            currently_active: false,
+                        },
+                    }),
+                );
+            });
+            await waitFor(() => {
+                expect(root.container.querySelector(".mx_PresenceIconView_unavailable")).not.toBeNull();
+            });
+        });
+    });
+
+    describe.each([true, false])("does order members correctly (presence %s)", (enablePresence) => {
+        let rendered: Rendered;
+
+        beforeEach(async function () {
+            rendered = await renderMemberList(enablePresence);
+        });
+
+        describe("does order members correctly", () => {
+            // Note: even if presence is disabled, we still expect that the presence
+            // tests will pass. All expectOrderedByPresenceAndPowerLevel does is ensure
+            // the order is perceived correctly, regardless of what we did to the members.
+
+            // Each of the 4 tests here is done to prove that the member list can meet
+            // all 4 criteria independently. Together, they should work.
+
+            it("by presence state", async () => {
+                const { adminUsers, defaultUsers, moderatorUsers, reRender, root, memberListRoom } = rendered;
+                // Intentionally pick users that will confuse the power level sorting
+                const activeUsers = [defaultUsers[0]];
+                const onlineUsers = [adminUsers[0]];
+                const offlineUsers = [...moderatorUsers, ...adminUsers.slice(1), ...defaultUsers.slice(1)];
+                activeUsers.forEach((u) => {
+                    u.user!.currentlyActive = true;
+                    u.user!.presence = "online";
+                });
+                onlineUsers.forEach((u) => {
+                    u.user!.currentlyActive = false;
+                    u.user!.presence = "online";
+                });
+                offlineUsers.forEach((u) => {
+                    u.user!.currentlyActive = false;
+                    u.user!.presence = "offline";
+                });
+
+                await reRender();
+
+                const tiles = root.container.querySelectorAll(".mx_MemberTileView");
+                expectOrderedByPresenceAndPowerLevel(memberListRoom, tiles, enablePresence);
+            });
+
+            it("by power level", async () => {
+                const { reRender, root, memberListRoom } = rendered;
+                // We already have admin, moderator, and default users so leave them alone
+
+                await reRender();
+
+                const tiles = root.container.querySelectorAll(".mx_EntityTile");
+                expectOrderedByPresenceAndPowerLevel(memberListRoom, tiles, enablePresence);
+            });
+
+            it("by last active timestamp", async () => {
+                const { adminUsers, defaultUsers, moderatorUsers, reRender, root, memberListRoom } = rendered;
+                // Intentionally pick users that will confuse the power level sorting
+                const activeUsers = [defaultUsers[0]];
+                const semiActiveUsers = [adminUsers[0]];
+                const inactiveUsers = [...moderatorUsers, ...adminUsers.slice(1), ...defaultUsers.slice(1)];
+                activeUsers.forEach((u) => {
+                    u.powerLevel = 100; // set everyone to the same PL to avoid running that check
+                    u.user!.lastPresenceTs = 1000;
+                    u.user!.lastActiveAgo = 0;
+                });
+                semiActiveUsers.forEach((u) => {
+                    u.powerLevel = 100;
+                    u.user!.lastPresenceTs = 1000;
+                    u.user!.lastActiveAgo = 50;
+                });
+                inactiveUsers.forEach((u) => {
+                    u.powerLevel = 100;
+                    u.user!.lastPresenceTs = 1000;
+                    u.user!.lastActiveAgo = 100;
+                });
+
+                await reRender();
+
+                const tiles = root.container.querySelectorAll(".mx_EntityTile");
+                expectOrderedByPresenceAndPowerLevel(memberListRoom, tiles, enablePresence);
+            });
+
+            it("by name", async () => {
+                const { adminUsers, defaultUsers, moderatorUsers, reRender, root, memberListRoom } = rendered;
+                // Intentionally put everyone on the same level to force a name comparison
+                const allUsers = [...adminUsers, ...moderatorUsers, ...defaultUsers];
+                allUsers.forEach((u) => {
+                    u.user!.currentlyActive = true;
+                    u.user!.presence = "online";
+                    u.user!.lastPresenceTs = 1000;
+                    u.user!.lastActiveAgo = 0;
+                    u.powerLevel = 100;
+                });
+
+                await reRender();
+
+                const tiles = root.container.querySelectorAll(".mx_EntityTile");
+                expectOrderedByPresenceAndPowerLevel(memberListRoom, tiles, enablePresence);
+            });
+        });
+    });
+});
diff --git a/test/unit-tests/components/views/rooms/memberlist/MemberTileView-test.tsx b/test/unit-tests/components/views/rooms/memberlist/MemberTileView-test.tsx
new file mode 100644
index 00000000000..284483a8397
--- /dev/null
+++ b/test/unit-tests/components/views/rooms/memberlist/MemberTileView-test.tsx
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2024 New Vector Ltd.
+ * Copyright 2023 The Matrix.org Foundation C.I.C.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+import React from "react";
+import { render, screen, waitFor } from "jest-matrix-react";
+import { MatrixClient, RoomMember as SdkRoomMember, Device, Room } from "matrix-js-sdk/src/matrix";
+import { UserVerificationStatus, DeviceVerificationStatus } from "matrix-js-sdk/src/crypto-api";
+import { mocked } from "jest-mock";
+import userEvent from "@testing-library/user-event";
+
+import * as TestUtils from "../../../../../test-utils";
+import { RoomMember } from "../../../../../../src/models/rooms/RoomMember";
+import {
+    getPending3PidInvites,
+    sdkRoomMemberToRoomMember,
+} from "../../../../../../src/components/viewmodels/memberlist/MemberListViewModel";
+import { RoomMemberTileView } from "../../../../../../src/components/views/rooms/MemberList/tiles/RoomMemberTileView";
+import { ThreePidInviteTileView } from "../../../../../../src/components/views/rooms/MemberList/tiles/ThreePidInviteTileView";
+
+describe("MemberTileView", () => {
+    describe("RoomMemberTileView", () => {
+        let matrixClient: MatrixClient;
+        let member: RoomMember;
+
+        beforeEach(() => {
+            matrixClient = TestUtils.stubClient();
+            mocked(matrixClient.isRoomEncrypted).mockReturnValue(true);
+            const sdkMember = new SdkRoomMember("roomId", matrixClient.getUserId()!);
+            member = sdkRoomMemberToRoomMember(sdkMember)!.member!;
+        });
+
+        it("should not display an E2EIcon when the e2E status = normal", () => {
+            const { container } = render(<RoomMemberTileView member={member} />);
+            const e2eIcon = container.querySelector(".mx_E2EIconView");
+            expect(e2eIcon).toBeNull();
+            expect(container).toMatchSnapshot();
+        });
+
+        it("should display an warning E2EIcon when the e2E status = Warning", async () => {
+            mocked(matrixClient.getCrypto()!.getUserVerificationStatus).mockResolvedValue({
+                isCrossSigningVerified: jest.fn().mockReturnValue(false),
+                wasCrossSigningVerified: jest.fn().mockReturnValue(true),
+            } as unknown as UserVerificationStatus);
+
+            const { container } = render(<RoomMemberTileView member={member} />);
+            await waitFor(async () => {
+                await userEvent.hover(container.querySelector(".mx_E2EIcon")!);
+                expect(screen.getByText("This user has not verified all of their sessions.")).toBeInTheDocument();
+            });
+            expect(container).toMatchSnapshot();
+        });
+
+        it("should display an verified E2EIcon when the e2E status = Verified", async () => {
+            // Mock all the required crypto methods
+            const deviceMap = new Map<string, Map<string, Device>>();
+            deviceMap.set(member.userId, new Map([["deviceId", {} as Device]]));
+            // Return a DeviceMap = Map<string, Map<string, Device>>
+            mocked(matrixClient.getCrypto()!.getUserDeviceInfo).mockResolvedValue(deviceMap);
+            mocked(matrixClient.getCrypto()!.getUserVerificationStatus).mockResolvedValue({
+                isCrossSigningVerified: jest.fn().mockReturnValue(true),
+            } as unknown as UserVerificationStatus);
+            mocked(matrixClient.getCrypto()!.getDeviceVerificationStatus).mockResolvedValue({
+                crossSigningVerified: true,
+            } as DeviceVerificationStatus);
+
+            const { container } = render(<RoomMemberTileView member={member} />);
+
+            await waitFor(async () => {
+                await userEvent.hover(container.querySelector(".mx_E2EIcon")!);
+                expect(
+                    screen.getByText("You have verified this user. This user has verified all of their sessions."),
+                ).toBeInTheDocument();
+            });
+            expect(container).toMatchSnapshot();
+        });
+
+        it("renders user labels correctly", async () => {
+            member.powerLevel = 50;
+            const { container: container1 } = render(<RoomMemberTileView member={member} />);
+            expect(container1).toHaveTextContent("Moderator");
+
+            member.powerLevel = 100;
+            const { container: container2 } = render(<RoomMemberTileView member={member} />);
+            expect(container2).toHaveTextContent("Admin");
+
+            member.isInvite = true;
+            const { container: container3 } = render(<RoomMemberTileView member={member} />);
+            expect(container3).toHaveTextContent("Invited");
+        });
+    });
+
+    describe("ThreePidInviteTileView", () => {
+        let cli: MatrixClient;
+        let room: Room;
+
+        beforeEach(() => {
+            cli = TestUtils.stubClient();
+            room = new Room("!mytestroom:foo.org", cli, cli.getSafeUserId());
+            room.getLiveTimeline().addEvent(
+                TestUtils.mkThirdPartyInviteEvent(cli.getSafeUserId(), "Foobar", room.roomId),
+                { toStartOfTimeline: false, addToState: true },
+            );
+        });
+
+        it("renders ThreePidInvite correctly", async () => {
+            const [{ threePidInvite }] = getPending3PidInvites(room);
+            const { container } = render(<ThreePidInviteTileView threePidInvite={threePidInvite!} />);
+            expect(container).toMatchSnapshot();
+        });
+    });
+});
diff --git a/test/unit-tests/components/views/rooms/memberlist/PresenceIconView-test.tsx b/test/unit-tests/components/views/rooms/memberlist/PresenceIconView-test.tsx
new file mode 100644
index 00000000000..74c23f2199e
--- /dev/null
+++ b/test/unit-tests/components/views/rooms/memberlist/PresenceIconView-test.tsx
@@ -0,0 +1,42 @@
+/*
+Copyright 2024 New Vector Ltd.
+Copyright 2023 The Matrix.org Foundation C.I.C.
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+Please see LICENSE files in the repository root for full details.
+*/
+
+import React from "react";
+import { render } from "jest-matrix-react";
+
+import AvatarPresenceIconView from "../../../../../../src/components/views/rooms/MemberList/tiles/common/PresenceIconView";
+
+describe("<PresenceIconView/>", () => {
+    it("renders correctly for presence=online", () => {
+        const { container } = render(<AvatarPresenceIconView presenceState="online" />);
+        expect(container.querySelector(".mx_PresenceIconView_online")).toBeDefined();
+        expect(container).toMatchSnapshot();
+    });
+
+    it("renders correctly for presence=offline", () => {
+        const { container } = render(<AvatarPresenceIconView presenceState="offline" />);
+        expect(container.querySelector(".mx_PresenceIconView_offline")).toBeDefined();
+        expect(container).toMatchSnapshot();
+    });
+
+    it("renders correctly for presence=unavailable/unreachable", () => {
+        const { container: container1 } = render(<AvatarPresenceIconView presenceState="unavailable" />);
+        expect(container1.querySelector(".mx_PresenceIconView_unavailable")).toBeDefined();
+        expect(container1).toMatchSnapshot();
+
+        const { container: container2 } = render(<AvatarPresenceIconView presenceState="io.element.unreachable" />);
+        expect(container2.querySelector(".mx_PresenceIconView_unavailable")).toBeDefined();
+        expect(container2).toMatchSnapshot();
+    });
+
+    it("renders correctly for presence=busy", () => {
+        const { container } = render(<AvatarPresenceIconView presenceState="busy" />);
+        expect(container.querySelector(".mx_PresenceIconView_dnd")).toBeDefined();
+        expect(container).toMatchSnapshot();
+    });
+});
diff --git a/test/unit-tests/components/views/rooms/memberlist/__snapshots__/MemberTileView-test.tsx.snap b/test/unit-tests/components/views/rooms/memberlist/__snapshots__/MemberTileView-test.tsx.snap
new file mode 100644
index 00000000000..6feb72ea62d
--- /dev/null
+++ b/test/unit-tests/components/views/rooms/memberlist/__snapshots__/MemberTileView-test.tsx.snap
@@ -0,0 +1,231 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`MemberTileView RoomMemberTileView should display an verified E2EIcon when the e2E status = Verified 1`] = `
+<div>
+  <div>
+    <div
+      aria-label="@userId:matrix.org (power 0)"
+      class="mx_AccessibleButton mx_MemberTileView"
+      role="button"
+      tabindex="0"
+    >
+      <div
+        class="mx_MemberTileView_left"
+      >
+        <div
+          class="mx_MemberTileView_avatar"
+        >
+          <span
+            class="_avatar_mcap2_17 mx_BaseAvatar _avatar-imageless_mcap2_61"
+            data-color="2"
+            data-testid="avatar-img"
+            data-type="round"
+            role="presentation"
+            style="--cpd-avatar-size: 32px;"
+            title="@userId:matrix.org"
+          >
+            u
+          </span>
+           
+        </div>
+        <div
+          class="mx_MemberTileView_name"
+        >
+          <div
+            class="mx_DisambiguatedProfile"
+          >
+            <span
+              class=""
+              dir="auto"
+            >
+              @userId:matrix.org
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="mx_MemberTileView_right"
+      >
+        <div
+          aria-labelledby=":ri:"
+          class="mx_E2EIconView"
+        >
+          <svg
+            class="mx_E2EIconView_verified"
+            fill="currentColor"
+            height="16px"
+            viewBox="0 0 24 24"
+            width="16px"
+            xmlns="http://www.w3.org/2000/svg"
+          >
+            <path
+              d="M8.15 21.75 6.7 19.3l-2.75-.6a.943.943 0 0 1-.6-.387.928.928 0 0 1-.175-.688L3.45 14.8l-1.875-2.15a.934.934 0 0 1-.25-.65c0-.25.083-.467.25-.65L3.45 9.2l-.275-2.825a.928.928 0 0 1 .175-.688.943.943 0 0 1 .6-.387l2.75-.6 1.45-2.45a.983.983 0 0 1 .55-.438.97.97 0 0 1 .7.038l2.6 1.1 2.6-1.1a.97.97 0 0 1 .7-.038.983.983 0 0 1 .55.438L17.3 4.7l2.75.6c.25.05.45.18.6.388.15.208.208.437.175.687L20.55 9.2l1.875 2.15c.167.183.25.4.25.65s-.083.467-.25.65L20.55 14.8l.275 2.825a.928.928 0 0 1-.175.688.943.943 0 0 1-.6.387l-2.75.6-1.45 2.45a.983.983 0 0 1-.55.438.97.97 0 0 1-.7-.038l-2.6-1.1-2.6 1.1a.97.97 0 0 1-.7.038.983.983 0 0 1-.55-.438Zm2.8-9.05L9.5 11.275A.933.933 0 0 0 8.813 11c-.275 0-.513.1-.713.3a.948.948 0 0 0-.275.7.95.95 0 0 0 .275.7l2.15 2.15c.2.2.433.3.7.3.267 0 .5-.1.7-.3l4.25-4.25c.2-.2.296-.433.287-.7a1.055 1.055 0 0 0-.287-.7 1.02 1.02 0 0 0-.713-.313.93.93 0 0 0-.712.288L10.95 12.7Z"
+            />
+          </svg>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>
+`;
+
+exports[`MemberTileView RoomMemberTileView should display an warning E2EIcon when the e2E status = Warning 1`] = `
+<div>
+  <div>
+    <div
+      aria-label="@userId:matrix.org (power 0)"
+      class="mx_AccessibleButton mx_MemberTileView"
+      role="button"
+      tabindex="0"
+    >
+      <div
+        class="mx_MemberTileView_left"
+      >
+        <div
+          class="mx_MemberTileView_avatar"
+        >
+          <span
+            class="_avatar_mcap2_17 mx_BaseAvatar _avatar-imageless_mcap2_61"
+            data-color="2"
+            data-testid="avatar-img"
+            data-type="round"
+            role="presentation"
+            style="--cpd-avatar-size: 32px;"
+            title="@userId:matrix.org"
+          >
+            u
+          </span>
+           
+        </div>
+        <div
+          class="mx_MemberTileView_name"
+        >
+          <div
+            class="mx_DisambiguatedProfile"
+          >
+            <span
+              class=""
+              dir="auto"
+            >
+              @userId:matrix.org
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="mx_MemberTileView_right"
+      >
+        <div
+          aria-labelledby=":r8:"
+          class="mx_E2EIconView"
+        >
+          <svg
+            class="mx_E2EIconView_warning"
+            fill="currentColor"
+            height="16px"
+            viewBox="0 0 24 24"
+            width="16px"
+            xmlns="http://www.w3.org/2000/svg"
+          >
+            <path
+              d="M12 17a.97.97 0 0 0 .713-.288A.968.968 0 0 0 13 16a.968.968 0 0 0-.287-.713A.968.968 0 0 0 12 15a.968.968 0 0 0-.713.287A.968.968 0 0 0 11 16c0 .283.096.52.287.712.192.192.43.288.713.288Zm0-4c.283 0 .52-.096.713-.287A.968.968 0 0 0 13 12V8a.967.967 0 0 0-.287-.713A.968.968 0 0 0 12 7a.968.968 0 0 0-.713.287A.967.967 0 0 0 11 8v4c0 .283.096.52.287.713.192.191.43.287.713.287Zm0 9a9.738 9.738 0 0 1-3.9-.788 10.099 10.099 0 0 1-3.175-2.137c-.9-.9-1.612-1.958-2.137-3.175A9.738 9.738 0 0 1 2 12a9.74 9.74 0 0 1 .788-3.9 10.099 10.099 0 0 1 2.137-3.175c.9-.9 1.958-1.612 3.175-2.137A9.738 9.738 0 0 1 12 2a9.74 9.74 0 0 1 3.9.788 10.098 10.098 0 0 1 3.175 2.137c.9.9 1.613 1.958 2.137 3.175A9.738 9.738 0 0 1 22 12a9.738 9.738 0 0 1-.788 3.9 10.098 10.098 0 0 1-2.137 3.175c-.9.9-1.958 1.613-3.175 2.137A9.738 9.738 0 0 1 12 22Z"
+            />
+          </svg>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>
+`;
+
+exports[`MemberTileView RoomMemberTileView should not display an E2EIcon when the e2E status = normal 1`] = `
+<div>
+  <div>
+    <div
+      aria-label="@userId:matrix.org (power 0)"
+      class="mx_AccessibleButton mx_MemberTileView"
+      role="button"
+      tabindex="0"
+    >
+      <div
+        class="mx_MemberTileView_left"
+      >
+        <div
+          class="mx_MemberTileView_avatar"
+        >
+          <span
+            class="_avatar_mcap2_17 mx_BaseAvatar _avatar-imageless_mcap2_61"
+            data-color="2"
+            data-testid="avatar-img"
+            data-type="round"
+            role="presentation"
+            style="--cpd-avatar-size: 32px;"
+            title="@userId:matrix.org"
+          >
+            u
+          </span>
+           
+        </div>
+        <div
+          class="mx_MemberTileView_name"
+        >
+          <div
+            class="mx_DisambiguatedProfile"
+          >
+            <span
+              class=""
+              dir="auto"
+            >
+              @userId:matrix.org
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="mx_MemberTileView_right"
+      />
+    </div>
+  </div>
+</div>
+`;
+
+exports[`MemberTileView ThreePidInviteTileView renders ThreePidInvite correctly 1`] = `
+<div>
+  <div>
+    <div
+      class="mx_AccessibleButton mx_MemberTileView"
+      role="button"
+      tabindex="0"
+    >
+      <div
+        class="mx_MemberTileView_left"
+      >
+        <div
+          class="mx_MemberTileView_avatar"
+        >
+          <span
+            aria-hidden="true"
+            class="_avatar_mcap2_17 mx_BaseAvatar _avatar-imageless_mcap2_61"
+            data-color="1"
+            data-testid="avatar-img"
+            data-type="round"
+            role="presentation"
+            style="--cpd-avatar-size: 32px;"
+          >
+            F
+          </span>
+           
+        </div>
+        <div
+          class="mx_MemberTileView_name"
+        >
+          Foobar
+        </div>
+      </div>
+      <div
+        class="mx_MemberTileView_right"
+      />
+    </div>
+  </div>
+</div>
+`;
diff --git a/test/unit-tests/components/views/rooms/memberlist/__snapshots__/PresenceIconView-test.tsx.snap b/test/unit-tests/components/views/rooms/memberlist/__snapshots__/PresenceIconView-test.tsx.snap
new file mode 100644
index 00000000000..edf24f529ea
--- /dev/null
+++ b/test/unit-tests/components/views/rooms/memberlist/__snapshots__/PresenceIconView-test.tsx.snap
@@ -0,0 +1,175 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`<PresenceIconView/> renders correctly for presence=busy 1`] = `
+<div>
+  <div
+    class="mx_PresenceIconView"
+  >
+    <svg
+      class="mx_PresenceIconView_dnd"
+      fill="currentColor"
+      height="8px"
+      viewBox="0 0 8 8"
+      width="8px"
+      xmlns="http://www.w3.org/2000/svg"
+    >
+      <g
+        clip-path="url(#a)"
+      >
+        <path
+          clip-rule="evenodd"
+          d="M8 4a4 4 0 1 1-8 0 4 4 0 0 1 8 0ZM5.435 6.048A2.5 2.5 0 0 1 1.687 3.05l3.748 2.998Zm.914-1.19L2.648 1.897a2.5 2.5 0 0 1 3.701 2.961Z"
+          fill-rule="evenodd"
+        />
+      </g>
+      <defs>
+        <clippath
+          id="a"
+        >
+          <path
+            d="M0 0h8v8H0z"
+          />
+        </clippath>
+      </defs>
+    </svg>
+  </div>
+</div>
+`;
+
+exports[`<PresenceIconView/> renders correctly for presence=offline 1`] = `
+<div>
+  <div
+    class="mx_PresenceIconView"
+  >
+    <svg
+      class="mx_PresenceIconView_offline"
+      fill="currentColor"
+      height="8px"
+      viewBox="0 0 8 8"
+      width="8px"
+      xmlns="http://www.w3.org/2000/svg"
+    >
+      <g
+        clip-path="url(#a)"
+      >
+        <path
+          clip-rule="evenodd"
+          d="M4 6.5a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5ZM4 8a4 4 0 1 0 0-8 4 4 0 0 0 0 8Z"
+          fill-rule="evenodd"
+        />
+      </g>
+      <defs>
+        <clippath
+          id="a"
+        >
+          <path
+            d="M0 0h8v8H0z"
+          />
+        </clippath>
+      </defs>
+    </svg>
+  </div>
+</div>
+`;
+
+exports[`<PresenceIconView/> renders correctly for presence=online 1`] = `
+<div>
+  <div
+    class="mx_PresenceIconView"
+  >
+    <svg
+      class="mx_PresenceIconView_online"
+      fill="currentColor"
+      height="8px"
+      viewBox="0 0 8 8"
+      width="8px"
+      xmlns="http://www.w3.org/2000/svg"
+    >
+      <g
+        clip-path="url(#a)"
+      >
+        <path
+          d="M8 4a4 4 0 1 1-8 0 4 4 0 0 1 8 0Z"
+        />
+      </g>
+      <defs>
+        <clippath
+          id="a"
+        >
+          <path
+            d="M0 0h8v8H0z"
+          />
+        </clippath>
+      </defs>
+    </svg>
+  </div>
+</div>
+`;
+
+exports[`<PresenceIconView/> renders correctly for presence=unavailable/unreachable 1`] = `
+<div>
+  <div
+    class="mx_PresenceIconView"
+  >
+    <svg
+      class="mx_PresenceIconView_unavailable"
+      fill="currentColor"
+      height="8px"
+      viewBox="0 0 8 8"
+      width="8px"
+      xmlns="http://www.w3.org/2000/svg"
+    >
+      <g
+        clip-path="url(#a)"
+      >
+        <path
+          d="M8 4a4 4 0 1 1-8 0 4 4 0 0 1 8 0Z"
+        />
+      </g>
+      <defs>
+        <clippath
+          id="a"
+        >
+          <path
+            d="M0 0h8v8H0z"
+          />
+        </clippath>
+      </defs>
+    </svg>
+  </div>
+</div>
+`;
+
+exports[`<PresenceIconView/> renders correctly for presence=unavailable/unreachable 2`] = `
+<div>
+  <div
+    class="mx_PresenceIconView"
+  >
+    <svg
+      class="mx_PresenceIconView_unavailable"
+      fill="currentColor"
+      height="8px"
+      viewBox="0 0 8 8"
+      width="8px"
+      xmlns="http://www.w3.org/2000/svg"
+    >
+      <g
+        clip-path="url(#a)"
+      >
+        <path
+          d="M8 4a4 4 0 1 1-8 0 4 4 0 0 1 8 0Z"
+        />
+      </g>
+      <defs>
+        <clippath
+          id="a"
+        >
+          <path
+            d="M0 0h8v8H0z"
+          />
+        </clippath>
+      </defs>
+    </svg>
+  </div>
+</div>
+`;
diff --git a/test/unit-tests/components/views/rooms/memberlist/common.tsx b/test/unit-tests/components/views/rooms/memberlist/common.tsx
new file mode 100644
index 00000000000..2d602356a7c
--- /dev/null
+++ b/test/unit-tests/components/views/rooms/memberlist/common.tsx
@@ -0,0 +1,146 @@
+/*
+Copyright 2024 New Vector Ltd.
+Copyright 2022 The Matrix.org Foundation C.I.C.
+Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+Please see LICENSE files in the repository root for full details.
+*/
+
+import React, { act } from "react";
+import { render, RenderResult, waitFor } from "jest-matrix-react";
+import { Room, MatrixClient, RoomState, RoomMember, User, EventType, RoomStateEvent } from "matrix-js-sdk/src/matrix";
+import { KnownMembership } from "matrix-js-sdk/src/types";
+
+import { MatrixClientPeg } from "../../../../../../src/MatrixClientPeg";
+import * as TestUtils from "../../../../../test-utils";
+import { SDKContext } from "../../../../../../src/contexts/SDKContext";
+import { TestSdkContext } from "../../../../TestSdkContext";
+import MemberListView from "../../../../../../src/components/views/rooms/MemberList/MemberListView";
+import MatrixClientContext from "../../../../../../src/contexts/MatrixClientContext";
+
+export function createRoom(client: MatrixClient, opts = {}) {
+    const roomId = "!" + Math.random().toString().slice(2, 10) + ":domain";
+    const room = new Room(roomId, client, client.getUserId()!);
+    room.updateMyMembership(KnownMembership.Join);
+    if (opts) {
+        Object.assign(room, opts);
+    }
+    return room;
+}
+
+export type Rendered = {
+    client: MatrixClient;
+    root: RenderResult;
+    memberListRoom: Room;
+    adminUsers: RoomMember[];
+    moderatorUsers: RoomMember[];
+    defaultUsers: RoomMember[];
+    reRender: () => Promise<void>;
+};
+
+export async function renderMemberList(
+    enablePresence: boolean,
+    roomSetup?: (room: Room) => void,
+    usersPerLevel: number = 2,
+): Promise<Rendered> {
+    TestUtils.stubClient();
+    const client = MatrixClientPeg.safeGet();
+    client.hasLazyLoadMembersEnabled = () => false;
+
+    // Make room
+    const memberListRoom = createRoom(client);
+    expect(memberListRoom.roomId).toBeTruthy();
+
+    // Give the test an opportunity to make changes to room before first render
+    roomSetup?.(memberListRoom);
+
+    // Make users
+    const adminUsers = [];
+    const moderatorUsers = [];
+    const defaultUsers = [];
+    for (let i = 0; i < usersPerLevel; i++) {
+        const adminUser = new RoomMember(memberListRoom.roomId, `@admin${i}:localhost`);
+        adminUser.membership = KnownMembership.Join;
+        adminUser.powerLevel = 100;
+        adminUser.user = User.createUser(adminUser.userId, client);
+        adminUser.user.currentlyActive = true;
+        adminUser.user.presence = "online";
+        adminUser.user.lastPresenceTs = 1000;
+        adminUser.user.lastActiveAgo = 10;
+        adminUsers.push(adminUser);
+
+        const moderatorUser = new RoomMember(memberListRoom.roomId, `@moderator${i}:localhost`);
+        moderatorUser.membership = KnownMembership.Join;
+        moderatorUser.powerLevel = 50;
+        moderatorUser.user = User.createUser(moderatorUser.userId, client);
+        moderatorUser.user.currentlyActive = true;
+        moderatorUser.user.presence = "online";
+        moderatorUser.user.lastPresenceTs = 1000;
+        moderatorUser.user.lastActiveAgo = 10;
+        moderatorUsers.push(moderatorUser);
+
+        const defaultUser = new RoomMember(memberListRoom.roomId, `@default${i}:localhost`);
+        defaultUser.membership = KnownMembership.Join;
+        defaultUser.powerLevel = 0;
+        defaultUser.user = User.createUser(defaultUser.userId, client);
+        defaultUser.user.currentlyActive = true;
+        defaultUser.user.presence = "online";
+        defaultUser.user.lastPresenceTs = 1000;
+        defaultUser.user.lastActiveAgo = 10;
+        defaultUsers.push(defaultUser);
+    }
+
+    client.getRoom = (roomId) => {
+        if (roomId === memberListRoom.roomId) return memberListRoom;
+        else return null;
+    };
+    memberListRoom.currentState = {
+        members: {},
+        getMember: jest.fn(),
+        getStateEvents: ((eventType, stateKey) => (stateKey === undefined ? [] : null)) as RoomState["getStateEvents"], // ignore 3pid invites
+    } as unknown as RoomState;
+    for (const member of [...adminUsers, ...moderatorUsers, ...defaultUsers]) {
+        memberListRoom.currentState.members[member.userId] = member;
+    }
+
+    const context = new TestSdkContext();
+    context.client = client;
+    context.memberListStore.isPresenceEnabled = jest.fn().mockReturnValue(enablePresence);
+    const root = render(
+        <MatrixClientContext.Provider value={client}>
+            <SDKContext.Provider value={context}>
+                <MemberListView roomId={memberListRoom.roomId} onClose={() => {}} />
+            </SDKContext.Provider>
+        </MatrixClientContext.Provider>,
+    );
+    await waitFor(async () => {
+        expect(root.container.querySelectorAll(".mx_MemberTileView")).toHaveLength(usersPerLevel * 3);
+    });
+
+    const reRender = createReRenderFunction(client, memberListRoom);
+
+    return {
+        client,
+        root,
+        memberListRoom,
+        adminUsers,
+        moderatorUsers,
+        defaultUsers,
+        reRender,
+    };
+}
+
+function createReRenderFunction(client: MatrixClient, memberListRoom: Room): Rendered["reRender"] {
+    return async function (): Promise<void> {
+        await act(async () => {
+            //@ts-ignore
+            client.emit(RoomStateEvent.Events, {
+                //@ts-ignore
+                getType: () => EventType.RoomThirdPartyInvite,
+                getRoomId: () => memberListRoom.roomId,
+            });
+        });
+        await new Promise((r) => setTimeout(r, 1000));
+    };
+}
diff --git a/test/unit-tests/components/views/rooms/wysiwyg_composer/EditWysiwygComposer-test.tsx b/test/unit-tests/components/views/rooms/wysiwyg_composer/EditWysiwygComposer-test.tsx
index a76c7a8b909..05c7bc4608f 100644
--- a/test/unit-tests/components/views/rooms/wysiwyg_composer/EditWysiwygComposer-test.tsx
+++ b/test/unit-tests/components/views/rooms/wysiwyg_composer/EditWysiwygComposer-test.tsx
@@ -2,13 +2,14 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 import "@testing-library/jest-dom";
 import React from "react";
 import { fireEvent, render, screen, waitFor } from "jest-matrix-react";
+import { initOnce } from "@vector-im/matrix-wysiwyg";
 
 import MatrixClientContext from "../../../../../../src/contexts/MatrixClientContext";
 import defaultDispatcher from "../../../../../../src/dispatcher/dispatcher";
@@ -24,6 +25,8 @@ import * as EmojiButton from "../../../../../../src/components/views/rooms/Emoji
 import { createMocks } from "./utils";
 import { ScopedRoomContextProvider } from "../../../../../../src/contexts/ScopedRoomContext.tsx";
 
+beforeAll(initOnce, 10000);
+
 describe("EditWysiwygComposer", () => {
     afterEach(() => {
         jest.resetAllMocks();
@@ -46,17 +49,6 @@ describe("EditWysiwygComposer", () => {
         );
     };
 
-    beforeAll(
-        async () => {
-            // Load the dynamic import
-            const component = customRender(false);
-            await component.findByRole("textbox");
-            component.unmount();
-        },
-        // it can take a while to load the wasm
-        20000,
-    );
-
     it("Should not render the component when not ready", async () => {
         // When
         const { rerender } = customRender(false);
diff --git a/test/unit-tests/components/views/rooms/wysiwyg_composer/SendWysiwygComposer-test.tsx b/test/unit-tests/components/views/rooms/wysiwyg_composer/SendWysiwygComposer-test.tsx
index 89415448b7b..4cba44bd9c0 100644
--- a/test/unit-tests/components/views/rooms/wysiwyg_composer/SendWysiwygComposer-test.tsx
+++ b/test/unit-tests/components/views/rooms/wysiwyg_composer/SendWysiwygComposer-test.tsx
@@ -2,13 +2,14 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 import "@testing-library/jest-dom";
 import React from "react";
 import { act, fireEvent, render, screen, waitFor } from "jest-matrix-react";
+import { initOnce } from "@vector-im/matrix-wysiwyg";
 
 import MatrixClientContext from "../../../../../../src/contexts/MatrixClientContext";
 import defaultDispatcher from "../../../../../../src/dispatcher/dispatcher";
@@ -31,6 +32,8 @@ jest.mock("../../../../../../src/components/views/rooms/EmojiButton", () => ({
     },
 }));
 
+beforeAll(initOnce, 10000);
+
 describe("SendWysiwygComposer", () => {
     afterEach(() => {
         jest.resetAllMocks();
diff --git a/test/unit-tests/components/views/rooms/wysiwyg_composer/components/FormattingButtons-test.tsx b/test/unit-tests/components/views/rooms/wysiwyg_composer/components/FormattingButtons-test.tsx
index f8e6427ea53..e0f9e2d8b4b 100644
--- a/test/unit-tests/components/views/rooms/wysiwyg_composer/components/FormattingButtons-test.tsx
+++ b/test/unit-tests/components/views/rooms/wysiwyg_composer/components/FormattingButtons-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/rooms/wysiwyg_composer/components/LinkModal-test.tsx b/test/unit-tests/components/views/rooms/wysiwyg_composer/components/LinkModal-test.tsx
index b1f86990e1d..f864f27de29 100644
--- a/test/unit-tests/components/views/rooms/wysiwyg_composer/components/LinkModal-test.tsx
+++ b/test/unit-tests/components/views/rooms/wysiwyg_composer/components/LinkModal-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/rooms/wysiwyg_composer/components/PlainTextComposer-test.tsx b/test/unit-tests/components/views/rooms/wysiwyg_composer/components/PlainTextComposer-test.tsx
index ae37afe8608..371960c8007 100644
--- a/test/unit-tests/components/views/rooms/wysiwyg_composer/components/PlainTextComposer-test.tsx
+++ b/test/unit-tests/components/views/rooms/wysiwyg_composer/components/PlainTextComposer-test.tsx
@@ -2,13 +2,14 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 import React from "react";
 import { act, render, screen } from "jest-matrix-react";
 import userEvent from "@testing-library/user-event";
+import { initOnce } from "@vector-im/matrix-wysiwyg";
 
 import { PlainTextComposer } from "../../../../../../../src/components/views/rooms/wysiwyg_composer/components/PlainTextComposer";
 import * as mockUseSettingsHook from "../../../../../../../src/hooks/useSettings";
@@ -16,6 +17,8 @@ import * as mockKeyboard from "../../../../../../../src/Keyboard";
 import { createMocks } from "../utils";
 import { ScopedRoomContextProvider } from "../../../../../../../src/contexts/ScopedRoomContext.tsx";
 
+beforeAll(initOnce, 10000);
+
 describe("PlainTextComposer", () => {
     const customRender = (
         onChange = (_content: string): void => void 0,
diff --git a/test/unit-tests/components/views/rooms/wysiwyg_composer/components/WysiwygAutocomplete-test.tsx b/test/unit-tests/components/views/rooms/wysiwyg_composer/components/WysiwygAutocomplete-test.tsx
index b0f4bbb5bd1..5886b501b43 100644
--- a/test/unit-tests/components/views/rooms/wysiwyg_composer/components/WysiwygAutocomplete-test.tsx
+++ b/test/unit-tests/components/views/rooms/wysiwyg_composer/components/WysiwygAutocomplete-test.tsx
@@ -2,13 +2,14 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 import "@testing-library/jest-dom";
 import React, { createRef } from "react";
 import { render, screen, waitFor } from "jest-matrix-react";
+import { initOnce } from "@vector-im/matrix-wysiwyg";
 
 import MatrixClientContext from "../../../../../../../src/contexts/MatrixClientContext";
 import { WysiwygAutocomplete } from "../../../../../../../src/components/views/rooms/wysiwyg_composer/components/WysiwygAutocomplete";
@@ -42,6 +43,8 @@ const constructMockProvider = (data: ICompletion[]) =>
         renderCompletions: jest.fn().mockImplementation((components) => components),
     }) as unknown as AutocompleteProvider;
 
+beforeAll(initOnce, 10000);
+
 describe("WysiwygAutocomplete", () => {
     beforeAll(() => {
         // scrollTo not implemented in JSDOM
diff --git a/test/unit-tests/components/views/rooms/wysiwyg_composer/components/WysiwygComposer-test.tsx b/test/unit-tests/components/views/rooms/wysiwyg_composer/components/WysiwygComposer-test.tsx
index c3c480eb828..e86488660e9 100644
--- a/test/unit-tests/components/views/rooms/wysiwyg_composer/components/WysiwygComposer-test.tsx
+++ b/test/unit-tests/components/views/rooms/wysiwyg_composer/components/WysiwygComposer-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -10,6 +10,7 @@ import "@testing-library/jest-dom";
 import React from "react";
 import { act, fireEvent, render, screen, waitFor } from "jest-matrix-react";
 import userEvent from "@testing-library/user-event";
+import { initOnce } from "@vector-im/matrix-wysiwyg";
 
 import { WysiwygComposer } from "../../../../../../../src/components/views/rooms/wysiwyg_composer/components/WysiwygComposer";
 import SettingsStore from "../../../../../../../src/settings/SettingsStore";
@@ -33,6 +34,8 @@ import * as Permalinks from "../../../../../../../src/utils/permalinks/Permalink
 import { PermalinkParts } from "../../../../../../../src/utils/permalinks/PermalinkConstructor";
 import { ScopedRoomContextProvider } from "../../../../../../../src/contexts/ScopedRoomContext.tsx";
 
+beforeAll(initOnce, 10000);
+
 describe("WysiwygComposer", () => {
     const customRender = (onChange = jest.fn(), onSend = jest.fn(), disabled = false, initialContent?: string) => {
         const { mockClient, defaultRoomContext } = createMocks();
@@ -419,7 +422,7 @@ describe("WysiwygComposer", () => {
         const onChange = jest.fn();
         const onSend = jest.fn();
         beforeEach(async () => {
-            jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string) => {
+            jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string): any => {
                 if (name === "MessageComposerInput.autoReplaceEmoji") return true;
             });
             customRender(onChange, onSend);
@@ -455,7 +458,7 @@ describe("WysiwygComposer", () => {
         const onChange = jest.fn();
         const onSend = jest.fn();
         beforeEach(async () => {
-            jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string) => {
+            jest.spyOn(SettingsStore, "getValue").mockImplementation((name): any => {
                 if (name === "MessageComposerInput.ctrlEnterToSend") return true;
             });
             customRender(onChange, onSend);
diff --git a/test/unit-tests/components/views/rooms/wysiwyg_composer/hooks/usePlainTextListeners-test.tsx b/test/unit-tests/components/views/rooms/wysiwyg_composer/hooks/usePlainTextListeners-test.tsx
index 20dc961cf4e..05645978772 100644
--- a/test/unit-tests/components/views/rooms/wysiwyg_composer/hooks/usePlainTextListeners-test.tsx
+++ b/test/unit-tests/components/views/rooms/wysiwyg_composer/hooks/usePlainTextListeners-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/rooms/wysiwyg_composer/hooks/useSuggestion-test.tsx b/test/unit-tests/components/views/rooms/wysiwyg_composer/hooks/useSuggestion-test.tsx
index 92243751042..06762b2c8f9 100644
--- a/test/unit-tests/components/views/rooms/wysiwyg_composer/hooks/useSuggestion-test.tsx
+++ b/test/unit-tests/components/views/rooms/wysiwyg_composer/hooks/useSuggestion-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 import React from "react";
diff --git a/test/unit-tests/components/views/rooms/wysiwyg_composer/hooks/utils-test.tsx b/test/unit-tests/components/views/rooms/wysiwyg_composer/hooks/utils-test.tsx
index eac4d6d35e2..c691756200c 100644
--- a/test/unit-tests/components/views/rooms/wysiwyg_composer/hooks/utils-test.tsx
+++ b/test/unit-tests/components/views/rooms/wysiwyg_composer/hooks/utils-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 import { IEventRelation, MatrixEvent } from "matrix-js-sdk/src/matrix";
diff --git a/test/unit-tests/components/views/rooms/wysiwyg_composer/utils.ts b/test/unit-tests/components/views/rooms/wysiwyg_composer/utils.ts
index d367e3488a9..cb72c90fb3b 100644
--- a/test/unit-tests/components/views/rooms/wysiwyg_composer/utils.ts
+++ b/test/unit-tests/components/views/rooms/wysiwyg_composer/utils.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/rooms/wysiwyg_composer/utils/autocomplete-test.ts b/test/unit-tests/components/views/rooms/wysiwyg_composer/utils/autocomplete-test.ts
index 8efc4df203f..292314f87f9 100644
--- a/test/unit-tests/components/views/rooms/wysiwyg_composer/utils/autocomplete-test.ts
+++ b/test/unit-tests/components/views/rooms/wysiwyg_composer/utils/autocomplete-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/rooms/wysiwyg_composer/utils/createMessageContent-test.ts b/test/unit-tests/components/views/rooms/wysiwyg_composer/utils/createMessageContent-test.ts
index 74852e9c6d7..80b3adcb139 100644
--- a/test/unit-tests/components/views/rooms/wysiwyg_composer/utils/createMessageContent-test.ts
+++ b/test/unit-tests/components/views/rooms/wysiwyg_composer/utils/createMessageContent-test.ts
@@ -2,10 +2,12 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
+
 import { MsgType } from "matrix-js-sdk/src/matrix";
+import { initOnce } from "@vector-im/matrix-wysiwyg";
 
 import { filterConsole, mkEvent } from "../../../../../../test-utils";
 import {
@@ -13,6 +15,8 @@ import {
     EMOTE_PREFIX,
 } from "../../../../../../../src/components/views/rooms/wysiwyg_composer/utils/createMessageContent";
 
+beforeAll(initOnce, 10000);
+
 describe("createMessageContent", () => {
     const message = "<em><b>hello</b> world</em>";
 
@@ -25,13 +29,6 @@ describe("createMessageContent", () => {
             "WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm`",
         );
 
-        beforeAll(async () => {
-            // Warm up by creating the component once, with a long timeout.
-            // This prevents tests timing out because of the time spent loading
-            // the WASM component.
-            await createMessageContent(message, true, {});
-        }, 10000);
-
         it("Should create html message", async () => {
             // When
             const content = await createMessageContent(message, true, {});
diff --git a/test/unit-tests/components/views/rooms/wysiwyg_composer/utils/message-test.ts b/test/unit-tests/components/views/rooms/wysiwyg_composer/utils/message-test.ts
index 43320b04445..867947bef91 100644
--- a/test/unit-tests/components/views/rooms/wysiwyg_composer/utils/message-test.ts
+++ b/test/unit-tests/components/views/rooms/wysiwyg_composer/utils/message-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/settings/AddPrivilegedUsers-test.tsx b/test/unit-tests/components/views/settings/AddPrivilegedUsers-test.tsx
index 68638597871..875b5d9f193 100644
--- a/test/unit-tests/components/views/settings/AddPrivilegedUsers-test.tsx
+++ b/test/unit-tests/components/views/settings/AddPrivilegedUsers-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 import React from "react";
diff --git a/test/unit-tests/components/views/settings/AddRemoveThreepids-test.tsx b/test/unit-tests/components/views/settings/AddRemoveThreepids-test.tsx
index a285a98f3b6..dacd2c52a5a 100644
--- a/test/unit-tests/components/views/settings/AddRemoveThreepids-test.tsx
+++ b/test/unit-tests/components/views/settings/AddRemoveThreepids-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/settings/AvatarSetting-test.tsx b/test/unit-tests/components/views/settings/AvatarSetting-test.tsx
index 1b88c416bc5..f6c4181b210 100644
--- a/test/unit-tests/components/views/settings/AvatarSetting-test.tsx
+++ b/test/unit-tests/components/views/settings/AvatarSetting-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 import React from "react";
diff --git a/test/unit-tests/components/views/settings/ChangePassword-test.tsx b/test/unit-tests/components/views/settings/ChangePassword-test.tsx
index 75211647e09..6b4c58f1d13 100644
--- a/test/unit-tests/components/views/settings/ChangePassword-test.tsx
+++ b/test/unit-tests/components/views/settings/ChangePassword-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/settings/CrossSigningPanel-test.tsx b/test/unit-tests/components/views/settings/CrossSigningPanel-test.tsx
index daa3570ed27..ee7c6425878 100644
--- a/test/unit-tests/components/views/settings/CrossSigningPanel-test.tsx
+++ b/test/unit-tests/components/views/settings/CrossSigningPanel-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/settings/CryptographyPanel-test.tsx b/test/unit-tests/components/views/settings/CryptographyPanel-test.tsx
index 03b469fe76e..3d368734731 100644
--- a/test/unit-tests/components/views/settings/CryptographyPanel-test.tsx
+++ b/test/unit-tests/components/views/settings/CryptographyPanel-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/settings/EventIndexPanel-test.tsx b/test/unit-tests/components/views/settings/EventIndexPanel-test.tsx
index 9859cc27fa5..c154a3c2a81 100644
--- a/test/unit-tests/components/views/settings/EventIndexPanel-test.tsx
+++ b/test/unit-tests/components/views/settings/EventIndexPanel-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/settings/FontScalingPanel-test.tsx b/test/unit-tests/components/views/settings/FontScalingPanel-test.tsx
index 4e2ed5451ab..fc8de6d631e 100644
--- a/test/unit-tests/components/views/settings/FontScalingPanel-test.tsx
+++ b/test/unit-tests/components/views/settings/FontScalingPanel-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/settings/JoinRuleSettings-test.tsx b/test/unit-tests/components/views/settings/JoinRuleSettings-test.tsx
index 36dd664ac69..87cef697868 100644
--- a/test/unit-tests/components/views/settings/JoinRuleSettings-test.tsx
+++ b/test/unit-tests/components/views/settings/JoinRuleSettings-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/settings/KeyboardShortcut-test.tsx b/test/unit-tests/components/views/settings/KeyboardShortcut-test.tsx
index 2bebd04cc8a..edcc915e4d4 100644
--- a/test/unit-tests/components/views/settings/KeyboardShortcut-test.tsx
+++ b/test/unit-tests/components/views/settings/KeyboardShortcut-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 Šimon Brandner <simon.bra.ag@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/settings/LayoutSwitcher-test.tsx b/test/unit-tests/components/views/settings/LayoutSwitcher-test.tsx
index 9148f7ceb1e..5d3f1709e29 100644
--- a/test/unit-tests/components/views/settings/LayoutSwitcher-test.tsx
+++ b/test/unit-tests/components/views/settings/LayoutSwitcher-test.tsx
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2024 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
@@ -57,7 +57,7 @@ describe("<LayoutSwitcher />", () => {
             act(() => screen.getByRole("radio", { name: "Message bubbles" }).click());
 
             expect(screen.getByRole("radio", { name: "Message bubbles" })).toBeChecked();
-            await waitFor(() => expect(SettingsStore.getValue<boolean>("layout")).toBe(Layout.Bubble));
+            await waitFor(() => expect(SettingsStore.getValue("layout")).toBe(Layout.Bubble));
         });
     });
 
@@ -77,7 +77,7 @@ describe("<LayoutSwitcher />", () => {
             await renderLayoutSwitcher();
             act(() => screen.getByRole("checkbox", { name: "Show compact text and messages" }).click());
 
-            await waitFor(() => expect(SettingsStore.getValue<boolean>("useCompactLayout")).toBe(true));
+            await waitFor(() => expect(SettingsStore.getValue("useCompactLayout")).toBe(true));
         });
 
         it("should be disabled when the modern layout is not enabled", async () => {
diff --git a/test/unit-tests/components/views/settings/Notifications-test.tsx b/test/unit-tests/components/views/settings/Notifications-test.tsx
index e3d97169010..c4b893920df 100644
--- a/test/unit-tests/components/views/settings/Notifications-test.tsx
+++ b/test/unit-tests/components/views/settings/Notifications-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022, 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/settings/PowerLevelSelector-test.tsx b/test/unit-tests/components/views/settings/PowerLevelSelector-test.tsx
index 052898debb8..d94587f0f38 100644
--- a/test/unit-tests/components/views/settings/PowerLevelSelector-test.tsx
+++ b/test/unit-tests/components/views/settings/PowerLevelSelector-test.tsx
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2024 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/test/unit-tests/components/views/settings/SecureBackupPanel-test.tsx b/test/unit-tests/components/views/settings/SecureBackupPanel-test.tsx
index 63490bf9150..78d59c07f17 100644
--- a/test/unit-tests/components/views/settings/SecureBackupPanel-test.tsx
+++ b/test/unit-tests/components/views/settings/SecureBackupPanel-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/settings/SetIntegrationManager-test.tsx b/test/unit-tests/components/views/settings/SetIntegrationManager-test.tsx
index 5c77e88d932..bab908c75e7 100644
--- a/test/unit-tests/components/views/settings/SetIntegrationManager-test.tsx
+++ b/test/unit-tests/components/views/settings/SetIntegrationManager-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -11,7 +11,6 @@ import { fireEvent, render, screen, waitFor, within } from "jest-matrix-react";
 import { logger } from "matrix-js-sdk/src/logger";
 
 import MatrixClientContext from "../../../../../src/contexts/MatrixClientContext";
-import { SDKContext, SdkContextClass } from "../../../../../src/contexts/SDKContext";
 import SettingsStore from "../../../../../src/settings/SettingsStore";
 import { UIFeature } from "../../../../../src/settings/UIFeature";
 import {
@@ -35,13 +34,9 @@ describe("SetIntegrationManager", () => {
         deleteThreePid: jest.fn(),
     });
 
-    let stores!: SdkContextClass;
-
     const getComponent = () => (
         <MatrixClientContext.Provider value={mockClient}>
-            <SDKContext.Provider value={stores}>
-                <SetIntegrationManager />
-            </SDKContext.Provider>
+            <SetIntegrationManager />
         </MatrixClientContext.Provider>
     );
 
diff --git a/test/unit-tests/components/views/settings/SettingsFieldset-test.tsx b/test/unit-tests/components/views/settings/SettingsFieldset-test.tsx
index 3049a1fb328..6e9242f06e5 100644
--- a/test/unit-tests/components/views/settings/SettingsFieldset-test.tsx
+++ b/test/unit-tests/components/views/settings/SettingsFieldset-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/settings/SettingsHeader-test.tsx b/test/unit-tests/components/views/settings/SettingsHeader-test.tsx
new file mode 100644
index 00000000000..eed0df01cf2
--- /dev/null
+++ b/test/unit-tests/components/views/settings/SettingsHeader-test.tsx
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2024 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+import React from "react";
+import { render } from "jest-matrix-react";
+
+import { SettingsHeader } from "../../../../../src/components/views/settings/SettingsHeader";
+
+describe("<SettingsHeader />", () => {
+    it("should render the component", () => {
+        const { asFragment } = render(<SettingsHeader label="Settings Header" />);
+        expect(asFragment()).toMatchSnapshot();
+    });
+
+    it("should render the component with the recommended tag", () => {
+        const { asFragment } = render(<SettingsHeader label="Settings Header" hasRecommendedTag={true} />);
+        expect(asFragment()).toMatchSnapshot();
+    });
+});
diff --git a/test/unit-tests/components/views/settings/SettingsSubheader-test.tsx b/test/unit-tests/components/views/settings/SettingsSubheader-test.tsx
new file mode 100644
index 00000000000..6a0bf21defd
--- /dev/null
+++ b/test/unit-tests/components/views/settings/SettingsSubheader-test.tsx
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2024 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+import React from "react";
+import { render } from "jest-matrix-react";
+
+import { SettingsSubheader } from "../../../../../src/components/views/settings/SettingsSubheader";
+
+describe("<SettingsSubheader />", () => {
+    it("should display a check icon when in success", () => {
+        const { asFragment } = render(<SettingsSubheader state="success" stateMessage="Success!" />);
+        expect(asFragment()).toMatchSnapshot();
+    });
+
+    it("should display an error icon when in error", () => {
+        const { asFragment } = render(<SettingsSubheader state="error" stateMessage="Error!" />);
+        expect(asFragment()).toMatchSnapshot();
+    });
+
+    it("should display a label", () => {
+        const { asFragment } = render(<SettingsSubheader label="My label" state="success" stateMessage="Success!" />);
+        expect(asFragment()).toMatchSnapshot();
+    });
+});
diff --git a/test/unit-tests/components/views/settings/ThemeChoicePanel-test.tsx b/test/unit-tests/components/views/settings/ThemeChoicePanel-test.tsx
index 2eafcc7ada2..354fd44b9df 100644
--- a/test/unit-tests/components/views/settings/ThemeChoicePanel-test.tsx
+++ b/test/unit-tests/components/views/settings/ThemeChoicePanel-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/settings/UserProfileSettings-test.tsx b/test/unit-tests/components/views/settings/UserProfileSettings-test.tsx
index 98b321a26dc..0c80cd6f5d0 100644
--- a/test/unit-tests/components/views/settings/UserProfileSettings-test.tsx
+++ b/test/unit-tests/components/views/settings/UserProfileSettings-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/settings/__snapshots__/SettingsHeader-test.tsx.snap b/test/unit-tests/components/views/settings/__snapshots__/SettingsHeader-test.tsx.snap
new file mode 100644
index 00000000000..4098a55ed41
--- /dev/null
+++ b/test/unit-tests/components/views/settings/__snapshots__/SettingsHeader-test.tsx.snap
@@ -0,0 +1,24 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`<SettingsHeader /> should render the component 1`] = `
+<DocumentFragment>
+  <h2
+    class="_typography_yh5dq_162 _font-heading-sm-semibold_yh5dq_102 mx_SettingsHeader"
+  >
+    Settings Header 
+  </h2>
+</DocumentFragment>
+`;
+
+exports[`<SettingsHeader /> should render the component with the recommended tag 1`] = `
+<DocumentFragment>
+  <h2
+    class="_typography_yh5dq_162 _font-heading-sm-semibold_yh5dq_102 mx_SettingsHeader"
+  >
+    Settings Header 
+    <span>
+      Recommended
+    </span>
+  </h2>
+</DocumentFragment>
+`;
diff --git a/test/unit-tests/components/views/settings/__snapshots__/SettingsSubheader-test.tsx.snap b/test/unit-tests/components/views/settings/__snapshots__/SettingsSubheader-test.tsx.snap
new file mode 100644
index 00000000000..23c9ce087d7
--- /dev/null
+++ b/test/unit-tests/components/views/settings/__snapshots__/SettingsSubheader-test.tsx.snap
@@ -0,0 +1,77 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`<SettingsSubheader /> should display a check icon when in success 1`] = `
+<DocumentFragment>
+  <div
+    class="mx_SettingsSubheader"
+  >
+    <span
+      class="mx_SettingsSubheader_success"
+    >
+      <svg
+        fill="currentColor"
+        height="20px"
+        viewBox="0 0 24 24"
+        width="20px"
+        xmlns="http://www.w3.org/2000/svg"
+      >
+        <path
+          d="m10.6 13.8-2.15-2.15a.948.948 0 0 0-.7-.275.948.948 0 0 0-.7.275.948.948 0 0 0-.275.7.95.95 0 0 0 .275.7L9.9 15.9c.2.2.433.3.7.3.267 0 .5-.1.7-.3l5.65-5.65a.948.948 0 0 0 .275-.7.948.948 0 0 0-.275-.7.948.948 0 0 0-.7-.275.948.948 0 0 0-.7.275L10.6 13.8ZM12 22a9.738 9.738 0 0 1-3.9-.788 10.099 10.099 0 0 1-3.175-2.137c-.9-.9-1.612-1.958-2.137-3.175A9.738 9.738 0 0 1 2 12a9.74 9.74 0 0 1 .788-3.9 10.099 10.099 0 0 1 2.137-3.175c.9-.9 1.958-1.612 3.175-2.137A9.738 9.738 0 0 1 12 2a9.74 9.74 0 0 1 3.9.788 10.098 10.098 0 0 1 3.175 2.137c.9.9 1.613 1.958 2.137 3.175A9.738 9.738 0 0 1 22 12a9.738 9.738 0 0 1-.788 3.9 10.098 10.098 0 0 1-2.137 3.175c-.9.9-1.958 1.613-3.175 2.137A9.738 9.738 0 0 1 12 22Z"
+        />
+      </svg>
+      Success!
+    </span>
+  </div>
+</DocumentFragment>
+`;
+
+exports[`<SettingsSubheader /> should display a label 1`] = `
+<DocumentFragment>
+  <div
+    class="mx_SettingsSubheader"
+  >
+    My label
+    <span
+      class="mx_SettingsSubheader_success"
+    >
+      <svg
+        fill="currentColor"
+        height="20px"
+        viewBox="0 0 24 24"
+        width="20px"
+        xmlns="http://www.w3.org/2000/svg"
+      >
+        <path
+          d="m10.6 13.8-2.15-2.15a.948.948 0 0 0-.7-.275.948.948 0 0 0-.7.275.948.948 0 0 0-.275.7.95.95 0 0 0 .275.7L9.9 15.9c.2.2.433.3.7.3.267 0 .5-.1.7-.3l5.65-5.65a.948.948 0 0 0 .275-.7.948.948 0 0 0-.275-.7.948.948 0 0 0-.7-.275.948.948 0 0 0-.7.275L10.6 13.8ZM12 22a9.738 9.738 0 0 1-3.9-.788 10.099 10.099 0 0 1-3.175-2.137c-.9-.9-1.612-1.958-2.137-3.175A9.738 9.738 0 0 1 2 12a9.74 9.74 0 0 1 .788-3.9 10.099 10.099 0 0 1 2.137-3.175c.9-.9 1.958-1.612 3.175-2.137A9.738 9.738 0 0 1 12 2a9.74 9.74 0 0 1 3.9.788 10.098 10.098 0 0 1 3.175 2.137c.9.9 1.613 1.958 2.137 3.175A9.738 9.738 0 0 1 22 12a9.738 9.738 0 0 1-.788 3.9 10.098 10.098 0 0 1-2.137 3.175c-.9.9-1.958 1.613-3.175 2.137A9.738 9.738 0 0 1 12 22Z"
+        />
+      </svg>
+      Success!
+    </span>
+  </div>
+</DocumentFragment>
+`;
+
+exports[`<SettingsSubheader /> should display an error icon when in error 1`] = `
+<DocumentFragment>
+  <div
+    class="mx_SettingsSubheader"
+  >
+    <span
+      class="mx_SettingsSubheader_error"
+    >
+      <svg
+        fill="currentColor"
+        height="20px"
+        viewBox="0 0 24 24"
+        width="20px"
+        xmlns="http://www.w3.org/2000/svg"
+      >
+        <path
+          d="M12 17a.97.97 0 0 0 .713-.288A.968.968 0 0 0 13 16a.968.968 0 0 0-.287-.713A.968.968 0 0 0 12 15a.968.968 0 0 0-.713.287A.968.968 0 0 0 11 16c0 .283.096.52.287.712.192.192.43.288.713.288Zm0-4c.283 0 .52-.096.713-.287A.968.968 0 0 0 13 12V8a.967.967 0 0 0-.287-.713A.968.968 0 0 0 12 7a.968.968 0 0 0-.713.287A.967.967 0 0 0 11 8v4c0 .283.096.52.287.713.192.191.43.287.713.287Zm0 9a9.738 9.738 0 0 1-3.9-.788 10.099 10.099 0 0 1-3.175-2.137c-.9-.9-1.612-1.958-2.137-3.175A9.738 9.738 0 0 1 2 12a9.74 9.74 0 0 1 .788-3.9 10.099 10.099 0 0 1 2.137-3.175c.9-.9 1.958-1.612 3.175-2.137A9.738 9.738 0 0 1 12 2a9.74 9.74 0 0 1 3.9.788 10.098 10.098 0 0 1 3.175 2.137c.9.9 1.613 1.958 2.137 3.175A9.738 9.738 0 0 1 22 12a9.738 9.738 0 0 1-.788 3.9 10.098 10.098 0 0 1-2.137 3.175c-.9.9-1.958 1.613-3.175 2.137A9.738 9.738 0 0 1 12 22Z"
+        />
+      </svg>
+      Error!
+    </span>
+  </div>
+</DocumentFragment>
+`;
diff --git a/test/unit-tests/components/views/settings/devices/CurrentDeviceSection-test.tsx b/test/unit-tests/components/views/settings/devices/CurrentDeviceSection-test.tsx
index 3cddfea9d1d..6ba46ed5280 100644
--- a/test/unit-tests/components/views/settings/devices/CurrentDeviceSection-test.tsx
+++ b/test/unit-tests/components/views/settings/devices/CurrentDeviceSection-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/settings/devices/DeviceDetailHeading-test.tsx b/test/unit-tests/components/views/settings/devices/DeviceDetailHeading-test.tsx
index acdaf229763..d963acf76b1 100644
--- a/test/unit-tests/components/views/settings/devices/DeviceDetailHeading-test.tsx
+++ b/test/unit-tests/components/views/settings/devices/DeviceDetailHeading-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/settings/devices/DeviceDetails-test.tsx b/test/unit-tests/components/views/settings/devices/DeviceDetails-test.tsx
index 218bda0df84..765621eee5f 100644
--- a/test/unit-tests/components/views/settings/devices/DeviceDetails-test.tsx
+++ b/test/unit-tests/components/views/settings/devices/DeviceDetails-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/settings/devices/DeviceExpandDetailsButton-test.tsx b/test/unit-tests/components/views/settings/devices/DeviceExpandDetailsButton-test.tsx
index 423c0575d82..5cb4d95f71a 100644
--- a/test/unit-tests/components/views/settings/devices/DeviceExpandDetailsButton-test.tsx
+++ b/test/unit-tests/components/views/settings/devices/DeviceExpandDetailsButton-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/settings/devices/DeviceSecurityCard-test.tsx b/test/unit-tests/components/views/settings/devices/DeviceSecurityCard-test.tsx
index 5716155d037..010c2e98fcb 100644
--- a/test/unit-tests/components/views/settings/devices/DeviceSecurityCard-test.tsx
+++ b/test/unit-tests/components/views/settings/devices/DeviceSecurityCard-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/settings/devices/DeviceTile-test.tsx b/test/unit-tests/components/views/settings/devices/DeviceTile-test.tsx
index 0e87c298fc0..a868b45f275 100644
--- a/test/unit-tests/components/views/settings/devices/DeviceTile-test.tsx
+++ b/test/unit-tests/components/views/settings/devices/DeviceTile-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/settings/devices/DeviceTypeIcon-test.tsx b/test/unit-tests/components/views/settings/devices/DeviceTypeIcon-test.tsx
index 242a7786825..525620fb11b 100644
--- a/test/unit-tests/components/views/settings/devices/DeviceTypeIcon-test.tsx
+++ b/test/unit-tests/components/views/settings/devices/DeviceTypeIcon-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/settings/devices/DeviceVerificationStatusCard-test.tsx b/test/unit-tests/components/views/settings/devices/DeviceVerificationStatusCard-test.tsx
index bdfcb4a0c2a..8ffb9889e67 100644
--- a/test/unit-tests/components/views/settings/devices/DeviceVerificationStatusCard-test.tsx
+++ b/test/unit-tests/components/views/settings/devices/DeviceVerificationStatusCard-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/settings/devices/FilteredDeviceList-test.tsx b/test/unit-tests/components/views/settings/devices/FilteredDeviceList-test.tsx
index 38d2b9ad8ac..3318a13e6ad 100644
--- a/test/unit-tests/components/views/settings/devices/FilteredDeviceList-test.tsx
+++ b/test/unit-tests/components/views/settings/devices/FilteredDeviceList-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/settings/devices/FilteredDeviceListHeader-test.tsx b/test/unit-tests/components/views/settings/devices/FilteredDeviceListHeader-test.tsx
index 1a7b0e006bd..f2c7e9d138a 100644
--- a/test/unit-tests/components/views/settings/devices/FilteredDeviceListHeader-test.tsx
+++ b/test/unit-tests/components/views/settings/devices/FilteredDeviceListHeader-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/settings/devices/LoginWithQR-test.tsx b/test/unit-tests/components/views/settings/devices/LoginWithQR-test.tsx
index 98a0657eae0..7b50ae02787 100644
--- a/test/unit-tests/components/views/settings/devices/LoginWithQR-test.tsx
+++ b/test/unit-tests/components/views/settings/devices/LoginWithQR-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/settings/devices/LoginWithQRFlow-test.tsx b/test/unit-tests/components/views/settings/devices/LoginWithQRFlow-test.tsx
index 2a16c793a2c..9120ff4f66e 100644
--- a/test/unit-tests/components/views/settings/devices/LoginWithQRFlow-test.tsx
+++ b/test/unit-tests/components/views/settings/devices/LoginWithQRFlow-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/settings/devices/LoginWithQRSection-test.tsx b/test/unit-tests/components/views/settings/devices/LoginWithQRSection-test.tsx
index edaf7b39d17..ebbc3598894 100644
--- a/test/unit-tests/components/views/settings/devices/LoginWithQRSection-test.tsx
+++ b/test/unit-tests/components/views/settings/devices/LoginWithQRSection-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/settings/devices/SecurityRecommendations-test.tsx b/test/unit-tests/components/views/settings/devices/SecurityRecommendations-test.tsx
index e970ebbb032..437d7111002 100644
--- a/test/unit-tests/components/views/settings/devices/SecurityRecommendations-test.tsx
+++ b/test/unit-tests/components/views/settings/devices/SecurityRecommendations-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/settings/devices/SelectableDeviceTile-test.tsx b/test/unit-tests/components/views/settings/devices/SelectableDeviceTile-test.tsx
index f7c8510656c..44d624f6210 100644
--- a/test/unit-tests/components/views/settings/devices/SelectableDeviceTile-test.tsx
+++ b/test/unit-tests/components/views/settings/devices/SelectableDeviceTile-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/settings/devices/__snapshots__/CurrentDeviceSection-test.tsx.snap b/test/unit-tests/components/views/settings/devices/__snapshots__/CurrentDeviceSection-test.tsx.snap
index 74a0fb919be..a3465ab5882 100644
--- a/test/unit-tests/components/views/settings/devices/__snapshots__/CurrentDeviceSection-test.tsx.snap
+++ b/test/unit-tests/components/views/settings/devices/__snapshots__/CurrentDeviceSection-test.tsx.snap
@@ -49,7 +49,7 @@ HTMLCollection [
           <p
             class="mx_DeviceSecurityCard_description"
           >
-            Verify or sign out from this session for best security and reliability.
+            Verify your current session for enhanced secure messaging.
             <div
               class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
               role="button"
diff --git a/test/unit-tests/components/views/settings/devices/deleteDevices-test.tsx b/test/unit-tests/components/views/settings/devices/deleteDevices-test.tsx
index af602a83e54..9aeaa5afcd5 100644
--- a/test/unit-tests/components/views/settings/devices/deleteDevices-test.tsx
+++ b/test/unit-tests/components/views/settings/devices/deleteDevices-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/settings/devices/filter-test.ts b/test/unit-tests/components/views/settings/devices/filter-test.ts
index 9a354eb3b57..bf131ac788c 100644
--- a/test/unit-tests/components/views/settings/devices/filter-test.ts
+++ b/test/unit-tests/components/views/settings/devices/filter-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/settings/discovery/DiscoverySettings-test.tsx b/test/unit-tests/components/views/settings/discovery/DiscoverySettings-test.tsx
index 4cd55f6fc45..404735f63aa 100644
--- a/test/unit-tests/components/views/settings/discovery/DiscoverySettings-test.tsx
+++ b/test/unit-tests/components/views/settings/discovery/DiscoverySettings-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -40,7 +40,7 @@ describe("DiscoverySettings", () => {
     const DiscoveryWrapper = (props = {}) => <MatrixClientContext.Provider value={client} {...props} />;
 
     it("is empty if 3pid features are disabled", async () => {
-        jest.spyOn(SettingsStore, "getValue").mockImplementation((key) => {
+        jest.spyOn(SettingsStore, "getValue").mockImplementation((key: any): any => {
             if (key === UIFeature.ThirdPartyID) return false;
         });
 
diff --git a/test/unit-tests/components/views/settings/encryption/ChangeRecoveryKey-test.tsx b/test/unit-tests/components/views/settings/encryption/ChangeRecoveryKey-test.tsx
new file mode 100644
index 00000000000..8929916a0eb
--- /dev/null
+++ b/test/unit-tests/components/views/settings/encryption/ChangeRecoveryKey-test.tsx
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2024 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+import React from "react";
+import { render, screen, waitFor } from "jest-matrix-react";
+import { MatrixClient } from "matrix-js-sdk/src/matrix";
+import userEvent from "@testing-library/user-event";
+
+import { ChangeRecoveryKey } from "../../../../../../src/components/views/settings/encryption/ChangeRecoveryKey";
+import { createTestClient, withClientContextRenderOptions } from "../../../../../test-utils";
+import { copyPlaintext } from "../../../../../../src/utils/strings";
+
+jest.mock("../../../../../../src/utils/strings", () => ({
+    copyPlaintext: jest.fn(),
+}));
+
+describe("<ChangeRecoveryKey />", () => {
+    let matrixClient: MatrixClient;
+
+    beforeEach(() => {
+        matrixClient = createTestClient();
+    });
+
+    function renderComponent(userHasRecoveryKey = true, onFinish = jest.fn(), onCancelClick = jest.fn()) {
+        return render(
+            <ChangeRecoveryKey
+                userHasRecoveryKey={userHasRecoveryKey}
+                onFinish={onFinish}
+                onCancelClick={onCancelClick}
+            />,
+            withClientContextRenderOptions(matrixClient),
+        );
+    }
+
+    describe("flow to setup a recovery key", () => {
+        it("should display information about the recovery key", async () => {
+            const user = userEvent.setup();
+
+            const onCancelClick = jest.fn();
+            const { asFragment } = renderComponent(false, jest.fn(), onCancelClick);
+            await waitFor(() =>
+                expect(
+                    screen.getByText(
+                        "Your key storage is protected by a recovery key. If you need a new recovery key after setup, you can recreate it by selecting ‘Change recovery key’.",
+                    ),
+                ).toBeInTheDocument(),
+            );
+            expect(asFragment()).toMatchSnapshot();
+
+            await user.click(screen.getByRole("button", { name: "Cancel" }));
+            expect(onCancelClick).toHaveBeenCalled();
+        });
+
+        it("should display the recovery key", async () => {
+            const user = userEvent.setup();
+
+            const onCancelClick = jest.fn();
+            const { asFragment } = renderComponent(false, jest.fn(), onCancelClick);
+            await waitFor(() => user.click(screen.getByRole("button", { name: "Continue" })));
+
+            expect(screen.getByText("Save your recovery key somewhere safe")).toBeInTheDocument();
+            expect(screen.getByText("encoded private key")).toBeInTheDocument();
+            expect(asFragment()).toMatchSnapshot();
+
+            // Test copy button
+            await user.click(screen.getByRole("button", { name: "Copy" }));
+            expect(copyPlaintext).toHaveBeenCalled();
+
+            await user.click(screen.getByRole("button", { name: "Cancel" }));
+            expect(onCancelClick).toHaveBeenCalled();
+        });
+
+        it("should ask the user to enter the recovery key", async () => {
+            const user = userEvent.setup();
+
+            const onFinish = jest.fn();
+            const { asFragment } = renderComponent(false, onFinish);
+            // Display the recovery key to save
+            await waitFor(() => user.click(screen.getByRole("button", { name: "Continue" })));
+            // Display the form to confirm the recovery key
+            await waitFor(() => user.click(screen.getByRole("button", { name: "Continue" })));
+
+            await waitFor(() => expect(screen.getByText("Enter your recovery key to confirm")).toBeInTheDocument());
+            expect(asFragment()).toMatchSnapshot();
+
+            // The finish button should be disabled by default
+            const finishButton = screen.getByRole("button", { name: "Finish set up" });
+            expect(finishButton).toHaveAttribute("aria-disabled", "true");
+
+            const input = screen.getByRole("textbox");
+            // If the user enters an incorrect recovery key, the finish button should be disabled
+            // and we display an error message
+            await userEvent.type(input, "wrong recovery key");
+            expect(finishButton).toHaveAttribute("aria-disabled", "true");
+            expect(screen.getByText("The recovery key you entered is not correct.")).toBeInTheDocument();
+            expect(asFragment()).toMatchSnapshot();
+
+            await userEvent.clear(input);
+            // If the user enters the correct recovery key, the finish button should be enabled
+            await userEvent.type(input, "encoded private key");
+            await waitFor(() => expect(finishButton).not.toHaveAttribute("aria-disabled", "true"));
+
+            await user.click(finishButton);
+            expect(onFinish).toHaveBeenCalledWith();
+        });
+    });
+
+    describe("flow to change the recovery key", () => {
+        it("should display the recovery key", async () => {
+            const { asFragment } = renderComponent();
+
+            await waitFor(() => expect(screen.getByText("Change recovery key?")).toBeInTheDocument());
+            expect(screen.getByText("encoded private key")).toBeInTheDocument();
+            expect(asFragment()).toMatchSnapshot();
+        });
+    });
+});
diff --git a/test/unit-tests/components/views/settings/encryption/EncryptionCard-test.tsx b/test/unit-tests/components/views/settings/encryption/EncryptionCard-test.tsx
new file mode 100644
index 00000000000..d51fcb840bf
--- /dev/null
+++ b/test/unit-tests/components/views/settings/encryption/EncryptionCard-test.tsx
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2024 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+import React from "react";
+import { render } from "jest-matrix-react";
+
+import { EncryptionCard } from "../../../../../../src/components/views/settings/encryption/EncryptionCard";
+
+describe("<EncryptionCard />", () => {
+    it("should render", () => {
+        const { asFragment } = render(
+            <EncryptionCard title="My title" description="My description">
+                Encryption card children
+            </EncryptionCard>,
+        );
+        expect(asFragment()).toMatchSnapshot();
+    });
+});
diff --git a/test/unit-tests/components/views/settings/encryption/RecoveryPanel-test.tsx b/test/unit-tests/components/views/settings/encryption/RecoveryPanel-test.tsx
new file mode 100644
index 00000000000..6ef79876c7a
--- /dev/null
+++ b/test/unit-tests/components/views/settings/encryption/RecoveryPanel-test.tsx
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2024 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+import React from "react";
+import { MatrixClient } from "matrix-js-sdk/src/matrix";
+import { render, screen } from "jest-matrix-react";
+import { waitFor } from "@testing-library/dom";
+import userEvent from "@testing-library/user-event";
+import { mocked } from "jest-mock";
+
+import { createTestClient, withClientContextRenderOptions } from "../../../../../test-utils";
+import { RecoveryPanel } from "../../../../../../src/components/views/settings/encryption/RecoveryPanel";
+import { accessSecretStorage } from "../../../../../../src/SecurityManager";
+
+jest.mock("../../../../../../src/SecurityManager", () => ({
+    accessSecretStorage: jest.fn(),
+}));
+
+describe("<RecoveryPanel />", () => {
+    let matrixClient: MatrixClient;
+
+    beforeEach(() => {
+        matrixClient = createTestClient();
+        mocked(accessSecretStorage).mockClear().mockResolvedValue();
+    });
+
+    function renderRecoverPanel(onChangeRecoveryKeyClick = jest.fn()) {
+        return render(
+            <RecoveryPanel onChangeRecoveryKeyClick={onChangeRecoveryKeyClick} />,
+            withClientContextRenderOptions(matrixClient),
+        );
+    }
+
+    it("should be in loading state when checking the recovery key and the cached keys", () => {
+        jest.spyOn(matrixClient.secretStorage, "getDefaultKeyId").mockImplementation(() => new Promise(() => {}));
+
+        const { asFragment } = renderRecoverPanel();
+        expect(screen.getByLabelText("Loading…")).toBeInTheDocument();
+        expect(asFragment()).toMatchSnapshot();
+    });
+
+    it("should ask to set up a recovery key when there is no recovery key", async () => {
+        const user = userEvent.setup();
+
+        const onChangeRecoveryKeyClick = jest.fn();
+        const { asFragment } = renderRecoverPanel(onChangeRecoveryKeyClick);
+
+        await waitFor(() => screen.getByRole("button", { name: "Set up recovery" }));
+        expect(asFragment()).toMatchSnapshot();
+
+        await user.click(screen.getByRole("button", { name: "Set up recovery" }));
+        expect(onChangeRecoveryKeyClick).toHaveBeenCalledWith(true);
+    });
+
+    it("should ask to enter the recovery key when secrets are not cached", async () => {
+        jest.spyOn(matrixClient.secretStorage, "getDefaultKeyId").mockResolvedValue("default key");
+        const user = userEvent.setup();
+        const { asFragment } = renderRecoverPanel();
+
+        await waitFor(() => screen.getByRole("button", { name: "Enter recovery key" }));
+        expect(asFragment()).toMatchSnapshot();
+
+        await user.click(screen.getByRole("button", { name: "Enter recovery key" }));
+        expect(accessSecretStorage).toHaveBeenCalled();
+    });
+
+    it("should allow to change the recovery key when everything is good", async () => {
+        jest.spyOn(matrixClient.secretStorage, "getDefaultKeyId").mockResolvedValue("default key");
+        jest.spyOn(matrixClient.getCrypto()!, "getCrossSigningStatus").mockResolvedValue({
+            privateKeysInSecretStorage: true,
+            publicKeysOnDevice: true,
+            privateKeysCachedLocally: {
+                masterKey: true,
+                selfSigningKey: true,
+                userSigningKey: true,
+            },
+        });
+        const user = userEvent.setup();
+
+        const onChangeRecoveryKeyClick = jest.fn();
+        const { asFragment } = renderRecoverPanel(onChangeRecoveryKeyClick);
+        await waitFor(() => screen.getByRole("button", { name: "Change recovery key" }));
+        expect(asFragment()).toMatchSnapshot();
+
+        await user.click(screen.getByRole("button", { name: "Change recovery key" }));
+        expect(onChangeRecoveryKeyClick).toHaveBeenCalledWith(false);
+    });
+});
diff --git a/test/unit-tests/components/views/settings/encryption/__snapshots__/ChangeRecoveryKey-test.tsx.snap b/test/unit-tests/components/views/settings/encryption/__snapshots__/ChangeRecoveryKey-test.tsx.snap
new file mode 100644
index 00000000000..0719c6cc531
--- /dev/null
+++ b/test/unit-tests/components/views/settings/encryption/__snapshots__/ChangeRecoveryKey-test.tsx.snap
@@ -0,0 +1,725 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`<ChangeRecoveryKey /> flow to change the recovery key should display the recovery key 1`] = `
+<DocumentFragment>
+  <nav
+    class="_breadcrumb_ikpbb_17"
+  >
+    <button
+      aria-label="Back"
+      class="_icon-button_bh2qc_17 _subtle-bg_bh2qc_38"
+      role="button"
+      style="--cpd-icon-button-size: 28px;"
+      tabindex="0"
+    >
+      <div
+        class="_indicator-icon_133tf_26"
+        style="--cpd-icon-button-size: 100%;"
+      >
+        <svg
+          fill="currentColor"
+          height="1em"
+          viewBox="0 0 24 24"
+          width="1em"
+          xmlns="http://www.w3.org/2000/svg"
+        >
+          <path
+            d="m13.3 17.3-4.6-4.6a.877.877 0 0 1-.213-.325A1.106 1.106 0 0 1 8.425 12c0-.133.02-.258.062-.375A.878.878 0 0 1 8.7 11.3l4.6-4.6a.948.948 0 0 1 .7-.275.95.95 0 0 1 .7.275.948.948 0 0 1 .275.7.948.948 0 0 1-.275.7L10.8 12l3.9 3.9a.949.949 0 0 1 .275.7.948.948 0 0 1-.275.7.948.948 0 0 1-.7.275.948.948 0 0 1-.7-.275Z"
+          />
+        </svg>
+      </div>
+    </button>
+    <ol
+      class="_pages_ikpbb_26"
+    >
+      <li>
+        <a
+          class="_link_ue21z_17"
+          data-kind="primary"
+          data-size="small"
+          rel="noreferrer noopener"
+          role="button"
+          tabindex="0"
+        >
+          Encryption
+        </a>
+      </li>
+      <li>
+        <span
+          aria-current="page"
+          class="_last-page_ikpbb_39"
+        >
+          Change recovery key
+        </span>
+      </li>
+    </ol>
+  </nav>
+  <div
+    class="mx_EncryptionCard mx_ChangeRecoveryKey"
+  >
+    <div
+      class="mx_EncryptionCard_header"
+    >
+      <div
+        class="_content_md016_17"
+        data-size="large"
+      >
+        <svg
+          fill="currentColor"
+          height="1em"
+          viewBox="0 0 24 24"
+          width="1em"
+          xmlns="http://www.w3.org/2000/svg"
+        >
+          <path
+            d="M10.475 16.9A5.863 5.863 0 0 1 7 18c-1.667 0-3.083-.583-4.25-1.75C1.583 15.083 1 13.667 1 12c0-1.667.583-3.083 1.75-4.25C3.917 6.583 5.333 6 7 6c1.35 0 2.53.383 3.537 1.15 1.009.767 1.713 1.717 2.113 2.85h7.95a1.033 1.033 0 0 1 .725.3l1.025 1.025a.99.99 0 0 1 .2.288c.05.108.075.229.075.362a1.066 1.066 0 0 1-.25.7l-2.25 2.575a.973.973 0 0 1-1.038.313 1.033 1.033 0 0 1-.337-.188L17 14l-1.3 1.3c-.1.1-.208.17-.325.212a1.106 1.106 0 0 1-.375.063c-.133 0-.258-.02-.375-.063a.877.877 0 0 1-.325-.212L13 14h-.35a5.81 5.81 0 0 1-2.175 2.9Zm-4.887-3.487c.391.39.862.587 1.412.587.55 0 1.02-.196 1.412-.588C8.804 13.021 9 12.55 9 12c0-.55-.196-1.02-.588-1.412A1.926 1.926 0 0 0 7 10c-.55 0-1.02.196-1.412.588A1.926 1.926 0 0 0 5 12c0 .55.196 1.02.588 1.412Z"
+          />
+        </svg>
+      </div>
+      <h2
+        class="_typography_yh5dq_162 _font-heading-sm-semibold_yh5dq_102"
+      >
+        Change recovery key?
+      </h2>
+      <span>
+        Write down this new recovery key somewhere safe. Then click Continue to confirm the change.
+      </span>
+    </div>
+    <div
+      class="mx_KeyPanel"
+    >
+      <span
+        class="_typography_yh5dq_162 _font-body-md-medium_yh5dq_69"
+      >
+        Recovery key
+      </span>
+      <div>
+        <span
+          class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59 mx_KeyPanel_key"
+          data-testid="recoveryKey"
+        >
+          encoded private key
+        </span>
+        <span
+          class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40"
+        >
+          Do not share this with anyone!
+        </span>
+      </div>
+      <button
+        aria-label="Copy"
+        class="_icon-button_bh2qc_17"
+        role="button"
+        style="--cpd-icon-button-size: 28px;"
+        tabindex="0"
+      >
+        <div
+          class="_indicator-icon_133tf_26"
+          style="--cpd-icon-button-size: 100%;"
+        >
+          <svg
+            fill="currentColor"
+            height="1em"
+            viewBox="0 0 24 24"
+            width="1em"
+            xmlns="http://www.w3.org/2000/svg"
+          >
+            <path
+              d="M14 5H5v9h1a1 1 0 1 1 0 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1a1 1 0 1 1-2 0V5Z"
+            />
+            <path
+              d="M8 10a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-9a2 2 0 0 1-2-2v-9Zm2 0v9h9v-9h-9Z"
+            />
+          </svg>
+        </div>
+      </button>
+    </div>
+    <div
+      class="mx_ChangeRecoveryKey_footer"
+    >
+      <button
+        class="_button_i91xf_17"
+        data-kind="primary"
+        data-size="lg"
+        role="button"
+        tabindex="0"
+      >
+        Continue
+      </button>
+      <button
+        class="_button_i91xf_17"
+        data-kind="tertiary"
+        data-size="lg"
+        role="button"
+        tabindex="0"
+      >
+        Cancel
+      </button>
+    </div>
+  </div>
+</DocumentFragment>
+`;
+
+exports[`<ChangeRecoveryKey /> flow to setup a recovery key should ask the user to enter the recovery key 1`] = `
+<DocumentFragment>
+  <nav
+    class="_breadcrumb_ikpbb_17"
+  >
+    <button
+      aria-label="Back"
+      class="_icon-button_bh2qc_17 _subtle-bg_bh2qc_38"
+      role="button"
+      style="--cpd-icon-button-size: 28px;"
+      tabindex="0"
+    >
+      <div
+        class="_indicator-icon_133tf_26"
+        style="--cpd-icon-button-size: 100%;"
+      >
+        <svg
+          fill="currentColor"
+          height="1em"
+          viewBox="0 0 24 24"
+          width="1em"
+          xmlns="http://www.w3.org/2000/svg"
+        >
+          <path
+            d="m13.3 17.3-4.6-4.6a.877.877 0 0 1-.213-.325A1.106 1.106 0 0 1 8.425 12c0-.133.02-.258.062-.375A.878.878 0 0 1 8.7 11.3l4.6-4.6a.948.948 0 0 1 .7-.275.95.95 0 0 1 .7.275.948.948 0 0 1 .275.7.948.948 0 0 1-.275.7L10.8 12l3.9 3.9a.949.949 0 0 1 .275.7.948.948 0 0 1-.275.7.948.948 0 0 1-.7.275.948.948 0 0 1-.7-.275Z"
+          />
+        </svg>
+      </div>
+    </button>
+    <ol
+      class="_pages_ikpbb_26"
+    >
+      <li>
+        <a
+          class="_link_ue21z_17"
+          data-kind="primary"
+          data-size="small"
+          rel="noreferrer noopener"
+          role="button"
+          tabindex="0"
+        >
+          Encryption
+        </a>
+      </li>
+      <li>
+        <span
+          aria-current="page"
+          class="_last-page_ikpbb_39"
+        >
+          Set up recovery
+        </span>
+      </li>
+    </ol>
+  </nav>
+  <div
+    class="mx_EncryptionCard mx_ChangeRecoveryKey"
+  >
+    <div
+      class="mx_EncryptionCard_header"
+    >
+      <div
+        class="_content_md016_17"
+        data-size="large"
+      >
+        <svg
+          fill="currentColor"
+          height="1em"
+          viewBox="0 0 24 24"
+          width="1em"
+          xmlns="http://www.w3.org/2000/svg"
+        >
+          <path
+            d="M10.475 16.9A5.863 5.863 0 0 1 7 18c-1.667 0-3.083-.583-4.25-1.75C1.583 15.083 1 13.667 1 12c0-1.667.583-3.083 1.75-4.25C3.917 6.583 5.333 6 7 6c1.35 0 2.53.383 3.537 1.15 1.009.767 1.713 1.717 2.113 2.85h7.95a1.033 1.033 0 0 1 .725.3l1.025 1.025a.99.99 0 0 1 .2.288c.05.108.075.229.075.362a1.066 1.066 0 0 1-.25.7l-2.25 2.575a.973.973 0 0 1-1.038.313 1.033 1.033 0 0 1-.337-.188L17 14l-1.3 1.3c-.1.1-.208.17-.325.212a1.106 1.106 0 0 1-.375.063c-.133 0-.258-.02-.375-.063a.877.877 0 0 1-.325-.212L13 14h-.35a5.81 5.81 0 0 1-2.175 2.9Zm-4.887-3.487c.391.39.862.587 1.412.587.55 0 1.02-.196 1.412-.588C8.804 13.021 9 12.55 9 12c0-.55-.196-1.02-.588-1.412A1.926 1.926 0 0 0 7 10c-.55 0-1.02.196-1.412.588A1.926 1.926 0 0 0 5 12c0 .55.196 1.02.588 1.412Z"
+          />
+        </svg>
+      </div>
+      <h2
+        class="_typography_yh5dq_162 _font-heading-sm-semibold_yh5dq_102"
+      >
+        Enter your recovery key to confirm
+      </h2>
+      <span>
+        Enter the recovery key shown on the previous screen to finish setting up recovery.
+      </span>
+    </div>
+    <form
+      class="_root_ssths_24 mx_KeyForm"
+    >
+      <div
+        class="_field_ssths_34"
+      >
+        <label
+          class="_label_ssths_67"
+          for="radix-:r0:"
+        >
+          Enter recovery key
+        </label>
+        <input
+          class="_control_9gon8_18"
+          id="radix-:r0:"
+          name="recoveryKey"
+          required=""
+          title=""
+        />
+      </div>
+      <div
+        class="mx_ChangeRecoveryKey_footer"
+      >
+        <button
+          aria-disabled="true"
+          class="_button_i91xf_17"
+          data-kind="primary"
+          data-size="lg"
+          role="button"
+          tabindex="0"
+        >
+          Finish set up
+        </button>
+        <button
+          class="_button_i91xf_17"
+          data-kind="tertiary"
+          data-size="lg"
+          role="button"
+          tabindex="0"
+        >
+          Cancel
+        </button>
+      </div>
+    </form>
+  </div>
+</DocumentFragment>
+`;
+
+exports[`<ChangeRecoveryKey /> flow to setup a recovery key should ask the user to enter the recovery key 2`] = `
+<DocumentFragment>
+  <nav
+    class="_breadcrumb_ikpbb_17"
+  >
+    <button
+      aria-label="Back"
+      class="_icon-button_bh2qc_17 _subtle-bg_bh2qc_38"
+      role="button"
+      style="--cpd-icon-button-size: 28px;"
+      tabindex="0"
+    >
+      <div
+        class="_indicator-icon_133tf_26"
+        style="--cpd-icon-button-size: 100%;"
+      >
+        <svg
+          fill="currentColor"
+          height="1em"
+          viewBox="0 0 24 24"
+          width="1em"
+          xmlns="http://www.w3.org/2000/svg"
+        >
+          <path
+            d="m13.3 17.3-4.6-4.6a.877.877 0 0 1-.213-.325A1.106 1.106 0 0 1 8.425 12c0-.133.02-.258.062-.375A.878.878 0 0 1 8.7 11.3l4.6-4.6a.948.948 0 0 1 .7-.275.95.95 0 0 1 .7.275.948.948 0 0 1 .275.7.948.948 0 0 1-.275.7L10.8 12l3.9 3.9a.949.949 0 0 1 .275.7.948.948 0 0 1-.275.7.948.948 0 0 1-.7.275.948.948 0 0 1-.7-.275Z"
+          />
+        </svg>
+      </div>
+    </button>
+    <ol
+      class="_pages_ikpbb_26"
+    >
+      <li>
+        <a
+          class="_link_ue21z_17"
+          data-kind="primary"
+          data-size="small"
+          rel="noreferrer noopener"
+          role="button"
+          tabindex="0"
+        >
+          Encryption
+        </a>
+      </li>
+      <li>
+        <span
+          aria-current="page"
+          class="_last-page_ikpbb_39"
+        >
+          Set up recovery
+        </span>
+      </li>
+    </ol>
+  </nav>
+  <div
+    class="mx_EncryptionCard mx_ChangeRecoveryKey"
+  >
+    <div
+      class="mx_EncryptionCard_header"
+    >
+      <div
+        class="_content_md016_17"
+        data-size="large"
+      >
+        <svg
+          fill="currentColor"
+          height="1em"
+          viewBox="0 0 24 24"
+          width="1em"
+          xmlns="http://www.w3.org/2000/svg"
+        >
+          <path
+            d="M10.475 16.9A5.863 5.863 0 0 1 7 18c-1.667 0-3.083-.583-4.25-1.75C1.583 15.083 1 13.667 1 12c0-1.667.583-3.083 1.75-4.25C3.917 6.583 5.333 6 7 6c1.35 0 2.53.383 3.537 1.15 1.009.767 1.713 1.717 2.113 2.85h7.95a1.033 1.033 0 0 1 .725.3l1.025 1.025a.99.99 0 0 1 .2.288c.05.108.075.229.075.362a1.066 1.066 0 0 1-.25.7l-2.25 2.575a.973.973 0 0 1-1.038.313 1.033 1.033 0 0 1-.337-.188L17 14l-1.3 1.3c-.1.1-.208.17-.325.212a1.106 1.106 0 0 1-.375.063c-.133 0-.258-.02-.375-.063a.877.877 0 0 1-.325-.212L13 14h-.35a5.81 5.81 0 0 1-2.175 2.9Zm-4.887-3.487c.391.39.862.587 1.412.587.55 0 1.02-.196 1.412-.588C8.804 13.021 9 12.55 9 12c0-.55-.196-1.02-.588-1.412A1.926 1.926 0 0 0 7 10c-.55 0-1.02.196-1.412.588A1.926 1.926 0 0 0 5 12c0 .55.196 1.02.588 1.412Z"
+          />
+        </svg>
+      </div>
+      <h2
+        class="_typography_yh5dq_162 _font-heading-sm-semibold_yh5dq_102"
+      >
+        Enter your recovery key to confirm
+      </h2>
+      <span>
+        Enter the recovery key shown on the previous screen to finish setting up recovery.
+      </span>
+    </div>
+    <form
+      class="_root_ssths_24 mx_KeyForm"
+    >
+      <div
+        class="_field_ssths_34"
+        data-invalid="true"
+      >
+        <label
+          class="_label_ssths_67"
+          data-invalid="true"
+          for="radix-:r0:"
+        >
+          Enter recovery key
+        </label>
+        <input
+          aria-describedby="radix-:r1:"
+          aria-invalid="true"
+          class="_control_9gon8_18"
+          data-invalid="true"
+          id="radix-:r0:"
+          name="recoveryKey"
+          required=""
+          title=""
+        />
+        <span
+          class="_message_ssths_93 _error-message_ssths_103"
+          id="radix-:r1:"
+        >
+          <svg
+            fill="currentColor"
+            height="1em"
+            viewBox="0 0 24 24"
+            width="1em"
+            xmlns="http://www.w3.org/2000/svg"
+          >
+            <path
+              d="M12 17a.97.97 0 0 0 .713-.288A.968.968 0 0 0 13 16a.968.968 0 0 0-.287-.713A.968.968 0 0 0 12 15a.968.968 0 0 0-.713.287A.968.968 0 0 0 11 16c0 .283.096.52.287.712.192.192.43.288.713.288Zm0-4c.283 0 .52-.096.713-.287A.968.968 0 0 0 13 12V8a.967.967 0 0 0-.287-.713A.968.968 0 0 0 12 7a.968.968 0 0 0-.713.287A.967.967 0 0 0 11 8v4c0 .283.096.52.287.713.192.191.43.287.713.287Zm0 9a9.738 9.738 0 0 1-3.9-.788 10.099 10.099 0 0 1-3.175-2.137c-.9-.9-1.612-1.958-2.137-3.175A9.738 9.738 0 0 1 2 12a9.74 9.74 0 0 1 .788-3.9 10.099 10.099 0 0 1 2.137-3.175c.9-.9 1.958-1.612 3.175-2.137A9.738 9.738 0 0 1 12 2a9.74 9.74 0 0 1 3.9.788 10.098 10.098 0 0 1 3.175 2.137c.9.9 1.613 1.958 2.137 3.175A9.738 9.738 0 0 1 22 12a9.738 9.738 0 0 1-.788 3.9 10.098 10.098 0 0 1-2.137 3.175c-.9.9-1.958 1.613-3.175 2.137A9.738 9.738 0 0 1 12 22Z"
+            />
+          </svg>
+          The recovery key you entered is not correct.
+        </span>
+      </div>
+      <div
+        class="mx_ChangeRecoveryKey_footer"
+      >
+        <button
+          aria-disabled="true"
+          class="_button_i91xf_17"
+          data-kind="primary"
+          data-size="lg"
+          role="button"
+          tabindex="0"
+        >
+          Finish set up
+        </button>
+        <button
+          class="_button_i91xf_17"
+          data-kind="tertiary"
+          data-size="lg"
+          role="button"
+          tabindex="0"
+        >
+          Cancel
+        </button>
+      </div>
+    </form>
+  </div>
+</DocumentFragment>
+`;
+
+exports[`<ChangeRecoveryKey /> flow to setup a recovery key should display information about the recovery key 1`] = `
+<DocumentFragment>
+  <nav
+    class="_breadcrumb_ikpbb_17"
+  >
+    <button
+      aria-label="Back"
+      class="_icon-button_bh2qc_17 _subtle-bg_bh2qc_38"
+      role="button"
+      style="--cpd-icon-button-size: 28px;"
+      tabindex="0"
+    >
+      <div
+        class="_indicator-icon_133tf_26"
+        style="--cpd-icon-button-size: 100%;"
+      >
+        <svg
+          fill="currentColor"
+          height="1em"
+          viewBox="0 0 24 24"
+          width="1em"
+          xmlns="http://www.w3.org/2000/svg"
+        >
+          <path
+            d="m13.3 17.3-4.6-4.6a.877.877 0 0 1-.213-.325A1.106 1.106 0 0 1 8.425 12c0-.133.02-.258.062-.375A.878.878 0 0 1 8.7 11.3l4.6-4.6a.948.948 0 0 1 .7-.275.95.95 0 0 1 .7.275.948.948 0 0 1 .275.7.948.948 0 0 1-.275.7L10.8 12l3.9 3.9a.949.949 0 0 1 .275.7.948.948 0 0 1-.275.7.948.948 0 0 1-.7.275.948.948 0 0 1-.7-.275Z"
+          />
+        </svg>
+      </div>
+    </button>
+    <ol
+      class="_pages_ikpbb_26"
+    >
+      <li>
+        <a
+          class="_link_ue21z_17"
+          data-kind="primary"
+          data-size="small"
+          rel="noreferrer noopener"
+          role="button"
+          tabindex="0"
+        >
+          Encryption
+        </a>
+      </li>
+      <li>
+        <span
+          aria-current="page"
+          class="_last-page_ikpbb_39"
+        >
+          Set up recovery
+        </span>
+      </li>
+    </ol>
+  </nav>
+  <div
+    class="mx_EncryptionCard mx_ChangeRecoveryKey"
+  >
+    <div
+      class="mx_EncryptionCard_header"
+    >
+      <div
+        class="_content_md016_17"
+        data-size="large"
+      >
+        <svg
+          fill="currentColor"
+          height="1em"
+          viewBox="0 0 24 24"
+          width="1em"
+          xmlns="http://www.w3.org/2000/svg"
+        >
+          <path
+            d="M10.475 16.9A5.863 5.863 0 0 1 7 18c-1.667 0-3.083-.583-4.25-1.75C1.583 15.083 1 13.667 1 12c0-1.667.583-3.083 1.75-4.25C3.917 6.583 5.333 6 7 6c1.35 0 2.53.383 3.537 1.15 1.009.767 1.713 1.717 2.113 2.85h7.95a1.033 1.033 0 0 1 .725.3l1.025 1.025a.99.99 0 0 1 .2.288c.05.108.075.229.075.362a1.066 1.066 0 0 1-.25.7l-2.25 2.575a.973.973 0 0 1-1.038.313 1.033 1.033 0 0 1-.337-.188L17 14l-1.3 1.3c-.1.1-.208.17-.325.212a1.106 1.106 0 0 1-.375.063c-.133 0-.258-.02-.375-.063a.877.877 0 0 1-.325-.212L13 14h-.35a5.81 5.81 0 0 1-2.175 2.9Zm-4.887-3.487c.391.39.862.587 1.412.587.55 0 1.02-.196 1.412-.588C8.804 13.021 9 12.55 9 12c0-.55-.196-1.02-.588-1.412A1.926 1.926 0 0 0 7 10c-.55 0-1.02.196-1.412.588A1.926 1.926 0 0 0 5 12c0 .55.196 1.02.588 1.412Z"
+          />
+        </svg>
+      </div>
+      <h2
+        class="_typography_yh5dq_162 _font-heading-sm-semibold_yh5dq_102"
+      >
+        Set up recovery
+      </h2>
+      <span>
+        Your key storage is protected by a recovery key. If you need a new recovery key after setup, you can recreate it by selecting ‘Change recovery key’.
+      </span>
+    </div>
+    <span
+      class="_typography_yh5dq_162 _font-body-md-medium_yh5dq_69 mx_InformationPanel_description"
+    >
+      After clicking continue, we’ll generate a recovery key for you.
+    </span>
+    <div
+      class="mx_ChangeRecoveryKey_footer"
+    >
+      <button
+        class="_button_i91xf_17"
+        data-kind="primary"
+        data-size="lg"
+        role="button"
+        tabindex="0"
+      >
+        Continue
+      </button>
+      <button
+        class="_button_i91xf_17"
+        data-kind="tertiary"
+        data-size="lg"
+        role="button"
+        tabindex="0"
+      >
+        Cancel
+      </button>
+    </div>
+  </div>
+</DocumentFragment>
+`;
+
+exports[`<ChangeRecoveryKey /> flow to setup a recovery key should display the recovery key 1`] = `
+<DocumentFragment>
+  <nav
+    class="_breadcrumb_ikpbb_17"
+  >
+    <button
+      aria-label="Back"
+      class="_icon-button_bh2qc_17 _subtle-bg_bh2qc_38"
+      role="button"
+      style="--cpd-icon-button-size: 28px;"
+      tabindex="0"
+    >
+      <div
+        class="_indicator-icon_133tf_26"
+        style="--cpd-icon-button-size: 100%;"
+      >
+        <svg
+          fill="currentColor"
+          height="1em"
+          viewBox="0 0 24 24"
+          width="1em"
+          xmlns="http://www.w3.org/2000/svg"
+        >
+          <path
+            d="m13.3 17.3-4.6-4.6a.877.877 0 0 1-.213-.325A1.106 1.106 0 0 1 8.425 12c0-.133.02-.258.062-.375A.878.878 0 0 1 8.7 11.3l4.6-4.6a.948.948 0 0 1 .7-.275.95.95 0 0 1 .7.275.948.948 0 0 1 .275.7.948.948 0 0 1-.275.7L10.8 12l3.9 3.9a.949.949 0 0 1 .275.7.948.948 0 0 1-.275.7.948.948 0 0 1-.7.275.948.948 0 0 1-.7-.275Z"
+          />
+        </svg>
+      </div>
+    </button>
+    <ol
+      class="_pages_ikpbb_26"
+    >
+      <li>
+        <a
+          class="_link_ue21z_17"
+          data-kind="primary"
+          data-size="small"
+          rel="noreferrer noopener"
+          role="button"
+          tabindex="0"
+        >
+          Encryption
+        </a>
+      </li>
+      <li>
+        <span
+          aria-current="page"
+          class="_last-page_ikpbb_39"
+        >
+          Set up recovery
+        </span>
+      </li>
+    </ol>
+  </nav>
+  <div
+    class="mx_EncryptionCard mx_ChangeRecoveryKey"
+  >
+    <div
+      class="mx_EncryptionCard_header"
+    >
+      <div
+        class="_content_md016_17"
+        data-size="large"
+      >
+        <svg
+          fill="currentColor"
+          height="1em"
+          viewBox="0 0 24 24"
+          width="1em"
+          xmlns="http://www.w3.org/2000/svg"
+        >
+          <path
+            d="M10.475 16.9A5.863 5.863 0 0 1 7 18c-1.667 0-3.083-.583-4.25-1.75C1.583 15.083 1 13.667 1 12c0-1.667.583-3.083 1.75-4.25C3.917 6.583 5.333 6 7 6c1.35 0 2.53.383 3.537 1.15 1.009.767 1.713 1.717 2.113 2.85h7.95a1.033 1.033 0 0 1 .725.3l1.025 1.025a.99.99 0 0 1 .2.288c.05.108.075.229.075.362a1.066 1.066 0 0 1-.25.7l-2.25 2.575a.973.973 0 0 1-1.038.313 1.033 1.033 0 0 1-.337-.188L17 14l-1.3 1.3c-.1.1-.208.17-.325.212a1.106 1.106 0 0 1-.375.063c-.133 0-.258-.02-.375-.063a.877.877 0 0 1-.325-.212L13 14h-.35a5.81 5.81 0 0 1-2.175 2.9Zm-4.887-3.487c.391.39.862.587 1.412.587.55 0 1.02-.196 1.412-.588C8.804 13.021 9 12.55 9 12c0-.55-.196-1.02-.588-1.412A1.926 1.926 0 0 0 7 10c-.55 0-1.02.196-1.412.588A1.926 1.926 0 0 0 5 12c0 .55.196 1.02.588 1.412Z"
+          />
+        </svg>
+      </div>
+      <h2
+        class="_typography_yh5dq_162 _font-heading-sm-semibold_yh5dq_102"
+      >
+        Save your recovery key somewhere safe
+      </h2>
+      <span>
+        Write down this recovery key somewhere safe, like a password manager, encrypted note, or a physical safe.
+      </span>
+    </div>
+    <div
+      class="mx_KeyPanel"
+    >
+      <span
+        class="_typography_yh5dq_162 _font-body-md-medium_yh5dq_69"
+      >
+        Recovery key
+      </span>
+      <div>
+        <span
+          class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59 mx_KeyPanel_key"
+          data-testid="recoveryKey"
+        >
+          encoded private key
+        </span>
+        <span
+          class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40"
+        >
+          Do not share this with anyone!
+        </span>
+      </div>
+      <button
+        aria-label="Copy"
+        class="_icon-button_bh2qc_17"
+        role="button"
+        style="--cpd-icon-button-size: 28px;"
+        tabindex="0"
+      >
+        <div
+          class="_indicator-icon_133tf_26"
+          style="--cpd-icon-button-size: 100%;"
+        >
+          <svg
+            fill="currentColor"
+            height="1em"
+            viewBox="0 0 24 24"
+            width="1em"
+            xmlns="http://www.w3.org/2000/svg"
+          >
+            <path
+              d="M14 5H5v9h1a1 1 0 1 1 0 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1a1 1 0 1 1-2 0V5Z"
+            />
+            <path
+              d="M8 10a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-9a2 2 0 0 1-2-2v-9Zm2 0v9h9v-9h-9Z"
+            />
+          </svg>
+        </div>
+      </button>
+    </div>
+    <div
+      class="mx_ChangeRecoveryKey_footer"
+    >
+      <button
+        class="_button_i91xf_17"
+        data-kind="primary"
+        data-size="lg"
+        role="button"
+        tabindex="0"
+      >
+        Continue
+      </button>
+      <button
+        class="_button_i91xf_17"
+        data-kind="tertiary"
+        data-size="lg"
+        role="button"
+        tabindex="0"
+      >
+        Cancel
+      </button>
+    </div>
+  </div>
+</DocumentFragment>
+`;
diff --git a/test/unit-tests/components/views/settings/encryption/__snapshots__/EncryptionCard-test.tsx.snap b/test/unit-tests/components/views/settings/encryption/__snapshots__/EncryptionCard-test.tsx.snap
new file mode 100644
index 00000000000..e523e57c090
--- /dev/null
+++ b/test/unit-tests/components/views/settings/encryption/__snapshots__/EncryptionCard-test.tsx.snap
@@ -0,0 +1,39 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`<EncryptionCard /> should render 1`] = `
+<DocumentFragment>
+  <div
+    class="mx_EncryptionCard"
+  >
+    <div
+      class="mx_EncryptionCard_header"
+    >
+      <div
+        class="_content_md016_17"
+        data-size="large"
+      >
+        <svg
+          fill="currentColor"
+          height="1em"
+          viewBox="0 0 24 24"
+          width="1em"
+          xmlns="http://www.w3.org/2000/svg"
+        >
+          <path
+            d="M10.475 16.9A5.863 5.863 0 0 1 7 18c-1.667 0-3.083-.583-4.25-1.75C1.583 15.083 1 13.667 1 12c0-1.667.583-3.083 1.75-4.25C3.917 6.583 5.333 6 7 6c1.35 0 2.53.383 3.537 1.15 1.009.767 1.713 1.717 2.113 2.85h7.95a1.033 1.033 0 0 1 .725.3l1.025 1.025a.99.99 0 0 1 .2.288c.05.108.075.229.075.362a1.066 1.066 0 0 1-.25.7l-2.25 2.575a.973.973 0 0 1-1.038.313 1.033 1.033 0 0 1-.337-.188L17 14l-1.3 1.3c-.1.1-.208.17-.325.212a1.106 1.106 0 0 1-.375.063c-.133 0-.258-.02-.375-.063a.877.877 0 0 1-.325-.212L13 14h-.35a5.81 5.81 0 0 1-2.175 2.9Zm-4.887-3.487c.391.39.862.587 1.412.587.55 0 1.02-.196 1.412-.588C8.804 13.021 9 12.55 9 12c0-.55-.196-1.02-.588-1.412A1.926 1.926 0 0 0 7 10c-.55 0-1.02.196-1.412.588A1.926 1.926 0 0 0 5 12c0 .55.196 1.02.588 1.412Z"
+          />
+        </svg>
+      </div>
+      <h2
+        class="_typography_yh5dq_162 _font-heading-sm-semibold_yh5dq_102"
+      >
+        My title
+      </h2>
+      <span>
+        My description
+      </span>
+    </div>
+    Encryption card children
+  </div>
+</DocumentFragment>
+`;
diff --git a/test/unit-tests/components/views/settings/encryption/__snapshots__/RecoveryPanel-test.tsx.snap b/test/unit-tests/components/views/settings/encryption/__snapshots__/RecoveryPanel-test.tsx.snap
new file mode 100644
index 00000000000..5030eb02cc9
--- /dev/null
+++ b/test/unit-tests/components/views/settings/encryption/__snapshots__/RecoveryPanel-test.tsx.snap
@@ -0,0 +1,179 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`<RecoveryPanel /> should allow to change the recovery key when everything is good 1`] = `
+<DocumentFragment>
+  <div
+    class="mx_SettingsSection mx_SettingsSection_newUi"
+  >
+    <div
+      class="mx_SettingsSection_header"
+    >
+      <h2
+        class="_typography_yh5dq_162 _font-heading-sm-semibold_yh5dq_102 mx_SettingsHeader"
+      >
+        Recovery 
+      </h2>
+      Recover your cryptographic identity and message history with a recovery key if you’ve lost all your existing devices.
+    </div>
+    <button
+      class="_button_i91xf_17 _has-icon_i91xf_66"
+      data-kind="secondary"
+      data-size="sm"
+      role="button"
+      tabindex="0"
+    >
+      <svg
+        aria-hidden="true"
+        fill="currentColor"
+        height="20"
+        viewBox="0 0 24 24"
+        width="20"
+        xmlns="http://www.w3.org/2000/svg"
+      >
+        <path
+          d="M7 14c-.55 0-1.02-.196-1.412-.588A1.926 1.926 0 0 1 5 12c0-.55.196-1.02.588-1.412A1.926 1.926 0 0 1 7 10c.55 0 1.02.196 1.412.588.392.391.588.862.588 1.412 0 .55-.196 1.02-.588 1.412A1.926 1.926 0 0 1 7 14Zm0 4c-1.667 0-3.083-.583-4.25-1.75C1.583 15.083 1 13.667 1 12c0-1.667.583-3.083 1.75-4.25C3.917 6.583 5.333 6 7 6c1.117 0 2.13.275 3.037.825A6.212 6.212 0 0 1 12.2 9h8.375a1.033 1.033 0 0 1 .725.3l2 2c.1.1.17.208.212.325.042.117.063.242.063.375s-.02.258-.063.375a.877.877 0 0 1-.212.325l-3.175 3.175a.946.946 0 0 1-.3.2c-.117.05-.233.083-.35.1a.832.832 0 0 1-.35-.025.884.884 0 0 1-.325-.175L17.5 15l-1.425 1.075a.945.945 0 0 1-.887.15.859.859 0 0 1-.288-.15L13.375 15H12.2a6.212 6.212 0 0 1-2.162 2.175C9.128 17.725 8.117 18 7 18Zm0-2c.933 0 1.754-.283 2.463-.85A4.032 4.032 0 0 0 10.875 13H14l1.45 1.025L17.5 12.5l1.775 1.375L21.15 12l-1-1h-9.275a4.032 4.032 0 0 0-1.412-2.15C8.754 8.283 7.933 8 7 8c-1.1 0-2.042.392-2.825 1.175C3.392 9.958 3 10.9 3 12s.392 2.042 1.175 2.825C4.958 15.608 5.9 16 7 16Z"
+        />
+      </svg>
+      Change recovery key
+    </button>
+  </div>
+</DocumentFragment>
+`;
+
+exports[`<RecoveryPanel /> should ask to enter the recovery key when secrets are not cached 1`] = `
+<DocumentFragment>
+  <div
+    class="mx_SettingsSection mx_SettingsSection_newUi"
+  >
+    <div
+      class="mx_SettingsSection_header"
+    >
+      <h2
+        class="_typography_yh5dq_162 _font-heading-sm-semibold_yh5dq_102 mx_SettingsHeader"
+      >
+        Recovery 
+      </h2>
+      <div
+        class="mx_SettingsSubheader"
+      >
+        Recover your cryptographic identity and message history with a recovery key if you’ve lost all your existing devices.
+        <span
+          class="mx_SettingsSubheader_error"
+        >
+          <svg
+            fill="currentColor"
+            height="20px"
+            viewBox="0 0 24 24"
+            width="20px"
+            xmlns="http://www.w3.org/2000/svg"
+          >
+            <path
+              d="M12 17a.97.97 0 0 0 .713-.288A.968.968 0 0 0 13 16a.968.968 0 0 0-.287-.713A.968.968 0 0 0 12 15a.968.968 0 0 0-.713.287A.968.968 0 0 0 11 16c0 .283.096.52.287.712.192.192.43.288.713.288Zm0-4c.283 0 .52-.096.713-.287A.968.968 0 0 0 13 12V8a.967.967 0 0 0-.287-.713A.968.968 0 0 0 12 7a.968.968 0 0 0-.713.287A.967.967 0 0 0 11 8v4c0 .283.096.52.287.713.192.191.43.287.713.287Zm0 9a9.738 9.738 0 0 1-3.9-.788 10.099 10.099 0 0 1-3.175-2.137c-.9-.9-1.612-1.958-2.137-3.175A9.738 9.738 0 0 1 2 12a9.74 9.74 0 0 1 .788-3.9 10.099 10.099 0 0 1 2.137-3.175c.9-.9 1.958-1.612 3.175-2.137A9.738 9.738 0 0 1 12 2a9.74 9.74 0 0 1 3.9.788 10.098 10.098 0 0 1 3.175 2.137c.9.9 1.613 1.958 2.137 3.175A9.738 9.738 0 0 1 22 12a9.738 9.738 0 0 1-.788 3.9 10.098 10.098 0 0 1-2.137 3.175c-.9.9-1.958 1.613-3.175 2.137A9.738 9.738 0 0 1 12 22Z"
+            />
+          </svg>
+          Your key storage is out of sync. Click the button below to fix the problem.
+        </span>
+      </div>
+    </div>
+    <button
+      class="_button_i91xf_17 _has-icon_i91xf_66"
+      data-kind="primary"
+      data-size="sm"
+      role="button"
+      tabindex="0"
+    >
+      <svg
+        aria-hidden="true"
+        fill="currentColor"
+        height="20"
+        viewBox="0 0 24 24"
+        width="20"
+        xmlns="http://www.w3.org/2000/svg"
+      >
+        <path
+          d="M7 14c-.55 0-1.02-.196-1.412-.588A1.926 1.926 0 0 1 5 12c0-.55.196-1.02.588-1.412A1.926 1.926 0 0 1 7 10c.55 0 1.02.196 1.412.588.392.391.588.862.588 1.412 0 .55-.196 1.02-.588 1.412A1.926 1.926 0 0 1 7 14Zm0 4c-1.667 0-3.083-.583-4.25-1.75C1.583 15.083 1 13.667 1 12c0-1.667.583-3.083 1.75-4.25C3.917 6.583 5.333 6 7 6c1.117 0 2.13.275 3.037.825A6.212 6.212 0 0 1 12.2 9h8.375a1.033 1.033 0 0 1 .725.3l2 2c.1.1.17.208.212.325.042.117.063.242.063.375s-.02.258-.063.375a.877.877 0 0 1-.212.325l-3.175 3.175a.946.946 0 0 1-.3.2c-.117.05-.233.083-.35.1a.832.832 0 0 1-.35-.025.884.884 0 0 1-.325-.175L17.5 15l-1.425 1.075a.945.945 0 0 1-.887.15.859.859 0 0 1-.288-.15L13.375 15H12.2a6.212 6.212 0 0 1-2.162 2.175C9.128 17.725 8.117 18 7 18Zm0-2c.933 0 1.754-.283 2.463-.85A4.032 4.032 0 0 0 10.875 13H14l1.45 1.025L17.5 12.5l1.775 1.375L21.15 12l-1-1h-9.275a4.032 4.032 0 0 0-1.412-2.15C8.754 8.283 7.933 8 7 8c-1.1 0-2.042.392-2.825 1.175C3.392 9.958 3 10.9 3 12s.392 2.042 1.175 2.825C4.958 15.608 5.9 16 7 16Z"
+        />
+      </svg>
+      Enter recovery key
+    </button>
+  </div>
+</DocumentFragment>
+`;
+
+exports[`<RecoveryPanel /> should ask to set up a recovery key when there is no recovery key 1`] = `
+<DocumentFragment>
+  <div
+    class="mx_SettingsSection mx_SettingsSection_newUi"
+  >
+    <div
+      class="mx_SettingsSection_header"
+    >
+      <h2
+        class="_typography_yh5dq_162 _font-heading-sm-semibold_yh5dq_102 mx_SettingsHeader"
+      >
+        Recovery 
+        <span>
+          Recommended
+        </span>
+      </h2>
+      Recover your cryptographic identity and message history with a recovery key if you’ve lost all your existing devices.
+    </div>
+    <button
+      class="_button_i91xf_17 _has-icon_i91xf_66"
+      data-kind="primary"
+      data-size="sm"
+      role="button"
+      tabindex="0"
+    >
+      <svg
+        aria-hidden="true"
+        fill="currentColor"
+        height="20"
+        viewBox="0 0 24 24"
+        width="20"
+        xmlns="http://www.w3.org/2000/svg"
+      >
+        <path
+          d="M7 14c-.55 0-1.02-.196-1.412-.588A1.926 1.926 0 0 1 5 12c0-.55.196-1.02.588-1.412A1.926 1.926 0 0 1 7 10c.55 0 1.02.196 1.412.588.392.391.588.862.588 1.412 0 .55-.196 1.02-.588 1.412A1.926 1.926 0 0 1 7 14Zm0 4c-1.667 0-3.083-.583-4.25-1.75C1.583 15.083 1 13.667 1 12c0-1.667.583-3.083 1.75-4.25C3.917 6.583 5.333 6 7 6c1.117 0 2.13.275 3.037.825A6.212 6.212 0 0 1 12.2 9h8.375a1.033 1.033 0 0 1 .725.3l2 2c.1.1.17.208.212.325.042.117.063.242.063.375s-.02.258-.063.375a.877.877 0 0 1-.212.325l-3.175 3.175a.946.946 0 0 1-.3.2c-.117.05-.233.083-.35.1a.832.832 0 0 1-.35-.025.884.884 0 0 1-.325-.175L17.5 15l-1.425 1.075a.945.945 0 0 1-.887.15.859.859 0 0 1-.288-.15L13.375 15H12.2a6.212 6.212 0 0 1-2.162 2.175C9.128 17.725 8.117 18 7 18Zm0-2c.933 0 1.754-.283 2.463-.85A4.032 4.032 0 0 0 10.875 13H14l1.45 1.025L17.5 12.5l1.775 1.375L21.15 12l-1-1h-9.275a4.032 4.032 0 0 0-1.412-2.15C8.754 8.283 7.933 8 7 8c-1.1 0-2.042.392-2.825 1.175C3.392 9.958 3 10.9 3 12s.392 2.042 1.175 2.825C4.958 15.608 5.9 16 7 16Z"
+        />
+      </svg>
+      Set up recovery
+    </button>
+  </div>
+</DocumentFragment>
+`;
+
+exports[`<RecoveryPanel /> should be in loading state when checking the recovery key and the cached keys 1`] = `
+<DocumentFragment>
+  <div
+    class="mx_SettingsSection mx_SettingsSection_newUi"
+  >
+    <div
+      class="mx_SettingsSection_header"
+    >
+      <h2
+        class="_typography_yh5dq_162 _font-heading-sm-semibold_yh5dq_102 mx_SettingsHeader"
+      >
+        Recovery 
+      </h2>
+      Recover your cryptographic identity and message history with a recovery key if you’ve lost all your existing devices.
+    </div>
+    <svg
+      aria-label="Loading…"
+      class="_icon_1ye7b_27"
+      fill="currentColor"
+      height="1em"
+      style="width: 20px; height: 20px;"
+      viewBox="0 0 24 24"
+      width="1em"
+      xmlns="http://www.w3.org/2000/svg"
+    >
+      <path
+        clip-rule="evenodd"
+        d="M12 4.031a8 8 0 1 0 8 8 1 1 0 0 1 2 0c0 5.523-4.477 10-10 10s-10-4.477-10-10 4.477-10 10-10a1 1 0 1 1 0 2Z"
+        fill-rule="evenodd"
+      />
+    </svg>
+  </div>
+</DocumentFragment>
+`;
diff --git a/test/unit-tests/components/views/settings/notifications/Notifications2-test.tsx b/test/unit-tests/components/views/settings/notifications/Notifications2-test.tsx
index 2507aa173f9..24441689a24 100644
--- a/test/unit-tests/components/views/settings/notifications/Notifications2-test.tsx
+++ b/test/unit-tests/components/views/settings/notifications/Notifications2-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022, 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/settings/shared/SettingsSubsection-test.tsx b/test/unit-tests/components/views/settings/shared/SettingsSubsection-test.tsx
index 428954e78ca..9f921552cfb 100644
--- a/test/unit-tests/components/views/settings/shared/SettingsSubsection-test.tsx
+++ b/test/unit-tests/components/views/settings/shared/SettingsSubsection-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/settings/shared/SettingsSubsectionHeading-test.tsx b/test/unit-tests/components/views/settings/shared/SettingsSubsectionHeading-test.tsx
index b1c36542add..cdf1fd9e88e 100644
--- a/test/unit-tests/components/views/settings/shared/SettingsSubsectionHeading-test.tsx
+++ b/test/unit-tests/components/views/settings/shared/SettingsSubsectionHeading-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/settings/tabs/SettingsTab-test.tsx b/test/unit-tests/components/views/settings/tabs/SettingsTab-test.tsx
index a1257ef9dc4..ff4d781e482 100644
--- a/test/unit-tests/components/views/settings/tabs/SettingsTab-test.tsx
+++ b/test/unit-tests/components/views/settings/tabs/SettingsTab-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/settings/tabs/room/AdvancedRoomSettingsTab-test.tsx b/test/unit-tests/components/views/settings/tabs/room/AdvancedRoomSettingsTab-test.tsx
index b6d62973c77..b19424f1923 100644
--- a/test/unit-tests/components/views/settings/tabs/room/AdvancedRoomSettingsTab-test.tsx
+++ b/test/unit-tests/components/views/settings/tabs/room/AdvancedRoomSettingsTab-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/settings/tabs/room/BridgeSettingsTab-test.tsx b/test/unit-tests/components/views/settings/tabs/room/BridgeSettingsTab-test.tsx
index af04ba410d7..298d4502c33 100644
--- a/test/unit-tests/components/views/settings/tabs/room/BridgeSettingsTab-test.tsx
+++ b/test/unit-tests/components/views/settings/tabs/room/BridgeSettingsTab-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/settings/tabs/room/NotificationSettingsTab-test.tsx b/test/unit-tests/components/views/settings/tabs/room/NotificationSettingsTab-test.tsx
index abb78bfcda7..47e95653295 100644
--- a/test/unit-tests/components/views/settings/tabs/room/NotificationSettingsTab-test.tsx
+++ b/test/unit-tests/components/views/settings/tabs/room/NotificationSettingsTab-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/settings/tabs/room/PeopleRoomSettingsTab-test.tsx b/test/unit-tests/components/views/settings/tabs/room/PeopleRoomSettingsTab-test.tsx
index 4527cbe2e35..c5fa2d8fe49 100644
--- a/test/unit-tests/components/views/settings/tabs/room/PeopleRoomSettingsTab-test.tsx
+++ b/test/unit-tests/components/views/settings/tabs/room/PeopleRoomSettingsTab-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 Nordeck IT + Consulting GmbH
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/settings/tabs/room/RolesRoomSettingsTab-test.tsx b/test/unit-tests/components/views/settings/tabs/room/RolesRoomSettingsTab-test.tsx
index e1a451c9d57..6d3d6881126 100644
--- a/test/unit-tests/components/views/settings/tabs/room/RolesRoomSettingsTab-test.tsx
+++ b/test/unit-tests/components/views/settings/tabs/room/RolesRoomSettingsTab-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -69,7 +69,7 @@ describe("RolesRoomSettingsTab", () => {
 
     describe("Element Call", () => {
         const setGroupCallsEnabled = (val: boolean): void => {
-            jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string) => {
+            jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string): any => {
                 if (name === "feature_group_calls") return val;
             });
         };
diff --git a/test/unit-tests/components/views/settings/tabs/room/SecurityRoomSettingsTab-test.tsx b/test/unit-tests/components/views/settings/tabs/room/SecurityRoomSettingsTab-test.tsx
index 5fc10714e6d..bb5300fc03d 100644
--- a/test/unit-tests/components/views/settings/tabs/room/SecurityRoomSettingsTab-test.tsx
+++ b/test/unit-tests/components/views/settings/tabs/room/SecurityRoomSettingsTab-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/settings/tabs/room/VoipRoomSettingsTab-test.tsx b/test/unit-tests/components/views/settings/tabs/room/VoipRoomSettingsTab-test.tsx
index c6e01242494..8e244999ade 100644
--- a/test/unit-tests/components/views/settings/tabs/room/VoipRoomSettingsTab-test.tsx
+++ b/test/unit-tests/components/views/settings/tabs/room/VoipRoomSettingsTab-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/settings/tabs/user/AccountUserSettingsTab-test.tsx b/test/unit-tests/components/views/settings/tabs/user/AccountUserSettingsTab-test.tsx
index 00a92a0fad2..18ad320b02e 100644
--- a/test/unit-tests/components/views/settings/tabs/user/AccountUserSettingsTab-test.tsx
+++ b/test/unit-tests/components/views/settings/tabs/user/AccountUserSettingsTab-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -114,7 +114,7 @@ describe("<AccountUserSettingsTab />", () => {
         expect(manageAccountLink.getAttribute("href")).toMatch(accountManagementLink);
     });
 
-    describe("deactive account", () => {
+    describe("deactivate account", () => {
         it("should not render section when account deactivation feature is disabled", () => {
             jest.spyOn(SettingsStore, "getValue").mockImplementation(
                 (settingName) => settingName !== UIFeature.Deactivate,
@@ -198,6 +198,11 @@ describe("<AccountUserSettingsTab />", () => {
 
     describe("3pids", () => {
         beforeEach(() => {
+            const mockOidcClientStore = {
+                accountManagementEndpoint: undefined,
+            } as unknown as OidcClientStore;
+            jest.spyOn(stores, "oidcClientStore", "get").mockReturnValue(mockOidcClientStore);
+
             mockClient.getCapabilities.mockResolvedValue({
                 "m.3pid_changes": {
                     enabled: true,
diff --git a/test/unit-tests/components/views/settings/tabs/user/AppearanceUserSettingsTab-test.tsx b/test/unit-tests/components/views/settings/tabs/user/AppearanceUserSettingsTab-test.tsx
index 9933fba6489..81ea6356098 100644
--- a/test/unit-tests/components/views/settings/tabs/user/AppearanceUserSettingsTab-test.tsx
+++ b/test/unit-tests/components/views/settings/tabs/user/AppearanceUserSettingsTab-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/settings/tabs/user/EncryptionUserSettingsTab-test.tsx b/test/unit-tests/components/views/settings/tabs/user/EncryptionUserSettingsTab-test.tsx
new file mode 100644
index 00000000000..49ce1404216
--- /dev/null
+++ b/test/unit-tests/components/views/settings/tabs/user/EncryptionUserSettingsTab-test.tsx
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2024 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+import React from "react";
+import { render, screen } from "jest-matrix-react";
+import { MatrixClient } from "matrix-js-sdk/src/matrix";
+import { waitFor } from "@testing-library/dom";
+import userEvent from "@testing-library/user-event";
+
+import { EncryptionUserSettingsTab } from "../../../../../../../src/components/views/settings/tabs/user/EncryptionUserSettingsTab";
+import { createTestClient, withClientContextRenderOptions } from "../../../../../../test-utils";
+import Modal from "../../../../../../../src/Modal";
+
+describe("<EncryptionUserSettingsTab />", () => {
+    let matrixClient: MatrixClient;
+
+    beforeEach(() => {
+        matrixClient = createTestClient();
+        jest.spyOn(matrixClient.getCrypto()!, "isCrossSigningReady").mockResolvedValue(true);
+        // Recovery key is available
+        jest.spyOn(matrixClient.secretStorage, "getDefaultKeyId").mockResolvedValue("default key");
+        // Secrets are cached
+        jest.spyOn(matrixClient.getCrypto()!, "getCrossSigningStatus").mockResolvedValue({
+            privateKeysInSecretStorage: true,
+            publicKeysOnDevice: true,
+            privateKeysCachedLocally: {
+                masterKey: true,
+                selfSigningKey: true,
+                userSigningKey: true,
+            },
+        });
+    });
+
+    function renderComponent() {
+        return render(<EncryptionUserSettingsTab />, withClientContextRenderOptions(matrixClient));
+    }
+
+    it("should display a loading state when the encryption state is computed", () => {
+        jest.spyOn(matrixClient.getCrypto()!, "isCrossSigningReady").mockImplementation(() => new Promise(() => {}));
+
+        renderComponent();
+        expect(screen.getByLabelText("Loading…")).toBeInTheDocument();
+    });
+
+    it("should display a verify button when the encryption is not set up", async () => {
+        const user = userEvent.setup();
+        jest.spyOn(matrixClient.getCrypto()!, "isCrossSigningReady").mockResolvedValue(false);
+
+        const { asFragment } = renderComponent();
+        await waitFor(() =>
+            expect(
+                screen.getByText("You need to verify this device in order to view your encryption settings."),
+            ).toBeInTheDocument(),
+        );
+        expect(asFragment()).toMatchSnapshot();
+
+        const spy = jest.spyOn(Modal, "createDialog").mockReturnValue({} as any);
+        await user.click(screen.getByText("Verify this device"));
+        expect(spy).toHaveBeenCalled();
+    });
+
+    it("should display the recovery panel when the encryption is set up", async () => {
+        renderComponent();
+        await waitFor(() => expect(screen.getByText("Recovery")).toBeInTheDocument());
+    });
+
+    it("should display the change recovery key panel when the user clicks on the change recovery button", async () => {
+        const user = userEvent.setup();
+
+        const { asFragment } = renderComponent();
+        await waitFor(() => {
+            const button = screen.getByRole("button", { name: "Change recovery key" });
+            expect(button).toBeInTheDocument();
+            user.click(button);
+        });
+        await waitFor(() => expect(screen.getByText("Change recovery key")).toBeInTheDocument());
+        expect(asFragment()).toMatchSnapshot();
+    });
+
+    it("should display the set up recovery key when the user clicks on the set up recovery key button", async () => {
+        jest.spyOn(matrixClient.secretStorage, "getDefaultKeyId").mockResolvedValue(null);
+        const user = userEvent.setup();
+
+        const { asFragment } = renderComponent();
+        await waitFor(() => {
+            const button = screen.getByRole("button", { name: "Set up recovery" });
+            expect(button).toBeInTheDocument();
+            user.click(button);
+        });
+        await waitFor(() => expect(screen.getByText("Set up recovery")).toBeInTheDocument());
+        expect(asFragment()).toMatchSnapshot();
+    });
+});
diff --git a/test/unit-tests/components/views/settings/tabs/user/KeyboardUserSettingsTab-test.tsx b/test/unit-tests/components/views/settings/tabs/user/KeyboardUserSettingsTab-test.tsx
index d7855dcea11..0af6d823862 100644
--- a/test/unit-tests/components/views/settings/tabs/user/KeyboardUserSettingsTab-test.tsx
+++ b/test/unit-tests/components/views/settings/tabs/user/KeyboardUserSettingsTab-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 Šimon Brandner <simon.bra.ag@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/settings/tabs/user/LabsUserSettingsTab-test.tsx b/test/unit-tests/components/views/settings/tabs/user/LabsUserSettingsTab-test.tsx
index 155256cbe6e..d9d7cb48b19 100644
--- a/test/unit-tests/components/views/settings/tabs/user/LabsUserSettingsTab-test.tsx
+++ b/test/unit-tests/components/views/settings/tabs/user/LabsUserSettingsTab-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/settings/tabs/user/MjolnirUserSettingsTab-test.tsx b/test/unit-tests/components/views/settings/tabs/user/MjolnirUserSettingsTab-test.tsx
index e21c1cbcc44..53671bfbd5d 100644
--- a/test/unit-tests/components/views/settings/tabs/user/MjolnirUserSettingsTab-test.tsx
+++ b/test/unit-tests/components/views/settings/tabs/user/MjolnirUserSettingsTab-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/settings/tabs/user/PreferencesUserSettingsTab-test.tsx b/test/unit-tests/components/views/settings/tabs/user/PreferencesUserSettingsTab-test.tsx
index efa072e7a1e..edecef24bb8 100644
--- a/test/unit-tests/components/views/settings/tabs/user/PreferencesUserSettingsTab-test.tsx
+++ b/test/unit-tests/components/views/settings/tabs/user/PreferencesUserSettingsTab-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -17,6 +17,7 @@ import SettingsStore from "../../../../../../../src/settings/SettingsStore";
 import { SettingLevel } from "../../../../../../../src/settings/SettingLevel";
 import MatrixClientBackedController from "../../../../../../../src/settings/controllers/MatrixClientBackedController";
 import PlatformPeg from "../../../../../../../src/PlatformPeg";
+import { SettingKey } from "../../../../../../../src/settings/Settings.tsx";
 
 describe("PreferencesUserSettingsTab", () => {
     beforeEach(() => {
@@ -121,13 +122,13 @@ describe("PreferencesUserSettingsTab", () => {
         const mockGetValue = (val: boolean) => {
             const copyOfGetValueAt = SettingsStore.getValueAt;
 
-            SettingsStore.getValueAt = <T,>(
+            SettingsStore.getValueAt = (
                 level: SettingLevel,
-                name: string,
+                name: SettingKey,
                 roomId?: string,
                 isExplicit?: boolean,
-            ): T => {
-                if (name === "sendReadReceipts") return val as T;
+            ) => {
+                if (name === "sendReadReceipts") return val;
                 return copyOfGetValueAt(level, name, roomId, isExplicit);
             };
         };
diff --git a/test/unit-tests/components/views/settings/tabs/user/SecurityUserSettingsTab-test.tsx b/test/unit-tests/components/views/settings/tabs/user/SecurityUserSettingsTab-test.tsx
index 27403919b6c..65c1bf1d480 100644
--- a/test/unit-tests/components/views/settings/tabs/user/SecurityUserSettingsTab-test.tsx
+++ b/test/unit-tests/components/views/settings/tabs/user/SecurityUserSettingsTab-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 import { render } from "jest-matrix-react";
diff --git a/test/unit-tests/components/views/settings/tabs/user/SessionManagerTab-test.tsx b/test/unit-tests/components/views/settings/tabs/user/SessionManagerTab-test.tsx
index 87411e18a17..030f769de21 100644
--- a/test/unit-tests/components/views/settings/tabs/user/SessionManagerTab-test.tsx
+++ b/test/unit-tests/components/views/settings/tabs/user/SessionManagerTab-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -1234,34 +1234,13 @@ describe("<SessionManagerTab />", () => {
                     toggleDeviceDetails(getByTestId, alicesMobileDevice.device_id);
 
                     const deviceDetails = getByTestId(`device-detail-${alicesMobileDevice.device_id}`);
-                    const signOutButton = deviceDetails.querySelector(
+                    const manageDeviceButton = deviceDetails.querySelector(
                         '[data-testid="device-detail-sign-out-cta"]',
                     ) as Element;
-                    fireEvent.click(signOutButton);
-
-                    await screen.findByRole("dialog");
-                    expect(
-                        screen.getByText(
-                            "You will be redirected to your server's authentication provider to complete sign out.",
-                        ),
-                    ).toBeInTheDocument();
-                    // correct link to auth provider
-                    expect(screen.getByText("Continue")).toHaveAttribute(
+                    expect(manageDeviceButton).toHaveAttribute(
                         "href",
-                        `https://issuer.org/account?action=session_end&device_id=${alicesMobileDevice.device_id}`,
+                        `https://issuer.org/account?action=org.matrix.session_view&device_id=${alicesMobileDevice.device_id}`,
                     );
-
-                    // go to the link
-                    fireEvent.click(screen.getByText("Continue"));
-                    await flushPromises();
-
-                    // come back from the link and close the modal
-                    fireEvent.click(screen.getByText("Close"));
-
-                    await flushPromises();
-
-                    // devices were refreshed
-                    expect(mockClient.getDevices).toHaveBeenCalled();
                 });
 
                 it("does not allow removing multiple devices at once", async () => {
diff --git a/test/unit-tests/components/views/settings/tabs/user/SidebarUserSettingsTab-test.tsx b/test/unit-tests/components/views/settings/tabs/user/SidebarUserSettingsTab-test.tsx
index c19d62b9a68..e1c7e4a3273 100644
--- a/test/unit-tests/components/views/settings/tabs/user/SidebarUserSettingsTab-test.tsx
+++ b/test/unit-tests/components/views/settings/tabs/user/SidebarUserSettingsTab-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/settings/tabs/user/VoiceUserSettingsTab-test.tsx b/test/unit-tests/components/views/settings/tabs/user/VoiceUserSettingsTab-test.tsx
index 50fcf419313..1c8ff6f2678 100644
--- a/test/unit-tests/components/views/settings/tabs/user/VoiceUserSettingsTab-test.tsx
+++ b/test/unit-tests/components/views/settings/tabs/user/VoiceUserSettingsTab-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/settings/tabs/user/__snapshots__/AccountUserSettingsTab-test.tsx.snap b/test/unit-tests/components/views/settings/tabs/user/__snapshots__/AccountUserSettingsTab-test.tsx.snap
index 5c6a8ac8ee5..1387b984d8b 100644
--- a/test/unit-tests/components/views/settings/tabs/user/__snapshots__/AccountUserSettingsTab-test.tsx.snap
+++ b/test/unit-tests/components/views/settings/tabs/user/__snapshots__/AccountUserSettingsTab-test.tsx.snap
@@ -169,7 +169,7 @@ exports[`<AccountUserSettingsTab /> 3pids should display 3pid email addresses an
 </div>
 `;
 
-exports[`<AccountUserSettingsTab /> deactive account should render section when account deactivation feature is enabled 1`] = `
+exports[`<AccountUserSettingsTab /> deactivate account should render section when account deactivation feature is enabled 1`] = `
 <div
   class="mx_SettingsSection"
 >
diff --git a/test/unit-tests/components/views/settings/tabs/user/__snapshots__/EncryptionUserSettingsTab-test.tsx.snap b/test/unit-tests/components/views/settings/tabs/user/__snapshots__/EncryptionUserSettingsTab-test.tsx.snap
new file mode 100644
index 00000000000..71ec4deb592
--- /dev/null
+++ b/test/unit-tests/components/views/settings/tabs/user/__snapshots__/EncryptionUserSettingsTab-test.tsx.snap
@@ -0,0 +1,95 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`<EncryptionUserSettingsTab /> should display a verify button when the encryption is not set up 1`] = `
+<DocumentFragment>
+  <div
+    class="mx_SettingsTab mx_EncryptionUserSettingsTab"
+    data-testid="encryptionTab"
+  >
+    <div
+      class="mx_SettingsTab_sections"
+    >
+      <div
+        class="mx_SettingsSection mx_SettingsSection_newUi"
+      >
+        <div
+          class="mx_SettingsSection_header"
+        >
+          <h2
+            class="_typography_yh5dq_162 _font-heading-sm-semibold_yh5dq_102 mx_SettingsHeader"
+          >
+            Device not verified 
+          </h2>
+          <div
+            class="mx_SettingsSubheader"
+          >
+            <span
+              class="mx_SettingsSubheader_error"
+            >
+              <svg
+                fill="currentColor"
+                height="20px"
+                viewBox="0 0 24 24"
+                width="20px"
+                xmlns="http://www.w3.org/2000/svg"
+              >
+                <path
+                  d="M12 17a.97.97 0 0 0 .713-.288A.968.968 0 0 0 13 16a.968.968 0 0 0-.287-.713A.968.968 0 0 0 12 15a.968.968 0 0 0-.713.287A.968.968 0 0 0 11 16c0 .283.096.52.287.712.192.192.43.288.713.288Zm0-4c.283 0 .52-.096.713-.287A.968.968 0 0 0 13 12V8a.967.967 0 0 0-.287-.713A.968.968 0 0 0 12 7a.968.968 0 0 0-.713.287A.967.967 0 0 0 11 8v4c0 .283.096.52.287.713.192.191.43.287.713.287Zm0 9a9.738 9.738 0 0 1-3.9-.788 10.099 10.099 0 0 1-3.175-2.137c-.9-.9-1.612-1.958-2.137-3.175A9.738 9.738 0 0 1 2 12a9.74 9.74 0 0 1 .788-3.9 10.099 10.099 0 0 1 2.137-3.175c.9-.9 1.958-1.612 3.175-2.137A9.738 9.738 0 0 1 12 2a9.74 9.74 0 0 1 3.9.788 10.098 10.098 0 0 1 3.175 2.137c.9.9 1.613 1.958 2.137 3.175A9.738 9.738 0 0 1 22 12a9.738 9.738 0 0 1-.788 3.9 10.098 10.098 0 0 1-2.137 3.175c-.9.9-1.958 1.613-3.175 2.137A9.738 9.738 0 0 1 12 22Z"
+                />
+              </svg>
+              You need to verify this device in order to view your encryption settings.
+            </span>
+          </div>
+        </div>
+        <button
+          class="_button_i91xf_17 _has-icon_i91xf_66"
+          data-kind="primary"
+          data-size="sm"
+          role="button"
+          tabindex="0"
+        >
+          <svg
+            aria-hidden="true"
+            fill="currentColor"
+            height="20"
+            viewBox="0 0 24 24"
+            width="20"
+            xmlns="http://www.w3.org/2000/svg"
+          >
+            <path
+              d="M4 18c-.55 0-1.02-.196-1.413-.587A1.926 1.926 0 0 1 2 16V5c0-.55.196-1.02.587-1.413A1.926 1.926 0 0 1 4 3h16c.55 0 1.02.196 1.413.587.39.393.587.863.587 1.413v11c0 .55-.196 1.02-.587 1.413A1.926 1.926 0 0 1 20 18H4Zm0-2h16V5H4v11Zm-2 5a.967.967 0 0 1-.712-.288A.968.968 0 0 1 1 20c0-.283.096-.52.288-.712A.967.967 0 0 1 2 19h20c.283 0 .52.096.712.288.192.191.288.429.288.712s-.096.52-.288.712A.968.968 0 0 1 22 21H2Z"
+            />
+          </svg>
+          Verify this device
+        </button>
+      </div>
+    </div>
+  </div>
+</DocumentFragment>
+`;
+
+exports[`<EncryptionUserSettingsTab /> should display the change recovery key panel when the user clicks on the change recovery button 1`] = `
+<DocumentFragment>
+  <div
+    class="mx_SettingsTab mx_EncryptionUserSettingsTab"
+    data-testid="encryptionTab"
+  >
+    <div
+      class="mx_SettingsTab_sections"
+    />
+  </div>
+</DocumentFragment>
+`;
+
+exports[`<EncryptionUserSettingsTab /> should display the set up recovery key when the user clicks on the set up recovery key button 1`] = `
+<DocumentFragment>
+  <div
+    class="mx_SettingsTab mx_EncryptionUserSettingsTab"
+    data-testid="encryptionTab"
+  >
+    <div
+      class="mx_SettingsTab_sections"
+    />
+  </div>
+</DocumentFragment>
+`;
diff --git a/test/unit-tests/components/views/spaces/AddExistingToSpaceDialog-test.tsx b/test/unit-tests/components/views/spaces/AddExistingToSpaceDialog-test.tsx
index 36f8ef44df6..c06847e7005 100644
--- a/test/unit-tests/components/views/spaces/AddExistingToSpaceDialog-test.tsx
+++ b/test/unit-tests/components/views/spaces/AddExistingToSpaceDialog-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/spaces/QuickSettingsButton-test.tsx b/test/unit-tests/components/views/spaces/QuickSettingsButton-test.tsx
index fae530f1127..af3fe770ff3 100644
--- a/test/unit-tests/components/views/spaces/QuickSettingsButton-test.tsx
+++ b/test/unit-tests/components/views/spaces/QuickSettingsButton-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/spaces/QuickThemeSwitcher-test.tsx b/test/unit-tests/components/views/spaces/QuickThemeSwitcher-test.tsx
index 502176d684c..842db5ace78 100644
--- a/test/unit-tests/components/views/spaces/QuickThemeSwitcher-test.tsx
+++ b/test/unit-tests/components/views/spaces/QuickThemeSwitcher-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/spaces/SpacePanel-test.tsx b/test/unit-tests/components/views/spaces/SpacePanel-test.tsx
index 1d1ebc194f0..3331de93341 100644
--- a/test/unit-tests/components/views/spaces/SpacePanel-test.tsx
+++ b/test/unit-tests/components/views/spaces/SpacePanel-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/spaces/SpaceSettingsVisibilityTab-test.tsx b/test/unit-tests/components/views/spaces/SpaceSettingsVisibilityTab-test.tsx
index 28314f97b2e..f16651abd93 100644
--- a/test/unit-tests/components/views/spaces/SpaceSettingsVisibilityTab-test.tsx
+++ b/test/unit-tests/components/views/spaces/SpaceSettingsVisibilityTab-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/spaces/SpaceTreeLevel-test.tsx b/test/unit-tests/components/views/spaces/SpaceTreeLevel-test.tsx
index 1e44fa6a0a8..98dc9723abb 100644
--- a/test/unit-tests/components/views/spaces/SpaceTreeLevel-test.tsx
+++ b/test/unit-tests/components/views/spaces/SpaceTreeLevel-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/spaces/ThreadsActivityCentre-test.tsx b/test/unit-tests/components/views/spaces/ThreadsActivityCentre-test.tsx
index da1fa7bb0f6..ecbe550d600 100644
--- a/test/unit-tests/components/views/spaces/ThreadsActivityCentre-test.tsx
+++ b/test/unit-tests/components/views/spaces/ThreadsActivityCentre-test.tsx
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2024 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
@@ -19,6 +19,7 @@ import { populateThread } from "../../../../test-utils/threads";
 import DMRoomMap from "../../../../../src/utils/DMRoomMap";
 import SettingsStore from "../../../../../src/settings/SettingsStore";
 import { SettingLevel } from "../../../../../src/settings/SettingLevel";
+import { Features } from "../../../../../src/settings/Settings.tsx";
 
 describe("ThreadsActivityCentre", () => {
     const getTACButton = () => {
@@ -92,7 +93,7 @@ describe("ThreadsActivityCentre", () => {
     });
 
     beforeEach(async () => {
-        await SettingsStore.setValue("feature_release_announcement", null, SettingLevel.DEVICE, false);
+        await SettingsStore.setValue(Features.ReleaseAnnouncement, null, SettingLevel.DEVICE, false);
     });
 
     it("should render the threads activity centre button", async () => {
@@ -102,7 +103,7 @@ describe("ThreadsActivityCentre", () => {
 
     it("should render the release announcement", async () => {
         // Enable release announcement
-        await SettingsStore.setValue("feature_release_announcement", null, SettingLevel.DEVICE, true);
+        await SettingsStore.setValue(Features.ReleaseAnnouncement, null, SettingLevel.DEVICE, true);
 
         renderTAC();
         expect(document.body).toMatchSnapshot();
@@ -110,7 +111,7 @@ describe("ThreadsActivityCentre", () => {
 
     it("should render not display the tooltip when the release announcement is displayed", async () => {
         // Enable release announcement
-        await SettingsStore.setValue("feature_release_announcement", null, SettingLevel.DEVICE, true);
+        await SettingsStore.setValue(Features.ReleaseAnnouncement, null, SettingLevel.DEVICE, true);
 
         renderTAC();
 
@@ -121,7 +122,7 @@ describe("ThreadsActivityCentre", () => {
 
     it("should close the release announcement when the TAC button is clicked", async () => {
         // Enable release announcement
-        await SettingsStore.setValue("feature_release_announcement", null, SettingLevel.DEVICE, true);
+        await SettingsStore.setValue(Features.ReleaseAnnouncement, null, SettingLevel.DEVICE, true);
 
         renderTAC();
         await userEvent.click(getTACButton());
diff --git a/test/unit-tests/components/views/spaces/useUnreadThreadRooms-test.tsx b/test/unit-tests/components/views/spaces/useUnreadThreadRooms-test.tsx
index c2773924266..f8e32289e9a 100644
--- a/test/unit-tests/components/views/spaces/useUnreadThreadRooms-test.tsx
+++ b/test/unit-tests/components/views/spaces/useUnreadThreadRooms-test.tsx
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2024 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/test/unit-tests/components/views/toasts/GenericToast-test.tsx b/test/unit-tests/components/views/toasts/GenericToast-test.tsx
index 51e75cc54cc..5947dcdbc6c 100644
--- a/test/unit-tests/components/views/toasts/GenericToast-test.tsx
+++ b/test/unit-tests/components/views/toasts/GenericToast-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/toasts/VerificationRequestToast-test.tsx b/test/unit-tests/components/views/toasts/VerificationRequestToast-test.tsx
index 8ee44ed499e..1f22da8d753 100644
--- a/test/unit-tests/components/views/toasts/VerificationRequestToast-test.tsx
+++ b/test/unit-tests/components/views/toasts/VerificationRequestToast-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/typography/Caption-test.tsx b/test/unit-tests/components/views/typography/Caption-test.tsx
index c2adfa80599..dde1a3977b0 100644
--- a/test/unit-tests/components/views/typography/Caption-test.tsx
+++ b/test/unit-tests/components/views/typography/Caption-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/typography/Heading-test.tsx b/test/unit-tests/components/views/typography/Heading-test.tsx
index 22138e3e815..a3097553846 100644
--- a/test/unit-tests/components/views/typography/Heading-test.tsx
+++ b/test/unit-tests/components/views/typography/Heading-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/user-onboarding/UserOnboardingList-test.tsx b/test/unit-tests/components/views/user-onboarding/UserOnboardingList-test.tsx
deleted file mode 100644
index a51491a39fd..00000000000
--- a/test/unit-tests/components/views/user-onboarding/UserOnboardingList-test.tsx
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2022 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
-Please see LICENSE files in the repository root for full details.
-*/
-
-import { getUserOnboardingCounters } from "../../../../../src/components/views/user-onboarding/UserOnboardingList";
-
-const tasks = [
-    {
-        id: "1",
-        title: "Lorem ipsum",
-        description: "Lorem ipsum dolor amet.",
-        completed: true,
-    },
-    {
-        id: "2",
-        title: "Lorem ipsum",
-        description: "Lorem ipsum dolor amet.",
-        completed: false,
-    },
-];
-
-describe("getUserOnboardingCounters()", () => {
-    it.each([
-        {
-            tasks: [],
-            expectation: {
-                completed: 0,
-                waiting: 0,
-                total: 0,
-            },
-        },
-        {
-            tasks: tasks,
-            expectation: {
-                completed: 1,
-                waiting: 1,
-                total: 2,
-            },
-        },
-    ])("should calculate counters correctly", ({ tasks, expectation }) => {
-        const result = getUserOnboardingCounters(tasks);
-        expect(result).toStrictEqual(expectation);
-    });
-});
diff --git a/test/unit-tests/components/views/user-onboarding/UserOnboardingPage-test.tsx b/test/unit-tests/components/views/user-onboarding/UserOnboardingPage-test.tsx
deleted file mode 100644
index 4999a84746d..00000000000
--- a/test/unit-tests/components/views/user-onboarding/UserOnboardingPage-test.tsx
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2022 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
-Please see LICENSE files in the repository root for full details.
-*/
-
-import React from "react";
-import { act, render, RenderResult } from "jest-matrix-react";
-
-import { filterConsole, withClientContextRenderOptions, stubClient } from "../../../../test-utils";
-import { UserOnboardingPage } from "../../../../../src/components/views/user-onboarding/UserOnboardingPage";
-import { MatrixClientPeg } from "../../../../../src/MatrixClientPeg";
-import SdkConfig from "../../../../../src/SdkConfig";
-
-jest.mock("../../../../../src/components/structures/EmbeddedPage", () => ({
-    __esModule: true,
-    default: ({ url }: { url: string }) => <div>{url}</div>,
-}));
-
-jest.mock("../../../../../src/components/structures/HomePage", () => ({
-    __esModule: true,
-    default: () => <div>home page</div>,
-}));
-
-describe("UserOnboardingPage", () => {
-    const renderComponent = async (): Promise<RenderResult> => {
-        const renderResult = render(<UserOnboardingPage />, withClientContextRenderOptions(MatrixClientPeg.safeGet()));
-        await act(async () => {
-            jest.runAllTimers();
-        });
-        return renderResult;
-    };
-
-    filterConsole(
-        // unrelated for this test
-        "could not update user onboarding context",
-    );
-
-    beforeEach(() => {
-        stubClient();
-        jest.useFakeTimers();
-    });
-
-    afterEach(() => {
-        jest.useRealTimers();
-        jest.restoreAllMocks();
-    });
-
-    describe("when the user registered before the cutoff date", () => {
-        beforeEach(() => {
-            jest.spyOn(MatrixClientPeg, "userRegisteredAfter").mockReturnValue(false);
-        });
-
-        it("should render the home page", async () => {
-            expect((await renderComponent()).queryByText("home page")).toBeInTheDocument();
-        });
-    });
-
-    describe("when the user registered after the cutoff date", () => {
-        beforeEach(() => {
-            jest.spyOn(MatrixClientPeg, "userRegisteredAfter").mockReturnValue(true);
-        });
-
-        describe("and there is an explicit home page configured", () => {
-            beforeEach(() => {
-                jest.spyOn(SdkConfig, "get").mockReturnValue({
-                    embedded_pages: {
-                        home_url: "https://example.com/home",
-                    },
-                });
-            });
-
-            it("should render the configured page", async () => {
-                expect((await renderComponent()).queryByText("https://example.com/home")).toBeInTheDocument();
-            });
-        });
-
-        describe("and there is no home page configured", () => {
-            it("should render the onboarding", async () => {
-                expect((await renderComponent()).queryByTestId("user-onboarding-list")).toBeInTheDocument();
-            });
-        });
-    });
-});
diff --git a/test/unit-tests/components/views/voip/CallView-test.tsx b/test/unit-tests/components/views/voip/CallView-test.tsx
index d47c5cffa45..cb1cc6ffb10 100644
--- a/test/unit-tests/components/views/voip/CallView-test.tsx
+++ b/test/unit-tests/components/views/voip/CallView-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/voip/DialPad-test.tsx b/test/unit-tests/components/views/voip/DialPad-test.tsx
index ca6859644af..664f53bdee0 100644
--- a/test/unit-tests/components/views/voip/DialPad-test.tsx
+++ b/test/unit-tests/components/views/voip/DialPad-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/components/views/voip/LegacyCallView/LegacyCallViewButtons-test.tsx b/test/unit-tests/components/views/voip/LegacyCallView/LegacyCallViewButtons-test.tsx
index a3bc0e987fa..b01f40b0901 100644
--- a/test/unit-tests/components/views/voip/LegacyCallView/LegacyCallViewButtons-test.tsx
+++ b/test/unit-tests/components/views/voip/LegacyCallView/LegacyCallViewButtons-test.tsx
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2024 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/test/unit-tests/components/views/voip/VideoFeed-test.tsx b/test/unit-tests/components/views/voip/VideoFeed-test.tsx
index 0e78fc6b96b..d9a396d6640 100644
--- a/test/unit-tests/components/views/voip/VideoFeed-test.tsx
+++ b/test/unit-tests/components/views/voip/VideoFeed-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/contexts/SdkContext-test.ts b/test/unit-tests/contexts/SdkContext-test.ts
index 340fabdd3dd..0ccf638aa29 100644
--- a/test/unit-tests/contexts/SdkContext-test.ts
+++ b/test/unit-tests/contexts/SdkContext-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/contexts/ToastContext-test.ts b/test/unit-tests/contexts/ToastContext-test.ts
index 5e650dc9722..1124dec7a21 100644
--- a/test/unit-tests/contexts/ToastContext-test.ts
+++ b/test/unit-tests/contexts/ToastContext-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/createRoom-test.ts b/test/unit-tests/createRoom-test.ts
index 0f2b61c04cd..f3dc57fed4c 100644
--- a/test/unit-tests/createRoom-test.ts
+++ b/test/unit-tests/createRoom-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -105,7 +105,7 @@ describe("createRoom", () => {
     });
 
     it("correctly sets up MSC3401 power levels", async () => {
-        jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string) => {
+        jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string): any => {
             if (name === "feature_group_calls") return true;
         });
 
diff --git a/test/unit-tests/customisations/Media-test.ts b/test/unit-tests/customisations/Media-test.ts
index 1fda2381d16..d7b3b681dcc 100644
--- a/test/unit-tests/customisations/Media-test.ts
+++ b/test/unit-tests/customisations/Media-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/dispatcher/dispatcher-test.ts b/test/unit-tests/dispatcher/dispatcher-test.ts
index 101c118b259..711fad2b5e7 100644
--- a/test/unit-tests/dispatcher/dispatcher-test.ts
+++ b/test/unit-tests/dispatcher/dispatcher-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/editor/caret-test.ts b/test/unit-tests/editor/caret-test.ts
index bd4850723fc..fd56404731d 100644
--- a/test/unit-tests/editor/caret-test.ts
+++ b/test/unit-tests/editor/caret-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/editor/deserialize-test.ts b/test/unit-tests/editor/deserialize-test.ts
index 25208c55212..b5b8dc1b9f9 100644
--- a/test/unit-tests/editor/deserialize-test.ts
+++ b/test/unit-tests/editor/deserialize-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 import { MatrixEvent } from "matrix-js-sdk/src/matrix";
diff --git a/test/unit-tests/editor/diff-test.ts b/test/unit-tests/editor/diff-test.ts
index c3f4d6fd81e..f5ec0db29e6 100644
--- a/test/unit-tests/editor/diff-test.ts
+++ b/test/unit-tests/editor/diff-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/editor/history-test.ts b/test/unit-tests/editor/history-test.ts
index 94f665e7ec1..2ae284d0d8f 100644
--- a/test/unit-tests/editor/history-test.ts
+++ b/test/unit-tests/editor/history-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/editor/mock.ts b/test/unit-tests/editor/mock.ts
index 5a1809e232c..e49a4558a48 100644
--- a/test/unit-tests/editor/mock.ts
+++ b/test/unit-tests/editor/mock.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019-2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/editor/model-test.ts b/test/unit-tests/editor/model-test.ts
index 16cdcb64588..5d548ce7fcc 100644
--- a/test/unit-tests/editor/model-test.ts
+++ b/test/unit-tests/editor/model-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/editor/operations-test.ts b/test/unit-tests/editor/operations-test.ts
index a3b61d6f001..d0dc1e837db 100644
--- a/test/unit-tests/editor/operations-test.ts
+++ b/test/unit-tests/editor/operations-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2020 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/editor/parts-test.ts b/test/unit-tests/editor/parts-test.ts
index d5cdf33bac7..6a8db136419 100644
--- a/test/unit-tests/editor/parts-test.ts
+++ b/test/unit-tests/editor/parts-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/editor/position-test.ts b/test/unit-tests/editor/position-test.ts
index 103cfb748f6..6f1928e05ce 100644
--- a/test/unit-tests/editor/position-test.ts
+++ b/test/unit-tests/editor/position-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/editor/range-test.ts b/test/unit-tests/editor/range-test.ts
index 55b39d20d89..c4e7dc05fb9 100644
--- a/test/unit-tests/editor/range-test.ts
+++ b/test/unit-tests/editor/range-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/editor/roundtrip-test.ts b/test/unit-tests/editor/roundtrip-test.ts
index 7420df90f84..dfce37472f4 100644
--- a/test/unit-tests/editor/roundtrip-test.ts
+++ b/test/unit-tests/editor/roundtrip-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/editor/serialize-test.ts b/test/unit-tests/editor/serialize-test.ts
index 8920bf17470..3162f1464ab 100644
--- a/test/unit-tests/editor/serialize-test.ts
+++ b/test/unit-tests/editor/serialize-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2019 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/email-test.ts b/test/unit-tests/email-test.ts
index 6efcde67c1b..f02566d2718 100644
--- a/test/unit-tests/email-test.ts
+++ b/test/unit-tests/email-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/events/EventTileFactory-test.ts b/test/unit-tests/events/EventTileFactory-test.ts
index 8a7d09c434f..eee94791fc3 100644
--- a/test/unit-tests/events/EventTileFactory-test.ts
+++ b/test/unit-tests/events/EventTileFactory-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/events/RelationsHelper-test.ts b/test/unit-tests/events/RelationsHelper-test.ts
index 48776d2fb0c..fa693a89538 100644
--- a/test/unit-tests/events/RelationsHelper-test.ts
+++ b/test/unit-tests/events/RelationsHelper-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/events/forward/getForwardableEvent-test.ts b/test/unit-tests/events/forward/getForwardableEvent-test.ts
index c2669ff003f..346fb09318c 100644
--- a/test/unit-tests/events/forward/getForwardableEvent-test.ts
+++ b/test/unit-tests/events/forward/getForwardableEvent-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/events/location/getShareableLocationEvent-test.ts b/test/unit-tests/events/location/getShareableLocationEvent-test.ts
index 8eb430b0aae..ceea7483024 100644
--- a/test/unit-tests/events/location/getShareableLocationEvent-test.ts
+++ b/test/unit-tests/events/location/getShareableLocationEvent-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/favicon-test.ts b/test/unit-tests/favicon-test.ts
index 25a482bb6c2..8972861773a 100644
--- a/test/unit-tests/favicon-test.ts
+++ b/test/unit-tests/favicon-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/hooks/room/useRoomThreadNotifications-test.tsx b/test/unit-tests/hooks/room/useRoomThreadNotifications-test.tsx
index 885c827e15c..26698af0582 100644
--- a/test/unit-tests/hooks/room/useRoomThreadNotifications-test.tsx
+++ b/test/unit-tests/hooks/room/useRoomThreadNotifications-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/hooks/useDebouncedCallback-test.tsx b/test/unit-tests/hooks/useDebouncedCallback-test.tsx
index ca09ecef20c..5d0e03b930c 100644
--- a/test/unit-tests/hooks/useDebouncedCallback-test.tsx
+++ b/test/unit-tests/hooks/useDebouncedCallback-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/hooks/useLatestResult-test.tsx b/test/unit-tests/hooks/useLatestResult-test.tsx
index 0286c3dd6c4..5a70d2148cb 100644
--- a/test/unit-tests/hooks/useLatestResult-test.tsx
+++ b/test/unit-tests/hooks/useLatestResult-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/hooks/useNotificationSettings-test.tsx b/test/unit-tests/hooks/useNotificationSettings-test.tsx
index b2f9cad33bc..b05c868a125 100644
--- a/test/unit-tests/hooks/useNotificationSettings-test.tsx
+++ b/test/unit-tests/hooks/useNotificationSettings-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/hooks/useProfileInfo-test.tsx b/test/unit-tests/hooks/useProfileInfo-test.tsx
index 0f1c77af0f8..e42dcb18583 100644
--- a/test/unit-tests/hooks/useProfileInfo-test.tsx
+++ b/test/unit-tests/hooks/useProfileInfo-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/hooks/usePublicRoomDirectory-test.tsx b/test/unit-tests/hooks/usePublicRoomDirectory-test.tsx
index 8e8789d2ac3..980c8b2aa12 100644
--- a/test/unit-tests/hooks/usePublicRoomDirectory-test.tsx
+++ b/test/unit-tests/hooks/usePublicRoomDirectory-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/hooks/useRoomMembers-test.tsx b/test/unit-tests/hooks/useRoomMembers-test.tsx
index b8b589690be..df572ead088 100644
--- a/test/unit-tests/hooks/useRoomMembers-test.tsx
+++ b/test/unit-tests/hooks/useRoomMembers-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/hooks/useSlidingSyncRoomSearch-test.tsx b/test/unit-tests/hooks/useSlidingSyncRoomSearch-test.tsx
index ff5304bf1ad..f8c33ac16b6 100644
--- a/test/unit-tests/hooks/useSlidingSyncRoomSearch-test.tsx
+++ b/test/unit-tests/hooks/useSlidingSyncRoomSearch-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/hooks/useUnreadNotifications-test.ts b/test/unit-tests/hooks/useUnreadNotifications-test.ts
index 6f5ef96b89f..6776efa7c04 100644
--- a/test/unit-tests/hooks/useUnreadNotifications-test.ts
+++ b/test/unit-tests/hooks/useUnreadNotifications-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/hooks/useUserDirectory-test.tsx b/test/unit-tests/hooks/useUserDirectory-test.tsx
index 1f8863143ad..a2a8f62e31e 100644
--- a/test/unit-tests/hooks/useUserDirectory-test.tsx
+++ b/test/unit-tests/hooks/useUserDirectory-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/hooks/useUserOnboardingTasks-test.tsx b/test/unit-tests/hooks/useUserOnboardingTasks-test.tsx
deleted file mode 100644
index f710862023b..00000000000
--- a/test/unit-tests/hooks/useUserOnboardingTasks-test.tsx
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2022 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
-Please see LICENSE files in the repository root for full details.
-*/
-
-import React from "react";
-import { renderHook, waitFor } from "jest-matrix-react";
-
-import { useUserOnboardingTasks } from "../../../src/hooks/useUserOnboardingTasks";
-import { useUserOnboardingContext } from "../../../src/hooks/useUserOnboardingContext";
-import { stubClient } from "../../test-utils";
-import MatrixClientContext from "../../../src/contexts/MatrixClientContext";
-import DMRoomMap from "../../../src/utils/DMRoomMap";
-import PlatformPeg from "../../../src/PlatformPeg";
-
-describe("useUserOnboardingTasks", () => {
-    it.each([
-        {
-            context: {
-                hasAvatar: false,
-                hasDevices: false,
-                hasDmRooms: false,
-                showNotificationsPrompt: false,
-            },
-        },
-        {
-            context: {
-                hasAvatar: true,
-                hasDevices: false,
-                hasDmRooms: false,
-                showNotificationsPrompt: true,
-            },
-        },
-    ])("sequence should stay static", async ({ context }) => {
-        const { result } = renderHook(() => useUserOnboardingTasks(context));
-
-        expect(result.current).toHaveLength(5);
-        expect(result.current[0].id).toBe("create-account");
-        expect(result.current[1].id).toBe("find-friends");
-        expect(result.current[2].id).toBe("download-apps");
-        expect(result.current[3].id).toBe("setup-profile");
-        expect(result.current[4].id).toBe("permission-notifications");
-    });
-
-    it("should mark desktop notifications task completed on click", async () => {
-        jest.spyOn(PlatformPeg, "get").mockReturnValue({
-            supportsNotifications: jest.fn().mockReturnValue(true),
-            maySendNotifications: jest.fn().mockReturnValue(false),
-        } as any);
-
-        const cli = stubClient();
-        cli.pushRules = {
-            global: {
-                override: [
-                    {
-                        rule_id: ".m.rule.master",
-                        enabled: false,
-                        actions: [],
-                        default: true,
-                    },
-                ],
-            },
-        };
-        DMRoomMap.makeShared(cli);
-        const context = renderHook(() => useUserOnboardingContext(), {
-            wrapper: (props) => {
-                return <MatrixClientContext.Provider value={cli}>{props.children}</MatrixClientContext.Provider>;
-            },
-        });
-        const { result, rerender } = renderHook(() => useUserOnboardingTasks(context.result.current));
-        expect(result.current[4].id).toBe("permission-notifications");
-        expect(result.current[4].completed).toBe(false);
-        result.current[4].action!.onClick!({ type: "click" } as any);
-        await waitFor(() => {
-            rerender();
-            expect(result.current[4].completed).toBe(true);
-        });
-    });
-});
diff --git a/test/unit-tests/hooks/useWindowWidth-test.ts b/test/unit-tests/hooks/useWindowWidth-test.ts
index 99e4cce1276..9ddc9750e2b 100644
--- a/test/unit-tests/hooks/useWindowWidth-test.ts
+++ b/test/unit-tests/hooks/useWindowWidth-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/integrations/IntegrationManagers-test.ts b/test/unit-tests/integrations/IntegrationManagers-test.ts
index f13d57db94e..e094926e4ef 100644
--- a/test/unit-tests/integrations/IntegrationManagers-test.ts
+++ b/test/unit-tests/integrations/IntegrationManagers-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/languageHandler-test.tsx b/test/unit-tests/languageHandler-test.tsx
index 90360ed56e6..1969c857cc1 100644
--- a/test/unit-tests/languageHandler-test.tsx
+++ b/test/unit-tests/languageHandler-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/linkify-matrix-test.ts b/test/unit-tests/linkify-matrix-test.ts
index 50edff2535b..70a6e18b3bb 100644
--- a/test/unit-tests/linkify-matrix-test.ts
+++ b/test/unit-tests/linkify-matrix-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/models/Call-test.ts b/test/unit-tests/models/Call-test.ts
index 316adbbea90..0da3e60ad87 100644
--- a/test/unit-tests/models/Call-test.ts
+++ b/test/unit-tests/models/Call-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -48,6 +48,7 @@ import ActiveWidgetStore, { ActiveWidgetStoreEvent } from "../../../src/stores/A
 import { ElementWidgetActions } from "../../../src/stores/widgets/ElementWidgetActions";
 import SettingsStore from "../../../src/settings/SettingsStore";
 import { PosthogAnalytics } from "../../../src/PosthogAnalytics";
+import { SettingKey } from "../../../src/settings/Settings.tsx";
 
 jest.spyOn(MediaDeviceHandler, "getDevices").mockResolvedValue({
     [MediaDeviceKindEnum.AudioInput]: [
@@ -63,7 +64,7 @@ jest.spyOn(MediaDeviceHandler, "getVideoInput").mockReturnValue("2");
 
 const enabledSettings = new Set(["feature_group_calls", "feature_video_rooms", "feature_element_call_video_rooms"]);
 jest.spyOn(SettingsStore, "getValue").mockImplementation(
-    (settingName) => enabledSettings.has(settingName) || undefined,
+    (settingName): any => enabledSettings.has(settingName) || undefined,
 );
 
 const setUpClientRoomAndStores = (): {
@@ -709,16 +710,18 @@ describe("ElementCall", () => {
 
         it("passes font settings through widget URL", async () => {
             const originalGetValue = SettingsStore.getValue;
-            SettingsStore.getValue = <T>(name: string, roomId?: string, excludeDefault?: boolean) => {
+            SettingsStore.getValue = (name: SettingKey, roomId: string | null = null, excludeDefault = false): any => {
                 switch (name) {
                     case "fontSizeDelta":
-                        return 4 as T;
+                        return 4;
                     case "useSystemFont":
-                        return true as T;
+                        return true;
                     case "systemFont":
-                        return "OpenDyslexic, DejaVu Sans" as T;
+                        return "OpenDyslexic, DejaVu Sans";
                     default:
-                        return originalGetValue<T>(name, roomId, excludeDefault);
+                        return excludeDefault
+                            ? originalGetValue(name, roomId, excludeDefault)
+                            : originalGetValue(name, roomId, excludeDefault);
                 }
             };
             document.documentElement.style.fontSize = "12px";
@@ -746,12 +749,14 @@ describe("ElementCall", () => {
 
             // Now test with the preference set to true
             const originalGetValue = SettingsStore.getValue;
-            SettingsStore.getValue = <T>(name: string, roomId?: string, excludeDefault?: boolean) => {
+            SettingsStore.getValue = (name: SettingKey, roomId: string | null = null, excludeDefault = false): any => {
                 switch (name) {
                     case "fallbackICEServerAllowed":
-                        return true as T;
+                        return true;
                     default:
-                        return originalGetValue<T>(name, roomId, excludeDefault);
+                        return excludeDefault
+                            ? originalGetValue(name, roomId, excludeDefault)
+                            : originalGetValue(name, roomId, excludeDefault);
                 }
             };
 
@@ -803,12 +808,14 @@ describe("ElementCall", () => {
         it("passes feature_allow_screen_share_only_mode setting to allowVoipWithNoMedia url param", async () => {
             // Now test with the preference set to true
             const originalGetValue = SettingsStore.getValue;
-            SettingsStore.getValue = <T>(name: string, roomId?: string, excludeDefault?: boolean) => {
+            SettingsStore.getValue = (name: SettingKey, roomId: string | null = null, excludeDefault = false): any => {
                 switch (name) {
                     case "feature_allow_screen_share_only_mode":
-                        return true as T;
+                        return true;
                     default:
-                        return originalGetValue<T>(name, roomId, excludeDefault);
+                        return excludeDefault
+                            ? originalGetValue(name, roomId, excludeDefault)
+                            : originalGetValue(name, roomId, excludeDefault);
                 }
             };
             await ElementCall.create(room);
diff --git a/test/unit-tests/models/LocalRoom-test.ts b/test/unit-tests/models/LocalRoom-test.ts
index 9b12ac5985c..b5398c00ae5 100644
--- a/test/unit-tests/models/LocalRoom-test.ts
+++ b/test/unit-tests/models/LocalRoom-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/models/notificationsettings/NotificationSettings-test.ts b/test/unit-tests/models/notificationsettings/NotificationSettings-test.ts
index 98d72e3238f..68bc6a5a4c8 100644
--- a/test/unit-tests/models/notificationsettings/NotificationSettings-test.ts
+++ b/test/unit-tests/models/notificationsettings/NotificationSettings-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/modules/AppModule-test.ts b/test/unit-tests/modules/AppModule-test.ts
index 6294fc50611..af79abd7520 100644
--- a/test/unit-tests/modules/AppModule-test.ts
+++ b/test/unit-tests/modules/AppModule-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/modules/MockModule.ts b/test/unit-tests/modules/MockModule.ts
index 799c22e884c..f699f68dea5 100644
--- a/test/unit-tests/modules/MockModule.ts
+++ b/test/unit-tests/modules/MockModule.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/modules/ModuleComponents-test.tsx b/test/unit-tests/modules/ModuleComponents-test.tsx
index a885e2f99dd..8723dd5135f 100644
--- a/test/unit-tests/modules/ModuleComponents-test.tsx
+++ b/test/unit-tests/modules/ModuleComponents-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/modules/ModuleRunner-test.ts b/test/unit-tests/modules/ModuleRunner-test.ts
index 178863259ae..69a3baf9f0b 100644
--- a/test/unit-tests/modules/ModuleRunner-test.ts
+++ b/test/unit-tests/modules/ModuleRunner-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/modules/ProxiedModuleApi-test.tsx b/test/unit-tests/modules/ProxiedModuleApi-test.tsx
index 9a93a3c76cc..34c3c534dd6 100644
--- a/test/unit-tests/modules/ProxiedModuleApi-test.tsx
+++ b/test/unit-tests/modules/ProxiedModuleApi-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/notifications/ContentRules-test.ts b/test/unit-tests/notifications/ContentRules-test.ts
index d73e2503aa1..16bd082156e 100644
--- a/test/unit-tests/notifications/ContentRules-test.ts
+++ b/test/unit-tests/notifications/ContentRules-test.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 Copyright 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/notifications/PushRuleVectorState-test.ts b/test/unit-tests/notifications/PushRuleVectorState-test.ts
index 66c3d108715..d495752a68f 100644
--- a/test/unit-tests/notifications/PushRuleVectorState-test.ts
+++ b/test/unit-tests/notifications/PushRuleVectorState-test.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 Copyright 2016 OpenMarket Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/settings/SettingsStore-test.ts b/test/unit-tests/settings/SettingsStore-test.ts
index de0012c276b..74da89bde24 100644
--- a/test/unit-tests/settings/SettingsStore-test.ts
+++ b/test/unit-tests/settings/SettingsStore-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -13,10 +13,11 @@ import SdkConfig from "../../../src/SdkConfig";
 import { SettingLevel } from "../../../src/settings/SettingLevel";
 import SettingsStore from "../../../src/settings/SettingsStore";
 import { mkStubRoom, mockPlatformPeg, stubClient } from "../../test-utils";
+import { SettingKey } from "../../../src/settings/Settings.tsx";
 
 const TEST_DATA = [
     {
-        name: "Electron.showTrayIcon",
+        name: "Electron.showTrayIcon" as SettingKey,
         level: SettingLevel.PLATFORM,
         value: true,
     },
diff --git a/test/unit-tests/settings/controllers/AnalyticsController-test.ts b/test/unit-tests/settings/controllers/AnalyticsController-test.ts
index 7b0f7b7b5f9..fb7d4a5613e 100644
--- a/test/unit-tests/settings/controllers/AnalyticsController-test.ts
+++ b/test/unit-tests/settings/controllers/AnalyticsController-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/settings/controllers/DeviceIsolationModeController-test.ts b/test/unit-tests/settings/controllers/DeviceIsolationModeController-test.ts
index cc39a71d2d7..dc1829a05f8 100644
--- a/test/unit-tests/settings/controllers/DeviceIsolationModeController-test.ts
+++ b/test/unit-tests/settings/controllers/DeviceIsolationModeController-test.ts
@@ -1,6 +1,7 @@
 /*
 Copyright 2024 New Vector Ltd.
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/settings/controllers/FallbackIceServerController-test.ts b/test/unit-tests/settings/controllers/FallbackIceServerController-test.ts
index 632ee81bcea..7d98f6087be 100644
--- a/test/unit-tests/settings/controllers/FallbackIceServerController-test.ts
+++ b/test/unit-tests/settings/controllers/FallbackIceServerController-test.ts
@@ -1,7 +1,7 @@
 /*
 Copyright 2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/settings/controllers/FontSizeController-test.ts b/test/unit-tests/settings/controllers/FontSizeController-test.ts
index 64868c7afd0..e9dc3ee9425 100644
--- a/test/unit-tests/settings/controllers/FontSizeController-test.ts
+++ b/test/unit-tests/settings/controllers/FontSizeController-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/settings/controllers/IncompatibleController-test.ts b/test/unit-tests/settings/controllers/IncompatibleController-test.ts
index 3012f4d0e71..3025a8142e8 100644
--- a/test/unit-tests/settings/controllers/IncompatibleController-test.ts
+++ b/test/unit-tests/settings/controllers/IncompatibleController-test.ts
@@ -2,13 +2,14 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 import IncompatibleController from "../../../../src/settings/controllers/IncompatibleController";
 import { SettingLevel } from "../../../../src/settings/SettingLevel";
 import SettingsStore from "../../../../src/settings/SettingsStore";
+import { FeatureSettingKey } from "../../../../src/settings/Settings.tsx";
 
 describe("IncompatibleController", () => {
     const settingsGetValueSpy = jest.spyOn(SettingsStore, "getValue");
@@ -20,7 +21,7 @@ describe("IncompatibleController", () => {
         describe("when incompatibleValue is not set", () => {
             it("returns true when setting value is true", () => {
                 // no incompatible value set, defaulted to true
-                const controller = new IncompatibleController("feature_spotlight", { key: null });
+                const controller = new IncompatibleController("feature_spotlight" as FeatureSettingKey, { key: null });
                 settingsGetValueSpy.mockReturnValue(true);
                 // true === true
                 expect(controller.incompatibleSetting).toBe(true);
@@ -30,7 +31,7 @@ describe("IncompatibleController", () => {
 
             it("returns false when setting value is not true", () => {
                 // no incompatible value set, defaulted to true
-                const controller = new IncompatibleController("feature_spotlight", { key: null });
+                const controller = new IncompatibleController("feature_spotlight" as FeatureSettingKey, { key: null });
                 settingsGetValueSpy.mockReturnValue("test");
                 expect(controller.incompatibleSetting).toBe(false);
             });
@@ -38,13 +39,21 @@ describe("IncompatibleController", () => {
 
         describe("when incompatibleValue is set to a value", () => {
             it("returns true when setting value matches incompatible value", () => {
-                const controller = new IncompatibleController("feature_spotlight", { key: null }, "test");
+                const controller = new IncompatibleController(
+                    "feature_spotlight" as FeatureSettingKey,
+                    { key: null },
+                    "test",
+                );
                 settingsGetValueSpy.mockReturnValue("test");
                 expect(controller.incompatibleSetting).toBe(true);
             });
 
             it("returns false when setting value is not true", () => {
-                const controller = new IncompatibleController("feature_spotlight", { key: null }, "test");
+                const controller = new IncompatibleController(
+                    "feature_spotlight" as FeatureSettingKey,
+                    { key: null },
+                    "test",
+                );
                 settingsGetValueSpy.mockReturnValue("not test");
                 expect(controller.incompatibleSetting).toBe(false);
             });
@@ -53,7 +62,11 @@ describe("IncompatibleController", () => {
         describe("when incompatibleValue is set to a function", () => {
             it("returns result from incompatibleValue function", () => {
                 const incompatibleValueFn = jest.fn().mockReturnValue(false);
-                const controller = new IncompatibleController("feature_spotlight", { key: null }, incompatibleValueFn);
+                const controller = new IncompatibleController(
+                    "feature_spotlight" as FeatureSettingKey,
+                    { key: null },
+                    incompatibleValueFn,
+                );
                 settingsGetValueSpy.mockReturnValue("test");
                 expect(controller.incompatibleSetting).toBe(false);
                 expect(incompatibleValueFn).toHaveBeenCalledWith("test");
@@ -64,7 +77,7 @@ describe("IncompatibleController", () => {
     describe("getValueOverride()", () => {
         it("returns forced value when setting is incompatible", () => {
             settingsGetValueSpy.mockReturnValue(true);
-            const controller = new IncompatibleController("feature_spotlight", { key: null });
+            const controller = new IncompatibleController("feature_spotlight" as FeatureSettingKey, { key: null });
             expect(
                 controller.getValueOverride(SettingLevel.ACCOUNT, "$room:server", true, SettingLevel.ACCOUNT),
             ).toEqual({ key: null });
@@ -72,7 +85,7 @@ describe("IncompatibleController", () => {
 
         it("returns null when setting is not incompatible", () => {
             settingsGetValueSpy.mockReturnValue(false);
-            const controller = new IncompatibleController("feature_spotlight", { key: null });
+            const controller = new IncompatibleController("feature_spotlight" as FeatureSettingKey, { key: null });
             expect(
                 controller.getValueOverride(SettingLevel.ACCOUNT, "$room:server", true, SettingLevel.ACCOUNT),
             ).toEqual(null);
diff --git a/test/unit-tests/settings/controllers/ServerSupportUnstableFeatureController-test.ts b/test/unit-tests/settings/controllers/ServerSupportUnstableFeatureController-test.ts
index 310cb535d02..8dd74c4de5a 100644
--- a/test/unit-tests/settings/controllers/ServerSupportUnstableFeatureController-test.ts
+++ b/test/unit-tests/settings/controllers/ServerSupportUnstableFeatureController-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -11,7 +11,7 @@ import { MatrixClient } from "matrix-js-sdk/src/matrix";
 
 import ServerSupportUnstableFeatureController from "../../../../src/settings/controllers/ServerSupportUnstableFeatureController";
 import { SettingLevel } from "../../../../src/settings/SettingLevel";
-import { LabGroup, SETTINGS } from "../../../../src/settings/Settings";
+import { FeatureSettingKey, LabGroup, SETTINGS } from "../../../../src/settings/Settings";
 import { stubClient } from "../../../test-utils";
 import { WatchManager } from "../../../../src/settings/WatchManager";
 import MatrixClientBackedController from "../../../../src/settings/controllers/MatrixClientBackedController";
@@ -19,7 +19,7 @@ import { TranslationKey } from "../../../../src/languageHandler";
 
 describe("ServerSupportUnstableFeatureController", () => {
     const watchers = new WatchManager();
-    const setting = "setting_name";
+    const setting = "setting_name" as FeatureSettingKey;
 
     async function prepareSetting(
         cli: MatrixClient,
diff --git a/test/unit-tests/settings/controllers/SystemFontController-test.ts b/test/unit-tests/settings/controllers/SystemFontController-test.ts
index fbbe411ca0b..13212ce650c 100644
--- a/test/unit-tests/settings/controllers/SystemFontController-test.ts
+++ b/test/unit-tests/settings/controllers/SystemFontController-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -17,7 +17,7 @@ describe("SystemFontController", () => {
     it("dispatches a system font update action on change", () => {
         const controller = new SystemFontController();
 
-        const getValueSpy = jest.spyOn(SettingsStore, "getValue").mockImplementation((settingName) => {
+        const getValueSpy = jest.spyOn(SettingsStore, "getValue").mockImplementation((settingName): any => {
             if (settingName === "useBundledEmojiFont") return false;
             if (settingName === "useSystemFont") return true;
             if (settingName === "systemFont") return "Comic Sans MS";
diff --git a/test/unit-tests/settings/controllers/ThemeController-test.ts b/test/unit-tests/settings/controllers/ThemeController-test.ts
index 1e5065bf352..c8eb6078985 100644
--- a/test/unit-tests/settings/controllers/ThemeController-test.ts
+++ b/test/unit-tests/settings/controllers/ThemeController-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/settings/enums/ImageSize-test.ts b/test/unit-tests/settings/enums/ImageSize-test.ts
index fdd4b525ac6..0d4990978b7 100644
--- a/test/unit-tests/settings/enums/ImageSize-test.ts
+++ b/test/unit-tests/settings/enums/ImageSize-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/settings/handlers/DeviceSettingsHandler-test.ts b/test/unit-tests/settings/handlers/DeviceSettingsHandler-test.ts
index ca22952737d..7b86e08517f 100644
--- a/test/unit-tests/settings/handlers/DeviceSettingsHandler-test.ts
+++ b/test/unit-tests/settings/handlers/DeviceSettingsHandler-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/settings/handlers/RoomDeviceSettingsHandler-test.ts b/test/unit-tests/settings/handlers/RoomDeviceSettingsHandler-test.ts
index 43e4ffe0370..8c3b1a74356 100644
--- a/test/unit-tests/settings/handlers/RoomDeviceSettingsHandler-test.ts
+++ b/test/unit-tests/settings/handlers/RoomDeviceSettingsHandler-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/settings/watchers/FontWatcher-test.tsx b/test/unit-tests/settings/watchers/FontWatcher-test.tsx
index ae56d0e4d68..e2084984493 100644
--- a/test/unit-tests/settings/watchers/FontWatcher-test.tsx
+++ b/test/unit-tests/settings/watchers/FontWatcher-test.tsx
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2022 r00ster91 <r00ster91@proton.me>
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/settings/watchers/ThemeWatcher-test.tsx b/test/unit-tests/settings/watchers/ThemeWatcher-test.tsx
index 206dbcbcbc8..3e094e0711d 100644
--- a/test/unit-tests/settings/watchers/ThemeWatcher-test.tsx
+++ b/test/unit-tests/settings/watchers/ThemeWatcher-test.tsx
@@ -2,13 +2,14 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 import SettingsStore from "../../../../src/settings/SettingsStore";
 import ThemeWatcher from "../../../../src/settings/watchers/ThemeWatcher";
 import { SettingLevel } from "../../../../src/settings/SettingLevel";
+import { SettingKey, Settings } from "../../../../src/settings/Settings.tsx";
 
 function makeMatchMedia(values: any) {
     class FakeMediaQueryList {
@@ -33,8 +34,12 @@ function makeMatchMedia(values: any) {
     };
 }
 
-function makeGetValue(values: any) {
-    return function getValue<T = any>(settingName: string, _roomId: string | null = null, _excludeDefault = false): T {
+function makeGetValue(values: any): any {
+    return function getValue<S extends SettingKey>(
+        settingName: S,
+        _roomId: string | null = null,
+        _excludeDefault = false,
+    ): Settings[S] {
         return values[settingName];
     };
 }
diff --git a/test/unit-tests/stores/AccountPasswordStore-test.ts b/test/unit-tests/stores/AccountPasswordStore-test.ts
deleted file mode 100644
index 00fa8e05e66..00000000000
--- a/test/unit-tests/stores/AccountPasswordStore-test.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2023 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
-Please see LICENSE files in the repository root for full details.
-*/
-
-import { AccountPasswordStore } from "../../../src/stores/AccountPasswordStore";
-
-jest.useFakeTimers();
-
-describe("AccountPasswordStore", () => {
-    let accountPasswordStore: AccountPasswordStore;
-
-    beforeEach(() => {
-        accountPasswordStore = new AccountPasswordStore();
-    });
-
-    it("should not have a password by default", () => {
-        expect(accountPasswordStore.getPassword()).toBeUndefined();
-    });
-
-    describe("when setting a password", () => {
-        beforeEach(() => {
-            accountPasswordStore.setPassword("pass1");
-        });
-
-        it("should return the password", () => {
-            expect(accountPasswordStore.getPassword()).toBe("pass1");
-        });
-
-        describe("and the password timeout exceed", () => {
-            beforeEach(() => {
-                jest.advanceTimersToNextTimer();
-            });
-
-            it("should clear the password", () => {
-                expect(accountPasswordStore.getPassword()).toBeUndefined();
-            });
-        });
-
-        describe("and setting another password", () => {
-            beforeEach(() => {
-                accountPasswordStore.setPassword("pass2");
-            });
-
-            it("should return the other password", () => {
-                expect(accountPasswordStore.getPassword()).toBe("pass2");
-            });
-        });
-    });
-});
diff --git a/test/unit-tests/stores/ActiveWidgetStore-test.ts b/test/unit-tests/stores/ActiveWidgetStore-test.ts
index 0447621d046..394ac4b743a 100644
--- a/test/unit-tests/stores/ActiveWidgetStore-test.ts
+++ b/test/unit-tests/stores/ActiveWidgetStore-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/stores/AutoRageshakeStore-test.ts b/test/unit-tests/stores/AutoRageshakeStore-test.ts
index ca26cb8d5d9..cbfd40b7f4d 100644
--- a/test/unit-tests/stores/AutoRageshakeStore-test.ts
+++ b/test/unit-tests/stores/AutoRageshakeStore-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/stores/BreadcrumbsStore-test.ts b/test/unit-tests/stores/BreadcrumbsStore-test.ts
index 6419d003029..a73a2f60954 100644
--- a/test/unit-tests/stores/BreadcrumbsStore-test.ts
+++ b/test/unit-tests/stores/BreadcrumbsStore-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/stores/InitialCryptoSetupStore-test.ts b/test/unit-tests/stores/InitialCryptoSetupStore-test.ts
index 64b81bade22..32f63edd688 100644
--- a/test/unit-tests/stores/InitialCryptoSetupStore-test.ts
+++ b/test/unit-tests/stores/InitialCryptoSetupStore-test.ts
@@ -1,19 +1,18 @@
 /*
 Copyright 2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
 import { mocked } from "jest-mock";
 import { MatrixClient } from "matrix-js-sdk/src/matrix";
 import { waitFor } from "jest-matrix-react";
+import { sleep } from "matrix-js-sdk/src/utils";
 
 import { createCrossSigning } from "../../../src/CreateCrossSigning";
 import { InitialCryptoSetupStore } from "../../../src/stores/InitialCryptoSetupStore";
-import { SdkContextClass } from "../../../src/contexts/SDKContext";
 import { createTestClient } from "../../test-utils";
-import { AccountPasswordStore } from "../../../src/stores/AccountPasswordStore";
 
 jest.mock("../../../src/CreateCrossSigning", () => ({
     createCrossSigning: jest.fn(),
@@ -22,7 +21,6 @@ jest.mock("../../../src/CreateCrossSigning", () => ({
 describe("InitialCryptoSetupStore", () => {
     let testStore: InitialCryptoSetupStore;
     let client: MatrixClient;
-    let stores: SdkContextClass;
 
     let createCrossSigningResolve: () => void;
     let createCrossSigningReject: (e: Error) => void;
@@ -30,11 +28,6 @@ describe("InitialCryptoSetupStore", () => {
     beforeEach(() => {
         testStore = new InitialCryptoSetupStore();
         client = createTestClient();
-        stores = {
-            accountPasswordStore: {
-                getPassword: jest.fn(),
-            } as unknown as AccountPasswordStore,
-        } as unknown as SdkContextClass;
 
         mocked(createCrossSigning).mockImplementation(() => {
             return new Promise<void>((resolve, reject) => {
@@ -45,7 +38,7 @@ describe("InitialCryptoSetupStore", () => {
     });
 
     it("should call createCrossSigning when startInitialCryptoSetup is called", async () => {
-        testStore.startInitialCryptoSetup(client, false, stores, jest.fn());
+        testStore.startInitialCryptoSetup(client, jest.fn());
 
         await waitFor(() => expect(createCrossSigning).toHaveBeenCalled());
     });
@@ -54,7 +47,7 @@ describe("InitialCryptoSetupStore", () => {
         const updateSpy = jest.fn();
         testStore.on("update", updateSpy);
 
-        testStore.startInitialCryptoSetup(client, false, stores, jest.fn());
+        testStore.startInitialCryptoSetup(client, jest.fn());
         createCrossSigningResolve();
 
         await waitFor(() => expect(updateSpy).toHaveBeenCalled());
@@ -65,21 +58,28 @@ describe("InitialCryptoSetupStore", () => {
         const updateSpy = jest.fn();
         testStore.on("update", updateSpy);
 
-        testStore.startInitialCryptoSetup(client, false, stores, jest.fn());
+        testStore.startInitialCryptoSetup(client, jest.fn());
         createCrossSigningReject(new Error("Test error"));
 
         await waitFor(() => expect(updateSpy).toHaveBeenCalled());
         expect(testStore.getStatus()).toBe("error");
     });
 
-    it("should ignore failures if tokenLogin is true", async () => {
-        const updateSpy = jest.fn();
-        testStore.on("update", updateSpy);
+    it("should fail to retry once complete", async () => {
+        testStore.startInitialCryptoSetup(client, jest.fn());
 
-        testStore.startInitialCryptoSetup(client, true, stores, jest.fn());
-        createCrossSigningReject(new Error("Test error"));
+        await waitFor(() => expect(createCrossSigning).toHaveBeenCalled());
+        createCrossSigningResolve();
+        await sleep(0); // await the next tick
+        expect(testStore.retry()).toBeFalsy();
+    });
 
-        await waitFor(() => expect(updateSpy).toHaveBeenCalled());
-        expect(testStore.getStatus()).toBe("complete");
+    it("should retry if initial attempt failed", async () => {
+        testStore.startInitialCryptoSetup(client, jest.fn());
+
+        await waitFor(() => expect(createCrossSigning).toHaveBeenCalled());
+        createCrossSigningReject(new Error("Test error"));
+        await sleep(0); // await the next tick
+        expect(testStore.retry()).toBeTruthy();
     });
 });
diff --git a/test/unit-tests/stores/LifecycleStore-test.ts b/test/unit-tests/stores/LifecycleStore-test.ts
index 468e27a5002..4c4b7a3a5d3 100644
--- a/test/unit-tests/stores/LifecycleStore-test.ts
+++ b/test/unit-tests/stores/LifecycleStore-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/stores/MemberListStore-test.ts b/test/unit-tests/stores/MemberListStore-test.ts
index 470087031ab..c61bb904255 100644
--- a/test/unit-tests/stores/MemberListStore-test.ts
+++ b/test/unit-tests/stores/MemberListStore-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/stores/OwnBeaconStore-test.ts b/test/unit-tests/stores/OwnBeaconStore-test.ts
index 9a668b7bf8a..bd35d037655 100644
--- a/test/unit-tests/stores/OwnBeaconStore-test.ts
+++ b/test/unit-tests/stores/OwnBeaconStore-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/stores/OwnProfileStore-test.ts b/test/unit-tests/stores/OwnProfileStore-test.ts
index 290df8113d5..57234091d04 100644
--- a/test/unit-tests/stores/OwnProfileStore-test.ts
+++ b/test/unit-tests/stores/OwnProfileStore-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/stores/ReleaseAnnouncementStore-test.tsx b/test/unit-tests/stores/ReleaseAnnouncementStore-test.tsx
index 919ff22d92d..61cfa93f42c 100644
--- a/test/unit-tests/stores/ReleaseAnnouncementStore-test.tsx
+++ b/test/unit-tests/stores/ReleaseAnnouncementStore-test.tsx
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2024 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/test/unit-tests/stores/RoomNotificationStateStore-test.ts b/test/unit-tests/stores/RoomNotificationStateStore-test.ts
index 15c36f8b3d3..7787b28b689 100644
--- a/test/unit-tests/stores/RoomNotificationStateStore-test.ts
+++ b/test/unit-tests/stores/RoomNotificationStateStore-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/stores/RoomViewStore-test.ts b/test/unit-tests/stores/RoomViewStore-test.ts
index 782bb797385..dc18d68cbdd 100644
--- a/test/unit-tests/stores/RoomViewStore-test.ts
+++ b/test/unit-tests/stores/RoomViewStore-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2017-2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/stores/SetupEncryptionStore-test.ts b/test/unit-tests/stores/SetupEncryptionStore-test.ts
index d3d0300a215..0609dbe66fb 100644
--- a/test/unit-tests/stores/SetupEncryptionStore-test.ts
+++ b/test/unit-tests/stores/SetupEncryptionStore-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -11,7 +11,6 @@ import { MatrixClient, Device } from "matrix-js-sdk/src/matrix";
 import { SecretStorageKeyDescriptionAesV1, ServerSideSecretStorage } from "matrix-js-sdk/src/secret-storage";
 import { BootstrapCrossSigningOpts, CryptoApi, DeviceVerificationStatus } from "matrix-js-sdk/src/crypto-api";
 
-import { SdkContextClass } from "../../../src/contexts/SDKContext";
 import { accessSecretStorage } from "../../../src/SecurityManager";
 import { SetupEncryptionStore } from "../../../src/stores/SetupEncryptionStore";
 import { emitPromise, stubClient } from "../../test-utils";
@@ -21,7 +20,6 @@ jest.mock("../../../src/SecurityManager", () => ({
 }));
 
 describe("SetupEncryptionStore", () => {
-    const cachedPassword = "p4assword";
     let client: Mocked<MatrixClient>;
     let mockCrypto: Mocked<CryptoApi>;
     let mockSecretStorage: Mocked<ServerSideSecretStorage>;
@@ -47,11 +45,6 @@ describe("SetupEncryptionStore", () => {
         Object.defineProperty(client, "secretStorage", { value: mockSecretStorage });
 
         setupEncryptionStore = new SetupEncryptionStore();
-        SdkContextClass.instance.accountPasswordStore.setPassword(cachedPassword);
-    });
-
-    afterEach(() => {
-        SdkContextClass.instance.accountPasswordStore.clearPassword();
     });
 
     describe("start", () => {
@@ -172,7 +165,6 @@ describe("SetupEncryptionStore", () => {
         await setupEncryptionStore.resetConfirm();
 
         expect(mocked(accessSecretStorage)).toHaveBeenCalledWith(expect.any(Function), {
-            accountPassword: cachedPassword,
             forceReset: true,
             resetCrossSigning: true,
         });
diff --git a/test/unit-tests/stores/SpaceStore-test.ts b/test/unit-tests/stores/SpaceStore-test.ts
index b5f4ddef4f0..27ec09b856e 100644
--- a/test/unit-tests/stores/SpaceStore-test.ts
+++ b/test/unit-tests/stores/SpaceStore-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/stores/ToastStore-test.ts b/test/unit-tests/stores/ToastStore-test.ts
index cb42f1e0936..8332cc823da 100644
--- a/test/unit-tests/stores/ToastStore-test.ts
+++ b/test/unit-tests/stores/ToastStore-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/stores/TypingStore-test.ts b/test/unit-tests/stores/TypingStore-test.ts
index 2249b4ff2db..af055a32f91 100644
--- a/test/unit-tests/stores/TypingStore-test.ts
+++ b/test/unit-tests/stores/TypingStore-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/stores/UserProfilesStore-test.ts b/test/unit-tests/stores/UserProfilesStore-test.ts
index 0bf4a559c77..8dec46e93ba 100644
--- a/test/unit-tests/stores/UserProfilesStore-test.ts
+++ b/test/unit-tests/stores/UserProfilesStore-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/stores/VoiceRecordingStore-test.ts b/test/unit-tests/stores/VoiceRecordingStore-test.ts
index 5cdb92f4236..8b0ba3d0653 100644
--- a/test/unit-tests/stores/VoiceRecordingStore-test.ts
+++ b/test/unit-tests/stores/VoiceRecordingStore-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/stores/WidgetLayoutStore-test.ts b/test/unit-tests/stores/WidgetLayoutStore-test.ts
index b2a2ddde642..5697cac3311 100644
--- a/test/unit-tests/stores/WidgetLayoutStore-test.ts
+++ b/test/unit-tests/stores/WidgetLayoutStore-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/stores/notifications/NotificationColor-test.ts b/test/unit-tests/stores/notifications/NotificationColor-test.ts
index 529fb125180..f6ad12829bf 100644
--- a/test/unit-tests/stores/notifications/NotificationColor-test.ts
+++ b/test/unit-tests/stores/notifications/NotificationColor-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/stores/notifications/RoomNotificationState-test.ts b/test/unit-tests/stores/notifications/RoomNotificationState-test.ts
index 396bb06ec63..88847b42e85 100644
--- a/test/unit-tests/stores/notifications/RoomNotificationState-test.ts
+++ b/test/unit-tests/stores/notifications/RoomNotificationState-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022, 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/stores/oidc/OidcClientStore-test.ts b/test/unit-tests/stores/oidc/OidcClientStore-test.ts
index c7e94764372..8de1d9dad10 100644
--- a/test/unit-tests/stores/oidc/OidcClientStore-test.ts
+++ b/test/unit-tests/stores/oidc/OidcClientStore-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/stores/right-panel/RightPanelStore-test.ts b/test/unit-tests/stores/right-panel/RightPanelStore-test.ts
index 27c4d730a97..1897649cee1 100644
--- a/test/unit-tests/stores/right-panel/RightPanelStore-test.ts
+++ b/test/unit-tests/stores/right-panel/RightPanelStore-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/stores/right-panel/action-handlers/View3pidInvite-test.ts b/test/unit-tests/stores/right-panel/action-handlers/View3pidInvite-test.ts
index 9503bb4ae37..757c1b93b48 100644
--- a/test/unit-tests/stores/right-panel/action-handlers/View3pidInvite-test.ts
+++ b/test/unit-tests/stores/right-panel/action-handlers/View3pidInvite-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/stores/room-list/MessagePreviewStore-test.ts b/test/unit-tests/stores/room-list/MessagePreviewStore-test.ts
index 861b6dcd11f..864fa6c2b47 100644
--- a/test/unit-tests/stores/room-list/MessagePreviewStore-test.ts
+++ b/test/unit-tests/stores/room-list/MessagePreviewStore-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/stores/room-list/RoomListStore-test.ts b/test/unit-tests/stores/room-list/RoomListStore-test.ts
index e8aad47a7b6..a84ea341bc9 100644
--- a/test/unit-tests/stores/room-list/RoomListStore-test.ts
+++ b/test/unit-tests/stores/room-list/RoomListStore-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/stores/room-list/SlidingRoomListStore-test.ts b/test/unit-tests/stores/room-list/SlidingRoomListStore-test.ts
index 4b0753ad669..40d8cbbc658 100644
--- a/test/unit-tests/stores/room-list/SlidingRoomListStore-test.ts
+++ b/test/unit-tests/stores/room-list/SlidingRoomListStore-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 import { mocked } from "jest-mock";
diff --git a/test/unit-tests/stores/room-list/SpaceWatcher-test.ts b/test/unit-tests/stores/room-list/SpaceWatcher-test.ts
index 619b92d4aa5..62686c7d3bd 100644
--- a/test/unit-tests/stores/room-list/SpaceWatcher-test.ts
+++ b/test/unit-tests/stores/room-list/SpaceWatcher-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/stores/room-list/algorithms/Algorithm-test.ts b/test/unit-tests/stores/room-list/algorithms/Algorithm-test.ts
index 9a4a518b1d6..07a668624ce 100644
--- a/test/unit-tests/stores/room-list/algorithms/Algorithm-test.ts
+++ b/test/unit-tests/stores/room-list/algorithms/Algorithm-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/stores/room-list/algorithms/RecentAlgorithm-test.ts b/test/unit-tests/stores/room-list/algorithms/RecentAlgorithm-test.ts
index e0e06bbaf7d..42fe0ca3dde 100644
--- a/test/unit-tests/stores/room-list/algorithms/RecentAlgorithm-test.ts
+++ b/test/unit-tests/stores/room-list/algorithms/RecentAlgorithm-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/stores/room-list/algorithms/list-ordering/ImportanceAlgorithm-test.ts b/test/unit-tests/stores/room-list/algorithms/list-ordering/ImportanceAlgorithm-test.ts
index 7c40f90ef81..5573157b143 100644
--- a/test/unit-tests/stores/room-list/algorithms/list-ordering/ImportanceAlgorithm-test.ts
+++ b/test/unit-tests/stores/room-list/algorithms/list-ordering/ImportanceAlgorithm-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/stores/room-list/algorithms/list-ordering/NaturalAlgorithm-test.ts b/test/unit-tests/stores/room-list/algorithms/list-ordering/NaturalAlgorithm-test.ts
index 799e196c2af..cf0fd59cd42 100644
--- a/test/unit-tests/stores/room-list/algorithms/list-ordering/NaturalAlgorithm-test.ts
+++ b/test/unit-tests/stores/room-list/algorithms/list-ordering/NaturalAlgorithm-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/stores/room-list/filters/SpaceFilterCondition-test.ts b/test/unit-tests/stores/room-list/filters/SpaceFilterCondition-test.ts
index 09ea9791986..f0a27c43a1c 100644
--- a/test/unit-tests/stores/room-list/filters/SpaceFilterCondition-test.ts
+++ b/test/unit-tests/stores/room-list/filters/SpaceFilterCondition-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/stores/room-list/filters/VisibilityProvider-test.ts b/test/unit-tests/stores/room-list/filters/VisibilityProvider-test.ts
index 078f774e486..0ccb70c308c 100644
--- a/test/unit-tests/stores/room-list/filters/VisibilityProvider-test.ts
+++ b/test/unit-tests/stores/room-list/filters/VisibilityProvider-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/stores/room-list/previews/MessageEventPreview-test.ts b/test/unit-tests/stores/room-list/previews/MessageEventPreview-test.ts
index ec97cdd20e4..78539d14fb1 100644
--- a/test/unit-tests/stores/room-list/previews/MessageEventPreview-test.ts
+++ b/test/unit-tests/stores/room-list/previews/MessageEventPreview-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/stores/room-list/previews/PollStartEventPreview-test.ts b/test/unit-tests/stores/room-list/previews/PollStartEventPreview-test.ts
index 1d6c5fa310c..2b09294c616 100644
--- a/test/unit-tests/stores/room-list/previews/PollStartEventPreview-test.ts
+++ b/test/unit-tests/stores/room-list/previews/PollStartEventPreview-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/stores/room-list/previews/ReactionEventPreview-test.ts b/test/unit-tests/stores/room-list/previews/ReactionEventPreview-test.ts
index 7a7ce9e2b38..8e01460abf2 100644
--- a/test/unit-tests/stores/room-list/previews/ReactionEventPreview-test.ts
+++ b/test/unit-tests/stores/room-list/previews/ReactionEventPreview-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/stores/room-list/utils/roomMute-test.ts b/test/unit-tests/stores/room-list/utils/roomMute-test.ts
index 8c6728772e3..9e6009e52a7 100644
--- a/test/unit-tests/stores/room-list/utils/roomMute-test.ts
+++ b/test/unit-tests/stores/room-list/utils/roomMute-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/stores/widgets/StopGapWidget-test.ts b/test/unit-tests/stores/widgets/StopGapWidget-test.ts
index 1416711017f..f767c96a028 100644
--- a/test/unit-tests/stores/widgets/StopGapWidget-test.ts
+++ b/test/unit-tests/stores/widgets/StopGapWidget-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/stores/widgets/StopGapWidgetDriver-test.ts b/test/unit-tests/stores/widgets/StopGapWidgetDriver-test.ts
index f5c0c5fe230..e484d0cc33f 100644
--- a/test/unit-tests/stores/widgets/StopGapWidgetDriver-test.ts
+++ b/test/unit-tests/stores/widgets/StopGapWidgetDriver-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/stores/widgets/WidgetPermissionStore-test.ts b/test/unit-tests/stores/widgets/WidgetPermissionStore-test.ts
index cca97bdbc65..1dc9936d895 100644
--- a/test/unit-tests/stores/widgets/WidgetPermissionStore-test.ts
+++ b/test/unit-tests/stores/widgets/WidgetPermissionStore-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/submit-rageshake-test.ts b/test/unit-tests/submit-rageshake-test.ts
index 2f1b150349d..44e4e3b517d 100644
--- a/test/unit-tests/submit-rageshake-test.ts
+++ b/test/unit-tests/submit-rageshake-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -21,6 +21,7 @@ import { getMockClientWithEventEmitter, mockClientMethodsCrypto, mockPlatformPeg
 import { collectBugReport } from "../../src/rageshake/submit-rageshake";
 import SettingsStore from "../../src/settings/SettingsStore";
 import { ConsoleLogger } from "../../src/rageshake/rageshake";
+import { FeatureSettingKey, SettingKey } from "../../src/settings/Settings.tsx";
 
 describe("Rageshakes", () => {
     const RUST_CRYPTO_VERSION = "Rust SDK 0.7.0 (691ec63), Vodozemac 0.5.0";
@@ -376,8 +377,11 @@ describe("Rageshakes", () => {
         const mockSettingsStore = mocked(SettingsStore);
 
         it("should collect labs from settings store", async () => {
-            const someFeatures: string[] = ["feature_video_rooms", "feature_notification_settings2"];
-            const enabledFeatures: string[] = ["feature_video_rooms"];
+            const someFeatures = [
+                "feature_video_rooms",
+                "feature_notification_settings2",
+            ] as unknown[] as FeatureSettingKey[];
+            const enabledFeatures: SettingKey[] = ["feature_video_rooms"];
             jest.spyOn(mockSettingsStore, "getFeatureSettingNames").mockReturnValue(someFeatures);
             jest.spyOn(mockSettingsStore, "getValue").mockImplementation((settingName): any => {
                 return enabledFeatures.includes(settingName);
diff --git a/test/unit-tests/theme-test.ts b/test/unit-tests/theme-test.ts
index 8d18281dbfd..6c2f247e4e1 100644
--- a/test/unit-tests/theme-test.ts
+++ b/test/unit-tests/theme-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -149,7 +149,7 @@ describe("theme", () => {
         });
 
         it("should be robust to malformed custom_themes values", () => {
-            jest.spyOn(SettingsStore, "getValue").mockReturnValue([23]);
+            jest.spyOn(SettingsStore, "getValue").mockReturnValue([23] as any);
             expect(enumerateThemes()).toEqual({
                 "light": "Light",
                 "light-high-contrast": "Light high contrast",
diff --git a/test/unit-tests/toasts/IncomingCallToast-test.tsx b/test/unit-tests/toasts/IncomingCallToast-test.tsx
index 28ca15943f8..2d035c94dd3 100644
--- a/test/unit-tests/toasts/IncomingCallToast-test.tsx
+++ b/test/unit-tests/toasts/IncomingCallToast-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/toasts/IncomingLegacyCallToast-test.tsx b/test/unit-tests/toasts/IncomingLegacyCallToast-test.tsx
index 796fb07eacc..4b766c6a08b 100644
--- a/test/unit-tests/toasts/IncomingLegacyCallToast-test.tsx
+++ b/test/unit-tests/toasts/IncomingLegacyCallToast-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 import { render } from "jest-matrix-react";
diff --git a/test/unit-tests/toasts/SetupEncryptionToast-test.tsx b/test/unit-tests/toasts/SetupEncryptionToast-test.tsx
index 5ce3fab9aeb..8917587cc1f 100644
--- a/test/unit-tests/toasts/SetupEncryptionToast-test.tsx
+++ b/test/unit-tests/toasts/SetupEncryptionToast-test.tsx
@@ -1,7 +1,7 @@
 /*
 Copyright 2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/toasts/UnverifiedSessionToast-test.tsx b/test/unit-tests/toasts/UnverifiedSessionToast-test.tsx
index 8b68b3e3786..14cacb46293 100644
--- a/test/unit-tests/toasts/UnverifiedSessionToast-test.tsx
+++ b/test/unit-tests/toasts/UnverifiedSessionToast-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/useTopic-test.tsx b/test/unit-tests/useTopic-test.tsx
index 81afaae985e..093bd82658f 100644
--- a/test/unit-tests/useTopic-test.tsx
+++ b/test/unit-tests/useTopic-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/AnimationUtils-test.ts b/test/unit-tests/utils/AnimationUtils-test.ts
index 97a1840deca..196285973a9 100644
--- a/test/unit-tests/utils/AnimationUtils-test.ts
+++ b/test/unit-tests/utils/AnimationUtils-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/AutoDiscoveryUtils-test.tsx b/test/unit-tests/utils/AutoDiscoveryUtils-test.tsx
index 6d60a2fa5f0..a49707e3101 100644
--- a/test/unit-tests/utils/AutoDiscoveryUtils-test.tsx
+++ b/test/unit-tests/utils/AutoDiscoveryUtils-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/DMRoomMap-test.ts b/test/unit-tests/utils/DMRoomMap-test.ts
index a59c4103738..d8c44da954b 100644
--- a/test/unit-tests/utils/DMRoomMap-test.ts
+++ b/test/unit-tests/utils/DMRoomMap-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/DateUtils-test.ts b/test/unit-tests/utils/DateUtils-test.ts
index 2007c8a05a3..edf7fee4816 100644
--- a/test/unit-tests/utils/DateUtils-test.ts
+++ b/test/unit-tests/utils/DateUtils-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/ErrorUtils-test.ts b/test/unit-tests/utils/ErrorUtils-test.ts
index 0a61bb053fb..f3ede81eb7b 100644
--- a/test/unit-tests/utils/ErrorUtils-test.ts
+++ b/test/unit-tests/utils/ErrorUtils-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/EventUtils-test.ts b/test/unit-tests/utils/EventUtils-test.ts
index c7828c3a2fc..94f1c6d2627 100644
--- a/test/unit-tests/utils/EventUtils-test.ts
+++ b/test/unit-tests/utils/EventUtils-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/Feedback-test.ts b/test/unit-tests/utils/Feedback-test.ts
index 249b55b2b11..a0e04df2e8a 100644
--- a/test/unit-tests/utils/Feedback-test.ts
+++ b/test/unit-tests/utils/Feedback-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/FileUtils-test.ts b/test/unit-tests/utils/FileUtils-test.ts
index 0b77aa23172..c15c58fd879 100644
--- a/test/unit-tests/utils/FileUtils-test.ts
+++ b/test/unit-tests/utils/FileUtils-test.ts
@@ -1,7 +1,7 @@
 /*
 Copyright 2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/FixedRollingArray-test.ts b/test/unit-tests/utils/FixedRollingArray-test.ts
index 7e01c310acc..51b4748a82d 100644
--- a/test/unit-tests/utils/FixedRollingArray-test.ts
+++ b/test/unit-tests/utils/FixedRollingArray-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/FormattingUtils-test.tsx b/test/unit-tests/utils/FormattingUtils-test.tsx
index 794086a62a8..1b5aedda530 100644
--- a/test/unit-tests/utils/FormattingUtils-test.tsx
+++ b/test/unit-tests/utils/FormattingUtils-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/LruCache-test.ts b/test/unit-tests/utils/LruCache-test.ts
index 177527ba468..3090c22ace3 100644
--- a/test/unit-tests/utils/LruCache-test.ts
+++ b/test/unit-tests/utils/LruCache-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/MegolmExportEncryption-test.ts b/test/unit-tests/utils/MegolmExportEncryption-test.ts
index 416f5f9bedf..0d963ec11a8 100644
--- a/test/unit-tests/utils/MegolmExportEncryption-test.ts
+++ b/test/unit-tests/utils/MegolmExportEncryption-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2017 Vector Creations Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/MessageDiffUtils-test.tsx b/test/unit-tests/utils/MessageDiffUtils-test.tsx
index 5094ffc45c0..08ac1d5209e 100644
--- a/test/unit-tests/utils/MessageDiffUtils-test.tsx
+++ b/test/unit-tests/utils/MessageDiffUtils-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/MultiInviter-test.ts b/test/unit-tests/utils/MultiInviter-test.ts
index 774b882c02c..15d1fc2dbb4 100644
--- a/test/unit-tests/utils/MultiInviter-test.ts
+++ b/test/unit-tests/utils/MultiInviter-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/PhasedRolloutFeature-test.ts b/test/unit-tests/utils/PhasedRolloutFeature-test.ts
index 013189c8724..3e4a75a1b28 100644
--- a/test/unit-tests/utils/PhasedRolloutFeature-test.ts
+++ b/test/unit-tests/utils/PhasedRolloutFeature-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/PinningUtils-test.ts b/test/unit-tests/utils/PinningUtils-test.ts
index 537c31dd638..59436ce48d7 100644
--- a/test/unit-tests/utils/PinningUtils-test.ts
+++ b/test/unit-tests/utils/PinningUtils-test.ts
@@ -2,7 +2,7 @@
  * Copyright 2024 New Vector Ltd.
  * Copyright 2024 The Matrix.org Foundation C.I.C.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
  */
 
diff --git a/test/unit-tests/utils/SearchInput-test.ts b/test/unit-tests/utils/SearchInput-test.ts
index fa09e79c2ac..79786601a5b 100644
--- a/test/unit-tests/utils/SearchInput-test.ts
+++ b/test/unit-tests/utils/SearchInput-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 Boluwatife Omosowon <boluomosowon@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 import { mocked } from "jest-mock";
diff --git a/test/unit-tests/utils/SessionLock-test.ts b/test/unit-tests/utils/SessionLock-test.ts
index 9bb5c05a6bf..fb3ab7e6ea1 100644
--- a/test/unit-tests/utils/SessionLock-test.ts
+++ b/test/unit-tests/utils/SessionLock-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/ShieldUtils-test.ts b/test/unit-tests/utils/ShieldUtils-test.ts
index 7b29aa44c34..02c69444dc8 100644
--- a/test/unit-tests/utils/ShieldUtils-test.ts
+++ b/test/unit-tests/utils/ShieldUtils-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/Singleflight-test.ts b/test/unit-tests/utils/Singleflight-test.ts
index 7da5c8d3512..58e15f20601 100644
--- a/test/unit-tests/utils/Singleflight-test.ts
+++ b/test/unit-tests/utils/Singleflight-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/SnakedObject-test.ts b/test/unit-tests/utils/SnakedObject-test.ts
index b1d7c16b9ba..d0195aef39b 100644
--- a/test/unit-tests/utils/SnakedObject-test.ts
+++ b/test/unit-tests/utils/SnakedObject-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/StorageAccess-test.ts b/test/unit-tests/utils/StorageAccess-test.ts
index 6a20827d688..73a5454bae3 100644
--- a/test/unit-tests/utils/StorageAccess-test.ts
+++ b/test/unit-tests/utils/StorageAccess-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/StorageManager-test.ts b/test/unit-tests/utils/StorageManager-test.ts
index d028784e9d5..99713e7b86f 100644
--- a/test/unit-tests/utils/StorageManager-test.ts
+++ b/test/unit-tests/utils/StorageManager-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2024 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/UrlUtils-test.ts b/test/unit-tests/utils/UrlUtils-test.ts
index e99dbf80591..649b7ab7cff 100644
--- a/test/unit-tests/utils/UrlUtils-test.ts
+++ b/test/unit-tests/utils/UrlUtils-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/WidgetUtils-test.ts b/test/unit-tests/utils/WidgetUtils-test.ts
index fd900b98988..b9c7e95f9de 100644
--- a/test/unit-tests/utils/WidgetUtils-test.ts
+++ b/test/unit-tests/utils/WidgetUtils-test.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2022 Oliver Sand
 Copyright 2022 Nordeck IT + Consulting GmbH.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/arrays-test.ts b/test/unit-tests/utils/arrays-test.ts
index 7e440d3ee5d..93cf56d3b9c 100644
--- a/test/unit-tests/utils/arrays-test.ts
+++ b/test/unit-tests/utils/arrays-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/beacon/bounds-test.ts b/test/unit-tests/utils/beacon/bounds-test.ts
index 133e86f83be..b517a4910d8 100644
--- a/test/unit-tests/utils/beacon/bounds-test.ts
+++ b/test/unit-tests/utils/beacon/bounds-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/beacon/duration-test.ts b/test/unit-tests/utils/beacon/duration-test.ts
index 044af296c75..da17d6cbb4d 100644
--- a/test/unit-tests/utils/beacon/duration-test.ts
+++ b/test/unit-tests/utils/beacon/duration-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/beacon/geolocation-test.ts b/test/unit-tests/utils/beacon/geolocation-test.ts
index a1a71155de3..f5094347722 100644
--- a/test/unit-tests/utils/beacon/geolocation-test.ts
+++ b/test/unit-tests/utils/beacon/geolocation-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/beacon/timeline-test.ts b/test/unit-tests/utils/beacon/timeline-test.ts
index 01748cd1466..0c7306bf4fb 100644
--- a/test/unit-tests/utils/beacon/timeline-test.ts
+++ b/test/unit-tests/utils/beacon/timeline-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/colour-test.ts b/test/unit-tests/utils/colour-test.ts
index 52490f82a38..7ba966e25e1 100644
--- a/test/unit-tests/utils/colour-test.ts
+++ b/test/unit-tests/utils/colour-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 Emmanuel Ezeka <eec.studies@gmail.com>
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/connection-test.ts b/test/unit-tests/utils/connection-test.ts
index b8f10bb2227..f39c5164e49 100644
--- a/test/unit-tests/utils/connection-test.ts
+++ b/test/unit-tests/utils/connection-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/createVoiceMessageContent-test.ts b/test/unit-tests/utils/createVoiceMessageContent-test.ts
index c37c4d1bd0d..6790104fc64 100644
--- a/test/unit-tests/utils/createVoiceMessageContent-test.ts
+++ b/test/unit-tests/utils/createVoiceMessageContent-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/crypto/deviceInfo-test.ts b/test/unit-tests/utils/crypto/deviceInfo-test.ts
index 0e1094d485e..a5348781fd0 100644
--- a/test/unit-tests/utils/crypto/deviceInfo-test.ts
+++ b/test/unit-tests/utils/crypto/deviceInfo-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/crypto/shouldForceDisableEncryption-test.ts b/test/unit-tests/utils/crypto/shouldForceDisableEncryption-test.ts
index a15184028e6..f4a3048f513 100644
--- a/test/unit-tests/utils/crypto/shouldForceDisableEncryption-test.ts
+++ b/test/unit-tests/utils/crypto/shouldForceDisableEncryption-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/device/clientInformation-test.ts b/test/unit-tests/utils/device/clientInformation-test.ts
index 78f7627c5fd..c85dbba4e61 100644
--- a/test/unit-tests/utils/device/clientInformation-test.ts
+++ b/test/unit-tests/utils/device/clientInformation-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/device/parseUserAgent-test.ts b/test/unit-tests/utils/device/parseUserAgent-test.ts
index efebae0abd7..26cdb22a377 100644
--- a/test/unit-tests/utils/device/parseUserAgent-test.ts
+++ b/test/unit-tests/utils/device/parseUserAgent-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/device/snoozeBulkUnverifiedDeviceReminder-test.ts b/test/unit-tests/utils/device/snoozeBulkUnverifiedDeviceReminder-test.ts
index b726e84eada..268176df299 100644
--- a/test/unit-tests/utils/device/snoozeBulkUnverifiedDeviceReminder-test.ts
+++ b/test/unit-tests/utils/device/snoozeBulkUnverifiedDeviceReminder-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/direct-messages-test.ts b/test/unit-tests/utils/direct-messages-test.ts
index ce6dc7805a0..cebb80db958 100644
--- a/test/unit-tests/utils/direct-messages-test.ts
+++ b/test/unit-tests/utils/direct-messages-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/dm/createDmLocalRoom-test.ts b/test/unit-tests/utils/dm/createDmLocalRoom-test.ts
index 0dca0daa01a..f42804489d7 100644
--- a/test/unit-tests/utils/dm/createDmLocalRoom-test.ts
+++ b/test/unit-tests/utils/dm/createDmLocalRoom-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/dm/filterValidMDirect-test.ts b/test/unit-tests/utils/dm/filterValidMDirect-test.ts
index 4eb450a43f9..ee21ed338a1 100644
--- a/test/unit-tests/utils/dm/filterValidMDirect-test.ts
+++ b/test/unit-tests/utils/dm/filterValidMDirect-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/dm/findDMForUser-test.ts b/test/unit-tests/utils/dm/findDMForUser-test.ts
index 55abd07460c..1e12eebcd14 100644
--- a/test/unit-tests/utils/dm/findDMForUser-test.ts
+++ b/test/unit-tests/utils/dm/findDMForUser-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/dm/findDMRoom-test.ts b/test/unit-tests/utils/dm/findDMRoom-test.ts
index c21d9355543..17efd31d9cc 100644
--- a/test/unit-tests/utils/dm/findDMRoom-test.ts
+++ b/test/unit-tests/utils/dm/findDMRoom-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/enums-test.ts b/test/unit-tests/utils/enums-test.ts
index 2596659c176..b431e2de3ed 100644
--- a/test/unit-tests/utils/enums-test.ts
+++ b/test/unit-tests/utils/enums-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/export-test.tsx b/test/unit-tests/utils/export-test.tsx
index e8231a3998d..3ff63da4b3b 100644
--- a/test/unit-tests/utils/export-test.tsx
+++ b/test/unit-tests/utils/export-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/exportUtils/HTMLExport-test.ts b/test/unit-tests/utils/exportUtils/HTMLExport-test.ts
index d169b55a7cc..e2ee0b670e3 100644
--- a/test/unit-tests/utils/exportUtils/HTMLExport-test.ts
+++ b/test/unit-tests/utils/exportUtils/HTMLExport-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022, 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/exportUtils/JSONExport-test.ts b/test/unit-tests/utils/exportUtils/JSONExport-test.ts
index 2f01018727d..0dcf49059d8 100644
--- a/test/unit-tests/utils/exportUtils/JSONExport-test.ts
+++ b/test/unit-tests/utils/exportUtils/JSONExport-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/exportUtils/PlainTextExport-test.ts b/test/unit-tests/utils/exportUtils/PlainTextExport-test.ts
index 7c90d03f4de..4b28c5bfb41 100644
--- a/test/unit-tests/utils/exportUtils/PlainTextExport-test.ts
+++ b/test/unit-tests/utils/exportUtils/PlainTextExport-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
@@ -44,7 +44,7 @@ describe("PlainTextExport", () => {
         [24, false, "Fri, Apr 16, 2021, 17:20:00 - @alice:example.com: Hello, world!\n"],
         [12, true, "Fri, Apr 16, 2021, 5:20:00 PM - @alice:example.com: Hello, world!\n"],
     ])("should return text with %i hr time format", async (hour: number, setting: boolean, expectedMessage: string) => {
-        jest.spyOn(SettingsStore, "getValue").mockImplementation((settingName: string) =>
+        jest.spyOn(SettingsStore, "getValue").mockImplementation((settingName: string): any =>
             settingName === "showTwelveHourTimestamps" ? setting : undefined,
         );
         const events: MatrixEvent[] = [
diff --git a/test/unit-tests/utils/exportUtils/exportCSS-test.ts b/test/unit-tests/utils/exportUtils/exportCSS-test.ts
index 28e49e81faf..0cf154e9be6 100644
--- a/test/unit-tests/utils/exportUtils/exportCSS-test.ts
+++ b/test/unit-tests/utils/exportUtils/exportCSS-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/i18n-helpers-test.ts b/test/unit-tests/utils/i18n-helpers-test.ts
index 68c94fb9f9a..04e72122644 100644
--- a/test/unit-tests/utils/i18n-helpers-test.ts
+++ b/test/unit-tests/utils/i18n-helpers-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/iterables-test.ts b/test/unit-tests/utils/iterables-test.ts
index 6ff175b95a6..963f6efd827 100644
--- a/test/unit-tests/utils/iterables-test.ts
+++ b/test/unit-tests/utils/iterables-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/leave-behaviour-test.ts b/test/unit-tests/utils/leave-behaviour-test.ts
index 996c53ed05c..f42fc072339 100644
--- a/test/unit-tests/utils/leave-behaviour-test.ts
+++ b/test/unit-tests/utils/leave-behaviour-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/local-room-test.ts b/test/unit-tests/utils/local-room-test.ts
index 2789bf65a3c..91219dcb585 100644
--- a/test/unit-tests/utils/local-room-test.ts
+++ b/test/unit-tests/utils/local-room-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/localRoom/isLocalRoom-test.ts b/test/unit-tests/utils/localRoom/isLocalRoom-test.ts
index 016da52b407..2d11f4e5237 100644
--- a/test/unit-tests/utils/localRoom/isLocalRoom-test.ts
+++ b/test/unit-tests/utils/localRoom/isLocalRoom-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/localRoom/isRoomReady-test.ts b/test/unit-tests/utils/localRoom/isRoomReady-test.ts
index aff645aa04a..2effc7c6a9a 100644
--- a/test/unit-tests/utils/localRoom/isRoomReady-test.ts
+++ b/test/unit-tests/utils/localRoom/isRoomReady-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/location/isSelfLocation-test.ts b/test/unit-tests/utils/location/isSelfLocation-test.ts
index 5115468f32c..6cccc63f72b 100644
--- a/test/unit-tests/utils/location/isSelfLocation-test.ts
+++ b/test/unit-tests/utils/location/isSelfLocation-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/location/locationEventGeoUri-test.ts b/test/unit-tests/utils/location/locationEventGeoUri-test.ts
index c48478c8ecc..c1c77f2844e 100644
--- a/test/unit-tests/utils/location/locationEventGeoUri-test.ts
+++ b/test/unit-tests/utils/location/locationEventGeoUri-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/location/map-test.ts b/test/unit-tests/utils/location/map-test.ts
index b6f9012c6c5..c2dcf751181 100644
--- a/test/unit-tests/utils/location/map-test.ts
+++ b/test/unit-tests/utils/location/map-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/location/parseGeoUri-test.ts b/test/unit-tests/utils/location/parseGeoUri-test.ts
index 565133b775b..608ed52ba06 100644
--- a/test/unit-tests/utils/location/parseGeoUri-test.ts
+++ b/test/unit-tests/utils/location/parseGeoUri-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/location/positionFailureMessage-test.ts b/test/unit-tests/utils/location/positionFailureMessage-test.ts
index 3936d9cea1b..f3eeacb83e9 100644
--- a/test/unit-tests/utils/location/positionFailureMessage-test.ts
+++ b/test/unit-tests/utils/location/positionFailureMessage-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/login-test.ts b/test/unit-tests/utils/login-test.ts
index f09152f4e21..b1f488c29f5 100644
--- a/test/unit-tests/utils/login-test.ts
+++ b/test/unit-tests/utils/login-test.ts
@@ -1,7 +1,7 @@
 /*
 Copyright 2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/maps-test.ts b/test/unit-tests/utils/maps-test.ts
index 426381bd3e8..619766e679a 100644
--- a/test/unit-tests/utils/maps-test.ts
+++ b/test/unit-tests/utils/maps-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/media/requestMediaPermissions-test.tsx b/test/unit-tests/utils/media/requestMediaPermissions-test.tsx
index 0683ad1b67d..a4cc3b7685b 100644
--- a/test/unit-tests/utils/media/requestMediaPermissions-test.tsx
+++ b/test/unit-tests/utils/media/requestMediaPermissions-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/membership-test.ts b/test/unit-tests/utils/membership-test.ts
index 92daf230ffa..c63dbe90744 100644
--- a/test/unit-tests/utils/membership-test.ts
+++ b/test/unit-tests/utils/membership-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/notifications-test.ts b/test/unit-tests/utils/notifications-test.ts
index 6cf6e3496b7..eeec145a367 100644
--- a/test/unit-tests/utils/notifications-test.ts
+++ b/test/unit-tests/utils/notifications-test.ts
@@ -2,11 +2,18 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
-import { MatrixEvent, NotificationCountType, Room, MatrixClient, ReceiptType } from "matrix-js-sdk/src/matrix";
+import {
+    MatrixEvent,
+    NotificationCountType,
+    Room,
+    MatrixClient,
+    ReceiptType,
+    AccountDataEvents,
+} from "matrix-js-sdk/src/matrix";
 import { Mocked, mocked } from "jest-mock";
 
 import {
@@ -32,7 +39,7 @@ jest.mock("../../../src/settings/SettingsStore");
 describe("notifications", () => {
     let accountDataStore: Record<string, MatrixEvent> = {};
     let mockClient: Mocked<MatrixClient>;
-    let accountDataEventKey: string;
+    let accountDataEventKey: keyof AccountDataEvents;
 
     beforeEach(() => {
         jest.clearAllMocks();
diff --git a/test/unit-tests/utils/numbers-test.ts b/test/unit-tests/utils/numbers-test.ts
index 4b29cc66b0e..1de68ce4991 100644
--- a/test/unit-tests/utils/numbers-test.ts
+++ b/test/unit-tests/utils/numbers-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/objects-test.ts b/test/unit-tests/utils/objects-test.ts
index ddae6d2365f..48d5ca84fe9 100644
--- a/test/unit-tests/utils/objects-test.ts
+++ b/test/unit-tests/utils/objects-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/oidc/TokenRefresher-test.ts b/test/unit-tests/utils/oidc/TokenRefresher-test.ts
index d318f45e503..643f61faacb 100644
--- a/test/unit-tests/utils/oidc/TokenRefresher-test.ts
+++ b/test/unit-tests/utils/oidc/TokenRefresher-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/oidc/authorize-test.ts b/test/unit-tests/utils/oidc/authorize-test.ts
index 30faa269c56..72c42fab370 100644
--- a/test/unit-tests/utils/oidc/authorize-test.ts
+++ b/test/unit-tests/utils/oidc/authorize-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/oidc/persistOidcSettings-test.ts b/test/unit-tests/utils/oidc/persistOidcSettings-test.ts
index e3971f24d65..4ffbfd43b23 100644
--- a/test/unit-tests/utils/oidc/persistOidcSettings-test.ts
+++ b/test/unit-tests/utils/oidc/persistOidcSettings-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/oidc/registerClient-test.ts b/test/unit-tests/utils/oidc/registerClient-test.ts
index a90997598be..0c6a41bc36d 100644
--- a/test/unit-tests/utils/oidc/registerClient-test.ts
+++ b/test/unit-tests/utils/oidc/registerClient-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/permalinks/MatrixSchemePermalinkConstructor-test.ts b/test/unit-tests/utils/permalinks/MatrixSchemePermalinkConstructor-test.ts
index bdebde4a2ef..514ff7bdb7c 100644
--- a/test/unit-tests/utils/permalinks/MatrixSchemePermalinkConstructor-test.ts
+++ b/test/unit-tests/utils/permalinks/MatrixSchemePermalinkConstructor-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/permalinks/MatrixToPermalinkConstructor-test.ts b/test/unit-tests/utils/permalinks/MatrixToPermalinkConstructor-test.ts
index b03e242ca59..92f005d0d96 100644
--- a/test/unit-tests/utils/permalinks/MatrixToPermalinkConstructor-test.ts
+++ b/test/unit-tests/utils/permalinks/MatrixToPermalinkConstructor-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/permalinks/Permalinks-test.ts b/test/unit-tests/utils/permalinks/Permalinks-test.ts
index 6e1b4dcdd0d..c961ff26462 100644
--- a/test/unit-tests/utils/permalinks/Permalinks-test.ts
+++ b/test/unit-tests/utils/permalinks/Permalinks-test.ts
@@ -3,7 +3,7 @@ Copyright 2024 New Vector Ltd.
 Copyright 2019-2022 The Matrix.org Foundation C.I.C.
 Copyright 2018 New Vector Ltd
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/pillify-test.tsx b/test/unit-tests/utils/pillify-test.tsx
index 3fc25a21922..4cca311c576 100644
--- a/test/unit-tests/utils/pillify-test.tsx
+++ b/test/unit-tests/utils/pillify-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/promise-test.ts b/test/unit-tests/utils/promise-test.ts
index 343a46d7edd..5761c8f881f 100644
--- a/test/unit-tests/utils/promise-test.ts
+++ b/test/unit-tests/utils/promise-test.ts
@@ -1,9 +1,8 @@
 /*
  * Copyright 2024 New Vector Ltd.
  *
- * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
  * Please see LICENSE files in the repository root for full details.
- *
  */
 
 import { batch } from "../../../src/utils/promise.ts";
diff --git a/test/unit-tests/utils/room/canInviteTo-test.ts b/test/unit-tests/utils/room/canInviteTo-test.ts
index f22a08fc68c..2340c667ddd 100644
--- a/test/unit-tests/utils/room/canInviteTo-test.ts
+++ b/test/unit-tests/utils/room/canInviteTo-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/room/getJoinedNonFunctionalMembers-test.ts b/test/unit-tests/utils/room/getJoinedNonFunctionalMembers-test.ts
index 19cac7b6da4..bd31269d332 100644
--- a/test/unit-tests/utils/room/getJoinedNonFunctionalMembers-test.ts
+++ b/test/unit-tests/utils/room/getJoinedNonFunctionalMembers-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/room/getRoomFunctionalMembers-test.ts b/test/unit-tests/utils/room/getRoomFunctionalMembers-test.ts
index 8d8ac50f834..4f910f9283d 100644
--- a/test/unit-tests/utils/room/getRoomFunctionalMembers-test.ts
+++ b/test/unit-tests/utils/room/getRoomFunctionalMembers-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/room/inviteToRoom-test.ts b/test/unit-tests/utils/room/inviteToRoom-test.ts
index b419ac399d9..bee74e2d1b8 100644
--- a/test/unit-tests/utils/room/inviteToRoom-test.ts
+++ b/test/unit-tests/utils/room/inviteToRoom-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/room/shouldEncryptRoomWithSingle3rdPartyInvite-test.ts b/test/unit-tests/utils/room/shouldEncryptRoomWithSingle3rdPartyInvite-test.ts
index d879c10e710..290dc8cf6c7 100644
--- a/test/unit-tests/utils/room/shouldEncryptRoomWithSingle3rdPartyInvite-test.ts
+++ b/test/unit-tests/utils/room/shouldEncryptRoomWithSingle3rdPartyInvite-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/room/tagRoom-test.ts b/test/unit-tests/utils/room/tagRoom-test.ts
index 1bfb7225090..41dc9ef1152 100644
--- a/test/unit-tests/utils/room/tagRoom-test.ts
+++ b/test/unit-tests/utils/room/tagRoom-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/rooms-test.ts b/test/unit-tests/utils/rooms-test.ts
index c3f9245f7a8..7f90b32fae7 100644
--- a/test/unit-tests/utils/rooms-test.ts
+++ b/test/unit-tests/utils/rooms-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/sets-test.ts b/test/unit-tests/utils/sets-test.ts
index 1fecccd4fbc..20889aa611a 100644
--- a/test/unit-tests/utils/sets-test.ts
+++ b/test/unit-tests/utils/sets-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/stringOrderField-test.ts b/test/unit-tests/utils/stringOrderField-test.ts
index 84f29aed6a8..e5c5c5f0507 100644
--- a/test/unit-tests/utils/stringOrderField-test.ts
+++ b/test/unit-tests/utils/stringOrderField-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2021 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/threepids-test.ts b/test/unit-tests/utils/threepids-test.ts
index 3270431cbd5..01b580abb0a 100644
--- a/test/unit-tests/utils/threepids-test.ts
+++ b/test/unit-tests/utils/threepids-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/tooltipify-test.tsx b/test/unit-tests/utils/tooltipify-test.tsx
index faac68ff9dc..459cf2d2bf3 100644
--- a/test/unit-tests/utils/tooltipify-test.tsx
+++ b/test/unit-tests/utils/tooltipify-test.tsx
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/utils/validate/numberInRange-test.ts b/test/unit-tests/utils/validate/numberInRange-test.ts
index ca52a7c332c..d62045ac68d 100644
--- a/test/unit-tests/utils/validate/numberInRange-test.ts
+++ b/test/unit-tests/utils/validate/numberInRange-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/vector/getconfig-test.ts b/test/unit-tests/vector/getconfig-test.ts
index cba19d5ae62..9a2cfbd3c3f 100644
--- a/test/unit-tests/vector/getconfig-test.ts
+++ b/test/unit-tests/vector/getconfig-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/vector/init-test.ts b/test/unit-tests/vector/init-test.ts
index 65b2ddac1c3..7f7d760360d 100644
--- a/test/unit-tests/vector/init-test.ts
+++ b/test/unit-tests/vector/init-test.ts
@@ -1,7 +1,7 @@
 /*
 Copyright 2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/vector/platform/ElectronPlatform-test.ts b/test/unit-tests/vector/platform/ElectronPlatform-test.ts
index f6c2008de8e..2633d15b145 100644
--- a/test/unit-tests/vector/platform/ElectronPlatform-test.ts
+++ b/test/unit-tests/vector/platform/ElectronPlatform-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/vector/platform/PWAPlatform-test.ts b/test/unit-tests/vector/platform/PWAPlatform-test.ts
index 8e1eb0e9cbf..3ab3e97415d 100644
--- a/test/unit-tests/vector/platform/PWAPlatform-test.ts
+++ b/test/unit-tests/vector/platform/PWAPlatform-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/vector/platform/WebPlatform-test.ts b/test/unit-tests/vector/platform/WebPlatform-test.ts
index 93a6a07eb65..b47f2d55372 100644
--- a/test/unit-tests/vector/platform/WebPlatform-test.ts
+++ b/test/unit-tests/vector/platform/WebPlatform-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/vector/routing-test.ts b/test/unit-tests/vector/routing-test.ts
index 8a1238a14f4..09b2df1d124 100644
--- a/test/unit-tests/vector/routing-test.ts
+++ b/test/unit-tests/vector/routing-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2022 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/vector/url_utils-test.ts b/test/unit-tests/vector/url_utils-test.ts
index f440834c6c6..242ca9ace94 100644
--- a/test/unit-tests/vector/url_utils-test.ts
+++ b/test/unit-tests/vector/url_utils-test.ts
@@ -1,7 +1,7 @@
 /*
 Copyright 2020-2024 New Vector Ltd.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/test/unit-tests/widgets/ManagedHybrid-test.ts b/test/unit-tests/widgets/ManagedHybrid-test.ts
index b07178ce4f5..53a4c302c30 100644
--- a/test/unit-tests/widgets/ManagedHybrid-test.ts
+++ b/test/unit-tests/widgets/ManagedHybrid-test.ts
@@ -2,7 +2,7 @@
 Copyright 2024 New Vector Ltd.
 Copyright 2023 The Matrix.org Foundation C.I.C.
 
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
diff --git a/webpack.config.js b/webpack.config.js
index 91606e34d07..e8413f372c2 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -10,6 +10,7 @@ const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
 const HtmlWebpackInjectPreload = require("@principalstudio/html-webpack-inject-preload");
 const CopyWebpackPlugin = require("copy-webpack-plugin");
 const VersionFilePlugin = require("webpack-version-file-plugin");
+const { RetryChunkLoadPlugin } = require("webpack-retry-chunk-load-plugin");
 
 // Environment variables
 // RIOT_OG_IMAGE_URL: specifies the URL to the image which should be used for the opengraph logo.
@@ -690,6 +691,13 @@ module.exports = (env, argv) => {
                 templateString: "<%= extras.VERSION %>",
                 extras: { VERSION },
             }),
+
+            // Due to issues such as https://github.com/vector-im/element-web/issues/25277 we should retry chunk loading
+            new RetryChunkLoadPlugin({
+                cacheBust: `() => Date.now()`,
+                retryDelay: 500,
+                maxRetries: 3,
+            }),
         ].filter(Boolean),
 
         output: {
diff --git a/yarn.lock b/yarn.lock
index bf2b3480a58..cbe07be2a19 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -259,11 +259,6 @@
   resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz#1aabb72ee72ed35789b4bbcad3ca2862ce614e8c"
   integrity sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==
 
-"@babel/helper-validator-identifier@^7.24.5":
-  version "7.25.7"
-  resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.7.tgz#77b7f60c40b15c97df735b38a66ba1d7c3e93da5"
-  integrity sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg==
-
 "@babel/helper-validator-identifier@^7.24.7", "@babel/helper-validator-identifier@^7.25.7", "@babel/helper-validator-identifier@^7.25.9":
   version "7.25.9"
   resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz#24b64e2c3ec7cd3b3c547729b8d16871f22cbdc7"
@@ -1094,6 +1089,13 @@
   dependencies:
     regenerator-runtime "^0.14.0"
 
+"@babel/runtime@^7.7.2":
+  version "7.25.9"
+  resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.25.9.tgz#65884fd6dc255a775402cc1d9811082918f4bf00"
+  integrity sha512-4zpTHZ9Cm6L9L+uIqghQX8ZXg8HKFcjYO3qHoO8zTmRm6HQUJ8SSJ+KRvbMBZn0EGVlT4DRYeQ/6hjlyXBh+Kg==
+  dependencies:
+    regenerator-runtime "^0.14.0"
+
 "@babel/template@^7.25.7", "@babel/template@^7.3.3":
   version "7.25.7"
   resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.25.7.tgz#27f69ce382855d915b14ab0fe5fb4cbf88fa0769"
@@ -1163,6 +1165,11 @@
     "@babel/helper-string-parser" "^7.25.9"
     "@babel/helper-validator-identifier" "^7.25.9"
 
+"@balena/dockerignore@^1.0.2":
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/@balena/dockerignore/-/dockerignore-1.0.2.tgz#9ffe4726915251e8eb69f44ef3547e0da2c03e0d"
+  integrity sha512-wMue2Sy4GAVTk6Ic4tJVcnfdau+gx2EnG7S+uAEe+TWJFqE4YoWN4/H8MSLj4eYJKxGg26lZwboEniNiNwZQ6Q==
+
 "@bcoe/v8-coverage@^0.2.3":
   version "0.2.3"
   resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
@@ -1184,97 +1191,107 @@
   dependencies:
     "@jridgewell/trace-mapping" "0.3.9"
 
-"@csstools/cascade-layer-name-parser@^2.0.2":
-  version "2.0.2"
-  resolved "https://registry.yarnpkg.com/@csstools/cascade-layer-name-parser/-/cascade-layer-name-parser-2.0.2.tgz#a71bd7ab4325fbbdd41e55645c2c958896b24fb1"
-  integrity sha512-rRWNJ8n16okpQT+8RWEbPfSl8D9WVoDZGBfHkjYnMYWcC20RiMpu/iGeKqUl1hR+SQIKg6p/QJap5rZJaHtVOg==
+"@csstools/cascade-layer-name-parser@^2.0.4":
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/@csstools/cascade-layer-name-parser/-/cascade-layer-name-parser-2.0.4.tgz#64d128529397aa1e1c986f685713363b262b81b1"
+  integrity sha512-7DFHlPuIxviKYZrOiwVU/PiHLm3lLUR23OMuEEtfEOQTOp9hzQ2JjdY6X5H18RVuUPJqSCI+qNnD5iOLMVE0bA==
 
 "@csstools/color-helpers@^5.0.1":
   version "5.0.1"
   resolved "https://registry.yarnpkg.com/@csstools/color-helpers/-/color-helpers-5.0.1.tgz#829f1c76f5800b79c51c709e2f36821b728e0e10"
   integrity sha512-MKtmkA0BX87PKaO1NFRTFH+UnkgnmySQOvNxJubsadusqPEC2aJ9MOQiMceZJJ6oitUl/i0L6u0M1IrmAOmgBA==
 
-"@csstools/css-calc@^2.0.2":
-  version "2.0.2"
-  resolved "https://registry.yarnpkg.com/@csstools/css-calc/-/css-calc-2.0.2.tgz#20f55c1c5857999b9cb0acca38e4eaf1a38b53e4"
-  integrity sha512-N70YZw+R6WDP9EEd5xAT3xd+SgZFZsllXR6kclq6U8e2thlakNpWCKhuOiWfCKU8HpeWOyL+2ArSX8uDszMytA==
+"@csstools/css-calc@^2.1.1":
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/@csstools/css-calc/-/css-calc-2.1.1.tgz#a7dbc66627f5cf458d42aed14bda0d3860562383"
+  integrity sha512-rL7kaUnTkL9K+Cvo2pnCieqNpTKgQzy5f+N+5Iuko9HAoasP+xgprVh7KN/MaJVvVL1l0EzQq2MoqBHKSrDrag==
 
-"@csstools/css-color-parser@^3.0.3":
-  version "3.0.3"
-  resolved "https://registry.yarnpkg.com/@csstools/css-color-parser/-/css-color-parser-3.0.3.tgz#a4ddf82aeafc452443851a3f108ecae52533e25f"
-  integrity sha512-mnOTQ6KbQ6GHfdVHVTNXffroW0r5P5531h73bIyEzWAScGjMPQi+1XYgAydYVaZiKeXlQ4GHG9dnBWq9h7xFIQ==
+"@csstools/css-color-parser@^3.0.7":
+  version "3.0.7"
+  resolved "https://registry.yarnpkg.com/@csstools/css-color-parser/-/css-color-parser-3.0.7.tgz#442d61d58e54ad258d52c309a787fceb33906484"
+  integrity sha512-nkMp2mTICw32uE5NN+EsJ4f5N+IGFeCFu4bGpiKgb2Pq/7J/MpyLBeQ5ry4KKtRFZaYs6sTmcMYrSRIyj5DFKA==
   dependencies:
     "@csstools/color-helpers" "^5.0.1"
-    "@csstools/css-calc" "^2.0.2"
+    "@csstools/css-calc" "^2.1.1"
 
-"@csstools/css-parser-algorithms@^3.0.1", "@csstools/css-parser-algorithms@^3.0.2":
+"@csstools/css-parser-algorithms@^3.0.1":
   version "3.0.2"
   resolved "https://registry.yarnpkg.com/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.2.tgz#be03c710a60b34f95ea62e332c9ca0c2674f6d5f"
   integrity sha512-6tC/MnlEvs5suR4Ahef4YlBccJDHZuxGsAlxXmybWjZ5jPxlzLSMlRZ9mVHSRvlD+CmtE7+hJ+UQbfXrws/rUQ==
 
-"@csstools/css-tokenizer@^3.0.1", "@csstools/css-tokenizer@^3.0.2":
+"@csstools/css-parser-algorithms@^3.0.4":
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.4.tgz#74426e93bd1c4dcab3e441f5cc7ba4fb35d94356"
+  integrity sha512-Up7rBoV77rv29d3uKHUIVubz1BTcgyUK72IvCQAbfbMv584xHcGKCKbWh7i8hPrRJ7qU4Y8IO3IY9m+iTB7P3A==
+
+"@csstools/css-tokenizer@^3.0.1":
   version "3.0.2"
   resolved "https://registry.yarnpkg.com/@csstools/css-tokenizer/-/css-tokenizer-3.0.2.tgz#1c1d7298f6a7b3db94afe53d949b9a7d6a8ebc57"
   integrity sha512-IuTRcD53WHsXPCZ6W7ubfGqReTJ9Ra0yRRFmXYP/Re8hFYYfoIYIK4080X5luslVLWimhIeFq0hj09urVMQzTw==
 
+"@csstools/css-tokenizer@^3.0.3":
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/@csstools/css-tokenizer/-/css-tokenizer-3.0.3.tgz#a5502c8539265fecbd873c1e395a890339f119c2"
+  integrity sha512-UJnjoFsmxfKUdNYdWgOB0mWUypuLvAfQPH1+pyvRJs6euowbFkFC6P13w1l8mJyi3vxYMxc9kld5jZEGRQs6bw==
+
 "@csstools/media-query-list-parser@^3.0.1":
   version "3.0.1"
   resolved "https://registry.yarnpkg.com/@csstools/media-query-list-parser/-/media-query-list-parser-3.0.1.tgz#9474e08e6d7767cf68c56bf1581b59d203360cb0"
   integrity sha512-HNo8gGD02kHmcbX6PvCoUuOQvn4szyB9ca63vZHKX5A81QytgDG4oxG4IaEfHTlEZSZ6MjPEMWIVU+zF2PZcgw==
 
-"@csstools/media-query-list-parser@^4.0.0":
-  version "4.0.0"
-  resolved "https://registry.yarnpkg.com/@csstools/media-query-list-parser/-/media-query-list-parser-4.0.0.tgz#d32a27f1d95f77c2a62c0f21f12a9e84b944bf5f"
-  integrity sha512-nUfbCGeqCju55Po8ujRNQ8DjuKYth5UcsDj5HsVzSfqnaFdpOwYCUAhRJ2grfwrXhb9+KuRXHQ6JHzaI0Qhu8Q==
+"@csstools/media-query-list-parser@^4.0.2":
+  version "4.0.2"
+  resolved "https://registry.yarnpkg.com/@csstools/media-query-list-parser/-/media-query-list-parser-4.0.2.tgz#e80e17eba1693fceafb8d6f2cfc68c0e7a9ab78a"
+  integrity sha512-EUos465uvVvMJehckATTlNqGj4UJWkTmdWuDMjqvSUkjGpmOyFZBVwb4knxCm/k2GMTXY+c/5RkdndzFYWeX5A==
 
-"@csstools/postcss-cascade-layers@^5.0.0":
-  version "5.0.0"
-  resolved "https://registry.yarnpkg.com/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-5.0.0.tgz#ad9985c2d273554552a546f6b1584d03d8886a8d"
-  integrity sha512-h+VunB3KXaoWTWEPBcdVk8Kz1eZ/CtDD+HXgKw5JLdbsViLEQdKUtFYH73VIQigdodng8s5DCrrwNQY7pnuWBA==
+"@csstools/postcss-cascade-layers@^5.0.1":
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-5.0.1.tgz#9640313e64b5e39133de7e38a5aa7f40dc259597"
+  integrity sha512-XOfhI7GShVcKiKwmPAnWSqd2tBR0uxt+runAxttbSp/LY2U16yAVPmAf7e9q4JJ0d+xMNmpwNDLBXnmRCl3HMQ==
   dependencies:
-    "@csstools/selector-specificity" "^4.0.0"
-    postcss-selector-parser "^6.1.0"
+    "@csstools/selector-specificity" "^5.0.0"
+    postcss-selector-parser "^7.0.0"
 
-"@csstools/postcss-color-function@^4.0.3":
-  version "4.0.3"
-  resolved "https://registry.yarnpkg.com/@csstools/postcss-color-function/-/postcss-color-function-4.0.3.tgz#eb66831b62f03bfdc0041924af709ab4853949b5"
-  integrity sha512-dziWTvbyBsXze7Li+BemXyYX9yCf8udlGKB78evZismrBf7SNN6K5S0qE4sRQELKEkttugcGz0hwqyXilEhoUA==
+"@csstools/postcss-color-function@^4.0.7":
+  version "4.0.7"
+  resolved "https://registry.yarnpkg.com/@csstools/postcss-color-function/-/postcss-color-function-4.0.7.tgz#d31d2044d8a4f8b3154ac54ac77014879eae9f56"
+  integrity sha512-aDHYmhNIHR6iLw4ElWhf+tRqqaXwKnMl0YsQ/X105Zc4dQwe6yJpMrTN6BwOoESrkDjOYMOfORviSSLeDTJkdQ==
   dependencies:
-    "@csstools/css-color-parser" "^3.0.3"
-    "@csstools/css-parser-algorithms" "^3.0.2"
-    "@csstools/css-tokenizer" "^3.0.2"
+    "@csstools/css-color-parser" "^3.0.7"
+    "@csstools/css-parser-algorithms" "^3.0.4"
+    "@csstools/css-tokenizer" "^3.0.3"
     "@csstools/postcss-progressive-custom-properties" "^4.0.0"
     "@csstools/utilities" "^2.0.0"
 
-"@csstools/postcss-color-mix-function@^3.0.3":
-  version "3.0.3"
-  resolved "https://registry.yarnpkg.com/@csstools/postcss-color-mix-function/-/postcss-color-mix-function-3.0.3.tgz#f447cba483f2b015785ab120db2fdbe27e41537b"
-  integrity sha512-L7v0pQlLC3VejShxn5bjrdo3GhhHExSVGB8CgZqIcED/W/eK9pKGxubyGivNcJQYl+iznBtTU3mFPMmOrLccBQ==
+"@csstools/postcss-color-mix-function@^3.0.7":
+  version "3.0.7"
+  resolved "https://registry.yarnpkg.com/@csstools/postcss-color-mix-function/-/postcss-color-mix-function-3.0.7.tgz#39735bbc84dc173061e4c2842ec656bb9bc6ed2e"
+  integrity sha512-e68Nev4CxZYCLcrfWhHH4u/N1YocOfTmw67/kVX5Rb7rnguqqLyxPjhHWjSBX8o4bmyuukmNf3wrUSU3//kT7g==
   dependencies:
-    "@csstools/css-color-parser" "^3.0.3"
-    "@csstools/css-parser-algorithms" "^3.0.2"
-    "@csstools/css-tokenizer" "^3.0.2"
+    "@csstools/css-color-parser" "^3.0.7"
+    "@csstools/css-parser-algorithms" "^3.0.4"
+    "@csstools/css-tokenizer" "^3.0.3"
     "@csstools/postcss-progressive-custom-properties" "^4.0.0"
     "@csstools/utilities" "^2.0.0"
 
-"@csstools/postcss-content-alt-text@^2.0.2":
-  version "2.0.2"
-  resolved "https://registry.yarnpkg.com/@csstools/postcss-content-alt-text/-/postcss-content-alt-text-2.0.2.tgz#96e60e9e247a6caf66d276dcfdd925f02c459597"
-  integrity sha512-GzMdDJrNPAOq4XxGac5xv5Ae2pB3JjvYWIJhJPcE6g87Q38gXG1Daaqq55QUU8DnC+iVm8lrO/JGvSC2T4YBOA==
+"@csstools/postcss-content-alt-text@^2.0.4":
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/@csstools/postcss-content-alt-text/-/postcss-content-alt-text-2.0.4.tgz#76f4687fb15ed45bc1139bb71e5775779762897a"
+  integrity sha512-YItlZUOuZJCBlRaCf8Aucc1lgN41qYGALMly0qQllrxYJhiyzlI6RxOTMUvtWk+KhS8GphMDsDhKQ7KTPfEMSw==
   dependencies:
-    "@csstools/css-parser-algorithms" "^3.0.2"
-    "@csstools/css-tokenizer" "^3.0.2"
+    "@csstools/css-parser-algorithms" "^3.0.4"
+    "@csstools/css-tokenizer" "^3.0.3"
     "@csstools/postcss-progressive-custom-properties" "^4.0.0"
     "@csstools/utilities" "^2.0.0"
 
-"@csstools/postcss-exponential-functions@^2.0.2":
-  version "2.0.2"
-  resolved "https://registry.yarnpkg.com/@csstools/postcss-exponential-functions/-/postcss-exponential-functions-2.0.2.tgz#3222171d194b73fa67bb8ca59322c6ad8a38e870"
-  integrity sha512-gSGeXEKse3U3lDzSXh9XE1DgdicMWolo+eyXN8nH96Vr5mWPd6jUwk6W+x8yRNwM5dDkoAE/HkYK6/WzSo9Jsw==
+"@csstools/postcss-exponential-functions@^2.0.6":
+  version "2.0.6"
+  resolved "https://registry.yarnpkg.com/@csstools/postcss-exponential-functions/-/postcss-exponential-functions-2.0.6.tgz#dcee86d22102576b13d8bea059125fbcf98e83cc"
+  integrity sha512-IgJA5DQsQLu/upA3HcdvC6xEMR051ufebBTIXZ5E9/9iiaA7juXWz1ceYj814lnDYP/7eWjZnw0grRJlX4eI6g==
   dependencies:
-    "@csstools/css-calc" "^2.0.2"
-    "@csstools/css-parser-algorithms" "^3.0.2"
-    "@csstools/css-tokenizer" "^3.0.2"
+    "@csstools/css-calc" "^2.1.1"
+    "@csstools/css-parser-algorithms" "^3.0.4"
+    "@csstools/css-tokenizer" "^3.0.3"
 
 "@csstools/postcss-font-format-keywords@^4.0.0":
   version "4.0.0"
@@ -1284,34 +1301,34 @@
     "@csstools/utilities" "^2.0.0"
     postcss-value-parser "^4.2.0"
 
-"@csstools/postcss-gamut-mapping@^2.0.3":
-  version "2.0.3"
-  resolved "https://registry.yarnpkg.com/@csstools/postcss-gamut-mapping/-/postcss-gamut-mapping-2.0.3.tgz#0af3e2a3643d21817bbcbeb85b3ad98230f3cf88"
-  integrity sha512-1mbYE41F3fluEdjExw70b339NVU62O6sz43mya5O+LultfZQdmY68qRsWT+rw85Imya9aeLCDgBHaxwgXf1Z/g==
+"@csstools/postcss-gamut-mapping@^2.0.7":
+  version "2.0.7"
+  resolved "https://registry.yarnpkg.com/@csstools/postcss-gamut-mapping/-/postcss-gamut-mapping-2.0.7.tgz#8aaa4b6ffb6e2187379a83d253607f988533be25"
+  integrity sha512-gzFEZPoOkY0HqGdyeBXR3JP218Owr683u7KOZazTK7tQZBE8s2yhg06W1tshOqk7R7SWvw9gkw2TQogKpIW8Xw==
   dependencies:
-    "@csstools/css-color-parser" "^3.0.3"
-    "@csstools/css-parser-algorithms" "^3.0.2"
-    "@csstools/css-tokenizer" "^3.0.2"
+    "@csstools/css-color-parser" "^3.0.7"
+    "@csstools/css-parser-algorithms" "^3.0.4"
+    "@csstools/css-tokenizer" "^3.0.3"
 
-"@csstools/postcss-gradients-interpolation-method@^5.0.3":
-  version "5.0.3"
-  resolved "https://registry.yarnpkg.com/@csstools/postcss-gradients-interpolation-method/-/postcss-gradients-interpolation-method-5.0.3.tgz#8813292f54b919764d7622331f4781912c3118c9"
-  integrity sha512-TW+utpEOOn2HLlRZTEVNS8XBlG5bOcSNBanIKjPWnkmdgkFjcj1eIaEtWezpGX2hKJpkiwZeIEyP/UItWk6c3g==
+"@csstools/postcss-gradients-interpolation-method@^5.0.7":
+  version "5.0.7"
+  resolved "https://registry.yarnpkg.com/@csstools/postcss-gradients-interpolation-method/-/postcss-gradients-interpolation-method-5.0.7.tgz#57e19d25e98aa028b98e22ef392ea24c3e61c568"
+  integrity sha512-WgEyBeg6glUeTdS2XT7qeTFBthTJuXlS9GFro/DVomj7W7WMTamAwpoP4oQCq/0Ki2gvfRYFi/uZtmRE14/DFA==
   dependencies:
-    "@csstools/css-color-parser" "^3.0.3"
-    "@csstools/css-parser-algorithms" "^3.0.2"
-    "@csstools/css-tokenizer" "^3.0.2"
+    "@csstools/css-color-parser" "^3.0.7"
+    "@csstools/css-parser-algorithms" "^3.0.4"
+    "@csstools/css-tokenizer" "^3.0.3"
     "@csstools/postcss-progressive-custom-properties" "^4.0.0"
     "@csstools/utilities" "^2.0.0"
 
-"@csstools/postcss-hwb-function@^4.0.3":
-  version "4.0.3"
-  resolved "https://registry.yarnpkg.com/@csstools/postcss-hwb-function/-/postcss-hwb-function-4.0.3.tgz#3714ef7c3d76a64294d50722ff8a7e4257b04388"
-  integrity sha512-HBeApQzk6UlqAAWbuXSiWmF0Xtc/hfMTESSbkRUpolXshuPkUaBWXflfQuoo6exv3MvID6iTmv11GZT1ZfADDQ==
+"@csstools/postcss-hwb-function@^4.0.7":
+  version "4.0.7"
+  resolved "https://registry.yarnpkg.com/@csstools/postcss-hwb-function/-/postcss-hwb-function-4.0.7.tgz#d09528098c4b99c49c76de686a4ae35585acc691"
+  integrity sha512-LKYqjO+wGwDCfNIEllessCBWfR4MS/sS1WXO+j00KKyOjm7jDW2L6jzUmqASEiv/kkJO39GcoIOvTTfB3yeBUA==
   dependencies:
-    "@csstools/css-color-parser" "^3.0.3"
-    "@csstools/css-parser-algorithms" "^3.0.2"
-    "@csstools/css-tokenizer" "^3.0.2"
+    "@csstools/css-color-parser" "^3.0.7"
+    "@csstools/css-parser-algorithms" "^3.0.4"
+    "@csstools/css-tokenizer" "^3.0.3"
     "@csstools/postcss-progressive-custom-properties" "^4.0.0"
     "@csstools/utilities" "^2.0.0"
 
@@ -1329,21 +1346,21 @@
   resolved "https://registry.yarnpkg.com/@csstools/postcss-initial/-/postcss-initial-2.0.0.tgz#a86f5fc59ab9f16f1422dade4c58bd941af5df22"
   integrity sha512-dv2lNUKR+JV+OOhZm9paWzYBXOCi+rJPqJ2cJuhh9xd8USVrd0cBEPczla81HNOyThMQWeCcdln3gZkQV2kYxA==
 
-"@csstools/postcss-is-pseudo-class@^5.0.0":
-  version "5.0.0"
-  resolved "https://registry.yarnpkg.com/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-5.0.0.tgz#61a4c74e55eec63c06349cfe8d6f2bab82b6ef69"
-  integrity sha512-E/CjrT03BL06WmrjupnrT0VUBTvxJdoW1hRVeXFa9qatWtvcLLw0j8hP372G4A9PpSGEMXi3/AoHzPf7DNryCQ==
+"@csstools/postcss-is-pseudo-class@^5.0.1":
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-5.0.1.tgz#12041448fedf01090dd4626022c28b7f7623f58e"
+  integrity sha512-JLp3POui4S1auhDR0n8wHd/zTOWmMsmK3nQd3hhL6FhWPaox5W7j1se6zXOG/aP07wV2ww0lxbKYGwbBszOtfQ==
   dependencies:
-    "@csstools/selector-specificity" "^4.0.0"
-    postcss-selector-parser "^6.1.0"
+    "@csstools/selector-specificity" "^5.0.0"
+    postcss-selector-parser "^7.0.0"
 
-"@csstools/postcss-light-dark-function@^2.0.5":
-  version "2.0.5"
-  resolved "https://registry.yarnpkg.com/@csstools/postcss-light-dark-function/-/postcss-light-dark-function-2.0.5.tgz#81cf05c760e011c929ce8093b8103923962b4198"
-  integrity sha512-mSqqxuwlBg10YyErq2YYB71KtvWDueBYE9WAnC6B7GHU+z0ECcGf+sR9zxpvePGzesuBNDB+cp15cW2CvOyszA==
+"@csstools/postcss-light-dark-function@^2.0.7":
+  version "2.0.7"
+  resolved "https://registry.yarnpkg.com/@csstools/postcss-light-dark-function/-/postcss-light-dark-function-2.0.7.tgz#807c170cd28eebb0c00e64dfc6ab0bf418f19209"
+  integrity sha512-ZZ0rwlanYKOHekyIPaU+sVm3BEHCe+Ha0/px+bmHe62n0Uc1lL34vbwrLYn6ote8PHlsqzKeTQdIejQCJ05tfw==
   dependencies:
-    "@csstools/css-parser-algorithms" "^3.0.2"
-    "@csstools/css-tokenizer" "^3.0.2"
+    "@csstools/css-parser-algorithms" "^3.0.4"
+    "@csstools/css-tokenizer" "^3.0.3"
     "@csstools/postcss-progressive-custom-properties" "^4.0.0"
     "@csstools/utilities" "^2.0.0"
 
@@ -1369,32 +1386,32 @@
   dependencies:
     postcss-value-parser "^4.2.0"
 
-"@csstools/postcss-logical-viewport-units@^3.0.2":
-  version "3.0.2"
-  resolved "https://registry.yarnpkg.com/@csstools/postcss-logical-viewport-units/-/postcss-logical-viewport-units-3.0.2.tgz#877b4e9ab47f3176b4d205b265952cca626ae8f1"
-  integrity sha512-oog7VobKvrS34oyUKslI6wCphtJxx0ldiA8RToPQ0HXPWNiXXSM7IbgwOTImJKTIUjo3eL7o5uuPxeu5MsnkvA==
+"@csstools/postcss-logical-viewport-units@^3.0.3":
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/@csstools/postcss-logical-viewport-units/-/postcss-logical-viewport-units-3.0.3.tgz#f6cc63520ca2a6eb76b9cd946070c38dda66d733"
+  integrity sha512-OC1IlG/yoGJdi0Y+7duz/kU/beCwO+Gua01sD6GtOtLi7ByQUpcIqs7UE/xuRPay4cHgOMatWdnDdsIDjnWpPw==
   dependencies:
-    "@csstools/css-tokenizer" "^3.0.2"
+    "@csstools/css-tokenizer" "^3.0.3"
     "@csstools/utilities" "^2.0.0"
 
-"@csstools/postcss-media-minmax@^2.0.2":
-  version "2.0.2"
-  resolved "https://registry.yarnpkg.com/@csstools/postcss-media-minmax/-/postcss-media-minmax-2.0.2.tgz#f917dfadde00b9429600c477e8b79e9043cde750"
-  integrity sha512-zodxyIwRNuro/SIjN+zrYeZCQJvMd1obPtsvmNxLRvk3FOM3KwuuX8GEev9if19OGlNVvJZIe9wH77c+jIbXzA==
+"@csstools/postcss-media-minmax@^2.0.6":
+  version "2.0.6"
+  resolved "https://registry.yarnpkg.com/@csstools/postcss-media-minmax/-/postcss-media-minmax-2.0.6.tgz#427921c0f08033203810af16dfed0baedc538eab"
+  integrity sha512-J1+4Fr2W3pLZsfxkFazK+9kr96LhEYqoeBszLmFjb6AjYs+g9oDAw3J5oQignLKk3rC9XHW+ebPTZ9FaW5u5pg==
   dependencies:
-    "@csstools/css-calc" "^2.0.2"
-    "@csstools/css-parser-algorithms" "^3.0.2"
-    "@csstools/css-tokenizer" "^3.0.2"
-    "@csstools/media-query-list-parser" "^4.0.0"
+    "@csstools/css-calc" "^2.1.1"
+    "@csstools/css-parser-algorithms" "^3.0.4"
+    "@csstools/css-tokenizer" "^3.0.3"
+    "@csstools/media-query-list-parser" "^4.0.2"
 
-"@csstools/postcss-media-queries-aspect-ratio-number-values@^3.0.2":
-  version "3.0.2"
-  resolved "https://registry.yarnpkg.com/@csstools/postcss-media-queries-aspect-ratio-number-values/-/postcss-media-queries-aspect-ratio-number-values-3.0.2.tgz#0bd50e483a99a6ebfe40afacfcb7ca11a86e11be"
-  integrity sha512-9bEvSC8hIkdqHwehYIADcwC7/TvuJeb1hAw0STI7BMRVE57nFxHyXY+WzfLPXtmhpdFqGcKJIyQkDcenQI3Sow==
+"@csstools/postcss-media-queries-aspect-ratio-number-values@^3.0.4":
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/@csstools/postcss-media-queries-aspect-ratio-number-values/-/postcss-media-queries-aspect-ratio-number-values-3.0.4.tgz#d71102172c74baf3f892fac88cf1ea46a961600d"
+  integrity sha512-AnGjVslHMm5xw9keusQYvjVWvuS7KWK+OJagaG0+m9QnIjZsrysD2kJP/tr/UJIyYtMCtu8OkUd+Rajb4DqtIQ==
   dependencies:
-    "@csstools/css-parser-algorithms" "^3.0.2"
-    "@csstools/css-tokenizer" "^3.0.2"
-    "@csstools/media-query-list-parser" "^4.0.0"
+    "@csstools/css-parser-algorithms" "^3.0.4"
+    "@csstools/css-tokenizer" "^3.0.3"
+    "@csstools/media-query-list-parser" "^4.0.2"
 
 "@csstools/postcss-nested-calc@^4.0.0":
   version "4.0.0"
@@ -1411,14 +1428,14 @@
   dependencies:
     postcss-value-parser "^4.2.0"
 
-"@csstools/postcss-oklab-function@^4.0.3":
-  version "4.0.3"
-  resolved "https://registry.yarnpkg.com/@csstools/postcss-oklab-function/-/postcss-oklab-function-4.0.3.tgz#fe0d98c9a4f6cc34189da70561bc1bdc67d76389"
-  integrity sha512-BrhnL98OSpWt5EOMk5Hm+kL0kjA8BhBc9DGG0jYgww1GhWItn+L/McQ4WgHE2cm9+jSUE2OMy/31WvSRKhWpnQ==
+"@csstools/postcss-oklab-function@^4.0.7":
+  version "4.0.7"
+  resolved "https://registry.yarnpkg.com/@csstools/postcss-oklab-function/-/postcss-oklab-function-4.0.7.tgz#33b3322dfb27b0b5eb83a7ad36e67f08bc4e66cd"
+  integrity sha512-I6WFQIbEKG2IO3vhaMGZDkucbCaUSXMxvHNzDdnfsTCF5tc0UlV3Oe2AhamatQoKFjBi75dSEMrgWq3+RegsOQ==
   dependencies:
-    "@csstools/css-color-parser" "^3.0.3"
-    "@csstools/css-parser-algorithms" "^3.0.2"
-    "@csstools/css-tokenizer" "^3.0.2"
+    "@csstools/css-color-parser" "^3.0.7"
+    "@csstools/css-parser-algorithms" "^3.0.4"
+    "@csstools/css-tokenizer" "^3.0.3"
     "@csstools/postcss-progressive-custom-properties" "^4.0.0"
     "@csstools/utilities" "^2.0.0"
 
@@ -1429,32 +1446,50 @@
   dependencies:
     postcss-value-parser "^4.2.0"
 
-"@csstools/postcss-relative-color-syntax@^3.0.3":
-  version "3.0.3"
-  resolved "https://registry.yarnpkg.com/@csstools/postcss-relative-color-syntax/-/postcss-relative-color-syntax-3.0.3.tgz#4d23238326e206da1e4f61a16b4bee695d166bd2"
-  integrity sha512-1VYBTdGiFSOFrlczaYcUNybCU3XZRL9DDY3ooYRkvweWJZas8dQVHi6vy9SUmxnk0vfGbMbrISXLOIHw4LjKDg==
+"@csstools/postcss-random-function@^1.0.2":
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/@csstools/postcss-random-function/-/postcss-random-function-1.0.2.tgz#699702820f19bb6b9632966ff44d8957db6889d2"
+  integrity sha512-vBCT6JvgdEkvRc91NFoNrLjgGtkLWt47GKT6E2UDn3nd8ZkMBiziQ1Md1OiKoSsgzxsSnGKG3RVdhlbdZEkHjA==
+  dependencies:
+    "@csstools/css-calc" "^2.1.1"
+    "@csstools/css-parser-algorithms" "^3.0.4"
+    "@csstools/css-tokenizer" "^3.0.3"
+
+"@csstools/postcss-relative-color-syntax@^3.0.7":
+  version "3.0.7"
+  resolved "https://registry.yarnpkg.com/@csstools/postcss-relative-color-syntax/-/postcss-relative-color-syntax-3.0.7.tgz#862f8c6a2bbbab1a46aff8265b6a095fd267a3a6"
+  integrity sha512-apbT31vsJVd18MabfPOnE977xgct5B1I+Jpf+Munw3n6kKb1MMuUmGGH+PT9Hm/fFs6fe61Q/EWnkrb4bNoNQw==
   dependencies:
-    "@csstools/css-color-parser" "^3.0.3"
-    "@csstools/css-parser-algorithms" "^3.0.2"
-    "@csstools/css-tokenizer" "^3.0.2"
+    "@csstools/css-color-parser" "^3.0.7"
+    "@csstools/css-parser-algorithms" "^3.0.4"
+    "@csstools/css-tokenizer" "^3.0.3"
     "@csstools/postcss-progressive-custom-properties" "^4.0.0"
     "@csstools/utilities" "^2.0.0"
 
-"@csstools/postcss-scope-pseudo-class@^4.0.0":
-  version "4.0.0"
-  resolved "https://registry.yarnpkg.com/@csstools/postcss-scope-pseudo-class/-/postcss-scope-pseudo-class-4.0.0.tgz#5b975e9e4f96ea8ae6cad4b9ab1be0baa49c61c9"
-  integrity sha512-+ZUOBtVMDcmHZcZqsP/jcNRriEILfWQflTI3tCTA+/RheXAg57VkFGyPDAilpQSqlCpxWLWG8VUFKFtZJPwuOg==
+"@csstools/postcss-scope-pseudo-class@^4.0.1":
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/@csstools/postcss-scope-pseudo-class/-/postcss-scope-pseudo-class-4.0.1.tgz#9fe60e9d6d91d58fb5fc6c768a40f6e47e89a235"
+  integrity sha512-IMi9FwtH6LMNuLea1bjVMQAsUhFxJnyLSgOp/cpv5hrzWmrUYU5fm0EguNDIIOHUqzXode8F/1qkC/tEo/qN8Q==
   dependencies:
-    postcss-selector-parser "^6.1.0"
+    postcss-selector-parser "^7.0.0"
 
-"@csstools/postcss-stepped-value-functions@^4.0.2":
-  version "4.0.2"
-  resolved "https://registry.yarnpkg.com/@csstools/postcss-stepped-value-functions/-/postcss-stepped-value-functions-4.0.2.tgz#9945875adae1dcaa0e1b8279426abed72e88a73b"
-  integrity sha512-AxLKGIV0zYIAkeN02fo4o/vcG39WEZjT9dXs78ajy87dM94OFNIu5huxqBgkFGKLiXhQIKBRxAF/MtJmuIWi8w==
+"@csstools/postcss-sign-functions@^1.1.1":
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/@csstools/postcss-sign-functions/-/postcss-sign-functions-1.1.1.tgz#eb8e4a5ac637982aeb9264cb99f85817612ad3e8"
+  integrity sha512-MslYkZCeMQDxetNkfmmQYgKCy4c+w9pPDfgOBCJOo/RI1RveEUdZQYtOfrC6cIZB7sD7/PHr2VGOcMXlZawrnA==
+  dependencies:
+    "@csstools/css-calc" "^2.1.1"
+    "@csstools/css-parser-algorithms" "^3.0.4"
+    "@csstools/css-tokenizer" "^3.0.3"
+
+"@csstools/postcss-stepped-value-functions@^4.0.6":
+  version "4.0.6"
+  resolved "https://registry.yarnpkg.com/@csstools/postcss-stepped-value-functions/-/postcss-stepped-value-functions-4.0.6.tgz#ee88c6122daf58a1b8641f462e8e33427c60b1f1"
+  integrity sha512-/dwlO9w8vfKgiADxpxUbZOWlL5zKoRIsCymYoh1IPuBsXODKanKnfuZRr32DEqT0//3Av1VjfNZU9yhxtEfIeA==
   dependencies:
-    "@csstools/css-calc" "^2.0.2"
-    "@csstools/css-parser-algorithms" "^3.0.2"
-    "@csstools/css-tokenizer" "^3.0.2"
+    "@csstools/css-calc" "^2.1.1"
+    "@csstools/css-parser-algorithms" "^3.0.4"
+    "@csstools/css-tokenizer" "^3.0.3"
 
 "@csstools/postcss-text-decoration-shorthand@^4.0.1":
   version "4.0.1"
@@ -1464,40 +1499,50 @@
     "@csstools/color-helpers" "^5.0.1"
     postcss-value-parser "^4.2.0"
 
-"@csstools/postcss-trigonometric-functions@^4.0.2":
-  version "4.0.2"
-  resolved "https://registry.yarnpkg.com/@csstools/postcss-trigonometric-functions/-/postcss-trigonometric-functions-4.0.2.tgz#23c35d72fdac211b436fba3460e9c4d7d32373e4"
-  integrity sha512-hQzJkTWNvHKGYa5ySpdex2K/ODX6bI3z8Pmdl3W/opRlaXMA7Xvq7Nagp31BTkr1ngzfnqTY9XNKEI2FqaO3fg==
+"@csstools/postcss-trigonometric-functions@^4.0.6":
+  version "4.0.6"
+  resolved "https://registry.yarnpkg.com/@csstools/postcss-trigonometric-functions/-/postcss-trigonometric-functions-4.0.6.tgz#fc5c5f4c9bd0fd796b58b9a14d5d663be76d19fa"
+  integrity sha512-c4Y1D2Why/PeccaSouXnTt6WcNHJkoJRidV2VW9s5gJ97cNxnLgQ4Qj8qOqkIR9VmTQKJyNcbF4hy79ZQnWD7A==
   dependencies:
-    "@csstools/css-calc" "^2.0.2"
-    "@csstools/css-parser-algorithms" "^3.0.2"
-    "@csstools/css-tokenizer" "^3.0.2"
+    "@csstools/css-calc" "^2.1.1"
+    "@csstools/css-parser-algorithms" "^3.0.4"
+    "@csstools/css-tokenizer" "^3.0.3"
 
 "@csstools/postcss-unset-value@^4.0.0":
   version "4.0.0"
   resolved "https://registry.yarnpkg.com/@csstools/postcss-unset-value/-/postcss-unset-value-4.0.0.tgz#7caa981a34196d06a737754864baf77d64de4bba"
   integrity sha512-cBz3tOCI5Fw6NIFEwU3RiwK6mn3nKegjpJuzCndoGq3BZPkUjnsq7uQmIeMNeMbMk7YD2MfKcgCpZwX5jyXqCA==
 
-"@csstools/selector-resolve-nested@^2.0.0":
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/@csstools/selector-resolve-nested/-/selector-resolve-nested-2.0.0.tgz#826e05f6971c334a12d86e2394129d62d4f19104"
-  integrity sha512-oklSrRvOxNeeOW1yARd4WNCs/D09cQjunGZUgSq6vM8GpzFswN+8rBZyJA29YFZhOTQ6GFzxgLDNtVbt9wPZMA==
+"@csstools/selector-resolve-nested@^3.0.0":
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/@csstools/selector-resolve-nested/-/selector-resolve-nested-3.0.0.tgz#704a9b637975680e025e069a4c58b3beb3e2752a"
+  integrity sha512-ZoK24Yku6VJU1gS79a5PFmC8yn3wIapiKmPgun0hZgEI5AOqgH2kiPRsPz1qkGv4HL+wuDLH83yQyk6inMYrJQ==
 
 "@csstools/selector-specificity@^4.0.0":
   version "4.0.0"
   resolved "https://registry.yarnpkg.com/@csstools/selector-specificity/-/selector-specificity-4.0.0.tgz#7dfccb9df5499e627e7bfdbb4021a06813a45dba"
   integrity sha512-189nelqtPd8++phaHNwYovKZI0FOzH1vQEE3QhHHkNIGrg5fSs9CbYP3RvfEH5geztnIA9Jwq91wyOIwAW5JIQ==
 
+"@csstools/selector-specificity@^5.0.0":
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz#037817b574262134cabd68fc4ec1a454f168407b"
+  integrity sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==
+
 "@csstools/utilities@^2.0.0":
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/@csstools/utilities/-/utilities-2.0.0.tgz#f7ff0fee38c9ffb5646d47b6906e0bc8868bde60"
   integrity sha512-5VdOr0Z71u+Yp3ozOx8T11N703wIFGVRgOWbOZMKgglPJsWA54MRIoMNVMa7shUToIhx5J8vX4sOZgD2XiihiQ==
 
-"@discoveryjs/json-ext@0.5.7", "@discoveryjs/json-ext@^0.5.0":
+"@discoveryjs/json-ext@0.5.7":
   version "0.5.7"
   resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70"
   integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==
 
+"@discoveryjs/json-ext@^0.6.1":
+  version "0.6.3"
+  resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.6.3.tgz#f13c7c205915eb91ae54c557f5e92bddd8be0e83"
+  integrity sha512-4B4OijXeVNOPZlYA2oEwWOTkzyltLao+xbotHQeqN++Rv27Y6s818+n2Qkp8q+Fxhn0t/5lA5X1Mxktud8eayQ==
+
 "@dual-bundle/import-meta-resolve@^4.1.0":
   version "4.1.0"
   resolved "https://registry.yarnpkg.com/@dual-bundle/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz#519c1549b0e147759e7825701ecffd25e5819f7b"
@@ -1542,26 +1587,16 @@
     minimatch "^3.1.2"
     strip-json-comments "^3.1.1"
 
-"@eslint/eslintrc@^3.0.2":
-  version "3.1.0"
-  resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.1.0.tgz#dbd3482bfd91efa663cbe7aa1f506839868207b6"
-  integrity sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==
-  dependencies:
-    ajv "^6.12.4"
-    debug "^4.3.2"
-    espree "^10.0.1"
-    globals "^14.0.0"
-    ignore "^5.2.0"
-    import-fresh "^3.2.1"
-    js-yaml "^4.1.0"
-    minimatch "^3.1.2"
-    strip-json-comments "^3.1.1"
-
 "@eslint/js@8.57.1":
   version "8.57.1"
   resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.1.tgz#de633db3ec2ef6a3c89e2f19038063e8a122e2c2"
   integrity sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==
 
+"@fastify/busboy@^2.0.0":
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/@fastify/busboy/-/busboy-2.1.1.tgz#b9da6a878a371829a0502c9b6c1c143ef6663f4d"
+  integrity sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==
+
 "@floating-ui/core@^1.6.0":
   version "1.6.8"
   resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.6.8.tgz#aa43561be075815879305965020f492cdb43da12"
@@ -1608,37 +1643,37 @@
   resolved "https://registry.yarnpkg.com/@fontsource/inter/-/inter-5.1.0.tgz#ab629b2c662457022d2d6a29854b8dc8ba538c47"
   integrity sha512-zKZR3kf1G0noIes1frLfOHP5EXVVm0M7sV/l9f/AaYf+M/DId35FO4LkigWjqWYjTJZGgplhdv4cB+ssvCqr5A==
 
-"@formatjs/ecma402-abstract@2.3.1":
-  version "2.3.1"
-  resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-2.3.1.tgz#cdeb3ffe1aeea9c4284b85b7e37e8e8615314c39"
-  integrity sha512-Ip9uV+/MpLXWRk03U/GzeJMuPeOXpJBSB5V1tjA6kJhvqssye5J5LoYLc7Z5IAHb7nR62sRoguzrFiVCP/hnzw==
+"@formatjs/ecma402-abstract@2.3.2":
+  version "2.3.2"
+  resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-2.3.2.tgz#0ee291effe7ee2c340742a6c95d92eacb5e6c00a"
+  integrity sha512-6sE5nyvDloULiyOMbOTJEEgWL32w+VHkZQs8S02Lnn8Y/O5aQhjOEXwWzvR7SsBE/exxlSpY2EsWZgqHbtLatg==
   dependencies:
-    "@formatjs/fast-memoize" "2.2.5"
-    "@formatjs/intl-localematcher" "0.5.9"
+    "@formatjs/fast-memoize" "2.2.6"
+    "@formatjs/intl-localematcher" "0.5.10"
     decimal.js "10"
     tslib "2"
 
-"@formatjs/fast-memoize@2.2.5":
-  version "2.2.5"
-  resolved "https://registry.yarnpkg.com/@formatjs/fast-memoize/-/fast-memoize-2.2.5.tgz#54a4a1793d773b72c372d3dcab3595149aee7880"
-  integrity sha512-6PoewUMrrcqxSoBXAOJDiW1m+AmkrAj0RiXnOMD59GRaswjXhm3MDhgepXPBgonc09oSirAJTsAggzAGQf6A6g==
+"@formatjs/fast-memoize@2.2.6":
+  version "2.2.6"
+  resolved "https://registry.yarnpkg.com/@formatjs/fast-memoize/-/fast-memoize-2.2.6.tgz#fac0a84207a1396be1f1aa4ee2805b179e9343d1"
+  integrity sha512-luIXeE2LJbQnnzotY1f2U2m7xuQNj2DA8Vq4ce1BY9ebRZaoPB1+8eZ6nXpLzsxuW5spQxr7LdCg+CApZwkqkw==
   dependencies:
     tslib "2"
 
-"@formatjs/intl-localematcher@0.5.9":
-  version "0.5.9"
-  resolved "https://registry.yarnpkg.com/@formatjs/intl-localematcher/-/intl-localematcher-0.5.9.tgz#43c6ee22be85b83340bcb09bdfed53657a2720db"
-  integrity sha512-8zkGu/sv5euxbjfZ/xmklqLyDGQSxsLqg8XOq88JW3cmJtzhCP8EtSJXlaKZnVO4beEaoiT9wj4eIoCQ9smwxA==
+"@formatjs/intl-localematcher@0.5.10":
+  version "0.5.10"
+  resolved "https://registry.yarnpkg.com/@formatjs/intl-localematcher/-/intl-localematcher-0.5.10.tgz#1e0bd3fc1332c1fe4540cfa28f07e9227b659a58"
+  integrity sha512-af3qATX+m4Rnd9+wHcjJ4w2ijq+rAVP3CCinJQvFv1kgSu1W6jypUmvleJxcewdxmutM8dmIRZFxO/IQBZmP2Q==
   dependencies:
     tslib "2"
 
 "@formatjs/intl-segmenter@^11.5.7":
-  version "11.7.7"
-  resolved "https://registry.yarnpkg.com/@formatjs/intl-segmenter/-/intl-segmenter-11.7.7.tgz#8a5aaa316e11ca2d31b99222e6fcf1ab539b085e"
-  integrity sha512-610J5xz5DxtEpa16zNR89CrvA9qWHxQFkUB3FKiGao0Nwn7i8cl+oyBhuH9SvtXF9j2LUOM9VMdVCMzJkVANNw==
+  version "11.7.8"
+  resolved "https://registry.yarnpkg.com/@formatjs/intl-segmenter/-/intl-segmenter-11.7.8.tgz#85990c7e3961ef686ed78b8cacb216852cadb061"
+  integrity sha512-+nqMCJ6LNLl+qXldE2uthF82O/2Yo6GZlyWbOY25fe3066iaHjmrR4nXd6AKRMCHNeBBx3rANFLm2B5cNTBzTQ==
   dependencies:
-    "@formatjs/ecma402-abstract" "2.3.1"
-    "@formatjs/intl-localematcher" "0.5.9"
+    "@formatjs/ecma402-abstract" "2.3.2"
+    "@formatjs/intl-localematcher" "0.5.10"
     tslib "2"
 
 "@humanwhocodes/config-array@^0.13.0":
@@ -1993,16 +2028,16 @@
   resolved "https://registry.yarnpkg.com/@mapbox/whoots-js/-/whoots-js-3.1.0.tgz#497c67a1cef50d1a2459ba60f315e448d2ad87fe"
   integrity sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q==
 
-"@maplibre/maplibre-gl-style-spec@^20.3.1":
-  version "20.4.0"
-  resolved "https://registry.yarnpkg.com/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-20.4.0.tgz#408339e051fb51e022b40af2235e0beb037937ea"
-  integrity sha512-AzBy3095fTFPjDjmWpR2w6HVRAZJ6hQZUCwk5Plz6EyfnfuQW1odeW5i2Ai47Y6TBA2hQnC+azscjBSALpaWgw==
+"@maplibre/maplibre-gl-style-spec@^22.0.1":
+  version "22.0.1"
+  resolved "https://registry.yarnpkg.com/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-22.0.1.tgz#49210dd9c08853130c453b2acb9439216ab81402"
+  integrity sha512-V7bSw7Ui6+NhpeeuYqGoqamvKuy+3+uCvQ/t4ZJkwN8cx527CAlQQQ2kp+w5R9q+Tw6bUAH+fsq+mPEkicgT8g==
   dependencies:
     "@mapbox/jsonlint-lines-primitives" "~2.0.2"
     "@mapbox/unitbezier" "^0.0.1"
     json-stringify-pretty-compact "^4.0.0"
     minimist "^1.2.8"
-    quickselect "^2.0.0"
+    quickselect "^3.0.0"
     rw "^1.3.3"
     tinyqueue "^3.0.0"
 
@@ -2019,10 +2054,10 @@
     emojibase "^15.3.1"
     emojibase-data "^15.3.1"
 
-"@matrix-org/matrix-sdk-crypto-wasm@^12.0.0":
-  version "12.0.0"
-  resolved "https://registry.yarnpkg.com/@matrix-org/matrix-sdk-crypto-wasm/-/matrix-sdk-crypto-wasm-12.0.0.tgz#e3a5150ccbb21d5e98ee3882e7057b9f17fb962a"
-  integrity sha512-nkkXAxUIk9UTso4TbU6Bgqsv/rJShXQXRx0ti/W+AWXHJ2HoH4sL5LsXkc7a8yYGn8tyXqxGPsYA1UeHqLwm0Q==
+"@matrix-org/matrix-sdk-crypto-wasm@^12.1.0":
+  version "12.1.0"
+  resolved "https://registry.yarnpkg.com/@matrix-org/matrix-sdk-crypto-wasm/-/matrix-sdk-crypto-wasm-12.1.0.tgz#2aef64eab2d30c0a1ace9c0fe876f53aa2949f14"
+  integrity sha512-NhJFu/8FOGjnW7mDssRUzaMSwXrYOcCqgAjZyAw9KQ9unNADKEi7KoIKe7GtrG2PWtm36y2bUf+hB8vhSY6Wdw==
 
 "@matrix-org/olm@3.2.15":
   version "3.2.15"
@@ -2096,12 +2131,17 @@
     tslib "^2.6.2"
     webcrypto-core "^1.8.0"
 
+"@pkgjs/parseargs@^0.11.0":
+  version "0.11.0"
+  resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33"
+  integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==
+
 "@playwright/test@^1.40.1":
-  version "1.49.0"
-  resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.49.0.tgz#74227385b58317ee076b86b56d0e1e1b25cff01e"
-  integrity sha512-DMulbwQURa8rNIQrf94+jPJQ4FmOVdpE5ZppRNvWVjvhC+6sOeo28r8MgIpQRYouXRtt/FCCXU7zn20jnHR4Qw==
+  version "1.49.1"
+  resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.49.1.tgz#55fa360658b3187bfb6371e2f8a64f50ef80c827"
+  integrity sha512-Ky+BVzPz8pL6PQxHqNRW1k3mIyv933LML7HktS8uik0bUXNCdPhoS/kLihiO1tMf/egaJb4IutXd7UywvXEW+g==
   dependencies:
-    playwright "1.49.0"
+    playwright "1.49.1"
 
 "@polka/url@^1.0.0-next.24":
   version "1.0.0-next.28"
@@ -2677,6 +2717,13 @@
     "@svgr/plugin-jsx" "8.1.0"
     "@svgr/plugin-svgo" "8.1.0"
 
+"@testcontainers/postgresql@^10.16.0":
+  version "10.16.0"
+  resolved "https://registry.yarnpkg.com/@testcontainers/postgresql/-/postgresql-10.16.0.tgz#0437a9b426d64ea958e745a0e2ae19462b786f81"
+  integrity sha512-zWFQI+3QxlEELRvVv27i6zlVEPNUz9zKaSh7iWmFlCdfhcyr78daS0FG8FIfdQ79VK7YXA4jv+dTYXa2SwXu/w==
+  dependencies:
+    testcontainers "^10.16.0"
+
 "@testing-library/dom@^10.4.0":
   version "10.4.0"
   resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-10.4.0.tgz#82a9d9462f11d240ecadbf406607c6ceeeff43a8"
@@ -2726,16 +2773,6 @@
   resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad"
   integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==
 
-"@ts-morph/common@~0.12.3":
-  version "0.12.3"
-  resolved "https://registry.yarnpkg.com/@ts-morph/common/-/common-0.12.3.tgz#a96e250217cd30e480ab22ec6a0ebbe65fd784ff"
-  integrity sha512-4tUmeLyXJnJWvTFOKtcNJ1yh0a3SsTLi2MUoyj8iUNznFRN1ZquaNe7Oukqrnki2FzZkm0J9adCNLDZxUzvj+w==
-  dependencies:
-    fast-glob "^3.2.7"
-    minimatch "^3.0.4"
-    mkdirp "^1.0.4"
-    path-browserify "^1.0.1"
-
 "@tsconfig/node10@^1.0.7":
   version "1.0.11"
   resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.11.tgz#6ee46400685f130e278128c7b38b7e031ff5b2f2"
@@ -2835,15 +2872,32 @@
   integrity sha512-aqBg5oAGo/qh/+wxUfuMadDu2WO0MEWOblyzwaM1Ske2xilUxBfgPqapAFVAfrVTDMVwa0UMarzGot8m64IAzA==
 
 "@types/css-tree@^2.3.8":
-  version "2.3.9"
-  resolved "https://registry.yarnpkg.com/@types/css-tree/-/css-tree-2.3.9.tgz#54c404e0a803e7e660fdc08c84fe73ee5266cece"
-  integrity sha512-g1FE6xkPDP4tsccmTd6jIugjKZdxIDqAf9h2pc+4LsGgYbOyfa9phNjBHYbm6FtwIlNfT1NBx3f2zSeqO7aRAw==
+  version "2.3.10"
+  resolved "https://registry.yarnpkg.com/@types/css-tree/-/css-tree-2.3.10.tgz#b96abb37c1b51b03fe16054c186130c6ab69fef7"
+  integrity sha512-WcaBazJ84RxABvRttQjjFWgTcHvZR9jGr0Y3hccPkHjFyk/a3N8EuxjKr+QfrwjoM5b1yI1Uj1i7EzOAAwBwag==
 
 "@types/diff-match-patch@^1.0.32":
   version "1.0.36"
   resolved "https://registry.yarnpkg.com/@types/diff-match-patch/-/diff-match-patch-1.0.36.tgz#dcef10a69d357fe9d43ac4ff2eca6b85dbf466af"
   integrity sha512-xFdR6tkm0MWvBfO8xXCSsinYxHcqkQUlcHeSpMC2ukzOb6lwQAfDmW+Qt0AvlGd8HpsS28qKsB+oPeJn9I39jg==
 
+"@types/docker-modem@*":
+  version "3.0.6"
+  resolved "https://registry.yarnpkg.com/@types/docker-modem/-/docker-modem-3.0.6.tgz#1f9262fcf85425b158ca725699a03eb23cddbf87"
+  integrity sha512-yKpAGEuKRSS8wwx0joknWxsmLha78wNMe9R2S3UNsVOkZded8UqOrV8KoeDXoXsjndxwyF3eIhyClGbO1SEhEg==
+  dependencies:
+    "@types/node" "*"
+    "@types/ssh2" "*"
+
+"@types/dockerode@^3.3.29":
+  version "3.3.33"
+  resolved "https://registry.yarnpkg.com/@types/dockerode/-/dockerode-3.3.33.tgz#67d9b4223caf41a0735695abe89c292e05d305c9"
+  integrity sha512-7av8lVOhkW7Xd11aZTSq5zhdpyNraldXwQR0pxUCiSNTvIzsP86KrFrmrZgxtrXD2Zrtzwt4H6OYLbATONWzWg==
+  dependencies:
+    "@types/docker-modem" "*"
+    "@types/node" "*"
+    "@types/ssh2" "*"
+
 "@types/escape-html@^1.0.1":
   version "1.0.4"
   resolved "https://registry.yarnpkg.com/@types/escape-html/-/escape-html-1.0.4.tgz#dc7c166b76c7b03b27e32f80edf01d91eb5d9af2"
@@ -2920,14 +2974,6 @@
   resolved "https://registry.yarnpkg.com/@types/file-saver/-/file-saver-2.0.7.tgz#8dbb2f24bdc7486c54aa854eb414940bbd056f7d"
   integrity sha512-dNKVfHd/jk0SkR/exKGj2ggkB45MAkzvWCaqLUUgkyjITkGNzH8H+yUwr+BLJUBjZOe9w8X3wgmXhZDRg1ED6A==
 
-"@types/fs-extra@^11.0.0":
-  version "11.0.4"
-  resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-11.0.4.tgz#e16a863bb8843fba8c5004362b5a73e17becca45"
-  integrity sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==
-  dependencies:
-    "@types/jsonfile" "*"
-    "@types/node" "*"
-
 "@types/geojson-vt@3.2.5":
   version "3.2.5"
   resolved "https://registry.yarnpkg.com/@types/geojson-vt/-/geojson-vt-3.2.5.tgz#b6c356874991d9ab4207533476dfbcdb21e38408"
@@ -2935,11 +2981,16 @@
   dependencies:
     "@types/geojson" "*"
 
-"@types/geojson@*", "@types/geojson@^7946.0.14":
+"@types/geojson@*":
   version "7946.0.14"
   resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.14.tgz#319b63ad6df705ee2a65a73ef042c8271e696613"
   integrity sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg==
 
+"@types/geojson@^7946.0.15":
+  version "7946.0.15"
+  resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.15.tgz#f9d55fd5a0aa2de9dc80b1b04e437538b7298868"
+  integrity sha512-9oSxFzDCT2Rj6DfcHF8G++jxBKS7mBqXl5xrRW+Kbvjry6Uduya2iiwqHPhVXpasAVMBYKkEPGgKhd3+/HZ6xA==
+
 "@types/glob-to-regexp@^0.4.1":
   version "0.4.4"
   resolved "https://registry.yarnpkg.com/@types/glob-to-regexp/-/glob-to-regexp-0.4.4.tgz#409e71290253203185b1ea8a3d6ea406a4bdc902"
@@ -3028,13 +3079,6 @@
   resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
   integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==
 
-"@types/jsonfile@*":
-  version "6.1.4"
-  resolved "https://registry.yarnpkg.com/@types/jsonfile/-/jsonfile-6.1.4.tgz#614afec1a1164e7d670b4a7ad64df3e7beb7b702"
-  integrity sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==
-  dependencies:
-    "@types/node" "*"
-
 "@types/jsrsasign@^10.5.4":
   version "10.5.15"
   resolved "https://registry.yarnpkg.com/@types/jsrsasign/-/jsrsasign-10.5.15.tgz#5cf1ee506b2fa2435b6e1786a873285c7110eb82"
@@ -3046,9 +3090,9 @@
   integrity sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ==
 
 "@types/lodash@^4.14.168":
-  version "4.17.13"
-  resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.13.tgz#786e2d67cfd95e32862143abe7463a7f90c300eb"
-  integrity sha512-lfx+dftrEZcdBPczf9d0Qv0x+j/rfNCMuC6OcfXmO8gkfeNAY88PgKUbvG56whcN23gc27yenwF6oJZXGFpYxg==
+  version "4.17.14"
+  resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.14.tgz#bafc053533f4cdc5fcc9635af46a963c1f3deaff"
+  integrity sha512-jsxagdikDiDBeIRaPYtArcT8my4tN1og7MtMRquFT3XNA6axxyHDRUemqDz/taRDdOUn0GnGHRCuff4q48sW9A==
 
 "@types/mapbox__point-geometry@*", "@types/mapbox__point-geometry@^0.1.4":
   version "0.1.4"
@@ -3102,9 +3146,16 @@
     undici-types "~6.20.0"
 
 "@types/node@18":
-  version "18.19.68"
-  resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.68.tgz#f4f10d9927a7eaf3568c46a6d739cc0967ccb701"
-  integrity sha512-QGtpFH1vB99ZmTa63K4/FU8twThj4fuVSBkGddTp7uIL/cuoLWIUSL2RcOaigBhfR+hg5pgGkBnkoOxrTVBMKw==
+  version "18.19.70"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.70.tgz#5a77508f5568d16fcd3b711c8102d7a430a04df7"
+  integrity sha512-RE+K0+KZoEpDUbGGctnGdkrLFwi1eYKTlIHNl2Um98mUkGsm1u2Ff6Ltd0e8DktTtC98uy7rSj+hO8t/QuLoVQ==
+  dependencies:
+    undici-types "~5.26.4"
+
+"@types/node@^18.11.18":
+  version "18.19.69"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.69.tgz#748d301818ba4b238854c53d290257a70aae7d01"
+  integrity sha512-ECPdY1nlaiO/Y6GUnwgtAAhLNaQ53AyIVz+eILxpEo5OvuqE6yWkqWBIb5dU0DqhKQtMeny+FBD3PK6lm7L5xQ==
   dependencies:
     undici-types "~5.26.4"
 
@@ -3118,16 +3169,16 @@
   resolved "https://registry.yarnpkg.com/@types/pako/-/pako-2.0.3.tgz#b6993334f3af27c158f3fe0dfeeba987c578afb1"
   integrity sha512-bq0hMV9opAcrmE0Byyo0fY3Ew4tgOevJmQ9grUhpXQhYfyLJ1Kqg3P33JT5fdbT2AjeAjR51zqqVjAL/HMkx7Q==
 
-"@types/parse-json@^4.0.0":
-  version "4.0.2"
-  resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.2.tgz#5950e50960793055845e956c427fc2b0d70c5239"
-  integrity sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==
-
 "@types/pbf@*", "@types/pbf@^3.0.5":
   version "3.0.5"
   resolved "https://registry.yarnpkg.com/@types/pbf/-/pbf-3.0.5.tgz#a9495a58d8c75be4ffe9a0bd749a307715c07404"
   integrity sha512-j3pOPiEcWZ34R6a6mN07mUkM4o4Lwf6hPNt8eilOeZhTFbxFXmKhvXl9Y28jotFPaI1bpPDJsbCprUoNke6OrA==
 
+"@types/png-chunks-extract@^1.0.2":
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/@types/png-chunks-extract/-/png-chunks-extract-1.0.2.tgz#31dd8d74d6ba879ace317c1e042dcdabc6300d6e"
+  integrity sha512-z6djfFIbrrddtunoMJBOPlyZrnmeuG1kkvHUNi2QfpOb+JMMLuLliHHTmMyRi7k7LiTAut0HbdGCF6ibDtQAHQ==
+
 "@types/prop-types@*":
   version "15.7.13"
   resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.13.tgz#2af91918ee12d9d32914feb13f5326658461b451"
@@ -3157,12 +3208,10 @@
   dependencies:
     "@types/react" "*"
 
-"@types/react-dom@18.3.1":
-  version "18.3.1"
-  resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.3.1.tgz#1e4654c08a9cdcfb6594c780ac59b55aad42fe07"
-  integrity sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==
-  dependencies:
-    "@types/react" "*"
+"@types/react-dom@18.3.5":
+  version "18.3.5"
+  resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.3.5.tgz#45f9f87398c5dcea085b715c58ddcf1faf65f716"
+  integrity sha512-P4t6saawp+b/dFrUr2cvkVsfvPguwsxtH6dNIYRllMsefqFzkZk5UIjzyDOv5g1dXIPdG4Sp1yCR4Z6RCUsG/Q==
 
 "@types/react-redux@^7.1.20":
   version "7.1.34"
@@ -3181,10 +3230,18 @@
   dependencies:
     "@types/react" "*"
 
-"@types/react@*", "@types/react@18.3.3":
-  version "18.3.3"
-  resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.3.tgz#9679020895318b0915d7a3ab004d92d33375c45f"
-  integrity sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==
+"@types/react-virtualized@^9.21.30":
+  version "9.22.0"
+  resolved "https://registry.yarnpkg.com/@types/react-virtualized/-/react-virtualized-9.22.0.tgz#2ff9b3692fa04a429df24ffc7d181d9f33b3831d"
+  integrity sha512-JL/YCCFZ123za//cj10Apk54F0UGFMrjOE0QHTuXt1KBMFrzLOGv9/x6Uc/pZ0Gaf4o6w61Fostvlw0DwuPXig==
+  dependencies:
+    "@types/prop-types" "*"
+    "@types/react" "*"
+
+"@types/react@*", "@types/react@18.3.18":
+  version "18.3.18"
+  resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.18.tgz#9b382c4cd32e13e463f97df07c2ee3bbcd26904b"
+  integrity sha512-t4yC+vtgnkYjNSKlFx1jkAhH8LgTo2N/7Qvi83kdEaUtMDiwpbLAktKDaAMlRcJ5eSxZkH74eEGt1ky31d7kfQ==
   dependencies:
     "@types/prop-types" "*"
     csstype "^3.0.2"
@@ -3247,6 +3304,28 @@
   dependencies:
     "@types/node" "*"
 
+"@types/ssh2-streams@*":
+  version "0.1.12"
+  resolved "https://registry.yarnpkg.com/@types/ssh2-streams/-/ssh2-streams-0.1.12.tgz#e68795ba2bf01c76b93f9c9809e1f42f0eaaec5f"
+  integrity sha512-Sy8tpEmCce4Tq0oSOYdfqaBpA3hDM8SoxoFh5vzFsu2oL+znzGz8oVWW7xb4K920yYMUY+PIG31qZnFMfPWNCg==
+  dependencies:
+    "@types/node" "*"
+
+"@types/ssh2@*":
+  version "1.15.1"
+  resolved "https://registry.yarnpkg.com/@types/ssh2/-/ssh2-1.15.1.tgz#4db4b6864abca09eb299fe5354fa591add412223"
+  integrity sha512-ZIbEqKAsi5gj35y4P4vkJYly642wIbY6PqoN0xiyQGshKUGXR9WQjF/iF9mXBQ8uBKy3ezfsCkcoHKhd0BzuDA==
+  dependencies:
+    "@types/node" "^18.11.18"
+
+"@types/ssh2@^0.5.48":
+  version "0.5.52"
+  resolved "https://registry.yarnpkg.com/@types/ssh2/-/ssh2-0.5.52.tgz#9dbd8084e2a976e551d5e5e70b978ed8b5965741"
+  integrity sha512-lbLLlXxdCZOSJMCInKH2+9V/77ET2J6NPQHpFI0kda61Dd1KglJs+fPQBchizmzYSOJBgdTajhPqBO1xxLywvg==
+  dependencies:
+    "@types/node" "*"
+    "@types/ssh2-streams" "*"
+
 "@types/stack-utils@^2.0.0":
   version "2.0.3"
   resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8"
@@ -3298,30 +3377,30 @@
   dependencies:
     "@types/yargs-parser" "*"
 
-"@typescript-eslint/eslint-plugin@^8.0.0":
-  version "8.16.0"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.16.0.tgz#ac56825bcdf3b392fc76a94b1315d4a162f201a6"
-  integrity sha512-5YTHKV8MYlyMI6BaEG7crQ9BhSc8RxzshOReKwZwRWN0+XvvTOm+L/UYLCYxFpfwYuAAqhxiq4yae0CMFwbL7Q==
+"@typescript-eslint/eslint-plugin@^8.19.0":
+  version "8.19.1"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.19.1.tgz#5f26c0a833b27bcb1aa402b82e76d3b8dda0b247"
+  integrity sha512-tJzcVyvvb9h/PB96g30MpxACd9IrunT7GF9wfA9/0TJ1LxGOJx1TdPzSbBBnNED7K9Ka8ybJsnEpiXPktolTLg==
   dependencies:
     "@eslint-community/regexpp" "^4.10.0"
-    "@typescript-eslint/scope-manager" "8.16.0"
-    "@typescript-eslint/type-utils" "8.16.0"
-    "@typescript-eslint/utils" "8.16.0"
-    "@typescript-eslint/visitor-keys" "8.16.0"
+    "@typescript-eslint/scope-manager" "8.19.1"
+    "@typescript-eslint/type-utils" "8.19.1"
+    "@typescript-eslint/utils" "8.19.1"
+    "@typescript-eslint/visitor-keys" "8.19.1"
     graphemer "^1.4.0"
     ignore "^5.3.1"
     natural-compare "^1.4.0"
-    ts-api-utils "^1.3.0"
+    ts-api-utils "^2.0.0"
 
-"@typescript-eslint/parser@^8.0.0":
-  version "8.16.0"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.16.0.tgz#ee5b2d6241c1ab3e2e53f03fd5a32d8e266d8e06"
-  integrity sha512-D7DbgGFtsqIPIFMPJwCad9Gfi/hC0PWErRRHFnaCWoEDYi5tQUDiJCTmGUbBiLzjqAck4KcXt9Ayj0CNlIrF+w==
+"@typescript-eslint/parser@^8.19.0":
+  version "8.19.1"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.19.1.tgz#b836fcfe7a704c8c65f5a50e5b0ff8acfca5c21b"
+  integrity sha512-67gbfv8rAwawjYx3fYArwldTQKoYfezNUT4D5ioWetr/xCrxXxvleo3uuiFuKfejipvq+og7mjz3b0G2bVyUCw==
   dependencies:
-    "@typescript-eslint/scope-manager" "8.16.0"
-    "@typescript-eslint/types" "8.16.0"
-    "@typescript-eslint/typescript-estree" "8.16.0"
-    "@typescript-eslint/visitor-keys" "8.16.0"
+    "@typescript-eslint/scope-manager" "8.19.1"
+    "@typescript-eslint/types" "8.19.1"
+    "@typescript-eslint/typescript-estree" "8.19.1"
+    "@typescript-eslint/visitor-keys" "8.19.1"
     debug "^4.3.4"
 
 "@typescript-eslint/scope-manager@8.16.0":
@@ -3332,21 +3411,34 @@
     "@typescript-eslint/types" "8.16.0"
     "@typescript-eslint/visitor-keys" "8.16.0"
 
-"@typescript-eslint/type-utils@8.16.0":
-  version "8.16.0"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.16.0.tgz#585388735f7ac390f07c885845c3d185d1b64740"
-  integrity sha512-IqZHGG+g1XCWX9NyqnI/0CX5LL8/18awQqmkZSl2ynn8F76j579dByc0jhfVSnSnhf7zv76mKBQv9HQFKvDCgg==
+"@typescript-eslint/scope-manager@8.19.1":
+  version "8.19.1"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.19.1.tgz#794cfc8add4f373b9cd6fa32e367e7565a0e231b"
+  integrity sha512-60L9KIuN/xgmsINzonOcMDSB8p82h95hoBfSBtXuO4jlR1R9L1xSkmVZKgCPVfavDlXihh4ARNjXhh1gGnLC7Q==
   dependencies:
-    "@typescript-eslint/typescript-estree" "8.16.0"
-    "@typescript-eslint/utils" "8.16.0"
+    "@typescript-eslint/types" "8.19.1"
+    "@typescript-eslint/visitor-keys" "8.19.1"
+
+"@typescript-eslint/type-utils@8.19.1":
+  version "8.19.1"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.19.1.tgz#23710ab52643c19f74601b3f4a076c98f4e159aa"
+  integrity sha512-Rp7k9lhDKBMRJB/nM9Ksp1zs4796wVNyihG9/TU9R6KCJDNkQbc2EOKjrBtLYh3396ZdpXLtr/MkaSEmNMtykw==
+  dependencies:
+    "@typescript-eslint/typescript-estree" "8.19.1"
+    "@typescript-eslint/utils" "8.19.1"
     debug "^4.3.4"
-    ts-api-utils "^1.3.0"
+    ts-api-utils "^2.0.0"
 
 "@typescript-eslint/types@8.16.0":
   version "8.16.0"
   resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.16.0.tgz#49c92ae1b57942458ab83d9ec7ccab3005e64737"
   integrity sha512-NzrHj6thBAOSE4d9bsuRNMvk+BvaQvmY4dDglgkgGC0EW/tB3Kelnp3tAKH87GEwzoxgeQn9fNGRyFJM/xd+GQ==
 
+"@typescript-eslint/types@8.19.1":
+  version "8.19.1"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.19.1.tgz#015a991281754ed986f2e549263a1188d6ed0a8c"
+  integrity sha512-JBVHMLj7B1K1v1051ZaMMgLW4Q/jre5qGK0Ew6UgXz1Rqh+/xPzV1aW581OM00X6iOfyr1be+QyW8LOUf19BbA==
+
 "@typescript-eslint/typescript-estree@8.16.0":
   version "8.16.0"
   resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.16.0.tgz#9d741e56e5b13469b5190e763432ce5551a9300c"
@@ -3361,7 +3453,31 @@
     semver "^7.6.0"
     ts-api-utils "^1.3.0"
 
-"@typescript-eslint/utils@8.16.0", "@typescript-eslint/utils@^6.0.0 || ^7.0.0 || ^8.0.0", "@typescript-eslint/utils@^8.13.0":
+"@typescript-eslint/typescript-estree@8.19.1":
+  version "8.19.1"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.19.1.tgz#c1094bb00bc251ac76cf215569ca27236435036b"
+  integrity sha512-jk/TZwSMJlxlNnqhy0Eod1PNEvCkpY6MXOXE/WLlblZ6ibb32i2We4uByoKPv1d0OD2xebDv4hbs3fm11SMw8Q==
+  dependencies:
+    "@typescript-eslint/types" "8.19.1"
+    "@typescript-eslint/visitor-keys" "8.19.1"
+    debug "^4.3.4"
+    fast-glob "^3.3.2"
+    is-glob "^4.0.3"
+    minimatch "^9.0.4"
+    semver "^7.6.0"
+    ts-api-utils "^2.0.0"
+
+"@typescript-eslint/utils@8.19.1":
+  version "8.19.1"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.19.1.tgz#dd8eabd46b92bf61e573286e1c0ba6bd243a185b"
+  integrity sha512-IxG5gLO0Ne+KaUc8iW1A+XuKLd63o4wlbI1Zp692n1xojCl/THvgIKXJXBZixTh5dd5+yTJ/VXH7GJaaw21qXA==
+  dependencies:
+    "@eslint-community/eslint-utils" "^4.4.0"
+    "@typescript-eslint/scope-manager" "8.19.1"
+    "@typescript-eslint/types" "8.19.1"
+    "@typescript-eslint/typescript-estree" "8.19.1"
+
+"@typescript-eslint/utils@^6.0.0 || ^7.0.0 || ^8.0.0", "@typescript-eslint/utils@^8.13.0":
   version "8.16.0"
   resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.16.0.tgz#c71264c437157feaa97842809836254a6fc833c3"
   integrity sha512-C1zRy/mOL8Pj157GiX4kaw7iyRLKfJXBR3L82hk5kS/GyHcOFmy4YUq/zfZti72I9wnuQtA/+xzft4wCC8PJdA==
@@ -3379,15 +3495,23 @@
     "@typescript-eslint/types" "8.16.0"
     eslint-visitor-keys "^4.2.0"
 
+"@typescript-eslint/visitor-keys@8.19.1":
+  version "8.19.1"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.19.1.tgz#fce54d7cfa5351a92387d6c0c5be598caee072e0"
+  integrity sha512-fzmjU8CHK853V/avYZAvuVut3ZTfwN5YtMaoi+X9Y9MA9keaWNHC3zEQ9zvyX/7Hj+5JkNyK1l7TOR2hevHB6Q==
+  dependencies:
+    "@typescript-eslint/types" "8.19.1"
+    eslint-visitor-keys "^4.2.0"
+
 "@ungap/structured-clone@^1.2.0":
   version "1.2.0"
   resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406"
   integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==
 
-"@vector-im/compound-design-tokens@^2.0.1":
-  version "2.1.1"
-  resolved "https://registry.yarnpkg.com/@vector-im/compound-design-tokens/-/compound-design-tokens-2.1.1.tgz#d6175a99fe4b97688464126f255386990f3048d6"
-  integrity sha512-QnUi2K14D9KTXxcLQKUU3V75cforZLMwhaaJDNftT8F5mG86950hAM+qhgDNEpEU+pkTffQj0/g/5859YmqWzQ==
+"@vector-im/compound-design-tokens@^2.1.0":
+  version "2.1.3"
+  resolved "https://registry.yarnpkg.com/@vector-im/compound-design-tokens/-/compound-design-tokens-2.1.3.tgz#8205ffb455a09d71a02d838f3dbb8503c4e6ec27"
+  integrity sha512-U4UF7MVguENf0lQnkU2a9p/3llTsLXzbzmFFOxi0h6ny2igNxZj/kROP/jXTxxV9xD4TNn3z098Bos4J/qJpBA==
 
 "@vector-im/compound-web@^7.5.0":
   version "7.5.0"
@@ -3405,12 +3529,16 @@
     ts-xor "^1.3.0"
     vaul "^1.0.0"
 
-"@vector-im/matrix-wysiwyg@2.37.13":
-  version "2.37.13"
-  resolved "https://registry.yarnpkg.com/@vector-im/matrix-wysiwyg/-/matrix-wysiwyg-2.37.13.tgz#7b64e7652a196e811c0470dcbff8d36e2229cd46"
-  integrity sha512-3ilnJBJSzeTfAQXNJJ29EAqa14exrkca3acTPssdoh3WhTKwXyQ0xU8sS50d6gqlAP/Nahw1y2k+PzajXo1SsQ==
+"@vector-im/matrix-wysiwyg-wasm@link:../../.cache/yarn/v6/npm-@vector-im-matrix-wysiwyg-2.38.0-af862ffd231dc0a6b8d6f2cb3601e68456c0ff24-integrity/node_modules/bindings/wysiwyg-wasm":
+  version "0.0.0"
+  uid ""
+
+"@vector-im/matrix-wysiwyg@2.38.0":
+  version "2.38.0"
+  resolved "https://registry.yarnpkg.com/@vector-im/matrix-wysiwyg/-/matrix-wysiwyg-2.38.0.tgz#af862ffd231dc0a6b8d6f2cb3601e68456c0ff24"
+  integrity sha512-cMEVicFYVzFxuSyWON0aVGjAJMcgJZ+LxuLTEp8EGuu8cRacuh0RN5rapb11YVZygzFvE7X1cMedJ/fKd5vRLA==
   dependencies:
-    eslint-plugin-unicorn "^54.0.0"
+    "@vector-im/matrix-wysiwyg-wasm" "link:../../../.cache/yarn/v6/npm-@vector-im-matrix-wysiwyg-2.38.0-af862ffd231dc0a6b8d6f2cb3601e68456c0ff24-integrity/node_modules/bindings/wysiwyg-wasm"
 
 "@webassemblyjs/ast@1.14.1", "@webassemblyjs/ast@^1.14.1":
   version "1.14.1"
@@ -3533,20 +3661,20 @@
     "@webassemblyjs/ast" "1.14.1"
     "@xtuc/long" "4.2.2"
 
-"@webpack-cli/configtest@^2.1.1":
-  version "2.1.1"
-  resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-2.1.1.tgz#3b2f852e91dac6e3b85fb2a314fb8bef46d94646"
-  integrity sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==
+"@webpack-cli/configtest@^3.0.1":
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-3.0.1.tgz#76ac285b9658fa642ce238c276264589aa2b6b57"
+  integrity sha512-u8d0pJ5YFgneF/GuvEiDA61Tf1VDomHHYMjv/wc9XzYj7nopltpG96nXN5dJRstxZhcNpV1g+nT6CydO7pHbjA==
 
-"@webpack-cli/info@^2.0.2":
-  version "2.0.2"
-  resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-2.0.2.tgz#cc3fbf22efeb88ff62310cf885c5b09f44ae0fdd"
-  integrity sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==
+"@webpack-cli/info@^3.0.1":
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-3.0.1.tgz#3cff37fabb7d4ecaab6a8a4757d3826cf5888c63"
+  integrity sha512-coEmDzc2u/ffMvuW9aCjoRzNSPDl/XLuhPdlFRpT9tZHmJ/039az33CE7uH+8s0uL1j5ZNtfdv0HkfaKRBGJsQ==
 
-"@webpack-cli/serve@^2.0.5":
-  version "2.0.5"
-  resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-2.0.5.tgz#325db42395cd49fe6c14057f9a900e427df8810e"
-  integrity sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==
+"@webpack-cli/serve@^3.0.1":
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-3.0.1.tgz#bd8b1f824d57e30faa19eb78e4c0951056f72f00"
+  integrity sha512-sbgw03xQaCLiT6gcY/6u3qBDn01CWw/nbaXl3gTdTFuJJ75Gffv3E3DBpgvY2fkkrdS1fpjaXNOmJlnbtKauKg==
 
 "@xtuc/ieee754@^1.2.0":
   version "1.2.0"
@@ -3580,6 +3708,13 @@ abab@^2.0.6:
   resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291"
   integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==
 
+abort-controller@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392"
+  integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==
+  dependencies:
+    event-target-shim "^5.0.0"
+
 accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.8:
   version "1.3.8"
   resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e"
@@ -3608,7 +3743,7 @@ acorn-walk@^8.0.0, acorn-walk@^8.0.2, acorn-walk@^8.1.1:
   dependencies:
     acorn "^8.11.0"
 
-acorn@^8.0.4, acorn@^8.1.0, acorn@^8.11.0, acorn@^8.12.0, acorn@^8.4.1, acorn@^8.9.0:
+acorn@^8.0.4, acorn@^8.1.0, acorn@^8.11.0, acorn@^8.4.1, acorn@^8.9.0:
   version "8.13.0"
   resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.13.0.tgz#2a30d670818ad16ddd6a35d3842dacec9e5d7ca3"
   integrity sha512-8zSiw54Oxrdym50NlZ9sUusyO1Z1ZchgRLWRaK6c86XJFClyCgFKetdowBg5bKxyp/u+CDBJG4Mpp0m3HLZl9w==
@@ -3738,6 +3873,32 @@ anymatch@^3.0.3, anymatch@~3.1.2:
     normalize-path "^3.0.0"
     picomatch "^2.0.4"
 
+archiver-utils@^5.0.0, archiver-utils@^5.0.2:
+  version "5.0.2"
+  resolved "https://registry.yarnpkg.com/archiver-utils/-/archiver-utils-5.0.2.tgz#63bc719d951803efc72cf961a56ef810760dd14d"
+  integrity sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==
+  dependencies:
+    glob "^10.0.0"
+    graceful-fs "^4.2.0"
+    is-stream "^2.0.1"
+    lazystream "^1.0.0"
+    lodash "^4.17.15"
+    normalize-path "^3.0.0"
+    readable-stream "^4.0.0"
+
+archiver@^7.0.1:
+  version "7.0.1"
+  resolved "https://registry.yarnpkg.com/archiver/-/archiver-7.0.1.tgz#c9d91c350362040b8927379c7aa69c0655122f61"
+  integrity sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==
+  dependencies:
+    archiver-utils "^5.0.2"
+    async "^3.2.4"
+    buffer-crc32 "^1.0.0"
+    readable-stream "^4.0.0"
+    readdir-glob "^1.1.2"
+    tar-stream "^3.0.0"
+    zip-stream "^6.0.1"
+
 arg@^4.1.0:
   version "4.1.3"
   resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089"
@@ -3873,6 +4034,13 @@ arraybuffer.prototype.slice@^1.0.3:
     is-array-buffer "^3.0.4"
     is-shared-array-buffer "^1.0.2"
 
+asn1@^0.2.6:
+  version "0.2.6"
+  resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.6.tgz#0d3a7bb6e64e02a90c0303b31f292868ea09a08d"
+  integrity sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==
+  dependencies:
+    safer-buffer "~2.1.0"
+
 asn1js@^3.0.5:
   version "3.0.5"
   resolved "https://registry.yarnpkg.com/asn1js/-/asn1js-3.0.5.tgz#5ea36820443dbefb51cc7f88a2ebb5b462114f38"
@@ -3892,7 +4060,12 @@ astral-regex@^2.0.0:
   resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31"
   integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==
 
-async@^3.2.3:
+async-lock@^1.4.1:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/async-lock/-/async-lock-1.4.1.tgz#56b8718915a9b68b10fce2f2a9a3dddf765ef53f"
+  integrity sha512-Az2ZTpuytrtqENulXwO3GGv1Bztugx6TT37NIo7imr/Qo0gsYiGtSdBa2B6fsXhTpVZDNfu1Qn3pk531e3q+nQ==
+
+async@^3.2.3, async@^3.2.4:
   version "3.2.6"
   resolved "https://registry.yarnpkg.com/async/-/async-3.2.6.tgz#1b0728e14929d51b85b449b7f06e27c1145e38ce"
   integrity sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==
@@ -3936,6 +4109,11 @@ axobject-query@^4.1.0:
   resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-4.1.0.tgz#28768c76d0e3cff21bc62a9e2d0b6ac30042a1ee"
   integrity sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==
 
+b4a@^1.6.4:
+  version "1.6.7"
+  resolved "https://registry.yarnpkg.com/b4a/-/b4a-1.6.7.tgz#a99587d4ebbfbd5a6e3b21bdb5d5fa385767abe4"
+  integrity sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==
+
 babel-jest@^29.0.0, babel-jest@^29.7.0:
   version "29.7.0"
   resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.7.0.tgz#f4369919225b684c56085998ac63dbd05be020d5"
@@ -4046,6 +4224,39 @@ balanced-match@^2.0.0:
   resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-2.0.0.tgz#dc70f920d78db8b858535795867bf48f820633d9"
   integrity sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==
 
+bare-events@^2.0.0, bare-events@^2.2.0:
+  version "2.5.0"
+  resolved "https://registry.yarnpkg.com/bare-events/-/bare-events-2.5.0.tgz#305b511e262ffd8b9d5616b056464f8e1b3329cc"
+  integrity sha512-/E8dDe9dsbLyh2qrZ64PEPadOQ0F4gbl1sUJOrmph7xOiIxfY8vwab/4bFLh4Y88/Hk/ujKcrQKc+ps0mv873A==
+
+bare-fs@^2.1.1:
+  version "2.3.5"
+  resolved "https://registry.yarnpkg.com/bare-fs/-/bare-fs-2.3.5.tgz#05daa8e8206aeb46d13c2fe25a2cd3797b0d284a"
+  integrity sha512-SlE9eTxifPDJrT6YgemQ1WGFleevzwY+XAP1Xqgl56HtcrisC2CHCZ2tq6dBpcH2TnNxwUEUGhweo+lrQtYuiw==
+  dependencies:
+    bare-events "^2.0.0"
+    bare-path "^2.0.0"
+    bare-stream "^2.0.0"
+
+bare-os@^2.1.0:
+  version "2.4.4"
+  resolved "https://registry.yarnpkg.com/bare-os/-/bare-os-2.4.4.tgz#01243392eb0a6e947177bb7c8a45123d45c9b1a9"
+  integrity sha512-z3UiI2yi1mK0sXeRdc4O1Kk8aOa/e+FNWZcTiPB/dfTWyLypuE99LibgRaQki914Jq//yAWylcAt+mknKdixRQ==
+
+bare-path@^2.0.0, bare-path@^2.1.0:
+  version "2.1.3"
+  resolved "https://registry.yarnpkg.com/bare-path/-/bare-path-2.1.3.tgz#594104c829ef660e43b5589ec8daef7df6cedb3e"
+  integrity sha512-lh/eITfU8hrj9Ru5quUp0Io1kJWIk1bTjzo7JH1P5dWmQ2EL4hFUlfI8FonAhSlgIfhn63p84CDY/x+PisgcXA==
+  dependencies:
+    bare-os "^2.1.0"
+
+bare-stream@^2.0.0:
+  version "2.6.1"
+  resolved "https://registry.yarnpkg.com/bare-stream/-/bare-stream-2.6.1.tgz#b3b9874fab05b662c9aea2706a12fb0698c46836"
+  integrity sha512-eVZbtKM+4uehzrsj49KtCy3Pbg7kO1pJ3SKZ1SFrIH/0pnj9scuGGgUlNDf/7qS8WKtGdiJY5Kyhs/ivYPTB/g==
+  dependencies:
+    streamx "^2.21.0"
+
 base-x@^5.0.0:
   version "5.0.0"
   resolved "https://registry.yarnpkg.com/base-x/-/base-x-5.0.0.tgz#6d835ceae379130e1a4cb846a70ac4746f28ea9b"
@@ -4056,11 +4267,23 @@ base64-arraybuffer@^1.0.2:
   resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz#1c37589a7c4b0746e34bd1feb951da2df01c1bdc"
   integrity sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==
 
+base64-js@^1.3.1:
+  version "1.5.1"
+  resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
+  integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
+
 batch@0.6.1:
   version "0.6.1"
   resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16"
   integrity sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==
 
+bcrypt-pbkdf@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e"
+  integrity sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==
+  dependencies:
+    tweetnacl "^0.14.3"
+
 big.js@^5.2.2:
   version "5.2.2"
   resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328"
@@ -4071,6 +4294,15 @@ binary-extensions@^2.0.0:
   resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522"
   integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==
 
+bl@^4.0.3:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a"
+  integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==
+  dependencies:
+    buffer "^5.5.0"
+    inherits "^2.0.4"
+    readable-stream "^3.4.0"
+
 blob-polyfill@^9.0.0:
   version "9.0.20240710"
   resolved "https://registry.yarnpkg.com/blob-polyfill/-/blob-polyfill-9.0.20240710.tgz#2ef075a207311ea327704f04dc4a98cbefe4143b"
@@ -4148,7 +4380,7 @@ braces@^3.0.3, braces@~3.0.2:
   dependencies:
     fill-range "^7.1.1"
 
-browserslist@^4.0.0, browserslist@^4.23.1, browserslist@^4.23.2, browserslist@^4.23.3, browserslist@^4.24.0, browserslist@^4.24.2:
+browserslist@^4.0.0, browserslist@^4.23.2, browserslist@^4.24.0, browserslist@^4.24.2:
   version "4.24.2"
   resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.2.tgz#f5845bc91069dbd55ee89faf9822e1d885d16580"
   integrity sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==
@@ -4158,6 +4390,16 @@ browserslist@^4.0.0, browserslist@^4.23.1, browserslist@^4.23.2, browserslist@^4
     node-releases "^2.0.18"
     update-browserslist-db "^1.1.1"
 
+browserslist@^4.23.1, browserslist@^4.23.3:
+  version "4.24.4"
+  resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.4.tgz#c6b2865a3f08bcb860a0e827389003b9fe686e4b"
+  integrity sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==
+  dependencies:
+    caniuse-lite "^1.0.30001688"
+    electron-to-chromium "^1.5.73"
+    node-releases "^2.0.19"
+    update-browserslist-db "^1.1.1"
+
 bs58@^6.0.0:
   version "6.0.0"
   resolved "https://registry.yarnpkg.com/bs58/-/bs58-6.0.0.tgz#a2cda0130558535dd281a2f8697df79caaf425d8"
@@ -4172,11 +4414,37 @@ bser@2.1.1:
   dependencies:
     node-int64 "^0.4.0"
 
+buffer-crc32@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-1.0.0.tgz#a10993b9055081d55304bd9feb4a072de179f405"
+  integrity sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==
+
 buffer-from@^1.0.0:
   version "1.1.2"
   resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5"
   integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==
 
+buffer@^5.5.0:
+  version "5.7.1"
+  resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0"
+  integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==
+  dependencies:
+    base64-js "^1.3.1"
+    ieee754 "^1.1.13"
+
+buffer@^6.0.3:
+  version "6.0.3"
+  resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6"
+  integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==
+  dependencies:
+    base64-js "^1.3.1"
+    ieee754 "^1.2.1"
+
+buildcheck@~0.0.6:
+  version "0.0.6"
+  resolved "https://registry.yarnpkg.com/buildcheck/-/buildcheck-0.0.6.tgz#89aa6e417cfd1e2196e3f8fe915eb709d2fe4238"
+  integrity sha512-8f9ZJCUXyT1M35Jx7MkBgmBMo3oHTTBIPLiY9xyL0pl3T5RwcPEY8cUHr5LBNfu/fk6c2T4DJZuVM/8ZZT2D2A==
+
 builtin-modules@^3.3.0:
   version "3.3.0"
   resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6"
@@ -4189,6 +4457,11 @@ bundle-name@^4.1.0:
   dependencies:
     run-applescript "^7.0.0"
 
+byline@^5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/byline/-/byline-5.0.0.tgz#741c5216468eadc457b03410118ad77de8c1ddb1"
+  integrity sha512-s6webAy+R4SR8XVuJWt2V2rGvhnrhxN+9S15GNuTK3wKPOXFF6RNc+8ug2XhH+2s4f+uudG4kUVYmYOQWL2g0Q==
+
 bytes@3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
@@ -4266,10 +4539,10 @@ caniuse-api@^3.0.0:
     lodash.memoize "^4.1.2"
     lodash.uniq "^4.5.0"
 
-caniuse-lite@1.0.30001684, caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001646, caniuse-lite@^1.0.30001669:
-  version "1.0.30001684"
-  resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001684.tgz#0eca437bab7d5f03452ff0ef9de8299be6b08e16"
-  integrity sha512-G1LRwLIQjBQoyq0ZJGqGIJUXzJ8irpbjHLpVRXDvBEScFJ9b17sgK6vlx0GAJFE21okD7zXl08rRRUfq6HdoEQ==
+caniuse-lite@1.0.30001690, caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001646, caniuse-lite@^1.0.30001669, caniuse-lite@^1.0.30001688:
+  version "1.0.30001690"
+  resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001690.tgz#f2d15e3aaf8e18f76b2b8c1481abde063b8104c8"
+  integrity sha512-5ExiE3qQN6oF8Clf8ifIDcMRCRE/dMGcETG/XGMD8/XiXm6HXQgQTh1yZYLXXpSOsEUlJm1Xr7kGULZTuGtP/w==
 
 chalk@5.2.0:
   version "5.2.0"
@@ -4333,6 +4606,11 @@ chokidar@^4.0.0:
   dependencies:
     readdirp "^4.0.1"
 
+chownr@^1.1.1:
+  version "1.1.4"
+  resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b"
+  integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==
+
 chrome-trace-event@^1.0.2:
   version "1.0.4"
   resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz#05bffd7ff928465093314708c93bdfa9bd1f0f5b"
@@ -4424,16 +4702,16 @@ clone@^1.0.2:
   resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e"
   integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==
 
+clsx@^1.0.4:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12"
+  integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==
+
 co@^4.6.0:
   version "4.6.0"
   resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
   integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==
 
-code-block-writer@^11.0.0:
-  version "11.0.3"
-  resolved "https://registry.yarnpkg.com/code-block-writer/-/code-block-writer-11.0.3.tgz#9eec2993edfb79bfae845fbc093758c0a0b73b76"
-  integrity sha512-NiujjUFB4SwScJq2bwbYUtXbZhBSlY6vYzm++3Q6oC+U+injTqfPYFK8wS9COOmb2lueqp0ZRB4nK1VYeHgNyw==
-
 collect-v8-coverage@^1.0.0:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz#c0b29bcd33bcd0779a1344c2136051e6afd3d9e9"
@@ -4480,10 +4758,10 @@ combined-stream@^1.0.8:
   dependencies:
     delayed-stream "~1.0.0"
 
-commander@^10.0.1:
-  version "10.0.1"
-  resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06"
-  integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==
+commander@^12.1.0, commander@~12.1.0:
+  version "12.1.0"
+  resolved "https://registry.yarnpkg.com/commander/-/commander-12.1.0.tgz#01423b36f501259fdaac4d0e4d60c96c991585d3"
+  integrity sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==
 
 commander@^2.20.0:
   version "2.20.3"
@@ -4495,11 +4773,6 @@ commander@^4.1.1:
   resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068"
   integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==
 
-commander@^6.2.1:
-  version "6.2.1"
-  resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c"
-  integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==
-
 commander@^7.2.0:
   version "7.2.0"
   resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7"
@@ -4510,11 +4783,6 @@ commander@^8.3.0:
   resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66"
   integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==
 
-commander@~12.1.0:
-  version "12.1.0"
-  resolved "https://registry.yarnpkg.com/commander/-/commander-12.1.0.tgz#01423b36f501259fdaac4d0e4d60c96c991585d3"
-  integrity sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==
-
 common-path-prefix@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/common-path-prefix/-/common-path-prefix-3.0.0.tgz#7d007a7e07c58c4b4d5f433131a19141b29f11e0"
@@ -4529,6 +4797,17 @@ commonmark@^0.31.0:
     mdurl "~1.0.1"
     minimist "~1.2.8"
 
+compress-commons@^6.0.2:
+  version "6.0.2"
+  resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-6.0.2.tgz#26d31251a66b9d6ba23a84064ecd3a6a71d2609e"
+  integrity sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==
+  dependencies:
+    crc-32 "^1.2.0"
+    crc32-stream "^6.0.0"
+    is-stream "^2.0.1"
+    normalize-path "^3.0.0"
+    readable-stream "^4.0.0"
+
 compressible@~2.0.16:
   version "2.0.18"
   resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba"
@@ -4611,13 +4890,6 @@ copy-webpack-plugin@^12.0.0:
     schema-utils "^4.2.0"
     serialize-javascript "^6.0.2"
 
-core-js-compat@^3.37.0:
-  version "3.38.1"
-  resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.38.1.tgz#2bc7a298746ca5a7bcb9c164bcb120f2ebc09a09"
-  integrity sha512-JRH6gfXxGmrzF3tZ57lFx97YARxCXPaMzPo6jELZhv88pBH5VXpQ+y0znKGlFnzuaihqhLbefxSJxWJMPtfDzw==
-  dependencies:
-    browserslist "^4.23.3"
-
 core-js-compat@^3.38.0, core-js-compat@^3.38.1:
   version "3.39.0"
   resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.39.0.tgz#b12dccb495f2601dc860bdbe7b4e3ffa8ba63f61"
@@ -4635,17 +4907,6 @@ core-util-is@~1.0.0:
   resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85"
   integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==
 
-cosmiconfig@^7.0.1:
-  version "7.1.0"
-  resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz#1443b9afa596b670082ea46cbd8f6a62b84635f6"
-  integrity sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==
-  dependencies:
-    "@types/parse-json" "^4.0.0"
-    import-fresh "^3.2.1"
-    parse-json "^5.0.0"
-    path-type "^4.0.0"
-    yaml "^1.10.0"
-
 cosmiconfig@^8.1.3:
   version "8.3.6"
   resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-8.3.6.tgz#060a2b871d66dba6c8538ea1118ba1ac16f5fae3"
@@ -4677,11 +4938,32 @@ counterpart@^0.18.6:
     pluralizers "^0.1.7"
     sprintf-js "^1.0.3"
 
+cpu-features@~0.0.10:
+  version "0.0.10"
+  resolved "https://registry.yarnpkg.com/cpu-features/-/cpu-features-0.0.10.tgz#9aae536db2710c7254d7ed67cb3cbc7d29ad79c5"
+  integrity sha512-9IkYqtX3YHPCzoVg1Py+o9057a3i0fp7S530UWokCSaFVTc7CwXPRiOjRjBQQ18ZCNafx78YfnG+HALxtVmOGA==
+  dependencies:
+    buildcheck "~0.0.6"
+    nan "^2.19.0"
+
 crc-32@^0.3.0:
   version "0.3.0"
   resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-0.3.0.tgz#6a3d3687f5baec41f7e9b99fe1953a2e5d19775e"
   integrity sha512-kucVIjOmMc1f0tv53BJ/5WIX+MGLcKuoBhnGqQrgKJNqLByb/sVMWfW/Aw6hw0jgcqjJ2pi9E5y32zOIpaUlsA==
 
+crc-32@^1.2.0:
+  version "1.2.2"
+  resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.2.tgz#3cad35a934b8bf71f25ca524b6da51fb7eace2ff"
+  integrity sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==
+
+crc32-stream@^6.0.0:
+  version "6.0.0"
+  resolved "https://registry.yarnpkg.com/crc32-stream/-/crc32-stream-6.0.0.tgz#8529a3868f8b27abb915f6c3617c0fadedbf9430"
+  integrity sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==
+  dependencies:
+    crc-32 "^1.2.0"
+    readable-stream "^4.0.0"
+
 create-jest@^29.7.0:
   version "29.7.0"
   resolved "https://registry.yarnpkg.com/create-jest/-/create-jest-29.7.0.tgz#a355c5b3cb1e1af02ba177fe7afd7feee49a5320"
@@ -4714,12 +4996,12 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3:
     shebang-command "^2.0.0"
     which "^2.0.1"
 
-css-blank-pseudo@^7.0.0:
-  version "7.0.0"
-  resolved "https://registry.yarnpkg.com/css-blank-pseudo/-/css-blank-pseudo-7.0.0.tgz#6069ac242aab6a4d52aabbd0287846080ac8e2d9"
-  integrity sha512-v9xXYGdm6LIn4iHEfu3egk/PM1g/yJr8uwTIj6E44kurv5dE/4y3QW7WdVmZ0PVnqfTuK+C0ClZcEEiaKWBL9Q==
+css-blank-pseudo@^7.0.1:
+  version "7.0.1"
+  resolved "https://registry.yarnpkg.com/css-blank-pseudo/-/css-blank-pseudo-7.0.1.tgz#32020bff20a209a53ad71b8675852b49e8d57e46"
+  integrity sha512-jf+twWGDf6LDoXDUode+nc7ZlrqfaNphrBIBrcmeP3D8yw1uPaix1gCC8LUQUGQ6CycuK2opkbFFWFuq/a94ag==
   dependencies:
-    postcss-selector-parser "^6.1.0"
+    postcss-selector-parser "^7.0.0"
 
 css-box-model@^1.2.0:
   version "1.2.1"
@@ -4738,13 +5020,13 @@ css-functions-list@^3.2.3:
   resolved "https://registry.yarnpkg.com/css-functions-list/-/css-functions-list-3.2.3.tgz#95652b0c24f0f59b291a9fc386041a19d4f40dbe"
   integrity sha512-IQOkD3hbR5KrN93MtcYuad6YPuTSUhntLHDuLEbFWE+ff2/XSZNdZG+LcbbIW5AXKg/WFIfYItIzVoHngHXZzA==
 
-css-has-pseudo@^7.0.0:
-  version "7.0.0"
-  resolved "https://registry.yarnpkg.com/css-has-pseudo/-/css-has-pseudo-7.0.0.tgz#f07f41ba7b55859ee27b0520888c3e21afe97ebc"
-  integrity sha512-vO6k9bBt4/eEZ2PeHmS2VXjJga5SBy6O1ESyaOkse5/lvp6piFqg8Sh5KTU7X33M7Uh/oqo+M3EeMktQrZoTCQ==
+css-has-pseudo@^7.0.2:
+  version "7.0.2"
+  resolved "https://registry.yarnpkg.com/css-has-pseudo/-/css-has-pseudo-7.0.2.tgz#fb42e8de7371f2896961e1f6308f13c2c7019b72"
+  integrity sha512-nzol/h+E0bId46Kn2dQH5VElaknX2Sr0hFuB/1EomdC7j+OISt2ZzK7EHX9DZDY53WbIVAR7FYKSO2XnSf07MQ==
   dependencies:
-    "@csstools/selector-specificity" "^4.0.0"
-    postcss-selector-parser "^6.1.0"
+    "@csstools/selector-specificity" "^5.0.0"
+    postcss-selector-parser "^7.0.0"
     postcss-value-parser "^4.2.0"
 
 css-loader@^7.0.0:
@@ -4834,10 +5116,10 @@ css.escape@^1.5.1:
   resolved "https://registry.yarnpkg.com/css.escape/-/css.escape-1.5.1.tgz#42e27d4fa04ae32f931a4b4d4191fa9cddee97cb"
   integrity sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==
 
-cssdb@^8.1.1:
-  version "8.1.2"
-  resolved "https://registry.yarnpkg.com/cssdb/-/cssdb-8.1.2.tgz#182ac60c19a9182d158dda2816ac2a81254752d5"
-  integrity sha512-ba3HmHU/lxy9nfz/fQLA/Ul+/oSdSOXqoR53BDmRvXTfRbkGqHKqr2rSxADYMRF4uD8vZhMlCQ6c5TEfLLkkVA==
+cssdb@^8.2.3:
+  version "8.2.3"
+  resolved "https://registry.yarnpkg.com/cssdb/-/cssdb-8.2.3.tgz#7e6980bb5a785a9b4eb2a21bd38d50624b56cb46"
+  integrity sha512-9BDG5XmJrJQQnJ51VFxXCAtpZ5ebDlAREmO8sxMOVU0aSxN/gocbctjIG5LMh3WBUq+xTlb/jw2LoljBEqraTA==
 
 cssesc@^3.0.0:
   version "3.0.0"
@@ -4990,7 +5272,7 @@ debug@2.6.9:
   dependencies:
     ms "2.0.0"
 
-debug@4, debug@^4.1.0, debug@^4.3.1:
+debug@4, debug@^4.1.0, debug@^4.3.1, debug@^4.3.5:
   version "4.4.0"
   resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a"
   integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==
@@ -5158,6 +5440,32 @@ dns-packet@^5.2.2:
   dependencies:
     "@leichtgewicht/ip-codec" "^2.0.1"
 
+docker-compose@^0.24.8:
+  version "0.24.8"
+  resolved "https://registry.yarnpkg.com/docker-compose/-/docker-compose-0.24.8.tgz#6c125e6b9e04cf68ced47e2596ef2bb93ee9694e"
+  integrity sha512-plizRs/Vf15H+GCVxq2EUvyPK7ei9b/cVesHvjnX4xaXjM9spHe2Ytq0BitndFgvTJ3E3NljPNUEl7BAN43iZw==
+  dependencies:
+    yaml "^2.2.2"
+
+docker-modem@^3.0.0:
+  version "3.0.8"
+  resolved "https://registry.yarnpkg.com/docker-modem/-/docker-modem-3.0.8.tgz#ef62c8bdff6e8a7d12f0160988c295ea8705e77a"
+  integrity sha512-f0ReSURdM3pcKPNS30mxOHSbaFLcknGmQjwSfmbcdOw1XWKXVhukM3NJHhr7NpY9BIyyWQb0EBo3KQvvuU5egQ==
+  dependencies:
+    debug "^4.1.1"
+    readable-stream "^3.5.0"
+    split-ca "^1.0.1"
+    ssh2 "^1.11.0"
+
+dockerode@^3.3.5:
+  version "3.3.5"
+  resolved "https://registry.yarnpkg.com/dockerode/-/dockerode-3.3.5.tgz#7ae3f40f2bec53ae5e9a741ce655fff459745629"
+  integrity sha512-/0YNa3ZDNeLr/tSckmD69+Gq+qVNhvKfAHNeZJBnp7EOP6RGKV8ORrJHkUn20So5wU+xxT7+1n5u8PjHbfjbSA==
+  dependencies:
+    "@balena/dockerignore" "^1.0.2"
+    docker-modem "^3.0.0"
+    tar-fs "~2.0.1"
+
 doctrine@^2.1.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d"
@@ -5189,7 +5497,7 @@ dom-converter@^0.2.0:
   dependencies:
     utila "~0.4"
 
-dom-helpers@^5.0.1:
+dom-helpers@^5.0.1, dom-helpers@^5.1.3:
   version "5.2.1"
   resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.1.tgz#d9400536b2bf8225ad98fe052e029451ac40e902"
   integrity sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==
@@ -5286,10 +5594,10 @@ duplexer@^0.1.2:
   resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6"
   integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==
 
-earcut@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/earcut/-/earcut-3.0.0.tgz#a8d5bf891224eaea8287201b5e787c6c0318af89"
-  integrity sha512-41Fs7Q/PLq1SDbqjsgcY7GA42T0jvaCNGXgGtsNdvg+Yv8eIu06bxv4/PoREkZ9nMDNwnUSG9OFB9+yv8eKhDg==
+earcut@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/earcut/-/earcut-3.0.1.tgz#f60b3f671c5657cca9d3e131c5527c5dde00ef38"
+  integrity sha512-0l1/0gOjESMeQyYaK5IDiPNvFeu93Z/cO0TjZh9eZ1vyCtZnA7KMZ8rQggpsJHIbGSdrqYq9OhuveadOVHCshw==
 
 eastasianwidth@^0.2.0:
   version "0.2.0"
@@ -5317,10 +5625,10 @@ ejs@^3.1.8:
   dependencies:
     jake "^10.8.5"
 
-electron-to-chromium@^1.5.41:
-  version "1.5.72"
-  resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.72.tgz#a732805986d3a5b5fedd438ddf4616c7d78ac2df"
-  integrity sha512-ZpSAUOZ2Izby7qnZluSrAlGgGQzucmFbN0n64dYzocYxnxV5ufurpj3VgEe4cUp7ir9LmeLxNYo8bVnlM8bQHw==
+electron-to-chromium@^1.5.41, electron-to-chromium@^1.5.73:
+  version "1.5.79"
+  resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.79.tgz#4424f23f319db7a653cf9ee76102e4ac283e6b3e"
+  integrity sha512-nYOxJNxQ9Om4EC88BE4pPoNI8xwSFf8pU/BAeOl4Hh/b/i6V4biTAzwV7pXi3ARKeoYO5JZKMIXTryXSVer5RA==
 
 emittery@^0.13.1:
   version "0.13.1"
@@ -5372,6 +5680,13 @@ encodeurl@~2.0.0:
   resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58"
   integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==
 
+end-of-stream@^1.1.0, end-of-stream@^1.4.1:
+  version "1.4.4"
+  resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
+  integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==
+  dependencies:
+    once "^1.4.0"
+
 enhanced-resolve@^5.17.1:
   version "5.17.1"
   resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz#67bfbbcc2f81d511be77d686a90267ef7f898a15"
@@ -5400,7 +5715,7 @@ env-paths@^2.2.1:
   resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2"
   integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==
 
-envinfo@^7.7.3:
+envinfo@^7.14.0:
   version "7.14.0"
   resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.14.0.tgz#26dac5db54418f2a4c1159153a0b2ae980838aae"
   integrity sha512-CO40UI41xDQzhLB1hWyqUKgFhs250pNcGbyGKe1l/e4FSaI/+YE4IMG76GDt0In67WLPACIITC+sOi08x4wIvg==
@@ -5691,28 +6006,6 @@ eslint-plugin-react@^7.28.0:
     string.prototype.matchall "^4.0.11"
     string.prototype.repeat "^1.0.0"
 
-eslint-plugin-unicorn@^54.0.0:
-  version "54.0.0"
-  resolved "https://registry.yarnpkg.com/eslint-plugin-unicorn/-/eslint-plugin-unicorn-54.0.0.tgz#ce3ea853e8fd7ca2bda2fd6065bf065adb5d8b6d"
-  integrity sha512-XxYLRiYtAWiAjPv6z4JREby1TAE2byBC7wlh0V4vWDCpccOSU1KovWV//jqPXF6bq3WKxqX9rdjoRQ1EhdmNdQ==
-  dependencies:
-    "@babel/helper-validator-identifier" "^7.24.5"
-    "@eslint-community/eslint-utils" "^4.4.0"
-    "@eslint/eslintrc" "^3.0.2"
-    ci-info "^4.0.0"
-    clean-regexp "^1.0.0"
-    core-js-compat "^3.37.0"
-    esquery "^1.5.0"
-    indent-string "^4.0.0"
-    is-builtin-module "^3.2.1"
-    jsesc "^3.0.2"
-    pluralize "^8.0.0"
-    read-pkg-up "^7.0.1"
-    regexp-tree "^0.1.27"
-    regjsparser "^0.10.0"
-    semver "^7.6.1"
-    strip-indent "^3.0.0"
-
 eslint-plugin-unicorn@^56.0.0:
   version "56.0.1"
   resolved "https://registry.yarnpkg.com/eslint-plugin-unicorn/-/eslint-plugin-unicorn-56.0.1.tgz#d10a3df69ba885939075bdc95a65a0c872e940d4"
@@ -5766,11 +6059,6 @@ eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4
   resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800"
   integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==
 
-eslint-visitor-keys@^4.1.0:
-  version "4.1.0"
-  resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz#1f785cc5e81eb7534523d85922248232077d2f8c"
-  integrity sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==
-
 eslint-visitor-keys@^4.2.0:
   version "4.2.0"
   resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz#687bacb2af884fcdda8a6e7d65c606f46a14cd45"
@@ -5820,15 +6108,6 @@ eslint@8.57.1:
     strip-ansi "^6.0.1"
     text-table "^0.2.0"
 
-espree@^10.0.1:
-  version "10.2.0"
-  resolved "https://registry.yarnpkg.com/espree/-/espree-10.2.0.tgz#f4bcead9e05b0615c968e85f83816bc386a45df6"
-  integrity sha512-upbkBJbckcCNBDBDXEbuhjbP68n+scUd3k/U2EkyM9nw+I/jPiL4cLF/Al06CF96wRltFda16sxDFrxsI1v0/g==
-  dependencies:
-    acorn "^8.12.0"
-    acorn-jsx "^5.3.2"
-    eslint-visitor-keys "^4.1.0"
-
 espree@^10.3.0:
   version "10.3.0"
   resolved "https://registry.yarnpkg.com/espree/-/espree-10.3.0.tgz#29267cf5b0cb98735b65e64ba07e0ed49d1eed8a"
@@ -5852,7 +6131,7 @@ esprima@^4.0.0, esprima@^4.0.1:
   resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
   integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
 
-esquery@^1.4.2, esquery@^1.5.0, esquery@^1.6.0:
+esquery@^1.4.2, esquery@^1.6.0:
   version "1.6.0"
   resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7"
   integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==
@@ -5886,6 +6165,11 @@ etag@~1.8.1:
   resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
   integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==
 
+event-target-shim@^5.0.0:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789"
+  integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==
+
 eventemitter3@^4.0.0:
   version "4.0.7"
   resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f"
@@ -5896,7 +6180,7 @@ eventemitter3@^5.0.1:
   resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4"
   integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==
 
-events@^3.2.0:
+events@^3.2.0, events@^3.3.0:
   version "3.3.0"
   resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400"
   integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==
@@ -6006,7 +6290,12 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
   resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
   integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
 
-fast-glob@^3.2.7, fast-glob@^3.2.9, fast-glob@^3.3.2:
+fast-fifo@^1.2.0, fast-fifo@^1.3.2:
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/fast-fifo/-/fast-fifo-1.3.2.tgz#286e31de96eb96d38a97899815740ba2a4f3640c"
+  integrity sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==
+
+fast-glob@^3.2.9, fast-glob@^3.3.2:
   version "3.3.2"
   resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129"
   integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==
@@ -6270,14 +6559,10 @@ fresh@0.5.2:
   resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
   integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==
 
-fs-extra@^11.0.0:
-  version "11.2.0"
-  resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.2.0.tgz#e70e17dfad64232287d01929399e0ea7c86b0e5b"
-  integrity sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==
-  dependencies:
-    graceful-fs "^4.2.0"
-    jsonfile "^6.0.1"
-    universalify "^2.0.0"
+fs-constants@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad"
+  integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==
 
 fs.realpath@^1.0.0:
   version "1.0.0"
@@ -6374,6 +6659,11 @@ get-package-type@^0.1.0:
   resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a"
   integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==
 
+get-port@^5.1.1:
+  version "5.1.1"
+  resolved "https://registry.yarnpkg.com/get-port/-/get-port-5.1.1.tgz#0469ed07563479de6efb986baf053dcd7d4e3193"
+  integrity sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==
+
 get-stream@^6.0.0, get-stream@^6.0.1:
   version "6.0.1"
   resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7"
@@ -6422,6 +6712,18 @@ glob-to-regexp@^0.4.0, glob-to-regexp@^0.4.1:
   resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e"
   integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==
 
+glob@^10.0.0:
+  version "10.4.5"
+  resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956"
+  integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==
+  dependencies:
+    foreground-child "^3.1.0"
+    jackspeak "^3.1.2"
+    minimatch "^9.0.4"
+    minipass "^7.1.2"
+    package-json-from-dist "^1.0.0"
+    path-scurry "^1.11.1"
+
 glob@^11.0.0:
   version "11.0.0"
   resolved "https://registry.yarnpkg.com/glob/-/glob-11.0.0.tgz#6031df0d7b65eaa1ccb9b29b5ced16cea658e77e"
@@ -6493,11 +6795,6 @@ globals@^13.19.0:
   dependencies:
     type-fest "^0.20.2"
 
-globals@^14.0.0:
-  version "14.0.0"
-  resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e"
-  integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==
-
 globals@^15.9.0:
   version "15.13.0"
   resolved "https://registry.yarnpkg.com/globals/-/globals-15.13.0.tgz#bbec719d69aafef188ecd67954aae76a696010fc"
@@ -6552,7 +6849,7 @@ gopd@^1.1.0:
   dependencies:
     get-intrinsic "^1.2.4"
 
-graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.11, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9:
+graceful-fs@^4.1.2, graceful-fs@^4.2.0, graceful-fs@^4.2.11, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9:
   version "4.2.11"
   resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
   integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
@@ -6839,7 +7136,7 @@ icss-utils@^5.0.0, icss-utils@^5.1.0:
   resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae"
   integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==
 
-ieee754@^1.1.12:
+ieee754@^1.1.12, ieee754@^1.1.13, ieee754@^1.2.1:
   version "1.2.1"
   resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
   integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
@@ -6898,7 +7195,7 @@ inflight@^1.0.4:
     once "^1.3.0"
     wrappy "1"
 
-inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3:
+inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3:
   version "2.0.4"
   resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
   integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
@@ -7186,7 +7483,7 @@ is-shared-array-buffer@^1.0.2, is-shared-array-buffer@^1.0.3:
   dependencies:
     call-bind "^1.0.7"
 
-is-stream@^2.0.0:
+is-stream@^2.0.0, is-stream@^2.0.1:
   version "2.0.1"
   resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077"
   integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==
@@ -7339,6 +7636,15 @@ iterator.prototype@^1.1.3:
     reflect.getprototypeof "^1.0.4"
     set-function-name "^2.0.1"
 
+jackspeak@^3.1.2:
+  version "3.4.3"
+  resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a"
+  integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==
+  dependencies:
+    "@isaacs/cliui" "^8.0.2"
+  optionalDependencies:
+    "@pkgjs/parseargs" "^0.11.0"
+
 jackspeak@^4.0.1:
   version "4.0.2"
   resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-4.0.2.tgz#11f9468a3730c6ff6f56823a820d7e3be9bef015"
@@ -7869,20 +8175,11 @@ json5@^1.0.2:
   dependencies:
     minimist "^1.2.0"
 
-json5@^2.1.2, json5@^2.1.3, json5@^2.2.3:
+json5@^2.1.2, json5@^2.2.3:
   version "2.2.3"
   resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283"
   integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==
 
-jsonfile@^6.0.1:
-  version "6.1.0"
-  resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae"
-  integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==
-  dependencies:
-    universalify "^2.0.0"
-  optionalDependencies:
-    graceful-fs "^4.1.6"
-
 jsqr@^1.4.0:
   version "1.4.0"
   resolved "https://registry.yarnpkg.com/jsqr/-/jsqr-1.4.0.tgz#8efb8d0a7cc6863cb6d95116b9069123ce9eb2d1"
@@ -7999,6 +8296,13 @@ launch-editor@^2.6.1:
     picocolors "^1.0.0"
     shell-quote "^1.8.1"
 
+lazystream@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.1.tgz#494c831062f1f9408251ec44db1cba29242a2638"
+  integrity sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==
+  dependencies:
+    readable-stream "^2.0.5"
+
 leven@^3.1.0:
   version "3.1.0"
   resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2"
@@ -8154,7 +8458,7 @@ lodash.uniq@^4.5.0:
   resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
   integrity sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==
 
-lodash@^4.17.20, lodash@^4.17.21:
+lodash@^4.17.15, lodash@^4.17.20, lodash@^4.17.21:
   version "4.17.21"
   resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
   integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
@@ -8249,10 +8553,10 @@ makeerror@1.0.12:
   dependencies:
     tmpl "1.0.5"
 
-maplibre-gl@^4.0.0:
-  version "4.7.1"
-  resolved "https://registry.yarnpkg.com/maplibre-gl/-/maplibre-gl-4.7.1.tgz#06a524438ee2aafbe8bcd91002a4e01468ea5486"
-  integrity sha512-lgL7XpIwsgICiL82ITplfS7IGwrB1OJIw/pCvprDp2dhmSSEBgmPzYRvwYYYvJGJD7fxUv1Tvpih4nZ6VrLuaA==
+maplibre-gl@^5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/maplibre-gl/-/maplibre-gl-5.0.0.tgz#d9120b6ced7df5d1c791497f25bbe4edd5039d96"
+  integrity sha512-WG8IYFK2gfJYXvWjlqg1yavo/YO/JlNkblAJMt19sjIafP5oJzTgXFiOLUIYkjtrv5pKiAWuSYsx4CD3ithJqw==
   dependencies:
     "@mapbox/geojson-rewind" "^0.5.2"
     "@mapbox/jsonlint-lines-primitives" "^2.0.2"
@@ -8261,14 +8565,14 @@ maplibre-gl@^4.0.0:
     "@mapbox/unitbezier" "^0.0.1"
     "@mapbox/vector-tile" "^1.3.1"
     "@mapbox/whoots-js" "^3.1.0"
-    "@maplibre/maplibre-gl-style-spec" "^20.3.1"
-    "@types/geojson" "^7946.0.14"
+    "@maplibre/maplibre-gl-style-spec" "^22.0.1"
+    "@types/geojson" "^7946.0.15"
     "@types/geojson-vt" "3.2.5"
     "@types/mapbox__point-geometry" "^0.1.4"
     "@types/mapbox__vector-tile" "^1.3.4"
     "@types/pbf" "^3.0.5"
     "@types/supercluster" "^7.1.3"
-    earcut "^3.0.0"
+    earcut "^3.0.1"
     geojson-vt "^4.0.2"
     gl-matrix "^3.4.3"
     global-prefix "^4.0.0"
@@ -8308,11 +8612,11 @@ matrix-events-sdk@0.0.1:
   integrity sha512-1QEOsXO+bhyCroIe2/A5OwaxHvBm7EsSQ46DEDn8RBIfQwN5HWBpFvyWWR4QY0KHPPnnJdI99wgRiAl7Ad5qaA==
 
 "matrix-js-sdk@github:matrix-org/matrix-js-sdk#develop":
-  version "35.0.0"
-  resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/349a86c119e6ac53d8d0677f6b6db5944c3ddcd1"
+  version "36.0.0"
+  resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/07f97d724f755a131571511af6662d4e3b345728"
   dependencies:
     "@babel/runtime" "^7.12.5"
-    "@matrix-org/matrix-sdk-crypto-wasm" "^12.0.0"
+    "@matrix-org/matrix-sdk-crypto-wasm" "^12.1.0"
     "@matrix-org/olm" "3.2.15"
     another-json "^0.2.0"
     bs58 "^6.0.0"
@@ -8471,10 +8775,10 @@ min-indent@^1.0.0:
   resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869"
   integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==
 
-mini-css-extract-plugin@2.9.0:
-  version "2.9.0"
-  resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.9.0.tgz#c73a1327ccf466f69026ac22a8e8fd707b78a235"
-  integrity sha512-Zs1YsZVfemekSZG+44vBsYTLQORkPMwnlv+aehcxK/NLKC+EGhDB39/YePYYqx/sTk6NnYpuqikhSn7+JIevTA==
+mini-css-extract-plugin@2.9.2:
+  version "2.9.2"
+  resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.9.2.tgz#966031b468917a5446f4c24a80854b2947503c5b"
+  integrity sha512-GJuACcS//jtq4kCtd5ii/M0SZf7OZRH+BxdqXZHaJfb8TJiVl+NgQRPwiYt2EuqeSkNydn/7vP+bcE27C5mb9w==
   dependencies:
     schema-utils "^4.0.0"
     tapable "^2.2.1"
@@ -8498,7 +8802,7 @@ minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2:
   dependencies:
     brace-expansion "^1.1.7"
 
-minimatch@^5.0.1:
+minimatch@^5.0.1, minimatch@^5.1.0:
   version "5.1.6"
   resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96"
   integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==
@@ -8534,6 +8838,11 @@ minipass@^4.2.4:
   resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707"
   integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==
 
+mkdirp-classic@^0.5.2:
+  version "0.5.3"
+  resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113"
+  integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==
+
 mkdirp@0.5.6:
   version "0.5.6"
   resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6"
@@ -8594,10 +8903,15 @@ murmurhash-js@^1.0.0:
   resolved "https://registry.yarnpkg.com/murmurhash-js/-/murmurhash-js-1.0.0.tgz#b06278e21fc6c37fa5313732b0412bcb6ae15f51"
   integrity sha512-TvmkNhkv8yct0SVBSy+o8wYzXjE4Zz3PCesbfs8HiCXXdcTuocApFv11UWlNFWKYsP2okqrhb7JNlSm9InBhIw==
 
+nan@^2.19.0, nan@^2.20.0:
+  version "2.22.0"
+  resolved "https://registry.yarnpkg.com/nan/-/nan-2.22.0.tgz#31bc433fc33213c97bad36404bb68063de604de3"
+  integrity sha512-nbajikzWTMwsW+eSsNm3QwlOs7het9gGJU5dDZzRTQGk03vyBOauxgI4VakDzE0PtsGTmXPsXTbbjVhRwR5mpw==
+
 nanoid@^3.3.7:
-  version "3.3.7"
-  resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8"
-  integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==
+  version "3.3.8"
+  resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.8.tgz#b1be3030bee36aaff18bacb375e5cce521684baf"
+  integrity sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==
 
 natural-compare@^1.4.0:
   version "1.4.0"
@@ -8639,7 +8953,7 @@ node-int64@^0.4.0:
   resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b"
   integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==
 
-node-releases@^2.0.18:
+node-releases@^2.0.18, node-releases@^2.0.19:
   version "2.0.19"
   resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.19.tgz#9e445a52950951ec4d177d843af370b411caf314"
   integrity sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==
@@ -8776,7 +9090,7 @@ on-headers@~1.0.2:
   resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f"
   integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==
 
-once@^1.3.0:
+once@^1.3.0, once@^1.3.1, once@^1.4.0:
   version "1.4.0"
   resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
   integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==
@@ -8977,11 +9291,6 @@ pascal-case@^3.1.2:
     no-case "^3.0.4"
     tslib "^2.0.3"
 
-path-browserify@^1.0.1:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd"
-  integrity sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==
-
 path-exists@^4.0.0:
   version "4.0.0"
   resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
@@ -9012,7 +9321,7 @@ path-parse@^1.0.7:
   resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
   integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
 
-path-scurry@^1.6.1:
+path-scurry@^1.11.1, path-scurry@^1.6.1:
   version "1.11.1"
   resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2"
   integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==
@@ -9056,7 +9365,7 @@ pbf@^3.2.1, pbf@^3.3.0:
     ieee754 "^1.1.12"
     resolve-protobuf-schema "^2.1.0"
 
-picocolors@^1.0.0, picocolors@^1.0.1, picocolors@^1.1.0:
+picocolors@^1.0.0, picocolors@^1.0.1, picocolors@^1.1.0, picocolors@^1.1.1:
   version "1.1.1"
   resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b"
   integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==
@@ -9100,17 +9409,17 @@ pkg-dir@^7.0.0:
   dependencies:
     find-up "^6.3.0"
 
-playwright-core@1.49.0, playwright-core@^1.45.1:
-  version "1.49.0"
-  resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.49.0.tgz#8e69ffed3f41855b854982f3632f2922c890afcb"
-  integrity sha512-R+3KKTQF3npy5GTiKH/T+kdhoJfJojjHESR1YEWhYuEKRVfVaxH3+4+GvXE5xyCngCxhxnykk0Vlah9v8fs3jA==
+playwright-core@1.49.1, playwright-core@^1.45.1:
+  version "1.49.1"
+  resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.49.1.tgz#32c62f046e950f586ff9e35ed490a424f2248015"
+  integrity sha512-BzmpVcs4kE2CH15rWfzpjzVGhWERJfmnXmniSyKeRZUs9Ws65m+RGIi7mjJK/euCegfn3i7jvqWeWyHe9y3Vgg==
 
-playwright@1.49.0:
-  version "1.49.0"
-  resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.49.0.tgz#df6b9e05423377a99658202844a294a8afb95d0a"
-  integrity sha512-eKpmys0UFDnfNb3vfsf8Vx2LEOtflgRebl0Im2eQQnYMA4Aqd+Zw8bEOB+7ZKvN76901mRnqdsiOGKxzVTbi7A==
+playwright@1.49.1:
+  version "1.49.1"
+  resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.49.1.tgz#830266dbca3008022afa7b4783565db9944ded7c"
+  integrity sha512-VYL8zLoNTBxVOrJBbDuRgDWa3i+mfQgDTrL8Ah9QXZ7ax4Dsj0MSq5bYgytRnDVVe+njoKnfsYkH3HzqVj5UZA==
   dependencies:
-    playwright-core "1.49.0"
+    playwright-core "1.49.1"
   optionalDependencies:
     fsevents "2.3.2"
 
@@ -9141,12 +9450,12 @@ possible-typed-array-names@^1.0.0:
   resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f"
   integrity sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==
 
-postcss-attribute-case-insensitive@^7.0.0:
-  version "7.0.0"
-  resolved "https://registry.yarnpkg.com/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-7.0.0.tgz#500034cdea39836a406626ce0f83686f2af52ffa"
-  integrity sha512-ETMUHIw67Kyv9Q81nden/NuJbRh+4/S963giXpfSLd5eaKK8kd1UdAHMVRV/NG/w/N6Cq8B0qZIZbZZWU/67+A==
+postcss-attribute-case-insensitive@^7.0.1:
+  version "7.0.1"
+  resolved "https://registry.yarnpkg.com/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-7.0.1.tgz#0c4500e3bcb2141848e89382c05b5a31c23033a3"
+  integrity sha512-Uai+SupNSqzlschRyNx3kbCTWgY/2hcwtHEI/ej2LJWc9JJ77qKgGptd8DHwY1mXtZ7Aoh4z4yxfwMBue9eNgw==
   dependencies:
-    postcss-selector-parser "^6.1.0"
+    postcss-selector-parser "^7.0.0"
 
 postcss-calc@^10.0.2:
   version "10.0.2"
@@ -9163,14 +9472,14 @@ postcss-clamp@^4.1.0:
   dependencies:
     postcss-value-parser "^4.2.0"
 
-postcss-color-functional-notation@^7.0.3:
-  version "7.0.3"
-  resolved "https://registry.yarnpkg.com/postcss-color-functional-notation/-/postcss-color-functional-notation-7.0.3.tgz#34ce769426dcc3fb06a0160ff7173ed3acf9b41d"
-  integrity sha512-mL3LVOwXr5sRX1N5so7AFCNciaYTNTxzXuv5bDoZ/JunV2NCAzGOuVfyICRKczDPFImoIuL4e0O33/zYap9D0w==
+postcss-color-functional-notation@^7.0.7:
+  version "7.0.7"
+  resolved "https://registry.yarnpkg.com/postcss-color-functional-notation/-/postcss-color-functional-notation-7.0.7.tgz#c5362df010926f902ce4e7fb3da2a46cff175d1b"
+  integrity sha512-EZvAHsvyASX63vXnyXOIynkxhaHRSsdb7z6yiXKIovGXAolW4cMZ3qoh7k3VdTsLBS6VGdksGfIo3r6+waLoOw==
   dependencies:
-    "@csstools/css-color-parser" "^3.0.3"
-    "@csstools/css-parser-algorithms" "^3.0.2"
-    "@csstools/css-tokenizer" "^3.0.2"
+    "@csstools/css-color-parser" "^3.0.7"
+    "@csstools/css-parser-algorithms" "^3.0.4"
+    "@csstools/css-tokenizer" "^3.0.3"
     "@csstools/postcss-progressive-custom-properties" "^4.0.0"
     "@csstools/utilities" "^2.0.0"
 
@@ -9208,43 +9517,43 @@ postcss-convert-values@^7.0.4:
     browserslist "^4.23.3"
     postcss-value-parser "^4.2.0"
 
-postcss-custom-media@^11.0.3:
-  version "11.0.3"
-  resolved "https://registry.yarnpkg.com/postcss-custom-media/-/postcss-custom-media-11.0.3.tgz#3c25c0d10870ea6d6afb17ff8ea636d089544ed4"
-  integrity sha512-h52R7j0/QZP7NgnpsUaqx6wdssplK4U+ZuErvic2StgvXt3v5sPopFH86yjLvqz3jBrj/8Hkvr7Gio1LLRFP0g==
+postcss-custom-media@^11.0.5:
+  version "11.0.5"
+  resolved "https://registry.yarnpkg.com/postcss-custom-media/-/postcss-custom-media-11.0.5.tgz#2fcd88a9b1d4da41c67dac6f2def903063a3377d"
+  integrity sha512-SQHhayVNgDvSAdX9NQ/ygcDQGEY+aSF4b/96z7QUX6mqL5yl/JgG/DywcF6fW9XbnCRE+aVYk+9/nqGuzOPWeQ==
   dependencies:
-    "@csstools/cascade-layer-name-parser" "^2.0.2"
-    "@csstools/css-parser-algorithms" "^3.0.2"
-    "@csstools/css-tokenizer" "^3.0.2"
-    "@csstools/media-query-list-parser" "^4.0.0"
+    "@csstools/cascade-layer-name-parser" "^2.0.4"
+    "@csstools/css-parser-algorithms" "^3.0.4"
+    "@csstools/css-tokenizer" "^3.0.3"
+    "@csstools/media-query-list-parser" "^4.0.2"
 
-postcss-custom-properties@^14.0.2:
-  version "14.0.2"
-  resolved "https://registry.yarnpkg.com/postcss-custom-properties/-/postcss-custom-properties-14.0.2.tgz#e9092ee55ce78f37bbfce5aab28b1772374ebd66"
-  integrity sha512-ZDJLIXa6uT6FlK6mYdzHxr1fr5ec6lPbp/CZ5+7EZedFmfjJx1fvYQhAPCBebuyc1lkketmiA26ZVl2UkPQ9Ig==
+postcss-custom-properties@^14.0.4:
+  version "14.0.4"
+  resolved "https://registry.yarnpkg.com/postcss-custom-properties/-/postcss-custom-properties-14.0.4.tgz#de9c663285a98833a946d7003a34369d3ce373a9"
+  integrity sha512-QnW8FCCK6q+4ierwjnmXF9Y9KF8q0JkbgVfvQEMa93x1GT8FvOiUevWCN2YLaOWyByeDX8S6VFbZEeWoAoXs2A==
   dependencies:
-    "@csstools/cascade-layer-name-parser" "^2.0.2"
-    "@csstools/css-parser-algorithms" "^3.0.2"
-    "@csstools/css-tokenizer" "^3.0.2"
+    "@csstools/cascade-layer-name-parser" "^2.0.4"
+    "@csstools/css-parser-algorithms" "^3.0.4"
+    "@csstools/css-tokenizer" "^3.0.3"
     "@csstools/utilities" "^2.0.0"
     postcss-value-parser "^4.2.0"
 
-postcss-custom-selectors@^8.0.2:
-  version "8.0.2"
-  resolved "https://registry.yarnpkg.com/postcss-custom-selectors/-/postcss-custom-selectors-8.0.2.tgz#d330f078df748ff3709e98128adb8aec2dbb7457"
-  integrity sha512-8y2fa+RgYHpVFtvR4h3/dHc7b0iWjT6GOpzWwB8VHJTEBdVNaqOB4FH9koa44hgRyaeDs3KTe3xP9EJf6NLvxQ==
+postcss-custom-selectors@^8.0.4:
+  version "8.0.4"
+  resolved "https://registry.yarnpkg.com/postcss-custom-selectors/-/postcss-custom-selectors-8.0.4.tgz#95ef8268fdbbbd84f34cf84a4517c9d99d419c5a"
+  integrity sha512-ASOXqNvDCE0dAJ/5qixxPeL1aOVGHGW2JwSy7HyjWNbnWTQCl+fDc968HY1jCmZI0+BaYT5CxsOiUhavpG/7eg==
   dependencies:
-    "@csstools/cascade-layer-name-parser" "^2.0.2"
-    "@csstools/css-parser-algorithms" "^3.0.2"
-    "@csstools/css-tokenizer" "^3.0.2"
-    postcss-selector-parser "^6.1.0"
+    "@csstools/cascade-layer-name-parser" "^2.0.4"
+    "@csstools/css-parser-algorithms" "^3.0.4"
+    "@csstools/css-tokenizer" "^3.0.3"
+    postcss-selector-parser "^7.0.0"
 
-postcss-dir-pseudo-class@^9.0.0:
-  version "9.0.0"
-  resolved "https://registry.yarnpkg.com/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-9.0.0.tgz#44e2bc44e32d05a8a92723cb7d7e23da493b6859"
-  integrity sha512-T59BG9lURiXmhcJMyKbyjNAK3KCyEQYEhaz9GAETHXfIy9XbGQeyz+H0zIwRJlrP4KKRPJolNYe3QjQPemMjBA==
+postcss-dir-pseudo-class@^9.0.1:
+  version "9.0.1"
+  resolved "https://registry.yarnpkg.com/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-9.0.1.tgz#80d9e842c9ae9d29f6bf5fd3cf9972891d6cc0ca"
+  integrity sha512-tRBEK0MHYvcMUrAuYMEOa0zg9APqirBcgzi6P21OhxtJyJADo/SWBwY1CAwEohQ/6HDaa9jCjLRG7K3PVQYHEA==
   dependencies:
-    postcss-selector-parser "^6.1.0"
+    postcss-selector-parser "^7.0.0"
 
 postcss-discard-comments@^7.0.3:
   version "7.0.3"
@@ -9284,19 +9593,19 @@ postcss-easings@^4.0.0:
   dependencies:
     postcss-value-parser "^4.2.0"
 
-postcss-focus-visible@^10.0.0:
-  version "10.0.0"
-  resolved "https://registry.yarnpkg.com/postcss-focus-visible/-/postcss-focus-visible-10.0.0.tgz#54435d9bba825165377cae4eef2a8028440d344c"
-  integrity sha512-GJjzvTj7JY+zN7wVBQ4osdKX53QLUdr6r2rSEkBUqrEMDKu3fHMHKOY9rirdirbHCx3IETnK25EtpPARR2KWNw==
+postcss-focus-visible@^10.0.1:
+  version "10.0.1"
+  resolved "https://registry.yarnpkg.com/postcss-focus-visible/-/postcss-focus-visible-10.0.1.tgz#1f7904904368a2d1180b220595d77b6f8a957868"
+  integrity sha512-U58wyjS/I1GZgjRok33aE8juW9qQgQUNwTSdxQGuShHzwuYdcklnvK/+qOWX1Q9kr7ysbraQ6ht6r+udansalA==
   dependencies:
-    postcss-selector-parser "^6.1.0"
+    postcss-selector-parser "^7.0.0"
 
-postcss-focus-within@^9.0.0:
-  version "9.0.0"
-  resolved "https://registry.yarnpkg.com/postcss-focus-within/-/postcss-focus-within-9.0.0.tgz#cb281d1c700178bf21b9ae2f4f3a515f53b959b2"
-  integrity sha512-QwflAWUToNZvQLGbc4qJhrQO8yZ5617L6hSNzNWDoqRX4FoIh9fbJbEjy0nvFPciaaOoCaeqcxBwYPbFU0HvBw==
+postcss-focus-within@^9.0.1:
+  version "9.0.1"
+  resolved "https://registry.yarnpkg.com/postcss-focus-within/-/postcss-focus-within-9.0.1.tgz#ac01ce80d3f2e8b2b3eac4ff84f8e15cd0057bc7"
+  integrity sha512-fzNUyS1yOYa7mOjpci/bR+u+ESvdar6hk8XNK/TRR0fiGTp2QT5N+ducP0n3rfH/m9I7H/EQU6lsa2BrgxkEjw==
   dependencies:
-    postcss-selector-parser "^6.1.0"
+    postcss-selector-parser "^7.0.0"
 
 postcss-font-variant@^5.0.0:
   version "5.0.0"
@@ -9339,14 +9648,14 @@ postcss-js@^4.0.1:
   dependencies:
     camelcase-css "^2.0.1"
 
-postcss-lab-function@^7.0.3:
-  version "7.0.3"
-  resolved "https://registry.yarnpkg.com/postcss-lab-function/-/postcss-lab-function-7.0.3.tgz#ce08b33388ba809c3f75ba2986dfe670841dbb24"
-  integrity sha512-yCBscY/dwipfvqqy7rQHbn6k18zYZy9O57JY4fGuibot6wz7pbtzRnhRlWraHBNUs+N4p2KogHv2aBsoB6G+5Q==
+postcss-lab-function@^7.0.7:
+  version "7.0.7"
+  resolved "https://registry.yarnpkg.com/postcss-lab-function/-/postcss-lab-function-7.0.7.tgz#9c87c21ce5132c55824190b75d7d7adede9c2fac"
+  integrity sha512-+ONj2bpOQfsCKZE2T9VGMyVVdGcGUpr7u3SVfvkJlvhTRmDCfY25k4Jc8fubB9DclAPR4+w8uVtDZmdRgdAHig==
   dependencies:
-    "@csstools/css-color-parser" "^3.0.3"
-    "@csstools/css-parser-algorithms" "^3.0.2"
-    "@csstools/css-tokenizer" "^3.0.2"
+    "@csstools/css-color-parser" "^3.0.7"
+    "@csstools/css-parser-algorithms" "^3.0.4"
+    "@csstools/css-tokenizer" "^3.0.3"
     "@csstools/postcss-progressive-custom-properties" "^4.0.0"
     "@csstools/utilities" "^2.0.0"
 
@@ -9467,14 +9776,14 @@ postcss-nested@^7.0.0:
   dependencies:
     postcss-selector-parser "^7.0.0"
 
-postcss-nesting@^13.0.0:
-  version "13.0.0"
-  resolved "https://registry.yarnpkg.com/postcss-nesting/-/postcss-nesting-13.0.0.tgz#4393158faa33f56674167b3556981c9216892ab2"
-  integrity sha512-TCGQOizyqvEkdeTPM+t6NYwJ3EJszYE/8t8ILxw/YoeUvz2rz7aM8XTAmBWh9/DJjfaaabL88fWrsVHSPF2zgA==
+postcss-nesting@^13.0.1:
+  version "13.0.1"
+  resolved "https://registry.yarnpkg.com/postcss-nesting/-/postcss-nesting-13.0.1.tgz#c405796d7245a3e4c267a9956cacfe9670b5d43e"
+  integrity sha512-VbqqHkOBOt4Uu3G8Dm8n6lU5+9cJFxiuty9+4rcoyRPO9zZS1JIs6td49VIoix3qYqELHlJIn46Oih9SAKo+yQ==
   dependencies:
-    "@csstools/selector-resolve-nested" "^2.0.0"
-    "@csstools/selector-specificity" "^4.0.0"
-    postcss-selector-parser "^6.1.0"
+    "@csstools/selector-resolve-nested" "^3.0.0"
+    "@csstools/selector-specificity" "^5.0.0"
+    postcss-selector-parser "^7.0.0"
 
 postcss-normalize-charset@^7.0.0:
   version "7.0.0"
@@ -9571,78 +9880,80 @@ postcss-place@^10.0.0:
     postcss-value-parser "^4.2.0"
 
 postcss-preset-env@^10.0.0:
-  version "10.0.7"
-  resolved "https://registry.yarnpkg.com/postcss-preset-env/-/postcss-preset-env-10.0.7.tgz#ba7600e3ac299b15f3596dd8ac61dbb89ad71bba"
-  integrity sha512-aUC/bMT2CULwaZ/RK1Ivzdsyv95DQCJs0dK98RTc9cZKUYIal1+85JdNwik0DXg35BKdRZM2ZwASU17PXoglsw==
-  dependencies:
-    "@csstools/postcss-cascade-layers" "^5.0.0"
-    "@csstools/postcss-color-function" "^4.0.3"
-    "@csstools/postcss-color-mix-function" "^3.0.3"
-    "@csstools/postcss-content-alt-text" "^2.0.2"
-    "@csstools/postcss-exponential-functions" "^2.0.2"
+  version "10.1.3"
+  resolved "https://registry.yarnpkg.com/postcss-preset-env/-/postcss-preset-env-10.1.3.tgz#7d07adef2237a643162e751b00eb1e339aa3b82e"
+  integrity sha512-9qzVhcMFU/MnwYHyYpJz4JhGku/4+xEiPTmhn0hj3IxnUYlEF9vbh7OC1KoLAnenS6Fgg43TKNp9xcuMeAi4Zw==
+  dependencies:
+    "@csstools/postcss-cascade-layers" "^5.0.1"
+    "@csstools/postcss-color-function" "^4.0.7"
+    "@csstools/postcss-color-mix-function" "^3.0.7"
+    "@csstools/postcss-content-alt-text" "^2.0.4"
+    "@csstools/postcss-exponential-functions" "^2.0.6"
     "@csstools/postcss-font-format-keywords" "^4.0.0"
-    "@csstools/postcss-gamut-mapping" "^2.0.3"
-    "@csstools/postcss-gradients-interpolation-method" "^5.0.3"
-    "@csstools/postcss-hwb-function" "^4.0.3"
+    "@csstools/postcss-gamut-mapping" "^2.0.7"
+    "@csstools/postcss-gradients-interpolation-method" "^5.0.7"
+    "@csstools/postcss-hwb-function" "^4.0.7"
     "@csstools/postcss-ic-unit" "^4.0.0"
     "@csstools/postcss-initial" "^2.0.0"
-    "@csstools/postcss-is-pseudo-class" "^5.0.0"
-    "@csstools/postcss-light-dark-function" "^2.0.5"
+    "@csstools/postcss-is-pseudo-class" "^5.0.1"
+    "@csstools/postcss-light-dark-function" "^2.0.7"
     "@csstools/postcss-logical-float-and-clear" "^3.0.0"
     "@csstools/postcss-logical-overflow" "^2.0.0"
     "@csstools/postcss-logical-overscroll-behavior" "^2.0.0"
     "@csstools/postcss-logical-resize" "^3.0.0"
-    "@csstools/postcss-logical-viewport-units" "^3.0.2"
-    "@csstools/postcss-media-minmax" "^2.0.2"
-    "@csstools/postcss-media-queries-aspect-ratio-number-values" "^3.0.2"
+    "@csstools/postcss-logical-viewport-units" "^3.0.3"
+    "@csstools/postcss-media-minmax" "^2.0.6"
+    "@csstools/postcss-media-queries-aspect-ratio-number-values" "^3.0.4"
     "@csstools/postcss-nested-calc" "^4.0.0"
     "@csstools/postcss-normalize-display-values" "^4.0.0"
-    "@csstools/postcss-oklab-function" "^4.0.3"
+    "@csstools/postcss-oklab-function" "^4.0.7"
     "@csstools/postcss-progressive-custom-properties" "^4.0.0"
-    "@csstools/postcss-relative-color-syntax" "^3.0.3"
-    "@csstools/postcss-scope-pseudo-class" "^4.0.0"
-    "@csstools/postcss-stepped-value-functions" "^4.0.2"
+    "@csstools/postcss-random-function" "^1.0.2"
+    "@csstools/postcss-relative-color-syntax" "^3.0.7"
+    "@csstools/postcss-scope-pseudo-class" "^4.0.1"
+    "@csstools/postcss-sign-functions" "^1.1.1"
+    "@csstools/postcss-stepped-value-functions" "^4.0.6"
     "@csstools/postcss-text-decoration-shorthand" "^4.0.1"
-    "@csstools/postcss-trigonometric-functions" "^4.0.2"
+    "@csstools/postcss-trigonometric-functions" "^4.0.6"
     "@csstools/postcss-unset-value" "^4.0.0"
     autoprefixer "^10.4.19"
     browserslist "^4.23.1"
-    css-blank-pseudo "^7.0.0"
-    css-has-pseudo "^7.0.0"
+    css-blank-pseudo "^7.0.1"
+    css-has-pseudo "^7.0.2"
     css-prefers-color-scheme "^10.0.0"
-    cssdb "^8.1.1"
-    postcss-attribute-case-insensitive "^7.0.0"
+    cssdb "^8.2.3"
+    postcss-attribute-case-insensitive "^7.0.1"
     postcss-clamp "^4.1.0"
-    postcss-color-functional-notation "^7.0.3"
+    postcss-color-functional-notation "^7.0.7"
     postcss-color-hex-alpha "^10.0.0"
     postcss-color-rebeccapurple "^10.0.0"
-    postcss-custom-media "^11.0.3"
-    postcss-custom-properties "^14.0.2"
-    postcss-custom-selectors "^8.0.2"
-    postcss-dir-pseudo-class "^9.0.0"
+    postcss-custom-media "^11.0.5"
+    postcss-custom-properties "^14.0.4"
+    postcss-custom-selectors "^8.0.4"
+    postcss-dir-pseudo-class "^9.0.1"
     postcss-double-position-gradients "^6.0.0"
-    postcss-focus-visible "^10.0.0"
-    postcss-focus-within "^9.0.0"
+    postcss-focus-visible "^10.0.1"
+    postcss-focus-within "^9.0.1"
     postcss-font-variant "^5.0.0"
     postcss-gap-properties "^6.0.0"
     postcss-image-set-function "^7.0.0"
-    postcss-lab-function "^7.0.3"
+    postcss-lab-function "^7.0.7"
     postcss-logical "^8.0.0"
-    postcss-nesting "^13.0.0"
+    postcss-nesting "^13.0.1"
     postcss-opacity-percentage "^3.0.0"
     postcss-overflow-shorthand "^6.0.0"
     postcss-page-break "^3.0.4"
     postcss-place "^10.0.0"
-    postcss-pseudo-class-any-link "^10.0.0"
+    postcss-pseudo-class-any-link "^10.0.1"
     postcss-replace-overflow-wrap "^4.0.0"
-    postcss-selector-not "^8.0.0"
+    postcss-selector-not "^8.0.1"
 
-postcss-pseudo-class-any-link@^10.0.0:
-  version "10.0.0"
-  resolved "https://registry.yarnpkg.com/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-10.0.0.tgz#ca8a1392c0ae207ccfa44f4de84984bf7cfdf93a"
-  integrity sha512-bde8VE08Gq3ekKDq2BQ0ESOjNX54lrFDK3U9zABPINaqHblbZL/4Wfo5Y2vk6U64yVd/sjDwTzuiisFBpGNNIQ==
+postcss-pseudo-class-any-link@^10.0.1:
+  version "10.0.1"
+  resolved "https://registry.yarnpkg.com/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-10.0.1.tgz#06455431171bf44b84d79ebaeee9fd1c05946544"
+  integrity sha512-3el9rXlBOqTFaMFkWDOkHUTQekFIYnaQY55Rsp8As8QQkpiSgIYEcF/6Ond93oHiDsGb4kad8zjt+NPlOC1H0Q==
   dependencies:
-    postcss-selector-parser "^6.1.0"
+    postcss-selector-parser "^7.0.0"
 
 postcss-reduce-initial@^7.0.2:
   version "7.0.2"
@@ -9679,14 +9990,14 @@ postcss-scss@^4.0.4:
   resolved "https://registry.yarnpkg.com/postcss-scss/-/postcss-scss-4.0.9.tgz#a03c773cd4c9623cb04ce142a52afcec74806685"
   integrity sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A==
 
-postcss-selector-not@^8.0.0:
-  version "8.0.0"
-  resolved "https://registry.yarnpkg.com/postcss-selector-not/-/postcss-selector-not-8.0.0.tgz#370e76ec27d417d944be966e924656a1ce624e49"
-  integrity sha512-g/juh7A83GWc3+kWL8BiS3YUIJb3XNqIVKz1kGvgN3OhoGCsPncy1qo/+q61tjy5r87OxBhSY1+hcH3yOhEW+g==
+postcss-selector-not@^8.0.1:
+  version "8.0.1"
+  resolved "https://registry.yarnpkg.com/postcss-selector-not/-/postcss-selector-not-8.0.1.tgz#f2df9c6ac9f95e9fe4416ca41a957eda16130172"
+  integrity sha512-kmVy/5PYVb2UOhy0+LqUYAhKj7DUGDpSWa5LZqlkWJaaAV+dxxsOG3+St0yNLu6vsKD7Dmqx+nWQt0iil89+WA==
   dependencies:
-    postcss-selector-parser "^6.1.0"
+    postcss-selector-parser "^7.0.0"
 
-postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.1.0, postcss-selector-parser@^6.1.2:
+postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.1.2:
   version "6.1.2"
   resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz#27ecb41fb0e3b6ba7a1ec84fff347f734c7929de"
   integrity sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==
@@ -9727,14 +10038,14 @@ postcss-value-parser@^4.0.0, postcss-value-parser@^4.1.0, postcss-value-parser@^
   resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
   integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
 
-postcss@8.4.38:
-  version "8.4.38"
-  resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.38.tgz#b387d533baf2054288e337066d81c6bee9db9e0e"
-  integrity sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==
+postcss@8.4.46:
+  version "8.4.46"
+  resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.46.tgz#d526f2126b6ace463e9b3c1cbdad040fb040ea22"
+  integrity sha512-73x4XLhY0QNN+87/u6F7TRq+yl3xPAjlbRRvhly1mAKJgNO4q5fiqegez/Yi3u+ez8wbBXXqY9N1+RAJAVCzEw==
   dependencies:
     nanoid "^3.3.7"
-    picocolors "^1.0.0"
-    source-map-js "^1.2.0"
+    picocolors "^1.1.0"
+    source-map-js "^1.2.1"
 
 postcss@^8.3.11, postcss@^8.4.33, postcss@^8.4.38, postcss@^8.4.47:
   version "8.4.47"
@@ -9774,6 +10085,11 @@ prettier@3.4.2:
   resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.4.2.tgz#a5ce1fb522a588bf2b78ca44c6e6fe5aa5a2b13f"
   integrity sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==
 
+prettier@^2.6.2:
+  version "2.8.8"
+  resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da"
+  integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==
+
 pretty-error@^4.0.0:
   version "4.0.0"
   resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-4.0.0.tgz#90a703f46dd7234adb46d0f84823e9d1cb8f10d6"
@@ -9839,6 +10155,22 @@ prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1:
     object-assign "^4.1.1"
     react-is "^16.13.1"
 
+proper-lockfile@^4.1.2:
+  version "4.1.2"
+  resolved "https://registry.yarnpkg.com/proper-lockfile/-/proper-lockfile-4.1.2.tgz#c8b9de2af6b2f1601067f98e01ac66baa223141f"
+  integrity sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==
+  dependencies:
+    graceful-fs "^4.2.4"
+    retry "^0.12.0"
+    signal-exit "^3.0.2"
+
+properties-reader@^2.3.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/properties-reader/-/properties-reader-2.3.0.tgz#f3ab84224c9535a7a36e011ae489a79a13b472b2"
+  integrity sha512-z597WicA7nDZxK12kZqHr2TcvwNU1GCfA5UwfDY/HDp3hXPoPlb5rlEx9bwGTiJnc0OqbBTkU975jDToth8Gxw==
+  dependencies:
+    mkdirp "^1.0.4"
+
 protocol-buffers-schema@^3.3.1:
   version "3.6.0"
   resolved "https://registry.yarnpkg.com/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz#77bc75a48b2ff142c1ad5b5b90c94cd0fa2efd03"
@@ -9862,6 +10194,14 @@ psl@^1.1.33:
   resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7"
   integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==
 
+pump@^3.0.0:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.2.tgz#836f3edd6bc2ee599256c924ffe0d88573ddcbf8"
+  integrity sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==
+  dependencies:
+    end-of-stream "^1.1.0"
+    once "^1.3.1"
+
 punycode@^2.1.0, punycode@^2.1.1:
   version "2.3.1"
   resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5"
@@ -9915,10 +10255,10 @@ queue-microtask@^1.2.2:
   resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
   integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
 
-quickselect@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/quickselect/-/quickselect-2.0.0.tgz#f19680a486a5eefb581303e023e98faaf25dd018"
-  integrity sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==
+queue-tick@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/queue-tick/-/queue-tick-1.0.1.tgz#f6f07ac82c1fd60f82e098b417a80e52f1f4c142"
+  integrity sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==
 
 quickselect@^3.0.0:
   version "3.0.0"
@@ -9960,10 +10300,10 @@ raw-loader@^4.0.2:
     loader-utils "^2.0.0"
     schema-utils "^3.0.0"
 
-re-resizable@6.10.1:
-  version "6.10.1"
-  resolved "https://registry.yarnpkg.com/re-resizable/-/re-resizable-6.10.1.tgz#d062ca50bbc4ec7ae940f756cba36479e9015bc5"
-  integrity sha512-m33nSWRH57UZLmep5M/LatkZ2NRqimVD/bOOpvymw5Zf33+eTSEixsUugscOZzAtK0/nx+OSuOf8VbKJx/4ptw==
+re-resizable@6.10.3:
+  version "6.10.3"
+  resolved "https://registry.yarnpkg.com/re-resizable/-/re-resizable-6.10.3.tgz#72c42532ede0cbcaf93308bcbfed782abbf97e79"
+  integrity sha512-zvWb7X3RJMA4cuSrqoxgs3KR+D+pEXnGrD2FAD6BMYAULnZsSF4b7AOVyG6pC3VVNVOtlagGDCDmZSwWLjjBBw==
 
 react-beautiful-dnd@^13.1.0:
   version "13.1.1"
@@ -10025,6 +10365,11 @@ react-is@^18.0.0:
   resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e"
   integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==
 
+react-lifecycles-compat@^3.0.4:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
+  integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==
+
 react-redux@^7.2.0:
   version "7.2.9"
   resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.9.tgz#09488fbb9416a4efe3735b7235055442b042481d"
@@ -10075,6 +10420,18 @@ react-transition-group@^4.4.1:
     loose-envify "^1.4.0"
     prop-types "^15.6.2"
 
+react-virtualized@^9.22.5:
+  version "9.22.5"
+  resolved "https://registry.yarnpkg.com/react-virtualized/-/react-virtualized-9.22.5.tgz#bfb96fed519de378b50d8c0064b92994b3b91620"
+  integrity sha512-YqQMRzlVANBv1L/7r63OHa2b0ZsAaDp1UhVNEdUaXI8A5u6hTpA5NYtUueLH2rFuY/27mTGIBl7ZhqFKzw18YQ==
+  dependencies:
+    "@babel/runtime" "^7.7.2"
+    clsx "^1.0.4"
+    dom-helpers "^5.1.3"
+    loose-envify "^1.4.0"
+    prop-types "^15.7.2"
+    react-lifecycles-compat "^3.0.4"
+
 react@^18.3.1:
   version "18.3.1"
   resolved "https://registry.yarnpkg.com/react/-/react-18.3.1.tgz#49ab892009c53933625bd16b2533fc754cab2891"
@@ -10108,7 +10465,7 @@ read-pkg@^5.2.0:
     parse-json "^5.0.0"
     type-fest "^0.6.0"
 
-readable-stream@^2.0.1, readable-stream@~2.3.6:
+readable-stream@^2.0.1, readable-stream@^2.0.5, readable-stream@~2.3.6:
   version "2.3.8"
   resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b"
   integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==
@@ -10121,7 +10478,7 @@ readable-stream@^2.0.1, readable-stream@~2.3.6:
     string_decoder "~1.1.1"
     util-deprecate "~1.0.1"
 
-readable-stream@^3.0.6:
+readable-stream@^3.0.6, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.5.0:
   version "3.6.2"
   resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967"
   integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==
@@ -10130,6 +10487,24 @@ readable-stream@^3.0.6:
     string_decoder "^1.1.1"
     util-deprecate "^1.0.1"
 
+readable-stream@^4.0.0:
+  version "4.6.0"
+  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-4.6.0.tgz#ce412dfb19c04efde1c5936d99c27f37a1ff94c9"
+  integrity sha512-cbAdYt0VcnpN2Bekq7PU+k363ZRsPwJoEEJOEtSJQlJXzwaxt3FIo/uL+KeDSGIjJqtkwyge4KQgD2S2kd+CQw==
+  dependencies:
+    abort-controller "^3.0.0"
+    buffer "^6.0.3"
+    events "^3.3.0"
+    process "^0.11.10"
+    string_decoder "^1.3.0"
+
+readdir-glob@^1.1.2:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/readdir-glob/-/readdir-glob-1.1.3.tgz#c3d831f51f5e7bfa62fa2ffbe4b508c640f09584"
+  integrity sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==
+  dependencies:
+    minimatch "^5.1.0"
+
 readdirp@^4.0.1:
   version "4.0.2"
   resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-4.0.2.tgz#388fccb8b75665da3abffe2d8f8ed59fe74c230a"
@@ -10348,6 +10723,11 @@ restore-cursor@^5.0.0:
     onetime "^7.0.0"
     signal-exit "^4.1.0"
 
+retry@^0.12.0:
+  version "0.12.0"
+  resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b"
+  integrity sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==
+
 retry@^0.13.1:
   version "0.13.1"
   resolved "https://registry.yarnpkg.com/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658"
@@ -10436,7 +10816,7 @@ safe-regex-test@^1.0.3:
     es-errors "^1.3.0"
     is-regex "^1.1.4"
 
-"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0":
+"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@~2.1.0:
   version "2.1.2"
   resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
   integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
@@ -10448,10 +10828,10 @@ sanitize-filename@^1.6.3:
   dependencies:
     truncate-utf8-bytes "^1.0.0"
 
-sanitize-html@2.13.1:
-  version "2.13.1"
-  resolved "https://registry.yarnpkg.com/sanitize-html/-/sanitize-html-2.13.1.tgz#b4639b0a09574ab62b1b353cb99b1b87af742834"
-  integrity sha512-ZXtKq89oue4RP7abL9wp/9URJcqQNABB5GGJ2acW1sdO8JTVl92f4ygD7Yc9Ze09VAZhnt2zegeU0tbNsdcLYg==
+sanitize-html@2.14.0:
+  version "2.14.0"
+  resolved "https://registry.yarnpkg.com/sanitize-html/-/sanitize-html-2.14.0.tgz#bd2a7b97ee1d86a7f0e0babf3a4468f639c3a429"
+  integrity sha512-CafX+IUPxZshXqqRaG9ZClSlfPVjSxI0td7n07hk8QO2oO+9JDnlcL8iM8TWeOXOIBFgIOx6zioTzM53AOMn3g==
   dependencies:
     deepmerge "^4.2.2"
     escape-string-regexp "^4.0.0"
@@ -10526,7 +10906,7 @@ semver@^6.3.0, semver@^6.3.1:
   resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
   integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
 
-semver@^7.5.2, semver@^7.5.3, semver@^7.5.4, semver@^7.6.0, semver@^7.6.1, semver@^7.6.3:
+semver@^7.5.2, semver@^7.5.3, semver@^7.5.4, semver@^7.6.0, semver@^7.6.3:
   version "7.6.3"
   resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143"
   integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==
@@ -10656,7 +11036,7 @@ side-channel@^1.0.4, side-channel@^1.0.6:
     get-intrinsic "^1.2.4"
     object-inspect "^1.13.1"
 
-signal-exit@^3.0.3, signal-exit@^3.0.7:
+signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7:
   version "3.0.7"
   resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
   integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
@@ -10737,7 +11117,7 @@ sockjs@^0.3.24:
     uuid "^8.3.2"
     websocket-driver "^0.7.4"
 
-source-map-js@^1.0.1, source-map-js@^1.0.2, source-map-js@^1.2.0, source-map-js@^1.2.1:
+source-map-js@^1.0.1, source-map-js@^1.0.2, source-map-js@^1.2.1:
   version "1.2.1"
   resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46"
   integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==
@@ -10820,6 +11200,11 @@ spdy@^4.0.2:
     select-hose "^2.0.0"
     spdy-transport "^3.0.0"
 
+split-ca@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/split-ca/-/split-ca-1.0.1.tgz#6c83aff3692fa61256e0cd197e05e9de157691a6"
+  integrity sha512-Q5thBSxp5t8WPTTJQS59LrGqOZqOsrhDGDVm8azCqIBjSBd7nd9o2PM+mDulQQkh8h//4U6hFZnc/mul8t5pWQ==
+
 sprintf-js@^1.0.3:
   version "1.1.3"
   resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.3.tgz#4914b903a2f8b685d17fdf78a70e917e872e444a"
@@ -10830,6 +11215,25 @@ sprintf-js@~1.0.2:
   resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
   integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==
 
+ssh-remote-port-forward@^1.0.4:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/ssh-remote-port-forward/-/ssh-remote-port-forward-1.0.4.tgz#72b0c5df8ec27ca300c75805cc6b266dee07e298"
+  integrity sha512-x0LV1eVDwjf1gmG7TTnfqIzf+3VPRz7vrNIjX6oYLbeCrf/PeVY6hkT68Mg+q02qXxQhrLjB0jfgvhevoCRmLQ==
+  dependencies:
+    "@types/ssh2" "^0.5.48"
+    ssh2 "^1.4.0"
+
+ssh2@^1.11.0, ssh2@^1.4.0:
+  version "1.16.0"
+  resolved "https://registry.yarnpkg.com/ssh2/-/ssh2-1.16.0.tgz#79221d40cbf4d03d07fe881149de0a9de928c9f0"
+  integrity sha512-r1X4KsBGedJqo7h8F5c4Ybpcr5RjyP+aWIG007uBPRjmdQWfEiVLzSK71Zji1B9sKxwaCvD8y8cwSkYrlLiRRg==
+  dependencies:
+    asn1 "^0.2.6"
+    bcrypt-pbkdf "^1.0.2"
+  optionalDependencies:
+    cpu-features "~0.0.10"
+    nan "^2.20.0"
+
 stack-utils@^2.0.3:
   version "2.0.6"
   resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f"
@@ -10847,6 +11251,17 @@ statuses@2.0.1:
   resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
   integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==
 
+streamx@^2.15.0, streamx@^2.21.0:
+  version "2.21.1"
+  resolved "https://registry.yarnpkg.com/streamx/-/streamx-2.21.1.tgz#f02979d8395b6b637d08a589fb514498bed55845"
+  integrity sha512-PhP9wUnFLa+91CPy3N6tiQsK+gnYyUNuk15S3YG/zjYE7RuPeCjJngqnzpC31ow0lzBHQ+QGO4cNJnd0djYUsw==
+  dependencies:
+    fast-fifo "^1.3.2"
+    queue-tick "^1.0.1"
+    text-decoder "^1.1.0"
+  optionalDependencies:
+    bare-events "^2.2.0"
+
 string-argv@~0.3.2:
   version "0.3.2"
   resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6"
@@ -10959,7 +11374,7 @@ string.prototype.trimstart@^1.0.8:
     define-properties "^1.2.1"
     es-object-atoms "^1.0.0"
 
-string_decoder@^1.1.1:
+string_decoder@^1.1.1, string_decoder@^1.3.0:
   version "1.3.0"
   resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e"
   integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
@@ -11217,11 +11632,52 @@ tapable@^2.0.0, tapable@^2.1.1, tapable@^2.2.0, tapable@^2.2.1:
   resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0"
   integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==
 
+tar-fs@^3.0.6:
+  version "3.0.6"
+  resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-3.0.6.tgz#eaccd3a67d5672f09ca8e8f9c3d2b89fa173f217"
+  integrity sha512-iokBDQQkUyeXhgPYaZxmczGPhnhXZ0CmrqI+MOb/WFGS9DW5wnfrLgtjUJBvz50vQ3qfRwJ62QVoCFu8mPVu5w==
+  dependencies:
+    pump "^3.0.0"
+    tar-stream "^3.1.5"
+  optionalDependencies:
+    bare-fs "^2.1.1"
+    bare-path "^2.1.0"
+
+tar-fs@~2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.0.1.tgz#e44086c1c60d31a4f0cf893b1c4e155dabfae9e2"
+  integrity sha512-6tzWDMeroL87uF/+lin46k+Q+46rAJ0SyPGz7OW7wTgblI273hsBqk2C1j0/xNadNLKDTUL9BukSjB7cwgmlPA==
+  dependencies:
+    chownr "^1.1.1"
+    mkdirp-classic "^0.5.2"
+    pump "^3.0.0"
+    tar-stream "^2.0.0"
+
 tar-js@^0.3.0:
   version "0.3.0"
   resolved "https://registry.yarnpkg.com/tar-js/-/tar-js-0.3.0.tgz#6949aabfb0ba18bb1562ae51a439fd0f30183a17"
   integrity sha512-9uqP2hJUZNKRkwPDe5nXxXdzo6w+BFBPq9x/tyi5/U/DneuSesO/HMb0y5TeWpfcv49YDJTs7SrrZeeu8ZHWDA==
 
+tar-stream@^2.0.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287"
+  integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==
+  dependencies:
+    bl "^4.0.3"
+    end-of-stream "^1.4.1"
+    fs-constants "^1.0.0"
+    inherits "^2.0.3"
+    readable-stream "^3.1.1"
+
+tar-stream@^3.0.0, tar-stream@^3.1.5:
+  version "3.1.7"
+  resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-3.1.7.tgz#24b3fb5eabada19fe7338ed6d26e5f7c482e792b"
+  integrity sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==
+  dependencies:
+    b4a "^1.6.4"
+    fast-fifo "^1.2.0"
+    streamx "^2.15.0"
+
 temporal-polyfill@^0.2.5:
   version "0.2.5"
   resolved "https://registry.yarnpkg.com/temporal-polyfill/-/temporal-polyfill-0.2.5.tgz#0796c40a50754c69ec0f9a2db3f6c582b9721aaf"
@@ -11274,6 +11730,34 @@ test-exclude@^6.0.0:
     glob "^7.1.4"
     minimatch "^3.0.4"
 
+testcontainers@^10.16.0:
+  version "10.16.0"
+  resolved "https://registry.yarnpkg.com/testcontainers/-/testcontainers-10.16.0.tgz#8a7e69ada5cd2c6cce1c6db72b3a3e8e412fcaf6"
+  integrity sha512-oxPLuOtrRWS11A+Yn0+zXB7GkmNarflWqmy6CQJk8KJ75LZs2/zlUXDpizTbPpCGtk4kE2EQYwFZjrE967F8Wg==
+  dependencies:
+    "@balena/dockerignore" "^1.0.2"
+    "@types/dockerode" "^3.3.29"
+    archiver "^7.0.1"
+    async-lock "^1.4.1"
+    byline "^5.0.0"
+    debug "^4.3.5"
+    docker-compose "^0.24.8"
+    dockerode "^3.3.5"
+    get-port "^5.1.1"
+    proper-lockfile "^4.1.2"
+    properties-reader "^2.3.0"
+    ssh-remote-port-forward "^1.0.4"
+    tar-fs "^3.0.6"
+    tmp "^0.2.3"
+    undici "^5.28.4"
+
+text-decoder@^1.1.0:
+  version "1.2.3"
+  resolved "https://registry.yarnpkg.com/text-decoder/-/text-decoder-1.2.3.tgz#b19da364d981b2326d5f43099c310cc80d770c65"
+  integrity sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==
+  dependencies:
+    b4a "^1.6.4"
+
 text-table@^0.2.0:
   version "0.2.0"
   resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
@@ -11307,6 +11791,11 @@ tinyqueue@^3.0.0:
   resolved "https://registry.yarnpkg.com/tinyqueue/-/tinyqueue-3.0.0.tgz#101ea761ccc81f979e29200929e78f1556e3661e"
   integrity sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g==
 
+tmp@^0.2.3:
+  version "0.2.3"
+  resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.3.tgz#eb783cc22bc1e8bebd0671476d46ea4eb32a79ae"
+  integrity sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==
+
 tmpl@1.0.5:
   version "1.0.5"
   resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc"
@@ -11373,11 +11862,6 @@ tree-kill@^1.2.2:
   resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc"
   integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==
 
-"true-myth@^4.1.0":
-  version "4.1.1"
-  resolved "https://registry.yarnpkg.com/true-myth/-/true-myth-4.1.1.tgz#ff4ac9d5130276e34aa338757e2416ec19248ba2"
-  integrity sha512-rqy30BSpxPznbbTcAcci90oZ1YR4DqvKcNXNerG5gQBU2v4jk0cygheiul5J6ExIMrgDVuanv/MkGfqZbKrNNg==
-
 truncate-utf8-bytes@^1.0.0:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz#405923909592d56f78a5818434b0b78489ca5f2b"
@@ -11390,13 +11874,10 @@ ts-api-utils@^1.3.0:
   resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.4.3.tgz#bfc2215fe6528fecab2b0fba570a2e8a4263b064"
   integrity sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==
 
-ts-morph@^13.0.1:
-  version "13.0.3"
-  resolved "https://registry.yarnpkg.com/ts-morph/-/ts-morph-13.0.3.tgz#c0c51d1273ae2edb46d76f65161eb9d763444c1d"
-  integrity sha512-pSOfUMx8Ld/WUreoSzvMFQG5i9uEiWIsBYjpU9+TTASOeUa89j5HykomeqVULm1oqWtBdleI3KEFRLrlA3zGIw==
-  dependencies:
-    "@ts-morph/common" "~0.12.3"
-    code-block-writer "^11.0.0"
+ts-api-utils@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-2.0.0.tgz#b9d7d5f7ec9f736f4d0f09758b8607979044a900"
+  integrity sha512-xCt/TOAc+EOHS1XPnijD3/yzpH6qg2xppZO1YDqGoVsNXfQfzHpOdNuXwrwOU8u4ITXJyDCTyt8w5g1sZv9ynQ==
 
 ts-node@^10.9.1:
   version "10.9.2"
@@ -11417,18 +11898,6 @@ ts-node@^10.9.1:
     v8-compile-cache-lib "^3.0.1"
     yn "3.1.1"
 
-ts-prune@^0.10.3:
-  version "0.10.3"
-  resolved "https://registry.yarnpkg.com/ts-prune/-/ts-prune-0.10.3.tgz#b6c71a525543b38dcf947a7d3adfb7f9e8b91f38"
-  integrity sha512-iS47YTbdIcvN8Nh/1BFyziyUqmjXz7GVzWu02RaZXqb+e/3Qe1B7IQ4860krOeCGUeJmterAlaM2FRH0Ue0hjw==
-  dependencies:
-    commander "^6.2.1"
-    cosmiconfig "^7.0.1"
-    json5 "^2.1.3"
-    lodash "^4.17.21"
-    "true-myth" "^4.1.0"
-    ts-morph "^13.0.1"
-
 ts-xor@^1.3.0:
   version "1.3.0"
   resolved "https://registry.yarnpkg.com/ts-xor/-/ts-xor-1.3.0.tgz#3e59f24f0321f9f10f350e0cee3b534b89a2c70b"
@@ -11454,6 +11923,11 @@ tslib@^2.0.0, tslib@^2.4.0, tslib@^2.6.1, tslib@^2.6.2, tslib@^2.7.0:
   resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.0.tgz#d124c86c3c05a40a91e6fdea4021bd31d377971b"
   integrity sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==
 
+tweetnacl@^0.14.3:
+  version "0.14.5"
+  resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
+  integrity sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==
+
 type-check@^0.4.0, type-check@~0.4.0:
   version "0.4.0"
   resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1"
@@ -11539,10 +12013,10 @@ typed-array-length@^1.0.6:
     possible-typed-array-names "^1.0.0"
     reflect.getprototypeof "^1.0.6"
 
-typescript@5.6.3:
-  version "5.6.3"
-  resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.6.3.tgz#5f3449e31c9d94febb17de03cc081dd56d81db5b"
-  integrity sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==
+typescript@5.7.2:
+  version "5.7.2"
+  resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.7.2.tgz#3169cf8c4c8a828cde53ba9ecb3d2b1d5dd67be6"
+  integrity sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==
 
 ua-parser-js@^1.0.2:
   version "1.0.39"
@@ -11579,6 +12053,13 @@ undici-types@~6.20.0:
   resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.20.0.tgz#8171bf22c1f588d1554d55bf204bc624af388433"
   integrity sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==
 
+undici@^5.28.4:
+  version "5.28.4"
+  resolved "https://registry.yarnpkg.com/undici/-/undici-5.28.4.tgz#6b280408edb6a1a604a9b20340f45b422e373068"
+  integrity sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==
+  dependencies:
+    "@fastify/busboy" "^2.0.0"
+
 unhomoglyph@^1.0.6:
   version "1.0.6"
   resolved "https://registry.yarnpkg.com/unhomoglyph/-/unhomoglyph-1.0.6.tgz#ea41f926d0fcf598e3b8bb2980c2ddac66b081d3"
@@ -11617,11 +12098,6 @@ universalify@^0.2.0:
   resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0"
   integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==
 
-universalify@^2.0.0:
-  version "2.0.1"
-  resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d"
-  integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==
-
 unpipe@1.0.0, unpipe@~1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
@@ -11638,12 +12114,12 @@ unplugin@1.0.1:
     webpack-virtual-modules "^0.5.0"
 
 update-browserslist-db@^1.1.1:
-  version "1.1.1"
-  resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz#80846fba1d79e82547fb661f8d141e0945755fe5"
-  integrity sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.2.tgz#97e9c96ab0ae7bcac08e9ae5151d26e6bc6b5580"
+  integrity sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==
   dependencies:
     escalade "^3.2.0"
-    picocolors "^1.1.0"
+    picocolors "^1.1.1"
 
 uri-js@^4.2.2:
   version "4.4.1"
@@ -11866,24 +12342,24 @@ webpack-bundle-analyzer@^4.8.0:
     sirv "^2.0.3"
     ws "^7.3.1"
 
-webpack-cli@^5.0.0:
-  version "5.1.4"
-  resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-5.1.4.tgz#c8e046ba7eaae4911d7e71e2b25b776fcc35759b"
-  integrity sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==
+webpack-cli@^6.0.0:
+  version "6.0.1"
+  resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-6.0.1.tgz#a1ce25da5ba077151afd73adfa12e208e5089207"
+  integrity sha512-MfwFQ6SfwinsUVi0rNJm7rHZ31GyTcpVE5pgVA3hwFRb7COD4TzjUUwhGWKfO50+xdc2MQPuEBBJoqIMGt3JDw==
   dependencies:
-    "@discoveryjs/json-ext" "^0.5.0"
-    "@webpack-cli/configtest" "^2.1.1"
-    "@webpack-cli/info" "^2.0.2"
-    "@webpack-cli/serve" "^2.0.5"
+    "@discoveryjs/json-ext" "^0.6.1"
+    "@webpack-cli/configtest" "^3.0.1"
+    "@webpack-cli/info" "^3.0.1"
+    "@webpack-cli/serve" "^3.0.1"
     colorette "^2.0.14"
-    commander "^10.0.1"
+    commander "^12.1.0"
     cross-spawn "^7.0.3"
-    envinfo "^7.7.3"
+    envinfo "^7.14.0"
     fastest-levenshtein "^1.0.12"
     import-local "^3.0.2"
     interpret "^3.1.1"
     rechoir "^0.8.0"
-    webpack-merge "^5.7.3"
+    webpack-merge "^6.0.1"
 
 webpack-dev-middleware@^7.4.2:
   version "7.4.2"
@@ -11931,14 +12407,21 @@ webpack-dev-server@^5.0.0:
     webpack-dev-middleware "^7.4.2"
     ws "^8.18.0"
 
-webpack-merge@^5.7.3:
-  version "5.10.0"
-  resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.10.0.tgz#a3ad5d773241e9c682803abf628d4cd62b8a4177"
-  integrity sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==
+webpack-merge@^6.0.1:
+  version "6.0.1"
+  resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-6.0.1.tgz#50c776868e080574725abc5869bd6e4ef0a16c6a"
+  integrity sha512-hXXvrjtx2PLYx4qruKl+kyRSLc52V+cCvMxRjmKwoA+CBbbF5GfIBtR6kCvl0fYGqTUPKB+1ktVmTHqMOzgCBg==
   dependencies:
     clone-deep "^4.0.1"
     flat "^5.0.2"
-    wildcard "^2.0.0"
+    wildcard "^2.0.1"
+
+webpack-retry-chunk-load-plugin@^3.1.1:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/webpack-retry-chunk-load-plugin/-/webpack-retry-chunk-load-plugin-3.1.1.tgz#44aefc21abd01769ecd07f9a200a58a78caf930c"
+  integrity sha512-BKq/7EcelyWUUI6SeBaUKB1G+fSZP0rlxIwRQ+aO6mK5tffljaHdpJ4I2q54rpaaKjSbwbZRQlaITXe93SL9nA==
+  dependencies:
+    prettier "^2.6.2"
 
 webpack-sources@^3.2.3:
   version "3.2.3"
@@ -12132,7 +12615,7 @@ which@^4.0.0:
   dependencies:
     isexe "^3.1.1"
 
-wildcard@^2.0.0:
+wildcard@^2.0.1:
   version "2.0.1"
   resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.1.tgz#5ab10d02487198954836b6349f74fff961e10f67"
   integrity sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==
@@ -12228,10 +12711,10 @@ yallist@^3.0.2:
   resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd"
   integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==
 
-yaml@^1.10.0:
-  version "1.10.2"
-  resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
-  integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==
+yaml@^2.2.2:
+  version "2.7.0"
+  resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.7.0.tgz#aef9bb617a64c937a9a748803786ad8d3ffe1e98"
+  integrity sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==
 
 yaml@^2.3.3:
   version "2.6.1"
@@ -12301,6 +12784,15 @@ yocto-queue@^1.0.0:
   resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-1.1.1.tgz#fef65ce3ac9f8a32ceac5a634f74e17e5b232110"
   integrity sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==
 
+zip-stream@^6.0.1:
+  version "6.0.1"
+  resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-6.0.1.tgz#e141b930ed60ccaf5d7fa9c8260e0d1748a2bbfb"
+  integrity sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==
+  dependencies:
+    archiver-utils "^5.0.0"
+    compress-commons "^6.0.2"
+    readable-stream "^4.0.0"
+
 zod-validation-error@^3.0.3:
   version "3.4.0"
   resolved "https://registry.yarnpkg.com/zod-validation-error/-/zod-validation-error-3.4.0.tgz#3a8a1f55c65579822d7faa190b51336c61bee2a6"