@bongos/core 1.19.458 → 1.19.459
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 +98 -28
- package/.claude/skills/design/SKILL.md +10 -0
- package/docs/adr/0219-a-look-is-a-branding-pack-the-style-library.md +30 -0
- package/docs/adr/README.md +1 -0
- package/docs/branding-contract.md +1 -1
- package/docs/file-map.md +1 -1
- package/docs/module-api-changelog.md +2 -0
- package/docs/recipes/ui-look-before-you-ship.md +2 -0
- package/modules/ui-design/kit/README.md +7 -5
- package/modules/ui-design/kit/check-mock.js +12 -5
- package/modules/ui-design/kit/contrast.js +13 -6
- package/modules/ui-design/kit/lib.js +39 -2
- package/modules/ui-design/kit/probe.js +4 -1
- package/modules/ui-design/kit/render.js +7 -4
- package/modules/ui-design/kit/serve.js +9 -2
- package/modules/ui-design/styles/README.md +54 -2
- package/modules/ui-design/styles/chrome-world/DESIGN.md +56 -0
- package/modules/ui-design/styles/chrome-world/mock.html +275 -0
- package/modules/ui-design/styles/chrome-world/mock.states.json +11 -0
- package/modules/ui-design/styles/chrome-world/pack.json +33 -0
- package/modules/ui-design/styles/expedition/DESIGN.md +141 -0
- package/modules/ui-design/styles/expedition/mock.html +285 -0
- package/modules/ui-design/styles/expedition/mock.states.json +11 -0
- package/modules/ui-design/styles/expedition/pack.json +33 -0
- package/modules/ui-design/styles/grove/DESIGN.md +148 -0
- package/modules/ui-design/styles/grove/mock.html +294 -0
- package/modules/ui-design/styles/grove/mock.states.json +11 -0
- package/modules/ui-design/styles/grove/pack.json +33 -0
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/src/module-api.js +1 -1
- package/tests/cosmos_token_contrast.mjs +9 -2
- package/tests/hall_tokens.mjs +15 -6
- package/tests/ui_design_styles.mjs +218 -0
- package/tests/world_tokens.mjs +9 -2
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: The Expedition
|
|
3
|
+
description: A printed field journal. Warm paper under a halftone screen, hairline frames instead of a grid, big heavy neo-grotesque headlines, one lamp yellow that lights only the mark, the primary door and the live step.
|
|
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: "#f4f3ef"
|
|
9
|
+
bg-card: "#ffffff"
|
|
10
|
+
bg-deep: "#e9e7e0"
|
|
11
|
+
bg-frame: "#eceae3"
|
|
12
|
+
ink: "#141412"
|
|
13
|
+
ink-soft: "#55544f"
|
|
14
|
+
ink-faint: "#66645b"
|
|
15
|
+
rule: "#d9d7cf"
|
|
16
|
+
rule-soft: "#e8e6df"
|
|
17
|
+
accent: "#ffd214"
|
|
18
|
+
accent-deep: "#7f6209"
|
|
19
|
+
sea: "#427d97"
|
|
20
|
+
terracotta: "#b4592f"
|
|
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 16% / 8%), 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) 70%, #ffffff)"
|
|
27
|
+
# ---- derived: the accent's jobs. The yellow is a FILL colour and never paints words: every
|
|
28
|
+
# accent-as-text job goes to accent-deep, and the ink that sits ON the yellow is near black.
|
|
29
|
+
accent-ink: "var(--accent-deep)"
|
|
30
|
+
accent-ink-dark: "var(--accent)"
|
|
31
|
+
accent-on: "color-mix(in srgb, var(--accent) 10%, #000000)"
|
|
32
|
+
accent-lift: "color-mix(in srgb, var(--accent) 70%, #ffffff)"
|
|
33
|
+
accent-tint: "color-mix(in srgb, var(--accent) 18%, var(--bg-card))"
|
|
34
|
+
accent-tint-dark: "color-mix(in srgb, var(--accent) 16%, #000000)"
|
|
35
|
+
focus: "var(--accent-deep)"
|
|
36
|
+
focus-dark: "var(--accent)"
|
|
37
|
+
# ---- derived: the print materials
|
|
38
|
+
dots: "rgba(0, 0, 0, .085)"
|
|
39
|
+
dots-dark: "rgba(255, 255, 255, .10)"
|
|
40
|
+
frame: "var(--ink)"
|
|
41
|
+
frame-dark: "rgba(255, 255, 255, .28)"
|
|
42
|
+
glass: "var(--bg-card)"
|
|
43
|
+
glass-dark: "rgba(255, 255, 255, .06)"
|
|
44
|
+
typography:
|
|
45
|
+
display: { fontFamily: "Archivo, Hanken Grotesk, Helvetica Neue, Helvetica, Arial, sans-serif", fontSize: "clamp(38px, 7.2vw, 96px)", fontWeight: 700, lineHeight: 0.92, letterSpacing: "-0.035em", textTransform: "uppercase" }
|
|
46
|
+
headline: { fontFamily: "{typography.display.fontFamily}", fontSize: "clamp(24px, 3vw, 40px)", fontWeight: 600, lineHeight: 1.04, letterSpacing: "-0.025em" }
|
|
47
|
+
body: { fontFamily: "Archivo, Hanken Grotesk, Helvetica Neue, Helvetica, Arial, sans-serif", fontSize: "16px", fontWeight: 400, lineHeight: 1.5 }
|
|
48
|
+
label: { fontFamily: "JetBrains Mono, ui-monospace, Cascadia Mono, Consolas, monospace", fontSize: "11px", fontWeight: 400, letterSpacing: "0.12em", textTransform: "uppercase" }
|
|
49
|
+
mono: { fontFamily: "{typography.label.fontFamily}", fontSize: "13px", fontWeight: 400, fontFeature: "tabular-nums" }
|
|
50
|
+
rounded:
|
|
51
|
+
pill: "999px"
|
|
52
|
+
panel: "0"
|
|
53
|
+
tile: "0"
|
|
54
|
+
spacing:
|
|
55
|
+
dot-pitch: "5px"
|
|
56
|
+
band: "clamp(40px, 7vh, 72px)"
|
|
57
|
+
gutter: "clamp(16px, 4vw, 26px)"
|
|
58
|
+
container: "1180px"
|
|
59
|
+
components:
|
|
60
|
+
mark-plate: { backgroundColor: "{colors.accent}", textColor: "{colors.accent-on}", height: "36px", padding: "0 12px", rounded: "0" }
|
|
61
|
+
door-primary: { backgroundColor: "{colors.accent}", textColor: "{colors.accent-on}", rounded: "{rounded.pill}", height: "48px", padding: "0 28px" }
|
|
62
|
+
door-secondary: { backgroundColor: "transparent", textColor: "{colors.ink}", border: "1px solid {colors.ink}", rounded: "{rounded.pill}", height: "48px" }
|
|
63
|
+
rail-cell-lit: { backgroundColor: "{colors.accent-tint}", textColor: "{colors.ink}" }
|
|
64
|
+
ledger-row: { textColor: "{colors.ink}", padding: "14px 0", border: "1px solid {colors.rule}" }
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
# Style: The Expedition
|
|
68
|
+
|
|
69
|
+
**Origin.** The `natgeo-editorial` candidate of the world round ([task 1003296](https://cloudbongos.com/builders#/task/1003296), `docs/design/mocks/world/natgeo-editorial/`), kept by the owner in round 1 and not picked in round 2. Ported into the style library ([task 1003323](https://cloudbongos.com/builders#/task/1003323)) as a **branding pack**, never a sheet: the thirteen light colours and the two faces in `pack.json`, retuned twice against the contract (ink-faint deepened from `#6f6d64` to `#66645b` so the thinnest pair clears 4.5:1 on the paper; sea lifted from `#2c5464` to `#427d97` for the hall's info state in dark). The candidate's own near-black dark ground (`#0e0e0e`) does not travel: a pack carries light values only, and dark is the sheets' black tier.
|
|
70
|
+
|
|
71
|
+
## Overview
|
|
72
|
+
|
|
73
|
+
**Creative North Star: "The field journal, printed"**
|
|
74
|
+
|
|
75
|
+
A page in this look is a sheet of warm paper that has been through a press. There is a halftone screen over the whole ground, ink and photograph alike, so nothing on the page is perfectly flat; structure is a hairline frame around a compartment rather than a grid of cards; and the type is a neo-grotesque set very large and very heavy for chapter titles, small and grey for everything secondary, in narrow columns. One lamp yellow is the only colour: it is the plate behind the mark, the fill of the primary door, and the cell of the one live step. Nothing else is yellow, which is why the yellow is believed.
|
|
76
|
+
|
|
77
|
+
**Key Characteristics:**
|
|
78
|
+
|
|
79
|
+
- Warm paper (`#f4f3ef`) under a printed dot screen; pure black in dark, where the screen turns to white dots.
|
|
80
|
+
- Frames, not cards: a 1px ink rule around a compartment, corners at 0 on every container.
|
|
81
|
+
- Archivo at 700, uppercase, tight, for the display voice; the same family at 400 in a narrow column for body.
|
|
82
|
+
- One lamp yellow (`accent`) as a fill only; a deep olive (`accent-deep`) wherever the accent must be read.
|
|
83
|
+
- Pills for buttons and discs, zero radius for everything that holds content.
|
|
84
|
+
|
|
85
|
+
## Colors
|
|
86
|
+
|
|
87
|
+
- **Lamp yellow** (`accent`, `#ffd214`): the one colour. It fills the mark's plate, the primary door and the lit rail cell. It **never paints text**: at 1.4:1 against white it cannot, so every accent-as-text job (`accent-ink`, links, the focus ring on paper) is `accent-deep`.
|
|
88
|
+
- **Deep olive** (`accent-deep`, `#7f6209`): the yellow's text-safe twin, 5.18:1 on the paper and 5.75:1 on the card. In dark it is derived (`color-mix(in srgb, var(--accent) 70%, #ffffff)`), never restated.
|
|
89
|
+
- **Ink on yellow** (`accent-on`): `color-mix(in srgb, var(--accent) 10%, #000000)`, a near black warmed by the yellow. White on this yellow would measure 1.4:1 and is banned.
|
|
90
|
+
- **Sea** (`#427d97`) and **Terracotta** (`#b4592f`): held because every pack carries them. Sea is a lake blue the journal may spend on a second voice (a map's water, a diagram); it sits in the narrow 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, and the candidate's deeper `#2c5464` could not carry the dark half. Terracotta is the error and warn source.
|
|
91
|
+
- **Paper, card, deep, frame** (`bg`, `bg-card`, `bg-deep`, `bg-frame`): the ground and its tonal layers. Card is pure white, the only white on the page, so a white compartment reads as a pasted-in photograph.
|
|
92
|
+
- **Ink, ink-soft, ink-faint**: near-black display and body ink, a warm grey for secondary prose, a deeper warm grey for labels. Ink-faint on paper is the thinnest pair (5.34:1); do not lighten it.
|
|
93
|
+
- **Rule, rule-soft**: the hairlines. The frame around a compartment takes `ink` itself (`frame`), not a rule: a frame is structure, a rule is a divider.
|
|
94
|
+
|
|
95
|
+
## Typography
|
|
96
|
+
|
|
97
|
+
**Display Font:** Archivo 700 (with Hanken Grotesk, Helvetica Neue, Helvetica, Arial, sans-serif)
|
|
98
|
+
**Body Font:** Archivo 400/500/600 (same stack)
|
|
99
|
+
**Label / Mono Font:** JetBrains Mono 400 (with ui-monospace, Cascadia Mono, Consolas)
|
|
100
|
+
|
|
101
|
+
**Character:** One neo-grotesque doing two jobs. At display size it is set at 700, uppercase, with tracking pulled to `-0.035em` and line-height under 1, so a headline reads as a printed chapter title. At body size it is plain and set in a narrow column with generous leading. The mono carries the labels on paper; in dark the labels take the grotesque, because mono caps that read as precise on paper read as thin on black.
|
|
102
|
+
|
|
103
|
+
## Shapes
|
|
104
|
+
|
|
105
|
+
**Pill or zero.** Buttons, discs and inputs are full pills. Every container is a rectangle with no radius. There is no third shape. The bar is a hairline rule with the mark on its yellow plate; the rail is five compartments inside one frame; the ledger is the journal's index.
|
|
106
|
+
|
|
107
|
+
## Materials
|
|
108
|
+
|
|
109
|
+
- **The screen.** A radial-gradient dot pattern in black at 8.5% on a 5px pitch over the whole page ground; white at 10% on 4.5px in dark. It is the one texture and it goes over everything.
|
|
110
|
+
- **Frames.** A 1px `frame` rule (ink on paper, white at 28% on black) around a compartment; hairline `rule-soft` dividers inside.
|
|
111
|
+
- **Plates** (when a surface adds them): printed as inverted engravings multiplied into the paper in light; lightened onto black in dark. A surface's plates are its own; this look brings none.
|
|
112
|
+
|
|
113
|
+
## Motion
|
|
114
|
+
|
|
115
|
+
Felt, not seen. State transitions at 200ms on `cubic-bezier(.2,.7,.3,1)`; no ambient loops in this look. The kill switch stands as the platform's.
|
|
116
|
+
|
|
117
|
+
## Do's and Don'ts
|
|
118
|
+
|
|
119
|
+
### Do
|
|
120
|
+
|
|
121
|
+
- **Do** fill with `accent` and write with `accent-deep`; put `accent-on` on any yellow.
|
|
122
|
+
- **Do** frame a compartment with `frame` and divide inside it with `rule-soft`.
|
|
123
|
+
- **Do** keep every container square and every control a pill.
|
|
124
|
+
- **Do** set display type heavy, uppercase and tight; keep body copy in a narrow column.
|
|
125
|
+
- **Do** let the screen show through: a solid panel on the paper is a photograph, not a card.
|
|
126
|
+
|
|
127
|
+
### Don't
|
|
128
|
+
|
|
129
|
+
- **Don't** write words in the lamp yellow, or put white on it.
|
|
130
|
+
- **Don't** round a container, or drop a shadow under one; a frame is the whole elevation system.
|
|
131
|
+
- **Don't** use an em dash or en dash in visible copy, an emoji, gradient text, a coloured text glow, or a trust strip.
|
|
132
|
+
- **Don't** pin the accent, sea or terracotta in a dark block; dark derives.
|
|
133
|
+
- **Don't** declare a `:root` in a page; page tokens live on `body`.
|
|
134
|
+
|
|
135
|
+
## Accessibility Floors
|
|
136
|
+
|
|
137
|
+
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 expedition`).
|
|
138
|
+
|
|
139
|
+
## Adopting this look
|
|
140
|
+
|
|
141
|
+
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 expedition`.
|
|
@@ -0,0 +1,285 @@
|
|
|
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 expedition, 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 expedition's derived tier, by the recipes in this style's DESIGN.md. The fifteen
|
|
14
|
+
arrive from the pack the stub splices after this sheet; nothing below is a colour of its
|
|
15
|
+
own: a var(), a color-mix(), or black or white with alpha. The paper carries a printed
|
|
16
|
+
halftone screen (dots of ink at low alpha) and hairline frames; corners are 0 on every
|
|
17
|
+
container and a pill on every control. */
|
|
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) 70%, #ffffff);
|
|
24
|
+
--accent-tint: color-mix(in srgb, var(--accent) 18%, var(--bg-card));
|
|
25
|
+
--accent-on: color-mix(in srgb, var(--accent) 10%, #000000);
|
|
26
|
+
--accent-glow: 0 0 0 0 transparent;
|
|
27
|
+
--focus: var(--accent-deep);
|
|
28
|
+
--type-halo: none;
|
|
29
|
+
--dots: rgba(0, 0, 0, .085);
|
|
30
|
+
--dot-pitch: 5px;
|
|
31
|
+
--frame: var(--ink);
|
|
32
|
+
--label-face: var(--font-mono);
|
|
33
|
+
--label-size: 11px;
|
|
34
|
+
--label-space: .12em;
|
|
35
|
+
--radius: 0;
|
|
36
|
+
--radius-sm: 0;
|
|
37
|
+
--radius-pill: 999px;
|
|
38
|
+
--top-h: 64px;
|
|
39
|
+
--gutter: clamp(16px, 4vw, 26px);
|
|
40
|
+
--band: clamp(40px, 7vh, 72px);
|
|
41
|
+
margin: 0;
|
|
42
|
+
background: var(--bg);
|
|
43
|
+
background-image: radial-gradient(var(--dots) .9px, transparent 1px);
|
|
44
|
+
background-size: var(--dot-pitch) var(--dot-pitch);
|
|
45
|
+
color: var(--ink);
|
|
46
|
+
font-family: var(--font-body);
|
|
47
|
+
font-size: 16px;
|
|
48
|
+
line-height: 1.5;
|
|
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) 70%, #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) 16%, #000000);
|
|
68
|
+
--focus: var(--accent);
|
|
69
|
+
--dots: rgba(255, 255, 255, .10);
|
|
70
|
+
--dot-pitch: 4.5px;
|
|
71
|
+
--frame: rgba(255, 255, 255, .28);
|
|
72
|
+
--label-face: var(--font-body);
|
|
73
|
+
--label-size: 11.5px;
|
|
74
|
+
--label-space: .1em;
|
|
75
|
+
}
|
|
76
|
+
@media (prefers-color-scheme: dark) {
|
|
77
|
+
:root:not([data-mode="light"]) body {
|
|
78
|
+
color-scheme: dark;
|
|
79
|
+
--bg: #000000;
|
|
80
|
+
--bg-card: color-mix(in srgb, #ffffff 7%, #000000);
|
|
81
|
+
--bg-deep: #000000;
|
|
82
|
+
--bg-frame: color-mix(in srgb, #ffffff 4%, #000000);
|
|
83
|
+
--ink: #ffffff;
|
|
84
|
+
--ink-soft: rgba(255, 255, 255, .72);
|
|
85
|
+
--ink-faint: rgba(255, 255, 255, .62);
|
|
86
|
+
--rule: rgba(255, 255, 255, .18);
|
|
87
|
+
--rule-soft: rgba(255, 255, 255, .09);
|
|
88
|
+
--accent-deep: color-mix(in srgb, var(--accent) 70%, #ffffff);
|
|
89
|
+
--glass: rgba(255, 255, 255, .06);
|
|
90
|
+
--glass-strong: rgba(255, 255, 255, .12);
|
|
91
|
+
--glass-edge: rgba(255, 255, 255, .18);
|
|
92
|
+
--accent-ink: var(--accent);
|
|
93
|
+
--accent-tint: color-mix(in srgb, var(--accent) 16%, #000000);
|
|
94
|
+
--focus: var(--accent);
|
|
95
|
+
--dots: rgba(255, 255, 255, .10);
|
|
96
|
+
--dot-pitch: 4.5px;
|
|
97
|
+
--frame: rgba(255, 255, 255, .28);
|
|
98
|
+
--label-face: var(--font-body);
|
|
99
|
+
--label-size: 11.5px;
|
|
100
|
+
--label-space: .1em;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
*, *::before, *::after { box-sizing: border-box; }
|
|
105
|
+
a { color: inherit; }
|
|
106
|
+
:focus-visible { outline: 2px solid var(--focus); outline-offset: 3px; }
|
|
107
|
+
.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; }
|
|
108
|
+
.skip:focus { top: 12px; }
|
|
109
|
+
.wrap { max-width: 1180px; margin: 0 auto; padding: 0 var(--gutter); }
|
|
110
|
+
|
|
111
|
+
/* the framed bar: a hairline rule, a yellow plate behind the mark */
|
|
112
|
+
.bar { height: var(--top-h); border-bottom: 1px solid var(--frame); background: var(--bg); }
|
|
113
|
+
.bar .wrap { height: 100%; display: flex; align-items: center; gap: 18px; }
|
|
114
|
+
.mark { display: inline-flex; align-items: center; height: 36px; padding: 0 12px; background: var(--accent); color: var(--accent-on); font-weight: 700; letter-spacing: -.01em; text-transform: uppercase; font-size: 14px; text-decoration: none; }
|
|
115
|
+
.nav { margin-left: auto; display: flex; align-items: center; gap: 4px; }
|
|
116
|
+
.nav a { text-decoration: none; text-transform: uppercase; font-family: var(--label-face); font-size: 12px; letter-spacing: .1em; color: var(--ink-soft); padding: 14px 10px; display: inline-block; line-height: 16px; }
|
|
117
|
+
.nav a:hover { color: var(--ink); }
|
|
118
|
+
.pill { display: inline-flex; align-items: center; height: 46px; padding: 0 22px; border-radius: var(--radius-pill); text-decoration: none; font-weight: 600; letter-spacing: 0; text-transform: none; font-family: var(--font-body); font-size: 15px; transition: background-color 200ms cubic-bezier(.2, .7, .3, 1); }
|
|
119
|
+
.pill.in { background: var(--ink); color: var(--bg); }
|
|
120
|
+
.who { display: none; align-items: center; gap: 8px; height: 46px; padding: 0 6px; border-radius: var(--radius-pill); border: 1px solid var(--rule); }
|
|
121
|
+
.who .dot { width: 30px; height: 30px; border-radius: 50%; background: var(--bg-deep); border: 1px solid var(--rule); }
|
|
122
|
+
body[data-state="signed-in"] .pill.in { display: none; }
|
|
123
|
+
body[data-state="signed-in"] .who { display: inline-flex; }
|
|
124
|
+
|
|
125
|
+
/* the bands: framed columns, not padded cards */
|
|
126
|
+
.band { padding: var(--band) 0; border-top: 1px solid var(--rule); }
|
|
127
|
+
.band:first-of-type { border-top: 0; }
|
|
128
|
+
h1 { font-family: var(--font-display); font-weight: 700; font-size: clamp(38px, 7.2vw, 96px); line-height: .92; letter-spacing: -.035em; text-transform: uppercase; margin: 0 0 18px; max-width: 12ch; }
|
|
129
|
+
h2 { font-family: var(--font-display); font-weight: 600; font-size: clamp(24px, 3vw, 40px); line-height: 1.04; letter-spacing: -.025em; margin: 0 0 14px; }
|
|
130
|
+
.lede { color: var(--ink-soft); max-width: 52ch; margin: 0; font-size: 15px; }
|
|
131
|
+
.label { font-family: var(--label-face); font-size: var(--label-size); letter-spacing: var(--label-space); text-transform: uppercase; color: var(--ink-faint); }
|
|
132
|
+
.kicker { display: inline-block; border-left: 3px solid var(--accent); padding-left: 10px; margin-bottom: 14px; }
|
|
133
|
+
|
|
134
|
+
/* the thirteen, as a specimen strip inside a frame */
|
|
135
|
+
.sw { display: grid; grid-template-columns: repeat(auto-fill, minmax(72px, 1fr)); gap: 0; margin: 0; padding: 0; list-style: none; border: 1px solid var(--frame); }
|
|
136
|
+
.sw li { margin: 0; padding: 10px; border-right: 1px solid var(--rule-soft); border-bottom: 1px solid var(--rule-soft); }
|
|
137
|
+
.sw i { display: block; height: 52px; border: 1px solid var(--rule); background: var(--c); }
|
|
138
|
+
.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; }
|
|
139
|
+
|
|
140
|
+
/* the door pair: pills on paper, the primary in lamp yellow */
|
|
141
|
+
.doors { display: inline-flex; flex-wrap: wrap; gap: 8px; }
|
|
142
|
+
.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 200ms cubic-bezier(.2, .7, .3, 1); }
|
|
143
|
+
.door.go { background: var(--accent); color: var(--accent-on); }
|
|
144
|
+
.door.go:hover { background: var(--accent-lift); }
|
|
145
|
+
.door.more { color: var(--ink); border: 1px solid var(--ink); }
|
|
146
|
+
.door.more:hover { background: var(--glass-strong); }
|
|
147
|
+
|
|
148
|
+
/* the lifecycle rail: compartments with a visible frame */
|
|
149
|
+
.rail { display: grid; grid-template-columns: repeat(5, 1fr); gap: 0; margin: 0; padding: 0; list-style: none; border: 1px solid var(--frame); }
|
|
150
|
+
.rail li { padding: 14px; border-right: 1px solid var(--rule-soft); }
|
|
151
|
+
.rail li:last-child { border-right: 0; }
|
|
152
|
+
.rail .dot { display: block; width: 8px; height: 8px; border: 1px solid var(--ink-faint); margin-bottom: 10px; }
|
|
153
|
+
.rail .lit { background: var(--accent-tint); }
|
|
154
|
+
.rail .lit .dot { background: var(--accent); border-color: var(--accent-deep); }
|
|
155
|
+
.rail .lit .label { color: var(--ink); }
|
|
156
|
+
.rail p { margin: 6px 0 0; color: var(--ink-soft); font-size: 14px; }
|
|
157
|
+
|
|
158
|
+
/* ledger rows: the journal's index */
|
|
159
|
+
.ledger { margin: 0; padding: 0; list-style: none; border-top: 1px solid var(--frame); }
|
|
160
|
+
.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); }
|
|
161
|
+
.ledger .id { font-family: var(--font-mono); font-size: 13px; color: var(--ink-faint); font-variant-numeric: tabular-nums; }
|
|
162
|
+
.ledger .by, .ledger .when { color: var(--ink-soft); font-size: 15px; }
|
|
163
|
+
.ledger .when { text-align: right; font-variant-numeric: tabular-nums; }
|
|
164
|
+
.ledger a { color: var(--accent-ink); text-underline-offset: 3px; display: inline-block; padding: 2px 0; }
|
|
165
|
+
|
|
166
|
+
footer { border-top: 1px solid var(--frame); padding: 26px 0 40px; }
|
|
167
|
+
footer .wrap { display: flex; flex-wrap: wrap; gap: 8px 22px; align-items: baseline; color: var(--ink-soft); font-size: 14px; }
|
|
168
|
+
footer p { margin: 0; flex: 1 1 320px; }
|
|
169
|
+
footer a { color: var(--accent-ink); display: inline-block; padding: 4px 0; font-family: var(--label-face); font-size: 12px; letter-spacing: .08em; text-transform: uppercase; }
|
|
170
|
+
|
|
171
|
+
@media (max-width: 900px) {
|
|
172
|
+
body { --top-h: 60px; }
|
|
173
|
+
.rail { grid-template-columns: 1fr; }
|
|
174
|
+
.rail li { border-right: 0; border-bottom: 1px solid var(--rule-soft); }
|
|
175
|
+
.rail li:last-child { border-bottom: 0; }
|
|
176
|
+
}
|
|
177
|
+
@media (max-width: 600px) {
|
|
178
|
+
.ledger li { grid-template-columns: 1fr; gap: 4px; }
|
|
179
|
+
.ledger .when { text-align: left; }
|
|
180
|
+
.nav a { display: none; }
|
|
181
|
+
}
|
|
182
|
+
@media (prefers-reduced-motion: reduce) {
|
|
183
|
+
*, *::before, *::after { animation: none !important; transition: none !important; }
|
|
184
|
+
}
|
|
185
|
+
</style>
|
|
186
|
+
</head>
|
|
187
|
+
<body>
|
|
188
|
+
<!-- THESIS: the expedition 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 framed bar with the mark on a yellow plate, an uppercase neo-grotesque display voice, a halftone screen printed over the paper, door pills with the primary in lamp yellow, a compartmented rail with one lit cell, the journal's index as ledger rows. This page declares no :root and no colour of its own: the pack is spliced by the stub (STYLE=expedition) 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 yellow and its faces, which is all a pack carries. STATES: rest (signed out), signed-in. MODES: ?mode=dark|light. -->
|
|
189
|
+
<a class="skip" href="#main">Skip to content</a>
|
|
190
|
+
<header class="bar">
|
|
191
|
+
<div class="wrap">
|
|
192
|
+
<a class="mark" href="/">{{productName}}</a>
|
|
193
|
+
<nav class="nav" aria-label="Primary">
|
|
194
|
+
<a href="#swatches">Projects</a>
|
|
195
|
+
<a href="#type">Docs</a>
|
|
196
|
+
<a class="pill in" href="#main">Sign in</a>
|
|
197
|
+
<span class="who"><span class="dot" aria-hidden="true"></span><span class="label">builder</span></span>
|
|
198
|
+
</nav>
|
|
199
|
+
</div>
|
|
200
|
+
</header>
|
|
201
|
+
<main id="main" tabindex="-1">
|
|
202
|
+
<section class="band">
|
|
203
|
+
<div class="wrap">
|
|
204
|
+
<p class="label kicker">A look from the style library</p>
|
|
205
|
+
<h1>The expedition</h1>
|
|
206
|
+
<p class="lede">A printed field journal. Warm paper under a halftone screen, hairline frames instead of a grid, headlines set big and heavy, and one lamp yellow that lights only the mark, the primary door and the live step.</p>
|
|
207
|
+
</div>
|
|
208
|
+
</section>
|
|
209
|
+
<section class="band" id="swatches">
|
|
210
|
+
<div class="wrap">
|
|
211
|
+
<h2>The thirteen</h2>
|
|
212
|
+
<ul class="sw">
|
|
213
|
+
<li><i style="--c: var(--bg)"></i><b>bg</b></li>
|
|
214
|
+
<li><i style="--c: var(--bg-card)"></i><b>bg-card</b></li>
|
|
215
|
+
<li><i style="--c: var(--bg-deep)"></i><b>bg-deep</b></li>
|
|
216
|
+
<li><i style="--c: var(--bg-frame)"></i><b>bg-frame</b></li>
|
|
217
|
+
<li><i style="--c: var(--ink)"></i><b>ink</b></li>
|
|
218
|
+
<li><i style="--c: var(--ink-soft)"></i><b>ink-soft</b></li>
|
|
219
|
+
<li><i style="--c: var(--ink-faint)"></i><b>ink-faint</b></li>
|
|
220
|
+
<li><i style="--c: var(--rule)"></i><b>rule</b></li>
|
|
221
|
+
<li><i style="--c: var(--rule-soft)"></i><b>rule-soft</b></li>
|
|
222
|
+
<li><i style="--c: var(--accent)"></i><b>accent</b></li>
|
|
223
|
+
<li><i style="--c: var(--accent-deep)"></i><b>accent-deep</b></li>
|
|
224
|
+
<li><i style="--c: var(--sea)"></i><b>sea</b></li>
|
|
225
|
+
<li><i style="--c: var(--terracotta)"></i><b>terracotta</b></li>
|
|
226
|
+
</ul>
|
|
227
|
+
</div>
|
|
228
|
+
</section>
|
|
229
|
+
<section class="band" id="type">
|
|
230
|
+
<div class="wrap">
|
|
231
|
+
<h2>One grotesque, three sizes</h2>
|
|
232
|
+
<p class="lede">The display face is a neo-grotesque set heavy and uppercase at display size, the way a journal prints its chapter titles. Body copy is the same family at reading weight in a narrow column. Labels take the mono on paper and the grotesque in dark.</p>
|
|
233
|
+
<p class="label" style="margin-top: 22px">Label face, tracked and uppercase</p>
|
|
234
|
+
<p style="margin: 6px 0 0; font-family: var(--font-mono); font-size: 13px; font-variant-numeric: tabular-nums">1003323 · 14,987 credits · 7 ships in 24h</p>
|
|
235
|
+
</div>
|
|
236
|
+
</section>
|
|
237
|
+
<section class="band">
|
|
238
|
+
<div class="wrap">
|
|
239
|
+
<h2>The doors</h2>
|
|
240
|
+
<p class="lede" style="margin-bottom: 22px">Two pills side by side. The primary is the lamp yellow with near-black ink on it; the secondary is a hairline outline, filled only on hover.</p>
|
|
241
|
+
<div class="doors">
|
|
242
|
+
<a class="door more" href="#swatches">Open the map</a>
|
|
243
|
+
<a class="door go" href="#main">Start a project</a>
|
|
244
|
+
</div>
|
|
245
|
+
</div>
|
|
246
|
+
</section>
|
|
247
|
+
<section class="band">
|
|
248
|
+
<div class="wrap">
|
|
249
|
+
<h2>The lifecycle rail</h2>
|
|
250
|
+
<ol class="rail">
|
|
251
|
+
<li><span class="dot"></span><span class="label">Claim</span><p>A builder locks a task.</p></li>
|
|
252
|
+
<li><span class="dot"></span><span class="label">Build</span><p>The code is written in a worktree.</p></li>
|
|
253
|
+
<li class="lit" aria-current="step"><span class="dot"></span><span class="label">Grade</span><p>An adversarial panel reads the diff.</p></li>
|
|
254
|
+
<li><span class="dot"></span><span class="label">Ship</span><p>Green checks land it on main.</p></li>
|
|
255
|
+
<li><span class="dot"></span><span class="label">Credit</span><p>The ledger pays on landing.</p></li>
|
|
256
|
+
</ol>
|
|
257
|
+
</div>
|
|
258
|
+
</section>
|
|
259
|
+
<section class="band">
|
|
260
|
+
<div class="wrap">
|
|
261
|
+
<h2>Ledger rows</h2>
|
|
262
|
+
<ul class="ledger">
|
|
263
|
+
<li><span class="id">1003320</span><span>The look-before-you-ship kit: a stub, a renderer, the probes</span><span class="by">jaxri</span><span class="when">3d ago</span></li>
|
|
264
|
+
<li><span class="id">1003321</span><span>The vetted UI skills: the vendoring policy and the platform preamble</span><span class="by">jaxri</span><span class="when">3d ago</span></li>
|
|
265
|
+
<li><span class="id">1003323</span><span><a href="#main">The style library: looks as branding packs</a></span><span class="by">jaxri</span><span class="when">today</span></li>
|
|
266
|
+
</ul>
|
|
267
|
+
</div>
|
|
268
|
+
</section>
|
|
269
|
+
</main>
|
|
270
|
+
<footer>
|
|
271
|
+
<div class="wrap">
|
|
272
|
+
<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>
|
|
273
|
+
<a href="#main">Privacy</a>
|
|
274
|
+
<a href="#main">Terms</a>
|
|
275
|
+
<a href="#main">Contact</a>
|
|
276
|
+
</div>
|
|
277
|
+
</footer>
|
|
278
|
+
<script>
|
|
279
|
+
(function () {
|
|
280
|
+
var state = new URLSearchParams(location.search).get('state');
|
|
281
|
+
if (state === 'signed-in') document.body.setAttribute('data-state', 'signed-in');
|
|
282
|
+
})();
|
|
283
|
+
</script>
|
|
284
|
+
</body>
|
|
285
|
+
</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/expedition/mock.states.json --style expedition. Both modes; the mock reads ?mode= itself.",
|
|
3
|
+
"page": "/mock",
|
|
4
|
+
"surface": "modules/ui-design/styles/expedition",
|
|
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
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_doc": "A look from the ui-design module's style library (task 1003323): the theme.ui overlay a branding pack carries, and nothing else. The stub lays it over the instance's pack (STYLE=expedition); an instance adopts it by copying `theme` into config/branding.json. Light values only, as the contract says: dark is each sheet's own black tier, which this look reaches through the accent and the faces.",
|
|
3
|
+
"name": "expedition",
|
|
4
|
+
"title": "The Expedition",
|
|
5
|
+
"summary": "A printed field journal: warm paper, hairline frames instead of a grid, big neo-grotesque headlines, one lamp yellow that lights only the pressable and the live.",
|
|
6
|
+
"origin": "docs/design/mocks/world/natgeo-editorial (the world round, task 1003296; kept by the owner in round 1, retuned to the contract here: ink-faint deepened to #66645b so the thinnest pair clears 4.5:1 on paper, and sea lifted from #2c5464 to #427d97 because the hall derives its info state from sea at 80% into white in dark, which the deep lake blue could not carry on black)",
|
|
7
|
+
"theme": {
|
|
8
|
+
"ui": {
|
|
9
|
+
"colors": {
|
|
10
|
+
"bg": "#f4f3ef",
|
|
11
|
+
"bgCard": "#ffffff",
|
|
12
|
+
"bgDeep": "#e9e7e0",
|
|
13
|
+
"bgFrame": "#eceae3",
|
|
14
|
+
"ink": "#141412",
|
|
15
|
+
"inkSoft": "#55544f",
|
|
16
|
+
"inkFaint": "#66645b",
|
|
17
|
+
"rule": "#d9d7cf",
|
|
18
|
+
"ruleSoft": "#e8e6df",
|
|
19
|
+
"accent": "#ffd214",
|
|
20
|
+
"accentDeep": "#7f6209",
|
|
21
|
+
"sea": "#427d97",
|
|
22
|
+
"terracotta": "#b4592f"
|
|
23
|
+
},
|
|
24
|
+
"fonts": {
|
|
25
|
+
"display": "\"Archivo\", \"Hanken Grotesk\", \"Helvetica Neue\", Helvetica, Arial, sans-serif",
|
|
26
|
+
"body": "\"Archivo\", \"Hanken Grotesk\", \"Helvetica Neue\", Helvetica, Arial, sans-serif",
|
|
27
|
+
"links": [
|
|
28
|
+
"https://fonts.googleapis.com/css2?family=Archivo:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400&display=swap"
|
|
29
|
+
]
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: The Grove
|
|
3
|
+
description: A sculpted paper garden. Pale sage paper, soft corners on everything that holds content, shadows tinted from the ink and never grey, the sea green as a second voice, one lit tan on everything pressable.
|
|
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: "#e1eadb"
|
|
9
|
+
bg-card: "#f6f9f3"
|
|
10
|
+
bg-deep: "#cad8c2"
|
|
11
|
+
bg-frame: "#eaf0e5"
|
|
12
|
+
ink: "#0f3226"
|
|
13
|
+
ink-soft: "#2f5240"
|
|
14
|
+
ink-faint: "#3f5a48"
|
|
15
|
+
rule: "#9db69a"
|
|
16
|
+
rule-soft: "#d0ddcb"
|
|
17
|
+
accent: "#e3c39c"
|
|
18
|
+
accent-deep: "#6d4b34"
|
|
19
|
+
sea: "#3d8562"
|
|
20
|
+
terracotta: "#b07a4e"
|
|
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, which the look reaches through the tan, the sea and the faces.
|
|
23
|
+
# The candidate's own green dark ground (#2f6049) cannot travel in a pack.
|
|
24
|
+
bg-dark: "#000000"
|
|
25
|
+
ink-dark: "#ffffff"
|
|
26
|
+
accent-deep-dark: "color-mix(in srgb, var(--accent) 70%, #ffffff)"
|
|
27
|
+
# ---- derived: the four fields. Sea is the SLAB (a whole band sits on it), bark (accent-deep)
|
|
28
|
+
# is every quiet mark and every accent-as-text job, tan (accent) is the lit thing, wood
|
|
29
|
+
# (terracotta) is held for a small drum's shell and for warn / err. The slab's field is the
|
|
30
|
+
# sea deepened 38% into black in BOTH modes: the contract's sea sits in the lightness band
|
|
31
|
+
# the hall's info state needs, and a slab that cream can be read on is darker than that.
|
|
32
|
+
accent-ink: "var(--accent-deep)"
|
|
33
|
+
accent-ink-dark: "var(--accent)"
|
|
34
|
+
accent-on: "color-mix(in srgb, var(--accent) 12%, #000000)"
|
|
35
|
+
accent-lift: "color-mix(in srgb, var(--accent) 72%, #ffffff)"
|
|
36
|
+
accent-tint: "color-mix(in srgb, var(--accent) 34%, var(--bg-card))"
|
|
37
|
+
accent-tint-dark: "color-mix(in srgb, var(--accent) 18%, #000000)"
|
|
38
|
+
field: "color-mix(in srgb, var(--sea) 62%, #000000)"
|
|
39
|
+
on-field: "color-mix(in srgb, var(--accent) 55%, #ffffff)"
|
|
40
|
+
on-field-soft: "color-mix(in srgb, var(--accent) 40%, #ffffff)"
|
|
41
|
+
field-rule: "color-mix(in srgb, #ffffff 20%, transparent)"
|
|
42
|
+
focus: "var(--accent-deep)"
|
|
43
|
+
focus-dark: "var(--accent)"
|
|
44
|
+
# ---- derived: the sculpted paper. Shadows are TINTED from the ink, never grey.
|
|
45
|
+
shade: "color-mix(in srgb, var(--ink) 16%, transparent)"
|
|
46
|
+
shade-soft: "color-mix(in srgb, var(--ink) 7%, transparent)"
|
|
47
|
+
shade-dark: "rgba(0, 0, 0, .6)"
|
|
48
|
+
shade-soft-dark: "rgba(0, 0, 0, .35)"
|
|
49
|
+
typography:
|
|
50
|
+
display: { fontFamily: "Nunito, Trebuchet MS, system-ui, sans-serif", fontSize: "clamp(34px, 6.4vw, 84px)", fontWeight: 800, lineHeight: 0.96, letterSpacing: "-0.03em" }
|
|
51
|
+
headline: { fontFamily: "{typography.display.fontFamily}", fontSize: "clamp(24px, 3vw, 38px)", fontWeight: 800, lineHeight: 1.08, letterSpacing: "-0.02em" }
|
|
52
|
+
body: { fontFamily: "Nunito, Trebuchet MS, system-ui, sans-serif", fontSize: "17px", fontWeight: 400, lineHeight: 1.55 }
|
|
53
|
+
label: { fontFamily: "JetBrains Mono, ui-monospace, Cascadia Mono, Consolas, monospace", fontSize: "11px", fontWeight: 500, letterSpacing: "0.08em", textTransform: "uppercase" }
|
|
54
|
+
mono: { fontFamily: "{typography.label.fontFamily}", fontSize: "13px", fontWeight: 400, fontFeature: "tabular-nums" }
|
|
55
|
+
rounded:
|
|
56
|
+
pill: "999px"
|
|
57
|
+
panel: "22px"
|
|
58
|
+
tile: "12px"
|
|
59
|
+
spacing:
|
|
60
|
+
band: "clamp(40px, 7vh, 72px)"
|
|
61
|
+
gutter: "clamp(16px, 4vw, 26px)"
|
|
62
|
+
container: "1180px"
|
|
63
|
+
components:
|
|
64
|
+
bar-card: { backgroundColor: "{colors.bg-card}", rounded: "{rounded.pill}", shadow: "0 10px 26px -14px {colors.shade}, 0 2px 6px {colors.shade-soft}" }
|
|
65
|
+
door-primary: { backgroundColor: "{colors.accent}", textColor: "{colors.accent-on}", rounded: "{rounded.pill}", height: "48px", padding: "0 28px" }
|
|
66
|
+
door-secondary: { backgroundColor: "transparent", textColor: "{colors.ink}", rounded: "{rounded.pill}", height: "48px" }
|
|
67
|
+
sign-in: { backgroundColor: "{colors.field}", textColor: "{colors.on-field}", rounded: "{rounded.pill}", height: "42px" }
|
|
68
|
+
slab: { backgroundColor: "{colors.field}", textColor: "{colors.on-field}", rounded: "{rounded.panel}" }
|
|
69
|
+
tile: { backgroundColor: "{colors.bg-card}", rounded: "{rounded.tile}", padding: "16px" }
|
|
70
|
+
badge: { backgroundColor: "{colors.accent-tint}", textColor: "{colors.accent-ink}", rounded: "{rounded.tile}", height: "26px" }
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
# Style: The Grove
|
|
74
|
+
|
|
75
|
+
**Origin.** The `organic-cards` candidate of the world round ([task 1003296](https://cloudbongos.com/builders#/task/1003296), `docs/design/mocks/world/organic-cards/`), kept by the owner in round 1 and not picked in round 2. Ported into the style library ([task 1003323](https://cloudbongos.com/builders#/task/1003323)) as a **branding pack**, never a sheet: the thirteen light colours and the two faces in `pack.json`, retuned against the contract. The retune is a measurement, not a taste: the candidate's sage ground (`#c8d7bf`) put the hub's fixed status vocabulary and the hall's chips under 4.5:1, so the ground lifted to `#e1eadb` and the inks deepened until every pair the three sheets paint cleared. The candidate's green **dark** ground (`#2f6049`) cannot travel in a pack (a pack carries light values only); in dark this look is the sheets' black under the tan and the sea.
|
|
76
|
+
|
|
77
|
+
## Overview
|
|
78
|
+
|
|
79
|
+
**Creative North Star: "A sculpted paper garden"**
|
|
80
|
+
|
|
81
|
+
Everything in this look is cut from soft paper and set down in a garden. Containers have real corners (22px on a panel, 12px on a tile, a pill on anything pressable), they lift off the ground on a shadow that is tinted from the ink and never grey, and the ground itself is a pale sage rather than white. Three named fields carry the system: sea green as a slab a whole band can sit on, bark brown for every quiet mark, and a lit tan on everything that can be pressed. Type is a rounded, wide-aperture face set heavy for headlines and plain for body.
|
|
82
|
+
|
|
83
|
+
**Key Characteristics:**
|
|
84
|
+
|
|
85
|
+
- Pale sage paper (`#e1eadb`); pure black in dark, where the tan and the slab do the work.
|
|
86
|
+
- Soft corners on everything that holds content; pills on everything pressable.
|
|
87
|
+
- Tinted shadows mixed from the ink; a hairline only where a shadow would be too much.
|
|
88
|
+
- Nunito 800 for display, 400 for body, JetBrains Mono for labels on paper.
|
|
89
|
+
- The sea green as a field, not an accent; the tan as the one lit thing.
|
|
90
|
+
|
|
91
|
+
## Colors
|
|
92
|
+
|
|
93
|
+
- **Tan** (`accent`, `#e3c39c`): the lit thing. It fills the primary door, the identity disc and the lit rail tile. It is a fill colour: at 1.6:1 against white it never paints words, so every accent-as-text job is `accent-deep`.
|
|
94
|
+
- **Bark** (`accent-deep`, `#6d4b34`): every quiet mark, every link, the badge's ink, 6.01:1 on the sage and 7.17:1 on the card. In dark it derives from the tan, never restated.
|
|
95
|
+
- **Ink on tan** (`accent-on`): `color-mix(in srgb, var(--accent) 12%, #000000)`, a near black warmed by the tan.
|
|
96
|
+
- **Sea** (`#3d8562`): the second voice. The contract's sea sits in the narrow lightness band the hall's info state needs (sea at 80% into white in dark, 86% into black in light), so the candidate's deep `#2a5a46` could not travel; the **slab** derives its field from it, `color-mix(in srgb, var(--sea) 62%, #000000)`, a deep green a whole band sits on with cream type (`on-field`: the tan mixed 55% into white, above 6:1). The sign-in door takes the field too, so the bar has one green thing.
|
|
97
|
+
- **Wood** (`terracotta`, `#b07a4e`): held for a small drum's shell and as the warn / error source.
|
|
98
|
+
- **Sage, card, deep, frame** (`bg`, `bg-card`, `bg-deep`, `bg-frame`): the ground and its layers. Card is a near-white with a green cast, so a tile reads as paper on paper, not white on green.
|
|
99
|
+
- **Ink, ink-soft, ink-faint**: deep forest inks. Ink-faint on the sage is 5.88:1; it was deepened from the candidate's `#476350` (4.29:1), the pair that failed first.
|
|
100
|
+
- **Rule, rule-soft**: the sage's own hairlines, for the rare divider a shadow cannot do.
|
|
101
|
+
|
|
102
|
+
## Typography
|
|
103
|
+
|
|
104
|
+
**Display Font:** Nunito 800 (with Trebuchet MS, system-ui, sans-serif)
|
|
105
|
+
**Body Font:** Nunito 400/600 (same stack)
|
|
106
|
+
**Label / Mono Font:** JetBrains Mono 400/500 (with ui-monospace, Cascadia Mono, Consolas)
|
|
107
|
+
|
|
108
|
+
**Character:** A rounded, wide-aperture humanist sans that is friendly at every size. Display is set at 800 with tracking pulled to `-0.03em`, sentence case: the grove never shouts. Labels take the mono on paper, at a looser `0.08em` than the chrome world, and the body face in dark.
|
|
109
|
+
|
|
110
|
+
## Shapes
|
|
111
|
+
|
|
112
|
+
**All soft.** 22px on panels and slabs, 12px on tiles and badges, a pill on every door, chip and input. The bar itself is a pill-shaped card floating on the sage. There is no square corner anywhere in this look.
|
|
113
|
+
|
|
114
|
+
## Materials
|
|
115
|
+
|
|
116
|
+
- **Tinted shadows.** `0 10px 26px -14px shade, 0 2px 6px shade-soft`, where `shade` is the ink at 16% and `shade-soft` the ink at 7%; in dark, black at 60% and 35%. Grey shadows are banned: a shadow is the ground's own colour, deepened.
|
|
117
|
+
- **The slab.** A deep-green panel (the sea mixed 62% into black, the same in both modes) with cream type and a 20%-white hairline inside it.
|
|
118
|
+
- **Plates** (when a surface adds them): photographic leaf plates over the paper, a real-alpha hero object. A surface's plates are its own; this look brings none.
|
|
119
|
+
|
|
120
|
+
## Motion
|
|
121
|
+
|
|
122
|
+
Gentle. Entry motion at 200ms on `cubic-bezier(.2,.7,.3,1)`; a tile lifts 2px on hover; no ambient loops in this look. The kill switch stands as the platform's.
|
|
123
|
+
|
|
124
|
+
## Do's and Don'ts
|
|
125
|
+
|
|
126
|
+
### Do
|
|
127
|
+
|
|
128
|
+
- **Do** fill with `accent` and write with `accent-deep`; put `accent-on` on any tan.
|
|
129
|
+
- **Do** tint every drop from the ink; keep the two-part lift recipe as the one elevation.
|
|
130
|
+
- **Do** spend the sea as a field, one slab per view at most.
|
|
131
|
+
- **Do** round everything: 22 / 12 / pill.
|
|
132
|
+
- **Do** keep the label face mono on paper and the body face in dark.
|
|
133
|
+
|
|
134
|
+
### Don't
|
|
135
|
+
|
|
136
|
+
- **Don't** write words in the tan, or put white on it.
|
|
137
|
+
- **Don't** use an em dash or en dash in visible copy, an emoji, gradient text, or a coloured text glow.
|
|
138
|
+
- **Don't** put a square corner on a container, or a hairline where a lift would do.
|
|
139
|
+
- **Don't** pin the accent, sea or terracotta in a dark block; dark derives.
|
|
140
|
+
- **Don't** declare a `:root` in a page; page tokens live on `body`.
|
|
141
|
+
|
|
142
|
+
## Accessibility Floors
|
|
143
|
+
|
|
144
|
+
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 doors are 48, the sign-in pill 42); 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 grove`).
|
|
145
|
+
|
|
146
|
+
## Adopting this look
|
|
147
|
+
|
|
148
|
+
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; the surfaces keep their hairlines, since a corner radius and a shadow are a sheet's derived tier, not a pack's. Look before you ship: `node modules/ui-design/kit/render.js --page / --style grove`.
|