20 CSS Cards06 / 20

Pure CSSMIT licensed

Blog Post Preview Card

Blog preview tile with 16:9 cosmic thumbnail, category chip, author + date meta, and a "Read more →" link whose arrow slides on hover.

Published Updated

Live Demo
Try it

The code

<section class="card-06">
  <div class="card-06__grid">
    <header class="card-06__head">
      <div class="card-06__title-row">
        <span class="card-06__eyebrow">
          <span class="card-06__eyebrow-dot" aria-hidden="true"></span>
          THE JOURNAL
        </span>
        <h3 class="card-06__stack-h">Latest posts</h3>
      </div>
      <a href="#archive" class="card-06__archive">
        Archive
        <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>
      </a>
    </header>

    <article class="card-06__card card-06__card--hero">
      <div class="card-06__thumb">
        <img class="card-06__img" src="https://images.unsplash.com/photo-1555066931-4365d14bab8c?w=1200&q=80&auto=format&fit=crop" alt="CSS code on editor" loading="lazy" decoding="async">
        <div class="card-06__thumb-shade" aria-hidden="true"></div>
        <span class="card-06__badge">FEATURED</span>
        <span class="card-06__reading-time">
          <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>
          6 min
        </span>
      </div>
      <div class="card-06__body">
        <span class="card-06__chip">Engineering</span>
        <h3 class="card-06__title">Why Container Queries Change Everything About Responsive Design</h3>
        <p class="card-06__desc">The most-requested CSS feature is finally shipping in every browser. Here's what changes about the way we think.</p>
        <div class="card-06__meta">
          <span class="card-06__avatar" aria-hidden="true">AC</span>
          <div class="card-06__meta-text">
            <span class="card-06__author-row">
              <span class="card-06__author">Alex Chen</span>
              <svg class="card-06__verified" role="img" aria-label="Verified" width="11" height="11" viewBox="0 0 24 24" fill="none"><path d="M12 2 L14 4 L17 3 L18 6 L21 7 L20 10 L22 12 L20 14 L21 17 L18 18 L17 21 L14 20 L12 22 L10 20 L7 21 L6 18 L3 17 L4 14 L2 12 L4 10 L3 7 L6 6 L7 3 L10 4 Z" fill="#3b82f6"/><path d="M9 12 L11 14 L15 10" stroke="#fff" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"/></svg>
            </span>
            <span class="card-06__meta-info">
              <time datetime="2026-07-08">Jul 8</time>
              <span class="card-06__dot" aria-hidden="true">·</span>
              42k reads
            </span>
          </div>
          <button type="button" class="card-06__save" aria-label="Save article">
            <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z"/></svg>
          </button>
        </div>
      </div>
    </article>

    <div class="card-06__row">
      <article class="card-06__card card-06__card--sm">
        <div class="card-06__thumb card-06__thumb--sm">
          <img class="card-06__img" src="https://images.unsplash.com/photo-1558655146-9f40138edfeb?w=600&q=80&auto=format&fit=crop" alt="Design workspace" loading="lazy" decoding="async">
          <span class="card-06__reading-time card-06__reading-time--sm">4 min</span>
        </div>
        <div class="card-06__body card-06__body--sm">
          <span class="card-06__chip">Design</span>
          <h4 class="card-06__title-sm">The Case Against Perfect Loading States</h4>
          <div class="card-06__meta-sm">
            <span class="card-06__avatar card-06__avatar--sm card-06__avatar--2" aria-hidden="true">EK</span>
            <span class="card-06__author-sm">Emil Kowalski</span>
            <span class="card-06__dot" aria-hidden="true">·</span>
            <time datetime="2026-07-05">Jul 5</time>
          </div>
        </div>
      </article>

      <article class="card-06__card card-06__card--sm">
        <div class="card-06__thumb card-06__thumb--sm">
          <img class="card-06__img" src="https://images.unsplash.com/photo-1451187580459-43490279c0fa?w=600&q=80&auto=format&fit=crop" alt="Server infrastructure" loading="lazy" decoding="async">
          <span class="card-06__reading-time card-06__reading-time--sm">8 min</span>
          <span class="card-06__badge card-06__badge--new">NEW</span>
        </div>
        <div class="card-06__body card-06__body--sm">
          <span class="card-06__chip">Infrastructure</span>
          <h4 class="card-06__title-sm">Why Local-First is the Future of Web Apps</h4>
          <div class="card-06__meta-sm">
            <span class="card-06__avatar card-06__avatar--sm card-06__avatar--3" aria-hidden="true">RF</span>
            <span class="card-06__author-sm">Rauno Freiberg</span>
            <span class="card-06__dot" aria-hidden="true">·</span>
            <time datetime="2026-07-08">Today</time>
          </div>
        </div>
      </article>
    </div>
  </div>
</section>
.card-06 {
  width: 100%;
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(28px, 5vw, 56px) clamp(20px, 4vw, 40px);
  box-sizing: border-box;
  background: radial-gradient(ellipse at 20% 20%, rgba(99, 102, 241, 0.05) 0%, transparent 50%), radial-gradient(ellipse at 80% 80%, rgba(236, 72, 153, 0.04) 0%, transparent 50%), #f5f4f0;
  font-family: 'Inter', system-ui, sans-serif;
  --focus: #6366f1;
}

.card-06 *,
.card-06 *::before,
.card-06 *::after {
  box-sizing: border-box;
}

.card-06__grid {
  width: 100%;
  max-width: 720px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
/* ── head ── */

.card-06__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 0 4px;
}

.card-06__title-row {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.card-06__eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-family: ui-monospace, 'JetBrains Mono', Menlo, monospace;
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.16em;
  color: #6366f1;
}

.card-06__eyebrow-dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: #ec4899;
  box-shadow: 0 0 8px rgba(236, 72, 153, 0.5);
  animation: card-06-pulse 2s ease-in-out infinite;
}

.card-06__stack-h {
  font-size: 20px;
  font-weight: 800;
  color: #1a1a1a;
  margin: 0;
  letter-spacing: -0.025em;
  background: linear-gradient(180deg, #1a1a1a 0%, #4b4b57 130%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}

.card-06__archive {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 12px;
  font-weight: 700;
  color: #4b4b57;
  text-decoration: none;
  padding: 6px 10px;
  border-radius: 8px;
  transition: color 0.18s, background 0.18s;
}

.card-06__archive:hover {
  color: #1a1a1a;
  background: rgba(0, 0, 0, 0.04);
}

.card-06__archive:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}
/* ── hero card (full-width) ── */

.card-06__card {
  background: #fff;
  border: 1px solid rgba(0, 0, 0, 0.05);
  border-radius: 20px;
  overflow: hidden;
  box-shadow: 0 12px 30px -18px rgba(80, 40, 100, 0.15), 0 0 0 1px rgba(255, 255, 255, 0.5) inset;
  transition: transform 0.35s ease, box-shadow 0.35s, border-color 0.35s;
}

.card-06__card:hover {
  transform: translateY(-3px);
  border-color: rgba(99, 102, 241, 0.2);
  box-shadow: 0 26px 44px -18px rgba(80, 40, 100, 0.22), 0 0 0 1px rgba(255, 255, 255, 0.5) inset;
}

.card-06__card--hero {
  display: grid;
  grid-template-columns: 240px 1fr;
}
/* ── thumb ── */

.card-06__thumb {
  position: relative;
  overflow: hidden;
  background: #1a1a1a;
}

.card-06__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 0.5s ease;
}

.card-06__card:hover .card-06__img {
  transform: scale(1.06);
}

.card-06__thumb-shade {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, transparent 0%, rgba(0, 0, 0, 0.35) 100%);
  pointer-events: none;
}

.card-06__badge {
  position: absolute;
  top: 10px;
  left: 10px;
  padding: 3px 8px;
  background: linear-gradient(180deg, #fef3c7 0%, #fde68a 100%);
  color: #78350f;
  font-family: ui-monospace, 'JetBrains Mono', Menlo, monospace;
  font-size: 9px;
  font-weight: 800;
  letter-spacing: 0.14em;
  border-radius: 5px;
  border: 1px solid rgba(146, 64, 14, 0.2);
  box-shadow: 0 2px 5px rgba(245, 158, 11, 0.25);
}

.card-06__badge--new {
  background: rgba(220, 38, 38, 0.9);
  color: #fff;
  border-color: rgba(255, 255, 255, 0.14);
  box-shadow: 0 2px 5px rgba(220, 38, 38, 0.3);
}

.card-06__reading-time {
  position: absolute;
  bottom: 10px;
  right: 10px;
  display: inline-flex;
  align-items: center;
  gap: 3px;
  padding: 3px 7px;
  background: rgba(0, 0, 0, 0.55);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  color: #fff;
  font-size: 10px;
  font-weight: 700;
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: 5px;
  letter-spacing: 0.02em;
}

.card-06__reading-time--sm {
  padding: 2px 6px;
  font-size: 9px;
}
/* ── body ── */

.card-06__body {
  padding: 20px 24px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  justify-content: center;
}

.card-06__chip {
  align-self: flex-start;
  font-family: ui-monospace, 'JetBrains Mono', Menlo, monospace;
  font-size: 9.5px;
  font-weight: 800;
  letter-spacing: 0.14em;
  color: #4338ca;
  padding: 3px 9px;
  background: rgba(99, 102, 241, 0.08);
  border: 1px solid rgba(99, 102, 241, 0.16);
  border-radius: 999px;
  text-transform: uppercase;
}

.card-06__title {
  font-size: 17px;
  font-weight: 800;
  color: #1a1a1a;
  margin: 0;
  letter-spacing: -0.02em;
  line-height: 1.3;
  background: linear-gradient(180deg, #1a1a1a 0%, #4b4b57 130%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}

.card-06__desc {
  font-size: 12.5px;
  color: #6b6b7c;
  margin: 0;
  line-height: 1.5;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
/* ── meta ── */

.card-06__meta {
  display: grid;
  grid-template-columns: 30px 1fr auto;
  gap: 8px;
  align-items: center;
  margin-top: 6px;
  padding-top: 10px;
  border-top: 1px dashed rgba(0, 0, 0, 0.08);
}

.card-06__avatar {
  width: 30px;
  height: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: linear-gradient(135deg, #6366f1, #ec4899);
  color: #fff;
  font-size: 10.5px;
  font-weight: 800;
  border: 1.5px solid #fff;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
  letter-spacing: -0.01em;
}

.card-06__avatar--2 {
  background: linear-gradient(135deg, #67e8f9, #0891b2);
}

.card-06__avatar--3 {
  background: linear-gradient(135deg, #fdba74, #ea580c);
}

.card-06__meta-text {
  display: flex;
  flex-direction: column;
  gap: 0;
  min-width: 0;
}

.card-06__author-row {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

.card-06__author {
  font-size: 12px;
  font-weight: 700;
  color: #1a1a1a;
  letter-spacing: -0.005em;
}

.card-06__verified {
  flex-shrink: 0;
}

.card-06__meta-info {
  font-size: 10.5px;
  color: #9ca3af;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-variant-numeric: tabular-nums;
}

.card-06__dot {
  color: #cbd5e1;
}

.card-06__save {
  width: 30px;
  height: 30px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 1px solid rgba(0, 0, 0, 0.06);
  border-radius: 8px;
  color: #6b6b7c;
  cursor: pointer;
  transition: color 0.18s, background 0.18s, border-color 0.18s, transform 0.18s;
}

.card-06__save:hover {
  color: #6366f1;
  background: rgba(99, 102, 241, 0.06);
  border-color: rgba(99, 102, 241, 0.24);
  transform: translateY(-1px);
}

.card-06__save:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}
/* ── row of two small cards ── */

.card-06__row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
}

.card-06__card--sm {
  display: flex;
  flex-direction: column;
}

.card-06__thumb--sm {
  height: 130px;
}

.card-06__body--sm {
  padding: 12px 14px;
  gap: 6px;
}

.card-06__title-sm {
  font-size: 13px;
  font-weight: 800;
  color: #1a1a1a;
  margin: 2px 0 0;
  letter-spacing: -0.015em;
  line-height: 1.3;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.card-06__meta-sm {
  display: flex;
  align-items: center;
  gap: 5px;
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px dashed rgba(0, 0, 0, 0.06);
  font-size: 10.5px;
  color: #9ca3af;
}

.card-06__avatar--sm {
  width: 22px;
  height: 22px;
  font-size: 9px;
  border-width: 1.5px;
}

.card-06__author-sm {
  font-size: 11px;
  font-weight: 700;
  color: #1a1a1a;
  letter-spacing: -0.005em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* mobile */

@media (max-width: 600px) {
  .card-06__card--hero {
    grid-template-columns: 1fr;
  }

  .card-06__card--hero .card-06__thumb {
    min-height: 160px;
  }

  .card-06__row {
    grid-template-columns: 1fr;
  }

  .card-06__head {
    flex-direction: column;
    align-items: flex-start;
  }
}

@keyframes card-06-pulse {
  0%,
    100% {
    transform: scale(1);
    opacity: 1;
  }

  50% {
    transform: scale(1.4);
    opacity: 0.7;
  }
}

@media (prefers-reduced-motion: reduce) {
  .card-06__card,
    .card-06__img,
    .card-06__save,
    .card-06__archive {
    transition: none;
  }

  .card-06__card:hover {
    transform: none;
  }

  .card-06__card:hover .card-06__img {
    transform: none;
  }

  .card-06__eyebrow-dot {
    animation: none;
  }
}
Paste this into ChatGPT, Claude, Cursor, or any coding assistant. The block below is pre-framed with everything the AI needs to integrate this demo into your project — markup, styles, scoping notes, and the source URL. Hit Copy and paste straight into your chat.
Here's a working CSS Card from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Blog Post Preview Card
Source: https://codefronts.com/components/css-cards/blog-post-preview-card/

Blog preview tile with 16:9 cosmic thumbnail, category chip, author + date meta, and a "Read more →" link whose arrow slides on hover.
## HTML
```html
<section class="card-06">
  <div class="card-06__grid">
    <header class="card-06__head">
      <div class="card-06__title-row">
        <span class="card-06__eyebrow">
          <span class="card-06__eyebrow-dot" aria-hidden="true"></span>
          THE JOURNAL
        </span>
        <h3 class="card-06__stack-h">Latest posts</h3>
      </div>
      <a href="#archive" class="card-06__archive">
        Archive
        <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>
      </a>
    </header>

    <article class="card-06__card card-06__card--hero">
      <div class="card-06__thumb">
        <img class="card-06__img" src="https://images.unsplash.com/photo-1555066931-4365d14bab8c?w=1200&q=80&auto=format&fit=crop" alt="CSS code on editor" loading="lazy" decoding="async">
        <div class="card-06__thumb-shade" aria-hidden="true"></div>
        <span class="card-06__badge">FEATURED</span>
        <span class="card-06__reading-time">
          <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>
          6 min
        </span>
      </div>
      <div class="card-06__body">
        <span class="card-06__chip">Engineering</span>
        <h3 class="card-06__title">Why Container Queries Change Everything About Responsive Design</h3>
        <p class="card-06__desc">The most-requested CSS feature is finally shipping in every browser. Here's what changes about the way we think.</p>
        <div class="card-06__meta">
          <span class="card-06__avatar" aria-hidden="true">AC</span>
          <div class="card-06__meta-text">
            <span class="card-06__author-row">
              <span class="card-06__author">Alex Chen</span>
              <svg class="card-06__verified" role="img" aria-label="Verified" width="11" height="11" viewBox="0 0 24 24" fill="none"><path d="M12 2 L14 4 L17 3 L18 6 L21 7 L20 10 L22 12 L20 14 L21 17 L18 18 L17 21 L14 20 L12 22 L10 20 L7 21 L6 18 L3 17 L4 14 L2 12 L4 10 L3 7 L6 6 L7 3 L10 4 Z" fill="#3b82f6"/><path d="M9 12 L11 14 L15 10" stroke="#fff" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"/></svg>
            </span>
            <span class="card-06__meta-info">
              <time datetime="2026-07-08">Jul 8</time>
              <span class="card-06__dot" aria-hidden="true">·</span>
              42k reads
            </span>
          </div>
          <button type="button" class="card-06__save" aria-label="Save article">
            <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z"/></svg>
          </button>
        </div>
      </div>
    </article>

    <div class="card-06__row">
      <article class="card-06__card card-06__card--sm">
        <div class="card-06__thumb card-06__thumb--sm">
          <img class="card-06__img" src="https://images.unsplash.com/photo-1558655146-9f40138edfeb?w=600&q=80&auto=format&fit=crop" alt="Design workspace" loading="lazy" decoding="async">
          <span class="card-06__reading-time card-06__reading-time--sm">4 min</span>
        </div>
        <div class="card-06__body card-06__body--sm">
          <span class="card-06__chip">Design</span>
          <h4 class="card-06__title-sm">The Case Against Perfect Loading States</h4>
          <div class="card-06__meta-sm">
            <span class="card-06__avatar card-06__avatar--sm card-06__avatar--2" aria-hidden="true">EK</span>
            <span class="card-06__author-sm">Emil Kowalski</span>
            <span class="card-06__dot" aria-hidden="true">·</span>
            <time datetime="2026-07-05">Jul 5</time>
          </div>
        </div>
      </article>

      <article class="card-06__card card-06__card--sm">
        <div class="card-06__thumb card-06__thumb--sm">
          <img class="card-06__img" src="https://images.unsplash.com/photo-1451187580459-43490279c0fa?w=600&q=80&auto=format&fit=crop" alt="Server infrastructure" loading="lazy" decoding="async">
          <span class="card-06__reading-time card-06__reading-time--sm">8 min</span>
          <span class="card-06__badge card-06__badge--new">NEW</span>
        </div>
        <div class="card-06__body card-06__body--sm">
          <span class="card-06__chip">Infrastructure</span>
          <h4 class="card-06__title-sm">Why Local-First is the Future of Web Apps</h4>
          <div class="card-06__meta-sm">
            <span class="card-06__avatar card-06__avatar--sm card-06__avatar--3" aria-hidden="true">RF</span>
            <span class="card-06__author-sm">Rauno Freiberg</span>
            <span class="card-06__dot" aria-hidden="true">·</span>
            <time datetime="2026-07-08">Today</time>
          </div>
        </div>
      </article>
    </div>
  </div>
</section>
```
## CSS
```css
.card-06 {
  width: 100%;
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(28px, 5vw, 56px) clamp(20px, 4vw, 40px);
  box-sizing: border-box;
  background: radial-gradient(ellipse at 20% 20%, rgba(99, 102, 241, 0.05) 0%, transparent 50%), radial-gradient(ellipse at 80% 80%, rgba(236, 72, 153, 0.04) 0%, transparent 50%), #f5f4f0;
  font-family: 'Inter', system-ui, sans-serif;
  --focus: #6366f1;
}

.card-06 *,
.card-06 *::before,
.card-06 *::after {
  box-sizing: border-box;
}

.card-06__grid {
  width: 100%;
  max-width: 720px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
/* ── head ── */

.card-06__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 0 4px;
}

.card-06__title-row {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.card-06__eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-family: ui-monospace, 'JetBrains Mono', Menlo, monospace;
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.16em;
  color: #6366f1;
}

.card-06__eyebrow-dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: #ec4899;
  box-shadow: 0 0 8px rgba(236, 72, 153, 0.5);
  animation: card-06-pulse 2s ease-in-out infinite;
}

.card-06__stack-h {
  font-size: 20px;
  font-weight: 800;
  color: #1a1a1a;
  margin: 0;
  letter-spacing: -0.025em;
  background: linear-gradient(180deg, #1a1a1a 0%, #4b4b57 130%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}

.card-06__archive {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 12px;
  font-weight: 700;
  color: #4b4b57;
  text-decoration: none;
  padding: 6px 10px;
  border-radius: 8px;
  transition: color 0.18s, background 0.18s;
}

.card-06__archive:hover {
  color: #1a1a1a;
  background: rgba(0, 0, 0, 0.04);
}

.card-06__archive:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}
/* ── hero card (full-width) ── */

.card-06__card {
  background: #fff;
  border: 1px solid rgba(0, 0, 0, 0.05);
  border-radius: 20px;
  overflow: hidden;
  box-shadow: 0 12px 30px -18px rgba(80, 40, 100, 0.15), 0 0 0 1px rgba(255, 255, 255, 0.5) inset;
  transition: transform 0.35s ease, box-shadow 0.35s, border-color 0.35s;
}

.card-06__card:hover {
  transform: translateY(-3px);
  border-color: rgba(99, 102, 241, 0.2);
  box-shadow: 0 26px 44px -18px rgba(80, 40, 100, 0.22), 0 0 0 1px rgba(255, 255, 255, 0.5) inset;
}

.card-06__card--hero {
  display: grid;
  grid-template-columns: 240px 1fr;
}
/* ── thumb ── */

.card-06__thumb {
  position: relative;
  overflow: hidden;
  background: #1a1a1a;
}

.card-06__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 0.5s ease;
}

.card-06__card:hover .card-06__img {
  transform: scale(1.06);
}

.card-06__thumb-shade {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, transparent 0%, rgba(0, 0, 0, 0.35) 100%);
  pointer-events: none;
}

.card-06__badge {
  position: absolute;
  top: 10px;
  left: 10px;
  padding: 3px 8px;
  background: linear-gradient(180deg, #fef3c7 0%, #fde68a 100%);
  color: #78350f;
  font-family: ui-monospace, 'JetBrains Mono', Menlo, monospace;
  font-size: 9px;
  font-weight: 800;
  letter-spacing: 0.14em;
  border-radius: 5px;
  border: 1px solid rgba(146, 64, 14, 0.2);
  box-shadow: 0 2px 5px rgba(245, 158, 11, 0.25);
}

.card-06__badge--new {
  background: rgba(220, 38, 38, 0.9);
  color: #fff;
  border-color: rgba(255, 255, 255, 0.14);
  box-shadow: 0 2px 5px rgba(220, 38, 38, 0.3);
}

.card-06__reading-time {
  position: absolute;
  bottom: 10px;
  right: 10px;
  display: inline-flex;
  align-items: center;
  gap: 3px;
  padding: 3px 7px;
  background: rgba(0, 0, 0, 0.55);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  color: #fff;
  font-size: 10px;
  font-weight: 700;
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: 5px;
  letter-spacing: 0.02em;
}

.card-06__reading-time--sm {
  padding: 2px 6px;
  font-size: 9px;
}
/* ── body ── */

.card-06__body {
  padding: 20px 24px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  justify-content: center;
}

.card-06__chip {
  align-self: flex-start;
  font-family: ui-monospace, 'JetBrains Mono', Menlo, monospace;
  font-size: 9.5px;
  font-weight: 800;
  letter-spacing: 0.14em;
  color: #4338ca;
  padding: 3px 9px;
  background: rgba(99, 102, 241, 0.08);
  border: 1px solid rgba(99, 102, 241, 0.16);
  border-radius: 999px;
  text-transform: uppercase;
}

.card-06__title {
  font-size: 17px;
  font-weight: 800;
  color: #1a1a1a;
  margin: 0;
  letter-spacing: -0.02em;
  line-height: 1.3;
  background: linear-gradient(180deg, #1a1a1a 0%, #4b4b57 130%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}

.card-06__desc {
  font-size: 12.5px;
  color: #6b6b7c;
  margin: 0;
  line-height: 1.5;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
/* ── meta ── */

.card-06__meta {
  display: grid;
  grid-template-columns: 30px 1fr auto;
  gap: 8px;
  align-items: center;
  margin-top: 6px;
  padding-top: 10px;
  border-top: 1px dashed rgba(0, 0, 0, 0.08);
}

.card-06__avatar {
  width: 30px;
  height: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: linear-gradient(135deg, #6366f1, #ec4899);
  color: #fff;
  font-size: 10.5px;
  font-weight: 800;
  border: 1.5px solid #fff;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
  letter-spacing: -0.01em;
}

.card-06__avatar--2 {
  background: linear-gradient(135deg, #67e8f9, #0891b2);
}

.card-06__avatar--3 {
  background: linear-gradient(135deg, #fdba74, #ea580c);
}

.card-06__meta-text {
  display: flex;
  flex-direction: column;
  gap: 0;
  min-width: 0;
}

.card-06__author-row {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

.card-06__author {
  font-size: 12px;
  font-weight: 700;
  color: #1a1a1a;
  letter-spacing: -0.005em;
}

.card-06__verified {
  flex-shrink: 0;
}

.card-06__meta-info {
  font-size: 10.5px;
  color: #9ca3af;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-variant-numeric: tabular-nums;
}

.card-06__dot {
  color: #cbd5e1;
}

.card-06__save {
  width: 30px;
  height: 30px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 1px solid rgba(0, 0, 0, 0.06);
  border-radius: 8px;
  color: #6b6b7c;
  cursor: pointer;
  transition: color 0.18s, background 0.18s, border-color 0.18s, transform 0.18s;
}

.card-06__save:hover {
  color: #6366f1;
  background: rgba(99, 102, 241, 0.06);
  border-color: rgba(99, 102, 241, 0.24);
  transform: translateY(-1px);
}

.card-06__save:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}
/* ── row of two small cards ── */

.card-06__row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
}

.card-06__card--sm {
  display: flex;
  flex-direction: column;
}

.card-06__thumb--sm {
  height: 130px;
}

.card-06__body--sm {
  padding: 12px 14px;
  gap: 6px;
}

.card-06__title-sm {
  font-size: 13px;
  font-weight: 800;
  color: #1a1a1a;
  margin: 2px 0 0;
  letter-spacing: -0.015em;
  line-height: 1.3;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.card-06__meta-sm {
  display: flex;
  align-items: center;
  gap: 5px;
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px dashed rgba(0, 0, 0, 0.06);
  font-size: 10.5px;
  color: #9ca3af;
}

.card-06__avatar--sm {
  width: 22px;
  height: 22px;
  font-size: 9px;
  border-width: 1.5px;
}

.card-06__author-sm {
  font-size: 11px;
  font-weight: 700;
  color: #1a1a1a;
  letter-spacing: -0.005em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* mobile */

@media (max-width: 600px) {
  .card-06__card--hero {
    grid-template-columns: 1fr;
  }

  .card-06__card--hero .card-06__thumb {
    min-height: 160px;
  }

  .card-06__row {
    grid-template-columns: 1fr;
  }

  .card-06__head {
    flex-direction: column;
    align-items: flex-start;
  }
}

@keyframes card-06-pulse {
  0%,
    100% {
    transform: scale(1);
    opacity: 1;
  }

  50% {
    transform: scale(1.4);
    opacity: 0.7;
  }
}

@media (prefers-reduced-motion: reduce) {
  .card-06__card,
    .card-06__img,
    .card-06__save,
    .card-06__archive {
    transition: none;
  }

  .card-06__card:hover {
    transform: none;
  }

  .card-06__card:hover .card-06__img {
    transform: none;
  }

  .card-06__eyebrow-dot {
    animation: none;
  }
}
```

How this works

The card-06 blog index is a hand-coded three-tile stack, not a single card, so the outer .card-06__grid uses display: flex; flex-direction: column with a 720px max-width and 14px gap. Inside, the hero .card-06__card--hero switches to display: grid with grid-template-columns: 240px 1fr so the 16:9 thumbnail column and the copy column share the same row without the child needing an explicit height, which keeps CLS at zero because layout resolves during style calc rather than after image decode.

The thumbnail wrapper is position: relative with overflow: hidden, and the image is absolutely positioned with inset: 0 plus object-fit: cover. That means the lazy/decoding="async" attributes on the semantic img tag hand painting to the browser without blocking hydration in React or Next. On hover, the card lifts with transform: translateY(-3px) and the image scales to 1.06 — both are composited transforms so INP stays comfortably under the 200ms budget even on mid-tier Android.

Below the hero, .card-06__row is a 1fr 1fr grid with the same 14px gap, and each small tile uses flex-direction: column with a fixed 130px thumbnail height so the two columns never disagree visually. The dashed border-top: 1px dashed rgba(0,0,0,0.08) on the meta row is a purely decorative rule painted by CSS, keeping the DOM copy-paste ready and framework agnostic. All animations — the card-06-pulse eyebrow dot and the hover scale — are killed inside @media (prefers-reduced-motion: reduce), satisfying WCAG 2.3.3 without runtime JavaScript.

Make it yours

  • Swap the --focus custom property from #6366f1 to your brand color; every focus ring on the hero card, the archive link, and the save button updates in a single edit because they all read from the same variable.
  • Retune the hero split by changing grid-template-columns: 240px 1fr to 1fr 1.4fr for a magazine feel, or to 200px 1fr for a denser Linear-style index. The image object-fit rule adapts automatically.
  • The FEATURED and NEW badges share a class root; add a third variant like .card-06__badge--live with a red gradient and a 1s ease-in-out infinite pulse to flag Substack-style live posts.
  • Replace the initials avatar with a real img tag inside .card-06__avatar; keep the 1.5px solid #fff border and the 135deg gradient fallback so SSR renders the ring before the image resolves.
  • Reading time pills read from static markup — wire them to a word-count utility (Vercel edge function or Next server component) that divides content length by 238 words per minute and stamps the number at build.

Gotchas — read before shipping

  • The eyebrow dot animation runs on transform: scale and opacity, both composited, so it will not trigger layout. But the pulse loops every 2s — if a user has prefers-reduced-motion: reduce the media query already kills it, satisfying WCAG 2.3.3 without any React effect hook.
  • The gradient title uses -webkit-text-fill-color: transparent with background-clip: text. Windows high-contrast mode strips the gradient and can render the text invisible — add forced-colors: active fallbacks that reset -webkit-text-fill-color to CanvasText or the hero title fails 1.4.3 contrast auditing.
  • The .card-06__desc uses -webkit-line-clamp: 2. In Vue 3 with a Suspense wrapper, the clamp calculates before the async component resolves and can visually snap when copy hydrates. Reserve height with min-height: 3em to keep CLS below the 0.1 Core Web Vitals threshold.
  • The save button is an actual button element with aria-label="Save article", but if you route it through a Next Link the click handler stops working because Link intercepts. Keep it as a real button and dispatch to your bookmarking API from an onClick handler instead of nesting inside an anchor.
  • On the 240px 1fr hero grid, if the image column drops below 320px the copy column collapses to unreadable widths before the 600px mobile media query fires. Test on iPad portrait (768px) with the parent constrained to 580px — the fallback to a stacked 1fr grid needs to kick in earlier or you fail 2.5.5 target size.
  • The featured badge sits at top: 10px; left: 10px inside an overflow: hidden wrapper. When the thumbnail loads a smaller image (say a 600px source), the badge still anchors correctly — but the reading time pill at bottom: 10px; right: 10px can overlap short titles on iOS Safari 17 where backdrop-filter: blur(6px) stacks unpredictably. Force a stacking context with isolation: isolate on the thumb.

Techniques used in this demo

Search CodeFronts

Loading…