@refrakt-md/lumina 0.14.4 → 0.16.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.
- package/base.css +1 -0
- package/contracts/structures.json +105 -0
- package/index.css +9 -5
- package/package.json +4 -4
- package/styles/layouts/docs.css +17 -0
- package/styles/layouts/theme-toggle.css +67 -0
- package/styles/runes/accordion.css +56 -16
- package/styles/runes/aggregate.css +75 -0
- package/styles/runes/badge.css +20 -16
- package/styles/runes/card.css +83 -0
- package/styles/runes/collection.css +166 -0
- package/styles/runes/conversation.css +8 -3
- package/styles/runes/drawer.css +316 -0
- package/styles/runes/expand.css +74 -0
- package/styles/runes/nav.css +15 -0
- package/styles/runes/progress.css +49 -0
- package/styles/runes/relationships.css +132 -0
- package/styles/runes/snippet.css +27 -0
- package/styles/runes/xref.css +16 -0
- package/styles/runes/backlog.css +0 -108
- package/styles/runes/decision-log.css +0 -46
- package/styles/runes/plan-activity.css +0 -87
- package/styles/runes/plan-entity-tabs.css +0 -88
- package/styles/runes/plan-relationships.css +0 -40
package/base.css
CHANGED
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
@import './styles/layouts/blog.css';
|
|
20
20
|
@import './styles/layouts/on-this-page.css';
|
|
21
21
|
@import './styles/layouts/search.css';
|
|
22
|
+
@import './styles/layouts/theme-toggle.css';
|
|
22
23
|
@import './styles/layouts/version-switcher.css';
|
|
23
24
|
@import './styles/layouts/split.css';
|
|
24
25
|
|
|
@@ -184,6 +184,85 @@
|
|
|
184
184
|
"{content}"
|
|
185
185
|
]
|
|
186
186
|
},
|
|
187
|
+
"Snippet": {
|
|
188
|
+
"block": "snippet",
|
|
189
|
+
"root": ".rf-snippet",
|
|
190
|
+
"dataRune": "snippet",
|
|
191
|
+
"childOrder": [
|
|
192
|
+
"{content}"
|
|
193
|
+
]
|
|
194
|
+
},
|
|
195
|
+
"Expand": {
|
|
196
|
+
"block": "expand",
|
|
197
|
+
"root": ".rf-expand",
|
|
198
|
+
"dataRune": "expand",
|
|
199
|
+
"childOrder": [
|
|
200
|
+
"{content}"
|
|
201
|
+
]
|
|
202
|
+
},
|
|
203
|
+
"Badge": {
|
|
204
|
+
"block": "badge",
|
|
205
|
+
"root": ".rf-badge",
|
|
206
|
+
"dataRune": "badge",
|
|
207
|
+
"childOrder": [
|
|
208
|
+
"{content}"
|
|
209
|
+
]
|
|
210
|
+
},
|
|
211
|
+
"Collection": {
|
|
212
|
+
"block": "collection",
|
|
213
|
+
"root": ".rf-collection",
|
|
214
|
+
"dataRune": "collection",
|
|
215
|
+
"childOrder": [
|
|
216
|
+
"{content}"
|
|
217
|
+
]
|
|
218
|
+
},
|
|
219
|
+
"Relationships": {
|
|
220
|
+
"block": "relationships",
|
|
221
|
+
"root": ".rf-relationships",
|
|
222
|
+
"dataRune": "relationships",
|
|
223
|
+
"childOrder": [
|
|
224
|
+
"{content}"
|
|
225
|
+
]
|
|
226
|
+
},
|
|
227
|
+
"Aggregate": {
|
|
228
|
+
"block": "aggregate",
|
|
229
|
+
"root": ".rf-aggregate",
|
|
230
|
+
"dataRune": "aggregate",
|
|
231
|
+
"childOrder": [
|
|
232
|
+
"{content}"
|
|
233
|
+
]
|
|
234
|
+
},
|
|
235
|
+
"Progress": {
|
|
236
|
+
"block": "progress",
|
|
237
|
+
"root": ".rf-progress",
|
|
238
|
+
"dataRune": "progress",
|
|
239
|
+
"childOrder": [
|
|
240
|
+
"{content}"
|
|
241
|
+
],
|
|
242
|
+
"modifiers": {
|
|
243
|
+
"sentiment": {
|
|
244
|
+
"source": "meta",
|
|
245
|
+
"classPattern": ".rf-progress--{value}",
|
|
246
|
+
"dataAttribute": "data-sentiment"
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
},
|
|
250
|
+
"Card": {
|
|
251
|
+
"block": "card",
|
|
252
|
+
"root": ".rf-card",
|
|
253
|
+
"dataRune": "card",
|
|
254
|
+
"childOrder": [
|
|
255
|
+
"{content}"
|
|
256
|
+
],
|
|
257
|
+
"modifiers": {
|
|
258
|
+
"layout": {
|
|
259
|
+
"source": "meta",
|
|
260
|
+
"default": "stacked",
|
|
261
|
+
"classPattern": ".rf-card--{value}",
|
|
262
|
+
"dataAttribute": "data-layout"
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
},
|
|
187
266
|
"Embed": {
|
|
188
267
|
"block": "embed",
|
|
189
268
|
"root": ".rf-embed",
|
|
@@ -425,6 +504,32 @@
|
|
|
425
504
|
}
|
|
426
505
|
}
|
|
427
506
|
},
|
|
507
|
+
"Drawer": {
|
|
508
|
+
"block": "drawer",
|
|
509
|
+
"root": ".rf-drawer",
|
|
510
|
+
"dataRune": "drawer",
|
|
511
|
+
"childOrder": [
|
|
512
|
+
"{content}"
|
|
513
|
+
],
|
|
514
|
+
"modifiers": {
|
|
515
|
+
"side": {
|
|
516
|
+
"source": "meta",
|
|
517
|
+
"default": "right",
|
|
518
|
+
"classPattern": ".rf-drawer--{value}",
|
|
519
|
+
"dataAttribute": "data-side"
|
|
520
|
+
},
|
|
521
|
+
"size": {
|
|
522
|
+
"source": "meta",
|
|
523
|
+
"default": "md",
|
|
524
|
+
"classPattern": ".rf-drawer--{value}",
|
|
525
|
+
"dataAttribute": "data-size"
|
|
526
|
+
},
|
|
527
|
+
"shortcut": {
|
|
528
|
+
"source": "meta",
|
|
529
|
+
"dataAttribute": "data-shortcut"
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
},
|
|
428
533
|
"Figure": {
|
|
429
534
|
"block": "figure",
|
|
430
535
|
"root": ".rf-figure",
|
package/index.css
CHANGED
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
@import './styles/layouts/blog.css';
|
|
20
20
|
@import './styles/layouts/on-this-page.css';
|
|
21
21
|
@import './styles/layouts/search.css';
|
|
22
|
+
@import './styles/layouts/theme-toggle.css';
|
|
22
23
|
@import './styles/layouts/version-switcher.css';
|
|
23
24
|
@import './styles/layouts/split.css';
|
|
24
25
|
@import './styles/layouts/plan.css';
|
|
@@ -41,6 +42,7 @@
|
|
|
41
42
|
@import './styles/runes/annotate.css';
|
|
42
43
|
@import './styles/runes/audio.css';
|
|
43
44
|
@import './styles/runes/api.css';
|
|
45
|
+
@import './styles/runes/card.css';
|
|
44
46
|
@import './styles/runes/badge.css';
|
|
45
47
|
@import './styles/runes/bento.css';
|
|
46
48
|
@import './styles/runes/blog.css';
|
|
@@ -49,6 +51,10 @@
|
|
|
49
51
|
@import './styles/runes/budget.css';
|
|
50
52
|
@import './styles/runes/cast.css';
|
|
51
53
|
@import './styles/runes/character.css';
|
|
54
|
+
@import './styles/runes/collection.css';
|
|
55
|
+
@import './styles/runes/relationships.css';
|
|
56
|
+
@import './styles/runes/aggregate.css';
|
|
57
|
+
@import './styles/runes/progress.css';
|
|
52
58
|
@import './styles/runes/changelog.css';
|
|
53
59
|
@import './styles/runes/chart.css';
|
|
54
60
|
@import './styles/runes/compare.css';
|
|
@@ -57,10 +63,13 @@
|
|
|
57
63
|
@import './styles/runes/cta.css';
|
|
58
64
|
@import './styles/runes/datatable.css';
|
|
59
65
|
@import './styles/runes/details.css';
|
|
66
|
+
@import './styles/runes/drawer.css';
|
|
60
67
|
@import './styles/runes/diagram.css';
|
|
61
68
|
@import './styles/runes/diff.css';
|
|
62
69
|
@import './styles/runes/codegroup.css';
|
|
70
|
+
@import './styles/runes/snippet.css';
|
|
63
71
|
@import './styles/runes/embed.css';
|
|
72
|
+
@import './styles/runes/expand.css';
|
|
64
73
|
@import './styles/runes/event.css';
|
|
65
74
|
@import './styles/runes/faction.css';
|
|
66
75
|
@import './styles/runes/feature.css';
|
|
@@ -114,11 +123,6 @@
|
|
|
114
123
|
@import './styles/runes/bug.css';
|
|
115
124
|
@import './styles/runes/decision.css';
|
|
116
125
|
@import './styles/runes/milestone.css';
|
|
117
|
-
@import './styles/runes/backlog.css';
|
|
118
|
-
@import './styles/runes/decision-log.css';
|
|
119
126
|
@import './styles/runes/plan-progress.css';
|
|
120
|
-
@import './styles/runes/plan-activity.css';
|
|
121
127
|
@import './styles/runes/plan-ref.css';
|
|
122
|
-
@import './styles/runes/plan-relationships.css';
|
|
123
128
|
@import './styles/runes/plan-history.css';
|
|
124
|
-
@import './styles/runes/plan-entity-tabs.css';
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@refrakt-md/lumina",
|
|
3
3
|
"description": "Lumina theme for refrakt.md — design tokens, CSS, identity transform, and layout configs",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.16.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
|
@@ -83,9 +83,9 @@
|
|
|
83
83
|
"build": "tsc"
|
|
84
84
|
},
|
|
85
85
|
"dependencies": {
|
|
86
|
-
"@refrakt-md/runes": "0.
|
|
87
|
-
"@refrakt-md/transform": "0.
|
|
88
|
-
"@refrakt-md/types": "0.
|
|
86
|
+
"@refrakt-md/runes": "0.16.0",
|
|
87
|
+
"@refrakt-md/transform": "0.16.0",
|
|
88
|
+
"@refrakt-md/types": "0.16.0"
|
|
89
89
|
},
|
|
90
90
|
"devDependencies": {
|
|
91
91
|
"postcss": "^8.4.0"
|
package/styles/layouts/docs.css
CHANGED
|
@@ -100,6 +100,15 @@
|
|
|
100
100
|
background: var(--rf-color-bg, #fff);
|
|
101
101
|
z-index: 5;
|
|
102
102
|
}
|
|
103
|
+
/* Match the sticky offset in the natural-flow position too. The fixed header
|
|
104
|
+
* is out of flow so `.rf-docs-body` starts at viewport top; without this
|
|
105
|
+
* margin, the sidebar's static position sits at Y=0 with its top 3.125rem
|
|
106
|
+
* hidden under the header — visible only when the page scrolls enough for
|
|
107
|
+
* sticky to activate. Scoped to `:has(.rf-docs-header)` so layouts without a
|
|
108
|
+
* header don't gain an unwanted top gap. */
|
|
109
|
+
html:has(.rf-docs-header) .rf-docs-sidebar {
|
|
110
|
+
margin-top: 3.125rem;
|
|
111
|
+
}
|
|
103
112
|
.rf-docs-sidebar::-webkit-scrollbar {
|
|
104
113
|
width: 0;
|
|
105
114
|
}
|
|
@@ -190,6 +199,8 @@ html:has(.rf-docs-header) {
|
|
|
190
199
|
padding: 0.625rem 1rem;
|
|
191
200
|
border-bottom: 1px solid var(--rf-color-border);
|
|
192
201
|
background: var(--rf-color-bg, #fff);
|
|
202
|
+
max-width: 100%;
|
|
203
|
+
overflow: hidden;
|
|
193
204
|
}
|
|
194
205
|
.rf-docs-toolbar__hamburger {
|
|
195
206
|
background: none;
|
|
@@ -206,6 +217,12 @@ html:has(.rf-docs-header) {
|
|
|
206
217
|
.rf-docs-toolbar__breadcrumb {
|
|
207
218
|
font-size: 0.8rem;
|
|
208
219
|
color: var(--rf-color-muted);
|
|
220
|
+
/* `flex: 1 1 0` (basis 0, not auto) so the breadcrumb shrinks against
|
|
221
|
+
* the available space rather than starting at its full content width —
|
|
222
|
+
* combined with `min-width: 0` this is what triggers ellipsis on long
|
|
223
|
+
* titles. Without basis 0 a long page title overflows the toolbar and
|
|
224
|
+
* forces horizontal page scroll on narrow viewports. */
|
|
225
|
+
flex: 1 1 0;
|
|
209
226
|
min-width: 0;
|
|
210
227
|
overflow: hidden;
|
|
211
228
|
text-overflow: ellipsis;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/* Theme-mode toggle button (SPEC-073).
|
|
2
|
+
*
|
|
3
|
+
* Layout chrome — a peer of the search trigger, placed in the header/toolbar.
|
|
4
|
+
* The `theme-toggle` behavior cycles auto → light → dark and reflects the
|
|
5
|
+
* current preference onto the button as `data-theme-pref`; the icon below
|
|
6
|
+
* tracks that. Ported verbatim from the former `ThemeToggle.svelte` so the
|
|
7
|
+
* look is unchanged, with the icon selector rekeyed from a swapped class to
|
|
8
|
+
* the `data-theme-pref` attribute. */
|
|
9
|
+
.rf-theme-toggle {
|
|
10
|
+
display: inline-flex;
|
|
11
|
+
align-items: center;
|
|
12
|
+
justify-content: center;
|
|
13
|
+
width: 2rem;
|
|
14
|
+
height: 2rem;
|
|
15
|
+
padding: 0;
|
|
16
|
+
border: 1px solid var(--rf-color-border);
|
|
17
|
+
border-radius: var(--rf-radius-md);
|
|
18
|
+
background: transparent;
|
|
19
|
+
color: var(--rf-color-text);
|
|
20
|
+
cursor: pointer;
|
|
21
|
+
transition: background-color 120ms ease, border-color 120ms ease;
|
|
22
|
+
}
|
|
23
|
+
.rf-theme-toggle:hover {
|
|
24
|
+
background: var(--rf-color-surface-hover);
|
|
25
|
+
}
|
|
26
|
+
.rf-theme-toggle:focus-visible {
|
|
27
|
+
outline: 2px solid var(--rf-color-primary);
|
|
28
|
+
outline-offset: 2px;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/* In the header chrome the brand/nav and the controls are flex siblings
|
|
32
|
+
* arranged by `order` (search is order 1, nav/menu order 3). Without this the
|
|
33
|
+
* toggle defaults to order 0 and groups with the brand on the left; order 2
|
|
34
|
+
* places it just after the right-aligned search trigger — matching the former
|
|
35
|
+
* component. The plan toolbar arranges by DOM order, so it isn't included. */
|
|
36
|
+
.rf-header__inner .rf-theme-toggle,
|
|
37
|
+
.rf-docs-header__inner .rf-theme-toggle,
|
|
38
|
+
.rf-blog-header__inner .rf-theme-toggle {
|
|
39
|
+
order: 2;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/* Hidden on tint-locked pages: the saved preference is preserved but ignored
|
|
43
|
+
* while the lock is active (SPEC-052), so a toggle that does nothing would be
|
|
44
|
+
* confusing. Pure CSS — the lock lands on <html> at SSR and on client nav. */
|
|
45
|
+
html[data-tint-lock="true"] .rf-theme-toggle {
|
|
46
|
+
display: none;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/* Icon — a currentColor-tinted mask. Defaults to the auto glyph so the SSR'd
|
|
50
|
+
* button shows an icon before the behavior sets data-theme-pref; the light and
|
|
51
|
+
* dark glyphs swap in by state. */
|
|
52
|
+
.rf-theme-toggle__icon {
|
|
53
|
+
display: inline-block;
|
|
54
|
+
width: 1rem;
|
|
55
|
+
height: 1rem;
|
|
56
|
+
background: currentColor;
|
|
57
|
+
mask-size: contain;
|
|
58
|
+
mask-repeat: no-repeat;
|
|
59
|
+
mask-position: center;
|
|
60
|
+
mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><circle cx='12' cy='12' r='10'/><path d='M12 2a10 10 0 0 0 0 20Z' fill='currentColor'/></svg>");
|
|
61
|
+
}
|
|
62
|
+
.rf-theme-toggle[data-theme-pref="light"] .rf-theme-toggle__icon {
|
|
63
|
+
mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><circle cx='12' cy='12' r='4'/><path d='M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M17.66 6.34l1.41-1.41'/></svg>");
|
|
64
|
+
}
|
|
65
|
+
.rf-theme-toggle[data-theme-pref="dark"] .rf-theme-toggle__icon {
|
|
66
|
+
mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z'/></svg>");
|
|
67
|
+
}
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
/* Accordion */
|
|
2
|
-
.
|
|
3
|
-
|
|
4
|
-
border-radius: var(--rf-radius-md);
|
|
5
|
-
overflow: hidden;
|
|
6
|
-
}
|
|
2
|
+
/* No wrapping border / radius — the only chrome is the divider between items. */
|
|
3
|
+
.rf-accordion {}
|
|
7
4
|
.rf-accordion__preamble {
|
|
8
5
|
margin-bottom: 1.5rem;
|
|
9
6
|
}
|
|
@@ -52,35 +49,69 @@
|
|
|
52
49
|
.rf-accordion-item__header {
|
|
53
50
|
display: flex;
|
|
54
51
|
align-items: center;
|
|
55
|
-
|
|
56
|
-
padding: 0.875rem
|
|
52
|
+
gap: 0.5rem;
|
|
53
|
+
padding: 0.875rem 0rem;
|
|
57
54
|
font-weight: 600;
|
|
58
55
|
font-size: 0.95rem;
|
|
59
56
|
cursor: pointer;
|
|
60
57
|
user-select: none;
|
|
61
|
-
transition: background-color 200ms ease;
|
|
62
58
|
list-style: none;
|
|
63
59
|
}
|
|
64
60
|
.rf-accordion-item__header::-webkit-details-marker { display: none; }
|
|
65
61
|
.rf-accordion-item__header::marker { display: none; content: ''; }
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
.rf-accordion-item__header::
|
|
70
|
-
content: '
|
|
62
|
+
/* Chevron in front of the label — points right when collapsed, rotates 90°
|
|
63
|
+
* to point down when expanded. SVG mask so the glyph is crisp at any size
|
|
64
|
+
* and tints with the muted text color. */
|
|
65
|
+
.rf-accordion-item__header::before {
|
|
66
|
+
content: '';
|
|
71
67
|
flex-shrink: 0;
|
|
72
|
-
|
|
68
|
+
width: 0.75rem;
|
|
69
|
+
height: 0.75rem;
|
|
70
|
+
background: var(--rf-color-muted);
|
|
71
|
+
mask-size: contain;
|
|
72
|
+
mask-repeat: no-repeat;
|
|
73
|
+
mask-position: center;
|
|
74
|
+
mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'><polyline points='9 18 15 12 9 6'/></svg>");
|
|
73
75
|
transition: transform 200ms ease;
|
|
74
76
|
}
|
|
75
|
-
.rf-accordion-item[open] .rf-accordion-item__header::
|
|
76
|
-
transform: rotate(
|
|
77
|
+
.rf-accordion-item[open] .rf-accordion-item__header::before {
|
|
78
|
+
transform: rotate(90deg);
|
|
77
79
|
}
|
|
78
80
|
.rf-accordion-item__title {
|
|
79
81
|
flex: 1;
|
|
80
82
|
min-width: 0;
|
|
81
83
|
}
|
|
84
|
+
/* Per-group count for collection/relationships group-display="accordion".
|
|
85
|
+
* Inherits the header's font (weight + color) so the count reads as part
|
|
86
|
+
* of the same label. The header's `gap` handles spacing — no margins needed. */
|
|
87
|
+
.rf-accordion-item__count {
|
|
88
|
+
flex-shrink: 0;
|
|
89
|
+
}
|
|
90
|
+
/* Animate the panel's collapse / expand. `::details-content` (the auto-generated
|
|
91
|
+
* wrapper for non-summary content) + `interpolate-size: allow-keywords` lets the
|
|
92
|
+
* height transition between 0 and auto. `transition-behavior: allow-discrete`
|
|
93
|
+
* on `content-visibility` keeps the panel reachable during the open animation.
|
|
94
|
+
* Browsers without `::details-content` support fall back to the native snap. */
|
|
95
|
+
.rf-accordion-item {
|
|
96
|
+
interpolate-size: allow-keywords;
|
|
97
|
+
}
|
|
98
|
+
.rf-accordion-item::details-content {
|
|
99
|
+
block-size: 0;
|
|
100
|
+
overflow: hidden;
|
|
101
|
+
transition: block-size 250ms ease, content-visibility 250ms allow-discrete;
|
|
102
|
+
}
|
|
103
|
+
.rf-accordion-item[open]::details-content {
|
|
104
|
+
block-size: auto;
|
|
105
|
+
}
|
|
82
106
|
.rf-accordion-item__body {
|
|
83
107
|
padding: 0 1.25rem 1rem;
|
|
108
|
+
}
|
|
109
|
+
/* Prose styles for the standalone accordion rune's bodies (paragraphs,
|
|
110
|
+
* lists, etc.). Scoped to `:not(:has([data-block]))` so they don't bleed into
|
|
111
|
+
* block-content children like cards inside a collection/relationships
|
|
112
|
+
* `group-display="accordion"` panel, where the card's own typography
|
|
113
|
+
* should govern. */
|
|
114
|
+
.rf-accordion-item__body:not(:has([data-block])) {
|
|
84
115
|
font-size: 0.925rem;
|
|
85
116
|
line-height: 1.65;
|
|
86
117
|
color: var(--rf-color-muted);
|
|
@@ -88,3 +119,12 @@
|
|
|
88
119
|
.rf-accordion-item__body p:last-child {
|
|
89
120
|
margin-bottom: 0;
|
|
90
121
|
}
|
|
122
|
+
/* Block-content children — collection / relationships mark their body-template
|
|
123
|
+
* items `data-block`. A panel housing them (group-display="accordion") switches
|
|
124
|
+
* to a flex column with the small gap so cards get the same spacing they'd have
|
|
125
|
+
* under a heading-grouped layout. */
|
|
126
|
+
.rf-accordion-item__body:has([data-block]) {
|
|
127
|
+
display: flex;
|
|
128
|
+
flex-direction: column;
|
|
129
|
+
gap: var(--rf-spacing-sm);
|
|
130
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/* Aggregate — counts and per-group breakdowns from the registry (SPEC-076).
|
|
2
|
+
*
|
|
3
|
+
* Two modes share the same block class. The no-body inline form is a `<span>`
|
|
4
|
+
* carrying the integer; the body-zoned form is a `<section>` rendering
|
|
5
|
+
* preamble / per-group template / fallback. Most of the visual weight inside
|
|
6
|
+
* the body comes from other runes (`progress`, `badge`, `humanize` text), so
|
|
7
|
+
* this stylesheet sticks to container chrome and the inline single-number
|
|
8
|
+
* form.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/* Block container — vertical rhythm matches collection / relationships. The
|
|
12
|
+
* bare selector also matches the inline form's `<span>`, but vertical margin
|
|
13
|
+
* on an inline span has no effect so it's safe to share. */
|
|
14
|
+
.rf-aggregate {
|
|
15
|
+
margin: var(--rf-spacing-md) 0;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/* Inline single-number form — `<span class="rf-aggregate" data-aggregate="count">`.
|
|
19
|
+
* Tabular nums keep digits aligned when the count changes between renders;
|
|
20
|
+
* weight tuned to stand out modestly in prose. */
|
|
21
|
+
.rf-aggregate[data-aggregate='count'] {
|
|
22
|
+
font-variant-numeric: tabular-nums;
|
|
23
|
+
font-weight: 600;
|
|
24
|
+
color: var(--rf-color-text);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/* Preamble — totals chrome above the breakdown (e.g. a progress bar). Trim
|
|
28
|
+
* first/last-child block margins so the rune's outer rhythm wins over the
|
|
29
|
+
* template's inner block margins (same pattern collection uses). */
|
|
30
|
+
.rf-aggregate__preamble > :first-child { margin-top: 0; }
|
|
31
|
+
.rf-aggregate__preamble > :last-child { margin-bottom: 0; }
|
|
32
|
+
|
|
33
|
+
/* Empty state — replaces the breakdown when the query yields nothing. */
|
|
34
|
+
.rf-aggregate__empty {
|
|
35
|
+
color: var(--rf-color-muted);
|
|
36
|
+
font-size: 0.9375em;
|
|
37
|
+
}
|
|
38
|
+
.rf-aggregate__empty > :first-child { margin-top: 0; }
|
|
39
|
+
.rf-aggregate__empty > :last-child { margin-bottom: 0; }
|
|
40
|
+
|
|
41
|
+
/* Items — either the per-group breakdown row, or the ungrouped single-render
|
|
42
|
+
* slot. Default stack handles the ungrouped case (one block element from the
|
|
43
|
+
* body). With groups, switch to a wrapping inline row so per-group renders
|
|
44
|
+
* (badges, pills, …) flow across the page. */
|
|
45
|
+
.rf-aggregate__items {
|
|
46
|
+
display: flex;
|
|
47
|
+
flex-direction: column;
|
|
48
|
+
gap: var(--rf-spacing-sm);
|
|
49
|
+
margin-top: var(--rf-spacing-sm);
|
|
50
|
+
}
|
|
51
|
+
.rf-aggregate__items:has(.rf-aggregate__group) {
|
|
52
|
+
flex-direction: row;
|
|
53
|
+
flex-wrap: wrap;
|
|
54
|
+
gap: var(--rf-spacing-xs) var(--rf-spacing-sm);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/* Direct children of __items (the ungrouped template render) — trim outer
|
|
58
|
+
* block margins so the rune's outer rhythm wins, same pattern as preamble /
|
|
59
|
+
* empty. */
|
|
60
|
+
.rf-aggregate__items > :first-child { margin-top: 0; }
|
|
61
|
+
.rf-aggregate__items > :last-child { margin-bottom: 0; }
|
|
62
|
+
|
|
63
|
+
/* Per-group block — wraps one render of the template. `data-block` is set
|
|
64
|
+
* by the resolver so we trim its outer block margins (the items-row `gap`
|
|
65
|
+
* governs inter-group spacing) — same pattern collection / relationships
|
|
66
|
+
* use for `__item[data-block]`. */
|
|
67
|
+
.rf-aggregate__group {
|
|
68
|
+
min-width: 0;
|
|
69
|
+
}
|
|
70
|
+
.rf-aggregate__group[data-block] > :first-child {
|
|
71
|
+
margin-top: 0;
|
|
72
|
+
}
|
|
73
|
+
.rf-aggregate__group[data-block] > :last-child {
|
|
74
|
+
margin-bottom: 0;
|
|
75
|
+
}
|
package/styles/runes/badge.css
CHANGED
|
@@ -1,33 +1,37 @@
|
|
|
1
|
-
/* Badge rune — standalone inline
|
|
1
|
+
/* Badge rune — standalone inline chip.
|
|
2
2
|
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
3
|
+
* Built atop the metadata pill base (`data-meta-type`), but reshaped to the
|
|
4
|
+
* compact chip look used by plan-progress status counts: **no border**,
|
|
5
|
+
* solid-ish sentiment-tinted background, smaller font + tighter padding, and
|
|
6
|
+
* a small corner radius. Tints come from the universal `--meta-color` set by
|
|
7
|
+
* `dimensions/metadata.css`'s sentiment rules (positive / caution / negative /
|
|
8
|
+
* neutral → success / warning / danger / muted). Background is a `color-mix`
|
|
9
|
+
* of that color, so the chip stays sentiment-flexible — any value the theme
|
|
10
|
+
* gives `--meta-color` works without per-status selectors.
|
|
10
11
|
*
|
|
11
|
-
* rank="primary" boosts emphasis with a heavier
|
|
12
|
-
*
|
|
13
|
-
* dominate over their neighbours.
|
|
12
|
+
* `rank="primary"` boosts emphasis with a heavier tint and bolder weight,
|
|
13
|
+
* useful for labels that should dominate over neighbours.
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
.rf-badge {
|
|
17
17
|
vertical-align: baseline;
|
|
18
|
-
border
|
|
19
|
-
background: color-mix(in srgb, var(--meta-color,
|
|
20
|
-
color: var(--meta-color, var(--rf-color-
|
|
18
|
+
border: none;
|
|
19
|
+
background: color-mix(in srgb, var(--meta-color, var(--rf-color-muted)) 10%, transparent);
|
|
20
|
+
color: var(--meta-color, var(--rf-color-muted));
|
|
21
|
+
font-size: 0.75rem;
|
|
21
22
|
font-weight: 500;
|
|
23
|
+
padding: 0.125rem 0.5rem;
|
|
24
|
+
border-radius: var(--rf-radius-sm);
|
|
25
|
+
white-space: nowrap;
|
|
22
26
|
}
|
|
23
27
|
|
|
24
28
|
.rf-badge[data-meta-rank="primary"] {
|
|
25
|
-
background: color-mix(in srgb, var(--meta-color,
|
|
29
|
+
background: color-mix(in srgb, var(--meta-color, var(--rf-color-muted)) 28%, transparent);
|
|
26
30
|
font-weight: 600;
|
|
27
31
|
}
|
|
28
32
|
|
|
29
33
|
/* Drop the sentiment dot — the background tint carries the cue for
|
|
30
|
-
* standalone
|
|
34
|
+
* standalone chips, and the dot competes visually with adjacent prose. */
|
|
31
35
|
.rf-badge::before {
|
|
32
36
|
display: none;
|
|
33
37
|
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/* card — generic content card (SPEC-070).
|
|
2
|
+
*
|
|
3
|
+
* Borderless (no outline) but with a soft surface fill — the surface + the
|
|
4
|
+
* structure (media split, footer separator) carry the card, no border needed.
|
|
5
|
+
* The media|content split + responsive collapse + mobile full-bleed media
|
|
6
|
+
* header come from the shared layouts/split.css (keyed off data-layout /
|
|
7
|
+
* data-section="media" / data-name="content" / data-media-position).
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
.rf-card {
|
|
11
|
+
position: relative; /* anchor for the stretched link + media bleed */
|
|
12
|
+
padding: var(--rune-padding, var(--rf-spacing-md));
|
|
13
|
+
border-radius: var(--rf-radius-md);
|
|
14
|
+
background: var(--rf-color-surface);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.rf-card:hover {
|
|
18
|
+
background: var(--rf-color-surface-hover);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.rf-card__body > :first-child { margin-top: 0; }
|
|
22
|
+
.rf-card__body > :last-child { margin-bottom: 0; }
|
|
23
|
+
|
|
24
|
+
/* Eyebrow — a leading paragraph immediately before a heading, the same kicker
|
|
25
|
+
* treatment as page-section / recipe. */
|
|
26
|
+
.rf-card__eyebrow {
|
|
27
|
+
font-size: 0.8rem;
|
|
28
|
+
font-weight: 600;
|
|
29
|
+
letter-spacing: 0.06em;
|
|
30
|
+
text-transform: uppercase;
|
|
31
|
+
color: var(--rf-color-primary);
|
|
32
|
+
margin: 0 0 0.375rem;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/* The body's leading heading is the card title; drop its prose top margin so it
|
|
36
|
+
* hugs the eyebrow (or the top of the card) instead of opening a gap. */
|
|
37
|
+
.rf-card__title {
|
|
38
|
+
margin-top: 0;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.rf-card__footer {
|
|
42
|
+
margin-top: var(--rf-spacing-sm);
|
|
43
|
+
padding-top: var(--rf-spacing-sm);
|
|
44
|
+
border-top: 1px solid var(--rf-color-border);
|
|
45
|
+
font-size: 0.8125em;
|
|
46
|
+
color: var(--rf-color-muted);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/* In a collection grid, each row stretches its items to the tallest (see
|
|
50
|
+
* collection.css); these rules make a stacked card spend that height usefully:
|
|
51
|
+
* the card becomes a column, its content fills the leftover height, and the
|
|
52
|
+
* body grows so footers drop to a common baseline across the row. Scoped to
|
|
53
|
+
* stacked cards so a split card's grid (layouts/split.css) is left intact. */
|
|
54
|
+
.rf-collection[data-layout='grid'] .rf-card[data-layout='stacked'] {
|
|
55
|
+
display: flex;
|
|
56
|
+
flex-direction: column;
|
|
57
|
+
/* The grid/flex wrapper stretches the card, but a nested flex container
|
|
58
|
+
* doesn't always pass that height to its own flex children; pin it so the
|
|
59
|
+
* content/body flex:1 reliably fills. */
|
|
60
|
+
height: 100%;
|
|
61
|
+
}
|
|
62
|
+
.rf-collection[data-layout='grid'] .rf-card[data-layout='stacked'] > .rf-card__content {
|
|
63
|
+
flex: 1;
|
|
64
|
+
}
|
|
65
|
+
.rf-collection[data-layout='grid'] .rf-card[data-layout='stacked'] .rf-card__content {
|
|
66
|
+
display: flex;
|
|
67
|
+
flex-direction: column;
|
|
68
|
+
}
|
|
69
|
+
.rf-collection[data-layout='grid'] .rf-card[data-layout='stacked'] .rf-card__body {
|
|
70
|
+
flex: 1;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/* Whole-card stretched link — covers the card; real links in body/footer
|
|
74
|
+
* sit above it via position:relative. */
|
|
75
|
+
.rf-card__link {
|
|
76
|
+
position: absolute;
|
|
77
|
+
inset: 0;
|
|
78
|
+
z-index: 0;
|
|
79
|
+
}
|
|
80
|
+
.rf-card a:not(.rf-card__link) {
|
|
81
|
+
position: relative;
|
|
82
|
+
z-index: 1;
|
|
83
|
+
}
|