@usableapp/cardds 0.2.2 → 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.
Files changed (103) hide show
  1. package/README.md +35 -107
  2. package/cardds.js +6 -449
  3. package/css/actions.css +41 -35
  4. package/css/base.css +9 -9
  5. package/css/card.css +26 -25
  6. package/css/choice.css +50 -50
  7. package/css/forms.css +18 -18
  8. package/css/journey.css +16 -16
  9. package/css/layover.css +45 -45
  10. package/css/lists.css +43 -43
  11. package/css/media.css +33 -33
  12. package/css/numbers.css +25 -25
  13. package/css/people.css +11 -11
  14. package/css/sheet.css +29 -29
  15. package/css/step.css +6 -6
  16. package/css/theme.template.css +6 -3
  17. package/css/tokens.css +2 -0
  18. package/dist/actions/Btn.d.ts +109 -108
  19. package/dist/actions/BtnRow.d.ts +2 -2
  20. package/dist/actions/Chip.d.ts +102 -101
  21. package/dist/actions/Dot.d.ts +2 -2
  22. package/dist/actions/Dropdown.d.ts +36 -19
  23. package/dist/actions/Dropdown.js +41 -11
  24. package/dist/actions/Fab.d.ts +2 -2
  25. package/dist/actions/IconBtn.d.ts +298 -10
  26. package/dist/actions/IconBtn.js +6 -8
  27. package/dist/actions/Link.d.ts +105 -104
  28. package/dist/actions/Segment.d.ts +3 -3
  29. package/dist/cardds.css +354 -345
  30. package/dist/cards/Card.d.ts +99 -98
  31. package/dist/cards/CardFoot.d.ts +2 -2
  32. package/dist/cards/CardHead.d.ts +2 -2
  33. package/dist/cards/CardParts.d.ts +7 -7
  34. package/dist/cards/Placeholder.d.ts +2 -2
  35. package/dist/cards/Stat.d.ts +7 -5
  36. package/dist/cards/Stat.js +2 -2
  37. package/dist/choice/Calendar.d.ts +17 -6
  38. package/dist/choice/Calendar.js +9 -3
  39. package/dist/choice/Check.d.ts +3 -3
  40. package/dist/choice/DayStrip.d.ts +3 -3
  41. package/dist/choice/Mood.d.ts +2 -2
  42. package/dist/choice/Slider.d.ts +3 -3
  43. package/dist/choice/Slider.js +12 -8
  44. package/dist/forms/AddRow.d.ts +2 -2
  45. package/dist/forms/Composer.d.ts +2 -2
  46. package/dist/forms/Field.d.ts +2 -2
  47. package/dist/forms/FileBtn.d.ts +2 -2
  48. package/dist/forms/Pin.d.ts +10 -7
  49. package/dist/forms/Pin.js +47 -18
  50. package/dist/journey/NoteRow.d.ts +2 -2
  51. package/dist/journey/Route.d.ts +2 -2
  52. package/dist/journey/TileBadge.d.ts +2 -2
  53. package/dist/layover/Banner.d.ts +2 -2
  54. package/dist/layover/Callout.d.ts +2 -2
  55. package/dist/layover/Deck.d.ts +3 -3
  56. package/dist/lists/Bubble.d.ts +3 -3
  57. package/dist/lists/Kv.d.ts +5 -5
  58. package/dist/lists/Legend.d.ts +3 -3
  59. package/dist/lists/Row.d.ts +5 -4
  60. package/dist/lists/Timeline.d.ts +3 -3
  61. package/dist/media/MapArea.d.ts +2 -2
  62. package/dist/media/Mosaic.d.ts +3 -3
  63. package/dist/media/Postcard.d.ts +9 -5
  64. package/dist/media/Postcard.js +8 -3
  65. package/dist/media/Quote.d.ts +2 -2
  66. package/dist/media/Tile.d.ts +5 -4
  67. package/dist/numbers/Badge.d.ts +2 -2
  68. package/dist/numbers/Band.d.ts +3 -3
  69. package/dist/numbers/Bars.d.ts +3 -3
  70. package/dist/numbers/DotGrid.d.ts +2 -2
  71. package/dist/numbers/Picker.d.ts +20 -8
  72. package/dist/numbers/Picker.js +51 -13
  73. package/dist/numbers/Ring.d.ts +2 -2
  74. package/dist/numbers/Track.d.ts +3 -3
  75. package/dist/people/Avatar.d.ts +100 -99
  76. package/dist/people/AvatarPick.d.ts +3 -3
  77. package/dist/scaffold/ActionBar.d.ts +3 -3
  78. package/dist/scaffold/AppBar.d.ts +2 -2
  79. package/dist/scaffold/BaseContent.d.ts +7 -7
  80. package/dist/scaffold/BaseContent.js +4 -4
  81. package/dist/scaffold/Centre.d.ts +3 -3
  82. package/dist/scaffold/EmptyState.d.ts +2 -2
  83. package/dist/scaffold/FilterRow.d.ts +2 -2
  84. package/dist/scaffold/FloatBar.d.ts +105 -104
  85. package/dist/scaffold/PagerAt.d.ts +2 -2
  86. package/dist/scaffold/Screen.d.ts +100 -99
  87. package/dist/scaffold/TopBar.d.ts +2 -2
  88. package/dist/sheets/CardBack.d.ts +2 -2
  89. package/dist/sheets/Drawer.d.ts +19 -8
  90. package/dist/sheets/Drawer.js +29 -5
  91. package/dist/sheets/Sheet.d.ts +29 -16
  92. package/dist/sheets/Sheet.js +157 -11
  93. package/dist/sheets/SheetBody.d.ts +2 -2
  94. package/dist/sheets/SheetHead.d.ts +2 -2
  95. package/dist/sheets/SheetStack.d.ts +15 -3
  96. package/dist/sheets/SheetStack.js +74 -2
  97. package/dist/sheets/SheetStage.d.ts +2 -2
  98. package/dist/sheets/Step.d.ts +2 -2
  99. package/dist/type/Icon.d.ts +22 -7
  100. package/dist/type/Icon.js +27 -4
  101. package/dist/type/Text.d.ts +7 -1
  102. package/dist/type/Text.js +2 -2
  103. package/package.json +3 -2
package/README.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # cardds
2
2
 
3
+ > **cardds is a UI framework, not one project's design system.** A project takes it and puts its own values and
4
+ > content into the UI — tokens (`theme.css`), props, slots, composition — without touching cardds. When a project
5
+ > cannot get what it needs from outside, that is a gap in the framework: report it; it is closed here as a
6
+ > GENERAL extension point, never as that project's special case. A consumer project never edits or releases cardds.
7
+ >
3
8
  > **For:** people and AI alike — this is the reference, the one place a rule of the system is written.
4
9
  > The other docs only point here: `CLAUDE.md` (AI working IN this repo — decisions and gotchas),
5
10
  > `docs/guides/building-with-cardds.md` (AI composing screens in React; shipped to Claude Design),
@@ -9,8 +14,7 @@ Card-first mobile design system, **React-first**: `src/` is the component
9
14
  library — one thin component per pattern, emitting exactly the markup the CSS
10
15
  documents. The CSS (`css/*.css`)
11
16
  stays the only truth: a component never styles anything, it only picks classes
12
- from props. The CSS also works alone, with no build, for a host that wants
13
- class names rather than components. The demo is the gallery (`npm run dev`):
17
+ from props. The demo is the gallery (`npm run dev`):
14
18
  every component's stories, live, searchable.
15
19
 
16
20
  Repo: **https://github.com/everysundays/cardds** (private — this is the
@@ -53,19 +57,6 @@ story live in a 375×812 phone cell, grouped by `src/<group>/`, searchable; swit
53
57
  it comes up over the phone cell and publishes `--kb` there — to SEE what a keyboard leaves of the screen; it
54
58
  types nothing), text size, and a slider per size base. Nothing is hand-listed: add a preview file or a story and it shows.
55
59
 
56
- **CSS only** (no React, no build):
57
-
58
- ```html
59
- <link rel="stylesheet" href="cardds.css">
60
- <script src="cardds.js" defer></script> <!-- optional: the behaviours above -->
61
- <html data-palette="clay"> <!-- omit for b&w wireframe -->
62
- ```
63
-
64
- Everything renders without `cardds.js`: a dropdown still opens (a native
65
- popover) but won't update its label, a stack still displays but won't open, a
66
- sheet renders every state but only moves when a class changes, a pin is six
67
- plain inputs.
68
-
69
60
  `tests/fixtures/*.html` are the pages the geometry tests measure — not a demo. Nothing here is verified by eye.
70
61
 
71
62
  ### In another project
@@ -83,38 +74,6 @@ import '@usableapp/cardds/dist/cardds.css'; // the CSS, fonts resolve from the
83
74
  ```
84
75
 
85
76
 
86
- **CSS only:** there's no build and no dependencies, so installing is cloning once, then
87
- copying the static files into your project — never edit the clone, never
88
- fork the CSS:
89
-
90
- ```bash
91
- # once, wherever you keep it (~/Sites/cardds is the convention on this machine)
92
- git clone git@github.com:everysundays/cardds.git ~/Sites/cardds
93
- # to update it later
94
- git -C ~/Sites/cardds pull
95
-
96
- # then vendor the static files into the consuming project
97
- cp -R ~/Sites/cardds/css ~/Sites/cardds/fonts ~/Sites/cardds/cardds.css \
98
- ~/Sites/cardds/cardds.js ~/Sites/cardds/icons.svg \
99
- ./assets/
100
- ```
101
-
102
- `cardds.css` is just the import bundle for `css/*.css`, so keep the `css/`
103
- folder next to it, and `fonts/` beside that (`css/fonts.css` reaches the faces
104
- as `../fonts/`). `icons.svg` is referenced by path from your markup
105
- (`<use href="icons.svg#bell">`), so put it where those references resolve.
106
- Then follow the rules below — the short version is: tune your own `theme.css`
107
- (a copy of `css/theme.template.css`, see "A project's theme") and nothing else, and never write a raw hex or px in a component.
108
-
109
- The repo is private, so cloning needs an account with access (`everysundays`
110
- on GitHub) — set that up as an SSH host alias if you already use a different
111
- account for `git@github.com` day to day, the way this machine's `~/.ssh/config`
112
- does it for other `everysundays` repos.
113
-
114
- **Record what you copied.** A vendored copy with no record of the commit it came
115
- from can't be told apart from a fork: write the commit hash (and a sha256 per
116
- file) beside the copy, so a hand edit or a stale copy can be caught.
117
-
118
77
  Working with Claude in another project? The `/cardds` skill
119
78
  (`~/.claude/skills/cardds/`) carries the install and the contract, and points
120
79
  back here. It is deliberately thin — **this repo stays the source of truth**,
@@ -126,10 +85,10 @@ if the contract itself changes.
126
85
  `src/<group>/<Name>.tsx`, one export per class family; sub-parts are their own
127
86
  components (`CardHead`, `KvRow`, `TrackStep`, `SheetBody`). A component
128
87
  chooses classes from props (`tone`, `state`, `primary`, `sm`…) and lays the
129
- contract's children in order — nothing else. Behaviour lives in `cardds.js`
130
- (delegated, class toggles) and a component only surfaces it: `Pin` listens
131
- for `cardds:pin` and calls `onChange(code, complete)`; `Sheet` sets the state
132
- class, `cardds.js` moves it. Never fix a look in a wrapper: fix the CSS, the
88
+ contract's children in order. A component that has STATE is controlled like an input
89
+ (`state` / `open` / `value` / `flipped` / `selected` + its `on…`, or a `default…` twin), keeps its own behaviour
90
+ inside itself and only ever asks through that callback; it never knows another component — the app wires them
91
+ (2026-09-21; `cardds.js` is down to `--kb`). Never fix a look in a wrapper: fix the CSS, the
133
92
  wrapper follows. **Claude Design** builds with these components through
134
93
  `/design-sync` (`.design-sync/`: the sync config, the authored preview
135
94
  stories, the conventions the design agent reads) — a new component needs a
@@ -191,7 +150,7 @@ whose markup has rules, because the sheet's box is the step itself:
191
150
  <!-- acts: the words + a sheet -->
192
151
  <section class="step">
193
152
  <section class="base-content">…the words…</section>
194
- <article class="card sheet sheet--half" data-sheet-states="peek half 3q full">
153
+ <article class="card sheet sheet--half">
195
154
  <button class="sheet__handle" type="button" aria-label="ปรับความสูง"></button>
196
155
  <div class="card__head"><h2 class="t-h2">…</h2><span class="chip">…</span></div>
197
156
  <div class="sheet__body">
@@ -244,12 +203,14 @@ whose markup has rules, because the sheet's box is the step itself:
244
203
  screen with a sheet finishes ON the sheet: a `.card__foot`, the sheet's last child — ONE row, the page's
245
204
  conclusion. The foot stands on the screen's bottom edge at half, 3q and full alike (a layer as tall as
246
205
  the sheet, slid up by the share the sheet slid down — `sheet.css`), and is gone at peek. Nothing inside
247
- the sheet's body commits on its own (a `Composer` there takes no `send`). A bar written beside a sheet anyway
248
- stands down — no pointer (`actions.css`), `inert` (`cardds.js`): a net for a mistake, not a layout.
206
+ the sheet's body commits on its own (a `Composer` there takes no `send`). This is how cardds's own screens are
207
+ composed — guidance; the framework does not enforce it: a component never changes because another one is there.
249
208
  - **Never write a sheet's height, and never a `.sheet-stage` inside a step.**
250
209
  State is a class (`sheet--peek` / `--half` / `--full`); the sheet is always
251
- the step's full height and only slides. `carddsSheetSet(sheet, state)` is
252
- the one way to change it from script, so listeners hear `cardds:sheet`.
210
+ the step's full height and only slides. In React the APP owns it: `<Sheet state={s}
211
+ onStateChange={setS}>` (controlled) or `<Sheet defaultState="half">` (it keeps its own). The sheet's own behaviour —
212
+ the handle's tap and drag, the focus raise, the climb when the keyboard moves the cut — lives in the component and
213
+ only ever ASKS through `onStateChange(state, reason)`; nothing outside the sheet is touched.
253
214
 
254
215
  ## Centred card markup
255
216
 
@@ -297,56 +258,19 @@ between at 40% down the screen (see *Anatomy*, "Where the centre is"):
297
258
  - **BaseContent that moves** (Lh 2026-09-20) — two ways, never both on one screen:
298
259
  - *Pages of words:* `.step > .pages > .base-content` (one `aria-current="step"`, the rest `inert`) — every page
299
260
  one height, the round pager turns them (`slideTo()`), the words slide like a page. No sheet there.
300
- - *Called sheets:* the base offers WAYS IN — sign in · new phone · join — as buttons (`.cta-pack`), each naming a
301
- sheet: `<button aria-controls="signin">` … `<article id="signin" class="card sheet sheet--away" inert
302
- data-sheet-states="peek full">`. Each sheet holds that way's WHOLE form and its own submit on its foot, leading
303
- to the next page; the base carries no control and the screen no bar. `.sheet--away` = not on the screen (slid
304
- out, hidden once gone). Nothing waits at peek. A tap raises its sheet to full and sends any other away; the
305
- handle takes it down to peek and never further — the words and the other buttons are back in reach (the step
306
- publishes `--sheet-room`, the peek strip, so they scroll clear of it); the same button raises it from peek to full.
261
+ - *Sheets the app calls:* the base offers WAYS IN — sign in · new phone · join — as buttons (`.cta-pack`); each
262
+ way has a sheet that holds its WHOLE form and its own submit on its foot, starting `.sheet--away` (not on the
263
+ screen: slid out, hidden once gone, `inert`). **The wiring is the app's, not cardds's**: a `useState` of which
264
+ sheet is on and where, each button sets it, each `<Sheet state onStateChange>` reads it — one at a time, the same
265
+ button raises a peeked sheet, the handle stops at peek (`states="peek full"`). Story `Step · Calls` is those few
266
+ lines; it could as well be a route, which is what makes the phone's back button close a sheet. CSS's only part:
267
+ behind a peeked sheet the words keep `--sheet-peek` of room (the box declares the token), so the buttons under
268
+ it scroll clear.
307
269
  **Never a form taken apart** — one sheet per field, a "send" left on the base: a form lives whole in ONE sheet.
308
270
  Fixture `tests/fixtures/calls.html`, tests `tests/calls.spec.js`, stories `Step · Walks` / `Step · Calls`.
309
271
  - **A pager turns pages of words, never a screen with a sheet** (Lh 2026-09-20). A
310
272
  sheet means this screen has work that cannot be walked past: no ← →, no bar at all — the sheet's
311
- own foot finishes it. Should a pager meet a sheet anyway it stands
312
- down while the sheet is on the screen, a peeking one included: dimmed, no pointer
313
- (`actions.css`), `inert` (`cardds.js`).
314
-
315
- ## Files
316
-
317
- | file | what | touch it? |
318
- |---|---|---|
319
- | `css/fonts.css` + `fonts/` | the two `@font-face`s: PK Nonthaburi (body, `--font-ui`), FC Pride (display, `--font-display`); the font files and their licences | when swapping a face |
320
- | `css/tokens.css` | spacing, radius, type levels, motion (`--motion-sheet`), the human centre (`--screen-centre`), grayscale role defaults; registers the two sheet tokens (`--sheet-peek`, `--sheet-half`) so script can read them resolved | rarely |
321
- | `css/theme.template.css` | **a project's theme** — the four size bases + the colour roles, at their defaults; NOT in the bundle: copied into the project as its `theme.css`, loaded after `cardds.css` | copy it, don't edit it |
322
- | `css/palette.css` | **color settings — palettes as role-token overrides** | yes, this one |
323
- | `css/base.css` | reset, surface, typography classes, `.base-content` | rarely |
324
- | `css/card.css` | `.card` + its skeleton (`.card__head` / content / `.card__foot`), `.card-list`, `.card--row`, `.icon-row`, stats, `.card--centre` (one card at the human centre of a fill screen) and `.screen__centre` (a small group there) | when adding variants |
325
- | `css/stack.css` | **sheet stack** — `.sheet-stack`: the menu, sheets stacked (heads peek, up to 5; `--tap` tap-to-open, the back button dissolves in; `--closed` nothing open, heads at the bottom, the base above (`.sheet-stack__base`); `--display` the title is the peek, `--fanned` wider peeks); always edge to edge; a stacked sheet is a `.card` | rarely |
326
- | `css/sheet.css` | **sheet single** — `.sheet`: a card as bottom sheet, full height always, a state is how far it slid: `--peek` / `--half` / `--full` (translate only); handle · head · `.sheet__body` (the head pinned, the body scrolls); `.sheet-stage` (overlay stage: map sheet, a `__hero` — one thing centred in the band a half sheet leaves open, `--dim`, `--raised`, ask drawer) | when adding states |
327
- | `css/step.css` | `.step` — one screen, one task: `.base-content` (reads) + optional `.sheet` (acts), the bar's room, the keyboard's room | rarely |
328
- | `css/forms.css` | `.field` (outlined input, label = placeholder), `.add-row` | when adding controls |
329
- | `css/journey.css` | `.route`, `.tile-badge`, `.note-row` — trip/status primitives | when adding variants |
330
- | `css/actions.css` | topbar, chips, buttons (`.btn--xl`), `.dropdown` (the standard select: pill + `.menu` popover), `.action-bar` (+ `--pager` for previous/next, two round icon buttons, never labels; `--tiers` for a control row above the buttons), `.fab` | when adding actions |
331
- | `css/numbers.css` | `.ring` gauge, `.track` steps, `.card--band` + `.band-stack`, `.dotgrid`, `.picker`, `.badge`, `.bars` | big numbers |
332
- | `css/people.css` | `.avatar` (sm/lg/xl, outline, add, on, halo), `.avatar-stack`, `.avatar-pick` | people |
333
- | `css/choice.css` | `.check`, `.toggle`, `.chip-grid` + `.chip--pick` (+ `--sign`), `.day-strip`, `.calendar`, `.mood`, `.pin`, `.composer`, `.slider` | choice controls |
334
- | `css/lists.css` | `.row` / `.rows` (frameless rows in a card), `.kv`, `.kv-grid`, `.thread` + `.bubble` (chat: theirs left, mine right, no tail), `.timeline`, `.legend`, `.link` | lists inside cards |
335
- | `css/media.css` | `.card--cover`, `.quote`, `.tile-grid` + `.tile`, `.card--fold`, `.mosaic`, `.wave` | media & display |
336
- | `css/layover.css` | `.modal` (the ask: `__lift` + `__drawer`, closes on any drawer button → `cardds:modal`), `.menu` (popover), `.banner` (details), `.float-bar`, `.callout`, `.deck` | cards over content |
337
- | `icons.svg` | Lucide sprite (ISC), 56 minimal stroke icons | add symbols as needed |
338
- | `src/` → `dist/` | the React library: `src/<group>/<Name>.tsx`, one thin component per pattern, JSDoc = the rule; built by `npm run build` (tsc) into `dist/` with `.d.ts`; `src/type/icons.ts` is generated from `icons.svg` | when adding a component |
339
- | `gallery/` | the gallery site: `npm run dev` → `/` every story, `/:Name` one component (`gallery/src/Gallery.tsx` globs `.design-sync/previews/`) | the demo |
340
- | `tests/fixtures/` | the HTML pages (`index`, `sheet`, `stack`, `elements`) the geometry tests measure — ex `demo/`, not a demo | when a geometry test needs a new case |
341
- | `docs/handoff/` | the Claude Design handoff spec (the Commons Time Bank app built from it was dropped 2026-09-16) | reference |
342
- | `scripts/` | `build-icons.mjs` (icons.svg → `src/type/icons.ts`), `flatten-css.mjs` (`cardds.css` + imports → `dist/cardds.css`) | rarely |
343
- | `docs/guides/` | `building-with-cardds.md` — the anatomy, the step, the two sheet systems and the vocabulary in React terms; shipped to Claude Design as its guidelines | when the contract changes |
344
- | `cardds.js` | the behaviours (delegated, class/property toggles only — everything renders without it): dropdown value sync, `.sheet-stack--tap` open/close (tolerates one wrapper per sheet; close reads the tapped sheet), `.pin` auto-advance / Backspace / paste + `cardds:pin`, the sheet handle (tap / drag-snap / Enter / Space), the focus and keyboard raises (`--kb`), `cardds:sheet` | rarely |
345
-
346
- ## Anatomy — base, menus, content, and the card skeleton
347
-
348
- Every screen is the same four things, and every card the same three:
349
-
273
+ own foot finishes it. (Guidance — not enforced.)
350
274
  - A screen is **base, top menu, bottom menu, content**. The base is the
351
275
  surface; the menus are the chrome above and below (`.topbar` / `.appbar`,
352
276
  `.action-bar` / `.float-bar`); content is everything between.
@@ -543,7 +467,7 @@ A project retunes cardds from ONE file of its own, and nothing else. Copy
543
467
  <html data-palette="own"> <!-- colours of your own = coloured mode; any value no stock palette uses -->
544
468
  ```
545
469
 
546
- That file is the whole public surface:
470
+ That file is where a project's look lives. Bases and roles:
547
471
 
548
472
  | what | tokens | moves |
549
473
  |---|---|---|
@@ -557,10 +481,14 @@ That file is the whole public surface:
557
481
 
558
482
  Rules:
559
483
 
560
- - **A base, never a multiplier.** Every size token is `calc(base × multiplier)`
561
- in `tokens.css`; the multipliers are the system's proportions. A project
562
- never sets a derived token (`--sp-4`, `--fs-h1`, `--r-card`, `--tap`…), a
563
- private one (`--_*`), or a published one (`--card-pad`, `--bar-reserve`, `--sheet-*`).
484
+ - **Three levels, widest first — use the widest that says what you mean.**
485
+ 1. a **base** moves a whole family (`--sp-base`, `--fs-base`, `--r-base`, `--tap-base`, the five `--color-*`): the system keeps its proportions.
486
+ 2. a **role / root token** moves one meaning everywhere (`--accent`, `--card-1-bg`, `--btn-h`, `--chip-h`, `--header-h`, `--screen-w`, `--motion-sheet`…).
487
+ 3. a **knob** moves ONE component (`--btn-pad-x`, `--chip-bg`, `--icon-btn-size`, `--appbar-pad-x`…) — on `:root` for everywhere, or on any element for
488
+ the components inside it. A knob is declared nowhere; its default is the fallback in the rule. The full list is generated from the CSS:
489
+ [`docs/knobs.md`](docs/knobs.md) (`npm run knobs`). Missing the knob you need? That is a gap in cardds — report it; it is added as a knob, never as your special case.
490
+ - **Never a multiplier, never a step of the scale** (`--sp-4`, `--fs-h1`, `--r-card` — retune the base, or the component's knob), never a private
491
+ (`--_*`) or a published value (`--card-pad`, `--bar-reserve`, `--sheet-*`: other rules do arithmetic with them).
564
492
  - **On `:root` only.** The derived tokens are computed where they are declared
565
493
  (`:root`), so a base set on a subtree does not reach them.
566
494
  - **After `cardds.css`.** A stock palette's block and a project's `:root` weigh