# New Session Dialog UX Refinements — Design **Goal:** Three focused UX improvements to the New Session modal: hide sandbox sub-options until sandboxing is enabled, unify the focus highlight to the dialog's Peach accent, and add context-aware j/k field navigation. **Scope:** `src/hqt/tui/screens/new_session.py` and `src/hqt/tui/styles.tcss`. No service, DB, or sandbox-policy changes. --- ## 1. Hide sandbox sub-options until the toggle is on The "Filesystem access" and "Network" rows are sub-options of the sandbox switch and should only appear when sandboxing is enabled — mirroring the existing worktree-checkbox → branch-input reveal pattern already in this screen. - Wrap the two label/widget pairs (`Filesystem access:` + `#fs-select`, `Network:` + `#net-switch`) in a `Vertical(id="sandbox-options")` container so they toggle as a single unit. - Set `display = False` on the container at compose time. - Add `on_switch_changed(self, event: Switch.Changed)`: when `event.switch.id == "sandbox-switch"`, set `#sandbox-options` `display` to `event.value`. - The sandbox switch starts off — and is `disabled` when bwrap is absent — so the sub-options start hidden in every case. No separate handling for the unavailable case is needed. - `_submit()` still reads `#fs-select` / `#net-switch` unconditionally. Their values are valid defaults (`rw` / net on) even while hidden, and the policy is only built when the sandbox switch is on, so hidden values are never used. ## 2. Unify the focus highlight to Peach (`$accent`) Buttons already get a Peach focus highlight from `styles.tcss`, but `Switch` / `Checkbox` / `Select` / `Input` fall back to Textual's default Lavender (`$border`) focus border. That inconsistency is the "off-palette" highlight. Add scoped rules so every focusable control in the dialog shares the Peach accent: ```css #new-session-dialog Switch:focus, #new-session-dialog Checkbox:focus, #new-session-dialog Select:focus, #new-session-dialog Input:focus { border: tall $accent; } ``` `Switch` / `Checkbox` / `Input` use a `tall` border by default, so matching `tall` keeps layout height identical — only the color changes. ## 3. Soft context-aware j/k navigation Add screen-level bindings that walk the dialog's focus chain: ```python BINDINGS = [ Binding("j", "focus_next", "Next field", show=False), Binding("k", "focus_previous", "Prev field", show=False), ] ``` `Input` consumes printable keys before screen bindings fire, so j/k type literally while editing a text field and only move focus when the focused widget is a toggle / select / button — the "soft" (context-aware) model the user chose. `focus_next` / `focus_previous` are built-in Textual screen actions. Tab / Shift+Tab / arrows keep working unchanged. --- ## Testing All three are testable against the screen in isolation via Textual's `run_test()` pilot: - **Sub-options reveal:** mount with `sandbox_available=True`; assert `#sandbox-options` `.display` is `False` initially, flip the sandbox switch, assert it becomes `True`, flip back, assert `False`. - **j/k navigation:** assert the `j` / `k` bindings map to `focus_next` / `focus_previous`; drive the pilot to confirm focus moves between toggles and that j/k typed into a focused `Input` land as literal text rather than moving focus. - **Focus highlight:** the color is visual, but the presence of the scoped `:focus` rule is assertable by reading the compiled CSS / `styles.tcss`. ## Out of scope - No modal (normal/insert) vim mode — the soft model was chosen deliberately. - No change to Enter-to-submit behavior. - No restyling of controls outside the New Session dialog.