@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/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, row, tile, menu, sheet, fab */
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: 50%;
2017
- translate: -50% 0;
2018
- max-width: calc(100% - 2 * var(--sp-4));
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 round icon buttons at the two edges ----
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 round shape and size (.icon-btn), one at each edge in
2750
- thumb reach from either side; the fill (--invert) alone leans forward. They
2751
- NEVER carry words (Lh 2026-09-16, for good): an arrow is the whole meaning,
2752
- and a word that isn't a direction ("Get started", "Done") is not a pager
2753
- button — that step COMMITS and goes back to the plain .action-bar with one
2754
- wide button. Where you are is said by the .pager__at dots — under the card
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 button sits at the left edge, the last at the right; a skip link between them stays centred */
2802
- :is(.action-bar--pager, .action-bar__tier--pager) > .icon-btn:first-child { margin-right: auto; }
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) — the native input lies over its whole box, unseen */
3338
- :is(.chip--pick, .mood__opt, .tile--pick, .sticky-pick__swatch) > input { appearance: none; position: absolute; inset: 0; margin: 0; opacity: 0; cursor: inherit; }
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;
@@ -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
  }
@@ -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
  }