@refrakt-md/lumina 0.17.0 → 0.19.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/contracts/structures.json +479 -232
- package/dist/config.js +5 -5
- package/dist/config.js.map +1 -1
- package/dist/presets/tideline.d.ts.map +1 -1
- package/dist/presets/tideline.js +0 -14
- package/dist/presets/tideline.js.map +1 -1
- package/dist/tokens.d.ts.map +1 -1
- package/dist/tokens.js +14 -23
- package/dist/tokens.js.map +1 -1
- package/index.css +1 -1
- package/package.json +4 -4
- package/styles/dimensions/media.css +1 -1
- package/styles/dimensions/sections.css +4 -1
- package/styles/dimensions/sequence.css +1 -1
- package/styles/dimensions/state.css +1 -1
- package/styles/dimensions/surfaces.css +15 -2
- package/styles/global.css +68 -0
- package/styles/layouts/on-this-page.css +2 -2
- package/styles/layouts/search.css +2 -2
- package/styles/layouts/split.css +134 -183
- package/styles/layouts/version-switcher.css +1 -1
- package/styles/runes/audio.css +1 -1
- package/styles/runes/bento.css +186 -97
- package/styles/runes/bond.css +1 -1
- package/styles/runes/budget.css +1 -1
- package/styles/runes/card.css +64 -9
- package/styles/runes/character.css +1 -1
- package/styles/runes/chart.css +100 -0
- package/styles/runes/design-context.css +7 -5
- package/styles/runes/drawer.css +4 -0
- package/styles/runes/event.css +1 -1
- package/styles/runes/expand.css +5 -7
- package/styles/runes/faction.css +32 -6
- package/styles/runes/feature.css +21 -16
- package/styles/runes/figure.css +1 -2
- package/styles/runes/gallery.css +39 -8
- package/styles/runes/itinerary.css +2 -2
- package/styles/runes/lore.css +1 -1
- package/styles/runes/mockup.css +7 -7
- package/styles/runes/palette.css +3 -3
- package/styles/runes/plan-progress.css +15 -62
- package/styles/runes/playlist.css +32 -0
- package/styles/runes/plot.css +2 -2
- package/styles/runes/realm.css +32 -6
- package/styles/runes/recipe.css +38 -2
- package/styles/runes/sandbox.css +1 -1
- package/styles/runes/spacing.css +4 -4
- package/styles/runes/swatch.css +1 -1
- package/styles/runes/tint.css +7 -7
- package/styles/runes/typography.css +7 -7
- package/styles/runes/xref.css +1 -1
- package/tokens/base.css +10 -14
- package/tokens/dark.css +16 -14
package/styles/runes/bento.css
CHANGED
|
@@ -1,126 +1,215 @@
|
|
|
1
|
-
/* Bento */
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
text-transform: uppercase;
|
|
13
|
-
color: var(--rf-color-primary);
|
|
14
|
-
margin: 0 0 0.5rem;
|
|
15
|
-
}
|
|
16
|
-
.rf-bento__eyebrow:has(a) {
|
|
17
|
-
display: inline-block;
|
|
18
|
-
position: relative;
|
|
19
|
-
padding: 0.25rem 0.875rem;
|
|
20
|
-
border: 1px solid var(--rf-color-border);
|
|
21
|
-
border-radius: var(--rf-radius-full);
|
|
22
|
-
color: var(--rf-color-text);
|
|
23
|
-
font-weight: 400;
|
|
24
|
-
text-transform: none;
|
|
25
|
-
letter-spacing: 0;
|
|
26
|
-
transition: border-color 150ms ease;
|
|
27
|
-
}
|
|
28
|
-
.rf-bento__eyebrow:has(a):hover { border-color: var(--rf-color-muted); }
|
|
29
|
-
.rf-bento__eyebrow:has(a) a { color: var(--rf-color-primary); font-weight: 600; text-decoration: none; }
|
|
30
|
-
.rf-bento__eyebrow:has(a) a::before { content: ''; position: absolute; inset: 0; border-radius: inherit; }
|
|
31
|
-
.rf-bento__headline {
|
|
32
|
-
margin-top: 0;
|
|
33
|
-
}
|
|
34
|
-
.rf-bento__blurb {
|
|
35
|
-
color: var(--rf-color-muted);
|
|
36
|
-
margin-bottom: 0;
|
|
37
|
-
}
|
|
38
|
-
.rf-bento__image {
|
|
39
|
-
margin-bottom: 1rem;
|
|
40
|
-
}
|
|
1
|
+
/* Bento — a grid of cells, each a card-in-a-grid-track (SPEC-085). */
|
|
2
|
+
|
|
3
|
+
/* The grid responds to its OWN width, not the viewport, so it reduces columns and
|
|
4
|
+
* stacks correctly inside any container — a doc preview, a sidebar, a narrow page
|
|
5
|
+
* track — not just at viewport breakpoints. The progressive-reduction and collapse
|
|
6
|
+
* rules below are `@container rf-bento` queries against this. */
|
|
7
|
+
.rf-bento {
|
|
8
|
+
container-type: inline-size;
|
|
9
|
+
container-name: rf-bento;
|
|
10
|
+
}
|
|
11
|
+
|
|
41
12
|
.rf-bento__grid {
|
|
13
|
+
/* Effective column count: the author's `--bento-columns` (default 6),
|
|
14
|
+
* progressively reduced at breakpoints below. A CSS variable (not the inline
|
|
15
|
+
* `--bento-columns`) so the media queries can override it without !important. */
|
|
16
|
+
--bento-cols-effective: var(--bento-columns, 6);
|
|
42
17
|
display: grid;
|
|
43
|
-
grid-template-columns: repeat(var(--bento-
|
|
18
|
+
grid-template-columns: repeat(var(--bento-cols-effective), 1fr);
|
|
19
|
+
/* Uniform fixed row tracks in grid mode — never tied to column width (which
|
|
20
|
+
* would explode vertically on collapse). Makes row spans meaningful and bounds
|
|
21
|
+
* tall guests instead of letting them balloon a row. When the grid collapses to
|
|
22
|
+
* a single column it becomes a STACK, and `--bento-row-track` is flipped to
|
|
23
|
+
* `auto` (below) so cells size to their content and text is never clipped.
|
|
24
|
+
* `--bento-row-height` is the author's `row-height` preset (below); it falls
|
|
25
|
+
* back to the theme default `--rf-bento-row-height`. */
|
|
26
|
+
grid-auto-rows: var(--bento-row-track, var(--bento-row-height, var(--rf-bento-row-height, 24rem)));
|
|
44
27
|
gap: var(--bento-gap, 1rem);
|
|
45
28
|
}
|
|
29
|
+
|
|
30
|
+
/* Author row-height presets — the uniform grid row track height (grid mode). */
|
|
31
|
+
.rf-bento[data-row-height="sm"] { --bento-row-height: 16rem; }
|
|
32
|
+
.rf-bento[data-row-height="md"] { --bento-row-height: 24rem; }
|
|
33
|
+
.rf-bento[data-row-height="lg"] { --bento-row-height: 32rem; }
|
|
34
|
+
.rf-bento[data-row-height="xl"] { --bento-row-height: 40rem; }
|
|
35
|
+
|
|
36
|
+
/* content-height / media-ratio — perpendicular text-zone knobs, each settable as
|
|
37
|
+
* a GRID default (on .rf-bento, inherited by every cell) or a per-CELL override
|
|
38
|
+
* (on .rf-bento-cell, shadowing the inherited value). A cell is either a column
|
|
39
|
+
* cell or a beside cell, so the two never collide:
|
|
40
|
+
* • column cells (top/bottom/no-media): `content-height` pins the TEXT height;
|
|
41
|
+
* the media zone (flex:1) absorbs the rest of the row track.
|
|
42
|
+
* • beside cells (start/end): `media-ratio` pins the MEDIA width; the content
|
|
43
|
+
* (flex:1) absorbs the rest of the cell width.
|
|
44
|
+
* The cascade is pure CSS variable inheritance — grid sets the var on the
|
|
45
|
+
* section, a cell redeclares it on itself. */
|
|
46
|
+
.rf-bento[data-content-height="sm"], .rf-bento-cell[data-content-height="sm"] { --cell-content-height: 6rem; --cell-content-overflow: hidden; }
|
|
47
|
+
.rf-bento[data-content-height="md"], .rf-bento-cell[data-content-height="md"] { --cell-content-height: 10rem; --cell-content-overflow: hidden; }
|
|
48
|
+
.rf-bento[data-content-height="lg"], .rf-bento-cell[data-content-height="lg"] { --cell-content-height: 14rem; --cell-content-overflow: hidden; }
|
|
49
|
+
.rf-bento[data-content-height="xl"], .rf-bento-cell[data-content-height="xl"] { --cell-content-height: 18rem; --cell-content-overflow: hidden; }
|
|
50
|
+
|
|
51
|
+
.rf-bento[data-media-ratio="1/3"], .rf-bento-cell[data-media-ratio="1/3"] { --cell-media-ratio: 33.333%; }
|
|
52
|
+
.rf-bento[data-media-ratio="2/5"], .rf-bento-cell[data-media-ratio="2/5"] { --cell-media-ratio: 40%; }
|
|
53
|
+
.rf-bento[data-media-ratio="1/2"], .rf-bento-cell[data-media-ratio="1/2"] { --cell-media-ratio: 50%; }
|
|
54
|
+
.rf-bento[data-media-ratio="3/5"], .rf-bento-cell[data-media-ratio="3/5"] { --cell-media-ratio: 60%; }
|
|
55
|
+
.rf-bento[data-media-ratio="2/3"], .rf-bento-cell[data-media-ratio="2/3"] { --cell-media-ratio: 66.667%; }
|
|
56
|
+
|
|
57
|
+
/* content-height pins the text area on COLUMN cells only (top/bottom — and
|
|
58
|
+
* no-media cells, which default to `top`). Positive selectors keep this at the
|
|
59
|
+
* same specificity as the mobile/collapse stack resets below, so those still win
|
|
60
|
+
* and the text area returns to natural height when stacked. Both the basis and
|
|
61
|
+
* the clip are gated on content-height being set (via the cascading vars): when
|
|
62
|
+
* unset they fall back to `auto` / `visible`, so the content zone keeps its
|
|
63
|
+
* default overflow and a bleeding showcase (negative margins) still reaches the
|
|
64
|
+
* cell edge. The clip only engages when you actually pin the height. */
|
|
65
|
+
.rf-bento-cell[data-media-position="top"] > .rf-bento-cell__content,
|
|
66
|
+
.rf-bento-cell[data-media-position="bottom"] > .rf-bento-cell__content {
|
|
67
|
+
flex-basis: var(--cell-content-height, auto);
|
|
68
|
+
overflow: var(--cell-content-overflow, visible);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/* Cell footprint: resolved `cols`/`rows` spans, auto-capped to the effective
|
|
72
|
+
* column count so a wide cell never overflows the (reduced) grid. */
|
|
46
73
|
.rf-bento-cell {
|
|
47
|
-
|
|
48
|
-
|
|
74
|
+
grid-column: span min(var(--cell-cols, 1), var(--bento-cols-effective, 6));
|
|
75
|
+
grid-row: span var(--cell-rows, 1);
|
|
76
|
+
min-width: 0;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/* The cell. `:where()` keeps the background at zero specificity so a per-cell
|
|
80
|
+
* `{% tint %}` can repaint it (tint-deferrable). */
|
|
81
|
+
:where(.rf-bento-cell) {
|
|
49
82
|
background: var(--rf-color-surface);
|
|
50
|
-
overflow: hidden;
|
|
51
|
-
}
|
|
52
|
-
.rf-bento-cell--full {
|
|
53
|
-
grid-column: 1 / -1;
|
|
54
|
-
}
|
|
55
|
-
.rf-bento-cell--large {
|
|
56
|
-
grid-column: span 2;
|
|
57
|
-
grid-row: span 2;
|
|
58
|
-
}
|
|
59
|
-
.rf-bento-cell--medium {
|
|
60
|
-
grid-column: span 2;
|
|
61
83
|
}
|
|
62
|
-
.rf-bento-cell
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
84
|
+
.rf-bento-cell {
|
|
85
|
+
border-radius: var(--rf-radius-container);
|
|
86
|
+
/* The cell hugs its media with only a thin edge margin; the content zone adds
|
|
87
|
+
* the remaining inset back (below), so copy still sits at the full padding
|
|
88
|
+
* while media — and a media banner — sits close to the cell border.
|
|
89
|
+
* `--bento-media-gap` is the always-on space between media and content (in any
|
|
90
|
+
* `data-media-position`), regardless of cell size; the flex gap handles both
|
|
91
|
+
* column / column-reverse (top/bottom) and row / row-reverse (start/end). */
|
|
92
|
+
--container-padding: 1.25rem;
|
|
93
|
+
--bento-cell-edge: 0.5rem;
|
|
94
|
+
--bento-media-gap: var(--rf-spacing-md);
|
|
95
|
+
padding: var(--bento-cell-edge);
|
|
96
|
+
border: 1px solid var(--rf-color-border);
|
|
97
|
+
overflow: hidden;
|
|
98
|
+
position: relative; /* anchor for the stretched link */
|
|
99
|
+
display: flex;
|
|
100
|
+
flex-direction: column;
|
|
101
|
+
gap: var(--bento-media-gap);
|
|
102
|
+
min-height: 0;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/* Media placement (data-media-position): top stacks media above content (the
|
|
106
|
+
* default flow order); bottom flips it; start/end place media beside the body. */
|
|
107
|
+
.rf-bento-cell[data-media-position="bottom"] { flex-direction: column-reverse; }
|
|
108
|
+
.rf-bento-cell[data-media-position="start"] { flex-direction: row; align-items: stretch; }
|
|
109
|
+
.rf-bento-cell[data-media-position="end"] { flex-direction: row-reverse; align-items: stretch; }
|
|
110
|
+
.rf-bento-cell[data-media-position="start"] > .rf-bento-cell__media,
|
|
111
|
+
.rf-bento-cell[data-media-position="end"] > .rf-bento-cell__media {
|
|
112
|
+
flex: 0 0 var(--cell-media-ratio, 42%);
|
|
113
|
+
margin-bottom: 0;
|
|
114
|
+
align-self: stretch;
|
|
115
|
+
}
|
|
116
|
+
.rf-bento-cell[data-media-position="start"] > .rf-bento-cell__content,
|
|
117
|
+
.rf-bento-cell[data-media-position="end"] > .rf-bento-cell__content { flex: 1; min-width: 0; }
|
|
118
|
+
|
|
119
|
+
/* Zones. The WORK-339 media-zone selector sizes/clips any guest — no per-guest
|
|
120
|
+
* CSS here. */
|
|
121
|
+
.rf-bento-cell__media { margin-bottom: 0; }
|
|
122
|
+
/* Text-first: the body keeps its natural height and is never squeezed out by
|
|
123
|
+
* media. In a fixed grid track the media zone (top/bottom) absorbs the leftover
|
|
124
|
+
* height and crops (cover); once collapsed to a stack it becomes an aspect-ratio
|
|
125
|
+
* banner (below). `--bento-media-aspect` is the knob SPEC-086's `frame-aspect`
|
|
126
|
+
* will drive; `--bento-media-anchor` picks which slice shows when cropped (e.g.
|
|
127
|
+
* `top` to peek the top of a tall guest like a phone mockup). */
|
|
128
|
+
/* Add the remaining inset back on top of the cell's thin edge, so text sits at
|
|
129
|
+
* the full `--container-padding`. The top inset doubles as the gap between media
|
|
130
|
+
* and copy (media zone carries no margin of its own). */
|
|
131
|
+
.rf-bento-cell__content {
|
|
132
|
+
display: flex;
|
|
133
|
+
flex-direction: column;
|
|
134
|
+
min-height: 0;
|
|
135
|
+
flex: 0 0 auto;
|
|
136
|
+
padding: calc(var(--container-padding) - var(--bento-cell-edge));
|
|
77
137
|
}
|
|
78
|
-
.rf-bento-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
138
|
+
.rf-bento-cell[data-media-position="top"] > .rf-bento-cell__media,
|
|
139
|
+
.rf-bento-cell[data-media-position="bottom"] > .rf-bento-cell__media {
|
|
140
|
+
flex: 1 1 auto;
|
|
141
|
+
min-height: 0;
|
|
142
|
+
aspect-ratio: var(--bento-media-aspect, 16 / 9);
|
|
82
143
|
}
|
|
144
|
+
.rf-bento-cell__media > :is(img, video) { object-position: var(--bento-media-anchor, center); }
|
|
83
145
|
.rf-bento-cell__title {
|
|
84
146
|
font-size: 1.125rem;
|
|
85
147
|
font-weight: 600;
|
|
86
148
|
margin: 0 0 0.5rem;
|
|
87
149
|
}
|
|
150
|
+
.rf-bento-cell__body { min-height: 0; }
|
|
88
151
|
.rf-bento-cell__body > span[property],
|
|
89
152
|
.rf-bento-cell__body > meta { display: none; }
|
|
153
|
+
.rf-bento-cell__body > :first-child { margin-top: 0; }
|
|
90
154
|
.rf-bento-cell__body p:last-child { margin-bottom: 0; }
|
|
91
|
-
.rf-bento-
|
|
155
|
+
.rf-bento-cell__footer {
|
|
156
|
+
margin-top: auto;
|
|
157
|
+
padding-top: 0.5rem;
|
|
158
|
+
border-top: 1px solid var(--rf-color-border);
|
|
159
|
+
font-size: 0.8125em;
|
|
160
|
+
color: var(--rf-color-muted);
|
|
161
|
+
}
|
|
162
|
+
.rf-bento-cell__body img {
|
|
92
163
|
width: 100%;
|
|
93
164
|
height: auto;
|
|
94
165
|
border-radius: var(--rf-radius-sm);
|
|
95
166
|
margin-bottom: 0.75rem;
|
|
96
167
|
}
|
|
97
|
-
|
|
168
|
+
|
|
169
|
+
/* Whole-cell link — stretched overlay; nested links stay clickable. */
|
|
170
|
+
.rf-bento-cell__link { position: absolute; inset: 0; z-index: 0; }
|
|
171
|
+
.rf-bento-cell a:not(.rf-bento-cell__link) { position: relative; z-index: 1; }
|
|
172
|
+
|
|
173
|
+
/* Drop padding on bleed edges when a showcase bleeds (clipped to a peek by
|
|
174
|
+
* the media-zone + cell overflow). */
|
|
98
175
|
.rf-bento-cell:has(.rf-showcase[data-bleed="bottom"]),
|
|
99
176
|
.rf-bento-cell:has(.rf-showcase[data-bleed="both"]),
|
|
100
|
-
.rf-bento-cell:has(.rf-showcase[data-bleed="bottom-end"]) {
|
|
101
|
-
padding-bottom: 0;
|
|
102
|
-
}
|
|
177
|
+
.rf-bento-cell:has(.rf-showcase[data-bleed="bottom-end"]) { padding-bottom: 0; }
|
|
103
178
|
.rf-bento-cell:has(.rf-showcase[data-bleed="end"]),
|
|
104
179
|
.rf-bento-cell:has(.rf-showcase[data-bleed="bottom-end"]),
|
|
105
|
-
.rf-bento-cell:has(.rf-showcase[data-bleed="top-end"]) {
|
|
106
|
-
padding-inline-end: 0;
|
|
107
|
-
}
|
|
180
|
+
.rf-bento-cell:has(.rf-showcase[data-bleed="top-end"]) { padding-inline-end: 0; }
|
|
108
181
|
.rf-bento-cell:has(.rf-showcase[data-bleed="top"]),
|
|
109
182
|
.rf-bento-cell:has(.rf-showcase[data-bleed="both"]),
|
|
110
|
-
.rf-bento-cell:has(.rf-showcase[data-bleed="top-end"]) {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
.rf-bento-
|
|
124
|
-
.rf-bento-cell
|
|
125
|
-
.rf-bento-cell
|
|
183
|
+
.rf-bento-cell:has(.rf-showcase[data-bleed="top-end"]) { padding-top: 0; }
|
|
184
|
+
|
|
185
|
+
/* ─── Binary collapse ─── Above the chosen breakpoint, the grid renders exactly
|
|
186
|
+
* as authored: `columns` and per-cell `cols`/`rows` are honored (span auto-cap
|
|
187
|
+
* above still keeps wide cells inside the grid). Below it, the grid drops to a
|
|
188
|
+
* single stacked column with auto row tracks (cells size to content, never
|
|
189
|
+
* clipped). Default = `sm` (640px), so phones stack but tablet-portrait and up
|
|
190
|
+
* keep the grid. Authors who want graceful column reduction between desktop and
|
|
191
|
+
* stack can opt in via `collapse="gradual"` (not yet implemented). */
|
|
192
|
+
@container rf-bento (max-width: 640px) {
|
|
193
|
+
/* `[data-collapse=""]` matches the unset (default) case — the engine emits
|
|
194
|
+
* the attribute with an empty value when the author doesn't set it, so a bare
|
|
195
|
+
* `:not([data-collapse])` wouldn't match. */
|
|
196
|
+
:is(.rf-bento[data-collapse="sm"], .rf-bento[data-collapse=""]) .rf-bento__grid { --bento-cols-effective: 1; --bento-row-track: auto; }
|
|
197
|
+
:is(.rf-bento[data-collapse="sm"], .rf-bento[data-collapse=""]) .rf-bento-cell[data-media-position="start"],
|
|
198
|
+
:is(.rf-bento[data-collapse="sm"], .rf-bento[data-collapse=""]) .rf-bento-cell[data-media-position="end"] { flex-direction: column; }
|
|
199
|
+
:is(.rf-bento[data-collapse="sm"], .rf-bento[data-collapse=""]) .rf-bento-cell[data-media-position] > .rf-bento-cell__media { flex: 0 0 auto; aspect-ratio: var(--bento-media-aspect, 16 / 9); }
|
|
200
|
+
:is(.rf-bento[data-collapse="sm"], .rf-bento[data-collapse=""]) .rf-bento-cell[data-media-position] > .rf-bento-cell__content { flex: 0 0 auto; }
|
|
201
|
+
}
|
|
202
|
+
@container rf-bento (max-width: 768px) {
|
|
203
|
+
.rf-bento[data-collapse="md"] .rf-bento__grid { --bento-cols-effective: 1; --bento-row-track: auto; }
|
|
204
|
+
.rf-bento[data-collapse="md"] .rf-bento-cell[data-media-position="start"],
|
|
205
|
+
.rf-bento[data-collapse="md"] .rf-bento-cell[data-media-position="end"] { flex-direction: column; }
|
|
206
|
+
.rf-bento[data-collapse="md"] .rf-bento-cell[data-media-position] > .rf-bento-cell__media { flex: 0 0 auto; aspect-ratio: var(--bento-media-aspect, 16 / 9); }
|
|
207
|
+
.rf-bento[data-collapse="md"] .rf-bento-cell[data-media-position] > .rf-bento-cell__content { flex: 0 0 auto; }
|
|
208
|
+
}
|
|
209
|
+
@container rf-bento (max-width: 1024px) {
|
|
210
|
+
.rf-bento[data-collapse="lg"] .rf-bento__grid { --bento-cols-effective: 1; --bento-row-track: auto; }
|
|
211
|
+
.rf-bento[data-collapse="lg"] .rf-bento-cell[data-media-position="start"],
|
|
212
|
+
.rf-bento[data-collapse="lg"] .rf-bento-cell[data-media-position="end"] { flex-direction: column; }
|
|
213
|
+
.rf-bento[data-collapse="lg"] .rf-bento-cell[data-media-position] > .rf-bento-cell__media { flex: 0 0 auto; aspect-ratio: var(--bento-media-aspect, 16 / 9); }
|
|
214
|
+
.rf-bento[data-collapse="lg"] .rf-bento-cell[data-media-position] > .rf-bento-cell__content { flex: 0 0 auto; }
|
|
126
215
|
}
|
package/styles/runes/bond.css
CHANGED
package/styles/runes/budget.css
CHANGED
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
gap: 1rem;
|
|
87
87
|
}
|
|
88
88
|
.rf-budget-line-item + .rf-budget-line-item {
|
|
89
|
-
border-top: 1px solid var(--rf-color-border
|
|
89
|
+
border-top: 1px solid var(--rf-color-border);
|
|
90
90
|
}
|
|
91
91
|
.rf-budget-line-item__description {
|
|
92
92
|
font-size: 0.875rem;
|
package/styles/runes/card.css
CHANGED
|
@@ -1,20 +1,75 @@
|
|
|
1
1
|
/* card — generic content card (SPEC-070).
|
|
2
2
|
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* data-
|
|
3
|
+
* A soft surface fill plus a subtle border; the surface + border + structure
|
|
4
|
+
* (media split, footer separator) carry the card. The media|content split +
|
|
5
|
+
* responsive collapse + inset media banner come from the shared
|
|
6
|
+
* layouts/split.css (keyed off data-layout / data-section="media" /
|
|
7
|
+
* data-name="content" / data-media-position).
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
.rf-card {
|
|
11
|
-
position: relative; /* anchor for the stretched link
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
position: relative; /* anchor for the stretched link */
|
|
12
|
+
/* Thin-edge inset model (matches `bento-cell`): the card hugs its media with
|
|
13
|
+
* only a small edge margin, and the content zone adds the remaining inset
|
|
14
|
+
* back below — so text still sits at the full `--rune-padding` while media
|
|
15
|
+
* sits close to the card border, with no negative-margin bleed.
|
|
16
|
+
* • `--rf-card-edge` — fixed thin outer padding.
|
|
17
|
+
* • `--rf-card-media-gap` — generous gap when media stacks above/below
|
|
18
|
+
* content (stacked layout, or split collapsed
|
|
19
|
+
* to one column on mobile).
|
|
20
|
+
* • `--rf-card-split-gap` — tight gap when media sits beside content,
|
|
21
|
+
* so the card reads as a unified surface
|
|
22
|
+
* rather than two loosely-related panels. */
|
|
23
|
+
--rf-card-edge: 0.5rem;
|
|
24
|
+
--rf-card-media-gap: var(--rf-spacing-lg);
|
|
25
|
+
--rf-card-split-gap: var(--rf-spacing-sm);
|
|
26
|
+
padding: var(--rf-card-edge);
|
|
27
|
+
border-radius: var(--rf-radius-container);
|
|
28
|
+
border: 1px solid var(--rf-color-border);
|
|
14
29
|
background: var(--rf-color-surface);
|
|
15
30
|
}
|
|
16
31
|
|
|
17
|
-
|
|
32
|
+
/* Content zone fills the remaining inset so total text padding still equals
|
|
33
|
+
* `--rune-padding`. `max(0, …)` keeps dense+ (rune-padding < edge) safe — at
|
|
34
|
+
* tighter densities the edge becomes the floor. */
|
|
35
|
+
.rf-card__content {
|
|
36
|
+
padding: max(0px, calc(var(--rune-padding, var(--rf-spacing-md)) - var(--rf-card-edge)));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/* Split layout: tight column-gap when media sits beside content. `row-gap`
|
|
40
|
+
* stays at the larger media-gap so the collapse step (split grid → single
|
|
41
|
+
* column) automatically picks up the generous stacked spacing instead of
|
|
42
|
+
* inheriting the tight beside-gap. (2-section cards have only one grid row in
|
|
43
|
+
* the uncollapsed state, so row-gap is dormant until collapse.) `stretch`
|
|
44
|
+
* lets the media zone match the content's height — the image inside uses
|
|
45
|
+
* `object-fit: cover` so it re-crops rather than letterboxing when content
|
|
46
|
+
* is taller than the media's natural aspect ratio.
|
|
47
|
+
*
|
|
48
|
+
* We set `column-gap` / `row-gap` / `align-items` directly rather than override
|
|
49
|
+
* `--split-gap` / `--split-valign`: the shared split layout transform emits
|
|
50
|
+
* those vars as inline styles even when the author doesn't set the matching
|
|
51
|
+
* attributes, so a CSS-variable override loses to inline-style specificity.
|
|
52
|
+
* Direct grid properties win via selector specificity and stay in our control. */
|
|
53
|
+
.rf-card[data-media-position="start"],
|
|
54
|
+
.rf-card[data-media-position="end"] {
|
|
55
|
+
column-gap: var(--rf-card-split-gap);
|
|
56
|
+
row-gap: var(--rf-card-media-gap);
|
|
57
|
+
align-items: stretch;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/* Stacked layouts (top / bottom): explicit gap between the media banner and
|
|
61
|
+
* the content zone (replaces the figure-style margin-bottom from the bleed
|
|
62
|
+
* model). For `bottom`, column-reverse already flips the visual order, so the
|
|
63
|
+
* gap still reads as the space between the two zones. */
|
|
64
|
+
.rf-card[data-media-position="top"] > [data-section="media"] {
|
|
65
|
+
margin-bottom: var(--rf-card-media-gap);
|
|
66
|
+
}
|
|
67
|
+
.rf-card[data-media-position="bottom"] > [data-section="media"] {
|
|
68
|
+
margin-top: var(--rf-card-media-gap);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/* Only a linked card (stretched `.rf-card__link` present) reacts to hover. */
|
|
72
|
+
.rf-card:has(.rf-card__link):hover {
|
|
18
73
|
background: var(--rf-color-surface-hover);
|
|
19
74
|
}
|
|
20
75
|
|
package/styles/runes/chart.css
CHANGED
|
@@ -1,9 +1,103 @@
|
|
|
1
1
|
/* Chart */
|
|
2
2
|
.rf-chart {
|
|
3
|
+
/* ─── Theming contract (SPEC-083 / WORK-353) ───
|
|
4
|
+
* Every paint + geometry value the renderer uses is one of these
|
|
5
|
+
* `--rf-chart-*` properties; a theme overrides any of them (here, on a tint
|
|
6
|
+
* scope, or inline) with no renderer or selector changes. A non-CSS provider
|
|
7
|
+
* (canvas) reads the same props via getComputedStyle. */
|
|
8
|
+
|
|
9
|
+
/* Series palette — a dedicated categorical palette, deliberately distinct
|
|
10
|
+
* from the semantic status tokens (those are reserved for sentiment mode). */
|
|
11
|
+
--rf-chart-series-1: #6366f1;
|
|
12
|
+
--rf-chart-series-2: #06b6d4;
|
|
13
|
+
--rf-chart-series-3: #22c55e;
|
|
14
|
+
--rf-chart-series-4: #f59e0b;
|
|
15
|
+
--rf-chart-series-5: #a855f7;
|
|
16
|
+
--rf-chart-series-6: #ec4899;
|
|
17
|
+
|
|
18
|
+
/* Geometry (layout values the renderer reads via getComputedStyle). */
|
|
19
|
+
--rf-chart-bar-ratio: 0.75; /* bar width as a fraction of its slot */
|
|
20
|
+
--rf-chart-bar-thickness: 48px; /* max bar width cap */
|
|
21
|
+
--rf-chart-bar-gap: 0.15; /* slot fraction reserved as inter-group gap */
|
|
22
|
+
--rf-chart-bar-radius: 2px;
|
|
23
|
+
--rf-chart-point-radius: 4px;
|
|
24
|
+
--rf-chart-line-width: 2px;
|
|
25
|
+
|
|
26
|
+
/* Typography / grid (paint values applied by CSS below). */
|
|
27
|
+
--rf-chart-label-size: 12px;
|
|
28
|
+
--rf-chart-label-color: var(--rf-color-muted);
|
|
29
|
+
--rf-chart-grid-color: var(--rf-color-border);
|
|
30
|
+
--rf-chart-grid-width: 1px;
|
|
31
|
+
|
|
32
|
+
display: block;
|
|
3
33
|
border-radius: var(--rf-radius-lg);
|
|
4
34
|
padding: 1.5rem;
|
|
5
35
|
margin: 0;
|
|
6
36
|
}
|
|
37
|
+
|
|
38
|
+
/* ─── SVG paint — driven entirely by the contract (the renderer sets no inline
|
|
39
|
+
* fill/stroke; it only tags elements with a class + data-series + optional
|
|
40
|
+
* data-meta-sentiment). ─── */
|
|
41
|
+
.rf-chart__axis { stroke: var(--rf-chart-grid-color); stroke-width: var(--rf-chart-grid-width); }
|
|
42
|
+
.rf-chart__label { fill: var(--rf-chart-label-color); font-size: var(--rf-chart-label-size); }
|
|
43
|
+
.rf-chart__bar { rx: var(--rf-chart-bar-radius); fill: var(--rf-chart-series-1); }
|
|
44
|
+
.rf-chart__point { fill: var(--rf-chart-series-1); }
|
|
45
|
+
.rf-chart__line { fill: none; stroke: var(--rf-chart-series-1); stroke-width: var(--rf-chart-line-width); }
|
|
46
|
+
|
|
47
|
+
/* Series palette rotation (data-series 0 is the default above). */
|
|
48
|
+
.rf-chart__bar[data-series="1"], .rf-chart__point[data-series="1"] { fill: var(--rf-chart-series-2); }
|
|
49
|
+
.rf-chart__bar[data-series="2"], .rf-chart__point[data-series="2"] { fill: var(--rf-chart-series-3); }
|
|
50
|
+
.rf-chart__bar[data-series="3"], .rf-chart__point[data-series="3"] { fill: var(--rf-chart-series-4); }
|
|
51
|
+
.rf-chart__bar[data-series="4"], .rf-chart__point[data-series="4"] { fill: var(--rf-chart-series-5); }
|
|
52
|
+
.rf-chart__bar[data-series="5"], .rf-chart__point[data-series="5"] { fill: var(--rf-chart-series-6); }
|
|
53
|
+
.rf-chart__line[data-series="1"] { stroke: var(--rf-chart-series-2); }
|
|
54
|
+
.rf-chart__line[data-series="2"] { stroke: var(--rf-chart-series-3); }
|
|
55
|
+
.rf-chart__line[data-series="3"] { stroke: var(--rf-chart-series-4); }
|
|
56
|
+
.rf-chart__line[data-series="4"] { stroke: var(--rf-chart-series-5); }
|
|
57
|
+
.rf-chart__line[data-series="5"] { stroke: var(--rf-chart-series-6); }
|
|
58
|
+
|
|
59
|
+
/* Sentiment colouring — a data cell carrying `data-meta-sentiment` overrides the
|
|
60
|
+
* rotating palette with the semantic token (the roadmap chart renders green-done
|
|
61
|
+
* / red-blocked with no per-chart config). After the palette so it wins at equal
|
|
62
|
+
* specificity. */
|
|
63
|
+
.rf-chart__bar[data-meta-sentiment="positive"], .rf-chart__point[data-meta-sentiment="positive"] { fill: var(--rf-color-success); }
|
|
64
|
+
.rf-chart__bar[data-meta-sentiment="negative"], .rf-chart__point[data-meta-sentiment="negative"] { fill: var(--rf-color-danger); }
|
|
65
|
+
.rf-chart__bar[data-meta-sentiment="caution"], .rf-chart__point[data-meta-sentiment="caution"] { fill: var(--rf-color-warning); }
|
|
66
|
+
.rf-chart__bar[data-meta-sentiment="neutral"], .rf-chart__point[data-meta-sentiment="neutral"] { fill: var(--rf-color-muted); }
|
|
67
|
+
.rf-chart__line[data-meta-sentiment="positive"] { stroke: var(--rf-color-success); }
|
|
68
|
+
.rf-chart__line[data-meta-sentiment="negative"] { stroke: var(--rf-color-danger); }
|
|
69
|
+
.rf-chart__line[data-meta-sentiment="caution"] { stroke: var(--rf-color-warning); }
|
|
70
|
+
.rf-chart__line[data-meta-sentiment="neutral"] { stroke: var(--rf-color-muted); }
|
|
71
|
+
|
|
72
|
+
/* Data table — the no-JS / screen-reader source of truth. Visible as the
|
|
73
|
+
* fallback; visually-hidden (but kept for assistive tech) once rf-chart has
|
|
74
|
+
* rendered the svg. */
|
|
75
|
+
.rf-chart__data {
|
|
76
|
+
width: 100%;
|
|
77
|
+
border-collapse: collapse;
|
|
78
|
+
font-size: 0.875rem;
|
|
79
|
+
}
|
|
80
|
+
.rf-chart__data caption {
|
|
81
|
+
font-weight: 600;
|
|
82
|
+
margin-bottom: 0.75rem;
|
|
83
|
+
}
|
|
84
|
+
.rf-chart__data th,
|
|
85
|
+
.rf-chart__data td {
|
|
86
|
+
border: 1px solid var(--rf-color-border);
|
|
87
|
+
padding: 0.375rem 0.625rem;
|
|
88
|
+
text-align: left;
|
|
89
|
+
}
|
|
90
|
+
.rf-chart[data-rendered] .rf-chart__data {
|
|
91
|
+
position: absolute;
|
|
92
|
+
width: 1px;
|
|
93
|
+
height: 1px;
|
|
94
|
+
padding: 0;
|
|
95
|
+
margin: -1px;
|
|
96
|
+
overflow: hidden;
|
|
97
|
+
clip: rect(0, 0, 0, 0);
|
|
98
|
+
white-space: nowrap;
|
|
99
|
+
border: 0;
|
|
100
|
+
}
|
|
7
101
|
.rf-chart__title {
|
|
8
102
|
font-weight: 600;
|
|
9
103
|
font-size: 1rem;
|
|
@@ -29,4 +123,10 @@
|
|
|
29
123
|
width: 12px;
|
|
30
124
|
height: 12px;
|
|
31
125
|
border-radius: 2px;
|
|
126
|
+
background: var(--rf-chart-series-1);
|
|
32
127
|
}
|
|
128
|
+
.rf-chart__legend-color[data-series="1"] { background: var(--rf-chart-series-2); }
|
|
129
|
+
.rf-chart__legend-color[data-series="2"] { background: var(--rf-chart-series-3); }
|
|
130
|
+
.rf-chart__legend-color[data-series="3"] { background: var(--rf-chart-series-4); }
|
|
131
|
+
.rf-chart__legend-color[data-series="4"] { background: var(--rf-chart-series-5); }
|
|
132
|
+
.rf-chart__legend-color[data-series="5"] { background: var(--rf-chart-series-6); }
|
|
@@ -10,12 +10,14 @@
|
|
|
10
10
|
gap: 1.5rem;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
/* Children inside design-context: remove card styling
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
/* Children inside design-context: remove card styling so the outer
|
|
14
|
+
* design-context surface is the only visible frame. Structural selector
|
|
15
|
+
* (`> [data-rune]` inside the sections wrapper) catches every direct rune
|
|
16
|
+
* child, not just the four design-system runes — so dropping a future rune
|
|
17
|
+
* into a design-context will Just Work without a per-rune CSS update. */
|
|
18
|
+
.rf-design-context__sections > [data-rune] {
|
|
18
19
|
background: none;
|
|
20
|
+
border: none;
|
|
19
21
|
border-radius: 0;
|
|
20
22
|
padding: 0;
|
|
21
23
|
}
|
package/styles/runes/drawer.css
CHANGED
|
@@ -124,6 +124,10 @@ dialog.rf-drawer .rf-drawer__header {
|
|
|
124
124
|
align-items: center;
|
|
125
125
|
justify-content: space-between;
|
|
126
126
|
gap: var(--rf-spacing-md);
|
|
127
|
+
/* Reset the generous `[data-section="header"]` bottom margin (3rem) — the
|
|
128
|
+
* dialog chrome spaces the header from the body via the body's own
|
|
129
|
+
* padding, so the section default would push the body off-screen. */
|
|
130
|
+
margin: 0;
|
|
127
131
|
padding: var(--rf-spacing-md) var(--rf-spacing-lg);
|
|
128
132
|
border-bottom: 1px solid var(--rf-drawer-border);
|
|
129
133
|
background: var(--rf-drawer-bg);
|
package/styles/runes/event.css
CHANGED
package/styles/runes/expand.css
CHANGED
|
@@ -23,15 +23,13 @@
|
|
|
23
23
|
margin: var(--rf-spacing-md) 0;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
/* Peer-document mode —
|
|
27
|
-
*
|
|
28
|
-
* visually with the host content. Authors who want a stronger
|
|
29
|
-
*
|
|
30
|
-
* theme. */
|
|
26
|
+
/* Peer-document mode — no background, no rounded corners, no rules.
|
|
27
|
+
* Reads as "set-aside material" through spacing alone, without competing
|
|
28
|
+
* visually with the host content. Authors who want a stronger treatment
|
|
29
|
+
* (rules, background, etc.) can override `.rf-expand[data-outline-scope]`
|
|
30
|
+
* in their theme. */
|
|
31
31
|
.rf-expand[data-outline-scope] {
|
|
32
32
|
padding: var(--rf-spacing-md) 0;
|
|
33
|
-
border-top: 1px solid var(--rf-color-border);
|
|
34
|
-
border-bottom: 1px solid var(--rf-color-border);
|
|
35
33
|
}
|
|
36
34
|
|
|
37
35
|
/* Tone down embedded headings so the host outline keeps visual primacy.
|