{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "message-dock",
  "title": "Message dock",
  "description": "Message dock is a production-ready interactive component from BJORK UI, packaged for shadcn registries.",
  "dependencies": [
    "clsx",
    "framer-motion",
    "next-themes",
    "tailwind-merge"
  ],
  "files": [
    {
      "path": "components/bjork-ui/hud/message-dock.tsx",
      "content": "\"use client\";\n\nimport { cn } from \"@/lib/utils\";\nimport { motion, useReducedMotion, AnimatePresence } from \"framer-motion\";\nimport { useTheme } from \"next-themes\";\nimport { useState, useRef, useEffect } from \"react\";\n\nexport interface Character {\n  id?: string | number;\n  emoji: string;\n  name: string;\n  online: boolean;\n  backgroundColor?: string;\n  gradientFrom?: string;\n  gradientTo?: string;\n  gradientColors?: string;\n  avatar?: string; // Optional image URL\n}\n\nexport interface MessageDockProps {\n  // Character data\n  characters?: Character[];\n  \n  // Event handlers\n  onMessageSend?: (message: string, character: Character, characterIndex: number) => void;\n  onCharacterSelect?: (character: Character, characterIndex: number) => void;\n  onDockToggle?: (isExpanded: boolean) => void;\n  \n  // Styling & layout\n  className?: string;\n  expandedWidth?: number;\n  position?: \"bottom\" | \"top\";\n  positionStrategy?: \"fixed\" | \"absolute\";\n  showSparkleButton?: boolean;\n  showMenuButton?: boolean;\n  \n  // Animation settings\n  enableAnimations?: boolean;\n  animationDuration?: number;\n  \n  // UI customization\n  placeholder?: (characterName: string) => string;\n  theme?: \"light\" | \"dark\" | \"auto\";\n  \n  // Advanced settings\n  autoFocus?: boolean;\n  closeOnClickOutside?: boolean;\n  closeOnEscape?: boolean;\n  closeOnSend?: boolean;\n}\n\nconst defaultCharacters: Character[] = [\n  { emoji: \"✨\", name: \"Sparkle\", online: false },\n  {\n    emoji: \"🧙‍♂️\",\n    name: \"Wizard\",\n    online: true,\n    backgroundColor: \"bg-green-300\",\n    gradientFrom: \"from-green-300\",\n    gradientTo: \"to-green-100\",\n    gradientColors: \"#86efac, #dcfce7\",\n  },\n  {\n    emoji: \"🦄\",\n    name: \"Unicorn\",\n    online: true,\n    backgroundColor: \"bg-purple-300\",\n    gradientFrom: \"from-purple-300\",\n    gradientTo: \"to-purple-100\",\n    gradientColors: \"#c084fc, #f3e8ff\",\n  },\n  {\n    emoji: \"🐵\",\n    name: \"Monkey\",\n    online: true,\n    backgroundColor: \"bg-yellow-300\",\n    gradientFrom: \"from-yellow-300\",\n    gradientTo: \"to-yellow-100\",\n    gradientColors: \"#fde047, #fefce8\",\n  },\n  {\n    emoji: \"🤖\",\n    name: \"Robot\",\n    online: false,\n    backgroundColor: \"bg-red-300\",\n    gradientFrom: \"from-red-300\",\n    gradientTo: \"to-red-100\",\n    gradientColors: \"#fca5a5, #fef2f2\",\n  },\n];\n\nconst dockPalettes = {\n  dark: {\n    surface: \"linear-gradient(180deg,#181818,#111111)\",\n    border: \"rgba(255,255,255,0.07)\",\n    shadow: \"0 18px 42px rgba(0,0,0,0.22)\",\n    divider: \"rgba(237,237,237,0.12)\",\n    text: \"text-[#ededed]\",\n    placeholder: \"placeholder:text-[#ededed]/38\",\n    icon: \"text-[#ededed]/66\",\n    iconHover: \"hover:bg-[#232323]\",\n    avatar: \"bg-[linear-gradient(180deg,#242424,#171717)] text-[#ededed]\",\n    avatarSelected: \"bg-[#eee9df] text-[#171717]\",\n    avatarBorder: \"border-[#2a2a2a]\",\n    send: \"bg-[#eee9df] text-[#171717] hover:bg-[#f6f2ea]\",\n    online: \"bg-[#ec5c13] border-[#111111]\",\n  },\n  light: {\n    surface: \"linear-gradient(180deg,#f4f1e9,#eee9df)\",\n    border: \"rgba(42,36,28,0.10)\",\n    shadow: \"0 14px 30px rgba(58,49,36,0.07)\",\n    divider: \"rgba(23,23,23,0.14)\",\n    text: \"text-[#171717]\",\n    placeholder: \"placeholder:text-[#171717]/40\",\n    icon: \"text-[#171717]/62\",\n    iconHover: \"hover:bg-[#e5ded1]\",\n    avatar: \"bg-[linear-gradient(180deg,#fffaf1,#e8dfd0)] text-[#171717]\",\n    avatarSelected: \"bg-[#111111] text-[#ededed]\",\n    avatarBorder: \"border-[#d8d0c2]\",\n    send: \"bg-[#111111] text-[#ededed] hover:bg-[#242424]\",\n    online: \"bg-[#ec5c13] border-[#eee9df]\",\n  },\n} as const;\n\nexport function MessageDock({\n  characters = defaultCharacters,\n  onMessageSend,\n  onCharacterSelect,\n  onDockToggle,\n  className,\n  expandedWidth = 448,\n  position = \"bottom\",\n  positionStrategy = \"fixed\",\n  showSparkleButton = true,\n  showMenuButton = true,\n  enableAnimations = true,\n  animationDuration = 1,\n  placeholder = (name: string) => `Message ${name}...`,\n  theme = \"light\",\n  autoFocus = true,\n  closeOnClickOutside = true,\n  closeOnEscape = true,\n  closeOnSend = true,\n}: MessageDockProps) {\n  const shouldReduceMotion = useReducedMotion();\n  const [expandedCharacter, setExpandedCharacter] = useState<number | null>(\n    null\n  );\n  const [messageInput, setMessageInput] = useState(\"\");\n  const dockRef = useRef<HTMLDivElement>(null);\n  const [collapsedWidth, setCollapsedWidth] = useState<number>(266); // Default fallback\n  const [hasInitialized, setHasInitialized] = useState(false);\n  const { resolvedTheme } = useTheme();\n\n  // Measure the TRUE initial collapsed width only once on first mount\n  useEffect(() => {\n    if (dockRef.current && !hasInitialized) {\n      const width = dockRef.current.offsetWidth;\n      if (width > 0) {\n        setCollapsedWidth(width);\n        setHasInitialized(true);\n      }\n    }\n  }, [hasInitialized]);\n\n  // Click outside handler\n  useEffect(() => {\n    if (!closeOnClickOutside) return;\n    \n    const handleClickOutside = (event: MouseEvent) => {\n      if (dockRef.current && !dockRef.current.contains(event.target as Node)) {\n        setExpandedCharacter(null);\n        setMessageInput(\"\");\n        onDockToggle?.(false);\n      }\n    };\n\n    document.addEventListener(\"mousedown\", handleClickOutside);\n    return () => {\n      document.removeEventListener(\"mousedown\", handleClickOutside);\n    };\n  }, [closeOnClickOutside, onDockToggle]);\n\n  const containerVariants = {\n    hidden: {\n      opacity: 0,\n      y: 100,\n      scale: 0.8,\n    },\n    visible: {\n      opacity: 1,\n      y: 0,\n      scale: 1,\n      transition: {\n        type: \"spring\",\n        stiffness: 300,\n        damping: 30,\n        mass: 0.8,\n        staggerChildren: 0.1,\n        delayChildren: 0.2,\n      },\n    },\n  };\n\n  const hoverAnimation = shouldReduceMotion\n    ? { scale: 1.02 }\n    : {\n        scale: 1.05,\n        y: -8,\n        transition: {\n          type: \"spring\",\n          stiffness: 400,\n          damping: 25,\n        },\n      };\n\n  const handleCharacterClick = (index: number) => {\n    const character = characters[index];\n    \n    if (expandedCharacter === index) {\n      setExpandedCharacter(null);\n      setMessageInput(\"\");\n      onDockToggle?.(false);\n    } else {\n      setExpandedCharacter(index);\n      onCharacterSelect?.(character, index);\n      onDockToggle?.(true);\n    }\n  };\n\n  const handleSendMessage = () => {\n    if (messageInput.trim() && expandedCharacter !== null) {\n      const character = characters[expandedCharacter];\n      \n      // Call the onMessageSend callback\n      onMessageSend?.(messageInput, character, expandedCharacter);\n      \n      setMessageInput(\"\");\n      \n      if (closeOnSend) {\n        setExpandedCharacter(null);\n        onDockToggle?.(false);\n      }\n    }\n  };\n\n  const selectedCharacter =\n    expandedCharacter !== null ? characters[expandedCharacter] : null;\n  const isExpanded = expandedCharacter !== null;\n  const activeTheme = theme === \"auto\" ? resolvedTheme : theme;\n  const isDark = activeTheme === \"dark\";\n  const palette = isDark ? dockPalettes.dark : dockPalettes.light;\n\n  const positionClasses = cn(\n    positionStrategy === \"absolute\" ? \"absolute\" : \"fixed\",\n    \"left-1/2 z-50 -translate-x-1/2\",\n    position === \"top\" ? \"top-6\" : \"bottom-6\"\n  );\n\n  return (\n    <motion.div\n      ref={dockRef}\n      className={cn(positionClasses, className)}\n      initial={enableAnimations ? \"hidden\" : \"visible\"}\n      animate=\"visible\"\n      variants={enableAnimations ? containerVariants : {}}\n    >\n      <motion.div\n        className=\"rounded-full border px-4 py-2\"\n        style={{\n          borderColor: palette.border,\n          boxShadow: palette.shadow,\n        }}\n        animate={{\n          width: isExpanded ? expandedWidth : collapsedWidth,\n          background: palette.surface,\n        }}\n        transition={enableAnimations ? { \n          type: \"spring\", \n          stiffness: isExpanded ? 300 : 500, \n          damping: isExpanded ? 30 : 35, \n          mass: isExpanded ? 0.8 : 0.6,\n          background: {\n            duration: 0.2 * animationDuration,\n            ease: \"easeInOut\"\n          }\n        } : { duration: 0 }}\n      >\n        <div className=\"flex items-center gap-2 relative\">\n          {/* Sparkle button - slides out when expanded */}\n          {showSparkleButton && (\n            <motion.div\n            className=\"flex items-center justify-center\"\n            animate={{\n              opacity: isExpanded ? 0 : 1,\n              x: isExpanded ? -20 : 0,\n              scale: isExpanded ? 0.8 : 1,\n            }}\n            transition={{\n              type: \"spring\",\n              stiffness: 400,\n              damping: 30,\n              delay: isExpanded ? 0 : 0, // Remove delay when coming back\n            }}\n          >\n            <motion.button\n              className={cn(\"flex h-12 w-12 cursor-pointer items-center justify-center rounded-full transition-colors\", palette.iconHover)}\n              whileHover={\n                !isExpanded\n                  ? {\n                      scale: 1.02,\n                      y: -2,\n                      transition: {\n                        type: \"spring\",\n                        stiffness: 400,\n                        damping: 25,\n                      },\n                    }\n                  : undefined\n              }\n              whileTap={{ scale: 0.95 }}\n              aria-label=\"Sparkle\"\n            >\n              <span className={cn(\"text-2xl\", palette.icon)}>✨</span>\n            </motion.button>\n          </motion.div>\n          )}\n\n          {/* First separator */}\n          <motion.div\n            className=\"mr-2 -ml-2 h-6 w-px\"\n            style={{ backgroundColor: palette.divider }}\n            animate={{\n              opacity: isExpanded ? 0 : 1,\n              scaleY: isExpanded ? 0 : 1,\n            }}\n            transition={{\n              type: \"spring\",\n              stiffness: 300,\n              damping: 30,\n              delay: isExpanded ? 0 : 0.3,\n            }}\n          />\n\n          {/* Character buttons */}\n          {characters.slice(1, -1).map((character, index) => {\n            const actualIndex = index + 1;\n            const isSelected = expandedCharacter === actualIndex;\n\n            return (\n              <motion.div\n                key={character.name}\n                className={cn(\n                  \"relative\",\n                  isSelected && isExpanded && \"absolute left-1 top-1 z-20\"\n                )}\n                style={{\n                  // When selected and expanded, don't take up space in flex layout\n                  width: isSelected && isExpanded ? 0 : \"auto\",\n                  minWidth: isSelected && isExpanded ? 0 : \"auto\",\n                  overflow: \"visible\",\n                }}\n                animate={{\n                  opacity: isExpanded && !isSelected ? 0 : 1,\n                  y: isExpanded && !isSelected ? 60 : 0,\n                  scale: isExpanded && !isSelected ? 0.8 : 1,\n                  // Only use translateX for non-selected or non-expanded\n                  x: isSelected && isExpanded ? 0 : 0,\n                }}\n                transition={{\n                  type: \"spring\",\n                  stiffness: 400,\n                  damping: 30,\n                  delay:\n                    isExpanded && !isSelected\n                      ? index * 0.05\n                      : isExpanded\n                      ? 0.1\n                      : 0, // Remove delay when coming back - immediate return\n                }}\n              >\n                <motion.button\n                  className={cn(\n                    \"relative flex h-10 w-10 cursor-pointer items-center justify-center rounded-full border text-xl\",\n                    isSelected && isExpanded ? palette.avatarSelected : palette.avatar,\n                    palette.avatarBorder\n                  )}\n                  onClick={() => handleCharacterClick(actualIndex)}\n                  whileHover={!isExpanded ? hoverAnimation : { scale: 1.05 }}\n                  whileTap={{ scale: 0.95 }}\n                  aria-label={`Message ${character.name}`}\n                >\n                  <span className=\"text-2xl\">{character.emoji}</span>\n\n                  {/* Online indicator */}\n                  {character.online && (\n                    <motion.div\n                      className={cn(\"absolute bottom-0 right-0 h-3 w-3 rounded-full border-2\", palette.online)}\n                      initial={{ scale: 0 }}\n                      animate={{ scale: isExpanded && !isSelected ? 0 : 1 }}\n                      transition={{\n                        delay: isExpanded\n                          ? isSelected\n                            ? 0.3\n                            : 0\n                          : (index + 1) * 0.1 + 0.5,\n                        type: \"spring\",\n                        stiffness: 500,\n                        damping: 30,\n                      }}\n                    />\n                  )}\n                </motion.button>\n              </motion.div>\n            );\n          })}\n\n          {/* Text input - slides out from center */}\n          <AnimatePresence>\n            {isExpanded && (\n              <motion.input\n                type=\"text\"\n                value={messageInput}\n                onChange={(e) => setMessageInput(e.target.value)}\n                onKeyDown={(e) => {\n                  if (e.key === \"Enter\") {\n                    handleSendMessage();\n                  }\n                  if (e.key === \"Escape\" && closeOnEscape) {\n                    setExpandedCharacter(null);\n                    setMessageInput(\"\");\n                    onDockToggle?.(false);\n                  }\n                }}\n                placeholder={placeholder(selectedCharacter?.name || \"\")}\n                className={cn(\n                  \"absolute left-14 right-0 z-50 w-[300px] border-none bg-transparent text-sm font-medium outline-none\",\n                  palette.text,\n                  palette.placeholder\n                )}\n                autoFocus={autoFocus}\n                initial={{ opacity: 0, x: 20 }}\n                animate={{ \n                  opacity: 1, \n                  x: 0,\n                  transition: {\n                    delay: 0.2,\n                    type: \"spring\",\n                    stiffness: 400,\n                    damping: 30,\n                  }\n                }}\n                exit={{ \n                  opacity: 0,\n                  transition: {\n                    duration: 0.1,\n                    ease: \"easeOut\"\n                  }\n                }}\n              />\n            )}\n          </AnimatePresence>\n\n          {/* Second separator */}\n          <motion.div\n            className=\"ml-2 -mr-2 h-6 w-px\"\n            style={{ backgroundColor: palette.divider }}\n            animate={{\n              opacity: isExpanded ? 0 : 1,\n              scaleY: isExpanded ? 0 : 1,\n            }}\n            transition={{\n              type: \"spring\",\n              stiffness: 300,\n              damping: 30,\n              delay: isExpanded ? 0 : 0, // Remove delay when coming back\n            }}\n          />\n\n          {/* Menu button / Send button - transforms in place */}\n          {showMenuButton && (\n            <motion.div\n              className={cn(\n                \"flex items-center justify-center z-20\",\n                isExpanded && \"absolute right-0\"\n              )}\n              transition={{ type: \"spring\", stiffness: 400, damping: 30 }}\n            >\n              <AnimatePresence mode=\"wait\">\n                {!isExpanded ? (\n                <motion.button\n                  key=\"menu\"\n                  className={cn(\"flex h-12 w-12 cursor-pointer items-center justify-center rounded-full transition-colors\", palette.iconHover)}\n                  whileHover={{\n                    scale: 1.02,\n                    y: -2,\n                    transition: {\n                      type: \"spring\",\n                      stiffness: 400,\n                      damping: 25,\n                    },\n                  }}\n                  whileTap={{ scale: 0.95 }}\n                  aria-label=\"Menu\"\n                  initial={{ opacity: 0, rotate: -90 }}\n                  animate={{ opacity: 1, rotate: 0 }}\n                  exit={{ opacity: 0, rotate: 90 }}\n                  transition={{ type: \"spring\", stiffness: 400, damping: 30 }}\n                >\n                  <svg\n                    width=\"20\"\n                    height=\"20\"\n                    viewBox=\"0 0 24 24\"\n                    fill=\"none\"\n                    stroke=\"currentColor\"\n                    strokeWidth=\"2\"\n                    className={palette.icon}\n                  >\n                    <line x1=\"3\" y1=\"6\" x2=\"21\" y2=\"6\" />\n                    <line x1=\"3\" y1=\"12\" x2=\"21\" y2=\"12\" />\n                    <line x1=\"3\" y1=\"18\" x2=\"21\" y2=\"18\" />\n                  </svg>\n                </motion.button>\n                ) : (\n                <motion.button\n                  key=\"send\"\n                  onClick={handleSendMessage}\n                  className={cn(\"relative z-30 flex h-10 w-10 cursor-pointer items-center justify-center rounded-full transition-colors disabled:opacity-45\", palette.send)}\n                  whileHover={{ scale: 1.1 }}\n                  whileTap={{ scale: 0.9 }}\n                  disabled={!messageInput.trim()}\n                  initial={{ opacity: 0, scale: 0, rotate: -90 }}\n                  animate={{ \n                    opacity: 1, \n                    scale: 1, \n                    rotate: 0,\n                    transition: {\n                      delay: 0.25,\n                      type: \"spring\",\n                      stiffness: 400,\n                      damping: 30,\n                    }\n                  }}\n                  exit={{ \n                    opacity: 0, \n                    scale: 0, \n                    rotate: 90,\n                    transition: {\n                      duration: 0.1,\n                      ease: \"easeIn\"\n                    }\n                  }}\n                >\n                  <svg\n                    width=\"16\"\n                    height=\"16\"\n                    viewBox=\"0 0 24 24\"\n                    fill=\"none\"\n                    stroke=\"currentColor\"\n                    strokeWidth=\"2\"\n                    className=\"text-current\"\n                  >\n                    <path d=\"m22 2-7 20-4-9-9-4z\" />\n                    <path d=\"M22 2 11 13\" />\n                  </svg>\n                </motion.button>\n              )}\n            </AnimatePresence>\n          </motion.div>\n          )}\n        </div>\n      </motion.div>\n    </motion.div>\n  );\n}\n",
      "type": "registry:component",
      "target": "@components/bjork-ui/hud/message-dock.tsx"
    },
    {
      "path": "lib/utils.ts",
      "content": "import { clsx, type ClassValue } from \"clsx\"\nimport { twMerge } from \"tailwind-merge\"\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs))\n}\n",
      "type": "registry:lib",
      "target": "@lib/utils.ts"
    }
  ],
  "cssVars": {
    "light": {
      "bjork-bg": "#f7f3ea",
      "bjork-surface": "#fffcf6",
      "bjork-surface-muted": "rgba(250, 246, 237, 0.94)",
      "bjork-surface-hover": "#f5efe3",
      "bjork-surface-active": "#efe7d8",
      "bjork-panel": "#f8f2e7",
      "bjork-menu": "rgba(255, 252, 246, 0.98)",
      "bjork-field": "rgba(255, 252, 246, 0.96)",
      "bjork-field-muted": "rgba(248, 242, 231, 0.82)",
      "bjork-field-inset": "rgba(239, 231, 216, 0.72)",
      "bjork-error-bg": "#fff0e8",
      "bjork-text": "#171717",
      "bjork-text-strong": "rgba(23, 23, 23, 0.9)",
      "bjork-text-medium": "rgba(23, 23, 23, 0.72)",
      "bjork-text-muted": "rgba(23, 23, 23, 0.52)",
      "bjork-text-soft": "rgba(23, 23, 23, 0.36)",
      "bjork-text-faint": "rgba(23, 23, 23, 0.22)",
      "bjork-inverted-text": "#fff8f0",
      "bjork-border": "#eee6db",
      "bjork-border-muted": "#f5ede2",
      "bjork-border-strong": "#e1d7c8",
      "bjork-thumb": "#a49b8e",
      "bjork-track": "#ded6ca",
      "bjork-accent": "#ec7d43",
      "bjork-accent-hover": "#f0935f",
      "bjork-accent-soft": "rgba(236, 125, 67, 0.1)",
      "bjork-accent-muted": "rgba(236, 125, 67, 0.2)",
      "bjork-accent-badge": "rgba(236, 125, 67, 0.16)",
      "bjork-accent-badge-foreground": "#8d421d",
      "bjork-accent-foreground": "#3f2112",
      "bjork-shadow-surface": "inset 0 7px 14px rgba(88, 72, 49, 0.045), inset 0 0.5px 0.5px rgba(255, 255, 255, 0.92), inset 1px 0 0 rgba(88, 72, 49, 0.026), inset -1px 0 0 rgba(255, 255, 255, 0.68), 0 14px 22px -9px rgba(66, 52, 33, 0.11)",
      "bjork-shadow-soft": "inset 0 1px 0 rgba(88, 72, 49, 0.045), inset 0 0.5px 0.5px rgba(255, 255, 255, 0.86)",
      "bjork-shadow-panel": "inset 0 1px 0 rgba(88, 72, 49, 0.04), inset 1px 0 0 rgba(88, 72, 49, 0.024), inset -1px 0 0 rgba(255, 255, 255, 0.64), 0 18px 38px -30px rgba(66, 52, 33, 0.2)",
      "bjork-shadow-menu": "inset 0 1px 0 rgba(88, 72, 49, 0.04), inset 0 12px 24px rgba(88, 72, 49, 0.022), inset 1px 0 0 rgba(88, 72, 49, 0.024), inset -1px 0 0 rgba(255, 255, 255, 0.62), 0 22px 44px -26px rgba(66, 52, 33, 0.22)",
      "bjork-shadow-inset": "inset 0 1px 10px rgba(88, 72, 49, 0.12), inset 0 0.5px 0.5px rgba(255, 255, 255, 0.72)",
      "bjork-ring-offset": "#f7f3ea"
    },
    "dark": {
      "bjork-bg": "#111111",
      "bjork-surface": "#121212",
      "bjork-surface-muted": "rgba(22, 22, 22, 0.92)",
      "bjork-surface-hover": "#161616",
      "bjork-surface-active": "#202020",
      "bjork-panel": "#0d0d0d",
      "bjork-menu": "rgba(18, 18, 18, 0.98)",
      "bjork-field": "rgba(18, 18, 18, 0.95)",
      "bjork-field-muted": "rgba(18, 18, 18, 0.55)",
      "bjork-field-inset": "rgba(9, 9, 9, 0.75)",
      "bjork-error-bg": "#130d0a",
      "bjork-text": "#ededed",
      "bjork-text-strong": "rgba(237, 237, 237, 0.9)",
      "bjork-text-medium": "rgba(237, 237, 237, 0.72)",
      "bjork-text-muted": "rgba(237, 237, 237, 0.52)",
      "bjork-text-soft": "rgba(237, 237, 237, 0.36)",
      "bjork-text-faint": "rgba(237, 237, 237, 0.22)",
      "bjork-inverted-text": "#080808",
      "bjork-border": "#232323",
      "bjork-border-muted": "#1c1c1c",
      "bjork-border-strong": "#343434",
      "bjork-thumb": "#626262",
      "bjork-track": "#090909",
      "bjork-accent": "#ec5c13",
      "bjork-accent-hover": "#f07832",
      "bjork-accent-soft": "rgba(236, 92, 19, 0.12)",
      "bjork-accent-muted": "rgba(236, 92, 19, 0.24)",
      "bjork-accent-badge": "#ec5c13",
      "bjork-accent-badge-foreground": "#fff2ea",
      "bjork-accent-foreground": "#fff2ea",
      "bjork-shadow-surface": "inset 0 7px 14px rgba(255, 255, 255, 0.03), inset 0 0.5px 0.5px rgba(255, 255, 255, 0.06), 0 14px 20px -6px rgba(0, 0, 0, 0.45)",
      "bjork-shadow-soft": "inset 0 1px 0 rgba(255, 255, 255, 0.045)",
      "bjork-shadow-panel": "inset 0 1px 0 rgba(255, 255, 255, 0.035), 0 18px 36px -28px rgba(0, 0, 0, 0.9)",
      "bjork-shadow-menu": "inset 0 1px 0 rgba(255, 255, 255, 0.055), inset 0 12px 24px rgba(255, 255, 255, 0.018), inset 0 -18px 26px rgba(0, 0, 0, 0.24), 0 22px 42px -22px rgba(0, 0, 0, 0.9)",
      "bjork-shadow-inset": "inset 0 1px 10px rgba(0, 0, 0, 0.45)",
      "bjork-ring-offset": "#080808"
    }
  },
  "css": {
    ".bjork-range": {
      "box-shadow": "inset 0 1px 1px rgba(255, 255, 255, 0.04), 0 0 14px rgba(189, 69, 20, 0.06)"
    },
    ".bjork-range::-webkit-slider-thumb": {
      "appearance": "none",
      "width": "16px",
      "height": "8px",
      "border": "0",
      "border-radius": "999px",
      "background": "var(--bjork-thumb)",
      "box-shadow": "inset 0 1px 0 rgba(255, 255, 255, 0.18), 0 0 0 1px rgba(0, 0, 0, 0.42)"
    },
    ".bjork-range::-moz-range-thumb": {
      "width": "16px",
      "height": "8px",
      "border": "0",
      "border-radius": "999px",
      "background": "var(--bjork-thumb)",
      "box-shadow": "inset 0 1px 0 rgba(255, 255, 255, 0.18), 0 0 0 1px rgba(0, 0, 0, 0.42)"
    },
    ".bjork-layered-button-accent, .bjork-layered-button-raised": {
      "position": "relative",
      "isolation": "isolate",
      "appearance": "none",
      "overflow": "hidden",
      "border": "0",
      "border-radius": "13px",
      "box-shadow": "inset 0 1px 0 #ffffff38, 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a",
      "transition": "filter 150ms ease-out, box-shadow 150ms ease-out"
    },
    ".bjork-layered-button-accent::after, .bjork-layered-button-raised::after": {
      "position": "absolute",
      "inset": "0",
      "pointer-events": "none",
      "content": "\"\"",
      "border": "1.5px solid transparent",
      "border-radius": "inherit",
      "background": "linear-gradient(#ffffffb8, #0000003d 41% 75%, #ffffff47) border-box",
      "mix-blend-mode": "overlay",
      "-webkit-mask-image": "linear-gradient(#000, #000), linear-gradient(#000, #000)",
      "mask-image": "linear-gradient(#000, #000), linear-gradient(#000, #000)",
      "-webkit-mask-clip": "padding-box, border-box",
      "mask-clip": "padding-box, border-box",
      "-webkit-mask-origin": "padding-box, border-box",
      "mask-origin": "padding-box, border-box",
      "-webkit-mask-composite": "xor",
      "mask-composite": "exclude"
    },
    ".bjork-layered-button-accent": {
      "color": "oklch(100% 0 0)",
      "text-shadow": "0 -1px #00000040",
      "background": "radial-gradient(ellipse at -20px top, rgba(255, 255, 255, 0.14), transparent), linear-gradient(180deg, #ec5c13 0%, #ec5c13 62%, color-mix(in oklab, #ec5c13 84%, black 16%) 100%)"
    },
    ".bjork-layered-button-raised": {
      "color": "oklch(100% 0 0)",
      "text-shadow": "0 -1px #00000026",
      "background": "radial-gradient(ellipse at -20px top, #ffffff38, #fff0), linear-gradient(180deg, oklch(0.1881 0.006 265), oklch(0.5493 0.0081 265))"
    },
    ".dark .bjork-layered-button-raised": {
      "color": "oklch(0.2574 0.0056 265)",
      "text-shadow": "0 -1px #00000026",
      "background": "radial-gradient(ellipse at -20px top, #ffffff38, #fff0), linear-gradient(180deg, color-mix(in oklab, oklch(0.9674 0.0013 265) 80%, oklch(0.2574 0.0056 265) 20%), color-mix(in oklab, oklch(0.669 0.0107 265) 80%, oklch(0.2574 0.0056 265) 20%))"
    },
    "@media (hover: hover)": {
      ".bjork-layered-button-accent:hover": {
        "filter": "brightness(1.08) saturate(1.04)"
      },
      ".bjork-layered-button-raised:hover": {
        "filter": "brightness(1.08) contrast(0.9)"
      }
    }
  },
  "meta": {
    "collection": "Interactive",
    "registryUrl": "https://ui.isaiahbjork.com/message-dock.json",
    "installCommand": "npx shadcn@latest add https://ui.isaiahbjork.com/message-dock.json"
  },
  "type": "registry:component"
}