diff --git a/behat.yml.dist b/behat.yml.dist
index aa081c1bb1bb8a6294840cbc5aea8d606e69a91a..59258ee2d26d5957417fa93dbff25932e4f8bc03 100644
--- a/behat.yml.dist
+++ b/behat.yml.dist
@@ -111,6 +111,7 @@ default:
       api_driver: 'drupal'
       blackbox: ~
       region_map:
+        Additional fields accordion: '#additional-fields'
         Administration toolbar: '#toolbar-administration'
         Comment: '.comments-section'
         Contact information inline form: '#edit-field-ar-contact-information-wrapper'
@@ -128,6 +129,7 @@ default:
         Highlighted event: '.block-entityqueue--highlighted-event'
         In the spotlight: '.block-views-blockin-the-spotlight-block'
         Left sidebar: '.section--sidebar-left'
+        Main fields accordion: '#main-fields'
         Main solution vertical tab: '#edit-group-main'
         Management solution vertical tab: '#edit-group-management'
         Members admin form actions: '#edit-action'
diff --git a/config/sync/block.block.ventuno_groupheader.yml b/config/sync/block.block.ventuno_groupheader.yml
index 2aaa08fc55ed39ec175b1b4d529c58c403f92547..5dadd079b9e0d0b2687317796c13d3eb2da1b3bb 100644
--- a/config/sync/block.block.ventuno_groupheader.yml
+++ b/config/sync/block.block.ventuno_groupheader.yml
@@ -4,6 +4,7 @@ status: true
 dependencies:
   module:
     - joinup
+    - joinup_core
   theme:
     - ventuno
 _core:
@@ -20,5 +21,10 @@ settings:
   label_display: '0'
   provider: joinup
   context_mapping:
-    og: '@og.context:og'
-visibility: {  }
+    og: '@asset_release.asset_release_route_context:asset_release'
+visibility:
+  request_route:
+    id: request_route
+    negate: true
+    routes:
+      - entity.rdf_entity.edit_form
diff --git a/config/sync/block.block.ventuno_joinup_add_content.yml b/config/sync/block.block.ventuno_joinup_add_content.yml
index 4bcbb0a0fa61f0e75453ca2a5faae607b8d5df88..b5a35517d7759a7cd7cd86c7330c5d4f28bff731 100644
--- a/config/sync/block.block.ventuno_joinup_add_content.yml
+++ b/config/sync/block.block.ventuno_joinup_add_content.yml
@@ -3,6 +3,7 @@ langcode: en
 status: true
 dependencies:
   module:
+    - joinup_core
     - joinup_group
     - og
   theme:
@@ -19,7 +20,7 @@ settings:
   id: add_content_block
   label: 'Add content'
   label_display: visible
-  provider: joinup
+  provider: joinup_group
   context_mapping:
     og: '@og.context:og'
 visibility:
@@ -31,3 +32,8 @@ visibility:
     group_types:
       rdf_entity-collection: rdf_entity-collection
       rdf_entity-solution: rdf_entity-solution
+  request_route:
+    id: request_route
+    negate: true
+    routes:
+      - entity.rdf_entity.edit_form
diff --git a/config/sync/block.block.ventuno_navigation.yml b/config/sync/block.block.ventuno_navigation.yml
index aa51ac01984ba7c4ef8dee799c355eb49016a854..8fcf9d46e94c1f4a7e77847b6344b42c2e2f4705 100644
--- a/config/sync/block.block.ventuno_navigation.yml
+++ b/config/sync/block.block.ventuno_navigation.yml
@@ -5,6 +5,7 @@ dependencies:
   config:
     - og_menu.ogmenu.navigation
   module:
+    - joinup_core
     - joinup_group
     - og
   theme:
@@ -19,7 +20,7 @@ settings:
   id: 'group_menu_block:navigation'
   label: 'Collection | Solution menu'
   label_display: '0'
-  provider: joinup_core
+  provider: joinup_group
   context_mapping:
     og: '@og.context:og'
   level: 1
@@ -33,3 +34,8 @@ visibility:
     group_types:
       rdf_entity-collection: rdf_entity-collection
       rdf_entity-solution: rdf_entity-solution
+  request_route:
+    id: request_route
+    negate: true
+    routes:
+      - entity.rdf_entity.edit_form
diff --git a/config/sync/block.block.ventuno_three_dots_menu.yml b/config/sync/block.block.ventuno_three_dots_menu.yml
index 9690cdb75916310898e1929e5b5e9f567f74a2fb..bf35c4cd600d8d207e330628b95e153a4904bbcf 100644
--- a/config/sync/block.block.ventuno_three_dots_menu.yml
+++ b/config/sync/block.block.ventuno_three_dots_menu.yml
@@ -2,6 +2,8 @@ uuid: c431d6ac-f6d0-4be7-80a8-2b7746dd7a6f
 langcode: en
 status: true
 dependencies:
+  module:
+    - joinup_core
   theme:
     - ventuno
 id: ventuno_three_dots_menu
@@ -17,4 +19,9 @@ settings:
   provider: core
   primary: true
   secondary: false
-visibility: {  }
+visibility:
+  request_route:
+    id: request_route
+    negate: true
+    routes:
+      - entity.rdf_entity.edit_form
diff --git a/config/sync/core.entity_form_display.rdf_entity.collection.default.yml b/config/sync/core.entity_form_display.rdf_entity.collection.default.yml
index 0e51d645e43ee9eaaf11fa4bf34939c0a25ad974..159bec3d56d9f7792c4d32b6f0a92dc2afd443bb 100644
--- a/config/sync/core.entity_form_display.rdf_entity.collection.default.yml
+++ b/config/sync/core.entity_form_display.rdf_entity.collection.default.yml
@@ -19,10 +19,10 @@ dependencies:
     - field.field.rdf_entity.collection.field_collection_content
     - field.field.rdf_entity.collection.field_keywords
     - field.field.rdf_entity.collection.field_newsletter
-    - field.field.rdf_entity.collection.field_topic
     - field.field.rdf_entity.collection.field_short_id
     - field.field.rdf_entity.collection.field_site_featured
     - field.field.rdf_entity.collection.field_spatial_coverage
+    - field.field.rdf_entity.collection.field_topic
     - image.style.thumbnail
     - media.type.collection_logo
     - rdf_entity.rdfentity.collection
@@ -42,16 +42,16 @@ third_party_settings:
       children:
         - group_main
         - group_description
-        - field_ar_state
       label: General
       region: content
       parent_name: ''
       weight: 0
-      format_type: tabs
+      format_type: accordion
       format_settings:
         classes: ''
+        show_empty_fields: false
         id: ''
-        direction: vertical
+        effect: none
     group_main:
       children:
         - label
@@ -66,12 +66,12 @@ third_party_settings:
       region: content
       parent_name: group_general
       weight: 6
-      format_type: tab
+      format_type: accordion_item
       format_settings:
         classes: ''
+        show_empty_fields: false
         id: ''
         formatter: open
-        description: 'Contains all the fields to be mandatorily filled to create a collection'
         required_fields: true
     group_description:
       children:
@@ -85,16 +85,17 @@ third_party_settings:
         - field_ar_closed
         - field_ar_content_creation
         - field_newsletter
+        - field_collection_content
       label: 'Additional fields'
       region: content
       parent_name: group_general
       weight: 7
-      format_type: tab
+      format_type: accordion_item
       format_settings:
         classes: ''
+        show_empty_fields: false
         id: ''
         formatter: closed
-        description: 'Contains all optional fields providing additional information on the collection'
         required_fields: true
 id: rdf_entity.collection.default
 targetEntityType: rdf_entity
@@ -141,7 +142,7 @@ content:
     third_party_settings: {  }
   field_ar_closed:
     type: boolean_checkbox
-    weight: 18
+    weight: 17
     region: content
     settings:
       display_label: false
@@ -165,7 +166,7 @@ content:
     third_party_settings: {  }
   field_ar_content_creation:
     type: options_buttons
-    weight: 19
+    weight: 18
     region: content
     settings: {  }
     third_party_settings: {  }
@@ -192,7 +193,7 @@ content:
     third_party_settings: {  }
   field_ar_moderation:
     type: boolean_checkbox
-    weight: 17
+    weight: 16
     region: content
     settings:
       display_label: false
@@ -223,7 +224,7 @@ content:
     third_party_settings: {  }
   field_collection_content:
     type: search_api_field_default
-    weight: 1
+    weight: 20
     region: content
     settings:
       query_builder: false
@@ -238,7 +239,7 @@ content:
     third_party_settings: {  }
   field_newsletter:
     type: oe_newsroom_newsletter_default
-    weight: 20
+    weight: 19
     region: content
     settings: {  }
     third_party_settings: {  }
diff --git a/config/sync/core.entity_form_display.rdf_entity.collection.propose.yml b/config/sync/core.entity_form_display.rdf_entity.collection.propose.yml
index 2b9754c4d596aaf3055492982fa64e1d43cf96eb..d7b86593f2fa91587bc959449b65819cc81c5994 100644
--- a/config/sync/core.entity_form_display.rdf_entity.collection.propose.yml
+++ b/config/sync/core.entity_form_display.rdf_entity.collection.propose.yml
@@ -20,10 +20,10 @@ dependencies:
     - field.field.rdf_entity.collection.field_collection_content
     - field.field.rdf_entity.collection.field_keywords
     - field.field.rdf_entity.collection.field_newsletter
-    - field.field.rdf_entity.collection.field_topic
     - field.field.rdf_entity.collection.field_short_id
     - field.field.rdf_entity.collection.field_site_featured
     - field.field.rdf_entity.collection.field_spatial_coverage
+    - field.field.rdf_entity.collection.field_topic
     - image.style.thumbnail
     - media.type.collection_logo
     - rdf_entity.rdfentity.collection
@@ -45,11 +45,12 @@ third_party_settings:
       region: content
       parent_name: ''
       weight: 0
-      format_type: tabs
+      format_type: accordion
       format_settings:
         classes: ''
+        show_empty_fields: false
         id: ''
-        direction: vertical
+        effect: none
     group_main:
       children:
         - label
@@ -63,12 +64,12 @@ third_party_settings:
       region: content
       parent_name: group_general
       weight: 5
-      format_type: tab
+      format_type: accordion_item
       format_settings:
         classes: ''
+        show_empty_fields: false
         id: ''
         formatter: open
-        description: 'Contains all the fields to be mandatorily filled to create a collection'
         required_fields: true
     group_description:
       children:
@@ -85,12 +86,12 @@ third_party_settings:
       region: content
       parent_name: group_general
       weight: 6
-      format_type: tab
+      format_type: accordion_item
       format_settings:
         classes: ''
+        show_empty_fields: false
         id: ''
         formatter: closed
-        description: 'Contains all optional fields providing additional information on the collection'
         required_fields: true
 _core:
   default_config_hash: sZ7uqiT2tsjscaEeNtBA28aEOnVEi4XiH_rJHHWbIWA
diff --git a/config/sync/core.entity_form_display.rdf_entity.solution.default.yml b/config/sync/core.entity_form_display.rdf_entity.solution.default.yml
index 8846f81dcb7b69d55b0a16f24ae1bcde1cc6f241..5ae68ae6226193672d521688c283eeae419a6a97 100644
--- a/config/sync/core.entity_form_display.rdf_entity.solution.default.yml
+++ b/config/sync/core.entity_form_display.rdf_entity.solution.default.yml
@@ -40,11 +40,11 @@ dependencies:
     - field.field.rdf_entity.solution.field_is_webdav_url
     - field.field.rdf_entity.solution.field_is_wiki
     - field.field.rdf_entity.solution.field_keywords
-    - field.field.rdf_entity.solution.field_topic
     - field.field.rdf_entity.solution.field_short_id
     - field.field.rdf_entity.solution.field_site_featured
     - field.field.rdf_entity.solution.field_spatial_coverage
     - field.field.rdf_entity.solution.field_status
+    - field.field.rdf_entity.solution.field_topic
     - image.style.thumbnail
     - media.type.solution_logo
     - rdf_entity.rdfentity.solution
@@ -67,11 +67,12 @@ third_party_settings:
       region: content
       parent_name: ''
       weight: 0
-      format_type: tabs
+      format_type: accordion
       format_settings:
         classes: ''
+        show_empty_fields: false
         id: ''
-        direction: vertical
+        effect: none
     group_main:
       children:
         - label
@@ -95,12 +96,12 @@ third_party_settings:
       region: content
       parent_name: group_general
       weight: 20
-      format_type: tab
+      format_type: accordion_item
       format_settings:
         classes: ''
+        show_empty_fields: false
         id: ''
         formatter: open
-        description: 'Contains all the fields to be mandatorily filled to create a solution'
         required_fields: true
     group_management:
       children:
@@ -121,12 +122,12 @@ third_party_settings:
       region: content
       parent_name: group_general
       weight: 21
-      format_type: tab
+      format_type: accordion_item
       format_settings:
         classes: ''
+        show_empty_fields: false
         id: ''
         formatter: closed
-        description: 'Contains all optional fields providing additional information on the solution'
         required_fields: true
 id: rdf_entity.solution.default
 targetEntityType: rdf_entity
diff --git a/config/sync/theme_rule.rule.collection_propose_form.yml b/config/sync/theme_rule.rule.collection_propose_form.yml
new file mode 100644
index 0000000000000000000000000000000000000000..9389c74745580ef9c1668b8045b8692043031856
--- /dev/null
+++ b/config/sync/theme_rule.rule.collection_propose_form.yml
@@ -0,0 +1,18 @@
+uuid: 1e6ae1c0-d6fc-4d23-9d1b-b359b99ed7f6
+langcode: en
+status: true
+dependencies:
+  module:
+    - joinup_core
+  theme:
+    - ventuno
+id: collection_propose_form
+label: 'Collection propose form'
+theme: ventuno
+weight: 0
+conditions:
+  request_route:
+    id: request_route
+    negate: false
+    routes:
+      - rdf_entity.propose_form
diff --git a/config/sync/theme_rule.rule.solution_add_form.yml b/config/sync/theme_rule.rule.solution_add_form.yml
new file mode 100644
index 0000000000000000000000000000000000000000..7c7a4096386926d210bcfa2b55f3108ec463a026
--- /dev/null
+++ b/config/sync/theme_rule.rule.solution_add_form.yml
@@ -0,0 +1,18 @@
+uuid: 57aaff61-1262-4b1a-99a7-aa7a6c2d9f29
+langcode: en
+status: true
+dependencies:
+  module:
+    - joinup_core
+  theme:
+    - ventuno
+id: solution_add_form
+label: 'Solution add form'
+theme: ventuno
+weight: 0
+conditions:
+  request_route:
+    id: request_route
+    negate: false
+    routes:
+      - solution.collection_solution.add
diff --git a/config/sync/theme_rule.rule.solution_and_collection_edit_forms.yml b/config/sync/theme_rule.rule.solution_and_collection_edit_forms.yml
new file mode 100644
index 0000000000000000000000000000000000000000..83a196783b1711c6ec6d3520f56f31542d8184be
--- /dev/null
+++ b/config/sync/theme_rule.rule.solution_and_collection_edit_forms.yml
@@ -0,0 +1,18 @@
+uuid: 402cef65-285f-4a2c-87ef-f0e51240e9de
+langcode: en
+status: true
+dependencies:
+  module:
+    - joinup_core
+  theme:
+    - ventuno
+id: solution_and_collection_edit_forms
+label: 'Solution and Collection edit forms'
+theme: ventuno
+weight: 0
+conditions:
+  request_route:
+    id: request_route
+    negate: false
+    routes:
+      - entity.rdf_entity.edit_form
diff --git a/tests/features/collection/collection.moderation.feature b/tests/features/collection/collection.moderation.feature
index 1cfab030bfc5064462ba4e2cf9d1451212464a42..c5a131452568b4f30bcad8adc052110e6c5cba91 100644
--- a/tests/features/collection/collection.moderation.feature
+++ b/tests/features/collection/collection.moderation.feature
@@ -213,7 +213,7 @@ Feature: Collection moderation
     Given I am logged in as a user with the "authenticated" role
     # Propose a collection, filling in the required fields.
     When I go to the propose collection form
-    Then the "Main fields" tab should be active
+    Then the "Main fields" accordion item should be active
     # @todo The summaries are no longer visible since we migrated to Drupal 9.
     #   Restore these when ISAICP-6963 is fixed.
     # And the "Main fields" tab summary should be "Contains all the fields to be mandatorily filled to create a collection"
@@ -225,16 +225,19 @@ Feature: Collection moderation
       | E-mail | fog@example.com        |
     And I enter "The samurai are attacking the railroads" in the "Description" wysiwyg editor
     And I select "Employment and Support Allowance" from "Topic"
+    And I scroll "Owner" into view
     And I press "Add new" at the "Owner" field
     And I wait for AJAX to finish
     And I fill in "Name" with "Katsumoto"
     And I check the box "Academia/Scientific organisation"
-    And I click the "Additional fields" tab
-    Then the "Additional fields" tab should be active
+    And I scroll "Additional fields" into view
+    And I press "Additional fields"
+    Then the "Additional fields" accordion item should be active
     And I attach the file "logo.png" to "Logo"
     And I wait for AJAX to finish
     And I attach the file "banner.jpg" to "Banner"
     And I wait for AJAX to finish
+    And I scroll "Content creation" into view
     And I select the radio button "Any user can create content."
 
     # Regression test for a bug that caused the content creation setting to be
@@ -242,7 +245,8 @@ Feature: Collection moderation
     # Note that this is an issue that affected the legacy eLibrary slider which
     # has been replaced with the Content creation radio buttons, but we are
     # keeping the coverage for now.
-    When I press "Add another item" at the "Geographical coverage" field
+    When I scroll "Geographical coverage" into view
+    And I press "Add another item" at the "Geographical coverage" field
     And I wait for AJAX to finish
     Then the radio button "Any user can create content." from field "Content creation" should be selected
 
@@ -254,14 +258,16 @@ Feature: Collection moderation
     And I go to the homepage of the "Spectres in fog" collection
     And I open the header local tasks menu
     And I click "Edit" in the "Entity actions" region
-    And I click the "Additional fields" tab
+    And I scroll "Additional fields" into view
+    And I press "Additional fields"
     Then the radio button "Any user can create content." from field "Content creation" should be selected
     # Also when saving and reopening the edit form the content creation option
     # should remain unchanged.
     When I press "Publish"
     And I open the header local tasks menu
     And I click "Edit" in the "Entity actions" region
-    And I click the "Additional fields" tab
+    And I press "Main fields"
+    And I press "Additional fields"
     Then the radio button "Any user can create content." from field "Content creation" should be selected
 
     # Clean up the entities that were created.
@@ -286,15 +292,20 @@ Feature: Collection moderation
     And I enter "Yaks and goats are friendly pets." in the "Description" wysiwyg editor
     And I select "Statistics and Analysis" from "Topic"
     # An ajax callback is executed now.
+    And I scroll "Owner" into view
     And I press "Add new" at the "Owner" field
     And I wait for AJAX to finish
     And I fill in "Name" with "Garnett Clifton"
+    And I scroll "Contact information" into view
     And I check the box "Supra-national authority"
-    And I click the "Additional fields" tab
+    And I scroll "Additional fields" into view
+    And I press "Additional fields"
+    And I scroll "Logo" into view
     And I attach the file "logo.png" to "Logo"
     And I wait for AJAX to finish
     And I attach the file "banner.jpg" to "Banner"
     And I wait for AJAX to finish
+    And I scroll "Content creation" into view
     And I select the radio button "Any user can create content."
 
     # Save the collection.
@@ -303,7 +314,8 @@ Feature: Collection moderation
     # Edit again.
     When I open the header local tasks menu
     And I click "Edit" in the "Entity actions" region
-    And I click the "Additional fields" tab
+    And I press "Main fields"
+    And I press "Additional fields"
     Then the radio button "Any user can create content." from field "Content creation" should be selected
 
     # Clean up the entities that were created.
@@ -328,15 +340,19 @@ Feature: Collection moderation
     And I enter "Kleptomaniac to the bone." in the "Description" wysiwyg editor
     And I select "Supplier exchange" from "Topic"
     # An ajax callback is executed now.
+    And I scroll "Owner" into view
     And I press "Add new" at the "Owner" field
     And I wait for AJAX to finish
     And I fill in "Name" with "Coretta Simonson"
+    And I scroll "Type" into view
     And I check the box "Private Individual(s)"
-    And I click the "Additional fields" tab
+    And I scroll "Additional fields" into view
+    And I press "Additional fields"
     And I attach the file "logo.png" to "Logo"
     And I wait for AJAX to finish
     And I attach the file "banner.jpg" to "Banner"
     And I wait for AJAX to finish
+    And I scroll "Content creation" into view
     And I select the radio button "Only facilitators and authors can create content."
 
     # Save the collection.
@@ -345,7 +361,8 @@ Feature: Collection moderation
     # Edit again.
     When I open the header local tasks menu
     And I click "Edit" in the "Entity actions" region
-    And I click the "Additional fields" tab
+    And I press "Main fields"
+    And I press "Additional fields"
     Then the radio button "Only facilitators and authors can create content." from field "Content creation" should be selected
 
     # Clean up the entities that were created.
@@ -371,17 +388,22 @@ Feature: Collection moderation
     And I enter "So smooth." in the "Description" wysiwyg editor
     And I select "Data gathering, data processing" from "Topic"
     # An ajax callback is executed now.
+    And I scroll "Owner" into view
     And I press "Add new" at the "Owner" field
     And I wait for AJAX to finish
     And I fill in "Name" with "Terrance Nash"
+    And I scroll "Type" into view
     And I check the box "Regional authority"
-    And I click the "Additional fields" tab
+    And I scroll "Additional fields" into view
+    And I press "Additional fields"
     And I attach the file "logo.png" to "Logo"
     And I wait for AJAX to finish
     And I attach the file "banner.jpg" to "Banner"
     And I wait for AJAX to finish
+    And I scroll "Geographical coverage" into view
     When I press "Add another item" at the "Geographical coverage" field
     And I wait for AJAX to finish
+    And I scroll "Content creation" into view
     And I select the radio button "Only facilitators and authors can create content."
 
     # Save the collection.
@@ -390,7 +412,8 @@ Feature: Collection moderation
     # Edit again.
     When I open the header local tasks menu
     And I click "Edit" in the "Entity actions" region
-    And I click the "Additional fields" tab
+    And I press "Main fields"
+    And I press "Additional fields"
     Then the radio button "Only facilitators and authors can create content." from field "Content creation" should be selected
 
     # Clean up the entities that were created.
@@ -415,18 +438,23 @@ Feature: Collection moderation
     And I enter "Invisible ships on deep sea." in the "Description" wysiwyg editor
     And I select "Employment and Support Allowance" from "Topic"
     # An ajax callback is executed now.
+    And I scroll "Owner" into view
     And I press "Add new" at the "Owner" field
     And I wait for AJAX to finish
     And I fill in "Name" with "Mable Pelley"
+    And I scroll "Type" into view
     And I check the box "National authority"
-    And I click the "Additional fields" tab
+    And I scroll "Additional fields" into view
+    And I press "Additional fields"
     And I attach the file "logo.png" to "Logo"
     And I wait for AJAX to finish
     And I attach the file "banner.jpg" to "Banner"
     And I wait for AJAX to finish
+    And I scroll "Content creation" into view
     And I select the radio button "Only facilitators and authors can create content."
 
-    When I press "Add another item" at the "Geographical coverage" field
+    When I scroll "Geographical coverage" into view
+    And I press "Add another item" at the "Geographical coverage" field
     And I wait for AJAX to finish
 
     # Save the collection.
@@ -435,7 +463,8 @@ Feature: Collection moderation
     # Edit again.
     When I open the header local tasks menu
     And I click "Edit" in the "Entity actions" region
-    And I click the "Additional fields" tab
+    And I press "Main fields"
+    And I press "Additional fields"
     Then the radio button "Only facilitators and authors can create content." from field "Content creation" should be selected
 
     # Clean up the entities that were created.
diff --git a/tests/features/collection/newsletter_subscription.feature b/tests/features/collection/newsletter_subscription.feature
index 25c217968478aef365983bd7552b5ad1de1578e1..ffe67860b6c0401395bf4f27f5413452935b8a4f 100644
--- a/tests/features/collection/newsletter_subscription.feature
+++ b/tests/features/collection/newsletter_subscription.feature
@@ -92,7 +92,9 @@ Feature: Subscribing to collection newsletters
     When I go to the "Volkor X" collection
     And I open the header local tasks menu
     And I click "Edit" in the "Entity actions" region
-    And I click the "Additional fields" tab
+    Then I scroll "Additional fields" into view
+    And I press "Additional fields"
+    And I scroll "Content creation" into view
     And I check "Enable newsletter subscriptions"
     And I fill in "Universe acronym" with "volkor-x"
     And I fill in "Newsletter service ID" with "123"
diff --git a/tests/features/collection/propose.feature b/tests/features/collection/propose.feature
index 9065f21b675467e4717d64bd20c6835d15457932..1e525a08e4e2a785e41bfdd976c0d009cd0cbcfe 100644
--- a/tests/features/collection/propose.feature
+++ b/tests/features/collection/propose.feature
@@ -125,7 +125,8 @@ Feature: Proposing a collection
   Scenario: Content creation options should not vanish after AJAX request.
     Given I am logged in as a user with the "authenticated" role
     When I go to the propose collection form
-    And I click the "Additional fields" tab
+    And I press "Main fields"
+    And I press "Additional fields"
     And I attach the file "banner.jpg" to "Banner"
     And I wait for AJAX to finish
     Then I should see the link "banner.jpg"
@@ -150,6 +151,7 @@ Feature: Proposing a collection
     And I fill in "Title" with "Just a proposal"
     And I enter "Nothing..." in the "Description" wysiwyg editor
     And I select "Employment and Support Allowance" from "Topic"
+    And I scroll "Owner" into view
     And I press "Add existing" at the "Owner" field
     And I fill in "Owner" with "Organisation example"
     And I press "Add owner"
@@ -158,7 +160,9 @@ Feature: Proposing a collection
       | Name   | Invisible Man             |
     And I press "Create contact information"
 
-    When I click "Additional fields" tab
+    When I scroll "Main fields" into view
+    And I press "Main fields"
+    And I press "Additional fields"
     Then the following fields should not be visible "Title, Description, Topic"
     And the following field widgets should not be visible "Owner"
     And the following fields should be visible "Content creation, Moderated, Abstract, Geographical coverage"
@@ -168,8 +172,10 @@ Feature: Proposing a collection
     # As a user, editing a collection, solution, event or news item, I want to
     # be able to pick-up a pre-uploaded image when editing the logo or the
     # banner, as an alternative to the image upload.
-    When I select image #3 as collection logo
+    When I scroll "Logo" into view
+    And I select image #3 as collection logo
     And I wait for AJAX to finish
+    And I scroll "Banner" into view
     And I select image #8 as collection banner
     And I wait for AJAX to finish
     And I press "Propose"
@@ -178,7 +184,9 @@ Feature: Proposing a collection
     And the "Just a proposal" collection banner is image #8
 
     Given I go to the edit form of the "Just a proposal" collection
-    And I click "Additional fields" tab
+    And I press "Main fields"
+    And I press "Additional fields"
+    And I scroll "Logo" into view
     And I remove the file from the "Logo" field
     But I wait for AJAX to finish
 
@@ -188,7 +196,8 @@ Feature: Proposing a collection
     And I press "Propose"
 
     When I go to the edit form of the "Just a proposal" collection
-    And I click "Additional fields" tab
+    And I press "Main fields"
+    And I press "Additional fields"
     Then I should see the link "logo.png"
 
     # As some entities were created via UI, we should explicitly delete them.
@@ -204,14 +213,15 @@ Feature: Proposing a collection
   Scenario: Browser validation errors should focus the correct field group.
     Given I am logged in as an "authenticated user"
     When I go to the propose collection form
-    Then the "Main fields" tab should be active
+    Then the "Main fields" accordion item should be active
     # This form has two elements only that have browser-side validation.
     When I fill in "Title" with "Constraint validation API"
-    And I click the "Additional fields" tab
+    And I press "Main fields"
+    And I press "Additional fields"
     And I press "Propose"
-    # Our code should have changed the active tab now. A browser message will
+    # Our code should have changed the active accordion item now. A browser message will
     # be shown to the user.
-    Then the "Main fields" tab should be active
+    Then the "Main fields" accordion item should be active
     # Fill the required fields.
     When I select "HR" from "Topic"
     And I fill in the following:
diff --git a/tests/features/file_url/widget-ui.feature b/tests/features/file_url/widget-ui.feature
index ec51d8cca41fa936be001a3ade1872126031f7da..b4766abd2bd528fe2152085996ed42dad8bab5c5 100644
--- a/tests/features/file_url/widget-ui.feature
+++ b/tests/features/file_url/widget-ui.feature
@@ -23,9 +23,11 @@ Feature: User interface for the File URL field
     But the following fields should not be visible "Choose a file,Remote URL"
     And I should not see the text "Allowed types: txt doc docx pdf."
     And I should not see the description "This must be an external URL such as http://example.com." for "Upload a new file or enter a URL"
-    And I click "Additional fields"
+    And I scroll "Additional fields" into view
+    And I press "Additional fields"
     # Try to upload a file.
-    Given I select the radio button "Upload file"
+    Given I scroll "Documentation" into view
+    And I select the radio button "Upload file"
     Then the following field should be visible "Choose a file"
     And I should see the text "Allowed types: txt doc docx pdf."
     But the following field should not be visible "Remote URL"
diff --git a/tests/features/joinup_document/document.moderation.feature b/tests/features/joinup_document/document.moderation.feature
index c0fad7bca16a183ac62117849afac751072e3a1a..77172130e27671f809638e59350b500cbef8a9f3 100644
--- a/tests/features/joinup_document/document.moderation.feature
+++ b/tests/features/joinup_document/document.moderation.feature
@@ -42,13 +42,14 @@ Feature: Document moderation
     And I click "Add document" in the plus button menu
     # Post moderated collections allow publishing content directly.
     And I should see the button "Publish"
-
     # Edit the collection and set it as moderated.
     When I am logged in as a moderator
     And I go to the homepage of the "The Naked Ashes" collection
     And I open the header local tasks menu
     And I click "Edit" in the "Entity actions" region
-    And I click the "Additional fields" tab
+    And I scroll "Additional fields" into view
+    And I press "Additional fields"
+    And I scroll "Content creation" into view
     And I check the box "Moderated"
     Then I press "Publish"
     And I should see the heading "The Naked Ashes"
@@ -68,7 +69,9 @@ Feature: Document moderation
     And I go to the homepage of the "The Naked Ashes" collection
     And I open the header local tasks menu
     And I click "Edit" in the "Entity actions" region
-    And I click the "Additional fields" tab
+    And I press "Main fields"
+    And I press "Additional fields"
+    And I scroll "Content creation" into view
     And I select the radio button "Only members can create content."
     And I press "Publish"
     # I should now have the possibility to add documents.
diff --git a/tests/features/joinup_event/event.moderation.feature b/tests/features/joinup_event/event.moderation.feature
index b8859973d06d7a64bec0e53a5fb5cd463a542352..acda13372350de0cee248d5eb9230010ee4a262f 100644
--- a/tests/features/joinup_event/event.moderation.feature
+++ b/tests/features/joinup_event/event.moderation.feature
@@ -48,7 +48,9 @@ Feature: Event moderation
     And I go to the homepage of the "Wet Lords" collection
     And I open the header local tasks menu
     And I click "Edit" in the "Entity actions" region
-    And I click the "Additional fields" tab
+    And I scroll "Additional fields" into view
+    And I press "Additional fields"
+    And I scroll "Content creation" into view
     And I check the box "Moderated"
     Then I press "Publish"
     And I should see the heading "Wet Lords"
@@ -68,7 +70,9 @@ Feature: Event moderation
     And I go to the homepage of the "Wet Lords" collection
     And I open the header local tasks menu
     And I click "Edit" in the "Entity actions" region
-    And I click the "Additional fields" tab
+    And I scroll "Additional fields" into view
+    And I press "Additional fields"
+    And I scroll "Content creation" into view
     And I check "Closed collection"
     And I wait for AJAX to finish
     And I select the radio button "Only members can create content."
diff --git a/tests/features/joinup_subscription/collection.subscribe-on-create.feature b/tests/features/joinup_subscription/collection.subscribe-on-create.feature
index c97f48ea15a2e0bfc9f9d62a1a91d76e2cea6cdd..097fc292ecbaa5ed322a0fe07467d7c655474d16 100644
--- a/tests/features/joinup_subscription/collection.subscribe-on-create.feature
+++ b/tests/features/joinup_subscription/collection.subscribe-on-create.feature
@@ -17,7 +17,7 @@ Feature: Subscribing to a collection after creating
 
     # Click the button to create an organisation owner.
     And I press "Add new" at the "Owner" field
-    When I set the Owner type to "Company"
+    When I check the box "Company"
     And I fill in "Name" with "Acme"
     And I press "Create owner"
 
diff --git a/tests/features/owner/collection_with_owner.feature b/tests/features/owner/collection_with_owner.feature
index 3405e6b340fa739c5985754a648bddad5e13b9b2..eec204e035d0b7cc5a8ad9aecb77ffedddcf377f 100644
--- a/tests/features/owner/collection_with_owner.feature
+++ b/tests/features/owner/collection_with_owner.feature
@@ -27,7 +27,7 @@ Feature: Creation of owners through UI
     # Since it is a 'propose' form, the field is not shown for the parent either.
     # It is safe to check that the field is not found in the entire form.
     Then the following fields should not be present "Current workflow state, Langcode, Translation"
-    When I set the Owner type to "Company"
+    When I check the box "Company"
     And I fill in "Name" with "Acme"
     And I press "Create owner"
     Then I should see "Acme"
@@ -35,7 +35,8 @@ Feature: Creation of owners through UI
 
     # Edit.
     When I press "Edit" at the "Owner" field
-    And I set the Owner type to "Industry consortium,Company"
+    And I check the box "Industry consortium"
+    And I check the box "Company"
     And I fill in "Name" with "Acme Inc."
     Then I press "Update owner"
     Then I should see "Acme Inc."
@@ -49,7 +50,7 @@ Feature: Creation of owners through UI
 
     # Create a person owner as well.
     And I press "Add new" at the "Owner" field
-    And I set the Owner type to "Private Individual(s)"
+    And I check the box "Private Individual(s)"
     And I fill in "Name" with "John Doe"
     And I press "Create owner"
     Then I should see "John Doe"
diff --git a/tests/features/owner/owner.moderation.feature b/tests/features/owner/owner.moderation.feature
index fa2bb1bd3e39d3985ba5c9ce40fd616ce2f04abe..7efe46defa11d05e17e0045d3b77567c05afea1e 100644
--- a/tests/features/owner/owner.moderation.feature
+++ b/tests/features/owner/owner.moderation.feature
@@ -29,7 +29,7 @@ Feature: Owner moderation
     # An authenticated user can create an owner in published state.
     When I click the 'Additional fields' tab
     And I press "Add new" at the "Owner" field
-    And I set the Owner type to "Academia/Scientific organisation"
+    And I check the box "Academia/Scientific organisation"
     And I fill in "Name" with "EU healthy movement"
     When I press "Create owner"
     Then I should see "EU healthy movement"
@@ -76,7 +76,7 @@ Feature: Owner moderation
     And the current workflow state should be "Needs update"
     And I should not see the link "Delete"
     # Do the changes.
-    When I set the Owner type to "Non-Governmental Organisation"
+    When I check the box "Non-Governmental Organisation"
     And I press "Update"
     Then I should see the heading "EU healthy group"
 
diff --git a/tests/features/solution/add_solution.feature b/tests/features/solution/add_solution.feature
index 1ceda9141035d86cfe633588c7244e3f14e8186b..576dae5262f404453be56f45730941e98764d727 100644
--- a/tests/features/solution/add_solution.feature
+++ b/tests/features/solution/add_solution.feature
@@ -299,8 +299,11 @@ Feature: "Add solution" visibility options.
 
     Given I am logged in as a moderator
     When I go to the edit form of the "Cleaning solution" solution
-    When I click "Additional fields" tab
+    And I press "Main fields"
+    When I press "Additional fields"
     And  I remove the first file from "Logo"
+    And I wait for AJAX to finish
+    Then I scroll "Banner" into view
     And  I remove the first file from "Banner"
     And I wait for AJAX to finish
 
diff --git a/tests/features/solution/related_solution.feature b/tests/features/solution/related_solution.feature
index dd376990a6e7823dd702777322562eeeaec6b335..ba7abf20271a3c2ec3702bb898195a21dd6f3c23 100644
--- a/tests/features/solution/related_solution.feature
+++ b/tests/features/solution/related_solution.feature
@@ -69,7 +69,8 @@ Feature: Related solution
       | PHP  |
 
     When I go to the edit form of the "Javascript" solution
-    And I click "Additional fields" tab
+    And I press "Main fields"
+    And I press "Additional fields"
     And I drag the table row in the "Related solutions" region at position 2 up
     And I press "Publish"
     Then I should see the heading "Javascript"
diff --git a/tests/features/solution/solution.edit.feature b/tests/features/solution/solution.edit.feature
index a8f0cb87a2181dcc2919fb050f5fc99744da5ac8..557f8f5976f64e08f648e56c4b1004a7ea46addf 100644
--- a/tests/features/solution/solution.edit.feature
+++ b/tests/features/solution/solution.edit.feature
@@ -62,8 +62,8 @@ Feature: Solution editing.
     And I should see the link "Edit"
     When I go to the edit form of the "Solution A" solution
     Then I should see the heading "Edit Solution Solution A"
-    Then the fields "Logo, Banner, Upload a new file or enter a URL, Geographical coverage, Keywords, Related solutions, Status, Languages, Landing page, Metrics page" should be correctly ordered in the region "Management solution vertical tab"
-    Then the fields "Title, Description, Contact information, Topic, Owner, Solution type, Moderated, Content creation" should be correctly ordered in the region "Main solution vertical tab"
+    Then the fields "Title, Description, Contact information, Topic, Owner, Solution type, Moderated, Content creation" should be correctly ordered in the region "Main fields accordion"
+    Then the fields "Logo, Banner, Upload a new file or enter a URL, Geographical coverage, Keywords, Related solutions, Status, Languages, Landing page, Metrics page" should be correctly ordered in the region "Additional fields accordion"
 
     And the following fields should not be present "Issue tracker, Wiki, Langcode, Translation"
     And the following fieldsets should be present "Contact information, Owner, Content creation"
@@ -116,13 +116,11 @@ Feature: Solution editing.
     And I check the "I have read and accept the legal notice and I commit to manage my solution on a regular basis." material checkbox
     And I press "Yes"
     Then I should see the heading "Add Solution"
-    And the "Main fields" tab should be active
+    And the "Main fields" accordion item should be active
     # @todo The summaries are no longer visible since we migrated to Drupal 9.
     #   Restore these when ISAICP-6963 is fixed.
     # And the "Main fields" tab summary should be "Contains all the fields to be mandatorily filled to create a solution"
     # And the "Additional fields" tab summary should be "Contains all optional fields providing additional information on the solution"
-    And I click the "Additional fields" tab
-    Then the "Additional fields" tab should be active
-    And the url should match "/collection/collection-example/solution/add#edit-group-management"
-    When I reload the page
-    Then the "Additional fields" tab should be active
+    And I press "Main fields"
+    And I press "Additional fields"
+    Then the "Additional fields" accordion item should be active
diff --git a/tests/features/solution/trr.feature b/tests/features/solution/trr.feature
index fad702503d3adf4fed08fe837aec2d40c55ca242..06272b92cc3bd9285740b6c2608469048ca7aa86 100644
--- a/tests/features/solution/trr.feature
+++ b/tests/features/solution/trr.feature
@@ -35,6 +35,7 @@ Feature: Creating a test (solution) in the TRR collection.
       | E-mail address | ernsy1999@gmail.com |
     And I select "Supplier exchange" from "Topic"
     # Click the button to select an existing owner.
+    And I scroll "Owner" into view
     And I press "Add existing" at the "Owner" field
     And I wait for AJAX to finish
     And I fill in "Owner" with "W3C"
diff --git a/tests/src/Context/FeatureContext.php b/tests/src/Context/FeatureContext.php
index fe100436f383b3e49f2b2baca2b5eb5edf235396..61888332d686539e9c18c48047b7c3115015ee92 100644
--- a/tests/src/Context/FeatureContext.php
+++ b/tests/src/Context/FeatureContext.php
@@ -905,43 +905,22 @@ public function clickVerticalTabLink(string $tab): void {
   }
 
   /**
-   * Asserts that a vertical tab is active.
+   * Asserts that an accordion item is active.
    *
-   * @param string $tab
-   *   The tab title.
+   * @param string $item
+   *   The accordion item title.
    *
    * @throws \Exception
-   *   When the tab is not found on the page or it's not active.
+   *   When the accordion item is not found on the page or it's not active.
    *
-   * @Then the :tab tab should be active
+   * @Then the :item accordion item should be active
    */
-  public function assertVerticalTabActive(string $tab): void {
-    $element = $this->findVerticalTab($tab);
+  public function assertAccordionItemActive(string $item): void {
+    $element = $this->findAccordionItem($item);
 
-    if (!$element->hasClass('is-selected')) {
-      throw new \Exception("The tab '$tab' is not active.");
-    }
-  }
-
-  /**
-   * Asserts that a vertical tab has a given summary.
-   *
-   * @param string $tab
-   *   The tab title.
-   * @param string $summary
-   *   The expected tab summary.
-   *
-   * @throws \Exception
-   *   When the tab is not found on the page or it's not active.
-   *
-   * @Then the :tab tab summary should be :summary
-   */
-  public function assertVerticalTabSummary(string $tab, string $summary): void {
-    $element = $this->findVerticalTab($tab);
-    if (!$actual_summary = $element->find('css', '.vertical-tabs__menu-item-summary')) {
-      throw new ElementNotFoundException($this->getSession()->getDriver(), 'span', 'css', '.vertical-tabs__menu-item-summary');
+    if ($element->hasClass('collapsed')) {
+      throw new \Exception("The accordion item '$item' is not active.");
     }
-    Assert::assertSame($summary, $actual_summary->getText());
   }
 
   /**
diff --git a/tests/src/Context/JoinupContext.php b/tests/src/Context/JoinupContext.php
index 78a955073c1c760a46c7baa07cb142051965a3ae..c7a7a3023bbf9e093cd1c323787a878c5768df57 100644
--- a/tests/src/Context/JoinupContext.php
+++ b/tests/src/Context/JoinupContext.php
@@ -879,7 +879,7 @@ public function pressButtonInWidget($button, $field) {
     // If this doesn't exist, search for a multivalue entity reference field
     // containing a label for the given field name.
     if (empty($element)) {
-      $xpath = '//table[contains(concat(" ", normalize-space(@class), " "), " field-multiple-table ") and //label[text()="' . $field . '"]]/ancestor::div[contains(concat(" ", normalize-space(@class), " "), " form-wrapper ")]';
+      $xpath = '//table[contains(concat(" ", normalize-space(@class), " "), " field-multiple-table ") and //label[text()="' . $field . '"]]/ancestor::div[contains(concat(" ", normalize-space(@class), " "), " form-wrapper ")] | //table[contains(concat(" ", normalize-space(@class), " "), " field-multiple-table ") and //h4[contains(concat(" ", normalize-space(@class), " "), " label ") and text()="' . $field . '"]]/ancestor::div[contains(concat(" ", normalize-space(@class), " "), " form-wrapper ")]';
       $element = $this->getSession()->getPage()->find('xpath', $xpath);
     }
 
@@ -1463,7 +1463,7 @@ public function assertFormSubmitButtonsVisible($buttons, $count = NULL) {
       // Only check the actual form submit buttons, ignore other buttons that
       // might be present in wysiwygs or are used to add multiple values to a
       // field.
-      $actual = count($this->getSession()->getPage()->findAll('xpath', '//div[contains(concat(" ", normalize-space(@class), " "), " form-actions ")]//input[@type = "submit"]'));
+      $actual = count($this->getSession()->getPage()->findAll('xpath', '//main//div[contains(concat(" ", normalize-space(@class), " "), " form-actions ")]//input[@type = "submit"]'));
       Assert::assertEquals($count, $actual);
     }
   }
@@ -1755,7 +1755,7 @@ public function assertWorkflowButtons(string $buttons): void {
    * @Then I should see the description :description for (the ):label( field)
    */
   public function assertFieldDescription($label, $description) {
-    $xpath = '//label[text()="' . $label . '"]/ancestor::div[contains(concat(" ", normalize-space(@class), " "), " form-item ")]//div[contains(concat(" ", normalize-space(@class), " "), " description ")]';
+    $xpath = '//label[text()="' . $label . '"]/ancestor::div[contains(concat(" ", normalize-space(@class), " "), " form-item ")]//div[contains(concat(" ", normalize-space(@class), " "), " description ")] | //label[text()="' . $label . '"]/ancestor::div[contains(concat(" ", normalize-space(@class), " "), " form-item ")]//small[contains(concat(" ", normalize-space(@class), " "), " description ")]';
     $elements = $this->getSession()->getPage()->findAll('xpath', $xpath);
     if (empty($elements)) {
       throw new \Exception("The $label field does not have a description.");
@@ -1787,7 +1787,7 @@ public function assertFieldDescription($label, $description) {
    * @Then I should not see the description :description for (the ):label( field)
    */
   public function assertNoFieldDescription($label, $description) {
-    $xpath = '//label[text()="' . $label . '"]/ancestor::div[contains(concat(" ", normalize-space(@class), " "), " form-item ")]//div[contains(concat(" ", normalize-space(@class), " "), " description ")]';
+    $xpath = '//label[text()="' . $label . '"]/ancestor::div[contains(concat(" ", normalize-space(@class), " "), " form-item ")]//div[contains(concat(" ", normalize-space(@class), " "), " description ")] | //label[text()="' . $label . '"]/ancestor::div[contains(concat(" ", normalize-space(@class), " "), " form-item ")]//small[contains(concat(" ", normalize-space(@class), " "), " description ")]';
     $elements = $this->getSession()->getPage()->findAll('xpath', $xpath);
     foreach ($elements as $element) {
       Assert::assertNotEquals($description, trim($element->getText()));
@@ -2287,11 +2287,11 @@ public function assertRegionLinkHref($link, $region, $href) {
    *
    * @Then the fields :fields should be correctly ordered in the region :region
    */
-  public function assertFieldsPresentInOrder($fields, $region) {
+  public function assertFieldsPresentInOrder(string $fields, string $region): void {
     $fields = $this->explodeCommaSeparatedStepArgument($fields);
     /** @var \Behat\Mink\Element\Element $regionObj */
     $regionObj = $this->getRegion($region);
-    $labels = $regionObj->findAll('xpath', "/.//*[contains(concat(' ', normalize-space(@class), ' '), ' form-wrapper ')]//label");
+    $labels = $regionObj->findAll('xpath', "/.//*[contains(concat(' ', normalize-space(@class), ' '), ' form-wrapper ')]//label | /.//*[contains(concat(' ', normalize-space(@class), ' '), ' form-wrapper ')]//h4[contains(concat(' ', normalize-space(@class), ' '), ' label ')] | /.//*[contains(concat(' ', normalize-space(@class), ' '), ' form-wrapper ')]//fieldset//legend[contains(concat(' ', normalize-space(@class), ' '), ' col-form-label ')]");
     $labels_on_page = [];
     /** @var \Behat\Mink\Element\NodeElement $label */
     foreach ($labels as $label) {
@@ -3041,4 +3041,42 @@ public function assertLinkIsInActiveTrail(string $link_label): void {
     }
   }
 
+  /**
+   * Shows label in the middle of the screen.
+   *
+   * In the latest version of Selenium in docker, moving to a button element
+   * might throw this exception while label is visible.
+   * This might be due to attempting to find label too fast.
+   *
+   * @param string $label
+   *   The label of field.
+   *
+   * @throws \Exception
+   *    Thrown when an expected scroll in to view failed.
+   *
+   * @Given I scroll :label into view
+   */
+  public function scrollLabelIntoView(string $label): void {
+    $page = $this->getSession()->getPage();
+    $element = $page->find('xpath', "//*[contains(text(),'{$label}')]");
+    $xpath = $element->getXpath();
+    $function = <<<JS
+  (
+      function(){
+        setTimeout(() => {
+          let elem = document.evaluate("$xpath", document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
+          elem.scrollIntoView({ behavior: 'instant', block: 'center' });
+        }, 300);
+      }
+  )()
+  JS;
+    try {
+      $this->getSession()->executeScript($function);
+      sleep(1);
+    }
+    catch (\Exception $e) {
+      throw new \Exception("Scroll element into view failed");
+    }
+  }
+
 }
diff --git a/tests/src/Context/MinkContext.php b/tests/src/Context/MinkContext.php
index 6d148b441759c7b22b82ec6260a6a1cf77cacb57..436a1ca610a52fd5f4fdf3405fed4346404c2fad 100644
--- a/tests/src/Context/MinkContext.php
+++ b/tests/src/Context/MinkContext.php
@@ -24,7 +24,13 @@ public function checkOption($option) {
     // Overrides the default method for checking checkboxes to make it
     // compatible with material design.
     $option = $this->fixStepArgument($option);
-    $this->checkMaterialDesignField($option, $this->getSession()->getPage());
+    $page = $this->getSession()->getPage();
+    if (!$page->find('css', 'div#block-ventuno-pagetitle')) {
+      $this->checkMaterialDesignField($option, $page);
+    }
+    else {
+      $page->checkField($option);
+    }
   }
 
   /**
@@ -34,7 +40,13 @@ public function uncheckOption($option) {
     // Overrides the default method for unchecking checkboxes to make it
     // compatible with material design.
     $option = $this->fixStepArgument($option);
-    $this->uncheckMaterialDesignField($option, $this->getSession()->getPage());
+    $page = $this->getSession()->getPage();
+    if (!$page->find('css', 'div#block-ventuno-pagetitle')) {
+      $this->uncheckMaterialDesignField($option, $this->getSession()->getPage());
+    }
+    else {
+      $page->uncheckField($option);
+    }
   }
 
   /**
diff --git a/tests/src/Context/WysiwygContext.php b/tests/src/Context/WysiwygContext.php
index a6ffcae2800e631207503ccd5c1b7c038d45d272..5386250a5732945971e9a8726424d27978a943aa 100644
--- a/tests/src/Context/WysiwygContext.php
+++ b/tests/src/Context/WysiwygContext.php
@@ -41,7 +41,26 @@ public function enterTextInWysiwyg(string $text, string $label): void {
     if ($this->browserSupportsJavaScript()) {
       // Scroll to the top because the button might be obscured by the floating
       // header.
-      $this->scrollToTop();
+      $page = $this->getSession()->getPage();
+      $element = $page->find('xpath', "//*[contains(text(),'{$label}')]");
+      $xpath = $element->getXpath();
+      $function = <<<JS
+  (
+      function(){
+        setTimeout(() => {
+          let elem = document.evaluate("$xpath", document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
+          elem.scrollIntoView({ behavior: 'instant', block: 'center' });
+        }, 300);
+      }
+  )()
+  JS;
+      try {
+        $this->getSession()->executeScript($function);
+        sleep(1);
+      }
+      catch (\Exception $e) {
+        throw new \Exception("Scroll element into view failed");
+      }
       $this->pressWysiwygButton($label, 'Source');
       $this->setWysiwygText($label, $text);
     }
diff --git a/tests/src/Traits/FormTrait.php b/tests/src/Traits/FormTrait.php
index dc1ee67535012e9abda396cbc6bfde4c914a0397..e57e016ecae0519ad2a7a47b320afca93fb02e6e 100644
--- a/tests/src/Traits/FormTrait.php
+++ b/tests/src/Traits/FormTrait.php
@@ -26,7 +26,7 @@ trait FormTrait {
    *   button is present.
    */
   public function assertSubmitButtonsVisible(array $labels, bool $strict = TRUE) {
-    $buttons = $this->getSession()->getPage()->findAll('xpath', '//div[contains(concat(" ", normalize-space(@class), " "), " form-actions ")]//input[@type = "submit"]');
+    $buttons = $this->getSession()->getPage()->findAll('xpath', '//main//div[contains(concat(" ", normalize-space(@class), " "), " form-actions ")]//input[@type = "submit"]');
     $actual_labels = [];
     foreach ($buttons as $button) {
       $actual_labels[] = $button->getValue();
diff --git a/tests/src/Traits/MaterialDesignTrait.php b/tests/src/Traits/MaterialDesignTrait.php
index 8e31ca1dad2a358f3d3b98ee2fea99fcf2be65df..debf10a5f76c30412c90f40db4006085a37fe652 100644
--- a/tests/src/Traits/MaterialDesignTrait.php
+++ b/tests/src/Traits/MaterialDesignTrait.php
@@ -4,6 +4,7 @@
 
 namespace Drupal\joinup\Traits;
 
+use Behat\Mink\Element\NodeElement;
 use Behat\Mink\Element\TraversableElement;
 
 /**
@@ -132,7 +133,7 @@ protected function toggleMaterialDesignCheckbox(TraversableElement $element, ?st
    *   Thrown when the browser does not support JavaScript or when the animated
    *   checkbox with the given label is not found.
    */
-  protected function findMaterialDesignCheckbox($label, TraversableElement $element) {
+  protected function findMaterialDesignCheckbox($label, TraversableElement $element): NodeElement {
     if (!$this->browserSupportsJavaScript()) {
       throw new \Exception("The hidden input field for the $label checkbox cannot be found in a browser that doesn't support JavaScript.");
     }
diff --git a/tests/src/Traits/TraversingTrait.php b/tests/src/Traits/TraversingTrait.php
index 6607b97de29d6a8134807fbc8c50aec8e9ea15cd..89773b42f72c04f60179a965eb2d639259847af2 100644
--- a/tests/src/Traits/TraversingTrait.php
+++ b/tests/src/Traits/TraversingTrait.php
@@ -38,7 +38,7 @@ protected function findAnyFormField(string $field, ?TraversableElement $region =
       // elements such as 'select' and 'input', so try both the standard
       // findField() as well as an XPath expression that finds the given label
       // inside any element marked as a form item.
-      $xpath = '//*[contains(concat(" ", normalize-space(@class), " "), " form-item ") and .//label[text() = "' . $field . '"]]';
+      $xpath = '//*[contains(concat(" ", normalize-space(@class), " "), " form-item ") and .//label[text() = "' . $field . '"]] | //*[contains(concat(" ", normalize-space(@class), " "), " form-wrapper ") and .//h4[text() = "' . $field . '"]] | //*[contains(concat(" ", normalize-space(@class), " "), " col-form-label ") and .//span[text() = "' . $field . '"]]';
       $element = $region->find('xpath', $xpath);
     }
 
@@ -205,6 +205,34 @@ protected function findVerticalTab(string $tab): NodeElement {
     return $element;
   }
 
+  /**
+   * Finds an accordion item by its title.
+   *
+   * @param string $item
+   *   The title of the accordion item.
+   *
+   * @return \Behat\Mink\Element\NodeElement
+   *   The accordion item element.
+   *
+   * @throws \Exception
+   *   Thrown when no item element is found.
+   */
+  protected function findAccordionItem(string $item): NodeElement {
+    // Xpath to find the accordion item.
+    $xpath = "//div[@class and contains(concat(' ', normalize-space(@class), ' '), ' accordion-item ')]";
+    // Filter down to the accordion item containing a button with the
+    // provided text.
+    $xpath .= "[.//h2[@class and contains(concat(' ', normalize-space(@class), ' '), ' accordion-header ')]/button[@class and contains(concat(' ', normalize-space(@class), ' '), ' accordion-button ')]"
+      . "[normalize-space(string(.)) = '$item']]";
+    $element = $this->getSession()->getPage()->find('xpath', $xpath);
+
+    if ($element === NULL) {
+      throw new \Exception('Accordion item not found: ' . $item);
+    }
+
+    return $element;
+  }
+
   /**
    * Retrieves a region container from the page.
    *
diff --git a/web/modules/custom/joinup_workflow/src/Plugin/Field/FieldWidget/StateMachineButtons.php b/web/modules/custom/joinup_workflow/src/Plugin/Field/FieldWidget/StateMachineButtons.php
index 29ed9cdd6588246295f9ec5dfd4eb5a76259a276..dbcb17c79812d130a9a7cc4f6a8a6d2573ecf8ca 100644
--- a/web/modules/custom/joinup_workflow/src/Plugin/Field/FieldWidget/StateMachineButtons.php
+++ b/web/modules/custom/joinup_workflow/src/Plugin/Field/FieldWidget/StateMachineButtons.php
@@ -202,6 +202,7 @@ public static function processActions($element, FormStateInterface $form_state,
         : t('Save as @transition', ['@transition' => $label]);
 
       $form['actions']['state_machine_' . $state_id] = $button + $default_button;
+      $form['actions']['state_machine_' . $state_id]['#attributes']['class'][] = 'state-machine-action-button';
     }
 
     // Hide the default buttons, including the specialty ones added by
diff --git a/web/profiles/joinup/joinup.profile b/web/profiles/joinup/joinup.profile
index 44319dcca6da9c53ce330e4cb29ca90a4b739b72..2265e2df4071e63fa0a95e61cd609d3d3989917c 100644
--- a/web/profiles/joinup/joinup.profile
+++ b/web/profiles/joinup/joinup.profile
@@ -184,16 +184,6 @@ function joinup_field_widget_inline_entity_form_complex_form_alter(&$element, Fo
       }
     }
   }
-
-  // If no title is provided for the fieldset wrapping the create form, add the
-  // label of the bundle of the entity being created.
-  if (empty($element['form']['#title']) && !empty($element['form']['inline_entity_form']['#bundle'])) {
-    $entity_type = $element['form']['inline_entity_form']['#entity_type'];
-    $bundle = $element['form']['inline_entity_form']['#bundle'];
-
-    $bundle_info = \Drupal::service('entity_type.bundle.info')->getBundleInfo($entity_type);
-    $element['form']['#title'] = $bundle_info[$bundle]['label'];
-  }
 }
 
 /**
diff --git a/web/themes/ventuno/bcl-builder.config.js b/web/themes/ventuno/bcl-builder.config.js
index 18ca8bcd483e88f10ca3e8a2b83f821ca8353c00..4bcb0cc006a1d85e797f3ca7934555e6a4c6dd02 100644
--- a/web/themes/ventuno/bcl-builder.config.js
+++ b/web/themes/ventuno/bcl-builder.config.js
@@ -19,6 +19,14 @@ module.exports = {
       },
     },
     // Custom
+    {
+      entry: path.resolve(outputFolder, "src/js/highlight-invalid-fields.js"),
+      dest: path.resolve(outputFolder, "assets/js/highlight-invalid-fields.js"),
+      options: {
+        minify: true,
+        sourceMap: true,
+      },
+    },
     {
       entry: path.resolve(outputFolder, "src/js/sticky-menu.js"),
       dest: path.resolve(outputFolder, "assets/js/sticky-menu.js"),
@@ -35,6 +43,14 @@ module.exports = {
         sourceMap: true,
       },
     },
+    {
+      entry: path.resolve(outputFolder, "src/js/show-accordion-invalid-fields.js"),
+      dest: path.resolve(outputFolder, "assets/js/show-accordion-invalid-fields.js"),
+      options: {
+        minify: true,
+        sourceMap: true,
+      },
+    },
     {
       entry: path.resolve(outputFolder, "src/js/tour-first-balloon.js"),
       dest: path.resolve(outputFolder, "assets/js/tour-first-balloon.js"),
@@ -89,7 +105,15 @@ module.exports = {
         sourceMap: "file",
       },
     },
-    // Bootstrap components
+    // Pure BCL components
+    {
+      entry: path.resolve(outputFolder, "src/scss/accordion.scss"),
+      dest: path.resolve(outputFolder, "assets/css/accordion.css"),
+      options: {
+        includePaths,
+        sourceMap: "file",
+      },
+    },
     {
       entry: path.resolve(outputFolder, "src/scss/close.scss"),
       dest: path.resolve(outputFolder, "assets/css/close.css"),
@@ -114,7 +138,7 @@ module.exports = {
         sourceMap: "file",
       },
     },
-    // Custom components
+    // Custom and hybrid (BCL + custom) components
     {
       entry: path.resolve(outputFolder, "src/scss/footer.scss"),
       dest: path.resolve(outputFolder, "assets/css/footer.css"),
@@ -123,6 +147,22 @@ module.exports = {
         sourceMap: "file",
       },
     },
+    {
+      entry: path.resolve(outputFolder, "src/scss/forms.scss"),
+      dest: path.resolve(outputFolder, "assets/css/forms.css"),
+      options: {
+        includePaths,
+        sourceMap: "file",
+      },
+    },
+    {
+      entry: path.resolve(outputFolder, "src/scss/ief-entity-table.scss"),
+      dest: path.resolve(outputFolder, "assets/css/ief-entity-table.css"),
+      options: {
+        includePaths,
+        sourceMap: "file",
+      },
+    },
     {
       entry: path.resolve(outputFolder, "src/scss/navbar.scss"),
       dest: path.resolve(outputFolder, "assets/css/navbar.css"),
@@ -163,6 +203,14 @@ module.exports = {
         sourceMap: "file",
       },
     },
+    {
+      entry: path.resolve(outputFolder, "src/scss/tabledrag.scss"),
+      dest: path.resolve(outputFolder, "assets/css/tabledrag.css"),
+      options: {
+        includePaths,
+        sourceMap: "file",
+      },
+    },
     // @todo remove when switch to Ventuno theme is complete
     {
       entry: path.resolve(outputFolder, "src/scss/core/base/bootstrap-base.scss"),
diff --git a/web/themes/ventuno/src/js/highlight-invalid-fields.js b/web/themes/ventuno/src/js/highlight-invalid-fields.js
new file mode 100644
index 0000000000000000000000000000000000000000..80f4a01db7b8c7749cd906d1163514483fa75b89
--- /dev/null
+++ b/web/themes/ventuno/src/js/highlight-invalid-fields.js
@@ -0,0 +1,20 @@
+/**
+ * @file
+ * Highlight the invalid required field(s) adding corresponding class.
+ */
+(() => {
+
+  Drupal.behaviors.highlightInvalidFields = {
+    attach: function () {
+      const requiredFields = document.querySelectorAll('.required');
+      requiredFields.forEach((field) => {
+        field.addEventListener('invalid', () => {
+          if (!field.classList.contains('is-invalid')) {
+            field.classList.add('is-invalid');
+          };
+        });
+      });
+    }
+  }
+
+})();
diff --git a/web/themes/ventuno/src/js/show-accordion-invalid-fields.js b/web/themes/ventuno/src/js/show-accordion-invalid-fields.js
new file mode 100644
index 0000000000000000000000000000000000000000..efe2562b296c3d41ea63c855cc6586519497857f
--- /dev/null
+++ b/web/themes/ventuno/src/js/show-accordion-invalid-fields.js
@@ -0,0 +1,25 @@
+/**
+ * @file
+ * Open accordions to allow user spot the invalid required field(s).
+ */
+(() => {
+
+  Drupal.behaviors.showAccordionInvalidFields = {
+    attach: function () {
+      const requiredFields = document.querySelectorAll('.accordion-body .required');
+      requiredFields.forEach((field) => {
+        field.addEventListener('invalid', () => {
+          openAccordionItem(field);
+        });
+      });
+      function openAccordionItem(element) {
+        const item = element.closest('.accordion-item');
+        const button = item.querySelector('.accordion-button');
+        if (button.classList.contains('collapsed')) {
+          button.click();
+        }
+      }
+    }
+  }
+
+})();
diff --git a/web/themes/ventuno/src/scss/accordion.scss b/web/themes/ventuno/src/scss/accordion.scss
new file mode 100644
index 0000000000000000000000000000000000000000..3ada2ba775a24439b51f29eda2fcf9ef7dbb50d5
--- /dev/null
+++ b/web/themes/ventuno/src/scss/accordion.scss
@@ -0,0 +1,2 @@
+@import "core/base/base";
+@import "@openeuropa/bcl-bootstrap/scss/accordion";
diff --git a/web/themes/ventuno/src/scss/components/_forms.scss b/web/themes/ventuno/src/scss/components/_forms.scss
new file mode 100644
index 0000000000000000000000000000000000000000..b6e76b03604fe8ece19fddb8e301c68760aac7ef
--- /dev/null
+++ b/web/themes/ventuno/src/scss/components/_forms.scss
@@ -0,0 +1,42 @@
+.form-wrapper {
+  margin-bottom: 1.5rem;
+}
+
+// Mark required fields
+.form-required {
+  &::after {
+    content: '*';
+    color: $danger;
+    margin-left: $spacer * .25; // 4px
+  }
+}
+
+// Make CKEditor textareas emulate @openeuropa invalid state
+.form-control.required.is-invalid + .cke {
+  border: 1px solid $danger;
+  border-radius: $form-check-input-border-radius;
+  .cke_inner {
+    border-radius: $form-check-input-border-radius;
+  }
+  .cke_top {
+    border-top-left-radius: $form-check-input-border-radius;
+    border-top-right-radius: $form-check-input-border-radius;
+  }
+  .cke_contents {
+    padding-right: calc(1.5em + 0.75rem);
+    background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23eb3434'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23eb3434' stroke='none'/%3e%3c/svg%3e");
+    background-repeat: no-repeat;
+    background-position: right calc(0.375em + 0.1875rem) center;
+    background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);
+  }
+  .cke_bottom {
+    border-bottom-right-radius: $form-check-input-border-radius;
+    border-bottom-left-radius: $form-check-input-border-radius;
+  }
+}
+
+// As we dropped slimselect which @openeuropa based the multiselect on,
+// emulate @openeuropa form-select.
+.multi-select {
+  @extend .form-select;
+}
diff --git a/web/themes/ventuno/src/scss/components/_ief-entity-table.scss b/web/themes/ventuno/src/scss/components/_ief-entity-table.scss
new file mode 100644
index 0000000000000000000000000000000000000000..f745c02cca1e43322242f92dc87f02b7275beb5f
--- /dev/null
+++ b/web/themes/ventuno/src/scss/components/_ief-entity-table.scss
@@ -0,0 +1,7 @@
+.ief-entity-table {
+  .ief-row-entity {
+    td:last-of-type {
+      width: 224px;
+    }
+  }
+}
diff --git a/web/themes/ventuno/src/scss/components/_tabledrag.scss b/web/themes/ventuno/src/scss/components/_tabledrag.scss
new file mode 100644
index 0000000000000000000000000000000000000000..9b58c467e395a053ea8727b60317b1607783247d
--- /dev/null
+++ b/web/themes/ventuno/src/scss/components/_tabledrag.scss
@@ -0,0 +1,14 @@
+.tabledrag-toggle-weight-wrapper,
+.tabledrag-handle,
+.tabledrag-hide {
+  display: none!important;
+}
+.table {
+  td.field-multiple-drag {
+  width: 0;
+  padding: 0;
+  }
+  td.delta-order {
+    min-width: 5rem;
+  }
+}
diff --git a/web/themes/ventuno/src/scss/core/overrides/_utilities.scss b/web/themes/ventuno/src/scss/core/overrides/_utilities.scss
index ba830f9109a1fec7bdcc2d2a4c28de4573d31a74..62c284cdfed364a0e9d39f3a8e219cc2c60627b7 100644
--- a/web/themes/ventuno/src/scss/core/overrides/_utilities.scss
+++ b/web/themes/ventuno/src/scss/core/overrides/_utilities.scss
@@ -208,12 +208,12 @@ $utilities: map-merge(
       //   property: flex,
       //   values: (fill: 1 1 auto)
       // ),
-      // "flex-direction": (
-      //   responsive: true,
-      //   property: flex-direction,
-      //   class: flex,
-      //   values: row column row-reverse column-reverse
-      // ),
+      "flex-direction": (
+        responsive: true,
+        property: flex-direction,
+        class: flex,
+        values: row column row-reverse column-reverse
+      ),
       // "flex-grow": (
       //   responsive: true,
       //   property: flex-grow,
diff --git a/web/themes/ventuno/src/scss/core/overrides/_variables.scss b/web/themes/ventuno/src/scss/core/overrides/_variables.scss
index 9923e8339fa7e329ad46501a1e9a6be045631716..bd3817a0d79ffc620e60b7c8b4eeadd95bdb7cb0 100644
--- a/web/themes/ventuno/src/scss/core/overrides/_variables.scss
+++ b/web/themes/ventuno/src/scss/core/overrides/_variables.scss
@@ -89,5 +89,6 @@ $banner-content-border-color: $primary;
 $form-check-input-size-lg: $form-check-input-width + 0.3em !default;
 $form-font-size: $font-size-base !default;
 $form-font-size-lg: $font-size-base + 0.25rem !default;
+$form-label-font-weight: $font-weight-bold;
 $form-select-height: 3rem !default;
 $form-select-height-md: 2.375rem !default;
diff --git a/web/themes/ventuno/src/scss/forms.scss b/web/themes/ventuno/src/scss/forms.scss
new file mode 100644
index 0000000000000000000000000000000000000000..dd5a90153625d471e369916c9a3dfa60a7dd4d49
--- /dev/null
+++ b/web/themes/ventuno/src/scss/forms.scss
@@ -0,0 +1,3 @@
+@import "core/base/base";
+@import "@openeuropa/bcl-bootstrap/scss/forms";
+@import "components/forms";
diff --git a/web/themes/ventuno/src/scss/ief-entity-table.scss b/web/themes/ventuno/src/scss/ief-entity-table.scss
new file mode 100644
index 0000000000000000000000000000000000000000..61918ea44652642953e38aa00c03ee7207a40ee4
--- /dev/null
+++ b/web/themes/ventuno/src/scss/ief-entity-table.scss
@@ -0,0 +1,2 @@
+@import "core/base/base";
+@import "components/ief-entity-table";
diff --git a/web/themes/ventuno/src/scss/main.scss b/web/themes/ventuno/src/scss/main.scss
index a5c2e5bd80524602377c6cb163ca1a21c4e0c968..857c6e3820622447541ef130bdee6c361b941326 100644
--- a/web/themes/ventuno/src/scss/main.scss
+++ b/web/themes/ventuno/src/scss/main.scss
@@ -27,7 +27,7 @@
 @import "@openeuropa/bcl-bootstrap/scss/containers";
 @import "@openeuropa/bcl-bootstrap/scss/grid";
 // @import "@openeuropa/bcl-bootstrap/scss/tables";
-@import "@openeuropa/bcl-bootstrap/scss/forms";
+// @import "@openeuropa/bcl-bootstrap/scss/forms";
 @import "@openeuropa/bcl-bootstrap/scss/buttons";
 @import "@openeuropa/bcl-bootstrap/scss/transitions";
 // @import "@openeuropa/bcl-bootstrap/scss/dropdown";
diff --git a/web/themes/ventuno/src/scss/tabledrag.scss b/web/themes/ventuno/src/scss/tabledrag.scss
new file mode 100644
index 0000000000000000000000000000000000000000..d486bc1e843888d31fba859a68fb524031015b03
--- /dev/null
+++ b/web/themes/ventuno/src/scss/tabledrag.scss
@@ -0,0 +1,2 @@
+@import "core/base/base";
+@import "components/tabledrag";
diff --git a/web/themes/ventuno/templates/field_group/field-group-accordion-item.html.twig b/web/themes/ventuno/templates/field_group/field-group-accordion-item.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..9a26ce152c4225f4eba9495627746e656ab43b32
--- /dev/null
+++ b/web/themes/ventuno/templates/field_group/field-group-accordion-item.html.twig
@@ -0,0 +1,31 @@
+{#
+/**
+ * @file
+ * Default theme implementation for a fieldgroup accordion item.
+ *
+ * Available variables:
+ * - title: Title of the group.
+ * - children: The children of the group.
+ * - label_attributes: A list of HTML attributes for the label.
+ * - attributes: A list of HTML attributes for the group wrapper.
+ *
+ * @see template_preprocess_field_group_accordion()
+ *
+ * @ingroup themeable
+ */
+#}
+{{ attach_library('ventuno/show-accordion-invalid-fields') }}
+{% set collapse_id = title|lower|replace({' ': '-'}) %}
+<div class="accordion-item">
+  <h2 class="accordion-header" id="heading-{{ collapse_id }}">
+    <button class="accordion-button fw-bold text-primary{{ open ? '' : ' collapsed'}}" type="button" data-bs-toggle="collapse" data-bs-target="#{{ collapse_id }}"{{ open ? ' aria-expanded="true"'}} aria-controls="{{ collapse_id }}">
+      {{ title }}
+    </button>
+  </h2>
+  <div id="{{ collapse_id }}" class="accordion-collapse collapse{{ open ? ' show'}}" aria-labelledby="heading-{{ collapse_id }}">
+    <div class="accordion-body">
+      <p>{{ description }}</p>
+      {{ children }}
+    </div>
+  </div>
+</div>
diff --git a/web/themes/ventuno/templates/field_group/field-group-accordion.html.twig b/web/themes/ventuno/templates/field_group/field-group-accordion.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..fb91437164dc63de394eb7e4c5ab46bd729e0e58
--- /dev/null
+++ b/web/themes/ventuno/templates/field_group/field-group-accordion.html.twig
@@ -0,0 +1,22 @@
+{#
+/**
+ * @file
+ * Default theme implementation for a fieldgroup accordion item.
+ *
+ * Available variables:
+ * - children: The children of the group.
+ * - attributes: A list of HTML attributes for the group wrapper.
+ *
+ * @see template_preprocess_field_group_accordion()
+ *
+ * @ingroup themeable
+ */
+#}
+{{ attach_library('ventuno/accordion') }}
+{%
+  set classes = [
+    'accordion',
+    'my-4',
+  ]
+%}
+<div {{ attributes.addClass(classes) }}>{{ children }}</div>
diff --git a/web/themes/ventuno/templates/form/container--edit-actions.html.twig b/web/themes/ventuno/templates/form/container--edit-actions.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..9541573f24517a66f469dc88d72cc74baf0029ca
--- /dev/null
+++ b/web/themes/ventuno/templates/form/container--edit-actions.html.twig
@@ -0,0 +1,31 @@
+{#
+/**
+ * @file
+ * Theme override of a container used to wrap child elements.
+ *
+ * Used for grouped form items. Can also be used as a theme wrapper for any
+ * renderable element, to surround it with a <div> and HTML attributes.
+ * See \Drupal\Core\Render\Element\RenderElement for more
+ * information on the #theme_wrappers render array property, and
+ * \Drupal\Core\Render\Element\container for usage of the container render
+ * element.
+ *
+ * Available variables:
+ * - attributes: HTML attributes for the containing element.
+ * - children: The rendered child elements of the container.
+ * - has_parent: A flag to indicate that the container has one or more parent
+     containers.
+ *
+ * @see template_preprocess_container()
+ */
+#}
+{%
+  set classes = [
+    'd-flex',
+    'flex-column',
+    'd-md-block'
+  ]
+%}
+<div{{ attributes.addClass(classes) }}>
+  {{ children }}
+</div>
diff --git a/web/themes/ventuno/templates/form/details.html.twig b/web/themes/ventuno/templates/form/details.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..a6ed1e6676af537ea1c5155544b300d53cc44547
--- /dev/null
+++ b/web/themes/ventuno/templates/form/details.html.twig
@@ -0,0 +1,37 @@
+{#
+/**
+ * @file
+ * Theme override for a details element.
+ *
+ * Available variables
+ * - attributes: A list of HTML attributes for the details element.
+ * - errors: (optional) Any errors for this details element, may not be set.
+ * - title: (optional) The title of the element, may not be set.
+ * - description: (optional) The description of the element, may not be set.
+ * - children: (optional) The children of the element, may not be set.
+ * - value: (optional) The value of the element, may not be set.
+ *
+ * @see template_preprocess_details()
+ */
+#}
+<details{{ attributes.addClass(['mb-3 border rounded']) }}>
+  {%- if title -%}
+    <summary{{ summary_attributes.addClass(['p-3 fw-bold bg-light']) }}>{{ title }}</summary>
+  {%- endif -%}
+  <div class="details-wrapper px-3 my-3">
+    {% if errors %}
+      <div class="form-item--error-message invalid-feedback d-block">
+        {{ errors }}
+      </div>
+    {% endif %}
+    {%- if description -%}
+      <small class="details-description text-muted">{{ description }}</small>
+    {%- endif -%}
+    {%- if children -%}
+      {{ children }}
+    {%- endif -%}
+    {%- if value -%}
+      {{ value }}
+    {%- endif -%}
+  </div>
+</details>
diff --git a/web/themes/ventuno/templates/form/fieldset.html.twig b/web/themes/ventuno/templates/form/fieldset.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..876996a15ff0aaf3da6885850426d9f5c0410359
--- /dev/null
+++ b/web/themes/ventuno/templates/form/fieldset.html.twig
@@ -0,0 +1,63 @@
+{#
+/**
+ * @file
+ * Theme override for a fieldset element and its children.
+ *
+ * Available variables:
+ * - attributes: HTML attributes for the fieldset element.
+ * - errors: (optional) Any errors for this fieldset element, may not be set.
+ * - required: Boolean indicating whether the fieldeset element is required.
+ * - legend: The legend element containing the following properties:
+ *   - title: Title of the fieldset, intended for use as the text of the legend.
+ *   - attributes: HTML attributes to apply to the legend.
+ * - description: The description element containing the following properties:
+ *   - content: The description content of the fieldset.
+ *   - attributes: HTML attributes to apply to the description container.
+ * - children: The rendered child elements of the fieldset.
+ * - prefix: The content to add before the fieldset children.
+ * - suffix: The content to add after the fieldset children.
+ *
+ * @see template_preprocess_fieldset()
+ */
+#}
+{%
+  set classes = [
+    'js-form-item',
+    'form-item',
+    'js-form-wrapper',
+    'mb-3',
+    errors ? 'has-error',
+  ]
+%}
+<fieldset{{ attributes.addClass(classes) }}>
+  {% set legend_classes = [
+    'col-form-label',
+  ] %}
+  {% set legend_span_classes = [
+    'fieldset-legend',
+    'fw-bold',
+    required ? 'js-form-required',
+    required ? 'form-required',
+  ] %}
+  {#  Always wrap fieldset legends in a SPAN for CSS positioning. #}
+  <legend{{ legend.attributes.addClass(legend_classes) }}>
+    <span{{ legend_span.attributes.addClass(legend_span_classes) }}>{{ legend.title }}</span>
+  </legend>
+  <div class="fieldset-wrapper">
+    {% if prefix %}
+      <span class="field-prefix">{{ prefix }}</span>
+    {% endif %}
+    {{ children }}
+    {% if suffix %}
+      <span class="field-suffix">{{ suffix }}</span>
+    {% endif %}
+    {% if errors %}
+      <div class="form-item--error-message invalid-feedback d-block">
+        {{ errors }}
+      </div>
+    {% endif %}
+    {% if description.content %}
+      <small{{ description.attributes.addClass('description', 'text-muted') }}>{{ description.content }}</small>
+    {% endif %}
+  </div>
+</fieldset>
diff --git a/web/themes/ventuno/templates/form/input--submit.html.twig b/web/themes/ventuno/templates/form/input--submit.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..89428a2d7a9639ce4fc1449ad3a94cd3a4081620
--- /dev/null
+++ b/web/themes/ventuno/templates/form/input--submit.html.twig
@@ -0,0 +1,29 @@
+{#
+/**
+ * @file
+ * Theme override for an 'input' #type form element.
+ *
+ * Available variables:
+ * - attributes: A list of HTML attributes for the input element.
+ * - children: Optional additional rendered elements.
+ *
+ * @see template_preprocess_input()
+ */
+#}
+{% if attributes.hasClass('button--primary') or attributes['data-drupal-selector'] == 'edit-submit' %}
+  {% set variant = 'primary' %}
+{% else %}
+  {% set variant = 'secondary' %}
+{% endif %}
+{% if attributes.disabled == 'disabled' %}
+  {% set attributes = attributes.addClass(['disabled']) %}
+{% endif %}
+{% set classes = [
+  'btn',
+  'btn-md',
+  'btn-' ~ variant,
+  'mb-3',
+  'mb-md-0',
+] %}
+
+<input{{ attributes.addClass(classes) }} />{{ children }}
diff --git a/web/themes/ventuno/templates/layout/page.html.twig b/web/themes/ventuno/templates/layout/page.html.twig
index 68ae8427a091b390bca6bddad7a052b704d7d9e2..857f0cbb5f17b7976978e30d0752aad59809cf34 100644
--- a/web/themes/ventuno/templates/layout/page.html.twig
+++ b/web/themes/ventuno/templates/layout/page.html.twig
@@ -45,7 +45,7 @@
     {{ page.header }}
 
     {% if page.header_bottom %}
-      <div class="region-header-bottom">
+      <div class="region-header-bottom container">
         {{ page.header_bottom }}
       </div>
     {% endif %}
@@ -65,7 +65,12 @@
     {{ page.messages }}
   {% endif %}
 
-  {{ page.content_top }}
+  {% if page.content_top %}
+    <div class="container">
+      {{ page.content_top }}
+    </div>
+  {% endif %}
+
   <div class="content container mb-5">
     <div class="row">
       {% if page.sidebar|render|striptags|trim is not empty %}
diff --git a/web/themes/ventuno/templates/system/vertical-tabs.html.twig b/web/themes/ventuno/templates/system/vertical-tabs.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..5d23183a07678fde4554c66eec5f27bf56b7b788
--- /dev/null
+++ b/web/themes/ventuno/templates/system/vertical-tabs.html.twig
@@ -0,0 +1,15 @@
+{#
+/**
+ * @file
+ * Default theme implementation for vertical tabs.
+ *
+ * Available variables
+ * - attributes: A list of HTML attributes for the wrapper element.
+ * - children: The rendered tabs.
+ *
+ * @see template_preprocess_vertical_tabs()
+ *
+ * @ingroup themeable
+ */
+#}
+<div{{ attributes }}>{{ children }}</div>
diff --git a/web/themes/ventuno/templates/views/views-view--image-library-widget.html.twig b/web/themes/ventuno/templates/views/views-view--image-library-widget.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..7ab5846a5db29ca636582aeffce2f858443fe089
--- /dev/null
+++ b/web/themes/ventuno/templates/views/views-view--image-library-widget.html.twig
@@ -0,0 +1,96 @@
+{#
+/**
+ * @file
+ * Theme override for a main view template.
+ *
+ * Available variables:
+ * - attributes: Remaining HTML attributes for the element.
+ * - css_name: A CSS-safe version of the view name.
+ * - css_class: The user-specified classes names, if any.
+ * - header: The optional header.
+ * - footer: The optional footer.
+ * - rows: The results of the view query, if any.
+ * - empty: The content to display if there are no rows.
+ * - pager: The optional pager next/prev links to display.
+ * - exposed: Exposed widget form/info to display.
+ * - feed_icons: Optional feed icons to display.
+ * - more: An optional link to the next page of results.
+ * - title: Title of the view, only used when displaying in the admin preview.
+ * - title_prefix: Additional output populated by modules, intended to be
+ *   displayed in front of the view title.
+ * - title_suffix: Additional output populated by modules, intended to be
+ *   displayed after the view title.
+ * - attachment_before: An optional attachment view to be displayed before the
+ *   view content.
+ * - attachment_after: An optional attachment view to be displayed after the
+ *   view content.
+ * - dom_id: Unique id for every view being printed to give unique class for
+ *   Javascript.
+ *
+ * @see template_preprocess_views_view()
+ */
+#}
+{{ attach_library('ventuno/pager') }}
+{%
+  set classes = [
+    'view',
+    'view-' ~ id|clean_class,
+    'view-id-' ~ id,
+    'view-display-id-' ~ display_id,
+    dom_id ? 'js-view-dom-id-' ~ dom_id,
+  ]
+%}
+<div{{ attributes.addClass(classes) }}>
+  {{ title_prefix }}
+  {% if title %}
+    {{ title }}
+  {% endif %}
+  {{ title_suffix }}
+  {% if header %}
+    <div class="view-header">
+      {{ header }}
+    </div>
+  {% endif %}
+  {% if exposed %}
+    <div class="view-filters">
+      {{ exposed }}
+    </div>
+  {% endif %}
+  {% if attachment_before %}
+    <div class="attachment attachment-before">
+      {{ attachment_before }}
+    </div>
+  {% endif %}
+
+  {% if rows %}
+    <div class="view-content d-flex">
+      {{ rows }}
+    </div>
+  {% elseif empty %}
+    <div class="view-empty">
+      {{ empty }}
+    </div>
+  {% endif %}
+
+  {% if pager %}
+    {{ pager }}
+  {% endif %}
+  {% if attachment_after %}
+    <div class="attachment attachment-after">
+      {{ attachment_after }}
+    </div>
+  {% endif %}
+  {% if more %}
+    {{ more }}
+  {% endif %}
+  {% if footer %}
+    <div class="view-footer">
+      {{ footer }}
+    </div>
+  {% endif %}
+  {% if feed_icons %}
+    <div class="feed-icons">
+      {{ feed_icons }}
+    </div>
+  {% endif %}
+</div>
diff --git a/web/themes/ventuno/templates/views/views-view-unformatted--image-library-widget.html.twig b/web/themes/ventuno/templates/views/views-view-unformatted--image-library-widget.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..52ddafa8c8137cb3a17fe77f774d94ca8b10a149
--- /dev/null
+++ b/web/themes/ventuno/templates/views/views-view-unformatted--image-library-widget.html.twig
@@ -0,0 +1,33 @@
+{#
+/**
+ * @file
+ * Default theme implementation to display a view of unformatted rows.
+ *
+ * Available variables:
+ * - title: The title of this group of rows. May be empty.
+ * - rows: A list of the view's row items.
+ *   - attributes: The row's HTML attributes.
+ *   - content: The row's content.
+ * - view: The view object.
+ * - default_row_class: A flag indicating whether default classes should be
+ *   used on rows.
+ *
+ * @see template_preprocess_views_view_unformatted()
+ *
+ * @ingroup themeable
+ */
+#}
+{% if title %}
+  <h3>{{ title }}</h3>
+{% endif %}
+{% for row in rows %}
+  {%
+    set row_classes = [
+      default_row_class ? 'views-row',
+      'px-1',
+    ]
+  %}
+  <div{{ row.attributes.addClass(row_classes) }}>
+    {{- row.content -}}
+  </div>
+{% endfor %}
diff --git a/web/themes/ventuno/ventuno.libraries.yml b/web/themes/ventuno/ventuno.libraries.yml
index 7891ad38e2ecac987dbac16a8346b653a1837798..dcc7f1ed388490ce9c3068b0184ddd5fdb4e96f6 100644
--- a/web/themes/ventuno/ventuno.libraries.yml
+++ b/web/themes/ventuno/ventuno.libraries.yml
@@ -30,7 +30,12 @@ searchpage:
   dependencies:
     - ventuno/close
 
-# Bootstrap components
+# Pure BCL components
+accordion:
+  css:
+    theme:
+      assets/css/accordion.css: {}
+
 close:
   css:
     theme:
@@ -48,12 +53,20 @@ tables:
     theme:
       assets/css/tables.css: {}
 
-# Custom components
+# Custom and hybrid (BCL + custom) components
+
 footer:
   css:
     theme:
       assets/css/footer.css: {}
 
+forms:
+  css:
+    theme:
+      assets/css/forms.css: {}
+  js:
+    assets/js/highlight-invalid-fields.js: { minified: true, attributes: { defer: true } }
+
 glide:
   js:
     assets/js/glide.js: { minified: false }
@@ -61,6 +74,11 @@ glide:
     theme:
       assets/css/glide.core.min.css: { minified: true }
 
+ief-entity-table:
+  css:
+    theme:
+      assets/css/ief-entity-table.css: {}
+
 navbar:
   css:
     theme:
@@ -85,6 +103,15 @@ site-alerts-messages:
     theme:
       assets/css/site-alerts-messages.css: {}
 
+show-accordion-invalid-fields:
+  js:
+    assets/js/show-accordion-invalid-fields.js: { minified: true, attributes: { defer: true } }
+
+tabledrag:
+  css:
+    theme:
+      assets/css/tabledrag.css: {}
+
 tour-first-balloon:
   js:
     assets/js/tour-first-balloon.js: { minified: true, attributes: { defer: true } }
diff --git a/web/themes/ventuno/ventuno.theme b/web/themes/ventuno/ventuno.theme
index ac055063c2e255e52e91c6b214ee9511d29026ea..fb28fcacb015941047a958a1e14198eeb370a4b3 100644
--- a/web/themes/ventuno/ventuno.theme
+++ b/web/themes/ventuno/ventuno.theme
@@ -475,23 +475,30 @@ function ventuno_theme_suggestions_form_element_alter(array &$suggestions, array
  */
 function ventuno_form_alter(&$form, FormStateInterface $form_state, $form_id): void {
   // Check if the form contains exposed filter form element.
-  if ($form_id !== 'views_exposed_form') {
-    return;
-  }
+  if ($form_id === 'views_exposed_form') {
+    $route_name = \Drupal::routeMatch()->getRouteName();
+    $view = $form_state->get('view');
+    if ($view->id() === 'search') {
+      $form['keys']['#theme'] = 'input__search_expose_form';
+      $form['keys']['#title_display'] = 'invisible';
+      $form['keys']['#attributes']['placeholder'] = t('Start typing to search…');
+      $form['keys']['#joinup_parent'] = $form_id . '_' . $view->id();
+    }
 
-  $route_name = \Drupal::routeMatch()->getRouteName();
-  $view = $form_state->get('view');
-  if ($view->id() === 'search') {
-    $form['keys']['#theme'] = 'input__search_expose_form';
-    $form['keys']['#title_display'] = 'invisible';
-    $form['keys']['#attributes']['placeholder'] = t('Start typing to search…');
-    $form['keys']['#joinup_parent'] = $form_id . '_' . $view->id();
+    if ($route_name != 'view.search.page_1' && $view->id() === 'search') {
+      // When re-using the exposed search form anywhere other than the search
+      // page, hide the "Sort by" select.
+      $form['sort_by']['#type'] = 'hidden';
+    }
   }
 
-  if ($route_name != 'view.search.page_1' && $view->id() === 'search') {
-    // When re-using the exposed search form anywhere other than the search
-    // page, hide the "Sort by" select.
-    $form['sort_by']['#type'] = 'hidden';
+  // Add classes to the delete action in any kind of form.
+  if (isset($form['actions']['delete'])) {
+    $form['actions']['delete']['#attributes']['class'] = [
+      'btn',
+      'btn-md',
+      'btn-outline-danger',
+    ];
   }
 }
 
@@ -544,3 +551,51 @@ function ventuno_theme_suggestions_field_alter(array &$suggestions, array $varia
     array_unshift($suggestions, 'field__bare');
   }
 }
+
+/**
+ * Implements hook_theme_suggestions_HOOK_alter() for container.html.twig.
+ */
+function ventuno_theme_suggestions_container_alter(array &$suggestions, array $variables) {
+  if (isset($variables['element']['#id'])) {
+    $suggestions[] = 'container__' . str_replace('-', '_', $variables['element']['#id']);
+
+    // Suggestion for form actions container if id has suffix.
+    if (end($suggestions) != 'container__edit_actions' && strpos($variables['element']['#id'], 'edit-actions') !== FALSE) {
+      $suggestions[] = 'container__edit_actions';
+    }
+  }
+}
+
+/**
+ * Implements hook_preprocess_field_ui_table().
+ */
+function ventuno_preprocess_field_ui_table(&$variables) {
+  if ($variables['user']->isAuthenticated()) {
+    $variables['#attached']['library'][] = 'ventuno/tabledrag';
+  }
+}
+
+/**
+ * Implements hook_preprocess_field_multiple_value_form().
+ */
+function ventuno_preprocess_field_multiple_value_form(&$variables) {
+  if ($variables['user']->isAuthenticated()) {
+    $variables['#attached']['library'][] = 'ventuno/tabledrag';
+  }
+}
+
+/**
+ * Implements hook_preprocess_inline_entity_form_entity_table().
+ */
+function ventuno_preprocess_inline_entity_form_entity_table(&$variables) {
+  if ($variables['user']->isAuthenticated()) {
+    $variables['#attached']['library'][] = 'ventuno/ief-entity-table';
+  }
+}
+
+/**
+ * Implements hook_preprocess_form_element().
+ */
+function ventuno_preprocess_form_element(&$variables) {
+  $variables['#attached']['library'][] = 'ventuno/forms';
+}