# El Captain Marketing Site — Animation & Motion Specification

## Animation Philosophy

> Motion serves comprehension. Every animation must earn its frame budget by making content clearer, transitions smoother, or data more meaningful.

---

## Framer Motion Variants Library

### Base Variants

```typescript
// src/lib/animations.ts

export const fadeUp = {
  hidden: { opacity: 0, y: 20 },
  visible: {
    opacity: 1,
    y: 0,
    transition: { duration: 0.6, ease: [0.25, 0.46, 0.45, 0.94] }
  }
};

export const fadeIn = {
  hidden: { opacity: 0 },
  visible: {
    opacity: 1,
    transition: { duration: 0.4 }
  }
};

export const scaleIn = {
  hidden: { opacity: 0, scale: 0.95 },
  visible: {
    opacity: 1,
    scale: 1,
    transition: { duration: 0.5, ease: [0.25, 0.46, 0.45, 0.94] }
  }
};

export const staggerContainer = {
  hidden: {},
  visible: {
    transition: {
      staggerChildren: 0.1,
      delayChildren: 0.1
    }
  }
};

export const staggerItem = {
  hidden: { opacity: 0, y: 16 },
  visible: {
    opacity: 1,
    y: 0,
    transition: { duration: 0.4, ease: 'easeOut' }
  }
};
```

---

## Section-by-Section Animation Plan

### 1. Navbar
| Element | Animation | Trigger | Duration |
|---------|-----------|---------|----------|
| Entire nav | Slide down + fade | Page load | 400ms |
| Background blur | Opacity 0 → 0.8 | Scroll > 50px | 200ms |
| Border bottom | Opacity 0 → 1 | Scroll > 50px | 200ms |
| Active link indicator | Width grows from center | Route change | 300ms |
| Mobile menu | Slide from right (RTL: left) | Toggle | 300ms |

### 2. Hero Section
| Element | Animation | Trigger | Duration | Delay |
|---------|-----------|---------|----------|-------|
| Headline | Fade up from 30px below | Page load | 600ms | 0ms |
| Subheadline | Fade up | Page load | 600ms | 150ms |
| CTA buttons | Fade up + scale from 0.95 | Page load | 500ms | 300ms |
| Dashboard mockup | Fade in + float up from 40px + slight rotate | Page load | 800ms | 400ms |
| Stats bar | Stagger fade up (3 items) | Page load | 400ms each | 600ms start |
| Stats numbers | Count from 0 to value | When stats bar visible | 1200ms | 800ms |

**Dashboard Mockup Continuous Animation:**
```typescript
// Subtle floating effect (always active)
animate={{
  y: [0, -8, 0],
  rotateX: [0, 1, 0],
  rotateY: [0, -0.5, 0],
}}
transition={{
  duration: 6,
  repeat: Infinity,
  ease: "easeInOut"
}}
```

### 3. Problem → Solution Transition
| Phase | What Happens | Duration |
|-------|-------------|----------|
| Enter viewport | "Before" state visible: scattered papers, Excel icon, WhatsApp icon | Static |
| Scroll 30% | Elements begin to scatter/dissolve (opacity fade + scale down + blur) | 800ms |
| Scroll 50% | Midpoint: brief clean slate | 200ms |
| Scroll 70% | Dashboard mockup assembles from the same positions | 800ms |
| Scroll 100% | "After" state fully revealed, clean and organized | Static |

**Implementation: Scroll-linked (not time-based)**
```typescript
const { scrollYProgress } = useScroll({ target: sectionRef });
const opacity = useTransform(scrollYProgress, [0, 0.3, 0.5, 0.7, 1], [1, 0.5, 0, 0.5, 1]);
const scale = useTransform(scrollYProgress, [0, 0.3, 0.7, 1], [1, 0.8, 0.8, 1]);
```

### 4. Module Showcase (6 Cards)
| Element | Animation | Trigger | Duration |
|---------|-----------|---------|----------|
| Section heading | Fade up | Viewport entry (20%) | 500ms |
| Cards container | Stagger children | Viewport entry | 100ms between |
| Each card | Fade up from 20px | Stagger | 400ms |
| Card icon | Scale from 0.8 + fade | Card appears | 300ms |
| Card on hover | translateY(-4px) + shadow increase + border color change | Mouse enter | 200ms |
| Card arrow | translate 4px inline-end | Card hover | 200ms |

### 5. Feature Deep-Dives (3 Sections)
| Element | Animation | Trigger | Duration |
|---------|-----------|---------|----------|
| Text block | Fade up + slide from inline-start (right in RTL) | Viewport entry | 600ms |
| Mockup image | Fade in + slight perspective tilt | 200ms after text | 700ms |
| Chart in mockup | Draw-in (SVG path) | Mockup fully visible | 1000ms |
| Numbers in mockup | Count up | Chart completes | 800ms |
| Progress bars | Width grows from 0 to target | Mockup visible | 600ms staggered |

**Interactive Cursor Response (desktop only):**
```typescript
// Mockup tilts slightly toward cursor position
const rotateX = useTransform(mouseY, [-300, 300], [3, -3]);
const rotateY = useTransform(mouseX, [-300, 300], [-3, 3]);
```

### 6. Testimonials Carousel
| Element | Animation | Trigger | Duration |
|---------|-----------|---------|----------|
| Cards | Slide in from inline-end | Auto-rotate or swipe | 500ms |
| Quote mark | Scale pulse | Card enters | 400ms |
| Avatar | Fade + scale from 0.9 | Card enters | 300ms |
| Dots indicator | Width transition (active dot wider) | Slide change | 200ms |
| Auto-rotate | Every 5 seconds | Always (pauses on hover) | — |

### 7. Stats Section (Big Numbers)
| Element | Animation | Trigger | Duration |
|---------|-----------|---------|----------|
| Numbers | Count up from 0 | Viewport entry (once) | 1500ms |
| Suffix (ج.م / +) | Fade in | Count reaches 80% | 200ms |
| Label text | Fade up | Number completes | 300ms |
| Background glow | Radial gradient pulse | Section in view | 3s loop |

**Count-up Easing:** ease-out (fast start, slow end — feels natural)

### 8. CTA Section
| Element | Animation | Trigger | Duration |
|---------|-----------|---------|----------|
| Background gradient | Subtle shift (dark navy → slightly lighter) | Always | 8s loop |
| Headline | Fade up | Viewport entry | 500ms |
| Subtext | Fade up | 150ms after headline | 400ms |
| Buttons | Fade up + scale | 300ms after subtext | 400ms |
| Decorative dots/grid | Very subtle parallax (2-3px) | Scroll | Continuous |

### 9. Footer
| Element | Animation | Trigger | Duration |
|---------|-----------|---------|----------|
| Content | Fade in | Viewport entry | 400ms |
| No complex animations (footer = utility, not spectacle) |

---

## Scroll-Triggered Orchestration

### IntersectionObserver Settings
```typescript
// AnimateOnScroll wrapper component
const defaultViewport = {
  once: true,        // animate only first time
  amount: 0.2,      // trigger at 20% visibility
  margin: "-50px"   // start slightly before fully in view
};
```

### Scroll Progress Sections
Only the "Problem → Solution" section uses scroll-linked (useScroll) animation.
Everything else uses viewport entry triggers (simpler, better performance).

---

## Performance Budget

### Animation Constraints
- Maximum simultaneous animations: 8 elements
- Maximum particle count: 0 (no particles — too playful)
- Maximum parallax layers: 3
- Transform-only animations (no layout thrashing):
  - OK: opacity, transform (translate, scale, rotate)
  - AVOID: width, height, top, left, margin, padding
- Will-change applied only during animation, removed after
- GPU-accelerated only: `transform: translateZ(0)` where needed

### Reduced Motion Support
```typescript
// Every animated component checks this
const prefersReducedMotion = useReducedMotion();

// If true: show final state immediately, no transitions
const variants = prefersReducedMotion ? {} : fadeUp;
```

### Mobile Performance
- Disable cursor-responsive tilt on touch devices
- Reduce stagger count (show all at once below 768px)
- Disable parallax entirely on mobile
- Reduce animation durations by 30% on mobile
- Skip "Problem → Solution" scroll animation on mobile (show static before/after)

---

## Micro-Interactions

### Buttons
```css
/* Hover (desktop only) */
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(14,165,233,0.25);
transition: all 150ms ease;

/* Active/Press */
transform: translateY(0) scale(0.98);
transition: all 100ms ease;

/* Focus */
outline: 2px solid var(--color-sky-500);
outline-offset: 2px;
```

### Cards
```css
/* Hover */
transform: translateY(-4px);
border-color: var(--color-sky-200);
box-shadow: var(--shadow-lg);
transition: all 200ms ease;

/* The internal arrow moves */
.card-arrow { transform: translateX(4px); /* inline-end */ }
```

### Links
```css
/* Underline grows from center */
.link::after {
  content: '';
  width: 0;
  height: 2px;
  background: var(--color-sky-500);
  transition: width 200ms ease;
}
.link:hover::after { width: 100%; }
```

### Language Toggle
```css
/* Smooth text direction change */
[dir] { transition: none; } /* No transition on dir change — instant */
/* But content fades: */
.content { animation: fadeIn 200ms ease; }
```

### Number Counters
```typescript
// Animated number component
function CountUp({ target, duration = 1200, suffix = '' }) {
  // Use requestAnimationFrame
  // Easing: easeOutExpo for "fast start, dramatic slow end"
  // Format: Arabic-Indic numerals in AR locale
}
```

---

## Page Transition Spec

### Route Changes
```typescript
// Layout wrapper with AnimatePresence
<AnimatePresence mode="wait">
  <motion.main
    key={pathname}
    initial={{ opacity: 0, y: 8 }}
    animate={{ opacity: 1, y: 0 }}
    exit={{ opacity: 0, y: -8 }}
    transition={{ duration: 0.25 }}
  >
    {children}
  </motion.main>
</AnimatePresence>
```

### Shared Elements (No Transition)
- Navbar: persists across routes (no animation)
- Footer: persists across routes
- Floating WhatsApp button: persists

---

## Animation Do's and Don'ts

### DO
- Use easeOut for enters (natural deceleration)
- Use easeIn for exits (natural acceleration)
- Stagger related items (cards, list items)
- Animate on first viewport entry only (once: true)
- Test on real Egyptian 4G speed (throttle Chrome)
- Keep total animation time under 1s for any single element
- Use transform properties only (GPU accelerated)

### DON'T
- Bounce effects (too playful, wrong brand)
- Spin/rotate more than 5 degrees (disorienting)
- Animate text color (not perceivable, wastes frames)
- Delay more than 500ms total (feels broken)
- Animate on scroll UP (confusing, breaks mental model)
- Use spring physics with high bounciness (wrong brand energy)
- Autoplay video (bandwidth cost in Egypt)
- Animate elements the user can't see (waste of resources)
- Add loading animations that block content (perceived as slow)
