{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "verified-badge",
  "type": "registry:ui",
  "registryDependencies": [],
  "dependencies": ["motion"],
  "devDependencies": [],
  "files": [
    {
      "path": "verified-badge.tsx",
      "content": "\"use client\";\n\nimport { motion, useReducedMotion } from \"motion/react\";\nimport {\n  type ComponentPropsWithoutRef,\n  type CSSProperties,\n  forwardRef,\n  useEffect,\n  useState,\n} from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst componentThemeClassName =\n  \"[--ic-background:#ffffff] [--ic-foreground:#111111] [--ic-primary:#111111] [--ic-secondary:#646b75] [--ic-surface-border:#e9edf2] [--ic-border:#e3e7ec] [--ic-card:#ffffff] [--ic-card-foreground:#111111] [--ic-muted:#f5f7fa] [--ic-muted-foreground:#6d7480] [--ic-accent:#f3f5f8] [--color-accent:var(--ic-accent)] [--color-accent-foreground:var(--ic-accent-foreground)] [--ic-accent-foreground:#111111] [--ic-input:#e3e7ec] [--ic-ring:rgba(17,17,17,0.16)] [--ic-destructive:#dc2626] [--ic-paper:#fcfcfd] [--ic-popover-foreground:#111111] [--ic-brand:#0ea5e9] [--ic-brand-soft:#bae6fd] [--ic-shadow-soft:0_18px_38px_-24px_rgba(15,23,42,0.35)] [--ic-chart-1:oklch(0.52_0.19_254)] [--ic-chart-2:oklch(0.74_0.11_232)] [--ic-chart-3:oklch(0.42_0.16_262)] [--ic-chart-4:oklch(0.84_0.07_228)] [--ic-chart-5:oklch(0.62_0.14_240)] [--color-background:var(--ic-background)] [--color-foreground:var(--ic-foreground)] [--color-primary:var(--ic-primary)] [--color-secondary:var(--ic-secondary)] [--color-border:var(--ic-border)] [--color-card:var(--ic-card)] [--color-card-foreground:var(--ic-card-foreground)] [--color-muted:var(--ic-muted)] [--color-muted-foreground:var(--ic-muted-foreground)] [--color-accent:var(--ic-accent)] [--color-accent-foreground:var(--ic-accent-foreground)] [--color-input:var(--ic-input)] [--color-ring:var(--ic-ring)] [--color-destructive:var(--ic-destructive)] [--color-paper:var(--ic-paper)] [--color-popover-foreground:var(--ic-popover-foreground)] [--color-brand:var(--ic-brand)] [--color-brand-soft:var(--ic-brand-soft)] [--color-chart-1:var(--ic-chart-1)] [--color-chart-2:var(--ic-chart-2)] [--color-chart-3:var(--ic-chart-3)] [--color-chart-4:var(--ic-chart-4)] [--color-chart-5:var(--ic-chart-5)] [--verified-badge-color:var(--ic-brand)] [--verified-badge-gold:#ca8a04] [--verified-badge-neutral:var(--ic-muted-foreground)] dark:[--ic-background:#111111] dark:[--ic-foreground:#f6f3ec] dark:[--ic-primary:#f6f3ec] dark:[--ic-secondary:#cbc6bb] dark:[--ic-surface-border:#2a2a25] dark:[--ic-border:#2b2a25] dark:[--ic-card:#111111] dark:[--ic-card-foreground:#f6f3ec] dark:[--ic-muted:#171716] dark:[--ic-muted-foreground:#9a958a] dark:[--ic-accent:#1a1a18] [--color-accent:var(--ic-accent)] [--color-accent-foreground:var(--ic-accent-foreground)] dark:[--ic-accent-foreground:#f6f3ec] dark:[--ic-input:#2b2a25] dark:[--ic-ring:rgba(246,243,236,0.18)] dark:[--ic-destructive:#f87171] dark:[--ic-paper:#171716] dark:[--ic-popover-foreground:#f6f3ec] dark:[--ic-brand:#38bdf8] dark:[--ic-brand-soft:#0c4a6e] dark:[--ic-shadow-soft:0_20px_44px_-28px_rgba(0,0,0,0.6)] dark:[--ic-chart-1:oklch(0.68_0.17_250)] dark:[--ic-chart-2:oklch(0.82_0.09_225)] dark:[--ic-chart-3:oklch(0.58_0.15_260)] dark:[--ic-chart-4:oklch(0.75_0.12_235)] dark:[--ic-chart-5:oklch(0.88_0.06_220)] dark:[--verified-badge-gold:#eab308]\";\n\nexport type VerifiedBadgeVariant = \"shimmer\" | \"static\";\nexport type VerifiedBadgeSize = \"sm\" | \"md\" | \"lg\";\nexport type VerifiedBadgeTone = \"brand\" | \"gold\" | \"neutral\";\n\nconst verifiedBadgeSizePixels = {\n  sm: 18,\n  md: 22,\n  lg: 28,\n} as const satisfies Record<VerifiedBadgeSize, number>;\n\nconst verifiedBadgeToneClassNames = {\n  brand: \"text-[var(--verified-badge-color)]\",\n  gold: \"text-[var(--verified-badge-gold)]\",\n  neutral: \"text-[var(--verified-badge-neutral)]\",\n} as const satisfies Record<VerifiedBadgeTone, string>;\n\nexport function resolveVerifiedBadgePixelSize(\n  size: VerifiedBadgeSize | number = \"md\"\n): number {\n  if (typeof size === \"number\") {\n    if (!Number.isFinite(size) || size <= 0) {\n      return verifiedBadgeSizePixels.md;\n    }\n\n    return size;\n  }\n\n  return verifiedBadgeSizePixels[size];\n}\n\nexport function resolveVerifiedBadgeStrokeWidth(pixelSize: number): number {\n  return Math.max(2, Math.min(4, pixelSize * 0.16));\n}\n\nexport function resolveVerifiedBadgeA11yProps({\n  ariaLabel = \"Verified\",\n  decorative = false,\n}: {\n  ariaLabel?: string;\n  decorative?: boolean;\n}) {\n  if (decorative) {\n    return { \"aria-hidden\": true as const };\n  }\n\n  return {\n    \"aria-label\": ariaLabel,\n    role: \"img\" as const,\n  };\n}\n\nexport function shouldRenderVerifiedBadgeShimmer({\n  mounted = true,\n  prefersReducedMotion,\n  variant,\n}: {\n  mounted?: boolean;\n  prefersReducedMotion: boolean | null;\n  variant: VerifiedBadgeVariant;\n}) {\n  return mounted && variant === \"shimmer\" && prefersReducedMotion !== true;\n}\n\nexport interface VerifiedBadgeProps\n  extends Omit<\n    ComponentPropsWithoutRef<\"span\">,\n    \"children\" | \"role\" | \"aria-hidden\"\n  > {\n  /** @default false */\n  decorative?: boolean;\n  /** Preset or explicit pixel width/height. @default \"md\" (22px) */\n  size?: VerifiedBadgeSize | number;\n  /** @default brand */\n  tone?: VerifiedBadgeTone;\n  /** @default shimmer */\n  variant?: VerifiedBadgeVariant;\n}\n\nconst SCALLOP_PATH =\n  \"M20.396 11c-.018-.646-.215-1.275-.57-1.816-.354-.54-.852-.972-1.438-1.246.223-.607.27-1.264.14-1.897-.131-.634-.437-1.218-.882-1.687-.47-.445-1.053-.75-1.687-.882-.633-.13-1.29-.083-1.897.14-.273-.587-.704-1.086-1.245-1.44S11.647 1.62 11 1.604c-.646.017-1.273.213-1.813.568s-.969.854-1.24 1.44c-.608-.223-1.267-.272-1.902-.14-.635.13-1.22.436-1.69.882-.445.47-.749 1.055-.878 1.688-.13.633-.08 1.29.144 1.896-.587.274-1.087.705-1.443 1.245-.356.54-.555 1.17-.574 1.817.02.647.218 1.276.574 1.817.356.54.856.972 1.443 1.245-.224.606-.274 1.263-.144 1.896.13.634.433 1.218.877 1.688.47.443 1.054.747 1.687.878.633.132 1.29.084 1.897-.136.274.586.705 1.084 1.246 1.439.54.354 1.17.551 1.816.569.647-.016 1.276-.213 1.817-.567s.972-.854 1.245-1.44c.604.239 1.266.296 1.903.164.636-.132 1.22-.447 1.68-.907.46-.46.776-1.044.908-1.681s.075-1.299-.165-1.903c.586-.274 1.084-.705 1.439-1.246.354-.54.551-1.17.569-1.816z\";\n\nconst scallopMaskSvg = `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 22 22\"><path fill=\"white\" d=\"${SCALLOP_PATH}\"/></svg>`;\nconst scallopMaskUrl = `url(\"data:image/svg+xml,${encodeURIComponent(scallopMaskSvg)}\")`;\n\nconst scallopMaskStyle: CSSProperties = {\n  maskImage: scallopMaskUrl,\n  WebkitMaskImage: scallopMaskUrl,\n  maskSize: \"100% 100%\",\n  WebkitMaskSize: \"100% 100%\",\n  maskRepeat: \"no-repeat\",\n  WebkitMaskRepeat: \"no-repeat\",\n};\n\nconst ScallopShape = ({ className }: { className?: string }) => (\n  <svg aria-hidden=\"true\" className={className} viewBox=\"0 0 22 22\">\n    <path d={SCALLOP_PATH} fill=\"currentColor\" />\n  </svg>\n);\n\nconst ScallopShimmer = ({ className }: { className?: string }) => {\n  return (\n    <span\n      aria-hidden=\"true\"\n      className={cn(\n        \"pointer-events-none absolute inset-0 overflow-hidden\",\n        className\n      )}\n      style={scallopMaskStyle}\n    >\n      <motion.span\n        animate={{ x: [\"-100%\", \"200%\"] }}\n        className=\"absolute inset-0\"\n        initial={{ x: \"-100%\" }}\n        style={{\n          background:\n            \"linear-gradient(105deg, transparent 0%, rgba(255,255,255,0.55) 50%, transparent 100%)\",\n        }}\n        transition={{\n          duration: 0.5,\n          repeat: Number.POSITIVE_INFINITY,\n          repeatDelay: 1.5,\n          ease: \"easeInOut\",\n        }}\n      />\n    </span>\n  );\n};\n\nconst VerifiedBadge = forwardRef<HTMLSpanElement, VerifiedBadgeProps>(\n  function VerifiedBadge(\n    {\n      variant = \"shimmer\",\n      size = \"md\",\n      tone = \"brand\",\n      decorative = false,\n      className,\n      \"aria-label\": ariaLabel = \"Verified\",\n      style,\n      ...props\n    },\n    ref\n  ) {\n    const [mounted, setMounted] = useState(false);\n    const prefersReducedMotion = useReducedMotion();\n\n    useEffect(() => {\n      setMounted(true);\n    }, []);\n\n    const pixelSize = resolveVerifiedBadgePixelSize(size);\n    const checkSize = pixelSize * 0.5;\n    const strokeWidth = resolveVerifiedBadgeStrokeWidth(pixelSize);\n    const a11yProps = resolveVerifiedBadgeA11yProps({ ariaLabel, decorative });\n    const showShimmer = shouldRenderVerifiedBadgeShimmer({\n      mounted,\n      prefersReducedMotion,\n      variant,\n    });\n\n    return (\n      <span\n        className={cn(\n          componentThemeClassName,\n          \"relative inline-block shrink-0 align-middle\",\n          verifiedBadgeToneClassNames[tone],\n          className\n        )}\n        ref={ref}\n        style={{ width: pixelSize, height: pixelSize, ...style }}\n        {...props}\n        {...a11yProps}\n      >\n        <ScallopShape className=\"absolute inset-0 h-full w-full\" />\n        {showShimmer ? <ScallopShimmer /> : null}\n\n        <svg\n          aria-hidden=\"true\"\n          className=\"absolute inset-0 z-10 m-auto\"\n          fill=\"none\"\n          stroke=\"white\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n          strokeWidth={strokeWidth}\n          style={{ width: checkSize, height: checkSize }}\n          viewBox=\"0 0 24 24\"\n        >\n          <polyline points=\"5 12.5 10 17.5 19 7.5\" />\n        </svg>\n      </span>\n    );\n  }\n);\n\nVerifiedBadge.displayName = \"VerifiedBadge\";\n\nexport { VerifiedBadge };\nexport default VerifiedBadge;\n",
      "type": "registry:ui"
    }
  ],
  "title": "Verified Badge",
  "description": "X-style verified scallop with shimmer or static variants, size presets, brand/gold/neutral tones, and reduced-motion aware animation."
}
