diff --git a/.gitignore b/.gitignore
index f5e9d58a8791a1f7513057ef460f91418e7f043c..6d50f6680193bc6647d82f15fa85cb76522bf1da 100644
--- a/.gitignore
+++ b/.gitignore
@@ -43,9 +43,6 @@
 /.vscode/
 /.devcontainer/
 
-# Ignore the cookie consent killswitch.
-/disable-cookie-consent
-
 # Ignore temporary and auto-generated files.
 /tmp/
 /web/VERSION.txt
diff --git a/behat.yml.dist b/behat.yml.dist
index 1c8df9bf3f51e6614240de22dfdea196dfdcb78a..202b73590393d7f0e928d41ea0e3e75de8f77352 100644
--- a/behat.yml.dist
+++ b/behat.yml.dist
@@ -3,6 +3,7 @@
   - '%paths.base%/tests/features'
 .contexts: &contexts
   - Drupal\joinup\Context\BootstrapDrupalContext
+  - Drupal\DrupalExtension\Context\ConfigContext
   - Drupal\DrupalExtension\Context\DrushContext
   - Drupal\DrupalExtension\Context\MarkupContext
   - Drupal\DrupalExtension\Context\MessageContext
@@ -67,6 +68,7 @@
   - Drupal\joinup\Context\JoinupSeoContext
   - Drupal\joinup\Context\JoinupSubscriptionContext
   - Drupal\joinup\Context\JoinupUserContext
+  - Drupal\joinup\Context\JsErrorsContext
   - Drupal\joinup\Context\LinkContext
   - Drupal\joinup\Context\LogRecordsContext
   - Drupal\joinup\Context\MediaContext
diff --git a/composer.json b/composer.json
index 8b1b22677f4d1cb157ebae5c33650823fed90100..9b94c8589c960c2405b2805789907bc15d0c9c16 100644
--- a/composer.json
+++ b/composer.json
@@ -338,7 +338,8 @@
                 "The submit button is not following any condition while in popup/dialogs @see https://drupal.org/i/3008172": "resources/patch/php/drupal/core/3008172-43.patch",
                 "Added deprecation suppression": "resources/patch/php/drupal/core/3467293.diff",
                 "Fix handling of unknown file extensions in FileMediaFormatterBase @see https://www.drupal.org/i/3466462": "resources/patch/php/drupal/core/3466462.diff",
-                "Allow ChangedItem to skip updating the entity's \"changed\" timestamp when synchronizing @see https://drupal.org/i/2329253": "resources/patch/php/drupal/core/2329253-10.x.patch"
+                "Allow ChangedItem to skip updating the entity's \"changed\" timestamp when synchronizing @see https://drupal.org/i/2329253": "resources/patch/php/drupal/core/2329253-10.x.patch",
+                "JS errors from Drupal.dialog.resetSize when rapidly closing dialogs @see https://www.drupal.org/i/3472624": "resources/patch/php/drupal/core/3472624.diff"
             },
             "drupal/default_content": {
                 "Allow manual imports @see https://www.drupal.org/i/2640734": "resources/patch/php/drupal/default_content/2640734.diff"
@@ -387,7 +388,8 @@
             },
             "drupal/honeypot": {
                 "Behat integration. @see https://www.drupal.org/project/honeypot/issues/3059040": "resources/patch/php/drupal/honeypot/3059040.patch",
-                "Provide ways to clean up old honeypot_time_restriction values @see https://www.drupal.org/project/honeypot/issues/2997609": "resources/patch/php/drupal/honeypot/2997609.patch"
+                "Provide ways to clean up old honeypot_time_restriction values @see https://www.drupal.org/project/honeypot/issues/2997609": "resources/patch/php/drupal/honeypot/2997609.patch",
+                "Remove caching in HoneypotService::getProtectedForms preventing proper invalidation @see https://www.drupal.org/i/3481399": "resources/patch/php/drupal/honeypot/3481399.patch"
             },
             "drupal/imagecache_external": {
                 "Support SVG @see https://www.drupal.org/i/3390948": "resources/patch/php/drupal/imagecache_external/3390948.diff",
diff --git a/composer.lock b/composer.lock
index bd86abbded8d744dd98c5df00add373081a930dc..3b386029cca7a43a87190abc7ff0875398617dbc 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "cf8792d8c3cb566dd5b99db3e9839e0a",
+    "content-hash": "c60614e39d086e7f4dc1e3a2cab0d2f4",
     "packages": [
         {
             "name": "asm89/stack-cors",
diff --git a/resources/patch/php/drupal/core/3472624.diff b/resources/patch/php/drupal/core/3472624.diff
new file mode 100644
index 0000000000000000000000000000000000000000..2af9300c49a69c644f831416b6000e106bde455e
--- /dev/null
+++ b/resources/patch/php/drupal/core/3472624.diff
@@ -0,0 +1,41 @@
+diff --git a/core/misc/dialog/dialog.position.js b/core/misc/dialog/dialog.position.js
+index 98662211595ede9a4d1a238f90c0cae8cfe006e3..a15f726d1c5afca5586580dd27e82f981fc6472b 100644
+--- a/core/misc/dialog/dialog.position.js
++++ b/core/misc/dialog/dialog.position.js
+@@ -63,6 +63,14 @@
+    * @fires event:dialogContentResize
+    */
+   function resetSize(event) {
++    // Ensure the UI dialog instance exists/is valid.
++    // If the dialog is closed very rapidly, the jQuery UI instance may have
++    // been destroyed, but debounce might still call this function within the
++    // setTimeout interval.
++    if (!event.data.$element.data('ui-dialog')) {
++      return;
++    }
++
+     const positionOptions = [
+       'width',
+       'height',
+diff --git a/core/tests/Drupal/FunctionalJavascriptTests/Ajax/DialogTest.php b/core/tests/Drupal/FunctionalJavascriptTests/Ajax/DialogTest.php
+index bdd324020866d453050e89517767df29de6e6bb2..bbbc60000b23570cead191360943aa481077fafd 100644
+--- a/core/tests/Drupal/FunctionalJavascriptTests/Ajax/DialogTest.php
++++ b/core/tests/Drupal/FunctionalJavascriptTests/Ajax/DialogTest.php
+@@ -69,6 +69,17 @@ public function testDialog(): void {
+     $this->assertNotNull($close_button);
+     $close_button->press();
+ 
++    // Test opening and immediately closing modal a few times.
++    // Ensure no JS errors are thrown.
++    for ($i = 0; $i < 10; $i++) {
++      $this->getSession()->getPage()->clickLink('Link 1 (modal)');
++      $this->assertSession()->waitForElementVisible('css', 'div.ui-dialog');
++      // Use JS directly which is much faster than Element::find.
++      // We want to close it as fast as possible, within 20ms, corresponding to
++      // the debounce on Drupal.dialog.resetSize.
++      $this->getSession()->executeScript('document.querySelector(".ui-dialog button[title=\"Close\"]").click();');
++    }
++
+     // Tests a modal with a dialog-option.
+     // Link 2 is similar to Link 1, except it submits additional width
+     // information which must be echoed in the resulting  DOM update.
diff --git a/resources/patch/php/drupal/honeypot/3481399.patch b/resources/patch/php/drupal/honeypot/3481399.patch
new file mode 100644
index 0000000000000000000000000000000000000000..9dfe2153d6abe315b36cd57a43fbd34d1bf38207
--- /dev/null
+++ b/resources/patch/php/drupal/honeypot/3481399.patch
@@ -0,0 +1,228 @@
+diff --git a/honeypot.services.yml b/honeypot.services.yml
+index 331a8c2..bd80d0d 100644
+--- a/honeypot.services.yml
++++ b/honeypot.services.yml
+@@ -1,4 +1,4 @@
+ services:
+   honeypot:
+     class: Drupal\honeypot\HoneypotService
+-    arguments: ['@current_user', '@module_handler', '@config.factory', '@keyvalue.expirable', '@page_cache_kill_switch', '@database', '@logger.factory', '@datetime.time', '@string_translation', '@cache.default', '@request_stack']
++    arguments: ['@current_user', '@module_handler', '@config.factory', '@keyvalue.expirable', '@page_cache_kill_switch', '@database', '@logger.factory', '@datetime.time', '@string_translation', '@request_stack']
+diff --git a/src/Form/HoneypotSettingsForm.php b/src/Form/HoneypotSettingsForm.php
+index cbf64b7..2116d72 100644
+--- a/src/Form/HoneypotSettingsForm.php
++++ b/src/Form/HoneypotSettingsForm.php
+@@ -3,7 +3,6 @@
+ namespace Drupal\honeypot\Form;
+ 
+ use Drupal\Component\Utility\Html;
+-use Drupal\Core\Cache\CacheBackendInterface;
+ use Drupal\Core\Config\ConfigFactoryInterface;
+ use Drupal\Core\Config\TypedConfigManagerInterface;
+ use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
+@@ -40,13 +39,6 @@ class HoneypotSettingsForm extends ConfigFormBase {
+    */
+   protected $entityTypeBundleInfo;
+ 
+-  /**
+-   * A cache backend interface.
+-   *
+-   * @var \Drupal\Core\Cache\CacheBackendInterface
+-   */
+-  protected $cache;
+-
+   /**
+    * Constructs a settings controller.
+    *
+@@ -60,15 +52,12 @@ class HoneypotSettingsForm extends ConfigFormBase {
+    *   The entity type manager.
+    * @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_type_bundle_info
+    *   The entity type bundle info service.
+-   * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
+-   *   The cache backend interface.
+    */
+-  public function __construct(ConfigFactoryInterface $config_factory, TypedConfigManagerInterface $typedConfigManager, ModuleHandlerInterface $module_handler, EntityTypeManagerInterface $entity_type_manager, EntityTypeBundleInfoInterface $entity_type_bundle_info, CacheBackendInterface $cache_backend) {
++  public function __construct(ConfigFactoryInterface $config_factory, TypedConfigManagerInterface $typedConfigManager, ModuleHandlerInterface $module_handler, EntityTypeManagerInterface $entity_type_manager, EntityTypeBundleInfoInterface $entity_type_bundle_info) {
+     parent::__construct($config_factory, $typedConfigManager);
+     $this->moduleHandler = $module_handler;
+     $this->entityTypeManager = $entity_type_manager;
+     $this->entityTypeBundleInfo = $entity_type_bundle_info;
+-    $this->cache = $cache_backend;
+   }
+ 
+   /**
+@@ -80,8 +69,7 @@ class HoneypotSettingsForm extends ConfigFormBase {
+       $container->get('config.typed'),
+       $container->get('module_handler'),
+       $container->get('entity_type.manager'),
+-      $container->get('entity_type.bundle.info'),
+-      $container->get('cache.default')
++      $container->get('entity_type.bundle.info')
+     );
+   }
+ 
+@@ -295,12 +283,7 @@ class HoneypotSettingsForm extends ConfigFormBase {
+     }
+ 
+     // Save the honeypot forms from $form_state into a 'form_settings' array.
+-    $config->set('form_settings', $form_state->getValue('form_settings'));
+-
+-    $config->save();
+-
+-    // Clear the honeypot protected forms cache.
+-    $this->cache->delete('honeypot_protected_forms');
++    $config->set('form_settings', $form_state->getValue('form_settings'))->save();
+ 
+     parent::submitForm($form, $form_state);
+   }
+diff --git a/src/HoneypotService.php b/src/HoneypotService.php
+index 22ea589..e767c32 100644
+--- a/src/HoneypotService.php
++++ b/src/HoneypotService.php
+@@ -4,7 +4,6 @@ namespace Drupal\honeypot;
+ 
+ use Drupal\Component\Datetime\TimeInterface;
+ use Drupal\Component\Utility\Crypt;
+-use Drupal\Core\Cache\CacheBackendInterface;
+ use Drupal\Core\Config\ConfigFactory;
+ use Drupal\Core\Database\Connection;
+ use Drupal\Core\DependencyInjection\DependencySerializationTrait;
+@@ -81,13 +80,6 @@ class HoneypotService implements HoneypotServiceInterface {
+    */
+   protected $timeService;
+ 
+-  /**
+-   * A cache backend interface.
+-   *
+-   * @var \Drupal\Core\Cache\CacheBackendInterface
+-   */
+-  protected $cacheBackend;
+-
+   /**
+    * The request stack service.
+    *
+@@ -116,12 +108,10 @@ class HoneypotService implements HoneypotServiceInterface {
+    *   The datetime.time service.
+    * @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation
+    *   The string translation service.
+-   * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
+-   *   The cache backend interface.
+    * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
+    *   The request stack service.
+    */
+-  public function __construct(AccountProxyInterface $account, ModuleHandlerInterface $module_handler, ConfigFactory $config_factory, KeyValueExpirableFactory $key_value, KillSwitch $kill_switch, Connection $connection, LoggerChannelFactoryInterface $logger_factory, TimeInterface $time_service, TranslationInterface $string_translation, CacheBackendInterface $cache_backend, RequestStack $request_stack) {
++  public function __construct(AccountProxyInterface $account, ModuleHandlerInterface $module_handler, ConfigFactory $config_factory, KeyValueExpirableFactory $key_value, KillSwitch $kill_switch, Connection $connection, LoggerChannelFactoryInterface $logger_factory, TimeInterface $time_service, TranslationInterface $string_translation, RequestStack $request_stack) {
+     $this->account = $account;
+     $this->moduleHandler = $module_handler;
+     $this->config = $config_factory->get('honeypot.settings');
+@@ -131,7 +121,6 @@ class HoneypotService implements HoneypotServiceInterface {
+     $this->loggerFactory = $logger_factory;
+     $this->timeService = $time_service;
+     $this->stringTranslation = $string_translation;
+-    $this->cacheBackend = $cache_backend;
+     $this->requestStack = $request_stack;
+   }
+ 
+@@ -139,31 +128,7 @@ class HoneypotService implements HoneypotServiceInterface {
+    * {@inheritdoc}
+    */
+   public function getProtectedForms(): array {
+-    $forms = &drupal_static(__METHOD__);
+-
+-    // If the data isn't already in memory, get from cache or look it up fresh.
+-    if (!isset($forms)) {
+-      if ($cache = $this->cacheBackend->get('honeypot_protected_forms')) {
+-        $forms = $cache->data;
+-      }
+-      else {
+-        $forms = [];
+-        $form_settings = $this->config->get('form_settings');
+-        if (!empty($form_settings)) {
+-          // Add each form that's enabled to the $forms array.
+-          foreach ($form_settings as $form_id => $enabled) {
+-            if ($enabled) {
+-              $forms[] = $form_id;
+-            }
+-          }
+-        }
+-
+-        // Save the cached data.
+-        $this->cacheBackend->set('honeypot_protected_forms', $forms);
+-      }
+-    }
+-
+-    return $forms;
++    return array_keys(array_filter($this->config->get('form_settings') ?? []));
+   }
+ 
+   /**
+diff --git a/tests/src/Kernel/HoneypotTest.php b/tests/src/Kernel/HoneypotTest.php
+new file mode 100644
+index 0000000..ae3610f
+--- /dev/null
++++ b/tests/src/Kernel/HoneypotTest.php
+@@ -0,0 +1,64 @@
++<?php
++
++declare(strict_types=1);
++
++namespace Drupal\Tests\honeypot\Kernel;
++
++use Drupal\KernelTests\KernelTestBase;
++
++/**
++ * Tests honeypot functionality.
++ *
++ * @group honeypot
++ */
++class HoneypotTest extends KernelTestBase {
++
++  /**
++   * {@inheritdoc}
++   */
++  protected static $modules = ['honeypot'];
++
++  /**
++   * The config factory service.
++   *
++   * @var \Drupal\Core\Config\ConfigFactoryInterface
++   */
++  protected $configFactory;
++
++  /**
++   * The Honeypot service.
++   *
++   * @var \Drupal\honeypot\HoneypotServiceInterface
++   */
++  protected $honeypot;
++
++  /**
++   * {@inheritdoc}
++   */
++  protected function setUp(): void {
++    parent::setUp();
++
++    $this->installSchema('honeypot', []);
++    $this->installConfig(['honeypot']);
++    $this->configFactory = $this->container->get('config.factory');
++    $this->honeypot = $this->container->get('honeypot');
++  }
++
++  /**
++   * Tests the Honeypot protected forms method.
++   *
++   * @covers \Drupal\honeypot\HoneypotService::getProtectedForms
++   */
++  public function testGetProtectedForms(): void {
++    $config = $this->configFactory->getEditable('honeypot.settings');
++
++    // Initial state: we have a protected form.
++    $config->set('form_settings', ['user_register_form' => TRUE])->save();
++    $this->assertEquals(['user_register_form'], $this->honeypot->getProtectedForms());
++
++    // Empty form_settings, expect no protected forms.
++    $config->set('form_settings', [])->save();
++    $this->assertEquals([], $this->honeypot->getProtectedForms());
++  }
++
++}
diff --git a/resources/runner/drupal.yml b/resources/runner/drupal.yml
index 2b0fc17ae356ed2a53ab142270962acbc31f1d68..74bb7f38350cc59a235789fe088f6282ad92338f 100644
--- a/resources/runner/drupal.yml
+++ b/resources/runner/drupal.yml
@@ -253,12 +253,11 @@ drupal:
         // Location of the site configuration files.
         $settings['config_sync_directory'] = '../config/sync';
       Testing configuration alters: |
+        // Enable test_mode.
+        $config['joinup_test.settings']['test_mode'] = TRUE;
+
         // The video from the home page interacts with Selenium tests.
         $config['page_manager.page_variant.homepage-layout_builder-0']['variant_settings']['sections'][4]['components']['6ab0ceea-4541-4153-8b64-227e02369d30']['configuration']['text'] = 'Some joinup video';
-        // Almost all tests should run without the cookie consent widget.
-        $oe_webtools_cck_enabled = !file_exists(getcwd() . '/../disable-cookie-consent');
-        $config['oe_webtools_cookie_consent.settings']['banner_popup'] = $oe_webtools_cck_enabled;
-        $config['oe_webtools_cookie_consent.settings']['video_popup'] = $oe_webtools_cck_enabled;
 
         // In order to ensure that tests assert dates correctly even in edge cases, we
         // set the website default timezone to UTC and the same in tests too so that
diff --git a/tests/src/Context/FeatureContext.php b/tests/src/Context/FeatureContext.php
index 6c75b00d7fb9bf4a318d2a1c373859952fc3e5e8..9ab05b765a646080198e430f37b78937cf41cdb9 100644
--- a/tests/src/Context/FeatureContext.php
+++ b/tests/src/Context/FeatureContext.php
@@ -22,6 +22,7 @@
 use Drupal\Core\Entity\EntityChangedInterface;
 use Drupal\Core\Site\Settings;
 use Drupal\Driver\Exception\UnsupportedDriverActionException as UnsupportedDrupalDriverActionException;
+use Drupal\DrupalExtension\Context\ConfigContext;
 use Drupal\DrupalExtension\Context\RawDrupalContext;
 use Drupal\DrupalExtension\TagTrait;
 use Drupal\image\Plugin\Field\FieldType\ImageItem;
@@ -2245,39 +2246,15 @@ public function assertNoTagsInsideDiv(): void {
   }
 
   /**
-   * Disables cookie consent banner for all tests.
+   * Disable cookie consent for all scenarios unless tagged with @cookieConsent.
    *
-   * @BeforeSuite
-   */
-  public static function suiteDisableCookieConsent(): void {
-    touch(__DIR__ . '/../../../disable-cookie-consent');
-  }
-
-  /**
-   * Re-enables cookie consent banner after testing.
-   *
-   * @AfterSuite
-   */
-  public static function suiteEnableCookieConsent(): void {
-    @unlink(__DIR__ . '/../../../disable-cookie-consent');
-  }
-
-  /**
-   * Enables cookie consent banner for @cookieConsent test.
-   *
-   * @BeforeScenario @cookieConsent&&@api
-   */
-  public function scenarioEnableCookieConsent(): void {
-    @unlink(__DIR__ . '/../../../disable-cookie-consent');
-  }
-
-  /**
-   * Disables cookie consent banner after @cookieConsent test.
-   *
-   * @AfterScenario @cookieConsent&&@api
+   * @BeforeScenario ~@cookieConsent&&@api
    */
-  public function scenarioDisableCookieConsent(): void {
-    touch(__DIR__ . '/../../../disable-cookie-consent');
+  public function disableCookieConsent(): void {
+    $config_context = $this->getContext(ConfigContext::class);
+    $name = 'oe_webtools_cookie_consent.settings';
+    $config_context->setConfig($name, 'banner_popup', FALSE);
+    $config_context->setConfig($name, 'video_popup', FALSE);
   }
 
   /**
diff --git a/tests/src/Context/JoinupSearchContext.php b/tests/src/Context/JoinupSearchContext.php
index 49d2db9c33460accb54021f8f0aa639d55e4d6a2..efa9926dfd4fe443eb7d82cf2ad36380b32ef5e7 100644
--- a/tests/src/Context/JoinupSearchContext.php
+++ b/tests/src/Context/JoinupSearchContext.php
@@ -15,7 +15,6 @@
 use Drupal\joinup\Traits\SearchTrait;
 use Drupal\joinup\Traits\TraversingTrait;
 use Drupal\joinup\Traits\UtilityTrait;
-use Drupal\joinup_test\EventSubscriber\SearchApiFinishRequestSubscriber;
 use PHPUnit\Framework\Assert;
 
 /**
@@ -36,24 +35,6 @@ class JoinupSearchContext extends RawDrupalContext {
    */
   protected const SEARCH_BOX_DROPDOWN = '.joinup-navbar button#search-box-dropdown.dropdown-toggle';
 
-  /**
-   * Enable search_api indexing on finish request.
-   *
-   * @BeforeScenario
-   */
-  public function beforeScenarioFinishIndexing(): void {
-    \Drupal::state()->set(SearchApiFinishRequestSubscriber::STATE_KEY, TRUE);
-  }
-
-  /**
-   * Disable search_api indexing on finish request.
-   *
-   * @AfterScenario
-   */
-  public function afterScenarioFinishIndexing(): void {
-    \Drupal::state()->delete(SearchApiFinishRequestSubscriber::STATE_KEY);
-  }
-
   /**
    * Forces the indexing of new or changed content after each step.
    *
diff --git a/tests/src/Context/JsErrorsContext.php b/tests/src/Context/JsErrorsContext.php
new file mode 100644
index 0000000000000000000000000000000000000000..aa8685de55fbbbd36dae92589eb179197e60f677
--- /dev/null
+++ b/tests/src/Context/JsErrorsContext.php
@@ -0,0 +1,125 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\joinup\Context;
+
+use Behat\Behat\Hook\Scope\AfterScenarioScope;
+use Drupal\DrupalExtension\Context\RawDrupalContext;
+use Symfony\Component\Yaml\Yaml;
+use WebDriver\Exception\JavaScriptError;
+
+/**
+ * Context to report JS errors.
+ *
+ * Relies on js_testing_log.js injected from joinup_test.
+ * JS errors will throw exceptions; making behat fail.
+ * Drupal JS deprecations are logged in PHP (E_USER_DEPRECATED).
+ */
+class JsErrorsContext extends RawDrupalContext {
+
+  /**
+   * Constructs a new context.
+   *
+   * @param string[]|null $ignoredErrors
+   *   (Optional) A list of regex matching errors to ignore.
+   * @param string[]|null $ignoredWarnings
+   *   (Optional) A list of regex matching warnings to ignore.
+   */
+  public function __construct(
+    protected array $ignoredErrors = [],
+    protected array $ignoredWarnings = [],
+  ) {}
+
+  /**
+   * Prepares state.
+   *
+   * @beforeScenario @javascript
+   */
+  public function prepare(): void {
+    if (!$this->getSession()->isStarted()) {
+      return;
+    }
+
+    // Clear the session storage.
+    $this->getSession()->executeScript("['js_testing_log_test.errors', 'js_testing_log_test.warnings'].forEach(key => sessionStorage.removeItem(key))");
+  }
+
+  /**
+   * Reports JS warnings/errors, if any.
+   *
+   * @AfterScenario ~@js-errors&&@javascript
+   *
+   * @throws \WebDriver\Exception\JavaScriptError
+   */
+  public function report(AfterScenarioScope $scope): void {
+    if (!$this->getSession()->isStarted()) {
+      return;
+    }
+
+    // Get warnings/errors and clear them from storage.
+    $warnings = $this->getSession()->evaluateScript("JSON.parse(sessionStorage.getItem('js_testing_log_test.warnings') || JSON.stringify([]))");
+    $errors = $this->getSession()->evaluateScript("JSON.parse(sessionStorage.getItem('js_testing_log_test.errors') || JSON.stringify([]))");
+    $this->getSession()->executeScript("['js_testing_log_test.errors', 'js_testing_log_test.warnings'].forEach(key => sessionStorage.removeItem(key))");
+
+    // Report.
+    $this->reportWarnings($warnings, $scope);
+    $this->reportErrors($errors, $scope);
+  }
+
+  /**
+   * Reports JS warnings, if any.
+   */
+  public function reportWarnings(array $warnings, AfterScenarioScope $scope): void {
+    if ($this->ignoredWarnings) {
+      $warnings = array_filter($warnings, fn(string $warning): bool => !$this->matchPatterns($warning, $this->ignoredWarnings));
+    }
+
+    foreach ($warnings as $warning) {
+      if (str_starts_with($warning, '[Deprecation]')) {
+        $path = sprintf("%s:%d", $scope->getFeature()->getFile(), $scope->getScenario()->getLine());
+        @trigger_error(sprintf("%s\n  JS deprecation: %s", $path, substr($warning, 13)), E_USER_DEPRECATED);
+      }
+    }
+  }
+
+  /**
+   * Reports JS errors, if any.
+   *
+   * @throws \WebDriver\Exception\JavaScriptError
+   */
+  public function reportErrors(array $errors, AfterScenarioScope $scope): void {
+    if ($this->ignoredErrors) {
+      $errors = array_filter($errors, fn(string $error): bool => !$this->matchPatterns($error, $this->ignoredErrors));
+    }
+
+    if (!$errors) {
+      return;
+    }
+
+    $dump = Yaml::dump($errors, 30, 2, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK);
+    $path = sprintf("%s:%d", $scope->getFeature()->getFile(), $scope->getScenario()->getLine());
+    throw new JavaScriptError(sprintf("%s\n  Found %d javascript error(s)\n%s", $path, count($errors), $dump));
+  }
+
+  /**
+   * Check if the given string matches any of the regex patterns.
+   *
+   * @param string $subject
+   *   The string to check patterns against.
+   * @param string[] $patterns
+   *   Array of regex patterns.
+   *
+   * @return bool
+   *   True if it matches, false otherwise.
+   */
+  private function matchPatterns(string $subject, array $patterns): bool {
+    foreach ($patterns as $pattern) {
+      if (preg_match($pattern, $subject)) {
+        return TRUE;
+      }
+    }
+    return FALSE;
+  }
+
+}
diff --git a/tests/src/Traits/AntispamTrait.php b/tests/src/Traits/AntispamTrait.php
index 2a4fc8d9a734390aa8d4facab52531adf7b09d37..b1a9114bc7bf8f6fbda71def10b168b474e46bf2 100644
--- a/tests/src/Traits/AntispamTrait.php
+++ b/tests/src/Traits/AntispamTrait.php
@@ -4,6 +4,8 @@
 
 namespace Drupal\joinup\Traits;
 
+use Drupal\DrupalExtension\Context\ConfigContext;
+
 /**
  * Reusable code that allows switching Antibot & Honeypot functionality on/off.
  */
@@ -47,32 +49,14 @@ public function assertFormIsProtectedByHoneypot(): void {
   }
 
   /**
-   * Enable the anti-spam functionalities during @antispam tests.
-   *
-   * @BeforeScenario @antispam&&@api
-   */
-  public function enableAntispamBeforeScenarioStarts(): void {
-    \Drupal::state()->set('joinup_test.antispam.enabled', TRUE);
-    $this->clearCache();
-  }
-
-  /**
-   * Restores the anti-spam functionalities after @antispam tests.
+   * Disable anti-spam for all scenarios unless tagged with @antispam.
    *
-   * @AfterScenario @antispam&&@api
+   * @BeforeScenario ~@antispam&&@api
    */
-  public function disableAntispamAfterScenarioEnds(): void {
-    \Drupal::state()->delete('joinup_test.antispam.enabled');
-    $this->clearCache();
-  }
-
-  /**
-   * Clear the cache bins storing cached markup.
-   */
-  protected function clearCache(): void {
-    foreach (['page', 'dynamic_page_cache', 'render'] as $bin) {
-      \Drupal::cache($bin)->deleteAll();
-    }
+  public function disableAntispamBeforeScenarioStarts(): void {
+    $config_context = $this->getContext(ConfigContext::class);
+    $config_context->setConfig('antibot.settings', 'form_ids', NULL);
+    $config_context->setConfig('honeypot.settings', 'form_settings', []);
   }
 
 }
diff --git a/web/modules/custom/joinup_core/tests/src/ExistingSite/ConfigTest.php b/web/modules/custom/joinup_core/tests/src/ExistingSite/ConfigTest.php
index 3d7e1a2280c12a495d541c22d441ccb20bc5b409..e0c3778f9a1e0e99b58bf792de31074dcd01cab6 100644
--- a/web/modules/custom/joinup_core/tests/src/ExistingSite/ConfigTest.php
+++ b/web/modules/custom/joinup_core/tests/src/ExistingSite/ConfigTest.php
@@ -16,6 +16,11 @@ class ConfigTest extends JoinupExistingSiteTestBase {
 
   use DrushTestTrait;
 
+  /**
+   * {@inheritdoc}
+   */
+  protected bool $disableSpamProtection = FALSE;
+
   /**
    * Tests that the active and sync stores are the same.
    */
diff --git a/web/modules/custom/joinup_licence/js/comparator.js b/web/modules/custom/joinup_licence/js/comparator.js
index 4fd4dc1a1512ad9416b6da0085c5db1783b96eef..b398dcc8f0145ca731ba43346e737ba21bebd30b 100644
--- a/web/modules/custom/joinup_licence/js/comparator.js
+++ b/web/modules/custom/joinup_licence/js/comparator.js
@@ -44,7 +44,6 @@
         let licencesString = "";
         const maxCompare = 5;
         const licencesArray = [];
-        const licenceListing = document.querySelector(".listing--licences");
         let licenceName = "";
         document
           .querySelectorAll(".licence-tile .form-check-input[type='checkbox']")
@@ -61,10 +60,14 @@
               }
             }
           });
-        licenceListing.setAttribute(
-          "data-joinup-licence-compare",
-          licencesString,
-        );
+
+        const licenceListing = document.querySelector(".listing--licences");
+        if (licenceListing) {
+          licenceListing.setAttribute(
+            "data-joinup-licence-compare",
+            licencesString,
+          );
+        }
       }
 
       // Reset licence listing.
diff --git a/web/modules/custom/joinup_licence/js/filter.js b/web/modules/custom/joinup_licence/js/filter.js
index a32784c84bc6a47e9eb2b70716e53a6582b2e041..303e3742a8145912bc26509dd1545c2e6aa4c09a 100644
--- a/web/modules/custom/joinup_licence/js/filter.js
+++ b/web/modules/custom/joinup_licence/js/filter.js
@@ -80,16 +80,17 @@
         const licenceCounterNumber = document.querySelector(
           ".licence-counter__number",
         );
-        licenceCounterNumber.textContent = licenceTiles;
+        if (licenceCounterNumber) {
+          licenceCounterNumber.textContent = licenceTiles;
+        }
 
         // Use plural only if licences count is higher than one.
         const licenceCounterText = document.querySelector(
           ".licence-counter__text",
         );
-        if (licenceTiles === 1) {
-          licenceCounterText.textContent = "licence found";
-        } else {
-          licenceCounterText.textContent = "licences found";
+        if (licenceCounterText) {
+          licenceCounterText.textContent =
+            licenceTiles === 1 ? "licence found" : "licences found";
         }
       }
 
diff --git a/web/modules/custom/joinup_test/config/install/joinup_test.settings.yml b/web/modules/custom/joinup_test/config/install/joinup_test.settings.yml
new file mode 100644
index 0000000000000000000000000000000000000000..e3d839dfe6de056796850fb0f6ab39acdbcc2d48
--- /dev/null
+++ b/web/modules/custom/joinup_test/config/install/joinup_test.settings.yml
@@ -0,0 +1 @@
+test_mode: FALSE
diff --git a/web/modules/custom/joinup_test/config/schema/joinup_test.schema.yml b/web/modules/custom/joinup_test/config/schema/joinup_test.schema.yml
new file mode 100644
index 0000000000000000000000000000000000000000..02110d6238b3b5be363c746de7082ae50f8a8d00
--- /dev/null
+++ b/web/modules/custom/joinup_test/config/schema/joinup_test.schema.yml
@@ -0,0 +1,5 @@
+joinup_test.settings:
+  type: config_object
+  mapping:
+    test_mode:
+      type: boolean
diff --git a/web/modules/custom/joinup_test/joinup_test.libraries.yml b/web/modules/custom/joinup_test/joinup_test.libraries.yml
new file mode 100644
index 0000000000000000000000000000000000000000..1bbfe411076c573213060fc036b53bb9c0d07878
--- /dev/null
+++ b/web/modules/custom/joinup_test/joinup_test.libraries.yml
@@ -0,0 +1,13 @@
+# Relies on core js_testing_log_test.
+testing.js_errors_log:
+  header: true
+  js:
+    /core/modules/system/tests/modules/js_testing_log_test/js/js_testing_log.js: { weight: -1000 }
+
+# Relies on core css_disable_transitions_test.
+testing.css_disable_transitions:
+  css:
+    theme:
+      /core/modules/system/tests/modules/css_disable_transitions_test/css/disable_transitions.theme.css: { weight: 100 }
+  js:
+    /core/modules/system/tests/modules/css_disable_transitions_test/js/disable_transitions.theme.js: { }
diff --git a/web/modules/custom/joinup_test/joinup_test.module b/web/modules/custom/joinup_test/joinup_test.module
index 9fdac42cbd22c96b40bca01e353273d45427913b..2119489a3c0d02cf111a85ad080d27dce975bbf4 100644
--- a/web/modules/custom/joinup_test/joinup_test.module
+++ b/web/modules/custom/joinup_test/joinup_test.module
@@ -7,13 +7,40 @@
 
 declare(strict_types=1);
 
+use Drupal\Core\Cache\CacheableMetadata;
+use Drupal\joinup_test\Utils\TestUtils;
+
+/**
+ * Implements hook_page_attachments().
+ */
+function joinup_test_page_attachments(array &$attachments): void {
+  // Behat mode: cache metadata.
+  $settings = \Drupal::config('joinup_test.settings');
+  CacheableMetadata::createFromRenderArray($attachments)
+    ->addCacheableDependency($settings)
+    ->applyTo($attachments);
+
+  if (TestUtils::isTestMode()) {
+    // Attach JS errors collector and disable CSS animations.
+    $attachments['#attached']['library'][] = 'joinup_test/testing.js_errors_log';
+    $attachments['#attached']['library'][] = 'joinup_test/testing.css_disable_transitions';
+  }
+}
+
+/**
+ * Implements hook_js_settings_alter().
+ */
+function joinup_test_js_settings_alter(&$settings): void {
+  // Output JS deprecation warnings.
+  $settings['suppressDeprecationErrors'] = FALSE;
+}
+
 /**
  * Implements hook_config_schema_info_alter().
  */
 function joinup_test_config_schema_info_alter(&$definitions): void {
   if (isset($definitions['antibot.settings']['mapping']['form_ids'])) {
     // Required to pass config_inspector validation.
-    /* @see \Drupal\joinup_test\Config\JoinupTestConfigOverrider::loadOverrides */
     $definitions['antibot.settings']['mapping']['form_ids']['nullable'] = TRUE;
   }
 }
@@ -22,8 +49,10 @@ function joinup_test_config_schema_info_alter(&$definitions): void {
  * Implements hook_honeypot_form_protections_alter().
  */
 function joinup_test_honeypot_form_protections_alter(array &$options, array $form): void {
-  // Allow to disable anti-spam tools.
-  if (!\Drupal::state()->get('joinup_test.antispam.enabled', FALSE)) {
+  // Disable Honeypot entirely if form_settings is empty, used in behat.
+  /* @see \Drupal\joinup\Traits\AntispamTrait::disableAntispamBeforeScenarioStarts */
+  $honeypot_settings = \Drupal::config('honeypot.settings');
+  if (!$honeypot_settings->get('form_settings')) {
     $options = [];
   }
 }
diff --git a/web/modules/custom/joinup_test/joinup_test.services.yml b/web/modules/custom/joinup_test/joinup_test.services.yml
index 84ee5e54555bbec7d2c8551ba9d094aa45e71fa8..25172d0c121acceefeb3ca7fd17689bcacacde65 100644
--- a/web/modules/custom/joinup_test/joinup_test.services.yml
+++ b/web/modules/custom/joinup_test/joinup_test.services.yml
@@ -1,11 +1,6 @@
 services:
-  joinup_test.config_overrider:
-    class: Drupal\joinup_test\Config\JoinupTestConfigOverrider
-    arguments: ['@state', '@config.factory']
-    tags:
-      - { name: config.factory.override }
   joinup_test.search_api_finish_request_subscriber:
     class: Drupal\joinup_test\EventSubscriber\SearchApiFinishRequestSubscriber
-    arguments: ['@state', '@search_api.post_request_indexing']
+    arguments: ['@search_api.post_request_indexing']
     tags:
       - { name: event_subscriber }
diff --git a/web/modules/custom/joinup_test/src/Config/JoinupTestConfigOverrider.php b/web/modules/custom/joinup_test/src/Config/JoinupTestConfigOverrider.php
deleted file mode 100644
index b07f13fb16c00709fd0226045b378c46d908d921..0000000000000000000000000000000000000000
--- a/web/modules/custom/joinup_test/src/Config/JoinupTestConfigOverrider.php
+++ /dev/null
@@ -1,75 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-namespace Drupal\joinup_test\Config;
-
-use Drupal\Core\Cache\CacheableMetadata;
-use Drupal\Core\Config\ConfigFactoryInterface;
-use Drupal\Core\Config\ConfigFactoryOverrideInterface;
-use Drupal\Core\Config\StorableConfigBase;
-use Drupal\Core\Config\StorageInterface;
-use Drupal\Core\State\StateInterface;
-
-/**
- * Config overrider use to disable anti-spam guard.
- */
-class JoinupTestConfigOverrider implements ConfigFactoryOverrideInterface {
-
-  /**
-   * Constructs a new config overrider service instance.
-   *
-   * @param \Drupal\Core\State\StateInterface $state
-   *   The state service.
-   * @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory
-   *   The configuration factory service.
-   */
-  public function __construct(
-    protected StateInterface $state,
-    protected ConfigFactoryInterface $configFactory,
-  ) {
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function loadOverrides($names): array {
-    if (in_array('antibot.settings', $names, TRUE) && !$this->state->get('joinup_test.antispam.enabled', FALSE)) {
-      return [
-        'antibot.settings' => [
-          // We cannot set an empty array as the indexed arrays are merged, and
-          // we'll get again the list from storage.
-          // @see https://www.drupal.org/project/drupal/issues/2990549
-          'form_ids' => NULL,
-        ],
-      ];
-    }
-    return [];
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getCacheSuffix(): string {
-    return 'joinup_core';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function createConfigObject($name, $collection = StorageInterface::DEFAULT_COLLECTION): ?StorableConfigBase {
-    return NULL;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getCacheableMetadata($name): CacheableMetadata {
-    $metadata = new CacheableMetadata();
-    if ($name === 'antibot.settings') {
-      $metadata->addCacheableDependency($this->configFactory->get($name));
-    }
-    return $metadata;
-  }
-
-}
diff --git a/web/modules/custom/joinup_test/src/EventSubscriber/SearchApiFinishRequestSubscriber.php b/web/modules/custom/joinup_test/src/EventSubscriber/SearchApiFinishRequestSubscriber.php
index a30f162f74aea2d74dcf29acfd43b568d9c86ab2..1810adc9120fd0d083aaf4933589972ebdd96aa0 100644
--- a/web/modules/custom/joinup_test/src/EventSubscriber/SearchApiFinishRequestSubscriber.php
+++ b/web/modules/custom/joinup_test/src/EventSubscriber/SearchApiFinishRequestSubscriber.php
@@ -4,7 +4,7 @@
 
 namespace Drupal\joinup_test\EventSubscriber;
 
-use Drupal\Core\State\StateInterface;
+use Drupal\joinup_test\Utils\TestUtils;
 use Drupal\search_api\Utility\PostRequestIndexing;
 use Symfony\Component\EventDispatcher\EventSubscriberInterface;
 use Symfony\Component\HttpKernel\KernelEvents;
@@ -21,17 +21,14 @@
  */
 class SearchApiFinishRequestSubscriber implements EventSubscriberInterface {
 
-  const STATE_KEY = 'joinup_test.index_on_finish_request';
-
-  public function __construct(protected StateInterface $state, protected PostRequestIndexing $postRequestIndexing) {
+  public function __construct(protected PostRequestIndexing $postRequestIndexing) {
   }
 
   /**
    * Indexes items on FINISH_REQUEST, if specified.
    */
   public function onKernelFinishRequest(): void {
-    $is_active = $this->state->get(self::STATE_KEY, FALSE);
-    if ($is_active) {
+    if (TestUtils::isTestMode()) {
       $this->postRequestIndexing->destruct();
     }
   }
diff --git a/web/modules/custom/joinup_test/src/Utils/TestUtils.php b/web/modules/custom/joinup_test/src/Utils/TestUtils.php
new file mode 100644
index 0000000000000000000000000000000000000000..11b8ab79e321160624ebeb8d14381a8d28bdd06b
--- /dev/null
+++ b/web/modules/custom/joinup_test/src/Utils/TestUtils.php
@@ -0,0 +1,19 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\joinup_test\Utils;
+
+/**
+ * Contains utility methods.
+ */
+class TestUtils {
+
+  /**
+   * Whether we are in test mode or not.
+   */
+  public static function isTestMode(): bool {
+    return (bool) \Drupal::config('joinup_test.settings')->get('test_mode');
+  }
+
+}
diff --git a/web/modules/custom/joinup_test/tests/src/ExistingSite/JoinupExistingSiteTestBase.php b/web/modules/custom/joinup_test/tests/src/ExistingSite/JoinupExistingSiteTestBase.php
index 7a0eee15fec3122ed0fda0b73c5759999b83bee9..fa20ee2d0e6461fac1b3a785b8a0cffe09d448e3 100644
--- a/web/modules/custom/joinup_test/tests/src/ExistingSite/JoinupExistingSiteTestBase.php
+++ b/web/modules/custom/joinup_test/tests/src/ExistingSite/JoinupExistingSiteTestBase.php
@@ -7,6 +7,7 @@
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\Url;
+use Drupal\Tests\joinup_test\Traits\ConfigTestTrait;
 use Drupal\Tests\joinup_test\Traits\RdfEntityCreationTrait;
 use Drupal\taxonomy\VocabularyInterface;
 use weitzman\DrupalTestTraits\ExistingSiteBase;
@@ -25,6 +26,12 @@ abstract class JoinupExistingSiteTestBase extends ExistingSiteBase {
    */
   protected array $casUsers = [];
 
+  /**
+   * Whether to disable the spam protection.
+   */
+  protected bool $disableSpamProtection = TRUE;
+
+  use ConfigTestTrait;
   use RdfEntityCreationTrait;
 
   /**
@@ -34,17 +41,17 @@ protected function setUp(): void {
     parent::setUp();
 
     // Disable the spam protection functionality.
-    \Drupal::state()->delete('joinup_test.antispam.enabled');
-    $this->clearCache();
+    if ($this->disableSpamProtection) {
+      $this->overrideConfig('antibot.settings', 'form_ids', NULL);
+      $this->overrideConfig('honeypot.settings', 'form_settings', []);
+    }
   }
 
   /**
    * {@inheritdoc}
    */
   public function tearDown(): void {
-    // Restores the spam protection functionality.
-    \Drupal::state()->set('joinup_test.antispam.enabled', TRUE);
-    $this->clearCache();
+    $this->restoreOverriddenConfig();
 
     // Avoid sending notifications during test entities cleanup. First, sort the
     // entities by moving the 'user' entities at the end, as deleting a user
@@ -79,15 +86,6 @@ public function tearDown(): void {
     $delete_orphans_plugin->process();
   }
 
-  /**
-   * Clear the cache bins storing cached markup.
-   */
-  protected function clearCache(): void {
-    foreach (['page', 'dynamic_page_cache', 'render'] as $bin) {
-      \Drupal::cache($bin)->deleteAll();
-    }
-  }
-
   /**
    * {@inheritdoc}
    */
diff --git a/web/modules/custom/joinup_test/tests/src/Traits/ConfigTestTrait.php b/web/modules/custom/joinup_test/tests/src/Traits/ConfigTestTrait.php
index 54b1bd9a5686281b9676ac690307d4cfb21fd67c..8d5821a0296569253365f1c09e4451565036ef38 100644
--- a/web/modules/custom/joinup_test/tests/src/Traits/ConfigTestTrait.php
+++ b/web/modules/custom/joinup_test/tests/src/Traits/ConfigTestTrait.php
@@ -5,12 +5,27 @@
 namespace Drupal\Tests\joinup_test\Traits;
 
 use Drupal\Component\Serialization\Yaml;
+use Drupal\Core\Config\ConfigFactoryInterface;
 
 /**
  * Config reusable testing helper methods.
  */
 trait ConfigTestTrait {
 
+  /**
+   * Config factory under test.
+   *
+   * @var \Drupal\Core\Config\ConfigFactory
+   */
+  protected $configFactory;
+
+  /**
+   * Keep track of any config that was changed, so they can easily be reverted.
+   *
+   * @var array
+   */
+  protected array $originalConfig = [];
+
   /**
    * Returns config sync configuration data.
    *
@@ -49,4 +64,55 @@ protected function importConfigs(array $config_names): void {
     }
   }
 
+  /**
+   * Sets a value in a configuration object.
+   *
+   * @param string $name
+   *   The name of the configuration object.
+   * @param string $key
+   *   Identifier to store value in configuration.
+   * @param mixed $value
+   *   Value to associate with identifier.
+   */
+  protected function overrideConfig(string $name, string $key, mixed $value): void {
+    $config = $this->getConfigFactory()->getEditable($name);
+    $original = $config->get($key);
+    $config->set($key, $value)->save();
+    if (!array_key_exists($name, $this->originalConfig)) {
+      $this->originalConfig[$name][$key] = $original;
+      return;
+    }
+
+    if (!array_key_exists($key, $this->originalConfig[$name])) {
+      $this->originalConfig[$name][$key] = $original;
+    }
+  }
+
+  /**
+   * Restores original config.
+   */
+  protected function restoreOverriddenConfig(): void {
+    if (!$this->originalConfig) {
+      // Nothing to restore.
+      return;
+    }
+
+    foreach ($this->originalConfig as $name => $key_value) {
+      foreach ($key_value as $key => $value) {
+        $this->getConfigFactory()->getEditable($name)->set($key, $value)->save();
+      }
+    }
+    $this->originalConfig = [];
+  }
+
+  /**
+   * Get the config factory.
+   */
+  protected function getConfigFactory(): ConfigFactoryInterface {
+    if (!isset($this->configFactory)) {
+      $this->configFactory = $this->container->get('config.factory');
+    }
+    return $this->configFactory;
+  }
+
 }
diff --git a/web/themes/ventuno/assets/js/fieldset-show-more.min.js b/web/themes/ventuno/assets/js/fieldset-show-more.min.js
index 1db95e9035112b7e5d18a91dd39bccd652e76be2..a8fa01a31cec2e456ab1f00c594a8fa49ae339b4 100644
--- a/web/themes/ventuno/assets/js/fieldset-show-more.min.js
+++ b/web/themes/ventuno/assets/js/fieldset-show-more.min.js
@@ -1,2 +1,2 @@
-!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){"use strict";((e,t)=>{e.behaviors.fieldsetShowMore={attach(o){t("fieldset-show-more",document.querySelectorAll(".fieldset-show-more"),o).forEach((t=>{const o=t.querySelector(".fieldset-show-more__btn"),n=o.querySelector(".fieldset-show-more__btn-text"),i=e.t("Show more"),r=e.t("Show less");null!=o&&void 0!==n&&void 0!==n&&o.addEventListener("click",(function(){"true"===o.getAttribute("aria-expanded")?n.textContent=r:n.textContent=i}))}))}}})(Drupal,once)}));
+!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){"use strict";((e,t)=>{e.behaviors.fieldsetShowMore={attach(o){t("fieldset-show-more",document.querySelectorAll(".fieldset-show-more"),o).forEach((t=>{const o=t.querySelector(".fieldset-show-more__btn"),n=o?o.querySelector(".fieldset-show-more__btn-text"):null;o&&n&&o.addEventListener("click",(()=>{n.textContent="true"===o.getAttribute("aria-expanded")?e.t("Show less"):e.t("Show more")}))}))}}})(Drupal,once)}));
 //# sourceMappingURL=fieldset-show-more.min.js.map
diff --git a/web/themes/ventuno/assets/js/sticky-groupheader.min.js b/web/themes/ventuno/assets/js/sticky-groupheader.min.js
index 4df748a0cf50779a1bce60ca26d430aa9a9e89de..51a858a730b016e99131661db7be81a6ca7c42f0 100644
--- a/web/themes/ventuno/assets/js/sticky-groupheader.min.js
+++ b/web/themes/ventuno/assets/js/sticky-groupheader.min.js
@@ -1,2 +1,2 @@
-!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){"use strict";((e,t,s,r)=>{const i="#block-ventuno-groupheader",n=".region-header",o=".region-header__inner",h=".joinup-navbar",a="html";class c{constructor(e){this.navbar=e.querySelector(h),this.header=e.querySelector(n),this.headerInner=e.querySelector(o),this.html=e.querySelector(a),this.scrollPT=0,this.isSticky=!1,this.observer=null}init(){this.navbar&&this.header&&this.headerInner&&this.html&&(this.scrollPT=parseInt(this.html.style.scrollPaddingTop,10)||0,this.navbar.classList.remove("navbar--sticky"),this.navbar.classList.add("position-static"),this.updateObserver())}updateObserver(){this.observer&&(this.observer.disconnect(),this.observer=null),this.observer=new IntersectionObserver((e=>{e.forEach((e=>{this.onIntersect(!e.isIntersecting)}))}),{rootMargin:`-${t.offsets.top}px 0px 0px -${t.offsets.left}px`}),this.observer.observe(this.navbar)}onIntersect(e){if(this.isSticky!==e){const s=!this.isSticky&&e,r=this.headerInner.offsetHeight;this.header.style.height=s?`${r}px`:null;const i=s?t.offsets.top+r:0;this.html.style.scrollPaddingTop=`${this.scrollPT+i}px`,this.headerInner.classList.toggle("fixed-top",s),this.isSticky=e}}}e.behaviors.stickyGroupHeader={attach(e){s("sticky-group-header",i,e).forEach((()=>{const t=new c(e);t.init(),r(e).on("drupalViewportOffsetChange",(()=>{t.updateObserver()}))}))}}})(Drupal,Drupal.displace,once,jQuery)}));
+!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){"use strict";((e,t,s,r)=>{const i="#block-ventuno-groupheader",n=".region-header",o=".region-header__inner",h=".joinup-navbar",a="html";class c{constructor(e){this.context=e,this.navbar=e.querySelector(h),this.header=e.querySelector(n),this.headerInner=e.querySelector(o),this.html=e.querySelector(a),this.scrollPT=0,this.isSticky=!1,this.observer=null}init(){this.navbar&&this.header&&this.headerInner&&this.html&&(this.scrollPT=parseInt(this.html.style.scrollPaddingTop,10)||0,this.navbar.classList.remove("navbar--sticky"),this.navbar.classList.add("position-static"),this.updateObserver(),r(this.context).on("drupalViewportOffsetChange",(()=>{this.updateObserver()})))}updateObserver(){this.observer&&(this.observer.disconnect(),this.observer=null),this.observer=new IntersectionObserver((e=>{e.forEach((e=>{this.onIntersect(!e.isIntersecting)}))}),{rootMargin:`-${t.offsets.top}px 0px 0px -${t.offsets.left}px`}),this.observer.observe(this.navbar)}onIntersect(e){if(this.isSticky!==e){const s=!this.isSticky&&e,r=this.headerInner.offsetHeight;this.header.style.height=s?`${r}px`:null;const i=s?t.offsets.top+r:0;this.html.style.scrollPaddingTop=`${this.scrollPT+i}px`,this.headerInner.classList.toggle("fixed-top",s),this.isSticky=e}}}e.behaviors.stickyGroupHeader={attach(e){s("sticky-group-header",i,e).forEach((()=>{new c(e).init()}))}}})(Drupal,Drupal.displace,once,jQuery)}));
 //# sourceMappingURL=sticky-groupheader.min.js.map
diff --git a/web/themes/ventuno/src/js/fieldset-show-more.js b/web/themes/ventuno/src/js/fieldset-show-more.js
index ce4bf9bcdedc73572a9a7e4baaf95a03c17954d5..c72b2030a1a92e45dff2c7fd28ff102db0a7266f 100644
--- a/web/themes/ventuno/src/js/fieldset-show-more.js
+++ b/web/themes/ventuno/src/js/fieldset-show-more.js
@@ -15,26 +15,19 @@
       // Ensures "Show more" functionality in case there are multiple fieldsets
       fieldsets.forEach((fieldset) => {
         const btn = fieldset.querySelector(".fieldset-show-more__btn");
-        const btnText = btn.querySelector(".fieldset-show-more__btn-text");
-        const textMore = Drupal.t("Show more");
-        const textLess = Drupal.t("Show less");
-        function updateContent() {
-          // Uses "aria-expanded" attribute to know the state of the collapse
-          if (btn.getAttribute("aria-expanded") === "true") {
-            btnText.textContent = textLess;
-          } else {
-            btnText.textContent = textMore;
-          }
-        }
-        if (
-          btn === null ||
-          btn === undefined ||
-          btnText === undefined ||
-          btnText === undefined
-        ) {
-          return;
+        const btnText = btn
+          ? btn.querySelector(".fieldset-show-more__btn-text")
+          : null;
+
+        if (btn && btnText) {
+          btn.addEventListener("click", () => {
+            // Uses "aria-expanded" attribute to know the state of the collapse
+            btnText.textContent =
+              btn.getAttribute("aria-expanded") === "true"
+                ? Drupal.t("Show less")
+                : Drupal.t("Show more");
+          });
         }
-        btn.addEventListener("click", updateContent);
       });
     },
   };
diff --git a/web/themes/ventuno/src/js/sticky-groupheader.js b/web/themes/ventuno/src/js/sticky-groupheader.js
index f4ac8da4c5ca7a0f9dcfccd8d051cdc7fc7fe5fa..7f7a0952862d090420d0180bb59d901612d04bb2 100644
--- a/web/themes/ventuno/src/js/sticky-groupheader.js
+++ b/web/themes/ventuno/src/js/sticky-groupheader.js
@@ -22,6 +22,7 @@
 
   class StickyGroupHeader {
     constructor(context) {
+      this.context = context;
       this.navbar = context.querySelector(SELECTORS.NAVBAR);
       this.header = context.querySelector(SELECTORS.HEADER);
       this.headerInner = context.querySelector(SELECTORS.HEADER_INNER);
@@ -46,6 +47,12 @@
 
       // Init the observer.
       this.updateObserver();
+
+      // Refresh the observer when Drupal.displace offsets change, for new
+      // rootMargin's to take effect.
+      $(this.context).on("drupalViewportOffsetChange", () => {
+        this.updateObserver();
+      });
     }
 
     /**
@@ -108,12 +115,6 @@
         () => {
           const stickyHeader = new StickyGroupHeader(context);
           stickyHeader.init();
-
-          // Refresh the observer when Drupal.displace offsets change, for new
-          // rootMargin's to take effect.
-          $(context).on("drupalViewportOffsetChange", () => {
-            stickyHeader.updateObserver();
-          });
         },
       );
     },