@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/base.css CHANGED
@@ -43,10 +43,10 @@ img, svg { display: block; max-width: 100%; }
43
43
  button { font: inherit; cursor: pointer; }
44
44
 
45
45
  /* icon from icons.svg sprite: <svg class="icon"><use href="icons.svg#bell"/></svg> */
46
- .icon { width: var(--icon); height: var(--icon); flex: none; }
47
- .icon--sm { width: var(--icon-sm); height: var(--icon-sm); }
48
- .icon--xs { width: var(--icon-xs); height: var(--icon-xs); } /* inside captions, chips, links */
49
- .icon--lg { width: var(--icon-lg); height: var(--icon-lg); } /* empty states */
46
+ .icon { width: var(--icon-size, var(--icon)); height: var(--icon-size, var(--icon)); flex: none; }
47
+ .icon--sm { width: var(--icon-sm-size, var(--icon-sm)); height: var(--icon-sm-size, var(--icon-sm)); }
48
+ .icon--xs { width: var(--icon-xs-size, var(--icon-xs)); height: var(--icon-xs-size, var(--icon-xs)); } /* inside captions, chips, links */
49
+ .icon--lg { width: var(--icon-lg-size, var(--icon-lg)); height: var(--icon-lg-size, var(--icon-lg)); } /* empty states */
50
50
 
51
51
  /* mobile screen column — the standard horizontal inset, and nothing vertical.
52
52
  Top and bottom are zero on purpose: vertical room is only ever a RESERVE for
@@ -113,9 +113,9 @@ button { font: inherit; cursor: pointer; }
113
113
  In a .step it is the reading block and step.css adds the flex/scroll rule ---- */
114
114
  .base-content {
115
115
  display: grid;
116
- gap: var(--sp-3);
116
+ gap: var(--base-content-gap, var(--sp-3));
117
117
  align-content: start; /* a tall column never stretches the rows — the words hug the top */
118
- padding-block: var(--sp-4);
118
+ padding-block: var(--base-content-pad-y, var(--sp-4));
119
119
  }
120
120
  .base-content > .t-body { color: var(--on-surface-muted); max-width: 34ch; }
121
121
  .base-content .cta-pack {
@@ -131,9 +131,9 @@ button { font: inherit; cursor: pointer; }
131
131
  display: grid;
132
132
  justify-items: center;
133
133
  text-align: center;
134
- gap: var(--sp-2);
135
- padding: var(--sp-12) var(--sp-6);
136
- color: var(--on-surface); /* full ink, icon and words alike: muted read as "disabled" at the middle of an empty screen (Lh 2026-09-16) — muted is for meta, not a sentence */
134
+ gap: var(--empty-state-gap, var(--sp-2));
135
+ padding: var(--empty-state-pad-y, var(--sp-12)) var(--empty-state-pad-x, var(--sp-6));
136
+ color: var(--empty-state-ink, var(--on-surface)); /* full ink, icon and words alike: muted read as "disabled" at the middle of an empty screen (Lh 2026-09-16) — muted is for meta, not a sentence */
137
137
  }
138
138
  .empty-state__action { margin-top: var(--sp-2); }
139
139
  /* inside a card (a section's "nothing yet"): the card's ink */
package/css/card.css CHANGED
@@ -6,12 +6,12 @@
6
6
  .card {
7
7
  --card-bg: var(--card-1-bg); /* the slot, readable by children (avatar rings, fold) */
8
8
  --card-ink: var(--card-1-ink);
9
- --card-pad: var(--sp-5); /* published so .bleed can cancel it exactly */
10
- --card-gap: var(--sp-4); /* published so a sheet's peek strip (sheet.css) is exact */
9
+ --card-pad: var(--card-pad-rest); /* published so .bleed can cancel it exactly */
10
+ --card-gap: var(--card-gap-rest); /* published so a sheet's peek strip (sheet.css) is exact */
11
11
  background: var(--card-bg);
12
12
  color: var(--card-ink);
13
13
  border: var(--border-w) solid var(--card-border);
14
- border-radius: var(--r-card);
14
+ border-radius: var(--card-radius, var(--r-card));
15
15
  padding: var(--card-pad);
16
16
  display: grid;
17
17
  gap: var(--card-gap);
@@ -42,8 +42,8 @@
42
42
  flex-wrap: wrap; /* the caption / overline take a line of their own — no wrapper div */
43
43
  align-items: center;
44
44
  justify-content: space-between;
45
- column-gap: var(--sp-3);
46
- row-gap: var(--sp-0);
45
+ column-gap: var(--card-head-col-gap, var(--sp-3));
46
+ row-gap: var(--card-head-row-gap, var(--sp-0));
47
47
  }
48
48
  /* flat head markup (Lh 2026-09-16 — no <p>, no wrapper, only padding and gap tokens):
49
49
  <div class="card__head"><span class="t-overline t-muted">…</span><h2 class="t-h2">…</h2><span class="t-caption t-muted">…</span><button class="icon-btn icon-btn--sm">…</button></div>
@@ -54,8 +54,8 @@
54
54
  .card__head > .t-overline { order: -1; }
55
55
  .card__head--top { align-items: flex-start; }
56
56
 
57
- .card__media { border-radius: var(--r-media); overflow: hidden; position: relative; } /* relative: corner badges */
58
- .card__end { text-align: right; display: grid; gap: var(--sp-0); justify-items: end; } /* trailing value + caption */
57
+ .card__media { border-radius: var(--card-media-radius, var(--r-media)); overflow: hidden; position: relative; } /* relative: corner badges */
58
+ .card__end { text-align: right; display: grid; gap: var(--card-end-gap, var(--sp-0)); justify-items: end; } /* trailing value + caption */
59
59
  .card__media > img { width: 100%; height: auto; object-fit: cover; }
60
60
 
61
61
  /* ---- the card skeleton: head · content · foot ----
@@ -119,7 +119,7 @@
119
119
  /* foot: the card's action buttons on one line. One button takes the width,
120
120
  up to four share it in even parts — so the gaps read even too — and from
121
121
  three on they drop their side padding so the labels keep the room. */
122
- .card__foot { display: flex; gap: var(--sp-2); align-items: center; }
122
+ .card__foot { display: flex; gap: var(--card-foot-gap, var(--sp-2)); align-items: center; }
123
123
  .card__foot > .btn { flex: 1 1 0; min-width: 0; }
124
124
  .card__foot:has(> :nth-child(3)) > .btn { padding-inline: var(--sp-2); }
125
125
 
@@ -253,48 +253,49 @@
253
253
  .screen__centre > .pager__at { justify-self: center; }
254
254
 
255
255
  /* compact card inside a card (nested note, promo) */
256
- .card--sm { padding: var(--sp-4); --card-gap: var(--sp-2); border-radius: var(--r-card); }
256
+ .card--sm { padding: var(--card-sm-pad, var(--sp-4)); --card-gap: var(--sp-2); border-radius: var(--card-sm-radius, var(--r-card)); }
257
257
 
258
258
  /* the sheet stack (.sheet-stack) — sheets stacked, heads peeking — lives in
259
259
  stack.css; a stacked sheet is a plain .card, the material */
260
260
 
261
261
  /* trailing icon cluster in a card header */
262
- .icon-row { display: flex; align-items: center; gap: var(--sp-4); opacity: 0.85; }
262
+ .icon-row { display: flex; align-items: center; gap: var(--icon-row-gap, var(--sp-4)); opacity: 0.85; }
263
263
 
264
264
  /* ---- card list: rows, each row its own boundary ---- */
265
- .card-list { display: grid; gap: var(--sp-3); }
265
+ .card-list { display: grid; gap: var(--card-list-gap, var(--sp-3)); }
266
266
 
267
267
  .card--row {
268
- border-radius: var(--r-card);
269
- padding: var(--sp-4);
268
+ border-radius: var(--card-row-radius, var(--r-card));
269
+ padding: var(--card-row-pad, var(--sp-4));
270
270
  display: flex;
271
271
  align-items: center;
272
- gap: var(--sp-3);
272
+ gap: var(--card-row-gap, var(--sp-3));
273
273
  }
274
274
  .card--row .card__body { flex: 1; display: grid; gap: var(--sp-0); }
275
275
 
276
276
  /* leading thumb/icon in a row */
277
277
  .card__thumb {
278
- width: var(--tap-sm); height: var(--tap-sm);
278
+ width: var(--card-thumb-size, var(--tap-sm)); height: var(--card-thumb-size, var(--tap-sm));
279
279
  flex: none;
280
- border-radius: var(--r-control);
280
+ border-radius: var(--card-thumb-radius, var(--r-control));
281
281
  border: var(--border-w) solid currentColor;
282
282
  display: grid;
283
283
  place-items: center;
284
- font: var(--type-label);
284
+ font: var(--card-thumb-font, var(--type-label));
285
285
  opacity: 0.85;
286
286
  }
287
287
 
288
288
  /* ---- inline stat block (revenue-style) ---- */
289
- .stat { display: grid; gap: var(--sp-1); }
290
- .stat__row { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); }
289
+ .stat { display: grid; gap: var(--stat-gap, var(--sp-1)); }
290
+ .stat--centre { text-align: center; justify-items: center; } /* the one number of a sheet or a stage, under a centred avatar */
291
+ .stat__row { display: flex; align-items: center; justify-content: space-between; gap: var(--stat-row-gap, var(--sp-3)); }
291
292
 
292
293
  .delta {
293
- font: var(--type-caption);
294
+ font: var(--delta-font, var(--type-caption));
294
295
  font-weight: 700;
295
- padding: var(--sp-1) var(--sp-2);
296
- border-radius: var(--r-chip);
297
- background: var(--card-3-bg);
298
- color: var(--card-3-ink);
296
+ padding: var(--delta-pad-y, var(--sp-1)) var(--delta-pad-x, var(--sp-2));
297
+ border-radius: var(--delta-radius, var(--r-chip));
298
+ background: var(--delta-bg, var(--card-3-bg));
299
+ color: var(--delta-ink, var(--card-3-ink));
299
300
  }
300
- .delta--neg { background: var(--neg); color: var(--card-3-ink); } /* light ink on the signal color in every slot */
301
+ .delta--neg { background: var(--delta-neg-bg, var(--neg)); color: var(--delta-neg-ink, var(--card-3-ink)); } /* light ink on the signal color in every slot */
package/css/choice.css CHANGED
@@ -12,13 +12,13 @@
12
12
  <input type="checkbox" class="check" aria-label="Done"> */
13
13
  .check {
14
14
  appearance: none;
15
- width: var(--tap);
16
- height: var(--tap);
15
+ width: var(--check-size, var(--tap));
16
+ height: var(--check-size, var(--tap));
17
17
  flex: none;
18
18
  margin: 0;
19
19
  border-radius: 50%;
20
- border: var(--border-w) solid var(--outline);
21
- background: var(--action-bg);
20
+ border: var(--border-w) solid var(--check-border, var(--outline));
21
+ background: var(--check-bg, var(--action-bg));
22
22
  display: grid;
23
23
  place-items: center;
24
24
  cursor: pointer;
@@ -35,7 +35,7 @@
35
35
  .check:checked { background: var(--accent); border-color: transparent; }
36
36
  .check:checked::after { opacity: 1; }
37
37
  .check:focus-visible { outline: var(--focus); outline-offset: var(--sp-1); }
38
- .check--sm { width: var(--tap-sm); height: var(--tap-sm); }
38
+ .check--sm { width: var(--check-sm-size, var(--tap-sm)); height: var(--check-sm-size, var(--tap-sm)); }
39
39
 
40
40
  /* ---- toggle: big switch ----
41
41
  <input type="checkbox" role="switch" class="toggle" aria-label="Private"> */
@@ -48,9 +48,9 @@
48
48
  height: var(--_h);
49
49
  flex: none;
50
50
  margin: 0;
51
- border-radius: var(--r-chip);
52
- border: var(--border-w) solid var(--outline);
53
- background: var(--action-bg);
51
+ border-radius: var(--toggle-radius, var(--r-chip));
52
+ border: var(--border-w) solid var(--toggle-border, var(--outline));
53
+ background: var(--toggle-bg, var(--action-bg));
54
54
  position: relative;
55
55
  cursor: pointer;
56
56
  transition: background 0.2s ease;
@@ -79,7 +79,7 @@
79
79
  .chip-grid {
80
80
  display: grid;
81
81
  grid-template-columns: repeat(auto-fill, minmax(min(5.5rem, 100%), 1fr));
82
- gap: var(--sp-2);
82
+ gap: var(--chip-grid-gap, var(--sp-2));
83
83
  }
84
84
  /* .chip hugs its text as a loose grid child (justify-self: start); inside a
85
85
  chip grid the whole point is equal, full-width pick targets, so stretch.
@@ -106,7 +106,7 @@
106
106
 
107
107
  /* ---- day strip: a week, one day selected ----
108
108
  <div class="day-strip" role="tablist"><button class="day" role="tab" aria-selected="true"><span class="day__name">Thu</span><span class="day__num">16</span></button>…</div> */
109
- .day-strip { display: grid; grid-template-columns: repeat(7, 1fr); gap: var(--sp-1); }
109
+ .day-strip { display: grid; grid-template-columns: repeat(7, 1fr); gap: var(--day-strip-gap, var(--sp-1)); }
110
110
  .day {
111
111
  display: grid;
112
112
  /* three rows, always: name · number · dot. The dot's row is reserved even on
@@ -116,33 +116,33 @@
116
116
  grid-template-rows: auto auto var(--dot-xs);
117
117
  align-content: center; /* the group sits centred in the cell, not spread out */
118
118
  justify-items: center;
119
- gap: var(--sp-0);
119
+ gap: var(--day-gap, var(--sp-0));
120
120
  min-width: 0;
121
- min-height: var(--bar-h);
122
- padding-block: var(--sp-3); /* equal air top and bottom, so the selected pill
121
+ min-height: var(--day-min-h, var(--bar-h));
122
+ padding-block: var(--day-pad-y, var(--sp-3)); /* equal air top and bottom, so the selected pill
123
123
  is the same shape on every day */
124
124
  padding-inline: 0;
125
125
  border: 0;
126
- border-radius: var(--r-chip);
126
+ border-radius: var(--day-radius, var(--r-chip));
127
127
  background: transparent;
128
128
  color: inherit;
129
129
  opacity: 0.6;
130
130
  }
131
- .day__name { font: var(--type-caption); }
131
+ .day__name { font: var(--day-name-font, var(--type-caption)); }
132
132
  .day__num { font: 700 var(--fs-lg)/1.1 var(--font-display); font-variant-numeric: tabular-nums; }
133
- .day[aria-selected="true"] { background: var(--accent); color: var(--on-accent); opacity: 1; }
134
- .day__dot { grid-row: 3; align-self: center; width: var(--dot-xs); height: var(--dot-xs); border-radius: 50%; background: currentColor; }
133
+ .day[aria-selected="true"] { background: var(--day-selected-bg, var(--accent)); color: var(--day-selected-ink, var(--on-accent)); opacity: 1; }
134
+ .day__dot { grid-row: 3; align-self: center; width: var(--day-dot-size, var(--dot-xs)); height: var(--day-dot-size, var(--dot-xs)); border-radius: 50%; background: currentColor; }
135
135
 
136
136
  /* ---- calendar: month grid, 44px cells, one accent day, optional marks ----
137
137
  <div class="calendar"><div class="calendar__head">…</div><div class="calendar__grid"><span class="calendar__wd">Mo</span>×7 <button class="calendar__day" style="--start: 3">1</button>…</div></div> */
138
- .calendar { display: grid; gap: var(--sp-3); }
139
- .calendar__head { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); }
140
- .calendar__grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: var(--sp-1); justify-items: center; }
141
- .calendar__wd { font: var(--type-overline); letter-spacing: var(--track-overline); text-transform: uppercase; color: var(--card-muted); padding-block: var(--sp-2); }
138
+ .calendar { display: grid; gap: var(--calendar-gap, var(--sp-3)); }
139
+ .calendar__head { display: flex; align-items: center; justify-content: space-between; gap: var(--calendar-head-gap, var(--sp-2)); }
140
+ .calendar__grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: var(--calendar-grid-gap, var(--sp-1)); justify-items: center; }
141
+ .calendar__wd { font: var(--calendar-wd-font, var(--type-overline)); letter-spacing: var(--track-overline); text-transform: uppercase; color: var(--calendar-wd-ink, var(--card-muted)); padding-block: var(--calendar-wd-pad-y, var(--sp-2)); }
142
142
  .card--3 .calendar__wd { color: inherit; opacity: 0.7; }
143
143
  .calendar__day {
144
144
  width: 100%;
145
- max-width: var(--tap);
145
+ max-width: var(--calendar-day-max-w, var(--tap));
146
146
  aspect-ratio: 1;
147
147
  display: grid;
148
148
  place-items: center;
@@ -154,9 +154,9 @@
154
154
  font-variant-numeric: tabular-nums;
155
155
  grid-column-start: var(--start, auto); /* --start on the 1st: weekday column 1–7 */
156
156
  }
157
- .calendar__day--mark { background: var(--accent-soft); }
158
- .calendar__day--mark2 { background: var(--accent-mid); color: var(--on-accent); }
159
- .calendar__day[aria-selected="true"] { background: var(--accent); color: var(--on-accent); font-weight: 700; }
157
+ .calendar__day--mark { background: var(--calendar-day-mark-bg, var(--accent-soft)); }
158
+ .calendar__day--mark2 { background: var(--calendar-day-mark2-bg, var(--accent-mid)); color: var(--calendar-day-mark2-ink, var(--on-accent)); }
159
+ .calendar__day[aria-selected="true"] { background: var(--calendar-day-selected-bg, var(--accent)); color: var(--calendar-day-selected-ink, var(--on-accent)); font-weight: 700; }
160
160
  .calendar__day:disabled { opacity: 0.3; }
161
161
 
162
162
  /* ---- mood: five dots in a pill, the picked one grows ----
@@ -164,19 +164,19 @@
164
164
  .mood {
165
165
  margin: 0;
166
166
  min-inline-size: 0; /* fieldset UA default is min-content — it must shrink with the card */
167
- padding: var(--sp-1);
168
- border: var(--border-w) solid var(--outline);
169
- border-radius: var(--r-chip);
170
- background: var(--action-bg);
171
- color: var(--action-ink);
167
+ padding: var(--mood-pad, var(--sp-1));
168
+ border: var(--border-w) solid var(--mood-border, var(--outline));
169
+ border-radius: var(--mood-radius, var(--r-chip));
170
+ background: var(--mood-bg, var(--action-bg));
171
+ color: var(--mood-ink, var(--action-ink));
172
172
  display: flex;
173
173
  justify-content: space-between;
174
174
  }
175
- .mood__opt { flex: 1 1 0; max-width: var(--tap); min-width: 0; height: var(--tap); display: grid; place-items: center; position: relative; cursor: pointer; }
175
+ .mood__opt { flex: 1 1 0; max-width: var(--mood-opt-max-w, var(--tap)); min-width: 0; height: var(--mood-opt-h, var(--tap)); display: grid; place-items: center; position: relative; cursor: pointer; }
176
176
  .mood__opt > input { appearance: none; position: absolute; inset: 0; margin: 0; opacity: 0; cursor: pointer; }
177
177
  .mood__dot {
178
- width: var(--icon-xs);
179
- height: var(--icon-xs);
178
+ width: var(--mood-dot-size, var(--icon-xs));
179
+ height: var(--mood-dot-size, var(--icon-xs));
180
180
  border-radius: 50%;
181
181
  background: var(--_mood, currentColor);
182
182
  transition: scale 0.2s ease, box-shadow 0.2s ease;
@@ -191,18 +191,18 @@
191
191
 
192
192
  /* ---- pin: big code entry, one digit per pill ----
193
193
  <div class="pin"><input class="pin__cell" inputmode="numeric" maxlength="1" placeholder=" ">×4</div> */
194
- .pin { display: flex; gap: var(--sp-3); }
194
+ .pin { display: flex; gap: var(--pin-gap, var(--sp-3)); }
195
195
  .pin__cell {
196
196
  flex: 1;
197
197
  min-width: 0;
198
- max-width: var(--fab);
198
+ max-width: var(--pin-cell-max-w, var(--fab));
199
199
  aspect-ratio: 2 / 3;
200
- border: var(--border-w) solid var(--outline);
201
- border-radius: var(--r-chip);
202
- background: var(--action-bg);
203
- color: var(--action-ink);
200
+ border: var(--border-w) solid var(--pin-cell-border, var(--outline));
201
+ border-radius: var(--pin-cell-radius, var(--r-chip));
202
+ background: var(--pin-cell-bg, var(--action-bg));
203
+ color: var(--pin-cell-ink, var(--action-ink));
204
204
  text-align: center;
205
- font: var(--type-stat);
205
+ font: var(--pin-cell-font, var(--type-stat));
206
206
  font-variant-numeric: tabular-nums;
207
207
  caret-color: currentColor;
208
208
  }
@@ -212,7 +212,7 @@
212
212
  /* ---- composer: big text area with a bottom bar (icon · hint · send) ----
213
213
  <div class="composer"><textarea class="composer__input" placeholder="What do you need?"></textarea>
214
214
  <div class="composer__bar"><button class="icon-btn">…</button><span class="composer__hint">Your idea is born</span><button class="icon-btn icon-btn--invert">↑</button></div></div> */
215
- .composer { display: grid; gap: var(--sp-3); }
215
+ .composer { display: grid; gap: var(--composer-gap, var(--sp-3)); }
216
216
  .composer__input {
217
217
  width: 100%;
218
218
  min-height: 11rem;
@@ -226,8 +226,8 @@
226
226
  outline: none;
227
227
  }
228
228
  .composer__input::placeholder { color: inherit; opacity: 0.4; }
229
- .composer__bar { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); }
230
- .composer__hint { font: var(--type-caption); color: var(--card-muted); }
229
+ .composer__bar { display: flex; align-items: center; justify-content: space-between; gap: var(--composer-bar-gap, var(--sp-3)); }
230
+ .composer__hint { font: var(--composer-hint-font, var(--type-caption)); color: var(--composer-hint-ink, var(--card-muted)); }
231
231
  .card--3 .composer__hint { color: inherit; opacity: 0.7; }
232
232
 
233
233
  /* ---- slider: one value along a track, a thumb-size knob ----
@@ -236,7 +236,7 @@
236
236
  slider does, the input's aria-label is enough. The track is a hairline rail;
237
237
  the knob is a full --tap, and the whole range is --tap tall, so the thumb has
238
238
  a real target anywhere along it. The value is the input's own. */
239
- .slider { display: grid; gap: var(--sp-1); flex: 1; min-width: 0; position: relative; } /* relative: the glyph rides the knob */
239
+ .slider { display: grid; gap: var(--slider-gap, var(--sp-1)); flex: 1; min-width: 0; position: relative; } /* relative: the glyph rides the knob */
240
240
  /* ---- the sample glyph: one letter IN the knob, on-accent, at the type size
241
241
  the slider sets — so a text-size slider shows the size before anything is
242
242
  read (Lh, 2026-09-12). cardds.js publishes the knob's place on the .slider
@@ -247,8 +247,8 @@
247
247
  position: absolute;
248
248
  bottom: 0;
249
249
  left: calc(var(--tap) / 2 + (100% - var(--tap)) * var(--slider-at, 0));
250
- width: var(--tap);
251
- height: var(--tap);
250
+ width: var(--slider-glyph-size, var(--tap));
251
+ height: var(--slider-glyph-size, var(--tap));
252
252
  /* the eye centres the INK, not the line box: a letter that stands on the
253
253
  baseline (ก) has no descender, while the face's box keeps 0.30em under it
254
254
  (fonts.css) — so the ink lands low when the box is centred; lifted 0.15em
@@ -256,15 +256,15 @@
256
256
  translate: -50% -0.15em;
257
257
  display: grid;
258
258
  place-items: center;
259
- font: var(--type-h2);
260
- color: var(--on-accent);
259
+ font: var(--slider-glyph-font, var(--type-h2));
260
+ color: var(--slider-glyph-ink, var(--on-accent));
261
261
  pointer-events: none;
262
262
  }
263
- .slider__label { font: var(--type-label); }
263
+ .slider__label { font: var(--slider-label-font, var(--type-label)); }
264
264
  .slider__range {
265
265
  appearance: none;
266
266
  width: 100%;
267
- height: var(--tap);
267
+ height: var(--slider-range-h, var(--tap));
268
268
  margin: 0;
269
269
  background: transparent;
270
270
  cursor: pointer;
package/css/forms.css CHANGED
@@ -7,13 +7,13 @@
7
7
  .field {
8
8
  display: flex;
9
9
  align-items: center;
10
- gap: var(--sp-2);
11
- border: var(--border-w) solid var(--action-border);
12
- border-radius: var(--r-control);
13
- background: var(--action-bg);
14
- color: var(--action-ink);
15
- padding-inline: var(--sp-4);
16
- min-height: var(--tap);
10
+ gap: var(--field-gap, var(--sp-2));
11
+ border: var(--border-w) solid var(--field-border, var(--action-border));
12
+ border-radius: var(--field-radius, var(--r-control));
13
+ background: var(--field-bg, var(--action-bg));
14
+ color: var(--field-ink, var(--action-ink));
15
+ padding-inline: var(--field-pad-x, var(--sp-4));
16
+ min-height: var(--field-min-h, var(--tap));
17
17
  min-width: 0;
18
18
  }
19
19
 
@@ -30,7 +30,7 @@
30
30
  .field input::placeholder { color: inherit; opacity: 0.55; }
31
31
 
32
32
  /* field with its action inside: date pick, send, go — the button sits flush right */
33
- .field--action { padding-right: var(--sp-1); min-height: var(--tap-lg); }
33
+ .field--action { padding-right: var(--sp-1); min-height: var(--field-action-min-h, var(--tap-lg)); }
34
34
  .field--action > .icon-btn { margin-left: auto; }
35
35
 
36
36
  /* colored palettes drop the visible outline elsewhere — fields keep one */
@@ -40,25 +40,25 @@
40
40
  .add-row {
41
41
  display: inline-flex;
42
42
  align-items: center;
43
- gap: var(--sp-2);
43
+ gap: var(--add-row-gap, var(--sp-2));
44
44
  border: 0;
45
45
  background: none;
46
46
  color: inherit;
47
- font: var(--type-label);
48
- font-size: var(--fs-body);
49
- padding: var(--sp-2) 0;
50
- min-height: var(--tap-sm);
47
+ font: var(--add-row-font, var(--type-label));
48
+ font-size: var(--add-row-font-size, var(--fs-body));
49
+ padding: var(--add-row-pad-y, var(--sp-2)) var(--add-row-pad-x, 0);
50
+ min-height: var(--add-row-min-h, var(--tap-sm));
51
51
  }
52
52
  .add-row__plus {
53
- width: var(--icon);
54
- height: var(--icon);
53
+ width: var(--add-row-plus-size, var(--icon));
54
+ height: var(--add-row-plus-size, var(--icon));
55
55
  flex: none;
56
56
  border-radius: 50%;
57
- background: var(--accent);
58
- color: var(--on-accent);
57
+ background: var(--add-row-plus-bg, var(--accent));
58
+ color: var(--add-row-plus-ink, var(--on-accent));
59
59
  display: grid;
60
60
  place-items: center;
61
- font-size: var(--fs-md);
61
+ font-size: var(--add-row-plus-font-size, var(--fs-md));
62
62
  line-height: 1;
63
63
  }
64
64
  .add-row__plus .icon { width: var(--icon-xs); height: var(--icon-xs); }
package/css/journey.css CHANGED
@@ -5,40 +5,40 @@
5
5
  ============================================================ */
6
6
 
7
7
  /* ---- route: endpoint · dotted connector (icon in middle) · endpoint ---- */
8
- .route { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; column-gap: var(--sp-1); } /* line → icon: --sp-1, as the via always had; code → line is the code row's own --sp-3 */
8
+ .route { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; column-gap: var(--route-col-gap, var(--sp-1)); } /* line → icon: --sp-1, as the via always had; code → line is the code row's own --sp-3 */
9
9
  /* the two endpoints get EQUAL columns whatever their words measure, so the via
10
10
  (the icon alone) sits at the card's centre; each dotted run lives on ITS
11
11
  endpoint's code row and fills that side's leftover — with short names the
12
12
  runs are long and equal, a long place name wraps in its half instead of
13
13
  pushing the plane (Lh 2026-09-16) */
14
14
 
15
- .route__point { display: grid; gap: var(--sp-0); min-width: 0; }
15
+ .route__point { display: grid; gap: var(--route-point-gap, var(--sp-0)); min-width: 0; }
16
16
  .route__point--end { text-align: right; }
17
17
 
18
- .route__code { font: var(--type-h2); letter-spacing: var(--track-h2); display: flex; align-items: center; gap: var(--sp-3); }
18
+ .route__code { font: var(--route-code-font, var(--type-h2)); letter-spacing: var(--track-h2); display: flex; align-items: center; gap: var(--route-code-gap, var(--sp-3)); }
19
19
  .route__code::after, .route__point--end .route__code::before { content: ""; flex: 1; border-top: var(--rule-w) dotted currentColor; opacity: 0.65; }
20
20
  .route__point--end .route__code::after { content: none; }
21
- .route__time { font: var(--type-body); font-variant-numeric: tabular-nums; }
22
- .route__place { font: var(--type-caption); color: var(--card-muted); }
21
+ .route__time { font: var(--route-time-font, var(--type-body)); font-variant-numeric: tabular-nums; }
22
+ .route__place { font: var(--route-place-font, var(--type-caption)); color: var(--route-place-ink, var(--card-muted)); }
23
23
  .card--3 .route__place { color: inherit; opacity: 0.7; }
24
24
 
25
- .route__via { display: flex; align-items: center; opacity: 0.65; font-size: var(--fs-body); }
25
+ .route__via { display: flex; align-items: center; opacity: 0.65; font-size: var(--route-via-font-size, var(--fs-body)); }
26
26
 
27
27
  /* ---- tile badge: tiny label over a big value (gate, seat, zone) ---- */
28
28
  .tile-badge {
29
29
  display: inline-grid;
30
30
  justify-items: center;
31
- gap: var(--sp-0);
32
- padding: var(--sp-1) var(--sp-2);
33
- border-radius: var(--r-badge);
34
- background: var(--card-3-bg);
35
- color: var(--card-3-ink);
31
+ gap: var(--tile-badge-gap, var(--sp-0));
32
+ padding: var(--tile-badge-pad-y, var(--sp-1)) var(--tile-badge-pad-x, var(--sp-2));
33
+ border-radius: var(--tile-badge-radius, var(--r-badge));
34
+ background: var(--tile-badge-bg, var(--card-3-bg));
35
+ color: var(--tile-badge-ink, var(--card-3-ink));
36
36
  }
37
- .tile-badge__label { font: var(--type-overline); letter-spacing: var(--track-overline); text-transform: uppercase; opacity: 0.7; }
37
+ .tile-badge__label { font: var(--tile-badge-label-font, var(--type-overline)); letter-spacing: var(--track-overline); text-transform: uppercase; opacity: 0.7; }
38
38
  .tile-badge__value { font: 800 var(--fs-lg)/1.1 var(--font-display); font-variant-numeric: tabular-nums; }
39
39
 
40
40
  /* plain: no fill — a date box beside a title (Jun / 18) */
41
- .tile-badge--plain { background: transparent; color: inherit; padding: 0; min-width: var(--tap-sm); }
41
+ .tile-badge--plain { background: transparent; color: inherit; padding: 0; min-width: var(--tile-badge-plain-min-w, var(--tap-sm)); }
42
42
  .tile-badge--plain .tile-badge__value { font: 800 var(--fs-h1)/1 var(--font-display); }
43
43
 
44
44
  /* corner badge: pin a tile badge on media (rating, price) — .card__media is relative */
@@ -48,8 +48,8 @@
48
48
  .note-row {
49
49
  display: flex;
50
50
  align-items: center;
51
- gap: var(--sp-2);
52
- font: var(--type-caption);
53
- color: var(--card-muted);
51
+ gap: var(--note-row-gap, var(--sp-2));
52
+ font: var(--note-row-font, var(--type-caption));
53
+ color: var(--note-row-ink, var(--card-muted));
54
54
  }
55
55
  .card--3 .note-row { color: inherit; opacity: 0.7; }