<div id="app">

  <main>
    
    <div class="card-grid">
      <div class="card-grid__inner">
        <template v-for="index in 4">
          <card-message></card-message>
          <card-todo></card-todo>
          <card-progress></card-progress>
        </template>
      </div>
    </div>

    <hr>

    <div class="card-grid card-grid--alt">
      <div class="card-grid__inner">
        <template v-for="index in 2">
          <card-message></card-message>
          <card-todo></card-todo>
          <card-progress></card-progress>
        </template>
      </div>
    </div>
    
  </main>

</div>
@import url('https://fonts.googleapis.com/css2?family=Nunito:wght@300;400;600;700&display=swap');

* {
  box-sizing: border-box;
}

body {
  background: #FAFAFA;
  font-family: 'Nunito', sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

main {
  width: 90%;
  margin: 50px auto;
  max-width: 1100px;
}

.card-grid {
  container-type: inline-size;
  container-name: card-grid;
  margin-bottom: 50px;
 
  &--alt {
    max-width: 500px;
    margin-top: 50px;
  }
  

  &__inner {
    --cols: 4;
    display: grid;
    grid-gap: 2cqw;
    grid-template-columns: repeat(var(--cols), 1fr);

    @container card-grid (max-width: 900px) {
      --cols: 3;
      grid-gap: 3cqw;
    }

    @container card-grid (max-width: 600px) {
      --cols: 2;
      grid-gap: 4cqw;
    }
  }
}

.card {
  container-type: size;
  container-name: card;
  aspect-ratio: 1;
  color: var(--color);

  &__inner {
    font-size: 5cqw;
    height: 100%;
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    padding: 2em;
    background: var(--bg);
    border-radius: 5px;
    border: 2px solid var(--border);
  }

  &--light {
    --color: #777;
    --bg: #FFF;
    --border: #D8D8D8;
  }

  &--mid {
    --color: #777;
    --bg: #E3E3E3;
    --border: #B9B9B9;
  }

  &--dark {
    --color: #FFF;
    --bg: #504b4b;
    --border: #1c1c1c;
  }

  h6 {
    margin-top: 0;
    font-size: 0.9em;
    text-transform: uppercase;
    font-weight: 400;
    letter-spacing: 0.2em;
    position: relative;

    &:before {
      content: '';
      position: absolute;
      bottom: -0.5em;
      left: 0;
      width: 2em;
      height: 2px;
      background: currentColor;
      opacity: 0.1;
    }
  }

  h2 {
    margin-top: 0;
    margin-bottom: 0.5em;
    font-size: 1.4em;
  }

  p {
    font-size: 1em;
    margin-top: 0;
    opacity: 0.8;
    -webkit-line-clamp: 4;
    -webkit-box-orient: vertical;
    display: -webkit-box;
    overflow: hidden;
  }

  &__link {
    margin-top: auto;
    text-decoration: none;
    font-size: 1.2em;
    color: currentColor;
    margin-bottom: -0.4em;
    display: inline-flex;
    align-items: center;

    svg {
      stroke: currentColor;
      margin-left: 0.5em;
      opacity: 0.5;
      width: 1em;
      height: 1em;
    }
  }
}

.todo {
  background: #FFF;
  width: 100%;
  border-radius: 999px;
  padding: 0.5em 1.5em;
  text-decoration: none;
  color: currentColor;
  display: inline-flex;
  align-items: center;
  justify-content: space-between;

  & + & {
    margin-top: 0.5em;
  }

  svg {
    stroke: currentColor;
    opacity: 0.5;
    width: 1em;
    height: 1em;
  }
}

.pie-chart {
  display: block;
  width: 100%;
  height: 10em;
  font-size: 1em;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);

  &__1 {
    stroke: #777;
    fill: none;
    stroke-width: 2;
    stroke-linecap: round;
    animation: progress 1s ease-out forwards;
  }

  &__2 {
    stroke: #EEE;
    fill: none;
    stroke-width: 2;
    animation: progress 1s ease-out forwards;
  }
}

.percentage {
  position: absolute;
  font-size: 3em;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  display: flex;
  flex-direction: column;
  text-align: center;
  line-height: 1;
  font-weight: bold;
  span {
    font-size: 40%;
    font-weight: lighter;
  }
}

@keyframes progress {
  0% {
    stroke-dasharray: 0 100;
  }
}
View Compiled
Vue.component('arrow', {
  template: `<svg xmlns="http://www.w3.org/2000/svg" width="13.889" height="14.718" viewBox="0 0 13.889 14.718">
                 <g transform="translate(1 1.414)">
                   <path d="M7.5,18H19.389" transform="translate(-7.5 -12.055)" fill="none" stroke-linecap="round"
                         stroke-linejoin="round" stroke-width="2"/>
                   <path d="M18,7.5l5.945,5.945L18,19.389" transform="translate(-12.055 -7.5)" fill="none"
                         stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
                 </g>
               </svg>`
});

Vue.component('card-message', {
  template: `
      <div class="card card--light">
          <div class="card__inner">
            <h6>Message</h6>
            <h2>Lorem Ipsum Dolor</h2>
            <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. 
            Ab accusamus accusantium asperiores beatae eaque eveniet explicabo 
            consectetur adipisicing elit.</p>

            <a href="#" class="card__link">
              Read More
              <arrow/> 
            </a>
          </div>
      </div>`
});

Vue.component('card-todo', {
  template: `
      <div class="card card--mid">
          <div class="card__inner">
            <h6>Todo</h6>
            <a :key="index" href="#" class="todo" v-for="index in 3">Lorem Ipsum
             <arrow/>
           </a>

            <a href="#" class="card__link">
              See All
              <arrow/> 
            </a>
          </div>
      </div>`
});

Vue.component('card-progress', {
  template: `
      <div class="card card--dark">
          <div class="card__inner">
            <h6>Progress</h6>
            <svg viewBox="0 0 36 36" class="pie-chart">
             <path class="pie-chart__1"
                   stroke-dasharray="100, 100"
                   d="M18 2.0845 a 15.9155 15.9155 0 0 1 0 31.831 a 15.9155 15.9155 0 0 1 0 -31.831"/>
             <path class="pie-chart__2"
                   stroke-dasharray="70, 100"
                   d="M18 2.0845
           a 15.9155 15.9155 0 0 1 0 31.831
           a 15.9155 15.9155 0 0 1 0 -31.831"
             />
           </svg>

           <div class="percentage">
             70 <span>%</span>
           </div>
            <a href="#" class="card__link">
              More Info
              <arrow/> 
            </a>
          </div>
      </div>`
});


let app = new Vue({

  el: '#app',

})
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/vue/2.7.8/vue.min.js