{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "loader",
  "type": "registry:component",
  "title": "Loader",
  "description": "Concentric conic-gradient loader (KokonutUI, MIT), drawn in --foreground so it theme-tracks.",
  "dependencies": [
    "framer-motion"
  ],
  "registryDependencies": [
    "https://design.subconscious.ai/r/utils.json"
  ],
  "files": [
    {
      "path": "registry/components/loader.tsx",
      "type": "registry:component",
      "content": "\"use client\";\n\n/**\n * @author: @kokonutui\n * @description: Loader\n * @version: 1.0.0\n * @date: 2025-06-26\n * @license: MIT\n * @website: https://kokonutui.com\n * @github: https://github.com/kokonut-labs/kokonutui\n *\n * Bridged to the Subconscious design contract: the conic-gradient rings draw in\n * `var(--color)`, so the loader tracks light/dark from one set of rings —\n * the original's duplicate hardcoded dark-mode rings are no longer needed.\n */\n\nimport { motion } from \"framer-motion\";\nimport { cn } from \"@/registry/lib/utils\";\n\ninterface LoaderProps extends React.HTMLAttributes<HTMLDivElement> {\n  title?: string;\n  subtitle?: string;\n  size?: \"sm\" | \"md\" | \"lg\";\n}\n\nexport default function Loader({\n  title = \"Configuring your account...\",\n  subtitle = \"Please wait while we prepare everything for you\",\n  size = \"md\",\n  className,\n  ...props\n}: LoaderProps) {\n  const sizeConfig = {\n    sm: {\n      container: \"size-20\",\n      titleClass: \"text-sm/tight font-medium\",\n      subtitleClass: \"text-xs/relaxed\",\n      spacing: \"space-y-2\",\n      maxWidth: \"max-w-48\",\n    },\n    md: {\n      container: \"size-32\",\n      titleClass: \"text-base/snug font-medium\",\n      subtitleClass: \"text-sm/relaxed\",\n      spacing: \"space-y-3\",\n      maxWidth: \"max-w-56\",\n    },\n    lg: {\n      container: \"size-40\",\n      titleClass: \"text-lg/tight font-semibold\",\n      subtitleClass: \"text-base/relaxed\",\n      spacing: \"space-y-4\",\n      maxWidth: \"max-w-64\",\n    },\n  };\n\n  const config = sizeConfig[size];\n\n  // Each ring: a conic-gradient masked to a thin annulus. Drawn in\n  // var(--color) so the whole loader theme-tracks via data-mode.\n  const ink = \"var(--color)\";\n  const ink60 = \"color-mix(in srgb, var(--color) 60%, transparent)\";\n  const ink50 = \"color-mix(in srgb, var(--color) 50%, transparent)\";\n  const ink40 = \"color-mix(in srgb, var(--color) 40%, transparent)\";\n\n  return (\n    <div\n      className={cn(\n        \"flex flex-col items-center justify-center gap-8 p-8\",\n        className\n      )}\n      {...props}\n    >\n      <motion.div\n        animate={{\n          scale: [1, 1.02, 1],\n        }}\n        className={cn(\"relative\", config.container)}\n        transition={{\n          duration: 4,\n          repeat: Number.POSITIVE_INFINITY,\n          ease: [0.4, 0, 0.6, 1],\n        }}\n      >\n        {/* Outer ring with shimmer */}\n        <motion.div\n          animate={{ rotate: [0, 360] }}\n          className=\"absolute inset-0 rounded-full\"\n          style={{\n            background: `conic-gradient(from 0deg, transparent 0deg, ${ink} 90deg, transparent 180deg)`,\n            mask: \"radial-gradient(circle at 50% 50%, transparent 35%, black 37%, black 39%, transparent 41%)\",\n            WebkitMask:\n              \"radial-gradient(circle at 50% 50%, transparent 35%, black 37%, black 39%, transparent 41%)\",\n            opacity: 0.8,\n          }}\n          transition={{\n            duration: 3,\n            repeat: Number.POSITIVE_INFINITY,\n            ease: \"linear\",\n          }}\n        />\n\n        {/* Primary animated ring */}\n        <motion.div\n          animate={{ rotate: [0, 360] }}\n          className=\"absolute inset-0 rounded-full\"\n          style={{\n            background: `conic-gradient(from 0deg, transparent 0deg, ${ink} 120deg, ${ink50} 240deg, transparent 360deg)`,\n            mask: \"radial-gradient(circle at 50% 50%, transparent 42%, black 44%, black 48%, transparent 50%)\",\n            WebkitMask:\n              \"radial-gradient(circle at 50% 50%, transparent 42%, black 44%, black 48%, transparent 50%)\",\n            opacity: 0.9,\n          }}\n          transition={{\n            duration: 2.5,\n            repeat: Number.POSITIVE_INFINITY,\n            ease: [0.4, 0, 0.6, 1],\n          }}\n        />\n\n        {/* Secondary ring — counter rotation */}\n        <motion.div\n          animate={{ rotate: [0, -360] }}\n          className=\"absolute inset-0 rounded-full\"\n          style={{\n            background: `conic-gradient(from 180deg, transparent 0deg, ${ink60} 45deg, transparent 90deg)`,\n            mask: \"radial-gradient(circle at 50% 50%, transparent 52%, black 54%, black 56%, transparent 58%)\",\n            WebkitMask:\n              \"radial-gradient(circle at 50% 50%, transparent 52%, black 54%, black 56%, transparent 58%)\",\n            opacity: 0.35,\n          }}\n          transition={{\n            duration: 4,\n            repeat: Number.POSITIVE_INFINITY,\n            ease: [0.4, 0, 0.6, 1],\n          }}\n        />\n\n        {/* Accent particles */}\n        <motion.div\n          animate={{ rotate: [0, 360] }}\n          className=\"absolute inset-0 rounded-full\"\n          style={{\n            background: `conic-gradient(from 270deg, transparent 0deg, ${ink40} 20deg, transparent 40deg)`,\n            mask: \"radial-gradient(circle at 50% 50%, transparent 61%, black 62%, black 63%, transparent 64%)\",\n            WebkitMask:\n              \"radial-gradient(circle at 50% 50%, transparent 61%, black 62%, black 63%, transparent 64%)\",\n            opacity: 0.5,\n          }}\n          transition={{\n            duration: 3.5,\n            repeat: Number.POSITIVE_INFINITY,\n            ease: \"linear\",\n          }}\n        />\n      </motion.div>\n\n      {/* Typography with breathing animation */}\n      <motion.div\n        animate={{\n          opacity: 1,\n          y: 0,\n        }}\n        className={cn(\"text-center\", config.spacing, config.maxWidth)}\n        initial={{ opacity: 0, y: 12 }}\n        transition={{\n          delay: 0.4,\n          duration: 1,\n          ease: [0.4, 0, 0.2, 1],\n        }}\n      >\n        <motion.h1\n          animate={{\n            opacity: 1,\n            y: 0,\n          }}\n          className={cn(\n            config.titleClass,\n            \"font-medium leading-[1.15] tracking-[-0.02em] antialiased\"\n          )}\n          initial={{ opacity: 0, y: 12 }}\n          style={{ color: \"color-mix(in srgb, var(--color) 90%, transparent)\" }}\n          transition={{\n            delay: 0.6,\n            duration: 0.8,\n            ease: [0.4, 0, 0.2, 1],\n          }}\n        >\n          <motion.span\n            animate={{\n              opacity: [0.9, 0.7, 0.9],\n            }}\n            transition={{\n              duration: 3,\n              repeat: Number.POSITIVE_INFINITY,\n              ease: [0.4, 0, 0.6, 1],\n            }}\n          >\n            {title}\n          </motion.span>\n        </motion.h1>\n\n        <motion.p\n          animate={{\n            opacity: 1,\n            y: 0,\n          }}\n          className={cn(\n            config.subtitleClass,\n            \"font-normal leading-[1.45] tracking-[-0.01em] antialiased\"\n          )}\n          initial={{ opacity: 0, y: 8 }}\n          style={{ color: \"color-mix(in srgb, var(--color) 60%, transparent)\" }}\n          transition={{\n            delay: 0.8,\n            duration: 0.8,\n            ease: [0.4, 0, 0.2, 1],\n          }}\n        >\n          <motion.span\n            animate={{\n              opacity: [0.6, 0.4, 0.6],\n            }}\n            transition={{\n              duration: 4,\n              repeat: Number.POSITIVE_INFINITY,\n              ease: [0.4, 0, 0.6, 1],\n            }}\n          >\n            {subtitle}\n          </motion.span>\n        </motion.p>\n      </motion.div>\n    </div>\n  );\n}\n"
    }
  ]
}
