{
  "name": "SourceCard",
  "package": "@magicblocksai/ui",
  "file": "packages/ui/src/components/SourceCard.tsx",
  "chapterTag": "20 Explainability",
  "chapter": "20-explainability.html",
  "sectionId": "source-card",
  "elName": "SourceCard",
  "demoUrl": "https://brand.magicblocks.ai/components/20-explainability#source-card",
  "hasLiveDemo": false,
  "description": "The kit's knowledge card — `label · value · meta` head that expands to a\nsource body. The body can be supplied eagerly (`details`) or **loaded on\nfirst open** (`loadDetails`), which is how a trace renders knowledge that\nisn't carried inline: the card owns the collapsed → loading → loaded →\nerror+retry lifecycle and caches the result.",
  "useClient": true,
  "interactivity": "interactive",
  "namedExports": [
    {
      "name": "SourceCard",
      "isPrincipal": true,
      "isType": false
    },
    {
      "name": "SourceCardProps",
      "isPrincipal": false,
      "isType": true
    }
  ],
  "importStatement": "import { SourceCard } from \"@magicblocksai/ui\";",
  "props": [
    {
      "name": "tone",
      "optional": true,
      "type": "TraceEventTone",
      "doc": "Tone band — left-edge accent + open-state border. Defaults to `neutral`. The same six tones as the rest of the trace family."
    },
    {
      "name": "label",
      "optional": true,
      "type": "ReactNode",
      "doc": "Short eyebrow above the value — the source name (\"Security policy v2\")."
    },
    {
      "name": "value",
      "optional": true,
      "type": "ReactNode",
      "doc": "One-line summary under the label (\"Reset links expire after 24h\")."
    },
    {
      "name": "meta",
      "optional": true,
      "type": "ReactNode",
      "doc": "Trailing meta caption — similarity / score / freshness (\"0.92 sim\")."
    },
    {
      "name": "details",
      "optional": true,
      "type": "ReactNode",
      "doc": "Expanded body, supplied **eagerly**. When set, the card opens to this immediately — no loading state. Takes precedence over `loadDetails`."
    },
    {
      "name": "loadDetails",
      "optional": true,
      "type": "() => Promise<ReactNode>",
      "doc": "Expanded body, **loaded on first open** and cached. The card owns the collapsed → loading → loaded → error+retry lifecycle. Return e.g. a `<SourcePassage>`. Memoise this (its identity is read once)."
    },
    {
      "name": "open",
      "optional": true,
      "type": "boolean",
      "doc": "Controlled open state. Pair with `onOpenChange`."
    },
    {
      "name": "defaultOpen",
      "optional": true,
      "type": "boolean",
      "doc": "Default open state when uncontrolled. Defaults to `false`."
    },
    {
      "name": "onOpenChange",
      "optional": true,
      "type": "(open: boolean) => void",
      "doc": "Open-state change callback (controlled + uncontrolled)."
    },
    {
      "name": "errorLabel",
      "optional": true,
      "type": "ReactNode",
      "doc": "Message shown when `loadDetails` rejects. Default `\"Couldn't load this source.\"`."
    },
    {
      "name": "retryLabel",
      "optional": true,
      "type": "ReactNode",
      "doc": "Retry-button label. Default `\"Retry\"`."
    }
  ],
  "classesUsed": [
    "source-card",
    "source-card-body",
    "source-card-chevron",
    "source-card-details",
    "source-card-error",
    "source-card-error-msg",
    "source-card-label",
    "source-card-loading",
    "source-card-meta",
    "source-card-retry",
    "source-card-shimmer",
    "source-card-trigger",
    "source-card-value",
    "title"
  ],
  "examples": {
    "react": "<SourceCard\n  tone=\"security\"\n  label=\"Security policy v2 · §4.1\"\n  value=\"Rate-limit password attempts\"\n  meta=\"0.88 sim\"\n  loadDetails={() => fetchPassage(\"sec-4-1\")}\n/>",
    "html": null,
    "css": ".source-card {\n  border: 1px solid var(--hair);\n  border-left: 3px solid var(--trace-tone, var(--hair));\n  border-radius: var(--r-sm);\n  background: var(--bg-paper);\n  overflow: hidden;\n  transition: border-color var(--dur-2) var(--ease);\n}\n\n.source-card-body {\n  min-width: 0;\n  display: inline-flex;\n  align-items: baseline;\n  gap: 6px;\n  flex-wrap: wrap;\n}\n\n.source-card-chevron {\n  width: 8px; height: 8px; position: relative; flex-shrink: 0;\n  color: var(--fg-faint);\n  transition: transform var(--dur-2) var(--ease);\n}\n\n.source-card-details {\n  padding: 8px 12px 10px;\n  border-top: 1px solid var(--hair);\n  background: var(--trace-tone-soft, var(--bg-warm));\n  font: 400 12.5px/1.5 var(--f-body);\n  color: var(--fg);\n}\n\n.source-card-error {\n  display: flex; align-items: center; justify-content: space-between; gap: var(--s-2);\n}\n\n.source-card-error-msg { color: var(--trace-tone-text, var(--fg-soft)); }\n\n.source-card-label { font-weight: 600; color: var(--fg); }\n\n.source-card-loading { display: flex; flex-direction: column; gap: 6px; }\n\n.source-card-meta { font: 400 11.5px/1 var(--f-mono); color: var(--fg-faint); }\n\n.source-card-retry {\n  appearance: none; flex-shrink: 0;\n  background: transparent;\n  border: 1px solid var(--trace-tone-border, var(--hair));\n  border-radius: var(--r-xs);\n  padding: 3px 10px;\n  font: 500 11.5px/1 var(--f-body);\n  color: var(--fg);\n  cursor: pointer;\n  transition: background var(--dur-2) var(--ease);\n}\n\n.source-card-shimmer {\n  height: 9px;\n  border-radius: var(--r-xs);\n  background: linear-gradient(90deg,\n    color-mix(in oklab, var(--fg) 6%, transparent) 0%,\n    color-mix(in oklab, var(--fg) 10%, transparent) 50%,\n    color-mix(in oklab, var(--fg) 6%, transparent) 100%);\n  background-size: 200% 100%;\n  animation: skel-shimmer 1.8s ease-in-out infinite;\n}\n\n.source-card-trigger {\n  appearance: none;\n  display: grid;\n  grid-template-columns: 1fr auto auto;\n  align-items: center;\n  gap: var(--s-2);\n  width: 100%;\n  padding: 8px 12px;\n  background: transparent;\n  border: 0;\n  text-align: left;\n  cursor: pointer;\n  color: var(--fg);\n  font: 400 13px/1.4 var(--f-body);\n}\n\n.source-card-value { color: var(--fg); }\n\n.title { font: 700 32px/1.15 var(--f-display); letter-spacing: -0.015em; margin: 0; }"
  }
}
