{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "badge",
  "title": "Badge",
  "description": "Badge: a status chip carried by fill alone — a tint of the tone at 12–15%, label inked toward the hue, and a sharp radius from --brand-radius-sm. Five tones (neutral, info, success, warning, danger) plus an optional icon slot. No runtime dependencies.",
  "registryDependencies": [
    "https://sc1m.vercel.app/r/tokens.json",
    "https://sc1m.vercel.app/r/cn.json"
  ],
  "files": [
    {
      "path": "src/components/ui/badge/badge.tsx",
      "content": "import * as React from \"react\";\nimport { cn } from \"@/lib/cn\";\n\ntype Tone = \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\";\n\n/**\n * The tinted tones share one formula, so a tone is three custom properties:\n *   --badge-tone  the hue\n *   --badge-wash  how much of it lands in the fill\n *   --badge-ink   how far the label is pulled from --fg toward the hue\n *\n * Same shape as the banner's wash, at heavier percentages — a badge is small\n * enough that the banner's 7% would read as an off-white smudge.\n */\nconst mix = [\n  \"bg-[color-mix(in_oklab,var(--badge-tone)_var(--badge-wash),var(--color-bg))]\",\n  \"text-[color-mix(in_oklab,var(--badge-tone)_var(--badge-ink),var(--color-fg))]\",\n].join(\" \");\n\n/**\n * Wash and ink are tuned per tone, not shared. Warning washes hardest (15%)\n * and inks lightest (50%) because yellow carries the least weight of the four\n * at any given percentage; green needs 14% where blue and red need 12%.\n * Flattening these to one pair would make warning the faintest chip on screen.\n */\nconst tones: Record<Tone, string> = {\n  // neutral is not a tint of anything — it is the absence of a state, so it\n  // takes the plain surface rather than a 0% mix of some arbitrary hue\n  neutral: \"bg-surface text-fg-muted\",\n  info: `[--badge-tone:var(--color-info)] [--badge-wash:12%] [--badge-ink:55%] ${mix}`,\n  success: `[--badge-tone:var(--color-success)] [--badge-wash:14%] [--badge-ink:55%] ${mix}`,\n  warning: `[--badge-tone:var(--color-warning)] [--badge-wash:15%] [--badge-ink:50%] ${mix}`,\n  danger: `[--badge-tone:var(--color-danger)] [--badge-wash:12%] [--badge-ink:50%] ${mix}`,\n};\n\nexport interface BadgeProps extends React.ComponentPropsWithRef<\"span\"> {\n  tone?: Tone;\n  /**\n   * Optional leading glyph. Study 3A is deliberately glyphless — the fill\n   * carries the state on its own — so this stays empty unless a badge has to\n   * survive greyscale, or sits somewhere the tint alone is ambiguous.\n   *\n   * The slot fixes the size and stops the icon shrinking, so a 16px or 24px\n   * source glyph still lands at the label's optical weight. It inherits the\n   * tone's ink through currentColor.\n   */\n  icon?: React.ReactNode;\n}\n\nexport function Badge({\n  tone = \"neutral\",\n  icon,\n  className,\n  children,\n  ...props\n}: BadgeProps) {\n  return (\n    <span\n      className={cn(\n        \"inline-flex h-7 items-center gap-[5px] rounded-sm px-[11px] text-xs font-semibold\",\n        // 2px in sc1m, which is the radius the study was drawn at — taken from\n        // the token rather than hardcoded so a rounder brand stays rounder\n        tones[tone],\n        className,\n      )}\n      {...props}\n    >\n      {icon ? (\n        <span\n          aria-hidden\n          className=\"grid size-3 shrink-0 place-items-center [&>*]:size-full\"\n        >\n          {icon}\n        </span>\n      ) : null}\n      {children}\n    </span>\n  );\n}\n",
      "type": "registry:ui"
    }
  ],
  "type": "registry:ui"
}