@usableapp/cardds 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/README.md +9 -5
  2. package/css/actions.css +38 -27
  3. package/css/base.css +9 -9
  4. package/css/card.css +24 -23
  5. package/css/choice.css +50 -50
  6. package/css/forms.css +18 -18
  7. package/css/journey.css +16 -16
  8. package/css/layover.css +45 -45
  9. package/css/lists.css +43 -43
  10. package/css/media.css +33 -33
  11. package/css/numbers.css +25 -25
  12. package/css/people.css +11 -11
  13. package/css/sheet.css +21 -21
  14. package/css/theme.template.css +6 -3
  15. package/dist/actions/Btn.d.ts +109 -108
  16. package/dist/actions/BtnRow.d.ts +2 -2
  17. package/dist/actions/Chip.d.ts +102 -101
  18. package/dist/actions/Dot.d.ts +2 -2
  19. package/dist/actions/Dropdown.d.ts +4 -4
  20. package/dist/actions/Fab.d.ts +2 -2
  21. package/dist/actions/IconBtn.d.ts +107 -106
  22. package/dist/actions/Link.d.ts +105 -104
  23. package/dist/actions/Segment.d.ts +3 -3
  24. package/dist/cardds.css +333 -321
  25. package/dist/cards/Card.d.ts +99 -98
  26. package/dist/cards/CardFoot.d.ts +2 -2
  27. package/dist/cards/CardHead.d.ts +2 -2
  28. package/dist/cards/CardParts.d.ts +7 -7
  29. package/dist/cards/Placeholder.d.ts +2 -2
  30. package/dist/cards/Stat.d.ts +7 -5
  31. package/dist/cards/Stat.js +2 -2
  32. package/dist/choice/Calendar.d.ts +2 -2
  33. package/dist/choice/Check.d.ts +3 -3
  34. package/dist/choice/DayStrip.d.ts +3 -3
  35. package/dist/choice/Mood.d.ts +2 -2
  36. package/dist/choice/Slider.d.ts +2 -2
  37. package/dist/forms/AddRow.d.ts +2 -2
  38. package/dist/forms/Composer.d.ts +2 -2
  39. package/dist/forms/Field.d.ts +2 -2
  40. package/dist/forms/FileBtn.d.ts +2 -2
  41. package/dist/forms/Pin.d.ts +2 -2
  42. package/dist/journey/NoteRow.d.ts +2 -2
  43. package/dist/journey/Route.d.ts +2 -2
  44. package/dist/journey/TileBadge.d.ts +2 -2
  45. package/dist/layover/Banner.d.ts +2 -2
  46. package/dist/layover/Callout.d.ts +2 -2
  47. package/dist/layover/Deck.d.ts +3 -3
  48. package/dist/lists/Bubble.d.ts +3 -3
  49. package/dist/lists/Kv.d.ts +5 -5
  50. package/dist/lists/Legend.d.ts +3 -3
  51. package/dist/lists/Row.d.ts +5 -4
  52. package/dist/lists/Timeline.d.ts +3 -3
  53. package/dist/media/MapArea.d.ts +2 -2
  54. package/dist/media/Mosaic.d.ts +3 -3
  55. package/dist/media/Postcard.d.ts +2 -2
  56. package/dist/media/Quote.d.ts +2 -2
  57. package/dist/media/Tile.d.ts +5 -4
  58. package/dist/numbers/Badge.d.ts +2 -2
  59. package/dist/numbers/Band.d.ts +3 -3
  60. package/dist/numbers/Bars.d.ts +3 -3
  61. package/dist/numbers/DotGrid.d.ts +2 -2
  62. package/dist/numbers/Picker.d.ts +3 -3
  63. package/dist/numbers/Ring.d.ts +2 -2
  64. package/dist/numbers/Track.d.ts +3 -3
  65. package/dist/people/Avatar.d.ts +100 -99
  66. package/dist/people/AvatarPick.d.ts +3 -3
  67. package/dist/scaffold/ActionBar.d.ts +3 -3
  68. package/dist/scaffold/AppBar.d.ts +2 -2
  69. package/dist/scaffold/BaseContent.d.ts +3 -3
  70. package/dist/scaffold/Centre.d.ts +3 -3
  71. package/dist/scaffold/EmptyState.d.ts +2 -2
  72. package/dist/scaffold/FilterRow.d.ts +2 -2
  73. package/dist/scaffold/FloatBar.d.ts +105 -104
  74. package/dist/scaffold/PagerAt.d.ts +2 -2
  75. package/dist/scaffold/Screen.d.ts +100 -99
  76. package/dist/scaffold/TopBar.d.ts +2 -2
  77. package/dist/sheets/CardBack.d.ts +2 -2
  78. package/dist/sheets/Drawer.d.ts +5 -5
  79. package/dist/sheets/Sheet.d.ts +2 -2
  80. package/dist/sheets/SheetBody.d.ts +2 -2
  81. package/dist/sheets/SheetHead.d.ts +2 -2
  82. package/dist/sheets/SheetStack.d.ts +2 -2
  83. package/dist/sheets/SheetStage.d.ts +2 -2
  84. package/dist/sheets/Step.d.ts +2 -2
  85. package/dist/type/Icon.d.ts +22 -7
  86. package/dist/type/Icon.js +27 -4
  87. package/dist/type/Text.d.ts +7 -1
  88. package/dist/type/Text.js +2 -2
  89. package/package.json +3 -2
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; }
package/css/layover.css CHANGED
@@ -46,7 +46,7 @@
46
46
  display: grid;
47
47
  grid-template-rows: minmax(0, 1fr) auto;
48
48
  overflow: clip;
49
- box-shadow: var(--shadow-sheet);
49
+ box-shadow: var(--modal-shadow, var(--shadow-sheet));
50
50
  }
51
51
  .modal__lift {
52
52
  padding: var(--card-pad);
@@ -60,15 +60,15 @@
60
60
  .modal__drawer {
61
61
  height: var(--drawer-h);
62
62
  box-sizing: border-box;
63
- padding: var(--sp-5);
63
+ padding: var(--modal-drawer-pad, var(--sp-5));
64
64
  overflow: clip;
65
65
  display: grid;
66
66
  align-content: center;
67
67
  justify-items: center;
68
- gap: var(--sp-1);
68
+ gap: var(--modal-drawer-gap, var(--sp-1));
69
69
  text-align: center;
70
- background: var(--card-3-bg);
71
- color: var(--card-3-ink);
70
+ background: var(--modal-drawer-bg, var(--card-3-bg));
71
+ color: var(--modal-drawer-ink, var(--card-3-ink));
72
72
  --accent: var(--card-3-ink); /* the one solid button inverts on the dark drawer */
73
73
  --on-accent: var(--card-3-bg);
74
74
  }
@@ -84,14 +84,14 @@
84
84
  }
85
85
  @keyframes modal-open {
86
86
  0%, 50% { height: 0; padding-block: 0; } /* inside the card */
87
- 100% { height: var(--drawer-h); padding-block: var(--sp-5); } /* 2. out below, the lift up, together */
87
+ 100% { height: var(--drawer-h); padding-block: var(--modal-drawer-pad, var(--sp-5)); } /* 2. out below, the lift up, together — the same knob the rule reads: a keyframe that pinned the value would make the knob dead */
88
88
  }
89
89
  }
90
90
 
91
- .btn-trio { display: flex; align-items: center; gap: var(--sp-3); margin-top: var(--sp-3); }
91
+ .btn-trio { display: flex; align-items: center; gap: var(--btn-trio-gap, var(--sp-3)); margin-top: var(--sp-3); }
92
92
  .btn-trio__dots {
93
- width: var(--sp-5);
94
- height: var(--sp-1);
93
+ width: var(--btn-trio-dots-w, var(--sp-5));
94
+ height: var(--btn-trio-dots-h, var(--sp-1));
95
95
  background: radial-gradient(circle, currentColor var(--sp-0), transparent calc(var(--sp-0) + 0.5px)) 0 0 / calc(var(--sp-5) / 2) 100% repeat-x;
96
96
  opacity: 0.4;
97
97
  }
@@ -112,31 +112,31 @@
112
112
  display: none; /* explicit closed state — never display on the base rule */
113
113
  margin: 0;
114
114
  inset: auto;
115
- border: var(--border-w) solid var(--action-border);
116
- border-radius: var(--r-card);
115
+ border: var(--border-w) solid var(--menu-border, var(--action-border));
116
+ border-radius: var(--menu-radius, var(--r-card));
117
117
  --menu-pad: var(--sp-2); /* published: a row's radius is concentric with the panel's */
118
118
  padding: var(--menu-pad);
119
119
  min-width: 12rem;
120
- background: var(--action-bg);
121
- color: var(--action-ink);
122
- box-shadow: var(--shadow-float);
120
+ background: var(--menu-bg, var(--action-bg));
121
+ color: var(--menu-ink, var(--action-ink));
122
+ box-shadow: var(--menu-shadow, var(--shadow-float));
123
123
  }
124
124
  .menu:popover-open { display: grid; }
125
125
  .menu:not([popover]) { display: grid; position: relative; } /* inline usage (no attribute) */
126
126
  .menu__item {
127
127
  display: flex;
128
128
  align-items: center;
129
- gap: var(--sp-3);
130
- min-height: var(--tap);
129
+ gap: var(--menu-item-gap, var(--sp-3));
130
+ min-height: var(--menu-item-min-h, var(--tap));
131
131
  width: 100%;
132
- padding: 0 var(--sp-3);
132
+ padding: var(--menu-item-pad-y, 0) var(--menu-item-pad-x, var(--sp-3));
133
133
  border: 0;
134
134
  /* concentric with the panel: the card radius minus the panel's padding, so the
135
135
  highlight's curve follows the outer corner (Lh 2026-09-16) */
136
136
  border-radius: calc(var(--r-card) - var(--menu-pad, var(--sp-2)));
137
137
  background: transparent;
138
138
  color: inherit;
139
- font: var(--type-title);
139
+ font: var(--menu-item-font, var(--type-title));
140
140
  text-align: left;
141
141
  cursor: pointer;
142
142
  }
@@ -164,12 +164,12 @@
164
164
  /* ---- banner: a chip that opens into a tinted card, no JS ----
165
165
  <details class="banner"><summary class="chip chip--on">Save $30 on orders over $70 <svg class="icon icon--xs"/></summary>
166
166
  <div class="card card--3 banner__body">…</div></details> */
167
- .banner { display: grid; gap: var(--sp-2); justify-items: start; }
167
+ .banner { display: grid; gap: var(--banner-gap, var(--sp-2)); justify-items: start; }
168
168
  .banner > summary { list-style: none; cursor: pointer; }
169
169
  .banner > summary::-webkit-details-marker { display: none; }
170
170
  .banner > summary .icon { transition: rotate 0.2s ease; }
171
171
  .banner[open] > summary .icon { rotate: 180deg; }
172
- .banner__body { width: 100%; padding: var(--sp-4) var(--sp-5); --card-gap: var(--sp-1); }
172
+ .banner__body { width: 100%; padding: var(--banner-body-pad-y, var(--sp-4)) var(--banner-body-pad-x, var(--sp-5)); --card-gap: var(--sp-1); }
173
173
  .banner::details-content { width: 100%; } /* Chromium wraps the content in this pseudo; justify-items: start shrink-wrapped it, so the body never reached the width */
174
174
  @supports (interpolate-size: allow-keywords) {
175
175
  @media (prefers-reduced-motion: no-preference) {
@@ -187,9 +187,9 @@
187
187
  bottom: var(--sp-5);
188
188
  max-width: var(--screen-w);
189
189
  margin-inline: auto;
190
- padding-inline: var(--sp-4);
190
+ padding-inline: var(--float-bar-pad-x, var(--sp-4));
191
191
  display: flex;
192
- gap: var(--sp-2);
192
+ gap: var(--float-bar-gap, var(--sp-2));
193
193
  align-items: center;
194
194
  z-index: 30;
195
195
  }
@@ -204,29 +204,29 @@
204
204
  display: flex;
205
205
  justify-content: space-around;
206
206
  align-items: center;
207
- min-height: var(--bar-h);
208
- padding: var(--sp-1);
209
- border-radius: var(--r-chip);
210
- border: var(--border-w) solid var(--action-border);
211
- background: color-mix(in srgb, var(--action-bg) 82%, transparent);
212
- color: var(--action-ink);
207
+ min-height: var(--float-bar-pill-min-h, var(--bar-h));
208
+ padding: var(--float-bar-pill-pad, var(--sp-1));
209
+ border-radius: var(--float-bar-pill-radius, var(--r-chip));
210
+ border: var(--border-w) solid var(--float-bar-pill-border, var(--action-border));
211
+ background: var(--float-bar-pill-bg, color-mix(in srgb, var(--action-bg) 82%, transparent));
212
+ color: var(--float-bar-pill-ink, var(--action-ink));
213
213
  backdrop-filter: blur(var(--sp-3));
214
214
  -webkit-backdrop-filter: blur(var(--sp-3));
215
- box-shadow: var(--shadow-float);
215
+ box-shadow: var(--float-bar-pill-shadow, var(--shadow-float));
216
216
  }
217
217
  .float-bar__item {
218
218
  flex: 1;
219
219
  min-width: 0;
220
220
  display: grid;
221
221
  justify-items: center;
222
- gap: var(--sp-0);
223
- min-height: var(--tap-lg);
224
- padding: var(--sp-1);
222
+ gap: var(--float-bar-item-gap, var(--sp-0));
223
+ min-height: var(--float-bar-item-min-h, var(--tap-lg));
224
+ padding: var(--float-bar-item-pad, var(--sp-1));
225
225
  border: 0;
226
- border-radius: var(--r-chip);
226
+ border-radius: var(--float-bar-item-radius, var(--r-chip));
227
227
  background: transparent;
228
228
  color: inherit;
229
- font: var(--type-caption);
229
+ font: var(--float-bar-item-font, var(--type-caption));
230
230
  text-decoration: none;
231
231
  opacity: 0.6;
232
232
  overflow: hidden;
@@ -244,15 +244,15 @@
244
244
  .callout {
245
245
  position: absolute;
246
246
  display: grid;
247
- gap: var(--sp-0);
247
+ gap: var(--callout-gap, var(--sp-0));
248
248
  width: max-content;
249
249
  max-width: 15rem;
250
- padding: var(--sp-3) var(--sp-4);
251
- border: var(--border-w) solid var(--action-border);
252
- border-radius: var(--r-card);
253
- background: var(--action-bg);
254
- color: var(--action-ink);
255
- box-shadow: var(--shadow-float);
250
+ padding: var(--callout-pad-y, var(--sp-3)) var(--callout-pad-x, var(--sp-4));
251
+ border: var(--border-w) solid var(--callout-border, var(--action-border));
252
+ border-radius: var(--callout-radius, var(--r-card));
253
+ background: var(--callout-bg, var(--action-bg));
254
+ color: var(--callout-ink, var(--action-ink));
255
+ box-shadow: var(--callout-shadow, var(--shadow-float));
256
256
  text-align: center;
257
257
  }
258
258
  .callout::after {
@@ -269,15 +269,15 @@
269
269
  border-top: 0;
270
270
  border-left: 0;
271
271
  }
272
- .callout__title { font: var(--type-title); }
273
- .callout__sub { font: var(--type-caption); opacity: 0.7; }
272
+ .callout__title { font: var(--callout-title-font, var(--type-title)); }
273
+ .callout__sub { font: var(--callout-sub-font, var(--type-caption)); opacity: 0.7; }
274
274
  /* ---- deck: swipe cards; the last child is on top ----
275
275
  <div class="deck"><article class="card">…</article><article class="card">…</article><article class="card card--fold">front</article></div>
276
276
  <div class="deck__actions"><button class="icon-btn">×</button><button class="icon-btn icon-btn--invert">✓</button></div> */
277
- .deck { display: grid; place-items: center; padding: var(--sp-4) var(--sp-4) var(--sp-6); }
277
+ .deck { display: grid; place-items: center; padding: var(--deck-pad-top, var(--sp-4)) var(--deck-pad-x, var(--sp-4)) var(--deck-pad-bottom, var(--sp-6)); }
278
278
  .deck > .card { grid-area: 1 / 1; width: min(100%, 20rem); min-height: 12.5rem; transition: rotate 0.3s ease, translate 0.3s ease; }
279
279
  .deck > .card:nth-last-child(2) { rotate: -4deg; translate: calc(-1 * var(--sp-2)) var(--sp-2); opacity: 0.85; }
280
280
  .deck > .card:nth-last-child(3) { rotate: 5deg; translate: var(--sp-3) var(--sp-4); opacity: 0.6; }
281
281
  .deck > .card:nth-last-child(n + 4) { display: none; }
282
- .deck__actions { display: flex; justify-content: center; gap: var(--sp-8); }
282
+ .deck__actions { display: flex; justify-content: center; gap: var(--deck-actions-gap, var(--sp-8)); }
283
283
  .deck__actions > .icon-btn { width: var(--bar-h); height: var(--bar-h); }
package/css/lists.css CHANGED
@@ -11,8 +11,8 @@
11
11
  .row {
12
12
  display: flex;
13
13
  align-items: center;
14
- gap: var(--sp-3);
15
- min-height: var(--tap); /* the tap target's room — the row's only vertical size */
14
+ gap: var(--row-gap, var(--sp-3));
15
+ min-height: var(--row-min-h, var(--tap)); /* the tap target's room — the row's only vertical size */
16
16
  min-width: 0;
17
17
  color: inherit;
18
18
  text-decoration: none; /* .row works as <a> too — it is a tap target */
@@ -21,20 +21,20 @@
21
21
  Space BETWEEN rows is .rows' gap; a lone row as card content takes the card's
22
22
  gap. (.row--flush, which zeroed the old padding, is gone — every row is flush.) */
23
23
  .row__lead {
24
- width: var(--tap);
25
- height: var(--tap);
24
+ width: var(--row-lead-size, var(--tap));
25
+ height: var(--row-lead-size, var(--tap));
26
26
  flex: none;
27
- border-radius: var(--r-control);
28
- border: var(--border-w) solid var(--outline);
27
+ border-radius: var(--row-lead-radius, var(--r-control));
28
+ border: var(--border-w) solid var(--row-lead-border, var(--outline));
29
29
  display: grid;
30
30
  place-items: center;
31
31
  }
32
- .row__body { flex: 1; min-width: 0; display: grid; gap: var(--sp-0); }
33
- .row__title { font: var(--type-title); overflow-wrap: anywhere; } /* wraps freely — no clip, so no padding trick for Thai marks (Lh 2026-09-16, same call as the card heading) */
34
- .row__meta { font: var(--type-caption); color: var(--card-muted); display: flex; align-items: center; gap: var(--sp-1); }
32
+ .row__body { flex: 1; min-width: 0; display: grid; gap: var(--row-body-gap, var(--sp-0)); }
33
+ .row__title { font: var(--row-title-font, var(--type-title)); overflow-wrap: anywhere; } /* wraps freely — no clip, so no padding trick for Thai marks (Lh 2026-09-16, same call as the card heading) */
34
+ .row__meta { font: var(--row-meta-font, var(--type-caption)); color: var(--row-meta-ink, var(--card-muted)); display: flex; align-items: center; gap: var(--row-meta-gap, var(--sp-1)); }
35
35
  .card--3 .row__meta { color: inherit; opacity: 0.7; }
36
- .row__end { margin-left: auto; text-align: right; display: grid; gap: var(--sp-0); justify-items: end; flex: none; }
37
- .row--lg { min-height: var(--fab); } /* menu rows: a taller target, round arrow at the end; .rows gives them more air */
36
+ .row__end { margin-left: auto; text-align: right; display: grid; gap: var(--row-end-gap, var(--sp-0)); justify-items: end; flex: none; }
37
+ .row--lg { min-height: var(--row-lg-min-h, var(--fab)); } /* menu rows: a taller target, round arrow at the end; .rows gives them more air */
38
38
  .row--lg .row__title { font: 700 var(--fs-lg)/1.2 var(--font-display); }
39
39
  /* a finished item in a checklist (a to-do list, an onboarding "complete your introduction" list):
40
40
  the words go muted, a filled tick sits at the end, and the row is no longer a tap target —
@@ -44,13 +44,13 @@
44
44
  .row--done .row__title { color: var(--card-muted); }
45
45
  .card--3 .row--done .row__title { color: inherit; opacity: 0.7; }
46
46
  .row__done {
47
- width: var(--tap-sm);
48
- height: var(--tap-sm);
47
+ width: var(--row-done-size, var(--tap-sm));
48
+ height: var(--row-done-size, var(--tap-sm));
49
49
  flex: none;
50
50
  margin-left: auto;
51
51
  border-radius: 50%;
52
- background: var(--accent);
53
- color: var(--on-accent);
52
+ background: var(--row-done-bg, var(--accent));
53
+ color: var(--row-done-ink, var(--on-accent));
54
54
  display: grid;
55
55
  place-items: center;
56
56
  }
@@ -71,20 +71,20 @@
71
71
  /* ---- kv: label left, value right ----
72
72
  <dl class="kv"><div class="kv__row"><dt class="kv__key">Pay with</dt><dd class="kv__val">GHO</dd></div>…</dl> */
73
73
  .kv { margin: 0; display: grid; }
74
- .kv__row { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); min-height: var(--tap); }
74
+ .kv__row { display: flex; align-items: center; justify-content: space-between; gap: var(--kv-row-gap, var(--sp-3)); min-height: var(--kv-row-min-h, var(--tap)); }
75
75
  .kv--lined > .kv__row + .kv__row { border-top: var(--border-w) solid var(--hairline); }
76
- .kv__key { font: var(--type-body); color: var(--card-muted); }
76
+ .kv__key { font: var(--kv-key-font, var(--type-body)); color: var(--kv-key-ink, var(--card-muted)); }
77
77
  .card--3 .kv__key { color: inherit; opacity: 0.7; }
78
- .kv__val { margin: 0; font: var(--type-title); display: inline-flex; align-items: center; gap: var(--sp-2); text-align: right; min-width: 0; }
78
+ .kv__val { margin: 0; font: var(--kv-val-font, var(--type-title)); display: inline-flex; align-items: center; gap: var(--kv-val-gap, var(--sp-2)); text-align: right; min-width: 0; }
79
79
 
80
80
  /* ---- kv grid: value over label, cells split by a rule (Sex | Weight) ----
81
81
  <div class="kv-grid"><div class="kv-cell"><svg class="icon"/><span class="kv-cell__val">15.6 kg</span><span class="kv-cell__key">Weight</span></div>…</div> */
82
- .kv-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(var(--tile-min), 100%), 1fr)); gap: var(--sp-4); }
82
+ .kv-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(var(--tile-min), 100%), 1fr)); gap: var(--kv-grid-gap, var(--sp-4)); }
83
83
  .kv-grid > .kv-cell + .kv-cell { border-left: var(--border-w) solid var(--hairline); padding-left: var(--sp-4); }
84
- .kv-cell { display: grid; gap: var(--sp-0); align-content: start; min-width: 0; }
84
+ .kv-cell { display: grid; gap: var(--kv-cell-gap, var(--sp-0)); align-content: start; min-width: 0; }
85
85
  .kv-cell > .icon { margin-bottom: var(--sp-1); }
86
- .kv-cell__val { font: var(--type-h2); letter-spacing: var(--track-h2); font-variant-numeric: tabular-nums; }
87
- .kv-cell__key { font: var(--type-caption); color: var(--card-muted); }
86
+ .kv-cell__val { font: var(--kv-cell-val-font, var(--type-h2)); letter-spacing: var(--track-h2); font-variant-numeric: tabular-nums; }
87
+ .kv-cell__key { font: var(--kv-cell-key-font, var(--type-caption)); color: var(--kv-cell-key-ink, var(--card-muted)); }
88
88
  .card--3 .kv-cell__key { color: inherit; opacity: 0.7; }
89
89
 
90
90
  /* ---- bubble: a chat message — theirs on the left, mine on the right (Lh 2026-09-18, replaces the chip's tail) ----
@@ -96,7 +96,7 @@
96
96
  <div class="bubble"><p class="bubble__body">…</p><span class="bubble__actions">…icon-btns…</span><span class="bubble__meta">Dec 4 · 8:15</span></div>
97
97
  <div class="bubble bubble--right">…</div>
98
98
  </div> */
99
- .thread { display: grid; gap: var(--sp-4); }
99
+ .thread { display: grid; gap: var(--thread-gap, var(--sp-4)); }
100
100
  /* two columns: the message (max-content, but it gives way — minmax(0) — so a long one shrinks
101
101
  and wraps while the actions stay beside it) and the actions; the meta on a second row under the message */
102
102
  .bubble {
@@ -116,12 +116,12 @@
116
116
  .bubble__body {
117
117
  margin: 0;
118
118
  min-width: 0;
119
- padding: var(--sp-3) var(--sp-4);
120
- border-radius: var(--r-card);
119
+ padding: var(--bubble-body-pad-y, var(--sp-3)) var(--bubble-body-pad-x, var(--sp-4));
120
+ border-radius: var(--bubble-body-radius, var(--r-card));
121
121
  border-bottom-left-radius: var(--r-control);
122
- background: var(--card-2-bg);
123
- color: var(--card-2-ink);
124
- font: var(--type-body);
122
+ background: var(--bubble-body-bg, var(--card-2-bg));
123
+ color: var(--bubble-body-ink, var(--card-2-ink));
124
+ font: var(--bubble-body-font, var(--type-body));
125
125
  overflow-wrap: anywhere;
126
126
  }
127
127
  .bubble--right > .bubble__body {
@@ -131,8 +131,8 @@
131
131
  color: var(--on-accent);
132
132
  text-align: right;
133
133
  }
134
- .bubble__actions { display: flex; gap: var(--sp-1); flex: none; opacity: 0.7; }
135
- .bubble__meta { display: flex; align-items: center; gap: var(--sp-1); font: var(--type-caption); color: var(--on-surface-muted); }
134
+ .bubble__actions { display: flex; gap: var(--bubble-actions-gap, var(--sp-1)); flex: none; opacity: 0.7; }
135
+ .bubble__meta { display: flex; align-items: center; gap: var(--bubble-meta-gap, var(--sp-1)); font: var(--bubble-meta-font, var(--type-caption)); color: var(--bubble-meta-ink, var(--on-surface-muted)); }
136
136
  .bubble--right > .bubble__meta { justify-self: end; }
137
137
  .bubble__meta > .icon { color: var(--accent); }
138
138
  .card--3 .bubble__meta { color: inherit; opacity: 0.7; }
@@ -144,7 +144,7 @@
144
144
  margin: 0;
145
145
  padding: 0 0 0 var(--sp-6);
146
146
  display: grid;
147
- gap: var(--sp-5);
147
+ gap: var(--timeline-gap, var(--sp-5));
148
148
  position: relative;
149
149
  }
150
150
  .timeline::before {
@@ -155,7 +155,7 @@
155
155
  bottom: var(--sp-3);
156
156
  border-left: var(--border-w) solid var(--hairline);
157
157
  }
158
- .timeline__item { display: grid; gap: var(--sp-2); position: relative; min-width: 0; }
158
+ .timeline__item { display: grid; gap: var(--timeline-item-gap, var(--sp-2)); position: relative; min-width: 0; }
159
159
  .timeline__item::before {
160
160
  content: "";
161
161
  position: absolute;
@@ -168,35 +168,35 @@
168
168
  }
169
169
  .timeline__mark {
170
170
  justify-self: start;
171
- font: var(--type-overline);
171
+ font: var(--timeline-mark-font, var(--type-overline));
172
172
  letter-spacing: var(--track-overline);
173
173
  text-transform: uppercase;
174
- padding: var(--sp-1) var(--sp-2);
175
- border-radius: var(--r-chip);
176
- background: var(--ink-tint);
174
+ padding: var(--timeline-mark-pad-y, var(--sp-1)) var(--timeline-mark-pad-x, var(--sp-2));
175
+ border-radius: var(--timeline-mark-radius, var(--r-chip));
176
+ background: var(--timeline-mark-bg, var(--ink-tint));
177
177
  }
178
178
 
179
179
  /* ---- legend: signal dots with captions ----
180
180
  <div class="legend"><span class="legend__item"><span class="dot"></span> very high</span>…</div> */
181
- .legend { display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-4); font: var(--type-caption); color: var(--card-muted); }
181
+ .legend { display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-4); font: var(--legend-font, var(--type-caption)); color: var(--legend-ink, var(--card-muted)); }
182
182
  .card--3 .legend { color: inherit; opacity: 0.8; }
183
- .legend__item { display: inline-flex; align-items: center; gap: var(--sp-2); min-height: var(--icon); }
183
+ .legend__item { display: inline-flex; align-items: center; gap: var(--legend-item-gap, var(--sp-2)); min-height: var(--legend-item-min-h, var(--icon)); }
184
184
 
185
185
  /* ---- link: "See all ↗" in a card head, big enough to tap ----
186
186
  <a class="link" href="#">See all <svg class="icon icon--xs"/></a> */
187
187
  .link {
188
188
  display: inline-flex;
189
189
  align-items: center;
190
- gap: var(--sp-1);
191
- min-height: var(--tap-sm);
190
+ gap: var(--link-gap, var(--sp-1));
191
+ min-height: var(--link-min-h, var(--tap-sm));
192
192
  color: inherit;
193
193
  text-decoration: none;
194
- font: var(--type-label);
195
- font-size: var(--fs-body);
194
+ font: var(--link-font, var(--type-label));
195
+ font-size: var(--link-font-size, var(--fs-body));
196
196
  border: 0;
197
197
  background: transparent;
198
198
  padding: 0;
199
199
  cursor: pointer;
200
200
  }
201
- .link--muted { color: var(--card-muted); }
201
+ .link--muted { color: var(--link-muted-ink, var(--card-muted)); }
202
202
  .card--3 .link--muted { color: inherit; opacity: 0.7; }
package/css/media.css CHANGED
@@ -43,16 +43,16 @@
43
43
 
44
44
  /* ---- quote: giant mark, big text, attribution ----
45
45
  <blockquote class="quote"><p class="quote__text">It's overcast…</p><footer class="quote__by">Wednesday 15</footer></blockquote> */
46
- .quote { margin: 0; display: grid; gap: var(--sp-3); }
46
+ .quote { margin: 0; display: grid; gap: var(--quote-gap, var(--sp-3)); }
47
47
  .quote::before {
48
48
  content: "\201C";
49
49
  font: 900 calc(var(--fs-h1) * 3)/0.55 var(--font-display);
50
50
  height: var(--sp-10);
51
51
  opacity: 0.9;
52
52
  }
53
- .quote__text { margin: 0; font: var(--type-h1); letter-spacing: var(--track-h1); text-wrap: balance; }
53
+ .quote__text { margin: 0; font: var(--quote-text-font, var(--type-h1)); letter-spacing: var(--track-h1); text-wrap: balance; }
54
54
  .quote--sm .quote__text { font: var(--type-h2); letter-spacing: var(--track-h2); }
55
- .quote__by { font: var(--type-overline); letter-spacing: var(--track-overline); text-transform: uppercase; color: var(--card-muted); }
55
+ .quote__by { font: var(--quote-by-font, var(--type-overline)); letter-spacing: var(--track-overline); text-transform: uppercase; color: var(--quote-by-ink, var(--card-muted)); }
56
56
  .card--3 .quote__by { color: inherit; opacity: 0.7; }
57
57
 
58
58
  /* ---- tile grid: big square tiles — icon top, label bottom ----
@@ -61,36 +61,36 @@
61
61
  .tile-grid {
62
62
  display: grid;
63
63
  grid-template-columns: repeat(auto-fill, minmax(min(var(--tile-min), 100%), 1fr));
64
- gap: var(--sp-3);
64
+ gap: var(--tile-grid-gap, var(--sp-3));
65
65
  }
66
66
  .tile-grid--3 { --tile-min: 6rem; } /* three across on a phone (attachments, upload kinds) */
67
67
  .tile {
68
68
  display: grid;
69
69
  align-content: space-between;
70
70
  justify-items: start;
71
- gap: var(--sp-5);
72
- min-height: var(--tile-h);
71
+ gap: var(--tile-gap, var(--sp-5));
72
+ min-height: var(--tile-min-h, var(--tile-h));
73
73
  min-width: 0;
74
- padding: var(--sp-4);
75
- border: var(--border-w) solid var(--outline);
76
- border-radius: var(--r-card);
77
- background: var(--action-bg);
78
- color: var(--action-ink);
74
+ padding: var(--tile-pad, var(--sp-4));
75
+ border: var(--border-w) solid var(--tile-border, var(--outline));
76
+ border-radius: var(--tile-radius, var(--r-card));
77
+ background: var(--tile-bg, var(--action-bg));
78
+ color: var(--tile-ink, var(--action-ink));
79
79
  font: inherit;
80
80
  text-align: left;
81
81
  position: relative;
82
82
  cursor: pointer;
83
83
  }
84
- .tile__label { font: var(--type-title); }
85
- .tile__value { font: var(--type-h2); letter-spacing: var(--track-h2); font-variant-numeric: tabular-nums; }
86
- .tile__sub { font: var(--type-caption); opacity: 0.7; }
87
- .tile__text { display: grid; gap: var(--sp-0); }
88
- .tile--on { background: var(--accent); color: var(--on-accent); border-color: transparent; }
84
+ .tile__label { font: var(--tile-label-font, var(--type-title)); }
85
+ .tile__value { font: var(--tile-value-font, var(--type-h2)); letter-spacing: var(--track-h2); font-variant-numeric: tabular-nums; }
86
+ .tile__sub { font: var(--tile-sub-font, var(--type-caption)); opacity: 0.7; }
87
+ .tile__text { display: grid; gap: var(--tile-text-gap, var(--sp-0)); }
88
+ .tile--on { background: var(--tile-on-bg, var(--accent)); color: var(--tile-on-ink, var(--on-accent)); border-color: transparent; }
89
89
  .tile--pick > input { appearance: none; position: absolute; inset: 0; margin: 0; opacity: 0; cursor: pointer; }
90
90
  .tile--pick:has(:checked) { background: var(--accent); color: var(--on-accent); border-color: transparent; }
91
91
  .tile--pick:has(:focus-visible) { outline: var(--focus); outline-offset: var(--sp-1); }
92
92
  .tile--wide { grid-column: 1 / -1; }
93
- .tile--stat { min-height: var(--avatar-xl); gap: var(--sp-3); grid-template-columns: auto 1fr; align-items: center; }
93
+ .tile--stat { min-height: var(--tile-stat-min-h, var(--avatar-xl)); gap: var(--tile-stat-gap, var(--sp-3)); grid-template-columns: auto 1fr; align-items: center; }
94
94
  /* upload: dashed, centred plus + label */
95
95
  .tile--upload {
96
96
  border-style: dashed;
@@ -98,12 +98,12 @@
98
98
  color: inherit;
99
99
  align-content: center;
100
100
  justify-items: center;
101
- gap: var(--sp-2);
101
+ gap: var(--tile-upload-gap, var(--sp-2));
102
102
  text-align: center;
103
103
  }
104
104
  /* tinted tiles: slot colors inside a card (schedule, notes) */
105
- .tile--2 { background: var(--card-2-bg); color: var(--card-2-ink); border-color: transparent; }
106
- .tile--3 { background: var(--card-3-bg); color: var(--card-3-ink); border-color: transparent; }
105
+ .tile--2 { background: var(--tile-2-bg, var(--card-2-bg)); color: var(--tile-2-ink, var(--card-2-ink)); border-color: transparent; }
106
+ .tile--3 { background: var(--tile-3-bg, var(--card-3-bg)); color: var(--tile-3-ink, var(--card-3-ink)); border-color: transparent; }
107
107
 
108
108
  /* ---- fold: a sticky-note corner on any card (decorative) ----
109
109
  No border. The card's outline follows its border box, so it ran straight
@@ -127,7 +127,7 @@
127
127
  <span class="wave"></span> — sits in a .row__body, fills the width */
128
128
  .wave {
129
129
  display: block;
130
- height: var(--icon);
130
+ height: var(--wave-h, var(--icon));
131
131
  width: 100%;
132
132
  background: repeating-linear-gradient(90deg, currentColor 0 var(--sp-1), transparent var(--sp-1) var(--sp-2));
133
133
  /* masks only read alpha: currentColor = "opaque" without naming a color */
@@ -142,9 +142,9 @@
142
142
  display: grid;
143
143
  grid-template-columns: 2fr 1fr;
144
144
  grid-auto-rows: 1fr;
145
- gap: var(--sp-1);
145
+ gap: var(--mosaic-gap, var(--sp-1));
146
146
  aspect-ratio: 4 / 3;
147
- border-radius: var(--r-media);
147
+ border-radius: var(--mosaic-radius, var(--r-media));
148
148
  overflow: hidden;
149
149
  }
150
150
  .mosaic > :first-child { grid-row: span 2; }
@@ -174,16 +174,16 @@
174
174
  position: relative;
175
175
  aspect-ratio: 3 / 2;
176
176
  perspective: 60rem;
177
- border-radius: var(--r-media);
177
+ border-radius: var(--postcard-radius, var(--r-media));
178
178
  }
179
179
  .postcard__face {
180
180
  position: absolute;
181
181
  inset: 0;
182
182
  display: grid;
183
183
  align-content: end;
184
- padding: var(--sp-4);
185
- gap: var(--sp-2);
186
- border: var(--border-w) solid var(--card-border);
184
+ padding: var(--postcard-face-pad, var(--sp-4));
185
+ gap: var(--postcard-face-gap, var(--sp-2));
186
+ border: var(--border-w) solid var(--postcard-face-border, var(--card-border));
187
187
  border-radius: inherit;
188
188
  overflow: hidden;
189
189
  isolation: isolate;
@@ -192,11 +192,11 @@
192
192
  backface-visibility: hidden;
193
193
  -webkit-backface-visibility: hidden;
194
194
  transition: transform var(--motion-flip) ease-in-out;
195
- box-shadow: var(--shadow-float);
195
+ box-shadow: var(--postcard-face-shadow, var(--shadow-float));
196
196
  }
197
197
  .postcard__face:focus-visible { outline: var(--focus); outline-offset: var(--sp-1); }
198
198
  /* the front: the photo (or the wireframe box) fills it, the name reads on a scrim */
199
- .postcard__front { background: var(--card-3-bg); color: var(--card-3-ink); }
199
+ .postcard__front { background: var(--postcard-front-bg, var(--card-3-bg)); color: var(--postcard-front-ink, var(--card-3-ink)); }
200
200
  .postcard__front > img,
201
201
  .postcard__front > .ph {
202
202
  position: absolute;
@@ -218,13 +218,13 @@
218
218
  }
219
219
  /* the back: paper — the words, big enough to read at arm's length */
220
220
  .postcard__back {
221
- background: var(--card-2-bg);
222
- color: var(--card-2-ink);
221
+ background: var(--postcard-back-bg, var(--card-2-bg));
222
+ color: var(--postcard-back-ink, var(--card-2-ink));
223
223
  align-content: space-between;
224
224
  transform: rotateY(180deg);
225
225
  }
226
- .postcard__caption { margin: 0; font: var(--type-title); text-wrap: pretty; }
227
- .postcard__label { font: var(--type-overline); letter-spacing: var(--track-overline); text-transform: uppercase; opacity: 0.85; }
226
+ .postcard__caption { margin: 0; font: var(--postcard-caption-font, var(--type-title)); text-wrap: pretty; }
227
+ .postcard__label { font: var(--postcard-label-font, var(--type-overline)); letter-spacing: var(--track-overline); text-transform: uppercase; opacity: 0.85; }
228
228
  .postcard.is-flipped > .postcard__front { transform: rotateY(-180deg); }
229
229
  .postcard.is-flipped > .postcard__back { transform: rotateY(0); }
230
230
  @media (prefers-reduced-motion: reduce) {