oneColumn.html
<section class="section container basicSection">
  <header class="section__header">
    <h2 class="h6 accent-primary">Heading Placeholder</h2>
    <h3>Ipsum nihil earum blanditiis dolore mollitia Adipisci voluptate.</h3>
    <p>Elit numquam corrupti magni sapiente non? Tenetur corporis ipsa voluptatibus vitae numquam Exercitationem distinctio vero nesciunt fuga molestiae Repellat dignissimos cumque est quisquam veniam Repellat nobis earum quo distinctio repellendus!</p>
  </header>
  <div class="basicSection__content">
    <div class="basicSection__media media accent-primary" style="--aspect-ratio: 634 / 368">
      <p-lazy>
        <video class="media__content" inert controls autoplay playsinline>
          <source data-src="https://www.w3schools.com/html/mov_bbb.mp4" type="video/mp4" />
          Your browser does not support the video tag.
        </video>
        <template #placeholder="{ load, modifier }">
          <picture class="media__mask" :class="modifier">
            <img class="media__maskImg" srcset="https://unsplash.it/634/368?random&gravity=center" alt="" />
          </picture>
          <button class="media__trigger" @click="load" :class="modifier">
            <svg class="media__icon icon" viewBox="0 0 96 96"><use href="/main-icons-sprite.svg#play" /></svg>
          </button>
        </template>
      </p-lazy>
    </div>
  </div>
  <footer class="section__footer">
    <p>Amet omnis eos omnis error beatae deleniti. Veritatis tempore vero!</p>
    <div class="actions">
      <a class="button" href="#">Learn More</a>
    </div>
  </footer>
</section>

<section class="section container basicSection accent-primary">
  <header class="section__header">
    <h2 class="h6">Heading Placeholder</h2>
    <h3>Ipsum nihil earum blanditiis dolore mollitia Adipisci voluptate.</h3>
  </header>
  <div class="basicSection__content">
    <div class="basicSection__image">
      <div class="placeholder" style="aspect-ratio: 634 / 368"></div>
    </div>
  </div>
</section>

<section class="section container basicSection accent-secondary">
  <div class="basicSection__content">
    <div class="basicSection__text">
      <h2 class="h6">Heading Placeholder</h2>
      <h3>Adipisicing tempora culpa a unde molestiae. Tenetur ducimus facilis.</h3>
      <p>Mauris euismod sit amet dolor vel vehicula. Nulla lacinia augue sem, accumsan luctus nunc facilisis Duis ex libero, auctor a semper in, condimentum sit amet enim. Vestibulum et consectetur arcu. <a href="#">Nam nunc justo,</a> varius id metus eu praesent dictum sit amet quam efficitur placerat.</p>
    </div>
  </div>
</section>
index.scss
@use '@/core' as *;

.basicSection {
  $b: &;

  &__content {
    --columns: 1;
    --gap: var(--root-gap, 16px);

    display: grid;
    gap: var(--gap);
    grid-template-columns: repeat(var(--columns, 1), minmax(0, 1fr));

    @include at(md) {
      --columns: 2;
    }

    > * {
      min-width: 0;
    }

    &.-center {
      align-items: center;
    }

    > :first-child:last-child {
      grid-column: 1 / -1;
    }
  }

  // When inside container, position within container's grid
  .container > &__content {
    grid-column: main / main;
  }

  // Natural content order for mobile
  &__image {
    order: 1;
  }

  &__testimonial {
    order: 2;
  }

  &__media {
    order: 3;
  }

  &__text {
    order: 4;
  }

  &__cta {
    order: 5;
  }

  &__text,
  &__image,
  &__media,
  &__cta,
  &__testimonial {
    @include at(md) {
      order: unset;
      grid-column: span var(--span, 1);
    }
  }

  &.-wide {
    #{$b}__content {
      @include at(md) {
        --columns: 3;
      }
    }

    @include at(md) {
      :is(#{$b}__text, #{$b}__image, #{$b}__media, #{$b}__cta, #{$b}__testimonial) {
        &.-wide {
          grid-column: span var(--span, 2);
        }
      }
    }
  }
}
PLazy.vue
<script setup>
import { computed, ref, nextTick, useTemplateRef } from 'vue'

/**
 * PLazy is a vue component that lazy loads its content after it's been clicked.
 *
 * @slot default - the content to lazyload. It will remove inert attributes, change data-src
 *                 attributes to src attributes, and call .load() on videos.
 * @slot placeholder - the content to display before it's lazyloaded. The following properties
 *                     are exposed to this slot:
 *       load {function} - function to call to load the content.
 *       loaded {boolean} - whether the content is loaded or not.
 *       modifier {string} - either '-loaded' or '' based on loaded.
 */

const loaded = ref(false)
const content = useTemplateRef('content')
const modifier = computed(() => (loaded.value ? '-loaded' : ''))

const load = async () => {
  if (loaded.value) return

  await nextTick()

  const promises = []

  /* Change data-src attributes to src attributes */
  content.value.querySelectorAll('[data-src]').forEach(element => element.setAttribute('src', element.dataset.src))

  /* remove inert attribute */
  content.value.querySelectorAll('[inert]').forEach(element => (element.inert = false))

  /* load videos */
  content.value.querySelectorAll('video').forEach(element => {
    element.load()
    promises.push(
      new Promise(resolve => {
        element.addEventListener('loadeddata', resolve, { once: true })
      }),
    )
  })

  /* load iframes */
  content.value.querySelectorAll('iframe').forEach(element => {
    promises.push(
      new Promise(resolve => {
        element.addEventListener('load', resolve, { once: true })
      }),
    )
  })

  /* wait for all videos and iframes to load, then update loaded.value */
  Promise.all(promises).then(() => (loaded.value = true))
}
</script>

<template>
  <div ref="content">
    <slot name="default" />
  </div>
  <slot name="placeholder" v-bind="{ load, loaded, modifier }" />
</template>

<style scoped>
div {
  container-type: size;
}
</style>