diff --git a/core/themes/olivero/components/teaser/teaser.component.yml b/core/themes/olivero/components/teaser/teaser.component.yml
new file mode 100644
index 0000000000000000000000000000000000000000..5fb91c2024013a2fa35efb1dc1b5ea4fbf83f308
--- /dev/null
+++ b/core/themes/olivero/components/teaser/teaser.component.yml
@@ -0,0 +1,44 @@
+# This is so your IDE knows about the syntax for fixes and autocomplete.
+$schema: https://git.drupalcode.org/project/drupal/-/raw/HEAD/core/assets/schemas/v1/metadata.schema.json
+
+# The human readable name.
+name: Teaser
+
+# Status can be: "experimental", "stable", "deprecated", "obsolete".
+status: stable
+
+# Schema for the props. We support www.json-schema.org. Learn more about the
+# syntax there.
+props:
+  type: object
+  properties:
+    attributes:
+      type: Drupal\Core\Template\Attribute
+      title: Attributes
+      description: Wrapper attributes.
+
+# Slots always hold arbitrary markup. We know that beforehand, so no need for
+# a schema for slots.
+slots:
+  # The key is the name of the slot. In your template you will use
+  # {% block content %}.
+  content:
+    title: Content
+    required: true
+    description: The teaser content
+  image:
+    title: Image
+    required: false
+    description: Teaser image
+  meta:
+    title: Meta
+    required: false
+    description: Teaser meta
+  prefix:
+    title: Prefix
+    required: false
+    description: Contextual links slot
+  title:
+    title: Title content
+    required: false
+    description: Teaser title
diff --git a/core/themes/olivero/components/teaser/teaser.css b/core/themes/olivero/components/teaser/teaser.css
new file mode 100644
index 0000000000000000000000000000000000000000..1db0a4466c37389a0087ccec7da3a9fab29a1004
--- /dev/null
+++ b/core/themes/olivero/components/teaser/teaser.css
@@ -0,0 +1,100 @@
+/*
+ * DO NOT EDIT THIS FILE.
+ * See the following change record for more information,
+ * https://www.drupal.org/node/3084859
+ * @preserve
+ */
+.teaser {
+  position: relative; /* Anchor after pseudo-element. */
+  padding-block-end: var(--sp1-5);
+}
+.teaser::after {
+  position: absolute;
+  inset-block-end: 0;
+  width: var(--sp3);
+  height: 0;
+  content: "";
+  /* Intentionally not using CSS logical properties. */
+  border-top: solid 2px var(--color--gray-95);
+}
+@media (min-width: 62.5rem) {
+  .teaser {
+    padding-block-end: var(--sp3);
+  }
+}
+.teaser__content {
+  display: grid;
+  grid-auto-rows: max-content;
+  gap: var(--sp);
+}
+.teaser__content .field:not(:last-child) {
+  margin-block-end: 0;
+}
+@media (min-width: 62.5rem) {
+  .teaser__content {
+    gap: var(--sp2);
+  }
+}
+.teaser__image {
+  flex-shrink: 0;
+  margin: 0;
+}
+.teaser__image:empty {
+  display: none;
+}
+.teaser__image:empty + .teaser__title {
+  flex-basis: auto;
+}
+.teaser__image a {
+  display: block;
+}
+.teaser__image img {
+  width: var(--sp3-5);
+  height: var(--sp3-5);
+  object-fit: cover;
+  border-radius: 50%;
+}
+@media (min-width: 62.5rem) {
+  .teaser__image img {
+    width: var(--grid-col-width);
+    height: var(--grid-col-width);
+  }
+}
+@media (min-width: 62.5rem) {
+  .teaser__image {
+    position: absolute;
+    inset-block-start: 0;
+    inset-inline-start: calc(-1 * ((var(--grid-col-width) + var(--grid-gap))));
+    margin: 0;
+  }
+}
+.teaser__meta {
+  margin-block-end: var(--sp);
+}
+.teaser__title {
+  margin-block: 0;
+  flex-basis: calc(100% - var(--sp4-5));
+  color: var(--color-text-neutral-loud);
+  font-size: 1.5rem;
+  line-height: var(--line-height-base);
+}
+@media (min-width: 62.5rem) {
+  .teaser__title {
+    flex-basis: auto;
+    font-size: var(--sp2);
+    line-height: var(--sp3);
+  }
+}
+.teaser__top {
+  display: flex;
+  flex-wrap: nowrap;
+  align-items: center;
+  margin: 0;
+  gap: var(--sp1);
+  margin-block-end: var(--sp1);
+}
+@media (min-width: 62.5rem) {
+  .teaser__top {
+    position: relative; /* Anchor the image */
+  }
+}
diff --git a/core/themes/olivero/components/teaser/teaser.pcss.css b/core/themes/olivero/components/teaser/teaser.pcss.css
new file mode 100644
index 0000000000000000000000000000000000000000..ff07f8c06542c7ce8c15624105fec8256e193dec
--- /dev/null
+++ b/core/themes/olivero/components/teaser/teaser.pcss.css
@@ -0,0 +1,101 @@
+@import "../../css/base/media-queries.pcss.css";
+
+.teaser {
+  position: relative; /* Anchor after pseudo-element. */
+  padding-block-end: var(--sp1-5);
+
+  &::after {
+    position: absolute;
+    inset-block-end: 0;
+    width: var(--sp3);
+    height: 0;
+    content: "";
+    /* Intentionally not using CSS logical properties. */
+    border-top: solid 2px var(--color--gray-95);
+  }
+
+  @media (--lg) {
+    padding-block-end: var(--sp3);
+  }
+}
+
+.teaser__content {
+  display: grid;
+  grid-auto-rows: max-content;
+  gap: var(--sp);
+
+  .field:not(:last-child) {
+    margin-block-end: 0;
+  }
+
+  @media (--lg) {
+    gap: var(--sp2);
+  }
+}
+
+.teaser__image {
+  flex-shrink: 0;
+  margin: 0;
+
+  &:empty {
+    display: none;
+
+    & + .teaser__title {
+      flex-basis: auto;
+    }
+  }
+
+  & a {
+    display: block;
+  }
+
+  & img {
+    width: var(--sp3-5);
+    height: var(--sp3-5);
+    object-fit: cover;
+    border-radius: 50%;
+
+    @media (--lg) {
+      width: var(--grid-col-width);
+      height: var(--grid-col-width);
+    }
+  }
+
+  @media (--lg) {
+    position: absolute;
+    inset-block-start: 0;
+    inset-inline-start: calc(-1 * ((var(--grid-col-width) + var(--grid-gap))));
+    margin: 0;
+  }
+}
+
+.teaser__meta {
+  margin-block-end: var(--sp);
+}
+
+.teaser__title {
+  margin-block: 0;
+  flex-basis: calc(100% - var(--sp4-5));
+  color: var(--color-text-neutral-loud);
+  font-size: 24px;
+  line-height: var(--line-height-base);
+
+  @media (--lg) {
+    flex-basis: auto;
+    font-size: var(--sp2);
+    line-height: var(--sp3);
+  }
+}
+
+.teaser__top {
+  display: flex;
+  flex-wrap: nowrap;
+  align-items: center;
+  margin: 0;
+  gap: var(--sp1);
+  margin-block-end: var(--sp1);
+
+  @media (--lg) {
+    position: relative; /* Anchor the image */
+  }
+}
diff --git a/core/themes/olivero/components/teaser/teaser.twig b/core/themes/olivero/components/teaser/teaser.twig
new file mode 100644
index 0000000000000000000000000000000000000000..ee1fe240d38e85412d327c09e38cf07762d14054
--- /dev/null
+++ b/core/themes/olivero/components/teaser/teaser.twig
@@ -0,0 +1,15 @@
+<article{{ attributes.addClass('teaser') }}>
+  <header>
+    {% block prefix %}{% endblock %}
+    <div class="teaser__meta">
+      {% block meta %}{% endblock %}
+    </div>
+    <div class="teaser__top">
+      <div class="teaser__image">{% block image %}{% endblock %}</div>
+      {% block title %}{% endblock %}
+    </div>
+  </header>
+  <div class="teaser__content">
+    {% block content %}{% endblock %}
+  </div>
+</article>
diff --git a/core/themes/olivero/css/components/field.css b/core/themes/olivero/css/components/field.css
index d4fad4c5b8e26981ae71257e7a636f7dca544571..17c474ee2b56b07abfcc973d7c4fc8d7e18e0907 100644
--- a/core/themes/olivero/css/components/field.css
+++ b/core/themes/olivero/css/components/field.css
@@ -14,20 +14,6 @@
   margin-block-end: var(--sp2);
 }
 
-.node--view-mode-teaser .field {
-  margin-block-end: var(--sp);
-}
-
-.node--view-mode-teaser .field:last-child {
-  margin-block-end: 0;
-}
-
-@media (min-width: 62.5rem) {
-  .node--view-mode-teaser .field {
-    margin-block-end: var(--sp2);
-  }
-}
-
 .field__label {
   font-weight: bold;
 }
diff --git a/core/themes/olivero/css/components/field.pcss.css b/core/themes/olivero/css/components/field.pcss.css
index 7c08eaf127dc02f8b66aa9ad5b34a11909ea7cdf..f2f9d691346744639570a6a8d7a468ae02f0b4cb 100644
--- a/core/themes/olivero/css/components/field.pcss.css
+++ b/core/themes/olivero/css/components/field.pcss.css
@@ -9,18 +9,6 @@
   margin-block-end: var(--sp2);
 }
 
-.node--view-mode-teaser .field {
-  margin-block-end: var(--sp);
-
-  &:last-child {
-    margin-block-end: 0;
-  }
-
-  @media (--lg) {
-    margin-block-end: var(--sp2);
-  }
-}
-
 .field__label {
   font-weight: bold;
 }
diff --git a/core/themes/olivero/css/components/node-teaser.css b/core/themes/olivero/css/components/node-teaser.css
index 103ca2ec8815cb31e154171345db17827b36ed57..b47415116eb43450c8967b0d0428b7f704318e1f 100644
--- a/core/themes/olivero/css/components/node-teaser.css
+++ b/core/themes/olivero/css/components/node-teaser.css
@@ -10,21 +10,6 @@
  * Node Teaser specific styles.
  */
 
-.node--view-mode-teaser {
-  position: relative; /* Anchor after pseudo-element. */
-  margin-block-end: var(--sp1-5);
-}
-
-.node--view-mode-teaser::after {
-  position: absolute;
-  inset-block-end: 0;
-  width: var(--sp3);
-  height: 0;
-  content: "";
-  /* Intentionally not using CSS logical properties. */
-  border-top: solid 2px var(--color--gray-95);
-}
-
 .node--view-mode-teaser .node__meta {
   margin-block-end: var(--sp);
 }
@@ -34,80 +19,6 @@
   font-weight: bold;
 }
 
-.node--view-mode-teaser .node__top-wrapper {
-  display: flex;
-  flex-wrap: wrap;
-  align-items: center;
-  margin: 0;
-}
-
-@media (min-width: 62.5rem) {
-  .node--view-mode-teaser .node__top-wrapper {
-    position: relative; /* Anchor the image */
-  }
-}
-
-.node--view-mode-teaser .primary-image {
-  flex-shrink: 0;
-  margin: 0;
-  margin-block-end: var(--sp1);
-  margin-inline-end: var(--sp1);
-
-  /* Ensure title does not wrap under image until necessary. */
-}
-
-:is(.node--view-mode-teaser .primary-image) + .node__title {
-  flex-basis: calc(100% - var(--sp4-5));
-}
-
-@media (min-width: 62.5rem) {
-  :is(.node--view-mode-teaser .primary-image) + .node__title {
-    flex-basis: auto;
-  }
-}
-
-.node--view-mode-teaser .primary-image a {
-  display: block;
-}
-
-.node--view-mode-teaser .primary-image img {
-  width: var(--sp3-5);
-  height: var(--sp3-5);
-  object-fit: cover;
-  border-radius: 50%;
-}
-
-@media (min-width: 62.5rem) {
-  .node--view-mode-teaser .primary-image img {
-    width: var(--grid-col-width);
-    height: var(--grid-col-width);
-  }
-}
-
-@media (min-width: 62.5rem) {
-  .node--view-mode-teaser .primary-image {
-    position: absolute;
-    inset-block-start: 0;
-    inset-inline-start: calc(-1 * ((var(--grid-col-width) + var(--grid-gap))));
-    margin: 0;
-  }
-}
-
-.node--view-mode-teaser .node__title {
-  margin: 0;
-  margin-block-end: var(--sp1);
-  color: var(--color-text-neutral-loud);
-  font-size: 1.5rem;
-  line-height: var(--line-height-base);
-}
-
-@media (min-width: 62.5rem) {
-  .node--view-mode-teaser .node__title {
-    font-size: var(--sp2);
-    line-height: var(--sp3);
-  }
-}
-
 .node--view-mode-teaser .field--tag-ref {
   margin-block-start: var(--sp1);
   margin-block-end: 0;
@@ -124,13 +35,3 @@
     margin-block-start: var(--sp2);
   }
 }
-
-@media (min-width: 62.5rem) {
-  .node--view-mode-teaser {
-    margin-block-end: var(--sp3);
-  }
-}
-
-.views-row:last-child .node--view-mode-teaser {
-  margin-block-end: 0;
-}
diff --git a/core/themes/olivero/css/components/node-teaser.pcss.css b/core/themes/olivero/css/components/node-teaser.pcss.css
index 1d045f46d2ea8784d4b1ac625c3383d8c8a15bd8..ec6492c2a363994e5dbcf07a8d8acbdfeb4e157b 100644
--- a/core/themes/olivero/css/components/node-teaser.pcss.css
+++ b/core/themes/olivero/css/components/node-teaser.pcss.css
@@ -6,19 +6,6 @@
 @import "../base/media-queries.pcss.css";
 
 .node--view-mode-teaser {
-  position: relative; /* Anchor after pseudo-element. */
-  margin-block-end: var(--sp1-5);
-
-  &::after {
-    position: absolute;
-    inset-block-end: 0;
-    width: var(--sp3);
-    height: 0;
-    content: "";
-    /* Intentionally not using CSS logical properties. */
-    border-top: solid 2px var(--color--gray-95);
-  }
-
   & .node__meta {
     margin-block-end: var(--sp);
 
@@ -28,69 +15,6 @@
     }
   }
 
-  & .node__top-wrapper {
-    display: flex;
-    flex-wrap: wrap;
-    align-items: center;
-    margin: 0;
-
-    @media (--lg) {
-      position: relative; /* Anchor the image */
-    }
-  }
-
-  & .primary-image {
-    flex-shrink: 0;
-    margin: 0;
-    margin-block-end: var(--sp1);
-    margin-inline-end: var(--sp1);
-
-    /* Ensure title does not wrap under image until necessary. */
-    & + .node__title {
-      flex-basis: calc(100% - var(--sp4-5));
-
-      @media (--lg) {
-        flex-basis: auto;
-      }
-    }
-
-    & a {
-      display: block;
-    }
-
-    & img {
-      width: var(--sp3-5);
-      height: var(--sp3-5);
-      object-fit: cover;
-      border-radius: 50%;
-
-      @media (--lg) {
-        width: var(--grid-col-width);
-        height: var(--grid-col-width);
-      }
-    }
-
-    @media (--lg) {
-      position: absolute;
-      inset-block-start: 0;
-      inset-inline-start: calc(-1 * ((var(--grid-col-width) + var(--grid-gap))));
-      margin: 0;
-    }
-  }
-
-  & .node__title {
-    margin: 0;
-    margin-block-end: var(--sp1);
-    color: var(--color-text-neutral-loud);
-    font-size: 24px;
-    line-height: var(--line-height-base);
-
-    @media (--lg) {
-      font-size: var(--sp2);
-      line-height: var(--sp3);
-    }
-  }
-
   & .field--tag-ref {
     margin-block-start: var(--sp1);
     margin-block-end: 0;
@@ -105,12 +29,4 @@
       margin-block-start: var(--sp2);
     }
   }
-
-  @media (--lg) {
-    margin-block-end: var(--sp3);
-  }
-}
-
-.views-row:last-child .node--view-mode-teaser {
-  margin-block-end: 0;
-}
+}
\ No newline at end of file
diff --git a/core/themes/olivero/css/layout/views.css b/core/themes/olivero/css/layout/views.css
index e97620b1ed0e3125cd1a31dad8a01e52948e3206..9594194e744f8e82c4fd64d3ff57cee316f6b277 100644
--- a/core/themes/olivero/css/layout/views.css
+++ b/core/themes/olivero/css/layout/views.css
@@ -10,16 +10,16 @@
  * Styles for views.
  */
 
-.view > * {
-  margin-block-end: var(--sp2);
-}
-
-.view > *:last-child {
-  margin-block-end: 0;
+.view,
+.view-content {
+  display: grid;
+  gap: var(--sp2);
+  grid-template-rows: max-content;
 }
 
 @media (min-width: 43.75rem) {
-  .view > * {
-    margin-block-end: var(--sp3);
+  .view,
+  .view-content {
+    gap: var(--sp3);
   }
 }
diff --git a/core/themes/olivero/css/layout/views.pcss.css b/core/themes/olivero/css/layout/views.pcss.css
index cbc6f03f479b098ea91fcee7fef2bbc43da1bdd8..3bedc2d9a4ec7625c3c8c0e42c328d7b42b326e5 100644
--- a/core/themes/olivero/css/layout/views.pcss.css
+++ b/core/themes/olivero/css/layout/views.pcss.css
@@ -5,16 +5,13 @@
 
 @import "../base/media-queries.pcss.css";
 
-.view {
-  & > * {
-    margin-block-end: var(--sp2);
+.view,
+.view-content {
+  display: grid;
+  gap: var(--sp2);
+  grid-template-rows: max-content;
 
-    &:last-child {
-      margin-block-end: 0;
-    }
-
-    @media (--md) {
-      margin-block-end: var(--sp3);
-    }
+  @media (--md) {
+    gap: var(--sp3);
   }
 }
diff --git a/core/themes/olivero/templates/content/node--teaser.html.twig b/core/themes/olivero/templates/content/node--teaser.html.twig
index 8720f2f473abcc6578da01be8d8b55c720ee1e5f..a6a0fc7cd6bfe120fc4136328bf8daa9dc105fdf 100644
--- a/core/themes/olivero/templates/content/node--teaser.html.twig
+++ b/core/themes/olivero/templates/content/node--teaser.html.twig
@@ -78,10 +78,27 @@
   ]
 %}
 
-<article{{ attributes.addClass(classes) }}>
-  <header>
+
+{% embed "olivero:teaser" with {
+  attributes: attributes.addClass(classes),
+  author_attributes,
+  author_name,
+  content,
+  date,
+  display_submitted,
+  label,
+  metadata,
+  title_attributes,
+  title_prefix,
+  title_suffix,
+  read_more,
+  url,
+  } only %}
+  {% block prefix %}
     {{ title_prefix }}
     {{ title_suffix }}
+  {% endblock %}
+  {% block meta %}
     {% if display_submitted %}
       <div class="node__meta">
         <span{{ author_attributes }}>
@@ -90,16 +107,16 @@
         {{ metadata }}
       </div>
     {% endif %}
+  {% endblock %}
+  {% block image %}{{~ content.field_image ~}}{% endblock %}
+  {% block title %}
     {% if label and not page %}
-      <div class="node__top-wrapper">
-        {{ content.field_image }}
-        <h2{{ title_attributes.addClass('node__title') }}>
-          <a href="{{ url }}" rel="bookmark">{{ label }}</a>
-        </h2>
-      </div>
+      <h2{{ title_attributes.addClass('node__title', 'teaser__title') }}>
+        <a href="{{ url }}" rel="bookmark">{{ label }}</a>
+      </h2>
     {% endif %}
-  </header>
-  <div{{ content_attributes.addClass('node__content') }}>
+  {% endblock %}
+  {% block content %}
     {{ content|without('field_image', 'links') }}
-  </div>
-</article>
+  {% endblock %}
+{% endembed %}
diff --git a/core/themes/olivero/templates/field/field--node--field-image.html.twig b/core/themes/olivero/templates/field/field--node--field-image.html.twig
deleted file mode 100644
index 77ce43a4dcc1fc84cd70fcf30ac18d192393755a..0000000000000000000000000000000000000000
--- a/core/themes/olivero/templates/field/field--node--field-image.html.twig
+++ /dev/null
@@ -1,26 +0,0 @@
-{#
-/**
- * @file
- * Theme override for the image field.
- *
- * Available variables:
- * - attributes: HTML attributes for the containing element.
- * - label_hidden: Whether to show the field label or not.
- * - title_attributes: HTML attributes for the title.
- * - label: The label for the field.
- * - multiple: TRUE if a field can contain multiple items.
- * - items: List of all the field items. Each item contains:
- *   - attributes: List of HTML attributes for each item.
- *   - content: The field item's content.
- * - entity_type: The entity type to which the field belongs.
- * - field_name: The name of the field.
- * - field_type: The type of the field.
- * - label_display: The display settings for the label.
- *
- *
- * @see template_preprocess_field()
- */
-#}
-
-{% extends 'field.html.twig' %}
-{% set attributes = attributes.addClass('primary-image') %}