@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/css/numbers.css CHANGED
@@ -31,8 +31,8 @@
31
31
  mask: radial-gradient(farthest-side, transparent calc(100% - var(--_w) - 1px), currentColor calc(100% - var(--_w)));
32
32
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - var(--_w) - 1px), currentColor calc(100% - var(--_w)));
33
33
  }
34
- .ring__value { font: var(--type-stat); letter-spacing: var(--track-display); }
35
- .ring__label { font: var(--type-caption); color: var(--card-muted); }
34
+ .ring__value { font: var(--ring-value-font, var(--type-stat)); letter-spacing: var(--track-display); }
35
+ .ring__label { font: var(--ring-label-font, var(--type-caption)); color: var(--ring-label-ink, var(--card-muted)); }
36
36
  .card--3 .ring__label { color: inherit; opacity: 0.7; }
37
37
  .ring--sm { --_size: var(--avatar-xl); --_w: var(--sp-3); }
38
38
  .ring--sm .ring__value { font: 800 var(--fs-2xl)/1 var(--font-display); }
@@ -52,10 +52,10 @@
52
52
  --on-accent: var(--_bg);
53
53
  list-style: none;
54
54
  margin: 0;
55
- padding: var(--sp-2);
55
+ padding: var(--track-pad, var(--sp-2));
56
56
  display: flex;
57
57
  align-items: center;
58
- border-radius: var(--r-chip);
58
+ border-radius: var(--track-radius, var(--r-chip));
59
59
  background: var(--_bg);
60
60
  color: var(--_ink);
61
61
  }
@@ -96,9 +96,9 @@
96
96
  grid-template-areas: "label num" "foot num";
97
97
  align-items: end;
98
98
  gap: var(--sp-2) var(--sp-4);
99
- min-height: var(--tile-h);
99
+ min-height: var(--card-band-min-h, var(--tile-h));
100
100
  }
101
- .band__label { grid-area: label; align-self: start; font: var(--type-label); font-size: var(--fs-body); line-height: 1.2; }
101
+ .band__label { grid-area: label; align-self: start; font: var(--band-label-font, var(--type-label)); font-size: var(--band-label-font-size, var(--fs-body)); line-height: 1.2; }
102
102
  .band__num {
103
103
  grid-area: num;
104
104
  font: 800 var(--fs-giant) / 0.9 var(--font-display);
@@ -106,14 +106,14 @@
106
106
  font-variant-numeric: tabular-nums;
107
107
  }
108
108
  .band__num small { font-size: 0.5em; font-weight: 700; margin-right: 0.1em; } /* unit or % */
109
- .band__foot { grid-area: foot; font: var(--type-caption); color: var(--card-muted); }
109
+ .band__foot { grid-area: foot; font: var(--band-foot-font, var(--type-caption)); color: var(--band-foot-ink, var(--card-muted)); }
110
110
  .card--3 .band__foot { color: inherit; opacity: 0.7; }
111
111
  /* band stack: ONE card boundary; bands are frameless inside it, a hairline
112
112
  between each. Bands may still carry slot tints (card--2 / card--3). */
113
113
  .band-stack {
114
114
  display: grid;
115
- border: var(--border-w) solid var(--card-border);
116
- border-radius: var(--r-card);
115
+ border: var(--border-w) solid var(--band-stack-border, var(--card-border));
116
+ border-radius: var(--band-stack-radius, var(--r-card));
117
117
  overflow: hidden;
118
118
  }
119
119
  .band-stack > .card--band { border: 0; border-radius: 0; box-shadow: none; }
@@ -164,7 +164,7 @@
164
164
 
165
165
  /* ---- picker: horizontal snap picker, centre value big ----
166
166
  <div class="picker"><div class="picker__rail"><button class="picker__item">100</button>…</div><span class="picker__unit">ml</span></div> */
167
- .picker { display: grid; gap: var(--sp-1); justify-items: center; position: relative; }
167
+ .picker { display: grid; gap: var(--picker-gap, var(--sp-1)); justify-items: center; position: relative; }
168
168
  .picker__rail {
169
169
  width: 100%;
170
170
  display: grid;
@@ -172,7 +172,7 @@
172
172
  /* side padding = one third of the rail, so the first and last value can sit
173
173
  in the centre; the content box is then one third wide, and each column
174
174
  fills it (percent columns resolve against the content box) */
175
- padding-inline: calc(100% / 3);
175
+ padding-inline: var(--picker-rail-pad-x, calc(100% / 3));
176
176
  grid-auto-columns: 100%;
177
177
  overflow-x: auto;
178
178
  scroll-snap-type: x mandatory;
@@ -185,8 +185,8 @@
185
185
  border: 0;
186
186
  background: transparent;
187
187
  color: inherit;
188
- padding: var(--sp-2) 0;
189
- font: var(--type-stat);
188
+ padding: var(--picker-item-pad-y, var(--sp-2)) var(--picker-item-pad-x, 0);
189
+ font: var(--picker-item-font, var(--type-stat));
190
190
  letter-spacing: var(--track-display);
191
191
  font-variant-numeric: tabular-nums;
192
192
  opacity: 0.3;
@@ -205,7 +205,7 @@
205
205
  left: calc(100% / 3);
206
206
  }
207
207
  .picker::after { left: auto; right: calc(100% / 3); }
208
- .picker__unit { font: var(--type-caption); color: var(--card-muted); }
208
+ .picker__unit { font: var(--picker-unit-font, var(--type-caption)); color: var(--picker-unit-ink, var(--card-muted)); }
209
209
  .card--3 .picker__unit { color: inherit; opacity: 0.7; }
210
210
  /* the scrolled-to item lights up by position — no JS */
211
211
  @supports (animation-timeline: view(x)) {
@@ -221,30 +221,30 @@
221
221
  .badge {
222
222
  display: inline-grid;
223
223
  place-items: center;
224
- min-width: var(--badge);
225
- height: var(--badge);
226
- padding: 0 var(--sp-2);
227
- border-radius: var(--r-chip);
228
- background: var(--accent);
229
- color: var(--on-accent);
230
- font: var(--type-label);
224
+ min-width: var(--badge-min-w, var(--badge));
225
+ height: var(--badge-h, var(--badge));
226
+ padding: var(--badge-pad-y, 0) var(--badge-pad-x, var(--sp-2));
227
+ border-radius: var(--badge-radius, var(--r-chip));
228
+ background: var(--badge-bg, var(--accent));
229
+ color: var(--badge-ink, var(--on-accent));
230
+ font: var(--badge-font, var(--type-label));
231
231
  font-variant-numeric: tabular-nums;
232
232
  vertical-align: middle;
233
233
  }
234
- .badge--soft { background: var(--ink-tint); color: inherit; }
234
+ .badge--soft { background: var(--badge-soft-bg, var(--ink-tint)); color: inherit; }
235
235
 
236
236
  /* ---- bars: three or four bars with a count on top — the glance chart ----
237
237
  <div class="bars"><div class="bar" style="--v: 16"><span>+16</span></div>… --max on the parent */
238
- .bars { --max: 20; --_h: 5rem; display: flex; align-items: end; gap: var(--sp-2); height: calc(var(--_h) + var(--sp-8)); }
238
+ .bars { --max: 20; --_h: 5rem; display: flex; align-items: end; gap: var(--bars-gap, var(--sp-2)); height: calc(var(--_h) + var(--sp-8)); }
239
239
  .bar {
240
240
  flex: 1;
241
241
  min-width: 0;
242
242
  display: grid;
243
243
  align-content: end;
244
244
  justify-items: center;
245
- gap: var(--sp-1);
245
+ gap: var(--bar-gap, var(--sp-1));
246
246
  height: 100%;
247
- font: var(--type-caption);
247
+ font: var(--bar-font, var(--type-caption));
248
248
  font-weight: 700;
249
249
  }
250
250
  .bar::after {
package/css/people.css CHANGED
@@ -15,9 +15,9 @@
15
15
  border-radius: 50%;
16
16
  display: grid;
17
17
  place-items: center;
18
- background: var(--card-2-bg);
19
- color: var(--card-2-ink);
20
- font: var(--type-label);
18
+ background: var(--avatar-bg, var(--card-2-bg));
19
+ color: var(--avatar-ink, var(--card-2-ink));
20
+ font: var(--avatar-font, var(--type-label));
21
21
  font-size: calc(var(--_size) * 0.3);
22
22
  text-transform: uppercase;
23
23
  letter-spacing: 0.02em;
@@ -30,10 +30,10 @@
30
30
  .avatar--lg { --_size: var(--avatar-lg); }
31
31
  .avatar--xl { --_size: var(--avatar-xl); } /* sheet head icon ring */
32
32
  /* outline avatar: no fill, an edge — icons in a ring, "add" slots */
33
- .avatar--outline { background: transparent; color: inherit; border: var(--border-w) solid var(--outline); }
34
- .avatar--add { background: transparent; color: inherit; border: var(--border-w) dashed var(--outline); cursor: pointer; }
33
+ .avatar--outline { background: transparent; color: inherit; border: var(--border-w) solid var(--avatar-outline-border, var(--outline)); }
34
+ .avatar--add { background: transparent; color: inherit; border: var(--border-w) dashed var(--avatar-add-border, var(--outline)); cursor: pointer; }
35
35
  /* accent avatar: the "+7" tail, the selected person */
36
- .avatar--on { background: var(--accent); color: var(--on-accent); }
36
+ .avatar--on { background: var(--avatar-on-bg, var(--accent)); color: var(--avatar-on-ink, var(--on-accent)); }
37
37
  /* halo: faint concentric rings behind a hero avatar (decorative) */
38
38
  .avatar--halo::before {
39
39
  content: "";
@@ -55,7 +55,7 @@
55
55
  <div class="avatar-pick"><button class="avatar-pick__item"><span class="avatar avatar--lg avatar--add">+</span><span class="avatar-pick__name">Add</span><span class="avatar-pick__role">member</span></button>…</div> */
56
56
  .avatar-pick {
57
57
  display: flex;
58
- gap: var(--sp-4);
58
+ gap: var(--avatar-pick-gap, var(--sp-4));
59
59
  overflow-x: auto;
60
60
  scroll-snap-type: x proximity;
61
61
  scrollbar-width: none; /* starts at the card's padding edge, like every row */
@@ -64,16 +64,16 @@
64
64
  .avatar-pick__item {
65
65
  scroll-snap-align: start;
66
66
  flex: none;
67
- width: var(--avatar-lg);
67
+ width: var(--avatar-pick-item-w, var(--avatar-lg));
68
68
  display: grid;
69
69
  justify-items: center;
70
- gap: var(--sp-2);
70
+ gap: var(--avatar-pick-item-gap, var(--sp-2));
71
71
  border: 0;
72
72
  background: transparent;
73
73
  color: inherit;
74
74
  padding: 0;
75
75
  text-align: center;
76
76
  }
77
- .avatar-pick__name { font: var(--type-label); font-size: var(--fs-sm); }
78
- .avatar-pick__role { font: var(--type-caption); color: var(--card-muted); margin-top: calc(-1 * var(--sp-1)); }
77
+ .avatar-pick__name { font: var(--avatar-pick-name-font, var(--type-label)); font-size: var(--avatar-pick-name-font-size, var(--fs-sm)); }
78
+ .avatar-pick__role { font: var(--avatar-pick-role-font, var(--type-caption)); color: var(--avatar-pick-role-ink, var(--card-muted)); margin-top: calc(-1 * var(--sp-1)); }
79
79
  .card--3 .avatar-pick__role { color: inherit; opacity: 0.7; }
package/css/sheet.css CHANGED
@@ -28,7 +28,7 @@
28
28
  page. Many sheets stacked as the app's menu are the other system,
29
29
  .sheet-stack (stack.css): the same material, its own class and file.
30
30
 
31
- <article class="card sheet sheet--half" data-sheet-states="peek half 3q full">
31
+ <article class="card sheet sheet--half">
32
32
  A tap on the handle TOGGLES the sheet between its own state and peek
33
33
  (Lh 2026-09-16) — never a step-by-step climb; a drag snaps to any of
34
34
  the listed states, and the state it lands on becomes the one a tap
@@ -46,14 +46,12 @@
46
46
  ============================================================ */
47
47
 
48
48
  .sheet {
49
- --_handle: var(--sp-1);
50
49
  /* the strip a peeked sheet shows: the card's own top padding, the handle,
51
50
  the gap, one title row (--tap — the head rule below makes every head at
52
51
  least that tall) and the gap under it, so the cut lands exactly where
53
52
  the first control starts and nothing of it leaks through. Published
54
53
  (and registered in tokens.css) so a sheet whose head is taller can
55
54
  retune it: .my-sheet { --sheet-peek: … } */
56
- --sheet-peek: calc(var(--card-pad) + var(--_handle) + 2 * var(--card-gap) + var(--tap));
57
55
  --sheet-half: 0.5; /* a share of the sheet's own height */
58
56
  --sheet-3q: 0.25; /* three quarters showing: slid by a quarter */
59
57
  /* the sheet's own height, seen from inside it: the box it slides in is the
@@ -82,20 +80,22 @@
82
80
  overflow: clip;
83
81
  border-radius: var(--r-card) var(--r-card) 0 0;
84
82
  border-bottom: 0;
85
- box-shadow: var(--shadow-sheet);
83
+ box-shadow: var(--sheet-shadow, var(--shadow-sheet));
86
84
  }
87
85
  .sheet--full { --_y: 0%; --_cover: 0rem; }
88
86
  .sheet--half { --_y: calc(var(--sheet-half) * 100%); --_cover: calc(var(--sheet-half) * var(--_box)); }
89
87
  .sheet--3q { --_y: calc(var(--sheet-3q) * 100%); --_cover: calc(var(--sheet-3q) * var(--_box)); }
90
88
  .sheet--peek { --_y: calc(100% - var(--sheet-peek)); --_cover: calc(var(--_box) - var(--sheet-peek)); }
89
+ /* --sheet-peek is declared on the BOX the sheet slides in, not on the sheet: the words behind a peeked sheet
90
+ have to read it too (step.css keeps that much room under them), and a token only flows down. The sheet
91
+ inherits it. A sheet whose head is taller retunes it on the box. */
92
+ :is(.step, .sheet-stage) { --_handle: var(--sp-1); --sheet-peek: calc(var(--card-pad-rest) + var(--_handle) + 2 * var(--card-gap-rest) + var(--tap)); }
93
+
91
94
  /* ---- called sheets (Lh, 2026-09-20): a .step whose .base-content has buttons that each CALL a sheet ----
92
95
  .sheet--away = not on the screen: slid all the way out (translate, like every state — the material never
93
96
  changes), and hidden once it has left so its shadow does not lie on the step's bottom edge; write it
94
- with `inert`. A button names its sheet — <button aria-controls="when"> … <article id="when" class="card
95
- sheet sheet--away" inert data-sheet-states="peek full"> — and cardds.js does the rest: a tap slides that
96
- sheet up to full and sends any other one away; the handle takes it down to peek, never further, so the
97
- words and the other buttons are back in reach; the same button again raises it from peek to full.
98
- Nothing waits at peek before the first call. No bar on such a screen (actions.css).
97
+ with `inert` (the React Sheet does). WHO brings it onto the screen is the app's business — a button, a route:
98
+ cardds ties no component to another. Nothing waits at peek before the first call.
99
99
  WHAT IT IS FOR: the base offers WAYS IN — sign in · new phone · join — and each button calls a sheet
100
100
  that holds that way's WHOLE form, its submit on the sheet's foot, leading to the next page. The base
101
101
  carries no control. It is NOT for a form taken apart — one sheet per field, a "send" left on the base:
@@ -178,7 +178,7 @@
178
178
  opacity: 0.3;
179
179
  width: var(--tap-sm);
180
180
  height: var(--_handle);
181
- border-radius: var(--r-chip);
181
+ border-radius: var(--sheet-handle-radius, var(--r-chip));
182
182
  margin: 0 auto;
183
183
  padding: 0;
184
184
  touch-action: none;
@@ -210,8 +210,8 @@
210
210
  min-height: var(--tap);
211
211
  text-align: center;
212
212
  }
213
- .sheet__title { font: var(--type-h2); letter-spacing: var(--track-h2); margin: 0; }
214
- .sheet__sub { font: var(--type-caption); color: var(--card-muted); }
213
+ .sheet__title { font: var(--sheet-title-font, var(--type-h2)); letter-spacing: var(--track-h2); margin: 0; }
214
+ .sheet__sub { font: var(--sheet-sub-font, var(--type-caption)); color: var(--sheet-sub-ink, var(--card-muted)); }
215
215
 
216
216
  /* ============================================================
217
217
  .sheet-stage — the overlay stage: a page-height box the sheet
@@ -233,7 +233,7 @@
233
233
  margin-inline: auto;
234
234
  overflow: clip; /* not hidden: a clipped box is not a scroll container, so revealing a focused field never shifts the stage */
235
235
  container-type: size; /* the sheet's body reads this box's height as 100cqh (--_box above) */
236
- background: var(--surface);
236
+ background: var(--sheet-stage-bg, var(--surface));
237
237
  }
238
238
  /* on an app screen the stage is the page: it takes the screen's inset back (edge to
239
239
  edge, like a step) and, after a fixed .appbar, the room the screen reserved for
@@ -268,7 +268,7 @@
268
268
  position: absolute;
269
269
  inset: 0;
270
270
  isolation: isolate; /* the ring and the hint stack inside the map only — a sheet over the map covers them */
271
- color: var(--on-surface);
271
+ color: var(--map-ink, var(--on-surface));
272
272
  background:
273
273
  repeating-linear-gradient(75deg, transparent 0 5.5rem, var(--hairline) 5.5rem 6.25rem),
274
274
  repeating-linear-gradient(-18deg, transparent 0 8.75rem, var(--ink-tint) 8.75rem 9.25rem),
@@ -286,9 +286,9 @@
286
286
  height: var(--map-ring);
287
287
  translate: -50% -50%;
288
288
  border-radius: 50%;
289
- border: var(--border-w) solid var(--accent);
290
- background: color-mix(in srgb, var(--accent) 22%, transparent);
291
- box-shadow: var(--shadow-float);
289
+ border: var(--border-w) solid var(--map-ring-border, var(--accent));
290
+ background: var(--map-ring-bg, color-mix(in srgb, var(--accent) 22%, transparent));
291
+ box-shadow: var(--map-ring-shadow, var(--shadow-float));
292
292
  pointer-events: none;
293
293
  z-index: 1; /* above the engine's panes (Leaflet's tiles sit at 200, but inside their own stacking context) */
294
294
  }
@@ -297,10 +297,10 @@
297
297
  right: var(--sp-2);
298
298
  bottom: var(--sp-2);
299
299
  padding: var(--sp-0) var(--sp-2);
300
- border-radius: var(--r-chip);
301
- background: color-mix(in srgb, var(--surface) 80%, transparent);
302
- color: var(--on-surface-muted);
303
- font: var(--type-caption);
300
+ border-radius: var(--map-credit-radius, var(--r-chip));
301
+ background: var(--map-credit-bg, color-mix(in srgb, var(--surface) 80%, transparent));
302
+ color: var(--map-credit-ink, var(--on-surface-muted));
303
+ font: var(--map-credit-font, var(--type-caption));
304
304
  pointer-events: none;
305
305
  z-index: 1;
306
306
  }
@@ -311,12 +311,12 @@
311
311
  translate: -50% 0;
312
312
  max-width: calc(100% - 2 * var(--sp-4));
313
313
  padding: var(--sp-2) var(--sp-4);
314
- border-radius: var(--r-chip);
315
- background: var(--card-3-bg);
316
- color: var(--card-3-ink);
317
- font: var(--type-label);
314
+ border-radius: var(--map-hint-radius, var(--r-chip));
315
+ background: var(--map-hint-bg, var(--card-3-bg));
316
+ color: var(--map-hint-ink, var(--card-3-ink));
317
+ font: var(--map-hint-font, var(--type-label));
318
318
  text-align: center;
319
- box-shadow: var(--shadow-float);
319
+ box-shadow: var(--map-hint-shadow, var(--shadow-float));
320
320
  pointer-events: none;
321
321
  z-index: 1;
322
322
  }
@@ -330,7 +330,7 @@
330
330
  the sheet gives it up itself, as --_lift — the same token a raised sheet floats on. */
331
331
  .sheet-stage > .sheet { --_lift: var(--kb, 0rem); bottom: var(--_lift); }
332
332
  .sheet-stage > .sheet--raised { --_lift: calc(var(--tap-lg) + var(--kb, 0rem)); }
333
- .sheet--raised { --_lift: var(--tap-lg); bottom: var(--_lift); border-radius: var(--r-card); border-bottom: var(--border-w) solid var(--card-border); }
333
+ .sheet--raised { --_lift: var(--tap-lg); bottom: var(--_lift); border-radius: var(--sheet-raised-radius, var(--r-card)); border-bottom: var(--border-w) solid var(--card-border); }
334
334
  .sheet-stage__foot {
335
335
  position: absolute;
336
336
  inset-inline: 0;
@@ -339,8 +339,8 @@
339
339
  margin: 0;
340
340
  display: grid;
341
341
  place-items: center;
342
- font: var(--type-caption);
343
- color: var(--card-3-ink);
342
+ font: var(--sheet-stage-foot-font, var(--type-caption));
343
+ color: var(--sheet-stage-foot-ink, var(--card-3-ink));
344
344
  z-index: 2;
345
345
  }
346
346
 
package/css/step.css CHANGED
@@ -62,8 +62,9 @@
62
62
  :has(> .action-bar) .step { margin-bottom: calc(var(--bar-reserve) + var(--kb, 0rem)); }
63
63
  /* LAYERS (Lh, 2026-09-20): the base, then the sheet over it, then the top bar. A bar is the BASE's — the
64
64
  move of a page of words — so a step with a sheet has NO bar: the sheet finishes on its own .card__foot
65
- (sheet.css), and a form lives whole in ONE sheet, never item by item on the base. Should a bar be written
66
- beside a sheet anyway it stands down (actions.css + cardds.js) — a net for a mistake, not a layout. */
65
+ (sheet.css), and a form lives whole in ONE sheet, never item by item on the base. That is how cardds's
66
+ own screens are composed (the guide); the framework does not police it — a component never changes
67
+ because another one is there. */
67
68
 
68
69
  /* the reading block: a .base-content (base.css) — the same words-on-the-base
69
70
  block as anywhere else (it was .step__card, and a .card before 2026-09-16;
@@ -82,11 +83,10 @@
82
83
  color: var(--on-surface);
83
84
  }
84
85
  /* the reading block is the .base-content — or the .pages that holds several of them, a walk of words
85
- (card.css). --sheet-room: the strip a CALLED sheet keeps at peek (sheet.css, "called sheets"), published
86
- on the step by cardds.js while one is on the screen, so the buttons under it can scroll clear of it;
87
- nothing without one. */
86
+ (card.css). Behind a PEEKED sheet the words keep the strip's room under them, so whatever is down there
87
+ (the buttons that call the other sheets) scrolls clear of it — CSS alone: the box declares --sheet-peek. */
88
+ .step:has(> .sheet--peek) > :is(.base-content, .pages) { padding-bottom: var(--sheet-peek); }
88
89
  .step > :is(.base-content, .pages) {
89
- padding-bottom: var(--sheet-room, 0rem);
90
90
  flex: 0 1 auto;
91
91
  }
92
92
  .step > :is(.base-content, .pages) {
@@ -4,9 +4,12 @@
4
4
  Not part of the bundle: copy this file into the project as its own
5
5
  `theme.css` and load it AFTER cardds.css. It is the whole public
6
6
  surface of the system — the four size bases and the colour roles.
7
- Everything else in tokens.css is derived from these; a project never
8
- sets a derived token (--sp-4, --fs-h1, --r-card, --tap, --sheet-*…)
9
- and never a multiplier.
7
+ Widest first: a BASE moves a whole family; a role / root token one meaning
8
+ everywhere (--accent, --btn-h, --header-h…); a KNOB one component
9
+ (--btn-pad-x, --chip-bg… — docs/knobs.md lists them; also settable on any
10
+ element, for the components inside it). Never a step of the scale
11
+ (--sp-4, --fs-h1, --r-card), a multiplier, a private --_* or a published
12
+ value (--card-pad, --bar-reserve, --sheet-*).
10
13
 
11
14
  The values below are the defaults (the wireframe): as shipped, this
12
15
  file changes nothing (tests/tokens.spec.js holds it to that).
package/css/tokens.css CHANGED
@@ -49,6 +49,8 @@
49
49
  --chip-h: calc(var(--tap-base) * 19 / 24); /* 38 chip height */
50
50
  --bar-h: calc(var(--tap-base) * 4 / 3); /* 64 float bar, day cell, deck actions */
51
51
  --header-h: calc(var(--tap-base) * 5 / 4); /* 60 top bar — .topbar and .appbar alike */
52
+ --card-pad-rest: var(--sp-5); /* 20 a card's padding before any variant — .card publishes it as --card-pad; the sheet's peek strip is built from it where no card is in scope */
53
+ --card-gap-rest: var(--sp-4); /* 16 …and its gap */
52
54
  --screen-pad: var(--sp-4); /* 16 the screen's inset — .sheet-stack cancels it */
53
55
  --map-ring: calc(var(--tap-base) * 10 / 3); /* the rough-area ring on a map (sheet.css .map__ring) — a neighbourhood, not a house */
54
56
  --fab: calc(var(--tap-base) * 3 / 2); /* 72 square floating action */