Open demo

CSS code

HTML
<div class="hz-list">
  <article class="hz-card">
    <div class="hz-media hz-m1" aria-hidden="true">🎧</div>
    <div class="hz-body">
      <p class="hz-kicker">Podcast · Ep. 42</p>
      <h2 class="hz-title">Design systems that survive the redesign</h2>
      <p class="hz-text">Why most token systems die at the first rebrand, and the three rules that kept ours alive through two.</p>
      <div class="hz-foot"><b>52 min</b><span>with Priya N.</span><a class="hz-link" href="#">Listen<span class="hz-sr"> to Design systems that survive the redesign</span> <span aria-hidden="true">→</span></a></div>
    </div>
  </article>
  <article class="hz-card">
    <div class="hz-media hz-m2" aria-hidden="true">📈</div>
    <div class="hz-body">
      <p class="hz-kicker hz-k2">Case study</p>
      <h2 class="hz-title">From 4s to 800ms: a checkout story</h2>
      <p class="hz-text">Every millisecond we clawed back, in order of effort — half the wins needed no JavaScript changes at all.</p>
      <div class="hz-foot"><b>8 min read</b><span>Engineering</span><a class="hz-link" href="#">Read<span class="hz-sr"> From 4s to 800ms: a checkout story</span> <span aria-hidden="true">→</span></a></div>
    </div>
  </article>
</div>
CSS
/* Horizontal media cards that stack below 560px. The footer link (Listen / Read) is stretched over the
   whole card with ::after, so the card has one link target; the focus ring is drawn on the card. */
.hz-list,.hz-list *,.hz-list *::before,.hz-list *::after{box-sizing:border-box}
.hz-list{display:flex;flex-direction:column;align-items:center;gap:24px;width:100%}
.hz-card{position:relative;display:flex;width:100%;max-width:620px;background:#fff;border-radius:16px;overflow:hidden;box-shadow:0 1px 3px rgba(16,24,40,.06),0 14px 34px -16px rgba(16,24,40,.14);transition:transform .18s}
.hz-card:hover{transform:translateY(-4px)}
.hz-media{flex:0 0 200px;display:flex;align-items:center;justify-content:center;font-size:3.4rem}
.hz-m1{background:linear-gradient(140deg,#0ea5e9,#6366f1)}
.hz-m2{background:linear-gradient(140deg,#f59e0b,#ef4444)}
.hz-body{padding:22px 24px;display:flex;flex-direction:column;min-width:0}
.hz-kicker{font-size:.72rem;font-weight:800;letter-spacing:.08em;text-transform:uppercase;color:#4f46e5;margin:0 0 6px}
.hz-k2{color:#c2410c}
.hz-title{font-size:1.1rem;color:#101828;letter-spacing:-.01em;margin:0 0 6px}
.hz-text{font-size:.86rem;line-height:1.6;color:#667085;margin:0 0 14px}
.hz-foot{margin-top:auto;display:flex;align-items:center;gap:14px;font-size:.78rem;color:#667085}
.hz-foot b{color:#344054;font-weight:600}
.hz-link{margin-left:auto;color:#101828;font-weight:700;font-size:.83rem;text-decoration:none;white-space:nowrap}
.hz-link::after{content:"";position:absolute;inset:0;z-index:1}
.hz-link:hover{text-decoration:underline}
.hz-link:focus-visible{outline:2px solid transparent}
.hz-card:has(.hz-link:focus-visible){outline:3px solid #4f46e5;outline-offset:3px}
@supports not selector(:has(*)){.hz-link:focus-visible{outline-color:#4f46e5;outline-offset:2px}}
.hz-sr{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
@media (max-width:560px){.hz-card{flex-direction:column}.hz-media{flex:none;height:150px}}
@media (prefers-reduced-motion:reduce){.hz-card{transition:none}.hz-card:hover{transform:none}}

Bootstrap 5 code

Requires: Bootstrap 5.3.8 CSS

HTML
<div class="hz-list w-100 d-flex flex-column gap-4">
  <article class="card hz-card flex-column flex-sm-row">
    <div class="hz-media hz-m1 d-flex align-items-center justify-content-center" aria-hidden="true">🎧</div>
    <div class="card-body d-flex flex-column">
      <p class="hz-kicker">Podcast · Ep. 42</p>
      <h2 class="card-title hz-title">Design systems that survive the redesign</h2>
      <p class="card-text hz-text">Why most token systems die at the first rebrand, and the three rules that kept ours alive through two.</p>
      <div class="hz-foot d-flex align-items-center mt-auto"><b>52 min</b><span>with Priya N.</span><a class="stretched-link ms-auto" href="#">Listen<span class="visually-hidden"> to Design systems that survive the redesign</span> <span aria-hidden="true">→</span></a></div>
    </div>
  </article>
  <article class="card hz-card flex-column flex-sm-row">
    <div class="hz-media hz-m2 d-flex align-items-center justify-content-center" aria-hidden="true">📈</div>
    <div class="card-body d-flex flex-column">
      <p class="hz-kicker hz-k2">Case study</p>
      <h2 class="card-title hz-title">From 4s to 800ms: a checkout story</h2>
      <p class="card-text hz-text">Every millisecond we clawed back, in order of effort — half the wins needed no JavaScript changes at all.</p>
      <div class="hz-foot d-flex align-items-center mt-auto"><b>8 min read</b><span>Engineering</span><a class="stretched-link ms-auto" href="#">Read<span class="visually-hidden"> From 4s to 800ms: a checkout story</span> <span aria-hidden="true">→</span></a></div>
    </div>
  </article>
</div>
CSS
/* Bootstrap .card laid out with .flex-column .flex-sm-row (stacks below 576px) and a .stretched-link
   in the footer, so the whole card is one link target; the focus ring is drawn on the card. */
.hz-list{max-width:620px}
.hz-card{--bs-card-border-width:0;--bs-card-border-radius:16px;--bs-card-spacer-x:24px;--bs-card-spacer-y:22px;overflow:hidden;
  box-shadow:0 1px 3px rgba(16,24,40,.06),0 14px 34px -16px rgba(16,24,40,.14);transition:transform .18s}
.hz-card:hover{transform:translateY(-4px)}
.hz-media{height:150px;font-size:3.4rem}
@media (min-width:576px){.hz-media{flex:0 0 200px;height:auto}}
.hz-m1{background:linear-gradient(140deg,#0ea5e9,#6366f1)}
.hz-m2{background:linear-gradient(140deg,#f59e0b,#ef4444)}
.hz-card .card-body{min-width:0}
.hz-kicker{font-size:.72rem;font-weight:800;letter-spacing:.08em;text-transform:uppercase;color:#4f46e5;margin:0 0 6px}
.hz-k2{color:#c2410c}
.hz-title{font-size:1.1rem;font-weight:700;line-height:normal;color:#101828;letter-spacing:-.01em;margin:0 0 6px}
.hz-text{font-size:.86rem;line-height:1.6;color:#667085;margin:0 0 14px}
.hz-foot{gap:14px;font-size:.78rem;color:#667085}
.hz-foot b{color:#344054;font-weight:600}
.hz-foot a{color:#101828;font-weight:700;font-size:.83rem;text-decoration:none;white-space:nowrap}
.hz-foot a:hover{text-decoration:underline}
.hz-foot a:focus-visible{outline:2px solid transparent}
.hz-card:has(.stretched-link:focus-visible){outline:3px solid #4f46e5;outline-offset:3px}
@supports not selector(:has(*)){.hz-foot a:focus-visible{outline-color:#4f46e5;outline-offset:2px}}
@media (prefers-reduced-motion:reduce){.hz-card{transition:none}.hz-card:hover{transform:none}}

Tailwind 4 code

Requires: Tailwind CSS 4

HTML
<div class="flex w-full flex-col items-center gap-6">
  <article class="relative flex w-full max-w-[620px] overflow-hidden rounded-2xl bg-white shadow-[0_1px_3px_rgba(16,24,40,.06),0_14px_34px_-16px_rgba(16,24,40,.14)] transition-[translate] duration-[180ms] hover:-translate-y-1 has-[a:focus-visible]:outline-3 has-[a:focus-visible]:outline-offset-3 has-[a:focus-visible]:outline-[#4f46e5] motion-reduce:transition-none motion-reduce:hover:translate-y-0 max-[560px]:flex-col">
    <div aria-hidden="true" class="flex flex-[0_0_200px] items-center justify-center bg-linear-[140deg] from-[#0ea5e9] to-[#6366f1] text-[3.4rem] max-[560px]:h-[150px] max-[560px]:flex-none">🎧</div>
    <div class="flex min-w-0 flex-col px-6 py-[22px]">
      <p class="mb-1.5 text-[.72rem] font-extrabold tracking-[.08em] text-[#4f46e5] uppercase">Podcast · Ep. 42</p>
      <h2 class="mb-1.5 text-[1.1rem] font-bold tracking-[-.01em] text-[#101828]">Design systems that survive the redesign</h2>
      <p class="mb-3.5 text-[.86rem] leading-[1.6] text-[#667085]">Why most token systems die at the first rebrand, and the three rules that kept ours alive through two.</p>
      <div class="mt-auto flex items-center gap-3.5 text-[.78rem] text-[#667085]"><b class="font-semibold text-[#344054]">52 min</b><span>with Priya N.</span><a href="#" class="ml-auto text-[.83rem] font-bold whitespace-nowrap text-[#101828] after:absolute after:inset-0 after:z-[1] hover:underline focus-visible:outline-2 focus-visible:outline-transparent">Listen<span class="sr-only"> to Design systems that survive the redesign</span> <span aria-hidden="true">→</span></a></div>
    </div>
  </article>
  <article class="relative flex w-full max-w-[620px] overflow-hidden rounded-2xl bg-white shadow-[0_1px_3px_rgba(16,24,40,.06),0_14px_34px_-16px_rgba(16,24,40,.14)] transition-[translate] duration-[180ms] hover:-translate-y-1 has-[a:focus-visible]:outline-3 has-[a:focus-visible]:outline-offset-3 has-[a:focus-visible]:outline-[#4f46e5] motion-reduce:transition-none motion-reduce:hover:translate-y-0 max-[560px]:flex-col">
    <div aria-hidden="true" class="flex flex-[0_0_200px] items-center justify-center bg-linear-[140deg] from-[#f59e0b] to-[#ef4444] text-[3.4rem] max-[560px]:h-[150px] max-[560px]:flex-none">📈</div>
    <div class="flex min-w-0 flex-col px-6 py-[22px]">
      <p class="mb-1.5 text-[.72rem] font-extrabold tracking-[.08em] text-[#c2410c] uppercase">Case study</p>
      <h2 class="mb-1.5 text-[1.1rem] font-bold tracking-[-.01em] text-[#101828]">From 4s to 800ms: a checkout story</h2>
      <p class="mb-3.5 text-[.86rem] leading-[1.6] text-[#667085]">Every millisecond we clawed back, in order of effort — half the wins needed no JavaScript changes at all.</p>
      <div class="mt-auto flex items-center gap-3.5 text-[.78rem] text-[#667085]"><b class="font-semibold text-[#344054]">8 min read</b><span>Engineering</span><a href="#" class="ml-auto text-[.83rem] font-bold whitespace-nowrap text-[#101828] after:absolute after:inset-0 after:z-[1] hover:underline focus-visible:outline-2 focus-visible:outline-transparent">Read<span class="sr-only"> From 4s to 800ms: a checkout story</span> <span aria-hidden="true">→</span></a></div>
    </div>
  </article>
</div>

About this set

Wide cards with a media panel on the left and text on the right, stacked in a column: a podcast episode and a case study. Each has a coloured kicker line, a heading, a short description and a footer with duration, a secondary detail and a Listen or Read link pushed to the right. Below 560 pixels (576 in the Bootstrap version) the media panel moves on top and the card becomes vertical. The footer link is the card’s only link and is stretched over the whole card with ::after, so clicking anywhere opens the episode or article; visually hidden text adds the item title to the link, so screen readers hear Listen to Design systems that survive the redesign rather than just Listen. Use it for podcast lists, article feeds, search results or case study indexes. The media panel is a gradient with an emoji; replace it with an img and alt text, or alt=”” if decorative. The Bootstrap version uses .card with .flex-column .flex-sm-row and .stretched-link, and Tailwind uses a max-[560px]:flex-col variant.

What’s included

  • Side-by-side media and text that stack on narrow screens
  • Footer link stretched over the card as its single link target
  • Link text completed with the item title for screen readers
  • Kicker, heading, description and meta footer
  • Hover lift that is turned off under prefers-reduced-motion

Accessibility

Each card has one link, named with the item title through visually hidden text, and the arrow is aria-hidden. While the link is focused an indigo 3px ring surrounds the card. The kicker and footer colours were darkened to pass 4.5:1, and the hover lift is disabled under prefers-reduced-motion.

Customise it

Change the media gradients in .hz-m1 and .hz-m2, the kicker colours in .hz-kicker and .hz-k2, and the stacking breakpoint in the max-width media query. In Bootstrap the stack point follows .flex-sm-row; in Tailwind change max-[560px]: and the text- utilities.