sheleg-design-skill 1.25.0 → 1.27.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.
Files changed (34) hide show
  1. package/CHANGELOG.md +103 -6
  2. package/kits/atrium/src/styles.css +5 -0
  3. package/kits/blueprint/src/styles.css +5 -0
  4. package/kits/cyclorama/src/styles.css +3 -0
  5. package/kits/datasheet/src/styles.css +2 -0
  6. package/kits/editorial-luxury/.design-sync/conventions.md +6 -2
  7. package/kits/editorial-luxury/src/styles.css +1 -0
  8. package/kits/field-notes/src/styles.css +1 -0
  9. package/kits/manpage/src/styles.css +3 -0
  10. package/kits/maquette/src/styles.css +1 -0
  11. package/kits/orchard/src/styles.css +4 -0
  12. package/kits/prism/src/styles.css +5 -0
  13. package/kits/roster/src/styles.css +3 -0
  14. package/kits/scoreboard/src/styles.css +16 -0
  15. package/kits/showroom/src/styles.css +21 -4
  16. package/kits/workbench/src/styles.css +4 -0
  17. package/package.json +1 -1
  18. package/plugins/sheleg-design/.claude-plugin/plugin.json +1 -1
  19. package/plugins/sheleg-design/skills/sheleg-design/SKILL.md +1 -1
  20. package/plugins/sheleg-design/skills/sheleg-design/SURFACE_COMPOSITION.md +6 -1
  21. package/plugins/sheleg-design/skills/sheleg-design/styles/blueprint.md +9 -3
  22. package/plugins/sheleg-design/skills/sheleg-design/styles/editorial-luxury.md +16 -2
  23. package/plugins/sheleg-design/skills/sheleg-design/styles/showroom.md +10 -1
  24. package/plugins/sheleg-design/skills/sheleg-design/styles/tokens/atrium.css +4 -0
  25. package/plugins/sheleg-design/skills/sheleg-design/styles/tokens/blueprint.css +5 -0
  26. package/plugins/sheleg-design/skills/sheleg-design/styles/tokens/cyclorama.css +3 -0
  27. package/plugins/sheleg-design/skills/sheleg-design/styles/tokens/datasheet.css +2 -0
  28. package/plugins/sheleg-design/skills/sheleg-design/styles/tokens/manpage.css +3 -0
  29. package/plugins/sheleg-design/skills/sheleg-design/styles/tokens/orchard.css +3 -0
  30. package/plugins/sheleg-design/skills/sheleg-design/styles/tokens/prism.css +5 -0
  31. package/plugins/sheleg-design/skills/sheleg-design/styles/tokens/roster.css +3 -0
  32. package/plugins/sheleg-design/skills/sheleg-design/styles/tokens/scoreboard.css +16 -0
  33. package/plugins/sheleg-design/skills/sheleg-design/styles/tokens/showroom.css +6 -0
  34. package/plugins/sheleg-design/skills/sheleg-design/styles/tokens/workbench.css +4 -0
package/CHANGELOG.md CHANGED
@@ -1,6 +1,108 @@
1
1
  # Changelog
2
2
 
3
- ## 1.25.0 — 2026-08-13
3
+ All notable changes to this project are documented in this file. The format
4
+ follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions
5
+ follow [SemVer](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [1.27.0] - 2026-08-13
8
+
9
+ A ban that said "no side-stripe accent borders" was measured against a real consumer for
10
+ the first time, and it turned out to forbid the wrong thing. Narrowed to what it always
11
+ meant.
12
+
13
+ ### Changed
14
+
15
+ - **`editorial-luxury` — the side-stripe ban now says which stripe.** The bare wording
16
+ banned every `border-left` accent, and a production app on this pack has **42** of them.
17
+ Reading them one at a time is what settled it: four are 1px hairlines on code blocks and
18
+ TOC drawers, so not accents at all; three are `transparent`, reserving the gutter for a
19
+ **selected-state** marker; the remaining thirty-five are 2–3px rules on TEXT BLOCKS —
20
+ blockquotes, callouts, toasts, notices, log entries. That is the oldest editorial device
21
+ there is, and a pack whose display face is Fraunces and whose field is cream paper has no
22
+ business banning it. What the list actually collects is **ornament** — its neighbours are
23
+ gradient text, glassmorphism, outer glow and purple — so the ban now names the ornament:
24
+ the full-height accent rule down the side of a card, carrying no state and no semantic
25
+ role, put there to make the card look designed. The line to hold is stated with it: a
26
+ stripe must mean something, and must never be drawn in a colour nobody chose.
27
+
28
+ Why it matters beyond wording: a guard written to the literal reading fails on all 42
29
+ sites at once, and a gate nobody can satisfy is a gate that gets bypassed — so the
30
+ over-broad ban was buying zero enforcement while looking like doctrine.
31
+
32
+ ## [1.26.0] - 2026-08-13
33
+
34
+ The palette gate computed one contrast per theme — ink against field — and never once
35
+ asked whether a status colour could be read on the surface it sits on. Twenty-eight
36
+ findings in eleven of seventeen packs were waiting behind that.
37
+
38
+ ### Added
39
+
40
+ - **`validate_status_on_field()`** — every semantic colour is checked against the field
41
+ of **its own theme**, in three tiers, which is what the packs already argued and
42
+ nothing enforced:
43
+ - **≥ 4.5:1** — text, no declaration needed.
44
+ - **≥ 3.0:1** — declared `@role non-text:`, a mark that can be understood on its own.
45
+ - **< 3.0:1** — declared **and** the pack states status is never by colour alone,
46
+ because below the non-text floor the colour is reinforcement and the word is the
47
+ message.
48
+ - **`@role non-text:`, a second canonical role marker**, beside the `@role accent:` this
49
+ library already had. It is the whole point of the release: eleven packs *did* say their
50
+ status colours were not text — in five different phrasings ("never text on the field",
51
+ "a FILL and large-text colour", "a fill, not a text colour", "No coral word under
52
+ 24px", "category marks") — and a class nobody can grep for is a class nobody checks.
53
+ Documented in `SURFACE_COMPOSITION.md` beside the accent marker.
54
+ - Two plants, one per tier, and the check's core was split out so a plant can be a token
55
+ layer written as a string rather than an edit to a real file.
56
+
57
+ ### Fixed
58
+
59
+ - **`scoreboard`'s dark band inherited the paper status set** (board B-034). Its
60
+ `[data-surface="panel"]` block remapped eleven tokens — `--ink-soft` among them, for
61
+ exactly this reason — and left the four statuses pointing at the paper values, so
62
+ `var(--good)` painted **3.69:1** on that band while `--good-on-dark` had **10.21:1**
63
+ waiting three lines away in the same file. The pack has always said to use the on-dark
64
+ set there; now the token layer does it.
65
+ - **`showroom`'s status chip painted its label in its own status colour** (board B-021).
66
+ Measured against the fills the kit actually uses: `--good` **2.03:1**, `--warning`
67
+ **1.54:1**, `--danger` **2.65:1**, at the 12px the same row specifies. The label is
68
+ `--ink` now (14.65–14.73:1) and the status colour is the chip's tint plus a 6px dot —
69
+ which is the pack's own "never by colour alone" rule applied to the component that
70
+ exists to serve it. Corrected in the pack, the kit and with the numbers.
71
+ - **`validate.py` counted its own worktree.** Both of its ROOT markdown walks read every
72
+ `.md` under the repository, and this project's standing practice for a concurrent run is
73
+ an isolated worktree at `.claude/worktrees/<name>` — a full second copy of the tree. So
74
+ the gate reported **2361 checks** where the same commit measures **2067** clean, and the
75
+ ratchet in `floors.json` was one commit away from enshrining the inflated number. A floor
76
+ measured with a worktree present fails the next clean run for a regression that never
77
+ happened, and the failure names a count, not a cause. Nested checkouts are now excluded
78
+ by what they **are** — a directory carrying its own `.git` — not by name, because the name
79
+ is a convention and the next one will differ. The plant is the only one in this suite
80
+ whose pass condition is silence: a nested checkout must change neither the verdict nor the
81
+ count, and with the guard removed it reports `MISSED`.
82
+ - **`blueprint` answered separation and never legibility.** Its four category marks clear
83
+ every separation floor under all three dichromacies, which the pack said — and
84
+ `--good` **2.40:1**, `--warning` **1.72:1** and `--info` **1.21:1** on the stock, which
85
+ it did not. Its own advice, *"label them anyway, because a legend of four coloured
86
+ squares is a legend nobody reads"*, is now the requirement it always was.
87
+
88
+ ### Notes
89
+
90
+ - **Nothing else changed colour.** The other twenty-four findings are declarations: the
91
+ packs were right about their own colours and unreadable about it to a machine.
92
+ - Gates on the merged tree: `validate.py` 2067, palette **1001**, sloplint 450 — palette
93
+ 958 base + 8 from 1.25.0's status set + 35 from this check, additive with nothing hidden
94
+ in it. Floors raised with the reason.
95
+ - **This release is 1.26.0 because 1.25.0 was taken while it was being built.** Two runs
96
+ worked the repository at once and both bumped to the same number; the other reached
97
+ `origin/main`, its tag and npm first, so it keeps 1.25.0 and its entry above. Nothing was
98
+ discarded and nothing was rewritten — the collision cost this release a version number and
99
+ twenty-two version references in prose, each of which would otherwise have named a release
100
+ it is not in.
101
+ - The two remaining `scoreboard` rows (B-033, B-035, B-036) are untouched — a retracted
102
+ permission still live in its token layer, eight numbers that disagree with the values
103
+ beside them, and a pixel-numeral rule with no working mechanism outside WebKit.
104
+
105
+ ## [1.25.0] - 2026-08-13
4
106
 
5
107
  **`editorial-luxury` gets the status set it told surfaces to ask for.**
6
108
 
@@ -25,11 +127,6 @@ Also: `--dur-hover` and `--dur-state`. The pack said the product register stays
25
127
  in the fast range and never named the values, so every product surface built on
26
128
  it typed `0.15s` literals — there was nothing to reference.
27
129
 
28
-
29
- All notable changes to this project are documented in this file. The format
30
- follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions
31
- follow [SemVer](https://semver.org/spec/v2.0.0.html).
32
-
33
130
  ## [1.24.0] - 2026-08-13
34
131
 
35
132
  A seventeenth style pack, whose whole argument is other people's names — and a reference
@@ -24,6 +24,10 @@
24
24
  --accent-gradient: linear-gradient(#b05a36, rgba(216, 161, 131, 0.96));
25
25
 
26
26
  /* ---- Semantics (fills and icons — NOT text; see Gotchas) ------------- */
27
+ /* @role non-text: --good, --info — the pack has always said so in words ("fills and
28
+ icons only", "never carries a word"); this is the same statement in the one form a
29
+ gate can read. --good 2.11:1 and --info 3.41:1 on the field, and --danger 5.0:1 is
30
+ the one semantic here that may be text. */
27
31
  --good: #79bd8b; /* 2.1:1 on --bg — never carries a word */
28
32
  --good-tint: #f1f3e5;
29
33
  --info: #488ad5; /* 3.4:1 — large text / UI marks only */
@@ -175,6 +179,7 @@
175
179
  --marquee-cycle: 0s;
176
180
  }
177
181
  }
182
+
178
183
  /* ── components ── */
179
184
 
180
185
  /* Everything below consumes var(--…) only. Colour never appears as a literal:
@@ -55,6 +55,11 @@
55
55
  /* Every pair clears both separation floors under all three dichromacies, so
56
56
  no secondary-encoding declaration is required here. It is still good
57
57
  practice to label them; the pack asks for it without needing to. */
58
+ /* @role non-text: --good, --info, --warning — on a drawing sheet these four are
59
+ CATEGORY MARKS, not labels: a swatch, a rule, a chip fill. Measured on the field:
60
+ --good 2.40:1, --warning 1.72:1, --info 1.21:1. All three are under the 3:1 non-text
61
+ floor as well, so the word beside the mark is the message and the pack says status is
62
+ never by colour alone. */
58
63
  --good: #86af80;
59
64
  --info: #8bf6ff;
60
65
  --danger: #a440ce;
@@ -66,6 +66,9 @@
66
66
  #C56200 3.01:1 (large text only), 1.4 from --warning under protanopia
67
67
  There is no text-safe orange in this palette. That is a property of the
68
68
  reference, not a shortcut taken here. */
69
+ /* @role non-text: --accent, --info, --warning — the accent's own declaration has
70
+ always read "NEVER text on the field", and the two statuses render as a mark plus
71
+ their word. Measured: --accent 1.86:1, --warning 3.78:1, --info 4.13:1. */
69
72
  --accent: #ff8c00; /* fill / dot / chart series. NEVER text on the field */
70
73
  --accent-hover: #e69900; /* the accent's hover fill */
71
74
  --on-accent: #1a1a1a; /* 7.46:1 on --accent, 7.39:1 on --accent-hover */
@@ -53,6 +53,8 @@
53
53
  floor for a non-text mark and for large text (>=24px). Its measured jobs on
54
54
  the reference are exactly those: one word of a 48px headline, the mono
55
55
  visitor id, a 2px focus ring, a tick. It is never body copy. */
56
+ /* @role non-text: --accent — 3.17:1 on the field. This pack's accent is a fill, a
57
+ rule and an alarm tint; --accent-ink is what carries a word. */
56
58
  --accent: #f35b22; /* MEASURED — its --orange-7 */
57
59
  --accent-deep: #be400f; /* 5.11:1 on --bg — MEASURED (--orange-8): the one orange that may carry a word */
58
60
  --accent-wash: #ffeadc; /* MEASURED — selected cell, hovered row (--orange-2) */
@@ -29,8 +29,12 @@ inside a card.
29
29
 
30
30
  **Bans** (verbatim from the pack):
31
31
 
32
- - No gradient text, no side-stripe accent borders, no glassmorphism, no
33
- neon/outer-glow shadows, no purple.
32
+ - No gradient text, no glassmorphism, no neon/outer-glow shadows, no purple.
33
+ - No decorative accent stripe on a card (the full-height accent rule that carries no
34
+ state and no meaning). A 2-3px rule on a text block — quote, callout, notice — is an
35
+ editorial device and is allowed; it must mean something and must never be drawn in a
36
+ colour nobody chose. Narrowed 2026-08-13 after the literal reading was measured
37
+ against a consumer and failed on all 42 of its border-left rules.
34
38
  - No emojis in product UI; no Inter/system display fonts (Fraunces owns
35
39
  display).
36
40
  - Never flatten the cream identity into generic white; never let motion
@@ -75,6 +75,7 @@
75
75
  cross-pack document can name them truthfully. Alias, never a new colour. */
76
76
  --bg: var(--paper); /* role alias -> --paper, this pack's field */
77
77
  }
78
+
78
79
  /* ── components ── */
79
80
 
80
81
  /* Everything below consumes var(--…) only. The token block above is the whole
@@ -299,6 +299,7 @@
299
299
  --dur-marquee: 0s;
300
300
  }
301
301
  }
302
+
302
303
  /* ── components ── */
303
304
 
304
305
  /* Everything below consumes var(--…) only. Colour never appears as a literal:
@@ -53,6 +53,9 @@
53
53
  spends it on the wordmark, the button fill, a 12px label chip and a link.
54
54
  The chip and the link are the two that do not clear the floor; see
55
55
  --accent-ink, which is what this pack paints a word in. */
56
+ /* @role non-text: --accent, --action — 3.61:1 on cream, which is why the pack's own
57
+ Bans read "No coral word under 24px" and point at --accent-ink. The coral fills, it
58
+ rules, and it sets large type; it does not set a sentence. */
56
59
  --accent: #eb3514; /* MEASURED — its --color-coral, and its <meta name=theme-color> */
57
60
  --accent-ink: #660202; /* 11.59:1 on --bg — MEASURED (--color-burgundy): the accent that may carry a word */
58
61
  --accent-wash: #f0e0da; /* COMPOSITED — bg-coral/8 over --bg */
@@ -152,6 +152,7 @@
152
152
  --dur-slow: 0s;
153
153
  }
154
154
  }
155
+
155
156
  /* ── components ── */
156
157
 
157
158
  /* Everything below consumes var(--…) only. Colour never appears as a literal:
@@ -18,6 +18,9 @@
18
18
  --on-primary: #fffef4; /* only on --primary-deep, never on --primary */
19
19
 
20
20
  /* ---- Brand green ----------------------------------------------------- */
21
+ /* @role non-text: --primary, --cta — sage at 3.42:1 and the candy orange at 2.75:1
22
+ are fills and large-text colours, which both declarations already say; --primary-deep
23
+ is the text-safe green at 4.9:1. */
21
24
  --primary: #78934a; /* sage — 3.4:1 on --bg: a FILL and large-text colour */
22
25
  --primary-deep: #61783b; /* the text-safe green: 4.9:1 under --on-primary */
23
26
  --primary-light: #aaca73; /* the mark / illustration green */
@@ -126,6 +129,7 @@
126
129
  --reveal-floor: 1;
127
130
  }
128
131
  }
132
+
129
133
  /* ── components ── */
130
134
 
131
135
  /* Everything below consumes var(--…) only. Colour never appears as a literal:
@@ -38,6 +38,11 @@
38
38
  This pack does not propagate it: the cyan is a fill, a rule, a chart series
39
39
  and a mark. Ink on it is 8.02:1, which is what --on-accent is for. Where a
40
40
  heading needs the accent's family in text, it takes --accent-ink. */
41
+ /* @role non-text: --accent, --good, --info, --warning — an iridescent pack whose
42
+ status hues are mint, cyan and orange: --good 1.33:1, --accent 2.36:1, --info 2.36:1,
43
+ --warning 3.33:1 on the field. The pack already calls --good "a fill, not a text
44
+ colour"; the other three are the same kind. Three of the four are under the 3:1
45
+ non-text floor, so the word carries the meaning and the pack says so. */
41
46
  --accent: #00b3ff; /* FILL ONLY — 2.36:1 as text on --bg */
42
47
  --accent-hover: #0077ad;
43
48
  --accent-ink: #1493cc; /* 3.4:1 — large display text only, never body */
@@ -74,6 +74,9 @@
74
74
  /* Both of the reference's oranges fail AA as a text or label colour: white on #f25533
75
75
  is 3.43:1 at the nav pill's 16px/600, and #fa5c12 is 3.18:1 on white. The accent is
76
76
  therefore a FILL and a large-text colour; --accent-ink is what carries a word. */
77
+ /* @role non-text: --accent — 3.18:1 on the field, which is legal for the 68px
78
+ headline phrase as large text and for a fill, and illegal for anything smaller.
79
+ --accent-ink is what carries a word. */
77
80
  --accent: #fa5c12; /* MEASURED — the headline phrase and the gradient's head */
78
81
  /* The reference spends this on its nav fill AND on its eyebrows. The pack keeps it for
79
82
  the fill and overrides the eyebrow to --accent-ink, because at the eyebrow's 16px this
@@ -46,6 +46,9 @@
46
46
  non-text mark. The reference obeys this without saying so: its orange is a
47
47
  3x18 tick, a ::marker, a focus ring, a link underline and one oversized
48
48
  chevron. Its primary button is ink. See the pack's Palette. */
49
+ /* @role non-text: --accent — 3.23:1 on the paper. In this pack the accent "only
50
+ marks": a 3x18px tick, a chip edge, a rule. --accent-ink is the one that may carry a
51
+ word, and the 1.13.1 correction says no orange here may carry a link. */
49
52
  --accent: #ff4801;
50
53
  --accent-hover: #e03d00; /* 4.12:1 on --bg — the one orange that may carry a link */
51
54
  --accent-wash: #fff7ed; /* MEASURED — selected row, hovered cell */
@@ -228,6 +231,19 @@
228
231
  --action: #ffffff;
229
232
  --action-hover: #e4e4e7;
230
233
  --on-action: #0a0a0a;
234
+
235
+ /* The status set has to be remapped here, and until 1.26.0 it was not. The block
236
+ already remapped eleven tokens for exactly this reason -- --ink-soft among them --
237
+ and left --good, --warn, --danger and --info pointing at the paper values, so
238
+ `var(--good)` painted 3.69:1 on this band while --good-on-dark had 10.21 waiting
239
+ three lines away in the same file. The pack has always said to use the on-dark set
240
+ here; nothing made the token layer do it, because the palette gate checked ink
241
+ against field and never a status against field. validate_status_on_field() checks it
242
+ now, and this is the defect it was written for (board B-034). */
243
+ --good: #00d492; /* 10.21:1 on this band — was inheriting the paper value at 3.69 */
244
+ --warn: #ffb900; /* 11.49:1 — was 3.94 */
245
+ --danger: #ff637e; /* 6.92:1 — was 2.37 */
246
+ --info: #51a2ff; /* 7.51:1 — was 2.90 */
231
247
  }
232
248
 
233
249
  /* The reference ships no reduced-motion branch. This pack requires one: every
@@ -55,6 +55,12 @@
55
55
  deuteranopia — the classic pair, under the floor of 8. Legal only with the
56
56
  secondary encoding the pack declares: a status is a chip with a word in it,
57
57
  never a bare dot. */
58
+ /* @role non-text: --good, --warning, --danger — 2.33:1, 1.78:1 and 3.05:1 on the
59
+ field. Since 1.26.0 the status chip's LABEL is --ink and these three are the chip's
60
+ tint and its 6px dot; before that the label was painted in them, at 2.03, 1.54 and
61
+ 2.65 against the fills the kit actually uses. All three are at or under the 3:1
62
+ non-text floor, so the word is the message — which is what the pack's own "never by
63
+ colour alone" rule has always said. */
58
64
  --good: #0fc27b;
59
65
  --warning: #f5b900;
60
66
  --danger: #ff5b59;
@@ -243,10 +249,21 @@
243
249
 
244
250
  .sw-status { display: inline-flex; align-items: center; border-radius: var(--radius-sm);
245
251
  padding: 2px var(--space-2); font-family: var(--font-mono); font-size: var(--t-xs); }
246
- .sw-status--good { background-color: var(--accent-wash); color: var(--good); }
247
- .sw-status--warning { background-color: var(--surface-2); color: var(--warning); }
248
- .sw-status--danger { background-color: var(--surface-2); color: var(--danger); }
249
- .sw-status--neutral { background-color: var(--surface-2); color: var(--ink-soft); }
252
+ /* The label is --ink and the status colour is the dot. Until 1.26.0 the label WAS the
253
+ status colour, which measured 2.03:1 for good, 1.54 for warning and 2.65 for danger at
254
+ the 12px this chip is set in; --ink on the same fills is 14.65-14.73. The pack's own
255
+ "never by colour alone" rule is what the dot implements. */
256
+ .sw-status { color: var(--ink); gap: var(--space-1); }
257
+ .sw-status::before { content: ""; width: 6px; height: 6px; border-radius: 999px;
258
+ background-color: currentColor; }
259
+ .sw-status--good { background-color: var(--accent-wash); }
260
+ .sw-status--good::before { background-color: var(--good); }
261
+ .sw-status--warning { background-color: var(--surface-2); }
262
+ .sw-status--warning::before { background-color: var(--warning); }
263
+ .sw-status--danger { background-color: var(--surface-2); }
264
+ .sw-status--danger::before { background-color: var(--danger); }
265
+ .sw-status--neutral { background-color: var(--surface-2); }
266
+ .sw-status--neutral::before { background-color: var(--ink-soft); }
250
267
 
251
268
  .sw-col { display: flex; align-items: center; gap: var(--space-2); height: 36px; padding: 0 var(--space-4);
252
269
  border-bottom: 1px solid var(--line); font-size: var(--t-xs); color: var(--ink-soft);
@@ -9,6 +9,10 @@
9
9
  --muted: #5b6472;
10
10
  --border: #e6e9ef;
11
11
  --border-strong: #d7dce4;
12
+ /* @role non-text: --accent, --info — 4.30:1 in both themes, just under AA. The accent
13
+ fills buttons and marks selection and --accent-ink is the text that sits ON it;
14
+ --info deliberately IS the accent hue, for "running / working", and it is a dot and a
15
+ bar rather than a word. */
12
16
  --accent: #2f6feb;
13
17
  --accent-weak: #eaf0fe;
14
18
  --accent-ink: #ffffff; /* text ON the accent — 4.57:1 on --accent */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sheleg-design-skill",
3
- "version": "1.25.0",
3
+ "version": "1.27.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 seventeen locked style packs with ready-made design tokens — instrument-console, editorial-luxury, workbench, briefing-room, atrium, orchard, field-notes, cyclorama, showroom, blueprint, prism, maquette, scoreboard, datasheet, manpage, pigeonhole and roster. 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"
@@ -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 seventeen 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 (friendly consumer biotech), 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). 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.",
5
- "version": "1.25.0",
5
+ "version": "1.27.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 building or upgrading a cinematic scroll-driven landing page, marketing site or hero (particle/WebGL background, scroll-linked animation, parallax, scrubbed sections) — when such a page feels busy or janky or its motion layers drift out of sync — or when styling product UI with its style packs - dashboards, admin panels, internal/dev tools, mobile app screens, design tokens, light/dark themes - or when carrying a visual system across the Figma border (publishing tokens as variables, implementing a design without importing raw values). Triggers - "cinematic landing" / "кинематографичный лендинг", "scroll animation" / "скролл-анимация", "dashboard style" / "стиль дашборда", "design tokens" / "дизайн-токены", "light/dark theme" / "светлая/тёмная тема", "figma variables / figma to code" / "переменные фигмы, фигма в код", "chat/agent UI" / "интерфейс чата или агента", "streaming output" / "стриминг ответа", "mobile screen" / "мобильный экран".
4
4
  license: MIT
5
5
  metadata:
6
- version: 1.25.0
6
+ version: 1.27.0
7
7
  ---
8
8
 
9
9
  # SHELEG Design
@@ -61,7 +61,12 @@ the runnable palette validation; a pack is the *parameter set* it consumes.
61
61
  This table is by *role*, not by token, because the names are not uniform across
62
62
  the seventeen: only `--bg` and `--ink` resolve in every pack. The accent is
63
63
  `--accent` in fifteen, `--brand` in `field-notes` and `--cta` in `orchard` (each
64
- declares `@role accent:` in its token layer). Status colours are the least uniform
64
+ declares `@role accent:` in its token layer). **A second marker joins it in 1.26.0:**
65
+ a semantic colour that sits below WCAG AA on its own field declares
66
+ `@role non-text:` with the reason and the ratio, because eleven of the seventeen packs
67
+ had such a colour and each said so in a different phrasing — "never text on the field",
68
+ "a FILL and large-text colour", "a fill, not a text colour", "No coral word under 24px",
69
+ "category marks" — which is exactly why nothing could check it. Status colours are the least uniform
65
70
  thing in the library, so the full map is here rather than summarised: the pair
66
71
  `--ok` / `--warn` in `workbench` and `instrument-console`; the pair `--good` /
67
72
  `--warning` in `blueprint`, `cyclorama`, `maquette`, `prism` and `showroom`;
@@ -116,9 +116,15 @@ Three rules carry this palette.
116
116
  white. `validate_palette.py` now recomputes every stated ratio.)*
117
117
  - **These are category marks, not statuses.** The pack labels *kinds* — an index
118
118
  type, a tier, a language — not health. Every pair clears both separation floors
119
- under all three dichromacies, so no secondary-encoding declaration is required
120
- here; label them anyway, because a legend of four coloured squares is a legend
121
- nobody reads.
119
+ under all three dichromacies, so telling two marks apart is not the problem here.
120
+ - **And a mark is never by colour alone, because on this stock it cannot be.**
121
+ *Separation* and *legibility on the field* are different questions, and the pack
122
+ answered only the first until 1.26.0. Measured against `--bg`: `--good` **2.40:1**,
123
+ `--warning` **1.72:1**, `--info` **1.21:1** — all three under the 3:1 floor a mark
124
+ needs to be understood on its own (WCAG 1.4.11). So each mark carries its name, and
125
+ what used to be advice here — *"label them anyway, because a legend of four coloured
126
+ squares is a legend nobody reads"* — is the requirement. The three are declared
127
+ `@role non-text:` in the token layer, and `validate_status_on_field()` is what asked.
122
128
  - **`--ink-faint` is furniture.** At 2.5:1 it draws a grid line or a tick and
123
129
  never a word.
124
130
 
@@ -139,8 +139,22 @@ How this pack rides the SHELEG motion layer (brand register only):
139
139
  word carries the meaning in `--ink` (11.8:1 on every tint).
140
140
  *(Corrected 2026-08-10: this bullet was copy-pasted into six of the twelve and
141
141
  claimed a measurement across "several pairs" that one colour cannot form.)*
142
- - No gradient text, no side-stripe accent borders, no glassmorphism, no
143
- neon/outer-glow shadows, no purple.
142
+ - No gradient text, no glassmorphism, no neon/outer-glow shadows, no purple.
143
+ - **No decorative accent stripe on a card** — the full-height rule down the side of a
144
+ panel, in the accent, carrying no state and no semantic role, put there to make the
145
+ card look designed. That is the ornament this list is about, and its neighbours above
146
+ are the same kind of thing.
147
+ *(Narrowed 2026-08-13, and narrowed because the bare wording "no side-stripe accent
148
+ borders" was measured against a real consumer and found to ban the wrong thing.* A
149
+ production app on this pack had **42** `border-left` rules, and reading them one by one
150
+ is what settled it: four are 1px hairlines on code blocks and TOC drawers — not accents
151
+ at all; three are `transparent`, reserving the gutter for a **selected-state** marker;
152
+ the rest are 2–3px rules on TEXT BLOCKS — blockquotes, callouts, toasts, notices, log
153
+ entries — which is the oldest editorial device there is, and a pack whose display face
154
+ is Fraunces and whose field is cream paper has no business banning it. A guard written
155
+ to the literal reading failed on all 42, and a gate nobody can satisfy is a gate that
156
+ gets bypassed. **The line to hold:** a stripe must mean something — state, severity, or
157
+ "this block is quoted" — and must never be drawn in a colour nobody chose.)*
144
158
  - No emojis in product UI; no Inter/system display fonts (Fraunces owns
145
159
  display).
146
160
  - Never flatten the cream identity into generic white; never let motion
@@ -121,6 +121,15 @@ Three rules carry this palette.
121
121
  The reason there is one token is that 4.64:1 clears AA in the hardest role it
122
122
  takes (text), so the link, the focus ring and the filled button can share it
123
123
  with no "on-dark" variant. Do not add one.
124
+ - **[CORRECTION — 1.26.0] The chip's label is `--ink`, not its status colour.** Until
125
+ 1.26.0 this row read *"that status's ink"*, and the kit did what it said: the label was
126
+ painted in the status colour, which measures **2.03:1** for `--good` on
127
+ `--accent-wash`, **1.54:1** for `--warning` and **2.65:1** for `--danger` on
128
+ `--surface-2` — the pack's own status colours, unreadable at the 12px the same row
129
+ specifies. `--ink` on those fills is 14.65–14.73:1. The status colour keeps the tint
130
+ and gains a 6px dot, which is the *"never by colour alone"* rule below applied to the
131
+ component that exists to serve it. The three status tokens are declared
132
+ `@role non-text:` in the token layer as a result.
124
133
  - **Status is never by colour alone.** `--good` and `--danger` separate by 33.7 at
125
134
  full colour but only **4.9 under deuteranopia**, which is the classic pair and
126
135
  the one nobody catches by looking. Every status renders as a chip containing its
@@ -185,7 +194,7 @@ Measured off the reference unless a row says **pack decision**.
185
194
  | **Nav item** | transparent, `--radius-lg`, `0 12px`, 15px/500, `--ink-2` | fill → `--surface-2`, colour → `--ink` over `0.3s` | — | — |
186
195
  | **Specimen frame** | `--surface` fill, `--radius-3xl`, `--shadow-specimen`, a 3-dot title bar | none — it is an exhibit, not a control | — | — |
187
196
  | **Data row** | transparent on `--surface`, `1px --line-weak` bottom rule, 36px tall | fill → `--accent-wash` | fill → `--accent-wash`, left edge 2px `--accent` | — |
188
- | **Status chip** | tinted fill of its own status at ~12%, that status's ink, `--radius-sm`, `2px 8px`, 12px mono, **always with its word** | none | — | — |
197
+ | **Status chip** | tinted fill of its own status, **`--ink` as the label**, a 6px dot of the status colour before the word, `--radius-sm`, `2px 8px`, 12px mono, **always with its word** | none | — | — |
189
198
  | **Column header** | `--ink-soft`, 12px/500, an icon at 14px, `1px --line` bottom | fill → `--surface-2` | sorted: `--ink` plus a caret | — |
190
199
  | **Input** | `--surface`, `1px --line`, `--radius-lg`, `8px 12px`, **16px** Inter | border → `--line-strong` | focus: `--accent` border plus `--ring-focus` | `--disabled` text |
191
200
  | **Loader** | **pack decision:** a skeleton whose geometry matches the row it replaces — same height, same radius, `--surface-2` fill, no shimmer | — | — | — |
@@ -24,6 +24,10 @@
24
24
  --accent-gradient: linear-gradient(#b05a36, rgba(216, 161, 131, 0.96));
25
25
 
26
26
  /* ---- Semantics (fills and icons — NOT text; see Gotchas) ------------- */
27
+ /* @role non-text: --good, --info — the pack has always said so in words ("fills and
28
+ icons only", "never carries a word"); this is the same statement in the one form a
29
+ gate can read. --good 2.11:1 and --info 3.41:1 on the field, and --danger 5.0:1 is
30
+ the one semantic here that may be text. */
27
31
  --good: #79bd8b; /* 2.1:1 on --bg — never carries a word */
28
32
  --good-tint: #f1f3e5;
29
33
  --info: #488ad5; /* 3.4:1 — large text / UI marks only */
@@ -55,6 +55,11 @@
55
55
  /* Every pair clears both separation floors under all three dichromacies, so
56
56
  no secondary-encoding declaration is required here. It is still good
57
57
  practice to label them; the pack asks for it without needing to. */
58
+ /* @role non-text: --good, --info, --warning — on a drawing sheet these four are
59
+ CATEGORY MARKS, not labels: a swatch, a rule, a chip fill. Measured on the field:
60
+ --good 2.40:1, --warning 1.72:1, --info 1.21:1. All three are under the 3:1 non-text
61
+ floor as well, so the word beside the mark is the message and the pack says status is
62
+ never by colour alone. */
58
63
  --good: #86af80;
59
64
  --info: #8bf6ff;
60
65
  --danger: #a440ce;
@@ -66,6 +66,9 @@
66
66
  #C56200 3.01:1 (large text only), 1.4 from --warning under protanopia
67
67
  There is no text-safe orange in this palette. That is a property of the
68
68
  reference, not a shortcut taken here. */
69
+ /* @role non-text: --accent, --info, --warning — the accent's own declaration has
70
+ always read "NEVER text on the field", and the two statuses render as a mark plus
71
+ their word. Measured: --accent 1.86:1, --warning 3.78:1, --info 4.13:1. */
69
72
  --accent: #ff8c00; /* fill / dot / chart series. NEVER text on the field */
70
73
  --accent-hover: #e69900; /* the accent's hover fill */
71
74
  --on-accent: #1a1a1a; /* 7.46:1 on --accent, 7.39:1 on --accent-hover */
@@ -53,6 +53,8 @@
53
53
  floor for a non-text mark and for large text (>=24px). Its measured jobs on
54
54
  the reference are exactly those: one word of a 48px headline, the mono
55
55
  visitor id, a 2px focus ring, a tick. It is never body copy. */
56
+ /* @role non-text: --accent — 3.17:1 on the field. This pack's accent is a fill, a
57
+ rule and an alarm tint; --accent-ink is what carries a word. */
56
58
  --accent: #f35b22; /* MEASURED — its --orange-7 */
57
59
  --accent-deep: #be400f; /* 5.11:1 on --bg — MEASURED (--orange-8): the one orange that may carry a word */
58
60
  --accent-wash: #ffeadc; /* MEASURED — selected cell, hovered row (--orange-2) */
@@ -53,6 +53,9 @@
53
53
  spends it on the wordmark, the button fill, a 12px label chip and a link.
54
54
  The chip and the link are the two that do not clear the floor; see
55
55
  --accent-ink, which is what this pack paints a word in. */
56
+ /* @role non-text: --accent, --action — 3.61:1 on cream, which is why the pack's own
57
+ Bans read "No coral word under 24px" and point at --accent-ink. The coral fills, it
58
+ rules, and it sets large type; it does not set a sentence. */
56
59
  --accent: #eb3514; /* MEASURED — its --color-coral, and its <meta name=theme-color> */
57
60
  --accent-ink: #660202; /* 11.59:1 on --bg — MEASURED (--color-burgundy): the accent that may carry a word */
58
61
  --accent-wash: #f0e0da; /* COMPOSITED — bg-coral/8 over --bg */
@@ -18,6 +18,9 @@
18
18
  --on-primary: #fffef4; /* only on --primary-deep, never on --primary */
19
19
 
20
20
  /* ---- Brand green ----------------------------------------------------- */
21
+ /* @role non-text: --primary, --cta — sage at 3.42:1 and the candy orange at 2.75:1
22
+ are fills and large-text colours, which both declarations already say; --primary-deep
23
+ is the text-safe green at 4.9:1. */
21
24
  --primary: #78934a; /* sage — 3.4:1 on --bg: a FILL and large-text colour */
22
25
  --primary-deep: #61783b; /* the text-safe green: 4.9:1 under --on-primary */
23
26
  --primary-light: #aaca73; /* the mark / illustration green */
@@ -38,6 +38,11 @@
38
38
  This pack does not propagate it: the cyan is a fill, a rule, a chart series
39
39
  and a mark. Ink on it is 8.02:1, which is what --on-accent is for. Where a
40
40
  heading needs the accent's family in text, it takes --accent-ink. */
41
+ /* @role non-text: --accent, --good, --info, --warning — an iridescent pack whose
42
+ status hues are mint, cyan and orange: --good 1.33:1, --accent 2.36:1, --info 2.36:1,
43
+ --warning 3.33:1 on the field. The pack already calls --good "a fill, not a text
44
+ colour"; the other three are the same kind. Three of the four are under the 3:1
45
+ non-text floor, so the word carries the meaning and the pack says so. */
41
46
  --accent: #00b3ff; /* FILL ONLY — 2.36:1 as text on --bg */
42
47
  --accent-hover: #0077ad;
43
48
  --accent-ink: #1493cc; /* 3.4:1 — large display text only, never body */
@@ -74,6 +74,9 @@
74
74
  /* Both of the reference's oranges fail AA as a text or label colour: white on #f25533
75
75
  is 3.43:1 at the nav pill's 16px/600, and #fa5c12 is 3.18:1 on white. The accent is
76
76
  therefore a FILL and a large-text colour; --accent-ink is what carries a word. */
77
+ /* @role non-text: --accent — 3.18:1 on the field, which is legal for the 68px
78
+ headline phrase as large text and for a fill, and illegal for anything smaller.
79
+ --accent-ink is what carries a word. */
77
80
  --accent: #fa5c12; /* MEASURED — the headline phrase and the gradient's head */
78
81
  /* The reference spends this on its nav fill AND on its eyebrows. The pack keeps it for
79
82
  the fill and overrides the eyebrow to --accent-ink, because at the eyebrow's 16px this
@@ -46,6 +46,9 @@
46
46
  non-text mark. The reference obeys this without saying so: its orange is a
47
47
  3x18 tick, a ::marker, a focus ring, a link underline and one oversized
48
48
  chevron. Its primary button is ink. See the pack's Palette. */
49
+ /* @role non-text: --accent — 3.23:1 on the paper. In this pack the accent "only
50
+ marks": a 3x18px tick, a chip edge, a rule. --accent-ink is the one that may carry a
51
+ word, and the 1.13.1 correction says no orange here may carry a link. */
49
52
  --accent: #ff4801;
50
53
  --accent-hover: #e03d00; /* 4.12:1 on --bg — the one orange that may carry a link */
51
54
  --accent-wash: #fff7ed; /* MEASURED — selected row, hovered cell */
@@ -228,6 +231,19 @@
228
231
  --action: #ffffff;
229
232
  --action-hover: #e4e4e7;
230
233
  --on-action: #0a0a0a;
234
+
235
+ /* The status set has to be remapped here, and until 1.26.0 it was not. The block
236
+ already remapped eleven tokens for exactly this reason -- --ink-soft among them --
237
+ and left --good, --warn, --danger and --info pointing at the paper values, so
238
+ `var(--good)` painted 3.69:1 on this band while --good-on-dark had 10.21 waiting
239
+ three lines away in the same file. The pack has always said to use the on-dark set
240
+ here; nothing made the token layer do it, because the palette gate checked ink
241
+ against field and never a status against field. validate_status_on_field() checks it
242
+ now, and this is the defect it was written for (board B-034). */
243
+ --good: #00d492; /* 10.21:1 on this band — was inheriting the paper value at 3.69 */
244
+ --warn: #ffb900; /* 11.49:1 — was 3.94 */
245
+ --danger: #ff637e; /* 6.92:1 — was 2.37 */
246
+ --info: #51a2ff; /* 7.51:1 — was 2.90 */
231
247
  }
232
248
 
233
249
  /* The reference ships no reduced-motion branch. This pack requires one: every
@@ -55,6 +55,12 @@
55
55
  deuteranopia — the classic pair, under the floor of 8. Legal only with the
56
56
  secondary encoding the pack declares: a status is a chip with a word in it,
57
57
  never a bare dot. */
58
+ /* @role non-text: --good, --warning, --danger — 2.33:1, 1.78:1 and 3.05:1 on the
59
+ field. Since 1.26.0 the status chip's LABEL is --ink and these three are the chip's
60
+ tint and its 6px dot; before that the label was painted in them, at 2.03, 1.54 and
61
+ 2.65 against the fills the kit actually uses. All three are at or under the 3:1
62
+ non-text floor, so the word is the message — which is what the pack's own "never by
63
+ colour alone" rule has always said. */
58
64
  --good: #0fc27b;
59
65
  --warning: #f5b900;
60
66
  --danger: #ff5b59;
@@ -9,6 +9,10 @@
9
9
  --muted: #5b6472;
10
10
  --border: #e6e9ef;
11
11
  --border-strong: #d7dce4;
12
+ /* @role non-text: --accent, --info — 4.30:1 in both themes, just under AA. The accent
13
+ fills buttons and marks selection and --accent-ink is the text that sits ON it;
14
+ --info deliberately IS the accent hue, for "running / working", and it is a dot and a
15
+ bar rather than a word. */
12
16
  --accent: #2f6feb;
13
17
  --accent-weak: #eaf0fe;
14
18
  --accent-ink: #ffffff; /* text ON the accent — 4.57:1 on --accent */