reviewzy 0.3.0 → 0.4.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/README.md +3 -3
- package/package.json +2 -2
- package/src/dashboard/mount.ts +20 -3
- package/src/dashboard/static/components.css +1196 -451
- package/src/dashboard/static/cursor-rules.js +30 -34
- package/src/dashboard/static/cursor.css +118 -89
- package/src/dashboard/static/cursor.js +1636 -245
- package/src/dashboard/static/dashboard.css +275 -179
- package/src/dashboard/static/dashboard.js +330 -185
- package/src/dashboard/static/tokens.css +240 -54
- package/src/dashboard/static/ui.js +666 -171
- package/src/dashboard/views.tsx +1138 -841
- package/src/dashboard/word-diff.ts +18 -25
- package/src/db/migrations.ts +5 -6
- package/src/db/queries.ts +37 -0
- package/src/mcp/file-entries.ts +1 -1
- package/src/mcp/list-entries.ts +11 -2
|
@@ -60,6 +60,20 @@
|
|
|
60
60
|
--surface-2: oklch(0.345 0.026 280); /* hover, nested */
|
|
61
61
|
--surface-3: oklch(0.395 0.028 280); /* pressed, selected */
|
|
62
62
|
|
|
63
|
+
/* The sky: one light above the page, the page hue drifted toward the accent,
|
|
64
|
+
painted on body::after as a radial ground 780px tall. The stops are
|
|
65
|
+
declared grounds, never an alpha over the page, so each is a measured pair.
|
|
66
|
+
On the peak: --text 9.89, --text-2 7.13, --text-3 5.37, --text-4 4.62:1,
|
|
67
|
+
--accent-text 7.73. On the mid: 10.87 / 7.84 / 5.90 / 5.08, --accent-text
|
|
68
|
+
8.50. NO HEADROOM: --text-4 falls under 4.5:1 once the ground passes
|
|
69
|
+
L 0.31, so the peak never rises. */
|
|
70
|
+
--sky-peak: oklch(0.305 0.040 252);
|
|
71
|
+
--sky-mid: oklch(0.278 0.032 262);
|
|
72
|
+
/* The accent band's ground, the page's closing ask: the page tone turned
|
|
73
|
+
toward the sapphire. --text 11.26, --text-2 8.12, --text-3 6.11, --text-4
|
|
74
|
+
5.26:1, --accent-text 8.81, and --accent as a fill 7.21 against it. */
|
|
75
|
+
--band-accent: oklch(0.265 0.050 242);
|
|
76
|
+
|
|
63
77
|
/* The system draws its own scrollbar, so the thumb is a graphic this file owns
|
|
64
78
|
and it clears 3:1 on every ground a scroller has: 5.20:1 on --well, 4.68 on
|
|
65
79
|
--bg, 4.05 on --surface-1, 3.43 on a --surface-2 hover tint. --surface-3, the
|
|
@@ -87,25 +101,45 @@
|
|
|
87
101
|
|
|
88
102
|
Measured on a 300x140 card, blue channel against --bg, deepest pixel and
|
|
89
103
|
the width of that last 1-level band:
|
|
90
|
-
--elev-1
|
|
104
|
+
--elev-1 23 levels under, 11 beside; band 3px under, 2px beside
|
|
91
105
|
--elev-2 23 / 12; band 7 / 6
|
|
92
106
|
--elev-float 34 / 18; band 8 / 6
|
|
93
107
|
The shipped v1 set measured 9 / 5 with a 15px band, which is the ring.
|
|
94
108
|
|
|
109
|
+
DEPTH IS NOT WHAT DRAWS THE CORNER, REACH IS. --elev-1's outer coat ran
|
|
110
|
+
`0 8px 16px -6px` and its footprint reached 21px under the card, 13 beside
|
|
111
|
+
and 18 out of the corner on the diagonal, so the far end of the footprint
|
|
112
|
+
closed as a curve tracing the box and the corner read as a smear. Depth was
|
|
113
|
+
never the problem: at `0 4px 8px -4px` the deepest pixel moves 24 to 23 and
|
|
114
|
+
the reach halves to 10 / 6 / 10.
|
|
115
|
+
|
|
95
116
|
THE EDGE IS WHAT THE EYE READS AS THE CARD STARTING, not the tone step.
|
|
96
117
|
A card sits .045 L over the page and .065 is not available: the fourth
|
|
97
118
|
text step falls to 4.40:1 on it. So separation is bought on the edge and
|
|
98
|
-
the contact instead, where no colour moves and no ratio re-derives.
|
|
119
|
+
the contact instead, where no colour moves and no ratio re-derives.
|
|
120
|
+
Measured on a card at --surface-1: --lit-1 paints 18 sRGB levels of lift
|
|
121
|
+
along the top, --lit-2 21.
|
|
122
|
+
|
|
123
|
+
A CARD CARRIES A DRAWN LINE. `.card` and `.stat-card` take `--card-line`,
|
|
124
|
+
a crisp 1px line drawn outside the box (box-shadow 0 0 0 1px, zero blur,
|
|
125
|
+
content box unchanged). A card at rest
|
|
126
|
+
wears the one line and no coat. Every other raised surface keeps the straight --lit-1,
|
|
127
|
+
and glass keeps --glass-edge. The line is a hairline, not a graphic, so it
|
|
128
|
+
is not held to a 3:1 floor; measured with tools/contrast.mjs against the
|
|
129
|
+
card's own fill and every surface it sits on, tightest first: sky peak
|
|
130
|
+
2.03:1, --surface-1 (the fill) 2.08:1, sky mid 2.24:1, --band-accent
|
|
131
|
+
2.32:1, --bg 2.41:1, --well 2.67:1. */
|
|
99
132
|
--lit-1: inset 0 1px 0 0 oklch(1 0 0 / 0.085);
|
|
100
133
|
--lit-2: inset 0 1px 0 0 oklch(1 0 0 / 0.100);
|
|
101
|
-
--
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
--
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
134
|
+
--card-line: oklch(0.48 0.032 280);
|
|
135
|
+
--contact-1: 0 1px 2px -1px oklch(0.11 0.025 280 / 0.72),
|
|
136
|
+
0 2px 4px -1px oklch(0.11 0.025 280 / 0.66),
|
|
137
|
+
0 4px 8px -4px oklch(0.11 0.025 280 / 0.60);
|
|
138
|
+
--contact-2: 0 1px 2px -1px oklch(0.11 0.025 280 / 0.66),
|
|
139
|
+
0 4px 8px -2px oklch(0.11 0.025 280 / 0.62),
|
|
140
|
+
0 10px 18px -8px oklch(0.11 0.025 280 / 0.58);
|
|
141
|
+
--elev-1: var(--lit-1), var(--contact-1);
|
|
142
|
+
--elev-2: var(--lit-2), var(--contact-2);
|
|
109
143
|
--elev-float: var(--lit-2),
|
|
110
144
|
0 2px 4px -1px oklch(0.09 0.022 280 / 0.72),
|
|
111
145
|
0 6px 12px -3px oklch(0.09 0.022 280 / 0.68),
|
|
@@ -125,7 +159,7 @@
|
|
|
125
159
|
tint with --bg: a bar is the page held still, and content passing under it
|
|
126
160
|
is the only thing that says a surface is there. Panels keep the raised
|
|
127
161
|
tone at the clearest alpha the dim ramp allows: --text-2 holds 4.67:1 on
|
|
128
|
-
the worst case at 0.86 and fails at 0.82 (4.
|
|
162
|
+
the worst case at 0.86 and fails at 0.82 (4.09:1), so 0.86 is the
|
|
129
163
|
floor. On that worst case, a white plate composited through the panel,
|
|
130
164
|
--text holds 6.48:1, --glass-dim 4.67, --glass-danger 4.62. The panel
|
|
131
165
|
moves 35.7 sRGB levels black to white, the measured (1 - alpha) * 255
|
|
@@ -133,23 +167,49 @@
|
|
|
133
167
|
crushing the backdrop enough to protect it crushes the blur with it,
|
|
134
168
|
measured across nine chains. ---- */
|
|
135
169
|
--glass-bar-tint: oklch(0.255 0.024 280 / 0.90);
|
|
136
|
-
/* the bar
|
|
137
|
-
|
|
170
|
+
/* the bar re-floors the same tokens as a panel, since the glass block names
|
|
171
|
+
both: --text-3/--text-4/--text-placeholder become --glass-dim, --danger
|
|
172
|
+
becomes --glass-danger, --text-disabled becomes --glass-disabled. Measured
|
|
173
|
+
over the bar's worst plate (white through 0.90 of the page colour): --text-2
|
|
174
|
+
6.21:1, --glass-danger 6.14:1, --glass-disabled 4.34:1. */
|
|
138
175
|
--glass-tint: oklch(0.300 0.024 280 / 0.86);
|
|
139
176
|
--glass-blur: 22px;
|
|
140
177
|
--glass-sat: 1.25;
|
|
141
178
|
--glass-dim: oklch(0.800 0.030 280); /* --text-3 and --text-4 on a panel:
|
|
142
179
|
4.67:1 on the worst case; unlifted, .720 / .680 fall to 3.52 / 3.03 */
|
|
143
180
|
--glass-danger: oklch(0.84 0.140 15); /* 4.62:1 on the panel worst case.
|
|
144
|
-
--danger is 3.31:1 there, and
|
|
181
|
+
--danger is 3.31:1 there, and L 0.78 fell to 4.04 at
|
|
145
182
|
0.86, so the re-floor moves with the alpha */
|
|
146
183
|
--glass-disabled: oklch(0.700 0.030 280); /* 3.27:1 on the panel worst case.
|
|
147
184
|
--text-disabled falls to 2.49 there, and the opacity: 0.45 costume this
|
|
148
185
|
replaces measured 2.17, which is what the panel had been shipping */
|
|
149
186
|
/* A translucent tint over a translucent surface composites twice and drifts 21
|
|
150
187
|
levels with the backdrop: --accent-text on it measures 4.40:1. The same mix
|
|
151
|
-
laid down opaque holds one tone and 5.95:1.
|
|
152
|
-
|
|
188
|
+
laid down opaque holds one tone and 5.95:1 on a panel. This is the accent's
|
|
189
|
+
share of that opaque fill; the glass block mixes --accent-quiet from it onto
|
|
190
|
+
each surface's own --glass-ground, so a bar's fill reads the bar's tone. */
|
|
191
|
+
--glass-quiet-share: 16%;
|
|
192
|
+
/* --danger-text on a glass surface, where --danger is already --glass-danger:
|
|
193
|
+
the hover and press tints mix opaque onto the surface (--tint-ground), so
|
|
194
|
+
the plate behind it no longer moves them. On the panel 5.64 / 4.74:1, on
|
|
195
|
+
the bar 6.55 / 5.38, the menu hover 6.50; 0.86 leaves the panel press at
|
|
196
|
+
4.52, so 0.88 holds a margin over the floor. */
|
|
197
|
+
--glass-danger-text: oklch(0.88 0.140 15);
|
|
198
|
+
/* what every translucent tint in components.css mixes onto. Transparent, so
|
|
199
|
+
off glass a tint paints exactly as `X p%, transparent` did. A glass surface
|
|
200
|
+
sets its own tone here, turning each tint inside it into an opaque mix the
|
|
201
|
+
backdrop cannot move; every rule that paints an opaque ground resets it to
|
|
202
|
+
transparent, so a tint nested in that ground composites over it. One value
|
|
203
|
+
for both themes. */
|
|
204
|
+
--tint-ground: transparent;
|
|
205
|
+
/* the same glass tone for a tint painted OUTSIDE its own box (an invalid
|
|
206
|
+
field's ring): an opaque ground resets --tint-ground on itself, but its
|
|
207
|
+
ring lands on whatever surrounds it, so no rule resets this one */
|
|
208
|
+
--glass-ground: transparent;
|
|
209
|
+
/* --accent-line on a glass surface, laid opaque on the surface's own
|
|
210
|
+
--glass-ground at the same 38 percent, so a focus ring and a primary edge
|
|
211
|
+
stop drifting with the backdrop the way the quiet share stopped the fill */
|
|
212
|
+
--glass-line-share: 38%;
|
|
153
213
|
/* The one place a drawn line beats the lit edge. A glass panel has no reliable
|
|
154
214
|
tone difference from its backdrop, since it takes that backdrop on, so the
|
|
155
215
|
edge is what says where the pane starts. Still a hairline. */
|
|
@@ -168,7 +228,7 @@
|
|
|
168
228
|
/* the hint inside a control. One step under --text-4 so a placeholder does
|
|
169
229
|
not read as a typed value or as metadata: 4.99:1 on --well. */
|
|
170
230
|
--text-placeholder: oklch(0.630 0.030 280);
|
|
171
|
-
/* a control that cannot act,
|
|
231
|
+
/* a control that cannot act, replacing the opacity: 0.45
|
|
172
232
|
ten declarations across twelve component classes rode. It takes the 3:1 graphics floor rather than the 4.5:1
|
|
173
233
|
text floor, so it can sit a real step under --text-4: 4.99:1 on --well, 4.50
|
|
174
234
|
on --bg, 3.89 on --surface-1, 3.29 on the --surface-2 a disabled fill takes.
|
|
@@ -188,15 +248,25 @@
|
|
|
188
248
|
--accent-glow: 0 0 10px 0 oklch(0.76 0.110 238 / 0.55);
|
|
189
249
|
--on-accent: oklch(0.22 0.020 280); /* 8.22:1 on the fill */
|
|
190
250
|
|
|
251
|
+
/* no on-colour: identity rule 7 makes accent-2 annotation only, never a fill,
|
|
252
|
+
so the pair it would sit on cannot exist */
|
|
191
253
|
--accent-2: oklch(0.72 0.130 42); /* editorial, 6.09:1, once per screen */
|
|
192
|
-
|
|
254
|
+
|
|
255
|
+
/* The brand mark's ring: rose, the identity accent. A 2px graphic on the
|
|
256
|
+
.sona, held to the 3:1 graphics floor on every bar surface it sits on;
|
|
257
|
+
measured with tools/contrast.mjs: surface-1 6.06:1, well 7.78:1, --bg
|
|
258
|
+
7.01:1, sky peak 5.93:1 dark; 5.16 / 4.20 / 4.59 / 5.16 light. */
|
|
259
|
+
--brand-ring: oklch(0.76 0.110 340);
|
|
193
260
|
|
|
194
261
|
/* ---- Status. Levelled under --text so no pill outshouts a title. ---- */
|
|
195
262
|
--success: oklch(0.80 0.130 150); /* 8.89:1 */
|
|
196
263
|
--warning: oklch(0.84 0.110 90); /* 9.68:1 */
|
|
197
264
|
--danger: oklch(0.72 0.140 15); /* 5.98:1 */
|
|
198
|
-
|
|
199
|
-
|
|
265
|
+
/* the danger label on its own hover and press tint: --danger there falls to
|
|
266
|
+
4.04 / 3.49:1 on surface-1, because label and tint are one hue. Lightness
|
|
267
|
+
stepped, chroma held: 6.04 / 5.16:1 on --bg, 5.27 / 4.55 on surface-1, and
|
|
268
|
+
5.76 on .menu-item.danger's 10 percent hover. */
|
|
269
|
+
--danger-text: oklch(0.81 0.140 15);
|
|
200
270
|
--on-danger: oklch(0.22 0.02 15); /* 6.58:1 on the fill */
|
|
201
271
|
--info: var(--accent); /* folded in: it was the same hue */
|
|
202
272
|
|
|
@@ -228,8 +298,9 @@
|
|
|
228
298
|
|
|
229
299
|
/* ---- Radius. Softer than v1's 1px, which rendered as 0. ---- */
|
|
230
300
|
--r-1: 10px; /* controls */
|
|
231
|
-
--r-2: 14px; /* cards, menus
|
|
301
|
+
--r-2: 14px; /* cards, menus, icon tiles */
|
|
232
302
|
--r-3: 18px; /* modals, sheets */
|
|
303
|
+
--r-4: 24px; /* KPI tiles */
|
|
233
304
|
--r-pill: 999px;
|
|
234
305
|
|
|
235
306
|
/* ---- Motion. Duration follows distance. ---- */
|
|
@@ -245,9 +316,17 @@
|
|
|
245
316
|
--dur-out-near: calc(var(--dur-near) * 0.6);
|
|
246
317
|
--dur-out-far: calc(var(--dur-far) * 0.6);
|
|
247
318
|
|
|
248
|
-
/* ----
|
|
319
|
+
/* ---- The jelly press. A spring settle, NOT a travel
|
|
320
|
+
distance, so it takes no --dur-* slot: --press-dur is how long the wobble
|
|
321
|
+
takes to settle, and --press-spring is the 320/18 spring sampled over
|
|
322
|
+
49 points as a linear() curve, normalized to settle at 1. ---- */
|
|
323
|
+
--press-dur: 380ms;
|
|
324
|
+
--press-spring: linear(0, 2.0833% 0.0098, 4.1667% 0.0372, 6.2500% 0.0793, 8.3333% 0.1334, 10.4167% 0.1970, 12.5000% 0.2675, 14.5833% 0.3428, 16.6667% 0.4208, 18.7500% 0.4996, 20.8333% 0.5777, 22.9167% 0.6538, 25.0000% 0.7267, 27.0833% 0.7954, 29.1667% 0.8592, 31.2500% 0.9176, 33.3333% 0.9702, 35.4167% 1.0168, 37.5000% 1.0574, 39.5833% 1.0919, 41.6667% 1.1205, 43.7500% 1.1435, 45.8333% 1.1613, 47.9167% 1.1740, 50.0000% 1.1823, 52.0833% 1.1865, 54.1667% 1.1871, 56.2500% 1.1845, 58.3333% 1.1793, 60.4167% 1.1718, 62.5000% 1.1626, 64.5833% 1.1520, 66.6667% 1.1404, 68.7500% 1.1281, 70.8333% 1.1155, 72.9167% 1.1028, 75.0000% 1.0904, 77.0833% 1.0783, 79.1667% 1.0668, 81.2500% 1.0560, 83.3333% 1.0461, 85.4167% 1.0370, 87.5000% 1.0289, 89.5833% 1.0217, 91.6667% 1.0155, 93.7500% 1.0103, 95.8333% 1.0060, 97.9167% 1.0026, 1);
|
|
325
|
+
|
|
326
|
+
/* ---- Type. 9 distinct steps; 11px and 12px are real tokens. ---- */
|
|
249
327
|
--t-1: 11px; --t-2: 12px; --t-3: 14px; --t-4: 16px;
|
|
250
328
|
--t-5: 20px; --t-6: 26px; --t-7: 34px; --t-8: 46px;
|
|
329
|
+
--t-9: 64px;
|
|
251
330
|
--caps: 0.09em; /* the one tracking value */
|
|
252
331
|
|
|
253
332
|
/* ---- Controls share one height ladder with inputs ---- */
|
|
@@ -255,13 +334,18 @@
|
|
|
255
334
|
|
|
256
335
|
/* ---- Layout ---- */
|
|
257
336
|
--page-w: 1200px; /* .page column; one override retunes a build */
|
|
258
|
-
/* prose measure, MEASURED against loaded Onest at --t-4 rather than estimated
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
337
|
+
/* prose measure, MEASURED against loaded Onest at --t-4 rather than estimated.
|
|
338
|
+
A line that runs the full page column is a line nobody finishes, and erring
|
|
339
|
+
short is the safer side of 66. The width sweep behind the value, five
|
|
340
|
+
candidates against two samples, is in references/rhythm.md; it lived here
|
|
341
|
+
too and the two copies had already drifted apart on one sample. */
|
|
262
342
|
--page-narrow: 528px;
|
|
263
|
-
--navbar-h: 56px; /* the
|
|
264
|
-
--topbar-h: 52px; /* the mobile bar
|
|
343
|
+
--navbar-h: 56px; /* the navbar's own height, and nothing else reads it as an offset */
|
|
344
|
+
--topbar-h: 52px; /* the mobile bar's own height */
|
|
345
|
+
/* How far down anything pinned to the top has to start, which is NOT a bar's
|
|
346
|
+
height: it is the height of whatever bar this page actually holds, and a
|
|
347
|
+
sidebar shell holds none. Derived on the root below, never set by a page. */
|
|
348
|
+
--pin-top: 0px;
|
|
265
349
|
|
|
266
350
|
/* ---- Fonts ---- */
|
|
267
351
|
--font-sans: "Onest", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
|
|
@@ -283,7 +367,7 @@
|
|
|
283
367
|
}
|
|
284
368
|
|
|
285
369
|
/* Radius preset: sharp is the opt-in variant, real 0 */
|
|
286
|
-
[data-radius="sharp"] { --r-1: 0px; --r-2: 0px; --r-3: 0px; }
|
|
370
|
+
[data-radius="sharp"] { --r-1: 0px; --r-2: 0px; --r-3: 0px; --r-4: 0px; }
|
|
287
371
|
|
|
288
372
|
/* ---- Light theme (Latte). EVERY colour and elevation token is
|
|
289
373
|
re-declared, because a partial override is the bug that broke
|
|
@@ -299,6 +383,16 @@
|
|
|
299
383
|
--well: oklch(0.925 0.008 275);
|
|
300
384
|
--bg: oklch(0.955 0.006 275);
|
|
301
385
|
--surface-1: oklch(0.995 0.003 275); /* cards still rise */
|
|
386
|
+
/* Light falls onto a light page too: the top goes whiter, which only raises
|
|
387
|
+
every text ratio there. On the peak: --text 13.46, --text-4 5.55:1,
|
|
388
|
+
--accent-text 5.68; on the mid 12.72 / 5.25 / 5.37. The peak sits at the
|
|
389
|
+
card's own lightness, so a card under it separates on the drawn line
|
|
390
|
+
alone. */
|
|
391
|
+
--sky-peak: oklch(0.995 0.008 240);
|
|
392
|
+
--sky-mid: oklch(0.975 0.007 255);
|
|
393
|
+
/* --text 11.17, --text-2 6.94, --text-3 4.92, --text-4 4.61:1, --accent-text
|
|
394
|
+
4.72; --accent as a fill 3.82 against it, over the 3:1 graphics floor */
|
|
395
|
+
--band-accent: oklch(0.930 0.030 238);
|
|
302
396
|
|
|
303
397
|
--line: oklch(0.890 0.012 275); /* barely there, 1.22:1 */
|
|
304
398
|
--line-soft: oklch(0.920 0.010 275);
|
|
@@ -325,13 +419,15 @@
|
|
|
325
419
|
--on-accent: oklch(0.995 0.003 238);
|
|
326
420
|
|
|
327
421
|
--accent-2: oklch(0.52 0.150 42); /* 5.16:1 */
|
|
328
|
-
|
|
422
|
+
|
|
423
|
+
--brand-ring: oklch(0.55 0.140 340);
|
|
329
424
|
|
|
330
425
|
--success: oklch(0.50 0.150 150); /* 4.85:1 */
|
|
331
426
|
--warning: oklch(0.50 0.130 90); /* 5.25:1 */
|
|
332
427
|
--danger: oklch(0.52 0.190 15); /* 5.36:1 */
|
|
333
|
-
--on-
|
|
334
|
-
|
|
428
|
+
/* hover / press: 5.25 / 4.61:1 on --bg, 5.87 / 5.10 on surface-1, 6.49 on
|
|
429
|
+
.menu-item.danger's hover; --danger there falls to 4.14 / 3.63 on --bg */
|
|
430
|
+
--danger-text: oklch(0.46 0.190 15);
|
|
335
431
|
--on-danger: oklch(0.995 0.003 15);
|
|
336
432
|
--info: var(--accent);
|
|
337
433
|
|
|
@@ -342,18 +438,32 @@
|
|
|
342
438
|
banding that governs the dark set is not the binding constraint here; the
|
|
343
439
|
geometry is shared because a component must not change depth on a toggle.
|
|
344
440
|
Measured on a 300x140 card, blue channel against --bg, deepest pixel and
|
|
345
|
-
the last 1-level band: --elev-1
|
|
441
|
+
the last 1-level band: --elev-1 30 under / 13 beside, band 2 / 2;
|
|
346
442
|
--elev-2 32 / 14, band 3 / 2; --elev-float 42 / 19, band 5 / 3. */
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
443
|
+
|
|
444
|
+
/* The underside line is a mid tone on a near-white card, so an alpha buys
|
|
445
|
+
fewer levels here than dark's white on --surface-1: at 0.10 it painted 15
|
|
446
|
+
against dark's 18. The two themes are matched on the PAINTED delta rather
|
|
447
|
+
than on each other's alphas, measured on a card: 0.125 lands 18, 0.145
|
|
448
|
+
lands 21. Matched in sRGB levels, not in oklab: a
|
|
449
|
+
perceptual match wants 0.165, which reaches 93 percent of --line-soft's
|
|
450
|
+
own step on a card and starts reading as a drawn line rather than a lit
|
|
451
|
+
edge. */
|
|
452
|
+
--lit-1: inset 0 -1px 0 0 oklch(0.55 0.03 275 / 0.125);
|
|
453
|
+
--lit-2: inset 0 -1px 0 0 oklch(0.55 0.03 275 / 0.145);
|
|
454
|
+
/* the card line is a hairline, not a graphic, so no 3:1 floor applies;
|
|
455
|
+
measured with tools/contrast.mjs against every surface a card sits on,
|
|
456
|
+
tightest first: --well 1.99:1, --band-accent 2.03:1, --bg 2.18:1,
|
|
457
|
+
--sky-mid 2.31:1, --surface-1 2.45:1, --sky-peak 2.45:1. */
|
|
458
|
+
--card-line: oklch(0.72 0.020 275);
|
|
459
|
+
--contact-1: 0 1px 2px -1px oklch(0.55 0.03 275 / 0.26),
|
|
460
|
+
0 2px 4px -1px oklch(0.55 0.03 275 / 0.23),
|
|
461
|
+
0 4px 8px -4px oklch(0.55 0.03 275 / 0.21);
|
|
462
|
+
--contact-2: 0 1px 2px -1px oklch(0.55 0.03 275 / 0.24),
|
|
463
|
+
0 4px 8px -2px oklch(0.55 0.03 275 / 0.21),
|
|
464
|
+
0 10px 18px -8px oklch(0.55 0.03 275 / 0.19);
|
|
465
|
+
--elev-1: var(--lit-1), var(--contact-1);
|
|
466
|
+
--elev-2: var(--lit-2), var(--contact-2);
|
|
357
467
|
--elev-float: var(--lit-2),
|
|
358
468
|
0 2px 4px -1px oklch(0.55 0.03 275 / 0.26),
|
|
359
469
|
0 6px 12px -3px oklch(0.55 0.03 275 / 0.23),
|
|
@@ -363,18 +473,29 @@
|
|
|
363
473
|
/* Glass. The same split the dark block ships: bars tint with --bg, panels
|
|
364
474
|
hold surface-1 at the clearest alpha the ramp allows. Worst case on a light
|
|
365
475
|
page is black behind the panel; composited through it, --text holds 10.76:1,
|
|
366
|
-
--text-2 6.68, the dim step 4.72 at 0.500 (re-measured twice 2026-09-02,
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
quiet fill
|
|
370
|
-
|
|
476
|
+
--text-2 6.68, the dim step 4.72 at 0.500 (re-measured twice 2026-09-02,
|
|
477
|
+
independently) and --danger 4.81. The shipped --text-4 value 0.515 measures
|
|
478
|
+
4.44 there, so it joins the dim step. 0.90 is 25.5 sRGB levels black to
|
|
479
|
+
white. --accent-text stays bound to its opaque quiet fill: 4.89:1 on a
|
|
480
|
+
panel's, but 4.38 on a bar's own, so every accent label that can sit on a
|
|
481
|
+
bar carries a mix: the shared light remix at 4.98, `.btn-primary`'s own
|
|
482
|
+
at 6.27.
|
|
483
|
+
|
|
484
|
+
The bar alpha is the floor, not a preference. At 0.92 the bar re-floors
|
|
485
|
+
--text-3/--text-4/--text-placeholder to --glass-dim, which measured 4.41:1
|
|
486
|
+
over black, and --glass-danger 4.48:1, both under 4.5:1. At 0.93 both clear:
|
|
487
|
+
--glass-dim 4.52:1 and --glass-danger 4.59:1 over black, and --glass-disabled
|
|
488
|
+
3.22:1 over the 3:1 floor. */
|
|
489
|
+
--glass-bar-tint: oklch(0.955 0.006 275 / 0.93);
|
|
371
490
|
--glass-tint: oklch(0.995 0.003 275 / 0.90);
|
|
372
491
|
--glass-dim: oklch(0.500 0.018 275);
|
|
373
492
|
--glass-danger: var(--danger);
|
|
493
|
+
--glass-danger-text: var(--danger-text);
|
|
374
494
|
/* light needs no lift here: --text-disabled already measures 3.37:1 on the
|
|
375
495
|
panel worst case, where dark's falls to 2.49 */
|
|
376
496
|
--glass-disabled: var(--text-disabled);
|
|
377
|
-
--glass-quiet:
|
|
497
|
+
--glass-quiet-share: 12%;
|
|
498
|
+
--glass-line-share: 34%;
|
|
378
499
|
--glass-edge: oklch(0.45 0.03 275 / 0.12);
|
|
379
500
|
|
|
380
501
|
/* A light page has less room under a dim than a dark one: at the 0.7 the dark
|
|
@@ -388,13 +509,13 @@
|
|
|
388
509
|
mauve here too: against sky the 1-3 pair measured 0.0790 in oklab and now
|
|
389
510
|
measures 0.1556.
|
|
390
511
|
|
|
391
|
-
SLOTS 1 AND 4 ARE HELD AT THE sRGB BOUNDARY
|
|
512
|
+
SLOTS 1 AND 4 ARE HELD AT THE sRGB BOUNDARY. At their
|
|
392
513
|
old chromas the browser clipped them (slot 1's linear red measured -0.0182,
|
|
393
514
|
slot 4's -0.0020), so the declared values named colours nobody saw and every
|
|
394
515
|
distance taken from a declaration overstated the gap. The gamut runs out at
|
|
395
516
|
C 0.1110 for slot 1 and 0.1378 for slot 4 at these lightnesses and hues;
|
|
396
|
-
both sit under that with a little margin
|
|
397
|
-
outside
|
|
517
|
+
both sit under that with a little margin; the sRGB check reds on any slot
|
|
518
|
+
outside the gamut, on every run. */
|
|
398
519
|
--chart-series-1: oklch(0.50 0.110 238);
|
|
399
520
|
--chart-series-2: oklch(0.52 0.150 42);
|
|
400
521
|
--chart-series-3: oklch(0.55 0.150 305);
|
|
@@ -424,6 +545,41 @@
|
|
|
424
545
|
--cat-blue: oklch(0.559 0.226 262); --cat-lavender: oklch(0.664 0.175 273);
|
|
425
546
|
}
|
|
426
547
|
|
|
548
|
+
/* ---- Language hues (GitHub-recognizable categorical) ----
|
|
549
|
+
The categorical ramp's per-language extension, for dots, bar segments and
|
|
550
|
+
legend marks. Hue and chroma are each language's own GitHub colour;
|
|
551
|
+
lightness is re-derived per theme so every mark clears the 3:1 graphics
|
|
552
|
+
floor on its theme's binding surface: dark marks are light and bind on the
|
|
553
|
+
lightest surface a dark-theme mark can sit on (--surface-1); light marks
|
|
554
|
+
are dark and bind on the darkest light-theme surface (--well). Worst
|
|
555
|
+
measured: dark 3.1:1, light 3.1:1. */
|
|
556
|
+
:root {
|
|
557
|
+
--cat-rust: oklch(0.768 0.081 51); --cat-javascript: oklch(0.896 0.153 102);
|
|
558
|
+
--cat-typescript: oklch(0.569 0.078 220); --cat-python: oklch(0.573 0.102 247);
|
|
559
|
+
--cat-csharp: oklch(0.559 0.179 141); --cat-java: oklch(0.604 0.123 69);
|
|
560
|
+
--cat-go: oklch(0.695 0.130 224); --cat-html: oklch(0.622 0.194 35);
|
|
561
|
+
--cat-css: oklch(0.585 0.104 300); --cat-shell: oklch(0.823 0.196 135);
|
|
562
|
+
--cat-php: oklch(0.579 0.091 272); --cat-kotlin: oklch(0.687 0.189 297);
|
|
563
|
+
--cat-qml: oklch(0.639 0.189 139); --cat-c: oklch(0.575 0.020 280);
|
|
564
|
+
--cat-cpp: oklch(0.661 0.206 7); --cat-vue: oklch(0.702 0.132 160);
|
|
565
|
+
--cat-svelte: oklch(0.654 0.234 34); --cat-lua: oklch(0.584 0.188 264);
|
|
566
|
+
--cat-nix: oklch(0.656 0.187 280); --cat-dockerfile: oklch(0.573 0.029 220);
|
|
567
|
+
--cat-makefile: oklch(0.564 0.137 135);
|
|
568
|
+
}
|
|
569
|
+
[data-theme="light"] {
|
|
570
|
+
--cat-rust: oklch(0.609 0.081 51); --cat-javascript: oklch(0.598 0.153 102);
|
|
571
|
+
--cat-typescript: oklch(0.523 0.078 220); --cat-python: oklch(0.535 0.102 247);
|
|
572
|
+
--cat-csharp: oklch(0.540 0.179 141); --cat-java: oklch(0.604 0.123 69);
|
|
573
|
+
--cat-go: oklch(0.588 0.130 224); --cat-html: oklch(0.622 0.194 35);
|
|
574
|
+
--cat-css: oklch(0.418 0.104 300); --cat-shell: oklch(0.585 0.196 135);
|
|
575
|
+
--cat-php: oklch(0.492 0.091 272); --cat-kotlin: oklch(0.622 0.189 297);
|
|
576
|
+
--cat-qml: oklch(0.586 0.189 139); --cat-c: oklch(0.450 0.020 280);
|
|
577
|
+
--cat-cpp: oklch(0.629 0.206 7); --cat-vue: oklch(0.587 0.132 160);
|
|
578
|
+
--cat-svelte: oklch(0.629 0.234 34); --cat-lua: oklch(0.271 0.188 264);
|
|
579
|
+
--cat-nix: oklch(0.616 0.187 280); --cat-dockerfile: oklch(0.406 0.029 220);
|
|
580
|
+
--cat-makefile: oklch(0.516 0.137 135);
|
|
581
|
+
}
|
|
582
|
+
|
|
427
583
|
/* ---- Base reset ---- */
|
|
428
584
|
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
|
429
585
|
html { font-size: 16px; }
|
|
@@ -438,6 +594,35 @@ body {
|
|
|
438
594
|
-webkit-font-smoothing: antialiased;
|
|
439
595
|
text-wrap: pretty;
|
|
440
596
|
}
|
|
597
|
+
/* The sky: a 62% x 100% ellipse hung from the top centre, reaching --bg at its
|
|
598
|
+
own edge, so the 780px box draws no seam where it ends. It is its own layer
|
|
599
|
+
at z -2, under the dot grid, so it can move slower than the page: it drifts
|
|
600
|
+
up at a quarter of the scroll speed, and is gone once the
|
|
601
|
+
page has scrolled 3120px. Absolute by default, which scrolls it with the page,
|
|
602
|
+
so an engine with no scroll timeline and a reduced-motion reader both get the
|
|
603
|
+
plain ground. */
|
|
604
|
+
body::after {
|
|
605
|
+
content: "";
|
|
606
|
+
position: absolute;
|
|
607
|
+
inset: 0 0 auto;
|
|
608
|
+
height: 780px;
|
|
609
|
+
z-index: -2;
|
|
610
|
+
pointer-events: none;
|
|
611
|
+
background:
|
|
612
|
+
radial-gradient(ellipse 62% 100% at 50% 0%,
|
|
613
|
+
var(--sky-peak) 0%, var(--sky-mid) 42%, var(--bg) 100%);
|
|
614
|
+
}
|
|
615
|
+
@supports (animation-timeline: scroll()) {
|
|
616
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
617
|
+
body::after {
|
|
618
|
+
position: fixed;
|
|
619
|
+
animation: sky-drift linear both;
|
|
620
|
+
animation-timeline: scroll(root);
|
|
621
|
+
animation-range: 0 3120px;
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
@keyframes sky-drift { to { transform: translateY(-780px); } }
|
|
441
626
|
::selection { background: var(--accent-quiet); color: var(--text); }
|
|
442
627
|
/* `font-family` does not inherit into a <button>: the UA sets it, together with
|
|
443
628
|
a 2px outset border, ButtonFace, ButtonText and centred text, and an author
|
|
@@ -475,8 +660,9 @@ h1 { font: 600 var(--t-8)/1.1 var(--font-sans); letter-spacing: -0.03em; }
|
|
|
475
660
|
h2 { font: 600 var(--t-6)/1.15 var(--font-sans); letter-spacing: -0.02em; }
|
|
476
661
|
h3 { font: 500 var(--t-5)/1.2 var(--font-sans); letter-spacing: -0.01em; }
|
|
477
662
|
h4 { font: 500 var(--t-4)/1.3 var(--font-sans); }
|
|
478
|
-
/* An anchored jump clears
|
|
479
|
-
|
|
663
|
+
/* An anchored jump clears whatever bar this page actually holds, not a fixed
|
|
664
|
+
navbar height: --pin-top is 0 on a page with no bar at all. */
|
|
665
|
+
[id] { scroll-margin-top: calc(var(--pin-top) + var(--space-2)); }
|
|
480
666
|
|
|
481
667
|
/* ---- Utilities ---- */
|
|
482
668
|
.label {
|