tasty.gallery
Overlays · Popups & menus
← Design
Specs
Theme

Popups & menus

Try menus and popups that open beside a control. Each example shows where it appears and whether it closes on an outside click, Escape, or key release.

This page uses a saved copy of the design system, last changed on . It may differ from the current design source.

Tools menu

Tools menu — anchored, no scrim

A popup anchored above the sidebar Tools button (left-aligned to it). Unlike the modal layer this is a lightweight menu — no scrim, dismisses on outside click or Esc. Built-in entries first, in this fixed order — Command palette… · Listening ports… · Remote connections… · Presets · Tutorial… · Task DAGs · Open File… — then a separator, then plugin-contributed tools in manifest order (Clipboard Viewer 100 · Git 130). Every label that opens a further window ends in the single ellipsis character …, never three periods. Width (2026-10-07): the menu is as wide as its longest row (label + --tasty-menu-item-padding-x both sides + the 4 ring + border), never narrower than 160 and never wider than 240; a label past 240 ellipsizes at its end. This covers translated labels without a per-locale width.

Layout spec
width
fit content · min 160 --tasty-tools-menu-min-width · max 240 --tasty-tools-menu-max-width
overflow
end ellipsis past max
anchor
above button, left-aligned
rows
28px MenuItem, no icons
built-in
7 — fixed order
inner ring
4 · --tasty-popup-content-margin
scrim
none
dismiss
outside click · Esc
Tokens used
menu-bg— menu fillmenu-border— edge → border-strongpopup-content-margin— → space-xs 4tools-menu-min-width— → size-160tools-menu-max-width— → size-240shadow-popover— lift

Plugins extend the list below the separator only — built-in order is fixed. This is a popover, not a dialog: it never dims the app.

Switch-number overlay

Tab switch overlay — modifier held

Holding the tab switch modifier (Ctrl by default — rebindable) paints a number keycap over every tab, previewing the Ctrl+1…Ctrl+9 / Ctrl+0 switch shortcuts. The keycap replaces the tab's leading icon in place — no width change, no scrim; the icon returns on release. The active tab's keycap is accent-filled so "where am I" stays legible. Workspaces show nothing — only the modifier bound to tabs triggers this.

Layout spec
widget
Kbd keycap · 16px
content
digit only · 0 = 10th tab
placement
replaces leading icon, in place
range
1–9 + 0; 11th tab onward: none
active tab
accent-filled keycap
scrim
none
appear
90ms fade · release 0ms
Tokens used
switch-overlay-bg— keycap fillswitch-overlay-active-bg— active-tab keycapswitch-overlay-border— keycap edgeswitch-overlay-fade— 90ms appear

The digit equals the key you press, so the 10th tab reads 0 (not "10") to match Ctrl+0. Tabs past the 10th carry no shortcut, so they get no keycap — never paint a number a key won't trigger.

Workspace switch overlay — modifier held

Holding the workspace switch modifier (Alt by default — rebindable) paints a keycap over each sidebar workspace, previewing Alt+1…Alt+9. In the full sidebar the keycap replaces the leading status dot; in the collapsed rail it replaces the letter avatar. Same in-place, no-scrim rule as tabs; tabs show nothing here. Releasing dismisses instantly.

Layout spec
widget
Kbd keycap · 16px
content
digit only (1–9)
full placement
replaces status dot
collapsed
replaces letter avatar
range
1–9 only; 10th onward: none
active ws
accent-filled keycap
scrim
none
Tokens used
switch-overlay-bg— keycap fillswitch-overlay-active-bg— active-ws keycapswitch-overlay-active-fg— digit on accentswitch-overlay-size— 16px footprint

Workspace shortcuts only go 1–9 (no 0), so the 10th workspace and beyond get no keycap — in the collapsed rail they keep their letter avatar (last item above). The bound modifier is read from the same keybindings the shortcut uses: rebind it and the overlay follows.

Do replace the leading indicator rather than overlapping the label — the keycap's own surface-raised fill + border clears 4.5:1 on both tab and sidebar backgrounds without a scrim.

Category switch overlay — Ctrl+Shift held

A third switch axis, present only when Workspace categories (folders) is on. Holding the category switch modifier (Ctrl+Shift by default — rebindable) paints a keycap over each category, previewing Ctrl+Shift+1…Ctrl+Shift+9 / Ctrl+Shift+0. In the full sidebar the keycap is right-aligned on the category header — it does not replace the chevron, which stays to carry collapse state (and its auto-expand rotation). In the rail it sits centered on the --- boundary. The reserved normal category (“Workspaces”) is 1. This overlay and the workspace overlay are modifier-exclusive — Alt paints workspaces, Ctrl+Shift paints categories, never both at once, so workspace rows keep their status dots here. The chord is the product default category_switch_modifier = ctrl+shift (every preset) — the gallery and the app read it from there.

Layout spec
widget
Kbd keycap · 16px
content
digit only · 0 = 10th category
full placement
trailing on header — chevron kept
rail
centered on the --- boundary
range
1–9 + 0; 11th category onward: none
reserved
normal (“Workspaces”) = 1
active cat
accent-filled keycap
exclusivity
Ctrl = tabs · Alt = ws · Ctrl+Shift = category
default
category_switch_modifier = ctrl+shift
Tokens used
switch-overlay-bg— keycap fillswitch-overlay-active-bg— active-category keycapswitch-overlay-active-fg— digit on accentsurface-active— landed workspace row

Auto-expand: switching to a collapsed category rotates its chevron open and reveals its rows (the chevron is why it isn't replaced by the keycap) — the new collapse state persists in layout.json. Last-active: the switch lands on that category's most-recently-focused workspace (its first if never visited), shown with the ordinary surface-active + 2px accent bar — no separate affordance. Reuses the NumCap keycap and every --tasty-switch-overlay-* token; no new tokens.

Modifier hints

Modifier hint panel — hold to reveal

A floating, focus-less discoverability panel painted while a modifier is held — like macOS's hold-⌘ shortcut sheet. Press & hold the Ctrl control: after a 500ms dwell the panel fades in (opacity 0.2→1 over 200ms); release dismisses it instantly. It defaults to the bottom-left, just above the sidebar footer, and is draggable + edge-resizable. It never dims the app and never takes keyboard focus.

Layout spec
trigger
modifier held 500ms
default size
180 × 400 · --tasty-modhint-width × --tasty-modhint-height
default pos
bottom-left, above sidebar footer
appear
fade opacity 0.2→1 · 200ms
release
0ms — instant dismiss
focus
never — not a focus window
scrim
none
Tokens used
modhint-bg— panel fillmodhint-shadow— floating liftmodhint-fade— 200ms fade-inmodhint-hold-delay— 500ms hold

Reduced motion skips the fade — the panel appears at full opacity the instant the 500ms hold completes. The bound modifier set is read from the same keybindings source the shortcuts use (Win/Linux: Ctrl / Alt / Shift; macOS adds Cmd / Option).

Anatomy & chord ordering

Sections are the shortcut chords that contain the held modifier, ordered by chord size (1→2→3→4) then by modifier priority Ctrl → Cmd/Alt → Option → Shift. Each section header is the chord as Kbd keycaps; under it sit the bound keycap rows (action + Kbd), an optional special-role row (what the chord itself does — e.g. Ctrl = tab-switch numbers, Shift = TUI mouse-capture bypass), and plugin rows carrying the agent dot. A chord with no bindings and no role is omitted entirely.

Layout spec
drag strip
muted sidebar fill — NOT a titlebar
X button
dismiss for this hold only
section order
size ↑, then Ctrl→Cmd/Alt→Option→Shift
keycap row
action + Kbd
role row
washed, leading glyph, no keycap
plugin row
agent dot, context-dependent
row text
11 · --tasty-modhint-row-font-size (chord · role · empty rows)
chord row
min 24 · --tasty-modhint-row-min-height
role row pad
6 / 8 · --tasty-modhint-row-gap / --tasty-space-sm
grip
12 · inset 2 from right/bottom · --tasty-modhint-grip-size · --tasty-modhint-grip-inset (on-scale)
min size
180 × 240
Tokens used
modhint-header-bg— drag stripmodhint-role-bg— role-row washmodhint-role-fg— role glyphaccent-agent— plugin dotmodhint-grip-fg— resize grip

Do keep it opaque and low-chrome — it floats over live terminal output, and the muted drag strip (not a titlebar) is the promise that it will never steal focus.

Don't hide a chord that a key combo could reach — a bound-empty chord shows its ChordHead with a muted “No shortcuts bound” placeholder (see below), never nothing, so holding an all-empty combo still surfaces the panel.

When Workspace categories (folders) is on, the Ctrl+Shift chord carries a “Switch category” role row (folder glyph) — the discoverability entry for the category quick-switch (see Switch-number overlay). A chord's role row is how a numeric switch announces itself, exactly like Ctrl = tab-switch numbers.

Empty chord — “No shortcuts bound” placeholder

A chord that exists but carries no binding and no role is not omitted — its ChordHead shows with a single muted placeholder row beneath it. This reverses the original decision (“empty chord → omitted entirely, never ‘none’”): holding an all-empty combo like Ctrl+Alt+Shift now surfaces the panel with a “No shortcuts bound” line instead of showing nothing. The placeholder is the quietest row in the panel — text-muted, no keycap, no wash, no leading glyph — an absence signal, deliberately not a role-row. It is fully static and non-interactive.

Layout spec
row
placeholder text only — no keycap
tone
muted (below a keycap row)
wash
none — not a role-row
glyph
none
min height
20px (tighter than a 24px keycap row)
section gap
3px inside (empty sits tight)
copy
“No shortcuts bound”
interaction
none — static, no hover/focus
Tokens used
modhint-empty-fg— placeholder texttext-muted— → semanticmodhint-section-gap— between sections (unchanged)

Do keep the placeholder muted and bare — it announces an absence, so it must read quieter than a bound keycap row and never borrow the role-row's wash or glyph.

Don't give it a keycap, a hover highlight, or a washed background — a keycap implies a binding that isn't there, and a wash makes it look like a role-row that does something.

i18n key modifier_hint.empty — en “No shortcuts bound” · ko “지정된 단축키 없음” · ja “割り当てなし”. Fits one line in the 180px panel across all three. New token --tasty-modhint-empty-fg → text-muted (a pointer, no new primitive), so the implementing side flips build_hint_sections()' empty-retain and paints one draw_row variant.

Workspace categories

Sidebar context menu — target resolves under the cursor

Right-clicking anywhere in the sidebar workspace area opens this menu (no dedicated buttons) — only when Settings › General › Workspace categories (folders) is on. Items resolve to the target under the cursor: empty background, a category header, or a workspace row. The reserved normal category (“Workspaces”) is additive-only — no rename/delete. Same MenuItem + anchored-popup language as the Tools menu.

Layout spec
trigger
right-click, no dedicated button
width
176px min
background
New category
category
Add ws · Rename · Delete · New
reserved
Add ws · New (additive-only)
workspace
Move to category (inert header) · targets · New
targets
every category except the current one · normal = “Workspaces”
Tokens used
surface-raised— menu fillborder-strong— edgeaccent-danger— delete rowshadow-popover— lift

“Move to category” is an inert header with the target categories listed flat beneath it (current category omitted) — no submenu, because the product draws this menu with the OS-native context menu (2026-10-07). Drag-and-drop reorder stays the primary path; this is the menu fallback. New strings: workspace_category.add_workspace · collapse · expand. Existing: new_category · rename_category · delete_category · move_to_category.

Collapsed rail — `---` category button + anchored popup

In the 52px rail, categories aren't labelled — each boundary is a clickable horizontal --- button (the old thin separator, now a button). Clicking it opens a popup to its right (like the rail Tools button). The popup's top line is the category name, a non-clickable header; below are the actions. A category's avatars sit below its ---; a collapsed or empty category shows only the --- button.

Layout spec
boundary
--- full-width button
anchor
popup to the right of the button
header
category name — non-clickable
items
Add workspace · Collapse · Rename · Delete
collapsed/empty
--- only, no avatars
reserved
no Rename/Delete
Tokens used
separator— --- line (idle)text-muted— --- line (hover)surface-raised— popup fillmenu-border— edgepopup-content-margin— inner ring 4 (all sides)accent-danger— delete row

Collapse state is per-category and shared with the full sidebar (both seed from the persisted collapsed flag in layout.json). Toggling here or in the full header updates the same state.

Notice column — restore failure · save halt · response wait (2026-10-19)

Restore failure — non-focus notice, top right (2026-10-19)

When the saved layout cannot be read at all at boot, Tasty does not stop: it opens one default workspace in its initial state and shows a small notice in the window's top-right notice column. No scrim, no centred modal, no focus move: the terminal keeps the keyboard, and keys, selection and scroll outside the notice behave as if it were not there. The notice is the shared popup frame (PopupTitleBar with ×, popup shadow): cause line with an error glyph, the saved-layout path (selectable, wraps anywhere, copy button), what happened and that the original is untouched, then Continue. × and Continue are the same action. The same error is recorded in Notifications, so dismissing loses nothing. Not for: a home locked by another instance, the first shell failing to start, an explicit webhook port failure.

Layout spec
place
notice column · work-area top-right, under the top-right pane's tab strip · inset 8 · width 360 (max = work area − 16)
frame
PopupTitleBar (28 · title centred · ×) · bg-panel · 1px border-frame · radius 4 · shadow-popover · no scrim
body
pad 12 · gap 8 · glyph alertCircle 16 notify-error + cause 13 text-primary · label mono 10 caps · path box · explanation term-sm text-secondary · Continue (secondary sm) right
path
mono 12 · bg-sidebar box, 1px border-default · selectable · overflow-wrap anywhere · copy IconButton sm
focus
never on appear · Enter / Esc NOT captured · role=status aria-live=polite
explicit controls
after a click inside: × / copy / Continue are normal buttons · Esc inside = Continue → focus back to the surface
dismiss
= continue in the initial state · never quits · never deletes / moves / overwrites the saved layout
not shown
internal method / class names · retry / reset / recovery buttons · any promise that changes are saved
Tokens used
restore-notice-width— → notice-column-width → size-360restore-notice-glyph— → notify-error → accent-dangerrestore-notice-padding— → space-md 12restore-notice-gap— → space-sm 8restore-notice-body-fg— → text-secondaryrestore-notice-label-fg— → text-mutedrestore-notice-path-bg— → bg-sidebarrestore-notice-path-border— → border-defaultrestore-notice-path-fg— → text-primary

Contrast (on bg-panel): cause text-primary Mocha ≈ 11:1 · Latte ≈ 7.1:1 · explanation text-secondary Mocha ≈ 8:1 · Latte n1000 ≈ 5.9:1 · label text-muted Mocha ≈ 5.4:1 · Latte n900 ≈ 4.6:1 · path text-primary on bg-sidebar Mocha ≈ 11.6:1 · Latte ≈ 6.5:1 · glyph accent-danger Mocha ≈ 6.5:1 · Latte ≈ 4.6:1 (≥ 3).

Narrow · long path · split + search bar · save halt · ko / ja · the notification record

Narrow window: the notice takes the work area minus 8 on each side; the path wraps, the button never leaves the frame. With a split, the column still belongs to the window's top-right; if the top-right pane has its search bar open, the column starts under it (the bar is where the user is typing and keeps its place). Save halt (running, saving stopped) uses the same notice: current output and input go on, and it says layout changes from now on may not be restored. The Notifications record is an ordinary error item with the same title, cause and path.

Layout spec
narrow
width = work area − 2 × 8 · path wraps · Continue stays inside
split
column = window top-right, not the focused pane
search bar
column top = tab strip + 8 + search bar + 8
halt
same frame · cause write · says output/input continue · no save promise
record
NotificationItem error · title + cause + path in body · source Tasty
i18n
notice.restore_failed_title / _body · notice.save_halted_title / _body · notice.cause_read_denied / _corrupt / _write_failed · notice.saved_layout_label · notice.copy_path · notice.continue

Notice column — what sits where, top right (2026-10-19)

One column, the window's work-area top-right, inset 8. Order top → bottom: restore / save-halt notice, then the response-wait chip (PendingIndicator), 8 apart, right-aligned. The column starts below a window-scope banner (resize failure, reconnect) and below an open search bar in the top-right pane; neither is moved by it. Pane- and surface-scope banners stay inside their own scope and do not move the column. While a reconnect banner is up the chip is gone (the request ended in the disconnect path). The chip never becomes a scrim or a full-width bar.

Layout spec
column
work area top-right · inset 8 · width 360 · gap 8 · items right-aligned
order
restore / halt notice › PendingIndicator
moves below
window-scope banner · top-right pane's open search bar
never covers
the tab strip: the column starts under the top-right pane's tab strip (tab-height + 8), so close / scroll arrows stay reachable
input
column itself pointer-events none; only the notice / chip boxes take the pointer
Tokens used
notice-column-inset— → space-sm 8notice-column-gap— → space-sm 8notice-column-width— → size-360

Over a web page — opaque mode (2026-10-21)

Contract — popup over a page in opaque mode

A markdown or html page is a native WebView. Where the host cannot composite over it with transparency (e.g. Linux X11 with no compositing manager), the host paints only inside the popup box rect and each dropdown box rect; those pixels are fully opaque and the page outside them cannot change. Transparent mode is unchanged. The mode is decided by the environment; there is no user setting and no on-screen indicator. Toasts and passive popups keep the current rule (overlapped page hidden).

Layout spec
1 · corner
square — box reads webview-opaque-radius (0); nothing to fill outside an arc
2 · shadow
none — webview-opaque-shadow; the existing 1px border is the only silhouette, no extra edge
3 · scrim
not drawn at all while any opaque-mode page is visible in the scrim's scope; no blotch
scope
same rule for surface scope (the page itself) and window scope
4 · straddle
box rect intersects a page anywhere → the WHOLE box goes square + no shadow, never per edge
5 · dropdown
same rule; a dropdown also follows its parent shell (shell opaque → dropdown opaque)
6 · tokens
webview-opaque-radius → radius-none → radius-0 · webview-opaque-shadow → shadow-none
unchanged
shell structure · padding · rows · hover/active · focus look · border tokens
Tokens used
webview-opaque-radius— → radius-none → radius-0 (0)webview-opaque-shadow— → shadow-none (none)border-frame— shell edge kept (convert, dialogs)menu-border— menu / dropdown edge keptscrim-bg— not drawn while a page is visible

Input routing (unchanged contract, annotated here): while a target popup is visible, a click on the page body is that popup's outside click and never reaches the page — popups that close on outside click close (convert_surface; command palette, which is sticky_focus=true, closes too), others stay open and only lose focus (notification panel, search bar). Keys and IME go to the focused popup, never to the page. Closing the popup leaves the page exactly as before it opened.

Why no scrim: the scrim cannot darken the page, so drawing it only on terminal / tab bar / sidebar makes the page the brightest thing on screen while a modal is up (measured). Dropping it keeps the screen uniform; the modal is still marked by its frame border, its focus, and outside-click routing. When no opaque page is on screen (page in a background tab, or transparent mode), the scrim draws as today.

A — convert_surface over a full-pane markdown page

Surface-scoped scrim, and the surface is the page. Transparent: scrim over the page, rounded shell with --tasty-shadow-modal. Opaque: no scrim, square shell, no shadow, --tasty-border-frame edge kept. Current: page hidden behind the boundary tile.

Mocha · Transparent — unchanged
release-notes.md
Release notes — 0.14
Surface conversion keeps the running process and its scrollback. Only the renderer changes, so a log can become a document and back without a restart.
Changes
AreaChange
ExplorerRemote write queue
MarkdownAddress bar browse
File pickerFolder mode
HandlersUser overrides
Every popup width is a token multiplied by ui_scale.
Surface Type
Mocha · Opaque — this request
release-notes.md
Release notes — 0.14
Surface conversion keeps the running process and its scrollback. Only the renderer changes, so a log can become a document and back without a restart.
Changes
AreaChange
ExplorerRemote write queue
MarkdownAddress bar browse
File pickerFolder mode
HandlersUser overrides
Every popup width is a token multiplied by ui_scale.
Surface Type
Mocha · Current — page hidden
release-notes.md
Surface Type
Latte · Transparent — unchanged
release-notes.md
Release notes — 0.14
Surface conversion keeps the running process and its scrollback. Only the renderer changes, so a log can become a document and back without a restart.
Changes
AreaChange
ExplorerRemote write queue
MarkdownAddress bar browse
File pickerFolder mode
HandlersUser overrides
Every popup width is a token multiplied by ui_scale.
Surface Type
Latte · Opaque — this request
release-notes.md
Release notes — 0.14
Surface conversion keeps the running process and its scrollback. Only the renderer changes, so a log can become a document and back without a restart.
Changes
AreaChange
ExplorerRemote write queue
MarkdownAddress bar browse
File pickerFolder mode
HandlersUser overrides
Every popup width is a token multiplied by ui_scale.
Surface Type
Latte · Current — page hidden
release-notes.md
Surface Type
host-drawable rect over the page (popup box · dropdown box) — every pixel inside is opaque, nothing outside it can change

The 240 × ui_scale width is unchanged; longer de / ja / ko titles take the same band and tooltip rule as today, the edge treatment does not depend on width.

B — command palette across markdown page | terminal

Window scrim. Opaque mode drops the scrim on both panes, because the page pane cannot be dimmed. The fourth column is the rejected option: scrim kept outside the page.

Mocha · Transparent — unchanged
Release notes — 0.14
Surface conversion keeps the running process and its scrollback. Only the renderer changes, so a log can become a document and back without a restart.
Changes
AreaChange
ExplorerRemote write queue
MarkdownAddress bar browse
File pickerFolder mode
HandlersUser overrides
Every popup width is a token multiplied by ui_scale.
❯ cargo build --release Compiling tasty v0.14.0 Finished release [optimized] in 41.2s❯
↑↓ navigate↵ runesc close
Mocha · Opaque — this request
Release notes — 0.14
Surface conversion keeps the running process and its scrollback. Only the renderer changes, so a log can become a document and back without a restart.
Changes
AreaChange
ExplorerRemote write queue
MarkdownAddress bar browse
File pickerFolder mode
HandlersUser overrides
Every popup width is a token multiplied by ui_scale.
❯ cargo build --release Compiling tasty v0.14.0 Finished release [optimized] in 41.2s❯
↑↓ navigate↵ runesc close
Mocha · Current — page hidden
❯ cargo build --release Compiling tasty v0.14.0 Finished release [optimized] in 41.2s❯
↑↓ navigate↵ runesc close
Mocha · Rejected — scrim outside page only
Release notes — 0.14
Surface conversion keeps the running process and its scrollback. Only the renderer changes, so a log can become a document and back without a restart.
Changes
AreaChange
ExplorerRemote write queue
MarkdownAddress bar browse
File pickerFolder mode
HandlersUser overrides
Every popup width is a token multiplied by ui_scale.
❯ cargo build --release Compiling tasty v0.14.0 Finished release [optimized] in 41.2s❯
↑↓ navigate↵ runesc close
Latte · Transparent — unchanged
Release notes — 0.14
Surface conversion keeps the running process and its scrollback. Only the renderer changes, so a log can become a document and back without a restart.
Changes
AreaChange
ExplorerRemote write queue
MarkdownAddress bar browse
File pickerFolder mode
HandlersUser overrides
Every popup width is a token multiplied by ui_scale.
❯ cargo build --release Compiling tasty v0.14.0 Finished release [optimized] in 41.2s❯
↑↓ navigate↵ runesc close
Latte · Opaque — this request
Release notes — 0.14
Surface conversion keeps the running process and its scrollback. Only the renderer changes, so a log can become a document and back without a restart.
Changes
AreaChange
ExplorerRemote write queue
MarkdownAddress bar browse
File pickerFolder mode
HandlersUser overrides
Every popup width is a token multiplied by ui_scale.
❯ cargo build --release Compiling tasty v0.14.0 Finished release [optimized] in 41.2s❯
↑↓ navigate↵ runesc close
Latte · Current — page hidden
❯ cargo build --release Compiling tasty v0.14.0 Finished release [optimized] in 41.2s❯
↑↓ navigate↵ runesc close
Latte · Rejected — scrim outside page only
Release notes — 0.14
Surface conversion keeps the running process and its scrollback. Only the renderer changes, so a log can become a document and back without a restart.
Changes
AreaChange
ExplorerRemote write queue
MarkdownAddress bar browse
File pickerFolder mode
HandlersUser overrides
Every popup width is a token multiplied by ui_scale.
❯ cargo build --release Compiling tasty v0.14.0 Finished release [optimized] in 41.2s❯
↑↓ navigate↵ runesc close
host-drawable rect over the page (popup box · dropdown box) — every pixel inside is opaque, nothing outside it can change

Don't keep the scrim on the non-page areas only: the page stays at full brightness while the terminal, tab bar and sidebar go dark (the blotch seen in measurement).

C — Tools menu straddling sidebar | page

Scrim-less, --tasty-shadow-popover in transparent mode. Part of the menu sits over the sidebar, part over the page. Because the box rect intersects the page, the whole menu is square with no shadow, including the part over the sidebar where a shadow could be drawn.

Mocha · Transparent — unchanged
Release notes — 0.14
Surface conversion keeps the running process and its scrollback. Only the renderer changes, so a log can become a document and back without a restart.
Changes
AreaChange
ExplorerRemote write queue
MarkdownAddress bar browse
File pickerFolder mode
HandlersUser overrides
Every popup width is a token multiplied by ui_scale.
Mocha · Opaque — this request
Release notes — 0.14
Surface conversion keeps the running process and its scrollback. Only the renderer changes, so a log can become a document and back without a restart.
Changes
AreaChange
ExplorerRemote write queue
MarkdownAddress bar browse
File pickerFolder mode
HandlersUser overrides
Every popup width is a token multiplied by ui_scale.
Mocha · Current — page hidden
Latte · Transparent — unchanged
Release notes — 0.14
Surface conversion keeps the running process and its scrollback. Only the renderer changes, so a log can become a document and back without a restart.
Changes
AreaChange
ExplorerRemote write queue
MarkdownAddress bar browse
File pickerFolder mode
HandlersUser overrides
Every popup width is a token multiplied by ui_scale.
Latte · Opaque — this request
Release notes — 0.14
Surface conversion keeps the running process and its scrollback. Only the renderer changes, so a log can become a document and back without a restart.
Changes
AreaChange
ExplorerRemote write queue
MarkdownAddress bar browse
File pickerFolder mode
HandlersUser overrides
Every popup width is a token multiplied by ui_scale.
Latte · Current — page hidden
host-drawable rect over the page (popup box · dropdown box) — every pixel inside is opaque, nothing outside it can change

Do decide the edge once per box from its rect. A half-rounded, half-shadowed menu reads as a rendering fault.

D — file picker with the path-bar dropdown hanging over the page

Two host rects: the picker box and the crumb dropdown box, which extends past the picker's bottom edge onto the page. Both are square with no shadow; the dropdown keeps --tasty-menu-border. Select / SearchableSelect menus opened from a popup over a page follow the same rule.

Mocha · Transparent — unchanged
Release notes — 0.14
Surface conversion keeps the running process and its scrollback. Only the renderer changes, so a log can become a document and back without a restart.
Changes
AreaChange
ExplorerRemote write queue
MarkdownAddress bar browse
File pickerFolder mode
HandlersUser overrides
Every popup width is a token multiplied by ui_scale.
Open file
/…exports2026-09
NameSizeModified
configs—Jul 12 09:14
logs—Jul 14 22:03
node_modules—Jul 02 11:40
README.md4.2 KBJul 15 08:21
package.json1.1 KBJul 15 08:21
pipeline.yaml3.8 KBJul 14 17:55
deploy.sh902 BJul 11 14:02
.env218 BJul 09 10:30
File name
Users
maya
tasty
config
keybindings
exports
Mocha · Opaque — this request
Release notes — 0.14
Surface conversion keeps the running process and its scrollback. Only the renderer changes, so a log can become a document and back without a restart.
Changes
AreaChange
ExplorerRemote write queue
MarkdownAddress bar browse
File pickerFolder mode
HandlersUser overrides
Every popup width is a token multiplied by ui_scale.
Open file
/…exports2026-09
NameSizeModified
configs—Jul 12 09:14
logs—Jul 14 22:03
node_modules—Jul 02 11:40
README.md4.2 KBJul 15 08:21
package.json1.1 KBJul 15 08:21
pipeline.yaml3.8 KBJul 14 17:55
deploy.sh902 BJul 11 14:02
.env218 BJul 09 10:30
File name
Users
maya
tasty
config
keybindings
exports
Mocha · Current — page hidden
Open file
/…exports2026-09
NameSizeModified
configs—Jul 12 09:14
logs—Jul 14 22:03
node_modules—Jul 02 11:40
README.md4.2 KBJul 15 08:21
package.json1.1 KBJul 15 08:21
pipeline.yaml3.8 KBJul 14 17:55
deploy.sh902 BJul 11 14:02
.env218 BJul 09 10:30
File name
Users
maya
tasty
config
keybindings
exports
Latte · Transparent — unchanged
Release notes — 0.14
Surface conversion keeps the running process and its scrollback. Only the renderer changes, so a log can become a document and back without a restart.
Changes
AreaChange
ExplorerRemote write queue
MarkdownAddress bar browse
File pickerFolder mode
HandlersUser overrides
Every popup width is a token multiplied by ui_scale.
Open file
/…exports2026-09
NameSizeModified
configs—Jul 12 09:14
logs—Jul 14 22:03
node_modules—Jul 02 11:40
README.md4.2 KBJul 15 08:21
package.json1.1 KBJul 15 08:21
pipeline.yaml3.8 KBJul 14 17:55
deploy.sh902 BJul 11 14:02
.env218 BJul 09 10:30
File name
Users
maya
tasty
config
keybindings
exports
Latte · Opaque — this request
Release notes — 0.14
Surface conversion keeps the running process and its scrollback. Only the renderer changes, so a log can become a document and back without a restart.
Changes
AreaChange
ExplorerRemote write queue
MarkdownAddress bar browse
File pickerFolder mode
HandlersUser overrides
Every popup width is a token multiplied by ui_scale.
Open file
/…exports2026-09
NameSizeModified
configs—Jul 12 09:14
logs—Jul 14 22:03
node_modules—Jul 02 11:40
README.md4.2 KBJul 15 08:21
package.json1.1 KBJul 15 08:21
pipeline.yaml3.8 KBJul 14 17:55
deploy.sh902 BJul 11 14:02
.env218 BJul 09 10:30
File name
Users
maya
tasty
config
keybindings
exports
Latte · Current — page hidden
Open file
/…exports2026-09
NameSizeModified
configs—Jul 12 09:14
logs—Jul 14 22:03
node_modules—Jul 02 11:40
README.md4.2 KBJul 15 08:21
package.json1.1 KBJul 15 08:21
pipeline.yaml3.8 KBJul 14 17:55
deploy.sh902 BJul 11 14:02
.env218 BJul 09 10:30
File name
Users
maya
tasty
config
keybindings
exports
host-drawable rect over the page (popup box · dropdown box) — every pixel inside is opaque, nothing outside it can change

A dropdown opened from an opaque-mode shell is opaque-mode even if its own rect ends over a terminal, so the parent and child never disagree.