{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "layer-card",
  "title": "Layer Card",
  "description": "A muted tray holding one or more raised panels, with a header and footer as chrome.",
  "dependencies": [
    "@base-ui/react@^1.7.0",
    "class-variance-authority@^0.7.1",
    "cn@^0.5.2"
  ],
  "registryDependencies": [
    "https://sevenui.dev/r/sevenui-tokens.json"
  ],
  "files": [
    {
      "path": "registry/base/ui/layer-card.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { mergeProps } from \"@base-ui/react/merge-props\";\nimport { useRender } from \"@base-ui/react/use-render\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { cn } from \"cn\";\n\n/**\n * The root owns every variable its parts read. Defaults sit in :where() at\n * zero specificity, so a variant or a consumer's own [--layer-card-*:…] class\n * overrides them without `!`. Each variant dimension writes a disjoint set of\n * variables, so no two classes compete for one property at equal specificity.\n */\nconst layerCardVariants = cva(\n  [\n    \"group/layer-card relative flex min-w-0 rounded-(--layer-card-radius) bg-clip-padding px-(--layer-card-pad-x) py-(--layer-card-pad-y) text-sm text-card-foreground shadow-(--layer-card-shadow)\",\n    // The tone is mixed into whatever the root is filled with, so an inverse\n    // or ghost tray keeps its own base and only takes the tint. The base comes\n    // first because Tailwind's no-color-mix() fallback is the first colour.\n    \"bg-[color:color-mix(in_oklch,var(--layer-card-fill),var(--destructive)_var(--layer-card-tone-mix))] border-[color:var(--layer-card-tone-border,var(--layer-card-border-color))]\",\n    // --theme() inlines the token like rounded-xl does on Card; var() would\n    // read --radius-xl as computed on :root and miss a scoped --radius.\n    \"[:where(&)]:[--layer-card-radius:--theme(--radius-xl)]\",\n    \"[:where(&)]:[--layer-card-pad-x:var(--layer-card-inset)] [:where(&)]:[--layer-card-pad-y:var(--layer-card-inset)] [:where(&)]:[--layer-card-fill:var(--layer-card-bg)] [:where(&)]:[--layer-card-shadow:0_0_#0000]\",\n    \"[:where(&)]:[--layer-card-border-color:color-mix(in_oklch,var(--foreground)_10%,transparent)]\",\n    // Concentric: the panel is inset by the tray padding plus the tray border,\n    // so subtracting exactly that keeps both arcs parallel. Clamped, because\n    // the radius-none preset leaves --radius-xl at 4px.\n    \"[:where(&)]:[--layer-card-panel-radius:max(0px,calc(var(--layer-card-radius)_-_var(--layer-card-inset)_-_var(--layer-card-border-width)))]\",\n    // Bars left-align with panel content: panel padding plus its 1px border.\n    \"[:where(&)]:[--layer-card-bar-px:calc(var(--layer-card-panel-px)_+_1px)]\",\n    // Surface mode: no panel anywhere inside, so the root is the surface. It\n    // only re-points variables, so a consumer's p-* / bg-* / shadow-* class\n    // still wins. The root's padding insets the content; the bars add none.\n    \"[&:not(:has([data-slot=layer-card-panel]))]:[--layer-card-fill:var(--layer-card-panel-bg)] [&:not(:has([data-slot=layer-card-panel]))]:[--layer-card-pad-x:var(--layer-card-panel-px)] [&:not(:has([data-slot=layer-card-panel]))]:[--layer-card-pad-y:var(--layer-card-panel-py)] [&:not(:has([data-slot=layer-card-panel]))]:[--layer-card-shadow:var(--elevation-raised,0_1px_2px_0_rgb(0_0_0/0.05))]\",\n    \"[&:not(:has([data-slot=layer-card-panel]))]:[--layer-card-bar-px:0px] [&:not(:has([data-slot=layer-card-panel]))]:[--layer-card-bar-py:0px]\",\n  ],\n  {\n    variants: {\n      variant: {\n        default:\n          \"border [--layer-card-border-width:1px] [--layer-card-bg:color-mix(in_oklch,var(--muted)_50%,transparent)] [--layer-card-panel-bg:var(--card)] dark:[--layer-card-panel-bg:color-mix(in_oklch,var(--card),var(--foreground)_4%)]\",\n        inverse:\n          \"border [--layer-card-border-width:1px] [--layer-card-bg:var(--card)] [--layer-card-panel-bg:color-mix(in_oklch,var(--muted)_50%,var(--card))]\",\n        ghost:\n          \"border-0 [--layer-card-border-width:0px] [--layer-card-bg:color-mix(in_oklch,var(--muted)_50%,transparent)] [--layer-card-panel-bg:var(--card)] dark:[--layer-card-panel-bg:color-mix(in_oklch,var(--card),var(--foreground)_4%)]\",\n      },\n      // Panel padding scales from --panel-pad, so data-density on any ancestor\n      // tightens it. Its fallback sits inside var() rather than in a :where()\n      // default: a declaration on the root would shadow the inherited value.\n      // Bars read as chrome: their py is about half the panel's, px is equal.\n      size: {\n        xs: \"[--layer-card-panel-px:calc(var(--panel-pad,1.125rem)*0.5)] [--layer-card-panel-py:calc(var(--panel-pad,1.125rem)*0.5)] [--layer-card-bar-py:calc(var(--panel-pad,1.125rem)*0.125)]\",\n        sm: \"[--layer-card-panel-px:calc(var(--panel-pad,1.125rem)*0.75)] [--layer-card-panel-py:calc(var(--panel-pad,1.125rem)*0.75)] [--layer-card-bar-py:calc(var(--panel-pad,1.125rem)*0.375)]\",\n        default:\n          \"[--layer-card-panel-px:var(--panel-pad,1.125rem)] [--layer-card-panel-py:var(--panel-pad,1.125rem)] [--layer-card-bar-py:calc(var(--panel-pad,1.125rem)*0.5)]\",\n        lg: \"[--layer-card-panel-px:calc(var(--panel-pad,1.125rem)*1.25)] [--layer-card-panel-py:calc(var(--panel-pad,1.125rem)*1.25)] [--layer-card-bar-py:calc(var(--panel-pad,1.125rem)*0.625)]\",\n      },\n      orientation: {\n        vertical: \"flex-col\",\n        // Only horizontal becomes a size container: inline-size containment\n        // collapses a root that sizes to its content.\n        horizontal:\n          \"@container/layer-card flex-row flex-wrap [&>[data-slot=layer-card-header]]:basis-full [&>[data-slot=layer-card-footer]]:basis-full [&>[data-slot=layer-card-panel]:not([data-fit])]:@md/layer-card:basis-0 [&>[data-slot=layer-card-panel]]:@max-md/layer-card:basis-full\",\n      },\n      stacked: {\n        true: \"gap-0\",\n        false: \"gap-1\",\n      },\n      dense: {\n        true: \"[--layer-card-inset:0px]\",\n        false: \"[--layer-card-inset:--spacing(1)]\",\n      },\n      tone: {\n        default: \"[--layer-card-tone-mix:0%] [--layer-card-tone-border:initial]\",\n        destructive:\n          \"[--layer-card-tone-mix:6%] dark:[--layer-card-tone-mix:12%] [--layer-card-tone-border:color-mix(in_oklch,var(--destructive)_30%,transparent)] [&>[data-slot=layer-card-header]_[data-slot=layer-card-title]]:text-destructive\",\n      },\n    },\n    compoundVariants: [\n      {\n        orientation: \"vertical\",\n        stacked: true,\n        className:\n          \"[&>[data-slot=layer-card-panel]:has(+[data-slot=layer-card-panel])]:rounded-b-none [&>[data-slot=layer-card-panel]+[data-slot=layer-card-panel]]:rounded-t-none [&>[data-slot=layer-card-panel]+[data-slot=layer-card-panel]]:border-t-0\",\n      },\n      {\n        // Seams run vertically in a row and flip to horizontal once the\n        // panels stack below @md.\n        orientation: \"horizontal\",\n        stacked: true,\n        className:\n          \"[&>[data-slot=layer-card-panel]:has(+[data-slot=layer-card-panel])]:@md/layer-card:rounded-e-none [&>[data-slot=layer-card-panel]+[data-slot=layer-card-panel]]:@md/layer-card:rounded-s-none [&>[data-slot=layer-card-panel]+[data-slot=layer-card-panel]]:@md/layer-card:border-s-0 [&>[data-slot=layer-card-panel]:has(+[data-slot=layer-card-panel])]:@max-md/layer-card:rounded-b-none [&>[data-slot=layer-card-panel]+[data-slot=layer-card-panel]]:@max-md/layer-card:rounded-t-none [&>[data-slot=layer-card-panel]+[data-slot=layer-card-panel]]:@max-md/layer-card:border-t-0\",\n      },\n      {\n        // Panels run edge to edge: the tray border is their side border. Only\n        // a panel touching the tray's top or bottom edge takes the tray's\n        // inner radius; the tray does not clip, so focus rings in the bars\n        // stay whole. Bars lose the panel side border from their alignment.\n        orientation: \"vertical\",\n        dense: true,\n        className:\n          \"[--layer-card-bar-px:var(--layer-card-panel-px)] [&>[data-slot=layer-card-panel]]:[--layer-card-panel-radius:0px] [&>[data-slot=layer-card-panel]]:border-x-0 [&>[data-slot=layer-card-panel]]:shadow-none [&>[data-slot=layer-card-panel]:first-child]:border-t-0 [&>[data-slot=layer-card-panel]:last-child]:border-b-0 [&>[data-slot=layer-card-panel]:first-child]:rounded-t-[max(0px,calc(var(--layer-card-radius)_-_var(--layer-card-border-width)))] [&>[data-slot=layer-card-panel]:last-child]:rounded-b-[max(0px,calc(var(--layer-card-radius)_-_var(--layer-card-border-width)))] [&>[data-slot=layer-card-panel]]:focus-visible:ring-inset\",\n      },\n    ],\n    defaultVariants: {\n      variant: \"default\",\n      size: \"default\",\n      orientation: \"vertical\",\n      stacked: false,\n      dense: false,\n      tone: \"default\",\n    },\n  },\n);\n\nfunction LayerCard({\n  className,\n  variant = \"default\",\n  size = \"default\",\n  orientation = \"vertical\",\n  stacked = false,\n  dense = false,\n  tone = \"default\",\n  render,\n  ...props\n}: useRender.ComponentProps<\"div\"> & VariantProps<typeof layerCardVariants>) {\n  return useRender({\n    defaultTagName: \"div\",\n    props: mergeProps<\"div\">(\n      {\n        className: cn(\n          layerCardVariants({ variant, size, orientation, stacked, dense, tone }),\n          className,\n        ),\n      },\n      props,\n    ),\n    render,\n    state: {\n      slot: \"layer-card\",\n      variant,\n      size,\n      orientation,\n      tone,\n      stacked,\n      dense,\n    },\n  });\n}\n\nfunction LayerCardHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"layer-card-header\"\n      className={cn(\n        \"group/layer-card-header grid auto-rows-min items-start gap-0.5 px-(--layer-card-bar-px) py-(--layer-card-bar-py) has-data-[slot=layer-card-action]:grid-cols-[1fr_auto]\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction LayerCardTitle({\n  className,\n  render,\n  ...props\n}: useRender.ComponentProps<\"div\">) {\n  return useRender({\n    defaultTagName: \"div\",\n    props: mergeProps<\"div\">(\n      { className: cn(\"text-sm leading-snug font-medium\", className) },\n      props,\n    ),\n    render,\n    state: { slot: \"layer-card-title\" },\n  });\n}\n\nfunction LayerCardDescription({\n  className,\n  ...props\n}: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"layer-card-description\"\n      className={cn(\"text-sm text-muted-foreground\", className)}\n      {...props}\n    />\n  );\n}\n\nfunction LayerCardAction({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"layer-card-action\"\n      className={cn(\n        \"col-start-2 row-span-2 row-start-1 self-center justify-self-end group-has-data-[slot=layer-card-description]/layer-card-header:self-start\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction LayerCardPanel({\n  className,\n  fit = false,\n  render,\n  ...props\n}: useRender.ComponentProps<\"div\"> & { fit?: boolean }) {\n  return useRender({\n    defaultTagName: \"div\",\n    props: mergeProps<\"div\">(\n      {\n        className: cn(\n          \"relative min-w-0 rounded-(--layer-card-panel-radius) border border-(color:--layer-card-border-color) bg-(--layer-card-panel-bg) bg-clip-padding px-(--layer-card-panel-px) py-(--layer-card-panel-py) text-card-foreground shadow-[var(--elevation-raised,0_1px_2px_0_rgb(0_0_0/0.05))]\",\n          !fit && \"grow\",\n          \"[a,button]:text-start [a,button]:no-underline [a,button]:transition-[color,background-color,border-color] [a,button]:outline-none [a,button]:hover:bg-[color-mix(in_oklch,var(--layer-card-panel-bg),var(--foreground)_4%)] [a,button]:focus-visible:border-ring [a,button]:focus-visible:z-10 [a,button]:focus-visible:ring-3 [a,button]:focus-visible:ring-ring/50 [a,button]:motion-reduce:transition-none\",\n          className,\n        ),\n      },\n      props,\n      // The tray finds its panels by this slot, so it goes last: a component\n      // that renders through a panel (CollapsibleContent render={…}) passes\n      // its own data-slot, which must not win.\n      { \"data-slot\": \"layer-card-panel\" } as React.ComponentProps<\"div\">,\n    ),\n    render,\n    state: { fit },\n  });\n}\n\nfunction LayerCardFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"layer-card-footer\"\n      className={cn(\n        \"flex items-center gap-2 px-(--layer-card-bar-px) py-(--layer-card-bar-py) text-sm text-muted-foreground\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nexport {\n  LayerCard,\n  LayerCardHeader,\n  LayerCardTitle,\n  LayerCardDescription,\n  LayerCardAction,\n  LayerCardPanel,\n  LayerCardFooter,\n  layerCardVariants,\n};\n",
      "type": "registry:ui"
    }
  ],
  "type": "registry:ui"
}