# feat(#829): キーボードからズームに入る／呼ばれたセルへ飛ぶ／割り当てを設定画面に出す

#829 の第2弾。

## なぜこの範囲か

第1弾で入ったアクションは**すべて「ズーム中」を前提**にしている。ところが**ズームに入る手段がキーボードに
無い**ため、キーマップを設定しても必ず一度 `⤢` をマウスでクリックしないと何も始まらない。入口が塞がって
いる状態なので、まずそこを開ける。

あわせて「今どのキーが何に割り当たっているか」を確かめる手段が皆無だった。これは設定画面に
**読み取り専用で出す**（別オーバーレイにしない）。オーバーレイをキーで開く案は、opt-in の性質上
「未割り当てだとヘルプ自体を開けない」という循環になるため採らない。

## 変更内容

### 1. `common/keymap.ts` — アクション追加

- `zoom-toggle` — 拡大の開閉。**非ズームでも効く**（＝これが入口）
- `next-attention` — 入力待ち／完了のセルへ飛ぶ。**非ズームならそのセルを拡大する**ので、これも入口になる

### 2. `src/components/gridTabs.ts` — 純粋関数2つ

- `toggleZoom(state, order)` — ズーム中なら解除、非ズームなら `order` の先頭を拡大
- `nextAttention(state, order, statusByUid)` — `blocked` → `done` の順に注目が要るセルを、`order` 上で
  現在位置の**次から巡回**して拡大する。1周して見つからなければ何もしない

どちらも `moveZoom` と同じく **移動先のページへ `page` を追従**させる。ズーム解除時に、直前まで見ていた
セルのページに戻すため。

**`runningCount >= 2` のガードを踏襲する。** `toggleExpand` は稼働セルが1つのときズームを拒否する
（フィルムストリップに何も並ばない拡大は無意味 / #374）。入口側もこれに揃える。

### 3. `src/components/SettingsModal.vue` — 割り当て一覧（読み取り専用）

既存セクションと同じ体裁で「Keyboard shortcuts」を追加。全アクションを行として出し、割り当てがあれば
そのキー、無ければ "Not set" と表示する。**未割り当ても含めて全部出す**のが要点で、そうしないと
「何が割り当てられるのか」を知る手段が無い。編集は `config.json`（またはスキル）に委ね、ここは表示のみ。

ラベルは `Record<KeymapAction, string>` として持つ。common/ にアクションを足したら、ラベルを書くまで
**型エラーで気付ける**ようにするため。

## テスト

- `toggleZoom` — 開閉、非ズームからの入口、稼働1セルでは拒否、page 追従、空 `order`
- `nextAttention` — blocked 優先、現在位置の次から巡回、1周して戻る、対象なしなら不変、非ズームからの入口
- ラベルは型で担保（テスト不要）

## 含めないもの（#829 に残す）

- 非ズーム時の選択状態と、それを前提とするアクション（並べ替え・Run）
- ページ切替 / ソート切替 / 表示切替 / ナビゲーション系
- 設定画面からの**編集**（今回は表示のみ）

## 追記: ズームの不変条件（実機フィードバックを経て確定）

拡大の on/off と選択の移動は、この機能で最もバグが出た部分で、将来の変更で副作用が出やすい。
**規約を `src/components/gridTabs.ts` のズーム節の冒頭にコメントで明記**し、`gridTabs.spec.ts` /
`GridView.spec.ts` の "zoom invariants" で固定した。以下の5つは、すべて実際に一度は壊した。

1. **拡大しているかどうかを変えるのは `toggleZoom` だけ。** 移動系（`moveZoom` / `nextAttention`）は
   拡大対象やページを動かすだけで、ズームに入りも出もしない。`closeCell` だけが意図的な例外
   （拡大中のセルを閉じたら何かする必要があるため、隣へ歩かせる）。
2. **`order` は常にページ分割前の全体リスト。** 非拡大時に描画されるのはその一部でしかないので、
   スライスを渡すと他ページのセルが探索から消え、インデックス→ページの計算も全部ずれる。
3. **`page` を決めるのは「ズーム解除の瞬間」の1箇所だけ**で、拡大していたセルの位置から導出する。
   ズーム中は未使用（全セルが描画されタブバーも隠れる）。入った時のページは、フィルムストリップを
   歩いた時点で意味を失う。
4. **「今のターミナル」は1つだけ。** 拡大中は拡大セル、それ以外はフォーカス中のセル。記憶を別に持つと
   選択が動いた瞬間に食い違い、拡大がユーザのいない場所へ飛ぶ。
5. **入るには稼働セルが2つ必要**（`toggleExpand` の規則 / #374）だが、**出るのは常に許可**する。

テストは対応するミューテーションで赤くなることを毎回確認している。
