{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "agent-recommendation",
  "type": "registry:ui",
  "title": "Agent recommendation",
  "description": "Frames a recommendation through confidence, rationale, alternatives, and acceptance.",
  "dependencies": [
    "motion"
  ],
  "categories": [
    "agent"
  ],
  "docs": "https://motion-lexicon.pages.dev/en/components/agent-recommendation/",
  "meta": {
    "engines": [
      "motion"
    ],
    "runtimeCost": "light",
    "signature": "Confidence and alternative paths complete the decision"
  },
  "files": [
    {
      "path": "src/registry/components/agent-recommendation.tsx",
      "type": "registry:ui",
      "target": "components/motion-lexicon/agent-recommendation.tsx",
      "content": "\"use client\";\n\nimport { AnimatePresence, motion, useReducedMotion } from \"motion/react\";\nimport { useState } from \"react\";\n\nexport type RecommendationAlternative = {\n  id: string;\n  title: string;\n  signal?: string;\n};\nexport type AgentRecommendationProps = {\n  title: string;\n  description: string;\n  confidence: number;\n  alternatives?: readonly RecommendationAlternative[];\n  eyebrow?: string;\n  confidenceLabel?: string;\n  acceptLabel?: string;\n  acceptedLabel?: string;\n  alternativesLabel?: string;\n  onAccept?: () => void;\n  className?: string;\n};\n\nexport function AgentRecommendation({\n  title,\n  description,\n  confidence,\n  alternatives = [],\n  eyebrow = \"Agent recommendation\",\n  confidenceLabel = \"Confidence\",\n  acceptLabel = \"Accept\",\n  acceptedLabel = \"Accepted ✓\",\n  alternativesLabel = \"Alternatives\",\n  onAccept,\n  className = \"\",\n}: AgentRecommendationProps) {\n  const [open, setOpen] = useState(false);\n  const [accepted, setAccepted] = useState(false);\n  const reduced = useReducedMotion();\n  return (\n    <section\n      className={`w-full rounded-[10px] border border-neutral-200 bg-white p-4 text-neutral-950 dark:border-white/10 dark:bg-[#1b1b1b] dark:text-neutral-50 ${className}`}\n    >\n      <div className=\"flex items-start gap-3\">\n        <span className=\"relative mt-0.5 grid size-9 shrink-0 place-items-center rounded-lg bg-neutral-950 text-white dark:bg-neutral-50 dark:text-neutral-950\">\n          <span className=\"text-[13px]\">↗</span>\n          <motion.i\n            aria-hidden=\"true\"\n            className=\"absolute inset-0 rounded-lg border border-neutral-950 dark:border-neutral-50\"\n            animate={\n              reduced ? undefined : { scale: [1, 1.35], opacity: [0.35, 0] }\n            }\n            transition={{ duration: 1.8, repeat: Infinity }}\n          />\n        </span>\n        <div className=\"min-w-0\">\n          <span className=\"text-[11px] font-medium text-neutral-500 dark:text-neutral-400\">\n            {eyebrow}\n          </span>\n          <h3 className=\"mt-1 text-[15px] font-semibold tracking-[-.02em]\">\n            {title}\n          </h3>\n          <p className=\"mt-1 text-[11px] leading-5 text-neutral-500 dark:text-neutral-400\">\n            {description}\n          </p>\n        </div>\n      </div>\n      <div className=\"mt-4 flex items-center gap-3\">\n        <span className=\"text-[9px] text-neutral-400\">{confidenceLabel}</span>\n        <span className=\"h-1 flex-1 overflow-hidden rounded-full bg-neutral-100 dark:bg-white/8\">\n          <motion.i\n            className=\"block h-full rounded-full bg-neutral-950 dark:bg-neutral-50\"\n            initial={{ width: 0 }}\n            animate={{ width: `${Math.max(0, Math.min(100, confidence))}%` }}\n            transition={{ duration: reduced ? 0 : 0.7 }}\n          />\n        </span>\n        <code className=\"text-[9px] text-neutral-500 dark:text-neutral-400\">\n          {confidence}%\n        </code>\n      </div>\n      <div className=\"mt-4 flex items-center gap-2\">\n        <button\n          type=\"button\"\n          aria-expanded={open}\n          onClick={() => setOpen((value) => !value)}\n          className=\"min-h-11 rounded-lg px-3 text-[10px] text-neutral-500 hover:bg-neutral-100 dark:hover:bg-white/5\"\n        >\n          {alternativesLabel}\n          {alternatives.length ? ` · ${alternatives.length}` : \"\"}\n        </button>\n        <motion.button\n          type=\"button\"\n          onClick={() => {\n            setAccepted(true);\n            onAccept?.();\n          }}\n          whileTap={reduced ? undefined : { scale: 0.96 }}\n          className={`ml-auto min-h-11 rounded-lg px-4 text-[10px] font-semibold text-white ${accepted ? \"bg-emerald-600\" : \"bg-neutral-950 dark:bg-neutral-50 dark:text-neutral-950\"}`}\n        >\n          {accepted ? acceptedLabel : acceptLabel}\n        </motion.button>\n      </div>\n      <AnimatePresence initial={false}>\n        {open && alternatives.length ? (\n          <motion.div\n            initial={reduced ? false : { height: 0, opacity: 0 }}\n            animate={{ height: \"auto\", opacity: 1 }}\n            exit={{ height: 0, opacity: 0 }}\n            className=\"mt-3 grid overflow-hidden border-t border-neutral-100 pt-3 dark:border-white/8\"\n          >\n            {alternatives.map((alternative) => (\n              <button\n                key={alternative.id}\n                type=\"button\"\n                className=\"flex min-h-11 items-center rounded-lg px-2 text-left hover:bg-neutral-50 dark:hover:bg-white/5\"\n              >\n                <span className=\"text-[10px]\">{alternative.title}</span>\n                {alternative.signal ? (\n                  <small className=\"ml-auto text-[9px] text-neutral-400\">\n                    {alternative.signal}\n                  </small>\n                ) : null}\n              </button>\n            ))}\n          </motion.div>\n        ) : null}\n      </AnimatePresence>\n    </section>\n  );\n}\n"
    }
  ]
}
