maquina-components 0.5.0 → 0.6.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 (149) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +79 -3
  3. data/app/assets/stylesheets/alert.css +169 -135
  4. data/app/assets/stylesheets/badge.css +143 -138
  5. data/app/assets/stylesheets/breadcrumbs.css +185 -147
  6. data/app/assets/stylesheets/calendar.css +219 -206
  7. data/app/assets/stylesheets/card.css +126 -120
  8. data/app/assets/stylesheets/combobox.css +215 -163
  9. data/app/assets/stylesheets/date_picker.css +144 -134
  10. data/app/assets/stylesheets/drawer.css +166 -118
  11. data/app/assets/stylesheets/dropdown_menu.css +203 -190
  12. data/app/assets/stylesheets/empty.css +125 -117
  13. data/app/assets/stylesheets/form.css +625 -525
  14. data/app/assets/stylesheets/header.css +63 -47
  15. data/app/assets/stylesheets/menu_button.css +178 -0
  16. data/app/assets/stylesheets/pagination.css +130 -125
  17. data/app/assets/stylesheets/separator.css +32 -0
  18. data/app/assets/stylesheets/sidebar.css +448 -390
  19. data/app/assets/stylesheets/stats.css +111 -0
  20. data/app/assets/stylesheets/table.css +184 -166
  21. data/app/assets/stylesheets/toast.css +287 -278
  22. data/app/assets/stylesheets/toggle_group.css +132 -139
  23. data/app/assets/tailwind/maquina_components_engine/engine.css +54 -12
  24. data/app/assets/tailwind/maquina_components_engine/tokens.css +101 -0
  25. data/app/helpers/maquina_components/combobox_helper.rb +34 -25
  26. data/app/helpers/maquina_components/components_helper.rb +57 -0
  27. data/app/helpers/maquina_components/dropdown_menu_helper.rb +12 -12
  28. data/app/helpers/maquina_components/icons_helper.rb +84 -2
  29. data/app/javascript/controllers/breadcrumb_controller.js +39 -30
  30. data/app/javascript/controllers/combobox_controller.js +9 -0
  31. data/app/javascript/controllers/drawer_controller.js +43 -9
  32. data/app/javascript/controllers/drawer_trigger_controller.js +55 -4
  33. data/app/javascript/controllers/menu_button_controller.js +107 -29
  34. data/app/javascript/controllers/sidebar_controller.js +6 -8
  35. data/app/javascript/controllers/sidebar_trigger_controller.js +33 -4
  36. data/app/javascript/controllers/toaster_controller.js +12 -0
  37. data/app/views/components/_alert.html.erb +3 -1
  38. data/app/views/components/_badge.html.erb +7 -1
  39. data/app/views/components/_breadcrumbs.html.erb +1 -1
  40. data/app/views/components/_calendar.html.erb +1 -1
  41. data/app/views/components/_card.html.erb +1 -1
  42. data/app/views/components/_combobox.html.erb +3 -2
  43. data/app/views/components/_date_picker.html.erb +4 -3
  44. data/app/views/components/_drawer.html.erb +8 -2
  45. data/app/views/components/_dropdown.html.erb +21 -24
  46. data/app/views/components/_dropdown_menu.html.erb +1 -1
  47. data/app/views/components/_empty.html.erb +1 -1
  48. data/app/views/components/_header.html.erb +1 -1
  49. data/app/views/components/_label.html.erb +14 -0
  50. data/app/views/components/_menu_button.html.erb +29 -34
  51. data/app/views/components/_pagination.html.erb +1 -1
  52. data/app/views/components/_separator.html.erb +9 -10
  53. data/app/views/components/_sidebar.html.erb +1 -1
  54. data/app/views/components/_simple_table.html.erb +3 -1
  55. data/app/views/components/_table.html.erb +3 -3
  56. data/app/views/components/_toast.html.erb +6 -1
  57. data/app/views/components/_toaster.html.erb +1 -1
  58. data/app/views/components/_toggle_group.html.erb +1 -1
  59. data/app/views/components/alert/_description.html.erb +1 -1
  60. data/app/views/components/alert/_title.html.erb +1 -1
  61. data/app/views/components/breadcrumbs/_ellipsis.html.erb +1 -1
  62. data/app/views/components/breadcrumbs/_item.html.erb +1 -1
  63. data/app/views/components/breadcrumbs/_link.html.erb +1 -1
  64. data/app/views/components/breadcrumbs/_list.html.erb +1 -1
  65. data/app/views/components/breadcrumbs/_page.html.erb +1 -1
  66. data/app/views/components/breadcrumbs/_separator.html.erb +1 -1
  67. data/app/views/components/calendar/_header.html.erb +1 -1
  68. data/app/views/components/calendar/_week.html.erb +5 -13
  69. data/app/views/components/card/_action.html.erb +1 -1
  70. data/app/views/components/card/_content.html.erb +1 -1
  71. data/app/views/components/card/_description.html.erb +1 -1
  72. data/app/views/components/card/_footer.html.erb +1 -1
  73. data/app/views/components/card/_header.html.erb +1 -1
  74. data/app/views/components/card/_title.html.erb +1 -1
  75. data/app/views/components/combobox/_content.html.erb +1 -1
  76. data/app/views/components/combobox/_empty.html.erb +3 -3
  77. data/app/views/components/combobox/_group.html.erb +1 -1
  78. data/app/views/components/combobox/_input.html.erb +1 -1
  79. data/app/views/components/combobox/_label.html.erb +1 -1
  80. data/app/views/components/combobox/_list.html.erb +1 -1
  81. data/app/views/components/combobox/_option.html.erb +1 -1
  82. data/app/views/components/combobox/_separator.html.erb +1 -1
  83. data/app/views/components/combobox/_trigger.html.erb +1 -1
  84. data/app/views/components/drawer/_close.html.erb +2 -2
  85. data/app/views/components/drawer/_content.html.erb +1 -1
  86. data/app/views/components/drawer/_description.html.erb +6 -0
  87. data/app/views/components/drawer/_footer.html.erb +1 -1
  88. data/app/views/components/drawer/_header.html.erb +3 -3
  89. data/app/views/components/drawer/_provider.html.erb +14 -5
  90. data/app/views/components/drawer/_section.html.erb +7 -0
  91. data/app/views/components/drawer/_separator.html.erb +11 -0
  92. data/app/views/components/drawer/_title.html.erb +6 -0
  93. data/app/views/components/drawer/_trigger.html.erb +24 -7
  94. data/app/views/components/dropdown_menu/_content.html.erb +1 -1
  95. data/app/views/components/dropdown_menu/_group.html.erb +1 -1
  96. data/app/views/components/dropdown_menu/_item.html.erb +1 -1
  97. data/app/views/components/dropdown_menu/_label.html.erb +3 -7
  98. data/app/views/components/dropdown_menu/_separator.html.erb +1 -1
  99. data/app/views/components/dropdown_menu/_shortcut.html.erb +3 -7
  100. data/app/views/components/dropdown_menu/_trigger.html.erb +1 -1
  101. data/app/views/components/empty/_content.html.erb +1 -1
  102. data/app/views/components/empty/_description.html.erb +3 -7
  103. data/app/views/components/empty/_header.html.erb +1 -1
  104. data/app/views/components/empty/_media.html.erb +5 -3
  105. data/app/views/components/empty/_title.html.erb +3 -7
  106. data/app/views/components/pagination/_content.html.erb +1 -1
  107. data/app/views/components/pagination/_item.html.erb +1 -1
  108. data/app/views/components/pagination/_link.html.erb +1 -1
  109. data/app/views/components/pagination/_next.html.erb +1 -1
  110. data/app/views/components/pagination/_previous.html.erb +1 -1
  111. data/app/views/components/sidebar/_content.html.erb +1 -1
  112. data/app/views/components/sidebar/_footer.html.erb +1 -1
  113. data/app/views/components/sidebar/_group.html.erb +1 -1
  114. data/app/views/components/sidebar/_group_action.html.erb +26 -0
  115. data/app/views/components/sidebar/_header.html.erb +1 -1
  116. data/app/views/components/sidebar/_inset.html.erb +1 -1
  117. data/app/views/components/sidebar/_menu.html.erb +1 -1
  118. data/app/views/components/sidebar/_menu_action.html.erb +28 -0
  119. data/app/views/components/sidebar/_menu_badge.html.erb +10 -0
  120. data/app/views/components/sidebar/_menu_button.html.erb +4 -3
  121. data/app/views/components/sidebar/_menu_item.html.erb +1 -1
  122. data/app/views/components/sidebar/_menu_link.html.erb +7 -9
  123. data/app/views/components/sidebar/_provider.html.erb +1 -1
  124. data/app/views/components/sidebar/_separator.html.erb +12 -0
  125. data/app/views/components/sidebar/_trigger.html.erb +1 -1
  126. data/app/views/components/stats/_stats_card.html.erb +32 -92
  127. data/app/views/components/stats/_stats_grid.html.erb +18 -24
  128. data/app/views/components/table/_body.html.erb +1 -1
  129. data/app/views/components/table/_caption.html.erb +3 -3
  130. data/app/views/components/table/_cell.html.erb +3 -3
  131. data/app/views/components/table/_footer.html.erb +1 -1
  132. data/app/views/components/table/_head.html.erb +3 -3
  133. data/app/views/components/table/_header.html.erb +1 -1
  134. data/app/views/components/table/_row.html.erb +1 -1
  135. data/app/views/components/toast/_action.html.erb +1 -1
  136. data/app/views/components/toast/_description.html.erb +1 -1
  137. data/app/views/components/toast/_title.html.erb +1 -1
  138. data/app/views/components/toggle_group/_item.html.erb +1 -1
  139. data/lib/generators/maquina_components/install/install_generator.rb +36 -1
  140. data/lib/generators/maquina_components/install/templates/maquina_components_helper.rb.tt +6 -0
  141. data/lib/generators/maquina_components/install/templates/shape_state_tokens.css.tt +76 -0
  142. data/lib/generators/maquina_components/install/templates/theme.css.tt +10 -3
  143. data/lib/maquina-components.rb +34 -1
  144. data/lib/maquina_components/doctor.rb +280 -0
  145. data/lib/maquina_components/engine.rb +7 -3
  146. data/lib/maquina_components/version.rb +1 -1
  147. data/lib/tasks/maquina_components_tasks.rake +16 -4
  148. metadata +46 -3
  149. data/app/assets/stylesheets/maquina_components.css +0 -178
@@ -16,203 +16,255 @@
16
16
  * - label (section heading)
17
17
  * - separator (divider)
18
18
  * - empty (no results message)
19
+ *
20
+ * Cascade order in this file (full contract documented in form.css):
21
+ * 1. base [data-component="combobox"], [data-combobox-part="…"]
22
+ * 2. sizes [data-combobox-part="content"]:where([data-width="…"])
23
+ * 3. variants :where([data-align="…"], [data-has-value="false"])
24
+ * 4. states […]:where(:hover, :focus, [data-selected], [aria-disabled], [hidden])
25
+ * 5. dark — none; dark-mode differences are tokens (see tokens.css)
26
+ * Every rule is flattened to 0,1,0 with :where() and lives in
27
+ * @layer components, so a caller's utility class wins and source order is
28
+ * the only tie-breaker. (Rules whose target is a bare element read 0,1,1 — an
29
+ * element selector cannot be zeroed away.) @keyframes sit outside the layer:
30
+ * they take no part in the cascade.
31
+ *
32
+ * The trigger carries data-component="button" (it is where the trigger's
33
+ * justify-content and min-width have to beat the button base), so this file
34
+ * must be imported after form.css. See engine.css.
19
35
  */
20
36
 
21
- /* ===== Root Container ===== */
22
- [data-component="combobox"] {
23
- position: relative;
24
- display: inline-block;
25
- }
37
+ @layer components {
38
+ /* ===== Root Container ===== */
39
+ [data-component="combobox"] {
40
+ position: relative;
41
+ display: inline-block;
42
+ }
26
43
 
27
- /* ===== Trigger Button ===== */
28
- /* Trigger uses button component styles via data-component="button" */
29
- [data-combobox-part="trigger"] {
30
- @apply justify-between gap-2;
31
- min-width: 200px;
32
- }
44
+ /* ===== Trigger Button ===== */
45
+ /* Trigger uses button component styles via data-component="button" */
46
+ [data-combobox-part="trigger"] {
47
+ @apply justify-between gap-2;
48
+ min-width: 200px;
49
+ }
33
50
 
34
- [data-combobox-part="trigger"] [data-combobox-target="label"] {
35
- @apply truncate text-left flex-1;
36
- }
51
+ :where([data-combobox-part="trigger"]) [data-combobox-target="label"] {
52
+ @apply truncate text-left flex-1;
53
+ }
37
54
 
38
- /* Placeholder state */
39
- [data-combobox-part="trigger"][data-has-value="false"] [data-combobox-target="label"] {
40
- color: var(--muted-foreground);
41
- }
55
+ /* Icon styling */
56
+ :where([data-combobox-part="trigger"]) > svg {
57
+ @apply size-4 shrink-0 opacity-50;
58
+ }
42
59
 
43
- /* Icon styling */
44
- [data-combobox-part="trigger"] > svg {
45
- @apply size-4 shrink-0 opacity-50;
46
- }
60
+ /* Placeholder state */
61
+ :where([data-combobox-part="trigger"][data-has-value="false"]) [data-combobox-target="label"] {
62
+ color: var(--muted-foreground);
63
+ }
47
64
 
48
- /* ===== Content (Popover) ===== */
49
- [data-combobox-part="content"] {
50
- background-color: var(--popover, var(--background));
51
- color: var(--popover-foreground, var(--foreground));
52
- border-color: var(--border);
53
- @apply rounded-md border p-0 shadow-md outline-none;
54
- @apply min-w-[200px];
55
-
56
- /* Reset popover defaults - positioning handled by JS */
57
- margin: 0;
58
- padding: 0;
59
- inset: unset;
60
- }
65
+ /* ===== Content (Popover) ===== */
66
+ [data-combobox-part="content"] {
67
+ background-color: var(--popover, var(--background));
68
+ color: var(--popover-foreground, var(--foreground));
69
+ border-color: var(--border);
70
+ @apply border p-0 outline-none;
71
+ border-radius: var(--combobox-radius, var(--surface-radius, 0.5rem));
72
+ box-shadow: var(--combobox-shadow, var(--elevation-overlay, var(--shadow-md, 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1))));
73
+ @apply min-w-[200px];
74
+
75
+ /* Reset popover defaults - positioning below (anchor CSS) or in JS fallback */
76
+ margin: 0;
77
+ padding: 0;
78
+ inset: unset;
79
+ }
61
80
 
62
- /* Width variants */
63
- [data-combobox-part="content"][data-width="sm"] {
64
- @apply w-40;
65
- }
81
+ /* ===== Anchor Positioning (modern browsers) ===== */
82
+ /* Places the top-layer popover declaratively; combobox_controller skips its
83
+ measured fallback when these features are supported. flip-block flips the
84
+ popover above the trigger when there is no room below — something the JS
85
+ fallback never did. */
86
+ @supports (anchor-name: --a) and (position-area: block-end) {
87
+ [data-combobox-part="trigger"] {
88
+ anchor-name: --maquina-combobox;
89
+ }
90
+
91
+ [data-combobox-part="content"] {
92
+ position: fixed;
93
+ position-anchor: --maquina-combobox;
94
+ margin-block-start: 4px;
95
+ position-try-fallbacks: flip-block;
96
+ }
97
+
98
+ [data-combobox-part="content"]:where([data-align="start"]) {
99
+ position-area: block-end span-inline-end;
100
+ }
101
+
102
+ [data-combobox-part="content"]:where([data-align="center"]) {
103
+ position-area: block-end;
104
+ }
105
+
106
+ [data-combobox-part="content"]:where([data-align="end"]) {
107
+ position-area: block-end span-inline-start;
108
+ }
109
+
110
+ [data-combobox-part="content"]:where([data-width="default"]) {
111
+ width: auto;
112
+ min-width: max(200px, anchor-size(inline));
113
+ }
114
+ }
66
115
 
67
- [data-combobox-part="content"][data-width="default"] {
68
- @apply w-[200px];
69
- }
116
+ /* Width variants */
117
+ [data-combobox-part="content"]:where([data-width="sm"]) {
118
+ @apply w-40;
119
+ }
70
120
 
71
- [data-combobox-part="content"][data-width="md"] {
72
- @apply w-56;
73
- }
121
+ [data-combobox-part="content"]:where([data-width="default"]) {
122
+ @apply w-[200px];
123
+ }
74
124
 
75
- [data-combobox-part="content"][data-width="lg"] {
76
- @apply w-72;
77
- }
125
+ [data-combobox-part="content"]:where([data-width="md"]) {
126
+ @apply w-56;
127
+ }
78
128
 
79
- [data-combobox-part="content"][data-width="full"] {
80
- @apply w-full;
81
- }
129
+ [data-combobox-part="content"]:where([data-width="lg"]) {
130
+ @apply w-72;
131
+ }
82
132
 
83
- /* Alignment is handled by JavaScript for proper popover positioning */
133
+ [data-combobox-part="content"]:where([data-width="full"]) {
134
+ @apply w-full;
135
+ }
84
136
 
85
- /* Animation */
86
- [data-combobox-part="content"]:popover-open {
87
- animation: combobox-in 150ms ease-out;
88
- }
137
+ /* Animation */
138
+ [data-combobox-part="content"]:where(:popover-open) {
139
+ animation: combobox-in 150ms ease-out;
140
+ }
89
141
 
90
- @keyframes combobox-in {
91
- from {
92
- opacity: 0;
93
- transform: scale(0.95) translateY(-4px);
142
+ /* ===== Search Input ===== */
143
+ [data-combobox-part="input-wrapper"] {
144
+ display: flex;
145
+ align-items: center;
146
+ border-bottom: 1px solid var(--border);
147
+ @apply px-3 gap-2;
94
148
  }
95
- to {
96
- opacity: 1;
97
- transform: scale(1) translateY(0);
149
+
150
+ :where([data-combobox-part="input-wrapper"]) > svg {
151
+ @apply size-4 shrink-0 opacity-50;
98
152
  }
99
- }
100
153
 
101
- /* ===== Search Input ===== */
102
- [data-combobox-part="input-wrapper"] {
103
- display: flex;
104
- align-items: center;
105
- border-bottom: 1px solid var(--border);
106
- @apply px-3 gap-2;
107
- }
154
+ [data-combobox-part="input"] {
155
+ background-color: transparent;
156
+ color: var(--foreground);
157
+ @apply flex h-10 w-full py-3 text-sm outline-none;
158
+ @apply placeholder:text-muted-foreground;
159
+ @apply disabled:cursor-not-allowed disabled:opacity-50;
160
+ }
108
161
 
109
- [data-combobox-part="input-wrapper"] > svg {
110
- @apply size-4 shrink-0 opacity-50;
111
- }
162
+ /* ===== Options List ===== */
163
+ [data-combobox-part="list"] {
164
+ @apply max-h-[300px] overflow-y-auto overflow-x-hidden p-1;
165
+ }
112
166
 
113
- [data-combobox-part="input"] {
114
- background-color: transparent;
115
- color: var(--foreground);
116
- @apply flex h-10 w-full py-3 text-sm outline-none;
117
- @apply placeholder:text-muted-foreground;
118
- @apply disabled:cursor-not-allowed disabled:opacity-50;
119
- }
167
+ /* ===== Option Item ===== */
168
+ [data-combobox-part="option"] {
169
+ position: relative;
170
+ display: flex;
171
+ align-items: center;
172
+ cursor: default;
173
+ user-select: none;
174
+ color: var(--popover-foreground, var(--foreground));
175
+ @apply gap-2 py-1.5 text-sm outline-none transition-colors;
176
+ border-radius: var(--combobox-item-radius, var(--control-radius, 0.375rem));
177
+ @apply pl-8 pr-2; /* Space for check icon on left */
178
+ }
120
179
 
121
- /* ===== Options List ===== */
122
- [data-combobox-part="list"] {
123
- @apply max-h-[300px] overflow-y-auto overflow-x-hidden p-1;
124
- }
180
+ /* ----- Option states ----- */
125
181
 
126
- /* ===== Option Item ===== */
127
- [data-combobox-part="option"] {
128
- position: relative;
129
- display: flex;
130
- align-items: center;
131
- cursor: default;
132
- user-select: none;
133
- color: var(--popover-foreground, var(--foreground));
134
- @apply gap-2 rounded-sm py-1.5 text-sm outline-none transition-colors;
135
- @apply pl-8 pr-2; /* Space for check icon on left */
136
- }
182
+ /* Hover state */
183
+ [data-combobox-part="option"]:where(:hover:not([aria-disabled="true"])) {
184
+ background-color: var(--accent-hover, var(--accent));
185
+ color: var(--accent-foreground);
186
+ cursor: pointer;
187
+ }
137
188
 
138
- /* Hover state */
139
- [data-combobox-part="option"]:hover:not([aria-disabled="true"]) {
140
- background-color: var(--accent);
141
- color: var(--accent-foreground);
142
- cursor: pointer;
143
- }
189
+ /* Focus state (keyboard navigation) */
190
+ [data-combobox-part="option"]:where(:focus) {
191
+ background-color: var(--accent);
192
+ color: var(--accent-foreground);
193
+ }
144
194
 
145
- /* Focus state (keyboard navigation) */
146
- [data-combobox-part="option"]:focus {
147
- background-color: var(--accent);
148
- color: var(--accent-foreground);
149
- }
195
+ /* Selected state */
196
+ [data-combobox-part="option"]:where([data-selected="true"]) {
197
+ background-color: var(--accent);
198
+ color: var(--accent-foreground);
199
+ }
150
200
 
151
- /* Selected state */
152
- [data-combobox-part="option"][data-selected="true"] {
153
- background-color: var(--accent);
154
- color: var(--accent-foreground);
155
- }
201
+ /* Disabled state */
202
+ [data-combobox-part="option"]:where([aria-disabled="true"]) {
203
+ @apply opacity-50 cursor-not-allowed pointer-events-none;
204
+ }
156
205
 
157
- /* Disabled state */
158
- [data-combobox-part="option"][aria-disabled="true"] {
159
- @apply opacity-50 cursor-not-allowed pointer-events-none;
160
- }
206
+ /* Hidden state (filtered out) */
207
+ [data-combobox-part="option"]:where([hidden]) {
208
+ display: none;
209
+ }
161
210
 
162
- /* Hidden state (filtered out) */
163
- [data-combobox-part="option"][hidden] {
164
- display: none;
165
- }
211
+ /* Check indicator */
212
+ [data-combobox-part="check"] {
213
+ position: absolute;
214
+ left: 8px;
215
+ display: flex;
216
+ align-items: center;
217
+ justify-content: center;
218
+ @apply size-4;
219
+ }
166
220
 
167
- /* Check indicator */
168
- [data-combobox-part="check"] {
169
- position: absolute;
170
- left: 8px;
171
- display: flex;
172
- align-items: center;
173
- justify-content: center;
174
- @apply size-4;
175
- }
221
+ [data-combobox-part="check"] svg {
222
+ @apply size-4;
223
+ }
176
224
 
177
- [data-combobox-part="check"].invisible {
178
- visibility: hidden;
179
- }
225
+ [data-combobox-part="check"]:where(.invisible) {
226
+ visibility: hidden;
227
+ }
180
228
 
181
- [data-combobox-part="check"] svg {
182
- @apply size-4;
183
- }
229
+ /* ===== Empty State ===== */
230
+ [data-combobox-part="empty"] {
231
+ @apply py-6 text-center text-sm;
232
+ color: var(--muted-foreground);
233
+ }
184
234
 
185
- /* ===== Empty State ===== */
186
- [data-combobox-part="empty"] {
187
- @apply py-6 text-center text-sm;
188
- color: var(--muted-foreground);
189
- }
235
+ [data-combobox-part="empty"]:where([hidden]) {
236
+ display: none;
237
+ }
190
238
 
191
- [data-combobox-part="empty"][hidden] {
192
- display: none;
193
- }
239
+ /* ===== Group ===== */
240
+ [data-combobox-part="group"] {
241
+ display: flex;
242
+ flex-direction: column;
243
+ }
194
244
 
195
- /* ===== Group ===== */
196
- [data-combobox-part="group"] {
197
- display: flex;
198
- flex-direction: column;
199
- }
245
+ /* ===== Label ===== */
246
+ [data-combobox-part="label"] {
247
+ @apply px-2 py-1.5 text-xs;
248
+ font-weight: var(--label-weight, 500);
249
+ color: var(--muted-foreground);
250
+ }
200
251
 
201
- /* ===== Label ===== */
202
- [data-combobox-part="label"] {
203
- @apply px-2 py-1.5 text-xs font-medium;
204
- color: var(--muted-foreground);
252
+ /* ===== Separator ===== */
253
+ [data-combobox-part="separator"] {
254
+ @apply -mx-1 my-1 h-px;
255
+ background-color: var(--border);
256
+ }
205
257
  }
206
258
 
207
- /* ===== Separator ===== */
208
- [data-combobox-part="separator"] {
209
- @apply -mx-1 my-1 h-px;
210
- background-color: var(--border);
259
+ /* ===== Keyframes ===== */
260
+ /* Outside the layer: @keyframes are not cascade participants. */
261
+ @keyframes combobox-in {
262
+ from {
263
+ opacity: 0;
264
+ transform: scale(0.95) translateY(-4px);
265
+ }
266
+ to {
267
+ opacity: 1;
268
+ transform: scale(1) translateY(0);
269
+ }
211
270
  }
212
-
213
- /* ===== Dark Mode ===== */
214
- /*
215
- * Dark mode is handled automatically through CSS variables.
216
- * The theme variables change based on the .dark class on html/body.
217
- * No additional dark mode styles needed here.
218
- */