@usableapp/cardds 0.7.82 → 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.
Files changed (47) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/README.md +72 -12
  3. package/bin/cardds.mjs +21 -10
  4. package/css/actions.css +2 -0
  5. package/css/card.css +4 -4
  6. package/css/layover.css +5 -0
  7. package/css/people.css +3 -2
  8. package/css/post.css +16 -4
  9. package/css/stamp.css +23 -21
  10. package/css/sticky.css +138 -28
  11. package/dist/actions/Chip.d.ts +4 -2
  12. package/dist/actions/Chip.js +3 -3
  13. package/dist/cardds.css +191 -59
  14. package/dist/catalog.json +1 -1
  15. package/dist/index.d.ts +2 -0
  16. package/dist/index.js +2 -0
  17. package/dist/post/PostBox.d.ts +1 -1
  18. package/dist/post/PostDesk.d.ts +2 -2
  19. package/dist/post/PostLetter.d.ts +1 -1
  20. package/dist/post/Postmark.d.ts +1 -1
  21. package/dist/post/Postmark.js +1 -1
  22. package/dist/post/postCorner.js +1 -1
  23. package/dist/scaffold/LayerHistory.d.ts +2 -0
  24. package/dist/scaffold/LayerHistory.js +2 -0
  25. package/dist/sheets/Modal.d.ts +4 -1
  26. package/dist/sheets/Modal.js +4 -1
  27. package/dist/stamp/Stamp.d.ts +4 -3
  28. package/dist/stamp/Stamp.js +3 -2
  29. package/dist/stamp/StampBook.d.ts +3 -3
  30. package/dist/stamp/StampBook.js +1 -1
  31. package/dist/stamp/StampOn.d.ts +1 -0
  32. package/dist/stamp/StampOn.js +1 -0
  33. package/dist/sticky/Sticky.d.ts +8 -6
  34. package/dist/sticky/Sticky.js +6 -3
  35. package/dist/sticky/StickyAnswer.d.ts +23 -0
  36. package/dist/sticky/StickyAnswer.js +35 -0
  37. package/dist/sticky/StickyBoard.d.ts +12 -0
  38. package/dist/sticky/StickyBoard.js +13 -0
  39. package/dist/sticky/StickyThread.d.ts +12 -6
  40. package/dist/sticky/StickyThread.js +8 -4
  41. package/dist/words.d.ts +1 -1
  42. package/dist/words.js +2 -2
  43. package/lib/catalog.mjs +1 -0
  44. package/lib/mcp.mjs +1 -1
  45. package/lib/role.mjs +11 -3
  46. package/lint/rules.mjs +7 -2
  47. package/package.json +1 -1
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,
@@ -2624,6 +2624,8 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
2624
2624
  .dot--warn { background: var(--signal-warn); }
2625
2625
  .dot--error { background: var(--signal-error); }
2626
2626
  .dot--info { background: var(--signal-info); }
2627
+ /* --sm: a small LABEL (a name on a note, a tag in a tight head) — low and tight; never a tap target */
2628
+ .chip--sm { min-height: 0; gap: var(--chip-sm-gap, var(--sp-1)); padding: var(--chip-sm-pad-y, var(--sp-0)) var(--chip-sm-pad-x, var(--sp-2)); }
2627
2629
  .chip--on { background: var(--chip-on-bg, var(--accent)); color: var(--chip-on-ink, var(--on-accent)); border-color: transparent; }
2628
2630
  /* muted: an untouched default — the words wash out, the edge stays; emphasis is the difference from the neighbours (README 13) */
2629
2631
  .chip--muted { color: var(--chip-muted-ink, var(--card-muted)); }
@@ -3184,9 +3186,10 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
3184
3186
  .avatar-stack { display: inline-flex; align-items: center; }
3185
3187
  .avatar-stack > .avatar { box-shadow: 0 0 0 var(--sp-1) var(--card-bg, var(--surface)); }
3186
3188
  .avatar-stack > .avatar + .avatar { margin-left: calc(-1 * var(--sp-3)); }
3187
- /* 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)
3188
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> */
3189
- .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; }
3190
3193
  .avatar-stack > .stamp + .stamp { margin-left: calc(-1 * var(--sp-2)); }
3191
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) */
3192
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; }
@@ -3762,15 +3765,17 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
3762
3765
  .bullets__text { flex: 1; min-width: 0; }
3763
3766
 
3764
3767
  /* ---- css/sticky.css — sticky note, its field, tone chooser, thread of posts, pile ---- */
3765
- /* cardds — sticky notes: the paper note, the field written on it, the tone chooser, a thread of posts.
3768
+ /* cardds — sticky notes: the paper note, the field written on it, the tone chooser, notes stuck on a page, a thread of posts, the answer note.
3766
3769
  A note is its own paper: it brings its colour and its ink, whatever card or palette it lies on. */
3767
3770
 
3768
- /* ---- sticky: a paper note — a flat pastel block, straight, the bottom-right corner folded over ----
3769
- Straight unless asked (--tilt-left / --tilt-right: the one note of a start screen), never patterned. The corner is CUT on the diagonal and a flap of a darker shade lies over it.
3771
+ /* ---- sticky: a paper note — a flat pastel SQUARE of one size, the bottom-right corner folded over ----
3772
+ ONE SIZE (Lh 2026-10-10): every note is --sticky-size square (168), whatever it says; words it cannot hold are cut where the words' room ends,
3773
+ no ellipsis. Square corners. THE FOLD SAYS UNREAD: a folded corner = not read yet, --flat = read.
3774
+ Straight unless asked (--tilt-left / --tilt-right, or a holder that turns its notes), never patterned. The corner is CUT on the diagonal and a flap of a darker shade lies over it.
3770
3775
  <div class="sticky sticky--custard">
3771
3776
  <div class="sticky__paper">
3772
3777
  <div class="sticky__head">12 Oct</div><div class="sticky__body">…</div><div class="sticky__foot">From Noi</div>
3773
- <span class="sticky__fold"></span>
3778
+ <span class="sticky__fold"></span><span class="sticky__state t-sr">Unread</span>
3774
3779
  </div>
3775
3780
  </div>
3776
3781
  Two boxes on purpose: the OUTER one holds the tone and the shadow, the PAPER is the one that is cut — a clip-path
@@ -3782,16 +3787,13 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
3782
3787
  --_muted: color-mix(in srgb, currentColor 62%, transparent); /* muted words: the ink sunk into the paper (currentColor is read where it is used: there it is still the note's ink) */
3783
3788
  padding-inline-end: var(--sticky-fold, var(--sp-6)); /* the knob, read by a real property first (the knob test probes that one); --_fold hands the same value to the paper and the flap */
3784
3789
  --_fold: var(--sticky-fold, var(--sp-6));
3785
- --_min: calc(var(--tap) * 3);
3786
- --_cap: calc(var(--tap) * 7);
3787
- --_tall: calc(var(--tap) * 4.4);
3788
3790
  position: relative;
3789
3791
  display: grid;
3792
+ grid-template: minmax(0, 1fr) / minmax(0, 1fr); /* the paper is the note's size, never its words' */
3790
3793
  box-sizing: border-box;
3791
- width: fit-content; /* hugs its words… */
3792
- min-width: var(--sticky-min-w, var(--_min)); /* …but a word alone is still a note */
3793
- max-width: var(--sticky-max-w, 100%);
3794
- min-height: var(--sticky-min-h, var(--_tall)); /* every note is one height, the height of a note being written (Lh 2026-10-07); more words still grow it */
3794
+ flex: none;
3795
+ width: var(--sticky-size, calc(var(--sp-12) * 3.5)); /* 168: two side by side on a phone */
3796
+ aspect-ratio: 1;
3795
3797
  padding: 0 var(--_fold) var(--_fold) 0; /* = the line above, written whole */
3796
3798
  background-clip: content-box;
3797
3799
  isolation: isolate; /* the two layers below stay under this note, over whatever is behind it */
@@ -3805,7 +3807,7 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
3805
3807
  position: absolute;
3806
3808
  z-index: -1;
3807
3809
  pointer-events: none;
3808
- border-radius: var(--sticky-radius, var(--sp-1));
3810
+ border-radius: var(--sticky-radius, 0rem);
3809
3811
  background-image: linear-gradient(-45deg, transparent calc(var(--_fold) * 0.7071), var(--_ink) 0); /* the folded corner, cut */
3810
3812
  }
3811
3813
  .sticky::after { --_ink: var(--sticky-edge-bg, rgb(0 0 0 / 0.14)); inset: calc(-1 * var(--border-w)); }
@@ -3833,18 +3835,20 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
3833
3835
  gap: var(--sticky-gap, var(--sp-3));
3834
3836
  box-sizing: border-box;
3835
3837
  min-width: 0;
3838
+ min-height: 0;
3836
3839
  margin: 0 calc(-1 * var(--_fold)) calc(-1 * var(--_fold)) 0;
3837
3840
  padding: var(--sticky-pad-y, var(--sp-4)) var(--sticky-pad-x, var(--sp-4));
3838
- border-radius: var(--sticky-radius, var(--sp-1));
3841
+ border-radius: var(--sticky-radius, 0rem);
3839
3842
  background-color: inherit;
3840
3843
  clip-path: polygon(0 0, 100% 0, 100% calc(100% - var(--_fold)), calc(100% - var(--_fold)) 100%, 0 100%);
3841
3844
  }
3842
- .sticky__head { display: flex; align-items: center; gap: var(--sticky-head-gap, var(--sp-2)); font: var(--sticky-head-font, var(--type-caption)); color: var(--sticky-muted-ink, var(--_muted)); }
3845
+ .sticky__head { flex: none; display: flex; align-items: center; gap: var(--sticky-head-gap, var(--sp-2)); font: var(--sticky-head-font, var(--type-caption)); color: var(--sticky-muted-ink, var(--_muted)); }
3843
3846
  .sticky__head > .ph { flex: 1 1 0; min-width: 0; } /* a picture in the head takes the note's width */
3844
3847
  .sticky__head:has(> .sticky-date) { align-items: start; }
3845
3848
  .sticky__head:has(> .sticky-date) > .ph { flex: none; width: var(--sticky-pic-size, calc(var(--tap) * 1.5)); min-height: 0; aspect-ratio: 1; } /* beside a date the picture is a small square at the start */
3846
- .sticky__body { flex: 1 1 auto; min-width: 0; font: var(--sticky-font, var(--type-title)); overflow-wrap: anywhere; }
3847
- .sticky__foot { font: var(--sticky-foot-font, var(--type-caption)); color: var(--sticky-muted-ink, var(--_muted)); padding-inline-end: var(--_fold); } /* the line stops before the fold */
3849
+ .sticky__body { flex: 1 1 auto; min-width: 0; min-height: 0; overflow: clip; /* words past the note's room are cut, the foot keeps its place */ font: var(--sticky-font, var(--type-title)); overflow-wrap: anywhere; }
3850
+ .sticky__paper > :not(.sticky__body) > .chip { border-color: transparent; background-color: var(--sticky-chip-bg, rgb(255 255 255 / 0.85)); color: var(--sticky-ink, #141414); } /* a chip on a note is a label ON the paper (whose note it is): a pale ground nearly opaque (it may lie over words), no edge, the note's ink */
3851
+ .sticky__foot { flex: none; font: var(--sticky-foot-font, var(--type-caption)); color: var(--sticky-muted-ink, var(--_muted)); padding-inline-end: var(--_fold); } /* the line stops before the fold */
3848
3852
  /* the flap: a square in the corner — the paper's cut takes its outer half, what is left is the triangle lying on the note */
3849
3853
  .sticky__fold {
3850
3854
  position: absolute;
@@ -3856,12 +3860,15 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
3856
3860
  background-color: var(--sticky-fold-bg, color-mix(in srgb, currentColor 14%, transparent)); /* a darker shade of whatever the paper is */
3857
3861
  box-shadow: calc(-1 * var(--sp-0)) calc(-1 * var(--sp-0)) var(--sp-1) rgb(0 0 0 / 0.08);
3858
3862
  }
3859
- /* 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
+ /* 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.
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. */
3860
3865
  .sticky__stuck { position: absolute; inset: 0; pointer-events: none; }
3861
3866
  .sticky--flat > .sticky__paper { clip-path: none; }
3862
3867
  .sticky--flat > .sticky__paper > .sticky__foot { padding-inline-end: 0; }
3863
3868
 
3864
- /* --tilt: the note turned a little on its middle. Straight is the rule; this is for the one note a start screen hands over. */
3869
+ /* --tilt: the note turned a little on its middle — the one note a start screen hands over. Notes on a board or in a lapped thread are turned by their holder. */
3870
+ /* a note that stands alone in a page's column or in a centre stands in its middle */
3871
+ .page > .sticky, .screen__centre > .sticky { margin-inline: auto; }
3865
3872
  .sticky--tilt-left, .sticky--tilt-right { margin-block: var(--sp-4); } /* the turned corners and the shadow need room: a box that scrolls (a centre) would cut them */
3866
3873
  .sticky--tilt-left { rotate: calc(-1 * var(--sticky-tilt, 5deg)); }
3867
3874
  .sticky--tilt-right { rotate: var(--sticky-tilt, 5deg); }
@@ -3872,9 +3879,6 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
3872
3879
  .sticky-date__day { font: var(--sticky-date-day-font, var(--type-stat)); }
3873
3880
  .sticky-date__month { font: var(--sticky-date-month-font, var(--type-caption)); color: var(--sticky-muted-ink, var(--_muted)); }
3874
3881
 
3875
- /* --square: the note to write on — 1:1, as wide as its column up to a cap, in the middle */
3876
- .sticky--square { width: 100%; max-width: var(--sticky-square-max-w, var(--_cap)); aspect-ratio: 1; margin-inline: auto; }
3877
-
3878
3882
  /* --corner: a control stands ON the bottom-right corner, half outside. The paper is notched round it (a mask, so no
3879
3883
  ground colour is needed; the edge and the shadow are notched the same way); the note has no fold. */
3880
3884
  .sticky__corner {
@@ -3890,7 +3894,6 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
3890
3894
  /* the half of the control that stands outside is the note's own room: it never runs past the column, nor onto what follows */
3891
3895
  .sticky--corner {
3892
3896
  --_corner: var(--sticky-corner-size, var(--tap-sm)); /* the same default as .sticky__corner above: the paper's notch needs it too */
3893
- max-width: calc(var(--sticky-max-w, 100%) - var(--_corner) / 2);
3894
3897
  margin: 0 calc(var(--_corner) / 2) calc(var(--_corner) / 2) 0;
3895
3898
  }
3896
3899
  .sticky--corner::before, .sticky--corner::after { background-image: radial-gradient(circle at 100% 100%, transparent calc(var(--_corner) / 2 + var(--sp-1)), var(--_ink) 0); }
@@ -3901,16 +3904,17 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
3901
3904
  mask: radial-gradient(circle at 100% 100%, transparent calc(var(--_notch) - var(--border-w)), #000 var(--_notch));
3902
3905
  }
3903
3906
 
3904
- /* a tilted square is sized by the SCREEN, not by a length: three quarters of its width inside the inset, about two thirds of the glass (Lh 2026-10-06) — the turned corners
3905
- keep clear of the edges on any phone. cqw reads the fill screen (the size container). After --square, so it wins. */
3906
- .sticky--square.sticky--tilt-left, .sticky--square.sticky--tilt-right { max-width: var(--sticky-tilt-max-w, 75cqw); }
3907
-
3908
3907
  /* --tap: the whole note is the button (`onClick`). The fold stays; the ring follows the note's turn. */
3909
3908
  .sticky--tap { appearance: none; border: 0; font: inherit; text-align: start; cursor: pointer; -webkit-tap-highlight-color: transparent; }
3910
3909
  .sticky--tap .sticky__body, .sticky--tap .sticky__foot { display: block; }
3911
3910
  .sticky--tap:focus-visible { outline: var(--focus); outline-offset: var(--sp-1); }
3912
3911
  .sticky--tap:active > .sticky__paper { translate: 0 var(--sp-0); }
3913
3912
 
3913
+ /* a name label in the foot (a Chip, `sm`) stands at the START, what follows it (the time) at the end, on one line: a long name is cut
3914
+ with an ellipsis past its share of the row and never wraps; the time is never cut (a long one may run a little onto the fold) */
3915
+ .sticky__paper > .sticky__foot:has(> .chip) { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); white-space: nowrap; text-align: end; }
3916
+ .sticky__foot > .chip { display: block; flex: none; min-width: 0; max-width: var(--sticky-foot-chip-max-w, 62%); overflow: hidden; text-overflow: ellipsis; text-align: start; }
3917
+
3914
3918
  /* ---- sticky field: the words written ON a note — a bare textarea in the note's type and ink, filling it ----
3915
3919
  <div class="sticky__body"><textarea class="sticky-field" aria-label="Note" placeholder="Add text to this note"></textarea></div> */
3916
3920
  .sticky__body:has(> .sticky-field) { display: grid; }
@@ -3918,7 +3922,7 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
3918
3922
  display: block;
3919
3923
  box-sizing: border-box;
3920
3924
  width: 100%;
3921
- min-height: var(--sticky-field-min-h, var(--_min));
3925
+ height: 100%; /* the note's whole room: a touch anywhere on the paper writes */
3922
3926
  resize: none;
3923
3927
  border: 0;
3924
3928
  margin: 0;
@@ -3974,7 +3978,6 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
3974
3978
  .sticky-post__name { min-width: 0; font: var(--sticky-post-name-font, var(--type-label)); overflow-wrap: anywhere; }
3975
3979
  .sticky-post__time { margin-inline-start: auto; font: var(--sticky-post-time-font, var(--type-caption)); color: var(--sticky-post-time-ink, var(--on-surface-muted)); white-space: nowrap; }
3976
3980
  .sticky-post__notes { grid-area: 2 / 2; display: grid; justify-items: start; gap: var(--sticky-post-notes-gap, var(--sp-3)); min-width: 0; }
3977
- .sticky-post__notes > .sticky { max-width: var(--sticky-post-max-w, 85%); } /* a note leaves the far side open, as a bubble does */
3978
3981
  .sticky-post__rail { display: none; grid-area: 2 / 1; justify-self: center; align-self: stretch; color: var(--sticky-thread-rail-ink, var(--on-surface-muted)); border-inline-start: var(--rule-w) dotted currentColor; margin-block-end: calc(-1 * var(--_thread-gap)); } /* runs on through the gap to the next avatar */
3979
3982
  .sticky-thread--rail > .sticky-post:not(:last-child) > .sticky-post__rail { display: block; }
3980
3983
  /* a chat (no rail): a note leans on its writer's own edge of the thread — it starts under the avatar, not under the name, so theirs and mine stand apart (Lh 2026-10-07: both sat in the middle). With a rail the notes keep clear of it, under the name. */
@@ -3986,6 +3989,116 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
3986
3989
  .sticky-post--right > .sticky-post__notes { grid-column: 1; justify-items: end; }
3987
3990
  .sticky-post--right > .sticky-post__rail { grid-column: 2; }
3988
3991
 
3992
+ /* --lapped: a chat with NO head rows (Lh 2026-10-10) — theirs at the left, mine at the right, each turn lying over a corner of the one before
3993
+ on the other side; two turns from one side have nothing to lie over and stand a small gap apart. The time stands close under its note, on
3994
+ its own side; the avatar is not drawn and the name is only heard (it stands once, in the screen's top bar). The thread is two notes wide
3995
+ less what they share, in the middle of its column, so the corners cross on any phone. Later = on top: the order of the turns. */
3996
+ .sticky-thread--lapped {
3997
+ gap: 0;
3998
+ width: 100%;
3999
+ max-width: calc(2 * var(--sticky-size, calc(var(--sp-12) * 3.5)) - var(--sticky-thread-lap-x, var(--sp-8))); /* 304: the two sides cross 32 in the middle (38 as they lie turned — the prototype's 39); on a 375 phone each stands 19.5 in from the screen's inset */
4000
+ margin-inline: auto;
4001
+ padding-block-start: var(--sp-4); /* the first note's turned corner */
4002
+ }
4003
+ .sticky-thread--lapped > .sticky-post { position: relative; display: grid; grid-template-columns: auto; justify-self: start; justify-items: start; row-gap: var(--sticky-thread-time-gap, var(--sp-0)); margin-block-start: var(--sticky-thread-same-gap, var(--sp-2)); }
4004
+ .sticky-thread--lapped > .sticky-post:first-child { margin-block-start: 0; }
4005
+ .sticky-thread--lapped > .sticky-post--right { justify-self: end; justify-items: end; }
4006
+ .sticky-thread--lapped > .sticky-post:not(.sticky-post--right) + .sticky-post--right,
4007
+ .sticky-thread--lapped > .sticky-post--right + .sticky-post:not(.sticky-post--right) { margin-block-start: calc(-1 * var(--sticky-thread-lap, calc(var(--sp-1) * 19))); } /* 76 */
4008
+ .sticky-thread--lapped > .sticky-post > .sticky-post__who { display: none; }
4009
+ .sticky-thread--lapped > .sticky-post > .sticky-post__notes { grid-area: 1 / 1; }
4010
+ .sticky-thread--lapped > .sticky-post > .sticky-post__head { grid-area: 2 / 1; }
4011
+ .sticky-thread--lapped > .sticky-post > .sticky-post__head > .sticky-post__name { position: absolute; width: 1px; height: 1px; margin: -1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; } /* as .t-sr: heard, not seen */
4012
+ .sticky-thread--lapped > .sticky-post > .sticky-post__head > .sticky-post__time { margin-inline: 0; }
4013
+ .sticky-thread--lapped > .sticky-post > .sticky-post__head:not(:has(> .sticky-post__time)) { display: none; }
4014
+ /* each note leans a little, one way then the other */
4015
+ .sticky-thread--lapped > .sticky-post > .sticky-post__notes > .sticky { rotate: calc(-1 * var(--sticky-thread-tilt, 2deg)); }
4016
+ .sticky-thread--lapped > .sticky-post:nth-child(even) > .sticky-post__notes > .sticky { rotate: var(--sticky-thread-tilt, 2deg); }
4017
+ /* under an answer note the thread ends with the room that note stands in: the last turn scrolls up clear of it */
4018
+ .screen:has(> .sticky-answer) .sticky-thread--lapped { padding-block-end: calc(var(--sticky-size, calc(var(--sp-12) * 3.5)) * var(--sticky-answer-show, 0.75) + var(--sp-6)); }
4019
+
4020
+ /* ---- sticky board: notes stuck on a page — rows that wrap by the width, each note turned a little ----
4021
+ <div class="sticky-board"><button class="sticky sticky--tap …">…</button>…</div>
4022
+ As many notes in a row as the width holds (two on a phone, three from 504 of room, a screen about 540 wide), the rows in the middle. The notes stand edge to
4023
+ edge both ways (--sticky-board-lap 0): only their turned corners cross. LATER = ON TOP, always: the right one over the left, the lower over
4024
+ the upper — the order of the notes, no z-index. Where two notes do not fit side by side, each lies over the one before by what is
4025
+ missing, so a phone still shows two — but never by more than half the fold, which would hide the corner that says unread: past that, one in a row.
4026
+ The columns are tracks of the note's size less the lap; a note is wider than its track by the lap, and the room at the end is what the last
4027
+ of a row runs into — none is cut. The tracks are 50% while the lap is the missing room (padding % and track % read the same width).
4028
+ A note here is the SAME note as inside its chat (Lh 2026-10-11): on the paper only what is the note's own — its words, its time at the END
4029
+ of the foot, the stamps really stuck on it. Whose it is, is a label of the page: a small Chip at the start of the note's foot.
4030
+ The foot takes no room from the words (below). */
4031
+ .sticky-board {
4032
+ --_size: var(--sticky-size, calc(var(--sp-12) * 3.5));
4033
+ --_most: calc(var(--sticky-fold, var(--sp-6)) / 2);
4034
+ padding-inline-end: clamp(var(--sticky-board-lap, 0rem), 2 * var(--_size) - 100%, var(--_most));
4035
+ --_cell: max(var(--_size) - var(--_most), min(var(--_size) - var(--sticky-board-lap, 0rem), 50%));
4036
+ display: grid;
4037
+ grid-template-columns: repeat(auto-fill, var(--_cell));
4038
+ grid-auto-rows: calc(var(--_size) - var(--sticky-board-lap, 0rem)); /* down the page the lap is the set one: a page is as long as it needs */
4039
+ justify-content: center;
4040
+ padding-block: var(--sp-2) calc(var(--sticky-board-lap, 0rem) + var(--sticky-board-drop, var(--sp-2)) + var(--sp-2)); /* the turned corners above; below, the last row's overhang and its drop */
4041
+ }
4042
+ .sticky-board > * { position: relative; }
4043
+ .sticky-board > :nth-child(even) { translate: 0 var(--sticky-board-drop, var(--sp-2)); } /* tops of a row NEAR one line, not on it */
4044
+ /* the foot is laid OVER the note's foot, out of its flow: the words keep the whole paper, so they break exactly as they do where the note is
4045
+ opened (Lh 2026-10-11 — a clamp showed three lines and "…" on the page and four inside). A long note's last line runs under the label and the time. */
4046
+ .sticky-board .sticky__paper > .sticky__foot { position: absolute; inset: auto var(--sticky-board-foot-inset, var(--sp-3)) var(--sticky-board-foot-inset, var(--sp-3)); text-align: end; }
4047
+ /* how far each is turned: FOUR unlike angles in turn (Lh 2026-10-11). At most three notes meet, so four keep the lean from ever looking the
4048
+ same: two in a row, a note lies over the one two before it and those lean opposite ways; three in a row, over the one three before it,
4049
+ never the same angle. (A run of seven left one column at 0.75° and −0.5°: its edges read as one straight line and the lean was lost.) */
4050
+ .sticky-board > :nth-child(4n + 1) { rotate: var(--sticky-board-turn-1, -3deg); }
4051
+ .sticky-board > :nth-child(4n + 2) { rotate: var(--sticky-board-turn-2, 1.5deg); }
4052
+ .sticky-board > :nth-child(4n + 3) { rotate: var(--sticky-board-turn-3, 2.75deg); }
4053
+ .sticky-board > :nth-child(4n) { rotate: var(--sticky-board-turn-4, -1.75deg); }
4054
+
4055
+ /* ---- sticky answer: the note you answer on — it waits at the screen's foot and comes to the top to be written on ----
4056
+ <div class="sticky-answer sticky-answer--writing">
4057
+ <div class="sticky-answer__scrim"></div>
4058
+ <div class="sticky-answer__note"><div class="sticky sticky--flat">…<textarea class="sticky-field"></textarea>…</div></div>
4059
+ <div class="sticky-answer__under" inert>
4060
+ <div class="sticky-answer__tools">…the paper chooser · the send button…</div>
4061
+ <div class="sticky-answer__tray">…what else stands under them (the writer's stamp)…</div>
4062
+ </div>
4063
+ </div>
4064
+ A LAYER of the screen (its child), as the snackbar is. AT REST the note stands near the right, three quarters of it above the screen's
4065
+ foot (--sticky-answer-show), turned a little; what stands under it is out of sight and inert. WRITING it stands straight in the middle under
4066
+ the top bar, the screen behind is washed pale and takes no touch, tools and tray stand under it. The note keeps its one size in both
4067
+ places. One `top`, one `right` — they slide between the two places; nothing else moves. */
4068
+ .sticky-answer {
4069
+ --_size: var(--sticky-size, calc(var(--sp-12) * 3.5));
4070
+ position: fixed; inset: 0;
4071
+ max-width: var(--screen-w); margin-inline: auto;
4072
+ overflow: clip;
4073
+ z-index: var(--z-fab);
4074
+ pointer-events: none;
4075
+ }
4076
+ .screen--fill > .sticky-answer { position: absolute; }
4077
+ .sticky-answer--writing { z-index: calc(var(--z-top) + 1); }
4078
+ .sticky-answer__scrim { position: absolute; inset: 0; background: var(--sticky-answer-scrim-bg, color-mix(in srgb, var(--surface) 82%, transparent)); opacity: 0; visibility: hidden; transition: opacity var(--motion-sheet) ease, visibility 0s var(--motion-sheet); }
4079
+ .sticky-answer--writing > .sticky-answer__scrim { opacity: 1; visibility: visible; pointer-events: auto; transition-delay: 0s; }
4080
+ .sticky-answer__note {
4081
+ position: absolute;
4082
+ top: calc(100% - var(--_size) * var(--sticky-answer-show, 0.75) - max(var(--safe-bottom), var(--kb, 0px)));
4083
+ right: var(--sticky-answer-end, var(--screen-pad));
4084
+ rotate: var(--sticky-answer-tilt, -3deg);
4085
+ pointer-events: auto;
4086
+ transition: top var(--motion-sheet) ease, right var(--motion-sheet) ease, rotate var(--motion-sheet) ease;
4087
+ }
4088
+ .sticky-answer--writing > .sticky-answer__note { top: calc(var(--safe-top) + var(--header-h) + var(--sticky-answer-top, var(--sp-5))); right: calc(50% - var(--_size) / 2); rotate: 0deg; }
4089
+ .sticky-answer__under {
4090
+ position: absolute; inset-inline: var(--screen-pad);
4091
+ top: calc(var(--safe-top) + var(--header-h) + var(--sticky-answer-top, var(--sp-5)) + var(--_size) + var(--sticky-answer-gap, var(--sp-4)));
4092
+ display: grid; gap: var(--sticky-answer-gap, var(--sp-4));
4093
+ opacity: 0; visibility: hidden;
4094
+ transition: opacity var(--motion-sheet-rest) ease, visibility 0s var(--motion-sheet-rest);
4095
+ }
4096
+ .sticky-answer--writing > .sticky-answer__under { opacity: 1; visibility: visible; pointer-events: auto; transition-delay: var(--motion-sheet-rest), 0s; }
4097
+ .sticky-answer__tools { display: flex; align-items: center; justify-content: space-between; gap: var(--sticky-answer-tools-gap, var(--sp-3)); }
4098
+ .sticky-answer__tools > .sticky-pick { justify-content: start; }
4099
+ .sticky-answer__tray { display: grid; gap: var(--sticky-answer-tray-gap, var(--sp-2)); }
4100
+ @media (prefers-reduced-motion: reduce) { .sticky-answer__scrim, .sticky-answer__note, .sticky-answer__under { transition: none; } }
4101
+
3989
4102
  /* ---- css/stamp.css — stamp, empty place, album page, a stamp stuck on a surface ---- */
3990
4103
  /* cardds — stamps: the paper stamp, an empty place for one, the album page, a stamp stuck on a surface.
3991
4104
  A stamp is its own paper, like a sticky note: it brings its ground and its ink, whatever card or palette it lies on.
@@ -4002,13 +4115,17 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
4002
4115
  </span>
4003
4116
  Two boxes, as the sticky note: the OUTER one holds the size and the shadow, the PAPER is the one whose edge is
4004
4117
  punched (a mask on the outer box would cut its own shadow off). The stamp is a size container: every inner length
4005
- 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 —
4006
- 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. */
4007
4125
  .stamp, .stamp-place {
4008
- --_cap: calc(var(--tap) * 4.5);
4009
4126
  box-sizing: border-box;
4010
- width: 100%; /* sized by its column… */
4011
- 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 */
4012
4129
  aspect-ratio: 4 / 5;
4013
4130
  margin-inline: auto;
4014
4131
  }
@@ -4052,7 +4169,7 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
4052
4169
  .stamp__words, .stamp__name { display: block; min-width: 0; white-space: nowrap; overflow-x: clip; text-overflow: ellipsis; }
4053
4170
  .stamp__words { --_words: 4.8cqw; font: 500 var(--_words) / 1.3 var(--font-ui); font-size: var(--stamp-words-font-size, var(--_words)); }
4054
4171
  .stamp__name { --_name: 9.5cqw; font: 900 var(--_name) / 1.15 var(--font-display); font-size: var(--stamp-name-font-size, var(--_name)); }
4055
- /* 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 */
4056
4173
  /* --bare: the pictures alone, no words — a stamp stuck on something (a note, a postcard). The words belong to the album.
4057
4174
  The pictures take the foot's room: each sits a little lower, so the group stands in the middle of the frame. */
4058
4175
  .stamp--bare .stamp__cap, .stamp-on .stamp__cap, .post-corner .stamp__cap { display: none; }
@@ -4071,12 +4188,8 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
4071
4188
  /* --tap: the whole stamp is the button (`onClick`); the press and the ring are the PRESS list's (actions.css) */
4072
4189
  .stamp--tap { appearance: none; border: 0; padding: 0; background: none; font: inherit; text-align: start; -webkit-tap-highlight-color: transparent; }
4073
4190
 
4074
- /* 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 */
4075
4192
  .screen__centre:has(> :is(.stamp, .stamp-place)) { justify-items: center; text-align: center; }
4076
- .screen__centre > :is(.stamp, .stamp-place) { max-width: var(--stamp-centre-max-w, 56cqw); }
4077
- /* 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
4078
- 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. */
4079
- .sheet-stack__base > .screen__centre > :is(.stamp, .stamp-place) { max-width: min(var(--stamp-centre-max-w, 56cqw), 36cqh); }
4080
4193
 
4081
4194
  /* ---- stamp place: an empty place for a stamp — an album's gap, "make yours" ----
4082
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>
@@ -4124,6 +4237,9 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
4124
4237
  .stamp-place--faint { --_edge: var(--stamp-place-faint-border, var(--hairline)); }
4125
4238
 
4126
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.
4127
4243
  <div class="stamp-book">
4128
4244
  <button class="stamp-cell"><span class="stamp">…</span><span class="stamp-cell__label">ต้น</span></button>
4129
4245
  <span class="stamp-cell">…</span>
@@ -4133,7 +4249,7 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
4133
4249
  display: grid;
4134
4250
  grid-template-columns: repeat(3, minmax(0, 1fr));
4135
4251
  align-items: start;
4136
- 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));
4137
4253
  padding: var(--stamp-book-pad, var(--sp-4));
4138
4254
  border-radius: var(--stamp-book-radius, var(--r-media));
4139
4255
  background-color: var(--stamp-book-bg, var(--ink-tint));
@@ -4141,6 +4257,7 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
4141
4257
  .stamp-cell {
4142
4258
  position: relative;
4143
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) */
4144
4261
  gap: var(--stamp-cell-gap, var(--sp-2));
4145
4262
  min-width: 0;
4146
4263
  appearance: none;
@@ -4167,15 +4284,13 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
4167
4284
  color: var(--stamp-cell-on-ink, var(--on-accent));
4168
4285
  }
4169
4286
  .stamp-cell__on > .icon { width: 70%; height: 70%; }
4170
- /* --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.
4171
4288
  <div class="stamp-book stamp-book--bare"> */
4172
- .stamp-book--bare { gap: var(--stamp-book-bare-gap, var(--sp-2)); padding: 0; border-radius: 0; background: none; }
4173
- .stamp-book--bare :is(.stamp, .stamp-place) { max-width: none; }
4174
- /* --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. */
4175
4291
  .stamp-book--strip {
4176
- --_strip: calc(var(--tap) * 1.5);
4177
4292
  display: flex;
4178
- gap: var(--stamp-book-col-gap, var(--sp-3));
4293
+ gap: var(--stamp-book-col-gap, var(--sp-2));
4179
4294
  padding: var(--sp-2) 0;
4180
4295
  border-radius: 0;
4181
4296
  background: none;
@@ -4184,7 +4299,7 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
4184
4299
  scrollbar-width: none;
4185
4300
  }
4186
4301
  .stamp-book--strip::-webkit-scrollbar { display: none; }
4187
- .stamp-book--strip > * { flex: none; width: var(--stamp-book-strip-w, var(--_strip)); }
4302
+ .stamp-book--strip > * { flex: none; }
4188
4303
 
4189
4304
  /* ---- stamp on: a stamp stuck on a surface where the member put it ----
4190
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>
@@ -4194,12 +4309,12 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
4194
4309
  position: absolute;
4195
4310
  left: calc(var(--stamp-on-x, 0.5) * 100%);
4196
4311
  top: calc(var(--stamp-on-y, 0.5) * 100%);
4197
- width: var(--stamp-on-w, 27%);
4198
4312
  translate: -50% -50%;
4199
4313
  rotate: calc(var(--stamp-on-turn, 0) * 1deg);
4200
4314
  pointer-events: auto; /* the layer it lies in lets a tap through to the surface; the stamp itself takes it */
4201
4315
  }
4202
- .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; }
4203
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) */
4204
4319
  .stamp-on--move { cursor: grab; touch-action: none; -webkit-user-select: none; user-select: none; transition: scale var(--motion-press) ease-out; }
4205
4320
  .stamp-on--move:focus-visible { outline: var(--focus); outline-offset: var(--sp-1); }
@@ -4269,7 +4384,7 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
4269
4384
  aspect-ratio: 4 / 5;
4270
4385
  rotate: var(--post-corner-stamp-tilt, 2deg);
4271
4386
  }
4272
- .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 */
4273
4388
 
4274
4389
  /* ============================================================
4275
4390
  post-letter — READING one that arrived. The written side stood upright: the address half over the message half.
@@ -4452,9 +4567,21 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
4452
4567
  .post-desk__reach--address { inset-inline-end: calc(-1 * var(--screen-pad)); }
4453
4568
  .post-desk__reach--message { inset-inline-start: calc(-1 * var(--screen-pad)); }
4454
4569
  .post-desk__reach:focus-visible { outline: var(--focus); outline-offset: calc(-1 * var(--sp-1)); }
4455
- /* the sender's stamps to choose from, under the card */
4456
- .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; }
4457
4583
  .post-desk__pick {
4584
+ flex: none;
4458
4585
  display: grid;
4459
4586
  place-items: center;
4460
4587
  min-width: var(--tap);
@@ -4464,7 +4591,7 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
4464
4591
  border-block-end: var(--rule-w) solid transparent;
4465
4592
  background: transparent;
4466
4593
  }
4467
- .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 */
4468
4595
  .post-desk__pick[aria-pressed="true"] { border-block-end-color: var(--on-surface); }
4469
4596
  .post-desk__note { margin: 0; font: var(--type-caption); color: var(--post-desk-note-ink, var(--on-surface-muted)); min-height: 1.35em; }
4470
4597
  /* what stands where the card was, once it has left */
@@ -4902,6 +5029,11 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
4902
5029
  .modal:not(:has(> .modal__lift)) > .modal__drawer { height: auto; padding-block: var(--modal-confirm-pad-y, var(--sp-6)); animation: none; }
4903
5030
  .modal__drawer .t-caption { opacity: var(--dim); }
4904
5031
  .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 */
5032
+ /* 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
5033
+ line — left to its words' width the row squeezed two buttons into round blobs, their words on two lines. A quiet button is an outline only,
5034
+ so on the ask its edge is the ask's ink at full strength (light on the dark end, dark on --light). The BtnTrio of round buttons is not touched. */
5035
+ .modal__drawer > .btn-row { justify-self: stretch; margin-top: var(--modal-drawer-answers-gap, var(--sp-5)); white-space: nowrap; }
5036
+ .modal__drawer .btn--quiet { border-color: var(--modal-drawer-quiet-border, currentColor); }
4905
5037
  .modal__drawer .icon-btn { background: transparent; color: inherit; border-color: var(--ink-rail); }
4906
5038
  .modal__drawer .icon-btn--invert { background: var(--accent); color: var(--on-accent); border-color: transparent; width: var(--tap-lg); height: var(--tap-lg); }
4907
5039
  @media (prefers-reduced-motion: no-preference) {