remarque-tokens 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,330 @@
1
+ /*
2
+ * Remarque Design Tokens — CORE TIER
3
+ * ───────────────────────────────────
4
+ * The immutable identity of Remarque: type scale, rhythm, spacing,
5
+ * widths, radius, and motion — plus the typography/prose machinery
6
+ * that consumes them.
7
+ *
8
+ * CONTRACT: a site that overrides tokens in THIS file has forked
9
+ * Remarque. Personalization happens exclusively in tokens-palette.css
10
+ * (fonts, colors, accent, reading measure). See "Token Tiers" in
11
+ * REMARQUE.md.
12
+ *
13
+ * Import via the aggregator (tokens.css) or directly:
14
+ * @import 'fonts.css';
15
+ * @import 'tokens-core.css';
16
+ * @import 'tokens-palette.css';
17
+ */
18
+
19
+ :root {
20
+ /* Type scale — fluid where it matters, fixed where it doesn't */
21
+ --text-display: clamp(2.75rem, 5.5vw, 5rem);
22
+ --text-title: clamp(1.875rem, 3.5vw, 3rem);
23
+ --text-section: clamp(1.375rem, 2.25vw, 2rem);
24
+ --text-body-lg: 1.1875rem; /* 19px — for lead paragraphs */
25
+ --text-body: 1.0625rem; /* 17px — minimum body size, non-negotiable */
26
+ --text-meta: 0.875rem; /* 14px — USWDS minimum for small text */
27
+ --text-micro: 0.8125rem; /* 13px — USWDS floor for timestamps only */
28
+
29
+ /* Line heights — matched to their type roles */
30
+ --leading-display: 1.05;
31
+ --leading-title: 1.15;
32
+ --leading-section: 1.2;
33
+ --leading-body: 1.75; /* generous — this is what makes prose readable */
34
+ --leading-meta: 1.5; /* USWDS minimum for short text */
35
+
36
+ /* Letter spacing */
37
+ --tracking-display: -0.02em;
38
+ --tracking-title: -0.015em;
39
+ --tracking-body: 0em;
40
+ --tracking-meta: 0.02em; /* mono metadata gets slight tracking */
41
+ --tracking-caps: 0.06em; /* for any rare uppercase labels */
42
+
43
+ /* Font weights */
44
+ --weight-regular: 400;
45
+ --weight-medium: 500;
46
+ --weight-semibold: 600;
47
+
48
+ /* Spacing scale — deliberately generous */
49
+ --space-1: 0.25rem; /* 4px */
50
+ --space-2: 0.5rem; /* 8px */
51
+ --space-3: 0.75rem; /* 12px */
52
+ --space-4: 1rem; /* 16px */
53
+ --space-5: 1.5rem; /* 24px */
54
+ --space-6: 2rem; /* 32px */
55
+ --space-7: 3rem; /* 48px */
56
+ --space-8: 4rem; /* 64px */
57
+ --space-9: 6rem; /* 96px — minimum top padding before main heading */
58
+ --space-10: 8rem; /* 128px */
59
+ --space-11: 10rem; /* 160px */
60
+ --space-12: 12rem; /* 192px */
61
+
62
+ /* Layout container widths.
63
+ (--content-reading, the prose measure, lives in the PALETTE tier —
64
+ it is tuned to the body font and moves with it. These two do not.) */
65
+ --content-standard: 72rem; /* ~1152px — project pages, wider layouts */
66
+ --content-wide: 88rem; /* ~1408px — outer container, navigation context */
67
+
68
+ /* Border radius — restrained */
69
+ --radius-sm: 0.25rem; /* 4px — subtle rounding */
70
+ --radius-md: 0.5rem; /* 8px — maximum for any component */
71
+ --radius-none: 0;
72
+
73
+ /* Borders */
74
+ --border-width: 1px;
75
+ --border-style: solid;
76
+
77
+ /* Motion — minimal, functional only */
78
+ /* All sanctioned motion MUST use these tokens; the reduced-motion
79
+ block below zeroes them, disabling motion system-wide. */
80
+ --motion-fast: 120ms; /* hover states, focus rings */
81
+ --motion-normal: 180ms; /* theme transitions */
82
+ --motion-easing: ease-out;
83
+ }
84
+
85
+ /* ─── Reduced Motion ────────────────────────────────────── */
86
+ /*
87
+ * WCAG 2.3.3 / vestibular safety. Because every sanctioned transition
88
+ * uses the two duration tokens, zeroing them disables all motion.
89
+ * Any future opt-in animation must be authored inside a
90
+ * (prefers-reduced-motion: no-preference) query.
91
+ */
92
+
93
+ @media (prefers-reduced-motion: reduce) {
94
+ :root,
95
+ [data-theme="light"],
96
+ [data-theme="dark"] {
97
+ --motion-fast: 0ms;
98
+ --motion-normal: 0ms;
99
+ }
100
+ }
101
+
102
+ /* ─── Base Resets ────────────────────────────────────────── */
103
+
104
+ *,
105
+ *::before,
106
+ *::after {
107
+ box-sizing: border-box;
108
+ }
109
+
110
+ html {
111
+ font-family: var(--font-body);
112
+ font-size: 100%;
113
+ line-height: var(--leading-body);
114
+ color: var(--color-fg);
115
+ background-color: var(--color-bg);
116
+ -webkit-font-smoothing: antialiased;
117
+ -moz-osx-font-smoothing: grayscale;
118
+ text-rendering: optimizeLegibility;
119
+ }
120
+
121
+ ::selection {
122
+ background-color: var(--color-selection-bg);
123
+ color: var(--color-selection-fg);
124
+ }
125
+
126
+ /* ─── Global Typography Classes ─────────────────────────── */
127
+
128
+ .text-display {
129
+ font-family: var(--font-display);
130
+ font-size: var(--text-display);
131
+ line-height: var(--leading-display);
132
+ letter-spacing: var(--tracking-display);
133
+ font-weight: var(--weight-regular);
134
+ }
135
+
136
+ .text-title {
137
+ font-family: var(--font-display);
138
+ font-size: var(--text-title);
139
+ line-height: var(--leading-title);
140
+ letter-spacing: var(--tracking-title);
141
+ font-weight: var(--weight-regular);
142
+ }
143
+
144
+ .text-section {
145
+ font-family: var(--font-display);
146
+ font-size: var(--text-section);
147
+ line-height: var(--leading-section);
148
+ letter-spacing: var(--tracking-title);
149
+ font-weight: var(--weight-medium);
150
+ }
151
+
152
+ .text-body {
153
+ font-family: var(--font-body);
154
+ font-size: var(--text-body);
155
+ line-height: var(--leading-body);
156
+ letter-spacing: var(--tracking-body);
157
+ font-weight: var(--weight-regular);
158
+ }
159
+
160
+ .text-body-lg {
161
+ font-family: var(--font-body);
162
+ font-size: var(--text-body-lg);
163
+ line-height: var(--leading-body);
164
+ letter-spacing: var(--tracking-body);
165
+ font-weight: var(--weight-regular);
166
+ }
167
+
168
+ .text-meta {
169
+ font-family: var(--font-mono);
170
+ font-size: var(--text-meta);
171
+ line-height: var(--leading-meta);
172
+ letter-spacing: var(--tracking-meta);
173
+ font-weight: var(--weight-regular);
174
+ color: var(--color-muted);
175
+ }
176
+
177
+ /* ─── Content Width Utilities ───────────────────────────── */
178
+
179
+ .content-reading {
180
+ max-width: var(--content-reading);
181
+ margin-inline: auto;
182
+ }
183
+
184
+ .content-standard {
185
+ max-width: var(--content-standard);
186
+ margin-inline: auto;
187
+ }
188
+
189
+ .content-wide {
190
+ max-width: var(--content-wide);
191
+ margin-inline: auto;
192
+ }
193
+
194
+ /* ─── Prose Styling ─────────────────────────────────────── */
195
+ /*
196
+ * Apply .remarque-prose to any container with article/essay content.
197
+ * Handles all typographic details for long-form reading.
198
+ */
199
+
200
+ .remarque-prose {
201
+ font-family: var(--font-body);
202
+ font-size: var(--text-body);
203
+ line-height: var(--leading-body);
204
+ color: var(--color-fg);
205
+ max-width: var(--content-reading);
206
+ }
207
+
208
+ .remarque-prose > * + * {
209
+ margin-top: var(--space-5);
210
+ }
211
+
212
+ .remarque-prose > :first-child {
213
+ margin-top: 0;
214
+ }
215
+
216
+ .remarque-prose h2 {
217
+ font-family: var(--font-display);
218
+ font-size: var(--text-section);
219
+ line-height: var(--leading-section);
220
+ letter-spacing: var(--tracking-title);
221
+ font-weight: var(--weight-medium);
222
+ margin-top: var(--space-7);
223
+ margin-bottom: var(--space-3);
224
+ color: var(--color-fg);
225
+ }
226
+
227
+ .remarque-prose h3 {
228
+ font-family: var(--font-body);
229
+ font-size: var(--text-body-lg);
230
+ line-height: var(--leading-title);
231
+ font-weight: var(--weight-semibold);
232
+ margin-top: var(--space-6);
233
+ margin-bottom: var(--space-2);
234
+ color: var(--color-fg);
235
+ }
236
+
237
+ .remarque-prose a {
238
+ color: var(--color-link);
239
+ text-decoration: underline;
240
+ text-underline-offset: 0.2em;
241
+ text-decoration-thickness: 1px;
242
+ transition: color var(--motion-fast) var(--motion-easing);
243
+ }
244
+
245
+ .remarque-prose a:hover {
246
+ color: var(--color-link-hover);
247
+ }
248
+
249
+ .remarque-prose strong {
250
+ font-weight: var(--weight-semibold);
251
+ }
252
+
253
+ .remarque-prose em {
254
+ font-style: italic;
255
+ }
256
+
257
+ .remarque-prose blockquote {
258
+ border-left: 2px solid var(--color-border-bold);
259
+ padding-left: var(--space-5);
260
+ margin-left: 0;
261
+ color: var(--color-fg-muted);
262
+ font-style: italic;
263
+ }
264
+
265
+ .remarque-prose ul,
266
+ .remarque-prose ol {
267
+ padding-left: var(--space-5);
268
+ }
269
+
270
+ .remarque-prose li + li {
271
+ margin-top: var(--space-2);
272
+ }
273
+
274
+ .remarque-prose code {
275
+ font-family: var(--font-mono);
276
+ font-size: 0.9em;
277
+ background-color: var(--color-code-bg);
278
+ padding: 0.15em 0.35em;
279
+ border-radius: var(--radius-sm);
280
+ color: var(--color-code-fg);
281
+ }
282
+
283
+ .remarque-prose pre {
284
+ font-family: var(--font-mono);
285
+ font-size: var(--text-meta);
286
+ line-height: 1.6;
287
+ background-color: var(--color-code-bg);
288
+ border: var(--border-width) var(--border-style) var(--color-border);
289
+ border-radius: var(--radius-md);
290
+ padding: var(--space-5);
291
+ overflow-x: auto;
292
+ }
293
+
294
+ .remarque-prose pre code {
295
+ background: none;
296
+ padding: 0;
297
+ border-radius: 0;
298
+ font-size: inherit;
299
+ }
300
+
301
+ .remarque-prose hr {
302
+ border: none;
303
+ border-top: var(--border-width) var(--border-style) var(--color-border);
304
+ margin: var(--space-8) 0;
305
+ }
306
+
307
+ .remarque-prose img {
308
+ max-width: 100%;
309
+ height: auto;
310
+ border: var(--border-width) var(--border-style) var(--color-border);
311
+ border-radius: var(--radius-sm);
312
+ }
313
+
314
+ .remarque-prose figcaption {
315
+ font-family: var(--font-mono);
316
+ font-size: var(--text-meta);
317
+ line-height: var(--leading-meta);
318
+ letter-spacing: var(--tracking-meta);
319
+ color: var(--color-muted);
320
+ margin-top: var(--space-2);
321
+ }
322
+
323
+ /* ─── Focus Styles ──────────────────────────────────────── */
324
+
325
+ :focus-visible {
326
+ outline: 2px solid var(--color-focus-ring);
327
+ outline-offset: 2px;
328
+ border-radius: var(--radius-sm);
329
+ transition: outline-color var(--motion-fast) var(--motion-easing);
330
+ }
@@ -0,0 +1,128 @@
1
+ /*
2
+ * Remarque Design Tokens — PALETTE TIER
3
+ * ──────────────────────────────────────
4
+ * The sanctioned personalization surface: font slots, colors, accent,
5
+ * and the reading measure. A site may override ANY token in this file
6
+ * (in its own stylesheet, loaded after this one) and still be a
7
+ * compliant Remarque site. Overriding tokens-core.css is a fork.
8
+ *
9
+ * RULES FOR OVERRIDES:
10
+ * - Font slots: choose from the approved pairings in REMARQUE.md
11
+ * ("Font Slots"). Display faces never set body copy; mono never
12
+ * sets headings or body.
13
+ * - --content-reading: pick the value matching your body font from
14
+ * the measure-compensation table in REMARQUE.md (target 66–72
15
+ * characters per line at --text-body).
16
+ * - Colors: every replacement palette must pass the contrast audit
17
+ * (npm run audit) — fg-muted ≥ 7:1, muted ≥ 4.5:1 on bg AND
18
+ * surface, accent + accent-hover ≥ 4.5:1, border-bold ≥ 3:1,
19
+ * in BOTH themes.
20
+ * - Accent: change the hue by re-deriving accent/accent-hover/
21
+ * accent-subtle/selection at the SAME lightness values used here,
22
+ * then validate — lightness carries the contrast, hue carries the
23
+ * personality. Not every hue passes at every lightness (yellows/
24
+ * cyans behave differently than blues); the audit is the gate.
25
+ */
26
+
27
+ /* ─── Font Slots ────────────────────────────────────────── */
28
+
29
+ :root {
30
+ --font-display: "Newsreader", Georgia, "Times New Roman", serif;
31
+ --font-body: "Inter", ui-sans-serif, system-ui, -apple-system, sans-serif;
32
+ --font-mono: "JetBrains Mono", ui-monospace, "Cascadia Code", "Fira Code", monospace;
33
+
34
+ /* Reading measure — tuned to the body font (see REMARQUE.md measure table).
35
+ 46rem ≈ 70 characters per line at 17px Inter. */
36
+ --content-reading: 46rem;
37
+ }
38
+
39
+ /* ─── Color: Light theme (default) ──────────────────────── */
40
+ /*
41
+ * Colors use OKLCH for perceptual uniformity.
42
+ * The palette is deliberately narrow: warm neutrals + one accent.
43
+ *
44
+ * Accent rule: used for inline links and ONE interactive element per
45
+ * viewport. No accent backgrounds, no accent borders, no accent fills.
46
+ *
47
+ * Contrast ratios in comments are computed WCAG 2.x values
48
+ * (OKLCH → linear sRGB → relative luminance); the audit script
49
+ * (scripts/audit.mjs) recomputes and enforces them in CI.
50
+ */
51
+
52
+ :root {
53
+ --color-bg: oklch(0.975 0.005 80); /* warm off-white, not pure white */
54
+ --color-bg-subtle: oklch(0.955 0.005 80); /* slightly darker for alternating sections */
55
+ --color-fg: oklch(0.18 0.01 80); /* near-black, warm undertone */
56
+ --color-fg-muted: oklch(0.43 0.015 80); /* secondary text — 7.55:1 bg / 7.33:1 surface (AAA) */
57
+ --color-muted: oklch(0.54 0.01 80); /* tertiary text — 4.71:1 bg / 4.57:1 surface (AA) */
58
+ --color-border: oklch(0.88 0.005 80); /* quiet borders — DECORATIVE ONLY (1.34:1, below WCAG 1.4.11's 3:1); functional boundaries use --color-border-bold */
59
+ --color-border-bold: oklch(0.62 0.01 80); /* functional/emphasized borders — 3.39:1 (meets WCAG 1.4.11) */
60
+ --color-surface: oklch(0.965 0.005 80); /* card/surface backgrounds */
61
+
62
+ --color-accent: oklch(0.50 0.14 250); /* muted blue — links and one interactive element */
63
+ --color-accent-hover: oklch(0.42 0.11 250); /* darker on hover — 7.87:1, in-gamut (0.14 chroma clipped) */
64
+ --color-accent-subtle: oklch(0.95 0.02 250); /* very faint accent background — in-gamut (0.03 chroma clipped) */
65
+
66
+ /* Semantic mappings */
67
+ --color-link: var(--color-accent);
68
+ --color-link-hover: var(--color-accent-hover);
69
+ --color-focus-ring: var(--color-accent);
70
+ --color-selection-bg: oklch(0.92 0.04 250);
71
+ --color-selection-fg: var(--color-fg);
72
+ --color-code-bg: oklch(0.945 0.005 80); /* inline code background */
73
+ --color-code-fg: var(--color-fg);
74
+ }
75
+
76
+ /* ─── Color: Dark theme ─────────────────────────────────── */
77
+ /*
78
+ * Dark mode is NOT an inverted light mode.
79
+ * It is independently tuned for readability on dark backgrounds.
80
+ * Key differences:
81
+ * - Background is warm dark gray, never pure black
82
+ * - Text is softened to reduce glare (not pure white)
83
+ * - Accent is brighter to maintain contrast
84
+ * - Borders are subtler
85
+ */
86
+
87
+ @media (prefers-color-scheme: dark) {
88
+ :root {
89
+ --color-bg: oklch(0.16 0.01 80); /* warm charcoal, not black */
90
+ --color-bg-subtle: oklch(0.19 0.01 80);
91
+ --color-fg: oklch(0.90 0.005 80); /* soft white, not pure */
92
+ --color-fg-muted: oklch(0.70 0.01 80); /* 7.26:1 bg (AAA) */
93
+ --color-muted: oklch(0.60 0.01 80); /* 4.92:1 bg / 4.68:1 surface (AA with margin) */
94
+ --color-border: oklch(0.25 0.005 80); /* decorative only — see light-theme note */
95
+ --color-border-bold: oklch(0.50 0.01 80); /* functional borders — 3.23:1 (meets WCAG 1.4.11) */
96
+ --color-surface: oklch(0.19 0.01 80);
97
+
98
+ --color-accent: oklch(0.68 0.12 250); /* brighter in dark mode for contrast */
99
+ --color-accent-hover: oklch(0.75 0.12 250);
100
+ --color-accent-subtle: oklch(0.22 0.04 250);
101
+
102
+ --color-selection-bg: oklch(0.30 0.06 250);
103
+ --color-selection-fg: oklch(0.92 0.005 80);
104
+ --color-code-bg: oklch(0.20 0.005 80);
105
+ --color-code-fg: oklch(0.88 0.005 80);
106
+ }
107
+ }
108
+
109
+ /* Manual dark mode toggle support */
110
+ [data-theme="dark"] {
111
+ --color-bg: oklch(0.16 0.01 80);
112
+ --color-bg-subtle: oklch(0.19 0.01 80);
113
+ --color-fg: oklch(0.90 0.005 80);
114
+ --color-fg-muted: oklch(0.70 0.01 80);
115
+ --color-muted: oklch(0.60 0.01 80);
116
+ --color-border: oklch(0.25 0.005 80);
117
+ --color-border-bold: oklch(0.50 0.01 80);
118
+ --color-surface: oklch(0.19 0.01 80);
119
+
120
+ --color-accent: oklch(0.68 0.12 250);
121
+ --color-accent-hover: oklch(0.75 0.12 250);
122
+ --color-accent-subtle: oklch(0.22 0.04 250);
123
+
124
+ --color-selection-bg: oklch(0.30 0.06 250);
125
+ --color-selection-fg: oklch(0.92 0.005 80);
126
+ --color-code-bg: oklch(0.20 0.005 80);
127
+ --color-code-fg: oklch(0.88 0.005 80);
128
+ }
package/tokens.css ADDED
@@ -0,0 +1,24 @@
1
+ /*
2
+ * Remarque Design Tokens — AGGREGATOR
3
+ * ────────────────────────────────────
4
+ * Backwards-compatible entry point. As of the Phase 1 restructuring
5
+ * (issue #47), tokens live in two tiers:
6
+ *
7
+ * tokens-core.css — the immutable identity (type scale, spacing,
8
+ * widths, radius, motion, prose machinery).
9
+ * Overriding these = forking Remarque.
10
+ * tokens-palette.css — the sanctioned personalization surface
11
+ * (font slots, colors, accent, reading measure).
12
+ * Override freely in a stylesheet loaded after
13
+ * this one; validate with `npm run audit`.
14
+ *
15
+ * Usage (fonts first — see fonts.css):
16
+ * @import 'fonts.css';
17
+ * @import 'tokens.css';
18
+ * ...then optionally your site's palette overrides, loaded last.
19
+ *
20
+ * Existing imports of tokens.css keep working unchanged.
21
+ */
22
+
23
+ @import './tokens-core.css';
24
+ @import './tokens-palette.css';