@refrakt-md/lumina 0.14.3 → 0.15.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 +42 -0
- package/index.css +3 -0
- package/package.json +4 -4
- package/styles/runes/drawer.css +316 -0
- package/styles/runes/expand.css +74 -0
- package/styles/runes/nav.css +12 -3
- package/styles/runes/snippet.css +27 -0
- package/styles/runes/xref.css +16 -0
|
@@ -184,6 +184,22 @@
|
|
|
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
|
+
},
|
|
187
203
|
"Embed": {
|
|
188
204
|
"block": "embed",
|
|
189
205
|
"root": ".rf-embed",
|
|
@@ -425,6 +441,32 @@
|
|
|
425
441
|
}
|
|
426
442
|
}
|
|
427
443
|
},
|
|
444
|
+
"Drawer": {
|
|
445
|
+
"block": "drawer",
|
|
446
|
+
"root": ".rf-drawer",
|
|
447
|
+
"dataRune": "drawer",
|
|
448
|
+
"childOrder": [
|
|
449
|
+
"{content}"
|
|
450
|
+
],
|
|
451
|
+
"modifiers": {
|
|
452
|
+
"side": {
|
|
453
|
+
"source": "meta",
|
|
454
|
+
"default": "right",
|
|
455
|
+
"classPattern": ".rf-drawer--{value}",
|
|
456
|
+
"dataAttribute": "data-side"
|
|
457
|
+
},
|
|
458
|
+
"size": {
|
|
459
|
+
"source": "meta",
|
|
460
|
+
"default": "md",
|
|
461
|
+
"classPattern": ".rf-drawer--{value}",
|
|
462
|
+
"dataAttribute": "data-size"
|
|
463
|
+
},
|
|
464
|
+
"shortcut": {
|
|
465
|
+
"source": "meta",
|
|
466
|
+
"dataAttribute": "data-shortcut"
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
},
|
|
428
470
|
"Figure": {
|
|
429
471
|
"block": "figure",
|
|
430
472
|
"root": ".rf-figure",
|
package/index.css
CHANGED
|
@@ -57,10 +57,13 @@
|
|
|
57
57
|
@import './styles/runes/cta.css';
|
|
58
58
|
@import './styles/runes/datatable.css';
|
|
59
59
|
@import './styles/runes/details.css';
|
|
60
|
+
@import './styles/runes/drawer.css';
|
|
60
61
|
@import './styles/runes/diagram.css';
|
|
61
62
|
@import './styles/runes/diff.css';
|
|
62
63
|
@import './styles/runes/codegroup.css';
|
|
64
|
+
@import './styles/runes/snippet.css';
|
|
63
65
|
@import './styles/runes/embed.css';
|
|
66
|
+
@import './styles/runes/expand.css';
|
|
64
67
|
@import './styles/runes/event.css';
|
|
65
68
|
@import './styles/runes/faction.css';
|
|
66
69
|
@import './styles/runes/feature.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.15.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.15.0",
|
|
87
|
+
"@refrakt-md/transform": "0.15.0",
|
|
88
|
+
"@refrakt-md/types": "0.15.0"
|
|
89
89
|
},
|
|
90
90
|
"devDependencies": {
|
|
91
91
|
"postcss": "^8.4.0"
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
/* Drawer — addressable modal panel (SPEC-060).
|
|
2
|
+
*
|
|
3
|
+
* Two visual modes ride on the same `.rf-drawer` element:
|
|
4
|
+
*
|
|
5
|
+
* 1. **No-JS (in-flow)** — `.rf-drawer` not inside a `<dialog>`. Renders
|
|
6
|
+
* as a styled callout block at its authored position, visually
|
|
7
|
+
* distinct so the reader understands "set-aside material". Close
|
|
8
|
+
* button stays `hidden` (the schema marks it that way; behaviors
|
|
9
|
+
* reveals it post-enhancement).
|
|
10
|
+
* 2. **JS (panel)** — `dialog.rf-drawer[open]`. Floats slightly off the
|
|
11
|
+
* viewport edge (margin on all four sides) so it reads as a "card
|
|
12
|
+
* that slid in" rather than a flush slab. Size modifier sets width
|
|
13
|
+
* (right/left) or height (top/bottom). Slide-in animation uses
|
|
14
|
+
* `@starting-style` to interpolate from off-screen on open.
|
|
15
|
+
*
|
|
16
|
+
* Body-scroll lock is applied as a class on `<html>` by the behavior
|
|
17
|
+
* (`html.rf-drawer-open` → `overflow: hidden`) so mobile Safari doesn't
|
|
18
|
+
* scroll the page underneath the open dialog.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
.rf-drawer {
|
|
22
|
+
--rf-drawer-size-sm: 22rem;
|
|
23
|
+
--rf-drawer-size-md: 36rem;
|
|
24
|
+
--rf-drawer-size-lg: 52rem;
|
|
25
|
+
--rf-drawer-bg: var(--rf-color-surface);
|
|
26
|
+
--rf-drawer-fg: var(--rf-color-text);
|
|
27
|
+
--rf-drawer-border: var(--rf-color-border);
|
|
28
|
+
--rf-drawer-shadow: 0 18px 48px -12px rgb(0 0 0 / 0.35);
|
|
29
|
+
--rf-drawer-gutter: var(--rf-spacing-sm);
|
|
30
|
+
--rf-drawer-radius: var(--rf-radius-md);
|
|
31
|
+
--rf-drawer-anim-duration: 220ms;
|
|
32
|
+
--rf-drawer-anim-ease: cubic-bezier(0.32, 0.72, 0, 1);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/* ─── Body-scroll lock while any drawer is open ────────────────── */
|
|
36
|
+
|
|
37
|
+
html.rf-drawer-open,
|
|
38
|
+
html.rf-drawer-open body {
|
|
39
|
+
overflow: hidden;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/* ─── No-JS / in-flow mode ─────────────────────────────────────── */
|
|
43
|
+
|
|
44
|
+
section.rf-drawer {
|
|
45
|
+
margin: var(--rf-spacing-lg) 0;
|
|
46
|
+
padding: var(--rf-spacing-md) var(--rf-spacing-lg);
|
|
47
|
+
background: var(--rf-drawer-bg);
|
|
48
|
+
color: var(--rf-drawer-fg);
|
|
49
|
+
border: 1px solid var(--rf-drawer-border);
|
|
50
|
+
border-left: 4px solid var(--rf-color-primary);
|
|
51
|
+
border-radius: var(--rf-drawer-radius);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
section.rf-drawer .rf-drawer__header {
|
|
55
|
+
display: flex;
|
|
56
|
+
align-items: baseline;
|
|
57
|
+
justify-content: space-between;
|
|
58
|
+
gap: var(--rf-spacing-sm);
|
|
59
|
+
margin-bottom: var(--rf-spacing-sm);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
section.rf-drawer .rf-drawer__title {
|
|
63
|
+
margin: 0;
|
|
64
|
+
font-size: 1.05rem;
|
|
65
|
+
font-weight: 600;
|
|
66
|
+
color: var(--rf-color-primary);
|
|
67
|
+
letter-spacing: 0.01em;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
section.rf-drawer .rf-drawer__body > :first-child { margin-top: 0; }
|
|
71
|
+
section.rf-drawer .rf-drawer__body > :last-child { margin-bottom: 0; }
|
|
72
|
+
|
|
73
|
+
/* ─── JS / dialog mode ─────────────────────────────────────────── */
|
|
74
|
+
|
|
75
|
+
dialog.rf-drawer {
|
|
76
|
+
box-sizing: border-box;
|
|
77
|
+
background: var(--rf-drawer-bg);
|
|
78
|
+
color: var(--rf-drawer-fg);
|
|
79
|
+
border: 1px solid var(--rf-drawer-border);
|
|
80
|
+
border-radius: var(--rf-drawer-radius);
|
|
81
|
+
box-shadow: var(--rf-drawer-shadow);
|
|
82
|
+
padding: 0;
|
|
83
|
+
margin: 0;
|
|
84
|
+
overflow: auto;
|
|
85
|
+
max-width: calc(100vw - 2 * var(--rf-drawer-gutter));
|
|
86
|
+
max-height: calc(100vh - 2 * var(--rf-drawer-gutter));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
dialog.rf-drawer::backdrop {
|
|
90
|
+
background: rgb(0 0 0 / 0.35);
|
|
91
|
+
backdrop-filter: blur(2px);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
dialog.rf-drawer .rf-drawer__header {
|
|
95
|
+
display: flex;
|
|
96
|
+
align-items: center;
|
|
97
|
+
justify-content: space-between;
|
|
98
|
+
gap: var(--rf-spacing-md);
|
|
99
|
+
padding: var(--rf-spacing-md) var(--rf-spacing-lg);
|
|
100
|
+
border-bottom: 1px solid var(--rf-drawer-border);
|
|
101
|
+
position: sticky;
|
|
102
|
+
top: 0;
|
|
103
|
+
background: var(--rf-drawer-bg);
|
|
104
|
+
z-index: 1;
|
|
105
|
+
}dialog.rf-drawer .rf-drawer__title {
|
|
106
|
+
margin: 0;
|
|
107
|
+
font-size: 1.05rem;
|
|
108
|
+
font-weight: 600;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
dialog.rf-drawer .rf-drawer__close {
|
|
112
|
+
appearance: none;
|
|
113
|
+
background: transparent;
|
|
114
|
+
border: 0;
|
|
115
|
+
cursor: pointer;
|
|
116
|
+
color: var(--rf-color-muted);
|
|
117
|
+
padding: var(--rf-spacing-xs) var(--rf-spacing-sm);
|
|
118
|
+
font-size: 1.25rem;
|
|
119
|
+
line-height: 1;
|
|
120
|
+
border-radius: var(--rf-radius-sm);
|
|
121
|
+
flex-shrink: 0;
|
|
122
|
+
}
|
|
123
|
+
dialog.rf-drawer .rf-drawer__close:hover {
|
|
124
|
+
color: var(--rf-color-text);
|
|
125
|
+
background: var(--rf-color-surface-hover);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
dialog.rf-drawer .rf-drawer__body {
|
|
129
|
+
padding: var(--rf-spacing-md) var(--rf-spacing-lg);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/* Collapse the vertical margins of first / last children inside the body
|
|
133
|
+
* so the drawer's own padding is what spaces content from the chrome —
|
|
134
|
+
* otherwise a `<figure>` or `<p>` with its own top/bottom margin stacks
|
|
135
|
+
* on top of the body's padding and the content looks adrift. A snippet
|
|
136
|
+
* inside a drawer compiles to `body > .rf-codeblock > .rf-snippet > <pre>`,
|
|
137
|
+
* so the margin-zero walk reaches two levels deep to catch the figure. */
|
|
138
|
+
dialog.rf-drawer .rf-drawer__body > :first-child,
|
|
139
|
+
dialog.rf-drawer .rf-drawer__body > :first-child > :first-child {
|
|
140
|
+
margin-top: 0;
|
|
141
|
+
}
|
|
142
|
+
dialog.rf-drawer .rf-drawer__body > :last-child,
|
|
143
|
+
dialog.rf-drawer .rf-drawer__body > :last-child > :last-child {
|
|
144
|
+
margin-bottom: 0;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/* ─── Side modifiers ───────────────────────────────────────────────
|
|
148
|
+
*
|
|
149
|
+
* Each side anchors the dialog with `inset`. The slide-in animation is
|
|
150
|
+
* a keyframes animation triggered by `[open]` — picked over
|
|
151
|
+
* `@starting-style` because keyframes have broader browser support
|
|
152
|
+
* (everywhere `<dialog>` works) and a clearer source-of-truth: the
|
|
153
|
+
* starting/ending frames are spelled out, no cascade-interaction
|
|
154
|
+
* footguns. The matching backdrop fade is a separate animation.
|
|
155
|
+
*/
|
|
156
|
+
|
|
157
|
+
dialog.rf-drawer[data-side="right"] {
|
|
158
|
+
inset:
|
|
159
|
+
var(--rf-drawer-gutter)
|
|
160
|
+
var(--rf-drawer-gutter)
|
|
161
|
+
var(--rf-drawer-gutter)
|
|
162
|
+
auto;
|
|
163
|
+
height: auto;
|
|
164
|
+
}
|
|
165
|
+
dialog.rf-drawer[data-side="right"][open]:not([data-state="closing"]) {
|
|
166
|
+
animation: rf-drawer-slide-in-right var(--rf-drawer-anim-duration) var(--rf-drawer-anim-ease);
|
|
167
|
+
}
|
|
168
|
+
dialog.rf-drawer[data-side="right"][data-state="closing"] {
|
|
169
|
+
animation: rf-drawer-slide-out-right var(--rf-drawer-anim-duration) var(--rf-drawer-anim-ease) forwards;
|
|
170
|
+
}
|
|
171
|
+
dialog.rf-drawer[data-side="left"] {
|
|
172
|
+
inset:
|
|
173
|
+
var(--rf-drawer-gutter)
|
|
174
|
+
auto
|
|
175
|
+
var(--rf-drawer-gutter)
|
|
176
|
+
var(--rf-drawer-gutter);
|
|
177
|
+
height: auto;
|
|
178
|
+
}
|
|
179
|
+
dialog.rf-drawer[data-side="left"][open]:not([data-state="closing"]) {
|
|
180
|
+
animation: rf-drawer-slide-in-left var(--rf-drawer-anim-duration) var(--rf-drawer-anim-ease);
|
|
181
|
+
}
|
|
182
|
+
dialog.rf-drawer[data-side="left"][data-state="closing"] {
|
|
183
|
+
animation: rf-drawer-slide-out-left var(--rf-drawer-anim-duration) var(--rf-drawer-anim-ease) forwards;
|
|
184
|
+
}
|
|
185
|
+
dialog.rf-drawer[data-side="top"] {
|
|
186
|
+
inset:
|
|
187
|
+
var(--rf-drawer-gutter)
|
|
188
|
+
var(--rf-drawer-gutter)
|
|
189
|
+
auto
|
|
190
|
+
var(--rf-drawer-gutter);
|
|
191
|
+
width: auto;
|
|
192
|
+
}
|
|
193
|
+
dialog.rf-drawer[data-side="top"][open]:not([data-state="closing"]) {
|
|
194
|
+
animation: rf-drawer-slide-in-top var(--rf-drawer-anim-duration) var(--rf-drawer-anim-ease);
|
|
195
|
+
}
|
|
196
|
+
dialog.rf-drawer[data-side="top"][data-state="closing"] {
|
|
197
|
+
animation: rf-drawer-slide-out-top var(--rf-drawer-anim-duration) var(--rf-drawer-anim-ease) forwards;
|
|
198
|
+
}
|
|
199
|
+
dialog.rf-drawer[data-side="bottom"] {
|
|
200
|
+
inset:
|
|
201
|
+
auto
|
|
202
|
+
var(--rf-drawer-gutter)
|
|
203
|
+
var(--rf-drawer-gutter)
|
|
204
|
+
var(--rf-drawer-gutter);
|
|
205
|
+
width: auto;
|
|
206
|
+
}
|
|
207
|
+
dialog.rf-drawer[data-side="bottom"][open]:not([data-state="closing"]) {
|
|
208
|
+
animation: rf-drawer-slide-in-bottom var(--rf-drawer-anim-duration) var(--rf-drawer-anim-ease);
|
|
209
|
+
}
|
|
210
|
+
dialog.rf-drawer[data-side="bottom"][data-state="closing"] {
|
|
211
|
+
animation: rf-drawer-slide-out-bottom var(--rf-drawer-anim-duration) var(--rf-drawer-anim-ease) forwards;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
dialog.rf-drawer[open]:not([data-state="closing"])::backdrop {
|
|
215
|
+
animation: rf-drawer-backdrop-in var(--rf-drawer-anim-duration) var(--rf-drawer-anim-ease);
|
|
216
|
+
}
|
|
217
|
+
dialog.rf-drawer[data-state="closing"]::backdrop {
|
|
218
|
+
animation: rf-drawer-backdrop-out var(--rf-drawer-anim-duration) var(--rf-drawer-anim-ease) forwards;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
@keyframes rf-drawer-slide-in-right {
|
|
222
|
+
from { transform: translateX(calc(100% + var(--rf-drawer-gutter))); opacity: 0; }
|
|
223
|
+
to { transform: translateX(0); opacity: 1; }
|
|
224
|
+
}
|
|
225
|
+
@keyframes rf-drawer-slide-in-left {
|
|
226
|
+
from { transform: translateX(calc(-100% - var(--rf-drawer-gutter))); opacity: 0; }
|
|
227
|
+
to { transform: translateX(0); opacity: 1; }
|
|
228
|
+
}
|
|
229
|
+
@keyframes rf-drawer-slide-in-top {
|
|
230
|
+
from { transform: translateY(calc(-100% - var(--rf-drawer-gutter))); opacity: 0; }
|
|
231
|
+
to { transform: translateY(0); opacity: 1; }
|
|
232
|
+
}
|
|
233
|
+
@keyframes rf-drawer-slide-in-bottom {
|
|
234
|
+
from { transform: translateY(calc(100% + var(--rf-drawer-gutter))); opacity: 0; }
|
|
235
|
+
to { transform: translateY(0); opacity: 1; }
|
|
236
|
+
}
|
|
237
|
+
@keyframes rf-drawer-backdrop-in {
|
|
238
|
+
from { background: rgb(0 0 0 / 0); backdrop-filter: blur(0); }
|
|
239
|
+
to { background: rgb(0 0 0 / 0.35); backdrop-filter: blur(2px); }
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
@keyframes rf-drawer-slide-out-right {
|
|
243
|
+
from { transform: translateX(0); opacity: 1; }
|
|
244
|
+
to { transform: translateX(calc(100% + var(--rf-drawer-gutter))); opacity: 0; }
|
|
245
|
+
}
|
|
246
|
+
@keyframes rf-drawer-slide-out-left {
|
|
247
|
+
from { transform: translateX(0); opacity: 1; }
|
|
248
|
+
to { transform: translateX(calc(-100% - var(--rf-drawer-gutter))); opacity: 0; }
|
|
249
|
+
}
|
|
250
|
+
@keyframes rf-drawer-slide-out-top {
|
|
251
|
+
from { transform: translateY(0); opacity: 1; }
|
|
252
|
+
to { transform: translateY(calc(-100% - var(--rf-drawer-gutter))); opacity: 0; }
|
|
253
|
+
}
|
|
254
|
+
@keyframes rf-drawer-slide-out-bottom {
|
|
255
|
+
from { transform: translateY(0); opacity: 1; }
|
|
256
|
+
to { transform: translateY(calc(100% + var(--rf-drawer-gutter))); opacity: 0; }
|
|
257
|
+
}
|
|
258
|
+
@keyframes rf-drawer-backdrop-out {
|
|
259
|
+
from { background: rgb(0 0 0 / 0.35); backdrop-filter: blur(2px); }
|
|
260
|
+
to { background: rgb(0 0 0 / 0); backdrop-filter: blur(0); }
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
@media (prefers-reduced-motion: reduce) {
|
|
264
|
+
dialog.rf-drawer[data-side="right"][open],
|
|
265
|
+
dialog.rf-drawer[data-side="left"][open],
|
|
266
|
+
dialog.rf-drawer[data-side="top"][open],
|
|
267
|
+
dialog.rf-drawer[data-side="bottom"][open],
|
|
268
|
+
dialog.rf-drawer[data-state="closing"],
|
|
269
|
+
dialog.rf-drawer[open]::backdrop,
|
|
270
|
+
dialog.rf-drawer[data-state="closing"]::backdrop {
|
|
271
|
+
animation: none;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/* ─── Mobile tightening ────────────────────────────────────────────
|
|
276
|
+
*
|
|
277
|
+
* On narrow viewports the drawer fills the screen (capped by
|
|
278
|
+
* `max-width: 100vw - 2*gutter`), so the desktop-comfortable
|
|
279
|
+
* 1.5rem / 2rem padding starts crowding the content. Halve it
|
|
280
|
+
* roughly to 0.75rem / 1rem so the body has more room without
|
|
281
|
+
* losing the chrome's breathing space.
|
|
282
|
+
*/
|
|
283
|
+
@media (max-width: 640px) {
|
|
284
|
+
dialog.rf-drawer .rf-drawer__header,
|
|
285
|
+
dialog.rf-drawer .rf-drawer__body {
|
|
286
|
+
padding: 0.75rem 1rem;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/* ─── Size modifiers (only meaningful in dialog mode) ─────────── */
|
|
291
|
+
|
|
292
|
+
dialog.rf-drawer[data-side="right"][data-size="sm"],
|
|
293
|
+
dialog.rf-drawer[data-side="left"][data-size="sm"] {
|
|
294
|
+
width: var(--rf-drawer-size-sm);
|
|
295
|
+
}
|
|
296
|
+
dialog.rf-drawer[data-side="right"][data-size="md"],
|
|
297
|
+
dialog.rf-drawer[data-side="left"][data-size="md"] {
|
|
298
|
+
width: var(--rf-drawer-size-md);
|
|
299
|
+
}
|
|
300
|
+
dialog.rf-drawer[data-side="right"][data-size="lg"],
|
|
301
|
+
dialog.rf-drawer[data-side="left"][data-size="lg"] {
|
|
302
|
+
width: var(--rf-drawer-size-lg);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
dialog.rf-drawer[data-side="top"][data-size="sm"],
|
|
306
|
+
dialog.rf-drawer[data-side="bottom"][data-size="sm"] {
|
|
307
|
+
height: var(--rf-drawer-size-sm);
|
|
308
|
+
}
|
|
309
|
+
dialog.rf-drawer[data-side="top"][data-size="md"],
|
|
310
|
+
dialog.rf-drawer[data-side="bottom"][data-size="md"] {
|
|
311
|
+
height: var(--rf-drawer-size-md);
|
|
312
|
+
}
|
|
313
|
+
dialog.rf-drawer[data-side="top"][data-size="lg"],
|
|
314
|
+
dialog.rf-drawer[data-side="bottom"][data-size="lg"] {
|
|
315
|
+
height: var(--rf-drawer-size-lg);
|
|
316
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/* Expand — inline-substitution of a registered entity (SPEC-066).
|
|
2
|
+
*
|
|
3
|
+
* The wrapper is intentionally minimal — the embedded rune (plan rune,
|
|
4
|
+
* character rune, etc.) renders itself standalone-style; expand just
|
|
5
|
+
* provides the wrapper + canonical-link affordance. Themes that want
|
|
6
|
+
* the embedded content visually distinguished from inline-authored
|
|
7
|
+
* content target `.rf-expand .rf-spec`, `.rf-expand h1`, etc.
|
|
8
|
+
*
|
|
9
|
+
* Two visual treatments:
|
|
10
|
+
*
|
|
11
|
+
* 1. **Default (`level=` unset, peer-document mode)** — the embed reads
|
|
12
|
+
* like a quoted document. A subtle border + indent treatment marks
|
|
13
|
+
* it as set-aside material. Heading scale is dialed down slightly
|
|
14
|
+
* so an H1 inside the embed doesn't compete with the host's H1.
|
|
15
|
+
* 2. **Sub-section mode (`level=` set)** — the embed merges into the
|
|
16
|
+
* host outline. The wrapper sheds the quoted treatment so it reads
|
|
17
|
+
* as authored sub-content. Authors opt into this by setting
|
|
18
|
+
* `level=`; CSS targets `.rf-expand:not([data-outline-scope])` to
|
|
19
|
+
* pick the right treatment automatically.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
.rf-expand {
|
|
23
|
+
margin: var(--rf-spacing-md) 0;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/* Peer-document mode — subtle top + bottom rule, no background, no
|
|
27
|
+
* rounded corners. Reads as "set-aside material" without competing
|
|
28
|
+
* visually with the host content. Authors who want a stronger
|
|
29
|
+
* treatment can override `.rf-expand[data-outline-scope]` in their
|
|
30
|
+
* theme. */
|
|
31
|
+
.rf-expand[data-outline-scope] {
|
|
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
|
+
}
|
|
36
|
+
|
|
37
|
+
/* Tone down embedded headings so the host outline keeps visual primacy.
|
|
38
|
+
* The semantic levels are preserved (H1 stays H1 etc.); only the visual
|
|
39
|
+
* scale is adjusted in the peer-document treatment. Authors using
|
|
40
|
+
* `level=` for sub-section mode get the normal heading scale. */
|
|
41
|
+
.rf-expand[data-outline-scope] :is(h1, h2, h3, h4, h5, h6):first-child {
|
|
42
|
+
margin-top: 0;
|
|
43
|
+
}
|
|
44
|
+
.rf-expand[data-outline-scope] h1 { font-size: 1.5rem; }
|
|
45
|
+
.rf-expand[data-outline-scope] h2 { font-size: 1.25rem; }
|
|
46
|
+
.rf-expand[data-outline-scope] h3 { font-size: 1.1rem; }
|
|
47
|
+
|
|
48
|
+
.rf-expand > :first-child { margin-top: 0; }
|
|
49
|
+
.rf-expand > :last-child { margin-bottom: 0; }
|
|
50
|
+
|
|
51
|
+
.rf-expand__canonical-link {
|
|
52
|
+
display: inline-block;
|
|
53
|
+
margin-top: var(--rf-spacing-sm);
|
|
54
|
+
font-size: 0.875rem;
|
|
55
|
+
color: var(--rf-color-primary);
|
|
56
|
+
text-decoration: none;
|
|
57
|
+
}
|
|
58
|
+
.rf-expand__canonical-link:hover {
|
|
59
|
+
text-decoration: underline;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/* Error-state placeholder rendered when resolution fails. The build
|
|
63
|
+
* also surfaces the error through `ctx.error`; this is the user-facing
|
|
64
|
+
* affordance so the failure isn't silent. Keyed off `[data-expand-error]`
|
|
65
|
+
* which the resolver sets on the error wrapper. */
|
|
66
|
+
.rf-expand[data-expand-error] {
|
|
67
|
+
padding: var(--rf-spacing-sm) var(--rf-spacing-md);
|
|
68
|
+
border-left: 3px solid var(--rf-color-danger);
|
|
69
|
+
background: var(--rf-color-danger-bg);
|
|
70
|
+
color: var(--rf-color-danger);
|
|
71
|
+
font-family: var(--rf-font-mono);
|
|
72
|
+
font-size: 0.875rem;
|
|
73
|
+
border-radius: 0 var(--rf-radius-sm) var(--rf-radius-sm) 0;
|
|
74
|
+
}
|
package/styles/runes/nav.css
CHANGED
|
@@ -361,8 +361,14 @@
|
|
|
361
361
|
|
|
362
362
|
@media (max-width: 600px) {
|
|
363
363
|
.rf-nav--columns {
|
|
364
|
-
|
|
365
|
-
|
|
364
|
+
/* Keep two columns on mobile. `minmax(0, 1fr)` lets columns shrink
|
|
365
|
+
* below their min-content width so long link labels don't push the
|
|
366
|
+
* grid wider than the viewport and trigger horizontal scroll. */
|
|
367
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
368
|
+
gap: 1.25rem 1.5rem;
|
|
369
|
+
}
|
|
370
|
+
.rf-nav--columns .rf-nav-item__link {
|
|
371
|
+
overflow-wrap: anywhere;
|
|
366
372
|
}
|
|
367
373
|
}
|
|
368
374
|
|
|
@@ -600,7 +606,10 @@
|
|
|
600
606
|
.rf-nav--columns:has(> div[data-name="column"]) {
|
|
601
607
|
grid-auto-flow: row;
|
|
602
608
|
grid-auto-columns: unset;
|
|
603
|
-
|
|
609
|
+
/* Keep two columns on mobile. `minmax(0, 1fr)` lets columns shrink
|
|
610
|
+
* below their min-content width so long link labels don't push the
|
|
611
|
+
* grid wider than the viewport and trigger horizontal scroll. */
|
|
612
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
604
613
|
}
|
|
605
614
|
}
|
|
606
615
|
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/* Snippet — file embedded as a code block.
|
|
2
|
+
*
|
|
3
|
+
* The standalone form is a `<figure class="rf-snippet">` wrapping the
|
|
4
|
+
* existing `<pre class="rf-code-block">`. Nested forms (snippet inside
|
|
5
|
+
* codegroup or diff) skip the figure wrapper entirely — the container's
|
|
6
|
+
* chrome owns the layout there.
|
|
7
|
+
*
|
|
8
|
+
* The figure exists primarily so themes can style snippet-derived code
|
|
9
|
+
* blocks distinctly from regular fences, and so tooling can find
|
|
10
|
+
* `data-source-path` for "edit this file" affordances. Authors wanting a
|
|
11
|
+
* labelled caption should wrap the snippet in `{% codegroup title="..." %}`.
|
|
12
|
+
*
|
|
13
|
+
* SPEC-062.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
.rf-snippet {
|
|
17
|
+
/* Override the UA `<figure>` defaults — browsers ship with
|
|
18
|
+
* margin-inline: 40px and margin-block: 1em which makes the snippet
|
|
19
|
+
* figure look indented inside any container. The longhand resets
|
|
20
|
+
* cover both physical and logical margin properties because the
|
|
21
|
+
* physical longhands set by `margin:` don't always cascade-override
|
|
22
|
+
* the UA's logical longhands. */
|
|
23
|
+
margin: var(--rf-spacing-md) 0;
|
|
24
|
+
margin-inline-start: 0;
|
|
25
|
+
margin-inline-end: 0;
|
|
26
|
+
padding: 0;
|
|
27
|
+
}
|
package/styles/runes/xref.css
CHANGED
|
@@ -4,6 +4,22 @@
|
|
|
4
4
|
/* Inherits normal link styling from the theme */
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
+
/* External — pattern-resolved refs and any other type that doesn't have a
|
|
8
|
+
* dedicated treatment. A subtle outbound indicator distinguishes these
|
|
9
|
+
* from local refs without being noisy. */
|
|
10
|
+
.rf-xref--external {
|
|
11
|
+
/* Theme-inherited link colour; outbound indicator via a small inline
|
|
12
|
+
* arrow that adapts to RTL via the logical-property side. */
|
|
13
|
+
}
|
|
14
|
+
.rf-xref--external::after {
|
|
15
|
+
content: '\2197'; /* ↗ */
|
|
16
|
+
display: inline-block;
|
|
17
|
+
margin-inline-start: 0.15em;
|
|
18
|
+
font-size: 0.85em;
|
|
19
|
+
vertical-align: 0.05em;
|
|
20
|
+
opacity: 0.6;
|
|
21
|
+
}
|
|
22
|
+
|
|
7
23
|
/* Unresolved reference */
|
|
8
24
|
.rf-xref--unresolved {
|
|
9
25
|
text-decoration: underline dashed;
|