@conscience-technology/ctds 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (289) hide show
  1. package/README.md +128 -2
  2. package/assets/components/AppFrame/AppFrame.module.css +177 -0
  3. package/assets/components/AppFrame/AppFrame.tsx +93 -0
  4. package/assets/components/AppFrame/index.ts +6 -0
  5. package/assets/components/AttachmentChip/AttachmentChip.module.css +71 -0
  6. package/assets/components/AttachmentChip/AttachmentChip.tsx +74 -0
  7. package/assets/components/AttachmentChip/index.ts +2 -0
  8. package/assets/components/AttachmentThumb/AttachmentThumb.module.css +107 -0
  9. package/assets/components/AttachmentThumb/AttachmentThumb.tsx +91 -0
  10. package/assets/components/AttachmentThumb/index.ts +2 -0
  11. package/assets/components/Avatar/Avatar.module.css +167 -0
  12. package/assets/components/Avatar/Avatar.tsx +228 -0
  13. package/assets/components/Avatar/index.ts +2 -0
  14. package/assets/components/AvatarUpload/AvatarUpload.module.css +130 -0
  15. package/assets/components/AvatarUpload/AvatarUpload.tsx +139 -0
  16. package/assets/components/AvatarUpload/index.ts +2 -0
  17. package/assets/components/Badge/Badge.module.css +76 -0
  18. package/assets/components/Badge/Badge.tsx +68 -0
  19. package/assets/components/Badge/index.ts +2 -0
  20. package/assets/components/Breadcrumb/Breadcrumb.module.css +213 -0
  21. package/assets/components/Breadcrumb/Breadcrumb.tsx +279 -0
  22. package/assets/components/Breadcrumb/index.ts +8 -0
  23. package/assets/components/Button/Button.module.css +216 -0
  24. package/assets/components/Button/Button.tsx +149 -0
  25. package/assets/components/Button/index.ts +2 -0
  26. package/assets/components/Callout/Callout.module.css +146 -0
  27. package/assets/components/Callout/Callout.tsx +138 -0
  28. package/assets/components/Callout/index.ts +2 -0
  29. package/assets/components/ChatInput/ChatInput.module.css +241 -0
  30. package/assets/components/ChatInput/ChatInput.tsx +322 -0
  31. package/assets/components/ChatInput/ModelSelector.tsx +40 -0
  32. package/assets/components/ChatInput/SendButton.tsx +41 -0
  33. package/assets/components/ChatInput/index.ts +10 -0
  34. package/assets/components/Checkbox/Checkbox.module.css +66 -0
  35. package/assets/components/Checkbox/Checkbox.tsx +36 -0
  36. package/assets/components/Checkbox/index.ts +2 -0
  37. package/assets/components/Chip/Chip.module.css +128 -0
  38. package/assets/components/Chip/Chip.tsx +103 -0
  39. package/assets/components/Chip/index.ts +2 -0
  40. package/assets/components/ChoiceCard/ChoiceCard.module.css +142 -0
  41. package/assets/components/ChoiceCard/ChoiceCard.tsx +132 -0
  42. package/assets/components/ChoiceCard/index.ts +2 -0
  43. package/assets/components/ContextMenu/ContextMenu.module.css +102 -0
  44. package/assets/components/ContextMenu/ContextMenu.tsx +392 -0
  45. package/assets/components/ContextMenu/index.ts +9 -0
  46. package/assets/components/DatePicker/Calendar.tsx +234 -0
  47. package/assets/components/DatePicker/DESIGN_NOTES.md +106 -0
  48. package/assets/components/DatePicker/DESIGN_NOTES_TIME.md +125 -0
  49. package/assets/components/DatePicker/DatePicker.module.css +295 -0
  50. package/assets/components/DatePicker/DatePicker.tsx +387 -0
  51. package/assets/components/DatePicker/TimeSelector.tsx +69 -0
  52. package/assets/components/DatePicker/index.ts +8 -0
  53. package/assets/components/DatePicker/presets.ts +80 -0
  54. package/assets/components/DatePicker/utils.ts +148 -0
  55. package/assets/components/Disclosure/Disclosure.module.css +73 -0
  56. package/assets/components/Disclosure/Disclosure.tsx +129 -0
  57. package/assets/components/Disclosure/index.ts +6 -0
  58. package/assets/components/Drawer/Drawer.module.css +257 -0
  59. package/assets/components/Drawer/Drawer.tsx +126 -0
  60. package/assets/components/Drawer/index.ts +7 -0
  61. package/assets/components/EmptyState/EmptyState.module.css +102 -0
  62. package/assets/components/EmptyState/EmptyState.tsx +80 -0
  63. package/assets/components/EmptyState/index.ts +2 -0
  64. package/assets/components/FileIcon/FileIcon.module.css +66 -0
  65. package/assets/components/FileIcon/FileIcon.tsx +84 -0
  66. package/assets/components/FileIcon/fileExtMap.ts +112 -0
  67. package/assets/components/FileIcon/index.ts +9 -0
  68. package/assets/components/FilterButton/FilterButton.module.css +130 -0
  69. package/assets/components/FilterButton/FilterButton.tsx +94 -0
  70. package/assets/components/FilterButton/index.ts +2 -0
  71. package/assets/components/GalleryItem/GalleryItem.module.css +220 -0
  72. package/assets/components/GalleryItem/GalleryItem.tsx +163 -0
  73. package/assets/components/GalleryItem/index.ts +7 -0
  74. package/assets/components/Icon/Icon.tsx +616 -0
  75. package/assets/components/Icon/context.tsx +39 -0
  76. package/assets/components/Icon/index.ts +4 -0
  77. package/assets/components/IconButton/IconButton.module.css +109 -0
  78. package/assets/components/IconButton/IconButton.tsx +110 -0
  79. package/assets/components/IconButton/index.ts +2 -0
  80. package/assets/components/Input/Input.module.css +338 -0
  81. package/assets/components/Input/Input.tsx +371 -0
  82. package/assets/components/Input/index.ts +2 -0
  83. package/assets/components/ListItem/ListItem.module.css +318 -0
  84. package/assets/components/ListItem/ListItem.tsx +262 -0
  85. package/assets/components/ListItem/index.ts +9 -0
  86. package/assets/components/MenuItem/MenuItem.module.css +437 -0
  87. package/assets/components/MenuItem/MenuItem.tsx +529 -0
  88. package/assets/components/MenuItem/index.ts +8 -0
  89. package/assets/components/MetricCard/MetricCard.module.css +153 -0
  90. package/assets/components/MetricCard/MetricCard.tsx +140 -0
  91. package/assets/components/MetricCard/index.ts +2 -0
  92. package/assets/components/Modal/Modal.module.css +175 -0
  93. package/assets/components/Modal/Modal.tsx +98 -0
  94. package/assets/components/Modal/index.ts +2 -0
  95. package/assets/components/Onboarding/DocsIndex.tsx +82 -0
  96. package/assets/components/Onboarding/LayoutBuilder.tsx +160 -0
  97. package/assets/components/Onboarding/Onboarding.module.css +1394 -0
  98. package/assets/components/Onboarding/OnboardingAxisPanel.tsx +515 -0
  99. package/assets/components/Onboarding/OnboardingPage.tsx +1193 -0
  100. package/assets/components/Onboarding/PresetsGallery.tsx +65 -0
  101. package/assets/components/Onboarding/actions.ts +250 -0
  102. package/assets/components/Onboarding/index.ts +8 -0
  103. package/assets/components/Onboarding/palette.css +40 -0
  104. package/assets/components/Onboarding/wizardData.ts +265 -0
  105. package/assets/components/Pagination/Pagination.module.css +82 -0
  106. package/assets/components/Pagination/Pagination.tsx +248 -0
  107. package/assets/components/Pagination/index.ts +6 -0
  108. package/assets/components/ProgressBar/ProgressBar.module.css +64 -0
  109. package/assets/components/ProgressBar/ProgressBar.tsx +54 -0
  110. package/assets/components/ProgressBar/index.ts +2 -0
  111. package/assets/components/QuotationBar/QuotationBar.module.css +61 -0
  112. package/assets/components/QuotationBar/QuotationBar.tsx +48 -0
  113. package/assets/components/QuotationBar/index.ts +2 -0
  114. package/assets/components/Radio/Radio.module.css +63 -0
  115. package/assets/components/Radio/Radio.tsx +33 -0
  116. package/assets/components/Radio/index.ts +2 -0
  117. package/assets/components/Select/Select.module.css +151 -0
  118. package/assets/components/Select/Select.tsx +425 -0
  119. package/assets/components/Select/index.ts +10 -0
  120. package/assets/components/SelectableCard/SelectableCard.module.css +177 -0
  121. package/assets/components/SelectableCard/SelectableCard.tsx +83 -0
  122. package/assets/components/SelectableCard/index.ts +2 -0
  123. package/assets/components/Shortcut/Shortcut.module.css +56 -0
  124. package/assets/components/Shortcut/Shortcut.tsx +156 -0
  125. package/assets/components/Shortcut/index.ts +2 -0
  126. package/assets/components/Sidebar/Sidebar.module.css +242 -0
  127. package/assets/components/Sidebar/Sidebar.tsx +264 -0
  128. package/assets/components/Sidebar/index.ts +7 -0
  129. package/assets/components/SidebarSplit/SidebarSplit.module.css +126 -0
  130. package/assets/components/SidebarSplit/SidebarSplit.tsx +222 -0
  131. package/assets/components/SidebarSplit/index.ts +6 -0
  132. package/assets/components/Slider/Slider.module.css +120 -0
  133. package/assets/components/Slider/Slider.tsx +88 -0
  134. package/assets/components/Slider/index.ts +2 -0
  135. package/assets/components/SplitButton/SplitButton.module.css +190 -0
  136. package/assets/components/SplitButton/SplitButton.tsx +145 -0
  137. package/assets/components/SplitButton/index.ts +6 -0
  138. package/assets/components/Stepper/Stepper.module.css +182 -0
  139. package/assets/components/Stepper/Stepper.tsx +185 -0
  140. package/assets/components/Stepper/index.ts +2 -0
  141. package/assets/components/Switch/Switch.module.css +116 -0
  142. package/assets/components/Switch/Switch.tsx +58 -0
  143. package/assets/components/Switch/index.ts +2 -0
  144. package/assets/components/TableCell/TableCell.module.css +137 -0
  145. package/assets/components/TableCell/TableCellAvatar.tsx +42 -0
  146. package/assets/components/TableCell/TableCellBadge.tsx +23 -0
  147. package/assets/components/TableCell/TableCellIcon.tsx +39 -0
  148. package/assets/components/TableCell/TableCellImage.tsx +49 -0
  149. package/assets/components/TableCell/TableCellLink.tsx +33 -0
  150. package/assets/components/TableCell/TableCellMeter.tsx +55 -0
  151. package/assets/components/TableCell/TableCellNumber.tsx +43 -0
  152. package/assets/components/TableCell/TableCellText.tsx +30 -0
  153. package/assets/components/TableCell/index.ts +23 -0
  154. package/assets/components/TableHeader/TableHeader.module.css +287 -0
  155. package/assets/components/TableHeader/TableHeader.tsx +590 -0
  156. package/assets/components/TableHeader/index.ts +9 -0
  157. package/assets/components/TableRow/TableRow.module.css +290 -0
  158. package/assets/components/TableRow/TableRow.tsx +253 -0
  159. package/assets/components/TableRow/index.ts +8 -0
  160. package/assets/components/TableRowEdit/TableRowEdit.module.css +126 -0
  161. package/assets/components/TableRowEdit/TableRowEdit.tsx +247 -0
  162. package/assets/components/TableRowEdit/index.ts +2 -0
  163. package/assets/components/TableRowSelect/TableRowSelect.module.css +23 -0
  164. package/assets/components/TableRowSelect/TableRowSelect.tsx +175 -0
  165. package/assets/components/TableRowSelect/index.ts +2 -0
  166. package/assets/components/Tabs/Tabs.module.css +234 -0
  167. package/assets/components/Tabs/Tabs.tsx +426 -0
  168. package/assets/components/Tabs/index.ts +9 -0
  169. package/assets/components/Textarea/Textarea.module.css +318 -0
  170. package/assets/components/Textarea/Textarea.tsx +426 -0
  171. package/assets/components/Textarea/index.ts +7 -0
  172. package/assets/components/ThemeController.tsx +271 -0
  173. package/assets/components/TimePicker/TimePicker.module.css +317 -0
  174. package/assets/components/TimePicker/TimePicker.tsx +821 -0
  175. package/assets/components/TimePicker/index.ts +8 -0
  176. package/assets/components/TimePicker/utils.ts +115 -0
  177. package/assets/components/Toast/Toast.module.css +264 -0
  178. package/assets/components/Toast/Toast.tsx +243 -0
  179. package/assets/components/Toast/index.ts +15 -0
  180. package/assets/components/Toolbar/Toolbar.module.css +72 -0
  181. package/assets/components/Toolbar/Toolbar.tsx +75 -0
  182. package/assets/components/Toolbar/index.ts +2 -0
  183. package/assets/components/Tooltip/Tooltip.module.css +42 -0
  184. package/assets/components/Tooltip/Tooltip.tsx +332 -0
  185. package/assets/components/Tooltip/index.ts +2 -0
  186. package/assets/components/Topbar/Topbar.module.css +26 -0
  187. package/assets/components/Topbar/Topbar.tsx +47 -0
  188. package/assets/components/Topbar/index.ts +2 -0
  189. package/assets/components/_cn.ts +3 -0
  190. package/assets/components/_color.ts +48 -0
  191. package/assets/components/_data.ts +659 -0
  192. package/assets/components/_utils.css +19 -0
  193. package/assets/components/axisOptions.ts +24 -0
  194. package/assets/components/tokens.css +742 -0
  195. package/assets/prompts/GUIDE.md +251 -0
  196. package/assets/prompts/OVERRIDE.md +170 -0
  197. package/assets/prompts/PRINCIPLES.md +130 -0
  198. package/assets/prompts/axes/density.md +38 -0
  199. package/assets/prompts/axes/font.md +36 -0
  200. package/assets/prompts/axes/hue.md +36 -0
  201. package/assets/prompts/axes/icon.md +48 -0
  202. package/assets/prompts/axes/mode.md +50 -0
  203. package/assets/prompts/axes/motion.md +77 -0
  204. package/assets/prompts/axes/palette.md +35 -0
  205. package/assets/prompts/axes/shape.md +33 -0
  206. package/assets/prompts/axes/voice.md +54 -0
  207. package/assets/prompts/components/README.md +84 -0
  208. package/assets/prompts/components/app-frame.md +94 -0
  209. package/assets/prompts/components/attachment-chip.md +46 -0
  210. package/assets/prompts/components/attachment-thumb.md +49 -0
  211. package/assets/prompts/components/avatar.md +86 -0
  212. package/assets/prompts/components/badge.md +104 -0
  213. package/assets/prompts/components/breadcrumb.md +77 -0
  214. package/assets/prompts/components/button.md +99 -0
  215. package/assets/prompts/components/callout.md +81 -0
  216. package/assets/prompts/components/chat-input.md +84 -0
  217. package/assets/prompts/components/checkbox.md +46 -0
  218. package/assets/prompts/components/chip.md +84 -0
  219. package/assets/prompts/components/choice-card.md +127 -0
  220. package/assets/prompts/components/context-menu.md +145 -0
  221. package/assets/prompts/components/date-picker.md +104 -0
  222. package/assets/prompts/components/drawer.md +152 -0
  223. package/assets/prompts/components/empty-state.md +69 -0
  224. package/assets/prompts/components/file-icon.md +73 -0
  225. package/assets/prompts/components/filter-button.md +42 -0
  226. package/assets/prompts/components/form-field.md +74 -0
  227. package/assets/prompts/components/gallery-item.md +158 -0
  228. package/assets/prompts/components/icon-button.md +82 -0
  229. package/assets/prompts/components/icon.md +68 -0
  230. package/assets/prompts/components/input.md +95 -0
  231. package/assets/prompts/components/list-item.md +235 -0
  232. package/assets/prompts/components/menu-item.md +234 -0
  233. package/assets/prompts/components/metric-card.md +132 -0
  234. package/assets/prompts/components/modal.md +131 -0
  235. package/assets/prompts/components/pagination.md +92 -0
  236. package/assets/prompts/components/progress-bar.md +61 -0
  237. package/assets/prompts/components/quotation-bar.md +39 -0
  238. package/assets/prompts/components/radio.md +41 -0
  239. package/assets/prompts/components/select.md +104 -0
  240. package/assets/prompts/components/selectable-card.md +67 -0
  241. package/assets/prompts/components/shortcut.md +76 -0
  242. package/assets/prompts/components/sidebar.md +107 -0
  243. package/assets/prompts/components/slider.md +89 -0
  244. package/assets/prompts/components/split-button.md +71 -0
  245. package/assets/prompts/components/stepper.md +93 -0
  246. package/assets/prompts/components/switch.md +86 -0
  247. package/assets/prompts/components/table-cell.md +87 -0
  248. package/assets/prompts/components/table-header.md +157 -0
  249. package/assets/prompts/components/table-row-edit.md +129 -0
  250. package/assets/prompts/components/table-row-select.md +82 -0
  251. package/assets/prompts/components/table-row.md +156 -0
  252. package/assets/prompts/components/tabs.md +122 -0
  253. package/assets/prompts/components/textarea.md +105 -0
  254. package/assets/prompts/components/toast.md +149 -0
  255. package/assets/prompts/components/tooltip.md +71 -0
  256. package/assets/prompts/components/topbar.md +148 -0
  257. package/assets/prompts/primitives/emerge.md +43 -0
  258. package/assets/prompts/primitives/fade.md +31 -0
  259. package/assets/prompts/primitives/scale.md +32 -0
  260. package/assets/prompts/primitives/scroll.md +75 -0
  261. package/assets/prompts/primitives/slide.md +31 -0
  262. package/assets/prompts/themes/_SCHEMA.md +135 -0
  263. package/assets/prompts/themes/_TEMPLATE.md +73 -0
  264. package/assets/prompts/themes/expressive.md +118 -0
  265. package/assets/prompts/themes/pure.md +87 -0
  266. package/assets/prompts/themes/spare.md +73 -0
  267. package/assets/prompts/tokens/breakpoint.md +29 -0
  268. package/assets/prompts/tokens/color.md +78 -0
  269. package/assets/prompts/tokens/radius.md +33 -0
  270. package/assets/prompts/tokens/shadow.md +35 -0
  271. package/assets/prompts/tokens/spacing.md +86 -0
  272. package/assets/prompts/tokens/typography.md +76 -0
  273. package/assets/prompts/tokens/z-index.md +35 -0
  274. package/assets/public/expressive.png +0 -0
  275. package/assets/public/pure.png +0 -0
  276. package/assets/public/spare.png +0 -0
  277. package/assets/skill/SKILL.md +36 -0
  278. package/bin/ctds.js +76 -0
  279. package/package.json +35 -4
  280. package/src/commands/init.js +215 -0
  281. package/src/commands/update.js +275 -0
  282. package/src/utils/assets.js +78 -0
  283. package/src/utils/deps.js +51 -0
  284. package/src/utils/detect.js +47 -0
  285. package/src/utils/diff.js +52 -0
  286. package/src/utils/hash.js +16 -0
  287. package/src/utils/log.js +41 -0
  288. package/src/utils/meta.js +73 -0
  289. package/src/utils/prompt.js +28 -0
@@ -0,0 +1,742 @@
1
+ @import url("https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/variable/pretendardvariable.min.css");
2
+ /* Font 축용 폰트 로드 — display=swap + 필요한 웨이트만.
3
+ ko: Pretendard(위) + Nanum Myeongjo(point)
4
+ en: Inter(normal) + Playfair Display(point)
5
+ ja/zh: system fallback 우선, 필요 시 Noto 계열 추가 */
6
+ @import url("https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Playfair+Display:wght@600;700&family=Nanum+Myeongjo:wght@400;700&family=JetBrains+Mono:wght@400;500&display=swap");
7
+ @import "./_utils.css";
8
+
9
+ /* ============================================================
10
+ === TOKENS START ===
11
+ TOKENS — light
12
+ Primitives(원자) + Semantic(역할) 토큰 전부.
13
+ Phase 1.5 스크립트의 파싱 anchor — 이 블록 안의 var 이름이 공식 whitelist.
14
+ ============================================================ */
15
+ :root {
16
+ /* === PRIMITIVES START ===
17
+ 원자 토큰. 축 영향 없음. 다른 토큰이 참조하는 기반.
18
+ 소속: --space-*, --radius-*, --radius-checkbox, --hairline, --scrollbar-size,
19
+ --scroll-fade-size, --control-h-*, --menu-item-h-*, --iconbtn-h-*,
20
+ --icon-size-*, --input-w-*, --font-normal, --font-code, --font-sans,
21
+ --font-mono, --font-scale, --text-*, --lh-*, --tracking-*,
22
+ --font-weight-*, --label-*, --duration-*, --ease-*,
23
+ --motion-scale, --motion-distance-scale, --transition-*, --z-*,
24
+ --shadow-*, --sidebar-w*, --topbar-h*, --header-h, --content-max 등.
25
+ === */
26
+ /* Density 축: --space-scale이 모든 space 토큰과 control-h를 스케일. */
27
+ --space-scale: 1;
28
+ --space-unit: calc(4px * var(--space-scale));
29
+
30
+ --space-0: 0;
31
+ --space-0_5: calc(var(--space-unit) * 0.5);
32
+ --space-1: var(--space-unit);
33
+ --space-1_5: calc(var(--space-unit) * 1.5);
34
+ --space-2: calc(var(--space-unit) * 2);
35
+ --space-2_5: calc(var(--space-unit) * 2.5);
36
+ --space-3: calc(var(--space-unit) * 3);
37
+ --space-4: calc(var(--space-unit) * 4);
38
+ --space-5: calc(var(--space-unit) * 5);
39
+ --space-6: calc(var(--space-unit) * 6);
40
+ --space-8: calc(var(--space-unit) * 8);
41
+ --space-10: calc(var(--space-unit) * 10);
42
+ --space-12: calc(var(--space-unit) * 12);
43
+ --space-16: calc(var(--space-unit) * 16);
44
+ --space-20: calc(var(--space-unit) * 20);
45
+ --space-24: calc(var(--space-unit) * 24);
46
+
47
+ /* Hairline — border 굵기/얇은 divider 고정 1px. Density·Shape 축 영향 없음. */
48
+ --hairline: 1px;
49
+
50
+ /* Scrollbar 두께 — 축 영향 없음, 얇은 오버레이 정책. */
51
+ --scrollbar-size: 8px;
52
+
53
+ /* Scroll fade — 스크롤 컨테이너 상하단(또는 좌우)에 콘텐츠가 잘려 보일 때
54
+ 가장자리를 부드럽게 페이드. --space-4 상당의 그라디언트. */
55
+ --scroll-fade-size: var(--space-4);
56
+
57
+ /* 컨트롤(버튼/인풋/셀렉트) 표준 높이 — Density 축이 스왑.
58
+ xs는 밀도 극한(MenuItem hitbox, IconButton xs) 전용. */
59
+ --control-h-xs: calc(24px * var(--space-scale));
60
+ --control-h-sm: calc(32px * var(--space-scale));
61
+ --control-h-md: calc(36px * var(--space-scale));
62
+ --control-h-lg: calc(40px * var(--space-scale));
63
+
64
+ /* LEGACY ALIAS — 신규 코드는 --control-h-* 직접 참조.
65
+ MenuItem 행 높이는 control 높이와 동일하므로 별칭이 불필요. 점진적 제거 대상. */
66
+ --menu-item-h-sm: var(--control-h-sm);
67
+ --menu-item-h-md: var(--control-h-md);
68
+
69
+ /* IconButton 전용 높이 — 텍스트 컨트롤보다 좁게.
70
+ Button/Input과 정책 분리(아이콘 하나에 넓은 hit area는 시각적으로 헐거움).
71
+ sm=인라인·툴바 초밀도 / md=툴바 기본 / lg=표준. */
72
+ --iconbtn-h-sm: calc(20px * var(--space-scale));
73
+ --iconbtn-h-md: calc(24px * var(--space-scale));
74
+ --iconbtn-h-lg: calc(32px * var(--space-scale));
75
+
76
+ /* 컨트롤 안 아이콘 표준 크기 — Density 축이 스왑.
77
+ 라이브러리별 size prop 처리 편차를 CSS로 svg에 강제. */
78
+ --icon-size-xs: calc(12px * var(--space-scale));
79
+ --icon-size-sm: calc(16px * var(--space-scale));
80
+ --icon-size-md: calc(20px * var(--space-scale));
81
+ --icon-size-lg: calc(24px * var(--space-scale));
82
+
83
+ /* 폼 컨트롤 권장 폭 — Input · Select 등 텍스트 필드 계열이 공유.
84
+ 기본 동작은 부모 폭 채움(fill)이지만, 카드/툴바 안에서 규격을 잡을 때 참조.
85
+ md = 이메일 · 이름 · 짧은 문장 표준. lg = URL · 설명 · 긴 문장.
86
+ 8px(=space-2) 배수라 Density 축 스케일에도 자연스럽게 반응. */
87
+ --input-w-md: calc(280px * var(--space-scale));
88
+ --input-w-lg: calc(400px * var(--space-scale));
89
+
90
+ --radius-none: 0;
91
+ --radius-xs: 6px;
92
+ --radius-sm: 8px;
93
+ --radius-md: 10px;
94
+ --radius-lg: 12px;
95
+ --radius-xl: 14px;
96
+ --radius-2xl: 18px;
97
+ --radius-3xl: 36px;
98
+ --radius-full: 9999px;
99
+
100
+ /* 소형 지표 전용 — 16px 고정 사이즈 컨트롤(체크박스 등)용.
101
+ 기본은 --radius-xs를 그대로 따라가되, soft 축에서만 리터럴 6px로 캡.
102
+ 이유: soft의 radius-xs(10px)는 16px 지표에 과해 원처럼 보임. */
103
+ --radius-checkbox: var(--radius-xs);
104
+
105
+ /* 테이블 셀 썸네일(TableCellImage) circle shape 전용.
106
+ 사람 아바타는 Avatar가 --radius-full을 그대로 쓰지만, 썸네일/문서 아이콘 자리에
107
+ 쓰이는 셀 이미지의 완전 원형은 soft 테마에선 과해 어색 — 2xl로 캡. */
108
+ --radius-image-circle: var(--radius-full);
109
+
110
+ /* Font 축 슬롯 — Language 축이 아래에서 스택을 갈아끼움.
111
+ 컴포넌트는 슬롯 이름(--font-normal/code)만 참조.
112
+ 본문·헤딩은 전부 normal, code/pre 만 code. */
113
+ --font-normal: "Pretendard Variable", Pretendard, -apple-system,
114
+ BlinkMacSystemFont, system-ui, "Segoe UI", Roboto, sans-serif;
115
+ --font-code: "JetBrains Mono", ui-monospace, SFMono-Regular, "SF Mono",
116
+ Menlo, Consolas, "Liberation Mono", monospace;
117
+
118
+ /* LEGACY ALIAS — 신규 코드는 --font-normal / --font-code 직접 참조.
119
+ Tailwind 관례 네이밍(sans/mono)과의 호환성만 유지. 점진적 제거 대상. */
120
+ --font-sans: var(--font-normal);
121
+ --font-mono: var(--font-code);
122
+
123
+ /* Density 축의 --font-scale로 전체 타이포 스케일 스왑 (line-height 포함). */
124
+ --font-scale: 1;
125
+ --text-3xs: calc(11px * var(--font-scale)); --lh-3xs: calc(14px * var(--font-scale));
126
+ --text-2xs: calc(12px * var(--font-scale)); --lh-2xs: calc(16px * var(--font-scale));
127
+ --text-xs: calc(13px * var(--font-scale)); --lh-xs: calc(20px * var(--font-scale));
128
+ --text-sm: calc(14px * var(--font-scale)); --lh-sm: calc(22px * var(--font-scale));
129
+ --text-base: calc(15.5px * var(--font-scale)); --lh-base: calc(26px * var(--font-scale));
130
+ --text-lg: calc(18px * var(--font-scale)); --lh-lg: calc(29px * var(--font-scale));
131
+ --text-xl: calc(20px * var(--font-scale)); --lh-xl: calc(30px * var(--font-scale));
132
+ --text-2xl: calc(24px * var(--font-scale)); --lh-2xl: calc(32px * var(--font-scale));
133
+ --text-3xl: calc(30px * var(--font-scale)); --lh-3xl: calc(38px * var(--font-scale));
134
+ --text-4xl: calc(36px * var(--font-scale)); --lh-4xl: calc(42px * var(--font-scale));
135
+ --text-5xl: calc(48px * var(--font-scale)); --lh-5xl: calc(50px * var(--font-scale));
136
+
137
+ /* Font weight */
138
+ --font-weight-regular: 400;
139
+ --font-weight-medium: 500;
140
+ --font-weight-semibold: 600;
141
+ --font-weight-bold: 700;
142
+
143
+ /* Letter spacing */
144
+ --tracking-tighter: -0.03em;
145
+ --tracking-tight: -0.02em;
146
+ --tracking-normal: 0;
147
+ --tracking-wide: 0.02em;
148
+
149
+ /* Typography preset — 사이즈 토큰과 1:1로 자간이 묶임.
150
+ 컴포넌트는 size/line-height/tracking을 각각 끊어 선언하지 않고
151
+ 이 세트를 함께 참조한다. "text-sm을 쓰는데 자간이 빠진" 상태를 구조적으로 차단.
152
+ 매핑: xs 이하는 normal(가독성), sm/base는 tighter, lg 이상은 tight. */
153
+ --type-3xs-tracking: var(--tracking-normal);
154
+ --type-2xs-tracking: var(--tracking-normal);
155
+ --type-xs-tracking: var(--tracking-normal);
156
+ --type-sm-tracking: var(--tracking-tighter);
157
+ --type-base-tracking: var(--tracking-tighter);
158
+ --type-lg-tracking: var(--tracking-tight);
159
+ --type-xl-tracking: var(--tracking-tight);
160
+ --type-2xl-tracking: var(--tracking-tight);
161
+ --type-3xl-tracking: var(--tracking-tight);
162
+ --type-4xl-tracking: var(--tracking-tight);
163
+ --type-5xl-tracking: var(--tracking-tight);
164
+
165
+ /* Semantic type — 역할 중심 조합 토큰.
166
+ 사이즈 스케일(--text-*)은 값, 이 토큰은 "어디에 쓰이는가"를 담는다.
167
+ Button · MenuItem · Chip · Tab 등 액션 요소의 라벨 전용.
168
+ 두 사이즈: sm(14, 작은 버튼)·md(15, 메뉴·큰 버튼). */
169
+ --label-font: var(--font-normal);
170
+ --label-weight: var(--font-weight-medium);
171
+ --label-tracking: var(--tracking-tighter);
172
+
173
+ --label-sm-size: var(--text-sm);
174
+ --label-sm-line-height: var(--lh-sm);
175
+ --label-md-size: calc(15px * var(--font-scale));
176
+ --label-md-line-height: calc(22px * var(--font-scale));
177
+
178
+ /* Line height (semantic) — 컨트롤 높이 계산 없이 텍스트만 밀착시킬 때.
179
+ tight=1.2 : line-height 1은 descender(g·y·p)가 라인 박스 밖으로 삐져나가
180
+ overflow:hidden 부모에서 잘리므로, 안전 여유값으로 1.2 사용.
181
+ 사이즈 scale 짝(--lh-sm/md/..)과 다른 "역할" 축 — tight은 UI 컨트롤,
182
+ snug은 짧은 문장, loose는 본문 상속용. */
183
+ --lh-tight: 1.2;
184
+ --lh-snug: 1.25;
185
+ --lh-loose: 1.5;
186
+
187
+ /* === PRIMITIVES END === */
188
+
189
+ /* === SEMANTIC START ===
190
+ 역할 토큰. 축 바인딩 받음. 컴포넌트 코드가 참조하는 대상.
191
+ 소속: --hue, --chroma, --lightness, --hue-shift,
192
+ --tone-chroma, --tone-hue, --bg*, --fg*,
193
+ --border*, --primary, --primary-hover, --primary-subtle,
194
+ --secondary-*, --ring*, --icon-color,
195
+ --success*, --warning*, --destructive*, --info*,
196
+ --avatar-tint-*, --hover, --tooltip-*, --sidebar-nav-*,
197
+ --focus-ring-* 등.
198
+ === */
199
+ /* ── Theme axes (color) ─────────────────────────────────────
200
+ Hue 축: 브랜드 컬러(primary/accent/ring)의 색상만 결정.
201
+ Palette 축: chroma·lightness 스왑.
202
+ 무채색 계열(bg/fg/border)은 별도의 --tone-* 사용해서 hue 스왑의 영향 안 받게 함.
203
+ ───────────────────────────────────────────────────────── */
204
+ --hue: 210; /* Hue 프리셋: ocean */
205
+ --chroma: 0.15; /* Palette: standard */
206
+ --lightness: 0.55; /* Palette × Mode 조합이 직접 지정 (아래 selector들 참고) */
207
+ /* Palette가 브랜드 hue를 인접 색조로 이동시킴 (0=원본, +값=warm 방향, -값=cool 방향).
208
+ calm이면 초록→카키·파랑→슬레이트처럼, pastel이면 초록→민트·오렌지→피치처럼
209
+ 자연스러운 인접 톤으로 재해석. 단순 채도 필터가 아님. */
210
+ --hue-shift: 0;
211
+
212
+ --icon-color: var(--primary);
213
+
214
+ /* secondary variant 기본값. 실제 색상은 Palette 블록에서 재지정.
215
+ mono는 무채색, 비mono는 primary 8%. */
216
+ --secondary-bg: oklch(var(--lightness) var(--chroma) calc(var(--hue) + var(--hue-shift)) / 0.08);
217
+ --secondary-bg-hover: oklch(var(--lightness) var(--chroma) calc(var(--hue) + var(--hue-shift)) / 0.14);
218
+ --secondary-fg: var(--primary);
219
+
220
+ /* 무채색 톤 (bg/fg/border 계열이 사용). 살짝의 hue 틴트만 부여 → 순수 회색보다 자연스러움 */
221
+ --tone-hue: 260;
222
+ --tone-chroma: 0.005;
223
+
224
+ /* semantic — light mode */
225
+ --bg: oklch(1 var(--tone-chroma) var(--tone-hue));
226
+ --bg-subtle: oklch(0.978 var(--tone-chroma) var(--tone-hue));
227
+ --bg-muted: oklch(0.955 var(--tone-chroma) var(--tone-hue));
228
+ --fg-strong: oklch(0.12 var(--tone-chroma) var(--tone-hue));
229
+ --fg: oklch(0.22 var(--tone-chroma) var(--tone-hue));
230
+ --fg-muted: oklch(0.50 var(--tone-chroma) var(--tone-hue));
231
+ --fg-subtle: oklch(0.68 var(--tone-chroma) var(--tone-hue));
232
+ --fg-disabled: oklch(0.80 var(--tone-chroma) var(--tone-hue));
233
+ /* border는 배경 대비 알파 기반 hairline — 겹치면 자연스럽게 짙어짐.
234
+ 라이트 모드: 어두운 잉크 톤(≈rgb(18,24,38))을 낮은 알파로 얹음. */
235
+ --border: oklch(0.18 var(--tone-chroma) var(--tone-hue) / 0.08);
236
+ --border-strong: oklch(0.18 var(--tone-chroma) var(--tone-hue) / 0.14);
237
+
238
+ /* primary — 브랜드 컬러. Hue × Palette 축이 여기 반영됨.
239
+ 실제 hue는 (--hue + --hue-shift)로, Palette가 인접 색조로 이동시킬 수 있음.
240
+ primary 위 텍스트/아이콘은 var(--bg) 사용 (라이트=흰색, 다크=거의 검정).
241
+ 별도 --primary-fg 토큰을 두지 않는 이유: bg가 항상 primary 반대편 극단에 있어 자동으로 대비 충분. */
242
+ --primary: oklch(var(--lightness) var(--chroma) calc(var(--hue) + var(--hue-shift)));
243
+ --ring: oklch(var(--lightness) var(--chroma) calc(var(--hue) + var(--hue-shift)) / 0.35);
244
+ --ring-width: var(--space-0_5);
245
+ --ring-offset: var(--space-0_5);
246
+ /* 박스 바깥 --ring-offset 만큼 --bg 여백을 만든 뒤, 그 바깥으로 --ring-width 굵기 링. */
247
+ --ring-shadow: 0 0 0 var(--ring-offset) var(--bg),
248
+ 0 0 0 calc(var(--ring-offset) + var(--ring-width)) var(--ring);
249
+ --ring-shadow-invalid: 0 0 0 var(--ring-offset) var(--bg),
250
+ 0 0 0 calc(var(--ring-offset) + var(--ring-width))
251
+ color-mix(in oklab, var(--destructive) 35%, transparent);
252
+
253
+ /* status — hue 고정 (성공은 항상 초록, 경고는 항상 주황 등).
254
+ Palette 축의 --chroma/--lightness와 분리된 --status-chroma/--status-lightness를 사용해
255
+ 경고색이 팔레트 때문에 디자인 컬러처럼 보이는 문제를 방지.
256
+ 팔레트 그룹별로 아래에서 살짝씩 다르게 지정 (vivid/standard=표준, calm=약간 순화, pastel=약간 연화). */
257
+ --status-chroma: 0.17;
258
+ --status-lightness: 0.55;
259
+ --success: oklch(var(--status-lightness) var(--status-chroma) 145);
260
+ --warning: oklch(var(--status-lightness) var(--status-chroma) 70);
261
+ --destructive: oklch(var(--status-lightness) var(--status-chroma) 20);
262
+ --info: oklch(var(--status-lightness) var(--status-chroma) 230);
263
+ /* status foreground — status fill 위 텍스트. 항상 밝게 유지 (light/dark 공통) */
264
+ --destructive-fg: oklch(0.985 var(--tone-chroma) var(--tone-hue));
265
+ --success-fg: oklch(0.985 var(--tone-chroma) var(--tone-hue));
266
+ --warning-fg: oklch(0.15 var(--tone-chroma) var(--tone-hue));
267
+ --info-fg: oklch(0.985 var(--tone-chroma) var(--tone-hue));
268
+
269
+ /* status/primary hover — 채워진 색(X)이 hover 상태일 때 어두워진 버전.
270
+ 공식: X 88% + fg 12%. 검정 오버레이 얹으면 채도가 죽어 별도 파생 토큰 유지. */
271
+ --primary-hover: color-mix(in oklab, var(--primary) 88%, var(--fg) 12%);
272
+ --destructive-hover: color-mix(in oklab, var(--destructive) 88%, var(--fg) 12%);
273
+ --success-hover: color-mix(in oklab, var(--success) 88%, var(--fg) 12%);
274
+ --warning-hover: color-mix(in oklab, var(--warning) 88%, var(--fg) 12%);
275
+ --info-hover: color-mix(in oklab, var(--info) 88%, var(--fg) 12%);
276
+
277
+ /* status/primary subtle — 컬러 힌트가 필요한 soft 표면 (Badge, Callout, IconButton destructive hover 등).
278
+ 공식: X 8% transparent. */
279
+ --primary-subtle: color-mix(in oklab, var(--primary) 8%, transparent);
280
+ --destructive-subtle: color-mix(in oklab, var(--destructive) 8%, transparent);
281
+ --success-subtle: color-mix(in oklab, var(--success) 8%, transparent);
282
+ --warning-subtle: color-mix(in oklab, var(--warning) 8%, transparent);
283
+ --info-subtle: color-mix(in oklab, var(--info) 8%, transparent);
284
+
285
+ /* status/primary border — subtle 표면과 짝을 이루는 경계 (Callout outline 등).
286
+ 공식: X 32% transparent. */
287
+ --primary-border-color: color-mix(in oklab, var(--primary) 32%, transparent);
288
+ --destructive-border-color: color-mix(in oklab, var(--destructive) 32%, transparent);
289
+ --success-border-color: color-mix(in oklab, var(--success) 32%, transparent);
290
+ --warning-border-color: color-mix(in oklab, var(--warning) 32%, transparent);
291
+ --info-border-color: color-mix(in oklab, var(--info) 32%, transparent);
292
+
293
+ /* interactive / overlay
294
+ --hover: 컴포넌트 hover 시 표면·그림자에 얹는 공통 오버레이.
295
+ 라이트=검정 3%, 다크=흰색 3%. 데이터 테이블·리스트 등 반복 행에서
296
+ "너무 두드러지지 않는" 톤. */
297
+ --hover: oklch(0 0 0 / 0.03);
298
+ /* tooltip: Mode 반전. 라이트에선 다크 bg + 밝은 fg, 다크에선 라이트 bg + 어두운 fg.
299
+ 페이지 전체 톤과 반대로 떠서 "일시 노출" 성격을 명확히. 다크 모드 재선언은 아래 블록. */
300
+ --tooltip-bg: oklch(0.18 0.005 260);
301
+ --tooltip-fg: oklch(1 0 0);
302
+ /* scrim: 이미지·모달 위에 얹는 다크 오버레이 표면.
303
+ mode 무관하게 검정 계열 반투명 — "빛을 가리는" 성격이라 반전 안 함.
304
+ scrim-fg는 그 위에 놓이는 텍스트·아이콘 색으로 항상 흰색. */
305
+ --scrim: oklch(0 0 0 / 0.55);
306
+ --scrim-fg: oklch(1 0 0);
307
+
308
+ /* shadow 색: oklch(L C H) 세 성분. 알파는 shadow 단계별 상수.
309
+ 테마가 override 하면 전체 그림자 톤이 스왑 (예: --shadow-color: 0.15 0.03 40 → warm tint shadow). */
310
+ --shadow-color: 0 0 0;
311
+
312
+ --shadow-xs: 0 1px 2px oklch(var(--shadow-color) / 0.04);
313
+ --shadow-sm: 0 1px 3px oklch(var(--shadow-color) / 0.06), 0 1px 2px oklch(var(--shadow-color) / 0.04);
314
+ --shadow-md: 0 6px 16px -4px oklch(var(--shadow-color) / 0.07),
315
+ 0 2px 6px -2px oklch(var(--shadow-color) / 0.04);
316
+ --shadow-lg: 0 12px 20px -6px oklch(var(--shadow-color) / 0.1),
317
+ 0 4px 8px -4px oklch(var(--shadow-color) / 0.06);
318
+ --shadow-xl: 0 24px 40px -12px oklch(var(--shadow-color) / 0.16);
319
+ --shadow-inner: inset 0 1px 2px oklch(var(--shadow-color) / 0.06);
320
+ /* drop-shadow 전용 단일 shadow (SVG·filter 컨텍스트에서 콤마 shadow 불가) */
321
+ --shadow-drop: 0 var(--space-1) 12px oklch(var(--shadow-color) / 0.16);
322
+
323
+ /* Motion 축: --motion-scale이 모든 duration을 스케일, --ease-emphasized가 성격을 결정.
324
+ Motion=standard일 때 아래 값이 그대로 사용됨. */
325
+ --motion-scale: 1;
326
+ --motion-distance-scale: 1;
327
+
328
+ /* Base duration 값은 2026 웹 표준(Vercel 150-250ms · Linear 100-350ms) 참고.
329
+ 150ms 미만은 flicker처럼 느껴진다는 임계 존재. Motion 축이 --motion-scale로 조절. */
330
+ --duration-fast: calc(80ms * var(--motion-scale)); /* hover, tap · 최소 임계 100ms 근처 */
331
+ --duration-base: calc(160ms * var(--motion-scale)); /* 표준 상호작용 */
332
+ --duration-slow: calc(240ms * var(--motion-scale)); /* 오버레이 등장 */
333
+ --duration-slower: calc(360ms * var(--motion-scale)); /* 페이지/뷰 전환 */
334
+
335
+ --ease-linear: linear;
336
+ --ease-in: cubic-bezier(0.4, 0, 1, 1);
337
+ --ease-out: cubic-bezier(0, 0, 0.2, 1);
338
+ --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
339
+ --ease-emphasized: cubic-bezier(0.2, 0, 0, 1);
340
+
341
+ /* Interaction transition presets — 컴포넌트 hover/press/focus의 톤을 통일한다.
342
+ 원칙:
343
+ - 색·보더는 slow → hover가 스르륵 물들며 소음이 적음
344
+ - focus ring은 fast → 키보드 사용자에게 즉각 피드백
345
+ - press(transform)는 base → 진입·해제 대칭
346
+ 모든 인터랙티브 컴포넌트(Button/IconButton/MenuItem/Input/Tabs 등)는
347
+ 이 3종을 조합해서 쓸 것. transition 값을 컴포넌트에 직접 적지 말고
348
+ 반드시 이 토큰을 경유. */
349
+ --transition-colors:
350
+ background var(--duration-slow) var(--ease-out),
351
+ color var(--duration-slow) var(--ease-out),
352
+ border-color var(--duration-slow) var(--ease-out);
353
+ --transition-ring: box-shadow var(--duration-fast) var(--ease-out);
354
+ --transition-press: transform var(--duration-base) var(--ease-out);
355
+
356
+ --z-base: 0;
357
+ /* 로컬 스택 조정용 최소 상대 z. 컴포넌트 내부에서 형제끼리
358
+ "위에 얹기"가 필요할 때 이 토큰을 쓴다(리터럴 1/2 대체). */
359
+ --z-raise: 1;
360
+ --z-raised: 2;
361
+ --z-docked: 10;
362
+ --z-dropdown: 1000;
363
+ --z-sticky: 1100;
364
+ --z-overlay: 1300;
365
+ --z-modal: 1400;
366
+ --z-popover: 1500;
367
+ --z-toast: 1600;
368
+ --z-tooltip: 1700;
369
+
370
+ --sidebar-w: 260px;
371
+ --sidebar-w-collapsed: calc(var(--control-h-lg) + var(--space-4));
372
+ --topbar-h-sm: var(--space-12);
373
+ --topbar-h-md: var(--space-16);
374
+ --topbar-h: var(--topbar-h-md);
375
+ /* Sidebar Brand — symbol/wordmark 최대 높이(상한).
376
+ 각각 아이콘/로고 SVG가 이 값을 넘지 않도록 CSS로 강제. */
377
+ --sidebar-brand-symbol-max: var(--control-h-lg);
378
+ --sidebar-brand-wordmark-max: var(--control-h-md);
379
+ --content-max: 800px;
380
+ /* anchor 섹션 스크롤 오프셋 — Topbar 제거로 0. 유지 사유: 변수 참조처가 섹션
381
+ scroll-margin-top/스크롤 padding 2곳이라 token 하나로 바꾸는 게 안전. */
382
+ --header-h: 0px;
383
+ /* === SEMANTIC END === */
384
+ }
385
+ /* === TOKENS END === */
386
+
387
+ /* ============================================================
388
+ === AXES START ===
389
+ 축 셀렉터 블록. 각 축의 값별 토큰 스왑.
390
+ 소속: html[data-focus-ring], [data-palette], [data-shape], [data-density],
391
+ [data-motion], [data-lang], [data-mode="dark"],
392
+ @media (prefers-reduced-motion).
393
+ ============================================================ */
394
+ /* Focus-ring 축: html[data-focus-ring="off"]면 링 숨김.
395
+ 모든 컴포넌트는 var(--ring-shadow)만 참조하면 자동 반응. */
396
+ html[data-focus-ring="off"] {
397
+ --ring-shadow: none;
398
+ --ring-shadow-invalid: none;
399
+ }
400
+
401
+ /* ── Palette 축 ─────────────────────────────────────────────
402
+ OKLCH의 chroma·lightness + hue-shift를 세트로 스왑.
403
+ 단순 채도 필터가 아니라 팔레트 스타일 자체를 바꿈:
404
+ - mono: 채도 0. 무채색 지배. 아이콘·secondary도 fg 톤.
405
+ - vivid: 원본 hue, 진한 채도, 표준 명도. 강렬한 브랜드 톤.
406
+ - standard: 원본 hue, 중간 채도. 무난한 기본.
407
+ - calm: +18° hue-shift(warm쪽), 중간 채도, 살짝 낮은 명도. 깊고 차분한 톤 (버건디/청록/포레스트).
408
+ 초록→카키/포레스트, 파랑→틸/슬레이트, 오렌지→테라코타/버건디 계열.
409
+ - pastel: -12° hue-shift(cool쪽), 중간 채도, 밝은 명도. 부드럽지만 색감이 살아있는 톤.
410
+ 초록→민트/세이지, 오렌지→피치, 파랑→베이비블루 계열.
411
+ Mode(dark)는 아래 [data-mode="dark"][data-palette="*"]에서 lightness만 별도 지정. */
412
+ [data-palette="mono"] { --chroma: 0; --lightness: 0.18; --hue-shift: 0; }
413
+ [data-palette="vivid"] { --chroma: 0.20; --lightness: 0.58; --hue-shift: 0; }
414
+ [data-palette="standard"] { --chroma: 0.14; --lightness: 0.55; --hue-shift: 0; }
415
+ [data-palette="calm"] { --chroma: 0.12; --lightness: 0.52; --hue-shift: 18; }
416
+ [data-palette="pastel"] { --chroma: 0.13; --lightness: 0.75; --hue-shift: -12; }
417
+
418
+ /* status 축은 팔레트별로 거의 고정 — 경고색이 디자인 컬러처럼 보이지 않도록 최소 강도 보장.
419
+ 그룹별 미세 차이만 허용 (vivid/standard=표준, calm=약간 순화, pastel=약간 연화).
420
+ mono는 상태색만큼은 유색 유지(사용자 안전 신호). */
421
+ [data-palette="mono"],
422
+ [data-palette="vivid"],
423
+ [data-palette="standard"] { --status-chroma: 0.17; --status-lightness: 0.55; }
424
+ [data-palette="calm"] { --status-chroma: 0.17; --status-lightness: 0.53; }
425
+ [data-palette="pastel"] { --status-chroma: 0.16; --status-lightness: 0.58; }
426
+
427
+ /* Palette별 color-usage 효과 — 과거 Accent 축이 담당하던 토큰을 Palette로 흡수.
428
+ - mono: 표면·secondary 무채색, 아이콘도 fg-muted. primary는 CTA/상태 등 소수 지점에만.
429
+ - 비mono: 아이콘·포커스·nav-active·secondary 전부 primary 톤. */
430
+ [data-palette="mono"] {
431
+ --icon-color: var(--fg-muted);
432
+ --selected-fg: var(--fg);
433
+ --secondary-bg: var(--bg-muted);
434
+ --secondary-bg-hover: color-mix(in oklab, var(--bg-muted) 70%, var(--fg) 30%);
435
+ --secondary-fg: var(--fg);
436
+ }
437
+ [data-palette="vivid"],
438
+ [data-palette="standard"],
439
+ [data-palette="calm"],
440
+ [data-palette="pastel"] {
441
+ --icon-color: var(--primary);
442
+ --selected-fg: var(--primary);
443
+ --secondary-bg: oklch(var(--lightness) var(--chroma) calc(var(--hue) + var(--hue-shift)) / 0.08);
444
+ --secondary-bg-hover: oklch(var(--lightness) var(--chroma) calc(var(--hue) + var(--hue-shift)) / 0.14);
445
+ --secondary-fg: var(--primary);
446
+ }
447
+
448
+ /* ── Avatar 이니셜 팔레트 ─────────────────────────────────
449
+ 유저·팀 이름 해시로 자동 매핑되는 10색 순환.
450
+ Radix Colors의 step 3(subtle bg) + step 11(low-contrast text) 조합 참고 —
451
+ 배경은 눈에 편한 연한 tint, 텍스트는 같은 hue의 진한 톤으로 높은 가독성.
452
+ 축 영향 안 받는 고정 팔레트 (사용자 식별용이라 흔들리지 않는 게 맞음). */
453
+ :root {
454
+ /* tomato */ --avatar-tint-0-bg: oklch(0.928 0.038 27); --avatar-tint-0-fg: oklch(0.545 0.190 32);
455
+ /* orange */ --avatar-tint-1-bg: oklch(0.925 0.055 70); --avatar-tint-1-fg: oklch(0.545 0.155 55);
456
+ /* amber */ --avatar-tint-2-bg: oklch(0.925 0.055 90); --avatar-tint-2-fg: oklch(0.500 0.115 75);
457
+ /* grass */ --avatar-tint-3-bg: oklch(0.935 0.055 140); --avatar-tint-3-fg: oklch(0.525 0.135 145);
458
+ /* teal */ --avatar-tint-4-bg: oklch(0.930 0.048 175); --avatar-tint-4-fg: oklch(0.500 0.100 180);
459
+ /* cyan */ --avatar-tint-5-bg: oklch(0.930 0.045 210); --avatar-tint-5-fg: oklch(0.545 0.135 225);
460
+ /* blue */ --avatar-tint-6-bg: oklch(0.930 0.045 255); --avatar-tint-6-fg: oklch(0.520 0.170 260);
461
+ /* violet */ --avatar-tint-7-bg: oklch(0.925 0.050 295); --avatar-tint-7-fg: oklch(0.510 0.180 285);
462
+ /* plum */ --avatar-tint-8-bg: oklch(0.920 0.055 330); --avatar-tint-8-fg: oklch(0.520 0.180 330);
463
+ /* pink */ --avatar-tint-9-bg: oklch(0.925 0.048 355); --avatar-tint-9-fg: oklch(0.545 0.190 355);
464
+ }
465
+
466
+ /* ── Shape 축 ───────────────────────────────────────────────
467
+ radius + shadow 세트로 스왑. border 굵기는 1px 고정(축 영향 없음).
468
+ 기본은 standard (soft와 crisp의 산술 중간, :root 값과 동일). */
469
+ [data-shape="soft"] {
470
+ --radius-xs: 10px;
471
+ --radius-sm: 12px;
472
+ --radius-md: 14px;
473
+ --radius-lg: 16px;
474
+ --radius-xl: 16px;
475
+ --radius-2xl: 20px;
476
+ --radius-3xl: 44px;
477
+
478
+ /* soft에서 radius-xs(10px)는 16px 체크박스에 과함 — 6px로 캡 */
479
+ --radius-checkbox: 6px;
480
+
481
+ /* soft 테마는 전반적으로 둥글어서 썸네일 circle이 완전 원이면 과함 — 2xl로 캡 */
482
+ --radius-image-circle: var(--radius-2xl);
483
+
484
+ --shadow-xs: 0 1px 2px oklch(var(--shadow-color) / 0.04);
485
+ --shadow-sm: 0 2px 6px -1px oklch(var(--shadow-color) / 0.06), 0 1px 2px oklch(var(--shadow-color) / 0.04);
486
+ --shadow-md: 0 8px 20px -4px oklch(var(--shadow-color) / 0.08), 0 3px 8px -3px oklch(var(--shadow-color) / 0.04);
487
+ --shadow-lg: 0 16px 32px -8px oklch(var(--shadow-color) / 0.14), 0 6px 12px -6px oklch(var(--shadow-color) / 0.06);
488
+ --shadow-xl: 0 32px 60px -14px oklch(var(--shadow-color) / 0.20);
489
+ }
490
+
491
+ /* standard — soft와 crisp의 산술 중간. 무난한 표준값. */
492
+ [data-shape="standard"] {
493
+ --radius-xs: 6px;
494
+ --radius-sm: 8px;
495
+ --radius-md: 10px;
496
+ --radius-lg: 12px;
497
+ --radius-xl: 14px;
498
+ --radius-2xl: 18px;
499
+ --radius-3xl: 36px;
500
+
501
+ --shadow-xs: 0 1px 2px oklch(var(--shadow-color) / 0.04);
502
+ --shadow-sm: 0 1px 3px oklch(var(--shadow-color) / 0.06), 0 1px 2px oklch(var(--shadow-color) / 0.04);
503
+ --shadow-md: 0 6px 16px -4px oklch(var(--shadow-color) / 0.07), 0 2px 6px -2px oklch(var(--shadow-color) / 0.04);
504
+ --shadow-lg: 0 12px 20px -6px oklch(var(--shadow-color) / 0.10), 0 4px 8px -4px oklch(var(--shadow-color) / 0.06);
505
+ --shadow-xl: 0 24px 40px -12px oklch(var(--shadow-color) / 0.16);
506
+ }
507
+
508
+ /* ── Density 축 ─────────────────────────────────────────────
509
+ --space-scale 로 --space-* 와 --control-h-* 를 스왑.
510
+ --font-scale 로 --text-* / --lh-* 를 스왑 (위계 유지 위해 폭 좁게). */
511
+ [data-density="compact"] { --space-scale: 0.94; --font-scale: 0.98; }
512
+ [data-density="default"] { --space-scale: 1; --font-scale: 1; }
513
+ [data-density="comfortable"] { --space-scale: 1.06; --font-scale: 1.02; }
514
+
515
+ /* ── Motion 축 ──────────────────────────────────────────────
516
+ Vercel/Linear 스타일 참고 — 짧고 매끈함. Base=160ms 기준.
517
+ 차이는 이징 곡선에서 나옴(속도는 세 프리셋 다 근접).
518
+ none은 축을 통한 강제 off, prefers-reduced-motion은 아래에서 별도 강제. */
519
+ [data-motion="bouncy"] {
520
+ --motion-scale: 1.2; /* ~192ms · 오버슛 여운만큼 */
521
+ --motion-distance-scale: 1.1;
522
+ --ease-emphasized: cubic-bezier(0.34, 1.4, 0.64, 1); /* 절제된 오버슛 spring */
523
+ }
524
+ [data-motion="standard"] {
525
+ --motion-scale: 1; /* 160ms */
526
+ --motion-distance-scale: 1;
527
+ --ease-emphasized: cubic-bezier(0.32, 0.72, 0, 1); /* Linear/Vercel ease-out */
528
+ }
529
+ [data-motion="calm"] {
530
+ --motion-scale: 0.9; /* ~144ms · flat 곡선이라 짧아도 안전 */
531
+ --motion-distance-scale: 0.9;
532
+ --ease-emphasized: cubic-bezier(0.4, 0, 0.2, 1); /* 표준 ease-out · 심심할수록 차분 */
533
+ }
534
+ [data-motion="none"] {
535
+ --motion-scale: 0;
536
+ --motion-distance-scale: 0;
537
+ }
538
+ [data-motion="none"] *,
539
+ [data-motion="none"] *::before,
540
+ [data-motion="none"] *::after {
541
+ animation-duration: 0.001ms !important;
542
+ animation-iteration-count: 1 !important;
543
+ transition-duration: 0.001ms !important;
544
+ }
545
+
546
+ /* 접근성 우선 — 사용자 OS 설정이 축 값을 이김 */
547
+ @media (prefers-reduced-motion: reduce) {
548
+ :root {
549
+ --motion-scale: 0;
550
+ --motion-distance-scale: 0;
551
+ }
552
+ *,
553
+ *::before,
554
+ *::after {
555
+ animation-duration: 0.001ms !important;
556
+ animation-iteration-count: 1 !important;
557
+ transition-duration: 0.001ms !important;
558
+ }
559
+ }
560
+
561
+ /* ── Font 축 — Language ─────────────────────────────────────
562
+ 슬롯(--font-normal/code)의 스택을 언어별로 스왑.
563
+ 프로젝트마다 여기서 바꾸면 됨. */
564
+ [data-lang="ko"] {
565
+ --font-normal: "Pretendard Variable", Pretendard, -apple-system,
566
+ BlinkMacSystemFont, system-ui, sans-serif;
567
+ --font-code: "JetBrains Mono", ui-monospace, monospace;
568
+ }
569
+ [data-lang="en"] {
570
+ --font-normal: "Inter", -apple-system, BlinkMacSystemFont, system-ui,
571
+ "Segoe UI", Roboto, sans-serif;
572
+ --font-code: "JetBrains Mono", ui-monospace, monospace;
573
+ }
574
+ [data-lang="ja"] {
575
+ --font-normal: "Hiragino Sans", "Yu Gothic", "Noto Sans JP",
576
+ -apple-system, sans-serif;
577
+ --font-code: "JetBrains Mono", ui-monospace, monospace;
578
+ }
579
+ [data-lang="zh"] {
580
+ --font-normal: "PingFang SC", "Microsoft YaHei", "Noto Sans SC",
581
+ -apple-system, sans-serif;
582
+ --font-code: "JetBrains Mono", ui-monospace, monospace;
583
+ }
584
+
585
+ [data-shape="crisp"] {
586
+ --radius-xs: 3px;
587
+ --radius-sm: 4px;
588
+ --radius-md: 6px;
589
+ --radius-lg: 10px;
590
+ --radius-xl: 14px;
591
+ --radius-2xl: 18px;
592
+ --radius-3xl: 22px;
593
+
594
+ --shadow-xs: 0 1px 0 oklch(var(--shadow-color) / 0.06);
595
+ --shadow-sm: 0 1px 2px oklch(var(--shadow-color) / 0.08), 0 0 0 1px oklch(var(--shadow-color) / 0.04);
596
+ --shadow-md: 0 2px 4px oklch(var(--shadow-color) / 0.10), 0 0 0 1px oklch(var(--shadow-color) / 0.06);
597
+ --shadow-lg: 0 4px 8px oklch(var(--shadow-color) / 0.12), 0 0 0 1px oklch(var(--shadow-color) / 0.06);
598
+ --shadow-xl: 0 8px 16px oklch(var(--shadow-color) / 0.16), 0 0 0 1px oklch(var(--shadow-color) / 0.06);
599
+ }
600
+
601
+ /* [data-mode="dark"]는 루트뿐 아니라 하위 스코프에서도 유효.
602
+ 라이트 모드 페이지 내 국소적으로 어두운 표면이 필요할 때 컨테이너에 감싸면
603
+ 그 서브트리의 --bg/--fg/--border/--shadow가 다크로 자동 반전된다.
604
+ IconButton 등 컴포넌트는 별도 tone prop 없이 기존 시맨틱 토큰을 그대로 사용. */
605
+ :root[data-mode="dark"],
606
+ [data-mode="dark"] {
607
+ --bg: oklch(0.20 var(--tone-chroma) var(--tone-hue));
608
+ --bg-subtle: oklch(0.25 var(--tone-chroma) var(--tone-hue));
609
+ --bg-muted: oklch(0.31 var(--tone-chroma) var(--tone-hue));
610
+ --fg-strong: oklch(1.0 var(--tone-chroma) var(--tone-hue));
611
+ --fg: oklch(0.95 var(--tone-chroma) var(--tone-hue));
612
+ --fg-muted: oklch(0.65 var(--tone-chroma) var(--tone-hue));
613
+ --fg-subtle: oklch(0.48 var(--tone-chroma) var(--tone-hue));
614
+ --fg-disabled: oklch(0.35 var(--tone-chroma) var(--tone-hue));
615
+ /* 다크 모드: fg 톤(밝은 잉크)을 낮은 알파로 얹음. */
616
+ --border: oklch(0.95 var(--tone-chroma) var(--tone-hue) / 0.08);
617
+ --border-strong: oklch(0.95 var(--tone-chroma) var(--tone-hue) / 0.16);
618
+
619
+ /* primary / status는 :root의 정의를 그대로 사용 — --lightness가 아래에서 재정의되어 자동 반영됨 */
620
+
621
+ --hover: oklch(1 0 0 / 0.06);
622
+ /* tooltip은 Mode 반전 — 다크 모드에선 밝은 bg + 어두운 fg. */
623
+ --tooltip-bg: oklch(0.95 var(--tone-chroma) var(--tone-hue));
624
+ --tooltip-fg: oklch(0.18 var(--tone-chroma) var(--tone-hue));
625
+
626
+ /* 다크도 --shadow-color는 검정 유지 — 그림자는 "빛의 반대". 알파만 상향해 어두운 bg 위에서도 보이게. */
627
+ --shadow-xs: 0 1px 2px oklch(var(--shadow-color) / 0.4);
628
+ --shadow-sm: 0 1px 3px oklch(var(--shadow-color) / 0.5);
629
+ --shadow-md: 0 6px 16px -4px oklch(var(--shadow-color) / 0.45), 0 2px 6px -2px oklch(var(--shadow-color) / 0.3);
630
+ --shadow-lg: 0 12px 20px -6px oklch(var(--shadow-color) / 0.55);
631
+ --shadow-xl: 0 24px 40px -12px oklch(var(--shadow-color) / 0.6);
632
+ --shadow-drop: 0 var(--space-1) 12px oklch(var(--shadow-color) / 0.6);
633
+
634
+ /* Avatar 이니셜 팔레트 — 다크: 배경은 어두운 tint, 텍스트는 밝은 tint */
635
+ /* tomato */ --avatar-tint-0-bg: oklch(0.320 0.075 27); --avatar-tint-0-fg: oklch(0.850 0.100 30);
636
+ /* orange */ --avatar-tint-1-bg: oklch(0.325 0.075 60); --avatar-tint-1-fg: oklch(0.860 0.100 70);
637
+ /* amber */ --avatar-tint-2-bg: oklch(0.320 0.065 85); --avatar-tint-2-fg: oklch(0.880 0.110 90);
638
+ /* grass */ --avatar-tint-3-bg: oklch(0.325 0.070 140); --avatar-tint-3-fg: oklch(0.860 0.100 145);
639
+ /* teal */ --avatar-tint-4-bg: oklch(0.320 0.060 180); --avatar-tint-4-fg: oklch(0.860 0.080 180);
640
+ /* cyan */ --avatar-tint-5-bg: oklch(0.325 0.065 220); --avatar-tint-5-fg: oklch(0.860 0.095 220);
641
+ /* blue */ --avatar-tint-6-bg: oklch(0.325 0.075 255); --avatar-tint-6-fg: oklch(0.850 0.110 260);
642
+ /* violet */ --avatar-tint-7-bg: oklch(0.325 0.080 290); --avatar-tint-7-fg: oklch(0.850 0.115 290);
643
+ /* plum */ --avatar-tint-8-bg: oklch(0.320 0.075 325); --avatar-tint-8-fg: oklch(0.850 0.110 325);
644
+ /* pink */ --avatar-tint-9-bg: oklch(0.325 0.075 355); --avatar-tint-9-fg: oklch(0.860 0.115 355);
645
+ }
646
+
647
+ /* ── Dark × Shape ───────────────────────────────────────────
648
+ [data-shape="soft|crisp"]의 shadow 알파는 라이트 기준. 다크 모드에서 shape 재정의가
649
+ 라이트 알파를 상속하지 않도록, 다크+shape 조합에서 다크 수준으로 알파 상향.
650
+ standard는 [data-mode="dark"] 블록이 이미 커버. */
651
+ :root[data-mode="dark"][data-shape="soft"],
652
+ [data-mode="dark"][data-shape="soft"] {
653
+ --shadow-xs: 0 1px 2px oklch(var(--shadow-color) / 0.4);
654
+ --shadow-sm: 0 2px 6px -1px oklch(var(--shadow-color) / 0.5), 0 1px 2px oklch(var(--shadow-color) / 0.3);
655
+ --shadow-md: 0 8px 20px -4px oklch(var(--shadow-color) / 0.5), 0 3px 8px -3px oklch(var(--shadow-color) / 0.3);
656
+ --shadow-lg: 0 16px 32px -8px oklch(var(--shadow-color) / 0.55), 0 6px 12px -6px oklch(var(--shadow-color) / 0.35);
657
+ --shadow-xl: 0 32px 60px -14px oklch(var(--shadow-color) / 0.6);
658
+ }
659
+
660
+ :root[data-mode="dark"][data-shape="crisp"],
661
+ [data-mode="dark"][data-shape="crisp"] {
662
+ --shadow-xs: 0 1px 0 oklch(var(--shadow-color) / 0.4);
663
+ --shadow-sm: 0 1px 2px oklch(var(--shadow-color) / 0.5), 0 0 0 1px oklch(var(--shadow-color) / 0.3);
664
+ --shadow-md: 0 2px 4px oklch(var(--shadow-color) / 0.5), 0 0 0 1px oklch(var(--shadow-color) / 0.35);
665
+ --shadow-lg: 0 4px 8px oklch(var(--shadow-color) / 0.55), 0 0 0 1px oklch(var(--shadow-color) / 0.35);
666
+ --shadow-xl: 0 8px 16px oklch(var(--shadow-color) / 0.6), 0 0 0 1px oklch(var(--shadow-color) / 0.35);
667
+ }
668
+
669
+ /* ── Palette × Dark Mode ────────────────────────────────────
670
+ 다크에서는 브랜드/스테이터스 컬러의 명도를 올리고 채도도 살짝 올려서 톤 유지.
671
+ hue-shift는 :root 값을 그대로 상속 (calm의 카키 톤, pastel의 민트 톤 유지). */
672
+ :root[data-mode="dark"][data-palette="mono"], [data-mode="dark"][data-palette="mono"] { --lightness: 0.98; --chroma: 0; }
673
+ :root[data-mode="dark"][data-palette="vivid"], [data-mode="dark"][data-palette="vivid"] { --lightness: 0.72; --chroma: 0.20; }
674
+ :root[data-mode="dark"][data-palette="standard"], [data-mode="dark"][data-palette="standard"] { --lightness: 0.68; --chroma: 0.15; }
675
+ :root[data-mode="dark"][data-palette="calm"], [data-mode="dark"][data-palette="calm"] { --lightness: 0.72; --chroma: 0.14; }
676
+ :root[data-mode="dark"][data-palette="pastel"], [data-mode="dark"][data-palette="pastel"] { --lightness: 0.80; --chroma: 0.12; }
677
+
678
+ /* status × dark: 다크 배경에서도 경고색이 선명하게 인지되도록 명도만 상향, 채도 로직은 라이트와 동일 그룹핑 유지 */
679
+ :root[data-mode="dark"][data-palette="mono"],
680
+ :root[data-mode="dark"][data-palette="vivid"],
681
+ :root[data-mode="dark"][data-palette="standard"],
682
+ [data-mode="dark"][data-palette="mono"],
683
+ [data-mode="dark"][data-palette="vivid"],
684
+ [data-mode="dark"][data-palette="standard"] { --status-chroma: 0.17; --status-lightness: 0.68; }
685
+ :root[data-mode="dark"][data-palette="calm"],
686
+ [data-mode="dark"][data-palette="calm"] { --status-chroma: 0.17; --status-lightness: 0.70; }
687
+ :root[data-mode="dark"][data-palette="pastel"],
688
+ [data-mode="dark"][data-palette="pastel"] { --status-chroma: 0.16; --status-lightness: 0.72; }
689
+
690
+ *, *::before, *::after { box-sizing: border-box; }
691
+
692
+ html {
693
+ scroll-behavior: smooth;
694
+ scroll-padding-top: calc(var(--header-h) + 16px);
695
+ }
696
+
697
+ body {
698
+ margin: 0;
699
+ background: var(--bg);
700
+ color: var(--fg);
701
+ font-family: var(--font-sans);
702
+ font-size: var(--text-base);
703
+ line-height: var(--lh-base);
704
+ /* 전역 자간 default — tight(-0.02em). letter-spacing은 상속 property라
705
+ 모든 하위 요소가 기본으로 받고, 필요한 자리만 override. "텍스트 쓰면
706
+ 자간이 자동으로 따라오는" 구조. */
707
+ letter-spacing: var(--tracking-tight);
708
+ -webkit-font-smoothing: antialiased;
709
+ text-rendering: optimizeLegibility;
710
+ transition: background var(--duration-base) var(--ease-out),
711
+ color var(--duration-base) var(--ease-out);
712
+ }
713
+
714
+ a { color: inherit; text-decoration: none; }
715
+ h1, h2, h3, h4 {
716
+ margin: 0;
717
+ font-weight: 600;
718
+ }
719
+ p { margin: 0; }
720
+ code {
721
+ font-family: var(--font-mono);
722
+ font-size: 0.9em;
723
+ background: var(--bg-muted);
724
+ padding: 2px 6px;
725
+ border-radius: var(--radius-xs);
726
+ color: var(--fg);
727
+ }
728
+ /* === AXES END === */
729
+
730
+ /* ============================================================
731
+ 컴포넌트 전역 side-effect
732
+ CSS Modules의 :global 로 둘 수 없는, 라이브러리 컴포넌트가 document.body나
733
+ document.documentElement에 토글하는 클래스/속성에 대한 스타일.
734
+ 토큰 whitelist 아님. 각 항목은 어느 컴포넌트가 설정하는지 명시.
735
+ ============================================================ */
736
+
737
+ /* Textarea.tsx — drag resize 중 전역 커서 강제. body.textarea-resizing 클래스 토글. */
738
+ body.textarea-resizing {
739
+ cursor: ns-resize !important;
740
+ user-select: none;
741
+ }
742
+