typebulb 0.23.3 → 0.23.5

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.
@@ -24,6 +24,13 @@
24
24
  /* Prose measure for text (bubbles + notes) — kept to a readable line length.
25
25
  Diagrams break out wider than this; see .md .mermaid. */
26
26
  --content-max: 800px;
27
+ /* One height for every word-pill control — the statusbar pills (bulbs/model/session/token) and
28
+ the floating overlay pills (copy, breakout). Set once here so they can't drift apart again;
29
+ chosen a touch under the old statusbar 1.7rem and a touch over the overlay pills' ~1.35rem. */
30
+ --pill-h: 1.5rem;
31
+ /* One text size for every word-pill too (statusbar pills + overlay copy/breakout). Was drifting:
32
+ statusbar .85rem vs overlay .72rem read as amateurish. The emoji glyph pill keeps its own size. */
33
+ --pill-font: .8rem;
27
34
  color-scheme: light;
28
35
  }
29
36
 
@@ -87,13 +94,17 @@ body {
87
94
  left: 0;
88
95
  right: 0;
89
96
  bottom: 0;
97
+ /* Same column as .messages and the composer: a --content-max band centred in a 1.75rem gutter
98
+ (max-width carries the two gutters so the content box lands on --content-max). The pills are
99
+ right-aligned within it, so the cluster's right edge tracks the prose column's — consistent
100
+ with the input above and the transcript behind. The gutter also clears the overlaid scrollbar
101
+ that the old asymmetric right padding was there to dodge. */
102
+ margin-inline: auto;
103
+ max-width: calc(var(--content-max) + 3.5rem);
90
104
  display: flex;
91
105
  align-items: center;
92
106
  gap: .65rem;
93
- /* .4rem inset on top/left/bottom; the right is larger to clear the scrollbar
94
- the statusbar overlays — so the *visible* gap to the content edge matches the
95
- other sides instead of the pills sitting flush against the scrollbar. */
96
- padding: .4rem 1.35rem .4rem .4rem;
107
+ padding: .4rem 1.75rem;
97
108
  font-size: .8rem;
98
109
  /* Drop the inherited 1.55 line-height so the bar's own strut doesn't add
99
110
  phantom ascender/descender room above the pills. Everything in the bar
@@ -107,24 +118,28 @@ body {
107
118
  gap: .4rem;
108
119
  align-items: center;
109
120
  }
110
- /* Chip shape shared by the status-bar pills, interactive (session chip) and
111
- passive (token counter). One rule = one source of vertical alignment, no
112
- element-type drift between siblings; inline-flex + line-height:1 + fixed
113
- height centers the glyph run by the box, not by the inherited line-box.
114
- Opaque so they read cleanly over the message text the transparent strip lets
115
- through. */
116
- .pill, .token {
117
- display: inline-flex;
118
- align-items: center;
119
- justify-content: center;
120
- line-height: 1;
121
- height: 1.7rem;
121
+ /* Chip shape shared by EVERY word-label control — the status-bar pills (interactive and
122
+ passive) AND the floating overlay pills (copy, breakout, code⇄run). One rule = one source
123
+ of vertical alignment; when these drift apart it reads as amateurish.
124
+ THE CENTERING RECIPE (don't re-tweak per button fix it here or nowhere): Segoe UI's font
125
+ ascent (~1.08em) dwarfs its descent (~0.25em), so anything that centers the LINE BOX
126
+ flex, line-height, padding — parks the glyphs ~2px low at pill sizes. `text-box` trims the
127
+ line box to the glyphs (cap→baseline) so centering centers the letters themselves. It only
128
+ applies to block containers (not flex), hence inline-block + align-content, not inline-flex
129
+ + align-items. Browsers without text-box (Firefox) fall back to plain line-box centering.
130
+ Opaque so pills read cleanly over the message text the transparent strip lets through. */
131
+ .pill, .token, .overlay-pill {
132
+ display: inline-block;
133
+ align-content: center;
134
+ text-align: center;
135
+ text-box: trim-both cap alphabetic;
136
+ height: var(--pill-h);
122
137
  padding: 0 .7rem;
123
138
  border-radius: 7px;
124
139
  background: var(--panel);
125
140
  border: 1px solid var(--border);
126
141
  color: var(--muted);
127
- font-size: .8rem;
142
+ font-size: var(--pill-font);
128
143
  white-space: nowrap;
129
144
  user-select: none;
130
145
  }
@@ -132,7 +147,7 @@ body {
132
147
  interactive affordance. Slightly larger text than the passive indicator. */
133
148
  .pill {
134
149
  font: inherit;
135
- font-size: .85rem;
150
+ font-size: var(--pill-font);
136
151
  appearance: none;
137
152
  margin: 0;
138
153
  cursor: pointer;
@@ -143,8 +158,19 @@ body {
143
158
  /* Square glyph pill (the prose-mode toggle): width pinned to the pill height rather than
144
159
  padding-driven — the bar's first non-word pill. The emoji can't take currentColor, so it
145
160
  carries state itself: grayscale at rest, color while hovered or on — filtered on the
146
- inner span, never the button, or it would wash the accent border too. */
147
- .pill.glyph { width: 1.7rem; padding: 0; font-size: .9rem; }
161
+ inner span, never the button, or it would wash the accent border too.
162
+ Glyph content (emoji span / the Anthropic SVG) is vertically symmetric, so plain flex
163
+ centering is exact for it — and cap/alphabetic trim mis-seats a replaced SVG (it trims to
164
+ TEXT metrics), so opt glyph pills back out of the word-pill recipe. */
165
+ .pill.glyph {
166
+ display: inline-flex;
167
+ align-items: center;
168
+ justify-content: center;
169
+ text-box: normal;
170
+ width: var(--pill-h);
171
+ padding: 0;
172
+ font-size: .9rem;
173
+ }
148
174
  .pill.glyph .glyph-img { filter: grayscale(1); opacity: .75; }
149
175
  .pill.glyph:hover .glyph-img, .pill.glyph.on .glyph-img { filter: none; opacity: 1; }
150
176
 
@@ -241,7 +267,18 @@ body {
241
267
 
242
268
  /* ── The composer (TB-Agent-Composer.md): the prompt panel under the transcript. In flow (not
243
269
  overlaid like the statusbar) — it owns real height and must never cover content. ── */
244
- .composer { position: relative; flex: none; background: var(--bg); }
270
+ .composer { position: relative; flex: none; background: var(--bg); padding-inline: 1.75rem; }
271
+ /* Keep the composer's rows on the same prose column as the transcript (--content-max, centered like
272
+ .messages) — full-mirror-width input reads badly, the eye has to travel to wrap long lines. The
273
+ 1.75rem inline padding above matches .messages' gutter so the two columns align at every width. */
274
+ .composer .splitter,
275
+ .composer .input-wrap,
276
+ .composer-err,
277
+ .composer-status,
278
+ .composer-queue {
279
+ max-width: var(--content-max);
280
+ margin-inline: auto;
281
+ }
245
282
  /* A 4px drag zone centered on the composer's top border; z-index lifts it above the input-wrap
246
283
  border so the line itself is grabbable. */
247
284
  .splitter {
@@ -267,8 +304,10 @@ body {
267
304
  font: inherit;
268
305
  font-size: .9rem;
269
306
  line-height: 1.45;
270
- /* Right padding clears the three overlaid 28px buttons: .5rem inset + 3×28px + 2×.15rem gaps. */
271
- padding: .5rem 6.2rem .5rem .75rem;
307
+ /* Zero horizontal padding so the text sits flush on the --content-max column its left and right
308
+ edges line up with the transcript prose (which has no inset) and the splitter. Buttons live in
309
+ .composer-actions below, so the text needs no right gutter either. */
310
+ padding: .5rem 0;
272
311
  }
273
312
  .composer-input:focus { outline: none; }
274
313
  .composer-input:disabled { opacity: .6; }
@@ -277,11 +316,17 @@ body {
277
316
  it. 14px default; context classes (.btn-icon, .caret-tri, …) override. */
278
317
  .icon { display: inline-flex; align-items: center; justify-content: center; width: 14px; height: 14px; flex: none; }
279
318
  .icon svg { width: 100%; height: 100%; display: block; }
280
- /* The overlay row, bottom-anchored to the textarea's right edge: send/stop is the primary CTA;
281
- + (new conversation) and the clipboard clip are the quiet secondaries to its left. */
319
+ /* The action bar under the textarea, right-aligned: send/stop is the primary CTA; + (new
320
+ conversation) and the clipboard clip are the quiet secondaries to its left. Below the text (not
321
+ overlaid) so the textarea keeps the full prose column. */
322
+ .composer-actions {
323
+ display: flex;
324
+ justify-content: flex-end;
325
+ align-items: center;
326
+ gap: .15rem;
327
+ padding: 0 0 .4rem; /* flush right, so Send lines up with the copy pill / statusbar pills */
328
+ }
282
329
  .composer-act, .composer-new, .composer-clip {
283
- position: absolute;
284
- bottom: .5rem;
285
330
  width: 28px;
286
331
  height: 28px;
287
332
  display: flex;
@@ -299,7 +344,7 @@ body {
299
344
  the button, no painted disc. One size for all three — the circles' diameter and the paperclip's
300
345
  ink height are both 800/960 of the material viewBox, so equal boxes = equal visual height. */
301
346
  .composer-act .icon, .composer-new .icon, .composer-clip .icon { width: 24px; height: 24px; }
302
- .composer-act { right: .5rem; background: transparent; }
347
+ .composer-act { background: transparent; }
303
348
  .composer-act.send { color: var(--accent); }
304
349
  .composer-act.send:hover:not(:disabled) { color: color-mix(in srgb, var(--accent) 80%, white); background: color-mix(in srgb, var(--accent) 10%, transparent); }
305
350
  .composer-act.stop { color: var(--err); }
@@ -307,38 +352,36 @@ body {
307
352
  .composer-act:active, .composer-new:active, .composer-clip:active { transform: scale(.94); }
308
353
  .composer-act:disabled, .composer-new:disabled, .composer-clip:disabled { opacity: .5; cursor: default; }
309
354
  .composer-new {
310
- /* offset = act's right inset (.5rem) + act width (28px) + gap (.15rem) */
311
- right: calc(.5rem + 28px + .15rem);
312
355
  background: transparent;
313
356
  color: var(--muted);
314
357
  }
315
358
  .composer-new:hover:not(:disabled) { color: var(--accent); background: color-mix(in srgb, var(--accent) 10%, transparent); }
316
359
  .composer-clip {
317
- /* one more button-width left of .composer-new */
318
- right: calc(.5rem + 2 * (28px + .15rem));
319
360
  background: transparent;
320
361
  color: var(--muted);
321
362
  }
322
363
  .composer-clip:hover:not(:disabled) { color: var(--accent); background: color-mix(in srgb, var(--accent) 10%, transparent); }
323
- .composer-err { padding: .3rem .75rem; color: var(--err); font-size: .78rem; }
364
+ /* Zero horizontal padding (like .composer-input): these rows sit flush on the content column. */
365
+ .composer-err { padding: .3rem 0; color: var(--err); font-size: .78rem; }
324
366
  /* The ambient status line (TB-Agent-Composer-Toolkit.md Piece 2): one slim kind-tinted row above the
325
367
  input — a retry/compaction in progress, an extension notice, a recipe's transient result. */
326
- .composer-status { padding: .3rem .75rem; font-size: .78rem; color: var(--muted); }
327
- .composer-status.warning { color: color-mix(in srgb, var(--err) 55%, var(--fg)); }
368
+ .composer-status { padding: .3rem 0; font-size: .78rem; color: var(--accent); }
369
+ .composer-status.warning { color: var(--warn); }
328
370
  .composer-status.error { color: var(--err); }
329
371
  /* The pending-queue strip (parity #2): queued steer/follow-up texts above the input. Block rows,
330
372
  not a flex column — .queue-row's overflow:hidden would zero flex min-heights (the .dlg-opts
331
373
  lesson). */
332
- .composer-queue { padding: .15rem .75rem 0; }
374
+ .composer-queue { padding: .15rem 0 0; }
333
375
  .queue-row { font-size: .78rem; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
334
376
  .queue-tag { color: var(--accent); font-size: .68rem; text-transform: uppercase; letter-spacing: .05em; margin-right: .5rem; }
335
377
  /* The @-file-mention popup, anchored above the composer. */
336
378
  .at-popup {
337
379
  position: absolute;
338
380
  bottom: calc(100% + .25rem);
339
- left: 1rem;
340
- right: 1rem;
381
+ left: 0;
382
+ right: 0;
341
383
  max-width: 600px;
384
+ margin-inline: auto;
342
385
  max-height: 280px;
343
386
  overflow-y: auto;
344
387
  background: var(--panel);
@@ -836,6 +879,11 @@ a.server-port:hover { text-decoration: underline; }
836
879
  .messages {
837
880
  flex: 1;
838
881
  overflow-y: auto;
882
+ /* Reserve the scrollbar gutter on BOTH edges so the centred --content-max column stays on the
883
+ true axis (window centre) whether or not a scrollbar is showing. Without this the scrollbar
884
+ shrinks the column and shifts it ~half a scrollbar left of the composer/statusbar columns
885
+ (which never scroll) — the misalignment between the prose and the composer's left edge. */
886
+ scrollbar-gutter: stable both-edges;
839
887
  /* Content runs under the overlaid statusbar rather than stopping above it.
840
888
  Gutters are symmetric: the turn stripe is absolutely positioned, so it claims no layout
841
889
  width and the left gutter needs no extra room for it (see Invariants). The bottom is
@@ -861,8 +909,8 @@ a.server-port:hover { text-decoration: underline; }
861
909
  .masthead {
862
910
  max-width: var(--content-max);
863
911
  width: 100%;
864
- margin: 0 auto 1rem auto;
865
- padding: .35rem 0 .35rem;
912
+ margin: 0 auto .25rem auto;
913
+ padding: .15rem 0;
866
914
  display: flex;
867
915
  flex-direction: column;
868
916
  align-items: flex-start;
@@ -871,7 +919,7 @@ a.server-port:hover { text-decoration: underline; }
871
919
  user-select: none;
872
920
  }
873
921
  .masthead-logo {
874
- width: 170px;
922
+ width: 150px;
875
923
  max-width: 55%;
876
924
  height: auto;
877
925
  opacity: .92;
@@ -1178,24 +1226,20 @@ html[data-theme="dark"] .masthead-logo.dark { display: block; }
1178
1226
  /* Overlay pill: a small hover-revealed control floated at a container's
1179
1227
  bottom-right, shared by the embed breakout button and the message copy button.
1180
1228
  Muted at rest, accent on hover (instant, matching the status pills). The
1181
- container supplies the reveal; per-button bits layer on top. */
1229
+ container supplies the reveal; per-button bits layer on top. Box shape, colors
1230
+ and vertical centering come from the shared word-pill rule (.pill, .token,
1231
+ .overlay-pill) — only positioning, reveal and sizing quirks live here. */
1182
1232
  .overlay-pill {
1183
1233
  position: absolute;
1184
1234
  bottom: .5rem;
1185
- right: .5rem;
1235
+ right: 0; /* flush with the content column's right edge (prose / statusbar pills) */
1186
1236
  font: inherit;
1187
- font-size: .72rem;
1188
- background: var(--panel);
1189
- border: 1px solid var(--border);
1190
- border-radius: 6px;
1191
- color: var(--muted);
1192
- padding: .12rem .45rem;
1193
- /* These are word buttons that swap labels in place (fit⇄spread, code⇄run, copy⇄copied), so a
1194
- min-width keeps the button from jumping as the word's length changes — "fit" is much narrower
1195
- than "spread". Centered text so the floor padding sits evenly. (An icon button wouldn't want
1196
- this, but every pill here is a word.) */
1237
+ font-size: var(--pill-font);
1238
+ padding: 0 .45rem;
1239
+ /* Word buttons that swap labels in place (fit⇄spread, code⇄run, copy⇄copied), so a min-width
1240
+ keeps the button from jumping as the word's length changes — "fit" is much narrower than
1241
+ "spread". */
1197
1242
  min-width: 3.5rem;
1198
- text-align: center;
1199
1243
  cursor: pointer;
1200
1244
  opacity: 0;
1201
1245
  transition: opacity .2s ease;
@@ -1223,7 +1267,7 @@ html[data-theme="dark"] .masthead-logo.dark { display: block; }
1223
1267
  .md .bulb-controls {
1224
1268
  position: absolute;
1225
1269
  top: 0;
1226
- right: .5rem;
1270
+ right: 0; /* flush with the content column's right edge (prose / statusbar pills) */
1227
1271
  z-index: 2;
1228
1272
  display: flex;
1229
1273
  gap: .4rem;