@workerdeck/ui 2.7.2 → 2.8.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.
Files changed (61) hide show
  1. package/README.md +30 -30
  2. package/build/{SessionPanel-B5FfiBxE.mjs → SessionPanel-Dg4xf-ql.mjs} +46 -46
  3. package/build/SessionPanel-Dg4xf-ql.mjs.map +1 -0
  4. package/build/format.mjs +1 -1
  5. package/build/index.d.mts +11 -11
  6. package/build/index.mjs +4 -4
  7. package/build/index.mjs.map +1 -1
  8. package/build/scoped.css +2 -2
  9. package/build/{status-BO9wJloK.mjs → status-kmsBhuFG.mjs} +3 -3
  10. package/build/status-kmsBhuFG.mjs.map +1 -0
  11. package/build/workspace.mjs +4 -4
  12. package/build/workspace.mjs.map +1 -1
  13. package/package.json +18 -18
  14. package/src/components/agent/Composer.tsx +2 -2
  15. package/src/components/agent/ContextDialog.tsx +1 -1
  16. package/src/components/agent/EntryIcon.tsx +1 -1
  17. package/src/components/agent/FileTree.tsx +1 -1
  18. package/src/components/agent/FileViewer.tsx +1 -1
  19. package/src/components/agent/HostFilesDialog.tsx +2 -2
  20. package/src/components/agent/PermissionModeSelect.tsx +2 -2
  21. package/src/components/agent/PermissionPrompt.tsx +2 -2
  22. package/src/components/agent/SessionBrowser.tsx +1 -1
  23. package/src/components/agent/SessionItem.tsx +1 -1
  24. package/src/components/agent/SessionPanel.tsx +2 -2
  25. package/src/components/agent/SkillsDialog.tsx +3 -3
  26. package/src/components/agent/StatusBar.tsx +1 -1
  27. package/src/components/agent/TaskList.tsx +2 -2
  28. package/src/components/agent/TranscriptRows.tsx +1 -1
  29. package/src/components/agent/UsageDialog.tsx +1 -1
  30. package/src/components/agent/use-subagent-frame.ts +2 -2
  31. package/src/components/agent/use-transcript-jumps.ts +2 -2
  32. package/src/components/prompt-area/clipboard-helpers.ts +2 -2
  33. package/src/components/prompt-area/cursor-helpers.ts +7 -7
  34. package/src/components/prompt-area/dom-helpers.ts +8 -8
  35. package/src/components/prompt-area/html-to-markdown.ts +2 -2
  36. package/src/components/prompt-area/prompt-area-engine.ts +4 -4
  37. package/src/components/prompt-area/prompt-area-list-ops.ts +10 -10
  38. package/src/components/prompt-area/prompt-area.tsx +2 -2
  39. package/src/components/prompt-area/trigger-presets.ts +6 -6
  40. package/src/components/prompt-area/types.ts +6 -6
  41. package/src/components/prompt-area/use-chip-editing.ts +8 -8
  42. package/src/components/prompt-area/use-markdown-mode.ts +3 -3
  43. package/src/components/prompt-area/use-prompt-area-events.ts +3 -3
  44. package/src/components/prompt-area/use-prompt-area-keydown.ts +3 -3
  45. package/src/components/prompt-area/use-prompt-area-state.ts +4 -4
  46. package/src/components/prompt-area/use-prompt-area.ts +5 -5
  47. package/src/components/prompt-area/use-trigger-search.ts +1 -1
  48. package/src/components/terminal/PermissionPrompt.tsx +4 -4
  49. package/src/components/terminal/affordances.tsx +1 -1
  50. package/src/components/terminal/height.ts +2 -2
  51. package/src/components/terminal/items.tsx +2 -2
  52. package/src/components/terminal/scrubber.tsx +1 -1
  53. package/src/components/terminal/todos.ts +1 -1
  54. package/src/components/ui/Splitter.tsx +1 -1
  55. package/src/lib/context-note.ts +3 -3
  56. package/src/lib/format.ts +2 -2
  57. package/src/styles/scoped.entry.css +2 -2
  58. package/src/styles/terminal.css +79 -79
  59. package/src/styles/theme.css +39 -39
  60. package/build/SessionPanel-B5FfiBxE.mjs.map +0 -1
  61. package/build/status-BO9wJloK.mjs.map +0 -1
@@ -5,7 +5,7 @@
5
5
  * *renderer*: every row it draws lands on the same character cell, and a grid
6
6
  * that has to be reassembled from `gap-2 pl-[calc(...)] -mx-1` at each call site
7
7
  * is a grid that drifts the first time someone edits one row. The components in
8
- * `components/terminal/` are therefore thin — they choose a class and a tone,
8
+ * `components/terminal/` are therefore thin - they choose a class and a tone,
9
9
  * and the geometry lives here in one place where it can be read as a whole.
10
10
  *
11
11
  * It also means an embedder gets the geometry without configuring Tailwind's
@@ -18,12 +18,12 @@
18
18
  * face is exactly one cell, so a gutter is `2ch` and an indent level is
19
19
  * `2ch`, and text lands on a column rather than near one. A wrapped line
20
20
  * hangs under its own first character because the body is its own grid
21
- * column — not because a padding and a negative text-indent were tuned
21
+ * column - not because a padding and a negative text-indent were tuned
22
22
  * against each other.
23
23
  * 2. **Vertical measures are whole multiples of `--term-line`, never padding.**
24
24
  * Blank space between blocks is a *blank line* (an empty row), the way it is
25
25
  * in a terminal. Nothing has margins, so no two blocks can disagree about
26
- * the rhythm, and a row's height is always an integer number of lines — the
26
+ * the rhythm, and a row's height is always an integer number of lines - the
27
27
  * thing that keeps text off half-pixels and out of the blur.
28
28
  *
29
29
  * `--term-font-size` and `--term-line` must both be whole pixels. A line height
@@ -33,8 +33,8 @@
33
33
  */
34
34
 
35
35
  [data-terminal] {
36
- /* Metrics. Overridable per host — VS Code hands its editor font down, and a
37
- phone wants a larger cell — but always in whole pixels. */
36
+ /* Metrics. Overridable per host - VS Code hands its editor font down, and a
37
+ phone wants a larger cell - but always in whole pixels. */
38
38
  --term-font-size: 13px;
39
39
  --term-line: 18px;
40
40
  /* One indent level, and the width of a gutter. The same value on purpose:
@@ -51,8 +51,8 @@
51
51
  font-feature-settings:
52
52
  'liga' 0,
53
53
  'calt' 0;
54
- /* `ch` is the advance of `0`, so tabular figures keep digit columns — the
55
- diff's line numbers — genuinely aligned. */
54
+ /* `ch` is the advance of `0`, so tabular figures keep digit columns - the
55
+ diff's line numbers - genuinely aligned. */
56
56
  font-variant-numeric: tabular-nums;
57
57
  -webkit-font-smoothing: antialiased;
58
58
  tab-size: 2;
@@ -96,7 +96,7 @@
96
96
  --term-diff-fg: #9a9a9a;
97
97
  --term-diff-num: #5a5a5a;
98
98
 
99
- /* A band of code or output. Barely there — one step off the canvas. */
99
+ /* A band of code or output. Barely there - one step off the canvas. */
100
100
  --term-band-bg: rgb(255 255 255 / 0.04);
101
101
  /* The user's own prompt row. */
102
102
  --term-user-bg: rgb(255 255 255 / 0.05);
@@ -104,7 +104,7 @@
104
104
  /* Behind an OPEN block. Yellow, not neutral, and the theme's one deliberate
105
105
  reuse of that tone for something other than "waiting on you": an open block
106
106
  is a state the reader put the transcript into, and on the phone it wants
107
- the same colour as the rail mark that says so. Kept very low — this washes
107
+ the same colour as the rail mark that says so. Kept very low - this washes
108
108
  whole regions, and at band strength an opened run would shout louder than
109
109
  anything inside it. */
110
110
  --term-open-wash: rgb(215 186 125 / 0.1);
@@ -150,7 +150,7 @@
150
150
  min-height: var(--term-line);
151
151
  }
152
152
 
153
- /* Indent levels. A nested row steps one cell per level — the same 2 columns a
153
+ /* Indent levels. A nested row steps one cell per level - the same 2 columns a
154
154
  marker occupies, so a child's marker sits under its parent's first letter. */
155
155
  .term-row[data-indent='1'] {
156
156
  padding-left: var(--term-cell);
@@ -163,7 +163,7 @@
163
163
  }
164
164
 
165
165
  .term-gutter {
166
- /* `pre` so a space-only gutter keeps its cell — an unmarked row must still
166
+ /* `pre` so a space-only gutter keeps its cell - an unmarked row must still
167
167
  start its text on the same column as a marked one. */
168
168
  white-space: pre;
169
169
  user-select: none;
@@ -172,7 +172,7 @@
172
172
  drag that *begins* on an unselectable node starts no selection at all, so
173
173
  without this the most natural way to select transcript text did nothing.
174
174
  Letting the press fall through to the row keeps `user-select: none` doing
175
- its real job — keeping the glyph out of the copied text — without owning
175
+ its real job - keeping the glyph out of the copied text - without owning
176
176
  the pointer. The row below is still pressable from here, since the press
177
177
  handler lives on the ancestor. */
178
178
  pointer-events: none;
@@ -188,7 +188,7 @@
188
188
  overflow-wrap: break-word;
189
189
  }
190
190
 
191
- /* A blank line — the only vertical spacing in the theme. Exactly one row tall
191
+ /* A blank line - the only vertical spacing in the theme. Exactly one row tall
192
192
  and holding nothing, which is what a terminal's blank line is. */
193
193
  .term-blank {
194
194
  height: var(--term-line);
@@ -197,7 +197,7 @@
197
197
  /* A row `scrollIntoView`ed lands one line below the top edge rather than flush
198
198
  against it, so the target reads as the start of something rather than as
199
199
  content cut off by the frame. Only the recap's `'center'` jump still goes
200
- through scrollIntoView — the scrubber's `'start'` jumps compute their own
200
+ through scrollIntoView - the scrubber's `'start'` jumps compute their own
201
201
  offset (a sticky row's rect is wherever it is pinned) and land the line at
202
202
  exactly the top edge. */
203
203
  [data-terminal] [data-slot='transcript-rows'] [data-index] {
@@ -215,7 +215,7 @@
215
215
  /* ── Bands ───────────────────────────────────────────────────────────────────
216
216
  *
217
217
  * A run of rows carrying a background: a code block, a command's output, a diff
218
- * hunk. Full-bleed — the wash reaches the scroller's edges rather than stopping
218
+ * hunk. Full-bleed - the wash reaches the scroller's edges rather than stopping
219
219
  * at a content gutter, because in a terminal the line *is* the full width.
220
220
  * `--term-bleed` is how far out that is; the transcript sets it to its own
221
221
  * padding and the band cancels it with matched negative margin and padding.
@@ -264,13 +264,13 @@
264
264
  }
265
265
 
266
266
  /* Weight is the only other axis. A terminal has one type size, so emphasis has
267
- to be carried by weight and colour — never by a larger glyph. */
267
+ to be carried by weight and colour - never by a larger glyph. */
268
268
  [data-terminal] [data-weight='bold'] {
269
269
  font-weight: 600;
270
270
  }
271
271
 
272
- /* The scroller. Its horizontal padding IS `--term-bleed` — that is the whole
273
- contract a full-bleed band relies on — and its vertical padding is a line, so
272
+ /* The scroller. Its horizontal padding IS `--term-bleed` - that is the whole
273
+ contract a full-bleed band relies on - and its vertical padding is a line, so
274
274
  the first row starts one blank line down like every other block. */
275
275
  [data-terminal].term-transcript {
276
276
  padding-inline: var(--term-bleed, 0px);
@@ -280,7 +280,7 @@
280
280
  /* ── Interaction ─────────────────────────────────────────────────────────────
281
281
  *
282
282
  * A terminal has no buttons, but a transcript does have things you can open. The
283
- * affordance is the hover fill on the row itself — nothing gains a border, a
283
+ * affordance is the hover fill on the row itself - nothing gains a border, a
284
284
  * radius or a focus box that would take it off the grid.
285
285
  */
286
286
  [data-terminal] .term-press {
@@ -299,7 +299,7 @@
299
299
  this is in `press.tsx`: the click that ends such a drag is refused. */
300
300
  user-select: text;
301
301
  }
302
- /* The hover fill lives with the other affordances below — it is one, and it is
302
+ /* The hover fill lives with the other affordances below - it is one, and it is
303
303
  switchable for the same reason. */
304
304
  [data-terminal] .term-press:focus-visible {
305
305
  outline: none;
@@ -307,9 +307,9 @@
307
307
 
308
308
  /* ── Affordances ─────────────────────────────────────────────────────────────
309
309
  *
310
- * What a real terminal cannot do. Every one of these costs **no layout** — a
310
+ * What a real terminal cannot do. Every one of these costs **no layout** - a
311
311
  * fill is a background, an action is an absolutely positioned overlay one line
312
- * tall — so switching them off leaves every glyph on the cell it was already on.
312
+ * tall - so switching them off leaves every glyph on the cell it was already on.
313
313
  * See `components/terminal/affordances.tsx`.
314
314
  */
315
315
 
@@ -326,7 +326,7 @@
326
326
  /* An opened block keeps the fill the pointer gave it, for the whole of what it
327
327
  opened. Eighty lines of output pushes its own first line off the top of the
328
328
  screen, and without a wash there is nothing to say where the thing you
329
- expanded began — or that these rows are one block at all. Full-bleed, like
329
+ expanded began - or that these rows are one block at all. Full-bleed, like
330
330
  every other wash; the hover fill inside it reaches the same edge, so the two
331
331
  stack without a step. (The other half is `useRevealOnOpen`, which brings that
332
332
  first line back when it has gone above the fold.) */
@@ -339,7 +339,7 @@
339
339
  /* Another frame of reference: the rows a subagent produced, inside the `Task`
340
340
  that spawned them.
341
341
 
342
- Two cells of indent, whole — the theme's rule is that horizontal measures are
342
+ Two cells of indent, whole - the theme's rule is that horizontal measures are
343
343
  `ch`, and these rows carry markers in a gutter that has to keep landing on the
344
344
  grid the rows above it use. The rule itself is drawn *inside* that padding
345
345
  with an inset shadow rather than as a border, which is what makes the 2ch
@@ -349,7 +349,7 @@
349
349
  `--term-faint` rather than the cards `--border` token, and that is the whole
350
350
  reason this class exists: the nested block sits on the *open* block's wash,
351
351
  and a border colour tuned for the base ground resolved to rgb(31,31,31) on it
352
- — a rule nobody could see. The same trap `row-hover` is alpha to avoid. */
352
+ - a rule nobody could see. The same trap `row-hover` is alpha to avoid. */
353
353
  [data-terminal] .term-nested {
354
354
  padding-left: 2ch;
355
355
  box-shadow: inset 1px 0 0 var(--term-faint);
@@ -396,14 +396,14 @@
396
396
  color: var(--term-fg);
397
397
  }
398
398
 
399
- /* What you typed, on a band of its own — the CLI's own treatment. */
399
+ /* What you typed, on a band of its own - the CLI's own treatment. */
400
400
  [data-terminal] .term-user {
401
401
  background: var(--term-user-bg);
402
402
  margin-inline: calc(-1 * var(--term-bleed, 0px));
403
403
  padding-inline: var(--term-bleed, 0px);
404
404
  /* Declared, never inherited. This band is the one transcript block that is
405
405
  neither a `.term-press` nor plain flow text, so without saying so it takes
406
- whatever the host gives it — which differs between the browser and the VS
406
+ whatever the host gives it - which differs between the browser and the VS
407
407
  Code webview, and a block that cannot host a selection endpoint does not
408
408
  merely refuse the drag: the selection jumps to the next valid position
409
409
  above it, swallowing everything in between. */
@@ -419,7 +419,7 @@
419
419
  /* A file path, while the modifier that would open it is held.
420
420
  *
421
421
  * Only then, and that is the point: a path *is* clickable but only under
422
- * Cmd/Ctrl, so it should only look clickable then — an always-underlined path
422
+ * Cmd/Ctrl, so it should only look clickable then - an always-underlined path
423
423
  * promises a plain click that does nothing. Applied by `usePathLinks` using the
424
424
  * same test the click itself makes, so nothing lights up that a click ignores.
425
425
  * Outside `[data-terminal]` too, since a cards transcript names files as well. */
@@ -430,7 +430,7 @@
430
430
  }
431
431
 
432
432
  /* A status-line reading that leads somewhere. Inline and unstyled until hovered
433
- — the line is meant to be quiet, and five underlined segments would make it
433
+ - the line is meant to be quiet, and five underlined segments would make it
434
434
  the loudest row on screen. */
435
435
  [data-terminal] .term-reading {
436
436
  font: inherit;
@@ -452,7 +452,7 @@
452
452
  * row is a fill, and the only "control" is a row you can press a number on.
453
453
  */
454
454
 
455
- /* One line tall with the stroke through its middle, full-bleed — the boundary
455
+ /* One line tall with the stroke through its middle, full-bleed - the boundary
456
456
  between the run and the decision. */
457
457
  [data-terminal] .term-rule-row {
458
458
  height: var(--term-line);
@@ -474,7 +474,7 @@
474
474
  }
475
475
 
476
476
  /* An option's expanded detail (a preview, a reason field) lines up with the
477
- option's own text — one gutter in, so it reads as belonging to that row. */
477
+ option's own text - one gutter in, so it reads as belonging to that row. */
478
478
  [data-terminal] .term-detail {
479
479
  padding-left: 5ch;
480
480
  }
@@ -511,7 +511,7 @@
511
511
  color: var(--bg, #000);
512
512
  }
513
513
 
514
- /* The bare text field — a caret and a rule, no box. */
514
+ /* The bare text field - a caret and a rule, no box. */
515
515
  [data-terminal] .term-input {
516
516
  width: 100%;
517
517
  min-width: 0;
@@ -524,7 +524,7 @@
524
524
  /* The terminal's own caret: a filled cell, not a hairline. It is the last
525
525
  thing in the theme still drawn the way the web draws it, and it is the one
526
526
  the eye is always on. `caret-animation: manual` hands the blink to the
527
- author and we then decline to animate it, so the block sits steady — a
527
+ author and we then decline to animate it, so the block sits steady - a
528
528
  blinking block is a strobe at this size, where a blinking hairline was
529
529
  merely a caret. Both are ignored where unsupported, which is exactly the
530
530
  right failure: a thin blinking caret is a plain caret, not a broken one. */
@@ -536,7 +536,7 @@
536
536
  no padding and `line-height` is `--term-line`, so the content box is always a
537
537
  whole number of lines and the rule under it lands on a cell boundary. The cap is
538
538
  lines too, not a pixel height. Where `field-sizing` is unsupported this is a
539
- one-line box that scrolls — the old single-line behaviour, minus the sideways
539
+ one-line box that scrolls - the old single-line behaviour, minus the sideways
540
540
  crawl, so the degradation costs nothing that was there before. */
541
541
  [data-terminal] textarea.term-input {
542
542
  display: block;
@@ -556,8 +556,8 @@
556
556
  *
557
557
  * The pinned prompt is the prompt's **first line**, and the pin is the
558
558
  * browser's, not script's. `TranscriptRows` renders each prompt inside a lane
559
- * spanning its turn; a one-line `sticky` **head** — the same row rendered
560
- * again, clipped by height — leads the lane with its flow footprint cancelled
559
+ * spanning its turn; a one-line `sticky` **head** - the same row rendered
560
+ * again, clipped by height - leads the lane with its flow footprint cancelled
561
561
  * (the negative bottom margin), so in flow it lies exactly over the real
562
562
  * row's first line and is invisible. The compositor pins it (no per-scroll
563
563
  * JS, no frame lag) and the lane's bottom edge pushes it off when the next
@@ -567,18 +567,18 @@
567
567
  * The head's visible line docks flush to the top edge of the scroller. Its
568
568
  * inter-row gap is padding on the head (matching the row it overlays), so a
569
569
  * gap-carrying head is one line taller and pins one line negative: the
570
- * padding parks above the viewport edge and the line starts at zero — which
570
+ * padding parks above the viewport edge and the line starts at zero - which
571
571
  * is also what makes the pin engage exactly when the line itself reaches the
572
572
  * top, not a line early.
573
573
  *
574
574
  * The lane spans the whole turn and the head is an overlay, so both are
575
- * transparent to the pointer — the rows it covers own interaction, and the
576
- * head is `aria-hidden` in the markup. The z-index is on the lane —
575
+ * transparent to the pointer - the rows it covers own interaction, and the
576
+ * head is `aria-hidden` in the markup. The z-index is on the lane -
577
577
  * every row wrapper is its own stacking context (they are transformed), so
578
578
  * the head's own z-index could never beat a later sibling.
579
579
  *
580
580
  * `--bg` is the panel's own ground, the same token the hover-revealed row
581
- * actions cover themselves with — the user band is translucent by design, so
581
+ * actions cover themselves with - the user band is translucent by design, so
582
582
  * without a ground the rows passing beneath would show straight through the
583
583
  * pinned head. Opaque always, which is invisible in flow: the ground behind
584
584
  * it is the same `--bg`, and the row it covers is its own content.
@@ -591,14 +591,14 @@
591
591
  /* The prompt itself is *inside* the lane, not beneath it, so the lane's `none`
592
592
  reached it too and made a user message the one block in the transcript the
593
593
  pointer could not touch: a drag started on it landed on the lane instead and
594
- selected nothing. Only the real row is given back — the head overlay above
594
+ selected nothing. Only the real row is given back - the head overlay above
595
595
  stays transparent, which is the whole point of the lane. */
596
596
  [data-terminal] [data-sticky-lane] > [data-index] {
597
597
  pointer-events: auto;
598
598
  }
599
599
 
600
600
  /* The head's own strip: the full lane, out of flow, so the head needs no
601
- footprint-cancelling margin — sticky confinement clamps the margin box, and
601
+ footprint-cancelling margin - sticky confinement clamps the margin box, and
602
602
  a negative margin shrinks it to nothing, letting the head overshoot the
603
603
  lane's end by its own height (two pinned prompts on screen at once). */
604
604
  [data-terminal] [data-sticky-lane] > [data-sticky-headlane] {
@@ -609,7 +609,7 @@
609
609
 
610
610
  /* Hidden until actually stuck (`data-stuck`, set by the lane's sentinel
611
611
  observer): an overlay visible in flow sits on the real row's first line and
612
- swallows its selection highlight — the line reads as unselectable. */
612
+ swallows its selection highlight - the line reads as unselectable. */
613
613
  [data-terminal] [data-sticky-headlane] > [data-sticky-head] {
614
614
  position: sticky;
615
615
  top: 0;
@@ -632,19 +632,19 @@
632
632
  /* ── Composer ────────────────────────────────────────────────────────────────
633
633
  *
634
634
  * The foot of the panel, and a *row* like every other: `>` in the gutter cell,
635
- * the caret on the body column. That is the whole design — a typed line and a
635
+ * the caret on the body column. That is the whole design - a typed line and a
636
636
  * rendered one start on the same character, which no chat composer does and
637
637
  * every terminal does for free.
638
638
  *
639
639
  * Docked rather than floating: no radius, no shadow, and a rule along the top
640
640
  * *and* the bottom, both turning accent while anything inside has focus. Those
641
641
  * two rules are the CLI's own frame for its prompt, and they are the only
642
- * affordance — which is what the transcript above (no boxes anywhere) asks for.
642
+ * affordance - which is what the transcript above (no boxes anywhere) asks for.
643
643
  * They also do the work a box would: the field reads as its own strip of the
644
644
  * panel rather than as the last row of the transcript, without a border on the
645
645
  * sides that would take the `❯` off the column the rows start on.
646
646
  *
647
- * The bottom rule is why the status bar under it draws none of its own — see
647
+ * The bottom rule is why the status bar under it draws none of its own - see
648
648
  * `StatusBar.tsx`. Two adjacent 1px rules is a 2px rule with a seam in it.
649
649
  */
650
650
  [data-terminal].term-composer {
@@ -654,7 +654,7 @@
654
654
  }
655
655
  /* The bar spans the panel; its contents sit in the transcript's own column, so
656
656
  the `>` lands on the column the rows above it start on. Two elements because
657
- those are two different widths — a rule that stopped at the content column
657
+ those are two different widths - a rule that stopped at the content column
658
658
  would read as a card, which is the one thing this theme has none of. */
659
659
  [data-terminal] .term-composer-body {
660
660
  margin-inline: auto;
@@ -663,7 +663,7 @@
663
663
  padding-inline: var(--term-bleed, 0px);
664
664
  /* Air on each side of the prompt, and a plain pixel value rather than a
665
665
  fraction of `--term-line`: this is chrome between two rules, not a
666
- transcript row, and the whole-multiple rule governs rows — a computed
666
+ transcript row, and the whole-multiple rule governs rows - a computed
667
667
  half-line would be exactly the fractional metric that rule exists to
668
668
  forbid. */
669
669
  padding-block: 8px;
@@ -674,7 +674,7 @@
674
674
  }
675
675
 
676
676
  /* Shell mode. The frame and the gutter glyph move together and both go magenta, because the thing
677
- the mode changes is where the text goes — a subtle cue would be the wrong kind of quiet. Listed
677
+ the mode changes is where the text goes - a subtle cue would be the wrong kind of quiet. Listed
678
678
  after the focus rule so it wins while the field is focused, which is the whole time it is on. */
679
679
  [data-terminal].term-composer-shell,
680
680
  [data-terminal].term-composer-shell:focus-within {
@@ -684,7 +684,7 @@
684
684
  color: var(--term-dim);
685
685
  }
686
686
 
687
- /* The contentEditable field. `font: inherit` is what makes it the cell — the
687
+ /* The contentEditable field. `font: inherit` is what makes it the cell - the
688
688
  surface above already carries the size and the line height, and anything that
689
689
  restates them here can disagree with the rows. */
690
690
  [data-terminal] .term-composer-field {
@@ -702,7 +702,7 @@
702
702
  * badge outside its top-right corner, over a strip with its own bottom rule.
703
703
  * None of that survives here: this theme has no rounded corners and no badges
704
704
  * floating off an edge, and the strip sits *inside* the composer's frame, which
705
- * already draws the only rule there is — a second one directly above the field
705
+ * already draws the only rule there is - a second one directly above the field
706
706
  * reads as the box this theme exists not to have.
707
707
  *
708
708
  * So the thumbnail is a plain 1px cell, and the remove control is tucked into
@@ -711,7 +711,7 @@
711
711
  * puts it just inside the thumbnail's border instead of straddling it.
712
712
  *
713
713
  * The strip's only spacing is the 8px the composer already uses above and below
714
- * its prompt — a plain pixel value, and deliberately, for the reason given
714
+ * its prompt - a plain pixel value, and deliberately, for the reason given
715
715
  * there: this is chrome between rules, not a transcript row, so the
716
716
  * whole-multiple-of-`--term-line` rule does not govern it. No side padding: the
717
717
  * strip is already inside the body column, so padding here would step it in
@@ -724,7 +724,7 @@
724
724
  }
725
725
  /* A refused upload, in the terminal's own red. This needs to be said here
726
726
  rather than left to the card form's `border-danger/50`: the rule above sets
727
- the `border` shorthand, colour included, and outranks a utility class — so
727
+ the `border` shorthand, colour included, and outranks a utility class - so
728
728
  without this the one state that must stand out is the one that looks
729
729
  ordinary. */
730
730
  [data-terminal] .term-attachment[data-failed] {
@@ -739,7 +739,7 @@
739
739
 
740
740
  /* A composer action as a character: one cell wide, one line tall, so pressing
741
741
  it costs no width and removing it would move nothing. Dim until you reach for
742
- it — the same restraint the row actions show. */
742
+ it - the same restraint the row actions show. */
743
743
  [data-terminal] .term-glyph {
744
744
  flex: none;
745
745
  width: var(--term-cell);
@@ -755,8 +755,8 @@
755
755
  cursor: pointer;
756
756
  }
757
757
  /* A glyph standing in the **gutter cell** is a marker, so it aligns like one.
758
- The cell is 2ch and a character is 1ch, so `text-align: center` — right for a
759
- standalone control at the row's trailing edge — lands the glyph half a cell
758
+ The cell is 2ch and a character is 1ch, so `text-align: center` - right for a
759
+ standalone control at the row's trailing edge - lands the glyph half a cell
760
760
  (≈3.9px at 13px/JetBrains Mono) to the right of the column every `❯` and `●`
761
761
  in the transcript starts on. `start` is what `.term-gutter` uses, and on this
762
762
  grid "nearly the same column" is just the wrong column. */
@@ -784,7 +784,7 @@
784
784
  * An added or removed line is a **band**, not coloured text: the wash runs the
785
785
  * full width of the screen, the way it does in a terminal, so the shape of a
786
786
  * change is readable from the scrollbar without reading a word of it. The line
787
- * numbers ride inside the wash — they are part of the changed line.
787
+ * numbers ride inside the wash - they are part of the changed line.
788
788
  */
789
789
  /* A diff belongs to the call above it, so it steps in one cell like any other
790
790
  tool output. */
@@ -813,7 +813,7 @@
813
813
  [data-terminal] .term-diff .term-row[data-diff='context'] {
814
814
  color: var(--term-diff-fg);
815
815
  }
816
- /* The number column is dimmer than the line it belongs to in every case — it is
816
+ /* The number column is dimmer than the line it belongs to in every case - it is
817
817
  an address, not content. `.term-gutter`'s own colour would flatten all three
818
818
  to one grey, so each state dims its own. */
819
819
  [data-terminal] .term-diff .term-row > .term-gutter {
@@ -829,13 +829,13 @@
829
829
  /* ── Markdown ────────────────────────────────────────────────────────────────
830
830
  *
831
831
  * The element map is in `components/terminal/markdown.tsx`; this is the little
832
- * CSS it needs. Nothing here is an override — the renderer is told what to emit,
832
+ * CSS it needs. Nothing here is an override - the renderer is told what to emit,
833
833
  * so there is no default to undo and no `!important` anywhere in the theme.
834
834
  */
835
835
 
836
836
  /* react-markdown emits the source's newlines as text nodes between blocks. The
837
837
  surrounding rows are `pre-wrap` (a plain line of output must keep its own
838
- spacing), which would render every one of those as a visible blank line — so
838
+ spacing), which would render every one of those as a visible blank line - so
839
839
  markdown bodies opt back out, and only a fenced block opts back in. */
840
840
  .term-md {
841
841
  white-space: normal;
@@ -844,7 +844,7 @@
844
844
  /* And it has to reach `.term-body` explicitly, because a list item *is* a Row
845
845
  and Rows carry `pre-wrap` (a plain line of tool output must keep its own
846
846
  spacing). Inherited, that turns every newline react-markdown emits between an
847
- item's block children into a visible empty line — a nested list drew k+2
847
+ item's block children into a visible empty line - a nested list drew k+2
848
848
  phantom blanks, so a two-line nested item was 72px of 18px rows. Models nest
849
849
  lists constantly, and the grid audit cannot see it: the phantoms are whole
850
850
  lines, so every row still lands on the grid. Fenced code opts back in for
@@ -856,7 +856,7 @@
856
856
 
857
857
  /* The one vertical rule: consecutive blocks are one blank line apart. A margin
858
858
  rather than an inserted row, because this row list belongs to the markdown
859
- renderer — but it is exactly one line, so the grid holds. */
859
+ renderer - but it is exactly one line, so the grid holds. */
860
860
  .term-md .term-block + .term-block {
861
861
  margin-top: var(--term-line);
862
862
  }
@@ -889,7 +889,7 @@
889
889
  background: linear-gradient(var(--term-faint), var(--term-faint)) left / 1px 100% no-repeat;
890
890
  }
891
891
 
892
- /* A horizontal rule is one line tall with the rule through its middle — the row
892
+ /* A horizontal rule is one line tall with the rule through its middle - the row
893
893
  it occupies is a whole line either way. */
894
894
  .term-md .term-rule {
895
895
  height: var(--term-line);
@@ -921,7 +921,7 @@
921
921
  border-collapse: collapse;
922
922
  /* `max-content` and **no** `max-width`. A cap of `100%` looks like the
923
923
  defensive choice and is the opposite: it clamps a wide table below its
924
- natural width, so the cells wrap and a 14-row table becomes 19 lines tall —
924
+ natural width, so the cells wrap and a 14-row table becomes 19 lines tall -
925
925
  which breaks the theme's premise (a row is a line) and with it the height
926
926
  calculator, whose table model counts rows. It also silently disables the
927
927
  wrapper's own `overflow-x`, since a table that shrinks never overflows.
@@ -943,15 +943,15 @@
943
943
  /* ── Scrubber ────────────────────────────────────────────────────────────────
944
944
  *
945
945
  * The overview ruler (`components/terminal/scrubber.tsx`): a 12px rail of marks
946
- * over the scroller's right edge — VS Code's strip beside the minimap, with
946
+ * over the scroller's right edge - VS Code's strip beside the minimap, with
947
947
  * this transcript's semantics. It is *chrome*, not rows: absolutely positioned
948
948
  * over the scroll container so the transcript's grid is untouched, and drawn
949
949
  * entirely from --term-* tokens so it follows the theme wherever the panel is
950
950
  * embedded. Its width is the one deliberate exception to the theme's `ch` rule
951
- * — see the note on `.term-scrubber` below.
951
+ * - see the note on `.term-scrubber` below.
952
952
  *
953
953
  * Interactivity is an affordance. Without `data-interactive` the rail is
954
- * passive paint with pointer events off — and the native scrollbar, which
954
+ * passive paint with pointer events off - and the native scrollbar, which
955
955
  * stays in that mode, keeps working straight through it.
956
956
  */
957
957
  [data-terminal].term-scrubber {
@@ -977,7 +977,7 @@
977
977
  touch-action: none;
978
978
  }
979
979
 
980
- /* The viewport band — where you are: a faint wash with a hairline frame,
980
+ /* The viewport band - where you are: a faint wash with a hairline frame,
981
981
  floated over the marks (z-index) so the framed region reads as a window
982
982
  onto the rail rather than a stripe behind it. `--term-faint` at 25% rather
983
983
  than a literal, so the light palette re-tints it. */
@@ -992,7 +992,7 @@
992
992
  }
993
993
 
994
994
  /* There is no separate cursor line. The band above answers "where am I" on its
995
- own — it is outlined, so its top edge already reads as an edge — and a 2px
995
+ own - it is outlined, so its top edge already reads as an edge - and a 2px
996
996
  blue rule laid over it was a second indicator of the same fact, in the
997
997
  loudest colour the rail has. */
998
998
 
@@ -1007,7 +1007,7 @@
1007
1007
  outline: 1px solid color-mix(in srgb, var(--term-bright) 40%, transparent);
1008
1008
  }
1009
1009
 
1010
- /* Two lanes of 8px — what you asked, and what came back — and 'f', the
1010
+ /* Two lanes of 8px - what you asked, and what came back - and 'f', the
1011
1011
  full-width lane for annotations *about* the run (an error, an approval, a
1012
1012
  bookmark, the catch-up seam) rather than steps through it. Pixels, not
1013
1013
  percentages: the whole point of the 16px rail is that a lane is a reliable
@@ -1026,7 +1026,7 @@
1026
1026
  width: 12px;
1027
1027
  }
1028
1028
 
1029
- /* Lane marks are two-tone: the first 2px — the mark's own anchor — at full
1029
+ /* Lane marks are two-tone: the first 2px - the mark's own anchor - at full
1030
1030
  strength, the rest of the row's extent a 25% tail, so a long answer reads
1031
1031
  as long without a tall solid bar shouting over the rail. A minimum-height
1032
1032
  mark shows only the solid segment, so short and long marks need no separate
@@ -1038,7 +1038,7 @@
1038
1038
  }
1039
1039
  /* A sub-agent's stretch of the transcript, in the input lane: green, because
1040
1040
  every other colour on this rail is already spoken for and none of them means
1041
- "somebody else's working" — blue is you, white is the answer, red is an
1041
+ "somebody else's working" - blue is you, white is the answer, red is an
1042
1042
  alarm, magenta is your bookmark, yellow is the session waiting on you. Drawn
1043
1043
  as an extent (2px head, 25% tail) like the two marks it shares its geometry
1044
1044
  with: collapsed it is a tick, expanded it is the band the sub-agent covers. */
@@ -1054,13 +1054,13 @@
1054
1054
  .term-scrubber .term-scrub-mark[data-kind='error'] {
1055
1055
  background: var(--term-red);
1056
1056
  }
1057
- /* A failed tool call is an alarm, so it is solid like the rest of them — in the
1058
- response lane, since it is something the run produced — but at 55%, which is the one thing keeping the rail readable. A session
1057
+ /* A failed tool call is an alarm, so it is solid like the rest of them - in the
1058
+ response lane, since it is something the run produced - but at 55%, which is the one thing keeping the rail readable. A session
1059
1059
  error is rare and a turn failure rarer; a tool that failed and was recovered
1060
1060
  from is routine (a grep that matched nothing, a build fixed on the second go),
1061
1061
  and at full strength a normal working session paints the rail solid red and
1062
1062
  the two errors that actually ended something stop standing out. Dimmer reads
1063
- as the same class of thing, one rank quieter — which is exactly its rank in
1063
+ as the same class of thing, one rank quieter - which is exactly its rank in
1064
1064
  LOUDNESS. */
1065
1065
  .term-scrubber .term-scrub-mark[data-kind='toolFailed'] {
1066
1066
  background: color-mix(in srgb, var(--term-red) 55%, transparent);
@@ -1087,8 +1087,8 @@
1087
1087
  }
1088
1088
  }
1089
1089
 
1090
- /* The peek. Rendered from transcript state — the row it describes is usually
1091
- unmounted — and framed the theme's way: strokes as backgrounds, no border.
1090
+ /* The peek. Rendered from transcript state - the row it describes is usually
1091
+ unmounted - and framed the theme's way: strokes as backgrounds, no border.
1092
1092
  pointer-events: none, so it can never trap the pointer that revealed it. */
1093
1093
  .term-scrubber .term-scrub-peek {
1094
1094
  position: absolute;
@@ -1124,7 +1124,7 @@
1124
1124
 
1125
1125
  /* While an interactive scrubber is mounted it IS the scrollbar; the transcript
1126
1126
  stamps this attribute on the scroll element. A passive rail leaves the
1127
- native scrollbar alone — pointer-events: none above is what keeps that
1127
+ native scrollbar alone - pointer-events: none above is what keeps that
1128
1128
  scrollbar reachable through the paint. */
1129
1129
  [data-term-scrubber-host] {
1130
1130
  scrollbar-width: none;
@@ -1138,7 +1138,7 @@
1138
1138
  * A picture a tool returned, drawn in a box of whole lines (`IMAGE_BOX_LINES`,
1139
1139
  * set inline by `TerminalImage` so the constant has one spelling across the
1140
1140
  * renderer and the height calculator). The height is on the element and nothing
1141
- * here may add to it: no margin, no border, no padding — a box that is not
1141
+ * here may add to it: no margin, no border, no padding - a box that is not
1142
1142
  * exactly N lines is a row the virtualizer was told the wrong size for.
1143
1143
  *
1144
1144
  * `object-fit: contain` with a top-left origin rather than a centred one: the