返回 CodeWhale
tokens-roles.css
根目录 / web / app / styles / tokens-roles.css
1 /* ------------------------------------------------------------------ */
2 /* Tokens and roles — the whale-road */
3 /* ------------------------------------------------------------------ */
4 /*
5 * Direction: codewhale-design/DIRECTION.md. Token authority:
6 * vendor/codewhale-design/tokens.json (1.1.x), generated into ../tokens.css
7 * as `--gpui-light-*` / `--gpui-dark-*`. This file names the roles every
8 * page paints with.
9 *
10 * The ocean. Dark is the preferred look: deep navy grounds that rise into
11 * the logo's gradient (#1E8FD8 -> #0B48BB). Light is warm paper above one
12 * calm horizon. Below the horizon (the footer, the home sea) is always
13 * the deep water, in both appearances (`.stage`).
14 *
15 * Depth is elevation. --panel is raised (nearer the surface, lighter);
16 * --bg is the floor; --surface is recessed (code, rails, fields).
17 *
18 * Light means something. Focus, live work and "needs you" carry a small
19 * point of light (--glow). Nothing else glows.
20 *
21 * State is a mark and a word: --live (working, done, ready), --attention
22 * (needs you), --danger (failed), --muted (idle). Never colour alone.
23 *
24 * Text, accent and state inks are the generated GPUI tokens in both
25 * appearances. The navy grounds are this site's reach for the ombre; they
26 * are measured against every ink here (gpui-role-tokens.test.ts checks
27 * WCAG AA on every ground).
28 *
29 * NAMING TRAP: tokens.json `surface` is the RAISED colour (web --panel);
30 * tokens.json `sidebar` is the RECESSED one (web --surface).
31 */
32
33 /* ---------- scheme-independent tokens ---------- */
34 :root {
35 /* The ocean: the navy grounds and the logo gradient. */
36 --ocean-abyss: #030a1c;
37 --ocean-floor: #061431;
38 --ocean-raised: #0c2152;
39 --ocean-hover: #11295e;
40 --ocean-selected: #16316b;
41 --ocean-line: #1f3a78;
42 --ocean-line-strong: #6f86b8;
43 --ocean-sky: #0a1d48;
44 --brand-light: #1e8fd8;
45 --brand-deep: #0b48bb;
46 /* The primary fill: the logo gradient, started where white text on it
47 still clears 4.5:1 (#1877c9 is 4.65:1; #1e8fd8 itself is 3.5:1). */
48 --brand-fill: linear-gradient(135deg, #1877c9, var(--brand-deep));
49 --brand-fill-hover: linear-gradient(135deg, #1670c2, #0a3fa6);
50 --on-brand: #ffffff;
51 /* The sea, one ramp from the logo's deep blue at the surface to the
52 floor. It settles within a few rows so text from 3rem down sits on
53 >= 4.5:1 muted contrast; it is never a bright wall. */
54 --sea-surface: var(--brand-deep);
55 --sea-shallow: #0a3a94;
56 --sea-mid: #072a6e;
57 --sea: linear-gradient(180deg, var(--sea-shallow) 0, var(--sea-mid) 5rem, var(--ocean-floor) 22rem);
58 --sea-band: linear-gradient(180deg, var(--sea-shallow) 0, var(--sea-mid) 40%, var(--ocean-floor) 100%);
59 /* The tide (the merch's Tide ombré): paper, light aqua, cobalt, then the
60 deep. Headings start past the logo-deep stop (7rem), where text ink
61 clears 4.5:1; muted ink only appears past the mid stop (11rem). */
62 --tide-aqua: #d3ebf7;
63 --tide: linear-gradient(180deg, var(--gpui-light-bg) 0, var(--tide-aqua) 2rem, var(--brand-light) 4.5rem, var(--brand-deep) 7rem, var(--sea-mid) 11rem, var(--ocean-floor) 26rem);
64 /* The horizon: one line of light where the paper meets the sea. */
65 --horizon-light: rgb(144 185 255 / 0.85);
66 --horizon-glow: var(--horizon-light);
67
68 /* Type: Shannon Sans for every role, the system monospace stack for
69 things a person could type or paste. No serif, no third family. */
70 --font-body: var(--font-shannon-latin), var(--font-shannon-ext), var(--gpui-font-fallbacks),
71 ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
72 --font-display: var(--font-body);
73 --font-mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Monaco, Consolas,
74 "Liberation Mono", monospace;
75 --font-cjk: var(--gpui-font-fallbacks), sans-serif;
76
77 /* Type scale. 12px is the floor. Display sizes are one per page. */
78 --text-caption: 0.75rem; /* 12 meta, timestamps, labels */
79 --text-mono: var(--gpui-mono-size); /* 13 code, commands */
80 --text-ui: 0.875rem; /* 14 controls, rows, panel body */
81 --text-body: 1rem; /* 16 short copy, form inputs (no iOS zoom) */
82 --text-prose: 1.0625rem; /* 17 reading: docs, legal, answers */
83 --leading-prose: 1.6;
84 --text-heading: 1.0625rem; /* 17 600 group heading */
85 --text-title: 1.375rem; /* 22 600 group and prose title */
86 --text-section: clamp(1.75rem, 1.2rem + 1.7vw, 2.5rem); /* 28-40 editorial section title */
87 --text-display: clamp(2rem, 1.3rem + 2.6vw, 3rem); /* inner-page title */
88 --text-display-lg: clamp(2.5rem, 1.4rem + 4.4vw, 4.5rem); /* the home hero */
89 --text-xs: var(--text-caption);
90 --text-sm: var(--text-ui);
91 --text-base: var(--text-body);
92
93 /* Space: a 4px program. */
94 --space-1: 0.25rem;
95 --space-2: 0.5rem;
96 --space-3: 0.75rem;
97 --space-4: 1rem;
98 --space-5: 1.5rem;
99 --space-6: 2rem;
100 --space-7: 3rem;
101 --space-8: 4rem;
102 --section-gap: clamp(var(--space-7), 7vw, 5.5rem);
103
104 /* One container, one reading measure. */
105 --container: min(100% - var(--gpui-spacing-page), 76rem);
106 --measure-prose: 46rem;
107 --measure-text: 68ch;
108 --hero-pad: clamp(3rem, 7vw, 5.5rem);
109 --section-pad: clamp(2.75rem, 5vw, 4rem);
110
111 /* Radius: 6 controls, 10 surfaces, 14 sheets, pill for dots. */
112 --radius-control: var(--gpui-radius-control);
113 --radius-surface: var(--gpui-radius-panel);
114 --radius-sheet: var(--gpui-radius-sheet);
115 --radius-pill: 999px;
116
117 /* Motion. Nothing bounces: every curve stays inside [0, 1]. */
118 --dur-state: 120ms; /* colour, border, opacity on hover and press */
119 --dur-arrive: 180ms; /* something new arrives, rise <= 4px */
120 --dur-exit: 120ms; /* something closes or leaves */
121 --dur-spring: 340ms; /* panes and sheets */
122 --dur-spin: 1.2s; /* a working spinner: motion that shows work */
123 --ease-out: cubic-bezier(0, 0, 0.2, 1);
124 --ease-in: cubic-bezier(0.4, 0, 1, 1);
125 --ease-spring: cubic-bezier(0.2, 0.1, 0.16, 1);
126 --ease-exit: var(--ease-in);
127 }
128
129 /* Reduced motion is a still pose: every duration steps. Keyframed motion is
130 additionally declared only inside `prefers-reduced-motion:
131 no-preference`, so it never starts. */
132 @media (prefers-reduced-motion: reduce) {
133 :root {
134 --dur-state: 0ms;
135 --dur-spring: 0ms;
136 --dur-arrive: 0ms;
137 --dur-exit: 0ms;
138 }
139 }
140
141 /* ---------- light — warm paper above the horizon ---------- */
142 :root {
143 --bg: var(--gpui-light-bg);
144 --surface: var(--gpui-light-sidebar);
145 --panel: var(--gpui-light-panel);
146 --text: var(--gpui-light-text);
147 --muted: var(--gpui-light-text-muted);
148 --line: var(--gpui-light-border);
149 --line-strong: var(--gpui-light-border-strong);
150 --accent: var(--gpui-light-primary);
151 --accent-hover: rgb(var(--gpui-light-primary-rgb) / var(--gpui-primary-hover-opacity));
152 --on-accent: var(--gpui-light-on-primary);
153 --hover: var(--gpui-light-accent);
154 --selected: var(--gpui-light-list-active);
155 --selection: rgb(var(--gpui-light-primary-rgb) / var(--gpui-selection-opacity));
156 --ring: var(--gpui-light-primary);
157 --live: var(--gpui-light-live);
158 --success: var(--gpui-light-live);
159 --attention: var(--gpui-light-attention);
160 --danger: var(--gpui-light-danger);
161 --mark-ink: var(--gpui-light-text);
162 --ombre-ink: linear-gradient(135deg, var(--brand-light), var(--brand-deep));
163 --diff-add: rgb(104 152 119 / 0.14);
164 --diff-del: rgb(189 119 116 / 0.11);
165 /* Paper: the plain ground above the horizon. */
166 --ground: var(--gpui-light-bg);
167 /* On paper, light is a quiet ring. */
168 --glow: 0 0 0 3px color-mix(in srgb, currentColor 16%, transparent);
169 --glow-focus: 0 0 0 6px rgb(var(--gpui-light-primary-rgb) / 0.12);
170 --shadow-popover: 0 4px 8px rgb(0 0 0 / 0.16);
171 color-scheme: light;
172 }
173
174 /* ---------- dark — the navy ocean, only when pinned ---------- */
175 /* Paper is the site's appearance; the sea lives below the horizon in both.
176 A reader who pins dark from the theme control gets the navy ground. */
177 :root[data-theme="dark"] {
178 --bg: var(--ocean-floor);
179 --surface: var(--ocean-abyss);
180 --panel: var(--ocean-raised);
181 --text: var(--gpui-dark-text);
182 --muted: var(--gpui-dark-text-muted);
183 --line: var(--ocean-line);
184 --line-strong: var(--ocean-line-strong);
185 --accent: var(--gpui-dark-primary);
186 --accent-hover: rgb(var(--gpui-dark-primary-rgb) / var(--gpui-primary-hover-opacity));
187 --on-accent: var(--gpui-dark-on-primary);
188 --hover: var(--ocean-hover);
189 --selected: var(--ocean-selected);
190 --selection: rgb(var(--gpui-dark-primary-rgb) / var(--gpui-selection-opacity));
191 --ring: var(--gpui-dark-primary);
192 --live: var(--gpui-dark-live);
193 --success: var(--gpui-dark-live);
194 --attention: var(--gpui-dark-attention);
195 --danger: var(--gpui-dark-danger);
196 --mark-ink: var(--gpui-dark-text);
197 --ombre-ink: linear-gradient(135deg, #7cc2f2, var(--brand-light));
198 --diff-add: rgb(80 170 140 / 0.16);
199 --diff-del: rgb(227 154 144 / 0.12);
200 --ground: radial-gradient(90rem 38rem at 50% -14rem, rgb(30 143 216 / 0.3), transparent 70%), linear-gradient(180deg, var(--ocean-sky) 0, var(--ocean-floor) 34rem);
201 --glow: 0 0 0 3px color-mix(in srgb, currentColor 20%, transparent), 0 0 12px 1px color-mix(in srgb, currentColor 45%, transparent);
202 --glow-focus: 0 0 14px 2px rgb(var(--gpui-dark-primary-rgb) / 0.35);
203 --shadow-popover: 0 4px 8px rgb(0 0 0 / 0.4);
204 color-scheme: dark;
205 }
206
207 /* ---------- the stage — below the horizon, in both appearances ---------- */
208 /* The footer and the home sea. The ground is the deep water; raised and
209 recessed plates step up and down from it. Legacy aliases are repeated
210 here because a custom property that references another is computed where
211 it is declared. */
212 .stage,
213 .site-footer {
214 --bg: var(--ocean-floor);
215 --surface: var(--ocean-abyss);
216 --panel: var(--ocean-raised);
217 --text: var(--gpui-dark-text);
218 --muted: var(--gpui-dark-text-muted);
219 --line: var(--ocean-line);
220 --line-strong: var(--ocean-line-strong);
221 --accent: var(--gpui-dark-primary);
222 --accent-hover: rgb(var(--gpui-dark-primary-rgb) / var(--gpui-primary-hover-opacity));
223 --on-accent: var(--gpui-dark-on-primary);
224 --hover: var(--ocean-hover);
225 --selected: var(--ocean-selected);
226 --selection: rgb(var(--gpui-dark-primary-rgb) / var(--gpui-selection-opacity));
227 --ring: var(--gpui-dark-primary);
228 --live: var(--gpui-dark-live);
229 --success: var(--gpui-dark-live);
230 --attention: var(--gpui-dark-attention);
231 --danger: var(--gpui-dark-danger);
232 --mark-ink: var(--gpui-dark-text);
233 --ombre-ink: linear-gradient(135deg, #7cc2f2, var(--brand-light));
234 --diff-add: rgb(80 170 140 / 0.16);
235 --diff-del: rgb(227 154 144 / 0.12);
236 --glow: 0 0 0 3px color-mix(in srgb, currentColor 20%, transparent), 0 0 12px 1px color-mix(in srgb, currentColor 45%, transparent);
237 --glow-focus: 0 0 14px 2px rgb(var(--gpui-dark-primary-rgb) / 0.35);
238 --shadow-popover: 0 4px 8px rgb(0 0 0 / 0.4);
239
240 --paper: var(--bg);
241 --paper-deep: var(--surface);
242 --paper-card: var(--panel);
243 --paper-edge: var(--line);
244 --paper-line: var(--line);
245 --paper-line-soft: var(--line);
246 --hairline: var(--line);
247 --ink: var(--text);
248 --ink-soft: var(--muted);
249 --ink-mute: var(--muted);
250 --indigo: var(--accent);
251 --indigo-deep: var(--accent-hover);
252 --indigo-pale: color-mix(in srgb, var(--accent) 14%, transparent);
253 --docs-accent: var(--accent);
254 --code-bg: var(--surface);
255 --code-fg: var(--text);
256 color-scheme: dark;
257 color: var(--text);
258 }
259
260 /* The page's own ground, resolved here on :root so it survives into regions
261 (the footer, the stage) that re-declare --bg. */
262 :root { --page-ground: var(--bg); }
263
264 /* ---------- legacy names ---------- */
265 /* Pages and partials that have not moved to the roles (the docs) read these.
266 Declared once on :root, they resolve against whichever scheme block wins
267 there; `.stage` repeats them. Removed in the post-renovation sweep. */
268 :root {
269 --paper: var(--bg);
270 --paper-deep: var(--surface);
271 --paper-card: var(--panel);
272 --paper-edge: var(--line);
273 --paper-line: var(--line);
274 --paper-line-soft: var(--line);
275 --hairline: var(--line);
276 --ink: var(--text);
277 --ink-soft: var(--muted);
278 --ink-mute: var(--muted);
279 --indigo: var(--accent);
280 --indigo-deep: var(--accent-hover);
281 --indigo-pale: color-mix(in srgb, var(--accent) 12%, transparent);
282 --cobalt: var(--accent);
283 --cyan: var(--accent);
284 --ochre: var(--attention);
285 --signal-gold: var(--attention);
286 --jade: var(--live);
287 --seafoam: var(--live);
288 --ocean-coral: var(--danger);
289 --docs-accent: var(--accent);
290 --docs-button-bg: var(--panel);
291 --docs-button-border: var(--line);
292 --docs-button-text: var(--text);
293 --code-bg: var(--surface);
294 --code-fg: var(--text);
295 --stage-line: var(--line);
296 --stage-dim: var(--muted);
297 }
298
298 lines CSS