{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "plan-card",
  "type": "registry:ui",
  "title": "Plan Card",
  "description": "Plan approval with a step checklist, plus the checkpoint-restore strip for the timeline.",
  "dependencies": [
    "lucide-react"
  ],
  "registryDependencies": [
    "https://seamui.dev/r/utils.json",
    "https://seamui.dev/r/button.json"
  ],
  "files": [
    {
      "path": "registry/seam/ui/plan-card.tsx",
      "content": "\"use client\"\n\nimport type * as React from \"react\"\nimport { Check, Flag, ListTodo, RotateCcw, X } from \"lucide-react\"\n\nimport { cn } from \"@/lib/utils\"\nimport { Button } from \"./button\"\n\n// Plan mode's moment of trust: the agent proposes, you inspect and approve.\n// The proposal is a raised key; steps sit flat inside it; once decided the\n// card settles into a receipt. The same card renders live execution progress\n// by flipping `done` on steps.\n\ntype PlanDecision = \"approved\" | \"rejected\"\n\nconst RECEIPT: Record<PlanDecision, { icon: React.ReactNode; label: string }> =\n  {\n    approved: { icon: <Check className=\"size-3.5\" />, label: \"Plan approved\" },\n    rejected: { icon: <X className=\"size-3.5\" />, label: \"Plan rejected\" },\n  }\n\nfunction PlanCard({\n  title = \"Proposed plan\",\n  description,\n  decision,\n  onApprove,\n  onReject,\n  className,\n  children,\n  ...props\n}: React.ComponentProps<\"div\"> & {\n  title?: React.ReactNode\n  description?: React.ReactNode\n  /** Set once resolved — replaces the actions with a settled receipt. */\n  decision?: PlanDecision\n  onApprove?: () => void\n  onReject?: () => void\n}) {\n  const pending = decision === undefined\n\n  return (\n    <div\n      data-slot=\"plan-card\"\n      data-decision={decision}\n      role=\"group\"\n      aria-label=\"Proposed plan\"\n      className={cn(\n        \"bg-card text-card-foreground w-full max-w-md space-y-3 rounded-xl squircle border border-border/60 p-4 shadow-resting\",\n        className\n      )}\n      {...props}\n    >\n      <div className=\"flex min-w-0 items-start gap-2.5\">\n        <ListTodo\n          aria-hidden\n          className=\"text-muted-foreground mt-0.5 size-4 shrink-0\"\n        />\n        <div className=\"min-w-0\">\n          <div className=\"text-sm font-medium\">{title}</div>\n          {description ? (\n            <div className=\"text-muted-foreground text-xs\">{description}</div>\n          ) : null}\n        </div>\n      </div>\n\n      <ol data-slot=\"plan-card-steps\" className=\"space-y-1.5\">\n        {children}\n      </ol>\n\n      <div aria-live=\"polite\">\n        {pending ? (\n          <div\n            data-slot=\"plan-card-actions\"\n            className=\"flex flex-wrap items-center gap-2\"\n          >\n            <Button size=\"sm\" onClick={() => onApprove?.()}>\n              Approve plan\n            </Button>\n            <Button size=\"sm\" variant=\"ghost\" onClick={() => onReject?.()}>\n              Reject\n            </Button>\n          </div>\n        ) : (\n          <div\n            data-slot=\"plan-card-receipt\"\n            className={cn(\n              \"bg-muted text-muted-foreground flex w-fit items-center gap-1.5 rounded-md squircle border border-border/60 px-2.5 py-1 text-xs font-medium shadow-well\",\n              decision === \"rejected\" && \"text-destructive\"\n            )}\n          >\n            {RECEIPT[decision].icon}\n            {RECEIPT[decision].label}\n          </div>\n        )}\n      </div>\n    </div>\n  )\n}\n\n// One checklist row. `index` renders as a quiet tabular number until `done`\n// swaps it for a check and the row settles muted.\nfunction PlanCardStep({\n  index,\n  done = false,\n  className,\n  children,\n  ...props\n}: React.ComponentProps<\"li\"> & {\n  index?: number\n  done?: boolean\n}) {\n  return (\n    <li\n      data-slot=\"plan-card-step\"\n      data-done={done || undefined}\n      className={cn(\n        \"flex items-baseline gap-2.5 text-sm\",\n        done && \"text-muted-foreground\",\n        className\n      )}\n      {...props}\n    >\n      <span\n        aria-hidden\n        className=\"text-muted-foreground flex w-4 shrink-0 justify-center text-xs tabular-nums\"\n      >\n        {done ? <Check className=\"size-3.5 self-center\" /> : (index ?? \"•\")}\n      </span>\n      <span className=\"min-w-0\">\n        {children}\n        {done ? <span className=\"sr-only\"> (completed)</span> : null}\n      </span>\n    </li>\n  )\n}\n\n// The timeline strip: settled history with a Restore key — not a demand, so\n// it's debossed muted rather than raised.\nfunction PlanCardCheckpoint({\n  label = \"Checkpoint saved\",\n  onRestore,\n  className,\n  ...props\n}: React.ComponentProps<\"div\"> & {\n  label?: React.ReactNode\n  onRestore?: () => void\n}) {\n  return (\n    <div\n      data-slot=\"plan-card-checkpoint\"\n      className={cn(\n        \"bg-muted text-muted-foreground flex w-full max-w-md items-center gap-2 rounded-md squircle border border-border/60 px-2.5 py-1.5 text-xs shadow-well\",\n        className\n      )}\n      {...props}\n    >\n      <Flag aria-hidden className=\"size-3.5 shrink-0\" />\n      <span className=\"min-w-0 flex-1 truncate\">{label}</span>\n      {/* The strip is a debossed well; Restore rises out of it as an embossed\n          key (secondary), not a flat ghost. */}\n      <Button\n        variant=\"secondary\"\n        size=\"sm\"\n        className=\"h-6 gap-1 px-2 text-xs\"\n        onClick={() => onRestore?.()}\n      >\n        <RotateCcw className=\"size-3\" /> Restore\n      </Button>\n    </div>\n  )\n}\n\nexport { PlanCard, PlanCardStep, PlanCardCheckpoint, type PlanDecision }\n",
      "type": "registry:ui",
      "target": "components/ui/plan-card.tsx"
    }
  ]
}