diff --git a/composer.json b/composer.json
index b8cfe748b..3d58bb239 100644
--- a/composer.json
+++ b/composer.json
@@ -27,6 +27,7 @@
"drupal/acquia_cms_tour": "dev-develop",
"drupal/acquia_drupal_starterkit_content_model": "dev-develop",
"drupal/acquia_drupal_starterkit_headless": "dev-develop",
+ "drupal/acquia_drupal_starterkit_installer": "dev-develop",
"drupal/acquia_drupal_starterkit_low_code": "dev-develop",
"drupal/acquia_drupal_starterkit_media_model": "dev-develop",
"drupal/consumer_image_styles": "^4.0",
@@ -289,6 +290,15 @@
}
}
},
+ "acquia_drupal_starterkit_installer": {
+ "type": "path",
+ "url": "./recipes/acquia_drupal_starterkit_installer",
+ "options": {
+ "versions": {
+ "drupal/acquia_drupal_starterkit_installer": "dev-develop"
+ }
+ }
+ },
"acquia_drupal_starterkit_low_code": {
"type": "path",
"url": "./recipes/acquia_drupal_starterkit_low_code",
diff --git a/composer.lock b/composer.lock
index 9909e1787..a64ab431b 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": "cf4f58c9eaab6a8bf179aef95488b52f",
+ "content-hash": "5f2330b61420c4b4c4bf1cb6767a44f1",
"packages": [
{
"name": "acquia/acquia-cms-starterkit",
@@ -3176,7 +3176,7 @@
"dist": {
"type": "path",
"url": "./recipes/acquia_drupal_starterkit_admin_theme",
- "reference": "c47546c10a61c63ef69fd16c86803f9c8ba9c6c2"
+ "reference": "aa6622831585944cce6b1fd8f5fda0833c164c8f"
},
"require": {
"drupal/core": ">=10.3",
@@ -3200,7 +3200,7 @@
"dist": {
"type": "path",
"url": "./recipes/acquia_drupal_starterkit_basic_html_editor",
- "reference": "5b5ea122a3562d798af87541193578962cbe624f"
+ "reference": "6a14dca07ac402804cfef0e504beb4c17fb97487"
},
"require": {
"drupal/core": ">=10.3",
@@ -3223,7 +3223,7 @@
"dist": {
"type": "path",
"url": "./recipes/acquia_drupal_starterkit_community",
- "reference": "c9c7b8480c0b9210b394161d966589ff53f404ea"
+ "reference": "4155a0d5dab5c927c1bd500b57b2dade6bf9f62e"
},
"require": {
"drupal/acquia_cms_toolbar": "^1.5",
@@ -3248,7 +3248,7 @@
"dist": {
"type": "path",
"url": "./recipes/acquia_drupal_starterkit_content_model",
- "reference": "e6dc048e7033d2ea92f55b48113e3ce150e02c1a"
+ "reference": "8db5360414b8d49f8413871807424cfad1e02469"
},
"require": {
"drupal/acquia_cms_article": "^1.6",
@@ -3275,7 +3275,7 @@
"dist": {
"type": "path",
"url": "./recipes/acquia_drupal_starterkit_full_html_editor",
- "reference": "694af2f66b9786e5c084c8316ee35d38fef70f9a"
+ "reference": "02301358c65dd0e41edd5029e3f8b39c84de126d"
},
"require": {
"drupal/core": ">=10.3",
@@ -3298,7 +3298,7 @@
"dist": {
"type": "path",
"url": "./recipes/acquia_drupal_starterkit_headless",
- "reference": "f1f33130ea1722aea9a39a01ec72a20b94a3688c"
+ "reference": "6d4e3e5e1fd2c3fa57843628f4e5c5ea6e8f10c5"
},
"require": {
"drupal/acquia_cms_headless": "^1.3.17",
@@ -3316,13 +3316,30 @@
"relative": true
}
},
+ {
+ "name": "drupal/acquia_drupal_starterkit_installer",
+ "version": "dev-develop",
+ "dist": {
+ "type": "path",
+ "url": "./recipes/acquia_drupal_starterkit_installer",
+ "reference": "666fc351909021efb5f0b4fb507dac4666675503"
+ },
+ "require": {
+ "drupal/core": ">=10.3"
+ },
+ "type": "drupal-profile",
+ "description": "Provides install-time tweaks for Acquia Drupal Starterkit.",
+ "transport-options": {
+ "relative": true
+ }
+ },
{
"name": "drupal/acquia_drupal_starterkit_low_code",
"version": "dev-develop",
"dist": {
"type": "path",
"url": "./recipes/acquia_drupal_starterkit_low_code",
- "reference": "d0be078b62b2be72d8d9a47b8bda331a167ddf12"
+ "reference": "e9a8fa94bfb9c638202fe998ecb43176c8d3ef1c"
},
"require": {
"drupal/acquia_cms_site_studio": "^1.6",
@@ -3346,7 +3363,7 @@
"dist": {
"type": "path",
"url": "./recipes/acquia_drupal_starterkit_media_model",
- "reference": "6475eae278a8235deeafdef0c327468e3e30506b"
+ "reference": "34b6a93c83ecf17c50cfdbbc6e8732ff4452ae2d"
},
"require": {
"drupal/acquia_cms_audio": "^1.5",
@@ -21767,6 +21784,7 @@
"drupal/acquia_cms_tour": 20,
"drupal/acquia_drupal_starterkit_content_model": 20,
"drupal/acquia_drupal_starterkit_headless": 20,
+ "drupal/acquia_drupal_starterkit_installer": 20,
"drupal/acquia_drupal_starterkit_low_code": 20,
"drupal/acquia_drupal_starterkit_media_model": 20,
"drupal/gin": 5,
diff --git a/recipes/acquia_drupal_starterkit_admin_theme/composer.json b/recipes/acquia_drupal_starterkit_admin_theme/composer.json
index 1bb7fedc5..007a87a22 100644
--- a/recipes/acquia_drupal_starterkit_admin_theme/composer.json
+++ b/recipes/acquia_drupal_starterkit_admin_theme/composer.json
@@ -2,7 +2,7 @@
"name": "drupal/acquia_drupal_starterkit_admin_theme",
"type": "drupal-recipe",
"description": "Sets up a nice administrative theme and navigation.",
- "version": "dev-main",
+ "version": "dev-develop",
"require": {
"drupal/core": ">=10.3",
"drupal/gin": "^3-rc11",
diff --git a/recipes/acquia_drupal_starterkit_basic_html_editor/composer.json b/recipes/acquia_drupal_starterkit_basic_html_editor/composer.json
index f9c3971eb..a98c4cf04 100644
--- a/recipes/acquia_drupal_starterkit_basic_html_editor/composer.json
+++ b/recipes/acquia_drupal_starterkit_basic_html_editor/composer.json
@@ -2,7 +2,7 @@
"name": "drupal/acquia_drupal_starterkit_basic_html_editor",
"type": "drupal-recipe",
"description": "Enhances the Basic HTML editor with better linking and media support.",
- "version": "dev-main",
+ "version": "dev-develop",
"require": {
"drupal/core": ">=10.3",
"drupal/linkit": "^6.1.4"
diff --git a/recipes/acquia_drupal_starterkit_community/composer.json b/recipes/acquia_drupal_starterkit_community/composer.json
index ba56cc4e8..af9e5a327 100644
--- a/recipes/acquia_drupal_starterkit_community/composer.json
+++ b/recipes/acquia_drupal_starterkit_community/composer.json
@@ -2,6 +2,7 @@
"name": "drupal/acquia_drupal_starterkit_community",
"type": "drupal-recipe",
"description": "The community starter kit will install Acquia CMS. An optional content model can be added in the installation process.",
+ "version": "dev-develop",
"require": {
"drupal/core": ">=10.3",
"drupal/acquia_cms_toolbar": "^1.5",
diff --git a/recipes/acquia_drupal_starterkit_content_model/composer.json b/recipes/acquia_drupal_starterkit_content_model/composer.json
index 9951b4c20..d45bf1e29 100644
--- a/recipes/acquia_drupal_starterkit_content_model/composer.json
+++ b/recipes/acquia_drupal_starterkit_content_model/composer.json
@@ -2,6 +2,7 @@
"name": "drupal/acquia_drupal_starterkit_content_model",
"type": "drupal-recipe",
"description": "An media model provides Audio, Document, Image< Video media types.",
+ "version": "dev-develop",
"require": {
"drupal/core": ">=10.3",
"drupal/acquia_cms_article": "^1.6",
diff --git a/recipes/acquia_drupal_starterkit_full_html_editor/composer.json b/recipes/acquia_drupal_starterkit_full_html_editor/composer.json
index a3c9e9384..822cfb879 100644
--- a/recipes/acquia_drupal_starterkit_full_html_editor/composer.json
+++ b/recipes/acquia_drupal_starterkit_full_html_editor/composer.json
@@ -2,7 +2,7 @@
"name": "drupal/acquia_drupal_starterkit_full_html_editor",
"type": "drupal-recipe",
"description": "Enhances the Full HTML editor with better linking and media support.",
- "version": "dev-main",
+ "version": "dev-develop",
"require": {
"drupal/core": ">=10.3",
"drupal/linkit": "^6.1.4"
diff --git a/recipes/acquia_drupal_starterkit_headless/composer.json b/recipes/acquia_drupal_starterkit_headless/composer.json
index 0a591bd07..46222c16b 100644
--- a/recipes/acquia_drupal_starterkit_headless/composer.json
+++ b/recipes/acquia_drupal_starterkit_headless/composer.json
@@ -2,6 +2,7 @@
"name": "drupal/acquia_drupal_starterkit_headless",
"type": "drupal-recipe",
"description": "The community starter kit will install Acquia CMS. An optional content model can be added in the installation process.",
+ "version": "dev-develop",
"require": {
"drupal/core": ">=10.3",
"drupal/acquia_cms_headless": "^1.3.17",
diff --git a/recipes/acquia_drupal_starterkit_installer/acquia_drupal_starterkit_installer.info.yml b/recipes/acquia_drupal_starterkit_installer/acquia_drupal_starterkit_installer.info.yml
new file mode 100644
index 000000000..5f2513d9a
--- /dev/null
+++ b/recipes/acquia_drupal_starterkit_installer/acquia_drupal_starterkit_installer.info.yml
@@ -0,0 +1,10 @@
+name: Acquia Drupal Starterkit Installer
+type: profile
+core_version_requirement: '>=10.3'
+description: 'Provides install-time tweaks for Acquia Drupal Starterkit.'
+# Acquia Drupal Starterkit isn't a distribution, but we need to use this
+# `distribution` key in order to skip the installer's profile selection step.
+distribution:
+ name: Acquia Drupal Starterkit
+ install:
+ finish_url: '/admin/dashboard/welcome'
diff --git a/recipes/acquia_drupal_starterkit_installer/acquia_drupal_starterkit_installer.profile b/recipes/acquia_drupal_starterkit_installer/acquia_drupal_starterkit_installer.profile
new file mode 100644
index 000000000..5142ddea5
--- /dev/null
+++ b/recipes/acquia_drupal_starterkit_installer/acquia_drupal_starterkit_installer.profile
@@ -0,0 +1,284 @@
+addPsr4('Drupal\\acquia_drupal_starterkit_installer\\', __DIR__ . '/src');
+
+ return [
+ 'acquia_drupal_starterkit_installer_prepare_trial' => [
+ 'run' => getenv('DRUPAL_CMS_TRIAL') ? INSTALL_TASK_RUN_IF_REACHED : INSTALL_TASK_SKIP,
+ ],
+ 'acquia_drupal_starterkit_installer_uninstall_myself' => [
+ // As a final task, this profile should uninstall itself.
+ ],
+ ];
+}
+
+/**
+ * Implements hook_install_tasks_alter().
+ */
+function acquia_drupal_starterkit_installer_install_tasks_alter(array &$tasks, array $install_state): void {
+ $insert_before = function (string $key, array $additions) use (&$tasks): void {
+ $key = array_search($key, array_keys($tasks), TRUE);
+ if ($key === FALSE) {
+ return;
+ }
+ // This isn't very clean, but it's the only way to positionally splice into
+ // an associative (and therefore by definition unordered) array.
+ $tasks_before = array_slice($tasks, 0, $key, TRUE);
+ $tasks_after = array_slice($tasks, $key, NULL, TRUE);
+ $tasks = $tasks_before + $additions + $tasks_after;
+ };
+ $insert_before('install_settings_form', [
+ 'acquia_drupal_starterkit_installer_choose_recipes' => [
+ 'display_name' => t('Choose add-ons'),
+ 'type' => 'form',
+ 'run' => array_key_exists('recipes', $install_state['parameters']) ? INSTALL_TASK_SKIP : INSTALL_TASK_RUN_IF_REACHED,
+ 'function' => RecipesForm::class,
+ ],
+ 'acquia_drupal_starterkit_installer_site_name_form' => [
+ 'display_name' => t('Name your site'),
+ 'type' => 'form',
+ 'run' => array_key_exists('site_name', $install_state['parameters']) ? INSTALL_TASK_SKIP : INSTALL_TASK_RUN_IF_REACHED,
+ 'function' => SiteNameForm::class,
+ ],
+ ]);
+
+ // Set English as the default language; it can be changed mid-stream. We can't
+ // use the passed-in $install_state because it's not passed by reference.
+ $GLOBALS['install_state']['parameters'] += ['langcode' => 'en'];
+
+ // The database settings form should be submitted programmatically in the
+ // trial experience.
+ $tasks['install_settings_form']['function'] = 'acquia_drupal_starterkit_installer_database_settings';
+ unset($tasks['install_settings_form']['type']);
+
+ // Submit the site configuration form programmatically.
+ $tasks['install_configure_form'] = [
+ 'function' => 'acquia_drupal_starterkit_installer_configure_site',
+ ];
+
+ // Wrap the install_profile_modules() function, which returns a batch job, and
+ // add all the necessary operations to apply the chosen template recipe.
+ $tasks['install_profile_modules']['function'] = 'acquia_drupal_starterkit_installer_apply_recipes';
+
+ // Since we're using recipes, we can skip `install_profile_themes` and
+ // `install_install_profile`.
+ $tasks['install_profile_themes']['run'] = INSTALL_TASK_SKIP;
+ $tasks['install_install_profile']['run'] = INSTALL_TASK_SKIP;
+}
+
+/**
+ * Implements hook_form_alter() for install_settings_form.
+ *
+ * @see \Drupal\Core\Installer\Form\SiteSettingsForm
+ */
+function acquia_drupal_starterkit_installer_form_install_settings_form_alter(array &$form): void {
+ // Default to SQLite, if available, because it doesn't require any additional
+ // configuration.
+ $sqlite = 'Drupal\sqlite\Driver\Database\sqlite';
+ if (array_key_exists($sqlite, $form['driver']['#options']) && extension_loaded('pdo_sqlite')) {
+ $form['driver']['#default_value'] = $sqlite;
+ }
+}
+
+/**
+ * Runs a batch job that applies the template and add-on recipes.
+ *
+ * @param array $install_state
+ * An array of information about the current installation state.
+ *
+ * @return array
+ * The batch job definition.
+ */
+function acquia_drupal_starterkit_installer_apply_recipes(array &$install_state): array {
+ $batch = install_profile_modules($install_state);
+ $batch['title'] = t('Setting up your site');
+
+ // If we're installing for the trial, install the drupal_cms_trial module.
+ if (getenv('DRUPAL_CMS_TRIAL')) {
+ $batch['operations'][] = ['_install_module_batch', ['drupal_cms_trial', t('Trial experience module')]];
+ }
+
+ $cookbook_path = \Drupal::root() . '/recipes';
+
+ foreach ($install_state['parameters']['recipes'] as $recipe) {
+ $recipe = Recipe::createFromDirectory($cookbook_path . '/' . $recipe);
+
+ foreach (RecipeRunner::toBatchOperations($recipe) as $operation) {
+ $batch['operations'][] = $operation;
+ }
+ }
+ return $batch;
+}
+
+/**
+ * Programmatically submits the database settings form if needed.
+ */
+function acquia_drupal_starterkit_installer_database_settings(array &$install_state): ?array {
+ $interactive = $install_state['interactive'];
+ // If we're installing the in-browser trial, submit the form programmatically
+ // with default values which, thanks to
+ // acquia_drupal_starterkit_installer_form_install_settings_form_alter(), should be the
+ // SQLite driver with its default options.
+ $install_state['interactive'] = getenv('DRUPAL_CMS_TRIAL') ? FALSE : $interactive;
+ $result = install_get_form(SiteSettingsForm::class, $install_state);
+ $install_state['interactive'] = $interactive;
+
+ return $result;
+}
+
+/**
+ * Programmatically executes core's site configuration form.
+ */
+function acquia_drupal_starterkit_installer_configure_site(array &$install_state): ?array {
+ $random_password = (new Random())->machineName();
+ $host = \Drupal::request()->getHost();
+
+ $install_state['forms'] += [
+ 'install_configure_form' => [
+ 'site_name' => $install_state['parameters']['site_name'],
+ 'site_mail' => "no-reply@$host",
+ 'account' => [
+ 'name' => 'admin',
+ 'mail' => "admin@$host",
+ 'pass' => [
+ 'pass1' => $random_password,
+ 'pass2' => $random_password,
+ ],
+ ],
+ ],
+ ];
+ // Temporarily switch to non-interactive mode and programmatically submit
+ // the form.
+ $interactive = $install_state['interactive'];
+ $install_state['interactive'] = FALSE;
+ $result = install_get_form(SiteConfigureForm::class, $install_state);
+ $install_state['interactive'] = $interactive;
+
+ $messenger = \Drupal::messenger();
+ // Clear all previous status messages to avoid clutter.
+ $messenger->deleteByType($messenger::TYPE_STATUS);
+
+ $message = t('Make a note of your login details to access your site later:
Username: admin
Password: @password', [
+ '@password' => $install_state['forms']['install_configure_form']['account']['pass']['pass1'],
+ ]);
+ $messenger->addStatus($message);
+
+ return $result;
+}
+
+/**
+ * Implements hook_library_info_alter().
+ */
+function acquia_drupal_starterkit_installer_library_info_alter(array &$libraries, string $extension): void {
+ global $install_state;
+ // If a library file's path starts with `/`, the library collection system
+ // treats it as relative to the base path.
+ // @see \Drupal\Core\Asset\LibraryDiscoveryParser::buildByExtension()
+ $base_path = '/' . $install_state['profiles']['acquia_drupal_starterkit_installer']->getPath();
+
+ if ($extension === 'claro') {
+ $libraries['maintenance-page']['css']['theme']["$base_path/css/gin-variables.css"] = [];
+ $libraries['maintenance-page']['css']['theme']["$base_path/css/fonts.css"] = [];
+ $libraries['maintenance-page']['css']['theme']["$base_path/css/installer-styles.css"] = [];
+ $libraries['maintenance-page']['css']['theme']["$base_path/css/add-ons.css"] = [];
+ $libraries['maintenance-page']['css']['theme']["$base_path/css/language-dropdown.css"] = [];
+ $libraries['maintenance-page']['js']["$base_path/js/language-dropdown.js"] = [];
+ $libraries['maintenance-page']['dependencies'][] = 'core/once';
+ }
+ if ($extension === 'core') {
+ $libraries['drupal.progress']['js']["$base_path/js/progress.js"] = [];
+ }
+}
+
+/**
+ * Makes configuration changes needed for the in-browser trial.
+ */
+function acquia_drupal_starterkit_installer_prepare_trial(): void {
+ // Use a test mail collector, since the trial won't have access to sendmail.
+ \Drupal::configFactory()
+ ->getEditable('system.mail')
+ ->set('interface.default', 'test_mail_collector')
+ ->save();
+
+ // Disable CSS and JS aggregation.
+ \Drupal::configFactory()
+ ->getEditable('system.performance')
+ ->set('css.preprocess', FALSE)
+ ->set('js.preprocess', FALSE)
+ ->save();
+
+ // Enable verbose logging.
+ \Drupal::configFactory()
+ ->getEditable('system.logging')
+ ->set('error_level', 'verbose')
+ ->save();
+
+ // Disable things that the WebAssembly runtime doesn't (yet) support, like
+ // running external processes or making HTTP requests.
+ // @todo revisit once php-wasm maps HTTP requests from PHP to Fetch API.
+ \Drupal::service(ModuleInstallerInterface::class)->uninstall([
+ 'automatic_updates',
+ 'update',
+ ]);
+ \Drupal::configFactory()
+ ->getEditable('project_browser.admin_settings')
+ ->set('allow_ui_install', FALSE)
+ ->save();
+}
+
+/**
+ * Uninstalls this install profile, as a final step.
+ *
+ * @see drupal_install_system()
+ */
+function acquia_drupal_starterkit_installer_uninstall_myself(): void {
+ // `drupal_install_system()` sets `profile` in `core.extension` regardless
+ // of whether the profile is actually installed by the module installer.
+ \Drupal::configFactory()
+ ->getEditable('core.extension')
+ ->clear('profile')
+ ->save();
+}
+
+/**
+ * Implements hook_theme_registry_alter().
+ */
+function acquia_drupal_starterkit_installer_theme_registry_alter(array &$hooks): void {
+ global $install_state;
+ $installer_path = $install_state['profiles']['acquia_drupal_starterkit_installer']->getPath();
+
+ $hooks['install_page']['path'] = $installer_path . '/templates';
+}
+
+/**
+ * Preprocess function for all pages in the installer.
+ */
+function acquia_drupal_starterkit_installer_preprocess_install_page(array &$variables): void {
+ // Don't show the task list or the version of Drupal.
+ unset($variables['page']['sidebar_first'], $variables['site_version']);
+
+ global $install_state;
+ $images_path = $install_state['profiles']['acquia_drupal_starterkit_installer']->getPath() . '/images';
+ $images_path = \Drupal::service(FileUrlGeneratorInterface::class)
+ ->generateString($images_path);
+ $variables['images_path'] = $images_path;
+}
diff --git a/recipes/acquia_drupal_starterkit_installer/composer.json b/recipes/acquia_drupal_starterkit_installer/composer.json
new file mode 100644
index 000000000..eab8583b2
--- /dev/null
+++ b/recipes/acquia_drupal_starterkit_installer/composer.json
@@ -0,0 +1,9 @@
+{
+ "name": "drupal/acquia_drupal_starterkit_installer",
+ "type": "drupal-profile",
+ "description": "Provides install-time tweaks for Acquia Drupal Starterkit.",
+ "version": "dev-develop",
+ "require": {
+ "drupal/core": ">=10.3"
+ }
+}
diff --git a/recipes/acquia_drupal_starterkit_installer/css/add-ons.css b/recipes/acquia_drupal_starterkit_installer/css/add-ons.css
new file mode 100644
index 000000000..a966205e2
--- /dev/null
+++ b/recipes/acquia_drupal_starterkit_installer/css/add-ons.css
@@ -0,0 +1,74 @@
+#edit-add-ons {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 10px 20px;
+}
+
+#edit-add-ons .form-item {
+ display: inline-block;
+ margin: 0;
+}
+
+#edit-add-ons [type="checkbox"] {
+ position: absolute;
+ overflow: hidden;
+ clip: rect(1px, 1px, 1px, 1px);
+ width: 1px;
+ height: 1px;
+ word-wrap: normal;
+}
+
+#edit-add-ons label {
+ display: inline-block;
+ color: #39353e;
+ padding: 15px 20px;
+ border: solid 2px #666;
+ font-size: 26px;
+ border-radius: 10px;
+ user-select: none;
+}
+
+#edit-add-ons label:hover {
+ background-color: #f8fafe;
+ color: black;
+}
+
+#edit-add-ons :checked + label {
+ position: relative;
+ background-color: var(--gin-color-primary);
+ border-color: var(--gin-color-primary);
+ color: white;
+}
+
+#edit-add-ons :checked+label:before {
+ position: absolute;
+ top: 0;
+ inset-inline-start: 0;
+ display: block;
+ width: 40px;
+ aspect-ratio: 1;
+ transform: translate(-50%, -50%); /* RTL */
+ content: url('../images/check-circle.svg');
+ background-color: white;
+ border-radius: 50%;
+}
+
+@media (forced-colors: active) {
+ #edit-add-ons :checked+label:before {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ content: "✓";
+ border: solid 2px;
+ font-weight: bold;
+ }
+}
+
+[dir="rtl"] #edit-add-ons :checked+label:before {
+ transform: translate(50%, -50%);
+}
+
+#edit-add-ons [type="checkbox"]:focus + label {
+ outline: 3px solid var(--color-focus);
+ outline-offset: 2px;
+}
diff --git a/recipes/acquia_drupal_starterkit_installer/css/fonts.css b/recipes/acquia_drupal_starterkit_installer/css/fonts.css
new file mode 100644
index 000000000..e646a41b1
--- /dev/null
+++ b/recipes/acquia_drupal_starterkit_installer/css/fonts.css
@@ -0,0 +1,139 @@
+/* cyrillic-ext */
+@font-face {
+ font-family: 'Inter';
+ font-style: italic;
+ font-weight: 100 900;
+ font-display: block;
+ src: url('../fonts/inter-italic-cyrillic-ext.woff2') format('woff2');
+ unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
+}
+
+/* cyrillic */
+@font-face {
+ font-family: 'Inter';
+ font-style: italic;
+ font-weight: 100 900;
+ font-display: block;
+ src: url('../fonts/inter-italic-cyrillic.woff2') format('woff2');
+ unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
+}
+
+/* greek-ext */
+@font-face {
+ font-family: 'Inter';
+ font-style: italic;
+ font-weight: 100 900;
+ font-display: block;
+ src: url('../fonts/inter-italic-greek-ext.woff2') format('woff2');
+ unicode-range: U+1F00-1FFF;
+}
+
+/* greek */
+@font-face {
+ font-family: 'Inter';
+ font-style: italic;
+ font-weight: 100 900;
+ font-display: block;
+ src: url('../fonts/inter-italic-greek.woff2') format('woff2');
+ unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
+}
+
+/* vietnamese */
+@font-face {
+ font-family: 'Inter';
+ font-style: italic;
+ font-weight: 100 900;
+ font-display: block;
+ src: url('../fonts/inter-italic-vietnamese.woff2') format('woff2');
+ unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
+}
+
+/* latin-ext */
+@font-face {
+ font-family: 'Inter';
+ font-style: italic;
+ font-weight: 100 900;
+ font-display: block;
+ src: url('../fonts/inter-italic-latin-ext.woff2') format('woff2');
+ unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
+}
+
+/* latin */
+@font-face {
+ font-family: 'Inter';
+ font-style: italic;
+ font-weight: 100 900;
+ font-display: block;
+ src: url('../fonts/inter-italic-latin.woff2') format('woff2');
+ unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
+}
+
+/* cyrillic-ext */
+@font-face {
+ font-family: 'Inter';
+ font-style: normal;
+ font-weight: 100 900;
+ font-display: block;
+ src: url('../fonts/inter-cryllic-ext.woff2') format('woff2');
+ unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
+}
+
+/* cyrillic */
+@font-face {
+ font-family: 'Inter';
+ font-style: normal;
+ font-weight: 100 900;
+ font-display: block;
+ src: url('../fonts/inter-cyrillic.woff2') format('woff2');
+ unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
+}
+
+/* greek-ext */
+@font-face {
+ font-family: 'Inter';
+ font-style: normal;
+ font-weight: 100 900;
+ font-display: block;
+ src: url('../fonts/inter-greek-ext.woff2') format('woff2');
+ unicode-range: U+1F00-1FFF;
+}
+
+/* greek */
+@font-face {
+ font-family: 'Inter';
+ font-style: normal;
+ font-weight: 100 900;
+ font-display: block;
+ src: url('../fonts/inter-greek.woff2') format('woff2');
+ unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
+}
+
+/* vietnamese */
+@font-face {
+ font-family: 'Inter';
+ font-style: normal;
+ font-weight: 100 900;
+ font-display: block;
+ src: url('../fonts/inter-vietnamese.woff2') format('woff2');
+ unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
+}
+
+/* latin-ext */
+@font-face {
+ font-family: 'Inter';
+ font-style: normal;
+ font-weight: 100 900;
+ font-display: block;
+ src: url('../fonts/inter-latin-ext.woff2') format('woff2');
+ unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
+}
+
+/* latin */
+@font-face {
+ font-family: 'Inter';
+ font-style: normal;
+ font-weight: 100 900;
+ font-display: block;
+ src: url('../fonts/inter-latin.woff2') format('woff2');
+ unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
+}
diff --git a/recipes/acquia_drupal_starterkit_installer/css/gin-variables.css b/recipes/acquia_drupal_starterkit_installer/css/gin-variables.css
new file mode 100644
index 000000000..a2f2f8d91
--- /dev/null
+++ b/recipes/acquia_drupal_starterkit_installer/css/gin-variables.css
@@ -0,0 +1,275 @@
+/**
+ * @file
+ * CSS variables for the Acquia Drupal Starterkit Installer. Mostly copied from Gin, with
+ * modifications.
+ */
+
+:root {
+
+ --color-focus: var(--gin-color-focus);
+ --gin-color-primary: rgb(var(--gin-color-primary-rgb));
+ --gin-color-primary-rgb: 5, 80, 230;
+ --gin-color-primary-light-rgb: 205, 220, 250;
+ --gin-color-primary-hover: #0444c4;
+ --gin-color-primary-active: #043cad;
+ --gin-bg-app-rgb: 248, 250, 254;
+ --gin-bg-header: #e1eafc;
+ --gin-color-sticky-rgb: 235, 241, 253;
+
+ --gin-color-title: #222330;
+ --gin-color-text: #222330;
+ --gin-color-text-light: #545560;
+ --gin-color-focus: rgba(0, 125, 250, .6);
+ --gin-color-focus-border: rgba(0, 0, 0, .2);
+ --gin-color-focus-neutral-rgb: rgba(0, 0, 0, .4);
+ --gin-color-disabled: #8d8d8d;
+ --gin-color-disabled-bg: #eaeaea;
+ --gin-color-disabled-border: #c2c2c2;
+ --gin-color-warning: #d8b234;
+ --gin-color-warning-light: #efcf64;
+ --gin-bg-warning: #605328;
+ --gin-bg-warning-light: rgba(226, 151, 0, .08);
+ --gin-color-danger: #cc3d3d;
+ --gin-color-danger-lightest: #fdd9d9;
+ --gin-color-danger-light: #f39b9d;
+ --gin-bg-danger: #583333;
+ --gin-bg-danger-light: rgba(222, 117, 96, .1);
+ --gin-color-green: #058260;
+ --gin-color-green-light: #32cea4;
+ --gin-color-green-lightest: #adebdb;
+ --gin-bg-green: #145242;
+ --gin-bg-green-light: rgba(72, 171, 123, .1);
+ --gin-color-info: #082538;
+ --gin-color-info-light: #589ac5;
+ --gin-bg-info: #122b3c;
+ --gin-status-text: #777;
+ --gin-status-bg: #eee;
+ --gin-status-success-text: #1d7c4e;
+ --gin-status-success-bg: #26a76930;
+ --gin-status-warning-text: #826b1f;
+ --gin-status-warning-bg: rgba(226, 151, 0, .15);
+ --gin-status-danger-text: #cc3d3d;
+ --gin-status-danger-bg: rgba(222, 117, 96, .15);
+ --gin-color-contextual: var(--gin-color-text);
+ --gin-color-contextual-text: #eee;
+ --gin-bg-input: #fff;
+ --gin-bg-layer: #fff;
+ --gin-bg-layer2: #edeff5;
+ --gin-bg-layer3: #fff;
+ --gin-bg-layer4: #e2e5ec;
+ --gin-bg-secondary: var(--gin-bg-layer);
+ --gin-bg-header: #eeeff3;
+ --gin-bg-unpublished: var(--gin-bg-danger-light);
+ --gin-pattern: var(--gin-border-color);
+ --gin-pattern-fallback: var(--gin-bg-layer2);
+ --gin-pattern-square: .5rem;
+ --gin-font: Ginter, Inter, "Helvetica Neue", BlinkMacSystemFont, -apple-system, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, sans-serif;
+ --gin-font-size-xxs: .75rem;
+ --gin-font-size-xs: small;
+ --gin-font-size-s: .875rem;
+ --gin-font-size: 1rem;
+ --gin-font-size-m: var(--gin-font-size);
+ --gin-font-size-l: 1.125rem;
+ --gin-font-size-xl: 1.25rem;
+ --gin-font-size-h3: 1.5rem;
+ --gin-font-size-h2: 1.75rem;
+ --gin-font-size-h1: 1.6rem;
+ --gin-font-size-quote: 1.1em;
+ --gin-font-weight-normal: 400;
+ --gin-font-weight-semibold: 525;
+ --gin-font-weight-bold: 575;
+ --gin-font-weight-heavy: 625;
+ --gin-spacing-xxxs: .125rem;
+ --gin-spacing-xxs: .25rem;
+ --gin-spacing-xs: .5rem;
+ --gin-spacing-s: .75rem;
+ --gin-spacing-m: 1rem;
+ --gin-spacing-l: 1.5rem;
+ --gin-spacing-xl: 2rem;
+ --gin-spacing-xxl: 3rem;
+ --gin-spacing-xxxl: 4rem;
+ --gin-icon-color: #414247;
+ --gin-icon-size-close: 20px;
+ --gin-icon-size-toolbar-secondary: 17px;
+ --gin-icon-size-toolbar: 17px;
+ --gin-icon-size-sidebar-toggle: 21px;
+ --gin-border-xxs: .125rem;
+ --gin-border-xs: .25rem;
+ --gin-border-s: .375rem;
+ --gin-border-m: .5rem;
+ --gin-border-l: .75rem;
+ --gin-border-xl: 1rem;
+ --gin-border-color: #d4d4d8;
+ --gin-border-color-secondary: rgba(0, 0, 0, .08);
+ --gin-border-color-layer: rgba(0, 0, 0, .08);
+ --gin-border-color-layer2: #d4d4d8;
+ --gin-border-color-table: rgba(0, 0, 0, .1);
+ --gin-border-color-table-header: rgba(0, 0, 0, .3);
+ --gin-border-color-form-element: #8e929c;
+ --size-summary-border-radius: calc(var(--gin-border-m) - 1px);
+ --gin-easing: cubic-bezier(.19, 1, .22, 1);
+ --gin-transition: .15s var(--gin-easing);
+ --gin-transition-fast: .3s var(--gin-easing);
+ --gin-shadow-l1: 0 1px 2px rgb(20 45 82 / 2%), 0 3px 4px rgb(20 45 82 / 3%), 0 5px 8px rgb(20 45 82 / 4%);
+ --gin-shadow-l2: 0 1px 2px rgb(20 45 82 / 2%), 0 3px 4px rgb(20 45 82 / 3%), 0 5px 8px rgb(20 45 82 / 4%), 0 20px 24px rgb(20 45 82 / 12%);
+ --gin-height-sticky: 60px;
+ --gin-toolbar-width-collapsed: 66px;
+ --gin-toolbar-width: 256px;
+ --gin-toolbar-height: 0px;
+ --gin-toolbar-secondary-height: 0px;
+ --gin-toolbar-bg-level2: #edeff5;
+ --gin-toolbar-bg-level3: rgba(44, 45, 47, .05);
+ --gin-toolbar-y-offset: 0px;
+ --gin-toolbar-x-offset: 0px;
+ --gin-scroll-offset: 0px;
+ --gin-sticky-offset: 0px;
+ --gin-sidebar-small-width: 320px;
+ --gin-sidebar-min-width: 240px;
+ --gin-sidebar-width: 320px;
+ --gin-sidebar-max-width: 560px;
+ --gin-sidebar-offset: var(--gin-sidebar-width);
+ --gin-switch: #26a769;
+ --gin-shadow-button: #00000033;
+ --gin-color-button-text: #fff;
+ --gin-offset-x: var(--gin-toolbar-x-offset);
+ --gin-offset-y: calc(var(--gin-toolbar-y-offset) + var(--gin-sticky-offset));
+ --gin-link-decoration-style: dotted;
+ --gin-max-line-length: 80ch;
+ --input-line-height: var(--gin-spacing-l);
+ --input-padding-horizontal: var(--gin-spacing-s);
+ --input-padding-vertical: var(--gin-spacing-xs);
+ --gin-tooltip-bg: #232429;
+ --jui-dialog-z-index: 1260;
+}
+
+@media (min-width: 61em) {
+ :root {
+ --gin-font-size-h1: 1.8125rem;
+ --gin-font-size-quote: 1.2em;
+ }
+}
+
+@media (min-width: 90em) {
+ :root {
+ --gin-font-size-h1: 2.125rem;
+ }
+}
+
+@media (min-width: 61em) {
+ :root {
+ --gin-icon-size-toolbar: 20px;
+ }
+}
+
+@media (min-width: 64em) {
+ :root {
+ --gin-sticky-offset: var(--gin-height-sticky);
+ }
+}
+
+@media (min-width: 80em) {
+ :root {
+ --gin-sidebar-width: 360px;
+ }
+}
+
+[data-gin-layout-density=small] {
+ --gin-spacing-density-xxs: .15625rem;
+ --gin-spacing-density-xs: .3125rem;
+ --gin-spacing-density-s: .46875rem;
+ --gin-spacing-density-m: .625rem;
+ --gin-spacing-density-l: .9375rem;
+ --gin-spacing-density-xl: 1.25rem;
+ --gin-spacing-density-xxl: 1.875rem;
+ --gin-spacing-density-xxxl: 2.5rem;
+}
+
+[data-gin-layout-density=medium] {
+ --gin-spacing-density-xxs: .1875rem;
+ --gin-spacing-density-xs: .375rem;
+ --gin-spacing-density-s: .5625rem;
+ --gin-spacing-density-m: .75rem;
+ --gin-spacing-density-l: 1.125rem;
+ --gin-spacing-density-xl: 1.5rem;
+ --gin-spacing-density-xxl: 2.25rem;
+ --gin-spacing-density-xxxl: 3rem;
+}
+
+:root {
+ --gin-spacing-density-xxs: .25rem;
+ --gin-spacing-density-xs: .5rem;
+ --gin-spacing-density-s: .75rem;
+ --gin-spacing-density-m: 1rem;
+ --gin-spacing-density-l: 1.5rem;
+ --gin-spacing-density-xl: 2rem;
+ --gin-spacing-density-xxl: 3rem;
+ --gin-spacing-density-xxxl: 4rem;
+}
+
+.gin--dark-mode {
+ --gin-color-title: #fff;
+ --gin-color-text: #d2d3d3;
+ --gin-color-text-light: #9e9fa0;
+ --gin-shadow-button: rgba(#111, .9);
+ --gin-color-button-text: #111;
+ --gin-color-focus: rgb(81, 168, 255);
+ --gin-color-focus-border: rgba(0, 0, 0, .8);
+ --gin-color-focus-neutral-rgb: rgba(255, 255, 255, .8);
+ --gin-color-disabled: #646464;
+ --gin-color-disabled-border: #646464;
+ --gin-color-disabled-bg: #47474c;
+ --gin-color-warning: #dec15f;
+ --gin-bg-warning-light: rgba(222, 193, 95, .1);
+ --gin-color-danger: #ce6060;
+ --gin-color-danger-lightest: #483439;
+ --gin-color-green: #32cea4;
+ --gin-color-info: #559bca;
+ --gin-bg-input: var(--gin-bg-layer2);
+ --gin-bg-app: #1b1b1d;
+ --gin-bg-layer: #2a2a2d;
+ --gin-bg-layer2: #3b3b3f;
+ --gin-bg-layer3: #47474c;
+ --gin-bg-layer4: #19191b;
+ --gin-bg-secondary: var(--gin-bg-app);
+ --gin-bg-unpublished: var(--gin-bg-warning-light);
+ --gin-color-contextual: var(--gin-bg-layer3);
+ --gin-border-color: #43454a;
+ --gin-border-color-secondary: rgba(255, 255, 255, .075);
+ --gin-border-color-layer: rgba(0, 0, 0, .05);
+ --gin-border-color-layer2: #76777b;
+ --gin-border-color-table: #43454a;
+ --gin-border-color-table-header: rgba(255, 255, 255, .12);
+ --gin-border-color-form-element: var(--gin-border-color-layer2);
+ --gin-bg-header: #1b1b1d;
+ --gin-switch: var(--gin-color-primary);
+ --gin-status-text: var(--gin-color-text-light);
+ --gin-status-bg: rgba(255, 255, 255, .1);
+ --gin-status-success-text: #39b77b;
+ --gin-status-success-bg: #26a76930;
+ --gin-status-warning-text: #e8d185;
+ --gin-status-warning-bg: rgba(226, 151, 0, .15);
+ --gin-status-danger-text: #e69e9e;
+ --gin-status-danger-bg: rgba(222, 117, 96, .15);
+ --gin-shadow-l1: 0 1px 2px rgb(0 0 0 / 2%), 0 3px 4px rgb(0 0 0 / 3%), 0 5px 8px rgb(0 0 0 / 4%);
+ --gin-shadow-l2: 0 1px 2px rgb(0 0 0 / 2%), 0 3px 4px rgb(0 0 0 / 3%), 0 5px 8px rgb(0 0 0 / 4%), 0 20px 24px rgb(0 0 0 / 12%);
+ --gin-icon-color: #888;
+ --gin-pattern-fallback: var(--gin-bg-layer2);
+ --gin-pattern: var(--gin-border-color);
+ --gin-tooltip-bg: var(--gin-bg-layer3);
+}
+
+@media (forced-colors: active) {
+ :root {
+ --gin-icon-color: CanvasText;
+ }
+}
+
+.entity-meta {
+ --entity-meta-color-bg: transparent;
+ --entity-meta-border-color: var(--gin-border-color);
+}
+
+.accordion {
+ --accordion-bg-color: transparent;
+ --accordion-border-color: var(--gin-border-color);
+}
diff --git a/recipes/acquia_drupal_starterkit_installer/css/installer-styles.css b/recipes/acquia_drupal_starterkit_installer/css/installer-styles.css
new file mode 100644
index 000000000..e8f99fb23
--- /dev/null
+++ b/recipes/acquia_drupal_starterkit_installer/css/installer-styles.css
@@ -0,0 +1,171 @@
+/**
+ * @file
+ * This file specifically overrides Claro's maintenance page styling to make
+ * tweaks specific to the Acquia Drupal Starterkit installer. None of this needs to be
+ * reusable.
+ */
+
+@view-transition {
+ navigation: auto;
+}
+
+*, *::before, *::after {
+ box-sizing: border-box;
+ -webkit-font-smoothing: antialiased;
+}
+
+a {
+ color: var(--gin-color-primary);
+}
+
+.install-page {
+ background: linear-gradient(0.33turn, #ccbaf4, #22a5e5);
+}
+
+.cms-installer {
+ display: flex;
+ width: 75%;
+ max-width: 1400px;
+ margin: 0 auto;
+ border: 1px solid transparent;
+ border-radius: 0.5rem;
+ background: #fff;
+ box-shadow: var(--shadow-z3);
+ font-family: "Inter", system-ui;
+}
+
+.cms-installer__first {
+ flex: 1;
+ padding: 100px;
+}
+
+.cms-installer__second {
+ position: relative; /* Anchor image. */
+ flex: 1;
+}
+
+.cms-installer__bg {
+ position: absolute;
+ inset: 0;
+ width: 100%;
+ height: 100%;
+ border-radius: 0 0.5rem 0.5rem 0;
+ object-fit: cover;
+ object-position: 90% center;
+}
+
+.cms-installer__header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ flex-wrap: wrap;
+ margin-bottom: 50px;
+}
+
+.cms-installer .cms-installer__heading {
+ font-size: 48px;
+ font-weight: 900;
+}
+
+.cms-installer .cms-installer__heading-secondary {
+ font-size: 36px;
+ opacity: 0.7;
+}
+
+.cms-installer__language-button {
+ display: inline-flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 10px;
+ appearance: none;
+ border: 0;
+ background: transparent;
+ font-weight: 600;
+ cursor: pointer;
+
+ &:before {
+ display: inline-block;
+ width: 20px;
+ aspect-ratio: 1;
+ content: "";
+ background-color: currentColor;
+ -webkit-mask-image: url('../images/translate.svg');
+ mask-image: url('../images/translate.svg');
+ -webkit-mask-repeat: no-repeat;
+ mask-repeat: no-repeat;
+ -webkit-mask-position: center;
+ mask-position: center;
+ -webkit-mask-size: contain;
+ mask-size: contain;
+ }
+}
+
+.cms-installer .cms-installer__main-heading {
+ font-size: 62px;
+ font-weight: 900;
+ line-height: 1;
+}
+
+.cms-installer__subhead {
+ font-size: 25px;
+ color: #484848;
+}
+
+.cms-installer .button {
+ all: revert;
+ display: inline-flex;
+ align-items: center;
+ flex-wrap: wrap;
+ height: 78px;
+ padding-inline: 30px;
+ border: solid 1px transparent;
+ background: transparent;
+ font-family: inherit;
+ font-size: 20px;
+ font-weight: 400;
+ text-decoration: underline;
+ box-shadow: none;
+ border-radius: 5px;
+ cursor: pointer;
+}
+.cms-installer .button:focus {
+ outline: 3px solid var(--color-focus);
+ outline-offset: 2px;
+}
+
+.cms-installer .button + .button {
+ margin-inline-start: 10px;
+}
+
+.cms-installer .button--primary {
+ padding: calc(var(--gin-spacing-s) - 2px) var(--gin-spacing-m);
+ border-radius: var(--gin-border-m);
+ box-shadow: 0 1px 2px var(--gin-color-primary-light);
+ transition: var(--gin-transition);
+ padding-inline: 50px;
+ background-color: var(--gin-color-primary);
+ color: var(--gin-color-button-text);
+ text-decoration: none;
+}
+
+.cms-installer .button--primary:active {
+ background-color: var(--gin-color-primary-active);
+}
+
+.cms-installer .button--primary:hover {
+ background-color: var(--gin-color-primary-hover);
+}
+
+.cms-installer__form-group {
+ margin-block: 50px;
+}
+
+.progress {
+ width: fit-content;
+ margin: 50px auto;
+}
+
+.progress__percentage {
+ font-size: 16px;
+ font-weight: 600;
+}
diff --git a/recipes/acquia_drupal_starterkit_installer/css/language-dropdown.css b/recipes/acquia_drupal_starterkit_installer/css/language-dropdown.css
new file mode 100644
index 000000000..a7f17c98a
--- /dev/null
+++ b/recipes/acquia_drupal_starterkit_installer/css/language-dropdown.css
@@ -0,0 +1,38 @@
+.cms-installer__language {
+ position: relative; /* Anchor dropdown. */
+}
+
+.cms-installer__language-dropdown {
+ position: absolute;
+ top: 100%;
+ left: 50%;
+ z-index: 1;
+ translate: -50% 0;
+ visibility: hidden;
+ opacity: 0;
+ width: min(90vw, 1000px);
+ padding: 20px;
+ background: white;
+ border: solid 1px transparent;
+ border-radius: 0.5rem;
+ box-shadow: 0 40px 40px #00000088;
+ transition: all 0.2s;
+}
+
+.cms-installer__language-button[aria-expanded="true"] + .cms-installer__language-dropdown {
+ visibility: visible;
+ opacity: 1;
+}
+
+.cms-installer__language-list {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+ column-width: 150px;
+ column-gap: 10px;
+
+}
+
+.cms-installer__list-item {
+ margin-bottom: 8px;
+}
diff --git a/recipes/acquia_drupal_starterkit_installer/fonts/inter-cryllic-ext.woff2 b/recipes/acquia_drupal_starterkit_installer/fonts/inter-cryllic-ext.woff2
new file mode 100644
index 000000000..1029b2511
Binary files /dev/null and b/recipes/acquia_drupal_starterkit_installer/fonts/inter-cryllic-ext.woff2 differ
diff --git a/recipes/acquia_drupal_starterkit_installer/fonts/inter-cyrillic.woff2 b/recipes/acquia_drupal_starterkit_installer/fonts/inter-cyrillic.woff2
new file mode 100644
index 000000000..4a88c023d
Binary files /dev/null and b/recipes/acquia_drupal_starterkit_installer/fonts/inter-cyrillic.woff2 differ
diff --git a/recipes/acquia_drupal_starterkit_installer/fonts/inter-greek-ext.woff2 b/recipes/acquia_drupal_starterkit_installer/fonts/inter-greek-ext.woff2
new file mode 100644
index 000000000..bbcbf2702
Binary files /dev/null and b/recipes/acquia_drupal_starterkit_installer/fonts/inter-greek-ext.woff2 differ
diff --git a/recipes/acquia_drupal_starterkit_installer/fonts/inter-greek.woff2 b/recipes/acquia_drupal_starterkit_installer/fonts/inter-greek.woff2
new file mode 100644
index 000000000..1339c681c
Binary files /dev/null and b/recipes/acquia_drupal_starterkit_installer/fonts/inter-greek.woff2 differ
diff --git a/recipes/acquia_drupal_starterkit_installer/fonts/inter-italic-cyrillic-ext.woff2 b/recipes/acquia_drupal_starterkit_installer/fonts/inter-italic-cyrillic-ext.woff2
new file mode 100644
index 000000000..83e50e1ed
Binary files /dev/null and b/recipes/acquia_drupal_starterkit_installer/fonts/inter-italic-cyrillic-ext.woff2 differ
diff --git a/recipes/acquia_drupal_starterkit_installer/fonts/inter-italic-cyrillic.woff2 b/recipes/acquia_drupal_starterkit_installer/fonts/inter-italic-cyrillic.woff2
new file mode 100644
index 000000000..87a694984
Binary files /dev/null and b/recipes/acquia_drupal_starterkit_installer/fonts/inter-italic-cyrillic.woff2 differ
diff --git a/recipes/acquia_drupal_starterkit_installer/fonts/inter-italic-greek-ext.woff2 b/recipes/acquia_drupal_starterkit_installer/fonts/inter-italic-greek-ext.woff2
new file mode 100644
index 000000000..ea4c043b8
Binary files /dev/null and b/recipes/acquia_drupal_starterkit_installer/fonts/inter-italic-greek-ext.woff2 differ
diff --git a/recipes/acquia_drupal_starterkit_installer/fonts/inter-italic-greek.woff2 b/recipes/acquia_drupal_starterkit_installer/fonts/inter-italic-greek.woff2
new file mode 100644
index 000000000..05fae388e
Binary files /dev/null and b/recipes/acquia_drupal_starterkit_installer/fonts/inter-italic-greek.woff2 differ
diff --git a/recipes/acquia_drupal_starterkit_installer/fonts/inter-italic-latin-ext.woff2 b/recipes/acquia_drupal_starterkit_installer/fonts/inter-italic-latin-ext.woff2
new file mode 100644
index 000000000..b1fae490f
Binary files /dev/null and b/recipes/acquia_drupal_starterkit_installer/fonts/inter-italic-latin-ext.woff2 differ
diff --git a/recipes/acquia_drupal_starterkit_installer/fonts/inter-italic-latin.woff2 b/recipes/acquia_drupal_starterkit_installer/fonts/inter-italic-latin.woff2
new file mode 100644
index 000000000..ac7e0de6b
Binary files /dev/null and b/recipes/acquia_drupal_starterkit_installer/fonts/inter-italic-latin.woff2 differ
diff --git a/recipes/acquia_drupal_starterkit_installer/fonts/inter-italic-vietnamese.woff2 b/recipes/acquia_drupal_starterkit_installer/fonts/inter-italic-vietnamese.woff2
new file mode 100644
index 000000000..ddc6badf4
Binary files /dev/null and b/recipes/acquia_drupal_starterkit_installer/fonts/inter-italic-vietnamese.woff2 differ
diff --git a/recipes/acquia_drupal_starterkit_installer/fonts/inter-latin-ext.woff2 b/recipes/acquia_drupal_starterkit_installer/fonts/inter-latin-ext.woff2
new file mode 100644
index 000000000..82e134726
Binary files /dev/null and b/recipes/acquia_drupal_starterkit_installer/fonts/inter-latin-ext.woff2 differ
diff --git a/recipes/acquia_drupal_starterkit_installer/fonts/inter-latin.woff2 b/recipes/acquia_drupal_starterkit_installer/fonts/inter-latin.woff2
new file mode 100644
index 000000000..e0cab47a8
Binary files /dev/null and b/recipes/acquia_drupal_starterkit_installer/fonts/inter-latin.woff2 differ
diff --git a/recipes/acquia_drupal_starterkit_installer/fonts/inter-vietnamese.woff2 b/recipes/acquia_drupal_starterkit_installer/fonts/inter-vietnamese.woff2
new file mode 100644
index 000000000..e9057325d
Binary files /dev/null and b/recipes/acquia_drupal_starterkit_installer/fonts/inter-vietnamese.woff2 differ
diff --git a/recipes/acquia_drupal_starterkit_installer/images/check-circle.svg b/recipes/acquia_drupal_starterkit_installer/images/check-circle.svg
new file mode 100644
index 000000000..bfd46c389
--- /dev/null
+++ b/recipes/acquia_drupal_starterkit_installer/images/check-circle.svg
@@ -0,0 +1 @@
+
diff --git a/recipes/acquia_drupal_starterkit_installer/images/cms-installer-bg.webp b/recipes/acquia_drupal_starterkit_installer/images/cms-installer-bg.webp
new file mode 100644
index 000000000..bcd3530d3
Binary files /dev/null and b/recipes/acquia_drupal_starterkit_installer/images/cms-installer-bg.webp differ
diff --git a/recipes/acquia_drupal_starterkit_installer/images/translate.svg b/recipes/acquia_drupal_starterkit_installer/images/translate.svg
new file mode 100644
index 000000000..de26e7ce4
--- /dev/null
+++ b/recipes/acquia_drupal_starterkit_installer/images/translate.svg
@@ -0,0 +1 @@
+
diff --git a/recipes/acquia_drupal_starterkit_installer/js/language-dropdown.js b/recipes/acquia_drupal_starterkit_installer/js/language-dropdown.js
new file mode 100644
index 000000000..e6943d9c7
--- /dev/null
+++ b/recipes/acquia_drupal_starterkit_installer/js/language-dropdown.js
@@ -0,0 +1,106 @@
+/**
+ * @file
+ * Creation and interactions for the language dropdown.
+ */
+
+((Drupal, once, drupalSettings) => {
+
+ /**
+ * Gets the current URL and queryStrings, sets the language, and returns the
+ * full URL.
+ *
+ * @param {string} langcode - The language code (e.g. 'es').
+ * @returns {string}
+ */
+ function getLanguageURL(langcode) {
+ const urlParams = new URLSearchParams(window.location.search);
+ urlParams.set('langcode', langcode);
+
+
+ return `${window.location.pathname}?${urlParams}`;
+ }
+
+ /**
+ * Creates the element.
+ */
+ function createElement() {
+ const dropdownWrapper = document.querySelector('.cms-installer__language');
+ const dropdown = document.createElement('div');
+
+ dropdown.setAttribute('id', 'cms-installer-language-dropdown');
+ dropdown.classList.add('cms-installer__language-dropdown');
+ dropdown.innerHTML = `
+
', + '#markup' => $this->t('You can change your mind later.'), + '#suffix' => '
', + ]; + + $options = [ + 'acquia_drupal_starterkit_community' => $this->t('Acquia Drupal Starterkit Community'), + 'acquia_drupal_starterkit_headless' => $this->t('Acquia Drupal Starterkit Headless'), + 'acquia_drupal_starterkit_low_code' => $this->t('Acquia Drupal Starterkit Low-Code'), + 'acquia_drupal_starterkit_content_model' => $this->t('Acquia Drupal Starterkit Content Model'), + 'acquia_drupal_starterkit_media_model' => $this->t('Acquia Drupal Starterkit Media Model'), + ]; + + $form['add_ons'] = [ + '#prefix' => '