@bigtablet/design-system 2.5.0 → 3.0.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.
@@ -1,7 +1,67 @@
1
1
  @use "../colors" as colors;
2
+ @use "../breakpoints" as breakpoint;
2
3
 
3
- $focus_ring: 0 0 0 3px rgba(colors.$color_base_brand_primary, 0.15);
4
- $focus_ring_error: 0 0 0 3px rgba(colors.$color_base_status_error, 0.15);
5
- $focus_ring_success: 0 0 0 3px rgba(colors.$color_base_status_success, 0.15);
4
+ // Focus rings CSS Custom Properties로 light/dark 자동 전환.
5
+ // Dark 모드는 흰색 alpha 기반으로 navy bg 위에서도 가시성 확보.
6
6
 
7
- $tap_min_size: 44px;
7
+ :root {
8
+ --bt-focus-ring: 0 0 0 3px rgba(0, 0, 0, 0.15);
9
+ --bt-focus-ring-error: 0 0 0 3px rgba(239, 68, 68, 0.30);
10
+ --bt-focus-ring-success: 0 0 0 3px rgba(16, 185, 129, 0.30);
11
+ }
12
+
13
+ [data-theme="dark"] {
14
+ --bt-focus-ring: 0 0 0 3px rgba(255, 255, 255, 0.35);
15
+ --bt-focus-ring-error: 0 0 0 3px rgba(239, 68, 68, 0.45);
16
+ --bt-focus-ring-success: 0 0 0 3px rgba(16, 185, 129, 0.45);
17
+ }
18
+
19
+ @media (prefers-color-scheme: dark) {
20
+ :root:not([data-theme]) {
21
+ --bt-focus-ring: 0 0 0 3px rgba(255, 255, 255, 0.35);
22
+ --bt-focus-ring-error: 0 0 0 3px rgba(239, 68, 68, 0.45);
23
+ --bt-focus-ring-success: 0 0 0 3px rgba(16, 185, 129, 0.45);
24
+ }
25
+ }
26
+
27
+ // SCSS aliases — 기존 사용처는 그대로 작동
28
+ $focus_ring: var(--bt-focus-ring);
29
+ $focus_ring_error: var(--bt-focus-ring-error);
30
+ $focus_ring_success: var(--bt-focus-ring-success);
31
+
32
+ // ── Tap target sizes (a11y) ─────────────────────────────────────────────
33
+ // WCAG 2.1 SC 2.5.5 권장 최소: 44×44
34
+
35
+ $tap_min_size: 44px; // a11y 최소 권장
36
+ $tap_target_dense: 32px; // 데스크탑 인라인 폼, 컴팩트 UI
37
+ $tap_target_compact: 40px; // 데스크탑 기본
38
+ $tap_target_comfortable: 48px; // 모바일/터치 기본 (44 초과)
39
+ $tap_target_spacious: 56px; // 강조 CTA, 풀스크린 액션
40
+
41
+ // ── Responsive height mixin ─────────────────────────────────────────────
42
+ // 데스크탑 height 기준으로 compact breakpoint(<600px)에서 한 단계 키움.
43
+ // 명시적으로 $mobile 지정 시 그 값을 사용.
44
+ //
45
+ // 사용 예:
46
+ // @include token.responsive_height(token.$tap_target_compact);
47
+ // → 데스크탑 40, 모바일 48
48
+ // @include token.responsive_height(token.$tap_target_compact, token.$tap_target_spacious);
49
+ // → 명시
50
+
51
+ @mixin responsive_height($desktop, $mobile: null) {
52
+ min-height: $desktop;
53
+
54
+ $bumped: $mobile;
55
+ @if $bumped == null {
56
+ @if $desktop == $tap_target_dense { $bumped: $tap_target_compact; }
57
+ @else if $desktop == $tap_target_compact { $bumped: $tap_target_comfortable; }
58
+ @else if $desktop == $tap_target_comfortable { $bumped: $tap_target_spacious; }
59
+ @else { $bumped: $desktop; }
60
+ }
61
+
62
+ @if $bumped != $desktop {
63
+ @include breakpoint.compact {
64
+ min-height: $bumped;
65
+ }
66
+ }
67
+ }
@@ -8,4 +8,5 @@ $border_width_2: 2px;
8
8
 
9
9
  $border_width_none: $border_width_0;
10
10
  $border_width_standard: $border_width_1;
11
+ $border_width_thick: $border_width_2;
11
12
  $border_width_indicator: $border_width_2;
@@ -1,9 +1,22 @@
1
- // ── Base colors ───────────────────────────────────────────────────────────────
1
+ // ════════════════════════════════════════════════════════════════════════
2
+ // Bigtablet 컬러 토큰 — Light/Dark 양쪽 지원
3
+ //
4
+ // 구조:
5
+ // 1. Base colors (raw values) — SCSS 변수
6
+ // 2. CSS custom properties (:root + [data-theme="dark"]) — 런타임 테마 전환
7
+ // 3. Semantic SCSS 변수 — CSS var를 참조 → 기존 사용처(@use token; $color_*) 호환 유지
8
+ //
9
+ // `brand_primary`, `accent.*`, `status.*` 는 light/dark 동일 (브랜드 일관성).
10
+ // 나머지 표면/텍스트/border 는 dark에서 navy 계열로 자동 전환.
11
+ // ════════════════════════════════════════════════════════════════════════
12
+
13
+ // ── Base colors (raw, never theme-aware) ────────────────────────────────
2
14
 
3
15
  $color_base_brand_primary: #121212;
4
16
  $color_base_blue_600: #1A73E8;
5
17
  $color_base_neutral_0: #FFFFFF;
6
18
  $color_base_neutral_50: #F4F4F4;
19
+ $color_base_neutral_100: #F2F2F2;
7
20
  $color_base_neutral_200: #E5E5E5;
8
21
  $color_base_neutral_300: #999999;
9
22
  $color_base_neutral_400: #B3B3B3;
@@ -16,6 +29,20 @@ $color_base_status_error: #EF4444;
16
29
  $color_base_status_success: #10B981;
17
30
  $color_base_status_warning: #F59E0B;
18
31
  $color_base_status_info: #3B82F6;
32
+
33
+ // Bigtablet navy (초기 홈페이지에서 추출) — slate-gray-blue + sky blue
34
+ $color_base_navy_50: #F2F5F8;
35
+ $color_base_navy_100: #DDE3E9;
36
+ $color_base_navy_200: #B4C2CD;
37
+ $color_base_navy_300: #7AA5D2;
38
+ $color_base_navy_400: #5A8DCB;
39
+ $color_base_navy_500: #4C7CB6;
40
+ $color_base_navy_600: #47555E;
41
+ $color_base_navy_700: #3D4852;
42
+ $color_base_navy_800: #303841;
43
+ $color_base_navy_900: #1F2630;
44
+
45
+ // Alpha
19
46
  $color_base_alpha_black_5: rgba(0, 0, 0, 0.05);
20
47
  $color_base_alpha_black_8: rgba(0, 0, 0, 0.08);
21
48
  $color_base_alpha_black_12: rgba(26, 26, 26, 0.12);
@@ -24,54 +51,227 @@ $color_base_alpha_black_50: rgba(0, 0, 0, 0.50);
24
51
  $color_base_alpha_white_5: rgba(255, 255, 255, 0.05);
25
52
  $color_base_alpha_white_8: rgba(255, 255, 255, 0.08);
26
53
  $color_base_alpha_white_12: rgba(255, 255, 255, 0.12);
54
+ $color_base_alpha_white_38: rgba(255, 255, 255, 0.38);
55
+
56
+ // ── CSS custom properties (런타임 테마 전환) ────────────────────────────
57
+ // `:root` = light mode 기본. `[data-theme="dark"]` = dark overrides.
58
+ // 컴포넌트는 SCSS `$color_*` 변수로 접근 — 아래 변수들이 var()로 컴파일됨.
59
+
60
+ :root {
61
+ // Brand (light/dark 동일)
62
+ --bt-color-brand-primary: #{$color_base_brand_primary};
63
+ --bt-color-brand-on-primary: #{$color_base_neutral_0};
64
+ --bt-color-brand-primary-container: #{$color_base_alpha_black_5};
65
+
66
+ // Text
67
+ --bt-color-text-heading: #{$color_base_neutral_900};
68
+ --bt-color-text-body: #{$color_base_neutral_700};
69
+ --bt-color-text-caption: #{$color_base_neutral_500};
70
+ --bt-color-text-brand: #{$color_base_brand_primary};
71
+ --bt-color-text-inverse: #{$color_base_neutral_0};
72
+ --bt-color-text-disabled: #{$color_base_alpha_black_38};
73
+
74
+ // Background
75
+ --bt-color-bg-solid: #{$color_base_neutral_0};
76
+ --bt-color-bg-solid-dim: #{$color_base_neutral_50};
77
+ --bt-color-bg-additive: #{$color_base_alpha_black_5};
78
+ --bt-color-bg-disabled: #{$color_base_alpha_black_12};
79
+ --bt-color-bg-overlay: #{$color_base_alpha_black_50};
80
+ --bt-color-bg-inverse-surface: #{$color_base_neutral_800};
81
+
82
+ // State
83
+ --bt-color-state-hover-on-light: #{$color_base_alpha_black_5};
84
+ --bt-color-state-pressed-on-light: #{$color_base_alpha_black_12};
85
+ --bt-color-state-focus-on-light: #{$color_base_alpha_black_8};
86
+ --bt-color-state-hover-on-dark: #{$color_base_alpha_white_5};
87
+ --bt-color-state-pressed-on-dark: #{$color_base_alpha_white_12};
88
+ --bt-color-state-focus-on-dark: #{$color_base_alpha_white_8};
89
+
90
+ // Border
91
+ --bt-color-border-default: #{$color_base_neutral_200};
92
+ --bt-color-border-hover: #{$color_base_neutral_400};
93
+ --bt-color-border-subtle: #{$color_base_alpha_black_8};
94
+ --bt-color-border-focus: #{$color_base_neutral_900};
95
+ --bt-color-border-disabled: #{$color_base_neutral_100};
96
+
97
+ // Status (light/dark 동일)
98
+ --bt-color-status-error: #{$color_base_status_error};
99
+ --bt-color-status-success: #{$color_base_status_success};
100
+ --bt-color-status-warning: #{$color_base_status_warning};
101
+ --bt-color-status-info: #{$color_base_status_info};
102
+
103
+ // Accent (검정 brand 기반 — light에서 검정, dark에서 흰색 반전)
104
+ // 컴포넌트 active/selected/indicator 강조에 사용.
105
+ // navy 색상은 `color_base_navy_*`로 별도 보존 (legacy/optional usage).
106
+ --bt-color-accent-subtle: #{$color_base_alpha_black_5};
107
+ --bt-color-accent-muted: #{$color_base_alpha_black_12};
108
+ --bt-color-accent-light: #{$color_base_neutral_400};
109
+ --bt-color-accent-default: #{$color_base_brand_primary}; // 검정 (brand와 동일)
110
+ --bt-color-accent-strong: #{$color_base_neutral_900};
111
+ --bt-color-accent-on-surface: #{$color_base_neutral_0}; // 검정 위 흰색
112
+
113
+ // Skeleton (light gray gradient — dark 에서 navy gray 로 전환)
114
+ --bt-color-skeleton-base: #F3F3F3;
115
+ --bt-color-skeleton-wave: #f0f0f0;
116
+ --bt-color-skeleton-highlight: #fafafa;
117
+ }
118
+
119
+ [data-theme="dark"] {
120
+ // 브라우저 기본 UI (스크롤바, form control 등) 다크 적응
121
+ color-scheme: dark;
122
+ // Font rendering — dark bg 위 흰 글씨의 halation/노이즈 보정
123
+ -webkit-font-smoothing: antialiased;
124
+ -moz-osx-font-smoothing: grayscale;
125
+
126
+ // Brand (dark 모드에서도 black 유지 — bg가 navy라 black 버튼 구분됨.
127
+ // 단 텍스트로 쓰일 땐 inverse 사용 권장)
128
+
129
+ // Text (light → inverted)
130
+ // heading: 100% 흰색 → 95%로 살짝 부드럽게 (눈 피로 완화, halation 보정)
131
+ --bt-color-text-heading: rgba(255, 255, 255, 0.95);
132
+ --bt-color-text-body: #{$color_base_navy_200};
133
+ --bt-color-text-caption: #{$color_base_neutral_400};
134
+ --bt-color-text-inverse: #{$color_base_neutral_900};
135
+ --bt-color-text-disabled: #{$color_base_alpha_white_38};
136
+
137
+ // Background (light → navy)
138
+ --bt-color-bg-solid: #{$color_base_navy_900};
139
+ --bt-color-bg-solid-dim: #{$color_base_navy_800};
140
+ --bt-color-bg-additive: #{$color_base_alpha_white_5};
141
+ --bt-color-bg-disabled: #{$color_base_alpha_white_12};
142
+ --bt-color-bg-overlay: rgba(0, 0, 0, 0.7);
143
+ --bt-color-bg-inverse-surface: #{$color_base_neutral_50};
144
+
145
+ // State (검정 alpha → 흰색 alpha — dark bg 위에서 작동)
146
+ --bt-color-state-hover-on-light: #{$color_base_alpha_white_8};
147
+ --bt-color-state-pressed-on-light: #{$color_base_alpha_white_12};
148
+ --bt-color-state-focus-on-light: #{$color_base_alpha_white_12};
149
+ --bt-color-state-hover-on-dark: #{$color_base_alpha_black_8};
150
+ --bt-color-state-pressed-on-dark: #{$color_base_alpha_black_12};
151
+ --bt-color-state-focus-on-dark: #{$color_base_alpha_black_12};
152
+
153
+ // Border (light gray → navy mid)
154
+ --bt-color-border-default: #{$color_base_navy_700};
155
+ --bt-color-border-hover: #{$color_base_navy_400};
156
+ --bt-color-border-subtle: #{$color_base_alpha_white_12};
157
+ --bt-color-border-focus: #{$color_base_neutral_0};
158
+ --bt-color-border-disabled: #{$color_base_navy_800};
159
+
160
+ // Brand container — dark 모드에선 white alpha로
161
+ --bt-color-brand-primary-container: #{$color_base_alpha_white_8};
162
+
163
+ // Accent (dark — 흰색 반전. active/selected가 dark navy bg 위에서 잘 보임)
164
+ --bt-color-accent-subtle: #{$color_base_alpha_white_8};
165
+ --bt-color-accent-muted: #{$color_base_alpha_white_12};
166
+ --bt-color-accent-light: #{$color_base_neutral_300};
167
+ --bt-color-accent-default: #{$color_base_neutral_0}; // 흰색
168
+ --bt-color-accent-strong: #{$color_base_neutral_0};
169
+ --bt-color-accent-on-surface: #{$color_base_neutral_900}; // 흰 위 검정 텍스트
170
+
171
+ // Skeleton — navy_700 (bg-solid-dim navy_800 보다 살짝 밝음 → 시각 대비)
172
+ --bt-color-skeleton-base: #{$color_base_navy_700};
173
+ --bt-color-skeleton-wave: #{$color_base_navy_700};
174
+ --bt-color-skeleton-highlight: #{$color_base_navy_600};
175
+ }
176
+
177
+ // `prefers-color-scheme: dark` 자동 응답 (ThemeProvider 없이도 작동)
178
+ @media (prefers-color-scheme: dark) {
179
+ :root:not([data-theme]) {
180
+ color-scheme: dark;
181
+ -webkit-font-smoothing: antialiased;
182
+ -moz-osx-font-smoothing: grayscale;
183
+
184
+ --bt-color-text-heading: rgba(255, 255, 255, 0.95);
185
+ --bt-color-text-body: #{$color_base_navy_200};
186
+ --bt-color-text-caption: #{$color_base_neutral_400};
187
+ --bt-color-text-inverse: #{$color_base_neutral_900};
188
+ --bt-color-text-disabled: #{$color_base_alpha_white_38};
27
189
 
28
- // ── Semantic: Brand ───────────────────────────────────────────────────────────
190
+ --bt-color-bg-solid: #{$color_base_navy_900};
191
+ --bt-color-bg-solid-dim: #{$color_base_navy_800};
192
+ --bt-color-bg-additive: #{$color_base_alpha_white_5};
193
+ --bt-color-bg-disabled: #{$color_base_alpha_white_12};
194
+ --bt-color-bg-overlay: rgba(0, 0, 0, 0.7);
195
+ --bt-color-bg-inverse-surface: #{$color_base_neutral_50};
29
196
 
30
- $color_brand_primary: $color_base_brand_primary;
31
- $color_brand_on_primary: $color_base_neutral_0;
197
+ --bt-color-state-hover-on-light: #{$color_base_alpha_white_8};
198
+ --bt-color-state-pressed-on-light: #{$color_base_alpha_white_12};
199
+ --bt-color-state-focus-on-light: #{$color_base_alpha_white_12};
200
+ --bt-color-state-hover-on-dark: #{$color_base_alpha_black_8};
201
+ --bt-color-state-pressed-on-dark: #{$color_base_alpha_black_12};
202
+ --bt-color-state-focus-on-dark: #{$color_base_alpha_black_12};
32
203
 
33
- // ── Semantic: Text ────────────────────────────────────────────────────────────
204
+ --bt-color-border-default: #{$color_base_navy_700};
205
+ --bt-color-border-hover: #{$color_base_navy_400};
206
+ --bt-color-border-subtle: #{$color_base_alpha_white_12};
207
+ --bt-color-border-focus: #{$color_base_neutral_0};
208
+ --bt-color-border-disabled: #{$color_base_navy_800};
34
209
 
35
- $color_text_heading: $color_base_neutral_900;
36
- $color_text_body: $color_base_neutral_700;
37
- $color_text_caption: $color_base_neutral_500;
38
- $color_text_brand: $color_base_brand_primary;
39
- $color_text_inverse: $color_base_neutral_0;
40
- $color_text_disabled: $color_base_alpha_black_38;
210
+ --bt-color-brand-primary-container: #{$color_base_alpha_white_8};
41
211
 
42
- // ── Semantic: Background ──────────────────────────────────────────────────────
212
+ // Accent dark 흰색 반전
213
+ --bt-color-accent-subtle: #{$color_base_alpha_white_8};
214
+ --bt-color-accent-muted: #{$color_base_alpha_white_12};
215
+ --bt-color-accent-light: #{$color_base_neutral_300};
216
+ --bt-color-accent-default: #{$color_base_neutral_0};
217
+ --bt-color-accent-strong: #{$color_base_neutral_0};
218
+ --bt-color-accent-on-surface: #{$color_base_neutral_900};
43
219
 
44
- $color_bg_solid: $color_base_neutral_0;
45
- $color_bg_solid_dim: $color_base_neutral_50;
46
- $color_bg_additive: $color_base_alpha_black_5;
47
- $color_bg_disabled: $color_base_alpha_black_12;
48
- $color_bg_overlay: $color_base_alpha_black_50;
49
- $color_bg_inverse_surface: $color_base_neutral_800;
220
+ --bt-color-skeleton-base: #{$color_base_navy_700};
221
+ --bt-color-skeleton-wave: #{$color_base_navy_700};
222
+ --bt-color-skeleton-highlight: #{$color_base_navy_600};
223
+ }
224
+ }
50
225
 
51
- // ── Semantic: State ───────────────────────────────────────────────────────────
226
+ // ── Semantic SCSS variables (CSS var 참조) ─────────────────────────────
227
+ // 기존 사용처 호환 — `@use "..." as token; background: token.$color_bg_solid;`
52
228
 
53
- $color_state_hover_on_light: $color_base_alpha_black_5;
54
- $color_state_pressed_on_light: $color_base_alpha_black_12;
55
- $color_state_hover_on_dark: $color_base_alpha_white_5;
56
- $color_state_pressed_on_dark: $color_base_alpha_white_12;
229
+ // Brand
230
+ $color_brand_primary: var(--bt-color-brand-primary);
231
+ $color_brand_on_primary: var(--bt-color-brand-on-primary);
232
+ $color_brand_primary_container: var(--bt-color-brand-primary-container);
57
233
 
58
- // ── Extended: tokens.json에 없지만 컴포넌트에서 사용 중 ─────────────────────
234
+ // Text
235
+ $color_text_heading: var(--bt-color-text-heading);
236
+ $color_text_body: var(--bt-color-text-body);
237
+ $color_text_caption: var(--bt-color-text-caption);
238
+ $color_text_brand: var(--bt-color-text-brand);
239
+ $color_text_inverse: var(--bt-color-text-inverse);
240
+ $color_text_disabled: var(--bt-color-text-disabled);
59
241
 
60
- $color_state_focus_on_light: $color_base_alpha_black_8;
61
- $color_state_focus_on_dark: $color_base_alpha_white_8;
62
- $color_brand_primary_container: $color_base_alpha_black_5;
242
+ // Background
243
+ $color_bg_solid: var(--bt-color-bg-solid);
244
+ $color_bg_solid_dim: var(--bt-color-bg-solid-dim);
245
+ $color_bg_additive: var(--bt-color-bg-additive);
246
+ $color_bg_disabled: var(--bt-color-bg-disabled);
247
+ $color_bg_overlay: var(--bt-color-bg-overlay);
248
+ $color_bg_inverse_surface: var(--bt-color-bg-inverse-surface);
63
249
 
64
- // ── Semantic: Border ──────────────────────────────────────────────────────────
250
+ // State
251
+ $color_state_hover_on_light: var(--bt-color-state-hover-on-light);
252
+ $color_state_pressed_on_light: var(--bt-color-state-pressed-on-light);
253
+ $color_state_focus_on_light: var(--bt-color-state-focus-on-light);
254
+ $color_state_hover_on_dark: var(--bt-color-state-hover-on-dark);
255
+ $color_state_pressed_on_dark: var(--bt-color-state-pressed-on-dark);
256
+ $color_state_focus_on_dark: var(--bt-color-state-focus-on-dark);
65
257
 
66
- $color_border_default: $color_base_neutral_200;
67
- $color_border_hover: $color_base_neutral_400;
68
- $color_border_subtle: $color_base_alpha_black_8;
69
- $color_border_focus: $color_base_neutral_900;
70
- $color_border_disabled: #F2F2F2;
258
+ // Border
259
+ $color_border_default: var(--bt-color-border-default);
260
+ $color_border_hover: var(--bt-color-border-hover);
261
+ $color_border_subtle: var(--bt-color-border-subtle);
262
+ $color_border_focus: var(--bt-color-border-focus);
263
+ $color_border_disabled: var(--bt-color-border-disabled);
71
264
 
72
- // ── Semantic: Status ──────────────────────────────────────────────────────────
265
+ // Status
266
+ $color_status_error: var(--bt-color-status-error);
267
+ $color_status_success: var(--bt-color-status-success);
268
+ $color_status_warning: var(--bt-color-status-warning);
269
+ $color_status_info: var(--bt-color-status-info);
73
270
 
74
- $color_status_error: $color_base_status_error;
75
- $color_status_success: $color_base_status_success;
76
- $color_status_warning: $color_base_status_warning;
77
- $color_status_info: $color_base_status_info;
271
+ // Accent
272
+ $color_accent_subtle: var(--bt-color-accent-subtle);
273
+ $color_accent_muted: var(--bt-color-accent-muted);
274
+ $color_accent_light: var(--bt-color-accent-light);
275
+ $color_accent_default: var(--bt-color-accent-default);
276
+ $color_accent_strong: var(--bt-color-accent-strong);
277
+ $color_accent_on_surface: var(--bt-color-accent-on-surface);
@@ -1,5 +1,36 @@
1
- $elevation_level1: 0 1px 1px -1px rgba(0, 0, 0, 0.20), 0 3px 3px 0px rgba(0, 0, 0, 0.12);
2
- $elevation_level2: 0 2px 2px -2px rgba(0, 0, 0, 0.20), 0 6px 6px 0px rgba(0, 0, 0, 0.12);
3
- $elevation_level3: 0 3px 3px -3px rgba(0, 0, 0, 0.20), 0 9px 9px 0px rgba(0, 0, 0, 0.12);
4
- $elevation_level4: 0 5px 5px -5px rgba(0, 0, 0, 0.20), 0 15px 15px 0px rgba(0, 0, 0, 0.12);
5
- $elevation_level5: 0 8px 10px -5px rgba(0, 0, 0, 0.20), 0 20px 20px 0px rgba(0, 0, 0, 0.12);
1
+ // Elevation shadows CSS Custom Properties로 light/dark 자동 전환.
2
+ // Dark 모드는 navy bg 위에서 그림자가 보이도록 강한 검정 + 살짝 spread 증가.
3
+
4
+ :root {
5
+ --bt-elevation-level1: 0 1px 1px -1px rgba(0, 0, 0, 0.20), 0 3px 3px 0px rgba(0, 0, 0, 0.12);
6
+ --bt-elevation-level2: 0 2px 2px -2px rgba(0, 0, 0, 0.20), 0 6px 6px 0px rgba(0, 0, 0, 0.12);
7
+ --bt-elevation-level3: 0 3px 3px -3px rgba(0, 0, 0, 0.20), 0 9px 9px 0px rgba(0, 0, 0, 0.12);
8
+ --bt-elevation-level4: 0 5px 5px -5px rgba(0, 0, 0, 0.20), 0 15px 15px 0px rgba(0, 0, 0, 0.12);
9
+ --bt-elevation-level5: 0 8px 10px -5px rgba(0, 0, 0, 0.20), 0 20px 20px 0px rgba(0, 0, 0, 0.12);
10
+ }
11
+
12
+ [data-theme="dark"] {
13
+ // navy bg 위에서 그림자 가시성 — 검정 더 진하게 + 약간 더 큰 spread
14
+ --bt-elevation-level1: 0 1px 2px 0 rgba(0, 0, 0, 0.45), 0 3px 6px 0 rgba(0, 0, 0, 0.30);
15
+ --bt-elevation-level2: 0 2px 4px 0 rgba(0, 0, 0, 0.45), 0 6px 12px 0 rgba(0, 0, 0, 0.30);
16
+ --bt-elevation-level3: 0 3px 6px 0 rgba(0, 0, 0, 0.50), 0 9px 18px 0 rgba(0, 0, 0, 0.35);
17
+ --bt-elevation-level4: 0 5px 10px 0 rgba(0, 0, 0, 0.55), 0 15px 30px 0 rgba(0, 0, 0, 0.40);
18
+ --bt-elevation-level5: 0 8px 16px 0 rgba(0, 0, 0, 0.60), 0 20px 40px 0 rgba(0, 0, 0, 0.45);
19
+ }
20
+
21
+ @media (prefers-color-scheme: dark) {
22
+ :root:not([data-theme]) {
23
+ --bt-elevation-level1: 0 1px 2px 0 rgba(0, 0, 0, 0.45), 0 3px 6px 0 rgba(0, 0, 0, 0.30);
24
+ --bt-elevation-level2: 0 2px 4px 0 rgba(0, 0, 0, 0.45), 0 6px 12px 0 rgba(0, 0, 0, 0.30);
25
+ --bt-elevation-level3: 0 3px 6px 0 rgba(0, 0, 0, 0.50), 0 9px 18px 0 rgba(0, 0, 0, 0.35);
26
+ --bt-elevation-level4: 0 5px 10px 0 rgba(0, 0, 0, 0.55), 0 15px 30px 0 rgba(0, 0, 0, 0.40);
27
+ --bt-elevation-level5: 0 8px 16px 0 rgba(0, 0, 0, 0.60), 0 20px 40px 0 rgba(0, 0, 0, 0.45);
28
+ }
29
+ }
30
+
31
+ // SCSS aliases — 기존 사용처는 그대로 작동
32
+ $elevation_level1: var(--bt-elevation-level1);
33
+ $elevation_level2: var(--bt-elevation-level2);
34
+ $elevation_level3: var(--bt-elevation-level3);
35
+ $elevation_level4: var(--bt-elevation-level4);
36
+ $elevation_level5: var(--bt-elevation-level5);
@@ -1,7 +1,12 @@
1
- /* Base Transitions */
2
- $transition_fast: 0.1s ease-in-out; // hover, icon
3
- $transition_base: 0.2s ease-in-out; // 메뉴 열림
4
- $transition_slow: 0.3s ease-in-out; // 레이아웃 변화
1
+ /* Duration only — easing 따로 조합할 때 사용 */
2
+ $duration_fast: 0.1s;
3
+ $duration_base: 0.2s;
4
+ $duration_slow: 0.3s;
5
+
6
+ /* Base Transitions (composite shorthand — easing 이미 포함) */
7
+ $transition_fast: $duration_fast ease-in-out; // hover, icon
8
+ $transition_base: $duration_base ease-in-out; // 메뉴 열림
9
+ $transition_slow: $duration_slow ease-in-out; // 레이아웃 변화
5
10
 
6
11
  /* Easing Curves */
7
12
  $ease_out_expo: cubic-bezier(0.16, 1, 0.3, 1);
@@ -9,6 +14,10 @@ $ease_out_quart: cubic-bezier(0.25, 1, 0.5, 1);
9
14
  $ease_in_out_cubic: cubic-bezier(0.65, 0, 0.35, 1);
10
15
  $ease_spring: cubic-bezier(0.34, 1.56, 0.64, 1);
11
16
 
17
+ /* Enter / Exit easing aliases (use these for popups, modals, drawers, toasts) */
18
+ $easing_enter: $ease_out_expo; // 감속 진입
19
+ $easing_exit: cubic-bezier(0.4, 0, 1, 1); // 가속 퇴출
20
+
12
21
  /* Material / Emphasized */
13
22
  $transition_emphasized: 0.25s cubic-bezier(0.4, 0, 0.2, 1);
14
23
  $transition_bounce: 0.3s $ease_out_expo;
@@ -19,6 +28,12 @@ $transition_slide: 0.25s $ease_out_expo;
19
28
  $transition_scale: 0.2s cubic-bezier(0.2, 0.8, 0.2, 1);
20
29
  $transition_state: 0.18s ease-in-out;
21
30
 
31
+ /* Enter / Exit pairs (퇴출은 진입보다 짧게가 관례) */
32
+ $transition_enter_fast: 0.15s $easing_enter;
33
+ $transition_enter_base: 0.2s $easing_enter;
34
+ $transition_exit_fast: 0.12s $easing_exit;
35
+ $transition_exit_base: 0.15s $easing_exit;
36
+
22
37
  /* Modern/Tech Transitions */
23
38
  $transition_smooth: 0.4s $ease_out_expo;
24
39
  $transition_spring: 0.5s $ease_spring;
@@ -1,9 +1,11 @@
1
1
  // Standalone skeleton tokens — no external @use so consumers can import
2
2
  // this file directly without needing the design system's src/ in their loadPaths.
3
3
 
4
- $color_skeleton_base: #F3F3F3;
5
- $color_skeleton_wave: #f0f0f0;
6
- $color_skeleton_highlight: #fafafa;
4
+ // CSS custom property 기반 — `[data-theme="dark"]` 에서 자동 전환.
5
+ // fallback 값은 standalone import (colors 미포함) 시 light 동작 보장.
6
+ $color_skeleton_base: var(--bt-color-skeleton-base, #F3F3F3);
7
+ $color_skeleton_wave: var(--bt-color-skeleton-wave, #f0f0f0);
8
+ $color_skeleton_highlight: var(--bt-color-skeleton-highlight, #fafafa);
7
9
 
8
10
  $skeleton_gradient: linear-gradient(
9
11
  90deg,
@@ -1,3 +1,5 @@
1
+ @use "../breakpoints" as breakpoint;
2
+
1
3
  $font_family_primary: "Pretendard", sans-serif;
2
4
 
3
5
  // ── Base: Font size ───────────────────────────────────────────────────────────
@@ -42,6 +44,7 @@ $line_height_50: 50px;
42
44
  $line_height_60: 60px;
43
45
 
44
46
  $letter_spacing_normal: 0px;
47
+ $letter_spacing_tight: 0.32px;
45
48
 
46
49
  // ── Semantic mixins ───────────────────────────────────────────────────────────
47
50
 
@@ -79,3 +82,71 @@ $letter_spacing_normal: 0px;
79
82
  @mixin label_medium_medium { font-size: $font_size_13; font-weight: $font_weight_medium; line-height: $line_height_18; letter-spacing: $letter_spacing_normal; }
80
83
  @mixin label_small { font-size: $font_size_12; font-weight: $font_weight_regular; line-height: $line_height_16; letter-spacing: $letter_spacing_normal; }
81
84
  @mixin label_small_medium { font-size: $font_size_12; font-weight: $font_weight_medium; line-height: $line_height_16; letter-spacing: $letter_spacing_normal; }
85
+
86
+ // ── Bold weight variants (v3.1) ───────────────────────────────────────────
87
+ // 강조용 — 매번 font-weight 명시 안 해도 되도록.
88
+
89
+ @mixin display_large_bold { font-size: $font_size_48; font-weight: $font_weight_bold; line-height: $line_height_60; letter-spacing: -0.02em; }
90
+ @mixin display_medium_bold { font-size: $font_size_40; font-weight: $font_weight_bold; line-height: $line_height_50; letter-spacing: -0.02em; }
91
+ @mixin display_small_bold { font-size: $font_size_32; font-weight: $font_weight_bold; line-height: $line_height_40; letter-spacing: -0.015em; }
92
+
93
+ @mixin heading_large_bold { font-size: $font_size_28; font-weight: $font_weight_bold; line-height: $line_height_36; letter-spacing: -0.01em; }
94
+ @mixin heading_medium_bold { font-size: $font_size_24; font-weight: $font_weight_bold; line-height: $line_height_32; letter-spacing: -0.01em; }
95
+ @mixin heading_small_bold { font-size: $font_size_20; font-weight: $font_weight_bold; line-height: $line_height_28; letter-spacing: $letter_spacing_normal; }
96
+
97
+ @mixin title_large_bold { font-size: $font_size_18; font-weight: $font_weight_bold; line-height: $line_height_24; letter-spacing: $letter_spacing_normal; }
98
+ @mixin title_medium_bold { font-size: $font_size_16; font-weight: $font_weight_bold; line-height: $line_height_24; letter-spacing: $letter_spacing_normal; }
99
+ @mixin title_small_bold { font-size: $font_size_14; font-weight: $font_weight_bold; line-height: $line_height_20; letter-spacing: $letter_spacing_normal; }
100
+
101
+ @mixin body_large_bold { font-size: $font_size_16; font-weight: $font_weight_bold; line-height: $line_height_24; letter-spacing: $letter_spacing_normal; }
102
+ @mixin body_medium_bold { font-size: $font_size_15; font-weight: $font_weight_bold; line-height: $line_height_22_5; letter-spacing: $letter_spacing_normal; }
103
+ @mixin body_small_bold { font-size: $font_size_14; font-weight: $font_weight_bold; line-height: $line_height_20; letter-spacing: $letter_spacing_normal; }
104
+
105
+ @mixin label_large_bold { font-size: $font_size_14; font-weight: $font_weight_bold; line-height: $line_height_20; letter-spacing: $letter_spacing_tight; }
106
+ @mixin label_medium_bold { font-size: $font_size_13; font-weight: $font_weight_bold; line-height: $line_height_18; letter-spacing: $letter_spacing_tight; }
107
+ @mixin label_small_bold { font-size: $font_size_12; font-weight: $font_weight_bold; line-height: $line_height_16; letter-spacing: $letter_spacing_tight; }
108
+
109
+ // ── Semantic aliases (v3.1) ───────────────────────────────────────────────
110
+ // 의미상 명확한 이름. heading_*/body_* 외워두기 어려운 경우 대안.
111
+
112
+ @mixin caption { font-size: $font_size_12; font-weight: $font_weight_regular; line-height: $line_height_16; letter-spacing: $letter_spacing_tight; }
113
+ @mixin caption_bold { font-size: $font_size_12; font-weight: $font_weight_bold; line-height: $line_height_16; letter-spacing: $letter_spacing_tight; }
114
+ @mixin overline { font-size: $font_size_12; font-weight: $font_weight_semi_bold; line-height: $line_height_16; letter-spacing: 0.08em; text-transform: uppercase; }
115
+ @mixin subtitle { font-size: $font_size_15; font-weight: $font_weight_medium; line-height: $line_height_22_5; letter-spacing: $letter_spacing_normal; }
116
+ @mixin code { font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace; font-size: $font_size_13; line-height: $line_height_18; }
117
+
118
+ // ── Responsive display (v3.1) ─────────────────────────────────────────────
119
+ // Hero/marketing title — 데스크탑 큰 사이즈, 모바일에서 자동 한 단계 축소.
120
+
121
+ @mixin display_large_responsive {
122
+ @include display_large_bold;
123
+ @include breakpoint.compact { @include display_small_bold; }
124
+ }
125
+
126
+ @mixin display_medium_responsive {
127
+ @include display_medium_bold;
128
+ @include breakpoint.compact { @include heading_large_bold; }
129
+ }
130
+
131
+ @mixin heading_large_responsive {
132
+ @include heading_large_bold;
133
+ @include breakpoint.compact { @include heading_medium_bold; }
134
+ }
135
+
136
+ // ── Text wrap helpers (v3.1) ──────────────────────────────────────────────
137
+ // CSS text-wrap 신기능 활용 — heading은 균형, body는 pretty.
138
+
139
+ @mixin text_balance { text-wrap: balance; }
140
+ @mixin text_pretty { text-wrap: pretty; }
141
+ @mixin text_nowrap { white-space: nowrap; }
142
+ @mixin text_truncate {
143
+ overflow: hidden;
144
+ text-overflow: ellipsis;
145
+ white-space: nowrap;
146
+ }
147
+
148
+ // ── Numeric (v3.1) ────────────────────────────────────────────────────────
149
+ // 매출/지표 표시할 때 숫자 자릿수 정렬.
150
+
151
+ @mixin tabular_nums { font-variant-numeric: tabular-nums; }
152
+ @mixin slashed_zero { font-variant-numeric: slashed-zero; }