@nurihaus/web-design-system 3.0.1 → 3.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 (175) hide show
  1. package/README.md +104 -5
  2. package/dist/.storybook/story-kit.d.ts +18 -0
  3. package/dist/ai/components.md +1036 -0
  4. package/dist/ai/tokens.md +344 -0
  5. package/dist/avatar.js +336 -0
  6. package/dist/breadcrumb.js +364 -0
  7. package/dist/check-box.js +360 -0
  8. package/dist/chunk-149.js +57 -0
  9. package/dist/chunk-298.js +34 -0
  10. package/dist/chunk-302.js +105 -0
  11. package/dist/chunk-309.js +36 -0
  12. package/dist/chunk-364.js +126 -0
  13. package/dist/chunk-387.js +56 -0
  14. package/dist/chunk-436.js +33 -0
  15. package/dist/chunk-558.js +200 -0
  16. package/dist/chunk-563.js +181 -0
  17. package/dist/chunk-657.js +143 -0
  18. package/dist/chunk-713.js +38 -0
  19. package/dist/chunk-739.js +68 -0
  20. package/dist/chunk-77.js +34 -0
  21. package/dist/chunk-777.js +117 -0
  22. package/dist/chunk-910.js +64 -0
  23. package/dist/chunk-917.js +35 -0
  24. package/dist/chunk-933.js +70 -0
  25. package/dist/chunk-976.js +29 -0
  26. package/dist/collapsible-menu.js +394 -0
  27. package/dist/components/avatar/avatar-props.d.ts +2 -6
  28. package/dist/components/avatar/avatar-type.d.ts +4 -5
  29. package/dist/components/avatar/avatar.d.ts +1 -0
  30. package/dist/components/avatar/avatar.stories.d.ts +17 -1
  31. package/dist/components/badge/badge-props.d.ts +17 -80
  32. package/dist/components/badge/badge-type.d.ts +38 -2
  33. package/dist/components/badge/badge.stories.d.ts +25 -2
  34. package/dist/components/badge/base-badge.d.ts +2 -1
  35. package/dist/components/badge/icon-text-badge.d.ts +3 -21
  36. package/dist/components/badge/icon-text-option-badge.d.ts +2 -15
  37. package/dist/components/badge/option-badge.d.ts +3 -20
  38. package/dist/components/breadcrumb/base-breadcrumb.d.ts +19 -0
  39. package/dist/components/breadcrumb/breadcrumb-props.d.ts +4 -0
  40. package/dist/components/breadcrumb/breadcrumb-type.d.ts +33 -0
  41. package/dist/components/breadcrumb/breadcrumb.d.ts +4 -0
  42. package/dist/components/breadcrumb/breadcrumb.stories.d.ts +25 -0
  43. package/dist/components/button/button-props.d.ts +2 -7
  44. package/dist/components/button/button-type.d.ts +11 -3
  45. package/dist/components/button/button.stories.d.ts +13 -10
  46. package/dist/components/button/cta-button.d.ts +3 -12
  47. package/dist/components/check-box/base-check-box.d.ts +9 -5
  48. package/dist/components/check-box/check-box-props.d.ts +2 -7
  49. package/dist/components/check-box/check-box-type.d.ts +11 -4
  50. package/dist/components/check-box/check-box.d.ts +3 -10
  51. package/dist/components/check-box/check-box.stories.d.ts +19 -4
  52. package/dist/components/collapsible-menu/base-collapsible-menu.d.ts +9 -5
  53. package/dist/components/collapsible-menu/collapsible-menu-props.d.ts +3 -12
  54. package/dist/components/collapsible-menu/collapsible-menu-type.d.ts +33 -9
  55. package/dist/components/collapsible-menu/collapsible-menu.d.ts +3 -23
  56. package/dist/components/collapsible-menu/collapsible-menu.stories.d.ts +20 -4
  57. package/dist/components/drawer/base-drawer.d.ts +15 -0
  58. package/dist/components/drawer/drawer-props.d.ts +11 -0
  59. package/dist/components/drawer/drawer-type.d.ts +28 -0
  60. package/dist/components/drawer/drawer.d.ts +4 -0
  61. package/dist/components/drawer/drawer.stories.d.ts +34 -0
  62. package/dist/components/drop-down/base-drop-down.d.ts +11 -3
  63. package/dist/components/drop-down/drop-down-props.d.ts +3 -12
  64. package/dist/components/drop-down/drop-down-type.d.ts +34 -15
  65. package/dist/components/drop-down/drop-down.d.ts +3 -32
  66. package/dist/components/drop-down/drop-down.stories.d.ts +23 -4
  67. package/dist/components/elements/text/base-text.d.ts +3 -0
  68. package/dist/components/elements/text/text-props.d.ts +16 -0
  69. package/dist/components/elements/text/text-type.d.ts +6 -2
  70. package/dist/components/elements/text/text.d.ts +2 -1
  71. package/dist/components/elements/text/text.stories.d.ts +43 -3
  72. package/dist/components/loading/index.d.ts +6 -6
  73. package/dist/components/loading/inline-loading/base-inline-loading.d.ts +3 -0
  74. package/dist/components/loading/inline-loading/inline-loading-props.d.ts +9 -0
  75. package/dist/components/loading/inline-loading/inline-loading-type.d.ts +8 -6
  76. package/dist/components/loading/inline-loading/inline-loading.d.ts +3 -2
  77. package/dist/components/loading/inline-loading/inline-loading.stories.d.ts +5 -9
  78. package/dist/components/loading/overlay-loading/base-overlay-loading.d.ts +3 -0
  79. package/dist/components/loading/overlay-loading/overlay-loading-props.d.ts +7 -0
  80. package/dist/components/loading/overlay-loading/overlay-loading-type.d.ts +6 -3
  81. package/dist/components/loading/overlay-loading/overlay-loading.d.ts +3 -3
  82. package/dist/components/loading/overlay-loading/overlay-loading.stories.d.ts +8 -8
  83. package/dist/components/loading/spinner/base-spinner.d.ts +4 -0
  84. package/dist/components/loading/spinner/spinner-props.d.ts +1 -0
  85. package/dist/components/loading/spinner/spinner-type.d.ts +4 -4
  86. package/dist/components/loading/spinner/spinner.d.ts +2 -2
  87. package/dist/components/loading/spinner/spinner.stories.d.ts +5 -12
  88. package/dist/components/modal/base-modal.d.ts +21 -6
  89. package/dist/components/modal/modal-props.d.ts +5 -7
  90. package/dist/components/modal/modal-type.d.ts +34 -10
  91. package/dist/components/modal/modal-with-double-button.d.ts +4 -16
  92. package/dist/components/modal/modal-with-double-button.stories.d.ts +22 -0
  93. package/dist/components/modal/modal.d.ts +4 -0
  94. package/dist/components/modal/modal.stories.d.ts +22 -4
  95. package/dist/components/pagination/base-pagination.d.ts +9 -0
  96. package/dist/components/pagination/pagination-props.d.ts +4 -0
  97. package/dist/components/pagination/pagination-type.d.ts +20 -0
  98. package/dist/components/pagination/pagination.d.ts +4 -0
  99. package/dist/components/pagination/pagination.stories.d.ts +25 -0
  100. package/dist/components/radio/base-radio.d.ts +9 -5
  101. package/dist/components/radio/radio-props.d.ts +1 -0
  102. package/dist/components/radio/radio-type.d.ts +6 -8
  103. package/dist/components/radio/radio.d.ts +2 -2
  104. package/dist/components/radio/radio.stories.d.ts +13 -4
  105. package/dist/components/skeleton/base-skeleton.d.ts +4 -0
  106. package/dist/components/skeleton/skeleton-props.d.ts +15 -0
  107. package/dist/components/skeleton/skeleton-type.d.ts +12 -0
  108. package/dist/components/skeleton/skeleton.d.ts +4 -0
  109. package/dist/components/skeleton/skeleton.stories.d.ts +327 -0
  110. package/dist/components/switch/base-switch.d.ts +11 -0
  111. package/dist/components/switch/switch-props.d.ts +4 -0
  112. package/dist/components/switch/switch-type.d.ts +19 -0
  113. package/dist/components/switch/switch.d.ts +4 -0
  114. package/dist/components/switch/switch.stories.d.ts +24 -0
  115. package/dist/components/table/base-table.d.ts +4 -5
  116. package/dist/components/table/data-table.d.ts +5 -22
  117. package/dist/components/table/table-type.d.ts +22 -1
  118. package/dist/components/table/table.stories.d.ts +19 -3
  119. package/dist/components/tabs/base-tabs.d.ts +7 -7
  120. package/dist/components/tabs/tabs-props.d.ts +1 -1
  121. package/dist/components/tabs/tabs-type.d.ts +9 -13
  122. package/dist/components/tabs/tabs.d.ts +3 -3
  123. package/dist/components/tabs/tabs.stories.d.ts +16 -10
  124. package/dist/components/text-area/base-text-area.d.ts +10 -0
  125. package/dist/components/text-area/text-area-props.d.ts +12 -0
  126. package/dist/components/text-area/text-area-type.d.ts +34 -0
  127. package/dist/components/text-area/text-area.d.ts +4 -0
  128. package/dist/components/text-area/text-area.stories.d.ts +32 -0
  129. package/dist/components/text-field/base-text-field.d.ts +5 -3
  130. package/dist/components/text-field/text-field-props.d.ts +3 -12
  131. package/dist/components/text-field/text-field-type.d.ts +14 -0
  132. package/dist/components/text-field/text-field.d.ts +3 -16
  133. package/dist/components/text-field/text-field.stories.d.ts +24 -0
  134. package/dist/components/toast/base-toast.d.ts +20 -0
  135. package/dist/components/toast/toast-props.d.ts +18 -0
  136. package/dist/components/toast/toast-type.d.ts +45 -0
  137. package/dist/components/toast/toast.d.ts +5 -0
  138. package/dist/components/toast/toast.stories.d.ts +310 -0
  139. package/dist/components/tooltip/base-tooltip.d.ts +13 -3
  140. package/dist/components/tooltip/tooltip-props.d.ts +3 -2
  141. package/dist/components/tooltip/tooltip-type.d.ts +17 -5
  142. package/dist/components/tooltip/tooltip.d.ts +4 -7
  143. package/dist/components/tooltip/tooltip.stories.d.ts +21 -4
  144. package/dist/components.css +3017 -0
  145. package/dist/cta-button.js +237 -0
  146. package/dist/data-table.js +386 -0
  147. package/dist/drawer.js +390 -0
  148. package/dist/drop-down.js +419 -0
  149. package/dist/helpers/hooks/useExternalState.d.ts +5 -0
  150. package/dist/helpers/props/common-props.d.ts +7 -0
  151. package/dist/helpers/types/common-props.d.ts +8 -0
  152. package/dist/icon-text-badge.js +294 -0
  153. package/dist/icon-text-option-badge.js +270 -0
  154. package/dist/index.d.ts +33 -1
  155. package/dist/index.js +4179 -10180
  156. package/dist/loading.js +383 -0
  157. package/dist/modal-with-double-button.js +332 -0
  158. package/dist/modal.js +288 -0
  159. package/dist/option-badge.js +293 -0
  160. package/dist/pagination.js +412 -0
  161. package/dist/radio.js +363 -0
  162. package/dist/reset.css +45 -0
  163. package/dist/skeleton.js +331 -0
  164. package/dist/styles.css +1386 -248
  165. package/dist/switch.js +349 -0
  166. package/dist/tabs.js +421 -0
  167. package/dist/text-area.js +374 -0
  168. package/dist/text-field.js +369 -0
  169. package/dist/text.js +233 -0
  170. package/dist/toast.js +496 -0
  171. package/dist/tokens.css +100 -0
  172. package/dist/tokens.js +4 -6
  173. package/dist/tooltip.js +360 -0
  174. package/package.json +123 -14
  175. package/dist/components/text-field/text-filed.stories.d.ts +0 -8
package/dist/styles.css CHANGED
@@ -1,8 +1,5 @@
1
-
2
- @import url('https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.8/dist/web/static/pretendard.css');
3
- @import url('https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap');
4
- @import url('https://fonts.googleapis.com/icon?family=Material+Icons');
5
- /* 토큰 + 글꼴 + 리셋 + 유틸리티 + 컴포넌트. 디자인 시스템 컴포넌트를 쓸 때 가져온다. */
1
+ /* 토큰 + 글꼴 스택(.nuri-theme) + 리셋 + 유틸리티 + 컴포넌트. 디자인 시스템 컴포넌트를 쓸 때 가져온다.
2
+ 글꼴 파일은 불러오지 않는다. 앱이 불러온다. */
6
3
  /* 변수만. 이것만 가져와도 화면이 바뀌지 않는다. CSS Modules 에서 var() 로 쓴다. */
7
4
  /* tokens/figma.json 에서 생성됨 — 손으로 고치지 않는다. `npm run tokens` */
8
5
  :root {
@@ -155,6 +152,101 @@
155
152
  --line-height-4xl: 43px;
156
153
  --line-height-5xl: 66px;
157
154
  --line-height-6xl: 82px;
155
+ /* 한 줄에 나란히 놓이는 컨트롤: button, drop-down, text-field */
156
+ --control-height-xs: 28px;
157
+ --control-height-s: 36px;
158
+ --control-height-m: 40px;
159
+ --control-height-l: 44px;
160
+ --control-height-xl: 48px;
161
+
162
+ /* 라벨: badge */
163
+ --label-height-xs: 28px;
164
+ --label-height-s: 32px;
165
+ --label-height-m: 36px;
166
+ --label-height-l: 40px;
167
+ --label-height-xl: 48px;
168
+
169
+ /* 메뉴 행: collapsible-menu, drop-down 항목 */
170
+ --menu-row-height-s: 40px;
171
+ --menu-row-height-m: 48px;
172
+ --drop-down-item-height: 46px;
173
+
174
+ /* 정사각 */
175
+ --checkbox-size-s: 18px;
176
+ --checkbox-size-m: 20px;
177
+ --checkbox-size-l: 24px;
178
+ --radio-size: 18px;
179
+ --radio-dot-size: 8px;
180
+
181
+ /* 스위치: 트랙 폭·높이. 손잡이는 트랙 높이에서 inset 을 뺀 정사각이다 */
182
+ --switch-width-s: 32px;
183
+ --switch-width-m: 40px;
184
+ --switch-width-l: 48px;
185
+ --switch-height-s: 18px;
186
+ --switch-height-m: 22px;
187
+ --switch-height-l: 26px;
188
+ --switch-thumb-inset: 2px;
189
+ --avatar-size-s: 40px;
190
+ --avatar-size-m: 58px;
191
+ --avatar-size-l: 74px;
192
+ --avatar-size-xl: 124px;
193
+ --avatar-badge-size-s: 18px;
194
+ --avatar-badge-size-m: 24px;
195
+ --avatar-badge-size-l: 30px;
196
+ --avatar-badge-size-xl: 48px;
197
+
198
+ /* 폭 */
199
+ --drawer-width-s: 320px;
200
+ --drawer-width-m: 400px;
201
+ --drawer-width-l: 520px;
202
+ --drawer-height-s: 320px;
203
+ --drawer-height-m: 400px;
204
+ --drawer-height-l: 520px;
205
+ --toast-width: 360px;
206
+ --modal-width-s: 400px;
207
+ --modal-width-m: 450px;
208
+ --modal-width-l: 500px;
209
+
210
+ /* 그 밖의 치수 */
211
+ --icon-size-s: 18px;
212
+ --icon-size-m: 20px;
213
+ --icon-size-l: 24px;
214
+ --tooltip-arrow: 8px;
215
+ --spinner-stroke: 3px;
216
+ --overlay-spinner-size: 64px;
217
+ --overlay-spinner-stroke: 8px;
218
+ --tab-indicator-thickness: 3px;
219
+ --checkbox-border: 1.5px;
220
+ --breadcrumb-chevron-xs: 12px;
221
+ --breadcrumb-chevron-s: 14px;
222
+ --breadcrumb-chevron-m: 16px;
223
+ --breadcrumb-chevron-l: 18px;
224
+ --breadcrumb-chevron-xl: 20px;
225
+ --skeleton-text-height: 16px;
226
+ --skeleton-last-line-width: 60%;
227
+ --hairline: 1px;
228
+
229
+ /* 그림자 */
230
+ --shadow-popover: 0px 4px 6px -2px rgba(0, 0, 0, 0.06), 0px 10px 15px -3px rgba(0, 0, 0, 0.1);
231
+
232
+ /* 레이어. 값이 같아도 역할이 다르면 이름을 따로 둔다 */
233
+ --z-base: 0;
234
+ --z-raised: 1;
235
+ --z-sticky: 2;
236
+ --z-sticky-header: 3;
237
+ --z-tooltip: 3;
238
+ --z-popover: 5;
239
+ --z-overlay: 9998;
240
+ --z-modal: 9999;
241
+ --z-toast: 10000;
242
+
243
+ /* 모션 */
244
+ --motion-fast: 160ms;
245
+ --motion-base: 300ms;
246
+ --motion-ease: ease;
247
+ --spinner-duration: 1.2s;
248
+ --skeleton-duration: 1.5s;
249
+ --spinner-ease: cubic-bezier(0.5, 0, 0.5, 1);
158
250
  }
159
251
  /* semantic: app */
160
252
  :root, :root[data-ds-theme='app'] {
@@ -233,6 +325,11 @@
233
325
  --button-size-l: 54;
234
326
  --button-size-xl: 60;
235
327
  }
328
+ /*
329
+ * 크기·두께·레이어·모션. figma.json 에서 만들지 않고 손으로 유지한다(font-face.css 와 같다).
330
+ * 디자이너가 숫자를 바꾸는 곳은 여기다. 컴포넌트 CSS 는 숫자를 쓰지 않고 이 변수를 쓴다(빌드가 검사).
331
+ * 크기 이름은 xs · s · m · l · xl 다섯 개다. 컴포넌트는 그중 지원하는 것만 고른다.
332
+ */
236
333
  .nuri-theme {
237
334
  --cursor-button: pointer;
238
335
  --cursor-disabled: not-allowed;
@@ -256,15 +353,11 @@
256
353
  'Noto Color Emoji',
257
354
  sans-serif;
258
355
  }
259
- /* 웹폰트와 기본 글꼴. 토큰이 아니라 손으로 유지한다. */
260
356
  /*
261
- * 글꼴은 `:root` 에 걸지 않는다. 토큰만 가져다 쓰는 앱의 글꼴을 뺏지 않기 위해서다.
262
- * 디자인 시스템의 글꼴을 원하면 이 클래스를 붙인다.
357
+ * 글꼴 스택. 토큰이 아니라 손으로 유지한다.
358
+ * 웹폰트 파일은 불러오지 않는다. 앱이 Pretendard 를 불러왔으면 그것을, 아니면 시스템 글꼴을 쓴다.
359
+ * `:root` 에 걸지 않는다. 토큰만 가져다 쓰는 앱의 글꼴을 뺏지 않기 위해서다.
263
360
  */
264
- .nuri-placeholder {
265
- color: var(--color-grey-scale-400);
266
- }
267
- /* Reset */
268
361
  /* 모든 요소의 마진과 패딩 제거 */
269
362
  * {
270
363
  margin: 0;
@@ -310,6 +403,13 @@ p {
310
403
  margin-top: 0;
311
404
  margin-bottom: 0;
312
405
  }
406
+ /* 유틸리티 + 컴포넌트 스타일. 토큰·글꼴·리셋은 없다.
407
+ 글꼴을 앱이 직접 관리할 때 tokens.css 와 함께 가져온다. 컴포넌트 글자는 앱의 글꼴을 물려받는다. */
408
+ /* 컴포넌트 글자는 앱의 글꼴을 물려받는다. <button> 처럼 브라우저가 글꼴을 따로 주는 요소도 포함한다.
409
+ :where 로 우선순위를 0 으로 둔다. styles.css 에서는 token/font-face.css 의 .nuri-theme 글꼴이 이긴다. */
410
+ :where(.nuri-theme) {
411
+ font-family: inherit;
412
+ }
313
413
  /* Utility */
314
414
  .nuri-display-flex {
315
415
  display: flex;
@@ -460,88 +560,99 @@ p {
460
560
  * avatar *
461
561
  * *
462
562
  ***************************************************************************************************/
563
+ .avatar-wrapper {
564
+ position: relative;
565
+ display: inline-block;
566
+ }
463
567
  .avatar {
464
568
  display: flex;
465
569
  align-items: center;
466
570
  justify-content: center;
467
571
  }
468
572
  .avatar.size-xl {
469
- width: 124px;
470
- height: 124px;
471
- border: 1px solid #e4e4e7;
573
+ width: var(--avatar-size-xl);
574
+ height: var(--avatar-size-xl);
575
+ border: var(--hairline) solid var(--color-grey-scale-200);
472
576
  }
473
- .avatar.size-xl.badge-option {
474
- width: 48px;
475
- height: 48px;
476
- }
477
577
  .avatar.size-l {
478
- width: 74px;
479
- height: 74px;
480
- border: 1px solid #e4e4e7;
578
+ width: var(--avatar-size-l);
579
+ height: var(--avatar-size-l);
580
+ border: var(--hairline) solid var(--color-grey-scale-200);
481
581
  }
482
- .avatar.size-l.badge-option {
483
- width: 30px;
484
- height: 30px;
485
- }
486
582
  .avatar.size-m {
487
- width: 58px;
488
- height: 58px;
489
- border: 1px solid #e4e4e7;
583
+ width: var(--avatar-size-m);
584
+ height: var(--avatar-size-m);
585
+ border: var(--hairline) solid var(--color-grey-scale-200);
490
586
  }
491
- .avatar.size-m.badge-option {
492
- width: 24px;
493
- height: 24px;
494
- }
495
587
  .avatar.size-s {
496
- width: 40px;
497
- height: 40px;
498
- border: 1px solid #e4e4e7;
588
+ width: var(--avatar-size-s);
589
+ height: var(--avatar-size-s);
590
+ border: var(--hairline) solid var(--color-grey-scale-200);
591
+ }
592
+ .avatar-badge {
593
+ position: absolute;
594
+ right: 0;
595
+ bottom: 0;
596
+ display: flex;
597
+ align-items: center;
598
+ justify-content: center;
599
+ gap: var(--spacing-4);
600
+ border-radius: var(--radius-full);
601
+ border: var(--hairline) solid var(--color-grey-scale-200);
602
+ }
603
+ .avatar-badge.size-xl {
604
+ width: var(--avatar-badge-size-xl);
605
+ height: var(--avatar-badge-size-xl);
606
+ }
607
+ .avatar-badge.size-l {
608
+ width: var(--avatar-badge-size-l);
609
+ height: var(--avatar-badge-size-l);
610
+ }
611
+ .avatar-badge.size-m {
612
+ width: var(--avatar-badge-size-m);
613
+ height: var(--avatar-badge-size-m);
614
+ }
615
+ .avatar-badge.size-s {
616
+ width: var(--avatar-badge-size-s);
617
+ height: var(--avatar-badge-size-s);
499
618
  }
500
- .avatar.size-s.badge-option {
501
- width: 18px;
502
- height: 18px;
503
- }
504
619
  .base-badge {
505
620
  position: relative;
506
621
  display: flex;
507
622
  align-items: center;
508
- gap: 4px;
509
- border-radius: 40px;
510
-
511
- background-color: attr(data-backgroundColor color, transparent);
512
- color: attr(data-textColor color, transparent);
513
- border: attr(data-borderColor color, transparent);
623
+ gap: var(--spacing-4);
624
+ border-radius: var(--radius-full);
514
625
  }
515
- .base-badge.size-l {
516
- height: 48px;
626
+ .base-badge.size-xl {
627
+ height: var(--label-height-xl);
517
628
 
518
629
  font-size: var(--font-size-sm);
519
630
  line-height: var(--line-height-sm);
520
631
  font-weight: var(--font-weight-semibold);
521
632
  }
522
- .base-badge.size-m {
523
- height: 40px;
633
+ .base-badge.size-l {
634
+ height: var(--label-height-l);
524
635
 
525
636
  font-size: var(--font-size-sm);
526
637
  line-height: var(--line-height-sm);
527
638
  font-weight: var(--font-weight-semibold);
528
639
  }
529
- .base-badge.size-r {
530
- height: 36px;
640
+ .base-badge.size-m {
641
+ height: var(--label-height-m);
531
642
 
532
643
  font-size: var(--font-size-sm);
533
644
  line-height: var(--line-height-sm);
534
645
  font-weight: var(--font-weight-semibold);
535
646
  }
536
647
  .base-badge.size-s {
537
- height: 32px;
648
+ height: var(--label-height-s);
538
649
 
539
650
  font-size: var(--font-size-sm);
540
651
  line-height: var(--line-height-sm);
541
652
  font-weight: var(--font-weight-bold);
542
653
  }
543
- .base-badge.size-sm {
544
- height: 28px;
654
+ .base-badge.size-xs {
655
+ height: var(--label-height-xs);
545
656
 
546
657
  font-size: var(--font-size-xsm);
547
658
  line-height: var(--line-height-xsm);
@@ -552,7 +663,7 @@ p {
552
663
  align-items: center;
553
664
  justify-content: space-between;
554
665
 
555
- padding: 0 20px;
666
+ padding: 0 var(--spacing-20);
556
667
  }
557
668
  /***************************************************************************************************
558
669
  * *
@@ -564,7 +675,7 @@ p {
564
675
  align-items: center;
565
676
  justify-content: center;
566
677
 
567
- border-width: 1px;
678
+ border-width: var(--hairline);
568
679
  border-style: solid;
569
680
  }
570
681
  /***************************************************************************************************
@@ -576,9 +687,9 @@ p {
576
687
  display: flex;
577
688
  align-items: center;
578
689
  justify-content: center;
579
- gap: 4px;
690
+ gap: var(--spacing-4);
580
691
 
581
- border-width: 1px;
692
+ border-width: var(--hairline);
582
693
  border-style: solid;
583
694
  }
584
695
  /***************************************************************************************************
@@ -591,19 +702,130 @@ p {
591
702
  align-items: center;
592
703
  justify-content: space-between;
593
704
 
594
- padding: 0 20px;
705
+ padding: 0 var(--spacing-20);
595
706
  }
596
707
  .icon-text-option > span {
597
708
  display: flex;
598
709
  align-items: center;
599
- gap: 4px;
710
+ gap: var(--spacing-4);
711
+ }
712
+ /***************************************************************************************************
713
+ * *
714
+ * variant *
715
+ * *
716
+ ***************************************************************************************************/
717
+ .variant-neutral:is(.option,.icon-text,.icon-text-option) {
718
+ color: var(--color-black);
719
+ background-color: var(--color-white);
720
+ border-color: transparent;
721
+ }
722
+ .variant-primary:is(.option,.icon-text,.icon-text-option) {
723
+ color: var(--color-purple-900);
724
+ background-color: var(--color-purple-50);
725
+ border-color: transparent;
726
+ }
727
+ .variant-danger:is(.option,.icon-text,.icon-text-option) {
728
+ color: var(--color-accent-red-700);
729
+ background-color: var(--color-accent-red-50);
730
+ border-color: transparent;
731
+ }
732
+ /* icon-text-option 은 테두리가 없는 모양이라 두께·스타일까지 여기서 준다. */
733
+ .variant-outlined:is(.option,.icon-text,.icon-text-option) {
734
+ color: var(--color-black);
735
+ background-color: var(--color-white);
736
+ border: var(--hairline) solid var(--color-grey-scale-300);
737
+ }
738
+ .base-breadcrumb:where(.list) {
739
+ display: flex;
740
+ flex-wrap: wrap;
741
+ align-items: center;
742
+ margin: 0;
743
+ padding: 0;
744
+ list-style: none;
745
+ }
746
+ .base-breadcrumb:where(.item,.separator) {
747
+ display: inline-flex;
748
+ align-items: center;
749
+ }
750
+ .base-breadcrumb:where(.link) {
751
+ color: inherit;
752
+ text-decoration: none;
753
+ cursor: var(--cursor-button);
754
+ }
755
+ .base-breadcrumb:where(.separator) {
756
+ -webkit-user-select: none;
757
+ -moz-user-select: none;
758
+ user-select: none;
759
+ }
760
+ /***************************************************************************************************
761
+ * *
762
+ * breadcrumb *
763
+ * *
764
+ ***************************************************************************************************/
765
+ .breadcrumb {
766
+ font-weight: var(--font-weight-medium);
767
+ color: var(--color-grey-scale-500);
768
+
769
+ /* 글자와 화살표가 같이 커진다. 화살표 치수는 size.css 의 --breadcrumb-chevron-* */
770
+ }
771
+ .breadcrumb.size-xs {
772
+ font-size: var(--font-size-xsm);
773
+ line-height: var(--line-height-xsm);
774
+ --breadcrumb-chevron: var(--breadcrumb-chevron-xs);
775
+ }
776
+ .breadcrumb.size-s {
777
+ font-size: var(--font-size-sm);
778
+ line-height: var(--line-height-sm);
779
+ --breadcrumb-chevron: var(--breadcrumb-chevron-s);
780
+ }
781
+ .breadcrumb.size-m {
782
+ font-size: var(--font-size-base);
783
+ line-height: var(--line-height-base);
784
+ --breadcrumb-chevron: var(--breadcrumb-chevron-m);
785
+ }
786
+ .breadcrumb.size-l {
787
+ font-size: var(--font-size-lg);
788
+ line-height: var(--line-height-lg);
789
+ --breadcrumb-chevron: var(--breadcrumb-chevron-l);
600
790
  }
791
+ .breadcrumb.size-xl {
792
+ font-size: var(--font-size-xl);
793
+ line-height: var(--line-height-xl);
794
+ --breadcrumb-chevron: var(--breadcrumb-chevron-xl);
795
+ }
796
+ .breadcrumb-list {
797
+ gap: var(--spacing-4);
798
+ }
799
+ .breadcrumb-link {
800
+ border-radius: var(--radius-4);
801
+ transition: color var(--motion-fast) var(--motion-ease);
802
+ }
803
+ .breadcrumb-link:hover {
804
+ color: var(--color-grey-scale-800);
805
+ text-decoration: underline;
806
+ }
807
+ .breadcrumb-link:focus-visible {
808
+ outline: var(--hairline) solid var(--color-purple-900);
809
+ outline-offset: var(--spacing-2);
810
+ }
811
+ .breadcrumb-page {
812
+ color: var(--color-grey-scale-900);
813
+ font-weight: var(--font-weight-semibold);
814
+ }
815
+ .breadcrumb-separator {
816
+ color: var(--color-grey-scale-400);
817
+ }
818
+ .breadcrumb-chevron {
819
+ width: var(--breadcrumb-chevron);
820
+ height: var(--breadcrumb-chevron);
821
+ transform: rotate(-90deg);
822
+ }
601
823
  .base-button {
602
824
  display: flex;
603
825
  justify-content: center;
604
826
  align-items: center;
605
- gap: 10px;
606
- border-radius: 6px;
827
+ gap: var(--spacing-10);
828
+ border-radius: var(--radius-6);
607
829
  border: none;
608
830
  cursor: pointer;
609
831
  }
@@ -617,11 +839,12 @@ p {
617
839
  * *
618
840
  ***************************************************************************************************/
619
841
  .cta-button {
620
- border-radius: 6px;
842
+ border-radius: var(--radius-6);
843
+ /* 좌우 여백은 size 가 정한다. 글자 길이와 상관없이 양쪽에 같은 여백이 남는다 */
621
844
  }
622
845
  .cta-button.variant-primary {
623
846
  background-color: var(--color-purple-900);
624
- border: 1px solid var(--color-purple-900);
847
+ border: var(--hairline) solid var(--color-purple-900);
625
848
  color: var(--color-white);
626
849
  }
627
850
  .cta-button.variant-primary:not(:disabled):hover {
@@ -640,7 +863,7 @@ p {
640
863
  }
641
864
  .cta-button.variant-ghost {
642
865
  background-color: var(--color-white);
643
- border: 1px solid var(--color-grey-scale-300);
866
+ border: var(--hairline) solid var(--color-grey-scale-300);
644
867
  color: var(--color-purple-900);
645
868
  }
646
869
  .cta-button.variant-ghost:not(:disabled):hover {
@@ -654,12 +877,12 @@ p {
654
877
  }
655
878
  .cta-button.variant-neutral:not(:disabled):hover {
656
879
  background-color: var(--color-grey-scale-100);
657
- border: 1px solid var(--color-grey-scale-100);
880
+ border: var(--hairline) solid var(--color-grey-scale-100);
658
881
  color: var(--color-purple-900);
659
882
  }
660
883
  .cta-button.variant-confirm {
661
884
  background-color: var(--color-accent-red-500);
662
- border: 1px solid var(--color-accent-red-500);
885
+ border: var(--hairline) solid var(--color-accent-red-500);
663
886
  color: var(--color-white);
664
887
  }
665
888
  .cta-button.variant-confirm:not(:disabled):hover {
@@ -669,46 +892,44 @@ p {
669
892
  }
670
893
  .cta-button.variant-outlined {
671
894
  background-color: var(--color-white);
672
- border: 1px solid var(--color-accent-red-700);
895
+ border: var(--hairline) solid var(--color-accent-red-700);
673
896
  color: var(--color-accent-red-700);
674
897
  }
675
898
  .cta-button.size-xl {
676
- height: 60px;
899
+ height: var(--control-height-xl);
900
+ padding: 0 var(--spacing-24);
677
901
 
678
902
  font-size: var(--font-size-lg);
679
903
  line-height: var(--line-height-lg);
680
904
  font-weight: var(--font-weight-bold);
681
905
  }
682
906
  .cta-button.size-l {
683
- height: 54px;
907
+ height: var(--control-height-l);
908
+ padding: 0 var(--spacing-20);
684
909
 
685
910
  font-size: var(--font-size-base);
686
911
  line-height: var(--line-height-base);
687
912
  font-weight: var(--font-weight-bold);
688
913
  }
689
- .cta-button.size-r {
690
- height: 48px;
691
-
692
- font-size: var(--font-size-sm);
693
- line-height: var(--line-height-sm);
694
- font-weight: var(--font-weight-semibold);
695
- }
696
914
  .cta-button.size-m {
697
- height: 50px;
915
+ height: var(--control-height-m);
916
+ padding: 0 var(--spacing-16);
698
917
 
699
918
  font-size: var(--font-size-sm);
700
919
  line-height: var(--line-height-sm);
701
920
  font-weight: var(--font-weight-semibold);
702
921
  }
703
922
  .cta-button.size-s {
704
- height: 40px;
923
+ height: var(--control-height-s);
924
+ padding: 0 var(--spacing-14);
705
925
 
706
926
  font-size: var(--font-size-xsm);
707
927
  line-height: var(--line-height-xsm);
708
928
  font-weight: var(--font-weight-semibold);
709
929
  }
710
930
  .cta-button.size-xs {
711
- height: 30px;
931
+ height: var(--control-height-xs);
932
+ padding: 0 var(--spacing-12);
712
933
 
713
934
  font-size: var(--font-size-xsm);
714
935
  line-height: var(--line-height-xsm);
@@ -733,7 +954,7 @@ p {
733
954
  .check-box {
734
955
  display: flex;
735
956
  align-items: center;
736
- gap: 10px;
957
+ gap: var(--spacing-10);
737
958
 
738
959
  background-color: transparent;
739
960
  border: none;
@@ -742,42 +963,53 @@ p {
742
963
  display: flex;
743
964
  align-items: center;
744
965
  justify-content: center;
745
- border-radius: 4px;
746
- border: 1.5px solid var(--color-purple-900);
966
+ border-radius: var(--radius-4);
967
+ border: var(--checkbox-border) solid var(--color-purple-900);
747
968
  }
748
969
  .check-box-indicator {
749
970
 
750
971
  width: 100%;
751
972
  height: 100%;
973
+
974
+ /* 체크 아이콘(16px 고정)을 칸 정가운데에 둔다. 빌드된 SVG 에 viewBox 가 없어 늘리면 그림이 왼쪽 위에 남는다 */
752
975
  }
976
+ .check-box-indicator:not(.wrapper) {
977
+ display: flex;
978
+ align-items: center;
979
+ justify-content: center;
980
+ }
981
+ .check-box-indicator:not(.wrapper) > svg {
982
+ display: block;
983
+ flex-shrink: 0;
984
+ }
753
985
  .check-box-indicator.size-l {
754
- width: 24px;
755
- height: 24px;
986
+ width: var(--checkbox-size-l);
987
+ height: var(--checkbox-size-l);
756
988
  }
757
989
  .check-box-indicator.size-m {
758
- width: 20px;
759
- height: 20px;
990
+ width: var(--checkbox-size-m);
991
+ height: var(--checkbox-size-m);
760
992
  }
761
993
  .check-box-indicator.size-s {
762
- width: 18px;
763
- height: 18px;
994
+ width: var(--checkbox-size-s);
995
+ height: var(--checkbox-size-s);
764
996
  }
765
997
  .check-box-indicator[data-state='unchecked'] {
766
- background-color: #fff;
998
+ background-color: var(--color-white);
767
999
  }
768
1000
  .check-box-indicator[data-state='checked'] {
769
1001
  background-color: var(--color-purple-900);
770
1002
  }
771
1003
  .check-box-indicator[data-disabled='true'] {
772
1004
  border: none;
773
- border-radius: 4px;
1005
+ border-radius: var(--radius-4);
774
1006
  background-color: var(--color-grey-scale-300);
775
1007
  }
776
1008
  .base-collapsible-menu.trigger {
777
1009
  display: flex;
778
1010
  align-items: center;
779
1011
  justify-content: space-between;
780
- gap: 10px;
1012
+ gap: var(--spacing-10);
781
1013
  width: 100%;
782
1014
  }
783
1015
  /***************************************************************************************************
@@ -788,13 +1020,13 @@ p {
788
1020
  .collapsible-menu {
789
1021
  display: flex;
790
1022
  flex-direction: column;
791
- gap: 4px;
1023
+ gap: var(--spacing-4);
792
1024
  }
793
- .collapsible-menu.size-m .collapsible-menu-row {
794
- height: 40px;
1025
+ .collapsible-menu.size-s .collapsible-menu-row {
1026
+ height: var(--menu-row-height-s);
795
1027
  }
796
- .collapsible-menu.size-l .collapsible-menu-row {
797
- height: 48px;
1028
+ .collapsible-menu.size-m .collapsible-menu-row {
1029
+ height: var(--menu-row-height-m);
798
1030
  }
799
1031
  .collapsible-menu-row {
800
1032
  all: unset;
@@ -802,11 +1034,12 @@ p {
802
1034
  display: flex;
803
1035
  align-items: center;
804
1036
  justify-content: space-between;
805
- gap: 10px;
1037
+ gap: var(--spacing-10);
806
1038
 
807
1039
  width: 100%;
808
- padding: 0 12px;
809
- border-radius: 8px;
1040
+ padding: 0 var(--spacing-12);
1041
+ /* figma 토큰에 --radius-8 없음. 디자이너 확인 전까지 숫자 유지 */
1042
+ border-radius: 8px; /* raw-px */
810
1043
  cursor: pointer;
811
1044
 
812
1045
  font-size: var(--font-size-sm);
@@ -829,17 +1062,17 @@ p {
829
1062
  .collapsible-menu-left {
830
1063
  display: inline-flex;
831
1064
  align-items: center;
832
- gap: 10px;
1065
+ gap: var(--spacing-10);
833
1066
  min-width: 0;
834
1067
  }
835
1068
  .collapsible-menu-left > * {
836
1069
  min-width: 0;
837
1070
  }
838
1071
  .collapsible-menu-chevron {
839
- width: 18px;
840
- height: 18px;
1072
+ width: var(--icon-size-s);
1073
+ height: var(--icon-size-s);
841
1074
  color: var(--color-grey-scale-500);
842
- transition: transform 160ms ease;
1075
+ transition: transform var(--motion-fast) var(--motion-ease);
843
1076
  }
844
1077
  .base-collapsible-menu.trigger[data-state='open'] .collapsible-menu-chevron {
845
1078
  transform: rotate(180deg);
@@ -847,34 +1080,214 @@ p {
847
1080
  .collapsible-menu-content {
848
1081
  display: flex;
849
1082
  flex-direction: column;
850
- gap: 2px;
851
- margin-top: 2px;
852
- margin-bottom: 4px;
1083
+ gap: var(--spacing-2);
1084
+ margin-top: var(--spacing-2);
1085
+ margin-bottom: var(--spacing-4);
1086
+ }
1087
+ /* Title·Close 같은 조각도 base-drawer 를 달므로 상자 스타일은 overlay·content 에만 건다. */
1088
+ .base-drawer:where(.overlay) {
1089
+ position: fixed;
1090
+ top: 0;
1091
+ left: 0;
1092
+ right: 0;
1093
+ bottom: 0;
1094
+ background-color: rgba(0, 0, 0, 0.5);
1095
+ z-index: var(--z-overlay);
1096
+ }
1097
+ .base-drawer[data-state='open']:where(.overlay) {
1098
+ animation: drawer-overlay-in var(--motion-base) var(--motion-ease);
1099
+ }
1100
+ .base-drawer[data-state='closed']:where(.overlay) {
1101
+ animation: drawer-overlay-out var(--motion-base) var(--motion-ease);
1102
+ }
1103
+ .base-drawer:where(.content) {
1104
+ position: fixed;
1105
+ display: flex;
1106
+ flex-direction: column;
1107
+ z-index: var(--z-modal);
1108
+ background-color: var(--color-white);
1109
+ }
1110
+ .base-drawer:where(.title) {
1111
+ margin: 0;
1112
+ font-size: var(--font-size-lg);
1113
+ font-weight: var(--font-weight-bold);
1114
+ color: var(--color-black);
1115
+ }
1116
+ .base-drawer:where(.description) {
1117
+ margin: 0;
1118
+ font-size: var(--font-size-sm);
1119
+ font-weight: var(--font-weight-medium);
1120
+ color: var(--color-grey-scale-600);
1121
+ }
1122
+ .base-drawer:where(.close) {
1123
+ display: inline-flex;
1124
+ align-items: center;
1125
+ justify-content: center;
1126
+ padding: 0;
1127
+ background-color: transparent;
1128
+ border: none;
1129
+ cursor: var(--cursor-button);
1130
+ }
1131
+ /***************************************************************************************************
1132
+ * *
1133
+ * drawer *
1134
+ * *
1135
+ ***************************************************************************************************/
1136
+ /* Radix 는 애니메이션이 끝나야 닫힌 패널을 지우므로 transition 이 아니라 keyframes 로 들어오고 나간다. */
1137
+ @keyframes drawer-overlay-in {
1138
+ from {
1139
+ opacity: 0;
1140
+ }
1141
+ to {
1142
+ opacity: 1;
1143
+ }
1144
+ }
1145
+ @keyframes drawer-overlay-out {
1146
+ from {
1147
+ opacity: 1;
1148
+ }
1149
+ to {
1150
+ opacity: 0;
1151
+ }
1152
+ }
1153
+ @keyframes drawer-slide-in {
1154
+ from {
1155
+ transform: var(--drawer-offset);
1156
+ }
1157
+ to {
1158
+ transform: translate(0, 0);
1159
+ }
1160
+ }
1161
+ @keyframes drawer-slide-out {
1162
+ from {
1163
+ transform: translate(0, 0);
1164
+ }
1165
+ to {
1166
+ transform: var(--drawer-offset);
1167
+ }
1168
+ }
1169
+ .drawer {
1170
+ gap: var(--spacing-8);
1171
+ padding: var(--spacing-24);
1172
+ box-sizing: border-box;
1173
+ }
1174
+ .drawer.size-s {
1175
+ --drawer-width: var(--drawer-width-s);
1176
+ --drawer-height: var(--drawer-height-s);
1177
+ }
1178
+ .drawer.size-m {
1179
+ --drawer-width: var(--drawer-width-m);
1180
+ --drawer-height: var(--drawer-height-m);
1181
+ }
1182
+ .drawer.size-l {
1183
+ --drawer-width: var(--drawer-width-l);
1184
+ --drawer-height: var(--drawer-height-l);
1185
+ }
1186
+ .drawer.side-right {
1187
+ top: 0;
1188
+ right: 0;
1189
+ bottom: 0;
1190
+ width: var(--drawer-width);
1191
+ max-width: 100%;
1192
+ --drawer-offset: translateX(100%);
1193
+ }
1194
+ .drawer.side-left {
1195
+ top: 0;
1196
+ left: 0;
1197
+ bottom: 0;
1198
+ width: var(--drawer-width);
1199
+ max-width: 100%;
1200
+ --drawer-offset: translateX(-100%);
1201
+ }
1202
+ .drawer.side-bottom {
1203
+ left: 0;
1204
+ right: 0;
1205
+ bottom: 0;
1206
+ height: var(--drawer-height);
1207
+ max-height: 100%;
1208
+ border-top-left-radius: var(--radius-16);
1209
+ border-top-right-radius: var(--radius-16);
1210
+ --drawer-offset: translateY(100%);
1211
+ }
1212
+ .drawer[data-state='open'] {
1213
+ animation: drawer-slide-in var(--motion-base) var(--motion-ease);
1214
+ }
1215
+ .drawer[data-state='closed'] {
1216
+ animation: drawer-slide-out var(--motion-base) var(--motion-ease);
1217
+ }
1218
+ .drawer-header {
1219
+ display: flex;
1220
+ align-items: center;
1221
+ justify-content: space-between;
1222
+ gap: var(--spacing-12);
1223
+ }
1224
+ .drawer-close {
1225
+ flex-shrink: 0;
1226
+ }
1227
+ .drawer-body {
1228
+ flex: 1;
1229
+ min-height: 0;
1230
+ overflow-y: auto;
1231
+ margin-top: var(--spacing-8);
1232
+ }
1233
+ .drawer-footer {
1234
+ display: flex;
1235
+ justify-content: flex-end;
1236
+ gap: var(--spacing-8);
1237
+ margin-top: var(--spacing-16);
1238
+ }
1239
+ /* placeholder 로 넘기는 span 의 색. base-drop-down 이 기본 placeholder 에 붙인다. */
1240
+ .nuri-placeholder {
1241
+ color: var(--color-grey-scale-400);
853
1242
  }
854
1243
  .base-drop-down.trigger {
855
1244
  display: flex;
856
1245
  align-items: center;
857
1246
  justify-content: space-between;
858
- gap: 10px;
1247
+ gap: var(--spacing-10);
859
1248
  }
860
1249
  /***************************************************************************************************
861
1250
  * *
862
1251
  * drop-down-single *
863
1252
  * *
864
1253
  ***************************************************************************************************/
1254
+ /* 높이·좌우 여백·글자는 버튼·텍스트필드와 같은 단계 */
1255
+ .drop-down-single-trigger.size-xs {
1256
+ height: var(--control-height-xs);
1257
+ padding: 0 var(--spacing-12);
1258
+ font-size: var(--font-size-xsm);
1259
+ line-height: var(--line-height-xsm);
1260
+ }
1261
+ .drop-down-single-trigger.size-s {
1262
+ height: var(--control-height-s);
1263
+ padding: 0 var(--spacing-14);
1264
+ font-size: var(--font-size-sm);
1265
+ line-height: var(--line-height-sm);
1266
+ }
865
1267
  .drop-down-single-trigger.size-m {
866
- height: 40px;
1268
+ height: var(--control-height-m);
1269
+ padding: 0 var(--spacing-16);
1270
+ font-size: var(--font-size-sm);
1271
+ line-height: var(--line-height-sm);
867
1272
  }
868
1273
  .drop-down-single-trigger.size-l {
869
- height: 50px;
1274
+ height: var(--control-height-l);
1275
+ padding: 0 var(--spacing-20);
1276
+ font-size: var(--font-size-base);
1277
+ line-height: var(--line-height-base);
1278
+ }
1279
+ .drop-down-single-trigger.size-xl {
1280
+ height: var(--control-height-xl);
1281
+ padding: 0 var(--spacing-24);
1282
+ font-size: var(--font-size-lg);
1283
+ line-height: var(--line-height-lg);
870
1284
  }
871
1285
  .drop-down-single-trigger {
872
1286
 
873
- border: 1px solid var(--color-grey-scale-300);
874
- border-radius: 4px;
1287
+ border: var(--hairline) solid var(--color-grey-scale-300);
1288
+ border-radius: var(--radius-4);
875
1289
  width: -moz-fit-content;
876
1290
  width: fit-content;
877
- padding: 0 14px;
878
1291
  background-color: var(--color-white);
879
1292
  }
880
1293
  .drop-down-single-trigger:focus {
@@ -895,12 +1308,15 @@ p {
895
1308
  .drop-down-single-trigger[data-state='open'] .rotate {
896
1309
  transform: rotate(180deg);
897
1310
  transform-origin: 50% 50%;
898
- transition: transform 160ms ease;
1311
+ transition: transform var(--motion-fast) var(--motion-ease);
899
1312
  will-change: transform;
900
1313
  }
1314
+ .drop-down-single-label {
1315
+ gap: var(--spacing-10);
1316
+ }
901
1317
  .drop-down-single-value {
902
- font-size: var(--font-size-sm);
903
- line-height: var(--line-height-sm);
1318
+ font-size: inherit;
1319
+ line-height: inherit;
904
1320
  font-weight: var(--font-weight-medium);
905
1321
 
906
1322
  text-align: left;
@@ -912,19 +1328,17 @@ p {
912
1328
  color: var(--color-grey-scale-400);
913
1329
  }
914
1330
  .drop-down-single-content {
915
- z-index: 5;
1331
+ z-index: var(--z-popover);
916
1332
  min-width: var(--radix-select-trigger-width);
917
1333
  overflow: hidden;
918
- box-shadow:
919
- 0px 4px 6px -2px rgba(0, 0, 0, 0.06),
920
- 0px 10px 15px -3px rgba(0, 0, 0, 0.1);
921
- border-radius: 6px;
1334
+ box-shadow: var(--shadow-popover);
1335
+ border-radius: var(--radius-6);
922
1336
  }
923
1337
  .drop-down-single-item {
924
- padding: 14px;
1338
+ padding: var(--spacing-14);
925
1339
  background-color: var(--color-white);
926
1340
  outline: none;
927
- height: 46px;
1341
+ height: var(--drop-down-item-height);
928
1342
 
929
1343
  font-size: var(--font-size-sm);
930
1344
  line-height: var(--line-height-sm);
@@ -1359,42 +1773,60 @@ p {
1359
1773
  .base-text.color-accent-orange-900[class*='color-'] {
1360
1774
  color: var(--color-accent-orange-900);
1361
1775
  }
1362
- .component-loading-inline {
1363
- display: flex;
1364
- width: 100%;
1365
- height: 100%;
1366
- align-items: center;
1367
- }
1368
- /* components/loading/overlay-loading/overlay-loading-style.css */
1369
- .page-loading-container {
1776
+ .base-inline-loading {
1777
+ display: flex;
1778
+ width: 100%;
1779
+ height: 100%;
1780
+ align-items: center;
1781
+ }
1782
+ /* 링은 currentColor 다. 우선순위 0 이라 넘겨받은 className 이나 style 의 color 가 늘 이긴다. */
1783
+ :where(.base-inline-loading) {
1784
+ color: var(--color-grey-scale-200);
1785
+ }
1786
+ .base-overlay-loading {
1370
1787
  position: fixed;
1371
1788
  inset: 0;
1372
1789
  display: flex;
1373
1790
  align-items: center;
1374
1791
  justify-content: center;
1375
1792
  }
1376
- .page-loading-backdrop { position: absolute; inset: 0; }
1793
+ .page-loading-backdrop {
1794
+ position: absolute;
1795
+ inset: 0;
1796
+ }
1377
1797
  .page-loading-content {
1378
1798
  position: relative;
1379
1799
  display: flex;
1380
1800
  flex-direction: column;
1381
1801
  align-items: center;
1382
- gap: 16px;
1802
+ gap: var(--spacing-16);
1803
+ }
1804
+ /* 스피너를 레이아웃 크기로 키운다. transform: scale 은 보이는 크기만 키워 아래 글자와 겹친다 */
1805
+ .page-loading-indicator {
1806
+ --spinner-stroke: var(--overlay-spinner-stroke);
1807
+ }
1808
+ .page-loading-indicator .base-spinner,.page-loading-indicator .loading-indicator-ring {
1809
+ width: var(--overlay-spinner-size);
1810
+ height: var(--overlay-spinner-size);
1811
+ }
1812
+ .page-loading-text {
1813
+ position: relative;
1383
1814
  }
1384
- /* 기본 스피너(20px)를 확대 */
1385
- .page-loading-indicator { transform: scale(3.2); transform-origin: center; }
1386
- .page-loading-text { position: relative; }
1387
- .component-loading-container {
1815
+ .base-spinner {
1388
1816
  display: flex;
1389
- width: 20px;
1390
- height: 20px;
1817
+ width: var(--icon-size-m);
1818
+ height: var(--icon-size-m);
1391
1819
  align-items: center;
1392
1820
  justify-content: center;
1393
1821
  }
1822
+ /* 우선순위 0 이라 넘겨받은 className 이나 style 의 color 가 늘 이긴다. */
1823
+ :where(.base-spinner) {
1824
+ color: var(--color-grey-scale-200);
1825
+ }
1394
1826
  .loading-indicator-ring {
1395
1827
  position: relative;
1396
- width: 20px;
1397
- height: 20px;
1828
+ width: var(--icon-size-m);
1829
+ height: var(--icon-size-m);
1398
1830
  }
1399
1831
  .loading-indicator-single-ring {
1400
1832
  box-sizing: border-box;
@@ -1402,37 +1834,46 @@ p {
1402
1834
  position: absolute;
1403
1835
  width: 100%;
1404
1836
  height: 100%;
1405
- border: 3px solid;
1837
+ border: var(--spinner-stroke) solid;
1406
1838
  border-radius: 50%;
1407
- animation: lds-ring 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
1408
- /* 기본값은 white, 상위에서 --spinner-border-color 주입 */
1409
- border-color: var(--spinner-border-color, var(--color-white)) transparent transparent transparent;
1839
+ animation: lds-ring var(--spinner-duration) var(--spinner-ease) infinite;
1840
+ border-color: currentColor transparent transparent transparent;
1841
+ }
1842
+ .loading-indicator-single-ring:nth-child(1) {
1843
+ animation-delay: calc(var(--spinner-duration) * -0.375);
1844
+ }
1845
+ .loading-indicator-single-ring:nth-child(2) {
1846
+ animation-delay: calc(var(--spinner-duration) * -0.25);
1847
+ }
1848
+ .loading-indicator-single-ring:nth-child(3) {
1849
+ animation-delay: calc(var(--spinner-duration) * -0.125);
1850
+ }
1851
+ .loading-indicator-single-ring:nth-child(4) {
1852
+ animation-delay: 0s;
1410
1853
  }
1411
- /* nth-child 지연은 그대로 CSS or 인라인 중 하나만 사용한다면, 아래는 제거 가능 (지금은 인라인 사용 중) */
1412
- /*
1413
- .loading-indicator-single-ring:nth-child(1) { animation-delay: -0.45s; }
1414
- .loading-indicator-single-ring:nth-child(2) { animation-delay: -0.3s; }
1415
- .loading-indicator-single-ring:nth-child(3) { animation-delay: -0.15s; }
1416
- .loading-indicator-single-ring:nth-child(4) { animation-delay: 0s; }
1417
- */
1418
1854
  @keyframes lds-ring {
1419
- 0% { transform: rotate(0deg); }
1420
- 100% { transform: rotate(360deg); }
1855
+ 0% {
1856
+ transform: rotate(0deg);
1857
+ }
1858
+ 100% {
1859
+ transform: rotate(360deg);
1860
+ }
1421
1861
  }
1422
- .base-modal {
1862
+ /* Title·Close 같은 조각도 base-modal 을 달므로 상자 스타일은 container·overlay 에만 건다. */
1863
+ .base-modal:where(.modal-container, .modal-overlay) {
1423
1864
  display: flex;
1424
1865
  flex-direction: column;
1425
1866
  align-items: center;
1426
1867
 
1427
- padding: 30px;
1428
- border-radius: 6px;
1868
+ padding: var(--spacing-30);
1869
+ border-radius: var(--radius-6);
1429
1870
  }
1430
1871
  .base-modal.modal-container {
1431
1872
  position: fixed;
1432
1873
  top: 50%;
1433
1874
  left: 50%;
1434
1875
  transform: translate(-50%, -50%);
1435
- z-index: 9999;
1876
+ z-index: var(--z-modal);
1436
1877
  background-color: var(--color-white);
1437
1878
  }
1438
1879
  .base-modal.modal-overlay {
@@ -1442,7 +1883,7 @@ p {
1442
1883
  right: 0;
1443
1884
  bottom: 0;
1444
1885
  background-color: rgba(0, 0, 0, 0.5);
1445
- z-index: 9998;
1886
+ z-index: var(--z-overlay);
1446
1887
  }
1447
1888
  /***************************************************************************************************
1448
1889
  * *
@@ -1456,36 +1897,47 @@ p {
1456
1897
  width: 100%;
1457
1898
  }
1458
1899
  .modal-with-double-button-container.size-s {
1459
- width: 400px;
1900
+ width: var(--modal-width-s);
1460
1901
  }
1461
1902
  .modal-with-double-button-container.size-m {
1462
- width: 450px;
1903
+ width: var(--modal-width-m);
1463
1904
  }
1464
1905
  .modal-with-double-button-container.size-l {
1465
- width: 500px;
1906
+ width: var(--modal-width-l);
1466
1907
  }
1467
1908
  .modal-with-double-button-title-icon {
1468
- margin-bottom: 20px;
1909
+ margin-bottom: var(--spacing-20);
1469
1910
  }
1470
1911
  .modal-with-double-button-title {
1471
- margin-bottom: 4px;
1912
+ margin: 0 0 var(--spacing-4);
1913
+ font-size: var(--font-size-lg);
1914
+ font-weight: var(--font-weight-bold);
1915
+ text-align: center;
1916
+ color: var(--color-black);
1917
+ }
1918
+ .modal-with-double-button-sub-title {
1919
+ margin: 0;
1920
+ font-size: var(--font-size-sm);
1921
+ font-weight: var(--font-weight-medium);
1922
+ text-align: center;
1923
+ color: var(--color-grey-scale-600);
1472
1924
  }
1473
1925
  .modal-with-double-button-content {
1474
- margin-top: 20px;
1926
+ margin-top: var(--spacing-20);
1475
1927
  }
1476
1928
  .modal-with-double-button-close {
1477
1929
  display: flex;
1478
1930
  justify-content: space-between;
1479
1931
  align-items: center;
1480
- gap: 16px;
1932
+ gap: var(--spacing-16);
1481
1933
  width: 100%;
1482
- margin-top: 30px;
1934
+ margin-top: var(--spacing-30);
1483
1935
  }
1484
1936
  .modal-with-double-button-close.row {
1485
1937
  display: flex;
1486
1938
  justify-content: center;
1487
1939
  align-items: center;
1488
- gap: 16px;
1940
+ gap: var(--spacing-16);
1489
1941
  }
1490
1942
  .modal-with-double-button-close.row > * {
1491
1943
  flex: 1;
@@ -1495,58 +1947,354 @@ p {
1495
1947
  flex-direction: column;
1496
1948
  justify-content: center;
1497
1949
  align-items: center;
1498
- gap: 10px;
1950
+ gap: var(--spacing-10);
1499
1951
  }
1500
1952
  .modal-with-double-button-close.column > * {
1501
1953
  width: 100%;
1502
1954
  }
1503
- .radio:where(.radio-group) {
1504
- display: flex;
1505
- flex-direction: column;
1506
- gap: 16px;
1507
- }
1508
- .radio:where(.radio-button) {
1509
- display: flex;
1510
- align-items: center;
1511
- justify-content: center;
1512
- width: 18px;
1513
- height: 18px;
1514
- border-radius: 50%;
1515
- background-color: var(--color-grey-scale-200);
1955
+ /***************************************************************************************************
1956
+ * *
1957
+ * modal *
1958
+ * *
1959
+ ***************************************************************************************************/
1960
+ .modal {
1961
+ align-items: stretch;
1962
+ gap: var(--spacing-20);
1963
+ max-width: calc(100% - var(--spacing-30) * 2);
1964
+ max-height: calc(100% - var(--spacing-30) * 2);
1965
+ overflow: auto;
1966
+ }
1967
+ .modal.size-s {
1968
+ width: var(--modal-width-s);
1516
1969
  }
1517
- .radio:where(.radio-indicator) {
1518
- width: 8px;
1519
- height: 8px;
1520
- border-radius: 50%;
1521
- background-color: var(--color-purple-900);
1970
+ .modal.size-m {
1971
+ width: var(--modal-width-m);
1522
1972
  }
1523
- .radio:where(.radio-label) {
1524
- font-size: var(--font-size-sm);
1525
- font-weight: var(--font-weight-medium);
1526
- color: var(--color-black);
1973
+ .modal.size-l {
1974
+ width: var(--modal-width-l);
1527
1975
  }
1528
- .base-table {
1529
- width: -moz-fit-content;
1530
- width: fit-content;
1976
+ .modal-header {
1977
+ display: flex;
1978
+ justify-content: space-between;
1979
+ align-items: flex-start;
1980
+ gap: var(--spacing-10);
1531
1981
  }
1532
- .base-table .header {
1533
- display: flex;
1982
+ .modal-title {
1983
+ flex: 1;
1984
+ margin: 0;
1985
+ font-size: var(--font-size-lg);
1986
+ font-weight: var(--font-weight-bold);
1987
+ color: var(--color-black);
1988
+ }
1989
+ .modal-close-icon {
1990
+ flex-shrink: 0;
1991
+ width: var(--icon-size-m);
1992
+ height: var(--icon-size-m);
1993
+ padding: 0;
1994
+ background-color: transparent;
1995
+ color: var(--color-grey-scale-600);
1996
+ }
1997
+ .modal-description {
1998
+ margin: 0;
1999
+ font-size: var(--font-size-sm);
2000
+ font-weight: var(--font-weight-medium);
2001
+ color: var(--color-grey-scale-600);
2002
+ }
2003
+ .modal-body {
2004
+ font-size: var(--font-size-sm);
2005
+ color: var(--color-black);
2006
+ }
2007
+ .modal-footer {
2008
+ display: flex;
2009
+ justify-content: flex-end;
2010
+ align-items: center;
2011
+ gap: var(--spacing-10);
2012
+ }
2013
+ .base-pagination:where(.item) {
2014
+ display: inline-flex;
1534
2015
  align-items: center;
1535
- width: 100%;
2016
+ justify-content: center;
2017
+ padding: 0;
2018
+ background-color: transparent;
2019
+ border: none;
2020
+ cursor: var(--cursor-button);
1536
2021
  }
1537
- .base-table .body {
1538
- width: 100%;
2022
+ .base-pagination[data-disabled]:where(.item) {
2023
+ cursor: var(--cursor-disabled);
2024
+ }
2025
+ .base-pagination:where(.ellipsis) {
2026
+ display: inline-flex;
2027
+ align-items: center;
2028
+ justify-content: center;
2029
+ -webkit-user-select: none;
2030
+ -moz-user-select: none;
2031
+ user-select: none;
2032
+ }
2033
+ /***************************************************************************************************
2034
+ * *
2035
+ * pagination *
2036
+ * *
2037
+ ***************************************************************************************************/
2038
+ .pagination {
2039
+ display: inline-flex;
2040
+ align-items: center;
2041
+ gap: var(--spacing-4);
2042
+ }
2043
+ .pagination.size-s {
2044
+ --pagination-item-size: var(--control-height-s);
2045
+ --pagination-icon-size: var(--icon-size-s);
2046
+ font-size: var(--font-size-xsm);
2047
+ line-height: var(--line-height-xsm);
2048
+ }
2049
+ .pagination.size-m {
2050
+ --pagination-item-size: var(--control-height-m);
2051
+ --pagination-icon-size: var(--icon-size-m);
2052
+ font-size: var(--font-size-sm);
2053
+ line-height: var(--line-height-sm);
2054
+ }
2055
+ .pagination-item {
2056
+ min-width: var(--pagination-item-size);
2057
+ height: var(--pagination-item-size);
2058
+ padding: 0 var(--spacing-4);
2059
+ border-radius: var(--radius-6);
2060
+ color: var(--color-grey-scale-600);
2061
+ font-size: inherit;
2062
+ line-height: inherit;
2063
+ font-weight: var(--font-weight-medium);
2064
+ transition:
2065
+ background-color var(--motion-fast) var(--motion-ease),
2066
+ color var(--motion-fast) var(--motion-ease);
2067
+ }
2068
+ .pagination-item:not(:disabled):hover {
2069
+ background-color: var(--color-grey-scale-100);
2070
+ color: var(--color-purple-900);
2071
+ }
2072
+ .pagination-item[data-state='active'] {
2073
+ background-color: var(--color-purple-50);
2074
+ color: var(--color-purple-900);
2075
+ font-weight: var(--font-weight-bold);
2076
+ }
2077
+ .pagination-item:disabled {
2078
+ background-color: transparent;
2079
+ color: var(--color-grey-scale-300);
2080
+ }
2081
+ .pagination-ellipsis {
2082
+ min-width: var(--pagination-item-size);
2083
+ height: var(--pagination-item-size);
2084
+ color: var(--color-grey-scale-400);
2085
+ }
2086
+ .pagination-icon {
2087
+ width: var(--pagination-icon-size);
2088
+ height: var(--pagination-icon-size);
2089
+ }
2090
+ .pagination-icon-prev {
2091
+ transform: rotate(90deg);
2092
+ }
2093
+ .pagination-icon-next {
2094
+ transform: rotate(-90deg);
2095
+ }
2096
+ .base-radio:where(.button) {
2097
+ padding: 0;
1539
2098
  }
1540
- .base-table .row {
2099
+ /***************************************************************************************************
2100
+ * *
2101
+ * radio *
2102
+ * *
2103
+ ***************************************************************************************************/
2104
+ .radio:where(.radio-group) {
2105
+ display: flex;
2106
+ flex-direction: column;
2107
+ gap: var(--spacing-16);
2108
+ }
2109
+ .radio:where(.radio-option) {
1541
2110
  display: flex;
1542
2111
  align-items: center;
1543
- width: 100%;
2112
+ gap: var(--spacing-6);
1544
2113
  }
1545
- .base-table .cell {
1546
- text-align: start;
2114
+ .radio:where(.radio-button) {
1547
2115
  display: flex;
1548
- flex-direction: column;
2116
+ align-items: center;
1549
2117
  justify-content: center;
2118
+ width: var(--radio-size);
2119
+ height: var(--radio-size);
2120
+ border-radius: 50%;
2121
+ background-color: var(--color-grey-scale-200);
2122
+ }
2123
+ .radio:where(.radio-indicator) {
2124
+ width: var(--radio-dot-size);
2125
+ height: var(--radio-dot-size);
2126
+ border-radius: 50%;
2127
+ background-color: var(--color-purple-900);
2128
+ }
2129
+ .radio:where(.radio-label) {
2130
+ font-size: var(--font-size-sm);
2131
+ font-weight: var(--font-weight-medium);
2132
+ color: var(--color-black);
2133
+ }
2134
+ /* disabled: 글자·점은 회색, 커서는 비활성. 버튼은 BaseButton 이, 라벨은 RadioLabel 이 data-disabled 를 단다 */
2135
+ .radio.radio-label[data-disabled] {
2136
+ color: var(--color-grey-scale-400);
2137
+ cursor: var(--cursor-disabled);
2138
+ }
2139
+ .radio.radio-button[data-disabled] {
2140
+ cursor: var(--cursor-disabled);
2141
+ background-color: var(--color-grey-scale-100);
2142
+ }
2143
+ .radio.radio-button[data-disabled] .radio-indicator {
2144
+ background-color: var(--color-grey-scale-400);
2145
+ }
2146
+ .base-skeleton {
2147
+ display: block;
2148
+ box-sizing: border-box;
2149
+ }
2150
+ /***************************************************************************************************
2151
+ * *
2152
+ * skeleton *
2153
+ * *
2154
+ ***************************************************************************************************/
2155
+ /* 단일 뼈대(text 한 줄·rect·circle)는 루트가, 여러 줄 text 는 각 .skeleton-line 이 뼈대다. */
2156
+ .skeleton {
2157
+ position: relative;
2158
+ overflow: hidden;
2159
+ height: var(--skeleton-text-height);
2160
+ border-radius: var(--radius-4);
2161
+ background-color: var(--color-grey-scale-200);
2162
+ }
2163
+ .skeleton.shape-circle {
2164
+ border-radius: var(--radius-full);
2165
+ aspect-ratio: 1;
2166
+ flex-shrink: 0;
2167
+ }
2168
+ .skeleton.multiline {
2169
+ display: flex;
2170
+ flex-direction: column;
2171
+ gap: var(--spacing-8);
2172
+ height: auto;
2173
+ overflow: visible;
2174
+ background-color: transparent;
2175
+ }
2176
+ .skeleton-line {
2177
+ position: relative;
2178
+ display: block;
2179
+ overflow: hidden;
2180
+ width: 100%;
2181
+ height: var(--skeleton-text-height);
2182
+ border-radius: var(--radius-4);
2183
+ background-color: var(--color-grey-scale-200);
2184
+ }
2185
+ .skeleton-line:last-child:not(:only-child) {
2186
+ width: var(--skeleton-last-line-width);
2187
+ }
2188
+ .skeleton.animated:not(.multiline)::after,
2189
+ .skeleton.animated .skeleton-line::after {
2190
+ content: '';
2191
+ position: absolute;
2192
+ inset: 0;
2193
+ background: linear-gradient(
2194
+ 90deg,
2195
+ transparent 0%,
2196
+ var(--color-grey-scale-100) 50%,
2197
+ transparent 100%
2198
+ );
2199
+ transform: translateX(-100%);
2200
+ animation: skeleton-shimmer var(--skeleton-duration) var(--motion-ease) infinite;
2201
+ }
2202
+ @media (prefers-reduced-motion: reduce) {
2203
+ .skeleton.animated:not(.multiline)::after,
2204
+ .skeleton.animated .skeleton-line::after {
2205
+ animation: none;
2206
+ }
2207
+ }
2208
+ @keyframes skeleton-shimmer {
2209
+ 0% {
2210
+ transform: translateX(-100%);
2211
+ }
2212
+ 100% {
2213
+ transform: translateX(100%);
2214
+ }
2215
+ }
2216
+ .base-switch:where(.thumb) {
2217
+ display: block;
2218
+ }
2219
+ .base-switch:where(.label) {
2220
+ font-size: var(--font-size-sm);
2221
+ font-weight: var(--font-weight-medium);
2222
+ color: var(--color-black);
2223
+ }
2224
+ /***************************************************************************************************
2225
+ * *
2226
+ * switch *
2227
+ * *
2228
+ ***************************************************************************************************/
2229
+ .switch {
2230
+ display: inline-flex;
2231
+ align-items: center;
2232
+ gap: var(--spacing-10);
2233
+
2234
+ padding: 0;
2235
+ background-color: transparent;
2236
+ border: none;
2237
+ cursor: var(--cursor-button);
2238
+ }
2239
+ .switch[data-disabled] {
2240
+ cursor: var(--cursor-disabled);
2241
+ }
2242
+ .switch-track {
2243
+ position: relative;
2244
+ display: inline-flex;
2245
+ align-items: center;
2246
+ flex-shrink: 0;
2247
+ padding: var(--switch-thumb-inset);
2248
+ border-radius: var(--radius-full);
2249
+ background-color: var(--color-grey-scale-300);
2250
+ transition: background-color var(--motion-fast) var(--motion-ease);
2251
+ }
2252
+ .switch-track.size-s {
2253
+ width: var(--switch-width-s);
2254
+ height: var(--switch-height-s);
2255
+ --switch-travel: calc(var(--switch-width-s) - var(--switch-height-s));
2256
+ }
2257
+ .switch-track.size-m {
2258
+ width: var(--switch-width-m);
2259
+ height: var(--switch-height-m);
2260
+ --switch-travel: calc(var(--switch-width-m) - var(--switch-height-m));
2261
+ }
2262
+ .switch-track.size-l {
2263
+ width: var(--switch-width-l);
2264
+ height: var(--switch-height-l);
2265
+ --switch-travel: calc(var(--switch-width-l) - var(--switch-height-l));
2266
+ }
2267
+ .switch-track[data-disabled] {
2268
+ background-color: var(--color-grey-scale-200);
2269
+ }
2270
+ .switch[data-state='checked'] .switch-track {
2271
+ background-color: var(--color-purple-900);
2272
+ }
2273
+ .switch-thumb {
2274
+ aspect-ratio: 1;
2275
+ height: 100%;
2276
+ border-radius: var(--radius-full);
2277
+ background-color: var(--color-white);
2278
+ transition: transform var(--motion-fast) var(--motion-ease);
2279
+ }
2280
+ .switch-thumb[data-state='checked'] {
2281
+ transform: translateX(var(--switch-travel));
2282
+ }
2283
+ .switch-thumb[data-disabled] {
2284
+ background-color: var(--color-grey-scale-100);
2285
+ }
2286
+ .base-table {
2287
+ /* 진짜 테이블 레이아웃을 쓴다. 행을 flex 로 두면 헤더와 본문의 열 폭이 따로 놀아 고정열 경계가 어긋난다 */
2288
+ width: -moz-fit-content;
2289
+ width: fit-content;
2290
+ border-collapse: collapse;
2291
+ border-spacing: 0;
2292
+ table-layout: auto;
2293
+ }
2294
+ .base-table .cell {
2295
+ padding: 0;
2296
+ text-align: start;
2297
+ vertical-align: middle;
1550
2298
  }
1551
2299
  /***************************************************************************************************
1552
2300
  * *
@@ -1560,40 +2308,203 @@ p {
1560
2308
  .data-table-header {
1561
2309
  position: sticky;
1562
2310
  top: 0;
1563
- background-color: #fff;
1564
- z-index: 3;
1565
- border-bottom: 1px solid #e4e4e7;
2311
+ background-color: var(--color-white);
2312
+ z-index: var(--z-sticky-header);
2313
+ border-bottom: var(--hairline) solid var(--color-grey-scale-200);
1566
2314
  }
1567
2315
  .data-table-row {
1568
2316
  position: relative;
1569
- border-bottom: 1px solid var(--color-grey-scale-200);
2317
+ border-bottom: var(--hairline) solid var(--color-grey-scale-200);
1570
2318
  }
1571
2319
  .data-table-row .fixed {
1572
2320
  position: sticky;
1573
- background-color: #fff;
1574
- z-index: 2;
2321
+ background-color: var(--color-white);
2322
+ z-index: var(--z-sticky);
1575
2323
  }
1576
2324
  :is(.data-table-row .fixed) > * {
1577
2325
  position: relative;
1578
- z-index: 1;
2326
+ z-index: var(--z-raised);
1579
2327
  }
1580
2328
  .body .data-table-row:hover {
1581
- background-color: #f5f5f5;
2329
+ background-color: var(--color-grey-scale-100);
1582
2330
  }
1583
2331
  :is(.body .data-table-row:hover) .fixed {
1584
- background-color: #f5f5f5;
2332
+ background-color: var(--color-grey-scale-100);
1585
2333
  }
1586
2334
  .fixed-cell {
1587
2335
  position: sticky;
1588
2336
  left: 0;
1589
2337
  }
1590
- .base-text-field.input {
2338
+ .base-tabs:where(.root) {
2339
+ width: 100%;
2340
+ display: block;
2341
+ }
2342
+ /***************************************************************************************************
2343
+ * *
2344
+ * tabs *
2345
+ * *
2346
+ ***************************************************************************************************/
2347
+ .tabs-list {
2348
+ display: flex;
2349
+ align-items: center;
2350
+ position: relative;
2351
+ }
2352
+ .tabs-list.variant-underline {
2353
+ border-bottom: var(--hairline) solid var(--color-grey-scale-200);
2354
+
2355
+ /* Scrollable logic */
2356
+ overflow-x: auto;
2357
+ scrollbar-width: none;
2358
+ }
2359
+ .tabs-list.variant-underline::-webkit-scrollbar {
2360
+ display: none;
2361
+ }
2362
+ .tabs-trigger {
2363
+ /* 1. 구조적 스타일 (Layout) */
2364
+ display: inline-flex;
2365
+ align-items: center;
2366
+ justify-content: center;
2367
+ cursor: pointer;
2368
+ background: transparent;
2369
+ border: 0;
2370
+ flex-shrink: 0;
2371
+
2372
+ /* 2. 테마 스타일 (Theme) */
2373
+ /* figma 토큰에 11px 없음. 디자이너 확인 전까지 숫자 유지 */
2374
+ padding: 10px 30px 11px 30px; /* raw-px */
2375
+ color: var(--color-grey-scale-400);
2376
+ font-size: var(--font-size-sm);
2377
+ font-weight: var(--font-weight-medium);
2378
+ border-bottom: var(--hairline) solid var(--color-grey-scale-200);
2379
+ transition: color var(--motion-base) var(--motion-ease);
2380
+ }
2381
+ .tabs-trigger:hover {
2382
+ color: var(--color-purple-700);
2383
+ }
2384
+ .tabs-trigger[data-state='active'] {
2385
+ color: var(--color-purple-700);
2386
+ font-weight: var(--font-weight-bold);
2387
+ }
2388
+ .tabs-trigger.disabled {
2389
+ cursor: not-allowed;
2390
+ opacity: 0.5;
2391
+ }
2392
+ /* 3. 변이 스타일 (Variants) */
2393
+ .tabs-trigger.variant-underline {
2394
+ border-bottom: 0;
2395
+ }
2396
+ .tabs-trigger.variant-underline[data-state='active'] {
2397
+ border-bottom-color: transparent;
2398
+ }
2399
+ .tabs-trigger.variant-filled {
2400
+ flex: 1; /* full-width logic integrated */
2401
+ text-align: center;
2402
+ /* figma 토큰에 11px 없음. 디자이너 확인 전까지 숫자 유지 */
2403
+ padding: 11px 30px; /* raw-px */
2404
+ border-bottom: 0;
2405
+ z-index: var(--z-raised);
2406
+ }
2407
+ .tabs-trigger.variant-filled:hover,.tabs-trigger.variant-filled[data-state='active'] {
2408
+ background-color: transparent;
2409
+ }
2410
+ .tabs-indicator {
2411
+ /* 1. 구조적 스타일 (Layout) */
2412
+ position: absolute;
2413
+ pointer-events: none;
2414
+ z-index: var(--z-raised);
2415
+ transition:
2416
+ left var(--motion-base) var(--motion-ease),
2417
+ width var(--motion-base) var(--motion-ease);
2418
+
2419
+ /* 2. 변이 스타일 (Variants) */
2420
+ }
2421
+ .tabs-indicator.variant-underline {
2422
+ bottom: 0;
2423
+ height: var(--tab-indicator-thickness);
2424
+ background-color: var(--color-purple-800);
2425
+ }
2426
+ .tabs-indicator.variant-filled {
2427
+ top: 0;
2428
+ bottom: 0;
2429
+ background-color: var(--color-purple-50);
2430
+ z-index: var(--z-base);
2431
+ }
2432
+ .base-text-area:where(.textarea) {
2433
+ display: block;
2434
+ width: 100%;
2435
+ margin: 0;
1591
2436
  border: none;
1592
2437
  outline: none;
1593
2438
  background-color: transparent;
2439
+ font-family: inherit;
2440
+ font-weight: var(--font-weight-medium);
2441
+ color: var(--color-black);
2442
+ }
2443
+ .base-text-area:where(.textarea)::-moz-placeholder {
2444
+ color: var(--color-grey-scale-400);
2445
+ }
2446
+ .base-text-area:where(.textarea)::placeholder {
2447
+ color: var(--color-grey-scale-400);
2448
+ }
2449
+ .base-text-area[data-disabled]:where(.textarea) {
2450
+ cursor: var(--cursor-disabled);
2451
+ }
2452
+ /***************************************************************************************************
2453
+ * *
2454
+ * text-area *
2455
+ * *
2456
+ ***************************************************************************************************/
2457
+ .text-area {
2458
+ height: -moz-fit-content;
2459
+ height: fit-content;
2460
+ }
2461
+ .text-area-title {
2462
+ margin-bottom: var(--spacing-8);
2463
+ }
2464
+ /* 높이는 rows 가 정한다. size 는 글자 크기와 안쪽 여백만 바꾼다 */
2465
+ .text-area-input-wrapper {
2466
+ display: flex;
2467
+ box-sizing: border-box;
1594
2468
 
2469
+ border-radius: var(--radius-4);
2470
+ border: var(--hairline) solid var(--color-grey-scale-300);
2471
+ }
2472
+ .text-area-input-wrapper.size-s > textarea {
2473
+ padding: var(--spacing-10) var(--spacing-14);
1595
2474
  font-size: var(--font-size-sm);
1596
2475
  line-height: var(--line-height-sm);
2476
+ }
2477
+ .text-area-input-wrapper.size-m > textarea {
2478
+ padding: var(--spacing-14) var(--spacing-14);
2479
+ font-size: var(--font-size-base);
2480
+ line-height: var(--line-height-base);
2481
+ }
2482
+ .text-area-input-wrapper.resize-none > textarea {
2483
+ resize: none;
2484
+ }
2485
+ .text-area-input-wrapper.resize-vertical > textarea {
2486
+ resize: vertical;
2487
+ }
2488
+ .text-area-input-wrapper:has( > textarea[data-disabled]) {
2489
+ border-color: var(--color-grey-scale-300);
2490
+ background-color: var(--color-grey-scale-100);
2491
+ }
2492
+ .text-area-input-wrapper:focus-within {
2493
+ border: var(--hairline) solid var(--color-purple-900);
2494
+ }
2495
+ .text-area-helper-text {
2496
+ margin-top: var(--spacing-4);
2497
+ }
2498
+ .text-area-helper-text.error {
2499
+ color: var(--color-accent-red-500);
2500
+ }
2501
+ .base-text-field.input {
2502
+ border: none;
2503
+ outline: none;
2504
+ background-color: transparent;
2505
+
2506
+ font-size: inherit;
2507
+ line-height: inherit;
1597
2508
  font-weight: var(--font-weight-medium);
1598
2509
  }
1599
2510
  .base-text-field.input::-moz-placeholder {
@@ -1603,76 +2514,303 @@ p {
1603
2514
  color: var(--color-grey-scale-400);
1604
2515
  }
1605
2516
  .base-text-field.input:-webkit-autofill,.base-text-field.input:-webkit-autofill:hover,.base-text-field.input:-webkit-autofill:focus,.base-text-field.input:-webkit-autofill:active {
1606
- box-shadow: 0 0 0px 1000px transparent inset;
2517
+ /* 브라우저 자동완성 배경을 덮는 관용 해킹. 토큰이 아니라 고정값이다 */ /* raw-value */
2518
+ box-shadow: 0 0 0px 1000px transparent inset; /* raw-value */
1607
2519
  -webkit-transition: background-color 5000s ease-in-out 0s;
1608
- transition: background-color 5000s ease-in-out 0s;
2520
+ transition: background-color 5000s ease-in-out 0s; /* raw-value */
1609
2521
  }
1610
2522
  /***************************************************************************************************
1611
2523
  * *
1612
2524
  * base-text-field *
1613
2525
  * *
1614
2526
  ***************************************************************************************************/
2527
+ .text-field {
2528
+ height: -moz-fit-content;
2529
+ height: fit-content;
2530
+ }
1615
2531
  .text-field-title {
1616
- margin-bottom: 8px;
2532
+ margin-bottom: var(--spacing-8);
1617
2533
  }
1618
2534
  .text-field-input-wrapper {
1619
2535
  display: flex;
1620
2536
  align-items: center;
1621
2537
  justify-content: space-between;
1622
- gap: 10px;
2538
+ gap: var(--spacing-10);
1623
2539
 
1624
- padding: 0 14px;
2540
+ /* 높이는 버튼과 같은 --control-height-* 축, 좌우 여백·글자는 size 마다 버튼과 같은 단계 */
1625
2541
 
1626
- border-radius: 4px;
1627
- border: 1px solid var(--color-grey-scale-300);
2542
+ border-radius: var(--radius-4);
2543
+ border: var(--hairline) solid var(--color-grey-scale-300);
1628
2544
  }
2545
+ .text-field-input-wrapper.size-xs {
2546
+ height: var(--control-height-xs);
2547
+ padding: 0 var(--spacing-12);
2548
+ font-size: var(--font-size-xsm);
2549
+ line-height: var(--line-height-xsm);
2550
+ }
2551
+ .text-field-input-wrapper.size-s {
2552
+ height: var(--control-height-s);
2553
+ padding: 0 var(--spacing-14);
2554
+ font-size: var(--font-size-sm);
2555
+ line-height: var(--line-height-sm);
2556
+ }
1629
2557
  .text-field-input-wrapper.size-m {
1630
- height: 40px;
2558
+ height: var(--control-height-m);
2559
+ padding: 0 var(--spacing-16);
2560
+ font-size: var(--font-size-sm);
2561
+ line-height: var(--line-height-sm);
1631
2562
  }
1632
2563
  .text-field-input-wrapper.size-l {
1633
- height: 50px;
2564
+ height: var(--control-height-l);
2565
+ padding: 0 var(--spacing-20);
2566
+ font-size: var(--font-size-base);
2567
+ line-height: var(--line-height-base);
1634
2568
  }
1635
- .text-field-input-wrapper:has([data-disabled='true']) {
2569
+ .text-field-input-wrapper.size-xl {
2570
+ height: var(--control-height-xl);
2571
+ padding: 0 var(--spacing-24);
2572
+ font-size: var(--font-size-lg);
2573
+ line-height: var(--line-height-lg);
2574
+ }
2575
+ .text-field-input-wrapper:has( > input[data-disabled='true']) {
1636
2576
  border-color: var(--color-grey-scale-300);
1637
2577
  background-color: var(--color-grey-scale-100);
1638
2578
  }
1639
2579
  .text-field-input-wrapper:focus-within {
1640
- border: 1px solid var(--color-purple-900);
2580
+ border: var(--hairline) solid var(--color-purple-900);
1641
2581
  }
1642
2582
  .text-field-input-wrapper > input {
1643
2583
  width: 100%;
1644
2584
  }
1645
2585
  .text-field-helper-text {
1646
- margin-top: 4px;
2586
+ margin-top: var(--spacing-4);
1647
2587
  }
1648
2588
  .text-field-helper-text.error {
1649
2589
  color: var(--color-accent-red-500);
1650
2590
  }
1651
- .base-tooltip {
1652
- z-index: 3;
2591
+ /* 조각(title·close 등)도 base-toast 를 달므로 상자 스타일은 루트와 viewport 에만 건다. */
2592
+ .base-toast:where(:not(.viewport, .title, .description, .action, .close)) {
2593
+ position: relative;
2594
+ display: flex;
2595
+ align-items: flex-start;
2596
+ gap: var(--spacing-12);
2597
+ list-style: none;
1653
2598
  }
2599
+ .base-toast[data-state='open']:where(:not(.viewport,.title,.description,.action,.close)) {
2600
+ animation: toast-in var(--motion-base) var(--motion-ease);
2601
+ }
2602
+ .base-toast[data-state='closed']:where(:not(.viewport,.title,.description,.action,.close)) {
2603
+ animation: toast-out var(--motion-fast) var(--motion-ease) forwards;
2604
+ }
2605
+ .base-toast[data-swipe='move']:where(:not(.viewport,.title,.description,.action,.close)) {
2606
+ transform: translateX(var(--radix-toast-swipe-move-x));
2607
+ }
2608
+ .base-toast[data-swipe='cancel']:where(:not(.viewport,.title,.description,.action,.close)) {
2609
+ transform: translateX(0);
2610
+ transition: transform var(--motion-fast) var(--motion-ease);
2611
+ }
2612
+ .base-toast[data-swipe='end']:where(:not(.viewport,.title,.description,.action,.close)) {
2613
+ animation: toast-swipe-out var(--motion-fast) var(--motion-ease) forwards;
2614
+ }
2615
+ .base-toast:where(.viewport) {
2616
+ position: fixed;
2617
+ z-index: var(--z-toast);
2618
+ display: flex;
2619
+ flex-direction: column;
2620
+ gap: var(--spacing-10);
2621
+ width: var(--toast-width);
2622
+ max-width: 100vw;
2623
+ margin: 0;
2624
+ padding: var(--spacing-24);
2625
+ list-style: none;
2626
+ outline: none;
2627
+ /* 아래에서 올라오는 자리를 기본으로 두고 position 클래스가 덮는다 */
2628
+ --toast-enter: translateY(var(--spacing-16));
2629
+ }
2630
+ .base-toast.position-top-right:where(.viewport) {
2631
+ top: 0;
2632
+ right: 0;
2633
+ --toast-enter: translateY(calc(-1 * var(--spacing-16)));
2634
+ }
2635
+ .base-toast.position-bottom-right:where(.viewport) {
2636
+ right: 0;
2637
+ bottom: 0;
2638
+ }
2639
+ .base-toast.position-bottom-center:where(.viewport) {
2640
+ bottom: 0;
2641
+ left: 50%;
2642
+ transform: translateX(-50%);
2643
+ }
2644
+ .base-toast:where(.title),.base-toast:where(.description) {
2645
+ margin: 0;
2646
+ }
2647
+ .base-toast:where(.action),.base-toast:where(.close) {
2648
+ flex-shrink: 0;
2649
+ padding: 0;
2650
+ border: none;
2651
+ background: transparent;
2652
+ cursor: var(--cursor-button);
2653
+ }
2654
+ @keyframes toast-in {
2655
+ from {
2656
+ opacity: 0;
2657
+ transform: var(--toast-enter);
2658
+ }
2659
+
2660
+ to {
2661
+ opacity: 1;
2662
+ transform: none;
2663
+ }
2664
+ }
2665
+ @keyframes toast-out {
2666
+ from {
2667
+ opacity: 1;
2668
+ }
2669
+
2670
+ to {
2671
+ opacity: 0;
2672
+ }
2673
+ }
2674
+ @keyframes toast-swipe-out {
2675
+ from {
2676
+ transform: translateX(var(--radix-toast-swipe-end-x));
2677
+ }
2678
+
2679
+ to {
2680
+ transform: translateX(calc(100% + var(--spacing-24)));
2681
+ }
2682
+ }
2683
+ @media (prefers-reduced-motion: reduce) {
2684
+ .base-toast:where(:not(.viewport, .title, .description, .action, .close)) {
2685
+ animation: none;
2686
+ }
2687
+ }
2688
+ /***************************************************************************************************
2689
+ * *
2690
+ * toast *
2691
+ * *
2692
+ ***************************************************************************************************/
2693
+ /* Tooltip 과 같은 표면: 진한 바탕에 흰 글자, radius-6. variant 가 바탕색을 정한다(기본 purple-900, success green, warning orange, error red-500 = confirm 버튼) */
2694
+ .toast {
2695
+ align-items: center;
2696
+ padding: var(--spacing-12) var(--spacing-14);
2697
+ border-radius: var(--radius-6);
2698
+ background-color: var(--color-purple-900);
2699
+ color: var(--color-white);
2700
+
2701
+ /* CTAButton secondary 와 같은 연보라. 이 variant 만 글자가 어둡다 */
2702
+ }
2703
+ .toast.variant-secondary {
2704
+ background-color: var(--color-purple-50);
2705
+ color: var(--color-purple-900);
2706
+ }
2707
+ .toast.variant-secondary .toast-title,.toast.variant-secondary .toast-close {
2708
+ color: var(--color-purple-900);
2709
+ }
2710
+ .toast.variant-secondary .toast-description {
2711
+ color: var(--color-purple-700);
2712
+ }
2713
+ .toast.variant-success {
2714
+ background-color: var(--color-accent-green-600);
2715
+ }
2716
+ .toast.variant-success .toast-description {
2717
+ color: var(--color-accent-green-100);
2718
+ }
2719
+ .toast.variant-warning {
2720
+ background-color: var(--color-accent-orange-500);
2721
+ }
2722
+ .toast.variant-warning .toast-description {
2723
+ color: var(--color-accent-orange-100);
2724
+ }
2725
+ .toast.variant-error {
2726
+ background-color: var(--color-accent-red-500);
2727
+ }
2728
+ .toast.variant-error .toast-description {
2729
+ color: var(--color-accent-red-100);
2730
+ }
2731
+ /* success·warning·error 는 앞에 상태 아이콘을 둔다. SVG 에 박힌 색을 글자색으로 맞춘다 */
2732
+ .toast-icon {
2733
+ flex-shrink: 0;
2734
+ width: var(--icon-size-s);
2735
+ height: var(--icon-size-s);
2736
+ }
2737
+ .toast-icon path[stroke] {
2738
+ stroke: currentColor;
2739
+ }
2740
+ .toast-icon path[fill]:not([fill='none']) {
2741
+ fill: currentColor;
2742
+ }
2743
+ .toast-body {
2744
+ display: flex;
2745
+ flex: 1;
2746
+ flex-direction: column;
2747
+ gap: var(--spacing-4);
2748
+ min-width: 0;
2749
+ }
2750
+ .toast-title {
2751
+ font-size: var(--font-size-sm);
2752
+ line-height: var(--line-height-sm);
2753
+ font-weight: var(--font-weight-semibold);
2754
+ color: var(--color-white);
2755
+ word-break: break-word;
2756
+ }
2757
+ .toast-description {
2758
+ font-size: var(--font-size-xsm);
2759
+ line-height: var(--line-height-xsm);
2760
+ font-weight: var(--font-weight-regular);
2761
+ color: var(--color-purple-200);
2762
+ word-break: break-word;
2763
+ }
2764
+ /* action 은 CTAButton(xs·neutral: 흰 바탕, 보라 글자) 이라 모양은 버튼 CSS 가 정한다 */
2765
+ .toast-action {
2766
+ white-space: nowrap;
2767
+ }
2768
+ .toast-close {
2769
+ display: inline-flex;
2770
+ align-items: center;
2771
+ justify-content: center;
2772
+ width: var(--icon-size-s);
2773
+ height: var(--icon-size-s);
2774
+ color: var(--color-white);
2775
+ opacity: 0.7;
2776
+ }
2777
+ .toast-close:hover {
2778
+ opacity: 1;
2779
+ }
2780
+ /* multifly.svg 의 fill 이 회색으로 박혀 있어 글자색을 따르게 한다 */
2781
+ .toast-close svg {
2782
+ width: 100%;
2783
+ height: 100%;
2784
+ }
2785
+ :is(.toast-close svg) path {
2786
+ fill: currentColor;
2787
+ }
2788
+ /* Trigger 도 base-tooltip 을 달므로 z-index 는 Content 에만 건다. */
2789
+ .base-tooltip:where(.content) {
2790
+ z-index: var(--z-tooltip);
2791
+ }
1654
2792
  .base-tooltip.content {
1655
2793
  text-align: center;
1656
2794
  }
2795
+ .base-tooltip:where(.trigger) {
2796
+ width: -moz-fit-content;
2797
+ width: fit-content;
2798
+ }
1657
2799
  /***************************************************************************************************
1658
2800
  * *
1659
2801
  * tooltip *
1660
2802
  * *
1661
2803
  ***************************************************************************************************/
1662
- .tooltip-trigger {
1663
- width: -moz-fit-content;
1664
- width: fit-content;
1665
- }
1666
2804
  .tooltip-content {
1667
2805
  display: flex;
1668
2806
  justify-content: space-around;
1669
2807
  align-items: center;
1670
- gap: 10px;
2808
+ gap: var(--spacing-10);
1671
2809
 
1672
2810
  background-color: var(--color-purple-900);
1673
2811
  color: var(--color-white);
1674
- border-radius: 6px;
1675
- padding: 12px;
2812
+ border-radius: var(--radius-6);
2813
+ padding: var(--spacing-12);
1676
2814
 
1677
2815
  font-size: var(--font-size-sm);
1678
2816
  line-height: var(--line-height-sm);
@@ -1688,42 +2826,42 @@ p {
1688
2826
  border-style: solid;
1689
2827
  }
1690
2828
  .tooltip-content.direction-top {
1691
- transform: translateY(-10px);
2829
+ transform: translateY(calc(-1 * var(--spacing-10)));
1692
2830
  }
1693
2831
  .tooltip-content.direction-top::before {
1694
- bottom: -8px;
2832
+ bottom: calc(-1 * var(--tooltip-arrow));
1695
2833
  left: 50%;
1696
2834
  transform: translateX(-50%);
1697
- border-width: 8px 8px 0 8px;
2835
+ border-width: var(--tooltip-arrow) var(--tooltip-arrow) 0 var(--tooltip-arrow);
1698
2836
  border-color: var(--color-purple-900) transparent transparent transparent;
1699
2837
  }
1700
2838
  .tooltip-content.direction-bottom {
1701
- transform: translateY(10px);
2839
+ transform: translateY(var(--spacing-10));
1702
2840
  }
1703
2841
  .tooltip-content.direction-bottom::before {
1704
- top: -8px;
2842
+ top: calc(-1 * var(--tooltip-arrow));
1705
2843
  left: 50%;
1706
2844
  transform: translateX(-50%);
1707
- border-width: 0 8px 8px 8px;
2845
+ border-width: 0 var(--tooltip-arrow) var(--tooltip-arrow) var(--tooltip-arrow);
1708
2846
  border-color: transparent transparent var(--color-purple-900) transparent;
1709
2847
  }
1710
2848
  .tooltip-content.direction-left {
1711
- transform: translateX(-10px);
2849
+ transform: translateX(calc(-1 * var(--spacing-10)));
1712
2850
  }
1713
2851
  .tooltip-content.direction-left::before {
1714
- right: -8px;
2852
+ right: calc(-1 * var(--tooltip-arrow));
1715
2853
  top: 50%;
1716
2854
  transform: translateY(-50%);
1717
- border-width: 8px 0 8px 8px;
2855
+ border-width: var(--tooltip-arrow) 0 var(--tooltip-arrow) var(--tooltip-arrow);
1718
2856
  border-color: transparent transparent transparent var(--color-purple-900);
1719
2857
  }
1720
2858
  .tooltip-content.direction-right {
1721
- transform: translateX(10px);
2859
+ transform: translateX(var(--spacing-10));
1722
2860
  }
1723
2861
  .tooltip-content.direction-right::before {
1724
- left: -8px;
2862
+ left: calc(-1 * var(--tooltip-arrow));
1725
2863
  top: 50%;
1726
2864
  transform: translateY(-50%);
1727
- border-width: 8px 8px 8px 0;
2865
+ border-width: var(--tooltip-arrow) var(--tooltip-arrow) var(--tooltip-arrow) 0;
1728
2866
  border-color: transparent var(--color-purple-900) transparent transparent;
1729
2867
  }