# Motion Guide — Agent Instructions

This file is the single source of truth for animation timing, easing, and motion patterns in this design system. See `philosophy.md` Motion & Transitions section for what moves and what does not.

---

## Animation Timing Reference

| Element | Duration | Easing |
|---|---|---|
| Button hover/press | 100–150ms | ease-out |
| Tooltip appear | 150–200ms | ease-out |
| Dropdown open | 200–250ms | ease-out |
| Modal enter | 250–300ms | ease-out |
| Modal exit | 200ms | ease-in |
| Page transition | 300–400ms | ease-in-out |
| Skeleton shimmer | 1500ms loop | linear |
| Stagger between items | 50–80ms | — |

### Rules

- Closing is always faster than opening
- NEVER linear easing except for continuous loops (progress bars, shimmer)
- Animate only `transform` and `opacity` (GPU-accelerated)
- Never animate `width`, `height`, `top`, `left` (causes layout reflow)
- `prefers-reduced-motion: reduce` → remove non-essential animation

### Accepted Exceptions

- **Accordion / collapsible sections**: Animating `height` is acceptable for expanding or contracting content sections (e.g., Radix UI accordion, collapsible panels). These are important for helping users track context changes.
- **Expressive homepage animations**: `filter: blur()` is acceptable for ambient homepage effects where the purpose is to set user expectations for the product experience.
- **Background-color and border-color transitions**: These are acceptable for interactive state changes (hover, focus, active). They are cheap enough on modern hardware and essential for communicating state.
- **Box-shadow transitions**: Not used. Shadows communicate static elevation and do not change on interaction.
- **Background-position**: Acceptable for shimmer/sweep effects.

### Deprecated Patterns

> **ALERT: Blobby button (`src/styles/ui/blobby-button.css`) is flagged for removal.** Its animation pattern (multiple blob transforms with staggered delays, complex transition chains) does not align with the design system's motion principles. It should be transitioned to a simpler interaction pattern. Flag this to the user when working on related code.

---

## Easing Functions

```css
:root {
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);      /* entering elements */
  --ease-in: cubic-bezier(0.7, 0, 0.84, 0);        /* exiting elements */
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);   /* repositioning */
}
```

No bounce/spring easing — see `philosophy.md` for the rationale.

Always use these tokens. Do not use raw CSS easing keywords (`ease`, `ease-out`, `ease-in-out`) — they have different curves than the design system's custom functions. Existing code using CSS keywords should migrate to these tokens over time.

---

## Duration Tokens

```css
:root {
  --duration-fast: 120ms;       /* hover, press, toggle */
  --duration-normal: 200ms;     /* tooltips, dropdowns, small reveals */
  --duration-slow: 300ms;       /* modals, panels, page transitions */
  --duration-ambient: 1500ms;   /* breathing, shimmer loops */
  --stagger-step: 60ms;         /* delay between staggered items */
}
```

---

## Staggered Animations

Multiple elements appearing together should stagger by 50–80ms:

```css
.card:nth-child(1) { animation-delay: 0ms; }
.card:nth-child(2) { animation-delay: 60ms; }
.card:nth-child(3) { animation-delay: 120ms; }
```

---

## Common Transitions

```css
/* Button interactions */
.btn { transition: all 120ms var(--ease-out); }

/* Card hover — background shift only */
.card {
  transition: background-color 150ms var(--ease-out);
}
.card:hover {
  background-color: var(--bg-surface-1);
}

/* Modal enter */
@keyframes modal-in {
  from { opacity: 0; transform: scale(0.95) translateY(8px); }
  to { opacity: 1; transform: scale(1) translateY(0); }
}
.modal { animation: modal-in 250ms var(--ease-out); }

/* Fade in up (for page content) */
@keyframes fade-in-up {
  from { opacity: 0; transform: translateY(12px); }
  to { opacity: 1; transform: translateY(0); }
}

/* Skeleton shimmer */
@keyframes shimmer {
  from { background-position: -200% 0; }
  to { background-position: 200% 0; }
}
.skeleton {
  background: linear-gradient(90deg,
    var(--grey-200) 25%, var(--grey-100) 50%, var(--grey-200) 75%);
  background-size: 200% 100%;
  animation: shimmer 1.5s linear infinite;
}
```

---

## Ambient & Decorative Animations

These are longer, continuous animations used for branding and atmosphere — not direct user interactions.

### Timing

| Pattern | Duration | Easing | Notes |
|---|---|---|---|
| Breathing / pulse | 1.5–8s | ease-in-out | Opacity or blur oscillation |
| Prism / reflection | 2s | ease-in-out | Subtle transform loops |
| Fade-in with drift | 0.35–0.55s | ease-out | One-shot entrance, often staggered |
| Shimmer sweep | 1.5–3s | ease-in-out or linear | Background-position or opacity loop |

### Rules

- Ambient animations must **never compete** with interactive motion — keep amplitudes subtle
- Always loop with `infinite` or play once with `forwards`
- Stagger delays for grouped ambient elements (e.g., mirror pulses: 0s, 0.15s, 0.3s)
- Ambient animations are **non-essential** — they must be disabled under `prefers-reduced-motion: reduce`
- Use `ease-in-out` for oscillating effects, `ease-out` for one-shot entrances
- `linear` is acceptable for continuous shimmer loops only

---

## Colored Shadows

Tint shadows with the element's color for depth that feels real:

```css
.card-accent {
  background: var(--blue-500);
  box-shadow: 0 8px 24px rgba(4, 120, 151, 0.25);
}
```

---

## Reduced Motion

```css
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}
```
