@usableapp/cardds 0.7.92 → 0.7.94
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 +34 -0
- package/README.md +10 -5
- package/css/actions.css +33 -17
- package/css/base.css +1 -1
- package/css/card.css +1 -1
- package/css/choice.css +16 -5
- package/css/sheet.css +68 -5
- package/css/stamp.css +8 -1
- package/css/tokens.css +4 -1
- package/dist/cardds.css +131 -31
- package/dist/cards/Card.d.ts +2 -1
- package/dist/cards/CardParts.d.ts +2 -1
- package/dist/cards/CardParts.js +2 -1
- package/dist/catalog.json +1 -1
- package/dist/choice/DayStrip.d.ts +5 -3
- package/dist/choice/DayStrip.js +4 -4
- package/dist/forms/Composer.d.ts +9 -3
- package/dist/forms/Composer.js +8 -3
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/media/MapArea.d.ts +12 -6
- package/dist/media/MapArea.js +8 -6
- package/dist/media/MapPick.d.ts +32 -0
- package/dist/media/MapPick.js +13 -0
- package/dist/scaffold/ActionBar.d.ts +7 -3
- package/dist/scaffold/ActionBar.js +5 -1
- package/dist/stamp/StampBook.d.ts +4 -2
- package/dist/stamp/StampBook.js +3 -3
- package/lint/eslint.mjs +1 -1
- package/lint/rules.mjs +11 -0
- package/package.json +1 -1
package/dist/cardds.css
CHANGED
|
@@ -120,7 +120,10 @@
|
|
|
120
120
|
|
|
121
121
|
/* ---- radius ---- */
|
|
122
122
|
--r-chip: 999px; /* pills, chips, buttons — always fully round */
|
|
123
|
-
--r-card: calc(var(--r-base) * 2); /* 41.6 the one card radius: every card,
|
|
123
|
+
--r-card: calc(var(--r-base) * 2); /* 41.6 the one card radius: every card, tile, menu, sheet, fab — but a row card (--r-card-row) */
|
|
124
|
+
--r-card-row: calc(var(--r-base) * 0.625); /* 13 a row card's corner (Lh 2026-10-17: a small card's corner shrinks to keep the big card's PROPORTION). Measured at 375:
|
|
125
|
+
whole cards stand 186–437 tall, corner/height 0.095–0.224 (Card · Skeleton 0.122); a two-line row stands 88, so its
|
|
126
|
+
corner is 11–20 — at 41.6 it was 0.475, a pill. 13 = 0.148 of 88. On --r-base, so a square theme squares it too */
|
|
124
127
|
--r-media: var(--r-base); /* 20.8 images inside cards */
|
|
125
128
|
--r-control: calc(var(--r-base) * 0.875); /* 18.2 fields, thumbs, menu rows */
|
|
126
129
|
--r-badge: calc(var(--r-base) * 0.625); /* 13 tile badge, bars */
|
|
@@ -485,7 +488,7 @@
|
|
|
485
488
|
the member wants to copy), and inputs are untouched. Native buttons and
|
|
486
489
|
links are matched by element; the rest by the class that makes them one */
|
|
487
490
|
button, [role="button"], [role="tab"], [role="option"], [role="menuitem"], a.btn, a.icon-btn, a.chip, label.chip, .chip--pick,
|
|
488
|
-
.segment__item, .day, .calendar__day, .mood__opt, .pin__cell, .slider, .picker__item, .float-bar__item, .menu__item, .sheet__handle, .track__step, .pager__at {
|
|
491
|
+
.segment__item, .day, .calendar__day, .mood__opt, .pin__cell, .slider, .picker__item, .float-bar__item, .menu__item, .sheet__handle, .track__step, .pager__at, .map-pick {
|
|
489
492
|
user-select: none;
|
|
490
493
|
-webkit-user-select: none;
|
|
491
494
|
-webkit-touch-callout: none;
|
|
@@ -992,7 +995,7 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
|
|
|
992
995
|
.card-list { display: grid; gap: var(--card-list-gap, var(--sp-3)); }
|
|
993
996
|
|
|
994
997
|
.card--row {
|
|
995
|
-
border-radius: var(--card-row-radius, var(--r-card));
|
|
998
|
+
border-radius: var(--card-row-radius, var(--r-card-row)); /* small: the big card's corner in proportion, not its size */
|
|
996
999
|
padding: var(--card-row-pad, var(--sp-4));
|
|
997
1000
|
display: flex;
|
|
998
1001
|
align-items: center;
|
|
@@ -1980,8 +1983,7 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
|
|
|
1980
1983
|
repeating-linear-gradient(-18deg, transparent 0 8.75rem, var(--ink-tint) 8.75rem 9.25rem),
|
|
1981
1984
|
var(--card-2-bg);
|
|
1982
1985
|
}
|
|
1983
|
-
.map > :first-child { position: absolute; inset: 0; z-index: 0; isolation: isolate; } /* its own stacking context: an engine's layered panes stay under the ring */
|
|
1984
|
-
.sheet-stage__bg .map > :first-child { background: transparent; } /* an engine's own grey ground would hide the pattern while tiles load */
|
|
1986
|
+
.map > :first-child { position: absolute; inset: 0; z-index: 0; isolation: isolate; background: transparent; } /* its own stacking context: an engine's layered panes stay under the ring; an engine's own grey ground would hide the pattern while tiles load */
|
|
1985
1987
|
.map__ring {
|
|
1986
1988
|
position: absolute;
|
|
1987
1989
|
left: 50%;
|
|
@@ -2013,9 +2015,10 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
|
|
|
2013
2015
|
.map__hint {
|
|
2014
2016
|
position: absolute;
|
|
2015
2017
|
top: calc(var(--_top, 0rem) + var(--sp-3));
|
|
2016
|
-
left:
|
|
2017
|
-
|
|
2018
|
-
|
|
2018
|
+
/* centred by its two sides, not left 50% + translate: that left the words only half the map to wrap in, so a short hint broke onto two lines */
|
|
2019
|
+
inset-inline: var(--sp-4);
|
|
2020
|
+
width: fit-content;
|
|
2021
|
+
margin-inline: auto;
|
|
2019
2022
|
padding: var(--sp-2) var(--sp-4);
|
|
2020
2023
|
border-radius: var(--map-hint-radius, var(--r-chip));
|
|
2021
2024
|
background: var(--map-hint-bg, var(--card-3-bg));
|
|
@@ -2027,6 +2030,69 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
|
|
|
2027
2030
|
z-index: 1;
|
|
2028
2031
|
}
|
|
2029
2032
|
|
|
2033
|
+
/* ---- the map IN FLOW (Lh 2026-10-17): `.map--inline` — a box in a card, or the whole of a sheet's body ----
|
|
2034
|
+
<div class="sheet__body"><div class="map map--inline"><div>…the engine…</div><label class="map-pick" …>…</label>…
|
|
2035
|
+
<span class="map__ring" …></span></div></div>
|
|
2036
|
+
Choosing where to meet without leaving the sheet: the open sheet becomes the map and its head stays on top (a stage
|
|
2037
|
+
behind a half sheet covers the head and changes the look). No stage, so no band and no bar: the ring is at the centre
|
|
2038
|
+
of the map's OWN box and the hint at its own top. In a card it is a rounded media box; as a SheetBody's only child it
|
|
2039
|
+
fills the body (the part above the foot), however far the sheet slid. */
|
|
2040
|
+
.map--inline {
|
|
2041
|
+
--_top: 0rem;
|
|
2042
|
+
--_band-centre: 50%;
|
|
2043
|
+
position: relative;
|
|
2044
|
+
min-height: var(--map-inline-h, calc(var(--map-ring) * 3 / 2));
|
|
2045
|
+
border-radius: var(--map-radius, var(--r-media));
|
|
2046
|
+
overflow: hidden;
|
|
2047
|
+
}
|
|
2048
|
+
.sheet__body:has(> .map--inline:only-child) { display: flex; flex-direction: column; }
|
|
2049
|
+
.sheet__body > .map--inline:only-child { flex: 1 0 auto; }
|
|
2050
|
+
|
|
2051
|
+
/* ---- map pick: a place on the map the member taps to choose it (Lh 2026-10-17) ----
|
|
2052
|
+
<label class="map-pick" style="top: 30%; left: 40%"><input type="radio" name="meet" value="library">
|
|
2053
|
+
<span class="map-pick__mark">{icon}</span><span class="map-pick__name">ห้องสมุด</span></label>
|
|
2054
|
+
A small round mark on its point and the place's short name under it — small, so five fit a phone's map (a Callout
|
|
2055
|
+
is a card: five crowd it). The label is a --tap square centred on the point: the tap is never smaller than the
|
|
2056
|
+
control floor however small the mark is drawn, and the name takes a tap too. The radios of one choice share a
|
|
2057
|
+
name; the picked one fills with accent. Above the ring: the ring takes no taps, the places do. */
|
|
2058
|
+
.map-pick {
|
|
2059
|
+
position: absolute;
|
|
2060
|
+
z-index: 2;
|
|
2061
|
+
width: var(--tap);
|
|
2062
|
+
height: var(--tap);
|
|
2063
|
+
translate: -50% -50%;
|
|
2064
|
+
display: grid;
|
|
2065
|
+
place-items: center;
|
|
2066
|
+
color: var(--map-pick-ink, var(--on-surface));
|
|
2067
|
+
}
|
|
2068
|
+
.map-pick__mark {
|
|
2069
|
+
display: grid;
|
|
2070
|
+
place-items: center;
|
|
2071
|
+
width: var(--map-pick-size, var(--sp-6));
|
|
2072
|
+
height: var(--map-pick-size, var(--sp-6));
|
|
2073
|
+
border-radius: 50%;
|
|
2074
|
+
border: var(--border-w) solid var(--map-pick-border, var(--accent));
|
|
2075
|
+
background: var(--map-pick-bg, var(--surface));
|
|
2076
|
+
color: var(--map-pick-mark-ink, var(--accent));
|
|
2077
|
+
box-shadow: var(--map-pick-shadow, var(--shadow-float));
|
|
2078
|
+
pointer-events: none;
|
|
2079
|
+
}
|
|
2080
|
+
.map-pick__name {
|
|
2081
|
+
position: absolute;
|
|
2082
|
+
top: calc(50% + var(--map-pick-size, var(--sp-6)) / 2 + var(--sp-1));
|
|
2083
|
+
left: 50%;
|
|
2084
|
+
translate: -50% 0;
|
|
2085
|
+
white-space: nowrap;
|
|
2086
|
+
padding: 0 var(--sp-2);
|
|
2087
|
+
border-radius: var(--map-pick-name-radius, var(--r-chip));
|
|
2088
|
+
background: var(--map-pick-name-bg, color-mix(in srgb, var(--surface) 85%, transparent));
|
|
2089
|
+
font: var(--map-pick-font, var(--type-caption));
|
|
2090
|
+
}
|
|
2091
|
+
.map-pick:has(:checked) { z-index: 3; } /* the picked place's name lies over a neighbour's */
|
|
2092
|
+
.map-pick:has(:checked) > :is(.map-pick__mark, .map-pick__name) { background: var(--map-pick-on-bg, var(--accent)); color: var(--map-pick-on-ink, var(--on-accent)); }
|
|
2093
|
+
.map-pick:has(:focus-visible) > .map-pick__mark { outline: var(--focus); outline-offset: var(--sp-0); }
|
|
2094
|
+
.map-pick:has(:disabled) { opacity: var(--off); cursor: default; }
|
|
2095
|
+
|
|
2030
2096
|
/* EVERY sheet has one shape (Lh, 2026-09-21): the handle and the head stay at the top and never scroll · the
|
|
2031
2097
|
foot's button stands at the bottom, and ABOVE the keyboard when there is one · everything between them
|
|
2032
2098
|
scrolls, as far as it needs to. In a .step the keyboard's room is the step's (--kb, step.css); on a stage
|
|
@@ -2740,18 +2806,24 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
|
|
|
2740
2806
|
.action-bar .btn { flex: 1; box-shadow: var(--shadow-float); }
|
|
2741
2807
|
.action-bar .icon-btn { width: var(--btn-h); height: var(--btn-h); box-shadow: var(--shadow-float); }
|
|
2742
2808
|
|
|
2743
|
-
/* ---- pager: previous / next as two
|
|
2809
|
+
/* ---- pager: previous / next as two peers at the two edges ----
|
|
2744
2810
|
For a sequence you can walk BOTH ways — a three-card feature intro, a step
|
|
2745
2811
|
flow. Use it instead of the default pack whenever going back is as ordinary
|
|
2746
2812
|
as going on: a wide CTA beside a small round icon reads as one action plus
|
|
2747
2813
|
an afterthought, which is wrong when the two are peers.
|
|
2748
2814
|
|
|
2749
|
-
The two are the same
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2815
|
+
The two are the same shape and size, one at each edge in thumb reach from
|
|
2816
|
+
either side; the fill alone leans forward. Two ways to draw them, both
|
|
2817
|
+
valid: two round .icon-btn (an arrow is the whole meaning), or two .btn
|
|
2818
|
+
that SAY the step each leads to, the arrow beside the name ("← คำขอ",
|
|
2819
|
+
"วันเวลา →"; Lh 2026-10-17, lifting the 2026-09-16 "never words"). Worded,
|
|
2820
|
+
they read as LEFT and RIGHT like the round pair (Lh 2026-10-17, second
|
|
2821
|
+
call): each hugs its edge at its own size (its words + the arrow, no
|
|
2822
|
+
stretch, so two widths are normal), open ground between them, and the
|
|
2823
|
+
arrow stays the round pager's size (the md .icon, not xs). The words are
|
|
2824
|
+
a STEP's name, a direction: a word that commits ("Get started", "Done")
|
|
2825
|
+
is not a pager button — that step goes back to the plain .action-bar
|
|
2826
|
+
with one wide button. Where you are is said by the .pager__at dots — under the card
|
|
2755
2827
|
that changes (a .screen__centre group, card.css) for a card walk, never in
|
|
2756
2828
|
that bar (Lh, 2026-09-12); a walk of words instead floats its dots as the
|
|
2757
2829
|
bar's own first row (step.css, Lh 2026-09-23) — either way the dots move
|
|
@@ -2760,7 +2832,11 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
|
|
|
2760
2832
|
<div class="action-bar action-bar--pager">
|
|
2761
2833
|
<button class="icon-btn" aria-label="ย้อนกลับ" disabled>…</button>
|
|
2762
2834
|
<button class="icon-btn icon-btn--invert" aria-label="ถัดไป">…</button>
|
|
2763
|
-
</div> — or the same two in an .action-bar__tier--pager under a control
|
|
2835
|
+
</div> — or the same two in an .action-bar__tier--pager under a control
|
|
2836
|
+
<div class="action-bar action-bar--pager">
|
|
2837
|
+
<button class="btn"><svg class="icon">…</svg> คำขอ</button>
|
|
2838
|
+
<button class="btn btn--primary">วันเวลา <svg class="icon">…</svg></button>
|
|
2839
|
+
</div> — worded: each at its edge, its own size; a skip link between stays centred */
|
|
2764
2840
|
.action-bar--pager { align-items: center; }
|
|
2765
2841
|
/* The bar belongs to the BASE: the move of a page of words — a pager turning them, or one wide button. A screen
|
|
2766
2842
|
with a sheet finishes on the sheet's own foot instead (sheet.css). Guidance for composing, not a rule the
|
|
@@ -2798,11 +2874,17 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
|
|
|
2798
2874
|
:has(> .action-bar--tiers > .action-bar__tier:nth-child(4)) { --bar-reserve: calc(3 * (var(--tap) + var(--sp-3)) + var(--btn-h) + var(--sp-3) + var(--sp-5) + var(--sp-6) + var(--safe-bottom)); }
|
|
2799
2875
|
:has(> .action-bar--tiers > .action-bar__tier:nth-child(5)) { --bar-reserve: calc(4 * (var(--tap) + var(--sp-3)) + var(--btn-h) + var(--sp-3) + var(--sp-5) + var(--sp-6) + var(--safe-bottom)); }
|
|
2800
2876
|
|
|
2801
|
-
/* the first round
|
|
2802
|
-
|
|
2877
|
+
/* the first button (round or worded) sits at the left edge, the last at the right; a skip link between them stays centred.
|
|
2878
|
+
A worded one keeps its own size here, not the plain bar's stretch: left and right, open ground between (Lh 2026-10-17) */
|
|
2879
|
+
:is(.action-bar--pager, .action-bar__tier--pager) > .btn { flex: 0 0 auto; }
|
|
2880
|
+
:is(.action-bar--pager, .action-bar__tier--pager) > :is(.icon-btn, .btn):first-child { margin-right: auto; }
|
|
2803
2881
|
/* …and whatever goes BETWEEN the two (a "skip" link) stands in the middle: the bar places it, never the link itself */
|
|
2804
|
-
:is(.action-bar--pager, .action-bar__tier--pager) > :not(.icon-btn):not(:first-child):not(:last-child) { margin-inline: auto; }
|
|
2805
|
-
:is(.action-bar--pager, .action-bar__tier--pager):has(> :nth-child(3)) > .icon-btn:first-child { margin-right: 0; }
|
|
2882
|
+
:is(.action-bar--pager, .action-bar__tier--pager) > :not(.icon-btn, .btn):not(:first-child):not(:last-child) { margin-inline: auto; }
|
|
2883
|
+
:is(.action-bar--pager, .action-bar__tier--pager):has(> :nth-child(3)) > :is(.icon-btn, .btn):first-child { margin-right: 0; }
|
|
2884
|
+
/* with a link between, three columns: two worded buttons are two widths, and only even side columns keep the link at the bar's middle */
|
|
2885
|
+
:is(.action-bar--pager, .action-bar__tier--pager):has(> :nth-child(3)) { display: grid; grid-template-columns: 1fr auto 1fr; }
|
|
2886
|
+
:is(.action-bar--pager, .action-bar__tier--pager):has(> :nth-child(3)) > :first-child { justify-self: start; }
|
|
2887
|
+
:is(.action-bar--pager, .action-bar__tier--pager):has(> :nth-child(3)) > :last-child { justify-self: end; }
|
|
2806
2888
|
|
|
2807
2889
|
|
|
2808
2890
|
/* ---- action note (Lh 2026-09-24): the main button's place, the main button's size, but ON the ground — no fill, no border, no
|
|
@@ -2837,7 +2919,7 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
|
|
|
2837
2919
|
button's, the card itself is never focused or disabled. */
|
|
2838
2920
|
:where(.btn, .icon-btn, .link, a.chip, button.chip, .chip--pick, a.tile, button.tile, .tile--pick, .day, .segment__item, .calendar__day,
|
|
2839
2921
|
.float-bar__item, .avatar-pick__item, .add-row, .picker__item, .dropdown__btn, .appbar__who, .check, .toggle, .mood__opt, .sheet__handle,
|
|
2840
|
-
a.avatar, button.avatar, .menu__item, button.snackbar__body, .stamp--tap, button.stamp-cell, button.stamp-place, .post-letter__turn, .post-desk__slot, .post-desk__pick, .post-desk__reach, .stamp-on__remove) {
|
|
2922
|
+
a.avatar, button.avatar, .menu__item, button.snackbar__body, .stamp--tap, button.stamp-cell, button.stamp-place, .post-letter__turn, .post-desk__slot, .post-desk__pick, .post-desk__reach, .stamp-on__remove, .map-pick) {
|
|
2841
2923
|
cursor: pointer;
|
|
2842
2924
|
touch-action: manipulation;
|
|
2843
2925
|
transition: scale var(--motion-press) ease-out;
|
|
@@ -2849,14 +2931,14 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
|
|
|
2849
2931
|
}
|
|
2850
2932
|
/* a CHOICE's fill fades in as it is picked (a plain button's colour never changes on a tap, so it does not fade) */
|
|
2851
2933
|
:where(.chip--pick, button.chip, .tile--pick, button.tile, .day, .segment__item, .calendar__day, .float-bar__item, .picker__item, .check,
|
|
2852
|
-
.icon-btn[role="tab"], .avatar-pick__item > .avatar) {
|
|
2934
|
+
.icon-btn[role="tab"], .avatar-pick__item > .avatar, .map-pick > .map-pick__mark, .map-pick > .map-pick__name) {
|
|
2853
2935
|
transition-property: scale, background-color, color, border-color, opacity;
|
|
2854
2936
|
transition-duration: var(--motion-press);
|
|
2855
2937
|
transition-timing-function: ease-out;
|
|
2856
2938
|
}
|
|
2857
2939
|
:where(.btn, .icon-btn, .link, a.chip, button.chip, .chip--pick, a.tile, button.tile, .tile--pick, .day, .segment__item, .calendar__day,
|
|
2858
2940
|
.float-bar__item, .avatar-pick__item, .add-row, .picker__item, .dropdown__btn, .appbar__who, .check, .toggle, .mood__opt, .sheet__handle,
|
|
2859
|
-
a.avatar, button.avatar, .menu__item, button.snackbar__body, .stamp--tap, button.stamp-cell, button.stamp-place, .post-letter__turn, .post-desk__slot, .post-desk__pick, .post-desk__reach, .stamp-on__remove):active:not(:disabled, [aria-disabled="true"], :has(:disabled)) { scale: var(--press-scale); }
|
|
2941
|
+
a.avatar, button.avatar, .menu__item, button.snackbar__body, .stamp--tap, button.stamp-cell, button.stamp-place, .post-letter__turn, .post-desk__slot, .post-desk__pick, .post-desk__reach, .stamp-on__remove, .map-pick):active:not(:disabled, [aria-disabled="true"], :has(:disabled)) { scale: var(--press-scale); }
|
|
2860
2942
|
:where(a.row, button.row, label.row, .row-expand > summary, .banner__summary, a.card, label.card, .card--go, .feed-card--small, .toggle-field, .post-box__edge):active:not([aria-disabled="true"], :has(:disabled)) { opacity: var(--press-dim); }
|
|
2861
2943
|
.sheet-step:has(> .sheet-step__go:active) { opacity: var(--press-dim); } /* the step bar's button is invisible over it: the bar answers */
|
|
2862
2944
|
/* a pile of notes pressed whole (Lh 2026-10-11): the button lies invisible UNDER the notes, so it is the notes that answer — DIM, as a card does (the group dims as one, the
|
|
@@ -2869,11 +2951,11 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
|
|
|
2869
2951
|
it darkens a touch instead (--press-shade) */
|
|
2870
2952
|
:where(.sheet-stack--tap > .card:not(.is-open), .postcard__turn, .post-letter__sheet:not(:has(.icon-btn:active))) { cursor: pointer; touch-action: manipulation; transition: filter var(--motion-press) ease-out; }
|
|
2871
2953
|
:where(.sheet-stack--tap > .card:not(.is-open), .postcard__turn, .post-letter__sheet:not(:has(.icon-btn:active))):active { filter: brightness(var(--press-shade)); }
|
|
2872
|
-
/* the focus ring: on the control, or on the label that wraps a hidden input (chip, tile, file button, a row that is a label) */
|
|
2954
|
+
/* the focus ring: on the control, or on the label that wraps a hidden input (chip, tile, file button, a row that is a label, a card that is a label round its radio) */
|
|
2873
2955
|
:where(.btn, .icon-btn, .link, a.chip, button.chip, .chip--pick, a.tile, button.tile, .tile--pick, .day, .segment__item, .calendar__day,
|
|
2874
2956
|
.float-bar__item, .avatar-pick__item, .add-row, .picker__item, .dropdown__btn, .appbar__who, .check, .toggle, .mood__opt, .sheet__handle,
|
|
2875
2957
|
a.avatar, button.avatar, .menu__item, button.snackbar__body, .stamp--tap, button.stamp-cell, button.stamp-place, .post-letter__turn, .post-desk__slot, .post-desk__pick, .post-desk__reach, .stamp-on__remove):focus-visible,
|
|
2876
|
-
:where(.chip--pick, .tile--pick, label.btn, label.row, .toggle-field):has(:focus-visible) { outline: var(--focus); outline-offset: var(--sp-1); }
|
|
2958
|
+
:where(.chip--pick, .tile--pick, label.btn, label.row, .toggle-field):has(:focus-visible), :where(label.card:has(> input[type="radio"]:focus-visible)) { outline: var(--focus); outline-offset: var(--sp-1); }
|
|
2877
2959
|
:where(a.row, button.row, label.row, .row-expand > summary, .banner__summary, a.card, label.card, .feed-card--small, .toggle-field, .post-box__edge):not(label, .toggle-field):focus-visible { outline: var(--focus); outline-offset: var(--sp-1); }
|
|
2878
2960
|
/* disabled: no pointer anywhere; a control fades (a link and a row keep their own muted look) */
|
|
2879
2961
|
:where(.btn, .icon-btn, .link, a.chip, button.chip, .chip--pick, a.tile, button.tile, .tile--pick, .day, .segment__item, .calendar__day,
|
|
@@ -3334,8 +3416,9 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
|
|
|
3334
3416
|
.chip-grid > .chip { justify-self: stretch; justify-content: center; min-height: var(--btn-h); padding-inline: var(--sp-2); }
|
|
3335
3417
|
.chip--pick { position: relative; } /* the input covers the whole chip, on a row as in a grid */
|
|
3336
3418
|
/* the hidden input, the same shape wherever a native radio/checkbox drives a picked look:
|
|
3337
|
-
a chip, a mood dot, a tile (media.css), a sticky's tone swatch (sticky.css)
|
|
3338
|
-
|
|
3419
|
+
a chip, a mood dot, a tile (media.css), a sticky's tone swatch (sticky.css), a place on a map (sheet.css), a card that is a label round a radio
|
|
3420
|
+
(a pickable row card: the app gives the picked one its `tone`) — the native input lies over its whole box, unseen */
|
|
3421
|
+
:is(.chip--pick, .mood__opt, .tile--pick, .sticky-pick__swatch, .map-pick) > input, label.card > input[type="radio"] { appearance: none; position: absolute; inset: 0; margin: 0; opacity: 0; cursor: inherit; }
|
|
3339
3422
|
:is(.chip--pick, .tile--pick):has(:checked) { background: var(--accent); color: var(--on-accent); border-color: transparent; }
|
|
3340
3423
|
/* --sign: the trailing + that turns 45° into an × when picked — one mask, one rotate, no swap (Lh 2026-09-16) */
|
|
3341
3424
|
.chip--sign { padding-right: var(--sp-2); }
|
|
@@ -3351,7 +3434,7 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
|
|
|
3351
3434
|
.chip--sign:has(:checked)::after { rotate: 45deg; }
|
|
3352
3435
|
@media (prefers-reduced-motion: no-preference) { .chip--sign::after { transition: rotate var(--motion-slide); } }
|
|
3353
3436
|
|
|
3354
|
-
/* ---- day strip: a week, one day selected ----
|
|
3437
|
+
/* ---- day strip: a week, one day selected, today a light tone ----
|
|
3355
3438
|
<div class="day-strip" role="tablist"><button class="day" role="tab" aria-selected="true"><span class="day__name">Thu</span><span class="day__num">16</span></button>…</div> */
|
|
3356
3439
|
.day-strip { display: grid; grid-template-columns: repeat(7, 1fr); gap: var(--day-strip-gap, var(--sp-1)); }
|
|
3357
3440
|
.day {
|
|
@@ -3374,6 +3457,8 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
|
|
|
3374
3457
|
}
|
|
3375
3458
|
.day__name { font: var(--day-name-font, var(--type-caption)); }
|
|
3376
3459
|
.day__num { font: 700 var(--fs-lg)/1.1 var(--font-display); font-variant-numeric: tabular-nums; }
|
|
3460
|
+
/* today: a light tone, no louder than a rest; the selected pill below wins when it is both (it comes after and weighs more) */
|
|
3461
|
+
.day--today { background: var(--day-today-bg, var(--ink-tint)); color: var(--day-today-ink, currentColor); }
|
|
3377
3462
|
.day[aria-selected="true"] { background: var(--day-selected-bg, var(--accent)); color: var(--day-selected-ink, var(--on-accent)); opacity: 1; }
|
|
3378
3463
|
.day__dot { grid-row: 3; align-self: center; width: var(--day-dot-size, var(--dot-xs)); height: var(--day-dot-size, var(--dot-xs)); border-radius: 50%; background: currentColor; }
|
|
3379
3464
|
|
|
@@ -3487,11 +3572,13 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
|
|
|
3487
3572
|
|
|
3488
3573
|
/* ---- composer: big text area with a bottom bar (icon · hint · send) ----
|
|
3489
3574
|
<div class="composer"><textarea class="composer__input" placeholder="What do you need?"></textarea>
|
|
3490
|
-
<div class="composer__bar"><button class="icon-btn">…</button><span class="composer__hint">Your idea is born</span><button class="icon-btn icon-btn--invert">↑</button></div></div>
|
|
3575
|
+
<div class="composer__bar"><button class="icon-btn">…</button><span class="composer__hint">Your idea is born</span><button class="icon-btn icon-btn--invert">↑</button></div></div>
|
|
3576
|
+
A second thing to write (the reason under the request) is <textarea class="composer__input composer__area"> after the
|
|
3577
|
+
first: the same type, shorter, and the area draws its own dashed rule above it (no selector looks at what sits before it). */
|
|
3491
3578
|
.composer { display: grid; gap: var(--composer-gap, var(--sp-3)); }
|
|
3492
3579
|
.composer__input {
|
|
3493
3580
|
width: 100%;
|
|
3494
|
-
min-height: 11rem;
|
|
3581
|
+
min-height: var(--composer-input-min-h, 11rem);
|
|
3495
3582
|
resize: none;
|
|
3496
3583
|
border: 0;
|
|
3497
3584
|
padding: 0;
|
|
@@ -3502,6 +3589,12 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
|
|
|
3502
3589
|
outline: none;
|
|
3503
3590
|
}
|
|
3504
3591
|
.composer__input::placeholder { color: inherit; opacity: var(--off); }
|
|
3592
|
+
.composer__area {
|
|
3593
|
+
box-sizing: content-box; /* its min-height is its words alone: the rule and the room under it come on top */
|
|
3594
|
+
min-height: var(--composer-area-min-h, 2lh);
|
|
3595
|
+
padding-block-start: var(--composer-area-pad, var(--sp-3));
|
|
3596
|
+
border-block-start: var(--rule-w) dashed var(--composer-area-border, var(--card-muted)); /* the rule: the hint's ink, the system's rule width */
|
|
3597
|
+
}
|
|
3505
3598
|
.composer__bar { display: flex; align-items: center; justify-content: space-between; gap: var(--composer-bar-gap, var(--sp-3)); }
|
|
3506
3599
|
.composer__hint { font: var(--composer-hint-font, var(--type-caption)); color: var(--composer-hint-ink, var(--card-muted)); }
|
|
3507
3600
|
|
|
@@ -4226,7 +4319,8 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
|
|
|
4226
4319
|
(one tap: half the stamp), for a stamp stuck ON something (`.stamp-on`, below), a stamp in an avatar stack (people.css) and a stamp
|
|
4227
4320
|
at the head of a feed card (`.feed-card__lead`, card.css): one knob for the three.
|
|
4228
4321
|
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,
|
|
4229
|
-
--post-corner-stamp-w, in neither. The desk's tray (post.css) holds stamps of the standard size.
|
|
4322
|
+
--post-corner-stamp-w, in neither. The desk's tray (post.css) holds stamps of the standard size.
|
|
4323
|
+
THE THIRD SIZE (Lh 2026-10-17): `.stamp-book--fill` (below) makes each stamp as wide as its third, the gaps one --screen-pad. */
|
|
4230
4324
|
.stamp, .stamp-place {
|
|
4231
4325
|
box-sizing: border-box;
|
|
4232
4326
|
width: var(--stamp-size, calc(var(--tap) * 2));
|
|
@@ -4392,6 +4486,12 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
|
|
|
4392
4486
|
/* --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.
|
|
4393
4487
|
<div class="stamp-book stamp-book--bare"> */
|
|
4394
4488
|
.stamp-book--bare { padding: 0; border-radius: 0; background: none; }
|
|
4489
|
+
/* --fill: the THIRD SIZE of a stamp (Lh 2026-10-17) — each stamp as wide as its third, 4:5, the gaps between the thirds one
|
|
4490
|
+
--screen-pad both ways, so the row is three stamps and two gaps and nothing at its sides. At 375 in a 343 column, bare:
|
|
4491
|
+
(343 − 2 × 16) / 3 = 103.67 × 129.58. The one place a stamp is not --stamp-size: the book sizes its stamps here.
|
|
4492
|
+
<div class="stamp-book stamp-book--bare stamp-book--fill"> */
|
|
4493
|
+
.stamp-book--fill { gap: var(--stamp-book-fill-gap, var(--screen-pad)); }
|
|
4494
|
+
.stamp-book--fill > .stamp-place, .stamp-book--fill > .stamp-cell > .stamp { width: 100%; }
|
|
4395
4495
|
/* --strip: ONE line of stamps that scrolls sideways — the tray a member picks from, each stamp its own size. No ground. */
|
|
4396
4496
|
.stamp-book--strip {
|
|
4397
4497
|
display: flex;
|
package/dist/cards/Card.d.ts
CHANGED
|
@@ -11,7 +11,8 @@ export interface CardProps extends ComponentProps<'article'> {
|
|
|
11
11
|
paper?: boolean;
|
|
12
12
|
/** compact: a small card inside a card or a sheet body (a note, a promo) */
|
|
13
13
|
sm?: boolean;
|
|
14
|
-
/** a list row that is its own card: thumb · body · end, in a CardList
|
|
14
|
+
/** a list row that is its own card: thumb · body · end, in a CardList. Its corner is the big card's PROPORTION, not its size (`--r-card-row`, 13; knob `--card-row-radius`).
|
|
15
|
+
* Pickable: `as="label"` round a radio (`<input type="radio">`, unseen, over the whole card) and the app gives the picked one its `tone` */
|
|
15
16
|
row?: boolean;
|
|
16
17
|
/** the image IS the card: a Placeholder or img first, text over a scrim */
|
|
17
18
|
cover?: boolean;
|
|
@@ -17,7 +17,8 @@ export interface CardEndProps extends ComponentProps<'div'> {
|
|
|
17
17
|
export declare function CardEnd({ className, ...rest }: CardEndProps): import("react").JSX.Element;
|
|
18
18
|
export interface CardListProps extends ComponentProps<'div'> {
|
|
19
19
|
}
|
|
20
|
-
/** CardList — a stack of `Card row`s, each its own boundary.
|
|
20
|
+
/** CardList — a stack of `Card row`s, each its own boundary: a list of things to open or to pick (past requests to reuse). It stands on the base or straight in a sheet's
|
|
21
|
+
* body and scrolls with it; never inside a card (a card never wraps a card — `cardds check` rule `card-in-card`). Rows inside a card are `Rows`. */
|
|
21
22
|
export declare function CardList({ className, ...rest }: CardListProps): import("react").JSX.Element;
|
|
22
23
|
export interface IconRowProps extends ComponentProps<'span'> {
|
|
23
24
|
}
|
package/dist/cards/CardParts.js
CHANGED
|
@@ -16,7 +16,8 @@ export function CardThumb({ className, ...rest }) {
|
|
|
16
16
|
export function CardEnd({ className, ...rest }) {
|
|
17
17
|
return _jsx("div", { className: cx('card__end', className), ...rest });
|
|
18
18
|
}
|
|
19
|
-
/** CardList — a stack of `Card row`s, each its own boundary.
|
|
19
|
+
/** CardList — a stack of `Card row`s, each its own boundary: a list of things to open or to pick (past requests to reuse). It stands on the base or straight in a sheet's
|
|
20
|
+
* body and scrolls with it; never inside a card (a card never wraps a card — `cardds check` rule `card-in-card`). Rows inside a card are `Rows`. */
|
|
20
21
|
export function CardList({ className, ...rest }) {
|
|
21
22
|
return _jsx("div", { className: cx('card-list', className), ...rest });
|
|
22
23
|
}
|