@aspect-ops/exon-ui 0.2.1 → 0.3.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 (75) hide show
  1. package/dist/components/AspectRatio/AspectRatio.svelte +1 -0
  2. package/dist/components/CTASection/CTASection.svelte +298 -0
  3. package/dist/components/CTASection/CTASection.svelte.d.ts +15 -0
  4. package/dist/components/CTASection/index.d.ts +2 -0
  5. package/dist/components/CTASection/index.js +1 -0
  6. package/dist/components/Card/FlipCard.svelte +155 -0
  7. package/dist/components/Card/FlipCard.svelte.d.ts +13 -0
  8. package/dist/components/Card/index.d.ts +1 -0
  9. package/dist/components/Card/index.js +1 -0
  10. package/dist/components/Container/Container.svelte +1 -0
  11. package/dist/components/DataTable/DataTable.svelte +460 -0
  12. package/dist/components/DataTable/DataTable.svelte.d.ts +49 -0
  13. package/dist/components/DataTable/index.d.ts +2 -0
  14. package/dist/components/DataTable/index.js +1 -0
  15. package/dist/components/DoughnutChart/DoughnutChart.svelte +20 -2
  16. package/dist/components/GlobalHeader/GlobalHeader.svelte +692 -0
  17. package/dist/components/GlobalHeader/GlobalHeader.svelte.d.ts +3 -0
  18. package/dist/components/GlobalHeader/index.d.ts +2 -0
  19. package/dist/components/GlobalHeader/index.js +1 -0
  20. package/dist/components/Hero/Hero.svelte +306 -0
  21. package/dist/components/Hero/Hero.svelte.d.ts +18 -0
  22. package/dist/components/Hero/index.d.ts +2 -0
  23. package/dist/components/Hero/index.js +1 -0
  24. package/dist/components/Icon/Icon.svelte +15 -18
  25. package/dist/components/Icon/Icon.svelte.d.ts +2 -1
  26. package/dist/components/LogoCloud/LogoCloud.svelte +333 -0
  27. package/dist/components/LogoCloud/LogoCloud.svelte.d.ts +20 -0
  28. package/dist/components/LogoCloud/index.d.ts +2 -0
  29. package/dist/components/LogoCloud/index.js +1 -0
  30. package/dist/components/Menu/MenuContent.svelte +1 -0
  31. package/dist/components/Menu/MenuSubContent.svelte +1 -0
  32. package/dist/components/Mermaid/Mermaid.svelte +121 -7
  33. package/dist/components/Mermaid/Mermaid.svelte.d.ts +10 -0
  34. package/dist/components/PageHeader/PageHeader.svelte +140 -0
  35. package/dist/components/PageHeader/PageHeader.svelte.d.ts +30 -0
  36. package/dist/components/PageHeader/index.d.ts +1 -0
  37. package/dist/components/PageHeader/index.js +1 -0
  38. package/dist/components/ServiceCard/ServiceCard.svelte +359 -0
  39. package/dist/components/ServiceCard/ServiceCard.svelte.d.ts +16 -0
  40. package/dist/components/ServiceCard/index.d.ts +1 -0
  41. package/dist/components/ServiceCard/index.js +1 -0
  42. package/dist/components/SplitSection/SplitSection.svelte +194 -0
  43. package/dist/components/SplitSection/SplitSection.svelte.d.ts +15 -0
  44. package/dist/components/SplitSection/index.d.ts +1 -0
  45. package/dist/components/SplitSection/index.js +1 -0
  46. package/dist/components/StatCircle/StatCircle.svelte +172 -0
  47. package/dist/components/StatCircle/StatCircle.svelte.d.ts +19 -0
  48. package/dist/components/StatCircle/index.d.ts +1 -0
  49. package/dist/components/StatCircle/index.js +1 -0
  50. package/dist/components/StatsCard/StatsCard.svelte +301 -0
  51. package/dist/components/StatsCard/StatsCard.svelte.d.ts +32 -0
  52. package/dist/components/StatsCard/index.d.ts +2 -0
  53. package/dist/components/StatsCard/index.js +1 -0
  54. package/dist/components/StatusBadge/StatusBadge.svelte +221 -0
  55. package/dist/components/StatusBadge/StatusBadge.svelte.d.ts +22 -0
  56. package/dist/components/StatusBadge/index.d.ts +2 -0
  57. package/dist/components/StatusBadge/index.js +1 -0
  58. package/dist/components/StatusBanner/StatusBanner.svelte +325 -0
  59. package/dist/components/StatusBanner/StatusBanner.svelte.d.ts +13 -0
  60. package/dist/components/StatusBanner/index.d.ts +1 -0
  61. package/dist/components/StatusBanner/index.js +1 -0
  62. package/dist/components/TestimonialCard/TestimonialCard.svelte +290 -0
  63. package/dist/components/TestimonialCard/TestimonialCard.svelte.d.ts +14 -0
  64. package/dist/components/TestimonialCard/index.d.ts +1 -0
  65. package/dist/components/TestimonialCard/index.js +1 -0
  66. package/dist/components/Timeline/Timeline.svelte +444 -0
  67. package/dist/components/Timeline/Timeline.svelte.d.ts +19 -0
  68. package/dist/components/Timeline/index.d.ts +2 -0
  69. package/dist/components/Timeline/index.js +1 -0
  70. package/dist/index.d.ts +24 -2
  71. package/dist/index.js +16 -1
  72. package/dist/types/data-display.d.ts +72 -0
  73. package/dist/types/feedback.d.ts +10 -0
  74. package/dist/types/index.d.ts +2 -2
  75. package/package.json +3 -2
@@ -0,0 +1,460 @@
1
+ <script lang="ts">
2
+ /**
3
+ * DataTable - A sortable, customizable data table component
4
+ * Supports custom cell rendering, sorting, loading states, and responsive overflow
5
+ */
6
+
7
+ type SortOrder = 'asc' | 'desc';
8
+ type ColumnAlign = 'left' | 'center' | 'right';
9
+
10
+ interface ColumnDef {
11
+ /** Unique key matching the data property */
12
+ key: string;
13
+ /** Header text to display */
14
+ header: string;
15
+ /** Whether this column is sortable */
16
+ sortable?: boolean;
17
+ /** Fixed width (e.g., '100px', '10rem') */
18
+ width?: string;
19
+ /** Text alignment */
20
+ align?: ColumnAlign;
21
+ /** Custom cell renderer - receives (value, row) */
22
+ cell?: import('svelte').Snippet<[value: unknown, row: unknown]>;
23
+ }
24
+
25
+ interface Props {
26
+ /** Array of data objects to display */
27
+ data: unknown[];
28
+ /** Column definitions */
29
+ columns: ColumnDef[];
30
+ /** Currently sorted column key */
31
+ sortBy?: string;
32
+ /** Current sort direction */
33
+ sortOrder?: SortOrder;
34
+ /** Callback when sort changes */
35
+ onsort?: (column: string, order: SortOrder) => void;
36
+ /** Show loading skeleton */
37
+ loading?: boolean;
38
+ /** Number of skeleton rows to show when loading */
39
+ loadingRows?: number;
40
+ /** Custom empty state content */
41
+ empty?: import('svelte').Snippet;
42
+ /** Enable row hover effect */
43
+ rowHover?: boolean;
44
+ /** Enable striped rows */
45
+ striped?: boolean;
46
+ /** Make header sticky on scroll */
47
+ stickyHeader?: boolean;
48
+ /** Additional CSS classes */
49
+ class?: string;
50
+ }
51
+
52
+ let {
53
+ data = [],
54
+ columns,
55
+ sortBy = $bindable(),
56
+ sortOrder = $bindable(),
57
+ onsort,
58
+ loading = false,
59
+ loadingRows = 5,
60
+ empty,
61
+ rowHover = true,
62
+ striped = false,
63
+ stickyHeader = false,
64
+ class: className = ''
65
+ }: Props = $props();
66
+
67
+ function handleSort(column: ColumnDef) {
68
+ if (!column.sortable) return;
69
+
70
+ let newOrder: SortOrder = 'asc';
71
+ if (sortBy === column.key) {
72
+ newOrder = sortOrder === 'asc' ? 'desc' : 'asc';
73
+ }
74
+
75
+ sortBy = column.key;
76
+ sortOrder = newOrder;
77
+ onsort?.(column.key, newOrder);
78
+ }
79
+
80
+ function getCellValue(row: unknown, key: string): unknown {
81
+ if (typeof row === 'object' && row !== null) {
82
+ return (row as Record<string, unknown>)[key];
83
+ }
84
+ return undefined;
85
+ }
86
+
87
+ const isEmpty = $derived(!loading && data.length === 0);
88
+ const skeletonRows = $derived(Array.from({ length: loadingRows }, (_, i) => i));
89
+ </script>
90
+
91
+ <div class="data-table-container {className}" class:data-table-container--sticky={stickyHeader}>
92
+ <table
93
+ class="data-table"
94
+ class:data-table--striped={striped}
95
+ class:data-table--row-hover={rowHover}
96
+ >
97
+ <thead class="data-table__head">
98
+ <tr>
99
+ {#each columns as column}
100
+ <th
101
+ class="data-table__header data-table__header--{column.align || 'left'}"
102
+ class:data-table__header--sortable={column.sortable}
103
+ style={column.width ? `width: ${column.width}` : undefined}
104
+ onclick={() => handleSort(column)}
105
+ role={column.sortable ? 'button' : undefined}
106
+ tabindex={column.sortable ? 0 : undefined}
107
+ onkeydown={(e) => {
108
+ if (column.sortable && (e.key === 'Enter' || e.key === ' ')) {
109
+ e.preventDefault();
110
+ handleSort(column);
111
+ }
112
+ }}
113
+ aria-sort={sortBy === column.key
114
+ ? sortOrder === 'asc'
115
+ ? 'ascending'
116
+ : 'descending'
117
+ : undefined}
118
+ >
119
+ <div class="data-table__header-content">
120
+ <span>{column.header}</span>
121
+ {#if column.sortable}
122
+ <span
123
+ class="data-table__sort-icon"
124
+ class:data-table__sort-icon--active={sortBy === column.key}
125
+ >
126
+ {#if sortBy === column.key}
127
+ <svg viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
128
+ {#if sortOrder === 'asc'}
129
+ <path
130
+ fill-rule="evenodd"
131
+ d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
132
+ clip-rule="evenodd"
133
+ />
134
+ {:else}
135
+ <path
136
+ fill-rule="evenodd"
137
+ d="M14.707 12.707a1 1 0 01-1.414 0L10 9.414l-3.293 3.293a1 1 0 01-1.414-1.414l4-4a1 1 0 011.414 0l4 4a1 1 0 010 1.414z"
138
+ clip-rule="evenodd"
139
+ />
140
+ {/if}
141
+ </svg>
142
+ {:else}
143
+ <svg viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
144
+ <path
145
+ d="M5 8.5a.5.5 0 01.5-.5h9a.5.5 0 010 1h-9A.5.5 0 015 8.5zm0 3a.5.5 0 01.5-.5h9a.5.5 0 010 1h-9a.5.5 0 01-.5-.5z"
146
+ />
147
+ </svg>
148
+ {/if}
149
+ </span>
150
+ {/if}
151
+ </div>
152
+ </th>
153
+ {/each}
154
+ </tr>
155
+ </thead>
156
+ <tbody class="data-table__body">
157
+ {#if loading}
158
+ {#each skeletonRows as _row}
159
+ <tr class="data-table__row data-table__row--skeleton">
160
+ {#each columns as column}
161
+ <td
162
+ class="data-table__cell data-table__cell--{column.align || 'left'}"
163
+ style={column.width ? `width: ${column.width}` : undefined}
164
+ >
165
+ <div class="data-table__skeleton"></div>
166
+ </td>
167
+ {/each}
168
+ </tr>
169
+ {/each}
170
+ {:else if isEmpty}
171
+ <tr class="data-table__row data-table__row--empty">
172
+ <td colspan={columns.length} class="data-table__cell data-table__cell--empty">
173
+ {#if empty}
174
+ {@render empty()}
175
+ {:else}
176
+ <div class="data-table__empty-default">
177
+ <span>No data available</span>
178
+ </div>
179
+ {/if}
180
+ </td>
181
+ </tr>
182
+ {:else}
183
+ {#each data as row, index}
184
+ <tr class="data-table__row" data-row-index={index}>
185
+ {#each columns as column}
186
+ <td
187
+ class="data-table__cell data-table__cell--{column.align || 'left'}"
188
+ style={column.width ? `width: ${column.width}` : undefined}
189
+ >
190
+ {#if column.cell}
191
+ {@render column.cell(getCellValue(row, column.key), row)}
192
+ {:else}
193
+ {getCellValue(row, column.key) ?? '-'}
194
+ {/if}
195
+ </td>
196
+ {/each}
197
+ </tr>
198
+ {/each}
199
+ {/if}
200
+ </tbody>
201
+ </table>
202
+ </div>
203
+
204
+ <style>
205
+ /* Container with horizontal overflow */
206
+ .data-table-container {
207
+ width: 100%;
208
+ overflow-x: auto;
209
+ -webkit-overflow-scrolling: touch;
210
+ border-radius: var(--radius-lg, 0.5rem);
211
+ background: var(--color-bg-card, #ffffff);
212
+ box-shadow: var(--shadow-sm, 0 1px 2px 0 rgb(0 0 0 / 0.05));
213
+ }
214
+
215
+ .data-table-container--sticky {
216
+ max-height: 70vh;
217
+ overflow-y: auto;
218
+ }
219
+
220
+ /* Table base */
221
+ .data-table {
222
+ width: 100%;
223
+ border-collapse: collapse;
224
+ font-family: inherit;
225
+ font-size: var(--text-sm, 0.875rem);
226
+ }
227
+
228
+ /* Header */
229
+ .data-table__head {
230
+ background: var(--color-bg-muted, #f9fafb);
231
+ }
232
+
233
+ .data-table-container--sticky .data-table__head {
234
+ position: sticky;
235
+ top: 0;
236
+ z-index: 1;
237
+ }
238
+
239
+ .data-table__header {
240
+ padding: var(--space-md, 0.75rem) var(--space-lg, 1rem);
241
+ font-size: var(--text-xs, 0.75rem);
242
+ font-weight: 600;
243
+ color: var(--color-text-muted, #6b7280);
244
+ text-transform: uppercase;
245
+ letter-spacing: 0.05em;
246
+ white-space: nowrap;
247
+ border-bottom: 1px solid var(--color-border, #e5e7eb);
248
+ user-select: none;
249
+ }
250
+
251
+ .data-table__header--left {
252
+ text-align: left;
253
+ }
254
+
255
+ .data-table__header--center {
256
+ text-align: center;
257
+ }
258
+
259
+ .data-table__header--right {
260
+ text-align: right;
261
+ }
262
+
263
+ .data-table__header--sortable {
264
+ cursor: pointer;
265
+ transition: background-color 0.15s ease;
266
+ }
267
+
268
+ .data-table__header--sortable:hover {
269
+ background: var(--color-bg-hover, #f3f4f6);
270
+ }
271
+
272
+ .data-table__header--sortable:focus-visible {
273
+ outline: 2px solid var(--color-primary, #3b82f6);
274
+ outline-offset: -2px;
275
+ }
276
+
277
+ .data-table__header-content {
278
+ display: inline-flex;
279
+ align-items: center;
280
+ gap: var(--space-xs, 0.25rem);
281
+ }
282
+
283
+ /* Sort icon */
284
+ .data-table__sort-icon {
285
+ display: inline-flex;
286
+ width: 1rem;
287
+ height: 1rem;
288
+ color: var(--color-text-muted, #9ca3af);
289
+ transition: color 0.15s ease;
290
+ }
291
+
292
+ .data-table__sort-icon svg {
293
+ width: 100%;
294
+ height: 100%;
295
+ }
296
+
297
+ .data-table__sort-icon--active {
298
+ color: var(--color-primary, #3b82f6);
299
+ }
300
+
301
+ /* Body */
302
+ .data-table__body {
303
+ background: var(--color-bg-card, #ffffff);
304
+ }
305
+
306
+ /* Row */
307
+ .data-table__row {
308
+ border-bottom: 1px solid var(--color-border, #e5e7eb);
309
+ }
310
+
311
+ .data-table__row:last-child {
312
+ border-bottom: none;
313
+ }
314
+
315
+ /* Row hover */
316
+ .data-table--row-hover
317
+ .data-table__row:not(.data-table__row--skeleton):not(.data-table__row--empty):hover {
318
+ background: var(--color-bg-hover, #f9fafb);
319
+ }
320
+
321
+ /* Striped rows */
322
+ .data-table--striped .data-table__row:nth-child(even) {
323
+ background: var(--color-bg-muted, #f9fafb);
324
+ }
325
+
326
+ /* Cell */
327
+ .data-table__cell {
328
+ padding: var(--space-md, 0.75rem) var(--space-lg, 1rem);
329
+ color: var(--color-text, #1f2937);
330
+ vertical-align: middle;
331
+ }
332
+
333
+ .data-table__cell--left {
334
+ text-align: left;
335
+ }
336
+
337
+ .data-table__cell--center {
338
+ text-align: center;
339
+ }
340
+
341
+ .data-table__cell--right {
342
+ text-align: right;
343
+ }
344
+
345
+ .data-table__cell--empty {
346
+ padding: var(--space-2xl, 3rem) var(--space-lg, 1rem);
347
+ text-align: center;
348
+ }
349
+
350
+ /* Empty state */
351
+ .data-table__empty-default {
352
+ display: flex;
353
+ flex-direction: column;
354
+ align-items: center;
355
+ gap: var(--space-sm, 0.5rem);
356
+ color: var(--color-text-muted, #6b7280);
357
+ }
358
+
359
+ /* Skeleton loading */
360
+ .data-table__skeleton {
361
+ height: 1rem;
362
+ width: 75%;
363
+ background: linear-gradient(
364
+ 90deg,
365
+ var(--color-bg-muted, #e5e7eb) 25%,
366
+ var(--color-bg-skeleton-shine, #f3f4f6) 50%,
367
+ var(--color-bg-muted, #e5e7eb) 75%
368
+ );
369
+ background-size: 200% 100%;
370
+ animation: skeleton-shimmer 1.5s ease-in-out infinite;
371
+ border-radius: var(--radius-sm, 0.25rem);
372
+ }
373
+
374
+ .data-table__cell--center .data-table__skeleton {
375
+ margin: 0 auto;
376
+ }
377
+
378
+ .data-table__cell--right .data-table__skeleton {
379
+ margin-left: auto;
380
+ }
381
+
382
+ @keyframes skeleton-shimmer {
383
+ 0% {
384
+ background-position: 200% 0;
385
+ }
386
+ 100% {
387
+ background-position: -200% 0;
388
+ }
389
+ }
390
+
391
+ /* Dark mode support */
392
+ :global([data-theme='dark']) .data-table-container {
393
+ background: var(--color-bg-card-dark, #1f2937);
394
+ box-shadow: var(--shadow-sm-dark, 0 1px 2px 0 rgb(0 0 0 / 0.2));
395
+ }
396
+
397
+ :global([data-theme='dark']) .data-table__head {
398
+ background: var(--color-bg-muted-dark, #374151);
399
+ }
400
+
401
+ :global([data-theme='dark']) .data-table__header {
402
+ color: var(--color-text-muted-dark, #9ca3af);
403
+ border-bottom-color: var(--color-border-dark, #4b5563);
404
+ }
405
+
406
+ :global([data-theme='dark']) .data-table__header--sortable:hover {
407
+ background: var(--color-bg-hover-dark, #4b5563);
408
+ }
409
+
410
+ :global([data-theme='dark']) .data-table__body {
411
+ background: var(--color-bg-card-dark, #1f2937);
412
+ }
413
+
414
+ :global([data-theme='dark']) .data-table__row {
415
+ border-bottom-color: var(--color-border-dark, #374151);
416
+ }
417
+
418
+ :global([data-theme='dark'])
419
+ .data-table--row-hover
420
+ .data-table__row:not(.data-table__row--skeleton):not(.data-table__row--empty):hover {
421
+ background: var(--color-bg-hover-dark, #374151);
422
+ }
423
+
424
+ :global([data-theme='dark']) .data-table--striped .data-table__row:nth-child(even) {
425
+ background: var(--color-bg-muted-dark, #374151);
426
+ }
427
+
428
+ :global([data-theme='dark']) .data-table__cell {
429
+ color: var(--color-text-dark, #f9fafb);
430
+ }
431
+
432
+ :global([data-theme='dark']) .data-table__empty-default {
433
+ color: var(--color-text-muted-dark, #9ca3af);
434
+ }
435
+
436
+ :global([data-theme='dark']) .data-table__skeleton {
437
+ background: linear-gradient(
438
+ 90deg,
439
+ var(--color-bg-muted-dark, #374151) 25%,
440
+ var(--color-bg-skeleton-shine-dark, #4b5563) 50%,
441
+ var(--color-bg-muted-dark, #374151) 75%
442
+ );
443
+ background-size: 200% 100%;
444
+ }
445
+
446
+ /* Mobile touch targets */
447
+ @media (pointer: coarse) {
448
+ .data-table__header {
449
+ padding: var(--space-md, 0.75rem) var(--space-md, 0.75rem);
450
+ }
451
+
452
+ .data-table__cell {
453
+ padding: var(--space-md, 0.75rem) var(--space-md, 0.75rem);
454
+ }
455
+
456
+ .data-table__header--sortable {
457
+ min-height: 2.75rem;
458
+ }
459
+ }
460
+ </style>
@@ -0,0 +1,49 @@
1
+ /**
2
+ * DataTable - A sortable, customizable data table component
3
+ * Supports custom cell rendering, sorting, loading states, and responsive overflow
4
+ */
5
+ type SortOrder = 'asc' | 'desc';
6
+ type ColumnAlign = 'left' | 'center' | 'right';
7
+ interface ColumnDef {
8
+ /** Unique key matching the data property */
9
+ key: string;
10
+ /** Header text to display */
11
+ header: string;
12
+ /** Whether this column is sortable */
13
+ sortable?: boolean;
14
+ /** Fixed width (e.g., '100px', '10rem') */
15
+ width?: string;
16
+ /** Text alignment */
17
+ align?: ColumnAlign;
18
+ /** Custom cell renderer - receives (value, row) */
19
+ cell?: import('svelte').Snippet<[value: unknown, row: unknown]>;
20
+ }
21
+ interface Props {
22
+ /** Array of data objects to display */
23
+ data: unknown[];
24
+ /** Column definitions */
25
+ columns: ColumnDef[];
26
+ /** Currently sorted column key */
27
+ sortBy?: string;
28
+ /** Current sort direction */
29
+ sortOrder?: SortOrder;
30
+ /** Callback when sort changes */
31
+ onsort?: (column: string, order: SortOrder) => void;
32
+ /** Show loading skeleton */
33
+ loading?: boolean;
34
+ /** Number of skeleton rows to show when loading */
35
+ loadingRows?: number;
36
+ /** Custom empty state content */
37
+ empty?: import('svelte').Snippet;
38
+ /** Enable row hover effect */
39
+ rowHover?: boolean;
40
+ /** Enable striped rows */
41
+ striped?: boolean;
42
+ /** Make header sticky on scroll */
43
+ stickyHeader?: boolean;
44
+ /** Additional CSS classes */
45
+ class?: string;
46
+ }
47
+ declare const DataTable: import("svelte").Component<Props, {}, "sortBy" | "sortOrder">;
48
+ type DataTable = ReturnType<typeof DataTable>;
49
+ export default DataTable;
@@ -0,0 +1,2 @@
1
+ export { default as DataTable } from './DataTable.svelte';
2
+ export type { DataTableProps, DataTableColumn, DataTableSortOrder } from '../../types/index.js';
@@ -0,0 +1 @@
1
+ export { default as DataTable } from './DataTable.svelte';
@@ -212,6 +212,17 @@
212
212
  </text>
213
213
  {/if}
214
214
  {/each}
215
+
216
+ <!-- Background circle for center content -->
217
+ {#if showTotal}
218
+ <circle
219
+ cx={size / 2}
220
+ cy={size / 2}
221
+ r={innerRadius * 0.95}
222
+ fill="var(--color-bg, #ffffff)"
223
+ class="doughnut-chart__center-bg"
224
+ />
225
+ {/if}
215
226
  </svg>
216
227
 
217
228
  <!-- Center total -->
@@ -290,6 +301,11 @@
290
301
  pointer-events: none;
291
302
  }
292
303
 
304
+ /* Center Background */
305
+ .doughnut-chart__center-bg {
306
+ filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.1));
307
+ }
308
+
293
309
  /* Center */
294
310
  .doughnut-chart__center {
295
311
  position: absolute;
@@ -298,12 +314,13 @@
298
314
  transform: translate(-50%, -50%);
299
315
  text-align: center;
300
316
  pointer-events: none;
317
+ z-index: 10;
301
318
  }
302
319
 
303
320
  .doughnut-chart__total {
304
321
  display: block;
305
- font-size: var(--text-2xl, 1.5rem);
306
- font-weight: var(--font-bold, 700);
322
+ font-size: var(--text-lg, 1.125rem);
323
+ font-weight: var(--font-semibold, 600);
307
324
  color: var(--color-text, #1f2937);
308
325
  line-height: 1.2;
309
326
  }
@@ -314,6 +331,7 @@
314
331
  color: var(--color-text-muted, #6b7280);
315
332
  text-transform: uppercase;
316
333
  letter-spacing: 0.05em;
334
+ margin-top: 2px;
317
335
  }
318
336
 
319
337
  /* Legend */