@stn-uiux/pub-ui 0.1.68 → 0.1.70

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/dist/chunk-7ONB2WVN.js +1 -0
  2. package/dist/{chunk-HJCUNRB3.js → chunk-FSSMH6VS.js} +17 -1
  3. package/dist/chunk-FSSMH6VS.js.map +1 -0
  4. package/dist/{chunk-LKVTW54X.js → chunk-IZRGNUH6.js} +1 -1
  5. package/dist/chunk-IZRGNUH6.js.map +1 -0
  6. package/dist/{chunk-XBFXX3D6.js → chunk-NGUMR3D6.js} +15 -3
  7. package/dist/chunk-NGUMR3D6.js.map +1 -0
  8. package/dist/chunk-O77GW7PM.js +1 -0
  9. package/dist/chunk-O77GW7PM.js.map +1 -0
  10. package/dist/cli.js +6 -6
  11. package/dist/data/index.d.ts +2 -0
  12. package/dist/data/index.js +13 -12
  13. package/dist/data/stnDropdown.d.ts +1 -1
  14. package/dist/data/stnDropdown.js +1 -1
  15. package/dist/data/stnLayer0Background.d.ts +15 -3
  16. package/dist/data/stnLayer0Background.js +2 -2
  17. package/dist/data/stnLayer0BackgroundAssets.d.ts +12 -0
  18. package/dist/data/stnLayer0BackgroundAssets.js +1 -1
  19. package/dist/data/stnTabs.d.ts +26 -0
  20. package/dist/data/stnTabs.js +2 -0
  21. package/dist/data/stnTabs.js.map +1 -0
  22. package/dist/index.d.ts +2 -0
  23. package/dist/index.js +13 -12
  24. package/package.json +1 -1
  25. package/styles/components/stn-card.css +44 -0
  26. package/styles/components/stn-chip.css +10 -34
  27. package/styles/components/stn-dropdown.css +20 -0
  28. package/styles/components/stn-status.css +26 -26
  29. package/styles/components/stn-tabs.css +412 -0
  30. package/styles/components/stn-widget.css +32 -0
  31. package/styles/layouts/stn-layer1-content.css +2 -2
  32. package/styles/style-pub.css +1 -0
  33. package/styles/tokens/stn-colors-semantic.css +16 -6
  34. package/styles/tokens/stn-size-semantic.css +1 -0
  35. package/styles/tokens/stn-spacing-semantic.css +4 -0
  36. package/dist/chunk-AVICAV6Z.js +0 -1
  37. package/dist/chunk-HJCUNRB3.js.map +0 -1
  38. package/dist/chunk-LKVTW54X.js.map +0 -1
  39. package/dist/chunk-XBFXX3D6.js.map +0 -1
  40. /package/dist/{chunk-AVICAV6Z.js.map → chunk-7ONB2WVN.js.map} +0 -0
@@ -173,6 +173,26 @@
173
173
  border-bottom: var(--stn-size-1, 1px) solid var(--stn-feedback-error);
174
174
  }
175
175
 
176
+ /* 3-5. Translucent (반투명 — 배경 비침 & 블러) */
177
+ .stn-dropdown.translucent>.selected {
178
+ border: var(--stn-size-1, 1px) solid var(--stn-input-border);
179
+ background-color: var(--stn-dropdown-bg-translucent, var(--stn-opacity-black-25));
180
+ color: var(--stn-input-fg, var(--stn-text-primary));
181
+ backdrop-filter: blur(var(--stn-dropdown-translucent-blur, 8px));
182
+ -webkit-backdrop-filter: blur(var(--stn-dropdown-translucent-blur, 8px));
183
+ }
184
+
185
+ .stn-dropdown.translucent:hover:not(.is-disabled)>.selected {
186
+ border-color: var(--stn-border-strong, var(--stn-gray-400));
187
+ background-color: color-mix(in srgb, var(--stn-dropdown-bg-translucent, var(--stn-opacity-black-25)) 75%, var(--stn-static-white) 25%);
188
+ }
189
+
190
+ .stn-dropdown.translucent.on>.selected,
191
+ .stn-dropdown.translucent:focus-within>.selected {
192
+ border: var(--stn-input-focus);
193
+ background-color: color-mix(in srgb, var(--stn-dropdown-bg-translucent, var(--stn-opacity-black-25)) 80%, var(--stn-primary) 20%);
194
+ }
195
+
176
196
  /* ==========================================================================
177
197
  4. Prop: state (Normal · Focus/Open · Disabled · Error · ReadOnly)
178
198
  ========================================================================== */
@@ -36,7 +36,7 @@
36
36
  }
37
37
 
38
38
  /* Size 스케일 — STN 표준 규격: xs · sm · md(기본) · lg · xl */
39
- /* xs — 18px */
39
+ /* xs — 20px (bordered) */
40
40
  .stn-status-dot.xs {
41
41
  font-size: var(--stn-font-size-11, 11px);
42
42
  gap: var(--stn-space-4, 4px);
@@ -46,14 +46,14 @@
46
46
  height: var(--stn-size-6, 6px);
47
47
  }
48
48
  .stn-status-dot.xs.bordered {
49
- height: var(--stn-size-18, 18px);
49
+ height: var(--stn-size-20, 20px);
50
50
  padding: 0 var(--stn-space-6, 6px);
51
51
  }
52
52
  .stn-status-dot.xs .stn-status-dot__count {
53
53
  font-size: var(--stn-font-size-10, 10px);
54
54
  }
55
55
 
56
- /* sm — 20px */
56
+ /* sm — 24px (bordered: 버튼 sm과 1:1 일치) */
57
57
  .stn-status-dot.sm {
58
58
  font-size: var(--stn-font-size-12, 12px);
59
59
  gap: var(--stn-space-4, 4px);
@@ -63,14 +63,14 @@
63
63
  height: var(--stn-size-7, 7px);
64
64
  }
65
65
  .stn-status-dot.sm.bordered {
66
- height: var(--stn-size-20, 20px);
67
- padding: 0 var(--stn-space-6, 6px);
66
+ height: var(--stn-size-24, 24px);
67
+ padding: 0 var(--stn-space-8, 8px);
68
68
  }
69
69
  .stn-status-dot.sm .stn-status-dot__count {
70
70
  font-size: var(--stn-font-size-11, 11px);
71
71
  }
72
72
 
73
- /* md — 24px (기본) */
73
+ /* md — 32px (기본 · bordered: 버튼 md와 1:1 일치) */
74
74
  .stn-status-dot.md {
75
75
  font-size: var(--stn-font-size-13, 13px);
76
76
  gap: var(--stn-space-6, 6px);
@@ -80,14 +80,14 @@
80
80
  height: var(--stn-size-8, 8px);
81
81
  }
82
82
  .stn-status-dot.md.bordered {
83
- height: var(--stn-size-24, 24px);
84
- padding: 0 var(--stn-space-8, 8px);
83
+ height: var(--stn-size-32, 32px);
84
+ padding: 0 var(--stn-space-10, 10px);
85
85
  }
86
86
  .stn-status-dot.md .stn-status-dot__count {
87
87
  font-size: var(--stn-font-size-12, 12px);
88
88
  }
89
89
 
90
- /* lg — 28px */
90
+ /* lg — 40px (bordered: 버튼 lg와 1:1 일치) */
91
91
  .stn-status-dot.lg {
92
92
  font-size: var(--stn-font-size-14, 14px);
93
93
  gap: var(--stn-space-8, 8px);
@@ -97,14 +97,14 @@
97
97
  height: var(--stn-size-10, 10px);
98
98
  }
99
99
  .stn-status-dot.lg.bordered {
100
- height: var(--stn-size-28, 28px);
101
- padding: 0 var(--stn-space-10, 10px);
100
+ height: var(--stn-size-40, 40px);
101
+ padding: 0 var(--stn-space-12, 12px);
102
102
  }
103
103
  .stn-status-dot.lg .stn-status-dot__count {
104
104
  font-size: var(--stn-font-size-13, 13px);
105
105
  }
106
106
 
107
- /* xl — 32px */
107
+ /* xl — 48px (bordered) */
108
108
  .stn-status-dot.xl {
109
109
  font-size: var(--stn-font-size-15, 15px);
110
110
  gap: var(--stn-space-8, 8px);
@@ -114,8 +114,8 @@
114
114
  height: var(--stn-size-10, 10px);
115
115
  }
116
116
  .stn-status-dot.xl.bordered {
117
- height: var(--stn-size-32, 32px);
118
- padding: 0 var(--stn-space-12, 12px);
117
+ height: var(--stn-size-48, 48px);
118
+ padding: 0 var(--stn-space-14, 14px);
119
119
  }
120
120
  .stn-status-dot.xl .stn-status-dot__count {
121
121
  font-size: var(--stn-font-size-14, 14px);
@@ -128,13 +128,13 @@
128
128
  .stn-status-dot.gap-md { gap: var(--stn-space-6, 6px); }
129
129
  .stn-status-dot.gap-lg { gap: var(--stn-space-10, 10px); }
130
130
 
131
- /* 단독 테두리 캡슐 모드 (Bordered Dot) */
131
+ /* 단독 테두리 캡슐 모드 (Bordered Dot: 기본 md 32px) */
132
132
  .stn-status-dot.bordered {
133
- height: var(--stn-size-24, 24px);
134
- padding: 0 var(--stn-space-8, 8px);
133
+ height: var(--stn-size-32, 32px);
134
+ padding: 0 var(--stn-space-10, 10px);
135
135
  border-radius: var(--stn-radius-chip-pill, 9999px);
136
- border: 1px solid var(--stn-status-dot-bordered-border);
137
- background-color: var(--stn-layer-bg-card);
136
+ border: 1px solid var(--stn-status-dot-bordered-border, var(--stn-border-subtle));
137
+ background-color: var(--stn-status-dot-bordered-bg, var(--stn-layer-bg-card, transparent));
138
138
  box-sizing: border-box;
139
139
  }
140
140
 
@@ -254,8 +254,8 @@
254
254
  .stn-status-dot-group.bordered {
255
255
  height: var(--stn-size-26, 26px);
256
256
  border-radius: var(--stn-radius-chip-pill, 9999px);
257
- border: 1px solid var(--stn-status-dot-bordered-border);
258
- background-color: var(--stn-layer-bg-card);
257
+ border: 1px solid var(--stn-status-dot-bordered-border, var(--stn-border-subtle));
258
+ background-color: var(--stn-status-dot-bordered-bg, var(--stn-layer-bg-card, transparent));
259
259
  box-shadow: none;
260
260
  overflow: hidden;
261
261
  }
@@ -272,7 +272,7 @@
272
272
  font-weight: var(--stn-font-weight-medium, 500);
273
273
  color: var(--stn-text-primary);
274
274
  user-select: none;
275
- border-right: 1px solid var(--stn-status-dot-bordered-border);
275
+ border-right: 1px solid var(--stn-status-dot-bordered-border, var(--stn-border-subtle));
276
276
  transition: opacity 0.2s ease, background-color 0.15s ease;
277
277
  }
278
278
 
@@ -596,7 +596,7 @@
596
596
  display: inline-flex;
597
597
  align-items: center;
598
598
  justify-content: center;
599
- gap: var(--stn-space-2, 2px);
599
+ gap: var(--stn-severity-badge-gap, var(--stn-space-4, 4px));
600
600
  border-radius: var(--stn-radius-4, 4px);
601
601
  font-family: var(--stn-font-body, Pretendard, sans-serif);
602
602
  line-height: 1.2;
@@ -631,7 +631,7 @@
631
631
  height: var(--stn-severity-badge-height-sm, var(--stn-size-18, 18px));
632
632
  padding: var(--stn-severity-badge-padding-sm, var(--stn-space-2, 2px) var(--stn-space-4, 4px));
633
633
  font-size: var(--stn-font-size-10, 10px);
634
- gap: var(--stn-space-2, 2px);
634
+ gap: var(--stn-severity-badge-gap-sm, var(--stn-space-2, 2px));
635
635
  }
636
636
 
637
637
  .stn-status-severity.sm .stn-status-severity__icon {
@@ -644,7 +644,7 @@
644
644
  height: var(--stn-severity-badge-height-md, var(--stn-size-20, 20px));
645
645
  padding: var(--stn-severity-badge-padding-md, var(--stn-space-4, 4px) var(--stn-space-8, 8px));
646
646
  font-size: var(--stn-font-size-11, 11px);
647
- gap: var(--stn-space-2, 2px);
647
+ gap: var(--stn-severity-badge-gap-md, var(--stn-space-4, 4px));
648
648
  }
649
649
 
650
650
  .stn-status-severity.md .stn-status-severity__icon {
@@ -657,7 +657,7 @@
657
657
  height: var(--stn-severity-badge-height-lg, var(--stn-size-24, 24px));
658
658
  padding: var(--stn-severity-badge-padding-lg, var(--stn-space-4, 4px) var(--stn-space-10, 10px));
659
659
  font-size: var(--stn-font-size-12, 12px);
660
- gap: var(--stn-space-4, 4px);
660
+ gap: var(--stn-severity-badge-gap-lg, var(--stn-space-4, 4px));
661
661
  }
662
662
 
663
663
  .stn-status-severity.lg .stn-status-severity__icon {
@@ -0,0 +1,412 @@
1
+ @charset "utf-8";
2
+ /**
3
+ * StnTabs — 탭 내비게이션 (Tabs, Tab, TabPanel)
4
+ *
5
+ * Classes:
6
+ * - Container: `.stn-tabs`
7
+ * - Scroll area: `.stn-tabs__scroller`
8
+ * - Tab List: `.stn-tabs__list`
9
+ * - Tab item: `.stn-tab`
10
+ * - Floating indicator: `.stn-tabs__indicator`
11
+ * - Scroll buttons: `.stn-tabs__scroll-button`
12
+ * - Panel: `.stn-tab-panel`
13
+ *
14
+ * Variants:
15
+ * - `line` (기본): 하단 2px 밑줄 인디케이터가 부드럽게 이동
16
+ *
17
+ * Sizes:
18
+ * - `sm`: height 32px, font 12px
19
+ * - `md` (기본): height 38px, font 13px
20
+ * - `lg`: height 44px, font 14px
21
+ */
22
+
23
+ /* ==========================================================================
24
+ 1. StnTabs Container
25
+ ========================================================================== */
26
+ .stn-tabs {
27
+ position: relative;
28
+ display: flex;
29
+ align-items: center;
30
+ width: 100%;
31
+ box-sizing: border-box;
32
+ user-select: none;
33
+ background-color: transparent;
34
+ border-bottom: 1px solid var(--stn-border-subtle);
35
+ transition: background-color 0.2s ease, border-color 0.2s ease;
36
+ }
37
+
38
+ .stn-tabs.line {
39
+ border-bottom: 1px solid var(--stn-border-subtle);
40
+ }
41
+
42
+ /* Full Width (stretch tabs) */
43
+ .stn-tabs.full .stn-tabs__list {
44
+ width: 100%;
45
+ }
46
+ .stn-tabs.full .stn-tab {
47
+ flex: 1 1 0%;
48
+ text-align: center;
49
+ justify-content: center;
50
+ }
51
+
52
+ /* Centered Tabs */
53
+ .stn-tabs.centered .stn-tabs__list {
54
+ justify-content: center;
55
+ }
56
+
57
+ /* ==========================================================================
58
+ 2. Scroller & Tab List
59
+ ========================================================================== */
60
+ .stn-tabs__scroller {
61
+ position: relative;
62
+ display: flex;
63
+ flex: 1 1 auto;
64
+ white-space: nowrap;
65
+ overflow-x: auto;
66
+ overflow-y: hidden;
67
+ -webkit-overflow-scrolling: touch; /* iOS Safari 관성 스크롤 */
68
+ touch-action: pan-x; /* 모바일 가로 제스처 최적화 */
69
+ overscroll-behavior-x: contain;
70
+ scrollbar-width: none; /* Hide scrollbar Firefox */
71
+ -ms-overflow-style: none; /* IE/Edge */
72
+ }
73
+
74
+ .stn-tabs__scroller::-webkit-scrollbar {
75
+ display: none; /* Hide scrollbar Chrome/Safari */
76
+ }
77
+
78
+ .stn-tabs__list {
79
+ position: relative;
80
+ display: flex;
81
+ flex-direction: row;
82
+ align-items: center;
83
+ list-style: none;
84
+ margin: 0;
85
+ padding: 0;
86
+ min-width: fit-content;
87
+ }
88
+
89
+ /* ==========================================================================
90
+ 3. Tab Item (.stn-tab)
91
+ ========================================================================== */
92
+ .stn-tab {
93
+ position: relative;
94
+ z-index: 1;
95
+ display: inline-flex;
96
+ align-items: center;
97
+ justify-content: center;
98
+ gap: var(--stn-space-6, 6px);
99
+ box-sizing: border-box;
100
+ background: transparent;
101
+ border: none;
102
+ cursor: pointer;
103
+ color: var(--stn-text-tertiary);
104
+ font-family: var(--stn-font-body, Pretendard, sans-serif);
105
+ font-weight: var(--stn-font-weight-medium, 500);
106
+ line-height: 1;
107
+ text-decoration: none;
108
+ white-space: nowrap;
109
+ outline: none;
110
+ -webkit-tap-highlight-color: transparent;
111
+ transition:
112
+ color 0.2s cubic-bezier(0.4, 0, 0.2, 1),
113
+ background-color 0.2s cubic-bezier(0.4, 0, 0.2, 1),
114
+ border-color 0.2s cubic-bezier(0.4, 0, 0.2, 1);
115
+ }
116
+
117
+ /* Size: sm */
118
+ .stn-tabs.sm .stn-tab {
119
+ height: var(--stn-size-32, 32px);
120
+ padding: 0 var(--stn-space-12, 12px);
121
+ font-size: var(--stn-font-size-12, 12px);
122
+ border-radius: var(--stn-radius-sm, 6px);
123
+ }
124
+
125
+ /* Size: md (기본) */
126
+ .stn-tabs.md .stn-tab,
127
+ .stn-tabs:not(.sm):not(.lg) .stn-tab {
128
+ height: var(--stn-size-38, 38px);
129
+ padding: 0 var(--stn-space-16, 16px);
130
+ font-size: var(--stn-font-size-13, 13px);
131
+ border-radius: var(--stn-radius-md, 8px);
132
+ }
133
+
134
+ /* Size: lg */
135
+ .stn-tabs.lg .stn-tab {
136
+ height: var(--stn-size-44, 44px);
137
+ padding: 0 var(--stn-space-20, 20px);
138
+ font-size: var(--stn-font-size-14, 14px);
139
+ border-radius: var(--stn-radius-md, 8px);
140
+ }
141
+
142
+ /* Wrapped Labels (긴 텍스트 2줄 자동 줄바꿈) */
143
+ .stn-tab.is-wrapped {
144
+ white-space: normal;
145
+ line-height: var(--stn-line-height-tight, 1.35);
146
+ text-align: center;
147
+ max-width: 260px;
148
+ min-height: var(--stn-size-48, 48px);
149
+ height: auto;
150
+ padding-top: var(--stn-space-6, 6px);
151
+ padding-bottom: var(--stn-space-6, 6px);
152
+ }
153
+
154
+ .stn-tab.is-wrapped .stn-tab__label {
155
+ display: -webkit-box;
156
+ -webkit-line-clamp: 2;
157
+ -webkit-box-orient: vertical;
158
+ overflow: hidden;
159
+ text-overflow: ellipsis;
160
+ word-break: keep-all;
161
+ }
162
+
163
+ /* Hover State */
164
+ .stn-tab:hover:not(.is-disabled) {
165
+ color: var(--stn-text-primary);
166
+ }
167
+
168
+ /* Focus Visible */
169
+ .stn-tab:focus-visible {
170
+ outline: var(--stn-focus-ring-width, var(--stn-size-2, 2px)) solid var(--stn-focus-ring);
171
+ outline-offset: -2px;
172
+ }
173
+
174
+ /* Active / Selected State */
175
+ .stn-tab.is-active {
176
+ color: var(--stn-primary, var(--stn-blue-400));
177
+ font-weight: var(--stn-font-weight-semibold, 600);
178
+ }
179
+
180
+ /* Disabled State */
181
+ .stn-tab.is-disabled {
182
+ cursor: not-allowed;
183
+ opacity: var(--stn-disabled-opacity, 0.45);
184
+ pointer-events: none;
185
+ }
186
+
187
+
188
+ /* Icon in Tab */
189
+ .stn-tab__icon {
190
+ display: inline-flex;
191
+ align-items: center;
192
+ justify-content: center;
193
+ line-height: 1;
194
+ flex-shrink: 0;
195
+ transition: transform 0.2s ease, color 0.2s ease;
196
+ }
197
+
198
+ .stn-tab__icon > svg,
199
+ .stn-tab__icon > img,
200
+ .stn-tab__icon > .stn-icon {
201
+ width: 100%;
202
+ height: 100%;
203
+ object-fit: contain;
204
+ }
205
+
206
+ /* Icon Sizes */
207
+ .stn-tab__icon.icon-sm {
208
+ width: var(--stn-size-14, 14px);
209
+ height: var(--stn-size-14, 14px);
210
+ }
211
+
212
+ .stn-tab__icon.icon-md {
213
+ width: var(--stn-size-18, 18px);
214
+ height: var(--stn-size-18, 18px);
215
+ }
216
+
217
+ .stn-tab__icon.icon-lg {
218
+ width: var(--stn-size-22, 22px);
219
+ height: var(--stn-size-22, 22px);
220
+ }
221
+
222
+ /* Icon Positions: start (기본), end, top, bottom */
223
+ .stn-tab.icon-top {
224
+ flex-direction: column;
225
+ justify-content: center;
226
+ gap: var(--stn-space-4, 4px);
227
+ min-height: var(--stn-size-48, 48px);
228
+ height: auto;
229
+ padding-top: var(--stn-space-8, 8px);
230
+ padding-bottom: var(--stn-space-8, 8px);
231
+ }
232
+
233
+ .stn-tab.icon-bottom {
234
+ flex-direction: column-reverse;
235
+ justify-content: center;
236
+ gap: var(--stn-space-4, 4px);
237
+ min-height: var(--stn-size-48, 48px);
238
+ height: auto;
239
+ padding-top: var(--stn-space-8, 8px);
240
+ padding-bottom: var(--stn-space-8, 8px);
241
+ }
242
+
243
+ .stn-tab.icon-end {
244
+ flex-direction: row-reverse;
245
+ }
246
+
247
+ /* Icon-only Tab (정방형 비율 & 툴팁 호환) */
248
+ .stn-tab.icon-only {
249
+ padding: 0;
250
+ aspect-ratio: 1 / 1;
251
+ }
252
+
253
+ .stn-tabs.sm .stn-tab.icon-only {
254
+ width: var(--stn-size-32, 32px);
255
+ min-width: var(--stn-size-32, 32px);
256
+ }
257
+
258
+ .stn-tabs.md .stn-tab.icon-only,
259
+ .stn-tabs:not(.sm):not(.lg) .stn-tab.icon-only {
260
+ width: var(--stn-size-38, 38px);
261
+ min-width: var(--stn-size-38, 38px);
262
+ }
263
+
264
+ .stn-tabs.lg .stn-tab.icon-only {
265
+ width: var(--stn-size-44, 44px);
266
+ min-width: var(--stn-size-44, 44px);
267
+ }
268
+
269
+ /* Badge / Count in Tab — StnChip 'sm' 표준 규격 1:1 연동 */
270
+ .stn-tab__badge {
271
+ display: inline-flex;
272
+ align-items: center;
273
+ justify-content: center;
274
+ min-width: var(--stn-chip-height-sm, 20px);
275
+ height: var(--stn-chip-height-sm, 20px);
276
+ padding: 0 var(--stn-chip-padding-x-sm, 6px);
277
+ border-radius: var(--stn-radius-chip-pill, 9999px);
278
+ font-size: var(--stn-chip-font-size-sm, 11px);
279
+ font-family: var(--stn-font-number, Pretendard, sans-serif);
280
+ font-weight: var(--stn-font-weight-bold, 700);
281
+ line-height: 1;
282
+ background-color: var(--stn-tab-badge-bg);
283
+ color: var(--stn-tab-badge-fg);
284
+ transition: background-color 0.2s ease, color 0.2s ease;
285
+ }
286
+
287
+ .stn-tab.is-active .stn-tab__badge {
288
+ background-color: color-mix(in srgb, var(--stn-primary) 18%, transparent);
289
+ color: var(--stn-primary);
290
+ }
291
+
292
+ .stn-tab__extra {
293
+ display: inline-flex;
294
+ align-items: center;
295
+ line-height: 1;
296
+ }
297
+
298
+ /* ==========================================================================
299
+ 4. Floating Animated Indicator (.stn-tabs__indicator)
300
+ ========================================================================== */
301
+ .stn-tabs__indicator {
302
+ position: absolute;
303
+ pointer-events: none;
304
+ z-index: 0;
305
+ bottom: 0;
306
+ height: 2px;
307
+ background-color: var(--stn-primary);
308
+ border-radius: var(--stn-radius-pill, 2px);
309
+ transition:
310
+ left 0.28s cubic-bezier(0.2, 0.9, 0.3, 1),
311
+ width 0.28s cubic-bezier(0.2, 0.9, 0.3, 1),
312
+ transform 0.28s cubic-bezier(0.2, 0.9, 0.3, 1),
313
+ opacity 0.2s ease;
314
+ }
315
+
316
+ /* ==========================================================================
317
+ 5. Scroll Buttons (.stn-tabs__scroll-button)
318
+ ========================================================================== */
319
+ .stn-tabs__scroll-button {
320
+ display: inline-flex;
321
+ align-items: center;
322
+ justify-content: center;
323
+ width: var(--stn-size-32, 32px);
324
+ height: 100%;
325
+ min-height: var(--stn-size-32, 32px);
326
+ background: transparent;
327
+ border: none;
328
+ color: var(--stn-text-secondary);
329
+ cursor: pointer;
330
+ padding: 0;
331
+ flex-shrink: 0;
332
+ outline: none;
333
+ z-index: 2;
334
+ transition: color 0.15s ease, opacity 0.15s ease, background-color 0.15s ease;
335
+ border-radius: var(--stn-radius-sm, 6px);
336
+ }
337
+
338
+ .stn-tabs__scroll-button:hover:not(:disabled) {
339
+ color: var(--stn-text-primary);
340
+ background-color: color-mix(in srgb, var(--stn-text-primary) 8%, transparent);
341
+ }
342
+
343
+ .stn-tabs__scroll-button:disabled {
344
+ opacity: 0.25;
345
+ cursor: not-allowed;
346
+ }
347
+
348
+ .stn-tabs__scroll-button.start {
349
+ margin-right: var(--stn-space-2, 2px);
350
+ }
351
+
352
+ .stn-tabs__scroll-button.end {
353
+ margin-left: var(--stn-space-2, 2px);
354
+ }
355
+
356
+ /* Fade Edges when scrollable */
357
+ .stn-tabs.is-scrollable.has-scroll-start .stn-tabs__scroller {
358
+ mask-image: linear-gradient(to right, transparent, black 28px, black 100%);
359
+ -webkit-mask-image: linear-gradient(to right, transparent, black 28px, black 100%);
360
+ }
361
+
362
+ .stn-tabs.is-scrollable.has-scroll-end .stn-tabs__scroller {
363
+ mask-image: linear-gradient(to left, transparent, black 28px, black 100%);
364
+ -webkit-mask-image: linear-gradient(to left, transparent, black 28px, black 100%);
365
+ }
366
+
367
+ .stn-tabs.is-scrollable.has-scroll-start.has-scroll-end .stn-tabs__scroller {
368
+ mask-image: linear-gradient(to right, transparent, black 28px, black calc(100% - 28px), transparent 100%);
369
+ -webkit-mask-image: linear-gradient(to right, transparent, black 28px, black calc(100% - 28px), transparent 100%);
370
+ }
371
+
372
+ /* ==========================================================================
373
+ 6. Tab Panel (.stn-tab-panel)
374
+ ========================================================================== */
375
+ .stn-tab-panel {
376
+ box-sizing: border-box;
377
+ width: 100%;
378
+ outline: none;
379
+ animation: stn-tab-panel-fade-in 0.2s cubic-bezier(0.2, 0, 0, 1);
380
+ }
381
+
382
+ .stn-tab-panel[hidden] {
383
+ display: none !important;
384
+ }
385
+
386
+ /* Padding Presets */
387
+ .stn-tab-panel.padding-none {
388
+ padding: 0;
389
+ }
390
+
391
+ .stn-tab-panel.padding-sm {
392
+ padding: var(--stn-space-8, 8px);
393
+ }
394
+
395
+ .stn-tab-panel.padding-md {
396
+ padding: var(--stn-space-16, 16px);
397
+ }
398
+
399
+ .stn-tab-panel.padding-lg {
400
+ padding: var(--stn-space-24, 24px);
401
+ }
402
+
403
+ @keyframes stn-tab-panel-fade-in {
404
+ from {
405
+ opacity: 0;
406
+ transform: translateY(3px);
407
+ }
408
+ to {
409
+ opacity: 1;
410
+ transform: translateY(0);
411
+ }
412
+ }
@@ -267,6 +267,17 @@
267
267
  text-overflow: ellipsis;
268
268
  }
269
269
 
270
+ /* Widget title size modifiers */
271
+ .stn-widget .stn-widget__title.sm { font-size: var(--stn-font-size-14, 14px); }
272
+ .stn-widget .stn-widget__title.md { font-size: var(--stn-font-size-16, 16px); }
273
+ .stn-widget .stn-widget__title.lg { font-size: var(--stn-font-size-18, 18px); }
274
+
275
+ /* Widget title weight modifiers */
276
+ .stn-widget .stn-widget__title.regular { font-weight: var(--stn-font-weight-regular, 400); }
277
+ .stn-widget .stn-widget__title.medium { font-weight: var(--stn-font-weight-medium, 500); }
278
+ .stn-widget .stn-widget__title.semibold { font-weight: var(--stn-font-weight-semibold, 600); }
279
+ .stn-widget .stn-widget__title.bold { font-weight: var(--stn-font-weight-bold, 700); }
280
+
270
281
  /* 다중 액션 또는 좁은 카드에서 개행을 허용한 경우 (BEM 표준: wrapActions / .stn-widget__head--wrap) */
271
282
  .stn-widget--wrap-actions .stn-widget__head,
272
283
  .stn-widget .stn-widget__head--wrap {
@@ -648,10 +659,31 @@
648
659
  background-color: var(--stn-widget-footer-well-bg);
649
660
  }
650
661
 
662
+ .stn-widget .stn-widget__body.stn-widget__body--no-scroll,
651
663
  .stn-widget__body--no-scroll {
652
664
  overflow: hidden;
653
665
  }
654
666
 
667
+ /* ==========================================================================
668
+ StnWidget Fit Dimensions (fullHeight=false / fullWidth=false)
669
+ ========================================================================== */
670
+ .stn-widget.stn-widget--fit-height {
671
+ height: auto;
672
+ flex-grow: 0;
673
+ }
674
+
675
+ .stn-widget.stn-widget--fit-height > .stn-widget__body {
676
+ height: auto;
677
+ flex: 0 0 auto;
678
+ overflow: visible;
679
+ }
680
+
681
+ .stn-widget.stn-widget--fit-width {
682
+ width: auto;
683
+ max-width: fit-content;
684
+ flex-grow: 0;
685
+ }
686
+
655
687
  /* ==========================================================================
656
688
  StnWidget Header Period Helpers
657
689
  ========================================================================== */
@@ -385,8 +385,8 @@
385
385
  justify-content: space-between !important;
386
386
  }
387
387
 
388
- /* 테이블 영역 모바일 최소 높이 보장 */
389
- .stn-layer-1__body .stn-container > .stn-stack > .stn-stack {
388
+ /* 테이블 영역 모바일 최소 높이 보장 (LNB 목록 레이아웃 전용) */
389
+ :is(.stn-layer-1:has(.stn-list-lnb), .stn-layer-1__body:has(.stn-list-lnb)) .stn-container > .stn-stack > .stn-stack {
390
390
  height: auto !important;
391
391
  min-height: var(--stn-layout-list-mobile-table-min-height);
392
392
  }
@@ -70,6 +70,7 @@
70
70
  @import './components/stn-card.css';
71
71
  @import './components/stn-topology.css';
72
72
  @import './components/stn-status.css';
73
+ @import './components/stn-tabs.css';
73
74
 
74
75
  /* --- 5. Patterns (Composite UI Recipes) --- */
75
76
  @import './patterns/stn-section-side.css';