diff --git a/claro.info.yml b/claro.info.yml
index 6a6eb57..c0d9163 100644
--- a/claro.info.yml
+++ b/claro.info.yml
@@ -137,6 +137,8 @@ libraries-extend:
     - claro/drupal.tableselect
   core/jquery.ui:
     - claro/claro.jquery.ui
+  file/drupal.file:
+    - claro/file
   media_library/view:
     - claro/media_library.view
   system/admin:
diff --git a/claro.libraries.yml b/claro.libraries.yml
index 5423375..5ca7adb 100644
--- a/claro.libraries.yml
+++ b/claro.libraries.yml
@@ -22,6 +22,7 @@ global-styling:
       css/dist/components/form--checkbox-radio.css: {}
       css/dist/components/form--checkbox-radio--ie.css: {}
       css/dist/components/form--field-multiple.css: {}
+      css/dist/components/form--managed-file.css: {}
       css/dist/components/form--text.css: {}
       css/dist/components/form--select.css: {}
       css/dist/components/help.css: {}
@@ -32,6 +33,7 @@ global-styling:
       css/dist/components/pager.css: {}
       css/dist/components/skip-link.css: {}
       css/dist/components/tables.css: {}
+      css/dist/components/table--file-multiple-widget.css: {}
       css/dist/components/search-admin-settings.css: {}
       css/dist/components/tablesort-indicator.css: {}
       css/dist/components/system-status-report-general-info.css: {}
@@ -49,6 +51,10 @@ global-styling:
     - system/admin
     - core/jquery
     - core/drupal
+      # Since we have small and extra small form elements, action links, buttons
+      # and we want to keep our touch target sizes big enought, we need
+      # Modernizr.
+    - core/modernizr
     # @todo Remove 'claro/drupal-theme' from dependencies and add to core/drupal
     # extensions after https://www.drupal.org/node/3024975 is in.
     - claro/drupal-theme
@@ -235,3 +241,8 @@ card:
     component:
       css/dist/layout/card-list.css: {}
       css/dist/components/card.css: {}
+
+file:
+  css:
+    component:
+      css/dist/components/file.css: {}
diff --git a/claro.theme b/claro.theme
index a205f72..c335b4d 100644
--- a/claro.theme
+++ b/claro.theme
@@ -227,23 +227,12 @@ function claro_preprocess_menu_local_action(array &$variables) {
   if ($legacy_class_key !== FALSE) {
     $variables['link']['#options']['attributes']['class'][$legacy_class_key] = 'button--action';
   }
-
-  // We require Modernizr's touch test for button styling.
-  $variables['#attached']['library'][] = 'core/modernizr';
 }
 
 /**
  * Implements hook_element_info_alter().
  */
 function claro_element_info_alter(&$type) {
-  // We require Modernizr for button styling.
-  if (isset($type['button'])) {
-    $type['button']['#attached']['library'][] = 'core/modernizr';
-  }
-  if (isset($type['submit'])) {
-    $type['submit']['#attached']['library'][] = 'core/modernizr';
-  }
-
   // Add a pre-render function that handles the sidebar of the node form.
   // @todo Refactor when https://www.drupal.org/node/3056089 is in.
   if (isset($type['container'])) {
@@ -262,6 +251,99 @@ function claro_element_info_alter(&$type) {
   if (isset($type['dropbutton'])) {
     $type['dropbutton']['#pre_render'][] = '_claro_dropbutton_prerender';
   }
+
+  // Add a pre-render to managed_file.
+  if (isset($type['managed_file'])) {
+    $type['managed_file']['#pre_render'][] = '_claro_managed_file_prerender';
+  }
+}
+
+/**
+ * Prerender callback for managed_file.
+ */
+function _claro_managed_file_prerender($element) {
+  $single_file_widget = !empty($element['#cardinality']) && $element['#cardinality'] === 1;
+
+  if (!empty($element['remove_button']) && is_array($element['remove_button'])) {
+    $element['remove_button']['#attributes']['class'][] = 'button--extrasmall';
+    $element['remove_button']['#attributes']['class'][] = 'remove-button';
+  }
+
+  if (!empty($element['upload_button']) && is_array($element['upload_button'])) {
+    $element['upload_button']['#attributes']['class'][] = 'upload-button';
+  }
+
+  // We need to display even single-cardinality widgets wrapped in a details.
+  if ($single_file_widget && empty($element['#single_wrapped'])) {
+    $upload_is_accessible = empty($element['#default_value']['fids']) && (!isset($element['upload']['#access']) || $element['upload']['#access'] !== FALSE);
+
+    $element['#theme_wrappers']['details'] = [
+      '#title' => $element['#title'],
+      '#summary_attributes' => [],
+      '#attributes' => ['open' => TRUE],
+      '#value' => NULL,
+      '#description' => $upload_is_accessible ? NULL : $element['#description'],
+      '#required' => $element['#required'],
+      '#errors' => NULL,
+      '#disabled' => !empty($element['#disabled']),
+    ];
+
+    // We want to display the description of single-cardinality widgets similar
+    // to the multiple value widget, so render the description from the field
+    // config in the details, separated from the other descriptions (that are
+    // computed from the file and image upload validators and from the
+    // cardinality).
+    // Actually, the description of the managed file widgets is rendered, and
+    // all of these descriptions are merged, and the field-config description is
+    // replaced with the rendered description.
+    // Right now, the only way to get back the potential field config
+    // description is to render the file_upload_help with an empty
+    // '#description' key, and compare its string value of the original
+    // description.
+    // @todo refactor when https://www.drupal.org/node/3084899 is fixed.
+    // @see https://git.drupalcode.org/project/drupal/blob/ade7b950a1/core/modules/file/file.field.inc#L53
+    // @see https://git.drupalcode.org/project/drupal/blob/ade7b950a1/core/modules/file/src/Plugin/Field/FieldWidget/FileWidget.php#L264
+    if (!empty($element['#description']) && !empty($element['#upload_validators'])) {
+      // For removing potential HTML comments.
+      $html_comment_pattern = '/<!--(.|\s)*?-->/';
+      $whole_description_string = (string) $element['#description'];
+      $upload_help_description_renderable = [
+        '#theme' => 'file_upload_help',
+        '#description' => '',
+        '#upload_validators' => $element['#upload_validators'],
+        '#cardinality' => $element['#cardinality'],
+      ];
+
+      $upload_help_description = trim(
+        preg_replace(
+          $html_comment_pattern,
+          '',
+          \Drupal::service('renderer')->renderPlain($upload_help_description_renderable)
+        )
+      );
+      $whole_description = trim(preg_replace($html_comment_pattern, '', $whole_description_string));
+
+      if (($start = strpos($whole_description, $upload_help_description)) !== FALSE) {
+        $element['#description'] = $upload_help_description;
+        $element['#theme_wrappers']['details']['#description'] = [
+          '#markup' => substr($whole_description, 0, $start),
+        ];
+      }
+    }
+
+    $element['#single_wrapped'] = TRUE;
+    if ($upload_is_accessible) {
+      // Change widget title.
+      // @see https://git.drupalcode.org/project/drupal/blob/ade7b950a1/core/modules/file/src/Plugin/Field/FieldWidget/FileWidget.php#L192
+      $element['#title'] = t('Add a new file');
+    }
+    else {
+      $element['#title_display'] = 'invisible';
+      $element['#description'] = NULL;
+    }
+  }
+
+  return $element;
 }
 
 /**
@@ -317,7 +399,7 @@ function _claro_text_format_prerender($element) {
   // Hide format select label visually.
   $element['format']['format']['#title_display'] = 'invisible';
   $element['format']['format']['#wrapper_attributes']['class'][] = 'form-item--editor-format';
-  $element['format']['format']['#attributes']['class'][] = 'form-element--small';
+  $element['format']['format']['#attributes']['class'][] = 'form-element--extrasmall';
   $element['format']['format']['#attributes']['class'][] = 'form-element--editor-format';
 
   // Fix JS inconsistencies of the 'text_textarea_with_summary' widgets.
@@ -403,6 +485,27 @@ function claro_preprocess_details(&$variables) {
     // Details should appear as a standalone accordion.
     $variables['accordion'] = TRUE;
   }
+
+  if (!empty($element['#theme']) &&  $element['#theme'] === 'file_widget_multiple') {
+    // Mark the details required if needed.
+    // If the file widget is multiple, the required state could be checked only
+    // by checking the $element's first children's state.
+    // If the widget is single, we will have the proper required state in
+    // $element['#required'].
+    $variables['required'] = isset($element[0]['#required']) ?
+      $element[0]['#required'] :
+      !empty($element['#required']);
+
+    // If the error is the same as the one in the multiple field widget element,
+    // we have to avoid displaying it twice.
+    // Seven and even Stark do have this issue.
+    // @todo revisit when https://www.drupal.org/node/3084906 is fixed.
+    if (isset($element['#errors']) && isset($variables['errors']) && $element['#errors'] === $variables['errors']) {
+      unset($variables['errors']);
+    }
+  }
+
+  $variables['disabled'] = !empty($element['#disabled']);
 }
 
 /**
@@ -413,7 +516,7 @@ function claro_form_alter(&$form, FormStateInterface $form_state) {
 
   // Make entity forms delete link use the action-link component.
   if (isset($form['actions']['delete']['#type']) && $form['actions']['delete']['#type'] === 'link' && !empty($build_info['callback_object']) && $build_info['callback_object'] instanceof EntityForm) {
-    $form['actions']['delete'] = _claro_convert_link_to_action_link($form['actions']['delete'], 'trash', FALSE, 'danger');
+    $form['actions']['delete'] = _claro_convert_link_to_action_link($form['actions']['delete'], 'trash', 'default', 'danger');
   }
 }
 
@@ -426,16 +529,16 @@ function claro_preprocess_links(&$variables) {
       if ($links_item['link']['#url']->isRouted()) {
         switch ($links_item['link']['#url']->getRouteName()) {
           case 'system.theme_settings_theme':
-            $links_item['link'] = _claro_convert_link_to_action_link($links_item['link'], 'cog', TRUE);
+            $links_item['link'] = _claro_convert_link_to_action_link($links_item['link'], 'cog', 'small');
             break;
 
           case 'system.theme_uninstall':
-            $links_item['link'] = _claro_convert_link_to_action_link($links_item['link'], 'ex', TRUE);
+            $links_item['link'] = _claro_convert_link_to_action_link($links_item['link'], 'ex', 'small');
             break;
 
           case 'system.theme_set_default':
           case 'system.theme_install':
-            $links_item['link'] = _claro_convert_link_to_action_link($links_item['link'], 'checkmark', TRUE);
+            $links_item['link'] = _claro_convert_link_to_action_link($links_item['link'], 'checkmark', 'small');
             break;
         }
       }
@@ -461,8 +564,12 @@ function claro_preprocess_links(&$variables) {
  *    - ex,
  *    - plus,
  *    - trash.
- * @param bool $small
- *   Whether the small action link variant is needed. Defaults to FALSE.
+ * @param string $size
+ *   Name of the small action link variant. Defaults to 'default'.
+ *   Supported sizes are:
+ *    - default,
+ *    - small,
+ *    - extrasmall.
  * @param string $variant
  *   Variant of the action link. Supported variants are 'default' and 'danger'.
  *   Defaults to 'default'.
@@ -470,7 +577,7 @@ function claro_preprocess_links(&$variables) {
  * @return array
  *   The link renderable converted to action link.
  */
-function _claro_convert_link_to_action_link(array $link, $icon_name = NULL, $small = FALSE, $variant = 'default') {
+function _claro_convert_link_to_action_link(array $link, $icon_name = NULL, $size = 'default', $variant = 'default') {
   // Early opt-out if we cannot do anything.
   if (empty($link['#type']) || $link['#type'] !== 'link' || empty($link['#url'])) {
     return $link;
@@ -508,6 +615,7 @@ function _claro_convert_link_to_action_link(array $link, $icon_name = NULL, $sma
     'button--primary',
     'button--danger',
     'button--small',
+    'button--extrasmall',
     'link',
   ]);
 
@@ -524,8 +632,8 @@ function _claro_convert_link_to_action_link(array $link, $icon_name = NULL, $sma
     $link['#options']['attributes']['class'][] = Html::getClass("action-link--icon-$icon_name");
   }
 
-  if ($small) {
-    $link['#options']['attributes']['class'][] = 'action-link--small';
+  if ($size && in_array($size, ['small', 'extrasmall'])) {
+    $link['#options']['attributes']['class'][] = Html::getClass("action-link--$size");
   }
 
   // If the provided $link is an item of the 'links' theme function, then only
@@ -764,7 +872,7 @@ function claro_preprocess_select(&$variables) {
     'form-element--type-select';
 
   if (in_array('block-region-select', $variables['attributes']['class'])) {
-    $variables['attributes']['class'][] = 'form-element--small';
+    $variables['attributes']['class'][] = 'form-element--extrasmall';
   }
 }
 
@@ -1126,3 +1234,82 @@ function claro_preprocess_links__action_links(&$variables) {
     $variables['links'][$delta]['attributes']->addClass('action-links__item');
   }
 }
+
+/**
+ * Implements hook_preprocess_HOOK() for file_managed_file.
+ */
+function claro_preprocess_file_managed_file(&$variables) {
+  $element = $variables['element'];
+
+  // Calculate helper values for the template.
+  $upload_is_accessible = !isset($element['upload']['#access']) || $element['upload']['#access'] !== FALSE;
+  $is_multiple = !empty($element['#cardinality']) && $element['#cardinality'] !== 1;
+  $has_value = isset($element['#value']['fids']) && !empty($element['#value']['fids']);
+  $display_can_be_displayed = !empty($element['#display_field']);
+  // Display is rendered in a separate table cell for multiple value widgets.
+  $display_is_visible = $display_can_be_displayed && !$is_multiple && isset($element['display']['#type']) && $element['display']['#type'] !== 'hidden';
+  $description_can_be_displayed = !empty($element['#description_field']);
+  $description_is_visible = $description_can_be_displayed && isset($element['description']);
+
+  $variables['multiple'] = $is_multiple;
+  $variables['upload'] = $upload_is_accessible;
+  $variables['has_value'] = $has_value;
+  $variables['has_meta'] = $display_is_visible || $description_is_visible;
+  $variables['display'] = $display_is_visible;
+}
+
+/**
+ * Implements hook_preprocess_HOOK() for file_widget_multiple.
+ */
+function claro_preprocess_file_widget_multiple(&$variables) {
+  if (isset($variables['table']['#type']) && $variables['table']['#type'] === 'table') {
+    // Add a variant class for the table.
+    $variables['table']['#attributes']['class'][] = 'table-file-multiple-widget';
+
+    // Mark table disabled if the field widget is disabled.
+    if (isset($variables['element']['#disabled']) && $variables['element']['#disabled']) {
+      $variables['table']['#attributes']['class'][] = 'tabledrag-disabled';
+      $variables['table']['#attributes']['class'][] = 'js-tabledrag-disabled';
+
+      // We will add the 'is-disabled' CSS class to the disabled table header
+      // cells.
+      foreach ($variables['table']['#header'] as &$cell) {
+        if (is_array($cell) && isset($cell['data'])) {
+          $cell = $cell + ['class' => []];
+          $cell['class'][] = 'is-disabled';
+        }
+        else {
+          // We have to modify the structure of this header cell.
+          $cell = [
+            'data' => $cell,
+            'class' => ['is-disabled'],
+          ];
+        }
+      }
+    }
+
+    // Mark operations column cells with a CSS class.
+    if (isset($variables['table']['#rows']) && is_array($variables['table']['#rows'])) {
+      foreach ($variables['table']['#rows'] as $row_key => $row) {
+        if (isset($row['data']) && is_array($row['data'])) {
+          $last_cell = end($row['data']);
+          $last_cell_key = key($row['data']);
+
+          if (is_array($last_cell['data'])) {
+            foreach ($last_cell['data'] as $last_cell_item) {
+              if (
+                isset($last_cell_item['#attributes']['class']) &&
+                is_array($last_cell_item['#attributes']['class']) &&
+                in_array('remove-button', $last_cell_item['#attributes']['class'])
+              ) {
+                $variables['table']['#rows'][$row_key]['data'][$last_cell_key] += ['class' => []];
+                $variables['table']['#rows'][$row_key]['data'][$last_cell_key]['class'][] = 'file-operations-cell';
+                break 1;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/css/src/base/elements.css b/css/src/base/elements.css
index 1dfb6cd..9cbc44b 100644
--- a/css/src/base/elements.css
+++ b/css/src/base/elements.css
@@ -35,10 +35,6 @@ hr {
 
 summary {
   font-weight: bold;
-  text-transform: uppercase;
-}
-.simpletest-results-form summary {
-  text-transform: none;
 }
 
 /**
diff --git a/css/src/base/variables.css b/css/src/base/variables.css
index f220c3c..d88d4e8 100644
--- a/css/src/base/variables.css
+++ b/css/src/base/variables.css
@@ -90,7 +90,15 @@
   --input--disabled-border-color: #bababf; /* Old silver with 0.5 opacity on white bg. */
   --input--disabled-border-opacity: 0.5;
   --input-border-radius-size: 0.125rem; /* (1/8)em ~ 2px */
-  --input-border-size: 0.0625rem; /* (1/16)em ~ 1px */
+  --input-border-size: 1px; /* (1/16)em ~ 1px */
+  --input-padding-vertical: calc(var(--space-s) - var(--input-border-size));
+  --input-padding-horizontal: calc(var(--space-m) - var(--input-border-size));
+  --input-font-size: var(--font-size-base);
+  --input-line-height: var(--space-l);
+  --input--extrasmall-padding-vertical: calc(0.15rem - var(--input-border-size));
+  --input--extrasmall-padding-horizontal: calc(var(--space-xs) - var(--input-border-size));
+  --input--extrasmall-font-size: var(--font-size-s);
+  --input--extrasmall-line-height: calc(var(--space-m) + 0.2rem); /* Font size is too big to use 1rem for extrasmall line-height */
   --input--required-mark-size: 0.4375rem; /* 7px inside the form element label. */
   --input--label-spacing: 1.6875rem; /* 8px with the checkbox width of 19px */
   /*
diff --git a/css/src/components/action-link.css b/css/src/components/action-link.css
index 60dd478..855ddbb 100644
--- a/css/src/components/action-link.css
+++ b/css/src/components/action-link.css
@@ -48,14 +48,21 @@
   line-height: var(--space-l); /* Bigger line-height needed to prevent the icon from increasing the height */
   -webkit-font-smoothing: antialiased;
   text-decoration: none;
+  cursor: pointer;
 }
 
 /* Small variant. */
-.action-link--small {
+.no-touchevents .action-link--small {
   padding: calc(var(--space-s) - ((var(--space-l) - var(--space-s)) / 2)) var(--space-s);
   font-size: var(--font-size-s);
 }
 
+/* Extra small variant. */
+.no-touchevents .action-link--extrasmall {
+  padding: 0 var(--space-xs);
+  font-size: var(--font-size-s);
+}
+
 .action-link + .action-link {
   margin-left: var(--space-s); /* LTR */
 }
@@ -63,10 +70,12 @@
   margin-right: var(--space-s);
   margin-left: 0;
 }
-.action-link--small + .action-link--small {
+.no-touchevents .action-link--small + .action-link--small,
+.no-touchevents .action-link--extrasmall + .action-link--extrasmall {
   margin-left: var(--space-xs); /* LTR */
 }
-[dir="rtl"] .action-link--small + .action-link--small {
+[dir="rtl"] .no-touchevents .action-link--small + .action-link--small,
+[dir="rtl"] .no-touchevents .action-link--extrasmall + .action-link--extrasmall {
   margin-right: var(--space-xs);
   margin-left: 0;
 }
@@ -94,6 +103,7 @@
 .action-link:focus {
   position: relative;
   text-decoration: none;
+  z-index: 1;
 }
 .action-link:active {
   color: var(--color-absolutezero-active);
@@ -140,12 +150,22 @@
   margin-left: 0.5em;
 }
 
-.action-link--small::before {
+.no-touchevents .action-link--small::before,
+.no-touchevents .action-link--extrasmall::before {
   top: 0.0625rem; /* Set the proper vertical alignment */
   width: var(--space-s);
   height: var(--space-s);
 }
 
+.no-touchevents .action-link--extrasmall::before {
+  margin-right: 0.4em; /* LTR */
+  margin-left: -0.125rem; /* LTR */
+}
+[dir="rtl"] .no-touchevents .action-link--extrasmall::before {
+  margin-right: -0.125em;
+  margin-left: 0.4rem;
+}
+
 /**
  * Hide action link icons for IE11.
  *
@@ -304,3 +324,61 @@
     background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16' fill='windowText'%3E%3Cpath d='M15.426 9.249C15.471 8.922 15.502 8.591 15.502 8.251C15.502 7.891 15.467 7.541 15.416 7.195L13.141 6.902C13.026 6.476 12.858 6.075 12.643 5.701L14.039 3.893C13.623 3.342 13.133 2.854 12.58 2.441L10.773 3.832C10.4 3.617 9.999 3.449 9.573 3.333L9.281 1.081C8.943 1.033 8.604 1 8.252 1C7.9 1 7.558 1.033 7.22 1.082L6.929 3.333C6.503 3.449 6.103 3.617 5.729 3.832L3.924 2.441C3.372 2.854 2.88 3.342 2.465 3.893L3.86 5.701C3.645 6.075 3.477 6.475 3.361 6.901L1.085 7.195C1.035 7.541 1 7.891 1 8.251C1 8.591 1.031 8.922 1.077 9.249L3.362 9.544C3.477 9.97 3.646 10.37 3.861 10.744L2.444 12.58C2.855 13.13 3.34 13.618 3.887 14.032L5.729 12.612C6.103 12.827 6.503 12.995 6.929 13.11L7.227 15.421C7.564 15.468 7.904 15.501 8.252 15.501C8.6 15.501 8.94 15.468 9.273 15.421L9.572 13.11C9.998 12.995 10.398 12.827 10.773 12.612L12.615 14.032C13.162 13.618 13.646 13.13 14.058 12.58L12.642 10.743C12.857 10.37 13.025 9.97 13.14 9.544L15.426 9.249ZM8.252 10.763C6.846 10.763 5.709 9.626 5.709 8.222C5.709 6.82 6.846 5.681 8.252 5.681C9.654 5.681 10.793 6.819 10.793 8.222C10.793 9.626 9.654 10.763 8.252 10.763Z'/%3E%3C/svg%3E") !important;
   }
 }
+
+/* Show */
+.action-link--icon-show::before {
+  content: '';
+  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16' fill='%23545560' fill-rule='evenodd'%3E%3Cpath d='M 8,3 C 4.3636399,3 1.2581813,5.0733333 0,8 1.2581813,10.926667 4.3636399,13 8,13 11.63636,13 14.741866,10.926667 16,8 14.741866,5.0733333 11.63636,3 8,3 Z m 0,8 C 9.6568531,11 11,9.656853 11,8 11,6.3431466 9.6568531,5 8,5 6.3431465,5 5,6.3431466 5,8 c 0,1.656853 1.3431466,3 3,3 z'/%3E%3C/svg%3E");
+}
+.action-link--icon-show:hover::before {
+  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16' fill='%230036b1' fill-rule='evenodd'%3E%3Cpath d='M 8,3 C 4.3636399,3 1.2581813,5.0733333 0,8 1.2581813,10.926667 4.3636399,13 8,13 11.63636,13 14.741866,10.926667 16,8 14.741866,5.0733333 11.63636,3 8,3 Z m 0,8 C 9.6568531,11 11,9.656853 11,8 11,6.3431466 9.6568531,5 8,5 6.3431465,5 5,6.3431466 5,8 c 0,1.656853 1.3431466,3 3,3 z'/%3E%3C/svg%3E");
+}
+.action-link--icon-show:active::before {
+  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16' fill='%2300309e' fill-rule='evenodd'%3E%3Cpath d='M 8,3 C 4.3636399,3 1.2581813,5.0733333 0,8 1.2581813,10.926667 4.3636399,13 8,13 11.63636,13 14.741866,10.926667 16,8 14.741866,5.0733333 11.63636,3 8,3 Z m 0,8 C 9.6568531,11 11,9.656853 11,8 11,6.3431466 9.6568531,5 8,5 6.3431465,5 5,6.3431466 5,8 c 0,1.656853 1.3431466,3 3,3 z'/%3E%3C/svg%3E");
+}
+
+/* Show - danger */
+.action-link--icon-show.action-link--danger::before {
+  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16' fill='%23d72222' fill-rule='evenodd'%3E%3Cpath d=M 8,3 C 4.3636399,3 1.2581813,5.0733333 0,8 1.2581813,10.926667 4.3636399,13 8,13 11.63636,13 14.741866,10.926667 16,8 14.741866,5.0733333 11.63636,3 8,3 Z m 0,8 C 9.6568531,11 11,9.656853 11,8 11,6.3431466 9.6568531,5 8,5 6.3431465,5 5,6.3431466 5,8 c 0,1.656853 1.3431466,3 3,3 z'/%3E%3C/svg%3E");
+}
+.action-link--icon-show.action-link--danger:hover::before {
+  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16' fill='%23c11f1f' fill-rule='evenodd'%3E%3Cpath d='M 8,3 C 4.3636399,3 1.2581813,5.0733333 0,8 1.2581813,10.926667 4.3636399,13 8,13 11.63636,13 14.741866,10.926667 16,8 14.741866,5.0733333 11.63636,3 8,3 Z m 0,8 C 9.6568531,11 11,9.656853 11,8 11,6.3431466 9.6568531,5 8,5 6.3431465,5 5,6.3431466 5,8 c 0,1.656853 1.3431466,3 3,3 z'/%3E%3C/svg%3E");
+}
+.action-link--icon-show.action-link--danger:active::before {
+  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16' fill='%23ab1b1b' fill-rule='evenodd'%3E%3Cpath d='M 8,3 C 4.3636399,3 1.2581813,5.0733333 0,8 1.2581813,10.926667 4.3636399,13 8,13 11.63636,13 14.741866,10.926667 16,8 14.741866,5.0733333 11.63636,3 8,3 Z m 0,8 C 9.6568531,11 11,9.656853 11,8 11,6.3431466 9.6568531,5 8,5 6.3431465,5 5,6.3431466 5,8 c 0,1.656853 1.3431466,3 3,3 z'/%3E%3C/svg%3E");
+}
+
+@media screen and (-ms-high-contrast: active) {
+  .action-link--icon-show.action-link--icon-show.action-link--icon-show::before {
+    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16' fill='windowText' fill-rule='evenodd'%3E%3Cpath d='M 8,3 C 4.3636399,3 1.2581813,5.0733333 0,8 1.2581813,10.926667 4.3636399,13 8,13 11.63636,13 14.741866,10.926667 16,8 14.741866,5.0733333 11.63636,3 8,3 Z m 0,8 C 9.6568531,11 11,9.656853 11,8 11,6.3431466 9.6568531,5 8,5 6.3431465,5 5,6.3431466 5,8 c 0,1.656853 1.3431466,3 3,3 z'/%3E%3C/svg%3E") !important;
+  }
+}
+
+/* Hide */
+.action-link--icon-hide::before {
+  content: '';
+  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16' fill='%23545560' fill-rule='evenodd'%3E%3Cpath d='M 2.0106399,1.6964404 2,1.707083 14.072,13.779133 13.3756,14.4756 11.297973,12.397987 C 10.282626,12.785827 9.1687331,13 8,13 4.3636399,13 1.2581813,10.926667 0,8 0.64703865,6.4949202 1.7826266,5.2155203 3.2277199,4.3277203 L 1,2.1 1.7071066,1.392904 Z m 2.98936,6.3035598 c 0,-0.54608 0.1459066,-1.0580666 0.4008533,-1.4991333 L 9.4991464,10.599147 C 9.0580798,10.854107 8.5460798,11 8,11 6.3431465,11 5,9.656854 5,8 Z'/%3E%3Cpath d='m 5.1510932,3.4439603 1.75984,1.75984 c 0.3376,-0.1315867 0.7048933,-0.2038 1.0890666,-0.2038 C 9.6568531,5 11,6.3431469 11,8 11,8.3841735 10.92779,8.7514668 10.7962,9.0890668 L 13.140293,11.43316 C 14.410266,10.561414 15.408933,9.3748668 16,8 14.741866,5.0733336 11.63636,3 8,3 c -0.9987733,0 -1.9575066,0.1564134 -2.8489066,0.44396 z'/%3E%3C/svg%3E");
+}
+.action-link--icon-hide:hover::before {
+  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16' fill='%230036b1' fill-rule='evenodd'%3E%3Cpath d='M 2.0106399,1.6964404 2,1.707083 14.072,13.779133 13.3756,14.4756 11.297973,12.397987 C 10.282626,12.785827 9.1687331,13 8,13 4.3636399,13 1.2581813,10.926667 0,8 0.64703865,6.4949202 1.7826266,5.2155203 3.2277199,4.3277203 L 1,2.1 1.7071066,1.392904 Z m 2.98936,6.3035598 c 0,-0.54608 0.1459066,-1.0580666 0.4008533,-1.4991333 L 9.4991464,10.599147 C 9.0580798,10.854107 8.5460798,11 8,11 6.3431465,11 5,9.656854 5,8 Z'/%3E%3Cpath d='m 5.1510932,3.4439603 1.75984,1.75984 c 0.3376,-0.1315867 0.7048933,-0.2038 1.0890666,-0.2038 C 9.6568531,5 11,6.3431469 11,8 11,8.3841735 10.92779,8.7514668 10.7962,9.0890668 L 13.140293,11.43316 C 14.410266,10.561414 15.408933,9.3748668 16,8 14.741866,5.0733336 11.63636,3 8,3 c -0.9987733,0 -1.9575066,0.1564134 -2.8489066,0.44396 z'/%3E%3C/svg%3E");
+}
+.action-link--icon-hide:active::before {
+  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16' fill='%2300309e' fill-rule='evenodd'%3E%3Cpath d='M 2.0106399,1.6964404 2,1.707083 14.072,13.779133 13.3756,14.4756 11.297973,12.397987 C 10.282626,12.785827 9.1687331,13 8,13 4.3636399,13 1.2581813,10.926667 0,8 0.64703865,6.4949202 1.7826266,5.2155203 3.2277199,4.3277203 L 1,2.1 1.7071066,1.392904 Z m 2.98936,6.3035598 c 0,-0.54608 0.1459066,-1.0580666 0.4008533,-1.4991333 L 9.4991464,10.599147 C 9.0580798,10.854107 8.5460798,11 8,11 6.3431465,11 5,9.656854 5,8 Z'/%3E%3Cpath d='m 5.1510932,3.4439603 1.75984,1.75984 c 0.3376,-0.1315867 0.7048933,-0.2038 1.0890666,-0.2038 C 9.6568531,5 11,6.3431469 11,8 11,8.3841735 10.92779,8.7514668 10.7962,9.0890668 L 13.140293,11.43316 C 14.410266,10.561414 15.408933,9.3748668 16,8 14.741866,5.0733336 11.63636,3 8,3 c -0.9987733,0 -1.9575066,0.1564134 -2.8489066,0.44396 z'/%3E%3C/svg%3E");
+}
+
+/* Hide - danger */
+.action-link--icon-hide.action-link--danger::before {
+  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16' fill='%23d72222' fill-rule='evenodd'%3E%3Cpath d=M 2.0106399,1.6964404 2,1.707083 14.072,13.779133 13.3756,14.4756 11.297973,12.397987 C 10.282626,12.785827 9.1687331,13 8,13 4.3636399,13 1.2581813,10.926667 0,8 0.64703865,6.4949202 1.7826266,5.2155203 3.2277199,4.3277203 L 1,2.1 1.7071066,1.392904 Z m 2.98936,6.3035598 c 0,-0.54608 0.1459066,-1.0580666 0.4008533,-1.4991333 L 9.4991464,10.599147 C 9.0580798,10.854107 8.5460798,11 8,11 6.3431465,11 5,9.656854 5,8 Z'/%3E%3Cpath d='m 5.1510932,3.4439603 1.75984,1.75984 c 0.3376,-0.1315867 0.7048933,-0.2038 1.0890666,-0.2038 C 9.6568531,5 11,6.3431469 11,8 11,8.3841735 10.92779,8.7514668 10.7962,9.0890668 L 13.140293,11.43316 C 14.410266,10.561414 15.408933,9.3748668 16,8 14.741866,5.0733336 11.63636,3 8,3 c -0.9987733,0 -1.9575066,0.1564134 -2.8489066,0.44396 z'/%3E%3C/svg%3E");
+}
+.action-link--icon-hide.action-link--danger:hover::before {
+  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16' fill='%23c11f1f' fill-rule='evenodd'%3E%3Cpath d='M 2.0106399,1.6964404 2,1.707083 14.072,13.779133 13.3756,14.4756 11.297973,12.397987 C 10.282626,12.785827 9.1687331,13 8,13 4.3636399,13 1.2581813,10.926667 0,8 0.64703865,6.4949202 1.7826266,5.2155203 3.2277199,4.3277203 L 1,2.1 1.7071066,1.392904 Z m 2.98936,6.3035598 c 0,-0.54608 0.1459066,-1.0580666 0.4008533,-1.4991333 L 9.4991464,10.599147 C 9.0580798,10.854107 8.5460798,11 8,11 6.3431465,11 5,9.656854 5,8 Z'/%3E%3Cpath d='m 5.1510932,3.4439603 1.75984,1.75984 c 0.3376,-0.1315867 0.7048933,-0.2038 1.0890666,-0.2038 C 9.6568531,5 11,6.3431469 11,8 11,8.3841735 10.92779,8.7514668 10.7962,9.0890668 L 13.140293,11.43316 C 14.410266,10.561414 15.408933,9.3748668 16,8 14.741866,5.0733336 11.63636,3 8,3 c -0.9987733,0 -1.9575066,0.1564134 -2.8489066,0.44396 z'/%3E%3C/svg%3E");
+}
+.action-link--icon-hide.action-link--danger:active::before {
+  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16' fill='%23ab1b1b' fill-rule='evenodd'%3E%3Cpath d='M 2.0106399,1.6964404 2,1.707083 14.072,13.779133 13.3756,14.4756 11.297973,12.397987 C 10.282626,12.785827 9.1687331,13 8,13 4.3636399,13 1.2581813,10.926667 0,8 0.64703865,6.4949202 1.7826266,5.2155203 3.2277199,4.3277203 L 1,2.1 1.7071066,1.392904 Z m 2.98936,6.3035598 c 0,-0.54608 0.1459066,-1.0580666 0.4008533,-1.4991333 L 9.4991464,10.599147 C 9.0580798,10.854107 8.5460798,11 8,11 6.3431465,11 5,9.656854 5,8 Z'/%3E%3Cpath d='m 5.1510932,3.4439603 1.75984,1.75984 c 0.3376,-0.1315867 0.7048933,-0.2038 1.0890666,-0.2038 C 9.6568531,5 11,6.3431469 11,8 11,8.3841735 10.92779,8.7514668 10.7962,9.0890668 L 13.140293,11.43316 C 14.410266,10.561414 15.408933,9.3748668 16,8 14.741866,5.0733336 11.63636,3 8,3 c -0.9987733,0 -1.9575066,0.1564134 -2.8489066,0.44396 z'/%3E%3C/svg%3E");
+}
+
+@media screen and (-ms-high-contrast: active) {
+  .action-link--icon-hide.action-link--icon-hide.action-link--icon-hide::before {
+    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16' fill='windowText' fill-rule='evenodd'%3E%3Cpath d='M 2.0106399,1.6964404 2,1.707083 14.072,13.779133 13.3756,14.4756 11.297973,12.397987 C 10.282626,12.785827 9.1687331,13 8,13 4.3636399,13 1.2581813,10.926667 0,8 0.64703865,6.4949202 1.7826266,5.2155203 3.2277199,4.3277203 L 1,2.1 1.7071066,1.392904 Z m 2.98936,6.3035598 c 0,-0.54608 0.1459066,-1.0580666 0.4008533,-1.4991333 L 9.4991464,10.599147 C 9.0580798,10.854107 8.5460798,11 8,11 6.3431465,11 5,9.656854 5,8 Z'/%3E%3Cpath d='m 5.1510932,3.4439603 1.75984,1.75984 c 0.3376,-0.1315867 0.7048933,-0.2038 1.0890666,-0.2038 C 9.6568531,5 11,6.3431469 11,8 11,8.3841735 10.92779,8.7514668 10.7962,9.0890668 L 13.140293,11.43316 C 14.410266,10.561414 15.408933,9.3748668 16,8 14.741866,5.0733336 11.63636,3 8,3 c -0.9987733,0 -1.9575066,0.1564134 -2.8489066,0.44396 z'/%3E%3C/svg%3E") !important;
+  }
+}
diff --git a/css/src/components/button.css b/css/src/components/button.css
index 87c7e21..6862d39 100644
--- a/css/src/components/button.css
+++ b/css/src/components/button.css
@@ -17,7 +17,6 @@
  *
  * @todo Consider moving box-sizing into base.css under a universal selector.
  * See https://www.drupal.org/node/2124251
- *
  */
 
 /**
@@ -72,8 +71,17 @@
   padding: calc(var(--space-xs) - 1px) calc(var(--space-m) - 1px); /* 1 */
   font-size: var(--font-size-xs);
 }
-[dir="rtl"].no-touchevents .button--small {
-  margin: var(--space-s) 0 var(--space-s) var(--space-xs);
+
+/* Common styles for extra small buttons */
+.no-touchevents .button--extrasmall {
+  margin: var(--space-xs) var(--space-xs) var(--space-xs) 0; /* LTR */
+  padding: calc(calc(var(--space-xs) / 2) - 1px) calc(var(--space-s) - 1px); /* 1 */
+  font-size: var(--font-size-xs);
+}
+[dir="rtl"].no-touchevents .button--small,
+[dir="rtl"].no-touchevents .button--extrasmall {
+  margin-right: 0;
+  margin-left: var(--space-xs);
 }
 
 /* Styles for action link buttons */
diff --git a/css/src/components/details.css b/css/src/components/details.css
index 66bdfa8..3abde59 100644
--- a/css/src/components/details.css
+++ b/css/src/components/details.css
@@ -69,7 +69,6 @@
   background-color: transparent;
   color: var(--color-davysgrey);
   line-height: 1rem;
-  text-transform: capitalize;
   border-radius: var(--size-summary-border-radius);
   transition: background-color var(--details-bg-color-transition-duration) ease-in-out;
   cursor: pointer;
@@ -91,6 +90,7 @@
   padding-right: var(--details-desktop-wrapper-padding-start);
   padding-left: var(--space-l);
 }
+
 /**
  * Accordion list items must not have border radius except they are the first
  * or the last ones.
@@ -380,6 +380,17 @@
   border-top: var(--details-border-size) solid var(--details-border-color);
 }
 
+/* Description. */
+.claro-details__description {
+  font-size: var(--font-size-xs); /* ~13px */
+  line-height: calc(17rem / 16); /* 17px */
+  color: var(--input-fg-color--description);
+  margin-bottom: var(--space-m);
+}
+.claro-details__description.is-disabled {
+  color: var(--input--disabled-fg-color);
+}
+
 /**
  * Collapse processed for non-supporting browsers like IE or Edge.
  */
@@ -490,3 +501,16 @@
     border: 2px dotted;
   }
 }
+
+.required-mark::after {
+  content: "";
+  vertical-align: super;
+  display: inline-block;
+  background-image: url(../../../images/core/ee0000/required.svg);
+  background-repeat: no-repeat;
+  background-size: 0.4375rem 0.4375rem;
+  width: 0.4375rem;
+  height: 0.4375rem;
+  margin-right: 0.3em;
+  margin-left: 0.3em;
+}
diff --git a/css/src/components/dropbutton.css b/css/src/components/dropbutton.css
index 6227708..b792464 100644
--- a/css/src/components/dropbutton.css
+++ b/css/src/components/dropbutton.css
@@ -71,11 +71,11 @@
 }
 
 /* Variants. */
-.js .dropbutton--small {
+.js.no-touchevents .dropbutton--small {
   height: var(--dropbutton-small-toggle-size);
 }
 
-.js .dropbutton--extrasmall {
+.js.no-touchevents .dropbutton--extrasmall {
   height: var(--dropbutton-extrasmall-toggle-size);
 }
 
@@ -91,18 +91,18 @@
 }
 
 /* First dropbutton list item variants */
-.js .dropbutton--multiple.dropbutton--small .dropbutton__item:first-of-type {
+.js.no-touchevents .dropbutton--multiple.dropbutton--small .dropbutton__item:first-of-type {
   margin-right: calc(var(--dropbutton-small-toggle-size) + var(--dropbutton-toggle-size-spacing)); /* LTR */
 }
-[dir="rtl"].js .dropbutton--multiple.dropbutton--small .dropbutton__item:first-of-type {
+[dir="rtl"].js.no-touchevents .dropbutton--multiple.dropbutton--small .dropbutton__item:first-of-type {
   margin-right: 0;
   margin-left: calc(var(--dropbutton-small-toggle-size) + var(--dropbutton-toggle-size-spacing));
 }
 
-.js .dropbutton--multiple.dropbutton--extrasmall .dropbutton__item:first-of-type {
+.js.no-touchevents .dropbutton--multiple.dropbutton--extrasmall .dropbutton__item:first-of-type {
   margin-right: calc(var(--dropbutton-extrasmall-toggle-size) + var(--dropbutton-toggle-size-spacing)); /* LTR */
 }
-[dir="rtl"].js .dropbutton--multiple.dropbutton--extrasmall .dropbutton__item:first-of-type {
+[dir="rtl"].js.no-touchevents .dropbutton--multiple.dropbutton--extrasmall .dropbutton__item:first-of-type {
   margin-right: 0;
   margin-left: calc(var(--dropbutton-extrasmall-toggle-size) + var(--dropbutton-toggle-size-spacing));
 }
@@ -166,18 +166,18 @@
 }
 
 /* Toggler variants */
-.dropbutton--small .dropbutton__toggle {
+.no-touchevents .dropbutton--small .dropbutton__toggle {
   width: var(--dropbutton-small-toggle-size);
   height: var(--dropbutton-small-toggle-size);
 }
 
-.dropbutton--extrasmall .dropbutton__toggle {
+.no-touchevents .dropbutton--extrasmall .dropbutton__toggle {
   width: var(--dropbutton-extrasmall-toggle-size);
   height: var(--dropbutton-extrasmall-toggle-size);
 }
 
-.dropbutton--small .dropbutton__toggle::before,
-.dropbutton--extrasmall .dropbutton__toggle::before {
+.no-touchevents .dropbutton--small .dropbutton__toggle::before,
+.no-touchevents .dropbutton--extrasmall .dropbutton__toggle::before {
   width: 0.75rem; /* 12px */
 }
 
@@ -204,8 +204,8 @@
 
   /* Variants */
 
-  .dropbutton--small .dropbutton__toggle::before,
-  .dropbutton--extrasmall .dropbutton__toggle::before {
+  .no-touchevents .dropbutton--small .dropbutton__toggle::before,
+  .no-touchevents .dropbutton--extrasmall .dropbutton__toggle::before {
     width: 0.4375rem;
     height: 0.4375rem;
     margin-top: calc(0.4375rem / (2 * -1.41429));
@@ -244,14 +244,14 @@
 }
 
 /* Variants */
-.dropbutton__item--small:first-of-type > * {
+.no-touchevents .dropbutton__item--small:first-of-type > * {
   padding-top: calc(var(--dropbutton-small-spacing-size) - var(--dropbutton-border-size));
   padding-bottom: calc(var(--dropbutton-small-spacing-size) - var(--dropbutton-border-size));
   font-size: var(--dropbutton-small-font-size);
   line-height: var(--dropbutton-small-line-height);
 }
 
-.dropbutton__item--extrasmall:first-of-type > * {
+.no-touchevents .dropbutton__item--extrasmall:first-of-type > * {
   padding-top: calc(var(--dropbutton-extrasmall-spacing-size) - var(--dropbutton-border-size));
   padding-bottom: calc(var(--dropbutton-extrasmall-spacing-size) - var(--dropbutton-border-size));
   font-size: var(--dropbutton-extrasmall-font-size);
@@ -367,16 +367,16 @@
 }
 
 /* Variants. */
-.dropbutton__item:first-of-type ~ .dropbutton__item--small > a,
-.dropbutton__item:first-of-type ~ .dropbutton__item--small > .button {
+.no-touchevents .dropbutton__item:first-of-type ~ .dropbutton__item--small > a,
+.no-touchevents .dropbutton__item:first-of-type ~ .dropbutton__item--small > .button {
   padding-top: var(--dropbutton-small-spacing-size);
   padding-bottom: var(--dropbutton-small-spacing-size);
   font-size: var(--dropbutton-small-font-size);
   line-height: var(--dropbutton-small-line-height);
 }
 
-.dropbutton__item:first-of-type ~ .dropbutton__item--extrasmall > a,
-.dropbutton__item:first-of-type ~ .dropbutton__item--extrasmall > .button {
+.no-touchevents .dropbutton__item:first-of-type ~ .dropbutton__item--extrasmall > a,
+.no-touchevents .dropbutton__item:first-of-type ~ .dropbutton__item--extrasmall > .button {
   padding-top: var(--dropbutton-extrasmall-spacing-size);
   padding-bottom: var(--dropbutton-extrasmall-spacing-size);
   font-size: var(--dropbutton-extrasmall-font-size);
diff --git a/css/src/components/file.css b/css/src/components/file.css
new file mode 100644
index 0000000..450c75c
--- /dev/null
+++ b/css/src/components/file.css
@@ -0,0 +1,9 @@
+/**
+ * @file
+ * Extends styles of the file link.
+ */
+
+.file {
+  font-size: var(--font-size-s);
+  line-height: calc(18rem / 16);
+}
diff --git a/css/src/components/form--managed-file.css b/css/src/components/form--managed-file.css
new file mode 100644
index 0000000..17b58e9
--- /dev/null
+++ b/css/src/components/form--managed-file.css
@@ -0,0 +1,78 @@
+/**
+ * @file
+ * Styles for the managed file widget.
+ */
+
+.form-managed-file.no-upload {
+  max-width: 32rem;
+}
+
+.form-managed-file.has-value.no-meta {
+  max-width: none;
+}
+
+.form-managed-file__main {
+  display: flex;
+  flex-wrap: wrap;
+  align-items: center;
+}
+
+.form-managed-file.has-upload .form-managed-file__main,
+.form-managed-file.has-value.no-meta .form-managed-file__main {
+  display: inline-flex;
+  flex-wrap: nowrap;
+  max-width: 100%;
+}
+
+.form-managed-file .file {
+  word-break: break-all;
+  hyphens: auto;
+}
+
+.form-managed-file .file__size {
+  word-break: normal;
+}
+
+.form-managed-file__main .file {
+  flex-grow: 1;
+  margin: var(--space-xs) var(--space-m) var(--space-xs) 0; /* LTR */
+}
+[dir="rtl"] .form-managed-file__main .file {
+  margin-right: 0;
+  margin-left: var(--space-m);
+}
+
+.form-managed-file .button {
+  margin: 0;
+}
+
+.form-managed-file__main .form-element--api-file {
+  flex: 1 1 auto;
+  width: 100%;
+}
+
+.form-managed-file__main .upload-button {
+  flex: 0 0 auto;
+}
+
+[dir="rtl"] .form-managed-file__main .file {
+  margin-right: 0;
+  margin-left: var(--space-m);
+}
+
+/**
+ * Alternative styles for the widget inside a (draggable) table.
+ */
+.table-file-multiple-widget .form-managed-file .file {
+  margin-bottom: 0;
+}
+
+.table-file-multiple-widget .form-item::before {
+  content: '';
+  display: table;
+  clear: both;
+}
+
+.table-file-multiple-widget .form-managed-file .form-element {
+  width: 100%;
+}
diff --git a/css/src/components/form--select.css b/css/src/components/form--select.css
index 8aba3bd..8f73789 100644
--- a/css/src/components/form--select.css
+++ b/css/src/components/form--select.css
@@ -15,11 +15,14 @@
   padding-left: calc(2rem - var(--input-border-size));
   background-position: 0 50%;
 }
-.form-element--type-select.form-element--small {
-  background-size: 1.75rem 0.5625rem; /* w: 14px + (2 * 7px), h: 9px */
+
+.no-touchevents .form-element--type-select.form-element--extrasmall,
+.no-touchevents .form-element--type-select[name$="][_weight]"] {
+  background-size: 1.75rem 0.4375rem; /* w: 14px + (2 * 7px), h: 7px */
   padding-right: calc(1.5rem - var(--input-border-size));
 }
-[dir="rtl"] .form-element--type-select.form-element--small {
+[dir="rtl"].no-touchevents .form-element--type-select.form-element--extrasmall,
+[dir="rtl"].no-touchevents .form-element--type-select[name$="][_weight]"] {
   padding-right: calc(0.5rem - var(--input-border-size));
   padding-left: calc(1.5rem - var(--input-border-size));
 }
diff --git a/css/src/components/form--text.css b/css/src/components/form--text.css
index fc84207..9a0f7eb 100644
--- a/css/src/components/form--text.css
+++ b/css/src/components/form--text.css
@@ -6,20 +6,23 @@
 .form-element {
   appearance: none; /* Being able to control inner box shadow on iOS. */
   box-sizing: border-box;
-  padding: calc(0.75rem - var(--input-border-size)) calc(1rem - var(--input-border-size));
+  padding: var(--input-padding-vertical) var(--input-padding-horizontal);
   max-width: 100%;
   border: var(--input-border-size) solid var(--input-border-color);
   border-radius: var(--input-border-radius-size);
   background: var(--input-bg-color);
   color: var(--input-fg-color);
-  min-height: 3rem; /* iOS. */
+  font-size: var(--input-font-size);
+  line-height: var(--input-line-height);
+  min-height: calc(((var(--input-padding-vertical) + var(--input-border-size)) * 2) + var(--input-line-height)); /* iOS. */
 }
 
-.form-element--small {
-  font-size: var(--font-size-label);
-  padding: calc(0.25rem - var(--input-border-size)) calc(0.5rem - var(--input-border-size));
-  line-height: 1rem;
-  min-height: 1.5rem; /* iOS. */
+.no-touchevents .form-element--extrasmall,
+.no-touchevents .form-element[name$="][_weight]"] {
+  min-height: calc(((var(--input--extrasmall-padding-vertical) + var(--input-border-size)) * 2) + var(--input--extrasmall-line-height)); /* iOS. */
+  padding: var(--input--extrasmall-padding-vertical) var(--input--extrasmall-padding-horizontal);
+  font-size: var(--input--extrasmall-font-size);
+  line-height: var(--input--extrasmall-line-height);
 }
 
 /**
@@ -50,6 +53,26 @@
   text-indent: calc(0.75rem - var(--input-border-size)); /* Text-input fallback for non-supporting browsers like Safari */
 }
 
+/**
+ * Reset value border and background of the file input on IE11 and Edge.
+ */
+.form-element--type-file::-ms-value {
+  border: 0;
+  background: inherit;
+}
+
+/**
+ * Target IE 11 and Edge.
+ *
+ * Reduce the vertical padding of the file input element to make the browse
+ * button fit into the needed input height.
+ */
+_:-ms-fullscreen,
+:root .form-element--type-file {
+  padding-top: 0.25rem;
+  padding-bottom: 0.25rem;
+}
+
 /**
  * States.
  */
diff --git a/css/src/components/table--file-multiple-widget.css b/css/src/components/table--file-multiple-widget.css
new file mode 100644
index 0000000..3b0bd96
--- /dev/null
+++ b/css/src/components/table--file-multiple-widget.css
@@ -0,0 +1,104 @@
+/**
+ * @file
+ * Styles for multiple file widget table.
+ */
+
+.table-file-multiple-widget tbody {
+  vertical-align: top;
+}
+
+.table-file-multiple-widget .tabledrag-cell-content {
+  position: relative;
+  display: block;
+  height: auto;
+}
+
+.table-file-multiple-widget .tabledrag-cell-content > * {
+  display: block;
+}
+
+.table-file-multiple-widget .tabledrag-cell-content__item {
+  padding: 0;
+}
+
+.table-file-multiple-widget .tabledrag-handle {
+  float: left; /* LTR */
+}
+[dir="rtl"] .table-file-multiple-widget .tabledrag-handle {
+  float: right;
+}
+
+.table-file-multiple-widget .tabledrag-changed {
+  float: left; /* LTR */
+  line-height: calc(var(--tabledrag-handle-icon-size) + calc(var(--space-xs) * 2));
+}
+[dir="rtl"] .table-file-multiple-widget .tabledrag-changed {
+  float: left;
+}
+
+.table-file-multiple-widget td {
+  height: calc(var(--space-m) * 3);
+}
+
+.table-file-multiple-widget td > :first-child {
+  margin-top: 0;
+}
+.table-file-multiple-widget td > :last-child {
+  margin-bottom: 0;
+}
+
+.table-file-multiple-widget .button {
+  margin: 0;
+}
+
+.table-file-multiple-widget th {
+  color: var(--color-davysgrey);
+  background: var(--color-whitesmoke);
+  font-size: var(--font-size-s);
+  height: calc(var(--space-m) * 2);
+}
+
+.table-file-multiple-widget td {
+  padding-top: var(--space-m);
+  padding-bottom: var(--space-m);
+}
+
+.table-file-multiple-widget .form-item {
+  margin-top: var(--space-m);
+  margin-bottom: var(--space-xs);
+}
+
+.table-file-multiple-widget .tabledrag-cell {
+  padding-top: var(--space-xs);
+  padding-bottom: var(--space-xs);
+}
+
+.table-file-multiple-widget .checkbox .form-type--boolean {
+  line-height: calc(var(--space-m) * 3);
+}
+
+.no-touchevents .table-file-multiple-widget .checkbox .form-type--boolean {
+  line-height: var(--line-height);
+}
+
+/**
+ * The cell that contains file operations (usually, this is the remove button).
+ */
+.file-operations-cell {
+  width: 1px;
+}
+
+/**
+ * Take as much space as possible.
+ */
+@media screen and (max-width: 37.5em) {
+  .claro-details__wrapper .file-widget-multiple__table-wrapper {
+    margin-right: calc(var(--space-m) * -1);
+    margin-left: calc(var(--space-m) * -1);
+  }
+
+  .claro-details__wrapper .file-widget-multiple__table-wrapper > :not(table) {
+    margin-right: var(--space-m);
+    margin-left: var(--space-m);
+  }
+}
diff --git a/css/src/components/tables.css b/css/src/components/tables.css
index a7e3184..5378e15 100644
--- a/css/src/components/tables.css
+++ b/css/src/components/tables.css
@@ -8,6 +8,7 @@ table {
   margin-top: var(--space-l);
   margin-bottom: var(--space-l);
 }
+
 .sticky-header {
   min-width: 0;
 }
@@ -23,6 +24,7 @@ th {
   height: var(--space-xl);
   padding: var(--space-xs) var(--space-m);
   background: var(--color-whitesmoke);
+  color: var(--color-text);
   line-height: 1.25rem; /* 20px */
   text-align: left; /* LTR */
   position: relative;
@@ -179,7 +181,8 @@ td > .ajax-new-content > .form-item > .form-element {
   width: 100%;
 }
 
-th.is-disabled {
+/* Win over table-file-multiple-widget. */
+th.is-disabled.is-disabled {
   color: var(--input--disabled-fg-color);
 }
 /* Force browsers to calculate the width of a 'select all' <th> element. */
@@ -227,3 +230,13 @@ td.priority-medium {
     display: table-cell;
   }
 }
+
+.tabledrag-toggle-weight-wrapper {
+  margin-top: var(--space-l);
+  line-height: calc(28rem / 16);
+}
+
+.tabledrag-toggle-weight-wrapper + table,
+.tabledrag-toggle-weight-wrapper + .tableresponsive-toggle-columns + table {
+  margin-top: 0;
+}
diff --git a/images/src/hide.svg b/images/src/hide.svg
new file mode 100644
index 0000000..6994deb
--- /dev/null
+++ b/images/src/hide.svg
@@ -0,0 +1,12 @@
+<svg
+  xmlns='http://www.w3.org/2000/svg'
+  width='16'
+  height='16'
+  viewBox='0 0 16 16'
+  fill='#000'
+  fill-rule='evenodd'>
+  <path
+     d="M 2.0106399,1.6964404 2,1.707083 14.072,13.779133 13.3756,14.4756 11.297973,12.397987 C 10.282626,12.785827 9.1687331,13 8,13 4.3636399,13 1.2581813,10.926667 0,8 0.64703865,6.4949202 1.7826266,5.2155203 3.2277199,4.3277203 L 1,2.1 1.7071066,1.392904 Z m 2.98936,6.3035598 c 0,-0.54608 0.1459066,-1.0580666 0.4008533,-1.4991333 L 9.4991464,10.599147 C 9.0580798,10.854107 8.5460798,11 8,11 6.3431465,11 5,9.656854 5,8 Z"/>
+  <path
+     d="m 5.1510932,3.4439603 1.75984,1.75984 c 0.3376,-0.1315867 0.7048933,-0.2038 1.0890666,-0.2038 C 9.6568531,5 11,6.3431469 11,8 11,8.3841735 10.92779,8.7514668 10.7962,9.0890668 L 13.140293,11.43316 C 14.410266,10.561414 15.408933,9.3748668 16,8 14.741866,5.0733336 11.63636,3 8,3 c -0.9987733,0 -1.9575066,0.1564134 -2.8489066,0.44396 z"/>
+</svg>
diff --git a/images/src/show.svg b/images/src/show.svg
new file mode 100644
index 0000000..e9be410
--- /dev/null
+++ b/images/src/show.svg
@@ -0,0 +1,10 @@
+<svg
+  xmlns='http://www.w3.org/2000/svg'
+  width='16'
+  height='16'
+  viewBox='0 0 16 16'
+  fill='#000'
+  fill-rule='evenodd'>
+  <path
+    d='M 8,3 C 4.3636399,3 1.2581813,5.0733333 0,8 1.2581813,10.926667 4.3636399,13 8,13 11.63636,13 14.741866,10.926667 16,8 14.741866,5.0733333 11.63636,3 8,3 Z m 0,8 C 9.6568531,11 11,9.656853 11,8 11,6.3431466 9.6568531,5 8,5 6.3431465,5 5,6.3431466 5,8 c 0,1.656853 1.3431466,3 3,3 z' />
+</svg>
diff --git a/js/claro.tabledrag.es6.js b/js/claro.tabledrag.es6.js
index 70d92f2..e1a995f 100644
--- a/js/claro.tabledrag.es6.js
+++ b/js/claro.tabledrag.es6.js
@@ -4,6 +4,10 @@
  *
  * - New Drupal.theme.tableDragHandle() function for tabledrag handle markup
  *   (https://www.drupal.org/node/3077938).
+ * - New Drupal.theme.tableDragToggle() function for tabledrag toggle markup
+ *   (@todo: https://www.drupal.org/node/3084916).
+ * - New Drupal.theme.tableDragToggleWrapper() function for the wrapper of the
+ *   tabledrag toggle (@todo: https://www.drupal.org/node/3084916).
  * - Tabledrag functionality can be disabled
  *   (https://www.drupal.org/node/3083039).
  * - The initial content of the tabledrag-cell is wrapped into a new DOM element
@@ -21,6 +25,8 @@
  *     changed marker.
  * - Fixes the RTL bug of the original tabledrag.js
  *   (https://www.drupal.org/node/197641).
+ * - Tabledrag changed mark is added next to the drag-handle, and not after the
+ *   last item. (@todo: https://www.drupal.org/node/3084910).
  *
  * The '_slicedToArray' shim added for handling destructured arrays breaks IE11,
  * that is why the 'prefer-destructuring' rule is disabled.
@@ -252,17 +258,18 @@
       self.makeDraggable(this);
     });
 
-    // Add a link before the table for users to show or hide weight columns.
-    $table.before($('<button type="button" class="link tabledrag-toggle-weight"></button>')
+    // Add the toggle link wrapper before the table that will contain the toggle
+    // for users to show or hide weight columns.
+    $table.before($(Drupal.theme('tableDragToggleWrapper'))
+      .addClass('js-tabledrag-toggle-weight-wrapper')
       .on(
         'click',
+        '.js-tabledrag-toggle-weight',
         $.proxy(function toggleColumns(event) {
           event.preventDefault();
           this.toggleColumns();
         }, this),
-      )
-      .wrap('<div class="tabledrag-toggle-weight-wrapper"></div>')
-      .parent());
+      ));
 
     // Initialize the specified columns (for example, weight or parent columns)
     // to show or hide according to user preference. This aids accessibility
@@ -431,7 +438,18 @@
         this.colSpan = this.colSpan - 1;
       });
       // Change link text.
-      $('.tabledrag-toggle-weight').text(Drupal.t('Show row weights'));
+      $('.js-tabledrag-toggle-weight-wrapper').each(function addShowWeightToggle() {
+        const $wrapper = $(this);
+        const toggleWasFocused = $wrapper.find('.js-tabledrag-toggle-weight:focus').length;
+        $wrapper.empty().append($(Drupal.theme(
+          'tableDragToggle',
+          'show',
+          Drupal.t('Show row weights'),
+        )).addClass('js-tabledrag-toggle-weight'));
+        if (toggleWasFocused) {
+          $wrapper.find('.js-tabledrag-toggle-weight').trigger('focus');
+        }
+      });
     },
 
     /**
@@ -450,7 +468,18 @@
         this.colSpan = this.colSpan + 1;
       });
       // Change link text.
-      $('.tabledrag-toggle-weight').text(Drupal.t('Hide row weights'));
+      $('.js-tabledrag-toggle-weight-wrapper').each(function addHideWeightToggle() {
+        const $wrapper = $(this);
+        const toggleWasFocused = $wrapper.find('.js-tabledrag-toggle-weight:focus').length;
+        $wrapper.empty().append($(Drupal.theme(
+          'tableDragToggle',
+          'hide',
+          Drupal.t('Hide row weights'),
+        )).addClass('js-tabledrag-toggle-weight'));
+        if (toggleWasFocused) {
+          $wrapper.find('.js-tabledrag-toggle-weight').trigger('focus');
+        }
+      });
     },
 
     /**
@@ -1682,7 +1711,7 @@
       const marker = $(Drupal.theme('tableDragChangedMarker')).addClass('js-tabledrag-changed-marker');
       const cell = $(this.element).find('td:first-of-type');
       if (cell.find('.js-tabledrag-changed-marker').length === 0) {
-        cell.parent().find('.js-tabledrag-cell-content').append(marker);
+        cell.find('.js-tabledrag-handle').after(marker);
       }
     },
 
@@ -1767,6 +1796,52 @@
       tableDragCellContentWrapper() {
         return '<div class="tabledrag-cell-content__item"/>';
       },
+
+      /**
+       * Constructs the weight column toggle.
+       *
+       * The 'tabledrag-toggle-weight' CSS class should be kept since it is used
+       * elsewhere as well (e.g. in tests).
+       *
+       * @param {string} action
+       *   The action the toggle will perform.
+       * @param {string} text
+       *   The text content of the toggle.
+       *
+       * @return {string}
+       *   A string representing a DOM fragment.
+       */
+      tableDragToggle(action, text) {
+        const classes = [
+          'action-link',
+          'action-link--extrasmall',
+          'tabledrag-toggle-weight',
+        ];
+        switch (action) {
+          case 'show':
+            classes.push('action-link--icon-show');
+            break;
+
+          default:
+            classes.push('action-link--icon-hide');
+            break;
+        }
+
+        return `<a href="#" class="${classes.join(' ')}">${text}</a>`;
+      },
+
+      /**
+       * Constructs the wrapper of the weight column toggle.
+       *
+       * The 'tabledrag-toggle-weight-wrapper' CSS class should be kept since it is used
+       * by Views UI and inside off-canvas dialogs.
+       *
+       * @return {string}
+       *   A string representing a DOM fragment.
+       */
+      tableDragToggleWrapper() {
+        return '<div class="tabledrag-toggle-weight-wrapper"></div>';
+      },
     },
   );
 })(jQuery, Drupal, drupalSettings);
diff --git a/js/claro.tabledrag.js b/js/claro.tabledrag.js
index 86c5dab..3791bca 100644
--- a/js/claro.tabledrag.js
+++ b/js/claro.tabledrag.js
@@ -86,10 +86,10 @@ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol
       self.makeDraggable(this);
     });
 
-    $table.before($('<button type="button" class="link tabledrag-toggle-weight"></button>').on('click', $.proxy(function toggleColumns(event) {
+    $table.before($(Drupal.theme('tableDragToggleWrapper')).addClass('js-tabledrag-toggle-weight-wrapper').on('click', '.js-tabledrag-toggle-weight', $.proxy(function toggleColumns(event) {
       event.preventDefault();
       this.toggleColumns();
-    }, this)).wrap('<div class="tabledrag-toggle-weight-wrapper"></div>').parent());
+    }, this)));
 
     self.initColumns();
 
@@ -191,7 +191,14 @@ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol
         this.colSpan = this.colSpan - 1;
       });
 
-      $('.tabledrag-toggle-weight').text(Drupal.t('Show row weights'));
+      $('.js-tabledrag-toggle-weight-wrapper').each(function addShowWeightToggle() {
+        var $wrapper = $(this);
+        var toggleWasFocused = $wrapper.find('.js-tabledrag-toggle-weight:focus').length;
+        $wrapper.empty().append($(Drupal.theme('tableDragToggle', 'show', Drupal.t('Show row weights'))).addClass('js-tabledrag-toggle-weight'));
+        if (toggleWasFocused) {
+          $wrapper.find('.js-tabledrag-toggle-weight').trigger('focus');
+        }
+      });
     },
     showColumns: function showColumns() {
       var $tables = $('table').findOnce('tabledrag');
@@ -204,7 +211,14 @@ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol
         this.colSpan = this.colSpan + 1;
       });
 
-      $('.tabledrag-toggle-weight').text(Drupal.t('Hide row weights'));
+      $('.js-tabledrag-toggle-weight-wrapper').each(function addHideWeightToggle() {
+        var $wrapper = $(this);
+        var toggleWasFocused = $wrapper.find('.js-tabledrag-toggle-weight:focus').length;
+        $wrapper.empty().append($(Drupal.theme('tableDragToggle', 'hide', Drupal.t('Hide row weights'))).addClass('js-tabledrag-toggle-weight'));
+        if (toggleWasFocused) {
+          $wrapper.find('.js-tabledrag-toggle-weight').trigger('focus');
+        }
+      });
     },
     rowSettings: function rowSettings(group, row) {
       var field = $(row).find('.' + group);
@@ -935,7 +949,7 @@ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol
       var marker = $(Drupal.theme('tableDragChangedMarker')).addClass('js-tabledrag-changed-marker');
       var cell = $(this.element).find('td:first-of-type');
       if (cell.find('.js-tabledrag-changed-marker').length === 0) {
-        cell.parent().find('.js-tabledrag-cell-content').append(marker);
+        cell.find('.js-tabledrag-handle').after(marker);
       }
     },
     onIndent: function onIndent() {
@@ -964,6 +978,23 @@ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol
     },
     tableDragCellContentWrapper: function tableDragCellContentWrapper() {
       return '<div class="tabledrag-cell-content__item"/>';
+    },
+    tableDragToggle: function tableDragToggle(action, text) {
+      var classes = ['action-link', 'action-link--extrasmall', 'tabledrag-toggle-weight'];
+      switch (action) {
+        case 'show':
+          classes.push('action-link--icon-show');
+          break;
+
+        default:
+          classes.push('action-link--icon-hide');
+          break;
+      }
+
+      return '<a href="#" class="' + classes.join(' ') + '">' + text + '</a>';
+    },
+    tableDragToggleWrapper: function tableDragToggleWrapper() {
+      return '<div class="tabledrag-toggle-weight-wrapper"></div>';
     }
   });
 })(jQuery, Drupal, drupalSettings);
\ No newline at end of file
diff --git a/templates/content-edit/file-managed-file.html.twig b/templates/content-edit/file-managed-file.html.twig
new file mode 100644
index 0000000..ee0fbff
--- /dev/null
+++ b/templates/content-edit/file-managed-file.html.twig
@@ -0,0 +1,46 @@
+{#
+/**
+ * @file
+ * Theme override to display a file form widget.
+ *
+ * Available variables:
+ * - element: Form element for the file upload.
+ * - attributes: HTML attributes for the containing element.
+ *
+ * Added by Claro:
+ * - multiple: Whether this widget is the part of a multi-value file widget or
+ *   not.
+ * - upload: Whether the file upload input is displayed or not.
+ * - has_value: true if the widget already contains a file.
+ * - has_meta: true when the display checkbox or the description input are
+ *   enabled and and are visible.
+ * - has_display: true when the display checkbox is enabled and is visible.
+ *
+ * @see template_preprocess_file_managed_file()
+ * @see claro_preprocess_file_managed_file()
+ */
+#}
+
+{%
+  set classes = [
+    'js-form-managed-file',
+    'form-managed-file',
+    upload ? 'has-upload' : 'no-upload',
+    has_value ? 'has-value' : 'no-value',
+    has_meta ? 'has-meta' : 'no-meta',
+  ]
+%}
+<div{{ attributes.addClass(classes) }}>
+  <div class="form-managed-file__main">
+    {{ element|without('display', 'description')}}
+  </div>
+
+  {% if has_meta %}
+    <div class="form-managed-file__meta">
+      {{ element.description }}
+      {% if display %}
+        {{ element.display }}
+      {% endif %}
+    </div>
+  {% endif %}
+</div>
diff --git a/templates/content-edit/file-widget-multiple.html.twig b/templates/content-edit/file-widget-multiple.html.twig
new file mode 100644
index 0000000..aa8dc81
--- /dev/null
+++ b/templates/content-edit/file-widget-multiple.html.twig
@@ -0,0 +1,19 @@
+{#
+/**
+ * @file
+ * Theme override to display a multi file form widget.
+ *
+ * Available variables:
+ * - table: Table of previously uploaded files.
+ * - element: The form element for uploading another file.
+ *
+ * @see template_preprocess_file_widget_multiple()
+ */
+#}
+<div class="file-widget-multiple">
+  <div class="file-widget-multiple__table-wrapper">
+    {{ table }}
+  </div>
+
+  {{ element }}
+</div>
diff --git a/templates/details.html.twig b/templates/details.html.twig
index 2bfcd1c..88f72ee 100644
--- a/templates/details.html.twig
+++ b/templates/details.html.twig
@@ -13,6 +13,7 @@
  * - accordion: whether the details element should look as an accordion.
  * - accordion_item: whether the details element is an item of an accordion
  *   list.
+ * - disabled: whether the details is disabled.
  *
  * @see template_preprocess_details()
  * @see claro_preprocess_details()
@@ -58,6 +59,9 @@
     %}
     <summary{{ summary_attributes.addClass(summary_classes) }}>
       {{- title -}}
+      {%- if required -%}
+        <span class="required-mark"></span>
+      {%- endif -%}
     </summary>
   {%- endif -%}
   <div{{ content_attributes.addClass(content_wrapper_classes) }}>
@@ -71,7 +75,7 @@
         </div>
       {% endif %}
       {%- if description -%}
-        <div class="claro-details__description">{{ description }}</div>
+        <div class="claro-details__description{{ disabled ? ' is-disabled' }}">{{ description }}</div>
       {%- endif -%}
       {%- if children -%}
         {{ children }}
diff --git a/templates/field/file-link.html.twig b/templates/field/file-link.html.twig
new file mode 100644
index 0000000..e962ec0
--- /dev/null
+++ b/templates/field/file-link.html.twig
@@ -0,0 +1,18 @@
+{#
+/**
+ * @file
+ * Theme override for a link to a file.
+ *
+ * Available variables:
+ * - attributes: The HTML attributes for the containing element.
+ * - link: A link to the file.
+ * - icon: The icon image representing the file type. This seems to be always
+ *   empty.
+ * - file_size: The size of the file.
+ *
+ * @see template_preprocess_file_link()
+ * @see stable_preprocess_image_widget()
+ */
+#}
+{{ attach_library('classy/file') }}
+<span{{ attributes }}>{{ link }} <span class="file__size">({{ file_size}})</span></span>
