{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "api-reference-table",
  "title": "API reference table",
  "description": "API reference table is a production-ready tables component from BJORK UI, packaged for shadcn registries.",
  "dependencies": [
    "clsx",
    "framer-motion",
    "lucide-react",
    "next-themes",
    "tailwind-merge"
  ],
  "files": [
    {
      "path": "components/bjork-ui/tables/api-reference-table.tsx",
      "content": "\"use client\";\n\nimport {\n  Fragment,\n  useCallback,\n  useEffect,\n  useMemo,\n  useRef,\n  useState,\n  useSyncExternalStore,\n  type KeyboardEvent as ReactKeyboardEvent,\n  type MouseEvent as ReactMouseEvent,\n} from \"react\";\nimport { motion, useReducedMotion } from \"framer-motion\";\nimport { useTheme } from \"next-themes\";\nimport { Check, ChevronRight, Link2 } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\nimport {\n  type BjorkTableThemeMode,\n  getBjorkSignalPalette,\n  getBjorkTablePalette,\n  useBjorkTableIsDark,\n} from \"./table-theme\";\n\nexport interface ApiParam {\n  /** Field name as it appears on the wire, e.g. `amount`. */\n  name: string;\n  /** Type expression. Unions (`\"a\" | \"b\"`) are split and wrapped. */\n  type: string;\n  required?: boolean;\n  /** Default value, rendered as code. */\n  default?: string;\n  /** Description. Wrap identifiers in backticks to render them as code. */\n  description: string;\n  /** `true`, or a short note such as \"Use `destination` instead.\" */\n  deprecated?: boolean | string;\n  /** API version or date the field was introduced. */\n  since?: string;\n  /** Nested fields of an object parameter. */\n  children?: ApiParam[];\n}\n\nexport interface ApiSection {\n  id: string;\n  label: string;\n  params: ApiParam[];\n}\n\nexport type ApiMethod = \"GET\" | \"POST\" | \"PUT\" | \"PATCH\" | \"DELETE\";\n\nexport interface ApiReferenceTableProps {\n  /** Flat list of parameters. Ignored when `sections` is given. */\n  params?: ApiParam[];\n  /** Optional tabbed sections, such as Path / Query / Body. */\n  sections?: ApiSection[];\n  /** Endpoint title shown above the table. */\n  title?: string;\n  method?: ApiMethod;\n  /** Endpoint path. `{placeholders}` are highlighted. */\n  path?: string;\n  /** Initially active section id. */\n  defaultSection?: string;\n  /** Dotted paths of parameters expanded on first render, e.g. `[\"destination\"]`. */\n  defaultExpanded?: string[];\n  /** Prefix for row anchors. Rows get ids like `param-destination-type`. */\n  anchorPrefix?: string;\n  /** Max height of the scrolling body. The header row sticks while it scrolls. */\n  maxHeight?: number;\n  loading?: boolean;\n  emptyMessage?: string;\n  onCopyAnchor?: (anchor: string, param: ApiParam) => void;\n  onSectionChange?: (sectionId: string) => void;\n  className?: string;\n  theme?: BjorkTableThemeMode;\n  enableAnimations?: boolean;\n}\n\nexport const API_REFERENCE_SAMPLE: {\n  title: string;\n  method: ApiMethod;\n  path: string;\n  sections: ApiSection[];\n} = {\n  title: \"Create a payout\",\n  method: \"POST\",\n  path: \"/v2/accounts/{account_id}/payouts\",\n  sections: [\n    {\n      id: \"path\",\n      label: \"Path\",\n      params: [\n        {\n          name: \"account_id\",\n          type: \"string\",\n          required: true,\n          description:\n            \"The connected account that sends the payout. Starts with `acct_`.\",\n        },\n      ],\n    },\n    {\n      id: \"query\",\n      label: \"Query\",\n      params: [\n        {\n          name: \"expand\",\n          type: \"string[]\",\n          description:\n            \"Related objects to inline in the response, such as `destination` or `balance_transaction`.\",\n        },\n        {\n          name: \"dry_run\",\n          type: \"boolean\",\n          default: \"false\",\n          since: \"2025-03\",\n          description:\n            \"Validate the request and return the fee quote without moving funds.\",\n        },\n      ],\n    },\n    {\n      id: \"body\",\n      label: \"Body\",\n      params: [\n        {\n          name: \"amount\",\n          type: \"integer\",\n          required: true,\n          description:\n            \"Amount in the smallest currency unit. `125000` sends 1,250.00 in a two-decimal currency.\",\n        },\n        {\n          name: \"currency\",\n          type: \"string\",\n          required: true,\n          description:\n            \"Three-letter ISO 4217 code in lowercase, such as `usd` or `eur`. Must match the destination.\",\n        },\n        {\n          name: \"destination\",\n          type: \"object\",\n          required: true,\n          description: \"Where the funds land. Pass an existing id or describe a new account.\",\n          children: [\n            {\n              name: \"type\",\n              type: '\"bank_account\" | \"debit_card\" | \"wallet\"',\n              required: true,\n              description: \"Kind of destination. Determines which other fields apply.\",\n            },\n            {\n              name: \"id\",\n              type: \"string\",\n              description: \"An existing destination, such as `ba_8Hq2Lm`. Overrides the fields below.\",\n            },\n            {\n              name: \"account_number\",\n              type: \"string\",\n              description: \"Bank account number. Required when `type` is `bank_account`.\",\n            },\n            {\n              name: \"routing_number\",\n              type: \"string\",\n              description: \"Nine-digit routing number for US accounts.\",\n            },\n            {\n              name: \"holder\",\n              type: \"object\",\n              description: \"The person or business that owns the account.\",\n              children: [\n                {\n                  name: \"name\",\n                  type: \"string\",\n                  required: true,\n                  description: \"Full legal name, as it appears on the account.\",\n                },\n                {\n                  name: \"entity\",\n                  type: '\"individual\" | \"company\"',\n                  default: '\"individual\"',\n                  description: \"Whether the holder is a person or a business.\",\n                },\n              ],\n            },\n          ],\n        },\n        {\n          name: \"method\",\n          type: '\"standard\" | \"instant\"',\n          default: '\"standard\"',\n          description:\n            \"`instant` arrives in minutes for a 1% fee. `standard` settles in one to two business days.\",\n        },\n        {\n          name: \"scheduled_for\",\n          type: \"timestamp | null\",\n          default: \"null\",\n          since: \"2024-11\",\n          description: \"Unix timestamp to hold the payout until. Must be within 90 days.\",\n        },\n        {\n          name: \"statement_descriptor\",\n          type: \"string\",\n          description: \"Up to 22 characters shown on the recipient's bank statement.\",\n        },\n        {\n          name: \"metadata\",\n          type: \"Record<string, string>\",\n          default: \"{}\",\n          description: \"Up to 50 key-value pairs for your own reference. Never shown to the recipient.\",\n        },\n        {\n          name: \"source_balance\",\n          type: '\"available\" | \"pending\"',\n          default: '\"available\"',\n          deprecated: \"Use `source_type` instead. Removed in 2026-01.\",\n          description: \"Which balance to draw from.\",\n        },\n      ],\n    },\n  ],\n};\n\n// ─── helpers ─────────────────────────────────────────────────────────────────\n\nconst noopSubscribe = () => () => {};\n\nfunction useMounted() {\n  return useSyncExternalStore(noopSubscribe, () => true, () => false);\n}\n\nfunction useIsNarrow<T extends HTMLElement>(threshold: number) {\n  const ref = useRef<T>(null);\n  const [narrow, setNarrow] = useState(false);\n  useEffect(() => {\n    const node = ref.current;\n    if (!node || typeof ResizeObserver === \"undefined\") return;\n    const observer = new ResizeObserver((entries) => {\n      const width = entries[0]?.contentRect.width ?? 0;\n      setNarrow(width > 0 && width < threshold);\n    });\n    observer.observe(node);\n    return () => observer.disconnect();\n  }, [threshold]);\n  return [ref, narrow] as const;\n}\n\nfunction toAnchor(prefix: string, path: string) {\n  return `${prefix}${path.replace(/[^a-zA-Z0-9_]+/g, \"-\")}`;\n}\n\ninterface FlatRow {\n  param: ApiParam;\n  path: string;\n  depth: number;\n  parentPath: string | null;\n}\n\nfunction flatten(\n  params: ApiParam[],\n  expanded: Set<string>,\n  depth = 0,\n  parentPath: string | null = null,\n  out: FlatRow[] = []\n) {\n  params.forEach((param) => {\n    const path = parentPath ? `${parentPath}.${param.name}` : param.name;\n    out.push({ param, path, depth, parentPath });\n    if (param.children?.length && expanded.has(path)) {\n      flatten(param.children, expanded, depth + 1, path, out);\n    }\n  });\n  return out;\n}\n\nfunction findPath(params: ApiParam[], anchor: string, prefix: string, parent: string | null = null): string | null {\n  for (const param of params) {\n    const path = parent ? `${parent}.${param.name}` : param.name;\n    if (toAnchor(prefix, path) === anchor) return path;\n    if (param.children) {\n      const hit = findPath(param.children, anchor, prefix, path);\n      if (hit) return hit;\n    }\n  }\n  return null;\n}\n\nfunction countParams(params: ApiParam[]): number {\n  return params.reduce((sum, p) => sum + 1 + (p.children ? countParams(p.children) : 0), 0);\n}\n\n/** Splits text on backticks; odd segments become inline code. */\nfunction InlineText({ text, codeClassName }: { text: string; codeClassName: string }) {\n  const parts = text.split(/`([^`]+)`/g);\n  return (\n    <>\n      {parts.map((part, i) =>\n        i % 2 === 1 ? (\n          <code key={i} className={codeClassName}>\n            {part}\n          </code>\n        ) : (\n          <Fragment key={i}>{part}</Fragment>\n        )\n      )}\n    </>\n  );\n}\n\n// ─── component ───────────────────────────────────────────────────────────────\n\nexport function ApiReferenceTable({\n  params,\n  sections: sectionsProp,\n  title = params ? undefined : API_REFERENCE_SAMPLE.title,\n  method = params ? undefined : API_REFERENCE_SAMPLE.method,\n  path = params ? undefined : API_REFERENCE_SAMPLE.path,\n  defaultSection,\n  defaultExpanded = [],\n  anchorPrefix = \"param-\",\n  maxHeight = 560,\n  loading = false,\n  emptyMessage = \"This endpoint takes no parameters here.\",\n  onCopyAnchor,\n  onSectionChange,\n  className,\n  theme = \"auto\",\n  enableAnimations = true,\n}: ApiReferenceTableProps) {\n  const mounted = useMounted();\n  const { resolvedTheme } = useTheme();\n  const forcedTheme = theme === \"auto\" ? undefined : theme;\n  const detectedIsDark = useBjorkTableIsDark(resolvedTheme, forcedTheme);\n  const isDark = !mounted && theme === \"auto\" ? true : detectedIsDark;\n  const palette = getBjorkTablePalette(isDark);\n  const orange = getBjorkSignalPalette(\"orange\", isDark);\n  const green = getBjorkSignalPalette(\"green\", isDark);\n  const shouldReduceMotion = useReducedMotion();\n  const shouldAnimate = enableAnimations && !shouldReduceMotion;\n\n  const sections = useMemo<ApiSection[]>(() => {\n    if (sectionsProp) return sectionsProp;\n    if (params) return [{ id: \"params\", label: \"Parameters\", params }];\n    return API_REFERENCE_SAMPLE.sections;\n  }, [sectionsProp, params]);\n  const showTabs = sections.length > 1;\n\n  const [activeId, setActiveId] = useState(\n    () => defaultSection ?? sections.find((s) => s.params.length > 2)?.id ?? sections[0]?.id ?? \"\"\n  );\n  const active = sections.find((s) => s.id === activeId) ?? sections[0];\n\n  const [expanded, setExpanded] = useState(() => new Set(defaultExpanded));\n  const [copied, setCopied] = useState<string | null>(null);\n  const [intro, setIntro] = useState(true);\n  // Rows revealed by a pointer click fade in; keyboard toggles are instant.\n  const [revealPath, setRevealPath] = useState<string | null>(null);\n  const [rootRef, narrow] = useIsNarrow<HTMLDivElement>(480);\n  const tabRefs = useRef(new Map<string, HTMLButtonElement>());\n  const copyTimer = useRef<number | undefined>(undefined);\n\n  useEffect(() => {\n    const t = window.setTimeout(() => setIntro(false), 900);\n    return () => window.clearTimeout(t);\n  }, []);\n\n  useEffect(() => () => window.clearTimeout(copyTimer.current), []);\n\n  // Deep link: open the section and ancestors that contain the hashed param.\n  useEffect(() => {\n    const hash = window.location.hash.slice(1);\n    if (!hash) return;\n    for (const section of sections) {\n      const hit = findPath(section.params, hash, anchorPrefix);\n      if (!hit) continue;\n      const segments = hit.split(\".\");\n      const ancestors = segments.slice(0, -1).map((_, i) => segments.slice(0, i + 1).join(\".\"));\n      const frame = requestAnimationFrame(() => {\n        setActiveId(section.id);\n        if (ancestors.length) setExpanded((prev) => new Set([...prev, ...ancestors]));\n        requestAnimationFrame(() =>\n          document.getElementById(hash)?.scrollIntoView({ block: \"center\" })\n        );\n      });\n      return () => cancelAnimationFrame(frame);\n    }\n  }, [sections, anchorPrefix]);\n\n  const rows = useMemo(\n    () => (active ? flatten(active.params, expanded) : []),\n    [active, expanded]\n  );\n\n  const selectSection = useCallback(\n    (id: string, focus = false) => {\n      setActiveId(id);\n      onSectionChange?.(id);\n      if (focus) tabRefs.current.get(id)?.focus();\n    },\n    [onSectionChange]\n  );\n\n  const handleTabKey = (event: ReactKeyboardEvent<HTMLButtonElement>, index: number) => {\n    const last = sections.length - 1;\n    let next = -1;\n    if (event.key === \"ArrowRight\") next = index === last ? 0 : index + 1;\n    else if (event.key === \"ArrowLeft\") next = index === 0 ? last : index - 1;\n    else if (event.key === \"Home\") next = 0;\n    else if (event.key === \"End\") next = last;\n    if (next < 0) return;\n    event.preventDefault();\n    selectSection(sections[next].id, true);\n  };\n\n  const toggle = (rowPath: string, event: ReactMouseEvent) => {\n    const fromKeyboard = event.detail === 0;\n    setRevealPath(fromKeyboard || !shouldAnimate ? null : rowPath);\n    setExpanded((prev) => {\n      const next = new Set(prev);\n      if (next.has(rowPath)) {\n        for (const key of prev) if (key === rowPath || key.startsWith(`${rowPath}.`)) next.delete(key);\n      } else {\n        next.add(rowPath);\n      }\n      return next;\n    });\n  };\n\n  const copyAnchor = (event: ReactMouseEvent<HTMLAnchorElement>, anchor: string, param: ApiParam) => {\n    event.preventDefault();\n    const url = `${window.location.href.split(\"#\")[0]}#${anchor}`;\n    window.history.replaceState(null, \"\", `#${anchor}`);\n    navigator.clipboard?.writeText(url).catch(() => {});\n    setCopied(anchor);\n    window.clearTimeout(copyTimer.current);\n    copyTimer.current = window.setTimeout(() => setCopied(null), 1600);\n    onCopyAnchor?.(anchor, param);\n  };\n\n  const codeChip = cn(\n    \"rounded-[5px] border px-[5px] py-px font-mono text-[11.5px] leading-[1.5]\",\n    isDark ? \"border-[#2a2a2a] bg-[#1b1b1b] text-[#ededed]/82\" : \"border-[#eadfce] bg-[#f8f2e7] text-[#171717]/80\"\n  );\n  const focusRing =\n    \"outline-none focus-visible:ring-2 focus-visible:ring-[#ec5c13]/60 focus-visible:ring-offset-0\";\n  const guideColor = isDark ? \"bg-[#2c2c2c]\" : \"bg-[#e6dccb]\";\n\n  const renderType = (type: string) => {\n    const parts = type.split(/\\s*\\|\\s*/);\n    return (\n      <span className=\"inline-flex flex-wrap items-center gap-x-1 gap-y-1\">\n        {parts.map((part, i) => {\n          const literal = /^[\"'].*[\"']$/.test(part) || /^\\d+$/.test(part);\n          return (\n            <Fragment key={`${part}-${i}`}>\n              {i > 0 ? (\n                <span aria-hidden className={cn(\"font-mono text-[11px]\", palette.secondaryText)}>\n                  |\n                </span>\n              ) : null}\n              <code className={cn(codeChip, \"whitespace-nowrap\", literal && (isDark ? \"text-[#d86a2c]\" : \"text-[#9f4317]\"))}>\n                {part}\n              </code>\n            </Fragment>\n          );\n        })}\n        {parts.length > 1 ? <span className=\"sr-only\">(one of {parts.length} values)</span> : null}\n      </span>\n    );\n  };\n\n  const renderMarkers = (param: ApiParam) => (\n    <>\n      {param.required ? (\n        <span className={cn(\"text-[11px] font-medium uppercase tracking-[0.08em]\", palette.accent)}>\n          Required\n        </span>\n      ) : null}\n      {param.deprecated ? (\n        <span\n          className={cn(\n            \"rounded-full border px-1.5 py-px text-[11px] font-medium uppercase tracking-[0.06em]\",\n            getBjorkSignalPalette(\"red\", isDark).borderColor,\n            getBjorkSignalPalette(\"red\", isDark).textColor\n          )}\n        >\n          Deprecated\n        </span>\n      ) : null}\n      {param.since ? (\n        <span className={cn(\"rounded-full border px-1.5 py-px text-[11px] tabular-nums\", green.borderColor, green.textColor)}>\n          since {param.since}\n        </span>\n      ) : null}\n    </>\n  );\n\n  const renderName = (row: FlatRow, anchor: string) => {\n    const { param, path: rowPath } = row;\n    const hasChildren = Boolean(param.children?.length);\n    const isOpen = expanded.has(rowPath);\n    const childIds = hasChildren && isOpen\n      ? param.children!.map((c) => toAnchor(anchorPrefix, `${rowPath}.${c.name}`)).join(\" \")\n      : undefined;\n    return (\n      <span className=\"flex min-w-0 items-start gap-1\">\n        {hasChildren ? (\n          <button\n            type=\"button\"\n            onClick={(e) => toggle(rowPath, e)}\n            aria-expanded={isOpen}\n            aria-controls={childIds}\n            aria-label={`${isOpen ? \"Hide\" : \"Show\"} ${param.children!.length} fields of ${param.name}`}\n            className={cn(\n              \"-ml-1 mt-px grid size-[18px] shrink-0 place-items-center rounded-[5px] transition-colors motion-reduce:transition-none\",\n              palette.menuItem,\n              palette.secondaryText,\n              focusRing\n            )}\n          >\n            <ChevronRight\n              size={13}\n              strokeWidth={2.2}\n              className={cn(\"transition-transform duration-200 motion-reduce:transition-none\", isOpen && \"rotate-90\")}\n            />\n          </button>\n        ) : row.depth > 0 ? null : (\n          <span aria-hidden className=\"w-[13px] shrink-0\" />\n        )}\n        <span className=\"flex min-w-0 flex-wrap items-center gap-x-2 gap-y-1\">\n          <span className=\"flex min-w-0 items-center gap-1\">\n            <code\n              className={cn(\n                \"min-w-0 break-all font-mono text-[13px] font-medium\",\n                palette.primaryText,\n                param.deprecated && \"line-through decoration-1\"\n              )}\n            >\n              {row.depth > 0 ? (\n                <span className={cn(\"font-normal\", palette.secondaryText)}>\n                  {row.parentPath!.split(\".\").pop()}.\n                </span>\n              ) : null}\n              {param.name}\n            </code>\n          </span>\n          {renderMarkers(param)}\n          <a\n            href={`#${anchor}`}\n            onClick={(e) => copyAnchor(e, anchor, param)}\n            aria-label={copied === anchor ? `Link to ${rowPath} copied` : `Copy link to ${rowPath}`}\n            className={cn(\n              \"grid size-[18px] shrink-0 place-items-center rounded-[5px] opacity-0 transition-opacity group-hover/row:opacity-100 focus-visible:opacity-100 motion-reduce:transition-none\",\n              copied === anchor && \"opacity-100\",\n              copied === anchor ? green.textColor : palette.secondaryText,\n              palette.menuItem,\n              focusRing\n            )}\n          >\n            {copied === anchor ? <Check size={12} strokeWidth={2.4} /> : <Link2 size={12} strokeWidth={2} />}\n          </a>\n        </span>\n      </span>\n    );\n  };\n\n  const renderDescription = (param: ApiParam) => (\n    <>\n      <span className={cn(param.deprecated ? palette.secondaryText : palette.primaryText, \"opacity-[0.92]\")}>\n        <InlineText text={param.description} codeClassName={codeChip} />\n      </span>\n      {typeof param.deprecated === \"string\" ? (\n        <span className={cn(\"mt-1.5 flex gap-1.5 text-[12px]\", getBjorkSignalPalette(\"red\", isDark).textColor)}>\n          <span aria-hidden>↳</span>\n          <span>\n            <InlineText text={param.deprecated} codeClassName={codeChip} />\n          </span>\n        </span>\n      ) : null}\n    </>\n  );\n\n  const renderDefault = (param: ApiParam) =>\n    param.default !== undefined ? (\n      <code className={cn(codeChip, \"whitespace-nowrap\")}>{param.default}</code>\n    ) : (\n      <span className={palette.secondaryText}>\n        <span aria-hidden>—</span>\n        <span className=\"sr-only\">None</span>\n      </span>\n    );\n\n  const guides = (row: FlatRow) =>\n    row.depth > 0 ? (\n      <span aria-hidden className=\"pointer-events-none absolute inset-y-0 left-0\">\n        {Array.from({ length: row.depth }).map((_, level) => (\n          <span\n            key={level}\n            className={cn(\"absolute inset-y-0 w-px\", guideColor)}\n            style={{ left: 22 + level * 20 }}\n          />\n        ))}\n        <span\n          className={cn(\"absolute h-px w-[9px]\", guideColor)}\n          style={{ left: 22 + (row.depth - 1) * 20, top: narrow ? 24 : 22 }}\n        />\n      </span>\n    ) : null;\n\n  const rowMotion = (row: FlatRow, index: number) => {\n    const isIntro = intro && shouldAnimate;\n    const isReveal = !intro && revealPath !== null && row.parentPath?.startsWith(revealPath) === true;\n    if (!isIntro && !isReveal) return { initial: false as const };\n    return {\n      initial: { opacity: 0, y: isIntro ? 6 : -4 },\n      animate: { opacity: 1, y: 0 },\n      transition: {\n        duration: 0.32,\n        ease: [0.22, 1, 0.36, 1] as const,\n        delay: isIntro ? 0.04 + index * 0.028 : 0,\n      },\n    };\n  };\n\n  const headerLabel = \"text-[11px] font-medium uppercase tracking-[0.08em]\";\n  const total = active ? countParams(active.params) : 0;\n\n  const methodTone =\n    method === \"GET\" ? green : method === \"DELETE\" ? getBjorkSignalPalette(\"red\", isDark) : orange;\n\n  const skeleton = (\n    <div className=\"space-y-0\" aria-hidden>\n      {Array.from({ length: 5 }).map((_, i) => (\n        <div key={i} className={cn(\"flex items-center gap-6 border-b px-5 py-4\", palette.divider)}>\n          <span className={cn(\"h-3 w-28 animate-pulse rounded motion-reduce:animate-none\", palette.mutedSurface)} />\n          <span className={cn(\"h-3 w-16 animate-pulse rounded motion-reduce:animate-none\", palette.mutedSurface)} />\n          <span className={cn(\"h-3 flex-1 animate-pulse rounded motion-reduce:animate-none\", palette.mutedSurface)} />\n        </div>\n      ))}\n    </div>\n  );\n\n  const empty = (\n    <div className={cn(\"flex flex-col items-center gap-1 px-6 py-12 text-center\", palette.secondaryText)}>\n      <span className={cn(\"text-[13px] font-medium\", palette.primaryText)}>No {active?.label.toLowerCase()} parameters</span>\n      <span className=\"text-[12.5px]\">{emptyMessage}</span>\n    </div>\n  );\n\n  const caption = `${title ?? \"API\"} ${active ? `${active.label.toLowerCase()} parameters` : \"parameters\"}`;\n\n  return (\n    <div\n      ref={rootRef}\n      className={cn(\"w-full overflow-hidden rounded-[18px] border text-[13px]\", palette.container, className)}\n    >\n      {title || path ? (\n        <div className={cn(\"flex flex-col gap-2 px-5 pb-3 pt-4\", narrow && \"px-4\")}>\n          {title ? (\n            <h3 className={cn(\"text-[15px] font-semibold tracking-[-0.01em]\", palette.primaryText)}>{title}</h3>\n          ) : null}\n          {path ? (\n            <div className=\"flex min-w-0 items-center gap-2\">\n              {method ? (\n                <span\n                  className={cn(\n                    \"shrink-0 rounded-[5px] border px-1.5 py-px font-mono text-[11px] font-semibold tracking-[0.04em]\",\n                    methodTone.bgColor,\n                    methodTone.borderColor,\n                    methodTone.textColor\n                  )}\n                >\n                  {method}\n                </span>\n              ) : null}\n              <code className={cn(\"min-w-0 break-all font-mono text-[12.5px]\", palette.secondaryText)}>\n                {path.split(/(\\{[^}]+\\})/g).map((seg, i) =>\n                  seg.startsWith(\"{\") ? (\n                    <span key={i} className={palette.accent}>\n                      {seg}\n                    </span>\n                  ) : (\n                    <Fragment key={i}>{seg}</Fragment>\n                  )\n                )}\n              </code>\n            </div>\n          ) : null}\n        </div>\n      ) : null}\n\n      {showTabs ? (\n        <div\n          role=\"tablist\"\n          aria-label=\"Parameter location\"\n          className={cn(\"flex gap-1 border-b px-4\", palette.divider, narrow && \"px-3\")}\n        >\n          {sections.map((section, index) => {\n            const selected = section.id === active?.id;\n            return (\n              <button\n                key={section.id}\n                ref={(node) => {\n                  if (node) tabRefs.current.set(section.id, node);\n                  else tabRefs.current.delete(section.id);\n                }}\n                type=\"button\"\n                role=\"tab\"\n                id={`${anchorPrefix}tab-${section.id}`}\n                aria-selected={selected}\n                aria-controls={`${anchorPrefix}panel-${section.id}`}\n                tabIndex={selected ? 0 : -1}\n                onClick={() => selectSection(section.id)}\n                onKeyDown={(e) => handleTabKey(e, index)}\n                className={cn(\n                  \"relative flex items-center gap-1.5 rounded-t-[6px] px-2.5 pb-2.5 pt-2 text-[12.5px] font-medium transition-colors motion-reduce:transition-none\",\n                  selected ? palette.primaryText : palette.secondaryText,\n                  !selected && (isDark ? \"hover:text-[#ededed]/70\" : \"hover:text-[#171717]/80\"),\n                  focusRing\n                )}\n              >\n                {section.label}\n                <span\n                  className={cn(\n                    \"rounded-full px-1.5 text-[11px] tabular-nums\",\n                    selected ? cn(palette.accentBg, palette.accent) : palette.mutedSurface\n                  )}\n                >\n                  {countParams(section.params)}\n                </span>\n                {selected ? (\n                  shouldAnimate ? (\n                    <motion.span\n                      layoutId={`${anchorPrefix}tab-underline`}\n                      className=\"absolute inset-x-1.5 -bottom-px h-[2px] rounded-full bg-[#ec5c13]\"\n                      transition={{ type: \"spring\", stiffness: 520, damping: 40 }}\n                    />\n                  ) : (\n                    <span className=\"absolute inset-x-1.5 -bottom-px h-[2px] rounded-full bg-[#ec5c13]\" />\n                  )\n                ) : null}\n              </button>\n            );\n          })}\n        </div>\n      ) : null}\n\n      <div\n        role={showTabs ? \"tabpanel\" : \"region\"}\n        id={`${anchorPrefix}panel-${active?.id}`}\n        aria-labelledby={showTabs ? `${anchorPrefix}tab-${active?.id}` : undefined}\n        aria-label={showTabs ? undefined : caption}\n        aria-busy={loading || undefined}\n        tabIndex={0}\n        className={cn(\"overflow-auto overscroll-contain\", focusRing, !showTabs && !title && !path ? \"\" : \"border-t-0\")}\n        style={{ maxHeight }}\n      >\n        {loading ? (\n          skeleton\n        ) : !active || active.params.length === 0 ? (\n          empty\n        ) : narrow ? (\n          <ul aria-label={caption} className=\"flex flex-col\">\n            {rows.map((row, index) => {\n              const anchor = toAnchor(anchorPrefix, row.path);\n              return (\n                <motion.li\n                  key={row.path}\n                  id={anchor}\n                  {...rowMotion(row, index)}\n                  className={cn(\n                    \"group/row relative scroll-mt-4 border-b px-4 py-3.5 last:border-b-0 target:bg-[#ec5c13]/[0.06]\",\n                    palette.divider,\n                    row.param.deprecated && \"opacity-70\"\n                  )}\n                  style={{ paddingLeft: 16 + row.depth * 20 }}\n                >\n                  {guides(row)}\n                  <div className=\"flex items-start justify-between gap-3\">{renderName(row, anchor)}</div>\n                  <dl className=\"mt-2.5 grid grid-cols-[64px_minmax(0,1fr)] gap-x-3 gap-y-2\">\n                    <dt className={cn(headerLabel, \"pt-[3px]\", palette.secondaryText)}>Type</dt>\n                    <dd>{renderType(row.param.type)}</dd>\n                    {row.param.default !== undefined ? (\n                      <>\n                        <dt className={cn(headerLabel, \"pt-[3px]\", palette.secondaryText)}>Default</dt>\n                        <dd>{renderDefault(row.param)}</dd>\n                      </>\n                    ) : null}\n                  </dl>\n                  <p className=\"mt-2.5 text-[13px] leading-[1.55]\">{renderDescription(row.param)}</p>\n                </motion.li>\n              );\n            })}\n          </ul>\n        ) : (\n          <table className=\"w-full min-w-[600px] table-fixed border-separate border-spacing-0 text-left\">\n            <caption className=\"sr-only\">{caption}</caption>\n            <colgroup>\n              <col style={{ width: \"29%\" }} />\n              <col style={{ width: \"21%\" }} />\n              <col style={{ width: \"12%\" }} />\n              <col />\n            </colgroup>\n            <thead>\n              <tr>\n                {[\"Parameter\", \"Type\", \"Default\", \"Description\"].map((label, i) => (\n                  <th\n                    key={label}\n                    scope=\"col\"\n                    className={cn(\n                      \"sticky top-0 z-10 border-b py-2.5 font-medium\",\n                      headerLabel,\n                      palette.header,\n                      i === 0 ? \"pl-5 pr-3\" : \"px-3\",\n                      i === 3 && \"pr-5\"\n                    )}\n                  >\n                    {label}\n                  </th>\n                ))}\n              </tr>\n            </thead>\n            <tbody>\n              {rows.map((row, index) => {\n                const anchor = toAnchor(anchorPrefix, row.path);\n                const cell = cn(\"border-b px-3 py-3 align-top\", palette.divider);\n                const lastRow = index === rows.length - 1;\n                return (\n                  <motion.tr\n                    key={row.path}\n                    id={anchor}\n                    {...rowMotion(row, index)}\n                    className={cn(\n                      \"group/row scroll-mt-12 transition-colors duration-150 motion-reduce:transition-none target:bg-[#ec5c13]/[0.06]\",\n                      palette.row,\n                      row.param.deprecated && \"opacity-[0.62]\",\n                      row.depth > 0 && (isDark ? \"bg-[#0d0d0d]/40\" : \"bg-[#fbf7ef]/50\")\n                    )}\n                  >\n                    <td\n                      className={cn(cell, \"relative pr-3\", lastRow && \"border-b-0\")}\n                      style={{ paddingLeft: 20 + row.depth * 20 }}\n                    >\n                      {guides(row)}\n                      {renderName(row, anchor)}\n                    </td>\n                    <td className={cn(cell, lastRow && \"border-b-0\")}>\n                      {renderType(row.param.type)}\n                      {row.param.children?.length ? (\n                        <span className={cn(\"mt-1.5 block text-[11.5px] tabular-nums\", palette.secondaryText)}>\n                          {row.param.children.length} fields\n                        </span>\n                      ) : null}\n                    </td>\n                    <td className={cn(cell, lastRow && \"border-b-0\")}>{renderDefault(row.param)}</td>\n                    <td className={cn(cell, \"pr-5 leading-[1.55]\", lastRow && \"border-b-0\")}>\n                      {renderDescription(row.param)}\n                    </td>\n                  </motion.tr>\n                );\n              })}\n            </tbody>\n          </table>\n        )}\n      </div>\n\n      <div\n        className={cn(\n          \"flex items-center justify-between gap-3 border-t px-5 py-2.5 text-[11.5px]\",\n          palette.divider,\n          palette.secondaryText,\n          narrow && \"px-4\"\n        )}\n      >\n        <span className=\"tabular-nums\">\n          {loading ? \"Loading parameters…\" : `${total} ${total === 1 ? \"parameter\" : \"parameters\"}`}\n        </span>\n        <span aria-live=\"polite\" className={cn(\"tabular-nums\", copied && green.textColor)}>\n          {copied ? \"Link copied\" : narrow ? null : \"Hover a name to copy its link\"}\n        </span>\n      </div>\n    </div>\n  );\n}\n\nexport default ApiReferenceTable;\n",
      "type": "registry:component",
      "target": "@components/bjork-ui/tables/api-reference-table.tsx"
    },
    {
      "path": "lib/utils.ts",
      "content": "import { clsx, type ClassValue } from \"clsx\"\nimport { twMerge } from \"tailwind-merge\"\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs))\n}\n",
      "type": "registry:lib",
      "target": "@lib/utils.ts"
    },
    {
      "path": "components/bjork-ui/tables/table-theme.ts",
      "content": "import { useEffect, useState } from \"react\";\n\nexport type BjorkTableThemeMode = \"light\" | \"dark\" | \"auto\";\n\nexport function useBjorkTableIsDark(\n  resolvedTheme?: string,\n  forcedTheme?: Exclude<BjorkTableThemeMode, \"auto\">\n) {\n  const [documentTheme, setDocumentTheme] = useState<\"light\" | \"dark\" | null>(null);\n  const [previewTheme, setPreviewTheme] = useState<\"light\" | \"dark\" | null>(null);\n  // Server and first client render must agree, otherwise React keeps the\n  // server-rendered (dark) classes when the real theme resolves to light.\n  const [mounted, setMounted] = useState(false);\n\n  useEffect(() => {\n    setMounted(true);\n    const syncDocumentTheme = () => {\n      const root = document.documentElement;\n      const searchParams = new URLSearchParams(window.location.search);\n      const theme = searchParams.get(\"theme\");\n\n      setPreviewTheme(theme === \"light\" || theme === \"dark\" ? theme : null);\n\n      setDocumentTheme(\n        root.classList.contains(\"light\")\n          ? \"light\"\n          : root.classList.contains(\"dark\")\n            ? \"dark\"\n            : null\n      );\n    };\n\n    syncDocumentTheme();\n\n    const observer = new MutationObserver(syncDocumentTheme);\n    observer.observe(document.documentElement, {\n      attributes: true,\n      attributeFilter: [\"class\"],\n    });\n\n    return () => observer.disconnect();\n  }, []);\n\n  const activeTheme =\n    forcedTheme ?? previewTheme ?? documentTheme ?? (mounted ? resolvedTheme : undefined);\n\n  return activeTheme !== \"light\";\n}\n\nexport function getBjorkTablePalette(isDark: boolean) {\n  return {\n    container: isDark\n      ? \"border-[#1c1c1c] bg-[#121212] shadow-[inset_0_7px_14px_rgba(255,255,255,0.03),inset_0_0.5px_0.5px_rgba(255,255,255,0.06),0_14px_20px_-6px_rgba(0,0,0,0.45)]\"\n      : \"border-[#f5ede2] bg-[#fffcf6] shadow-[inset_0_7px_14px_rgba(88,72,49,0.045),inset_0_0.5px_0.5px_rgba(255,255,255,0.92),inset_1px_0_0_rgba(88,72,49,0.026),inset_-1px_0_0_rgba(255,255,255,0.68),0_14px_22px_-9px_rgba(66,52,33,0.11)]\",\n    header: isDark\n      ? \"border-[#232323] bg-[#181818] text-[#ededed]/42\"\n      : \"border-[#f1e8dc] bg-[#fbf7ef] text-[#171717]/60\",\n    row: isDark\n      ? \"border-[#232323] hover:bg-[#181818]/70\"\n      : \"border-[#f1e8dc] hover:bg-[#f8f2e7]/72\",\n    selectedRow: isDark\n      ? \"border-[#2a2a2a] bg-[#181818]\"\n      : \"border-[#eadfce] bg-[#f8f2e7]\",\n    control: isDark\n      ? \"border-[#232323] bg-[#181818] text-[#ededed]/70 hover:bg-[#202020] shadow-[inset_0_1px_0_rgba(255,255,255,0.045)]\"\n      : \"border-[#eadfce] bg-[#fffcf6] text-[#171717]/68 shadow-[var(--bjork-shadow-soft)] hover:bg-[#f8f2e7]\",\n    menu: isDark\n      ? \"border-[#232323] bg-[#181818] text-[#ededed]/76 shadow-[inset_0_1px_0_rgba(255,255,255,0.055),inset_0_12px_24px_rgba(255,255,255,0.018),0_22px_42px_-22px_rgba(0,0,0,0.9)]\"\n      : \"border-[#eadfce] bg-[#fffcf6] text-[#171717]/76 shadow-[inset_0_1px_0_rgba(88,72,49,0.04),inset_0_12px_24px_rgba(88,72,49,0.022),0_22px_44px_-26px_rgba(66,52,33,0.22)]\",\n    menuItem: isDark ? \"hover:bg-[#232323]\" : \"hover:bg-[#f8f2e7]\",\n    menuActive: isDark ? \"bg-[#232323]\" : \"bg-[#f8f2e7]\",\n    divider: isDark ? \"border-[#232323]\" : \"border-[#f1e8dc]\",\n    primaryText: isDark ? \"text-[#ededed]/90\" : \"text-[#171717]/86\",\n    secondaryText: isDark ? \"text-[#ededed]/38\" : \"text-[#171717]/60\",\n    mutedSurface: isDark ? \"bg-[#181818]\" : \"bg-[#f8f2e7]\",\n    popover: isDark ? \"bg-[#111] text-[#ededed]\" : \"bg-[#fffcf6] text-[#171717]\",\n    accent: isDark ? \"text-[#d86a2c]\" : \"text-[#bd4514]\",\n    accentBg: isDark ? \"bg-[#ec5c13]/12\" : \"bg-[#ec5c13]/14\",\n    accentBorder: isDark ? \"border-[#ec5c13]/24\" : \"border-[#bd4514]/22\",\n    checkboxAccent: isDark ? \"#d86a2c\" : \"#bd4514\",\n  };\n}\n\nexport function getBjorkSignalPalette(\n  tone: \"green\" | \"red\" | \"orange\" | \"neutral\",\n  isDark: boolean\n) {\n  const palettes = {\n    green: {\n      bgColor: isDark ? \"bg-[#3e6f52]/18\" : \"bg-[#dce8dc]\",\n      borderColor: isDark ? \"border-[#5f9f78]/28\" : \"border-[#bad0bd]\",\n      textColor: isDark ? \"text-[#77b58b]\" : \"text-[#47785c]\",\n      dotColor: isDark ? \"bg-[#77b58b]\" : \"bg-[#47785c]\",\n      color: isDark ? \"#77b58b\" : \"#47785c\",\n    },\n    red: {\n      bgColor: isDark ? \"bg-[#87463f]/18\" : \"bg-[#eadad5]\",\n      borderColor: isDark ? \"border-[#c46a61]/28\" : \"border-[#d7bcb4]\",\n      textColor: isDark ? \"text-[#cf7c72]\" : \"text-[#9d5149]\",\n      dotColor: isDark ? \"bg-[#cf7c72]\" : \"bg-[#9d5149]\",\n      color: isDark ? \"#cf7c72\" : \"#9d5149\",\n    },\n    orange: {\n      bgColor: isDark ? \"bg-[#ec5c13]/14\" : \"bg-[#ead9cb]\",\n      borderColor: isDark ? \"border-[#ec5c13]/28\" : \"border-[#d5b59f]\",\n      textColor: isDark ? \"text-[#d86a2c]\" : \"text-[#9f4317]\",\n      dotColor: isDark ? \"bg-[#d86a2c]\" : \"bg-[#9f4317]\",\n      color: isDark ? \"#d86a2c\" : \"#9f4317\",\n    },\n    neutral: {\n      bgColor: isDark ? \"bg-[#ededed]/8\" : \"bg-[#ded7ca]\",\n      borderColor: isDark ? \"border-[#ededed]/14\" : \"border-[#cfc6b7]\",\n      textColor: isDark ? \"text-[#ededed]/58\" : \"text-[#171717]/60\",\n      dotColor: isDark ? \"bg-[#ededed]/45\" : \"bg-[#171717]/42\",\n      color: isDark ? \"#a3a3a3\" : \"#706b62\",\n    },\n  } as const;\n\n  return palettes[tone];\n}\n",
      "type": "registry:component",
      "target": "@components/bjork-ui/tables/table-theme.ts"
    }
  ],
  "cssVars": {
    "light": {
      "bjork-bg": "#f7f3ea",
      "bjork-surface": "#fffcf6",
      "bjork-surface-muted": "rgba(250, 246, 237, 0.94)",
      "bjork-surface-hover": "#f5efe3",
      "bjork-surface-active": "#efe7d8",
      "bjork-panel": "#f8f2e7",
      "bjork-menu": "rgba(255, 252, 246, 0.98)",
      "bjork-field": "rgba(255, 252, 246, 0.96)",
      "bjork-field-muted": "rgba(248, 242, 231, 0.82)",
      "bjork-field-inset": "rgba(239, 231, 216, 0.72)",
      "bjork-error-bg": "#fff0e8",
      "bjork-text": "#171717",
      "bjork-text-strong": "rgba(23, 23, 23, 0.9)",
      "bjork-text-medium": "rgba(23, 23, 23, 0.78)",
      "bjork-text-muted": "rgba(23, 23, 23, 0.68)",
      "bjork-text-soft": "rgba(23, 23, 23, 0.62)",
      "bjork-text-faint": "rgba(23, 23, 23, 0.22)",
      "bjork-inverted-text": "#fff8f0",
      "bjork-border": "#eee6db",
      "bjork-border-muted": "#f5ede2",
      "bjork-border-strong": "#e1d7c8",
      "bjork-thumb": "#a49b8e",
      "bjork-track": "#ded6ca",
      "bjork-accent": "#ec7d43",
      "bjork-accent-hover": "#f0935f",
      "bjork-accent-soft": "rgba(236, 125, 67, 0.1)",
      "bjork-accent-muted": "rgba(236, 125, 67, 0.2)",
      "bjork-accent-badge": "rgba(236, 125, 67, 0.16)",
      "bjork-accent-badge-foreground": "#8d421d",
      "bjork-accent-foreground": "#3f2112",
      "bjork-accent-fill": "#ec7d43",
      "bjork-accent-fill-hover": "#f0935f",
      "bjork-shadow-surface": "inset 0 7px 14px rgba(88, 72, 49, 0.045), inset 0 0.5px 0.5px rgba(255, 255, 255, 0.92), inset 1px 0 0 rgba(88, 72, 49, 0.026), inset -1px 0 0 rgba(255, 255, 255, 0.68), 0 14px 22px -9px rgba(66, 52, 33, 0.11)",
      "bjork-shadow-soft": "inset 0 1px 0 rgba(88, 72, 49, 0.045), inset 0 0.5px 0.5px rgba(255, 255, 255, 0.86)",
      "bjork-shadow-panel": "inset 0 1px 0 rgba(88, 72, 49, 0.04), inset 1px 0 0 rgba(88, 72, 49, 0.024), inset -1px 0 0 rgba(255, 255, 255, 0.64), 0 18px 38px -30px rgba(66, 52, 33, 0.2)",
      "bjork-shadow-menu": "inset 0 1px 0 rgba(88, 72, 49, 0.04), inset 0 12px 24px rgba(88, 72, 49, 0.022), inset 1px 0 0 rgba(88, 72, 49, 0.024), inset -1px 0 0 rgba(255, 255, 255, 0.62), 0 22px 44px -26px rgba(66, 52, 33, 0.22)",
      "bjork-shadow-inset": "inset 0 1px 10px rgba(88, 72, 49, 0.12), inset 0 0.5px 0.5px rgba(255, 255, 255, 0.72)",
      "bjork-ring-offset": "#f7f3ea"
    },
    "dark": {
      "bjork-bg": "#111111",
      "bjork-surface": "#121212",
      "bjork-surface-muted": "rgba(22, 22, 22, 0.92)",
      "bjork-surface-hover": "#161616",
      "bjork-surface-active": "#202020",
      "bjork-panel": "#0d0d0d",
      "bjork-menu": "rgba(18, 18, 18, 0.98)",
      "bjork-field": "rgba(18, 18, 18, 0.95)",
      "bjork-field-muted": "rgba(18, 18, 18, 0.55)",
      "bjork-field-inset": "rgba(9, 9, 9, 0.75)",
      "bjork-error-bg": "#130d0a",
      "bjork-text": "#ededed",
      "bjork-text-strong": "rgba(237, 237, 237, 0.9)",
      "bjork-text-medium": "rgba(237, 237, 237, 0.72)",
      "bjork-text-muted": "rgba(237, 237, 237, 0.6)",
      "bjork-text-soft": "rgba(237, 237, 237, 0.5)",
      "bjork-text-faint": "rgba(237, 237, 237, 0.22)",
      "bjork-inverted-text": "#080808",
      "bjork-border": "#232323",
      "bjork-border-muted": "#1c1c1c",
      "bjork-border-strong": "#343434",
      "bjork-thumb": "#626262",
      "bjork-track": "#090909",
      "bjork-accent": "#ec5c13",
      "bjork-accent-hover": "#f07832",
      "bjork-accent-soft": "rgba(236, 92, 19, 0.12)",
      "bjork-accent-muted": "rgba(236, 92, 19, 0.24)",
      "bjork-accent-badge": "#b84a12",
      "bjork-accent-badge-foreground": "#fff2ea",
      "bjork-accent-foreground": "#fff2ea",
      "bjork-accent-fill": "#b84a12",
      "bjork-accent-fill-hover": "#a84a14",
      "bjork-shadow-surface": "inset 0 7px 14px rgba(255, 255, 255, 0.03), inset 0 0.5px 0.5px rgba(255, 255, 255, 0.06), 0 14px 20px -6px rgba(0, 0, 0, 0.45)",
      "bjork-shadow-soft": "inset 0 1px 0 rgba(255, 255, 255, 0.045)",
      "bjork-shadow-panel": "inset 0 1px 0 rgba(255, 255, 255, 0.035), 0 18px 36px -28px rgba(0, 0, 0, 0.9)",
      "bjork-shadow-menu": "inset 0 1px 0 rgba(255, 255, 255, 0.055), inset 0 12px 24px rgba(255, 255, 255, 0.018), inset 0 -18px 26px rgba(0, 0, 0, 0.24), 0 22px 42px -22px rgba(0, 0, 0, 0.9)",
      "bjork-shadow-inset": "inset 0 1px 10px rgba(0, 0, 0, 0.45)",
      "bjork-ring-offset": "#080808"
    }
  },
  "css": {
    ".bjork-range": {
      "box-shadow": "inset 0 1px 1px rgba(255, 255, 255, 0.04), 0 0 14px rgba(189, 69, 20, 0.06)"
    },
    ".bjork-range::-webkit-slider-thumb": {
      "appearance": "none",
      "width": "16px",
      "height": "8px",
      "border": "0",
      "border-radius": "999px",
      "background": "var(--bjork-thumb)",
      "box-shadow": "inset 0 1px 0 rgba(255, 255, 255, 0.18), 0 0 0 1px rgba(0, 0, 0, 0.42)"
    },
    ".bjork-range::-moz-range-thumb": {
      "width": "16px",
      "height": "8px",
      "border": "0",
      "border-radius": "999px",
      "background": "var(--bjork-thumb)",
      "box-shadow": "inset 0 1px 0 rgba(255, 255, 255, 0.18), 0 0 0 1px rgba(0, 0, 0, 0.42)"
    },
    ".bjork-layered-button-accent, .bjork-layered-button-raised": {
      "position": "relative",
      "isolation": "isolate",
      "appearance": "none",
      "overflow": "hidden",
      "border": "0",
      "border-radius": "13px",
      "box-shadow": "inset 0 1px 0 #ffffff38, 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a",
      "transition": "filter 150ms ease-out, box-shadow 150ms ease-out"
    },
    ".bjork-layered-button-accent::after, .bjork-layered-button-raised::after": {
      "position": "absolute",
      "inset": "0",
      "pointer-events": "none",
      "content": "\"\"",
      "border": "1.5px solid transparent",
      "border-radius": "inherit",
      "background": "linear-gradient(#ffffffb8, #0000003d 41% 75%, #ffffff47) border-box",
      "mix-blend-mode": "overlay",
      "-webkit-mask-image": "linear-gradient(#000, #000), linear-gradient(#000, #000)",
      "mask-image": "linear-gradient(#000, #000), linear-gradient(#000, #000)",
      "-webkit-mask-clip": "padding-box, border-box",
      "mask-clip": "padding-box, border-box",
      "-webkit-mask-origin": "padding-box, border-box",
      "mask-origin": "padding-box, border-box",
      "-webkit-mask-composite": "xor",
      "mask-composite": "exclude"
    },
    ".bjork-layered-button-accent": {
      "color": "oklch(100% 0 0)",
      "text-shadow": "0 -1px #00000040",
      "background": "radial-gradient(ellipse at -20px top, rgba(255, 255, 255, 0.14), transparent), linear-gradient(180deg, #ec5c13 0%, #ec5c13 62%, color-mix(in oklab, #ec5c13 84%, black 16%) 100%)"
    },
    ".bjork-layered-button-raised": {
      "color": "oklch(100% 0 0)",
      "text-shadow": "0 -1px #00000026",
      "background": "radial-gradient(ellipse at -20px top, #ffffff38, #fff0), linear-gradient(180deg, oklch(0.1881 0.006 265), oklch(0.5493 0.0081 265))"
    },
    ".dark .bjork-layered-button-raised": {
      "color": "oklch(0.2574 0.0056 265)",
      "text-shadow": "0 -1px #00000026",
      "background": "radial-gradient(ellipse at -20px top, #ffffff38, #fff0), linear-gradient(180deg, color-mix(in oklab, oklch(0.9674 0.0013 265) 80%, oklch(0.2574 0.0056 265) 20%), color-mix(in oklab, oklch(0.669 0.0107 265) 80%, oklch(0.2574 0.0056 265) 20%))"
    },
    "@media (hover: hover)": {
      ".bjork-layered-button-accent:hover": {
        "filter": "brightness(1.08) saturate(1.04)"
      },
      ".bjork-layered-button-raised:hover": {
        "filter": "brightness(1.08) contrast(0.9)"
      }
    }
  },
  "meta": {
    "collection": "Tables",
    "registryUrl": "https://ui.isaiahbjork.com/api-reference-table.json",
    "installCommand": "npx shadcn@latest add https://ui.isaiahbjork.com/api-reference-table.json"
  },
  "type": "registry:component"
}