@justai/cuts 0.138.0 → 0.139.0
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/package.json +2 -2
- package/src/ActionList.astro +27 -31
- package/src/ActionRow.astro +64 -68
- package/src/BackToZone.astro +35 -39
- package/src/Catalogue.astro +83 -87
- package/src/CatalogueCard.astro +68 -72
- package/src/ChildPersona.astro +51 -55
- package/src/ConfirmSheet.astro +65 -69
- package/src/FilePicker.astro +13 -17
- package/src/LangPicker.astro +41 -45
- package/src/Posts.astro +169 -173
- package/src/Preroll.astro +193 -197
- package/src/Profile.astro +35 -39
- package/src/Segmented.astro +54 -58
- package/src/Sheet.astro +212 -237
- package/src/Toolbar.astro +280 -284
- package/src/ground.css +120 -124
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@justai/cuts",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.139.0",
|
|
4
4
|
"description": "A persona's named parts \u2014 the page shell that holds them, and the cuts themselves.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"repository": {
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"@justai/core": "^0.36.0",
|
|
45
|
-
"@justai/ui": "^0.
|
|
45
|
+
"@justai/ui": "^0.26.0",
|
|
46
46
|
"@justai/atrium": "^0.1.9"
|
|
47
47
|
},
|
|
48
48
|
"scripts": {
|
package/src/ActionList.astro
CHANGED
|
@@ -45,36 +45,32 @@ const { title, note } = Astro.props;
|
|
|
45
45
|
</div>
|
|
46
46
|
|
|
47
47
|
<style>
|
|
48
|
-
/*
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
border: 1px solid var(--border);
|
|
67
|
-
border-radius: var(--radius-md);
|
|
68
|
-
overflow: hidden;
|
|
69
|
-
}
|
|
70
|
-
.jal-title {
|
|
71
|
-
font-size: var(--fs-xs);
|
|
72
|
-
font-weight: 600;
|
|
73
|
-
color: var(--text-dim);
|
|
74
|
-
text-transform: uppercase;
|
|
75
|
-
letter-spacing: 0.04em;
|
|
76
|
-
padding-inline: 4px;
|
|
77
|
-
}
|
|
78
|
-
.jal-note { font-size: var(--fs-xs); color: var(--text-dim); padding-inline: 4px; line-height: 1.45; }
|
|
48
|
+
/* queries: two action lists touching · no gap between groups · the second group sits on the first
|
|
49
|
+
THE BREAK IS THE GRAMMAR, so the component owns it.
|
|
50
|
+
A group carried its INTERNAL 7px and nothing between itself and the next one, which left the
|
|
51
|
+
break — the thing that separates "things you might do" from "the door with no way back" — to
|
|
52
|
+
whichever consumer remembered a wrapper. files did in one sheet and not in another, and the
|
|
53
|
+
second one read as one long list with a red row at the end.
|
|
54
|
+
`:last-child` so a lone group adds no trailing space it did not ask for. */
|
|
55
|
+
.jal-group { display: flex; flex-direction: column; gap: 7px; }
|
|
56
|
+
.jal-group + .jal-group { margin-block-start: 22px; }
|
|
57
|
+
/* Inset and grouped: the card is the group, and `overflow: hidden` is what lets a row's own
|
|
58
|
+
background reach the rounded corner instead of squaring it off on press. */
|
|
59
|
+
.jal {
|
|
60
|
+
display: flex;
|
|
61
|
+
flex-direction: column;
|
|
62
|
+
background: var(--surface-2);
|
|
63
|
+
border: 1px solid var(--border);
|
|
64
|
+
border-radius: var(--radius-md);
|
|
65
|
+
overflow: hidden;
|
|
79
66
|
}
|
|
67
|
+
.jal-title {
|
|
68
|
+
font-size: var(--fs-xs);
|
|
69
|
+
font-weight: 600;
|
|
70
|
+
color: var(--text-dim);
|
|
71
|
+
text-transform: uppercase;
|
|
72
|
+
letter-spacing: 0.04em;
|
|
73
|
+
padding-inline: 4px;
|
|
74
|
+
}
|
|
75
|
+
.jal-note { font-size: var(--fs-xs); color: var(--text-dim); padding-inline: 4px; line-height: 1.45; }
|
|
80
76
|
</style>
|
package/src/ActionRow.astro
CHANGED
|
@@ -69,76 +69,72 @@ const { id, label, tone = "plain", detail, hidden, i18n, ...rest } = Astro.props
|
|
|
69
69
|
</button>
|
|
70
70
|
|
|
71
71
|
<style>
|
|
72
|
-
/*
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
.jal-row
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
.jal-row:hover { background: color-mix(in srgb, var(--text) 5%, transparent); }
|
|
104
|
-
}
|
|
105
|
-
.jal-row:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
|
|
106
|
-
|
|
107
|
-
.jal-ico {
|
|
108
|
-
display: inline-flex;
|
|
109
|
-
flex: none;
|
|
110
|
-
color: var(--text-dim);
|
|
111
|
-
}
|
|
112
|
-
/* The glyph is cut to a fixed box, so it is sized in px on purpose — it is a mark, not reading
|
|
113
|
-
text, and the box it sits in is a hand size rather than a type size. */
|
|
114
|
-
.jal-ico :global(svg) { width: 20px; height: 20px; display: block; }
|
|
72
|
+
/* A ROW, not a button in a line: it takes the full width it is given, so the label is never the
|
|
73
|
+
thing that has to shrink. The 44px floor is the one number iOS never moves — it is a fingertip,
|
|
74
|
+
and `min-height` rather than a fixed height so a reader who raised their text size gets a
|
|
75
|
+
taller row instead of a clipped one. */
|
|
76
|
+
.jal-row {
|
|
77
|
+
display: flex;
|
|
78
|
+
align-items: center;
|
|
79
|
+
gap: 12px;
|
|
80
|
+
width: 100%;
|
|
81
|
+
min-height: 44px;
|
|
82
|
+
padding: 11px 14px;
|
|
83
|
+
border: 0;
|
|
84
|
+
background: none;
|
|
85
|
+
color: var(--text);
|
|
86
|
+
font: inherit;
|
|
87
|
+
font-size: var(--fs-sm);
|
|
88
|
+
font-weight: 500;
|
|
89
|
+
text-align: start;
|
|
90
|
+
cursor: pointer;
|
|
91
|
+
/* The separator lives on the row and is removed from the last one by the list — so a row can be
|
|
92
|
+
hidden or revealed without leaving a hairline hanging under nothing. */
|
|
93
|
+
border-block-end: 1px solid var(--border);
|
|
94
|
+
transition: background 0.15s;
|
|
95
|
+
}
|
|
96
|
+
.jal-row:last-child,
|
|
97
|
+
.jal-row[hidden] + .jal-row:last-child { border-block-end: 0; }
|
|
98
|
+
.jal-row:active { background: color-mix(in srgb, var(--text) 8%, transparent); }
|
|
99
|
+
@media (hover: hover) {
|
|
100
|
+
.jal-row:hover { background: color-mix(in srgb, var(--text) 5%, transparent); }
|
|
101
|
+
}
|
|
102
|
+
.jal-row:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
|
|
115
103
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
104
|
+
.jal-ico {
|
|
105
|
+
display: inline-flex;
|
|
106
|
+
flex: none;
|
|
107
|
+
color: var(--text-dim);
|
|
108
|
+
}
|
|
109
|
+
/* The glyph is cut to a fixed box, so it is sized in px on purpose — it is a mark, not reading
|
|
110
|
+
text, and the box it sits in is a hand size rather than a type size. */
|
|
111
|
+
.jal-ico :global(svg) { width: 20px; height: 20px; display: block; }
|
|
119
112
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
and a persona whose accent is light fails contrast here while looking perfect as a button — tts's
|
|
124
|
-
amber measures 1.67:1 on the light surface against the 4.5 a word needs.
|
|
125
|
-
This is the same problem ConfirmSheet already solved with `--confirm-accent`, one component over,
|
|
126
|
-
for the same stated reason ("the action reads as TEXT"). The hook is additive: a consumer that
|
|
127
|
-
sets nothing gets exactly what it got before, and one that sets `--accent-text` gets a readable
|
|
128
|
-
row. Prefer fixing it here over a persona globalising this class — that is what tts had to do
|
|
129
|
-
while this shipped, and a persona reaching into a cut's internals is a fix that rots. */
|
|
130
|
-
.jal-row.is-accent { color: var(--accent-text, var(--accent)); font-weight: 600; }
|
|
131
|
-
.jal-row.is-accent .jal-ico { color: var(--accent-text, var(--accent)); }
|
|
132
|
-
.jal-row.is-danger { color: var(--danger); }
|
|
133
|
-
.jal-row.is-danger .jal-ico { color: var(--danger); }
|
|
134
|
-
.jal-row.is-danger:active { background: color-mix(in srgb, var(--danger) 12%, transparent); }
|
|
135
|
-
@media (hover: hover) {
|
|
136
|
-
.jal-row.is-danger:hover { background: color-mix(in srgb, var(--danger) 10%, transparent); }
|
|
137
|
-
}
|
|
113
|
+
/* The label takes the room. This is the whole point of the component: nothing here clips. */
|
|
114
|
+
.jal-label { flex: 1; min-width: 0; }
|
|
115
|
+
.jal-detail { color: var(--text-dim); font-size: var(--fs-xs); flex: none; }
|
|
138
116
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
117
|
+
/* queries: the accent row is unreadable in light mode · is-accent contrast · accent as text ·
|
|
118
|
+
my persona's accent is too bright to read in a sheet
|
|
119
|
+
THE ACCENT AS INK IS NOT THE ACCENT AS PAINT. A fill only has to be SEEN; a word has to be READ,
|
|
120
|
+
and a persona whose accent is light fails contrast here while looking perfect as a button — tts's
|
|
121
|
+
amber measures 1.67:1 on the light surface against the 4.5 a word needs.
|
|
122
|
+
This is the same problem ConfirmSheet already solved with `--confirm-accent`, one component over,
|
|
123
|
+
for the same stated reason ("the action reads as TEXT"). The hook is additive: a consumer that
|
|
124
|
+
sets nothing gets exactly what it got before, and one that sets `--accent-text` gets a readable
|
|
125
|
+
row. Prefer fixing it here over a persona globalising this class — that is what tts had to do
|
|
126
|
+
while this shipped, and a persona reaching into a cut's internals is a fix that rots. */
|
|
127
|
+
.jal-row.is-accent { color: var(--accent-text, var(--accent)); font-weight: 600; }
|
|
128
|
+
.jal-row.is-accent .jal-ico { color: var(--accent-text, var(--accent)); }
|
|
129
|
+
.jal-row.is-danger { color: var(--danger); }
|
|
130
|
+
.jal-row.is-danger .jal-ico { color: var(--danger); }
|
|
131
|
+
.jal-row.is-danger:active { background: color-mix(in srgb, var(--danger) 12%, transparent); }
|
|
132
|
+
@media (hover: hover) {
|
|
133
|
+
.jal-row.is-danger:hover { background: color-mix(in srgb, var(--danger) 10%, transparent); }
|
|
143
134
|
}
|
|
135
|
+
|
|
136
|
+
.jal-row[disabled] { opacity: 0.4; cursor: default; }
|
|
137
|
+
/* A class-set display beats the user agent's `[hidden] { display: none }` — that has bitten this
|
|
138
|
+
ecosystem twice already, in this very sheet. Said again where the display is set. */
|
|
139
|
+
.jal-row[hidden] { display: none !important; }
|
|
144
140
|
</style>
|
package/src/BackToZone.astro
CHANGED
|
@@ -92,48 +92,44 @@ const href = `https://${apex}`;
|
|
|
92
92
|
</a>
|
|
93
93
|
|
|
94
94
|
<style>
|
|
95
|
-
/*
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
.
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
.home:hover { color: var(--text); }
|
|
105
|
-
.home:active { transform: scale(0.9); }
|
|
106
|
-
.home svg { width: 20px; height: 20px; display: block; }
|
|
95
|
+
/* icon-only, flat — flush to the left edge of the (full-bleed) toolbar */
|
|
96
|
+
.home {
|
|
97
|
+
display: inline-grid; place-items: center; width: 36px; height: 36px;
|
|
98
|
+
color: var(--text-dim); text-decoration: none; margin-inline-start: -7px;
|
|
99
|
+
transition: color 0.2s, transform 0.2s var(--ease-spring);
|
|
100
|
+
}
|
|
101
|
+
.home:hover { color: var(--text); }
|
|
102
|
+
.home:active { transform: scale(0.9); }
|
|
103
|
+
.home svg { width: 20px; height: 20px; display: block; }
|
|
107
104
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
105
|
+
/* At rest every part of the mark is the row's ink, so the silhouette reads as one shape rather than
|
|
106
|
+
a logo parked in a toolbar. The centre is FILLED rather than knocked out: in the coloured drawing
|
|
107
|
+
it is a counter-shape separating four saturated arms, and in one colour there is nothing to
|
|
108
|
+
separate — a hole there would be a gap the mark does not have. */
|
|
109
|
+
.azmark .arm,
|
|
110
|
+
.azmark .ctr { fill: currentColor; }
|
|
114
111
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
112
|
+
/* queries: the home icon is smaller than the other glyphs · 20px of ink · pgmark size
|
|
113
|
+
FILLED, AND THE viewBox IS THE INK'S OWN BOUNDS. This mark was three round-capped strokes, which
|
|
114
|
+
is the same shape — but getBBox reports a stroke's centreline only, and the fleet's "every icon
|
|
115
|
+
paints 20px of ink" spec measured it at 9.9px beside 20px glyphs. The spec was right: at that
|
|
116
|
+
size it really was half its neighbours. Rotated rounded rects draw exactly what the strokes did
|
|
117
|
+
and measure what they look like. */
|
|
118
|
+
.pgmark .arm { fill: currentColor; }
|
|
119
|
+
.home:hover .pgmark .a1, .home:focus-visible .pgmark .a1 { fill: #3D6FD9; }
|
|
120
|
+
.home:hover .pgmark .a2, .home:focus-visible .pgmark .a2 { fill: #E8503A; }
|
|
121
|
+
.home:hover .pgmark .a3, .home:focus-visible .pgmark .a3 { fill: #F5A623; }
|
|
125
122
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
}
|
|
123
|
+
.home:hover .azmark .a1, .home:focus-visible .azmark .a1 { fill: url(#azHome1); }
|
|
124
|
+
.home:hover .azmark .a2, .home:focus-visible .azmark .a2 { fill: url(#azHome2); }
|
|
125
|
+
.home:hover .azmark .a3, .home:focus-visible .azmark .a3 { fill: url(#azHome3); }
|
|
126
|
+
.home:hover .azmark .a4, .home:focus-visible .azmark .a4 { fill: url(#azHome4); }
|
|
127
|
+
/* The centre follows the ground, and both values are the project's own: #F5F1E8 is the centre of
|
|
128
|
+
Logo Black, drawn for dark grounds, and #2B2724 the centre of Logo White, drawn for pale ones.
|
|
129
|
+
Dark is the un-queried default because the fleet's tokens are dark-first. */
|
|
130
|
+
.home:hover .azmark .ctr, .home:focus-visible .azmark .ctr { fill: #F5F1E8; }
|
|
131
|
+
@media (prefers-color-scheme: light) {
|
|
132
|
+
:global(html:not([data-theme="dark"])) .home:hover .azmark .ctr, :global(html:not([data-theme="dark"])) .home:focus-visible .azmark .ctr { fill: #2B2724; }
|
|
137
133
|
}
|
|
138
134
|
</style>
|
|
139
135
|
|
package/src/Catalogue.astro
CHANGED
|
@@ -389,96 +389,92 @@ const isNew = (added: string): boolean => { const t0 = Date.parse(added || "");
|
|
|
389
389
|
</script>
|
|
390
390
|
|
|
391
391
|
<style>
|
|
392
|
-
/*
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
that distance it stops reading as the head of the grid and starts looking as though it drifted
|
|
402
|
-
down toward it. A gap that changes with the window is a rhythm nobody designed. */
|
|
403
|
-
.kbody { flex: 1 0 auto; display: flex; flex-direction: column; padding-block: 26px 16px; }
|
|
392
|
+
/* The three gaps down this column are one rhythm: 26 to the search, 18 from it to the grid, 14
|
|
393
|
+
between cards. Each step is about 1.4x the next, so they read as one thing narrowing — section,
|
|
394
|
+
then control-to-list, then item-to-item.
|
|
395
|
+
THE TOP ONE USED TO BE `clamp(20px, 5vh, 44px)`, which is not a chosen number: it is whatever the
|
|
396
|
+
viewport gives. Measured, the same page had 37px of it at 700px tall and 46px at 900px, against a
|
|
397
|
+
fixed 18px below — so the search sat 1.8x from the bar on a laptop and 2.2x on a desktop, and at
|
|
398
|
+
that distance it stops reading as the head of the grid and starts looking as though it drifted
|
|
399
|
+
down toward it. A gap that changes with the window is a rhythm nobody designed. */
|
|
400
|
+
.kbody { flex: 1 0 auto; display: flex; flex-direction: column; padding-block: 26px 16px; }
|
|
404
401
|
|
|
405
|
-
|
|
402
|
+
.controls { margin-block-end: 18px; }
|
|
406
403
|
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
404
|
+
/* The field carries the CARD's material, and the reason is a measurement rather than a preference.
|
|
405
|
+
On this page "raised" means whiter plus a shadow: the cards are `--card-bg` (#fff in light) on an
|
|
406
|
+
off-white ground. The field was `--surface-2` — 4% BLACK over that same ground — with no shadow, so
|
|
407
|
+
it was not lifting, it was recessed, and a recessed input in light reads as disabled. Giving it the
|
|
408
|
+
card recipe means the page has ONE raised surface instead of two treatments arguing.
|
|
409
|
+
Dark loses nothing: there `--card-bg` and `--surface` are the same value, so the fill stays the 6%
|
|
410
|
+
white overlay that was already lifting correctly, and only the shadow is added. That asymmetry is
|
|
411
|
+
why the complaint could only come from the light side. */
|
|
412
|
+
.search {
|
|
413
|
+
display: flex; align-items: center; gap: 10px;
|
|
414
|
+
background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius-md);
|
|
415
|
+
box-shadow: var(--card-shadow);
|
|
416
|
+
/* the end padding is the button's, not the text's — 16px would park the icon away from the edge it
|
|
417
|
+
belongs to, and the button brings its own 30px of hit area */
|
|
418
|
+
padding: 12px 8px 12px 16px;
|
|
419
|
+
transition: border-color 0.2s var(--ease-out), box-shadow 0.25s var(--ease-out);
|
|
420
|
+
}
|
|
421
|
+
/* focus lives on the whole box as a soft OUTER breeze — not a thick inner ring. The card shadow is
|
|
422
|
+
re-stated after the ring rather than replaced by it: `box-shadow` is one property, so naming only
|
|
423
|
+
the ring here would drop the lift the moment somebody clicked into the field. */
|
|
424
|
+
.search:focus-within {
|
|
425
|
+
border-color: color-mix(in srgb, var(--accent) 45%, var(--border));
|
|
426
|
+
box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 16%, transparent), var(--card-shadow);
|
|
427
|
+
}
|
|
428
|
+
.search svg { width: 18px; height: 18px; color: var(--text-dim); flex: none; }
|
|
429
|
+
.search input { flex: 1; min-width: 0; border: none; background: none; color: var(--text); font: inherit; font-size: var(--fs-base); outline: none; }
|
|
430
|
+
.search input:focus-visible { box-shadow: none; } /* the box carries the breeze; the input has no ring of its own */
|
|
434
431
|
|
|
435
|
-
|
|
436
|
-
|
|
432
|
+
/* ---- the filter: a button at the field's own end, and the shelves in a sheet under it ---- */
|
|
433
|
+
.fwrap { position: relative; } /* the panel hangs off this, not off .search, so focus styles stay put */
|
|
437
434
|
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
}
|
|
463
|
-
.opt {
|
|
464
|
-
display: flex; align-items: center; gap: 9px; padding: 9px 10px;
|
|
465
|
-
border: none; background: none; border-radius: var(--radius-sm); cursor: pointer;
|
|
466
|
-
color: var(--text); font: inherit; font-size: var(--fs-sm); text-align: start;
|
|
467
|
-
transition: background 0.2s var(--ease-out);
|
|
468
|
-
}
|
|
469
|
-
.opt:hover, .opt:focus-visible { background: color-mix(in srgb, var(--text) 8%, transparent); }
|
|
470
|
-
.opt .lb { flex: 1; min-width: 0; }
|
|
471
|
-
/* the count is the shelf's size, so a person knows what is behind a word before spending a click */
|
|
472
|
-
.opt .n { flex: none; font-variant-numeric: tabular-nums; font-size: var(--fs-2xs); color: var(--text-dim); }
|
|
473
|
-
/* hidden, not absent: the tick keeps its column either way, so the labels do not jump sideways when
|
|
474
|
-
the selection moves from one row to another */
|
|
475
|
-
.opt .tick { flex: none; width: 15px; height: 15px; color: var(--accent); visibility: hidden; }
|
|
476
|
-
.opt.active .tick { visibility: visible; }
|
|
477
|
-
.opt.active .lb { font-weight: 600; }
|
|
478
|
-
|
|
479
|
-
.grid { display: grid; grid-template-columns: 1fr; gap: 14px; }
|
|
480
|
-
/* no entrance animation — when you walk into the room, everyone is already in their place.
|
|
481
|
-
the cards are simply there on load; the only motion is a whisper on hover. */
|
|
482
|
-
.empty { text-align: center; color: var(--text-dim); padding: 40px 0; }
|
|
435
|
+
/* A 30px hit area inside a box whose height is set by the input's line box: the negative block margin
|
|
436
|
+
pulls its outer height back under that line, so adding this button does NOT make the field taller.
|
|
437
|
+
Measured before and after — the field is the same height it was with the chip row. */
|
|
438
|
+
.fbtn {
|
|
439
|
+
flex: none; display: grid; place-items: center; width: 30px; height: 30px; margin-block: -6px;
|
|
440
|
+
border: none; background: none; padding: 0; border-radius: var(--radius-sm); cursor: pointer;
|
|
441
|
+
color: var(--text-dim);
|
|
442
|
+
transition: color 0.25s var(--ease-out), background 0.25s var(--ease-out);
|
|
443
|
+
}
|
|
444
|
+
/* `.search svg` sets colour on the ELEMENT, and a direct declaration beats an inherited one — so
|
|
445
|
+
without this the button's own colour (and the accent below) would never reach its icon. Equal
|
|
446
|
+
specificity, later in the sheet, so this wins. */
|
|
447
|
+
.fbtn svg { width: 18px; height: 18px; color: inherit; }
|
|
448
|
+
.fbtn:hover, .fbtn:focus-visible { color: var(--text); background: color-mix(in srgb, var(--text) 8%, transparent); }
|
|
449
|
+
/* the row that used to announce the active shelf is gone, so the button carries it */
|
|
450
|
+
.fbtn.on { color: var(--accent); background: color-mix(in srgb, var(--accent) 14%, transparent); }
|
|
451
|
+
.fpanel {
|
|
452
|
+
position: absolute; inset-inline: 0; top: calc(100% + 8px); z-index: 5;
|
|
453
|
+
display: flex; flex-direction: column; gap: 2px; padding: 6px;
|
|
454
|
+
/* the column's own material — a translucent ground would let the cards read through the labels */
|
|
455
|
+
background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-md);
|
|
456
|
+
box-shadow: 0 18px 40px -20px rgba(0, 0, 0, 0.45);
|
|
457
|
+
backdrop-filter: blur(30px) saturate(1.4);
|
|
458
|
+
-webkit-backdrop-filter: blur(30px) saturate(1.4);
|
|
483
459
|
}
|
|
460
|
+
.opt {
|
|
461
|
+
display: flex; align-items: center; gap: 9px; padding: 9px 10px;
|
|
462
|
+
border: none; background: none; border-radius: var(--radius-sm); cursor: pointer;
|
|
463
|
+
color: var(--text); font: inherit; font-size: var(--fs-sm); text-align: start;
|
|
464
|
+
transition: background 0.2s var(--ease-out);
|
|
465
|
+
}
|
|
466
|
+
.opt:hover, .opt:focus-visible { background: color-mix(in srgb, var(--text) 8%, transparent); }
|
|
467
|
+
.opt .lb { flex: 1; min-width: 0; }
|
|
468
|
+
/* the count is the shelf's size, so a person knows what is behind a word before spending a click */
|
|
469
|
+
.opt .n { flex: none; font-variant-numeric: tabular-nums; font-size: var(--fs-2xs); color: var(--text-dim); }
|
|
470
|
+
/* hidden, not absent: the tick keeps its column either way, so the labels do not jump sideways when
|
|
471
|
+
the selection moves from one row to another */
|
|
472
|
+
.opt .tick { flex: none; width: 15px; height: 15px; color: var(--accent); visibility: hidden; }
|
|
473
|
+
.opt.active .tick { visibility: visible; }
|
|
474
|
+
.opt.active .lb { font-weight: 600; }
|
|
475
|
+
|
|
476
|
+
.grid { display: grid; grid-template-columns: 1fr; gap: 14px; }
|
|
477
|
+
/* no entrance animation — when you walk into the room, everyone is already in their place.
|
|
478
|
+
the cards are simply there on load; the only motion is a whisper on hover. */
|
|
479
|
+
.empty { text-align: center; color: var(--text-dim); padding: 40px 0; }
|
|
484
480
|
</style>
|