Motion

Motion communicates relationships and reinforces hierarchy. Use the right token for the right moment — fast for press states, slow for reveals — and combine duration with easing to shape how an element arrives or departs.

Duration

Five steps, each tuned to a specific interaction type. Heavier geometry and content reveals warrant longer durations; micro-interactions should be nearly invisible.

Reference — Duration
TokenValueUse
--duration-fast80msPress / active states. The user should feel the response, not watch it.
--duration-base120msThe default for hover colour and background shifts.
--duration-slow200msFill and progress indicators; anything tracking a measured change.
--duration-enter250msPanel slide-ins, drawer opens, nav transitions. Default for geometry.
--duration-reveal400msContent that appears in stages. Use sparingly.
--duration-loop800msRepeating cycle animations — spinner, skeleton shimmer.

Easing

All easings are one-directional — they describe how something arrives. The preview shows each curve in the direction it is designed to be used, then snaps back to reset.

Reference — Easing
TokenValueUse
--ease-defaulteaseSafe choice when direction is neutral (colour shifts, opacity fades).
--ease-outease-outAnything sliding or fading into view; standard pairing with --duration-enter.
--ease-in-outease-in-outElements that travel a significant distance and need to feel settled at both ends.
--ease-springcubic-bezier(0.16, 1, 0.3, 1)Use for one expressive moment per interaction. Not for loops or repeated micro-interactions.

prefers-reduced-motion: base.css sets transition-duration and animation-duration to 0.01ms when the user has requested reduced motion; no extra guard is needed if you import farn.css. In custom animation code, always add an explicit @media (prefers-reduced-motion: reduce) guard.

Pairing Guide

Each scenario calls for a specific duration and easing combination. The demos below loop continuously to show the intended feel.

Button press / active
--duration-fast + --ease-default
Hover colour shift
--duration-base + --ease-out
Panel / drawer enter
--duration-enter + --ease-spring
Panel / drawer exit
--duration-enter + --ease-out
Content reveal
--duration-reveal + --ease-out
Reference — Pairing Guide
SituationDurationEasing
Button press / active--duration-fast--ease-default
Hover colour shift--duration-base--ease-out
Panel / drawer enter--duration-enter--ease-spring
Panel / drawer exit--duration-enter--ease-out
Content reveal--duration-reveal--ease-out

Code example

Combining duration and easing in a single transition declaration. Transform and opacity use different easing functions to feel natural — spring for the slide, ease-out for the fade.

.panel {
  transform: translateY(8px);
  opacity: 0;
  transition:
    transform var(--duration-enter) var(--ease-spring),
    opacity   var(--duration-enter) var(--ease-out);
}

.panel.is-open {
  transform: translateY(0);
  opacity: 1;
}