@wipco/sdui 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,615 @@
1
+ /* ============================================================
2
+ @wipco/sdui — 독립 실행 스타일시트
3
+ WIPCO 브랜드 토큰(wp-*) + 내장 컴포넌트 스타일 전체.
4
+ 호스트 앱은 이 파일 하나만 import하면 된다:
5
+ import '@wipco/sdui/styles.css'
6
+ ============================================================ */
7
+
8
+ /* ---------- 토큰: 팔레트 ---------- */
9
+ :root {
10
+ --wp-white: #ffffff;
11
+
12
+ /* WIPCO Blue 램프 — 600이 브랜드 값 */
13
+ --wp-navy-50: #eef1f8;
14
+ --wp-navy-100: #dde2ef;
15
+ --wp-navy-200: #b9c2db;
16
+ --wp-navy-300: #8e9bc2;
17
+ --wp-navy-400: #5c6d9f;
18
+ --wp-navy-500: #2c4080;
19
+ --wp-navy-600: #1d2c60;
20
+ --wp-navy-700: #172449;
21
+ --wp-navy-800: #121b36;
22
+
23
+ /* WIPCO Red 램프 — 600이 브랜드 값 */
24
+ --wp-red-50: #fdeded;
25
+ --wp-red-100: #fadcdc;
26
+ --wp-red-200: #f2b0b1;
27
+ --wp-red-500: #dc2226;
28
+ --wp-red-600: #ca1a1d;
29
+ --wp-red-700: #a41417;
30
+
31
+ /* Signal blue */
32
+ --wp-blue-50: #e8f2fc;
33
+ --wp-blue-200: #a5cdf1;
34
+ --wp-blue-500: #0a73c9;
35
+ --wp-blue-600: #0a63ad;
36
+ --wp-blue-700: #08518a;
37
+
38
+ /* Survey gold */
39
+ --wp-gold-50: #fbf6e8;
40
+ --wp-gold-200: #e9d79b;
41
+ --wp-gold-600: #a98d34;
42
+ --wp-gold-700: #836c22;
43
+
44
+ /* Verified green */
45
+ --wp-green-50: #e7f5ef;
46
+ --wp-green-200: #93d3ba;
47
+ --wp-green-600: #0e6b4b;
48
+ --wp-green-700: #0a563c;
49
+
50
+ /* UI 뉴트럴 — WIPCO Blue 쪽으로 2% 틴트된 무채색 램프 */
51
+ --wp-slate-25: #fafbfd;
52
+ --wp-slate-50: #f5f7fa;
53
+ --wp-slate-100: #eef1f6;
54
+ --wp-slate-200: #e1e6ef;
55
+ --wp-slate-300: #cdd4e1;
56
+ --wp-slate-400: #a4adc0;
57
+ --wp-slate-500: #7b8598;
58
+ --wp-slate-600: #5b6577;
59
+ --wp-slate-700: #424b5c;
60
+ --wp-slate-800: #2b3242;
61
+ --wp-slate-900: #1a2030;
62
+ --wp-slate-950: #0f131e;
63
+ }
64
+
65
+ /* ---------- 토큰: 시맨틱 ---------- */
66
+ :root {
67
+ --wp-text-strong: var(--wp-slate-900);
68
+ --wp-text-default: var(--wp-slate-800);
69
+ --wp-text-muted: var(--wp-slate-600);
70
+ --wp-text-subtle: var(--wp-slate-500);
71
+ --wp-text-disabled: var(--wp-slate-400);
72
+ --wp-text-inverse: var(--wp-white);
73
+ --wp-text-brand: var(--wp-navy-600);
74
+ --wp-text-link: var(--wp-blue-500);
75
+ --wp-text-link-hover: var(--wp-blue-600);
76
+ --wp-text-success: var(--wp-green-600);
77
+ --wp-text-warning: var(--wp-gold-700);
78
+ --wp-text-danger: var(--wp-red-600);
79
+ --wp-text-info: var(--wp-blue-600);
80
+
81
+ --wp-surface-page: var(--wp-slate-50);
82
+ --wp-surface-card: var(--wp-white);
83
+ --wp-surface-sunken: var(--wp-slate-100);
84
+ --wp-surface-hover: var(--wp-slate-50);
85
+ --wp-surface-active: var(--wp-slate-100);
86
+ --wp-surface-selected: var(--wp-navy-50);
87
+ --wp-surface-disabled: var(--wp-slate-100);
88
+ --wp-surface-inverse: var(--wp-navy-600);
89
+ --wp-surface-overlay: rgba(15, 19, 30, 0.52);
90
+
91
+ --wp-border-subtle: var(--wp-slate-200);
92
+ --wp-border-default: var(--wp-slate-300);
93
+ --wp-border-strong: var(--wp-slate-400);
94
+ --wp-border-focus: var(--wp-blue-500);
95
+ --wp-border-danger: var(--wp-red-600);
96
+ --wp-divider: var(--wp-slate-200);
97
+
98
+ --wp-action-primary-bg: var(--wp-navy-600);
99
+ --wp-action-primary-bg-hover: var(--wp-navy-700);
100
+ --wp-action-primary-bg-active: var(--wp-navy-800);
101
+ --wp-action-primary-fg: var(--wp-white);
102
+ --wp-action-secondary-bg: var(--wp-white);
103
+ --wp-action-secondary-bg-hover: var(--wp-slate-50);
104
+ --wp-action-secondary-bg-active: var(--wp-slate-100);
105
+ --wp-action-secondary-fg: var(--wp-slate-800);
106
+ --wp-action-secondary-border: var(--wp-slate-300);
107
+ --wp-action-ghost-bg-hover: var(--wp-slate-100);
108
+ --wp-action-ghost-bg-active: var(--wp-slate-200);
109
+ --wp-action-ghost-fg: var(--wp-slate-700);
110
+ --wp-action-danger-bg: var(--wp-red-600);
111
+ --wp-action-danger-bg-hover: var(--wp-red-700);
112
+ --wp-action-danger-fg: var(--wp-white);
113
+ --wp-action-disabled-bg: var(--wp-slate-200);
114
+ --wp-action-disabled-fg: var(--wp-slate-400);
115
+
116
+ --wp-accent: var(--wp-red-600);
117
+
118
+ --wp-status-info-bg: var(--wp-blue-50);
119
+ --wp-status-info-border: var(--wp-blue-200);
120
+ --wp-status-info-fg: var(--wp-blue-700);
121
+ --wp-status-success-bg: var(--wp-green-50);
122
+ --wp-status-success-border: var(--wp-green-200);
123
+ --wp-status-success-fg: var(--wp-green-700);
124
+ --wp-status-warning-bg: var(--wp-gold-50);
125
+ --wp-status-warning-border: var(--wp-gold-200);
126
+ --wp-status-warning-fg: var(--wp-gold-700);
127
+ --wp-status-danger-bg: var(--wp-red-50);
128
+ --wp-status-danger-border: var(--wp-red-200);
129
+ --wp-status-danger-fg: var(--wp-red-700);
130
+ --wp-status-neutral-bg: var(--wp-slate-100);
131
+ --wp-status-neutral-border: var(--wp-slate-300);
132
+ --wp-status-neutral-fg: var(--wp-slate-700);
133
+
134
+ --wp-chrome-bg: var(--wp-navy-600);
135
+ --wp-chrome-fg: var(--wp-white);
136
+ --wp-chrome-fg-muted: rgba(255, 255, 255, 0.64);
137
+ --wp-chrome-item-hover: rgba(255, 255, 255, 0.1);
138
+ --wp-chrome-item-active: rgba(255, 255, 255, 0.16);
139
+ --wp-chrome-border: rgba(255, 255, 255, 0.12);
140
+
141
+ /* 형태·간격·타이포 */
142
+ --wp-radius-sm: 4px;
143
+ --wp-radius-md: 5px;
144
+ --wp-radius-lg: 8px;
145
+ --wp-radius-full: 999px;
146
+ --wp-space-1: 4px;
147
+ --wp-space-2: 8px;
148
+ --wp-space-3: 12px;
149
+ --wp-space-4: 16px;
150
+ --wp-space-5: 20px;
151
+ --wp-space-6: 24px;
152
+ --wp-space-8: 32px;
153
+ --wp-font-sans: 'Pretendard', 'Pretendard Variable', -apple-system, BlinkMacSystemFont,
154
+ 'Segoe UI', 'Apple SD Gothic Neo', 'Noto Sans KR', sans-serif;
155
+ --wp-font-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
156
+ --wp-shadow-sm: 0 1px 2px rgba(15, 19, 30, 0.06);
157
+ --wp-shadow-md: 0 4px 12px rgba(15, 19, 30, 0.1);
158
+ --wp-shadow-lg: 0 12px 32px rgba(15, 19, 30, 0.18);
159
+ --wp-z-dialog: 100;
160
+ --wp-z-toast: 110;
161
+ }
162
+
163
+ /* ---------- 베이스 ---------- */
164
+ .sdui-root,
165
+ .wp-app {
166
+ font-family: var(--wp-font-sans);
167
+ color: var(--wp-text-default);
168
+ font-size: 13px;
169
+ line-height: 1.5;
170
+ }
171
+ .sdui-root *,
172
+ .wp-app * {
173
+ box-sizing: border-box;
174
+ }
175
+
176
+ /* ---------- 타입 프리셋 ---------- */
177
+ .wp-display-1 { font-size: 40px; font-weight: 800; line-height: 1.15; color: var(--wp-text-strong); margin: 0; }
178
+ .wp-display-2 { font-size: 32px; font-weight: 800; line-height: 1.2; color: var(--wp-text-strong); margin: 0; }
179
+ .wp-h1 { font-size: 24px; font-weight: 700; line-height: 1.3; color: var(--wp-text-strong); margin: 0; }
180
+ .wp-h2 { font-size: 20px; font-weight: 700; line-height: 1.3; color: var(--wp-text-strong); margin: 0; }
181
+ .wp-h3 { font-size: 17px; font-weight: 700; line-height: 1.35; color: var(--wp-text-strong); margin: 0; }
182
+ .wp-h4 { font-size: 15px; font-weight: 700; line-height: 1.4; color: var(--wp-text-strong); margin: 0; }
183
+ .wp-h5 { font-size: 13px; font-weight: 700; line-height: 1.4; color: var(--wp-text-strong); margin: 0; }
184
+ .wp-h6 { font-size: 12px; font-weight: 700; line-height: 1.4; color: var(--wp-text-strong); margin: 0; }
185
+ .wp-body-lg { font-size: 15px; margin: 0; }
186
+ .wp-body { font-size: 13px; margin: 0; }
187
+ .wp-body-sm { font-size: 12px; margin: 0; }
188
+ .wp-caption { font-size: 12px; color: var(--wp-text-muted); margin: 0; }
189
+ .wp-label { font-size: 12px; font-weight: 600; color: var(--wp-text-muted); margin: 0; }
190
+ .wp-overline { font-size: 11px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--wp-text-subtle); margin: 0; }
191
+ .wp-micro { font-size: 10.5px; color: var(--wp-text-subtle); margin: 0; }
192
+ .wp-metric { font-size: 32px; font-weight: 800; font-variant-numeric: tabular-nums; color: var(--wp-text-strong); margin: 0; }
193
+ .wp-metric-sm { font-size: 22px; font-weight: 800; font-variant-numeric: tabular-nums; color: var(--wp-text-strong); margin: 0; }
194
+ .wp-mono { font-family: var(--wp-font-mono); font-size: 12.5px; margin: 0; }
195
+ .wp-mono-xs { font-family: var(--wp-font-mono); font-size: 11px; margin: 0; }
196
+ .wp-num { font-variant-numeric: tabular-nums; font-size: 12px; color: var(--wp-text-muted); }
197
+
198
+ /* ---------- 레이아웃 프리미티브 ---------- */
199
+ .wp-col { display: flex; flex-direction: column; gap: var(--wp-space-4); min-width: 0; }
200
+ .wp-row { display: flex; align-items: center; gap: var(--wp-space-2); min-width: 0; }
201
+ .wp-row--between { justify-content: space-between; }
202
+ .wp-grid { display: grid; gap: var(--wp-space-4); min-width: 0; }
203
+ .wp-grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
204
+ .wp-grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
205
+ .wp-grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
206
+ @media (max-width: 900px) {
207
+ .wp-grid--3, .wp-grid--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
208
+ }
209
+ @media (max-width: 600px) {
210
+ .wp-grid--2, .wp-grid--3, .wp-grid--4 { grid-template-columns: minmax(0, 1fr); }
211
+ }
212
+ .wp-spacer { flex: 1; }
213
+ /*
214
+ * size를 준 Spacer — 남는 공간을 먹는 대신 간격 토큰만큼의 고정 여백이 된다.
215
+ * 가로 묶음(.wp-row)에 들어가든 세로 묶음(.wp-col/.wp-card__body)에 들어가든 같은
216
+ * 값이 나오도록 폭과 높이를 함께 잡는다. 둘 다 명시 크기라 세로 묶음의 stretch도 먹지 않는다.
217
+ */
218
+ .wp-spacer--1, .wp-spacer--2, .wp-spacer--3,
219
+ .wp-spacer--4, .wp-spacer--5, .wp-spacer--6, .wp-spacer--8 { flex: none; }
220
+ .wp-spacer--1 { width: var(--wp-space-1); height: var(--wp-space-1); }
221
+ .wp-spacer--2 { width: var(--wp-space-2); height: var(--wp-space-2); }
222
+ .wp-spacer--3 { width: var(--wp-space-3); height: var(--wp-space-3); }
223
+ .wp-spacer--4 { width: var(--wp-space-4); height: var(--wp-space-4); }
224
+ .wp-spacer--5 { width: var(--wp-space-5); height: var(--wp-space-5); }
225
+ .wp-spacer--6 { width: var(--wp-space-6); height: var(--wp-space-6); }
226
+ .wp-spacer--8 { width: var(--wp-space-8); height: var(--wp-space-8); }
227
+ .wp-divider { border: 0; border-top: 1px solid var(--wp-divider); margin: 0; width: 100%; }
228
+
229
+ /* ---------- 페이지 헤더 ---------- */
230
+ .wp-page-head { display: flex; align-items: flex-end; justify-content: space-between; gap: var(--wp-space-4); }
231
+ .wp-page-head__text { flex: 1; min-width: 0; }
232
+ .wp-page-head__title { font-size: 22px; font-weight: 800; color: var(--wp-text-strong); margin: 0; letter-spacing: -0.01em; }
233
+ .wp-page-head__title::after { content: ''; display: inline-block; width: 6px; height: 6px; border-radius: 50%; background: var(--wp-accent); margin-left: 6px; vertical-align: super; }
234
+ .wp-page-head__sub { font-size: 13px; color: var(--wp-text-muted); margin-top: 4px; }
235
+ .wp-page-head__actions { display: flex; gap: var(--wp-space-2); flex: none; }
236
+
237
+ /* ---------- 키-값 목록 ---------- */
238
+ .wp-kv { display: grid; grid-template-columns: minmax(96px, auto) 1fr; gap: 7px var(--wp-space-4); align-items: baseline; }
239
+ .wp-kv__k { font-size: 12px; font-weight: 600; color: var(--wp-text-muted); }
240
+ .wp-kv__v { font-size: 13px; color: var(--wp-text-default); min-width: 0; overflow-wrap: anywhere; }
241
+
242
+ /* ---------- 버튼 ---------- */
243
+ .wp-btn {
244
+ display: inline-flex; align-items: center; justify-content: center; gap: 6px;
245
+ height: 32px; padding: 0 12px; border-radius: var(--wp-radius-md);
246
+ font-family: inherit; font-size: 13px; font-weight: 600; line-height: 1;
247
+ border: 1px solid transparent; cursor: pointer; white-space: nowrap;
248
+ transition: background 0.12s, border-color 0.12s, color 0.12s;
249
+ }
250
+ .wp-btn:focus-visible { outline: 2px solid var(--wp-border-focus); outline-offset: 1px; }
251
+ .wp-btn:disabled { cursor: not-allowed; }
252
+ .wp-btn--primary { background: var(--wp-action-primary-bg); color: var(--wp-action-primary-fg); }
253
+ .wp-btn--primary:hover:not(:disabled) { background: var(--wp-action-primary-bg-hover); }
254
+ .wp-btn--primary:active:not(:disabled) { background: var(--wp-action-primary-bg-active); }
255
+ .wp-btn--secondary { background: var(--wp-action-secondary-bg); color: var(--wp-action-secondary-fg); border-color: var(--wp-action-secondary-border); }
256
+ .wp-btn--secondary:hover:not(:disabled) { background: var(--wp-action-secondary-bg-hover); }
257
+ .wp-btn--secondary:active:not(:disabled) { background: var(--wp-action-secondary-bg-active); }
258
+ .wp-btn--ghost { background: transparent; color: var(--wp-action-ghost-fg); }
259
+ .wp-btn--ghost:hover:not(:disabled) { background: var(--wp-action-ghost-bg-hover); }
260
+ .wp-btn--ghost:active:not(:disabled) { background: var(--wp-action-ghost-bg-active); }
261
+ .wp-btn--danger { background: var(--wp-action-danger-bg); color: var(--wp-action-danger-fg); }
262
+ .wp-btn--danger:hover:not(:disabled) { background: var(--wp-action-danger-bg-hover); }
263
+ .wp-btn--link { background: none; border: none; color: var(--wp-text-link); padding: 0; height: auto; font-weight: 600; }
264
+ .wp-btn--link:hover:not(:disabled) { color: var(--wp-text-link-hover); text-decoration: underline; }
265
+ .wp-btn--primary:disabled, .wp-btn--secondary:disabled, .wp-btn--ghost:disabled, .wp-btn--danger:disabled {
266
+ background: var(--wp-action-disabled-bg); color: var(--wp-action-disabled-fg); border-color: transparent;
267
+ }
268
+ .wp-btn--xs { height: 24px; padding: 0 8px; font-size: 12px; }
269
+ .wp-btn--sm { height: 28px; padding: 0 10px; font-size: 12.5px; }
270
+ .wp-btn--lg { height: 40px; padding: 0 16px; font-size: 14px; }
271
+ .wp-btn--xl { height: 48px; padding: 0 20px; font-size: 15px; }
272
+ .wp-btn--block { width: 100%; }
273
+ .wp-btn--loading { pointer-events: none; }
274
+
275
+ .wp-iconbtn {
276
+ display: inline-flex; align-items: center; justify-content: center;
277
+ width: 32px; height: 32px; border-radius: var(--wp-radius-md);
278
+ border: none; background: transparent; color: var(--wp-action-ghost-fg); cursor: pointer;
279
+ transition: background 0.12s;
280
+ }
281
+ .wp-iconbtn:hover { background: var(--wp-action-ghost-bg-hover); }
282
+ .wp-iconbtn:active { background: var(--wp-action-ghost-bg-active); }
283
+ .wp-iconbtn:focus-visible { outline: 2px solid var(--wp-border-focus); outline-offset: 1px; }
284
+ .wp-iconbtn--sm { width: 28px; height: 28px; }
285
+ .wp-iconbtn--xs { width: 24px; height: 24px; }
286
+ .wp-iconbtn--danger { color: var(--wp-text-danger); }
287
+ .wp-iconbtn--danger:hover { background: var(--wp-red-50); }
288
+ /* outlined — 툴바에서 배경이 같은 표면 위에 놓일 때 눌리는 자리임을 하드라인으로 보인다. */
289
+ .wp-iconbtn--outlined {
290
+ border: 1px solid var(--wp-action-secondary-border);
291
+ background: var(--wp-action-secondary-bg);
292
+ color: var(--wp-action-secondary-fg);
293
+ box-shadow: var(--wp-shadow-sm);
294
+ }
295
+ .wp-iconbtn--outlined:hover { background: var(--wp-action-secondary-bg-hover); border-color: var(--wp-border-strong); }
296
+ .wp-iconbtn--outlined:active { background: var(--wp-action-secondary-bg-active); }
297
+
298
+ /* ---------- 입력 ---------- */
299
+ .wp-input, .wp-textarea, .wp-select {
300
+ font-family: inherit; font-size: 13px; color: var(--wp-text-default);
301
+ background: var(--wp-surface-card); border: 1px solid var(--wp-border-default);
302
+ border-radius: var(--wp-radius-md); transition: border-color 0.12s, box-shadow 0.12s;
303
+ width: 100%;
304
+ }
305
+ .wp-input { height: 32px; padding: 0 10px; }
306
+ .wp-input--sm { height: 28px; font-size: 12.5px; }
307
+ .wp-input--lg { height: 40px; font-size: 14px; }
308
+ .wp-input--mono { font-family: var(--wp-font-mono); font-size: 12.5px; }
309
+ .wp-input:focus, .wp-textarea:focus, .wp-select:focus {
310
+ outline: none; border-color: var(--wp-border-focus);
311
+ box-shadow: 0 0 0 3px rgba(10, 115, 201, 0.15);
312
+ }
313
+ .wp-input:disabled, .wp-textarea:disabled, .wp-select:disabled {
314
+ background: var(--wp-surface-disabled); color: var(--wp-text-disabled); cursor: not-allowed;
315
+ }
316
+ .wp-input--invalid, .wp-textarea--invalid, .wp-select--invalid { border-color: var(--wp-border-danger); }
317
+ .wp-input--invalid:focus, .wp-textarea--invalid:focus {
318
+ box-shadow: 0 0 0 3px rgba(202, 26, 29, 0.12); border-color: var(--wp-border-danger);
319
+ }
320
+ .wp-input::placeholder, .wp-textarea::placeholder { color: var(--wp-text-subtle); }
321
+
322
+ .wp-inputwrap { position: relative; display: flex; align-items: center; width: 100%; }
323
+ .wp-inputwrap__lead { position: absolute; left: 10px; color: var(--wp-text-subtle); display: flex; pointer-events: none; }
324
+ .wp-inputwrap--lead .wp-input { padding-left: 32px; }
325
+ /* 후행 단위 — 값의 일부가 아니므로 작고 흐리게, 클릭도 입력으로 통과시킨다. */
326
+ .wp-inputwrap__trail {
327
+ position: absolute; right: 10px; display: flex; pointer-events: none;
328
+ font-size: 11.5px; color: var(--wp-text-subtle);
329
+ }
330
+ .wp-inputwrap--trail .wp-input { padding-right: 32px; }
331
+ /*
332
+ * 단위가 오른쪽 끝을 차지하므로 number 입력의 네이티브 증감 화살표가 그 위에 겹친다.
333
+ * 자리를 나눠 쓸 폭이 없어 화살표를 접는다(값은 여전히 키보드 ↑↓로 조절된다).
334
+ */
335
+ .wp-inputwrap--trail .wp-input[type='number'] { appearance: textfield; -moz-appearance: textfield; }
336
+ .wp-inputwrap--trail .wp-input::-webkit-outer-spin-button,
337
+ .wp-inputwrap--trail .wp-input::-webkit-inner-spin-button { appearance: none; -webkit-appearance: none; margin: 0; }
338
+
339
+ .wp-textarea { padding: 8px 10px; resize: vertical; min-height: 60px; line-height: 1.5; }
340
+
341
+ .wp-selectwrap { position: relative; display: flex; width: 100%; }
342
+ .wp-select { height: 32px; padding: 0 30px 0 10px; appearance: none; cursor: pointer; }
343
+ .wp-select--sm { height: 28px; font-size: 12.5px; }
344
+ .wp-select--lg { height: 40px; font-size: 14px; }
345
+ .wp-selectwrap__caret { position: absolute; right: 9px; top: 50%; transform: translateY(-50%); color: var(--wp-text-subtle); pointer-events: none; display: flex; }
346
+
347
+ /* ---------- 체크박스 / 스위치 ---------- */
348
+ .wp-check { display: inline-flex; align-items: flex-start; gap: 8px; cursor: pointer; font-size: 13px; }
349
+ .wp-check input { position: absolute; opacity: 0; width: 0; height: 0; }
350
+ .wp-check__box {
351
+ width: 16px; height: 16px; flex: none; margin-top: 1.5px;
352
+ border: 1px solid var(--wp-border-default); border-radius: var(--wp-radius-sm);
353
+ background: var(--wp-surface-card); color: transparent;
354
+ display: inline-flex; align-items: center; justify-content: center; transition: background 0.12s, border-color 0.12s;
355
+ }
356
+ .wp-check input:checked + .wp-check__box { background: var(--wp-action-primary-bg); border-color: var(--wp-action-primary-bg); color: var(--wp-white); }
357
+ .wp-check input:focus-visible + .wp-check__box { outline: 2px solid var(--wp-border-focus); outline-offset: 1px; }
358
+ .wp-check__text { display: flex; flex-direction: column; gap: 2px; }
359
+ .wp-check__desc { font-size: 12px; color: var(--wp-text-muted); }
360
+ .wp-check--disabled { cursor: not-allowed; color: var(--wp-text-disabled); }
361
+
362
+ .wp-switch { display: inline-flex; align-items: center; gap: 8px; cursor: pointer; font-size: 13px; }
363
+ .wp-switch input { position: absolute; opacity: 0; width: 0; height: 0; }
364
+ .wp-switch__track {
365
+ width: 34px; height: 18px; flex: none; border-radius: var(--wp-radius-full);
366
+ background: var(--wp-slate-300); position: relative; transition: background 0.15s;
367
+ }
368
+ .wp-switch__track::after {
369
+ content: ''; position: absolute; top: 2px; left: 2px; width: 14px; height: 14px;
370
+ border-radius: 50%; background: var(--wp-white); box-shadow: var(--wp-shadow-sm); transition: left 0.15s;
371
+ }
372
+ .wp-switch input:checked + .wp-switch__track { background: var(--wp-action-primary-bg); }
373
+ .wp-switch input:checked + .wp-switch__track::after { left: 18px; }
374
+ .wp-switch input:focus-visible + .wp-switch__track { outline: 2px solid var(--wp-border-focus); outline-offset: 1px; }
375
+ .wp-switch--sm .wp-switch__track { width: 28px; height: 16px; }
376
+ .wp-switch--sm .wp-switch__track::after { width: 12px; height: 12px; }
377
+ .wp-switch--sm input:checked + .wp-switch__track::after { left: 14px; }
378
+
379
+ /* ---------- 필드 ---------- */
380
+ .wp-field { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
381
+ .wp-field--horizontal { flex-direction: row; align-items: flex-start; gap: var(--wp-space-3); }
382
+ .wp-field--horizontal .wp-field__label { width: 132px; flex: none; padding-top: 7px; }
383
+ .wp-field__label { font-size: 12px; font-weight: 600; color: var(--wp-text-muted); }
384
+ .wp-field__req { color: var(--wp-accent); margin-left: 3px; }
385
+ .wp-field__body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 5px; }
386
+ .wp-field__hint { font-size: 12px; color: var(--wp-text-subtle); }
387
+ .wp-field__error { font-size: 12px; color: var(--wp-text-danger); display: inline-flex; align-items: center; gap: 4px; }
388
+
389
+ /* ---------- 카드 ---------- */
390
+ .wp-card {
391
+ background: var(--wp-surface-card); border: 1px solid var(--wp-border-subtle);
392
+ border-radius: var(--wp-radius-lg); box-shadow: var(--wp-shadow-sm);
393
+ display: flex; flex-direction: column; min-width: 0;
394
+ }
395
+ .wp-card--raised { box-shadow: var(--wp-shadow-md); }
396
+ .wp-card--flat { box-shadow: none; }
397
+ .wp-card--sunken { background: var(--wp-surface-sunken); box-shadow: none; }
398
+ .wp-card--selected { border-color: var(--wp-navy-600); }
399
+ .wp-card--interactive { cursor: pointer; transition: box-shadow 0.12s, transform 0.12s; }
400
+ .wp-card--interactive:hover { box-shadow: var(--wp-shadow-md); transform: translateY(-1px); }
401
+ .wp-card__head {
402
+ display: flex; align-items: center; justify-content: space-between; gap: var(--wp-space-3);
403
+ padding: 14px 20px; border-bottom: 1px solid var(--wp-border-subtle);
404
+ }
405
+ .wp-card__title { font-size: 14px; font-weight: 700; color: var(--wp-text-strong); }
406
+ .wp-card__sub { font-size: 12px; color: var(--wp-text-muted); margin-top: 2px; }
407
+ .wp-card__body { padding: 20px; display: flex; flex-direction: column; gap: var(--wp-space-4); min-width: 0; }
408
+ .wp-card__body--tight { padding: 14px; }
409
+ .wp-card__foot {
410
+ display: flex; justify-content: flex-end; gap: var(--wp-space-2);
411
+ padding: 12px 20px; border-top: 1px solid var(--wp-border-subtle);
412
+ }
413
+
414
+ /* ---------- 배지 / 태그 ---------- */
415
+ .wp-badge {
416
+ display: inline-flex; align-items: center; gap: 5px; height: 20px; padding: 0 8px;
417
+ border-radius: var(--wp-radius-full); font-size: 11.5px; font-weight: 600; white-space: nowrap;
418
+ border: 1px solid;
419
+ }
420
+ .wp-badge--lg { height: 24px; font-size: 12.5px; padding: 0 10px; }
421
+ .wp-badge--neutral { background: var(--wp-status-neutral-bg); border-color: var(--wp-status-neutral-border); color: var(--wp-status-neutral-fg); }
422
+ .wp-badge--info { background: var(--wp-status-info-bg); border-color: var(--wp-status-info-border); color: var(--wp-status-info-fg); }
423
+ .wp-badge--success { background: var(--wp-status-success-bg); border-color: var(--wp-status-success-border); color: var(--wp-status-success-fg); }
424
+ .wp-badge--warning { background: var(--wp-status-warning-bg); border-color: var(--wp-status-warning-border); color: var(--wp-status-warning-fg); }
425
+ .wp-badge--danger { background: var(--wp-status-danger-bg); border-color: var(--wp-status-danger-border); color: var(--wp-status-danger-fg); }
426
+ .wp-badge--brand { background: var(--wp-navy-50); border-color: var(--wp-navy-200); color: var(--wp-navy-600); }
427
+ .wp-badge--dot::before { content: ''; width: 5px; height: 5px; border-radius: 50%; background: currentColor; }
428
+
429
+ .wp-tag {
430
+ display: inline-flex; align-items: center; gap: 5px; height: 22px; padding: 0 8px;
431
+ border-radius: var(--wp-radius-sm); font-size: 12px;
432
+ border: 1px solid var(--wp-border-default); background: var(--wp-surface-card); color: var(--wp-text-default);
433
+ }
434
+ .wp-tag--filled { background: var(--wp-slate-100); border-color: transparent; }
435
+ .wp-tag__dot { width: 7px; height: 7px; border-radius: 50%; flex: none; }
436
+ .wp-tag__x { display: inline-flex; cursor: pointer; color: var(--wp-text-subtle); }
437
+ .wp-tag__x:hover { color: var(--wp-text-danger); }
438
+
439
+ /* ---------- 알림 (Alert / Toast) ---------- */
440
+ .wp-alert {
441
+ display: flex; align-items: flex-start; gap: 10px; padding: 12px 14px;
442
+ border: 1px solid; border-radius: var(--wp-radius-md); font-size: 13px;
443
+ }
444
+ .wp-alert__icon { flex: none; display: flex; margin-top: 1px; }
445
+ .wp-alert__body { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
446
+ .wp-alert__title { font-weight: 700; }
447
+ .wp-alert__actions { display: flex; gap: 8px; margin-top: 6px; }
448
+ .wp-alert--info { background: var(--wp-status-info-bg); border-color: var(--wp-status-info-border); color: var(--wp-status-info-fg); }
449
+ .wp-alert--success { background: var(--wp-status-success-bg); border-color: var(--wp-status-success-border); color: var(--wp-status-success-fg); }
450
+ .wp-alert--warning { background: var(--wp-status-warning-bg); border-color: var(--wp-status-warning-border); color: var(--wp-status-warning-fg); }
451
+ .wp-alert--danger { background: var(--wp-status-danger-bg); border-color: var(--wp-status-danger-border); color: var(--wp-status-danger-fg); }
452
+ .wp-alert--neutral { background: var(--wp-status-neutral-bg); border-color: var(--wp-status-neutral-border); color: var(--wp-status-neutral-fg); }
453
+ /*
454
+ * bar — 테두리를 왼쪽 색 막대 하나로 바꾼 페이지 배너 형태.
455
+ * 모서리를 각지게 펴고 나머지 세 변을 지워, 카드 안의 알림이 아니라 화면 폭을 가르는
456
+ * 공지로 읽히게 한다. 막대 색은 본문 글자색(currentColor)이다 — 톤 테두리색은
457
+ * 배경과 붙어 있어 막대로 쓰기엔 약하고, 이렇게 하면 톤별 규칙을 다섯 번 쓰지 않아도 된다.
458
+ */
459
+ .wp-alert--bar { border-radius: 0; border-width: 0 0 0 3px; border-left-color: currentColor; }
460
+
461
+ .wp-toast-region {
462
+ position: fixed; right: 20px; bottom: 20px; z-index: var(--wp-z-toast);
463
+ display: flex; flex-direction: column; gap: 10px; max-width: 380px;
464
+ }
465
+ .wp-toast {
466
+ display: flex; align-items: flex-start; gap: 10px; padding: 12px 14px;
467
+ background: var(--wp-slate-900); color: var(--wp-white);
468
+ border-radius: var(--wp-radius-lg); box-shadow: var(--wp-shadow-lg); font-size: 13px;
469
+ animation: wp-toast-in 0.18s ease-out;
470
+ }
471
+ @keyframes wp-toast-in {
472
+ from { opacity: 0; transform: translateY(8px); }
473
+ to { opacity: 1; transform: none; }
474
+ }
475
+ .wp-toast__icon { flex: none; display: flex; margin-top: 1px; }
476
+ .wp-toast--info .wp-toast__icon { color: var(--wp-blue-200); }
477
+ .wp-toast--success .wp-toast__icon { color: var(--wp-green-200); }
478
+ .wp-toast--warning .wp-toast__icon { color: var(--wp-gold-200); }
479
+ .wp-toast--danger .wp-toast__icon { color: var(--wp-red-200); }
480
+ .wp-toast__body { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
481
+ .wp-toast__title { font-weight: 700; }
482
+ .wp-toast__text { color: rgba(255, 255, 255, 0.85); }
483
+ .wp-toast__x { background: none; border: none; color: rgba(255, 255, 255, 0.6); cursor: pointer; padding: 0; display: flex; }
484
+ .wp-toast__x:hover { color: var(--wp-white); }
485
+
486
+ /* ---------- 탭 ---------- */
487
+ .wp-tabs { display: flex; gap: 2px; border-bottom: 1px solid var(--wp-border-subtle); }
488
+ .wp-tab {
489
+ display: inline-flex; align-items: center; gap: 6px; height: 36px; padding: 0 12px;
490
+ background: none; border: none; border-bottom: 2px solid transparent; margin-bottom: -1px;
491
+ font-family: inherit; font-size: 13px; font-weight: 600; color: var(--wp-text-muted); cursor: pointer;
492
+ transition: color 0.12s, border-color 0.12s;
493
+ }
494
+ .wp-tab:hover { color: var(--wp-text-default); }
495
+ .wp-tab[aria-selected='true'] { color: var(--wp-text-brand); border-bottom-color: var(--wp-accent); }
496
+ .wp-tabs--lg .wp-tab { height: 42px; font-size: 14px; }
497
+ .wp-tab__count {
498
+ font-size: 11px; font-weight: 700; padding: 1px 6px;
499
+ background: var(--wp-slate-100); border-radius: var(--wp-radius-full); color: var(--wp-text-muted);
500
+ }
501
+
502
+ /* ---------- 테이블 ---------- */
503
+ .wp-table { width: 100%; border-collapse: collapse; font-size: 13px; }
504
+ .wp-table th {
505
+ text-align: left; font-size: 11.5px; font-weight: 700; letter-spacing: 0.03em;
506
+ color: var(--wp-text-muted); text-transform: uppercase;
507
+ padding: 9px 12px; border-bottom: 1px solid var(--wp-border-default);
508
+ background: var(--wp-slate-25); white-space: nowrap;
509
+ }
510
+ .wp-table td { padding: 10px 12px; border-bottom: 1px solid var(--wp-border-subtle); vertical-align: middle; }
511
+ .wp-table--dense td { padding: 6px 12px; }
512
+ .wp-table--hover tbody tr:hover { background: var(--wp-surface-hover); }
513
+ .wp-table__num { text-align: right; font-variant-numeric: tabular-nums; }
514
+ .wp-table__mono { font-family: var(--wp-font-mono); font-size: 12px; }
515
+ .wp-table__strong { font-weight: 600; color: var(--wp-text-strong); }
516
+
517
+ /* ---------- 스탯 ---------- */
518
+ .wp-stat { display: flex; flex-direction: column; gap: 4px; }
519
+ .wp-stat__label { display: flex; align-items: center; gap: 5px; font-size: 12px; font-weight: 600; color: var(--wp-text-muted); }
520
+ .wp-stat__value { font-size: 32px; font-weight: 800; line-height: 1.1; color: var(--wp-text-strong); font-variant-numeric: tabular-nums; }
521
+ .wp-stat--sm .wp-stat__value { font-size: 22px; }
522
+ .wp-stat__unit { font-size: 14px; font-weight: 600; color: var(--wp-text-muted); margin-left: 4px; }
523
+ .wp-stat__delta { display: inline-flex; align-items: center; gap: 3px; font-size: 12px; font-weight: 600; }
524
+ .wp-stat__delta--up { color: var(--wp-text-success); }
525
+ .wp-stat__delta--down { color: var(--wp-text-danger); }
526
+ .wp-stat__delta--flat { color: var(--wp-text-subtle); }
527
+
528
+ /* ---------- 빈 상태 ---------- */
529
+ .wp-empty {
530
+ display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px;
531
+ padding: 48px 24px; text-align: center;
532
+ }
533
+ .wp-empty--tight { padding: 24px 16px; }
534
+ .wp-empty__mark {
535
+ width: 44px; height: 44px; display: flex; align-items: center; justify-content: center;
536
+ background: var(--wp-slate-100); color: var(--wp-text-subtle);
537
+ clip-path: polygon(25% 5%, 75% 5%, 100% 50%, 75% 95%, 25% 95%, 0% 50%);
538
+ }
539
+ .wp-empty__title { font-size: 14px; font-weight: 700; color: var(--wp-text-strong); }
540
+ .wp-empty__text { font-size: 12.5px; color: var(--wp-text-muted); max-width: 360px; }
541
+ .wp-empty__actions { margin-top: 8px; display: flex; gap: 8px; }
542
+
543
+ /* ---------- 스피너 / 프로그레스 ---------- */
544
+ .wp-spinner {
545
+ width: 16px; height: 16px; flex: none; border-radius: 50%;
546
+ border: 2px solid var(--wp-slate-200); border-top-color: var(--wp-navy-600);
547
+ animation: wp-spin 0.7s linear infinite; display: inline-block;
548
+ }
549
+ .wp-spinner--sm { width: 12px; height: 12px; border-width: 2px; }
550
+ .wp-spinner--lg { width: 24px; height: 24px; border-width: 3px; }
551
+ @keyframes wp-spin { to { transform: rotate(360deg); } }
552
+
553
+ .wp-progress { display: flex; flex-direction: column; gap: 5px; }
554
+ /* showValue를 켜면 라벨 줄이 "라벨 … 값" 두 칸이 된다(라벨이 없으면 값만 오른쪽에). */
555
+ .wp-progress__label { display: flex; align-items: baseline; gap: var(--wp-space-2); font-size: 12px; color: var(--wp-text-muted); }
556
+ /* 값은 라벨과 같은 무게로 흐리게 둔다 — 눈에 먼저 걸려야 하는 것은 막대 자체다. */
557
+ .wp-progress__value { margin-left: auto; flex: none; text-align: right; }
558
+ .wp-progress__track { height: 6px; background: var(--wp-slate-100); border-radius: var(--wp-radius-full); overflow: hidden; }
559
+ .wp-progress__fill { height: 100%; border-radius: var(--wp-radius-full); transition: width 0.25s; }
560
+ .wp-progress__fill--brand { background: var(--wp-navy-600); }
561
+ .wp-progress__fill--success { background: var(--wp-green-600); }
562
+ .wp-progress__fill--warning { background: var(--wp-gold-600); }
563
+ .wp-progress__fill--danger { background: var(--wp-red-600); }
564
+ /* info — 브랜드 네이비와 헷갈리지 않게 시그널 블루 쪽을 쓴다. */
565
+ .wp-progress__fill--info { background: var(--wp-blue-600); }
566
+
567
+ /* ---------- 페이지네이션 ---------- */
568
+ .wp-pager { display: flex; align-items: center; gap: 4px; width: 100%; }
569
+ .wp-pager__pages { display: flex; gap: 2px; }
570
+ .wp-pager__page {
571
+ min-width: 28px; height: 28px; padding: 0 6px; border: none; background: none;
572
+ border-radius: var(--wp-radius-md); font-family: inherit; font-size: 12.5px; font-weight: 600;
573
+ color: var(--wp-text-muted); cursor: pointer; display: inline-flex; align-items: center; justify-content: center;
574
+ }
575
+ .wp-pager__page:hover:not(:disabled) { background: var(--wp-slate-100); color: var(--wp-text-default); }
576
+ .wp-pager__page[aria-current] { background: var(--wp-navy-600); color: var(--wp-white); }
577
+ .wp-pager__page:disabled { color: var(--wp-text-disabled); cursor: not-allowed; }
578
+ .wp-pager__gap { color: var(--wp-text-subtle); padding: 0 4px; }
579
+
580
+ /* ---------- 다이얼로그 ---------- */
581
+ .wp-overlay {
582
+ position: absolute; inset: 0; background: var(--wp-surface-overlay);
583
+ display: flex; align-items: flex-start; justify-content: center;
584
+ padding: 9vh 20px 20px; overflow-y: auto;
585
+ }
586
+ .wp-dialog {
587
+ width: 480px; max-width: 100%; background: var(--wp-surface-card);
588
+ border-radius: var(--wp-radius-lg); box-shadow: var(--wp-shadow-lg);
589
+ display: flex; flex-direction: column; max-height: 82vh;
590
+ animation: wp-dialog-in 0.16s ease-out;
591
+ }
592
+ @keyframes wp-dialog-in {
593
+ from { opacity: 0; transform: translateY(-8px) scale(0.98); }
594
+ to { opacity: 1; transform: none; }
595
+ }
596
+ .wp-dialog--sm { width: 380px; }
597
+ .wp-dialog--lg { width: 680px; }
598
+ .wp-dialog--xl { width: 880px; }
599
+ .wp-dialog__head {
600
+ display: flex; align-items: center; gap: 10px;
601
+ padding: 16px 20px; border-bottom: 1px solid var(--wp-border-subtle);
602
+ }
603
+ .wp-dialog__mark {
604
+ width: 32px; height: 32px; flex: none; display: flex; align-items: center; justify-content: center;
605
+ background: var(--wp-navy-600); color: var(--wp-white);
606
+ clip-path: polygon(25% 5%, 75% 5%, 100% 50%, 75% 95%, 25% 95%, 0% 50%);
607
+ }
608
+ .wp-dialog__mark--danger { background: var(--wp-red-600); }
609
+ .wp-dialog__title { font-size: 15px; font-weight: 700; color: var(--wp-text-strong); }
610
+ .wp-dialog__sub { font-size: 12px; color: var(--wp-text-muted); margin-top: 1px; }
611
+ .wp-dialog__body { padding: 20px; overflow-y: auto; display: flex; flex-direction: column; gap: var(--wp-space-4); }
612
+ .wp-dialog__foot {
613
+ display: flex; justify-content: flex-end; gap: var(--wp-space-2);
614
+ padding: 14px 20px; border-top: 1px solid var(--wp-border-subtle);
615
+ }