remarque-tokens 0.27.0 → 0.29.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 +28 -5
- package/CHANGELOG.md +95 -0
- package/README.md +28 -3
- package/REMARQUE.md +211 -28
- package/broadsheet.css +62 -14
- package/chrome.css +364 -0
- package/essay.css +47 -24
- package/fonts/features.json +100 -0
- package/forms.css +10 -6
- package/package.json +9 -3
- package/print.css +3 -0
- package/prose.css +47 -15
- package/registry/breadcrumb.json +53 -0
- package/registry/broadsheet.json +5 -4
- package/registry/essay.json +3 -3
- package/registry/forms.json +4 -4
- package/registry/pager.json +53 -0
- package/registry/palette-deck.json +1 -1
- package/registry/skip-link.json +53 -0
- package/registry/tags.json +53 -0
- package/registry.json +45 -9
- package/scripts/audit.mjs +73 -1
- package/scripts/build-registry.mjs +33 -1
- package/scripts/lib/font-features.mjs +148 -0
- package/scripts/lib/palette-coherence.mjs +234 -0
- package/scripts/theme.mjs +78 -9
- package/scripts/tokens-json.mjs +21 -15
- package/skills/remarque-new-page/SKILL.md +1 -1
- package/tokens-core.css +48 -7
- package/tokens.d.ts +1 -1
- package/tokens.json +11 -6
- package/tokens.schema.json +1 -1
package/AGENT_RULES.md
CHANGED
|
@@ -8,7 +8,7 @@ Read `REMARQUE.md` first for the full system specification. This file tells you
|
|
|
8
8
|
|
|
9
9
|
## Prefer the Registry Over Transcribing Prose
|
|
10
10
|
|
|
11
|
-
For the Essay Module, the Broadsheet pattern, and
|
|
11
|
+
For the Essay Module, the Broadsheet pattern, Forms and the Chrome Module (`remarque-tokens/essay`, `remarque-tokens/broadsheet`, `remarque-tokens/forms`, `remarque-tokens/chrome`), a machine-readable markup-contract registry ships alongside the spec (REMARQUE.md "The Registry"; issue #100). **Agents building a Remarque page SHOULD fetch the relevant registry item and apply its `usage.html`/CSS `content` verbatim, rather than re-typing the markup from this file's or REMARQUE.md's prose.**
|
|
12
12
|
|
|
13
13
|
- Fetch `https://williamzujkowski.github.io/remarque/registry/<name>.json` (`essay`, `broadsheet`, `forms`, or `palette-deck`), or read it from an installed package at `node_modules/remarque-tokens/registry/<name>.json` — same content either way.
|
|
14
14
|
- The known-good markup lives in `files[].content` where `type` is `"remarque:markup"`; the CSS module (if any) is in the `"remarque:css"` entry. Both are the exact, versioned, hash-pinned (`integrity`) bytes — copy them, don't re-derive them from memory.
|
|
@@ -221,11 +221,13 @@ Before considering any implementation complete, verify:
|
|
|
221
221
|
- [ ] Every image has a 1px border and mono caption
|
|
222
222
|
- [ ] Every page maps to an archetype (Essay, Dossier, Notebook, Landing, Reference/Docs, Changelog, Gallery)
|
|
223
223
|
- [ ] If the Essay uses sidenotes/a TOC rail (`remarque-tokens/essay`): `.remarque-sidenote-ref`/`.remarque-sidenote` alternate in strict DOM order, the rail never intrudes into `.remarque-prose`'s own measure, and the page renders correctly with `essay.css`'s `@media` block deleted (the narrow-viewport/no-JS fallback)
|
|
224
|
-
- [ ] If a Landing/archive page uses the Broadsheet pattern (`remarque-tokens/broadsheet`): entry numerals are generated from `data-entry-number` via `attr()` (not `counter()`), the entry list stays a `<ul>` (not `<ol>` — the numeral is `aria-hidden` and decorative), and every kicker/dateline row uses `font-variant-caps: all-small-caps
|
|
225
|
-
- [ ]
|
|
224
|
+
- [ ] If a Landing/archive page uses the Broadsheet pattern (`remarque-tokens/broadsheet`): entry numerals are generated from `data-entry-number` via `attr()` (not `counter()`), the entry list stays a `<ul>` (not `<ol>` — the numeral is `aria-hidden` and decorative), and every kicker/dateline row uses the label voice: tracked capitals (`text-transform: uppercase` + `--tracking-caps`), because the default mono face has no small caps; `font-variant-caps: all-small-caps` only on a label face that has `smcp` + `c2sc` (REMARQUE.md "Small Caps"; `remarque-audit` fails synthesized small caps)
|
|
225
|
+
- [ ] Site chrome uses `remarque-tokens/chrome` instead of hand-rolled copies: `.remarque-skip-link` is the first focusable element and targets `<main id="main-content" tabindex="-1">`; a breadcrumb's current page is `<span aria-current="page">`, never a link, with no separator typed into the DOM; prev/next links carry `rel="prev"`/`rel="next"` and an endpoint with nowhere to go is omitted (or plain text in numbered pagination), never a disabled-looking link; tags are plain mono links with `rel="tag"`, no border, fill or radius (REMARQUE.md "Chrome Module")
|
|
226
|
+
- [ ] If a page uses form controls (`remarque-tokens/forms`): checkboxes/radios are styled with `accent-color` only — never `appearance: none` plus a hand-drawn replacement; every control (input, button, checkbox/radio label) is ≥44×44px; every input collecting known personal data has a valid `autocomplete` token and paste is never blocked (WCAG 3.3.7/3.3.8); validation state lives on `.remarque-field[data-state]` AND a real `aria-invalid`/`aria-describedby` pair on the input, not `data-state` alone; disabled controls use `--color-disabled`, never a state color
|
|
226
227
|
- [ ] If a page uses the Palette Deck (`remarque-tokens/deck`): `data-palette` is set/cleared on the same root element as `data-theme` (they compose, never conflict); the FOUC-safe restore is a synchronous classic `<script>` physically in `<head>` (never `type="module"`, which defers); the switcher control itself is a native, keyboard-operable element (e.g. `.remarque-input` `<select>`) at ≥44×44px, not a hand-rolled widget; every registered palette was generated via `remarque-theme --scope`, never hand-authored
|
|
227
228
|
- [ ] Mobile version is roomy — not a compressed desktop layout
|
|
228
|
-
- [ ] Mobile nav links have ≥44px touch targets
|
|
229
|
+
- [ ] Mobile nav links have ≥44px touch targets (meets WCAG 2.5.8 AA; exceeds it, and meets 2.5.5 AAA)
|
|
230
|
+
- [ ] WCAG 2.2 AA (not 2.1): any consumer sticky/fixed chrome has `scroll-padding-top`/`-bottom` so focus is never obscured (2.4.11); inputs collecting known personal data carry a valid `autocomplete` token and never block paste (3.3.7, 3.3.8); `cd site && npx playwright test tests/a11y.spec.ts` (axe-core) passes. See REMARQUE.md "WCAG 2.2 AA Criterion Map"
|
|
229
231
|
- [ ] No pure white or pure black backgrounds
|
|
230
232
|
- [ ] `npm run audit` passes (contrast, gamut, font floors, hardcoded colors)
|
|
231
233
|
- [ ] Muted text placed on `--color-surface` still meets 4.5:1 (check the surface pairing, not just bg)
|
|
@@ -261,7 +263,7 @@ npx remarque-audit --palette <file> --src <dir> --json
|
|
|
261
263
|
version: string; // the remarque-tokens package version running the audit
|
|
262
264
|
palette: string; // the --palette path as given
|
|
263
265
|
src: string; // the --src path as given
|
|
264
|
-
passed: boolean; // true iff failures.length === 0
|
|
266
|
+
passed: boolean; // true iff failures.length === 0 (warnings do not count)
|
|
265
267
|
contrast: Array<{
|
|
266
268
|
theme: 'light' | 'dark';
|
|
267
269
|
fg: string; // fg token name, no leading --
|
|
@@ -286,9 +288,30 @@ npx remarque-audit --palette <file> --src <dir> --json
|
|
|
286
288
|
ambiguousTextSize: Array<{ file: string; line: number; snippet: string }>; // Tailwind text-[var(--text-*)] (Pitfall #8)
|
|
287
289
|
};
|
|
288
290
|
failures: string[]; // every failure as a human-readable message, same text the non-JSON run prints
|
|
291
|
+
warnings: Array<{ // palette-coherence warnings (REMARQUE.md "Palette Coherence"); added in 0.28.0, additive
|
|
292
|
+
id: string; // 'text-tier-monotonic' | 'accent-vs-fg' | 'accent-vs-error' | 'accent-vs-viz-1' | 'error-vs-success-deutan' | 'surface-step' | 'viz-cvd-normal' | 'viz-cvd-protan' | 'viz-cvd-deutan' | 'viz-cvd-tritan'
|
|
293
|
+
theme: 'light' | 'dark';
|
|
294
|
+
tokens: string[]; // the token names involved, no leading --
|
|
295
|
+
actual: number; // measured value (ΔE2000, or the contrast shortfall for text tiers), 2dp
|
|
296
|
+
threshold: number; // the minimum it was compared to
|
|
297
|
+
message: string; // human-readable, same text the non-JSON run prints
|
|
298
|
+
}>;
|
|
299
|
+
fontFeatures: Array<{ // font-feature requests the face can't render (REMARQUE.md "Small Caps"); added in 0.28.0, additive
|
|
300
|
+
file: string; // 'remarque-tokens/<module>.css' for the package's own modules, else the --src-relative path
|
|
301
|
+
line: number; selector: string;
|
|
302
|
+
family: string | null; // first family of the rule's font-family (or --font-body when the rule sets none)
|
|
303
|
+
inferred: boolean; // true when the family was inferred as --font-body
|
|
304
|
+
tag: string; // OpenType feature tag, e.g. 'smcp', 'onum'
|
|
305
|
+
via: string; // the declaration that asked for it
|
|
306
|
+
status: 'missing' | 'conditional' | 'unverifiable'; // only 'missing' is also a failure
|
|
307
|
+
}>;
|
|
289
308
|
}
|
|
290
309
|
```
|
|
291
310
|
|
|
311
|
+
`--font-features <manifest.json>` (repeatable) adds your own faces to the check, in the shape of the package's `fonts/features.json` (`{ families: { "<family>": { figures: { style, spacing }, files: { "<file>": { features: [tags] } } } } }`). Faces missing from every manifest are reported `unverifiable` and never fail.
|
|
312
|
+
|
|
313
|
+
`warnings` never affects `passed` or the exit code in this release — only `failures` does. The warning set is expected to grow and to be promoted to failures in a later minor, so treat an unknown `id` as informational.
|
|
314
|
+
|
|
292
315
|
`contrast` and `gamut` list EVERY check performed (passing and failing);
|
|
293
316
|
only `srcScans` and `failures` are violation-only lists, since a source
|
|
294
317
|
scan that finds nothing has nothing to report per line.
|
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,101 @@ 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.29.0 — 2026-10-24
|
|
8
|
+
|
|
9
|
+
The "chrome" minor of the 2026-10 roadmap (#133, ratified 7–0 in `vote-1792819887868-esau595`): a new `remarque-tokens/chrome` module and four registry items. Additive: nothing existing changes for consumers who don't import it.
|
|
10
|
+
|
|
11
|
+
### Added — Chrome Module (#127; additive)
|
|
12
|
+
|
|
13
|
+
- **New subpath `remarque-tokens/chrome` (`chrome.css`):** the site-chrome and wayfinding pieces the spec required and never shipped CSS for, so every consumer hand-rolled them. The skip link had four implementations across the flagship, tsundoku, the starter and this demo, and one tsundoku pagination kept its "disabled" endpoints as focusable links. Not aggregated into `tokens.css`.
|
|
14
|
+
- **Skip link** (`.remarque-skip-link`, plus `.remarque-sr-only`): first focusable element, targets `<main id="main-content" tabindex="-1">`, hidden by clip-path until focused (never an off-screen offset, which breaks in RTL), then a filled fg-on-bg block on `--z-skip-link`, 44px tall, bordered under forced colors.
|
|
15
|
+
- **Breadcrumb** (`nav.remarque-breadcrumb > ol`): mono `--text-meta`, the current page `<span aria-current="page">`, separators generated with empty alt text so screen readers don't read them.
|
|
16
|
+
- **Pager** (`.remarque-pager`): prev/next with `rel`, a label line over the target's title, arrows that flip in RTL, an optional series row with a `<details>` part list. Plus numbered `.remarque-pagination`. An endpoint with nowhere to go is omitted, or plain text in pagination.
|
|
17
|
+
- **Tags** (`.remarque-tags`): plain mono links, `rel="tag"`, no border, fill or radius. An outlined chip is a documented deviation.
|
|
18
|
+
- The module sets no outer margins on the lists consumers position, because it's unlayered and would beat Tailwind utilities (Pitfall #7).
|
|
19
|
+
- **Four new registry items** (`skip-link`, `breadcrumb`, `pager`, `tags`), each with a REMARQUE.md "Chrome Module" markup contract that `scripts/test-registry.mjs` asserts: the skip-link target, a current page that isn't a link, no DOM separators, `rel` on pager and tag links, no disabled-looking links, and no border, fill or radius on tags.
|
|
20
|
+
- `print.css` hides the skip link, pager and pagination. AGENT_RULES gains a chrome checklist line. `remarque-audit`'s font-feature check and the budget/closure test cover the new module.
|
|
21
|
+
- Demo: the layout's Tailwind skip-link chain, which set `focus:outline-none`, is replaced by `.remarque-skip-link`; essays end with the pager; the dossier has a breadcrumb; `/components` gains a Chrome section. New `site/tests/chrome.spec.ts` covers the keyboard skip flow, separators and arrows out of the accessibility tree, pager sides with an omitted endpoint, tag styling, and the 44px pagination targets.
|
|
22
|
+
|
|
23
|
+
## 0.28.0 — 2026-10-24
|
|
24
|
+
|
|
25
|
+
The "truth" minor of the 2026-10 roadmap (#133): it makes the spec's claims true on the default stack. It was researched with Open Design and nexus-agents, ratified 7–0 (`vote-1792819887868-esau595`), and landed as one PR per issue, each with its own regression test proven red on 0.27.0. **Consumer-visible changes:**
|
|
26
|
+
- labels render in tracked capitals instead of synthesized small caps (#124);
|
|
27
|
+
- the broadsheet masthead box widens to `--content-standard`, with its title sized from that box (#121);
|
|
28
|
+
- the essay column moves onto the page axis (#119);
|
|
29
|
+
- long strings wrap (#122);
|
|
30
|
+
- RTL and non-Latin scripts get logical properties and `:lang()` guards (#123);
|
|
31
|
+
- `remarque-audit` gains a failing font-feature check (#124) and palette-coherence warnings (#125);
|
|
32
|
+
- `html` reserves the scrollbar gutter.
|
|
33
|
+
|
|
34
|
+
No token was removed or renamed, and no token value changed.
|
|
35
|
+
|
|
36
|
+
### Changed — Node engines
|
|
37
|
+
|
|
38
|
+
- **`engines.node` raised from `>=18` to `>=22`** (#120). Node 18 and 20 are end-of-life, and CI now tests 22 and 24. The CSS itself has no Node requirement; this covers the bins (`remarque-audit`, `remarque-drift`, `remarque-theme`).
|
|
39
|
+
|
|
40
|
+
### Changed — labels in tracked capitals; font-feature gate (#124; consumer-visible, ratified 7–0)
|
|
41
|
+
|
|
42
|
+
- **Labels set in real capitals, not synthesized small caps.** `.text-label` and every module label (broadsheet kickers and datelines, the TOC summary, the footnotes heading, `.remarque-field-label`) now use `text-transform: uppercase` + `--tracking-caps` instead of `font-variant-caps: all-small-caps`. None of the shipped fonts has `smcp` or `c2sc` (nor do their full upstream releases), so the browser faked small caps by shrinking capitals: a 14px label drew its caps at about 9.9px, under the 13px floor. Labels keep the 14px size. **Labels look different**: larger capitals in the same mono voice. If your label face has real `smcp` + `c2sc`, you can restore `font-variant-caps: all-small-caps; text-transform: none` yourself (REMARQUE.md "Small Caps"). Ratified 7–0 in `vote-1792819660668-a5kb6q3`. This replaces the #51 rule, rewritten in the same change in REMARQUE.md, AGENT_RULES.md, the registry description and the new-page skill.
|
|
43
|
+
- **Oldstyle figures are conditional.** `.remarque-prose` and the broadsheet entry numerals keep `oldstyle-nums`, now documented as "when the face has `onum`". Inter and Newsreader don't, so default figures are lining, and this always was the rendering. A face with `onum` (the flagship's Source Serif 4) still gets text figures.
|
|
44
|
+
- **New `remarque-audit` check: font features.** Every feature a stylesheet asks for (`font-variant-caps`, `font-variant-numeric`, `font-variant`, `font-feature-settings`), in the package's modules and in every `.css` under `--src`, is checked against the face the rule renders in, from the new shipped manifest `fonts/features.json` (OpenType GSUB+GPOS tags per face, generated with fontTools by `scripts/font-features.py`). A request the face can't render **fails**, unless the rule carries a `remarque-feature: conditional` comment. The check accounts for default figures (lining faces need no `lnum`; tabular faces no `tnum`). `--font-features <manifest>` adds a consumer's faces; faces in no manifest are reported, never failed. New JSON key `fontFeatures` (additive). The check landed red on the 0.27.0 tree first: 8 failures across 6 small-caps rules and 2 oldstyle rules.
|
|
45
|
+
- `scripts/test-font-features.mjs` covers manifest freshness (a sha256 per shipped woff2, so re-subsetting a font without regenerating the manifest fails), each status, and the CLI end to end, including a consumer manifest clearing a request.
|
|
46
|
+
- REMARQUE.md "Wrapping & Optical Defaults" gains a feature-support table (webstatus.dev, 2026-10-24): `text-wrap: pretty` and `hanging-punctuation` have no Firefox support, and `initial-letter` is Chromium plus prefixed Safari.
|
|
47
|
+
|
|
48
|
+
### Documentation — DTCG (#132)
|
|
49
|
+
|
|
50
|
+
- **The #99 DTCG trigger fired on 2025-10-28.** The Format, Color and Resolver modules were published as Final Community Group Reports. REMARQUE.md's "DTCG Conformance" now records this, retires the rule against fixing `tokens.json` toward unratified drafts, and does not word the gate as waiting for a W3C Recommendation (a CG cannot produce one).
|
|
51
|
+
- **All three divergences are documented**, in REMARQUE.md, the generated `tokens.json` `$extensions.remarque.dtcg` note, the `tokens.schema.json` description and the README: oklch() color strings, per-token light/dark nesting, and the new third one, CSS-string dimension/duration values (`clamp()` has no DTCG form).
|
|
52
|
+
- **A demand gate replaces the ratification gate.** A `tokens.dtcg.json` export is built only when a consumer asks for a DTCG 2025.10-shaped file, or Style Dictionary or Terrazzo documents full 2025.10 support including resolver output. Nothing is built now.
|
|
53
|
+
- Metadata only: no token value, name, CSS output or `tokens.d.ts` change. `test-types.mjs` §6 now requires at least three divergences, a dimension/duration aspect, and no `gatedOn` still saying "ratifying". Ships with 0.28.0.
|
|
54
|
+
|
|
55
|
+
### Fixed — RTL and non-Latin scripts (#123; LTR rendering unchanged)
|
|
56
|
+
|
|
57
|
+
- **essay.css: wide sidenotes float to `inline-start`.** A physical `float: left` paired with a logical negative `margin-inline-start` printed every note on top of the paragraph under `dir="rtl"` (measured at 1440px: note at x 400–560 over prose at 400–1008). It now lands in the right-hand gutter in RTL, and `float: left` stays as the fallback for engines without logical float values.
|
|
58
|
+
- **A logical-property sweep** of every physical left/right left in the modules. The blockquote bar, list indent, `dd` and table header/caption alignment, numeric cells (`text-align: end`), the details marker margin, the prose and lead drop caps (`float: inline-start`, logical padding), and the broadsheet numerals now mirror. In RTL the blockquote bar had stayed on the left, and lists and `dd` kept the browser's 40px start indent on the right. The closed disclosure marker flips under `:dir(rtl)`.
|
|
59
|
+
- **Script-aware guards.** Under `:lang(ar|fa|ur)` the tracking tokens are 0 (Remarque's `-0.02em` display tracking breaks cursive joining). Under `:lang(zh|ja|ko)` display tracking is 0 and heading leading is 1.35–1.4. The decorative italics set upright for `ar`, `fa`, `ur`, `he`, `zh`, `ja` and `ko`, and `em` uses weight instead. REMARQUE.md's Latin-only note now says what is and isn't guarded.
|
|
60
|
+
- New `site/tests/rtl.spec.ts` gates the RTL sidenotes and rail, the prose mirroring and the script guards, with an English control. 4 of its 5 tests fail on 0.27.0.
|
|
61
|
+
- `budgets.json` was raised. `tokens-core.css` and `broadsheet.css` passed their 10% headroom (brotli 3627 vs 3600; gzip 7301 vs 7300). The budget test caught it, as intended.
|
|
62
|
+
|
|
63
|
+
### Fixed — page axis and the masthead (#119, #121; consumer-visible)
|
|
64
|
+
|
|
65
|
+
- **broadsheet.css: the masthead title is sized from its nameplate, not the viewport (#121, a 0.27.0 regression).** The title grew at `9vw` inside a box capped at `--content-reading`. When that token went to 38rem in 0.27.0, the box stopped growing at about 640px of viewport while the title kept growing to 7.5rem, so a four-word title wrapped to four lines at 1280px. `.remarque-masthead` is now an inline-size container with a `--content-standard` (72rem) box, and the title rate is `9cqi`, with `9vw` kept as the fallback; the bounds are unchanged. At 1280px and up the title is about 98px, four- to seven-word titles hold to two lines, and the title stays above the `--text-display` lead title. A 38rem box would have put the masthead below the lead, which is why the nameplate widened instead (ratified 7–0, `vote-1792889632787-bm0nogp`). The lead and entry list stay at the reading measure. **If you set `--remarque-masthead-size` yourself, nothing changes for you.**
|
|
66
|
+
- **essay.css: the reading column sits on the page axis (#119).** At 80rem and up the grid was `1fr | reading | 10–12rem`, so the column was centered only when the left slack happened to equal the rail: 48px off-axis at 1440px on the demo. Both outer tracks are now `minmax(--space-11, 1fr)` and the rail is capped at `--space-12` plus its focus-ring padding. Sidenotes and the rail are unchanged.
|
|
67
|
+
- **tokens-core.css: `html { scrollbar-gutter: stable; }`.** On classic-scrollbar platforms a centered column no longer shifts by about 15px between short and long pages. Overlay scrollbars (macOS, phones) are unaffected.
|
|
68
|
+
- New gates in `site/tests/page-axis.spec.ts`: the essay column is centered like a plain page at 1280, 1440 and 1920px; sidenotes and the rail clear the prose; a four-word masthead title is at most two lines and larger than the lead title at 768, 1280 and 1920px.
|
|
69
|
+
|
|
70
|
+
### Fixed — long strings reflow (#122; consumer-visible)
|
|
71
|
+
|
|
72
|
+
- **`html { overflow-wrap: break-word; }` in `tokens-core.css`.** No layer set `overflow-wrap`, so one unbreakable string (a URL, a hash, a package path, long inline `code`) widened the whole page at phone width, failing WCAG 1.4.10. Measured on the demo at 320px with fixtures: 788px of page overflow in prose, 1291px across the broadsheet titles. It changes nothing for text that fits, and it inherits into consumer chrome too.
|
|
73
|
+
- **`overflow-wrap: anywhere` on flex labels** (TOC rail links and summary, `.remarque-button`, `.remarque-checkbox`, `.remarque-radio`). Their text is an anonymous flex item whose min-content is its longest word, which `break-word` can't shrink: a long TOC entry pushed the rail 528px wide.
|
|
74
|
+
- `<pre>` is unchanged on purpose: it keeps `white-space: pre` and scrolls inside its own box. REMARQUE.md "Wrapping & Optical Defaults" documents the difference.
|
|
75
|
+
- New `site/tests/reflow.spec.ts`: every demo page at 320 CSS px; long-string fixtures in prose, broadsheet titles, forms messages, buttons and labels, and the TOC rail; and the WCAG 1.4.12 text-spacing override set, with no clipped controls, TOC entries or sidenotes. The WCAG 2.2 criterion map now points at it.
|
|
76
|
+
|
|
77
|
+
### Accessibility — WCAG 2.2 AA (#126)
|
|
78
|
+
|
|
79
|
+
- **Spec moves from WCAG 2.1 AA to 2.2 AA.** REMARQUE.md's accessibility section and enforcement checklist now cite 2.2, with a new "WCAG 2.2 AA Criterion Map" (criterion, mechanism, enforcement) and a "Regulatory Context" paragraph (EN 301 549 V4.1.1, the EAA, Section 508). 4.1.1 Parsing is noted as removed in 2.2. No CSS output change.
|
|
80
|
+
- The 44px touch-target line now cites 2.5.8 (AA) as the criterion met, with 2.5.5 (AAA) as the exceeded one; before, it cited only 2.5.5.
|
|
81
|
+
- **2.4.11 note:** consumer sticky/fixed chrome needs `scroll-padding-top`.
|
|
82
|
+
- **Forms contract (3.3.7 / 3.3.8):** inputs that collect known personal data carry a valid `autocomplete` token and never block paste. The forms markup sample now shows `autocomplete="email"`. Mirrored in AGENT_RULES.md.
|
|
83
|
+
- **axe-core gate.** `site/tests/a11y.spec.ts` runs `@axe-core/playwright` (4.13.0) with the wcag2a/2aa/21a/21aa/22aa tags over every demo page in both themes, plus a forced-colors pass, and fails on serious/critical violations. The only exclusion is `color-contrast` in the forced-colors pass (justified in the spec).
|
|
84
|
+
- Demo fix found by axe: the inline link in the Notebook page's body text was distinguished by color alone (2.13:1 against the surrounding text in dark); it is now underlined (`link-in-text-block`).
|
|
85
|
+
|
|
86
|
+
### CI and release (not part of the package; #120, roadmap Step 0)
|
|
87
|
+
|
|
88
|
+
- **Every root gate now runs on pull requests.** The gates moved verbatim from `deploy.yml` into a reusable `.github/workflows/ci.yml` (Node 22 and 24). `deploy.yml` and `release.yml` both `need` it. Before this, pull requests ran only visual regression, and a `v*` tag ran only `audit.mjs`, so a tag on a commit with a stale `tokens.json` or a failing fixture suite would have published.
|
|
89
|
+
- **`release.yml`** pins npm to an exact version instead of `npm@latest` and creates a GitHub Release whose notes are this file's matching section. A tag with no `## X.Y.Z ` section fails before publishing.
|
|
90
|
+
- **`npm test`** chains the same gates for local runs. `scripts/test-pack.mjs` now strips the parent's `npm_*` environment from its child `npm`/`npx` calls; under `npm test` they inherited npm's local prefix and installed into this repo instead of the scratch consumer.
|
|
91
|
+
- **`.github/dependabot.yml`**: weekly version updates for the root and `site/` npm trees and for the SHA-pinned actions, with a 7-day cooldown. `@williamzujkowski/oklch-terminal-themes` stays a hand bump because `palette-golden.mjs` gates it.
|
|
92
|
+
- `main` is now branch-protected and requires the CI and visual-regression checks.
|
|
93
|
+
- **`scripts/test-budget.mjs`** (picked up by `npm test` and run in CI): gzip and brotli size budgets for every shipped CSS file plus the effective bare `tokens.css` import, against a committed, unshipped `budgets.json` (current size + 10%; `--update` rewrites it), and a module-closure check that every `var(--x)` in `prose`/`essay`/`broadsheet`/`forms`/`print` resolves to a core, palette or module-local custom property.
|
|
94
|
+
|
|
95
|
+
### Added — palette coherence warnings (#125)
|
|
96
|
+
|
|
97
|
+
- **`remarque-audit` now checks palette coherence**, as **warnings** for this minor (printed in the human output and in `--json` under a new additive `warnings` array; `passed` and the exit code are unchanged). Rules: monotonic text tiers (`fg` ≥ `fg-muted` ≥ `muted` contrast); accent vs `fg` ≥ 3:1 or ΔE2000 ≥ 15; accent vs `error` and vs `viz-1` ΔE ≥ 8; `error` vs `success` ΔE ≥ 5 under deuteranopia; adjacent `bg`/`surface`/`bg-subtle`/`code-bg` steps ΔE ≥ 3; minimum pairwise ΔE ≥ 5 across `--color-viz-1..6` under normal, protan, deutan and tritan simulation. Thresholds sit in one block, `THRESHOLDS` in `scripts/lib/palette-coherence.mjs`; rationale in REMARQUE.md "Palette Coherence". The warnings are slated to become failures in a later minor.
|
|
98
|
+
- **No new runtime dependency.** The audit ships to consumers who do not install culori, so the color math (OKLCH to sRGB, Machado CVD matrices, CIEDE2000) is implemented in the new shipped `scripts/lib/palette-coherence.mjs`; `scripts/test-coherence-math.mjs` cross-checks it against culori's `differenceCiede2000` and `filterDeficiency*` so the two cannot drift.
|
|
99
|
+
- **`remarque-theme` enforces the accent guards when generating.** If the default accent source collides with the derived error color (ΔE < 8) or with `fg`, it rotates to the nearest-hue other chromatic ANSI color that clears both, and it keeps `fg` at least as high-contrast as `fg-muted`. This fixes the Palette Deck's gruvbox (accent == error) and rose-pine (accent ≈ fg, fg-muted above fg) palettes on regeneration. `scripts/test-theme.mjs` now asserts the guards across the whole terminal-theme corpus.
|
|
100
|
+
- The default palette emits warnings today (viz-1 near accent, dark `surface` == `bg-subtle`, viz slots under CVD). That is the evidence base for #128; no default token values change here.
|
|
101
|
+
|
|
7
102
|
## 0.27.0 — 2026-10-23
|
|
8
103
|
|
|
9
104
|
Design review of the system and its demo site, run with Open Design's `design-review` methodology (gstack's 10-category / ~80-item rubric, calibrated against REMARQUE.md and AGENT_RULES.md): five independent reviewers, about 50 findings, AI-slop grade A throughout. The defects were in implementation, not identity. Two identity-level calls were put to a nexus consensus vote, and both passed 7–0. Closes #115 and #116.
|
package/README.md
CHANGED
|
@@ -54,7 +54,7 @@ Add `--json` to either `remarque-audit` or `remarque-drift` for a single structu
|
|
|
54
54
|
@import "remarque-tokens/theme.css";
|
|
55
55
|
```
|
|
56
56
|
|
|
57
|
-
**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, with a published JSON Schema at `remarque-tokens/tokens.schema.json` (also referenced by tokens.json's own `$schema` field) so tooling can validate it structurally instead of hand-parsing. tokens.json is conformant in spirit with the [Design Tokens Community Group](https://www.designtokens.org/) format (`$value`/`$type` on every token), with
|
|
57
|
+
**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, with a published JSON Schema at `remarque-tokens/tokens.schema.json` (also referenced by tokens.json's own `$schema` field) so tooling can validate it structurally instead of hand-parsing. tokens.json is conformant in spirit with the [Design Tokens Community Group](https://www.designtokens.org/) format (`$value`/`$type` on every token), with three deliberate divergences (oklch() color strings, per-token light/dark nesting, CSS-string dimension/duration values) — see REMARQUE.md's "DTCG Conformance" section. 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).
|
|
58
58
|
|
|
59
59
|
## For AI Agents
|
|
60
60
|
|
|
@@ -107,17 +107,38 @@ Output" shape changes) to pick up the current playbook.
|
|
|
107
107
|
| `tokens-core.css` | Core tier — type scale, spacing, widths, radius, motion, prose styling. Never overridden |
|
|
108
108
|
| `tokens-palette.css` | Palette tier — font slots, colors, accent, reading measure. The sanctioned personalization surface |
|
|
109
109
|
| `prose.css` | `.remarque-prose` long-form styling — own subpath so sites with their own prose system can skip it |
|
|
110
|
+
| `chrome.css` | Site chrome and wayfinding (`remarque-tokens/chrome`, 0.29): skip link + `.remarque-sr-only`, breadcrumb, pager/pagination, tags — see REMARQUE.md "Chrome Module" |
|
|
110
111
|
| `scripts/audit.mjs` | `npm run audit` — enforces the spec's contrast/gamut/font-floor/no-hardcoded-color checklist (`--json` for structured output) |
|
|
111
112
|
| `scripts/drift-check.mjs` | `npx remarque-drift` — token drift check for consumers (`--json` for structured output) |
|
|
112
113
|
| `tokens.json` + `tokens.d.ts` | Generated machine-readable token inventory + TypeScript types (`scripts/tokens-json.mjs`) |
|
|
113
114
|
| `tokens.schema.json` | Generated JSON Schema (draft 2020-12) for `tokens.json`, published alongside it |
|
|
114
|
-
| `registry.json` + `registry/` | Generated markup-contract registry index + per-item files for essay/broadsheet/forms/palette-deck (`scripts/build-registry.mjs`) — see REMARQUE.md "The Registry" |
|
|
115
|
+
| `registry.json` + `registry/` | Generated markup-contract registry index + per-item files for essay/broadsheet/forms/skip-link/breadcrumb/pager/tags/palette-deck (`scripts/build-registry.mjs`) — see REMARQUE.md "The Registry" |
|
|
115
116
|
| `registry-item.schema.json` + `registry.schema.json` | Generated JSON Schemas (draft 2020-12) for the per-item and index registry files |
|
|
116
117
|
| `skills/remarque/SKILL.md` + `skills/remarque-adopt/SKILL.md` | Generated packaging copies of the two Claude Code skills (`scripts/build-skills.mjs`) — canonical source is `.claude/skills/*/SKILL.md`; see "Installing the skills" above |
|
|
117
|
-
| `fonts.css` + `fonts/` | Self-hosted @font-face declarations and woff2 files (no CDN requests) |
|
|
118
|
+
| `fonts.css` + `fonts/` | Self-hosted @font-face declarations and woff2 files (no CDN requests); `fonts/features.json` lists each face's OpenType features for `remarque-audit`'s font-feature check |
|
|
118
119
|
| `tailwind.config.js` | Tailwind CSS **v3** configuration (v4 projects use an `@theme` block instead) |
|
|
119
120
|
| `package.json` | npm package manifest for `remarque-tokens` |
|
|
120
121
|
|
|
122
|
+
### Sizes
|
|
123
|
+
|
|
124
|
+
Gzip (level 9) / brotli (max) bytes per shipped stylesheet, enforced by `scripts/test-budget.mjs` against `budgets.json` (current size + 10%, repo-only, not in the package). Bare `remarque-tokens` imports core + palette + prose.
|
|
125
|
+
|
|
126
|
+
| File | gzip | brotli |
|
|
127
|
+
|------|-----:|-------:|
|
|
128
|
+
| `tokens.css` (effective: core + palette + prose) | 15,788 | 13,269 |
|
|
129
|
+
| `tokens-core.css` | 4,790 | 3,995 |
|
|
130
|
+
| `tokens-palette.css` | 7,036 | 5,848 |
|
|
131
|
+
| `prose.css` | 4,949 | 4,139 |
|
|
132
|
+
| `essay.css` | 7,914 | 6,680 |
|
|
133
|
+
| `broadsheet.css` | 7,463 | 6,241 |
|
|
134
|
+
| `forms.css` | 7,709 | 6,378 |
|
|
135
|
+
| `chrome.css` | 3,296 | 2,772 |
|
|
136
|
+
| `print.css` | 2,542 | 2,095 |
|
|
137
|
+
| `theme.css` | 1,744 | 1,452 |
|
|
138
|
+
| `fonts.css` | 612 | 484 |
|
|
139
|
+
|
|
140
|
+
Minimal import: `tokens-core.css` + `tokens-palette.css` alone (about 12 KB gzip) work without `prose.css`; the same test checks that every `var(--x)` in the optional modules resolves to a core or palette token.
|
|
141
|
+
|
|
121
142
|
## Three-Font System
|
|
122
143
|
|
|
123
144
|
| Role | Font | Usage |
|
|
@@ -191,6 +212,10 @@ deliberately stayed local.
|
|
|
191
212
|
| Ambient/decorative animation | Site-local only, never in system modules — and the `prefers-reduced-motion` guard is mandatory, not advisory. A future audit scan may flag unguarded infinite animations (as a heuristic check, not a soundness proof). |
|
|
192
213
|
| Landing-page entry counts | Permitted as meta-voice data in the Landing archetype **only when computed from real inventory at build time**. A hardcoded count is a violation — counts drift (see the upstream count-drift bug class this system just fixed in its own theme provider). |
|
|
193
214
|
|
|
215
|
+
## Development
|
|
216
|
+
|
|
217
|
+
`npm test` runs every gate CI runs: the token audit, the freshness checks for the generated files (`tokens.json`, the registry, the packaged skills), the palette golden gate, and every `scripts/test-*.mjs` fixture suite, including the consumer pack smoke test, which needs the network. `.github/workflows/ci.yml` runs the same gates on every pull request on Node 22 and 24, and both the Pages deploy and the npm release `need` it, so nothing deploys or publishes from a red commit.
|
|
218
|
+
|
|
194
219
|
## Named For
|
|
195
220
|
|
|
196
221
|
In fine art printmaking, a *remarque* is a small original drawing made by the artist in the margin of a proof print. Found only in limited editions, it is the mark that says: this was made by someone specific, with intention.
|