{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"not-found","type":"registry:ui","title":"Not Found","description":"Drop-in 404 section: a huge parallax code with RGB-split glitch bursts, a friendly message and a home button.","dependencies":["lucide-react"],"registryDependencies":[],"files":[{"path":"registry/ui/not-found.tsx","type":"registry:ui","content":"\"use client\";\n\nimport { useId, type PointerEvent } from \"react\";\nimport { ArrowLeft } from \"lucide-react\";\n\nexport interface NotFoundProps {\n  /** Big code shown in the middle. */\n  code?: string;\n  title?: string;\n  message?: string;\n  /** Where the button goes. */\n  homeHref?: string;\n  buttonLabel?: string;\n  /** Periodic RGB-split glitch bursts on the code. */\n  glitch?: boolean;\n  /** Px each digit drifts with the pointer. 0 disables parallax. */\n  parallax?: number;\n  /** Accent used for the glow and one glitch channel. */\n  accent?: string;\n  className?: string;\n}\n\nconst css = `\n.nf-digit{transform:translate3d(calc(var(--nf-x,0)*var(--d)*1px),calc(var(--nf-y,0)*var(--d)*1px),0);transition:transform .6s cubic-bezier(.2,.8,.2,1)}\n.nf-ghost{position:absolute;inset:0;mix-blend-mode:screen;opacity:0;pointer-events:none}\n.nf-glitch .nf-ghost-a{color:var(--nf-accent);animation:nf-a 3.4s steps(1) infinite}\n.nf-glitch .nf-ghost-b{color:#22d3ee;animation:nf-b 3.4s steps(1) infinite}\n.nf-glitch .nf-core{animation:nf-core 3.4s steps(1) infinite}\n@keyframes nf-a{\n0%,78%,100%{opacity:0;transform:none;clip-path:none}\n80%{opacity:.9;transform:translate(-6px,0);clip-path:inset(12% 0 62% 0)}\n83%{opacity:.9;transform:translate(8px,0);clip-path:inset(58% 0 18% 0)}\n86%{opacity:.9;transform:translate(-3px,0);clip-path:inset(30% 0 44% 0)}\n89%{opacity:.9;transform:translate(5px,0);clip-path:inset(76% 0 4% 0)}\n92%{opacity:0}}\n@keyframes nf-b{\n0%,78%,100%{opacity:0;transform:none;clip-path:none}\n80%{opacity:.9;transform:translate(6px,0);clip-path:inset(40% 0 38% 0)}\n83%{opacity:.9;transform:translate(-8px,0);clip-path:inset(4% 0 80% 0)}\n86%{opacity:.9;transform:translate(4px,0);clip-path:inset(66% 0 10% 0)}\n89%{opacity:.9;transform:translate(-5px,0);clip-path:inset(22% 0 60% 0)}\n92%{opacity:0}}\n@keyframes nf-core{0%,79%,93%,100%{transform:none}81%{transform:translate(3px,0) skewX(-6deg)}85%{transform:translate(-2px,0)}88%{transform:translate(1px,0) skewX(4deg)}}\n.nf-float{animation:nf-float 6s ease-in-out infinite}\n@keyframes nf-float{50%{transform:translateY(-10px)}}\n@keyframes nf-in{from{opacity:0;transform:translateY(14px);filter:blur(6px)}}\n.nf-in{animation:nf-in .8s cubic-bezier(.2,.8,.2,1) both}\n@media (prefers-reduced-motion: reduce){.nf-digit{transform:none;transition:none}.nf-glitch .nf-ghost-a,.nf-glitch .nf-ghost-b,.nf-glitch .nf-core,.nf-float,.nf-in{animation:none}}\n`;\n\n/**\n * Drop-in 404 section. Fills its parent; put it in `app/not-found.tsx` inside a\n * `min-h-screen` wrapper, or any sized box.\n */\nexport function NotFound({\n  code = \"404\",\n  title = \"This page drifted off\",\n  message = \"The link might be broken, or the page moved somewhere new. Let's get you back on track.\",\n  homeHref = \"/\",\n  buttonLabel = \"Back to home\",\n  glitch = true,\n  parallax = 18,\n  accent = \"#f43f5e\",\n  className,\n}: NotFoundProps) {\n  const onMove = (e: PointerEvent<HTMLElement>) => {\n    if (!parallax) return;\n    const r = e.currentTarget.getBoundingClientRect();\n    e.currentTarget.style.setProperty(\"--nf-x\", String(((e.clientX - r.left) / r.width - 0.5) * 2));\n    e.currentTarget.style.setProperty(\"--nf-y\", String(((e.clientY - r.top) / r.height - 0.5) * 2));\n  };\n  const onLeave = (e: PointerEvent<HTMLElement>) => {\n    e.currentTarget.style.setProperty(\"--nf-x\", \"0\");\n    e.currentTarget.style.setProperty(\"--nf-y\", \"0\");\n  };\n\n  const titleId = useId();\n  const digits = code.split(\"\");\n  // Outer digits drift more than inner ones, alternating direction for depth.\n  const depth = (i: number) => {\n    const mid = (digits.length - 1) / 2;\n    return parallax * (0.5 + Math.abs(i - mid) / Math.max(mid, 1)) * (i % 2 ? -1 : 1);\n  };\n\n  return (\n    <section\n      onPointerMove={onMove}\n      onPointerLeave={onLeave}\n      aria-labelledby={titleId}\n      className={`relative flex size-full min-h-[24rem] flex-col items-center justify-center overflow-hidden px-6 py-16 text-center ${className ?? \"\"}`}\n      style={{ [\"--nf-accent\" as string]: accent }}\n    >\n      <style href=\"not-found\" precedence=\"default\">\n        {css}\n      </style>\n\n      {/* Backdrop: fading grid + accent glow that also drifts with the pointer. */}\n      <div\n        aria-hidden\n        className=\"pointer-events-none absolute inset-0\"\n        style={{\n          backgroundImage:\n            \"linear-gradient(to right, color-mix(in oklab, var(--foreground) 7%, transparent) 1px, transparent 1px), linear-gradient(to bottom, color-mix(in oklab, var(--foreground) 7%, transparent) 1px, transparent 1px)\",\n          backgroundSize: \"44px 44px\",\n          maskImage: \"radial-gradient(ellipse 60% 55% at 50% 45%, #000 20%, transparent 75%)\",\n          WebkitMaskImage: \"radial-gradient(ellipse 60% 55% at 50% 45%, #000 20%, transparent 75%)\",\n        }}\n      />\n      <div\n        aria-hidden\n        className=\"nf-digit pointer-events-none absolute left-1/2 top-[42%] size-[28rem] -translate-x-1/2 -translate-y-1/2 rounded-full\"\n        style={{ [\"--d\" as string]: -parallax * 0.8, background: `radial-gradient(circle, color-mix(in oklab, ${accent} 30%, transparent), transparent 65%)`, filter: \"blur(20px)\" }}\n      />\n\n      <p className=\"sr-only\">Error {code}</p>\n      <div aria-hidden className={`nf-float relative flex select-none ${glitch ? \"nf-glitch\" : \"\"}`}>\n        {digits.map((d, i) => (\n          <span key={i} className=\"nf-digit relative block\" style={{ [\"--d\" as string]: depth(i) }}>\n            <span\n              className=\"nf-core block bg-clip-text font-black leading-none tracking-tighter text-transparent\"\n              style={{\n                fontSize: \"clamp(6rem, 22vw, 13rem)\",\n                backgroundImage: \"linear-gradient(to bottom, var(--foreground) 35%, color-mix(in oklab, var(--foreground) 15%, transparent))\",\n                animationDelay: `${i * 0.04}s`,\n              }}\n            >\n              {d}\n            </span>\n            <span className=\"nf-ghost nf-ghost-a font-black leading-none tracking-tighter\" style={{ fontSize: \"clamp(6rem, 22vw, 13rem)\", animationDelay: `${i * 0.04}s` }}>\n              {d}\n            </span>\n            <span className=\"nf-ghost nf-ghost-b font-black leading-none tracking-tighter\" style={{ fontSize: \"clamp(6rem, 22vw, 13rem)\", animationDelay: `${i * 0.04}s` }}>\n              {d}\n            </span>\n          </span>\n        ))}\n      </div>\n\n      <h1 id={titleId} className=\"nf-in relative mt-4 text-2xl font-semibold tracking-tight text-foreground sm:text-3xl\" style={{ animationDelay: \".1s\" }}>\n        {title}\n      </h1>\n      <p className=\"nf-in relative mt-3 max-w-md text-pretty text-sm leading-relaxed text-muted-foreground sm:text-base\" style={{ animationDelay: \".2s\" }}>\n        {message}\n      </p>\n      <a\n        href={homeHref}\n        className=\"nf-in group relative mt-8 inline-flex items-center gap-2 rounded-full bg-primary px-5 py-2.5 text-sm font-medium text-primary-foreground shadow-lg transition hover:scale-[1.03] active:scale-[0.98] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background\"\n        style={{ animationDelay: \".3s\" }}\n      >\n        <ArrowLeft className=\"size-4 transition-transform duration-300 group-hover:-translate-x-0.5\" aria-hidden />\n        {buttonLabel}\n      </a>\n    </section>\n  );\n}\n"}]}