diff --git a/project_template/composer.json b/project_template/composer.json
index fd08374a6f7e3979e70e78bbad6f0545ba8bafee..ea00d5503495149483359013483d4ffc2a66d997 100644
--- a/project_template/composer.json
+++ b/project_template/composer.json
@@ -34,6 +34,7 @@
         "drupal/drupal_cms_seo_tools": "^1.0.1",
         "drupal/drupal_cms_starter": "^1.0.1",
         "drupal/project_browser": "@alpha",
+        "drupal/recipe_installer_kit": "^1@alpha",
         "drupal/webform": "@beta",
         "drush/drush": "^13"
     },
diff --git a/project_template/web/profiles/drupal_cms_installer/drupal_cms_installer.info.yml b/project_template/web/profiles/drupal_cms_installer/drupal_cms_installer.info.yml
index bd7a5238a5909ae49eb56d19b99e9f877b0b792b..a3a4b3e3b3724ad97249f102fa101e9aadf22721 100644
--- a/project_template/web/profiles/drupal_cms_installer/drupal_cms_installer.info.yml
+++ b/project_template/web/profiles/drupal_cms_installer/drupal_cms_installer.info.yml
@@ -1,13 +1,36 @@
 name: Drupal CMS Installer
 type: profile
-core_version_requirement: '>=10.3'
+core_version_requirement: '^11.1'
 description: 'Provides install-time tweaks for Drupal CMS. Not to be used in production.'
-# Drupal CMS isn't a distribution, but we need to use this `distribution` key in order
-# to skip the installer's profile selection step.
+
+# Use the `distribution` key to skip the installer's profile selection step.
 distribution:
   name: Drupal CMS
   install:
     finish_url: '/admin/dashboard/welcome'
+    theme: drupal_cms_installer_theme
+
+forms:
+  - '\Drupal\RecipeKit\Installer\Form\RecipesForm'
+  - '\Drupal\RecipeKit\Installer\Form\SiteNameForm'
+
+recipes:
+  required:
+    - drupal/drupal_cms_starter
+  optional:
+    'Blog':
+      - drupal/drupal_cms_blog
+    'Case Studies':
+      - drupal/drupal_cms_case_study
+    'Events':
+      - drupal/drupal_cms_events
+    'News':
+      - drupal/drupal_cms_news
+    'Person Profiles':
+      - drupal/drupal_cms_person
+    'Projects':
+      - drupal/drupal_cms_project
+
 # Explicitly provide an empty list of themes -- this prevents the installer from
 # injecting Stark into it.
 # @see install_profile_info()
diff --git a/project_template/web/profiles/drupal_cms_installer/drupal_cms_installer.profile b/project_template/web/profiles/drupal_cms_installer/drupal_cms_installer.profile
index 1ad09758421945a2913b7db86529893603a5f7c3..e40d9c5faa01ad6e4fa10bd74057fbfaf1f35590 100644
--- a/project_template/web/profiles/drupal_cms_installer/drupal_cms_installer.profile
+++ b/project_template/web/profiles/drupal_cms_installer/drupal_cms_installer.profile
@@ -2,347 +2,43 @@
 
 declare(strict_types=1);
 
-use Composer\InstalledVersions;
-use Drupal\Core\DependencyInjection\ContainerBuilder;
-use Drupal\Core\Render\Element\Password;
-use Drupal\Core\Extension\ModuleInstallerInterface;
-use Drupal\Core\File\FileUrlGeneratorInterface;
 use Drupal\Core\Form\FormStateInterface;
-use Drupal\Core\Messenger\MessengerInterface;
-use Drupal\Core\Recipe\Recipe;
-use Drupal\Core\Recipe\RecipeRunner;
-use Drupal\drupal_cms_installer\Form\RecipesForm;
-use Drupal\drupal_cms_installer\Form\SiteNameForm;
-use Drupal\drupal_cms_installer\MessageInterceptor;
-use Drupal\drupal_cms_installer\RecipeAppliedSubscriber;
-
-const SQLITE_DRIVER = 'Drupal\sqlite\Driver\Database\sqlite';
+use Drupal\RecipeKit\Installer\Hooks;
+use Drupal\RecipeKit\Installer\Messenger;
 
 /**
  * Implements hook_install_tasks().
  */
 function drupal_cms_installer_install_tasks(): array {
-  // Ensure our forms are loadable in all situations, even if the installer is
-  // not a Composer-managed package.
-  \Drupal::service('class_loader')
-    ->addPsr4('Drupal\\drupal_cms_installer\\', __DIR__ . '/src');
+  $tasks = Hooks::installTasks();
 
-  // If the container can be altered, wrap the messenger service to suppress
-  // certain messages.
-  $container = \Drupal::getContainer();
-  if ($container instanceof ContainerBuilder) {
-    $container->set('messenger', new MessageInterceptor(
-      \Drupal::messenger(),
-    ));
+  if (getenv('IS_DDEV_PROJECT')) {
+    Messenger::reject(
+      'All necessary changes to %dir and %file have been made, so you should remove write permissions to them now in order to avoid security risks. If you are unsure how to do so, consult the <a href=":handbook_url">online handbook</a>.',
+    );
   }
-
-  return [
-    'drupal_cms_installer_uninstall_myself' => [
-      // As a final task, this profile should uninstall itself.
-    ],
-  ];
+  return $tasks;
 }
 
 /**
  * Implements hook_install_tasks_alter().
  */
 function drupal_cms_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', [
-    'drupal_cms_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,
-    ],
-    'drupal_cms_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,
-    ],
-  ]);
-
-  $configure_form_task = $tasks['install_configure_form'];
-  unset(
-    $tasks['install_install_profile'],
-    $tasks['install_configure_form'],
-  );
-  $insert_before('install_profile_modules', [
-    'install_install_profile' => [
-      'function' => 'drupal_cms_installer_install_myself',
-    ],
-    'install_configure_form' => $configure_form_task,
-  ]);
-
-  // 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'];
-
-  // 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'] = 'drupal_cms_installer_apply_recipes';
-}
-
-/**
- * Installs the User module, and this profile.
- *
- * @param array $install_state
- *   The current installation state.
- */
-function drupal_cms_installer_install_myself(array &$install_state): void {
-  // We'll need User installed for the next step, which is configuring the site
-  // and administrator account.
-  \Drupal::service(ModuleInstallerInterface::class)->install([
-    'user',
-  ]);
-  // Officially install this profile so that its behaviors and visual overrides
-  // will be in effect for the remainder of the install process. This also
-  // ensures that the administrator role is created and assigned to user 1 in
-  // the next step.
-  install_install_profile($install_state);
+  Hooks::installTasksAlter($tasks, $install_state);
 }
 
 /**
- * Implements hook_form_alter() for install_settings_form.
- *
- * @see \Drupal\Core\Installer\Form\SiteSettingsForm
+ * Implements hook_form_alter().
  */
-function drupal_cms_installer_form_install_settings_form_alter(array &$form): void {
-  // Default to SQLite, if available, because it doesn't require any additional
-  // configuration.
-  if (extension_loaded('pdo_sqlite') && array_key_exists(SQLITE_DRIVER, $form['driver']['#options'])) {
-    $form['driver']['#default_value'] = SQLITE_DRIVER;
-    $form['driver']['#type'] = 'select';
-
-    // The database file path has a sensible default value, so move it into the
-    // advanced options.
-    $form['settings'][SQLITE_DRIVER]['advanced_options']['database'] = $form['settings'][SQLITE_DRIVER]['database'];
-    unset($form['settings'][SQLITE_DRIVER]['database']);
-
-    $form['help'] = [
-      '#prefix' => '<p class="cms-installer__subhead">',
-      '#markup' => t("You don't need to change anything here unless you want to use a different database type."),
-      '#suffix' => '</p>',
-      '#weight' => -50,
-    ];
-  }
+function drupal_cms_installer_form_alter(array &$form, FormStateInterface $form_state, string $form_id): void {
+  Hooks::formAlter($form, $form_state, $form_id);
 }
 
 /**
  * Implements hook_form_alter() for install_configure_form.
- *
- * @see \Drupal\Core\Installer\Form\SiteConfigureForm
  */
-function drupal_cms_installer_form_install_configure_form_alter(array &$form, FormStateInterface $form_state): void {
-  global $install_state;
-
-  $form['#title'] = t('Create your account');
-
-  $form['help'] = [
-    '#prefix' => '<p class="cms-installer__subhead">',
-    '#markup' => t('Creating an account allows you to log in to your site.'),
-    '#suffix' => '</p>',
-    '#weight' => -40,
-  ];
-
-  $form['site_information']['#type'] = 'container';
-  // We collected the site name in a previous step.
-  $form['site_information']['site_name'] = [
-    '#type' => 'hidden',
-    '#default_value' => $GLOBALS['install_state']['parameters']['site_name'],
-  ];
-
-  // Use a custom submit handler to set the site email.
-  unset($form['site_information']['site_mail']);
-  $form['#submit'][] = 'drupal_cms_installer_update_site_mail';
-
-  $form['admin_account']['#type'] = 'container';
-  // `admin` is a sensible name for user 1.
-  $form['admin_account']['account']['name'] = [
-    '#type' => 'hidden',
-    '#default_value' => 'admin',
-  ];
-  $form['admin_account']['account']['mail'] = [
-    '#prefix' => '<div class="cms-installer__form-group">',
-    '#suffix' => '</div>',
-    '#type' => 'email',
-    '#title' => t('Email'),
-    '#required' => TRUE,
-    '#default_value' => $install_state['forms']['install_configure_form']['account']['mail'] ?? '',
-    '#weight' => 10,
-  ];
-  $form['admin_account']['account']['pass'] = [
-    '#prefix' => '<div class="cms-installer__form-group">',
-    '#suffix' => '</div>',
-    '#type' => 'password',
-    '#title' => t('Password'),
-    '#required' => TRUE,
-    '#default_value' => $install_state['forms']['install_configure_form']['account']['pass']['pass1'] ?? '',
-    '#weight' => 20,
-    '#value_callback' => '_drupal_cms_installer_password_value',
-  ];
-
-  // Hide the timezone selection. Core automatically uses client-side JavaScript
-  // to detect it, but we don't need to expose that to the user. But the
-  // JavaScript expects the form elements to look a certain way, so hiding the
-  // fields visually is the correct approach here.
-  // @see core/misc/timezone.js
-  $form['regional_settings']['#attributes']['class'][] = 'visually-hidden';
-  // Don't allow the timezone selection to be tab-focused.
-  $form['regional_settings']['date_default_timezone']['#attributes']['tabindex'] = -1;
-
+function drupal_cms_installer_form_install_configure_form_alter(array &$form): void {
   // We always install Automatic Updates, so we don't need to expose the update
   // notification settings.
   $form['update_notifications']['#access'] = FALSE;
-
-  $form['actions']['submit']['#value'] = t('Finish');
-}
-
-/**
- * Custom submit handler to update the site email.
- */
-function drupal_cms_installer_update_site_mail(array &$form, FormStateInterface $form_state): void {
-  \Drupal::configFactory()
-    ->getEditable('system.site')
-    ->set('mail', $form_state->getValue(['account', 'mail']))
-    ->save();
-}
-
-function _drupal_cms_installer_password_value(&$element, $input, FormStateInterface $form_state): mixed {
-  // Work around this fact that Drush and `drupal install`, which submit this
-  // form programmatically, assume the password is a password_confirm element.
-  if (is_array($input) && $form_state->isProgrammed()) {
-    $input = $input['pass1'];
-  }
-  return Password::valueCallback($element, $input, $form_state);
-}
-
-/**
- * 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 drupal_cms_installer_apply_recipes(array &$install_state): array {
-  // If the installer ran before but failed mid-stream, don't reapply any
-  // recipes that were successfully applied.
-  $recipes_to_apply = array_diff(
-    $install_state['parameters']['recipes'],
-    \Drupal::state()->get(RecipeAppliedSubscriber::STATE_KEY, []),
-  );
-
-  // If we've already applied all the chosen recipes, there's nothing to do.
-  // Since we only start applying recipes once `install_profile_modules()` has
-  // finished, we can be safely certain that we already did that step.
-  if (empty($recipes_to_apply)) {
-    return [];
-  }
-
-  $batch = install_profile_modules($install_state);
-  $batch['title'] = t('Setting up your site');
-
-  $recipe_operations = [];
-
-  foreach ($recipes_to_apply as $name) {
-    $recipe = InstalledVersions::getInstallPath('drupal/' . $name);
-    $recipe = Recipe::createFromDirectory($recipe);
-    $recipe_operations = array_merge($recipe_operations, RecipeRunner::toBatchOperations($recipe));
-  }
-
-  // Only do each recipe's batch operations once.
-  foreach ($recipe_operations as $operation) {
-    if (in_array($operation, $batch['operations'], TRUE)) {
-      continue;
-    }
-    else {
-      $batch['operations'][] = $operation;
-    }
-  }
-
-  return $batch;
-}
-
-/**
- * Implements hook_library_info_alter().
- */
-function drupal_cms_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']['drupal_cms_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']['dependencies'][] = 'core/once';
-  }
-  if ($extension === 'core') {
-    $libraries['drupal.progress']['js']["$base_path/js/progress.js"] = [];
-  }
-}
-
-/**
- * Uninstalls this install profile, as a final step.
- *
- * @see drupal_install_system()
- */
-function drupal_cms_installer_uninstall_myself(): void {
-  \Drupal::service(ModuleInstallerInterface::class)->uninstall([
-    'drupal_cms_installer',
-  ]);
-
-  // The install is done, so we don't need the list of applied recipes anymore.
-  \Drupal::state()->delete(RecipeAppliedSubscriber::STATE_KEY);
-
-  // Clear all previous status messages to avoid clutter.
-  \Drupal::messenger()->deleteByType(MessengerInterface::TYPE_STATUS);
-
-  // Invalidate the container in case any stray requests were made during the
-  // install process, which would have bootstrapped Drupal and cached the
-  // install-time container, which is now stale (during the installer, the
-  // container cannot be dumped, which would normally happen during the
-  // container rebuild triggered by uninstalling this profile). We do not want
-  // to redirect into Drupal with a stale container.
-  \Drupal::service('kernel')->invalidateContainer();
-}
-
-/**
- * Implements hook_theme_registry_alter().
- */
-function drupal_cms_installer_theme_registry_alter(array &$hooks): void {
-  global $install_state;
-  $installer_path = $install_state['profiles']['drupal_cms_installer']->getPath();
-
-  $hooks['install_page']['path'] = $installer_path . '/templates';
-}
-
-/**
- * Preprocess function for all pages in the installer.
- */
-function drupal_cms_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']['drupal_cms_installer']->getPath() . '/images';
-  $images_path = \Drupal::service(FileUrlGeneratorInterface::class)
-    ->generateString($images_path);
-  $variables['images_path'] = $images_path;
 }
diff --git a/project_template/web/profiles/drupal_cms_installer/drupal_cms_installer.services.yml b/project_template/web/profiles/drupal_cms_installer/drupal_cms_installer.services.yml
index 40478993ccd15756811606db8e0bbd48b93ab995..79adafd058fa05be48b7630feb20f259863bf8ce 100644
--- a/project_template/web/profiles/drupal_cms_installer/drupal_cms_installer.services.yml
+++ b/project_template/web/profiles/drupal_cms_installer/drupal_cms_installer.services.yml
@@ -1,5 +1,5 @@
 services:
-  Drupal\drupal_cms_installer\RecipeAppliedSubscriber:
+  Drupal\RecipeKit\Installer\RecipeAppliedSubscriber:
     autowire: true
     tags:
       - { name: event_subscriber }
diff --git a/project_template/web/profiles/drupal_cms_installer/src/Form/RecipesForm.php b/project_template/web/profiles/drupal_cms_installer/src/Form/RecipesForm.php
deleted file mode 100644
index 38c0de6dc4b8074f4411ce1b89c04696ebc902ad..0000000000000000000000000000000000000000
--- a/project_template/web/profiles/drupal_cms_installer/src/Form/RecipesForm.php
+++ /dev/null
@@ -1,120 +0,0 @@
-<?php
-
-namespace Drupal\drupal_cms_installer\Form;
-
-use Drupal\Core\Form\FormBase;
-use Composer\InstalledVersions;
-use Drupal\Component\Serialization\Yaml;
-use Drupal\Core\Form\FormStateInterface;
-use Drupal\Core\Render\Element\Checkboxes;
-
-/**
- * Provides a form to choose the site template and optional add-on recipes.
- *
- * @todo Present this as a mini project browser once
- *   https://www.drupal.org/i/3450629 is fixed.
- */
-final class RecipesForm extends FormBase {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getFormId(): string {
-    return 'drupal_cms_installer_recipes_form';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function buildForm(array $form, FormStateInterface $form_state): array {
-    $form['#title'] = $this->t('Get started');
-
-    $form['help'] = [
-      '#prefix' => '<p class="cms-installer__subhead">',
-      '#markup' => $this->t('You can select pre-configured types of content now, or add them later.'),
-      '#suffix' => '</p>',
-    ];
-
-    $form['add_ons'] = [
-      '#prefix' => '<div class="cms-installer__form-group">',
-      '#suffix' => '</div>',
-      '#type' => 'checkboxes',
-      '#value_callback' => static::class . '::valueCallback',
-    ];
-
-    $base_recipe_path = InstalledVersions::getInstallPath('drupal/drupal_cms_starter');
-    $cookbook_path = dirname($base_recipe_path);
-
-    // Read the list of optional recipes from the base recipe's `composer.json`.
-    $composer = file_get_contents($base_recipe_path . '/composer.json');
-    $composer = json_decode($composer, TRUE, flags: JSON_THROW_ON_ERROR);
-    $optional_recipes = array_keys($composer['suggest'] ?? []);
-
-    foreach ($optional_recipes as $name) {
-      $recipe = $cookbook_path . '/' . basename($name) . '/recipe.yml';
-      if (file_exists($recipe)) {
-        $recipe = file_get_contents($recipe);
-        $recipe = Yaml::decode($recipe);
-        $key = basename($name);
-        $form['add_ons']['#options'][$key] = $recipe['name'];
-      }
-    }
-
-    $form['add_ons']['help'] = [
-      '#prefix' => '<p class="cms-installer__info">',
-      '#markup' => $this->t('Don’t see what you’re looking for? You can set up customized content later.'),
-      '#suffix' => '</p>',
-      '#weight' => 100,
-    ];
-
-    $form['actions'] = [
-      'submit' => [
-        '#type' => 'submit',
-        '#value' => $this->t('Next'),
-        '#button_type' => 'primary',
-        '#op' => 'submit',
-        '#attributes' => [
-          'class' => ['button--next']
-        ]
-      ],
-      'skip' => [
-        '#type' => 'submit',
-        '#value' => $this->t('Skip this step'),
-        '#op' => 'skip',
-      ],
-      '#type' => 'actions',
-    ];
-    return $form;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function submitForm(array &$form, FormStateInterface $form_state): void {
-    global $install_state;
-    $install_state['parameters']['recipes'] = ['drupal_cms_starter'];
-
-    $pressed_button = $form_state->getTriggeringElement();
-    // Only choose add-ons if the Next button was pressed, or if the form was
-    // submitted programmatically (i.e., by `drush site:install`).
-    if (($pressed_button && $pressed_button['#op'] === 'submit') || $form_state->isProgrammed()) {
-      $add_ons = $form_state->getValue('add_ons', []);
-      $add_ons = array_filter($add_ons);
-      array_push($install_state['parameters']['recipes'], ...array_values($add_ons));
-    }
-  }
-
-  public static function valueCallback(&$element, $input, FormStateInterface $form_state): array {
-    // If the input was a comma-separated string or `*`, transform it -- this is
-    // for compatibility with `drush site:install`.
-    if (is_string($input)) {
-      $selections = $input === '*'
-        ? array_keys($element['#options'])
-        : array_map('trim', explode(',', $input));
-
-      $input = array_combine($selections, $selections);
-    }
-    return Checkboxes::valueCallback($element, $input, $form_state);
-  }
-
-}
diff --git a/project_template/web/profiles/drupal_cms_installer/src/Form/SiteNameForm.php b/project_template/web/profiles/drupal_cms_installer/src/Form/SiteNameForm.php
deleted file mode 100644
index 445ca9764497e5b46a8064821727eefdca183449..0000000000000000000000000000000000000000
--- a/project_template/web/profiles/drupal_cms_installer/src/Form/SiteNameForm.php
+++ /dev/null
@@ -1,67 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-namespace Drupal\drupal_cms_installer\Form;
-
-use Drupal\Core\Form\FormBase;
-use Drupal\Core\Form\FormStateInterface;
-
-/**
- * Defines a form to set the site name.
- */
-final class SiteNameForm extends FormBase {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getFormId(): string {
-    return 'drupal_cms_installer_site_name_form';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function buildForm(array $form, FormStateInterface $form_state): array {
-    global $install_state;
-
-    $form['#title'] = $this->t('Give your site a name');
-
-    $form['help'] = [
-      '#prefix' => '<p class="cms-installer__subhead">',
-      '#markup' => $this->t('You can change this later.'),
-      '#suffix' => '</p>',
-    ];
-
-    $form['site_name'] = [
-      '#prefix' => '<div class="cms-installer__form-group">',
-      '#suffix' => '</div>',
-      '#type' => 'textfield',
-      '#title' => $this->t('Site name'),
-      '#required' => TRUE,
-      '#default_value' => $install_state['forms']['install_configure_form']['site_name'] ?? $this->t('My Drupal CMS site'),
-    ];
-    $form['actions'] = [
-      '#type' => 'actions',
-      'submit' => [
-        '#type' => 'submit',
-        '#value' => $this->t('Next'),
-        '#button_type' => 'primary',
-        '#attributes' => [
-          'class' => ['button--next']
-        ],
-      ],
-    ];
-
-    return $form;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function submitForm(array &$form, FormStateInterface $form_state): void {
-    global $install_state;
-    $install_state['parameters']['site_name'] = $form_state->getValue('site_name');
-  }
-
-}
diff --git a/project_template/web/profiles/drupal_cms_installer/src/MessageInterceptor.php b/project_template/web/profiles/drupal_cms_installer/src/MessageInterceptor.php
deleted file mode 100644
index 1f5958065c472ace0502d0d6edbdc481f451a8d6..0000000000000000000000000000000000000000
--- a/project_template/web/profiles/drupal_cms_installer/src/MessageInterceptor.php
+++ /dev/null
@@ -1,90 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-namespace Drupal\drupal_cms_installer;
-
-use Drupal\Core\Messenger\MessengerInterface;
-use Drupal\Core\StringTranslation\TranslatableMarkup;
-
-/**
- * Decorates the messenger to suppress or alter certain install-time messages.
- */
-final class MessageInterceptor implements MessengerInterface {
-
-  private array $reject = [
-    'Congratulations, you installed @drupal!',
-  ];
-
-  public function __construct(
-    private readonly MessengerInterface $decorated,
-  ) {
-    if (getenv('IS_DDEV_PROJECT')) {
-      $this->reject[] = 'All necessary changes to %dir and %file have been made, so you should remove write permissions to them now in order to avoid security risks. If you are unsure how to do so, consult the <a href=":handbook_url">online handbook</a>.';
-    }
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function addMessage($message, $type = self::TYPE_STATUS, $repeat = FALSE): static {
-    $raw = $message instanceof TranslatableMarkup
-      ? $message->getUntranslatedString()
-      : strval($message);
-
-    if (!in_array($raw, $this->reject, TRUE)) {
-      $this->decorated->addMessage($message, $type, $repeat);
-    }
-    return $this;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function addStatus($message, $repeat = FALSE): static {
-    return $this->addMessage($message, self::TYPE_STATUS, $repeat);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function addError($message, $repeat = FALSE): static {
-    return $this->addMessage($message, self::TYPE_ERROR, $repeat);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function addWarning($message, $repeat = FALSE): static {
-    return $this->addMessage($message, self::TYPE_WARNING, $repeat);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function all(): array {
-    return $this->decorated->all();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function messagesByType($type): array {
-    return $this->decorated->messagesByType($type);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function deleteAll(): array {
-    return $this->decorated->deleteAll();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function deleteByType($type): array {
-    return $this->decorated->deleteByType($type);
-  }
-
-}
diff --git a/project_template/web/profiles/drupal_cms_installer/src/RecipeAppliedSubscriber.php b/project_template/web/profiles/drupal_cms_installer/src/RecipeAppliedSubscriber.php
deleted file mode 100644
index d9babe3371edc458fd75921bc6daa507ed9c125f..0000000000000000000000000000000000000000
--- a/project_template/web/profiles/drupal_cms_installer/src/RecipeAppliedSubscriber.php
+++ /dev/null
@@ -1,59 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-namespace Drupal\drupal_cms_installer;
-
-use Drupal\Core\Recipe\RecipeAppliedEvent;
-use Drupal\Core\State\StateInterface;
-use Symfony\Component\EventDispatcher\EventSubscriberInterface;
-
-/**
- * Tracks our applied recipes.
- *
- * This is done to increase fault tolerance. On hosting plans that don't have
- * a ton of RAM or computing power to spare, the possibility of the installer
- * timing out or failing in mid-stream is increased, especially with a big,
- * complex distribution like Drupal CMS. Tracking the recipes which have been
- * applied allows the installer to recover and "pick up where it left off",
- * without applying recipes that have already been applied successfully. Once
- * the install is done, the list of recipes is deleted.
- *
- * @see drupal_cms_installer_apply_recipes()
- * @see drupal_cms_installer_uninstall_myself()
- */
-final class RecipeAppliedSubscriber implements EventSubscriberInterface {
-
-  /**
-   * The state key that stores the record of our applied recipes.
-   *
-   * @var string
-   */
-  public const STATE_KEY = 'drupal_cms_installer.applied_recipes';
-
-  public function __construct(
-    private readonly StateInterface $state,
-  ) {}
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function getSubscribedEvents(): array {
-    return [
-      RecipeAppliedEvent::class => 'onApply',
-    ];
-  }
-
-  /**
-   * Reacts when a recipe is applied to the site.
-   *
-   * @param \Drupal\Core\Recipe\RecipeAppliedEvent $event
-   *   The event object.
-   */
-  public function onApply(RecipeAppliedEvent $event): void {
-    $list = $this->state->get(static::STATE_KEY, []);
-    $list[] = basename($event->recipe->path);
-    $this->state->set(static::STATE_KEY, $list);
-  }
-
-}
diff --git a/project_template/web/profiles/drupal_cms_installer/tests/src/Functional/CommandLineInstallTest.php b/project_template/web/profiles/drupal_cms_installer/tests/src/Functional/CommandLineInstallTest.php
index e70bf3a883d47360e0e689f5a0dd9616b7d190a2..6f27f82a694a9c1c08ea6a72f65f87ba764026e2 100644
--- a/project_template/web/profiles/drupal_cms_installer/tests/src/Functional/CommandLineInstallTest.php
+++ b/project_template/web/profiles/drupal_cms_installer/tests/src/Functional/CommandLineInstallTest.php
@@ -5,7 +5,7 @@ declare(strict_types=1);
 namespace Drupal\Tests\drupal_cms_installer\Functional;
 
 use Drupal\Core\Test\TestSetupTrait;
-use Drupal\drupal_cms_installer\RecipeAppliedSubscriber;
+use Drupal\RecipeKit\Installer\RecipeAppliedSubscriber;
 use Drush\TestTraits\DrushTestTrait;
 use PHPUnit\Framework\TestCase;
 use Symfony\Component\Filesystem\Filesystem;
diff --git a/project_template/web/profiles/drupal_cms_installer/tests/src/Functional/InteractiveInstallTest.php b/project_template/web/profiles/drupal_cms_installer/tests/src/Functional/InteractiveInstallTest.php
index 10e629b4632d35e72cf14625cd1af7bf094b45c8..1a72dbc693b9f39fc8af72afe67e0bbea21b6365 100644
--- a/project_template/web/profiles/drupal_cms_installer/tests/src/Functional/InteractiveInstallTest.php
+++ b/project_template/web/profiles/drupal_cms_installer/tests/src/Functional/InteractiveInstallTest.php
@@ -10,8 +10,8 @@ use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Extension\ThemeExtensionList;
 use Drupal\Core\Extension\ThemeHandlerInterface;
 use Drupal\Core\State\StateInterface;
-use Drupal\drupal_cms_installer\RecipeAppliedSubscriber;
 use Drupal\FunctionalTests\Installer\InstallerTestBase;
+use Drupal\RecipeKit\Installer\RecipeAppliedSubscriber;
 use Drupal\user\Entity\User;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -110,7 +110,7 @@ class InteractiveInstallTest extends InstallerTestBase {
     $this->assertNull($this->container->get(StateInterface::class)->get(RecipeAppliedSubscriber::STATE_KEY));
 
     // The site name and site-wide email address should have been set.
-    // @see \Drupal\drupal_cms_installer\Form\SiteNameForm
+    // @see \Drupal\RecipeKit\Installer\Form\SiteNameForm
     $site_config = $this->config('system.site');
     $this->assertSame('Installer Test', $site_config->get('name'));
     $this->assertSame("hello@good.bye", $site_config->get('mail'));
@@ -123,8 +123,9 @@ class InteractiveInstallTest extends InstallerTestBase {
     $this->assertContains('administrator', $account->getRoles());
 
     // The installer should have uninstalled itself.
-    // @see drupal_cms_installer_uninstall_myself()
     $this->assertFalse($this->container->getParameter('install_profile'));
+    // The theme used in the installer, should not be installed.
+    $this->assertArrayNotHasKey('drupal_cms_installer_theme', $this->config('core.extension')->get('theme'));
 
     // Ensure that there are non-core extensions installed, which proves that
     // recipes were applied during site installation.
diff --git a/project_template/web/profiles/drupal_cms_installer/css/add-ons.css b/project_template/web/profiles/drupal_cms_installer/theme/css/add-ons.css
similarity index 100%
rename from project_template/web/profiles/drupal_cms_installer/css/add-ons.css
rename to project_template/web/profiles/drupal_cms_installer/theme/css/add-ons.css
diff --git a/project_template/web/profiles/drupal_cms_installer/css/fonts.css b/project_template/web/profiles/drupal_cms_installer/theme/css/fonts.css
similarity index 100%
rename from project_template/web/profiles/drupal_cms_installer/css/fonts.css
rename to project_template/web/profiles/drupal_cms_installer/theme/css/fonts.css
diff --git a/project_template/web/profiles/drupal_cms_installer/css/gin-variables.css b/project_template/web/profiles/drupal_cms_installer/theme/css/gin-variables.css
similarity index 100%
rename from project_template/web/profiles/drupal_cms_installer/css/gin-variables.css
rename to project_template/web/profiles/drupal_cms_installer/theme/css/gin-variables.css
diff --git a/project_template/web/profiles/drupal_cms_installer/css/installer-styles.css b/project_template/web/profiles/drupal_cms_installer/theme/css/installer-styles.css
similarity index 100%
rename from project_template/web/profiles/drupal_cms_installer/css/installer-styles.css
rename to project_template/web/profiles/drupal_cms_installer/theme/css/installer-styles.css
diff --git a/project_template/web/profiles/drupal_cms_installer/theme/drupal_cms_installer_theme.info.yml b/project_template/web/profiles/drupal_cms_installer/theme/drupal_cms_installer_theme.info.yml
new file mode 100644
index 0000000000000000000000000000000000000000..945a3869ba1042098b97d0b35b1e271e9a4db4cd
--- /dev/null
+++ b/project_template/web/profiles/drupal_cms_installer/theme/drupal_cms_installer_theme.info.yml
@@ -0,0 +1,10 @@
+name: Drupal CMS Installer Theme
+type: theme
+core_version_requirement: '^11.1'
+description: 'Themes the Drupal CMS installer. Not to be used in production.'
+base theme: claro
+libraries-extend:
+  claro/maintenance-page:
+    - drupal_cms_installer_theme/maintenance-page
+  core/drupal.progress:
+    - drupal_cms_installer_theme/drupal.progress
diff --git a/project_template/web/profiles/drupal_cms_installer/theme/drupal_cms_installer_theme.libraries.yml b/project_template/web/profiles/drupal_cms_installer/theme/drupal_cms_installer_theme.libraries.yml
new file mode 100644
index 0000000000000000000000000000000000000000..04fd5c3e37f5df60a4230b863047e4e1a68a67eb
--- /dev/null
+++ b/project_template/web/profiles/drupal_cms_installer/theme/drupal_cms_installer_theme.libraries.yml
@@ -0,0 +1,13 @@
+maintenance-page:
+  css:
+    theme:
+      css/gin-variables.css: {}
+      css/fonts.css: {}
+      css/installer-styles.css: {}
+      css/add-ons.css: {}
+  dependencies:
+    - core/once
+
+drupal.progress:
+  js:
+    js/progress.js: {}
diff --git a/project_template/web/profiles/drupal_cms_installer/theme/drupal_cms_installer_theme.theme b/project_template/web/profiles/drupal_cms_installer/theme/drupal_cms_installer_theme.theme
new file mode 100644
index 0000000000000000000000000000000000000000..4ca6b3dfa4454d1c6dc2bbdfdb16a00348e012a0
--- /dev/null
+++ b/project_template/web/profiles/drupal_cms_installer/theme/drupal_cms_installer_theme.theme
@@ -0,0 +1,100 @@
+<?php
+
+declare(strict_types=1);
+
+use Drupal\Core\File\FileUrlGeneratorInterface;
+
+/**
+ * Implements template_preprocess_install_page().
+ */
+function drupal_cms_installer_theme_preprocess_install_page(array &$variables): void {
+  $theme_path = \Drupal::theme()->getActiveTheme()->getPath();
+  $variables['theme_path'] = \Drupal::service(FileUrlGeneratorInterface::class)
+    ->generateString($theme_path);
+}
+
+/**
+ * Implements hook_form_FORM_ID_alter() for installer_site_name_form.
+ */
+function drupal_cms_installer_theme_form_installer_site_name_form_alter(array &$form): void {
+  $form['#title'] = t('Give your site a name');
+
+  $form['help'] = [
+    '#prefix' => '<p class="cms-installer__subhead">',
+    '#markup' => t('You can change this later.'),
+    '#suffix' => '</p>',
+    '#weight' => -100,
+  ];
+  $form['site_name'] += [
+    '#prefix' => '<div class="cms-installer__form-group">',
+    '#suffix' => '</div>',
+  ];
+  $form['actions']['submit']['#attributes']['class'] = ['button--next'];
+}
+
+/**
+ * Implements hook_form_FORM_ID_alter() for installer_recipes_form.
+ */
+function drupal_cms_installer_theme_form_installer_recipes_form_alter(array &$form): void {
+  $form['#title'] = t('Get started');
+
+  $form['help'] = [
+    '#prefix' => '<p class="cms-installer__subhead">',
+    '#markup' => t('You can select pre-configured types of content now, or add them later.'),
+    '#suffix' => '</p>',
+    '#weight' => -100,
+  ];
+  $form['add_ons'] += [
+    '#prefix' => '<div class="cms-installer__form-group">',
+    '#suffix' => '</div>',
+  ];
+  $form['add_ons']['help'] = [
+    '#prefix' => '<p class="cms-installer__info">',
+    '#markup' => t('Don’t see what you’re looking for? You can set up customized content later.'),
+    '#suffix' => '</p>',
+    '#weight' => 100,
+  ];
+
+  $form['actions']['submit']['#attributes']['class'] = ['button--next'];
+}
+
+/**
+ * Implements hook_form_FORM_ID_alter() for install_settings_form.
+ */
+function drupal_cms_installer_theme_form_install_settings_form_alter(array &$form): void {
+  $form['help'] = [
+    '#prefix' => '<p class="cms-installer__subhead">',
+    '#markup' => t("You don't need to change anything here unless you want to use a different database type."),
+    '#suffix' => '</p>',
+    '#weight' => -50,
+  ];
+}
+
+/**
+ * Implements hook_form_FORM_ID_alter() for install_configure_form.
+ */
+function drupal_cms_installer_theme_form_install_configure_form_alter(array &$form): void {
+  $form['#title'] = t('Create your account');
+
+  $form['help'] = [
+    '#prefix' => '<p class="cms-installer__subhead">',
+    '#markup' => t('Creating an account allows you to log in to your site.'),
+    '#suffix' => '</p>',
+    '#weight' => -40,
+  ];
+
+  // Use isset() to guard against the possibility that core will change the
+  // structure of this form in a minor release.
+  if (isset($form['admin_account']['account']['name'])) {
+    $form['admin_account']['account']['mail'] += [
+      '#prefix' => '<div class="cms-installer__form-group">',
+      '#suffix' => '</div>',
+    ];
+  }
+  if (isset($form['admin_account']['account']['pass'])) {
+    $form['admin_account']['account']['pass'] += [
+      '#prefix' => '<div class="cms-installer__form-group">',
+      '#suffix' => '</div>',
+    ];
+  }
+}
diff --git a/project_template/web/profiles/drupal_cms_installer/fonts/inter-cryllic-ext.woff2 b/project_template/web/profiles/drupal_cms_installer/theme/fonts/inter-cryllic-ext.woff2
similarity index 100%
rename from project_template/web/profiles/drupal_cms_installer/fonts/inter-cryllic-ext.woff2
rename to project_template/web/profiles/drupal_cms_installer/theme/fonts/inter-cryllic-ext.woff2
diff --git a/project_template/web/profiles/drupal_cms_installer/fonts/inter-cyrillic.woff2 b/project_template/web/profiles/drupal_cms_installer/theme/fonts/inter-cyrillic.woff2
similarity index 100%
rename from project_template/web/profiles/drupal_cms_installer/fonts/inter-cyrillic.woff2
rename to project_template/web/profiles/drupal_cms_installer/theme/fonts/inter-cyrillic.woff2
diff --git a/project_template/web/profiles/drupal_cms_installer/fonts/inter-greek-ext.woff2 b/project_template/web/profiles/drupal_cms_installer/theme/fonts/inter-greek-ext.woff2
similarity index 100%
rename from project_template/web/profiles/drupal_cms_installer/fonts/inter-greek-ext.woff2
rename to project_template/web/profiles/drupal_cms_installer/theme/fonts/inter-greek-ext.woff2
diff --git a/project_template/web/profiles/drupal_cms_installer/fonts/inter-greek.woff2 b/project_template/web/profiles/drupal_cms_installer/theme/fonts/inter-greek.woff2
similarity index 100%
rename from project_template/web/profiles/drupal_cms_installer/fonts/inter-greek.woff2
rename to project_template/web/profiles/drupal_cms_installer/theme/fonts/inter-greek.woff2
diff --git a/project_template/web/profiles/drupal_cms_installer/fonts/inter-italic-cyrillic-ext.woff2 b/project_template/web/profiles/drupal_cms_installer/theme/fonts/inter-italic-cyrillic-ext.woff2
similarity index 100%
rename from project_template/web/profiles/drupal_cms_installer/fonts/inter-italic-cyrillic-ext.woff2
rename to project_template/web/profiles/drupal_cms_installer/theme/fonts/inter-italic-cyrillic-ext.woff2
diff --git a/project_template/web/profiles/drupal_cms_installer/fonts/inter-italic-cyrillic.woff2 b/project_template/web/profiles/drupal_cms_installer/theme/fonts/inter-italic-cyrillic.woff2
similarity index 100%
rename from project_template/web/profiles/drupal_cms_installer/fonts/inter-italic-cyrillic.woff2
rename to project_template/web/profiles/drupal_cms_installer/theme/fonts/inter-italic-cyrillic.woff2
diff --git a/project_template/web/profiles/drupal_cms_installer/fonts/inter-italic-greek-ext.woff2 b/project_template/web/profiles/drupal_cms_installer/theme/fonts/inter-italic-greek-ext.woff2
similarity index 100%
rename from project_template/web/profiles/drupal_cms_installer/fonts/inter-italic-greek-ext.woff2
rename to project_template/web/profiles/drupal_cms_installer/theme/fonts/inter-italic-greek-ext.woff2
diff --git a/project_template/web/profiles/drupal_cms_installer/fonts/inter-italic-greek.woff2 b/project_template/web/profiles/drupal_cms_installer/theme/fonts/inter-italic-greek.woff2
similarity index 100%
rename from project_template/web/profiles/drupal_cms_installer/fonts/inter-italic-greek.woff2
rename to project_template/web/profiles/drupal_cms_installer/theme/fonts/inter-italic-greek.woff2
diff --git a/project_template/web/profiles/drupal_cms_installer/fonts/inter-italic-latin-ext.woff2 b/project_template/web/profiles/drupal_cms_installer/theme/fonts/inter-italic-latin-ext.woff2
similarity index 100%
rename from project_template/web/profiles/drupal_cms_installer/fonts/inter-italic-latin-ext.woff2
rename to project_template/web/profiles/drupal_cms_installer/theme/fonts/inter-italic-latin-ext.woff2
diff --git a/project_template/web/profiles/drupal_cms_installer/fonts/inter-italic-latin.woff2 b/project_template/web/profiles/drupal_cms_installer/theme/fonts/inter-italic-latin.woff2
similarity index 100%
rename from project_template/web/profiles/drupal_cms_installer/fonts/inter-italic-latin.woff2
rename to project_template/web/profiles/drupal_cms_installer/theme/fonts/inter-italic-latin.woff2
diff --git a/project_template/web/profiles/drupal_cms_installer/fonts/inter-italic-vietnamese.woff2 b/project_template/web/profiles/drupal_cms_installer/theme/fonts/inter-italic-vietnamese.woff2
similarity index 100%
rename from project_template/web/profiles/drupal_cms_installer/fonts/inter-italic-vietnamese.woff2
rename to project_template/web/profiles/drupal_cms_installer/theme/fonts/inter-italic-vietnamese.woff2
diff --git a/project_template/web/profiles/drupal_cms_installer/fonts/inter-latin-ext.woff2 b/project_template/web/profiles/drupal_cms_installer/theme/fonts/inter-latin-ext.woff2
similarity index 100%
rename from project_template/web/profiles/drupal_cms_installer/fonts/inter-latin-ext.woff2
rename to project_template/web/profiles/drupal_cms_installer/theme/fonts/inter-latin-ext.woff2
diff --git a/project_template/web/profiles/drupal_cms_installer/fonts/inter-latin.woff2 b/project_template/web/profiles/drupal_cms_installer/theme/fonts/inter-latin.woff2
similarity index 100%
rename from project_template/web/profiles/drupal_cms_installer/fonts/inter-latin.woff2
rename to project_template/web/profiles/drupal_cms_installer/theme/fonts/inter-latin.woff2
diff --git a/project_template/web/profiles/drupal_cms_installer/fonts/inter-vietnamese.woff2 b/project_template/web/profiles/drupal_cms_installer/theme/fonts/inter-vietnamese.woff2
similarity index 100%
rename from project_template/web/profiles/drupal_cms_installer/fonts/inter-vietnamese.woff2
rename to project_template/web/profiles/drupal_cms_installer/theme/fonts/inter-vietnamese.woff2
diff --git a/project_template/web/profiles/drupal_cms_installer/images/arrow-right.svg b/project_template/web/profiles/drupal_cms_installer/theme/images/arrow-right.svg
similarity index 100%
rename from project_template/web/profiles/drupal_cms_installer/images/arrow-right.svg
rename to project_template/web/profiles/drupal_cms_installer/theme/images/arrow-right.svg
diff --git a/project_template/web/profiles/drupal_cms_installer/images/check-circle.svg b/project_template/web/profiles/drupal_cms_installer/theme/images/check-circle.svg
similarity index 100%
rename from project_template/web/profiles/drupal_cms_installer/images/check-circle.svg
rename to project_template/web/profiles/drupal_cms_installer/theme/images/check-circle.svg
diff --git a/project_template/web/profiles/drupal_cms_installer/images/chevron-down.svg b/project_template/web/profiles/drupal_cms_installer/theme/images/chevron-down.svg
similarity index 100%
rename from project_template/web/profiles/drupal_cms_installer/images/chevron-down.svg
rename to project_template/web/profiles/drupal_cms_installer/theme/images/chevron-down.svg
diff --git a/project_template/web/profiles/drupal_cms_installer/images/drupal-cms-logo.svg b/project_template/web/profiles/drupal_cms_installer/theme/images/drupal-cms-logo.svg
similarity index 100%
rename from project_template/web/profiles/drupal_cms_installer/images/drupal-cms-logo.svg
rename to project_template/web/profiles/drupal_cms_installer/theme/images/drupal-cms-logo.svg
diff --git a/project_template/web/profiles/drupal_cms_installer/images/info.svg b/project_template/web/profiles/drupal_cms_installer/theme/images/info.svg
similarity index 100%
rename from project_template/web/profiles/drupal_cms_installer/images/info.svg
rename to project_template/web/profiles/drupal_cms_installer/theme/images/info.svg
diff --git a/project_template/web/profiles/drupal_cms_installer/images/translate.svg b/project_template/web/profiles/drupal_cms_installer/theme/images/translate.svg
similarity index 100%
rename from project_template/web/profiles/drupal_cms_installer/images/translate.svg
rename to project_template/web/profiles/drupal_cms_installer/theme/images/translate.svg
diff --git a/project_template/web/profiles/drupal_cms_installer/js/progress.js b/project_template/web/profiles/drupal_cms_installer/theme/js/progress.js
similarity index 100%
rename from project_template/web/profiles/drupal_cms_installer/js/progress.js
rename to project_template/web/profiles/drupal_cms_installer/theme/js/progress.js
diff --git a/project_template/web/profiles/drupal_cms_installer/templates/install-page.html.twig b/project_template/web/profiles/drupal_cms_installer/theme/templates/install-page.html.twig
similarity index 80%
rename from project_template/web/profiles/drupal_cms_installer/templates/install-page.html.twig
rename to project_template/web/profiles/drupal_cms_installer/theme/templates/install-page.html.twig
index f5d3676bfedebe9038cf889523f6bd7c93040b37..d514f816b37eb51a541e25e067e4360d1d133ebe 100644
--- a/project_template/web/profiles/drupal_cms_installer/templates/install-page.html.twig
+++ b/project_template/web/profiles/drupal_cms_installer/theme/templates/install-page.html.twig
@@ -12,15 +12,10 @@
 <div class="cms-installer">
   <header class="cms-installer__header">
     <h1 class="cms-installer__heading">
-      <img src="{{ images_path }}/drupal-cms-logo.svg" alt="{{ 'Drupal CMS'|t }}" />
+      <img src="{{ theme_path }}/images/drupal-cms-logo.svg" alt="{{ 'Drupal CMS'|t }}" />
     </h1>
   </header>
   <div class="cms-installer__wrapper">
-    {% if page.sidebar_first %}
-      <aside class="cms-installer__sidebar-first">
-        {{ page.sidebar_first }}
-      </aside>
-    {% endif %}
 
     <main class="cms-installer__main">
       {% if title %}
diff --git a/recipes/drupal_cms_starter/composer.json b/recipes/drupal_cms_starter/composer.json
index 1ea92aa545d2903e7593f03ea796f05ea972d309..69d71064591e3dd0158aebe4d7fb8ce2a63f3f0d 100644
--- a/recipes/drupal_cms_starter/composer.json
+++ b/recipes/drupal_cms_starter/composer.json
@@ -22,13 +22,5 @@
         "drupal/project_browser": "^2-alpha8",
         "drupal/token": "^1"
     },
-    "suggest": {
-        "drupal/drupal_cms_blog": "Adds a blog post content type and listing page.",
-        "drupal/drupal_cms_case_study": "Adds a case study content type and listing page.",
-        "drupal/drupal_cms_events": "Adds an event content type and listing page.",
-        "drupal/drupal_cms_news": "Adds a news content type and listing page.",
-        "drupal/drupal_cms_person": "Adds a person profile content type.",
-        "drupal/drupal_cms_project": "Adds a project content type and listing page."
-    },
     "version": "1.x-dev"
 }