@3w-witim/ui 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.
@@ -0,0 +1,662 @@
1
+ /* ⚠ 새 :root 변수 블록 추가 시 [data-theme="light"]를 항상 함께 나열할 것 — 라이트 핀 래퍼 동작 조건 */
2
+ :root,
3
+ [data-theme="light"] {
4
+ /* ---- primitive ---- */
5
+ --color-witim-primary-10: #f7f8ff;
6
+ --color-witim-primary-20: #dcdfff;
7
+ --color-witim-primary-30: #b9beff;
8
+ --color-witim-primary-40: #8893ff;
9
+ --color-witim-primary-50: #455fff;
10
+ --color-witim-primary-60: #3f57ec;
11
+ --color-witim-primary-70: #394ed5;
12
+ --color-witim-primary-80: #3144b9;
13
+ --color-witim-primary-90: #29389b;
14
+ --color-witim-primary-100: #1e2972;
15
+ --color-witim-red-10: #fef7f7;
16
+ --color-witim-red-20: #fadcdc;
17
+ --color-witim-red-30: #f6b8b8;
18
+ --color-witim-red-40: #f28888;
19
+ --color-witim-red-50: #ef4444;
20
+ --color-witim-red-60: #dd3f3f;
21
+ --color-witim-red-70: #c7383a;
22
+ --color-witim-red-80: #ad3133;
23
+ --color-witim-red-90: #90292c;
24
+ --color-witim-red-100: #691e24;
25
+ --color-witim-gray-10: #f7f7f9;
26
+ --color-witim-gray-20: #ebecf1;
27
+ --color-witim-gray-30: #bdbecc;
28
+ --color-witim-gray-40: #9192a4;
29
+ --color-witim-gray-50: #51536a;
30
+ --color-witim-gray-60: #3f4155;
31
+ --color-witim-gray-70: #292a36;
32
+ --color-witim-gray-80: #20212b;
33
+ --color-witim-gray-90: #181920;
34
+ --color-witim-gray-100: #0f0f13;
35
+ --color-witim-common-white: #ffffff;
36
+ --color-witim-common-black: #0e0f1a;
37
+ --color-witim-whiteAlpha-8: #ffffff14;
38
+ --color-witim-whiteAlpha-16: #ffffff29;
39
+ --color-witim-whiteAlpha-60: #ffffff99;
40
+ --color-witim-blackAlpha-8: #0e0f1a14;
41
+ --color-witim-blackAlpha-16: #0e0f1a29;
42
+ --color-witim-blackAlpha-60: #0e0f1a99;
43
+
44
+ /* ---- semantic (light = default) ---- */
45
+ --color-bg-base: var(--color-witim-gray-20);
46
+ --color-bg-subtle: var(--color-witim-gray-30);
47
+ --color-bg-emphasis: var(--color-witim-gray-40);
48
+ --color-surface-default: var(--color-witim-common-white);
49
+ --color-surface-raised: var(--color-witim-common-white);
50
+ --color-surface-sunken: var(--color-witim-gray-20);
51
+ --color-surface-hover: var(--color-witim-blackAlpha-8);
52
+ --color-surface-pressed: var(--color-witim-blackAlpha-16);
53
+ --color-overlay-scrim: var(--color-witim-blackAlpha-60);
54
+ --color-text-strong: var(--color-witim-gray-100);
55
+ --color-text-default: var(--color-witim-gray-90);
56
+ --color-text-subtle: var(--color-witim-gray-50);
57
+ --color-text-disabled: var(--color-witim-gray-40);
58
+ --color-text-on-brand: var(--color-witim-common-white);
59
+ --color-border-subtle: var(--color-witim-gray-20);
60
+ --color-border-default: var(--color-witim-gray-30);
61
+ --color-border-strong: var(--color-witim-gray-50);
62
+ --color-border-focus: var(--color-witim-primary-50);
63
+ --color-brand-solid: var(--color-witim-primary-50);
64
+ --color-brand-solid-hover: var(--color-witim-primary-60);
65
+ --color-brand-solid-pressed: var(--color-witim-primary-70);
66
+ --color-brand-subtle: var(--color-witim-primary-10);
67
+ --color-brand-text: var(--color-witim-primary-60);
68
+ --color-brand-border: var(--color-witim-primary-30);
69
+ --color-danger-solid: var(--color-witim-red-50);
70
+ --color-danger-solid-hover: var(--color-witim-red-60);
71
+ --color-danger-subtle: var(--color-witim-red-10);
72
+ --color-danger-text: var(--color-witim-red-70);
73
+ --color-danger-border: var(--color-witim-red-30);
74
+ --color-sidebar-bg: var(--color-witim-gray-10);
75
+ --color-sidebar-accent: var(--color-witim-gray-20);
76
+ --color-sidebar-fg: var(--color-witim-gray-50);
77
+ --color-sidebar-accent-fg: var(--color-witim-gray-90);
78
+ --color-rail-active: var(--color-witim-primary-20);
79
+ --color-rail-active-fg: var(--color-witim-primary-60);
80
+ --color-brand-soft: var(--color-witim-primary-40);
81
+ --color-chart-muted: var(--color-witim-gray-30);
82
+ --color-presence-away-bg: var(--color-witim-gray-50);
83
+ --color-presence-away-fg: var(--color-witim-common-white);
84
+ --color-presence-offline: var(--color-witim-gray-40);
85
+
86
+ /* ---- component (derived) ---- */
87
+ --comp-button-primary-bg: var(--color-brand-solid);
88
+ --comp-button-primary-bg-hover: var(--color-brand-solid-hover);
89
+ --comp-button-primary-bg-press: var(--color-brand-solid-pressed);
90
+ --comp-button-primary-text: var(--color-text-on-brand);
91
+ --comp-button-danger-bg: var(--color-danger-solid);
92
+ --comp-button-danger-bg-hover: var(--color-danger-solid-hover);
93
+ --comp-button-danger-text: var(--color-text-on-brand);
94
+ --comp-button-neutral-bg: var(--color-surface-default);
95
+ --comp-button-neutral-bg-hover: var(--color-surface-hover);
96
+ --comp-button-neutral-border: var(--color-border-default);
97
+ --comp-button-neutral-text: var(--color-text-default);
98
+ --comp-button-ghost-bg-hover: var(--color-surface-hover);
99
+ --comp-button-ghost-text: var(--color-text-default);
100
+ --comp-button-disabled-bg: var(--color-bg-emphasis);
101
+ --comp-button-disabled-text: var(--color-text-disabled);
102
+ --comp-input-bg: var(--color-surface-default);
103
+ --comp-input-border: var(--color-border-default);
104
+ --comp-input-border-hover: var(--color-border-strong);
105
+ --comp-input-border-focus: var(--color-border-focus);
106
+ --comp-input-border-error: var(--color-danger-border);
107
+ --comp-input-text: var(--color-text-default);
108
+ --comp-input-placeholder: var(--color-text-subtle);
109
+ --comp-input-disabled-bg: var(--color-bg-subtle);
110
+ --comp-card-bg: var(--color-surface-default);
111
+ --comp-card-bg-raised: var(--color-surface-raised);
112
+ --comp-card-border: var(--color-border-subtle);
113
+ --comp-label-neutral-bg: var(--color-witim-gray-20);
114
+ --comp-label-neutral-text: var(--color-text-default);
115
+ --comp-label-brand-bg: var(--color-brand-subtle);
116
+ --comp-label-brand-text: var(--color-brand-text);
117
+ --comp-label-danger-bg: var(--color-danger-subtle);
118
+ --comp-label-danger-text: var(--color-danger-text);
119
+ --comp-choice-bg: var(--color-surface-default);
120
+ --comp-choice-border: var(--color-border-strong);
121
+ --comp-choice-bg-checked: var(--color-brand-solid);
122
+ --comp-choice-mark: var(--color-text-on-brand);
123
+ --comp-choice-border-disabled: var(--color-border-subtle);
124
+ --comp-toggle-track: var(--color-bg-emphasis);
125
+ --comp-toggle-track-on: var(--color-brand-solid);
126
+ --comp-toggle-thumb: var(--color-witim-common-white);
127
+ --comp-tooltip-bg: var(--color-witim-gray-90);
128
+ --comp-tooltip-text: var(--color-witim-common-white);
129
+ --comp-modal-bg: var(--color-surface-raised);
130
+ --comp-modal-border: var(--color-border-subtle);
131
+ --comp-modal-scrim: var(--color-overlay-scrim);
132
+ --comp-dropdown-bg: var(--color-surface-raised);
133
+ --comp-dropdown-border: var(--color-border-subtle);
134
+ --comp-dropdown-item-text: var(--color-text-default);
135
+ --comp-dropdown-item-bg-hover: var(--color-surface-hover);
136
+ --comp-dropdown-item-text-active: var(--color-brand-text);
137
+ --comp-tab-text: var(--color-text-subtle);
138
+ --comp-tab-text-active: var(--color-text-strong);
139
+ --comp-tab-indicator: var(--color-brand-solid);
140
+ --comp-tab-border: var(--color-border-subtle);
141
+ --comp-tab-bg-hover: var(--color-surface-hover);
142
+ --comp-table-header-bg: var(--color-bg-subtle);
143
+ --comp-table-header-text: var(--color-text-subtle);
144
+ --comp-table-cell-text: var(--color-text-default);
145
+ --comp-table-border: var(--color-border-subtle);
146
+ --comp-table-row-bg-hover: var(--color-surface-hover);
147
+ --comp-table-row-bg-selected: var(--color-brand-subtle);
148
+ --comp-toast-bg: var(--color-surface-raised);
149
+ --comp-toast-border: var(--color-border-subtle);
150
+ --comp-toast-text: var(--color-text-default);
151
+ --comp-avatar-bg: var(--color-bg-emphasis);
152
+ --comp-avatar-text: var(--color-text-default);
153
+ --comp-avatar-ring: var(--color-surface-default);
154
+ --comp-sheet-bg: var(--color-surface-raised);
155
+ --comp-sheet-border: var(--color-border-subtle);
156
+ --comp-sheet-scrim: var(--color-overlay-scrim);
157
+ --comp-sheet-handle: var(--color-bg-emphasis);
158
+ --comp-select-bg: var(--color-surface-default);
159
+ --comp-select-border: var(--color-border-default);
160
+ --comp-select-border-hover: var(--color-border-strong);
161
+ --comp-select-border-focus: var(--color-border-focus);
162
+ --comp-select-text: var(--color-text-default);
163
+ --comp-select-placeholder: var(--color-text-subtle);
164
+ --comp-select-disabled-bg: var(--color-bg-subtle);
165
+ --comp-textarea-bg: var(--color-surface-default);
166
+ --comp-textarea-border: var(--color-border-default);
167
+ --comp-textarea-border-hover: var(--color-border-strong);
168
+ --comp-textarea-border-focus: var(--color-border-focus);
169
+ --comp-textarea-text: var(--color-text-default);
170
+ --comp-textarea-placeholder: var(--color-text-subtle);
171
+ --comp-textarea-disabled-bg: var(--color-bg-subtle);
172
+ --comp-chip-bg: var(--color-surface-default);
173
+ --comp-chip-text: var(--color-text-default);
174
+ --comp-chip-border: var(--color-border-default);
175
+ --comp-chip-bg-hover: var(--color-surface-hover);
176
+ --comp-chip-bg-selected: var(--color-brand-subtle);
177
+ --comp-chip-text-selected: var(--color-brand-text);
178
+ --comp-chip-border-selected: var(--color-brand-border);
179
+ --comp-chip-remove: var(--color-text-subtle);
180
+ --comp-alert-info-bg: var(--color-brand-subtle);
181
+ --comp-alert-info-text: var(--color-brand-text);
182
+ --comp-alert-info-border: var(--color-brand-border);
183
+ --comp-alert-danger-bg: var(--color-danger-subtle);
184
+ --comp-alert-danger-text: var(--color-danger-text);
185
+ --comp-alert-danger-border: var(--color-danger-border);
186
+ --comp-alert-neutral-bg: var(--color-bg-subtle);
187
+ --comp-alert-neutral-text: var(--color-text-default);
188
+ --comp-alert-neutral-border: var(--color-border-subtle);
189
+ --comp-pagination-text: var(--color-text-default);
190
+ --comp-pagination-bg-hover: var(--color-surface-hover);
191
+ --comp-pagination-bg-active: var(--color-brand-solid);
192
+ --comp-pagination-text-active: var(--color-text-on-brand);
193
+ --comp-pagination-disabled: var(--color-text-disabled);
194
+ --comp-progress-track: var(--color-bg-subtle);
195
+ --comp-progress-fill: var(--color-brand-solid);
196
+ --comp-skeleton-base: var(--color-bg-subtle);
197
+ --comp-skeleton-shimmer: var(--color-bg-emphasis);
198
+ --comp-segment-bg: var(--color-bg-subtle);
199
+ --comp-segment-thumb: var(--color-surface-default);
200
+ --comp-segment-text: var(--color-text-subtle);
201
+ --comp-segment-text-active: var(--color-text-strong);
202
+ /* component shadows -> elevation roles */
203
+ --comp-modal-shadow: var(--elevation-modal);
204
+ --comp-dropdown-shadow: var(--elevation-dropdown);
205
+ --comp-toast-shadow: var(--elevation-toast);
206
+ --comp-sheet-shadow: var(--elevation-modal);
207
+ }
208
+
209
+ [data-theme="dark"] {
210
+ /* semantic overrides */
211
+ --color-bg-base: var(--color-witim-gray-100);
212
+ --color-bg-subtle: var(--color-witim-gray-90);
213
+ --color-bg-emphasis: var(--color-witim-gray-70);
214
+ --color-surface-default: var(--color-witim-gray-80);
215
+ --color-surface-raised: var(--color-witim-gray-70);
216
+ --color-surface-sunken: var(--color-witim-gray-90);
217
+ --color-surface-hover: var(--color-witim-gray-70);
218
+ --color-surface-pressed: var(--color-witim-gray-60);
219
+ --color-overlay-scrim: var(--color-witim-blackAlpha-60);
220
+ --color-text-strong: var(--color-witim-gray-20);
221
+ --color-text-default: var(--color-witim-gray-30);
222
+ --color-text-subtle: var(--color-witim-gray-40);
223
+ --color-text-disabled: var(--color-witim-gray-50);
224
+ --color-text-on-brand: var(--color-witim-common-white);
225
+ --color-border-subtle: var(--color-witim-gray-60);
226
+ --color-border-default: var(--color-witim-gray-50);
227
+ --color-border-strong: var(--color-witim-gray-40);
228
+ --color-border-focus: var(--color-witim-primary-40);
229
+ --color-brand-solid: var(--color-witim-primary-50);
230
+ --color-brand-solid-hover: var(--color-witim-primary-40);
231
+ --color-brand-solid-pressed: var(--color-witim-primary-30);
232
+ --color-brand-subtle: var(--color-witim-primary-100);
233
+ --color-brand-text: var(--color-witim-primary-40);
234
+ --color-brand-border: var(--color-witim-primary-70);
235
+ --color-danger-solid: var(--color-witim-red-50);
236
+ --color-danger-solid-hover: var(--color-witim-red-40);
237
+ --color-danger-subtle: var(--color-witim-red-100);
238
+ --color-danger-text: var(--color-witim-red-40);
239
+ --color-danger-border: var(--color-witim-red-70);
240
+ --color-sidebar-bg: var(--color-witim-gray-80);
241
+ --color-sidebar-accent: var(--color-witim-gray-70);
242
+ --color-sidebar-fg: var(--color-witim-gray-30);
243
+ --color-sidebar-accent-fg: var(--color-witim-common-white);
244
+ /* rail-active(-fg) 는 라이트/다크 동일 — 다크 오버라이드 없음 */
245
+ --color-brand-soft: var(--color-witim-primary-70);
246
+ --color-chart-muted: var(--color-witim-gray-60);
247
+ --color-presence-away-bg: var(--color-witim-gray-30);
248
+ --color-presence-away-fg: var(--color-witim-gray-90);
249
+ /* presence-offline 은 라이트/다크 동일(gray-40) — 다크 오버라이드 없음 */
250
+ /* component overrides (inverse) */
251
+ --comp-label-neutral-bg: var(--color-witim-gray-60);
252
+ /* tooltip: 다크에선 반전(밝은 버블 + 검정 텍스트) — 어두운 페이지 위에서 뚜렷 */
253
+ --comp-tooltip-bg: var(--color-witim-gray-10);
254
+ --comp-tooltip-text: var(--color-witim-common-black);
255
+ }
256
+ /* === FOUNDATION: radius + typography (gen_typography.py) === */
257
+ :root,
258
+ [data-theme="light"] {
259
+ /* radius */
260
+ --radius-xs: 4px;
261
+ --radius-sm: 8px;
262
+ --radius-lg: 20px;
263
+ --radius-full: 9999px;
264
+
265
+ /* typography */
266
+ --font-sans:
267
+ "Inter", "Pretendard", -apple-system, BlinkMacSystemFont,
268
+ "Apple SD Gothic Neo", sans-serif;
269
+ --font-weight-regular: 400;
270
+ --font-weight-medium: 500;
271
+ --font-weight-semibold: 600;
272
+ --font-weight-bold: 700;
273
+ --tracking-kr: -0.04em;
274
+ --tracking-en: -0.02em;
275
+ --text-display-size: 32px;
276
+ --text-heading-lg-size: 28px;
277
+ --text-heading-md-size: 24px;
278
+ --text-heading-sm-size: 20px;
279
+ --text-title-size: 18px;
280
+ --text-body-lg-size: 18px;
281
+ --text-body-size: 16px;
282
+ --text-body-sm-size: 14px;
283
+ --text-button1-size: 18px;
284
+ --text-button2-size: 16px;
285
+ --text-label1-size: 14px;
286
+ --text-label2-size: 14px;
287
+ --text-caption-size: 12px;
288
+ }
289
+
290
+ /* text styles — apply directly, e.g. <h1 class="text-display"> */
291
+ .text-display {
292
+ font-family: var(--font-sans);
293
+ font-size: var(--text-display-size);
294
+ font-weight: var(--font-weight-bold);
295
+ line-height: 1.4;
296
+ letter-spacing: var(--tracking-kr);
297
+ }
298
+ .text-heading-lg {
299
+ font-family: var(--font-sans);
300
+ font-size: var(--text-heading-lg-size);
301
+ font-weight: var(--font-weight-bold);
302
+ line-height: 1.4;
303
+ letter-spacing: var(--tracking-kr);
304
+ }
305
+ .text-heading-md {
306
+ font-family: var(--font-sans);
307
+ font-size: var(--text-heading-md-size);
308
+ font-weight: var(--font-weight-bold);
309
+ line-height: 1.4;
310
+ letter-spacing: var(--tracking-kr);
311
+ }
312
+ .text-heading-sm {
313
+ font-family: var(--font-sans);
314
+ font-size: var(--text-heading-sm-size);
315
+ font-weight: var(--font-weight-bold);
316
+ line-height: 1.4;
317
+ letter-spacing: var(--tracking-kr);
318
+ }
319
+ .text-title {
320
+ font-family: var(--font-sans);
321
+ font-size: var(--text-title-size);
322
+ font-weight: var(--font-weight-bold);
323
+ line-height: 1.4;
324
+ letter-spacing: var(--tracking-kr);
325
+ }
326
+ .text-body-lg {
327
+ font-family: var(--font-sans);
328
+ font-size: var(--text-body-lg-size);
329
+ font-weight: var(--font-weight-regular);
330
+ line-height: 1.5;
331
+ letter-spacing: var(--tracking-kr);
332
+ }
333
+ .text-body {
334
+ font-family: var(--font-sans);
335
+ font-size: var(--text-body-size);
336
+ font-weight: var(--font-weight-regular);
337
+ line-height: 1.5;
338
+ letter-spacing: var(--tracking-kr);
339
+ }
340
+ .text-body-sm {
341
+ font-family: var(--font-sans);
342
+ font-size: var(--text-body-sm-size);
343
+ font-weight: var(--font-weight-regular);
344
+ line-height: 1.5;
345
+ letter-spacing: var(--tracking-kr);
346
+ }
347
+ .text-button1 {
348
+ font-family: var(--font-sans);
349
+ font-size: var(--text-button1-size);
350
+ font-weight: var(--font-weight-semibold);
351
+ line-height: 1.4;
352
+ letter-spacing: var(--tracking-kr);
353
+ }
354
+ .text-button2 {
355
+ font-family: var(--font-sans);
356
+ font-size: var(--text-button2-size);
357
+ font-weight: var(--font-weight-semibold);
358
+ line-height: 1.4;
359
+ letter-spacing: var(--tracking-kr);
360
+ }
361
+ .text-label1 {
362
+ font-family: var(--font-sans);
363
+ font-size: var(--text-label1-size);
364
+ font-weight: var(--font-weight-semibold);
365
+ line-height: 1.4;
366
+ letter-spacing: var(--tracking-kr);
367
+ }
368
+ .text-label2 {
369
+ font-family: var(--font-sans);
370
+ font-size: var(--text-label2-size);
371
+ font-weight: var(--font-weight-regular);
372
+ line-height: 1.4;
373
+ letter-spacing: var(--tracking-kr);
374
+ }
375
+ .text-caption {
376
+ font-family: var(--font-sans);
377
+ font-size: var(--text-caption-size);
378
+ font-weight: var(--font-weight-medium);
379
+ line-height: 1.4;
380
+ letter-spacing: var(--tracking-kr);
381
+ }
382
+ /* === SPACING + LAYOUT (gen_spacing.py) === */
383
+ :root,
384
+ [data-theme="light"] {
385
+ /* spacing (4pt grid) */
386
+ --spacing-0: 0px;
387
+ --spacing-2: 2px;
388
+ --spacing-4: 4px;
389
+ --spacing-8: 8px;
390
+ --spacing-12: 12px;
391
+ --spacing-16: 16px;
392
+ --spacing-20: 20px;
393
+ --spacing-24: 24px;
394
+ --spacing-32: 32px;
395
+ --spacing-40: 40px;
396
+ --spacing-48: 48px;
397
+ --spacing-64: 64px;
398
+
399
+ /* layout */
400
+ --layout-screen-margin: 16px;
401
+ --layout-card-margin: 18px;
402
+ --layout-gutter: 16px;
403
+ --layout-section-gap: 24px;
404
+ --layout-container-max: 1200px;
405
+
406
+ /* breakpoint (참조용 — @media엔 리터럴 px) */
407
+ --bp-sm: 640px;
408
+ --bp-md: 768px;
409
+ --bp-lg: 1024px;
410
+ --bp-xl: 1280px;
411
+ }
412
+
413
+ /* ---- elevation (shadow) — light defaults ---- */
414
+ :root,
415
+ [data-theme="light"] {
416
+ --shadow-xs: 0 1px 2px 0 rgba(14, 15, 26, 0.06);
417
+ --shadow-sm:
418
+ 0 1px 2px 0 rgba(14, 15, 26, 0.06), 0 2px 6px -1px rgba(14, 15, 26, 0.08);
419
+ --shadow-md:
420
+ 0 2px 4px -1px rgba(14, 15, 26, 0.07), 0 6px 14px -2px rgba(14, 15, 26, 0.1);
421
+ --shadow-lg:
422
+ 0 4px 8px -2px rgba(14, 15, 26, 0.08),
423
+ 0 12px 28px -4px rgba(14, 15, 26, 0.12);
424
+ --shadow-xl:
425
+ 0 8px 16px -4px rgba(14, 15, 26, 0.1),
426
+ 0 24px 56px -8px rgba(14, 15, 26, 0.18);
427
+ --elevation-card: var(--shadow-sm);
428
+ --elevation-dropdown: var(--shadow-md);
429
+ --elevation-popover: var(--shadow-lg);
430
+ --elevation-modal: var(--shadow-xl);
431
+ --elevation-toast: var(--shadow-lg);
432
+ }
433
+ [data-theme="dark"] {
434
+ --shadow-xs: 0 1px 2px 0 rgba(14, 15, 26, 0.32);
435
+ --shadow-sm:
436
+ 0 1px 2px 0 rgba(14, 15, 26, 0.32), 0 2px 6px -1px rgba(14, 15, 26, 0.36);
437
+ --shadow-md:
438
+ 0 2px 4px -1px rgba(14, 15, 26, 0.36),
439
+ 0 6px 14px -2px rgba(14, 15, 26, 0.42);
440
+ --shadow-lg:
441
+ 0 4px 8px -2px rgba(14, 15, 26, 0.4),
442
+ 0 12px 28px -4px rgba(14, 15, 26, 0.48);
443
+ --shadow-xl:
444
+ 0 8px 16px -4px rgba(14, 15, 26, 0.44),
445
+ 0 24px 56px -8px rgba(14, 15, 26, 0.56);
446
+ }
447
+
448
+ /* ---- focus ring (keyboard) — WCAG 2.4.7 / 1.4.11 ---- */
449
+ :root,
450
+ [data-theme="light"] {
451
+ --focus-ring-width: 2px;
452
+ --focus-ring-offset: 2px;
453
+ --focus-ring-color: var(--color-border-focus);
454
+ --focus-ring-color-danger: var(--color-danger-solid);
455
+ --focus-ring: var(--focus-ring-width) solid var(--focus-ring-color);
456
+ --focus-ring-shadow:
457
+ 0 0 0 var(--focus-ring-offset) var(--color-surface-default),
458
+ 0 0 0 calc(var(--focus-ring-offset) + var(--focus-ring-width))
459
+ var(--focus-ring-color);
460
+ }
461
+ /* base: visible keyboard focus on interactive elements. :where() => 0 specificity (overridable) */
462
+ :where(
463
+ a,
464
+ button,
465
+ input,
466
+ select,
467
+ textarea,
468
+ summary,
469
+ [tabindex],
470
+ [role="button"],
471
+ [role="tab"],
472
+ [role="link"],
473
+ [role="menuitem"],
474
+ [role="checkbox"],
475
+ [role="radio"],
476
+ [role="switch"]
477
+ ):focus-visible {
478
+ outline: var(--focus-ring);
479
+ outline-offset: var(--focus-ring-offset);
480
+ }
481
+ /* opt-in halo for colored buttons / chips / clipped corners */
482
+ .focus-ring-shadow:focus-visible {
483
+ outline: none;
484
+ box-shadow: var(--focus-ring-shadow);
485
+ }
486
+ .focus-ring-danger:focus-visible {
487
+ outline-color: var(--focus-ring-color-danger);
488
+ }
489
+
490
+ /* ---- component specs (dimensions: padding/gap/height/radius/icon/font) ---- */
491
+ :root,
492
+ [data-theme="light"] {
493
+ --comp-button-height: var(--spacing-40);
494
+ --comp-button-padding-x: var(--spacing-16);
495
+ --comp-button-gap: var(--spacing-8);
496
+ --comp-button-radius: var(--radius-xs);
497
+ --comp-button-icon: var(--spacing-20);
498
+ --comp-button-font: var(--text-button2-size);
499
+ --comp-button-border-width: 1px;
500
+ --comp-input-height: var(--spacing-40);
501
+ --comp-input-padding-x: var(--spacing-12);
502
+ --comp-input-gap: var(--spacing-8);
503
+ --comp-input-radius: var(--radius-xs);
504
+ --comp-input-icon: var(--spacing-20);
505
+ --comp-input-font: var(--text-body-size);
506
+ --comp-input-border-width: 1px;
507
+ --comp-card-padding: var(--spacing-20);
508
+ --comp-card-gap: var(--spacing-12);
509
+ --comp-card-radius: var(--radius-sm);
510
+ --comp-card-border-width: 1px;
511
+ --comp-label-padding-x: var(--spacing-8);
512
+ --comp-label-padding-y: var(--spacing-2);
513
+ --comp-label-gap: var(--spacing-4);
514
+ --comp-label-radius: var(--radius-full);
515
+ --comp-label-font: var(--text-caption-size);
516
+ --comp-checkbox-size: var(--spacing-20);
517
+ --comp-checkbox-radius: var(--radius-xs);
518
+ --comp-checkbox-border-width: 2px;
519
+ --comp-checkbox-icon: var(--spacing-12);
520
+ --comp-radio-size: var(--spacing-20);
521
+ --comp-radio-radius: var(--radius-full);
522
+ --comp-radio-border-width: 2px;
523
+ --comp-radio-dot: var(--spacing-8);
524
+ --comp-toggle-track-w: 44px;
525
+ --comp-toggle-track-h: var(--spacing-24);
526
+ --comp-toggle-thumb-size: var(--spacing-20);
527
+ --comp-toggle-padding: var(--spacing-2);
528
+ --comp-toggle-radius: var(--radius-full);
529
+ --comp-tooltip-padding-x: var(--spacing-8);
530
+ --comp-tooltip-padding-y: var(--spacing-4);
531
+ --comp-tooltip-radius: var(--radius-xs);
532
+ --comp-tooltip-arrow: 8px;
533
+ --comp-tooltip-font: var(--text-caption-size);
534
+ --comp-modal-padding: var(--spacing-24);
535
+ --comp-modal-padding-bottom: var(--spacing-16);
536
+ --comp-modal-gap: var(--spacing-16);
537
+ --comp-modal-radius: var(--radius-sm);
538
+ --comp-modal-border-width: 1px;
539
+ --comp-modal-min-width: 280px;
540
+ --comp-modal-max-width: 480px;
541
+ --comp-dropdown-padding: var(--spacing-4);
542
+ --comp-dropdown-item-padding-x: var(--spacing-12);
543
+ --comp-dropdown-item-padding-y: var(--spacing-8);
544
+ --comp-dropdown-gap: var(--spacing-8);
545
+ --comp-dropdown-radius: var(--radius-sm);
546
+ --comp-dropdown-item-radius: var(--radius-xs);
547
+ --comp-dropdown-min-width: 180px;
548
+ --comp-tabs-padding-x: var(--spacing-12);
549
+ --comp-tabs-padding-y: var(--spacing-8);
550
+ --comp-tabs-gap: var(--spacing-4);
551
+ --comp-tabs-indicator: 2px;
552
+ --comp-tabs-font: var(--text-label2-size);
553
+ --comp-table-cell-padding-x: var(--spacing-12);
554
+ --comp-table-cell-padding-y: var(--spacing-8);
555
+ --comp-table-radius: var(--radius-sm);
556
+ --comp-table-border-width: 1px;
557
+ --comp-table-header-font: var(--text-caption-size);
558
+ --comp-table-cell-font: var(--text-body-sm-size);
559
+ --comp-toast-padding-x: var(--spacing-16);
560
+ --comp-toast-padding-y: var(--spacing-16);
561
+ --comp-toast-gap: var(--spacing-8);
562
+ --comp-toast-radius: var(--radius-sm);
563
+ --comp-toast-font: var(--text-body-sm-size);
564
+ --comp-avatar-size: var(--spacing-32);
565
+ --comp-avatar-radius: var(--radius-full);
566
+ --comp-avatar-ring-width: 2px;
567
+ --comp-avatar-overlap: -8px;
568
+ --comp-avatar-font: var(--text-label2-size);
569
+ --comp-sheet-radius: var(--radius-lg);
570
+ --comp-sheet-padding-top: var(--spacing-16);
571
+ --comp-sheet-padding-x: var(--spacing-20);
572
+ --comp-sheet-padding-bottom: var(--spacing-24);
573
+ --comp-sheet-gap: var(--spacing-16);
574
+ --comp-sheet-handle-w: 40px;
575
+ --comp-sheet-handle-h: 4px;
576
+ --comp-select-height: var(--spacing-40);
577
+ --comp-select-padding-x: var(--spacing-12);
578
+ --comp-select-gap: var(--spacing-8);
579
+ --comp-select-radius: var(--radius-xs);
580
+ --comp-select-icon: var(--spacing-20);
581
+ --comp-select-font: var(--text-body-size);
582
+ --comp-select-border-width: 1px;
583
+ --comp-textarea-padding: var(--spacing-12);
584
+ --comp-textarea-radius: var(--radius-xs);
585
+ --comp-textarea-min-height: 80px;
586
+ --comp-textarea-font: var(--text-body-size);
587
+ --comp-textarea-border-width: 1px;
588
+ --comp-chip-height: var(--spacing-32);
589
+ --comp-chip-padding-x: var(--spacing-12);
590
+ --comp-chip-gap: var(--spacing-4);
591
+ --comp-chip-radius: var(--radius-xs);
592
+ --comp-chip-icon: var(--spacing-16);
593
+ --comp-chip-font: var(--text-label2-size);
594
+ --comp-chip-border-width: 1px;
595
+ --comp-alert-padding: var(--spacing-12);
596
+ --comp-alert-gap: var(--spacing-12);
597
+ --comp-alert-radius: var(--radius-sm);
598
+ --comp-alert-icon: var(--spacing-20);
599
+ --comp-alert-border-width: 1px;
600
+ --comp-pagination-item-size: var(--spacing-32);
601
+ --comp-pagination-gap: var(--spacing-4);
602
+ --comp-pagination-radius: var(--radius-sm);
603
+ --comp-pagination-font: var(--text-label2-size);
604
+ --comp-progress-height: 6px;
605
+ --comp-progress-radius: var(--radius-full);
606
+ --comp-skeleton-radius: var(--radius-sm);
607
+ --comp-segment-height: var(--spacing-32);
608
+ --comp-segment-padding: var(--spacing-2);
609
+ --comp-segment-radius: var(--radius-sm);
610
+ --comp-segment-thumb-radius: var(--radius-sm);
611
+ --comp-segment-font: var(--text-label2-size);
612
+ }
613
+
614
+ /* ---- icon (Lucide-base, currentColor) ---- */
615
+ :root,
616
+ [data-theme="light"] {
617
+ --icon-sm: 18px;
618
+ --icon-md: 20px;
619
+ --icon-lg: 24px;
620
+ --icon-grid: 24px;
621
+ --icon-stroke: 1.5px;
622
+ }
623
+
624
+ /* ---- P1 foundation: motion · z-index · border-width · touch ---- */
625
+ :root,
626
+ [data-theme="light"] {
627
+ /* motion */
628
+ --duration-fast: 120ms;
629
+ --duration-base: 200ms;
630
+ --duration-slow: 300ms;
631
+ --ease-standard: cubic-bezier(0.2, 0, 0, 1);
632
+ --ease-out: cubic-bezier(0, 0, 0, 1);
633
+ --ease-in: cubic-bezier(0.3, 0, 1, 1);
634
+ /* z-index (stack order) */
635
+ --z-dropdown: 1000;
636
+ --z-sticky: 1100;
637
+ --z-overlay: 1200;
638
+ --z-modal: 1300;
639
+ --z-popover: 1400;
640
+ --z-toast: 1500;
641
+ --z-tooltip: 1600;
642
+ /* border-width */
643
+ --border-width-1: 1px;
644
+ --border-width-2: 2px;
645
+ /* touch target (hit area) */
646
+ --size-touch-min: 44px;
647
+ --size-avatar-xs: 24px;
648
+ --size-avatar-sm: 32px;
649
+ --size-avatar-md: 40px;
650
+ --size-avatar-lg: 48px;
651
+ --size-avatar-xl: 64px;
652
+ }
653
+ /* ⚠ 모션 토큰 수정 시 아래 @media 블록도 함께 확인할 것 — duration이 1ms로 덮어씌워진다 */
654
+ /* 접근성: 모션 줄이기 켜면 트랜지션 사실상 즉시 */
655
+ @media (prefers-reduced-motion: reduce) {
656
+ :root,
657
+ [data-theme="light"] {
658
+ --duration-fast: 1ms;
659
+ --duration-base: 1ms;
660
+ --duration-slow: 1ms;
661
+ }
662
+ }