@justin_evo/evo-ui 1.0.1

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 (110) hide show
  1. package/dist/Alert/Alert.d.ts +11 -0
  2. package/dist/AutoComplete/AutoComplete.d.ts +95 -0
  3. package/dist/Badge/Badge.d.ts +23 -0
  4. package/dist/Breadcrumb/Breadcrumb.d.ts +16 -0
  5. package/dist/Button/Button.d.ts +54 -0
  6. package/dist/Card/Card.d.ts +60 -0
  7. package/dist/Checkbox/Checkbox.d.ts +16 -0
  8. package/dist/CommandPalette/CommandPalette.d.ts +17 -0
  9. package/dist/Container/Container.d.ts +10 -0
  10. package/dist/Divider/Divider.d.ts +7 -0
  11. package/dist/Form/Form.d.ts +61 -0
  12. package/dist/Grid/Grid.d.ts +23 -0
  13. package/dist/ImageCropper/ImageCropper.d.ts +111 -0
  14. package/dist/Input/Input.d.ts +12 -0
  15. package/dist/Modal/Modal.d.ts +26 -0
  16. package/dist/Nav/Nav.d.ts +63 -0
  17. package/dist/Notification/Notification.d.ts +186 -0
  18. package/dist/Pagination/Pagination.d.ts +10 -0
  19. package/dist/Radio/Radio.d.ts +20 -0
  20. package/dist/RichTextArea/RichTextArea.d.ts +70 -0
  21. package/dist/Select/Select.d.ts +44 -0
  22. package/dist/Skeleton/Skeleton.d.ts +23 -0
  23. package/dist/Stack/Stack.d.ts +16 -0
  24. package/dist/Table/Table.d.ts +77 -0
  25. package/dist/Tabs/Tabs.d.ts +28 -0
  26. package/dist/Theme/ThemeProvider.d.ts +96 -0
  27. package/dist/Theme/ThemeToggle.d.ts +22 -0
  28. package/dist/Toggle/Toggle.d.ts +11 -0
  29. package/dist/Tooltip/Tooltip.d.ts +10 -0
  30. package/dist/TopNav/TopNav.d.ts +76 -0
  31. package/dist/TreeSelect/TreeSelect.d.ts +50 -0
  32. package/dist/declarations.d.ts +6 -0
  33. package/dist/evo-ui.css +1 -0
  34. package/dist/index.cjs.js +1 -0
  35. package/dist/index.d.ts +31 -0
  36. package/dist/index.es.js +5688 -0
  37. package/package.json +52 -0
  38. package/src/Alert/Alert.tsx +49 -0
  39. package/src/AutoComplete/AutoComplete.tsx +810 -0
  40. package/src/Badge/Badge.tsx +53 -0
  41. package/src/Breadcrumb/Breadcrumb.tsx +53 -0
  42. package/src/Button/Button.tsx +125 -0
  43. package/src/Card/Card.tsx +257 -0
  44. package/src/Checkbox/Checkbox.tsx +59 -0
  45. package/src/CommandPalette/CommandPalette.tsx +185 -0
  46. package/src/Container/Container.tsx +31 -0
  47. package/src/Divider/Divider.tsx +31 -0
  48. package/src/Form/Form.tsx +185 -0
  49. package/src/Grid/Grid.tsx +66 -0
  50. package/src/ImageCropper/ImageCropper.tsx +911 -0
  51. package/src/Input/Input.tsx +74 -0
  52. package/src/Modal/Modal.tsx +77 -0
  53. package/src/Nav/Nav.tsx +626 -0
  54. package/src/Notification/Notification.tsx +1503 -0
  55. package/src/Pagination/Pagination.tsx +76 -0
  56. package/src/Radio/Radio.tsx +69 -0
  57. package/src/RichTextArea/RichTextArea.tsx +869 -0
  58. package/src/Select/Select.tsx +515 -0
  59. package/src/Skeleton/Skeleton.tsx +70 -0
  60. package/src/Stack/Stack.tsx +52 -0
  61. package/src/Table/Table.tsx +335 -0
  62. package/src/Tabs/Tabs.tsx +90 -0
  63. package/src/Theme/ThemeProvider.tsx +253 -0
  64. package/src/Theme/ThemeToggle.tsx +79 -0
  65. package/src/Toggle/Toggle.tsx +48 -0
  66. package/src/Tooltip/Tooltip.tsx +38 -0
  67. package/src/TopNav/TopNav.tsx +994 -0
  68. package/src/TreeSelect/TreeSelect.tsx +825 -0
  69. package/src/css/alert.module.scss +93 -0
  70. package/src/css/autocomplete.module.scss +416 -0
  71. package/src/css/badge.module.scss +82 -0
  72. package/src/css/base/_color.scss +159 -0
  73. package/src/css/base/_theme.scss +237 -0
  74. package/src/css/base/_variables.scss +161 -0
  75. package/src/css/breadcrumb.module.scss +50 -0
  76. package/src/css/button.module.scss +385 -0
  77. package/src/css/card.module.scss +217 -0
  78. package/src/css/checkbox.module.scss +120 -0
  79. package/src/css/commandpalette.module.scss +211 -0
  80. package/src/css/container.module.scss +18 -0
  81. package/src/css/divider.module.scss +41 -0
  82. package/src/css/form.module.scss +245 -0
  83. package/src/css/imagecropper.module.scss +397 -0
  84. package/src/css/input.module.scss +89 -0
  85. package/src/css/modal.module.scss +105 -0
  86. package/src/css/nav.module.scss +339 -0
  87. package/src/css/notification.module.scss +691 -0
  88. package/src/css/pagination.module.scss +63 -0
  89. package/src/css/radio.module.scss +89 -0
  90. package/src/css/richtextarea.module.scss +307 -0
  91. package/src/css/select.module.scss +525 -0
  92. package/src/css/skeleton.module.scss +30 -0
  93. package/src/css/table.module.scss +386 -0
  94. package/src/css/tabs.module.scss +63 -0
  95. package/src/css/theme-toggle.module.scss +83 -0
  96. package/src/css/toggle.module.scss +54 -0
  97. package/src/css/tooltip.module.scss +97 -0
  98. package/src/css/topnav.module.scss +396 -0
  99. package/src/css/treeselect.module.scss +558 -0
  100. package/src/css/utilities/_borders.scss +111 -0
  101. package/src/css/utilities/_colors.scss +66 -0
  102. package/src/css/utilities/_effects.scss +216 -0
  103. package/src/css/utilities/_layout.scss +181 -0
  104. package/src/css/utilities/_position.scss +75 -0
  105. package/src/css/utilities/_sizing.scss +138 -0
  106. package/src/css/utilities/_spacing.scss +99 -0
  107. package/src/css/utilities/_typography.scss +121 -0
  108. package/src/css/utilities/index.scss +24 -0
  109. package/src/declarations.d.ts +6 -0
  110. package/src/index.ts +60 -0
@@ -0,0 +1,397 @@
1
+ @use 'base/variables' as *;
2
+
3
+ // =============================================================
4
+ // EvoImageCropper
5
+ // -------------------------------------------------------------
6
+ // A pointer-driven image cropper. The image transforms with
7
+ // CSS (translate + scale + rotate); the crop rectangle is a
8
+ // fixed overlay with eight resize handles. Final pixel work
9
+ // (rendering the crop to a blob) is deferred until requested.
10
+ //
11
+ // Everything responds to viewport width — handles grow on touch,
12
+ // the toolbar reflows on narrow screens, and a tall portrait
13
+ // orientation keeps the canvas usable.
14
+ // =============================================================
15
+
16
+ .root {
17
+ display: flex;
18
+ flex-direction: column;
19
+ gap: 0.75rem;
20
+ font-family: $font-sans;
21
+ color: $color-text-primary;
22
+ min-width: 0;
23
+ width: 100%;
24
+ }
25
+
26
+ .fullWidth { width: 100%; }
27
+
28
+ .label {
29
+ font-size: $text-sm;
30
+ font-weight: 500;
31
+ color: $color-text-primary;
32
+ }
33
+
34
+ // ---------- Canvas area (image + overlay) ----------
35
+ .stage {
36
+ position: relative;
37
+ width: 100%;
38
+ height: 360px;
39
+ border-radius: $radius-md;
40
+ background-color: $color-surface-sunken;
41
+ border: 1px solid $color-border;
42
+ overflow: hidden;
43
+ touch-action: none;
44
+ user-select: none;
45
+ -webkit-user-select: none;
46
+ -webkit-tap-highlight-color: transparent;
47
+ cursor: grab;
48
+
49
+ &:active { cursor: grabbing; }
50
+
51
+ &.disabled {
52
+ opacity: 0.55;
53
+ pointer-events: none;
54
+ }
55
+ }
56
+
57
+ // Checkerboard background — clearly shows alpha & PNG borders
58
+ .bgChecker {
59
+ background-image:
60
+ linear-gradient(45deg, $color-surface-active 25%, transparent 25%),
61
+ linear-gradient(-45deg, $color-surface-active 25%, transparent 25%),
62
+ linear-gradient(45deg, transparent 75%, $color-surface-active 75%),
63
+ linear-gradient(-45deg, transparent 75%, $color-surface-active 75%);
64
+ background-size: 16px 16px;
65
+ background-position: 0 0, 0 8px, 8px -8px, -8px 0;
66
+ }
67
+
68
+ .imageWrap {
69
+ position: absolute;
70
+ inset: 0;
71
+ display: flex;
72
+ align-items: center;
73
+ justify-content: center;
74
+ pointer-events: none;
75
+ }
76
+
77
+ .image {
78
+ display: block;
79
+ max-width: none;
80
+ pointer-events: none;
81
+ user-select: none;
82
+ -webkit-user-drag: none;
83
+ transform-origin: center center;
84
+ will-change: transform;
85
+ }
86
+
87
+ // ---------- Crop overlay ----------
88
+ // A full-stage element with a giant inset box-shadow that darkens
89
+ // everything *outside* the crop rectangle. The element itself sits
90
+ // at the crop coords and has no fill of its own.
91
+ .overlay {
92
+ position: absolute;
93
+ box-sizing: border-box;
94
+ border: 1px solid rgba(255, 255, 255, 0.92);
95
+ box-shadow:
96
+ 0 0 0 9999px rgba(0, 0, 0, 0.55),
97
+ 0 0 0 1px rgba(0, 0, 0, 0.25) inset;
98
+ cursor: move;
99
+ touch-action: none;
100
+ }
101
+
102
+ .overlayCircle {
103
+ border-radius: 50%;
104
+ // Box-shadow can't follow a border-radius cutout, so the circle
105
+ // mode uses a radial gradient on a sibling element instead.
106
+ box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.25) inset;
107
+ }
108
+
109
+ .circleMask {
110
+ position: absolute;
111
+ inset: 0;
112
+ pointer-events: none;
113
+ background:
114
+ radial-gradient(circle at var(--mask-cx) var(--mask-cy),
115
+ transparent 0,
116
+ transparent var(--mask-r),
117
+ rgba(0, 0, 0, 0.55) calc(var(--mask-r) + 1px));
118
+ }
119
+
120
+ // ---------- Rule-of-thirds grid ----------
121
+ .grid {
122
+ position: absolute;
123
+ inset: 0;
124
+ pointer-events: none;
125
+ }
126
+
127
+ .gridLine {
128
+ position: absolute;
129
+ background-color: rgba(255, 255, 255, 0.35);
130
+
131
+ &.h { left: 0; right: 0; height: 1px; }
132
+ &.v { top: 0; bottom: 0; width: 1px; }
133
+ }
134
+
135
+ // ---------- Resize handles ----------
136
+ .handle {
137
+ position: absolute;
138
+ width: 12px;
139
+ height: 12px;
140
+ background-color: #fff;
141
+ border: 1px solid rgba(0, 0, 0, 0.4);
142
+ border-radius: 2px;
143
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
144
+ z-index: 2;
145
+ touch-action: none;
146
+
147
+ // Larger tap targets on touch-capable devices
148
+ @media (hover: none) and (pointer: coarse) {
149
+ width: 20px;
150
+ height: 20px;
151
+ }
152
+ }
153
+
154
+ // Corner handles — at the four corners of the crop rect
155
+ .handleTL { top: -7px; left: -7px; cursor: nwse-resize; }
156
+ .handleTR { top: -7px; right: -7px; cursor: nesw-resize; }
157
+ .handleBL { bottom: -7px; left: -7px; cursor: nesw-resize; }
158
+ .handleBR { bottom: -7px; right: -7px; cursor: nwse-resize; }
159
+
160
+ // Edge handles — wider/taller to feel like pull-bars
161
+ .handleT, .handleB {
162
+ left: 50%;
163
+ transform: translateX(-50%);
164
+ width: 24px;
165
+ height: 6px;
166
+ cursor: ns-resize;
167
+
168
+ @media (hover: none) and (pointer: coarse) {
169
+ width: 36px;
170
+ height: 10px;
171
+ }
172
+ }
173
+ .handleL, .handleR {
174
+ top: 50%;
175
+ transform: translateY(-50%);
176
+ width: 6px;
177
+ height: 24px;
178
+ cursor: ew-resize;
179
+
180
+ @media (hover: none) and (pointer: coarse) {
181
+ width: 10px;
182
+ height: 36px;
183
+ }
184
+ }
185
+ .handleT { top: -3px; }
186
+ .handleB { bottom: -3px; }
187
+ .handleL { left: -3px; }
188
+ .handleR { right: -3px; }
189
+
190
+ // In circular mode, edge handles look odd; hide them and keep corners
191
+ .overlay.overlayCircle {
192
+ .handleT, .handleB, .handleL, .handleR { display: none; }
193
+ }
194
+
195
+ // ---------- Controls toolbar ----------
196
+ .controls {
197
+ display: flex;
198
+ flex-wrap: wrap;
199
+ align-items: center;
200
+ gap: 0.5rem 0.75rem;
201
+ padding: 0.625rem 0.75rem;
202
+ background-color: $color-surface;
203
+ border: 1px solid $color-border;
204
+ border-radius: $radius-sm;
205
+ }
206
+
207
+ .controlGroup {
208
+ display: flex;
209
+ align-items: center;
210
+ gap: 0.375rem;
211
+ min-width: 0;
212
+ }
213
+
214
+ .controlLabel {
215
+ font-size: $text-xs;
216
+ color: $color-text-muted;
217
+ font-weight: 500;
218
+ letter-spacing: 0.02em;
219
+ text-transform: uppercase;
220
+ white-space: nowrap;
221
+ }
222
+
223
+ .iconBtn {
224
+ display: inline-flex;
225
+ align-items: center;
226
+ justify-content: center;
227
+ width: 32px;
228
+ height: 32px;
229
+ padding: 0;
230
+ background: transparent;
231
+ border: 1px solid $color-border;
232
+ border-radius: $evo-border-radius-sm;
233
+ color: $color-text-secondary;
234
+ cursor: pointer;
235
+ transition: background-color $transition-fast, color $transition-fast, border-color $transition-fast;
236
+ -webkit-tap-highlight-color: transparent;
237
+
238
+ &:hover:not(:disabled) {
239
+ background-color: $color-surface-hover;
240
+ color: $color-text-primary;
241
+ border-color: $color-border-strong;
242
+ }
243
+
244
+ &:active:not(:disabled) { background-color: $color-surface-active; }
245
+
246
+ &:disabled { cursor: not-allowed; opacity: 0.45; }
247
+
248
+ &:focus-visible {
249
+ outline: none;
250
+ border-color: $evo-primary-color;
251
+ box-shadow: 0 0 0 2px color-mix(in srgb, $evo-primary-color 22%, transparent);
252
+ }
253
+ }
254
+
255
+ .zoomSlider {
256
+ appearance: none;
257
+ -webkit-appearance: none;
258
+ flex: 1 1 120px;
259
+ min-width: 80px;
260
+ max-width: 220px;
261
+ height: 4px;
262
+ background-color: $color-surface-active;
263
+ border-radius: $radius-full;
264
+ cursor: pointer;
265
+
266
+ &::-webkit-slider-thumb {
267
+ appearance: none;
268
+ -webkit-appearance: none;
269
+ width: 16px;
270
+ height: 16px;
271
+ background-color: $evo-primary-color;
272
+ border-radius: 50%;
273
+ cursor: pointer;
274
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);
275
+ }
276
+
277
+ &::-moz-range-thumb {
278
+ width: 16px;
279
+ height: 16px;
280
+ background-color: $evo-primary-color;
281
+ border: none;
282
+ border-radius: 50%;
283
+ cursor: pointer;
284
+ }
285
+
286
+ &:focus-visible {
287
+ outline: none;
288
+ box-shadow: 0 0 0 3px color-mix(in srgb, $evo-primary-color 22%, transparent);
289
+ }
290
+ }
291
+
292
+ // ---------- Aspect ratio preset chips ----------
293
+ .ratioRow {
294
+ display: flex;
295
+ flex-wrap: wrap;
296
+ gap: 0.375rem;
297
+ }
298
+
299
+ .ratioChip {
300
+ display: inline-flex;
301
+ align-items: center;
302
+ padding: 0.25rem 0.625rem;
303
+ background-color: $color-surface;
304
+ border: 1px solid $color-border;
305
+ border-radius: $radius-full;
306
+ font-size: $text-xs;
307
+ font-weight: 500;
308
+ color: $color-text-secondary;
309
+ cursor: pointer;
310
+ transition: background-color $transition-fast, color $transition-fast, border-color $transition-fast;
311
+ -webkit-tap-highlight-color: transparent;
312
+
313
+ &:hover:not(:disabled) {
314
+ background-color: $color-surface-hover;
315
+ color: $color-text-primary;
316
+ }
317
+
318
+ &.active {
319
+ background-color: $evo-primary-soft;
320
+ border-color: $evo-primary-color;
321
+ color: $evo-primary-color;
322
+ }
323
+
324
+ &:focus-visible {
325
+ outline: none;
326
+ border-color: $evo-primary-color;
327
+ box-shadow: 0 0 0 2px color-mix(in srgb, $evo-primary-color 22%, transparent);
328
+ }
329
+
330
+ &:disabled { cursor: not-allowed; opacity: 0.45; }
331
+ }
332
+
333
+ .divider {
334
+ width: 1px;
335
+ height: 20px;
336
+ background-color: $color-border;
337
+ }
338
+
339
+ .helper {
340
+ font-size: $text-xs;
341
+ color: $color-text-muted;
342
+ }
343
+
344
+ // ---------- Loading state ----------
345
+ .placeholder {
346
+ position: absolute;
347
+ inset: 0;
348
+ display: flex;
349
+ flex-direction: column;
350
+ align-items: center;
351
+ justify-content: center;
352
+ gap: 0.5rem;
353
+ color: $color-text-muted;
354
+ font-size: $text-sm;
355
+ }
356
+
357
+ .spinner {
358
+ width: 20px;
359
+ height: 20px;
360
+ border: 2px solid $color-border;
361
+ border-top-color: $evo-primary-color;
362
+ border-radius: 50%;
363
+ animation: evoCropperSpin 700ms linear infinite;
364
+ }
365
+
366
+ @keyframes evoCropperSpin {
367
+ to { transform: rotate(360deg); }
368
+ }
369
+
370
+ // ---------- Responsive ----------
371
+ @media (max-width: 640px) {
372
+ .stage { height: 300px; }
373
+
374
+ .controls {
375
+ padding: 0.5rem;
376
+ gap: 0.5rem;
377
+ }
378
+
379
+ // On narrow screens the divider becomes a full-width row break
380
+ .divider {
381
+ width: 100%;
382
+ height: 0;
383
+ background: transparent;
384
+ }
385
+
386
+ .controlGroup { flex: 1 1 auto; justify-content: flex-start; }
387
+ }
388
+
389
+ @media (max-width: 420px) {
390
+ .stage { height: 260px; }
391
+ .controlLabel { display: none; }
392
+ }
393
+
394
+ @media (prefers-reduced-motion: reduce) {
395
+ .image, .overlay, .iconBtn, .ratioChip { transition: none !important; }
396
+ .spinner { animation: none; }
397
+ }
@@ -0,0 +1,89 @@
1
+ @use 'base/variables' as *;
2
+ @use 'base/color' as *;
3
+
4
+ .field {
5
+ display: flex;
6
+ flex-direction: column;
7
+ gap: 0.375rem;
8
+ font-family: $font-sans;
9
+ }
10
+
11
+ .fullWidth { width: 100%; }
12
+
13
+ .label {
14
+ font-size: $text-sm;
15
+ font-weight: 500;
16
+ color: $color-text-primary;
17
+ }
18
+
19
+ .inputWrapper {
20
+ display: flex;
21
+ align-items: center;
22
+ background-color: $color-surface;
23
+ border: 1px solid $color-border;
24
+ border-radius: $radius-sm;
25
+ transition: border-color $transition-fast, box-shadow $transition-fast;
26
+
27
+ &:focus-within {
28
+ border-color: $evo-primary-color;
29
+ box-shadow: 0 0 0 3px color-mix(in srgb, $evo-primary-color 18%, transparent);
30
+ }
31
+
32
+ &.hasError {
33
+ border-color: $evo-danger-color;
34
+
35
+ &:focus-within {
36
+ border-color: $evo-danger-color;
37
+ box-shadow: 0 0 0 3px color-mix(in srgb, $evo-danger-color 18%, transparent);
38
+ }
39
+ }
40
+ }
41
+
42
+ .sm { padding: 0.25rem 0.5rem; }
43
+ .md { padding: 0.5rem 0.75rem; }
44
+ .lg { padding: 0.625rem 1rem; }
45
+
46
+ .input {
47
+ flex: 1;
48
+ background: transparent;
49
+ border: none;
50
+ outline: none;
51
+ font-size: $text-sm;
52
+ color: $color-text-primary;
53
+ font-family: $font-sans;
54
+ width: 100%;
55
+ min-width: 0;
56
+
57
+ &::placeholder { color: $color-text-muted; }
58
+
59
+ &:disabled {
60
+ opacity: 0.5;
61
+ cursor: not-allowed;
62
+ }
63
+ }
64
+
65
+ .adornment {
66
+ display: flex;
67
+ align-items: center;
68
+ color: $color-text-muted;
69
+ font-size: $text-sm;
70
+ flex-shrink: 0;
71
+ padding-right: 0.375rem;
72
+ }
73
+
74
+ .trailingAdornment {
75
+ padding-right: 0;
76
+ padding-left: 0.375rem;
77
+ }
78
+
79
+ .errorText {
80
+ font-size: $text-xs;
81
+ color: $evo-danger-color;
82
+ margin: 0;
83
+ }
84
+
85
+ .helperText {
86
+ font-size: $text-xs;
87
+ color: $color-text-muted;
88
+ margin: 0;
89
+ }
@@ -0,0 +1,105 @@
1
+ @use 'base/variables' as *;
2
+ @use 'base/color' as *;
3
+
4
+ @keyframes overlayFadeIn {
5
+ from { opacity: 0; }
6
+ to { opacity: 1; }
7
+ }
8
+
9
+ @keyframes dialogSlideUp {
10
+ from { opacity: 0; transform: translateY(20px) scale(0.97); }
11
+ to { opacity: 1; transform: translateY(0) scale(1); }
12
+ }
13
+
14
+ .overlay {
15
+ position: fixed;
16
+ inset: 0;
17
+ background-color: $color-backdrop;
18
+ backdrop-filter: blur(4px);
19
+ display: flex;
20
+ align-items: center;
21
+ justify-content: center;
22
+ z-index: 9999;
23
+ padding: 1rem;
24
+ animation: overlayFadeIn 150ms ease;
25
+ }
26
+
27
+ .dialog {
28
+ position: relative;
29
+ background-color: $color-surface-elevated;
30
+ border: 1px solid $color-border;
31
+ border-radius: $radius-lg;
32
+ box-shadow: 0 25px 60px -12px rgb(0 0 0 / 0.45);
33
+ display: flex;
34
+ flex-direction: column;
35
+ max-height: 90vh;
36
+ overflow: hidden;
37
+ animation: dialogSlideUp 200ms ease;
38
+
39
+ // Mobile-first: dialog stays comfortable on narrow screens.
40
+ width: 100%;
41
+
42
+ &.sm { max-width: 400px; }
43
+ &.md { max-width: 560px; }
44
+ &.lg { max-width: 768px; }
45
+ &.fullscreen { height: 100%; max-width: none; border-radius: 0; }
46
+ }
47
+
48
+ .header {
49
+ display: flex;
50
+ align-items: center;
51
+ justify-content: space-between;
52
+ padding: 1.25rem 1.5rem;
53
+ border-bottom: 1px solid $color-border;
54
+ flex-shrink: 0;
55
+ gap: 1rem;
56
+ }
57
+
58
+ .headerContent {
59
+ flex: 1;
60
+ font-size: $text-lg;
61
+ font-weight: 600;
62
+ color: $color-text-primary;
63
+ font-family: $font-sans;
64
+ }
65
+
66
+ .closeBtn {
67
+ display: inline-flex;
68
+ align-items: center;
69
+ justify-content: center;
70
+ width: 1.75rem;
71
+ height: 1.75rem;
72
+ background: transparent;
73
+ border: none;
74
+ border-radius: $radius-sm;
75
+ color: $color-text-muted;
76
+ cursor: pointer;
77
+ font-size: $text-sm;
78
+ transition: background-color $transition-fast, color $transition-fast;
79
+ flex-shrink: 0;
80
+
81
+ &:hover {
82
+ background-color: $color-surface-hover;
83
+ color: $color-text-primary;
84
+ }
85
+ }
86
+
87
+ .body {
88
+ padding: 1.5rem;
89
+ overflow-y: auto;
90
+ flex: 1;
91
+ font-family: $font-sans;
92
+ color: $color-text-secondary;
93
+ font-size: $text-sm;
94
+ line-height: 1.7;
95
+ }
96
+
97
+ .footer {
98
+ display: flex;
99
+ align-items: center;
100
+ justify-content: flex-end;
101
+ gap: 0.5rem;
102
+ padding: 1rem 1.5rem;
103
+ border-top: 1px solid $color-border;
104
+ flex-shrink: 0;
105
+ }