---
id: seed:archetypes/features-grid
title: Features grid section archetypes
source_type: seed_archetype
priority: hot
---

A features section answers "what can it do" in scannable chunks. Aim for 3, 4, or 6 cards — never 5 (orphan card) or more than 9 (overwhelming). Six working archetypes:

---

**Icon + title + description (default).** Three columns on desktop, one on mobile. Each card has a small icon (24–48px), a 2–4 word title, and a 1–2 sentence description.

*Animation & Visual Details:*
- *Entrance*: Cards stagger in from translateY(30px) with fade, 0.08s delay between each (max 4 cards animate simultaneously)
- *Hover*: Card lifts with translateY(-4px), shadow deepens; icon color shifts to accent; subtle radial glow appears behind the card
- *Gradients*: Icon has gradient fill (accent colors); card hover shows radial gradient overlay at 4% opacity
- *Radial circles*: Small radial orb (40px) positioned behind each card's icon, animates opacity on hover
- *Scroll trigger*: IntersectionObserver at 15% threshold triggers stagger animation; each card beyond the viewport threshold animates independently
- *JS interaction*: None for base variant — pure CSS hover and IntersectionObserver entrance

```html
<section data-amb-section="features" class="features-section">
  <div class="container">
    <div class="features-header">
      <h2 class="features-title">{outcome-led headline, not "Features"}</h2>
      <p class="features-subtitle">{the throughline tying the cards together}</p>
    </div>
    <div class="features-grid">
      <article class="feature-card">
        <div class="feature-icon-wrapper">
          <div class="feature-icon-glow"></div>
          <svg class="feature-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
            <path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z"/>
          </svg>
        </div>
        <h3 class="feature-heading">{capability in 2–4 words}</h3>
        <p class="feature-text">{the user benefit, not the technical detail, 1–2 sentences}</p>
      </article>
      <article class="feature-card">
        <div class="feature-icon-wrapper">
          <div class="feature-icon-glow"></div>
          <svg class="feature-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
            <circle cx="12" cy="12" r="10"/>
            <polyline points="12 6 12 12 16 14"/>
          </svg>
        </div>
        <h3 class="feature-heading">{capability in 2–4 words}</h3>
        <p class="feature-text">{the user benefit, not the technical detail, 1–2 sentences}</p>
      </article>
      <article class="feature-card">
        <div class="feature-icon-wrapper">
          <div class="feature-icon-glow"></div>
          <svg class="feature-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
            <path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/>
          </svg>
        </div>
        <h3 class="feature-heading">{capability in 2–4 words}</h3>
        <p class="feature-text">{the user benefit, not the technical detail, 1–2 sentences}</p>
      </article>
    </div>
  </div>
</section>
```

```css
:root {
  --feature-enter-duration: 0.5s;
  --feature-stagger-delay: 0.08s;
  --feature-icon-size: 40px;
  --feature-glow-size: 60px;
}

.features-section {
  padding: clamp(64px, 8vw, 100px) 0;
}

.features-header {
  text-align: center;
  max-width: 600px;
  margin: 0 auto clamp(40px, 5vw, 60px);
}

.features-title {
  font-size: clamp(1.75rem, 3.5vw, 2.5rem);
  font-weight: 700;
  color: var(--color-text, #1e293b);
}

.features-subtitle {
  font-size: clamp(1rem, 1.5vw, 1.15rem);
  color: var(--color-text-muted, #64748b);
  margin-top: 12px;
}

.features-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 24px;
}

.feature-card {
  position: relative;
  padding: 28px;
  background: #fff;
  border-radius: 16px;
  border: 1px solid #f1f5f9;
  opacity: 0;
  transform: translateY(24px);
  transition: transform 0.3s ease, box-shadow 0.3s ease, border-color 0.3s ease;
}

.feature-card.is-visible {
  animation: feature-enter var(--feature-enter-duration) ease-out forwards;
}

.feature-card:nth-child(1).is-visible { animation-delay: 0s; }
.feature-card:nth-child(2).is-visible { animation-delay: var(--feature-stagger-delay); }
.feature-card:nth-child(3).is-visible { animation-delay: calc(var(--feature-stagger-delay) * 2); }
.feature-card:nth-child(4).is-visible { animation-delay: calc(var(--feature-stagger-delay) * 3); }
.feature-card:nth-child(5).is-visible { animation-delay: calc(var(--feature-stagger-delay) * 4); }
.feature-card:nth-child(6).is-visible { animation-delay: calc(var(--feature-stagger-delay) * 5); }

@keyframes feature-enter {
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.feature-card:hover {
  transform: translateY(-4px);
  box-shadow: 0 12px 32px rgba(0,0,0,0.08);
  border-color: #e2e8f0;
}

.feature-card:hover .feature-icon {
  color: var(--color-accent, #6366f1);
}

.feature-card:hover .feature-icon-glow {
  opacity: 1;
}

.feature-icon-wrapper {
  position: relative;
  width: var(--feature-icon-size);
  height: var(--feature-icon-size);
  margin-bottom: 16px;
}

.feature-icon-glow {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: var(--feature-glow-size);
  height: var(--feature-glow-size);
  background: radial-gradient(circle, rgba(99,102,241,0.15) 0%, transparent 70%);
  opacity: 0;
  transition: opacity 0.3s ease;
  pointer-events: none;
  z-index: 0;
}

.feature-icon {
  position: relative;
  z-index: 1;
  width: var(--feature-icon-size);
  height: var(--feature-icon-size);
  color: var(--color-text, #1e293b);
  transition: color 0.2s ease;
}

.feature-heading {
  font-size: 1.1rem;
  font-weight: 600;
  color: var(--color-text, #1e293b);
  margin-bottom: 8px;
}

.feature-text {
  font-size: 0.95rem;
  color: var(--color-text-muted, #64748b);
  line-height: 1.6;
}

@media (prefers-reduced-motion: reduce) {
  .feature-card {
    opacity: 1;
    transform: none;
  }
  .feature-icon-glow {
    opacity: 0;
  }
}
```

*JS behavior:*
```javascript
const cards = document.querySelectorAll('.feature-card');
const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      entry.target.classList.add('is-visible');
      observer.unobserve(entry.target);
    }
  });
}, { threshold: 0.15, rootMargin: '0px 0px -50px 0px' });
cards.forEach(card => observer.observe(card));
```

---

**Alternating row layout.** Each feature gets its own row with text on one side and a screenshot/illustration on the other; rows alternate left/right to create visual rhythm. Use when each feature is substantial enough to warrant its own product shot.

*Animation & Visual Details:*
- *Entrance*: Text column fades in from its side (left rows from left, right rows from right); image follows at 0.15s stagger
- *Hover*: Image has subtle parallax offset (±8px) tracking cursor position; text fades slightly (0.9 opacity)
- *Gradients*: Image has a subtle radial gradient overlay at the bottom for depth
- *Radial circles*: Radial glow behind each image (accent color at 8% opacity)
- *Scroll trigger*: Each row triggers independently; image animates at 0.2s delay after text
- *JS interaction*: Cursor-tracking parallax on images (desktop only, disabled on touch devices)

```html
<section data-amb-section="features" class="features-section features-section--alternating">
  <div class="container">
    <h2 class="features-title">{outcome-led headline}</h2>
    <div class="features-rows">
      <article class="feature-row">
        <div class="feature-row-content">
          <span class="feature-row-eyebrow">Feature 01</span>
          <h3 class="feature-row-title">{capability in 2–4 words}</h3>
          <p class="feature-row-text">{the user benefit, not the technical detail, 1–2 sentences}</p>
        </div>
        <div class="feature-row-media">
          <div class="feature-row-image-glow"></div>
          <img class="feature-row-image" src="https://placehold.co/640x400" alt="Feature screenshot" />
        </div>
      </article>
      <article class="feature-row feature-row--reverse">
        <div class="feature-row-content">
          <span class="feature-row-eyebrow">Feature 02</span>
          <h3 class="feature-row-title">{capability in 2–4 words}</h3>
          <p class="feature-row-text">{the user benefit, not the technical detail, 1–2 sentences}</p>
        </div>
        <div class="feature-row-media">
          <div class="feature-row-image-glow"></div>
          <img class="feature-row-image" src="https://placehold.co/640x400" alt="Feature screenshot" />
        </div>
      </article>
      <article class="feature-row">
        <div class="feature-row-content">
          <span class="feature-row-eyebrow">Feature 03</span>
          <h3 class="feature-row-title">{capability in 2–4 words}</h3>
          <p class="feature-row-text">{the user benefit, not the technical detail, 1–2 sentences}</p>
        </div>
        <div class="feature-row-media">
          <div class="feature-row-image-glow"></div>
          <img class="feature-row-image" src="https://placehold.co/640x400" alt="Feature screenshot" />
        </div>
      </article>
    </div>
  </div>
</section>
```

```css
.features-section--alternating {
  padding: clamp(64px, 8vw, 100px) 0;
  background: var(--color-bg-alt, #f8fafc);
}

.feature-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(40px, 6vw, 80px);
  align-items: center;
  margin-bottom: clamp(48px, 7vw, 80px);
}

.feature-row:last-child {
  margin-bottom: 0;
}

.feature-row--reverse {
  direction: rtl;
}

.feature-row--reverse > * {
  direction: ltr;
}

.feature-row-content {
  opacity: 0;
  transform: translateX(-40px);
  transition: opacity 0.6s ease, transform 0.6s ease;
}

.feature-row--reverse .feature-row-content {
  transform: translateX(40px);
}

.feature-row-media {
  position: relative;
  opacity: 0;
  transform: translateX(40px);
  transition: opacity 0.6s ease, transform 0.6s ease;
  transition-delay: 0.15s;
}

.feature-row--reverse .feature-row-media {
  transform: translateX(-40px);
}

.feature-row.is-visible .feature-row-content,
.feature-row.is-visible .feature-row-media {
  opacity: 1;
  transform: translateX(0);
}

.feature-row-image-glow {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 80%;
  height: 80%;
  background: radial-gradient(ellipse, rgba(99,102,241,0.08) 0%, transparent 70%);
  pointer-events: none;
  z-index: 0;
}

.feature-row-image {
  position: relative;
  z-index: 1;
  width: 100%;
  height: auto;
  border-radius: 16px;
  box-shadow: 0 8px 32px rgba(0,0,0,0.1);
  transition: transform 0.3s ease;
}

.feature-row-eyebrow {
  display: inline-block;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--color-accent, #6366f1);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  margin-bottom: 12px;
}

.feature-row-title {
  font-size: clamp(1.5rem, 3vw, 2rem);
  font-weight: 700;
  color: var(--color-text, #1e293b);
  margin-bottom: 16px;
}

.feature-row-text {
  font-size: 1.05rem;
  color: var(--color-text-muted, #64748b);
  line-height: 1.7;
}

@media (max-width: 768px) {
  .feature-row {
    grid-template-columns: 1fr;
    gap: 32px;
  }
  .feature-row--reverse {
    direction: ltr;
  }
}

@media (prefers-reduced-motion: reduce) {
  .feature-row-content,
  .feature-row-media {
    opacity: 1;
    transform: none;
    transition: none;
  }
}
```

*JS behavior:*
```javascript
const rows = document.querySelectorAll('.feature-row');
const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      entry.target.classList.add('is-visible');
      observer.unobserve(entry.target);
    }
  });
}, { threshold: 0.2 });
rows.forEach(row => observer.observe(row));

// Cursor parallax on images (desktop only)
if (window.matchMedia('(hover: hover)').matches) {
  const images = document.querySelectorAll('.feature-row-image');
  images.forEach(img => {
    img.addEventListener('mousemove', (e) => {
      const rect = img.getBoundingClientRect();
      const x = (e.clientX - rect.left) / rect.width - 0.5;
      const y = (e.clientY - rect.top) / rect.height - 0.5;
      img.style.transform = `translate(${x * 8}px, ${y * 8}px)`;
    });
    img.addEventListener('mouseleave', () => {
      img.style.transform = '';
    });
  });
}
```

---

**Compact list with check marks.** Two-column ul of checkmarked feature names. Use as a follow-up to a card grid, or in pricing comparisons.

*Animation & Visual Details:*
- *Entrance*: List items stagger in from left with opacity 0 → 1, 0.05s delay per item
- *Hover*: Check icon scales to 1.2 and color shifts to accent; item background gets subtle tint
- *Gradients*: Check icon uses gradient fill (accent to accent-secondary)
- *Radial circles*: Small radial dot behind each check icon (accent color at 6% opacity)
- *Scroll trigger*: IntersectionObserver stagger on list items
- *JS interaction*: None for base — CSS-only hover

```html
<section data-amb-section="features" class="features-section features-section--list">
  <div class="container">
    <div class="features-list-wrapper">
      <div class="features-list-col">
        <ul class="features-list">
          <li class="features-list-item">
            <span class="features-list-check">
              <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
                <polyline points="20 6 9 17 4 12"/>
              </svg>
            </span>
            <span class="features-list-text">{feature name in noun phrase}</span>
          </li>
          <li class="features-list-item">
            <span class="features-list-check">
              <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
                <polyline points="20 6 9 17 4 12"/>
              </svg>
            </span>
            <span class="features-list-text">{feature name in noun phrase}</span>
          </li>
          <li class="features-list-item">
            <span class="features-list-check">
              <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
                <polyline points="20 6 9 17 4 12"/>
              </svg>
            </span>
            <span class="features-list-text">{feature name in noun phrase}</span>
          </li>
        </ul>
      </div>
      <div class="features-list-col">
        <ul class="features-list">
          <li class="features-list-item">
            <span class="features-list-check">
              <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
                <polyline points="20 6 9 17 4 12"/>
              </svg>
            </span>
            <span class="features-list-text">{feature name in noun phrase}</span>
          </li>
          <li class="features-list-item">
            <span class="features-list-check">
              <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
                <polyline points="20 6 9 17 4 12"/>
              </svg>
            </span>
            <span class="features-list-text">{feature name in noun phrase}</span>
          </li>
          <li class="features-list-item">
            <span class="features-list-check">
              <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
                <polyline points="20 6 9 17 4 12"/>
              </svg>
            </span>
            <span class="features-list-text">{feature name in noun phrase}</span>
          </li>
        </ul>
      </div>
    </div>
  </div>
</section>
```

```css
.features-section--list {
  padding: clamp(48px, 6vw, 72px) 0;
}

.features-list-wrapper {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(24px, 4vw, 48px);
  max-width: 800px;
  margin: 0 auto;
}

.features-list {
  list-style: none;
  padding: 0;
  margin: 0;
}

.features-list-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 0;
  border-bottom: 1px solid #f1f5f9;
  opacity: 0;
  transform: translateX(-16px);
  transition: background 0.2s ease;
}

.features-list-item.is-visible {
  animation: list-item-enter 0.4s ease-out forwards;
}

.features-list-item:nth-child(1).is-visible { animation-delay: 0s; }
.features-list-item:nth-child(2).is-visible { animation-delay: 0.05s; }
.features-list-item:nth-child(3).is-visible { animation-delay: 0.1s; }
.features-list-item:nth-child(4).is-visible { animation-delay: 0.15s; }
.features-list-item:nth-child(5).is-visible { animation-delay: 0.2s; }
.features-list-item:nth-child(6).is-visible { animation-delay: 0.25s; }

@keyframes list-item-enter {
  to {
    opacity: 1;
    transform: translateX(0);
  }
}

.features-list-item:hover {
  background: rgba(99,102,241,0.03);
  border-radius: 8px;
  padding-left: 8px;
  margin-left: -8px;
}

.features-list-check {
  position: relative;
  flex-shrink: 0;
  width: 24px;
  height: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.features-list-check::before {
  content: '';
  position: absolute;
  width: 32px;
  height: 32px;
  background: radial-gradient(circle, rgba(99,102,241,0.06) 0%, transparent 70%);
  border-radius: 50%;
}

.features-list-check svg {
  position: relative;
  z-index: 1;
  width: 18px;
  height: 18px;
  color: var(--color-accent, #6366f1);
  transition: transform 0.2s ease;
}

.features-list-item:hover .features-list-check svg {
  transform: scale(1.15);
}

.features-list-text {
  font-size: 0.95rem;
  color: var(--color-text, #1e293b);
  font-weight: 500;
}

@media (max-width: 640px) {
  .features-list-wrapper {
    grid-template-columns: 1fr;
  }
}

@media (prefers-reduced-motion: reduce) {
  .features-list-item {
    opacity: 1;
    transform: none;
  }
}
```

---

**Glassmorphism feature cards.** Frosted glass effect with backdrop-blur, radial gradient glow, and transparent borders.

*Animation & Visual Details:*
- *Entrance*: Cards fade in with scale 0.96 → 1, staggered at 0.1s intervals
- *Hover*: Radial glow intensifies (opacity 0.15 → 0.3) and card lifts slightly; icon has pulsing glow ring
- *Gradients*: Card background is gradient (white at 60% opacity → transparent); radial glow uses accent color
- *Radial circles*: Each card has a radial orb behind the icon area; orbs pulse at 2s interval
- *Scroll trigger*: IntersectionObserver with 20% threshold; cards animate in a wave pattern
- *JS interaction*: None beyond entrance trigger

```html
<section data-amb-section="features" class="features-section features-section--glass">
  <div class="container">
    <div class="features-header">
      <h2 class="features-title">{outcome-led headline}</h2>
      <p class="features-subtitle">{the throughline tying the cards together}</p>
    </div>
    <div class="features-grid features-grid--glass">
      <article class="feature-card feature-card--glass">
        <div class="feature-card-glow"></div>
        <div class="feature-icon-wrapper">
          <div class="feature-icon-ring"></div>
          <svg class="feature-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
            <path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/>
          </svg>
        </div>
        <h3 class="feature-heading">{capability}</h3>
        <p class="feature-text">{benefit description}</p>
      </article>
      <article class="feature-card feature-card--glass">
        <div class="feature-card-glow"></div>
        <div class="feature-icon-wrapper">
          <div class="feature-icon-ring"></div>
          <svg class="feature-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
            <path d="M12 2L2 7l10 5 10-5-10-5z"/>
            <path d="M2 17l10 5 10-5"/>
            <path d="M2 12l10 5 10-5"/>
          </svg>
        </div>
        <h3 class="feature-heading">{capability}</h3>
        <p class="feature-text">{benefit description}</p>
      </article>
      <article class="feature-card feature-card--glass">
        <div class="feature-card-glow"></div>
        <div class="feature-icon-wrapper">
          <div class="feature-icon-ring"></div>
          <svg class="feature-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
            <circle cx="12" cy="12" r="3"/>
            <path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/>
          </svg>
        </div>
        <h3 class="feature-heading">{capability}</h3>
        <p class="feature-text">{benefit description}</p>
      </article>
    </div>
  </div>
</section>
```

```css
.features-section--glass {
  padding: clamp(64px, 8vw, 100px) 0;
  background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
}

.features-section--glass .features-title,
.features-section--glass .features-subtitle {
  color: #fff;
}

.features-section--glass .features-subtitle {
  color: rgba(255,255,255,0.7);
}

.features-grid--glass {
  gap: 24px;
}

.feature-card--glass {
  position: relative;
  padding: 32px;
  background: rgba(255,255,255,0.05);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border: 1px solid rgba(255,255,255,0.1);
  border-radius: 20px;
  opacity: 0;
  transform: scale(0.96);
  transition: transform 0.3s ease, box-shadow 0.3s ease, background 0.3s ease;
}

.feature-card--glass.is-visible {
  animation: glass-card-enter 0.5s ease-out forwards;
}

@keyframes glass-card-enter {
  to {
    opacity: 1;
    transform: scale(1);
  }
}

.feature-card--glass:nth-child(1).is-visible { animation-delay: 0s; }
.feature-card--glass:nth-child(2).is-visible { animation-delay: 0.1s; }
.feature-card--glass:nth-child(3).is-visible { animation-delay: 0.2s; }
.feature-card--glass:nth-child(4).is-visible { animation-delay: 0.3s; }

.feature-card-glow {
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 120px;
  height: 80px;
  background: radial-gradient(ellipse, rgba(99,102,241,0.15) 0%, transparent 70%);
  opacity: 0.15;
  transition: opacity 0.3s ease;
  pointer-events: none;
}

.feature-card--glass:hover {
  transform: translateY(-4px);
  background: rgba(255,255,255,0.08);
  box-shadow: 0 12px 40px rgba(0,0,0,0.2);
}

.feature-card--glass:hover .feature-card-glow {
  opacity: 0.35;
}

.feature-icon-ring {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 64px;
  height: 64px;
  border-radius: 50%;
  border: 1px solid rgba(99,102,241,0.2);
  animation: ring-pulse 2s ease-in-out infinite;
}

@keyframes ring-pulse {
  0%, 100% { transform: translate(-50%, -50%) scale(1); opacity: 0.5; }
  50% { transform: translate(-50%, -50%) scale(1.1); opacity: 0.8; }
}

.feature-card--glass .feature-icon {
  color: rgba(255,255,255,0.9);
  transition: color 0.2s ease;
}

.feature-card--glass:hover .feature-icon {
  color: #fff;
}

.feature-card--glass .feature-heading {
  color: #fff;
}

.feature-card--glass .feature-text {
  color: rgba(255,255,255,0.65);
}

@media (prefers-reduced-motion: reduce) {
  .feature-card--glass {
    opacity: 1;
    transform: none;
  }
  .feature-icon-ring {
    animation: none;
  }
}
```

---

**Animated counter features.** Numbers animate on scroll-into-view with count-up effect. Each card shows a large animated number as the primary visual.

*Animation & Visual Details:*
- *Entrance*: Number counts from 0 to target value over 1.5s with easeOutQuart when card enters viewport
- *Hover*: Card lifts, number scales slightly (1.02), shadow deepens
- *Gradients*: Number uses gradient text (accent to accent-secondary)
- *Radial circles*: Radial ring behind the number pulses once on animation complete
- *Scroll trigger*: IntersectionObserver triggers the count-up animation once per session
- *JS interaction*: Full count-up animation from 0 to final value, with easing, triggered once on viewport entry

```html
<section data-amb-section="features" class="features-section features-section--counters">
  <div class="container">
    <div class="features-header">
      <h2 class="features-title">{outcome-led headline}</h2>
    </div>
    <div class="features-grid features-grid--counters">
      <article class="feature-card feature-card--counter" data-count-target="99.9" data-count-suffix="%">
        <div class="feature-counter-ring"></div>
        <div class="feature-counter-value" data-count="0">0</div>
        <div class="feature-counter-label">{metric label, 2–4 words}</div>
        <p class="feature-text">{brief benefit description}</p>
      </article>
      <article class="feature-card feature-card--counter" data-count-target="3" data-count-suffix="x">
        <div class="feature-counter-ring"></div>
        <div class="feature-counter-value" data-count="0">0</div>
        <div class="feature-counter-label">{metric label, 2–4 words}</div>
        <p class="feature-text">{brief benefit description}</p>
      </article>
      <article class="feature-card feature-card--counter" data-count-target="50" data-count-suffix="ms">
        <div class="feature-counter-ring"></div>
        <div class="feature-counter-value" data-count="0">0</div>
        <div class="feature-counter-label">{metric label, 2–4 words}</div>
        <p class="feature-text">{brief benefit description}</p>
      </article>
    </div>
  </div>
</section>
```

```css
.features-section--counters {
  padding: clamp(64px, 8vw, 100px) 0;
}

.features-grid--counters {
  grid-template-columns: repeat(3, 1fr);
  gap: 24px;
}

.feature-card--counter {
  position: relative;
  text-align: center;
  padding: 36px 24px;
  background: #fff;
  border-radius: 20px;
  border: 1px solid #f1f5f9;
  opacity: 0;
  transform: translateY(20px);
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}

.feature-card--counter.is-visible {
  animation: counter-card-enter 0.5s ease-out forwards;
}

.feature-card--counter:nth-child(1).is-visible { animation-delay: 0s; }
.feature-card--counter:nth-child(2).is-visible { animation-delay: 0.15s; }
.feature-card--counter:nth-child(3).is-visible { animation-delay: 0.3s; }

@keyframes counter-card-enter {
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.feature-card--counter:hover {
  transform: translateY(-4px);
  box-shadow: 0 12px 32px rgba(0,0,0,0.08);
}

.feature-counter-ring {
  position: absolute;
  top: 20px;
  left: 50%;
  transform: translateX(-50%);
  width: 100px;
  height: 100px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(99,102,241,0.08) 0%, transparent 70%);
  opacity: 0;
  transition: opacity 0.5s ease;
}

.feature-card--counter.is-animated .feature-counter-ring {
  opacity: 1;
  animation: ring-complete 0.6s ease-out;
}

@keyframes ring-complete {
  0% { transform: translateX(-50%) scale(0.8); opacity: 0; }
  50% { transform: translateX(-50%) scale(1.1); opacity: 1; }
  100% { transform: translateX(-50%) scale(1); opacity: 1; }
}

.feature-counter-value {
  font-size: clamp(3rem, 5vw, 4rem);
  font-weight: 700;
  line-height: 1;
  background: linear-gradient(135deg, #6366f1, #a855f7);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
  margin-bottom: 8px;
  transition: transform 0.2s ease;
}

.feature-card--counter:hover .feature-counter-value {
  transform: scale(1.02);
}

.feature-counter-label {
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--color-text, #1e293b);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin-bottom: 12px;
}

.feature-card--counter .feature-text {
  font-size: 0.9rem;
  color: var(--color-text-muted, #64748b);
}

@media (max-width: 768px) {
  .features-grid--counters {
    grid-template-columns: 1fr;
  }
}

@media (prefers-reduced-motion: reduce) {
  .feature-card--counter {
    opacity: 1;
    transform: none;
  }
  .feature-card--counter.is-animated .feature-counter-ring {
    animation: none;
    opacity: 1;
  }
}
```

*JS behavior:*
```javascript
function easeOutQuart(t) {
  return 1 - Math.pow(1 - t, 4);
}

function animateCounter(element, target, suffix, duration) {
  const start = performance.now();
  const isFloat = target % 1 !== 0;

  function update(currentTime) {
    const elapsed = currentTime - start;
    const progress = Math.min(elapsed / duration, 1);
    const eased = easeOutQuart(progress);
    const current = eased * target;

    element.textContent = isFloat ? current.toFixed(1) : Math.floor(current);
    element.dataset.count = current;

    if (progress < 1) {
      requestAnimationFrame(update);
    } else {
      element.textContent = isFloat ? target.toFixed(1) : target;
      element.dataset.count = target;
      element.closest('.feature-card--counter').classList.add('is-animated');
    }
  }

  requestAnimationFrame(update);
}

const counterCards = document.querySelectorAll('.feature-card--counter');
const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting && !entry.target.classList.contains('is-animated')) {
      const card = entry.target;
      const valueEl = card.querySelector('.feature-counter-value');
      const target = parseFloat(card.dataset.countTarget);
      const suffix = card.dataset.countSuffix || '';
      const duration = 1500;

      setTimeout(() => {
        animateCounter(valueEl, target, suffix, duration);
      }, 300);

      observer.unobserve(card);
    }
  });
}, { threshold: 0.5 });

counterCards.forEach(card => observer.observe(card));
```

---

**Gradient border feature cards.** Animated gradient border (rotating conic-gradient) on hover; card has a distinct visual edge.

*Animation & Visual Details:*
- *Entrance*: Cards fade in from below with standard stagger
- *Hover*: Gradient border animates (rotates or shifts), card lifts with shadow
- *Gradients*: Card has a border-image conic-gradient that rotates on hover (0deg → 360deg over 1s)
- *Radial circles*: Radial glow behind the card intensifies on hover (8% → 15% opacity)
- *Scroll trigger*: IntersectionObserver with 15% threshold
- *JS interaction*: Border gradient rotation triggered on mouseenter, reversed on mouseleave

```html
<section data-amb-section="features" class="features-section features-section--gradient-border">
  <div class="container">
    <div class="features-grid">
      <article class="feature-card feature-card--gradient">
        <div class="feature-card-bg-glow"></div>
        <div class="feature-card-inner">
          <svg class="feature-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
            <polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/>
          </svg>
          <h3 class="feature-heading">{capability}</h3>
          <p class="feature-text">{benefit description}</p>
        </div>
      </article>
      <article class="feature-card feature-card--gradient">
        <div class="feature-card-bg-glow"></div>
        <div class="feature-card-inner">
          <svg class="feature-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
            <path d="M18 20V10"/>
            <path d="M12 20V4"/>
            <path d="M6 20v-6"/>
          </svg>
          <h3 class="feature-heading">{capability}</h3>
          <p class="feature-text">{benefit description}</p>
        </div>
      </article>
      <article class="feature-card feature-card--gradient">
        <div class="feature-card-bg-glow"></div>
        <div class="feature-card-inner">
          <svg class="feature-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
            <path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/>
            <polyline points="22 4 12 14.01 9 11.01"/>
          </svg>
          <h3 class="feature-heading">{capability}</h3>
          <p class="feature-text">{benefit description}</p>
        </div>
      </article>
    </div>
  </div>
</section>
```

```css
.features-section--gradient-border {
  padding: clamp(64px, 8vw, 100px) 0;
}

.feature-card--gradient {
  position: relative;
  background: #fff;
  border-radius: 20px;
  padding: 2px;
  opacity: 0;
  transform: translateY(24px);
  transition: transform 0.3s ease;
}

.feature-card--gradient.is-visible {
  animation: gradient-card-enter 0.5s ease-out forwards;
}

.feature-card--gradient:nth-child(1).is-visible { animation-delay: 0s; }
.feature-card--gradient:nth-child(2).is-visible { animation-delay: 0.1s; }
.feature-card--gradient:nth-child(3).is-visible { animation-delay: 0.2s; }

@keyframes gradient-card-enter {
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.feature-card--gradient::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 22px;
  background: conic-gradient(from 0deg, #6366f1, #a855f7, #ec4899, #f59e0b, #6366f1);
  opacity: 0;
  transition: opacity 0.4s ease;
}

.feature-card--gradient.is-hovered::before {
  opacity: 1;
  animation: gradient-spin 1.5s linear infinite;
}

@keyframes gradient-spin {
  to { background: conic-gradient(from 360deg, #6366f1, #a855f7, #ec4899, #f59e0b, #6366f1); }
}

.feature-card-inner {
  position: relative;
  z-index: 1;
  height: 100%;
  padding: 32px;
  background: #fff;
  border-radius: 18px;
}

.feature-card-bg-glow {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 80%;
  height: 60%;
  background: radial-gradient(ellipse, rgba(99,102,241,0.08) 0%, transparent 70%);
  opacity: 0;
  transition: opacity 0.4s ease;
  pointer-events: none;
}

.feature-card--gradient:hover {
  transform: translateY(-4px);
}

.feature-card--gradient:hover .feature-card-bg-glow {
  opacity: 1;
}

.feature-card--gradient .feature-icon {
  width: 40px;
  height: 40px;
  color: var(--color-accent, #6366f1);
  margin-bottom: 16px;
}

.feature-card--gradient .feature-heading {
  font-size: 1.1rem;
  font-weight: 600;
  color: var(--color-text, #1e293b);
  margin-bottom: 8px;
}

.feature-card--gradient .feature-text {
  font-size: 0.95rem;
  color: var(--color-text-muted, #64748b);
  line-height: 1.6;
}

.feature-card--gradient:hover .feature-card-inner {
  background: rgba(255,255,255,0.95);
}

@media (prefers-reduced-motion: reduce) {
  .feature-card--gradient {
    opacity: 1;
    transform: none;
  }
  .feature-card--gradient::before,
  .feature-card--gradient.is-hovered::before {
    animation: none;
    opacity: 0.8;
  }
}
```

*JS behavior:*
```javascript
const gradientCards = document.querySelectorAll('.feature-card--gradient');
const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      entry.target.classList.add('is-visible');
      observer.unobserve(entry.target);
    }
  });
}, { threshold: 0.15 });

gradientCards.forEach(card => {
  observer.observe(card);
  card.addEventListener('mouseenter', () => card.classList.add('is-hovered'));
  card.addEventListener('mouseleave', () => card.classList.remove('is-hovered'));
});
```

---

Copy rules: every feature title should be a noun phrase ("Real-time collaboration"), not a verb ("Collaborate in real time"). Lead descriptions with the user outcome ("Ship faster") then explain how ("with one-click deploys"). Don't list table-stakes features ("Reliable", "Secure") — only differentiators.

Layout rules: cards in the same row must have equal height. Icon style must be consistent across all cards in one section — never mix line icons with solid icons.

CSS custom property summary:
```css
:root {
  --feature-enter-duration: 0.5s;
  --feature-stagger-delay: 0.08s;
  --feature-icon-size: 40px;
  --color-accent: #6366f1;
  --color-text: #1e293b;
  --color-text-muted: #64748b;
}
```