{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "recommendation-card",
  "type": "registry:component",
  "title": "Recommendation card",
  "description": "Agent suggestion with a confidence meter and actions.",
  "categories": [
    "ai-interface"
  ],
  "registryDependencies": [
    "https://irisui.dev/r/foundation.json",
    "https://irisui.dev/r/button.json",
    "https://irisui.dev/r/entity-chip.json",
    "https://irisui.dev/r/value-pill.json"
  ],
  "files": [
    {
      "path": "src/registry/components/recommendation-card/recommendation-card.tsx",
      "content": "\"use client\";\n\nimport { useState } from \"react\";\nimport { Button, type ButtonVariant } from \"../button/button\";\nimport { EntityChip } from \"../entity-chip/entity-chip\";\nimport { ValuePill } from \"../value-pill/value-pill\";\n\n/* ─────────────────────────────────────────────────────────\n * RECOMMENDATION CARD\n * The card holds its shape. Pressing \"Alternatives\" opens a\n * new drawer listing the other options; picking one promotes\n * it to the recommendation. The primary action confirms.\n * ───────────────────────────────────────────────────────── */\n\nexport type RecommendationOption = {\n  key: string;\n  body: React.ReactNode;\n  short: string;\n  signal: number;\n  tone: string;\n  label: string;\n  cta: string;\n  ctaVariant: ButtonVariant;\n};\n\nexport type RecommendationLabels = {\n  title: string;\n  alternatives: string;\n  otherOptions: string;\n  accepted: string;\n};\n\nconst DEFAULT_LABELS: RecommendationLabels = {\n  title: \"Want me to move this project to Ship?\",\n  alternatives: \"Alternatives\",\n  otherOptions: \"Other options\",\n  accepted: \"Accepted\",\n};\n\n/* a CapyDB project outgrowing its plan */\nconst OPTIONS: RecommendationOption[] = [\n  {\n    key: \"high\",\n    body: (\n      <>\n        Move <EntityChip name=\"shop\" /> to Ship with <ValuePill tone=\"green\">7-day restore</ValuePill>\n      </>\n    ),\n    short: \"Move shop to Ship · 7-day restore\",\n    signal: 3,\n    tone: \"var(--green)\",\n    label: \"High confidence\",\n    cta: \"Accept\",\n    ctaVariant: \"accent\",\n  },\n  {\n    key: \"review\",\n    body: (\n      <>\n        Test migration 0042 on a <ValuePill>preview database</ValuePill> first.\n      </>\n    ),\n    short: \"Test on a preview database first\",\n    signal: 2,\n    tone: \"var(--orange)\",\n    label: \"Needs review\",\n    cta: \"Configure\",\n    ctaVariant: \"primary\",\n  },\n  {\n    key: \"none\",\n    body: (\n      <>\n        Stay on <span className=\"font-medium text-ink\">Vibe</span> and revisit when storage passes 2 GiB.\n      </>\n    ),\n    short: \"Stay on Vibe until 2 GiB\",\n    signal: 0,\n    tone: \"var(--ink-3)\",\n    label: \"No signal\",\n    cta: \"Stay on Vibe\",\n    ctaVariant: \"primary\",\n  },\n];\n\nfunction Meter({ signal, tone }: { signal: number; tone: string }) {\n  return (\n    <span className=\"flex items-end gap-0.5\">\n      {[0, 1, 2].map((bar) => (\n        <span\n          key={bar}\n          className=\"w-1 rounded-full transition-colors duration-300\"\n          style={{ height: 10, background: bar < signal ? tone : \"var(--line-strong)\" }}\n        />\n      ))}\n    </span>\n  );\n}\n\nexport default function RecommendationCard({\n  options = OPTIONS,\n  labels,\n}: {\n  options?: RecommendationOption[];\n  labels?: Partial<RecommendationLabels>;\n  variant?: string;\n} = {}) {\n  const t = { ...DEFAULT_LABELS, ...labels };\n  const [selected, setSelected] = useState(0);\n  const [open, setOpen] = useState(false);\n  const [accepted, setAccepted] = useState(false);\n\n  const active = options[selected];\n  const others = options.map((o, i) => ({ o, i })).filter(({ i }) => i !== selected);\n\n  return (\n    <div className=\"w-full max-w-95 overflow-hidden rounded-card bg-surface shadow-card\">\n      <div className=\"p-3\">\n        <span className=\"text-[14px] font-medium text-ink\">{t.title}</span>\n        <p\n          key={active.key}\n          className=\"mt-1.5 min-h-12 animate-recommendation-card-body-in text-[13px] leading-relaxed text-ink-2\"\n        >\n          {active.body}\n        </p>\n      </div>\n\n      {/* alternatives drawer — a distinctly new section of the card */}\n      <div\n        className=\"grid transition-[grid-template-rows,opacity] duration-300\"\n        style={{\n          gridTemplateRows: open ? \"1fr\" : \"0fr\",\n          opacity: open ? 1 : 0,\n          transitionTimingFunction: \"cubic-bezier(0.16, 1, 0.3, 1)\",\n        }}\n      >\n        <div className=\"overflow-hidden\">\n          <div className=\"border-t border-line bg-surface px-2 py-2\">\n            <p className=\"px-1.5 pb-1 text-[11px] font-medium text-ink-3\">{t.otherOptions}</p>\n            {others.map(({ o, i }) => (\n              <button\n                key={o.key}\n                type=\"button\"\n                onClick={() => {\n                  setSelected(i);\n                  setAccepted(false);\n                }}\n                className=\"flex w-full items-center gap-2.5 rounded-control px-1.5 py-1.5\n                  text-left transition-colors duration-100 hover:bg-hover\"\n              >\n                <Meter signal={o.signal} tone={o.tone} />\n                <span className=\"min-w-0 flex-1 truncate text-[12.5px] text-ink\">{o.short}</span>\n                <span className=\"shrink-0 text-[11px] text-ink-3\">{o.label}</span>\n              </button>\n            ))}\n          </div>\n        </div>\n      </div>\n\n      <div className=\"flex p-2.5 items-center justify-between gap-3 bg-surface\">\n        <span className=\"flex items-center gap-2\">\n          <Meter signal={active.signal} tone={active.tone} />\n          <span className=\"text-[12.5px] font-medium text-ink-2\">{active.label}</span>\n        </span>\n\n        <span className=\"-mr-0.5 flex items-center gap-2\">\n          <Button\n            variant=\"secondary\"\n            size=\"sm\"\n            aria-expanded={open}\n            onClick={() => setOpen((current) => !current)}\n            className=\"px-2.5 text-[12.5px]\"\n          >\n            {t.alternatives}\n          </Button>\n          <Button\n            variant={accepted ? \"success\" : active.ctaVariant}\n            size=\"sm\"\n            onClick={() => setAccepted(true)}\n            className=\"text-[12.5px]\"\n          >\n            {accepted ? t.accepted : active.cta}\n          </Button>\n        </span>\n      </div>\n    </div>\n  );\n}\n",
      "type": "registry:component",
      "target": "@components/iris/recommendation-card/recommendation-card.tsx"
    }
  ],
  "docs": "Docs and live preview: https://irisui.dev/components/recommendation-card",
  "meta": {
    "kind": "component",
    "group": "AI interface",
    "export": "RecommendationCard",
    "docs": "https://irisui.dev/components/recommendation-card"
  }
}
