remarque-tokens 0.2.0 → 0.4.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.
- package/AGENT_RULES.md +6 -2
- package/CHANGELOG.md +43 -0
- package/README.md +21 -5
- package/REMARQUE.md +2 -2
- package/package.json +14 -4
- package/prose.css +139 -0
- package/scripts/audit.mjs +5 -51
- package/scripts/lib/css-tokens.mjs +51 -0
- package/scripts/tokens-json.mjs +83 -0
- package/theme.css +77 -0
- package/tokens-core.css +0 -129
- package/tokens.css +1 -0
- package/tokens.json +417 -0
package/AGENT_RULES.md
CHANGED
|
@@ -10,7 +10,7 @@ Read `REMARQUE.md` first for the full system specification. This file tells you
|
|
|
10
10
|
|
|
11
11
|
Execute in this exact order. Do not skip steps. Do not reorder.
|
|
12
12
|
|
|
13
|
-
1. **Load tokens.** Import `
|
|
13
|
+
1. **Load tokens.** Import `fonts.css` then `tokens.css`, and wire Tailwind: v4 projects import `theme.css` (after `tailwindcss` and the tokens, unlayered — see Pitfall #7); v3 projects use `tailwind.config.js`. Verify fonts load correctly.
|
|
14
14
|
|
|
15
15
|
2. **Set up global typography.** Apply display, title, section, body, meta, and prose classes. Verify the type scale renders correctly at mobile and desktop widths.
|
|
16
16
|
|
|
@@ -138,7 +138,9 @@ project/
|
|
|
138
138
|
├── tokens.css # Aggregator — imports the two tiers below
|
|
139
139
|
├── tokens-core.css # CORE tier: type scale, spacing, widths, radius, motion, prose machinery. NEVER override
|
|
140
140
|
├── tokens-palette.css # PALETTE tier: font slots, colors, accent, reading measure. Override freely, then run the audit
|
|
141
|
-
├──
|
|
141
|
+
├── prose.css # .remarque-prose long-form styling (aggregated by tokens.css; own subpath for opt-out)
|
|
142
|
+
├── theme.css # Tailwind v4 adapter (@theme inline) — import after tailwindcss + tokens
|
|
143
|
+
├── tailwind.config.js # Tailwind v3 ONLY — v4 projects use theme.css instead
|
|
142
144
|
├── public/
|
|
143
145
|
│ └── fonts/ # Self-hosted woff2 fonts (Inter, Newsreader, JetBrains Mono)
|
|
144
146
|
├── styles/
|
|
@@ -172,6 +174,8 @@ project/
|
|
|
172
174
|
|
|
173
175
|
6. **String-form @import only:** Always write `@import './tokens.css';` (string form). Tailwind v4 / Lightning CSS silently DROPS `@import url(...)` for local files — the build succeeds while the entire token cascade vanishes from the output. Verify the built CSS contains `.remarque-prose` after changing imports.
|
|
174
176
|
|
|
177
|
+
7. **Tokens must be imported unlayered (Tailwind v4):** never `@import "remarque-tokens" layer(...)`. theme.css's `@theme inline` mappings emit same-named self-referencing declarations inside `@layer theme`; the real token values win only because unlayered declarations beat layered ones. Layering the tokens makes every mapped utility circular and invalid, with no build error.
|
|
178
|
+
|
|
175
179
|
---
|
|
176
180
|
|
|
177
181
|
## Quality Checklist
|
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,49 @@ All notable changes to `remarque-tokens` are documented here. Token value
|
|
|
4
4
|
changes always state the design rationale — downstream sites pin against
|
|
5
5
|
these entries when syncing.
|
|
6
6
|
|
|
7
|
+
## 0.4.0 — 2026-07-20
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
- **`remarque-tokens/prose`** subpath: `.remarque-prose` split out of
|
|
11
|
+
`tokens-core.css` into `prose.css`, so consumers with their own prose
|
|
12
|
+
system (e.g. the reference consumer's `.prose`) can import the core
|
|
13
|
+
structural tokens without it.
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
- **Breaking for `/core` importers:** `remarque-tokens/core` no longer
|
|
17
|
+
includes `.remarque-prose` — import `remarque-tokens/prose` alongside
|
|
18
|
+
it, or use the aggregator (`remarque-tokens`), which now includes all
|
|
19
|
+
three files and is unchanged for consumers.
|
|
20
|
+
- Demo pages exercise the Tailwind v4 adapter utilities directly
|
|
21
|
+
(`pt-remarque-10`, `rounded-sm`) instead of arbitrary-value escapes —
|
|
22
|
+
same computed styles, real coverage of the theme.css surface.
|
|
23
|
+
- Internals: the brace-aware CSS token parser previously duplicated in
|
|
24
|
+
`audit.mjs` and `tokens-json.mjs` now lives once in
|
|
25
|
+
`scripts/lib/css-tokens.mjs` (shipped with the package for the bin).
|
|
26
|
+
|
|
27
|
+
No token values changed in this release.
|
|
28
|
+
|
|
29
|
+
## 0.3.0 — 2026-07-20
|
|
30
|
+
|
|
31
|
+
### Added
|
|
32
|
+
- **`remarque-tokens/theme.css`** (#48): Tailwind v4 adapter using
|
|
33
|
+
`@theme inline` — utilities (`font-display`, `bg-surface`,
|
|
34
|
+
`max-w-reading`, `mt-remarque-9`, …) reference the runtime custom
|
|
35
|
+
properties directly, so palette switches (light/dark/theme-deck) flow
|
|
36
|
+
through utilities with zero value duplication. Import order:
|
|
37
|
+
`tailwindcss` → `remarque-tokens` → `remarque-tokens/theme.css`.
|
|
38
|
+
- **`tokens.json`** (#48): machine-readable token inventory (W3C
|
|
39
|
+
design-tokens flavored, core/palette tiers, light+dark values),
|
|
40
|
+
GENERATED from the CSS by `scripts/tokens-json.mjs` — the CSS remains
|
|
41
|
+
the single source of truth; CI fails if the JSON goes stale.
|
|
42
|
+
|
|
43
|
+
### Changed
|
|
44
|
+
- The reference site now consumes the package itself (`file:..` link)
|
|
45
|
+
instead of maintaining file copies — the demo build is the package's
|
|
46
|
+
integration test, and the copy-sync burden is gone.
|
|
47
|
+
|
|
48
|
+
No token values changed in this release.
|
|
49
|
+
|
|
7
50
|
## 0.2.0 — 2026-07-20
|
|
8
51
|
|
|
9
52
|
First published release. Everything below is relative to the unpublished
|
package/README.md
CHANGED
|
@@ -21,16 +21,31 @@ Most developer sites inherit the visual language of SaaS dashboards or component
|
|
|
21
21
|
|
|
22
22
|
## Install
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
```bash
|
|
25
|
+
npm install remarque-tokens
|
|
26
|
+
```
|
|
25
27
|
|
|
26
28
|
```css
|
|
27
|
-
@import 'fonts.css';
|
|
28
|
-
@import 'tokens
|
|
29
|
+
@import 'remarque-tokens/fonts.css';
|
|
30
|
+
@import 'remarque-tokens';
|
|
31
|
+
/* then optionally your site's palette overrides, loaded last */
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Copy the `fonts/` woff2 files from `node_modules/remarque-tokens/fonts/` into your static assets (or serve them from wherever your bundler puts font URLs). Personalize by overriding `remarque-tokens/palette` tokens in your own stylesheet, then validate:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npx remarque-audit --palette src/styles/my-palette.css --src src
|
|
29
38
|
```
|
|
30
39
|
|
|
31
|
-
Tailwind
|
|
40
|
+
**Tailwind v4** projects add the shipped adapter — utilities that track the tokens through every theme switch, no value duplication:
|
|
41
|
+
|
|
42
|
+
```css
|
|
43
|
+
@import "tailwindcss";
|
|
44
|
+
@import "remarque-tokens";
|
|
45
|
+
@import "remarque-tokens/theme.css";
|
|
46
|
+
```
|
|
32
47
|
|
|
33
|
-
|
|
48
|
+
**Tailwind v3** projects use the shipped config (`remarque-tokens/tailwind`) instead. A machine-readable token inventory ships as `remarque-tokens/tokens.json` (generated from the CSS — core/palette tiers, light+dark values) for tooling and AI agents. Prefer copy-paste? Grab `fonts.css`, `tokens.css`, `tokens-core.css`, `tokens-palette.css`, and `fonts/` directly — `tokens.css` aggregates the two tier files, so all three CSS files travel together. Use string-form `@import './tokens.css'` only (some bundlers silently drop `@import url(...)` for local files).
|
|
34
49
|
|
|
35
50
|
## For AI Agents
|
|
36
51
|
|
|
@@ -52,6 +67,7 @@ The agent rules define build order, non-negotiable rules, disallowed patterns, a
|
|
|
52
67
|
| `tokens.css` | Aggregator importing the two token tiers below |
|
|
53
68
|
| `tokens-core.css` | Core tier — type scale, spacing, widths, radius, motion, prose styling. Never overridden |
|
|
54
69
|
| `tokens-palette.css` | Palette tier — font slots, colors, accent, reading measure. The sanctioned personalization surface |
|
|
70
|
+
| `prose.css` | `.remarque-prose` long-form styling — own subpath so sites with their own prose system can skip it |
|
|
55
71
|
| `scripts/audit.mjs` | `npm run audit` — enforces the spec's contrast/gamut/font-floor/no-hardcoded-color checklist |
|
|
56
72
|
| `fonts.css` + `fonts/` | Self-hosted @font-face declarations and woff2 files (no CDN requests) |
|
|
57
73
|
| `tailwind.config.js` | Tailwind CSS **v3** configuration (v4 projects use an `@theme` block instead) |
|
package/REMARQUE.md
CHANGED
|
@@ -40,14 +40,14 @@ Remarque projects should feel like a modern technical publication — not a gene
|
|
|
40
40
|
|
|
41
41
|
## Technology Stack
|
|
42
42
|
|
|
43
|
-
- **CSS framework:** Tailwind CSS — v4 via
|
|
43
|
+
- **CSS framework:** Tailwind CSS — v4 via the shipped `remarque-tokens/theme.css` (`@theme inline` adapter; utilities reference the runtime tokens), or v3 via the shipped `tailwind.config.js`. One mechanism per project, never both.
|
|
44
44
|
- **Component primitives:** shadcn/ui (when reusable components are needed)
|
|
45
45
|
- **Markup:** Semantic HTML with ARIA landmarks
|
|
46
46
|
- **Theming:** Light and dark mode via `[data-theme]` attribute (system preference + manual toggle)
|
|
47
47
|
- **Accessibility:** USWDS-informed. Keyboard navigation, skip-to-content link, ARIA labels, WCAG AA contrast compliance, 44px touch targets, 14px minimum small text
|
|
48
48
|
- **Tokens:** Centralized CSS custom properties in two tiers — `tokens-core.css` (immutable identity) + `tokens-palette.css` (sanctioned personalization). `tokens.css` aggregates both. See "Token Tiers"
|
|
49
49
|
- **Fonts:** Self-hosted woff2 (no CDN dependency). Preloaded via `<link rel="preload">`
|
|
50
|
-
- **Package:** Copy `fonts.css` + `tokens.css` + `tokens-core.css` + `tokens-palette.css` + `fonts/`
|
|
50
|
+
- **Package:** `npm install remarque-tokens` — subpaths: `remarque-tokens` (aggregator), `/core`, `/palette`, `/fonts.css`, `/tailwind`; ships `npx remarque-audit`. Copy path also supported: `fonts.css` + `tokens.css` + `tokens-core.css` + `tokens-palette.css` + `fonts/` travel together (the aggregator imports the tier files)
|
|
51
51
|
|
|
52
52
|
### Tailwind Spacing Integration Note
|
|
53
53
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "remarque-tokens",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"engines": {
|
|
5
5
|
"node": ">=18"
|
|
6
6
|
},
|
|
@@ -37,7 +37,12 @@
|
|
|
37
37
|
"./tokens-palette.css": "./tokens-palette.css",
|
|
38
38
|
"./fonts.css": "./fonts.css",
|
|
39
39
|
"./fonts/*": "./fonts/*",
|
|
40
|
-
"./tailwind": "./tailwind.config.js"
|
|
40
|
+
"./tailwind": "./tailwind.config.js",
|
|
41
|
+
"./theme.css": "./theme.css",
|
|
42
|
+
"./theme": "./theme.css",
|
|
43
|
+
"./tokens.json": "./tokens.json",
|
|
44
|
+
"./prose": "./prose.css",
|
|
45
|
+
"./prose.css": "./prose.css"
|
|
41
46
|
},
|
|
42
47
|
"files": [
|
|
43
48
|
"tokens.css",
|
|
@@ -50,6 +55,11 @@
|
|
|
50
55
|
"REMARQUE.md",
|
|
51
56
|
"AGENT_RULES.md",
|
|
52
57
|
"LICENSE",
|
|
53
|
-
"CHANGELOG.md"
|
|
58
|
+
"CHANGELOG.md",
|
|
59
|
+
"theme.css",
|
|
60
|
+
"tokens.json",
|
|
61
|
+
"scripts/tokens-json.mjs",
|
|
62
|
+
"prose.css",
|
|
63
|
+
"scripts/lib/css-tokens.mjs"
|
|
54
64
|
]
|
|
55
|
-
}
|
|
65
|
+
}
|
package/prose.css
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Remarque — Prose Styling (core tier)
|
|
3
|
+
* ─────────────────────────────────────
|
|
4
|
+
* .remarque-prose: all typographic details for long-form reading.
|
|
5
|
+
* Split from tokens-core.css as its own subpath (remarque-tokens/prose)
|
|
6
|
+
* so consumers with their own prose systems can import the core
|
|
7
|
+
* structural tokens without it. The tokens.css aggregator includes it.
|
|
8
|
+
* Values consumed here come from the core + palette tiers.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/* ─── Prose Styling ─────────────────────────────────────── */
|
|
12
|
+
/*
|
|
13
|
+
* Apply .remarque-prose to any container with article/essay content.
|
|
14
|
+
* Handles all typographic details for long-form reading.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
.remarque-prose {
|
|
18
|
+
font-family: var(--font-body);
|
|
19
|
+
font-size: var(--text-body);
|
|
20
|
+
line-height: var(--leading-body);
|
|
21
|
+
color: var(--color-fg);
|
|
22
|
+
max-width: var(--content-reading);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.remarque-prose > * + * {
|
|
26
|
+
margin-top: var(--space-5);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.remarque-prose > :first-child {
|
|
30
|
+
margin-top: 0;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.remarque-prose h2 {
|
|
34
|
+
font-family: var(--font-display);
|
|
35
|
+
font-size: var(--text-section);
|
|
36
|
+
line-height: var(--leading-section);
|
|
37
|
+
letter-spacing: var(--tracking-title);
|
|
38
|
+
font-weight: var(--weight-medium);
|
|
39
|
+
margin-top: var(--space-7);
|
|
40
|
+
margin-bottom: var(--space-3);
|
|
41
|
+
color: var(--color-fg);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.remarque-prose h3 {
|
|
45
|
+
font-family: var(--font-body);
|
|
46
|
+
font-size: var(--text-body-lg);
|
|
47
|
+
line-height: var(--leading-title);
|
|
48
|
+
font-weight: var(--weight-semibold);
|
|
49
|
+
margin-top: var(--space-6);
|
|
50
|
+
margin-bottom: var(--space-2);
|
|
51
|
+
color: var(--color-fg);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.remarque-prose a {
|
|
55
|
+
color: var(--color-link);
|
|
56
|
+
text-decoration: underline;
|
|
57
|
+
text-underline-offset: 0.2em;
|
|
58
|
+
text-decoration-thickness: 1px;
|
|
59
|
+
transition: color var(--motion-fast) var(--motion-easing);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.remarque-prose a:hover {
|
|
63
|
+
color: var(--color-link-hover);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.remarque-prose strong {
|
|
67
|
+
font-weight: var(--weight-semibold);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.remarque-prose em {
|
|
71
|
+
font-style: italic;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.remarque-prose blockquote {
|
|
75
|
+
border-left: 2px solid var(--color-border-bold);
|
|
76
|
+
padding-left: var(--space-5);
|
|
77
|
+
margin-left: 0;
|
|
78
|
+
color: var(--color-fg-muted);
|
|
79
|
+
font-style: italic;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.remarque-prose ul,
|
|
83
|
+
.remarque-prose ol {
|
|
84
|
+
padding-left: var(--space-5);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.remarque-prose li + li {
|
|
88
|
+
margin-top: var(--space-2);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.remarque-prose code {
|
|
92
|
+
font-family: var(--font-mono);
|
|
93
|
+
font-size: 0.9em;
|
|
94
|
+
background-color: var(--color-code-bg);
|
|
95
|
+
padding: 0.15em 0.35em;
|
|
96
|
+
border-radius: var(--radius-sm);
|
|
97
|
+
color: var(--color-code-fg);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.remarque-prose pre {
|
|
101
|
+
font-family: var(--font-mono);
|
|
102
|
+
font-size: var(--text-meta);
|
|
103
|
+
line-height: 1.6;
|
|
104
|
+
background-color: var(--color-code-bg);
|
|
105
|
+
border: var(--border-width) var(--border-style) var(--color-border);
|
|
106
|
+
border-radius: var(--radius-md);
|
|
107
|
+
padding: var(--space-5);
|
|
108
|
+
overflow-x: auto;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.remarque-prose pre code {
|
|
112
|
+
background: none;
|
|
113
|
+
padding: 0;
|
|
114
|
+
border-radius: 0;
|
|
115
|
+
font-size: inherit;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.remarque-prose hr {
|
|
119
|
+
border: none;
|
|
120
|
+
border-top: var(--border-width) var(--border-style) var(--color-border);
|
|
121
|
+
margin: var(--space-8) 0;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.remarque-prose img {
|
|
125
|
+
max-width: 100%;
|
|
126
|
+
height: auto;
|
|
127
|
+
border: var(--border-width) var(--border-style) var(--color-border);
|
|
128
|
+
border-radius: var(--radius-sm);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.remarque-prose figcaption {
|
|
132
|
+
font-family: var(--font-mono);
|
|
133
|
+
font-size: var(--text-meta);
|
|
134
|
+
line-height: var(--leading-meta);
|
|
135
|
+
letter-spacing: var(--tracking-meta);
|
|
136
|
+
color: var(--color-muted);
|
|
137
|
+
margin-top: var(--space-2);
|
|
138
|
+
}
|
|
139
|
+
|
package/scripts/audit.mjs
CHANGED
|
@@ -22,7 +22,9 @@
|
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
24
|
import { readFileSync, readdirSync, statSync, existsSync } from 'node:fs';
|
|
25
|
-
import { join, relative } from 'node:path';
|
|
25
|
+
import { join, relative, dirname } from 'node:path';
|
|
26
|
+
import { fileURLToPath } from 'node:url';
|
|
27
|
+
import { extractBlocks, declsOf, isLightRoot, isDarkBlock } from './lib/css-tokens.mjs';
|
|
26
28
|
|
|
27
29
|
const args = process.argv.slice(2);
|
|
28
30
|
function argOf(flag, dflt) {
|
|
@@ -75,57 +77,9 @@ function ratio(c1, c2) {
|
|
|
75
77
|
return (hi + 0.05) / (lo + 0.05);
|
|
76
78
|
}
|
|
77
79
|
|
|
78
|
-
/* ── Brace-aware CSS block extraction ───────────────────── */
|
|
79
|
-
/* Returns [{ prelude, body, context }] where context is the enclosing
|
|
80
|
-
at-rule prelude ('' at top level). One level of at-rule nesting is
|
|
81
|
-
supported — enough for token files; deeper nesting is flattened with
|
|
82
|
-
its outermost context. Comments are stripped first. */
|
|
83
|
-
|
|
84
|
-
function extractBlocks(css) {
|
|
85
|
-
const src = css.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
86
|
-
const blocks = [];
|
|
87
|
-
function scan(text, context) {
|
|
88
|
-
let i = 0;
|
|
89
|
-
while (i < text.length) {
|
|
90
|
-
const open = text.indexOf('{', i);
|
|
91
|
-
if (open === -1) break;
|
|
92
|
-
const prelude = text.slice(i, open).trim().replace(/^[;\s]+/, '');
|
|
93
|
-
let depth = 1, j = open + 1;
|
|
94
|
-
while (j < text.length && depth > 0) {
|
|
95
|
-
if (text[j] === '{') depth++;
|
|
96
|
-
else if (text[j] === '}') depth--;
|
|
97
|
-
j++;
|
|
98
|
-
}
|
|
99
|
-
const body = text.slice(open + 1, j - 1);
|
|
100
|
-
if (prelude.startsWith('@')) {
|
|
101
|
-
scan(body, prelude);
|
|
102
|
-
} else {
|
|
103
|
-
blocks.push({ prelude, body, context });
|
|
104
|
-
}
|
|
105
|
-
i = j;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
scan(src, '');
|
|
109
|
-
return blocks;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
function declsOf(blocks, filterFn) {
|
|
113
|
-
const decls = {};
|
|
114
|
-
for (const b of blocks) {
|
|
115
|
-
if (!filterFn(b)) continue;
|
|
116
|
-
for (const m of b.body.matchAll(/--([a-z0-9-]+)\s*:\s*([^;]+);/g)) {
|
|
117
|
-
decls[m[1]] = m[2].trim();
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
return decls;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
80
|
const blocks = extractBlocks(readFileSync(PALETTE, 'utf8'));
|
|
124
|
-
const lightDecls = declsOf(blocks,
|
|
125
|
-
const darkOverrides = declsOf(blocks,
|
|
126
|
-
(b.context.includes('prefers-color-scheme') && b.context.includes('dark') && b.prelude.includes(':root')) ||
|
|
127
|
-
b.prelude.includes('[data-theme="dark"]')
|
|
128
|
-
);
|
|
81
|
+
const lightDecls = declsOf(blocks, isLightRoot);
|
|
82
|
+
const darkOverrides = declsOf(blocks, isDarkBlock);
|
|
129
83
|
if (Object.keys(lightDecls).length === 0) fail(`no top-level :root declarations found in ${PALETTE}`);
|
|
130
84
|
if (Object.keys(darkOverrides).length === 0) fail(`no dark-theme declarations found in ${PALETTE} (@media prefers-color-scheme: dark or [data-theme="dark"])`);
|
|
131
85
|
// CSS cascade: dark blocks override light; unset dark tokens inherit light values.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Shared CSS token extraction for scripts/audit.mjs and
|
|
3
|
+
* scripts/tokens-json.mjs (previously duplicated in both).
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/* Brace-aware CSS block extraction. Returns [{ prelude, body, context }]
|
|
7
|
+
where context is the enclosing at-rule prelude ('' at top level).
|
|
8
|
+
One level of at-rule nesting is supported — enough for token files;
|
|
9
|
+
deeper nesting is flattened with its outermost context. Comments are
|
|
10
|
+
stripped first. */
|
|
11
|
+
export function extractBlocks(css) {
|
|
12
|
+
const src = css.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
13
|
+
const blocks = [];
|
|
14
|
+
function scan(text, context) {
|
|
15
|
+
let i = 0;
|
|
16
|
+
while (i < text.length) {
|
|
17
|
+
const open = text.indexOf('{', i);
|
|
18
|
+
if (open === -1) break;
|
|
19
|
+
const prelude = text.slice(i, open).trim().replace(/^[;\s]+/, '');
|
|
20
|
+
let depth = 1, j = open + 1;
|
|
21
|
+
while (j < text.length && depth > 0) {
|
|
22
|
+
if (text[j] === '{') depth++;
|
|
23
|
+
else if (text[j] === '}') depth--;
|
|
24
|
+
j++;
|
|
25
|
+
}
|
|
26
|
+
const body = text.slice(open + 1, j - 1);
|
|
27
|
+
if (prelude.startsWith('@')) scan(body, prelude);
|
|
28
|
+
else blocks.push({ prelude, body, context });
|
|
29
|
+
i = j;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
scan(src, '');
|
|
33
|
+
return blocks;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function declsOf(blocks, filterFn) {
|
|
37
|
+
const decls = {};
|
|
38
|
+
for (const b of blocks) {
|
|
39
|
+
if (!filterFn(b)) continue;
|
|
40
|
+
for (const m of b.body.matchAll(/--([a-z0-9-]+)\s*:\s*([^;]+);/g)) {
|
|
41
|
+
decls[m[1]] = m[2].trim();
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return decls;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/* Standard tier filters */
|
|
48
|
+
export const isLightRoot = (b) => b.context === '' && b.prelude.includes(':root');
|
|
49
|
+
export const isDarkBlock = (b) =>
|
|
50
|
+
(b.context.includes('prefers-color-scheme') && b.context.includes('dark') && b.prelude.includes(':root')) ||
|
|
51
|
+
b.prelude.includes('[data-theme="dark"]');
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/*
|
|
3
|
+
* Generates tokens.json (W3C design-tokens flavored) FROM the CSS —
|
|
4
|
+
* tokens-core.css and tokens-palette.css remain the single source of
|
|
5
|
+
* truth; this file is derived output for tooling and AI agents.
|
|
6
|
+
*
|
|
7
|
+
* node scripts/tokens-json.mjs # (re)write tokens.json
|
|
8
|
+
* node scripts/tokens-json.mjs --check # exit 1 if tokens.json is stale (CI)
|
|
9
|
+
*
|
|
10
|
+
* Multi-theme values use per-token light/dark groups with $value on each
|
|
11
|
+
* (the W3C spec has no native theming; this follows its $extensions
|
|
12
|
+
* escape hatch conservatively).
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { readFileSync, writeFileSync, existsSync } from 'node:fs';
|
|
16
|
+
import { extractBlocks, declsOf, isLightRoot, isDarkBlock } from './lib/css-tokens.mjs';
|
|
17
|
+
|
|
18
|
+
function typeOf(name, value) {
|
|
19
|
+
if (name.startsWith('color-')) return 'color';
|
|
20
|
+
if (name.startsWith('font-')) return 'fontFamily';
|
|
21
|
+
if (name.startsWith('weight-')) return 'fontWeight';
|
|
22
|
+
if (name.startsWith('motion-') && /ms$/.test(value)) return 'duration';
|
|
23
|
+
if (name.startsWith('leading-')) return 'number';
|
|
24
|
+
if (value === '0') return 'dimension';
|
|
25
|
+
if (/(^|\s)(rem|px|em|%)/.test(value) || /^-?[\d.]+(rem|px|em)$/.test(value) || value.startsWith('clamp(')) return 'dimension';
|
|
26
|
+
return 'string';
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// W3C spec: number-like types carry numeric $value, not strings.
|
|
30
|
+
function valueFor(type, value) {
|
|
31
|
+
if (type === 'number' || type === 'fontWeight') {
|
|
32
|
+
const n = Number(value);
|
|
33
|
+
if (!Number.isNaN(n)) return n;
|
|
34
|
+
}
|
|
35
|
+
return value;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const version = JSON.parse(readFileSync('package.json', 'utf8')).version;
|
|
39
|
+
const coreDecls = declsOf(extractBlocks(readFileSync('tokens-core.css', 'utf8')), isLightRoot);
|
|
40
|
+
const paletteBlocks = extractBlocks(readFileSync('tokens-palette.css', 'utf8'));
|
|
41
|
+
const lightDecls = declsOf(paletteBlocks, isLightRoot);
|
|
42
|
+
const darkOverrides = declsOf(paletteBlocks, isDarkBlock);
|
|
43
|
+
|
|
44
|
+
const out = {
|
|
45
|
+
$description: 'Remarque design tokens — GENERATED from tokens-core.css + tokens-palette.css by scripts/tokens-json.mjs. Do not edit; the CSS is the source of truth.',
|
|
46
|
+
$extensions: {
|
|
47
|
+
remarque: {
|
|
48
|
+
version,
|
|
49
|
+
tiers: {
|
|
50
|
+
core: 'immutable identity — overriding forks the system',
|
|
51
|
+
palette: 'sanctioned personalization surface — override freely, then run remarque-audit',
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
core: {},
|
|
56
|
+
palette: {},
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
for (const [name, value] of Object.entries(coreDecls)) {
|
|
60
|
+
const $type = typeOf(name, value);
|
|
61
|
+
out.core[name] = { $value: valueFor($type, value), $type };
|
|
62
|
+
}
|
|
63
|
+
for (const [name, value] of Object.entries(lightDecls)) {
|
|
64
|
+
const $type = typeOf(name, value);
|
|
65
|
+
const token = { $type, light: { $value: valueFor($type, value) } };
|
|
66
|
+
if (name in darkOverrides) token.dark = { $value: valueFor($type, darkOverrides[name]) };
|
|
67
|
+
else token.dark = { $value: valueFor($type, value), $extensions: { remarque: { inheritedFromLight: true } } };
|
|
68
|
+
out.palette[name] = token;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const json = JSON.stringify(out, null, 2) + '\n';
|
|
72
|
+
|
|
73
|
+
if (process.argv.includes('--check')) {
|
|
74
|
+
const current = existsSync('tokens.json') ? readFileSync('tokens.json', 'utf8') : '';
|
|
75
|
+
if (current !== json) {
|
|
76
|
+
console.error('tokens.json is stale — run: node scripts/tokens-json.mjs');
|
|
77
|
+
process.exit(1);
|
|
78
|
+
}
|
|
79
|
+
console.log('tokens.json is fresh ✓');
|
|
80
|
+
} else {
|
|
81
|
+
writeFileSync('tokens.json', json);
|
|
82
|
+
console.log(`tokens.json written — ${Object.keys(out.core).length} core + ${Object.keys(out.palette).length} palette tokens (v${version})`);
|
|
83
|
+
}
|
package/theme.css
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Remarque — Tailwind v4 Theme Adapter
|
|
3
|
+
* ─────────────────────────────────────
|
|
4
|
+
* Maps Remarque's runtime CSS custom properties into Tailwind v4
|
|
5
|
+
* utilities (font-display, bg-surface, max-w-reading, mt-remarque-9, …)
|
|
6
|
+
* without duplicating any values: `@theme inline` makes utilities
|
|
7
|
+
* reference the vars directly, so light/dark/theme-deck palette
|
|
8
|
+
* switches flow through automatically and tokens-palette.css stays the
|
|
9
|
+
* single source of color truth.
|
|
10
|
+
*
|
|
11
|
+
* Usage (order matters — Tailwind first, tokens before this file):
|
|
12
|
+
* @import "tailwindcss";
|
|
13
|
+
* @import "remarque-tokens";
|
|
14
|
+
* @import "remarque-tokens/theme.css";
|
|
15
|
+
*
|
|
16
|
+
* IMPORTANT: import "remarque-tokens" UNLAYERED — never wrap it in
|
|
17
|
+
* layer(...). Tailwind still emits the same-named theme keys as
|
|
18
|
+
* self-referencing declarations inside @layer theme; they are inert
|
|
19
|
+
* only because unlayered token declarations always beat layered ones
|
|
20
|
+
* in the cascade. Wrapping the tokens in a layer would make every
|
|
21
|
+
* mapped utility resolve to an invalid circular value.
|
|
22
|
+
*
|
|
23
|
+
* Spacing is namespaced remarque-* so Tailwind's default numeric scale
|
|
24
|
+
* is never overridden (mt-12 stays 3rem; use mt-remarque-9 for 6rem).
|
|
25
|
+
* Motion utilities: use arbitrary values with the tokens —
|
|
26
|
+
* duration-[var(--motion-fast)] — so reduced-motion zeroing applies.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
@theme inline {
|
|
30
|
+
/* Font slots */
|
|
31
|
+
--font-display: var(--font-display);
|
|
32
|
+
--font-body: var(--font-body);
|
|
33
|
+
--font-mono: var(--font-mono);
|
|
34
|
+
|
|
35
|
+
/* Colors — track the palette tier through every theme switch */
|
|
36
|
+
--color-bg: var(--color-bg);
|
|
37
|
+
--color-bg-subtle: var(--color-bg-subtle);
|
|
38
|
+
--color-fg: var(--color-fg);
|
|
39
|
+
--color-fg-muted: var(--color-fg-muted);
|
|
40
|
+
--color-muted: var(--color-muted);
|
|
41
|
+
--color-border: var(--color-border);
|
|
42
|
+
--color-border-bold: var(--color-border-bold);
|
|
43
|
+
--color-surface: var(--color-surface);
|
|
44
|
+
--color-accent: var(--color-accent);
|
|
45
|
+
--color-accent-hover: var(--color-accent-hover);
|
|
46
|
+
--color-accent-subtle: var(--color-accent-subtle);
|
|
47
|
+
--color-code-bg: var(--color-code-bg);
|
|
48
|
+
--color-code-fg: var(--color-code-fg);
|
|
49
|
+
--color-link: var(--color-link);
|
|
50
|
+
--color-link-hover: var(--color-link-hover);
|
|
51
|
+
--color-focus-ring: var(--color-focus-ring);
|
|
52
|
+
--color-selection-bg: var(--color-selection-bg);
|
|
53
|
+
--color-selection-fg: var(--color-selection-fg);
|
|
54
|
+
|
|
55
|
+
/* Content widths (max-w-reading / -standard / -wide) */
|
|
56
|
+
--max-width-reading: var(--content-reading);
|
|
57
|
+
--max-width-standard: var(--content-standard);
|
|
58
|
+
--max-width-wide: var(--content-wide);
|
|
59
|
+
|
|
60
|
+
/* Remarque spacing scale, namespaced (mt-remarque-9 = 6rem, …) */
|
|
61
|
+
--spacing-remarque-1: var(--space-1);
|
|
62
|
+
--spacing-remarque-2: var(--space-2);
|
|
63
|
+
--spacing-remarque-3: var(--space-3);
|
|
64
|
+
--spacing-remarque-4: var(--space-4);
|
|
65
|
+
--spacing-remarque-5: var(--space-5);
|
|
66
|
+
--spacing-remarque-6: var(--space-6);
|
|
67
|
+
--spacing-remarque-7: var(--space-7);
|
|
68
|
+
--spacing-remarque-8: var(--space-8);
|
|
69
|
+
--spacing-remarque-9: var(--space-9);
|
|
70
|
+
--spacing-remarque-10: var(--space-10);
|
|
71
|
+
--spacing-remarque-11: var(--space-11);
|
|
72
|
+
--spacing-remarque-12: var(--space-12);
|
|
73
|
+
|
|
74
|
+
/* Radius (rounded-sm / rounded-md — the system's ceiling) */
|
|
75
|
+
--radius-sm: var(--radius-sm);
|
|
76
|
+
--radius-md: var(--radius-md);
|
|
77
|
+
}
|
package/tokens-core.css
CHANGED
|
@@ -191,135 +191,6 @@ html {
|
|
|
191
191
|
margin-inline: auto;
|
|
192
192
|
}
|
|
193
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
194
|
/* ─── Focus Styles ──────────────────────────────────────── */
|
|
324
195
|
|
|
325
196
|
:focus-visible {
|
package/tokens.css
CHANGED
package/tokens.json
ADDED
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$description": "Remarque design tokens — GENERATED from tokens-core.css + tokens-palette.css by scripts/tokens-json.mjs. Do not edit; the CSS is the source of truth.",
|
|
3
|
+
"$extensions": {
|
|
4
|
+
"remarque": {
|
|
5
|
+
"version": "0.4.0",
|
|
6
|
+
"tiers": {
|
|
7
|
+
"core": "immutable identity — overriding forks the system",
|
|
8
|
+
"palette": "sanctioned personalization surface — override freely, then run remarque-audit"
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"core": {
|
|
13
|
+
"text-display": {
|
|
14
|
+
"$value": "clamp(2.75rem, 5.5vw, 5rem)",
|
|
15
|
+
"$type": "dimension"
|
|
16
|
+
},
|
|
17
|
+
"text-title": {
|
|
18
|
+
"$value": "clamp(1.875rem, 3.5vw, 3rem)",
|
|
19
|
+
"$type": "dimension"
|
|
20
|
+
},
|
|
21
|
+
"text-section": {
|
|
22
|
+
"$value": "clamp(1.375rem, 2.25vw, 2rem)",
|
|
23
|
+
"$type": "dimension"
|
|
24
|
+
},
|
|
25
|
+
"text-body-lg": {
|
|
26
|
+
"$value": "1.1875rem",
|
|
27
|
+
"$type": "dimension"
|
|
28
|
+
},
|
|
29
|
+
"text-body": {
|
|
30
|
+
"$value": "1.0625rem",
|
|
31
|
+
"$type": "dimension"
|
|
32
|
+
},
|
|
33
|
+
"text-meta": {
|
|
34
|
+
"$value": "0.875rem",
|
|
35
|
+
"$type": "dimension"
|
|
36
|
+
},
|
|
37
|
+
"text-micro": {
|
|
38
|
+
"$value": "0.8125rem",
|
|
39
|
+
"$type": "dimension"
|
|
40
|
+
},
|
|
41
|
+
"leading-display": {
|
|
42
|
+
"$value": 1.05,
|
|
43
|
+
"$type": "number"
|
|
44
|
+
},
|
|
45
|
+
"leading-title": {
|
|
46
|
+
"$value": 1.15,
|
|
47
|
+
"$type": "number"
|
|
48
|
+
},
|
|
49
|
+
"leading-section": {
|
|
50
|
+
"$value": 1.2,
|
|
51
|
+
"$type": "number"
|
|
52
|
+
},
|
|
53
|
+
"leading-body": {
|
|
54
|
+
"$value": 1.75,
|
|
55
|
+
"$type": "number"
|
|
56
|
+
},
|
|
57
|
+
"leading-meta": {
|
|
58
|
+
"$value": 1.5,
|
|
59
|
+
"$type": "number"
|
|
60
|
+
},
|
|
61
|
+
"tracking-display": {
|
|
62
|
+
"$value": "-0.02em",
|
|
63
|
+
"$type": "dimension"
|
|
64
|
+
},
|
|
65
|
+
"tracking-title": {
|
|
66
|
+
"$value": "-0.015em",
|
|
67
|
+
"$type": "dimension"
|
|
68
|
+
},
|
|
69
|
+
"tracking-body": {
|
|
70
|
+
"$value": "0em",
|
|
71
|
+
"$type": "dimension"
|
|
72
|
+
},
|
|
73
|
+
"tracking-meta": {
|
|
74
|
+
"$value": "0.02em",
|
|
75
|
+
"$type": "dimension"
|
|
76
|
+
},
|
|
77
|
+
"tracking-caps": {
|
|
78
|
+
"$value": "0.06em",
|
|
79
|
+
"$type": "dimension"
|
|
80
|
+
},
|
|
81
|
+
"weight-regular": {
|
|
82
|
+
"$value": 400,
|
|
83
|
+
"$type": "fontWeight"
|
|
84
|
+
},
|
|
85
|
+
"weight-medium": {
|
|
86
|
+
"$value": 500,
|
|
87
|
+
"$type": "fontWeight"
|
|
88
|
+
},
|
|
89
|
+
"weight-semibold": {
|
|
90
|
+
"$value": 600,
|
|
91
|
+
"$type": "fontWeight"
|
|
92
|
+
},
|
|
93
|
+
"space-1": {
|
|
94
|
+
"$value": "0.25rem",
|
|
95
|
+
"$type": "dimension"
|
|
96
|
+
},
|
|
97
|
+
"space-2": {
|
|
98
|
+
"$value": "0.5rem",
|
|
99
|
+
"$type": "dimension"
|
|
100
|
+
},
|
|
101
|
+
"space-3": {
|
|
102
|
+
"$value": "0.75rem",
|
|
103
|
+
"$type": "dimension"
|
|
104
|
+
},
|
|
105
|
+
"space-4": {
|
|
106
|
+
"$value": "1rem",
|
|
107
|
+
"$type": "dimension"
|
|
108
|
+
},
|
|
109
|
+
"space-5": {
|
|
110
|
+
"$value": "1.5rem",
|
|
111
|
+
"$type": "dimension"
|
|
112
|
+
},
|
|
113
|
+
"space-6": {
|
|
114
|
+
"$value": "2rem",
|
|
115
|
+
"$type": "dimension"
|
|
116
|
+
},
|
|
117
|
+
"space-7": {
|
|
118
|
+
"$value": "3rem",
|
|
119
|
+
"$type": "dimension"
|
|
120
|
+
},
|
|
121
|
+
"space-8": {
|
|
122
|
+
"$value": "4rem",
|
|
123
|
+
"$type": "dimension"
|
|
124
|
+
},
|
|
125
|
+
"space-9": {
|
|
126
|
+
"$value": "6rem",
|
|
127
|
+
"$type": "dimension"
|
|
128
|
+
},
|
|
129
|
+
"space-10": {
|
|
130
|
+
"$value": "8rem",
|
|
131
|
+
"$type": "dimension"
|
|
132
|
+
},
|
|
133
|
+
"space-11": {
|
|
134
|
+
"$value": "10rem",
|
|
135
|
+
"$type": "dimension"
|
|
136
|
+
},
|
|
137
|
+
"space-12": {
|
|
138
|
+
"$value": "12rem",
|
|
139
|
+
"$type": "dimension"
|
|
140
|
+
},
|
|
141
|
+
"content-standard": {
|
|
142
|
+
"$value": "72rem",
|
|
143
|
+
"$type": "dimension"
|
|
144
|
+
},
|
|
145
|
+
"content-wide": {
|
|
146
|
+
"$value": "88rem",
|
|
147
|
+
"$type": "dimension"
|
|
148
|
+
},
|
|
149
|
+
"radius-sm": {
|
|
150
|
+
"$value": "0.25rem",
|
|
151
|
+
"$type": "dimension"
|
|
152
|
+
},
|
|
153
|
+
"radius-md": {
|
|
154
|
+
"$value": "0.5rem",
|
|
155
|
+
"$type": "dimension"
|
|
156
|
+
},
|
|
157
|
+
"radius-none": {
|
|
158
|
+
"$value": "0",
|
|
159
|
+
"$type": "dimension"
|
|
160
|
+
},
|
|
161
|
+
"border-width": {
|
|
162
|
+
"$value": "1px",
|
|
163
|
+
"$type": "dimension"
|
|
164
|
+
},
|
|
165
|
+
"border-style": {
|
|
166
|
+
"$value": "solid",
|
|
167
|
+
"$type": "string"
|
|
168
|
+
},
|
|
169
|
+
"motion-fast": {
|
|
170
|
+
"$value": "120ms",
|
|
171
|
+
"$type": "duration"
|
|
172
|
+
},
|
|
173
|
+
"motion-normal": {
|
|
174
|
+
"$value": "180ms",
|
|
175
|
+
"$type": "duration"
|
|
176
|
+
},
|
|
177
|
+
"motion-easing": {
|
|
178
|
+
"$value": "ease-out",
|
|
179
|
+
"$type": "string"
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
"palette": {
|
|
183
|
+
"font-display": {
|
|
184
|
+
"$type": "fontFamily",
|
|
185
|
+
"light": {
|
|
186
|
+
"$value": "\"Newsreader\", Georgia, \"Times New Roman\", serif"
|
|
187
|
+
},
|
|
188
|
+
"dark": {
|
|
189
|
+
"$value": "\"Newsreader\", Georgia, \"Times New Roman\", serif",
|
|
190
|
+
"$extensions": {
|
|
191
|
+
"remarque": {
|
|
192
|
+
"inheritedFromLight": true
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
"font-body": {
|
|
198
|
+
"$type": "fontFamily",
|
|
199
|
+
"light": {
|
|
200
|
+
"$value": "\"Inter\", ui-sans-serif, system-ui, -apple-system, sans-serif"
|
|
201
|
+
},
|
|
202
|
+
"dark": {
|
|
203
|
+
"$value": "\"Inter\", ui-sans-serif, system-ui, -apple-system, sans-serif",
|
|
204
|
+
"$extensions": {
|
|
205
|
+
"remarque": {
|
|
206
|
+
"inheritedFromLight": true
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
},
|
|
211
|
+
"font-mono": {
|
|
212
|
+
"$type": "fontFamily",
|
|
213
|
+
"light": {
|
|
214
|
+
"$value": "\"JetBrains Mono\", ui-monospace, \"Cascadia Code\", \"Fira Code\", monospace"
|
|
215
|
+
},
|
|
216
|
+
"dark": {
|
|
217
|
+
"$value": "\"JetBrains Mono\", ui-monospace, \"Cascadia Code\", \"Fira Code\", monospace",
|
|
218
|
+
"$extensions": {
|
|
219
|
+
"remarque": {
|
|
220
|
+
"inheritedFromLight": true
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
"content-reading": {
|
|
226
|
+
"$type": "dimension",
|
|
227
|
+
"light": {
|
|
228
|
+
"$value": "46rem"
|
|
229
|
+
},
|
|
230
|
+
"dark": {
|
|
231
|
+
"$value": "46rem",
|
|
232
|
+
"$extensions": {
|
|
233
|
+
"remarque": {
|
|
234
|
+
"inheritedFromLight": true
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
},
|
|
239
|
+
"color-bg": {
|
|
240
|
+
"$type": "color",
|
|
241
|
+
"light": {
|
|
242
|
+
"$value": "oklch(0.975 0.005 80)"
|
|
243
|
+
},
|
|
244
|
+
"dark": {
|
|
245
|
+
"$value": "oklch(0.16 0.01 80)"
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
"color-bg-subtle": {
|
|
249
|
+
"$type": "color",
|
|
250
|
+
"light": {
|
|
251
|
+
"$value": "oklch(0.955 0.005 80)"
|
|
252
|
+
},
|
|
253
|
+
"dark": {
|
|
254
|
+
"$value": "oklch(0.19 0.01 80)"
|
|
255
|
+
}
|
|
256
|
+
},
|
|
257
|
+
"color-fg": {
|
|
258
|
+
"$type": "color",
|
|
259
|
+
"light": {
|
|
260
|
+
"$value": "oklch(0.18 0.01 80)"
|
|
261
|
+
},
|
|
262
|
+
"dark": {
|
|
263
|
+
"$value": "oklch(0.90 0.005 80)"
|
|
264
|
+
}
|
|
265
|
+
},
|
|
266
|
+
"color-fg-muted": {
|
|
267
|
+
"$type": "color",
|
|
268
|
+
"light": {
|
|
269
|
+
"$value": "oklch(0.43 0.015 80)"
|
|
270
|
+
},
|
|
271
|
+
"dark": {
|
|
272
|
+
"$value": "oklch(0.70 0.01 80)"
|
|
273
|
+
}
|
|
274
|
+
},
|
|
275
|
+
"color-muted": {
|
|
276
|
+
"$type": "color",
|
|
277
|
+
"light": {
|
|
278
|
+
"$value": "oklch(0.54 0.01 80)"
|
|
279
|
+
},
|
|
280
|
+
"dark": {
|
|
281
|
+
"$value": "oklch(0.60 0.01 80)"
|
|
282
|
+
}
|
|
283
|
+
},
|
|
284
|
+
"color-border": {
|
|
285
|
+
"$type": "color",
|
|
286
|
+
"light": {
|
|
287
|
+
"$value": "oklch(0.88 0.005 80)"
|
|
288
|
+
},
|
|
289
|
+
"dark": {
|
|
290
|
+
"$value": "oklch(0.25 0.005 80)"
|
|
291
|
+
}
|
|
292
|
+
},
|
|
293
|
+
"color-border-bold": {
|
|
294
|
+
"$type": "color",
|
|
295
|
+
"light": {
|
|
296
|
+
"$value": "oklch(0.62 0.01 80)"
|
|
297
|
+
},
|
|
298
|
+
"dark": {
|
|
299
|
+
"$value": "oklch(0.50 0.01 80)"
|
|
300
|
+
}
|
|
301
|
+
},
|
|
302
|
+
"color-surface": {
|
|
303
|
+
"$type": "color",
|
|
304
|
+
"light": {
|
|
305
|
+
"$value": "oklch(0.965 0.005 80)"
|
|
306
|
+
},
|
|
307
|
+
"dark": {
|
|
308
|
+
"$value": "oklch(0.19 0.01 80)"
|
|
309
|
+
}
|
|
310
|
+
},
|
|
311
|
+
"color-accent": {
|
|
312
|
+
"$type": "color",
|
|
313
|
+
"light": {
|
|
314
|
+
"$value": "oklch(0.50 0.14 250)"
|
|
315
|
+
},
|
|
316
|
+
"dark": {
|
|
317
|
+
"$value": "oklch(0.68 0.12 250)"
|
|
318
|
+
}
|
|
319
|
+
},
|
|
320
|
+
"color-accent-hover": {
|
|
321
|
+
"$type": "color",
|
|
322
|
+
"light": {
|
|
323
|
+
"$value": "oklch(0.42 0.11 250)"
|
|
324
|
+
},
|
|
325
|
+
"dark": {
|
|
326
|
+
"$value": "oklch(0.75 0.12 250)"
|
|
327
|
+
}
|
|
328
|
+
},
|
|
329
|
+
"color-accent-subtle": {
|
|
330
|
+
"$type": "color",
|
|
331
|
+
"light": {
|
|
332
|
+
"$value": "oklch(0.95 0.02 250)"
|
|
333
|
+
},
|
|
334
|
+
"dark": {
|
|
335
|
+
"$value": "oklch(0.22 0.04 250)"
|
|
336
|
+
}
|
|
337
|
+
},
|
|
338
|
+
"color-link": {
|
|
339
|
+
"$type": "color",
|
|
340
|
+
"light": {
|
|
341
|
+
"$value": "var(--color-accent)"
|
|
342
|
+
},
|
|
343
|
+
"dark": {
|
|
344
|
+
"$value": "var(--color-accent)",
|
|
345
|
+
"$extensions": {
|
|
346
|
+
"remarque": {
|
|
347
|
+
"inheritedFromLight": true
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
},
|
|
352
|
+
"color-link-hover": {
|
|
353
|
+
"$type": "color",
|
|
354
|
+
"light": {
|
|
355
|
+
"$value": "var(--color-accent-hover)"
|
|
356
|
+
},
|
|
357
|
+
"dark": {
|
|
358
|
+
"$value": "var(--color-accent-hover)",
|
|
359
|
+
"$extensions": {
|
|
360
|
+
"remarque": {
|
|
361
|
+
"inheritedFromLight": true
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
},
|
|
366
|
+
"color-focus-ring": {
|
|
367
|
+
"$type": "color",
|
|
368
|
+
"light": {
|
|
369
|
+
"$value": "var(--color-accent)"
|
|
370
|
+
},
|
|
371
|
+
"dark": {
|
|
372
|
+
"$value": "var(--color-accent)",
|
|
373
|
+
"$extensions": {
|
|
374
|
+
"remarque": {
|
|
375
|
+
"inheritedFromLight": true
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
},
|
|
380
|
+
"color-selection-bg": {
|
|
381
|
+
"$type": "color",
|
|
382
|
+
"light": {
|
|
383
|
+
"$value": "oklch(0.92 0.04 250)"
|
|
384
|
+
},
|
|
385
|
+
"dark": {
|
|
386
|
+
"$value": "oklch(0.30 0.06 250)"
|
|
387
|
+
}
|
|
388
|
+
},
|
|
389
|
+
"color-selection-fg": {
|
|
390
|
+
"$type": "color",
|
|
391
|
+
"light": {
|
|
392
|
+
"$value": "var(--color-fg)"
|
|
393
|
+
},
|
|
394
|
+
"dark": {
|
|
395
|
+
"$value": "oklch(0.92 0.005 80)"
|
|
396
|
+
}
|
|
397
|
+
},
|
|
398
|
+
"color-code-bg": {
|
|
399
|
+
"$type": "color",
|
|
400
|
+
"light": {
|
|
401
|
+
"$value": "oklch(0.945 0.005 80)"
|
|
402
|
+
},
|
|
403
|
+
"dark": {
|
|
404
|
+
"$value": "oklch(0.20 0.005 80)"
|
|
405
|
+
}
|
|
406
|
+
},
|
|
407
|
+
"color-code-fg": {
|
|
408
|
+
"$type": "color",
|
|
409
|
+
"light": {
|
|
410
|
+
"$value": "var(--color-fg)"
|
|
411
|
+
},
|
|
412
|
+
"dark": {
|
|
413
|
+
"$value": "oklch(0.88 0.005 80)"
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
}
|