@bongos/core 1.19.478 → 1.19.480
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/.bongos-core.json +100 -35
- package/.claude/skills/design/SKILL.md +9 -3
- package/clients/bongos-client/README.md +1 -1
- package/clients/bongos-client/bongos-client.global.js +4 -0
- package/clients/bongos-client/index.cjs +4 -0
- package/clients/bongos-client/index.d.ts +4 -0
- package/clients/bongos-client/index.mjs +4 -0
- package/docs/adr/0230-a-look-skill-is-a-composition-grammar-the-palette-is-the-pack.md +36 -0
- package/docs/adr/0231-the-style-session-an-owner-authors-a-look-inside-the-contract.md +32 -0
- package/docs/adr/README.md +2 -0
- package/docs/api/openapi.json +80 -1
- package/docs/api-reference.md +5 -3
- package/docs/copy-inventory.md +6 -6
- package/docs/copy-registry.json +6 -6
- package/docs/file-map.md +1 -1
- package/docs/module-api-changelog.md +4 -0
- package/modules/dev-box/app/src/vendor/bongos-client.cjs +4 -0
- package/modules/economy/credits.js +78 -0
- package/modules/economy/module.json +1 -1
- package/modules/economy/reward.js +4 -0
- package/modules/economy/routes/credits.js +151 -0
- package/modules/hall-ui/public/md-reader.js +24 -1
- package/modules/ui-design/module.json +1 -1
- package/modules/ui-design/skills/README.md +14 -2
- package/modules/ui-design/skills/gpt-taste/SKILL.md +110 -0
- package/modules/ui-design/skills/industrial-brutalist-ui/SKILL.md +110 -0
- package/modules/ui-design/skills/minimalist-ui/SKILL.md +103 -0
- package/modules/ui-design/skills/stitch-design-taste/SKILL.md +91 -0
- package/modules/ui-design/skills/style/SKILL.md +112 -0
- package/modules/ui-design/styles/README.md +3 -0
- package/modules/ui-design/styles/blueprint/DESIGN.md +152 -0
- package/modules/ui-design/styles/blueprint/mock.html +308 -0
- package/modules/ui-design/styles/blueprint/mock.states.json +11 -0
- package/modules/ui-design/styles/blueprint/pack.json +33 -0
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/src/module-api.js +1 -1
- package/tests/credit_ledger_read.mjs +347 -0
- package/tests/hall_reading_world.mjs +80 -0
- package/tests/own_scope_guard.mjs +24 -2
- package/tests/ui_design_skills.mjs +102 -11
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: style
|
|
3
|
+
description: Runs a bounded session in which an owner authors their OWN look for the instance, as a branding pack inside the fifteen-token contract, and proves it clean before it lands. Four steps and no more. SEARCH reads the instance's world and the style library, renders the nearest two entries so the owner looks rather than imagines, and asks two or three questions about feel. CREATE drafts modules/ui-design/styles/<name>/ in the library's contract shape (pack.json, DESIGN.md, mock.html), never a fork of a sheet and never a sixteenth token. PROVE retunes the thirteen against contrast.js, the styles suite, check-mock and the kit's renders until every named pair is green, showing the shots each round. ADOPT hands the owner the one-step switch and files the look into the catalogue. Triggers on "/style", "make a look", "author a style", "I want our own theme", "can we have a different look", "add a style to the library".
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
<!-- BEGIN PLATFORM PREAMBLE · ui-design module · one block, byte-identical in every skill the module ships (vendored or rebuilt in-house) so an upstream refresh is a three-way merge; the source is modules/ui-design/skills/PREAMBLE.md and tests/ui_design_skills.mjs fails on drift -->
|
|
7
|
+
> **Platform preamble — read before any rule below.** This skill ships with the `ui-design` module (vendored from a scanned origin, or rebuilt in-house from a spec) and runs INSIDE an instance's world, which it reads first and never overrides.
|
|
8
|
+
>
|
|
9
|
+
> 1. **Load the world before any taste rule.** `config/branding.json` over `config/branding.neutral.json` (`theme.ui` is the fifteen tokens: <redacted> colours and two font stacks), `config/design-tokens.json` over `config/design-tokens.neutral.json`, and `DESIGN.md` at the repo root: the instance's palette and derived tiers, faces, materials, motion grammar, components, and its Do's and Don'ts. Where an instance has no `DESIGN.md`, the neutral pack is the world and the platform floors in item 6 are the whole rulebook; say so and build to them. Never invent a palette.
|
|
10
|
+
> 2. **The fifteen-token contract is the only colour source.** Every colour is a `var()` or a `color-mix()` of the fifteen; the only legal literal is pure black or white with alpha as a scrim, mask or halo. No page `:root` (page tokens live on `body`), and every dark rule is written twice: `:root[data-mode="dark"]` and its `prefers-color-scheme` twin.
|
|
11
|
+
> 3. **A style skill produces variants INSIDE that world, never a second world.** The look this skill carries (its palette, faces, materials, mood boards) is a reference for composition and craft; the instance's tokens and faces replace it. Changing the world is the owner's decision and an ADR, not a session's taste.
|
|
12
|
+
> 4. **Images are for hero plates and hero objects only.** UI is built from templates and the instance's world, not painted; any image-generation step below applies to text-free plates and hero objects, never to controls, cards, text, or a screenshot of a screen.
|
|
13
|
+
> 5. **The instance's taste bans apply and win.** Read them from its `DESIGN.md`. Cloud Bongos's own (no em dash or en dash in visible copy, no emoji, no gradient text, no three-equal-card row, no fake screenshot built from divs) are that instance's, not the module's; where this skill's rules conflict with an instance's bans, the instance wins.
|
|
14
|
+
> 6. **The platform floors hold on every instance** and a `DESIGN.md` may tighten them, never loosen them: every control clears 24px on both sides (primary pills 46–48px); AA in both modes (4.5:1 body text, 3:1 large text and non-text) measured from the real stylesheet; and the Kill Switch, `@media (prefers-reduced-motion: reduce)` at the foot of the token layer killing every animation and transition, no motion authored in JavaScript, and a rest frame that is a complete composition on its own.
|
|
15
|
+
> 7. **Look before you ship.** Render the real surface through the module's kit before and after (`/design` Step 2 and `docs/recipes/ui-look-before-you-ship.md`: every state at 1440 / 390 / 320 in dark and light, audited against the floors); a page with no states file gets one first, and new interactive code ships with a pin in the page's own test file.
|
|
16
|
+
>
|
|
17
|
+
> The rules below are the skill's own. A vendored copy carries a `PROVENANCE.md` beside this file naming the origin, the pinned commit, the licence and the scan verdict it was vendored under; an in-house rebuild names its rebuild spec and its ADR in the section right after this block.
|
|
18
|
+
<!-- END PLATFORM PREAMBLE -->
|
|
19
|
+
|
|
20
|
+
## First party
|
|
21
|
+
|
|
22
|
+
This skill has **no upstream**. It was authored for the platform by [task 1003475](https://cloudbongos.com/builders#/task/1003475) from the owner's idea on the style-library sheet: the library ships looks an instance can adopt, and the next step is letting an owner *make* one with Claude beside them. It is not a rebuild, carries no vendored bytes and claims no origin; the two-origin rule for the module's skills is [ADR 0231](../../../../docs/adr/<redacted>.md).
|
|
23
|
+
|
|
24
|
+
Why it exists: a look in this library is a **branding pack** ([ADR 0219](../../../../docs/adr/<redacted>.md)) — thirteen colours, two font stacks, a `DESIGN.md` of derived recipes and one specimen. That is a small enough object for an owner to have opinions about and a strict enough one that a wrong guess fails a measurement rather than shipping. What was missing was the loop between the two: the search that shows what already exists, the draft that stays inside the contract, the retune that is arithmetic rather than taste, and the one-line adoption at the end. This skill is that loop, bounded.
|
|
25
|
+
|
|
26
|
+
## What this session is, and is not
|
|
27
|
+
|
|
28
|
+
**Is:** one look, authored end to end, landed in `modules/ui-design/styles/<name>/` under a claimed task, measured clean before the owner ever adopts it.
|
|
29
|
+
|
|
30
|
+
**Is not:** a redesign of a surface (that is `impeccable shape` or `design-taste-frontend`), a change to the instance's live world (that is the owner's `config/branding.json` and their decision, taken at step 4 and never by this session), or a contract change. **A look that needs a sixteenth token is an ADR, not a style** — say so and stop.
|
|
31
|
+
|
|
32
|
+
## Step 1 — Search, before a single colour is chosen
|
|
33
|
+
|
|
34
|
+
Read the world first, then look at what the library already has, then ask.
|
|
35
|
+
|
|
36
|
+
1. **Read.** `config/branding.json` over `config/branding.neutral.json` (`theme.ui`: the thirteen colours and the two font stacks), the repo-root `DESIGN.md`, and every entry in `modules/ui-design/styles/` — each one's `pack.json` summary and its `DESIGN.md` North Star. State in one line what the instance's world is today.
|
|
37
|
+
2. **Show, do not describe.** Render the nearest two entries and let the owner look:
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
node modules/ui-design/kit/render.js --page / --style <name>
|
|
41
|
+
node modules/ui-design/kit/render.js --page /builders/ranks --surface hall-ui --style <name>
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The hall's page is worth the second render because it carries the light tier and the fixed status vocabulary a look must not repaint.
|
|
45
|
+
3. **Ask two or three questions, no more.** Ask about the feel, never about tokens:
|
|
46
|
+
- **References.** A site, a book cover, a room, a piece of packaging. One or two, not a mood board.
|
|
47
|
+
- **A colour they already own.** A brand colour, a product colour, a colour from the references. If they have none, say so and derive one at step 2.
|
|
48
|
+
- **Paper or void.** Does the surface read as a lit sheet or as a dark room? (A pack carries **light** values only; the dark ground is the platform's black, which every look reaches through its accent and its faces. Say this out loud now, because it is the single thing owners are most surprised by later.)
|
|
49
|
+
- **Quiet or loud.** How much of the page is allowed to be the accent.
|
|
50
|
+
4. **Decide adapt or draft, and say which.** If a library entry is within a retune of the answers, adapt it and name it. If nothing is near, draft. Either way, state the decision in one sentence before writing a file; a session that quietly drafts when an adapt would have done has spent the owner's time on a fourth almost-identical look.
|
|
51
|
+
|
|
52
|
+
## Step 2 — Create, inside the contract
|
|
53
|
+
|
|
54
|
+
Make `modules/ui-design/styles/<name>/` with the three files the library's README specifies. Start from the nearest entry's files, never from a served sheet.
|
|
55
|
+
|
|
56
|
+
- **`pack.json`** — `{ name, title, summary, origin, theme: { ui: { colors: <exactly the thirteen>, fonts: { display, body, links } } } }` and nothing else. `name` is the dir, kebab-case. Every colour is a plain six-digit hex (the sheets do hex arithmetic on this tier). `origin` records the brief in the owner's own words and every retune you make, so a later reader knows what moved and why.
|
|
57
|
+
- **`DESIGN.md`** — the frontmatter shape the root `DESIGN.md` uses: the thirteen value for value with `pack.json` (a test holds them in lockstep), the dark facts as a comment (dark is not this look's to set), the derived recipes, then `typography`, `rounded`, `spacing`, `components`; then the look's prose in the root document's sections, ending in a `### Don't` block, which is where the copy bans the kit reads live.
|
|
58
|
+
- **`mock.html`** — the specimen: no page `:root`, tokens on `body`, every dark rule written twice (`:root[data-mode="dark"] body` and the `prefers-color-scheme` twin), every colour a `var()` or a `color-mix()` of the pack, one `<header>` / `<main>` / `<h1>`, a skip link, `?state=` and `?mode=`, and a head comment saying what the sheet claims. Add `mock.states.json` beside it so the kit can render it.
|
|
59
|
+
|
|
60
|
+
The rules that decide what a look may be:
|
|
61
|
+
|
|
62
|
+
- **Never a fork of a sheet.** The library ships a pack, not CSS. If you find yourself copying `world.css`, stop.
|
|
63
|
+
- **Never a sixteenth token.** A radius, a shadow, a glass and a texture are a *sheet's* derived tier, not a pack's. A look expresses them in its `DESIGN.md` recipes and its specimen, and the instance's surfaces keep their own.
|
|
64
|
+
- **The platform's stays the platform's** whichever look is on: the dark ground, the hall's green / amber / red verification vocabulary, the status ledger's pillars, and the floors.
|
|
65
|
+
- **Faces come with a `links` line.** Two stacks with real fallbacks and the stylesheet URL that loads them; a face with no fallback is a layout shift.
|
|
66
|
+
- **Reference plates, if any, are hero plates and hero objects only** — text-free, with a provenance sidecar beside each file, through the instance's art pipeline. A look never needs one to ship, and this session never asks for one on its own.
|
|
67
|
+
- **Motion belongs to the specimen, not the pack**, and every rule of it sits inside the Kill Switch (`@media (prefers-reduced-motion: reduce)` at the foot of the token layer), with the rest frame a complete composition.
|
|
68
|
+
|
|
69
|
+
## Step 3 — Prove, and retune with the owner watching
|
|
70
|
+
|
|
71
|
+
The retune is **arithmetic, not taste**: a pack is laid through sheets that already exist and every pair they paint must clear AA. Tune the thirteen, never the sheets.
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
node modules/ui-design/kit/contrast.js --pack <name> # the pack floor: every ink on every ground
|
|
75
|
+
node --test --test-reporter=tap tests/ui_design_styles.mjs # the world / hub / hall suites under the pack
|
|
76
|
+
node modules/ui-design/kit/check-mock.js --file modules/ui-design/styles/<name>/mock.html --pack <name>
|
|
77
|
+
node modules/ui-design/kit/render.js --page / --style <name> # every state x width x mode, audited
|
|
78
|
+
node modules/ui-design/kit/render.js --page /builders/ranks --surface hall-ui --style <name>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Each round: run, read the **named failing pair** the suite prints, make one change, show the owner the shots. Common failures and their one right fix:
|
|
82
|
+
|
|
83
|
+
| What fails | What it means | The fix |
|
|
84
|
+
|---|---|---|
|
|
85
|
+
| `ink-faint on the page ground` | the thinnest pair on the paper | deepen `inkFaint`; never lighten the ground to save it |
|
|
86
|
+
| an accent-as-text pair | the accent is a fill, not a word | send the text job to `accentDeep` and deepen that |
|
|
87
|
+
| the hall's info state in dark | `sea` sits outside the band the hall derives from it | move `sea` toward the middle of its lightness range |
|
|
88
|
+
| a warn or error chip | `terracotta` drifted | return it to a red that reads on both grounds |
|
|
89
|
+
| the pack floor on `bgCard` | the card is too close to the paper | separate the two grounds by one real step |
|
|
90
|
+
|
|
91
|
+
Stop when `PACK CLEAN`, the styles suite is green, `ALL RULES PASS` on the specimen, and the renders say `ALL CLEAN`. Paste those four lines into the task's notes; they are the evidence the look is landable.
|
|
92
|
+
|
|
93
|
+
## Step 4 — Adopt, and file it
|
|
94
|
+
|
|
95
|
+
- **Hand the owner one step**, and let them take it: copy `pack.json`'s `theme` into `config/branding.json` (the file `cloudbongos init` writes; an existing instance merges the block over its own). Removing the block goes back to the neutral pack. **This session does not edit `config/branding.json`** — the instance's world is the host boundary and adopting a look is the owner's decision.
|
|
96
|
+
- **File the look into the catalogue** under the claimed task: the row in `modules/ui-design/styles/README.md`, the line in the module's `CLAUDE.md`, and the line in `/design`. A dir that is not named in all three is not in the library.
|
|
97
|
+
- **Say what stays the platform's** in the handover, so the owner is not surprised later: the black dark ground, the verification vocabulary, the ledger's pillars, the floors.
|
|
98
|
+
|
|
99
|
+
## What this skill never does
|
|
100
|
+
|
|
101
|
+
No hooks are written into any harness config. No child agent is spawned with permissions bypassed. No telemetry is collected or sent. No remote bundle is downloaded. No image generation is required to finish a look, and none is invoked without the owner asking. The instance's `config/branding.json` and its served sheets are read, never written, by this session.
|
|
102
|
+
|
|
103
|
+
## Pre-flight
|
|
104
|
+
|
|
105
|
+
- [ ] The world was read and stated in one line before any colour was chosen.
|
|
106
|
+
- [ ] The nearest two library entries were **rendered and looked at**, not just named.
|
|
107
|
+
- [ ] Two or three questions asked, about feel; the light-only fact about packs was said out loud.
|
|
108
|
+
- [ ] Adapt-or-draft decided and stated before a file was written.
|
|
109
|
+
- [ ] Three files (plus `mock.states.json`), exactly the thirteen and the two stacks, no sixteenth token, no forked sheet.
|
|
110
|
+
- [ ] `PACK CLEAN`, the styles suite green, `ALL RULES PASS`, `ALL CLEAN` on `/` and on the hall's light tier, all four pasted into the notes.
|
|
111
|
+
- [ ] The catalogue row, the module `CLAUDE.md` line and the `/design` line landed under the claimed task.
|
|
112
|
+
- [ ] The owner has the one-step adoption and knows what stays the platform's.
|
|
@@ -8,6 +8,7 @@ A **look** is something a builder or an instance owner picks for a new surface o
|
|
|
8
8
|
|---|---|---|---|
|
|
9
9
|
| `chrome-world` | the neutral pack, byte for byte | The canonical entry: one iridescent chrome sculpture in a black void, pale grey paper in light, one warm salmon that lights only the pressable and the live. Its recipes are the repo-root [`DESIGN.md`](../../../DESIGN.md); [`chrome-world/DESIGN.md`](chrome-world/DESIGN.md) points there. | the world round's pick (task 1003296 → 1003298) |
|
|
10
10
|
| `expedition` | warm paper, lamp yellow, Archivo | A printed field journal: a halftone screen over the paper, hairline frames instead of a grid, big heavy uppercase headlines, the yellow as a fill only. [`expedition/DESIGN.md`](expedition/DESIGN.md) | `docs/design/mocks/world/natgeo-editorial` (kept in round 1) |
|
|
11
|
+
| `blueprint` | cool grey-blue paper, cyanotype blue, slate green, IBM Plex Sans | A drafting table under north light: a faint graph lattice on the ground, compartments registered to the board with a crosshair tick at a 2px cut edge, the display voice in sentence case, every figure mono and tabular, one cyanotype blue on what is pressable, a slate green for what was measured and a rust pencil for what went wrong. The library's first cool look. [`blueprint/DESIGN.md`](blueprint/DESIGN.md) | authored through the `/style` session ([task 1003475](https://cloudbongos.com/builders#/task/1003475), [ADR 0231](../../../docs/adr/<redacted>.md)) |
|
|
11
12
|
| `grove` | pale sage, tan, sea green, Nunito | A sculpted paper garden: soft corners on everything that holds content, tinted shadows, the sea as a slab a whole band sits on, the tan as the one lit thing. [`grove/DESIGN.md`](grove/DESIGN.md) | `docs/design/mocks/world/organic-cards` (kept in round 1) |
|
|
12
13
|
|
|
13
14
|
The owner looked at both alternates on the sheet on 2026-09-01 and kept them ("styles look good for a start"). Both alternates were **retuned against the contract**, which is a measurement and not a taste: a pack's thirteen are laid through three sheets that already exist (the landing's `world.css`, the hub's `cosmos.css`, the hall's `style.css`) and every pair those sheets paint must clear AA under it. The grove's sage ground lifted and its inks deepened until the hub's fixed status vocabulary and the hall's chips cleared; the expedition's `ink-faint` deepened one step. What a pack cannot carry is **dark**: the contract is light values only, and every sheet's dark tier is its own black, which a look reaches through its accent and its faces. So the grove's green dark ground stays in the world round's mock and does not travel.
|
|
@@ -48,6 +49,8 @@ SURFACE=modules/ui-design/styles/expedition STYLE=expedition node modules/ui-des
|
|
|
48
49
|
|
|
49
50
|
## Adding a look
|
|
50
51
|
|
|
52
|
+
The steps below are the manual path. The **`/style` session** ([task 1003475](https://cloudbongos.com/builders#/task/1003475), [ADR 0231](../../../docs/adr/<redacted>.md)) walks them with an owner instead: it renders the nearest entries before it asks anything, drafts inside the contract, retunes against the same measurements below with a failure-to-fix table, and hands over the one-step adoption without taking it. `blueprint` was authored that way.
|
|
53
|
+
|
|
51
54
|
1. Make the dir with the three files; start from the alternate nearest to it.
|
|
52
55
|
2. `node modules/ui-design/kit/contrast.js --pack <name>` until the floor is clean; then `node --test tests/ui_design_styles.mjs`, which runs the world / cosmos / hall suites under the pack and tells you the exact pair that fails. Tune the thirteen, never the sheets.
|
|
53
56
|
3. `node modules/ui-design/kit/check-mock.js --file modules/ui-design/styles/<name>/mock.html --pack <name>` until ALL RULES PASS.
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: The Blueprint
|
|
3
|
+
description: A drafting table under north light. Cool grey-blue paper on a faint graph lattice, graphite rules with crosshair ticks at the corners, one cyanotype blue on everything pressable or live, a slate green for what has been measured, and a rust pencil held for what went wrong.
|
|
4
|
+
colors:
|
|
5
|
+
# ---- contract tier, LIGHT: the thirteen this look's pack.json carries, value for value
|
|
6
|
+
# (tests/ui_design_styles.mjs holds the two in lockstep). Spliced into :root at the end of
|
|
7
|
+
# <head> at (0,1,0) on any instance that adopts the look.
|
|
8
|
+
bg: "#e6ebf0"
|
|
9
|
+
bg-card: "#f7fafc"
|
|
10
|
+
bg-deep: "#d3dae2"
|
|
11
|
+
bg-frame: "#edf1f5"
|
|
12
|
+
ink: "#10161d"
|
|
13
|
+
ink-soft: "#464f5a"
|
|
14
|
+
ink-faint: "#566069"
|
|
15
|
+
rule: "#aeb9c4"
|
|
16
|
+
rule-soft: "#cfd7de"
|
|
17
|
+
accent: "#4f9fd6"
|
|
18
|
+
accent-deep: "#17527e"
|
|
19
|
+
sea: "#3f7f6a"
|
|
20
|
+
terracotta: "#b04a2c"
|
|
21
|
+
# ---- contract tier, DARK: NOT this look's to set. A pack carries light values only; dark is
|
|
22
|
+
# each sheet's own black tier (bg #000000, ink #ffffff, rules as white at 18% / 9%), which the
|
|
23
|
+
# look reaches through its accent and its faces. Written here so a reader knows what dark IS.
|
|
24
|
+
bg-dark: "#000000"
|
|
25
|
+
ink-dark: "#ffffff"
|
|
26
|
+
accent-deep-dark: "color-mix(in srgb, var(--accent) 74%, #ffffff)"
|
|
27
|
+
# ---- derived: the accent's jobs. Unlike the library's three warm looks, this accent is COOL
|
|
28
|
+
# and light enough to carry near-black ink, so it fills a door and a lit cell; text still goes
|
|
29
|
+
# to accent-deep, because a 2.4:1 blue on paper is not a word.
|
|
30
|
+
accent-ink: "var(--accent-deep)"
|
|
31
|
+
accent-ink-dark: "var(--accent)"
|
|
32
|
+
accent-on: "color-mix(in srgb, var(--accent) 10%, #000000)"
|
|
33
|
+
accent-lift: "color-mix(in srgb, var(--accent) 74%, #ffffff)"
|
|
34
|
+
accent-tint: "color-mix(in srgb, var(--accent) 16%, var(--bg-card))"
|
|
35
|
+
accent-tint-dark: "color-mix(in srgb, var(--accent) 14%, #000000)"
|
|
36
|
+
focus: "var(--accent-deep)"
|
|
37
|
+
focus-dark: "var(--accent)"
|
|
38
|
+
# ---- derived: the second and third voices. Sea is what has been MEASURED (a verified count,
|
|
39
|
+
# a cleared check); terracotta is the annotation pencil, and it is the only red on the sheet.
|
|
40
|
+
measure: "var(--sea)"
|
|
41
|
+
note: "var(--terracotta)"
|
|
42
|
+
# ---- derived: the drafting materials
|
|
43
|
+
grid: "rgba(0, 0, 0, .05)"
|
|
44
|
+
grid-dark: "rgba(255, 255, 255, .055)"
|
|
45
|
+
grid-major: "rgba(0, 0, 0, .105)"
|
|
46
|
+
grid-major-dark: "rgba(255, 255, 255, .115)"
|
|
47
|
+
tick: "var(--rule)"
|
|
48
|
+
tick-dark: "rgba(255, 255, 255, .28)"
|
|
49
|
+
glass: "var(--bg-card)"
|
|
50
|
+
glass-dark: "rgba(255, 255, 255, .06)"
|
|
51
|
+
typography:
|
|
52
|
+
display: { fontFamily: "IBM Plex Sans, Segoe UI, system-ui, -apple-system, sans-serif", fontSize: "clamp(34px, 5.4vw, 68px)", fontWeight: 600, lineHeight: 1.02, letterSpacing: "-0.03em" }
|
|
53
|
+
headline: { fontFamily: "{typography.display.fontFamily}", fontSize: "clamp(22px, 2.6vw, 34px)", fontWeight: 600, lineHeight: 1.1, letterSpacing: "-0.02em" }
|
|
54
|
+
body: { fontFamily: "IBM Plex Sans, Segoe UI, system-ui, -apple-system, sans-serif", fontSize: "16px", fontWeight: 400, lineHeight: 1.55 }
|
|
55
|
+
label: { fontFamily: "JetBrains Mono, ui-monospace, Cascadia Mono, Consolas, monospace", fontSize: "11px", fontWeight: 400, letterSpacing: "0.14em", textTransform: "uppercase" }
|
|
56
|
+
mono: { fontFamily: "{typography.label.fontFamily}", fontSize: "13px", fontWeight: 400, fontFeature: "tabular-nums" }
|
|
57
|
+
rounded:
|
|
58
|
+
pill: "999px"
|
|
59
|
+
panel: "2px"
|
|
60
|
+
tile: "2px"
|
|
61
|
+
spacing:
|
|
62
|
+
grid-pitch: "22px"
|
|
63
|
+
grid-major-pitch: "110px"
|
|
64
|
+
band: "clamp(44px, 7.5vh, 78px)"
|
|
65
|
+
gutter: "clamp(16px, 4vw, 26px)"
|
|
66
|
+
container: "1180px"
|
|
67
|
+
components:
|
|
68
|
+
mark-tick: { textColor: "{colors.ink}", height: "36px", padding: "0 10px 0 0", rounded: "0" }
|
|
69
|
+
door-primary: { backgroundColor: "{colors.accent}", textColor: "{colors.accent-on}", rounded: "{rounded.pill}", height: "48px", padding: "0 28px" }
|
|
70
|
+
door-secondary: { backgroundColor: "transparent", textColor: "{colors.ink}", border: "1px solid {colors.rule}", rounded: "{rounded.pill}", height: "48px" }
|
|
71
|
+
plate: { backgroundColor: "{colors.bg-card}", border: "1px solid {colors.rule}", rounded: "{rounded.panel}" }
|
|
72
|
+
cell-lit: { backgroundColor: "{colors.accent-tint}", textColor: "{colors.ink}" }
|
|
73
|
+
ledger-row: { textColor: "{colors.ink}", padding: "14px 0", border: "1px solid {colors.rule}" }
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
# Style: The Blueprint
|
|
77
|
+
|
|
78
|
+
**Origin.** Authored through the `/style` session ([task 1003475](https://cloudbongos.com/builders#/task/1003475), [ADR 0231](../../../../docs/adr/<redacted>.md)) from a two-line brief: *"a drafting table under north light, cool paper and graphite; one cyanotype blue on what is pressable, a rust pencil for what went wrong."* The library's three existing looks are all warm and all carry a warm accent (salmon, lamp yellow, tan), so the search step found no near neighbour and the session drafted rather than adapted. The retune against the contract took one pass: the pack floor and all three token suites cleared on the first measurement, which is what a cool ground and a deep graphite ink buy you. The candidate's own dark ground does not travel, as with every look: a pack carries light values only.
|
|
79
|
+
|
|
80
|
+
## Overview
|
|
81
|
+
|
|
82
|
+
**Creative North Star: "The drafting table, under north light"**
|
|
83
|
+
|
|
84
|
+
A page in this look is a sheet on a drafting table. The ground is a cool grey-blue paper carrying a faint graph lattice, so nothing is perfectly empty; structure is a compartment on a hairline rule with a small crosshair tick at its corner, the way a drawing registers to its board; corners are 2px, which reads as a cut edge rather than a rounded card; and the type is a technical grotesque set at a workable weight, sentence case, with mono for every number. One cyanotype blue lights what is pressable or live. A slate green marks what has been measured. One rust pencil annotates what went wrong, and it is the only red on the sheet.
|
|
85
|
+
|
|
86
|
+
**Key Characteristics:**
|
|
87
|
+
|
|
88
|
+
- Cool grey-blue paper (`#e6ebf0`) under a two-tier graph lattice on its own fixed layer, fine at 22px and major at 110px; pure black in dark, where both tiers turn to white.
|
|
89
|
+
- Compartments, not cards: a 1px `rule` outline at a 2px radius, with a crosshair tick at the top-left corner.
|
|
90
|
+
- IBM Plex Sans at 600 for the display voice, sentence case, tracking at `-0.03em`; the same family at 400 for body.
|
|
91
|
+
- One cyanotype blue (`accent`) as a fill; a deep prussian (`accent-deep`) wherever the accent must be read.
|
|
92
|
+
- Every number is mono and tabular. A readout that reflows when it changes is a defect.
|
|
93
|
+
|
|
94
|
+
## Colors
|
|
95
|
+
|
|
96
|
+
- **Cyanotype blue** (`accent`, `#4f9fd6`): the one lit colour. It fills the primary door, the lit rail cell and the focus ring in dark. It is light enough to carry near-black ink (`accent-on`), which is why the door works, and too light to be a word on paper (2.4:1), which is why text goes to `accent-deep`.
|
|
97
|
+
- **Deep prussian** (`accent-deep`, `#17527e`): the blue's text-safe twin, 6.88:1 on the paper and 7.87:1 on the card. In dark it is derived (`color-mix(in srgb, var(--accent) 74%, #ffffff)`), never restated.
|
|
98
|
+
- **Slate green** (`sea`, `#3f7f6a`): the second voice, spent on what has been **measured** — a verified count, a cleared check, a passing readout. It sits in the lightness band the contract needs, because the hall derives its info state from sea at 80% into white in dark and at 86% into black in light.
|
|
99
|
+
- **Rust** (`terracotta`, `#b04a2c`): the annotation pencil, and the only red on the sheet. It is the error and warn source, and it never decorates.
|
|
100
|
+
- **Paper, card, deep, frame** (`bg`, `bg-card`, `bg-deep`, `bg-frame`): the cool ground and its tonal layers. `bg-card` is not white; a compartment on this table is another sheet of the same paper, one step lighter.
|
|
101
|
+
- **Graphite** (`ink`, `ink-soft`, `ink-faint`): a blue-black display and body ink, then two cool greys. `ink-faint` on paper is the thinnest pair at 5.35:1; do not lighten it.
|
|
102
|
+
- **Rule, rule-soft**: the hairlines. `rule` outlines a compartment and draws a tick; `rule-soft` divides inside one.
|
|
103
|
+
|
|
104
|
+
## Typography
|
|
105
|
+
|
|
106
|
+
**Display Font:** IBM Plex Sans 600 (with Segoe UI, system-ui, -apple-system, sans-serif)
|
|
107
|
+
**Body Font:** IBM Plex Sans 400/500/600 (same stack)
|
|
108
|
+
**Label / Mono Font:** JetBrains Mono 400 (with ui-monospace, Cascadia Mono, Consolas)
|
|
109
|
+
|
|
110
|
+
**Character:** A technical grotesque doing two jobs, and a mono doing the third. The display voice is **sentence case**, not uppercase: this look's precision comes from the lattice and the ticks, so shouting the headline as well would be one signal too many. Labels are mono, uppercase and tracked to `0.14em`. Every figure on the page is mono with tabular numerals, in both modes, because a drafting sheet's numbers are read in columns.
|
|
111
|
+
|
|
112
|
+
## Shapes
|
|
113
|
+
|
|
114
|
+
**Two-pixel or pill.** Every container is a rectangle with a 2px radius, a cut edge rather than a rounded card. Every control is a full pill. There is no third shape and no shadow: elevation on this table is the lattice showing through, the outline, and the tick.
|
|
115
|
+
|
|
116
|
+
## Materials
|
|
117
|
+
|
|
118
|
+
- **The lattice, in two tiers, on its own layer.** Four `repeating-linear-gradient`s: a fine rule every 22px in `grid` (black at 5%, white at 5.5%) and a major one every 110px in `grid-major` (black at 10.5%, white at 11.5%), the way a drawing sheet is ruled fine and counted coarse. The major tier is what makes the table readable in a screenshot; the fine tier is what makes it feel measured. It lives on a **fixed, `pointer-events: none` `body::before` at `z-index: -1`**, never as `body`'s `background-image`: a branding pack's `backdrop` emits `body{background:...}` *after* the page's own stylesheet (`themeMarkup()` in `serve-internal.js`), and that shorthand resets `background-image` to `none` on every served page. A texture on `body` silently does not exist; a texture on a layer does. Neither tier sits over the drawing, and neither changes the contrast of anything measured on top.
|
|
119
|
+
- **The tick.** An 8px crosshair in `tick`, drawn with a pseudo-element on the top-left corner of a compartment. One per compartment. It registers the drawing to the board and it is the look's signature.
|
|
120
|
+
- **Compartments.** A 1px `rule` outline at `rounded.panel`; `rule-soft` divides inside one. No shadow anywhere, in either mode.
|
|
121
|
+
- **Plates** (when a surface adds them): a surface's plates are its own; this look brings none. Where one is used it is a text-free hero plate with its provenance sidecar, as the platform's imagery rule says.
|
|
122
|
+
|
|
123
|
+
## Motion
|
|
124
|
+
|
|
125
|
+
Measured, not felt. State transitions at 180ms on `cubic-bezier(.2,.7,.3,1)`; no ambient loops in this look, and nothing moves in script. The kill switch stands as the platform's, and the rest frame is the whole drawing.
|
|
126
|
+
|
|
127
|
+
## Do's and Don'ts
|
|
128
|
+
|
|
129
|
+
### Do
|
|
130
|
+
|
|
131
|
+
- **Do** fill with `accent` and write with `accent-deep`; put `accent-on` on any blue.
|
|
132
|
+
- **Do** outline a compartment with `rule` and divide inside it with `rule-soft`; give it one tick.
|
|
133
|
+
- **Do** keep every container at a 2px radius and every control a pill.
|
|
134
|
+
- **Do** set every figure in the mono with tabular numerals, in both modes.
|
|
135
|
+
- **Do** spend `sea` on what was measured and `terracotta` on what went wrong, and nowhere else.
|
|
136
|
+
|
|
137
|
+
### Don't
|
|
138
|
+
|
|
139
|
+
- **Don't** write words in the cyanotype blue, or put white on it.
|
|
140
|
+
- **Don't** drop a shadow under a container, or round one past 2px; the outline and the tick are the whole elevation system.
|
|
141
|
+
- **Don't** use an em dash or en dash in visible copy, an emoji, gradient text, or a coloured text glow.
|
|
142
|
+
- **Don't** uppercase the display voice; the lattice and the ticks already carry the precision.
|
|
143
|
+
- **Don't** pin the accent, sea or terracotta in a dark block; dark derives.
|
|
144
|
+
- **Don't** declare a `:root` in a page; page tokens live on `body`.
|
|
145
|
+
|
|
146
|
+
## Accessibility Floors
|
|
147
|
+
|
|
148
|
+
The platform's, unchanged: 4.5:1 body text and 3:1 large text and non-text in both modes, measured from the real stylesheet; every control 24px on both sides (the pills are 46 and 48); the kill switch at the foot of the token layer. This pack measures clean against every pair the landing's `world.css`, the hub's `cosmos.css` and the hall's `style.css` paint (`tests/ui_design_styles.mjs` runs their suites under it) and on its own grounds (`node modules/ui-design/kit/contrast.js --pack blueprint`).
|
|
149
|
+
|
|
150
|
+
## Adopting this look
|
|
151
|
+
|
|
152
|
+
Copy `pack.json`'s `theme` into the instance's `config/branding.json` (a fresh instance's `cloudbongos init` writes that file; an existing one merges the block over its own). Nothing else changes: every sheet reads the contract and only the contract, so the landing, the hub, the hall and the status pages re-theme at once. What stays the platform's: the dark ground (black), the hall's fixed green / amber / red verification vocabulary, the status ledger's pillars, and every derived recipe a sheet already carries. Look before you ship: `node modules/ui-design/kit/render.js --page / --style blueprint`.
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<title>{{productName}} · the blueprint, on a sheet</title>
|
|
7
|
+
<script>
|
|
8
|
+
(function(){try{var q=new URLSearchParams(location.search);var m=q.get('mode');if(m==='light'||m==='dark')document.documentElement.setAttribute('data-mode',m);}catch(e){}})();
|
|
9
|
+
</script>
|
|
10
|
+
<style>
|
|
11
|
+
html { color-scheme: light; }
|
|
12
|
+
body {
|
|
13
|
+
/* the blueprint's derived tier, by the recipes in this style's DESIGN.md. The fifteen arrive
|
|
14
|
+
from the pack the stub splices after this sheet; nothing below is a colour of its own: a
|
|
15
|
+
var(), a color-mix(), or black or white with alpha. The paper sits on a graph lattice, a
|
|
16
|
+
compartment is an outline with one crosshair tick at its corner, corners are 2px and every
|
|
17
|
+
control is a pill. There is no shadow in either mode. */
|
|
18
|
+
--font-mono: "JetBrains Mono", ui-monospace, "Cascadia Mono", Consolas, monospace;
|
|
19
|
+
--glass: var(--bg-card);
|
|
20
|
+
--glass-strong: var(--bg-deep);
|
|
21
|
+
--glass-edge: var(--rule);
|
|
22
|
+
--accent-ink: var(--accent-deep);
|
|
23
|
+
--accent-lift: color-mix(in srgb, var(--accent) 74%, #ffffff);
|
|
24
|
+
--accent-tint: color-mix(in srgb, var(--accent) 16%, var(--bg-card));
|
|
25
|
+
--accent-on: color-mix(in srgb, var(--accent) 10%, #000000);
|
|
26
|
+
--focus: var(--accent-deep);
|
|
27
|
+
--measure: var(--sea);
|
|
28
|
+
--note: var(--terracotta);
|
|
29
|
+
--grid: rgba(0, 0, 0, .05);
|
|
30
|
+
--grid-major: rgba(0, 0, 0, .105);
|
|
31
|
+
--grid-pitch: 22px;
|
|
32
|
+
--grid-major-pitch: 110px;
|
|
33
|
+
--tick: var(--rule);
|
|
34
|
+
--label-face: var(--font-mono);
|
|
35
|
+
--label-size: 11px;
|
|
36
|
+
--label-space: .14em;
|
|
37
|
+
--radius: 2px;
|
|
38
|
+
--radius-sm: 2px;
|
|
39
|
+
--radius-pill: 999px;
|
|
40
|
+
--top-h: 64px;
|
|
41
|
+
--gutter: clamp(16px, 4vw, 26px);
|
|
42
|
+
--band: clamp(44px, 7.5vh, 78px);
|
|
43
|
+
margin: 0;
|
|
44
|
+
background-color: var(--bg);
|
|
45
|
+
color: var(--ink);
|
|
46
|
+
font-family: var(--font-body);
|
|
47
|
+
font-size: 16px;
|
|
48
|
+
line-height: 1.55;
|
|
49
|
+
-webkit-font-smoothing: antialiased;
|
|
50
|
+
}
|
|
51
|
+
:root[data-mode="dark"] body {
|
|
52
|
+
color-scheme: dark;
|
|
53
|
+
--bg: #000000;
|
|
54
|
+
--bg-card: color-mix(in srgb, #ffffff 7%, #000000);
|
|
55
|
+
--bg-deep: #000000;
|
|
56
|
+
--bg-frame: color-mix(in srgb, #ffffff 4%, #000000);
|
|
57
|
+
--ink: #ffffff;
|
|
58
|
+
--ink-soft: rgba(255, 255, 255, .72);
|
|
59
|
+
--ink-faint: rgba(255, 255, 255, .62);
|
|
60
|
+
--rule: rgba(255, 255, 255, .18);
|
|
61
|
+
--rule-soft: rgba(255, 255, 255, .09);
|
|
62
|
+
--accent-deep: color-mix(in srgb, var(--accent) 74%, #ffffff);
|
|
63
|
+
--glass: rgba(255, 255, 255, .06);
|
|
64
|
+
--glass-strong: rgba(255, 255, 255, .12);
|
|
65
|
+
--glass-edge: rgba(255, 255, 255, .18);
|
|
66
|
+
--accent-ink: var(--accent);
|
|
67
|
+
--accent-tint: color-mix(in srgb, var(--accent) 14%, #000000);
|
|
68
|
+
--focus: var(--accent);
|
|
69
|
+
--grid: rgba(255, 255, 255, .055);
|
|
70
|
+
--grid-major: rgba(255, 255, 255, .115);
|
|
71
|
+
--tick: rgba(255, 255, 255, .28);
|
|
72
|
+
}
|
|
73
|
+
@media (prefers-color-scheme: dark) {
|
|
74
|
+
:root:not([data-mode="light"]) body {
|
|
75
|
+
color-scheme: dark;
|
|
76
|
+
--bg: #000000;
|
|
77
|
+
--bg-card: color-mix(in srgb, #ffffff 7%, #000000);
|
|
78
|
+
--bg-deep: #000000;
|
|
79
|
+
--bg-frame: color-mix(in srgb, #ffffff 4%, #000000);
|
|
80
|
+
--ink: #ffffff;
|
|
81
|
+
--ink-soft: rgba(255, 255, 255, .72);
|
|
82
|
+
--ink-faint: rgba(255, 255, 255, .62);
|
|
83
|
+
--rule: rgba(255, 255, 255, .18);
|
|
84
|
+
--rule-soft: rgba(255, 255, 255, .09);
|
|
85
|
+
--accent-deep: color-mix(in srgb, var(--accent) 74%, #ffffff);
|
|
86
|
+
--glass: rgba(255, 255, 255, .06);
|
|
87
|
+
--glass-strong: rgba(255, 255, 255, .12);
|
|
88
|
+
--glass-edge: rgba(255, 255, 255, .18);
|
|
89
|
+
--accent-ink: var(--accent);
|
|
90
|
+
--accent-tint: color-mix(in srgb, var(--accent) 14%, #000000);
|
|
91
|
+
--focus: var(--accent);
|
|
92
|
+
--grid: rgba(255, 255, 255, .055);
|
|
93
|
+
--grid-major: rgba(255, 255, 255, .115);
|
|
94
|
+
--tick: rgba(255, 255, 255, .28);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/* the drafting table itself: a fixed, pointer-inert lattice UNDER the content. It is a layer
|
|
99
|
+
and not a body background-image on purpose - the branding pack's `backdrop` emits a
|
|
100
|
+
`body{background:...}` rule after the page's own sheet (serve-internal.js themeMarkup),
|
|
101
|
+
and that shorthand resets background-image to none on any served page. */
|
|
102
|
+
body::before {
|
|
103
|
+
content: "";
|
|
104
|
+
position: fixed;
|
|
105
|
+
inset: 0;
|
|
106
|
+
z-index: -1;
|
|
107
|
+
pointer-events: none;
|
|
108
|
+
background-image:
|
|
109
|
+
repeating-linear-gradient(to right, var(--grid-major) 0 1px, transparent 1px var(--grid-major-pitch)),
|
|
110
|
+
repeating-linear-gradient(to bottom, var(--grid-major) 0 1px, transparent 1px var(--grid-major-pitch)),
|
|
111
|
+
repeating-linear-gradient(to right, var(--grid) 0 1px, transparent 1px var(--grid-pitch)),
|
|
112
|
+
repeating-linear-gradient(to bottom, var(--grid) 0 1px, transparent 1px var(--grid-pitch));
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
*, *::before, *::after { box-sizing: border-box; }
|
|
116
|
+
a { color: inherit; }
|
|
117
|
+
:focus-visible { outline: 2px solid var(--focus); outline-offset: 3px; }
|
|
118
|
+
.skip { position: absolute; left: 12px; top: -60px; padding: 11px 18px; border-radius: var(--radius-pill); background: var(--bg-card); color: var(--ink); text-decoration: none; }
|
|
119
|
+
.skip:focus { top: 12px; }
|
|
120
|
+
.wrap { max-width: 1180px; margin: 0 auto; padding: 0 var(--gutter); }
|
|
121
|
+
|
|
122
|
+
/* the registered bar: a hairline rule under it, the mark behind its own tick */
|
|
123
|
+
.bar { height: var(--top-h); border-bottom: 1px solid var(--rule); background: var(--bg-frame); }
|
|
124
|
+
.bar .wrap { height: 100%; display: flex; align-items: center; gap: 18px; }
|
|
125
|
+
.mark { position: relative; display: inline-flex; align-items: center; height: 36px; padding-left: 16px; font-weight: 600; letter-spacing: -.01em; font-size: 15px; text-decoration: none; }
|
|
126
|
+
.mark::before { content: ""; position: absolute; left: 0; top: 12px; width: 9px; height: 9px; background:
|
|
127
|
+
linear-gradient(to right, var(--accent-deep) 0 9px) center / 9px 1px no-repeat,
|
|
128
|
+
linear-gradient(to bottom, var(--accent-deep) 0 9px) center / 1px 9px no-repeat; }
|
|
129
|
+
.nav { margin-left: auto; display: flex; align-items: center; gap: 4px; }
|
|
130
|
+
.nav a { text-decoration: none; font-family: var(--label-face); font-size: 11px; letter-spacing: var(--label-space); text-transform: uppercase; color: var(--ink-soft); padding: 14px 10px; display: inline-block; line-height: 16px; }
|
|
131
|
+
.nav a:hover { color: var(--ink); }
|
|
132
|
+
.pill { display: inline-flex; align-items: center; height: 46px; padding: 0 22px; border-radius: var(--radius-pill); text-decoration: none; font-weight: 600; font-family: var(--font-body); font-size: 15px; transition: background-color 180ms cubic-bezier(.2, .7, .3, 1); }
|
|
133
|
+
.pill.in { background: var(--ink); color: var(--bg); }
|
|
134
|
+
.who { display: none; align-items: center; gap: 8px; height: 46px; padding: 0 6px; border-radius: var(--radius-pill); border: 1px solid var(--rule); }
|
|
135
|
+
.who .dot { width: 30px; height: 30px; border-radius: 50%; background: var(--bg-deep); border: 1px solid var(--rule); }
|
|
136
|
+
body[data-state="signed-in"] .pill.in { display: none; }
|
|
137
|
+
body[data-state="signed-in"] .who { display: inline-flex; }
|
|
138
|
+
|
|
139
|
+
/* the bands: the lattice shows through; a rule between chapters */
|
|
140
|
+
.band { padding: var(--band) 0; border-top: 1px solid var(--rule-soft); }
|
|
141
|
+
.band:first-of-type { border-top: 0; }
|
|
142
|
+
h1 { font-family: var(--font-display); font-weight: 600; font-size: clamp(34px, 5.4vw, 68px); line-height: 1.02; letter-spacing: -.03em; margin: 0 0 18px; max-width: 16ch; }
|
|
143
|
+
h2 { font-family: var(--font-display); font-weight: 600; font-size: clamp(22px, 2.6vw, 34px); line-height: 1.1; letter-spacing: -.02em; margin: 0 0 14px; }
|
|
144
|
+
.lede { color: var(--ink-soft); max-width: 56ch; margin: 0; font-size: 15px; }
|
|
145
|
+
.label { font-family: var(--label-face); font-size: var(--label-size); letter-spacing: var(--label-space); text-transform: uppercase; color: var(--ink-faint); }
|
|
146
|
+
.kicker { display: inline-block; margin-bottom: 14px; color: var(--accent-ink); }
|
|
147
|
+
|
|
148
|
+
/* a compartment: an outline at 2px with one crosshair tick at its corner */
|
|
149
|
+
.plate { position: relative; background: var(--bg-card); border: 1px solid var(--rule); border-radius: var(--radius); padding: 20px; }
|
|
150
|
+
.plate::before { content: ""; position: absolute; left: -4px; top: -4px; width: 9px; height: 9px; background:
|
|
151
|
+
linear-gradient(to right, var(--tick) 0 9px) center / 9px 1px no-repeat,
|
|
152
|
+
linear-gradient(to bottom, var(--tick) 0 9px) center / 1px 9px no-repeat; }
|
|
153
|
+
|
|
154
|
+
/* the thirteen, as a specimen strip inside one compartment */
|
|
155
|
+
.sw { display: grid; grid-template-columns: repeat(auto-fill, minmax(72px, 1fr)); gap: 12px; margin: 0; padding: 0; list-style: none; }
|
|
156
|
+
.sw i { display: block; height: 52px; border: 1px solid var(--rule); border-radius: var(--radius-sm); background: var(--c); }
|
|
157
|
+
.sw b { display: block; margin-top: 6px; font-family: var(--font-mono); font-weight: 400; font-size: 11px; color: var(--ink-faint); overflow-wrap: anywhere; }
|
|
158
|
+
|
|
159
|
+
/* the door pair: pills, the primary in cyanotype blue */
|
|
160
|
+
.doors { display: inline-flex; flex-wrap: wrap; gap: 8px; }
|
|
161
|
+
.door { display: inline-flex; align-items: center; height: 48px; padding: 0 28px; border-radius: var(--radius-pill); text-decoration: none; font-weight: 600; transition: background-color 180ms cubic-bezier(.2, .7, .3, 1); }
|
|
162
|
+
.door.go { background: var(--accent); color: var(--accent-on); }
|
|
163
|
+
.door.go:hover { background: var(--accent-lift); }
|
|
164
|
+
.door.more { color: var(--ink); border: 1px solid var(--rule); }
|
|
165
|
+
.door.more:hover { background: var(--glass-strong); }
|
|
166
|
+
|
|
167
|
+
/* the lifecycle rail: five compartments on one lattice row, one lit */
|
|
168
|
+
.rail { display: grid; grid-template-columns: repeat(5, 1fr); gap: 12px; margin: 0; padding: 0; list-style: none; }
|
|
169
|
+
.rail li { position: relative; padding: 14px; border: 1px solid var(--rule); border-radius: var(--radius); }
|
|
170
|
+
.rail li::before { content: ""; position: absolute; left: -4px; top: -4px; width: 9px; height: 9px; background:
|
|
171
|
+
linear-gradient(to right, var(--tick) 0 9px) center / 9px 1px no-repeat,
|
|
172
|
+
linear-gradient(to bottom, var(--tick) 0 9px) center / 1px 9px no-repeat; }
|
|
173
|
+
.rail .dot { display: block; width: 8px; height: 8px; border-radius: 50%; border: 1px solid var(--ink-faint); margin-bottom: 10px; }
|
|
174
|
+
.rail .lit { background: var(--accent-tint); border-color: var(--accent-deep); }
|
|
175
|
+
.rail .lit .dot { background: var(--accent); border-color: var(--accent-deep); }
|
|
176
|
+
.rail .lit .label { color: var(--ink); }
|
|
177
|
+
.rail p { margin: 6px 0 0; color: var(--ink-soft); font-size: 14px; }
|
|
178
|
+
|
|
179
|
+
/* ledger rows: the drawing register, every figure in the mono */
|
|
180
|
+
.ledger { margin: 0; padding: 0; list-style: none; border-top: 1px solid var(--rule); }
|
|
181
|
+
.ledger li { display: grid; grid-template-columns: 88px 1fr 152px 96px; gap: 20px; align-items: baseline; padding: 14px 0; border-bottom: 1px solid var(--rule-soft); }
|
|
182
|
+
.ledger .id { font-family: var(--font-mono); font-size: 13px; color: var(--ink-faint); font-variant-numeric: tabular-nums; }
|
|
183
|
+
.ledger .by, .ledger .when { color: var(--ink-soft); font-size: 15px; }
|
|
184
|
+
.ledger .when { text-align: right; font-family: var(--font-mono); font-size: 13px; font-variant-numeric: tabular-nums; }
|
|
185
|
+
.ledger a { color: var(--accent-ink); text-underline-offset: 3px; display: inline-block; padding: 2px 0; }
|
|
186
|
+
.ledger .ok { color: var(--measure); font-family: var(--font-mono); font-size: 12px; letter-spacing: .06em; text-transform: uppercase; }
|
|
187
|
+
.ledger .bad { color: var(--note); font-family: var(--font-mono); font-size: 12px; letter-spacing: .06em; text-transform: uppercase; }
|
|
188
|
+
|
|
189
|
+
footer { border-top: 1px solid var(--rule); padding: 26px 0 40px; }
|
|
190
|
+
footer .wrap { display: flex; flex-wrap: wrap; gap: 8px 22px; align-items: baseline; color: var(--ink-soft); font-size: 14px; }
|
|
191
|
+
footer p { margin: 0; flex: 1 1 320px; }
|
|
192
|
+
footer a { color: var(--accent-ink); display: inline-block; padding: 4px 0; font-family: var(--label-face); font-size: 11px; letter-spacing: .1em; text-transform: uppercase; }
|
|
193
|
+
|
|
194
|
+
@media (max-width: 900px) {
|
|
195
|
+
body { --top-h: 60px; }
|
|
196
|
+
.rail { grid-template-columns: 1fr; }
|
|
197
|
+
}
|
|
198
|
+
@media (max-width: 600px) {
|
|
199
|
+
.ledger li { grid-template-columns: 1fr; gap: 4px; }
|
|
200
|
+
.ledger .when { text-align: left; }
|
|
201
|
+
.nav a { display: none; }
|
|
202
|
+
}
|
|
203
|
+
@media (prefers-reduced-motion: reduce) {
|
|
204
|
+
*, *::before, *::after { animation: none !important; transition: none !important; }
|
|
205
|
+
}
|
|
206
|
+
</style>
|
|
207
|
+
</head>
|
|
208
|
+
<body>
|
|
209
|
+
<!-- THESIS: the blueprint as a specimen sheet. The thirteen colours and the two faces the pack carries, laid through this look's own derived recipes (its DESIGN.md frontmatter): a graph lattice on the page ground, compartments that are an outline at a 2px radius with one crosshair tick at the corner, a sentence-case technical grotesque for the display voice, mono tabular figures everywhere a number appears, door pills with the primary in cyanotype blue, a rail with one lit cell, and a register whose verdict column spends sea on what was measured and terracotta on what went wrong. This page declares no :root and no colour of its own: the pack is spliced by the stub (STYLE=blueprint) and every value is a var() or a color-mix() of it. Dark restates the platform's black tier on body, since a mock links no sheet; this look reaches dark through its blue and its faces, which is all a pack carries. STATES: rest (signed out), signed-in. MODES: ?mode=dark|light. -->
|
|
210
|
+
<a class="skip" href="#main">Skip to content</a>
|
|
211
|
+
<header class="bar">
|
|
212
|
+
<div class="wrap">
|
|
213
|
+
<a class="mark" href="/">{{productName}}</a>
|
|
214
|
+
<nav class="nav" aria-label="Primary">
|
|
215
|
+
<a href="#swatches">Projects</a>
|
|
216
|
+
<a href="#type">Docs</a>
|
|
217
|
+
<a class="pill in" href="#main">Sign in</a>
|
|
218
|
+
<span class="who"><span class="dot" aria-hidden="true"></span><span class="label">builder</span></span>
|
|
219
|
+
</nav>
|
|
220
|
+
</div>
|
|
221
|
+
</header>
|
|
222
|
+
<main id="main" tabindex="-1">
|
|
223
|
+
<section class="band">
|
|
224
|
+
<div class="wrap">
|
|
225
|
+
<p class="label kicker">A look from the style library</p>
|
|
226
|
+
<h1>The blueprint</h1>
|
|
227
|
+
<p class="lede">A drafting table under north light. Cool grey-blue paper on a faint graph lattice, compartments registered to the board with a crosshair tick, one cyanotype blue on everything pressable or live, a slate green for what has been measured, and a rust pencil held for what went wrong.</p>
|
|
228
|
+
</div>
|
|
229
|
+
</section>
|
|
230
|
+
<section class="band" id="swatches">
|
|
231
|
+
<div class="wrap">
|
|
232
|
+
<h2>The thirteen</h2>
|
|
233
|
+
<div class="plate">
|
|
234
|
+
<ul class="sw">
|
|
235
|
+
<li><i style="--c: var(--bg)"></i><b>bg</b></li>
|
|
236
|
+
<li><i style="--c: var(--bg-card)"></i><b>bg-card</b></li>
|
|
237
|
+
<li><i style="--c: var(--bg-deep)"></i><b>bg-deep</b></li>
|
|
238
|
+
<li><i style="--c: var(--bg-frame)"></i><b>bg-frame</b></li>
|
|
239
|
+
<li><i style="--c: var(--ink)"></i><b>ink</b></li>
|
|
240
|
+
<li><i style="--c: var(--ink-soft)"></i><b>ink-soft</b></li>
|
|
241
|
+
<li><i style="--c: var(--ink-faint)"></i><b>ink-faint</b></li>
|
|
242
|
+
<li><i style="--c: var(--rule)"></i><b>rule</b></li>
|
|
243
|
+
<li><i style="--c: var(--rule-soft)"></i><b>rule-soft</b></li>
|
|
244
|
+
<li><i style="--c: var(--accent)"></i><b>accent</b></li>
|
|
245
|
+
<li><i style="--c: var(--accent-deep)"></i><b>accent-deep</b></li>
|
|
246
|
+
<li><i style="--c: var(--sea)"></i><b>sea</b></li>
|
|
247
|
+
<li><i style="--c: var(--terracotta)"></i><b>terracotta</b></li>
|
|
248
|
+
</ul>
|
|
249
|
+
</div>
|
|
250
|
+
</div>
|
|
251
|
+
</section>
|
|
252
|
+
<section class="band" id="type">
|
|
253
|
+
<div class="wrap">
|
|
254
|
+
<h2>Sentence case, and a mono that counts</h2>
|
|
255
|
+
<p class="lede">The display face is a technical grotesque at 600, set in sentence case with the tracking pulled in. This look does not shout its headline: the lattice and the ticks already carry the precision, so a second precision signal in the type would be one too many. Every figure is mono with tabular numerals, in both modes.</p>
|
|
256
|
+
<p class="label" style="margin-top: 22px">Label face, tracked and uppercase</p>
|
|
257
|
+
<p style="margin: 6px 0 0; font-family: var(--font-mono); font-size: 13px; font-variant-numeric: tabular-nums">1003475 · 15,647 credits · 7 ships in 24h</p>
|
|
258
|
+
</div>
|
|
259
|
+
</section>
|
|
260
|
+
<section class="band">
|
|
261
|
+
<div class="wrap">
|
|
262
|
+
<h2>The doors</h2>
|
|
263
|
+
<p class="lede" style="margin-bottom: 22px">Two pills side by side. The primary is the cyanotype blue with near-black ink on it; the secondary is a hairline outline, filled only on hover.</p>
|
|
264
|
+
<div class="doors">
|
|
265
|
+
<a class="door more" href="#swatches">Open the register</a>
|
|
266
|
+
<a class="door go" href="#main">Start a drawing</a>
|
|
267
|
+
</div>
|
|
268
|
+
</div>
|
|
269
|
+
</section>
|
|
270
|
+
<section class="band">
|
|
271
|
+
<div class="wrap">
|
|
272
|
+
<h2>The lifecycle rail</h2>
|
|
273
|
+
<ol class="rail">
|
|
274
|
+
<li><span class="dot"></span><span class="label">Claim</span><p>A builder locks a task.</p></li>
|
|
275
|
+
<li><span class="dot"></span><span class="label">Build</span><p>The code is written in a worktree.</p></li>
|
|
276
|
+
<li class="lit" aria-current="step"><span class="dot"></span><span class="label">Grade</span><p>An adversarial panel reads the diff.</p></li>
|
|
277
|
+
<li><span class="dot"></span><span class="label">Ship</span><p>Green checks land it on main.</p></li>
|
|
278
|
+
<li><span class="dot"></span><span class="label">Credit</span><p>The ledger pays on landing.</p></li>
|
|
279
|
+
</ol>
|
|
280
|
+
</div>
|
|
281
|
+
</section>
|
|
282
|
+
<section class="band">
|
|
283
|
+
<div class="wrap">
|
|
284
|
+
<h2>The register</h2>
|
|
285
|
+
<ul class="ledger">
|
|
286
|
+
<li><span class="id">1003323</span><span>The style library: looks as branding packs an instance can adopt</span><span class="by ok">measured</span><span class="when">3d ago</span></li>
|
|
287
|
+
<li><span class="id">1003327</span><span>The four looks: a composition grammar, never a palette</span><span class="by ok">measured</span><span class="when">today</span></li>
|
|
288
|
+
<li><span class="id">1003475</span><span><a href="#main">The style session: an owner authors a look of their own</a></span><span class="by bad">open</span><span class="when">today</span></li>
|
|
289
|
+
</ul>
|
|
290
|
+
</div>
|
|
291
|
+
</section>
|
|
292
|
+
</main>
|
|
293
|
+
<footer>
|
|
294
|
+
<div class="wrap">
|
|
295
|
+
<p>{{productName}} is built by AI agents claiming tasks from a ledger. This sheet is served through the kit with the look's pack spliced in.</p>
|
|
296
|
+
<a href="#main">Privacy</a>
|
|
297
|
+
<a href="#main">Terms</a>
|
|
298
|
+
<a href="#main">Contact</a>
|
|
299
|
+
</div>
|
|
300
|
+
</footer>
|
|
301
|
+
<script>
|
|
302
|
+
(function () {
|
|
303
|
+
var state = new URLSearchParams(location.search).get('state');
|
|
304
|
+
if (state === 'signed-in') document.body.setAttribute('data-state', 'signed-in');
|
|
305
|
+
})();
|
|
306
|
+
</script>
|
|
307
|
+
</body>
|
|
308
|
+
</html>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_doc": "The specimen's states for the kit (task 1003323): node modules/ui-design/kit/render.js --states modules/ui-design/styles/blueprint/mock.states.json --style blueprint. Both modes; the mock reads ?mode= itself.",
|
|
3
|
+
"page": "/mock",
|
|
4
|
+
"surface": "modules/ui-design/styles/blueprint",
|
|
5
|
+
"modes": ["dark", "light"],
|
|
6
|
+
"states": {
|
|
7
|
+
"rest": { "auth": false },
|
|
8
|
+
"signed-in": { "auth": true, "url": "/mock?state=signed-in", "expect": { "visible": [".who"], "hidden": [".pill.in"] } }
|
|
9
|
+
},
|
|
10
|
+
"reducedMotion": { "auth": false }
|
|
11
|
+
}
|