@refrakt-md/lumina 0.7.2 → 0.8.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.
@@ -6,12 +6,42 @@
6
6
  --mockup-bezel: var(--mockup-bezel-dark);
7
7
  --mockup-chrome: #2a2a2a;
8
8
  --mockup-chrome-text: #999;
9
- --mockup-shadow: var(--rf-shadow-lg);
10
9
  --mockup-scale: 1;
11
- display: inline-block;
10
+ display: block;
11
+ width: 100%;
12
+ container-type: inline-size;
12
13
  margin: 1.5rem 0;
13
- transform: scale(var(--mockup-scale));
14
+ background-color: transparent;
15
+ }
16
+
17
+ /* Inside a placed showcase, let device frame use natural width */
18
+ .rf-showcase[data-place] .rf-mockup {
19
+ width: auto;
20
+ max-width: 100%;
21
+ container-type: normal;
22
+ }
23
+ .rf-showcase[data-place] .rf-mockup__frame {
24
+ zoom: var(--mockup-scale, 1);
25
+ }
26
+
27
+ /* ── Fit mode: none (native pixel size) ── */
28
+
29
+ .rf-mockup[data-fit="none"] {
30
+ display: inline-block;
31
+ width: auto;
32
+ container-type: normal;
33
+ }
34
+
35
+ .rf-mockup[data-fit="none"] .rf-mockup__frame {
36
+ zoom: normal;
37
+ transform: scale(var(--mockup-scale, 1));
14
38
  transform-origin: top center;
39
+ margin-inline: 0;
40
+ }
41
+
42
+ .rf-mockup[data-fit="none"].rf-mockup--browser,
43
+ .rf-mockup[data-fit="none"].rf-mockup--browser-dark {
44
+ display: block;
15
45
  }
16
46
 
17
47
  /* ── Color modifiers ── */
@@ -20,14 +50,12 @@
20
50
  --mockup-bezel: var(--mockup-bezel-dark);
21
51
  --mockup-chrome: #2a2a2a;
22
52
  --mockup-chrome-text: #999;
23
- --mockup-shadow: 0 8px 24px rgba(0, 0, 0, 0.25), 0 2px 6px rgba(0, 0, 0, 0.15);
24
53
  }
25
54
 
26
55
  .rf-mockup--light {
27
56
  --mockup-bezel: var(--mockup-bezel-light);
28
57
  --mockup-chrome: #f5f5f5;
29
58
  --mockup-chrome-text: #666;
30
- --mockup-shadow: 0 8px 24px rgba(0, 0, 0, 0.1), 0 2px 6px rgba(0, 0, 0, 0.06);
31
59
  }
32
60
 
33
61
  .rf-mockup--auto {
@@ -40,7 +68,8 @@
40
68
 
41
69
  .rf-mockup__frame {
42
70
  position: relative;
43
- box-shadow: var(--mockup-shadow);
71
+ margin-inline: auto;
72
+ zoom: calc(var(--mockup-scale, 1) * min(1, tan(atan2(100cqi, var(--mockup-device-width, 100cqi)))));
44
73
  }
45
74
 
46
75
  /* ── Viewport (content area) ── */
@@ -49,6 +78,9 @@
49
78
  overflow: auto;
50
79
  background: var(--rf-color-bg);
51
80
  }
81
+ .rf-mockup__viewport img {
82
+ display: block;
83
+ }
52
84
 
53
85
  .rf-mockup__viewport > *:first-child {
54
86
  margin-top: 0;
@@ -165,6 +197,7 @@
165
197
  /* ── iPhone 15 ── */
166
198
 
167
199
  .rf-mockup--iphone-15 .rf-mockup__frame {
200
+ --mockup-device-width: 393px;
168
201
  width: 393px;
169
202
  border-radius: 55px;
170
203
  }
@@ -182,6 +215,7 @@
182
215
  /* ── iPhone SE ── */
183
216
 
184
217
  .rf-mockup--iphone-se .rf-mockup__frame {
218
+ --mockup-device-width: 375px;
185
219
  width: 375px;
186
220
  border-radius: 40px;
187
221
  }
@@ -223,6 +257,7 @@
223
257
  /* ── Pixel ── */
224
258
 
225
259
  .rf-mockup--pixel .rf-mockup__frame {
260
+ --mockup-device-width: 412px;
226
261
  width: 412px;
227
262
  border-radius: 40px;
228
263
  }
@@ -239,6 +274,7 @@
239
274
  /* ── Generic phone ── */
240
275
 
241
276
  .rf-mockup--phone .rf-mockup__frame {
277
+ --mockup-device-width: 390px;
242
278
  width: 390px;
243
279
  border-radius: 48px;
244
280
  }
@@ -259,6 +295,7 @@
259
295
  /* ── iPad ── */
260
296
 
261
297
  .rf-mockup--ipad .rf-mockup__frame {
298
+ --mockup-device-width: 820px;
262
299
  width: 820px;
263
300
  border-radius: 24px;
264
301
  }
@@ -275,6 +312,7 @@
275
312
  /* ── Generic tablet ── */
276
313
 
277
314
  .rf-mockup--tablet .rf-mockup__frame {
315
+ --mockup-device-width: 800px;
278
316
  width: 800px;
279
317
  border-radius: 20px;
280
318
  }
@@ -357,7 +395,6 @@
357
395
 
358
396
  .rf-mockup--browser .rf-mockup__frame {
359
397
  width: 100%;
360
- max-width: 960px;
361
398
  border-radius: var(--rf-radius-lg) var(--rf-radius-lg) 0 0;
362
399
  overflow: hidden;
363
400
  }
@@ -367,7 +404,7 @@
367
404
  }
368
405
 
369
406
  .rf-mockup--browser .rf-mockup__viewport {
370
- height: 800px;
407
+ min-height: 12rem;
371
408
  border: 1px solid var(--rf-color-border);
372
409
  border-top: none;
373
410
  }
@@ -376,7 +413,6 @@
376
413
 
377
414
  .rf-mockup--browser-dark .rf-mockup__frame {
378
415
  width: 100%;
379
- max-width: 960px;
380
416
  border-radius: var(--rf-radius-lg) var(--rf-radius-lg) 0 0;
381
417
  overflow: hidden;
382
418
  }
@@ -391,7 +427,7 @@
391
427
  }
392
428
 
393
429
  .rf-mockup--browser-dark .rf-mockup__viewport {
394
- height: 800px;
430
+ min-height: 12rem;
395
431
  border: 1px solid rgba(255, 255, 255, 0.1);
396
432
  border-top: none;
397
433
  }
@@ -399,8 +435,8 @@
399
435
  /* ── MacBook ── */
400
436
 
401
437
  .rf-mockup--macbook .rf-mockup__frame {
438
+ --mockup-device-width: 1440px;
402
439
  width: 1440px;
403
- max-width: 100%;
404
440
  }
405
441
 
406
442
  .rf-mockup--macbook .rf-mockup__title-bar {
@@ -410,7 +446,7 @@
410
446
  }
411
447
 
412
448
  .rf-mockup--macbook .rf-mockup__viewport {
413
- height: 900px;
449
+ min-height: 12rem;
414
450
  border: 3px solid var(--mockup-bezel);
415
451
  border-top: none;
416
452
  border-bottom: none;
@@ -441,6 +477,7 @@
441
477
  /* ── Watch ── */
442
478
 
443
479
  .rf-mockup--watch .rf-mockup__frame {
480
+ --mockup-device-width: 198px;
444
481
  width: 198px;
445
482
  border-radius: 40px;
446
483
  position: relative;
@@ -469,10 +506,6 @@
469
506
 
470
507
  /* ── None (no frame) ── */
471
508
 
472
- .rf-mockup--none .rf-mockup__frame {
473
- box-shadow: none;
474
- }
475
-
476
509
  .rf-mockup--none .rf-mockup__viewport {
477
510
  border: 1px dashed var(--rf-color-border);
478
511
  border-radius: var(--rf-radius-sm);
@@ -482,6 +515,9 @@
482
515
  CONTEXT: inside preview
483
516
  ═══════════════════════════════════════ */
484
517
 
518
+ .rf-grid .rf-mockup {
519
+ justify-self: center;
520
+ }
485
521
  .rf-preview .rf-mockup {
486
522
  margin: 0;
487
523
  }
@@ -12,6 +12,7 @@
12
12
  gap: 3rem;
13
13
  align-items: start;
14
14
  }
15
+
15
16
  @media (max-width: 768px) {
16
17
  .rf-page-section--split {
17
18
  grid-template-columns: 1fr;
@@ -0,0 +1,88 @@
1
+ /* Playlist */
2
+ .rf-playlist {
3
+ border: 1px solid var(--rf-color-border);
4
+ border-radius: var(--rf-radius-lg);
5
+ margin: 1.5rem 0;
6
+ overflow: hidden;
7
+ }
8
+
9
+ /* Header: cover art + title + description */
10
+ .rf-playlist__header {
11
+ display: flex;
12
+ flex-direction: column;
13
+ gap: 0.75rem;
14
+ padding: 1.5rem 1.5rem 1rem;
15
+ }
16
+ .rf-playlist__header img {
17
+ width: 100%;
18
+ max-width: 200px;
19
+ aspect-ratio: 1;
20
+ object-fit: cover;
21
+ border-radius: var(--rf-radius-md);
22
+ }
23
+ .rf-playlist__header h1,
24
+ .rf-playlist__header h2,
25
+ .rf-playlist__header h3,
26
+ .rf-playlist__header h4,
27
+ .rf-playlist__header h5,
28
+ .rf-playlist__header h6 {
29
+ margin: 0;
30
+ font-size: 1.25rem;
31
+ font-weight: 700;
32
+ color: var(--rf-color-text);
33
+ }
34
+ .rf-playlist__header p {
35
+ margin: 0;
36
+ font-size: 0.875rem;
37
+ color: var(--rf-color-muted);
38
+ line-height: 1.5;
39
+ }
40
+
41
+ /* Type badge */
42
+ .rf-playlist__type-badge {
43
+ display: inline-block;
44
+ font-size: 0.7rem;
45
+ font-weight: 600;
46
+ text-transform: uppercase;
47
+ letter-spacing: 0.05em;
48
+ padding: 0.125rem 0.5rem;
49
+ border-radius: var(--rf-radius-full);
50
+ color: var(--rf-color-primary);
51
+ background: color-mix(in srgb, var(--rf-color-primary) 10%, transparent);
52
+ width: fit-content;
53
+ }
54
+
55
+ /* Type-specific badge colors via data attributes */
56
+ [data-type="podcast"] > .rf-playlist__header .rf-playlist__type-badge {
57
+ color: var(--rf-color-info);
58
+ background: var(--rf-color-info-bg);
59
+ }
60
+ [data-type="audiobook"] > .rf-playlist__header .rf-playlist__type-badge {
61
+ color: var(--rf-color-success);
62
+ background: var(--rf-color-success-bg);
63
+ }
64
+
65
+ /* Tracks list wrapper */
66
+ .rf-playlist__tracks {
67
+ list-style: none;
68
+ padding: 0;
69
+ margin: 0;
70
+ border-top: 1px solid var(--rf-color-border);
71
+ }
72
+
73
+ /* Player area */
74
+ .rf-playlist__player {
75
+ padding: 0.75rem 1.5rem;
76
+ border-top: 1px solid var(--rf-color-border);
77
+ }
78
+
79
+ @media (min-width: 480px) {
80
+ .rf-playlist__header {
81
+ flex-direction: row;
82
+ align-items: flex-start;
83
+ gap: 1.25rem;
84
+ }
85
+ .rf-playlist__header img {
86
+ flex-shrink: 0;
87
+ }
88
+ }
@@ -7,10 +7,6 @@
7
7
  }
8
8
 
9
9
  /* Width variants */
10
- .rf-preview[data-width="medium"] {
11
- width: calc(100% + 4rem);
12
- margin-left: -2rem;
13
- }
14
10
  @container (min-width: 1008px) {
15
11
  .rf-preview[data-width="wide"] {
16
12
  width: calc(100% + 8rem);
@@ -93,6 +89,9 @@
93
89
  padding: 2rem 2.5rem;
94
90
  background: var(--rf-color-bg);
95
91
  }
92
+ .rf-preview__canvas:has(.rf-mockup) {
93
+ text-align: center;
94
+ }
96
95
  .rf-preview__canvas > *:first-child {
97
96
  margin-top: 0;
98
97
  }
@@ -66,8 +66,8 @@
66
66
  font-weight: 600;
67
67
  margin: 0 0 0.5rem;
68
68
  }
69
- .rf-reveal-step__body span[property],
70
- .rf-reveal-step__body meta { display: none; }
69
+ .rf-reveal-step__body > span[property],
70
+ .rf-reveal-step__body > meta { display: none; }
71
71
  .rf-reveal-step__body p:last-child { margin-bottom: 0; }
72
72
  .rf-reveal__next,
73
73
  .rf-reveal__reset {
@@ -0,0 +1,94 @@
1
+ /* Showcase — Media presentation wrapper with shadows, bleed, and aspect ratio */
2
+ .rf-showcase {
3
+ position: relative;
4
+ }
5
+ .rf-showcase__viewport {
6
+ position: relative;
7
+ }
8
+ /* Shadows */
9
+ .rf-showcase[data-shadow="soft"] {
10
+ filter: drop-shadow(0 4px 12px rgba(0, 0, 0, 0.1));
11
+ }
12
+ .rf-showcase[data-shadow="hard"] {
13
+ filter: drop-shadow(0 2px 8px rgba(0, 0, 0, 0.25));
14
+ }
15
+ .rf-showcase[data-shadow="elevated"] {
16
+ filter: drop-shadow(0 12px 40px rgba(0, 0, 0, 0.2));
17
+ }
18
+ /* Bleed displacement via negative margins */
19
+ .rf-showcase[data-bleed="top"] {
20
+ margin-top: calc(-1 * var(--showcase-offset, 2rem));
21
+ position: relative;
22
+ z-index: 1;
23
+ }
24
+ .rf-showcase[data-bleed="bottom"] {
25
+ margin-bottom: calc(-1 * var(--showcase-offset, 2rem));
26
+ position: relative;
27
+ z-index: 1;
28
+ }
29
+ .rf-showcase[data-bleed="both"] {
30
+ margin-top: calc(-1 * var(--showcase-offset, 2rem));
31
+ margin-bottom: calc(-1 * var(--showcase-offset, 2rem));
32
+ position: relative;
33
+ z-index: 1;
34
+ }
35
+ .rf-showcase[data-bleed="end"] {
36
+ margin-inline-end: calc(-1 * var(--showcase-offset, 2rem));
37
+ position: relative;
38
+ z-index: 1;
39
+ }
40
+ .rf-showcase[data-bleed="bottom-end"] {
41
+ margin-bottom: calc(-1 * var(--showcase-offset, 2rem));
42
+ margin-inline-end: calc(-1 * var(--showcase-offset, 2rem));
43
+ position: relative;
44
+ z-index: 1;
45
+ }
46
+ .rf-showcase[data-bleed="top-end"] {
47
+ margin-top: calc(-1 * var(--showcase-offset, 2rem));
48
+ margin-inline-end: calc(-1 * var(--showcase-offset, 2rem));
49
+ position: relative;
50
+ z-index: 1;
51
+ }
52
+ /* Parent needs overflow visible for bleed — except inside clipping containers like bento cells */
53
+ :has(> .rf-showcase[data-bleed]:not(.rf-showcase--in-bento-cell)) {
54
+ overflow: visible;
55
+ }
56
+ /* Bento cell context — showcase fills remaining space */
57
+ .rf-showcase--in-bento-cell {
58
+ flex: 1;
59
+ min-height: 0;
60
+ }
61
+ /* Aspect ratio enforcement */
62
+ .rf-showcase[data-aspect] .rf-showcase__viewport {
63
+ aspect-ratio: var(--showcase-aspect);
64
+ overflow: hidden;
65
+ }
66
+ .rf-showcase[data-aspect] .rf-showcase__viewport > img,
67
+ .rf-showcase[data-aspect] .rf-showcase__viewport > video {
68
+ width: 100%;
69
+ height: 100%;
70
+ object-fit: cover;
71
+ }
72
+ /* Self-positioning within parent via place attribute */
73
+ .rf-showcase[data-place] {
74
+ justify-self: var(--place-x, auto);
75
+ align-self: var(--place-y, auto);
76
+ }
77
+ /* Spacing — vertical margin around the showcase */
78
+ .rf-showcase[data-spacing="flush"] { margin-top: 0; margin-bottom: 0; }
79
+ .rf-showcase[data-spacing="tight"] { margin-top: var(--rf-spacing-section-tight, 1.5rem); margin-bottom: var(--rf-spacing-section-tight, 1.5rem); }
80
+ .rf-showcase[data-spacing="loose"] { margin-top: var(--rf-spacing-section-loose, 8rem); margin-bottom: var(--rf-spacing-section-loose, 8rem); }
81
+ .rf-showcase[data-spacing="breathe"] { margin-top: var(--rf-spacing-section-breathe, 12rem); margin-bottom: var(--rf-spacing-section-breathe, 12rem); }
82
+ /* Inset — all-around padding (not just inline, since showcase is a contained frame) */
83
+ .rf-showcase[data-inset="flush"] { padding: 0; }
84
+ .rf-showcase[data-inset="tight"] { padding: var(--rf-inset-tight, 1rem); }
85
+ .rf-showcase[data-inset="loose"] { padding: var(--rf-inset-loose, 4rem); }
86
+ .rf-showcase[data-inset="breathe"] { padding: var(--rf-inset-breathe, 8rem); }
87
+ /* Responsive: collapse bleed on mobile */
88
+ @media (max-width: 768px) {
89
+ .rf-showcase[data-bleed] {
90
+ margin-top: 0;
91
+ margin-bottom: 0;
92
+ margin-inline-end: 0;
93
+ }
94
+ }
@@ -44,7 +44,7 @@
44
44
  padding-left: 0;
45
45
  margin: 0;
46
46
  }
47
- .rf-step__main {
47
+ .rf-step__content {
48
48
  display: contents;
49
49
  }
50
50
  .rf-step {
@@ -99,15 +99,7 @@
99
99
  font-size: 0.925rem;
100
100
  line-height: 1.65;
101
101
  }
102
- .rf-step--split {
103
- display: grid;
104
- grid-template-columns: 1fr 1fr;
105
- gap: 2rem;
106
- }
107
- .rf-step--mirror .rf-step__showcase {
108
- order: -1;
109
- }
110
- .rf-step__showcase {
102
+ .rf-step__media {
111
103
  border-radius: var(--rf-radius-md);
112
104
  overflow: hidden;
113
105
  }
@@ -54,8 +54,8 @@
54
54
  height: auto;
55
55
  display: block;
56
56
  }
57
- .rf-storyboard-panel__body span[property],
58
- .rf-storyboard-panel__body meta { display: none; }
57
+ .rf-storyboard-panel__body > span[property],
58
+ .rf-storyboard-panel__body > meta { display: none; }
59
59
  .rf-storyboard-panel__body p:last-child { margin-bottom: 0; }
60
60
  @media (max-width: 768px) {
61
61
  .rf-storyboard__panels { grid-template-columns: repeat(2, 1fr) !important; }
@@ -0,0 +1,203 @@
1
+ /* Tint Rune — Colour Token Bridge
2
+ *
3
+ * Maps --tint-* custom properties (set by the identity transform) to
4
+ * Lumina's internal --rf-color-* tokens.
5
+ *
6
+ * The six bridgeable tokens are registered with @property so that when a
7
+ * tint doesn't override a particular token, the property falls back to
8
+ * its inherited value instead of becoming guaranteed-invalid (which would
9
+ * happen with a self-referencing var() fallback — a CSS cycle). */
10
+
11
+ /* ── 0. Token registration ────────────────────────────────────────────────
12
+ * @property makes guaranteed-invalid fall back to the inherited value
13
+ * (inherits: true) rather than propagating as invalid through children.
14
+ * initial-value matches the light-mode defaults from tokens/base.css. */
15
+
16
+ @property --rf-color-bg {
17
+ syntax: '<color>';
18
+ inherits: true;
19
+ initial-value: #ffffff;
20
+ }
21
+ @property --rf-color-surface {
22
+ syntax: '<color>';
23
+ inherits: true;
24
+ initial-value: #f8fafc;
25
+ }
26
+ @property --rf-color-text {
27
+ syntax: '<color>';
28
+ inherits: true;
29
+ initial-value: #1a1a2e;
30
+ }
31
+ @property --rf-color-muted {
32
+ syntax: '<color>';
33
+ inherits: true;
34
+ initial-value: #64748b;
35
+ }
36
+ @property --rf-color-primary {
37
+ syntax: '<color>';
38
+ inherits: true;
39
+ initial-value: #0ea5e9;
40
+ }
41
+ @property --rf-color-border {
42
+ syntax: '<color>';
43
+ inherits: true;
44
+ initial-value: #e2e8f0;
45
+ }
46
+
47
+ /* ── 1. Colour scheme override ──────────────────────────────────────────────
48
+ * Forces dark or light mode tokens on a subtree. The six tint-bridgeable
49
+ * tokens are also exposed as --cs-* intermediaries so compound selectors
50
+ * in step 4 can fall back to them without a cycle. */
51
+
52
+ [data-color-scheme="dark"] {
53
+ color-scheme: dark;
54
+ color: var(--rf-color-text);
55
+ background-color: var(--rf-color-bg);
56
+
57
+ --cs-bg: #0c1222;
58
+ --cs-surface: #0f172a;
59
+ --cs-text: #e2e8f0;
60
+ --cs-muted: #94a3b8;
61
+ --cs-accent: #38bdf8;
62
+ --cs-border: rgba(255, 255, 255, 0.1);
63
+
64
+ --rf-color-bg: var(--cs-bg);
65
+ --rf-color-surface: var(--cs-surface);
66
+ --rf-color-text: var(--cs-text);
67
+ --rf-color-muted: var(--cs-muted);
68
+ --rf-color-primary: var(--cs-accent);
69
+ --rf-color-border: var(--cs-border);
70
+
71
+ --rf-color-primary-hover: #7dd3fc;
72
+ --rf-color-surface-hover: #1e293b;
73
+ --rf-color-surface-active: #334155;
74
+ --rf-color-surface-raised: #1e293b;
75
+
76
+ --rf-color-info: #60a5fa;
77
+ --rf-color-info-bg: rgba(59, 130, 246, 0.1);
78
+ --rf-color-info-border: rgba(59, 130, 246, 0.3);
79
+ --rf-color-warning: #fbbf24;
80
+ --rf-color-warning-bg: rgba(245, 158, 11, 0.1);
81
+ --rf-color-warning-border: rgba(245, 158, 11, 0.3);
82
+ --rf-color-danger: #f87171;
83
+ --rf-color-danger-bg: rgba(239, 68, 68, 0.1);
84
+ --rf-color-danger-border: rgba(239, 68, 68, 0.3);
85
+ --rf-color-success: #34d399;
86
+ --rf-color-success-bg: rgba(16, 185, 129, 0.1);
87
+ --rf-color-success-border: rgba(16, 185, 129, 0.3);
88
+
89
+ --rf-color-code-bg: #0f172a;
90
+ --rf-color-code-text: #e2e8f0;
91
+ --rf-color-inline-code-bg: rgba(255, 255, 255, 0.08);
92
+
93
+ --rf-shadow-xs: 0 1px 2px rgba(0,0,0,0.3);
94
+ --rf-shadow-sm: 0 1px 3px rgba(0,0,0,0.4), 0 1px 2px rgba(0,0,0,0.3);
95
+ --rf-shadow-md: 0 4px 12px rgba(0,0,0,0.4), 0 1px 3px rgba(0,0,0,0.3);
96
+ --rf-shadow-lg: 0 8px 24px rgba(0,0,0,0.5), 0 2px 6px rgba(0,0,0,0.3);
97
+ }
98
+
99
+ [data-color-scheme="light"] {
100
+ color-scheme: light;
101
+ color: var(--rf-color-text);
102
+ background-color: var(--rf-color-bg);
103
+
104
+ --cs-bg: #ffffff;
105
+ --cs-surface: #f8fafc;
106
+ --cs-text: #1a1a2e;
107
+ --cs-muted: #64748b;
108
+ --cs-accent: #0ea5e9;
109
+ --cs-border: #e2e8f0;
110
+
111
+ --rf-color-bg: var(--cs-bg);
112
+ --rf-color-surface: var(--cs-surface);
113
+ --rf-color-text: var(--cs-text);
114
+ --rf-color-muted: var(--cs-muted);
115
+ --rf-color-primary: var(--cs-accent);
116
+ --rf-color-border: var(--cs-border);
117
+
118
+ --rf-color-primary-hover: #0284c7;
119
+ --rf-color-surface-hover: #f1f5f9;
120
+ --rf-color-surface-active: #e2e8f0;
121
+ --rf-color-surface-raised: #ffffff;
122
+
123
+ --rf-color-info: #3b82f6;
124
+ --rf-color-info-bg: #eff6ff;
125
+ --rf-color-info-border: #bfdbfe;
126
+ --rf-color-warning: #f59e0b;
127
+ --rf-color-warning-bg: #fffbeb;
128
+ --rf-color-warning-border: #fde68a;
129
+ --rf-color-danger: #ef4444;
130
+ --rf-color-danger-bg: #fef2f2;
131
+ --rf-color-danger-border: #fecaca;
132
+ --rf-color-success: #10b981;
133
+ --rf-color-success-bg: #ecfdf5;
134
+ --rf-color-success-border: #a7f3d0;
135
+
136
+ --rf-color-inline-code-bg: #f1f5f9;
137
+
138
+ --rf-shadow-xs: 0 1px 2px rgba(0,0,0,0.04);
139
+ --rf-shadow-sm: 0 1px 3px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04);
140
+ --rf-shadow-md: 0 4px 12px rgba(0,0,0,0.07), 0 1px 3px rgba(0,0,0,0.04);
141
+ --rf-shadow-lg: 0 8px 24px rgba(0,0,0,0.08), 0 2px 6px rgba(0,0,0,0.04);
142
+ }
143
+
144
+ /* ── 2. Tint bridge — light mode (default) ────────────────────────────────
145
+ * Maps --tint-* → --rf-color-*. No fallback needed — when --tint-* is
146
+ * unset, var() produces guaranteed-invalid, and @property makes the
147
+ * token inherit from the parent element.
148
+ *
149
+ * :where() background gives tinted elements a painted background at zero
150
+ * specificity — runes with their own background naturally override it. */
151
+
152
+ :where([data-tint]) {
153
+ background-color: var(--rf-color-bg);
154
+ }
155
+
156
+ [data-tint] {
157
+ color: var(--rf-color-text);
158
+ --rf-color-bg: var(--tint-background);
159
+ --rf-color-surface: var(--tint-surface);
160
+ --rf-color-text: var(--tint-primary);
161
+ --rf-color-muted: var(--tint-secondary);
162
+ --rf-color-primary: var(--tint-accent);
163
+ --rf-color-border: var(--tint-border);
164
+ }
165
+
166
+ /* ── 3. Tint bridge — dark ancestor ───────────────────────────────────────
167
+ * When a dark context is on an ancestor (data-theme on html, or
168
+ * data-color-scheme on a parent), prefer dark tint values.
169
+ * Uses descendant combinator — does NOT match same-element.
170
+ * Unset tokens → guaranteed-invalid → @property inherits from parent
171
+ * (which carries the dark theme value). */
172
+
173
+ :is([data-theme="dark"], [data-color-scheme="dark"]) [data-tint] {
174
+ --rf-color-bg: var(--tint-dark-background, var(--tint-background));
175
+ --rf-color-surface: var(--tint-dark-surface, var(--tint-surface));
176
+ --rf-color-text: var(--tint-dark-primary, var(--tint-primary));
177
+ --rf-color-muted: var(--tint-dark-secondary, var(--tint-secondary));
178
+ --rf-color-primary: var(--tint-dark-accent, var(--tint-accent));
179
+ --rf-color-border: var(--tint-dark-border, var(--tint-border));
180
+ }
181
+
182
+ /* ── 4. Tint bridge — colour scheme + tint on SAME element ────────────────
183
+ * Compound selectors (no space) match when both attributes sit on the
184
+ * same element. Falls back to --cs-* intermediaries so that unlisted
185
+ * tint tokens use the colour-scheme value, not the page-level value. */
186
+
187
+ [data-color-scheme="dark"][data-tint] {
188
+ --rf-color-bg: var(--tint-dark-background, var(--tint-background, var(--cs-bg)));
189
+ --rf-color-surface: var(--tint-dark-surface, var(--tint-surface, var(--cs-surface)));
190
+ --rf-color-text: var(--tint-dark-primary, var(--tint-primary, var(--cs-text)));
191
+ --rf-color-muted: var(--tint-dark-secondary, var(--tint-secondary, var(--cs-muted)));
192
+ --rf-color-primary: var(--tint-dark-accent, var(--tint-accent, var(--cs-accent)));
193
+ --rf-color-border: var(--tint-dark-border, var(--tint-border, var(--cs-border)));
194
+ }
195
+
196
+ [data-color-scheme="light"][data-tint] {
197
+ --rf-color-bg: var(--tint-background, var(--cs-bg));
198
+ --rf-color-surface: var(--tint-surface, var(--cs-surface));
199
+ --rf-color-text: var(--tint-primary, var(--cs-text));
200
+ --rf-color-muted: var(--tint-secondary, var(--cs-muted));
201
+ --rf-color-primary: var(--tint-accent, var(--cs-accent));
202
+ --rf-color-border: var(--tint-border, var(--cs-border));
203
+ }