sheleg-design-skill 1.19.0 → 1.20.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 (49) hide show
  1. package/CHANGELOG.md +80 -0
  2. package/README.md +5 -4
  3. package/bin/cli.js +5 -3
  4. package/cursor/rules/sheleg-design.mdc +4 -1
  5. package/kits/manpage/.design-sync/config.json +14 -0
  6. package/kits/manpage/.design-sync/conventions.md +75 -0
  7. package/kits/manpage/README.md +39 -0
  8. package/kits/manpage/package.json +29 -0
  9. package/kits/manpage/src/Button.md +23 -0
  10. package/kits/manpage/src/Button.tsx +33 -0
  11. package/kits/manpage/src/Card.md +16 -0
  12. package/kits/manpage/src/Card.tsx +24 -0
  13. package/kits/manpage/src/Chip.md +15 -0
  14. package/kits/manpage/src/Chip.tsx +25 -0
  15. package/kits/manpage/src/CodeFrame.md +22 -0
  16. package/kits/manpage/src/CodeFrame.tsx +26 -0
  17. package/kits/manpage/src/EndpointRow.md +20 -0
  18. package/kits/manpage/src/EndpointRow.tsx +33 -0
  19. package/kits/manpage/src/FaqList.md +24 -0
  20. package/kits/manpage/src/FaqList.tsx +31 -0
  21. package/kits/manpage/src/Heading.md +19 -0
  22. package/kits/manpage/src/Heading.tsx +19 -0
  23. package/kits/manpage/src/LabelChip.md +23 -0
  24. package/kits/manpage/src/LabelChip.tsx +26 -0
  25. package/kits/manpage/src/Rule.md +15 -0
  26. package/kits/manpage/src/Rule.tsx +18 -0
  27. package/kits/manpage/src/Stat.md +16 -0
  28. package/kits/manpage/src/Stat.tsx +17 -0
  29. package/kits/manpage/src/TreeItem.md +17 -0
  30. package/kits/manpage/src/TreeItem.tsx +19 -0
  31. package/kits/manpage/src/index.ts +25 -0
  32. package/kits/manpage/src/styles.css +529 -0
  33. package/kits/manpage/tsconfig.json +15 -0
  34. package/package.json +2 -2
  35. package/plugins/sheleg-design/.claude-plugin/plugin.json +2 -2
  36. package/plugins/sheleg-design/commands/sheleg-design.md +1 -1
  37. package/plugins/sheleg-design/skills/sheleg-design/DESIGN_SYNC_BRIDGE.md +1 -1
  38. package/plugins/sheleg-design/skills/sheleg-design/MOBILE_SURFACES.md +1 -1
  39. package/plugins/sheleg-design/skills/sheleg-design/SKILL.md +5 -4
  40. package/plugins/sheleg-design/skills/sheleg-design/SURFACE_COMPOSITION.md +3 -3
  41. package/plugins/sheleg-design/skills/sheleg-design/styles/blueprint.md +1 -0
  42. package/plugins/sheleg-design/skills/sheleg-design/styles/datasheet.md +2 -1
  43. package/plugins/sheleg-design/skills/sheleg-design/styles/field-notes.md +4 -0
  44. package/plugins/sheleg-design/skills/sheleg-design/styles/instrument-console.md +4 -0
  45. package/plugins/sheleg-design/skills/sheleg-design/styles/manpage.md +456 -0
  46. package/plugins/sheleg-design/skills/sheleg-design/styles/scoreboard.md +2 -1
  47. package/plugins/sheleg-design/skills/sheleg-design/styles/showroom.md +2 -1
  48. package/plugins/sheleg-design/skills/sheleg-design/styles/tokens/manpage.css +272 -0
  49. package/plugins/sheleg-design/skills/sheleg-design/styles/workbench.md +4 -0
package/CHANGELOG.md CHANGED
@@ -4,6 +4,86 @@ All notable changes to this project are documented in this file. The format
4
4
  follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions
5
5
  follow [SemVer](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [1.20.0] - 2026-08-12
8
+
9
+ A fifteenth style pack, whose display typeface costs zero bytes — and three
10
+ WCAG failures in the reference, one of them on the very element the design is
11
+ remembered by.
12
+
13
+ ### Added
14
+
15
+ - **`manpage`** — the fifteenth pack, extracted from `zernio.com` off the
16
+ server-rendered HTML of three pages and its two shipped stylesheets, which
17
+ declare 398 custom properties: the Tailwind v4 default ramps plus twelve
18
+ bespoke brand names (coral, cream, ink, charcoal, burgundy, each with a
19
+ `-muted` partner). Cream paper, a 48px display that never grows louder, a
20
+ 576px argument column narrower than most prose, coral label chips that are
21
+ real `<h2>`s, `└` tree glyphs in their own grid column, and one dark code
22
+ frame as the focal point. For developer products whose buyer reads code —
23
+ APIs, SDKs, CLIs, MCP servers. Widened contract, a two-theme token layer, a
24
+ full reference kit, and reciprocal forks written into `blueprint`,
25
+ `datasheet`, `field-notes`, `instrument-console`, `scoreboard`, `showroom`
26
+ and `workbench`.
27
+ - **The display face is the system monospace, and that is the whole identity.**
28
+ The reference loads exactly one webfont — a single variable Geist Sans — and
29
+ sets its headline, body, chips, code frames and FAQ in
30
+ `Menlo, Consolas, Monaco, "Liberation Mono", "Courier New", monospace`, which
31
+ is already on the reader's machine. No render-blocking request for the face
32
+ that carries the page, and no swap window on the headline. Substituting a
33
+ webfont mono is banned in the pack: it costs a request to look less native.
34
+ - **The section heading is a chip and the chip is a real heading.** `LabelChip`
35
+ wraps its span in an `<h2>`, which is why the reference keeps a clean outline
36
+ — one `h1`, one `h2` per section — while reading as a printed specification.
37
+ - **`FaqList` is a `<dl>` that never collapses.** The reference ships zero
38
+ `<details>` and zero `<summary>` on its FAQ: every answer is flat text in the
39
+ DOM, paired with its question, extractable without running JavaScript. The
40
+ component has no `collapsed` prop and will not get one.
41
+
42
+ ### Fixed
43
+
44
+ Four corrections to the reference, every replacement a colour it already ships:
45
+
46
+ - **The white button label fails AA.** `Start for Free` is white on coral at
47
+ **4.16:1**, on both the hero and the closing CTA. The fill is kept — the coral
48
+ button *is* the identity — and the label darkens to `--on-action` (ink) at
49
+ **4.55:1**. `--action-strong` is the reference's burgundy, carrying white at
50
+ 13.34:1.
51
+ - **The signature element is the least readable thing on the page.** The section
52
+ chip paints 12px coral on a coral/8 wash: **3.24:1**, worse than coral on bare
53
+ cream because the wash lifts the field. The wash and edge are kept so the chip
54
+ looks identical; the label becomes `--accent-ink` at **10.40:1**.
55
+ - **The live-status green fails AA at 2.82:1.** `green-600` carries the credit
56
+ balance, the `online` badge and both weekly counters. Its own ramp cannot be
57
+ stepped into a legal set — `green-700` still misses at 4.35:1 and `green-800`
58
+ clears AA but separates by only 3.9 under dichromacy — so success takes
59
+ emerald-800, a ramp the reference also ships in full.
60
+ - **One reduced-motion gate out of eight animations.** The reference gates its
61
+ 40s logo marquee behind `motion-safe:` and leaves the hero blur-in, every
62
+ section rise, `fadeInScale`, `slideInRight`, `pulse`, `ping` and a **1.1s
63
+ infinite `waveform`** running for a reader who asked for stillness. The pack
64
+ collapses the whole surface, and infinite motion **stops** rather than
65
+ shortens.
66
+
67
+ ### Changed
68
+
69
+ - `test/floors.json` raised: `validate.py` 1647 → 1788, `validate_palette.py`
70
+ 716 → 791, `sloplint.py` 366 → 422.
71
+ - **The stated-ratio checker earned its keep twice on this pack**, catching
72
+ `--ink-strong` claimed at 18.98:1 against a computed 19.44 and
73
+ `--on-action-strong` at 6.71:1 against 7.76 — both authored by hand, both
74
+ wrong, neither visible on inspection.
75
+ - `SURFACE_COMPOSITION.md`: three counts corrected by measurement — the accent
76
+ resolves as `--accent` in **thirteen** packs, `--brand` in `field-notes` and
77
+ `--cta` in `orchard`. **B-016 stays open**: none of the three reaches a check,
78
+ because `in thirteen,` is not followed by a counted noun. This is the third
79
+ release in which they were fixed by hand.
80
+ - `plugins/sheleg-design/.claude-plugin/plugin.json` said **thirteen** style
81
+ packs while fourteen shipped. `validate_counted_claims()` did not catch it:
82
+ its pattern wants `<number> [pluggable|locked] style packs` and the manifest
83
+ wrote `pluggable visual style packs`, so the intervening adjective hid a stale
84
+ count from the gate that exists to find them. Corrected to fifteen; the
85
+ pattern gap is the same class as B-016.
86
+
7
87
  ## [1.19.0] - 2026-08-12
8
88
 
9
89
  A fourteenth style pack, and the Refero style card it started from was wrong in
package/README.md CHANGED
@@ -11,7 +11,7 @@ problem — invented colors, six accent hues, dark mode retrofitted later.
11
11
 
12
12
  This skill is the taste layer. It gives a coding agent **one motion
13
13
  methodology** for cinematic, scroll-driven pages, **a motion doctrine** that
14
- decides whether to animate before it decides how, and **fourteen locked style
14
+ decides whether to animate before it decides how, and **fifteen locked style
15
15
  packs** with ready-made design tokens, so what it builds reads as one system
16
16
  instead of a pile of effects.
17
17
 
@@ -59,6 +59,7 @@ into the cinematic layer, and says so in its own *Motion flavor* section.
59
59
  | `scoreboard` | warm paper and warm near-black ink, 2–3px radii, an ink primary button, one hot orange that only ever marks, and a dark ledger of dotted-leader rows whose numbers are set in an aliased pixel face | products whose argument is an accumulating number — ads and SEO operators, growth tools, revenue dashboards sold on results |
60
60
  | `cyclorama` | a pale field cycling through six pastel stops on a 32s loop under near-black ink that never moves with it, a monospaced typewriter serif over mono, one orange used only as a fill, a particle organ that holds then redeploys, no shadows anywhere | enterprise AI transformation, applied-AI services, technical consultancies — where what is sold is a change of state and there is no screenshot worth showing |
61
61
  | `datasheet` | an off-white spec sheet ruled with dashed page guides, a live instrument built from hairline cells at radius zero, one vivid orange, Inter over JetBrains Mono, concentric radii from 16 to 2, and a dark alarm state the instrument enters when it detects the reader is hiding | B2B SaaS whose product is a verdict about the visitor, the request or the device — fraud and bot detection, device intelligence, identity and verification, API products sold on their payload |
62
+ | `manpage` | cream paper under the reader's own system monospace — zero webfont bytes for the display face — a 48px display that never grows louder, a 576px argument column, coral label chips that are real `<h2>`s, `└` tree glyphs in their own grid column, and one dark code frame as the focal point | developer products whose buyer reads code — APIs, SDKs, CLIs, MCP servers, developer infrastructure, where the honest hero is the call itself |
62
63
 
63
64
  Each pack locks palette, type, texture, motion tokens, signature motifs and
64
65
  bans — and ships a `tokens/<pack>.css` to copy verbatim, so the agent never
@@ -133,7 +134,7 @@ skills.
133
134
  | `DESIGN_SYNC_BRIDGE.md` | The Claude Design contract: what a pack sends to claude.ai/design and in what shape, the rule for each of the four reference types, and the border motion does not cross |
134
135
  | `FIGMA_BRIDGE.md` | The design↔code contract: how a pack's tokens map onto Figma variable collections and modes, how to implement a design without importing raw values, and what cannot cross the border |
135
136
  | `AI_PRODUCT_PATTERNS.md` | The surfaces a model drives: the five states of a call, streaming instead of spinners, latency, provenance and uncertainty, agent confirmations, and the bans that keep it honest |
136
- | `styles/*.md` | The fourteen style packs — palette, type, texture, motion tokens, motifs, bans, and the traps each one carries |
137
+ | `styles/*.md` | The fifteen style packs — palette, type, texture, motion tokens, motifs, bans, and the traps each one carries |
137
138
  | `styles/tokens/*.css` | The ready-made token layer per pack, copied verbatim instead of transcribed (`workbench` and `field-notes` each ship a light `:root` plus a `data-theme="dark"` twin) |
138
139
  | `styles/STYLE_PACK_TEMPLATE.md` | The pack contract as a skeleton, so a new style is authored against the same headings rather than improvised |
139
140
 
@@ -204,7 +205,7 @@ cd ./ds-workbench && npm install && npm run build
204
205
  then `/design-sync` in that directory, from Claude Code. Three layers cross: the
205
206
  pack's **bans** as the design system's own README, `styles.css` built from
206
207
  `tokens/<pack>.css` verbatim, and the components — a six-name spine that is
207
- identical in all fourteen kits, so switching packs swaps identity rather than API,
208
+ identical in all fifteen kits, so switching packs swaps identity rather than API,
208
209
  plus each pack's signature parts. **Motion does not cross**, exactly as it does
209
210
  not cross into Figma: a kit is the static half of a pack, and saying so is what
210
211
  stops an agent inventing motion to fill the silence.
@@ -250,7 +251,7 @@ a pack's four widened sections used to make two gates *quieter* and still green.
250
251
  One honest limit: the npx installer is checked by asserting its runtime bundle
251
252
  walker exists, not by reading a file list — it has none by design. What proves
252
253
  it ships the right files is CI, which installs the bundle through **both**
253
- installers and `diff -r`s the result against the source, then builds all fourteen
254
+ installers and `diff -r`s the result against the source, then builds all fifteen
254
255
  kits.
255
256
 
256
257
  `test/scenarios.md` (T1–T19) is the behavioral harness: fresh subagents given a
package/bin/cli.js CHANGED
@@ -234,7 +234,7 @@ ${c("bold", "What it installs")}
234
234
  DESIGN_SYNC_BRIDGE.md the Claude Design contract (what a pack sends, and
235
235
  what does not cross)
236
236
  AI_PRODUCT_PATTERNS.md chat / agent / streaming surfaces (honest state)
237
- styles/ fourteen style packs — instrument-console (dark console),
237
+ styles/ fifteen style packs — instrument-console (dark console),
238
238
  editorial-luxury (warm editorial), workbench (light/dark
239
239
  product UI), briefing-room (dark 16:9 presentation deck),
240
240
  atrium (warm cream consumer health), orchard (friendly
@@ -245,7 +245,9 @@ ${c("bold", "What it installs")}
245
245
  maquette (cream axonometric models on a dark table),
246
246
  scoreboard (warm paper, pixel numerals, a dark ledger),
247
247
  datasheet (an off-white spec sheet whose live instrument
248
- goes dark when it catches the reader hiding) —
248
+ goes dark when it catches the reader hiding),
249
+ manpage (a developer landing page set in the reader's
250
+ own system monospace, cream paper, coral label chips) —
249
251
  plus a ready-made token CSS per pack and
250
252
  STYLE_PACK_TEMPLATE.md for authoring more
251
253
  `);
@@ -327,7 +329,7 @@ function main() {
327
329
  ` ${c("dim", "SKILL.md")} the agent skill\n` +
328
330
  ` ${c("dim", "SHELEG_DESIGN.md")} the full reference\n` +
329
331
  ` ${c("dim", "MOTION_DOCTRINE.md")} whether to animate at all — read before any animation\n` +
330
- ` ${c("dim", "styles/")} style packs + token CSS (instrument-console / editorial-luxury / workbench / briefing-room / atrium / orchard / field-notes / cyclorama / showroom / blueprint / prism / maquette / scoreboard / datasheet)\n\n` +
332
+ ` ${c("dim", "styles/")} style packs + token CSS (instrument-console / editorial-luxury / workbench / briefing-room / atrium / orchard / field-notes / cyclorama / showroom / blueprint / prism / maquette / scoreboard / datasheet / manpage)\n\n` +
331
333
  `Your Cursor / Claude agent can now discover the skill and build\n` +
332
334
  `cinematic, scroll-driven pages — or style product UI (dashboards, admin,\n` +
333
335
  `internal tools) from a standalone pack — on its principles.\n\n` +
@@ -33,7 +33,10 @@ numbers are set in an aliased pixel face, for a product whose argument is
33
33
  an accumulating number; datasheet — an off-white spec
34
34
  sheet whose focal element is a live instrument ruled at radius zero and
35
35
  which re-skins itself dark when it detects the reader is hiding, for B2B
36
- SaaS whose product is a verdict about the visitor or the device);
36
+ SaaS whose product is a verdict about the visitor or the device;
37
+ manpage — a developer landing page set in the reader's own system
38
+ monospace on cream paper, coral label chips that are real headings and a
39
+ dark code frame as the argument, for APIs, SDKs and CLIs);
37
40
  otherwise follow the contract below (self-contained on purpose).
38
41
 
39
42
  ## Whether to animate at all — before how
@@ -0,0 +1,14 @@
1
+ {
2
+ "pkg": "@sheleg-design/manpage",
3
+ "globalName": "ShelegManpage",
4
+ "shape": "package",
5
+ "buildCmd": "npm run build",
6
+ "srcDir": "src",
7
+ "tsconfig": "tsconfig.json",
8
+ "cssEntry": "src/styles.css",
9
+ "docsDir": "src",
10
+ "readmeHeader": ".design-sync/conventions.md",
11
+ "guidelinesGlob": [
12
+ "guidelines/*.md"
13
+ ]
14
+ }
@@ -0,0 +1,75 @@
1
+ # Manpage — the contract this design system ships under
2
+
3
+ **Register.** Choose Manpage for **a developer product whose buyer reads code for
4
+ a living**: an API, an SDK, a CLI, a protocol, an MCP server, developer
5
+ infrastructure. The landing page *is* the documentation, set in the typeface of
6
+ the documentation — the honest hero is not a screenshot but six lines of a request.
7
+ The fork people get wrong is against `datasheet`, which shares the off-white
8
+ paper, the hairlines and the one warm orange-red: there the page is about **the
9
+ reader** and its mono carries a reading the product produced (*what did you get?*);
10
+ here the page is about **the product** and its mono is the whole body face, showing
11
+ a call the reader will write (*what will you type?*). Build every screen against
12
+ `var(--…)` and never a literal.
13
+
14
+ **The display face is free, and that is the identity.** One webfont ships — a
15
+ single variable Geist Sans — and everything visible is set in `--font-mono`, which
16
+ is the **system** monospace stack: Menlo, Consolas, Monaco. There is nothing to
17
+ download for the face that carries the whole page, no swap window on the headline,
18
+ and the slight variation between machines is the point — it reads as the terminal
19
+ rather than as art direction. Substituting a webfont mono costs a render-blocking
20
+ request to look less native. Do not.
21
+
22
+ **The accent is a mark, a fill and a wash — almost never a word.** `--accent`
23
+ measures 3.61:1 on the field: enough for a non-text mark and for large text at 24px
24
+ and above, not enough at body size. Where a word must be coral, use `--accent-ink`
25
+ at 11.59:1. The primary button keeps the coral fill — the coral button *is* the
26
+ identity — but its label is `--on-action`, which is ink at 4.55:1, because white on
27
+ coral measures 4.16:1 and fails AA. `--action-strong` is the burgundy that carries
28
+ white at 13.34:1.
29
+
30
+ **The section heading is a chip, and the chip is a real heading.** `LabelChip`
31
+ wraps its span in an `<h2>`. That single decision is why the page keeps a clean
32
+ outline — one `h1`, one `h2` per section — while reading as a printed specification.
33
+ An eyebrow that merely sits above a heading is not this component and does not earn
34
+ the identity.
35
+
36
+ **The width ladder is the layout.** The argument runs in `--measure-text` (576px),
37
+ narrower than most prose; the hero and its code frame take `--measure-hero`
38
+ (768px); only evidence widens — `--measure-proof` for the testimonial grid,
39
+ `--measure-foot` for the footer, `--measure-wall` for the logo wall. Below 896px
40
+ every step collapses to `--measure-text` and the rhythm carries the structure
41
+ instead.
42
+
43
+ **Radii stay small and nothing is a pill.** 2px on the label chip, 6px on a
44
+ control, 8px on a button, 12px on a card, 16px on a panel. A fully round control
45
+ breaks the printed-tag reading immediately.
46
+
47
+ **One hairline, no shadow.** `--lift-card` is a single 1px bottom line. Nothing
48
+ casts downward, nothing lifts on hover, nothing scales. The one glow that exists,
49
+ `--glow-accent`, is a glow and not an elevation.
50
+
51
+ **The 4px frame is load-bearing.** `body { padding: var(--frame) }` insets the
52
+ whole document from the window edge so every panel closes against a visible margin
53
+ of paper. It is the cheapest identity move in the system and the easiest to delete
54
+ by accident in a layout refactor — it has a token name so it has something worth
55
+ preserving.
56
+
57
+ **Status is never by colour alone.** Every status carries its word, exactly as the
58
+ reference does — `online`, `Done`, `GET`, `POST`. The light set clears both gate
59
+ floors (17.5 at full colour, 8.1 under dichromacy); the dark set clears the hard
60
+ floor at 10.1 and runs tight at 6.8 under dichromacy, which the word covers. Note
61
+ that `--warning` is a near-black brown by arithmetic rather than by taste: the
62
+ coral accent occupies the warning hue, and every amber that reads as a warning
63
+ collides either with the accent under dichromacy or with danger at full colour.
64
+
65
+ **Motion is entry only, and then the page holds still.** One `fadeInBlur` on the
66
+ headline (0.6s, `--ease-out`, after `--stagger`), one entrance per section on the
67
+ way down, and nothing moves again — no hover lift, no drifting gradient, no
68
+ counter that keeps counting. **No scroll clock, no scrubbing, no parallax:** this
69
+ is the calmest pack in the family. At `prefers-reduced-motion: reduce` every
70
+ duration and the stagger go to zero, the blur never applies, and infinite motion
71
+ **stops** rather than shortens.
72
+
73
+ **The FAQ does not open.** `FaqList` is a `<dl>` whose answers are always visible,
74
+ because a collapsed answer is an answer no machine can extract. There is no
75
+ `collapsed` prop and there will not be one.
@@ -0,0 +1,39 @@
1
+ # @sheleg-design/manpage
2
+
3
+ The React reference kit for the SHELEG **Manpage** style pack — cream paper under
4
+ the reader's own system monospace, a 48px display that never grows louder, coral
5
+ label chips that are real headings, and one dark code frame as the argument.
6
+
7
+ It is generated from the pack, not authored beside it: `src/styles.css` opens with
8
+ `styles/tokens/manpage.css` byte for byte, and the rules the design agent must obey
9
+ are in [`.design-sync/conventions.md`](./.design-sync/conventions.md).
10
+
11
+ ```bash
12
+ npm install && npm run build
13
+ ```
14
+
15
+ Then run `/design-sync` in Claude Code from this directory to push it to
16
+ claude.ai/design.
17
+
18
+ ## The spine, and this pack's five
19
+
20
+ `Button`, `Card`, `Chip`, `Stat`, `Heading` and `Rule` are identical in name, props
21
+ and types across every SHELEG kit — switching packs swaps identity, not API.
22
+
23
+ The five that are this pack's own:
24
+
25
+ | Component | What it is |
26
+ |---|---|
27
+ | `LabelChip` | the coral section tag that **is** an `<h2>` — the signature element |
28
+ | `CodeFrame` | the dark panel holding the call; scrolls, never reflows |
29
+ | `TreeItem` | a `└` glyph in its own grid column, never a text prefix |
30
+ | `FaqList` | a `<dl>` whose answers are always visible, so a machine can quote them |
31
+ | `EndpointRow` | a method badge, a path in mono, one line of prose |
32
+
33
+ ## The two things most likely to be broken
34
+
35
+ **The 4px body frame.** `body { padding: var(--frame) }` is what makes the page
36
+ read as a sheet laid on a desk. Deleting it produces no error and no failing test.
37
+
38
+ **The label chip's ink.** It is `--accent-ink`, not `--accent`. Coral on the chip's
39
+ own wash measures 3.24:1; burgundy measures 10.40:1, and the chip looks the same.
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "@sheleg-design/manpage",
3
+ "version": "0.0.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "default": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist",
17
+ "src"
18
+ ],
19
+ "scripts": {
20
+ "build": "tsc -p tsconfig.json"
21
+ },
22
+ "peerDependencies": {
23
+ "react": ">=18"
24
+ },
25
+ "devDependencies": {
26
+ "typescript": "^5.6.0",
27
+ "@types/react": "^18.3.0"
28
+ }
29
+ }
@@ -0,0 +1,23 @@
1
+ ---
2
+ category: Actions
3
+ ---
4
+
5
+ One accent fill per view. In this pack the fill is `--action` — the reference's
6
+ own coral, kept because the coral button *is* the identity — but the label is
7
+ `--on-action`, which is ink rather than white. White on coral measures 4.16:1 and
8
+ does not clear AA at the 16px semibold the reference ships; ink clears at 4.55:1.
9
+ Where a white label is non-negotiable, hover onto `--action-strong` (burgundy,
10
+ 13.34:1).
11
+
12
+ `secondary` is the white 1px-bordered control the reference pairs with it — on a
13
+ developer page that is usually an OAuth continue. `ghost` changes ink and nothing
14
+ else.
15
+
16
+ Transitions `background-color` over `--dur-instant` and nothing more: no lift, no
17
+ scale, no shadow bloom.
18
+
19
+ ```tsx
20
+ <Button onClick={start}>Start for Free</Button>
21
+ <Button variant="secondary" onClick={google}>Continue with Google</Button>
22
+ <Button variant="ghost" size="sm" onClick={skip}>I'll do this later</Button>
23
+ ```
@@ -0,0 +1,33 @@
1
+ import type { ReactNode } from 'react';
2
+
3
+ export interface ButtonProps {
4
+ /** `primary` is the accent fill — at most one per view. */
5
+ variant?: 'primary' | 'secondary' | 'ghost';
6
+ size?: 'sm' | 'md' | 'lg';
7
+ disabled?: boolean;
8
+ onClick?: () => void;
9
+ children: ReactNode;
10
+ className?: string;
11
+ }
12
+
13
+ export function Button({
14
+ variant = 'primary',
15
+ size = 'md',
16
+ disabled = false,
17
+ onClick,
18
+ children,
19
+ className,
20
+ }: ButtonProps) {
21
+ return (
22
+ <button
23
+ type="button"
24
+ className={['mp-btn', `mp-btn--${variant}`, `mp-btn--${size}`, className]
25
+ .filter(Boolean)
26
+ .join(' ')}
27
+ disabled={disabled}
28
+ onClick={onClick}
29
+ >
30
+ {children}
31
+ </button>
32
+ );
33
+ }
@@ -0,0 +1,16 @@
1
+ ---
2
+ category: Surfaces
3
+ ---
4
+
5
+ `--surface` on `--rule`, radius `--r-card`, padding `--pad-card`, and a single 1px
6
+ bottom line for lift. The reference uses it for testimonials at
7
+ `--measure-proof`, three across.
8
+
9
+ **No hover state.** The card does not lift, tint or shift on this pack — it is a
10
+ quotation on paper, and paper does not respond to a cursor.
11
+
12
+ ```tsx
13
+ <Card title="Dev Singh" meta="Founder, ad-attribution SaaS">
14
+ I love the speed and quality here.
15
+ </Card>
16
+ ```
@@ -0,0 +1,24 @@
1
+ import type { ReactNode } from 'react';
2
+
3
+ export interface CardProps {
4
+ title?: string;
5
+ /** Right-aligned metadata on the title row: a count, an id, a timestamp. */
6
+ meta?: string;
7
+ children: ReactNode;
8
+ className?: string;
9
+ }
10
+
11
+ export function Card({ title, meta, children, className }: CardProps) {
12
+ const head = title !== undefined || meta !== undefined;
13
+ return (
14
+ <section className={['mp-card', className].filter(Boolean).join(' ')}>
15
+ {head && (
16
+ <div className="mp-card__head">
17
+ {title !== undefined && <h3 className="mp-card__title">{title}</h3>}
18
+ {meta !== undefined && <span className="mp-card__meta">{meta}</span>}
19
+ </div>
20
+ )}
21
+ <div className="mp-card__body">{children}</div>
22
+ </section>
23
+ );
24
+ }
@@ -0,0 +1,15 @@
1
+ ---
2
+ category: Data
3
+ ---
4
+
5
+ The generic tag. For the section-heading chip that carries this pack's identity,
6
+ use `LabelChip` instead — it wraps a real `<h2>` and this one does not.
7
+
8
+ `neutral` is `--surface-2` under `--ink-soft`. `accent` is `--accent-wash` under
9
+ `--accent-ink`, never under `--accent`: coral on its own wash is 3.24:1.
10
+ `selected` adds a `--accent-edge` border.
11
+
12
+ ```tsx
13
+ <Chip>CASE STUDY</Chip>
14
+ <Chip tone="accent" selected>Free credits</Chip>
15
+ ```
@@ -0,0 +1,25 @@
1
+ import type { ReactNode } from 'react';
2
+
3
+ export interface ChipProps {
4
+ children: ReactNode;
5
+ selected?: boolean;
6
+ tone?: 'neutral' | 'accent';
7
+ className?: string;
8
+ }
9
+
10
+ export function Chip({ children, selected = false, tone = 'neutral', className }: ChipProps) {
11
+ return (
12
+ <span
13
+ className={[
14
+ 'mp-chip',
15
+ `mp-chip--${tone}`,
16
+ selected ? 'mp-chip--selected' : undefined,
17
+ className,
18
+ ]
19
+ .filter(Boolean)
20
+ .join(' ')}
21
+ >
22
+ {children}
23
+ </span>
24
+ );
25
+ }
@@ -0,0 +1,22 @@
1
+ ---
2
+ category: Surfaces
3
+ ---
4
+
5
+ The focal element of the hero, and the only dark surface on the light theme. A
6
+ `--r-panel` frame with three window dots, a filename, a language label and a copy
7
+ affordance — because the page's argument is the call, not a screenshot of a
8
+ dashboard.
9
+
10
+ Two rules it does not bend. It **scrolls horizontally and never reflows**: a
11
+ wrapped code sample is a wrong code sample. And it **never shrinks its type** below
12
+ `--t-mono` (12px) on small screens — the sample stops being evidence the moment it
13
+ becomes unreadable.
14
+
15
+ Place it at `--measure-hero` and let the fold crop it. The crop is what signals
16
+ there is more.
17
+
18
+ ```tsx
19
+ <CodeFrame filename="zernio.ts" language="TypeScript">
20
+ {snippet}
21
+ </CodeFrame>
22
+ ```
@@ -0,0 +1,26 @@
1
+ import type { ReactNode } from 'react';
2
+
3
+ export interface CodeFrameProps {
4
+ /** The filename in the header row — `zernio.ts`, `main.py`. */
5
+ filename: string;
6
+ /** The language label on the right of the header row. */
7
+ language?: string;
8
+ /** Rendered as-is; highlight upstream. Never reflowed, never resized. */
9
+ children: ReactNode;
10
+ className?: string;
11
+ }
12
+
13
+ export function CodeFrame({ filename, language, children, className }: CodeFrameProps) {
14
+ return (
15
+ <figure className={['mp-code', className].filter(Boolean).join(' ')}>
16
+ <figcaption className="mp-code__head">
17
+ <span className="mp-code__dots" aria-hidden="true">
18
+ <i /><i /><i />
19
+ </span>
20
+ <span className="mp-code__name">{filename}</span>
21
+ {language !== undefined && <span className="mp-code__lang">{language}</span>}
22
+ </figcaption>
23
+ <pre className="mp-code__body"><code>{children}</code></pre>
24
+ </figure>
25
+ );
26
+ }
@@ -0,0 +1,20 @@
1
+ ---
2
+ category: Data
3
+ ---
4
+
5
+ The "what you can do" row: a method badge, a path in mono, and one line of prose.
6
+ It is how this pack lists capability without a feature grid — each row is a thing
7
+ you can call, so the list reads as an index rather than as marketing.
8
+
9
+ The badge is a status token on its own tint at `--r-chip`: `--info` for writes,
10
+ `--success` for reads. The method word is always spelled out, never colour alone —
11
+ `GET` and `POST` separate by 29.2 at full colour but only 16.3 under dichromacy,
12
+ and a reader who cannot tell them apart still has to be able to read them.
13
+
14
+ `selected` marks the row the surrounding copy is talking about, using
15
+ `--accent-wash`. At most one per list.
16
+
17
+ ```tsx
18
+ <EndpointRow method="GET" path="/connect/{platform}">One OAuth flow for every platform.</EndpointRow>
19
+ <EndpointRow method="POST" path="/posts" selected>One call, 16 platforms.</EndpointRow>
20
+ ```
@@ -0,0 +1,33 @@
1
+ import type { ReactNode } from 'react';
2
+
3
+ export type Method = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
4
+
5
+ export interface EndpointRowProps {
6
+ method: Method;
7
+ /** The path, set in mono: `/whatsapp/phone-numbers/purchase`. */
8
+ path: string;
9
+ children?: ReactNode;
10
+ /** Drawn as the selected row — the one the surrounding copy is about. */
11
+ selected?: boolean;
12
+ className?: string;
13
+ }
14
+
15
+ export function EndpointRow({ method, path, children, selected = false, className }: EndpointRowProps) {
16
+ return (
17
+ <div
18
+ className={[
19
+ 'mp-endpoint',
20
+ selected ? 'mp-endpoint--selected' : undefined,
21
+ className,
22
+ ]
23
+ .filter(Boolean)
24
+ .join(' ')}
25
+ >
26
+ <span className={['mp-endpoint__method', `mp-endpoint__method--${method.toLowerCase()}`].join(' ')}>
27
+ {method}
28
+ </span>
29
+ <code className="mp-endpoint__path">{path}</code>
30
+ {children !== undefined && <span className="mp-endpoint__note">{children}</span>}
31
+ </div>
32
+ );
33
+ }
@@ -0,0 +1,24 @@
1
+ ---
2
+ category: Data
3
+ ---
4
+
5
+ A `<dl>` / `<dt>` / `<dd>` whose answers are **always visible**. The reference
6
+ ships zero `<details>` and zero `<summary>` elements on this section, and that is
7
+ the single best decision on its page: every answer is flat text in the DOM,
8
+ semantically paired with its question, readable without running a line of
9
+ JavaScript.
10
+
11
+ There is no `collapsed` prop and there will not be one. An accordion trades an
12
+ extractable answer for a click, and the answer is the reason the section exists.
13
+ Nine questions expanded at 14px cost less vertical space than most people assume,
14
+ and nothing here animates because nothing here opens.
15
+
16
+ Pair it with `FaqSchema` in the host app so the visible text and the `FAQPage`
17
+ JSON-LD come from the same array — the reference publishes the section without the
18
+ schema, which is the gap this component exists to close.
19
+
20
+ ```tsx
21
+ <FaqList entries={[
22
+ { q: 'What happens when a post fails?', a: 'We auto-retry, then fire a webhook with the reason.' },
23
+ ]} />
24
+ ```
@@ -0,0 +1,31 @@
1
+ import type { ReactNode } from 'react';
2
+
3
+ export interface FaqEntry {
4
+ q: string;
5
+ a: ReactNode;
6
+ }
7
+
8
+ export interface FaqListProps {
9
+ entries: FaqEntry[];
10
+ className?: string;
11
+ }
12
+
13
+ /**
14
+ * A definition list, always open. There is deliberately no `collapsed` prop:
15
+ * an accordion here costs the extractable answer and buys nothing.
16
+ */
17
+ export function FaqList({ entries, className }: FaqListProps) {
18
+ return (
19
+ <dl className={['mp-faq', className].filter(Boolean).join(' ')}>
20
+ {entries.map(({ q, a }) => (
21
+ <div className="mp-faq__row" key={q}>
22
+ <dt className="mp-faq__q">{q}</dt>
23
+ <dd className="mp-faq__a">
24
+ <span className="mp-faq__glyph" aria-hidden="true">└</span>
25
+ <span>{a}</span>
26
+ </dd>
27
+ </div>
28
+ ))}
29
+ </dl>
30
+ );
31
+ }