@usableapp/cardds 0.7.65 → 0.7.67

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/css/stamp.css ADDED
@@ -0,0 +1,182 @@
1
+ /* cardds — stamps: the paper stamp, an empty place for one, the album page, a stamp stuck on a surface.
2
+ A stamp is its own paper, like a sticky note: it brings its ground and its ink, whatever card or palette it lies on.
3
+ Its pictures are the APP's (any node); cardds lays them out by how many there are. */
4
+
5
+ /* ---- stamp: a perforated paper stamp, 4:5 — the picture fills the inner frame, the words sit ON it at the foot ----
6
+ <span class="stamp stamp--3">
7
+ <span class="stamp__paper">
8
+ <span class="stamp__pic sticky--custard">
9
+ <span class="stamp__art">…svg / img…</span>…
10
+ <span class="stamp__cap"><span class="stamp__words">กาแฟ · หมา</span><span class="stamp__name">ต้น</span></span>
11
+ </span>
12
+ </span>
13
+ </span>
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
+ 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. */
18
+ .stamp, .stamp-place {
19
+ --_cap: calc(var(--tap) * 4.5);
20
+ box-sizing: border-box;
21
+ width: 100%; /* sized by its column… */
22
+ max-width: var(--stamp-max-w, var(--_cap)); /* …up to a cap */
23
+ aspect-ratio: 4 / 5;
24
+ margin-inline: auto;
25
+ }
26
+ .stamp {
27
+ position: relative;
28
+ display: block;
29
+ container-type: inline-size;
30
+ color: var(--stamp-ink, #141414);
31
+ filter: drop-shadow(var(--stamp-drop, 0 var(--sp-1) var(--sp-2) rgb(0 0 0 / 0.16))); /* drop-shadow follows the teeth; a box-shadow would draw the rectangle */
32
+ }
33
+ .stamp__paper {
34
+ --_pitch: 5cqw; /* one tooth: 20 across, 25 down — the holes land whole on every edge */
35
+ --_hole: 1.6cqw;
36
+ position: absolute;
37
+ inset: 0;
38
+ background-color: var(--stamp-paper-bg, #fffdf8);
39
+ -webkit-mask: linear-gradient(#000 0 0) center / calc(100% - var(--_pitch)) calc(100% - var(--_pitch)) no-repeat,
40
+ radial-gradient(circle, transparent var(--_hole), #000 calc(var(--_hole) + 0.4cqw)) calc(var(--_pitch) / -2) calc(var(--_pitch) / -2) / var(--_pitch) var(--_pitch);
41
+ mask: linear-gradient(#000 0 0) center / calc(100% - var(--_pitch)) calc(100% - var(--_pitch)) no-repeat,
42
+ radial-gradient(circle, transparent var(--_hole), #000 calc(var(--_hole) + 0.4cqw)) calc(var(--_pitch) / -2) calc(var(--_pitch) / -2) / var(--_pitch) var(--_pitch);
43
+ }
44
+ .stamp__pic { position: absolute; inset: var(--stamp-frame, 8cqw); overflow: hidden; } /* the white frame round the picture; the ground is the tone class's */
45
+
46
+ /* the pictures, placed by COUNT: where, how wide, how far turned — the layout is the stamp's look, never the app's.
47
+ A share of the picture area; the foot stays clear for the words. */
48
+ .stamp__art { position: absolute; left: var(--_x); top: var(--_y); width: var(--_w); aspect-ratio: 1; translate: -50% -50%; rotate: var(--_r); }
49
+ .stamp__art > * { display: block; width: 100%; height: 100%; }
50
+ .stamp--1 .stamp__art { --_x: 50%; --_y: 40%; --_w: 72%; --_r: 0deg; }
51
+ .stamp--2 .stamp__art:nth-child(1) { --_x: 37%; --_y: 27%; --_w: 58%; --_r: -6deg; }
52
+ .stamp--2 .stamp__art:nth-child(2) { --_x: 63%; --_y: 56%; --_w: 54%; --_r: 8deg; }
53
+ .stamp--3 .stamp__art:nth-child(1) { --_x: 30%; --_y: 21%; --_w: 50%; --_r: -8deg; }
54
+ .stamp--3 .stamp__art:nth-child(2) { --_x: 71%; --_y: 31%; --_w: 46%; --_r: 7deg; }
55
+ .stamp--3 .stamp__art:nth-child(3) { --_x: 47%; --_y: 58%; --_w: 54%; --_r: -2deg; }
56
+ .stamp--4 .stamp__art:nth-child(1) { --_x: 29%; --_y: 19%; --_w: 44%; --_r: -8deg; }
57
+ .stamp--4 .stamp__art:nth-child(2) { --_x: 71%; --_y: 24%; --_w: 42%; --_r: 7deg; }
58
+ .stamp--4 .stamp__art:nth-child(3) { --_x: 31%; --_y: 57%; --_w: 42%; --_r: 5deg; }
59
+ .stamp--4 .stamp__art:nth-child(4) { --_x: 70%; --_y: 60%; --_w: 44%; --_r: -6deg; }
60
+
61
+ /* the words on the picture's foot: a small line, then the big name — one line each (clipped sideways only: Thai tone marks stand above the line box) */
62
+ .stamp__cap { position: absolute; inset-inline: 5cqw; bottom: 3.5cqw; display: grid; gap: 0.4cqw; }
63
+ .stamp__words, .stamp__name { display: block; min-width: 0; white-space: nowrap; overflow-x: clip; text-overflow: ellipsis; }
64
+ .stamp__words { --_words: 4.8cqw; font: 500 var(--_words) / 1.3 var(--font-ui); font-size: var(--stamp-words-font-size, var(--_words)); }
65
+ .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 */
67
+ /* --bare: the pictures alone, no words — a stamp stuck on something (a note, a postcard). The words belong to the album.
68
+ The pictures take the foot's room: each sits a little lower, so the group stands in the middle of the frame. */
69
+ .stamp--bare .stamp__cap, .stamp-on .stamp__cap, .post-corner .stamp__cap { display: none; }
70
+ .stamp--bare .stamp__art, .stamp-on .stamp__art, .post-corner .stamp__art { top: calc(var(--_y) + 9%); }
71
+
72
+ @container (max-width: 6rem) {
73
+ .stamp__words { display: none; }
74
+ .stamp__name { --_name: 12cqw; }
75
+ }
76
+
77
+ /* --tilt: turned a little on its middle — the one stamp a start screen hands over */
78
+ .stamp--tilt-left, .stamp--tilt-right { margin-block: var(--sp-4); } /* the turned corners and the shadow need room: a centre scrolls and would cut them */
79
+ .stamp--tilt-left { rotate: calc(-1 * var(--stamp-tilt, 5deg)); }
80
+ .stamp--tilt-right { rotate: var(--stamp-tilt, 5deg); }
81
+
82
+ /* --tap: the whole stamp is the button (`onClick`); the press and the ring are the PRESS list's (actions.css) */
83
+ .stamp--tap { appearance: none; border: 0; padding: 0; background: none; font: inherit; text-align: start; -webkit-tap-highlight-color: transparent; }
84
+
85
+ /* a stamp handed over in a Centre: sized by the SCREEN (a little over half its width inside the inset), its greeting centred under it */
86
+ .screen__centre:has(> .stamp) { justify-items: center; text-align: center; }
87
+ .screen__centre > .stamp { max-width: var(--stamp-centre-max-w, 56cqw); }
88
+
89
+ /* ---- stamp place: an empty place for a stamp — an album's gap, "make yours" ----
90
+ <span class="stamp-place">สร้าง</span> · <button class="stamp-place">…</button> · <span class="stamp-place stamp-place--faint"></span> */
91
+ .stamp-place {
92
+ display: grid;
93
+ place-content: center;
94
+ justify-items: center;
95
+ padding: var(--sp-1);
96
+ border: var(--rule-w) dashed var(--stamp-place-border, var(--on-surface-muted));
97
+ border-radius: var(--stamp-place-radius, var(--sp-2));
98
+ background: none;
99
+ color: var(--stamp-place-ink, var(--on-surface-muted));
100
+ font: var(--stamp-place-font, var(--type-caption));
101
+ text-align: center;
102
+ }
103
+ .card .stamp-place, .post-paper .stamp-place { border-color: var(--stamp-place-border, var(--card-muted)); color: var(--stamp-place-ink, var(--card-muted)); }
104
+ .stamp-place--faint { border-color: var(--stamp-place-faint-border, var(--hairline)); }
105
+
106
+ /* ---- stamp book: the album page — three stamps across on an album ground, who each is from under it ----
107
+ <div class="stamp-book">
108
+ <button class="stamp-cell"><span class="stamp">…</span><span class="stamp-cell__label">ต้น</span></button>
109
+ <span class="stamp-cell">…</span>
110
+ <span class="stamp-place stamp-place--faint" aria-hidden="true"></span>…
111
+ </div> */
112
+ .stamp-book {
113
+ display: grid;
114
+ grid-template-columns: repeat(3, minmax(0, 1fr));
115
+ align-items: start;
116
+ gap: var(--stamp-book-row-gap, var(--sp-4)) var(--stamp-book-col-gap, var(--sp-3));
117
+ padding: var(--stamp-book-pad, var(--sp-4));
118
+ border-radius: var(--stamp-book-radius, var(--r-media));
119
+ background-color: var(--stamp-book-bg, var(--ink-tint));
120
+ }
121
+ .stamp-cell {
122
+ position: relative;
123
+ display: grid;
124
+ gap: var(--stamp-cell-gap, var(--sp-2));
125
+ min-width: 0;
126
+ appearance: none;
127
+ border: 0;
128
+ padding: 0;
129
+ background: none;
130
+ color: var(--stamp-cell-ink, inherit);
131
+ font: var(--stamp-cell-font, var(--type-caption));
132
+ text-align: center;
133
+ -webkit-tap-highlight-color: transparent;
134
+ }
135
+ .stamp-cell__label { display: block; min-width: 0; overflow-wrap: anywhere; }
136
+ /* `on`: this one is in use (stuck on the note) — a filled disc with a check on its top corner */
137
+ .stamp-cell__on {
138
+ position: absolute;
139
+ top: 0;
140
+ right: 0;
141
+ display: grid;
142
+ place-items: center;
143
+ width: var(--stamp-cell-on-size, var(--icon));
144
+ aspect-ratio: 1;
145
+ border-radius: 50%;
146
+ background-color: var(--stamp-cell-on-bg, var(--accent));
147
+ color: var(--stamp-cell-on-ink, var(--on-accent));
148
+ }
149
+ .stamp-cell__on > .icon { width: 70%; height: 70%; }
150
+ /* --strip: ONE line of small stamps that scrolls sideways — the tray a member picks from. No ground. */
151
+ .stamp-book--strip {
152
+ --_strip: calc(var(--tap) * 1.5);
153
+ display: flex;
154
+ gap: var(--stamp-book-col-gap, var(--sp-3));
155
+ padding: var(--sp-2) 0;
156
+ border-radius: 0;
157
+ background: none;
158
+ overflow-x: auto;
159
+ overscroll-behavior-x: contain;
160
+ scrollbar-width: none;
161
+ }
162
+ .stamp-book--strip::-webkit-scrollbar { display: none; }
163
+ .stamp-book--strip > * { flex: none; width: var(--stamp-book-strip-w, var(--_strip)); }
164
+
165
+ /* ---- stamp on: a stamp stuck on a surface where the member put it ----
166
+ <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>
167
+ The surface is the nearest positioned box. --stamp-on-x / -y are the stamp's MIDDLE as a share of the surface (data, written by
168
+ the component); --move = the member may drag it (StampOn with `onAtChange`). */
169
+ .stamp-on {
170
+ position: absolute;
171
+ left: calc(var(--stamp-on-x, 0.5) * 100%);
172
+ top: calc(var(--stamp-on-y, 0.5) * 100%);
173
+ width: var(--stamp-on-w, 27%);
174
+ translate: -50% -50%;
175
+ rotate: calc(var(--stamp-on-turn, 0) * 1deg);
176
+ pointer-events: auto; /* the layer it lies in lets a tap through to the surface; the stamp itself takes it */
177
+ }
178
+ .stamp-on > .stamp { max-width: none; }
179
+ .stamp-on--move { cursor: grab; touch-action: none; -webkit-user-select: none; user-select: none; transition: scale var(--motion-press) ease-out; }
180
+ .stamp-on--move:focus-visible { outline: var(--focus); outline-offset: var(--sp-1); }
181
+ .stamp-on.is-held { cursor: grabbing; z-index: 1; scale: 1.06; } /* lifted off the paper while the finger holds it */
182
+ @media (prefers-reduced-motion: reduce) { .stamp-on.is-held { scale: 1; } }
package/css/step.css CHANGED
@@ -95,6 +95,9 @@
95
95
  It ends with the bottom layer's room, as a walk's page does: it scrolls only when the layer would cover its words
96
96
  (timebank onboard-04, 2026-09-27 — its last Link lay under the bar; Lh: same rule as the walk) */
97
97
  .step > .page { margin: var(--_lead, 0) var(--screen-pad) 0; padding-bottom: var(--bottom-h, 0rem); }
98
+ /* --bleed: the page's box runs to the screen's edges, the inset is its own padding — what leans, slides or casts a shadow past
99
+ the inset (a postcard) is cut at the glass, not at the inset; a little room on top for a turned corner. Nothing pans sideways. */
100
+ .step > .page--bleed { margin-inline: 0; padding-inline: var(--screen-pad); padding-block-start: var(--sp-2); overflow-x: hidden; }
98
101
 
99
102
  /* a WALK (Pages of Page) — Lh 2026-09-23, third call: no top; the picture and the words are ONE run that scrolls up together
100
103
  (the picture is never pinned). Each page starts at the screen's lead and ends with the same room under it — the lead as
package/css/sticky.css CHANGED
@@ -20,12 +20,14 @@
20
20
  --_fold: var(--sticky-fold, var(--sp-6));
21
21
  --_min: calc(var(--tap) * 3);
22
22
  --_cap: calc(var(--tap) * 7);
23
+ --_tall: calc(var(--tap) * 4.4);
23
24
  position: relative;
24
25
  display: grid;
25
26
  box-sizing: border-box;
26
27
  width: fit-content; /* hugs its words… */
27
28
  min-width: var(--sticky-min-w, var(--_min)); /* …but a word alone is still a note */
28
29
  max-width: var(--sticky-max-w, 100%);
30
+ 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 */
29
31
  padding: 0 var(--_fold) var(--_fold) 0; /* = the line above, written whole */
30
32
  background-clip: content-box;
31
33
  filter: drop-shadow(var(--sticky-drop, 0 var(--sp-1) var(--sp-2) rgb(0 0 0 / 0.16))); /* drop-shadow follows the cut; a box-shadow would draw the square */
@@ -71,6 +73,8 @@
71
73
  background-color: var(--sticky-fold-bg, color-mix(in srgb, currentColor 14%, transparent)); /* a darker shade of whatever the paper is */
72
74
  box-shadow: calc(-1 * var(--sp-0)) calc(-1 * var(--sp-0)) var(--sp-1) rgb(0 0 0 / 0.08);
73
75
  }
76
+ /* 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. */
77
+ .sticky__stuck { position: absolute; inset: 0; pointer-events: none; }
74
78
  .sticky--flat > .sticky__paper { clip-path: none; }
75
79
  .sticky--flat > .sticky__paper > .sticky__foot { padding-inline-end: 0; }
76
80
 
@@ -113,6 +117,16 @@
113
117
  mask: radial-gradient(circle at 100% 100%, transparent calc(var(--_notch) - var(--border-w)), #000 var(--_notch));
114
118
  }
115
119
 
120
+ /* 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
121
+ keep clear of the edges on any phone. cqw reads the fill screen (the size container). After --square, so it wins. */
122
+ .sticky--square.sticky--tilt-left, .sticky--square.sticky--tilt-right { max-width: var(--sticky-tilt-max-w, 75cqw); }
123
+
124
+ /* --tap: the whole note is the button (`onClick`). The fold stays; the ring follows the note's turn. */
125
+ .sticky--tap { appearance: none; border: 0; font: inherit; text-align: start; cursor: pointer; -webkit-tap-highlight-color: transparent; }
126
+ .sticky--tap .sticky__body, .sticky--tap .sticky__foot { display: block; }
127
+ .sticky--tap:focus-visible { outline: var(--focus); outline-offset: var(--sp-1); }
128
+ .sticky--tap:active > .sticky__paper { translate: 0 var(--sp-0); }
129
+
116
130
  /* ---- sticky field: the words written ON a note — a bare textarea in the note's type and ink, filling it ----
117
131
  <div class="sticky__body"><textarea class="sticky-field" aria-label="Note" placeholder="Add text to this note"></textarea></div> */
118
132
  .sticky__body:has(> .sticky-field) { display: grid; }