@cplieger/web-terminal-ui 3.5.0 → 4.0.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/README.md +52 -23
- package/css/00-tokens.css +8 -2
- package/css/01-scope.css +56 -0
- package/css/{02-app.css → 02-terminal.css} +64 -239
- package/css/{03-primitives.css → 10-primitives.css} +21 -19
- package/css/20-connection-banner.css +42 -0
- package/css/21-scroll-to-bottom.css +65 -0
- package/css/22-context-menu.css +45 -0
- package/css/23-toolbar.css +181 -0
- package/css/{05-tabs.css → 30-tabs.css} +96 -57
- package/css/{06-mobile.css → 31-switcher.css} +66 -81
- package/css/{07-animations.css → 40-animations.css} +15 -15
- package/css/MANIFEST +19 -11
- package/css/MANIFEST.single +12 -0
- package/css/MANIFEST.tabbed +16 -0
- package/css/MANIFEST.touch +12 -0
- package/css/{01-reset.css → page.css} +18 -19
- package/package.json +18 -5
- package/scaffold/index.html +5 -0
- package/src/features/context-menu.ts +6 -33
- package/src/features/menu-position.ts +50 -0
- package/src/features/{tabs.ts → tabs/index.ts} +204 -655
- package/src/features/tabs/model.ts +334 -0
- package/src/features/tabs/strip.ts +101 -0
- package/src/features/tabs/switcher.ts +129 -0
- package/src/index.ts +1 -0
- package/src/kernel/a11y.ts +30 -5
- package/src/kernel/kernel.ts +149 -59
- package/src/kernel/types.ts +55 -14
- package/src/presets/agent-tabbed.ts +15 -0
- package/src/presets/single.ts +27 -0
- package/src/presets/tabbed.ts +42 -0
- package/src/presets/touch.ts +13 -0
- package/src/presets.ts +12 -76
- package/src/viewport.ts +28 -15
- package/css/04-feedback.css +0 -180
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
/* ===== Tabs: desktop strip + activity vocabulary (tabs feature) =====
|
|
2
2
|
The desktop top-bar tab strip, its per-tab chrome (label, close, add, the
|
|
3
|
-
right-click menu), the surface offset that clears the
|
|
3
|
+
right-click menu), the surface offset that clears the docked strip, and the
|
|
4
4
|
shared activity-dot status vocabulary. The mobile tab chrome (switcher bar,
|
|
5
|
-
overview sheet, external key grid) lives in
|
|
6
|
-
|
|
5
|
+
overview sheet, external key grid) lives in 31-switcher.css; all motion lives
|
|
6
|
+
in 40-animations.css. */
|
|
7
7
|
|
|
8
|
-
.wt-region-top-bar {
|
|
8
|
+
:where(.wt-root) .wt-region-top-bar {
|
|
9
9
|
/* On desktop the tab strip docks to the top; the region is transparent, so
|
|
10
10
|
the bar element below owns its own fixed placement. */
|
|
11
11
|
display: contents;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
.wt-tab-bar {
|
|
15
|
-
|
|
14
|
+
:where(.wt-root) .wt-tab-bar {
|
|
15
|
+
/* Absolute against .wt-root, like all chrome (identical geometry in
|
|
16
|
+
wt-viewport mode; see 01-scope.css). */
|
|
17
|
+
position: absolute;
|
|
16
18
|
bottom: var(--safe-bottom);
|
|
17
19
|
left: 0;
|
|
18
20
|
right: 0;
|
|
@@ -28,7 +30,7 @@
|
|
|
28
30
|
z-index: 15;
|
|
29
31
|
}
|
|
30
32
|
|
|
31
|
-
.wt-tab {
|
|
33
|
+
:where(.wt-root) .wt-tab {
|
|
32
34
|
display: inline-flex;
|
|
33
35
|
align-items: center;
|
|
34
36
|
gap: var(--sp-1);
|
|
@@ -56,12 +58,12 @@
|
|
|
56
58
|
|
|
57
59
|
/* Inactive tabs read as outlined chips with a subtle dark fill (so adjacent tabs
|
|
58
60
|
stay separated from the bar and from each other) and lift on hover. */
|
|
59
|
-
.wt-tab:not(.wt-tab-active) {
|
|
61
|
+
:where(.wt-root) .wt-tab:not(.wt-tab-active) {
|
|
60
62
|
border-color: var(--border);
|
|
61
63
|
background: var(--tab-bg);
|
|
62
64
|
}
|
|
63
65
|
|
|
64
|
-
.wt-tab:not(.wt-tab-active):hover {
|
|
66
|
+
:where(.wt-root) .wt-tab:not(.wt-tab-active):hover {
|
|
65
67
|
/* A solid lift over the chip. --tab-hover-bg is a translucent wash meant for a
|
|
66
68
|
transparent-rest control; replacing the --tab-bg chip with it would read as
|
|
67
69
|
"more transparent", not "lighter", so bake the same 15% --text lift into the
|
|
@@ -73,7 +75,7 @@
|
|
|
73
75
|
/* The active tab reads clearly above the inactive chips: a stronger fill plus an
|
|
74
76
|
accent-coloured edge (inactive chips carry a faint white --border; the active
|
|
75
77
|
one gets the accent equivalent). Themeable via --accent (web-terminal-kiro -> purple). */
|
|
76
|
-
.wt-tab-active {
|
|
78
|
+
:where(.wt-root) .wt-tab-active {
|
|
77
79
|
background: var(--tab-active-bg);
|
|
78
80
|
border-color: var(--tab-active-border);
|
|
79
81
|
color: var(--tab-active-fg);
|
|
@@ -81,7 +83,7 @@
|
|
|
81
83
|
|
|
82
84
|
/* The label flexes to fill the fixed-width tab and truncates with an ellipsis
|
|
83
85
|
(min-width: 0 lets a flex item shrink below its content width). */
|
|
84
|
-
.wt-tab-label {
|
|
86
|
+
:where(.wt-root) .wt-tab-label {
|
|
85
87
|
flex: 1 1 auto;
|
|
86
88
|
min-width: 0;
|
|
87
89
|
overflow: hidden;
|
|
@@ -90,14 +92,14 @@
|
|
|
90
92
|
}
|
|
91
93
|
|
|
92
94
|
/* A little breathing room after the activity dot, before the label. */
|
|
93
|
-
.wt-tab-dot {
|
|
95
|
+
:where(.wt-root) .wt-tab-dot {
|
|
94
96
|
margin-right: 2px;
|
|
95
97
|
}
|
|
96
98
|
|
|
97
99
|
/* The tab close (x): a centered, muted square icon button with a box on hover.
|
|
98
100
|
Its glyph is an inline SVG (styled below), so flex-centering the button
|
|
99
101
|
centers it exactly. */
|
|
100
|
-
.wt-tab-close {
|
|
102
|
+
:where(.wt-root) .wt-tab-close {
|
|
101
103
|
display: inline-flex;
|
|
102
104
|
align-items: center;
|
|
103
105
|
justify-content: center;
|
|
@@ -116,27 +118,28 @@
|
|
|
116
118
|
cursor: pointer;
|
|
117
119
|
}
|
|
118
120
|
|
|
119
|
-
.wt-tab-close:hover {
|
|
121
|
+
:where(.wt-root) .wt-tab-close:hover {
|
|
120
122
|
background: var(--text-active);
|
|
121
123
|
color: var(--text);
|
|
122
124
|
}
|
|
123
125
|
|
|
124
126
|
/* On an inactive tab the close appears only on hover, kept in the layout via
|
|
125
127
|
visibility so the tab width never jumps; on the active tab it is always shown. */
|
|
126
|
-
.wt-tab:not(.wt-tab-active) .wt-tab-close {
|
|
128
|
+
:where(.wt-root) .wt-tab:not(.wt-tab-active) .wt-tab-close {
|
|
127
129
|
visibility: hidden;
|
|
128
130
|
}
|
|
129
131
|
|
|
130
|
-
.wt-tab:not(.wt-tab-active):hover .wt-tab-close {
|
|
132
|
+
:where(.wt-root) .wt-tab:not(.wt-tab-active):hover .wt-tab-close {
|
|
131
133
|
visibility: visible;
|
|
132
134
|
}
|
|
133
135
|
|
|
134
136
|
/* Coarse pointer (an iPad using the strip): no hover fires, so an inactive tab's close
|
|
135
137
|
would be unreachable without first activating the tab. Reveal every tab's close there,
|
|
136
|
-
matching the always-visible mobile switcher closes.
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
138
|
+
matching the always-visible mobile switcher closes. No narrow gate needed: on the
|
|
139
|
+
narrow-coarse phone the whole strip is display:none (31-switcher.css), so this rule
|
|
140
|
+
is moot there. */
|
|
141
|
+
@media (pointer: coarse) {
|
|
142
|
+
:where(.wt-root) .wt-tab:not(.wt-tab-active) .wt-tab-close {
|
|
140
143
|
visibility: visible;
|
|
141
144
|
}
|
|
142
145
|
}
|
|
@@ -144,7 +147,7 @@
|
|
|
144
147
|
/* The add-tab (+) button: its hover box matches an active tab's fill and
|
|
145
148
|
stretches to the strip height; the 2px strip gap (not a custom margin) spaces
|
|
146
149
|
it from the last tab. Its glyph is an inline SVG. */
|
|
147
|
-
.wt-tab-new {
|
|
150
|
+
:where(.wt-root) .wt-tab-new {
|
|
148
151
|
display: inline-flex;
|
|
149
152
|
align-items: center;
|
|
150
153
|
justify-content: center;
|
|
@@ -166,7 +169,7 @@
|
|
|
166
169
|
cursor: pointer;
|
|
167
170
|
}
|
|
168
171
|
|
|
169
|
-
.wt-tab-new:hover {
|
|
172
|
+
:where(.wt-root) .wt-tab-new:hover {
|
|
170
173
|
/* Keep the accent glyph on hover (no colour override) so the "+" stays the
|
|
171
174
|
accent colour like the mobile "+"; hover only adds the fill. */
|
|
172
175
|
background: var(--tab-active-bg);
|
|
@@ -175,8 +178,8 @@
|
|
|
175
178
|
/* The +/x icons are inline SVG so they center exactly in their flex-centered
|
|
176
179
|
button and stay symmetric regardless of the UI font (fixes the off-center
|
|
177
180
|
glyph and the lopsided "+"). The + is a touch larger and bolder than the x. */
|
|
178
|
-
.wt-tab-close svg,
|
|
179
|
-
.wt-tab-new svg {
|
|
181
|
+
:where(.wt-root) .wt-tab-close svg,
|
|
182
|
+
:where(.wt-root) .wt-tab-new svg {
|
|
180
183
|
stroke: currentcolor;
|
|
181
184
|
fill: none;
|
|
182
185
|
stroke-width: 2.5;
|
|
@@ -184,12 +187,12 @@
|
|
|
184
187
|
stroke-linejoin: round;
|
|
185
188
|
}
|
|
186
189
|
|
|
187
|
-
.wt-tab-close svg {
|
|
190
|
+
:where(.wt-root) .wt-tab-close svg {
|
|
188
191
|
width: 13px;
|
|
189
192
|
height: 13px;
|
|
190
193
|
}
|
|
191
194
|
|
|
192
|
-
.wt-tab-new svg {
|
|
195
|
+
:where(.wt-root) .wt-tab-new svg {
|
|
193
196
|
width: 16px;
|
|
194
197
|
height: 16px;
|
|
195
198
|
}
|
|
@@ -205,23 +208,23 @@
|
|
|
205
208
|
strip, before the "+" (kb-then-new, mirroring the mobile switcher's order).
|
|
206
209
|
Hidden on a fine-pointer desktop (a real keyboard is present) and until a
|
|
207
210
|
keyboardToggle feature is wired ([hidden]); shown only on a coarse pointer at
|
|
208
|
-
strip widths (the
|
|
209
|
-
|
|
210
|
-
.wt-tab-kb {
|
|
211
|
+
strip widths (the .wt-narrow complement below; the breakpoint itself is the
|
|
212
|
+
kernel's, mirrored as the root class). */
|
|
213
|
+
:where(.wt-root) .wt-tab-kb {
|
|
211
214
|
display: none;
|
|
212
215
|
flex: none;
|
|
213
216
|
}
|
|
214
217
|
|
|
215
218
|
/* Grid open: filled so the toggled state reads at a glance (mirrors the
|
|
216
219
|
switcher keyboard button). */
|
|
217
|
-
.wt-tab-kb.wt-active {
|
|
220
|
+
:where(.wt-root) .wt-tab-kb.wt-active {
|
|
218
221
|
background: var(--tab-hover-bg);
|
|
219
222
|
color: var(--tab-active-fg);
|
|
220
223
|
}
|
|
221
224
|
|
|
222
225
|
/* Sticky-Ctrl armed: invert (matches the switcher keyboard button + the armed
|
|
223
226
|
Ctrl key) so a pending Ctrl is visible with the grid closed. */
|
|
224
|
-
.wt-tab-kb.wt-armed {
|
|
227
|
+
:where(.wt-root) .wt-tab-kb.wt-armed {
|
|
225
228
|
background: var(--text);
|
|
226
229
|
color: var(--bg);
|
|
227
230
|
}
|
|
@@ -229,14 +232,14 @@
|
|
|
229
232
|
/* Show only on a WIDE touchscreen (where the desktop strip is used AND a
|
|
230
233
|
keyboardToggle is wired, hence :not([hidden])). In-flow now, so the strip
|
|
231
234
|
needs no reserved right padding for it. */
|
|
232
|
-
@media (pointer: coarse)
|
|
233
|
-
.wt-tab-kb:not([hidden]) {
|
|
235
|
+
@media (pointer: coarse) {
|
|
236
|
+
:where(.wt-root:not(.wt-narrow)) .wt-tab-kb:not([hidden]) {
|
|
234
237
|
display: inline-flex;
|
|
235
238
|
}
|
|
236
239
|
}
|
|
237
240
|
|
|
238
241
|
/* The tab being dragged (reorder) dims while it moves. */
|
|
239
|
-
.wt-tab-dragging {
|
|
242
|
+
:where(.wt-root) .wt-tab-dragging {
|
|
240
243
|
opacity: 0.5;
|
|
241
244
|
}
|
|
242
245
|
|
|
@@ -244,8 +247,10 @@
|
|
|
244
247
|
Close to the right / Close to the left / Close all. Replaces the old bar
|
|
245
248
|
"Close all" button. Mirrors .wt-ctx-menu (a fixed surface popover, clamped
|
|
246
249
|
into the viewport by the feature); disabled items are dimmed and inert. */
|
|
247
|
-
.wt-tab-menu {
|
|
248
|
-
|
|
250
|
+
:where(.wt-root) .wt-tab-menu {
|
|
251
|
+
/* Absolute against .wt-root; placed by the shared point-anchored positioner
|
|
252
|
+
(menu-position.ts), which converts to root-relative offsets. */
|
|
253
|
+
position: absolute;
|
|
249
254
|
display: none;
|
|
250
255
|
flex-direction: column;
|
|
251
256
|
background: var(--surface);
|
|
@@ -256,11 +261,11 @@
|
|
|
256
261
|
z-index: 30;
|
|
257
262
|
}
|
|
258
263
|
|
|
259
|
-
.wt-tab-menu.visible {
|
|
264
|
+
:where(.wt-root) .wt-tab-menu.visible {
|
|
260
265
|
display: flex;
|
|
261
266
|
}
|
|
262
267
|
|
|
263
|
-
.wt-tab-menu button {
|
|
268
|
+
:where(.wt-root) .wt-tab-menu button {
|
|
264
269
|
background: transparent;
|
|
265
270
|
color: var(--text);
|
|
266
271
|
border: none;
|
|
@@ -274,30 +279,37 @@
|
|
|
274
279
|
white-space: nowrap;
|
|
275
280
|
}
|
|
276
281
|
|
|
277
|
-
|
|
282
|
+
/* :enabled (not :not(:disabled)) keeps the pseudo-class count within the
|
|
283
|
+
stylelint budget alongside the zero-specificity scope. */
|
|
284
|
+
:where(.wt-root) .wt-tab-menu button:enabled:hover {
|
|
278
285
|
background: var(--text-active);
|
|
279
286
|
}
|
|
280
287
|
|
|
281
|
-
.wt-tab-menu button:disabled {
|
|
288
|
+
:where(.wt-root) .wt-tab-menu button:disabled {
|
|
282
289
|
color: color-mix(in oklch, var(--text) 35%, transparent);
|
|
283
290
|
cursor: default;
|
|
284
291
|
}
|
|
285
292
|
|
|
286
|
-
/* Pull the terminal surface up off the
|
|
293
|
+
/* Pull the terminal surface up off the docked BOTTOM tab strip so it does not
|
|
287
294
|
overlap the last rows (a mirror of the old top offset). The tabs feature
|
|
288
295
|
marks the surface (.wt-with-tabbar) and keeps the measured strip height in
|
|
289
|
-
--wt-tabbar-h; the surface is
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
css/
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
296
|
+
--wt-tabbar-h; the surface is absolute inset:0, so a bottom offset clears it.
|
|
297
|
+
Applies whenever the desktop strip is shown — a fine pointer OR a root that
|
|
298
|
+
is not narrow (an iPad) — the complement of the narrow-coarse switcher gate
|
|
299
|
+
in css/31-switcher.css. On the narrow-coarse phone the strip is hidden and
|
|
300
|
+
the mobile switcher's inset is applied through viewport.ts
|
|
301
|
+
(--wt-reserve-bottom) instead. Two rules because the class half cannot mix
|
|
302
|
+
into a media condition; they set the same declaration. */
|
|
303
|
+
@media (pointer: fine) {
|
|
304
|
+
:where(.wt-root) .term.wt-with-tabbar {
|
|
297
305
|
bottom: var(--wt-tabbar-h, 44px);
|
|
298
306
|
}
|
|
299
307
|
}
|
|
300
308
|
|
|
309
|
+
:where(.wt-root:not(.wt-narrow)) .term.wt-with-tabbar {
|
|
310
|
+
bottom: var(--wt-tabbar-h, 44px);
|
|
311
|
+
}
|
|
312
|
+
|
|
301
313
|
/* ===== Activity dots (activityMonitor via tabs) =====
|
|
302
314
|
Four-state, distinguishable without color (shape + motion, not hue alone),
|
|
303
315
|
per section 12 / WCAG 1.4.1. The one .wt-status-dot vocabulary is shared by
|
|
@@ -310,7 +322,7 @@
|
|
|
310
322
|
stay clean, label-only; a progress-reporting agent (kiro-cli, Claude Code)
|
|
311
323
|
lights up. The element stays in the DOM either way (JS sets data-status
|
|
312
324
|
regardless), so revealing it is a pure CSS switch. */
|
|
313
|
-
.wt-status-dot {
|
|
325
|
+
:where(.wt-root) .wt-status-dot {
|
|
314
326
|
display: none;
|
|
315
327
|
width: 9px;
|
|
316
328
|
height: 9px;
|
|
@@ -327,11 +339,11 @@
|
|
|
327
339
|
/* Reveal a dot only once its session has reported activity (the tabs feature
|
|
328
340
|
adds .wt-reports per dot; see paintStatusDot). Without it the dot — and the
|
|
329
341
|
whole activity vocabulary for that tab — stays invisible. */
|
|
330
|
-
.wt-status-dot.wt-reports {
|
|
342
|
+
:where(.wt-root) .wt-status-dot.wt-reports {
|
|
331
343
|
display: block;
|
|
332
344
|
}
|
|
333
345
|
|
|
334
|
-
.wt-status-dot[data-status="idle"] {
|
|
346
|
+
:where(.wt-root) .wt-status-dot[data-status="idle"] {
|
|
335
347
|
background: transparent;
|
|
336
348
|
border: 1.5px solid color-mix(in oklch, var(--text) 45%, transparent);
|
|
337
349
|
}
|
|
@@ -341,7 +353,7 @@
|
|
|
341
353
|
on every tab state.) Motion is the primary non-hue cue. Server-side this is
|
|
342
354
|
driven by the OSC 9;4 progress signal, so it tracks agent activity, not the
|
|
343
355
|
user typing at the prompt. */
|
|
344
|
-
.wt-status-dot[data-status="working"] {
|
|
356
|
+
:where(.wt-root) .wt-status-dot[data-status="working"] {
|
|
345
357
|
background: #fff;
|
|
346
358
|
border-color: #fff;
|
|
347
359
|
animation: wt-pulse 1.2s ease-in-out infinite;
|
|
@@ -349,7 +361,7 @@
|
|
|
349
361
|
|
|
350
362
|
/* Agent done / ready: solid green, matching Kiro IDE's "Ready" (#22c55e), no
|
|
351
363
|
motion. The filled dot distinguishes it from the hollow idle without hue. */
|
|
352
|
-
.wt-status-dot[data-status="done"] {
|
|
364
|
+
:where(.wt-root) .wt-status-dot[data-status="done"] {
|
|
353
365
|
background: #22c55e;
|
|
354
366
|
border-color: #22c55e;
|
|
355
367
|
}
|
|
@@ -357,14 +369,14 @@
|
|
|
357
369
|
/* User action required (permission / approval): solid amber matching Kiro IDE's
|
|
358
370
|
"waiting-approval" (#fbbf24), plus a ring so it reads as "needs you" via shape
|
|
359
371
|
as well as hue. It persists until you act on or switch into the tab. */
|
|
360
|
-
.wt-status-dot[data-status="input"] {
|
|
372
|
+
:where(.wt-root) .wt-status-dot[data-status="input"] {
|
|
361
373
|
background: #fbbf24;
|
|
362
374
|
border-color: #fbbf24;
|
|
363
375
|
box-shadow: 0 0 0 2px oklch(85% 0.16 85deg / 40%);
|
|
364
376
|
}
|
|
365
377
|
|
|
366
378
|
/* Exited: a dim hollow dot, static; distinct from idle by its lower opacity. */
|
|
367
|
-
.wt-status-dot[data-status="exited"] {
|
|
379
|
+
:where(.wt-root) .wt-status-dot[data-status="exited"] {
|
|
368
380
|
background: transparent;
|
|
369
381
|
border: 1.5px solid color-mix(in oklch, var(--text) 30%, transparent);
|
|
370
382
|
opacity: 0.5;
|
|
@@ -378,7 +390,7 @@
|
|
|
378
390
|
|
|
379
391
|
/* Reduced-motion (or the animations feature off): drop the pulse, keep color. */
|
|
380
392
|
@media (prefers-reduced-motion: reduce) {
|
|
381
|
-
.wt-status-dot[data-status="working"] {
|
|
393
|
+
:where(.wt-root) .wt-status-dot[data-status="working"] {
|
|
382
394
|
animation: none;
|
|
383
395
|
/* The pulse is working's ONLY non-hue cue; with motion removed,
|
|
384
396
|
add a static shape cue (an inner hole -> a ring) so working differs
|
|
@@ -386,3 +398,30 @@
|
|
|
386
398
|
box-shadow: inset 0 0 0 2px var(--bg);
|
|
387
399
|
}
|
|
388
400
|
}
|
|
401
|
+
|
|
402
|
+
/* ===== Catching-up cue (tabs feature, sections 12/13) =====
|
|
403
|
+
A switched-into tab's cached screen is stale until its resume delta lands, so
|
|
404
|
+
it must not read as live. This unobtrusive cue shows only if the delta has not
|
|
405
|
+
arrived shortly after the switch, and clears on the first screen frame.
|
|
406
|
+
Absolute against .wt-root, like all chrome. */
|
|
407
|
+
:where(.wt-root) .wt-catchup {
|
|
408
|
+
position: absolute;
|
|
409
|
+
top: calc(var(--safe-top, 0px) + var(--vv-top, 0px) + 44px);
|
|
410
|
+
left: 50%;
|
|
411
|
+
transform: translateX(-50%);
|
|
412
|
+
padding: 2px var(--sp-2);
|
|
413
|
+
background: var(--surface);
|
|
414
|
+
backdrop-filter: var(--blur);
|
|
415
|
+
border: 1px solid var(--border);
|
|
416
|
+
border-radius: var(--radius);
|
|
417
|
+
color: color-mix(in oklch, var(--text) 75%, transparent);
|
|
418
|
+
font-family: var(--font-ui);
|
|
419
|
+
font-size: 0.75rem;
|
|
420
|
+
z-index: 24;
|
|
421
|
+
pointer-events: none; /* passive status surface: never steal taps from the terminal beneath */
|
|
422
|
+
display: none;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
:where(.wt-root) .wt-catchup.visible {
|
|
426
|
+
display: block;
|
|
427
|
+
}
|