sheleg-design-skill 1.51.1 → 1.52.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/CHANGELOG.md +91 -0
- package/kits/deskmate/src/styles.css +89 -26
- package/kits/onionskin/src/styles.css +19 -2
- package/package.json +2 -2
- package/plugins/sheleg-design/.claude-plugin/plugin.json +1 -1
- package/plugins/sheleg-design/skills/sheleg-design/SKILL.md +3 -3
- package/plugins/sheleg-design/skills/sheleg-design/SURFACE_COMPOSITION.md +6 -3
- package/plugins/sheleg-design/skills/sheleg-design/styles/deskmate.md +61 -18
- package/plugins/sheleg-design/skills/sheleg-design/styles/tokens/deskmate.css +68 -10
- package/plugins/sheleg-design/skills/sheleg-design/styles/tokens/onionskin.css +19 -2
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,97 @@ follow [SemVer](https://semver.org/spec/v2.0.0.html).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [1.52.0] - 2026-08-27
|
|
10
|
+
|
|
11
|
+
### The front door is the designs
|
|
12
|
+
|
|
13
|
+
Opening the published catalogue used to mean reading three tiles and clicking one before
|
|
14
|
+
seeing a single pack. It now opens **on the packs**, behind a tab strip of three real
|
|
15
|
+
screens: **Designs** (the front door, and it is the gallery), **Audit** and **Method** —
|
|
16
|
+
the prose that used to occupy the index. `packs.html` stays as a canonical alias for the
|
|
17
|
+
URL the gallery lived at, because two URLs serving one gallery is duplicate content.
|
|
18
|
+
|
|
19
|
+
The tabs are links to pages rather than panels toggled in one document, and that is the
|
|
20
|
+
SEO decision, not a shortcut: one URL per screen, every screen fully in the HTML, nothing
|
|
21
|
+
behind a click a crawler has to execute. `rel="prefetch"` buys the tab feel back.
|
|
22
|
+
|
|
23
|
+
### What the SEO pass changed
|
|
24
|
+
|
|
25
|
+
- **Structured data, with one publisher everybody points at.** A `CollectionPage` whose
|
|
26
|
+
`mainEntity` is an `ItemList` of all thirty-six packs, each with its own anchor
|
|
27
|
+
(`/#pack-<name>`), so an answer engine can lift the list without running the filter JS;
|
|
28
|
+
a `SoftwareApplication` on Method; `BreadcrumbList` on both sub-pages; and an
|
|
29
|
+
`Organization` node referenced by `@id` from every page. The family site shipped the
|
|
30
|
+
opposite of that for two releases — a publisher node nothing pointed at.
|
|
31
|
+
- **A `404.html`**, a three-URL sitemap that lists only indexable screens, `llms.txt`
|
|
32
|
+
rewritten for the new shape, and `max-image-preview:large`, `color-scheme`,
|
|
33
|
+
`theme-color`, `og:site_name` and `og:locale` on every page.
|
|
34
|
+
- **Two defects the pass found in the old pages:** `method.html` was emitting its
|
|
35
|
+
canonical and description **twice** (the shared `HEAD` and `page_meta` both fired), and
|
|
36
|
+
the published dark-field count was **wrong** — `gallery.py` could not parse
|
|
37
|
+
`oklch()`, so `briefing-room`'s near-black field read as light and the site, its
|
|
38
|
+
`llms.txt` and its gallery all said five dark packs where six ship.
|
|
39
|
+
|
|
40
|
+
### `deskmate`, corrected by its own audit
|
|
41
|
+
|
|
42
|
+
A blind read of the pack (T34a, which also routed correctly and rejected `tenor` on the
|
|
43
|
+
quoted clause) found nine defects. The important one is a colour pairing no gate can see:
|
|
44
|
+
`--surface` stays white on the dusk surface while `--ink` inverts to white, so **a card
|
|
45
|
+
that painted its heading in `--ink` painted white on white** inside an inverted section.
|
|
46
|
+
The pack now ships `--on-surface` and `--on-surface-soft` — words on a card take those,
|
|
47
|
+
words on the field take `--ink` — and the kit consumes them.
|
|
48
|
+
|
|
49
|
+
Also fixed: the focus ring shipped derived-only, so a browser without `color-mix()` got
|
|
50
|
+
**no ring at all** (literal first now, derived inside `@supports`, the mechanism
|
|
51
|
+
`showroom` established); the slab's inset was 40px in the pack and 80px in the token
|
|
52
|
+
layer; the gutter ramp stated four steps and shipped two tokens; the measure stated in
|
|
53
|
+
prose (62ch/68ch) had no token; the entrance duration's two measurements (0.64s declared,
|
|
54
|
+
0.7s computed) were never reconciled; "the smallest radius that ships" and "every control
|
|
55
|
+
is 56px" were both contradicted by the pack's own body; and the provenance promise was
|
|
56
|
+
broader than the layer delivers.
|
|
57
|
+
|
|
58
|
+
One finding was rejected: `deskmate` is absent from `MOTION_DOCTRINE.md`'s ceiling
|
|
59
|
+
passage, and that passage is a named selection whose home the gate declares to be the
|
|
60
|
+
pack's own Register.
|
|
61
|
+
|
|
62
|
+
### `onionskin` gets the same focus-ring guard
|
|
63
|
+
|
|
64
|
+
The audit that read `deskmate` measured the whole library for the same shape: three
|
|
65
|
+
packs derive a focus ring, and only `showroom` guarded it. `onionskin`'s ring was
|
|
66
|
+
`color-mix()`-only, so a browser without `color-mix()` painted **no ring at all** — the
|
|
67
|
+
one degradation both packs say they may not ship. The literal now sits in `:root` and the
|
|
68
|
+
derived form in an `@supports` block; no computed value changed, and its kit's token
|
|
69
|
+
block was resynced with it.
|
|
70
|
+
|
|
71
|
+
### A count nothing could check, and now can
|
|
72
|
+
|
|
73
|
+
`SURFACE_COMPOSITION.md` claimed `--accent` in **twenty-nine** of the packs at a true
|
|
74
|
+
**thirty-three**, and named two of the three packs that call the accent something else —
|
|
75
|
+
omitting `babylove` entirely, so a reader following that sentence would look for a token
|
|
76
|
+
that pack does not have. `validate_counted_claims` cannot read a count whose noun is
|
|
77
|
+
"packs that declare a token", so `validate_token_population_counts` now derives both that
|
|
78
|
+
figure and the `@role non-text:` population from the token layers, and refuses a pack
|
|
79
|
+
that declares neither an `--accent` nor an `@role accent:` marker. The same sweep found
|
|
80
|
+
`SKILL.md` still saying "the twenty-nine".
|
|
81
|
+
|
|
82
|
+
### The scenario that produced all of this, and the half of it that did not run
|
|
83
|
+
|
|
84
|
+
`T34` is the behavioural scenario shipped with `deskmate`, and 1.52.0 is the first
|
|
85
|
+
release where one of these branches was actually run rather than filed. **`T34a`
|
|
86
|
+
passed**: it routed to the pack, quoted the deciding clause, rejected `tenor` on the
|
|
87
|
+
clause that rules it out, and stayed inside the bundle directory. It then did the half
|
|
88
|
+
these scenarios have always asked for and never exercised — read the chosen pack in full
|
|
89
|
+
and report defects with quotes — and returned nine, eight of which are fixed above.
|
|
90
|
+
|
|
91
|
+
**`T34b`, the negative branch, terminated on an account spend limit before reporting a
|
|
92
|
+
verdict, and is not counted as a result.** A positive-only pass cannot detect the failure
|
|
93
|
+
that branch exists to detect. `test/scenarios.md` records both outcomes.
|
|
94
|
+
|
|
95
|
+
### Ratchets
|
|
96
|
+
|
|
97
|
+
`validate.py` 5047 → 5060, `validate_palette.py` 3013 → 3023, `computed_at_least`
|
|
98
|
+
686 → 691. Thirteen of the first delta are the new gate.
|
|
99
|
+
|
|
9
100
|
## [1.51.1] - 2026-08-27
|
|
10
101
|
|
|
11
102
|
### `deskmate`, the thirty-sixth pack — a colleague, quoted
|
|
@@ -58,6 +58,13 @@
|
|
|
58
58
|
rules and it bars, and an icon that must be READ takes --ink-soft instead. */
|
|
59
59
|
--ink-faint: #9693a3;
|
|
60
60
|
--on-ink: #ffffff; /* 17.36:1 on --ink */
|
|
61
|
+
/* THE RULE THIS PACK CANNOT BE READ WITHOUT: --ink is for words on --bg, and
|
|
62
|
+
--on-surface is for words on --surface. On the light field the two are the same
|
|
63
|
+
value and the distinction looks decorative. On the dusk surface it is the whole
|
|
64
|
+
difference: --surface stays white there, measured, so a card that paints its text
|
|
65
|
+
in --ink paints white on white. Every component that sits on a card takes these. */
|
|
66
|
+
--on-surface: #1a182b; /* 17.36:1 on --surface */
|
|
67
|
+
--on-surface-soft: #716f7e; /* 4.91:1 on --surface */
|
|
61
68
|
|
|
62
69
|
/* ---- The accent: it writes, it fills, and it needed no correction ---- */
|
|
63
70
|
/* MEASURED. #6e47ff is the reference's purple-500 and its only functional accent:
|
|
@@ -121,9 +128,18 @@
|
|
|
121
128
|
/* MEASURED — `ring-3` is 3px, and the ring's alpha IS its specification: 50% behind
|
|
122
129
|
a control, 40% behind a field. Composited over white #ffffff the ring is
|
|
123
130
|
#b6a3ff at 2.17:1, which is why the control's own border moves colour in the
|
|
124
|
-
same state.
|
|
125
|
-
|
|
126
|
-
|
|
131
|
+
same state.
|
|
132
|
+
|
|
133
|
+
THE LITERAL IS HERE AND THE DERIVED FORM IS IN THE `@supports` BLOCK AT THE END OF
|
|
134
|
+
THIS FILE, and the order is not a style preference. A custom property accepts
|
|
135
|
+
almost any token sequence, so `--focus-ring: color-mix(…)` parses even where
|
|
136
|
+
`color-mix()` is unsupported and wins the cascade; the invalidity surfaces only
|
|
137
|
+
where it is substituted, as invalid-at-computed-value-time, and by then the literal
|
|
138
|
+
is gone and `var(--focus-ring)` resolves to `unset` — an INVISIBLE FOCUS RING, on
|
|
139
|
+
the one degradation this pack says it may not ship. `showroom` is the worked
|
|
140
|
+
example this copies. */
|
|
141
|
+
--focus-ring: 0 0 0 3px rgba(110, 71, 255, 0.5);
|
|
142
|
+
--focus-ring-field: 0 0 0 3px rgba(110, 71, 255, 0.4);
|
|
127
143
|
|
|
128
144
|
/* ---- Radii: a pill for the hand, a slab for the eye ----------------- */
|
|
129
145
|
/* MEASURED at 1440: 977 of 1,191 visible elements compute 0px, 52 take the 32px
|
|
@@ -160,14 +176,20 @@
|
|
|
160
176
|
--space-28: 112px; /* MEASURED — the section's own vertical rhythm */
|
|
161
177
|
|
|
162
178
|
--page-max: 90rem; /* 1440px — MEASURED */
|
|
163
|
-
|
|
164
|
-
|
|
179
|
+
/* MEASURED, and the ramp ships as four tokens rather than as a sentence: the page's
|
|
180
|
+
gutter steps 20 → 40 → 56 → 80 across the reference's own breakpoints, and a step a
|
|
181
|
+
consumer cannot reach through a variable is a step the pack did not ship. */
|
|
182
|
+
--gutter: 20px;
|
|
183
|
+
--gutter-2: 40px; /* from 40rem */
|
|
184
|
+
--gutter-3: 56px; /* from 48rem */
|
|
185
|
+
--gutter-wide: 80px; /* from 64rem, and the value at 1440 */
|
|
165
186
|
--control-h: 56px; /* MEASURED — the button and the field are the same height */
|
|
166
187
|
--control-h-sm: 40px; /* MEASURED — the navigation's own pair, and see --tap-min */
|
|
167
188
|
--control-px: 40px; /* MEASURED — 24px on the small size */
|
|
168
189
|
/* The navigation slab is not a control and does not take a control's height:
|
|
169
|
-
MEASURED at 65px with a 30px bottom radius at 1440
|
|
170
|
-
|
|
190
|
+
MEASURED at 65px with a 30px bottom radius at 1440 and 57px at the narrow width,
|
|
191
|
+
inset 40px from each side of the viewport and 12px below 40rem. That inset is the
|
|
192
|
+
SLAB's, and it is not the page's gutter — the gutter is 80px at the same width. */
|
|
171
193
|
--slab-h: 65px;
|
|
172
194
|
--slab-h-sm: 57px;
|
|
173
195
|
--r-slab: 30px;
|
|
@@ -204,6 +226,13 @@
|
|
|
204
226
|
--t-display-mid: 4.5rem; /* 72px from 40rem */
|
|
205
227
|
--t-display-sm: 4rem; /* 64px below 40rem */
|
|
206
228
|
|
|
229
|
+
/* The reference holds its lede in a grid column and sets `max-width: none` on both
|
|
230
|
+
the headline and the paragraph, so these two are a PACK DECISION rather than a
|
|
231
|
+
measurement: the measure the reference implies, stated in `ch` so it survives the
|
|
232
|
+
face substitution below. */
|
|
233
|
+
--measure-lede: 62ch;
|
|
234
|
+
--measure-body: 68ch;
|
|
235
|
+
|
|
207
236
|
--lh-display: 1.1; /* MEASURED — 88px on 80px */
|
|
208
237
|
--lh-body: 1.4; /* MEASURED — 22.4px on 16px */
|
|
209
238
|
--lh-ui: 1.5;
|
|
@@ -230,7 +259,12 @@
|
|
|
230
259
|
--dur-fast: 0.15s; /* a colour, a border or an opacity */
|
|
231
260
|
--dur-base: 0.2s; /* MEASURED — 23 elements */
|
|
232
261
|
--dur-slow: 0.3s; /* MEASURED — 9 elements, a disclosure opening */
|
|
233
|
-
|
|
262
|
+
/* MEASURED, and the two halves of the measurement disagree by 60ms: the reference
|
|
263
|
+
DECLARES `--enter-duration` as .6s, .64s and .68s across three sections, while the
|
|
264
|
+
transition on the 19 entering elements COMPUTES 0.7s. The pack ships the declared
|
|
265
|
+
middle value, because that is the number the reference's own author chose and the
|
|
266
|
+
0.7s is one section's instance of it. */
|
|
267
|
+
--dur-enter: 0.64s;
|
|
234
268
|
--stagger: 60ms; /* MEASURED — its enter-delay steps 0, 40, 60, 80, 120ms */
|
|
235
269
|
--enter-y: 16px; /* MEASURED — the entrance travels 8px or 16px, never further */
|
|
236
270
|
|
|
@@ -294,6 +328,10 @@
|
|
|
294
328
|
a muted icon here anyway, because its role is set by the light block. */
|
|
295
329
|
--ink-faint: #9693a3;
|
|
296
330
|
--on-ink: #150079;
|
|
331
|
+
/* A card on this surface stays WHITE — that is the measurement — so these two do NOT
|
|
332
|
+
invert with the field. They are the light block's values, and that is the point. */
|
|
333
|
+
--on-surface: #1a182b; /* 17.36:1 on --surface */
|
|
334
|
+
--on-surface-soft: #716f7e; /* 4.91:1 on --surface */
|
|
297
335
|
|
|
298
336
|
--accent: #d2c6ff; /* 10.14:1 on --bg — SELECTED, the reference's own on-dusk eyebrow */
|
|
299
337
|
--on-accent: #150079; /* 10.14:1 on --accent */
|
|
@@ -307,8 +345,12 @@
|
|
|
307
345
|
--hairline-quiet: color-mix(in srgb, #ffffff 15%, var(--bg));
|
|
308
346
|
|
|
309
347
|
--focus-color: #bcaaff; /* 7.90:1 on --bg, over the 3:1 mark floor */
|
|
310
|
-
|
|
311
|
-
|
|
348
|
+
/* MEASURED — the reference's on-dusk focus outline is its purple-400, and it is a
|
|
349
|
+
token here so the ring below derives from something rather than from a loose hex.
|
|
350
|
+
Literal first, derived in the `@supports` block, for the reason stated above. */
|
|
351
|
+
--focus-ring-base: #8b6cff;
|
|
352
|
+
--focus-ring: 0 0 0 3px rgba(139, 108, 255, 0.5);
|
|
353
|
+
--focus-ring-field: 0 0 0 3px rgba(139, 108, 255, 0.4);
|
|
312
354
|
--gradient-word-fallback: #d2c6ff; /* 10.14:1 on --bg */
|
|
313
355
|
|
|
314
356
|
/* DERIVED, and remapped rather than inherited: the light set measures 2.6-4.1:1 on
|
|
@@ -343,6 +385,22 @@
|
|
|
343
385
|
}
|
|
344
386
|
}
|
|
345
387
|
|
|
388
|
+
/* THE LITERALS ABOVE ARE THE FALLBACK, AND THEY ONLY WORK FROM IN HERE. The derived
|
|
389
|
+
form tracks the accent — change `--accent` and the ring follows — which is what a
|
|
390
|
+
literal cannot do; the literal exists so that a browser without `color-mix()` still
|
|
391
|
+
paints a ring at all. Both fields get one. */
|
|
392
|
+
@supports (color: color-mix(in srgb, red, red)) {
|
|
393
|
+
:root {
|
|
394
|
+
--focus-ring: 0 0 0 3px color-mix(in srgb, var(--accent) 50%, transparent);
|
|
395
|
+
--focus-ring-field: 0 0 0 3px color-mix(in srgb, var(--accent) 40%, transparent);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
[data-surface="dusk"] {
|
|
399
|
+
--focus-ring: 0 0 0 3px color-mix(in srgb, var(--focus-ring-base) 50%, transparent);
|
|
400
|
+
--focus-ring-field: 0 0 0 3px color-mix(in srgb, var(--focus-ring-base) 40%, transparent);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
346
404
|
/* Body copy here is weight 500 on 146 nodes, and an unset `font-weight` gives 400 —
|
|
347
405
|
one step light across the whole page. The UA's own 700 for `strong` and `b` is a
|
|
348
406
|
step the other way and lands on the display's heading weight, so emphasis is pinned
|
|
@@ -367,10 +425,15 @@ b {
|
|
|
367
425
|
/* PAGE — the page's own gutter, on the element a consumer never nests: a
|
|
368
426
|
container query here would ask a component's box how wide the page is. */
|
|
369
427
|
@media (min-width: 40rem) {
|
|
370
|
-
.dm-page { padding-inline: var(--
|
|
428
|
+
.dm-page { padding-inline: var(--gutter-2); }
|
|
371
429
|
}
|
|
372
|
-
/* PAGE —
|
|
373
|
-
@media (min-width:
|
|
430
|
+
/* PAGE — the middle step. */
|
|
431
|
+
@media (min-width: 48rem) {
|
|
432
|
+
.dm-page { padding-inline: var(--gutter-3); }
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/* PAGE — the wide step, and the value measured at 1440. */
|
|
436
|
+
@media (min-width: 64rem) {
|
|
374
437
|
.dm-page { padding-inline: var(--gutter-wide); }
|
|
375
438
|
}
|
|
376
439
|
|
|
@@ -486,15 +549,15 @@ b {
|
|
|
486
549
|
font-size: var(--t-h3);
|
|
487
550
|
font-weight: var(--weight-strong);
|
|
488
551
|
letter-spacing: var(--track-display);
|
|
489
|
-
color: var(--
|
|
552
|
+
color: var(--on-surface);
|
|
490
553
|
}
|
|
491
554
|
|
|
492
555
|
.dm-card__meta {
|
|
493
556
|
font-size: var(--t-sm);
|
|
494
|
-
color: var(--
|
|
557
|
+
color: var(--on-surface-soft);
|
|
495
558
|
}
|
|
496
559
|
|
|
497
|
-
.dm-card__body { color: var(--
|
|
560
|
+
.dm-card__body { color: var(--on-surface-soft); font-size: var(--t-body); line-height: var(--lh-body); max-width: var(--measure-body); }
|
|
498
561
|
|
|
499
562
|
/* ---- Chip ------------------------------------------------------------ */
|
|
500
563
|
.dm-chip {
|
|
@@ -508,7 +571,7 @@ b {
|
|
|
508
571
|
background-color: var(--surface);
|
|
509
572
|
font-size: var(--t-sm);
|
|
510
573
|
font-weight: var(--weight-body);
|
|
511
|
-
color: var(--
|
|
574
|
+
color: var(--on-surface);
|
|
512
575
|
transition: border-color var(--dur-fast) var(--ease);
|
|
513
576
|
}
|
|
514
577
|
|
|
@@ -617,7 +680,7 @@ b {
|
|
|
617
680
|
margin-bottom: var(--space-2);
|
|
618
681
|
font-size: var(--t-body);
|
|
619
682
|
font-weight: var(--weight-body);
|
|
620
|
-
color: var(--
|
|
683
|
+
color: var(--on-surface);
|
|
621
684
|
}
|
|
622
685
|
|
|
623
686
|
.dm-field__input {
|
|
@@ -632,11 +695,11 @@ b {
|
|
|
632
695
|
font-family: var(--font-body);
|
|
633
696
|
font-size: var(--t-body);
|
|
634
697
|
font-weight: var(--weight-regular);
|
|
635
|
-
color: var(--
|
|
698
|
+
color: var(--on-surface);
|
|
636
699
|
transition: border-color var(--dur-fast) var(--ease);
|
|
637
700
|
}
|
|
638
701
|
|
|
639
|
-
.dm-field__input::placeholder { color: var(--
|
|
702
|
+
.dm-field__input::placeholder { color: var(--on-surface-soft); }
|
|
640
703
|
|
|
641
704
|
.dm-field__input:focus-visible {
|
|
642
705
|
outline: none;
|
|
@@ -665,7 +728,7 @@ b {
|
|
|
665
728
|
font-size: var(--t-sm);
|
|
666
729
|
}
|
|
667
730
|
|
|
668
|
-
.dm-slab__brand { color: var(--
|
|
731
|
+
.dm-slab__brand { color: var(--on-surface); font-weight: var(--weight-strong); }
|
|
669
732
|
.dm-slab__nav { display: flex; gap: var(--space-2); margin-inline-end: auto; }
|
|
670
733
|
|
|
671
734
|
.dm-slab__nav a {
|
|
@@ -674,7 +737,7 @@ b {
|
|
|
674
737
|
min-height: var(--tap-min);
|
|
675
738
|
padding: var(--space-2) var(--space-3);
|
|
676
739
|
border-radius: var(--r-pill);
|
|
677
|
-
color: var(--
|
|
740
|
+
color: var(--on-surface);
|
|
678
741
|
text-decoration: none;
|
|
679
742
|
transition: background-color var(--dur-fast) var(--ease);
|
|
680
743
|
}
|
|
@@ -791,10 +854,10 @@ b {
|
|
|
791
854
|
font-size: var(--t-h3);
|
|
792
855
|
font-weight: var(--weight-strong);
|
|
793
856
|
letter-spacing: var(--track-display);
|
|
794
|
-
color: var(--
|
|
857
|
+
color: var(--on-surface);
|
|
795
858
|
}
|
|
796
859
|
|
|
797
|
-
.dm-qcard__body { color: var(--
|
|
860
|
+
.dm-qcard__body { color: var(--on-surface-soft); font-size: var(--t-body); line-height: var(--lh-body); }
|
|
798
861
|
|
|
799
862
|
/* The card's halves answer to the CARD's box, not to the screen: at 34rem of
|
|
800
863
|
container the artefact sits beside the sentence instead of under it. */
|
|
@@ -812,8 +875,8 @@ b {
|
|
|
812
875
|
text-align: center;
|
|
813
876
|
}
|
|
814
877
|
|
|
815
|
-
.dm-empty__title { margin: 0; font-size: var(--t-body); font-weight: var(--weight-body); color: var(--
|
|
816
|
-
.dm-empty__detail { margin: var(--space-2) 0 0; font-size: var(--t-body); color: var(--
|
|
878
|
+
.dm-empty__title { margin: 0; font-size: var(--t-body); font-weight: var(--weight-body); color: var(--on-surface); }
|
|
879
|
+
.dm-empty__detail { margin: var(--space-2) 0 0; font-size: var(--t-body); color: var(--on-surface-soft); }
|
|
817
880
|
.dm-empty__action { margin-top: var(--space-6); }
|
|
818
881
|
|
|
819
882
|
/* ---- Skeleton -------------------------------------------------------- */
|
|
@@ -108,8 +108,15 @@
|
|
|
108
108
|
--shadow-hair: 0 1px 0 0 color-mix(in srgb, var(--ink) 6%, transparent); /* MEASURED */
|
|
109
109
|
--shadow-lift: 0 32px 64px -24px color-mix(in srgb, var(--ink) 28%, transparent); /* MEASURED — once */
|
|
110
110
|
|
|
111
|
-
|
|
112
|
-
|
|
111
|
+
/* MEASURED, and declared LITERAL FIRST with the derived form in the `@supports` block
|
|
112
|
+
at the end of this file. The order is the guard, not a style: a custom property
|
|
113
|
+
accepts almost any token sequence, so a `color-mix()` value parses even where
|
|
114
|
+
`color-mix()` is unsupported and wins the cascade; it fails only at substitution, by
|
|
115
|
+
which point the literal is gone and `var(--focus-ring)` resolves to `unset` — an
|
|
116
|
+
invisible focus ring. Added 1.52.0; `showroom` is the pack that established the
|
|
117
|
+
mechanism and `deskmate` carries the same guard. */
|
|
118
|
+
--focus-ring: 0 0 0 4px rgba(5, 98, 239, 0.1),
|
|
119
|
+
0 4px 10px -3px rgba(5, 98, 239, 0.45);
|
|
113
120
|
--focus-w: 2px;
|
|
114
121
|
--focus-offset: 2px;
|
|
115
122
|
--focus-color: var(--accent); /* 5.25:1 on --bg, over the 3:1 mark floor */
|
|
@@ -262,6 +269,16 @@
|
|
|
262
269
|
}
|
|
263
270
|
}
|
|
264
271
|
|
|
272
|
+
/* THE LITERALS ABOVE ARE THE FALLBACK, AND THEY ONLY WORK FROM IN HERE. The derived form
|
|
273
|
+
tracks `--accent`; the literal exists so a browser without `color-mix()` still paints a
|
|
274
|
+
ring at all. The dark band inherits this ring, and its lighter accent with it. */
|
|
275
|
+
@supports (color: color-mix(in srgb, red, red)) {
|
|
276
|
+
:root {
|
|
277
|
+
--focus-ring: 0 0 0 4px color-mix(in srgb, var(--accent) 10%, transparent),
|
|
278
|
+
0 4px 10px -3px color-mix(in srgb, var(--accent) 45%, transparent);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
265
282
|
/* The pack bans bold, and a ban the UA overrides is not a ban: `strong` and `b` are 700
|
|
266
283
|
by default in every browser. 500 is the heaviest weight this page spends at scale, so
|
|
267
284
|
emphasis here is the medium weight — or, better, the mono. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sheleg-design-skill",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.52.0",
|
|
4
4
|
"description": "Design taste as an installable agent skill. Cinematic scroll-driven landing pages built on one scroll clock and layered degrade-to-calm motion, a motion doctrine that decides whether to animate before it decides how, three calibration dials, and thirty-six locked style packs with ready-made design tokens — instrument-console, editorial-luxury, workbench, briefing-room, atrium, orchard, outrank, babylove, patchbay, nameplate, field-notes, cyclorama, showroom, blueprint, prism, maquette, scoreboard, datasheet, manpage, pigeonhole, roster, ora, tenor, paperclip, ledger, router, daylight, notation, almanac, vitrine, proscenium, awning, bulletin, rimlight, onionskin and deskmate. Colour, slop and fork-reciprocity gates run as scripts, not opinions. Works with Cursor, Claude Code and any agent that reads a SKILL.md.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"sheleg-design-skill": "bin/cli.js"
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"type": "git",
|
|
54
54
|
"url": "git+https://github.com/ssheleg/sheleg-design-skill.git"
|
|
55
55
|
},
|
|
56
|
-
"homepage": "https://
|
|
56
|
+
"homepage": "https://skills.sshlg.me/skills/sheleg-design/",
|
|
57
57
|
"bugs": {
|
|
58
58
|
"url": "https://github.com/ssheleg/sheleg-design-skill/issues"
|
|
59
59
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "sheleg-design",
|
|
3
3
|
"displayName": "SHELEG Design",
|
|
4
4
|
"description": "SHELEG Design methodology: cinematic scroll-driven landing pages (single scroll clock, layered degrade-to-calm motion, WebGL particle formations), a motion doctrine that decides whether to animate before it decides how, and thirty-six pluggable visual style packs — instrument-console (dark console), editorial-luxury (warm editorial), workbench (light/dark product UI for dashboards and tools), briefing-room (dark 16:9 deck), atrium (warm consumer health), orchard, outrank, babylove (friendly consumer biotech), patchbay (a dark live schematic: one mint-cyan, 8% hairlines and no shadow, and an architecture diagram whose cords carry SMIL particles), field-notes (warm paper for dev tools sold on auditability), cyclorama (a pastel field on a 32s cycle), showroom (the product as the exhibit), blueprint (a drawing sheet, zero radius), prism (one iridescent wash over mono body), maquette (cream axonometric models on a dark table), scoreboard (warm paper, pixel numerals, a dark ledger of results), datasheet (an off-white spec sheet whose live instrument goes dark when it detects the reader is hiding), manpage (a developer landing page set in the reader's own system monospace on cream paper, with coral label chips that are real headings and a dark code frame as the argument), pigeonhole (a white sorting wall whose nine pastel categories are a filing scheme rather than a mood, each a two-layer chip whose label word is mandatory), roster (a white field in a faint grid of squares whose argument is other people's marks — client logotypes in pill-labelled industry columns, an engine's wordmark inside the headline — where the proof is a name rather than a number), ora (a warm coal field with cream ink and no third hue — the accent is the inverted field — a serif carrying every human sentence over a monospace carrying every machine fact, a terminal surface cut below the page, and a six-step verdict ramp, for products whose output is a machine's verdict about the reader), tenor (warm paper with zero radius and zero shadow, one hairline weight, an orange that exists only on hover and on focus, a sans tracked negative against a mono tracked positive, display at a line-height below one in an eight-to-twelve-character measure, and product proof delivered as silent looping video, for products arguing that a new kind of thing must be managed like an existing organisation), paperclip (neutral coal with no functional colour at all — every control monochrome and elevation made of hairlines, with the whole chromatic budget spent on a curtain of gradient capsules and twelve gradient section badges that cannot be clicked — for products that ask a person to run something that runs itself: agent teams, autonomous back-office, schedulers and budget-governed compute), ledger (warm cream paper ruled by a hairline at 12% ink and no shadow on any card, radius 15 nested concentrically, an ink primary button and a terracotta accent that never fills a control — it labels, as a 10px monospace uppercase kicker — with a seal on every card stating how its number is known, for the console of a product that answers questions about data: AI analysts, BI surfaces, query workspaces), router (a near-white field with a trace of blue and white cards standing on it, hairline seams instead of shadows anywhere, body at 14px and weight 450, and a status triplet in which the colour you paint with is not the colour you write with, for product consoles and the landing pages that have to look like them), daylight (a cool near-white portal field with generous radii and one very large soft shadow spent on a single object per screen, for client portals), notation (a near-white page drawn entirely in hairlines with a light serif over a monospace, no bold anywhere and an ink primary, for developer products sold on restraint), almanac (oatmeal paper with 2px seams and no 1px anywhere, a display set below a line-height of one, and mono tags notched through drawn boxes, for pages that assert a category), vitrine (a white hairline field with a serif display, an ink primary and one framed record carrying the evidence, for the front door of a product sold on trust). Ships the sheleg-design skill, the architecture reference, the motion doctrine, the Figma and Claude Design bridges, AI-surface patterns, style packs with ready-made token CSS, and the /sheleg-design command, and awning (a white forecourt where the accent is black and no hue reaches the chrome at all, a pill whose radius is a declared component token, one variable grotesque at 420/550 with no 700, and a single three-layer shadow, for commerce and platform front doors), and proscenium (a white field carrying two cool acts and one deep indigo act at the middle, an electric violet filling a control that stays nearly square at 4px against cards at 16, one family at nine weights, and a framed product panel the fold cuts off, for product-led marketing front doors whose argument is a demonstration), and bulletin (warm cream paper cut by flat pastel bands, every card and control a 1px ink outline standing on a hard zero-blur ink offset it travels into when pressed, a display face at 800 inside controls and 700 in the headline, and no tracking at any size, for front doors whose argument is breadth), and nameplate (a cool near-white slab under a page that is square on 87% of its elements, where the one round shape is reserved for a white 1px-bordered pill carrying somebody else's publication name as type, one family with the body at weight 500, and two uppercase registers tracked 0.06em and 0.175em, for pages whose argument is that named third parties will vouch for you: press placement, trust marks, certification and review aggregation), and rimlight (a white field with a cool grey act separator and one near-black act, a grotesque for every sentence and a monospace for every piece of chrome, square on 84% of its elements and tracked negative at every size, whose only elevation is a sixteen-layer coloured light rig — six layers lit and ten held at alpha 0, thrown from below-left — for a studio's own front door and the pages that sell what it makes), and onionskin (a white technical sheet at 96.5% zero radius — the squarest page in the library — where two bases do all the work and everything quiet is one of them at an alpha: text dims through the ink, structure dims through a navy that is never a word, over a dot grid with dashed hairlines and three faces at an 11px working size, for developer and AI infrastructure whose front page is a working document), and deskmate (a warm beige working day lit from one source above the top edge, where a single four-stop ramp — peach, lilac, violet, deep navy — washes the field, fills a panel and fills one word of a heading, everything a hand touches is a pill at 56px and everything else a 32px slab, elevation is a field step with two shadows on a 10,211px page, and the set piece is a framed transcript whose quoted chat client keeps its own face, ink and status colours under a --quoted-* namespace, for products sold as a colleague rather than a tool: AI employees and chat-native agents).",
|
|
5
|
-
"version": "1.
|
|
5
|
+
"version": "1.52.0",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "ssheleg",
|
|
8
8
|
"url": "https://x.com/sshlg93"
|
|
@@ -3,7 +3,7 @@ name: sheleg-design
|
|
|
3
3
|
description: Use when deciding how something LOOKS or MOVES — cinematic landing pages and hero sections, particle/WebGL backgrounds, scroll-linked or scrubbed motion, layers that drift, dashboards, admin or internal tools, mobile screens, chat or agent interfaces, tokens, themes, palettes, typography and the Figma border. Triggers include "design a landing" / "дизайн лендинга", "build a landing page" / "сделай лендинг", "scroll animation" / "скролл-анимация", "dashboard style" / "стиль дашборда", "design tokens, style pack" / "дизайн-токены", "light/dark theme" / "светлая/тёмная тема", "figma variables" / "переменные фигмы, фигма в код", "mobile screen" / "мобильный экран", "palette, colors" / "палитра, цвета", "typography, font" / "типографика, шрифт", "how it looks, make it prettier" / "выглядит, красиво, красивее", "visual reference" / "визуальные референсы", "investor deck" / "презентация". Not for structure, copy or backend behavior.
|
|
4
4
|
license: MIT
|
|
5
5
|
metadata:
|
|
6
|
-
version: 1.
|
|
6
|
+
version: 1.52.0
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# SHELEG Design
|
|
@@ -154,8 +154,8 @@ as a definition of done, in that order:
|
|
|
154
154
|
before writing CSS for a cinematic page. A scene has planes; everything on one
|
|
155
155
|
plane is the failure no amount of easing repairs.
|
|
156
156
|
- **Charts — hand the pack to `dataviz`** (same file), before drawing a chart in
|
|
157
|
-
any pack. Token names are not uniform across the
|
|
158
|
-
`--ink` resolve
|
|
157
|
+
any pack. Token names are not uniform across the thirty-six packs — only `--bg`
|
|
158
|
+
and `--ink` resolve in every one — and an undefined custom property does not error,
|
|
159
159
|
it silently falls back. Guessing one is the quietest way to ship a wrong chart.
|
|
160
160
|
- **Mobile surfaces** ([`MOBILE_SURFACES.md`](./MOBILE_SURFACES.md)), when the
|
|
161
161
|
brief is a native app screen or a mobile-web view — not a desktop page whose
|
|
@@ -60,10 +60,13 @@ the runnable palette validation; a pack is the *parameter set* it consumes.
|
|
|
60
60
|
**Read the chosen pack's own token names before you write a single `var()`.**
|
|
61
61
|
This table is by *role*, not by token, because the names are not uniform across
|
|
62
62
|
the thirty-six packs: only `--bg` and `--ink` resolve in every pack. The accent is
|
|
63
|
-
`--accent` in
|
|
64
|
-
|
|
63
|
+
`--accent` in thirty-three of the thirty-six packs; the other three name it themselves —
|
|
64
|
+
`--brand` in `babylove` and `field-notes`, `--cta` in `orchard` — and each declares
|
|
65
|
+
`@role accent:` in its token layer, which is the marker to read rather than the name.
|
|
66
|
+
(`roster` also ships a `--cta`, beside its `--accent`: that one is a component slot, not
|
|
67
|
+
the accent role, and the missing `@role accent:` marker is what says so.) **A second marker joins it in 1.26.0:**
|
|
65
68
|
a semantic colour that sits below WCAG AA on its own field declares
|
|
66
|
-
`@role non-text:` with the reason and the ratio, because
|
|
69
|
+
`@role non-text:` with the reason and the ratio, because twenty-three of the token layers
|
|
67
70
|
carry such a colour and each said so in a different phrasing — "never text on the field",
|
|
68
71
|
"a FILL and large-text colour", "a fill, not a text colour", "No coral word under 24px",
|
|
69
72
|
"category marks" — which is exactly why nothing could check it.
|
|
@@ -52,8 +52,9 @@ appears zero times in 364,905 bytes and exactly one element is fixed — so
|
|
|
52
52
|
`MOTION_INTENSITY` above **4** has nothing legal to buy here.
|
|
53
53
|
|
|
54
54
|
**Not for:** dense operator chrome. The elevation model is a field step and a 1.25px
|
|
55
|
-
hairline, the smallest radius
|
|
56
|
-
fourth nested panel has nothing to sit on and a toolbar of pills
|
|
55
|
+
hairline, the smallest radius in the ramp is 8.4px, and a control is 56px tall or 44px
|
|
56
|
+
at the small size — a fourth nested panel has nothing to sit on and a toolbar of pills
|
|
57
|
+
is a novelty item. That
|
|
57
58
|
is `workbench`'s half, and `router`'s. Not for regulated, clinical or public-sector
|
|
58
59
|
pages, where a peach-to-violet bleed under the fold reads as a consumer app. Not for
|
|
59
60
|
anything sold on austerity: this page spends 38 gradient fills, and a pack that spends
|
|
@@ -94,8 +95,10 @@ ramp that hangs is this one.
|
|
|
94
95
|
|
|
95
96
|
## Palette
|
|
96
97
|
|
|
97
|
-
Copy [`tokens/deskmate.css`](./tokens/deskmate.css) verbatim. Every
|
|
98
|
-
its provenance — MEASURED, SELECTED or DERIVED — and its ratio.
|
|
98
|
+
Copy [`tokens/deskmate.css`](./tokens/deskmate.css) verbatim. Every **colour** there
|
|
99
|
+
carries its provenance — MEASURED, SELECTED or DERIVED — and its ratio. The geometry
|
|
100
|
+
ramps (spacing, radii, type sizes) carry a provenance note per band rather than per
|
|
101
|
+
value, because a band was measured as a band.
|
|
99
102
|
|
|
100
103
|
| Role | Token | Value | On `--bg` |
|
|
101
104
|
|---|---|---|---|
|
|
@@ -109,6 +112,16 @@ its provenance — MEASURED, SELECTED or DERIVED — and its ratio.
|
|
|
109
112
|
| Eyebrow | `--accent-deep` | `#4e32b5` | 7.93:1 |
|
|
110
113
|
| Warm stop | `--peach` | `#ffbb98` | 1.51:1 — declared non-text, a stop and a star |
|
|
111
114
|
| Last stop | `--dusk` | `#150079` | 14.83:1 — and the dusk surface's own field |
|
|
115
|
+
| On a card | `--on-surface` | `#1a182b` | 17.36:1 on `--surface`, and it does NOT invert |
|
|
116
|
+
| On a card, quiet | `--on-surface-soft` | `#716f7e` | 4.91:1 on `--surface` |
|
|
117
|
+
|
|
118
|
+
**`--ink` is for words on `--bg`; `--on-surface` is for words on a card.** On the light
|
|
119
|
+
field the two are the same value and the distinction reads as decoration. On the dusk
|
|
120
|
+
surface it is the whole difference: `--surface` stays white there — measured on
|
|
121
|
+
`/business`, where a card inside an inverted section keeps its white fill — so a card
|
|
122
|
+
that paints its heading in `--ink` paints **white on white**. Every component that sits
|
|
123
|
+
on a card takes the `--on-surface` pair, and the four that sit on the field
|
|
124
|
+
(the display, the lede, a stat's figure, a section's own heading) take `--ink`.
|
|
112
125
|
|
|
113
126
|
**One accent, and it needed no correction.** It writes and it fills: `#6e47ff` is
|
|
114
127
|
4.84:1 on the field `#faf5f1`, and `#ffffff` on `#6e47ff` is 5.24:1. A single token
|
|
@@ -174,8 +187,8 @@ is quoting a different library.
|
|
|
174
187
|
|
|
175
188
|
**A measure in `ch`, and the reference has none.** It holds its lede in a grid column
|
|
176
189
|
rather than in a measure — `max-width: none` on both the headline and the paragraph — so
|
|
177
|
-
this pack states the measure the reference implies
|
|
178
|
-
body
|
|
190
|
+
this pack states the measure the reference implies and ships it as
|
|
191
|
+
`--measure-lede` (62ch) and `--measure-body` (68ch), against Gellix at 16px. Where the two faces are substituted the
|
|
179
192
|
column holds and the character count moves, which is the point of stating it in `ch`.
|
|
180
193
|
|
|
181
194
|
**Both brand faces are licensed and the substitutes are a pack decision.** Ulm Grotesk
|
|
@@ -191,8 +204,11 @@ library's own rule.
|
|
|
191
204
|
**Elevation is a field step.** 68 white fills sit on a beige field with 51 hairlines
|
|
192
205
|
between them, and the entire 10,211px page carries **two** shadows, which is why the
|
|
193
206
|
pack ships exactly two shadow tokens and no ramp: `--shadow-panel` is the 5% whisper
|
|
194
|
-
under the signature frame (`0 3.863px 17.769px`) and `--glow-bloom` is the
|
|
195
|
-
bloom
|
|
207
|
+
under the signature frame (`0 3.863px 17.769px`), and `--glow-bloom` is the single purple
|
|
208
|
+
bloom (`0 0 16px 8px` of purple-900 at 8%) that the reference spends **once on the whole
|
|
209
|
+
page**. The pack does not prescribe where — the census records one instance and not which
|
|
210
|
+
element carried it — so the rule is the count: one bloom per page, on the object the page
|
|
211
|
+
is about, and if you cannot name that object do not spend it. A card is white on beige; a
|
|
196
212
|
panel inside a card is beige on white; the third step is a hairline and there is no
|
|
197
213
|
fourth.
|
|
198
214
|
|
|
@@ -253,9 +269,10 @@ grid:
|
|
|
253
269
|
- The **message half** takes `--gradient-dusk`, white text, a byline row (a name, a small
|
|
254
270
|
`APP` badge, a time), and under it an illustration of the artefact produced — a file
|
|
255
271
|
tile, a set of connected tool marks, a checklist. Radius `--r-card` on the top corners.
|
|
256
|
-
- The **explanation half** is `--surface`, a 24px heading in `--
|
|
257
|
-
in `--
|
|
258
|
-
corners.
|
|
272
|
+
- The **explanation half** is `--surface`, a 24px heading in `--on-surface` and a 16px
|
|
273
|
+
paragraph in `--on-surface-soft`, with 24px/32px/32px of padding. Radius `--r-card` on
|
|
274
|
+
the bottom corners. Those two tokens rather than `--ink`: a card keeps its white fill
|
|
275
|
+
inside a dusk section, so the ink that sits on it cannot invert with the field.
|
|
259
276
|
- No border and no shadow on either half; the two fills are the separation.
|
|
260
277
|
- The small tile — a chip, a logo, a status row — is `--surface` at `--r-chip` with a
|
|
261
278
|
`--rule-w` hairline at the ink's 5% and 10px of padding.
|
|
@@ -299,8 +316,8 @@ would be the liveliest thing on it.
|
|
|
299
316
|
**Empty states.** The reference's is a measured refusal, not an absence: a search on
|
|
300
317
|
`/integrations` matching nothing collapses the grid to 1280×0 at 1440 and says nothing at
|
|
301
318
|
all — no message, no count, no reset. The pack's answer is a `--surface` card at
|
|
302
|
-
`--r-card` holding a 16px/500 line in `--
|
|
303
|
-
secondary pill that clears the filter. An empty result is a state, and a state that
|
|
319
|
+
`--r-card` holding a 16px/500 line in `--on-surface`, one sentence in
|
|
320
|
+
`--on-surface-soft`, and a secondary pill that clears the filter. An empty result is a state, and a state that
|
|
304
321
|
paints nothing is indistinguishable from a broken query.
|
|
305
322
|
|
|
306
323
|
Every interactive element takes `--tap-min` (44px) as a height floor. This is a
|
|
@@ -312,8 +329,10 @@ the navigation toggle at 48×32 and the transcript's reaction pills at 42×24.
|
|
|
312
329
|
A marketing opening: full width, not full height, and it ends in the set piece rather
|
|
313
330
|
than beginning with it.
|
|
314
331
|
|
|
315
|
-
- The page holds `--page-max` (90rem)
|
|
316
|
-
|
|
332
|
+
- The page holds `--page-max` (90rem) and its gutter steps through four tokens —
|
|
333
|
+
`--gutter` 20px, `--gutter-2` 40px, `--gutter-3` 56px, `--gutter-wide` 80px — because a
|
|
334
|
+
step a consumer cannot reach through a variable is a step the pack did not ship. The
|
|
335
|
+
hero's own top padding is 176px at 1440, because the navigation slab hangs into it.
|
|
317
336
|
- Field `--bg` with `--gradient-dawn` blooming from above the headline, and the slab's
|
|
318
337
|
bottom corners rounded at `--r-section` where the field bleeds into `--gradient-fold`.
|
|
319
338
|
- A two-column grid at `1.15fr / 1fr` with a 56px gap: **the argument on the left, the
|
|
@@ -346,8 +365,10 @@ Three widths, measured: 1440, 768 and the sub-640 branch read at 500.
|
|
|
346
365
|
collides its own ascenders at the awkward widths between the steps.
|
|
347
366
|
- **The hero grid collapses to one column** and its gap goes 56px → 32px. The control pair
|
|
348
367
|
goes full width at `--control-h`, which is how a 56px pill stays a 56px pill.
|
|
349
|
-
- **Gutters step 80 → 56 → 40 → 20px**
|
|
350
|
-
its height 65px → 57px
|
|
368
|
+
- **Gutters step 80 → 56 → 40 → 20px** through the four `--gutter*` tokens. The
|
|
369
|
+
navigation slab's own inset goes 40px → 12px and its height 65px → 57px — that inset is
|
|
370
|
+
the slab's and not the page's gutter, which is 80px at the same width. Section rhythm
|
|
371
|
+
halves: 112px → 56px.
|
|
351
372
|
- **The frame's radius does not scale.** 47.319px at 1440 and at 500, with the same 15px
|
|
352
373
|
inset — the concentric relationship is the object's identity and rescaling it makes the
|
|
353
374
|
frame read as a different component.
|
|
@@ -437,7 +458,9 @@ cards made of the same material.
|
|
|
437
458
|
a flicker.
|
|
438
459
|
- **Focus-visible:** the control's own border takes `--focus-color` **and** the ring
|
|
439
460
|
appears outside it. Both, always: the ring alone composites to `#b6a3ff` on white
|
|
440
|
-
`#ffffff`, which is 2.17:1, and that is why the border moves in the same state.
|
|
461
|
+
`#ffffff`, which is 2.17:1, and that is why the border moves in the same state. The
|
|
462
|
+
ring ships as a **literal first** and derives from the accent inside an `@supports`
|
|
463
|
+
block — see Gotchas, because getting that order wrong removes the ring entirely.
|
|
441
464
|
- **Disclosure row:** 62px tall at `--r-root`, transparent until focus, opening over
|
|
442
465
|
`--dur-slow`. The row's chevron rotates; the row does not.
|
|
443
466
|
- **Section reveal:** opacity and `--enter-y` on `--ease-out` over `--dur-enter`, with
|
|
@@ -519,3 +542,23 @@ nodes, `#1264a3` on `#e8f5fa` for a mention at 5.59:1, `#007c58` for an approval
|
|
|
519
542
|
for a decline rule. They ship under `--quoted-*` so a status dot cannot reach them by
|
|
520
543
|
accident. A page that lifts them into its own palette has adopted somebody else's design
|
|
521
544
|
system one token at a time.
|
|
545
|
+
|
|
546
|
+
**A card does not invert with the field, and painting its text in `--ink` is the trap.**
|
|
547
|
+
`--surface` is white on both blocks — measured, because a chat-client card inside an
|
|
548
|
+
inverted section is still a white card — while `--ink` inverts to `#ffffff` on the dusk
|
|
549
|
+
surface. A card whose heading takes `--ink` therefore renders white on white inside a
|
|
550
|
+
dusk section — `#ffffff` on `#ffffff` is 1.00:1 — and no gate can see it: both tokens are
|
|
551
|
+
legal, both clear their own field, and the pairing only exists at render time. That is what `--on-surface` and
|
|
552
|
+
`--on-surface-soft` are for, and it is why they do not invert. Found by reading this
|
|
553
|
+
pack's own kit on a dusk section, which is the second defect that render caught after the
|
|
554
|
+
secondary control painting white on white — the same mechanism, one component along.
|
|
555
|
+
|
|
556
|
+
**The focus ring is declared literal-first, and the order is the guard.** A custom
|
|
557
|
+
property accepts almost any token sequence, so `--focus-ring: color-mix(…)` parses even
|
|
558
|
+
where `color-mix()` is unsupported, wins the cascade, and fails only at substitution — by
|
|
559
|
+
which point the literal is gone and `var(--focus-ring)` resolves to `unset`. An invisible
|
|
560
|
+
focus ring is the one degradation this pack may not ship, so the literal sits in `:root`
|
|
561
|
+
and the derived form sits in an `@supports (color: color-mix(in srgb, red, red))` block at
|
|
562
|
+
the end of the layer. `showroom` is the pack that learned this first; this one copies its
|
|
563
|
+
mechanism rather than its syntax, because the derived form here is a mix rather than a
|
|
564
|
+
relative colour.
|
|
@@ -58,6 +58,13 @@
|
|
|
58
58
|
rules and it bars, and an icon that must be READ takes --ink-soft instead. */
|
|
59
59
|
--ink-faint: #9693a3;
|
|
60
60
|
--on-ink: #ffffff; /* 17.36:1 on --ink */
|
|
61
|
+
/* THE RULE THIS PACK CANNOT BE READ WITHOUT: --ink is for words on --bg, and
|
|
62
|
+
--on-surface is for words on --surface. On the light field the two are the same
|
|
63
|
+
value and the distinction looks decorative. On the dusk surface it is the whole
|
|
64
|
+
difference: --surface stays white there, measured, so a card that paints its text
|
|
65
|
+
in --ink paints white on white. Every component that sits on a card takes these. */
|
|
66
|
+
--on-surface: #1a182b; /* 17.36:1 on --surface */
|
|
67
|
+
--on-surface-soft: #716f7e; /* 4.91:1 on --surface */
|
|
61
68
|
|
|
62
69
|
/* ---- The accent: it writes, it fills, and it needed no correction ---- */
|
|
63
70
|
/* MEASURED. #6e47ff is the reference's purple-500 and its only functional accent:
|
|
@@ -121,9 +128,18 @@
|
|
|
121
128
|
/* MEASURED — `ring-3` is 3px, and the ring's alpha IS its specification: 50% behind
|
|
122
129
|
a control, 40% behind a field. Composited over white #ffffff the ring is
|
|
123
130
|
#b6a3ff at 2.17:1, which is why the control's own border moves colour in the
|
|
124
|
-
same state.
|
|
125
|
-
|
|
126
|
-
|
|
131
|
+
same state.
|
|
132
|
+
|
|
133
|
+
THE LITERAL IS HERE AND THE DERIVED FORM IS IN THE `@supports` BLOCK AT THE END OF
|
|
134
|
+
THIS FILE, and the order is not a style preference. A custom property accepts
|
|
135
|
+
almost any token sequence, so `--focus-ring: color-mix(…)` parses even where
|
|
136
|
+
`color-mix()` is unsupported and wins the cascade; the invalidity surfaces only
|
|
137
|
+
where it is substituted, as invalid-at-computed-value-time, and by then the literal
|
|
138
|
+
is gone and `var(--focus-ring)` resolves to `unset` — an INVISIBLE FOCUS RING, on
|
|
139
|
+
the one degradation this pack says it may not ship. `showroom` is the worked
|
|
140
|
+
example this copies. */
|
|
141
|
+
--focus-ring: 0 0 0 3px rgba(110, 71, 255, 0.5);
|
|
142
|
+
--focus-ring-field: 0 0 0 3px rgba(110, 71, 255, 0.4);
|
|
127
143
|
|
|
128
144
|
/* ---- Radii: a pill for the hand, a slab for the eye ----------------- */
|
|
129
145
|
/* MEASURED at 1440: 977 of 1,191 visible elements compute 0px, 52 take the 32px
|
|
@@ -160,14 +176,20 @@
|
|
|
160
176
|
--space-28: 112px; /* MEASURED — the section's own vertical rhythm */
|
|
161
177
|
|
|
162
178
|
--page-max: 90rem; /* 1440px — MEASURED */
|
|
163
|
-
|
|
164
|
-
|
|
179
|
+
/* MEASURED, and the ramp ships as four tokens rather than as a sentence: the page's
|
|
180
|
+
gutter steps 20 → 40 → 56 → 80 across the reference's own breakpoints, and a step a
|
|
181
|
+
consumer cannot reach through a variable is a step the pack did not ship. */
|
|
182
|
+
--gutter: 20px;
|
|
183
|
+
--gutter-2: 40px; /* from 40rem */
|
|
184
|
+
--gutter-3: 56px; /* from 48rem */
|
|
185
|
+
--gutter-wide: 80px; /* from 64rem, and the value at 1440 */
|
|
165
186
|
--control-h: 56px; /* MEASURED — the button and the field are the same height */
|
|
166
187
|
--control-h-sm: 40px; /* MEASURED — the navigation's own pair, and see --tap-min */
|
|
167
188
|
--control-px: 40px; /* MEASURED — 24px on the small size */
|
|
168
189
|
/* The navigation slab is not a control and does not take a control's height:
|
|
169
|
-
MEASURED at 65px with a 30px bottom radius at 1440
|
|
170
|
-
|
|
190
|
+
MEASURED at 65px with a 30px bottom radius at 1440 and 57px at the narrow width,
|
|
191
|
+
inset 40px from each side of the viewport and 12px below 40rem. That inset is the
|
|
192
|
+
SLAB's, and it is not the page's gutter — the gutter is 80px at the same width. */
|
|
171
193
|
--slab-h: 65px;
|
|
172
194
|
--slab-h-sm: 57px;
|
|
173
195
|
--r-slab: 30px;
|
|
@@ -204,6 +226,13 @@
|
|
|
204
226
|
--t-display-mid: 4.5rem; /* 72px from 40rem */
|
|
205
227
|
--t-display-sm: 4rem; /* 64px below 40rem */
|
|
206
228
|
|
|
229
|
+
/* The reference holds its lede in a grid column and sets `max-width: none` on both
|
|
230
|
+
the headline and the paragraph, so these two are a PACK DECISION rather than a
|
|
231
|
+
measurement: the measure the reference implies, stated in `ch` so it survives the
|
|
232
|
+
face substitution below. */
|
|
233
|
+
--measure-lede: 62ch;
|
|
234
|
+
--measure-body: 68ch;
|
|
235
|
+
|
|
207
236
|
--lh-display: 1.1; /* MEASURED — 88px on 80px */
|
|
208
237
|
--lh-body: 1.4; /* MEASURED — 22.4px on 16px */
|
|
209
238
|
--lh-ui: 1.5;
|
|
@@ -230,7 +259,12 @@
|
|
|
230
259
|
--dur-fast: 0.15s; /* a colour, a border or an opacity */
|
|
231
260
|
--dur-base: 0.2s; /* MEASURED — 23 elements */
|
|
232
261
|
--dur-slow: 0.3s; /* MEASURED — 9 elements, a disclosure opening */
|
|
233
|
-
|
|
262
|
+
/* MEASURED, and the two halves of the measurement disagree by 60ms: the reference
|
|
263
|
+
DECLARES `--enter-duration` as .6s, .64s and .68s across three sections, while the
|
|
264
|
+
transition on the 19 entering elements COMPUTES 0.7s. The pack ships the declared
|
|
265
|
+
middle value, because that is the number the reference's own author chose and the
|
|
266
|
+
0.7s is one section's instance of it. */
|
|
267
|
+
--dur-enter: 0.64s;
|
|
234
268
|
--stagger: 60ms; /* MEASURED — its enter-delay steps 0, 40, 60, 80, 120ms */
|
|
235
269
|
--enter-y: 16px; /* MEASURED — the entrance travels 8px or 16px, never further */
|
|
236
270
|
|
|
@@ -294,6 +328,10 @@
|
|
|
294
328
|
a muted icon here anyway, because its role is set by the light block. */
|
|
295
329
|
--ink-faint: #9693a3;
|
|
296
330
|
--on-ink: #150079;
|
|
331
|
+
/* A card on this surface stays WHITE — that is the measurement — so these two do NOT
|
|
332
|
+
invert with the field. They are the light block's values, and that is the point. */
|
|
333
|
+
--on-surface: #1a182b; /* 17.36:1 on --surface */
|
|
334
|
+
--on-surface-soft: #716f7e; /* 4.91:1 on --surface */
|
|
297
335
|
|
|
298
336
|
--accent: #d2c6ff; /* 10.14:1 on --bg — SELECTED, the reference's own on-dusk eyebrow */
|
|
299
337
|
--on-accent: #150079; /* 10.14:1 on --accent */
|
|
@@ -307,8 +345,12 @@
|
|
|
307
345
|
--hairline-quiet: color-mix(in srgb, #ffffff 15%, var(--bg));
|
|
308
346
|
|
|
309
347
|
--focus-color: #bcaaff; /* 7.90:1 on --bg, over the 3:1 mark floor */
|
|
310
|
-
|
|
311
|
-
|
|
348
|
+
/* MEASURED — the reference's on-dusk focus outline is its purple-400, and it is a
|
|
349
|
+
token here so the ring below derives from something rather than from a loose hex.
|
|
350
|
+
Literal first, derived in the `@supports` block, for the reason stated above. */
|
|
351
|
+
--focus-ring-base: #8b6cff;
|
|
352
|
+
--focus-ring: 0 0 0 3px rgba(139, 108, 255, 0.5);
|
|
353
|
+
--focus-ring-field: 0 0 0 3px rgba(139, 108, 255, 0.4);
|
|
312
354
|
--gradient-word-fallback: #d2c6ff; /* 10.14:1 on --bg */
|
|
313
355
|
|
|
314
356
|
/* DERIVED, and remapped rather than inherited: the light set measures 2.6-4.1:1 on
|
|
@@ -343,6 +385,22 @@
|
|
|
343
385
|
}
|
|
344
386
|
}
|
|
345
387
|
|
|
388
|
+
/* THE LITERALS ABOVE ARE THE FALLBACK, AND THEY ONLY WORK FROM IN HERE. The derived
|
|
389
|
+
form tracks the accent — change `--accent` and the ring follows — which is what a
|
|
390
|
+
literal cannot do; the literal exists so that a browser without `color-mix()` still
|
|
391
|
+
paints a ring at all. Both fields get one. */
|
|
392
|
+
@supports (color: color-mix(in srgb, red, red)) {
|
|
393
|
+
:root {
|
|
394
|
+
--focus-ring: 0 0 0 3px color-mix(in srgb, var(--accent) 50%, transparent);
|
|
395
|
+
--focus-ring-field: 0 0 0 3px color-mix(in srgb, var(--accent) 40%, transparent);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
[data-surface="dusk"] {
|
|
399
|
+
--focus-ring: 0 0 0 3px color-mix(in srgb, var(--focus-ring-base) 50%, transparent);
|
|
400
|
+
--focus-ring-field: 0 0 0 3px color-mix(in srgb, var(--focus-ring-base) 40%, transparent);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
346
404
|
/* Body copy here is weight 500 on 146 nodes, and an unset `font-weight` gives 400 —
|
|
347
405
|
one step light across the whole page. The UA's own 700 for `strong` and `b` is a
|
|
348
406
|
step the other way and lands on the display's heading weight, so emphasis is pinned
|
|
@@ -108,8 +108,15 @@
|
|
|
108
108
|
--shadow-hair: 0 1px 0 0 color-mix(in srgb, var(--ink) 6%, transparent); /* MEASURED */
|
|
109
109
|
--shadow-lift: 0 32px 64px -24px color-mix(in srgb, var(--ink) 28%, transparent); /* MEASURED — once */
|
|
110
110
|
|
|
111
|
-
|
|
112
|
-
|
|
111
|
+
/* MEASURED, and declared LITERAL FIRST with the derived form in the `@supports` block
|
|
112
|
+
at the end of this file. The order is the guard, not a style: a custom property
|
|
113
|
+
accepts almost any token sequence, so a `color-mix()` value parses even where
|
|
114
|
+
`color-mix()` is unsupported and wins the cascade; it fails only at substitution, by
|
|
115
|
+
which point the literal is gone and `var(--focus-ring)` resolves to `unset` — an
|
|
116
|
+
invisible focus ring. Added 1.52.0; `showroom` is the pack that established the
|
|
117
|
+
mechanism and `deskmate` carries the same guard. */
|
|
118
|
+
--focus-ring: 0 0 0 4px rgba(5, 98, 239, 0.1),
|
|
119
|
+
0 4px 10px -3px rgba(5, 98, 239, 0.45);
|
|
113
120
|
--focus-w: 2px;
|
|
114
121
|
--focus-offset: 2px;
|
|
115
122
|
--focus-color: var(--accent); /* 5.25:1 on --bg, over the 3:1 mark floor */
|
|
@@ -262,6 +269,16 @@
|
|
|
262
269
|
}
|
|
263
270
|
}
|
|
264
271
|
|
|
272
|
+
/* THE LITERALS ABOVE ARE THE FALLBACK, AND THEY ONLY WORK FROM IN HERE. The derived form
|
|
273
|
+
tracks `--accent`; the literal exists so a browser without `color-mix()` still paints a
|
|
274
|
+
ring at all. The dark band inherits this ring, and its lighter accent with it. */
|
|
275
|
+
@supports (color: color-mix(in srgb, red, red)) {
|
|
276
|
+
:root {
|
|
277
|
+
--focus-ring: 0 0 0 4px color-mix(in srgb, var(--accent) 10%, transparent),
|
|
278
|
+
0 4px 10px -3px color-mix(in srgb, var(--accent) 45%, transparent);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
265
282
|
/* The pack bans bold, and a ban the UA overrides is not a ban: `strong` and `b` are 700
|
|
266
283
|
by default in every browser. 500 is the heaviest weight this page spends at scale, so
|
|
267
284
|
emphasis here is the medium weight — or, better, the mono. */
|