959f249c4b
The user's rulings on the two beads PR #55 filed. improvise-7ybz: the browser was keyboard-only by omission. Nothing outside an editable grid cell had a click listener, so clicking the collapse triangle on a category did nothing — which is what "I can't expand categories" meant, since the keyboard path worked all along. `improvise_protocol::resolve::click` now answers all three widgets under one rule: **go there, then do what Enter does there.** A category row focuses the panel, moves its cursor and activates (expand on a header, filter on an item); a tile selects and cycles its axis; a cell moves the selection, with the page's inline editor as the pointer's `i`. One rule rather than three inventions, and it is the keyboard's own definition rather than a second one — `cat_tree_entry`, `toggle_cat_expand`, `filter_to_item` and `tile_axis` each gained an `_at` twin and the cursor-reading form is now a one-line call of it. It lives in the protocol crate, not the wasm client, for the `flatten_cat_tree` reason: a third front end must call this, not derive it. `Client::click_category` / `click_tile` / `click_cell` are thin wasm-bindgen wrappers that fold and serialize exactly as `key` does, so `app.js` still composes no `Command`. The subtlety worth knowing: a click's three intents are resolved in one pure call, so the activation must be asked about the row *clicked*, never about `cat_panel_cursor` — the `SetPanelCursor` ahead of it has not been folded yet. Injecting that exact fault turns `ToggleCatExpand("Product")` into `ToggleCatExpand("Region")`, which is the silent half and is now pinned. improvise-wsaw: `RenderModel::category_panel_open` existed from the start and `app.js` never read it, so the sidebar was drawn unconditionally and `C` moved only the mode label. It now hides on load and toggles with `C`, matching `src/draw.rs:322` and the two panels PR #55 added. A first-time visitor sees one fewer thing; the user chose front-end consistency, and the grid is still populated. Tests: harness/tests/pointer.spec.js, six assertions, **all six proved by running them against the bundle built immediately before this commit** — where the sidebar is wrongly visible and every click lands on an element with no listener. Plus four Rust tests on the resolver, one of them proved by the injection above. Note this branch is based on gh/main but MERGES fix/web-ui-correctness (PR #55): click_tile needs a tile bar to click, and that is #55's. Rebase or re-merge once #55 lands. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>