{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "card",
  "title": "Card",
  "description": "The dualtone card from the Notra dashboard: a grey shell with a lifted body, an eyebrow title with an optional hint, a readout and an action slot, plus a flat variant, a section heading and an empty state.",
  "dependencies": [
    "@hugeicons/core-free-icons",
    "@hugeicons/react",
    "cn"
  ],
  "registryDependencies": [
    "card",
    "spinner",
    "https://ui.usenotra.com/r/notra-tooltip.json",
    "https://ui.usenotra.com/r/shimmer.json"
  ],
  "files": [
    {
      "path": "registry/notra/card/components/card-labels.tsx",
      "content": "\"use client\";\n\nimport { createContext, useContext, useMemo } from \"react\";\n\nimport { CARD_LABELS } from \"../constants/card\";\nimport type { CardLabels, CardLabelsProviderProps } from \"../types/card\";\n\nconst CardLabelsContext = createContext<CardLabels>(CARD_LABELS);\n\nexport function CardLabelsProvider({\n  labels,\n  children,\n}: CardLabelsProviderProps) {\n  const parent = useContext(CardLabelsContext);\n  const value = useMemo(() => ({ ...parent, ...labels }), [parent, labels]);\n  return (\n    <CardLabelsContext.Provider value={value}>\n      {children}\n    </CardLabelsContext.Provider>\n  );\n}\n\nexport function useCardLabels(): CardLabels {\n  return useContext(CardLabelsContext);\n}\n",
      "type": "registry:component",
      "target": "components/card/components/card-labels.tsx"
    },
    {
      "path": "registry/notra/card/components/instrument-grid.tsx",
      "content": "import { cn } from \"cn\";\n\nimport type { InstrumentGridProps } from \"../types/card\";\n\nexport function InstrumentGrid({ children, className }: InstrumentGridProps) {\n  return <div className={cn(\"grid gap-3\", className)}>{children}</div>;\n}\n",
      "type": "registry:component",
      "target": "components/card/components/instrument-grid.tsx"
    },
    {
      "path": "registry/notra/card/components/instrument-module.tsx",
      "content": "\"use client\";\n\nimport { InformationCircleIcon } from \"@hugeicons/core-free-icons\";\nimport { HugeiconsIcon } from \"@hugeicons/react\";\nimport { cn } from \"cn\";\n\nimport {\n  Card,\n  CardAction,\n  CardContent,\n  CardDescription,\n  CardHeader,\n  CardTitle,\n} from \"@/components/ui/card\";\nimport { Spinner } from \"@/components/ui/spinner\";\n\nimport { Shimmer } from \"../../shimmer/components/shimmer\";\nimport {\n  Tooltip,\n  TooltipContent,\n  TooltipTrigger,\n} from \"../../tooltip/components/tooltip\";\nimport { INSTRUMENT_SURFACE_CLASSES } from \"../constants/card\";\nimport type {\n  InstrumentEmptyProps,\n  InstrumentHintProps,\n  InstrumentModuleProps,\n} from \"../types/card\";\nimport { useCardLabels } from \"./card-labels\";\n\nfunction EyebrowHint({ hint }: InstrumentHintProps) {\n  const { moreInfo } = useCardLabels();\n  return (\n    <Tooltip>\n      <TooltipTrigger\n        aria-label={moreInfo}\n        className=\"text-muted-foreground hover:text-foreground inline-flex cursor-help\"\n      >\n        <HugeiconsIcon icon={InformationCircleIcon} size={14} />\n      </TooltipTrigger>\n      <TooltipContent side=\"top\">\n        <div className=\"max-w-64 text-xs\">{hint}</div>\n      </TooltipContent>\n    </Tooltip>\n  );\n}\n\nfunction DualtoneModule({\n  eyebrow,\n  description,\n  hint,\n  readout,\n  action,\n  children,\n  className,\n  bodyClassName,\n  variant,\n  bareBody = false,\n}: InstrumentModuleProps & {\n  variant: Exclude<InstrumentModuleProps[\"variant\"], \"flat\" | undefined>;\n}) {\n  const tableHeader = variant === \"table\" || variant === \"table-compact\";\n  const surface = INSTRUMENT_SURFACE_CLASSES[bareBody ? \"bare\" : variant];\n\n  return (\n    <Card\n      className={cn(\n        \"min-w-0 flex-1 overflow-visible rounded-2xl bg-transparent p-0 ring-0\",\n        (tableHeader || !bareBody) && \"gap-0\",\n        !bareBody && \"border-shell-border bg-shell border p-0.5\",\n        className\n      )}\n    >\n      <CardHeader className={surface.header}>\n        <CardTitle className={tableHeader ? \"text-sm\" : undefined}>\n          <span className=\"inline-flex items-center gap-1.5\">\n            {eyebrow}\n            {hint ? <EyebrowHint hint={hint} /> : null}\n          </span>\n        </CardTitle>\n        {description && <CardDescription>{description}</CardDescription>}\n        {(readout || action) && (\n          <CardAction\n            className={cn(\n              \"flex min-w-0 items-center gap-2\",\n              tableHeader && \"row-span-1 self-center\"\n            )}\n          >\n            {readout && (\n              <span className=\"text-muted-foreground truncate text-xs tabular-nums\">\n                {readout}\n              </span>\n            )}\n            {action}\n          </CardAction>\n        )}\n      </CardHeader>\n      <CardContent className={cn(surface.content, bodyClassName)}>\n        {children}\n      </CardContent>\n    </Card>\n  );\n}\n\nexport function InstrumentModule({\n  eyebrow,\n  description,\n  hint,\n  readout,\n  action,\n  children,\n  className,\n  bodyClassName,\n  variant = \"flat\",\n  bareBody = false,\n}: InstrumentModuleProps) {\n  if (variant !== \"flat\") {\n    return (\n      <DualtoneModule\n        action={action}\n        bareBody={bareBody}\n        bodyClassName={bodyClassName}\n        className={className}\n        description={description}\n        eyebrow={eyebrow}\n        hint={hint}\n        readout={readout}\n        variant={variant}\n      >\n        {children}\n      </DualtoneModule>\n    );\n  }\n\n  return (\n    <Card className={cn(\"min-w-0 flex-1\", className)}>\n      <CardHeader className=\"items-center\">\n        <CardTitle className=\"text-sm\">\n          <span className=\"inline-flex items-center gap-1.5\">\n            {eyebrow}\n            {hint ? <EyebrowHint hint={hint} /> : null}\n          </span>\n        </CardTitle>\n        {(readout || action) && (\n          <CardAction className=\"flex min-w-0 items-center gap-2 self-center\">\n            {readout && (\n              <span className=\"text-muted-foreground truncate text-xs tabular-nums first-letter:uppercase\">\n                {readout}\n              </span>\n            )}\n            {action}\n          </CardAction>\n        )}\n      </CardHeader>\n      <CardContent className={cn(\"min-w-0 flex-1\", bodyClassName)}>\n        {children}\n      </CardContent>\n    </Card>\n  );\n}\n\nexport function InstrumentSection({\n  eyebrow,\n  description,\n  hint,\n  readout,\n  action,\n  children,\n  className,\n  bodyClassName,\n}: InstrumentModuleProps) {\n  return (\n    <section\n      className={cn(\n        \"@container/instrument flex min-w-0 flex-col gap-3\",\n        className\n      )}\n    >\n      <div\n        className={cn(\n          \"flex min-w-0 flex-col gap-2 @min-[32rem]/instrument:flex-row @min-[32rem]/instrument:justify-between\",\n          description\n            ? \"@min-[32rem]/instrument:items-start\"\n            : \"@min-[32rem]/instrument:items-center\"\n        )}\n      >\n        <div\n          className={cn(\n            \"min-w-0\",\n            description\n              ? \"space-y-1\"\n              : (readout || action) && \"flex h-7 items-center\"\n          )}\n        >\n          <h2\n            className={cn(\n              \"text-foreground flex items-center gap-1.5 text-sm font-medium\",\n              !description && (readout || action) && \"leading-none\"\n            )}\n          >\n            {eyebrow}\n            {hint ? <EyebrowHint hint={hint} /> : null}\n          </h2>\n          {description ? (\n            <p className=\"text-muted-foreground text-sm\">{description}</p>\n          ) : null}\n        </div>\n        {(readout || action) && (\n          <div className=\"flex w-full min-w-0 flex-wrap items-center gap-2 @min-[32rem]/instrument:w-auto @min-[32rem]/instrument:justify-end\">\n            {readout && (\n              <span className=\"text-muted-foreground truncate text-xs tabular-nums first-letter:uppercase\">\n                {readout}\n              </span>\n            )}\n            {action}\n          </div>\n        )}\n      </div>\n      <div className={cn(\"min-w-0 flex-1\", bodyClassName)}>{children}</div>\n    </section>\n  );\n}\n\nexport function InstrumentEmpty({\n  message,\n  className,\n  busy = false,\n  action,\n  preview,\n}: InstrumentEmptyProps) {\n  return (\n    <div\n      aria-busy={busy}\n      aria-live={busy ? \"polite\" : undefined}\n      className={cn(\n        \"relative flex h-full min-h-56 flex-col items-center justify-center gap-3 text-center\",\n        preview && \"overflow-hidden\",\n        className\n      )}\n    >\n      {preview ? (\n        <div\n          aria-hidden\n          className=\"pointer-events-none absolute inset-0 [mask-image:linear-gradient(to_bottom,transparent_0%,black_24%,black_70%,transparent_100%)] opacity-40 select-none\"\n        >\n          {preview}\n        </div>\n      ) : null}\n      {message || busy ? (\n        <div\n          className={cn(\n            \"relative z-10 flex items-center justify-center gap-2\",\n            preview &&\n              \"bg-background/85 rounded-full px-3 py-1.5 shadow-xs backdrop-blur-[2px]\"\n          )}\n        >\n          {busy ? <Spinner className=\"text-muted-foreground\" /> : null}\n          <p className=\"text-muted-foreground text-sm first-letter:uppercase\">\n            {busy && message ? <Shimmer>{message}</Shimmer> : message}\n          </p>\n        </div>\n      ) : null}\n      {action && !busy ? <div className=\"relative z-10\">{action}</div> : null}\n    </div>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/card/components/instrument-module.tsx"
    },
    {
      "path": "registry/notra/card/components/instrument-reveal.tsx",
      "content": "\"use client\";\n\nimport { cn } from \"cn\";\nimport type { CSSProperties } from \"react\";\n\nimport type { InstrumentRevealProps } from \"../types/card\";\n\nexport function InstrumentReveal({\n  active,\n  order = 0,\n  children,\n  className,\n}: InstrumentRevealProps) {\n  return (\n    <div\n      className={cn(\n        \"duration-normal ease-emphasized flex min-w-0 flex-col transition delay-(--reveal-delay) motion-reduce:translate-none motion-reduce:transition-none motion-reduce:delay-0\",\n        active ? \"translate-y-0 opacity-100\" : \"translate-y-1.5 opacity-0\",\n        className\n      )}\n      style={{ \"--reveal-delay\": `${order * 45}ms` } as CSSProperties}\n    >\n      {children}\n    </div>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/card/components/instrument-reveal.tsx"
    },
    {
      "path": "registry/notra/card/constants/card.ts",
      "content": "import type { CardLabels } from \"../types/card\";\n\n/** Header and body classes for each dualtone `InstrumentModule` layout. */\nexport const INSTRUMENT_SURFACE_CLASSES = {\n  panel: {\n    header: \"min-h-24 content-start rounded-t-[14px] pt-4 pb-9\",\n    content:\n      \"border-table-card-border bg-table-card shadow-table-card relative -mt-5 flex flex-1 flex-col rounded-[14px] border p-6\",\n  },\n  table: {\n    header:\n      \"min-h-[4.25rem] content-center items-center rounded-t-[14px] pt-3 pb-8\",\n    content:\n      \"border-table-card-border bg-table-card shadow-table-card relative -mt-5 flex flex-1 flex-col rounded-[14px] border p-4\",\n  },\n  \"table-compact\": {\n    header:\n      \"min-h-14 content-center items-center rounded-t-[14px] pt-1.5 pb-6.5\",\n    content:\n      \"border-table-card-border bg-table-card shadow-table-card relative -mt-5 flex flex-1 flex-col rounded-[14px] border p-4\",\n  },\n  bare: {\n    header: \"px-1\",\n    content: \"flex flex-1 flex-col p-0\",\n  },\n} as const;\n\nexport const CARD_LABELS: CardLabels = {\n  moreInfo: \"More info\",\n};\n",
      "type": "registry:lib",
      "target": "components/card/constants/card.ts"
    },
    {
      "path": "registry/notra/card/types/card.ts",
      "content": "import type { ReactNode } from \"react\";\n\nexport type InstrumentModuleVariant =\n  | \"flat\"\n  | \"panel\"\n  | \"table\"\n  | \"table-compact\";\n\nexport interface InstrumentGridProps {\n  children: ReactNode;\n  className?: string;\n}\n\nexport interface InstrumentModuleProps {\n  eyebrow: string;\n  description?: ReactNode;\n  hint?: ReactNode;\n  readout?: ReactNode;\n  action?: ReactNode;\n  children: ReactNode;\n  className?: string;\n  bodyClassName?: string;\n  variant?: InstrumentModuleVariant;\n  bareBody?: boolean;\n}\n\nexport interface InstrumentRevealProps {\n  active: boolean;\n  order?: number;\n  children: ReactNode;\n  className?: string;\n}\n\nexport interface InstrumentEmptyProps {\n  seed?: string;\n  message: string;\n  className?: string;\n  busy?: boolean;\n  action?: ReactNode;\n  preview?: ReactNode;\n}\n\nexport interface InstrumentHintProps {\n  hint: ReactNode;\n}\n\nexport interface CardLabels {\n  moreInfo: string;\n}\n\nexport interface CardLabelsProviderProps {\n  labels?: Partial<CardLabels>;\n  children: ReactNode;\n}\n",
      "type": "registry:lib",
      "target": "components/card/types/card.ts"
    }
  ],
  "cssVars": {
    "theme": {
      "color-shell": "var(--shell)",
      "color-shell-border": "var(--shell-border)",
      "color-table-shell": "var(--table-shell)",
      "color-table-shell-border": "var(--table-shell-border)",
      "color-table-card": "var(--table-card)",
      "color-table-card-border": "var(--table-card-border)",
      "color-table-row-border": "var(--table-row-border)",
      "shadow-table-card": "var(--table-card-shadow)"
    },
    "light": {
      "shell": "var(--table-shell)",
      "shell-border": "var(--table-shell-border)",
      "table-shell": "#f3f3f2",
      "table-shell-border": "#e7e7e5",
      "table-card": "#ffffff",
      "table-card-border": "#e5e5e5",
      "table-row-border": "#efefee",
      "table-card-shadow": "0 1px 2px hsl(240 10% 10% / 0.06), 0 2px 8px -2px hsl(240 10% 10% / 0.06)"
    },
    "dark": {
      "shell": "var(--table-shell)",
      "shell-border": "var(--table-shell-border)",
      "table-shell": "#161616",
      "table-shell-border": "#232323",
      "table-card": "#1f1f1f",
      "table-card-border": "#333333",
      "table-row-border": "#292929",
      "table-card-shadow": "inset 0 1px 0 hsl(0 0% 100% / 0.05), inset 0 0 0 1px hsl(0 0% 100% / 0.015), inset 0 12px 18px -16px hsl(0 0% 100% / 0.035)"
    }
  },
  "type": "registry:component"
}