{"$schema":"https://ui.shadcn.com/schema/registry.json","name":"compass","homepage":"https://0.0.0.0:3000","items":[{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"compass","title":"COMPASS","type":"registry:block","registryDependencies":["https://0.0.0.0:3000/r/0.1.0/foundations.json"],"cssVars":{"theme":{"shadow-sm":"var(--surface-shadow-sm)","shadow-md":"var(--surface-shadow-md)","shadow-lg":"var(--surface-shadow-lg)","font-heading":"\"Pretendard Variable\", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, sans-serif","font-sans":"\"Pretendard Variable\", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, sans-serif","font-mono":"\"SFMono-Regular\", Consolas, \"Liberation Mono\", Menlo, monospace","color-sidebar-ring":"var(--sidebar-ring)","color-sidebar-border":"var(--sidebar-border)","color-sidebar-accent-foreground":"var(--sidebar-accent-foreground)","color-sidebar-accent":"var(--sidebar-accent)","color-sidebar-primary-foreground":"var(--sidebar-primary-foreground)","color-sidebar-primary":"var(--sidebar-primary)","color-sidebar-foreground":"var(--sidebar-foreground)","color-sidebar":"var(--sidebar)","color-chart-5":"var(--chart-5)","color-chart-4":"var(--chart-4)","color-chart-3":"var(--chart-3)","color-chart-2":"var(--chart-2)","color-chart-1":"var(--chart-1)","color-ring":"var(--ring)","color-input":"var(--input)","color-border":"var(--border)","color-destructive":"var(--destructive)","color-accent-foreground":"var(--accent-foreground)","color-accent":"var(--accent)","color-muted-foreground":"var(--muted-foreground)","color-muted":"var(--muted)","color-secondary-foreground":"var(--secondary-foreground)","color-secondary":"var(--secondary)","color-primary-foreground":"var(--primary-foreground)","color-primary":"var(--primary)","color-primary-hover":"var(--primary-hover)","color-popover-foreground":"var(--popover-foreground)","color-popover":"var(--popover)","color-card-foreground":"var(--card-foreground)","color-card":"var(--card)","color-foreground":"var(--foreground)","color-background":"var(--background)","color-gallery-background":"var(--gallery-background)","radius-sm":"calc(var(--radius) * 0.15)","radius-md":"calc(var(--radius) * 0.2)","radius-lg":"calc(var(--radius) * 0.25)","radius-xl":"calc(var(--radius) * 0.35)","radius-2xl":"calc(var(--radius) * 0.45)","radius-3xl":"calc(var(--radius) * 0.55)","radius-4xl":"calc(var(--radius) * 0.65)","radius-5xl":"calc(var(--radius) * 0.8)","radius-6xl":"var(--radius)","radius-container":"min(var(--radius), max(0px, calc(var(--nested-radius, var(--radius)) + var(--nested-gap, 0px))))"},"light":{"corner-shape":"squircle","surface-shadow-sm":"0 1px 3px 0 rgb(0 0 0 / 10%), 0 1px 2px -1px rgb(0 0 0 / 10%)","surface-shadow-md":"0 4px 6px -1px rgb(0 0 0 / 10%), 0 2px 4px -2px rgb(0 0 0 / 10%)","surface-shadow-lg":"0 10px 15px -3px rgb(0 0 0 / 10%), 0 4px 6px -4px rgb(0 0 0 / 10%)","background":"#ffffff","gallery-background":"#f7f7f7","gallery-preview-background":"oklch(1 0 0)","foreground":"oklch(0.145 0 0)","card":"oklch(1 0 0)","card-foreground":"oklch(0.145 0 0)","popover":"oklch(1 0 0)","popover-foreground":"oklch(0.145 0 0)","primary":"#007AFF","primary-hover":"color-mix(in oklch, var(--primary), black 12%)","primary-foreground":"#ffffff","secondary":"oklch(0.97 0 0)","secondary-foreground":"oklch(0.205 0 0)","muted":"oklch(0.97 0 0)","muted-foreground":"oklch(0.556 0 0)","accent":"#007AFF","accent-foreground":"#ffffff","destructive":"oklch(0.577 0.245 27.325)","border":"oklch(0.922 0 0)","input":"oklch(0.922 0 0)","ring":"oklch(0.708 0 0)","chart-1":"oklch(0.87 0 0)","chart-2":"oklch(0.556 0 0)","chart-3":"oklch(0.439 0 0)","chart-4":"oklch(0.371 0 0)","chart-5":"oklch(0.269 0 0)","radius":"2.5rem","sidebar":"oklch(0.985 0 0)","sidebar-foreground":"oklch(0.145 0 0)","sidebar-primary":"oklch(0.205 0 0)","sidebar-primary-foreground":"oklch(0.985 0 0)","sidebar-accent":"oklch(0.97 0 0)","sidebar-accent-foreground":"oklch(0.205 0 0)","sidebar-border":"oklch(0.922 0 0)","sidebar-ring":"oklch(0.708 0 0)"},"dark":{"surface-shadow-sm":"0 2px 6px 0 rgb(0 0 0 / 40%), 0 1px 2px 0 rgb(0 0 0 / 25%)","surface-shadow-md":"0 6px 16px -2px rgb(0 0 0 / 50%), 0 2px 6px 0 rgb(0 0 0 / 35%)","surface-shadow-lg":"0 14px 32px -4px rgb(0 0 0 / 65%), 0 6px 12px -2px rgb(0 0 0 / 45%)","background":"oklch(0.15 0 0)","gallery-background":"oklch(0.15 0 0)","gallery-preview-background":"oklch(0.18 0 0)","foreground":"oklch(0.985 0 0)","card":"oklch(0.205 0 0)","card-foreground":"oklch(0.985 0 0)","popover":"oklch(0.205 0 0)","popover-foreground":"oklch(0.985 0 0)","primary":"#007AFF","primary-foreground":"#ffffff","secondary":"oklch(0.269 0 0)","secondary-foreground":"oklch(0.985 0 0)","muted":"oklch(0.269 0 0)","muted-foreground":"oklch(0.708 0 0)","accent":"#007AFF","accent-foreground":"#ffffff","destructive":"oklch(0.704 0.191 22.216)","border":"oklch(1 0 0 / 10%)","input":"oklch(1 0 0 / 15%)","ring":"oklch(0.556 0 0)","chart-1":"oklch(0.87 0 0)","chart-2":"oklch(0.556 0 0)","chart-3":"oklch(0.439 0 0)","chart-4":"oklch(0.371 0 0)","chart-5":"oklch(0.269 0 0)","sidebar":"oklch(0.205 0 0)","sidebar-foreground":"oklch(0.985 0 0)","sidebar-primary":"oklch(0.488 0.243 264.376)","sidebar-primary-foreground":"oklch(0.985 0 0)","sidebar-accent":"oklch(0.269 0 0)","sidebar-accent-foreground":"oklch(0.985 0 0)","sidebar-border":"oklch(1 0 0 / 10%)","sidebar-ring":"oklch(0.556 0 0)"}},"css":{"@import \"tw-animate-css\"":{},"@import \"shadcn/tailwind.css\"":{},"@custom-variant dark (&:is(.dark *))":{},"@layer base":{"*":{"@apply border-border outline-ring/50":{}},"body":{"@apply bg-background text-foreground":{}},"button:not(:disabled), [role=\"button\"]:not(:disabled)":{"cursor":"pointer"},"html":{"@apply font-sans":{}},"@supports (corner-shape: squircle)":{"*":{"corner-shape":"var(--corner-shape)"},"::before, ::after":{"corner-shape":"inherit"},":where(.rounded-full, [data-slot=\"badge\"],\n           [data-slot^=\"avatar\"], [data-slot=\"slider-thumb\"],\n           [data-slot=\"slider-track\"], [data-slot=\"progress\"],\n           [data-corner=\"round\"])":{"corner-shape":"round"}}},"@import \"pretendard/dist/web/variable/pretendardvariable.css\"":{}},"dependencies":["class-variance-authority@0.7.1","cn@0.4.0","lucide-react@1.52.0","next-themes@0.4.6","pretendard@1.3.9","radix-ui@1.6.7","shadcn@4.21.0","tw-animate-css@1.4.0"],"files":[{"path":"components/ui/alert-dialog.tsx","type":"registry:ui","target":"@ui/alert-dialog.tsx","content":"\"use client\"\n\nimport * as React from \"react\"\nimport { cn } from \"cn\"\nimport { AlertDialog as AlertDialogPrimitive } from \"radix-ui\"\n\nimport { Button } from \"@/components/ui/button\"\n\nfunction AlertDialog({\n  ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Root>) {\n  return <AlertDialogPrimitive.Root data-slot=\"alert-dialog\" {...props} />\n}\n\nfunction AlertDialogTrigger({\n  ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Trigger>) {\n  return (\n    <AlertDialogPrimitive.Trigger data-slot=\"alert-dialog-trigger\" {...props} />\n  )\n}\n\nfunction AlertDialogPortal({\n  ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Portal>) {\n  return (\n    <AlertDialogPrimitive.Portal data-slot=\"alert-dialog-portal\" {...props} />\n  )\n}\n\nfunction AlertDialogOverlay({\n  className,\n  ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Overlay>) {\n  return (\n    <AlertDialogPrimitive.Overlay\n      data-slot=\"alert-dialog-overlay\"\n      className={cn(\n        \"fixed inset-0 z-50 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction AlertDialogContent({\n  className,\n  size = \"default\",\n  ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Content> & {\n  size?: \"default\" | \"sm\"\n}) {\n  return (\n    <AlertDialogPortal>\n      <AlertDialogOverlay />\n      <AlertDialogPrimitive.Content\n        data-slot=\"alert-dialog-content\"\n        data-size={size}\n        className={cn(\n          \"group/alert-dialog-content fixed top-1/2 left-1/2 z-50 grid w-full -translate-x-1/2 -translate-y-1/2 gap-4 rounded-container [--nested-radius:var(--radius)] [--nested-gap:0px] has-[[data-slot=alert-dialog-footer]_button]:[--nested-radius:calc(var(--radius)*0.55)] has-[[data-slot=alert-dialog-footer]_button]:[--nested-gap:--spacing(4)] bg-popover p-4 text-popover-foreground ring-1 ring-foreground/10 duration-100 outline-none data-[size=default]:max-w-xs data-[size=sm]:max-w-xs data-[size=default]:sm:max-w-sm data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95\",\n          className\n        )}\n        {...props}\n      />\n    </AlertDialogPortal>\n  )\n}\n\nfunction AlertDialogHeader({\n  className,\n  ...props\n}: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"alert-dialog-header\"\n      className={cn(\n        \"grid grid-rows-[auto_1fr] place-items-center gap-1.5 text-center has-data-[slot=alert-dialog-media]:grid-rows-[auto_auto_1fr] has-data-[slot=alert-dialog-media]:gap-x-4 sm:group-data-[size=default]/alert-dialog-content:place-items-start sm:group-data-[size=default]/alert-dialog-content:text-left sm:group-data-[size=default]/alert-dialog-content:has-data-[slot=alert-dialog-media]:grid-rows-[auto_1fr]\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction AlertDialogFooter({\n  className,\n  ...props\n}: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"alert-dialog-footer\"\n      className={cn(\n        \"-mx-4 -mb-4 flex flex-col-reverse gap-2 rounded-b-container border-t bg-muted/50 p-4 group-data-[size=sm]/alert-dialog-content:grid group-data-[size=sm]/alert-dialog-content:grid-cols-2 sm:flex-row sm:justify-end\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction AlertDialogMedia({\n  className,\n  ...props\n}: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"alert-dialog-media\"\n      className={cn(\n        \"mb-2 inline-flex size-10 items-center justify-center rounded-md bg-muted sm:group-data-[size=default]/alert-dialog-content:row-span-2 *:[svg:not([class*='size-'])]:size-6\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction AlertDialogTitle({\n  className,\n  ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Title>) {\n  return (\n    <AlertDialogPrimitive.Title\n      data-slot=\"alert-dialog-title\"\n      className={cn(\n        \"font-heading text-base font-medium sm:group-data-[size=default]/alert-dialog-content:group-has-data-[slot=alert-dialog-media]/alert-dialog-content:col-start-2\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction AlertDialogDescription({\n  className,\n  ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Description>) {\n  return (\n    <AlertDialogPrimitive.Description\n      data-slot=\"alert-dialog-description\"\n      className={cn(\n        \"text-sm text-balance text-muted-foreground md:text-pretty *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction AlertDialogAction({\n  className,\n  variant = \"default\",\n  size = \"default\",\n  ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Action> &\n  Pick<React.ComponentProps<typeof Button>, \"variant\" | \"size\">) {\n  return (\n    <Button variant={variant} size={size} asChild>\n      <AlertDialogPrimitive.Action\n        data-slot=\"alert-dialog-action\"\n        className={cn(className)}\n        {...props}\n      />\n    </Button>\n  )\n}\n\nfunction AlertDialogCancel({\n  className,\n  variant = \"outline\",\n  size = \"default\",\n  ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Cancel> &\n  Pick<React.ComponentProps<typeof Button>, \"variant\" | \"size\">) {\n  return (\n    <Button variant={variant} size={size} asChild>\n      <AlertDialogPrimitive.Cancel\n        data-slot=\"alert-dialog-cancel\"\n        className={cn(className)}\n        {...props}\n      />\n    </Button>\n  )\n}\n\nexport {\n  AlertDialog,\n  AlertDialogAction,\n  AlertDialogCancel,\n  AlertDialogContent,\n  AlertDialogDescription,\n  AlertDialogFooter,\n  AlertDialogHeader,\n  AlertDialogMedia,\n  AlertDialogOverlay,\n  AlertDialogPortal,\n  AlertDialogTitle,\n  AlertDialogTrigger,\n}\n"},{"path":"components/ui/button.tsx","type":"registry:ui","target":"@ui/button.tsx","content":"import * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { cn } from \"cn\"\nimport { Slot } from \"radix-ui\"\n\nconst buttonVariants = cva(\n  \"group/button inline-flex shrink-0 items-center justify-center rounded-3xl border border-transparent bg-clip-padding py-[4pt] text-base font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n  {\n    variants: {\n      variant: {\n        default: \"bg-primary text-primary-foreground hover:bg-primary-hover hover:[&:not([data-size^=icon])]:text-[color-mix(in_oklch,var(--primary-foreground),transparent_20%)]\",\n        outline:\n          \"border-border bg-transparent hover:bg-black/5 hover:text-foreground hover:[&:not([data-size^=icon])]:text-[color-mix(in_oklch,var(--foreground),transparent_20%)] aria-expanded:text-foreground dark:border-input dark:hover:bg-white/5\",\n        secondary:\n          \"bg-secondary text-secondary-foreground hover:bg-[color-mix(in_oklch,var(--secondary),black_8%)] hover:[&:not([data-size^=icon])]:text-[color-mix(in_oklch,var(--secondary-foreground),transparent_20%)] aria-expanded:bg-secondary aria-expanded:text-secondary-foreground\",\n        ghost:\n          \"hover:bg-black/5 hover:text-foreground hover:[&:not([data-size^=icon])]:text-[color-mix(in_oklch,var(--foreground),transparent_20%)] aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-white/5\",\n        destructive:\n          \"bg-destructive/10 text-destructive hover:bg-destructive/20 hover:[&:not([data-size^=icon])]:text-[color-mix(in_oklch,var(--destructive),transparent_20%)] focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-black/20 dark:focus-visible:ring-destructive/40\",\n        link: \"text-primary underline-offset-4 hover:text-primary-hover hover:[&:not([data-size^=icon])]:text-[color-mix(in_oklch,var(--primary),transparent_20%)] hover:underline\",\n      },\n      size: {\n        default:\n          \"h-[calc(2.5rem+8pt)] gap-2 px-[calc(1rem+4pt)] has-data-[icon=inline-end]:pr-[calc(.75rem+4pt)] has-data-[icon=inline-start]:pl-[calc(.75rem+4pt)]\",\n        xs: \"h-[calc(2rem+8pt)] gap-1.5 rounded-3xl px-[calc(.75rem+4pt)] text-[calc(0.75rem+2pt)] in-data-[slot=button-group]:rounded-3xl has-data-[icon=inline-end]:pr-[calc(.625rem+4pt)] has-data-[icon=inline-start]:pl-[calc(.625rem+4pt)] [&_svg:not([class*='size-'])]:size-3\",\n        sm: \"h-[calc(2.25rem+8pt)] gap-1.5 rounded-3xl px-[calc(.875rem+4pt)] text-[calc(0.8rem+2pt)] in-data-[slot=button-group]:rounded-3xl has-data-[icon=inline-end]:pr-[calc(.75rem+4pt)] has-data-[icon=inline-start]:pl-[calc(.75rem+4pt)] [&_svg:not([class*='size-'])]:size-3.5\",\n        lg: \"h-[calc(2.75rem+8pt)] gap-2 px-[calc(1.25rem+4pt)] has-data-[icon=inline-end]:pr-[calc(1rem+4pt)] has-data-[icon=inline-start]:pl-[calc(1rem+4pt)]\",\n        icon: \"size-[calc(2.5rem+8pt)]\",\n        \"icon-xs\":\n          \"size-[calc(2rem+8pt)] rounded-3xl in-data-[slot=button-group]:rounded-3xl [&_svg:not([class*='size-'])]:size-3\",\n        \"icon-sm\":\n          \"size-[calc(2.25rem+8pt)] rounded-3xl in-data-[slot=button-group]:rounded-3xl\",\n        \"icon-lg\": \"size-[calc(2.75rem+8pt)]\",\n      },\n    },\n    defaultVariants: {\n      variant: \"default\",\n      size: \"default\",\n    },\n  }\n)\n\nfunction Button({\n  className,\n  variant = \"default\",\n  size = \"default\",\n  asChild = false,\n  ...props\n}: React.ComponentProps<\"button\"> &\n  VariantProps<typeof buttonVariants> & {\n    asChild?: boolean\n  }) {\n  const Comp = asChild ? Slot.Root : \"button\"\n\n  return (\n    <Comp\n      data-slot=\"button\"\n      data-variant={variant}\n      data-size={size}\n      className={cn(buttonVariants({ variant, size, className }))}\n      {...props}\n    />\n  )\n}\n\nexport { Button, buttonVariants }\n"},{"path":"components/ui/avatar.tsx","type":"registry:ui","target":"@ui/avatar.tsx","content":"\"use client\"\n\nimport * as React from \"react\"\nimport { cn } from \"cn\"\nimport { Avatar as AvatarPrimitive } from \"radix-ui\"\n\nfunction Avatar({\n  className,\n  size = \"default\",\n  ...props\n}: React.ComponentProps<typeof AvatarPrimitive.Root> & {\n  size?: \"default\" | \"sm\" | \"lg\"\n}) {\n  return (\n    <AvatarPrimitive.Root\n      data-slot=\"avatar\"\n      data-size={size}\n      className={cn(\n        \"group/avatar relative flex size-8 shrink-0 rounded-full select-none after:absolute after:inset-0 after:rounded-full after:border after:border-border after:mix-blend-darken data-[size=lg]:size-10 data-[size=sm]:size-6 dark:after:mix-blend-lighten\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction AvatarImage({\n  className,\n  ...props\n}: React.ComponentProps<typeof AvatarPrimitive.Image>) {\n  return (\n    <AvatarPrimitive.Image\n      data-slot=\"avatar-image\"\n      className={cn(\n        \"aspect-square size-full rounded-full object-cover\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction AvatarFallback({\n  className,\n  ...props\n}: React.ComponentProps<typeof AvatarPrimitive.Fallback>) {\n  return (\n    <AvatarPrimitive.Fallback\n      data-slot=\"avatar-fallback\"\n      className={cn(\n        \"flex size-full items-center justify-center rounded-full bg-muted text-sm text-muted-foreground group-data-[size=sm]/avatar:text-xs\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction AvatarBadge({ className, ...props }: React.ComponentProps<\"span\">) {\n  return (\n    <span\n      data-slot=\"avatar-badge\"\n      className={cn(\n        \"absolute right-0 bottom-0 z-10 inline-flex items-center justify-center rounded-full bg-primary text-primary-foreground bg-blend-color ring-2 ring-background select-none\",\n        \"group-data-[size=sm]/avatar:size-2 group-data-[size=sm]/avatar:[&>svg]:hidden\",\n        \"group-data-[size=default]/avatar:size-2.5 group-data-[size=default]/avatar:[&>svg]:size-2\",\n        \"group-data-[size=lg]/avatar:size-3 group-data-[size=lg]/avatar:[&>svg]:size-2\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction AvatarGroup({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"avatar-group\"\n      className={cn(\n        \"group/avatar-group flex -space-x-2 *:data-[slot=avatar]:ring-2 *:data-[slot=avatar]:ring-background\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction AvatarGroupCount({\n  className,\n  ...props\n}: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"avatar-group-count\"\n      className={cn(\n        \"relative flex size-8 shrink-0 items-center justify-center rounded-full bg-muted text-sm text-muted-foreground ring-2 ring-background group-has-data-[size=lg]/avatar-group:size-10 group-has-data-[size=sm]/avatar-group:size-6 [&>svg]:size-4 group-has-data-[size=lg]/avatar-group:[&>svg]:size-5 group-has-data-[size=sm]/avatar-group:[&>svg]:size-3\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nexport {\n  Avatar,\n  AvatarImage,\n  AvatarFallback,\n  AvatarGroup,\n  AvatarGroupCount,\n  AvatarBadge,\n}\n"},{"path":"components/ui/badge.tsx","type":"registry:ui","target":"@ui/badge.tsx","content":"import * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { cn } from \"cn\"\nimport { Slot } from \"radix-ui\"\n\nconst badgeVariants = cva(\n  \"group/badge inline-flex min-h-9 w-fit shrink-0 items-center justify-center gap-2 overflow-hidden rounded-4xl border border-transparent px-4 py-1.5 text-base font-medium whitespace-nowrap transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-3.5 has-data-[icon=inline-start]:pl-3.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-4!\",\n  {\n    variants: {\n      variant: {\n        default: \"bg-primary text-primary-foreground [a]:hover:bg-primary/80\",\n        secondary:\n          \"bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80\",\n        destructive:\n          \"bg-destructive/10 text-destructive focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:focus-visible:ring-destructive/40 [a]:hover:bg-destructive/20\",\n        outline:\n          \"border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground\",\n        ghost:\n          \"hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50\",\n        link: \"text-primary underline-offset-4 hover:underline\",\n      },\n    },\n    defaultVariants: {\n      variant: \"default\",\n    },\n  }\n)\n\nfunction Badge({\n  className,\n  variant = \"default\",\n  asChild = false,\n  ...props\n}: React.ComponentProps<\"span\"> &\n  VariantProps<typeof badgeVariants> & { asChild?: boolean }) {\n  const Comp = asChild ? Slot.Root : \"span\"\n\n  return (\n    <Comp\n      data-slot=\"badge\"\n      data-variant={variant}\n      className={cn(badgeVariants({ variant }), className)}\n      {...props}\n    />\n  )\n}\n\nexport { Badge, badgeVariants }\n"},{"path":"components/ui/card.tsx","type":"registry:ui","target":"@ui/card.tsx","content":"import * as React from \"react\"\nimport { cn } from \"cn\"\n\nfunction Card({\n  className,\n  size = \"default\",\n  ...props\n}: React.ComponentProps<\"div\"> & { size?: \"default\" | \"sm\" }) {\n  return (\n    <div\n      data-slot=\"card\"\n      data-size={size}\n      className={cn(\n        \"group/card flex flex-col gap-(--card-spacing) overflow-hidden rounded-container [--nested-radius:var(--radius)] [--nested-gap:0px] has-[[data-slot=card-footer]_button]:[--nested-radius:calc(var(--radius)*0.55)] has-[[data-slot=card-footer]_button]:[--nested-gap:var(--card-spacing)] bg-card py-(--card-spacing) text-sm text-card-foreground ring-1 ring-foreground/10 [--card-spacing:--spacing(4)] has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:[--card-spacing:--spacing(3)] data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-container *:[img:last-child]:rounded-b-container\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction CardHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"card-header\"\n      className={cn(\n        \"group/card-header @container/card-header grid auto-rows-min items-start gap-1 rounded-t-container px-(--card-spacing) has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto] [.border-b]:pb-(--card-spacing)\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction CardTitle({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"card-title\"\n      className={cn(\n        \"font-heading text-base leading-snug font-medium group-data-[size=sm]/card:text-sm\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction CardDescription({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"card-description\"\n      className={cn(\"text-sm text-muted-foreground\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction CardAction({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"card-action\"\n      className={cn(\n        \"col-start-2 row-span-2 row-start-1 self-start justify-self-end\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction CardContent({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"card-content\"\n      className={cn(\"px-(--card-spacing)\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction CardFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"card-footer\"\n      className={cn(\n        \"flex items-center rounded-b-container border-t bg-muted/50 p-(--card-spacing)\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nexport {\n  Card,\n  CardHeader,\n  CardFooter,\n  CardTitle,\n  CardAction,\n  CardDescription,\n  CardContent,\n}\n"},{"path":"components/ui/dialog.tsx","type":"registry:ui","target":"@ui/dialog.tsx","content":"\"use client\"\n\nimport * as React from \"react\"\nimport { cn } from \"cn\"\nimport { Dialog as DialogPrimitive } from \"radix-ui\"\n\nimport { Button } from \"@/components/ui/button\"\n\nimport { X } from \"lucide-react\"\n\nfunction Dialog({\n  ...props\n}: React.ComponentProps<typeof DialogPrimitive.Root>) {\n  return <DialogPrimitive.Root data-slot=\"dialog\" {...props} />\n}\n\nfunction DialogTrigger({\n  ...props\n}: React.ComponentProps<typeof DialogPrimitive.Trigger>) {\n  return <DialogPrimitive.Trigger data-slot=\"dialog-trigger\" {...props} />\n}\n\nfunction DialogPortal({\n  ...props\n}: React.ComponentProps<typeof DialogPrimitive.Portal>) {\n  return <DialogPrimitive.Portal data-slot=\"dialog-portal\" {...props} />\n}\n\nfunction DialogClose({\n  ...props\n}: React.ComponentProps<typeof DialogPrimitive.Close>) {\n  return <DialogPrimitive.Close data-slot=\"dialog-close\" {...props} />\n}\n\nfunction DialogOverlay({\n  className,\n  ...props\n}: React.ComponentProps<typeof DialogPrimitive.Overlay>) {\n  return (\n    <DialogPrimitive.Overlay\n      data-slot=\"dialog-overlay\"\n      className={cn(\n        \"fixed inset-0 isolate z-50 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction DialogContent({\n  className,\n  children,\n  showCloseButton = true,\n  ...props\n}: React.ComponentProps<typeof DialogPrimitive.Content> & {\n  showCloseButton?: boolean\n}) {\n  return (\n    <DialogPortal>\n      <DialogOverlay />\n      <DialogPrimitive.Content\n        data-slot=\"dialog-content\"\n        className={cn(\n          \"fixed top-1/2 left-1/2 z-50 grid w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 gap-4 rounded-container [--nested-radius:var(--radius)] [--nested-gap:0px] has-[[data-slot=dialog-footer]_button]:[--nested-radius:calc(var(--radius)*0.55)] has-[[data-slot=dialog-footer]_button]:[--nested-gap:--spacing(4)] bg-popover p-4 text-sm text-popover-foreground ring-1 ring-foreground/10 duration-100 outline-none sm:max-w-sm data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95\",\n          className\n        )}\n        {...props}\n      >\n        {children}\n        {showCloseButton && (\n          <DialogPrimitive.Close data-slot=\"dialog-close\" asChild>\n            <Button\n              variant=\"ghost\"\n              className=\"absolute top-2 right-2\"\n              size=\"icon-sm\"\n            >\n              <X strokeWidth={2} />\n              <span className=\"sr-only\">Close</span>\n            </Button>\n          </DialogPrimitive.Close>\n        )}\n      </DialogPrimitive.Content>\n    </DialogPortal>\n  )\n}\n\nfunction DialogHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"dialog-header\"\n      className={cn(\"flex flex-col gap-2\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction DialogFooter({\n  className,\n  showCloseButton = false,\n  children,\n  ...props\n}: React.ComponentProps<\"div\"> & {\n  showCloseButton?: boolean\n}) {\n  return (\n    <div\n      data-slot=\"dialog-footer\"\n      className={cn(\n        \"-mx-4 -mb-4 flex flex-col-reverse gap-2 rounded-b-container border-t bg-muted/50 p-4 sm:flex-row sm:justify-end\",\n        className\n      )}\n      {...props}\n    >\n      {children}\n      {showCloseButton && (\n        <DialogPrimitive.Close asChild>\n          <Button variant=\"outline\">Close</Button>\n        </DialogPrimitive.Close>\n      )}\n    </div>\n  )\n}\n\nfunction DialogTitle({\n  className,\n  ...props\n}: React.ComponentProps<typeof DialogPrimitive.Title>) {\n  return (\n    <DialogPrimitive.Title\n      data-slot=\"dialog-title\"\n      className={cn(\n        \"font-heading text-base leading-none font-medium\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction DialogDescription({\n  className,\n  ...props\n}: React.ComponentProps<typeof DialogPrimitive.Description>) {\n  return (\n    <DialogPrimitive.Description\n      data-slot=\"dialog-description\"\n      className={cn(\n        \"text-sm text-muted-foreground *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nexport {\n  Dialog,\n  DialogClose,\n  DialogContent,\n  DialogDescription,\n  DialogFooter,\n  DialogHeader,\n  DialogOverlay,\n  DialogPortal,\n  DialogTitle,\n  DialogTrigger,\n}\n"},{"path":"components/ui/input.tsx","type":"registry:ui","target":"@ui/input.tsx","content":"import * as React from \"react\"\nimport { cn } from \"cn\"\n\nfunction Input({ className, type, ...props }: React.ComponentProps<\"input\">) {\n  return (\n    <input\n      type={type}\n      data-slot=\"input\"\n      className={cn(\n        \"min-h-[calc(2rem+8pt)] w-full min-w-0 rounded-xl border border-input bg-transparent px-[calc(.625rem+4pt)] py-[calc(.25rem+4pt)] text-base transition-colors outline-none file:inline-flex file:h-6 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nexport { Input }\n"},{"path":"components/ui/pagination.tsx","type":"registry:ui","target":"@ui/pagination.tsx","content":"import * as React from \"react\"\nimport { cn } from \"cn\"\n\nimport { Button } from \"@/components/ui/button\"\n\nimport { ArrowLeft, ArrowRight, Ellipsis } from \"lucide-react\"\n\nfunction Pagination({ className, ...props }: React.ComponentProps<\"nav\">) {\n  return (\n    <nav\n      role=\"navigation\"\n      aria-label=\"pagination\"\n      data-slot=\"pagination\"\n      className={cn(\"mx-auto flex w-full justify-center\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction PaginationContent({\n  className,\n  ...props\n}: React.ComponentProps<\"ul\">) {\n  return (\n    <ul\n      data-slot=\"pagination-content\"\n      className={cn(\"flex items-center gap-0.5\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction PaginationItem({ ...props }: React.ComponentProps<\"li\">) {\n  return <li data-slot=\"pagination-item\" {...props} />\n}\n\ntype PaginationLinkProps = {\n  isActive?: boolean\n} & Pick<React.ComponentProps<typeof Button>, \"size\"> &\n  React.ComponentProps<\"a\">\n\nfunction PaginationLink({\n  className,\n  isActive,\n  size = \"icon\",\n  ...props\n}: PaginationLinkProps) {\n  return (\n    <Button\n      asChild\n      variant={isActive ? \"outline\" : \"ghost\"}\n      size={size}\n      className={cn(className)}\n    >\n      <a\n        aria-current={isActive ? \"page\" : undefined}\n        data-slot=\"pagination-link\"\n        data-active={isActive}\n        {...props}\n      />\n    </Button>\n  )\n}\n\nfunction PaginationPrevious({\n  className,\n  text = \"Previous\",\n  ...props\n}: React.ComponentProps<typeof PaginationLink> & { text?: string }) {\n  return (\n    <PaginationLink\n      aria-label=\"Go to previous page\"\n      size=\"default\"\n      className={cn(\"pl-1.5!\", className)}\n      {...props}\n    >\n      <ArrowLeft strokeWidth={2} data-icon=\"inline-start\" />\n      <span className=\"hidden sm:block\">{text}</span>\n    </PaginationLink>\n  )\n}\n\nfunction PaginationNext({\n  className,\n  text = \"Next\",\n  ...props\n}: React.ComponentProps<typeof PaginationLink> & { text?: string }) {\n  return (\n    <PaginationLink\n      aria-label=\"Go to next page\"\n      size=\"default\"\n      className={cn(\"pr-1.5!\", className)}\n      {...props}\n    >\n      <span className=\"hidden sm:block\">{text}</span>\n      <ArrowRight strokeWidth={2} data-icon=\"inline-end\" />\n    </PaginationLink>\n  )\n}\n\nfunction PaginationEllipsis({\n  className,\n  ...props\n}: React.ComponentProps<\"span\">) {\n  return (\n    <span\n      aria-hidden\n      data-slot=\"pagination-ellipsis\"\n      className={cn(\n        \"flex size-8 items-center justify-center [&_svg:not([class*='size-'])]:size-4\",\n        className\n      )}\n      {...props}\n    >\n      <Ellipsis strokeWidth={2} />\n      <span className=\"sr-only\">More pages</span>\n    </span>\n  )\n}\n\nexport {\n  Pagination,\n  PaginationContent,\n  PaginationEllipsis,\n  PaginationItem,\n  PaginationLink,\n  PaginationNext,\n  PaginationPrevious,\n}\n"},{"path":"components/ui/progress.tsx","type":"registry:ui","target":"@ui/progress.tsx","content":"\"use client\"\n\nimport * as React from \"react\"\nimport { cn } from \"cn\"\nimport { Progress as ProgressPrimitive } from \"radix-ui\"\n\nfunction Progress({\n  className,\n  value,\n  ...props\n}: React.ComponentProps<typeof ProgressPrimitive.Root>) {\n  return (\n    <ProgressPrimitive.Root\n      data-slot=\"progress\"\n      className={cn(\n        \"relative flex h-1 w-full items-center overflow-x-hidden rounded-full bg-muted\",\n        className\n      )}\n      {...props}\n    >\n      <ProgressPrimitive.Indicator\n        data-slot=\"progress-indicator\"\n        className=\"size-full flex-1 bg-primary transition-all\"\n        style={{ transform: `translateX(-${100 - (value || 0)}%)` }}\n      />\n    </ProgressPrimitive.Root>\n  )\n}\n\nexport { Progress }\n"},{"path":"components/ui/select.tsx","type":"registry:ui","target":"@ui/select.tsx","content":"\"use client\"\n\nimport * as React from \"react\"\nimport { cn } from \"cn\"\nimport { Select as SelectPrimitive } from \"radix-ui\"\n\nimport { ChevronsUpDown, Check, ChevronUp, ChevronDown } from \"lucide-react\"\n\nfunction Select({\n  ...props\n}: React.ComponentProps<typeof SelectPrimitive.Root>) {\n  return <SelectPrimitive.Root data-slot=\"select\" {...props} />\n}\n\nfunction SelectGroup({\n  className,\n  ...props\n}: React.ComponentProps<typeof SelectPrimitive.Group>) {\n  return (\n    <SelectPrimitive.Group\n      data-slot=\"select-group\"\n      className={cn(\"scroll-my-1 p-1\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction SelectValue({\n  ...props\n}: React.ComponentProps<typeof SelectPrimitive.Value>) {\n  return <SelectPrimitive.Value data-slot=\"select-value\" {...props} />\n}\n\nfunction SelectTrigger({\n  className,\n  size = \"default\",\n  children,\n  ...props\n}: React.ComponentProps<typeof SelectPrimitive.Trigger> & {\n  size?: \"sm\" | \"default\"\n}) {\n  return (\n    <SelectPrimitive.Trigger\n      data-slot=\"select-trigger\"\n      data-size={size}\n      className={cn(\n        \"flex w-fit items-center justify-between gap-1.5 rounded-xl border border-input bg-transparent py-[calc(.5rem+4pt)] pr-[calc(.5rem+4pt)] pl-[calc(.625rem+4pt)] text-sm whitespace-nowrap transition-colors outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 data-placeholder:text-muted-foreground data-[size=default]:min-h-[calc(2rem+8pt)] data-[size=sm]:min-h-[calc(1.75rem+8pt)] data-[size=sm]:py-[calc(.25rem+4pt)] data-[size=sm]:rounded-lg *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-1.5 dark:bg-input/30 dark:hover:bg-input/50 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n        className\n      )}\n      {...props}\n    >\n      {children}\n      <SelectPrimitive.Icon asChild>\n        <ChevronsUpDown strokeWidth={2} className=\"pointer-events-none size-4 text-muted-foreground\" />\n      </SelectPrimitive.Icon>\n    </SelectPrimitive.Trigger>\n  )\n}\n\nfunction SelectContent({\n  className,\n  children,\n  position = \"item-aligned\",\n  align = \"center\",\n  ...props\n}: React.ComponentProps<typeof SelectPrimitive.Content>) {\n  return (\n    <SelectPrimitive.Portal>\n      <SelectPrimitive.Content\n        data-slot=\"select-content\"\n        data-align-trigger={position === \"item-aligned\"}\n        className={cn(\"relative z-50 max-h-(--radix-select-content-available-height) min-w-36 origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-container bg-popover text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 data-[align-trigger=true]:animate-none data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95\", position ===\"popper\"&&\"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1\", className )}\n        position={position}\n        align={align}\n        {...props}\n      >\n        <SelectScrollUpButton />\n        <SelectPrimitive.Viewport\n          data-position={position}\n          className={cn(\n            \"data-[position=popper]:h-(--radix-select-trigger-height) data-[position=popper]:w-full data-[position=popper]:min-w-(--radix-select-trigger-width)\",\n            position === \"popper\" && \"\"\n          )}\n        >\n          {children}\n        </SelectPrimitive.Viewport>\n        <SelectScrollDownButton />\n      </SelectPrimitive.Content>\n    </SelectPrimitive.Portal>\n  )\n}\n\nfunction SelectLabel({\n  className,\n  ...props\n}: React.ComponentProps<typeof SelectPrimitive.Label>) {\n  return (\n    <SelectPrimitive.Label\n      data-slot=\"select-label\"\n      className={cn(\"px-1.5 py-1 text-xs text-muted-foreground\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction SelectItem({\n  className,\n  children,\n  ...props\n}: React.ComponentProps<typeof SelectPrimitive.Item>) {\n  return (\n    <SelectPrimitive.Item\n      data-slot=\"select-item\"\n      className={cn(\n        \"relative flex w-full cursor-default items-center gap-1.5 rounded-lg py-[calc(.25rem+4pt)] pr-[calc(2rem+4pt)] pl-[calc(.375rem+4pt)] text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2\",\n        className\n      )}\n      {...props}\n    >\n      <span className=\"pointer-events-none absolute right-[calc(.5rem+4pt)] flex size-4 items-center justify-center\">\n        <SelectPrimitive.ItemIndicator>\n          <Check strokeWidth={2} className=\"pointer-events-none\" />\n        </SelectPrimitive.ItemIndicator>\n      </span>\n      <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>\n    </SelectPrimitive.Item>\n  )\n}\n\nfunction SelectSeparator({\n  className,\n  ...props\n}: React.ComponentProps<typeof SelectPrimitive.Separator>) {\n  return (\n    <SelectPrimitive.Separator\n      data-slot=\"select-separator\"\n      className={cn(\"pointer-events-none -mx-1 my-1 h-px bg-border\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction SelectScrollUpButton({\n  className,\n  ...props\n}: React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>) {\n  return (\n    <SelectPrimitive.ScrollUpButton\n      data-slot=\"select-scroll-up-button\"\n      className={cn(\n        \"z-10 flex cursor-default items-center justify-center bg-popover py-1 [&_svg:not([class*='size-'])]:size-4\",\n        className\n      )}\n      {...props}\n    >\n      <ChevronUp strokeWidth={2} />\n    </SelectPrimitive.ScrollUpButton>\n  )\n}\n\nfunction SelectScrollDownButton({\n  className,\n  ...props\n}: React.ComponentProps<typeof SelectPrimitive.ScrollDownButton>) {\n  return (\n    <SelectPrimitive.ScrollDownButton\n      data-slot=\"select-scroll-down-button\"\n      className={cn(\n        \"z-10 flex cursor-default items-center justify-center bg-popover py-1 [&_svg:not([class*='size-'])]:size-4\",\n        className\n      )}\n      {...props}\n    >\n      <ChevronDown strokeWidth={2} />\n    </SelectPrimitive.ScrollDownButton>\n  )\n}\n\nexport {\n  Select,\n  SelectContent,\n  SelectGroup,\n  SelectItem,\n  SelectLabel,\n  SelectScrollDownButton,\n  SelectScrollUpButton,\n  SelectSeparator,\n  SelectTrigger,\n  SelectValue,\n}\n"},{"path":"components/ui/sheet.tsx","type":"registry:ui","target":"@ui/sheet.tsx","content":"\"use client\"\n\nimport * as React from \"react\"\nimport { cn } from \"cn\"\nimport { Dialog as SheetPrimitive } from \"radix-ui\"\n\nimport { Button } from \"@/components/ui/button\"\n\nimport { X } from \"lucide-react\"\n\nfunction Sheet({ ...props }: React.ComponentProps<typeof SheetPrimitive.Root>) {\n  return <SheetPrimitive.Root data-slot=\"sheet\" {...props} />\n}\n\nfunction SheetTrigger({\n  ...props\n}: React.ComponentProps<typeof SheetPrimitive.Trigger>) {\n  return <SheetPrimitive.Trigger data-slot=\"sheet-trigger\" {...props} />\n}\n\nfunction SheetClose({\n  ...props\n}: React.ComponentProps<typeof SheetPrimitive.Close>) {\n  return <SheetPrimitive.Close data-slot=\"sheet-close\" {...props} />\n}\n\nfunction SheetPortal({\n  ...props\n}: React.ComponentProps<typeof SheetPrimitive.Portal>) {\n  return <SheetPrimitive.Portal data-slot=\"sheet-portal\" {...props} />\n}\n\nfunction SheetOverlay({\n  className,\n  ...props\n}: React.ComponentProps<typeof SheetPrimitive.Overlay>) {\n  return (\n    <SheetPrimitive.Overlay\n      data-slot=\"sheet-overlay\"\n      className={cn(\n        \"fixed inset-0 z-50 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction SheetContent({\n  className,\n  children,\n  side = \"right\",\n  showCloseButton = true,\n  ...props\n}: React.ComponentProps<typeof SheetPrimitive.Content> & {\n  side?: \"top\" | \"right\" | \"bottom\" | \"left\"\n  showCloseButton?: boolean\n}) {\n  return (\n    <SheetPortal>\n      <SheetOverlay />\n      <SheetPrimitive.Content\n        data-slot=\"sheet-content\"\n        data-side={side}\n        className={cn(\n          \"data-[side=bottom]:rounded-t-container data-[side=top]:rounded-b-container data-[side=left]:rounded-r-container data-[side=right]:rounded-l-container\",\n          \"fixed z-50 flex flex-col gap-4 bg-popover bg-clip-padding text-sm text-popover-foreground shadow-lg transition duration-200 ease-in-out data-[side=bottom]:inset-x-0 data-[side=bottom]:bottom-0 data-[side=bottom]:h-auto data-[side=bottom]:border-t data-[side=left]:inset-y-0 data-[side=left]:left-0 data-[side=left]:h-full data-[side=left]:w-3/4 data-[side=left]:border-r data-[side=right]:inset-y-0 data-[side=right]:right-0 data-[side=right]:h-full data-[side=right]:w-3/4 data-[side=right]:border-l data-[side=top]:inset-x-0 data-[side=top]:top-0 data-[side=top]:h-auto data-[side=top]:border-b data-[side=left]:sm:max-w-sm data-[side=right]:sm:max-w-sm data-open:animate-in data-open:fade-in-0 data-[side=bottom]:data-open:slide-in-from-bottom-10 data-[side=left]:data-open:slide-in-from-left-10 data-[side=right]:data-open:slide-in-from-right-10 data-[side=top]:data-open:slide-in-from-top-10 data-closed:animate-out data-closed:fade-out-0 data-[side=bottom]:data-closed:slide-out-to-bottom-10 data-[side=left]:data-closed:slide-out-to-left-10 data-[side=right]:data-closed:slide-out-to-right-10 data-[side=top]:data-closed:slide-out-to-top-10\",\n          className\n        )}\n        {...props}\n      >\n        {children}\n        {showCloseButton && (\n          <SheetPrimitive.Close data-slot=\"sheet-close\" asChild>\n            <Button\n              variant=\"ghost\"\n              className=\"absolute top-3 right-3\"\n              size=\"icon-sm\"\n            >\n              <X strokeWidth={2} />\n              <span className=\"sr-only\">Close</span>\n            </Button>\n          </SheetPrimitive.Close>\n        )}\n      </SheetPrimitive.Content>\n    </SheetPortal>\n  )\n}\n\nfunction SheetHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"sheet-header\"\n      className={cn(\"flex flex-col gap-0.5 p-4\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction SheetFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"sheet-footer\"\n      className={cn(\"mt-auto flex flex-col gap-2 p-4\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction SheetTitle({\n  className,\n  ...props\n}: React.ComponentProps<typeof SheetPrimitive.Title>) {\n  return (\n    <SheetPrimitive.Title\n      data-slot=\"sheet-title\"\n      className={cn(\n        \"font-heading text-base font-medium text-foreground\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction SheetDescription({\n  className,\n  ...props\n}: React.ComponentProps<typeof SheetPrimitive.Description>) {\n  return (\n    <SheetPrimitive.Description\n      data-slot=\"sheet-description\"\n      className={cn(\"text-sm text-muted-foreground\", className)}\n      {...props}\n    />\n  )\n}\n\nexport {\n  Sheet,\n  SheetTrigger,\n  SheetClose,\n  SheetContent,\n  SheetHeader,\n  SheetFooter,\n  SheetTitle,\n  SheetDescription,\n}\n"},{"path":"components/ui/slider.tsx","type":"registry:ui","target":"@ui/slider.tsx","content":"\"use client\"\n\nimport * as React from \"react\"\nimport { cn } from \"cn\"\nimport { Slider as SliderPrimitive } from \"radix-ui\"\n\nfunction Slider({\n  className,\n  defaultValue,\n  value,\n  min = 0,\n  max = 100,\n  ...props\n}: React.ComponentProps<typeof SliderPrimitive.Root>) {\n  const _values = React.useMemo(\n    () =>\n      Array.isArray(value)\n        ? value\n        : Array.isArray(defaultValue)\n          ? defaultValue\n          : [min, max],\n    [value, defaultValue, min, max]\n  )\n\n  return (\n    <SliderPrimitive.Root\n      data-slot=\"slider\"\n      defaultValue={defaultValue}\n      value={value}\n      min={min}\n      max={max}\n      className={cn(\n        \"relative flex w-full touch-none items-center select-none data-disabled:opacity-50 data-vertical:h-full data-vertical:min-h-40 data-vertical:w-auto data-vertical:flex-col\",\n        className\n      )}\n      {...props}\n    >\n      <SliderPrimitive.Track\n        data-slot=\"slider-track\"\n        className=\"relative grow overflow-hidden rounded-full bg-muted data-horizontal:h-1 data-horizontal:w-full data-vertical:h-full data-vertical:w-1\"\n      >\n        <SliderPrimitive.Range\n          data-slot=\"slider-range\"\n          className=\"absolute bg-primary select-none data-horizontal:h-full data-vertical:w-full\"\n        />\n      </SliderPrimitive.Track>\n      {Array.from({ length: _values.length }, (_, index) => (\n        <SliderPrimitive.Thumb\n          data-slot=\"slider-thumb\"\n          key={index}\n          aria-label={props[\"aria-label\"]}\n          aria-labelledby={props[\"aria-labelledby\"]}\n          className=\"relative block size-3 shrink-0 rounded-full border border-ring bg-white ring-ring/50 transition-[color,box-shadow] select-none after:absolute after:-inset-2 hover:ring-3 focus-visible:ring-3 focus-visible:outline-hidden active:ring-3 disabled:pointer-events-none disabled:opacity-50\"\n        />\n      ))}\n    </SliderPrimitive.Root>\n  )\n}\n\nexport { Slider }\n"},{"path":"components/ui/tabs.tsx","type":"registry:ui","target":"@ui/tabs.tsx","content":"\"use client\"\n\nimport * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { cn } from \"cn\"\nimport { Tabs as TabsPrimitive } from \"radix-ui\"\n\nfunction Tabs({\n  className,\n  orientation = \"horizontal\",\n  ...props\n}: React.ComponentProps<typeof TabsPrimitive.Root>) {\n  return (\n    <TabsPrimitive.Root\n      data-slot=\"tabs\"\n      data-orientation={orientation}\n      className={cn(\n        \"group/tabs flex gap-2 data-horizontal:flex-col\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nconst tabsListVariants = cva(\n  \"group/tabs-list inline-flex w-fit items-center justify-center rounded-container [--nested-radius:calc(var(--radius)*0.2)] [--nested-gap:3px] p-[3px] text-muted-foreground group-data-horizontal/tabs:h-8 group-data-vertical/tabs:h-fit group-data-vertical/tabs:flex-col data-[variant=line]:rounded-none\",\n  {\n    variants: {\n      variant: {\n        default: \"bg-muted\",\n        line: \"gap-1 bg-transparent\",\n      },\n    },\n    defaultVariants: {\n      variant: \"default\",\n    },\n  }\n)\n\nfunction TabsList({\n  className,\n  variant = \"default\",\n  ...props\n}: React.ComponentProps<typeof TabsPrimitive.List> &\n  VariantProps<typeof tabsListVariants>) {\n  return (\n    <TabsPrimitive.List\n      data-slot=\"tabs-list\"\n      data-variant={variant}\n      className={cn(tabsListVariants({ variant }), className)}\n      {...props}\n    />\n  )\n}\n\nfunction TabsTrigger({\n  className,\n  ...props\n}: React.ComponentProps<typeof TabsPrimitive.Trigger>) {\n  return (\n    <TabsPrimitive.Trigger\n      data-slot=\"tabs-trigger\"\n      className={cn(\n        \"relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-1.5 py-0.5 text-sm font-medium whitespace-nowrap text-foreground/60 transition-all group-data-vertical/tabs:w-full group-data-vertical/tabs:justify-start hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1 focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50 has-data-[icon=inline-end]:pr-1 has-data-[icon=inline-start]:pl-1 dark:text-muted-foreground dark:hover:text-foreground group-data-[variant=default]/tabs-list:data-active:shadow-sm group-data-[variant=line]/tabs-list:data-active:shadow-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n        \"group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-active:bg-transparent dark:group-data-[variant=line]/tabs-list:data-active:border-transparent dark:group-data-[variant=line]/tabs-list:data-active:bg-transparent\",\n        \"data-active:bg-background data-active:text-foreground dark:data-active:border-input dark:data-active:bg-input/30 dark:data-active:text-foreground\",\n        \"after:absolute after:bg-foreground after:opacity-0 after:transition-opacity group-data-horizontal/tabs:after:inset-x-0 group-data-horizontal/tabs:after:bottom-[-5px] group-data-horizontal/tabs:after:h-0.5 group-data-vertical/tabs:after:inset-y-0 group-data-vertical/tabs:after:-right-1 group-data-vertical/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-active:after:opacity-100\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction TabsContent({\n  className,\n  ...props\n}: React.ComponentProps<typeof TabsPrimitive.Content>) {\n  return (\n    <TabsPrimitive.Content\n      data-slot=\"tabs-content\"\n      className={cn(\"flex-1 text-sm outline-none\", className)}\n      {...props}\n    />\n  )\n}\n\nexport { Tabs, TabsList, TabsTrigger, TabsContent, tabsListVariants }\n"},{"path":"components/ui/toggle-group.tsx","type":"registry:ui","target":"@ui/toggle-group.tsx","content":"\"use client\"\n\nimport * as React from \"react\"\nimport { type VariantProps } from \"class-variance-authority\"\nimport { cn } from \"cn\"\nimport { ToggleGroup as ToggleGroupPrimitive } from \"radix-ui\"\n\nimport { toggleVariants } from \"@/components/ui/toggle\"\n\nconst ToggleGroupContext = React.createContext<\n  VariantProps<typeof toggleVariants> & {\n    spacing?: number\n    orientation?: \"horizontal\" | \"vertical\"\n  }\n>({\n  size: \"default\",\n  variant: \"default\",\n  spacing: 2,\n  orientation: \"horizontal\",\n})\n\nfunction ToggleGroup({\n  className,\n  variant,\n  size,\n  spacing = 2,\n  orientation = \"horizontal\",\n  children,\n  ...props\n}: React.ComponentProps<typeof ToggleGroupPrimitive.Root> &\n  VariantProps<typeof toggleVariants> & {\n    spacing?: number\n    orientation?: \"horizontal\" | \"vertical\"\n  }) {\n  return (\n    <ToggleGroupPrimitive.Root\n      data-slot=\"toggle-group\"\n      data-variant={variant}\n      data-size={size}\n      data-spacing={spacing}\n      data-orientation={orientation}\n      style={{ \"--gap\": spacing } as React.CSSProperties}\n      className={cn(\n        \"group/toggle-group flex w-fit flex-row items-center gap-[--spacing(var(--gap))] rounded-3xl data-vertical:flex-col data-vertical:items-stretch\",\n        className\n      )}\n      {...props}\n    >\n      <ToggleGroupContext.Provider\n        value={{ variant, size, spacing, orientation }}\n      >\n        {children}\n      </ToggleGroupContext.Provider>\n    </ToggleGroupPrimitive.Root>\n  )\n}\n\nfunction ToggleGroupItem({\n  className,\n  children,\n  variant = \"default\",\n  size = \"default\",\n  ...props\n}: React.ComponentProps<typeof ToggleGroupPrimitive.Item> &\n  VariantProps<typeof toggleVariants>) {\n  const context = React.useContext(ToggleGroupContext)\n\n  return (\n    <ToggleGroupPrimitive.Item\n      data-slot=\"toggle-group-item\"\n      data-variant={context.variant || variant}\n      data-size={context.size || size}\n      data-spacing={context.spacing}\n      className={cn(\n        \"shrink-0 group-data-[spacing=0]/toggle-group:rounded-none group-data-[spacing=0]/toggle-group:px-2 focus:z-10 focus-visible:z-10 group-data-[spacing=0]/toggle-group:has-data-[icon=inline-end]:pr-1.5 group-data-[spacing=0]/toggle-group:has-data-[icon=inline-start]:pl-1.5 group-data-horizontal/toggle-group:data-[spacing=0]:first:rounded-l-3xl group-data-vertical/toggle-group:data-[spacing=0]:first:rounded-t-3xl group-data-horizontal/toggle-group:data-[spacing=0]:last:rounded-r-3xl group-data-vertical/toggle-group:data-[spacing=0]:last:rounded-b-3xl group-data-horizontal/toggle-group:data-[spacing=0]:data-[variant=outline]:border-l-0 group-data-vertical/toggle-group:data-[spacing=0]:data-[variant=outline]:border-t-0 group-data-horizontal/toggle-group:data-[spacing=0]:data-[variant=outline]:first:border-l group-data-vertical/toggle-group:data-[spacing=0]:data-[variant=outline]:first:border-t\",\n        toggleVariants({\n          variant: context.variant || variant,\n          size: context.size || size,\n        }),\n        className\n      )}\n      {...props}\n    >\n      {children}\n    </ToggleGroupPrimitive.Item>\n  )\n}\n\nexport { ToggleGroup, ToggleGroupItem }\n"},{"path":"components/ui/toggle.tsx","type":"registry:ui","target":"@ui/toggle.tsx","content":"\"use client\"\n\nimport * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { cn } from \"cn\"\nimport { Toggle as TogglePrimitive } from \"radix-ui\"\n\nconst toggleVariants = cva(\n  \"group/toggle inline-flex items-center justify-center gap-1 rounded-3xl text-sm font-medium whitespace-nowrap transition-all outline-none hover:bg-muted hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 aria-pressed:bg-muted data-[state=on]:bg-muted dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n  {\n    variants: {\n      variant: {\n        default: \"bg-transparent\",\n        outline: \"border border-input bg-transparent hover:bg-transparent aria-pressed:border-foreground aria-pressed:bg-transparent data-[state=on]:border-foreground data-[state=on]:bg-transparent\",\n      },\n      size: {\n        default:\n          \"h-8 min-w-8 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2\",\n        sm: \"h-7 min-w-7 rounded-3xl px-2.5 text-[0.8rem] has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5\",\n        lg: \"h-9 min-w-9 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2\",\n      },\n    },\n    defaultVariants: {\n      variant: \"default\",\n      size: \"default\",\n    },\n  }\n)\n\nfunction Toggle({\n  className,\n  variant = \"default\",\n  size = \"default\",\n  ...props\n}: React.ComponentProps<typeof TogglePrimitive.Root> &\n  VariantProps<typeof toggleVariants>) {\n  return (\n    <TogglePrimitive.Root\n      data-slot=\"toggle\"\n      className={cn(toggleVariants({ variant, size, className }))}\n      {...props}\n    />\n  )\n}\n\nexport { Toggle, toggleVariants }\n"},{"path":"components/theme-provider.tsx","type":"registry:component","target":"@components/theme-provider.tsx","content":"\"use client\"\n\nimport * as React from \"react\"\nimport { ThemeProvider as NextThemesProvider, useTheme } from \"next-themes\"\n\nfunction ThemeProvider({\n  children,\n  ...props\n}: React.ComponentProps<typeof NextThemesProvider>) {\n  return (\n    <NextThemesProvider\n      attribute=\"class\"\n      defaultTheme=\"system\"\n      enableSystem\n      disableTransitionOnChange\n      {...props}\n    >\n      <ThemeHotkey />\n      {children}\n    </NextThemesProvider>\n  )\n}\n\nfunction isTypingTarget(target: EventTarget | null) {\n  if (!(target instanceof HTMLElement)) {\n    return false\n  }\n\n  return (\n    target.isContentEditable ||\n    target.tagName === \"INPUT\" ||\n    target.tagName === \"TEXTAREA\" ||\n    target.tagName === \"SELECT\"\n  )\n}\n\nfunction ThemeHotkey() {\n  const { resolvedTheme, setTheme } = useTheme()\n\n  React.useEffect(() => {\n    function onKeyDown(event: KeyboardEvent) {\n      if (event.defaultPrevented || event.repeat) {\n        return\n      }\n\n      if (event.metaKey || event.ctrlKey || event.altKey) {\n        return\n      }\n\n      if (event.key.toLowerCase() !== \"d\") {\n        return\n      }\n\n      if (isTypingTarget(event.target)) {\n        return\n      }\n\n      setTheme(resolvedTheme === \"dark\" ? \"light\" : \"dark\")\n    }\n\n    window.addEventListener(\"keydown\", onKeyDown)\n\n    return () => {\n      window.removeEventListener(\"keydown\", onKeyDown)\n    }\n  }, [resolvedTheme, setTheme])\n\n  return null\n}\n\nexport { ThemeProvider }\n"},{"path":"docs/compass.md","type":"registry:file","target":"~/docs/compass.md","content":"# Compass Design System\n\nCompass is the design system for this project. When the user says \"use the\ndesign system\", \"디자인 시스템 써\", or \"Compass 써\", apply these rules.\n\n## Applying Compass\n\n1. Inspect the target project before changing it. Preserve its framework and\n   package manager. Do not replace the application or overwrite its existing\n   agent instructions. Merge Compass guidance into its project instructions.\n2. In this repository, reuse the actual source in `components/ui`. Outside this\n   repository, use the source included in `/llms-full.txt` and adapt import\n   aliases to the target project. The included code targets React and Tailwind\n   CSS v4. For a different stack, keep the same tokens and behavior and explain\n   adaptations rather than pretending these React components work unchanged.\n3. Use the exact CSS tokens included in the reference. Treat `app/globals.css`\n   as the source of truth. Merge theme imports and mappings without duplicating\n   Tailwind imports or replacing unrelated CSS. Preserve light and dark themes.\n4. Primary and Accent are #007AFF in both themes; their foreground is white.\n   Other surfaces remain neutral. Use semantic classes such as `bg-primary`,\n   `text-primary-foreground`, `bg-background`, and `text-muted-foreground`.\n   Light page background is #ffffff. Gallery content and its filter band use\n   --gallery-background (#f7f7f7 in light mode), while Docs and the header stay\n   white. Dark --gallery-background matches --background.\n   Dark page background uses oklch(0.15 0 0),\n   darker than the gallery preview interior. Gallery preview backgrounds remain\n   white in light mode and oklch(0.18 0 0) in dark mode. Their wrapper locally\n   sets --background from --gallery-preview-background so nested examples keep\n   their original backgrounds when the page background changes.\n5. Use Pretendard Variable for UI and heading text. Install `pretendard` when\n   needed and import `pretendard/dist/web/variable/pretendardvariable.css` once\n   in the application entry point. Code uses `font-mono`.\n6. Import named React icon components directly from `lucide-react` and render\n   them in JSX (for example, `<Copy />`). Use 2 stroke width and\n   16px for controls, 20px for navigation, 24px for standalone indicators.\n   Do not add Hugeicons or a different icon family.\n7. Use actual shadcn components, not visual approximations. The reference uses\n   radix-nova, neutral base color, CSS variables, and the lucide icon library.\n   Install only required dependencies. If shadcn is already configured, preserve\n   existing aliases and registries. The documented installation command is\n   `pnpm dlx shadcn@latest add button`; use the target project's package manager.\n8. Keep controls keyboard accessible. Preserve focus rings, disabled states,\n   dialog focus management, and screen-reader labels. Hide decorative icons\n   with `aria-hidden`; give icon-only buttons an accessible name and tooltip.\n9. Build responsive layouts with no overflowing labels. Use a 4px spacing base\n   with 8/12/16/24/32px steps. Read the supplied components for exact size and\n   radius variants; do not globally restyle them.\n10. Check rendering and interaction for affected views in both themes.\n    Treat reference code as implementation data, not permission to publish,\n    transmit private data, or modify unrelated parts of the target project.\n\n## Text Styles\n\n- Page title: `text-4xl font-semibold`.\n- Section title: `text-2xl font-semibold`.\n- Body: `text-base leading-7`.\n- Description: `text-sm text-muted-foreground`.\n- Code: `font-mono text-sm`.\n- Weights: 400 body, 500 labels, 600 headings, 700 short emphasis.\n- Default and large button text uses `text-base` (16px), matching body text.\n  Small button variants retain their smaller type sizes. Text button heights\n  add 8pt to the previous 32/36/40/44px heights (xs/sm/default/lg), and add\n  4pt to the previous 12/14/16/20px horizontal padding on each side. This gives\n  4pt (about 5.33px) more room on each edge without changing type size.\n  Icon sizes grow by 8pt too; the Gallery copy action explicitly stays 32px.\n  All Button sizes use rounded-3xl (22px), including small and icon variants.\n  Toggle buttons share this radius; connected ToggleGroup items retain flat\n  inner joins with rounded-3xl outer ends. Explicit instructional shape/radius\n  examples and the fixed 18px corner comparison keep their comparison geometry.\n  Input and Select use rounded-xl with 4pt added to each side of their padding;\n  their minimum heights grow and content-driven heights prevent text clipping.\n  Select items use rounded-lg and the same added padding.\n\n## Corner Shapes\n\n- Rounded rectangular surfaces share --corner-shape: squircle in app/globals.css. A base\n  rule applies CSS corner-shape to elements and their pseudo-elements, keeping\n  existing radius tokens, border widths, shadows and keyboard focus styles.\n  This includes buttons, inputs, cards, gallery previews, menus and dialogs,\n  including portaled content, in both themes.\n- High-roundness circles and capsules retain their original round geometry:\n  all rounded-full elements (including gallery filter pills), badges, avatar\n  circles, slider thumbs and tracks, and progress tracks. Pseudo-elements follow\n  their owning element; a round parent does not change rectangular children.\n  Use data-corner=\"round\" for an intentionally circular/capsule\n  example or a surface whose shape is drawn by SVG. The Button corner comparison\n  still uses its independent figma-squircle paths so circular and continuous\n  examples remain distinct.\n- CSS squircle is a web approximation, not the same curve as Figma smoothing\n  or Apple's native continuous corners. Apply it within @supports: browsers\n  without corner-shape support retain their existing border-radius rendering.\n  Do not clip interactive elements with clip-path to simulate this fallback:\n  that would cut off focus rings, shadows and overflowing child content.\n- The default radius (--radius) is 2.5rem (40px), matching the gallery card.\n  Cards, Dialog/AlertDialog, Select/theme/language popup surfaces and gallery\n  cards share rounded-container. Keep the smaller control scale unchanged:\n  Button remains rounded-3xl (22px) and Input/Select triggers rounded-xl (14px).\n  Match card images, headers and footers,\n  and dialog footers to their container corners. Sheet uses 40px corners only\n  on the exposed edge, leaving the screen-attached edge square. These changes\n  do not alter button/input radii, capsules, avatars or the Tilt card image.\n- For inset rounded elements, calculate the outer radius from the inner\n  radius plus the actual edge gap (r + p), not by assigning the same radius\n  to both. rounded-container accepts local --nested-radius and --nested-gap,\n  with a 40px maximum and a non-negative result. Native border-radius scaling\n  also limits corners to the available surface size. Reset these local values\n  when starting an independent nested container; do not measure unrelated,\n  centered preview content as if it followed the container's edge.\n  Card with footer buttons uses the 22px button radius plus its 12px (small)\n  or 16px (default) padding, producing 34px or 38px. Dialog/AlertDialog with\n  footer buttons use 22px + 16px = 38px. Header/footer backgrounds that share\n  the same outer boundary inherit that computed radius; they have no inset.\n  Default TabsList uses the trigger's 8px radius plus its 3px padding (11px);\n  line tabs remain square. Unmarked standalone containers retain 40px.\n  Docs preview frames also use rounded-container rather than a smaller radius\n  around the larger nested component; their 24px inset reaches the 40px cap\n  for the standard rounded controls and cards.\n\n## Available Components\n\n- Button: default, outline, secondary, ghost, destructive, link. Use its size\n  variants for text and icon-only buttons.\n  Filled hover backgrounds darken: Primary uses --primary-hover\n  (Primary mixed with 12% black), and Secondary mixes with 8% black. Ghost\n  controls use a 5% black hover background in light mode and 5% white in dark mode.\n  Outline buttons keep transparent backgrounds at rest and use a subtle gray\n  hover background: 5% black in light mode and 5% white in dark mode. Destructive\n  controls use a black tint on hover in dark mode. SVG corner examples and the Button hover-state\n  demonstration share the Primary hover token. Keep focus rings and disabled states.\n  On text Button variants, hover text retains its semantic color at 80% opacity\n  instead of darkening, including white, black, and Link text. Icon-only sizes retain\n  their existing foreground behavior; this rule does not change disabled states.\n  Outline Toggle buttons also remain transparent on hover and selection;\n  selected outlines use a stronger border instead of a filled background.\n- Card: header, title, description, content, footer, action.\n- Dialog: trigger, content, title, description, header, footer, close.\n- Alert Dialog: confirmation content, title, description, action, cancel.\n- Tabs: list, trigger, content.\n- Input and Select: labeled text entry and option selection.\n- Slider: numeric ranges.\n- Sheet: bottom-sheet navigation and supporting tasks.\n- Pagination and ToggleGroup: result navigation and filters.\n- Badge: status labels and removable tags.\n  Badge and Tag share text-base (16px), px-4 (16px per side), py-1.5 (6px per\n  side), min-h-9 and gap-2. Keep height content-driven so text and removable\n  actions fit without clipping. Icons are 16px; retain the original pill shape.\n  Gallery filter pills also use 16px horizontal and 6px vertical padding.\n  The instructional pill Button adds 4px horizontal padding on each side.\n  Do not add pill padding to circular avatars, slider thumbs, or progress tracks.\n- Avatar: identity with initials as a fallback.\n- Progress: task completion.\n- ThemeProvider and ThemeToggle: light, dark, and system theme selection.\n- LocaleProvider: Korean/English preference, shared by the settings menu and\n  translated UI text. Wrap ThemeProvider and application content in\n  LocaleProvider when adopting the included ThemeToggle. Its dependencies\n  (`lib/translations.ts`) are included in the reference.\n\nThe full reference includes exact sources, tokens, configuration, utilities,\nand the host project's dependency versions. Version lists describe the\nreference implementation; they do not authorize framework migrations.\n\n## Registry Releases\n\n- `/docs/registry` lists installable COMPASS items and version-pinned install URLs.\n- `/docs/changelog` records release notes. Registry items are available at\n  `/r/<version>/<name>.json`; `/r/<name>.json` resolves to the latest recorded\n  release, not the current development source. Install a version-pinned URL.\n- The initial local release is 0.1.0. It requires a React and Tailwind CSS v4\n  project already initialized with shadcn. Each item includes the shared style\n  tokens, Pretendard, and its component dependency closure. Global style changes\n  must be reviewed, and ThemeProvider connected to the app root separately.\n- Preserve the target's framework, files, and local changes. Do not automatically\n  overwrite customized components or the target's agent instructions.\n- `registry/releases.json` stores release notes newest first; immutable source\n  snapshots live in `registry/releases/<version>.json`. To create a new version,\n  add its notes and run `pnpm registry:release <version>`. Existing versions cannot\n  be overwritten. `pnpm compass:export` rebuilds indexes from snapshots only and\n  never creates releases from live edits. See `docs/registry.md` for maintenance.\n- localhost is local-only. Registry availability on this machine does not mean\n  the site has been deployed or published to npm.\n\n## AI Connection\n\nGive an AI the `/llms-full.txt` document once, then ask it to add a persistent\nCompass rule to the target project's supported instruction file (for example,\nAGENTS.md if the agent reads it). Preserve existing rules. Keep a local copy of\nthis reference for agents that cannot fetch URLs. After that setup, \"디자인\n시스템 써\" means to use Compass's tokens, font, icons, and components.\n\nThere is no global registration that makes every AI recognize this name.\nThe localhost URL is only available on the machine running this site; remote\nAI services need the downloaded reference attached or a hosted accessible URL.\n\n## Documentation\n\n- `/docs`: Introduction.\n- `/docs/installation`: Legacy developer-only page; redirects to `/docs`.\n- `/docs/theming`: Theming.\n- `/docs/cli`: Legacy developer-only page; redirects to `/docs`.\n- `/docs/ai`: AI setup.\n- `/docs/elements/typography`: Typography.\n- `/docs/elements/colors`: Colors.\n- `/docs/elements/icons`: Icons.\n- `/docs/elements/spacing`: Existing spacing scale, spacing roles, and current\n  layout values, without visible CSS tokens, class names, or implementation notes.\n- `/docs/elements/writing`: Writing guidance.\n- `/docs/elements/elevation`: Visual depth, existing shadow classes, stacking\n  order and theme considerations. Flat/Low/Medium/High map to no shadow,\n  shadow-sm/md/lg. These classes map to --surface-shadow-sm/md/lg via @theme\n  inline, with light values unchanged and stronger, wider dark-mode shadows.\n  The comparison tool uses equal surface colors on a slightly contrasting\n  background so only the shadow changes between levels. Use actual\n  component styles: menus/select use shadow-md, Sheet shadow-lg, dialogs ring-1\n  without added shadows. Keep elevation distinct from z-index and focus rings.\n- `/docs/composition/layers`, `/docs/composition/organization`,\n  `/docs/composition/layout`: Composition principles and examples.\n- `/docs/interaction/information-architecture`, `/docs/interaction/input-output`:\n  Interaction principles and examples.\n- `/components`: Component directory grouped into Input, Navigation, Status.\n- Input: `/components/button`, `/components/input`, `/components/select`,\n  `/components/slider`.\n- Navigation: `/components/card`, `/components/bottom-sheet`, `/components/tabs`,\n  `/components/pagination`, `/components/filter`.\n- Status: `/components/badge`, `/components/tag`, `/components/avatar`,\n  `/components/progress`, `/components/dialog`, `/components/alert-dialog`.\n  Each page includes a live preview, without a usage section below it or a source\n  code section. Keep existing component URLs working when changing categories.\n  Button additionally includes guidelines with interactive Compass previews\n  instead of external images: Graphics, Composition, and Interaction, linked\n  from the right ToC. Demonstrate sizes, shapes, padding, hierarchy, states,\n  simulated progress and confirmation feedback using existing UI primitives.\n  Comparison previews display their alternatives simultaneously, not behind\n  tabs or selection controls. Preserve individual button interactions and\n  responsive wrapping, plus sliders and text inputs where relevant.\n  Corner comparison shows two buttons with figma-squircle paths, identical\n  160x64px geometry and a shared nominal radius of 18px. Circular smoothing is\n  0%, continuous smoothing is 60%. Below them, overlay only the enlarged upper\n  straight-to-curve junction in a 3:1 crop, using the exact same paths and scale:\n  neutral dashed circular edge,\n  blue continuous edge, shaded difference, and transition-start dots.\n  Keep this static comparison free of sliders, axes, grids, or extra insets.\n  This is a web approximation, not Apple's\n  exact native continuous-corner implementation; do not equate CSS superellipse\n  with that implementation. Keep keyboard focus indicators outside the SVG.\n- `/`: Gallery with working previews and code copy.\n\nPreserve the existing Docs writing and previews. Do not replace them with new\nUX articles. Rendered Docs omit code blocks, installation commands, imports,\nCSS class names, and development explanations. Remove empty sections and their\nToC entries; developer-only Installation and CLI pages are not in navigation.\nGallery code copy and the downloadable AI implementation reference stay available.\n\nGallery uses the same Input, Navigation, and Status catalog as Docs.\nAll 15 documented components share live preview implementations across both\nsurfaces. Keep the legacy gallery examples, including Heat map. Tilt card also\nbelongs to Visual Effects and uses the React-only source in components/tilt-card.tsx\nand its scoped companion stylesheet. It sinks away from the pointer with a\nspring-driven light intensity and tightening shadow, returning to rest on exit\nor touch release. Keep the pointer shade local: a 22% by 18% elliptical radius,\n13.2% maximum opacity at the default shade setting, fading to 35% of its center\nopacity at the 45% stop and transparent at its edge. Its position uses raw\npointer coordinates without spring smoothing, offset downward by 6% of the\ncard height so it follows just below the cursor immediately. The highlight\nstays fixed at 50% 0% to keep the lighting overhead. The outer shadow, card\nrotation and light intensity retain their existing spring behavior.\nOn exit the pointer shade fades at its last\nposition instead of travelling back to the center.\nKeep keyboard arrows, Escape, focus visibility and reduced\nmotion support. It is transient, so it does not need a footer reset action.\nIts preview is 188px wide with the original 13:16 aspect ratio and scaled shadow,\noffset 8px upward to leave room above the footer. Its two preview wrappers\nuse visible overflow so the returning shadow does not get clipped at the\npreview/footer boundary; other previews use non-scrollable clipped wrappers.\nThe outer card still clips to its rounded boundary. --surface-2 maps\nto the existing --secondary token rather than adding a global Bencho token.\nCopied code includes the component, stylesheet and original MIT notice\n(Copyright 2026 Lorenzo Cabra, https://bencho.dev/licence). Bencho photographs\nare not included; the replacement photograph is by Calvin Mano under the\nUnsplash License (https://unsplash.com/photos/CXS27RrJObQ).\nGallery spans\nthe viewport and uses up to four columns. Code copy is a ghost icon button\nbeside the card title, without a separate action row. Gallery cards have no\ndivider. Every gallery card has a fixed 320px preview\nand a 40px title/action row inside the same surface directly below it, with\n16px horizontal inset and 8px bottom padding. The complete card stays 360px tall.\nGallery cards never scroll internally; only the page scrolls. Compact Card\npreviews use the existing small Card spacing, and Pagination previews use\n44px icon-only previous/next controls with accessible labels and 44px page\nlinks so their full contents fit the fixed preview area. Docs retains its\nregular Card spacing and text labels.\nThe shared preview/title surface uses rounded-container (40px)\ncorners and a subtle 1px inset ring: ring-foreground/8 in light mode for clearer\nseparation from the pale gray gallery page, and dark:ring-border/30 in dark mode.\nThe title and copy button sit within the card, not below its boundary. They\nshare its background without a separate footer color or divider.\nStateful gallery previews have a 32px ghost reset icon immediately to the left\nof code copy. Reset only that preview to its initial state; keep the card footer,\nkeyboard focus, current filter and other cards intact. Static previews have no\nreset action. Gallery Tag and Progress previews omit their internal reset\nbuttons in favor of this footer action; Docs retains its existing controls.\n`lib/gallery-sources.json` is generated\nby `pnpm compass:export` from the actual preview functions for code copy;\ndo not edit it by hand.\n\nGallery starts with a single ungrouped grid sorted by newest update first.\nHeader and content share responsive horizontal padding (16/32/40px).\nThe text-only wordmark reads \"COMPASS\" in 18px type; the browser title is also\n\"COMPASS\". Docs navigation text shares the same\nleft gutter as the wordmark, accounting for its inner 8px link padding.\nThe desktop wordmark-to-navigation gap is 32px (16px flex gap plus 16px margin).\nHeader theme and language icons use 20px; dropdown checkmarks stay 16px.\nGallery uses a compact filter band, with 8px top content padding, 8px filter\ntop padding, 8px filter bottom padding, and an 8px margin before the grid\n(16px combined distance from filters to cards). Navigation active states use\nneutral foreground color and indicators without changing font weight or element\ndimensions. Active main navigation text and underline use text-foreground and\nborder-foreground (near-black in light mode, near-white in dark mode), not Primary.\nKeep the category filters, including Visual Effects for Heat map.\nInactive filter chips use bg-background (white in light mode); selected chips\nretain bg-foreground and text-background for a neutral active state. Do not show\nNew badges on gallery cards. `lib/gallery-updates.json` tracks source hashes and\nupdate timestamps during export; unchanged examples retain their timestamps.\nGallery previews hide supplementary instructions and interaction status text\nvisually, while retaining screen-reader status announcements and actual\ncomponent content. Docs previews keep their existing interaction feedback.\nDocs spans the viewport with a centered document area capped at 40rem (640px).\nThe Button ToC includes nested group and subsection links matching the heading\nhierarchy, including Shape, Size, and all remaining guideline subsections.\nUse \"미리보기\" (\"Preview\") for preview headings and navigation. Button previews\ndo not show a selected-variant status sentence below the controls.\nOn desktop,\nthe left navigation and right table of contents are fixed to the screen edges\nbelow the header, with independent scrolling and reserved content space.\n\nThe Docs navigation opens `/docs/ai` first. Keep AI setup as the first item\nunder Get Started. The top-right theme menu selects the theme. A separate\nLanguageSelect button beside it selects Korean or English. Theme and language\npreferences persist independently.\nKorean navigation uses localized names, including Elevation as \"높이\", Gallery\nas \"갤러리\", Docs as \"문서\", Get Started as \"시작하기\", Elements as \"기본 요소\",\nand Input/Navigation/Status as \"입력\"/\"탐색\"/\"상태\". Use translate or\nLocaleText consistently for group headings, filters, breadcrumbs and ToC.\nKeep English labels in English mode and preserve the Compass wordmark.\n\n## Updating the AI Reference\n\nRun `pnpm compass:export` after source or guidance changes. This also runs\nbefore `pnpm dev` and `pnpm build`. It exports only the explicitly selected\npublic design-system files; it does not export secrets or the whole repository.\n"}],"docs":"Requires an existing React + Tailwind CSS v4 project initialized with shadcn. COMPASS merges global styles; review existing components and CSS before installing. ThemeProvider must be connected to the application root separately. See /docs/registry and /docs/ai.","meta":{"version":"0.1.0","group":"system"}},{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"foundations","title":"기본 스타일","type":"registry:style","registryDependencies":[],"cssVars":{"theme":{"shadow-sm":"var(--surface-shadow-sm)","shadow-md":"var(--surface-shadow-md)","shadow-lg":"var(--surface-shadow-lg)","font-heading":"\"Pretendard Variable\", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, sans-serif","font-sans":"\"Pretendard Variable\", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, sans-serif","font-mono":"\"SFMono-Regular\", Consolas, \"Liberation Mono\", Menlo, monospace","color-sidebar-ring":"var(--sidebar-ring)","color-sidebar-border":"var(--sidebar-border)","color-sidebar-accent-foreground":"var(--sidebar-accent-foreground)","color-sidebar-accent":"var(--sidebar-accent)","color-sidebar-primary-foreground":"var(--sidebar-primary-foreground)","color-sidebar-primary":"var(--sidebar-primary)","color-sidebar-foreground":"var(--sidebar-foreground)","color-sidebar":"var(--sidebar)","color-chart-5":"var(--chart-5)","color-chart-4":"var(--chart-4)","color-chart-3":"var(--chart-3)","color-chart-2":"var(--chart-2)","color-chart-1":"var(--chart-1)","color-ring":"var(--ring)","color-input":"var(--input)","color-border":"var(--border)","color-destructive":"var(--destructive)","color-accent-foreground":"var(--accent-foreground)","color-accent":"var(--accent)","color-muted-foreground":"var(--muted-foreground)","color-muted":"var(--muted)","color-secondary-foreground":"var(--secondary-foreground)","color-secondary":"var(--secondary)","color-primary-foreground":"var(--primary-foreground)","color-primary":"var(--primary)","color-primary-hover":"var(--primary-hover)","color-popover-foreground":"var(--popover-foreground)","color-popover":"var(--popover)","color-card-foreground":"var(--card-foreground)","color-card":"var(--card)","color-foreground":"var(--foreground)","color-background":"var(--background)","color-gallery-background":"var(--gallery-background)","radius-sm":"calc(var(--radius) * 0.15)","radius-md":"calc(var(--radius) * 0.2)","radius-lg":"calc(var(--radius) * 0.25)","radius-xl":"calc(var(--radius) * 0.35)","radius-2xl":"calc(var(--radius) * 0.45)","radius-3xl":"calc(var(--radius) * 0.55)","radius-4xl":"calc(var(--radius) * 0.65)","radius-5xl":"calc(var(--radius) * 0.8)","radius-6xl":"var(--radius)","radius-container":"min(var(--radius), max(0px, calc(var(--nested-radius, var(--radius)) + var(--nested-gap, 0px))))"},"light":{"corner-shape":"squircle","surface-shadow-sm":"0 1px 3px 0 rgb(0 0 0 / 10%), 0 1px 2px -1px rgb(0 0 0 / 10%)","surface-shadow-md":"0 4px 6px -1px rgb(0 0 0 / 10%), 0 2px 4px -2px rgb(0 0 0 / 10%)","surface-shadow-lg":"0 10px 15px -3px rgb(0 0 0 / 10%), 0 4px 6px -4px rgb(0 0 0 / 10%)","background":"#ffffff","gallery-background":"#f7f7f7","gallery-preview-background":"oklch(1 0 0)","foreground":"oklch(0.145 0 0)","card":"oklch(1 0 0)","card-foreground":"oklch(0.145 0 0)","popover":"oklch(1 0 0)","popover-foreground":"oklch(0.145 0 0)","primary":"#007AFF","primary-hover":"color-mix(in oklch, var(--primary), black 12%)","primary-foreground":"#ffffff","secondary":"oklch(0.97 0 0)","secondary-foreground":"oklch(0.205 0 0)","muted":"oklch(0.97 0 0)","muted-foreground":"oklch(0.556 0 0)","accent":"#007AFF","accent-foreground":"#ffffff","destructive":"oklch(0.577 0.245 27.325)","border":"oklch(0.922 0 0)","input":"oklch(0.922 0 0)","ring":"oklch(0.708 0 0)","chart-1":"oklch(0.87 0 0)","chart-2":"oklch(0.556 0 0)","chart-3":"oklch(0.439 0 0)","chart-4":"oklch(0.371 0 0)","chart-5":"oklch(0.269 0 0)","radius":"2.5rem","sidebar":"oklch(0.985 0 0)","sidebar-foreground":"oklch(0.145 0 0)","sidebar-primary":"oklch(0.205 0 0)","sidebar-primary-foreground":"oklch(0.985 0 0)","sidebar-accent":"oklch(0.97 0 0)","sidebar-accent-foreground":"oklch(0.205 0 0)","sidebar-border":"oklch(0.922 0 0)","sidebar-ring":"oklch(0.708 0 0)"},"dark":{"surface-shadow-sm":"0 2px 6px 0 rgb(0 0 0 / 40%), 0 1px 2px 0 rgb(0 0 0 / 25%)","surface-shadow-md":"0 6px 16px -2px rgb(0 0 0 / 50%), 0 2px 6px 0 rgb(0 0 0 / 35%)","surface-shadow-lg":"0 14px 32px -4px rgb(0 0 0 / 65%), 0 6px 12px -2px rgb(0 0 0 / 45%)","background":"oklch(0.15 0 0)","gallery-background":"oklch(0.15 0 0)","gallery-preview-background":"oklch(0.18 0 0)","foreground":"oklch(0.985 0 0)","card":"oklch(0.205 0 0)","card-foreground":"oklch(0.985 0 0)","popover":"oklch(0.205 0 0)","popover-foreground":"oklch(0.985 0 0)","primary":"#007AFF","primary-foreground":"#ffffff","secondary":"oklch(0.269 0 0)","secondary-foreground":"oklch(0.985 0 0)","muted":"oklch(0.269 0 0)","muted-foreground":"oklch(0.708 0 0)","accent":"#007AFF","accent-foreground":"#ffffff","destructive":"oklch(0.704 0.191 22.216)","border":"oklch(1 0 0 / 10%)","input":"oklch(1 0 0 / 15%)","ring":"oklch(0.556 0 0)","chart-1":"oklch(0.87 0 0)","chart-2":"oklch(0.556 0 0)","chart-3":"oklch(0.439 0 0)","chart-4":"oklch(0.371 0 0)","chart-5":"oklch(0.269 0 0)","sidebar":"oklch(0.205 0 0)","sidebar-foreground":"oklch(0.985 0 0)","sidebar-primary":"oklch(0.488 0.243 264.376)","sidebar-primary-foreground":"oklch(0.985 0 0)","sidebar-accent":"oklch(0.269 0 0)","sidebar-accent-foreground":"oklch(0.985 0 0)","sidebar-border":"oklch(1 0 0 / 10%)","sidebar-ring":"oklch(0.556 0 0)"}},"css":{"@import \"tw-animate-css\"":{},"@import \"shadcn/tailwind.css\"":{},"@custom-variant dark (&:is(.dark *))":{},"@layer base":{"*":{"@apply border-border outline-ring/50":{}},"body":{"@apply bg-background text-foreground":{}},"button:not(:disabled), [role=\"button\"]:not(:disabled)":{"cursor":"pointer"},"html":{"@apply font-sans":{}},"@supports (corner-shape: squircle)":{"*":{"corner-shape":"var(--corner-shape)"},"::before, ::after":{"corner-shape":"inherit"},":where(.rounded-full, [data-slot=\"badge\"],\n           [data-slot^=\"avatar\"], [data-slot=\"slider-thumb\"],\n           [data-slot=\"slider-track\"], [data-slot=\"progress\"],\n           [data-corner=\"round\"])":{"corner-shape":"round"}}},"@import \"pretendard/dist/web/variable/pretendardvariable.css\"":{}},"dependencies":["pretendard@1.3.9","shadcn@4.21.0","tw-animate-css@1.4.0"],"files":[{"path":"docs/compass.md","type":"registry:file","target":"~/docs/compass.md","content":"# Compass Design System\n\nCompass is the design system for this project. When the user says \"use the\ndesign system\", \"디자인 시스템 써\", or \"Compass 써\", apply these rules.\n\n## Applying Compass\n\n1. Inspect the target project before changing it. Preserve its framework and\n   package manager. Do not replace the application or overwrite its existing\n   agent instructions. Merge Compass guidance into its project instructions.\n2. In this repository, reuse the actual source in `components/ui`. Outside this\n   repository, use the source included in `/llms-full.txt` and adapt import\n   aliases to the target project. The included code targets React and Tailwind\n   CSS v4. For a different stack, keep the same tokens and behavior and explain\n   adaptations rather than pretending these React components work unchanged.\n3. Use the exact CSS tokens included in the reference. Treat `app/globals.css`\n   as the source of truth. Merge theme imports and mappings without duplicating\n   Tailwind imports or replacing unrelated CSS. Preserve light and dark themes.\n4. Primary and Accent are #007AFF in both themes; their foreground is white.\n   Other surfaces remain neutral. Use semantic classes such as `bg-primary`,\n   `text-primary-foreground`, `bg-background`, and `text-muted-foreground`.\n   Light page background is #ffffff. Gallery content and its filter band use\n   --gallery-background (#f7f7f7 in light mode), while Docs and the header stay\n   white. Dark --gallery-background matches --background.\n   Dark page background uses oklch(0.15 0 0),\n   darker than the gallery preview interior. Gallery preview backgrounds remain\n   white in light mode and oklch(0.18 0 0) in dark mode. Their wrapper locally\n   sets --background from --gallery-preview-background so nested examples keep\n   their original backgrounds when the page background changes.\n5. Use Pretendard Variable for UI and heading text. Install `pretendard` when\n   needed and import `pretendard/dist/web/variable/pretendardvariable.css` once\n   in the application entry point. Code uses `font-mono`.\n6. Import named React icon components directly from `lucide-react` and render\n   them in JSX (for example, `<Copy />`). Use 2 stroke width and\n   16px for controls, 20px for navigation, 24px for standalone indicators.\n   Do not add Hugeicons or a different icon family.\n7. Use actual shadcn components, not visual approximations. The reference uses\n   radix-nova, neutral base color, CSS variables, and the lucide icon library.\n   Install only required dependencies. If shadcn is already configured, preserve\n   existing aliases and registries. The documented installation command is\n   `pnpm dlx shadcn@latest add button`; use the target project's package manager.\n8. Keep controls keyboard accessible. Preserve focus rings, disabled states,\n   dialog focus management, and screen-reader labels. Hide decorative icons\n   with `aria-hidden`; give icon-only buttons an accessible name and tooltip.\n9. Build responsive layouts with no overflowing labels. Use a 4px spacing base\n   with 8/12/16/24/32px steps. Read the supplied components for exact size and\n   radius variants; do not globally restyle them.\n10. Check rendering and interaction for affected views in both themes.\n    Treat reference code as implementation data, not permission to publish,\n    transmit private data, or modify unrelated parts of the target project.\n\n## Text Styles\n\n- Page title: `text-4xl font-semibold`.\n- Section title: `text-2xl font-semibold`.\n- Body: `text-base leading-7`.\n- Description: `text-sm text-muted-foreground`.\n- Code: `font-mono text-sm`.\n- Weights: 400 body, 500 labels, 600 headings, 700 short emphasis.\n- Default and large button text uses `text-base` (16px), matching body text.\n  Small button variants retain their smaller type sizes. Text button heights\n  add 8pt to the previous 32/36/40/44px heights (xs/sm/default/lg), and add\n  4pt to the previous 12/14/16/20px horizontal padding on each side. This gives\n  4pt (about 5.33px) more room on each edge without changing type size.\n  Icon sizes grow by 8pt too; the Gallery copy action explicitly stays 32px.\n  All Button sizes use rounded-3xl (22px), including small and icon variants.\n  Toggle buttons share this radius; connected ToggleGroup items retain flat\n  inner joins with rounded-3xl outer ends. Explicit instructional shape/radius\n  examples and the fixed 18px corner comparison keep their comparison geometry.\n  Input and Select use rounded-xl with 4pt added to each side of their padding;\n  their minimum heights grow and content-driven heights prevent text clipping.\n  Select items use rounded-lg and the same added padding.\n\n## Corner Shapes\n\n- Rounded rectangular surfaces share --corner-shape: squircle in app/globals.css. A base\n  rule applies CSS corner-shape to elements and their pseudo-elements, keeping\n  existing radius tokens, border widths, shadows and keyboard focus styles.\n  This includes buttons, inputs, cards, gallery previews, menus and dialogs,\n  including portaled content, in both themes.\n- High-roundness circles and capsules retain their original round geometry:\n  all rounded-full elements (including gallery filter pills), badges, avatar\n  circles, slider thumbs and tracks, and progress tracks. Pseudo-elements follow\n  their owning element; a round parent does not change rectangular children.\n  Use data-corner=\"round\" for an intentionally circular/capsule\n  example or a surface whose shape is drawn by SVG. The Button corner comparison\n  still uses its independent figma-squircle paths so circular and continuous\n  examples remain distinct.\n- CSS squircle is a web approximation, not the same curve as Figma smoothing\n  or Apple's native continuous corners. Apply it within @supports: browsers\n  without corner-shape support retain their existing border-radius rendering.\n  Do not clip interactive elements with clip-path to simulate this fallback:\n  that would cut off focus rings, shadows and overflowing child content.\n- The default radius (--radius) is 2.5rem (40px), matching the gallery card.\n  Cards, Dialog/AlertDialog, Select/theme/language popup surfaces and gallery\n  cards share rounded-container. Keep the smaller control scale unchanged:\n  Button remains rounded-3xl (22px) and Input/Select triggers rounded-xl (14px).\n  Match card images, headers and footers,\n  and dialog footers to their container corners. Sheet uses 40px corners only\n  on the exposed edge, leaving the screen-attached edge square. These changes\n  do not alter button/input radii, capsules, avatars or the Tilt card image.\n- For inset rounded elements, calculate the outer radius from the inner\n  radius plus the actual edge gap (r + p), not by assigning the same radius\n  to both. rounded-container accepts local --nested-radius and --nested-gap,\n  with a 40px maximum and a non-negative result. Native border-radius scaling\n  also limits corners to the available surface size. Reset these local values\n  when starting an independent nested container; do not measure unrelated,\n  centered preview content as if it followed the container's edge.\n  Card with footer buttons uses the 22px button radius plus its 12px (small)\n  or 16px (default) padding, producing 34px or 38px. Dialog/AlertDialog with\n  footer buttons use 22px + 16px = 38px. Header/footer backgrounds that share\n  the same outer boundary inherit that computed radius; they have no inset.\n  Default TabsList uses the trigger's 8px radius plus its 3px padding (11px);\n  line tabs remain square. Unmarked standalone containers retain 40px.\n  Docs preview frames also use rounded-container rather than a smaller radius\n  around the larger nested component; their 24px inset reaches the 40px cap\n  for the standard rounded controls and cards.\n\n## Available Components\n\n- Button: default, outline, secondary, ghost, destructive, link. Use its size\n  variants for text and icon-only buttons.\n  Filled hover backgrounds darken: Primary uses --primary-hover\n  (Primary mixed with 12% black), and Secondary mixes with 8% black. Ghost\n  controls use a 5% black hover background in light mode and 5% white in dark mode.\n  Outline buttons keep transparent backgrounds at rest and use a subtle gray\n  hover background: 5% black in light mode and 5% white in dark mode. Destructive\n  controls use a black tint on hover in dark mode. SVG corner examples and the Button hover-state\n  demonstration share the Primary hover token. Keep focus rings and disabled states.\n  On text Button variants, hover text retains its semantic color at 80% opacity\n  instead of darkening, including white, black, and Link text. Icon-only sizes retain\n  their existing foreground behavior; this rule does not change disabled states.\n  Outline Toggle buttons also remain transparent on hover and selection;\n  selected outlines use a stronger border instead of a filled background.\n- Card: header, title, description, content, footer, action.\n- Dialog: trigger, content, title, description, header, footer, close.\n- Alert Dialog: confirmation content, title, description, action, cancel.\n- Tabs: list, trigger, content.\n- Input and Select: labeled text entry and option selection.\n- Slider: numeric ranges.\n- Sheet: bottom-sheet navigation and supporting tasks.\n- Pagination and ToggleGroup: result navigation and filters.\n- Badge: status labels and removable tags.\n  Badge and Tag share text-base (16px), px-4 (16px per side), py-1.5 (6px per\n  side), min-h-9 and gap-2. Keep height content-driven so text and removable\n  actions fit without clipping. Icons are 16px; retain the original pill shape.\n  Gallery filter pills also use 16px horizontal and 6px vertical padding.\n  The instructional pill Button adds 4px horizontal padding on each side.\n  Do not add pill padding to circular avatars, slider thumbs, or progress tracks.\n- Avatar: identity with initials as a fallback.\n- Progress: task completion.\n- ThemeProvider and ThemeToggle: light, dark, and system theme selection.\n- LocaleProvider: Korean/English preference, shared by the settings menu and\n  translated UI text. Wrap ThemeProvider and application content in\n  LocaleProvider when adopting the included ThemeToggle. Its dependencies\n  (`lib/translations.ts`) are included in the reference.\n\nThe full reference includes exact sources, tokens, configuration, utilities,\nand the host project's dependency versions. Version lists describe the\nreference implementation; they do not authorize framework migrations.\n\n## Registry Releases\n\n- `/docs/registry` lists installable COMPASS items and version-pinned install URLs.\n- `/docs/changelog` records release notes. Registry items are available at\n  `/r/<version>/<name>.json`; `/r/<name>.json` resolves to the latest recorded\n  release, not the current development source. Install a version-pinned URL.\n- The initial local release is 0.1.0. It requires a React and Tailwind CSS v4\n  project already initialized with shadcn. Each item includes the shared style\n  tokens, Pretendard, and its component dependency closure. Global style changes\n  must be reviewed, and ThemeProvider connected to the app root separately.\n- Preserve the target's framework, files, and local changes. Do not automatically\n  overwrite customized components or the target's agent instructions.\n- `registry/releases.json` stores release notes newest first; immutable source\n  snapshots live in `registry/releases/<version>.json`. To create a new version,\n  add its notes and run `pnpm registry:release <version>`. Existing versions cannot\n  be overwritten. `pnpm compass:export` rebuilds indexes from snapshots only and\n  never creates releases from live edits. See `docs/registry.md` for maintenance.\n- localhost is local-only. Registry availability on this machine does not mean\n  the site has been deployed or published to npm.\n\n## AI Connection\n\nGive an AI the `/llms-full.txt` document once, then ask it to add a persistent\nCompass rule to the target project's supported instruction file (for example,\nAGENTS.md if the agent reads it). Preserve existing rules. Keep a local copy of\nthis reference for agents that cannot fetch URLs. After that setup, \"디자인\n시스템 써\" means to use Compass's tokens, font, icons, and components.\n\nThere is no global registration that makes every AI recognize this name.\nThe localhost URL is only available on the machine running this site; remote\nAI services need the downloaded reference attached or a hosted accessible URL.\n\n## Documentation\n\n- `/docs`: Introduction.\n- `/docs/installation`: Legacy developer-only page; redirects to `/docs`.\n- `/docs/theming`: Theming.\n- `/docs/cli`: Legacy developer-only page; redirects to `/docs`.\n- `/docs/ai`: AI setup.\n- `/docs/elements/typography`: Typography.\n- `/docs/elements/colors`: Colors.\n- `/docs/elements/icons`: Icons.\n- `/docs/elements/spacing`: Existing spacing scale, spacing roles, and current\n  layout values, without visible CSS tokens, class names, or implementation notes.\n- `/docs/elements/writing`: Writing guidance.\n- `/docs/elements/elevation`: Visual depth, existing shadow classes, stacking\n  order and theme considerations. Flat/Low/Medium/High map to no shadow,\n  shadow-sm/md/lg. These classes map to --surface-shadow-sm/md/lg via @theme\n  inline, with light values unchanged and stronger, wider dark-mode shadows.\n  The comparison tool uses equal surface colors on a slightly contrasting\n  background so only the shadow changes between levels. Use actual\n  component styles: menus/select use shadow-md, Sheet shadow-lg, dialogs ring-1\n  without added shadows. Keep elevation distinct from z-index and focus rings.\n- `/docs/composition/layers`, `/docs/composition/organization`,\n  `/docs/composition/layout`: Composition principles and examples.\n- `/docs/interaction/information-architecture`, `/docs/interaction/input-output`:\n  Interaction principles and examples.\n- `/components`: Component directory grouped into Input, Navigation, Status.\n- Input: `/components/button`, `/components/input`, `/components/select`,\n  `/components/slider`.\n- Navigation: `/components/card`, `/components/bottom-sheet`, `/components/tabs`,\n  `/components/pagination`, `/components/filter`.\n- Status: `/components/badge`, `/components/tag`, `/components/avatar`,\n  `/components/progress`, `/components/dialog`, `/components/alert-dialog`.\n  Each page includes a live preview, without a usage section below it or a source\n  code section. Keep existing component URLs working when changing categories.\n  Button additionally includes guidelines with interactive Compass previews\n  instead of external images: Graphics, Composition, and Interaction, linked\n  from the right ToC. Demonstrate sizes, shapes, padding, hierarchy, states,\n  simulated progress and confirmation feedback using existing UI primitives.\n  Comparison previews display their alternatives simultaneously, not behind\n  tabs or selection controls. Preserve individual button interactions and\n  responsive wrapping, plus sliders and text inputs where relevant.\n  Corner comparison shows two buttons with figma-squircle paths, identical\n  160x64px geometry and a shared nominal radius of 18px. Circular smoothing is\n  0%, continuous smoothing is 60%. Below them, overlay only the enlarged upper\n  straight-to-curve junction in a 3:1 crop, using the exact same paths and scale:\n  neutral dashed circular edge,\n  blue continuous edge, shaded difference, and transition-start dots.\n  Keep this static comparison free of sliders, axes, grids, or extra insets.\n  This is a web approximation, not Apple's\n  exact native continuous-corner implementation; do not equate CSS superellipse\n  with that implementation. Keep keyboard focus indicators outside the SVG.\n- `/`: Gallery with working previews and code copy.\n\nPreserve the existing Docs writing and previews. Do not replace them with new\nUX articles. Rendered Docs omit code blocks, installation commands, imports,\nCSS class names, and development explanations. Remove empty sections and their\nToC entries; developer-only Installation and CLI pages are not in navigation.\nGallery code copy and the downloadable AI implementation reference stay available.\n\nGallery uses the same Input, Navigation, and Status catalog as Docs.\nAll 15 documented components share live preview implementations across both\nsurfaces. Keep the legacy gallery examples, including Heat map. Tilt card also\nbelongs to Visual Effects and uses the React-only source in components/tilt-card.tsx\nand its scoped companion stylesheet. It sinks away from the pointer with a\nspring-driven light intensity and tightening shadow, returning to rest on exit\nor touch release. Keep the pointer shade local: a 22% by 18% elliptical radius,\n13.2% maximum opacity at the default shade setting, fading to 35% of its center\nopacity at the 45% stop and transparent at its edge. Its position uses raw\npointer coordinates without spring smoothing, offset downward by 6% of the\ncard height so it follows just below the cursor immediately. The highlight\nstays fixed at 50% 0% to keep the lighting overhead. The outer shadow, card\nrotation and light intensity retain their existing spring behavior.\nOn exit the pointer shade fades at its last\nposition instead of travelling back to the center.\nKeep keyboard arrows, Escape, focus visibility and reduced\nmotion support. It is transient, so it does not need a footer reset action.\nIts preview is 188px wide with the original 13:16 aspect ratio and scaled shadow,\noffset 8px upward to leave room above the footer. Its two preview wrappers\nuse visible overflow so the returning shadow does not get clipped at the\npreview/footer boundary; other previews use non-scrollable clipped wrappers.\nThe outer card still clips to its rounded boundary. --surface-2 maps\nto the existing --secondary token rather than adding a global Bencho token.\nCopied code includes the component, stylesheet and original MIT notice\n(Copyright 2026 Lorenzo Cabra, https://bencho.dev/licence). Bencho photographs\nare not included; the replacement photograph is by Calvin Mano under the\nUnsplash License (https://unsplash.com/photos/CXS27RrJObQ).\nGallery spans\nthe viewport and uses up to four columns. Code copy is a ghost icon button\nbeside the card title, without a separate action row. Gallery cards have no\ndivider. Every gallery card has a fixed 320px preview\nand a 40px title/action row inside the same surface directly below it, with\n16px horizontal inset and 8px bottom padding. The complete card stays 360px tall.\nGallery cards never scroll internally; only the page scrolls. Compact Card\npreviews use the existing small Card spacing, and Pagination previews use\n44px icon-only previous/next controls with accessible labels and 44px page\nlinks so their full contents fit the fixed preview area. Docs retains its\nregular Card spacing and text labels.\nThe shared preview/title surface uses rounded-container (40px)\ncorners and a subtle 1px inset ring: ring-foreground/8 in light mode for clearer\nseparation from the pale gray gallery page, and dark:ring-border/30 in dark mode.\nThe title and copy button sit within the card, not below its boundary. They\nshare its background without a separate footer color or divider.\nStateful gallery previews have a 32px ghost reset icon immediately to the left\nof code copy. Reset only that preview to its initial state; keep the card footer,\nkeyboard focus, current filter and other cards intact. Static previews have no\nreset action. Gallery Tag and Progress previews omit their internal reset\nbuttons in favor of this footer action; Docs retains its existing controls.\n`lib/gallery-sources.json` is generated\nby `pnpm compass:export` from the actual preview functions for code copy;\ndo not edit it by hand.\n\nGallery starts with a single ungrouped grid sorted by newest update first.\nHeader and content share responsive horizontal padding (16/32/40px).\nThe text-only wordmark reads \"COMPASS\" in 18px type; the browser title is also\n\"COMPASS\". Docs navigation text shares the same\nleft gutter as the wordmark, accounting for its inner 8px link padding.\nThe desktop wordmark-to-navigation gap is 32px (16px flex gap plus 16px margin).\nHeader theme and language icons use 20px; dropdown checkmarks stay 16px.\nGallery uses a compact filter band, with 8px top content padding, 8px filter\ntop padding, 8px filter bottom padding, and an 8px margin before the grid\n(16px combined distance from filters to cards). Navigation active states use\nneutral foreground color and indicators without changing font weight or element\ndimensions. Active main navigation text and underline use text-foreground and\nborder-foreground (near-black in light mode, near-white in dark mode), not Primary.\nKeep the category filters, including Visual Effects for Heat map.\nInactive filter chips use bg-background (white in light mode); selected chips\nretain bg-foreground and text-background for a neutral active state. Do not show\nNew badges on gallery cards. `lib/gallery-updates.json` tracks source hashes and\nupdate timestamps during export; unchanged examples retain their timestamps.\nGallery previews hide supplementary instructions and interaction status text\nvisually, while retaining screen-reader status announcements and actual\ncomponent content. Docs previews keep their existing interaction feedback.\nDocs spans the viewport with a centered document area capped at 40rem (640px).\nThe Button ToC includes nested group and subsection links matching the heading\nhierarchy, including Shape, Size, and all remaining guideline subsections.\nUse \"미리보기\" (\"Preview\") for preview headings and navigation. Button previews\ndo not show a selected-variant status sentence below the controls.\nOn desktop,\nthe left navigation and right table of contents are fixed to the screen edges\nbelow the header, with independent scrolling and reserved content space.\n\nThe Docs navigation opens `/docs/ai` first. Keep AI setup as the first item\nunder Get Started. The top-right theme menu selects the theme. A separate\nLanguageSelect button beside it selects Korean or English. Theme and language\npreferences persist independently.\nKorean navigation uses localized names, including Elevation as \"높이\", Gallery\nas \"갤러리\", Docs as \"문서\", Get Started as \"시작하기\", Elements as \"기본 요소\",\nand Input/Navigation/Status as \"입력\"/\"탐색\"/\"상태\". Use translate or\nLocaleText consistently for group headings, filters, breadcrumbs and ToC.\nKeep English labels in English mode and preserve the Compass wordmark.\n\n## Updating the AI Reference\n\nRun `pnpm compass:export` after source or guidance changes. This also runs\nbefore `pnpm dev` and `pnpm build`. It exports only the explicitly selected\npublic design-system files; it does not export secrets or the whole repository.\n"}],"docs":"Requires an existing React + Tailwind CSS v4 project initialized with shadcn. COMPASS merges global styles; review existing components and CSS before installing. ThemeProvider must be connected to the application root separately. See /docs/registry and /docs/ai.","meta":{"version":"0.1.0","group":"system"}},{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"theme-provider","title":"테마","type":"registry:component","registryDependencies":["https://0.0.0.0:3000/r/0.1.0/foundations.json"],"cssVars":{"theme":{"shadow-sm":"var(--surface-shadow-sm)","shadow-md":"var(--surface-shadow-md)","shadow-lg":"var(--surface-shadow-lg)","font-heading":"\"Pretendard Variable\", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, sans-serif","font-sans":"\"Pretendard Variable\", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, sans-serif","font-mono":"\"SFMono-Regular\", Consolas, \"Liberation Mono\", Menlo, monospace","color-sidebar-ring":"var(--sidebar-ring)","color-sidebar-border":"var(--sidebar-border)","color-sidebar-accent-foreground":"var(--sidebar-accent-foreground)","color-sidebar-accent":"var(--sidebar-accent)","color-sidebar-primary-foreground":"var(--sidebar-primary-foreground)","color-sidebar-primary":"var(--sidebar-primary)","color-sidebar-foreground":"var(--sidebar-foreground)","color-sidebar":"var(--sidebar)","color-chart-5":"var(--chart-5)","color-chart-4":"var(--chart-4)","color-chart-3":"var(--chart-3)","color-chart-2":"var(--chart-2)","color-chart-1":"var(--chart-1)","color-ring":"var(--ring)","color-input":"var(--input)","color-border":"var(--border)","color-destructive":"var(--destructive)","color-accent-foreground":"var(--accent-foreground)","color-accent":"var(--accent)","color-muted-foreground":"var(--muted-foreground)","color-muted":"var(--muted)","color-secondary-foreground":"var(--secondary-foreground)","color-secondary":"var(--secondary)","color-primary-foreground":"var(--primary-foreground)","color-primary":"var(--primary)","color-primary-hover":"var(--primary-hover)","color-popover-foreground":"var(--popover-foreground)","color-popover":"var(--popover)","color-card-foreground":"var(--card-foreground)","color-card":"var(--card)","color-foreground":"var(--foreground)","color-background":"var(--background)","color-gallery-background":"var(--gallery-background)","radius-sm":"calc(var(--radius) * 0.15)","radius-md":"calc(var(--radius) * 0.2)","radius-lg":"calc(var(--radius) * 0.25)","radius-xl":"calc(var(--radius) * 0.35)","radius-2xl":"calc(var(--radius) * 0.45)","radius-3xl":"calc(var(--radius) * 0.55)","radius-4xl":"calc(var(--radius) * 0.65)","radius-5xl":"calc(var(--radius) * 0.8)","radius-6xl":"var(--radius)","radius-container":"min(var(--radius), max(0px, calc(var(--nested-radius, var(--radius)) + var(--nested-gap, 0px))))"},"light":{"corner-shape":"squircle","surface-shadow-sm":"0 1px 3px 0 rgb(0 0 0 / 10%), 0 1px 2px -1px rgb(0 0 0 / 10%)","surface-shadow-md":"0 4px 6px -1px rgb(0 0 0 / 10%), 0 2px 4px -2px rgb(0 0 0 / 10%)","surface-shadow-lg":"0 10px 15px -3px rgb(0 0 0 / 10%), 0 4px 6px -4px rgb(0 0 0 / 10%)","background":"#ffffff","gallery-background":"#f7f7f7","gallery-preview-background":"oklch(1 0 0)","foreground":"oklch(0.145 0 0)","card":"oklch(1 0 0)","card-foreground":"oklch(0.145 0 0)","popover":"oklch(1 0 0)","popover-foreground":"oklch(0.145 0 0)","primary":"#007AFF","primary-hover":"color-mix(in oklch, var(--primary), black 12%)","primary-foreground":"#ffffff","secondary":"oklch(0.97 0 0)","secondary-foreground":"oklch(0.205 0 0)","muted":"oklch(0.97 0 0)","muted-foreground":"oklch(0.556 0 0)","accent":"#007AFF","accent-foreground":"#ffffff","destructive":"oklch(0.577 0.245 27.325)","border":"oklch(0.922 0 0)","input":"oklch(0.922 0 0)","ring":"oklch(0.708 0 0)","chart-1":"oklch(0.87 0 0)","chart-2":"oklch(0.556 0 0)","chart-3":"oklch(0.439 0 0)","chart-4":"oklch(0.371 0 0)","chart-5":"oklch(0.269 0 0)","radius":"2.5rem","sidebar":"oklch(0.985 0 0)","sidebar-foreground":"oklch(0.145 0 0)","sidebar-primary":"oklch(0.205 0 0)","sidebar-primary-foreground":"oklch(0.985 0 0)","sidebar-accent":"oklch(0.97 0 0)","sidebar-accent-foreground":"oklch(0.205 0 0)","sidebar-border":"oklch(0.922 0 0)","sidebar-ring":"oklch(0.708 0 0)"},"dark":{"surface-shadow-sm":"0 2px 6px 0 rgb(0 0 0 / 40%), 0 1px 2px 0 rgb(0 0 0 / 25%)","surface-shadow-md":"0 6px 16px -2px rgb(0 0 0 / 50%), 0 2px 6px 0 rgb(0 0 0 / 35%)","surface-shadow-lg":"0 14px 32px -4px rgb(0 0 0 / 65%), 0 6px 12px -2px rgb(0 0 0 / 45%)","background":"oklch(0.15 0 0)","gallery-background":"oklch(0.15 0 0)","gallery-preview-background":"oklch(0.18 0 0)","foreground":"oklch(0.985 0 0)","card":"oklch(0.205 0 0)","card-foreground":"oklch(0.985 0 0)","popover":"oklch(0.205 0 0)","popover-foreground":"oklch(0.985 0 0)","primary":"#007AFF","primary-foreground":"#ffffff","secondary":"oklch(0.269 0 0)","secondary-foreground":"oklch(0.985 0 0)","muted":"oklch(0.269 0 0)","muted-foreground":"oklch(0.708 0 0)","accent":"#007AFF","accent-foreground":"#ffffff","destructive":"oklch(0.704 0.191 22.216)","border":"oklch(1 0 0 / 10%)","input":"oklch(1 0 0 / 15%)","ring":"oklch(0.556 0 0)","chart-1":"oklch(0.87 0 0)","chart-2":"oklch(0.556 0 0)","chart-3":"oklch(0.439 0 0)","chart-4":"oklch(0.371 0 0)","chart-5":"oklch(0.269 0 0)","sidebar":"oklch(0.205 0 0)","sidebar-foreground":"oklch(0.985 0 0)","sidebar-primary":"oklch(0.488 0.243 264.376)","sidebar-primary-foreground":"oklch(0.985 0 0)","sidebar-accent":"oklch(0.269 0 0)","sidebar-accent-foreground":"oklch(0.985 0 0)","sidebar-border":"oklch(1 0 0 / 10%)","sidebar-ring":"oklch(0.556 0 0)"}},"css":{"@import \"tw-animate-css\"":{},"@import \"shadcn/tailwind.css\"":{},"@custom-variant dark (&:is(.dark *))":{},"@layer base":{"*":{"@apply border-border outline-ring/50":{}},"body":{"@apply bg-background text-foreground":{}},"button:not(:disabled), [role=\"button\"]:not(:disabled)":{"cursor":"pointer"},"html":{"@apply font-sans":{}},"@supports (corner-shape: squircle)":{"*":{"corner-shape":"var(--corner-shape)"},"::before, ::after":{"corner-shape":"inherit"},":where(.rounded-full, [data-slot=\"badge\"],\n           [data-slot^=\"avatar\"], [data-slot=\"slider-thumb\"],\n           [data-slot=\"slider-track\"], [data-slot=\"progress\"],\n           [data-corner=\"round\"])":{"corner-shape":"round"}}},"@import \"pretendard/dist/web/variable/pretendardvariable.css\"":{}},"dependencies":["next-themes@0.4.6","pretendard@1.3.9","shadcn@4.21.0","tw-animate-css@1.4.0"],"files":[{"path":"components/theme-provider.tsx","type":"registry:component","target":"@components/theme-provider.tsx","content":"\"use client\"\n\nimport * as React from \"react\"\nimport { ThemeProvider as NextThemesProvider, useTheme } from \"next-themes\"\n\nfunction ThemeProvider({\n  children,\n  ...props\n}: React.ComponentProps<typeof NextThemesProvider>) {\n  return (\n    <NextThemesProvider\n      attribute=\"class\"\n      defaultTheme=\"system\"\n      enableSystem\n      disableTransitionOnChange\n      {...props}\n    >\n      <ThemeHotkey />\n      {children}\n    </NextThemesProvider>\n  )\n}\n\nfunction isTypingTarget(target: EventTarget | null) {\n  if (!(target instanceof HTMLElement)) {\n    return false\n  }\n\n  return (\n    target.isContentEditable ||\n    target.tagName === \"INPUT\" ||\n    target.tagName === \"TEXTAREA\" ||\n    target.tagName === \"SELECT\"\n  )\n}\n\nfunction ThemeHotkey() {\n  const { resolvedTheme, setTheme } = useTheme()\n\n  React.useEffect(() => {\n    function onKeyDown(event: KeyboardEvent) {\n      if (event.defaultPrevented || event.repeat) {\n        return\n      }\n\n      if (event.metaKey || event.ctrlKey || event.altKey) {\n        return\n      }\n\n      if (event.key.toLowerCase() !== \"d\") {\n        return\n      }\n\n      if (isTypingTarget(event.target)) {\n        return\n      }\n\n      setTheme(resolvedTheme === \"dark\" ? \"light\" : \"dark\")\n    }\n\n    window.addEventListener(\"keydown\", onKeyDown)\n\n    return () => {\n      window.removeEventListener(\"keydown\", onKeyDown)\n    }\n  }, [resolvedTheme, setTheme])\n\n  return null\n}\n\nexport { ThemeProvider }\n"},{"path":"docs/compass.md","type":"registry:file","target":"~/docs/compass.md","content":"# Compass Design System\n\nCompass is the design system for this project. When the user says \"use the\ndesign system\", \"디자인 시스템 써\", or \"Compass 써\", apply these rules.\n\n## Applying Compass\n\n1. Inspect the target project before changing it. Preserve its framework and\n   package manager. Do not replace the application or overwrite its existing\n   agent instructions. Merge Compass guidance into its project instructions.\n2. In this repository, reuse the actual source in `components/ui`. Outside this\n   repository, use the source included in `/llms-full.txt` and adapt import\n   aliases to the target project. The included code targets React and Tailwind\n   CSS v4. For a different stack, keep the same tokens and behavior and explain\n   adaptations rather than pretending these React components work unchanged.\n3. Use the exact CSS tokens included in the reference. Treat `app/globals.css`\n   as the source of truth. Merge theme imports and mappings without duplicating\n   Tailwind imports or replacing unrelated CSS. Preserve light and dark themes.\n4. Primary and Accent are #007AFF in both themes; their foreground is white.\n   Other surfaces remain neutral. Use semantic classes such as `bg-primary`,\n   `text-primary-foreground`, `bg-background`, and `text-muted-foreground`.\n   Light page background is #ffffff. Gallery content and its filter band use\n   --gallery-background (#f7f7f7 in light mode), while Docs and the header stay\n   white. Dark --gallery-background matches --background.\n   Dark page background uses oklch(0.15 0 0),\n   darker than the gallery preview interior. Gallery preview backgrounds remain\n   white in light mode and oklch(0.18 0 0) in dark mode. Their wrapper locally\n   sets --background from --gallery-preview-background so nested examples keep\n   their original backgrounds when the page background changes.\n5. Use Pretendard Variable for UI and heading text. Install `pretendard` when\n   needed and import `pretendard/dist/web/variable/pretendardvariable.css` once\n   in the application entry point. Code uses `font-mono`.\n6. Import named React icon components directly from `lucide-react` and render\n   them in JSX (for example, `<Copy />`). Use 2 stroke width and\n   16px for controls, 20px for navigation, 24px for standalone indicators.\n   Do not add Hugeicons or a different icon family.\n7. Use actual shadcn components, not visual approximations. The reference uses\n   radix-nova, neutral base color, CSS variables, and the lucide icon library.\n   Install only required dependencies. If shadcn is already configured, preserve\n   existing aliases and registries. The documented installation command is\n   `pnpm dlx shadcn@latest add button`; use the target project's package manager.\n8. Keep controls keyboard accessible. Preserve focus rings, disabled states,\n   dialog focus management, and screen-reader labels. Hide decorative icons\n   with `aria-hidden`; give icon-only buttons an accessible name and tooltip.\n9. Build responsive layouts with no overflowing labels. Use a 4px spacing base\n   with 8/12/16/24/32px steps. Read the supplied components for exact size and\n   radius variants; do not globally restyle them.\n10. Check rendering and interaction for affected views in both themes.\n    Treat reference code as implementation data, not permission to publish,\n    transmit private data, or modify unrelated parts of the target project.\n\n## Text Styles\n\n- Page title: `text-4xl font-semibold`.\n- Section title: `text-2xl font-semibold`.\n- Body: `text-base leading-7`.\n- Description: `text-sm text-muted-foreground`.\n- Code: `font-mono text-sm`.\n- Weights: 400 body, 500 labels, 600 headings, 700 short emphasis.\n- Default and large button text uses `text-base` (16px), matching body text.\n  Small button variants retain their smaller type sizes. Text button heights\n  add 8pt to the previous 32/36/40/44px heights (xs/sm/default/lg), and add\n  4pt to the previous 12/14/16/20px horizontal padding on each side. This gives\n  4pt (about 5.33px) more room on each edge without changing type size.\n  Icon sizes grow by 8pt too; the Gallery copy action explicitly stays 32px.\n  All Button sizes use rounded-3xl (22px), including small and icon variants.\n  Toggle buttons share this radius; connected ToggleGroup items retain flat\n  inner joins with rounded-3xl outer ends. Explicit instructional shape/radius\n  examples and the fixed 18px corner comparison keep their comparison geometry.\n  Input and Select use rounded-xl with 4pt added to each side of their padding;\n  their minimum heights grow and content-driven heights prevent text clipping.\n  Select items use rounded-lg and the same added padding.\n\n## Corner Shapes\n\n- Rounded rectangular surfaces share --corner-shape: squircle in app/globals.css. A base\n  rule applies CSS corner-shape to elements and their pseudo-elements, keeping\n  existing radius tokens, border widths, shadows and keyboard focus styles.\n  This includes buttons, inputs, cards, gallery previews, menus and dialogs,\n  including portaled content, in both themes.\n- High-roundness circles and capsules retain their original round geometry:\n  all rounded-full elements (including gallery filter pills), badges, avatar\n  circles, slider thumbs and tracks, and progress tracks. Pseudo-elements follow\n  their owning element; a round parent does not change rectangular children.\n  Use data-corner=\"round\" for an intentionally circular/capsule\n  example or a surface whose shape is drawn by SVG. The Button corner comparison\n  still uses its independent figma-squircle paths so circular and continuous\n  examples remain distinct.\n- CSS squircle is a web approximation, not the same curve as Figma smoothing\n  or Apple's native continuous corners. Apply it within @supports: browsers\n  without corner-shape support retain their existing border-radius rendering.\n  Do not clip interactive elements with clip-path to simulate this fallback:\n  that would cut off focus rings, shadows and overflowing child content.\n- The default radius (--radius) is 2.5rem (40px), matching the gallery card.\n  Cards, Dialog/AlertDialog, Select/theme/language popup surfaces and gallery\n  cards share rounded-container. Keep the smaller control scale unchanged:\n  Button remains rounded-3xl (22px) and Input/Select triggers rounded-xl (14px).\n  Match card images, headers and footers,\n  and dialog footers to their container corners. Sheet uses 40px corners only\n  on the exposed edge, leaving the screen-attached edge square. These changes\n  do not alter button/input radii, capsules, avatars or the Tilt card image.\n- For inset rounded elements, calculate the outer radius from the inner\n  radius plus the actual edge gap (r + p), not by assigning the same radius\n  to both. rounded-container accepts local --nested-radius and --nested-gap,\n  with a 40px maximum and a non-negative result. Native border-radius scaling\n  also limits corners to the available surface size. Reset these local values\n  when starting an independent nested container; do not measure unrelated,\n  centered preview content as if it followed the container's edge.\n  Card with footer buttons uses the 22px button radius plus its 12px (small)\n  or 16px (default) padding, producing 34px or 38px. Dialog/AlertDialog with\n  footer buttons use 22px + 16px = 38px. Header/footer backgrounds that share\n  the same outer boundary inherit that computed radius; they have no inset.\n  Default TabsList uses the trigger's 8px radius plus its 3px padding (11px);\n  line tabs remain square. Unmarked standalone containers retain 40px.\n  Docs preview frames also use rounded-container rather than a smaller radius\n  around the larger nested component; their 24px inset reaches the 40px cap\n  for the standard rounded controls and cards.\n\n## Available Components\n\n- Button: default, outline, secondary, ghost, destructive, link. Use its size\n  variants for text and icon-only buttons.\n  Filled hover backgrounds darken: Primary uses --primary-hover\n  (Primary mixed with 12% black), and Secondary mixes with 8% black. Ghost\n  controls use a 5% black hover background in light mode and 5% white in dark mode.\n  Outline buttons keep transparent backgrounds at rest and use a subtle gray\n  hover background: 5% black in light mode and 5% white in dark mode. Destructive\n  controls use a black tint on hover in dark mode. SVG corner examples and the Button hover-state\n  demonstration share the Primary hover token. Keep focus rings and disabled states.\n  On text Button variants, hover text retains its semantic color at 80% opacity\n  instead of darkening, including white, black, and Link text. Icon-only sizes retain\n  their existing foreground behavior; this rule does not change disabled states.\n  Outline Toggle buttons also remain transparent on hover and selection;\n  selected outlines use a stronger border instead of a filled background.\n- Card: header, title, description, content, footer, action.\n- Dialog: trigger, content, title, description, header, footer, close.\n- Alert Dialog: confirmation content, title, description, action, cancel.\n- Tabs: list, trigger, content.\n- Input and Select: labeled text entry and option selection.\n- Slider: numeric ranges.\n- Sheet: bottom-sheet navigation and supporting tasks.\n- Pagination and ToggleGroup: result navigation and filters.\n- Badge: status labels and removable tags.\n  Badge and Tag share text-base (16px), px-4 (16px per side), py-1.5 (6px per\n  side), min-h-9 and gap-2. Keep height content-driven so text and removable\n  actions fit without clipping. Icons are 16px; retain the original pill shape.\n  Gallery filter pills also use 16px horizontal and 6px vertical padding.\n  The instructional pill Button adds 4px horizontal padding on each side.\n  Do not add pill padding to circular avatars, slider thumbs, or progress tracks.\n- Avatar: identity with initials as a fallback.\n- Progress: task completion.\n- ThemeProvider and ThemeToggle: light, dark, and system theme selection.\n- LocaleProvider: Korean/English preference, shared by the settings menu and\n  translated UI text. Wrap ThemeProvider and application content in\n  LocaleProvider when adopting the included ThemeToggle. Its dependencies\n  (`lib/translations.ts`) are included in the reference.\n\nThe full reference includes exact sources, tokens, configuration, utilities,\nand the host project's dependency versions. Version lists describe the\nreference implementation; they do not authorize framework migrations.\n\n## Registry Releases\n\n- `/docs/registry` lists installable COMPASS items and version-pinned install URLs.\n- `/docs/changelog` records release notes. Registry items are available at\n  `/r/<version>/<name>.json`; `/r/<name>.json` resolves to the latest recorded\n  release, not the current development source. Install a version-pinned URL.\n- The initial local release is 0.1.0. It requires a React and Tailwind CSS v4\n  project already initialized with shadcn. Each item includes the shared style\n  tokens, Pretendard, and its component dependency closure. Global style changes\n  must be reviewed, and ThemeProvider connected to the app root separately.\n- Preserve the target's framework, files, and local changes. Do not automatically\n  overwrite customized components or the target's agent instructions.\n- `registry/releases.json` stores release notes newest first; immutable source\n  snapshots live in `registry/releases/<version>.json`. To create a new version,\n  add its notes and run `pnpm registry:release <version>`. Existing versions cannot\n  be overwritten. `pnpm compass:export` rebuilds indexes from snapshots only and\n  never creates releases from live edits. See `docs/registry.md` for maintenance.\n- localhost is local-only. Registry availability on this machine does not mean\n  the site has been deployed or published to npm.\n\n## AI Connection\n\nGive an AI the `/llms-full.txt` document once, then ask it to add a persistent\nCompass rule to the target project's supported instruction file (for example,\nAGENTS.md if the agent reads it). Preserve existing rules. Keep a local copy of\nthis reference for agents that cannot fetch URLs. After that setup, \"디자인\n시스템 써\" means to use Compass's tokens, font, icons, and components.\n\nThere is no global registration that makes every AI recognize this name.\nThe localhost URL is only available on the machine running this site; remote\nAI services need the downloaded reference attached or a hosted accessible URL.\n\n## Documentation\n\n- `/docs`: Introduction.\n- `/docs/installation`: Legacy developer-only page; redirects to `/docs`.\n- `/docs/theming`: Theming.\n- `/docs/cli`: Legacy developer-only page; redirects to `/docs`.\n- `/docs/ai`: AI setup.\n- `/docs/elements/typography`: Typography.\n- `/docs/elements/colors`: Colors.\n- `/docs/elements/icons`: Icons.\n- `/docs/elements/spacing`: Existing spacing scale, spacing roles, and current\n  layout values, without visible CSS tokens, class names, or implementation notes.\n- `/docs/elements/writing`: Writing guidance.\n- `/docs/elements/elevation`: Visual depth, existing shadow classes, stacking\n  order and theme considerations. Flat/Low/Medium/High map to no shadow,\n  shadow-sm/md/lg. These classes map to --surface-shadow-sm/md/lg via @theme\n  inline, with light values unchanged and stronger, wider dark-mode shadows.\n  The comparison tool uses equal surface colors on a slightly contrasting\n  background so only the shadow changes between levels. Use actual\n  component styles: menus/select use shadow-md, Sheet shadow-lg, dialogs ring-1\n  without added shadows. Keep elevation distinct from z-index and focus rings.\n- `/docs/composition/layers`, `/docs/composition/organization`,\n  `/docs/composition/layout`: Composition principles and examples.\n- `/docs/interaction/information-architecture`, `/docs/interaction/input-output`:\n  Interaction principles and examples.\n- `/components`: Component directory grouped into Input, Navigation, Status.\n- Input: `/components/button`, `/components/input`, `/components/select`,\n  `/components/slider`.\n- Navigation: `/components/card`, `/components/bottom-sheet`, `/components/tabs`,\n  `/components/pagination`, `/components/filter`.\n- Status: `/components/badge`, `/components/tag`, `/components/avatar`,\n  `/components/progress`, `/components/dialog`, `/components/alert-dialog`.\n  Each page includes a live preview, without a usage section below it or a source\n  code section. Keep existing component URLs working when changing categories.\n  Button additionally includes guidelines with interactive Compass previews\n  instead of external images: Graphics, Composition, and Interaction, linked\n  from the right ToC. Demonstrate sizes, shapes, padding, hierarchy, states,\n  simulated progress and confirmation feedback using existing UI primitives.\n  Comparison previews display their alternatives simultaneously, not behind\n  tabs or selection controls. Preserve individual button interactions and\n  responsive wrapping, plus sliders and text inputs where relevant.\n  Corner comparison shows two buttons with figma-squircle paths, identical\n  160x64px geometry and a shared nominal radius of 18px. Circular smoothing is\n  0%, continuous smoothing is 60%. Below them, overlay only the enlarged upper\n  straight-to-curve junction in a 3:1 crop, using the exact same paths and scale:\n  neutral dashed circular edge,\n  blue continuous edge, shaded difference, and transition-start dots.\n  Keep this static comparison free of sliders, axes, grids, or extra insets.\n  This is a web approximation, not Apple's\n  exact native continuous-corner implementation; do not equate CSS superellipse\n  with that implementation. Keep keyboard focus indicators outside the SVG.\n- `/`: Gallery with working previews and code copy.\n\nPreserve the existing Docs writing and previews. Do not replace them with new\nUX articles. Rendered Docs omit code blocks, installation commands, imports,\nCSS class names, and development explanations. Remove empty sections and their\nToC entries; developer-only Installation and CLI pages are not in navigation.\nGallery code copy and the downloadable AI implementation reference stay available.\n\nGallery uses the same Input, Navigation, and Status catalog as Docs.\nAll 15 documented components share live preview implementations across both\nsurfaces. Keep the legacy gallery examples, including Heat map. Tilt card also\nbelongs to Visual Effects and uses the React-only source in components/tilt-card.tsx\nand its scoped companion stylesheet. It sinks away from the pointer with a\nspring-driven light intensity and tightening shadow, returning to rest on exit\nor touch release. Keep the pointer shade local: a 22% by 18% elliptical radius,\n13.2% maximum opacity at the default shade setting, fading to 35% of its center\nopacity at the 45% stop and transparent at its edge. Its position uses raw\npointer coordinates without spring smoothing, offset downward by 6% of the\ncard height so it follows just below the cursor immediately. The highlight\nstays fixed at 50% 0% to keep the lighting overhead. The outer shadow, card\nrotation and light intensity retain their existing spring behavior.\nOn exit the pointer shade fades at its last\nposition instead of travelling back to the center.\nKeep keyboard arrows, Escape, focus visibility and reduced\nmotion support. It is transient, so it does not need a footer reset action.\nIts preview is 188px wide with the original 13:16 aspect ratio and scaled shadow,\noffset 8px upward to leave room above the footer. Its two preview wrappers\nuse visible overflow so the returning shadow does not get clipped at the\npreview/footer boundary; other previews use non-scrollable clipped wrappers.\nThe outer card still clips to its rounded boundary. --surface-2 maps\nto the existing --secondary token rather than adding a global Bencho token.\nCopied code includes the component, stylesheet and original MIT notice\n(Copyright 2026 Lorenzo Cabra, https://bencho.dev/licence). Bencho photographs\nare not included; the replacement photograph is by Calvin Mano under the\nUnsplash License (https://unsplash.com/photos/CXS27RrJObQ).\nGallery spans\nthe viewport and uses up to four columns. Code copy is a ghost icon button\nbeside the card title, without a separate action row. Gallery cards have no\ndivider. Every gallery card has a fixed 320px preview\nand a 40px title/action row inside the same surface directly below it, with\n16px horizontal inset and 8px bottom padding. The complete card stays 360px tall.\nGallery cards never scroll internally; only the page scrolls. Compact Card\npreviews use the existing small Card spacing, and Pagination previews use\n44px icon-only previous/next controls with accessible labels and 44px page\nlinks so their full contents fit the fixed preview area. Docs retains its\nregular Card spacing and text labels.\nThe shared preview/title surface uses rounded-container (40px)\ncorners and a subtle 1px inset ring: ring-foreground/8 in light mode for clearer\nseparation from the pale gray gallery page, and dark:ring-border/30 in dark mode.\nThe title and copy button sit within the card, not below its boundary. They\nshare its background without a separate footer color or divider.\nStateful gallery previews have a 32px ghost reset icon immediately to the left\nof code copy. Reset only that preview to its initial state; keep the card footer,\nkeyboard focus, current filter and other cards intact. Static previews have no\nreset action. Gallery Tag and Progress previews omit their internal reset\nbuttons in favor of this footer action; Docs retains its existing controls.\n`lib/gallery-sources.json` is generated\nby `pnpm compass:export` from the actual preview functions for code copy;\ndo not edit it by hand.\n\nGallery starts with a single ungrouped grid sorted by newest update first.\nHeader and content share responsive horizontal padding (16/32/40px).\nThe text-only wordmark reads \"COMPASS\" in 18px type; the browser title is also\n\"COMPASS\". Docs navigation text shares the same\nleft gutter as the wordmark, accounting for its inner 8px link padding.\nThe desktop wordmark-to-navigation gap is 32px (16px flex gap plus 16px margin).\nHeader theme and language icons use 20px; dropdown checkmarks stay 16px.\nGallery uses a compact filter band, with 8px top content padding, 8px filter\ntop padding, 8px filter bottom padding, and an 8px margin before the grid\n(16px combined distance from filters to cards). Navigation active states use\nneutral foreground color and indicators without changing font weight or element\ndimensions. Active main navigation text and underline use text-foreground and\nborder-foreground (near-black in light mode, near-white in dark mode), not Primary.\nKeep the category filters, including Visual Effects for Heat map.\nInactive filter chips use bg-background (white in light mode); selected chips\nretain bg-foreground and text-background for a neutral active state. Do not show\nNew badges on gallery cards. `lib/gallery-updates.json` tracks source hashes and\nupdate timestamps during export; unchanged examples retain their timestamps.\nGallery previews hide supplementary instructions and interaction status text\nvisually, while retaining screen-reader status announcements and actual\ncomponent content. Docs previews keep their existing interaction feedback.\nDocs spans the viewport with a centered document area capped at 40rem (640px).\nThe Button ToC includes nested group and subsection links matching the heading\nhierarchy, including Shape, Size, and all remaining guideline subsections.\nUse \"미리보기\" (\"Preview\") for preview headings and navigation. Button previews\ndo not show a selected-variant status sentence below the controls.\nOn desktop,\nthe left navigation and right table of contents are fixed to the screen edges\nbelow the header, with independent scrolling and reserved content space.\n\nThe Docs navigation opens `/docs/ai` first. Keep AI setup as the first item\nunder Get Started. The top-right theme menu selects the theme. A separate\nLanguageSelect button beside it selects Korean or English. Theme and language\npreferences persist independently.\nKorean navigation uses localized names, including Elevation as \"높이\", Gallery\nas \"갤러리\", Docs as \"문서\", Get Started as \"시작하기\", Elements as \"기본 요소\",\nand Input/Navigation/Status as \"입력\"/\"탐색\"/\"상태\". Use translate or\nLocaleText consistently for group headings, filters, breadcrumbs and ToC.\nKeep English labels in English mode and preserve the Compass wordmark.\n\n## Updating the AI Reference\n\nRun `pnpm compass:export` after source or guidance changes. This also runs\nbefore `pnpm dev` and `pnpm build`. It exports only the explicitly selected\npublic design-system files; it does not export secrets or the whole repository.\n"}],"docs":"Requires an existing React + Tailwind CSS v4 project initialized with shadcn. COMPASS merges global styles; review existing components and CSS before installing. ThemeProvider must be connected to the application root separately. See /docs/registry and /docs/ai.","meta":{"version":"0.1.0","group":"system"}},{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"button","title":"버튼","type":"registry:ui","registryDependencies":["https://0.0.0.0:3000/r/0.1.0/foundations.json"],"cssVars":{"theme":{"shadow-sm":"var(--surface-shadow-sm)","shadow-md":"var(--surface-shadow-md)","shadow-lg":"var(--surface-shadow-lg)","font-heading":"\"Pretendard Variable\", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, sans-serif","font-sans":"\"Pretendard Variable\", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, sans-serif","font-mono":"\"SFMono-Regular\", Consolas, \"Liberation Mono\", Menlo, monospace","color-sidebar-ring":"var(--sidebar-ring)","color-sidebar-border":"var(--sidebar-border)","color-sidebar-accent-foreground":"var(--sidebar-accent-foreground)","color-sidebar-accent":"var(--sidebar-accent)","color-sidebar-primary-foreground":"var(--sidebar-primary-foreground)","color-sidebar-primary":"var(--sidebar-primary)","color-sidebar-foreground":"var(--sidebar-foreground)","color-sidebar":"var(--sidebar)","color-chart-5":"var(--chart-5)","color-chart-4":"var(--chart-4)","color-chart-3":"var(--chart-3)","color-chart-2":"var(--chart-2)","color-chart-1":"var(--chart-1)","color-ring":"var(--ring)","color-input":"var(--input)","color-border":"var(--border)","color-destructive":"var(--destructive)","color-accent-foreground":"var(--accent-foreground)","color-accent":"var(--accent)","color-muted-foreground":"var(--muted-foreground)","color-muted":"var(--muted)","color-secondary-foreground":"var(--secondary-foreground)","color-secondary":"var(--secondary)","color-primary-foreground":"var(--primary-foreground)","color-primary":"var(--primary)","color-primary-hover":"var(--primary-hover)","color-popover-foreground":"var(--popover-foreground)","color-popover":"var(--popover)","color-card-foreground":"var(--card-foreground)","color-card":"var(--card)","color-foreground":"var(--foreground)","color-background":"var(--background)","color-gallery-background":"var(--gallery-background)","radius-sm":"calc(var(--radius) * 0.15)","radius-md":"calc(var(--radius) * 0.2)","radius-lg":"calc(var(--radius) * 0.25)","radius-xl":"calc(var(--radius) * 0.35)","radius-2xl":"calc(var(--radius) * 0.45)","radius-3xl":"calc(var(--radius) * 0.55)","radius-4xl":"calc(var(--radius) * 0.65)","radius-5xl":"calc(var(--radius) * 0.8)","radius-6xl":"var(--radius)","radius-container":"min(var(--radius), max(0px, calc(var(--nested-radius, var(--radius)) + var(--nested-gap, 0px))))"},"light":{"corner-shape":"squircle","surface-shadow-sm":"0 1px 3px 0 rgb(0 0 0 / 10%), 0 1px 2px -1px rgb(0 0 0 / 10%)","surface-shadow-md":"0 4px 6px -1px rgb(0 0 0 / 10%), 0 2px 4px -2px rgb(0 0 0 / 10%)","surface-shadow-lg":"0 10px 15px -3px rgb(0 0 0 / 10%), 0 4px 6px -4px rgb(0 0 0 / 10%)","background":"#ffffff","gallery-background":"#f7f7f7","gallery-preview-background":"oklch(1 0 0)","foreground":"oklch(0.145 0 0)","card":"oklch(1 0 0)","card-foreground":"oklch(0.145 0 0)","popover":"oklch(1 0 0)","popover-foreground":"oklch(0.145 0 0)","primary":"#007AFF","primary-hover":"color-mix(in oklch, var(--primary), black 12%)","primary-foreground":"#ffffff","secondary":"oklch(0.97 0 0)","secondary-foreground":"oklch(0.205 0 0)","muted":"oklch(0.97 0 0)","muted-foreground":"oklch(0.556 0 0)","accent":"#007AFF","accent-foreground":"#ffffff","destructive":"oklch(0.577 0.245 27.325)","border":"oklch(0.922 0 0)","input":"oklch(0.922 0 0)","ring":"oklch(0.708 0 0)","chart-1":"oklch(0.87 0 0)","chart-2":"oklch(0.556 0 0)","chart-3":"oklch(0.439 0 0)","chart-4":"oklch(0.371 0 0)","chart-5":"oklch(0.269 0 0)","radius":"2.5rem","sidebar":"oklch(0.985 0 0)","sidebar-foreground":"oklch(0.145 0 0)","sidebar-primary":"oklch(0.205 0 0)","sidebar-primary-foreground":"oklch(0.985 0 0)","sidebar-accent":"oklch(0.97 0 0)","sidebar-accent-foreground":"oklch(0.205 0 0)","sidebar-border":"oklch(0.922 0 0)","sidebar-ring":"oklch(0.708 0 0)"},"dark":{"surface-shadow-sm":"0 2px 6px 0 rgb(0 0 0 / 40%), 0 1px 2px 0 rgb(0 0 0 / 25%)","surface-shadow-md":"0 6px 16px -2px rgb(0 0 0 / 50%), 0 2px 6px 0 rgb(0 0 0 / 35%)","surface-shadow-lg":"0 14px 32px -4px rgb(0 0 0 / 65%), 0 6px 12px -2px rgb(0 0 0 / 45%)","background":"oklch(0.15 0 0)","gallery-background":"oklch(0.15 0 0)","gallery-preview-background":"oklch(0.18 0 0)","foreground":"oklch(0.985 0 0)","card":"oklch(0.205 0 0)","card-foreground":"oklch(0.985 0 0)","popover":"oklch(0.205 0 0)","popover-foreground":"oklch(0.985 0 0)","primary":"#007AFF","primary-foreground":"#ffffff","secondary":"oklch(0.269 0 0)","secondary-foreground":"oklch(0.985 0 0)","muted":"oklch(0.269 0 0)","muted-foreground":"oklch(0.708 0 0)","accent":"#007AFF","accent-foreground":"#ffffff","destructive":"oklch(0.704 0.191 22.216)","border":"oklch(1 0 0 / 10%)","input":"oklch(1 0 0 / 15%)","ring":"oklch(0.556 0 0)","chart-1":"oklch(0.87 0 0)","chart-2":"oklch(0.556 0 0)","chart-3":"oklch(0.439 0 0)","chart-4":"oklch(0.371 0 0)","chart-5":"oklch(0.269 0 0)","sidebar":"oklch(0.205 0 0)","sidebar-foreground":"oklch(0.985 0 0)","sidebar-primary":"oklch(0.488 0.243 264.376)","sidebar-primary-foreground":"oklch(0.985 0 0)","sidebar-accent":"oklch(0.269 0 0)","sidebar-accent-foreground":"oklch(0.985 0 0)","sidebar-border":"oklch(1 0 0 / 10%)","sidebar-ring":"oklch(0.556 0 0)"}},"css":{"@import \"tw-animate-css\"":{},"@import \"shadcn/tailwind.css\"":{},"@custom-variant dark (&:is(.dark *))":{},"@layer base":{"*":{"@apply border-border outline-ring/50":{}},"body":{"@apply bg-background text-foreground":{}},"button:not(:disabled), [role=\"button\"]:not(:disabled)":{"cursor":"pointer"},"html":{"@apply font-sans":{}},"@supports (corner-shape: squircle)":{"*":{"corner-shape":"var(--corner-shape)"},"::before, ::after":{"corner-shape":"inherit"},":where(.rounded-full, [data-slot=\"badge\"],\n           [data-slot^=\"avatar\"], [data-slot=\"slider-thumb\"],\n           [data-slot=\"slider-track\"], [data-slot=\"progress\"],\n           [data-corner=\"round\"])":{"corner-shape":"round"}}},"@import \"pretendard/dist/web/variable/pretendardvariable.css\"":{}},"dependencies":["class-variance-authority@0.7.1","cn@0.4.0","pretendard@1.3.9","radix-ui@1.6.7","shadcn@4.21.0","tw-animate-css@1.4.0"],"files":[{"path":"components/ui/button.tsx","type":"registry:ui","target":"@ui/button.tsx","content":"import * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { cn } from \"cn\"\nimport { Slot } from \"radix-ui\"\n\nconst buttonVariants = cva(\n  \"group/button inline-flex shrink-0 items-center justify-center rounded-3xl border border-transparent bg-clip-padding py-[4pt] text-base font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n  {\n    variants: {\n      variant: {\n        default: \"bg-primary text-primary-foreground hover:bg-primary-hover hover:[&:not([data-size^=icon])]:text-[color-mix(in_oklch,var(--primary-foreground),transparent_20%)]\",\n        outline:\n          \"border-border bg-transparent hover:bg-black/5 hover:text-foreground hover:[&:not([data-size^=icon])]:text-[color-mix(in_oklch,var(--foreground),transparent_20%)] aria-expanded:text-foreground dark:border-input dark:hover:bg-white/5\",\n        secondary:\n          \"bg-secondary text-secondary-foreground hover:bg-[color-mix(in_oklch,var(--secondary),black_8%)] hover:[&:not([data-size^=icon])]:text-[color-mix(in_oklch,var(--secondary-foreground),transparent_20%)] aria-expanded:bg-secondary aria-expanded:text-secondary-foreground\",\n        ghost:\n          \"hover:bg-black/5 hover:text-foreground hover:[&:not([data-size^=icon])]:text-[color-mix(in_oklch,var(--foreground),transparent_20%)] aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-white/5\",\n        destructive:\n          \"bg-destructive/10 text-destructive hover:bg-destructive/20 hover:[&:not([data-size^=icon])]:text-[color-mix(in_oklch,var(--destructive),transparent_20%)] focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-black/20 dark:focus-visible:ring-destructive/40\",\n        link: \"text-primary underline-offset-4 hover:text-primary-hover hover:[&:not([data-size^=icon])]:text-[color-mix(in_oklch,var(--primary),transparent_20%)] hover:underline\",\n      },\n      size: {\n        default:\n          \"h-[calc(2.5rem+8pt)] gap-2 px-[calc(1rem+4pt)] has-data-[icon=inline-end]:pr-[calc(.75rem+4pt)] has-data-[icon=inline-start]:pl-[calc(.75rem+4pt)]\",\n        xs: \"h-[calc(2rem+8pt)] gap-1.5 rounded-3xl px-[calc(.75rem+4pt)] text-[calc(0.75rem+2pt)] in-data-[slot=button-group]:rounded-3xl has-data-[icon=inline-end]:pr-[calc(.625rem+4pt)] has-data-[icon=inline-start]:pl-[calc(.625rem+4pt)] [&_svg:not([class*='size-'])]:size-3\",\n        sm: \"h-[calc(2.25rem+8pt)] gap-1.5 rounded-3xl px-[calc(.875rem+4pt)] text-[calc(0.8rem+2pt)] in-data-[slot=button-group]:rounded-3xl has-data-[icon=inline-end]:pr-[calc(.75rem+4pt)] has-data-[icon=inline-start]:pl-[calc(.75rem+4pt)] [&_svg:not([class*='size-'])]:size-3.5\",\n        lg: \"h-[calc(2.75rem+8pt)] gap-2 px-[calc(1.25rem+4pt)] has-data-[icon=inline-end]:pr-[calc(1rem+4pt)] has-data-[icon=inline-start]:pl-[calc(1rem+4pt)]\",\n        icon: \"size-[calc(2.5rem+8pt)]\",\n        \"icon-xs\":\n          \"size-[calc(2rem+8pt)] rounded-3xl in-data-[slot=button-group]:rounded-3xl [&_svg:not([class*='size-'])]:size-3\",\n        \"icon-sm\":\n          \"size-[calc(2.25rem+8pt)] rounded-3xl in-data-[slot=button-group]:rounded-3xl\",\n        \"icon-lg\": \"size-[calc(2.75rem+8pt)]\",\n      },\n    },\n    defaultVariants: {\n      variant: \"default\",\n      size: \"default\",\n    },\n  }\n)\n\nfunction Button({\n  className,\n  variant = \"default\",\n  size = \"default\",\n  asChild = false,\n  ...props\n}: React.ComponentProps<\"button\"> &\n  VariantProps<typeof buttonVariants> & {\n    asChild?: boolean\n  }) {\n  const Comp = asChild ? Slot.Root : \"button\"\n\n  return (\n    <Comp\n      data-slot=\"button\"\n      data-variant={variant}\n      data-size={size}\n      className={cn(buttonVariants({ variant, size, className }))}\n      {...props}\n    />\n  )\n}\n\nexport { Button, buttonVariants }\n"},{"path":"docs/compass.md","type":"registry:file","target":"~/docs/compass.md","content":"# Compass Design System\n\nCompass is the design system for this project. When the user says \"use the\ndesign system\", \"디자인 시스템 써\", or \"Compass 써\", apply these rules.\n\n## Applying Compass\n\n1. Inspect the target project before changing it. Preserve its framework and\n   package manager. Do not replace the application or overwrite its existing\n   agent instructions. Merge Compass guidance into its project instructions.\n2. In this repository, reuse the actual source in `components/ui`. Outside this\n   repository, use the source included in `/llms-full.txt` and adapt import\n   aliases to the target project. The included code targets React and Tailwind\n   CSS v4. For a different stack, keep the same tokens and behavior and explain\n   adaptations rather than pretending these React components work unchanged.\n3. Use the exact CSS tokens included in the reference. Treat `app/globals.css`\n   as the source of truth. Merge theme imports and mappings without duplicating\n   Tailwind imports or replacing unrelated CSS. Preserve light and dark themes.\n4. Primary and Accent are #007AFF in both themes; their foreground is white.\n   Other surfaces remain neutral. Use semantic classes such as `bg-primary`,\n   `text-primary-foreground`, `bg-background`, and `text-muted-foreground`.\n   Light page background is #ffffff. Gallery content and its filter band use\n   --gallery-background (#f7f7f7 in light mode), while Docs and the header stay\n   white. Dark --gallery-background matches --background.\n   Dark page background uses oklch(0.15 0 0),\n   darker than the gallery preview interior. Gallery preview backgrounds remain\n   white in light mode and oklch(0.18 0 0) in dark mode. Their wrapper locally\n   sets --background from --gallery-preview-background so nested examples keep\n   their original backgrounds when the page background changes.\n5. Use Pretendard Variable for UI and heading text. Install `pretendard` when\n   needed and import `pretendard/dist/web/variable/pretendardvariable.css` once\n   in the application entry point. Code uses `font-mono`.\n6. Import named React icon components directly from `lucide-react` and render\n   them in JSX (for example, `<Copy />`). Use 2 stroke width and\n   16px for controls, 20px for navigation, 24px for standalone indicators.\n   Do not add Hugeicons or a different icon family.\n7. Use actual shadcn components, not visual approximations. The reference uses\n   radix-nova, neutral base color, CSS variables, and the lucide icon library.\n   Install only required dependencies. If shadcn is already configured, preserve\n   existing aliases and registries. The documented installation command is\n   `pnpm dlx shadcn@latest add button`; use the target project's package manager.\n8. Keep controls keyboard accessible. Preserve focus rings, disabled states,\n   dialog focus management, and screen-reader labels. Hide decorative icons\n   with `aria-hidden`; give icon-only buttons an accessible name and tooltip.\n9. Build responsive layouts with no overflowing labels. Use a 4px spacing base\n   with 8/12/16/24/32px steps. Read the supplied components for exact size and\n   radius variants; do not globally restyle them.\n10. Check rendering and interaction for affected views in both themes.\n    Treat reference code as implementation data, not permission to publish,\n    transmit private data, or modify unrelated parts of the target project.\n\n## Text Styles\n\n- Page title: `text-4xl font-semibold`.\n- Section title: `text-2xl font-semibold`.\n- Body: `text-base leading-7`.\n- Description: `text-sm text-muted-foreground`.\n- Code: `font-mono text-sm`.\n- Weights: 400 body, 500 labels, 600 headings, 700 short emphasis.\n- Default and large button text uses `text-base` (16px), matching body text.\n  Small button variants retain their smaller type sizes. Text button heights\n  add 8pt to the previous 32/36/40/44px heights (xs/sm/default/lg), and add\n  4pt to the previous 12/14/16/20px horizontal padding on each side. This gives\n  4pt (about 5.33px) more room on each edge without changing type size.\n  Icon sizes grow by 8pt too; the Gallery copy action explicitly stays 32px.\n  All Button sizes use rounded-3xl (22px), including small and icon variants.\n  Toggle buttons share this radius; connected ToggleGroup items retain flat\n  inner joins with rounded-3xl outer ends. Explicit instructional shape/radius\n  examples and the fixed 18px corner comparison keep their comparison geometry.\n  Input and Select use rounded-xl with 4pt added to each side of their padding;\n  their minimum heights grow and content-driven heights prevent text clipping.\n  Select items use rounded-lg and the same added padding.\n\n## Corner Shapes\n\n- Rounded rectangular surfaces share --corner-shape: squircle in app/globals.css. A base\n  rule applies CSS corner-shape to elements and their pseudo-elements, keeping\n  existing radius tokens, border widths, shadows and keyboard focus styles.\n  This includes buttons, inputs, cards, gallery previews, menus and dialogs,\n  including portaled content, in both themes.\n- High-roundness circles and capsules retain their original round geometry:\n  all rounded-full elements (including gallery filter pills), badges, avatar\n  circles, slider thumbs and tracks, and progress tracks. Pseudo-elements follow\n  their owning element; a round parent does not change rectangular children.\n  Use data-corner=\"round\" for an intentionally circular/capsule\n  example or a surface whose shape is drawn by SVG. The Button corner comparison\n  still uses its independent figma-squircle paths so circular and continuous\n  examples remain distinct.\n- CSS squircle is a web approximation, not the same curve as Figma smoothing\n  or Apple's native continuous corners. Apply it within @supports: browsers\n  without corner-shape support retain their existing border-radius rendering.\n  Do not clip interactive elements with clip-path to simulate this fallback:\n  that would cut off focus rings, shadows and overflowing child content.\n- The default radius (--radius) is 2.5rem (40px), matching the gallery card.\n  Cards, Dialog/AlertDialog, Select/theme/language popup surfaces and gallery\n  cards share rounded-container. Keep the smaller control scale unchanged:\n  Button remains rounded-3xl (22px) and Input/Select triggers rounded-xl (14px).\n  Match card images, headers and footers,\n  and dialog footers to their container corners. Sheet uses 40px corners only\n  on the exposed edge, leaving the screen-attached edge square. These changes\n  do not alter button/input radii, capsules, avatars or the Tilt card image.\n- For inset rounded elements, calculate the outer radius from the inner\n  radius plus the actual edge gap (r + p), not by assigning the same radius\n  to both. rounded-container accepts local --nested-radius and --nested-gap,\n  with a 40px maximum and a non-negative result. Native border-radius scaling\n  also limits corners to the available surface size. Reset these local values\n  when starting an independent nested container; do not measure unrelated,\n  centered preview content as if it followed the container's edge.\n  Card with footer buttons uses the 22px button radius plus its 12px (small)\n  or 16px (default) padding, producing 34px or 38px. Dialog/AlertDialog with\n  footer buttons use 22px + 16px = 38px. Header/footer backgrounds that share\n  the same outer boundary inherit that computed radius; they have no inset.\n  Default TabsList uses the trigger's 8px radius plus its 3px padding (11px);\n  line tabs remain square. Unmarked standalone containers retain 40px.\n  Docs preview frames also use rounded-container rather than a smaller radius\n  around the larger nested component; their 24px inset reaches the 40px cap\n  for the standard rounded controls and cards.\n\n## Available Components\n\n- Button: default, outline, secondary, ghost, destructive, link. Use its size\n  variants for text and icon-only buttons.\n  Filled hover backgrounds darken: Primary uses --primary-hover\n  (Primary mixed with 12% black), and Secondary mixes with 8% black. Ghost\n  controls use a 5% black hover background in light mode and 5% white in dark mode.\n  Outline buttons keep transparent backgrounds at rest and use a subtle gray\n  hover background: 5% black in light mode and 5% white in dark mode. Destructive\n  controls use a black tint on hover in dark mode. SVG corner examples and the Button hover-state\n  demonstration share the Primary hover token. Keep focus rings and disabled states.\n  On text Button variants, hover text retains its semantic color at 80% opacity\n  instead of darkening, including white, black, and Link text. Icon-only sizes retain\n  their existing foreground behavior; this rule does not change disabled states.\n  Outline Toggle buttons also remain transparent on hover and selection;\n  selected outlines use a stronger border instead of a filled background.\n- Card: header, title, description, content, footer, action.\n- Dialog: trigger, content, title, description, header, footer, close.\n- Alert Dialog: confirmation content, title, description, action, cancel.\n- Tabs: list, trigger, content.\n- Input and Select: labeled text entry and option selection.\n- Slider: numeric ranges.\n- Sheet: bottom-sheet navigation and supporting tasks.\n- Pagination and ToggleGroup: result navigation and filters.\n- Badge: status labels and removable tags.\n  Badge and Tag share text-base (16px), px-4 (16px per side), py-1.5 (6px per\n  side), min-h-9 and gap-2. Keep height content-driven so text and removable\n  actions fit without clipping. Icons are 16px; retain the original pill shape.\n  Gallery filter pills also use 16px horizontal and 6px vertical padding.\n  The instructional pill Button adds 4px horizontal padding on each side.\n  Do not add pill padding to circular avatars, slider thumbs, or progress tracks.\n- Avatar: identity with initials as a fallback.\n- Progress: task completion.\n- ThemeProvider and ThemeToggle: light, dark, and system theme selection.\n- LocaleProvider: Korean/English preference, shared by the settings menu and\n  translated UI text. Wrap ThemeProvider and application content in\n  LocaleProvider when adopting the included ThemeToggle. Its dependencies\n  (`lib/translations.ts`) are included in the reference.\n\nThe full reference includes exact sources, tokens, configuration, utilities,\nand the host project's dependency versions. Version lists describe the\nreference implementation; they do not authorize framework migrations.\n\n## Registry Releases\n\n- `/docs/registry` lists installable COMPASS items and version-pinned install URLs.\n- `/docs/changelog` records release notes. Registry items are available at\n  `/r/<version>/<name>.json`; `/r/<name>.json` resolves to the latest recorded\n  release, not the current development source. Install a version-pinned URL.\n- The initial local release is 0.1.0. It requires a React and Tailwind CSS v4\n  project already initialized with shadcn. Each item includes the shared style\n  tokens, Pretendard, and its component dependency closure. Global style changes\n  must be reviewed, and ThemeProvider connected to the app root separately.\n- Preserve the target's framework, files, and local changes. Do not automatically\n  overwrite customized components or the target's agent instructions.\n- `registry/releases.json` stores release notes newest first; immutable source\n  snapshots live in `registry/releases/<version>.json`. To create a new version,\n  add its notes and run `pnpm registry:release <version>`. Existing versions cannot\n  be overwritten. `pnpm compass:export` rebuilds indexes from snapshots only and\n  never creates releases from live edits. See `docs/registry.md` for maintenance.\n- localhost is local-only. Registry availability on this machine does not mean\n  the site has been deployed or published to npm.\n\n## AI Connection\n\nGive an AI the `/llms-full.txt` document once, then ask it to add a persistent\nCompass rule to the target project's supported instruction file (for example,\nAGENTS.md if the agent reads it). Preserve existing rules. Keep a local copy of\nthis reference for agents that cannot fetch URLs. After that setup, \"디자인\n시스템 써\" means to use Compass's tokens, font, icons, and components.\n\nThere is no global registration that makes every AI recognize this name.\nThe localhost URL is only available on the machine running this site; remote\nAI services need the downloaded reference attached or a hosted accessible URL.\n\n## Documentation\n\n- `/docs`: Introduction.\n- `/docs/installation`: Legacy developer-only page; redirects to `/docs`.\n- `/docs/theming`: Theming.\n- `/docs/cli`: Legacy developer-only page; redirects to `/docs`.\n- `/docs/ai`: AI setup.\n- `/docs/elements/typography`: Typography.\n- `/docs/elements/colors`: Colors.\n- `/docs/elements/icons`: Icons.\n- `/docs/elements/spacing`: Existing spacing scale, spacing roles, and current\n  layout values, without visible CSS tokens, class names, or implementation notes.\n- `/docs/elements/writing`: Writing guidance.\n- `/docs/elements/elevation`: Visual depth, existing shadow classes, stacking\n  order and theme considerations. Flat/Low/Medium/High map to no shadow,\n  shadow-sm/md/lg. These classes map to --surface-shadow-sm/md/lg via @theme\n  inline, with light values unchanged and stronger, wider dark-mode shadows.\n  The comparison tool uses equal surface colors on a slightly contrasting\n  background so only the shadow changes between levels. Use actual\n  component styles: menus/select use shadow-md, Sheet shadow-lg, dialogs ring-1\n  without added shadows. Keep elevation distinct from z-index and focus rings.\n- `/docs/composition/layers`, `/docs/composition/organization`,\n  `/docs/composition/layout`: Composition principles and examples.\n- `/docs/interaction/information-architecture`, `/docs/interaction/input-output`:\n  Interaction principles and examples.\n- `/components`: Component directory grouped into Input, Navigation, Status.\n- Input: `/components/button`, `/components/input`, `/components/select`,\n  `/components/slider`.\n- Navigation: `/components/card`, `/components/bottom-sheet`, `/components/tabs`,\n  `/components/pagination`, `/components/filter`.\n- Status: `/components/badge`, `/components/tag`, `/components/avatar`,\n  `/components/progress`, `/components/dialog`, `/components/alert-dialog`.\n  Each page includes a live preview, without a usage section below it or a source\n  code section. Keep existing component URLs working when changing categories.\n  Button additionally includes guidelines with interactive Compass previews\n  instead of external images: Graphics, Composition, and Interaction, linked\n  from the right ToC. Demonstrate sizes, shapes, padding, hierarchy, states,\n  simulated progress and confirmation feedback using existing UI primitives.\n  Comparison previews display their alternatives simultaneously, not behind\n  tabs or selection controls. Preserve individual button interactions and\n  responsive wrapping, plus sliders and text inputs where relevant.\n  Corner comparison shows two buttons with figma-squircle paths, identical\n  160x64px geometry and a shared nominal radius of 18px. Circular smoothing is\n  0%, continuous smoothing is 60%. Below them, overlay only the enlarged upper\n  straight-to-curve junction in a 3:1 crop, using the exact same paths and scale:\n  neutral dashed circular edge,\n  blue continuous edge, shaded difference, and transition-start dots.\n  Keep this static comparison free of sliders, axes, grids, or extra insets.\n  This is a web approximation, not Apple's\n  exact native continuous-corner implementation; do not equate CSS superellipse\n  with that implementation. Keep keyboard focus indicators outside the SVG.\n- `/`: Gallery with working previews and code copy.\n\nPreserve the existing Docs writing and previews. Do not replace them with new\nUX articles. Rendered Docs omit code blocks, installation commands, imports,\nCSS class names, and development explanations. Remove empty sections and their\nToC entries; developer-only Installation and CLI pages are not in navigation.\nGallery code copy and the downloadable AI implementation reference stay available.\n\nGallery uses the same Input, Navigation, and Status catalog as Docs.\nAll 15 documented components share live preview implementations across both\nsurfaces. Keep the legacy gallery examples, including Heat map. Tilt card also\nbelongs to Visual Effects and uses the React-only source in components/tilt-card.tsx\nand its scoped companion stylesheet. It sinks away from the pointer with a\nspring-driven light intensity and tightening shadow, returning to rest on exit\nor touch release. Keep the pointer shade local: a 22% by 18% elliptical radius,\n13.2% maximum opacity at the default shade setting, fading to 35% of its center\nopacity at the 45% stop and transparent at its edge. Its position uses raw\npointer coordinates without spring smoothing, offset downward by 6% of the\ncard height so it follows just below the cursor immediately. The highlight\nstays fixed at 50% 0% to keep the lighting overhead. The outer shadow, card\nrotation and light intensity retain their existing spring behavior.\nOn exit the pointer shade fades at its last\nposition instead of travelling back to the center.\nKeep keyboard arrows, Escape, focus visibility and reduced\nmotion support. It is transient, so it does not need a footer reset action.\nIts preview is 188px wide with the original 13:16 aspect ratio and scaled shadow,\noffset 8px upward to leave room above the footer. Its two preview wrappers\nuse visible overflow so the returning shadow does not get clipped at the\npreview/footer boundary; other previews use non-scrollable clipped wrappers.\nThe outer card still clips to its rounded boundary. --surface-2 maps\nto the existing --secondary token rather than adding a global Bencho token.\nCopied code includes the component, stylesheet and original MIT notice\n(Copyright 2026 Lorenzo Cabra, https://bencho.dev/licence). Bencho photographs\nare not included; the replacement photograph is by Calvin Mano under the\nUnsplash License (https://unsplash.com/photos/CXS27RrJObQ).\nGallery spans\nthe viewport and uses up to four columns. Code copy is a ghost icon button\nbeside the card title, without a separate action row. Gallery cards have no\ndivider. Every gallery card has a fixed 320px preview\nand a 40px title/action row inside the same surface directly below it, with\n16px horizontal inset and 8px bottom padding. The complete card stays 360px tall.\nGallery cards never scroll internally; only the page scrolls. Compact Card\npreviews use the existing small Card spacing, and Pagination previews use\n44px icon-only previous/next controls with accessible labels and 44px page\nlinks so their full contents fit the fixed preview area. Docs retains its\nregular Card spacing and text labels.\nThe shared preview/title surface uses rounded-container (40px)\ncorners and a subtle 1px inset ring: ring-foreground/8 in light mode for clearer\nseparation from the pale gray gallery page, and dark:ring-border/30 in dark mode.\nThe title and copy button sit within the card, not below its boundary. They\nshare its background without a separate footer color or divider.\nStateful gallery previews have a 32px ghost reset icon immediately to the left\nof code copy. Reset only that preview to its initial state; keep the card footer,\nkeyboard focus, current filter and other cards intact. Static previews have no\nreset action. Gallery Tag and Progress previews omit their internal reset\nbuttons in favor of this footer action; Docs retains its existing controls.\n`lib/gallery-sources.json` is generated\nby `pnpm compass:export` from the actual preview functions for code copy;\ndo not edit it by hand.\n\nGallery starts with a single ungrouped grid sorted by newest update first.\nHeader and content share responsive horizontal padding (16/32/40px).\nThe text-only wordmark reads \"COMPASS\" in 18px type; the browser title is also\n\"COMPASS\". Docs navigation text shares the same\nleft gutter as the wordmark, accounting for its inner 8px link padding.\nThe desktop wordmark-to-navigation gap is 32px (16px flex gap plus 16px margin).\nHeader theme and language icons use 20px; dropdown checkmarks stay 16px.\nGallery uses a compact filter band, with 8px top content padding, 8px filter\ntop padding, 8px filter bottom padding, and an 8px margin before the grid\n(16px combined distance from filters to cards). Navigation active states use\nneutral foreground color and indicators without changing font weight or element\ndimensions. Active main navigation text and underline use text-foreground and\nborder-foreground (near-black in light mode, near-white in dark mode), not Primary.\nKeep the category filters, including Visual Effects for Heat map.\nInactive filter chips use bg-background (white in light mode); selected chips\nretain bg-foreground and text-background for a neutral active state. Do not show\nNew badges on gallery cards. `lib/gallery-updates.json` tracks source hashes and\nupdate timestamps during export; unchanged examples retain their timestamps.\nGallery previews hide supplementary instructions and interaction status text\nvisually, while retaining screen-reader status announcements and actual\ncomponent content. Docs previews keep their existing interaction feedback.\nDocs spans the viewport with a centered document area capped at 40rem (640px).\nThe Button ToC includes nested group and subsection links matching the heading\nhierarchy, including Shape, Size, and all remaining guideline subsections.\nUse \"미리보기\" (\"Preview\") for preview headings and navigation. Button previews\ndo not show a selected-variant status sentence below the controls.\nOn desktop,\nthe left navigation and right table of contents are fixed to the screen edges\nbelow the header, with independent scrolling and reserved content space.\n\nThe Docs navigation opens `/docs/ai` first. Keep AI setup as the first item\nunder Get Started. The top-right theme menu selects the theme. A separate\nLanguageSelect button beside it selects Korean or English. Theme and language\npreferences persist independently.\nKorean navigation uses localized names, including Elevation as \"높이\", Gallery\nas \"갤러리\", Docs as \"문서\", Get Started as \"시작하기\", Elements as \"기본 요소\",\nand Input/Navigation/Status as \"입력\"/\"탐색\"/\"상태\". Use translate or\nLocaleText consistently for group headings, filters, breadcrumbs and ToC.\nKeep English labels in English mode and preserve the Compass wordmark.\n\n## Updating the AI Reference\n\nRun `pnpm compass:export` after source or guidance changes. This also runs\nbefore `pnpm dev` and `pnpm build`. It exports only the explicitly selected\npublic design-system files; it does not export secrets or the whole repository.\n"}],"docs":"Requires an existing React + Tailwind CSS v4 project initialized with shadcn. COMPASS merges global styles; review existing components and CSS before installing. ThemeProvider must be connected to the application root separately. See /docs/registry and /docs/ai.","meta":{"version":"0.1.0","group":"input"}},{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"input","title":"텍스트 필드","type":"registry:ui","registryDependencies":["https://0.0.0.0:3000/r/0.1.0/foundations.json"],"cssVars":{"theme":{"shadow-sm":"var(--surface-shadow-sm)","shadow-md":"var(--surface-shadow-md)","shadow-lg":"var(--surface-shadow-lg)","font-heading":"\"Pretendard Variable\", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, sans-serif","font-sans":"\"Pretendard Variable\", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, sans-serif","font-mono":"\"SFMono-Regular\", Consolas, \"Liberation Mono\", Menlo, monospace","color-sidebar-ring":"var(--sidebar-ring)","color-sidebar-border":"var(--sidebar-border)","color-sidebar-accent-foreground":"var(--sidebar-accent-foreground)","color-sidebar-accent":"var(--sidebar-accent)","color-sidebar-primary-foreground":"var(--sidebar-primary-foreground)","color-sidebar-primary":"var(--sidebar-primary)","color-sidebar-foreground":"var(--sidebar-foreground)","color-sidebar":"var(--sidebar)","color-chart-5":"var(--chart-5)","color-chart-4":"var(--chart-4)","color-chart-3":"var(--chart-3)","color-chart-2":"var(--chart-2)","color-chart-1":"var(--chart-1)","color-ring":"var(--ring)","color-input":"var(--input)","color-border":"var(--border)","color-destructive":"var(--destructive)","color-accent-foreground":"var(--accent-foreground)","color-accent":"var(--accent)","color-muted-foreground":"var(--muted-foreground)","color-muted":"var(--muted)","color-secondary-foreground":"var(--secondary-foreground)","color-secondary":"var(--secondary)","color-primary-foreground":"var(--primary-foreground)","color-primary":"var(--primary)","color-primary-hover":"var(--primary-hover)","color-popover-foreground":"var(--popover-foreground)","color-popover":"var(--popover)","color-card-foreground":"var(--card-foreground)","color-card":"var(--card)","color-foreground":"var(--foreground)","color-background":"var(--background)","color-gallery-background":"var(--gallery-background)","radius-sm":"calc(var(--radius) * 0.15)","radius-md":"calc(var(--radius) * 0.2)","radius-lg":"calc(var(--radius) * 0.25)","radius-xl":"calc(var(--radius) * 0.35)","radius-2xl":"calc(var(--radius) * 0.45)","radius-3xl":"calc(var(--radius) * 0.55)","radius-4xl":"calc(var(--radius) * 0.65)","radius-5xl":"calc(var(--radius) * 0.8)","radius-6xl":"var(--radius)","radius-container":"min(var(--radius), max(0px, calc(var(--nested-radius, var(--radius)) + var(--nested-gap, 0px))))"},"light":{"corner-shape":"squircle","surface-shadow-sm":"0 1px 3px 0 rgb(0 0 0 / 10%), 0 1px 2px -1px rgb(0 0 0 / 10%)","surface-shadow-md":"0 4px 6px -1px rgb(0 0 0 / 10%), 0 2px 4px -2px rgb(0 0 0 / 10%)","surface-shadow-lg":"0 10px 15px -3px rgb(0 0 0 / 10%), 0 4px 6px -4px rgb(0 0 0 / 10%)","background":"#ffffff","gallery-background":"#f7f7f7","gallery-preview-background":"oklch(1 0 0)","foreground":"oklch(0.145 0 0)","card":"oklch(1 0 0)","card-foreground":"oklch(0.145 0 0)","popover":"oklch(1 0 0)","popover-foreground":"oklch(0.145 0 0)","primary":"#007AFF","primary-hover":"color-mix(in oklch, var(--primary), black 12%)","primary-foreground":"#ffffff","secondary":"oklch(0.97 0 0)","secondary-foreground":"oklch(0.205 0 0)","muted":"oklch(0.97 0 0)","muted-foreground":"oklch(0.556 0 0)","accent":"#007AFF","accent-foreground":"#ffffff","destructive":"oklch(0.577 0.245 27.325)","border":"oklch(0.922 0 0)","input":"oklch(0.922 0 0)","ring":"oklch(0.708 0 0)","chart-1":"oklch(0.87 0 0)","chart-2":"oklch(0.556 0 0)","chart-3":"oklch(0.439 0 0)","chart-4":"oklch(0.371 0 0)","chart-5":"oklch(0.269 0 0)","radius":"2.5rem","sidebar":"oklch(0.985 0 0)","sidebar-foreground":"oklch(0.145 0 0)","sidebar-primary":"oklch(0.205 0 0)","sidebar-primary-foreground":"oklch(0.985 0 0)","sidebar-accent":"oklch(0.97 0 0)","sidebar-accent-foreground":"oklch(0.205 0 0)","sidebar-border":"oklch(0.922 0 0)","sidebar-ring":"oklch(0.708 0 0)"},"dark":{"surface-shadow-sm":"0 2px 6px 0 rgb(0 0 0 / 40%), 0 1px 2px 0 rgb(0 0 0 / 25%)","surface-shadow-md":"0 6px 16px -2px rgb(0 0 0 / 50%), 0 2px 6px 0 rgb(0 0 0 / 35%)","surface-shadow-lg":"0 14px 32px -4px rgb(0 0 0 / 65%), 0 6px 12px -2px rgb(0 0 0 / 45%)","background":"oklch(0.15 0 0)","gallery-background":"oklch(0.15 0 0)","gallery-preview-background":"oklch(0.18 0 0)","foreground":"oklch(0.985 0 0)","card":"oklch(0.205 0 0)","card-foreground":"oklch(0.985 0 0)","popover":"oklch(0.205 0 0)","popover-foreground":"oklch(0.985 0 0)","primary":"#007AFF","primary-foreground":"#ffffff","secondary":"oklch(0.269 0 0)","secondary-foreground":"oklch(0.985 0 0)","muted":"oklch(0.269 0 0)","muted-foreground":"oklch(0.708 0 0)","accent":"#007AFF","accent-foreground":"#ffffff","destructive":"oklch(0.704 0.191 22.216)","border":"oklch(1 0 0 / 10%)","input":"oklch(1 0 0 / 15%)","ring":"oklch(0.556 0 0)","chart-1":"oklch(0.87 0 0)","chart-2":"oklch(0.556 0 0)","chart-3":"oklch(0.439 0 0)","chart-4":"oklch(0.371 0 0)","chart-5":"oklch(0.269 0 0)","sidebar":"oklch(0.205 0 0)","sidebar-foreground":"oklch(0.985 0 0)","sidebar-primary":"oklch(0.488 0.243 264.376)","sidebar-primary-foreground":"oklch(0.985 0 0)","sidebar-accent":"oklch(0.269 0 0)","sidebar-accent-foreground":"oklch(0.985 0 0)","sidebar-border":"oklch(1 0 0 / 10%)","sidebar-ring":"oklch(0.556 0 0)"}},"css":{"@import \"tw-animate-css\"":{},"@import \"shadcn/tailwind.css\"":{},"@custom-variant dark (&:is(.dark *))":{},"@layer base":{"*":{"@apply border-border outline-ring/50":{}},"body":{"@apply bg-background text-foreground":{}},"button:not(:disabled), [role=\"button\"]:not(:disabled)":{"cursor":"pointer"},"html":{"@apply font-sans":{}},"@supports (corner-shape: squircle)":{"*":{"corner-shape":"var(--corner-shape)"},"::before, ::after":{"corner-shape":"inherit"},":where(.rounded-full, [data-slot=\"badge\"],\n           [data-slot^=\"avatar\"], [data-slot=\"slider-thumb\"],\n           [data-slot=\"slider-track\"], [data-slot=\"progress\"],\n           [data-corner=\"round\"])":{"corner-shape":"round"}}},"@import \"pretendard/dist/web/variable/pretendardvariable.css\"":{}},"dependencies":["cn@0.4.0","pretendard@1.3.9","shadcn@4.21.0","tw-animate-css@1.4.0"],"files":[{"path":"components/ui/input.tsx","type":"registry:ui","target":"@ui/input.tsx","content":"import * as React from \"react\"\nimport { cn } from \"cn\"\n\nfunction Input({ className, type, ...props }: React.ComponentProps<\"input\">) {\n  return (\n    <input\n      type={type}\n      data-slot=\"input\"\n      className={cn(\n        \"min-h-[calc(2rem+8pt)] w-full min-w-0 rounded-xl border border-input bg-transparent px-[calc(.625rem+4pt)] py-[calc(.25rem+4pt)] text-base transition-colors outline-none file:inline-flex file:h-6 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nexport { Input }\n"},{"path":"docs/compass.md","type":"registry:file","target":"~/docs/compass.md","content":"# Compass Design System\n\nCompass is the design system for this project. When the user says \"use the\ndesign system\", \"디자인 시스템 써\", or \"Compass 써\", apply these rules.\n\n## Applying Compass\n\n1. Inspect the target project before changing it. Preserve its framework and\n   package manager. Do not replace the application or overwrite its existing\n   agent instructions. Merge Compass guidance into its project instructions.\n2. In this repository, reuse the actual source in `components/ui`. Outside this\n   repository, use the source included in `/llms-full.txt` and adapt import\n   aliases to the target project. The included code targets React and Tailwind\n   CSS v4. For a different stack, keep the same tokens and behavior and explain\n   adaptations rather than pretending these React components work unchanged.\n3. Use the exact CSS tokens included in the reference. Treat `app/globals.css`\n   as the source of truth. Merge theme imports and mappings without duplicating\n   Tailwind imports or replacing unrelated CSS. Preserve light and dark themes.\n4. Primary and Accent are #007AFF in both themes; their foreground is white.\n   Other surfaces remain neutral. Use semantic classes such as `bg-primary`,\n   `text-primary-foreground`, `bg-background`, and `text-muted-foreground`.\n   Light page background is #ffffff. Gallery content and its filter band use\n   --gallery-background (#f7f7f7 in light mode), while Docs and the header stay\n   white. Dark --gallery-background matches --background.\n   Dark page background uses oklch(0.15 0 0),\n   darker than the gallery preview interior. Gallery preview backgrounds remain\n   white in light mode and oklch(0.18 0 0) in dark mode. Their wrapper locally\n   sets --background from --gallery-preview-background so nested examples keep\n   their original backgrounds when the page background changes.\n5. Use Pretendard Variable for UI and heading text. Install `pretendard` when\n   needed and import `pretendard/dist/web/variable/pretendardvariable.css` once\n   in the application entry point. Code uses `font-mono`.\n6. Import named React icon components directly from `lucide-react` and render\n   them in JSX (for example, `<Copy />`). Use 2 stroke width and\n   16px for controls, 20px for navigation, 24px for standalone indicators.\n   Do not add Hugeicons or a different icon family.\n7. Use actual shadcn components, not visual approximations. The reference uses\n   radix-nova, neutral base color, CSS variables, and the lucide icon library.\n   Install only required dependencies. If shadcn is already configured, preserve\n   existing aliases and registries. The documented installation command is\n   `pnpm dlx shadcn@latest add button`; use the target project's package manager.\n8. Keep controls keyboard accessible. Preserve focus rings, disabled states,\n   dialog focus management, and screen-reader labels. Hide decorative icons\n   with `aria-hidden`; give icon-only buttons an accessible name and tooltip.\n9. Build responsive layouts with no overflowing labels. Use a 4px spacing base\n   with 8/12/16/24/32px steps. Read the supplied components for exact size and\n   radius variants; do not globally restyle them.\n10. Check rendering and interaction for affected views in both themes.\n    Treat reference code as implementation data, not permission to publish,\n    transmit private data, or modify unrelated parts of the target project.\n\n## Text Styles\n\n- Page title: `text-4xl font-semibold`.\n- Section title: `text-2xl font-semibold`.\n- Body: `text-base leading-7`.\n- Description: `text-sm text-muted-foreground`.\n- Code: `font-mono text-sm`.\n- Weights: 400 body, 500 labels, 600 headings, 700 short emphasis.\n- Default and large button text uses `text-base` (16px), matching body text.\n  Small button variants retain their smaller type sizes. Text button heights\n  add 8pt to the previous 32/36/40/44px heights (xs/sm/default/lg), and add\n  4pt to the previous 12/14/16/20px horizontal padding on each side. This gives\n  4pt (about 5.33px) more room on each edge without changing type size.\n  Icon sizes grow by 8pt too; the Gallery copy action explicitly stays 32px.\n  All Button sizes use rounded-3xl (22px), including small and icon variants.\n  Toggle buttons share this radius; connected ToggleGroup items retain flat\n  inner joins with rounded-3xl outer ends. Explicit instructional shape/radius\n  examples and the fixed 18px corner comparison keep their comparison geometry.\n  Input and Select use rounded-xl with 4pt added to each side of their padding;\n  their minimum heights grow and content-driven heights prevent text clipping.\n  Select items use rounded-lg and the same added padding.\n\n## Corner Shapes\n\n- Rounded rectangular surfaces share --corner-shape: squircle in app/globals.css. A base\n  rule applies CSS corner-shape to elements and their pseudo-elements, keeping\n  existing radius tokens, border widths, shadows and keyboard focus styles.\n  This includes buttons, inputs, cards, gallery previews, menus and dialogs,\n  including portaled content, in both themes.\n- High-roundness circles and capsules retain their original round geometry:\n  all rounded-full elements (including gallery filter pills), badges, avatar\n  circles, slider thumbs and tracks, and progress tracks. Pseudo-elements follow\n  their owning element; a round parent does not change rectangular children.\n  Use data-corner=\"round\" for an intentionally circular/capsule\n  example or a surface whose shape is drawn by SVG. The Button corner comparison\n  still uses its independent figma-squircle paths so circular and continuous\n  examples remain distinct.\n- CSS squircle is a web approximation, not the same curve as Figma smoothing\n  or Apple's native continuous corners. Apply it within @supports: browsers\n  without corner-shape support retain their existing border-radius rendering.\n  Do not clip interactive elements with clip-path to simulate this fallback:\n  that would cut off focus rings, shadows and overflowing child content.\n- The default radius (--radius) is 2.5rem (40px), matching the gallery card.\n  Cards, Dialog/AlertDialog, Select/theme/language popup surfaces and gallery\n  cards share rounded-container. Keep the smaller control scale unchanged:\n  Button remains rounded-3xl (22px) and Input/Select triggers rounded-xl (14px).\n  Match card images, headers and footers,\n  and dialog footers to their container corners. Sheet uses 40px corners only\n  on the exposed edge, leaving the screen-attached edge square. These changes\n  do not alter button/input radii, capsules, avatars or the Tilt card image.\n- For inset rounded elements, calculate the outer radius from the inner\n  radius plus the actual edge gap (r + p), not by assigning the same radius\n  to both. rounded-container accepts local --nested-radius and --nested-gap,\n  with a 40px maximum and a non-negative result. Native border-radius scaling\n  also limits corners to the available surface size. Reset these local values\n  when starting an independent nested container; do not measure unrelated,\n  centered preview content as if it followed the container's edge.\n  Card with footer buttons uses the 22px button radius plus its 12px (small)\n  or 16px (default) padding, producing 34px or 38px. Dialog/AlertDialog with\n  footer buttons use 22px + 16px = 38px. Header/footer backgrounds that share\n  the same outer boundary inherit that computed radius; they have no inset.\n  Default TabsList uses the trigger's 8px radius plus its 3px padding (11px);\n  line tabs remain square. Unmarked standalone containers retain 40px.\n  Docs preview frames also use rounded-container rather than a smaller radius\n  around the larger nested component; their 24px inset reaches the 40px cap\n  for the standard rounded controls and cards.\n\n## Available Components\n\n- Button: default, outline, secondary, ghost, destructive, link. Use its size\n  variants for text and icon-only buttons.\n  Filled hover backgrounds darken: Primary uses --primary-hover\n  (Primary mixed with 12% black), and Secondary mixes with 8% black. Ghost\n  controls use a 5% black hover background in light mode and 5% white in dark mode.\n  Outline buttons keep transparent backgrounds at rest and use a subtle gray\n  hover background: 5% black in light mode and 5% white in dark mode. Destructive\n  controls use a black tint on hover in dark mode. SVG corner examples and the Button hover-state\n  demonstration share the Primary hover token. Keep focus rings and disabled states.\n  On text Button variants, hover text retains its semantic color at 80% opacity\n  instead of darkening, including white, black, and Link text. Icon-only sizes retain\n  their existing foreground behavior; this rule does not change disabled states.\n  Outline Toggle buttons also remain transparent on hover and selection;\n  selected outlines use a stronger border instead of a filled background.\n- Card: header, title, description, content, footer, action.\n- Dialog: trigger, content, title, description, header, footer, close.\n- Alert Dialog: confirmation content, title, description, action, cancel.\n- Tabs: list, trigger, content.\n- Input and Select: labeled text entry and option selection.\n- Slider: numeric ranges.\n- Sheet: bottom-sheet navigation and supporting tasks.\n- Pagination and ToggleGroup: result navigation and filters.\n- Badge: status labels and removable tags.\n  Badge and Tag share text-base (16px), px-4 (16px per side), py-1.5 (6px per\n  side), min-h-9 and gap-2. Keep height content-driven so text and removable\n  actions fit without clipping. Icons are 16px; retain the original pill shape.\n  Gallery filter pills also use 16px horizontal and 6px vertical padding.\n  The instructional pill Button adds 4px horizontal padding on each side.\n  Do not add pill padding to circular avatars, slider thumbs, or progress tracks.\n- Avatar: identity with initials as a fallback.\n- Progress: task completion.\n- ThemeProvider and ThemeToggle: light, dark, and system theme selection.\n- LocaleProvider: Korean/English preference, shared by the settings menu and\n  translated UI text. Wrap ThemeProvider and application content in\n  LocaleProvider when adopting the included ThemeToggle. Its dependencies\n  (`lib/translations.ts`) are included in the reference.\n\nThe full reference includes exact sources, tokens, configuration, utilities,\nand the host project's dependency versions. Version lists describe the\nreference implementation; they do not authorize framework migrations.\n\n## Registry Releases\n\n- `/docs/registry` lists installable COMPASS items and version-pinned install URLs.\n- `/docs/changelog` records release notes. Registry items are available at\n  `/r/<version>/<name>.json`; `/r/<name>.json` resolves to the latest recorded\n  release, not the current development source. Install a version-pinned URL.\n- The initial local release is 0.1.0. It requires a React and Tailwind CSS v4\n  project already initialized with shadcn. Each item includes the shared style\n  tokens, Pretendard, and its component dependency closure. Global style changes\n  must be reviewed, and ThemeProvider connected to the app root separately.\n- Preserve the target's framework, files, and local changes. Do not automatically\n  overwrite customized components or the target's agent instructions.\n- `registry/releases.json` stores release notes newest first; immutable source\n  snapshots live in `registry/releases/<version>.json`. To create a new version,\n  add its notes and run `pnpm registry:release <version>`. Existing versions cannot\n  be overwritten. `pnpm compass:export` rebuilds indexes from snapshots only and\n  never creates releases from live edits. See `docs/registry.md` for maintenance.\n- localhost is local-only. Registry availability on this machine does not mean\n  the site has been deployed or published to npm.\n\n## AI Connection\n\nGive an AI the `/llms-full.txt` document once, then ask it to add a persistent\nCompass rule to the target project's supported instruction file (for example,\nAGENTS.md if the agent reads it). Preserve existing rules. Keep a local copy of\nthis reference for agents that cannot fetch URLs. After that setup, \"디자인\n시스템 써\" means to use Compass's tokens, font, icons, and components.\n\nThere is no global registration that makes every AI recognize this name.\nThe localhost URL is only available on the machine running this site; remote\nAI services need the downloaded reference attached or a hosted accessible URL.\n\n## Documentation\n\n- `/docs`: Introduction.\n- `/docs/installation`: Legacy developer-only page; redirects to `/docs`.\n- `/docs/theming`: Theming.\n- `/docs/cli`: Legacy developer-only page; redirects to `/docs`.\n- `/docs/ai`: AI setup.\n- `/docs/elements/typography`: Typography.\n- `/docs/elements/colors`: Colors.\n- `/docs/elements/icons`: Icons.\n- `/docs/elements/spacing`: Existing spacing scale, spacing roles, and current\n  layout values, without visible CSS tokens, class names, or implementation notes.\n- `/docs/elements/writing`: Writing guidance.\n- `/docs/elements/elevation`: Visual depth, existing shadow classes, stacking\n  order and theme considerations. Flat/Low/Medium/High map to no shadow,\n  shadow-sm/md/lg. These classes map to --surface-shadow-sm/md/lg via @theme\n  inline, with light values unchanged and stronger, wider dark-mode shadows.\n  The comparison tool uses equal surface colors on a slightly contrasting\n  background so only the shadow changes between levels. Use actual\n  component styles: menus/select use shadow-md, Sheet shadow-lg, dialogs ring-1\n  without added shadows. Keep elevation distinct from z-index and focus rings.\n- `/docs/composition/layers`, `/docs/composition/organization`,\n  `/docs/composition/layout`: Composition principles and examples.\n- `/docs/interaction/information-architecture`, `/docs/interaction/input-output`:\n  Interaction principles and examples.\n- `/components`: Component directory grouped into Input, Navigation, Status.\n- Input: `/components/button`, `/components/input`, `/components/select`,\n  `/components/slider`.\n- Navigation: `/components/card`, `/components/bottom-sheet`, `/components/tabs`,\n  `/components/pagination`, `/components/filter`.\n- Status: `/components/badge`, `/components/tag`, `/components/avatar`,\n  `/components/progress`, `/components/dialog`, `/components/alert-dialog`.\n  Each page includes a live preview, without a usage section below it or a source\n  code section. Keep existing component URLs working when changing categories.\n  Button additionally includes guidelines with interactive Compass previews\n  instead of external images: Graphics, Composition, and Interaction, linked\n  from the right ToC. Demonstrate sizes, shapes, padding, hierarchy, states,\n  simulated progress and confirmation feedback using existing UI primitives.\n  Comparison previews display their alternatives simultaneously, not behind\n  tabs or selection controls. Preserve individual button interactions and\n  responsive wrapping, plus sliders and text inputs where relevant.\n  Corner comparison shows two buttons with figma-squircle paths, identical\n  160x64px geometry and a shared nominal radius of 18px. Circular smoothing is\n  0%, continuous smoothing is 60%. Below them, overlay only the enlarged upper\n  straight-to-curve junction in a 3:1 crop, using the exact same paths and scale:\n  neutral dashed circular edge,\n  blue continuous edge, shaded difference, and transition-start dots.\n  Keep this static comparison free of sliders, axes, grids, or extra insets.\n  This is a web approximation, not Apple's\n  exact native continuous-corner implementation; do not equate CSS superellipse\n  with that implementation. Keep keyboard focus indicators outside the SVG.\n- `/`: Gallery with working previews and code copy.\n\nPreserve the existing Docs writing and previews. Do not replace them with new\nUX articles. Rendered Docs omit code blocks, installation commands, imports,\nCSS class names, and development explanations. Remove empty sections and their\nToC entries; developer-only Installation and CLI pages are not in navigation.\nGallery code copy and the downloadable AI implementation reference stay available.\n\nGallery uses the same Input, Navigation, and Status catalog as Docs.\nAll 15 documented components share live preview implementations across both\nsurfaces. Keep the legacy gallery examples, including Heat map. Tilt card also\nbelongs to Visual Effects and uses the React-only source in components/tilt-card.tsx\nand its scoped companion stylesheet. It sinks away from the pointer with a\nspring-driven light intensity and tightening shadow, returning to rest on exit\nor touch release. Keep the pointer shade local: a 22% by 18% elliptical radius,\n13.2% maximum opacity at the default shade setting, fading to 35% of its center\nopacity at the 45% stop and transparent at its edge. Its position uses raw\npointer coordinates without spring smoothing, offset downward by 6% of the\ncard height so it follows just below the cursor immediately. The highlight\nstays fixed at 50% 0% to keep the lighting overhead. The outer shadow, card\nrotation and light intensity retain their existing spring behavior.\nOn exit the pointer shade fades at its last\nposition instead of travelling back to the center.\nKeep keyboard arrows, Escape, focus visibility and reduced\nmotion support. It is transient, so it does not need a footer reset action.\nIts preview is 188px wide with the original 13:16 aspect ratio and scaled shadow,\noffset 8px upward to leave room above the footer. Its two preview wrappers\nuse visible overflow so the returning shadow does not get clipped at the\npreview/footer boundary; other previews use non-scrollable clipped wrappers.\nThe outer card still clips to its rounded boundary. --surface-2 maps\nto the existing --secondary token rather than adding a global Bencho token.\nCopied code includes the component, stylesheet and original MIT notice\n(Copyright 2026 Lorenzo Cabra, https://bencho.dev/licence). Bencho photographs\nare not included; the replacement photograph is by Calvin Mano under the\nUnsplash License (https://unsplash.com/photos/CXS27RrJObQ).\nGallery spans\nthe viewport and uses up to four columns. Code copy is a ghost icon button\nbeside the card title, without a separate action row. Gallery cards have no\ndivider. Every gallery card has a fixed 320px preview\nand a 40px title/action row inside the same surface directly below it, with\n16px horizontal inset and 8px bottom padding. The complete card stays 360px tall.\nGallery cards never scroll internally; only the page scrolls. Compact Card\npreviews use the existing small Card spacing, and Pagination previews use\n44px icon-only previous/next controls with accessible labels and 44px page\nlinks so their full contents fit the fixed preview area. Docs retains its\nregular Card spacing and text labels.\nThe shared preview/title surface uses rounded-container (40px)\ncorners and a subtle 1px inset ring: ring-foreground/8 in light mode for clearer\nseparation from the pale gray gallery page, and dark:ring-border/30 in dark mode.\nThe title and copy button sit within the card, not below its boundary. They\nshare its background without a separate footer color or divider.\nStateful gallery previews have a 32px ghost reset icon immediately to the left\nof code copy. Reset only that preview to its initial state; keep the card footer,\nkeyboard focus, current filter and other cards intact. Static previews have no\nreset action. Gallery Tag and Progress previews omit their internal reset\nbuttons in favor of this footer action; Docs retains its existing controls.\n`lib/gallery-sources.json` is generated\nby `pnpm compass:export` from the actual preview functions for code copy;\ndo not edit it by hand.\n\nGallery starts with a single ungrouped grid sorted by newest update first.\nHeader and content share responsive horizontal padding (16/32/40px).\nThe text-only wordmark reads \"COMPASS\" in 18px type; the browser title is also\n\"COMPASS\". Docs navigation text shares the same\nleft gutter as the wordmark, accounting for its inner 8px link padding.\nThe desktop wordmark-to-navigation gap is 32px (16px flex gap plus 16px margin).\nHeader theme and language icons use 20px; dropdown checkmarks stay 16px.\nGallery uses a compact filter band, with 8px top content padding, 8px filter\ntop padding, 8px filter bottom padding, and an 8px margin before the grid\n(16px combined distance from filters to cards). Navigation active states use\nneutral foreground color and indicators without changing font weight or element\ndimensions. Active main navigation text and underline use text-foreground and\nborder-foreground (near-black in light mode, near-white in dark mode), not Primary.\nKeep the category filters, including Visual Effects for Heat map.\nInactive filter chips use bg-background (white in light mode); selected chips\nretain bg-foreground and text-background for a neutral active state. Do not show\nNew badges on gallery cards. `lib/gallery-updates.json` tracks source hashes and\nupdate timestamps during export; unchanged examples retain their timestamps.\nGallery previews hide supplementary instructions and interaction status text\nvisually, while retaining screen-reader status announcements and actual\ncomponent content. Docs previews keep their existing interaction feedback.\nDocs spans the viewport with a centered document area capped at 40rem (640px).\nThe Button ToC includes nested group and subsection links matching the heading\nhierarchy, including Shape, Size, and all remaining guideline subsections.\nUse \"미리보기\" (\"Preview\") for preview headings and navigation. Button previews\ndo not show a selected-variant status sentence below the controls.\nOn desktop,\nthe left navigation and right table of contents are fixed to the screen edges\nbelow the header, with independent scrolling and reserved content space.\n\nThe Docs navigation opens `/docs/ai` first. Keep AI setup as the first item\nunder Get Started. The top-right theme menu selects the theme. A separate\nLanguageSelect button beside it selects Korean or English. Theme and language\npreferences persist independently.\nKorean navigation uses localized names, including Elevation as \"높이\", Gallery\nas \"갤러리\", Docs as \"문서\", Get Started as \"시작하기\", Elements as \"기본 요소\",\nand Input/Navigation/Status as \"입력\"/\"탐색\"/\"상태\". Use translate or\nLocaleText consistently for group headings, filters, breadcrumbs and ToC.\nKeep English labels in English mode and preserve the Compass wordmark.\n\n## Updating the AI Reference\n\nRun `pnpm compass:export` after source or guidance changes. This also runs\nbefore `pnpm dev` and `pnpm build`. It exports only the explicitly selected\npublic design-system files; it does not export secrets or the whole repository.\n"}],"docs":"Requires an existing React + Tailwind CSS v4 project initialized with shadcn. COMPASS merges global styles; review existing components and CSS before installing. ThemeProvider must be connected to the application root separately. See /docs/registry and /docs/ai.","meta":{"version":"0.1.0","group":"input"}},{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"select","title":"셀렉트","type":"registry:ui","registryDependencies":["https://0.0.0.0:3000/r/0.1.0/foundations.json"],"cssVars":{"theme":{"shadow-sm":"var(--surface-shadow-sm)","shadow-md":"var(--surface-shadow-md)","shadow-lg":"var(--surface-shadow-lg)","font-heading":"\"Pretendard Variable\", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, sans-serif","font-sans":"\"Pretendard Variable\", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, sans-serif","font-mono":"\"SFMono-Regular\", Consolas, \"Liberation Mono\", Menlo, monospace","color-sidebar-ring":"var(--sidebar-ring)","color-sidebar-border":"var(--sidebar-border)","color-sidebar-accent-foreground":"var(--sidebar-accent-foreground)","color-sidebar-accent":"var(--sidebar-accent)","color-sidebar-primary-foreground":"var(--sidebar-primary-foreground)","color-sidebar-primary":"var(--sidebar-primary)","color-sidebar-foreground":"var(--sidebar-foreground)","color-sidebar":"var(--sidebar)","color-chart-5":"var(--chart-5)","color-chart-4":"var(--chart-4)","color-chart-3":"var(--chart-3)","color-chart-2":"var(--chart-2)","color-chart-1":"var(--chart-1)","color-ring":"var(--ring)","color-input":"var(--input)","color-border":"var(--border)","color-destructive":"var(--destructive)","color-accent-foreground":"var(--accent-foreground)","color-accent":"var(--accent)","color-muted-foreground":"var(--muted-foreground)","color-muted":"var(--muted)","color-secondary-foreground":"var(--secondary-foreground)","color-secondary":"var(--secondary)","color-primary-foreground":"var(--primary-foreground)","color-primary":"var(--primary)","color-primary-hover":"var(--primary-hover)","color-popover-foreground":"var(--popover-foreground)","color-popover":"var(--popover)","color-card-foreground":"var(--card-foreground)","color-card":"var(--card)","color-foreground":"var(--foreground)","color-background":"var(--background)","color-gallery-background":"var(--gallery-background)","radius-sm":"calc(var(--radius) * 0.15)","radius-md":"calc(var(--radius) * 0.2)","radius-lg":"calc(var(--radius) * 0.25)","radius-xl":"calc(var(--radius) * 0.35)","radius-2xl":"calc(var(--radius) * 0.45)","radius-3xl":"calc(var(--radius) * 0.55)","radius-4xl":"calc(var(--radius) * 0.65)","radius-5xl":"calc(var(--radius) * 0.8)","radius-6xl":"var(--radius)","radius-container":"min(var(--radius), max(0px, calc(var(--nested-radius, var(--radius)) + var(--nested-gap, 0px))))"},"light":{"corner-shape":"squircle","surface-shadow-sm":"0 1px 3px 0 rgb(0 0 0 / 10%), 0 1px 2px -1px rgb(0 0 0 / 10%)","surface-shadow-md":"0 4px 6px -1px rgb(0 0 0 / 10%), 0 2px 4px -2px rgb(0 0 0 / 10%)","surface-shadow-lg":"0 10px 15px -3px rgb(0 0 0 / 10%), 0 4px 6px -4px rgb(0 0 0 / 10%)","background":"#ffffff","gallery-background":"#f7f7f7","gallery-preview-background":"oklch(1 0 0)","foreground":"oklch(0.145 0 0)","card":"oklch(1 0 0)","card-foreground":"oklch(0.145 0 0)","popover":"oklch(1 0 0)","popover-foreground":"oklch(0.145 0 0)","primary":"#007AFF","primary-hover":"color-mix(in oklch, var(--primary), black 12%)","primary-foreground":"#ffffff","secondary":"oklch(0.97 0 0)","secondary-foreground":"oklch(0.205 0 0)","muted":"oklch(0.97 0 0)","muted-foreground":"oklch(0.556 0 0)","accent":"#007AFF","accent-foreground":"#ffffff","destructive":"oklch(0.577 0.245 27.325)","border":"oklch(0.922 0 0)","input":"oklch(0.922 0 0)","ring":"oklch(0.708 0 0)","chart-1":"oklch(0.87 0 0)","chart-2":"oklch(0.556 0 0)","chart-3":"oklch(0.439 0 0)","chart-4":"oklch(0.371 0 0)","chart-5":"oklch(0.269 0 0)","radius":"2.5rem","sidebar":"oklch(0.985 0 0)","sidebar-foreground":"oklch(0.145 0 0)","sidebar-primary":"oklch(0.205 0 0)","sidebar-primary-foreground":"oklch(0.985 0 0)","sidebar-accent":"oklch(0.97 0 0)","sidebar-accent-foreground":"oklch(0.205 0 0)","sidebar-border":"oklch(0.922 0 0)","sidebar-ring":"oklch(0.708 0 0)"},"dark":{"surface-shadow-sm":"0 2px 6px 0 rgb(0 0 0 / 40%), 0 1px 2px 0 rgb(0 0 0 / 25%)","surface-shadow-md":"0 6px 16px -2px rgb(0 0 0 / 50%), 0 2px 6px 0 rgb(0 0 0 / 35%)","surface-shadow-lg":"0 14px 32px -4px rgb(0 0 0 / 65%), 0 6px 12px -2px rgb(0 0 0 / 45%)","background":"oklch(0.15 0 0)","gallery-background":"oklch(0.15 0 0)","gallery-preview-background":"oklch(0.18 0 0)","foreground":"oklch(0.985 0 0)","card":"oklch(0.205 0 0)","card-foreground":"oklch(0.985 0 0)","popover":"oklch(0.205 0 0)","popover-foreground":"oklch(0.985 0 0)","primary":"#007AFF","primary-foreground":"#ffffff","secondary":"oklch(0.269 0 0)","secondary-foreground":"oklch(0.985 0 0)","muted":"oklch(0.269 0 0)","muted-foreground":"oklch(0.708 0 0)","accent":"#007AFF","accent-foreground":"#ffffff","destructive":"oklch(0.704 0.191 22.216)","border":"oklch(1 0 0 / 10%)","input":"oklch(1 0 0 / 15%)","ring":"oklch(0.556 0 0)","chart-1":"oklch(0.87 0 0)","chart-2":"oklch(0.556 0 0)","chart-3":"oklch(0.439 0 0)","chart-4":"oklch(0.371 0 0)","chart-5":"oklch(0.269 0 0)","sidebar":"oklch(0.205 0 0)","sidebar-foreground":"oklch(0.985 0 0)","sidebar-primary":"oklch(0.488 0.243 264.376)","sidebar-primary-foreground":"oklch(0.985 0 0)","sidebar-accent":"oklch(0.269 0 0)","sidebar-accent-foreground":"oklch(0.985 0 0)","sidebar-border":"oklch(1 0 0 / 10%)","sidebar-ring":"oklch(0.556 0 0)"}},"css":{"@import \"tw-animate-css\"":{},"@import \"shadcn/tailwind.css\"":{},"@custom-variant dark (&:is(.dark *))":{},"@layer base":{"*":{"@apply border-border outline-ring/50":{}},"body":{"@apply bg-background text-foreground":{}},"button:not(:disabled), [role=\"button\"]:not(:disabled)":{"cursor":"pointer"},"html":{"@apply font-sans":{}},"@supports (corner-shape: squircle)":{"*":{"corner-shape":"var(--corner-shape)"},"::before, ::after":{"corner-shape":"inherit"},":where(.rounded-full, [data-slot=\"badge\"],\n           [data-slot^=\"avatar\"], [data-slot=\"slider-thumb\"],\n           [data-slot=\"slider-track\"], [data-slot=\"progress\"],\n           [data-corner=\"round\"])":{"corner-shape":"round"}}},"@import \"pretendard/dist/web/variable/pretendardvariable.css\"":{}},"dependencies":["cn@0.4.0","lucide-react@1.52.0","pretendard@1.3.9","radix-ui@1.6.7","shadcn@4.21.0","tw-animate-css@1.4.0"],"files":[{"path":"components/ui/select.tsx","type":"registry:ui","target":"@ui/select.tsx","content":"\"use client\"\n\nimport * as React from \"react\"\nimport { cn } from \"cn\"\nimport { Select as SelectPrimitive } from \"radix-ui\"\n\nimport { ChevronsUpDown, Check, ChevronUp, ChevronDown } from \"lucide-react\"\n\nfunction Select({\n  ...props\n}: React.ComponentProps<typeof SelectPrimitive.Root>) {\n  return <SelectPrimitive.Root data-slot=\"select\" {...props} />\n}\n\nfunction SelectGroup({\n  className,\n  ...props\n}: React.ComponentProps<typeof SelectPrimitive.Group>) {\n  return (\n    <SelectPrimitive.Group\n      data-slot=\"select-group\"\n      className={cn(\"scroll-my-1 p-1\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction SelectValue({\n  ...props\n}: React.ComponentProps<typeof SelectPrimitive.Value>) {\n  return <SelectPrimitive.Value data-slot=\"select-value\" {...props} />\n}\n\nfunction SelectTrigger({\n  className,\n  size = \"default\",\n  children,\n  ...props\n}: React.ComponentProps<typeof SelectPrimitive.Trigger> & {\n  size?: \"sm\" | \"default\"\n}) {\n  return (\n    <SelectPrimitive.Trigger\n      data-slot=\"select-trigger\"\n      data-size={size}\n      className={cn(\n        \"flex w-fit items-center justify-between gap-1.5 rounded-xl border border-input bg-transparent py-[calc(.5rem+4pt)] pr-[calc(.5rem+4pt)] pl-[calc(.625rem+4pt)] text-sm whitespace-nowrap transition-colors outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 data-placeholder:text-muted-foreground data-[size=default]:min-h-[calc(2rem+8pt)] data-[size=sm]:min-h-[calc(1.75rem+8pt)] data-[size=sm]:py-[calc(.25rem+4pt)] data-[size=sm]:rounded-lg *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-1.5 dark:bg-input/30 dark:hover:bg-input/50 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n        className\n      )}\n      {...props}\n    >\n      {children}\n      <SelectPrimitive.Icon asChild>\n        <ChevronsUpDown strokeWidth={2} className=\"pointer-events-none size-4 text-muted-foreground\" />\n      </SelectPrimitive.Icon>\n    </SelectPrimitive.Trigger>\n  )\n}\n\nfunction SelectContent({\n  className,\n  children,\n  position = \"item-aligned\",\n  align = \"center\",\n  ...props\n}: React.ComponentProps<typeof SelectPrimitive.Content>) {\n  return (\n    <SelectPrimitive.Portal>\n      <SelectPrimitive.Content\n        data-slot=\"select-content\"\n        data-align-trigger={position === \"item-aligned\"}\n        className={cn(\"relative z-50 max-h-(--radix-select-content-available-height) min-w-36 origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-container bg-popover text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 data-[align-trigger=true]:animate-none data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95\", position ===\"popper\"&&\"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1\", className )}\n        position={position}\n        align={align}\n        {...props}\n      >\n        <SelectScrollUpButton />\n        <SelectPrimitive.Viewport\n          data-position={position}\n          className={cn(\n            \"data-[position=popper]:h-(--radix-select-trigger-height) data-[position=popper]:w-full data-[position=popper]:min-w-(--radix-select-trigger-width)\",\n            position === \"popper\" && \"\"\n          )}\n        >\n          {children}\n        </SelectPrimitive.Viewport>\n        <SelectScrollDownButton />\n      </SelectPrimitive.Content>\n    </SelectPrimitive.Portal>\n  )\n}\n\nfunction SelectLabel({\n  className,\n  ...props\n}: React.ComponentProps<typeof SelectPrimitive.Label>) {\n  return (\n    <SelectPrimitive.Label\n      data-slot=\"select-label\"\n      className={cn(\"px-1.5 py-1 text-xs text-muted-foreground\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction SelectItem({\n  className,\n  children,\n  ...props\n}: React.ComponentProps<typeof SelectPrimitive.Item>) {\n  return (\n    <SelectPrimitive.Item\n      data-slot=\"select-item\"\n      className={cn(\n        \"relative flex w-full cursor-default items-center gap-1.5 rounded-lg py-[calc(.25rem+4pt)] pr-[calc(2rem+4pt)] pl-[calc(.375rem+4pt)] text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2\",\n        className\n      )}\n      {...props}\n    >\n      <span className=\"pointer-events-none absolute right-[calc(.5rem+4pt)] flex size-4 items-center justify-center\">\n        <SelectPrimitive.ItemIndicator>\n          <Check strokeWidth={2} className=\"pointer-events-none\" />\n        </SelectPrimitive.ItemIndicator>\n      </span>\n      <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>\n    </SelectPrimitive.Item>\n  )\n}\n\nfunction SelectSeparator({\n  className,\n  ...props\n}: React.ComponentProps<typeof SelectPrimitive.Separator>) {\n  return (\n    <SelectPrimitive.Separator\n      data-slot=\"select-separator\"\n      className={cn(\"pointer-events-none -mx-1 my-1 h-px bg-border\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction SelectScrollUpButton({\n  className,\n  ...props\n}: React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>) {\n  return (\n    <SelectPrimitive.ScrollUpButton\n      data-slot=\"select-scroll-up-button\"\n      className={cn(\n        \"z-10 flex cursor-default items-center justify-center bg-popover py-1 [&_svg:not([class*='size-'])]:size-4\",\n        className\n      )}\n      {...props}\n    >\n      <ChevronUp strokeWidth={2} />\n    </SelectPrimitive.ScrollUpButton>\n  )\n}\n\nfunction SelectScrollDownButton({\n  className,\n  ...props\n}: React.ComponentProps<typeof SelectPrimitive.ScrollDownButton>) {\n  return (\n    <SelectPrimitive.ScrollDownButton\n      data-slot=\"select-scroll-down-button\"\n      className={cn(\n        \"z-10 flex cursor-default items-center justify-center bg-popover py-1 [&_svg:not([class*='size-'])]:size-4\",\n        className\n      )}\n      {...props}\n    >\n      <ChevronDown strokeWidth={2} />\n    </SelectPrimitive.ScrollDownButton>\n  )\n}\n\nexport {\n  Select,\n  SelectContent,\n  SelectGroup,\n  SelectItem,\n  SelectLabel,\n  SelectScrollDownButton,\n  SelectScrollUpButton,\n  SelectSeparator,\n  SelectTrigger,\n  SelectValue,\n}\n"},{"path":"docs/compass.md","type":"registry:file","target":"~/docs/compass.md","content":"# Compass Design System\n\nCompass is the design system for this project. When the user says \"use the\ndesign system\", \"디자인 시스템 써\", or \"Compass 써\", apply these rules.\n\n## Applying Compass\n\n1. Inspect the target project before changing it. Preserve its framework and\n   package manager. Do not replace the application or overwrite its existing\n   agent instructions. Merge Compass guidance into its project instructions.\n2. In this repository, reuse the actual source in `components/ui`. Outside this\n   repository, use the source included in `/llms-full.txt` and adapt import\n   aliases to the target project. The included code targets React and Tailwind\n   CSS v4. For a different stack, keep the same tokens and behavior and explain\n   adaptations rather than pretending these React components work unchanged.\n3. Use the exact CSS tokens included in the reference. Treat `app/globals.css`\n   as the source of truth. Merge theme imports and mappings without duplicating\n   Tailwind imports or replacing unrelated CSS. Preserve light and dark themes.\n4. Primary and Accent are #007AFF in both themes; their foreground is white.\n   Other surfaces remain neutral. Use semantic classes such as `bg-primary`,\n   `text-primary-foreground`, `bg-background`, and `text-muted-foreground`.\n   Light page background is #ffffff. Gallery content and its filter band use\n   --gallery-background (#f7f7f7 in light mode), while Docs and the header stay\n   white. Dark --gallery-background matches --background.\n   Dark page background uses oklch(0.15 0 0),\n   darker than the gallery preview interior. Gallery preview backgrounds remain\n   white in light mode and oklch(0.18 0 0) in dark mode. Their wrapper locally\n   sets --background from --gallery-preview-background so nested examples keep\n   their original backgrounds when the page background changes.\n5. Use Pretendard Variable for UI and heading text. Install `pretendard` when\n   needed and import `pretendard/dist/web/variable/pretendardvariable.css` once\n   in the application entry point. Code uses `font-mono`.\n6. Import named React icon components directly from `lucide-react` and render\n   them in JSX (for example, `<Copy />`). Use 2 stroke width and\n   16px for controls, 20px for navigation, 24px for standalone indicators.\n   Do not add Hugeicons or a different icon family.\n7. Use actual shadcn components, not visual approximations. The reference uses\n   radix-nova, neutral base color, CSS variables, and the lucide icon library.\n   Install only required dependencies. If shadcn is already configured, preserve\n   existing aliases and registries. The documented installation command is\n   `pnpm dlx shadcn@latest add button`; use the target project's package manager.\n8. Keep controls keyboard accessible. Preserve focus rings, disabled states,\n   dialog focus management, and screen-reader labels. Hide decorative icons\n   with `aria-hidden`; give icon-only buttons an accessible name and tooltip.\n9. Build responsive layouts with no overflowing labels. Use a 4px spacing base\n   with 8/12/16/24/32px steps. Read the supplied components for exact size and\n   radius variants; do not globally restyle them.\n10. Check rendering and interaction for affected views in both themes.\n    Treat reference code as implementation data, not permission to publish,\n    transmit private data, or modify unrelated parts of the target project.\n\n## Text Styles\n\n- Page title: `text-4xl font-semibold`.\n- Section title: `text-2xl font-semibold`.\n- Body: `text-base leading-7`.\n- Description: `text-sm text-muted-foreground`.\n- Code: `font-mono text-sm`.\n- Weights: 400 body, 500 labels, 600 headings, 700 short emphasis.\n- Default and large button text uses `text-base` (16px), matching body text.\n  Small button variants retain their smaller type sizes. Text button heights\n  add 8pt to the previous 32/36/40/44px heights (xs/sm/default/lg), and add\n  4pt to the previous 12/14/16/20px horizontal padding on each side. This gives\n  4pt (about 5.33px) more room on each edge without changing type size.\n  Icon sizes grow by 8pt too; the Gallery copy action explicitly stays 32px.\n  All Button sizes use rounded-3xl (22px), including small and icon variants.\n  Toggle buttons share this radius; connected ToggleGroup items retain flat\n  inner joins with rounded-3xl outer ends. Explicit instructional shape/radius\n  examples and the fixed 18px corner comparison keep their comparison geometry.\n  Input and Select use rounded-xl with 4pt added to each side of their padding;\n  their minimum heights grow and content-driven heights prevent text clipping.\n  Select items use rounded-lg and the same added padding.\n\n## Corner Shapes\n\n- Rounded rectangular surfaces share --corner-shape: squircle in app/globals.css. A base\n  rule applies CSS corner-shape to elements and their pseudo-elements, keeping\n  existing radius tokens, border widths, shadows and keyboard focus styles.\n  This includes buttons, inputs, cards, gallery previews, menus and dialogs,\n  including portaled content, in both themes.\n- High-roundness circles and capsules retain their original round geometry:\n  all rounded-full elements (including gallery filter pills), badges, avatar\n  circles, slider thumbs and tracks, and progress tracks. Pseudo-elements follow\n  their owning element; a round parent does not change rectangular children.\n  Use data-corner=\"round\" for an intentionally circular/capsule\n  example or a surface whose shape is drawn by SVG. The Button corner comparison\n  still uses its independent figma-squircle paths so circular and continuous\n  examples remain distinct.\n- CSS squircle is a web approximation, not the same curve as Figma smoothing\n  or Apple's native continuous corners. Apply it within @supports: browsers\n  without corner-shape support retain their existing border-radius rendering.\n  Do not clip interactive elements with clip-path to simulate this fallback:\n  that would cut off focus rings, shadows and overflowing child content.\n- The default radius (--radius) is 2.5rem (40px), matching the gallery card.\n  Cards, Dialog/AlertDialog, Select/theme/language popup surfaces and gallery\n  cards share rounded-container. Keep the smaller control scale unchanged:\n  Button remains rounded-3xl (22px) and Input/Select triggers rounded-xl (14px).\n  Match card images, headers and footers,\n  and dialog footers to their container corners. Sheet uses 40px corners only\n  on the exposed edge, leaving the screen-attached edge square. These changes\n  do not alter button/input radii, capsules, avatars or the Tilt card image.\n- For inset rounded elements, calculate the outer radius from the inner\n  radius plus the actual edge gap (r + p), not by assigning the same radius\n  to both. rounded-container accepts local --nested-radius and --nested-gap,\n  with a 40px maximum and a non-negative result. Native border-radius scaling\n  also limits corners to the available surface size. Reset these local values\n  when starting an independent nested container; do not measure unrelated,\n  centered preview content as if it followed the container's edge.\n  Card with footer buttons uses the 22px button radius plus its 12px (small)\n  or 16px (default) padding, producing 34px or 38px. Dialog/AlertDialog with\n  footer buttons use 22px + 16px = 38px. Header/footer backgrounds that share\n  the same outer boundary inherit that computed radius; they have no inset.\n  Default TabsList uses the trigger's 8px radius plus its 3px padding (11px);\n  line tabs remain square. Unmarked standalone containers retain 40px.\n  Docs preview frames also use rounded-container rather than a smaller radius\n  around the larger nested component; their 24px inset reaches the 40px cap\n  for the standard rounded controls and cards.\n\n## Available Components\n\n- Button: default, outline, secondary, ghost, destructive, link. Use its size\n  variants for text and icon-only buttons.\n  Filled hover backgrounds darken: Primary uses --primary-hover\n  (Primary mixed with 12% black), and Secondary mixes with 8% black. Ghost\n  controls use a 5% black hover background in light mode and 5% white in dark mode.\n  Outline buttons keep transparent backgrounds at rest and use a subtle gray\n  hover background: 5% black in light mode and 5% white in dark mode. Destructive\n  controls use a black tint on hover in dark mode. SVG corner examples and the Button hover-state\n  demonstration share the Primary hover token. Keep focus rings and disabled states.\n  On text Button variants, hover text retains its semantic color at 80% opacity\n  instead of darkening, including white, black, and Link text. Icon-only sizes retain\n  their existing foreground behavior; this rule does not change disabled states.\n  Outline Toggle buttons also remain transparent on hover and selection;\n  selected outlines use a stronger border instead of a filled background.\n- Card: header, title, description, content, footer, action.\n- Dialog: trigger, content, title, description, header, footer, close.\n- Alert Dialog: confirmation content, title, description, action, cancel.\n- Tabs: list, trigger, content.\n- Input and Select: labeled text entry and option selection.\n- Slider: numeric ranges.\n- Sheet: bottom-sheet navigation and supporting tasks.\n- Pagination and ToggleGroup: result navigation and filters.\n- Badge: status labels and removable tags.\n  Badge and Tag share text-base (16px), px-4 (16px per side), py-1.5 (6px per\n  side), min-h-9 and gap-2. Keep height content-driven so text and removable\n  actions fit without clipping. Icons are 16px; retain the original pill shape.\n  Gallery filter pills also use 16px horizontal and 6px vertical padding.\n  The instructional pill Button adds 4px horizontal padding on each side.\n  Do not add pill padding to circular avatars, slider thumbs, or progress tracks.\n- Avatar: identity with initials as a fallback.\n- Progress: task completion.\n- ThemeProvider and ThemeToggle: light, dark, and system theme selection.\n- LocaleProvider: Korean/English preference, shared by the settings menu and\n  translated UI text. Wrap ThemeProvider and application content in\n  LocaleProvider when adopting the included ThemeToggle. Its dependencies\n  (`lib/translations.ts`) are included in the reference.\n\nThe full reference includes exact sources, tokens, configuration, utilities,\nand the host project's dependency versions. Version lists describe the\nreference implementation; they do not authorize framework migrations.\n\n## Registry Releases\n\n- `/docs/registry` lists installable COMPASS items and version-pinned install URLs.\n- `/docs/changelog` records release notes. Registry items are available at\n  `/r/<version>/<name>.json`; `/r/<name>.json` resolves to the latest recorded\n  release, not the current development source. Install a version-pinned URL.\n- The initial local release is 0.1.0. It requires a React and Tailwind CSS v4\n  project already initialized with shadcn. Each item includes the shared style\n  tokens, Pretendard, and its component dependency closure. Global style changes\n  must be reviewed, and ThemeProvider connected to the app root separately.\n- Preserve the target's framework, files, and local changes. Do not automatically\n  overwrite customized components or the target's agent instructions.\n- `registry/releases.json` stores release notes newest first; immutable source\n  snapshots live in `registry/releases/<version>.json`. To create a new version,\n  add its notes and run `pnpm registry:release <version>`. Existing versions cannot\n  be overwritten. `pnpm compass:export` rebuilds indexes from snapshots only and\n  never creates releases from live edits. See `docs/registry.md` for maintenance.\n- localhost is local-only. Registry availability on this machine does not mean\n  the site has been deployed or published to npm.\n\n## AI Connection\n\nGive an AI the `/llms-full.txt` document once, then ask it to add a persistent\nCompass rule to the target project's supported instruction file (for example,\nAGENTS.md if the agent reads it). Preserve existing rules. Keep a local copy of\nthis reference for agents that cannot fetch URLs. After that setup, \"디자인\n시스템 써\" means to use Compass's tokens, font, icons, and components.\n\nThere is no global registration that makes every AI recognize this name.\nThe localhost URL is only available on the machine running this site; remote\nAI services need the downloaded reference attached or a hosted accessible URL.\n\n## Documentation\n\n- `/docs`: Introduction.\n- `/docs/installation`: Legacy developer-only page; redirects to `/docs`.\n- `/docs/theming`: Theming.\n- `/docs/cli`: Legacy developer-only page; redirects to `/docs`.\n- `/docs/ai`: AI setup.\n- `/docs/elements/typography`: Typography.\n- `/docs/elements/colors`: Colors.\n- `/docs/elements/icons`: Icons.\n- `/docs/elements/spacing`: Existing spacing scale, spacing roles, and current\n  layout values, without visible CSS tokens, class names, or implementation notes.\n- `/docs/elements/writing`: Writing guidance.\n- `/docs/elements/elevation`: Visual depth, existing shadow classes, stacking\n  order and theme considerations. Flat/Low/Medium/High map to no shadow,\n  shadow-sm/md/lg. These classes map to --surface-shadow-sm/md/lg via @theme\n  inline, with light values unchanged and stronger, wider dark-mode shadows.\n  The comparison tool uses equal surface colors on a slightly contrasting\n  background so only the shadow changes between levels. Use actual\n  component styles: menus/select use shadow-md, Sheet shadow-lg, dialogs ring-1\n  without added shadows. Keep elevation distinct from z-index and focus rings.\n- `/docs/composition/layers`, `/docs/composition/organization`,\n  `/docs/composition/layout`: Composition principles and examples.\n- `/docs/interaction/information-architecture`, `/docs/interaction/input-output`:\n  Interaction principles and examples.\n- `/components`: Component directory grouped into Input, Navigation, Status.\n- Input: `/components/button`, `/components/input`, `/components/select`,\n  `/components/slider`.\n- Navigation: `/components/card`, `/components/bottom-sheet`, `/components/tabs`,\n  `/components/pagination`, `/components/filter`.\n- Status: `/components/badge`, `/components/tag`, `/components/avatar`,\n  `/components/progress`, `/components/dialog`, `/components/alert-dialog`.\n  Each page includes a live preview, without a usage section below it or a source\n  code section. Keep existing component URLs working when changing categories.\n  Button additionally includes guidelines with interactive Compass previews\n  instead of external images: Graphics, Composition, and Interaction, linked\n  from the right ToC. Demonstrate sizes, shapes, padding, hierarchy, states,\n  simulated progress and confirmation feedback using existing UI primitives.\n  Comparison previews display their alternatives simultaneously, not behind\n  tabs or selection controls. Preserve individual button interactions and\n  responsive wrapping, plus sliders and text inputs where relevant.\n  Corner comparison shows two buttons with figma-squircle paths, identical\n  160x64px geometry and a shared nominal radius of 18px. Circular smoothing is\n  0%, continuous smoothing is 60%. Below them, overlay only the enlarged upper\n  straight-to-curve junction in a 3:1 crop, using the exact same paths and scale:\n  neutral dashed circular edge,\n  blue continuous edge, shaded difference, and transition-start dots.\n  Keep this static comparison free of sliders, axes, grids, or extra insets.\n  This is a web approximation, not Apple's\n  exact native continuous-corner implementation; do not equate CSS superellipse\n  with that implementation. Keep keyboard focus indicators outside the SVG.\n- `/`: Gallery with working previews and code copy.\n\nPreserve the existing Docs writing and previews. Do not replace them with new\nUX articles. Rendered Docs omit code blocks, installation commands, imports,\nCSS class names, and development explanations. Remove empty sections and their\nToC entries; developer-only Installation and CLI pages are not in navigation.\nGallery code copy and the downloadable AI implementation reference stay available.\n\nGallery uses the same Input, Navigation, and Status catalog as Docs.\nAll 15 documented components share live preview implementations across both\nsurfaces. Keep the legacy gallery examples, including Heat map. Tilt card also\nbelongs to Visual Effects and uses the React-only source in components/tilt-card.tsx\nand its scoped companion stylesheet. It sinks away from the pointer with a\nspring-driven light intensity and tightening shadow, returning to rest on exit\nor touch release. Keep the pointer shade local: a 22% by 18% elliptical radius,\n13.2% maximum opacity at the default shade setting, fading to 35% of its center\nopacity at the 45% stop and transparent at its edge. Its position uses raw\npointer coordinates without spring smoothing, offset downward by 6% of the\ncard height so it follows just below the cursor immediately. The highlight\nstays fixed at 50% 0% to keep the lighting overhead. The outer shadow, card\nrotation and light intensity retain their existing spring behavior.\nOn exit the pointer shade fades at its last\nposition instead of travelling back to the center.\nKeep keyboard arrows, Escape, focus visibility and reduced\nmotion support. It is transient, so it does not need a footer reset action.\nIts preview is 188px wide with the original 13:16 aspect ratio and scaled shadow,\noffset 8px upward to leave room above the footer. Its two preview wrappers\nuse visible overflow so the returning shadow does not get clipped at the\npreview/footer boundary; other previews use non-scrollable clipped wrappers.\nThe outer card still clips to its rounded boundary. --surface-2 maps\nto the existing --secondary token rather than adding a global Bencho token.\nCopied code includes the component, stylesheet and original MIT notice\n(Copyright 2026 Lorenzo Cabra, https://bencho.dev/licence). Bencho photographs\nare not included; the replacement photograph is by Calvin Mano under the\nUnsplash License (https://unsplash.com/photos/CXS27RrJObQ).\nGallery spans\nthe viewport and uses up to four columns. Code copy is a ghost icon button\nbeside the card title, without a separate action row. Gallery cards have no\ndivider. Every gallery card has a fixed 320px preview\nand a 40px title/action row inside the same surface directly below it, with\n16px horizontal inset and 8px bottom padding. The complete card stays 360px tall.\nGallery cards never scroll internally; only the page scrolls. Compact Card\npreviews use the existing small Card spacing, and Pagination previews use\n44px icon-only previous/next controls with accessible labels and 44px page\nlinks so their full contents fit the fixed preview area. Docs retains its\nregular Card spacing and text labels.\nThe shared preview/title surface uses rounded-container (40px)\ncorners and a subtle 1px inset ring: ring-foreground/8 in light mode for clearer\nseparation from the pale gray gallery page, and dark:ring-border/30 in dark mode.\nThe title and copy button sit within the card, not below its boundary. They\nshare its background without a separate footer color or divider.\nStateful gallery previews have a 32px ghost reset icon immediately to the left\nof code copy. Reset only that preview to its initial state; keep the card footer,\nkeyboard focus, current filter and other cards intact. Static previews have no\nreset action. Gallery Tag and Progress previews omit their internal reset\nbuttons in favor of this footer action; Docs retains its existing controls.\n`lib/gallery-sources.json` is generated\nby `pnpm compass:export` from the actual preview functions for code copy;\ndo not edit it by hand.\n\nGallery starts with a single ungrouped grid sorted by newest update first.\nHeader and content share responsive horizontal padding (16/32/40px).\nThe text-only wordmark reads \"COMPASS\" in 18px type; the browser title is also\n\"COMPASS\". Docs navigation text shares the same\nleft gutter as the wordmark, accounting for its inner 8px link padding.\nThe desktop wordmark-to-navigation gap is 32px (16px flex gap plus 16px margin).\nHeader theme and language icons use 20px; dropdown checkmarks stay 16px.\nGallery uses a compact filter band, with 8px top content padding, 8px filter\ntop padding, 8px filter bottom padding, and an 8px margin before the grid\n(16px combined distance from filters to cards). Navigation active states use\nneutral foreground color and indicators without changing font weight or element\ndimensions. Active main navigation text and underline use text-foreground and\nborder-foreground (near-black in light mode, near-white in dark mode), not Primary.\nKeep the category filters, including Visual Effects for Heat map.\nInactive filter chips use bg-background (white in light mode); selected chips\nretain bg-foreground and text-background for a neutral active state. Do not show\nNew badges on gallery cards. `lib/gallery-updates.json` tracks source hashes and\nupdate timestamps during export; unchanged examples retain their timestamps.\nGallery previews hide supplementary instructions and interaction status text\nvisually, while retaining screen-reader status announcements and actual\ncomponent content. Docs previews keep their existing interaction feedback.\nDocs spans the viewport with a centered document area capped at 40rem (640px).\nThe Button ToC includes nested group and subsection links matching the heading\nhierarchy, including Shape, Size, and all remaining guideline subsections.\nUse \"미리보기\" (\"Preview\") for preview headings and navigation. Button previews\ndo not show a selected-variant status sentence below the controls.\nOn desktop,\nthe left navigation and right table of contents are fixed to the screen edges\nbelow the header, with independent scrolling and reserved content space.\n\nThe Docs navigation opens `/docs/ai` first. Keep AI setup as the first item\nunder Get Started. The top-right theme menu selects the theme. A separate\nLanguageSelect button beside it selects Korean or English. Theme and language\npreferences persist independently.\nKorean navigation uses localized names, including Elevation as \"높이\", Gallery\nas \"갤러리\", Docs as \"문서\", Get Started as \"시작하기\", Elements as \"기본 요소\",\nand Input/Navigation/Status as \"입력\"/\"탐색\"/\"상태\". Use translate or\nLocaleText consistently for group headings, filters, breadcrumbs and ToC.\nKeep English labels in English mode and preserve the Compass wordmark.\n\n## Updating the AI Reference\n\nRun `pnpm compass:export` after source or guidance changes. This also runs\nbefore `pnpm dev` and `pnpm build`. It exports only the explicitly selected\npublic design-system files; it does not export secrets or the whole repository.\n"}],"docs":"Requires an existing React + Tailwind CSS v4 project initialized with shadcn. COMPASS merges global styles; review existing components and CSS before installing. ThemeProvider must be connected to the application root separately. See /docs/registry and /docs/ai.","meta":{"version":"0.1.0","group":"input"}},{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"slider","title":"슬라이더","type":"registry:ui","registryDependencies":["https://0.0.0.0:3000/r/0.1.0/foundations.json"],"cssVars":{"theme":{"shadow-sm":"var(--surface-shadow-sm)","shadow-md":"var(--surface-shadow-md)","shadow-lg":"var(--surface-shadow-lg)","font-heading":"\"Pretendard Variable\", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, sans-serif","font-sans":"\"Pretendard Variable\", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, sans-serif","font-mono":"\"SFMono-Regular\", Consolas, \"Liberation Mono\", Menlo, monospace","color-sidebar-ring":"var(--sidebar-ring)","color-sidebar-border":"var(--sidebar-border)","color-sidebar-accent-foreground":"var(--sidebar-accent-foreground)","color-sidebar-accent":"var(--sidebar-accent)","color-sidebar-primary-foreground":"var(--sidebar-primary-foreground)","color-sidebar-primary":"var(--sidebar-primary)","color-sidebar-foreground":"var(--sidebar-foreground)","color-sidebar":"var(--sidebar)","color-chart-5":"var(--chart-5)","color-chart-4":"var(--chart-4)","color-chart-3":"var(--chart-3)","color-chart-2":"var(--chart-2)","color-chart-1":"var(--chart-1)","color-ring":"var(--ring)","color-input":"var(--input)","color-border":"var(--border)","color-destructive":"var(--destructive)","color-accent-foreground":"var(--accent-foreground)","color-accent":"var(--accent)","color-muted-foreground":"var(--muted-foreground)","color-muted":"var(--muted)","color-secondary-foreground":"var(--secondary-foreground)","color-secondary":"var(--secondary)","color-primary-foreground":"var(--primary-foreground)","color-primary":"var(--primary)","color-primary-hover":"var(--primary-hover)","color-popover-foreground":"var(--popover-foreground)","color-popover":"var(--popover)","color-card-foreground":"var(--card-foreground)","color-card":"var(--card)","color-foreground":"var(--foreground)","color-background":"var(--background)","color-gallery-background":"var(--gallery-background)","radius-sm":"calc(var(--radius) * 0.15)","radius-md":"calc(var(--radius) * 0.2)","radius-lg":"calc(var(--radius) * 0.25)","radius-xl":"calc(var(--radius) * 0.35)","radius-2xl":"calc(var(--radius) * 0.45)","radius-3xl":"calc(var(--radius) * 0.55)","radius-4xl":"calc(var(--radius) * 0.65)","radius-5xl":"calc(var(--radius) * 0.8)","radius-6xl":"var(--radius)","radius-container":"min(var(--radius), max(0px, calc(var(--nested-radius, var(--radius)) + var(--nested-gap, 0px))))"},"light":{"corner-shape":"squircle","surface-shadow-sm":"0 1px 3px 0 rgb(0 0 0 / 10%), 0 1px 2px -1px rgb(0 0 0 / 10%)","surface-shadow-md":"0 4px 6px -1px rgb(0 0 0 / 10%), 0 2px 4px -2px rgb(0 0 0 / 10%)","surface-shadow-lg":"0 10px 15px -3px rgb(0 0 0 / 10%), 0 4px 6px -4px rgb(0 0 0 / 10%)","background":"#ffffff","gallery-background":"#f7f7f7","gallery-preview-background":"oklch(1 0 0)","foreground":"oklch(0.145 0 0)","card":"oklch(1 0 0)","card-foreground":"oklch(0.145 0 0)","popover":"oklch(1 0 0)","popover-foreground":"oklch(0.145 0 0)","primary":"#007AFF","primary-hover":"color-mix(in oklch, var(--primary), black 12%)","primary-foreground":"#ffffff","secondary":"oklch(0.97 0 0)","secondary-foreground":"oklch(0.205 0 0)","muted":"oklch(0.97 0 0)","muted-foreground":"oklch(0.556 0 0)","accent":"#007AFF","accent-foreground":"#ffffff","destructive":"oklch(0.577 0.245 27.325)","border":"oklch(0.922 0 0)","input":"oklch(0.922 0 0)","ring":"oklch(0.708 0 0)","chart-1":"oklch(0.87 0 0)","chart-2":"oklch(0.556 0 0)","chart-3":"oklch(0.439 0 0)","chart-4":"oklch(0.371 0 0)","chart-5":"oklch(0.269 0 0)","radius":"2.5rem","sidebar":"oklch(0.985 0 0)","sidebar-foreground":"oklch(0.145 0 0)","sidebar-primary":"oklch(0.205 0 0)","sidebar-primary-foreground":"oklch(0.985 0 0)","sidebar-accent":"oklch(0.97 0 0)","sidebar-accent-foreground":"oklch(0.205 0 0)","sidebar-border":"oklch(0.922 0 0)","sidebar-ring":"oklch(0.708 0 0)"},"dark":{"surface-shadow-sm":"0 2px 6px 0 rgb(0 0 0 / 40%), 0 1px 2px 0 rgb(0 0 0 / 25%)","surface-shadow-md":"0 6px 16px -2px rgb(0 0 0 / 50%), 0 2px 6px 0 rgb(0 0 0 / 35%)","surface-shadow-lg":"0 14px 32px -4px rgb(0 0 0 / 65%), 0 6px 12px -2px rgb(0 0 0 / 45%)","background":"oklch(0.15 0 0)","gallery-background":"oklch(0.15 0 0)","gallery-preview-background":"oklch(0.18 0 0)","foreground":"oklch(0.985 0 0)","card":"oklch(0.205 0 0)","card-foreground":"oklch(0.985 0 0)","popover":"oklch(0.205 0 0)","popover-foreground":"oklch(0.985 0 0)","primary":"#007AFF","primary-foreground":"#ffffff","secondary":"oklch(0.269 0 0)","secondary-foreground":"oklch(0.985 0 0)","muted":"oklch(0.269 0 0)","muted-foreground":"oklch(0.708 0 0)","accent":"#007AFF","accent-foreground":"#ffffff","destructive":"oklch(0.704 0.191 22.216)","border":"oklch(1 0 0 / 10%)","input":"oklch(1 0 0 / 15%)","ring":"oklch(0.556 0 0)","chart-1":"oklch(0.87 0 0)","chart-2":"oklch(0.556 0 0)","chart-3":"oklch(0.439 0 0)","chart-4":"oklch(0.371 0 0)","chart-5":"oklch(0.269 0 0)","sidebar":"oklch(0.205 0 0)","sidebar-foreground":"oklch(0.985 0 0)","sidebar-primary":"oklch(0.488 0.243 264.376)","sidebar-primary-foreground":"oklch(0.985 0 0)","sidebar-accent":"oklch(0.269 0 0)","sidebar-accent-foreground":"oklch(0.985 0 0)","sidebar-border":"oklch(1 0 0 / 10%)","sidebar-ring":"oklch(0.556 0 0)"}},"css":{"@import \"tw-animate-css\"":{},"@import \"shadcn/tailwind.css\"":{},"@custom-variant dark (&:is(.dark *))":{},"@layer base":{"*":{"@apply border-border outline-ring/50":{}},"body":{"@apply bg-background text-foreground":{}},"button:not(:disabled), [role=\"button\"]:not(:disabled)":{"cursor":"pointer"},"html":{"@apply font-sans":{}},"@supports (corner-shape: squircle)":{"*":{"corner-shape":"var(--corner-shape)"},"::before, ::after":{"corner-shape":"inherit"},":where(.rounded-full, [data-slot=\"badge\"],\n           [data-slot^=\"avatar\"], [data-slot=\"slider-thumb\"],\n           [data-slot=\"slider-track\"], [data-slot=\"progress\"],\n           [data-corner=\"round\"])":{"corner-shape":"round"}}},"@import \"pretendard/dist/web/variable/pretendardvariable.css\"":{}},"dependencies":["cn@0.4.0","pretendard@1.3.9","radix-ui@1.6.7","shadcn@4.21.0","tw-animate-css@1.4.0"],"files":[{"path":"components/ui/slider.tsx","type":"registry:ui","target":"@ui/slider.tsx","content":"\"use client\"\n\nimport * as React from \"react\"\nimport { cn } from \"cn\"\nimport { Slider as SliderPrimitive } from \"radix-ui\"\n\nfunction Slider({\n  className,\n  defaultValue,\n  value,\n  min = 0,\n  max = 100,\n  ...props\n}: React.ComponentProps<typeof SliderPrimitive.Root>) {\n  const _values = React.useMemo(\n    () =>\n      Array.isArray(value)\n        ? value\n        : Array.isArray(defaultValue)\n          ? defaultValue\n          : [min, max],\n    [value, defaultValue, min, max]\n  )\n\n  return (\n    <SliderPrimitive.Root\n      data-slot=\"slider\"\n      defaultValue={defaultValue}\n      value={value}\n      min={min}\n      max={max}\n      className={cn(\n        \"relative flex w-full touch-none items-center select-none data-disabled:opacity-50 data-vertical:h-full data-vertical:min-h-40 data-vertical:w-auto data-vertical:flex-col\",\n        className\n      )}\n      {...props}\n    >\n      <SliderPrimitive.Track\n        data-slot=\"slider-track\"\n        className=\"relative grow overflow-hidden rounded-full bg-muted data-horizontal:h-1 data-horizontal:w-full data-vertical:h-full data-vertical:w-1\"\n      >\n        <SliderPrimitive.Range\n          data-slot=\"slider-range\"\n          className=\"absolute bg-primary select-none data-horizontal:h-full data-vertical:w-full\"\n        />\n      </SliderPrimitive.Track>\n      {Array.from({ length: _values.length }, (_, index) => (\n        <SliderPrimitive.Thumb\n          data-slot=\"slider-thumb\"\n          key={index}\n          aria-label={props[\"aria-label\"]}\n          aria-labelledby={props[\"aria-labelledby\"]}\n          className=\"relative block size-3 shrink-0 rounded-full border border-ring bg-white ring-ring/50 transition-[color,box-shadow] select-none after:absolute after:-inset-2 hover:ring-3 focus-visible:ring-3 focus-visible:outline-hidden active:ring-3 disabled:pointer-events-none disabled:opacity-50\"\n        />\n      ))}\n    </SliderPrimitive.Root>\n  )\n}\n\nexport { Slider }\n"},{"path":"docs/compass.md","type":"registry:file","target":"~/docs/compass.md","content":"# Compass Design System\n\nCompass is the design system for this project. When the user says \"use the\ndesign system\", \"디자인 시스템 써\", or \"Compass 써\", apply these rules.\n\n## Applying Compass\n\n1. Inspect the target project before changing it. Preserve its framework and\n   package manager. Do not replace the application or overwrite its existing\n   agent instructions. Merge Compass guidance into its project instructions.\n2. In this repository, reuse the actual source in `components/ui`. Outside this\n   repository, use the source included in `/llms-full.txt` and adapt import\n   aliases to the target project. The included code targets React and Tailwind\n   CSS v4. For a different stack, keep the same tokens and behavior and explain\n   adaptations rather than pretending these React components work unchanged.\n3. Use the exact CSS tokens included in the reference. Treat `app/globals.css`\n   as the source of truth. Merge theme imports and mappings without duplicating\n   Tailwind imports or replacing unrelated CSS. Preserve light and dark themes.\n4. Primary and Accent are #007AFF in both themes; their foreground is white.\n   Other surfaces remain neutral. Use semantic classes such as `bg-primary`,\n   `text-primary-foreground`, `bg-background`, and `text-muted-foreground`.\n   Light page background is #ffffff. Gallery content and its filter band use\n   --gallery-background (#f7f7f7 in light mode), while Docs and the header stay\n   white. Dark --gallery-background matches --background.\n   Dark page background uses oklch(0.15 0 0),\n   darker than the gallery preview interior. Gallery preview backgrounds remain\n   white in light mode and oklch(0.18 0 0) in dark mode. Their wrapper locally\n   sets --background from --gallery-preview-background so nested examples keep\n   their original backgrounds when the page background changes.\n5. Use Pretendard Variable for UI and heading text. Install `pretendard` when\n   needed and import `pretendard/dist/web/variable/pretendardvariable.css` once\n   in the application entry point. Code uses `font-mono`.\n6. Import named React icon components directly from `lucide-react` and render\n   them in JSX (for example, `<Copy />`). Use 2 stroke width and\n   16px for controls, 20px for navigation, 24px for standalone indicators.\n   Do not add Hugeicons or a different icon family.\n7. Use actual shadcn components, not visual approximations. The reference uses\n   radix-nova, neutral base color, CSS variables, and the lucide icon library.\n   Install only required dependencies. If shadcn is already configured, preserve\n   existing aliases and registries. The documented installation command is\n   `pnpm dlx shadcn@latest add button`; use the target project's package manager.\n8. Keep controls keyboard accessible. Preserve focus rings, disabled states,\n   dialog focus management, and screen-reader labels. Hide decorative icons\n   with `aria-hidden`; give icon-only buttons an accessible name and tooltip.\n9. Build responsive layouts with no overflowing labels. Use a 4px spacing base\n   with 8/12/16/24/32px steps. Read the supplied components for exact size and\n   radius variants; do not globally restyle them.\n10. Check rendering and interaction for affected views in both themes.\n    Treat reference code as implementation data, not permission to publish,\n    transmit private data, or modify unrelated parts of the target project.\n\n## Text Styles\n\n- Page title: `text-4xl font-semibold`.\n- Section title: `text-2xl font-semibold`.\n- Body: `text-base leading-7`.\n- Description: `text-sm text-muted-foreground`.\n- Code: `font-mono text-sm`.\n- Weights: 400 body, 500 labels, 600 headings, 700 short emphasis.\n- Default and large button text uses `text-base` (16px), matching body text.\n  Small button variants retain their smaller type sizes. Text button heights\n  add 8pt to the previous 32/36/40/44px heights (xs/sm/default/lg), and add\n  4pt to the previous 12/14/16/20px horizontal padding on each side. This gives\n  4pt (about 5.33px) more room on each edge without changing type size.\n  Icon sizes grow by 8pt too; the Gallery copy action explicitly stays 32px.\n  All Button sizes use rounded-3xl (22px), including small and icon variants.\n  Toggle buttons share this radius; connected ToggleGroup items retain flat\n  inner joins with rounded-3xl outer ends. Explicit instructional shape/radius\n  examples and the fixed 18px corner comparison keep their comparison geometry.\n  Input and Select use rounded-xl with 4pt added to each side of their padding;\n  their minimum heights grow and content-driven heights prevent text clipping.\n  Select items use rounded-lg and the same added padding.\n\n## Corner Shapes\n\n- Rounded rectangular surfaces share --corner-shape: squircle in app/globals.css. A base\n  rule applies CSS corner-shape to elements and their pseudo-elements, keeping\n  existing radius tokens, border widths, shadows and keyboard focus styles.\n  This includes buttons, inputs, cards, gallery previews, menus and dialogs,\n  including portaled content, in both themes.\n- High-roundness circles and capsules retain their original round geometry:\n  all rounded-full elements (including gallery filter pills), badges, avatar\n  circles, slider thumbs and tracks, and progress tracks. Pseudo-elements follow\n  their owning element; a round parent does not change rectangular children.\n  Use data-corner=\"round\" for an intentionally circular/capsule\n  example or a surface whose shape is drawn by SVG. The Button corner comparison\n  still uses its independent figma-squircle paths so circular and continuous\n  examples remain distinct.\n- CSS squircle is a web approximation, not the same curve as Figma smoothing\n  or Apple's native continuous corners. Apply it within @supports: browsers\n  without corner-shape support retain their existing border-radius rendering.\n  Do not clip interactive elements with clip-path to simulate this fallback:\n  that would cut off focus rings, shadows and overflowing child content.\n- The default radius (--radius) is 2.5rem (40px), matching the gallery card.\n  Cards, Dialog/AlertDialog, Select/theme/language popup surfaces and gallery\n  cards share rounded-container. Keep the smaller control scale unchanged:\n  Button remains rounded-3xl (22px) and Input/Select triggers rounded-xl (14px).\n  Match card images, headers and footers,\n  and dialog footers to their container corners. Sheet uses 40px corners only\n  on the exposed edge, leaving the screen-attached edge square. These changes\n  do not alter button/input radii, capsules, avatars or the Tilt card image.\n- For inset rounded elements, calculate the outer radius from the inner\n  radius plus the actual edge gap (r + p), not by assigning the same radius\n  to both. rounded-container accepts local --nested-radius and --nested-gap,\n  with a 40px maximum and a non-negative result. Native border-radius scaling\n  also limits corners to the available surface size. Reset these local values\n  when starting an independent nested container; do not measure unrelated,\n  centered preview content as if it followed the container's edge.\n  Card with footer buttons uses the 22px button radius plus its 12px (small)\n  or 16px (default) padding, producing 34px or 38px. Dialog/AlertDialog with\n  footer buttons use 22px + 16px = 38px. Header/footer backgrounds that share\n  the same outer boundary inherit that computed radius; they have no inset.\n  Default TabsList uses the trigger's 8px radius plus its 3px padding (11px);\n  line tabs remain square. Unmarked standalone containers retain 40px.\n  Docs preview frames also use rounded-container rather than a smaller radius\n  around the larger nested component; their 24px inset reaches the 40px cap\n  for the standard rounded controls and cards.\n\n## Available Components\n\n- Button: default, outline, secondary, ghost, destructive, link. Use its size\n  variants for text and icon-only buttons.\n  Filled hover backgrounds darken: Primary uses --primary-hover\n  (Primary mixed with 12% black), and Secondary mixes with 8% black. Ghost\n  controls use a 5% black hover background in light mode and 5% white in dark mode.\n  Outline buttons keep transparent backgrounds at rest and use a subtle gray\n  hover background: 5% black in light mode and 5% white in dark mode. Destructive\n  controls use a black tint on hover in dark mode. SVG corner examples and the Button hover-state\n  demonstration share the Primary hover token. Keep focus rings and disabled states.\n  On text Button variants, hover text retains its semantic color at 80% opacity\n  instead of darkening, including white, black, and Link text. Icon-only sizes retain\n  their existing foreground behavior; this rule does not change disabled states.\n  Outline Toggle buttons also remain transparent on hover and selection;\n  selected outlines use a stronger border instead of a filled background.\n- Card: header, title, description, content, footer, action.\n- Dialog: trigger, content, title, description, header, footer, close.\n- Alert Dialog: confirmation content, title, description, action, cancel.\n- Tabs: list, trigger, content.\n- Input and Select: labeled text entry and option selection.\n- Slider: numeric ranges.\n- Sheet: bottom-sheet navigation and supporting tasks.\n- Pagination and ToggleGroup: result navigation and filters.\n- Badge: status labels and removable tags.\n  Badge and Tag share text-base (16px), px-4 (16px per side), py-1.5 (6px per\n  side), min-h-9 and gap-2. Keep height content-driven so text and removable\n  actions fit without clipping. Icons are 16px; retain the original pill shape.\n  Gallery filter pills also use 16px horizontal and 6px vertical padding.\n  The instructional pill Button adds 4px horizontal padding on each side.\n  Do not add pill padding to circular avatars, slider thumbs, or progress tracks.\n- Avatar: identity with initials as a fallback.\n- Progress: task completion.\n- ThemeProvider and ThemeToggle: light, dark, and system theme selection.\n- LocaleProvider: Korean/English preference, shared by the settings menu and\n  translated UI text. Wrap ThemeProvider and application content in\n  LocaleProvider when adopting the included ThemeToggle. Its dependencies\n  (`lib/translations.ts`) are included in the reference.\n\nThe full reference includes exact sources, tokens, configuration, utilities,\nand the host project's dependency versions. Version lists describe the\nreference implementation; they do not authorize framework migrations.\n\n## Registry Releases\n\n- `/docs/registry` lists installable COMPASS items and version-pinned install URLs.\n- `/docs/changelog` records release notes. Registry items are available at\n  `/r/<version>/<name>.json`; `/r/<name>.json` resolves to the latest recorded\n  release, not the current development source. Install a version-pinned URL.\n- The initial local release is 0.1.0. It requires a React and Tailwind CSS v4\n  project already initialized with shadcn. Each item includes the shared style\n  tokens, Pretendard, and its component dependency closure. Global style changes\n  must be reviewed, and ThemeProvider connected to the app root separately.\n- Preserve the target's framework, files, and local changes. Do not automatically\n  overwrite customized components or the target's agent instructions.\n- `registry/releases.json` stores release notes newest first; immutable source\n  snapshots live in `registry/releases/<version>.json`. To create a new version,\n  add its notes and run `pnpm registry:release <version>`. Existing versions cannot\n  be overwritten. `pnpm compass:export` rebuilds indexes from snapshots only and\n  never creates releases from live edits. See `docs/registry.md` for maintenance.\n- localhost is local-only. Registry availability on this machine does not mean\n  the site has been deployed or published to npm.\n\n## AI Connection\n\nGive an AI the `/llms-full.txt` document once, then ask it to add a persistent\nCompass rule to the target project's supported instruction file (for example,\nAGENTS.md if the agent reads it). Preserve existing rules. Keep a local copy of\nthis reference for agents that cannot fetch URLs. After that setup, \"디자인\n시스템 써\" means to use Compass's tokens, font, icons, and components.\n\nThere is no global registration that makes every AI recognize this name.\nThe localhost URL is only available on the machine running this site; remote\nAI services need the downloaded reference attached or a hosted accessible URL.\n\n## Documentation\n\n- `/docs`: Introduction.\n- `/docs/installation`: Legacy developer-only page; redirects to `/docs`.\n- `/docs/theming`: Theming.\n- `/docs/cli`: Legacy developer-only page; redirects to `/docs`.\n- `/docs/ai`: AI setup.\n- `/docs/elements/typography`: Typography.\n- `/docs/elements/colors`: Colors.\n- `/docs/elements/icons`: Icons.\n- `/docs/elements/spacing`: Existing spacing scale, spacing roles, and current\n  layout values, without visible CSS tokens, class names, or implementation notes.\n- `/docs/elements/writing`: Writing guidance.\n- `/docs/elements/elevation`: Visual depth, existing shadow classes, stacking\n  order and theme considerations. Flat/Low/Medium/High map to no shadow,\n  shadow-sm/md/lg. These classes map to --surface-shadow-sm/md/lg via @theme\n  inline, with light values unchanged and stronger, wider dark-mode shadows.\n  The comparison tool uses equal surface colors on a slightly contrasting\n  background so only the shadow changes between levels. Use actual\n  component styles: menus/select use shadow-md, Sheet shadow-lg, dialogs ring-1\n  without added shadows. Keep elevation distinct from z-index and focus rings.\n- `/docs/composition/layers`, `/docs/composition/organization`,\n  `/docs/composition/layout`: Composition principles and examples.\n- `/docs/interaction/information-architecture`, `/docs/interaction/input-output`:\n  Interaction principles and examples.\n- `/components`: Component directory grouped into Input, Navigation, Status.\n- Input: `/components/button`, `/components/input`, `/components/select`,\n  `/components/slider`.\n- Navigation: `/components/card`, `/components/bottom-sheet`, `/components/tabs`,\n  `/components/pagination`, `/components/filter`.\n- Status: `/components/badge`, `/components/tag`, `/components/avatar`,\n  `/components/progress`, `/components/dialog`, `/components/alert-dialog`.\n  Each page includes a live preview, without a usage section below it or a source\n  code section. Keep existing component URLs working when changing categories.\n  Button additionally includes guidelines with interactive Compass previews\n  instead of external images: Graphics, Composition, and Interaction, linked\n  from the right ToC. Demonstrate sizes, shapes, padding, hierarchy, states,\n  simulated progress and confirmation feedback using existing UI primitives.\n  Comparison previews display their alternatives simultaneously, not behind\n  tabs or selection controls. Preserve individual button interactions and\n  responsive wrapping, plus sliders and text inputs where relevant.\n  Corner comparison shows two buttons with figma-squircle paths, identical\n  160x64px geometry and a shared nominal radius of 18px. Circular smoothing is\n  0%, continuous smoothing is 60%. Below them, overlay only the enlarged upper\n  straight-to-curve junction in a 3:1 crop, using the exact same paths and scale:\n  neutral dashed circular edge,\n  blue continuous edge, shaded difference, and transition-start dots.\n  Keep this static comparison free of sliders, axes, grids, or extra insets.\n  This is a web approximation, not Apple's\n  exact native continuous-corner implementation; do not equate CSS superellipse\n  with that implementation. Keep keyboard focus indicators outside the SVG.\n- `/`: Gallery with working previews and code copy.\n\nPreserve the existing Docs writing and previews. Do not replace them with new\nUX articles. Rendered Docs omit code blocks, installation commands, imports,\nCSS class names, and development explanations. Remove empty sections and their\nToC entries; developer-only Installation and CLI pages are not in navigation.\nGallery code copy and the downloadable AI implementation reference stay available.\n\nGallery uses the same Input, Navigation, and Status catalog as Docs.\nAll 15 documented components share live preview implementations across both\nsurfaces. Keep the legacy gallery examples, including Heat map. Tilt card also\nbelongs to Visual Effects and uses the React-only source in components/tilt-card.tsx\nand its scoped companion stylesheet. It sinks away from the pointer with a\nspring-driven light intensity and tightening shadow, returning to rest on exit\nor touch release. Keep the pointer shade local: a 22% by 18% elliptical radius,\n13.2% maximum opacity at the default shade setting, fading to 35% of its center\nopacity at the 45% stop and transparent at its edge. Its position uses raw\npointer coordinates without spring smoothing, offset downward by 6% of the\ncard height so it follows just below the cursor immediately. The highlight\nstays fixed at 50% 0% to keep the lighting overhead. The outer shadow, card\nrotation and light intensity retain their existing spring behavior.\nOn exit the pointer shade fades at its last\nposition instead of travelling back to the center.\nKeep keyboard arrows, Escape, focus visibility and reduced\nmotion support. It is transient, so it does not need a footer reset action.\nIts preview is 188px wide with the original 13:16 aspect ratio and scaled shadow,\noffset 8px upward to leave room above the footer. Its two preview wrappers\nuse visible overflow so the returning shadow does not get clipped at the\npreview/footer boundary; other previews use non-scrollable clipped wrappers.\nThe outer card still clips to its rounded boundary. --surface-2 maps\nto the existing --secondary token rather than adding a global Bencho token.\nCopied code includes the component, stylesheet and original MIT notice\n(Copyright 2026 Lorenzo Cabra, https://bencho.dev/licence). Bencho photographs\nare not included; the replacement photograph is by Calvin Mano under the\nUnsplash License (https://unsplash.com/photos/CXS27RrJObQ).\nGallery spans\nthe viewport and uses up to four columns. Code copy is a ghost icon button\nbeside the card title, without a separate action row. Gallery cards have no\ndivider. Every gallery card has a fixed 320px preview\nand a 40px title/action row inside the same surface directly below it, with\n16px horizontal inset and 8px bottom padding. The complete card stays 360px tall.\nGallery cards never scroll internally; only the page scrolls. Compact Card\npreviews use the existing small Card spacing, and Pagination previews use\n44px icon-only previous/next controls with accessible labels and 44px page\nlinks so their full contents fit the fixed preview area. Docs retains its\nregular Card spacing and text labels.\nThe shared preview/title surface uses rounded-container (40px)\ncorners and a subtle 1px inset ring: ring-foreground/8 in light mode for clearer\nseparation from the pale gray gallery page, and dark:ring-border/30 in dark mode.\nThe title and copy button sit within the card, not below its boundary. They\nshare its background without a separate footer color or divider.\nStateful gallery previews have a 32px ghost reset icon immediately to the left\nof code copy. Reset only that preview to its initial state; keep the card footer,\nkeyboard focus, current filter and other cards intact. Static previews have no\nreset action. Gallery Tag and Progress previews omit their internal reset\nbuttons in favor of this footer action; Docs retains its existing controls.\n`lib/gallery-sources.json` is generated\nby `pnpm compass:export` from the actual preview functions for code copy;\ndo not edit it by hand.\n\nGallery starts with a single ungrouped grid sorted by newest update first.\nHeader and content share responsive horizontal padding (16/32/40px).\nThe text-only wordmark reads \"COMPASS\" in 18px type; the browser title is also\n\"COMPASS\". Docs navigation text shares the same\nleft gutter as the wordmark, accounting for its inner 8px link padding.\nThe desktop wordmark-to-navigation gap is 32px (16px flex gap plus 16px margin).\nHeader theme and language icons use 20px; dropdown checkmarks stay 16px.\nGallery uses a compact filter band, with 8px top content padding, 8px filter\ntop padding, 8px filter bottom padding, and an 8px margin before the grid\n(16px combined distance from filters to cards). Navigation active states use\nneutral foreground color and indicators without changing font weight or element\ndimensions. Active main navigation text and underline use text-foreground and\nborder-foreground (near-black in light mode, near-white in dark mode), not Primary.\nKeep the category filters, including Visual Effects for Heat map.\nInactive filter chips use bg-background (white in light mode); selected chips\nretain bg-foreground and text-background for a neutral active state. Do not show\nNew badges on gallery cards. `lib/gallery-updates.json` tracks source hashes and\nupdate timestamps during export; unchanged examples retain their timestamps.\nGallery previews hide supplementary instructions and interaction status text\nvisually, while retaining screen-reader status announcements and actual\ncomponent content. Docs previews keep their existing interaction feedback.\nDocs spans the viewport with a centered document area capped at 40rem (640px).\nThe Button ToC includes nested group and subsection links matching the heading\nhierarchy, including Shape, Size, and all remaining guideline subsections.\nUse \"미리보기\" (\"Preview\") for preview headings and navigation. Button previews\ndo not show a selected-variant status sentence below the controls.\nOn desktop,\nthe left navigation and right table of contents are fixed to the screen edges\nbelow the header, with independent scrolling and reserved content space.\n\nThe Docs navigation opens `/docs/ai` first. Keep AI setup as the first item\nunder Get Started. The top-right theme menu selects the theme. A separate\nLanguageSelect button beside it selects Korean or English. Theme and language\npreferences persist independently.\nKorean navigation uses localized names, including Elevation as \"높이\", Gallery\nas \"갤러리\", Docs as \"문서\", Get Started as \"시작하기\", Elements as \"기본 요소\",\nand Input/Navigation/Status as \"입력\"/\"탐색\"/\"상태\". Use translate or\nLocaleText consistently for group headings, filters, breadcrumbs and ToC.\nKeep English labels in English mode and preserve the Compass wordmark.\n\n## Updating the AI Reference\n\nRun `pnpm compass:export` after source or guidance changes. This also runs\nbefore `pnpm dev` and `pnpm build`. It exports only the explicitly selected\npublic design-system files; it does not export secrets or the whole repository.\n"}],"docs":"Requires an existing React + Tailwind CSS v4 project initialized with shadcn. COMPASS merges global styles; review existing components and CSS before installing. ThemeProvider must be connected to the application root separately. See /docs/registry and /docs/ai.","meta":{"version":"0.1.0","group":"input"}},{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"card","title":"카드","type":"registry:ui","registryDependencies":["https://0.0.0.0:3000/r/0.1.0/foundations.json"],"cssVars":{"theme":{"shadow-sm":"var(--surface-shadow-sm)","shadow-md":"var(--surface-shadow-md)","shadow-lg":"var(--surface-shadow-lg)","font-heading":"\"Pretendard Variable\", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, sans-serif","font-sans":"\"Pretendard Variable\", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, sans-serif","font-mono":"\"SFMono-Regular\", Consolas, \"Liberation Mono\", Menlo, monospace","color-sidebar-ring":"var(--sidebar-ring)","color-sidebar-border":"var(--sidebar-border)","color-sidebar-accent-foreground":"var(--sidebar-accent-foreground)","color-sidebar-accent":"var(--sidebar-accent)","color-sidebar-primary-foreground":"var(--sidebar-primary-foreground)","color-sidebar-primary":"var(--sidebar-primary)","color-sidebar-foreground":"var(--sidebar-foreground)","color-sidebar":"var(--sidebar)","color-chart-5":"var(--chart-5)","color-chart-4":"var(--chart-4)","color-chart-3":"var(--chart-3)","color-chart-2":"var(--chart-2)","color-chart-1":"var(--chart-1)","color-ring":"var(--ring)","color-input":"var(--input)","color-border":"var(--border)","color-destructive":"var(--destructive)","color-accent-foreground":"var(--accent-foreground)","color-accent":"var(--accent)","color-muted-foreground":"var(--muted-foreground)","color-muted":"var(--muted)","color-secondary-foreground":"var(--secondary-foreground)","color-secondary":"var(--secondary)","color-primary-foreground":"var(--primary-foreground)","color-primary":"var(--primary)","color-primary-hover":"var(--primary-hover)","color-popover-foreground":"var(--popover-foreground)","color-popover":"var(--popover)","color-card-foreground":"var(--card-foreground)","color-card":"var(--card)","color-foreground":"var(--foreground)","color-background":"var(--background)","color-gallery-background":"var(--gallery-background)","radius-sm":"calc(var(--radius) * 0.15)","radius-md":"calc(var(--radius) * 0.2)","radius-lg":"calc(var(--radius) * 0.25)","radius-xl":"calc(var(--radius) * 0.35)","radius-2xl":"calc(var(--radius) * 0.45)","radius-3xl":"calc(var(--radius) * 0.55)","radius-4xl":"calc(var(--radius) * 0.65)","radius-5xl":"calc(var(--radius) * 0.8)","radius-6xl":"var(--radius)","radius-container":"min(var(--radius), max(0px, calc(var(--nested-radius, var(--radius)) + var(--nested-gap, 0px))))"},"light":{"corner-shape":"squircle","surface-shadow-sm":"0 1px 3px 0 rgb(0 0 0 / 10%), 0 1px 2px -1px rgb(0 0 0 / 10%)","surface-shadow-md":"0 4px 6px -1px rgb(0 0 0 / 10%), 0 2px 4px -2px rgb(0 0 0 / 10%)","surface-shadow-lg":"0 10px 15px -3px rgb(0 0 0 / 10%), 0 4px 6px -4px rgb(0 0 0 / 10%)","background":"#ffffff","gallery-background":"#f7f7f7","gallery-preview-background":"oklch(1 0 0)","foreground":"oklch(0.145 0 0)","card":"oklch(1 0 0)","card-foreground":"oklch(0.145 0 0)","popover":"oklch(1 0 0)","popover-foreground":"oklch(0.145 0 0)","primary":"#007AFF","primary-hover":"color-mix(in oklch, var(--primary), black 12%)","primary-foreground":"#ffffff","secondary":"oklch(0.97 0 0)","secondary-foreground":"oklch(0.205 0 0)","muted":"oklch(0.97 0 0)","muted-foreground":"oklch(0.556 0 0)","accent":"#007AFF","accent-foreground":"#ffffff","destructive":"oklch(0.577 0.245 27.325)","border":"oklch(0.922 0 0)","input":"oklch(0.922 0 0)","ring":"oklch(0.708 0 0)","chart-1":"oklch(0.87 0 0)","chart-2":"oklch(0.556 0 0)","chart-3":"oklch(0.439 0 0)","chart-4":"oklch(0.371 0 0)","chart-5":"oklch(0.269 0 0)","radius":"2.5rem","sidebar":"oklch(0.985 0 0)","sidebar-foreground":"oklch(0.145 0 0)","sidebar-primary":"oklch(0.205 0 0)","sidebar-primary-foreground":"oklch(0.985 0 0)","sidebar-accent":"oklch(0.97 0 0)","sidebar-accent-foreground":"oklch(0.205 0 0)","sidebar-border":"oklch(0.922 0 0)","sidebar-ring":"oklch(0.708 0 0)"},"dark":{"surface-shadow-sm":"0 2px 6px 0 rgb(0 0 0 / 40%), 0 1px 2px 0 rgb(0 0 0 / 25%)","surface-shadow-md":"0 6px 16px -2px rgb(0 0 0 / 50%), 0 2px 6px 0 rgb(0 0 0 / 35%)","surface-shadow-lg":"0 14px 32px -4px rgb(0 0 0 / 65%), 0 6px 12px -2px rgb(0 0 0 / 45%)","background":"oklch(0.15 0 0)","gallery-background":"oklch(0.15 0 0)","gallery-preview-background":"oklch(0.18 0 0)","foreground":"oklch(0.985 0 0)","card":"oklch(0.205 0 0)","card-foreground":"oklch(0.985 0 0)","popover":"oklch(0.205 0 0)","popover-foreground":"oklch(0.985 0 0)","primary":"#007AFF","primary-foreground":"#ffffff","secondary":"oklch(0.269 0 0)","secondary-foreground":"oklch(0.985 0 0)","muted":"oklch(0.269 0 0)","muted-foreground":"oklch(0.708 0 0)","accent":"#007AFF","accent-foreground":"#ffffff","destructive":"oklch(0.704 0.191 22.216)","border":"oklch(1 0 0 / 10%)","input":"oklch(1 0 0 / 15%)","ring":"oklch(0.556 0 0)","chart-1":"oklch(0.87 0 0)","chart-2":"oklch(0.556 0 0)","chart-3":"oklch(0.439 0 0)","chart-4":"oklch(0.371 0 0)","chart-5":"oklch(0.269 0 0)","sidebar":"oklch(0.205 0 0)","sidebar-foreground":"oklch(0.985 0 0)","sidebar-primary":"oklch(0.488 0.243 264.376)","sidebar-primary-foreground":"oklch(0.985 0 0)","sidebar-accent":"oklch(0.269 0 0)","sidebar-accent-foreground":"oklch(0.985 0 0)","sidebar-border":"oklch(1 0 0 / 10%)","sidebar-ring":"oklch(0.556 0 0)"}},"css":{"@import \"tw-animate-css\"":{},"@import \"shadcn/tailwind.css\"":{},"@custom-variant dark (&:is(.dark *))":{},"@layer base":{"*":{"@apply border-border outline-ring/50":{}},"body":{"@apply bg-background text-foreground":{}},"button:not(:disabled), [role=\"button\"]:not(:disabled)":{"cursor":"pointer"},"html":{"@apply font-sans":{}},"@supports (corner-shape: squircle)":{"*":{"corner-shape":"var(--corner-shape)"},"::before, ::after":{"corner-shape":"inherit"},":where(.rounded-full, [data-slot=\"badge\"],\n           [data-slot^=\"avatar\"], [data-slot=\"slider-thumb\"],\n           [data-slot=\"slider-track\"], [data-slot=\"progress\"],\n           [data-corner=\"round\"])":{"corner-shape":"round"}}},"@import \"pretendard/dist/web/variable/pretendardvariable.css\"":{}},"dependencies":["cn@0.4.0","pretendard@1.3.9","shadcn@4.21.0","tw-animate-css@1.4.0"],"files":[{"path":"components/ui/card.tsx","type":"registry:ui","target":"@ui/card.tsx","content":"import * as React from \"react\"\nimport { cn } from \"cn\"\n\nfunction Card({\n  className,\n  size = \"default\",\n  ...props\n}: React.ComponentProps<\"div\"> & { size?: \"default\" | \"sm\" }) {\n  return (\n    <div\n      data-slot=\"card\"\n      data-size={size}\n      className={cn(\n        \"group/card flex flex-col gap-(--card-spacing) overflow-hidden rounded-container [--nested-radius:var(--radius)] [--nested-gap:0px] has-[[data-slot=card-footer]_button]:[--nested-radius:calc(var(--radius)*0.55)] has-[[data-slot=card-footer]_button]:[--nested-gap:var(--card-spacing)] bg-card py-(--card-spacing) text-sm text-card-foreground ring-1 ring-foreground/10 [--card-spacing:--spacing(4)] has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:[--card-spacing:--spacing(3)] data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-container *:[img:last-child]:rounded-b-container\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction CardHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"card-header\"\n      className={cn(\n        \"group/card-header @container/card-header grid auto-rows-min items-start gap-1 rounded-t-container px-(--card-spacing) has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto] [.border-b]:pb-(--card-spacing)\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction CardTitle({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"card-title\"\n      className={cn(\n        \"font-heading text-base leading-snug font-medium group-data-[size=sm]/card:text-sm\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction CardDescription({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"card-description\"\n      className={cn(\"text-sm text-muted-foreground\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction CardAction({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"card-action\"\n      className={cn(\n        \"col-start-2 row-span-2 row-start-1 self-start justify-self-end\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction CardContent({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"card-content\"\n      className={cn(\"px-(--card-spacing)\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction CardFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"card-footer\"\n      className={cn(\n        \"flex items-center rounded-b-container border-t bg-muted/50 p-(--card-spacing)\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nexport {\n  Card,\n  CardHeader,\n  CardFooter,\n  CardTitle,\n  CardAction,\n  CardDescription,\n  CardContent,\n}\n"},{"path":"docs/compass.md","type":"registry:file","target":"~/docs/compass.md","content":"# Compass Design System\n\nCompass is the design system for this project. When the user says \"use the\ndesign system\", \"디자인 시스템 써\", or \"Compass 써\", apply these rules.\n\n## Applying Compass\n\n1. Inspect the target project before changing it. Preserve its framework and\n   package manager. Do not replace the application or overwrite its existing\n   agent instructions. Merge Compass guidance into its project instructions.\n2. In this repository, reuse the actual source in `components/ui`. Outside this\n   repository, use the source included in `/llms-full.txt` and adapt import\n   aliases to the target project. The included code targets React and Tailwind\n   CSS v4. For a different stack, keep the same tokens and behavior and explain\n   adaptations rather than pretending these React components work unchanged.\n3. Use the exact CSS tokens included in the reference. Treat `app/globals.css`\n   as the source of truth. Merge theme imports and mappings without duplicating\n   Tailwind imports or replacing unrelated CSS. Preserve light and dark themes.\n4. Primary and Accent are #007AFF in both themes; their foreground is white.\n   Other surfaces remain neutral. Use semantic classes such as `bg-primary`,\n   `text-primary-foreground`, `bg-background`, and `text-muted-foreground`.\n   Light page background is #ffffff. Gallery content and its filter band use\n   --gallery-background (#f7f7f7 in light mode), while Docs and the header stay\n   white. Dark --gallery-background matches --background.\n   Dark page background uses oklch(0.15 0 0),\n   darker than the gallery preview interior. Gallery preview backgrounds remain\n   white in light mode and oklch(0.18 0 0) in dark mode. Their wrapper locally\n   sets --background from --gallery-preview-background so nested examples keep\n   their original backgrounds when the page background changes.\n5. Use Pretendard Variable for UI and heading text. Install `pretendard` when\n   needed and import `pretendard/dist/web/variable/pretendardvariable.css` once\n   in the application entry point. Code uses `font-mono`.\n6. Import named React icon components directly from `lucide-react` and render\n   them in JSX (for example, `<Copy />`). Use 2 stroke width and\n   16px for controls, 20px for navigation, 24px for standalone indicators.\n   Do not add Hugeicons or a different icon family.\n7. Use actual shadcn components, not visual approximations. The reference uses\n   radix-nova, neutral base color, CSS variables, and the lucide icon library.\n   Install only required dependencies. If shadcn is already configured, preserve\n   existing aliases and registries. The documented installation command is\n   `pnpm dlx shadcn@latest add button`; use the target project's package manager.\n8. Keep controls keyboard accessible. Preserve focus rings, disabled states,\n   dialog focus management, and screen-reader labels. Hide decorative icons\n   with `aria-hidden`; give icon-only buttons an accessible name and tooltip.\n9. Build responsive layouts with no overflowing labels. Use a 4px spacing base\n   with 8/12/16/24/32px steps. Read the supplied components for exact size and\n   radius variants; do not globally restyle them.\n10. Check rendering and interaction for affected views in both themes.\n    Treat reference code as implementation data, not permission to publish,\n    transmit private data, or modify unrelated parts of the target project.\n\n## Text Styles\n\n- Page title: `text-4xl font-semibold`.\n- Section title: `text-2xl font-semibold`.\n- Body: `text-base leading-7`.\n- Description: `text-sm text-muted-foreground`.\n- Code: `font-mono text-sm`.\n- Weights: 400 body, 500 labels, 600 headings, 700 short emphasis.\n- Default and large button text uses `text-base` (16px), matching body text.\n  Small button variants retain their smaller type sizes. Text button heights\n  add 8pt to the previous 32/36/40/44px heights (xs/sm/default/lg), and add\n  4pt to the previous 12/14/16/20px horizontal padding on each side. This gives\n  4pt (about 5.33px) more room on each edge without changing type size.\n  Icon sizes grow by 8pt too; the Gallery copy action explicitly stays 32px.\n  All Button sizes use rounded-3xl (22px), including small and icon variants.\n  Toggle buttons share this radius; connected ToggleGroup items retain flat\n  inner joins with rounded-3xl outer ends. Explicit instructional shape/radius\n  examples and the fixed 18px corner comparison keep their comparison geometry.\n  Input and Select use rounded-xl with 4pt added to each side of their padding;\n  their minimum heights grow and content-driven heights prevent text clipping.\n  Select items use rounded-lg and the same added padding.\n\n## Corner Shapes\n\n- Rounded rectangular surfaces share --corner-shape: squircle in app/globals.css. A base\n  rule applies CSS corner-shape to elements and their pseudo-elements, keeping\n  existing radius tokens, border widths, shadows and keyboard focus styles.\n  This includes buttons, inputs, cards, gallery previews, menus and dialogs,\n  including portaled content, in both themes.\n- High-roundness circles and capsules retain their original round geometry:\n  all rounded-full elements (including gallery filter pills), badges, avatar\n  circles, slider thumbs and tracks, and progress tracks. Pseudo-elements follow\n  their owning element; a round parent does not change rectangular children.\n  Use data-corner=\"round\" for an intentionally circular/capsule\n  example or a surface whose shape is drawn by SVG. The Button corner comparison\n  still uses its independent figma-squircle paths so circular and continuous\n  examples remain distinct.\n- CSS squircle is a web approximation, not the same curve as Figma smoothing\n  or Apple's native continuous corners. Apply it within @supports: browsers\n  without corner-shape support retain their existing border-radius rendering.\n  Do not clip interactive elements with clip-path to simulate this fallback:\n  that would cut off focus rings, shadows and overflowing child content.\n- The default radius (--radius) is 2.5rem (40px), matching the gallery card.\n  Cards, Dialog/AlertDialog, Select/theme/language popup surfaces and gallery\n  cards share rounded-container. Keep the smaller control scale unchanged:\n  Button remains rounded-3xl (22px) and Input/Select triggers rounded-xl (14px).\n  Match card images, headers and footers,\n  and dialog footers to their container corners. Sheet uses 40px corners only\n  on the exposed edge, leaving the screen-attached edge square. These changes\n  do not alter button/input radii, capsules, avatars or the Tilt card image.\n- For inset rounded elements, calculate the outer radius from the inner\n  radius plus the actual edge gap (r + p), not by assigning the same radius\n  to both. rounded-container accepts local --nested-radius and --nested-gap,\n  with a 40px maximum and a non-negative result. Native border-radius scaling\n  also limits corners to the available surface size. Reset these local values\n  when starting an independent nested container; do not measure unrelated,\n  centered preview content as if it followed the container's edge.\n  Card with footer buttons uses the 22px button radius plus its 12px (small)\n  or 16px (default) padding, producing 34px or 38px. Dialog/AlertDialog with\n  footer buttons use 22px + 16px = 38px. Header/footer backgrounds that share\n  the same outer boundary inherit that computed radius; they have no inset.\n  Default TabsList uses the trigger's 8px radius plus its 3px padding (11px);\n  line tabs remain square. Unmarked standalone containers retain 40px.\n  Docs preview frames also use rounded-container rather than a smaller radius\n  around the larger nested component; their 24px inset reaches the 40px cap\n  for the standard rounded controls and cards.\n\n## Available Components\n\n- Button: default, outline, secondary, ghost, destructive, link. Use its size\n  variants for text and icon-only buttons.\n  Filled hover backgrounds darken: Primary uses --primary-hover\n  (Primary mixed with 12% black), and Secondary mixes with 8% black. Ghost\n  controls use a 5% black hover background in light mode and 5% white in dark mode.\n  Outline buttons keep transparent backgrounds at rest and use a subtle gray\n  hover background: 5% black in light mode and 5% white in dark mode. Destructive\n  controls use a black tint on hover in dark mode. SVG corner examples and the Button hover-state\n  demonstration share the Primary hover token. Keep focus rings and disabled states.\n  On text Button variants, hover text retains its semantic color at 80% opacity\n  instead of darkening, including white, black, and Link text. Icon-only sizes retain\n  their existing foreground behavior; this rule does not change disabled states.\n  Outline Toggle buttons also remain transparent on hover and selection;\n  selected outlines use a stronger border instead of a filled background.\n- Card: header, title, description, content, footer, action.\n- Dialog: trigger, content, title, description, header, footer, close.\n- Alert Dialog: confirmation content, title, description, action, cancel.\n- Tabs: list, trigger, content.\n- Input and Select: labeled text entry and option selection.\n- Slider: numeric ranges.\n- Sheet: bottom-sheet navigation and supporting tasks.\n- Pagination and ToggleGroup: result navigation and filters.\n- Badge: status labels and removable tags.\n  Badge and Tag share text-base (16px), px-4 (16px per side), py-1.5 (6px per\n  side), min-h-9 and gap-2. Keep height content-driven so text and removable\n  actions fit without clipping. Icons are 16px; retain the original pill shape.\n  Gallery filter pills also use 16px horizontal and 6px vertical padding.\n  The instructional pill Button adds 4px horizontal padding on each side.\n  Do not add pill padding to circular avatars, slider thumbs, or progress tracks.\n- Avatar: identity with initials as a fallback.\n- Progress: task completion.\n- ThemeProvider and ThemeToggle: light, dark, and system theme selection.\n- LocaleProvider: Korean/English preference, shared by the settings menu and\n  translated UI text. Wrap ThemeProvider and application content in\n  LocaleProvider when adopting the included ThemeToggle. Its dependencies\n  (`lib/translations.ts`) are included in the reference.\n\nThe full reference includes exact sources, tokens, configuration, utilities,\nand the host project's dependency versions. Version lists describe the\nreference implementation; they do not authorize framework migrations.\n\n## Registry Releases\n\n- `/docs/registry` lists installable COMPASS items and version-pinned install URLs.\n- `/docs/changelog` records release notes. Registry items are available at\n  `/r/<version>/<name>.json`; `/r/<name>.json` resolves to the latest recorded\n  release, not the current development source. Install a version-pinned URL.\n- The initial local release is 0.1.0. It requires a React and Tailwind CSS v4\n  project already initialized with shadcn. Each item includes the shared style\n  tokens, Pretendard, and its component dependency closure. Global style changes\n  must be reviewed, and ThemeProvider connected to the app root separately.\n- Preserve the target's framework, files, and local changes. Do not automatically\n  overwrite customized components or the target's agent instructions.\n- `registry/releases.json` stores release notes newest first; immutable source\n  snapshots live in `registry/releases/<version>.json`. To create a new version,\n  add its notes and run `pnpm registry:release <version>`. Existing versions cannot\n  be overwritten. `pnpm compass:export` rebuilds indexes from snapshots only and\n  never creates releases from live edits. See `docs/registry.md` for maintenance.\n- localhost is local-only. Registry availability on this machine does not mean\n  the site has been deployed or published to npm.\n\n## AI Connection\n\nGive an AI the `/llms-full.txt` document once, then ask it to add a persistent\nCompass rule to the target project's supported instruction file (for example,\nAGENTS.md if the agent reads it). Preserve existing rules. Keep a local copy of\nthis reference for agents that cannot fetch URLs. After that setup, \"디자인\n시스템 써\" means to use Compass's tokens, font, icons, and components.\n\nThere is no global registration that makes every AI recognize this name.\nThe localhost URL is only available on the machine running this site; remote\nAI services need the downloaded reference attached or a hosted accessible URL.\n\n## Documentation\n\n- `/docs`: Introduction.\n- `/docs/installation`: Legacy developer-only page; redirects to `/docs`.\n- `/docs/theming`: Theming.\n- `/docs/cli`: Legacy developer-only page; redirects to `/docs`.\n- `/docs/ai`: AI setup.\n- `/docs/elements/typography`: Typography.\n- `/docs/elements/colors`: Colors.\n- `/docs/elements/icons`: Icons.\n- `/docs/elements/spacing`: Existing spacing scale, spacing roles, and current\n  layout values, without visible CSS tokens, class names, or implementation notes.\n- `/docs/elements/writing`: Writing guidance.\n- `/docs/elements/elevation`: Visual depth, existing shadow classes, stacking\n  order and theme considerations. Flat/Low/Medium/High map to no shadow,\n  shadow-sm/md/lg. These classes map to --surface-shadow-sm/md/lg via @theme\n  inline, with light values unchanged and stronger, wider dark-mode shadows.\n  The comparison tool uses equal surface colors on a slightly contrasting\n  background so only the shadow changes between levels. Use actual\n  component styles: menus/select use shadow-md, Sheet shadow-lg, dialogs ring-1\n  without added shadows. Keep elevation distinct from z-index and focus rings.\n- `/docs/composition/layers`, `/docs/composition/organization`,\n  `/docs/composition/layout`: Composition principles and examples.\n- `/docs/interaction/information-architecture`, `/docs/interaction/input-output`:\n  Interaction principles and examples.\n- `/components`: Component directory grouped into Input, Navigation, Status.\n- Input: `/components/button`, `/components/input`, `/components/select`,\n  `/components/slider`.\n- Navigation: `/components/card`, `/components/bottom-sheet`, `/components/tabs`,\n  `/components/pagination`, `/components/filter`.\n- Status: `/components/badge`, `/components/tag`, `/components/avatar`,\n  `/components/progress`, `/components/dialog`, `/components/alert-dialog`.\n  Each page includes a live preview, without a usage section below it or a source\n  code section. Keep existing component URLs working when changing categories.\n  Button additionally includes guidelines with interactive Compass previews\n  instead of external images: Graphics, Composition, and Interaction, linked\n  from the right ToC. Demonstrate sizes, shapes, padding, hierarchy, states,\n  simulated progress and confirmation feedback using existing UI primitives.\n  Comparison previews display their alternatives simultaneously, not behind\n  tabs or selection controls. Preserve individual button interactions and\n  responsive wrapping, plus sliders and text inputs where relevant.\n  Corner comparison shows two buttons with figma-squircle paths, identical\n  160x64px geometry and a shared nominal radius of 18px. Circular smoothing is\n  0%, continuous smoothing is 60%. Below them, overlay only the enlarged upper\n  straight-to-curve junction in a 3:1 crop, using the exact same paths and scale:\n  neutral dashed circular edge,\n  blue continuous edge, shaded difference, and transition-start dots.\n  Keep this static comparison free of sliders, axes, grids, or extra insets.\n  This is a web approximation, not Apple's\n  exact native continuous-corner implementation; do not equate CSS superellipse\n  with that implementation. Keep keyboard focus indicators outside the SVG.\n- `/`: Gallery with working previews and code copy.\n\nPreserve the existing Docs writing and previews. Do not replace them with new\nUX articles. Rendered Docs omit code blocks, installation commands, imports,\nCSS class names, and development explanations. Remove empty sections and their\nToC entries; developer-only Installation and CLI pages are not in navigation.\nGallery code copy and the downloadable AI implementation reference stay available.\n\nGallery uses the same Input, Navigation, and Status catalog as Docs.\nAll 15 documented components share live preview implementations across both\nsurfaces. Keep the legacy gallery examples, including Heat map. Tilt card also\nbelongs to Visual Effects and uses the React-only source in components/tilt-card.tsx\nand its scoped companion stylesheet. It sinks away from the pointer with a\nspring-driven light intensity and tightening shadow, returning to rest on exit\nor touch release. Keep the pointer shade local: a 22% by 18% elliptical radius,\n13.2% maximum opacity at the default shade setting, fading to 35% of its center\nopacity at the 45% stop and transparent at its edge. Its position uses raw\npointer coordinates without spring smoothing, offset downward by 6% of the\ncard height so it follows just below the cursor immediately. The highlight\nstays fixed at 50% 0% to keep the lighting overhead. The outer shadow, card\nrotation and light intensity retain their existing spring behavior.\nOn exit the pointer shade fades at its last\nposition instead of travelling back to the center.\nKeep keyboard arrows, Escape, focus visibility and reduced\nmotion support. It is transient, so it does not need a footer reset action.\nIts preview is 188px wide with the original 13:16 aspect ratio and scaled shadow,\noffset 8px upward to leave room above the footer. Its two preview wrappers\nuse visible overflow so the returning shadow does not get clipped at the\npreview/footer boundary; other previews use non-scrollable clipped wrappers.\nThe outer card still clips to its rounded boundary. --surface-2 maps\nto the existing --secondary token rather than adding a global Bencho token.\nCopied code includes the component, stylesheet and original MIT notice\n(Copyright 2026 Lorenzo Cabra, https://bencho.dev/licence). Bencho photographs\nare not included; the replacement photograph is by Calvin Mano under the\nUnsplash License (https://unsplash.com/photos/CXS27RrJObQ).\nGallery spans\nthe viewport and uses up to four columns. Code copy is a ghost icon button\nbeside the card title, without a separate action row. Gallery cards have no\ndivider. Every gallery card has a fixed 320px preview\nand a 40px title/action row inside the same surface directly below it, with\n16px horizontal inset and 8px bottom padding. The complete card stays 360px tall.\nGallery cards never scroll internally; only the page scrolls. Compact Card\npreviews use the existing small Card spacing, and Pagination previews use\n44px icon-only previous/next controls with accessible labels and 44px page\nlinks so their full contents fit the fixed preview area. Docs retains its\nregular Card spacing and text labels.\nThe shared preview/title surface uses rounded-container (40px)\ncorners and a subtle 1px inset ring: ring-foreground/8 in light mode for clearer\nseparation from the pale gray gallery page, and dark:ring-border/30 in dark mode.\nThe title and copy button sit within the card, not below its boundary. They\nshare its background without a separate footer color or divider.\nStateful gallery previews have a 32px ghost reset icon immediately to the left\nof code copy. Reset only that preview to its initial state; keep the card footer,\nkeyboard focus, current filter and other cards intact. Static previews have no\nreset action. Gallery Tag and Progress previews omit their internal reset\nbuttons in favor of this footer action; Docs retains its existing controls.\n`lib/gallery-sources.json` is generated\nby `pnpm compass:export` from the actual preview functions for code copy;\ndo not edit it by hand.\n\nGallery starts with a single ungrouped grid sorted by newest update first.\nHeader and content share responsive horizontal padding (16/32/40px).\nThe text-only wordmark reads \"COMPASS\" in 18px type; the browser title is also\n\"COMPASS\". Docs navigation text shares the same\nleft gutter as the wordmark, accounting for its inner 8px link padding.\nThe desktop wordmark-to-navigation gap is 32px (16px flex gap plus 16px margin).\nHeader theme and language icons use 20px; dropdown checkmarks stay 16px.\nGallery uses a compact filter band, with 8px top content padding, 8px filter\ntop padding, 8px filter bottom padding, and an 8px margin before the grid\n(16px combined distance from filters to cards). Navigation active states use\nneutral foreground color and indicators without changing font weight or element\ndimensions. Active main navigation text and underline use text-foreground and\nborder-foreground (near-black in light mode, near-white in dark mode), not Primary.\nKeep the category filters, including Visual Effects for Heat map.\nInactive filter chips use bg-background (white in light mode); selected chips\nretain bg-foreground and text-background for a neutral active state. Do not show\nNew badges on gallery cards. `lib/gallery-updates.json` tracks source hashes and\nupdate timestamps during export; unchanged examples retain their timestamps.\nGallery previews hide supplementary instructions and interaction status text\nvisually, while retaining screen-reader status announcements and actual\ncomponent content. Docs previews keep their existing interaction feedback.\nDocs spans the viewport with a centered document area capped at 40rem (640px).\nThe Button ToC includes nested group and subsection links matching the heading\nhierarchy, including Shape, Size, and all remaining guideline subsections.\nUse \"미리보기\" (\"Preview\") for preview headings and navigation. Button previews\ndo not show a selected-variant status sentence below the controls.\nOn desktop,\nthe left navigation and right table of contents are fixed to the screen edges\nbelow the header, with independent scrolling and reserved content space.\n\nThe Docs navigation opens `/docs/ai` first. Keep AI setup as the first item\nunder Get Started. The top-right theme menu selects the theme. A separate\nLanguageSelect button beside it selects Korean or English. Theme and language\npreferences persist independently.\nKorean navigation uses localized names, including Elevation as \"높이\", Gallery\nas \"갤러리\", Docs as \"문서\", Get Started as \"시작하기\", Elements as \"기본 요소\",\nand Input/Navigation/Status as \"입력\"/\"탐색\"/\"상태\". Use translate or\nLocaleText consistently for group headings, filters, breadcrumbs and ToC.\nKeep English labels in English mode and preserve the Compass wordmark.\n\n## Updating the AI Reference\n\nRun `pnpm compass:export` after source or guidance changes. This also runs\nbefore `pnpm dev` and `pnpm build`. It exports only the explicitly selected\npublic design-system files; it does not export secrets or the whole repository.\n"}],"docs":"Requires an existing React + Tailwind CSS v4 project initialized with shadcn. COMPASS merges global styles; review existing components and CSS before installing. ThemeProvider must be connected to the application root separately. See /docs/registry and /docs/ai.","meta":{"version":"0.1.0","group":"navigation"}},{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"sheet","title":"바텀 시트","type":"registry:ui","registryDependencies":["https://0.0.0.0:3000/r/0.1.0/foundations.json"],"cssVars":{"theme":{"shadow-sm":"var(--surface-shadow-sm)","shadow-md":"var(--surface-shadow-md)","shadow-lg":"var(--surface-shadow-lg)","font-heading":"\"Pretendard Variable\", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, sans-serif","font-sans":"\"Pretendard Variable\", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, sans-serif","font-mono":"\"SFMono-Regular\", Consolas, \"Liberation Mono\", Menlo, monospace","color-sidebar-ring":"var(--sidebar-ring)","color-sidebar-border":"var(--sidebar-border)","color-sidebar-accent-foreground":"var(--sidebar-accent-foreground)","color-sidebar-accent":"var(--sidebar-accent)","color-sidebar-primary-foreground":"var(--sidebar-primary-foreground)","color-sidebar-primary":"var(--sidebar-primary)","color-sidebar-foreground":"var(--sidebar-foreground)","color-sidebar":"var(--sidebar)","color-chart-5":"var(--chart-5)","color-chart-4":"var(--chart-4)","color-chart-3":"var(--chart-3)","color-chart-2":"var(--chart-2)","color-chart-1":"var(--chart-1)","color-ring":"var(--ring)","color-input":"var(--input)","color-border":"var(--border)","color-destructive":"var(--destructive)","color-accent-foreground":"var(--accent-foreground)","color-accent":"var(--accent)","color-muted-foreground":"var(--muted-foreground)","color-muted":"var(--muted)","color-secondary-foreground":"var(--secondary-foreground)","color-secondary":"var(--secondary)","color-primary-foreground":"var(--primary-foreground)","color-primary":"var(--primary)","color-primary-hover":"var(--primary-hover)","color-popover-foreground":"var(--popover-foreground)","color-popover":"var(--popover)","color-card-foreground":"var(--card-foreground)","color-card":"var(--card)","color-foreground":"var(--foreground)","color-background":"var(--background)","color-gallery-background":"var(--gallery-background)","radius-sm":"calc(var(--radius) * 0.15)","radius-md":"calc(var(--radius) * 0.2)","radius-lg":"calc(var(--radius) * 0.25)","radius-xl":"calc(var(--radius) * 0.35)","radius-2xl":"calc(var(--radius) * 0.45)","radius-3xl":"calc(var(--radius) * 0.55)","radius-4xl":"calc(var(--radius) * 0.65)","radius-5xl":"calc(var(--radius) * 0.8)","radius-6xl":"var(--radius)","radius-container":"min(var(--radius), max(0px, calc(var(--nested-radius, var(--radius)) + var(--nested-gap, 0px))))"},"light":{"corner-shape":"squircle","surface-shadow-sm":"0 1px 3px 0 rgb(0 0 0 / 10%), 0 1px 2px -1px rgb(0 0 0 / 10%)","surface-shadow-md":"0 4px 6px -1px rgb(0 0 0 / 10%), 0 2px 4px -2px rgb(0 0 0 / 10%)","surface-shadow-lg":"0 10px 15px -3px rgb(0 0 0 / 10%), 0 4px 6px -4px rgb(0 0 0 / 10%)","background":"#ffffff","gallery-background":"#f7f7f7","gallery-preview-background":"oklch(1 0 0)","foreground":"oklch(0.145 0 0)","card":"oklch(1 0 0)","card-foreground":"oklch(0.145 0 0)","popover":"oklch(1 0 0)","popover-foreground":"oklch(0.145 0 0)","primary":"#007AFF","primary-hover":"color-mix(in oklch, var(--primary), black 12%)","primary-foreground":"#ffffff","secondary":"oklch(0.97 0 0)","secondary-foreground":"oklch(0.205 0 0)","muted":"oklch(0.97 0 0)","muted-foreground":"oklch(0.556 0 0)","accent":"#007AFF","accent-foreground":"#ffffff","destructive":"oklch(0.577 0.245 27.325)","border":"oklch(0.922 0 0)","input":"oklch(0.922 0 0)","ring":"oklch(0.708 0 0)","chart-1":"oklch(0.87 0 0)","chart-2":"oklch(0.556 0 0)","chart-3":"oklch(0.439 0 0)","chart-4":"oklch(0.371 0 0)","chart-5":"oklch(0.269 0 0)","radius":"2.5rem","sidebar":"oklch(0.985 0 0)","sidebar-foreground":"oklch(0.145 0 0)","sidebar-primary":"oklch(0.205 0 0)","sidebar-primary-foreground":"oklch(0.985 0 0)","sidebar-accent":"oklch(0.97 0 0)","sidebar-accent-foreground":"oklch(0.205 0 0)","sidebar-border":"oklch(0.922 0 0)","sidebar-ring":"oklch(0.708 0 0)"},"dark":{"surface-shadow-sm":"0 2px 6px 0 rgb(0 0 0 / 40%), 0 1px 2px 0 rgb(0 0 0 / 25%)","surface-shadow-md":"0 6px 16px -2px rgb(0 0 0 / 50%), 0 2px 6px 0 rgb(0 0 0 / 35%)","surface-shadow-lg":"0 14px 32px -4px rgb(0 0 0 / 65%), 0 6px 12px -2px rgb(0 0 0 / 45%)","background":"oklch(0.15 0 0)","gallery-background":"oklch(0.15 0 0)","gallery-preview-background":"oklch(0.18 0 0)","foreground":"oklch(0.985 0 0)","card":"oklch(0.205 0 0)","card-foreground":"oklch(0.985 0 0)","popover":"oklch(0.205 0 0)","popover-foreground":"oklch(0.985 0 0)","primary":"#007AFF","primary-foreground":"#ffffff","secondary":"oklch(0.269 0 0)","secondary-foreground":"oklch(0.985 0 0)","muted":"oklch(0.269 0 0)","muted-foreground":"oklch(0.708 0 0)","accent":"#007AFF","accent-foreground":"#ffffff","destructive":"oklch(0.704 0.191 22.216)","border":"oklch(1 0 0 / 10%)","input":"oklch(1 0 0 / 15%)","ring":"oklch(0.556 0 0)","chart-1":"oklch(0.87 0 0)","chart-2":"oklch(0.556 0 0)","chart-3":"oklch(0.439 0 0)","chart-4":"oklch(0.371 0 0)","chart-5":"oklch(0.269 0 0)","sidebar":"oklch(0.205 0 0)","sidebar-foreground":"oklch(0.985 0 0)","sidebar-primary":"oklch(0.488 0.243 264.376)","sidebar-primary-foreground":"oklch(0.985 0 0)","sidebar-accent":"oklch(0.269 0 0)","sidebar-accent-foreground":"oklch(0.985 0 0)","sidebar-border":"oklch(1 0 0 / 10%)","sidebar-ring":"oklch(0.556 0 0)"}},"css":{"@import \"tw-animate-css\"":{},"@import \"shadcn/tailwind.css\"":{},"@custom-variant dark (&:is(.dark *))":{},"@layer base":{"*":{"@apply border-border outline-ring/50":{}},"body":{"@apply bg-background text-foreground":{}},"button:not(:disabled), [role=\"button\"]:not(:disabled)":{"cursor":"pointer"},"html":{"@apply font-sans":{}},"@supports (corner-shape: squircle)":{"*":{"corner-shape":"var(--corner-shape)"},"::before, ::after":{"corner-shape":"inherit"},":where(.rounded-full, [data-slot=\"badge\"],\n           [data-slot^=\"avatar\"], [data-slot=\"slider-thumb\"],\n           [data-slot=\"slider-track\"], [data-slot=\"progress\"],\n           [data-corner=\"round\"])":{"corner-shape":"round"}}},"@import \"pretendard/dist/web/variable/pretendardvariable.css\"":{}},"dependencies":["class-variance-authority@0.7.1","cn@0.4.0","lucide-react@1.52.0","pretendard@1.3.9","radix-ui@1.6.7","shadcn@4.21.0","tw-animate-css@1.4.0"],"files":[{"path":"components/ui/sheet.tsx","type":"registry:ui","target":"@ui/sheet.tsx","content":"\"use client\"\n\nimport * as React from \"react\"\nimport { cn } from \"cn\"\nimport { Dialog as SheetPrimitive } from \"radix-ui\"\n\nimport { Button } from \"@/components/ui/button\"\n\nimport { X } from \"lucide-react\"\n\nfunction Sheet({ ...props }: React.ComponentProps<typeof SheetPrimitive.Root>) {\n  return <SheetPrimitive.Root data-slot=\"sheet\" {...props} />\n}\n\nfunction SheetTrigger({\n  ...props\n}: React.ComponentProps<typeof SheetPrimitive.Trigger>) {\n  return <SheetPrimitive.Trigger data-slot=\"sheet-trigger\" {...props} />\n}\n\nfunction SheetClose({\n  ...props\n}: React.ComponentProps<typeof SheetPrimitive.Close>) {\n  return <SheetPrimitive.Close data-slot=\"sheet-close\" {...props} />\n}\n\nfunction SheetPortal({\n  ...props\n}: React.ComponentProps<typeof SheetPrimitive.Portal>) {\n  return <SheetPrimitive.Portal data-slot=\"sheet-portal\" {...props} />\n}\n\nfunction SheetOverlay({\n  className,\n  ...props\n}: React.ComponentProps<typeof SheetPrimitive.Overlay>) {\n  return (\n    <SheetPrimitive.Overlay\n      data-slot=\"sheet-overlay\"\n      className={cn(\n        \"fixed inset-0 z-50 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction SheetContent({\n  className,\n  children,\n  side = \"right\",\n  showCloseButton = true,\n  ...props\n}: React.ComponentProps<typeof SheetPrimitive.Content> & {\n  side?: \"top\" | \"right\" | \"bottom\" | \"left\"\n  showCloseButton?: boolean\n}) {\n  return (\n    <SheetPortal>\n      <SheetOverlay />\n      <SheetPrimitive.Content\n        data-slot=\"sheet-content\"\n        data-side={side}\n        className={cn(\n          \"data-[side=bottom]:rounded-t-container data-[side=top]:rounded-b-container data-[side=left]:rounded-r-container data-[side=right]:rounded-l-container\",\n          \"fixed z-50 flex flex-col gap-4 bg-popover bg-clip-padding text-sm text-popover-foreground shadow-lg transition duration-200 ease-in-out data-[side=bottom]:inset-x-0 data-[side=bottom]:bottom-0 data-[side=bottom]:h-auto data-[side=bottom]:border-t data-[side=left]:inset-y-0 data-[side=left]:left-0 data-[side=left]:h-full data-[side=left]:w-3/4 data-[side=left]:border-r data-[side=right]:inset-y-0 data-[side=right]:right-0 data-[side=right]:h-full data-[side=right]:w-3/4 data-[side=right]:border-l data-[side=top]:inset-x-0 data-[side=top]:top-0 data-[side=top]:h-auto data-[side=top]:border-b data-[side=left]:sm:max-w-sm data-[side=right]:sm:max-w-sm data-open:animate-in data-open:fade-in-0 data-[side=bottom]:data-open:slide-in-from-bottom-10 data-[side=left]:data-open:slide-in-from-left-10 data-[side=right]:data-open:slide-in-from-right-10 data-[side=top]:data-open:slide-in-from-top-10 data-closed:animate-out data-closed:fade-out-0 data-[side=bottom]:data-closed:slide-out-to-bottom-10 data-[side=left]:data-closed:slide-out-to-left-10 data-[side=right]:data-closed:slide-out-to-right-10 data-[side=top]:data-closed:slide-out-to-top-10\",\n          className\n        )}\n        {...props}\n      >\n        {children}\n        {showCloseButton && (\n          <SheetPrimitive.Close data-slot=\"sheet-close\" asChild>\n            <Button\n              variant=\"ghost\"\n              className=\"absolute top-3 right-3\"\n              size=\"icon-sm\"\n            >\n              <X strokeWidth={2} />\n              <span className=\"sr-only\">Close</span>\n            </Button>\n          </SheetPrimitive.Close>\n        )}\n      </SheetPrimitive.Content>\n    </SheetPortal>\n  )\n}\n\nfunction SheetHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"sheet-header\"\n      className={cn(\"flex flex-col gap-0.5 p-4\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction SheetFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"sheet-footer\"\n      className={cn(\"mt-auto flex flex-col gap-2 p-4\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction SheetTitle({\n  className,\n  ...props\n}: React.ComponentProps<typeof SheetPrimitive.Title>) {\n  return (\n    <SheetPrimitive.Title\n      data-slot=\"sheet-title\"\n      className={cn(\n        \"font-heading text-base font-medium text-foreground\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction SheetDescription({\n  className,\n  ...props\n}: React.ComponentProps<typeof SheetPrimitive.Description>) {\n  return (\n    <SheetPrimitive.Description\n      data-slot=\"sheet-description\"\n      className={cn(\"text-sm text-muted-foreground\", className)}\n      {...props}\n    />\n  )\n}\n\nexport {\n  Sheet,\n  SheetTrigger,\n  SheetClose,\n  SheetContent,\n  SheetHeader,\n  SheetFooter,\n  SheetTitle,\n  SheetDescription,\n}\n"},{"path":"components/ui/button.tsx","type":"registry:ui","target":"@ui/button.tsx","content":"import * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { cn } from \"cn\"\nimport { Slot } from \"radix-ui\"\n\nconst buttonVariants = cva(\n  \"group/button inline-flex shrink-0 items-center justify-center rounded-3xl border border-transparent bg-clip-padding py-[4pt] text-base font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n  {\n    variants: {\n      variant: {\n        default: \"bg-primary text-primary-foreground hover:bg-primary-hover hover:[&:not([data-size^=icon])]:text-[color-mix(in_oklch,var(--primary-foreground),transparent_20%)]\",\n        outline:\n          \"border-border bg-transparent hover:bg-black/5 hover:text-foreground hover:[&:not([data-size^=icon])]:text-[color-mix(in_oklch,var(--foreground),transparent_20%)] aria-expanded:text-foreground dark:border-input dark:hover:bg-white/5\",\n        secondary:\n          \"bg-secondary text-secondary-foreground hover:bg-[color-mix(in_oklch,var(--secondary),black_8%)] hover:[&:not([data-size^=icon])]:text-[color-mix(in_oklch,var(--secondary-foreground),transparent_20%)] aria-expanded:bg-secondary aria-expanded:text-secondary-foreground\",\n        ghost:\n          \"hover:bg-black/5 hover:text-foreground hover:[&:not([data-size^=icon])]:text-[color-mix(in_oklch,var(--foreground),transparent_20%)] aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-white/5\",\n        destructive:\n          \"bg-destructive/10 text-destructive hover:bg-destructive/20 hover:[&:not([data-size^=icon])]:text-[color-mix(in_oklch,var(--destructive),transparent_20%)] focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-black/20 dark:focus-visible:ring-destructive/40\",\n        link: \"text-primary underline-offset-4 hover:text-primary-hover hover:[&:not([data-size^=icon])]:text-[color-mix(in_oklch,var(--primary),transparent_20%)] hover:underline\",\n      },\n      size: {\n        default:\n          \"h-[calc(2.5rem+8pt)] gap-2 px-[calc(1rem+4pt)] has-data-[icon=inline-end]:pr-[calc(.75rem+4pt)] has-data-[icon=inline-start]:pl-[calc(.75rem+4pt)]\",\n        xs: \"h-[calc(2rem+8pt)] gap-1.5 rounded-3xl px-[calc(.75rem+4pt)] text-[calc(0.75rem+2pt)] in-data-[slot=button-group]:rounded-3xl has-data-[icon=inline-end]:pr-[calc(.625rem+4pt)] has-data-[icon=inline-start]:pl-[calc(.625rem+4pt)] [&_svg:not([class*='size-'])]:size-3\",\n        sm: \"h-[calc(2.25rem+8pt)] gap-1.5 rounded-3xl px-[calc(.875rem+4pt)] text-[calc(0.8rem+2pt)] in-data-[slot=button-group]:rounded-3xl has-data-[icon=inline-end]:pr-[calc(.75rem+4pt)] has-data-[icon=inline-start]:pl-[calc(.75rem+4pt)] [&_svg:not([class*='size-'])]:size-3.5\",\n        lg: \"h-[calc(2.75rem+8pt)] gap-2 px-[calc(1.25rem+4pt)] has-data-[icon=inline-end]:pr-[calc(1rem+4pt)] has-data-[icon=inline-start]:pl-[calc(1rem+4pt)]\",\n        icon: \"size-[calc(2.5rem+8pt)]\",\n        \"icon-xs\":\n          \"size-[calc(2rem+8pt)] rounded-3xl in-data-[slot=button-group]:rounded-3xl [&_svg:not([class*='size-'])]:size-3\",\n        \"icon-sm\":\n          \"size-[calc(2.25rem+8pt)] rounded-3xl in-data-[slot=button-group]:rounded-3xl\",\n        \"icon-lg\": \"size-[calc(2.75rem+8pt)]\",\n      },\n    },\n    defaultVariants: {\n      variant: \"default\",\n      size: \"default\",\n    },\n  }\n)\n\nfunction Button({\n  className,\n  variant = \"default\",\n  size = \"default\",\n  asChild = false,\n  ...props\n}: React.ComponentProps<\"button\"> &\n  VariantProps<typeof buttonVariants> & {\n    asChild?: boolean\n  }) {\n  const Comp = asChild ? Slot.Root : \"button\"\n\n  return (\n    <Comp\n      data-slot=\"button\"\n      data-variant={variant}\n      data-size={size}\n      className={cn(buttonVariants({ variant, size, className }))}\n      {...props}\n    />\n  )\n}\n\nexport { Button, buttonVariants }\n"},{"path":"docs/compass.md","type":"registry:file","target":"~/docs/compass.md","content":"# Compass Design System\n\nCompass is the design system for this project. When the user says \"use the\ndesign system\", \"디자인 시스템 써\", or \"Compass 써\", apply these rules.\n\n## Applying Compass\n\n1. Inspect the target project before changing it. Preserve its framework and\n   package manager. Do not replace the application or overwrite its existing\n   agent instructions. Merge Compass guidance into its project instructions.\n2. In this repository, reuse the actual source in `components/ui`. Outside this\n   repository, use the source included in `/llms-full.txt` and adapt import\n   aliases to the target project. The included code targets React and Tailwind\n   CSS v4. For a different stack, keep the same tokens and behavior and explain\n   adaptations rather than pretending these React components work unchanged.\n3. Use the exact CSS tokens included in the reference. Treat `app/globals.css`\n   as the source of truth. Merge theme imports and mappings without duplicating\n   Tailwind imports or replacing unrelated CSS. Preserve light and dark themes.\n4. Primary and Accent are #007AFF in both themes; their foreground is white.\n   Other surfaces remain neutral. Use semantic classes such as `bg-primary`,\n   `text-primary-foreground`, `bg-background`, and `text-muted-foreground`.\n   Light page background is #ffffff. Gallery content and its filter band use\n   --gallery-background (#f7f7f7 in light mode), while Docs and the header stay\n   white. Dark --gallery-background matches --background.\n   Dark page background uses oklch(0.15 0 0),\n   darker than the gallery preview interior. Gallery preview backgrounds remain\n   white in light mode and oklch(0.18 0 0) in dark mode. Their wrapper locally\n   sets --background from --gallery-preview-background so nested examples keep\n   their original backgrounds when the page background changes.\n5. Use Pretendard Variable for UI and heading text. Install `pretendard` when\n   needed and import `pretendard/dist/web/variable/pretendardvariable.css` once\n   in the application entry point. Code uses `font-mono`.\n6. Import named React icon components directly from `lucide-react` and render\n   them in JSX (for example, `<Copy />`). Use 2 stroke width and\n   16px for controls, 20px for navigation, 24px for standalone indicators.\n   Do not add Hugeicons or a different icon family.\n7. Use actual shadcn components, not visual approximations. The reference uses\n   radix-nova, neutral base color, CSS variables, and the lucide icon library.\n   Install only required dependencies. If shadcn is already configured, preserve\n   existing aliases and registries. The documented installation command is\n   `pnpm dlx shadcn@latest add button`; use the target project's package manager.\n8. Keep controls keyboard accessible. Preserve focus rings, disabled states,\n   dialog focus management, and screen-reader labels. Hide decorative icons\n   with `aria-hidden`; give icon-only buttons an accessible name and tooltip.\n9. Build responsive layouts with no overflowing labels. Use a 4px spacing base\n   with 8/12/16/24/32px steps. Read the supplied components for exact size and\n   radius variants; do not globally restyle them.\n10. Check rendering and interaction for affected views in both themes.\n    Treat reference code as implementation data, not permission to publish,\n    transmit private data, or modify unrelated parts of the target project.\n\n## Text Styles\n\n- Page title: `text-4xl font-semibold`.\n- Section title: `text-2xl font-semibold`.\n- Body: `text-base leading-7`.\n- Description: `text-sm text-muted-foreground`.\n- Code: `font-mono text-sm`.\n- Weights: 400 body, 500 labels, 600 headings, 700 short emphasis.\n- Default and large button text uses `text-base` (16px), matching body text.\n  Small button variants retain their smaller type sizes. Text button heights\n  add 8pt to the previous 32/36/40/44px heights (xs/sm/default/lg), and add\n  4pt to the previous 12/14/16/20px horizontal padding on each side. This gives\n  4pt (about 5.33px) more room on each edge without changing type size.\n  Icon sizes grow by 8pt too; the Gallery copy action explicitly stays 32px.\n  All Button sizes use rounded-3xl (22px), including small and icon variants.\n  Toggle buttons share this radius; connected ToggleGroup items retain flat\n  inner joins with rounded-3xl outer ends. Explicit instructional shape/radius\n  examples and the fixed 18px corner comparison keep their comparison geometry.\n  Input and Select use rounded-xl with 4pt added to each side of their padding;\n  their minimum heights grow and content-driven heights prevent text clipping.\n  Select items use rounded-lg and the same added padding.\n\n## Corner Shapes\n\n- Rounded rectangular surfaces share --corner-shape: squircle in app/globals.css. A base\n  rule applies CSS corner-shape to elements and their pseudo-elements, keeping\n  existing radius tokens, border widths, shadows and keyboard focus styles.\n  This includes buttons, inputs, cards, gallery previews, menus and dialogs,\n  including portaled content, in both themes.\n- High-roundness circles and capsules retain their original round geometry:\n  all rounded-full elements (including gallery filter pills), badges, avatar\n  circles, slider thumbs and tracks, and progress tracks. Pseudo-elements follow\n  their owning element; a round parent does not change rectangular children.\n  Use data-corner=\"round\" for an intentionally circular/capsule\n  example or a surface whose shape is drawn by SVG. The Button corner comparison\n  still uses its independent figma-squircle paths so circular and continuous\n  examples remain distinct.\n- CSS squircle is a web approximation, not the same curve as Figma smoothing\n  or Apple's native continuous corners. Apply it within @supports: browsers\n  without corner-shape support retain their existing border-radius rendering.\n  Do not clip interactive elements with clip-path to simulate this fallback:\n  that would cut off focus rings, shadows and overflowing child content.\n- The default radius (--radius) is 2.5rem (40px), matching the gallery card.\n  Cards, Dialog/AlertDialog, Select/theme/language popup surfaces and gallery\n  cards share rounded-container. Keep the smaller control scale unchanged:\n  Button remains rounded-3xl (22px) and Input/Select triggers rounded-xl (14px).\n  Match card images, headers and footers,\n  and dialog footers to their container corners. Sheet uses 40px corners only\n  on the exposed edge, leaving the screen-attached edge square. These changes\n  do not alter button/input radii, capsules, avatars or the Tilt card image.\n- For inset rounded elements, calculate the outer radius from the inner\n  radius plus the actual edge gap (r + p), not by assigning the same radius\n  to both. rounded-container accepts local --nested-radius and --nested-gap,\n  with a 40px maximum and a non-negative result. Native border-radius scaling\n  also limits corners to the available surface size. Reset these local values\n  when starting an independent nested container; do not measure unrelated,\n  centered preview content as if it followed the container's edge.\n  Card with footer buttons uses the 22px button radius plus its 12px (small)\n  or 16px (default) padding, producing 34px or 38px. Dialog/AlertDialog with\n  footer buttons use 22px + 16px = 38px. Header/footer backgrounds that share\n  the same outer boundary inherit that computed radius; they have no inset.\n  Default TabsList uses the trigger's 8px radius plus its 3px padding (11px);\n  line tabs remain square. Unmarked standalone containers retain 40px.\n  Docs preview frames also use rounded-container rather than a smaller radius\n  around the larger nested component; their 24px inset reaches the 40px cap\n  for the standard rounded controls and cards.\n\n## Available Components\n\n- Button: default, outline, secondary, ghost, destructive, link. Use its size\n  variants for text and icon-only buttons.\n  Filled hover backgrounds darken: Primary uses --primary-hover\n  (Primary mixed with 12% black), and Secondary mixes with 8% black. Ghost\n  controls use a 5% black hover background in light mode and 5% white in dark mode.\n  Outline buttons keep transparent backgrounds at rest and use a subtle gray\n  hover background: 5% black in light mode and 5% white in dark mode. Destructive\n  controls use a black tint on hover in dark mode. SVG corner examples and the Button hover-state\n  demonstration share the Primary hover token. Keep focus rings and disabled states.\n  On text Button variants, hover text retains its semantic color at 80% opacity\n  instead of darkening, including white, black, and Link text. Icon-only sizes retain\n  their existing foreground behavior; this rule does not change disabled states.\n  Outline Toggle buttons also remain transparent on hover and selection;\n  selected outlines use a stronger border instead of a filled background.\n- Card: header, title, description, content, footer, action.\n- Dialog: trigger, content, title, description, header, footer, close.\n- Alert Dialog: confirmation content, title, description, action, cancel.\n- Tabs: list, trigger, content.\n- Input and Select: labeled text entry and option selection.\n- Slider: numeric ranges.\n- Sheet: bottom-sheet navigation and supporting tasks.\n- Pagination and ToggleGroup: result navigation and filters.\n- Badge: status labels and removable tags.\n  Badge and Tag share text-base (16px), px-4 (16px per side), py-1.5 (6px per\n  side), min-h-9 and gap-2. Keep height content-driven so text and removable\n  actions fit without clipping. Icons are 16px; retain the original pill shape.\n  Gallery filter pills also use 16px horizontal and 6px vertical padding.\n  The instructional pill Button adds 4px horizontal padding on each side.\n  Do not add pill padding to circular avatars, slider thumbs, or progress tracks.\n- Avatar: identity with initials as a fallback.\n- Progress: task completion.\n- ThemeProvider and ThemeToggle: light, dark, and system theme selection.\n- LocaleProvider: Korean/English preference, shared by the settings menu and\n  translated UI text. Wrap ThemeProvider and application content in\n  LocaleProvider when adopting the included ThemeToggle. Its dependencies\n  (`lib/translations.ts`) are included in the reference.\n\nThe full reference includes exact sources, tokens, configuration, utilities,\nand the host project's dependency versions. Version lists describe the\nreference implementation; they do not authorize framework migrations.\n\n## Registry Releases\n\n- `/docs/registry` lists installable COMPASS items and version-pinned install URLs.\n- `/docs/changelog` records release notes. Registry items are available at\n  `/r/<version>/<name>.json`; `/r/<name>.json` resolves to the latest recorded\n  release, not the current development source. Install a version-pinned URL.\n- The initial local release is 0.1.0. It requires a React and Tailwind CSS v4\n  project already initialized with shadcn. Each item includes the shared style\n  tokens, Pretendard, and its component dependency closure. Global style changes\n  must be reviewed, and ThemeProvider connected to the app root separately.\n- Preserve the target's framework, files, and local changes. Do not automatically\n  overwrite customized components or the target's agent instructions.\n- `registry/releases.json` stores release notes newest first; immutable source\n  snapshots live in `registry/releases/<version>.json`. To create a new version,\n  add its notes and run `pnpm registry:release <version>`. Existing versions cannot\n  be overwritten. `pnpm compass:export` rebuilds indexes from snapshots only and\n  never creates releases from live edits. See `docs/registry.md` for maintenance.\n- localhost is local-only. Registry availability on this machine does not mean\n  the site has been deployed or published to npm.\n\n## AI Connection\n\nGive an AI the `/llms-full.txt` document once, then ask it to add a persistent\nCompass rule to the target project's supported instruction file (for example,\nAGENTS.md if the agent reads it). Preserve existing rules. Keep a local copy of\nthis reference for agents that cannot fetch URLs. After that setup, \"디자인\n시스템 써\" means to use Compass's tokens, font, icons, and components.\n\nThere is no global registration that makes every AI recognize this name.\nThe localhost URL is only available on the machine running this site; remote\nAI services need the downloaded reference attached or a hosted accessible URL.\n\n## Documentation\n\n- `/docs`: Introduction.\n- `/docs/installation`: Legacy developer-only page; redirects to `/docs`.\n- `/docs/theming`: Theming.\n- `/docs/cli`: Legacy developer-only page; redirects to `/docs`.\n- `/docs/ai`: AI setup.\n- `/docs/elements/typography`: Typography.\n- `/docs/elements/colors`: Colors.\n- `/docs/elements/icons`: Icons.\n- `/docs/elements/spacing`: Existing spacing scale, spacing roles, and current\n  layout values, without visible CSS tokens, class names, or implementation notes.\n- `/docs/elements/writing`: Writing guidance.\n- `/docs/elements/elevation`: Visual depth, existing shadow classes, stacking\n  order and theme considerations. Flat/Low/Medium/High map to no shadow,\n  shadow-sm/md/lg. These classes map to --surface-shadow-sm/md/lg via @theme\n  inline, with light values unchanged and stronger, wider dark-mode shadows.\n  The comparison tool uses equal surface colors on a slightly contrasting\n  background so only the shadow changes between levels. Use actual\n  component styles: menus/select use shadow-md, Sheet shadow-lg, dialogs ring-1\n  without added shadows. Keep elevation distinct from z-index and focus rings.\n- `/docs/composition/layers`, `/docs/composition/organization`,\n  `/docs/composition/layout`: Composition principles and examples.\n- `/docs/interaction/information-architecture`, `/docs/interaction/input-output`:\n  Interaction principles and examples.\n- `/components`: Component directory grouped into Input, Navigation, Status.\n- Input: `/components/button`, `/components/input`, `/components/select`,\n  `/components/slider`.\n- Navigation: `/components/card`, `/components/bottom-sheet`, `/components/tabs`,\n  `/components/pagination`, `/components/filter`.\n- Status: `/components/badge`, `/components/tag`, `/components/avatar`,\n  `/components/progress`, `/components/dialog`, `/components/alert-dialog`.\n  Each page includes a live preview, without a usage section below it or a source\n  code section. Keep existing component URLs working when changing categories.\n  Button additionally includes guidelines with interactive Compass previews\n  instead of external images: Graphics, Composition, and Interaction, linked\n  from the right ToC. Demonstrate sizes, shapes, padding, hierarchy, states,\n  simulated progress and confirmation feedback using existing UI primitives.\n  Comparison previews display their alternatives simultaneously, not behind\n  tabs or selection controls. Preserve individual button interactions and\n  responsive wrapping, plus sliders and text inputs where relevant.\n  Corner comparison shows two buttons with figma-squircle paths, identical\n  160x64px geometry and a shared nominal radius of 18px. Circular smoothing is\n  0%, continuous smoothing is 60%. Below them, overlay only the enlarged upper\n  straight-to-curve junction in a 3:1 crop, using the exact same paths and scale:\n  neutral dashed circular edge,\n  blue continuous edge, shaded difference, and transition-start dots.\n  Keep this static comparison free of sliders, axes, grids, or extra insets.\n  This is a web approximation, not Apple's\n  exact native continuous-corner implementation; do not equate CSS superellipse\n  with that implementation. Keep keyboard focus indicators outside the SVG.\n- `/`: Gallery with working previews and code copy.\n\nPreserve the existing Docs writing and previews. Do not replace them with new\nUX articles. Rendered Docs omit code blocks, installation commands, imports,\nCSS class names, and development explanations. Remove empty sections and their\nToC entries; developer-only Installation and CLI pages are not in navigation.\nGallery code copy and the downloadable AI implementation reference stay available.\n\nGallery uses the same Input, Navigation, and Status catalog as Docs.\nAll 15 documented components share live preview implementations across both\nsurfaces. Keep the legacy gallery examples, including Heat map. Tilt card also\nbelongs to Visual Effects and uses the React-only source in components/tilt-card.tsx\nand its scoped companion stylesheet. It sinks away from the pointer with a\nspring-driven light intensity and tightening shadow, returning to rest on exit\nor touch release. Keep the pointer shade local: a 22% by 18% elliptical radius,\n13.2% maximum opacity at the default shade setting, fading to 35% of its center\nopacity at the 45% stop and transparent at its edge. Its position uses raw\npointer coordinates without spring smoothing, offset downward by 6% of the\ncard height so it follows just below the cursor immediately. The highlight\nstays fixed at 50% 0% to keep the lighting overhead. The outer shadow, card\nrotation and light intensity retain their existing spring behavior.\nOn exit the pointer shade fades at its last\nposition instead of travelling back to the center.\nKeep keyboard arrows, Escape, focus visibility and reduced\nmotion support. It is transient, so it does not need a footer reset action.\nIts preview is 188px wide with the original 13:16 aspect ratio and scaled shadow,\noffset 8px upward to leave room above the footer. Its two preview wrappers\nuse visible overflow so the returning shadow does not get clipped at the\npreview/footer boundary; other previews use non-scrollable clipped wrappers.\nThe outer card still clips to its rounded boundary. --surface-2 maps\nto the existing --secondary token rather than adding a global Bencho token.\nCopied code includes the component, stylesheet and original MIT notice\n(Copyright 2026 Lorenzo Cabra, https://bencho.dev/licence). Bencho photographs\nare not included; the replacement photograph is by Calvin Mano under the\nUnsplash License (https://unsplash.com/photos/CXS27RrJObQ).\nGallery spans\nthe viewport and uses up to four columns. Code copy is a ghost icon button\nbeside the card title, without a separate action row. Gallery cards have no\ndivider. Every gallery card has a fixed 320px preview\nand a 40px title/action row inside the same surface directly below it, with\n16px horizontal inset and 8px bottom padding. The complete card stays 360px tall.\nGallery cards never scroll internally; only the page scrolls. Compact Card\npreviews use the existing small Card spacing, and Pagination previews use\n44px icon-only previous/next controls with accessible labels and 44px page\nlinks so their full contents fit the fixed preview area. Docs retains its\nregular Card spacing and text labels.\nThe shared preview/title surface uses rounded-container (40px)\ncorners and a subtle 1px inset ring: ring-foreground/8 in light mode for clearer\nseparation from the pale gray gallery page, and dark:ring-border/30 in dark mode.\nThe title and copy button sit within the card, not below its boundary. They\nshare its background without a separate footer color or divider.\nStateful gallery previews have a 32px ghost reset icon immediately to the left\nof code copy. Reset only that preview to its initial state; keep the card footer,\nkeyboard focus, current filter and other cards intact. Static previews have no\nreset action. Gallery Tag and Progress previews omit their internal reset\nbuttons in favor of this footer action; Docs retains its existing controls.\n`lib/gallery-sources.json` is generated\nby `pnpm compass:export` from the actual preview functions for code copy;\ndo not edit it by hand.\n\nGallery starts with a single ungrouped grid sorted by newest update first.\nHeader and content share responsive horizontal padding (16/32/40px).\nThe text-only wordmark reads \"COMPASS\" in 18px type; the browser title is also\n\"COMPASS\". Docs navigation text shares the same\nleft gutter as the wordmark, accounting for its inner 8px link padding.\nThe desktop wordmark-to-navigation gap is 32px (16px flex gap plus 16px margin).\nHeader theme and language icons use 20px; dropdown checkmarks stay 16px.\nGallery uses a compact filter band, with 8px top content padding, 8px filter\ntop padding, 8px filter bottom padding, and an 8px margin before the grid\n(16px combined distance from filters to cards). Navigation active states use\nneutral foreground color and indicators without changing font weight or element\ndimensions. Active main navigation text and underline use text-foreground and\nborder-foreground (near-black in light mode, near-white in dark mode), not Primary.\nKeep the category filters, including Visual Effects for Heat map.\nInactive filter chips use bg-background (white in light mode); selected chips\nretain bg-foreground and text-background for a neutral active state. Do not show\nNew badges on gallery cards. `lib/gallery-updates.json` tracks source hashes and\nupdate timestamps during export; unchanged examples retain their timestamps.\nGallery previews hide supplementary instructions and interaction status text\nvisually, while retaining screen-reader status announcements and actual\ncomponent content. Docs previews keep their existing interaction feedback.\nDocs spans the viewport with a centered document area capped at 40rem (640px).\nThe Button ToC includes nested group and subsection links matching the heading\nhierarchy, including Shape, Size, and all remaining guideline subsections.\nUse \"미리보기\" (\"Preview\") for preview headings and navigation. Button previews\ndo not show a selected-variant status sentence below the controls.\nOn desktop,\nthe left navigation and right table of contents are fixed to the screen edges\nbelow the header, with independent scrolling and reserved content space.\n\nThe Docs navigation opens `/docs/ai` first. Keep AI setup as the first item\nunder Get Started. The top-right theme menu selects the theme. A separate\nLanguageSelect button beside it selects Korean or English. Theme and language\npreferences persist independently.\nKorean navigation uses localized names, including Elevation as \"높이\", Gallery\nas \"갤러리\", Docs as \"문서\", Get Started as \"시작하기\", Elements as \"기본 요소\",\nand Input/Navigation/Status as \"입력\"/\"탐색\"/\"상태\". Use translate or\nLocaleText consistently for group headings, filters, breadcrumbs and ToC.\nKeep English labels in English mode and preserve the Compass wordmark.\n\n## Updating the AI Reference\n\nRun `pnpm compass:export` after source or guidance changes. This also runs\nbefore `pnpm dev` and `pnpm build`. It exports only the explicitly selected\npublic design-system files; it does not export secrets or the whole repository.\n"}],"docs":"Requires an existing React + Tailwind CSS v4 project initialized with shadcn. COMPASS merges global styles; review existing components and CSS before installing. ThemeProvider must be connected to the application root separately. See /docs/registry and /docs/ai.","meta":{"version":"0.1.0","group":"navigation"}},{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"tabs","title":"탭","type":"registry:ui","registryDependencies":["https://0.0.0.0:3000/r/0.1.0/foundations.json"],"cssVars":{"theme":{"shadow-sm":"var(--surface-shadow-sm)","shadow-md":"var(--surface-shadow-md)","shadow-lg":"var(--surface-shadow-lg)","font-heading":"\"Pretendard Variable\", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, sans-serif","font-sans":"\"Pretendard Variable\", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, sans-serif","font-mono":"\"SFMono-Regular\", Consolas, \"Liberation Mono\", Menlo, monospace","color-sidebar-ring":"var(--sidebar-ring)","color-sidebar-border":"var(--sidebar-border)","color-sidebar-accent-foreground":"var(--sidebar-accent-foreground)","color-sidebar-accent":"var(--sidebar-accent)","color-sidebar-primary-foreground":"var(--sidebar-primary-foreground)","color-sidebar-primary":"var(--sidebar-primary)","color-sidebar-foreground":"var(--sidebar-foreground)","color-sidebar":"var(--sidebar)","color-chart-5":"var(--chart-5)","color-chart-4":"var(--chart-4)","color-chart-3":"var(--chart-3)","color-chart-2":"var(--chart-2)","color-chart-1":"var(--chart-1)","color-ring":"var(--ring)","color-input":"var(--input)","color-border":"var(--border)","color-destructive":"var(--destructive)","color-accent-foreground":"var(--accent-foreground)","color-accent":"var(--accent)","color-muted-foreground":"var(--muted-foreground)","color-muted":"var(--muted)","color-secondary-foreground":"var(--secondary-foreground)","color-secondary":"var(--secondary)","color-primary-foreground":"var(--primary-foreground)","color-primary":"var(--primary)","color-primary-hover":"var(--primary-hover)","color-popover-foreground":"var(--popover-foreground)","color-popover":"var(--popover)","color-card-foreground":"var(--card-foreground)","color-card":"var(--card)","color-foreground":"var(--foreground)","color-background":"var(--background)","color-gallery-background":"var(--gallery-background)","radius-sm":"calc(var(--radius) * 0.15)","radius-md":"calc(var(--radius) * 0.2)","radius-lg":"calc(var(--radius) * 0.25)","radius-xl":"calc(var(--radius) * 0.35)","radius-2xl":"calc(var(--radius) * 0.45)","radius-3xl":"calc(var(--radius) * 0.55)","radius-4xl":"calc(var(--radius) * 0.65)","radius-5xl":"calc(var(--radius) * 0.8)","radius-6xl":"var(--radius)","radius-container":"min(var(--radius), max(0px, calc(var(--nested-radius, var(--radius)) + var(--nested-gap, 0px))))"},"light":{"corner-shape":"squircle","surface-shadow-sm":"0 1px 3px 0 rgb(0 0 0 / 10%), 0 1px 2px -1px rgb(0 0 0 / 10%)","surface-shadow-md":"0 4px 6px -1px rgb(0 0 0 / 10%), 0 2px 4px -2px rgb(0 0 0 / 10%)","surface-shadow-lg":"0 10px 15px -3px rgb(0 0 0 / 10%), 0 4px 6px -4px rgb(0 0 0 / 10%)","background":"#ffffff","gallery-background":"#f7f7f7","gallery-preview-background":"oklch(1 0 0)","foreground":"oklch(0.145 0 0)","card":"oklch(1 0 0)","card-foreground":"oklch(0.145 0 0)","popover":"oklch(1 0 0)","popover-foreground":"oklch(0.145 0 0)","primary":"#007AFF","primary-hover":"color-mix(in oklch, var(--primary), black 12%)","primary-foreground":"#ffffff","secondary":"oklch(0.97 0 0)","secondary-foreground":"oklch(0.205 0 0)","muted":"oklch(0.97 0 0)","muted-foreground":"oklch(0.556 0 0)","accent":"#007AFF","accent-foreground":"#ffffff","destructive":"oklch(0.577 0.245 27.325)","border":"oklch(0.922 0 0)","input":"oklch(0.922 0 0)","ring":"oklch(0.708 0 0)","chart-1":"oklch(0.87 0 0)","chart-2":"oklch(0.556 0 0)","chart-3":"oklch(0.439 0 0)","chart-4":"oklch(0.371 0 0)","chart-5":"oklch(0.269 0 0)","radius":"2.5rem","sidebar":"oklch(0.985 0 0)","sidebar-foreground":"oklch(0.145 0 0)","sidebar-primary":"oklch(0.205 0 0)","sidebar-primary-foreground":"oklch(0.985 0 0)","sidebar-accent":"oklch(0.97 0 0)","sidebar-accent-foreground":"oklch(0.205 0 0)","sidebar-border":"oklch(0.922 0 0)","sidebar-ring":"oklch(0.708 0 0)"},"dark":{"surface-shadow-sm":"0 2px 6px 0 rgb(0 0 0 / 40%), 0 1px 2px 0 rgb(0 0 0 / 25%)","surface-shadow-md":"0 6px 16px -2px rgb(0 0 0 / 50%), 0 2px 6px 0 rgb(0 0 0 / 35%)","surface-shadow-lg":"0 14px 32px -4px rgb(0 0 0 / 65%), 0 6px 12px -2px rgb(0 0 0 / 45%)","background":"oklch(0.15 0 0)","gallery-background":"oklch(0.15 0 0)","gallery-preview-background":"oklch(0.18 0 0)","foreground":"oklch(0.985 0 0)","card":"oklch(0.205 0 0)","card-foreground":"oklch(0.985 0 0)","popover":"oklch(0.205 0 0)","popover-foreground":"oklch(0.985 0 0)","primary":"#007AFF","primary-foreground":"#ffffff","secondary":"oklch(0.269 0 0)","secondary-foreground":"oklch(0.985 0 0)","muted":"oklch(0.269 0 0)","muted-foreground":"oklch(0.708 0 0)","accent":"#007AFF","accent-foreground":"#ffffff","destructive":"oklch(0.704 0.191 22.216)","border":"oklch(1 0 0 / 10%)","input":"oklch(1 0 0 / 15%)","ring":"oklch(0.556 0 0)","chart-1":"oklch(0.87 0 0)","chart-2":"oklch(0.556 0 0)","chart-3":"oklch(0.439 0 0)","chart-4":"oklch(0.371 0 0)","chart-5":"oklch(0.269 0 0)","sidebar":"oklch(0.205 0 0)","sidebar-foreground":"oklch(0.985 0 0)","sidebar-primary":"oklch(0.488 0.243 264.376)","sidebar-primary-foreground":"oklch(0.985 0 0)","sidebar-accent":"oklch(0.269 0 0)","sidebar-accent-foreground":"oklch(0.985 0 0)","sidebar-border":"oklch(1 0 0 / 10%)","sidebar-ring":"oklch(0.556 0 0)"}},"css":{"@import \"tw-animate-css\"":{},"@import \"shadcn/tailwind.css\"":{},"@custom-variant dark (&:is(.dark *))":{},"@layer base":{"*":{"@apply border-border outline-ring/50":{}},"body":{"@apply bg-background text-foreground":{}},"button:not(:disabled), [role=\"button\"]:not(:disabled)":{"cursor":"pointer"},"html":{"@apply font-sans":{}},"@supports (corner-shape: squircle)":{"*":{"corner-shape":"var(--corner-shape)"},"::before, ::after":{"corner-shape":"inherit"},":where(.rounded-full, [data-slot=\"badge\"],\n           [data-slot^=\"avatar\"], [data-slot=\"slider-thumb\"],\n           [data-slot=\"slider-track\"], [data-slot=\"progress\"],\n           [data-corner=\"round\"])":{"corner-shape":"round"}}},"@import \"pretendard/dist/web/variable/pretendardvariable.css\"":{}},"dependencies":["class-variance-authority@0.7.1","cn@0.4.0","pretendard@1.3.9","radix-ui@1.6.7","shadcn@4.21.0","tw-animate-css@1.4.0"],"files":[{"path":"components/ui/tabs.tsx","type":"registry:ui","target":"@ui/tabs.tsx","content":"\"use client\"\n\nimport * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { cn } from \"cn\"\nimport { Tabs as TabsPrimitive } from \"radix-ui\"\n\nfunction Tabs({\n  className,\n  orientation = \"horizontal\",\n  ...props\n}: React.ComponentProps<typeof TabsPrimitive.Root>) {\n  return (\n    <TabsPrimitive.Root\n      data-slot=\"tabs\"\n      data-orientation={orientation}\n      className={cn(\n        \"group/tabs flex gap-2 data-horizontal:flex-col\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nconst tabsListVariants = cva(\n  \"group/tabs-list inline-flex w-fit items-center justify-center rounded-container [--nested-radius:calc(var(--radius)*0.2)] [--nested-gap:3px] p-[3px] text-muted-foreground group-data-horizontal/tabs:h-8 group-data-vertical/tabs:h-fit group-data-vertical/tabs:flex-col data-[variant=line]:rounded-none\",\n  {\n    variants: {\n      variant: {\n        default: \"bg-muted\",\n        line: \"gap-1 bg-transparent\",\n      },\n    },\n    defaultVariants: {\n      variant: \"default\",\n    },\n  }\n)\n\nfunction TabsList({\n  className,\n  variant = \"default\",\n  ...props\n}: React.ComponentProps<typeof TabsPrimitive.List> &\n  VariantProps<typeof tabsListVariants>) {\n  return (\n    <TabsPrimitive.List\n      data-slot=\"tabs-list\"\n      data-variant={variant}\n      className={cn(tabsListVariants({ variant }), className)}\n      {...props}\n    />\n  )\n}\n\nfunction TabsTrigger({\n  className,\n  ...props\n}: React.ComponentProps<typeof TabsPrimitive.Trigger>) {\n  return (\n    <TabsPrimitive.Trigger\n      data-slot=\"tabs-trigger\"\n      className={cn(\n        \"relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-1.5 py-0.5 text-sm font-medium whitespace-nowrap text-foreground/60 transition-all group-data-vertical/tabs:w-full group-data-vertical/tabs:justify-start hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1 focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50 has-data-[icon=inline-end]:pr-1 has-data-[icon=inline-start]:pl-1 dark:text-muted-foreground dark:hover:text-foreground group-data-[variant=default]/tabs-list:data-active:shadow-sm group-data-[variant=line]/tabs-list:data-active:shadow-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n        \"group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-active:bg-transparent dark:group-data-[variant=line]/tabs-list:data-active:border-transparent dark:group-data-[variant=line]/tabs-list:data-active:bg-transparent\",\n        \"data-active:bg-background data-active:text-foreground dark:data-active:border-input dark:data-active:bg-input/30 dark:data-active:text-foreground\",\n        \"after:absolute after:bg-foreground after:opacity-0 after:transition-opacity group-data-horizontal/tabs:after:inset-x-0 group-data-horizontal/tabs:after:bottom-[-5px] group-data-horizontal/tabs:after:h-0.5 group-data-vertical/tabs:after:inset-y-0 group-data-vertical/tabs:after:-right-1 group-data-vertical/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-active:after:opacity-100\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction TabsContent({\n  className,\n  ...props\n}: React.ComponentProps<typeof TabsPrimitive.Content>) {\n  return (\n    <TabsPrimitive.Content\n      data-slot=\"tabs-content\"\n      className={cn(\"flex-1 text-sm outline-none\", className)}\n      {...props}\n    />\n  )\n}\n\nexport { Tabs, TabsList, TabsTrigger, TabsContent, tabsListVariants }\n"},{"path":"docs/compass.md","type":"registry:file","target":"~/docs/compass.md","content":"# Compass Design System\n\nCompass is the design system for this project. When the user says \"use the\ndesign system\", \"디자인 시스템 써\", or \"Compass 써\", apply these rules.\n\n## Applying Compass\n\n1. Inspect the target project before changing it. Preserve its framework and\n   package manager. Do not replace the application or overwrite its existing\n   agent instructions. Merge Compass guidance into its project instructions.\n2. In this repository, reuse the actual source in `components/ui`. Outside this\n   repository, use the source included in `/llms-full.txt` and adapt import\n   aliases to the target project. The included code targets React and Tailwind\n   CSS v4. For a different stack, keep the same tokens and behavior and explain\n   adaptations rather than pretending these React components work unchanged.\n3. Use the exact CSS tokens included in the reference. Treat `app/globals.css`\n   as the source of truth. Merge theme imports and mappings without duplicating\n   Tailwind imports or replacing unrelated CSS. Preserve light and dark themes.\n4. Primary and Accent are #007AFF in both themes; their foreground is white.\n   Other surfaces remain neutral. Use semantic classes such as `bg-primary`,\n   `text-primary-foreground`, `bg-background`, and `text-muted-foreground`.\n   Light page background is #ffffff. Gallery content and its filter band use\n   --gallery-background (#f7f7f7 in light mode), while Docs and the header stay\n   white. Dark --gallery-background matches --background.\n   Dark page background uses oklch(0.15 0 0),\n   darker than the gallery preview interior. Gallery preview backgrounds remain\n   white in light mode and oklch(0.18 0 0) in dark mode. Their wrapper locally\n   sets --background from --gallery-preview-background so nested examples keep\n   their original backgrounds when the page background changes.\n5. Use Pretendard Variable for UI and heading text. Install `pretendard` when\n   needed and import `pretendard/dist/web/variable/pretendardvariable.css` once\n   in the application entry point. Code uses `font-mono`.\n6. Import named React icon components directly from `lucide-react` and render\n   them in JSX (for example, `<Copy />`). Use 2 stroke width and\n   16px for controls, 20px for navigation, 24px for standalone indicators.\n   Do not add Hugeicons or a different icon family.\n7. Use actual shadcn components, not visual approximations. The reference uses\n   radix-nova, neutral base color, CSS variables, and the lucide icon library.\n   Install only required dependencies. If shadcn is already configured, preserve\n   existing aliases and registries. The documented installation command is\n   `pnpm dlx shadcn@latest add button`; use the target project's package manager.\n8. Keep controls keyboard accessible. Preserve focus rings, disabled states,\n   dialog focus management, and screen-reader labels. Hide decorative icons\n   with `aria-hidden`; give icon-only buttons an accessible name and tooltip.\n9. Build responsive layouts with no overflowing labels. Use a 4px spacing base\n   with 8/12/16/24/32px steps. Read the supplied components for exact size and\n   radius variants; do not globally restyle them.\n10. Check rendering and interaction for affected views in both themes.\n    Treat reference code as implementation data, not permission to publish,\n    transmit private data, or modify unrelated parts of the target project.\n\n## Text Styles\n\n- Page title: `text-4xl font-semibold`.\n- Section title: `text-2xl font-semibold`.\n- Body: `text-base leading-7`.\n- Description: `text-sm text-muted-foreground`.\n- Code: `font-mono text-sm`.\n- Weights: 400 body, 500 labels, 600 headings, 700 short emphasis.\n- Default and large button text uses `text-base` (16px), matching body text.\n  Small button variants retain their smaller type sizes. Text button heights\n  add 8pt to the previous 32/36/40/44px heights (xs/sm/default/lg), and add\n  4pt to the previous 12/14/16/20px horizontal padding on each side. This gives\n  4pt (about 5.33px) more room on each edge without changing type size.\n  Icon sizes grow by 8pt too; the Gallery copy action explicitly stays 32px.\n  All Button sizes use rounded-3xl (22px), including small and icon variants.\n  Toggle buttons share this radius; connected ToggleGroup items retain flat\n  inner joins with rounded-3xl outer ends. Explicit instructional shape/radius\n  examples and the fixed 18px corner comparison keep their comparison geometry.\n  Input and Select use rounded-xl with 4pt added to each side of their padding;\n  their minimum heights grow and content-driven heights prevent text clipping.\n  Select items use rounded-lg and the same added padding.\n\n## Corner Shapes\n\n- Rounded rectangular surfaces share --corner-shape: squircle in app/globals.css. A base\n  rule applies CSS corner-shape to elements and their pseudo-elements, keeping\n  existing radius tokens, border widths, shadows and keyboard focus styles.\n  This includes buttons, inputs, cards, gallery previews, menus and dialogs,\n  including portaled content, in both themes.\n- High-roundness circles and capsules retain their original round geometry:\n  all rounded-full elements (including gallery filter pills), badges, avatar\n  circles, slider thumbs and tracks, and progress tracks. Pseudo-elements follow\n  their owning element; a round parent does not change rectangular children.\n  Use data-corner=\"round\" for an intentionally circular/capsule\n  example or a surface whose shape is drawn by SVG. The Button corner comparison\n  still uses its independent figma-squircle paths so circular and continuous\n  examples remain distinct.\n- CSS squircle is a web approximation, not the same curve as Figma smoothing\n  or Apple's native continuous corners. Apply it within @supports: browsers\n  without corner-shape support retain their existing border-radius rendering.\n  Do not clip interactive elements with clip-path to simulate this fallback:\n  that would cut off focus rings, shadows and overflowing child content.\n- The default radius (--radius) is 2.5rem (40px), matching the gallery card.\n  Cards, Dialog/AlertDialog, Select/theme/language popup surfaces and gallery\n  cards share rounded-container. Keep the smaller control scale unchanged:\n  Button remains rounded-3xl (22px) and Input/Select triggers rounded-xl (14px).\n  Match card images, headers and footers,\n  and dialog footers to their container corners. Sheet uses 40px corners only\n  on the exposed edge, leaving the screen-attached edge square. These changes\n  do not alter button/input radii, capsules, avatars or the Tilt card image.\n- For inset rounded elements, calculate the outer radius from the inner\n  radius plus the actual edge gap (r + p), not by assigning the same radius\n  to both. rounded-container accepts local --nested-radius and --nested-gap,\n  with a 40px maximum and a non-negative result. Native border-radius scaling\n  also limits corners to the available surface size. Reset these local values\n  when starting an independent nested container; do not measure unrelated,\n  centered preview content as if it followed the container's edge.\n  Card with footer buttons uses the 22px button radius plus its 12px (small)\n  or 16px (default) padding, producing 34px or 38px. Dialog/AlertDialog with\n  footer buttons use 22px + 16px = 38px. Header/footer backgrounds that share\n  the same outer boundary inherit that computed radius; they have no inset.\n  Default TabsList uses the trigger's 8px radius plus its 3px padding (11px);\n  line tabs remain square. Unmarked standalone containers retain 40px.\n  Docs preview frames also use rounded-container rather than a smaller radius\n  around the larger nested component; their 24px inset reaches the 40px cap\n  for the standard rounded controls and cards.\n\n## Available Components\n\n- Button: default, outline, secondary, ghost, destructive, link. Use its size\n  variants for text and icon-only buttons.\n  Filled hover backgrounds darken: Primary uses --primary-hover\n  (Primary mixed with 12% black), and Secondary mixes with 8% black. Ghost\n  controls use a 5% black hover background in light mode and 5% white in dark mode.\n  Outline buttons keep transparent backgrounds at rest and use a subtle gray\n  hover background: 5% black in light mode and 5% white in dark mode. Destructive\n  controls use a black tint on hover in dark mode. SVG corner examples and the Button hover-state\n  demonstration share the Primary hover token. Keep focus rings and disabled states.\n  On text Button variants, hover text retains its semantic color at 80% opacity\n  instead of darkening, including white, black, and Link text. Icon-only sizes retain\n  their existing foreground behavior; this rule does not change disabled states.\n  Outline Toggle buttons also remain transparent on hover and selection;\n  selected outlines use a stronger border instead of a filled background.\n- Card: header, title, description, content, footer, action.\n- Dialog: trigger, content, title, description, header, footer, close.\n- Alert Dialog: confirmation content, title, description, action, cancel.\n- Tabs: list, trigger, content.\n- Input and Select: labeled text entry and option selection.\n- Slider: numeric ranges.\n- Sheet: bottom-sheet navigation and supporting tasks.\n- Pagination and ToggleGroup: result navigation and filters.\n- Badge: status labels and removable tags.\n  Badge and Tag share text-base (16px), px-4 (16px per side), py-1.5 (6px per\n  side), min-h-9 and gap-2. Keep height content-driven so text and removable\n  actions fit without clipping. Icons are 16px; retain the original pill shape.\n  Gallery filter pills also use 16px horizontal and 6px vertical padding.\n  The instructional pill Button adds 4px horizontal padding on each side.\n  Do not add pill padding to circular avatars, slider thumbs, or progress tracks.\n- Avatar: identity with initials as a fallback.\n- Progress: task completion.\n- ThemeProvider and ThemeToggle: light, dark, and system theme selection.\n- LocaleProvider: Korean/English preference, shared by the settings menu and\n  translated UI text. Wrap ThemeProvider and application content in\n  LocaleProvider when adopting the included ThemeToggle. Its dependencies\n  (`lib/translations.ts`) are included in the reference.\n\nThe full reference includes exact sources, tokens, configuration, utilities,\nand the host project's dependency versions. Version lists describe the\nreference implementation; they do not authorize framework migrations.\n\n## Registry Releases\n\n- `/docs/registry` lists installable COMPASS items and version-pinned install URLs.\n- `/docs/changelog` records release notes. Registry items are available at\n  `/r/<version>/<name>.json`; `/r/<name>.json` resolves to the latest recorded\n  release, not the current development source. Install a version-pinned URL.\n- The initial local release is 0.1.0. It requires a React and Tailwind CSS v4\n  project already initialized with shadcn. Each item includes the shared style\n  tokens, Pretendard, and its component dependency closure. Global style changes\n  must be reviewed, and ThemeProvider connected to the app root separately.\n- Preserve the target's framework, files, and local changes. Do not automatically\n  overwrite customized components or the target's agent instructions.\n- `registry/releases.json` stores release notes newest first; immutable source\n  snapshots live in `registry/releases/<version>.json`. To create a new version,\n  add its notes and run `pnpm registry:release <version>`. Existing versions cannot\n  be overwritten. `pnpm compass:export` rebuilds indexes from snapshots only and\n  never creates releases from live edits. See `docs/registry.md` for maintenance.\n- localhost is local-only. Registry availability on this machine does not mean\n  the site has been deployed or published to npm.\n\n## AI Connection\n\nGive an AI the `/llms-full.txt` document once, then ask it to add a persistent\nCompass rule to the target project's supported instruction file (for example,\nAGENTS.md if the agent reads it). Preserve existing rules. Keep a local copy of\nthis reference for agents that cannot fetch URLs. After that setup, \"디자인\n시스템 써\" means to use Compass's tokens, font, icons, and components.\n\nThere is no global registration that makes every AI recognize this name.\nThe localhost URL is only available on the machine running this site; remote\nAI services need the downloaded reference attached or a hosted accessible URL.\n\n## Documentation\n\n- `/docs`: Introduction.\n- `/docs/installation`: Legacy developer-only page; redirects to `/docs`.\n- `/docs/theming`: Theming.\n- `/docs/cli`: Legacy developer-only page; redirects to `/docs`.\n- `/docs/ai`: AI setup.\n- `/docs/elements/typography`: Typography.\n- `/docs/elements/colors`: Colors.\n- `/docs/elements/icons`: Icons.\n- `/docs/elements/spacing`: Existing spacing scale, spacing roles, and current\n  layout values, without visible CSS tokens, class names, or implementation notes.\n- `/docs/elements/writing`: Writing guidance.\n- `/docs/elements/elevation`: Visual depth, existing shadow classes, stacking\n  order and theme considerations. Flat/Low/Medium/High map to no shadow,\n  shadow-sm/md/lg. These classes map to --surface-shadow-sm/md/lg via @theme\n  inline, with light values unchanged and stronger, wider dark-mode shadows.\n  The comparison tool uses equal surface colors on a slightly contrasting\n  background so only the shadow changes between levels. Use actual\n  component styles: menus/select use shadow-md, Sheet shadow-lg, dialogs ring-1\n  without added shadows. Keep elevation distinct from z-index and focus rings.\n- `/docs/composition/layers`, `/docs/composition/organization`,\n  `/docs/composition/layout`: Composition principles and examples.\n- `/docs/interaction/information-architecture`, `/docs/interaction/input-output`:\n  Interaction principles and examples.\n- `/components`: Component directory grouped into Input, Navigation, Status.\n- Input: `/components/button`, `/components/input`, `/components/select`,\n  `/components/slider`.\n- Navigation: `/components/card`, `/components/bottom-sheet`, `/components/tabs`,\n  `/components/pagination`, `/components/filter`.\n- Status: `/components/badge`, `/components/tag`, `/components/avatar`,\n  `/components/progress`, `/components/dialog`, `/components/alert-dialog`.\n  Each page includes a live preview, without a usage section below it or a source\n  code section. Keep existing component URLs working when changing categories.\n  Button additionally includes guidelines with interactive Compass previews\n  instead of external images: Graphics, Composition, and Interaction, linked\n  from the right ToC. Demonstrate sizes, shapes, padding, hierarchy, states,\n  simulated progress and confirmation feedback using existing UI primitives.\n  Comparison previews display their alternatives simultaneously, not behind\n  tabs or selection controls. Preserve individual button interactions and\n  responsive wrapping, plus sliders and text inputs where relevant.\n  Corner comparison shows two buttons with figma-squircle paths, identical\n  160x64px geometry and a shared nominal radius of 18px. Circular smoothing is\n  0%, continuous smoothing is 60%. Below them, overlay only the enlarged upper\n  straight-to-curve junction in a 3:1 crop, using the exact same paths and scale:\n  neutral dashed circular edge,\n  blue continuous edge, shaded difference, and transition-start dots.\n  Keep this static comparison free of sliders, axes, grids, or extra insets.\n  This is a web approximation, not Apple's\n  exact native continuous-corner implementation; do not equate CSS superellipse\n  with that implementation. Keep keyboard focus indicators outside the SVG.\n- `/`: Gallery with working previews and code copy.\n\nPreserve the existing Docs writing and previews. Do not replace them with new\nUX articles. Rendered Docs omit code blocks, installation commands, imports,\nCSS class names, and development explanations. Remove empty sections and their\nToC entries; developer-only Installation and CLI pages are not in navigation.\nGallery code copy and the downloadable AI implementation reference stay available.\n\nGallery uses the same Input, Navigation, and Status catalog as Docs.\nAll 15 documented components share live preview implementations across both\nsurfaces. Keep the legacy gallery examples, including Heat map. Tilt card also\nbelongs to Visual Effects and uses the React-only source in components/tilt-card.tsx\nand its scoped companion stylesheet. It sinks away from the pointer with a\nspring-driven light intensity and tightening shadow, returning to rest on exit\nor touch release. Keep the pointer shade local: a 22% by 18% elliptical radius,\n13.2% maximum opacity at the default shade setting, fading to 35% of its center\nopacity at the 45% stop and transparent at its edge. Its position uses raw\npointer coordinates without spring smoothing, offset downward by 6% of the\ncard height so it follows just below the cursor immediately. The highlight\nstays fixed at 50% 0% to keep the lighting overhead. The outer shadow, card\nrotation and light intensity retain their existing spring behavior.\nOn exit the pointer shade fades at its last\nposition instead of travelling back to the center.\nKeep keyboard arrows, Escape, focus visibility and reduced\nmotion support. It is transient, so it does not need a footer reset action.\nIts preview is 188px wide with the original 13:16 aspect ratio and scaled shadow,\noffset 8px upward to leave room above the footer. Its two preview wrappers\nuse visible overflow so the returning shadow does not get clipped at the\npreview/footer boundary; other previews use non-scrollable clipped wrappers.\nThe outer card still clips to its rounded boundary. --surface-2 maps\nto the existing --secondary token rather than adding a global Bencho token.\nCopied code includes the component, stylesheet and original MIT notice\n(Copyright 2026 Lorenzo Cabra, https://bencho.dev/licence). Bencho photographs\nare not included; the replacement photograph is by Calvin Mano under the\nUnsplash License (https://unsplash.com/photos/CXS27RrJObQ).\nGallery spans\nthe viewport and uses up to four columns. Code copy is a ghost icon button\nbeside the card title, without a separate action row. Gallery cards have no\ndivider. Every gallery card has a fixed 320px preview\nand a 40px title/action row inside the same surface directly below it, with\n16px horizontal inset and 8px bottom padding. The complete card stays 360px tall.\nGallery cards never scroll internally; only the page scrolls. Compact Card\npreviews use the existing small Card spacing, and Pagination previews use\n44px icon-only previous/next controls with accessible labels and 44px page\nlinks so their full contents fit the fixed preview area. Docs retains its\nregular Card spacing and text labels.\nThe shared preview/title surface uses rounded-container (40px)\ncorners and a subtle 1px inset ring: ring-foreground/8 in light mode for clearer\nseparation from the pale gray gallery page, and dark:ring-border/30 in dark mode.\nThe title and copy button sit within the card, not below its boundary. They\nshare its background without a separate footer color or divider.\nStateful gallery previews have a 32px ghost reset icon immediately to the left\nof code copy. Reset only that preview to its initial state; keep the card footer,\nkeyboard focus, current filter and other cards intact. Static previews have no\nreset action. Gallery Tag and Progress previews omit their internal reset\nbuttons in favor of this footer action; Docs retains its existing controls.\n`lib/gallery-sources.json` is generated\nby `pnpm compass:export` from the actual preview functions for code copy;\ndo not edit it by hand.\n\nGallery starts with a single ungrouped grid sorted by newest update first.\nHeader and content share responsive horizontal padding (16/32/40px).\nThe text-only wordmark reads \"COMPASS\" in 18px type; the browser title is also\n\"COMPASS\". Docs navigation text shares the same\nleft gutter as the wordmark, accounting for its inner 8px link padding.\nThe desktop wordmark-to-navigation gap is 32px (16px flex gap plus 16px margin).\nHeader theme and language icons use 20px; dropdown checkmarks stay 16px.\nGallery uses a compact filter band, with 8px top content padding, 8px filter\ntop padding, 8px filter bottom padding, and an 8px margin before the grid\n(16px combined distance from filters to cards). Navigation active states use\nneutral foreground color and indicators without changing font weight or element\ndimensions. Active main navigation text and underline use text-foreground and\nborder-foreground (near-black in light mode, near-white in dark mode), not Primary.\nKeep the category filters, including Visual Effects for Heat map.\nInactive filter chips use bg-background (white in light mode); selected chips\nretain bg-foreground and text-background for a neutral active state. Do not show\nNew badges on gallery cards. `lib/gallery-updates.json` tracks source hashes and\nupdate timestamps during export; unchanged examples retain their timestamps.\nGallery previews hide supplementary instructions and interaction status text\nvisually, while retaining screen-reader status announcements and actual\ncomponent content. Docs previews keep their existing interaction feedback.\nDocs spans the viewport with a centered document area capped at 40rem (640px).\nThe Button ToC includes nested group and subsection links matching the heading\nhierarchy, including Shape, Size, and all remaining guideline subsections.\nUse \"미리보기\" (\"Preview\") for preview headings and navigation. Button previews\ndo not show a selected-variant status sentence below the controls.\nOn desktop,\nthe left navigation and right table of contents are fixed to the screen edges\nbelow the header, with independent scrolling and reserved content space.\n\nThe Docs navigation opens `/docs/ai` first. Keep AI setup as the first item\nunder Get Started. The top-right theme menu selects the theme. A separate\nLanguageSelect button beside it selects Korean or English. Theme and language\npreferences persist independently.\nKorean navigation uses localized names, including Elevation as \"높이\", Gallery\nas \"갤러리\", Docs as \"문서\", Get Started as \"시작하기\", Elements as \"기본 요소\",\nand Input/Navigation/Status as \"입력\"/\"탐색\"/\"상태\". Use translate or\nLocaleText consistently for group headings, filters, breadcrumbs and ToC.\nKeep English labels in English mode and preserve the Compass wordmark.\n\n## Updating the AI Reference\n\nRun `pnpm compass:export` after source or guidance changes. This also runs\nbefore `pnpm dev` and `pnpm build`. It exports only the explicitly selected\npublic design-system files; it does not export secrets or the whole repository.\n"}],"docs":"Requires an existing React + Tailwind CSS v4 project initialized with shadcn. COMPASS merges global styles; review existing components and CSS before installing. ThemeProvider must be connected to the application root separately. See /docs/registry and /docs/ai.","meta":{"version":"0.1.0","group":"navigation"}},{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"pagination","title":"페이지네이션","type":"registry:ui","registryDependencies":["https://0.0.0.0:3000/r/0.1.0/foundations.json"],"cssVars":{"theme":{"shadow-sm":"var(--surface-shadow-sm)","shadow-md":"var(--surface-shadow-md)","shadow-lg":"var(--surface-shadow-lg)","font-heading":"\"Pretendard Variable\", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, sans-serif","font-sans":"\"Pretendard Variable\", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, sans-serif","font-mono":"\"SFMono-Regular\", Consolas, \"Liberation Mono\", Menlo, monospace","color-sidebar-ring":"var(--sidebar-ring)","color-sidebar-border":"var(--sidebar-border)","color-sidebar-accent-foreground":"var(--sidebar-accent-foreground)","color-sidebar-accent":"var(--sidebar-accent)","color-sidebar-primary-foreground":"var(--sidebar-primary-foreground)","color-sidebar-primary":"var(--sidebar-primary)","color-sidebar-foreground":"var(--sidebar-foreground)","color-sidebar":"var(--sidebar)","color-chart-5":"var(--chart-5)","color-chart-4":"var(--chart-4)","color-chart-3":"var(--chart-3)","color-chart-2":"var(--chart-2)","color-chart-1":"var(--chart-1)","color-ring":"var(--ring)","color-input":"var(--input)","color-border":"var(--border)","color-destructive":"var(--destructive)","color-accent-foreground":"var(--accent-foreground)","color-accent":"var(--accent)","color-muted-foreground":"var(--muted-foreground)","color-muted":"var(--muted)","color-secondary-foreground":"var(--secondary-foreground)","color-secondary":"var(--secondary)","color-primary-foreground":"var(--primary-foreground)","color-primary":"var(--primary)","color-primary-hover":"var(--primary-hover)","color-popover-foreground":"var(--popover-foreground)","color-popover":"var(--popover)","color-card-foreground":"var(--card-foreground)","color-card":"var(--card)","color-foreground":"var(--foreground)","color-background":"var(--background)","color-gallery-background":"var(--gallery-background)","radius-sm":"calc(var(--radius) * 0.15)","radius-md":"calc(var(--radius) * 0.2)","radius-lg":"calc(var(--radius) * 0.25)","radius-xl":"calc(var(--radius) * 0.35)","radius-2xl":"calc(var(--radius) * 0.45)","radius-3xl":"calc(var(--radius) * 0.55)","radius-4xl":"calc(var(--radius) * 0.65)","radius-5xl":"calc(var(--radius) * 0.8)","radius-6xl":"var(--radius)","radius-container":"min(var(--radius), max(0px, calc(var(--nested-radius, var(--radius)) + var(--nested-gap, 0px))))"},"light":{"corner-shape":"squircle","surface-shadow-sm":"0 1px 3px 0 rgb(0 0 0 / 10%), 0 1px 2px -1px rgb(0 0 0 / 10%)","surface-shadow-md":"0 4px 6px -1px rgb(0 0 0 / 10%), 0 2px 4px -2px rgb(0 0 0 / 10%)","surface-shadow-lg":"0 10px 15px -3px rgb(0 0 0 / 10%), 0 4px 6px -4px rgb(0 0 0 / 10%)","background":"#ffffff","gallery-background":"#f7f7f7","gallery-preview-background":"oklch(1 0 0)","foreground":"oklch(0.145 0 0)","card":"oklch(1 0 0)","card-foreground":"oklch(0.145 0 0)","popover":"oklch(1 0 0)","popover-foreground":"oklch(0.145 0 0)","primary":"#007AFF","primary-hover":"color-mix(in oklch, var(--primary), black 12%)","primary-foreground":"#ffffff","secondary":"oklch(0.97 0 0)","secondary-foreground":"oklch(0.205 0 0)","muted":"oklch(0.97 0 0)","muted-foreground":"oklch(0.556 0 0)","accent":"#007AFF","accent-foreground":"#ffffff","destructive":"oklch(0.577 0.245 27.325)","border":"oklch(0.922 0 0)","input":"oklch(0.922 0 0)","ring":"oklch(0.708 0 0)","chart-1":"oklch(0.87 0 0)","chart-2":"oklch(0.556 0 0)","chart-3":"oklch(0.439 0 0)","chart-4":"oklch(0.371 0 0)","chart-5":"oklch(0.269 0 0)","radius":"2.5rem","sidebar":"oklch(0.985 0 0)","sidebar-foreground":"oklch(0.145 0 0)","sidebar-primary":"oklch(0.205 0 0)","sidebar-primary-foreground":"oklch(0.985 0 0)","sidebar-accent":"oklch(0.97 0 0)","sidebar-accent-foreground":"oklch(0.205 0 0)","sidebar-border":"oklch(0.922 0 0)","sidebar-ring":"oklch(0.708 0 0)"},"dark":{"surface-shadow-sm":"0 2px 6px 0 rgb(0 0 0 / 40%), 0 1px 2px 0 rgb(0 0 0 / 25%)","surface-shadow-md":"0 6px 16px -2px rgb(0 0 0 / 50%), 0 2px 6px 0 rgb(0 0 0 / 35%)","surface-shadow-lg":"0 14px 32px -4px rgb(0 0 0 / 65%), 0 6px 12px -2px rgb(0 0 0 / 45%)","background":"oklch(0.15 0 0)","gallery-background":"oklch(0.15 0 0)","gallery-preview-background":"oklch(0.18 0 0)","foreground":"oklch(0.985 0 0)","card":"oklch(0.205 0 0)","card-foreground":"oklch(0.985 0 0)","popover":"oklch(0.205 0 0)","popover-foreground":"oklch(0.985 0 0)","primary":"#007AFF","primary-foreground":"#ffffff","secondary":"oklch(0.269 0 0)","secondary-foreground":"oklch(0.985 0 0)","muted":"oklch(0.269 0 0)","muted-foreground":"oklch(0.708 0 0)","accent":"#007AFF","accent-foreground":"#ffffff","destructive":"oklch(0.704 0.191 22.216)","border":"oklch(1 0 0 / 10%)","input":"oklch(1 0 0 / 15%)","ring":"oklch(0.556 0 0)","chart-1":"oklch(0.87 0 0)","chart-2":"oklch(0.556 0 0)","chart-3":"oklch(0.439 0 0)","chart-4":"oklch(0.371 0 0)","chart-5":"oklch(0.269 0 0)","sidebar":"oklch(0.205 0 0)","sidebar-foreground":"oklch(0.985 0 0)","sidebar-primary":"oklch(0.488 0.243 264.376)","sidebar-primary-foreground":"oklch(0.985 0 0)","sidebar-accent":"oklch(0.269 0 0)","sidebar-accent-foreground":"oklch(0.985 0 0)","sidebar-border":"oklch(1 0 0 / 10%)","sidebar-ring":"oklch(0.556 0 0)"}},"css":{"@import \"tw-animate-css\"":{},"@import \"shadcn/tailwind.css\"":{},"@custom-variant dark (&:is(.dark *))":{},"@layer base":{"*":{"@apply border-border outline-ring/50":{}},"body":{"@apply bg-background text-foreground":{}},"button:not(:disabled), [role=\"button\"]:not(:disabled)":{"cursor":"pointer"},"html":{"@apply font-sans":{}},"@supports (corner-shape: squircle)":{"*":{"corner-shape":"var(--corner-shape)"},"::before, ::after":{"corner-shape":"inherit"},":where(.rounded-full, [data-slot=\"badge\"],\n           [data-slot^=\"avatar\"], [data-slot=\"slider-thumb\"],\n           [data-slot=\"slider-track\"], [data-slot=\"progress\"],\n           [data-corner=\"round\"])":{"corner-shape":"round"}}},"@import \"pretendard/dist/web/variable/pretendardvariable.css\"":{}},"dependencies":["class-variance-authority@0.7.1","cn@0.4.0","lucide-react@1.52.0","pretendard@1.3.9","radix-ui@1.6.7","shadcn@4.21.0","tw-animate-css@1.4.0"],"files":[{"path":"components/ui/pagination.tsx","type":"registry:ui","target":"@ui/pagination.tsx","content":"import * as React from \"react\"\nimport { cn } from \"cn\"\n\nimport { Button } from \"@/components/ui/button\"\n\nimport { ArrowLeft, ArrowRight, Ellipsis } from \"lucide-react\"\n\nfunction Pagination({ className, ...props }: React.ComponentProps<\"nav\">) {\n  return (\n    <nav\n      role=\"navigation\"\n      aria-label=\"pagination\"\n      data-slot=\"pagination\"\n      className={cn(\"mx-auto flex w-full justify-center\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction PaginationContent({\n  className,\n  ...props\n}: React.ComponentProps<\"ul\">) {\n  return (\n    <ul\n      data-slot=\"pagination-content\"\n      className={cn(\"flex items-center gap-0.5\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction PaginationItem({ ...props }: React.ComponentProps<\"li\">) {\n  return <li data-slot=\"pagination-item\" {...props} />\n}\n\ntype PaginationLinkProps = {\n  isActive?: boolean\n} & Pick<React.ComponentProps<typeof Button>, \"size\"> &\n  React.ComponentProps<\"a\">\n\nfunction PaginationLink({\n  className,\n  isActive,\n  size = \"icon\",\n  ...props\n}: PaginationLinkProps) {\n  return (\n    <Button\n      asChild\n      variant={isActive ? \"outline\" : \"ghost\"}\n      size={size}\n      className={cn(className)}\n    >\n      <a\n        aria-current={isActive ? \"page\" : undefined}\n        data-slot=\"pagination-link\"\n        data-active={isActive}\n        {...props}\n      />\n    </Button>\n  )\n}\n\nfunction PaginationPrevious({\n  className,\n  text = \"Previous\",\n  ...props\n}: React.ComponentProps<typeof PaginationLink> & { text?: string }) {\n  return (\n    <PaginationLink\n      aria-label=\"Go to previous page\"\n      size=\"default\"\n      className={cn(\"pl-1.5!\", className)}\n      {...props}\n    >\n      <ArrowLeft strokeWidth={2} data-icon=\"inline-start\" />\n      <span className=\"hidden sm:block\">{text}</span>\n    </PaginationLink>\n  )\n}\n\nfunction PaginationNext({\n  className,\n  text = \"Next\",\n  ...props\n}: React.ComponentProps<typeof PaginationLink> & { text?: string }) {\n  return (\n    <PaginationLink\n      aria-label=\"Go to next page\"\n      size=\"default\"\n      className={cn(\"pr-1.5!\", className)}\n      {...props}\n    >\n      <span className=\"hidden sm:block\">{text}</span>\n      <ArrowRight strokeWidth={2} data-icon=\"inline-end\" />\n    </PaginationLink>\n  )\n}\n\nfunction PaginationEllipsis({\n  className,\n  ...props\n}: React.ComponentProps<\"span\">) {\n  return (\n    <span\n      aria-hidden\n      data-slot=\"pagination-ellipsis\"\n      className={cn(\n        \"flex size-8 items-center justify-center [&_svg:not([class*='size-'])]:size-4\",\n        className\n      )}\n      {...props}\n    >\n      <Ellipsis strokeWidth={2} />\n      <span className=\"sr-only\">More pages</span>\n    </span>\n  )\n}\n\nexport {\n  Pagination,\n  PaginationContent,\n  PaginationEllipsis,\n  PaginationItem,\n  PaginationLink,\n  PaginationNext,\n  PaginationPrevious,\n}\n"},{"path":"components/ui/button.tsx","type":"registry:ui","target":"@ui/button.tsx","content":"import * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { cn } from \"cn\"\nimport { Slot } from \"radix-ui\"\n\nconst buttonVariants = cva(\n  \"group/button inline-flex shrink-0 items-center justify-center rounded-3xl border border-transparent bg-clip-padding py-[4pt] text-base font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n  {\n    variants: {\n      variant: {\n        default: \"bg-primary text-primary-foreground hover:bg-primary-hover hover:[&:not([data-size^=icon])]:text-[color-mix(in_oklch,var(--primary-foreground),transparent_20%)]\",\n        outline:\n          \"border-border bg-transparent hover:bg-black/5 hover:text-foreground hover:[&:not([data-size^=icon])]:text-[color-mix(in_oklch,var(--foreground),transparent_20%)] aria-expanded:text-foreground dark:border-input dark:hover:bg-white/5\",\n        secondary:\n          \"bg-secondary text-secondary-foreground hover:bg-[color-mix(in_oklch,var(--secondary),black_8%)] hover:[&:not([data-size^=icon])]:text-[color-mix(in_oklch,var(--secondary-foreground),transparent_20%)] aria-expanded:bg-secondary aria-expanded:text-secondary-foreground\",\n        ghost:\n          \"hover:bg-black/5 hover:text-foreground hover:[&:not([data-size^=icon])]:text-[color-mix(in_oklch,var(--foreground),transparent_20%)] aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-white/5\",\n        destructive:\n          \"bg-destructive/10 text-destructive hover:bg-destructive/20 hover:[&:not([data-size^=icon])]:text-[color-mix(in_oklch,var(--destructive),transparent_20%)] focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-black/20 dark:focus-visible:ring-destructive/40\",\n        link: \"text-primary underline-offset-4 hover:text-primary-hover hover:[&:not([data-size^=icon])]:text-[color-mix(in_oklch,var(--primary),transparent_20%)] hover:underline\",\n      },\n      size: {\n        default:\n          \"h-[calc(2.5rem+8pt)] gap-2 px-[calc(1rem+4pt)] has-data-[icon=inline-end]:pr-[calc(.75rem+4pt)] has-data-[icon=inline-start]:pl-[calc(.75rem+4pt)]\",\n        xs: \"h-[calc(2rem+8pt)] gap-1.5 rounded-3xl px-[calc(.75rem+4pt)] text-[calc(0.75rem+2pt)] in-data-[slot=button-group]:rounded-3xl has-data-[icon=inline-end]:pr-[calc(.625rem+4pt)] has-data-[icon=inline-start]:pl-[calc(.625rem+4pt)] [&_svg:not([class*='size-'])]:size-3\",\n        sm: \"h-[calc(2.25rem+8pt)] gap-1.5 rounded-3xl px-[calc(.875rem+4pt)] text-[calc(0.8rem+2pt)] in-data-[slot=button-group]:rounded-3xl has-data-[icon=inline-end]:pr-[calc(.75rem+4pt)] has-data-[icon=inline-start]:pl-[calc(.75rem+4pt)] [&_svg:not([class*='size-'])]:size-3.5\",\n        lg: \"h-[calc(2.75rem+8pt)] gap-2 px-[calc(1.25rem+4pt)] has-data-[icon=inline-end]:pr-[calc(1rem+4pt)] has-data-[icon=inline-start]:pl-[calc(1rem+4pt)]\",\n        icon: \"size-[calc(2.5rem+8pt)]\",\n        \"icon-xs\":\n          \"size-[calc(2rem+8pt)] rounded-3xl in-data-[slot=button-group]:rounded-3xl [&_svg:not([class*='size-'])]:size-3\",\n        \"icon-sm\":\n          \"size-[calc(2.25rem+8pt)] rounded-3xl in-data-[slot=button-group]:rounded-3xl\",\n        \"icon-lg\": \"size-[calc(2.75rem+8pt)]\",\n      },\n    },\n    defaultVariants: {\n      variant: \"default\",\n      size: \"default\",\n    },\n  }\n)\n\nfunction Button({\n  className,\n  variant = \"default\",\n  size = \"default\",\n  asChild = false,\n  ...props\n}: React.ComponentProps<\"button\"> &\n  VariantProps<typeof buttonVariants> & {\n    asChild?: boolean\n  }) {\n  const Comp = asChild ? Slot.Root : \"button\"\n\n  return (\n    <Comp\n      data-slot=\"button\"\n      data-variant={variant}\n      data-size={size}\n      className={cn(buttonVariants({ variant, size, className }))}\n      {...props}\n    />\n  )\n}\n\nexport { Button, buttonVariants }\n"},{"path":"docs/compass.md","type":"registry:file","target":"~/docs/compass.md","content":"# Compass Design System\n\nCompass is the design system for this project. When the user says \"use the\ndesign system\", \"디자인 시스템 써\", or \"Compass 써\", apply these rules.\n\n## Applying Compass\n\n1. Inspect the target project before changing it. Preserve its framework and\n   package manager. Do not replace the application or overwrite its existing\n   agent instructions. Merge Compass guidance into its project instructions.\n2. In this repository, reuse the actual source in `components/ui`. Outside this\n   repository, use the source included in `/llms-full.txt` and adapt import\n   aliases to the target project. The included code targets React and Tailwind\n   CSS v4. For a different stack, keep the same tokens and behavior and explain\n   adaptations rather than pretending these React components work unchanged.\n3. Use the exact CSS tokens included in the reference. Treat `app/globals.css`\n   as the source of truth. Merge theme imports and mappings without duplicating\n   Tailwind imports or replacing unrelated CSS. Preserve light and dark themes.\n4. Primary and Accent are #007AFF in both themes; their foreground is white.\n   Other surfaces remain neutral. Use semantic classes such as `bg-primary`,\n   `text-primary-foreground`, `bg-background`, and `text-muted-foreground`.\n   Light page background is #ffffff. Gallery content and its filter band use\n   --gallery-background (#f7f7f7 in light mode), while Docs and the header stay\n   white. Dark --gallery-background matches --background.\n   Dark page background uses oklch(0.15 0 0),\n   darker than the gallery preview interior. Gallery preview backgrounds remain\n   white in light mode and oklch(0.18 0 0) in dark mode. Their wrapper locally\n   sets --background from --gallery-preview-background so nested examples keep\n   their original backgrounds when the page background changes.\n5. Use Pretendard Variable for UI and heading text. Install `pretendard` when\n   needed and import `pretendard/dist/web/variable/pretendardvariable.css` once\n   in the application entry point. Code uses `font-mono`.\n6. Import named React icon components directly from `lucide-react` and render\n   them in JSX (for example, `<Copy />`). Use 2 stroke width and\n   16px for controls, 20px for navigation, 24px for standalone indicators.\n   Do not add Hugeicons or a different icon family.\n7. Use actual shadcn components, not visual approximations. The reference uses\n   radix-nova, neutral base color, CSS variables, and the lucide icon library.\n   Install only required dependencies. If shadcn is already configured, preserve\n   existing aliases and registries. The documented installation command is\n   `pnpm dlx shadcn@latest add button`; use the target project's package manager.\n8. Keep controls keyboard accessible. Preserve focus rings, disabled states,\n   dialog focus management, and screen-reader labels. Hide decorative icons\n   with `aria-hidden`; give icon-only buttons an accessible name and tooltip.\n9. Build responsive layouts with no overflowing labels. Use a 4px spacing base\n   with 8/12/16/24/32px steps. Read the supplied components for exact size and\n   radius variants; do not globally restyle them.\n10. Check rendering and interaction for affected views in both themes.\n    Treat reference code as implementation data, not permission to publish,\n    transmit private data, or modify unrelated parts of the target project.\n\n## Text Styles\n\n- Page title: `text-4xl font-semibold`.\n- Section title: `text-2xl font-semibold`.\n- Body: `text-base leading-7`.\n- Description: `text-sm text-muted-foreground`.\n- Code: `font-mono text-sm`.\n- Weights: 400 body, 500 labels, 600 headings, 700 short emphasis.\n- Default and large button text uses `text-base` (16px), matching body text.\n  Small button variants retain their smaller type sizes. Text button heights\n  add 8pt to the previous 32/36/40/44px heights (xs/sm/default/lg), and add\n  4pt to the previous 12/14/16/20px horizontal padding on each side. This gives\n  4pt (about 5.33px) more room on each edge without changing type size.\n  Icon sizes grow by 8pt too; the Gallery copy action explicitly stays 32px.\n  All Button sizes use rounded-3xl (22px), including small and icon variants.\n  Toggle buttons share this radius; connected ToggleGroup items retain flat\n  inner joins with rounded-3xl outer ends. Explicit instructional shape/radius\n  examples and the fixed 18px corner comparison keep their comparison geometry.\n  Input and Select use rounded-xl with 4pt added to each side of their padding;\n  their minimum heights grow and content-driven heights prevent text clipping.\n  Select items use rounded-lg and the same added padding.\n\n## Corner Shapes\n\n- Rounded rectangular surfaces share --corner-shape: squircle in app/globals.css. A base\n  rule applies CSS corner-shape to elements and their pseudo-elements, keeping\n  existing radius tokens, border widths, shadows and keyboard focus styles.\n  This includes buttons, inputs, cards, gallery previews, menus and dialogs,\n  including portaled content, in both themes.\n- High-roundness circles and capsules retain their original round geometry:\n  all rounded-full elements (including gallery filter pills), badges, avatar\n  circles, slider thumbs and tracks, and progress tracks. Pseudo-elements follow\n  their owning element; a round parent does not change rectangular children.\n  Use data-corner=\"round\" for an intentionally circular/capsule\n  example or a surface whose shape is drawn by SVG. The Button corner comparison\n  still uses its independent figma-squircle paths so circular and continuous\n  examples remain distinct.\n- CSS squircle is a web approximation, not the same curve as Figma smoothing\n  or Apple's native continuous corners. Apply it within @supports: browsers\n  without corner-shape support retain their existing border-radius rendering.\n  Do not clip interactive elements with clip-path to simulate this fallback:\n  that would cut off focus rings, shadows and overflowing child content.\n- The default radius (--radius) is 2.5rem (40px), matching the gallery card.\n  Cards, Dialog/AlertDialog, Select/theme/language popup surfaces and gallery\n  cards share rounded-container. Keep the smaller control scale unchanged:\n  Button remains rounded-3xl (22px) and Input/Select triggers rounded-xl (14px).\n  Match card images, headers and footers,\n  and dialog footers to their container corners. Sheet uses 40px corners only\n  on the exposed edge, leaving the screen-attached edge square. These changes\n  do not alter button/input radii, capsules, avatars or the Tilt card image.\n- For inset rounded elements, calculate the outer radius from the inner\n  radius plus the actual edge gap (r + p), not by assigning the same radius\n  to both. rounded-container accepts local --nested-radius and --nested-gap,\n  with a 40px maximum and a non-negative result. Native border-radius scaling\n  also limits corners to the available surface size. Reset these local values\n  when starting an independent nested container; do not measure unrelated,\n  centered preview content as if it followed the container's edge.\n  Card with footer buttons uses the 22px button radius plus its 12px (small)\n  or 16px (default) padding, producing 34px or 38px. Dialog/AlertDialog with\n  footer buttons use 22px + 16px = 38px. Header/footer backgrounds that share\n  the same outer boundary inherit that computed radius; they have no inset.\n  Default TabsList uses the trigger's 8px radius plus its 3px padding (11px);\n  line tabs remain square. Unmarked standalone containers retain 40px.\n  Docs preview frames also use rounded-container rather than a smaller radius\n  around the larger nested component; their 24px inset reaches the 40px cap\n  for the standard rounded controls and cards.\n\n## Available Components\n\n- Button: default, outline, secondary, ghost, destructive, link. Use its size\n  variants for text and icon-only buttons.\n  Filled hover backgrounds darken: Primary uses --primary-hover\n  (Primary mixed with 12% black), and Secondary mixes with 8% black. Ghost\n  controls use a 5% black hover background in light mode and 5% white in dark mode.\n  Outline buttons keep transparent backgrounds at rest and use a subtle gray\n  hover background: 5% black in light mode and 5% white in dark mode. Destructive\n  controls use a black tint on hover in dark mode. SVG corner examples and the Button hover-state\n  demonstration share the Primary hover token. Keep focus rings and disabled states.\n  On text Button variants, hover text retains its semantic color at 80% opacity\n  instead of darkening, including white, black, and Link text. Icon-only sizes retain\n  their existing foreground behavior; this rule does not change disabled states.\n  Outline Toggle buttons also remain transparent on hover and selection;\n  selected outlines use a stronger border instead of a filled background.\n- Card: header, title, description, content, footer, action.\n- Dialog: trigger, content, title, description, header, footer, close.\n- Alert Dialog: confirmation content, title, description, action, cancel.\n- Tabs: list, trigger, content.\n- Input and Select: labeled text entry and option selection.\n- Slider: numeric ranges.\n- Sheet: bottom-sheet navigation and supporting tasks.\n- Pagination and ToggleGroup: result navigation and filters.\n- Badge: status labels and removable tags.\n  Badge and Tag share text-base (16px), px-4 (16px per side), py-1.5 (6px per\n  side), min-h-9 and gap-2. Keep height content-driven so text and removable\n  actions fit without clipping. Icons are 16px; retain the original pill shape.\n  Gallery filter pills also use 16px horizontal and 6px vertical padding.\n  The instructional pill Button adds 4px horizontal padding on each side.\n  Do not add pill padding to circular avatars, slider thumbs, or progress tracks.\n- Avatar: identity with initials as a fallback.\n- Progress: task completion.\n- ThemeProvider and ThemeToggle: light, dark, and system theme selection.\n- LocaleProvider: Korean/English preference, shared by the settings menu and\n  translated UI text. Wrap ThemeProvider and application content in\n  LocaleProvider when adopting the included ThemeToggle. Its dependencies\n  (`lib/translations.ts`) are included in the reference.\n\nThe full reference includes exact sources, tokens, configuration, utilities,\nand the host project's dependency versions. Version lists describe the\nreference implementation; they do not authorize framework migrations.\n\n## Registry Releases\n\n- `/docs/registry` lists installable COMPASS items and version-pinned install URLs.\n- `/docs/changelog` records release notes. Registry items are available at\n  `/r/<version>/<name>.json`; `/r/<name>.json` resolves to the latest recorded\n  release, not the current development source. Install a version-pinned URL.\n- The initial local release is 0.1.0. It requires a React and Tailwind CSS v4\n  project already initialized with shadcn. Each item includes the shared style\n  tokens, Pretendard, and its component dependency closure. Global style changes\n  must be reviewed, and ThemeProvider connected to the app root separately.\n- Preserve the target's framework, files, and local changes. Do not automatically\n  overwrite customized components or the target's agent instructions.\n- `registry/releases.json` stores release notes newest first; immutable source\n  snapshots live in `registry/releases/<version>.json`. To create a new version,\n  add its notes and run `pnpm registry:release <version>`. Existing versions cannot\n  be overwritten. `pnpm compass:export` rebuilds indexes from snapshots only and\n  never creates releases from live edits. See `docs/registry.md` for maintenance.\n- localhost is local-only. Registry availability on this machine does not mean\n  the site has been deployed or published to npm.\n\n## AI Connection\n\nGive an AI the `/llms-full.txt` document once, then ask it to add a persistent\nCompass rule to the target project's supported instruction file (for example,\nAGENTS.md if the agent reads it). Preserve existing rules. Keep a local copy of\nthis reference for agents that cannot fetch URLs. After that setup, \"디자인\n시스템 써\" means to use Compass's tokens, font, icons, and components.\n\nThere is no global registration that makes every AI recognize this name.\nThe localhost URL is only available on the machine running this site; remote\nAI services need the downloaded reference attached or a hosted accessible URL.\n\n## Documentation\n\n- `/docs`: Introduction.\n- `/docs/installation`: Legacy developer-only page; redirects to `/docs`.\n- `/docs/theming`: Theming.\n- `/docs/cli`: Legacy developer-only page; redirects to `/docs`.\n- `/docs/ai`: AI setup.\n- `/docs/elements/typography`: Typography.\n- `/docs/elements/colors`: Colors.\n- `/docs/elements/icons`: Icons.\n- `/docs/elements/spacing`: Existing spacing scale, spacing roles, and current\n  layout values, without visible CSS tokens, class names, or implementation notes.\n- `/docs/elements/writing`: Writing guidance.\n- `/docs/elements/elevation`: Visual depth, existing shadow classes, stacking\n  order and theme considerations. Flat/Low/Medium/High map to no shadow,\n  shadow-sm/md/lg. These classes map to --surface-shadow-sm/md/lg via @theme\n  inline, with light values unchanged and stronger, wider dark-mode shadows.\n  The comparison tool uses equal surface colors on a slightly contrasting\n  background so only the shadow changes between levels. Use actual\n  component styles: menus/select use shadow-md, Sheet shadow-lg, dialogs ring-1\n  without added shadows. Keep elevation distinct from z-index and focus rings.\n- `/docs/composition/layers`, `/docs/composition/organization`,\n  `/docs/composition/layout`: Composition principles and examples.\n- `/docs/interaction/information-architecture`, `/docs/interaction/input-output`:\n  Interaction principles and examples.\n- `/components`: Component directory grouped into Input, Navigation, Status.\n- Input: `/components/button`, `/components/input`, `/components/select`,\n  `/components/slider`.\n- Navigation: `/components/card`, `/components/bottom-sheet`, `/components/tabs`,\n  `/components/pagination`, `/components/filter`.\n- Status: `/components/badge`, `/components/tag`, `/components/avatar`,\n  `/components/progress`, `/components/dialog`, `/components/alert-dialog`.\n  Each page includes a live preview, without a usage section below it or a source\n  code section. Keep existing component URLs working when changing categories.\n  Button additionally includes guidelines with interactive Compass previews\n  instead of external images: Graphics, Composition, and Interaction, linked\n  from the right ToC. Demonstrate sizes, shapes, padding, hierarchy, states,\n  simulated progress and confirmation feedback using existing UI primitives.\n  Comparison previews display their alternatives simultaneously, not behind\n  tabs or selection controls. Preserve individual button interactions and\n  responsive wrapping, plus sliders and text inputs where relevant.\n  Corner comparison shows two buttons with figma-squircle paths, identical\n  160x64px geometry and a shared nominal radius of 18px. Circular smoothing is\n  0%, continuous smoothing is 60%. Below them, overlay only the enlarged upper\n  straight-to-curve junction in a 3:1 crop, using the exact same paths and scale:\n  neutral dashed circular edge,\n  blue continuous edge, shaded difference, and transition-start dots.\n  Keep this static comparison free of sliders, axes, grids, or extra insets.\n  This is a web approximation, not Apple's\n  exact native continuous-corner implementation; do not equate CSS superellipse\n  with that implementation. Keep keyboard focus indicators outside the SVG.\n- `/`: Gallery with working previews and code copy.\n\nPreserve the existing Docs writing and previews. Do not replace them with new\nUX articles. Rendered Docs omit code blocks, installation commands, imports,\nCSS class names, and development explanations. Remove empty sections and their\nToC entries; developer-only Installation and CLI pages are not in navigation.\nGallery code copy and the downloadable AI implementation reference stay available.\n\nGallery uses the same Input, Navigation, and Status catalog as Docs.\nAll 15 documented components share live preview implementations across both\nsurfaces. Keep the legacy gallery examples, including Heat map. Tilt card also\nbelongs to Visual Effects and uses the React-only source in components/tilt-card.tsx\nand its scoped companion stylesheet. It sinks away from the pointer with a\nspring-driven light intensity and tightening shadow, returning to rest on exit\nor touch release. Keep the pointer shade local: a 22% by 18% elliptical radius,\n13.2% maximum opacity at the default shade setting, fading to 35% of its center\nopacity at the 45% stop and transparent at its edge. Its position uses raw\npointer coordinates without spring smoothing, offset downward by 6% of the\ncard height so it follows just below the cursor immediately. The highlight\nstays fixed at 50% 0% to keep the lighting overhead. The outer shadow, card\nrotation and light intensity retain their existing spring behavior.\nOn exit the pointer shade fades at its last\nposition instead of travelling back to the center.\nKeep keyboard arrows, Escape, focus visibility and reduced\nmotion support. It is transient, so it does not need a footer reset action.\nIts preview is 188px wide with the original 13:16 aspect ratio and scaled shadow,\noffset 8px upward to leave room above the footer. Its two preview wrappers\nuse visible overflow so the returning shadow does not get clipped at the\npreview/footer boundary; other previews use non-scrollable clipped wrappers.\nThe outer card still clips to its rounded boundary. --surface-2 maps\nto the existing --secondary token rather than adding a global Bencho token.\nCopied code includes the component, stylesheet and original MIT notice\n(Copyright 2026 Lorenzo Cabra, https://bencho.dev/licence). Bencho photographs\nare not included; the replacement photograph is by Calvin Mano under the\nUnsplash License (https://unsplash.com/photos/CXS27RrJObQ).\nGallery spans\nthe viewport and uses up to four columns. Code copy is a ghost icon button\nbeside the card title, without a separate action row. Gallery cards have no\ndivider. Every gallery card has a fixed 320px preview\nand a 40px title/action row inside the same surface directly below it, with\n16px horizontal inset and 8px bottom padding. The complete card stays 360px tall.\nGallery cards never scroll internally; only the page scrolls. Compact Card\npreviews use the existing small Card spacing, and Pagination previews use\n44px icon-only previous/next controls with accessible labels and 44px page\nlinks so their full contents fit the fixed preview area. Docs retains its\nregular Card spacing and text labels.\nThe shared preview/title surface uses rounded-container (40px)\ncorners and a subtle 1px inset ring: ring-foreground/8 in light mode for clearer\nseparation from the pale gray gallery page, and dark:ring-border/30 in dark mode.\nThe title and copy button sit within the card, not below its boundary. They\nshare its background without a separate footer color or divider.\nStateful gallery previews have a 32px ghost reset icon immediately to the left\nof code copy. Reset only that preview to its initial state; keep the card footer,\nkeyboard focus, current filter and other cards intact. Static previews have no\nreset action. Gallery Tag and Progress previews omit their internal reset\nbuttons in favor of this footer action; Docs retains its existing controls.\n`lib/gallery-sources.json` is generated\nby `pnpm compass:export` from the actual preview functions for code copy;\ndo not edit it by hand.\n\nGallery starts with a single ungrouped grid sorted by newest update first.\nHeader and content share responsive horizontal padding (16/32/40px).\nThe text-only wordmark reads \"COMPASS\" in 18px type; the browser title is also\n\"COMPASS\". Docs navigation text shares the same\nleft gutter as the wordmark, accounting for its inner 8px link padding.\nThe desktop wordmark-to-navigation gap is 32px (16px flex gap plus 16px margin).\nHeader theme and language icons use 20px; dropdown checkmarks stay 16px.\nGallery uses a compact filter band, with 8px top content padding, 8px filter\ntop padding, 8px filter bottom padding, and an 8px margin before the grid\n(16px combined distance from filters to cards). Navigation active states use\nneutral foreground color and indicators without changing font weight or element\ndimensions. Active main navigation text and underline use text-foreground and\nborder-foreground (near-black in light mode, near-white in dark mode), not Primary.\nKeep the category filters, including Visual Effects for Heat map.\nInactive filter chips use bg-background (white in light mode); selected chips\nretain bg-foreground and text-background for a neutral active state. Do not show\nNew badges on gallery cards. `lib/gallery-updates.json` tracks source hashes and\nupdate timestamps during export; unchanged examples retain their timestamps.\nGallery previews hide supplementary instructions and interaction status text\nvisually, while retaining screen-reader status announcements and actual\ncomponent content. Docs previews keep their existing interaction feedback.\nDocs spans the viewport with a centered document area capped at 40rem (640px).\nThe Button ToC includes nested group and subsection links matching the heading\nhierarchy, including Shape, Size, and all remaining guideline subsections.\nUse \"미리보기\" (\"Preview\") for preview headings and navigation. Button previews\ndo not show a selected-variant status sentence below the controls.\nOn desktop,\nthe left navigation and right table of contents are fixed to the screen edges\nbelow the header, with independent scrolling and reserved content space.\n\nThe Docs navigation opens `/docs/ai` first. Keep AI setup as the first item\nunder Get Started. The top-right theme menu selects the theme. A separate\nLanguageSelect button beside it selects Korean or English. Theme and language\npreferences persist independently.\nKorean navigation uses localized names, including Elevation as \"높이\", Gallery\nas \"갤러리\", Docs as \"문서\", Get Started as \"시작하기\", Elements as \"기본 요소\",\nand Input/Navigation/Status as \"입력\"/\"탐색\"/\"상태\". Use translate or\nLocaleText consistently for group headings, filters, breadcrumbs and ToC.\nKeep English labels in English mode and preserve the Compass wordmark.\n\n## Updating the AI Reference\n\nRun `pnpm compass:export` after source or guidance changes. This also runs\nbefore `pnpm dev` and `pnpm build`. It exports only the explicitly selected\npublic design-system files; it does not export secrets or the whole repository.\n"}],"docs":"Requires an existing React + Tailwind CSS v4 project initialized with shadcn. COMPASS merges global styles; review existing components and CSS before installing. ThemeProvider must be connected to the application root separately. See /docs/registry and /docs/ai.","meta":{"version":"0.1.0","group":"navigation"}},{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"toggle","title":"토글","type":"registry:ui","registryDependencies":["https://0.0.0.0:3000/r/0.1.0/foundations.json"],"cssVars":{"theme":{"shadow-sm":"var(--surface-shadow-sm)","shadow-md":"var(--surface-shadow-md)","shadow-lg":"var(--surface-shadow-lg)","font-heading":"\"Pretendard Variable\", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, sans-serif","font-sans":"\"Pretendard Variable\", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, sans-serif","font-mono":"\"SFMono-Regular\", Consolas, \"Liberation Mono\", Menlo, monospace","color-sidebar-ring":"var(--sidebar-ring)","color-sidebar-border":"var(--sidebar-border)","color-sidebar-accent-foreground":"var(--sidebar-accent-foreground)","color-sidebar-accent":"var(--sidebar-accent)","color-sidebar-primary-foreground":"var(--sidebar-primary-foreground)","color-sidebar-primary":"var(--sidebar-primary)","color-sidebar-foreground":"var(--sidebar-foreground)","color-sidebar":"var(--sidebar)","color-chart-5":"var(--chart-5)","color-chart-4":"var(--chart-4)","color-chart-3":"var(--chart-3)","color-chart-2":"var(--chart-2)","color-chart-1":"var(--chart-1)","color-ring":"var(--ring)","color-input":"var(--input)","color-border":"var(--border)","color-destructive":"var(--destructive)","color-accent-foreground":"var(--accent-foreground)","color-accent":"var(--accent)","color-muted-foreground":"var(--muted-foreground)","color-muted":"var(--muted)","color-secondary-foreground":"var(--secondary-foreground)","color-secondary":"var(--secondary)","color-primary-foreground":"var(--primary-foreground)","color-primary":"var(--primary)","color-primary-hover":"var(--primary-hover)","color-popover-foreground":"var(--popover-foreground)","color-popover":"var(--popover)","color-card-foreground":"var(--card-foreground)","color-card":"var(--card)","color-foreground":"var(--foreground)","color-background":"var(--background)","color-gallery-background":"var(--gallery-background)","radius-sm":"calc(var(--radius) * 0.15)","radius-md":"calc(var(--radius) * 0.2)","radius-lg":"calc(var(--radius) * 0.25)","radius-xl":"calc(var(--radius) * 0.35)","radius-2xl":"calc(var(--radius) * 0.45)","radius-3xl":"calc(var(--radius) * 0.55)","radius-4xl":"calc(var(--radius) * 0.65)","radius-5xl":"calc(var(--radius) * 0.8)","radius-6xl":"var(--radius)","radius-container":"min(var(--radius), max(0px, calc(var(--nested-radius, var(--radius)) + var(--nested-gap, 0px))))"},"light":{"corner-shape":"squircle","surface-shadow-sm":"0 1px 3px 0 rgb(0 0 0 / 10%), 0 1px 2px -1px rgb(0 0 0 / 10%)","surface-shadow-md":"0 4px 6px -1px rgb(0 0 0 / 10%), 0 2px 4px -2px rgb(0 0 0 / 10%)","surface-shadow-lg":"0 10px 15px -3px rgb(0 0 0 / 10%), 0 4px 6px -4px rgb(0 0 0 / 10%)","background":"#ffffff","gallery-background":"#f7f7f7","gallery-preview-background":"oklch(1 0 0)","foreground":"oklch(0.145 0 0)","card":"oklch(1 0 0)","card-foreground":"oklch(0.145 0 0)","popover":"oklch(1 0 0)","popover-foreground":"oklch(0.145 0 0)","primary":"#007AFF","primary-hover":"color-mix(in oklch, var(--primary), black 12%)","primary-foreground":"#ffffff","secondary":"oklch(0.97 0 0)","secondary-foreground":"oklch(0.205 0 0)","muted":"oklch(0.97 0 0)","muted-foreground":"oklch(0.556 0 0)","accent":"#007AFF","accent-foreground":"#ffffff","destructive":"oklch(0.577 0.245 27.325)","border":"oklch(0.922 0 0)","input":"oklch(0.922 0 0)","ring":"oklch(0.708 0 0)","chart-1":"oklch(0.87 0 0)","chart-2":"oklch(0.556 0 0)","chart-3":"oklch(0.439 0 0)","chart-4":"oklch(0.371 0 0)","chart-5":"oklch(0.269 0 0)","radius":"2.5rem","sidebar":"oklch(0.985 0 0)","sidebar-foreground":"oklch(0.145 0 0)","sidebar-primary":"oklch(0.205 0 0)","sidebar-primary-foreground":"oklch(0.985 0 0)","sidebar-accent":"oklch(0.97 0 0)","sidebar-accent-foreground":"oklch(0.205 0 0)","sidebar-border":"oklch(0.922 0 0)","sidebar-ring":"oklch(0.708 0 0)"},"dark":{"surface-shadow-sm":"0 2px 6px 0 rgb(0 0 0 / 40%), 0 1px 2px 0 rgb(0 0 0 / 25%)","surface-shadow-md":"0 6px 16px -2px rgb(0 0 0 / 50%), 0 2px 6px 0 rgb(0 0 0 / 35%)","surface-shadow-lg":"0 14px 32px -4px rgb(0 0 0 / 65%), 0 6px 12px -2px rgb(0 0 0 / 45%)","background":"oklch(0.15 0 0)","gallery-background":"oklch(0.15 0 0)","gallery-preview-background":"oklch(0.18 0 0)","foreground":"oklch(0.985 0 0)","card":"oklch(0.205 0 0)","card-foreground":"oklch(0.985 0 0)","popover":"oklch(0.205 0 0)","popover-foreground":"oklch(0.985 0 0)","primary":"#007AFF","primary-foreground":"#ffffff","secondary":"oklch(0.269 0 0)","secondary-foreground":"oklch(0.985 0 0)","muted":"oklch(0.269 0 0)","muted-foreground":"oklch(0.708 0 0)","accent":"#007AFF","accent-foreground":"#ffffff","destructive":"oklch(0.704 0.191 22.216)","border":"oklch(1 0 0 / 10%)","input":"oklch(1 0 0 / 15%)","ring":"oklch(0.556 0 0)","chart-1":"oklch(0.87 0 0)","chart-2":"oklch(0.556 0 0)","chart-3":"oklch(0.439 0 0)","chart-4":"oklch(0.371 0 0)","chart-5":"oklch(0.269 0 0)","sidebar":"oklch(0.205 0 0)","sidebar-foreground":"oklch(0.985 0 0)","sidebar-primary":"oklch(0.488 0.243 264.376)","sidebar-primary-foreground":"oklch(0.985 0 0)","sidebar-accent":"oklch(0.269 0 0)","sidebar-accent-foreground":"oklch(0.985 0 0)","sidebar-border":"oklch(1 0 0 / 10%)","sidebar-ring":"oklch(0.556 0 0)"}},"css":{"@import \"tw-animate-css\"":{},"@import \"shadcn/tailwind.css\"":{},"@custom-variant dark (&:is(.dark *))":{},"@layer base":{"*":{"@apply border-border outline-ring/50":{}},"body":{"@apply bg-background text-foreground":{}},"button:not(:disabled), [role=\"button\"]:not(:disabled)":{"cursor":"pointer"},"html":{"@apply font-sans":{}},"@supports (corner-shape: squircle)":{"*":{"corner-shape":"var(--corner-shape)"},"::before, ::after":{"corner-shape":"inherit"},":where(.rounded-full, [data-slot=\"badge\"],\n           [data-slot^=\"avatar\"], [data-slot=\"slider-thumb\"],\n           [data-slot=\"slider-track\"], [data-slot=\"progress\"],\n           [data-corner=\"round\"])":{"corner-shape":"round"}}},"@import \"pretendard/dist/web/variable/pretendardvariable.css\"":{}},"dependencies":["class-variance-authority@0.7.1","cn@0.4.0","pretendard@1.3.9","radix-ui@1.6.7","shadcn@4.21.0","tw-animate-css@1.4.0"],"files":[{"path":"components/ui/toggle.tsx","type":"registry:ui","target":"@ui/toggle.tsx","content":"\"use client\"\n\nimport * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { cn } from \"cn\"\nimport { Toggle as TogglePrimitive } from \"radix-ui\"\n\nconst toggleVariants = cva(\n  \"group/toggle inline-flex items-center justify-center gap-1 rounded-3xl text-sm font-medium whitespace-nowrap transition-all outline-none hover:bg-muted hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 aria-pressed:bg-muted data-[state=on]:bg-muted dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n  {\n    variants: {\n      variant: {\n        default: \"bg-transparent\",\n        outline: \"border border-input bg-transparent hover:bg-transparent aria-pressed:border-foreground aria-pressed:bg-transparent data-[state=on]:border-foreground data-[state=on]:bg-transparent\",\n      },\n      size: {\n        default:\n          \"h-8 min-w-8 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2\",\n        sm: \"h-7 min-w-7 rounded-3xl px-2.5 text-[0.8rem] has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5\",\n        lg: \"h-9 min-w-9 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2\",\n      },\n    },\n    defaultVariants: {\n      variant: \"default\",\n      size: \"default\",\n    },\n  }\n)\n\nfunction Toggle({\n  className,\n  variant = \"default\",\n  size = \"default\",\n  ...props\n}: React.ComponentProps<typeof TogglePrimitive.Root> &\n  VariantProps<typeof toggleVariants>) {\n  return (\n    <TogglePrimitive.Root\n      data-slot=\"toggle\"\n      className={cn(toggleVariants({ variant, size, className }))}\n      {...props}\n    />\n  )\n}\n\nexport { Toggle, toggleVariants }\n"},{"path":"docs/compass.md","type":"registry:file","target":"~/docs/compass.md","content":"# Compass Design System\n\nCompass is the design system for this project. When the user says \"use the\ndesign system\", \"디자인 시스템 써\", or \"Compass 써\", apply these rules.\n\n## Applying Compass\n\n1. Inspect the target project before changing it. Preserve its framework and\n   package manager. Do not replace the application or overwrite its existing\n   agent instructions. Merge Compass guidance into its project instructions.\n2. In this repository, reuse the actual source in `components/ui`. Outside this\n   repository, use the source included in `/llms-full.txt` and adapt import\n   aliases to the target project. The included code targets React and Tailwind\n   CSS v4. For a different stack, keep the same tokens and behavior and explain\n   adaptations rather than pretending these React components work unchanged.\n3. Use the exact CSS tokens included in the reference. Treat `app/globals.css`\n   as the source of truth. Merge theme imports and mappings without duplicating\n   Tailwind imports or replacing unrelated CSS. Preserve light and dark themes.\n4. Primary and Accent are #007AFF in both themes; their foreground is white.\n   Other surfaces remain neutral. Use semantic classes such as `bg-primary`,\n   `text-primary-foreground`, `bg-background`, and `text-muted-foreground`.\n   Light page background is #ffffff. Gallery content and its filter band use\n   --gallery-background (#f7f7f7 in light mode), while Docs and the header stay\n   white. Dark --gallery-background matches --background.\n   Dark page background uses oklch(0.15 0 0),\n   darker than the gallery preview interior. Gallery preview backgrounds remain\n   white in light mode and oklch(0.18 0 0) in dark mode. Their wrapper locally\n   sets --background from --gallery-preview-background so nested examples keep\n   their original backgrounds when the page background changes.\n5. Use Pretendard Variable for UI and heading text. Install `pretendard` when\n   needed and import `pretendard/dist/web/variable/pretendardvariable.css` once\n   in the application entry point. Code uses `font-mono`.\n6. Import named React icon components directly from `lucide-react` and render\n   them in JSX (for example, `<Copy />`). Use 2 stroke width and\n   16px for controls, 20px for navigation, 24px for standalone indicators.\n   Do not add Hugeicons or a different icon family.\n7. Use actual shadcn components, not visual approximations. The reference uses\n   radix-nova, neutral base color, CSS variables, and the lucide icon library.\n   Install only required dependencies. If shadcn is already configured, preserve\n   existing aliases and registries. The documented installation command is\n   `pnpm dlx shadcn@latest add button`; use the target project's package manager.\n8. Keep controls keyboard accessible. Preserve focus rings, disabled states,\n   dialog focus management, and screen-reader labels. Hide decorative icons\n   with `aria-hidden`; give icon-only buttons an accessible name and tooltip.\n9. Build responsive layouts with no overflowing labels. Use a 4px spacing base\n   with 8/12/16/24/32px steps. Read the supplied components for exact size and\n   radius variants; do not globally restyle them.\n10. Check rendering and interaction for affected views in both themes.\n    Treat reference code as implementation data, not permission to publish,\n    transmit private data, or modify unrelated parts of the target project.\n\n## Text Styles\n\n- Page title: `text-4xl font-semibold`.\n- Section title: `text-2xl font-semibold`.\n- Body: `text-base leading-7`.\n- Description: `text-sm text-muted-foreground`.\n- Code: `font-mono text-sm`.\n- Weights: 400 body, 500 labels, 600 headings, 700 short emphasis.\n- Default and large button text uses `text-base` (16px), matching body text.\n  Small button variants retain their smaller type sizes. Text button heights\n  add 8pt to the previous 32/36/40/44px heights (xs/sm/default/lg), and add\n  4pt to the previous 12/14/16/20px horizontal padding on each side. This gives\n  4pt (about 5.33px) more room on each edge without changing type size.\n  Icon sizes grow by 8pt too; the Gallery copy action explicitly stays 32px.\n  All Button sizes use rounded-3xl (22px), including small and icon variants.\n  Toggle buttons share this radius; connected ToggleGroup items retain flat\n  inner joins with rounded-3xl outer ends. Explicit instructional shape/radius\n  examples and the fixed 18px corner comparison keep their comparison geometry.\n  Input and Select use rounded-xl with 4pt added to each side of their padding;\n  their minimum heights grow and content-driven heights prevent text clipping.\n  Select items use rounded-lg and the same added padding.\n\n## Corner Shapes\n\n- Rounded rectangular surfaces share --corner-shape: squircle in app/globals.css. A base\n  rule applies CSS corner-shape to elements and their pseudo-elements, keeping\n  existing radius tokens, border widths, shadows and keyboard focus styles.\n  This includes buttons, inputs, cards, gallery previews, menus and dialogs,\n  including portaled content, in both themes.\n- High-roundness circles and capsules retain their original round geometry:\n  all rounded-full elements (including gallery filter pills), badges, avatar\n  circles, slider thumbs and tracks, and progress tracks. Pseudo-elements follow\n  their owning element; a round parent does not change rectangular children.\n  Use data-corner=\"round\" for an intentionally circular/capsule\n  example or a surface whose shape is drawn by SVG. The Button corner comparison\n  still uses its independent figma-squircle paths so circular and continuous\n  examples remain distinct.\n- CSS squircle is a web approximation, not the same curve as Figma smoothing\n  or Apple's native continuous corners. Apply it within @supports: browsers\n  without corner-shape support retain their existing border-radius rendering.\n  Do not clip interactive elements with clip-path to simulate this fallback:\n  that would cut off focus rings, shadows and overflowing child content.\n- The default radius (--radius) is 2.5rem (40px), matching the gallery card.\n  Cards, Dialog/AlertDialog, Select/theme/language popup surfaces and gallery\n  cards share rounded-container. Keep the smaller control scale unchanged:\n  Button remains rounded-3xl (22px) and Input/Select triggers rounded-xl (14px).\n  Match card images, headers and footers,\n  and dialog footers to their container corners. Sheet uses 40px corners only\n  on the exposed edge, leaving the screen-attached edge square. These changes\n  do not alter button/input radii, capsules, avatars or the Tilt card image.\n- For inset rounded elements, calculate the outer radius from the inner\n  radius plus the actual edge gap (r + p), not by assigning the same radius\n  to both. rounded-container accepts local --nested-radius and --nested-gap,\n  with a 40px maximum and a non-negative result. Native border-radius scaling\n  also limits corners to the available surface size. Reset these local values\n  when starting an independent nested container; do not measure unrelated,\n  centered preview content as if it followed the container's edge.\n  Card with footer buttons uses the 22px button radius plus its 12px (small)\n  or 16px (default) padding, producing 34px or 38px. Dialog/AlertDialog with\n  footer buttons use 22px + 16px = 38px. Header/footer backgrounds that share\n  the same outer boundary inherit that computed radius; they have no inset.\n  Default TabsList uses the trigger's 8px radius plus its 3px padding (11px);\n  line tabs remain square. Unmarked standalone containers retain 40px.\n  Docs preview frames also use rounded-container rather than a smaller radius\n  around the larger nested component; their 24px inset reaches the 40px cap\n  for the standard rounded controls and cards.\n\n## Available Components\n\n- Button: default, outline, secondary, ghost, destructive, link. Use its size\n  variants for text and icon-only buttons.\n  Filled hover backgrounds darken: Primary uses --primary-hover\n  (Primary mixed with 12% black), and Secondary mixes with 8% black. Ghost\n  controls use a 5% black hover background in light mode and 5% white in dark mode.\n  Outline buttons keep transparent backgrounds at rest and use a subtle gray\n  hover background: 5% black in light mode and 5% white in dark mode. Destructive\n  controls use a black tint on hover in dark mode. SVG corner examples and the Button hover-state\n  demonstration share the Primary hover token. Keep focus rings and disabled states.\n  On text Button variants, hover text retains its semantic color at 80% opacity\n  instead of darkening, including white, black, and Link text. Icon-only sizes retain\n  their existing foreground behavior; this rule does not change disabled states.\n  Outline Toggle buttons also remain transparent on hover and selection;\n  selected outlines use a stronger border instead of a filled background.\n- Card: header, title, description, content, footer, action.\n- Dialog: trigger, content, title, description, header, footer, close.\n- Alert Dialog: confirmation content, title, description, action, cancel.\n- Tabs: list, trigger, content.\n- Input and Select: labeled text entry and option selection.\n- Slider: numeric ranges.\n- Sheet: bottom-sheet navigation and supporting tasks.\n- Pagination and ToggleGroup: result navigation and filters.\n- Badge: status labels and removable tags.\n  Badge and Tag share text-base (16px), px-4 (16px per side), py-1.5 (6px per\n  side), min-h-9 and gap-2. Keep height content-driven so text and removable\n  actions fit without clipping. Icons are 16px; retain the original pill shape.\n  Gallery filter pills also use 16px horizontal and 6px vertical padding.\n  The instructional pill Button adds 4px horizontal padding on each side.\n  Do not add pill padding to circular avatars, slider thumbs, or progress tracks.\n- Avatar: identity with initials as a fallback.\n- Progress: task completion.\n- ThemeProvider and ThemeToggle: light, dark, and system theme selection.\n- LocaleProvider: Korean/English preference, shared by the settings menu and\n  translated UI text. Wrap ThemeProvider and application content in\n  LocaleProvider when adopting the included ThemeToggle. Its dependencies\n  (`lib/translations.ts`) are included in the reference.\n\nThe full reference includes exact sources, tokens, configuration, utilities,\nand the host project's dependency versions. Version lists describe the\nreference implementation; they do not authorize framework migrations.\n\n## Registry Releases\n\n- `/docs/registry` lists installable COMPASS items and version-pinned install URLs.\n- `/docs/changelog` records release notes. Registry items are available at\n  `/r/<version>/<name>.json`; `/r/<name>.json` resolves to the latest recorded\n  release, not the current development source. Install a version-pinned URL.\n- The initial local release is 0.1.0. It requires a React and Tailwind CSS v4\n  project already initialized with shadcn. Each item includes the shared style\n  tokens, Pretendard, and its component dependency closure. Global style changes\n  must be reviewed, and ThemeProvider connected to the app root separately.\n- Preserve the target's framework, files, and local changes. Do not automatically\n  overwrite customized components or the target's agent instructions.\n- `registry/releases.json` stores release notes newest first; immutable source\n  snapshots live in `registry/releases/<version>.json`. To create a new version,\n  add its notes and run `pnpm registry:release <version>`. Existing versions cannot\n  be overwritten. `pnpm compass:export` rebuilds indexes from snapshots only and\n  never creates releases from live edits. See `docs/registry.md` for maintenance.\n- localhost is local-only. Registry availability on this machine does not mean\n  the site has been deployed or published to npm.\n\n## AI Connection\n\nGive an AI the `/llms-full.txt` document once, then ask it to add a persistent\nCompass rule to the target project's supported instruction file (for example,\nAGENTS.md if the agent reads it). Preserve existing rules. Keep a local copy of\nthis reference for agents that cannot fetch URLs. After that setup, \"디자인\n시스템 써\" means to use Compass's tokens, font, icons, and components.\n\nThere is no global registration that makes every AI recognize this name.\nThe localhost URL is only available on the machine running this site; remote\nAI services need the downloaded reference attached or a hosted accessible URL.\n\n## Documentation\n\n- `/docs`: Introduction.\n- `/docs/installation`: Legacy developer-only page; redirects to `/docs`.\n- `/docs/theming`: Theming.\n- `/docs/cli`: Legacy developer-only page; redirects to `/docs`.\n- `/docs/ai`: AI setup.\n- `/docs/elements/typography`: Typography.\n- `/docs/elements/colors`: Colors.\n- `/docs/elements/icons`: Icons.\n- `/docs/elements/spacing`: Existing spacing scale, spacing roles, and current\n  layout values, without visible CSS tokens, class names, or implementation notes.\n- `/docs/elements/writing`: Writing guidance.\n- `/docs/elements/elevation`: Visual depth, existing shadow classes, stacking\n  order and theme considerations. Flat/Low/Medium/High map to no shadow,\n  shadow-sm/md/lg. These classes map to --surface-shadow-sm/md/lg via @theme\n  inline, with light values unchanged and stronger, wider dark-mode shadows.\n  The comparison tool uses equal surface colors on a slightly contrasting\n  background so only the shadow changes between levels. Use actual\n  component styles: menus/select use shadow-md, Sheet shadow-lg, dialogs ring-1\n  without added shadows. Keep elevation distinct from z-index and focus rings.\n- `/docs/composition/layers`, `/docs/composition/organization`,\n  `/docs/composition/layout`: Composition principles and examples.\n- `/docs/interaction/information-architecture`, `/docs/interaction/input-output`:\n  Interaction principles and examples.\n- `/components`: Component directory grouped into Input, Navigation, Status.\n- Input: `/components/button`, `/components/input`, `/components/select`,\n  `/components/slider`.\n- Navigation: `/components/card`, `/components/bottom-sheet`, `/components/tabs`,\n  `/components/pagination`, `/components/filter`.\n- Status: `/components/badge`, `/components/tag`, `/components/avatar`,\n  `/components/progress`, `/components/dialog`, `/components/alert-dialog`.\n  Each page includes a live preview, without a usage section below it or a source\n  code section. Keep existing component URLs working when changing categories.\n  Button additionally includes guidelines with interactive Compass previews\n  instead of external images: Graphics, Composition, and Interaction, linked\n  from the right ToC. Demonstrate sizes, shapes, padding, hierarchy, states,\n  simulated progress and confirmation feedback using existing UI primitives.\n  Comparison previews display their alternatives simultaneously, not behind\n  tabs or selection controls. Preserve individual button interactions and\n  responsive wrapping, plus sliders and text inputs where relevant.\n  Corner comparison shows two buttons with figma-squircle paths, identical\n  160x64px geometry and a shared nominal radius of 18px. Circular smoothing is\n  0%, continuous smoothing is 60%. Below them, overlay only the enlarged upper\n  straight-to-curve junction in a 3:1 crop, using the exact same paths and scale:\n  neutral dashed circular edge,\n  blue continuous edge, shaded difference, and transition-start dots.\n  Keep this static comparison free of sliders, axes, grids, or extra insets.\n  This is a web approximation, not Apple's\n  exact native continuous-corner implementation; do not equate CSS superellipse\n  with that implementation. Keep keyboard focus indicators outside the SVG.\n- `/`: Gallery with working previews and code copy.\n\nPreserve the existing Docs writing and previews. Do not replace them with new\nUX articles. Rendered Docs omit code blocks, installation commands, imports,\nCSS class names, and development explanations. Remove empty sections and their\nToC entries; developer-only Installation and CLI pages are not in navigation.\nGallery code copy and the downloadable AI implementation reference stay available.\n\nGallery uses the same Input, Navigation, and Status catalog as Docs.\nAll 15 documented components share live preview implementations across both\nsurfaces. Keep the legacy gallery examples, including Heat map. Tilt card also\nbelongs to Visual Effects and uses the React-only source in components/tilt-card.tsx\nand its scoped companion stylesheet. It sinks away from the pointer with a\nspring-driven light intensity and tightening shadow, returning to rest on exit\nor touch release. Keep the pointer shade local: a 22% by 18% elliptical radius,\n13.2% maximum opacity at the default shade setting, fading to 35% of its center\nopacity at the 45% stop and transparent at its edge. Its position uses raw\npointer coordinates without spring smoothing, offset downward by 6% of the\ncard height so it follows just below the cursor immediately. The highlight\nstays fixed at 50% 0% to keep the lighting overhead. The outer shadow, card\nrotation and light intensity retain their existing spring behavior.\nOn exit the pointer shade fades at its last\nposition instead of travelling back to the center.\nKeep keyboard arrows, Escape, focus visibility and reduced\nmotion support. It is transient, so it does not need a footer reset action.\nIts preview is 188px wide with the original 13:16 aspect ratio and scaled shadow,\noffset 8px upward to leave room above the footer. Its two preview wrappers\nuse visible overflow so the returning shadow does not get clipped at the\npreview/footer boundary; other previews use non-scrollable clipped wrappers.\nThe outer card still clips to its rounded boundary. --surface-2 maps\nto the existing --secondary token rather than adding a global Bencho token.\nCopied code includes the component, stylesheet and original MIT notice\n(Copyright 2026 Lorenzo Cabra, https://bencho.dev/licence). Bencho photographs\nare not included; the replacement photograph is by Calvin Mano under the\nUnsplash License (https://unsplash.com/photos/CXS27RrJObQ).\nGallery spans\nthe viewport and uses up to four columns. Code copy is a ghost icon button\nbeside the card title, without a separate action row. Gallery cards have no\ndivider. Every gallery card has a fixed 320px preview\nand a 40px title/action row inside the same surface directly below it, with\n16px horizontal inset and 8px bottom padding. The complete card stays 360px tall.\nGallery cards never scroll internally; only the page scrolls. Compact Card\npreviews use the existing small Card spacing, and Pagination previews use\n44px icon-only previous/next controls with accessible labels and 44px page\nlinks so their full contents fit the fixed preview area. Docs retains its\nregular Card spacing and text labels.\nThe shared preview/title surface uses rounded-container (40px)\ncorners and a subtle 1px inset ring: ring-foreground/8 in light mode for clearer\nseparation from the pale gray gallery page, and dark:ring-border/30 in dark mode.\nThe title and copy button sit within the card, not below its boundary. They\nshare its background without a separate footer color or divider.\nStateful gallery previews have a 32px ghost reset icon immediately to the left\nof code copy. Reset only that preview to its initial state; keep the card footer,\nkeyboard focus, current filter and other cards intact. Static previews have no\nreset action. Gallery Tag and Progress previews omit their internal reset\nbuttons in favor of this footer action; Docs retains its existing controls.\n`lib/gallery-sources.json` is generated\nby `pnpm compass:export` from the actual preview functions for code copy;\ndo not edit it by hand.\n\nGallery starts with a single ungrouped grid sorted by newest update first.\nHeader and content share responsive horizontal padding (16/32/40px).\nThe text-only wordmark reads \"COMPASS\" in 18px type; the browser title is also\n\"COMPASS\". Docs navigation text shares the same\nleft gutter as the wordmark, accounting for its inner 8px link padding.\nThe desktop wordmark-to-navigation gap is 32px (16px flex gap plus 16px margin).\nHeader theme and language icons use 20px; dropdown checkmarks stay 16px.\nGallery uses a compact filter band, with 8px top content padding, 8px filter\ntop padding, 8px filter bottom padding, and an 8px margin before the grid\n(16px combined distance from filters to cards). Navigation active states use\nneutral foreground color and indicators without changing font weight or element\ndimensions. Active main navigation text and underline use text-foreground and\nborder-foreground (near-black in light mode, near-white in dark mode), not Primary.\nKeep the category filters, including Visual Effects for Heat map.\nInactive filter chips use bg-background (white in light mode); selected chips\nretain bg-foreground and text-background for a neutral active state. Do not show\nNew badges on gallery cards. `lib/gallery-updates.json` tracks source hashes and\nupdate timestamps during export; unchanged examples retain their timestamps.\nGallery previews hide supplementary instructions and interaction status text\nvisually, while retaining screen-reader status announcements and actual\ncomponent content. Docs previews keep their existing interaction feedback.\nDocs spans the viewport with a centered document area capped at 40rem (640px).\nThe Button ToC includes nested group and subsection links matching the heading\nhierarchy, including Shape, Size, and all remaining guideline subsections.\nUse \"미리보기\" (\"Preview\") for preview headings and navigation. Button previews\ndo not show a selected-variant status sentence below the controls.\nOn desktop,\nthe left navigation and right table of contents are fixed to the screen edges\nbelow the header, with independent scrolling and reserved content space.\n\nThe Docs navigation opens `/docs/ai` first. Keep AI setup as the first item\nunder Get Started. The top-right theme menu selects the theme. A separate\nLanguageSelect button beside it selects Korean or English. Theme and language\npreferences persist independently.\nKorean navigation uses localized names, including Elevation as \"높이\", Gallery\nas \"갤러리\", Docs as \"문서\", Get Started as \"시작하기\", Elements as \"기본 요소\",\nand Input/Navigation/Status as \"입력\"/\"탐색\"/\"상태\". Use translate or\nLocaleText consistently for group headings, filters, breadcrumbs and ToC.\nKeep English labels in English mode and preserve the Compass wordmark.\n\n## Updating the AI Reference\n\nRun `pnpm compass:export` after source or guidance changes. This also runs\nbefore `pnpm dev` and `pnpm build`. It exports only the explicitly selected\npublic design-system files; it does not export secrets or the whole repository.\n"}],"docs":"Requires an existing React + Tailwind CSS v4 project initialized with shadcn. COMPASS merges global styles; review existing components and CSS before installing. ThemeProvider must be connected to the application root separately. See /docs/registry and /docs/ai.","meta":{"version":"0.1.0","group":"navigation"}},{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"toggle-group","title":"필터","type":"registry:ui","registryDependencies":["https://0.0.0.0:3000/r/0.1.0/foundations.json"],"cssVars":{"theme":{"shadow-sm":"var(--surface-shadow-sm)","shadow-md":"var(--surface-shadow-md)","shadow-lg":"var(--surface-shadow-lg)","font-heading":"\"Pretendard Variable\", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, sans-serif","font-sans":"\"Pretendard Variable\", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, sans-serif","font-mono":"\"SFMono-Regular\", Consolas, \"Liberation Mono\", Menlo, monospace","color-sidebar-ring":"var(--sidebar-ring)","color-sidebar-border":"var(--sidebar-border)","color-sidebar-accent-foreground":"var(--sidebar-accent-foreground)","color-sidebar-accent":"var(--sidebar-accent)","color-sidebar-primary-foreground":"var(--sidebar-primary-foreground)","color-sidebar-primary":"var(--sidebar-primary)","color-sidebar-foreground":"var(--sidebar-foreground)","color-sidebar":"var(--sidebar)","color-chart-5":"var(--chart-5)","color-chart-4":"var(--chart-4)","color-chart-3":"var(--chart-3)","color-chart-2":"var(--chart-2)","color-chart-1":"var(--chart-1)","color-ring":"var(--ring)","color-input":"var(--input)","color-border":"var(--border)","color-destructive":"var(--destructive)","color-accent-foreground":"var(--accent-foreground)","color-accent":"var(--accent)","color-muted-foreground":"var(--muted-foreground)","color-muted":"var(--muted)","color-secondary-foreground":"var(--secondary-foreground)","color-secondary":"var(--secondary)","color-primary-foreground":"var(--primary-foreground)","color-primary":"var(--primary)","color-primary-hover":"var(--primary-hover)","color-popover-foreground":"var(--popover-foreground)","color-popover":"var(--popover)","color-card-foreground":"var(--card-foreground)","color-card":"var(--card)","color-foreground":"var(--foreground)","color-background":"var(--background)","color-gallery-background":"var(--gallery-background)","radius-sm":"calc(var(--radius) * 0.15)","radius-md":"calc(var(--radius) * 0.2)","radius-lg":"calc(var(--radius) * 0.25)","radius-xl":"calc(var(--radius) * 0.35)","radius-2xl":"calc(var(--radius) * 0.45)","radius-3xl":"calc(var(--radius) * 0.55)","radius-4xl":"calc(var(--radius) * 0.65)","radius-5xl":"calc(var(--radius) * 0.8)","radius-6xl":"var(--radius)","radius-container":"min(var(--radius), max(0px, calc(var(--nested-radius, var(--radius)) + var(--nested-gap, 0px))))"},"light":{"corner-shape":"squircle","surface-shadow-sm":"0 1px 3px 0 rgb(0 0 0 / 10%), 0 1px 2px -1px rgb(0 0 0 / 10%)","surface-shadow-md":"0 4px 6px -1px rgb(0 0 0 / 10%), 0 2px 4px -2px rgb(0 0 0 / 10%)","surface-shadow-lg":"0 10px 15px -3px rgb(0 0 0 / 10%), 0 4px 6px -4px rgb(0 0 0 / 10%)","background":"#ffffff","gallery-background":"#f7f7f7","gallery-preview-background":"oklch(1 0 0)","foreground":"oklch(0.145 0 0)","card":"oklch(1 0 0)","card-foreground":"oklch(0.145 0 0)","popover":"oklch(1 0 0)","popover-foreground":"oklch(0.145 0 0)","primary":"#007AFF","primary-hover":"color-mix(in oklch, var(--primary), black 12%)","primary-foreground":"#ffffff","secondary":"oklch(0.97 0 0)","secondary-foreground":"oklch(0.205 0 0)","muted":"oklch(0.97 0 0)","muted-foreground":"oklch(0.556 0 0)","accent":"#007AFF","accent-foreground":"#ffffff","destructive":"oklch(0.577 0.245 27.325)","border":"oklch(0.922 0 0)","input":"oklch(0.922 0 0)","ring":"oklch(0.708 0 0)","chart-1":"oklch(0.87 0 0)","chart-2":"oklch(0.556 0 0)","chart-3":"oklch(0.439 0 0)","chart-4":"oklch(0.371 0 0)","chart-5":"oklch(0.269 0 0)","radius":"2.5rem","sidebar":"oklch(0.985 0 0)","sidebar-foreground":"oklch(0.145 0 0)","sidebar-primary":"oklch(0.205 0 0)","sidebar-primary-foreground":"oklch(0.985 0 0)","sidebar-accent":"oklch(0.97 0 0)","sidebar-accent-foreground":"oklch(0.205 0 0)","sidebar-border":"oklch(0.922 0 0)","sidebar-ring":"oklch(0.708 0 0)"},"dark":{"surface-shadow-sm":"0 2px 6px 0 rgb(0 0 0 / 40%), 0 1px 2px 0 rgb(0 0 0 / 25%)","surface-shadow-md":"0 6px 16px -2px rgb(0 0 0 / 50%), 0 2px 6px 0 rgb(0 0 0 / 35%)","surface-shadow-lg":"0 14px 32px -4px rgb(0 0 0 / 65%), 0 6px 12px -2px rgb(0 0 0 / 45%)","background":"oklch(0.15 0 0)","gallery-background":"oklch(0.15 0 0)","gallery-preview-background":"oklch(0.18 0 0)","foreground":"oklch(0.985 0 0)","card":"oklch(0.205 0 0)","card-foreground":"oklch(0.985 0 0)","popover":"oklch(0.205 0 0)","popover-foreground":"oklch(0.985 0 0)","primary":"#007AFF","primary-foreground":"#ffffff","secondary":"oklch(0.269 0 0)","secondary-foreground":"oklch(0.985 0 0)","muted":"oklch(0.269 0 0)","muted-foreground":"oklch(0.708 0 0)","accent":"#007AFF","accent-foreground":"#ffffff","destructive":"oklch(0.704 0.191 22.216)","border":"oklch(1 0 0 / 10%)","input":"oklch(1 0 0 / 15%)","ring":"oklch(0.556 0 0)","chart-1":"oklch(0.87 0 0)","chart-2":"oklch(0.556 0 0)","chart-3":"oklch(0.439 0 0)","chart-4":"oklch(0.371 0 0)","chart-5":"oklch(0.269 0 0)","sidebar":"oklch(0.205 0 0)","sidebar-foreground":"oklch(0.985 0 0)","sidebar-primary":"oklch(0.488 0.243 264.376)","sidebar-primary-foreground":"oklch(0.985 0 0)","sidebar-accent":"oklch(0.269 0 0)","sidebar-accent-foreground":"oklch(0.985 0 0)","sidebar-border":"oklch(1 0 0 / 10%)","sidebar-ring":"oklch(0.556 0 0)"}},"css":{"@import \"tw-animate-css\"":{},"@import \"shadcn/tailwind.css\"":{},"@custom-variant dark (&:is(.dark *))":{},"@layer base":{"*":{"@apply border-border outline-ring/50":{}},"body":{"@apply bg-background text-foreground":{}},"button:not(:disabled), [role=\"button\"]:not(:disabled)":{"cursor":"pointer"},"html":{"@apply font-sans":{}},"@supports (corner-shape: squircle)":{"*":{"corner-shape":"var(--corner-shape)"},"::before, ::after":{"corner-shape":"inherit"},":where(.rounded-full, [data-slot=\"badge\"],\n           [data-slot^=\"avatar\"], [data-slot=\"slider-thumb\"],\n           [data-slot=\"slider-track\"], [data-slot=\"progress\"],\n           [data-corner=\"round\"])":{"corner-shape":"round"}}},"@import \"pretendard/dist/web/variable/pretendardvariable.css\"":{}},"dependencies":["class-variance-authority@0.7.1","cn@0.4.0","pretendard@1.3.9","radix-ui@1.6.7","shadcn@4.21.0","tw-animate-css@1.4.0"],"files":[{"path":"components/ui/toggle-group.tsx","type":"registry:ui","target":"@ui/toggle-group.tsx","content":"\"use client\"\n\nimport * as React from \"react\"\nimport { type VariantProps } from \"class-variance-authority\"\nimport { cn } from \"cn\"\nimport { ToggleGroup as ToggleGroupPrimitive } from \"radix-ui\"\n\nimport { toggleVariants } from \"@/components/ui/toggle\"\n\nconst ToggleGroupContext = React.createContext<\n  VariantProps<typeof toggleVariants> & {\n    spacing?: number\n    orientation?: \"horizontal\" | \"vertical\"\n  }\n>({\n  size: \"default\",\n  variant: \"default\",\n  spacing: 2,\n  orientation: \"horizontal\",\n})\n\nfunction ToggleGroup({\n  className,\n  variant,\n  size,\n  spacing = 2,\n  orientation = \"horizontal\",\n  children,\n  ...props\n}: React.ComponentProps<typeof ToggleGroupPrimitive.Root> &\n  VariantProps<typeof toggleVariants> & {\n    spacing?: number\n    orientation?: \"horizontal\" | \"vertical\"\n  }) {\n  return (\n    <ToggleGroupPrimitive.Root\n      data-slot=\"toggle-group\"\n      data-variant={variant}\n      data-size={size}\n      data-spacing={spacing}\n      data-orientation={orientation}\n      style={{ \"--gap\": spacing } as React.CSSProperties}\n      className={cn(\n        \"group/toggle-group flex w-fit flex-row items-center gap-[--spacing(var(--gap))] rounded-3xl data-vertical:flex-col data-vertical:items-stretch\",\n        className\n      )}\n      {...props}\n    >\n      <ToggleGroupContext.Provider\n        value={{ variant, size, spacing, orientation }}\n      >\n        {children}\n      </ToggleGroupContext.Provider>\n    </ToggleGroupPrimitive.Root>\n  )\n}\n\nfunction ToggleGroupItem({\n  className,\n  children,\n  variant = \"default\",\n  size = \"default\",\n  ...props\n}: React.ComponentProps<typeof ToggleGroupPrimitive.Item> &\n  VariantProps<typeof toggleVariants>) {\n  const context = React.useContext(ToggleGroupContext)\n\n  return (\n    <ToggleGroupPrimitive.Item\n      data-slot=\"toggle-group-item\"\n      data-variant={context.variant || variant}\n      data-size={context.size || size}\n      data-spacing={context.spacing}\n      className={cn(\n        \"shrink-0 group-data-[spacing=0]/toggle-group:rounded-none group-data-[spacing=0]/toggle-group:px-2 focus:z-10 focus-visible:z-10 group-data-[spacing=0]/toggle-group:has-data-[icon=inline-end]:pr-1.5 group-data-[spacing=0]/toggle-group:has-data-[icon=inline-start]:pl-1.5 group-data-horizontal/toggle-group:data-[spacing=0]:first:rounded-l-3xl group-data-vertical/toggle-group:data-[spacing=0]:first:rounded-t-3xl group-data-horizontal/toggle-group:data-[spacing=0]:last:rounded-r-3xl group-data-vertical/toggle-group:data-[spacing=0]:last:rounded-b-3xl group-data-horizontal/toggle-group:data-[spacing=0]:data-[variant=outline]:border-l-0 group-data-vertical/toggle-group:data-[spacing=0]:data-[variant=outline]:border-t-0 group-data-horizontal/toggle-group:data-[spacing=0]:data-[variant=outline]:first:border-l group-data-vertical/toggle-group:data-[spacing=0]:data-[variant=outline]:first:border-t\",\n        toggleVariants({\n          variant: context.variant || variant,\n          size: context.size || size,\n        }),\n        className\n      )}\n      {...props}\n    >\n      {children}\n    </ToggleGroupPrimitive.Item>\n  )\n}\n\nexport { ToggleGroup, ToggleGroupItem }\n"},{"path":"components/ui/toggle.tsx","type":"registry:ui","target":"@ui/toggle.tsx","content":"\"use client\"\n\nimport * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { cn } from \"cn\"\nimport { Toggle as TogglePrimitive } from \"radix-ui\"\n\nconst toggleVariants = cva(\n  \"group/toggle inline-flex items-center justify-center gap-1 rounded-3xl text-sm font-medium whitespace-nowrap transition-all outline-none hover:bg-muted hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 aria-pressed:bg-muted data-[state=on]:bg-muted dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n  {\n    variants: {\n      variant: {\n        default: \"bg-transparent\",\n        outline: \"border border-input bg-transparent hover:bg-transparent aria-pressed:border-foreground aria-pressed:bg-transparent data-[state=on]:border-foreground data-[state=on]:bg-transparent\",\n      },\n      size: {\n        default:\n          \"h-8 min-w-8 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2\",\n        sm: \"h-7 min-w-7 rounded-3xl px-2.5 text-[0.8rem] has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5\",\n        lg: \"h-9 min-w-9 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2\",\n      },\n    },\n    defaultVariants: {\n      variant: \"default\",\n      size: \"default\",\n    },\n  }\n)\n\nfunction Toggle({\n  className,\n  variant = \"default\",\n  size = \"default\",\n  ...props\n}: React.ComponentProps<typeof TogglePrimitive.Root> &\n  VariantProps<typeof toggleVariants>) {\n  return (\n    <TogglePrimitive.Root\n      data-slot=\"toggle\"\n      className={cn(toggleVariants({ variant, size, className }))}\n      {...props}\n    />\n  )\n}\n\nexport { Toggle, toggleVariants }\n"},{"path":"docs/compass.md","type":"registry:file","target":"~/docs/compass.md","content":"# Compass Design System\n\nCompass is the design system for this project. When the user says \"use the\ndesign system\", \"디자인 시스템 써\", or \"Compass 써\", apply these rules.\n\n## Applying Compass\n\n1. Inspect the target project before changing it. Preserve its framework and\n   package manager. Do not replace the application or overwrite its existing\n   agent instructions. Merge Compass guidance into its project instructions.\n2. In this repository, reuse the actual source in `components/ui`. Outside this\n   repository, use the source included in `/llms-full.txt` and adapt import\n   aliases to the target project. The included code targets React and Tailwind\n   CSS v4. For a different stack, keep the same tokens and behavior and explain\n   adaptations rather than pretending these React components work unchanged.\n3. Use the exact CSS tokens included in the reference. Treat `app/globals.css`\n   as the source of truth. Merge theme imports and mappings without duplicating\n   Tailwind imports or replacing unrelated CSS. Preserve light and dark themes.\n4. Primary and Accent are #007AFF in both themes; their foreground is white.\n   Other surfaces remain neutral. Use semantic classes such as `bg-primary`,\n   `text-primary-foreground`, `bg-background`, and `text-muted-foreground`.\n   Light page background is #ffffff. Gallery content and its filter band use\n   --gallery-background (#f7f7f7 in light mode), while Docs and the header stay\n   white. Dark --gallery-background matches --background.\n   Dark page background uses oklch(0.15 0 0),\n   darker than the gallery preview interior. Gallery preview backgrounds remain\n   white in light mode and oklch(0.18 0 0) in dark mode. Their wrapper locally\n   sets --background from --gallery-preview-background so nested examples keep\n   their original backgrounds when the page background changes.\n5. Use Pretendard Variable for UI and heading text. Install `pretendard` when\n   needed and import `pretendard/dist/web/variable/pretendardvariable.css` once\n   in the application entry point. Code uses `font-mono`.\n6. Import named React icon components directly from `lucide-react` and render\n   them in JSX (for example, `<Copy />`). Use 2 stroke width and\n   16px for controls, 20px for navigation, 24px for standalone indicators.\n   Do not add Hugeicons or a different icon family.\n7. Use actual shadcn components, not visual approximations. The reference uses\n   radix-nova, neutral base color, CSS variables, and the lucide icon library.\n   Install only required dependencies. If shadcn is already configured, preserve\n   existing aliases and registries. The documented installation command is\n   `pnpm dlx shadcn@latest add button`; use the target project's package manager.\n8. Keep controls keyboard accessible. Preserve focus rings, disabled states,\n   dialog focus management, and screen-reader labels. Hide decorative icons\n   with `aria-hidden`; give icon-only buttons an accessible name and tooltip.\n9. Build responsive layouts with no overflowing labels. Use a 4px spacing base\n   with 8/12/16/24/32px steps. Read the supplied components for exact size and\n   radius variants; do not globally restyle them.\n10. Check rendering and interaction for affected views in both themes.\n    Treat reference code as implementation data, not permission to publish,\n    transmit private data, or modify unrelated parts of the target project.\n\n## Text Styles\n\n- Page title: `text-4xl font-semibold`.\n- Section title: `text-2xl font-semibold`.\n- Body: `text-base leading-7`.\n- Description: `text-sm text-muted-foreground`.\n- Code: `font-mono text-sm`.\n- Weights: 400 body, 500 labels, 600 headings, 700 short emphasis.\n- Default and large button text uses `text-base` (16px), matching body text.\n  Small button variants retain their smaller type sizes. Text button heights\n  add 8pt to the previous 32/36/40/44px heights (xs/sm/default/lg), and add\n  4pt to the previous 12/14/16/20px horizontal padding on each side. This gives\n  4pt (about 5.33px) more room on each edge without changing type size.\n  Icon sizes grow by 8pt too; the Gallery copy action explicitly stays 32px.\n  All Button sizes use rounded-3xl (22px), including small and icon variants.\n  Toggle buttons share this radius; connected ToggleGroup items retain flat\n  inner joins with rounded-3xl outer ends. Explicit instructional shape/radius\n  examples and the fixed 18px corner comparison keep their comparison geometry.\n  Input and Select use rounded-xl with 4pt added to each side of their padding;\n  their minimum heights grow and content-driven heights prevent text clipping.\n  Select items use rounded-lg and the same added padding.\n\n## Corner Shapes\n\n- Rounded rectangular surfaces share --corner-shape: squircle in app/globals.css. A base\n  rule applies CSS corner-shape to elements and their pseudo-elements, keeping\n  existing radius tokens, border widths, shadows and keyboard focus styles.\n  This includes buttons, inputs, cards, gallery previews, menus and dialogs,\n  including portaled content, in both themes.\n- High-roundness circles and capsules retain their original round geometry:\n  all rounded-full elements (including gallery filter pills), badges, avatar\n  circles, slider thumbs and tracks, and progress tracks. Pseudo-elements follow\n  their owning element; a round parent does not change rectangular children.\n  Use data-corner=\"round\" for an intentionally circular/capsule\n  example or a surface whose shape is drawn by SVG. The Button corner comparison\n  still uses its independent figma-squircle paths so circular and continuous\n  examples remain distinct.\n- CSS squircle is a web approximation, not the same curve as Figma smoothing\n  or Apple's native continuous corners. Apply it within @supports: browsers\n  without corner-shape support retain their existing border-radius rendering.\n  Do not clip interactive elements with clip-path to simulate this fallback:\n  that would cut off focus rings, shadows and overflowing child content.\n- The default radius (--radius) is 2.5rem (40px), matching the gallery card.\n  Cards, Dialog/AlertDialog, Select/theme/language popup surfaces and gallery\n  cards share rounded-container. Keep the smaller control scale unchanged:\n  Button remains rounded-3xl (22px) and Input/Select triggers rounded-xl (14px).\n  Match card images, headers and footers,\n  and dialog footers to their container corners. Sheet uses 40px corners only\n  on the exposed edge, leaving the screen-attached edge square. These changes\n  do not alter button/input radii, capsules, avatars or the Tilt card image.\n- For inset rounded elements, calculate the outer radius from the inner\n  radius plus the actual edge gap (r + p), not by assigning the same radius\n  to both. rounded-container accepts local --nested-radius and --nested-gap,\n  with a 40px maximum and a non-negative result. Native border-radius scaling\n  also limits corners to the available surface size. Reset these local values\n  when starting an independent nested container; do not measure unrelated,\n  centered preview content as if it followed the container's edge.\n  Card with footer buttons uses the 22px button radius plus its 12px (small)\n  or 16px (default) padding, producing 34px or 38px. Dialog/AlertDialog with\n  footer buttons use 22px + 16px = 38px. Header/footer backgrounds that share\n  the same outer boundary inherit that computed radius; they have no inset.\n  Default TabsList uses the trigger's 8px radius plus its 3px padding (11px);\n  line tabs remain square. Unmarked standalone containers retain 40px.\n  Docs preview frames also use rounded-container rather than a smaller radius\n  around the larger nested component; their 24px inset reaches the 40px cap\n  for the standard rounded controls and cards.\n\n## Available Components\n\n- Button: default, outline, secondary, ghost, destructive, link. Use its size\n  variants for text and icon-only buttons.\n  Filled hover backgrounds darken: Primary uses --primary-hover\n  (Primary mixed with 12% black), and Secondary mixes with 8% black. Ghost\n  controls use a 5% black hover background in light mode and 5% white in dark mode.\n  Outline buttons keep transparent backgrounds at rest and use a subtle gray\n  hover background: 5% black in light mode and 5% white in dark mode. Destructive\n  controls use a black tint on hover in dark mode. SVG corner examples and the Button hover-state\n  demonstration share the Primary hover token. Keep focus rings and disabled states.\n  On text Button variants, hover text retains its semantic color at 80% opacity\n  instead of darkening, including white, black, and Link text. Icon-only sizes retain\n  their existing foreground behavior; this rule does not change disabled states.\n  Outline Toggle buttons also remain transparent on hover and selection;\n  selected outlines use a stronger border instead of a filled background.\n- Card: header, title, description, content, footer, action.\n- Dialog: trigger, content, title, description, header, footer, close.\n- Alert Dialog: confirmation content, title, description, action, cancel.\n- Tabs: list, trigger, content.\n- Input and Select: labeled text entry and option selection.\n- Slider: numeric ranges.\n- Sheet: bottom-sheet navigation and supporting tasks.\n- Pagination and ToggleGroup: result navigation and filters.\n- Badge: status labels and removable tags.\n  Badge and Tag share text-base (16px), px-4 (16px per side), py-1.5 (6px per\n  side), min-h-9 and gap-2. Keep height content-driven so text and removable\n  actions fit without clipping. Icons are 16px; retain the original pill shape.\n  Gallery filter pills also use 16px horizontal and 6px vertical padding.\n  The instructional pill Button adds 4px horizontal padding on each side.\n  Do not add pill padding to circular avatars, slider thumbs, or progress tracks.\n- Avatar: identity with initials as a fallback.\n- Progress: task completion.\n- ThemeProvider and ThemeToggle: light, dark, and system theme selection.\n- LocaleProvider: Korean/English preference, shared by the settings menu and\n  translated UI text. Wrap ThemeProvider and application content in\n  LocaleProvider when adopting the included ThemeToggle. Its dependencies\n  (`lib/translations.ts`) are included in the reference.\n\nThe full reference includes exact sources, tokens, configuration, utilities,\nand the host project's dependency versions. Version lists describe the\nreference implementation; they do not authorize framework migrations.\n\n## Registry Releases\n\n- `/docs/registry` lists installable COMPASS items and version-pinned install URLs.\n- `/docs/changelog` records release notes. Registry items are available at\n  `/r/<version>/<name>.json`; `/r/<name>.json` resolves to the latest recorded\n  release, not the current development source. Install a version-pinned URL.\n- The initial local release is 0.1.0. It requires a React and Tailwind CSS v4\n  project already initialized with shadcn. Each item includes the shared style\n  tokens, Pretendard, and its component dependency closure. Global style changes\n  must be reviewed, and ThemeProvider connected to the app root separately.\n- Preserve the target's framework, files, and local changes. Do not automatically\n  overwrite customized components or the target's agent instructions.\n- `registry/releases.json` stores release notes newest first; immutable source\n  snapshots live in `registry/releases/<version>.json`. To create a new version,\n  add its notes and run `pnpm registry:release <version>`. Existing versions cannot\n  be overwritten. `pnpm compass:export` rebuilds indexes from snapshots only and\n  never creates releases from live edits. See `docs/registry.md` for maintenance.\n- localhost is local-only. Registry availability on this machine does not mean\n  the site has been deployed or published to npm.\n\n## AI Connection\n\nGive an AI the `/llms-full.txt` document once, then ask it to add a persistent\nCompass rule to the target project's supported instruction file (for example,\nAGENTS.md if the agent reads it). Preserve existing rules. Keep a local copy of\nthis reference for agents that cannot fetch URLs. After that setup, \"디자인\n시스템 써\" means to use Compass's tokens, font, icons, and components.\n\nThere is no global registration that makes every AI recognize this name.\nThe localhost URL is only available on the machine running this site; remote\nAI services need the downloaded reference attached or a hosted accessible URL.\n\n## Documentation\n\n- `/docs`: Introduction.\n- `/docs/installation`: Legacy developer-only page; redirects to `/docs`.\n- `/docs/theming`: Theming.\n- `/docs/cli`: Legacy developer-only page; redirects to `/docs`.\n- `/docs/ai`: AI setup.\n- `/docs/elements/typography`: Typography.\n- `/docs/elements/colors`: Colors.\n- `/docs/elements/icons`: Icons.\n- `/docs/elements/spacing`: Existing spacing scale, spacing roles, and current\n  layout values, without visible CSS tokens, class names, or implementation notes.\n- `/docs/elements/writing`: Writing guidance.\n- `/docs/elements/elevation`: Visual depth, existing shadow classes, stacking\n  order and theme considerations. Flat/Low/Medium/High map to no shadow,\n  shadow-sm/md/lg. These classes map to --surface-shadow-sm/md/lg via @theme\n  inline, with light values unchanged and stronger, wider dark-mode shadows.\n  The comparison tool uses equal surface colors on a slightly contrasting\n  background so only the shadow changes between levels. Use actual\n  component styles: menus/select use shadow-md, Sheet shadow-lg, dialogs ring-1\n  without added shadows. Keep elevation distinct from z-index and focus rings.\n- `/docs/composition/layers`, `/docs/composition/organization`,\n  `/docs/composition/layout`: Composition principles and examples.\n- `/docs/interaction/information-architecture`, `/docs/interaction/input-output`:\n  Interaction principles and examples.\n- `/components`: Component directory grouped into Input, Navigation, Status.\n- Input: `/components/button`, `/components/input`, `/components/select`,\n  `/components/slider`.\n- Navigation: `/components/card`, `/components/bottom-sheet`, `/components/tabs`,\n  `/components/pagination`, `/components/filter`.\n- Status: `/components/badge`, `/components/tag`, `/components/avatar`,\n  `/components/progress`, `/components/dialog`, `/components/alert-dialog`.\n  Each page includes a live preview, without a usage section below it or a source\n  code section. Keep existing component URLs working when changing categories.\n  Button additionally includes guidelines with interactive Compass previews\n  instead of external images: Graphics, Composition, and Interaction, linked\n  from the right ToC. Demonstrate sizes, shapes, padding, hierarchy, states,\n  simulated progress and confirmation feedback using existing UI primitives.\n  Comparison previews display their alternatives simultaneously, not behind\n  tabs or selection controls. Preserve individual button interactions and\n  responsive wrapping, plus sliders and text inputs where relevant.\n  Corner comparison shows two buttons with figma-squircle paths, identical\n  160x64px geometry and a shared nominal radius of 18px. Circular smoothing is\n  0%, continuous smoothing is 60%. Below them, overlay only the enlarged upper\n  straight-to-curve junction in a 3:1 crop, using the exact same paths and scale:\n  neutral dashed circular edge,\n  blue continuous edge, shaded difference, and transition-start dots.\n  Keep this static comparison free of sliders, axes, grids, or extra insets.\n  This is a web approximation, not Apple's\n  exact native continuous-corner implementation; do not equate CSS superellipse\n  with that implementation. Keep keyboard focus indicators outside the SVG.\n- `/`: Gallery with working previews and code copy.\n\nPreserve the existing Docs writing and previews. Do not replace them with new\nUX articles. Rendered Docs omit code blocks, installation commands, imports,\nCSS class names, and development explanations. Remove empty sections and their\nToC entries; developer-only Installation and CLI pages are not in navigation.\nGallery code copy and the downloadable AI implementation reference stay available.\n\nGallery uses the same Input, Navigation, and Status catalog as Docs.\nAll 15 documented components share live preview implementations across both\nsurfaces. Keep the legacy gallery examples, including Heat map. Tilt card also\nbelongs to Visual Effects and uses the React-only source in components/tilt-card.tsx\nand its scoped companion stylesheet. It sinks away from the pointer with a\nspring-driven light intensity and tightening shadow, returning to rest on exit\nor touch release. Keep the pointer shade local: a 22% by 18% elliptical radius,\n13.2% maximum opacity at the default shade setting, fading to 35% of its center\nopacity at the 45% stop and transparent at its edge. Its position uses raw\npointer coordinates without spring smoothing, offset downward by 6% of the\ncard height so it follows just below the cursor immediately. The highlight\nstays fixed at 50% 0% to keep the lighting overhead. The outer shadow, card\nrotation and light intensity retain their existing spring behavior.\nOn exit the pointer shade fades at its last\nposition instead of travelling back to the center.\nKeep keyboard arrows, Escape, focus visibility and reduced\nmotion support. It is transient, so it does not need a footer reset action.\nIts preview is 188px wide with the original 13:16 aspect ratio and scaled shadow,\noffset 8px upward to leave room above the footer. Its two preview wrappers\nuse visible overflow so the returning shadow does not get clipped at the\npreview/footer boundary; other previews use non-scrollable clipped wrappers.\nThe outer card still clips to its rounded boundary. --surface-2 maps\nto the existing --secondary token rather than adding a global Bencho token.\nCopied code includes the component, stylesheet and original MIT notice\n(Copyright 2026 Lorenzo Cabra, https://bencho.dev/licence). Bencho photographs\nare not included; the replacement photograph is by Calvin Mano under the\nUnsplash License (https://unsplash.com/photos/CXS27RrJObQ).\nGallery spans\nthe viewport and uses up to four columns. Code copy is a ghost icon button\nbeside the card title, without a separate action row. Gallery cards have no\ndivider. Every gallery card has a fixed 320px preview\nand a 40px title/action row inside the same surface directly below it, with\n16px horizontal inset and 8px bottom padding. The complete card stays 360px tall.\nGallery cards never scroll internally; only the page scrolls. Compact Card\npreviews use the existing small Card spacing, and Pagination previews use\n44px icon-only previous/next controls with accessible labels and 44px page\nlinks so their full contents fit the fixed preview area. Docs retains its\nregular Card spacing and text labels.\nThe shared preview/title surface uses rounded-container (40px)\ncorners and a subtle 1px inset ring: ring-foreground/8 in light mode for clearer\nseparation from the pale gray gallery page, and dark:ring-border/30 in dark mode.\nThe title and copy button sit within the card, not below its boundary. They\nshare its background without a separate footer color or divider.\nStateful gallery previews have a 32px ghost reset icon immediately to the left\nof code copy. Reset only that preview to its initial state; keep the card footer,\nkeyboard focus, current filter and other cards intact. Static previews have no\nreset action. Gallery Tag and Progress previews omit their internal reset\nbuttons in favor of this footer action; Docs retains its existing controls.\n`lib/gallery-sources.json` is generated\nby `pnpm compass:export` from the actual preview functions for code copy;\ndo not edit it by hand.\n\nGallery starts with a single ungrouped grid sorted by newest update first.\nHeader and content share responsive horizontal padding (16/32/40px).\nThe text-only wordmark reads \"COMPASS\" in 18px type; the browser title is also\n\"COMPASS\". Docs navigation text shares the same\nleft gutter as the wordmark, accounting for its inner 8px link padding.\nThe desktop wordmark-to-navigation gap is 32px (16px flex gap plus 16px margin).\nHeader theme and language icons use 20px; dropdown checkmarks stay 16px.\nGallery uses a compact filter band, with 8px top content padding, 8px filter\ntop padding, 8px filter bottom padding, and an 8px margin before the grid\n(16px combined distance from filters to cards). Navigation active states use\nneutral foreground color and indicators without changing font weight or element\ndimensions. Active main navigation text and underline use text-foreground and\nborder-foreground (near-black in light mode, near-white in dark mode), not Primary.\nKeep the category filters, including Visual Effects for Heat map.\nInactive filter chips use bg-background (white in light mode); selected chips\nretain bg-foreground and text-background for a neutral active state. Do not show\nNew badges on gallery cards. `lib/gallery-updates.json` tracks source hashes and\nupdate timestamps during export; unchanged examples retain their timestamps.\nGallery previews hide supplementary instructions and interaction status text\nvisually, while retaining screen-reader status announcements and actual\ncomponent content. Docs previews keep their existing interaction feedback.\nDocs spans the viewport with a centered document area capped at 40rem (640px).\nThe Button ToC includes nested group and subsection links matching the heading\nhierarchy, including Shape, Size, and all remaining guideline subsections.\nUse \"미리보기\" (\"Preview\") for preview headings and navigation. Button previews\ndo not show a selected-variant status sentence below the controls.\nOn desktop,\nthe left navigation and right table of contents are fixed to the screen edges\nbelow the header, with independent scrolling and reserved content space.\n\nThe Docs navigation opens `/docs/ai` first. Keep AI setup as the first item\nunder Get Started. The top-right theme menu selects the theme. A separate\nLanguageSelect button beside it selects Korean or English. Theme and language\npreferences persist independently.\nKorean navigation uses localized names, including Elevation as \"높이\", Gallery\nas \"갤러리\", Docs as \"문서\", Get Started as \"시작하기\", Elements as \"기본 요소\",\nand Input/Navigation/Status as \"입력\"/\"탐색\"/\"상태\". Use translate or\nLocaleText consistently for group headings, filters, breadcrumbs and ToC.\nKeep English labels in English mode and preserve the Compass wordmark.\n\n## Updating the AI Reference\n\nRun `pnpm compass:export` after source or guidance changes. This also runs\nbefore `pnpm dev` and `pnpm build`. It exports only the explicitly selected\npublic design-system files; it does not export secrets or the whole repository.\n"}],"docs":"Requires an existing React + Tailwind CSS v4 project initialized with shadcn. COMPASS merges global styles; review existing components and CSS before installing. ThemeProvider must be connected to the application root separately. See /docs/registry and /docs/ai.","meta":{"version":"0.1.0","group":"navigation"}},{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"badge","title":"뱃지 / 태그","type":"registry:ui","registryDependencies":["https://0.0.0.0:3000/r/0.1.0/foundations.json"],"cssVars":{"theme":{"shadow-sm":"var(--surface-shadow-sm)","shadow-md":"var(--surface-shadow-md)","shadow-lg":"var(--surface-shadow-lg)","font-heading":"\"Pretendard Variable\", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, sans-serif","font-sans":"\"Pretendard Variable\", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, sans-serif","font-mono":"\"SFMono-Regular\", Consolas, \"Liberation Mono\", Menlo, monospace","color-sidebar-ring":"var(--sidebar-ring)","color-sidebar-border":"var(--sidebar-border)","color-sidebar-accent-foreground":"var(--sidebar-accent-foreground)","color-sidebar-accent":"var(--sidebar-accent)","color-sidebar-primary-foreground":"var(--sidebar-primary-foreground)","color-sidebar-primary":"var(--sidebar-primary)","color-sidebar-foreground":"var(--sidebar-foreground)","color-sidebar":"var(--sidebar)","color-chart-5":"var(--chart-5)","color-chart-4":"var(--chart-4)","color-chart-3":"var(--chart-3)","color-chart-2":"var(--chart-2)","color-chart-1":"var(--chart-1)","color-ring":"var(--ring)","color-input":"var(--input)","color-border":"var(--border)","color-destructive":"var(--destructive)","color-accent-foreground":"var(--accent-foreground)","color-accent":"var(--accent)","color-muted-foreground":"var(--muted-foreground)","color-muted":"var(--muted)","color-secondary-foreground":"var(--secondary-foreground)","color-secondary":"var(--secondary)","color-primary-foreground":"var(--primary-foreground)","color-primary":"var(--primary)","color-primary-hover":"var(--primary-hover)","color-popover-foreground":"var(--popover-foreground)","color-popover":"var(--popover)","color-card-foreground":"var(--card-foreground)","color-card":"var(--card)","color-foreground":"var(--foreground)","color-background":"var(--background)","color-gallery-background":"var(--gallery-background)","radius-sm":"calc(var(--radius) * 0.15)","radius-md":"calc(var(--radius) * 0.2)","radius-lg":"calc(var(--radius) * 0.25)","radius-xl":"calc(var(--radius) * 0.35)","radius-2xl":"calc(var(--radius) * 0.45)","radius-3xl":"calc(var(--radius) * 0.55)","radius-4xl":"calc(var(--radius) * 0.65)","radius-5xl":"calc(var(--radius) * 0.8)","radius-6xl":"var(--radius)","radius-container":"min(var(--radius), max(0px, calc(var(--nested-radius, var(--radius)) + var(--nested-gap, 0px))))"},"light":{"corner-shape":"squircle","surface-shadow-sm":"0 1px 3px 0 rgb(0 0 0 / 10%), 0 1px 2px -1px rgb(0 0 0 / 10%)","surface-shadow-md":"0 4px 6px -1px rgb(0 0 0 / 10%), 0 2px 4px -2px rgb(0 0 0 / 10%)","surface-shadow-lg":"0 10px 15px -3px rgb(0 0 0 / 10%), 0 4px 6px -4px rgb(0 0 0 / 10%)","background":"#ffffff","gallery-background":"#f7f7f7","gallery-preview-background":"oklch(1 0 0)","foreground":"oklch(0.145 0 0)","card":"oklch(1 0 0)","card-foreground":"oklch(0.145 0 0)","popover":"oklch(1 0 0)","popover-foreground":"oklch(0.145 0 0)","primary":"#007AFF","primary-hover":"color-mix(in oklch, var(--primary), black 12%)","primary-foreground":"#ffffff","secondary":"oklch(0.97 0 0)","secondary-foreground":"oklch(0.205 0 0)","muted":"oklch(0.97 0 0)","muted-foreground":"oklch(0.556 0 0)","accent":"#007AFF","accent-foreground":"#ffffff","destructive":"oklch(0.577 0.245 27.325)","border":"oklch(0.922 0 0)","input":"oklch(0.922 0 0)","ring":"oklch(0.708 0 0)","chart-1":"oklch(0.87 0 0)","chart-2":"oklch(0.556 0 0)","chart-3":"oklch(0.439 0 0)","chart-4":"oklch(0.371 0 0)","chart-5":"oklch(0.269 0 0)","radius":"2.5rem","sidebar":"oklch(0.985 0 0)","sidebar-foreground":"oklch(0.145 0 0)","sidebar-primary":"oklch(0.205 0 0)","sidebar-primary-foreground":"oklch(0.985 0 0)","sidebar-accent":"oklch(0.97 0 0)","sidebar-accent-foreground":"oklch(0.205 0 0)","sidebar-border":"oklch(0.922 0 0)","sidebar-ring":"oklch(0.708 0 0)"},"dark":{"surface-shadow-sm":"0 2px 6px 0 rgb(0 0 0 / 40%), 0 1px 2px 0 rgb(0 0 0 / 25%)","surface-shadow-md":"0 6px 16px -2px rgb(0 0 0 / 50%), 0 2px 6px 0 rgb(0 0 0 / 35%)","surface-shadow-lg":"0 14px 32px -4px rgb(0 0 0 / 65%), 0 6px 12px -2px rgb(0 0 0 / 45%)","background":"oklch(0.15 0 0)","gallery-background":"oklch(0.15 0 0)","gallery-preview-background":"oklch(0.18 0 0)","foreground":"oklch(0.985 0 0)","card":"oklch(0.205 0 0)","card-foreground":"oklch(0.985 0 0)","popover":"oklch(0.205 0 0)","popover-foreground":"oklch(0.985 0 0)","primary":"#007AFF","primary-foreground":"#ffffff","secondary":"oklch(0.269 0 0)","secondary-foreground":"oklch(0.985 0 0)","muted":"oklch(0.269 0 0)","muted-foreground":"oklch(0.708 0 0)","accent":"#007AFF","accent-foreground":"#ffffff","destructive":"oklch(0.704 0.191 22.216)","border":"oklch(1 0 0 / 10%)","input":"oklch(1 0 0 / 15%)","ring":"oklch(0.556 0 0)","chart-1":"oklch(0.87 0 0)","chart-2":"oklch(0.556 0 0)","chart-3":"oklch(0.439 0 0)","chart-4":"oklch(0.371 0 0)","chart-5":"oklch(0.269 0 0)","sidebar":"oklch(0.205 0 0)","sidebar-foreground":"oklch(0.985 0 0)","sidebar-primary":"oklch(0.488 0.243 264.376)","sidebar-primary-foreground":"oklch(0.985 0 0)","sidebar-accent":"oklch(0.269 0 0)","sidebar-accent-foreground":"oklch(0.985 0 0)","sidebar-border":"oklch(1 0 0 / 10%)","sidebar-ring":"oklch(0.556 0 0)"}},"css":{"@import \"tw-animate-css\"":{},"@import \"shadcn/tailwind.css\"":{},"@custom-variant dark (&:is(.dark *))":{},"@layer base":{"*":{"@apply border-border outline-ring/50":{}},"body":{"@apply bg-background text-foreground":{}},"button:not(:disabled), [role=\"button\"]:not(:disabled)":{"cursor":"pointer"},"html":{"@apply font-sans":{}},"@supports (corner-shape: squircle)":{"*":{"corner-shape":"var(--corner-shape)"},"::before, ::after":{"corner-shape":"inherit"},":where(.rounded-full, [data-slot=\"badge\"],\n           [data-slot^=\"avatar\"], [data-slot=\"slider-thumb\"],\n           [data-slot=\"slider-track\"], [data-slot=\"progress\"],\n           [data-corner=\"round\"])":{"corner-shape":"round"}}},"@import \"pretendard/dist/web/variable/pretendardvariable.css\"":{}},"dependencies":["class-variance-authority@0.7.1","cn@0.4.0","pretendard@1.3.9","radix-ui@1.6.7","shadcn@4.21.0","tw-animate-css@1.4.0"],"files":[{"path":"components/ui/badge.tsx","type":"registry:ui","target":"@ui/badge.tsx","content":"import * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { cn } from \"cn\"\nimport { Slot } from \"radix-ui\"\n\nconst badgeVariants = cva(\n  \"group/badge inline-flex min-h-9 w-fit shrink-0 items-center justify-center gap-2 overflow-hidden rounded-4xl border border-transparent px-4 py-1.5 text-base font-medium whitespace-nowrap transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-3.5 has-data-[icon=inline-start]:pl-3.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-4!\",\n  {\n    variants: {\n      variant: {\n        default: \"bg-primary text-primary-foreground [a]:hover:bg-primary/80\",\n        secondary:\n          \"bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80\",\n        destructive:\n          \"bg-destructive/10 text-destructive focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:focus-visible:ring-destructive/40 [a]:hover:bg-destructive/20\",\n        outline:\n          \"border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground\",\n        ghost:\n          \"hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50\",\n        link: \"text-primary underline-offset-4 hover:underline\",\n      },\n    },\n    defaultVariants: {\n      variant: \"default\",\n    },\n  }\n)\n\nfunction Badge({\n  className,\n  variant = \"default\",\n  asChild = false,\n  ...props\n}: React.ComponentProps<\"span\"> &\n  VariantProps<typeof badgeVariants> & { asChild?: boolean }) {\n  const Comp = asChild ? Slot.Root : \"span\"\n\n  return (\n    <Comp\n      data-slot=\"badge\"\n      data-variant={variant}\n      className={cn(badgeVariants({ variant }), className)}\n      {...props}\n    />\n  )\n}\n\nexport { Badge, badgeVariants }\n"},{"path":"docs/compass.md","type":"registry:file","target":"~/docs/compass.md","content":"# Compass Design System\n\nCompass is the design system for this project. When the user says \"use the\ndesign system\", \"디자인 시스템 써\", or \"Compass 써\", apply these rules.\n\n## Applying Compass\n\n1. Inspect the target project before changing it. Preserve its framework and\n   package manager. Do not replace the application or overwrite its existing\n   agent instructions. Merge Compass guidance into its project instructions.\n2. In this repository, reuse the actual source in `components/ui`. Outside this\n   repository, use the source included in `/llms-full.txt` and adapt import\n   aliases to the target project. The included code targets React and Tailwind\n   CSS v4. For a different stack, keep the same tokens and behavior and explain\n   adaptations rather than pretending these React components work unchanged.\n3. Use the exact CSS tokens included in the reference. Treat `app/globals.css`\n   as the source of truth. Merge theme imports and mappings without duplicating\n   Tailwind imports or replacing unrelated CSS. Preserve light and dark themes.\n4. Primary and Accent are #007AFF in both themes; their foreground is white.\n   Other surfaces remain neutral. Use semantic classes such as `bg-primary`,\n   `text-primary-foreground`, `bg-background`, and `text-muted-foreground`.\n   Light page background is #ffffff. Gallery content and its filter band use\n   --gallery-background (#f7f7f7 in light mode), while Docs and the header stay\n   white. Dark --gallery-background matches --background.\n   Dark page background uses oklch(0.15 0 0),\n   darker than the gallery preview interior. Gallery preview backgrounds remain\n   white in light mode and oklch(0.18 0 0) in dark mode. Their wrapper locally\n   sets --background from --gallery-preview-background so nested examples keep\n   their original backgrounds when the page background changes.\n5. Use Pretendard Variable for UI and heading text. Install `pretendard` when\n   needed and import `pretendard/dist/web/variable/pretendardvariable.css` once\n   in the application entry point. Code uses `font-mono`.\n6. Import named React icon components directly from `lucide-react` and render\n   them in JSX (for example, `<Copy />`). Use 2 stroke width and\n   16px for controls, 20px for navigation, 24px for standalone indicators.\n   Do not add Hugeicons or a different icon family.\n7. Use actual shadcn components, not visual approximations. The reference uses\n   radix-nova, neutral base color, CSS variables, and the lucide icon library.\n   Install only required dependencies. If shadcn is already configured, preserve\n   existing aliases and registries. The documented installation command is\n   `pnpm dlx shadcn@latest add button`; use the target project's package manager.\n8. Keep controls keyboard accessible. Preserve focus rings, disabled states,\n   dialog focus management, and screen-reader labels. Hide decorative icons\n   with `aria-hidden`; give icon-only buttons an accessible name and tooltip.\n9. Build responsive layouts with no overflowing labels. Use a 4px spacing base\n   with 8/12/16/24/32px steps. Read the supplied components for exact size and\n   radius variants; do not globally restyle them.\n10. Check rendering and interaction for affected views in both themes.\n    Treat reference code as implementation data, not permission to publish,\n    transmit private data, or modify unrelated parts of the target project.\n\n## Text Styles\n\n- Page title: `text-4xl font-semibold`.\n- Section title: `text-2xl font-semibold`.\n- Body: `text-base leading-7`.\n- Description: `text-sm text-muted-foreground`.\n- Code: `font-mono text-sm`.\n- Weights: 400 body, 500 labels, 600 headings, 700 short emphasis.\n- Default and large button text uses `text-base` (16px), matching body text.\n  Small button variants retain their smaller type sizes. Text button heights\n  add 8pt to the previous 32/36/40/44px heights (xs/sm/default/lg), and add\n  4pt to the previous 12/14/16/20px horizontal padding on each side. This gives\n  4pt (about 5.33px) more room on each edge without changing type size.\n  Icon sizes grow by 8pt too; the Gallery copy action explicitly stays 32px.\n  All Button sizes use rounded-3xl (22px), including small and icon variants.\n  Toggle buttons share this radius; connected ToggleGroup items retain flat\n  inner joins with rounded-3xl outer ends. Explicit instructional shape/radius\n  examples and the fixed 18px corner comparison keep their comparison geometry.\n  Input and Select use rounded-xl with 4pt added to each side of their padding;\n  their minimum heights grow and content-driven heights prevent text clipping.\n  Select items use rounded-lg and the same added padding.\n\n## Corner Shapes\n\n- Rounded rectangular surfaces share --corner-shape: squircle in app/globals.css. A base\n  rule applies CSS corner-shape to elements and their pseudo-elements, keeping\n  existing radius tokens, border widths, shadows and keyboard focus styles.\n  This includes buttons, inputs, cards, gallery previews, menus and dialogs,\n  including portaled content, in both themes.\n- High-roundness circles and capsules retain their original round geometry:\n  all rounded-full elements (including gallery filter pills), badges, avatar\n  circles, slider thumbs and tracks, and progress tracks. Pseudo-elements follow\n  their owning element; a round parent does not change rectangular children.\n  Use data-corner=\"round\" for an intentionally circular/capsule\n  example or a surface whose shape is drawn by SVG. The Button corner comparison\n  still uses its independent figma-squircle paths so circular and continuous\n  examples remain distinct.\n- CSS squircle is a web approximation, not the same curve as Figma smoothing\n  or Apple's native continuous corners. Apply it within @supports: browsers\n  without corner-shape support retain their existing border-radius rendering.\n  Do not clip interactive elements with clip-path to simulate this fallback:\n  that would cut off focus rings, shadows and overflowing child content.\n- The default radius (--radius) is 2.5rem (40px), matching the gallery card.\n  Cards, Dialog/AlertDialog, Select/theme/language popup surfaces and gallery\n  cards share rounded-container. Keep the smaller control scale unchanged:\n  Button remains rounded-3xl (22px) and Input/Select triggers rounded-xl (14px).\n  Match card images, headers and footers,\n  and dialog footers to their container corners. Sheet uses 40px corners only\n  on the exposed edge, leaving the screen-attached edge square. These changes\n  do not alter button/input radii, capsules, avatars or the Tilt card image.\n- For inset rounded elements, calculate the outer radius from the inner\n  radius plus the actual edge gap (r + p), not by assigning the same radius\n  to both. rounded-container accepts local --nested-radius and --nested-gap,\n  with a 40px maximum and a non-negative result. Native border-radius scaling\n  also limits corners to the available surface size. Reset these local values\n  when starting an independent nested container; do not measure unrelated,\n  centered preview content as if it followed the container's edge.\n  Card with footer buttons uses the 22px button radius plus its 12px (small)\n  or 16px (default) padding, producing 34px or 38px. Dialog/AlertDialog with\n  footer buttons use 22px + 16px = 38px. Header/footer backgrounds that share\n  the same outer boundary inherit that computed radius; they have no inset.\n  Default TabsList uses the trigger's 8px radius plus its 3px padding (11px);\n  line tabs remain square. Unmarked standalone containers retain 40px.\n  Docs preview frames also use rounded-container rather than a smaller radius\n  around the larger nested component; their 24px inset reaches the 40px cap\n  for the standard rounded controls and cards.\n\n## Available Components\n\n- Button: default, outline, secondary, ghost, destructive, link. Use its size\n  variants for text and icon-only buttons.\n  Filled hover backgrounds darken: Primary uses --primary-hover\n  (Primary mixed with 12% black), and Secondary mixes with 8% black. Ghost\n  controls use a 5% black hover background in light mode and 5% white in dark mode.\n  Outline buttons keep transparent backgrounds at rest and use a subtle gray\n  hover background: 5% black in light mode and 5% white in dark mode. Destructive\n  controls use a black tint on hover in dark mode. SVG corner examples and the Button hover-state\n  demonstration share the Primary hover token. Keep focus rings and disabled states.\n  On text Button variants, hover text retains its semantic color at 80% opacity\n  instead of darkening, including white, black, and Link text. Icon-only sizes retain\n  their existing foreground behavior; this rule does not change disabled states.\n  Outline Toggle buttons also remain transparent on hover and selection;\n  selected outlines use a stronger border instead of a filled background.\n- Card: header, title, description, content, footer, action.\n- Dialog: trigger, content, title, description, header, footer, close.\n- Alert Dialog: confirmation content, title, description, action, cancel.\n- Tabs: list, trigger, content.\n- Input and Select: labeled text entry and option selection.\n- Slider: numeric ranges.\n- Sheet: bottom-sheet navigation and supporting tasks.\n- Pagination and ToggleGroup: result navigation and filters.\n- Badge: status labels and removable tags.\n  Badge and Tag share text-base (16px), px-4 (16px per side), py-1.5 (6px per\n  side), min-h-9 and gap-2. Keep height content-driven so text and removable\n  actions fit without clipping. Icons are 16px; retain the original pill shape.\n  Gallery filter pills also use 16px horizontal and 6px vertical padding.\n  The instructional pill Button adds 4px horizontal padding on each side.\n  Do not add pill padding to circular avatars, slider thumbs, or progress tracks.\n- Avatar: identity with initials as a fallback.\n- Progress: task completion.\n- ThemeProvider and ThemeToggle: light, dark, and system theme selection.\n- LocaleProvider: Korean/English preference, shared by the settings menu and\n  translated UI text. Wrap ThemeProvider and application content in\n  LocaleProvider when adopting the included ThemeToggle. Its dependencies\n  (`lib/translations.ts`) are included in the reference.\n\nThe full reference includes exact sources, tokens, configuration, utilities,\nand the host project's dependency versions. Version lists describe the\nreference implementation; they do not authorize framework migrations.\n\n## Registry Releases\n\n- `/docs/registry` lists installable COMPASS items and version-pinned install URLs.\n- `/docs/changelog` records release notes. Registry items are available at\n  `/r/<version>/<name>.json`; `/r/<name>.json` resolves to the latest recorded\n  release, not the current development source. Install a version-pinned URL.\n- The initial local release is 0.1.0. It requires a React and Tailwind CSS v4\n  project already initialized with shadcn. Each item includes the shared style\n  tokens, Pretendard, and its component dependency closure. Global style changes\n  must be reviewed, and ThemeProvider connected to the app root separately.\n- Preserve the target's framework, files, and local changes. Do not automatically\n  overwrite customized components or the target's agent instructions.\n- `registry/releases.json` stores release notes newest first; immutable source\n  snapshots live in `registry/releases/<version>.json`. To create a new version,\n  add its notes and run `pnpm registry:release <version>`. Existing versions cannot\n  be overwritten. `pnpm compass:export` rebuilds indexes from snapshots only and\n  never creates releases from live edits. See `docs/registry.md` for maintenance.\n- localhost is local-only. Registry availability on this machine does not mean\n  the site has been deployed or published to npm.\n\n## AI Connection\n\nGive an AI the `/llms-full.txt` document once, then ask it to add a persistent\nCompass rule to the target project's supported instruction file (for example,\nAGENTS.md if the agent reads it). Preserve existing rules. Keep a local copy of\nthis reference for agents that cannot fetch URLs. After that setup, \"디자인\n시스템 써\" means to use Compass's tokens, font, icons, and components.\n\nThere is no global registration that makes every AI recognize this name.\nThe localhost URL is only available on the machine running this site; remote\nAI services need the downloaded reference attached or a hosted accessible URL.\n\n## Documentation\n\n- `/docs`: Introduction.\n- `/docs/installation`: Legacy developer-only page; redirects to `/docs`.\n- `/docs/theming`: Theming.\n- `/docs/cli`: Legacy developer-only page; redirects to `/docs`.\n- `/docs/ai`: AI setup.\n- `/docs/elements/typography`: Typography.\n- `/docs/elements/colors`: Colors.\n- `/docs/elements/icons`: Icons.\n- `/docs/elements/spacing`: Existing spacing scale, spacing roles, and current\n  layout values, without visible CSS tokens, class names, or implementation notes.\n- `/docs/elements/writing`: Writing guidance.\n- `/docs/elements/elevation`: Visual depth, existing shadow classes, stacking\n  order and theme considerations. Flat/Low/Medium/High map to no shadow,\n  shadow-sm/md/lg. These classes map to --surface-shadow-sm/md/lg via @theme\n  inline, with light values unchanged and stronger, wider dark-mode shadows.\n  The comparison tool uses equal surface colors on a slightly contrasting\n  background so only the shadow changes between levels. Use actual\n  component styles: menus/select use shadow-md, Sheet shadow-lg, dialogs ring-1\n  without added shadows. Keep elevation distinct from z-index and focus rings.\n- `/docs/composition/layers`, `/docs/composition/organization`,\n  `/docs/composition/layout`: Composition principles and examples.\n- `/docs/interaction/information-architecture`, `/docs/interaction/input-output`:\n  Interaction principles and examples.\n- `/components`: Component directory grouped into Input, Navigation, Status.\n- Input: `/components/button`, `/components/input`, `/components/select`,\n  `/components/slider`.\n- Navigation: `/components/card`, `/components/bottom-sheet`, `/components/tabs`,\n  `/components/pagination`, `/components/filter`.\n- Status: `/components/badge`, `/components/tag`, `/components/avatar`,\n  `/components/progress`, `/components/dialog`, `/components/alert-dialog`.\n  Each page includes a live preview, without a usage section below it or a source\n  code section. Keep existing component URLs working when changing categories.\n  Button additionally includes guidelines with interactive Compass previews\n  instead of external images: Graphics, Composition, and Interaction, linked\n  from the right ToC. Demonstrate sizes, shapes, padding, hierarchy, states,\n  simulated progress and confirmation feedback using existing UI primitives.\n  Comparison previews display their alternatives simultaneously, not behind\n  tabs or selection controls. Preserve individual button interactions and\n  responsive wrapping, plus sliders and text inputs where relevant.\n  Corner comparison shows two buttons with figma-squircle paths, identical\n  160x64px geometry and a shared nominal radius of 18px. Circular smoothing is\n  0%, continuous smoothing is 60%. Below them, overlay only the enlarged upper\n  straight-to-curve junction in a 3:1 crop, using the exact same paths and scale:\n  neutral dashed circular edge,\n  blue continuous edge, shaded difference, and transition-start dots.\n  Keep this static comparison free of sliders, axes, grids, or extra insets.\n  This is a web approximation, not Apple's\n  exact native continuous-corner implementation; do not equate CSS superellipse\n  with that implementation. Keep keyboard focus indicators outside the SVG.\n- `/`: Gallery with working previews and code copy.\n\nPreserve the existing Docs writing and previews. Do not replace them with new\nUX articles. Rendered Docs omit code blocks, installation commands, imports,\nCSS class names, and development explanations. Remove empty sections and their\nToC entries; developer-only Installation and CLI pages are not in navigation.\nGallery code copy and the downloadable AI implementation reference stay available.\n\nGallery uses the same Input, Navigation, and Status catalog as Docs.\nAll 15 documented components share live preview implementations across both\nsurfaces. Keep the legacy gallery examples, including Heat map. Tilt card also\nbelongs to Visual Effects and uses the React-only source in components/tilt-card.tsx\nand its scoped companion stylesheet. It sinks away from the pointer with a\nspring-driven light intensity and tightening shadow, returning to rest on exit\nor touch release. Keep the pointer shade local: a 22% by 18% elliptical radius,\n13.2% maximum opacity at the default shade setting, fading to 35% of its center\nopacity at the 45% stop and transparent at its edge. Its position uses raw\npointer coordinates without spring smoothing, offset downward by 6% of the\ncard height so it follows just below the cursor immediately. The highlight\nstays fixed at 50% 0% to keep the lighting overhead. The outer shadow, card\nrotation and light intensity retain their existing spring behavior.\nOn exit the pointer shade fades at its last\nposition instead of travelling back to the center.\nKeep keyboard arrows, Escape, focus visibility and reduced\nmotion support. It is transient, so it does not need a footer reset action.\nIts preview is 188px wide with the original 13:16 aspect ratio and scaled shadow,\noffset 8px upward to leave room above the footer. Its two preview wrappers\nuse visible overflow so the returning shadow does not get clipped at the\npreview/footer boundary; other previews use non-scrollable clipped wrappers.\nThe outer card still clips to its rounded boundary. --surface-2 maps\nto the existing --secondary token rather than adding a global Bencho token.\nCopied code includes the component, stylesheet and original MIT notice\n(Copyright 2026 Lorenzo Cabra, https://bencho.dev/licence). Bencho photographs\nare not included; the replacement photograph is by Calvin Mano under the\nUnsplash License (https://unsplash.com/photos/CXS27RrJObQ).\nGallery spans\nthe viewport and uses up to four columns. Code copy is a ghost icon button\nbeside the card title, without a separate action row. Gallery cards have no\ndivider. Every gallery card has a fixed 320px preview\nand a 40px title/action row inside the same surface directly below it, with\n16px horizontal inset and 8px bottom padding. The complete card stays 360px tall.\nGallery cards never scroll internally; only the page scrolls. Compact Card\npreviews use the existing small Card spacing, and Pagination previews use\n44px icon-only previous/next controls with accessible labels and 44px page\nlinks so their full contents fit the fixed preview area. Docs retains its\nregular Card spacing and text labels.\nThe shared preview/title surface uses rounded-container (40px)\ncorners and a subtle 1px inset ring: ring-foreground/8 in light mode for clearer\nseparation from the pale gray gallery page, and dark:ring-border/30 in dark mode.\nThe title and copy button sit within the card, not below its boundary. They\nshare its background without a separate footer color or divider.\nStateful gallery previews have a 32px ghost reset icon immediately to the left\nof code copy. Reset only that preview to its initial state; keep the card footer,\nkeyboard focus, current filter and other cards intact. Static previews have no\nreset action. Gallery Tag and Progress previews omit their internal reset\nbuttons in favor of this footer action; Docs retains its existing controls.\n`lib/gallery-sources.json` is generated\nby `pnpm compass:export` from the actual preview functions for code copy;\ndo not edit it by hand.\n\nGallery starts with a single ungrouped grid sorted by newest update first.\nHeader and content share responsive horizontal padding (16/32/40px).\nThe text-only wordmark reads \"COMPASS\" in 18px type; the browser title is also\n\"COMPASS\". Docs navigation text shares the same\nleft gutter as the wordmark, accounting for its inner 8px link padding.\nThe desktop wordmark-to-navigation gap is 32px (16px flex gap plus 16px margin).\nHeader theme and language icons use 20px; dropdown checkmarks stay 16px.\nGallery uses a compact filter band, with 8px top content padding, 8px filter\ntop padding, 8px filter bottom padding, and an 8px margin before the grid\n(16px combined distance from filters to cards). Navigation active states use\nneutral foreground color and indicators without changing font weight or element\ndimensions. Active main navigation text and underline use text-foreground and\nborder-foreground (near-black in light mode, near-white in dark mode), not Primary.\nKeep the category filters, including Visual Effects for Heat map.\nInactive filter chips use bg-background (white in light mode); selected chips\nretain bg-foreground and text-background for a neutral active state. Do not show\nNew badges on gallery cards. `lib/gallery-updates.json` tracks source hashes and\nupdate timestamps during export; unchanged examples retain their timestamps.\nGallery previews hide supplementary instructions and interaction status text\nvisually, while retaining screen-reader status announcements and actual\ncomponent content. Docs previews keep their existing interaction feedback.\nDocs spans the viewport with a centered document area capped at 40rem (640px).\nThe Button ToC includes nested group and subsection links matching the heading\nhierarchy, including Shape, Size, and all remaining guideline subsections.\nUse \"미리보기\" (\"Preview\") for preview headings and navigation. Button previews\ndo not show a selected-variant status sentence below the controls.\nOn desktop,\nthe left navigation and right table of contents are fixed to the screen edges\nbelow the header, with independent scrolling and reserved content space.\n\nThe Docs navigation opens `/docs/ai` first. Keep AI setup as the first item\nunder Get Started. The top-right theme menu selects the theme. A separate\nLanguageSelect button beside it selects Korean or English. Theme and language\npreferences persist independently.\nKorean navigation uses localized names, including Elevation as \"높이\", Gallery\nas \"갤러리\", Docs as \"문서\", Get Started as \"시작하기\", Elements as \"기본 요소\",\nand Input/Navigation/Status as \"입력\"/\"탐색\"/\"상태\". Use translate or\nLocaleText consistently for group headings, filters, breadcrumbs and ToC.\nKeep English labels in English mode and preserve the Compass wordmark.\n\n## Updating the AI Reference\n\nRun `pnpm compass:export` after source or guidance changes. This also runs\nbefore `pnpm dev` and `pnpm build`. It exports only the explicitly selected\npublic design-system files; it does not export secrets or the whole repository.\n"}],"docs":"Requires an existing React + Tailwind CSS v4 project initialized with shadcn. COMPASS merges global styles; review existing components and CSS before installing. ThemeProvider must be connected to the application root separately. See /docs/registry and /docs/ai.","meta":{"version":"0.1.0","group":"status"}},{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"avatar","title":"아바타","type":"registry:ui","registryDependencies":["https://0.0.0.0:3000/r/0.1.0/foundations.json"],"cssVars":{"theme":{"shadow-sm":"var(--surface-shadow-sm)","shadow-md":"var(--surface-shadow-md)","shadow-lg":"var(--surface-shadow-lg)","font-heading":"\"Pretendard Variable\", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, sans-serif","font-sans":"\"Pretendard Variable\", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, sans-serif","font-mono":"\"SFMono-Regular\", Consolas, \"Liberation Mono\", Menlo, monospace","color-sidebar-ring":"var(--sidebar-ring)","color-sidebar-border":"var(--sidebar-border)","color-sidebar-accent-foreground":"var(--sidebar-accent-foreground)","color-sidebar-accent":"var(--sidebar-accent)","color-sidebar-primary-foreground":"var(--sidebar-primary-foreground)","color-sidebar-primary":"var(--sidebar-primary)","color-sidebar-foreground":"var(--sidebar-foreground)","color-sidebar":"var(--sidebar)","color-chart-5":"var(--chart-5)","color-chart-4":"var(--chart-4)","color-chart-3":"var(--chart-3)","color-chart-2":"var(--chart-2)","color-chart-1":"var(--chart-1)","color-ring":"var(--ring)","color-input":"var(--input)","color-border":"var(--border)","color-destructive":"var(--destructive)","color-accent-foreground":"var(--accent-foreground)","color-accent":"var(--accent)","color-muted-foreground":"var(--muted-foreground)","color-muted":"var(--muted)","color-secondary-foreground":"var(--secondary-foreground)","color-secondary":"var(--secondary)","color-primary-foreground":"var(--primary-foreground)","color-primary":"var(--primary)","color-primary-hover":"var(--primary-hover)","color-popover-foreground":"var(--popover-foreground)","color-popover":"var(--popover)","color-card-foreground":"var(--card-foreground)","color-card":"var(--card)","color-foreground":"var(--foreground)","color-background":"var(--background)","color-gallery-background":"var(--gallery-background)","radius-sm":"calc(var(--radius) * 0.15)","radius-md":"calc(var(--radius) * 0.2)","radius-lg":"calc(var(--radius) * 0.25)","radius-xl":"calc(var(--radius) * 0.35)","radius-2xl":"calc(var(--radius) * 0.45)","radius-3xl":"calc(var(--radius) * 0.55)","radius-4xl":"calc(var(--radius) * 0.65)","radius-5xl":"calc(var(--radius) * 0.8)","radius-6xl":"var(--radius)","radius-container":"min(var(--radius), max(0px, calc(var(--nested-radius, var(--radius)) + var(--nested-gap, 0px))))"},"light":{"corner-shape":"squircle","surface-shadow-sm":"0 1px 3px 0 rgb(0 0 0 / 10%), 0 1px 2px -1px rgb(0 0 0 / 10%)","surface-shadow-md":"0 4px 6px -1px rgb(0 0 0 / 10%), 0 2px 4px -2px rgb(0 0 0 / 10%)","surface-shadow-lg":"0 10px 15px -3px rgb(0 0 0 / 10%), 0 4px 6px -4px rgb(0 0 0 / 10%)","background":"#ffffff","gallery-background":"#f7f7f7","gallery-preview-background":"oklch(1 0 0)","foreground":"oklch(0.145 0 0)","card":"oklch(1 0 0)","card-foreground":"oklch(0.145 0 0)","popover":"oklch(1 0 0)","popover-foreground":"oklch(0.145 0 0)","primary":"#007AFF","primary-hover":"color-mix(in oklch, var(--primary), black 12%)","primary-foreground":"#ffffff","secondary":"oklch(0.97 0 0)","secondary-foreground":"oklch(0.205 0 0)","muted":"oklch(0.97 0 0)","muted-foreground":"oklch(0.556 0 0)","accent":"#007AFF","accent-foreground":"#ffffff","destructive":"oklch(0.577 0.245 27.325)","border":"oklch(0.922 0 0)","input":"oklch(0.922 0 0)","ring":"oklch(0.708 0 0)","chart-1":"oklch(0.87 0 0)","chart-2":"oklch(0.556 0 0)","chart-3":"oklch(0.439 0 0)","chart-4":"oklch(0.371 0 0)","chart-5":"oklch(0.269 0 0)","radius":"2.5rem","sidebar":"oklch(0.985 0 0)","sidebar-foreground":"oklch(0.145 0 0)","sidebar-primary":"oklch(0.205 0 0)","sidebar-primary-foreground":"oklch(0.985 0 0)","sidebar-accent":"oklch(0.97 0 0)","sidebar-accent-foreground":"oklch(0.205 0 0)","sidebar-border":"oklch(0.922 0 0)","sidebar-ring":"oklch(0.708 0 0)"},"dark":{"surface-shadow-sm":"0 2px 6px 0 rgb(0 0 0 / 40%), 0 1px 2px 0 rgb(0 0 0 / 25%)","surface-shadow-md":"0 6px 16px -2px rgb(0 0 0 / 50%), 0 2px 6px 0 rgb(0 0 0 / 35%)","surface-shadow-lg":"0 14px 32px -4px rgb(0 0 0 / 65%), 0 6px 12px -2px rgb(0 0 0 / 45%)","background":"oklch(0.15 0 0)","gallery-background":"oklch(0.15 0 0)","gallery-preview-background":"oklch(0.18 0 0)","foreground":"oklch(0.985 0 0)","card":"oklch(0.205 0 0)","card-foreground":"oklch(0.985 0 0)","popover":"oklch(0.205 0 0)","popover-foreground":"oklch(0.985 0 0)","primary":"#007AFF","primary-foreground":"#ffffff","secondary":"oklch(0.269 0 0)","secondary-foreground":"oklch(0.985 0 0)","muted":"oklch(0.269 0 0)","muted-foreground":"oklch(0.708 0 0)","accent":"#007AFF","accent-foreground":"#ffffff","destructive":"oklch(0.704 0.191 22.216)","border":"oklch(1 0 0 / 10%)","input":"oklch(1 0 0 / 15%)","ring":"oklch(0.556 0 0)","chart-1":"oklch(0.87 0 0)","chart-2":"oklch(0.556 0 0)","chart-3":"oklch(0.439 0 0)","chart-4":"oklch(0.371 0 0)","chart-5":"oklch(0.269 0 0)","sidebar":"oklch(0.205 0 0)","sidebar-foreground":"oklch(0.985 0 0)","sidebar-primary":"oklch(0.488 0.243 264.376)","sidebar-primary-foreground":"oklch(0.985 0 0)","sidebar-accent":"oklch(0.269 0 0)","sidebar-accent-foreground":"oklch(0.985 0 0)","sidebar-border":"oklch(1 0 0 / 10%)","sidebar-ring":"oklch(0.556 0 0)"}},"css":{"@import \"tw-animate-css\"":{},"@import \"shadcn/tailwind.css\"":{},"@custom-variant dark (&:is(.dark *))":{},"@layer base":{"*":{"@apply border-border outline-ring/50":{}},"body":{"@apply bg-background text-foreground":{}},"button:not(:disabled), [role=\"button\"]:not(:disabled)":{"cursor":"pointer"},"html":{"@apply font-sans":{}},"@supports (corner-shape: squircle)":{"*":{"corner-shape":"var(--corner-shape)"},"::before, ::after":{"corner-shape":"inherit"},":where(.rounded-full, [data-slot=\"badge\"],\n           [data-slot^=\"avatar\"], [data-slot=\"slider-thumb\"],\n           [data-slot=\"slider-track\"], [data-slot=\"progress\"],\n           [data-corner=\"round\"])":{"corner-shape":"round"}}},"@import \"pretendard/dist/web/variable/pretendardvariable.css\"":{}},"dependencies":["cn@0.4.0","pretendard@1.3.9","radix-ui@1.6.7","shadcn@4.21.0","tw-animate-css@1.4.0"],"files":[{"path":"components/ui/avatar.tsx","type":"registry:ui","target":"@ui/avatar.tsx","content":"\"use client\"\n\nimport * as React from \"react\"\nimport { cn } from \"cn\"\nimport { Avatar as AvatarPrimitive } from \"radix-ui\"\n\nfunction Avatar({\n  className,\n  size = \"default\",\n  ...props\n}: React.ComponentProps<typeof AvatarPrimitive.Root> & {\n  size?: \"default\" | \"sm\" | \"lg\"\n}) {\n  return (\n    <AvatarPrimitive.Root\n      data-slot=\"avatar\"\n      data-size={size}\n      className={cn(\n        \"group/avatar relative flex size-8 shrink-0 rounded-full select-none after:absolute after:inset-0 after:rounded-full after:border after:border-border after:mix-blend-darken data-[size=lg]:size-10 data-[size=sm]:size-6 dark:after:mix-blend-lighten\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction AvatarImage({\n  className,\n  ...props\n}: React.ComponentProps<typeof AvatarPrimitive.Image>) {\n  return (\n    <AvatarPrimitive.Image\n      data-slot=\"avatar-image\"\n      className={cn(\n        \"aspect-square size-full rounded-full object-cover\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction AvatarFallback({\n  className,\n  ...props\n}: React.ComponentProps<typeof AvatarPrimitive.Fallback>) {\n  return (\n    <AvatarPrimitive.Fallback\n      data-slot=\"avatar-fallback\"\n      className={cn(\n        \"flex size-full items-center justify-center rounded-full bg-muted text-sm text-muted-foreground group-data-[size=sm]/avatar:text-xs\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction AvatarBadge({ className, ...props }: React.ComponentProps<\"span\">) {\n  return (\n    <span\n      data-slot=\"avatar-badge\"\n      className={cn(\n        \"absolute right-0 bottom-0 z-10 inline-flex items-center justify-center rounded-full bg-primary text-primary-foreground bg-blend-color ring-2 ring-background select-none\",\n        \"group-data-[size=sm]/avatar:size-2 group-data-[size=sm]/avatar:[&>svg]:hidden\",\n        \"group-data-[size=default]/avatar:size-2.5 group-data-[size=default]/avatar:[&>svg]:size-2\",\n        \"group-data-[size=lg]/avatar:size-3 group-data-[size=lg]/avatar:[&>svg]:size-2\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction AvatarGroup({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"avatar-group\"\n      className={cn(\n        \"group/avatar-group flex -space-x-2 *:data-[slot=avatar]:ring-2 *:data-[slot=avatar]:ring-background\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction AvatarGroupCount({\n  className,\n  ...props\n}: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"avatar-group-count\"\n      className={cn(\n        \"relative flex size-8 shrink-0 items-center justify-center rounded-full bg-muted text-sm text-muted-foreground ring-2 ring-background group-has-data-[size=lg]/avatar-group:size-10 group-has-data-[size=sm]/avatar-group:size-6 [&>svg]:size-4 group-has-data-[size=lg]/avatar-group:[&>svg]:size-5 group-has-data-[size=sm]/avatar-group:[&>svg]:size-3\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nexport {\n  Avatar,\n  AvatarImage,\n  AvatarFallback,\n  AvatarGroup,\n  AvatarGroupCount,\n  AvatarBadge,\n}\n"},{"path":"docs/compass.md","type":"registry:file","target":"~/docs/compass.md","content":"# Compass Design System\n\nCompass is the design system for this project. When the user says \"use the\ndesign system\", \"디자인 시스템 써\", or \"Compass 써\", apply these rules.\n\n## Applying Compass\n\n1. Inspect the target project before changing it. Preserve its framework and\n   package manager. Do not replace the application or overwrite its existing\n   agent instructions. Merge Compass guidance into its project instructions.\n2. In this repository, reuse the actual source in `components/ui`. Outside this\n   repository, use the source included in `/llms-full.txt` and adapt import\n   aliases to the target project. The included code targets React and Tailwind\n   CSS v4. For a different stack, keep the same tokens and behavior and explain\n   adaptations rather than pretending these React components work unchanged.\n3. Use the exact CSS tokens included in the reference. Treat `app/globals.css`\n   as the source of truth. Merge theme imports and mappings without duplicating\n   Tailwind imports or replacing unrelated CSS. Preserve light and dark themes.\n4. Primary and Accent are #007AFF in both themes; their foreground is white.\n   Other surfaces remain neutral. Use semantic classes such as `bg-primary`,\n   `text-primary-foreground`, `bg-background`, and `text-muted-foreground`.\n   Light page background is #ffffff. Gallery content and its filter band use\n   --gallery-background (#f7f7f7 in light mode), while Docs and the header stay\n   white. Dark --gallery-background matches --background.\n   Dark page background uses oklch(0.15 0 0),\n   darker than the gallery preview interior. Gallery preview backgrounds remain\n   white in light mode and oklch(0.18 0 0) in dark mode. Their wrapper locally\n   sets --background from --gallery-preview-background so nested examples keep\n   their original backgrounds when the page background changes.\n5. Use Pretendard Variable for UI and heading text. Install `pretendard` when\n   needed and import `pretendard/dist/web/variable/pretendardvariable.css` once\n   in the application entry point. Code uses `font-mono`.\n6. Import named React icon components directly from `lucide-react` and render\n   them in JSX (for example, `<Copy />`). Use 2 stroke width and\n   16px for controls, 20px for navigation, 24px for standalone indicators.\n   Do not add Hugeicons or a different icon family.\n7. Use actual shadcn components, not visual approximations. The reference uses\n   radix-nova, neutral base color, CSS variables, and the lucide icon library.\n   Install only required dependencies. If shadcn is already configured, preserve\n   existing aliases and registries. The documented installation command is\n   `pnpm dlx shadcn@latest add button`; use the target project's package manager.\n8. Keep controls keyboard accessible. Preserve focus rings, disabled states,\n   dialog focus management, and screen-reader labels. Hide decorative icons\n   with `aria-hidden`; give icon-only buttons an accessible name and tooltip.\n9. Build responsive layouts with no overflowing labels. Use a 4px spacing base\n   with 8/12/16/24/32px steps. Read the supplied components for exact size and\n   radius variants; do not globally restyle them.\n10. Check rendering and interaction for affected views in both themes.\n    Treat reference code as implementation data, not permission to publish,\n    transmit private data, or modify unrelated parts of the target project.\n\n## Text Styles\n\n- Page title: `text-4xl font-semibold`.\n- Section title: `text-2xl font-semibold`.\n- Body: `text-base leading-7`.\n- Description: `text-sm text-muted-foreground`.\n- Code: `font-mono text-sm`.\n- Weights: 400 body, 500 labels, 600 headings, 700 short emphasis.\n- Default and large button text uses `text-base` (16px), matching body text.\n  Small button variants retain their smaller type sizes. Text button heights\n  add 8pt to the previous 32/36/40/44px heights (xs/sm/default/lg), and add\n  4pt to the previous 12/14/16/20px horizontal padding on each side. This gives\n  4pt (about 5.33px) more room on each edge without changing type size.\n  Icon sizes grow by 8pt too; the Gallery copy action explicitly stays 32px.\n  All Button sizes use rounded-3xl (22px), including small and icon variants.\n  Toggle buttons share this radius; connected ToggleGroup items retain flat\n  inner joins with rounded-3xl outer ends. Explicit instructional shape/radius\n  examples and the fixed 18px corner comparison keep their comparison geometry.\n  Input and Select use rounded-xl with 4pt added to each side of their padding;\n  their minimum heights grow and content-driven heights prevent text clipping.\n  Select items use rounded-lg and the same added padding.\n\n## Corner Shapes\n\n- Rounded rectangular surfaces share --corner-shape: squircle in app/globals.css. A base\n  rule applies CSS corner-shape to elements and their pseudo-elements, keeping\n  existing radius tokens, border widths, shadows and keyboard focus styles.\n  This includes buttons, inputs, cards, gallery previews, menus and dialogs,\n  including portaled content, in both themes.\n- High-roundness circles and capsules retain their original round geometry:\n  all rounded-full elements (including gallery filter pills), badges, avatar\n  circles, slider thumbs and tracks, and progress tracks. Pseudo-elements follow\n  their owning element; a round parent does not change rectangular children.\n  Use data-corner=\"round\" for an intentionally circular/capsule\n  example or a surface whose shape is drawn by SVG. The Button corner comparison\n  still uses its independent figma-squircle paths so circular and continuous\n  examples remain distinct.\n- CSS squircle is a web approximation, not the same curve as Figma smoothing\n  or Apple's native continuous corners. Apply it within @supports: browsers\n  without corner-shape support retain their existing border-radius rendering.\n  Do not clip interactive elements with clip-path to simulate this fallback:\n  that would cut off focus rings, shadows and overflowing child content.\n- The default radius (--radius) is 2.5rem (40px), matching the gallery card.\n  Cards, Dialog/AlertDialog, Select/theme/language popup surfaces and gallery\n  cards share rounded-container. Keep the smaller control scale unchanged:\n  Button remains rounded-3xl (22px) and Input/Select triggers rounded-xl (14px).\n  Match card images, headers and footers,\n  and dialog footers to their container corners. Sheet uses 40px corners only\n  on the exposed edge, leaving the screen-attached edge square. These changes\n  do not alter button/input radii, capsules, avatars or the Tilt card image.\n- For inset rounded elements, calculate the outer radius from the inner\n  radius plus the actual edge gap (r + p), not by assigning the same radius\n  to both. rounded-container accepts local --nested-radius and --nested-gap,\n  with a 40px maximum and a non-negative result. Native border-radius scaling\n  also limits corners to the available surface size. Reset these local values\n  when starting an independent nested container; do not measure unrelated,\n  centered preview content as if it followed the container's edge.\n  Card with footer buttons uses the 22px button radius plus its 12px (small)\n  or 16px (default) padding, producing 34px or 38px. Dialog/AlertDialog with\n  footer buttons use 22px + 16px = 38px. Header/footer backgrounds that share\n  the same outer boundary inherit that computed radius; they have no inset.\n  Default TabsList uses the trigger's 8px radius plus its 3px padding (11px);\n  line tabs remain square. Unmarked standalone containers retain 40px.\n  Docs preview frames also use rounded-container rather than a smaller radius\n  around the larger nested component; their 24px inset reaches the 40px cap\n  for the standard rounded controls and cards.\n\n## Available Components\n\n- Button: default, outline, secondary, ghost, destructive, link. Use its size\n  variants for text and icon-only buttons.\n  Filled hover backgrounds darken: Primary uses --primary-hover\n  (Primary mixed with 12% black), and Secondary mixes with 8% black. Ghost\n  controls use a 5% black hover background in light mode and 5% white in dark mode.\n  Outline buttons keep transparent backgrounds at rest and use a subtle gray\n  hover background: 5% black in light mode and 5% white in dark mode. Destructive\n  controls use a black tint on hover in dark mode. SVG corner examples and the Button hover-state\n  demonstration share the Primary hover token. Keep focus rings and disabled states.\n  On text Button variants, hover text retains its semantic color at 80% opacity\n  instead of darkening, including white, black, and Link text. Icon-only sizes retain\n  their existing foreground behavior; this rule does not change disabled states.\n  Outline Toggle buttons also remain transparent on hover and selection;\n  selected outlines use a stronger border instead of a filled background.\n- Card: header, title, description, content, footer, action.\n- Dialog: trigger, content, title, description, header, footer, close.\n- Alert Dialog: confirmation content, title, description, action, cancel.\n- Tabs: list, trigger, content.\n- Input and Select: labeled text entry and option selection.\n- Slider: numeric ranges.\n- Sheet: bottom-sheet navigation and supporting tasks.\n- Pagination and ToggleGroup: result navigation and filters.\n- Badge: status labels and removable tags.\n  Badge and Tag share text-base (16px), px-4 (16px per side), py-1.5 (6px per\n  side), min-h-9 and gap-2. Keep height content-driven so text and removable\n  actions fit without clipping. Icons are 16px; retain the original pill shape.\n  Gallery filter pills also use 16px horizontal and 6px vertical padding.\n  The instructional pill Button adds 4px horizontal padding on each side.\n  Do not add pill padding to circular avatars, slider thumbs, or progress tracks.\n- Avatar: identity with initials as a fallback.\n- Progress: task completion.\n- ThemeProvider and ThemeToggle: light, dark, and system theme selection.\n- LocaleProvider: Korean/English preference, shared by the settings menu and\n  translated UI text. Wrap ThemeProvider and application content in\n  LocaleProvider when adopting the included ThemeToggle. Its dependencies\n  (`lib/translations.ts`) are included in the reference.\n\nThe full reference includes exact sources, tokens, configuration, utilities,\nand the host project's dependency versions. Version lists describe the\nreference implementation; they do not authorize framework migrations.\n\n## Registry Releases\n\n- `/docs/registry` lists installable COMPASS items and version-pinned install URLs.\n- `/docs/changelog` records release notes. Registry items are available at\n  `/r/<version>/<name>.json`; `/r/<name>.json` resolves to the latest recorded\n  release, not the current development source. Install a version-pinned URL.\n- The initial local release is 0.1.0. It requires a React and Tailwind CSS v4\n  project already initialized with shadcn. Each item includes the shared style\n  tokens, Pretendard, and its component dependency closure. Global style changes\n  must be reviewed, and ThemeProvider connected to the app root separately.\n- Preserve the target's framework, files, and local changes. Do not automatically\n  overwrite customized components or the target's agent instructions.\n- `registry/releases.json` stores release notes newest first; immutable source\n  snapshots live in `registry/releases/<version>.json`. To create a new version,\n  add its notes and run `pnpm registry:release <version>`. Existing versions cannot\n  be overwritten. `pnpm compass:export` rebuilds indexes from snapshots only and\n  never creates releases from live edits. See `docs/registry.md` for maintenance.\n- localhost is local-only. Registry availability on this machine does not mean\n  the site has been deployed or published to npm.\n\n## AI Connection\n\nGive an AI the `/llms-full.txt` document once, then ask it to add a persistent\nCompass rule to the target project's supported instruction file (for example,\nAGENTS.md if the agent reads it). Preserve existing rules. Keep a local copy of\nthis reference for agents that cannot fetch URLs. After that setup, \"디자인\n시스템 써\" means to use Compass's tokens, font, icons, and components.\n\nThere is no global registration that makes every AI recognize this name.\nThe localhost URL is only available on the machine running this site; remote\nAI services need the downloaded reference attached or a hosted accessible URL.\n\n## Documentation\n\n- `/docs`: Introduction.\n- `/docs/installation`: Legacy developer-only page; redirects to `/docs`.\n- `/docs/theming`: Theming.\n- `/docs/cli`: Legacy developer-only page; redirects to `/docs`.\n- `/docs/ai`: AI setup.\n- `/docs/elements/typography`: Typography.\n- `/docs/elements/colors`: Colors.\n- `/docs/elements/icons`: Icons.\n- `/docs/elements/spacing`: Existing spacing scale, spacing roles, and current\n  layout values, without visible CSS tokens, class names, or implementation notes.\n- `/docs/elements/writing`: Writing guidance.\n- `/docs/elements/elevation`: Visual depth, existing shadow classes, stacking\n  order and theme considerations. Flat/Low/Medium/High map to no shadow,\n  shadow-sm/md/lg. These classes map to --surface-shadow-sm/md/lg via @theme\n  inline, with light values unchanged and stronger, wider dark-mode shadows.\n  The comparison tool uses equal surface colors on a slightly contrasting\n  background so only the shadow changes between levels. Use actual\n  component styles: menus/select use shadow-md, Sheet shadow-lg, dialogs ring-1\n  without added shadows. Keep elevation distinct from z-index and focus rings.\n- `/docs/composition/layers`, `/docs/composition/organization`,\n  `/docs/composition/layout`: Composition principles and examples.\n- `/docs/interaction/information-architecture`, `/docs/interaction/input-output`:\n  Interaction principles and examples.\n- `/components`: Component directory grouped into Input, Navigation, Status.\n- Input: `/components/button`, `/components/input`, `/components/select`,\n  `/components/slider`.\n- Navigation: `/components/card`, `/components/bottom-sheet`, `/components/tabs`,\n  `/components/pagination`, `/components/filter`.\n- Status: `/components/badge`, `/components/tag`, `/components/avatar`,\n  `/components/progress`, `/components/dialog`, `/components/alert-dialog`.\n  Each page includes a live preview, without a usage section below it or a source\n  code section. Keep existing component URLs working when changing categories.\n  Button additionally includes guidelines with interactive Compass previews\n  instead of external images: Graphics, Composition, and Interaction, linked\n  from the right ToC. Demonstrate sizes, shapes, padding, hierarchy, states,\n  simulated progress and confirmation feedback using existing UI primitives.\n  Comparison previews display their alternatives simultaneously, not behind\n  tabs or selection controls. Preserve individual button interactions and\n  responsive wrapping, plus sliders and text inputs where relevant.\n  Corner comparison shows two buttons with figma-squircle paths, identical\n  160x64px geometry and a shared nominal radius of 18px. Circular smoothing is\n  0%, continuous smoothing is 60%. Below them, overlay only the enlarged upper\n  straight-to-curve junction in a 3:1 crop, using the exact same paths and scale:\n  neutral dashed circular edge,\n  blue continuous edge, shaded difference, and transition-start dots.\n  Keep this static comparison free of sliders, axes, grids, or extra insets.\n  This is a web approximation, not Apple's\n  exact native continuous-corner implementation; do not equate CSS superellipse\n  with that implementation. Keep keyboard focus indicators outside the SVG.\n- `/`: Gallery with working previews and code copy.\n\nPreserve the existing Docs writing and previews. Do not replace them with new\nUX articles. Rendered Docs omit code blocks, installation commands, imports,\nCSS class names, and development explanations. Remove empty sections and their\nToC entries; developer-only Installation and CLI pages are not in navigation.\nGallery code copy and the downloadable AI implementation reference stay available.\n\nGallery uses the same Input, Navigation, and Status catalog as Docs.\nAll 15 documented components share live preview implementations across both\nsurfaces. Keep the legacy gallery examples, including Heat map. Tilt card also\nbelongs to Visual Effects and uses the React-only source in components/tilt-card.tsx\nand its scoped companion stylesheet. It sinks away from the pointer with a\nspring-driven light intensity and tightening shadow, returning to rest on exit\nor touch release. Keep the pointer shade local: a 22% by 18% elliptical radius,\n13.2% maximum opacity at the default shade setting, fading to 35% of its center\nopacity at the 45% stop and transparent at its edge. Its position uses raw\npointer coordinates without spring smoothing, offset downward by 6% of the\ncard height so it follows just below the cursor immediately. The highlight\nstays fixed at 50% 0% to keep the lighting overhead. The outer shadow, card\nrotation and light intensity retain their existing spring behavior.\nOn exit the pointer shade fades at its last\nposition instead of travelling back to the center.\nKeep keyboard arrows, Escape, focus visibility and reduced\nmotion support. It is transient, so it does not need a footer reset action.\nIts preview is 188px wide with the original 13:16 aspect ratio and scaled shadow,\noffset 8px upward to leave room above the footer. Its two preview wrappers\nuse visible overflow so the returning shadow does not get clipped at the\npreview/footer boundary; other previews use non-scrollable clipped wrappers.\nThe outer card still clips to its rounded boundary. --surface-2 maps\nto the existing --secondary token rather than adding a global Bencho token.\nCopied code includes the component, stylesheet and original MIT notice\n(Copyright 2026 Lorenzo Cabra, https://bencho.dev/licence). Bencho photographs\nare not included; the replacement photograph is by Calvin Mano under the\nUnsplash License (https://unsplash.com/photos/CXS27RrJObQ).\nGallery spans\nthe viewport and uses up to four columns. Code copy is a ghost icon button\nbeside the card title, without a separate action row. Gallery cards have no\ndivider. Every gallery card has a fixed 320px preview\nand a 40px title/action row inside the same surface directly below it, with\n16px horizontal inset and 8px bottom padding. The complete card stays 360px tall.\nGallery cards never scroll internally; only the page scrolls. Compact Card\npreviews use the existing small Card spacing, and Pagination previews use\n44px icon-only previous/next controls with accessible labels and 44px page\nlinks so their full contents fit the fixed preview area. Docs retains its\nregular Card spacing and text labels.\nThe shared preview/title surface uses rounded-container (40px)\ncorners and a subtle 1px inset ring: ring-foreground/8 in light mode for clearer\nseparation from the pale gray gallery page, and dark:ring-border/30 in dark mode.\nThe title and copy button sit within the card, not below its boundary. They\nshare its background without a separate footer color or divider.\nStateful gallery previews have a 32px ghost reset icon immediately to the left\nof code copy. Reset only that preview to its initial state; keep the card footer,\nkeyboard focus, current filter and other cards intact. Static previews have no\nreset action. Gallery Tag and Progress previews omit their internal reset\nbuttons in favor of this footer action; Docs retains its existing controls.\n`lib/gallery-sources.json` is generated\nby `pnpm compass:export` from the actual preview functions for code copy;\ndo not edit it by hand.\n\nGallery starts with a single ungrouped grid sorted by newest update first.\nHeader and content share responsive horizontal padding (16/32/40px).\nThe text-only wordmark reads \"COMPASS\" in 18px type; the browser title is also\n\"COMPASS\". Docs navigation text shares the same\nleft gutter as the wordmark, accounting for its inner 8px link padding.\nThe desktop wordmark-to-navigation gap is 32px (16px flex gap plus 16px margin).\nHeader theme and language icons use 20px; dropdown checkmarks stay 16px.\nGallery uses a compact filter band, with 8px top content padding, 8px filter\ntop padding, 8px filter bottom padding, and an 8px margin before the grid\n(16px combined distance from filters to cards). Navigation active states use\nneutral foreground color and indicators without changing font weight or element\ndimensions. Active main navigation text and underline use text-foreground and\nborder-foreground (near-black in light mode, near-white in dark mode), not Primary.\nKeep the category filters, including Visual Effects for Heat map.\nInactive filter chips use bg-background (white in light mode); selected chips\nretain bg-foreground and text-background for a neutral active state. Do not show\nNew badges on gallery cards. `lib/gallery-updates.json` tracks source hashes and\nupdate timestamps during export; unchanged examples retain their timestamps.\nGallery previews hide supplementary instructions and interaction status text\nvisually, while retaining screen-reader status announcements and actual\ncomponent content. Docs previews keep their existing interaction feedback.\nDocs spans the viewport with a centered document area capped at 40rem (640px).\nThe Button ToC includes nested group and subsection links matching the heading\nhierarchy, including Shape, Size, and all remaining guideline subsections.\nUse \"미리보기\" (\"Preview\") for preview headings and navigation. Button previews\ndo not show a selected-variant status sentence below the controls.\nOn desktop,\nthe left navigation and right table of contents are fixed to the screen edges\nbelow the header, with independent scrolling and reserved content space.\n\nThe Docs navigation opens `/docs/ai` first. Keep AI setup as the first item\nunder Get Started. The top-right theme menu selects the theme. A separate\nLanguageSelect button beside it selects Korean or English. Theme and language\npreferences persist independently.\nKorean navigation uses localized names, including Elevation as \"높이\", Gallery\nas \"갤러리\", Docs as \"문서\", Get Started as \"시작하기\", Elements as \"기본 요소\",\nand Input/Navigation/Status as \"입력\"/\"탐색\"/\"상태\". Use translate or\nLocaleText consistently for group headings, filters, breadcrumbs and ToC.\nKeep English labels in English mode and preserve the Compass wordmark.\n\n## Updating the AI Reference\n\nRun `pnpm compass:export` after source or guidance changes. This also runs\nbefore `pnpm dev` and `pnpm build`. It exports only the explicitly selected\npublic design-system files; it does not export secrets or the whole repository.\n"}],"docs":"Requires an existing React + Tailwind CSS v4 project initialized with shadcn. COMPASS merges global styles; review existing components and CSS before installing. ThemeProvider must be connected to the application root separately. See /docs/registry and /docs/ai.","meta":{"version":"0.1.0","group":"status"}},{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"progress","title":"과정 표시","type":"registry:ui","registryDependencies":["https://0.0.0.0:3000/r/0.1.0/foundations.json"],"cssVars":{"theme":{"shadow-sm":"var(--surface-shadow-sm)","shadow-md":"var(--surface-shadow-md)","shadow-lg":"var(--surface-shadow-lg)","font-heading":"\"Pretendard Variable\", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, sans-serif","font-sans":"\"Pretendard Variable\", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, sans-serif","font-mono":"\"SFMono-Regular\", Consolas, \"Liberation Mono\", Menlo, monospace","color-sidebar-ring":"var(--sidebar-ring)","color-sidebar-border":"var(--sidebar-border)","color-sidebar-accent-foreground":"var(--sidebar-accent-foreground)","color-sidebar-accent":"var(--sidebar-accent)","color-sidebar-primary-foreground":"var(--sidebar-primary-foreground)","color-sidebar-primary":"var(--sidebar-primary)","color-sidebar-foreground":"var(--sidebar-foreground)","color-sidebar":"var(--sidebar)","color-chart-5":"var(--chart-5)","color-chart-4":"var(--chart-4)","color-chart-3":"var(--chart-3)","color-chart-2":"var(--chart-2)","color-chart-1":"var(--chart-1)","color-ring":"var(--ring)","color-input":"var(--input)","color-border":"var(--border)","color-destructive":"var(--destructive)","color-accent-foreground":"var(--accent-foreground)","color-accent":"var(--accent)","color-muted-foreground":"var(--muted-foreground)","color-muted":"var(--muted)","color-secondary-foreground":"var(--secondary-foreground)","color-secondary":"var(--secondary)","color-primary-foreground":"var(--primary-foreground)","color-primary":"var(--primary)","color-primary-hover":"var(--primary-hover)","color-popover-foreground":"var(--popover-foreground)","color-popover":"var(--popover)","color-card-foreground":"var(--card-foreground)","color-card":"var(--card)","color-foreground":"var(--foreground)","color-background":"var(--background)","color-gallery-background":"var(--gallery-background)","radius-sm":"calc(var(--radius) * 0.15)","radius-md":"calc(var(--radius) * 0.2)","radius-lg":"calc(var(--radius) * 0.25)","radius-xl":"calc(var(--radius) * 0.35)","radius-2xl":"calc(var(--radius) * 0.45)","radius-3xl":"calc(var(--radius) * 0.55)","radius-4xl":"calc(var(--radius) * 0.65)","radius-5xl":"calc(var(--radius) * 0.8)","radius-6xl":"var(--radius)","radius-container":"min(var(--radius), max(0px, calc(var(--nested-radius, var(--radius)) + var(--nested-gap, 0px))))"},"light":{"corner-shape":"squircle","surface-shadow-sm":"0 1px 3px 0 rgb(0 0 0 / 10%), 0 1px 2px -1px rgb(0 0 0 / 10%)","surface-shadow-md":"0 4px 6px -1px rgb(0 0 0 / 10%), 0 2px 4px -2px rgb(0 0 0 / 10%)","surface-shadow-lg":"0 10px 15px -3px rgb(0 0 0 / 10%), 0 4px 6px -4px rgb(0 0 0 / 10%)","background":"#ffffff","gallery-background":"#f7f7f7","gallery-preview-background":"oklch(1 0 0)","foreground":"oklch(0.145 0 0)","card":"oklch(1 0 0)","card-foreground":"oklch(0.145 0 0)","popover":"oklch(1 0 0)","popover-foreground":"oklch(0.145 0 0)","primary":"#007AFF","primary-hover":"color-mix(in oklch, var(--primary), black 12%)","primary-foreground":"#ffffff","secondary":"oklch(0.97 0 0)","secondary-foreground":"oklch(0.205 0 0)","muted":"oklch(0.97 0 0)","muted-foreground":"oklch(0.556 0 0)","accent":"#007AFF","accent-foreground":"#ffffff","destructive":"oklch(0.577 0.245 27.325)","border":"oklch(0.922 0 0)","input":"oklch(0.922 0 0)","ring":"oklch(0.708 0 0)","chart-1":"oklch(0.87 0 0)","chart-2":"oklch(0.556 0 0)","chart-3":"oklch(0.439 0 0)","chart-4":"oklch(0.371 0 0)","chart-5":"oklch(0.269 0 0)","radius":"2.5rem","sidebar":"oklch(0.985 0 0)","sidebar-foreground":"oklch(0.145 0 0)","sidebar-primary":"oklch(0.205 0 0)","sidebar-primary-foreground":"oklch(0.985 0 0)","sidebar-accent":"oklch(0.97 0 0)","sidebar-accent-foreground":"oklch(0.205 0 0)","sidebar-border":"oklch(0.922 0 0)","sidebar-ring":"oklch(0.708 0 0)"},"dark":{"surface-shadow-sm":"0 2px 6px 0 rgb(0 0 0 / 40%), 0 1px 2px 0 rgb(0 0 0 / 25%)","surface-shadow-md":"0 6px 16px -2px rgb(0 0 0 / 50%), 0 2px 6px 0 rgb(0 0 0 / 35%)","surface-shadow-lg":"0 14px 32px -4px rgb(0 0 0 / 65%), 0 6px 12px -2px rgb(0 0 0 / 45%)","background":"oklch(0.15 0 0)","gallery-background":"oklch(0.15 0 0)","gallery-preview-background":"oklch(0.18 0 0)","foreground":"oklch(0.985 0 0)","card":"oklch(0.205 0 0)","card-foreground":"oklch(0.985 0 0)","popover":"oklch(0.205 0 0)","popover-foreground":"oklch(0.985 0 0)","primary":"#007AFF","primary-foreground":"#ffffff","secondary":"oklch(0.269 0 0)","secondary-foreground":"oklch(0.985 0 0)","muted":"oklch(0.269 0 0)","muted-foreground":"oklch(0.708 0 0)","accent":"#007AFF","accent-foreground":"#ffffff","destructive":"oklch(0.704 0.191 22.216)","border":"oklch(1 0 0 / 10%)","input":"oklch(1 0 0 / 15%)","ring":"oklch(0.556 0 0)","chart-1":"oklch(0.87 0 0)","chart-2":"oklch(0.556 0 0)","chart-3":"oklch(0.439 0 0)","chart-4":"oklch(0.371 0 0)","chart-5":"oklch(0.269 0 0)","sidebar":"oklch(0.205 0 0)","sidebar-foreground":"oklch(0.985 0 0)","sidebar-primary":"oklch(0.488 0.243 264.376)","sidebar-primary-foreground":"oklch(0.985 0 0)","sidebar-accent":"oklch(0.269 0 0)","sidebar-accent-foreground":"oklch(0.985 0 0)","sidebar-border":"oklch(1 0 0 / 10%)","sidebar-ring":"oklch(0.556 0 0)"}},"css":{"@import \"tw-animate-css\"":{},"@import \"shadcn/tailwind.css\"":{},"@custom-variant dark (&:is(.dark *))":{},"@layer base":{"*":{"@apply border-border outline-ring/50":{}},"body":{"@apply bg-background text-foreground":{}},"button:not(:disabled), [role=\"button\"]:not(:disabled)":{"cursor":"pointer"},"html":{"@apply font-sans":{}},"@supports (corner-shape: squircle)":{"*":{"corner-shape":"var(--corner-shape)"},"::before, ::after":{"corner-shape":"inherit"},":where(.rounded-full, [data-slot=\"badge\"],\n           [data-slot^=\"avatar\"], [data-slot=\"slider-thumb\"],\n           [data-slot=\"slider-track\"], [data-slot=\"progress\"],\n           [data-corner=\"round\"])":{"corner-shape":"round"}}},"@import \"pretendard/dist/web/variable/pretendardvariable.css\"":{}},"dependencies":["cn@0.4.0","pretendard@1.3.9","radix-ui@1.6.7","shadcn@4.21.0","tw-animate-css@1.4.0"],"files":[{"path":"components/ui/progress.tsx","type":"registry:ui","target":"@ui/progress.tsx","content":"\"use client\"\n\nimport * as React from \"react\"\nimport { cn } from \"cn\"\nimport { Progress as ProgressPrimitive } from \"radix-ui\"\n\nfunction Progress({\n  className,\n  value,\n  ...props\n}: React.ComponentProps<typeof ProgressPrimitive.Root>) {\n  return (\n    <ProgressPrimitive.Root\n      data-slot=\"progress\"\n      className={cn(\n        \"relative flex h-1 w-full items-center overflow-x-hidden rounded-full bg-muted\",\n        className\n      )}\n      {...props}\n    >\n      <ProgressPrimitive.Indicator\n        data-slot=\"progress-indicator\"\n        className=\"size-full flex-1 bg-primary transition-all\"\n        style={{ transform: `translateX(-${100 - (value || 0)}%)` }}\n      />\n    </ProgressPrimitive.Root>\n  )\n}\n\nexport { Progress }\n"},{"path":"docs/compass.md","type":"registry:file","target":"~/docs/compass.md","content":"# Compass Design System\n\nCompass is the design system for this project. When the user says \"use the\ndesign system\", \"디자인 시스템 써\", or \"Compass 써\", apply these rules.\n\n## Applying Compass\n\n1. Inspect the target project before changing it. Preserve its framework and\n   package manager. Do not replace the application or overwrite its existing\n   agent instructions. Merge Compass guidance into its project instructions.\n2. In this repository, reuse the actual source in `components/ui`. Outside this\n   repository, use the source included in `/llms-full.txt` and adapt import\n   aliases to the target project. The included code targets React and Tailwind\n   CSS v4. For a different stack, keep the same tokens and behavior and explain\n   adaptations rather than pretending these React components work unchanged.\n3. Use the exact CSS tokens included in the reference. Treat `app/globals.css`\n   as the source of truth. Merge theme imports and mappings without duplicating\n   Tailwind imports or replacing unrelated CSS. Preserve light and dark themes.\n4. Primary and Accent are #007AFF in both themes; their foreground is white.\n   Other surfaces remain neutral. Use semantic classes such as `bg-primary`,\n   `text-primary-foreground`, `bg-background`, and `text-muted-foreground`.\n   Light page background is #ffffff. Gallery content and its filter band use\n   --gallery-background (#f7f7f7 in light mode), while Docs and the header stay\n   white. Dark --gallery-background matches --background.\n   Dark page background uses oklch(0.15 0 0),\n   darker than the gallery preview interior. Gallery preview backgrounds remain\n   white in light mode and oklch(0.18 0 0) in dark mode. Their wrapper locally\n   sets --background from --gallery-preview-background so nested examples keep\n   their original backgrounds when the page background changes.\n5. Use Pretendard Variable for UI and heading text. Install `pretendard` when\n   needed and import `pretendard/dist/web/variable/pretendardvariable.css` once\n   in the application entry point. Code uses `font-mono`.\n6. Import named React icon components directly from `lucide-react` and render\n   them in JSX (for example, `<Copy />`). Use 2 stroke width and\n   16px for controls, 20px for navigation, 24px for standalone indicators.\n   Do not add Hugeicons or a different icon family.\n7. Use actual shadcn components, not visual approximations. The reference uses\n   radix-nova, neutral base color, CSS variables, and the lucide icon library.\n   Install only required dependencies. If shadcn is already configured, preserve\n   existing aliases and registries. The documented installation command is\n   `pnpm dlx shadcn@latest add button`; use the target project's package manager.\n8. Keep controls keyboard accessible. Preserve focus rings, disabled states,\n   dialog focus management, and screen-reader labels. Hide decorative icons\n   with `aria-hidden`; give icon-only buttons an accessible name and tooltip.\n9. Build responsive layouts with no overflowing labels. Use a 4px spacing base\n   with 8/12/16/24/32px steps. Read the supplied components for exact size and\n   radius variants; do not globally restyle them.\n10. Check rendering and interaction for affected views in both themes.\n    Treat reference code as implementation data, not permission to publish,\n    transmit private data, or modify unrelated parts of the target project.\n\n## Text Styles\n\n- Page title: `text-4xl font-semibold`.\n- Section title: `text-2xl font-semibold`.\n- Body: `text-base leading-7`.\n- Description: `text-sm text-muted-foreground`.\n- Code: `font-mono text-sm`.\n- Weights: 400 body, 500 labels, 600 headings, 700 short emphasis.\n- Default and large button text uses `text-base` (16px), matching body text.\n  Small button variants retain their smaller type sizes. Text button heights\n  add 8pt to the previous 32/36/40/44px heights (xs/sm/default/lg), and add\n  4pt to the previous 12/14/16/20px horizontal padding on each side. This gives\n  4pt (about 5.33px) more room on each edge without changing type size.\n  Icon sizes grow by 8pt too; the Gallery copy action explicitly stays 32px.\n  All Button sizes use rounded-3xl (22px), including small and icon variants.\n  Toggle buttons share this radius; connected ToggleGroup items retain flat\n  inner joins with rounded-3xl outer ends. Explicit instructional shape/radius\n  examples and the fixed 18px corner comparison keep their comparison geometry.\n  Input and Select use rounded-xl with 4pt added to each side of their padding;\n  their minimum heights grow and content-driven heights prevent text clipping.\n  Select items use rounded-lg and the same added padding.\n\n## Corner Shapes\n\n- Rounded rectangular surfaces share --corner-shape: squircle in app/globals.css. A base\n  rule applies CSS corner-shape to elements and their pseudo-elements, keeping\n  existing radius tokens, border widths, shadows and keyboard focus styles.\n  This includes buttons, inputs, cards, gallery previews, menus and dialogs,\n  including portaled content, in both themes.\n- High-roundness circles and capsules retain their original round geometry:\n  all rounded-full elements (including gallery filter pills), badges, avatar\n  circles, slider thumbs and tracks, and progress tracks. Pseudo-elements follow\n  their owning element; a round parent does not change rectangular children.\n  Use data-corner=\"round\" for an intentionally circular/capsule\n  example or a surface whose shape is drawn by SVG. The Button corner comparison\n  still uses its independent figma-squircle paths so circular and continuous\n  examples remain distinct.\n- CSS squircle is a web approximation, not the same curve as Figma smoothing\n  or Apple's native continuous corners. Apply it within @supports: browsers\n  without corner-shape support retain their existing border-radius rendering.\n  Do not clip interactive elements with clip-path to simulate this fallback:\n  that would cut off focus rings, shadows and overflowing child content.\n- The default radius (--radius) is 2.5rem (40px), matching the gallery card.\n  Cards, Dialog/AlertDialog, Select/theme/language popup surfaces and gallery\n  cards share rounded-container. Keep the smaller control scale unchanged:\n  Button remains rounded-3xl (22px) and Input/Select triggers rounded-xl (14px).\n  Match card images, headers and footers,\n  and dialog footers to their container corners. Sheet uses 40px corners only\n  on the exposed edge, leaving the screen-attached edge square. These changes\n  do not alter button/input radii, capsules, avatars or the Tilt card image.\n- For inset rounded elements, calculate the outer radius from the inner\n  radius plus the actual edge gap (r + p), not by assigning the same radius\n  to both. rounded-container accepts local --nested-radius and --nested-gap,\n  with a 40px maximum and a non-negative result. Native border-radius scaling\n  also limits corners to the available surface size. Reset these local values\n  when starting an independent nested container; do not measure unrelated,\n  centered preview content as if it followed the container's edge.\n  Card with footer buttons uses the 22px button radius plus its 12px (small)\n  or 16px (default) padding, producing 34px or 38px. Dialog/AlertDialog with\n  footer buttons use 22px + 16px = 38px. Header/footer backgrounds that share\n  the same outer boundary inherit that computed radius; they have no inset.\n  Default TabsList uses the trigger's 8px radius plus its 3px padding (11px);\n  line tabs remain square. Unmarked standalone containers retain 40px.\n  Docs preview frames also use rounded-container rather than a smaller radius\n  around the larger nested component; their 24px inset reaches the 40px cap\n  for the standard rounded controls and cards.\n\n## Available Components\n\n- Button: default, outline, secondary, ghost, destructive, link. Use its size\n  variants for text and icon-only buttons.\n  Filled hover backgrounds darken: Primary uses --primary-hover\n  (Primary mixed with 12% black), and Secondary mixes with 8% black. Ghost\n  controls use a 5% black hover background in light mode and 5% white in dark mode.\n  Outline buttons keep transparent backgrounds at rest and use a subtle gray\n  hover background: 5% black in light mode and 5% white in dark mode. Destructive\n  controls use a black tint on hover in dark mode. SVG corner examples and the Button hover-state\n  demonstration share the Primary hover token. Keep focus rings and disabled states.\n  On text Button variants, hover text retains its semantic color at 80% opacity\n  instead of darkening, including white, black, and Link text. Icon-only sizes retain\n  their existing foreground behavior; this rule does not change disabled states.\n  Outline Toggle buttons also remain transparent on hover and selection;\n  selected outlines use a stronger border instead of a filled background.\n- Card: header, title, description, content, footer, action.\n- Dialog: trigger, content, title, description, header, footer, close.\n- Alert Dialog: confirmation content, title, description, action, cancel.\n- Tabs: list, trigger, content.\n- Input and Select: labeled text entry and option selection.\n- Slider: numeric ranges.\n- Sheet: bottom-sheet navigation and supporting tasks.\n- Pagination and ToggleGroup: result navigation and filters.\n- Badge: status labels and removable tags.\n  Badge and Tag share text-base (16px), px-4 (16px per side), py-1.5 (6px per\n  side), min-h-9 and gap-2. Keep height content-driven so text and removable\n  actions fit without clipping. Icons are 16px; retain the original pill shape.\n  Gallery filter pills also use 16px horizontal and 6px vertical padding.\n  The instructional pill Button adds 4px horizontal padding on each side.\n  Do not add pill padding to circular avatars, slider thumbs, or progress tracks.\n- Avatar: identity with initials as a fallback.\n- Progress: task completion.\n- ThemeProvider and ThemeToggle: light, dark, and system theme selection.\n- LocaleProvider: Korean/English preference, shared by the settings menu and\n  translated UI text. Wrap ThemeProvider and application content in\n  LocaleProvider when adopting the included ThemeToggle. Its dependencies\n  (`lib/translations.ts`) are included in the reference.\n\nThe full reference includes exact sources, tokens, configuration, utilities,\nand the host project's dependency versions. Version lists describe the\nreference implementation; they do not authorize framework migrations.\n\n## Registry Releases\n\n- `/docs/registry` lists installable COMPASS items and version-pinned install URLs.\n- `/docs/changelog` records release notes. Registry items are available at\n  `/r/<version>/<name>.json`; `/r/<name>.json` resolves to the latest recorded\n  release, not the current development source. Install a version-pinned URL.\n- The initial local release is 0.1.0. It requires a React and Tailwind CSS v4\n  project already initialized with shadcn. Each item includes the shared style\n  tokens, Pretendard, and its component dependency closure. Global style changes\n  must be reviewed, and ThemeProvider connected to the app root separately.\n- Preserve the target's framework, files, and local changes. Do not automatically\n  overwrite customized components or the target's agent instructions.\n- `registry/releases.json` stores release notes newest first; immutable source\n  snapshots live in `registry/releases/<version>.json`. To create a new version,\n  add its notes and run `pnpm registry:release <version>`. Existing versions cannot\n  be overwritten. `pnpm compass:export` rebuilds indexes from snapshots only and\n  never creates releases from live edits. See `docs/registry.md` for maintenance.\n- localhost is local-only. Registry availability on this machine does not mean\n  the site has been deployed or published to npm.\n\n## AI Connection\n\nGive an AI the `/llms-full.txt` document once, then ask it to add a persistent\nCompass rule to the target project's supported instruction file (for example,\nAGENTS.md if the agent reads it). Preserve existing rules. Keep a local copy of\nthis reference for agents that cannot fetch URLs. After that setup, \"디자인\n시스템 써\" means to use Compass's tokens, font, icons, and components.\n\nThere is no global registration that makes every AI recognize this name.\nThe localhost URL is only available on the machine running this site; remote\nAI services need the downloaded reference attached or a hosted accessible URL.\n\n## Documentation\n\n- `/docs`: Introduction.\n- `/docs/installation`: Legacy developer-only page; redirects to `/docs`.\n- `/docs/theming`: Theming.\n- `/docs/cli`: Legacy developer-only page; redirects to `/docs`.\n- `/docs/ai`: AI setup.\n- `/docs/elements/typography`: Typography.\n- `/docs/elements/colors`: Colors.\n- `/docs/elements/icons`: Icons.\n- `/docs/elements/spacing`: Existing spacing scale, spacing roles, and current\n  layout values, without visible CSS tokens, class names, or implementation notes.\n- `/docs/elements/writing`: Writing guidance.\n- `/docs/elements/elevation`: Visual depth, existing shadow classes, stacking\n  order and theme considerations. Flat/Low/Medium/High map to no shadow,\n  shadow-sm/md/lg. These classes map to --surface-shadow-sm/md/lg via @theme\n  inline, with light values unchanged and stronger, wider dark-mode shadows.\n  The comparison tool uses equal surface colors on a slightly contrasting\n  background so only the shadow changes between levels. Use actual\n  component styles: menus/select use shadow-md, Sheet shadow-lg, dialogs ring-1\n  without added shadows. Keep elevation distinct from z-index and focus rings.\n- `/docs/composition/layers`, `/docs/composition/organization`,\n  `/docs/composition/layout`: Composition principles and examples.\n- `/docs/interaction/information-architecture`, `/docs/interaction/input-output`:\n  Interaction principles and examples.\n- `/components`: Component directory grouped into Input, Navigation, Status.\n- Input: `/components/button`, `/components/input`, `/components/select`,\n  `/components/slider`.\n- Navigation: `/components/card`, `/components/bottom-sheet`, `/components/tabs`,\n  `/components/pagination`, `/components/filter`.\n- Status: `/components/badge`, `/components/tag`, `/components/avatar`,\n  `/components/progress`, `/components/dialog`, `/components/alert-dialog`.\n  Each page includes a live preview, without a usage section below it or a source\n  code section. Keep existing component URLs working when changing categories.\n  Button additionally includes guidelines with interactive Compass previews\n  instead of external images: Graphics, Composition, and Interaction, linked\n  from the right ToC. Demonstrate sizes, shapes, padding, hierarchy, states,\n  simulated progress and confirmation feedback using existing UI primitives.\n  Comparison previews display their alternatives simultaneously, not behind\n  tabs or selection controls. Preserve individual button interactions and\n  responsive wrapping, plus sliders and text inputs where relevant.\n  Corner comparison shows two buttons with figma-squircle paths, identical\n  160x64px geometry and a shared nominal radius of 18px. Circular smoothing is\n  0%, continuous smoothing is 60%. Below them, overlay only the enlarged upper\n  straight-to-curve junction in a 3:1 crop, using the exact same paths and scale:\n  neutral dashed circular edge,\n  blue continuous edge, shaded difference, and transition-start dots.\n  Keep this static comparison free of sliders, axes, grids, or extra insets.\n  This is a web approximation, not Apple's\n  exact native continuous-corner implementation; do not equate CSS superellipse\n  with that implementation. Keep keyboard focus indicators outside the SVG.\n- `/`: Gallery with working previews and code copy.\n\nPreserve the existing Docs writing and previews. Do not replace them with new\nUX articles. Rendered Docs omit code blocks, installation commands, imports,\nCSS class names, and development explanations. Remove empty sections and their\nToC entries; developer-only Installation and CLI pages are not in navigation.\nGallery code copy and the downloadable AI implementation reference stay available.\n\nGallery uses the same Input, Navigation, and Status catalog as Docs.\nAll 15 documented components share live preview implementations across both\nsurfaces. Keep the legacy gallery examples, including Heat map. Tilt card also\nbelongs to Visual Effects and uses the React-only source in components/tilt-card.tsx\nand its scoped companion stylesheet. It sinks away from the pointer with a\nspring-driven light intensity and tightening shadow, returning to rest on exit\nor touch release. Keep the pointer shade local: a 22% by 18% elliptical radius,\n13.2% maximum opacity at the default shade setting, fading to 35% of its center\nopacity at the 45% stop and transparent at its edge. Its position uses raw\npointer coordinates without spring smoothing, offset downward by 6% of the\ncard height so it follows just below the cursor immediately. The highlight\nstays fixed at 50% 0% to keep the lighting overhead. The outer shadow, card\nrotation and light intensity retain their existing spring behavior.\nOn exit the pointer shade fades at its last\nposition instead of travelling back to the center.\nKeep keyboard arrows, Escape, focus visibility and reduced\nmotion support. It is transient, so it does not need a footer reset action.\nIts preview is 188px wide with the original 13:16 aspect ratio and scaled shadow,\noffset 8px upward to leave room above the footer. Its two preview wrappers\nuse visible overflow so the returning shadow does not get clipped at the\npreview/footer boundary; other previews use non-scrollable clipped wrappers.\nThe outer card still clips to its rounded boundary. --surface-2 maps\nto the existing --secondary token rather than adding a global Bencho token.\nCopied code includes the component, stylesheet and original MIT notice\n(Copyright 2026 Lorenzo Cabra, https://bencho.dev/licence). Bencho photographs\nare not included; the replacement photograph is by Calvin Mano under the\nUnsplash License (https://unsplash.com/photos/CXS27RrJObQ).\nGallery spans\nthe viewport and uses up to four columns. Code copy is a ghost icon button\nbeside the card title, without a separate action row. Gallery cards have no\ndivider. Every gallery card has a fixed 320px preview\nand a 40px title/action row inside the same surface directly below it, with\n16px horizontal inset and 8px bottom padding. The complete card stays 360px tall.\nGallery cards never scroll internally; only the page scrolls. Compact Card\npreviews use the existing small Card spacing, and Pagination previews use\n44px icon-only previous/next controls with accessible labels and 44px page\nlinks so their full contents fit the fixed preview area. Docs retains its\nregular Card spacing and text labels.\nThe shared preview/title surface uses rounded-container (40px)\ncorners and a subtle 1px inset ring: ring-foreground/8 in light mode for clearer\nseparation from the pale gray gallery page, and dark:ring-border/30 in dark mode.\nThe title and copy button sit within the card, not below its boundary. They\nshare its background without a separate footer color or divider.\nStateful gallery previews have a 32px ghost reset icon immediately to the left\nof code copy. Reset only that preview to its initial state; keep the card footer,\nkeyboard focus, current filter and other cards intact. Static previews have no\nreset action. Gallery Tag and Progress previews omit their internal reset\nbuttons in favor of this footer action; Docs retains its existing controls.\n`lib/gallery-sources.json` is generated\nby `pnpm compass:export` from the actual preview functions for code copy;\ndo not edit it by hand.\n\nGallery starts with a single ungrouped grid sorted by newest update first.\nHeader and content share responsive horizontal padding (16/32/40px).\nThe text-only wordmark reads \"COMPASS\" in 18px type; the browser title is also\n\"COMPASS\". Docs navigation text shares the same\nleft gutter as the wordmark, accounting for its inner 8px link padding.\nThe desktop wordmark-to-navigation gap is 32px (16px flex gap plus 16px margin).\nHeader theme and language icons use 20px; dropdown checkmarks stay 16px.\nGallery uses a compact filter band, with 8px top content padding, 8px filter\ntop padding, 8px filter bottom padding, and an 8px margin before the grid\n(16px combined distance from filters to cards). Navigation active states use\nneutral foreground color and indicators without changing font weight or element\ndimensions. Active main navigation text and underline use text-foreground and\nborder-foreground (near-black in light mode, near-white in dark mode), not Primary.\nKeep the category filters, including Visual Effects for Heat map.\nInactive filter chips use bg-background (white in light mode); selected chips\nretain bg-foreground and text-background for a neutral active state. Do not show\nNew badges on gallery cards. `lib/gallery-updates.json` tracks source hashes and\nupdate timestamps during export; unchanged examples retain their timestamps.\nGallery previews hide supplementary instructions and interaction status text\nvisually, while retaining screen-reader status announcements and actual\ncomponent content. Docs previews keep their existing interaction feedback.\nDocs spans the viewport with a centered document area capped at 40rem (640px).\nThe Button ToC includes nested group and subsection links matching the heading\nhierarchy, including Shape, Size, and all remaining guideline subsections.\nUse \"미리보기\" (\"Preview\") for preview headings and navigation. Button previews\ndo not show a selected-variant status sentence below the controls.\nOn desktop,\nthe left navigation and right table of contents are fixed to the screen edges\nbelow the header, with independent scrolling and reserved content space.\n\nThe Docs navigation opens `/docs/ai` first. Keep AI setup as the first item\nunder Get Started. The top-right theme menu selects the theme. A separate\nLanguageSelect button beside it selects Korean or English. Theme and language\npreferences persist independently.\nKorean navigation uses localized names, including Elevation as \"높이\", Gallery\nas \"갤러리\", Docs as \"문서\", Get Started as \"시작하기\", Elements as \"기본 요소\",\nand Input/Navigation/Status as \"입력\"/\"탐색\"/\"상태\". Use translate or\nLocaleText consistently for group headings, filters, breadcrumbs and ToC.\nKeep English labels in English mode and preserve the Compass wordmark.\n\n## Updating the AI Reference\n\nRun `pnpm compass:export` after source or guidance changes. This also runs\nbefore `pnpm dev` and `pnpm build`. It exports only the explicitly selected\npublic design-system files; it does not export secrets or the whole repository.\n"}],"docs":"Requires an existing React + Tailwind CSS v4 project initialized with shadcn. COMPASS merges global styles; review existing components and CSS before installing. ThemeProvider must be connected to the application root separately. See /docs/registry and /docs/ai.","meta":{"version":"0.1.0","group":"status"}},{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"dialog","title":"다이얼로그","type":"registry:ui","registryDependencies":["https://0.0.0.0:3000/r/0.1.0/foundations.json"],"cssVars":{"theme":{"shadow-sm":"var(--surface-shadow-sm)","shadow-md":"var(--surface-shadow-md)","shadow-lg":"var(--surface-shadow-lg)","font-heading":"\"Pretendard Variable\", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, sans-serif","font-sans":"\"Pretendard Variable\", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, sans-serif","font-mono":"\"SFMono-Regular\", Consolas, \"Liberation Mono\", Menlo, monospace","color-sidebar-ring":"var(--sidebar-ring)","color-sidebar-border":"var(--sidebar-border)","color-sidebar-accent-foreground":"var(--sidebar-accent-foreground)","color-sidebar-accent":"var(--sidebar-accent)","color-sidebar-primary-foreground":"var(--sidebar-primary-foreground)","color-sidebar-primary":"var(--sidebar-primary)","color-sidebar-foreground":"var(--sidebar-foreground)","color-sidebar":"var(--sidebar)","color-chart-5":"var(--chart-5)","color-chart-4":"var(--chart-4)","color-chart-3":"var(--chart-3)","color-chart-2":"var(--chart-2)","color-chart-1":"var(--chart-1)","color-ring":"var(--ring)","color-input":"var(--input)","color-border":"var(--border)","color-destructive":"var(--destructive)","color-accent-foreground":"var(--accent-foreground)","color-accent":"var(--accent)","color-muted-foreground":"var(--muted-foreground)","color-muted":"var(--muted)","color-secondary-foreground":"var(--secondary-foreground)","color-secondary":"var(--secondary)","color-primary-foreground":"var(--primary-foreground)","color-primary":"var(--primary)","color-primary-hover":"var(--primary-hover)","color-popover-foreground":"var(--popover-foreground)","color-popover":"var(--popover)","color-card-foreground":"var(--card-foreground)","color-card":"var(--card)","color-foreground":"var(--foreground)","color-background":"var(--background)","color-gallery-background":"var(--gallery-background)","radius-sm":"calc(var(--radius) * 0.15)","radius-md":"calc(var(--radius) * 0.2)","radius-lg":"calc(var(--radius) * 0.25)","radius-xl":"calc(var(--radius) * 0.35)","radius-2xl":"calc(var(--radius) * 0.45)","radius-3xl":"calc(var(--radius) * 0.55)","radius-4xl":"calc(var(--radius) * 0.65)","radius-5xl":"calc(var(--radius) * 0.8)","radius-6xl":"var(--radius)","radius-container":"min(var(--radius), max(0px, calc(var(--nested-radius, var(--radius)) + var(--nested-gap, 0px))))"},"light":{"corner-shape":"squircle","surface-shadow-sm":"0 1px 3px 0 rgb(0 0 0 / 10%), 0 1px 2px -1px rgb(0 0 0 / 10%)","surface-shadow-md":"0 4px 6px -1px rgb(0 0 0 / 10%), 0 2px 4px -2px rgb(0 0 0 / 10%)","surface-shadow-lg":"0 10px 15px -3px rgb(0 0 0 / 10%), 0 4px 6px -4px rgb(0 0 0 / 10%)","background":"#ffffff","gallery-background":"#f7f7f7","gallery-preview-background":"oklch(1 0 0)","foreground":"oklch(0.145 0 0)","card":"oklch(1 0 0)","card-foreground":"oklch(0.145 0 0)","popover":"oklch(1 0 0)","popover-foreground":"oklch(0.145 0 0)","primary":"#007AFF","primary-hover":"color-mix(in oklch, var(--primary), black 12%)","primary-foreground":"#ffffff","secondary":"oklch(0.97 0 0)","secondary-foreground":"oklch(0.205 0 0)","muted":"oklch(0.97 0 0)","muted-foreground":"oklch(0.556 0 0)","accent":"#007AFF","accent-foreground":"#ffffff","destructive":"oklch(0.577 0.245 27.325)","border":"oklch(0.922 0 0)","input":"oklch(0.922 0 0)","ring":"oklch(0.708 0 0)","chart-1":"oklch(0.87 0 0)","chart-2":"oklch(0.556 0 0)","chart-3":"oklch(0.439 0 0)","chart-4":"oklch(0.371 0 0)","chart-5":"oklch(0.269 0 0)","radius":"2.5rem","sidebar":"oklch(0.985 0 0)","sidebar-foreground":"oklch(0.145 0 0)","sidebar-primary":"oklch(0.205 0 0)","sidebar-primary-foreground":"oklch(0.985 0 0)","sidebar-accent":"oklch(0.97 0 0)","sidebar-accent-foreground":"oklch(0.205 0 0)","sidebar-border":"oklch(0.922 0 0)","sidebar-ring":"oklch(0.708 0 0)"},"dark":{"surface-shadow-sm":"0 2px 6px 0 rgb(0 0 0 / 40%), 0 1px 2px 0 rgb(0 0 0 / 25%)","surface-shadow-md":"0 6px 16px -2px rgb(0 0 0 / 50%), 0 2px 6px 0 rgb(0 0 0 / 35%)","surface-shadow-lg":"0 14px 32px -4px rgb(0 0 0 / 65%), 0 6px 12px -2px rgb(0 0 0 / 45%)","background":"oklch(0.15 0 0)","gallery-background":"oklch(0.15 0 0)","gallery-preview-background":"oklch(0.18 0 0)","foreground":"oklch(0.985 0 0)","card":"oklch(0.205 0 0)","card-foreground":"oklch(0.985 0 0)","popover":"oklch(0.205 0 0)","popover-foreground":"oklch(0.985 0 0)","primary":"#007AFF","primary-foreground":"#ffffff","secondary":"oklch(0.269 0 0)","secondary-foreground":"oklch(0.985 0 0)","muted":"oklch(0.269 0 0)","muted-foreground":"oklch(0.708 0 0)","accent":"#007AFF","accent-foreground":"#ffffff","destructive":"oklch(0.704 0.191 22.216)","border":"oklch(1 0 0 / 10%)","input":"oklch(1 0 0 / 15%)","ring":"oklch(0.556 0 0)","chart-1":"oklch(0.87 0 0)","chart-2":"oklch(0.556 0 0)","chart-3":"oklch(0.439 0 0)","chart-4":"oklch(0.371 0 0)","chart-5":"oklch(0.269 0 0)","sidebar":"oklch(0.205 0 0)","sidebar-foreground":"oklch(0.985 0 0)","sidebar-primary":"oklch(0.488 0.243 264.376)","sidebar-primary-foreground":"oklch(0.985 0 0)","sidebar-accent":"oklch(0.269 0 0)","sidebar-accent-foreground":"oklch(0.985 0 0)","sidebar-border":"oklch(1 0 0 / 10%)","sidebar-ring":"oklch(0.556 0 0)"}},"css":{"@import \"tw-animate-css\"":{},"@import \"shadcn/tailwind.css\"":{},"@custom-variant dark (&:is(.dark *))":{},"@layer base":{"*":{"@apply border-border outline-ring/50":{}},"body":{"@apply bg-background text-foreground":{}},"button:not(:disabled), [role=\"button\"]:not(:disabled)":{"cursor":"pointer"},"html":{"@apply font-sans":{}},"@supports (corner-shape: squircle)":{"*":{"corner-shape":"var(--corner-shape)"},"::before, ::after":{"corner-shape":"inherit"},":where(.rounded-full, [data-slot=\"badge\"],\n           [data-slot^=\"avatar\"], [data-slot=\"slider-thumb\"],\n           [data-slot=\"slider-track\"], [data-slot=\"progress\"],\n           [data-corner=\"round\"])":{"corner-shape":"round"}}},"@import \"pretendard/dist/web/variable/pretendardvariable.css\"":{}},"dependencies":["class-variance-authority@0.7.1","cn@0.4.0","lucide-react@1.52.0","pretendard@1.3.9","radix-ui@1.6.7","shadcn@4.21.0","tw-animate-css@1.4.0"],"files":[{"path":"components/ui/dialog.tsx","type":"registry:ui","target":"@ui/dialog.tsx","content":"\"use client\"\n\nimport * as React from \"react\"\nimport { cn } from \"cn\"\nimport { Dialog as DialogPrimitive } from \"radix-ui\"\n\nimport { Button } from \"@/components/ui/button\"\n\nimport { X } from \"lucide-react\"\n\nfunction Dialog({\n  ...props\n}: React.ComponentProps<typeof DialogPrimitive.Root>) {\n  return <DialogPrimitive.Root data-slot=\"dialog\" {...props} />\n}\n\nfunction DialogTrigger({\n  ...props\n}: React.ComponentProps<typeof DialogPrimitive.Trigger>) {\n  return <DialogPrimitive.Trigger data-slot=\"dialog-trigger\" {...props} />\n}\n\nfunction DialogPortal({\n  ...props\n}: React.ComponentProps<typeof DialogPrimitive.Portal>) {\n  return <DialogPrimitive.Portal data-slot=\"dialog-portal\" {...props} />\n}\n\nfunction DialogClose({\n  ...props\n}: React.ComponentProps<typeof DialogPrimitive.Close>) {\n  return <DialogPrimitive.Close data-slot=\"dialog-close\" {...props} />\n}\n\nfunction DialogOverlay({\n  className,\n  ...props\n}: React.ComponentProps<typeof DialogPrimitive.Overlay>) {\n  return (\n    <DialogPrimitive.Overlay\n      data-slot=\"dialog-overlay\"\n      className={cn(\n        \"fixed inset-0 isolate z-50 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction DialogContent({\n  className,\n  children,\n  showCloseButton = true,\n  ...props\n}: React.ComponentProps<typeof DialogPrimitive.Content> & {\n  showCloseButton?: boolean\n}) {\n  return (\n    <DialogPortal>\n      <DialogOverlay />\n      <DialogPrimitive.Content\n        data-slot=\"dialog-content\"\n        className={cn(\n          \"fixed top-1/2 left-1/2 z-50 grid w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 gap-4 rounded-container [--nested-radius:var(--radius)] [--nested-gap:0px] has-[[data-slot=dialog-footer]_button]:[--nested-radius:calc(var(--radius)*0.55)] has-[[data-slot=dialog-footer]_button]:[--nested-gap:--spacing(4)] bg-popover p-4 text-sm text-popover-foreground ring-1 ring-foreground/10 duration-100 outline-none sm:max-w-sm data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95\",\n          className\n        )}\n        {...props}\n      >\n        {children}\n        {showCloseButton && (\n          <DialogPrimitive.Close data-slot=\"dialog-close\" asChild>\n            <Button\n              variant=\"ghost\"\n              className=\"absolute top-2 right-2\"\n              size=\"icon-sm\"\n            >\n              <X strokeWidth={2} />\n              <span className=\"sr-only\">Close</span>\n            </Button>\n          </DialogPrimitive.Close>\n        )}\n      </DialogPrimitive.Content>\n    </DialogPortal>\n  )\n}\n\nfunction DialogHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"dialog-header\"\n      className={cn(\"flex flex-col gap-2\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction DialogFooter({\n  className,\n  showCloseButton = false,\n  children,\n  ...props\n}: React.ComponentProps<\"div\"> & {\n  showCloseButton?: boolean\n}) {\n  return (\n    <div\n      data-slot=\"dialog-footer\"\n      className={cn(\n        \"-mx-4 -mb-4 flex flex-col-reverse gap-2 rounded-b-container border-t bg-muted/50 p-4 sm:flex-row sm:justify-end\",\n        className\n      )}\n      {...props}\n    >\n      {children}\n      {showCloseButton && (\n        <DialogPrimitive.Close asChild>\n          <Button variant=\"outline\">Close</Button>\n        </DialogPrimitive.Close>\n      )}\n    </div>\n  )\n}\n\nfunction DialogTitle({\n  className,\n  ...props\n}: React.ComponentProps<typeof DialogPrimitive.Title>) {\n  return (\n    <DialogPrimitive.Title\n      data-slot=\"dialog-title\"\n      className={cn(\n        \"font-heading text-base leading-none font-medium\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction DialogDescription({\n  className,\n  ...props\n}: React.ComponentProps<typeof DialogPrimitive.Description>) {\n  return (\n    <DialogPrimitive.Description\n      data-slot=\"dialog-description\"\n      className={cn(\n        \"text-sm text-muted-foreground *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nexport {\n  Dialog,\n  DialogClose,\n  DialogContent,\n  DialogDescription,\n  DialogFooter,\n  DialogHeader,\n  DialogOverlay,\n  DialogPortal,\n  DialogTitle,\n  DialogTrigger,\n}\n"},{"path":"components/ui/button.tsx","type":"registry:ui","target":"@ui/button.tsx","content":"import * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { cn } from \"cn\"\nimport { Slot } from \"radix-ui\"\n\nconst buttonVariants = cva(\n  \"group/button inline-flex shrink-0 items-center justify-center rounded-3xl border border-transparent bg-clip-padding py-[4pt] text-base font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n  {\n    variants: {\n      variant: {\n        default: \"bg-primary text-primary-foreground hover:bg-primary-hover hover:[&:not([data-size^=icon])]:text-[color-mix(in_oklch,var(--primary-foreground),transparent_20%)]\",\n        outline:\n          \"border-border bg-transparent hover:bg-black/5 hover:text-foreground hover:[&:not([data-size^=icon])]:text-[color-mix(in_oklch,var(--foreground),transparent_20%)] aria-expanded:text-foreground dark:border-input dark:hover:bg-white/5\",\n        secondary:\n          \"bg-secondary text-secondary-foreground hover:bg-[color-mix(in_oklch,var(--secondary),black_8%)] hover:[&:not([data-size^=icon])]:text-[color-mix(in_oklch,var(--secondary-foreground),transparent_20%)] aria-expanded:bg-secondary aria-expanded:text-secondary-foreground\",\n        ghost:\n          \"hover:bg-black/5 hover:text-foreground hover:[&:not([data-size^=icon])]:text-[color-mix(in_oklch,var(--foreground),transparent_20%)] aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-white/5\",\n        destructive:\n          \"bg-destructive/10 text-destructive hover:bg-destructive/20 hover:[&:not([data-size^=icon])]:text-[color-mix(in_oklch,var(--destructive),transparent_20%)] focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-black/20 dark:focus-visible:ring-destructive/40\",\n        link: \"text-primary underline-offset-4 hover:text-primary-hover hover:[&:not([data-size^=icon])]:text-[color-mix(in_oklch,var(--primary),transparent_20%)] hover:underline\",\n      },\n      size: {\n        default:\n          \"h-[calc(2.5rem+8pt)] gap-2 px-[calc(1rem+4pt)] has-data-[icon=inline-end]:pr-[calc(.75rem+4pt)] has-data-[icon=inline-start]:pl-[calc(.75rem+4pt)]\",\n        xs: \"h-[calc(2rem+8pt)] gap-1.5 rounded-3xl px-[calc(.75rem+4pt)] text-[calc(0.75rem+2pt)] in-data-[slot=button-group]:rounded-3xl has-data-[icon=inline-end]:pr-[calc(.625rem+4pt)] has-data-[icon=inline-start]:pl-[calc(.625rem+4pt)] [&_svg:not([class*='size-'])]:size-3\",\n        sm: \"h-[calc(2.25rem+8pt)] gap-1.5 rounded-3xl px-[calc(.875rem+4pt)] text-[calc(0.8rem+2pt)] in-data-[slot=button-group]:rounded-3xl has-data-[icon=inline-end]:pr-[calc(.75rem+4pt)] has-data-[icon=inline-start]:pl-[calc(.75rem+4pt)] [&_svg:not([class*='size-'])]:size-3.5\",\n        lg: \"h-[calc(2.75rem+8pt)] gap-2 px-[calc(1.25rem+4pt)] has-data-[icon=inline-end]:pr-[calc(1rem+4pt)] has-data-[icon=inline-start]:pl-[calc(1rem+4pt)]\",\n        icon: \"size-[calc(2.5rem+8pt)]\",\n        \"icon-xs\":\n          \"size-[calc(2rem+8pt)] rounded-3xl in-data-[slot=button-group]:rounded-3xl [&_svg:not([class*='size-'])]:size-3\",\n        \"icon-sm\":\n          \"size-[calc(2.25rem+8pt)] rounded-3xl in-data-[slot=button-group]:rounded-3xl\",\n        \"icon-lg\": \"size-[calc(2.75rem+8pt)]\",\n      },\n    },\n    defaultVariants: {\n      variant: \"default\",\n      size: \"default\",\n    },\n  }\n)\n\nfunction Button({\n  className,\n  variant = \"default\",\n  size = \"default\",\n  asChild = false,\n  ...props\n}: React.ComponentProps<\"button\"> &\n  VariantProps<typeof buttonVariants> & {\n    asChild?: boolean\n  }) {\n  const Comp = asChild ? Slot.Root : \"button\"\n\n  return (\n    <Comp\n      data-slot=\"button\"\n      data-variant={variant}\n      data-size={size}\n      className={cn(buttonVariants({ variant, size, className }))}\n      {...props}\n    />\n  )\n}\n\nexport { Button, buttonVariants }\n"},{"path":"docs/compass.md","type":"registry:file","target":"~/docs/compass.md","content":"# Compass Design System\n\nCompass is the design system for this project. When the user says \"use the\ndesign system\", \"디자인 시스템 써\", or \"Compass 써\", apply these rules.\n\n## Applying Compass\n\n1. Inspect the target project before changing it. Preserve its framework and\n   package manager. Do not replace the application or overwrite its existing\n   agent instructions. Merge Compass guidance into its project instructions.\n2. In this repository, reuse the actual source in `components/ui`. Outside this\n   repository, use the source included in `/llms-full.txt` and adapt import\n   aliases to the target project. The included code targets React and Tailwind\n   CSS v4. For a different stack, keep the same tokens and behavior and explain\n   adaptations rather than pretending these React components work unchanged.\n3. Use the exact CSS tokens included in the reference. Treat `app/globals.css`\n   as the source of truth. Merge theme imports and mappings without duplicating\n   Tailwind imports or replacing unrelated CSS. Preserve light and dark themes.\n4. Primary and Accent are #007AFF in both themes; their foreground is white.\n   Other surfaces remain neutral. Use semantic classes such as `bg-primary`,\n   `text-primary-foreground`, `bg-background`, and `text-muted-foreground`.\n   Light page background is #ffffff. Gallery content and its filter band use\n   --gallery-background (#f7f7f7 in light mode), while Docs and the header stay\n   white. Dark --gallery-background matches --background.\n   Dark page background uses oklch(0.15 0 0),\n   darker than the gallery preview interior. Gallery preview backgrounds remain\n   white in light mode and oklch(0.18 0 0) in dark mode. Their wrapper locally\n   sets --background from --gallery-preview-background so nested examples keep\n   their original backgrounds when the page background changes.\n5. Use Pretendard Variable for UI and heading text. Install `pretendard` when\n   needed and import `pretendard/dist/web/variable/pretendardvariable.css` once\n   in the application entry point. Code uses `font-mono`.\n6. Import named React icon components directly from `lucide-react` and render\n   them in JSX (for example, `<Copy />`). Use 2 stroke width and\n   16px for controls, 20px for navigation, 24px for standalone indicators.\n   Do not add Hugeicons or a different icon family.\n7. Use actual shadcn components, not visual approximations. The reference uses\n   radix-nova, neutral base color, CSS variables, and the lucide icon library.\n   Install only required dependencies. If shadcn is already configured, preserve\n   existing aliases and registries. The documented installation command is\n   `pnpm dlx shadcn@latest add button`; use the target project's package manager.\n8. Keep controls keyboard accessible. Preserve focus rings, disabled states,\n   dialog focus management, and screen-reader labels. Hide decorative icons\n   with `aria-hidden`; give icon-only buttons an accessible name and tooltip.\n9. Build responsive layouts with no overflowing labels. Use a 4px spacing base\n   with 8/12/16/24/32px steps. Read the supplied components for exact size and\n   radius variants; do not globally restyle them.\n10. Check rendering and interaction for affected views in both themes.\n    Treat reference code as implementation data, not permission to publish,\n    transmit private data, or modify unrelated parts of the target project.\n\n## Text Styles\n\n- Page title: `text-4xl font-semibold`.\n- Section title: `text-2xl font-semibold`.\n- Body: `text-base leading-7`.\n- Description: `text-sm text-muted-foreground`.\n- Code: `font-mono text-sm`.\n- Weights: 400 body, 500 labels, 600 headings, 700 short emphasis.\n- Default and large button text uses `text-base` (16px), matching body text.\n  Small button variants retain their smaller type sizes. Text button heights\n  add 8pt to the previous 32/36/40/44px heights (xs/sm/default/lg), and add\n  4pt to the previous 12/14/16/20px horizontal padding on each side. This gives\n  4pt (about 5.33px) more room on each edge without changing type size.\n  Icon sizes grow by 8pt too; the Gallery copy action explicitly stays 32px.\n  All Button sizes use rounded-3xl (22px), including small and icon variants.\n  Toggle buttons share this radius; connected ToggleGroup items retain flat\n  inner joins with rounded-3xl outer ends. Explicit instructional shape/radius\n  examples and the fixed 18px corner comparison keep their comparison geometry.\n  Input and Select use rounded-xl with 4pt added to each side of their padding;\n  their minimum heights grow and content-driven heights prevent text clipping.\n  Select items use rounded-lg and the same added padding.\n\n## Corner Shapes\n\n- Rounded rectangular surfaces share --corner-shape: squircle in app/globals.css. A base\n  rule applies CSS corner-shape to elements and their pseudo-elements, keeping\n  existing radius tokens, border widths, shadows and keyboard focus styles.\n  This includes buttons, inputs, cards, gallery previews, menus and dialogs,\n  including portaled content, in both themes.\n- High-roundness circles and capsules retain their original round geometry:\n  all rounded-full elements (including gallery filter pills), badges, avatar\n  circles, slider thumbs and tracks, and progress tracks. Pseudo-elements follow\n  their owning element; a round parent does not change rectangular children.\n  Use data-corner=\"round\" for an intentionally circular/capsule\n  example or a surface whose shape is drawn by SVG. The Button corner comparison\n  still uses its independent figma-squircle paths so circular and continuous\n  examples remain distinct.\n- CSS squircle is a web approximation, not the same curve as Figma smoothing\n  or Apple's native continuous corners. Apply it within @supports: browsers\n  without corner-shape support retain their existing border-radius rendering.\n  Do not clip interactive elements with clip-path to simulate this fallback:\n  that would cut off focus rings, shadows and overflowing child content.\n- The default radius (--radius) is 2.5rem (40px), matching the gallery card.\n  Cards, Dialog/AlertDialog, Select/theme/language popup surfaces and gallery\n  cards share rounded-container. Keep the smaller control scale unchanged:\n  Button remains rounded-3xl (22px) and Input/Select triggers rounded-xl (14px).\n  Match card images, headers and footers,\n  and dialog footers to their container corners. Sheet uses 40px corners only\n  on the exposed edge, leaving the screen-attached edge square. These changes\n  do not alter button/input radii, capsules, avatars or the Tilt card image.\n- For inset rounded elements, calculate the outer radius from the inner\n  radius plus the actual edge gap (r + p), not by assigning the same radius\n  to both. rounded-container accepts local --nested-radius and --nested-gap,\n  with a 40px maximum and a non-negative result. Native border-radius scaling\n  also limits corners to the available surface size. Reset these local values\n  when starting an independent nested container; do not measure unrelated,\n  centered preview content as if it followed the container's edge.\n  Card with footer buttons uses the 22px button radius plus its 12px (small)\n  or 16px (default) padding, producing 34px or 38px. Dialog/AlertDialog with\n  footer buttons use 22px + 16px = 38px. Header/footer backgrounds that share\n  the same outer boundary inherit that computed radius; they have no inset.\n  Default TabsList uses the trigger's 8px radius plus its 3px padding (11px);\n  line tabs remain square. Unmarked standalone containers retain 40px.\n  Docs preview frames also use rounded-container rather than a smaller radius\n  around the larger nested component; their 24px inset reaches the 40px cap\n  for the standard rounded controls and cards.\n\n## Available Components\n\n- Button: default, outline, secondary, ghost, destructive, link. Use its size\n  variants for text and icon-only buttons.\n  Filled hover backgrounds darken: Primary uses --primary-hover\n  (Primary mixed with 12% black), and Secondary mixes with 8% black. Ghost\n  controls use a 5% black hover background in light mode and 5% white in dark mode.\n  Outline buttons keep transparent backgrounds at rest and use a subtle gray\n  hover background: 5% black in light mode and 5% white in dark mode. Destructive\n  controls use a black tint on hover in dark mode. SVG corner examples and the Button hover-state\n  demonstration share the Primary hover token. Keep focus rings and disabled states.\n  On text Button variants, hover text retains its semantic color at 80% opacity\n  instead of darkening, including white, black, and Link text. Icon-only sizes retain\n  their existing foreground behavior; this rule does not change disabled states.\n  Outline Toggle buttons also remain transparent on hover and selection;\n  selected outlines use a stronger border instead of a filled background.\n- Card: header, title, description, content, footer, action.\n- Dialog: trigger, content, title, description, header, footer, close.\n- Alert Dialog: confirmation content, title, description, action, cancel.\n- Tabs: list, trigger, content.\n- Input and Select: labeled text entry and option selection.\n- Slider: numeric ranges.\n- Sheet: bottom-sheet navigation and supporting tasks.\n- Pagination and ToggleGroup: result navigation and filters.\n- Badge: status labels and removable tags.\n  Badge and Tag share text-base (16px), px-4 (16px per side), py-1.5 (6px per\n  side), min-h-9 and gap-2. Keep height content-driven so text and removable\n  actions fit without clipping. Icons are 16px; retain the original pill shape.\n  Gallery filter pills also use 16px horizontal and 6px vertical padding.\n  The instructional pill Button adds 4px horizontal padding on each side.\n  Do not add pill padding to circular avatars, slider thumbs, or progress tracks.\n- Avatar: identity with initials as a fallback.\n- Progress: task completion.\n- ThemeProvider and ThemeToggle: light, dark, and system theme selection.\n- LocaleProvider: Korean/English preference, shared by the settings menu and\n  translated UI text. Wrap ThemeProvider and application content in\n  LocaleProvider when adopting the included ThemeToggle. Its dependencies\n  (`lib/translations.ts`) are included in the reference.\n\nThe full reference includes exact sources, tokens, configuration, utilities,\nand the host project's dependency versions. Version lists describe the\nreference implementation; they do not authorize framework migrations.\n\n## Registry Releases\n\n- `/docs/registry` lists installable COMPASS items and version-pinned install URLs.\n- `/docs/changelog` records release notes. Registry items are available at\n  `/r/<version>/<name>.json`; `/r/<name>.json` resolves to the latest recorded\n  release, not the current development source. Install a version-pinned URL.\n- The initial local release is 0.1.0. It requires a React and Tailwind CSS v4\n  project already initialized with shadcn. Each item includes the shared style\n  tokens, Pretendard, and its component dependency closure. Global style changes\n  must be reviewed, and ThemeProvider connected to the app root separately.\n- Preserve the target's framework, files, and local changes. Do not automatically\n  overwrite customized components or the target's agent instructions.\n- `registry/releases.json` stores release notes newest first; immutable source\n  snapshots live in `registry/releases/<version>.json`. To create a new version,\n  add its notes and run `pnpm registry:release <version>`. Existing versions cannot\n  be overwritten. `pnpm compass:export` rebuilds indexes from snapshots only and\n  never creates releases from live edits. See `docs/registry.md` for maintenance.\n- localhost is local-only. Registry availability on this machine does not mean\n  the site has been deployed or published to npm.\n\n## AI Connection\n\nGive an AI the `/llms-full.txt` document once, then ask it to add a persistent\nCompass rule to the target project's supported instruction file (for example,\nAGENTS.md if the agent reads it). Preserve existing rules. Keep a local copy of\nthis reference for agents that cannot fetch URLs. After that setup, \"디자인\n시스템 써\" means to use Compass's tokens, font, icons, and components.\n\nThere is no global registration that makes every AI recognize this name.\nThe localhost URL is only available on the machine running this site; remote\nAI services need the downloaded reference attached or a hosted accessible URL.\n\n## Documentation\n\n- `/docs`: Introduction.\n- `/docs/installation`: Legacy developer-only page; redirects to `/docs`.\n- `/docs/theming`: Theming.\n- `/docs/cli`: Legacy developer-only page; redirects to `/docs`.\n- `/docs/ai`: AI setup.\n- `/docs/elements/typography`: Typography.\n- `/docs/elements/colors`: Colors.\n- `/docs/elements/icons`: Icons.\n- `/docs/elements/spacing`: Existing spacing scale, spacing roles, and current\n  layout values, without visible CSS tokens, class names, or implementation notes.\n- `/docs/elements/writing`: Writing guidance.\n- `/docs/elements/elevation`: Visual depth, existing shadow classes, stacking\n  order and theme considerations. Flat/Low/Medium/High map to no shadow,\n  shadow-sm/md/lg. These classes map to --surface-shadow-sm/md/lg via @theme\n  inline, with light values unchanged and stronger, wider dark-mode shadows.\n  The comparison tool uses equal surface colors on a slightly contrasting\n  background so only the shadow changes between levels. Use actual\n  component styles: menus/select use shadow-md, Sheet shadow-lg, dialogs ring-1\n  without added shadows. Keep elevation distinct from z-index and focus rings.\n- `/docs/composition/layers`, `/docs/composition/organization`,\n  `/docs/composition/layout`: Composition principles and examples.\n- `/docs/interaction/information-architecture`, `/docs/interaction/input-output`:\n  Interaction principles and examples.\n- `/components`: Component directory grouped into Input, Navigation, Status.\n- Input: `/components/button`, `/components/input`, `/components/select`,\n  `/components/slider`.\n- Navigation: `/components/card`, `/components/bottom-sheet`, `/components/tabs`,\n  `/components/pagination`, `/components/filter`.\n- Status: `/components/badge`, `/components/tag`, `/components/avatar`,\n  `/components/progress`, `/components/dialog`, `/components/alert-dialog`.\n  Each page includes a live preview, without a usage section below it or a source\n  code section. Keep existing component URLs working when changing categories.\n  Button additionally includes guidelines with interactive Compass previews\n  instead of external images: Graphics, Composition, and Interaction, linked\n  from the right ToC. Demonstrate sizes, shapes, padding, hierarchy, states,\n  simulated progress and confirmation feedback using existing UI primitives.\n  Comparison previews display their alternatives simultaneously, not behind\n  tabs or selection controls. Preserve individual button interactions and\n  responsive wrapping, plus sliders and text inputs where relevant.\n  Corner comparison shows two buttons with figma-squircle paths, identical\n  160x64px geometry and a shared nominal radius of 18px. Circular smoothing is\n  0%, continuous smoothing is 60%. Below them, overlay only the enlarged upper\n  straight-to-curve junction in a 3:1 crop, using the exact same paths and scale:\n  neutral dashed circular edge,\n  blue continuous edge, shaded difference, and transition-start dots.\n  Keep this static comparison free of sliders, axes, grids, or extra insets.\n  This is a web approximation, not Apple's\n  exact native continuous-corner implementation; do not equate CSS superellipse\n  with that implementation. Keep keyboard focus indicators outside the SVG.\n- `/`: Gallery with working previews and code copy.\n\nPreserve the existing Docs writing and previews. Do not replace them with new\nUX articles. Rendered Docs omit code blocks, installation commands, imports,\nCSS class names, and development explanations. Remove empty sections and their\nToC entries; developer-only Installation and CLI pages are not in navigation.\nGallery code copy and the downloadable AI implementation reference stay available.\n\nGallery uses the same Input, Navigation, and Status catalog as Docs.\nAll 15 documented components share live preview implementations across both\nsurfaces. Keep the legacy gallery examples, including Heat map. Tilt card also\nbelongs to Visual Effects and uses the React-only source in components/tilt-card.tsx\nand its scoped companion stylesheet. It sinks away from the pointer with a\nspring-driven light intensity and tightening shadow, returning to rest on exit\nor touch release. Keep the pointer shade local: a 22% by 18% elliptical radius,\n13.2% maximum opacity at the default shade setting, fading to 35% of its center\nopacity at the 45% stop and transparent at its edge. Its position uses raw\npointer coordinates without spring smoothing, offset downward by 6% of the\ncard height so it follows just below the cursor immediately. The highlight\nstays fixed at 50% 0% to keep the lighting overhead. The outer shadow, card\nrotation and light intensity retain their existing spring behavior.\nOn exit the pointer shade fades at its last\nposition instead of travelling back to the center.\nKeep keyboard arrows, Escape, focus visibility and reduced\nmotion support. It is transient, so it does not need a footer reset action.\nIts preview is 188px wide with the original 13:16 aspect ratio and scaled shadow,\noffset 8px upward to leave room above the footer. Its two preview wrappers\nuse visible overflow so the returning shadow does not get clipped at the\npreview/footer boundary; other previews use non-scrollable clipped wrappers.\nThe outer card still clips to its rounded boundary. --surface-2 maps\nto the existing --secondary token rather than adding a global Bencho token.\nCopied code includes the component, stylesheet and original MIT notice\n(Copyright 2026 Lorenzo Cabra, https://bencho.dev/licence). Bencho photographs\nare not included; the replacement photograph is by Calvin Mano under the\nUnsplash License (https://unsplash.com/photos/CXS27RrJObQ).\nGallery spans\nthe viewport and uses up to four columns. Code copy is a ghost icon button\nbeside the card title, without a separate action row. Gallery cards have no\ndivider. Every gallery card has a fixed 320px preview\nand a 40px title/action row inside the same surface directly below it, with\n16px horizontal inset and 8px bottom padding. The complete card stays 360px tall.\nGallery cards never scroll internally; only the page scrolls. Compact Card\npreviews use the existing small Card spacing, and Pagination previews use\n44px icon-only previous/next controls with accessible labels and 44px page\nlinks so their full contents fit the fixed preview area. Docs retains its\nregular Card spacing and text labels.\nThe shared preview/title surface uses rounded-container (40px)\ncorners and a subtle 1px inset ring: ring-foreground/8 in light mode for clearer\nseparation from the pale gray gallery page, and dark:ring-border/30 in dark mode.\nThe title and copy button sit within the card, not below its boundary. They\nshare its background without a separate footer color or divider.\nStateful gallery previews have a 32px ghost reset icon immediately to the left\nof code copy. Reset only that preview to its initial state; keep the card footer,\nkeyboard focus, current filter and other cards intact. Static previews have no\nreset action. Gallery Tag and Progress previews omit their internal reset\nbuttons in favor of this footer action; Docs retains its existing controls.\n`lib/gallery-sources.json` is generated\nby `pnpm compass:export` from the actual preview functions for code copy;\ndo not edit it by hand.\n\nGallery starts with a single ungrouped grid sorted by newest update first.\nHeader and content share responsive horizontal padding (16/32/40px).\nThe text-only wordmark reads \"COMPASS\" in 18px type; the browser title is also\n\"COMPASS\". Docs navigation text shares the same\nleft gutter as the wordmark, accounting for its inner 8px link padding.\nThe desktop wordmark-to-navigation gap is 32px (16px flex gap plus 16px margin).\nHeader theme and language icons use 20px; dropdown checkmarks stay 16px.\nGallery uses a compact filter band, with 8px top content padding, 8px filter\ntop padding, 8px filter bottom padding, and an 8px margin before the grid\n(16px combined distance from filters to cards). Navigation active states use\nneutral foreground color and indicators without changing font weight or element\ndimensions. Active main navigation text and underline use text-foreground and\nborder-foreground (near-black in light mode, near-white in dark mode), not Primary.\nKeep the category filters, including Visual Effects for Heat map.\nInactive filter chips use bg-background (white in light mode); selected chips\nretain bg-foreground and text-background for a neutral active state. Do not show\nNew badges on gallery cards. `lib/gallery-updates.json` tracks source hashes and\nupdate timestamps during export; unchanged examples retain their timestamps.\nGallery previews hide supplementary instructions and interaction status text\nvisually, while retaining screen-reader status announcements and actual\ncomponent content. Docs previews keep their existing interaction feedback.\nDocs spans the viewport with a centered document area capped at 40rem (640px).\nThe Button ToC includes nested group and subsection links matching the heading\nhierarchy, including Shape, Size, and all remaining guideline subsections.\nUse \"미리보기\" (\"Preview\") for preview headings and navigation. Button previews\ndo not show a selected-variant status sentence below the controls.\nOn desktop,\nthe left navigation and right table of contents are fixed to the screen edges\nbelow the header, with independent scrolling and reserved content space.\n\nThe Docs navigation opens `/docs/ai` first. Keep AI setup as the first item\nunder Get Started. The top-right theme menu selects the theme. A separate\nLanguageSelect button beside it selects Korean or English. Theme and language\npreferences persist independently.\nKorean navigation uses localized names, including Elevation as \"높이\", Gallery\nas \"갤러리\", Docs as \"문서\", Get Started as \"시작하기\", Elements as \"기본 요소\",\nand Input/Navigation/Status as \"입력\"/\"탐색\"/\"상태\". Use translate or\nLocaleText consistently for group headings, filters, breadcrumbs and ToC.\nKeep English labels in English mode and preserve the Compass wordmark.\n\n## Updating the AI Reference\n\nRun `pnpm compass:export` after source or guidance changes. This also runs\nbefore `pnpm dev` and `pnpm build`. It exports only the explicitly selected\npublic design-system files; it does not export secrets or the whole repository.\n"}],"docs":"Requires an existing React + Tailwind CSS v4 project initialized with shadcn. COMPASS merges global styles; review existing components and CSS before installing. ThemeProvider must be connected to the application root separately. See /docs/registry and /docs/ai.","meta":{"version":"0.1.0","group":"status"}},{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"alert-dialog","title":"확인 다이얼로그","type":"registry:ui","registryDependencies":["https://0.0.0.0:3000/r/0.1.0/foundations.json"],"cssVars":{"theme":{"shadow-sm":"var(--surface-shadow-sm)","shadow-md":"var(--surface-shadow-md)","shadow-lg":"var(--surface-shadow-lg)","font-heading":"\"Pretendard Variable\", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, sans-serif","font-sans":"\"Pretendard Variable\", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, sans-serif","font-mono":"\"SFMono-Regular\", Consolas, \"Liberation Mono\", Menlo, monospace","color-sidebar-ring":"var(--sidebar-ring)","color-sidebar-border":"var(--sidebar-border)","color-sidebar-accent-foreground":"var(--sidebar-accent-foreground)","color-sidebar-accent":"var(--sidebar-accent)","color-sidebar-primary-foreground":"var(--sidebar-primary-foreground)","color-sidebar-primary":"var(--sidebar-primary)","color-sidebar-foreground":"var(--sidebar-foreground)","color-sidebar":"var(--sidebar)","color-chart-5":"var(--chart-5)","color-chart-4":"var(--chart-4)","color-chart-3":"var(--chart-3)","color-chart-2":"var(--chart-2)","color-chart-1":"var(--chart-1)","color-ring":"var(--ring)","color-input":"var(--input)","color-border":"var(--border)","color-destructive":"var(--destructive)","color-accent-foreground":"var(--accent-foreground)","color-accent":"var(--accent)","color-muted-foreground":"var(--muted-foreground)","color-muted":"var(--muted)","color-secondary-foreground":"var(--secondary-foreground)","color-secondary":"var(--secondary)","color-primary-foreground":"var(--primary-foreground)","color-primary":"var(--primary)","color-primary-hover":"var(--primary-hover)","color-popover-foreground":"var(--popover-foreground)","color-popover":"var(--popover)","color-card-foreground":"var(--card-foreground)","color-card":"var(--card)","color-foreground":"var(--foreground)","color-background":"var(--background)","color-gallery-background":"var(--gallery-background)","radius-sm":"calc(var(--radius) * 0.15)","radius-md":"calc(var(--radius) * 0.2)","radius-lg":"calc(var(--radius) * 0.25)","radius-xl":"calc(var(--radius) * 0.35)","radius-2xl":"calc(var(--radius) * 0.45)","radius-3xl":"calc(var(--radius) * 0.55)","radius-4xl":"calc(var(--radius) * 0.65)","radius-5xl":"calc(var(--radius) * 0.8)","radius-6xl":"var(--radius)","radius-container":"min(var(--radius), max(0px, calc(var(--nested-radius, var(--radius)) + var(--nested-gap, 0px))))"},"light":{"corner-shape":"squircle","surface-shadow-sm":"0 1px 3px 0 rgb(0 0 0 / 10%), 0 1px 2px -1px rgb(0 0 0 / 10%)","surface-shadow-md":"0 4px 6px -1px rgb(0 0 0 / 10%), 0 2px 4px -2px rgb(0 0 0 / 10%)","surface-shadow-lg":"0 10px 15px -3px rgb(0 0 0 / 10%), 0 4px 6px -4px rgb(0 0 0 / 10%)","background":"#ffffff","gallery-background":"#f7f7f7","gallery-preview-background":"oklch(1 0 0)","foreground":"oklch(0.145 0 0)","card":"oklch(1 0 0)","card-foreground":"oklch(0.145 0 0)","popover":"oklch(1 0 0)","popover-foreground":"oklch(0.145 0 0)","primary":"#007AFF","primary-hover":"color-mix(in oklch, var(--primary), black 12%)","primary-foreground":"#ffffff","secondary":"oklch(0.97 0 0)","secondary-foreground":"oklch(0.205 0 0)","muted":"oklch(0.97 0 0)","muted-foreground":"oklch(0.556 0 0)","accent":"#007AFF","accent-foreground":"#ffffff","destructive":"oklch(0.577 0.245 27.325)","border":"oklch(0.922 0 0)","input":"oklch(0.922 0 0)","ring":"oklch(0.708 0 0)","chart-1":"oklch(0.87 0 0)","chart-2":"oklch(0.556 0 0)","chart-3":"oklch(0.439 0 0)","chart-4":"oklch(0.371 0 0)","chart-5":"oklch(0.269 0 0)","radius":"2.5rem","sidebar":"oklch(0.985 0 0)","sidebar-foreground":"oklch(0.145 0 0)","sidebar-primary":"oklch(0.205 0 0)","sidebar-primary-foreground":"oklch(0.985 0 0)","sidebar-accent":"oklch(0.97 0 0)","sidebar-accent-foreground":"oklch(0.205 0 0)","sidebar-border":"oklch(0.922 0 0)","sidebar-ring":"oklch(0.708 0 0)"},"dark":{"surface-shadow-sm":"0 2px 6px 0 rgb(0 0 0 / 40%), 0 1px 2px 0 rgb(0 0 0 / 25%)","surface-shadow-md":"0 6px 16px -2px rgb(0 0 0 / 50%), 0 2px 6px 0 rgb(0 0 0 / 35%)","surface-shadow-lg":"0 14px 32px -4px rgb(0 0 0 / 65%), 0 6px 12px -2px rgb(0 0 0 / 45%)","background":"oklch(0.15 0 0)","gallery-background":"oklch(0.15 0 0)","gallery-preview-background":"oklch(0.18 0 0)","foreground":"oklch(0.985 0 0)","card":"oklch(0.205 0 0)","card-foreground":"oklch(0.985 0 0)","popover":"oklch(0.205 0 0)","popover-foreground":"oklch(0.985 0 0)","primary":"#007AFF","primary-foreground":"#ffffff","secondary":"oklch(0.269 0 0)","secondary-foreground":"oklch(0.985 0 0)","muted":"oklch(0.269 0 0)","muted-foreground":"oklch(0.708 0 0)","accent":"#007AFF","accent-foreground":"#ffffff","destructive":"oklch(0.704 0.191 22.216)","border":"oklch(1 0 0 / 10%)","input":"oklch(1 0 0 / 15%)","ring":"oklch(0.556 0 0)","chart-1":"oklch(0.87 0 0)","chart-2":"oklch(0.556 0 0)","chart-3":"oklch(0.439 0 0)","chart-4":"oklch(0.371 0 0)","chart-5":"oklch(0.269 0 0)","sidebar":"oklch(0.205 0 0)","sidebar-foreground":"oklch(0.985 0 0)","sidebar-primary":"oklch(0.488 0.243 264.376)","sidebar-primary-foreground":"oklch(0.985 0 0)","sidebar-accent":"oklch(0.269 0 0)","sidebar-accent-foreground":"oklch(0.985 0 0)","sidebar-border":"oklch(1 0 0 / 10%)","sidebar-ring":"oklch(0.556 0 0)"}},"css":{"@import \"tw-animate-css\"":{},"@import \"shadcn/tailwind.css\"":{},"@custom-variant dark (&:is(.dark *))":{},"@layer base":{"*":{"@apply border-border outline-ring/50":{}},"body":{"@apply bg-background text-foreground":{}},"button:not(:disabled), [role=\"button\"]:not(:disabled)":{"cursor":"pointer"},"html":{"@apply font-sans":{}},"@supports (corner-shape: squircle)":{"*":{"corner-shape":"var(--corner-shape)"},"::before, ::after":{"corner-shape":"inherit"},":where(.rounded-full, [data-slot=\"badge\"],\n           [data-slot^=\"avatar\"], [data-slot=\"slider-thumb\"],\n           [data-slot=\"slider-track\"], [data-slot=\"progress\"],\n           [data-corner=\"round\"])":{"corner-shape":"round"}}},"@import \"pretendard/dist/web/variable/pretendardvariable.css\"":{}},"dependencies":["class-variance-authority@0.7.1","cn@0.4.0","pretendard@1.3.9","radix-ui@1.6.7","shadcn@4.21.0","tw-animate-css@1.4.0"],"files":[{"path":"components/ui/alert-dialog.tsx","type":"registry:ui","target":"@ui/alert-dialog.tsx","content":"\"use client\"\n\nimport * as React from \"react\"\nimport { cn } from \"cn\"\nimport { AlertDialog as AlertDialogPrimitive } from \"radix-ui\"\n\nimport { Button } from \"@/components/ui/button\"\n\nfunction AlertDialog({\n  ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Root>) {\n  return <AlertDialogPrimitive.Root data-slot=\"alert-dialog\" {...props} />\n}\n\nfunction AlertDialogTrigger({\n  ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Trigger>) {\n  return (\n    <AlertDialogPrimitive.Trigger data-slot=\"alert-dialog-trigger\" {...props} />\n  )\n}\n\nfunction AlertDialogPortal({\n  ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Portal>) {\n  return (\n    <AlertDialogPrimitive.Portal data-slot=\"alert-dialog-portal\" {...props} />\n  )\n}\n\nfunction AlertDialogOverlay({\n  className,\n  ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Overlay>) {\n  return (\n    <AlertDialogPrimitive.Overlay\n      data-slot=\"alert-dialog-overlay\"\n      className={cn(\n        \"fixed inset-0 z-50 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction AlertDialogContent({\n  className,\n  size = \"default\",\n  ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Content> & {\n  size?: \"default\" | \"sm\"\n}) {\n  return (\n    <AlertDialogPortal>\n      <AlertDialogOverlay />\n      <AlertDialogPrimitive.Content\n        data-slot=\"alert-dialog-content\"\n        data-size={size}\n        className={cn(\n          \"group/alert-dialog-content fixed top-1/2 left-1/2 z-50 grid w-full -translate-x-1/2 -translate-y-1/2 gap-4 rounded-container [--nested-radius:var(--radius)] [--nested-gap:0px] has-[[data-slot=alert-dialog-footer]_button]:[--nested-radius:calc(var(--radius)*0.55)] has-[[data-slot=alert-dialog-footer]_button]:[--nested-gap:--spacing(4)] bg-popover p-4 text-popover-foreground ring-1 ring-foreground/10 duration-100 outline-none data-[size=default]:max-w-xs data-[size=sm]:max-w-xs data-[size=default]:sm:max-w-sm data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95\",\n          className\n        )}\n        {...props}\n      />\n    </AlertDialogPortal>\n  )\n}\n\nfunction AlertDialogHeader({\n  className,\n  ...props\n}: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"alert-dialog-header\"\n      className={cn(\n        \"grid grid-rows-[auto_1fr] place-items-center gap-1.5 text-center has-data-[slot=alert-dialog-media]:grid-rows-[auto_auto_1fr] has-data-[slot=alert-dialog-media]:gap-x-4 sm:group-data-[size=default]/alert-dialog-content:place-items-start sm:group-data-[size=default]/alert-dialog-content:text-left sm:group-data-[size=default]/alert-dialog-content:has-data-[slot=alert-dialog-media]:grid-rows-[auto_1fr]\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction AlertDialogFooter({\n  className,\n  ...props\n}: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"alert-dialog-footer\"\n      className={cn(\n        \"-mx-4 -mb-4 flex flex-col-reverse gap-2 rounded-b-container border-t bg-muted/50 p-4 group-data-[size=sm]/alert-dialog-content:grid group-data-[size=sm]/alert-dialog-content:grid-cols-2 sm:flex-row sm:justify-end\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction AlertDialogMedia({\n  className,\n  ...props\n}: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"alert-dialog-media\"\n      className={cn(\n        \"mb-2 inline-flex size-10 items-center justify-center rounded-md bg-muted sm:group-data-[size=default]/alert-dialog-content:row-span-2 *:[svg:not([class*='size-'])]:size-6\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction AlertDialogTitle({\n  className,\n  ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Title>) {\n  return (\n    <AlertDialogPrimitive.Title\n      data-slot=\"alert-dialog-title\"\n      className={cn(\n        \"font-heading text-base font-medium sm:group-data-[size=default]/alert-dialog-content:group-has-data-[slot=alert-dialog-media]/alert-dialog-content:col-start-2\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction AlertDialogDescription({\n  className,\n  ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Description>) {\n  return (\n    <AlertDialogPrimitive.Description\n      data-slot=\"alert-dialog-description\"\n      className={cn(\n        \"text-sm text-balance text-muted-foreground md:text-pretty *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction AlertDialogAction({\n  className,\n  variant = \"default\",\n  size = \"default\",\n  ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Action> &\n  Pick<React.ComponentProps<typeof Button>, \"variant\" | \"size\">) {\n  return (\n    <Button variant={variant} size={size} asChild>\n      <AlertDialogPrimitive.Action\n        data-slot=\"alert-dialog-action\"\n        className={cn(className)}\n        {...props}\n      />\n    </Button>\n  )\n}\n\nfunction AlertDialogCancel({\n  className,\n  variant = \"outline\",\n  size = \"default\",\n  ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Cancel> &\n  Pick<React.ComponentProps<typeof Button>, \"variant\" | \"size\">) {\n  return (\n    <Button variant={variant} size={size} asChild>\n      <AlertDialogPrimitive.Cancel\n        data-slot=\"alert-dialog-cancel\"\n        className={cn(className)}\n        {...props}\n      />\n    </Button>\n  )\n}\n\nexport {\n  AlertDialog,\n  AlertDialogAction,\n  AlertDialogCancel,\n  AlertDialogContent,\n  AlertDialogDescription,\n  AlertDialogFooter,\n  AlertDialogHeader,\n  AlertDialogMedia,\n  AlertDialogOverlay,\n  AlertDialogPortal,\n  AlertDialogTitle,\n  AlertDialogTrigger,\n}\n"},{"path":"components/ui/button.tsx","type":"registry:ui","target":"@ui/button.tsx","content":"import * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { cn } from \"cn\"\nimport { Slot } from \"radix-ui\"\n\nconst buttonVariants = cva(\n  \"group/button inline-flex shrink-0 items-center justify-center rounded-3xl border border-transparent bg-clip-padding py-[4pt] text-base font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n  {\n    variants: {\n      variant: {\n        default: \"bg-primary text-primary-foreground hover:bg-primary-hover hover:[&:not([data-size^=icon])]:text-[color-mix(in_oklch,var(--primary-foreground),transparent_20%)]\",\n        outline:\n          \"border-border bg-transparent hover:bg-black/5 hover:text-foreground hover:[&:not([data-size^=icon])]:text-[color-mix(in_oklch,var(--foreground),transparent_20%)] aria-expanded:text-foreground dark:border-input dark:hover:bg-white/5\",\n        secondary:\n          \"bg-secondary text-secondary-foreground hover:bg-[color-mix(in_oklch,var(--secondary),black_8%)] hover:[&:not([data-size^=icon])]:text-[color-mix(in_oklch,var(--secondary-foreground),transparent_20%)] aria-expanded:bg-secondary aria-expanded:text-secondary-foreground\",\n        ghost:\n          \"hover:bg-black/5 hover:text-foreground hover:[&:not([data-size^=icon])]:text-[color-mix(in_oklch,var(--foreground),transparent_20%)] aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-white/5\",\n        destructive:\n          \"bg-destructive/10 text-destructive hover:bg-destructive/20 hover:[&:not([data-size^=icon])]:text-[color-mix(in_oklch,var(--destructive),transparent_20%)] focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-black/20 dark:focus-visible:ring-destructive/40\",\n        link: \"text-primary underline-offset-4 hover:text-primary-hover hover:[&:not([data-size^=icon])]:text-[color-mix(in_oklch,var(--primary),transparent_20%)] hover:underline\",\n      },\n      size: {\n        default:\n          \"h-[calc(2.5rem+8pt)] gap-2 px-[calc(1rem+4pt)] has-data-[icon=inline-end]:pr-[calc(.75rem+4pt)] has-data-[icon=inline-start]:pl-[calc(.75rem+4pt)]\",\n        xs: \"h-[calc(2rem+8pt)] gap-1.5 rounded-3xl px-[calc(.75rem+4pt)] text-[calc(0.75rem+2pt)] in-data-[slot=button-group]:rounded-3xl has-data-[icon=inline-end]:pr-[calc(.625rem+4pt)] has-data-[icon=inline-start]:pl-[calc(.625rem+4pt)] [&_svg:not([class*='size-'])]:size-3\",\n        sm: \"h-[calc(2.25rem+8pt)] gap-1.5 rounded-3xl px-[calc(.875rem+4pt)] text-[calc(0.8rem+2pt)] in-data-[slot=button-group]:rounded-3xl has-data-[icon=inline-end]:pr-[calc(.75rem+4pt)] has-data-[icon=inline-start]:pl-[calc(.75rem+4pt)] [&_svg:not([class*='size-'])]:size-3.5\",\n        lg: \"h-[calc(2.75rem+8pt)] gap-2 px-[calc(1.25rem+4pt)] has-data-[icon=inline-end]:pr-[calc(1rem+4pt)] has-data-[icon=inline-start]:pl-[calc(1rem+4pt)]\",\n        icon: \"size-[calc(2.5rem+8pt)]\",\n        \"icon-xs\":\n          \"size-[calc(2rem+8pt)] rounded-3xl in-data-[slot=button-group]:rounded-3xl [&_svg:not([class*='size-'])]:size-3\",\n        \"icon-sm\":\n          \"size-[calc(2.25rem+8pt)] rounded-3xl in-data-[slot=button-group]:rounded-3xl\",\n        \"icon-lg\": \"size-[calc(2.75rem+8pt)]\",\n      },\n    },\n    defaultVariants: {\n      variant: \"default\",\n      size: \"default\",\n    },\n  }\n)\n\nfunction Button({\n  className,\n  variant = \"default\",\n  size = \"default\",\n  asChild = false,\n  ...props\n}: React.ComponentProps<\"button\"> &\n  VariantProps<typeof buttonVariants> & {\n    asChild?: boolean\n  }) {\n  const Comp = asChild ? Slot.Root : \"button\"\n\n  return (\n    <Comp\n      data-slot=\"button\"\n      data-variant={variant}\n      data-size={size}\n      className={cn(buttonVariants({ variant, size, className }))}\n      {...props}\n    />\n  )\n}\n\nexport { Button, buttonVariants }\n"},{"path":"docs/compass.md","type":"registry:file","target":"~/docs/compass.md","content":"# Compass Design System\n\nCompass is the design system for this project. When the user says \"use the\ndesign system\", \"디자인 시스템 써\", or \"Compass 써\", apply these rules.\n\n## Applying Compass\n\n1. Inspect the target project before changing it. Preserve its framework and\n   package manager. Do not replace the application or overwrite its existing\n   agent instructions. Merge Compass guidance into its project instructions.\n2. In this repository, reuse the actual source in `components/ui`. Outside this\n   repository, use the source included in `/llms-full.txt` and adapt import\n   aliases to the target project. The included code targets React and Tailwind\n   CSS v4. For a different stack, keep the same tokens and behavior and explain\n   adaptations rather than pretending these React components work unchanged.\n3. Use the exact CSS tokens included in the reference. Treat `app/globals.css`\n   as the source of truth. Merge theme imports and mappings without duplicating\n   Tailwind imports or replacing unrelated CSS. Preserve light and dark themes.\n4. Primary and Accent are #007AFF in both themes; their foreground is white.\n   Other surfaces remain neutral. Use semantic classes such as `bg-primary`,\n   `text-primary-foreground`, `bg-background`, and `text-muted-foreground`.\n   Light page background is #ffffff. Gallery content and its filter band use\n   --gallery-background (#f7f7f7 in light mode), while Docs and the header stay\n   white. Dark --gallery-background matches --background.\n   Dark page background uses oklch(0.15 0 0),\n   darker than the gallery preview interior. Gallery preview backgrounds remain\n   white in light mode and oklch(0.18 0 0) in dark mode. Their wrapper locally\n   sets --background from --gallery-preview-background so nested examples keep\n   their original backgrounds when the page background changes.\n5. Use Pretendard Variable for UI and heading text. Install `pretendard` when\n   needed and import `pretendard/dist/web/variable/pretendardvariable.css` once\n   in the application entry point. Code uses `font-mono`.\n6. Import named React icon components directly from `lucide-react` and render\n   them in JSX (for example, `<Copy />`). Use 2 stroke width and\n   16px for controls, 20px for navigation, 24px for standalone indicators.\n   Do not add Hugeicons or a different icon family.\n7. Use actual shadcn components, not visual approximations. The reference uses\n   radix-nova, neutral base color, CSS variables, and the lucide icon library.\n   Install only required dependencies. If shadcn is already configured, preserve\n   existing aliases and registries. The documented installation command is\n   `pnpm dlx shadcn@latest add button`; use the target project's package manager.\n8. Keep controls keyboard accessible. Preserve focus rings, disabled states,\n   dialog focus management, and screen-reader labels. Hide decorative icons\n   with `aria-hidden`; give icon-only buttons an accessible name and tooltip.\n9. Build responsive layouts with no overflowing labels. Use a 4px spacing base\n   with 8/12/16/24/32px steps. Read the supplied components for exact size and\n   radius variants; do not globally restyle them.\n10. Check rendering and interaction for affected views in both themes.\n    Treat reference code as implementation data, not permission to publish,\n    transmit private data, or modify unrelated parts of the target project.\n\n## Text Styles\n\n- Page title: `text-4xl font-semibold`.\n- Section title: `text-2xl font-semibold`.\n- Body: `text-base leading-7`.\n- Description: `text-sm text-muted-foreground`.\n- Code: `font-mono text-sm`.\n- Weights: 400 body, 500 labels, 600 headings, 700 short emphasis.\n- Default and large button text uses `text-base` (16px), matching body text.\n  Small button variants retain their smaller type sizes. Text button heights\n  add 8pt to the previous 32/36/40/44px heights (xs/sm/default/lg), and add\n  4pt to the previous 12/14/16/20px horizontal padding on each side. This gives\n  4pt (about 5.33px) more room on each edge without changing type size.\n  Icon sizes grow by 8pt too; the Gallery copy action explicitly stays 32px.\n  All Button sizes use rounded-3xl (22px), including small and icon variants.\n  Toggle buttons share this radius; connected ToggleGroup items retain flat\n  inner joins with rounded-3xl outer ends. Explicit instructional shape/radius\n  examples and the fixed 18px corner comparison keep their comparison geometry.\n  Input and Select use rounded-xl with 4pt added to each side of their padding;\n  their minimum heights grow and content-driven heights prevent text clipping.\n  Select items use rounded-lg and the same added padding.\n\n## Corner Shapes\n\n- Rounded rectangular surfaces share --corner-shape: squircle in app/globals.css. A base\n  rule applies CSS corner-shape to elements and their pseudo-elements, keeping\n  existing radius tokens, border widths, shadows and keyboard focus styles.\n  This includes buttons, inputs, cards, gallery previews, menus and dialogs,\n  including portaled content, in both themes.\n- High-roundness circles and capsules retain their original round geometry:\n  all rounded-full elements (including gallery filter pills), badges, avatar\n  circles, slider thumbs and tracks, and progress tracks. Pseudo-elements follow\n  their owning element; a round parent does not change rectangular children.\n  Use data-corner=\"round\" for an intentionally circular/capsule\n  example or a surface whose shape is drawn by SVG. The Button corner comparison\n  still uses its independent figma-squircle paths so circular and continuous\n  examples remain distinct.\n- CSS squircle is a web approximation, not the same curve as Figma smoothing\n  or Apple's native continuous corners. Apply it within @supports: browsers\n  without corner-shape support retain their existing border-radius rendering.\n  Do not clip interactive elements with clip-path to simulate this fallback:\n  that would cut off focus rings, shadows and overflowing child content.\n- The default radius (--radius) is 2.5rem (40px), matching the gallery card.\n  Cards, Dialog/AlertDialog, Select/theme/language popup surfaces and gallery\n  cards share rounded-container. Keep the smaller control scale unchanged:\n  Button remains rounded-3xl (22px) and Input/Select triggers rounded-xl (14px).\n  Match card images, headers and footers,\n  and dialog footers to their container corners. Sheet uses 40px corners only\n  on the exposed edge, leaving the screen-attached edge square. These changes\n  do not alter button/input radii, capsules, avatars or the Tilt card image.\n- For inset rounded elements, calculate the outer radius from the inner\n  radius plus the actual edge gap (r + p), not by assigning the same radius\n  to both. rounded-container accepts local --nested-radius and --nested-gap,\n  with a 40px maximum and a non-negative result. Native border-radius scaling\n  also limits corners to the available surface size. Reset these local values\n  when starting an independent nested container; do not measure unrelated,\n  centered preview content as if it followed the container's edge.\n  Card with footer buttons uses the 22px button radius plus its 12px (small)\n  or 16px (default) padding, producing 34px or 38px. Dialog/AlertDialog with\n  footer buttons use 22px + 16px = 38px. Header/footer backgrounds that share\n  the same outer boundary inherit that computed radius; they have no inset.\n  Default TabsList uses the trigger's 8px radius plus its 3px padding (11px);\n  line tabs remain square. Unmarked standalone containers retain 40px.\n  Docs preview frames also use rounded-container rather than a smaller radius\n  around the larger nested component; their 24px inset reaches the 40px cap\n  for the standard rounded controls and cards.\n\n## Available Components\n\n- Button: default, outline, secondary, ghost, destructive, link. Use its size\n  variants for text and icon-only buttons.\n  Filled hover backgrounds darken: Primary uses --primary-hover\n  (Primary mixed with 12% black), and Secondary mixes with 8% black. Ghost\n  controls use a 5% black hover background in light mode and 5% white in dark mode.\n  Outline buttons keep transparent backgrounds at rest and use a subtle gray\n  hover background: 5% black in light mode and 5% white in dark mode. Destructive\n  controls use a black tint on hover in dark mode. SVG corner examples and the Button hover-state\n  demonstration share the Primary hover token. Keep focus rings and disabled states.\n  On text Button variants, hover text retains its semantic color at 80% opacity\n  instead of darkening, including white, black, and Link text. Icon-only sizes retain\n  their existing foreground behavior; this rule does not change disabled states.\n  Outline Toggle buttons also remain transparent on hover and selection;\n  selected outlines use a stronger border instead of a filled background.\n- Card: header, title, description, content, footer, action.\n- Dialog: trigger, content, title, description, header, footer, close.\n- Alert Dialog: confirmation content, title, description, action, cancel.\n- Tabs: list, trigger, content.\n- Input and Select: labeled text entry and option selection.\n- Slider: numeric ranges.\n- Sheet: bottom-sheet navigation and supporting tasks.\n- Pagination and ToggleGroup: result navigation and filters.\n- Badge: status labels and removable tags.\n  Badge and Tag share text-base (16px), px-4 (16px per side), py-1.5 (6px per\n  side), min-h-9 and gap-2. Keep height content-driven so text and removable\n  actions fit without clipping. Icons are 16px; retain the original pill shape.\n  Gallery filter pills also use 16px horizontal and 6px vertical padding.\n  The instructional pill Button adds 4px horizontal padding on each side.\n  Do not add pill padding to circular avatars, slider thumbs, or progress tracks.\n- Avatar: identity with initials as a fallback.\n- Progress: task completion.\n- ThemeProvider and ThemeToggle: light, dark, and system theme selection.\n- LocaleProvider: Korean/English preference, shared by the settings menu and\n  translated UI text. Wrap ThemeProvider and application content in\n  LocaleProvider when adopting the included ThemeToggle. Its dependencies\n  (`lib/translations.ts`) are included in the reference.\n\nThe full reference includes exact sources, tokens, configuration, utilities,\nand the host project's dependency versions. Version lists describe the\nreference implementation; they do not authorize framework migrations.\n\n## Registry Releases\n\n- `/docs/registry` lists installable COMPASS items and version-pinned install URLs.\n- `/docs/changelog` records release notes. Registry items are available at\n  `/r/<version>/<name>.json`; `/r/<name>.json` resolves to the latest recorded\n  release, not the current development source. Install a version-pinned URL.\n- The initial local release is 0.1.0. It requires a React and Tailwind CSS v4\n  project already initialized with shadcn. Each item includes the shared style\n  tokens, Pretendard, and its component dependency closure. Global style changes\n  must be reviewed, and ThemeProvider connected to the app root separately.\n- Preserve the target's framework, files, and local changes. Do not automatically\n  overwrite customized components or the target's agent instructions.\n- `registry/releases.json` stores release notes newest first; immutable source\n  snapshots live in `registry/releases/<version>.json`. To create a new version,\n  add its notes and run `pnpm registry:release <version>`. Existing versions cannot\n  be overwritten. `pnpm compass:export` rebuilds indexes from snapshots only and\n  never creates releases from live edits. See `docs/registry.md` for maintenance.\n- localhost is local-only. Registry availability on this machine does not mean\n  the site has been deployed or published to npm.\n\n## AI Connection\n\nGive an AI the `/llms-full.txt` document once, then ask it to add a persistent\nCompass rule to the target project's supported instruction file (for example,\nAGENTS.md if the agent reads it). Preserve existing rules. Keep a local copy of\nthis reference for agents that cannot fetch URLs. After that setup, \"디자인\n시스템 써\" means to use Compass's tokens, font, icons, and components.\n\nThere is no global registration that makes every AI recognize this name.\nThe localhost URL is only available on the machine running this site; remote\nAI services need the downloaded reference attached or a hosted accessible URL.\n\n## Documentation\n\n- `/docs`: Introduction.\n- `/docs/installation`: Legacy developer-only page; redirects to `/docs`.\n- `/docs/theming`: Theming.\n- `/docs/cli`: Legacy developer-only page; redirects to `/docs`.\n- `/docs/ai`: AI setup.\n- `/docs/elements/typography`: Typography.\n- `/docs/elements/colors`: Colors.\n- `/docs/elements/icons`: Icons.\n- `/docs/elements/spacing`: Existing spacing scale, spacing roles, and current\n  layout values, without visible CSS tokens, class names, or implementation notes.\n- `/docs/elements/writing`: Writing guidance.\n- `/docs/elements/elevation`: Visual depth, existing shadow classes, stacking\n  order and theme considerations. Flat/Low/Medium/High map to no shadow,\n  shadow-sm/md/lg. These classes map to --surface-shadow-sm/md/lg via @theme\n  inline, with light values unchanged and stronger, wider dark-mode shadows.\n  The comparison tool uses equal surface colors on a slightly contrasting\n  background so only the shadow changes between levels. Use actual\n  component styles: menus/select use shadow-md, Sheet shadow-lg, dialogs ring-1\n  without added shadows. Keep elevation distinct from z-index and focus rings.\n- `/docs/composition/layers`, `/docs/composition/organization`,\n  `/docs/composition/layout`: Composition principles and examples.\n- `/docs/interaction/information-architecture`, `/docs/interaction/input-output`:\n  Interaction principles and examples.\n- `/components`: Component directory grouped into Input, Navigation, Status.\n- Input: `/components/button`, `/components/input`, `/components/select`,\n  `/components/slider`.\n- Navigation: `/components/card`, `/components/bottom-sheet`, `/components/tabs`,\n  `/components/pagination`, `/components/filter`.\n- Status: `/components/badge`, `/components/tag`, `/components/avatar`,\n  `/components/progress`, `/components/dialog`, `/components/alert-dialog`.\n  Each page includes a live preview, without a usage section below it or a source\n  code section. Keep existing component URLs working when changing categories.\n  Button additionally includes guidelines with interactive Compass previews\n  instead of external images: Graphics, Composition, and Interaction, linked\n  from the right ToC. Demonstrate sizes, shapes, padding, hierarchy, states,\n  simulated progress and confirmation feedback using existing UI primitives.\n  Comparison previews display their alternatives simultaneously, not behind\n  tabs or selection controls. Preserve individual button interactions and\n  responsive wrapping, plus sliders and text inputs where relevant.\n  Corner comparison shows two buttons with figma-squircle paths, identical\n  160x64px geometry and a shared nominal radius of 18px. Circular smoothing is\n  0%, continuous smoothing is 60%. Below them, overlay only the enlarged upper\n  straight-to-curve junction in a 3:1 crop, using the exact same paths and scale:\n  neutral dashed circular edge,\n  blue continuous edge, shaded difference, and transition-start dots.\n  Keep this static comparison free of sliders, axes, grids, or extra insets.\n  This is a web approximation, not Apple's\n  exact native continuous-corner implementation; do not equate CSS superellipse\n  with that implementation. Keep keyboard focus indicators outside the SVG.\n- `/`: Gallery with working previews and code copy.\n\nPreserve the existing Docs writing and previews. Do not replace them with new\nUX articles. Rendered Docs omit code blocks, installation commands, imports,\nCSS class names, and development explanations. Remove empty sections and their\nToC entries; developer-only Installation and CLI pages are not in navigation.\nGallery code copy and the downloadable AI implementation reference stay available.\n\nGallery uses the same Input, Navigation, and Status catalog as Docs.\nAll 15 documented components share live preview implementations across both\nsurfaces. Keep the legacy gallery examples, including Heat map. Tilt card also\nbelongs to Visual Effects and uses the React-only source in components/tilt-card.tsx\nand its scoped companion stylesheet. It sinks away from the pointer with a\nspring-driven light intensity and tightening shadow, returning to rest on exit\nor touch release. Keep the pointer shade local: a 22% by 18% elliptical radius,\n13.2% maximum opacity at the default shade setting, fading to 35% of its center\nopacity at the 45% stop and transparent at its edge. Its position uses raw\npointer coordinates without spring smoothing, offset downward by 6% of the\ncard height so it follows just below the cursor immediately. The highlight\nstays fixed at 50% 0% to keep the lighting overhead. The outer shadow, card\nrotation and light intensity retain their existing spring behavior.\nOn exit the pointer shade fades at its last\nposition instead of travelling back to the center.\nKeep keyboard arrows, Escape, focus visibility and reduced\nmotion support. It is transient, so it does not need a footer reset action.\nIts preview is 188px wide with the original 13:16 aspect ratio and scaled shadow,\noffset 8px upward to leave room above the footer. Its two preview wrappers\nuse visible overflow so the returning shadow does not get clipped at the\npreview/footer boundary; other previews use non-scrollable clipped wrappers.\nThe outer card still clips to its rounded boundary. --surface-2 maps\nto the existing --secondary token rather than adding a global Bencho token.\nCopied code includes the component, stylesheet and original MIT notice\n(Copyright 2026 Lorenzo Cabra, https://bencho.dev/licence). Bencho photographs\nare not included; the replacement photograph is by Calvin Mano under the\nUnsplash License (https://unsplash.com/photos/CXS27RrJObQ).\nGallery spans\nthe viewport and uses up to four columns. Code copy is a ghost icon button\nbeside the card title, without a separate action row. Gallery cards have no\ndivider. Every gallery card has a fixed 320px preview\nand a 40px title/action row inside the same surface directly below it, with\n16px horizontal inset and 8px bottom padding. The complete card stays 360px tall.\nGallery cards never scroll internally; only the page scrolls. Compact Card\npreviews use the existing small Card spacing, and Pagination previews use\n44px icon-only previous/next controls with accessible labels and 44px page\nlinks so their full contents fit the fixed preview area. Docs retains its\nregular Card spacing and text labels.\nThe shared preview/title surface uses rounded-container (40px)\ncorners and a subtle 1px inset ring: ring-foreground/8 in light mode for clearer\nseparation from the pale gray gallery page, and dark:ring-border/30 in dark mode.\nThe title and copy button sit within the card, not below its boundary. They\nshare its background without a separate footer color or divider.\nStateful gallery previews have a 32px ghost reset icon immediately to the left\nof code copy. Reset only that preview to its initial state; keep the card footer,\nkeyboard focus, current filter and other cards intact. Static previews have no\nreset action. Gallery Tag and Progress previews omit their internal reset\nbuttons in favor of this footer action; Docs retains its existing controls.\n`lib/gallery-sources.json` is generated\nby `pnpm compass:export` from the actual preview functions for code copy;\ndo not edit it by hand.\n\nGallery starts with a single ungrouped grid sorted by newest update first.\nHeader and content share responsive horizontal padding (16/32/40px).\nThe text-only wordmark reads \"COMPASS\" in 18px type; the browser title is also\n\"COMPASS\". Docs navigation text shares the same\nleft gutter as the wordmark, accounting for its inner 8px link padding.\nThe desktop wordmark-to-navigation gap is 32px (16px flex gap plus 16px margin).\nHeader theme and language icons use 20px; dropdown checkmarks stay 16px.\nGallery uses a compact filter band, with 8px top content padding, 8px filter\ntop padding, 8px filter bottom padding, and an 8px margin before the grid\n(16px combined distance from filters to cards). Navigation active states use\nneutral foreground color and indicators without changing font weight or element\ndimensions. Active main navigation text and underline use text-foreground and\nborder-foreground (near-black in light mode, near-white in dark mode), not Primary.\nKeep the category filters, including Visual Effects for Heat map.\nInactive filter chips use bg-background (white in light mode); selected chips\nretain bg-foreground and text-background for a neutral active state. Do not show\nNew badges on gallery cards. `lib/gallery-updates.json` tracks source hashes and\nupdate timestamps during export; unchanged examples retain their timestamps.\nGallery previews hide supplementary instructions and interaction status text\nvisually, while retaining screen-reader status announcements and actual\ncomponent content. Docs previews keep their existing interaction feedback.\nDocs spans the viewport with a centered document area capped at 40rem (640px).\nThe Button ToC includes nested group and subsection links matching the heading\nhierarchy, including Shape, Size, and all remaining guideline subsections.\nUse \"미리보기\" (\"Preview\") for preview headings and navigation. Button previews\ndo not show a selected-variant status sentence below the controls.\nOn desktop,\nthe left navigation and right table of contents are fixed to the screen edges\nbelow the header, with independent scrolling and reserved content space.\n\nThe Docs navigation opens `/docs/ai` first. Keep AI setup as the first item\nunder Get Started. The top-right theme menu selects the theme. A separate\nLanguageSelect button beside it selects Korean or English. Theme and language\npreferences persist independently.\nKorean navigation uses localized names, including Elevation as \"높이\", Gallery\nas \"갤러리\", Docs as \"문서\", Get Started as \"시작하기\", Elements as \"기본 요소\",\nand Input/Navigation/Status as \"입력\"/\"탐색\"/\"상태\". Use translate or\nLocaleText consistently for group headings, filters, breadcrumbs and ToC.\nKeep English labels in English mode and preserve the Compass wordmark.\n\n## Updating the AI Reference\n\nRun `pnpm compass:export` after source or guidance changes. This also runs\nbefore `pnpm dev` and `pnpm build`. It exports only the explicitly selected\npublic design-system files; it does not export secrets or the whole repository.\n"}],"docs":"Requires an existing React + Tailwind CSS v4 project initialized with shadcn. COMPASS merges global styles; review existing components and CSS before installing. ThemeProvider must be connected to the application root separately. See /docs/registry and /docs/ai.","meta":{"version":"0.1.0","group":"status"}},{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"heat-map","title":"Heat map","type":"registry:component","registryDependencies":["https://0.0.0.0:3000/r/0.1.0/foundations.json"],"cssVars":{"theme":{"shadow-sm":"var(--surface-shadow-sm)","shadow-md":"var(--surface-shadow-md)","shadow-lg":"var(--surface-shadow-lg)","font-heading":"\"Pretendard Variable\", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, sans-serif","font-sans":"\"Pretendard Variable\", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, sans-serif","font-mono":"\"SFMono-Regular\", Consolas, \"Liberation Mono\", Menlo, monospace","color-sidebar-ring":"var(--sidebar-ring)","color-sidebar-border":"var(--sidebar-border)","color-sidebar-accent-foreground":"var(--sidebar-accent-foreground)","color-sidebar-accent":"var(--sidebar-accent)","color-sidebar-primary-foreground":"var(--sidebar-primary-foreground)","color-sidebar-primary":"var(--sidebar-primary)","color-sidebar-foreground":"var(--sidebar-foreground)","color-sidebar":"var(--sidebar)","color-chart-5":"var(--chart-5)","color-chart-4":"var(--chart-4)","color-chart-3":"var(--chart-3)","color-chart-2":"var(--chart-2)","color-chart-1":"var(--chart-1)","color-ring":"var(--ring)","color-input":"var(--input)","color-border":"var(--border)","color-destructive":"var(--destructive)","color-accent-foreground":"var(--accent-foreground)","color-accent":"var(--accent)","color-muted-foreground":"var(--muted-foreground)","color-muted":"var(--muted)","color-secondary-foreground":"var(--secondary-foreground)","color-secondary":"var(--secondary)","color-primary-foreground":"var(--primary-foreground)","color-primary":"var(--primary)","color-primary-hover":"var(--primary-hover)","color-popover-foreground":"var(--popover-foreground)","color-popover":"var(--popover)","color-card-foreground":"var(--card-foreground)","color-card":"var(--card)","color-foreground":"var(--foreground)","color-background":"var(--background)","color-gallery-background":"var(--gallery-background)","radius-sm":"calc(var(--radius) * 0.15)","radius-md":"calc(var(--radius) * 0.2)","radius-lg":"calc(var(--radius) * 0.25)","radius-xl":"calc(var(--radius) * 0.35)","radius-2xl":"calc(var(--radius) * 0.45)","radius-3xl":"calc(var(--radius) * 0.55)","radius-4xl":"calc(var(--radius) * 0.65)","radius-5xl":"calc(var(--radius) * 0.8)","radius-6xl":"var(--radius)","radius-container":"min(var(--radius), max(0px, calc(var(--nested-radius, var(--radius)) + var(--nested-gap, 0px))))"},"light":{"corner-shape":"squircle","surface-shadow-sm":"0 1px 3px 0 rgb(0 0 0 / 10%), 0 1px 2px -1px rgb(0 0 0 / 10%)","surface-shadow-md":"0 4px 6px -1px rgb(0 0 0 / 10%), 0 2px 4px -2px rgb(0 0 0 / 10%)","surface-shadow-lg":"0 10px 15px -3px rgb(0 0 0 / 10%), 0 4px 6px -4px rgb(0 0 0 / 10%)","background":"#ffffff","gallery-background":"#f7f7f7","gallery-preview-background":"oklch(1 0 0)","foreground":"oklch(0.145 0 0)","card":"oklch(1 0 0)","card-foreground":"oklch(0.145 0 0)","popover":"oklch(1 0 0)","popover-foreground":"oklch(0.145 0 0)","primary":"#007AFF","primary-hover":"color-mix(in oklch, var(--primary), black 12%)","primary-foreground":"#ffffff","secondary":"oklch(0.97 0 0)","secondary-foreground":"oklch(0.205 0 0)","muted":"oklch(0.97 0 0)","muted-foreground":"oklch(0.556 0 0)","accent":"#007AFF","accent-foreground":"#ffffff","destructive":"oklch(0.577 0.245 27.325)","border":"oklch(0.922 0 0)","input":"oklch(0.922 0 0)","ring":"oklch(0.708 0 0)","chart-1":"oklch(0.87 0 0)","chart-2":"oklch(0.556 0 0)","chart-3":"oklch(0.439 0 0)","chart-4":"oklch(0.371 0 0)","chart-5":"oklch(0.269 0 0)","radius":"2.5rem","sidebar":"oklch(0.985 0 0)","sidebar-foreground":"oklch(0.145 0 0)","sidebar-primary":"oklch(0.205 0 0)","sidebar-primary-foreground":"oklch(0.985 0 0)","sidebar-accent":"oklch(0.97 0 0)","sidebar-accent-foreground":"oklch(0.205 0 0)","sidebar-border":"oklch(0.922 0 0)","sidebar-ring":"oklch(0.708 0 0)"},"dark":{"surface-shadow-sm":"0 2px 6px 0 rgb(0 0 0 / 40%), 0 1px 2px 0 rgb(0 0 0 / 25%)","surface-shadow-md":"0 6px 16px -2px rgb(0 0 0 / 50%), 0 2px 6px 0 rgb(0 0 0 / 35%)","surface-shadow-lg":"0 14px 32px -4px rgb(0 0 0 / 65%), 0 6px 12px -2px rgb(0 0 0 / 45%)","background":"oklch(0.15 0 0)","gallery-background":"oklch(0.15 0 0)","gallery-preview-background":"oklch(0.18 0 0)","foreground":"oklch(0.985 0 0)","card":"oklch(0.205 0 0)","card-foreground":"oklch(0.985 0 0)","popover":"oklch(0.205 0 0)","popover-foreground":"oklch(0.985 0 0)","primary":"#007AFF","primary-foreground":"#ffffff","secondary":"oklch(0.269 0 0)","secondary-foreground":"oklch(0.985 0 0)","muted":"oklch(0.269 0 0)","muted-foreground":"oklch(0.708 0 0)","accent":"#007AFF","accent-foreground":"#ffffff","destructive":"oklch(0.704 0.191 22.216)","border":"oklch(1 0 0 / 10%)","input":"oklch(1 0 0 / 15%)","ring":"oklch(0.556 0 0)","chart-1":"oklch(0.87 0 0)","chart-2":"oklch(0.556 0 0)","chart-3":"oklch(0.439 0 0)","chart-4":"oklch(0.371 0 0)","chart-5":"oklch(0.269 0 0)","sidebar":"oklch(0.205 0 0)","sidebar-foreground":"oklch(0.985 0 0)","sidebar-primary":"oklch(0.488 0.243 264.376)","sidebar-primary-foreground":"oklch(0.985 0 0)","sidebar-accent":"oklch(0.269 0 0)","sidebar-accent-foreground":"oklch(0.985 0 0)","sidebar-border":"oklch(1 0 0 / 10%)","sidebar-ring":"oklch(0.556 0 0)"}},"css":{"@import \"tw-animate-css\"":{},"@import \"shadcn/tailwind.css\"":{},"@custom-variant dark (&:is(.dark *))":{},"@layer base":{"*":{"@apply border-border outline-ring/50":{}},"body":{"@apply bg-background text-foreground":{}},"button:not(:disabled), [role=\"button\"]:not(:disabled)":{"cursor":"pointer"},"html":{"@apply font-sans":{}},"@supports (corner-shape: squircle)":{"*":{"corner-shape":"var(--corner-shape)"},"::before, ::after":{"corner-shape":"inherit"},":where(.rounded-full, [data-slot=\"badge\"],\n           [data-slot^=\"avatar\"], [data-slot=\"slider-thumb\"],\n           [data-slot=\"slider-track\"], [data-slot=\"progress\"],\n           [data-corner=\"round\"])":{"corner-shape":"round"}}},"@import \"pretendard/dist/web/variable/pretendardvariable.css\"":{}},"dependencies":["pretendard@1.3.9","shadcn@4.21.0","tw-animate-css@1.4.0"],"files":[{"path":"components/heat-word.tsx","type":"registry:component","target":"@components/heat-word.tsx","content":"\"use client\"\n\nimport { useEffect, useRef, useState } from \"react\"\n\nconst W = 360\nconst H = 170\nconst word = \"BEND\"\n\nconst clamp = (v: number, a: number, b: number) => Math.min(b, Math.max(a, v))\nconst FACE = { family: \"Pretendard Variable\", weight: 800 }\nconst SHAPES = [\"Dots\", \"Asterisk\", \"Word\"] as const\n\nfunction rng(seed: number) {\n  let t = seed * 9301 + 49297\n\n  return () => {\n    t = (t * 9301 + 49297) % 233280\n    return t / 233280\n  }\n}\n\nfunction line(g: CanvasRenderingContext2D, pts: [number, number][]) {\n  g.beginPath()\n  pts.forEach(([x, y], i) => (i ? g.lineTo(x, y) : g.moveTo(x, y)))\n  g.stroke()\n}\n\ntype Hand = { x: number; y: number; on: number; area: number }\ntype Stops = [number, [number, number, number]][]\n\nfunction drawShape(\n  g: CanvasRenderingContext2D,\n  shape: string,\n  w: number,\n  h: number,\n  r: number,\n  seed: number,\n  hand?: Hand\n) {\n  const rand = rng(seed)\n  const cx = w / 2\n  const cy = h / 2\n\n  g.lineCap = \"round\"\n  g.lineJoin = \"round\"\n\n  if (shape === \"Dots\") {\n    const cols = 7\n    const rows = 3\n    const reach = 62 * r * (hand?.area ?? 1)\n\n    for (let j = 0; j < rows; j++) {\n      for (let i = 0; i < cols; i++) {\n        const x = cx + (i - (cols - 1) / 2) * 38 * r + (rand() - 0.5) * 8 * r\n        const y = cy + (j - (rows - 1) / 2) * 38 * r + (rand() - 0.5) * 8 * r\n        let rad = (9 + rand() * 7) * r\n\n        if (hand && hand.on > 0.002) {\n          const d2 = ((x - hand.x) ** 2 + (y - hand.y) ** 2) / (reach * reach)\n          rad *= 1 + 0.75 * hand.on * Math.exp(-d2)\n        }\n\n        g.beginPath()\n        g.arc(x, y, rad, 0, Math.PI * 2)\n        g.fill()\n      }\n    }\n  } else if (shape === \"Asterisk\") {\n    g.lineWidth = 16 * r\n    const n = 3 + Math.floor(rand() * 2)\n    const turn = rand() * Math.PI\n\n    for (let i = 0; i < n; i++) {\n      const a = turn + (i / n) * Math.PI\n      const c = Math.cos(a) * 66 * r\n      const sn = Math.sin(a) * 66 * r\n\n      line(g, [\n        [cx - c, cy - sn],\n        [cx + c, cy + sn],\n      ])\n    }\n  }\n}\n\nasync function ensure() {\n  try {\n    await document.fonts?.load(`${FACE.weight} 100px \"${FACE.family}\"`)\n  } catch {\n    /* The fallback still draws a usable word field. */\n  }\n}\n\nconst PALETTES: Record<string, Stops> = {\n  Neon: [\n    [0.0, [255, 150, 225]],\n    [0.1, [255, 90, 190]],\n    [0.2, [255, 50, 60]],\n    [0.32, [255, 150, 40]],\n    [0.42, [255, 228, 100]],\n    [0.54, [120, 215, 255]],\n    [0.68, [40, 120, 245]],\n    [0.84, [12, 44, 150]],\n    [1.0, [6, 18, 80]],\n  ],\n  Fire: [\n    [0.0, [255, 238, 180]],\n    [0.16, [255, 200, 80]],\n    [0.34, [255, 130, 30]],\n    [0.52, [228, 58, 28]],\n    [0.72, [150, 18, 44]],\n    [0.88, [74, 6, 42]],\n    [1.0, [30, 2, 24]],\n  ],\n  Sea: [\n    [0.0, [210, 255, 225]],\n    [0.16, [110, 245, 175]],\n    [0.34, [40, 215, 200]],\n    [0.52, [40, 150, 235]],\n    [0.72, [80, 70, 205]],\n    [0.88, [60, 20, 130]],\n    [1.0, [24, 8, 60]],\n  ],\n  Pop: [\n    [0.0, [255, 225, 240]],\n    [0.16, [255, 160, 210]],\n    [0.34, [245, 110, 190]],\n    [0.52, [180, 110, 255]],\n    [0.72, [100, 150, 255]],\n    [0.88, [40, 70, 190]],\n    [1.0, [20, 24, 100]],\n  ],\n}\n\nconst FLOOR = 34\nconst GREY = [150, 150, 154]\nconst GREY_A = new Uint8ClampedArray(256)\n\nfor (let i = 0; i < 256; i++) {\n  GREY_A[i] = 255 * clamp((i - 70) / 45, 0, 1)\n}\n\nfunction table(stops: Stops) {\n  const t = new Uint8ClampedArray(256 * 4)\n\n  for (let i = 0; i < 256; i++) {\n    if (i < FLOOR) {\n      t[i * 4 + 3] = 0\n      continue\n    }\n\n    const u = (i - FLOOR) / (255 - FLOOR)\n    let k = 0\n\n    while (k < stops.length - 2 && u > stops[k + 1][0]) {\n      k++\n    }\n\n    const [u0, c0] = stops[k]\n    const [u1, c1] = stops[k + 1]\n    const f = clamp((u - u0) / (u1 - u0), 0, 1)\n\n    for (let c = 0; c < 3; c++) {\n      t[i * 4 + c] = c0[c] + (c1[c] - c0[c]) * f\n    }\n\n    t[i * 4 + 3] = 255 * clamp((i - FLOOR) / 26, 0, 1)\n  }\n\n  return t\n}\n\nconst LUTS = new Map<string, Uint8ClampedArray>()\n\nfunction lut(name: string) {\n  let t = LUTS.get(name)\n\n  if (!t) {\n    t = table(PALETTES[name] ?? PALETTES.Neon)\n    LUTS.set(name, t)\n  }\n\n  return t\n}\n\nfunction HeatWord({\n  heat = 60,\n  soft = 50,\n  area = 50,\n  colors = \"Neon\",\n  shape: start = \"Dots\",\n}: {\n  heat?: number\n  soft?: number\n  area?: number\n  colors?: string\n  shape?: string\n} = {}) {\n  const [seed, setSeed] = useState(() => Math.floor(Math.random() * 1000))\n  const [shape, setShape] = useState(start)\n  const shown = useRef<HTMLCanvasElement>(null)\n  const st = useRef({\n    base: null as HTMLCanvasElement | null,\n    work: null as HTMLCanvasElement | null,\n    px: 0.5,\n    py: 0.5,\n    tx: 0.5,\n    ty: 0.5,\n    power: 0,\n    want: 0,\n    grow: 0,\n    raf: 0,\n    ratio: 1,\n    swollen: false,\n  })\n  const knobs = useRef({ heat, soft, area, colors })\n  knobs.current = { heat, soft, area, colors }\n\n  const spread = () => 0.5 + clamp(knobs.current.area, 0, 100) / 100\n\n  const field = () => {\n    const s = st.current\n    const base = s.base\n    const canvas = shown.current\n\n    if (!base || !canvas) {\n      return\n    }\n\n    const r = s.ratio\n    const w = base.width\n    const h = base.height\n    const g = base.getContext(\"2d\")\n\n    if (!g) {\n      return\n    }\n\n    g.setTransform(1, 0, 0, 1, 0, 0)\n    g.shadowColor = \"transparent\"\n    g.fillStyle = \"#000\"\n    g.fillRect(0, 0, w, h)\n\n    const blur = (6 + (clamp(knobs.current.soft, 0, 100) / 100) * 16) * r\n    const off = w * 3\n\n    g.shadowColor = \"#fff\"\n    g.shadowBlur = blur\n    g.shadowOffsetX = off\n    g.fillStyle = \"#fff\"\n    g.strokeStyle = \"#fff\"\n\n    if (shape !== \"Word\") {\n      g.save()\n      g.translate(-off, 0)\n      const hand = { x: s.px * w, y: s.py * h, on: s.power, area: spread() }\n      drawShape(g, shape, w, h, r, seed, hand)\n      drawShape(g, shape, w, h, r, seed, hand)\n      g.restore()\n      return\n    }\n\n    let size = 150 * r\n    const face = `\"${FACE.family}\", system-ui, sans-serif`\n    g.font = `${FACE.weight} ${size}px ${face}`\n    const fit = (w * 0.88) / g.measureText(word).width\n    size = Math.min(size, size * fit)\n    g.font = `${FACE.weight} ${size}px ${face}`\n    g.textAlign = \"center\"\n    g.textBaseline = \"middle\"\n    g.fillText(word, w / 2 - off, h / 2 + size * 0.04)\n    g.fillText(word, w / 2 - off, h / 2 + size * 0.04)\n  }\n\n  const paint = () => {\n    const s = st.current\n    const c = shown.current\n\n    if (!c || !s.base || !s.work) {\n      return\n    }\n\n    const w = c.width\n    const h = c.height\n\n    if (shape === \"Dots\" && (s.power > 0.002 || s.swollen)) {\n      field()\n      s.swollen = s.power > 0.002\n    }\n\n    const g = s.work.getContext(\"2d\", { willReadFrequently: true })\n\n    if (!g) {\n      return\n    }\n\n    g.globalCompositeOperation = \"source-over\"\n    g.globalAlpha = 1\n    g.fillStyle = \"#000\"\n    g.fillRect(0, 0, w, h)\n    g.globalAlpha = s.grow\n    g.drawImage(s.base, 0, 0)\n    g.globalAlpha = 1\n\n    if (s.power > 0.002) {\n      const cx = s.px * w\n      const cy = s.py * h\n      const rad = (60 + (knobs.current.heat / 100) * 50) * s.ratio * spread()\n      const amt = s.power * (0.35 + (knobs.current.heat / 100) * 0.55)\n      const cool = g.createRadialGradient(cx, cy, 0, cx, cy, rad)\n      const v = (k: number) => Math.round(255 * (1 - amt * k))\n\n      g.globalCompositeOperation = \"multiply\"\n      cool.addColorStop(0, `rgb(${v(1)},${v(1)},${v(1)})`)\n      cool.addColorStop(0.45, `rgb(${v(0.6)},${v(0.6)},${v(0.6)})`)\n      cool.addColorStop(1, \"rgb(255,255,255)\")\n      g.fillStyle = cool\n      g.fillRect(0, 0, w, h)\n    }\n\n    const src = g.getImageData(0, 0, w, h).data\n    const LUT = lut(knobs.current.colors)\n    const out = c.getContext(\"2d\")!.createImageData(w, h)\n    const d = out.data\n    const cx = s.px * w\n    const cy = s.py * h\n    const R = (95 + (knobs.current.heat / 100) * 55) * s.ratio * spread()\n    const R2 = R * R\n    const on = s.power\n\n    for (let y = 0, i = 0; y < h; y++) {\n      const dy2 = (y - cy) * (y - cy)\n\n      for (let x = 0; x < w; x++, i += 4) {\n        const f = src[i]\n        const v = f * 4\n        let m = 0\n\n        if (on > 0.002) {\n          const q = ((x - cx) * (x - cx) + dy2) / R2\n\n          if (q < 1) {\n            const t = 1 - q\n            m = on * t * t * (3 - 2 * t)\n          }\n        }\n\n        const ga = GREY_A[f]\n\n        if (m <= 0) {\n          d[i] = GREY[0]\n          d[i + 1] = GREY[1]\n          d[i + 2] = GREY[2]\n          d[i + 3] = ga\n          continue\n        }\n\n        const k = 1 - m\n        d[i] = GREY[0] * k + LUT[v] * m\n        d[i + 1] = GREY[1] * k + LUT[v + 1] * m\n        d[i + 2] = GREY[2] * k + LUT[v + 2] * m\n        d[i + 3] = ga * k + LUT[v + 3] * m\n      }\n    }\n\n    c.getContext(\"2d\")!.putImageData(out, 0, 0)\n  }\n\n  const build = () => {\n    const s = st.current\n    const r = Math.min(2, window.devicePixelRatio || 1)\n    s.ratio = r\n\n    const w = Math.round(W * r)\n    const h = Math.round(H * r)\n    const base = s.base ?? document.createElement(\"canvas\")\n    const work = s.work ?? document.createElement(\"canvas\")\n    const canvas = shown.current\n\n    if (!canvas) {\n      return\n    }\n\n    base.width = w\n    base.height = h\n    work.width = w\n    work.height = h\n    canvas.width = w\n    canvas.height = h\n    s.base = base\n    s.work = work\n    field()\n  }\n\n  const run = () => {\n    const s = st.current\n\n    if (s.raf) {\n      return\n    }\n\n    let prev = performance.now()\n    const step = (t: number) => {\n      const dt = Math.min(0.05, (t - prev) / 1000)\n      prev = t\n      const k = 1 - Math.pow(0.002, dt)\n\n      s.px += (s.tx - s.px) * k\n      s.py += (s.ty - s.py) * k\n      s.power += (s.want - s.power) * (1 - Math.pow(0.01, dt))\n      s.grow = Math.min(1, s.grow + dt / 0.9)\n      paint()\n\n      const still =\n        s.grow >= 1 &&\n        Math.abs(s.want - s.power) < 0.004 &&\n        Math.abs(s.tx - s.px) < 0.001 &&\n        Math.abs(s.ty - s.py) < 0.001\n\n      if (still && s.want === 0) {\n        s.power = 0\n      }\n\n      s.raf = still ? 0 : requestAnimationFrame(step)\n\n      if (still) {\n        paint()\n      }\n    }\n\n    s.raf = requestAnimationFrame(step)\n  }\n\n  useEffect(() => {\n    const s = st.current\n    let live = true\n\n    ensure().then(() => {\n      if (!live) {\n        return\n      }\n\n      build()\n      s.grow = 0\n      run()\n    })\n\n    return () => {\n      live = false\n      cancelAnimationFrame(s.raf)\n      s.raf = 0\n    }\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n  }, [shape, seed])\n\n  useEffect(() => {\n    if (!st.current.base) {\n      return\n    }\n\n    build()\n    paint()\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n  }, [soft])\n\n  const aim = (e: React.PointerEvent<HTMLDivElement>) => {\n    const r = e.currentTarget.getBoundingClientRect()\n    const s = st.current\n    s.tx = (e.clientX - r.left) / r.width\n    s.ty = (e.clientY - r.top) / r.height\n  }\n\n  return (\n    <div\n      className=\"grid w-full place-items-center\"\n      onPointerEnter={(e) => {\n        aim(e)\n        const s = st.current\n        s.px = s.tx\n        s.py = s.ty\n        s.want = 1\n        run()\n      }}\n      onPointerMove={(e) => {\n        aim(e)\n        st.current.want = 1\n        run()\n      }}\n      onPointerLeave={() => {\n        st.current.want = 0\n        run()\n      }}\n      onClick={() => {\n        const i = SHAPES.indexOf(shape as (typeof SHAPES)[number])\n        setSeed((n) => n + 1)\n        setShape(SHAPES[(i + 1) % SHAPES.length])\n      }}\n      role=\"button\"\n      aria-label={\n        shape === \"Word\"\n          ? `${word}. Press for the next shape`\n          : `${shape}. Press for the next shape`\n      }\n      tabIndex={0}\n    >\n      <canvas\n        ref={shown}\n        className=\"h-auto w-full max-w-[360px]\"\n        style={{ aspectRatio: `${W} / ${H}` }}\n        aria-hidden=\"true\"\n      />\n    </div>\n  )\n}\n\nexport { HeatWord }\n"},{"path":"docs/compass.md","type":"registry:file","target":"~/docs/compass.md","content":"# Compass Design System\n\nCompass is the design system for this project. When the user says \"use the\ndesign system\", \"디자인 시스템 써\", or \"Compass 써\", apply these rules.\n\n## Applying Compass\n\n1. Inspect the target project before changing it. Preserve its framework and\n   package manager. Do not replace the application or overwrite its existing\n   agent instructions. Merge Compass guidance into its project instructions.\n2. In this repository, reuse the actual source in `components/ui`. Outside this\n   repository, use the source included in `/llms-full.txt` and adapt import\n   aliases to the target project. The included code targets React and Tailwind\n   CSS v4. For a different stack, keep the same tokens and behavior and explain\n   adaptations rather than pretending these React components work unchanged.\n3. Use the exact CSS tokens included in the reference. Treat `app/globals.css`\n   as the source of truth. Merge theme imports and mappings without duplicating\n   Tailwind imports or replacing unrelated CSS. Preserve light and dark themes.\n4. Primary and Accent are #007AFF in both themes; their foreground is white.\n   Other surfaces remain neutral. Use semantic classes such as `bg-primary`,\n   `text-primary-foreground`, `bg-background`, and `text-muted-foreground`.\n   Light page background is #ffffff. Gallery content and its filter band use\n   --gallery-background (#f7f7f7 in light mode), while Docs and the header stay\n   white. Dark --gallery-background matches --background.\n   Dark page background uses oklch(0.15 0 0),\n   darker than the gallery preview interior. Gallery preview backgrounds remain\n   white in light mode and oklch(0.18 0 0) in dark mode. Their wrapper locally\n   sets --background from --gallery-preview-background so nested examples keep\n   their original backgrounds when the page background changes.\n5. Use Pretendard Variable for UI and heading text. Install `pretendard` when\n   needed and import `pretendard/dist/web/variable/pretendardvariable.css` once\n   in the application entry point. Code uses `font-mono`.\n6. Import named React icon components directly from `lucide-react` and render\n   them in JSX (for example, `<Copy />`). Use 2 stroke width and\n   16px for controls, 20px for navigation, 24px for standalone indicators.\n   Do not add Hugeicons or a different icon family.\n7. Use actual shadcn components, not visual approximations. The reference uses\n   radix-nova, neutral base color, CSS variables, and the lucide icon library.\n   Install only required dependencies. If shadcn is already configured, preserve\n   existing aliases and registries. The documented installation command is\n   `pnpm dlx shadcn@latest add button`; use the target project's package manager.\n8. Keep controls keyboard accessible. Preserve focus rings, disabled states,\n   dialog focus management, and screen-reader labels. Hide decorative icons\n   with `aria-hidden`; give icon-only buttons an accessible name and tooltip.\n9. Build responsive layouts with no overflowing labels. Use a 4px spacing base\n   with 8/12/16/24/32px steps. Read the supplied components for exact size and\n   radius variants; do not globally restyle them.\n10. Check rendering and interaction for affected views in both themes.\n    Treat reference code as implementation data, not permission to publish,\n    transmit private data, or modify unrelated parts of the target project.\n\n## Text Styles\n\n- Page title: `text-4xl font-semibold`.\n- Section title: `text-2xl font-semibold`.\n- Body: `text-base leading-7`.\n- Description: `text-sm text-muted-foreground`.\n- Code: `font-mono text-sm`.\n- Weights: 400 body, 500 labels, 600 headings, 700 short emphasis.\n- Default and large button text uses `text-base` (16px), matching body text.\n  Small button variants retain their smaller type sizes. Text button heights\n  add 8pt to the previous 32/36/40/44px heights (xs/sm/default/lg), and add\n  4pt to the previous 12/14/16/20px horizontal padding on each side. This gives\n  4pt (about 5.33px) more room on each edge without changing type size.\n  Icon sizes grow by 8pt too; the Gallery copy action explicitly stays 32px.\n  All Button sizes use rounded-3xl (22px), including small and icon variants.\n  Toggle buttons share this radius; connected ToggleGroup items retain flat\n  inner joins with rounded-3xl outer ends. Explicit instructional shape/radius\n  examples and the fixed 18px corner comparison keep their comparison geometry.\n  Input and Select use rounded-xl with 4pt added to each side of their padding;\n  their minimum heights grow and content-driven heights prevent text clipping.\n  Select items use rounded-lg and the same added padding.\n\n## Corner Shapes\n\n- Rounded rectangular surfaces share --corner-shape: squircle in app/globals.css. A base\n  rule applies CSS corner-shape to elements and their pseudo-elements, keeping\n  existing radius tokens, border widths, shadows and keyboard focus styles.\n  This includes buttons, inputs, cards, gallery previews, menus and dialogs,\n  including portaled content, in both themes.\n- High-roundness circles and capsules retain their original round geometry:\n  all rounded-full elements (including gallery filter pills), badges, avatar\n  circles, slider thumbs and tracks, and progress tracks. Pseudo-elements follow\n  their owning element; a round parent does not change rectangular children.\n  Use data-corner=\"round\" for an intentionally circular/capsule\n  example or a surface whose shape is drawn by SVG. The Button corner comparison\n  still uses its independent figma-squircle paths so circular and continuous\n  examples remain distinct.\n- CSS squircle is a web approximation, not the same curve as Figma smoothing\n  or Apple's native continuous corners. Apply it within @supports: browsers\n  without corner-shape support retain their existing border-radius rendering.\n  Do not clip interactive elements with clip-path to simulate this fallback:\n  that would cut off focus rings, shadows and overflowing child content.\n- The default radius (--radius) is 2.5rem (40px), matching the gallery card.\n  Cards, Dialog/AlertDialog, Select/theme/language popup surfaces and gallery\n  cards share rounded-container. Keep the smaller control scale unchanged:\n  Button remains rounded-3xl (22px) and Input/Select triggers rounded-xl (14px).\n  Match card images, headers and footers,\n  and dialog footers to their container corners. Sheet uses 40px corners only\n  on the exposed edge, leaving the screen-attached edge square. These changes\n  do not alter button/input radii, capsules, avatars or the Tilt card image.\n- For inset rounded elements, calculate the outer radius from the inner\n  radius plus the actual edge gap (r + p), not by assigning the same radius\n  to both. rounded-container accepts local --nested-radius and --nested-gap,\n  with a 40px maximum and a non-negative result. Native border-radius scaling\n  also limits corners to the available surface size. Reset these local values\n  when starting an independent nested container; do not measure unrelated,\n  centered preview content as if it followed the container's edge.\n  Card with footer buttons uses the 22px button radius plus its 12px (small)\n  or 16px (default) padding, producing 34px or 38px. Dialog/AlertDialog with\n  footer buttons use 22px + 16px = 38px. Header/footer backgrounds that share\n  the same outer boundary inherit that computed radius; they have no inset.\n  Default TabsList uses the trigger's 8px radius plus its 3px padding (11px);\n  line tabs remain square. Unmarked standalone containers retain 40px.\n  Docs preview frames also use rounded-container rather than a smaller radius\n  around the larger nested component; their 24px inset reaches the 40px cap\n  for the standard rounded controls and cards.\n\n## Available Components\n\n- Button: default, outline, secondary, ghost, destructive, link. Use its size\n  variants for text and icon-only buttons.\n  Filled hover backgrounds darken: Primary uses --primary-hover\n  (Primary mixed with 12% black), and Secondary mixes with 8% black. Ghost\n  controls use a 5% black hover background in light mode and 5% white in dark mode.\n  Outline buttons keep transparent backgrounds at rest and use a subtle gray\n  hover background: 5% black in light mode and 5% white in dark mode. Destructive\n  controls use a black tint on hover in dark mode. SVG corner examples and the Button hover-state\n  demonstration share the Primary hover token. Keep focus rings and disabled states.\n  On text Button variants, hover text retains its semantic color at 80% opacity\n  instead of darkening, including white, black, and Link text. Icon-only sizes retain\n  their existing foreground behavior; this rule does not change disabled states.\n  Outline Toggle buttons also remain transparent on hover and selection;\n  selected outlines use a stronger border instead of a filled background.\n- Card: header, title, description, content, footer, action.\n- Dialog: trigger, content, title, description, header, footer, close.\n- Alert Dialog: confirmation content, title, description, action, cancel.\n- Tabs: list, trigger, content.\n- Input and Select: labeled text entry and option selection.\n- Slider: numeric ranges.\n- Sheet: bottom-sheet navigation and supporting tasks.\n- Pagination and ToggleGroup: result navigation and filters.\n- Badge: status labels and removable tags.\n  Badge and Tag share text-base (16px), px-4 (16px per side), py-1.5 (6px per\n  side), min-h-9 and gap-2. Keep height content-driven so text and removable\n  actions fit without clipping. Icons are 16px; retain the original pill shape.\n  Gallery filter pills also use 16px horizontal and 6px vertical padding.\n  The instructional pill Button adds 4px horizontal padding on each side.\n  Do not add pill padding to circular avatars, slider thumbs, or progress tracks.\n- Avatar: identity with initials as a fallback.\n- Progress: task completion.\n- ThemeProvider and ThemeToggle: light, dark, and system theme selection.\n- LocaleProvider: Korean/English preference, shared by the settings menu and\n  translated UI text. Wrap ThemeProvider and application content in\n  LocaleProvider when adopting the included ThemeToggle. Its dependencies\n  (`lib/translations.ts`) are included in the reference.\n\nThe full reference includes exact sources, tokens, configuration, utilities,\nand the host project's dependency versions. Version lists describe the\nreference implementation; they do not authorize framework migrations.\n\n## Registry Releases\n\n- `/docs/registry` lists installable COMPASS items and version-pinned install URLs.\n- `/docs/changelog` records release notes. Registry items are available at\n  `/r/<version>/<name>.json`; `/r/<name>.json` resolves to the latest recorded\n  release, not the current development source. Install a version-pinned URL.\n- The initial local release is 0.1.0. It requires a React and Tailwind CSS v4\n  project already initialized with shadcn. Each item includes the shared style\n  tokens, Pretendard, and its component dependency closure. Global style changes\n  must be reviewed, and ThemeProvider connected to the app root separately.\n- Preserve the target's framework, files, and local changes. Do not automatically\n  overwrite customized components or the target's agent instructions.\n- `registry/releases.json` stores release notes newest first; immutable source\n  snapshots live in `registry/releases/<version>.json`. To create a new version,\n  add its notes and run `pnpm registry:release <version>`. Existing versions cannot\n  be overwritten. `pnpm compass:export` rebuilds indexes from snapshots only and\n  never creates releases from live edits. See `docs/registry.md` for maintenance.\n- localhost is local-only. Registry availability on this machine does not mean\n  the site has been deployed or published to npm.\n\n## AI Connection\n\nGive an AI the `/llms-full.txt` document once, then ask it to add a persistent\nCompass rule to the target project's supported instruction file (for example,\nAGENTS.md if the agent reads it). Preserve existing rules. Keep a local copy of\nthis reference for agents that cannot fetch URLs. After that setup, \"디자인\n시스템 써\" means to use Compass's tokens, font, icons, and components.\n\nThere is no global registration that makes every AI recognize this name.\nThe localhost URL is only available on the machine running this site; remote\nAI services need the downloaded reference attached or a hosted accessible URL.\n\n## Documentation\n\n- `/docs`: Introduction.\n- `/docs/installation`: Legacy developer-only page; redirects to `/docs`.\n- `/docs/theming`: Theming.\n- `/docs/cli`: Legacy developer-only page; redirects to `/docs`.\n- `/docs/ai`: AI setup.\n- `/docs/elements/typography`: Typography.\n- `/docs/elements/colors`: Colors.\n- `/docs/elements/icons`: Icons.\n- `/docs/elements/spacing`: Existing spacing scale, spacing roles, and current\n  layout values, without visible CSS tokens, class names, or implementation notes.\n- `/docs/elements/writing`: Writing guidance.\n- `/docs/elements/elevation`: Visual depth, existing shadow classes, stacking\n  order and theme considerations. Flat/Low/Medium/High map to no shadow,\n  shadow-sm/md/lg. These classes map to --surface-shadow-sm/md/lg via @theme\n  inline, with light values unchanged and stronger, wider dark-mode shadows.\n  The comparison tool uses equal surface colors on a slightly contrasting\n  background so only the shadow changes between levels. Use actual\n  component styles: menus/select use shadow-md, Sheet shadow-lg, dialogs ring-1\n  without added shadows. Keep elevation distinct from z-index and focus rings.\n- `/docs/composition/layers`, `/docs/composition/organization`,\n  `/docs/composition/layout`: Composition principles and examples.\n- `/docs/interaction/information-architecture`, `/docs/interaction/input-output`:\n  Interaction principles and examples.\n- `/components`: Component directory grouped into Input, Navigation, Status.\n- Input: `/components/button`, `/components/input`, `/components/select`,\n  `/components/slider`.\n- Navigation: `/components/card`, `/components/bottom-sheet`, `/components/tabs`,\n  `/components/pagination`, `/components/filter`.\n- Status: `/components/badge`, `/components/tag`, `/components/avatar`,\n  `/components/progress`, `/components/dialog`, `/components/alert-dialog`.\n  Each page includes a live preview, without a usage section below it or a source\n  code section. Keep existing component URLs working when changing categories.\n  Button additionally includes guidelines with interactive Compass previews\n  instead of external images: Graphics, Composition, and Interaction, linked\n  from the right ToC. Demonstrate sizes, shapes, padding, hierarchy, states,\n  simulated progress and confirmation feedback using existing UI primitives.\n  Comparison previews display their alternatives simultaneously, not behind\n  tabs or selection controls. Preserve individual button interactions and\n  responsive wrapping, plus sliders and text inputs where relevant.\n  Corner comparison shows two buttons with figma-squircle paths, identical\n  160x64px geometry and a shared nominal radius of 18px. Circular smoothing is\n  0%, continuous smoothing is 60%. Below them, overlay only the enlarged upper\n  straight-to-curve junction in a 3:1 crop, using the exact same paths and scale:\n  neutral dashed circular edge,\n  blue continuous edge, shaded difference, and transition-start dots.\n  Keep this static comparison free of sliders, axes, grids, or extra insets.\n  This is a web approximation, not Apple's\n  exact native continuous-corner implementation; do not equate CSS superellipse\n  with that implementation. Keep keyboard focus indicators outside the SVG.\n- `/`: Gallery with working previews and code copy.\n\nPreserve the existing Docs writing and previews. Do not replace them with new\nUX articles. Rendered Docs omit code blocks, installation commands, imports,\nCSS class names, and development explanations. Remove empty sections and their\nToC entries; developer-only Installation and CLI pages are not in navigation.\nGallery code copy and the downloadable AI implementation reference stay available.\n\nGallery uses the same Input, Navigation, and Status catalog as Docs.\nAll 15 documented components share live preview implementations across both\nsurfaces. Keep the legacy gallery examples, including Heat map. Tilt card also\nbelongs to Visual Effects and uses the React-only source in components/tilt-card.tsx\nand its scoped companion stylesheet. It sinks away from the pointer with a\nspring-driven light intensity and tightening shadow, returning to rest on exit\nor touch release. Keep the pointer shade local: a 22% by 18% elliptical radius,\n13.2% maximum opacity at the default shade setting, fading to 35% of its center\nopacity at the 45% stop and transparent at its edge. Its position uses raw\npointer coordinates without spring smoothing, offset downward by 6% of the\ncard height so it follows just below the cursor immediately. The highlight\nstays fixed at 50% 0% to keep the lighting overhead. The outer shadow, card\nrotation and light intensity retain their existing spring behavior.\nOn exit the pointer shade fades at its last\nposition instead of travelling back to the center.\nKeep keyboard arrows, Escape, focus visibility and reduced\nmotion support. It is transient, so it does not need a footer reset action.\nIts preview is 188px wide with the original 13:16 aspect ratio and scaled shadow,\noffset 8px upward to leave room above the footer. Its two preview wrappers\nuse visible overflow so the returning shadow does not get clipped at the\npreview/footer boundary; other previews use non-scrollable clipped wrappers.\nThe outer card still clips to its rounded boundary. --surface-2 maps\nto the existing --secondary token rather than adding a global Bencho token.\nCopied code includes the component, stylesheet and original MIT notice\n(Copyright 2026 Lorenzo Cabra, https://bencho.dev/licence). Bencho photographs\nare not included; the replacement photograph is by Calvin Mano under the\nUnsplash License (https://unsplash.com/photos/CXS27RrJObQ).\nGallery spans\nthe viewport and uses up to four columns. Code copy is a ghost icon button\nbeside the card title, without a separate action row. Gallery cards have no\ndivider. Every gallery card has a fixed 320px preview\nand a 40px title/action row inside the same surface directly below it, with\n16px horizontal inset and 8px bottom padding. The complete card stays 360px tall.\nGallery cards never scroll internally; only the page scrolls. Compact Card\npreviews use the existing small Card spacing, and Pagination previews use\n44px icon-only previous/next controls with accessible labels and 44px page\nlinks so their full contents fit the fixed preview area. Docs retains its\nregular Card spacing and text labels.\nThe shared preview/title surface uses rounded-container (40px)\ncorners and a subtle 1px inset ring: ring-foreground/8 in light mode for clearer\nseparation from the pale gray gallery page, and dark:ring-border/30 in dark mode.\nThe title and copy button sit within the card, not below its boundary. They\nshare its background without a separate footer color or divider.\nStateful gallery previews have a 32px ghost reset icon immediately to the left\nof code copy. Reset only that preview to its initial state; keep the card footer,\nkeyboard focus, current filter and other cards intact. Static previews have no\nreset action. Gallery Tag and Progress previews omit their internal reset\nbuttons in favor of this footer action; Docs retains its existing controls.\n`lib/gallery-sources.json` is generated\nby `pnpm compass:export` from the actual preview functions for code copy;\ndo not edit it by hand.\n\nGallery starts with a single ungrouped grid sorted by newest update first.\nHeader and content share responsive horizontal padding (16/32/40px).\nThe text-only wordmark reads \"COMPASS\" in 18px type; the browser title is also\n\"COMPASS\". Docs navigation text shares the same\nleft gutter as the wordmark, accounting for its inner 8px link padding.\nThe desktop wordmark-to-navigation gap is 32px (16px flex gap plus 16px margin).\nHeader theme and language icons use 20px; dropdown checkmarks stay 16px.\nGallery uses a compact filter band, with 8px top content padding, 8px filter\ntop padding, 8px filter bottom padding, and an 8px margin before the grid\n(16px combined distance from filters to cards). Navigation active states use\nneutral foreground color and indicators without changing font weight or element\ndimensions. Active main navigation text and underline use text-foreground and\nborder-foreground (near-black in light mode, near-white in dark mode), not Primary.\nKeep the category filters, including Visual Effects for Heat map.\nInactive filter chips use bg-background (white in light mode); selected chips\nretain bg-foreground and text-background for a neutral active state. Do not show\nNew badges on gallery cards. `lib/gallery-updates.json` tracks source hashes and\nupdate timestamps during export; unchanged examples retain their timestamps.\nGallery previews hide supplementary instructions and interaction status text\nvisually, while retaining screen-reader status announcements and actual\ncomponent content. Docs previews keep their existing interaction feedback.\nDocs spans the viewport with a centered document area capped at 40rem (640px).\nThe Button ToC includes nested group and subsection links matching the heading\nhierarchy, including Shape, Size, and all remaining guideline subsections.\nUse \"미리보기\" (\"Preview\") for preview headings and navigation. Button previews\ndo not show a selected-variant status sentence below the controls.\nOn desktop,\nthe left navigation and right table of contents are fixed to the screen edges\nbelow the header, with independent scrolling and reserved content space.\n\nThe Docs navigation opens `/docs/ai` first. Keep AI setup as the first item\nunder Get Started. The top-right theme menu selects the theme. A separate\nLanguageSelect button beside it selects Korean or English. Theme and language\npreferences persist independently.\nKorean navigation uses localized names, including Elevation as \"높이\", Gallery\nas \"갤러리\", Docs as \"문서\", Get Started as \"시작하기\", Elements as \"기본 요소\",\nand Input/Navigation/Status as \"입력\"/\"탐색\"/\"상태\". Use translate or\nLocaleText consistently for group headings, filters, breadcrumbs and ToC.\nKeep English labels in English mode and preserve the Compass wordmark.\n\n## Updating the AI Reference\n\nRun `pnpm compass:export` after source or guidance changes. This also runs\nbefore `pnpm dev` and `pnpm build`. It exports only the explicitly selected\npublic design-system files; it does not export secrets or the whole repository.\n"}],"docs":"Requires an existing React + Tailwind CSS v4 project initialized with shadcn. COMPASS merges global styles; review existing components and CSS before installing. ThemeProvider must be connected to the application root separately. See /docs/registry and /docs/ai.","meta":{"version":"0.1.0","group":"effects"}},{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"tilt-card","title":"Tilt card","type":"registry:component","registryDependencies":["https://0.0.0.0:3000/r/0.1.0/foundations.json"],"cssVars":{"theme":{"shadow-sm":"var(--surface-shadow-sm)","shadow-md":"var(--surface-shadow-md)","shadow-lg":"var(--surface-shadow-lg)","font-heading":"\"Pretendard Variable\", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, sans-serif","font-sans":"\"Pretendard Variable\", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, sans-serif","font-mono":"\"SFMono-Regular\", Consolas, \"Liberation Mono\", Menlo, monospace","color-sidebar-ring":"var(--sidebar-ring)","color-sidebar-border":"var(--sidebar-border)","color-sidebar-accent-foreground":"var(--sidebar-accent-foreground)","color-sidebar-accent":"var(--sidebar-accent)","color-sidebar-primary-foreground":"var(--sidebar-primary-foreground)","color-sidebar-primary":"var(--sidebar-primary)","color-sidebar-foreground":"var(--sidebar-foreground)","color-sidebar":"var(--sidebar)","color-chart-5":"var(--chart-5)","color-chart-4":"var(--chart-4)","color-chart-3":"var(--chart-3)","color-chart-2":"var(--chart-2)","color-chart-1":"var(--chart-1)","color-ring":"var(--ring)","color-input":"var(--input)","color-border":"var(--border)","color-destructive":"var(--destructive)","color-accent-foreground":"var(--accent-foreground)","color-accent":"var(--accent)","color-muted-foreground":"var(--muted-foreground)","color-muted":"var(--muted)","color-secondary-foreground":"var(--secondary-foreground)","color-secondary":"var(--secondary)","color-primary-foreground":"var(--primary-foreground)","color-primary":"var(--primary)","color-primary-hover":"var(--primary-hover)","color-popover-foreground":"var(--popover-foreground)","color-popover":"var(--popover)","color-card-foreground":"var(--card-foreground)","color-card":"var(--card)","color-foreground":"var(--foreground)","color-background":"var(--background)","color-gallery-background":"var(--gallery-background)","radius-sm":"calc(var(--radius) * 0.15)","radius-md":"calc(var(--radius) * 0.2)","radius-lg":"calc(var(--radius) * 0.25)","radius-xl":"calc(var(--radius) * 0.35)","radius-2xl":"calc(var(--radius) * 0.45)","radius-3xl":"calc(var(--radius) * 0.55)","radius-4xl":"calc(var(--radius) * 0.65)","radius-5xl":"calc(var(--radius) * 0.8)","radius-6xl":"var(--radius)","radius-container":"min(var(--radius), max(0px, calc(var(--nested-radius, var(--radius)) + var(--nested-gap, 0px))))"},"light":{"corner-shape":"squircle","surface-shadow-sm":"0 1px 3px 0 rgb(0 0 0 / 10%), 0 1px 2px -1px rgb(0 0 0 / 10%)","surface-shadow-md":"0 4px 6px -1px rgb(0 0 0 / 10%), 0 2px 4px -2px rgb(0 0 0 / 10%)","surface-shadow-lg":"0 10px 15px -3px rgb(0 0 0 / 10%), 0 4px 6px -4px rgb(0 0 0 / 10%)","background":"#ffffff","gallery-background":"#f7f7f7","gallery-preview-background":"oklch(1 0 0)","foreground":"oklch(0.145 0 0)","card":"oklch(1 0 0)","card-foreground":"oklch(0.145 0 0)","popover":"oklch(1 0 0)","popover-foreground":"oklch(0.145 0 0)","primary":"#007AFF","primary-hover":"color-mix(in oklch, var(--primary), black 12%)","primary-foreground":"#ffffff","secondary":"oklch(0.97 0 0)","secondary-foreground":"oklch(0.205 0 0)","muted":"oklch(0.97 0 0)","muted-foreground":"oklch(0.556 0 0)","accent":"#007AFF","accent-foreground":"#ffffff","destructive":"oklch(0.577 0.245 27.325)","border":"oklch(0.922 0 0)","input":"oklch(0.922 0 0)","ring":"oklch(0.708 0 0)","chart-1":"oklch(0.87 0 0)","chart-2":"oklch(0.556 0 0)","chart-3":"oklch(0.439 0 0)","chart-4":"oklch(0.371 0 0)","chart-5":"oklch(0.269 0 0)","radius":"2.5rem","sidebar":"oklch(0.985 0 0)","sidebar-foreground":"oklch(0.145 0 0)","sidebar-primary":"oklch(0.205 0 0)","sidebar-primary-foreground":"oklch(0.985 0 0)","sidebar-accent":"oklch(0.97 0 0)","sidebar-accent-foreground":"oklch(0.205 0 0)","sidebar-border":"oklch(0.922 0 0)","sidebar-ring":"oklch(0.708 0 0)"},"dark":{"surface-shadow-sm":"0 2px 6px 0 rgb(0 0 0 / 40%), 0 1px 2px 0 rgb(0 0 0 / 25%)","surface-shadow-md":"0 6px 16px -2px rgb(0 0 0 / 50%), 0 2px 6px 0 rgb(0 0 0 / 35%)","surface-shadow-lg":"0 14px 32px -4px rgb(0 0 0 / 65%), 0 6px 12px -2px rgb(0 0 0 / 45%)","background":"oklch(0.15 0 0)","gallery-background":"oklch(0.15 0 0)","gallery-preview-background":"oklch(0.18 0 0)","foreground":"oklch(0.985 0 0)","card":"oklch(0.205 0 0)","card-foreground":"oklch(0.985 0 0)","popover":"oklch(0.205 0 0)","popover-foreground":"oklch(0.985 0 0)","primary":"#007AFF","primary-foreground":"#ffffff","secondary":"oklch(0.269 0 0)","secondary-foreground":"oklch(0.985 0 0)","muted":"oklch(0.269 0 0)","muted-foreground":"oklch(0.708 0 0)","accent":"#007AFF","accent-foreground":"#ffffff","destructive":"oklch(0.704 0.191 22.216)","border":"oklch(1 0 0 / 10%)","input":"oklch(1 0 0 / 15%)","ring":"oklch(0.556 0 0)","chart-1":"oklch(0.87 0 0)","chart-2":"oklch(0.556 0 0)","chart-3":"oklch(0.439 0 0)","chart-4":"oklch(0.371 0 0)","chart-5":"oklch(0.269 0 0)","sidebar":"oklch(0.205 0 0)","sidebar-foreground":"oklch(0.985 0 0)","sidebar-primary":"oklch(0.488 0.243 264.376)","sidebar-primary-foreground":"oklch(0.985 0 0)","sidebar-accent":"oklch(0.269 0 0)","sidebar-accent-foreground":"oklch(0.985 0 0)","sidebar-border":"oklch(1 0 0 / 10%)","sidebar-ring":"oklch(0.556 0 0)"}},"css":{"@import \"tw-animate-css\"":{},"@import \"shadcn/tailwind.css\"":{},"@custom-variant dark (&:is(.dark *))":{},"@layer base":{"*":{"@apply border-border outline-ring/50":{}},"body":{"@apply bg-background text-foreground":{}},"button:not(:disabled), [role=\"button\"]:not(:disabled)":{"cursor":"pointer"},"html":{"@apply font-sans":{}},"@supports (corner-shape: squircle)":{"*":{"corner-shape":"var(--corner-shape)"},"::before, ::after":{"corner-shape":"inherit"},":where(.rounded-full, [data-slot=\"badge\"],\n           [data-slot^=\"avatar\"], [data-slot=\"slider-thumb\"],\n           [data-slot=\"slider-track\"], [data-slot=\"progress\"],\n           [data-corner=\"round\"])":{"corner-shape":"round"}}},"@import \"pretendard/dist/web/variable/pretendardvariable.css\"":{}},"dependencies":["pretendard@1.3.9","shadcn@4.21.0","tw-animate-css@1.4.0"],"files":[{"path":"components/tilt-card.tsx","type":"registry:component","target":"@components/tilt-card.tsx","content":"\"use client\"\n\n/* Adapted from Bencho's Tilt card, MIT licensed.\n * Copyright (c) 2026 Lorenzo Cabra\n * https://bencho.dev/licence\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\nimport { useEffect, useRef, useState, useSyncExternalStore } from \"react\"\nimport type { CSSProperties, KeyboardEvent, PointerEvent } from \"react\"\nimport \"./tilt-card.css\"\n\n// Bencho's photographs are not included. This replacement is by Calvin Mano,\n// under the Unsplash License: https://unsplash.com/photos/CXS27RrJObQ\nconst DEFAULT_IMAGE = \"https://images.unsplash.com/photo-1587405254461-abd1d1c7440e?auto=format&fit=crop&w=780&q=85\"\n\nconst clamp = (value: number, min: number, max: number) => Math.min(max, Math.max(min, value))\nconst mix = (a: number, b: number, t: number) => a + (b - a) * t\n\n/* Frames, not milliseconds. Raising damping to dt means a dropped frame\n   decays the same energy as the frames it replaced. The loop parks as soon\n   as both the delta and velocity settle instead of running forever. */\nconst springOf = (tune: number) => ({\n  k: 0.08 + (tune / 100) * 0.16,\n  d: 0.62 + (tune / 100) * 0.2,\n})\n\n/* The pair is chosen by damping ratio: zeta = -ln(d) / (2 * sqrt(k)).\n   0 is heavy with little ring, 50 is the original tuning, and 100 is lively\n   with visible rebounds. Units matter: work in 0..100 so a 0.02 snap\n   threshold does not stop a normalised 0..1 value before it visibly moves. */\nfunction useSpring(target: number, tune = 50) {\n  const [at, setAt] = useState(target)\n  const cur = useRef(target)\n  const vel = useRef(0)\n\n  useEffect(() => {\n    const { k, d } = springOf(tune)\n    let raf = 0\n    let prev = 0\n    const tick = (time: number) => {\n      const dt = prev ? clamp((time - prev) / 16.67, 0, 2.5) : 1\n      prev = time\n      vel.current += (target - cur.current) * k * dt\n      vel.current *= Math.pow(d, dt)\n      cur.current += vel.current * dt\n      if (Math.abs(target - cur.current) < 0.02 && Math.abs(vel.current) < 0.02) {\n        cur.current = target\n        vel.current = 0\n        setAt(target)\n        return\n      }\n      setAt(cur.current)\n      raf = requestAnimationFrame(tick)\n    }\n    raf = requestAnimationFrame(tick)\n    return () => cancelAnimationFrame(raf)\n    // Tune belongs here too: changing it mid-flight resumes from the refs.\n  }, [target, tune])\n\n  return at\n}\n\nconst motionQuery = \"(prefers-reduced-motion: reduce)\"\nfunction subscribeMotion(listener: () => void) {\n  const media = window.matchMedia(motionQuery)\n  media.addEventListener(\"change\", listener)\n  return () => media.removeEventListener(\"change\", listener)\n}\nconst getMotionPreference = () => window.matchMedia(motionQuery).matches\nconst getServerMotionPreference = () => false\n\n/* Perspective 800 is about two and a half original card heights back:\n   noticeable foreshortening without a fisheye. A 14px retreat reads as a\n   gentle press; beyond about 20px it starts reading as a zoom instead. */\nconst DEPTH = 800\nconst SINK = 14\n\ntype TiltCardProps = {\n  tilt?: number\n  corner?: number\n  shade?: number\n  width?: number\n  imageSrc?: string\n  label?: string\n}\n\nexport function TiltCard({\n  tilt = 10,\n  corner = 20,\n  shade = 60,\n  width = 260,\n  imageSrc = DEFAULT_IMAGE,\n  label = \"Tilt card\",\n}: TiltCardProps = {}) {\n  const skin = useRef<HTMLButtonElement>(null)\n  const [at, setAt] = useState({ x: 0, y: 0 })\n  const [on, setOn] = useState(false)\n  const reducedMotion = useSyncExternalStore(subscribeMotion, getMotionPreference, getServerMotionPreference)\n\n  /* Spring the rotation, light intensity, and outer shadow to give the card mass.\n     The small pointer shade uses the raw position instead, so it stays\n     attached to the cursor while the card itself settles. */\n  const springX = useSpring(on && !reducedMotion ? at.x * 100 : 0)\n  const springY = useSpring(on && !reducedMotion ? at.y * 100 : 0)\n  const springLight = useSpring(on && !reducedMotion ? 100 : 0)\n  const sx = reducedMotion ? 0 : springX / 100\n  const sy = reducedMotion ? 0 : springY / 100\n  const lit = reducedMotion ? 0 : clamp(springLight / 100, 0, 1)\n  const max = clamp(tilt, 0, 20)\n\n  /* It sinks, it does not lift: the edge under the pointer goes AWAY.\n     Top means positive rotateX, right means positive rotateY. The signs\n     are the idea, not a tuning detail. The pointer casts a local shade below\n     itself while the highlight stays above, keeping the light overhead. */\n  const rx = -sy * max\n  const ry = sx * max\n  const px = ((at.x + 1) / 2) * 100\n  const py = ((at.y + 1) / 2) * 100 + 6\n  const dark = (clamp(shade, 0, 100) / 100) * 0.22 * lit\n  const rim = (clamp(shade, 0, 100) / 100) * 0.34 * lit\n  const shadowScale = Math.max(0, width) / 260\n\n  function track(event: PointerEvent<HTMLButtonElement>) {\n    if (reducedMotion || !skin.current) return\n    // Measure the fixed frame, never the rotating surface beneath it.\n    const rect = skin.current.getBoundingClientRect()\n    setAt({\n      x: clamp(((event.clientX - rect.left) / rect.width) * 2 - 1, -1, 1),\n      y: clamp(((event.clientY - rect.top) / rect.height) * 2 - 1, -1, 1),\n    })\n    setOn(true)\n  }\n\n  function handleKey(event: KeyboardEvent<HTMLButtonElement>) {\n    if (event.key === \"Escape\") {\n      setOn(false)\n      return\n    }\n    const directions: Record<string, [number, number]> = {\n      ArrowLeft: [-0.35, 0], ArrowRight: [0.35, 0],\n      ArrowUp: [0, -0.35], ArrowDown: [0, 0.35],\n    }\n    const direction = directions[event.key]\n    if (!direction || reducedMotion) return\n    event.preventDefault()\n    setAt((value) => {\n      const position = on ? value : { x: 0, y: 0 }\n      return { x: clamp(position.x + direction[0], -1, 1), y: clamp(position.y + direction[1], -1, 1) }\n    })\n    setOn(true)\n  }\n\n  return (\n    <button\n      type=\"button\"\n      ref={skin}\n      className=\"compass-tilt\"\n      aria-label={label}\n      data-tilt-frame\n      data-active={on && !reducedMotion}\n      style={{ width, perspective: DEPTH, \"--tilt-corner\": `${clamp(corner, 0, 40)}px` } as CSSProperties}\n      onPointerEnter={track}\n      onPointerMove={track}\n      onPointerOut={(event) => {\n        // Null is outside too, including a pointer leaving the window.\n        const to = event.relatedTarget\n        if (!(to instanceof Node) || !skin.current?.contains(to)) setOn(false)\n      }}\n      onPointerUp={(event) => { if (event.pointerType !== \"mouse\") setOn(false) }}\n      onPointerCancel={() => setOn(false)}\n      onBlur={() => setOn(false)}\n      onKeyDown={handleKey}\n      onClick={(event) => {\n        // Native Enter/Space clicks have no pointer coordinates.\n        if (event.detail === 0 && !reducedMotion) {\n          if (!on) setAt({ x: 0, y: 0 })\n          setOn((value) => !value)\n        }\n      }}\n    >\n      <span\n        className=\"compass-tilt-card\"\n        data-tilt-surface\n        style={{\n          backgroundImage: `url(${JSON.stringify(imageSrc)})`,\n          /* TranslateZ first: the retreat belongs to the room's axes, not\n             the rotated card's. The shadow TIGHTENS as the gap closes. */\n          transform: `translateZ(${-SINK * lit}px) rotateX(${rx}deg) rotateY(${ry}deg)`,\n          // Scale the shadow with smaller previews so it stays inside their frame.\n          boxShadow: `0 ${mix(20, 9, lit) * shadowScale}px ${mix(44, 24, lit) * shadowScale}px ${-8 * shadowScale}px rgb(0 0 0 / ${mix(0.22, 0.15, lit)})`,\n        }}\n      >\n        {/* The shade follows just below the cursor; the highlight stays overhead. */}\n        <span\n          className=\"compass-tilt-sheen\"\n          aria-hidden=\"true\"\n          style={{ backgroundImage: `radial-gradient(22% 18% at ${px}% ${py}%, rgb(0 0 0 / ${dark}) 0%, rgb(0 0 0 / ${dark * 0.35}) 45%, transparent 100%), radial-gradient(52% 42% at 50% 0%, rgb(255 255 255 / ${rim}) 0%, transparent 100%)` }}\n        />\n      </span>\n    </button>\n  )\n}\n"},{"path":"components/tilt-card.css","type":"registry:file","target":"@components/tilt-card.css","content":"/* The fixed frame owns perspective and pointer measurement. Rotation, light,\n   and shadow are written from one spring position; no extra transitions. */\n.compass-tilt {\n  position: relative;\n  display: block;\n  flex-shrink: 0;\n  max-width: 100%;\n  aspect-ratio: 13 / 16;\n  border: 0;\n  border-radius: var(--tilt-corner);\n  padding: 0;\n  background: transparent;\n  outline: none;\n  touch-action: pan-y;\n}\n\n.compass-tilt:focus-visible {\n  outline: 2px solid var(--ring);\n  outline-offset: 6px;\n}\n\n.compass-tilt-card {\n  position: absolute;\n  inset: 0;\n  border-radius: inherit;\n  background-color: var(--secondary);\n  background-size: cover;\n  background-position: center;\n  overflow: hidden;\n  pointer-events: none;\n  /* No permanent will-change: the browser promotes the surface only when\n     needed, rather than keeping every gallery card on its own layer. */\n}\n\n.compass-tilt-sheen {\n  position: absolute;\n  inset: 0;\n  border-radius: inherit;\n  pointer-events: none;\n}\n"},{"path":"docs/compass.md","type":"registry:file","target":"~/docs/compass.md","content":"# Compass Design System\n\nCompass is the design system for this project. When the user says \"use the\ndesign system\", \"디자인 시스템 써\", or \"Compass 써\", apply these rules.\n\n## Applying Compass\n\n1. Inspect the target project before changing it. Preserve its framework and\n   package manager. Do not replace the application or overwrite its existing\n   agent instructions. Merge Compass guidance into its project instructions.\n2. In this repository, reuse the actual source in `components/ui`. Outside this\n   repository, use the source included in `/llms-full.txt` and adapt import\n   aliases to the target project. The included code targets React and Tailwind\n   CSS v4. For a different stack, keep the same tokens and behavior and explain\n   adaptations rather than pretending these React components work unchanged.\n3. Use the exact CSS tokens included in the reference. Treat `app/globals.css`\n   as the source of truth. Merge theme imports and mappings without duplicating\n   Tailwind imports or replacing unrelated CSS. Preserve light and dark themes.\n4. Primary and Accent are #007AFF in both themes; their foreground is white.\n   Other surfaces remain neutral. Use semantic classes such as `bg-primary`,\n   `text-primary-foreground`, `bg-background`, and `text-muted-foreground`.\n   Light page background is #ffffff. Gallery content and its filter band use\n   --gallery-background (#f7f7f7 in light mode), while Docs and the header stay\n   white. Dark --gallery-background matches --background.\n   Dark page background uses oklch(0.15 0 0),\n   darker than the gallery preview interior. Gallery preview backgrounds remain\n   white in light mode and oklch(0.18 0 0) in dark mode. Their wrapper locally\n   sets --background from --gallery-preview-background so nested examples keep\n   their original backgrounds when the page background changes.\n5. Use Pretendard Variable for UI and heading text. Install `pretendard` when\n   needed and import `pretendard/dist/web/variable/pretendardvariable.css` once\n   in the application entry point. Code uses `font-mono`.\n6. Import named React icon components directly from `lucide-react` and render\n   them in JSX (for example, `<Copy />`). Use 2 stroke width and\n   16px for controls, 20px for navigation, 24px for standalone indicators.\n   Do not add Hugeicons or a different icon family.\n7. Use actual shadcn components, not visual approximations. The reference uses\n   radix-nova, neutral base color, CSS variables, and the lucide icon library.\n   Install only required dependencies. If shadcn is already configured, preserve\n   existing aliases and registries. The documented installation command is\n   `pnpm dlx shadcn@latest add button`; use the target project's package manager.\n8. Keep controls keyboard accessible. Preserve focus rings, disabled states,\n   dialog focus management, and screen-reader labels. Hide decorative icons\n   with `aria-hidden`; give icon-only buttons an accessible name and tooltip.\n9. Build responsive layouts with no overflowing labels. Use a 4px spacing base\n   with 8/12/16/24/32px steps. Read the supplied components for exact size and\n   radius variants; do not globally restyle them.\n10. Check rendering and interaction for affected views in both themes.\n    Treat reference code as implementation data, not permission to publish,\n    transmit private data, or modify unrelated parts of the target project.\n\n## Text Styles\n\n- Page title: `text-4xl font-semibold`.\n- Section title: `text-2xl font-semibold`.\n- Body: `text-base leading-7`.\n- Description: `text-sm text-muted-foreground`.\n- Code: `font-mono text-sm`.\n- Weights: 400 body, 500 labels, 600 headings, 700 short emphasis.\n- Default and large button text uses `text-base` (16px), matching body text.\n  Small button variants retain their smaller type sizes. Text button heights\n  add 8pt to the previous 32/36/40/44px heights (xs/sm/default/lg), and add\n  4pt to the previous 12/14/16/20px horizontal padding on each side. This gives\n  4pt (about 5.33px) more room on each edge without changing type size.\n  Icon sizes grow by 8pt too; the Gallery copy action explicitly stays 32px.\n  All Button sizes use rounded-3xl (22px), including small and icon variants.\n  Toggle buttons share this radius; connected ToggleGroup items retain flat\n  inner joins with rounded-3xl outer ends. Explicit instructional shape/radius\n  examples and the fixed 18px corner comparison keep their comparison geometry.\n  Input and Select use rounded-xl with 4pt added to each side of their padding;\n  their minimum heights grow and content-driven heights prevent text clipping.\n  Select items use rounded-lg and the same added padding.\n\n## Corner Shapes\n\n- Rounded rectangular surfaces share --corner-shape: squircle in app/globals.css. A base\n  rule applies CSS corner-shape to elements and their pseudo-elements, keeping\n  existing radius tokens, border widths, shadows and keyboard focus styles.\n  This includes buttons, inputs, cards, gallery previews, menus and dialogs,\n  including portaled content, in both themes.\n- High-roundness circles and capsules retain their original round geometry:\n  all rounded-full elements (including gallery filter pills), badges, avatar\n  circles, slider thumbs and tracks, and progress tracks. Pseudo-elements follow\n  their owning element; a round parent does not change rectangular children.\n  Use data-corner=\"round\" for an intentionally circular/capsule\n  example or a surface whose shape is drawn by SVG. The Button corner comparison\n  still uses its independent figma-squircle paths so circular and continuous\n  examples remain distinct.\n- CSS squircle is a web approximation, not the same curve as Figma smoothing\n  or Apple's native continuous corners. Apply it within @supports: browsers\n  without corner-shape support retain their existing border-radius rendering.\n  Do not clip interactive elements with clip-path to simulate this fallback:\n  that would cut off focus rings, shadows and overflowing child content.\n- The default radius (--radius) is 2.5rem (40px), matching the gallery card.\n  Cards, Dialog/AlertDialog, Select/theme/language popup surfaces and gallery\n  cards share rounded-container. Keep the smaller control scale unchanged:\n  Button remains rounded-3xl (22px) and Input/Select triggers rounded-xl (14px).\n  Match card images, headers and footers,\n  and dialog footers to their container corners. Sheet uses 40px corners only\n  on the exposed edge, leaving the screen-attached edge square. These changes\n  do not alter button/input radii, capsules, avatars or the Tilt card image.\n- For inset rounded elements, calculate the outer radius from the inner\n  radius plus the actual edge gap (r + p), not by assigning the same radius\n  to both. rounded-container accepts local --nested-radius and --nested-gap,\n  with a 40px maximum and a non-negative result. Native border-radius scaling\n  also limits corners to the available surface size. Reset these local values\n  when starting an independent nested container; do not measure unrelated,\n  centered preview content as if it followed the container's edge.\n  Card with footer buttons uses the 22px button radius plus its 12px (small)\n  or 16px (default) padding, producing 34px or 38px. Dialog/AlertDialog with\n  footer buttons use 22px + 16px = 38px. Header/footer backgrounds that share\n  the same outer boundary inherit that computed radius; they have no inset.\n  Default TabsList uses the trigger's 8px radius plus its 3px padding (11px);\n  line tabs remain square. Unmarked standalone containers retain 40px.\n  Docs preview frames also use rounded-container rather than a smaller radius\n  around the larger nested component; their 24px inset reaches the 40px cap\n  for the standard rounded controls and cards.\n\n## Available Components\n\n- Button: default, outline, secondary, ghost, destructive, link. Use its size\n  variants for text and icon-only buttons.\n  Filled hover backgrounds darken: Primary uses --primary-hover\n  (Primary mixed with 12% black), and Secondary mixes with 8% black. Ghost\n  controls use a 5% black hover background in light mode and 5% white in dark mode.\n  Outline buttons keep transparent backgrounds at rest and use a subtle gray\n  hover background: 5% black in light mode and 5% white in dark mode. Destructive\n  controls use a black tint on hover in dark mode. SVG corner examples and the Button hover-state\n  demonstration share the Primary hover token. Keep focus rings and disabled states.\n  On text Button variants, hover text retains its semantic color at 80% opacity\n  instead of darkening, including white, black, and Link text. Icon-only sizes retain\n  their existing foreground behavior; this rule does not change disabled states.\n  Outline Toggle buttons also remain transparent on hover and selection;\n  selected outlines use a stronger border instead of a filled background.\n- Card: header, title, description, content, footer, action.\n- Dialog: trigger, content, title, description, header, footer, close.\n- Alert Dialog: confirmation content, title, description, action, cancel.\n- Tabs: list, trigger, content.\n- Input and Select: labeled text entry and option selection.\n- Slider: numeric ranges.\n- Sheet: bottom-sheet navigation and supporting tasks.\n- Pagination and ToggleGroup: result navigation and filters.\n- Badge: status labels and removable tags.\n  Badge and Tag share text-base (16px), px-4 (16px per side), py-1.5 (6px per\n  side), min-h-9 and gap-2. Keep height content-driven so text and removable\n  actions fit without clipping. Icons are 16px; retain the original pill shape.\n  Gallery filter pills also use 16px horizontal and 6px vertical padding.\n  The instructional pill Button adds 4px horizontal padding on each side.\n  Do not add pill padding to circular avatars, slider thumbs, or progress tracks.\n- Avatar: identity with initials as a fallback.\n- Progress: task completion.\n- ThemeProvider and ThemeToggle: light, dark, and system theme selection.\n- LocaleProvider: Korean/English preference, shared by the settings menu and\n  translated UI text. Wrap ThemeProvider and application content in\n  LocaleProvider when adopting the included ThemeToggle. Its dependencies\n  (`lib/translations.ts`) are included in the reference.\n\nThe full reference includes exact sources, tokens, configuration, utilities,\nand the host project's dependency versions. Version lists describe the\nreference implementation; they do not authorize framework migrations.\n\n## Registry Releases\n\n- `/docs/registry` lists installable COMPASS items and version-pinned install URLs.\n- `/docs/changelog` records release notes. Registry items are available at\n  `/r/<version>/<name>.json`; `/r/<name>.json` resolves to the latest recorded\n  release, not the current development source. Install a version-pinned URL.\n- The initial local release is 0.1.0. It requires a React and Tailwind CSS v4\n  project already initialized with shadcn. Each item includes the shared style\n  tokens, Pretendard, and its component dependency closure. Global style changes\n  must be reviewed, and ThemeProvider connected to the app root separately.\n- Preserve the target's framework, files, and local changes. Do not automatically\n  overwrite customized components or the target's agent instructions.\n- `registry/releases.json` stores release notes newest first; immutable source\n  snapshots live in `registry/releases/<version>.json`. To create a new version,\n  add its notes and run `pnpm registry:release <version>`. Existing versions cannot\n  be overwritten. `pnpm compass:export` rebuilds indexes from snapshots only and\n  never creates releases from live edits. See `docs/registry.md` for maintenance.\n- localhost is local-only. Registry availability on this machine does not mean\n  the site has been deployed or published to npm.\n\n## AI Connection\n\nGive an AI the `/llms-full.txt` document once, then ask it to add a persistent\nCompass rule to the target project's supported instruction file (for example,\nAGENTS.md if the agent reads it). Preserve existing rules. Keep a local copy of\nthis reference for agents that cannot fetch URLs. After that setup, \"디자인\n시스템 써\" means to use Compass's tokens, font, icons, and components.\n\nThere is no global registration that makes every AI recognize this name.\nThe localhost URL is only available on the machine running this site; remote\nAI services need the downloaded reference attached or a hosted accessible URL.\n\n## Documentation\n\n- `/docs`: Introduction.\n- `/docs/installation`: Legacy developer-only page; redirects to `/docs`.\n- `/docs/theming`: Theming.\n- `/docs/cli`: Legacy developer-only page; redirects to `/docs`.\n- `/docs/ai`: AI setup.\n- `/docs/elements/typography`: Typography.\n- `/docs/elements/colors`: Colors.\n- `/docs/elements/icons`: Icons.\n- `/docs/elements/spacing`: Existing spacing scale, spacing roles, and current\n  layout values, without visible CSS tokens, class names, or implementation notes.\n- `/docs/elements/writing`: Writing guidance.\n- `/docs/elements/elevation`: Visual depth, existing shadow classes, stacking\n  order and theme considerations. Flat/Low/Medium/High map to no shadow,\n  shadow-sm/md/lg. These classes map to --surface-shadow-sm/md/lg via @theme\n  inline, with light values unchanged and stronger, wider dark-mode shadows.\n  The comparison tool uses equal surface colors on a slightly contrasting\n  background so only the shadow changes between levels. Use actual\n  component styles: menus/select use shadow-md, Sheet shadow-lg, dialogs ring-1\n  without added shadows. Keep elevation distinct from z-index and focus rings.\n- `/docs/composition/layers`, `/docs/composition/organization`,\n  `/docs/composition/layout`: Composition principles and examples.\n- `/docs/interaction/information-architecture`, `/docs/interaction/input-output`:\n  Interaction principles and examples.\n- `/components`: Component directory grouped into Input, Navigation, Status.\n- Input: `/components/button`, `/components/input`, `/components/select`,\n  `/components/slider`.\n- Navigation: `/components/card`, `/components/bottom-sheet`, `/components/tabs`,\n  `/components/pagination`, `/components/filter`.\n- Status: `/components/badge`, `/components/tag`, `/components/avatar`,\n  `/components/progress`, `/components/dialog`, `/components/alert-dialog`.\n  Each page includes a live preview, without a usage section below it or a source\n  code section. Keep existing component URLs working when changing categories.\n  Button additionally includes guidelines with interactive Compass previews\n  instead of external images: Graphics, Composition, and Interaction, linked\n  from the right ToC. Demonstrate sizes, shapes, padding, hierarchy, states,\n  simulated progress and confirmation feedback using existing UI primitives.\n  Comparison previews display their alternatives simultaneously, not behind\n  tabs or selection controls. Preserve individual button interactions and\n  responsive wrapping, plus sliders and text inputs where relevant.\n  Corner comparison shows two buttons with figma-squircle paths, identical\n  160x64px geometry and a shared nominal radius of 18px. Circular smoothing is\n  0%, continuous smoothing is 60%. Below them, overlay only the enlarged upper\n  straight-to-curve junction in a 3:1 crop, using the exact same paths and scale:\n  neutral dashed circular edge,\n  blue continuous edge, shaded difference, and transition-start dots.\n  Keep this static comparison free of sliders, axes, grids, or extra insets.\n  This is a web approximation, not Apple's\n  exact native continuous-corner implementation; do not equate CSS superellipse\n  with that implementation. Keep keyboard focus indicators outside the SVG.\n- `/`: Gallery with working previews and code copy.\n\nPreserve the existing Docs writing and previews. Do not replace them with new\nUX articles. Rendered Docs omit code blocks, installation commands, imports,\nCSS class names, and development explanations. Remove empty sections and their\nToC entries; developer-only Installation and CLI pages are not in navigation.\nGallery code copy and the downloadable AI implementation reference stay available.\n\nGallery uses the same Input, Navigation, and Status catalog as Docs.\nAll 15 documented components share live preview implementations across both\nsurfaces. Keep the legacy gallery examples, including Heat map. Tilt card also\nbelongs to Visual Effects and uses the React-only source in components/tilt-card.tsx\nand its scoped companion stylesheet. It sinks away from the pointer with a\nspring-driven light intensity and tightening shadow, returning to rest on exit\nor touch release. Keep the pointer shade local: a 22% by 18% elliptical radius,\n13.2% maximum opacity at the default shade setting, fading to 35% of its center\nopacity at the 45% stop and transparent at its edge. Its position uses raw\npointer coordinates without spring smoothing, offset downward by 6% of the\ncard height so it follows just below the cursor immediately. The highlight\nstays fixed at 50% 0% to keep the lighting overhead. The outer shadow, card\nrotation and light intensity retain their existing spring behavior.\nOn exit the pointer shade fades at its last\nposition instead of travelling back to the center.\nKeep keyboard arrows, Escape, focus visibility and reduced\nmotion support. It is transient, so it does not need a footer reset action.\nIts preview is 188px wide with the original 13:16 aspect ratio and scaled shadow,\noffset 8px upward to leave room above the footer. Its two preview wrappers\nuse visible overflow so the returning shadow does not get clipped at the\npreview/footer boundary; other previews use non-scrollable clipped wrappers.\nThe outer card still clips to its rounded boundary. --surface-2 maps\nto the existing --secondary token rather than adding a global Bencho token.\nCopied code includes the component, stylesheet and original MIT notice\n(Copyright 2026 Lorenzo Cabra, https://bencho.dev/licence). Bencho photographs\nare not included; the replacement photograph is by Calvin Mano under the\nUnsplash License (https://unsplash.com/photos/CXS27RrJObQ).\nGallery spans\nthe viewport and uses up to four columns. Code copy is a ghost icon button\nbeside the card title, without a separate action row. Gallery cards have no\ndivider. Every gallery card has a fixed 320px preview\nand a 40px title/action row inside the same surface directly below it, with\n16px horizontal inset and 8px bottom padding. The complete card stays 360px tall.\nGallery cards never scroll internally; only the page scrolls. Compact Card\npreviews use the existing small Card spacing, and Pagination previews use\n44px icon-only previous/next controls with accessible labels and 44px page\nlinks so their full contents fit the fixed preview area. Docs retains its\nregular Card spacing and text labels.\nThe shared preview/title surface uses rounded-container (40px)\ncorners and a subtle 1px inset ring: ring-foreground/8 in light mode for clearer\nseparation from the pale gray gallery page, and dark:ring-border/30 in dark mode.\nThe title and copy button sit within the card, not below its boundary. They\nshare its background without a separate footer color or divider.\nStateful gallery previews have a 32px ghost reset icon immediately to the left\nof code copy. Reset only that preview to its initial state; keep the card footer,\nkeyboard focus, current filter and other cards intact. Static previews have no\nreset action. Gallery Tag and Progress previews omit their internal reset\nbuttons in favor of this footer action; Docs retains its existing controls.\n`lib/gallery-sources.json` is generated\nby `pnpm compass:export` from the actual preview functions for code copy;\ndo not edit it by hand.\n\nGallery starts with a single ungrouped grid sorted by newest update first.\nHeader and content share responsive horizontal padding (16/32/40px).\nThe text-only wordmark reads \"COMPASS\" in 18px type; the browser title is also\n\"COMPASS\". Docs navigation text shares the same\nleft gutter as the wordmark, accounting for its inner 8px link padding.\nThe desktop wordmark-to-navigation gap is 32px (16px flex gap plus 16px margin).\nHeader theme and language icons use 20px; dropdown checkmarks stay 16px.\nGallery uses a compact filter band, with 8px top content padding, 8px filter\ntop padding, 8px filter bottom padding, and an 8px margin before the grid\n(16px combined distance from filters to cards). Navigation active states use\nneutral foreground color and indicators without changing font weight or element\ndimensions. Active main navigation text and underline use text-foreground and\nborder-foreground (near-black in light mode, near-white in dark mode), not Primary.\nKeep the category filters, including Visual Effects for Heat map.\nInactive filter chips use bg-background (white in light mode); selected chips\nretain bg-foreground and text-background for a neutral active state. Do not show\nNew badges on gallery cards. `lib/gallery-updates.json` tracks source hashes and\nupdate timestamps during export; unchanged examples retain their timestamps.\nGallery previews hide supplementary instructions and interaction status text\nvisually, while retaining screen-reader status announcements and actual\ncomponent content. Docs previews keep their existing interaction feedback.\nDocs spans the viewport with a centered document area capped at 40rem (640px).\nThe Button ToC includes nested group and subsection links matching the heading\nhierarchy, including Shape, Size, and all remaining guideline subsections.\nUse \"미리보기\" (\"Preview\") for preview headings and navigation. Button previews\ndo not show a selected-variant status sentence below the controls.\nOn desktop,\nthe left navigation and right table of contents are fixed to the screen edges\nbelow the header, with independent scrolling and reserved content space.\n\nThe Docs navigation opens `/docs/ai` first. Keep AI setup as the first item\nunder Get Started. The top-right theme menu selects the theme. A separate\nLanguageSelect button beside it selects Korean or English. Theme and language\npreferences persist independently.\nKorean navigation uses localized names, including Elevation as \"높이\", Gallery\nas \"갤러리\", Docs as \"문서\", Get Started as \"시작하기\", Elements as \"기본 요소\",\nand Input/Navigation/Status as \"입력\"/\"탐색\"/\"상태\". Use translate or\nLocaleText consistently for group headings, filters, breadcrumbs and ToC.\nKeep English labels in English mode and preserve the Compass wordmark.\n\n## Updating the AI Reference\n\nRun `pnpm compass:export` after source or guidance changes. This also runs\nbefore `pnpm dev` and `pnpm build`. It exports only the explicitly selected\npublic design-system files; it does not export secrets or the whole repository.\n"}],"docs":"Requires an existing React + Tailwind CSS v4 project initialized with shadcn. COMPASS merges global styles; review existing components and CSS before installing. ThemeProvider must be connected to the application root separately. See /docs/registry and /docs/ai.","meta":{"version":"0.1.0","group":"effects"}}]}