@fastwork/xosmoz-svelte 0.0.21

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.
@@ -0,0 +1,1048 @@
1
+ <script lang="ts">
2
+ import { onDestroy } from 'svelte'
3
+ import {
4
+ detectDarkTheme,
5
+ watchThemeChanges,
6
+ } from '../../utils/themeDetection'
7
+ import { calculateAPCA } from '../../utils/colorCalculations'
8
+ import { createClipboardHandler } from '../../utils/clipboard'
9
+
10
+ let isDarkTheme = $state(false)
11
+
12
+ let cleanupThemeWatcher: (() => void) | null = null
13
+
14
+ // Update colors based on theme
15
+ function updateColors() {
16
+ isDarkTheme = detectDarkTheme()
17
+ }
18
+
19
+ // Initial theme detection and watch for changes
20
+ if (typeof window !== 'undefined') {
21
+ updateColors()
22
+ cleanupThemeWatcher = watchThemeChanges(updateColors)
23
+ }
24
+
25
+ // Cleanup observer on component destroy
26
+ onDestroy(() => {
27
+ if (cleanupThemeWatcher) {
28
+ cleanupThemeWatcher()
29
+ }
30
+ })
31
+
32
+ // Define theme color tokens - using CSS variables for dynamic theme switching
33
+ const themeColors = [
34
+ {
35
+ category: 'Base Background',
36
+ description:
37
+ 'Theme-agnostic surface colors that adapt to light and dark modes. Use these for page backgrounds, cards, panels, and layered surfaces.',
38
+ colors: [
39
+ {
40
+ name: 'bg.100',
41
+ token: '--xz-color-bg-100',
42
+ description:
43
+ 'Primary app background - Use for main page surface',
44
+ },
45
+ {
46
+ name: 'bg.200',
47
+ token: '--xz-color-bg-200',
48
+ description:
49
+ 'Secondary surface - Use for cards, modals, dropdowns',
50
+ },
51
+ {
52
+ name: 'bg.300',
53
+ token: '--xz-color-bg-300',
54
+ description:
55
+ 'Tertiary surface - Use for table headers, sidebars',
56
+ },
57
+ {
58
+ name: 'bg.400',
59
+ token: '--xz-color-bg-400',
60
+ description:
61
+ 'Elevated surface - Use for popovers, tooltips',
62
+ },
63
+ ],
64
+ },
65
+ {
66
+ category: 'Base Content',
67
+ description:
68
+ 'Universal text colors that maintain proper contrast across all themes. Use these for body text and supporting content.',
69
+ colors: [
70
+ {
71
+ name: 'content.100',
72
+ token: '--xz-color-content-100',
73
+ description:
74
+ 'Primary text - Use for headings, body text, labels',
75
+ },
76
+ {
77
+ name: 'content.200',
78
+ token: '--xz-color-content-200',
79
+ description:
80
+ 'Secondary text - Use for descriptions, helper text (60% opacity)',
81
+ },
82
+ ],
83
+ },
84
+ {
85
+ category: 'Base Line',
86
+ description:
87
+ 'Border and divider colors for creating visual separation. These adapt to theme and provide subtle to prominent boundaries.',
88
+ colors: [
89
+ {
90
+ name: 'line.100',
91
+ token: '--xz-color-line-100',
92
+ description:
93
+ 'Subtle border - Use for dividers, subtle separations (10% opacity)',
94
+ },
95
+ {
96
+ name: 'line.200',
97
+ token: '--xz-color-line-200',
98
+ description:
99
+ 'Standard border - Use for input fields, cards (20% opacity)',
100
+ },
101
+ {
102
+ name: 'line.300',
103
+ token: '--xz-color-line-300',
104
+ description:
105
+ 'Strong border - Use for active states, emphasis (30% opacity)',
106
+ },
107
+ ],
108
+ },
109
+ {
110
+ category: 'Primary',
111
+ description:
112
+ 'Brand identity colors for primary actions, links, and key UI elements. Built from the Fastwork color scale.',
113
+ colors: [
114
+ {
115
+ name: 'primary.soft.100',
116
+ token: '--xz-color-primary-soft-100',
117
+ description:
118
+ 'Subtle tint - Use for light backgrounds, tags, badges',
119
+ },
120
+ {
121
+ name: 'primary.soft.200',
122
+ token: '--xz-color-primary-soft-200',
123
+ description:
124
+ 'Soft background - Use for component hover states, highlights',
125
+ },
126
+ {
127
+ name: 'primary.soft.300',
128
+ token: '--xz-color-primary-soft-300',
129
+ description:
130
+ 'Soft active - Use for pressed states, selected items',
131
+ },
132
+ {
133
+ name: 'primary.line.100',
134
+ token: '--xz-color-primary-line-100',
135
+ description:
136
+ 'Subtle border - Use for focus rings, decorative lines',
137
+ },
138
+ {
139
+ name: 'primary.line.200',
140
+ token: '--xz-color-primary-line-200',
141
+ description:
142
+ 'Standard border - Use for outlined buttons, input focus',
143
+ },
144
+ {
145
+ name: 'primary.line.300',
146
+ token: '--xz-color-primary-line-300',
147
+ description:
148
+ 'Strong border - Use for emphasis, active borders',
149
+ },
150
+ {
151
+ name: 'primary.bg.100',
152
+ token: '--xz-color-primary-bg-100',
153
+ description:
154
+ 'Solid fill - Use for primary buttons, key actions',
155
+ },
156
+ {
157
+ name: 'primary.bg.200',
158
+ token: '--xz-color-primary-bg-200',
159
+ description: 'Solid hover - Use for button hover states',
160
+ },
161
+ {
162
+ name: 'primary.content.100',
163
+ token: '--xz-color-primary-content-100',
164
+ description:
165
+ 'Primary text - Use for links, primary text elements',
166
+ },
167
+ {
168
+ name: 'primary.content.200',
169
+ token: '--xz-color-primary-content-200',
170
+ description:
171
+ 'Emphasized text - Use for hovered links, strong emphasis',
172
+ },
173
+ {
174
+ name: 'primary.fg',
175
+ token: '--xz-color-primary-fg',
176
+ description:
177
+ 'Text on solid - Use for text on primary.bg buttons (white)',
178
+ },
179
+ ],
180
+ },
181
+ {
182
+ category: 'Danger',
183
+ description:
184
+ 'Error states and destructive actions. Use for validation errors, delete actions, and critical alerts. Built from the red color scale.',
185
+ colors: [
186
+ {
187
+ name: 'danger.soft.100',
188
+ token: '--xz-color-danger-soft-100',
189
+ description:
190
+ 'Subtle tint - Use for error backgrounds, alert panels',
191
+ },
192
+ {
193
+ name: 'danger.soft.200',
194
+ token: '--xz-color-danger-soft-200',
195
+ description:
196
+ 'Soft background - Use for error component states',
197
+ },
198
+ {
199
+ name: 'danger.soft.300',
200
+ token: '--xz-color-danger-soft-300',
201
+ description:
202
+ 'Soft active - Use for error hover/pressed states',
203
+ },
204
+ {
205
+ name: 'danger.line.100',
206
+ token: '--xz-color-danger-line-100',
207
+ description:
208
+ 'Subtle border - Use for error decorative lines',
209
+ },
210
+ {
211
+ name: 'danger.line.200',
212
+ token: '--xz-color-danger-line-200',
213
+ description:
214
+ 'Standard border - Use for error input borders',
215
+ },
216
+ {
217
+ name: 'danger.line.300',
218
+ token: '--xz-color-danger-line-300',
219
+ description:
220
+ 'Strong border - Use for critical error emphasis',
221
+ },
222
+ {
223
+ name: 'danger.bg.100',
224
+ token: '--xz-color-danger-bg-100',
225
+ description:
226
+ 'Solid fill - Use for delete buttons, destructive actions',
227
+ },
228
+ {
229
+ name: 'danger.bg.200',
230
+ token: '--xz-color-danger-bg-200',
231
+ description:
232
+ 'Solid hover - Use for destructive button hover',
233
+ },
234
+ {
235
+ name: 'danger.content.100',
236
+ token: '--xz-color-danger-content-100',
237
+ description:
238
+ 'Error text - Use for error messages, validation text',
239
+ },
240
+ {
241
+ name: 'danger.content.200',
242
+ token: '--xz-color-danger-content-200',
243
+ description:
244
+ 'Emphasized error - Use for critical error emphasis',
245
+ },
246
+ {
247
+ name: 'danger.fg',
248
+ token: '--xz-color-danger-fg',
249
+ description:
250
+ 'Text on solid - Use for text on danger.bg buttons (white)',
251
+ },
252
+ ],
253
+ },
254
+ {
255
+ category: 'Success',
256
+ description:
257
+ 'Success states and positive confirmations. Use for completed actions, valid inputs, and positive feedback. Built from the green color scale.',
258
+ colors: [
259
+ {
260
+ name: 'success.soft.100',
261
+ token: '--xz-color-success-soft-100',
262
+ description:
263
+ 'Subtle tint - Use for success backgrounds, confirmation panels',
264
+ },
265
+ {
266
+ name: 'success.soft.200',
267
+ token: '--xz-color-success-soft-200',
268
+ description:
269
+ 'Soft background - Use for success component states',
270
+ },
271
+ {
272
+ name: 'success.soft.300',
273
+ token: '--xz-color-success-soft-300',
274
+ description:
275
+ 'Soft active - Use for success hover/pressed states',
276
+ },
277
+ {
278
+ name: 'success.line.100',
279
+ token: '--xz-color-success-line-100',
280
+ description:
281
+ 'Subtle border - Use for success decorative lines',
282
+ },
283
+ {
284
+ name: 'success.line.200',
285
+ token: '--xz-color-success-line-200',
286
+ description:
287
+ 'Standard border - Use for valid input borders',
288
+ },
289
+ {
290
+ name: 'success.line.300',
291
+ token: '--xz-color-success-line-300',
292
+ description: 'Strong border - Use for success emphasis',
293
+ },
294
+ {
295
+ name: 'success.bg.100',
296
+ token: '--xz-color-success-bg-100',
297
+ description:
298
+ 'Solid fill - Use for success buttons, positive actions',
299
+ },
300
+ {
301
+ name: 'success.bg.200',
302
+ token: '--xz-color-success-bg-200',
303
+ description: 'Solid hover - Use for success button hover',
304
+ },
305
+ {
306
+ name: 'success.content.100',
307
+ token: '--xz-color-success-content-100',
308
+ description:
309
+ 'Success text - Use for success messages, confirmation text',
310
+ },
311
+ {
312
+ name: 'success.content.200',
313
+ token: '--xz-color-success-content-200',
314
+ description:
315
+ 'Emphasized success - Use for strong positive emphasis',
316
+ },
317
+ {
318
+ name: 'success.fg',
319
+ token: '--xz-color-success-fg',
320
+ description:
321
+ 'Text on solid - Use for text on success.bg buttons (white)',
322
+ },
323
+ ],
324
+ },
325
+ {
326
+ category: 'Warning',
327
+ description:
328
+ 'Warning states and cautionary messages. Use for important alerts, potential issues, and actions requiring attention. Built from the amber color scale.',
329
+ colors: [
330
+ {
331
+ name: 'warning.soft.100',
332
+ token: '--xz-color-warning-soft-100',
333
+ description:
334
+ 'Subtle tint - Use for warning backgrounds, alert panels',
335
+ },
336
+ {
337
+ name: 'warning.soft.200',
338
+ token: '--xz-color-warning-soft-200',
339
+ description:
340
+ 'Soft background - Use for warning component states',
341
+ },
342
+ {
343
+ name: 'warning.soft.300',
344
+ token: '--xz-color-warning-soft-300',
345
+ description:
346
+ 'Soft active - Use for warning hover/pressed states',
347
+ },
348
+ {
349
+ name: 'warning.line.100',
350
+ token: '--xz-color-warning-line-100',
351
+ description:
352
+ 'Subtle border - Use for warning decorative lines',
353
+ },
354
+ {
355
+ name: 'warning.line.200',
356
+ token: '--xz-color-warning-line-200',
357
+ description:
358
+ 'Standard border - Use for warning borders, caution lines',
359
+ },
360
+ {
361
+ name: 'warning.line.300',
362
+ token: '--xz-color-warning-line-300',
363
+ description:
364
+ 'Strong border - Use for important warning emphasis',
365
+ },
366
+ {
367
+ name: 'warning.bg.100',
368
+ token: '--xz-color-warning-bg-100',
369
+ description:
370
+ 'Solid fill - Use for warning buttons, caution actions',
371
+ },
372
+ {
373
+ name: 'warning.bg.200',
374
+ token: '--xz-color-warning-bg-200',
375
+ description: 'Solid hover - Use for warning button hover',
376
+ },
377
+ {
378
+ name: 'warning.content.100',
379
+ token: '--xz-color-warning-content-100',
380
+ description:
381
+ 'Warning text - Use for warning messages, alert text',
382
+ },
383
+ {
384
+ name: 'warning.content.200',
385
+ token: '--xz-color-warning-content-200',
386
+ description:
387
+ 'Emphasized warning - Use for critical warning emphasis',
388
+ },
389
+ {
390
+ name: 'warning.fg',
391
+ token: '--xz-color-warning-fg',
392
+ description:
393
+ 'Text on solid - Use for text on warning.bg buttons (white)',
394
+ },
395
+ ],
396
+ },
397
+ {
398
+ category: 'Info',
399
+ description:
400
+ 'Informational states and neutral messages. Use for help text, tips, general information, and educational content. Built from the cyan color scale.',
401
+ colors: [
402
+ {
403
+ name: 'info.soft.100',
404
+ token: '--xz-color-info-soft-100',
405
+ description:
406
+ 'Subtle tint - Use for info backgrounds, tip panels',
407
+ },
408
+ {
409
+ name: 'info.soft.200',
410
+ token: '--xz-color-info-soft-200',
411
+ description:
412
+ 'Soft background - Use for info component states',
413
+ },
414
+ {
415
+ name: 'info.soft.300',
416
+ token: '--xz-color-info-soft-300',
417
+ description:
418
+ 'Soft active - Use for info hover/pressed states',
419
+ },
420
+ {
421
+ name: 'info.line.100',
422
+ token: '--xz-color-info-line-100',
423
+ description:
424
+ 'Subtle border - Use for info decorative lines',
425
+ },
426
+ {
427
+ name: 'info.line.200',
428
+ token: '--xz-color-info-line-200',
429
+ description:
430
+ 'Standard border - Use for info borders, help lines',
431
+ },
432
+ {
433
+ name: 'info.line.300',
434
+ token: '--xz-color-info-line-300',
435
+ description:
436
+ 'Strong border - Use for important info emphasis',
437
+ },
438
+ {
439
+ name: 'info.bg.100',
440
+ token: '--xz-color-info-bg-100',
441
+ description:
442
+ 'Solid fill - Use for info buttons, educational actions',
443
+ },
444
+ {
445
+ name: 'info.bg.200',
446
+ token: '--xz-color-info-bg-200',
447
+ description: 'Solid hover - Use for info button hover',
448
+ },
449
+ {
450
+ name: 'info.content.100',
451
+ token: '--xz-color-info-content-100',
452
+ description: 'Info text - Use for info messages, help text',
453
+ },
454
+ {
455
+ name: 'info.content.200',
456
+ token: '--xz-color-info-content-200',
457
+ description:
458
+ 'Emphasized info - Use for important info emphasis',
459
+ },
460
+ {
461
+ name: 'info.fg',
462
+ token: '--xz-color-info-fg',
463
+ description:
464
+ 'Text on solid - Use for text on info.bg buttons (white)',
465
+ },
466
+ ],
467
+ },
468
+ ]
469
+
470
+ // Track copied state
471
+ let copiedVar = $state('')
472
+
473
+ // Create clipboard handler with state management
474
+ const copyToClipboard = createClipboardHandler(
475
+ () => copiedVar,
476
+ (val) => (copiedVar = val),
477
+ )
478
+
479
+ // Get computed CSS variable value
480
+ function getComputedValue(token: string): string {
481
+ if (typeof window !== 'undefined' && typeof document !== 'undefined') {
482
+ const value = getComputedStyle(document.documentElement)
483
+ .getPropertyValue(token)
484
+ .trim()
485
+ return value || 'Not defined'
486
+ }
487
+ return ''
488
+ }
489
+
490
+ // Determine foreground color for contrast display based on token name
491
+ function getForegroundToken(tokenName: string): string | null {
492
+ // For bg tokens of semantic colors (primary, danger, etc.), use their fg token
493
+ if (tokenName.includes('-bg-')) {
494
+ const parts = tokenName.split('-')
495
+ // Extract category (e.g., 'primary', 'danger', 'success', etc.)
496
+ const colorIndex = parts.findIndex((p) => p === 'color') + 1
497
+ const category = parts[colorIndex]
498
+ if (category && category !== 'bg') {
499
+ return `--xz-color-${category}-fg`
500
+ }
501
+ }
502
+ // Base background tokens should use content.100 as text
503
+ if (tokenName.includes('-bg-')) {
504
+ return '--xz-color-content-100'
505
+ }
506
+ // Soft tokens can have content on them
507
+ if (tokenName.includes('-soft-')) {
508
+ const parts = tokenName.split('-')
509
+ const colorIndex = parts.findIndex((p) => p === 'color') + 1
510
+ const category = parts[colorIndex]
511
+ return `--xz-color-${category}-content-100`
512
+ }
513
+ return null
514
+ }
515
+
516
+ // Check if we should show contrast for this token
517
+ function shouldShowContrast(tokenName: string): boolean {
518
+ // Show contrast for bg tokens (they have text on them)
519
+ if (tokenName.includes('-bg-')) {
520
+ return true
521
+ }
522
+ // Show contrast for soft tokens (they can have content on them)
523
+ if (tokenName.includes('-soft-')) {
524
+ return true
525
+ }
526
+ // Don't show contrast for fg, content, line tokens
527
+ return false
528
+ }
529
+ </script>
530
+
531
+ <div class="themes-page">
532
+ <div class="header">
533
+ <h1>Theme Colors</h1>
534
+ <p class="lead">
535
+ Semantic color tokens that automatically adapt to the active theme.
536
+ Switch between light and dark themes using the theme icon in the
537
+ toolbar above. All colors use OKLCH color space for optimal color
538
+ management and perceptual uniformity.
539
+ </p>
540
+ <div class="theme-indicator">
541
+ <span class="indicator-label">Current Theme:</span>
542
+ <span class="indicator-badge" class:dark={isDarkTheme}>
543
+ {isDarkTheme ? '🌙 Dark' : '☀️ Light'}
544
+ </span>
545
+ <span class="indicator-hint">
546
+ Switch using the theme icon in the toolbar
547
+ </span>
548
+ </div>
549
+ </div>
550
+
551
+ <!-- Usage Examples -->
552
+ <section class="usage-section">
553
+ <h2>How to Use</h2>
554
+
555
+ <div class="usage-example">
556
+ <h3>Importing Themes</h3>
557
+ <div class="example-block">
558
+ <pre><code
559
+ >import &#123; lightTheme, darkTheme &#125; from '@fastwork/xosmoz-theme'
560
+
561
+ // Access color values
562
+ const primaryColor = lightTheme.colors.primary.bg[100]
563
+ const backgroundColor = darkTheme.colors.bg[100]
564
+ const textColor = lightTheme.colors.content[100]</code
565
+ ></pre>
566
+ </div>
567
+ </div>
568
+
569
+ <div class="usage-example">
570
+ <h3>Using CSS Variables (Recommended)</h3>
571
+ <p class="usage-note">
572
+ For runtime theme switching, use CSS variables instead. They
573
+ automatically update when the theme changes.
574
+ </p>
575
+ <div class="example-block">
576
+ <pre><code
577
+ >/* In your CSS */
578
+ .button &#123;
579
+ background: var(--xz-color-primary-bg-100);
580
+ color: var(--xz-color-primary-fg);
581
+ border: 1px solid var(--xz-color-primary-line-200);
582
+ &#125;
583
+
584
+ .card &#123;
585
+ background: var(--xz-color-bg-100);
586
+ color: var(--xz-color-content-100);
587
+ &#125;</code
588
+ ></pre>
589
+ </div>
590
+ </div>
591
+ </section>
592
+
593
+ <!-- Theme Color Categories -->
594
+ {#each themeColors as category, idx (idx)}
595
+ <section class="section">
596
+ <div class="category-header">
597
+ <h2>{category.category}</h2>
598
+ <p>{category.description}</p>
599
+ </div>
600
+
601
+ <div class="color-table">
602
+ <div class="table-header">
603
+ <div class="col-preview">Preview</div>
604
+ <div class="col-name">Name</div>
605
+ <div class="col-token">CSS Variable</div>
606
+ <div class="col-value">Current Value</div>
607
+ </div>
608
+
609
+ {#each category.colors as color, idx (idx)}
610
+ {@const currentValue = getComputedValue(color.token)}
611
+ {@const hasAlpha =
612
+ currentValue.includes('rgba') ||
613
+ currentValue.includes('hsla') ||
614
+ currentValue.includes('transparent') ||
615
+ currentValue.includes('color-mix') ||
616
+ (currentValue.includes('oklch') &&
617
+ currentValue.match(/\/\s*0?\.\d+/))}
618
+ {@const fgToken = getForegroundToken(color.token)}
619
+ {@const showContrast =
620
+ shouldShowContrast(color.token) &&
621
+ currentValue !== 'Not defined'}
622
+ {@const bgValue = currentValue}
623
+ {@const fgValue = fgToken ? getComputedValue(fgToken) : ''}
624
+ {@const contrastRatio =
625
+ showContrast &&
626
+ fgValue &&
627
+ bgValue !== 'Not defined' &&
628
+ fgValue !== 'Not defined'
629
+ ? calculateAPCA(fgValue, bgValue)
630
+ : 0}
631
+ <div class="table-row">
632
+ <div class="col-preview">
633
+ <div
634
+ class="color-swatch"
635
+ class:has-alpha={hasAlpha &&
636
+ !color.token.includes('-line-')}
637
+ class:is-line={color.token.includes('-line-')}
638
+ style={color.token.includes('-line-')
639
+ ? `--line-color: var(${color.token});`
640
+ : hasAlpha
641
+ ? `--alpha-color: var(${color.token}); --text-color: var(${fgToken || '--xz-color-content-100'});`
642
+ : fgToken
643
+ ? `background: var(${color.token}); color: var(${fgToken});`
644
+ : `background: var(${color.token});`}
645
+ title="var({color.token})"
646
+ >
647
+ {#if !color.token.includes('-fg') && !color.token.includes('content') && !color.token.includes('-line-')}
648
+ <div
649
+ class="swatch-label"
650
+ class:show-contrast={showContrast &&
651
+ contrastRatio > 0}
652
+ style={hasAlpha && fgToken
653
+ ? 'color: var(--text-color);'
654
+ : ''}
655
+ >
656
+ A
657
+ {#if showContrast && contrastRatio > 0}
658
+ <span class="contrast-ratio"
659
+ >{contrastRatio}</span
660
+ >
661
+ {/if}
662
+ </div>
663
+ {/if}
664
+ </div>
665
+ </div>
666
+ <div class="col-name">
667
+ <code>{color.name}</code>
668
+ </div>
669
+ <div class="col-token">
670
+ <button
671
+ class="token-button"
672
+ class:copied={copiedVar === color.token}
673
+ onclick={() => copyToClipboard(color.token)}
674
+ title="Click to copy CSS variable"
675
+ >
676
+ {color.token}
677
+ </button>
678
+ </div>
679
+ <div class="col-value">
680
+ <button
681
+ class="value-button"
682
+ class:copied={copiedVar === currentValue}
683
+ onclick={() => copyToClipboard(currentValue)}
684
+ title="Click to copy {currentValue.includes(
685
+ 'oklch',
686
+ )
687
+ ? 'OKLCH'
688
+ : currentValue.includes('color-mix')
689
+ ? 'color-mix()'
690
+ : ''} value"
691
+ >
692
+ {currentValue}
693
+ </button>
694
+ </div>
695
+ </div>
696
+ {/each}
697
+ </div>
698
+ </section>
699
+ {/each}
700
+ </div>
701
+
702
+ <style>
703
+ .themes-page {
704
+ font-family: var(--xz-font-family-primary, system-ui);
705
+ padding: 2rem;
706
+ max-width: 100%;
707
+ background: var(--xz-color-bg-100);
708
+ color: var(--xz-color-content-100);
709
+ min-height: 100vh;
710
+ overflow: hidden;
711
+ }
712
+
713
+ .header {
714
+ margin-bottom: 3rem;
715
+ }
716
+
717
+ h1 {
718
+ font-size: 2.5rem;
719
+ font-weight: 700;
720
+ margin-bottom: 0.75rem;
721
+ color: var(--xz-color-content-100);
722
+ }
723
+
724
+ .lead {
725
+ font-size: 1.125rem;
726
+ color: var(--xz-color-content-200);
727
+ line-height: 1.6;
728
+ max-width: 800px;
729
+ }
730
+
731
+ .theme-indicator {
732
+ display: flex;
733
+ align-items: center;
734
+ gap: 0.75rem;
735
+ margin-top: 1.5rem;
736
+ padding: 1rem;
737
+ background: var(--xz-color-bg-200);
738
+ border-radius: var(--xz-radius-md, 0.375rem);
739
+ border: 1px solid var(--xz-color-line-100);
740
+ max-width: fit-content;
741
+ }
742
+
743
+ .indicator-label {
744
+ font-size: 0.875rem;
745
+ font-weight: 600;
746
+ color: var(--xz-color-content-100);
747
+ }
748
+
749
+ .indicator-badge {
750
+ padding: 0.375rem 0.75rem;
751
+ border-radius: var(--xz-radius-sm, 0.25rem);
752
+ font-size: 0.875rem;
753
+ font-weight: 600;
754
+ background: var(--xz-color-primary-soft-200);
755
+ color: var(--xz-color-primary-content-100);
756
+ transition: all 0.2s;
757
+ }
758
+
759
+ .indicator-badge.dark {
760
+ background: var(--xz-color-primary-soft-300);
761
+ color: var(--xz-color-primary-content-200);
762
+ }
763
+
764
+ .indicator-hint {
765
+ font-size: 0.8125rem;
766
+ color: var(--xz-color-content-200);
767
+ font-style: italic;
768
+ }
769
+
770
+ /* Usage Section */
771
+ .usage-section {
772
+ margin-bottom: 4rem;
773
+ }
774
+
775
+ .usage-section h2 {
776
+ font-size: 1.75rem;
777
+ font-weight: 600;
778
+ color: var(--xz-color-content-100);
779
+ margin-bottom: 2rem;
780
+ }
781
+
782
+ .usage-example {
783
+ margin-bottom: 2.5rem;
784
+ }
785
+
786
+ .usage-example h3 {
787
+ font-size: 1.25rem;
788
+ font-weight: 600;
789
+ color: var(--xz-color-content-100);
790
+ margin-bottom: 0.75rem;
791
+ }
792
+
793
+ .usage-note {
794
+ font-size: 0.9375rem;
795
+ color: var(--xz-color-content-200);
796
+ line-height: 1.6;
797
+ margin-bottom: 1rem;
798
+ }
799
+
800
+ .usage-note code {
801
+ background: var(--xz-color-bg-300);
802
+ padding: 0.125rem 0.375rem;
803
+ border-radius: var(--xz-radius-sm, 0.25rem);
804
+ font-family: var(--xz-font-family-mono, monospace);
805
+ font-size: 0.9em;
806
+ color: var(--xz-color-primary-content-100);
807
+ }
808
+
809
+ .example-block {
810
+ background: var(--xz-color-bg-300);
811
+ border-radius: var(--xz-radius-md, 0.375rem);
812
+ border: 1px solid var(--xz-color-line-200);
813
+ overflow: hidden;
814
+ }
815
+
816
+ .example-block pre {
817
+ margin: 0;
818
+ padding: 1.25rem;
819
+ overflow-x: auto;
820
+ }
821
+
822
+ .example-block code {
823
+ font-family: var(--xz-font-family-mono, monospace);
824
+ font-size: 0.875rem;
825
+ line-height: 1.6;
826
+ color: var(--xz-color-content-100);
827
+ }
828
+
829
+ .section {
830
+ margin-bottom: 4rem;
831
+ }
832
+
833
+ .category-header {
834
+ margin-bottom: 1.5rem;
835
+ }
836
+
837
+ .category-header h2 {
838
+ font-size: 1.5rem;
839
+ font-weight: 600;
840
+ margin-bottom: 0.25rem;
841
+ color: var(--xz-color-content-100);
842
+ }
843
+
844
+ .category-header p {
845
+ font-size: 0.9375rem;
846
+ color: var(--xz-color-content-200);
847
+ line-height: 1.6;
848
+ margin: 0;
849
+ }
850
+
851
+ /* Table Styles */
852
+ .color-table {
853
+ margin-top: 1rem;
854
+ }
855
+
856
+ .table-header {
857
+ display: grid;
858
+ grid-template-columns: 80px 1fr 2fr 1.5fr;
859
+ gap: 1rem;
860
+ padding: 0.75rem 1rem;
861
+ background: var(--xz-color-bg-300);
862
+ border-radius: var(--xz-radius-md, 0.375rem);
863
+ font-weight: 600;
864
+ font-size: 0.875rem;
865
+ color: var(--xz-color-content-100);
866
+ margin-bottom: 0.5rem;
867
+ }
868
+
869
+ .table-row {
870
+ display: grid;
871
+ grid-template-columns: 80px 1fr 2fr 1.5fr;
872
+ gap: 1rem;
873
+ padding: 0.75rem 1rem;
874
+ align-items: center;
875
+ border-bottom: 1px solid var(--xz-color-border);
876
+ transition: background-color 0.15s;
877
+ }
878
+
879
+ .table-row:hover {
880
+ background: var(--xz-color-bg-200);
881
+ }
882
+
883
+ .table-row:last-child {
884
+ border-bottom: none;
885
+ }
886
+
887
+ .color-swatch {
888
+ width: 48px;
889
+ height: 48px;
890
+ border-radius: var(--xz-radius-md, 0.375rem);
891
+ border: 1px solid rgba(0, 0, 0, 0.1);
892
+ cursor: pointer;
893
+ transition: transform 0.15s;
894
+ position: relative;
895
+ display: flex;
896
+ align-items: center;
897
+ justify-content: center;
898
+ }
899
+
900
+ /* Line colors show only the border */
901
+ .color-swatch.is-line {
902
+ background: transparent;
903
+ border: 1px solid var(--line-color);
904
+ }
905
+
906
+ .color-swatch.has-alpha {
907
+ background-image:
908
+ linear-gradient(45deg, #e0e0e0 25%, transparent 25%),
909
+ linear-gradient(-45deg, #e0e0e0 25%, transparent 25%),
910
+ linear-gradient(45deg, transparent 75%, #e0e0e0 75%),
911
+ linear-gradient(-45deg, transparent 75%, #e0e0e0 75%);
912
+ background-size: 8px 8px;
913
+ background-position:
914
+ 0 0,
915
+ 0 4px,
916
+ 4px -4px,
917
+ -4px 0px;
918
+ background-color: #f5f5f5;
919
+ }
920
+
921
+ .color-swatch.has-alpha::before {
922
+ content: '';
923
+ position: absolute;
924
+ inset: 0;
925
+ background-color: var(--alpha-color);
926
+ border-radius: inherit;
927
+ }
928
+
929
+ .color-swatch.has-alpha .swatch-label {
930
+ color: var(--text-color);
931
+ }
932
+
933
+ .color-swatch:hover {
934
+ transform: scale(1.05);
935
+ }
936
+
937
+ .swatch-label {
938
+ font-size: 1.25rem;
939
+ font-weight: 700;
940
+ opacity: 1;
941
+ user-select: none;
942
+ position: relative;
943
+ z-index: 1;
944
+ display: flex;
945
+ flex-direction: column;
946
+ align-items: center;
947
+ gap: 0.125rem;
948
+ }
949
+
950
+ .swatch-label.show-contrast {
951
+ opacity: 1;
952
+ }
953
+
954
+ .contrast-ratio {
955
+ font-size: 0.5rem;
956
+ font-weight: 500;
957
+ opacity: 0.7;
958
+ line-height: 1;
959
+ }
960
+
961
+ .col-name code {
962
+ font-family: var(--xz-font-family-mono, monospace);
963
+ font-size: 0.875rem;
964
+ color: var(--xz-color-primary-content-100);
965
+ font-weight: 500;
966
+ }
967
+
968
+ .token-button,
969
+ .value-button {
970
+ background: none;
971
+ border: none;
972
+ padding: 0.375rem 0.5rem;
973
+ font-family: var(--xz-font-family-mono, monospace);
974
+ font-size: 0.875rem;
975
+ color: var(--xz-color-primary-content-100);
976
+ cursor: pointer;
977
+ border-radius: var(--xz-radius-sm, 0.25rem);
978
+ transition: all 0.15s;
979
+ text-align: left;
980
+ width: 100%;
981
+ }
982
+
983
+ .token-button:hover,
984
+ .value-button:hover {
985
+ background: var(--xz-color-bg-300);
986
+ }
987
+
988
+ .token-button.copied,
989
+ .value-button.copied {
990
+ background: var(--xz-color-success-bg-100);
991
+ color: white;
992
+ }
993
+
994
+ .col-value {
995
+ font-size: 0.875rem;
996
+ }
997
+
998
+ /* Responsive */
999
+ @media (max-width: 768px) {
1000
+ .themes-page {
1001
+ padding: 1rem;
1002
+ }
1003
+
1004
+ h1 {
1005
+ font-size: 2rem;
1006
+ }
1007
+
1008
+ .usage-section h2 {
1009
+ font-size: 1.5rem;
1010
+ }
1011
+
1012
+ .example-block pre {
1013
+ padding: 1rem;
1014
+ }
1015
+
1016
+ .example-block code {
1017
+ font-size: 0.8125rem;
1018
+ }
1019
+
1020
+ .table-header {
1021
+ display: none;
1022
+ }
1023
+
1024
+ .table-row {
1025
+ grid-template-columns: 1fr;
1026
+ gap: 0.75rem;
1027
+ padding: 1rem;
1028
+ }
1029
+
1030
+ .col-preview {
1031
+ display: flex;
1032
+ align-items: center;
1033
+ gap: 1rem;
1034
+ }
1035
+
1036
+ .col-name,
1037
+ .col-token,
1038
+ .col-value {
1039
+ font-size: 0.8125rem;
1040
+ }
1041
+
1042
+ .token-button,
1043
+ .value-button {
1044
+ font-size: 0.75rem;
1045
+ padding: 0.25rem 0.375rem;
1046
+ }
1047
+ }
1048
+ </style>