---
id: seed:archetypes/hero
title: Hero section archetypes
source_type: seed_archetype
priority: hot
---

A hero is the first viewport of a page. It must answer three questions inside three seconds: what is this, who is it for, what do I do next. Production heroes share eight working archetypes.

**Headline + subhead + CTA stack (default).** Single column, centered or left-aligned. One H1 expressing the core value, one paragraph clarifying the audience, one primary button plus an optional secondary link.

*Animation & Visual Details:*
- *Entrance*: Headline fades up with 0.6s ease-out on load; subhead follows at 0.15s stagger; CTA at 0.3s stagger
- *Hover*: CTA button scales to 1.03 with 200ms ease, shadow deepens; secondary link underline draws in from left
- *Gradients*: Optional radial gradient behind the CTA cluster (accent color at 8% opacity)
- *Radial circles*: Two large decorative radial rings at opposite corners (8% opacity, 400px diameter)
- *Scroll trigger*: On scroll past 100px, hero fades to 0.95 opacity with subtle translateY(20px)
- *JS interaction*: Magnetic button effect on CTA — cursor within 80px radius attracts button toward it with spring physics (damping 0.18, stiffness 200)

```html
<section data-amb-section="hero" class="hero-section">
  <div class="hero-decorative-ring hero-decorative-ring--tl"></div>
  <div class="hero-decorative-ring hero-decorative-ring--br"></div>
  <div class="container">
    <div class="hero-content">
      <h1 class="hero-title">{benefit-led headline, 6–12 words}</h1>
      <p class="hero-description">{who-it-is-for + how-it-works, one sentence}</p>
      <div class="hero-actions">
        <a class="cta-button cta-button--primary" href="#">{primary verb}</a>
        <a class="hero-link" href="#">{secondary, less commitment}</a>
      </div>
    </div>
  </div>
</section>
```

```css
:root {
  --hero-ring-size: 400px;
  --hero-ring-opacity: 0.08;
  --hero-ring-color: var(--color-accent, #6366f1);
  --hero-ring-tl-x: -100px;
  --hero-ring-tl-y: -80px;
  --hero-ring-br-x: calc(100% + 80px);
  --hero-ring-br-y: calc(100% + 60px);
  --hero-enter-duration: 0.6s;
  --hero-enter-delay-step: 0.15s;
}

.hero-section {
  position: relative;
  padding: clamp(80px, 12vw, 140px) 0 clamp(60px, 8vw, 100px);
  overflow: hidden;
}

.hero-decorative-ring {
  position: absolute;
  width: var(--hero-ring-size);
  height: var(--hero-ring-size);
  border-radius: 50%;
  background: radial-gradient(circle, var(--hero-ring-color) 0%, transparent 70%);
  opacity: var(--hero-ring-opacity);
  pointer-events: none;
  z-index: 0;
}
.hero-decorative-ring--tl {
  top: var(--hero-ring-tl-y);
  left: var(--hero-ring-tl-x);
}
.hero-decorative-ring--br {
  bottom: var(--hero-ring-br-y);
  right: var(--hero-ring-br-x);
}

.hero-content {
  position: relative;
  z-index: 1;
  max-width: 720px;
}

.hero-title {
  font-size: clamp(2.5rem, 5vw, 4rem);
  font-weight: 700;
  line-height: 1.1;
  letter-spacing: -0.02em;
  opacity: 0;
  transform: translateY(24px);
  animation: hero-enter var(--hero-enter-duration) ease-out forwards;
  animation-delay: 0.1s;
}

.hero-description {
  font-size: clamp(1.1rem, 2vw, 1.35rem);
  color: var(--color-text-muted, #64748b);
  margin-top: 20px;
  opacity: 0;
  transform: translateY(24px);
  animation: hero-enter var(--hero-enter-duration) ease-out forwards;
  animation-delay: calc(0.1s + var(--hero-enter-delay-step));
}

.hero-actions {
  display: flex;
  gap: 16px;
  align-items: center;
  margin-top: 36px;
  flex-wrap: wrap;
  opacity: 0;
  transform: translateY(24px);
  animation: hero-enter var(--hero-enter-duration) ease-out forwards;
  animation-delay: calc(0.1s + var(--hero-enter-delay-step) * 2);
}

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

@media (prefers-reduced-motion: reduce) {
  .hero-title,
  .hero-description,
  .hero-actions {
    opacity: 1;
    transform: none;
    animation: none;
  }
}
```

*JS behavior:*
```javascript
// Magnetic button effect
const magneticButtons = document.querySelectorAll('.cta-button--primary');
magneticButtons.forEach(btn => {
  btn.addEventListener('mousemove', (e) => {
    const rect = btn.getBoundingClientRect();
    const x = e.clientX - rect.left - rect.width / 2;
    const y = e.clientY - rect.top - rect.height / 2;
    const distance = Math.sqrt(x * x + y * y);
    const radius = 80;
    if (distance < radius) {
      const strength = 1 - distance / radius;
      btn.style.transform = `translate(${x * strength * 0.4}px, ${y * strength * 0.4}px) scale(1.03)`;
    } else {
      btn.style.transform = '';
    }
  });
  btn.addEventListener('mouseleave', () => {
    btn.style.transform = '';
  });
});

// Hero fade on scroll
const hero = document.querySelector('.hero-section');
window.addEventListener('scroll', () => {
  const scrollY = window.scrollY;
  if (scrollY < 100) {
    hero.style.opacity = 1 - scrollY / 1000;
    hero.style.transform = `translateY(${scrollY * 0.2}px)`;
  }
}, { passive: true });
```

---

**Split hero (50/50).** Copy left, product image or short demo right. Use when the product is visual and a screenshot does the work the copy can't.

*Animation & Visual Details:*
- *Entrance*: Content column fades in from left with translateX(-30px), image column from right with translateX(30px), 0.5s stagger
- *Hover*: Image scales to 1.02 with soft shadow lift; subtle parallax offset on image (±10px tracking cursor)
- *Gradients*: Subtle gradient overlay on the image (dark to transparent, 10% opacity at bottom)
- *Radial circles*: Radial glow behind the image at the center point between the two halves
- *Scroll trigger*: Image fades to 0.95 opacity when section scrolls past 80%
- *JS interaction*: Tilt-on-cursor effect on the image — on desktop, image tilts up to 5° tracking cursor position with spring physics

```html
<section data-amb-section="hero" class="hero-section hero-section--split">
  <div class="hero-decorative-glow"></div>
  <div class="container">
    <div class="hero-split">
      <div class="hero-split-content">
        <h1 class="hero-title">{benefit-led headline, 6–12 words}</h1>
        <p class="hero-description">{who-it-is-for + how-it-works, one sentence}</p>
        <div class="hero-actions">
          <a class="cta-button" href="#">{primary verb}</a>
          <a class="hero-link" href="#">{secondary, less commitment}</a>
        </div>
      </div>
      <div class="hero-split-media">
        <img class="hero-image" src="https://placehold.co/800x600" alt="Product screenshot" />
      </div>
    </div>
  </div>
</section>
```

```css
.hero-section--split {
  padding: clamp(60px, 10vw, 120px) 0;
}

.hero-decorative-glow {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 600px;
  height: 600px;
  background: radial-gradient(circle, rgba(99,102,241,0.12) 0%, transparent 70%);
  pointer-events: none;
  z-index: 0;
}

.hero-split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(40px, 6vw, 80px);
  align-items: center;
}

.hero-split-content {
  opacity: 0;
  transform: translateX(-30px);
  animation: hero-slide-in 0.6s ease-out forwards;
  animation-delay: 0.1s;
}

.hero-split-media {
  opacity: 0;
  transform: translateX(30px);
  animation: hero-slide-in 0.6s ease-out forwards;
  animation-delay: 0.25s;
}

.hero-image {
  width: 100%;
  height: auto;
  border-radius: 16px;
  box-shadow: 0 24px 64px rgba(0,0,0,0.12);
  transition: transform 0.3s ease, box-shadow 0.3s ease;
  transform-style: preserve-3d;
  perspective: 1000px;
}

@keyframes hero-slide-in {
  to {
    opacity: 1;
    transform: translateX(0);
  }
}

@media (max-width: 768px) {
  .hero-split {
    grid-template-columns: 1fr;
  }
  .hero-split-content {
    animation-delay: 0.1s;
  }
  .hero-split-media {
    animation-delay: 0.2s;
  }
}

@media (prefers-reduced-motion: reduce) {
  .hero-split-content,
  .hero-split-media {
    opacity: 1;
    transform: none;
    animation: none;
  }
}
```

*JS behavior:*
```javascript
// Tilt-on-cursor for hero image
const heroImage = document.querySelector('.hero-image');
if (heroImage && window.matchMedia('(hover: hover)').matches) {
  heroImage.addEventListener('mousemove', (e) => {
    const rect = heroImage.getBoundingClientRect();
    const x = (e.clientX - rect.left) / rect.width - 0.5;
    const y = (e.clientY - rect.top) / rect.height - 0.5;
    const rotateX = y * -5;
    const rotateY = x * 5;
    heroImage.style.transform = `perspective(1000px) rotateX(${rotateX}deg) rotateY(${rotateY}deg) scale(1.02)`;
  });
  heroImage.addEventListener('mouseleave', () => {
    heroImage.style.transform = '';
  });
}
```

---

**Glassmorphism hero.** Frosted glass panel floating over a colorful background. Uses backdrop-filter blur, subtle transparency, and radial gradient lighting.

*Animation & Visual Details:*
- *Entrance*: Panel slides up from translateY(40px) with fade-in, 0.7s ease-out; background shapes animate separately
- *Hover*: Panel shadow deepens and scales to 1.01; background gradient shifts toward cursor position
- *Gradients*: Multi-stop background gradient (purple → indigo → blue at 45°), panel uses transparent white with blur
- *Radial circles*: Two large radial gradient orbs (pink and cyan) float behind the glass panel, animate on mouse movement
- *Scroll trigger*: Background orbs shift position on scroll (parallax at 0.3 rate)
- *JS interaction*: Background orbs follow cursor position with spring physics (30% cursor position offset)

```html
<section data-amb-section="hero" class="hero-section hero-section--glass">
  <div class="hero-bg-layer">
    <div class="hero-orb hero-orb--pink"></div>
    <div class="hero-orb hero-orb--cyan"></div>
  </div>
  <div class="container">
    <div class="hero-glass-panel">
      <div class="hero-content">
        <h1 class="hero-title">{benefit-led headline, 6–12 words}</h1>
        <p class="hero-description">{who-it-is-for + how-it-works, one sentence}</p>
        <div class="hero-actions">
          <a class="cta-button" href="#">{primary verb}</a>
          <a class="hero-link" href="#">{secondary, less commitment}</a>
        </div>
      </div>
    </div>
  </div>
</section>
```

```css
:root {
  --glass-bg: rgba(255, 255, 255, 0.08);
  --glass-border: rgba(255, 255, 255, 0.18);
  --glass-blur: 20px;
  --orb-size: 500px;
}

.hero-section--glass {
  position: relative;
  min-height: 100vh;
  display: flex;
  align-items: center;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 50%, #6B8DD6 100%);
  overflow: hidden;
}

.hero-bg-layer {
  position: absolute;
  inset: 0;
  overflow: hidden;
  z-index: 0;
}

.hero-orb {
  position: absolute;
  border-radius: 50%;
  filter: blur(80px);
  opacity: 0.6;
  transition: transform 0.8s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}

.hero-orb--pink {
  width: var(--orb-size);
  height: var(--orb-size);
  background: radial-gradient(circle, #ff6b9d 0%, transparent 70%);
  top: -100px;
  right: -100px;
}

.hero-orb--cyan {
  width: calc(var(--orb-size) * 0.8);
  height: calc(var(--orb-size) * 0.8);
  background: radial-gradient(circle, #00d4ff 0%, transparent 70%);
  bottom: -80px;
  left: -80px;
}

.hero-glass-panel {
  position: relative;
  z-index: 1;
  max-width: 680px;
  margin: 0 auto;
  padding: 48px;
  background: var(--glass-bg);
  backdrop-filter: blur(var(--glass-blur));
  -webkit-backdrop-filter: blur(var(--glass-blur));
  border: 1px solid var(--glass-border);
  border-radius: 24px;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1), inset 0 1px 0 rgba(255,255,255,0.1);
  opacity: 0;
  transform: translateY(40px);
  animation: glass-panel-enter 0.7s ease-out forwards;
  animation-delay: 0.2s;
}

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

.hero-section--glass .hero-title,
.hero-section--glass .hero-description {
  color: #fff;
}

.hero-section--glass .hero-description {
  color: rgba(255, 255, 255, 0.75);
}

.hero-section--glass .hero-link {
  color: rgba(255, 255, 255, 0.8);
}

@media (prefers-reduced-motion: reduce) {
  .hero-glass-panel {
    opacity: 1;
    transform: none;
    animation: none;
  }
  .hero-orb {
    transition: none;
  }
}
```

*JS behavior:*
```javascript
// Orb follow cursor with spring physics
const orbs = document.querySelectorAll('.hero-orb');
let targetX = 0, targetY = 0, currentX = 0, currentY = 0;
const spring = 0.08;

document.addEventListener('mousemove', (e) => {
  targetX = (e.clientX / window.innerWidth - 0.5) * 60;
  targetY = (e.clientY / window.innerHeight - 0.5) * 60;
});

function animateOrbs() {
  currentX += (targetX - currentX) * spring;
  currentY += (targetY - currentY) * spring;
  orbs.forEach((orb, i) => {
    const factor = i === 0 ? 1 : 0.8;
    orb.style.transform = `translate(${currentX * factor}px, ${currentY * factor}px)`;
  });
  requestAnimationFrame(animateOrbs);
}
animateOrbs();
```

---

**Gradient mesh hero.** Multi-color mesh gradient background that subtly animates on scroll. Modern, dynamic, attention-grabbing without being distracting.

*Animation & Visual Details:*
- *Entrance*: Content fades up with standard stagger; background gradient starts at reduced animation state
- *Hover*: Gradient shifts slightly toward cursor position (10–15% offset)
- *Gradients*: Five-stop mesh gradient (coral, amber, emerald, cyan, violet) animated with CSS custom properties
- *Radial circles*: Radial burst points at gradient color stops, animated opacity pulse at 0.3Hz
- *Scroll trigger*: Gradient position shifts by ±5% as user scrolls through the section
- *JS interaction*: Mesh gradient positions controlled via CSS custom properties updated on scroll and mouse move

```html
<section data-amb-section="hero" class="hero-section hero-section--mesh">
  <div class="hero-mesh-bg"></div>
  <div class="hero-mesh-burst hero-mesh-burst--1"></div>
  <div class="hero-mesh-burst hero-mesh-burst--2"></div>
  <div class="hero-mesh-burst hero-mesh-burst--3"></div>
  <div class="container">
    <div class="hero-content">
      <h1 class="hero-title">{benefit-led headline, 6–12 words}</h1>
      <p class="hero-description">{who-it-is-for + how-it-works, one sentence}</p>
      <div class="hero-actions">
        <a class="cta-button" href="#">{primary verb}</a>
        <a class="hero-link" href="#">{secondary, less commitment}</a>
      </div>
    </div>
  </div>
</section>
```

```css
:root {
  --mesh-color-1: #ff6b6b;
  --mesh-color-2: #feca57;
  --mesh-color-3: #48dbfb;
  --mesh-color-4: #ff9ff3;
  --mesh-color-5: #1dd1a1;
  --mesh-pos-1: 20% 30%;
  --mesh-pos-2: 80% 20%;
  --mesh-pos-3: 60% 70%;
  --mesh-pos-4: 10% 80%;
  --mesh-pos-5: 90% 60%;
  --mesh-animate-speed: 20s;
}

.hero-section--mesh {
  position: relative;
  padding: clamp(100px, 14vw, 160px) 0 clamp(80px, 10vw, 120px);
  overflow: hidden;
}

.hero-mesh-bg {
  position: absolute;
  inset: -50%;
  background:
    radial-gradient(ellipse at var(--mesh-pos-1), var(--mesh-color-1) 0%, transparent 50%),
    radial-gradient(ellipse at var(--mesh-pos-2), var(--mesh-color-2) 0%, transparent 50%),
    radial-gradient(ellipse at var(--mesh-pos-3), var(--mesh-color-3) 0%, transparent 50%),
    radial-gradient(ellipse at var(--mesh-pos-4), var(--mesh-color-4) 0%, transparent 50%),
    radial-gradient(ellipse at var(--mesh-pos-5), var(--mesh-color-5) 0%, transparent 50%);
  animation: mesh-drift var(--mesh-animate-speed) ease-in-out infinite alternate;
  z-index: 0;
}

@keyframes mesh-drift {
  0% {
    --mesh-pos-1: 20% 30%;
    --mesh-pos-2: 80% 20%;
    --mesh-pos-3: 60% 70%;
    --mesh-pos-4: 10% 80%;
    --mesh-pos-5: 90% 60%;
  }
  100% {
    --mesh-pos-1: 25% 25%;
    --mesh-pos-2: 75% 25%;
    --mesh-pos-3: 55% 75%;
    --mesh-pos-4: 15% 75%;
    --mesh-pos-5: 85% 55%;
  }
}

.hero-mesh-burst {
  position: absolute;
  border-radius: 50%;
  pointer-events: none;
  z-index: 1;
  animation: burst-pulse 3s ease-in-out infinite;
}

.hero-mesh-burst--1 {
  width: 300px;
  height: 300px;
  top: 10%;
  left: 5%;
  background: radial-gradient(circle, rgba(255,107,107,0.15) 0%, transparent 70%);
  animation-delay: 0s;
}

.hero-mesh-burst--2 {
  width: 200px;
  height: 200px;
  top: 60%;
  right: 10%;
  background: radial-gradient(circle, rgba(72,219,251,0.12) 0%, transparent 70%);
  animation-delay: 1s;
}

.hero-mesh-burst--3 {
  width: 250px;
  height: 250px;
  bottom: 15%;
  left: 40%;
  background: radial-gradient(circle, rgba(255,159,243,0.1) 0%, transparent 70%);
  animation-delay: 2s;
}

@keyframes burst-pulse {
  0%, 100% { opacity: 0.6; transform: scale(1); }
  50% { opacity: 1; transform: scale(1.05); }
}

.hero-content {
  position: relative;
  z-index: 2;
}

@media (prefers-reduced-motion: reduce) {
  .hero-mesh-bg {
    animation: none;
  }
  .hero-mesh-burst {
    animation: none;
    opacity: 0.6;
  }
}
```

*JS behavior:*
```javascript
// Update mesh gradient on scroll
const hero = document.querySelector('.hero-section--mesh');
let scrollProgress = 0;

window.addEventListener('scroll', () => {
  const rect = hero.getBoundingClientRect();
  const viewportHeight = window.innerHeight;
  scrollProgress = Math.max(0, Math.min(1, (viewportHeight - rect.top) / (viewportHeight + rect.height)));
  const offset = (scrollProgress - 0.5) * 10;
  hero.style.setProperty('--mesh-scroll-offset', `${offset}%`);
}, { passive: true });

// Subtle cursor influence on mesh
document.addEventListener('mousemove', (e) => {
  const x = e.clientX / window.innerWidth;
  const y = e.clientY / window.innerHeight;
  hero.style.setProperty('--mesh-cursor-x', `${(x - 0.5) * 5}%`);
  hero.style.setProperty('--mesh-cursor-y', `${(y - 0.5) * 5}%`);
});
```

---

**Animated particle field hero.** Canvas-based radial circle particles that react to mouse movement. Creates depth and modern feel without heavy WebGL.

*Animation & Visual Details:*
- *Entrance*: Particles spawn in with staggered fade (0ms to 800ms across all particles)
- *Hover*: Particles within 150px radius of cursor accelerate toward cursor, then spring back; particle size increases near cursor
- *Gradients*: Each particle uses a radial gradient from solid center to transparent edge
- *Radial circles*: Each particle IS a radial circle (rendered on canvas), varying sizes from 2px to 8px radius
- *Scroll trigger*: Particle opacity reduces to 30% as section scrolls past viewport
- *JS interaction*: Full canvas particle system with mouse tracking, spring physics, and requestAnimationFrame loop

```html
<section data-amb-section="hero" class="hero-section hero-section--particles">
  <canvas class="hero-particle-canvas" aria-hidden="true"></canvas>
  <div class="container">
    <div class="hero-content">
      <h1 class="hero-title">{benefit-led headline, 6–12 words}</h1>
      <p class="hero-description">{who-it-is-for + how-it-works, one sentence}</p>
      <div class="hero-actions">
        <a class="cta-button" href="#">{primary verb}</a>
        <a class="hero-link" href="#">{secondary, less commitment}</a>
      </div>
    </div>
  </div>
</section>
```

```css
.hero-section--particles {
  position: relative;
  min-height: 100vh;
  display: flex;
  align-items: center;
  overflow: hidden;
  background: #0a0a0f;
}

.hero-particle-canvas {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}

.hero-section--particles .hero-title,
.hero-section--particles .hero-description {
  color: #fff;
  position: relative;
  z-index: 1;
}

.hero-section--particles .hero-description {
  color: rgba(255,255,255,0.7);
}

.hero-section--particles .hero-link {
  color: rgba(255,255,255,0.7);
}

.hero-section--particles .cta-button {
  background: linear-gradient(135deg, #6366f1, #8b5cf6);
  box-shadow: 0 4px 24px rgba(99,102,241,0.4);
}

.hero-section--particles .cta-button:hover {
  box-shadow: 0 8px 32px rgba(99,102,241,0.5);
}

@media (prefers-reduced-motion: reduce) {
  .hero-particle-canvas {
    display: none;
  }
}
```

*JS behavior:*
```javascript
const canvas = document.querySelector('.hero-particle-canvas');
const ctx = canvas.getContext('2d');
let particles = [];
let mouse = { x: null, y: null };
let animationId;

function resizeCanvas() {
  canvas.width = canvas.offsetWidth;
  canvas.height = canvas.offsetHeight;
}
resizeCanvas();
window.addEventListener('resize', resizeCanvas);

class Particle {
  constructor() {
    this.reset();
  }
  reset() {
    this.x = Math.random() * canvas.width;
    this.y = Math.random() * canvas.height;
    this.baseX = this.x;
    this.baseY = this.y;
    this.size = Math.random() * 6 + 2;
    this.speedX = (Math.random() - 0.5) * 0.3;
    this.speedY = (Math.random() - 0.5) * 0.3;
    this.opacity = Math.random() * 0.5 + 0.3;
    this.color = `rgba(${99 + Math.random() * 60}, ${102 + Math.random() * 60}, ${241 + Math.random() * 20}, ${this.opacity})`;
  }
  update() {
    this.baseX += this.speedX;
    this.baseY += this.speedY;
    if (this.baseX < 0 || this.baseX > canvas.width) this.speedX *= -1;
    if (this.baseY < 0 || this.baseY > canvas.height) this.speedY *= -1;

    if (mouse.x !== null) {
      const dx = mouse.x - this.x;
      const dy = mouse.y - this.y;
      const dist = Math.sqrt(dx * dx + dy * dy);
      const maxDist = 150;
      if (dist < maxDist) {
        const force = (1 - dist / maxDist) * 0.5;
        this.x += dx * force * 0.05;
        this.y += dy * force * 0.05;
      }
    }
    this.x += (this.baseX - this.x) * 0.05;
    this.y += (this.baseY - this.y) * 0.05;
  }
  draw() {
    const gradient = ctx.createRadialGradient(this.x, this.y, 0, this.x, this.y, this.size);
    gradient.addColorStop(0, this.color);
    gradient.addColorStop(1, 'transparent');
    ctx.beginPath();
    ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
    ctx.fillStyle = gradient;
    ctx.fill();
  }
}

const particleCount = Math.min(80, Math.floor(canvas.width * canvas.height / 15000));
for (let i = 0; i < particleCount; i++) {
  particles.push(new Particle());
}

canvas.addEventListener('mousemove', (e) => {
  const rect = canvas.getBoundingClientRect();
  mouse.x = e.clientX - rect.left;
  mouse.y = e.clientY - rect.top;
});
canvas.addEventListener('mouseleave', () => {
  mouse.x = null;
  mouse.y = null;
});

function animate() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  particles.forEach(p => {
    p.update();
    p.draw();
  });
  animationId = requestAnimationFrame(animate);
}
animate();

// Fade on scroll
const hero = document.querySelector('.hero-section--particles');
window.addEventListener('scroll', () => {
  const rect = hero.getBoundingClientRect();
  const opacity = Math.max(0.3, Math.min(1, 1 - (Math.abs(rect.top) / rect.height)));
  canvas.style.opacity = opacity;
}, { passive: true });
```

---

**Split video hero.** Video on the right side with gradient overlay on the left. Video autoplays muted, with play/pause toggle.

*Animation & Visual Details:*
- *Entrance*: Content left side fades in from left (0.4s), video right side fades in from right (0.6s, 0.15s delay)
- *Hover*: Video shows a subtle play icon overlay on hover; gradient overlay on left shifts slightly
- *Gradients*: Left panel uses gradient overlay (dark at bottom 30%, transparent at top) so content is readable over the video
- *Radial circles*: Radial glow behind the play button, pulsing at 0.5Hz when paused
- *Scroll trigger*: Video opacity fades to 0.7 when section is 60% scrolled past
- *JS interaction*: Play/pause toggle with smooth opacity transition; video prefetched on link hover

```html
<section data-amb-section="hero" class="hero-section hero-section--video">
  <div class="hero-split">
    <div class="hero-split-content">
      <h1 class="hero-title">{benefit-led headline, 6–12 words}</h1>
      <p class="hero-description">{who-it-is-for + how-it-works, one sentence}</p>
      <div class="hero-actions">
        <a class="cta-button" href="#">{primary verb}</a>
        <a class="hero-link" href="#">{secondary, less commitment}</a>
      </div>
    </div>
    <div class="hero-split-media">
      <div class="hero-video-wrapper">
        <video class="hero-video" src="https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4" autoplay muted loop playsinline></video>
        <div class="hero-video-overlay"></div>
        <button class="hero-video-toggle" aria-label="Pause video">
          <svg class="icon-play" viewBox="0 0 24 24" fill="currentColor"><path d="M8 5v14l11-7z"/></svg>
          <svg class="icon-pause" viewBox="0 0 24 24" fill="currentColor" style="display:none"><path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/></svg>
        </button>
      </div>
    </div>
  </div>
</section>
```

```css
.hero-section--video {
  padding: clamp(60px, 8vw, 100px) 0;
  background: linear-gradient(135deg, #0f0f1a 0%, #1a1a2e 100%);
}

.hero-split-media {
  position: relative;
}

.hero-video-wrapper {
  position: relative;
  border-radius: 16px;
  overflow: hidden;
  box-shadow: 0 24px 64px rgba(0,0,0,0.3);
}

.hero-video {
  width: 100%;
  height: auto;
  display: block;
}

.hero-video-overlay {
  position: absolute;
  inset: 0;
  background: linear-gradient(to right, rgba(15,15,26,0.4) 0%, transparent 30%);
  pointer-events: none;
}

.hero-video-toggle {
  position: absolute;
  bottom: 20px;
  right: 20px;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  background: rgba(255,255,255,0.15);
  backdrop-filter: blur(8px);
  border: 1px solid rgba(255,255,255,0.2);
  color: #fff;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: transform 0.2s ease, background 0.2s ease;
}

.hero-video-toggle:hover {
  transform: scale(1.1);
  background: rgba(255,255,255,0.25);
}

.hero-video-toggle svg {
  width: 20px;
  height: 20px;
}
```

*JS behavior:*
```javascript
const video = document.querySelector('.hero-video');
const toggleBtn = document.querySelector('.hero-video-toggle');
const playIcon = toggleBtn.querySelector('.icon-play');
const pauseIcon = toggleBtn.querySelector('.icon-pause');

toggleBtn.addEventListener('click', () => {
  if (video.paused) {
    video.play();
    playIcon.style.display = 'none';
    pauseIcon.style.display = 'block';
  } else {
    video.pause();
    playIcon.style.display = 'block';
    pauseIcon.style.display = 'none';
  }
});

// Prefetch video on CTA hover
document.querySelector('.hero-section--video .cta-button').addEventListener('mouseenter', () => {
  const link = document.createElement('link');
  link.rel = 'prefetch';
  link.href = video.src;
  document.head.appendChild(link);
});

// Scroll-based fade
window.addEventListener('scroll', () => {
  const wrapper = document.querySelector('.hero-video-wrapper');
  const rect = wrapper.getBoundingClientRect();
  const visibility = Math.max(0.7, Math.min(1, (window.innerHeight - rect.top) / (window.innerHeight * 0.6)));
  wrapper.style.opacity = visibility;
}, { passive: true });
```

---

**Minimal clean hero.** Whitespace-heavy, typography-focused. Content fades in on load with subtle translateY. No decorative elements except two small radial accent dots.

*Animation & Visual Details:*
- *Entrance*: Headline enters with a slow, confident fade-up (0.8s ease-out). Subhead follows at 0.2s delay. CTA at 0.4s delay. Everything calm and measured.
- *Hover*: CTA button has a subtle underline draw (width 0% → 100% in 0.3s). No scale, no glow — restraint is the aesthetic.
- *Gradients*: None on the background. CTA button uses a subtle linear gradient (accent to accent-hover).
- *Radial circles*: Two small radial dots (8px diameter, 12% opacity) positioned near the CTA as a subtle accent.
- *Scroll trigger*: On scroll, hero content translates down slightly (parallax at 0.2 rate) and fades to 0.9 opacity.
- *JS interaction*: Scroll-linked parallax, no heavy JS.

```html
<section data-amb-section="hero" class="hero-section hero-section--minimal">
  <div class="container">
    <div class="hero-content">
      <h1 class="hero-title">{benefit-led headline, 6–12 words}</h1>
      <p class="hero-description">{who-it-is-for + how-it-works, one sentence}</p>
      <div class="hero-actions">
        <a class="cta-button cta-button--minimal" href="#">{primary verb}</a>
        <a class="hero-link" href="#">{secondary}</a>
        <span class="hero-accent-dot"></span>
        <span class="hero-accent-dot"></span>
      </div>
    </div>
  </div>
</section>
```

```css
.hero-section--minimal {
  padding: clamp(120px, 18vw, 200px) 0 clamp(100px, 14vw, 160px);
}

.hero-section--minimal .hero-content {
  max-width: 580px;
  margin: 0 auto;
  text-align: center;
}

.hero-section--minimal .hero-title {
  font-size: clamp(2.8rem, 6vw, 4.5rem);
  font-weight: 600;
  letter-spacing: -0.03em;
  line-height: 1.05;
}

.hero-section--minimal .hero-description {
  font-size: clamp(1.15rem, 2vw, 1.4rem);
  color: var(--color-text-muted, #64748b);
  margin-top: 24px;
}

.hero-section--minimal .hero-actions {
  justify-content: center;
  margin-top: 40px;
  position: relative;
}

.hero-accent-dot {
  position: absolute;
  bottom: -20px;
  right: 20px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: radial-gradient(circle, var(--color-accent, #6366f1) 0%, transparent 70%);
  opacity: 0.12;
}
.hero-accent-dot:first-of-type {
  right: auto;
  left: 30px;
  bottom: -12px;
}

.cta-button--minimal {
  position: relative;
  padding: 14px 32px;
  font-weight: 500;
  border-radius: 8px;
  background: linear-gradient(135deg, var(--color-accent, #6366f1), #7c3aed);
  color: #fff;
  transition: opacity 0.2s ease;
}

.cta-button--minimal::after {
  content: '';
  position: absolute;
  bottom: 10px;
  left: 50%;
  transform: translateX(-50%);
  width: 0;
  height: 2px;
  background: #fff;
  transition: width 0.3s ease;
}

.cta-button--minimal:hover::after {
  width: calc(100% - 64px);
}

.hero-link {
  color: var(--color-text-muted, #64748b);
  font-weight: 500;
}

@media (prefers-reduced-motion: reduce) {
  .hero-title, .hero-description, .hero-actions {
    opacity: 1;
    transform: none;
    animation: none;
  }
  .cta-button--minimal::after {
    transition: none;
    width: calc(100% - 64px);
  }
}
```

*JS behavior:*
```javascript
// Subtle scroll parallax
const hero = document.querySelector('.hero-section--minimal');
const content = hero.querySelector('.hero-content');

window.addEventListener('scroll', () => {
  const scrollY = window.scrollY;
  const opacity = Math.max(0.9, 1 - scrollY / 2000);
  const translateY = scrollY * 0.2;
  content.style.opacity = opacity;
  content.style.transform = `translateY(${translateY}px)`;
}, { passive: true });
```

---

**Centered hero with proof strip.** Headline + CTA centered over a logo row of recognizable customers. Social proof delivered before any other section.

*Animation & Visual Details:*
- *Entrance*: Headline fades up (0.6s), subhead follows (0.15s stagger), CTA at 0.3s, logo strip at 0.5s stagger
- *Hover*: Logo strip auto-scrolls at slow speed, pauses on hover; individual logos scale to 1.05 on hover
- *Gradients*: Radial gradient glow behind the CTA (accent color at 6% opacity)
- *Radial circles*: One large radial ring behind the logo strip as a subtle container decoration
- *Scroll trigger*: Logo strip animates (translates) on scroll at 0.3 rate
- *JS interaction*: Auto-scrolling logo strip with IntersectionObserver pause, magnetic button on CTA

```html
<section data-amb-section="hero" class="hero-section hero-section--proof">
  <div class="hero-ring-bg"></div>
  <div class="container">
    <div class="hero-content">
      <h1 class="hero-title">{benefit-led headline, 6–12 words}</h1>
      <p class="hero-description">{who-it-is-for + how-it-works, one sentence}</p>
      <div class="hero-actions">
        <a class="cta-button" href="#">{primary verb}</a>
      </div>
    </div>
    <div class="hero-proof-strip">
      <p class="hero-proof-label">Trusted by teams at</p>
      <div class="hero-logo-track-wrapper">
        <div class="hero-logo-track">
          <img class="hero-logo" src="https://placehold.co/120x40?text=Acme" alt="Acme" />
          <img class="hero-logo" src="https://placehold.co/120x40?text=Brand" alt="Brand" />
          <img class="hero-logo" src="https://placehold.co/120x40?text=Corp" alt="Corp" />
          <img class="hero-logo" src="https://placehold.co/120x40?text=Studio" alt="Studio" />
          <img class="hero-logo" src="https://placehold.co/120x40?text=First" alt="First" />
          <img class="hero-logo" src="https://placehold.co/120x40?text=Acme" alt="Acme" />
          <img class="hero-logo" src="https://placehold.co/120x40?text=Brand" alt="Brand" />
          <img class="hero-logo" src="https://placehold.co/120x40?text=Corp" alt="Corp" />
          <img class="hero-logo" src="https://placehold.co/120x40?text=Studio" alt="Studio" />
          <img class="hero-logo" src="https://placehold.co/120x40?text=First" alt="First" />
        </div>
      </div>
    </div>
  </div>
</section>
```

```css
.hero-section--proof {
  padding: clamp(100px, 14vw, 160px) 0 clamp(80px, 10vw, 120px);
  text-align: center;
}

.hero-ring-bg {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 800px;
  height: 400px;
  background: radial-gradient(ellipse, rgba(99,102,241,0.06) 0%, transparent 70%);
  pointer-events: none;
  z-index: 0;
}

.hero-proof-strip {
  margin-top: 64px;
  position: relative;
  z-index: 1;
}

.hero-proof-label {
  font-size: 0.875rem;
  color: var(--color-text-muted, #64748b);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  margin-bottom: 24px;
}

.hero-logo-track-wrapper {
  overflow: hidden;
  mask-image: linear-gradient(to right, transparent, black 15%, black 85%, transparent);
  -webkit-mask-image: linear-gradient(to right, transparent, black 15%, black 85%, transparent);
}

.hero-logo-track {
  display: flex;
  gap: 48px;
  align-items: center;
  animation: logo-scroll 30s linear infinite;
  width: max-content;
}

.hero-logo-track:hover {
  animation-play-state: paused;
}

.hero-logo {
  height: 32px;
  width: auto;
  opacity: 0.5;
  filter: grayscale(100%);
  transition: opacity 0.2s ease, filter 0.2s ease, transform 0.2s ease;
  flex-shrink: 0;
}

.hero-logo:hover {
  opacity: 1;
  filter: grayscale(0%);
  transform: scale(1.05);
}

@keyframes logo-scroll {
  0% { transform: translateX(0); }
  100% { transform: translateX(-50%); }
}

@media (prefers-reduced-motion: reduce) {
  .hero-logo-track {
    animation: none;
    justify-content: center;
    flex-wrap: wrap;
  }
}
```

*JS behavior:*
```javascript
// Magnetic button (reuses earlier implementation)
// IntersectionObserver pause on scroll-out
const logoTrack = document.querySelector('.hero-logo-track');
const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      logoTrack.style.animationPlayState = 'running';
    } else {
      logoTrack.style.animationPlayState = 'paused';
    }
  });
}, { threshold: 0 });
observer.observe(document.querySelector('.hero-proof-strip'));
```

---

Copy rules: lead with benefit, not feature. Avoid "we" — speak to the visitor. The CTA verb should be specific ("Start free trial", "Book a demo") not generic ("Submit", "Learn more"). Keep the subhead under 18 words.

Layout rules: hero never contains a `<nav>` element — that belongs to the page header. Use placeholder imagery via `https://placehold.co/{w}x{h}` at deliberate ratios (1440x720 editorial, 800x600 product split, 96x96 avatar).

CSS custom property summary for hero system:
```css
:root {
  --color-accent: #6366f1;
  --color-text: #1e293b;
  --color-text-muted: #64748b;
  --hero-ring-size: 400px;
  --hero-enter-duration: 0.6s;
  --hero-enter-delay-step: 0.15s;
}
```