@usableapp/cardds 0.7.83 → 0.7.84

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 CHANGED
@@ -2,6 +2,24 @@
2
2
 
3
3
  > For: a project that consumes `@usableapp/cardds` and its AI — what changed between versions, written as before → after, so a screen can be brought up to date without reading the source. Newest first. A consumer never edits cardds; if something here leaves you without a way to do what you did before, report the gap.
4
4
 
5
+ ## 0.7.84 — 2026-10-11
6
+
7
+ ### Changed — breaking for a screen that draws a `Stamp`
8
+ - **A stamp is one of two sizes, wherever it stands** (Lh 2026-10-11) — the standard size, `--stamp-size`, and the small size, `--stamp-sm-size`, for a stamp in a `StampOn` and in an `AvatarStack`. The stamp at a postcard's corner is neither: it keeps its own size, 72 × 90 (`--post-corner-stamp-w`), as before. Before → after for the standard size: a `Stamp` or a `StampPlace` filled its column up to a cap, so its size came from what held it → it is `--stamp-size` wide (two taps: 96 × 120; 90 × 112.5 on a screen 360 wide) in every holder, and the holder only places it. A holder narrower than a stamp shrinks it. Every screen that draws a stamp changes look. Measured at 375, before → after: in a `Centre` on a fill screen 192.08 × 240.09 → 96 × 120; in a sheet body or on a page 216 × 270 → 96 × 120; in a `Centre` inside a sheet body 210 × 262.5 → 96 × 120; in a `StampBook` on its ground 95.66 × 119.56 → 96 × 120; in a `StampBook bare` 109 × 136.25 → 96 × 120; in a `StampBook strip` 72 × 90 → 96 × 120; in a card's head 96 × 120, unchanged. To bring a screen up to date: look at each stamp screen again. For a larger or smaller stamp set `--stamp-size`, on `:root` for every stamp or on an element for the stamps inside it.
9
+ - **Nine knobs are gone**: `--stamp-max-w`, `--stamp-centre-max-w`, `--card-head-stamp-w`, `--stamp-book-bare-gap`, `--stamp-book-strip-w`, `--stamp-on-w`, `--sticky-stamp-w`, `--avatar-stack-stamp-w`, `--post-desk-pick-w`. Setting one now does nothing. Use `--stamp-size` for a standing stamp (the first five, and `--post-desk-pick-w`) and `--stamp-sm-size` for a stamp in a `StampOn` or an `AvatarStack` (`--sticky-stamp-w`, `--stamp-on-w`, `--avatar-stack-stamp-w`). There is no knob per place: set `--stamp-size` on the element that holds the stamps to move only those.
10
+ - **`StampBook bare` no longer makes its stamps fill their thirds** — before → after: no ground, the stamp's cap lifted, each stamp the whole width of its third (109 × 136.25 at 375) → no ground, no padding, no round, and nothing else: each stamp is its own size in the middle of its third, with the same gaps as on the ground.
11
+ - **`--stamp-book-col-gap` defaults to `--sp-2`** — before → after: `--sp-3` → `--sp-2` (8), so three stamps of 96 keep their size on the ground in a 343 column (343 − 32 of padding − 16 of gaps = 295). In a holder narrower than that the three shrink alike (81.67 each at 320). The strip reads the same knob.
12
+ - **A stamp in a `StampOn` is 48 × 60 on any surface** — before → after: 27% of the surface's width (54 × 67.5 on a 200 surface), or 48 on a note → 48 × 60 everywhere, `--stamp-sm-size` (one tap). On a note nothing moved.
13
+ - **`Stamp words` is not drawn at the standard size** — before → after: the small line showed on a stamp wider than 96, which a centred stamp was (192 to 218) → a stamp is 96, where the small line is not drawn and `name` is larger. It shows again only where `--stamp-size` is set above 6rem (96).
14
+ - **A stamp in an `AvatarStack` is the small size** (Lh 2026-10-11) — before → after: 32 × 40 (`--avatar-stack-stamp-w`) → 48 × 60 (`--stamp-sm-size`), the same size as a stamp in a `StampOn`. The lap between stamps is 8, unchanged. The stack is wider, so the words beside it have less room. Measured on a `Row` whose lead is three stamps and a count, with a title, a meta line and an end button: at 375 the meta line is on two lines and the row is 76.6 high (was 53.6); at 360 and 390 it stays on one line and the rows are 56.3 and 60 high. To bring a screen up to date: look at each row that leads with a stack of stamps, and shorten its meta line where it now breaks.
15
+ - **The stamps in a `PostDesk`'s tray are the standard size** (Lh 2026-10-11, "ทำในรุ่นนี้เลย"; this release only, so the postcard set changes with the stamp's) — before → after: each stamp in the tray was 72 × 90 (`--post-desk-pick-w`) → `--stamp-size`, 96 × 120 (90 × 112.5 at 360, where the root is 15px). The tilt (`--post-corner-stamp-tilt`, 2deg) and the 4:5 ratio are as before. The tray row is 130 high at 375 (was 100), so on the address half of `PostScreens · Write` its bottom is at 698 on a screen 812 high (the bar starts at 720); on a screen 667 high the tray was already under the bar and the page scrolls, now 30 further. To bring a screen up to date: look at each `PostDesk` again. The corner's stamp, the desk's stamp box and the postmark are unchanged.
16
+ - **The desk's tray scrolls sideways when its stamps outrun the screen** — before → after: a row that did not scroll (four stamps of 72 ran 25 past a column of 343) → one line that scrolls (`overflow-x: auto`, no scroll bar) and never shrinks a stamp. Three fit a column of 343 at 375 (3 × 104 + 2 × 12 = 336), four do not.
17
+ - **`--post-desk-stamps-gap` defaults to `--sp-3`** — before → after: `--sp-4` (16) → `--sp-3` (12). Three stamps of 96 with the old gap are 344 wide, 1px more than the column at 375, and the tray would scroll for nothing.
18
+
19
+ ### Docs
20
+ - **Mount a `Modal` only when it is to show.** A `Modal` first mounted with `open={false}` is drawn, leaves, and calls `onClosed` after about 700ms. Known fault, not fixed in this release: under React StrictMode `onClosed` is never called for a `Modal` mounted that way.
21
+ - **`useLayer`: one layer per tick.** Two layers opened in the same handler lose the first (`a.open(1); b.open(2)` gives `a.value` null, `b.value` 2). Open the second in a later tick.
22
+
5
23
  ## 0.7.83 — 2026-10-11
6
24
 
7
25
  ### Changed — breaking for a screen that draws a `Sticky`
package/README.md CHANGED
@@ -386,6 +386,10 @@ whose markup has rules, because the sheet's box is the step itself:
386
386
  bottom layer), stays `duration` (4 s), slides out, never takes the cursor, never stops the member. `open` +
387
387
  `onOpenChange(open, reason)` or `defaultOpen`; unmount it in `onClosed`. One at a time: the queue and the notification
388
388
  list are the app's — the app shows its newest notification in it, `onTap` opens that notification.
389
+ - **Mount a `Modal` only when it is to show.** A `Modal` first mounted with `open={false}` is drawn in place, then leaves,
390
+ and calls `onClosed` after about 700ms. Known fault, not fixed: under React StrictMode (any dev build) `onClosed` is
391
+ never called for a `Modal` mounted that way. Keep the app's own `mounted` flag: set it when the question is asked,
392
+ clear it in `onClosed`.
389
393
  - **cardds names its own controls, in the page's language** (Lh 2026-09-29): a handle, a back button, a Pin's cells… read
390
394
  their name from `src/words.ts` by `<html lang>` (en, th ship; `setWords(lang, {…})` adds one). An app passes no label that
391
395
  only repeats these words; a prop still wins.
@@ -447,7 +451,9 @@ between at 40% down the screen (see *Anatomy*, "Where the centre is"):
447
451
  back one entry, or, when it came with the page, the entry without it) · `way.arrive(value)` (a link straight to an open
448
452
  sheet: read `?way=` once, no entry added, the query dropped). `useLayers().closeAll(then)` takes every layer off, then moves
449
453
  (signing out). NOTHING INSIDE A LAYER TAKES AN ENTRY — a step, typed text, a sheet's rest, a tab: back at any step takes the
450
- whole sheet down, and opened again it starts anew (a new `key` per opening). The project hands its router over once:
454
+ whole sheet down, and opened again it starts anew (a new `key` per opening). ONE LAYER PER TICK: two layers opened in
455
+ the same handler lose the first (`a.open(1); b.open(2)` gives `a.value` null and `b.value` 2). Open the second in a
456
+ later tick. The project hands its router over once:
451
457
  `<LayerHistory state push replace back>` around its screens — react-router: `location = useLocation()`, `state = location.state`,
452
458
  `push = (s, search) => navigate({ pathname: location.pathname, search: search === 'drop' ? '' : location.search }, { state: s })`, `replace = (s, search) => navigate({ pathname: location.pathname, search: search === 'drop' ? '' : location.search }, { replace: true, state: s })`,
453
459
  `back = (n) => navigate(-n)`. cardds never calls the History API itself. Story `LayerHistory · Back`.
@@ -616,26 +622,35 @@ it up. cardds draws the paper; the pictures, their words and which stamp a membe
616
622
  - **`Stamp`** — a perforated 4:5 stamp. `pictures` is one to four nodes, the app's own art (an svg, an img), in placement
617
623
  order: the stamp places, sizes and turns them by how many there are. `tone` is the ground, one of `STICKY_TONES` (the
618
624
  same list and the same `--sticky-<tone>-bg` knobs as a note's paper). `name` is the big line on the picture's foot,
619
- `words` the small line above it. `tilt` turns it, `onClick` makes the whole stamp a button. It fills its column up to
620
- `--stamp-max-w`, and every inner length follows its width, so one stamp reads in a tray and in a sheet.
625
+ `words` the small line above it. `tilt` turns it, `onClick` makes the whole stamp a button. Every inner length follows
626
+ the stamp's width.
627
+ - **A stamp is one size wherever it stands** (Lh 2026-10-11). A `Stamp` and a `StampPlace` are `--stamp-size` wide (two
628
+ taps: 96 × 120) in a `Centre`, a sheet, a page, a `StampBook` and a card's head. What holds a stamp only places it. A
629
+ holder narrower than a stamp shrinks it, and the stamp is still shown whole. Set `--stamp-size` on `:root` for every
630
+ stamp, or on an element for the stamps inside it. There is one other size, the small one: a stamp in a `StampOn` and a
631
+ stamp in an `AvatarStack` are `--stamp-sm-size` wide (one tap: 48 × 60), on any surface and in any row. The stamps in
632
+ a `PostDesk`'s tray are the standard size. One exception, by the owner's decision: the stamp at a postcard's corner is
633
+ the postcard's own size, 72 × 90 (`--post-corner-stamp-w`), in neither. `words` is not drawn on a stamp 96 wide or
634
+ narrower, so at the standard size only `name` shows, and it is larger.
621
635
  - **`StampPlace`** — an empty place the size of a stamp, its edge a ring of round dots: a word inside, `onClick` for "make
622
636
  yours", `faint` for a gap nobody is asked to fill. The edge is a drawn stroke, so the dots are yours: `--stamp-place-dot`
623
637
  is how wide each is (default `--rule-w`, 2px), `--stamp-place-gap` the distance from one dot's centre to the next
624
638
  (default 6px), and a `--stamp-place-dash` above 0 stretches each dot into a round-ended dash. Its corner is
625
639
  `--stamp-place-radius`. The dots' outer edge is the box's edge whatever their width.
626
640
  - **`StampBook`** + **`StampCell`** — the album page: cells three across on an album ground, a `label` under each stamp,
627
- the free places drawn up to `places`. A cell with `onClick` is a button; `on` marks it pressed. `strip` is one line
628
- of small stamps that scrolls sideways, the tray a member picks from. A `false` or `null` child holds no place.
629
- - A stamp stands for a person in three more places. In a `Centre` — a `Stamp` or a `StampPlace` — it takes the screen's
630
- size and the words and link under it centre. In a card's head — `<Card heading={name} caption={greeting}
641
+ the free places drawn up to `places`. A cell with `onClick` is a button; `on` marks it pressed. Each stamp stands in
642
+ the middle of its third. `bare` is the page with no ground, no padding and no round. `strip` is one line of stamps
643
+ that scrolls sideways, the tray a member picks from. A `false` or `null` child holds no place.
644
+ - A stamp stands for a person in three more places. In a `Centre` — a `Stamp` or a `StampPlace` — it stands in the
645
+ middle and the words and link under it centre. In a card's head — `<Card heading={name} caption={greeting}
631
646
  end={<Stamp bare …/>} foot={<Btn primary block>…</Btn>} />` — the words stand at the left and the stamp at the right,
632
- as tall as both lines, `--card-head-stamp-w` wide (default two taps); the card's one button presses it whole. In an
633
- `AvatarStack` it is a head (`more="+9"` for the count).
647
+ beside both lines; the card's one button presses it whole. In an `AvatarStack` it is a head, the small size
648
+ (`more="+9"` for the count).
634
649
  - **`StampOn`** — a stamp stuck on a surface. `at` is the stamp's middle as a share of the surface (`{ x, y }`, 0 to 1),
635
650
  `turn` its angle in degrees. With `onAtChange` the member drags it (the arrow keys move it too) and it asks with the
636
651
  new place when the finger lets go; without it the stamp is still. The surface is the nearest positioned box:
637
- `Sticky stuck={…}` is one. On a note a stamp is 48 wide whatever the note's size (`--sticky-stamp-w`), and it may lie
638
- over the words.
652
+ `Sticky stuck={…}` is one. The stamp is the small size, 48 × 60 whatever the surface's size (`--stamp-sm-size`), and
653
+ on a note it may lie over the words.
639
654
 
640
655
  What an app stores for a stamp: the picture ids (1 to 4, in order), the ground tone, the name, the small line. Making
641
656
  one is the app's screen: `ChipPick` checkboxes that each show a picture, the app refuses a fifth, and the app draws
@@ -671,8 +686,13 @@ the older `Postcard` (a member's cover card that turns over) is another componen
671
686
  the box at that card (`open` is its `id`, `null` is the front card; `onOpenChange`).
672
687
  - **`Postmark`**: the round mark, `place` and `date`. Information, nothing to press.
673
688
 
674
- The stamp is always a `Stamp` the app hands over. On a card's corner it shows its pictures only (pass `bare`; the corner
675
- drops the words by itself too); in the desk's tray it keeps its words. `PostLetter` and `PostDesk` size themselves to the
689
+ The stamp is always a `Stamp` the app hands over. On a card's corner it is the postcard's own size, 72 × 90
690
+ (`--post-corner-stamp-w`; it is not one of the stamp's two sizes), and shows its pictures only (pass `bare`; the corner
691
+ drops the words by itself too); the postmark is struck over it by 0.4 of its own size. The empty stamp box in a
692
+ `PostDesk` is the same size and shows its word. In the desk's tray a stamp is the standard size, 96 × 120
693
+ (`--stamp-size`), and keeps its words; the tray is one line that scrolls sideways when the stamps are wider than the
694
+ screen (three fit a 343 column). `--post-desk-stamps-gap` is the space between them. `PostLetter` and `PostDesk` size
695
+ themselves to the
676
696
  screen they are in, so they go in a `Step` > `Page bleed`. **`Page bleed`** runs the page to the screen's edges and keeps
677
697
  the inset as its own padding, so a card that leans, slides or casts a shadow is cut at the glass, not at the inset.
678
698
  The gallery's `PostScreens` page has the three finished screens (read, write, keep) to start from.
package/css/card.css CHANGED
@@ -84,14 +84,14 @@
84
84
  height, only the row gap. */
85
85
  .card__head :is(h1, h2, h3) { overflow-wrap: anywhere; }
86
86
 
87
- /* a Stamp in a card's head (`Card end={<Stamp …/>}`): the words stand at the left, the stamp at the right and AS TALL AS BOTH LINES — the heading and the
88
- caption pair up beside it, not the stamp beside the heading alone with the caption left under it. A stamp has no size of its own in a flex
89
- row (a width of 100% of the head, up to its cap), so it takes --card-head-stamp-w here, as a stamp in an AvatarStack takes a width of its own.
87
+ /* 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
88
+ 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,
89
+ stamp.css); the head only places it.
90
90
  <div class="card__head"><h2 class="t-h2">…</h2><span class="t-caption t-muted">…</span><span class="stamp">…</span></div> */
91
91
  .card__head:has(> .stamp) { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; }
92
92
  .card__head:has(> .stamp) > :is(h1, h2, h3) { grid-column: 1; grid-row: 1; align-self: end; }
93
93
  .card__head:has(> .stamp) > :is(.t-caption, .t-body) { grid-column: 1; grid-row: 2; align-self: start; }
94
- .card__head > .stamp { grid-column: 2; grid-row: 1 / span 2; width: var(--card-head-stamp-w, calc(var(--tap) * 2)); margin-inline: 0; }
94
+ .card__head > .stamp { grid-column: 2; grid-row: 1 / span 2; margin-inline: 0; }
95
95
 
96
96
  /* ---- bleed: a scrolling track that runs to the container's edges ----
97
97
  For a horizontal strip inside a padded container — .avatar-pick, .chip-row,
package/css/people.css CHANGED
@@ -50,9 +50,10 @@
50
50
  .avatar-stack { display: inline-flex; align-items: center; }
51
51
  .avatar-stack > .avatar { box-shadow: 0 0 0 var(--sp-1) var(--card-bg, var(--surface)); }
52
52
  .avatar-stack > .avatar + .avatar { margin-left: calc(-1 * var(--sp-3)); }
53
- /* stamps in the stack: a Stamp is as wide as its column, and an inline row has none — so it brings one, as tall as an sm head (4:5) and a little overlapped, like the heads
53
+ /* a stamp in the stack is the stamp's small size, the one a stuck stamp is (--stamp-sm-size, stamp.css: 48 × 60), lapped like the heads. Measured 2026-10-11 in a Row's
54
+ lead with a title, a meta line and an end button: at 375 the meta line breaks in two, accepted by Lh (a lap of 16 would hold it; the lap stays 8)
54
55
  <span class="avatar-stack"><span class="stamp stamp--bare">…</span><span class="stamp stamp--bare">…</span><span class="avatar-stack__more">+9</span></span> */
55
- .avatar-stack > .stamp { --_stack-w: calc(var(--avatar-sm) * 4 / 5); flex: none; width: var(--avatar-stack-stamp-w, var(--_stack-w)); margin-inline: 0; }
56
+ .avatar-stack > .stamp { flex: none; width: var(--stamp-sm-size, var(--tap)); margin-inline: 0; }
56
57
  .avatar-stack > .stamp + .stamp { margin-left: calc(-1 * var(--sp-2)); }
57
58
  /* more: the count that trails the stack — plain words on the ground, title size so it reads at arm's length (the accent "+7" avatar is the small, framed way) */
58
59
  .avatar-stack__more { margin-left: var(--avatar-stack-more-gap, var(--sp-3)); font: var(--avatar-stack-more-font, var(--type-title)); color: var(--avatar-stack-more-ink, inherit); white-space: nowrap; }
package/css/post.css CHANGED
@@ -60,7 +60,7 @@
60
60
  aspect-ratio: 4 / 5;
61
61
  rotate: var(--post-corner-stamp-tilt, 2deg);
62
62
  }
63
- .post-corner__stamp > :is(.stamp, .stamp-place) { grid-area: 1 / 1; max-width: none; }
63
+ .post-corner__stamp > :is(.stamp, .stamp-place) { grid-area: 1 / 1; width: 100%; max-width: none; } /* the corner is the postcard's own size (72 × 90), outside the stamp's two sizes, by the owner's decision (2026-10-11); its box sizes the stamp, which fills it */
64
64
 
65
65
  /* ============================================================
66
66
  post-letter — READING one that arrived. The written side stood upright: the address half over the message half.
@@ -243,9 +243,21 @@
243
243
  .post-desk__reach--address { inset-inline-end: calc(-1 * var(--screen-pad)); }
244
244
  .post-desk__reach--message { inset-inline-start: calc(-1 * var(--screen-pad)); }
245
245
  .post-desk__reach:focus-visible { outline: var(--focus); outline-offset: calc(-1 * var(--sp-1)); }
246
- /* the sender's stamps to choose from, under the card */
247
- .post-desk__stamps { display: flex; gap: var(--post-desk-stamps-gap, var(--sp-4)); align-items: center; }
246
+ /* the sender's stamps to choose from, under the card: each the standard size (--stamp-size, stamp.css), in one line that scrolls sideways when
247
+ they outrun the screen — a stamp never shrinks to fit. Three fit a 343 column at 375 (3 × 104 + 2 × 12); with the gap at sp-4 they were 1px over. The padding (taken back by the margin) keeps the focus ring and the lean inside the scroller */
248
+ .post-desk__stamps {
249
+ display: flex;
250
+ gap: var(--post-desk-stamps-gap, var(--sp-3));
251
+ align-items: center;
252
+ margin: calc(-1 * var(--sp-2));
253
+ padding: var(--sp-2);
254
+ overflow-x: auto;
255
+ overscroll-behavior-x: contain;
256
+ scrollbar-width: none;
257
+ }
258
+ .post-desk__stamps::-webkit-scrollbar { display: none; }
248
259
  .post-desk__pick {
260
+ flex: none;
249
261
  display: grid;
250
262
  place-items: center;
251
263
  min-width: var(--tap);
@@ -255,7 +267,7 @@
255
267
  border-block-end: var(--rule-w) solid transparent;
256
268
  background: transparent;
257
269
  }
258
- .post-desk__pick > .stamp { --_w: calc(var(--sp-2) * 9); width: var(--post-desk-pick-w, var(--_w)); max-width: none; rotate: var(--post-corner-stamp-tilt, 2deg); } /* in the tray a stamp keeps its words */
270
+ .post-desk__pick > .stamp { rotate: var(--post-corner-stamp-tilt, 2deg); } /* in the tray a stamp keeps its words */
259
271
  .post-desk__pick[aria-pressed="true"] { border-block-end-color: var(--on-surface); }
260
272
  .post-desk__note { margin: 0; font: var(--type-caption); color: var(--post-desk-note-ink, var(--on-surface-muted)); min-height: 1.35em; }
261
273
  /* what stands where the card was, once it has left */
package/css/stamp.css CHANGED
@@ -13,13 +13,17 @@
13
13
  </span>
14
14
  Two boxes, as the sticky note: the OUTER one holds the size and the shadow, the PAPER is the one whose edge is
15
15
  punched (a mask on the outer box would cut its own shadow off). The stamp is a size container: every inner length
16
- is a share of its width (cqw), so it reads the same from a tray to a sheet. The ground wears a sticky tone class —
17
- one list of tones (src/sticky/tones.ts), one set of tone knobs. */
16
+ is a share of its width (cqw). The ground wears a sticky tone class — one list of tones (src/sticky/tones.ts), one
17
+ set of tone knobs.
18
+ ONE SIZE (Lh 2026-10-11): a stamp, and the empty place for one, is --stamp-size wide wherever it stands — in a book, a tray,
19
+ a card's head, a centre, a sheet, a page. What holds it only PLACES it. There is ONE other size, the small one, --stamp-sm-size
20
+ (one tap: half the stamp), for a stamp stuck ON something (`.stamp-on`, below) and a stamp in an avatar stack (people.css): one knob for both.
21
+ ONE exception, by the owner's decision (Lh 2026-10-11): the stamp at a postcard's corner (post.css) is the postcard's own size, 72 × 90,
22
+ --post-corner-stamp-w, in neither. The desk's tray (post.css) holds stamps of the standard size. */
18
23
  .stamp, .stamp-place {
19
- --_cap: calc(var(--tap) * 4.5);
20
24
  box-sizing: border-box;
21
- width: 100%; /* sized by its column… */
22
- max-width: var(--stamp-max-w, var(--_cap)); /* …up to a cap */
25
+ width: var(--stamp-size, calc(var(--tap) * 2));
26
+ max-width: 100%; /* a holder narrower than a stamp still shows it whole */
23
27
  aspect-ratio: 4 / 5;
24
28
  margin-inline: auto;
25
29
  }
@@ -63,7 +67,7 @@
63
67
  .stamp__words, .stamp__name { display: block; min-width: 0; white-space: nowrap; overflow-x: clip; text-overflow: ellipsis; }
64
68
  .stamp__words { --_words: 4.8cqw; font: 500 var(--_words) / 1.3 var(--font-ui); font-size: var(--stamp-words-font-size, var(--_words)); }
65
69
  .stamp__name { --_name: 9.5cqw; font: 900 var(--_name) / 1.15 var(--font-display); font-size: var(--stamp-name-font-size, var(--_name)); }
66
- /* tiny (a tray, an album cell, a stamp stuck on a note): the small line goes, the name grows */
70
+ /* at the stamp's own size and under (and stuck on a note): the small line goes, the name grows */
67
71
  /* --bare: the pictures alone, no words — a stamp stuck on something (a note, a postcard). The words belong to the album.
68
72
  The pictures take the foot's room: each sits a little lower, so the group stands in the middle of the frame. */
69
73
  .stamp--bare .stamp__cap, .stamp-on .stamp__cap, .post-corner .stamp__cap { display: none; }
@@ -82,12 +86,8 @@
82
86
  /* --tap: the whole stamp is the button (`onClick`); the press and the ring are the PRESS list's (actions.css) */
83
87
  .stamp--tap { appearance: none; border: 0; padding: 0; background: none; font: inherit; text-align: start; -webkit-tap-highlight-color: transparent; }
84
88
 
85
- /* a stamp — or the empty place for one — handed over in a Centre: sized by the SCREEN (a little over half its width inside the inset), its greeting centred under it */
89
+ /* a stamp — or the empty place for one — handed over in a Centre: its greeting centred under it. The stamp is its own size here as everywhere */
86
90
  .screen__centre:has(> :is(.stamp, .stamp-place)) { justify-items: center; text-align: center; }
87
- .screen__centre > :is(.stamp, .stamp-place) { max-width: var(--stamp-centre-max-w, 56cqw); }
88
- /* in the room above a closed stack's heads the stamp is held by that room's HEIGHT too: its height at most 45% of it, so two lines of words under it
89
- still fit on a short phone (320×568 left 253px for a group 314 tall — reported by timebank, 2026-10-07). cqh reads the base, a size container. */
90
- .sheet-stack__base > .screen__centre > :is(.stamp, .stamp-place) { max-width: min(var(--stamp-centre-max-w, 56cqw), 36cqh); }
91
91
 
92
92
  /* ---- stamp place: an empty place for a stamp — an album's gap, "make yours" ----
93
93
  <span class="stamp-place"><svg class="stamp-place__edge" aria-hidden="true"><rect/></svg>สร้าง</span> · <button class="stamp-place">…</button> · <span class="stamp-place stamp-place--faint">…</span>
@@ -135,6 +135,9 @@
135
135
  .stamp-place--faint { --_edge: var(--stamp-place-faint-border, var(--hairline)); }
136
136
 
137
137
  /* ---- stamp book: the album page — three stamps across on an album ground, who each is from under it ----
138
+ The book places its stamps, it does not size them: each stands in the middle of its third. The column gap is the one that lets
139
+ three stamps keep their size in a phone's column (343 − 2 × 16 of padding − 2 × 8 = 295 ≥ 3 × 96); in a holder narrower than
140
+ that the thirds, and the stamps with them, shrink alike.
138
141
  <div class="stamp-book">
139
142
  <button class="stamp-cell"><span class="stamp">…</span><span class="stamp-cell__label">ต้น</span></button>
140
143
  <span class="stamp-cell">…</span>
@@ -144,7 +147,7 @@
144
147
  display: grid;
145
148
  grid-template-columns: repeat(3, minmax(0, 1fr));
146
149
  align-items: start;
147
- gap: var(--stamp-book-row-gap, var(--sp-4)) var(--stamp-book-col-gap, var(--sp-3));
150
+ gap: var(--stamp-book-row-gap, var(--sp-4)) var(--stamp-book-col-gap, var(--sp-2));
148
151
  padding: var(--stamp-book-pad, var(--sp-4));
149
152
  border-radius: var(--stamp-book-radius, var(--r-media));
150
153
  background-color: var(--stamp-book-bg, var(--ink-tint));
@@ -152,6 +155,7 @@
152
155
  .stamp-cell {
153
156
  position: relative;
154
157
  display: grid;
158
+ grid-template-columns: minmax(0, 1fr); /* the cell's one column is the cell, never its stamp: in a third narrower than a stamp the stamp gives way (its max-width) */
155
159
  gap: var(--stamp-cell-gap, var(--sp-2));
156
160
  min-width: 0;
157
161
  appearance: none;
@@ -178,15 +182,13 @@
178
182
  color: var(--stamp-cell-on-ink, var(--on-accent));
179
183
  }
180
184
  .stamp-cell__on > .icon { width: 70%; height: 70%; }
181
- /* --bare: no ground, no padding — the stamps lie on what holds the book and fill it: three across, each the whole width of its third (the Stamp's own cap is lifted), the gap the least that still keeps three apart (the shadow's room), the row gap the same. The name is the Stamp's own; free places still draw.
185
+ /* --bare: no ground, no padding, no round — the stamps lie on what holds the book, three across as on the ground. The name is the Stamp's own; free places still draw.
182
186
  <div class="stamp-book stamp-book--bare"> */
183
- .stamp-book--bare { gap: var(--stamp-book-bare-gap, var(--sp-2)); padding: 0; border-radius: 0; background: none; }
184
- .stamp-book--bare :is(.stamp, .stamp-place) { max-width: none; }
185
- /* --strip: ONE line of small stamps that scrolls sideways — the tray a member picks from. No ground. */
187
+ .stamp-book--bare { padding: 0; border-radius: 0; background: none; }
188
+ /* --strip: ONE line of stamps that scrolls sideways — the tray a member picks from, each stamp its own size. No ground. */
186
189
  .stamp-book--strip {
187
- --_strip: calc(var(--tap) * 1.5);
188
190
  display: flex;
189
- gap: var(--stamp-book-col-gap, var(--sp-3));
191
+ gap: var(--stamp-book-col-gap, var(--sp-2));
190
192
  padding: var(--sp-2) 0;
191
193
  border-radius: 0;
192
194
  background: none;
@@ -195,7 +197,7 @@
195
197
  scrollbar-width: none;
196
198
  }
197
199
  .stamp-book--strip::-webkit-scrollbar { display: none; }
198
- .stamp-book--strip > * { flex: none; width: var(--stamp-book-strip-w, var(--_strip)); }
200
+ .stamp-book--strip > * { flex: none; }
199
201
 
200
202
  /* ---- stamp on: a stamp stuck on a surface where the member put it ----
201
203
  <div class="sticky__stuck"><div class="stamp-on stamp-on--move" style="--stamp-on-x: 0.8; --stamp-on-y: 0.2; --stamp-on-turn: 6"><span class="stamp">…</span></div></div>
@@ -205,12 +207,12 @@
205
207
  position: absolute;
206
208
  left: calc(var(--stamp-on-x, 0.5) * 100%);
207
209
  top: calc(var(--stamp-on-y, 0.5) * 100%);
208
- width: var(--stamp-on-w, 27%);
209
210
  translate: -50% -50%;
210
211
  rotate: calc(var(--stamp-on-turn, 0) * 1deg);
211
212
  pointer-events: auto; /* the layer it lies in lets a tap through to the surface; the stamp itself takes it */
212
213
  }
213
- .stamp-on > .stamp { max-width: none; }
214
+ /* the SMALL stamp: stuck on a surface (a note). 48 × 60 whatever the surface's size. The stamp carries the size and the `.stamp-on` box is as wide as its stamp */
215
+ .stamp-on > .stamp { width: var(--stamp-sm-size, var(--tap)); max-width: none; }
214
216
  .stamp-on--move { will-change: transform; } /* its own layer: Safari left the stamp's shadow behind as a trail along the drag when it was painted with the note (seen on the simulator, 2026-10-07) */
215
217
  .stamp-on--move { cursor: grab; touch-action: none; -webkit-user-select: none; user-select: none; transition: scale var(--motion-press) ease-out; }
216
218
  .stamp-on--move:focus-visible { outline: var(--focus); outline-offset: var(--sp-1); }
package/css/sticky.css CHANGED
@@ -94,9 +94,8 @@
94
94
  box-shadow: calc(-1 * var(--sp-0)) calc(-1 * var(--sp-0)) var(--sp-1) rgb(0 0 0 / 0.08);
95
95
  }
96
96
  /* things stuck ON the note (a stamp, placed by hand): a layer over the whole paper. A tap between them still reaches the words under it.
97
- A stamp on a note is one width whatever the note's (48 × 60, the stamp of the album's strip), and may lie over the words. */
97
+ A stamp on a note is the stamp's small size whatever the note's (48 × 60, --stamp-sm-size: stamp.css), and may lie over the words. */
98
98
  .sticky__stuck { position: absolute; inset: 0; pointer-events: none; }
99
- .sticky__stuck > .stamp-on { width: var(--sticky-stamp-w, var(--stamp-on-w, var(--sp-12))); } /* the stamp's own knob still reaches it; the note's wins */
100
99
  .sticky--flat > .sticky__paper { clip-path: none; }
101
100
  .sticky--flat > .sticky__paper > .sticky__foot { padding-inline-end: 0; }
102
101
 
package/dist/cardds.css CHANGED
@@ -770,14 +770,14 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
770
770
  height, only the row gap. */
771
771
  .card__head :is(h1, h2, h3) { overflow-wrap: anywhere; }
772
772
 
773
- /* a Stamp in a card's head (`Card end={<Stamp …/>}`): the words stand at the left, the stamp at the right and AS TALL AS BOTH LINES — the heading and the
774
- caption pair up beside it, not the stamp beside the heading alone with the caption left under it. A stamp has no size of its own in a flex
775
- row (a width of 100% of the head, up to its cap), so it takes --card-head-stamp-w here, as a stamp in an AvatarStack takes a width of its own.
773
+ /* 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
774
+ 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,
775
+ stamp.css); the head only places it.
776
776
  <div class="card__head"><h2 class="t-h2">…</h2><span class="t-caption t-muted">…</span><span class="stamp">…</span></div> */
777
777
  .card__head:has(> .stamp) { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; }
778
778
  .card__head:has(> .stamp) > :is(h1, h2, h3) { grid-column: 1; grid-row: 1; align-self: end; }
779
779
  .card__head:has(> .stamp) > :is(.t-caption, .t-body) { grid-column: 1; grid-row: 2; align-self: start; }
780
- .card__head > .stamp { grid-column: 2; grid-row: 1 / span 2; width: var(--card-head-stamp-w, calc(var(--tap) * 2)); margin-inline: 0; }
780
+ .card__head > .stamp { grid-column: 2; grid-row: 1 / span 2; margin-inline: 0; }
781
781
 
782
782
  /* ---- bleed: a scrolling track that runs to the container's edges ----
783
783
  For a horizontal strip inside a padded container — .avatar-pick, .chip-row,
@@ -3186,9 +3186,10 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
3186
3186
  .avatar-stack { display: inline-flex; align-items: center; }
3187
3187
  .avatar-stack > .avatar { box-shadow: 0 0 0 var(--sp-1) var(--card-bg, var(--surface)); }
3188
3188
  .avatar-stack > .avatar + .avatar { margin-left: calc(-1 * var(--sp-3)); }
3189
- /* stamps in the stack: a Stamp is as wide as its column, and an inline row has none — so it brings one, as tall as an sm head (4:5) and a little overlapped, like the heads
3189
+ /* a stamp in the stack is the stamp's small size, the one a stuck stamp is (--stamp-sm-size, stamp.css: 48 × 60), lapped like the heads. Measured 2026-10-11 in a Row's
3190
+ lead with a title, a meta line and an end button: at 375 the meta line breaks in two, accepted by Lh (a lap of 16 would hold it; the lap stays 8)
3190
3191
  <span class="avatar-stack"><span class="stamp stamp--bare">…</span><span class="stamp stamp--bare">…</span><span class="avatar-stack__more">+9</span></span> */
3191
- .avatar-stack > .stamp { --_stack-w: calc(var(--avatar-sm) * 4 / 5); flex: none; width: var(--avatar-stack-stamp-w, var(--_stack-w)); margin-inline: 0; }
3192
+ .avatar-stack > .stamp { flex: none; width: var(--stamp-sm-size, var(--tap)); margin-inline: 0; }
3192
3193
  .avatar-stack > .stamp + .stamp { margin-left: calc(-1 * var(--sp-2)); }
3193
3194
  /* more: the count that trails the stack — plain words on the ground, title size so it reads at arm's length (the accent "+7" avatar is the small, framed way) */
3194
3195
  .avatar-stack__more { margin-left: var(--avatar-stack-more-gap, var(--sp-3)); font: var(--avatar-stack-more-font, var(--type-title)); color: var(--avatar-stack-more-ink, inherit); white-space: nowrap; }
@@ -3860,9 +3861,8 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
3860
3861
  box-shadow: calc(-1 * var(--sp-0)) calc(-1 * var(--sp-0)) var(--sp-1) rgb(0 0 0 / 0.08);
3861
3862
  }
3862
3863
  /* things stuck ON the note (a stamp, placed by hand): a layer over the whole paper. A tap between them still reaches the words under it.
3863
- A stamp on a note is one width whatever the note's (48 × 60, the stamp of the album's strip), and may lie over the words. */
3864
+ A stamp on a note is the stamp's small size whatever the note's (48 × 60, --stamp-sm-size: stamp.css), and may lie over the words. */
3864
3865
  .sticky__stuck { position: absolute; inset: 0; pointer-events: none; }
3865
- .sticky__stuck > .stamp-on { width: var(--sticky-stamp-w, var(--stamp-on-w, var(--sp-12))); } /* the stamp's own knob still reaches it; the note's wins */
3866
3866
  .sticky--flat > .sticky__paper { clip-path: none; }
3867
3867
  .sticky--flat > .sticky__paper > .sticky__foot { padding-inline-end: 0; }
3868
3868
 
@@ -4115,13 +4115,17 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
4115
4115
  </span>
4116
4116
  Two boxes, as the sticky note: the OUTER one holds the size and the shadow, the PAPER is the one whose edge is
4117
4117
  punched (a mask on the outer box would cut its own shadow off). The stamp is a size container: every inner length
4118
- is a share of its width (cqw), so it reads the same from a tray to a sheet. The ground wears a sticky tone class —
4119
- one list of tones (src/sticky/tones.ts), one set of tone knobs. */
4118
+ is a share of its width (cqw). The ground wears a sticky tone class — one list of tones (src/sticky/tones.ts), one
4119
+ set of tone knobs.
4120
+ ONE SIZE (Lh 2026-10-11): a stamp, and the empty place for one, is --stamp-size wide wherever it stands — in a book, a tray,
4121
+ a card's head, a centre, a sheet, a page. What holds it only PLACES it. There is ONE other size, the small one, --stamp-sm-size
4122
+ (one tap: half the stamp), for a stamp stuck ON something (`.stamp-on`, below) and a stamp in an avatar stack (people.css): one knob for both.
4123
+ ONE exception, by the owner's decision (Lh 2026-10-11): the stamp at a postcard's corner (post.css) is the postcard's own size, 72 × 90,
4124
+ --post-corner-stamp-w, in neither. The desk's tray (post.css) holds stamps of the standard size. */
4120
4125
  .stamp, .stamp-place {
4121
- --_cap: calc(var(--tap) * 4.5);
4122
4126
  box-sizing: border-box;
4123
- width: 100%; /* sized by its column… */
4124
- max-width: var(--stamp-max-w, var(--_cap)); /* …up to a cap */
4127
+ width: var(--stamp-size, calc(var(--tap) * 2));
4128
+ max-width: 100%; /* a holder narrower than a stamp still shows it whole */
4125
4129
  aspect-ratio: 4 / 5;
4126
4130
  margin-inline: auto;
4127
4131
  }
@@ -4165,7 +4169,7 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
4165
4169
  .stamp__words, .stamp__name { display: block; min-width: 0; white-space: nowrap; overflow-x: clip; text-overflow: ellipsis; }
4166
4170
  .stamp__words { --_words: 4.8cqw; font: 500 var(--_words) / 1.3 var(--font-ui); font-size: var(--stamp-words-font-size, var(--_words)); }
4167
4171
  .stamp__name { --_name: 9.5cqw; font: 900 var(--_name) / 1.15 var(--font-display); font-size: var(--stamp-name-font-size, var(--_name)); }
4168
- /* tiny (a tray, an album cell, a stamp stuck on a note): the small line goes, the name grows */
4172
+ /* at the stamp's own size and under (and stuck on a note): the small line goes, the name grows */
4169
4173
  /* --bare: the pictures alone, no words — a stamp stuck on something (a note, a postcard). The words belong to the album.
4170
4174
  The pictures take the foot's room: each sits a little lower, so the group stands in the middle of the frame. */
4171
4175
  .stamp--bare .stamp__cap, .stamp-on .stamp__cap, .post-corner .stamp__cap { display: none; }
@@ -4184,12 +4188,8 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
4184
4188
  /* --tap: the whole stamp is the button (`onClick`); the press and the ring are the PRESS list's (actions.css) */
4185
4189
  .stamp--tap { appearance: none; border: 0; padding: 0; background: none; font: inherit; text-align: start; -webkit-tap-highlight-color: transparent; }
4186
4190
 
4187
- /* a stamp — or the empty place for one — handed over in a Centre: sized by the SCREEN (a little over half its width inside the inset), its greeting centred under it */
4191
+ /* a stamp — or the empty place for one — handed over in a Centre: its greeting centred under it. The stamp is its own size here as everywhere */
4188
4192
  .screen__centre:has(> :is(.stamp, .stamp-place)) { justify-items: center; text-align: center; }
4189
- .screen__centre > :is(.stamp, .stamp-place) { max-width: var(--stamp-centre-max-w, 56cqw); }
4190
- /* in the room above a closed stack's heads the stamp is held by that room's HEIGHT too: its height at most 45% of it, so two lines of words under it
4191
- still fit on a short phone (320×568 left 253px for a group 314 tall — reported by timebank, 2026-10-07). cqh reads the base, a size container. */
4192
- .sheet-stack__base > .screen__centre > :is(.stamp, .stamp-place) { max-width: min(var(--stamp-centre-max-w, 56cqw), 36cqh); }
4193
4193
 
4194
4194
  /* ---- stamp place: an empty place for a stamp — an album's gap, "make yours" ----
4195
4195
  <span class="stamp-place"><svg class="stamp-place__edge" aria-hidden="true"><rect/></svg>สร้าง</span> · <button class="stamp-place">…</button> · <span class="stamp-place stamp-place--faint">…</span>
@@ -4237,6 +4237,9 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
4237
4237
  .stamp-place--faint { --_edge: var(--stamp-place-faint-border, var(--hairline)); }
4238
4238
 
4239
4239
  /* ---- stamp book: the album page — three stamps across on an album ground, who each is from under it ----
4240
+ The book places its stamps, it does not size them: each stands in the middle of its third. The column gap is the one that lets
4241
+ three stamps keep their size in a phone's column (343 − 2 × 16 of padding − 2 × 8 = 295 ≥ 3 × 96); in a holder narrower than
4242
+ that the thirds, and the stamps with them, shrink alike.
4240
4243
  <div class="stamp-book">
4241
4244
  <button class="stamp-cell"><span class="stamp">…</span><span class="stamp-cell__label">ต้น</span></button>
4242
4245
  <span class="stamp-cell">…</span>
@@ -4246,7 +4249,7 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
4246
4249
  display: grid;
4247
4250
  grid-template-columns: repeat(3, minmax(0, 1fr));
4248
4251
  align-items: start;
4249
- gap: var(--stamp-book-row-gap, var(--sp-4)) var(--stamp-book-col-gap, var(--sp-3));
4252
+ gap: var(--stamp-book-row-gap, var(--sp-4)) var(--stamp-book-col-gap, var(--sp-2));
4250
4253
  padding: var(--stamp-book-pad, var(--sp-4));
4251
4254
  border-radius: var(--stamp-book-radius, var(--r-media));
4252
4255
  background-color: var(--stamp-book-bg, var(--ink-tint));
@@ -4254,6 +4257,7 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
4254
4257
  .stamp-cell {
4255
4258
  position: relative;
4256
4259
  display: grid;
4260
+ grid-template-columns: minmax(0, 1fr); /* the cell's one column is the cell, never its stamp: in a third narrower than a stamp the stamp gives way (its max-width) */
4257
4261
  gap: var(--stamp-cell-gap, var(--sp-2));
4258
4262
  min-width: 0;
4259
4263
  appearance: none;
@@ -4280,15 +4284,13 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
4280
4284
  color: var(--stamp-cell-on-ink, var(--on-accent));
4281
4285
  }
4282
4286
  .stamp-cell__on > .icon { width: 70%; height: 70%; }
4283
- /* --bare: no ground, no padding — the stamps lie on what holds the book and fill it: three across, each the whole width of its third (the Stamp's own cap is lifted), the gap the least that still keeps three apart (the shadow's room), the row gap the same. The name is the Stamp's own; free places still draw.
4287
+ /* --bare: no ground, no padding, no round — the stamps lie on what holds the book, three across as on the ground. The name is the Stamp's own; free places still draw.
4284
4288
  <div class="stamp-book stamp-book--bare"> */
4285
- .stamp-book--bare { gap: var(--stamp-book-bare-gap, var(--sp-2)); padding: 0; border-radius: 0; background: none; }
4286
- .stamp-book--bare :is(.stamp, .stamp-place) { max-width: none; }
4287
- /* --strip: ONE line of small stamps that scrolls sideways — the tray a member picks from. No ground. */
4289
+ .stamp-book--bare { padding: 0; border-radius: 0; background: none; }
4290
+ /* --strip: ONE line of stamps that scrolls sideways — the tray a member picks from, each stamp its own size. No ground. */
4288
4291
  .stamp-book--strip {
4289
- --_strip: calc(var(--tap) * 1.5);
4290
4292
  display: flex;
4291
- gap: var(--stamp-book-col-gap, var(--sp-3));
4293
+ gap: var(--stamp-book-col-gap, var(--sp-2));
4292
4294
  padding: var(--sp-2) 0;
4293
4295
  border-radius: 0;
4294
4296
  background: none;
@@ -4297,7 +4299,7 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
4297
4299
  scrollbar-width: none;
4298
4300
  }
4299
4301
  .stamp-book--strip::-webkit-scrollbar { display: none; }
4300
- .stamp-book--strip > * { flex: none; width: var(--stamp-book-strip-w, var(--_strip)); }
4302
+ .stamp-book--strip > * { flex: none; }
4301
4303
 
4302
4304
  /* ---- stamp on: a stamp stuck on a surface where the member put it ----
4303
4305
  <div class="sticky__stuck"><div class="stamp-on stamp-on--move" style="--stamp-on-x: 0.8; --stamp-on-y: 0.2; --stamp-on-turn: 6"><span class="stamp">…</span></div></div>
@@ -4307,12 +4309,12 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
4307
4309
  position: absolute;
4308
4310
  left: calc(var(--stamp-on-x, 0.5) * 100%);
4309
4311
  top: calc(var(--stamp-on-y, 0.5) * 100%);
4310
- width: var(--stamp-on-w, 27%);
4311
4312
  translate: -50% -50%;
4312
4313
  rotate: calc(var(--stamp-on-turn, 0) * 1deg);
4313
4314
  pointer-events: auto; /* the layer it lies in lets a tap through to the surface; the stamp itself takes it */
4314
4315
  }
4315
- .stamp-on > .stamp { max-width: none; }
4316
+ /* the SMALL stamp: stuck on a surface (a note). 48 × 60 whatever the surface's size. The stamp carries the size and the `.stamp-on` box is as wide as its stamp */
4317
+ .stamp-on > .stamp { width: var(--stamp-sm-size, var(--tap)); max-width: none; }
4316
4318
  .stamp-on--move { will-change: transform; } /* its own layer: Safari left the stamp's shadow behind as a trail along the drag when it was painted with the note (seen on the simulator, 2026-10-07) */
4317
4319
  .stamp-on--move { cursor: grab; touch-action: none; -webkit-user-select: none; user-select: none; transition: scale var(--motion-press) ease-out; }
4318
4320
  .stamp-on--move:focus-visible { outline: var(--focus); outline-offset: var(--sp-1); }
@@ -4382,7 +4384,7 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
4382
4384
  aspect-ratio: 4 / 5;
4383
4385
  rotate: var(--post-corner-stamp-tilt, 2deg);
4384
4386
  }
4385
- .post-corner__stamp > :is(.stamp, .stamp-place) { grid-area: 1 / 1; max-width: none; }
4387
+ .post-corner__stamp > :is(.stamp, .stamp-place) { grid-area: 1 / 1; width: 100%; max-width: none; } /* the corner is the postcard's own size (72 × 90), outside the stamp's two sizes, by the owner's decision (2026-10-11); its box sizes the stamp, which fills it */
4386
4388
 
4387
4389
  /* ============================================================
4388
4390
  post-letter — READING one that arrived. The written side stood upright: the address half over the message half.
@@ -4565,9 +4567,21 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
4565
4567
  .post-desk__reach--address { inset-inline-end: calc(-1 * var(--screen-pad)); }
4566
4568
  .post-desk__reach--message { inset-inline-start: calc(-1 * var(--screen-pad)); }
4567
4569
  .post-desk__reach:focus-visible { outline: var(--focus); outline-offset: calc(-1 * var(--sp-1)); }
4568
- /* the sender's stamps to choose from, under the card */
4569
- .post-desk__stamps { display: flex; gap: var(--post-desk-stamps-gap, var(--sp-4)); align-items: center; }
4570
+ /* the sender's stamps to choose from, under the card: each the standard size (--stamp-size, stamp.css), in one line that scrolls sideways when
4571
+ they outrun the screen — a stamp never shrinks to fit. Three fit a 343 column at 375 (3 × 104 + 2 × 12); with the gap at sp-4 they were 1px over. The padding (taken back by the margin) keeps the focus ring and the lean inside the scroller */
4572
+ .post-desk__stamps {
4573
+ display: flex;
4574
+ gap: var(--post-desk-stamps-gap, var(--sp-3));
4575
+ align-items: center;
4576
+ margin: calc(-1 * var(--sp-2));
4577
+ padding: var(--sp-2);
4578
+ overflow-x: auto;
4579
+ overscroll-behavior-x: contain;
4580
+ scrollbar-width: none;
4581
+ }
4582
+ .post-desk__stamps::-webkit-scrollbar { display: none; }
4570
4583
  .post-desk__pick {
4584
+ flex: none;
4571
4585
  display: grid;
4572
4586
  place-items: center;
4573
4587
  min-width: var(--tap);
@@ -4577,7 +4591,7 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
4577
4591
  border-block-end: var(--rule-w) solid transparent;
4578
4592
  background: transparent;
4579
4593
  }
4580
- .post-desk__pick > .stamp { --_w: calc(var(--sp-2) * 9); width: var(--post-desk-pick-w, var(--_w)); max-width: none; rotate: var(--post-corner-stamp-tilt, 2deg); } /* in the tray a stamp keeps its words */
4594
+ .post-desk__pick > .stamp { rotate: var(--post-corner-stamp-tilt, 2deg); } /* in the tray a stamp keeps its words */
4581
4595
  .post-desk__pick[aria-pressed="true"] { border-block-end-color: var(--on-surface); }
4582
4596
  .post-desk__note { margin: 0; font: var(--type-caption); color: var(--post-desk-note-ink, var(--on-surface-muted)); min-height: 1.35em; }
4583
4597
  /* what stands where the card was, once it has left */