{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "galvanize",
  "type": "registry:ui",
  "title": "Galvanize",
  "description": "An animated gradient border cycling silver to blue to violet, like electroplating in progress. Hover accelerates the rotation and thickens the ring by a pixel. Pure CSS via a masked conic gradient.",
  "dependencies": [],
  "registryDependencies": [],
  "files": [
    {
      "path": "registry/default/buttons/galvanize/galvanize.tsx",
      "type": "registry:ui",
      "target": "components/crucible/galvanize.tsx",
      "content": "import * as React from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\nexport interface GalvanizeProps extends React.ComponentPropsWithoutRef<\"button\"> {\n  /** Three colors the border rotates through. Any CSS colors. @default silver, blue, violet */\n  colors?: [string, string, string];\n  /** Border radius in px. @default 12 */\n  radius?: number;\n  /** Ring thickness in px at rest — thickens by 1px on hover. @default 1.5 */\n  thickness?: number;\n  /** Seconds for one full rotation at rest (hover runs ~2.9x faster). @default 5 */\n  duration?: number;\n  /** Freeze the animation, holding the current frame. @default false */\n  paused?: boolean;\n}\n\n/**\n * Galvanize — an animated gradient border, like electroplating in progress.\n * Silver, blue, and violet rotate continuously around the edge; on hover\n * the rotation visibly accelerates and the ring thickens by a pixel, as if\n * current had increased. Pure CSS via a masked conic gradient — the\n * gradient never bleeds into the label. Honors prefers-reduced-motion by\n * freezing the ring at a static tri-tone gradient.\n */\nexport function Galvanize({\n  colors = [\"#cbd5e1\", \"#60a5fa\", \"#8b5cf6\"],\n  radius = 12,\n  thickness = 1.5,\n  duration = 5,\n  paused = false,\n  className,\n  style,\n  disabled,\n  children,\n  ...rest\n}: GalvanizeProps) {\n  return (\n    <button\n      data-crucible=\"galvanize\"\n      className={cn(\n        \"relative isolate inline-flex items-center justify-center overflow-hidden\",\n        \"bg-neutral-900 px-6 py-3 text-sm font-medium text-white\",\n        \"select-none transition-colors\",\n        \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-offset-neutral-950\",\n        \"focus-visible:ring-[color:var(--galvanize-c1)]\",\n        \"disabled:cursor-not-allowed disabled:opacity-50\",\n        className\n      )}\n      style={\n        {\n          \"--galvanize-c1\": colors[0],\n          \"--galvanize-c2\": colors[1],\n          \"--galvanize-c3\": colors[2],\n          \"--galvanize-thickness\": `${thickness}px`,\n          \"--galvanize-duration\": `${duration}s`,\n          \"--galvanize-play\": paused ? \"paused\" : \"running\",\n          borderRadius: radius,\n          ...style,\n        } as React.CSSProperties\n      }\n      disabled={disabled}\n      {...rest}\n    >\n      <style>{`\n        @property --galvanize-angle {\n          syntax: \"<angle>\";\n          inherits: false;\n          initial-value: 0deg;\n        }\n        @keyframes crucible-galvanize-rotate {\n          to { --galvanize-angle: 360deg; }\n        }\n        /* The rotating conic lives ON the ring element (not an oversized child),\n           so the border fills evenly at any button aspect ratio — animating the\n           gradient's start angle rather than transform-rotating a rectangle. */\n        [data-crucible=\"galvanize\"] .galvanize-ring {\n          position: absolute;\n          inset: 0;\n          border-radius: inherit;\n          padding: var(--galvanize-thickness);\n          transition: padding 200ms ease;\n          background: conic-gradient(\n            from var(--galvanize-angle),\n            var(--galvanize-c1),\n            var(--galvanize-c2),\n            var(--galvanize-c3),\n            var(--galvanize-c1)\n          );\n          -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);\n          -webkit-mask-composite: xor;\n          mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);\n          mask-composite: exclude;\n          animation: crucible-galvanize-rotate var(--galvanize-duration) linear infinite;\n          animation-play-state: var(--galvanize-play);\n        }\n        [data-crucible=\"galvanize\"]:hover .galvanize-ring {\n          padding: calc(var(--galvanize-thickness) + 1px);\n          animation-duration: calc(var(--galvanize-duration) * 0.35);\n        }\n        [data-crucible=\"galvanize\"]:disabled .galvanize-ring {\n          animation-play-state: paused;\n        }\n        @media (prefers-reduced-motion: reduce) {\n          [data-crucible=\"galvanize\"] .galvanize-ring {\n            animation: none;\n            background: conic-gradient(from 35deg, var(--galvanize-c1), var(--galvanize-c2), var(--galvanize-c3), var(--galvanize-c1));\n          }\n          [data-crucible=\"galvanize\"]:hover .galvanize-ring {\n            padding: var(--galvanize-thickness);\n          }\n        }\n      `}</style>\n\n      <span aria-hidden className=\"galvanize-ring pointer-events-none\" />\n\n      {/* Faint persistent rim over the gradient: keeps the silhouette readable\n          (and lifts the dim ember/violet phases) no matter the spin phase. */}\n      <span\n        aria-hidden\n        className=\"pointer-events-none absolute inset-0 rounded-[inherit] border border-white/15\"\n      />\n\n      <span className=\"relative z-10\">{children}</span>\n    </button>\n  );\n}\n"
    }
  ]
}