{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "not-found",
  "title": "404",
  "description": "Five playful 404 sections with a giant status code hero: cursor-following eyeball, flashlight reveal, throwable tiles, orbiting moon and a decoding error log.",
  "dependencies": [
    "motion",
    "lucide-react"
  ],
  "registryDependencies": [
    "utils",
    "https://trytweenly.vercel.app/r/use-reduced-motion.json",
    "https://trytweenly.vercel.app/r/tweenly-theme.json"
  ],
  "files": [
    {
      "path": "registry/new-york/not-found/not-found.tsx",
      "content": "\"use client\"\n\nimport {\n  useEffect,\n  useRef,\n  useState,\n  useSyncExternalStore,\n  type CSSProperties,\n  type ReactNode,\n  type RefObject,\n} from \"react\"\nimport {\n  animate as animateValue,\n  motion,\n  useMotionTemplate,\n  useMotionValue,\n  useSpring,\n  useTransform,\n  useVelocity,\n  type MotionValue,\n} from \"motion/react\"\nimport { ArrowLeft, ArrowUpRight, Hand } from \"lucide-react\"\nimport { cn } from \"@/lib/utils\"\nimport { useReducedMotion } from \"@/registry/new-york/hooks/use-reduced-motion\"\n\nexport type NotFoundVariant = \"eyes\" | \"spotlight\" | \"drag\" | \"orbit\" | \"scramble\"\nexport type NotFoundDigitFont = \"display\" | \"sans\" | \"mono\"\n\nexport interface NotFoundAction {\n  /** Button text. */\n  label: string\n  /** Renders a link when set, otherwise a button. */\n  href?: string\n  /** Click handler (runs before navigation for links). */\n  onClick?: () => void\n}\n\nexport interface NotFoundProps {\n  /** Visual style of the hero. Default: \"eyes\" */\n  variant?: NotFoundVariant\n  /** Status code shown as the giant hero. Zeros become the eye / planet. Default: \"404\" */\n  code?: string\n  /** Short headline under the code. Default: \"Page not found\" */\n  title?: string\n  /** Supporting line. Default: a short sentence that matches the variant */\n  description?: string\n  /** Requested path. Shown in the scramble log (falls back to the current URL) and as a chip elsewhere when set. Default: undefined */\n  path?: string\n  /** Primary action. Default: { label: \"Back home\", href: \"/\" } */\n  primaryAction?: NotFoundAction\n  /** Secondary action. Pass null to hide. Default: { label: \"Browse docs\", href: \"/docs\" } */\n  secondaryAction?: NotFoundAction | null\n  /** Accent color (iris, moon, scramble glyphs, accent tile). Default: \"#ff4d12\" */\n  accent?: string\n  /** Section background (any CSS color). Default: theme background (\"#0a0a0a\" for spotlight and orbit) */\n  background?: string\n  /** Text and digit color (any CSS color). Default: theme foreground (\"#ededed\" for spotlight and orbit) */\n  color?: string\n  /** Secondary text color (any CSS color). Default: theme muted foreground (\"#8f8f8f\" for spotlight and orbit) */\n  muted?: string\n  /** Typeface of the digits. Default: \"display\" */\n  digitFont?: NotFoundDigitFont\n  /** Multiplier for the digit size (sized in container query units). Default: 1 */\n  size?: number\n  /** Enable animation. Reduced motion always renders static final states. Default: true */\n  animate?: boolean\n  /** Additional classes for the root section. */\n  className?: string\n}\n\nconst EASE_OUT = [0.22, 1, 0.36, 1] as const\nconst EASE_IN_OUT = [0.76, 0, 0.24, 1] as const\nconst SPRING = { stiffness: 450, damping: 34 }\n\nconst DARK_BG = \"#0a0a0a\"\nconst DARK_FG = \"#ededed\"\nconst DARK_MUTED = \"#8f8f8f\"\n\nconst DESCRIPTIONS: Record<NotFoundVariant, string> = {\n  eyes: \"We looked everywhere. This page isn't here.\",\n  spotlight: \"It's a little dark in here, and the page you want isn't.\",\n  drag: \"This page fell apart. Feel free to play with the pieces.\",\n  orbit: \"This page drifted out of orbit. Let's get you back.\",\n  scramble: \"That address didn't resolve to anything we know.\",\n}\n\nconst DEFAULT_PRIMARY: NotFoundAction = { label: \"Back home\", href: \"/\" }\nconst DEFAULT_SECONDARY: NotFoundAction = { label: \"Browse docs\", href: \"/docs\" }\n\nconst FONTS: Record<NotFoundDigitFont, string> = {\n  display: \"font-[family-name:var(--font-display)] font-bold\",\n  sans: \"font-sans font-semibold tracking-[-0.06em]\",\n  mono: \"font-mono font-medium tracking-[-0.04em]\",\n}\n\nconst CONTENT =\n  \"relative z-10 flex w-full flex-col items-center justify-center gap-[clamp(1.25rem,4cqw,2.25rem)] px-6 py-12 text-center\"\n\n// ---------------------------------------------------------------------------\n// Shared helpers\n\n/** True while the element is on screen and the tab is visible. */\nfunction useActive(ref: RefObject<HTMLElement | null>) {\n  const [inView, setInView] = useState(false)\n  const [visible, setVisible] = useState(true)\n  useEffect(() => {\n    const el = ref.current\n    if (!el) return\n    const io = new IntersectionObserver(([entry]) => setInView(entry.isIntersecting))\n    io.observe(el)\n    const onVisibility = () => setVisible(document.visibilityState === \"visible\")\n    document.addEventListener(\"visibilitychange\", onVisibility)\n    return () => {\n      io.disconnect()\n      document.removeEventListener(\"visibilitychange\", onVisibility)\n    }\n  }, [ref])\n  return inView && visible\n}\n\nconst noopSubscribe = () => () => {}\n\nfunction useLocationPath(fallback: string) {\n  return useSyncExternalStore(\n    noopSubscribe,\n    () => window.location.pathname,\n    () => fallback\n  )\n}\n\nfunction mulberry32(seed: number) {\n  let s = seed\n  return () => {\n    s = (s + 0x6d2b79f5) | 0\n    let t = Math.imul(s ^ (s >>> 15), 1 | s)\n    t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t\n    return ((t ^ (t >>> 14)) >>> 0) / 4294967296\n  }\n}\n\nconst STARS = (() => {\n  const rand = mulberry32(404)\n  return Array.from({ length: 56 }, () => ({\n    x: rand() * 100,\n    y: rand() * 100,\n    size: 1 + rand() * 1.6,\n    opacity: 0.15 + rand() * 0.45,\n    duration: 2.4 + rand() * 3.6,\n    delay: rand() * -6,\n  }))\n})()\n\nfunction hash(text: string) {\n  let h = 0\n  for (let i = 0; i < text.length; i++) h = (h * 31 + text.charCodeAt(i)) | 0\n  return Math.abs(h)\n}\n\n/** Indices of the zeros, or the middle character when there are none. */\nfunction specialIndices(chars: string[]) {\n  const zeros = chars.flatMap((c, i) => (c === \"0\" ? [i] : []))\n  return zeros.length ? zeros : [Math.floor(chars.length / 2)]\n}\n\nfunction enter(reduced: boolean, delay = 0, y = 14) {\n  return {\n    initial: reduced ? false : { opacity: 0, y },\n    animate: { opacity: 1, y: 0 },\n    transition: { duration: 0.8, ease: EASE_OUT, delay },\n  } as const\n}\n\n// ---------------------------------------------------------------------------\n// Copy + actions\n\nfunction ActionButton({ action, primary, tabIndex }: { action: NotFoundAction; primary?: boolean; tabIndex?: number }) {\n  const className = cn(\n    \"group inline-flex h-10 items-center gap-2 rounded-full px-5 text-sm font-medium whitespace-nowrap\",\n    \"transition-transform duration-300 ease-[cubic-bezier(0.22,1,0.36,1)] hover:-translate-y-0.5 active:translate-y-0\",\n    \"focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:[outline-color:var(--nf-accent)]\",\n    !primary && \"border [border-color:var(--nf-line)]\"\n  )\n  const style: CSSProperties | undefined = primary ? { background: \"var(--nf-fg)\", color: \"var(--nf-bg)\" } : undefined\n  const content = (\n    <>\n      {primary && (\n        <ArrowLeft\n          aria-hidden=\"true\"\n          className=\"size-4 transition-transform duration-300 ease-[cubic-bezier(0.22,1,0.36,1)] group-hover:-translate-x-0.5\"\n        />\n      )}\n      {action.label}\n      {!primary && (\n        <ArrowUpRight\n          aria-hidden=\"true\"\n          className=\"size-4 opacity-60 transition-transform duration-300 ease-[cubic-bezier(0.22,1,0.36,1)] group-hover:translate-x-0.5 group-hover:-translate-y-0.5\"\n        />\n      )}\n    </>\n  )\n  if (action.href) {\n    return (\n      <a href={action.href} onClick={action.onClick} className={className} style={style} tabIndex={tabIndex}>\n        {content}\n      </a>\n    )\n  }\n  return (\n    <button type=\"button\" onClick={action.onClick} className={className} style={style} tabIndex={tabIndex}>\n      {content}\n    </button>\n  )\n}\n\ninterface CopyProps {\n  code: string\n  title: string\n  description: string\n  chip?: string\n  primary: NotFoundAction\n  secondary: NotFoundAction | null\n  reduced: boolean\n  delay: number\n  titleNode?: ReactNode\n  hidden?: boolean\n}\n\nfunction Copy({ code, title, description, chip, primary, secondary, reduced, delay, titleNode, hidden }: CopyProps) {\n  return (\n    <div\n      className={cn(\"flex flex-col items-center gap-[clamp(1rem,2.6cqw,1.5rem)]\", hidden && \"invisible\")}\n      aria-hidden={hidden || undefined}\n      inert={hidden || undefined}\n    >\n      <div className=\"flex max-w-[34rem] flex-col items-center gap-2.5\">\n        {chip && (\n          <motion.code\n            {...enter(reduced, delay - 0.08, 8)}\n            className=\"rounded-full border px-2.5 py-0.5 font-mono text-xs text-(--nf-muted) [border-color:var(--nf-line)]\"\n          >\n            {chip}\n          </motion.code>\n        )}\n        <motion.h1\n          {...enter(reduced, delay)}\n          className=\"text-[clamp(1.35rem,3.4cqw,2.25rem)] leading-tight font-semibold tracking-tight text-balance\"\n          aria-label={hidden ? undefined : `${code}: ${title}`}\n        >\n          {titleNode ?? title}\n        </motion.h1>\n        <motion.p\n          {...enter(reduced, delay + 0.06)}\n          className=\"text-[clamp(0.875rem,1.7cqw,1.0625rem)] leading-relaxed text-pretty text-(--nf-muted)\"\n        >\n          {description}\n        </motion.p>\n      </div>\n      <motion.div {...enter(reduced, delay + 0.12)} className=\"flex flex-wrap items-center justify-center gap-3\">\n        <ActionButton action={primary} primary tabIndex={hidden ? -1 : undefined} />\n        {secondary && <ActionButton action={secondary} tabIndex={hidden ? -1 : undefined} />}\n      </motion.div>\n    </div>\n  )\n}\n\nfunction Digit({ char, font, className }: { char: string; font: string; className?: string }) {\n  return <span className={cn(\"inline-block leading-[0.8]\", font, className)}>{char}</span>\n}\n\n// ---------------------------------------------------------------------------\n// 1. Eyes\n\nfunction Eye({ lookX, lookY, blink }: { lookX: MotionValue<number>; lookY: MotionValue<number>; blink: MotionValue<number> }) {\n  const x = useTransform(lookX, (v) => `${v * 0.12}em`)\n  const y = useTransform(lookY, (v) => `${v * 0.15}em`)\n  return (\n    <motion.span\n      style={{ scaleY: blink }}\n      className=\"relative mx-[0.02em] inline-block h-[0.72em] w-[0.6em] rounded-[50%] border-[0.095em] border-current\"\n    >\n      <span className=\"absolute inset-0 grid place-items-center overflow-hidden rounded-[50%]\">\n        <motion.span\n          style={{ x, y, background: \"var(--nf-accent)\" }}\n          className=\"relative grid size-[0.24em] place-items-center rounded-full\"\n        >\n          <span className=\"size-[0.11em] rounded-full bg-[#0a0a0a]\" />\n          <span className=\"absolute top-[0.045em] right-[0.05em] size-[0.045em] rounded-full bg-white/90\" />\n        </motion.span>\n      </span>\n    </motion.span>\n  )\n}\n\nfunction EyesHero({ chars, font, reduced, active }: HeroProps) {\n  const heroRef = useRef<HTMLDivElement>(null)\n  const lookX = useMotionValue(0)\n  const lookY = useMotionValue(0)\n  const sx = useSpring(lookX, { stiffness: 420, damping: 34 })\n  const sy = useSpring(lookY, { stiffness: 420, damping: 34 })\n  const blink = useMotionValue(1)\n  const eyes = specialIndices(chars)\n\n  useEffect(() => {\n    if (reduced) {\n      lookX.jump(0.35)\n      lookY.jump(-0.3)\n      sx.jump(0.35)\n      sy.jump(-0.3)\n      blink.jump(1)\n      return\n    }\n    if (!active) return\n    let lastMove = 0\n    let glanceTimer = 0\n    let blinkTimer = 0\n    const onMove = (e: PointerEvent) => {\n      const el = heroRef.current\n      if (!el) return\n      const r = el.getBoundingClientRect()\n      const dx = e.clientX - (r.left + r.width / 2)\n      const dy = e.clientY - (r.top + r.height / 2)\n      const dist = Math.hypot(dx, dy) || 1\n      const reach = Math.min(1, dist / Math.max(r.height, 80))\n      lookX.set((dx / dist) * reach)\n      lookY.set((dy / dist) * reach)\n      lastMove = performance.now()\n    }\n    const glance = () => {\n      if (performance.now() - lastMove > 2500) {\n        if (Math.random() < 0.25) {\n          lookX.set(0)\n          lookY.set(0)\n        } else {\n          const a = Math.random() * Math.PI * 2\n          const m = 0.55 + Math.random() * 0.45\n          lookX.set(Math.cos(a) * m)\n          lookY.set(Math.sin(a) * m * 0.8)\n        }\n      }\n      glanceTimer = window.setTimeout(glance, 1100 + Math.random() * 1500)\n    }\n    const doBlink = () => {\n      const twice = Math.random() < 0.2\n      animateValue(blink, twice ? [1, 0.08, 1, 0.08, 1] : [1, 0.08, 1], {\n        duration: twice ? 0.46 : 0.22,\n        ease: EASE_IN_OUT,\n      })\n      blinkTimer = window.setTimeout(doBlink, 2800 + Math.random() * 2800)\n    }\n    window.addEventListener(\"pointermove\", onMove, { passive: true })\n    glanceTimer = window.setTimeout(glance, 1600)\n    blinkTimer = window.setTimeout(doBlink, 1400)\n    return () => {\n      window.removeEventListener(\"pointermove\", onMove)\n      window.clearTimeout(glanceTimer)\n      window.clearTimeout(blinkTimer)\n      blink.jump(1)\n    }\n  }, [active, reduced, lookX, lookY, sx, sy, blink])\n\n  return (\n    <motion.div\n      ref={heroRef}\n      aria-hidden=\"true\"\n      initial={reduced ? false : { opacity: 0, y: 24, filter: \"blur(10px)\" }}\n      animate={{ opacity: 1, y: 0, filter: \"blur(0px)\" }}\n      transition={{ duration: 0.9, ease: EASE_OUT }}\n      className=\"flex items-baseline justify-center gap-[0.03em] text-(length:--nf-digit) select-none\"\n    >\n      {chars.map((c, i) =>\n        eyes.includes(i) ? <Eye key={i} lookX={sx} lookY={sy} blink={blink} /> : <Digit key={i} char={c} font={font} />\n      )}\n    </motion.div>\n  )\n}\n\n// ---------------------------------------------------------------------------\n// 2. Spotlight\n\nconst LIGHT_RADIUS = \"clamp(110px, 21cqw, 240px)\"\n\nfunction SpotlightScene({ chars, font, reduced, active, rootRef, copy }: HeroProps & { copy: CopyProps }) {\n  const rawX = useMotionValue(0)\n  const rawY = useMotionValue(0)\n  const x = useSpring(rawX, { stiffness: 400, damping: 38 })\n  const y = useSpring(rawY, { stiffness: 400, damping: 38 })\n  const light = useMotionValue(0)\n  // Alpha mask for the flashlight's edge fading, not a color gradient\n  const mask = useMotionTemplate`radial-gradient(circle ${LIGHT_RADIUS} at ${x}px ${y}px, #000 0%, rgba(0,0,0,0.85) 38%, transparent 72%)`\n\n  // Mount: center the light, then flicker it on.\n  useEffect(() => {\n    const el = rootRef.current\n    if (!el) return\n    const cx = el.clientWidth / 2\n    const cy = el.clientHeight * 0.4\n    rawX.jump(cx)\n    rawY.jump(cy)\n    x.jump(cx)\n    y.jump(cy)\n    if (reduced) {\n      light.jump(1)\n      return\n    }\n    const controls = animateValue(light, [0, 0.9, 0.12, 1, 0.45, 1], {\n      duration: 1.1,\n      times: [0, 0.14, 0.3, 0.52, 0.68, 1],\n      ease: \"linear\",\n      delay: 0.35,\n    })\n    return () => controls.stop()\n  }, [rootRef, reduced, rawX, rawY, x, y, light])\n\n  // Follow the pointer; drift on its own for touch or when the pointer rests.\n  useEffect(() => {\n    const el = rootRef.current\n    if (!el || !active) return\n    let lastMove = reduced ? Number.POSITIVE_INFINITY : 0\n    const finePointer = window.matchMedia(\"(pointer: fine)\").matches\n    const onMove = (e: PointerEvent) => {\n      const r = el.getBoundingClientRect()\n      rawX.set(e.clientX - r.left)\n      rawY.set(e.clientY - r.top)\n      lastMove = performance.now()\n    }\n    const onLeave = () => {\n      if (!reduced) lastMove = performance.now() - 1500\n    }\n    el.addEventListener(\"pointermove\", onMove, { passive: true })\n    el.addEventListener(\"pointerleave\", onLeave)\n\n    let raf = 0\n    const start = performance.now()\n    const tick = (now: number) => {\n      const idle = now - lastMove > (finePointer ? 2500 : 1200)\n      if (idle && !reduced) {\n        const t = (now - start) / 1000\n        const w = el.clientWidth\n        const h = el.clientHeight\n        rawX.set(w / 2 + Math.cos(t * 0.33) * w * 0.26)\n        rawY.set(h * 0.4 + Math.sin(t * 0.52) * h * 0.16)\n      }\n      raf = requestAnimationFrame(tick)\n    }\n    if (!reduced) raf = requestAnimationFrame(tick)\n    return () => {\n      cancelAnimationFrame(raf)\n      el.removeEventListener(\"pointermove\", onMove)\n      el.removeEventListener(\"pointerleave\", onLeave)\n    }\n  }, [rootRef, active, reduced, rawX, rawY])\n\n  const glowX = useTransform(x, (v) => `calc(${v}px - 50%)`)\n  const glowY = useTransform(y, (v) => `calc(${v}px - 50%)`)\n\n  const digits = (lit: boolean) => (\n    <div className=\"relative flex flex-col items-center gap-[clamp(0.75rem,2cqw,1.25rem)]\">\n      <div\n        className=\"flex items-baseline justify-center gap-[0.03em] text-(length:--nf-digit) select-none\"\n        style={\n          lit\n            ? { textShadow: \"0 0 0.12em color-mix(in oklab, var(--nf-fg) 35%, transparent)\" }\n            : { color: \"transparent\", WebkitTextStroke: \"1px color-mix(in oklab, var(--nf-fg) 10%, transparent)\" }\n        }\n      >\n        {chars.map((c, i) => (\n          <Digit key={i} char={c} font={font} className={lit && c === \"0\" ? \"text-(--nf-accent)\" : undefined} />\n        ))}\n      </div>\n      <p className={cn(\"font-mono text-[clamp(0.7rem,1.4cqw,0.875rem)] text-(--nf-accent)\", !lit && \"invisible\")}>\n        You found a secret. Still lost though.\n      </p>\n    </div>\n  )\n\n  return (\n    <>\n      {/* Flat pool of light on the wall */}\n      <motion.div\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute top-0 left-0 z-0 rounded-full\"\n        style={{\n          x: glowX,\n          y: glowY,\n          opacity: light,\n          width: `calc(${LIGHT_RADIUS} * 1.5)`,\n          height: `calc(${LIGHT_RADIUS} * 1.5)`,\n          backgroundColor: \"color-mix(in oklab, var(--nf-fg) 5%, transparent)\",\n        }}\n      />\n      <div className={CONTENT}>\n        <div aria-hidden=\"true\">{digits(false)}</div>\n        <Copy {...copy} />\n      </div>\n      {/* Lit layer: identical layout, only visible inside the flashlight */}\n      <motion.div\n        aria-hidden=\"true\"\n        className={cn(CONTENT, \"pointer-events-none absolute inset-0 z-20\")}\n        style={{ maskImage: mask, WebkitMaskImage: mask, opacity: light }}\n      >\n        {digits(true)}\n        <Copy {...copy} hidden />\n        <span className=\"absolute top-[12%] left-[8%] -rotate-6 font-mono text-xs text-(--nf-muted)\">no exit here</span>\n        <span className=\"absolute right-[9%] bottom-[14%] rotate-3 font-mono text-xs text-(--nf-muted)\">\n          try the buttons &darr;\n        </span>\n      </motion.div>\n    </>\n  )\n}\n\n// ---------------------------------------------------------------------------\n// 3. Drag\n\nconst REST_TILT = [-5, 3, -2, 4, -3]\n\nfunction DragTile({\n  char,\n  index,\n  accent,\n  font,\n  reduced,\n  constraints,\n  onGrab,\n}: {\n  char: string\n  index: number\n  accent: boolean\n  font: string\n  reduced: boolean\n  constraints: RefObject<HTMLElement | null>\n  onGrab: () => void\n}) {\n  const x = useMotionValue(0)\n  const y = useMotionValue(0)\n  const velocity = useVelocity(x)\n  const lean = useTransform(velocity, [-1600, 0, 1600], [-28, 0, 28], { clamp: true })\n  const spun = useSpring(lean, SPRING)\n  const rest = REST_TILT[index % REST_TILT.length]\n  const rotate = useTransform(spun, (v) => v + rest)\n\n  return (\n    <motion.div\n      drag\n      dragConstraints={constraints}\n      dragElastic={0.55}\n      dragSnapToOrigin\n      dragTransition={{ bounceStiffness: 450, bounceDamping: 30 }}\n      onDragStart={onGrab}\n      whileDrag={{ scale: 1.07, zIndex: 30 }}\n      whileHover={{ scale: 1.03 }}\n      initial={reduced ? false : { y: -420, opacity: 0 }}\n      animate={{ y: 0, opacity: 1 }}\n      transition={{\n        y: { type: \"spring\", stiffness: 420, damping: 22, mass: 1.1, delay: 0.1 + index * 0.1 },\n        opacity: { duration: 0.2, delay: 0.1 + index * 0.1 },\n        scale: { type: \"spring\", ...SPRING },\n      }}\n      style={{\n        x,\n        y,\n        rotate,\n        background: accent ? \"var(--nf-accent)\" : \"color-mix(in oklab, var(--nf-fg) 5%, var(--nf-bg))\",\n        color: accent ? \"var(--nf-bg)\" : undefined,\n        boxShadow: \"0 0.05em 0 0 color-mix(in oklab, var(--nf-fg) 14%, transparent)\",\n      }}\n      className={cn(\n        \"relative grid h-[1em] w-[0.84em] cursor-grab touch-none place-items-center rounded-[0.16em] select-none active:cursor-grabbing\",\n        !accent && \"border [border-color:var(--nf-line)]\"\n      )}\n    >\n      <span className={cn(\"block -translate-y-[0.02em] text-[0.8em] leading-none\", font)}>{char}</span>\n    </motion.div>\n  )\n}\n\nfunction DragHero({ chars, font, reduced, rootRef }: HeroProps) {\n  const [grabbed, setGrabbed] = useState(false)\n  const accents = specialIndices(chars)\n  return (\n    <div className=\"flex flex-col items-center gap-[clamp(0.75rem,2.4cqw,1.5rem)]\">\n      <div aria-hidden=\"true\" className=\"flex items-center justify-center gap-[0.08em] text-[length:calc(var(--nf-digit)*0.8)]\">\n        {chars.map((c, i) => (\n          <DragTile\n            key={i}\n            char={c}\n            index={i}\n            accent={accents.includes(i)}\n            font={font}\n            reduced={reduced}\n            constraints={rootRef}\n            onGrab={() => setGrabbed(true)}\n          />\n        ))}\n      </div>\n      <motion.p\n        {...enter(reduced, 0.6 + chars.length * 0.1, 6)}\n        className=\"inline-flex items-center gap-2 font-mono text-xs text-(--nf-muted)\"\n      >\n        <Hand aria-hidden=\"true\" className=\"size-3.5\" />\n        {grabbed ? \"Nice. They always come back.\" : \"Go on, throw them.\"}\n      </motion.p>\n    </div>\n  )\n}\n\n// ---------------------------------------------------------------------------\n// 4. Orbit\n\nconst ORBIT_RX = 0.56\nconst ORBIT_RY = 0.13\nconst ORBIT_TILT = (-16 * Math.PI) / 180\nconst COS_T = Math.cos(ORBIT_TILT)\nconst SIN_T = Math.sin(ORBIT_TILT)\n\nfunction Planet({ time, phase }: { time: MotionValue<number>; phase: number }) {\n  const angle = useTransform(time, (t) => t * 0.85 + 0.7 + phase)\n  const mx = useTransform(angle, (a) => Math.cos(a) * ORBIT_RX * COS_T - Math.sin(a) * ORBIT_RY * SIN_T)\n  const my = useTransform(angle, (a) => Math.cos(a) * ORBIT_RX * SIN_T + Math.sin(a) * ORBIT_RY * COS_T)\n  const depth = useTransform(angle, (a) => Math.sin(a))\n  const scale = useTransform(depth, (d) => 0.7 + (d + 1) * 0.22)\n  const opacity = useTransform(depth, (d) => 0.5 + (d + 1) * 0.25)\n  const zIndex = useTransform(depth, (d) => (d > 0 ? 3 : 0))\n  const x = useMotionTemplate`${mx}em`\n  const y = useMotionTemplate`${my}em`\n  const half =\n    \"absolute top-1/2 left-1/2 h-[0.26em] w-[1.12em] -translate-x-1/2 -translate-y-1/2 rotate-[-16deg] rounded-[50%] border-[0.012em] border-dashed\"\n\n  return (\n    <span className=\"relative isolate mx-[0.02em] inline-block h-[0.72em] w-[0.6em]\">\n      <span\n        className={cn(half, \"z-0\")}\n        style={{ clipPath: \"inset(0 0 50% 0)\", borderColor: \"color-mix(in oklab, var(--nf-fg) 22%, transparent)\" }}\n      />\n      <span\n        className=\"absolute inset-0 z-[1] rounded-[50%] border-[0.095em] border-current\"\n        style={{ backgroundColor: \"color-mix(in oklab, var(--nf-accent) 10%, transparent)\" }}\n      />\n      <span\n        className={cn(half, \"z-[2]\")}\n        style={{ clipPath: \"inset(50% 0 0 0)\", borderColor: \"color-mix(in oklab, var(--nf-fg) 30%, transparent)\" }}\n      />\n      <motion.span\n        className=\"absolute top-1/2 left-1/2 -mt-[0.06em] -ml-[0.06em] size-[0.12em] rounded-full\"\n        style={{\n          x,\n          y,\n          scale,\n          opacity,\n          zIndex,\n          background: \"var(--nf-accent)\",\n          boxShadow: \"0 0 0.14em color-mix(in oklab, var(--nf-accent) 70%, transparent)\",\n        }}\n      />\n    </span>\n  )\n}\n\nfunction FloatingDigit({ char, font, time, phase }: { char: string; font: string; time: MotionValue<number>; phase: number }) {\n  const fy = useTransform(time, (t) => Math.sin(t * 0.9 + phase) * 0.035)\n  const rotate = useTransform(time, (t) => Math.sin(t * 0.6 + phase) * 2)\n  const y = useMotionTemplate`${fy}em`\n  return (\n    <motion.span style={{ y, rotate }} className=\"inline-block\">\n      <Digit char={char} font={font} />\n    </motion.span>\n  )\n}\n\nfunction OrbitHero({ chars, font, reduced, active }: HeroProps) {\n  const time = useMotionValue(0)\n  const planets = specialIndices(chars)\n\n  useEffect(() => {\n    if (reduced) {\n      time.jump(0)\n      return\n    }\n    if (!active) return\n    let raf = 0\n    let last = performance.now()\n    const tick = (now: number) => {\n      time.set(time.get() + Math.min(now - last, 64) / 1000)\n      last = now\n      raf = requestAnimationFrame(tick)\n    }\n    raf = requestAnimationFrame(tick)\n    return () => cancelAnimationFrame(raf)\n  }, [active, reduced, time])\n\n  return (\n    <motion.div\n      aria-hidden=\"true\"\n      initial={reduced ? false : { opacity: 0, scale: 0.92, filter: \"blur(10px)\" }}\n      animate={{ opacity: 1, scale: 1, filter: \"blur(0px)\" }}\n      transition={{ duration: 1, ease: EASE_OUT }}\n      className=\"flex items-baseline justify-center gap-[0.03em] text-(length:--nf-digit) select-none\"\n    >\n      {chars.map((c, i) =>\n        planets.includes(i) ? (\n          <Planet key={i} time={time} phase={i * 2.1} />\n        ) : (\n          <FloatingDigit key={i} char={c} font={font} time={time} phase={i * 1.7} />\n        )\n      )}\n    </motion.div>\n  )\n}\n\nfunction Stars({ running, reduced }: { running: boolean; reduced: boolean }) {\n  return (\n    <div aria-hidden=\"true\" className=\"pointer-events-none absolute inset-0 z-0\">\n      {STARS.map((s, i) => (\n        <span\n          key={i}\n          className={cn(\"absolute rounded-full\", !reduced && \"animate-pulse\")}\n          style={{\n            left: `${s.x}%`,\n            top: `${s.y}%`,\n            width: s.size,\n            height: s.size,\n            opacity: s.opacity,\n            background: \"var(--nf-fg)\",\n            animationDuration: `${s.duration}s`,\n            animationDelay: `${s.delay}s`,\n            animationPlayState: running ? \"running\" : \"paused\",\n          }}\n        />\n      ))}\n    </div>\n  )\n}\n\n// ---------------------------------------------------------------------------\n// 5. Scramble\n\nconst GLYPHS = \"!<>-_\\\\/[]{}=+*^?#%&$@0123456789ABCDEF\"\nconst randomGlyph = () => GLYPHS[Math.floor(Math.random() * GLYPHS.length)]\n\n/** Decodes `text` into `el` from random glyphs. Returns a cancel function that restores the final text. */\nfunction scramble(el: HTMLElement, text: string, duration: number, stagger: number, colorize: boolean, onDone?: () => void) {\n  const chars = Array.from(text)\n  const reveal = chars.map((_, i) => i * stagger + duration * (0.45 + Math.random() * 0.55))\n  const end = Math.max(0, ...reveal)\n  const start = performance.now()\n  let lastSwap = 0\n  let raf = 0\n  const finish = () => {\n    el.textContent = text\n    if (colorize) el.style.color = \"\"\n  }\n  const tick = (now: number) => {\n    const t = now - start\n    if (t >= end) {\n      finish()\n      onDone?.()\n      return\n    }\n    if (now - lastSwap > 45) {\n      lastSwap = now\n      el.textContent = chars.map((c, i) => (c === \" \" || t >= reveal[i] ? c : randomGlyph())).join(\"\")\n      if (colorize) el.style.color = \"var(--nf-accent)\"\n    }\n    raf = requestAnimationFrame(tick)\n  }\n  raf = requestAnimationFrame(tick)\n  return () => {\n    cancelAnimationFrame(raf)\n    finish()\n  }\n}\n\nfunction ScrambleDigit({ char, font, index, reduced, active }: { char: string; font: string; index: number; reduced: boolean; active: boolean }) {\n  const ref = useRef<HTMLSpanElement>(null)\n  const cancel = useRef<(() => void) | null>(null)\n  const done = useRef(false)\n\n  useEffect(() => {\n    if (reduced || !active || done.current || !ref.current) return\n    const stop = scramble(ref.current, char, 700 + index * 160, 0, true, () => {\n      done.current = true\n    })\n    cancel.current = stop\n    return () => {\n      stop()\n      cancel.current = null\n    }\n  }, [active, reduced, char, index])\n\n  const onEnter = () => {\n    if (reduced || !ref.current) return\n    cancel.current?.()\n    cancel.current = scramble(ref.current, char, 420, 0, true)\n  }\n\n  return (\n    <span onPointerEnter={onEnter} className={cn(\"relative inline-block leading-[0.8]\", font)}>\n      <span className=\"invisible\">{char}</span>\n      <span ref={ref} className=\"absolute inset-0 text-center\">\n        {char}\n      </span>\n    </span>\n  )\n}\n\nfunction ScrambleTitle({ text, reduced, active }: { text: string; reduced: boolean; active: boolean }) {\n  const ref = useRef<HTMLSpanElement>(null)\n  const done = useRef(false)\n  useEffect(() => {\n    if (reduced || !active || done.current || !ref.current) return\n    return scramble(ref.current, text, 500, 28, false, () => {\n      done.current = true\n    })\n  }, [active, reduced, text])\n  return (\n    <span ref={ref} aria-hidden=\"true\">\n      {text}\n    </span>\n  )\n}\n\nfunction ErrorLog({ code, path, reduced, active }: { code: string; path: string; reduced: boolean; active: boolean }) {\n  const [typed, setTyped] = useState(0)\n  const progress = useRef(0)\n  const ms = 8 + (hash(path) % 38)\n  const segments = [\n    { text: \"GET \", className: \"text-(--nf-muted)\" },\n    { text: path, className: \"\" },\n    { text: \" → \", className: \"text-(--nf-muted)\" },\n    { text: code, className: \"text-(--nf-accent)\" },\n    { text: ` · ${ms}ms`, className: \"text-(--nf-muted)\" },\n  ]\n  const total = segments.reduce((n, s) => n + s.text.length, 0)\n\n  useEffect(() => {\n    if (reduced || !active || progress.current >= total) return\n    let timer = 0\n    const step = () => {\n      progress.current += 1\n      const finished = progress.current >= total\n      setTyped(finished ? Number.POSITIVE_INFINITY : progress.current)\n      if (!finished) timer = window.setTimeout(step, 24 + Math.random() * 30)\n    }\n    timer = window.setTimeout(step, progress.current === 0 ? 1100 : 200)\n    return () => window.clearTimeout(timer)\n  }, [active, reduced, total])\n\n  const shown = reduced ? Number.POSITIVE_INFINITY : typed\n  let left = shown\n  return (\n    <p\n      className=\"inline-flex max-w-full items-center gap-2 overflow-hidden rounded-md border px-3 py-1.5 font-mono text-[clamp(0.7rem,1.35cqw,0.85rem)] whitespace-nowrap [border-color:var(--nf-line)]\"\n      aria-label={`GET ${path} returned ${code}`}\n    >\n      <span aria-hidden=\"true\" className=\"size-1.5 shrink-0 rounded-full\" style={{ background: \"var(--nf-accent)\" }} />\n      <span aria-hidden=\"true\" className=\"min-h-[1lh] truncate\">\n        {segments.map((s, i) => {\n          const part = s.text.slice(0, Math.max(0, left))\n          left -= s.text.length\n          return part ? (\n            <span key={i} className={s.className}>\n              {part}\n            </span>\n          ) : null\n        })}\n        <span className={cn(\"ml-0.5 inline-block h-[1.1em] w-[0.5em] translate-y-[0.2em] bg-current opacity-70\", !reduced && \"animate-pulse\")} />\n      </span>\n    </p>\n  )\n}\n\nfunction ScrambleHero({ chars, font, reduced, active, code, path }: HeroProps & { code: string; path: string }) {\n  return (\n    <div className=\"flex flex-col items-center gap-[clamp(1rem,2.8cqw,1.75rem)]\">\n      <motion.div\n        aria-hidden=\"true\"\n        {...enter(reduced, 0, 10)}\n        className=\"flex items-baseline justify-center gap-[0.03em] text-(length:--nf-digit) select-none\"\n      >\n        {chars.map((c, i) => (\n          <ScrambleDigit key={`${i}-${c}`} char={c} font={font} index={i} reduced={reduced} active={active} />\n        ))}\n      </motion.div>\n      <motion.div {...enter(reduced, 0.3, 8)} className=\"max-w-full\">\n        <ErrorLog code={code} path={path} reduced={reduced} active={active} />\n      </motion.div>\n    </div>\n  )\n}\n\n// ---------------------------------------------------------------------------\n\ninterface HeroProps {\n  chars: string[]\n  font: string\n  reduced: boolean\n  active: boolean\n  rootRef: RefObject<HTMLElement | null>\n}\n\nexport function NotFound({\n  variant = \"eyes\",\n  code = \"404\",\n  title = \"Page not found\",\n  description,\n  path,\n  primaryAction = DEFAULT_PRIMARY,\n  secondaryAction = DEFAULT_SECONDARY,\n  accent = \"#ff4d12\",\n  background,\n  color,\n  muted,\n  digitFont = \"display\",\n  size = 1,\n  animate = true,\n  className,\n}: NotFoundProps) {\n  const rootRef = useRef<HTMLElement>(null)\n  const prefersReduced = useReducedMotion()\n  const reduced = prefersReduced || !animate\n  const active = useActive(rootRef)\n  const locationPath = useLocationPath(\"/this-page\")\n\n  const dark = variant === \"spotlight\" || variant === \"orbit\"\n  const chars = Array.from(code || \"404\")\n  const font = FONTS[digitFont]\n  const s = Math.max(0.2, size)\n\n  const style = {\n    \"--nf-accent\": accent,\n    \"--nf-bg\": background ?? (dark ? DARK_BG : \"var(--background)\"),\n    \"--nf-fg\": color ?? (dark ? DARK_FG : \"var(--foreground)\"),\n    \"--nf-muted\": muted ?? (dark ? DARK_MUTED : \"var(--muted-foreground)\"),\n    \"--nf-line\": \"color-mix(in oklab, var(--nf-fg) 14%, transparent)\",\n    \"--nf-digit\": `min(${24 * s}cqw, ${34 * s}cqh)`,\n    background: \"var(--nf-bg)\",\n    color: \"var(--nf-fg)\",\n  } as CSSProperties\n\n  const hero: HeroProps = { chars, font, reduced, active, rootRef }\n  const copy: CopyProps = {\n    code,\n    title,\n    description: description ?? DESCRIPTIONS[variant],\n    chip: variant === \"scramble\" ? undefined : path,\n    primary: primaryAction,\n    secondary: secondaryAction,\n    reduced,\n    delay: variant === \"drag\" ? 0.45 : 0.2,\n    titleNode: variant === \"scramble\" ? <ScrambleTitle key={title} text={title} reduced={reduced} active={active} /> : undefined,\n  }\n\n  return (\n    <section\n      ref={rootRef}\n      style={style}\n      className={cn(\n        \"relative isolate flex h-full min-h-full w-full flex-col items-center justify-center overflow-hidden [container-type:inline-size]\",\n        className\n      )}\n    >\n      {variant === \"spotlight\" ? (\n        <SpotlightScene {...hero} copy={copy} />\n      ) : (\n        <>\n          {variant === \"orbit\" && <Stars running={active} reduced={reduced} />}\n          <div className={CONTENT}>\n            {variant === \"eyes\" && <EyesHero {...hero} />}\n            {variant === \"drag\" && <DragHero {...hero} />}\n            {variant === \"orbit\" && <OrbitHero {...hero} />}\n            {variant === \"scramble\" && <ScrambleHero {...hero} code={code} path={path ?? locationPath} />}\n            <Copy {...copy} />\n          </div>\n        </>\n      )}\n    </section>\n  )\n}\n",
      "type": "registry:component"
    }
  ],
  "docs": "Docs, live playground and every prop: https://trytweenly.vercel.app/docs/components/not-found",
  "type": "registry:component"
}