reviewzy 0.2.0 → 0.3.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 +1 -1
- package/package.json +1 -1
- package/src/dashboard/static/components.css +6780 -546
- package/src/dashboard/static/cursor-rules.js +83 -0
- package/src/dashboard/static/cursor.css +105 -0
- package/src/dashboard/static/cursor.js +358 -0
- package/src/dashboard/static/dashboard.css +52 -125
- package/src/dashboard/static/dashboard.js +6 -29
- package/src/dashboard/static/fonts/jetbrainsmono-latin-ext.woff2 +0 -0
- package/src/dashboard/static/fonts/jetbrainsmono-latin.woff2 +0 -0
- package/src/dashboard/static/fonts/onest-cyrillic.woff2 +0 -0
- package/src/dashboard/static/fonts/onest-latin-ext.woff2 +0 -0
- package/src/dashboard/static/fonts/onest-latin.woff2 +0 -0
- package/src/dashboard/static/icons.svg +184 -0
- package/src/dashboard/static/tokens.css +421 -110
- package/src/dashboard/static/ui.js +1992 -0
- package/src/dashboard/views.tsx +158 -201
- package/src/db/queries.ts +1 -1
- package/src/mcp/await-approved.ts +17 -10
- package/src/mcp/fetch-approved.ts +11 -6
- package/src/mcp/file-entries.ts +45 -22
- package/src/mcp/list-entries.ts +42 -55
- package/src/mcp/mark-applied.ts +5 -5
- package/src/mcp/server.ts +8 -3
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
/* ============================================================
|
|
2
|
-
|
|
2
|
+
design tokens
|
|
3
|
+
Dark by default, and still full of light.
|
|
4
|
+
Neutrals hold hue 280 (Catppuccin lavender haze), never grey.
|
|
5
|
+
Every ratio in the comments measured, not estimated.
|
|
3
6
|
============================================================ */
|
|
4
7
|
|
|
5
|
-
/* Self-hosted variable fonts
|
|
8
|
+
/* Self-hosted variable fonts - ship the woff2 subsets in fonts/ alongside these
|
|
6
9
|
@font-face blocks. No CDN dependency; faster, private, offline-safe. Subsets:
|
|
7
10
|
latin / latin-ext / cyrillic. Subset your own with fonttools/glyphhanger. */
|
|
8
11
|
@font-face {
|
|
@@ -45,38 +48,226 @@
|
|
|
45
48
|
src: url("fonts/jetbrainsmono-latin-ext.woff2") format("woff2");
|
|
46
49
|
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
|
47
50
|
}
|
|
48
|
-
|
|
49
51
|
:root {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
--
|
|
56
|
-
|
|
57
|
-
--
|
|
58
|
-
--
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
52
|
+
color-scheme: dark;
|
|
53
|
+
|
|
54
|
+
/* ---- Surfaces. The page is NOT the darkest thing possible;
|
|
55
|
+
raising the floor is what makes a dark theme feel airy.
|
|
56
|
+
Surfaces rise TOWARD the light, wells sink below. ---- */
|
|
57
|
+
--well: oklch(0.215 0.020 280); /* inputs, code, tracks */
|
|
58
|
+
--bg: oklch(0.255 0.024 280); /* the page */
|
|
59
|
+
--surface-1: oklch(0.300 0.024 280); /* cards, menus */
|
|
60
|
+
--surface-2: oklch(0.345 0.026 280); /* hover, nested */
|
|
61
|
+
--surface-3: oklch(0.395 0.028 280); /* pressed, selected */
|
|
62
|
+
|
|
63
|
+
/* The system draws its own scrollbar, so the thumb is a graphic this file owns
|
|
64
|
+
and it clears 3:1 on every ground a scroller has: 5.20:1 on --well, 4.68 on
|
|
65
|
+
--bg, 4.05 on --surface-1, 3.43 on a --surface-2 hover tint. --surface-3, the
|
|
66
|
+
colour the retired native rule used, measures 1.67:1 on --bg. */
|
|
67
|
+
--scrollbar-thumb: oklch(0.640 0.028 280);
|
|
68
|
+
|
|
69
|
+
/* Lines are a fallback, not the separation device */
|
|
70
|
+
--line: oklch(0.345 0.026 280);
|
|
71
|
+
--line-soft: oklch(0.310 0.024 280);
|
|
72
|
+
|
|
73
|
+
/* ---- Elevation. A lit top edge plus a dark contact shadow, both in-hue.
|
|
74
|
+
Never rgb(0 0 0): black shadow on lavender goes muddy.
|
|
75
|
+
|
|
76
|
+
A DARK PAGE HAS NO ROOM FOR A WIDE SOFT SHADOW. The page sits 46/255 on
|
|
77
|
+
the blue channel, so a shadow has 46 levels of headroom, and a wide blur
|
|
78
|
+
spends most of them below the quantization floor. The final band, where
|
|
79
|
+
the shadow paints exactly 1 level, is then wide, flat and bounded by a
|
|
80
|
+
clean closed curve: that curve is what reads as a ring drawn around the
|
|
81
|
+
box rather than as light. It widens with the outermost blur radius and
|
|
82
|
+
with how faint the shadow is. Measured beside a card: 28px of blur
|
|
83
|
+
peaking 5 levels deep drew 15px of ring, 40px peaking 10 drew 14px, and
|
|
84
|
+
14px peaking 11 drew 4px. Every blur here stays at or under 22px, every
|
|
85
|
+
coat lands with real depth, which is also what a physical shadow does:
|
|
86
|
+
dark where the object meets the surface, gone a short way out.
|
|
87
|
+
|
|
88
|
+
Measured on a 300x140 card, blue channel against --bg, deepest pixel and
|
|
89
|
+
the width of that last 1-level band:
|
|
90
|
+
--elev-1 24 levels under, 12 beside; band 5px under, 5px beside
|
|
91
|
+
--elev-2 23 / 12; band 7 / 6
|
|
92
|
+
--elev-float 34 / 18; band 8 / 6
|
|
93
|
+
The shipped v1 set measured 9 / 5 with a 15px band, which is the ring.
|
|
94
|
+
|
|
95
|
+
THE EDGE IS WHAT THE EYE READS AS THE CARD STARTING, not the tone step.
|
|
96
|
+
A card sits .045 L over the page and .065 is not available: the fourth
|
|
97
|
+
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. */
|
|
99
|
+
--lit-1: inset 0 1px 0 0 oklch(1 0 0 / 0.085);
|
|
100
|
+
--lit-2: inset 0 1px 0 0 oklch(1 0 0 / 0.100);
|
|
101
|
+
--elev-1: var(--lit-1),
|
|
102
|
+
0 1px 2px -1px oklch(0.11 0.025 280 / 0.72),
|
|
103
|
+
0 3px 6px -2px oklch(0.11 0.025 280 / 0.68),
|
|
104
|
+
0 8px 16px -6px oklch(0.11 0.025 280 / 0.64);
|
|
105
|
+
--elev-2: var(--lit-2),
|
|
106
|
+
0 1px 2px -1px oklch(0.11 0.025 280 / 0.66),
|
|
107
|
+
0 4px 8px -2px oklch(0.11 0.025 280 / 0.62),
|
|
108
|
+
0 10px 18px -8px oklch(0.11 0.025 280 / 0.58);
|
|
109
|
+
--elev-float: var(--lit-2),
|
|
110
|
+
0 2px 4px -1px oklch(0.09 0.022 280 / 0.72),
|
|
111
|
+
0 6px 12px -3px oklch(0.09 0.022 280 / 0.68),
|
|
112
|
+
0 14px 22px -10px oklch(0.09 0.022 280 / 0.66);
|
|
113
|
+
--backdrop: oklch(0.16 0.02 280 / 0.66);
|
|
114
|
+
|
|
115
|
+
/* ---- Glass. Real background blur, on the surfaces something passes behind:
|
|
116
|
+
the mobile topbar, the stuck section header, the floating panels, and a
|
|
117
|
+
panel over the scrim. The navbar is opaque in both of its states. The scrim
|
|
118
|
+
itself stays a flat tint.
|
|
119
|
+
|
|
120
|
+
NEITHER THE ALPHA NOR THE BAR TONE IS TASTE. A glass surface takes on part
|
|
121
|
+
of whatever is behind it, and on a dark page that is nearly always dark, so
|
|
122
|
+
a surface tinted with --surface-1 reads as an opaque slab whatever the blur
|
|
123
|
+
(the 0.90 first material moved 22 levels over a white plate and two or
|
|
124
|
+
three over real content: every panel read as "not blurred"). Bars therefore
|
|
125
|
+
tint with --bg: a bar is the page held still, and content passing under it
|
|
126
|
+
is the only thing that says a surface is there. Panels keep the raised
|
|
127
|
+
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.07, round 1), so 0.86 is the
|
|
129
|
+
floor. On that worst case, a white plate composited through the panel,
|
|
130
|
+
--text holds 6.48:1, --glass-dim 4.67, --glass-danger 4.62. The panel
|
|
131
|
+
moves 35.7 sRGB levels black to white, the measured (1 - alpha) * 255
|
|
132
|
+
identity confirmed on a plate. Filter chains do not buy the floor back:
|
|
133
|
+
crushing the backdrop enough to protect it crushes the blur with it,
|
|
134
|
+
measured across nine chains. ---- */
|
|
135
|
+
--glass-bar-tint: oklch(0.255 0.024 280 / 0.90);
|
|
136
|
+
/* the bar carries only --text and --text-2: 6.21:1 for text-2 on the bar's
|
|
137
|
+
worst case (a white plate through 0.90 of the page colour), no re-floor */
|
|
138
|
+
--glass-tint: oklch(0.300 0.024 280 / 0.86);
|
|
139
|
+
--glass-blur: 22px;
|
|
140
|
+
--glass-sat: 1.25;
|
|
141
|
+
--glass-dim: oklch(0.800 0.030 280); /* --text-3 and --text-4 on a panel:
|
|
142
|
+
4.67:1 on the worst case; unlifted, .720 / .680 fall to 3.52 / 3.03 */
|
|
143
|
+
--glass-danger: oklch(0.84 0.140 15); /* 4.62:1 on the panel worst case.
|
|
144
|
+
--danger is 3.31:1 there, and the round-1 value L 0.78 fell to 4.04 at
|
|
145
|
+
0.86, so the re-floor moves with the alpha */
|
|
146
|
+
--glass-disabled: oklch(0.700 0.030 280); /* 3.27:1 on the panel worst case.
|
|
147
|
+
--text-disabled falls to 2.49 there, and the opacity: 0.45 costume this
|
|
148
|
+
replaces measured 2.17, which is what the panel had been shipping */
|
|
149
|
+
/* A translucent tint over a translucent surface composites twice and drifts 21
|
|
150
|
+
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
|
+
--glass-quiet: color-mix(in oklab, var(--accent) 16%, var(--surface-1));
|
|
153
|
+
/* The one place a drawn line beats the lit edge. A glass panel has no reliable
|
|
154
|
+
tone difference from its backdrop, since it takes that backdrop on, so the
|
|
155
|
+
edge is what says where the pane starts. Still a hairline. */
|
|
156
|
+
--glass-edge: oklch(1 0 0 / 0.10);
|
|
157
|
+
/* a dimmed icon is a graphic against the surface it sits on: on the dark
|
|
158
|
+
glass panel 0.85 leaves a text-3 icon at 2.99:1, under the 3:1 floor, so
|
|
159
|
+
the glass block lifts this to 0.90: 3.15 dark and 3.89 light for the
|
|
160
|
+
dimmest icons on the panel worst cases */
|
|
161
|
+
--icon-dim: 0.7;
|
|
162
|
+
|
|
163
|
+
/* ---- Text. Nothing is pure white; purity reads as hard. ---- */
|
|
164
|
+
--text: oklch(0.900 0.030 280); /* 11.70:1 on --bg */
|
|
165
|
+
--text-2: oklch(0.800 0.030 280); /* 8.43:1 */
|
|
166
|
+
--text-3: oklch(0.720 0.030 280); /* 6.35:1 */
|
|
167
|
+
--text-4: oklch(0.680 0.030 280); /* 5.47:1, the floor */
|
|
168
|
+
/* the hint inside a control. One step under --text-4 so a placeholder does
|
|
169
|
+
not read as a typed value or as metadata: 4.99:1 on --well. */
|
|
170
|
+
--text-placeholder: oklch(0.630 0.030 280);
|
|
171
|
+
/* a control that cannot act, her call 2026-09-02, replacing the opacity: 0.45
|
|
172
|
+
ten declarations across twelve component classes rode. It takes the 3:1 graphics floor rather than the 4.5:1
|
|
173
|
+
text floor, so it can sit a real step under --text-4: 4.99:1 on --well, 4.50
|
|
174
|
+
on --bg, 3.89 on --surface-1, 3.29 on the --surface-2 a disabled fill takes.
|
|
175
|
+
Dark shares the placeholder's value on purpose, since both say "present, not
|
|
176
|
+
live" and this ramp has exactly one step down there. Light does not: its
|
|
177
|
+
placeholder is pinned to --text-4 by the text floor, and a disabled label
|
|
178
|
+
pinned with it would read as enabled metadata, which is the whole defect. */
|
|
179
|
+
--text-disabled: oklch(0.630 0.030 280);
|
|
180
|
+
|
|
181
|
+
/* ---- Accent: Catppuccin sapphire. The break in the overcast. ---- */
|
|
182
|
+
--accent: oklch(0.76 0.110 238); /* 7.49:1 as text on --bg */
|
|
183
|
+
--accent-hover: oklch(0.82 0.115 238); /* brighter in dark */
|
|
184
|
+
--accent-press: oklch(0.70 0.105 238);
|
|
185
|
+
--accent-text: oklch(0.82 0.115 238); /* 9.15:1 as type, the only accent as text */
|
|
186
|
+
--accent-quiet: oklch(0.76 0.110 238 / 0.16);
|
|
187
|
+
--accent-line: oklch(0.76 0.110 238 / 0.38);
|
|
188
|
+
--accent-glow: 0 0 10px 0 oklch(0.76 0.110 238 / 0.55);
|
|
189
|
+
--on-accent: oklch(0.22 0.020 280); /* 8.22:1 on the fill */
|
|
190
|
+
|
|
191
|
+
--accent-2: oklch(0.72 0.130 42); /* editorial, 6.09:1, once per screen */
|
|
192
|
+
--on-accent-2: oklch(0.22 0.020 42); /* 6.69:1 on the fill */
|
|
193
|
+
|
|
194
|
+
/* ---- Status. Levelled under --text so no pill outshouts a title. ---- */
|
|
195
|
+
--success: oklch(0.80 0.130 150); /* 8.89:1 */
|
|
196
|
+
--warning: oklch(0.84 0.110 90); /* 9.68:1 */
|
|
197
|
+
--danger: oklch(0.72 0.140 15); /* 5.98:1 */
|
|
198
|
+
--on-success: oklch(0.22 0.02 150); /* 9.68:1 on the fill */
|
|
199
|
+
--on-warning: oklch(0.22 0.02 90); /* 10.59:1 on the fill */
|
|
200
|
+
--on-danger: oklch(0.22 0.02 15); /* 6.58:1 on the fill */
|
|
201
|
+
--info: var(--accent); /* folded in: it was the same hue */
|
|
202
|
+
|
|
203
|
+
/* ---- Chart series. Four slots; the ORDER is the CVD mechanism, and what it
|
|
204
|
+
buys is that each dichromat's CLOSEST pair never lands on adjacent slots.
|
|
205
|
+
Simulated (Vienot, Brettel & Mollon 1999) and measured as oklab distance:
|
|
206
|
+
protan's closest pair is 1-3 at 0.0355 with orange sitting between them,
|
|
207
|
+
deutan's is 2-4 at 0.0516 with mauve sitting between them, and the closest
|
|
208
|
+
pair a legend does put side by side is 3-4 at 0.1666 / 0.1419. A fifth
|
|
209
|
+
series is a legend problem, not a palette problem, and yellow and red never
|
|
210
|
+
join a series: they read as status.
|
|
211
|
+
|
|
212
|
+
THOSE TWO ARE THE ONLY DICHROMACIES THIS RAMP IS MEASURED AGAINST. Vienot
|
|
213
|
+
publishes a projection plane for protan and deutan only; the tritan row that
|
|
214
|
+
circulates with them moved an equal-lightness blue/yellow pair from 0.2630
|
|
215
|
+
APART to 0.3601, so it cannot be a tritan simulation and no number taken
|
|
216
|
+
from it belongs here. Until one is modelled, treat a two-series chart as
|
|
217
|
+
needing direct labels rather than a legend.
|
|
218
|
+
|
|
219
|
+
Slot 3 is mauve rather than the sky it shipped as. Sky measured 0.0955 from
|
|
220
|
+
sapphire in normal vision, 2.5x closer than any other pair, and the two read
|
|
221
|
+
as one series; mauve puts the ramp's worst normal-vision pair at 0.1411.
|
|
222
|
+
Measured on --surface-1 (WCAG 1.4.11, 3:1 graphics floor):
|
|
223
|
+
5.21 / 5.27 / 6.62 / 6.45:1. Re-measure if --surface-1 moves. ---- */
|
|
224
|
+
--chart-series-1: oklch(0.70 0.110 238); /* sapphire */
|
|
225
|
+
--chart-series-2: oklch(0.72 0.130 42); /* orange */
|
|
226
|
+
--chart-series-3: oklch(0.78 0.100 305); /* mauve */
|
|
227
|
+
--chart-series-4: oklch(0.75 0.120 150); /* green */
|
|
228
|
+
|
|
229
|
+
/* ---- Radius. Softer than v1's 1px, which rendered as 0. ---- */
|
|
230
|
+
--r-1: 10px; /* controls */
|
|
231
|
+
--r-2: 14px; /* cards, menus */
|
|
232
|
+
--r-3: 18px; /* modals, sheets */
|
|
233
|
+
--r-pill: 999px;
|
|
234
|
+
|
|
235
|
+
/* ---- Motion. Duration follows distance. ---- */
|
|
236
|
+
--ease: cubic-bezier(0.2, 0, 0, 1); /* state changes, exits */
|
|
237
|
+
--ease-out: cubic-bezier(0.16, 1, 0.3, 1); /* entrances, arrivals */
|
|
238
|
+
--dur-tint: 120ms; /* no travel: colour, opacity, border */
|
|
239
|
+
--dur-near: 180ms; /* under 12px: toast, popover, tooltip */
|
|
240
|
+
--dur-far: 260ms; /* a panel's worth: sheet, accordion */
|
|
241
|
+
--dur-cross: 360ms; /* across the viewport: drawer */
|
|
242
|
+
--dur-slide: 440ms; /* sliding indicators only */
|
|
243
|
+
--stagger: 40ms; /* per item, capped at 6 */
|
|
244
|
+
--dur-out: calc(var(--dur-tint) * 0.6); /* exits run at 0.6x */
|
|
245
|
+
--dur-out-near: calc(var(--dur-near) * 0.6);
|
|
246
|
+
--dur-out-far: calc(var(--dur-far) * 0.6);
|
|
247
|
+
|
|
248
|
+
/* ---- Type. 8 distinct steps; 11px and 12px are real tokens. ---- */
|
|
249
|
+
--t-1: 11px; --t-2: 12px; --t-3: 14px; --t-4: 16px;
|
|
250
|
+
--t-5: 20px; --t-6: 26px; --t-7: 34px; --t-8: 46px;
|
|
251
|
+
--caps: 0.09em; /* the one tracking value */
|
|
252
|
+
|
|
253
|
+
/* ---- Controls share one height ladder with inputs ---- */
|
|
254
|
+
--ctl-sm: 30px; --ctl: 36px; --ctl-lg: 44px;
|
|
255
|
+
|
|
256
|
+
/* ---- Layout ---- */
|
|
257
|
+
--page-w: 1200px; /* .page column; one override retunes a build */
|
|
258
|
+
/* prose measure, MEASURED against loaded Onest at --t-4 rather than estimated:
|
|
259
|
+
528px lands 64.9 and 68.1 characters per line on two samples, 664px lands
|
|
260
|
+
84.4 and 85.3. A line that runs the full page column is a line nobody
|
|
261
|
+
finishes. Erring short is the safer side of 66. */
|
|
262
|
+
--page-narrow: 528px;
|
|
263
|
+
--navbar-h: 56px; /* the sticky header and the anchor offset both derive from it */
|
|
264
|
+
--topbar-h: 52px; /* the mobile bar; the sticky header pins under this one below 768px */
|
|
265
|
+
|
|
266
|
+
/* ---- Fonts ---- */
|
|
66
267
|
--font-sans: "Onest", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
|
|
67
268
|
--font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
68
269
|
|
|
69
|
-
/*
|
|
70
|
-
--text-xs: 12px;
|
|
71
|
-
--text-sm: 13px;
|
|
72
|
-
--text-base: 14px;
|
|
73
|
-
--text-md: 16px;
|
|
74
|
-
--text-lg: 18px;
|
|
75
|
-
--text-xl: 22px;
|
|
76
|
-
--text-2xl: 28px;
|
|
77
|
-
--text-3xl: 36px;
|
|
78
|
-
|
|
79
|
-
/* Spacing (4px scale) */
|
|
270
|
+
/* ---- Spacing (4px scale) ---- */
|
|
80
271
|
--space-0: 0;
|
|
81
272
|
--space-1: 4px;
|
|
82
273
|
--space-2: 8px;
|
|
@@ -89,91 +280,148 @@
|
|
|
89
280
|
--space-12: 48px;
|
|
90
281
|
--space-16: 64px;
|
|
91
282
|
--space-20: 80px;
|
|
283
|
+
}
|
|
92
284
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
--radius-pill: 999px;
|
|
285
|
+
/* Radius preset: sharp is the opt-in variant, real 0 */
|
|
286
|
+
[data-radius="sharp"] { --r-1: 0px; --r-2: 0px; --r-3: 0px; }
|
|
96
287
|
|
|
97
|
-
|
|
98
|
-
|
|
288
|
+
/* ---- Light theme (Latte). EVERY colour and elevation token is
|
|
289
|
+
re-declared, because a partial override is the bug that broke
|
|
290
|
+
v1's light theme: its tints were mixed from the dark accent.
|
|
291
|
+
Ratios measured against THIS block's --bg. ---- */
|
|
292
|
+
[data-theme="light"] {
|
|
293
|
+
color-scheme: light;
|
|
99
294
|
|
|
100
|
-
/*
|
|
101
|
-
--
|
|
102
|
-
--
|
|
103
|
-
--
|
|
104
|
-
--
|
|
105
|
-
--
|
|
106
|
-
|
|
295
|
+
--surface-3: oklch(0.905 0.010 275); /* pressed: light goes DOWN */
|
|
296
|
+
/* 3.58:1 on --well, 3.92 on --bg, 4.40 on --surface-1, 3.69 on the hover tint */
|
|
297
|
+
--scrollbar-thumb: oklch(0.570 0.010 275);
|
|
298
|
+
--surface-2: oklch(0.935 0.008 275); /* hover */
|
|
299
|
+
--well: oklch(0.925 0.008 275);
|
|
300
|
+
--bg: oklch(0.955 0.006 275);
|
|
301
|
+
--surface-1: oklch(0.995 0.003 275); /* cards still rise */
|
|
107
302
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
[data-radius="soft"] { --radius: 1px; }
|
|
111
|
-
[data-radius="rounded"] { --radius: 6px; }
|
|
303
|
+
--line: oklch(0.890 0.012 275); /* barely there, 1.22:1 */
|
|
304
|
+
--line-soft: oklch(0.920 0.010 275);
|
|
112
305
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
--
|
|
116
|
-
--
|
|
117
|
-
--
|
|
118
|
-
|
|
306
|
+
--text: oklch(0.300 0.020 275); /* 11.98:1 */
|
|
307
|
+
--text-2: oklch(0.420 0.020 275); /* 7.44:1 */
|
|
308
|
+
--text-3: oklch(0.500 0.018 275); /* 5.27:1 */
|
|
309
|
+
--text-4: oklch(0.515 0.016 275); /* 4.94:1 on --bg, 4.52:1 on --well, the floor */
|
|
310
|
+
/* 4.52:1 on --well is the floor already; light has no headroom under it, so
|
|
311
|
+
the placeholder holds --text-4's value and the dark block alone dims. */
|
|
312
|
+
--text-placeholder: oklch(0.515 0.016 275);
|
|
313
|
+
/* the 3:1 floor is what buys the step the 4.5:1 one denies the placeholder:
|
|
314
|
+
3.23:1 on --surface-3, 3.44 on --well, 3.54 on --surface-2, 3.76 on --bg,
|
|
315
|
+
4.23 on --surface-1 */
|
|
316
|
+
--text-disabled: oklch(0.580 0.016 275);
|
|
119
317
|
|
|
120
|
-
--
|
|
121
|
-
--
|
|
122
|
-
--
|
|
318
|
+
--accent: oklch(0.55 0.140 238); /* 4.60:1 under --on-accent; 4.09:1 as text */
|
|
319
|
+
--accent-hover: oklch(0.49 0.135 238);
|
|
320
|
+
--accent-press: oklch(0.44 0.125 238);
|
|
321
|
+
--accent-text: oklch(0.50 0.130 238); /* 5.06:1 as type; accent as text fails 4.5 */
|
|
322
|
+
--accent-quiet: oklch(0.55 0.140 238 / 0.12);
|
|
323
|
+
--accent-line: oklch(0.55 0.140 238 / 0.34);
|
|
324
|
+
--accent-glow: 0 0 10px 0 oklch(0.55 0.140 238 / 0.30);
|
|
325
|
+
--on-accent: oklch(0.995 0.003 238);
|
|
123
326
|
|
|
124
|
-
--
|
|
125
|
-
--
|
|
126
|
-
--text-dim: #A6ADC8;
|
|
127
|
-
--text-faint: #7F849C;
|
|
128
|
-
--text-on-accent: #11111B;
|
|
129
|
-
}
|
|
327
|
+
--accent-2: oklch(0.52 0.150 42); /* 5.16:1 */
|
|
328
|
+
--on-accent-2: oklch(0.995 0.003 42);
|
|
130
329
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
--
|
|
134
|
-
--
|
|
135
|
-
--
|
|
136
|
-
--
|
|
330
|
+
--success: oklch(0.50 0.150 150); /* 4.85:1 */
|
|
331
|
+
--warning: oklch(0.50 0.130 90); /* 5.25:1 */
|
|
332
|
+
--danger: oklch(0.52 0.190 15); /* 5.36:1 */
|
|
333
|
+
--on-success: oklch(0.995 0.003 150);
|
|
334
|
+
--on-warning: oklch(0.995 0.003 90);
|
|
335
|
+
--on-danger: oklch(0.995 0.003 15);
|
|
336
|
+
--info: var(--accent);
|
|
137
337
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
338
|
+
/* The lit edge flips to the underside: light falls from above, so
|
|
339
|
+
on a light page the visible edge is the shadow, not the highlight.
|
|
340
|
+
Same geometry as the dark set, so both themes carry one shadow shape and
|
|
341
|
+
only the alphas differ. A light page has 244 levels of headroom, so the
|
|
342
|
+
banding that governs the dark set is not the binding constraint here; the
|
|
343
|
+
geometry is shared because a component must not change depth on a toggle.
|
|
344
|
+
Measured on a 300x140 card, blue channel against --bg, deepest pixel and
|
|
345
|
+
the last 1-level band: --elev-1 33 under / 13 beside, band 4 / 4;
|
|
346
|
+
--elev-2 32 / 14, band 3 / 2; --elev-float 42 / 19, band 5 / 3. */
|
|
347
|
+
--lit-1: inset 0 -1px 0 0 oklch(0.55 0.03 275 / 0.10);
|
|
348
|
+
--lit-2: inset 0 -1px 0 0 oklch(0.55 0.03 275 / 0.12);
|
|
349
|
+
--elev-1: var(--lit-1),
|
|
350
|
+
0 1px 2px -1px oklch(0.55 0.03 275 / 0.26),
|
|
351
|
+
0 3px 6px -2px oklch(0.55 0.03 275 / 0.23),
|
|
352
|
+
0 8px 16px -6px oklch(0.55 0.03 275 / 0.21);
|
|
353
|
+
--elev-2: var(--lit-2),
|
|
354
|
+
0 1px 2px -1px oklch(0.55 0.03 275 / 0.24),
|
|
355
|
+
0 4px 8px -2px oklch(0.55 0.03 275 / 0.21),
|
|
356
|
+
0 10px 18px -8px oklch(0.55 0.03 275 / 0.19);
|
|
357
|
+
--elev-float: var(--lit-2),
|
|
358
|
+
0 2px 4px -1px oklch(0.55 0.03 275 / 0.26),
|
|
359
|
+
0 6px 12px -3px oklch(0.55 0.03 275 / 0.23),
|
|
360
|
+
0 14px 22px -10px oklch(0.55 0.03 275 / 0.21);
|
|
361
|
+
--backdrop: oklch(0.45 0.02 275 / 0.32);
|
|
141
362
|
|
|
142
|
-
--
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
363
|
+
/* Glass. The same split the dark block ships: bars tint with --bg, panels
|
|
364
|
+
hold surface-1 at the clearest alpha the ramp allows. Worst case on a light
|
|
365
|
+
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, independently) and --danger 4.81. The shipped
|
|
367
|
+
--text-4 value 0.515 measures 4.44 there, so it joins the dim step. 0.90 is
|
|
368
|
+
25.5 sRGB levels black to white. --accent-text stays bound to its opaque
|
|
369
|
+
quiet fill (4.89:1, unchanged, because the fill is opaque). */
|
|
370
|
+
--glass-bar-tint: oklch(0.955 0.006 275 / 0.92);
|
|
371
|
+
--glass-tint: oklch(0.995 0.003 275 / 0.90);
|
|
372
|
+
--glass-dim: oklch(0.500 0.018 275);
|
|
373
|
+
--glass-danger: var(--danger);
|
|
374
|
+
/* light needs no lift here: --text-disabled already measures 3.37:1 on the
|
|
375
|
+
panel worst case, where dark's falls to 2.49 */
|
|
376
|
+
--glass-disabled: var(--text-disabled);
|
|
377
|
+
--glass-quiet: color-mix(in oklab, var(--accent) 12%, var(--surface-1));
|
|
378
|
+
--glass-edge: oklch(0.45 0.03 275 / 0.12);
|
|
147
379
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
380
|
+
/* A light page has less room under a dim than a dark one: at the 0.7 the dark
|
|
381
|
+
block ships, --text-4 measures 2.79:1 on --bg and 2.98 on --surface-1 here,
|
|
382
|
+
both under the 3:1 graphics floor, and --text-3 2.90 / 3.10. Lifted to the
|
|
383
|
+
same 0.90 the glass block uses, which takes the worst of those to 4.04, and
|
|
384
|
+
means an icon does not change when it crosses onto a glass panel. */
|
|
385
|
+
--icon-dim: 0.90;
|
|
151
386
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
--info: #209FB5;
|
|
387
|
+
/* Chart series on the light surface-1: 5.81 / 5.80 / 5.12 / 5.55:1. Slot 3 is
|
|
388
|
+
mauve here too: against sky the 1-3 pair measured 0.0790 in oklab and now
|
|
389
|
+
measures 0.1556.
|
|
156
390
|
|
|
157
|
-
|
|
391
|
+
SLOTS 1 AND 4 ARE HELD AT THE sRGB BOUNDARY, her call 2026-09-02. At their
|
|
392
|
+
old chromas the browser clipped them (slot 1's linear red measured -0.0182,
|
|
393
|
+
slot 4's -0.0020), so the declared values named colours nobody saw and every
|
|
394
|
+
distance taken from a declaration overstated the gap. The gamut runs out at
|
|
395
|
+
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. `tools/cvd.mjs` reds on any slot
|
|
397
|
+
outside sRGB, on every run. */
|
|
398
|
+
--chart-series-1: oklch(0.50 0.110 238);
|
|
399
|
+
--chart-series-2: oklch(0.52 0.150 42);
|
|
400
|
+
--chart-series-3: oklch(0.55 0.150 305);
|
|
401
|
+
--chart-series-4: oklch(0.50 0.135 150);
|
|
158
402
|
}
|
|
159
403
|
|
|
160
|
-
/* ---- Optional categorical palette (
|
|
404
|
+
/* ---- Optional categorical palette (Catppuccin accent ramp) ----
|
|
161
405
|
For category coding only: per-language dots, syntax, tags, multi-series charts.
|
|
162
|
-
NOT for status (use --success / --warning / --danger
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
--cat-rosewater
|
|
166
|
-
--cat-
|
|
167
|
-
--cat-
|
|
168
|
-
--cat-
|
|
169
|
-
--cat-
|
|
406
|
+
NOT for status (use --success / --warning / --danger) and NOT for chrome.
|
|
407
|
+
Converted from the v1 hex ramp, computed not estimated. */
|
|
408
|
+
:root {
|
|
409
|
+
--cat-rosewater: oklch(0.923 0.024 30); --cat-flamingo: oklch(0.880 0.042 18);
|
|
410
|
+
--cat-pink: oklch(0.870 0.075 336); --cat-mauve: oklch(0.787 0.119 305);
|
|
411
|
+
--cat-red: oklch(0.756 0.130 3); --cat-maroon: oklch(0.782 0.090 9);
|
|
412
|
+
--cat-peach: oklch(0.824 0.101 53); --cat-yellow: oklch(0.919 0.070 87);
|
|
413
|
+
--cat-green: oklch(0.858 0.109 143); --cat-teal: oklch(0.858 0.079 183);
|
|
414
|
+
--cat-sky: oklch(0.847 0.083 210); --cat-sapphire: oklch(0.791 0.096 229);
|
|
415
|
+
--cat-blue: oklch(0.766 0.111 260); --cat-lavender: oklch(0.817 0.091 277);
|
|
170
416
|
}
|
|
171
417
|
[data-theme="light"] {
|
|
172
|
-
--cat-rosewater
|
|
173
|
-
--cat-
|
|
174
|
-
--cat-
|
|
175
|
-
--cat-
|
|
176
|
-
--cat-
|
|
418
|
+
--cat-rosewater: oklch(0.714 0.105 33); --cat-flamingo: oklch(0.686 0.126 21);
|
|
419
|
+
--cat-pink: oklch(0.726 0.174 338); --cat-mauve: oklch(0.555 0.250 297);
|
|
420
|
+
--cat-red: oklch(0.550 0.216 20); --cat-maroon: oklch(0.625 0.197 20);
|
|
421
|
+
--cat-peach: oklch(0.692 0.204 42); --cat-yellow: oklch(0.714 0.149 68);
|
|
422
|
+
--cat-green: oklch(0.625 0.177 140); --cat-teal: oklch(0.602 0.098 201);
|
|
423
|
+
--cat-sky: oklch(0.682 0.145 235); --cat-sapphire: oklch(0.648 0.107 213);
|
|
424
|
+
--cat-blue: oklch(0.559 0.226 262); --cat-lavender: oklch(0.664 0.175 273);
|
|
177
425
|
}
|
|
178
426
|
|
|
179
427
|
/* ---- Base reset ---- */
|
|
@@ -181,33 +429,96 @@
|
|
|
181
429
|
html { font-size: 16px; }
|
|
182
430
|
body {
|
|
183
431
|
font-family: var(--font-sans);
|
|
184
|
-
font-size: var(--
|
|
432
|
+
font-size: var(--t-3);
|
|
185
433
|
line-height: 1.55;
|
|
186
434
|
font-weight: 400;
|
|
187
435
|
color: var(--text);
|
|
188
436
|
background: var(--bg);
|
|
437
|
+
accent-color: var(--accent);
|
|
189
438
|
-webkit-font-smoothing: antialiased;
|
|
190
439
|
text-wrap: pretty;
|
|
191
440
|
}
|
|
192
|
-
::selection { background: var(--accent-
|
|
193
|
-
|
|
441
|
+
::selection { background: var(--accent-quiet); color: var(--text); }
|
|
442
|
+
/* `font-family` does not inherit into a <button>: the UA sets it, together with
|
|
443
|
+
a 2px outset border, ButtonFace, ButtonText and centred text, and an author
|
|
444
|
+
rule beats a UA rule at any specificity. Every component class that lands on a
|
|
445
|
+
button would otherwise have to restate all five, and the ones that do not
|
|
446
|
+
measured in the UA's Arial on a bare button. At (0,0,1) this loses to a
|
|
447
|
+
component's own costume whatever the source order. */
|
|
448
|
+
button {
|
|
449
|
+
font: inherit;
|
|
450
|
+
border: 0;
|
|
451
|
+
background: none;
|
|
452
|
+
color: inherit;
|
|
453
|
+
text-align: inherit;
|
|
454
|
+
}
|
|
455
|
+
:focus-visible {
|
|
456
|
+
outline: 2px solid var(--accent);
|
|
457
|
+
outline-offset: 3px;
|
|
458
|
+
box-shadow: 0 0 0 1px var(--bg);
|
|
459
|
+
}
|
|
460
|
+
/* An author rule beats a UA rule whatever the specificity, so `.btn` and every other block
|
|
461
|
+
here keeps painting under the `hidden` attribute without this line. A script toggling
|
|
462
|
+
`hidden` then silently does nothing. `!important` is load-bearing: the component rules
|
|
463
|
+
are the thing being overridden. */
|
|
464
|
+
[hidden] { display: none !important; }
|
|
465
|
+
|
|
466
|
+
/* ---- Document defaults: pages stop hand-rolling typography. ---- */
|
|
467
|
+
a { color: var(--accent-text); text-decoration: none; }
|
|
468
|
+
/* :where() zeroes the specificity, so every component class that sets
|
|
469
|
+
`text-decoration: none` in its base rule outranks this. At (0,1,1) it beat
|
|
470
|
+
them all and underlined the sidebar rows, a `.btn` written as a link and every
|
|
471
|
+
menu row; four components had already restated the reset on hover. */
|
|
472
|
+
:where(a):hover { text-decoration: underline; text-underline-offset: 2px; }
|
|
473
|
+
h1, h2, h3, h4 { color: var(--text); text-wrap: balance; }
|
|
474
|
+
h1 { font: 600 var(--t-8)/1.1 var(--font-sans); letter-spacing: -0.03em; }
|
|
475
|
+
h2 { font: 600 var(--t-6)/1.15 var(--font-sans); letter-spacing: -0.02em; }
|
|
476
|
+
h3 { font: 500 var(--t-5)/1.2 var(--font-sans); letter-spacing: -0.01em; }
|
|
477
|
+
h4 { font: 500 var(--t-4)/1.3 var(--font-sans); }
|
|
478
|
+
/* An anchored jump clears the sticky navbar instead of tucking under it. */
|
|
479
|
+
[id] { scroll-margin-top: calc(var(--navbar-h) + var(--space-2)); }
|
|
194
480
|
|
|
195
481
|
/* ---- Utilities ---- */
|
|
196
482
|
.label {
|
|
197
|
-
font:
|
|
198
|
-
letter-spacing:
|
|
483
|
+
font: 500 11px/1.4 var(--font-sans);
|
|
484
|
+
letter-spacing: var(--caps);
|
|
199
485
|
text-transform: uppercase;
|
|
200
|
-
color: var(--text-
|
|
486
|
+
color: var(--text-3);
|
|
201
487
|
}
|
|
202
488
|
.num {
|
|
203
489
|
font-variant-numeric: tabular-nums;
|
|
204
490
|
font-feature-settings: "tnum";
|
|
205
491
|
}
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
492
|
+
/* Unbreakable machine strings wrap inside their box; they never widen a page.
|
|
493
|
+
The five component selectors below are the same costume, named here rather
|
|
494
|
+
than restated in components.css. `.copy-chip-fill > .copy-chip-value` at
|
|
495
|
+
(0,2,0) still turns it back off, and `.chart-ticks-band .chart-tick` keeps its
|
|
496
|
+
own position and translate. */
|
|
497
|
+
.truncate,
|
|
498
|
+
.select-value,
|
|
499
|
+
.tree-label,
|
|
500
|
+
.status-legend-name,
|
|
501
|
+
.copy-chip-value,
|
|
502
|
+
.chart-ticks-band .chart-tick { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
503
|
+
.clamp-2 {
|
|
504
|
+
display: -webkit-box;
|
|
505
|
+
-webkit-line-clamp: 2;
|
|
506
|
+
-webkit-box-orient: vertical;
|
|
507
|
+
overflow: hidden;
|
|
508
|
+
}
|
|
509
|
+
/* `.stepper-compact .step-text` is this costume under another name, so it is
|
|
510
|
+
named here. The navbar's own label cannot join: it hides only under
|
|
511
|
+
`@media (max-width: 768px)`, and this rule has no condition to carry. */
|
|
512
|
+
.sr-only,
|
|
513
|
+
.stepper-compact .step-text {
|
|
514
|
+
position: absolute;
|
|
515
|
+
width: 1px;
|
|
516
|
+
height: 1px;
|
|
517
|
+
padding: 0;
|
|
518
|
+
margin: -1px;
|
|
519
|
+
overflow: hidden;
|
|
520
|
+
clip: rect(0 0 0 0);
|
|
521
|
+
clip-path: inset(50%);
|
|
522
|
+
white-space: nowrap;
|
|
523
|
+
border: 0;
|
|
213
524
|
}
|