{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "card",
  "type": "registry:component",
  "title": "Card",
  "description": "A surface that holds one thing, with a heading, an action beside it and a footer.",
  "dependencies": [
    "@base-ui/react",
    "tailwind-variants"
  ],
  "registryDependencies": [],
  "files": [
    {
      "path": "components/panelui/card.tsx",
      "type": "registry:component",
      "target": "@components/panelui/card.tsx",
      "content": "'use client';\n\n/**\n * Card — a surface that holds one thing: a plan, a setting, a summary.\n *\n * ```tsx\n * <Card>\n *   <Card.Header>\n *     <Card.Title>Storage</Card.Title>\n *     <Card.Description>Northwind Studio workspace</Card.Description>\n *     <Card.Action><Button variant=\"ghost\">Manage</Button></Card.Action>\n *   </Card.Header>\n *   <Card.Content>…</Card.Content>\n *   <Card.Footer variant=\"panel\">…</Card.Footer>\n * </Card>\n * ```\n *\n * ## The padding is on the parts\n *\n * The card itself draws a surface and nothing inside it, and every part\n * carries its own padding. That is what lets a picture reach the card's\n * corners with nothing but `overflow-hidden` on the card, and what lets a\n * footer be a band set into the bottom of it rather than one more row.\n *\n * ## The action sits beside the heading\n *\n * `Card.Action` is placed in the header's top trailing corner whatever order\n * it is written in, and the title and description keep the rest of the width.\n * A button that belongs to the whole card goes there; one that belongs to the\n * content goes in the content.\n *\n * ## It renders on the server\n *\n * No state, no effects, no handlers of its own: everything that changes with\n * `size` or with the parts present is done in CSS, so a page of cards costs no\n * JavaScript.\n */\nimport type { ComponentProps } from 'react';\nimport { tv } from 'tailwind-variants';\nimport { mergeProps } from '@base-ui/react/merge-props';\nimport { useRender } from '@base-ui/react/use-render';\nimport type { ElementType as RenderElementType } from 'react';\n\n/** Draws a part as another element, or composes it with a component: `render={<a href=\"/\" />}`. */\ntype RenderProp<Tag extends RenderElementType> = { render?: useRender.ComponentProps<Tag>['render'] };\n\nconst cardVariants = tv({\n  slots: {\n    root: 'group/card flex flex-col rounded-2xl border bg-card text-card-foreground shadow-xs',\n    header: [\n      'grid auto-rows-min grid-cols-[minmax(0,1fr)] items-start gap-x-4 gap-y-1.5 p-6',\n      'has-data-[slot=card-action]:grid-cols-[minmax(0,1fr)_auto]',\n      'group-data-[size=sm]/card:gap-y-1 group-data-[size=sm]/card:p-4',\n    ],\n    title: 'text-lg font-semibold leading-tight tracking-[-0.01em] group-data-[size=sm]/card:text-base',\n    description: 'text-sm text-muted-foreground',\n    // Its own column, across both of the heading's rows, so a long title wraps\n    // beside it instead of underneath it.\n    action: 'col-start-2 row-span-2 row-start-1 self-start justify-self-end',\n    // `first:` for a card with no header, which would otherwise start flush.\n    content:\n      'px-6 pb-6 first:pt-6 group-data-[size=sm]/card:px-4 group-data-[size=sm]/card:pb-4 group-data-[size=sm]/card:first:pt-4',\n    footer: 'flex items-center gap-2',\n  },\n  variants: {\n    footer: {\n      /** Part of the card: same surface, continuing the content's padding. */\n      plain: {\n        footer:\n          'px-6 pb-6 first:pt-6 group-data-[size=sm]/card:px-4 group-data-[size=sm]/card:pb-4 group-data-[size=sm]/card:first:pt-4',\n      },\n      /**\n       * A band set into the bottom of the card: a rule across its top, a step\n       * darker, and the card's own bottom corners. For a footer that is what\n       * somebody does with the card, not more of what it says.\n       */\n      panel: {\n        footer:\n          'mt-auto rounded-b-[calc(var(--radius-2xl)-1px)] border-t bg-muted/60 px-6 py-4 group-data-[size=sm]/card:px-4 group-data-[size=sm]/card:py-3',\n      },\n    },\n  },\n});\n\nexport interface CardProps extends ComponentProps<'div'> {\n  /** `sm` tightens the padding and the title, for a card in a dense grid. Default `default`. */\n  size?: 'default' | 'sm';\n  /**\n   * The element to render. `article` for a card that stands on its own, `li`\n   * for one in a list, `section` for one that groups a part of a page.\n   */\n  as?: 'div' | 'article' | 'section' | 'li';\n}\n\nfunction CardRoot({ size = 'default', as = 'div', render, className, ...props }: CardProps & RenderProp<'div'>) {\n  const slots = cardVariants();\n  return useRender({\n    defaultTagName: as,\n    render,\n    props: mergeProps({ 'data-slot': 'card', 'data-size': size, className: slots.root({ className }) }, props),\n  });\n}\nCardRoot.displayName = 'Card';\n\nexport interface CardHeaderProps extends ComponentProps<'div'> {}\n\n/** The title, the line under it, and the action beside them. */\nfunction CardHeader({ className, render, ...props }: CardHeaderProps & RenderProp<'div'>) {\n  const slots = cardVariants();\n  return useRender({\n    defaultTagName: 'div',\n    render,\n    props: mergeProps({ 'data-slot': 'card-header', className: slots.header({ className }) }, props),\n  });\n}\nCardHeader.displayName = 'Card.Header';\n\nexport interface CardTitleProps extends ComponentProps<'h3'> {\n  /** The heading level, to fit the page around the card. Default `h3`. */\n  as?: 'h2' | 'h3' | 'h4' | 'div';\n}\n\n/** What the card is about. A heading, so the page outline includes it. */\nfunction CardTitle({ as = 'h3', render, className, ...props }: CardTitleProps & RenderProp<'h3'>) {\n  const slots = cardVariants();\n  return useRender({\n    defaultTagName: as,\n    render,\n    props: mergeProps({ 'data-slot': 'card-title', className: slots.title({ className }) }, props),\n  });\n}\nCardTitle.displayName = 'Card.Title';\n\nexport interface CardDescriptionProps extends ComponentProps<'p'> {}\n\n/** A line under the title. */\nfunction CardDescription({ className, render, ...props }: CardDescriptionProps & RenderProp<'p'>) {\n  const slots = cardVariants();\n  return useRender({\n    defaultTagName: 'p',\n    render,\n    props: mergeProps({ 'data-slot': 'card-description', className: slots.description({ className }) }, props),\n  });\n}\nCardDescription.displayName = 'Card.Description';\n\nexport interface CardActionProps extends ComponentProps<'div'> {}\n\n/** A control for the whole card, held in the header's top trailing corner. */\nfunction CardAction({ className, render, ...props }: CardActionProps & RenderProp<'div'>) {\n  const slots = cardVariants();\n  return useRender({\n    defaultTagName: 'div',\n    render,\n    props: mergeProps({ 'data-slot': 'card-action', className: slots.action({ className }) }, props),\n  });\n}\nCardAction.displayName = 'Card.Action';\n\nexport interface CardContentProps extends ComponentProps<'div'> {}\n\n/** The body. */\nfunction CardContent({ className, render, ...props }: CardContentProps & RenderProp<'div'>) {\n  const slots = cardVariants();\n  return useRender({\n    defaultTagName: 'div',\n    render,\n    props: mergeProps({ 'data-slot': 'card-content', className: slots.content({ className }) }, props),\n  });\n}\nCardContent.displayName = 'Card.Content';\n\nexport interface CardFooterProps extends ComponentProps<'div'> {\n  /**\n   * `plain` continues the card. `panel` is a darker band set into its bottom,\n   * for actions. Default `plain`.\n   */\n  variant?: 'plain' | 'panel';\n}\n\n/** The row at the bottom, usually the card's actions. */\nfunction CardFooter({ variant = 'plain', className, render, ...props }: CardFooterProps & RenderProp<'div'>) {\n  const slots = cardVariants({ footer: variant });\n  return useRender({\n    defaultTagName: 'div',\n    render,\n    props: mergeProps({ 'data-slot': 'card-footer', className: slots.footer({ className }) }, props),\n  });\n}\nCardFooter.displayName = 'Card.Footer';\n\nexport const Card = Object.assign(CardRoot, {\n  Header: CardHeader,\n  Title: CardTitle,\n  Description: CardDescription,\n  Action: CardAction,\n  Content: CardContent,\n  Footer: CardFooter,\n});\n\nexport { CardHeader, CardTitle, CardDescription, CardAction, CardContent, CardFooter };\n"
    }
  ]
}
