@usableapp/cardds 0.7.106 → 0.7.108
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +121 -0
- package/bin/cardds.mjs +5 -3
- package/cardds.css +1 -0
- package/css/actions.css +9 -9
- package/css/base.css +6 -9
- package/css/card.css +19 -186
- package/css/choice.css +26 -1
- package/css/finish.css +4 -4
- package/css/journey.css +7 -3
- package/css/layover.css +4 -14
- package/css/lists.css +6 -18
- package/css/media.css +1 -7
- package/css/palette.css +1 -1
- package/css/parts.css +380 -0
- package/css/sheet.css +12 -139
- package/css/stack.css +15 -26
- package/css/stamp.css +1 -1
- package/css/step.css +3 -3
- package/css/theme.template.css +1 -1
- package/css/tokens.css +4 -4
- package/dist/actions/BarNote.d.ts +2 -2
- package/dist/actions/BarNote.js +2 -2
- package/dist/actions/Btn.d.ts +2 -2
- package/dist/actions/Btn.js +1 -1
- package/dist/actions/BtnRow.d.ts +1 -1
- package/dist/actions/BtnRow.js +1 -1
- package/dist/actions/IconBtn.d.ts +1 -1
- package/dist/actions/IconBtn.js +1 -1
- package/dist/cardds.css +500 -426
- package/dist/cards/Card.d.ts +6 -22
- package/dist/cards/Card.js +11 -22
- package/dist/cards/CardFeed.d.ts +1 -1
- package/dist/cards/CardFeed.js +5 -5
- package/dist/cards/CardParts.d.ts +2 -13
- package/dist/cards/CardParts.js +2 -13
- package/dist/cards/cardGo.js +1 -1
- package/dist/cards/cardGrounds.js +2 -2
- package/dist/catalog.json +1 -1
- package/dist/choice/Calendar.d.ts +12 -3
- package/dist/choice/Calendar.js +17 -5
- package/dist/choice/CalendarWeeks.d.ts +10 -2
- package/dist/choice/CalendarWeeks.js +18 -4
- package/dist/choice/HourGrid.d.ts +36 -0
- package/dist/choice/HourGrid.js +21 -0
- package/dist/choice/calendarDay.d.ts +7 -2
- package/dist/choice/calendarDay.js +6 -3
- package/dist/choice/span.d.ts +34 -0
- package/dist/choice/span.js +80 -0
- package/dist/forms/Field.d.ts +1 -1
- package/dist/forms/Field.js +1 -1
- package/dist/index.d.ts +8 -5
- package/dist/index.js +7 -5
- package/dist/journey/JourneyBadge.d.ts +2 -1
- package/dist/lists/Kv.d.ts +4 -2
- package/dist/lists/Kv.js +3 -3
- package/dist/lists/Row.d.ts +2 -28
- package/dist/lists/Row.js +2 -17
- package/dist/media/MapArea.d.ts +2 -2
- package/dist/media/MapArea.js +1 -1
- package/dist/media/Tile.d.ts +3 -7
- package/dist/media/Tile.js +5 -5
- package/dist/parts/Body.d.ts +7 -0
- package/dist/parts/Body.js +11 -0
- package/dist/parts/End.d.ts +10 -0
- package/dist/parts/End.js +7 -0
- package/dist/parts/Foot.d.ts +17 -0
- package/dist/parts/Foot.js +11 -0
- package/dist/parts/Head.d.ts +15 -0
- package/dist/parts/Head.js +34 -0
- package/dist/parts/Lead.d.ts +10 -0
- package/dist/parts/Lead.js +9 -0
- package/dist/parts/Words.d.ts +13 -0
- package/dist/parts/Words.js +20 -0
- package/dist/parts/headCtx.d.ts +7 -0
- package/dist/parts/headCtx.js +9 -0
- package/dist/scaffold/EmptyState.d.ts +1 -1
- package/dist/scaffold/EmptyState.js +1 -1
- package/dist/scaffold/Screen.js +1 -1
- package/dist/sheets/Modal.d.ts +3 -7
- package/dist/sheets/Modal.js +3 -7
- package/dist/sheets/Sheet.d.ts +2 -2
- package/dist/sheets/Sheet.js +8 -9
- package/dist/sheets/SheetStack.d.ts +3 -3
- package/dist/sheets/SheetStack.js +4 -4
- package/dist/sheets/SheetSteps.d.ts +1 -1
- package/dist/sheets/SheetSteps.js +2 -2
- package/dist/sheets/StackBack.d.ts +1 -1
- package/dist/sheets/StackBack.js +1 -1
- package/dist/sheets/StackSheet.js +7 -7
- package/dist/sheets/sheetMeasure.js +3 -3
- package/dist/sheets/sheetStepsPile.js +2 -2
- package/dist/sheets/stackCard.js +6 -6
- package/dist/templates/CallSheet.js +6 -5
- package/dist/templates/Walkthrough.js +3 -2
- package/docs/reference.md +76 -37
- package/lib/catalog.mjs +1 -1
- package/lib/mcp.mjs +1 -1
- package/lint/rules.mjs +14 -7
- package/package.json +2 -1
- package/scripts/codemod-parts.mjs +403 -0
- package/dist/cards/CardFoot.d.ts +0 -15
- package/dist/cards/CardFoot.js +0 -9
- package/dist/cards/CardHead.d.ts +0 -21
- package/dist/cards/CardHead.js +0 -39
- package/dist/cards/Stat.d.ts +0 -19
- package/dist/cards/Stat.js +0 -14
- package/dist/sheets/SheetBody.d.ts +0 -5
- package/dist/sheets/SheetBody.js +0 -9
- package/dist/sheets/SheetHead.d.ts +0 -15
- package/dist/sheets/SheetHead.js +0 -6
package/css/card.css
CHANGED
|
@@ -42,80 +42,14 @@
|
|
|
42
42
|
.card--4 { --card-bg: var(--card-4-bg); --dark: var(--card-4-dark); }
|
|
43
43
|
.card--5 { --card-bg: var(--card-5-bg); --dark: var(--card-5-dark); }
|
|
44
44
|
|
|
45
|
-
/* header row: title left, floating action right — centered, since the
|
|
46
|
-
trailing control (chip/badge/icon-btn/link) is almost always taller than
|
|
47
|
-
a single line of title text; top-aligning them left the control visually
|
|
48
|
-
low against the title's optical center. A head with a genuinely tall,
|
|
49
|
-
multi-line title can opt back out with .card__head--top. */
|
|
50
|
-
.card__head {
|
|
51
|
-
display: flex;
|
|
52
|
-
flex-wrap: var(--card-head-wrap, wrap); /* the caption takes a line of its own — no wrapper div */
|
|
53
|
-
align-items: center;
|
|
54
|
-
justify-content: space-between;
|
|
55
|
-
column-gap: var(--card-head-col-gap, var(--sp-3));
|
|
56
|
-
row-gap: var(--card-head-row-gap, var(--sp-0));
|
|
57
|
-
min-height: var(--card-head-min-h, auto);
|
|
58
|
-
}
|
|
59
|
-
.card__head--top { align-items: flex-start; }
|
|
60
45
|
|
|
61
46
|
.card__media { border-radius: var(--card-media-radius, var(--r-media)); overflow: hidden; position: relative; } /* relative: corner badges */
|
|
62
|
-
.card__end { text-align: right; display: grid; gap: var(--card-end-gap, var(--sp-0)); justify-items: end; } /* trailing value + caption */
|
|
63
47
|
.card__media > img { width: 100%; height: auto; object-fit: cover; }
|
|
64
48
|
|
|
65
|
-
/* ---- the card skeleton: head · content · foot ----
|
|
66
|
-
Every card is a head (the heading left, hints / actions / a more-menu at
|
|
67
|
-
the far right), its content, and an optional foot of action buttons.
|
|
68
|
-
The head's leading child — the heading, or the div that wraps heading and
|
|
69
|
-
caption — takes the room, so a heading with nothing at the far right runs
|
|
70
|
-
all the way across; whatever trails it hugs its own width. Only the
|
|
71
|
-
heading (or the div that wraps it) is that leading child: a control that
|
|
72
|
-
leads a custom head — a chip, an avatar, a tile badge — keeps its own
|
|
73
|
-
width, else the rule stretched a chip into a bar and an avatar into an
|
|
74
|
-
ellipse (two agents and the wallet demo caught it, 2026-09-10). */
|
|
75
|
-
.card__head > :is(h1, h2, h3, div, p):first-child { flex: 1; min-width: 0; }
|
|
76
|
-
|
|
77
|
-
/* Skeleton head — the heading in a card's OWN head, and only there.
|
|
78
|
-
The heading wraps, no squeeze, up to three lines and cut there with an
|
|
79
|
-
ellipsis (Lh 2026-10-21: "มันควรจะ max สามบรรทัด" — a request's title ran to
|
|
80
|
-
four lines on a phone; reverses 2026-09-16's "no clamp"). The count is the knob
|
|
81
|
-
--card-head-title-lines. The group that holds heading ·
|
|
82
|
-
caption is the head's own wrapping row (above) — no wrapper element, no
|
|
83
|
-
height, only the row gap. */
|
|
84
|
-
.card__head :is(h1, h2, h3) {
|
|
85
|
-
overflow-wrap: anywhere;
|
|
86
|
-
display: -webkit-box;
|
|
87
|
-
-webkit-box-orient: vertical;
|
|
88
|
-
-webkit-line-clamp: var(--card-head-title-lines, 3);
|
|
89
|
-
line-clamp: var(--card-head-title-lines, 3);
|
|
90
|
-
overflow: hidden;
|
|
91
|
-
padding-block-start: var(--_mark-room); /* a stacked Thai mark rises over the first line's box: room inside the clip, given back outside */
|
|
92
|
-
margin-block-start: calc(-1 * var(--_mark-room));
|
|
93
|
-
--_mark-room: 0.2em;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/* a Stamp in a card's head (`Card end={<Stamp …/>}`): the words stand at the left, the stamp at the right BESIDE BOTH LINES — the heading and the
|
|
97
|
-
caption pair up beside it, not the stamp beside the heading alone with the caption left under it. The stamp is its own size (--stamp-size,
|
|
98
|
-
stamp.css); the head only places it.
|
|
99
|
-
<div class="card__head"><h2 class="t-h2">…</h2><span class="t-caption t-muted">…</span><span class="stamp">…</span></div> */
|
|
100
|
-
.card__head:has(> .stamp) { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; }
|
|
101
|
-
.card__head:has(> .stamp) > :is(h1, h2, h3) { grid-column: 1; grid-row: 1; align-self: end; }
|
|
102
|
-
|
|
103
|
-
/* a head that LEADS with a date (Lh 2026-10-21, timebank's request card): a `CardHead` whose first child is a JourneyBadge and whose second is a
|
|
104
|
-
ChipRow. The date stands at the left and the chips beside it, the two as tall as each other; the heading and its caption take the whole
|
|
105
|
-
width under them, so the heading sits right over the words of the middle. The date is always as tall as the chips. The gap under the date row is --card-head-lead-gap; the date and the chips place themselves (journey.css, actions.css).
|
|
106
|
-
<div class="card__head"><span class="tile-badge tile-badge--stretch">…</span><div class="chip-row">…</div><div><h2 class="t-h1">…</h2>…</div></div> */
|
|
107
|
-
.card__head:has(> .tile-badge:first-child + .chip-row) {
|
|
108
|
-
display: grid;
|
|
109
|
-
grid-template-columns: auto minmax(0, 1fr);
|
|
110
|
-
align-items: center;
|
|
111
|
-
row-gap: var(--card-head-lead-gap, var(--sp-3));
|
|
112
|
-
}
|
|
113
|
-
.card__head:has(> .tile-badge:first-child + .chip-row) > :nth-child(n + 3) { grid-column: 1 / -1; }
|
|
114
|
-
|
|
115
49
|
/* a JourneyBadge at the edge of the card's own first head (the date box in the top-left or top-right corner) keeps its corner concentric
|
|
116
50
|
with the card's: the card's corner (--r-card) less the room the padding leaves round it. journey.css reads it behind the theme's --tile-badge-radius,
|
|
117
51
|
so a theme that sets that knob still wins. */
|
|
118
|
-
:is(.card > .
|
|
52
|
+
:is(.card > .head:first-child, .card__face > .card__turn + .head) > .tile-badge:is(:first-child, :last-child) { --_badge-radius: calc(var(--r-card) - var(--card-pad)); } /* a turning card's face: its head follows the unseen turn button */
|
|
119
53
|
|
|
120
54
|
/* ---- paper bands: the two-tone card (`Card paper="bands"`, Lh 2026-10-19): the head and the foot are paper bands edge to
|
|
121
55
|
edge over the card's padding, no hairline; the middle between them keeps the card's tone, lightened (--card-middle-bg). The card
|
|
@@ -127,20 +61,9 @@
|
|
|
127
61
|
overflow: hidden;
|
|
128
62
|
}
|
|
129
63
|
.card--bands.card--turns { background: none; overflow: visible; } /* the turning box keeps --dark: the faces' ink is computed from it */
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
background: var(--card-bg);
|
|
134
|
-
color: var(--card-ink);
|
|
135
|
-
margin-inline: calc(-1 * var(--card-pad));
|
|
136
|
-
padding-inline: var(--card-pad);
|
|
137
|
-
}
|
|
138
|
-
:is(.card--bands, .card--bands > .card__face) > .card__head { margin-top: calc(-1 * var(--card-pad)); padding-block: var(--card-pad); }
|
|
139
|
-
:is(.card--bands, .card--bands > .card__face) > .card__head { padding-block-end: var(--card-band-seam, var(--sp-2)); }
|
|
140
|
-
/* the seam: the heading and the words under it read as ONE paragraph that changes colour at the band's edge (Lh 2026-10-21), so the room on
|
|
141
|
-
each side of the head band's lower edge is --card-band-seam, not the card's padding and gap */
|
|
142
|
-
:is(.card--bands, .card--bands > .card__face) > .card__head + * { margin-block-start: calc(var(--card-band-seam, var(--sp-2)) - var(--card-gap)); }
|
|
143
|
-
:is(.card--bands, .card--bands > .card__face) > .card__foot { margin-bottom: calc(-1 * var(--card-pad)); padding-block: var(--sp-3); } /* the foot band is slim */
|
|
64
|
+
/* on a dark tone (3, 5) the lightened middle is a mid grey (#adadad, #bbbbbb in wireframe) that no muted ink reads on (3.2:1 and 3.8:1;
|
|
65
|
+
the ink gate, 2026-10-22, from the caption under a code on a `Card back`): there the middle's secondary words take the full ink */
|
|
66
|
+
:is(.card--bands, .card--bands > .card__face):is(.card--3, .card--5, .card--3 > *, .card--5 > *) { --card-muted: var(--card-ink); }
|
|
144
67
|
|
|
145
68
|
/* ---- two faces: the WHOLE card turns (`Card back`, Lh 2026-10-19). The article is the turning box (.flip, base.css) and only that;
|
|
146
69
|
each face is the card's paper — head · middle · foot — and both lie in one grid cell. The head and the foot are the same on both
|
|
@@ -162,10 +85,10 @@
|
|
|
162
85
|
position: relative;
|
|
163
86
|
}
|
|
164
87
|
.card__face > * { min-width: 0; }
|
|
165
|
-
.card__middle { flex: 1 0 auto; display:
|
|
88
|
+
.card__middle { flex: 1 0 auto; display: flex; flex-direction: column; gap: var(--card-gap); height: var(--card-middle-h, auto); overflow: hidden; } /* a flex column, not a grid: the middle's height is the flexed one, so one thing on a face (a QR, a code) may take the whole middle with height: 100% (a grid's auto row never stretched to it, and the thing stood at the top of an empty band) */
|
|
166
89
|
.card__turn { position: absolute; inset: 0; width: var(--px); height: var(--px); padding: 0; border: 0; overflow: hidden; clip-path: inset(50%); }
|
|
167
90
|
.card__face:has(> .card__turn:focus-visible) { outline: var(--focus); outline-offset: calc(-1 * var(--sp-1)); }
|
|
168
|
-
.
|
|
91
|
+
.head > .chip-row > .chip > .icon { --icon-display: inline-block; --icon-align: -0.15em; --icon-margin: 0 var(--chip-sm-gap, var(--sp-1)) 0 0; }
|
|
169
92
|
|
|
170
93
|
/* ---- bleed: a scrolling track that runs to the container's edges ----
|
|
171
94
|
For a horizontal strip inside a padded container — .avatar-pick, .chip-row,
|
|
@@ -205,19 +128,6 @@
|
|
|
205
128
|
is genuinely first or last needs the corner clipped for it */
|
|
206
129
|
.card:has(> :is(.bleed, .map--bleed):first-child), .card:has(> :is(.bleed, .map--bleed):last-child) { overflow: clip; }
|
|
207
130
|
|
|
208
|
-
/* foot: the card's action buttons on one line. One button takes the width,
|
|
209
|
-
up to four share it in even parts — so the gaps read even too — and from
|
|
210
|
-
three on they drop their side padding so the labels keep the room. */
|
|
211
|
-
.card__foot { display: flex; gap: var(--card-foot-gap, var(--sp-2)); align-items: center; color: var(--card-foot-ink, inherit); }
|
|
212
|
-
.card__foot:has(> :nth-child(3)) > .btn { --btn-pad-x: var(--sp-2); }
|
|
213
|
-
/* a small link under the buttons (CardFoot link — Lh 2026-09-23, as the ActionBar's ctaLink): the row wraps, the link takes a
|
|
214
|
-
whole short row of its own, centred — it never shares the buttons' line */
|
|
215
|
-
.card__foot--link { flex-wrap: wrap; align-content: end; row-gap: var(--card-foot-link-gap, var(--sp-1)); }
|
|
216
|
-
.card__foot-link { flex: 1 0 100%; display: flex; justify-content: center; }
|
|
217
|
-
/* round (CardFoot round): the foot holds a few round IconBtns, each its own size (they never share the line), as ONE group in the middle with
|
|
218
|
-
a gap that does not follow the card's width. The gap is wider than the Btns' (a miss between two round targets): --card-foot-gap sets it */
|
|
219
|
-
.card__foot--round { justify-content: center; gap: var(--card-foot-gap, var(--sp-6)); }
|
|
220
|
-
|
|
221
131
|
/* media placeholder for wireframes — currentColor so it survives any palette */
|
|
222
132
|
.ph {
|
|
223
133
|
background:
|
|
@@ -334,7 +244,6 @@
|
|
|
334
244
|
align-items: center;
|
|
335
245
|
gap: var(--card-row-gap, var(--sp-3));
|
|
336
246
|
}
|
|
337
|
-
.card--row .card__body { flex: 1; display: grid; gap: var(--sp-0); }
|
|
338
247
|
|
|
339
248
|
/* ---- a short window of past entries (`CardList show`, Lh 2026-10-19): the list scrolls IN ITSELF, a few rows in sight and the next one cut
|
|
340
249
|
in half to say there is more. The height is counted in rows by the component (`--_card-list-h`, px: rows wrap to any height); the room
|
|
@@ -351,7 +260,7 @@
|
|
|
351
260
|
}
|
|
352
261
|
|
|
353
262
|
/* ---- the cross that takes a row off the list (`Card row onRemove`): small, at the row's top right corner, inside it ----
|
|
354
|
-
<label class="card card--row"><input type="radio">…<
|
|
263
|
+
<label class="card card--row"><input type="radio">…<span class="words">…</span><button class="card__remove" aria-label="Remove"><svg class="icon">x</svg></button></label>
|
|
355
264
|
Smaller than any button (a ring half a thing's size, `--tap-base` / 2 = 24) and it grows with the size of things; the touch target is an
|
|
356
265
|
unseen ring round it, never under --tap-floor (44). It stands in the row's flow, so the title wraps before it, tucked into the corner
|
|
357
266
|
by the row's own padding; it sits over the row's radio (which covers the whole card), so a touch on it removes and never picks. */
|
|
@@ -379,21 +288,10 @@
|
|
|
379
288
|
.card__remove > .icon { --icon-size: 62%; }
|
|
380
289
|
.card__remove:focus-visible { outline: var(--focus); outline-offset: var(--sp-0); }
|
|
381
290
|
|
|
382
|
-
/* leading thumb/icon in a row */
|
|
383
|
-
.card__thumb {
|
|
384
|
-
width: var(--card-thumb-size, var(--tap-sm)); height: var(--card-thumb-size, var(--tap-sm));
|
|
385
|
-
flex: none;
|
|
386
|
-
border-radius: var(--card-thumb-radius, var(--r-control));
|
|
387
|
-
border: var(--border-w) solid currentColor;
|
|
388
|
-
display: grid;
|
|
389
|
-
place-items: center;
|
|
390
|
-
font: var(--card-thumb-font, var(--type-label));
|
|
391
|
-
}
|
|
392
|
-
|
|
393
291
|
/* ---- card feed: a queue of cards, all in sight — one big, the rest small (Lh 2026-10-09, the whole queue 2026-10-15) ----
|
|
394
292
|
<div class="card-feed">
|
|
395
|
-
<article class="card feed-card"><div class="
|
|
396
|
-
<div class="feed-card__more"><div class="feed-card__rest">content · <div class="
|
|
293
|
+
<article class="card feed-card"><div class="head">lead · h2 · caption</div>
|
|
294
|
+
<div class="feed-card__more"><div class="feed-card__rest">content · <div class="foot">…</div></div></div></article>
|
|
397
295
|
<article class="card feed-card feed-card--small" role="button" tabindex="0">… <div class="feed-card__more" inert>…</div></article>
|
|
398
296
|
<p class="t-caption card-feed__end" role="note">the end</p>
|
|
399
297
|
</div>
|
|
@@ -404,9 +302,7 @@
|
|
|
404
302
|
shut content in the scrollable overflow of whatever holds the feed — and hidden once the row has shut. */
|
|
405
303
|
.card-feed { display: grid; grid-template-columns: minmax(0, 1fr); align-content: start; gap: var(--card-feed-gap, var(--card-gap-rest)); }
|
|
406
304
|
.feed-card { row-gap: 0; }
|
|
407
|
-
.feed-
|
|
408
|
-
.feed-card__head:has(> :is(.card__thumb, .feed-card__lead)) { grid-template-columns: auto minmax(0, 1fr); }
|
|
409
|
-
.feed-card__head:has(> .t-caption) > :is(.card__thumb, .feed-card__lead) { grid-row: span 2; }
|
|
305
|
+
.feed-card > .head:has(> .t-caption) > .feed-card__lead { grid-row: span 2; }
|
|
410
306
|
.feed-card__lead { display: grid; align-self: center; } /* a Stamp here is the small one, 48 × 60 (stamp.css) */
|
|
411
307
|
.card-feed__end { text-align: center; }
|
|
412
308
|
.feed-card__more { display: grid; grid-template-columns: minmax(0, 1fr); grid-template-rows: 1fr; }
|
|
@@ -423,22 +319,6 @@
|
|
|
423
319
|
.feed-card--small .feed-card__rest { transition: visibility 0s var(--motion-sheet); }
|
|
424
320
|
}
|
|
425
321
|
|
|
426
|
-
/* ---- inline stat block (revenue-style) ---- */
|
|
427
|
-
.stat { display: grid; gap: var(--stat-gap, var(--sp-1)); }
|
|
428
|
-
.stat--centre { text-align: center; justify-items: center; } /* the one number of a sheet or a stage, under a centred avatar */
|
|
429
|
-
.stat__row { display: flex; align-items: center; justify-content: space-between; gap: var(--stat-row-gap, var(--sp-3)); }
|
|
430
|
-
|
|
431
|
-
.delta {
|
|
432
|
-
font: var(--delta-font, var(--type-caption));
|
|
433
|
-
font-weight: var(--fw-bold);
|
|
434
|
-
padding: var(--delta-pad-y, var(--sp-1)) var(--delta-pad-x, var(--sp-2));
|
|
435
|
-
border-radius: var(--delta-radius, var(--r-chip));
|
|
436
|
-
background: var(--delta-bg, var(--card-3-bg));
|
|
437
|
-
--dark: var(--card-3-dark);
|
|
438
|
-
color: var(--delta-ink, var(--card-ink));
|
|
439
|
-
}
|
|
440
|
-
.delta--neg { background: var(--delta-neg-bg, var(--neg)); --dark: var(--neg-dark); color: var(--delta-neg-ink, var(--card-ink)); }
|
|
441
|
-
|
|
442
322
|
/* ---- panes: a few panes side by side inside a card or a sheet, one in sight (Lh 2026-10-02) ----
|
|
443
323
|
<div class="panes" role="group"><div class="panes__rail"><div class="panes__pane">…</div>…</div><span class="pager__at">…</span></div>
|
|
444
324
|
The rail runs to the card's edges and snaps a pane at a time; each pane takes the inset back, so its content stands on the
|
|
@@ -462,7 +342,7 @@
|
|
|
462
342
|
|
|
463
343
|
/* ---- cover: the image IS the card; text over a scrim ----
|
|
464
344
|
<article class="card card--cover"><div class="ph" role="img"></div>
|
|
465
|
-
<div class="
|
|
345
|
+
<div class="head"><button class="icon-btn icon-btn--sm">♥</button></div>
|
|
466
346
|
<div><h2 class="t-h1">Art Institute</h2><p class="t-body">111 South Michigan Ave</p></div>
|
|
467
347
|
<div class="row">…meta…</div></article> */
|
|
468
348
|
.card--cover {
|
|
@@ -552,14 +432,6 @@
|
|
|
552
432
|
.sheet-stack > .card:nth-child(3) { margin-top: calc(2 * var(--stack-step)); }
|
|
553
433
|
.sheet-stack > .card:nth-child(4) { margin-top: calc(3 * var(--stack-step)); }
|
|
554
434
|
.sheet-stack > .card:nth-child(5) { margin-top: calc(4 * var(--stack-step)); }
|
|
555
|
-
/* stack headers: uniform — [back?] title left, icons right, one height,
|
|
556
|
-
same gap to content on every card */
|
|
557
|
-
.sheet-stack > .card > .card__head {
|
|
558
|
-
align-items: center;
|
|
559
|
-
justify-content: flex-start;
|
|
560
|
-
min-height: var(--tap);
|
|
561
|
-
}
|
|
562
|
-
.sheet-stack--display > .card > .card__head { align-items: start; min-height: 0; }
|
|
563
435
|
/* ============================================================
|
|
564
436
|
.sheet-stack--tap — tap a peeked sheet open; a back button returns it.
|
|
565
437
|
|
|
@@ -612,8 +484,7 @@
|
|
|
612
484
|
overscroll-behavior: contain;
|
|
613
485
|
}
|
|
614
486
|
.sheet-stack--tap > .card.is-open.is-dragging { transition: none; }
|
|
615
|
-
.sheet-stack--tap > .card
|
|
616
|
-
.sheet-stack--tap > .card.is-open:not(:has(> .sheet__body)) {
|
|
487
|
+
.sheet-stack--tap > .card.is-open:not(:has(> .body)) {
|
|
617
488
|
padding-top: calc(var(--card-pad) + var(--_refresh, 0rem));
|
|
618
489
|
transition: translate var(--motion-sheet) var(--ease), padding-top var(--motion-sheet) var(--ease);
|
|
619
490
|
}
|
|
@@ -649,56 +520,18 @@
|
|
|
649
520
|
only, the sheet's size is untouched. A pull on the head keeps them square until the finger lets go. */
|
|
650
521
|
.sheet-stack--flood > .card { transition: translate var(--motion-sheet) var(--ease), border-radius var(--motion-sheet) var(--ease); }
|
|
651
522
|
.sheet-stack--flood > .card.is-open { border-top-left-radius: 0; border-top-right-radius: 0; }
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
transition: padding-left var(--motion-sheet) var(--ease);
|
|
656
|
-
}
|
|
657
|
-
/* ---- a stacked sheet with a SheetBody has the ONE sheet shape (Lh 2026-09-23, the home layout): sheet head
|
|
658
|
-
pinned at the top · sheet body scrolls, as long as it needs · sheet foot (a CardFoot, the CTA) at the bottom.
|
|
659
|
-
The card becomes a flex column and stops scrolling itself — only the body does. A sheet with no SheetBody
|
|
523
|
+
/* ---- a stacked sheet with a Body has the ONE sheet shape (Lh 2026-09-23, the home layout): sheet head
|
|
524
|
+
pinned at the top · sheet body scrolls, as long as it needs · sheet foot (a Foot, the CTA) at the bottom.
|
|
525
|
+
The card becomes a flex column and stops scrolling itself — only the body does. A sheet with no Body
|
|
660
526
|
keeps the old way: the whole open card scrolls. ---- */
|
|
661
|
-
.sheet-stack--tap > .card:has(> .
|
|
662
|
-
.sheet-stack--tap > .card:has(> .
|
|
663
|
-
/* a paper stack's foot is paper to the card's edges, and it covers the tinted flex gap above it so the
|
|
664
|
-
button does not sit on a colour stripe. The head's gap stays: it is outside this foot. The button stays
|
|
665
|
-
where it was — the padding gives back what the bleed takes. */
|
|
666
|
-
.sheet-stack > .card.sheet--paper > .card__foot {
|
|
667
|
-
background: var(--action-bg);
|
|
668
|
-
color: var(--card-ink);
|
|
669
|
-
margin-top: calc(-1 * var(--card-gap));
|
|
670
|
-
margin-inline: calc(-1 * var(--card-pad));
|
|
671
|
-
margin-bottom: calc(-1 * var(--card-pad));
|
|
672
|
-
padding-top: var(--card-gap);
|
|
673
|
-
padding-inline: var(--card-pad);
|
|
674
|
-
padding-bottom: var(--card-pad);
|
|
675
|
-
}
|
|
676
|
-
.stack-sheet > .card__head { flex-wrap: nowrap; }
|
|
527
|
+
.sheet-stack--tap > .card:has(> .body) { display: flex; flex-direction: column; gap: var(--card-gap); }
|
|
528
|
+
.sheet-stack--tap > .card:has(> .body).is-open { overflow: clip; }
|
|
677
529
|
/* ---- the back button, SMALL (Lh 2026-09-23: "give the sheet head more room" — and then "a glyph alone does not read as
|
|
678
530
|
tappable"): a SMALL DISC — its ring kept, 32px instead of 44, the chevron in it at 20 — so the head gives it 32px + a gap
|
|
679
531
|
(was 56px). Its tap target stays 44px: an invisible ::after around the disc. ---- */
|
|
680
|
-
.sheet-stack--tap > .card.is-open > .card__head:has(> .sheet-stack__back:not(.sheet-stack__back--end)) { padding-left: var(--stack-back-room, calc(var(--_back-size) + var(--sp-2))); }
|
|
681
|
-
:is(.sheet-stack--tap > .card, .sheet-stack--tap > :not(.card, .sheet-stack__base) > .card) > .card__head:has(> .sheet-stack__back--end) { transition: padding-right var(--motion-sheet) var(--ease); }
|
|
682
|
-
.sheet-stack--tap > .card.is-open > .card__head:has(> .sheet-stack__back--end) { padding-right: var(--stack-back-room, calc(var(--_back-size) + var(--sp-2))); }
|
|
683
532
|
/* a stacked sheet is a control until it is open — tapped, never read into: no text selection (a drag, a double tap, a long press),
|
|
684
533
|
no grey flash, no iOS callout; its head stays one when open. Only the OPEN sheet's body is text to select (Lh 2026-09-23) */
|
|
685
|
-
.sheet-stack--tap > .card
|
|
686
|
-
/* ---- where it sits in what sheet.css draws (docs/reference.md rule 15) ---- */
|
|
687
|
-
.sheet > .card__foot {
|
|
688
|
-
position: absolute; inset: calc(-1 * var(--border-w)) 0 0; z-index: var(--z-over); /* the sheet's border box: the same height the sheet's own % reads */
|
|
689
|
-
align-items: end;
|
|
690
|
-
align-content: end;
|
|
691
|
-
padding: 0 var(--card-pad) calc(var(--card-pad) + var(--_safe-b-open));
|
|
692
|
-
background: linear-gradient(var(--card-bg), var(--card-bg)) bottom / 100% var(--_foot) no-repeat;
|
|
693
|
-
pointer-events: none;
|
|
694
|
-
translate: 0 calc(-1 * var(--_y) - var(--_drag, 0rem));
|
|
695
|
-
transition: translate var(--motion-sheet) var(--ease), visibility 0s;
|
|
696
|
-
}
|
|
697
|
-
.sheet.is-dragging > .card__foot { transition: none; }
|
|
698
|
-
/* at peek and away the foot is NOT held on the box's edge: it stands on the sheet's own bottom edge (no counter-slide), so it
|
|
699
|
-
LEAVES AND ARRIVES WITH ITS SHEET — solid the whole way, hidden only once the slide is over. It used to stay in place and
|
|
700
|
-
fade: the body slid through the strip behind a half-transparent button (timebank, Lh 2026-10-01: "ตัวหนังสือลอดใต้ปุ่ม"). */
|
|
701
|
-
:is(.sheet--peek, .sheet--away) > .card__foot { translate: 0 0; visibility: hidden; transition: translate var(--motion-sheet) var(--ease), visibility 0s var(--ease-linear) var(--motion-sheet); }
|
|
534
|
+
.sheet-stack--tap > .card { -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; }
|
|
702
535
|
/* ---- where it sits in what step.css draws (docs/reference.md rule 15) ---- */
|
|
703
536
|
/* a WALK (Pages of Page) — Lh 2026-09-23, third call: no top; the picture and the words are ONE run that scrolls up together
|
|
704
537
|
(the picture is never pinned). Each page starts at the screen's lead and ends with the same room under it — the lead as
|
|
@@ -727,7 +560,7 @@
|
|
|
727
560
|
.postcard__front .postcard__turn > .ph { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; border: 0; border-radius: 0; min-height: 0; }
|
|
728
561
|
|
|
729
562
|
/* ---- where it sits in what stack.css draws: a sheet pulled to refresh holds still (docs/reference.md rule 15) ---- */
|
|
730
|
-
.sheet-stack--tap > .card.is-open.is-refreshing:not(:has(> .
|
|
563
|
+
.sheet-stack--tap > .card.is-open.is-refreshing:not(:has(> .body)) { transition: none; }
|
|
731
564
|
|
|
732
565
|
/* ---- where it sits in what step.css draws: the reading block, a walk of pages (docs/reference.md rule 15) ---- */
|
|
733
566
|
.step:has(> .sheet--peek) > .pages { padding-bottom: var(--sheet-peek); }
|
package/css/choice.css
CHANGED
|
@@ -119,7 +119,7 @@
|
|
|
119
119
|
<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> */
|
|
120
120
|
.calendar { display: grid; gap: var(--calendar-gap, var(--sp-3)); }
|
|
121
121
|
.calendar__head { display: flex; align-items: center; justify-content: space-between; gap: var(--calendar-head-gap, var(--sp-2)); }
|
|
122
|
-
.calendar__grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: var(--calendar-grid-gap, var(--sp-1)); justify-items: center; }
|
|
122
|
+
.calendar__grid { display: grid; grid-template-columns: repeat(var(--_cols, 7), 1fr); gap: var(--calendar-grid-gap, var(--sp-1)); justify-items: center; container-type: inline-size; } /* a container: the span band below is measured in its width */
|
|
123
123
|
.calendar__wd { font: var(--calendar-wd-font, var(--type-caption)); color: var(--calendar-wd-ink, var(--card-muted)); padding-block: var(--calendar-wd-pad-y, var(--sp-2)); }
|
|
124
124
|
.calendar__day {
|
|
125
125
|
width: 100%;
|
|
@@ -140,6 +140,31 @@
|
|
|
140
140
|
.calendar__day:disabled { opacity: var(--fade-dim); }
|
|
141
141
|
.calendar__day[aria-current="date"] { text-decoration: underline; text-underline-offset: 0.2em; }
|
|
142
142
|
|
|
143
|
+
/* ---- span: a run of cells covered by one drag or two taps (Calendar, CalendarWeeks, HourGrid; src/choice/span.ts is the mechanic). The whole
|
|
144
|
+
run is ONE highlight, as a finger drags over words (Lh 2026-10-21: no picked first or last day, the same colour throughout): each covered
|
|
145
|
+
cell's own ::before is a slice of the band, a column and a gap wide between so the slices meet across the grid's gaps, the slice at an end
|
|
146
|
+
stops at its column's edge with the pill's corner; a one-cell run is a pill the column wide. The cells keep their ink. A grid that is a
|
|
147
|
+
span takes the touch (no scroll starts on it); the weeks' box keeps its vertical scroll, so there a drag covers a row and two taps cover across rows */
|
|
148
|
+
.calendar--span .calendar__grid { touch-action: none; -webkit-user-select: none; user-select: none; }
|
|
149
|
+
.calendar--weeks.calendar--span .calendar__grid { touch-action: pan-y; }
|
|
150
|
+
.calendar__grid { --_col: calc((100cqw - (var(--_cols, 7) - 1) * var(--calendar-grid-gap, var(--sp-1))) / var(--_cols, 7)); --_span-w: calc(var(--_col) + var(--calendar-grid-gap, var(--sp-1))); }
|
|
151
|
+
:is(.calendar__day--span-start, .calendar__day--span-in, .calendar__day--span-end, .calendar__day--span-one) { position: relative; isolation: isolate; }
|
|
152
|
+
.calendar__day--span-start::before, .calendar__day--span-in::before, .calendar__day--span-end::before, .calendar__day--span-one::before { /* flat, not :is(): the knob walk reads each alternative's element */
|
|
153
|
+
content: "";
|
|
154
|
+
position: absolute;
|
|
155
|
+
inset-block: 0;
|
|
156
|
+
inset-inline-start: calc(50% - var(--_span-w) / 2);
|
|
157
|
+
width: var(--_span-w);
|
|
158
|
+
z-index: var(--z-under);
|
|
159
|
+
background: var(--calendar-span-bg, color-mix(in srgb, var(--accent) 25%, transparent));
|
|
160
|
+
}
|
|
161
|
+
.calendar__day--span-start::before { inset-inline-start: calc(50% - var(--_col) / 2); width: calc(var(--_span-w) - var(--calendar-grid-gap, var(--sp-1)) / 2); border-start-start-radius: var(--r-chip); border-end-start-radius: var(--r-chip); }
|
|
162
|
+
.calendar__day--span-end::before { width: calc(var(--_span-w) - var(--calendar-grid-gap, var(--sp-1)) / 2); border-start-end-radius: var(--r-chip); border-end-end-radius: var(--r-chip); }
|
|
163
|
+
.calendar__day--span-one::before { inset-inline-start: calc(50% - var(--_col) / 2); width: var(--_col); border-radius: var(--r-chip); }
|
|
164
|
+
/* ---- hour grid: the hours of a day in Calendar's cells, `--hour-grid-cols` to a row, a label over them
|
|
165
|
+
<div class="calendar hour-grid"><span class="calendar__label">น.</span><div class="calendar__grid"><button class="calendar__day">9</button>…</div></div> */
|
|
166
|
+
.hour-grid > .calendar__grid { --_cols: var(--hour-grid-cols, 6); }
|
|
167
|
+
|
|
143
168
|
/* ---- calendar weeks: a run of week rows that scrolls week by week, `show` rows in sight; the head sticks at the top of the box
|
|
144
169
|
<div class="calendar calendar--weeks"><div class="calendar__weeks-head"><span class="calendar__label">June 2026</span><div class="calendar__grid">…wd×7</div></div>
|
|
145
170
|
<div class="calendar__grid calendar__week"><button class="calendar__day">…</button>×7</div>…</div>
|
package/css/finish.css
CHANGED
|
@@ -82,7 +82,7 @@
|
|
|
82
82
|
0 0.5rem 1rem -0.25rem color-mix(in srgb, var(--accent) 45%, transparent);
|
|
83
83
|
}
|
|
84
84
|
/* a peeked stack tab is the icon alone: no sheen and no shadow until its sheet is open (the fill fades with the sheet) */
|
|
85
|
-
[data-finish="lit"] .sheet-stack--tap > .card:not(.is-open) > .
|
|
85
|
+
[data-finish="lit"] .sheet-stack--tap > .card:not(.is-open) > .head .stack-sheet__tab {
|
|
86
86
|
background-image: none;
|
|
87
87
|
box-shadow: none;
|
|
88
88
|
}
|
|
@@ -121,7 +121,7 @@
|
|
|
121
121
|
}
|
|
122
122
|
/* a dark card (the brand tone, a cover): multiply would only blacken it, so the grain lightens, fainter */
|
|
123
123
|
[data-finish="print"] :is(.card--3, .card--cover)::after { mix-blend-mode: screen; opacity: calc(var(--print-grain, 0.32) * 0.56); }
|
|
124
|
-
[data-finish="print"] .card:not(.card--row, .card--cover, .feed-card--small, .sheet-stack > *, .sheet-stack > :not(.sheet-stack__base) > *) > .
|
|
124
|
+
[data-finish="print"] .card:not(.card--row, .card--cover, .feed-card--small, .sheet-stack > *, .sheet-stack > :not(.sheet-stack__base) > *) > .head {
|
|
125
125
|
padding-bottom: var(--sp-2);
|
|
126
126
|
border-bottom: var(--rule-w) dotted color-mix(in srgb, currentColor 45%, transparent);
|
|
127
127
|
}
|
|
@@ -132,7 +132,7 @@
|
|
|
132
132
|
[data-finish="print"] .chip { border-color: var(--chip-border, var(--_ink)); } /* a holder that clears a chip's edge (a note's chips) clears it in print too */
|
|
133
133
|
[data-finish="print"] .btn--primary { box-shadow: 0.125rem 0.125rem 0 0 color-mix(in srgb, var(--card-ink) 60%, transparent); }
|
|
134
134
|
[data-finish="print"] :is(.btn, .chip):active { box-shadow: none; translate: 0.125rem 0.125rem; }
|
|
135
|
-
[data-finish="print"] .
|
|
135
|
+
[data-finish="print"] .card--row > .lead { border-style: dashed; }
|
|
136
136
|
|
|
137
137
|
/* ============================================================
|
|
138
138
|
sticker — a die-cut sticker on a sheet: --sticker-cut of white paper left round the print, a short hard
|
|
@@ -167,4 +167,4 @@
|
|
|
167
167
|
[data-finish="ink"] :is(.btn, .chip, .icon-btn:not(.icon-btn-group > *)) { border: var(--ink-w, 0.15625rem) solid currentColor; box-shadow: 0.1875rem 0.1875rem 0 0 currentColor; }
|
|
168
168
|
[data-finish="ink"] .btn--primary { border-color: var(--on-surface); box-shadow: 0.1875rem 0.1875rem 0 0 var(--on-surface); }
|
|
169
169
|
[data-finish="ink"] .toggle { box-shadow: 0.125rem 0.125rem 0 0 var(--on-surface); }
|
|
170
|
-
[data-finish="ink"] .
|
|
170
|
+
[data-finish="ink"] .card--row > .lead { border-width: var(--ink-w, 0.15625rem); }
|
package/css/journey.css
CHANGED
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
align-self: stretch;
|
|
59
59
|
max-block-size: calc((2 * var(--fs-caption) + var(--fs-lg)) * var(--tile-badge-line, var(--lh-badge)) + 2 * var(--sp-3));
|
|
60
60
|
container-type: size;
|
|
61
|
-
inline-size: calc(var(--fs-lg) * 3.25);
|
|
61
|
+
inline-size: var(--tile-badge-stretch-w, calc(var(--fs-lg) * 3.25)); /* a run of days ("18–21") needs more: the app sets the knob on that badge */
|
|
62
62
|
grid-template-columns: auto auto;
|
|
63
63
|
align-content: center;
|
|
64
64
|
justify-content: center;
|
|
@@ -67,17 +67,21 @@
|
|
|
67
67
|
row-gap: 0;
|
|
68
68
|
padding-block: var(--sp-3);
|
|
69
69
|
}
|
|
70
|
-
.tile-badge--stretch > * { line-height: inherit; }
|
|
70
|
+
.tile-badge--stretch > * { line-height: inherit; white-space: nowrap; } /* a value never breaks at its dash */
|
|
71
71
|
.tile-badge--stretch > :first-child { grid-column: 1 / -1; }
|
|
72
72
|
@container (min-height: 3.5rem) { /* just under the three lines' own height, the most the badge grows to */
|
|
73
73
|
.tile-badge--stretch > * { grid-column: 1 / -1; }
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
/* where it sits in a head that leads with the date (card.css): the first cell, as tall as the chips beside it however many rows, so no cap */
|
|
77
|
-
.
|
|
77
|
+
.head:has(> .tile-badge:first-child + .chip-row) > .tile-badge--stretch:first-child { grid-column: 1; grid-row: 1; max-block-size: none; }
|
|
78
78
|
|
|
79
79
|
/* corner badge: pin a tile badge on media (rating, price) — .card__media is relative */
|
|
80
80
|
.tile-badge--corner { position: absolute; right: var(--sp-3); bottom: var(--sp-3); }
|
|
81
|
+
/* on a CardMedia (ruled Lh 2026-10-21, three screenshots side by side): the card's paper, its corner concentric with the media's — the media's
|
|
82
|
+
corner less the inset above. Not the theme's highlight: the distance on a request card is information, and a highlight fill reads as a
|
|
83
|
+
control. Both knobs still win (palette.css leaves this badge out of orchard's highlight rule for the same reason) */
|
|
84
|
+
.card__media > .tile-badge--corner { --_badge-radius: calc(var(--r-media) - var(--sp-3)); background: var(--tile-badge-bg, var(--card-1-bg)); --dark: var(--card-1-dark); }
|
|
81
85
|
|
|
82
86
|
/* ---- note row: icon + caption (transit hints, fine print) ---- */
|
|
83
87
|
.note-row {
|
package/css/layover.css
CHANGED
|
@@ -8,14 +8,14 @@
|
|
|
8
8
|
/* ---- the Modal — the case drops in, its drawer opens below (Lh 2026-09-16: ONE card, two parts)
|
|
9
9
|
<div class="sheet-stage sheet-stage--dim"> (dim = the page under a scrim; a Modal on a clean ground is the stage without it — Lh 2026-09-22, `--ask` retired: the stage does the ground, the modal centres itself)
|
|
10
10
|
<article class="card modal">
|
|
11
|
-
<div class="
|
|
11
|
+
<div class="body">…the card's content (a head, rows, a timeline)…</div>
|
|
12
12
|
<div class="modal__drawer"><h2 class="t-h2">Take the case?</h2><p class="t-caption">This cannot be undone.</p>
|
|
13
13
|
<div class="btn-trio">…</div>
|
|
14
14
|
</div>
|
|
15
15
|
</article>
|
|
16
16
|
</div>
|
|
17
17
|
.modal is the card — no border (the shadow is its edge on the scrim);
|
|
18
|
-
.
|
|
18
|
+
.body the light part that holds the thing being asked about (it
|
|
19
19
|
scrolls when tall); .modal__drawer the dark end that asks. The ground is
|
|
20
20
|
whatever the stage shows (dim it or not). Two beats (2 × --motion-sheet) when
|
|
21
21
|
the stage appears, and the same two backwards when it closes:
|
|
@@ -47,16 +47,6 @@
|
|
|
47
47
|
overflow: clip;
|
|
48
48
|
box-shadow: var(--modal-shadow, var(--shadow-sheet));
|
|
49
49
|
}
|
|
50
|
-
.modal__lift {
|
|
51
|
-
padding: var(--card-pad);
|
|
52
|
-
display: grid;
|
|
53
|
-
gap: var(--card-gap);
|
|
54
|
-
align-content: start;
|
|
55
|
-
flex: 0 1 auto;
|
|
56
|
-
min-height: 0;
|
|
57
|
-
overflow-y: auto; /* tall content scrolls inside; the drawer stays */
|
|
58
|
-
overscroll-behavior: contain;
|
|
59
|
-
}
|
|
60
50
|
.modal__drawer {
|
|
61
51
|
flex-shrink: 0;
|
|
62
52
|
height: var(--drawer-h);
|
|
@@ -81,8 +71,8 @@
|
|
|
81
71
|
--accent: var(--card-ink);
|
|
82
72
|
--accent-dark: calc(1 - var(--dark));
|
|
83
73
|
}
|
|
84
|
-
/* the CONFIRM: a Modal with no
|
|
85
|
-
.modal:not(:has(> .
|
|
74
|
+
/* the CONFIRM: a Modal with no Body: the ModalAsk IS the card, as tall as its words (no fixed band, no second beat) */
|
|
75
|
+
.modal:not(:has(> .body)) > .modal__drawer { height: auto; padding-block: var(--modal-confirm-pad-y, var(--sp-6)); animation: none; }
|
|
86
76
|
.modal__drawer .t-caption { --t-caption-ink: var(--modal-drawer-caption-ink, var(--card-muted)); }
|
|
87
77
|
.modal__drawer > h2:focus { outline: none; } /* the question takes the cursor when the modal arrives (for a screen reader, the keyboard's way in) — it is not a control: no ring */
|
|
88
78
|
/* the answers as WORD buttons (a BtnRow of Btns; Lh 2026-10-11): the row fills the ask with room over it and each button keeps its words on one
|
package/css/lists.css
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/* ============================================================
|
|
2
2
|
cardds/lists.css — frameless rows and pairs INSIDE a card:
|
|
3
|
-
row (lead ·
|
|
4
|
-
timeline · legend · link
|
|
3
|
+
row (its parts, lead · words · end, are parts.css) · key-value
|
|
4
|
+
rows · kv grid · timeline · legend · link
|
|
5
5
|
A row inside a card has no boundary of its own; .rows draws
|
|
6
6
|
hairlines between rows. A row that IS a card = .card--row.
|
|
7
7
|
============================================================ */
|
|
8
8
|
|
|
9
9
|
/* ---- row: leading visual · title + meta · trailing control ----
|
|
10
|
-
<div class="row"><span class="avatar">A</span><
|
|
10
|
+
<div class="row"><span class="avatar">A</span><span class="words"><span class="words__title">Alice Kau</span><span class="words__meta">Owner</span></span><button class="icon-btn icon-btn--sm">›</button></div> */
|
|
11
11
|
.row {
|
|
12
12
|
display: flex;
|
|
13
13
|
align-items: center;
|
|
@@ -20,21 +20,7 @@
|
|
|
20
20
|
/* no padding on a row (Lh 2026-09-16): padding is for room, not for spreading.
|
|
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
|
-
.row__lead {
|
|
24
|
-
width: var(--row-lead-size, var(--tap));
|
|
25
|
-
height: var(--row-lead-size, var(--tap));
|
|
26
|
-
flex: none;
|
|
27
|
-
border-radius: var(--row-lead-radius, var(--r-control));
|
|
28
|
-
border: var(--border-w) solid var(--row-lead-border, var(--outline));
|
|
29
|
-
display: grid;
|
|
30
|
-
place-items: center;
|
|
31
|
-
}
|
|
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
|
-
.row__end { margin-left: auto; text-align: right; display: grid; gap: var(--row-end-gap, var(--sp-0)); justify-items: end; flex: none; }
|
|
36
23
|
.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 */
|
|
37
|
-
.row--lg .row__title { font: var(--fw-bold) var(--fs-lg) / var(--lh-h1) var(--font-display); }
|
|
38
24
|
/* a row that EXPANDS (Lh 2026-09-22): the row is a <details>' summary, what it shows comes out under it —
|
|
39
25
|
who liked a postcard, the rest of a list. An end chevron turns when open. The app owns the list.
|
|
40
26
|
<details class="row-expand"><summary class="row">…lead · body · end…</summary><div class="row-expand__more">…</div></details> */
|
|
@@ -49,7 +35,6 @@
|
|
|
49
35
|
pointer-events off here, aria-disabled from the markup. The tick is the .check's checked look
|
|
50
36
|
at --tap-sm, but not an input: nothing to press. */
|
|
51
37
|
.row--done { pointer-events: none; cursor: default; }
|
|
52
|
-
.row--done .row__title { color: var(--card-muted); }
|
|
53
38
|
.row__done {
|
|
54
39
|
width: var(--row-done-size, var(--tap-sm));
|
|
55
40
|
height: var(--row-done-size, var(--tap-sm));
|
|
@@ -90,6 +75,9 @@
|
|
|
90
75
|
<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> */
|
|
91
76
|
.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)); }
|
|
92
77
|
.kv-grid > .kv-cell + .kv-cell { border-left: var(--border-w) solid var(--hairline); padding-left: var(--sp-4); }
|
|
78
|
+
/* `centre` (Lh 2026-10-21, the code on timebank's request card, as `Stat centre` and `Head centre` were): the grid is as tall as its holder, its cells stand in the middle of it, each value and caption centred */
|
|
79
|
+
.kv-grid--centre { min-height: 100%; align-content: center; text-align: center; } /* min-height, not height: in a plain card (a grid of auto rows) a percent height resolved 8px short and the cell overflowed it; a percent min-height is nothing there, and the holder's height on a turning card's face */
|
|
80
|
+
.kv-grid--centre > .kv-cell { justify-items: center; }
|
|
93
81
|
.kv-cell { display: grid; gap: var(--kv-cell-gap, var(--sp-0)); align-content: start; min-width: 0; }
|
|
94
82
|
.kv-cell > .icon { --icon-margin: 0 0 var(--sp-1); }
|
|
95
83
|
.kv-cell__val { font: var(--kv-cell-val-font, var(--type-h2)); letter-spacing: var(--track-h2); font-variant-numeric: tabular-nums; }
|
package/css/media.css
CHANGED
|
@@ -43,17 +43,11 @@
|
|
|
43
43
|
position: relative;
|
|
44
44
|
}
|
|
45
45
|
.tile__label { font: var(--tile-label-font, var(--type-title)); }
|
|
46
|
-
.tile__value { font: var(--tile-value-font, var(--type-h2)); letter-spacing: var(--track-h2); font-variant-numeric: tabular-nums; }
|
|
47
46
|
.tile__sub { font: var(--tile-sub-font, var(--type-caption)); color: var(--tile-sub-ink, var(--card-muted)); } /* the muted words of the tile's ground; --dim faded the full ink to 2.4–3.4:1 */
|
|
48
47
|
.tile__text { display: grid; gap: var(--tile-text-gap, var(--sp-0)); }
|
|
49
48
|
.tile--on { background: var(--tile-on-bg, var(--accent)); --dark: var(--accent-dark); color: var(--tile-on-ink, var(--card-ink)); border-color: transparent; }
|
|
50
49
|
/* .tile--pick's hidden input and :has(:checked) fill are declared once in choice.css, alongside .chip--pick and .mood__opt */
|
|
51
50
|
.tile--wide { grid-column: 1 / -1; }
|
|
52
|
-
/* stat: READ, not pressed — no frame of its own inside a card (a frame says "tap me"): icon · value · words on the card's ground */
|
|
53
|
-
/* a stat tile has no fill of its own, so it has no ink of its own: it takes the ink of what it stands on (currentColor on `color`
|
|
54
|
-
= the inherited colour), as the card's heading does. It kept the plain tile's --action-ink, dark on a dark card (timebank, tone 3,
|
|
55
|
-
Lh 2026-10-18). --tile-ink still overrides; a toned stat tile (.tile--N, below) takes its fill and its ink back */
|
|
56
|
-
.tile--stat { --dark: inherit; color: var(--tile-ink, currentColor); border-color: transparent; background: none; padding-inline: 0; 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; }
|
|
57
51
|
/* upload: dashed, centred plus + label */
|
|
58
52
|
.tile--upload {
|
|
59
53
|
border-style: dashed;
|
|
@@ -72,7 +66,7 @@
|
|
|
72
66
|
.tile--3 { background: var(--tile-3-bg, var(--card-3-bg)); --dark: var(--card-3-dark); color: var(--tile-3-ink, var(--card-ink)); border-color: transparent; }
|
|
73
67
|
|
|
74
68
|
/* ---- wave: audio waveform stand-in for voice rows ----
|
|
75
|
-
<span class="wave"></span> — sits in a .
|
|
69
|
+
<span class="wave"></span> — sits in a .words, fills the width */
|
|
76
70
|
.wave {
|
|
77
71
|
/* only WHOLE bars show (Lh 2026-09-23 — a clipped last bar read thinner): the columns are as many whole bar-widths as fit
|
|
78
72
|
(auto-fill), spread edge to edge; bars that do not fit go to rows of no height, clipped away */
|
package/css/palette.css
CHANGED
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
/* where the highlights land — written as the component's own rule, its knob still first, so a project's knob wins (a palette never DECLARES a
|
|
93
93
|
knob). Each fill says its side; the words on it follow */
|
|
94
94
|
[data-palette="orchard"] .badge:not(.badge--soft) { background: var(--badge-bg, var(--highlight-1)); color: var(--badge-ink, var(--ink-ondark)); }
|
|
95
|
-
[data-palette="orchard"] .tile-badge:not(.tile-badge--plain) { background: var(--tile-badge-bg, var(--highlight-2)); --dark: 0; }
|
|
95
|
+
[data-palette="orchard"] .tile-badge:not(.tile-badge--plain, .card__media > .tile-badge--corner) { background: var(--tile-badge-bg, var(--highlight-2)); --dark: 0; } /* a badge on a media stays the paper (journey.css) */
|
|
96
96
|
[data-palette="orchard"] .calendar__day--mark { background: var(--calendar-day-mark-bg, color-mix(in srgb, var(--highlight-2) 15%, transparent)); }
|
|
97
97
|
/* fields are WHITE boxes on every ground (Lh 2026-09-25): a light ground, so the words typed in them are onlight, even on the moss card */
|
|
98
98
|
[data-palette="orchard"] .field { background: var(--field-bg, #ffffff); color: var(--ink-onlight); }
|