omnira-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.
Files changed (111) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +145 -0
  3. package/cli/omnira-init.mjs +260 -0
  4. package/cli/presets.mjs +386 -0
  5. package/components/ui/AppStoreButton/AppStoreButton.module.css +87 -0
  6. package/components/ui/AppStoreButton/AppStoreButton.tsx +114 -0
  7. package/components/ui/AppStoreButton/index.ts +2 -0
  8. package/components/ui/Avatar/Avatar.module.css +76 -0
  9. package/components/ui/Avatar/Avatar.tsx +102 -0
  10. package/components/ui/Avatar/index.ts +2 -0
  11. package/components/ui/Badge/Badge.module.css +120 -0
  12. package/components/ui/Badge/Badge.tsx +25 -0
  13. package/components/ui/Badge/index.ts +2 -0
  14. package/components/ui/BadgeGroup/BadgeGroup.module.css +214 -0
  15. package/components/ui/BadgeGroup/BadgeGroup.tsx +88 -0
  16. package/components/ui/BadgeGroup/index.ts +2 -0
  17. package/components/ui/Browser/Browser.module.css +105 -0
  18. package/components/ui/Browser/Browser.tsx +54 -0
  19. package/components/ui/Browser/index.ts +2 -0
  20. package/components/ui/Button/Button.module.css +188 -0
  21. package/components/ui/Button/Button.tsx +74 -0
  22. package/components/ui/Button/index.ts +2 -0
  23. package/components/ui/ButtonUtility/ButtonUtility.module.css +154 -0
  24. package/components/ui/ButtonUtility/ButtonUtility.tsx +65 -0
  25. package/components/ui/ButtonUtility/index.ts +2 -0
  26. package/components/ui/Card/Card.module.css +80 -0
  27. package/components/ui/Card/Card.tsx +39 -0
  28. package/components/ui/Card/index.ts +2 -0
  29. package/components/ui/Checkbox/Checkbox.module.css +92 -0
  30. package/components/ui/Checkbox/Checkbox.tsx +95 -0
  31. package/components/ui/Checkbox/index.ts +2 -0
  32. package/components/ui/Collapse/Collapse.module.css +60 -0
  33. package/components/ui/Collapse/Collapse.tsx +100 -0
  34. package/components/ui/Collapse/index.ts +2 -0
  35. package/components/ui/CreditCard/CreditCard.module.css +117 -0
  36. package/components/ui/CreditCard/CreditCard.tsx +86 -0
  37. package/components/ui/CreditCard/index.ts +2 -0
  38. package/components/ui/Dropdown/Dropdown.module.css +269 -0
  39. package/components/ui/Dropdown/Dropdown.tsx +419 -0
  40. package/components/ui/Dropdown/index.ts +31 -0
  41. package/components/ui/GridLines/GridLines.module.css +95 -0
  42. package/components/ui/GridLines/GridLines.tsx +10 -0
  43. package/components/ui/GridLines/index.ts +1 -0
  44. package/components/ui/Illustration/Illustration.module.css +10 -0
  45. package/components/ui/Illustration/Illustration.tsx +96 -0
  46. package/components/ui/Illustration/index.ts +2 -0
  47. package/components/ui/Input/Input.module.css +217 -0
  48. package/components/ui/Input/Input.tsx +93 -0
  49. package/components/ui/Input/index.ts +2 -0
  50. package/components/ui/Phone/Phone.module.css +104 -0
  51. package/components/ui/Phone/Phone.tsx +54 -0
  52. package/components/ui/Phone/index.ts +2 -0
  53. package/components/ui/PinInput/PinInput.module.css +104 -0
  54. package/components/ui/PinInput/PinInput.tsx +210 -0
  55. package/components/ui/PinInput/index.ts +1 -0
  56. package/components/ui/ProgressBar/ProgressBar.module.css +180 -0
  57. package/components/ui/ProgressBar/ProgressBar.tsx +206 -0
  58. package/components/ui/ProgressBar/index.ts +2 -0
  59. package/components/ui/QRCode/QRCode.module.css +13 -0
  60. package/components/ui/QRCode/QRCode.tsx +128 -0
  61. package/components/ui/QRCode/index.ts +2 -0
  62. package/components/ui/RadioButton/RadioButton.module.css +92 -0
  63. package/components/ui/RadioButton/RadioButton.tsx +134 -0
  64. package/components/ui/RadioButton/index.ts +2 -0
  65. package/components/ui/RadioGroup/RadioGroup.module.css +382 -0
  66. package/components/ui/RadioGroup/RadioGroup.tsx +292 -0
  67. package/components/ui/RadioGroup/index.ts +1 -0
  68. package/components/ui/Rating/Rating.module.css +99 -0
  69. package/components/ui/Rating/Rating.tsx +123 -0
  70. package/components/ui/Rating/index.ts +2 -0
  71. package/components/ui/Select/Select.module.css +371 -0
  72. package/components/ui/Select/Select.tsx +507 -0
  73. package/components/ui/Select/index.ts +2 -0
  74. package/components/ui/SidebarNavigation/SidebarDual.tsx +71 -0
  75. package/components/ui/SidebarNavigation/SidebarFeatureCard.module.css +351 -0
  76. package/components/ui/SidebarNavigation/SidebarFeatureCard.tsx +388 -0
  77. package/components/ui/SidebarNavigation/SidebarNavigation.module.css +610 -0
  78. package/components/ui/SidebarNavigation/SidebarParts.tsx +215 -0
  79. package/components/ui/SidebarNavigation/SidebarSectionDividers.tsx +46 -0
  80. package/components/ui/SidebarNavigation/SidebarSectionHeadings.tsx +52 -0
  81. package/components/ui/SidebarNavigation/SidebarSimple.tsx +46 -0
  82. package/components/ui/SidebarNavigation/SidebarSlim.tsx +48 -0
  83. package/components/ui/SidebarNavigation/index.ts +29 -0
  84. package/components/ui/SidebarNavigation/types.ts +27 -0
  85. package/components/ui/Slider/Slider.module.css +93 -0
  86. package/components/ui/Slider/Slider.tsx +118 -0
  87. package/components/ui/Slider/index.ts +2 -0
  88. package/components/ui/SocialButton/SocialButton.module.css +223 -0
  89. package/components/ui/SocialButton/SocialButton.tsx +185 -0
  90. package/components/ui/SocialButton/index.ts +2 -0
  91. package/components/ui/Tag/Tag.module.css +203 -0
  92. package/components/ui/Tag/Tag.tsx +161 -0
  93. package/components/ui/Tag/index.ts +2 -0
  94. package/components/ui/TextEditor/TextEditor.module.css +182 -0
  95. package/components/ui/TextEditor/TextEditor.tsx +323 -0
  96. package/components/ui/TextEditor/index.ts +1 -0
  97. package/components/ui/Textarea/Textarea.module.css +75 -0
  98. package/components/ui/Textarea/Textarea.tsx +59 -0
  99. package/components/ui/Textarea/index.ts +2 -0
  100. package/components/ui/Toggle/Toggle.module.css +118 -0
  101. package/components/ui/Toggle/Toggle.tsx +77 -0
  102. package/components/ui/Toggle/index.ts +2 -0
  103. package/components/ui/Tooltip/Tooltip.module.css +95 -0
  104. package/components/ui/Tooltip/Tooltip.tsx +55 -0
  105. package/components/ui/Tooltip/index.ts +2 -0
  106. package/components/ui/VideoPlayer/VideoPlayer.module.css +120 -0
  107. package/components/ui/VideoPlayer/VideoPlayer.tsx +229 -0
  108. package/components/ui/VideoPlayer/index.ts +2 -0
  109. package/lib/cn.ts +3 -0
  110. package/lib/copy-to-clipboard.ts +21 -0
  111. package/package.json +61 -0
@@ -0,0 +1,99 @@
1
+ /* ══════════════════════════════════════
2
+ Rating (interactive)
3
+ ══════════════════════════════════════ */
4
+
5
+ .rating {
6
+ display: inline-flex;
7
+ align-items: center;
8
+ gap: 2px;
9
+ }
10
+
11
+ .readOnly {
12
+ pointer-events: none;
13
+ }
14
+
15
+ .star {
16
+ display: flex;
17
+ align-items: center;
18
+ justify-content: center;
19
+ background: none;
20
+ border: none;
21
+ padding: 2px;
22
+ cursor: pointer;
23
+ color: var(--color-border-medium);
24
+ transition: color 0.15s, transform 0.15s;
25
+ border-radius: var(--radius-sm);
26
+ }
27
+
28
+ .star:hover {
29
+ transform: scale(1.15);
30
+ }
31
+
32
+ .starFilled {
33
+ color: #f59e0b;
34
+ }
35
+
36
+ .starSvg {
37
+ display: block;
38
+ }
39
+
40
+ /* ── Sizes ── */
41
+ .rating_sm .starSvg { width: 16px; height: 16px; }
42
+ .rating_md .starSvg { width: 22px; height: 22px; }
43
+ .rating_lg .starSvg { width: 28px; height: 28px; }
44
+
45
+ /* ══════════════════════════════════════
46
+ Rating Badge
47
+ ══════════════════════════════════════ */
48
+
49
+ .badge {
50
+ display: inline-flex;
51
+ align-items: center;
52
+ gap: 8px;
53
+ padding: 6px 12px;
54
+ border-radius: var(--radius-full);
55
+ background: var(--color-bg-card);
56
+ border: 1px solid var(--color-border-standard);
57
+ backdrop-filter: var(--blur-standard);
58
+ }
59
+
60
+ .badgeStars {
61
+ display: flex;
62
+ align-items: center;
63
+ gap: 1px;
64
+ }
65
+
66
+ .badgeStar {
67
+ display: flex;
68
+ color: var(--color-border-medium);
69
+ }
70
+
71
+ .badgeStarFilled {
72
+ color: #f59e0b;
73
+ }
74
+
75
+ .badgeValue {
76
+ font-weight: 700;
77
+ color: var(--color-text-primary);
78
+ font-family: var(--font-display);
79
+ }
80
+
81
+ .badgeCount {
82
+ font-weight: 500;
83
+ color: var(--color-text-tertiary);
84
+ }
85
+
86
+ /* ── Badge sizes ── */
87
+ .badge_sm .badgeStar svg { width: 12px; height: 12px; }
88
+ .badge_sm .badgeValue { font-size: 12px; }
89
+ .badge_sm .badgeCount { font-size: 11px; }
90
+ .badge_sm { padding: 4px 10px; gap: 6px; }
91
+
92
+ .badge_md .badgeStar svg { width: 16px; height: 16px; }
93
+ .badge_md .badgeValue { font-size: 14px; }
94
+ .badge_md .badgeCount { font-size: 13px; }
95
+
96
+ .badge_lg .badgeStar svg { width: 20px; height: 20px; }
97
+ .badge_lg .badgeValue { font-size: 16px; }
98
+ .badge_lg .badgeCount { font-size: 14px; }
99
+ .badge_lg { padding: 8px 16px; gap: 10px; }
@@ -0,0 +1,123 @@
1
+ "use client";
2
+
3
+ import { useState, useCallback, forwardRef } from "react";
4
+ import { cn } from "@/lib/cn";
5
+ import styles from "./Rating.module.css";
6
+
7
+ /* ══════════════════════════════════════
8
+ Rating (interactive stars)
9
+ ══════════════════════════════════════ */
10
+ export interface RatingProps {
11
+ value?: number;
12
+ defaultValue?: number;
13
+ max?: number;
14
+ onChange?: (value: number) => void;
15
+ size?: "sm" | "md" | "lg";
16
+ readOnly?: boolean;
17
+ className?: string;
18
+ }
19
+
20
+ export const Rating = forwardRef<HTMLDivElement, RatingProps>(
21
+ (
22
+ {
23
+ value: controlledValue,
24
+ defaultValue = 0,
25
+ max = 5,
26
+ onChange,
27
+ size = "md",
28
+ readOnly = false,
29
+ className,
30
+ },
31
+ ref,
32
+ ) => {
33
+ const isControlled = controlledValue !== undefined;
34
+ const [internalValue, setInternalValue] = useState(defaultValue);
35
+ const [hoverValue, setHoverValue] = useState(0);
36
+ const value = isControlled ? controlledValue : internalValue;
37
+ const displayValue = hoverValue || value;
38
+
39
+ const handleClick = useCallback(
40
+ (star: number) => {
41
+ if (readOnly) return;
42
+ const newVal = star === value ? 0 : star;
43
+ if (!isControlled) setInternalValue(newVal);
44
+ onChange?.(newVal);
45
+ },
46
+ [readOnly, value, isControlled, onChange],
47
+ );
48
+
49
+ return (
50
+ <div
51
+ ref={ref}
52
+ className={cn(styles.rating, styles[`rating_${size}`], readOnly && styles.readOnly, className)}
53
+ role="radiogroup"
54
+ aria-label="Rating"
55
+ >
56
+ {Array.from({ length: max }, (_, i) => {
57
+ const star = i + 1;
58
+ const filled = star <= displayValue;
59
+ return (
60
+ <button
61
+ key={star}
62
+ type="button"
63
+ className={cn(styles.star, filled && styles.starFilled)}
64
+ onClick={() => handleClick(star)}
65
+ onMouseEnter={() => !readOnly && setHoverValue(star)}
66
+ onMouseLeave={() => !readOnly && setHoverValue(0)}
67
+ aria-label={`${star} star${star > 1 ? "s" : ""}`}
68
+ tabIndex={readOnly ? -1 : 0}
69
+ >
70
+ <StarIcon />
71
+ </button>
72
+ );
73
+ })}
74
+ </div>
75
+ );
76
+ },
77
+ );
78
+
79
+ Rating.displayName = "Rating";
80
+
81
+ /* ══════════════════════════════════════
82
+ Rating Badge
83
+ ══════════════════════════════════════ */
84
+ export interface RatingBadgeProps {
85
+ value: number;
86
+ max?: number;
87
+ count?: number;
88
+ size?: "sm" | "md" | "lg";
89
+ className?: string;
90
+ }
91
+
92
+ export function RatingBadge({
93
+ value,
94
+ max = 5,
95
+ count,
96
+ size = "md",
97
+ className,
98
+ }: RatingBadgeProps) {
99
+ return (
100
+ <div className={cn(styles.badge, styles[`badge_${size}`], className)}>
101
+ <div className={styles.badgeStars}>
102
+ {Array.from({ length: max }, (_, i) => (
103
+ <span key={i} className={cn(styles.badgeStar, i < Math.round(value) && styles.badgeStarFilled)}>
104
+ <StarIcon />
105
+ </span>
106
+ ))}
107
+ </div>
108
+ <span className={styles.badgeValue}>{value.toFixed(1)}</span>
109
+ {count !== undefined && (
110
+ <span className={styles.badgeCount}>({count})</span>
111
+ )}
112
+ </div>
113
+ );
114
+ }
115
+
116
+ /* ── Star SVG ── */
117
+ function StarIcon() {
118
+ return (
119
+ <svg viewBox="0 0 20 20" fill="currentColor" className={styles.starSvg}>
120
+ <path d="M10 1.5L12.47 7.03L18.5 7.72L13.97 11.67L15.35 17.5L10 14.27L4.65 17.5L6.03 11.67L1.5 7.72L7.53 7.03L10 1.5Z" />
121
+ </svg>
122
+ );
123
+ }
@@ -0,0 +1,2 @@
1
+ export { Rating, RatingBadge } from "./Rating";
2
+ export type { RatingProps, RatingBadgeProps } from "./Rating";
@@ -0,0 +1,371 @@
1
+ /* ── Wrapper ── */
2
+ .wrapper {
3
+ display: flex;
4
+ flex-direction: column;
5
+ gap: 6px;
6
+ width: 100%;
7
+ position: relative;
8
+ }
9
+
10
+ /* ── Label ── */
11
+ .label {
12
+ font-size: 12px;
13
+ font-weight: 600;
14
+ text-transform: uppercase;
15
+ letter-spacing: 0.06em;
16
+ color: var(--color-text-tertiary);
17
+ }
18
+
19
+ .required {
20
+ color: var(--color-error);
21
+ margin-left: 2px;
22
+ }
23
+
24
+ /* ── Trigger ── */
25
+ .trigger {
26
+ display: flex;
27
+ align-items: center;
28
+ justify-content: space-between;
29
+ gap: 8px;
30
+ width: 100%;
31
+ padding: 0 14px;
32
+ border-radius: var(--radius-md);
33
+ background: var(--color-bg-input);
34
+ border: 1px solid var(--color-border-standard);
35
+ font-family: inherit;
36
+ color: var(--color-text-primary);
37
+ cursor: pointer;
38
+ transition: all 0.25s;
39
+ outline: none;
40
+ text-align: left;
41
+ position: relative;
42
+ }
43
+
44
+ .trigger:hover {
45
+ border-color: var(--color-border-medium);
46
+ }
47
+
48
+ .triggerOpen {
49
+ border-color: var(--color-border-lime-strong);
50
+ background: var(--color-bg-elevated);
51
+ }
52
+
53
+ .triggerError {
54
+ border-color: var(--color-error-border);
55
+ }
56
+
57
+ .triggerError.triggerOpen {
58
+ border-color: var(--color-error);
59
+ }
60
+
61
+ .triggerDisabled {
62
+ opacity: 0.5;
63
+ cursor: not-allowed;
64
+ pointer-events: none;
65
+ }
66
+
67
+ /* ── Trigger Sizes ── */
68
+ .sm {
69
+ height: 36px;
70
+ font-size: 13px;
71
+ padding: 0 12px;
72
+ }
73
+
74
+ .md {
75
+ height: 44px;
76
+ font-size: 14px;
77
+ }
78
+
79
+ .lg {
80
+ height: 52px;
81
+ font-size: 16px;
82
+ padding: 0 16px;
83
+ }
84
+
85
+ /* ── Tags trigger ── */
86
+ .triggerTags {
87
+ height: auto;
88
+ min-height: 44px;
89
+ padding: 6px 14px;
90
+ flex-wrap: wrap;
91
+ }
92
+
93
+ .triggerTags.sm {
94
+ min-height: 36px;
95
+ padding: 4px 12px;
96
+ }
97
+
98
+ .triggerTags.lg {
99
+ min-height: 52px;
100
+ padding: 8px 16px;
101
+ }
102
+
103
+ /* ── Trigger Value ── */
104
+ .triggerValue {
105
+ flex: 1;
106
+ min-width: 0;
107
+ overflow: hidden;
108
+ }
109
+
110
+ /* ── Placeholder ── */
111
+ .placeholder {
112
+ display: flex;
113
+ align-items: center;
114
+ gap: 8px;
115
+ color: var(--color-text-tertiary);
116
+ opacity: 0.6;
117
+ font-weight: 400;
118
+ }
119
+
120
+ .placeholderIcon {
121
+ display: flex;
122
+ align-items: center;
123
+ flex-shrink: 0;
124
+ }
125
+
126
+ /* ── Chevron ── */
127
+ .chevron {
128
+ flex-shrink: 0;
129
+ transition: transform 0.2s;
130
+ }
131
+
132
+ .chevronOpen {
133
+ transform: rotate(180deg);
134
+ }
135
+
136
+ /* ── Listbox ── */
137
+ .listbox {
138
+ position: absolute;
139
+ top: 100%;
140
+ left: 0;
141
+ right: 0;
142
+ z-index: 100;
143
+ margin-top: 6px;
144
+ padding: 6px;
145
+ border-radius: var(--radius-xl);
146
+ background: var(--color-bg-card);
147
+ border: 1.5px solid var(--color-border-standard);
148
+ box-shadow: var(--shadow-card);
149
+ max-height: 280px;
150
+ overflow-y: auto;
151
+ display: flex;
152
+ flex-direction: column;
153
+ gap: 2px;
154
+ animation: selectIn 0.15s ease-out;
155
+ }
156
+
157
+ @keyframes selectIn {
158
+ from {
159
+ opacity: 0;
160
+ transform: translateY(-4px);
161
+ }
162
+ to {
163
+ opacity: 1;
164
+ transform: translateY(0);
165
+ }
166
+ }
167
+
168
+ /* ── Search Box ── */
169
+ .searchBox {
170
+ display: flex;
171
+ align-items: center;
172
+ gap: 8px;
173
+ padding: 8px 10px;
174
+ border-bottom: 1px solid var(--color-border-subtle);
175
+ margin-bottom: 4px;
176
+ }
177
+
178
+ .searchInput {
179
+ flex: 1;
180
+ background: none;
181
+ border: none;
182
+ outline: none;
183
+ font-family: inherit;
184
+ font-size: 13px;
185
+ color: var(--color-text-primary);
186
+ }
187
+
188
+ .searchInput::placeholder {
189
+ color: var(--color-text-tertiary);
190
+ opacity: 0.5;
191
+ }
192
+
193
+ /* ── No Results ── */
194
+ .noResults {
195
+ padding: 12px;
196
+ text-align: center;
197
+ font-size: 13px;
198
+ color: var(--color-text-tertiary);
199
+ }
200
+
201
+ /* ── Option ── */
202
+ .option {
203
+ display: flex;
204
+ align-items: center;
205
+ justify-content: space-between;
206
+ gap: 10px;
207
+ width: 100%;
208
+ padding: 8px 10px;
209
+ border: none;
210
+ border-radius: var(--radius-md);
211
+ background: transparent;
212
+ color: var(--color-text-primary);
213
+ font-size: 13px;
214
+ font-weight: 500;
215
+ font-family: inherit;
216
+ cursor: pointer;
217
+ transition: all 0.15s;
218
+ text-align: left;
219
+ white-space: nowrap;
220
+ }
221
+
222
+ .option:hover {
223
+ background: var(--color-bg-hover);
224
+ }
225
+
226
+ .optionSelected {
227
+ background: var(--color-bg-lime-subtle);
228
+ }
229
+
230
+ .optionSelected:hover {
231
+ background: var(--color-bg-lime-medium);
232
+ }
233
+
234
+ .optionDisabled {
235
+ opacity: 0.4;
236
+ cursor: not-allowed;
237
+ pointer-events: none;
238
+ }
239
+
240
+ /* ── Item Content ── */
241
+ .itemContent {
242
+ display: flex;
243
+ align-items: center;
244
+ gap: 10px;
245
+ min-width: 0;
246
+ flex: 1;
247
+ }
248
+
249
+ .itemText {
250
+ display: flex;
251
+ align-items: center;
252
+ gap: 8px;
253
+ min-width: 0;
254
+ }
255
+
256
+ .itemLabel {
257
+ font-weight: 500;
258
+ white-space: nowrap;
259
+ overflow: hidden;
260
+ text-overflow: ellipsis;
261
+ }
262
+
263
+ .itemSupporting {
264
+ font-size: 12px;
265
+ color: var(--color-text-tertiary);
266
+ white-space: nowrap;
267
+ }
268
+
269
+ .itemIcon {
270
+ display: flex;
271
+ align-items: center;
272
+ justify-content: center;
273
+ flex-shrink: 0;
274
+ width: 18px;
275
+ height: 18px;
276
+ color: var(--color-text-tertiary);
277
+ }
278
+
279
+ /* ── Avatar ── */
280
+ .avatar {
281
+ width: 24px;
282
+ height: 24px;
283
+ border-radius: 50%;
284
+ object-fit: cover;
285
+ flex-shrink: 0;
286
+ border: 1px solid var(--color-border-subtle);
287
+ }
288
+
289
+ /* ── Dot ── */
290
+ .dot {
291
+ width: 8px;
292
+ height: 8px;
293
+ border-radius: 50%;
294
+ background: var(--color-success);
295
+ flex-shrink: 0;
296
+ }
297
+
298
+ /* ── Tags Container ── */
299
+ .tagsContainer {
300
+ display: flex;
301
+ flex-wrap: wrap;
302
+ gap: 6px;
303
+ flex: 1;
304
+ align-items: center;
305
+ min-width: 0;
306
+ }
307
+
308
+ /* ── Tag Chip ── */
309
+ .tagChip {
310
+ display: inline-flex;
311
+ align-items: center;
312
+ gap: 4px;
313
+ padding: 2px 8px;
314
+ border-radius: var(--radius-full);
315
+ background: var(--color-bg-elevated);
316
+ border: 1px solid var(--color-border-subtle);
317
+ font-size: 12px;
318
+ font-weight: 500;
319
+ color: var(--color-text-primary);
320
+ white-space: nowrap;
321
+ line-height: 1.4;
322
+ }
323
+
324
+ .tagChipAvatar {
325
+ width: 16px;
326
+ height: 16px;
327
+ border-radius: 50%;
328
+ object-fit: cover;
329
+ margin-left: -2px;
330
+ }
331
+
332
+ .tagChipRemove {
333
+ display: flex;
334
+ align-items: center;
335
+ background: none;
336
+ border: none;
337
+ padding: 0;
338
+ cursor: pointer;
339
+ color: var(--color-text-tertiary);
340
+ transition: color 0.15s;
341
+ line-height: 1;
342
+ }
343
+
344
+ .tagChipRemove:hover {
345
+ color: var(--color-text-primary);
346
+ }
347
+
348
+ /* ── Hint / Error ── */
349
+ .hint {
350
+ font-size: 12px;
351
+ color: var(--color-text-tertiary);
352
+ }
353
+
354
+ .errorText {
355
+ font-size: 12px;
356
+ color: var(--color-error);
357
+ }
358
+
359
+ /* ── Scrollbar ── */
360
+ .listbox::-webkit-scrollbar {
361
+ width: 4px;
362
+ }
363
+
364
+ .listbox::-webkit-scrollbar-track {
365
+ background: transparent;
366
+ }
367
+
368
+ .listbox::-webkit-scrollbar-thumb {
369
+ background: var(--color-border-medium);
370
+ border-radius: 4px;
371
+ }