{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "buttons-glass",
  "title": "Glass buttons",
  "description": "Styled buttons: the Glass set. 5 decorative buttons variations (FrostButton, TintButton, CrystalButton, SmokeButton, DepthButton) on the ai2 token system, powered by framer-motion, reduced-motion aware and sized sm to xl. Part of the free styled layer.",
  "dependencies": [
    "motion@^12.42.2"
  ],
  "registryDependencies": [
    "@ai2/tokens",
    "@ai2/glass"
  ],
  "files": [
    {
      "path": "registry/ai2/styled/buttons-glass.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { motion, useReducedMotion, type HTMLMotionProps } from \"motion/react\"\n\nimport { cn } from \"@/lib/utils\"\nimport { glassDepth } from \"@/registry/ai2/ui/glass\"\n\n/* Glass button family: 5 variations on a frosted/translucent surface theme. All\n   of them are sized, use framer-motion, take color ONLY from semantic tokens\n   (transparency via color-mix), and are reduced-motion safe. If backdrop-filter\n   is unsupported they fall back to an opaque surface.\n\n   The surface is no longer hand-made: it derives from the glassDepth scale inside\n   @ai2/glass (AGENTS.md 4.5). This file holds SMALL controls (h-8..h-12), so the\n   scale is deliberately shifted DOWN: sm/md carry the body, lg is reserved for\n   Depth alone since that is the one leaving the plane, and xl is never used\n   (there is not enough content behind a button for a 24px blur to diffuse).\n\n   twMerge trap: glassDepth carries a [box-shadow:...] (the ai2 signature = top\n   inner highlight + ambient shadow). A second shadow from the same group CANNOT\n   be written, it silently deletes the signature. Extra depth is therefore applied\n   with drop-shadow (the filter group); the signature stays intact in box-shadow.\n\n   The tint hue is info: primary/brand sits on the neutral ramp (chroma ~0.005),\n   so a \"primary tint\" would stay invisible and would give the same pixels as\n   Smoke. */\n\nexport type StyledSize = \"sm\" | \"md\" | \"lg\" | \"xl\"\n\nconst sizes: Record<StyledSize, string> = {\n  sm: \"h-8 gap-1.5 rounded-md px-3 text-sm\",\n  md: \"h-9 gap-2 rounded-lg px-4 text-sm\",\n  lg: \"h-10 gap-2 rounded-lg px-5 text-sm\",\n  xl: \"h-12 gap-2.5 rounded-xl px-6 text-base\",\n}\n\nconst base =\n  \"relative inline-flex shrink-0 select-none items-center justify-center font-medium whitespace-nowrap text-foreground outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 [&_i]:text-base [&_i]:leading-none\"\n\ntype Props = HTMLMotionProps<\"button\"> & { size?: StyledSize }\n\n/* Frost: classic frosted glass. Depth = md (8px), the same canonical default as glass.overlay. A button is this family's \"normal\" surface; departing from it needs a reason, and Frost has none. Its character comes entirely from the library signature: the inner top highlight plus a neutral border. */\nexport function FrostButton({ className, size = \"md\", children, ...props }: Props) {\n  const reduce = useReducedMotion()\n  return (\n    <motion.button\n      data-slot=\"styled-button\"\n      whileHover={reduce ? undefined : { scale: 1.03 }}\n      whileTap={reduce ? undefined : { scale: 0.97 }}\n      transition={{ type: \"spring\", stiffness: 350, damping: 22 }}\n      className={cn(\n        base,\n        sizes[size],\n        glassDepth.md,\n        \"border border-border\",\n        className\n      )}\n      {...props}\n    >\n      {children}\n    </motion.button>\n  )\n}\n\n/* Tint: translucent glass colored with info. Depth = sm (4px). The tint's job is\n   to carry color; the more the blur grows the more neutral the content behind it\n   becomes, and the hue piles onto itself and turns muddy. 4px keeps the hue\n   clear.\n   bg DELIBERATELY overrides the lib's bg-background (the tint is the surface\n   itself); the supports- variant is overridden too, otherwise in a browser that\n   supports backdrop-filter the lib's supports-[backdrop-filter]:bg-background/50\n   would take the tint back. */\nexport function TintButton({ className, size = \"md\", children, ...props }: Props) {\n  const reduce = useReducedMotion()\n  return (\n    <motion.button\n      data-slot=\"styled-button\"\n      whileHover={reduce ? undefined : { scale: 1.03 }}\n      whileTap={reduce ? undefined : { scale: 0.97 }}\n      transition={{ type: \"spring\", stiffness: 350, damping: 22 }}\n      className={cn(\n        base,\n        sizes[size],\n        glassDepth.sm,\n        \"border border-info/30 bg-[color-mix(in_oklab,var(--color-info)_16%,transparent)] supports-[backdrop-filter]:bg-[color-mix(in_oklab,var(--color-info)_16%,transparent)]\",\n        className\n      )}\n      {...props}\n    >\n      {children}\n    </motion.button>\n  )\n}\n\n/* Crystal: clear glass. Depth = sm (4px) - the LEAST diffusing in the family. It used to be blur-lg (16px), which contradicted its own name: being \"clear\" requires being able to see what is behind. The edge highlight is no longer hand-made but the library signature itself; writing a second inset on top would erase the signature. Crystal takes its character from a brighter border that foregrounds the signature. */\nexport function CrystalButton({ className, size = \"md\", children, ...props }: Props) {\n  const reduce = useReducedMotion()\n  return (\n    <motion.button\n      data-slot=\"styled-button\"\n      whileHover={reduce ? undefined : { scale: 1.03 }}\n      whileTap={reduce ? undefined : { scale: 0.97 }}\n      transition={{ type: \"spring\", stiffness: 350, damping: 22 }}\n      className={cn(\n        base,\n        sizes[size],\n        glassDepth.sm,\n        \"border border-[color-mix(in_oklab,var(--color-foreground)_20%,transparent)]\",\n        className\n      )}\n      {...props}\n    >\n      {children}\n    </motion.button>\n  )\n}\n\n/* Smoke: smoky glass darkened with foreground. Depth = md (8px). Smoke means\n   diffusion, so it sits one step above Crystal/Tint; but behind an h-9 button\n   there is not enough content for 16px to diffuse, and there the blur would\n   become an invisible cost. The surface color is foreground: what separates it\n   from Tint is the absence of hue (neutral smoke) - and that distinction only\n   works because Tint is info; had it been primary the two would be identical\n   pixels. */\nexport function SmokeButton({ className, size = \"md\", children, ...props }: Props) {\n  const reduce = useReducedMotion()\n  return (\n    <motion.button\n      data-slot=\"styled-button\"\n      whileHover={reduce ? undefined : { scale: 1.03 }}\n      whileTap={reduce ? undefined : { scale: 0.97 }}\n      transition={{ type: \"spring\", stiffness: 350, damping: 22 }}\n      className={cn(\n        base,\n        sizes[size],\n        glassDepth.md,\n        \"border border-foreground/10 bg-[color-mix(in_oklab,var(--color-foreground)_12%,transparent)] supports-[backdrop-filter]:bg-[color-mix(in_oklab,var(--color-foreground)_12%,transparent)]\",\n        className\n      )}\n      {...props}\n    >\n      {children}\n    </motion.button>\n  )\n}\n\n/* Depth: layered glass - a floating feel. Depth = lg (16px) and the DEEPEST step\n   in this file. The reason is behavior, not size: this is the only variation in\n   the family that leaves the plane (y:-2 on hover), and content to actually\n   diffuse forms underneath a rising surface. It does not go up to xl - 24px is\n   wasted on a button.\n   The extra shadow is applied with drop-shadow (the filter group), because\n   box-shadow belongs to the lib signature: writing shadow-lg there would silently\n   delete it. */\nexport function DepthButton({ className, size = \"md\", children, ...props }: Props) {\n  const reduce = useReducedMotion()\n  return (\n    <motion.button\n      data-slot=\"styled-button\"\n      whileHover={reduce ? undefined : { y: -2, scale: 1.02 }}\n      whileTap={reduce ? undefined : { scale: 0.97 }}\n      transition={{ type: \"spring\", stiffness: 350, damping: 22 }}\n      className={cn(\n        base,\n        sizes[size],\n        glassDepth.lg,\n        \"border border-border drop-shadow-lg\",\n        className\n      )}\n      {...props}\n    >\n      {children}\n    </motion.button>\n  )\n}\n",
      "type": "registry:component",
      "target": "components/ui/buttons-glass.tsx"
    }
  ],
  "categories": [
    "styled",
    "buttons"
  ],
  "type": "registry:component"
}