{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "motion",
  "title": "Motion Tiers",
  "description": "Three duration tiers and one easing, as CSS custom properties: --motion-fast/moderate/slow with a matching -exit for each, and --motion-ease, the settle curve of a critically damped spring. Reduced motion zeroes every tier in one place, so no component carries its own guard.",
  "files": [
    {
      "path": "registry/lib/motion.ts",
      "content": "/**\n * Reading a motion tier from JS.\n *\n * The tiers themselves are CSS custom properties — `--motion-fast`,\n * `--motion-moderate`, `--motion-slow` and their `-exit` pairs — declared in\n * `app/globals.css` and shipped by the `motion` entry in `registry.json`.\n * Animations use them directly, through `duration-(--motion-moderate)` and\n * friends. Nothing here is needed for that.\n *\n * This exists for the handful of places that need a JS *timer* sized to a\n * transition: a piece of state that has to be held for exactly as long as\n * something is moving. Reading the token rather than restating its value is\n * the point — a hardcoded number is how the timings drifted apart before they\n * were tokenised, and reading the live property means reduced motion (which\n * zeroes every tier) zeroes the timer with it.\n *\n * If you are reaching for this to drive an animation, stop: write a CSS\n * transition instead.\n */\n\n/** A tier's length in milliseconds. `fallback` covers the server, where there\n *  is no computed style to read. */\nfunction motionMs(token: string, fallback: number): number {\n  if (typeof window === \"undefined\") return fallback;\n  const raw = getComputedStyle(document.documentElement)\n    .getPropertyValue(token)\n    .trim();\n  if (!raw) return fallback;\n  const value = Number.parseFloat(raw);\n  if (Number.isNaN(value)) return fallback;\n  // The tokens are written in ms; seconds are accepted so a consumer who\n  // redefines a tier as `0.2s` doesn't get a 0.2 millisecond timer.\n  return raw.endsWith(\"ms\") ? value : value * 1000;\n}\n\n/** A timer that must outlast a transition rather than match it — the tier plus\n *  a margin, so a throttled or backgrounded tab that paints late still clears\n *  the state it was holding. */\nexport function motionHoldMs(token: string, fallback: number): number {\n  return motionMs(token, fallback) + 100;\n}\n",
      "type": "registry:lib"
    }
  ],
  "cssVars": {
    "theme": {
      "motion-ease": "cubic-bezier(0.32, 0.72, 0, 1)",
      "motion-fast": "80ms",
      "motion-fast-exit": "60ms",
      "motion-moderate": "160ms",
      "motion-moderate-exit": "120ms",
      "motion-slow": "240ms",
      "motion-slow-exit": "160ms",
      "ease-spring": "var(--motion-ease)"
    }
  },
  "css": {
    "@media (prefers-reduced-motion: reduce)": {
      ":root": {
        "--motion-fast": "0ms",
        "--motion-fast-exit": "0ms",
        "--motion-moderate": "0ms",
        "--motion-moderate-exit": "0ms",
        "--motion-slow": "0ms",
        "--motion-slow-exit": "0ms"
      },
      "*, *::before, *::after": {
        "animation-duration": "0.01ms !important",
        "animation-iteration-count": "1 !important",
        "scroll-behavior": "auto !important"
      }
    }
  },
  "categories": [
    "lib"
  ],
  "type": "registry:lib"
}