# Changelog

A-COUNTER X の主要なバージョンと変更履歴。日付は JST。
各バージョンが PC 版 (Electron `.exe`) / Android PWA / 共通 のどれに影響するかも併記。

## [0.2.185] - 2026-05-23 (PC + PWA 同期)

### 新機能: 機種別にテーマとレイアウトを自動保存・自動復元 (旧 DIGI-COUNTER 互換)
- お客様問い合わせ:「旧 DIGI-COUNTER のように機種別のテーマやレイアウトを保存する方法はないか。機種を変更すると後に設定した機種に変わってしまうため」
- これまで theme-store / layout-store は全機種共通の 1 セットしか持たず、機種を切り替えてもテーマやレイアウトは引き継がれて上書きされていた
- **機種ごとに独立したテーマ・レイアウトを覚える仕組みを追加**:
  - 機種を選び直すと、その機種に保存された見た目 (フォント・色・背景画像・ラベル設定 + カード配置) が即時復元される
  - 機種を選択中にテーマやレイアウトを編集すると、現在の機種に 500ms デバウンスで自動保存される
  - 機種にまだ保存が無い場合は、現在の見た目を初期値として種付けする (= 切替前後で違和感が出ない、以降の編集は新機種に独立保存される)
  - 機種を削除すると対応する保存も一緒に消去される (孤児領域防止)
- 既存ユーザーへの影響:更新直後は現在の見た目がそのまま現在選択中の機種に種付けされ、別機種に切替えるとそれ以降が独立保存される。今ある設定は失われない
- 機種未選択 (カタログ / ini 直読み込み等で `loadedLibraryId` が null) のときは従来通り全機種共通として動作
- 新規追加ファイル: `src/ui/store/machine-prefs-store.ts` (機種 id → snapshot レジストリ)、`src/ui/hooks/useMachineBoundPrefs.ts` (機種切替購読 + 自動保存バインダー)
- 該当: `src/App.tsx` (hook 呼び出し 1 行)、`src/ui/store/machine-library-store.ts` (deleteMachine で対応 prefs 削除)、`src/ui/store/machine-prefs-store.ts` (新規)、`src/ui/hooks/useMachineBoundPrefs.ts` (新規)

## [0.2.184] - 2026-05-16 (PC + PWA 同期)

### 新機能: セッションを個別 JSON ファイルにエクスポート / インポート
- お客様問い合わせ: 「DIGI-COUNTER のように個別ファイル (ini 等) で出力できないか。動画撮影で使うので後日復元したい」
- これまで「全データ引き継ぎ」(機種選択モーダル) は PC 全体の移行用しかなかったため、1 セッション単位の書き出し / 読み込み機能を新規実装
- **エクスポート**: セッション一覧の各行に「⬇」(export) ボタンを追加。クリックで `.acxs.json` ファイルがダウンロード
  - ファイル名: `{機種名}_{日時}_{差枚}.acxs.json` (例: `マクロスフロンティア_2026-05-16-14-30_+1234.acxs.json`)
  - 内容: `SessionSnapshot` 全体 (機種設定 / エンジン状態 / スランプ / サイクル / 払出) + メタ情報 (formatVersion / exportedAt / appVersion)
- **インポート**: セッション画面の「📂 ファイルから読み込み」ボタンから `.acxs.json` を読み込み、内容プレビュー (機種名・日時・差枚・エクスポート時アプリ ver) → 確認ダイアログ → 履歴に追加。追加後は通常のセッション行と同じくタップで完全復元可能
- フォーマットバージョン管理付き (未来版ファイルは安全に読み込み拒否)
- 新規追加ファイル: `src/ui/services/session-file-io.ts` (純関数 export/import)
- 該当: `src/ui/components/SessionManager.tsx`, `src/ui/styles/machine-selector.css`, `src/ui/services/session-file-io.ts`

## [0.2.183] - 2026-05-16 (PC + PWA 同期)

### 改善: セッション履歴の保持件数を拡大 (50 → 200) + 期間フィルタ追加
- 「前々日のセッションが見つからない」というお客様問い合わせを受けた改善。原因は保持件数が 50 件で上限に達して古いものから自動削除されていたこと
- **保持件数を 50 → 200 件に拡大** ([session-history-store.ts](src/ui/store/session-history-store.ts) の `MAX_SESSIONS`)。1 日 1〜3 セッションのユーザーで 2〜6 か月分の履歴をカバー
- **セッション一覧に期間フィルタを追加** ([SessionManager.tsx](src/ui/components/SessionManager.tsx)):
  - チップ式プリセット: 全期間 / 今日 / 昨日 / 過去 7 日 / 過去 30 日 / 日付指定...
  - 「日付指定」を選ぶと from-to の `<input type="date">` が下に展開、片側未入力でもフィルタ可能
  - フィルタ ON 時の件数表示は `(該当 N / 全 M 件)` で両方提示
  - 期間に該当 0 件のときは「この期間に該当するセッションはありません」と専用メッセージ表示
  - iOS Safari の `<input type="date">` ズーム抑止のため CSS で font-size: 16px 確保
- 永続化スキーマは変更なし、既存ユーザーは何も失わない
- 該当: `src/ui/store/session-history-store.ts`, `src/ui/components/SessionManager.tsx`, `src/ui/styles/machine-selector.css`

## [0.2.182] - 2026-05-16 (PC + PWA 同期)

### UX 改善: 小役カウンターの操作ドロワーを「枠外タップで閉じる」よう改善
- スマホ縦の小役カウンターでは、画面上部に操作パネル (プリセット選択 / 設定判別 / リセット / ボーナス中設定 等) が **ドロワー** として開閉する。これを閉じるには従来「ステータスバーの▼ボタン」をタップする必要があったが、直感的には「枠外をタップしたら閉じる」挙動が自然
- `KoyakuCounterPanel.tsx` に `controlsWrapRef` (useRef) と `useEffect` を追加し、ドロワーが開いている間だけ `document.addEventListener("pointerdown", ...)` で外側タップを検知して `setControlsOpen(false)`
- 内側タップは `wrap.contains(e.target)` の contains 判定で素通りさせるので、ステータスバー・プリセット選択・各ボタンの既存 onClick は二重発火せず正常動作
- listener は controlsOpen=false に戻ったときと unmount 時に確実に解除 (useEffect の cleanup)
- pointerdown 経由なのでタッチ・マウス両対応 (Android スマホでも自然に動作)
- 該当: `src/ui/components/KoyakuCounterPanel.tsx`

## [0.2.181] - 2026-05-16 (PC + PWA 同期)

### 設計変更: 小役カウンターの bonus カード (BB/RB/SBB/ART) を「本体 = 唯一の正」の絶対値同期に変更
- 実機 (Android PWA) で「本体 BB=1, SBB=3 のとき小役 BB=0, SBB=3 になる」ズレが報告された (v0.2.180 で interval resync を追加したが根本解決ではなかった)
- 根本原因: ON 時点の baseline からの **差分を独自管理する方式** が、Android Chrome の listener suspend/throttle で取りこぼされた瞬間に永久乖離する設計上の弱点を抱えていた
- 設計刷新 (ユーザー提案を採用): bonus カードの count を **本体 counter-store の `bbCount`/`rbCount`/`sbbCount`/`artCount` の絶対値で直接コピー** する。「本体 = 唯一の正」(source of truth)、二重管理を原理的に廃止
  - 差分計算 / `lastBonus` baseline を全廃 → コードシンプル化
  - 本体リセット (全 4 種 0) も BB→SBB 昇格 (一部減・別増) も特殊判定不要、単純コピーで正しく追従
  - listener が一時停止しても、interval (2s) / visibility 復帰時の `syncBonusFromCounter()` 1 回で必ず本体値に揃う (永久乖離不可)
  - ON 以前の本体ボーナス累積も小役側に表示される (= ON 時点で 0 から始めない仕様変更)
  - 手動 ± タップは UI 上は反応するが次の resync で本体値に上書きされる (補正手段としては機能しないが、操作感は維持)
- `syncBonusFromCounter()` 純関数で listener / interval / visibility 復帰 / mount 時の 4 経路から呼ばれる。既に一致するカードは no-op で subscriber 再 render を回避
- 永続化スキーマは変更なし。既存ユーザーは ON すると最初の resync で本体値に上書きされる (OFF のユーザーには影響なし)
- 該当: `src/ui/hooks/useKoyakuAutoDetect.ts`

## [0.2.180] - 2026-05-16 (PC + PWA 同期)

### 修正: Android PWA で 4 回目以降の BB が小役カウンターに反映されないことがある問題への対策
- 実機テスト (Android PWA) で「本体 BB=1, SBB=3 (= 4 回 BB 引いて 3 回昇格、1 回通常 BB) のとき、小役 BB=0, SBB=3 になる」現象が報告された。BB だけが listener に届いていない
- 原因の確定はできなかったが、最も可能性が高いのは「Android Chrome PWA が **OS / Chrome のメモリ管理で内部的に listener を一時停止 (suspend / throttle)** していて、その間の counter-store の patch を取りこぼし、復帰時に `curr === lastBonus` でスキップされて永久に反映されない」というケース
- 対策 (取りこぼし補完): `useKoyakuAutoDetect` 内に **2 秒ごとの interval + visibility 復帰時の resync** を追加。`reconcileBonusFromCounter()` 純関数を作って listener と resync の両方で共有 → listener が普通に動いていれば差分 0 で no-op、止まっていれば次の interval 発火で差分を反映
- 副作用: listener と resync で同時に同じ差分を計算しても、`lastBonus[kind] = curr` を同期で mutate するので二重カウントは起きない
- 該当: `src/ui/hooks/useKoyakuAutoDetect.ts`

## [0.2.179] - 2026-05-16 (PC + PWA 同期)

### 修正: 小役カウンターが本体の BB→SBB 昇格を認識せず BB/SBB がズレる不具合
- 実機テストで「本体 BB=1, SBB=1 (昇格認識済) のとき、小役カウンター BB=2, SBB=0 になる」現象が報告された
- 原因: `useKoyakuAutoDetect` の counter-store listener が **正の差分しか反映しない** (`curr < lastBonus[kind]` で全部ガード) 設計だったため、本体側で BB→SBB 昇格が起きて本体 BB が 1→0 に下がるイベントを取りこぼし、 BB の中間値 (=2) がそのまま残ってしまっていた。本来 v0.2.177 のガードは「本体リセット (全カウント 0 化) で小役側を消さない」ためのもので、昇格 (一部だけ減って別が増える) は別の意味
- 修正:
  - listener で「本体リセット (BB/RB/SBB/ART すべて 0 に戻る)」と「昇格 (1 種だけ減って他が上がる)」を **区別**。 4 種全部 0 のときだけ旧来の baseline 下げ保護、それ以外の負差分は本体 BB → −1、本体 SBB → +1 として **そのまま反映**
  - `bumpBonusCard` に負 delta 対応を追加 (`Math.max(0, current + delta)` で 0 未満には行かない防御)
- これで本体 BB=1, SBB=1 と小役 BB=1, SBB=1 が一致する
- 該当: `src/ui/hooks/useKoyakuAutoDetect.ts`

## [0.2.178] - 2026-05-15 (PC + PWA 同期)

### 修正: preset 切替後 (および本体リセット後) に「総合ゲーム数 / 有効ゲーム数」が動かないロックアップを解消
- 実機テストで「preset 切替後、小役カウントは進むが総合ゲーム数と有効ゲーム数だけ動かない」現象が報告された
- 原因: `useKoyakuAutoDetect` 内の `syncTotalGamesToSessionRotations` が **Math.max ガード** (`if (next <= ks.totalGames) return ks`) を持っていたため、本体側で機種変更 / リセット相当の操作があって sessionRotations が下がった場合、小役側の totalGames が高い値で固定 → その後本体が 0 から積み上がっても `next <= totalGames` で弾かれて永久に反映されないロックアップが発生していた
- 修正: Math.max ガードを「等値のときのみ no-op」に緩和し、**減少時は totalGames も合わせて下げ、startGame も `Math.min(startGame, next)` で切り下げる**。これで本体リセット/機種変更後も小役側の totalGames が追従し、有効ゲーム数も負にならない
- 該当: `src/ui/hooks/useKoyakuAutoDetect.ts`

## [0.2.177] - 2026-05-15 (PC + PWA 同期)

### 修正: 小役カードを手動でタップしても数字が上がらない不具合 (ボーナス中 + bonusCountMode=off で発生)
- 実機テストで「カードをタップしても数字があがらない」現象が報告された
- 原因: `handleCardTap` 内で `shouldCountKoyaku` のボーナス中ガードを通していたため、ボーナス中かつ `bonusCountMode === "off"` (デフォルト) のとき payout カード (小役) が手動加算もブロックされていた
- 修正: 手動タップは常に +1 する (自動判別 ON / ボーナス中 / bonusCountMode に関わらず)。`bonusCountMode` の設定は **自動判別 (applyAutoDetection) 専用** として扱うように責務分離
- これで自動判別 ON 中でも手動タップで併用カウントできる (= ユーザー要望どおり)
- 該当: `src/ui/components/KoyakuCounterPanel.tsx`

### 改善: 小役カウンターの bonus カード (RB/BB/SBB/ART) を本体のボーナス回数と同期 (ON 以降の差分)
- これまで bonus カードのカウントは signal-log の `summary.bonusStarted` (= ボーナス信号エッジ検知) を起点に +1 していたが、本体表示のカウントとは別ロジックなので両者が乖離するケースがあった
- 出所を **本体 counter-store の `bbCount` / `rbCount` / `sbbCount` / `artCount`** に統一。`useKoyakuAutoDetect` 内で `useCounterStore.subscribe` の listener が差分を監視し、本体側で +1 されたぶんだけ小役の対応 bonus カードに +1 する
- 自動判別 ON の瞬間に本体現在値を baseline として記録、それ以降の差分のみ取り込む (= ON 以降の本体 +1 と完全同期)
- 本体リセット (curr < prev) のときは baseline も合わせて下げ、負差分は出さない
- `applyAutoDetection` 内の bonusGames 処理 (signal-log ベース) は撤去 → 二重カウント防止
- 該当: `src/ui/hooks/useKoyakuAutoDetect.ts`, `src/ui/store/koyaku-store.ts`

## [0.2.176] - 2026-05-15 (PC + PWA 同期)

### 仕様修正: 小役カウンターの「総合ゲーム数」を本体「総回転」(sessionRotations) と一致させ、ボーナス中は停止する仕様に統一
- ユーザー期待値: 小役の「総合ゲーム数」は本体メインの「総回転」カードと同じ値で、ボーナス中は停止 (= 通常回転のみ累積) であるべき
- v0.2.171〜175 は「純回転」(engine.counts.gameCount、リプレイ含むがボーナス中も +1) との同期を試みていたため、ボーナス中も小役側ゲーム数が進んでしまい本体「総回転」と乖離していた
- 修正内容 (役割分離):
  - **判別キー** (`lastDetectedGameNumber` / `lastBonusDetectedGameNumber`) は引き続き signal-log の `gameNumber` (= 純回転) を使う — 「未処理ゲーム」を抽出する内部キーなので純回転で OK
  - **表示用** (`totalGames` / `startGame`) は本体「総回転」 = `sessionRotations` (counter-store.totalRotations) のみに追従。`applyAutoDetection` 内の totalGames 取り込みを撤去し、`useKoyakuAutoDetect` の `useCounterStore.subscribe` listener を唯一の出所に
  - 自動判別 ON 時の baseline / `resetCounts` / `setActivePreset` も「判別キー = 純回転」「表示用 = 総回転」を別々に取り直す形に変更 (`currentSignalMaxGameNumber()` + `currentSessionRotations()`)
- これでボーナス中は小役側のゲーム数も停止し、本体「総回転」と完全一致するようになる
- 該当: `src/ui/store/koyaku-store.ts`, `src/ui/hooks/useKoyakuAutoDetect.ts`

## [0.2.175] - 2026-05-15 (PC + PWA 同期)

### 修正: v0.2.174 で取りこぼしていた「ハズレ・リプレイのみのゲームで totalGames が進まない」ケースを解消
- 実機テストで「自動判別 ON 後、最初の 1〜2 ゲームから本体『純回転』と小役『総合ゲーム数』がズレる」現象が報告された (50G 時点で確認済み)
- 原因: `applyAutoDetection` の **早期 return パス** (`settled.length === 0 && bonusGames.length === 0`、= 確定払出もボーナス信号も無いゲームだけが進んだ場合) で totalGames を更新していなかった。v0.2.174 で書いた `Math.max(s.totalGames, maxInLog)` は早期 return の **後ろ** にあったので、ハズレ・リプレイだけで進んだ patch では適用されていなかった
- 修正: 早期 return パス内でも `Math.max(s.totalGames, maxInLog)` の判定を行い、変化があれば patch に含めて return するように
- これで小役の「総合ゲーム数」は払出確定・ボーナス検出を待たず、本体「純回転」と毎ゲームリアルタイムに同期する
- 該当: `src/ui/store/koyaku-store.ts`

## [0.2.174] - 2026-05-15 (PC + PWA 同期)

### 修正: 自動判別 ON 中、小役カウンターの「総合ゲーム数」が本体「純回転」とズレる問題を解消
- 実機テストで本体「純回転 101」に対して小役カウンター「総合ゲーム数 99」と 2 ズレる現象が報告された
- 原因 1: `applyAutoDetection` 内の `totalGames` 更新が `Math.max(s.totalGames, payoutMaxGn, bonusMaxGn)` だったため、`payoutMaxGn` (払出確定ゲーム) と `bonusMaxGn` (ボーナス検出ゲーム) のいずれにも該当しない **ハズレ・リプレイのゲーム** で totalGames が進まなかった (= 「最後にカウントを発生させたゲーム番号」までしか進まない)
- 原因 2: v0.2.171 で入れた `useCounterStore((s) => s.totalRotations)` listener が補完するつもりだったが、counter-store の `totalRotations` は実は **`sessionRotations`** (ボーナス中除外の「総回転」カード値) を保持しており、ユーザー期待値 (本体「純回転」= リプレイ含む全 IN = `engine.counts.gameCount`) と意味が違ったので逆にズレを固定化していた
- 修正:
  1. `applyAutoDetection`: `totalGames` の更新を `Math.max(s.totalGames, maxInLog)` に変更。`maxInLog` は signal-log の最新ゲーム番号 (= `engine.counts.gameCount` = 純回転、リプレイ含む全 IN)。ハズレ・リプレイでも追従するようになる
  2. `useKoyakuAutoDetect`: v0.2.171 で追加した counter-store listener を撤回 (sessionRotations は純回転とは別物のため)
  3. `lastDetectedGameNumber` / `lastBonusDetectedGameNumber` は判別の二重カウント防止に使うため、純回転ベースのまま維持
- 該当: `src/ui/store/koyaku-store.ts`, `src/ui/hooks/useKoyakuAutoDetect.ts`

## [0.2.173] - 2026-05-15 (PC + PWA 同期)

### 性能修正: 自動判別 ON 中、500ゲーム超で重くなる問題の追撃 (v0.2.172 で残っていた主因を解消)
- v0.2.172 で `applyAutoDetection` 自体は軽くしたが、それでも実機で 500 ゲーム以降に重さが残っていた
- 原因: `KoyakuCounterPanel` と `useKoyakuAutoDetect` の両方が `useSignalLogStore((s) => s.games)` でフック購読していたため、signal-log の patch (約 16ms 周期 = 60Hz) が来るたびに **コンポーネント全体が 60Hz で再 render** されていた。再 render のたびに 12 枚のカード + 各種派生計算が走るので、ゲーム数に直接比例しない部分でも CPU を食われる
- 対策:
  1. `KoyakuCounterPanel` の `signalGames` 配列購読を撤去し、**最大ゲーム番号 (プリミティブ)** のセレクタ購読に置換。`games[games.length-1].gameNumber` を見るだけなので、ゲームが 1 つ完了するごと (約 1Hz) しか再 render しなくなる
  2. `useKoyakuAutoDetect` の `games` フック購読を撤去し、`useSignalLogStore.subscribe(listener)` の listener 方式に変更。listener は React の render と独立に動くので、フックを呼ぶコンポーネント (KoyakuCounterPanel) に再 render を波及させない
  3. 本体 `counterTotalRotations` の追従も同じく `useCounterStore.subscribe` の listener 方式に変更。`prev.totalRotations` と比較して変化時だけ書き込み
- これで signal-log の patch が 60Hz で来てもコンポーネント自体は再 render しなくなる (再 render は「カウントが実際に変わった瞬間」「最大ゲーム番号が +1 された瞬間」だけ)
- 該当: `src/ui/components/KoyakuCounterPanel.tsx`, `src/ui/hooks/useKoyakuAutoDetect.ts`

## [0.2.172] - 2026-05-15 (PC + PWA 同期)

### 性能修正: 自動判別 ON 中、500ゲーム以降に反応が重くなる問題を解消
- 自動判別 ON 中は signal-log の patch (約 16ms 周期 / 60Hz) が来るたびに `applyAutoDetection` が走るが、その中身が「games 配列全体を毎回 scan + filter + sort」する実装になっており、ゲーム数が増えるほど線形に重くなっていた (500ゲーム × 60Hz = 30,000 件/秒の不要な走査)
- `games` は signal-log-store 側で gameNumber 昇順に append されることが保証されている (FIFO eviction と inProgressUpdate のみ末尾に作用) ので、**末尾から逆走査して baseline 以下に達した時点で break** する形に書き換え。未処理ゲームのぶん (典型的に 0〜2 件) しか触らないので、500ゲームでも 5000ゲームでも処理量は一定になる
- 修正範囲:
  - `maxInLog` の `reduce` 全走査 → 末尾要素参照 (`games[games.length-1]?.gameNumber`)
  - payout カード判別: `filter+sort` 全走査 → 末尾からの逆ループ + `break`
  - bonus カード判別: 同上
  - `isPayoutSettled` の events 全走査 → events を後ろから走査して最初の OUT で確定判定 (events も時系列順で末尾近くに最後の OUT があるため)
- 振る舞いは完全に同じ (判定ロジック・カウント結果は不変、O(N) を O(未処理ゲーム数) に縮めただけ)
- 加えて、加算が一切発生しなかった patch では `counts` を新オブジェクトにせず旧参照のまま `return s` で Zustand に同値を返すよう変更 → subscriber (KoyakuCounterPanel 等) の不要な re-render を抑制
- 該当: `src/ui/store/koyaku-store.ts`

## [0.2.171] - 2026-05-15 (PC + PWA 同期)

### 改善: 小役カウンターの「総合ゲーム数」を本体の総回転数とリアルタイム同期 (自動判別 ON 時)
- これまで自動判別 ON 時の小役側「総合ゲーム数」は「OUT が settle した払出ありゲーム」と「ボーナス検出ゲーム」を起点に更新していたため、**ハズレ / リプレイのゲームでは加算されず、本体の総回転数だけが先行**してずれていく挙動だった
- `useKoyakuAutoDetect` で本体の `counterTotalRotations` を購読し、自動判別 ON のとき小役側 `totalGames` に即時追従させるよう変更
- `Math.max` で防御 (本体リセット時に小役側カウントが消えない)
- 自動判別 OFF (手入力モード = ホール手タップ用途) では発火しないので、その経路は無変更
- 該当: `src/ui/hooks/useKoyakuAutoDetect.ts`

## [0.2.170] - 2026-05-15 (PC + PWA 同期)

### 改善: 小役カウンターの数値表示フォントを本体のテーマ設定と連動
- 本体 (テーマ →「数字フォント」) で DSEG7 / Orbitron / Audiowide 等を選ぶと、小役カウンター側の数値表示もそのフォントに切り替わる
- 連動する箇所: 小役カードのカウント数字 / 確率 (1/X) / ゲーム数入力 / 有効ゲーム数 / 設定判別の入力欄 / スコアバー数値 / サンプル G 数 / 寄り設定の各種数値表示
- CSS の `font-family` を `var(--num-font, "JetBrains Mono", monospace)` に統一 (13 箇所)。`--num-font` は本体 `useApplyTheme` が `:root` に設定するため、テーマ変更が即座に小役側にも反映される
- カード名・「設定1」等の日本語ラベルは従来通り通常フォントのまま
- 該当: `src/ui/styles/koyaku-counter.css`

### 修正: 設定判別カード展開時に設定3〜6 がクリップされて表示されない不具合
- カードを展開すると 設定1 と 設定2 だけが見え、設定3〜6 が次のカードに隠れて見えない問題があった
- 原因: `.koyaku-hantei-row` がフレックスアイテムで `flex-shrink: 1` (デフォルト) のため、カード数 (12 枚) が多いと親の `.koyaku-hantei-input-list` の高さに合わせて圧縮され、`overflow: hidden` でボディの下半分が切り取られていた
- `.koyaku-hantei-row` に `flex: 0 0 auto` を指定して圧縮を禁止。各行は自然な高さを保ち、総高さが画面を超えたら `.koyaku-hantei-input-list` の `overflow-y: auto` で縦スクロールするように
- 該当: `src/ui/styles/koyaku-counter.css`

## [0.2.169] - 2026-05-15 (PC + PWA 同期、小役カウンターを正式公開)

> 🎉 小役カウンター / 設定判別機能を**正式リリース**。フラグ管理を撤去し、全ユーザーのメニューに常時表示。「メニュー」見出し 7 回タップは「デバッグ情報コピー」に役割転用。

### 新機能: PWA shortcuts でホーム画面から直接起動 (Android Chrome / Edge)
- PWA manifest に `shortcuts` 配列を追加。ホーム画面アイコン長押し (Windows 11 はタスクバー右クリック) で 2 つのクイック起動メニューが出る:
  - 「小役カウンター」→ `/app/?shortcut=koyaku` で起動 → 小役カウンター画面が自動で開く
  - 「設定判別」→ `/app/?shortcut=hantei` で起動 → 設定判別の入力画面が自動で開く
- iOS Safari は仕様未対応のため、ホーム画面追加で通常起動になる (今後の対応待ち)
- URL クエリは初回マウント時に 1 度だけ処理してすぐに履歴から削除 → リロード時の意図しない再発火を防ぐ
- 該当: `vite.config.ts` (manifest) / `src/App.tsx` (useEffect) / `src/ui/util/boot-shortcut.ts` (新規 singleton) / `src/ui/components/KoyakuCounterPanel.tsx` (初期画面決定)

### 公開: 小役カウンター / 設定判別を全ユーザーに常時表示
- メニュー見出し 7 回タップでの「テスト機能 ON/OFF」隠しコマンドを撤去。フラグ判定 (`a-counter-x:feature-koyaku` localStorage キー) も削除し、メニューには常に「小役カウンター」が並ぶ
- 一旦 ON にしていたテスト端末でも同じ表示になるので追加の操作は不要
- 該当: `src/ui/components/MainMenu.tsx`

### 改善: 隠しコマンド (7 タップ) を「デバッグ情報コピー」に転用
- 公開リリースに伴い役割を変え、メニュー見出し 7 回連続タップで**端末のデバッグ情報**をクリップボードへコピーするようにした
- コピー内容: バージョン / Platform (Electron / PWA standalone / Web) / 画面サイズ / User-Agent / 機種数 / セッション件数 / 信号ログゲーム数 / 小役プリセット数 / 設定判別プロファイル数 / localStorage 使用量
- 用途: サポート問い合わせ時に端末状態を素早く貼り付ける。`navigator.clipboard` 非対応環境は `window.prompt` にフォールバック
- 該当: `src/ui/components/MainMenu.tsx`

### 改善: 設定判別の理論値入力欄を横並び 1〜3 列のグリッドに (テスト中→公開)
- 設定1〜6 を縦 6 行で並べていたのを `display: grid` + `repeat(auto-fit, minmax(180px, 1fr))` に変更し、横幅に応じて自動で 1〜3 列に展開
  - 〜359px → 1 列 / 360〜539px → 2 列 / 540px〜 → 3 列
- PC 別ウィンドウ (600×680) でも設定1〜6 すべてが 2 行で一望できる
- 各行 padding `6px` → `5px`、gap `12px` → `10px` に微調整
- 該当: `src/ui/styles/koyaku-counter.css`

## [0.2.168] - 2026-05-15 (PC + PWA 同期、小役カウンターはテスト中フラグ管理)

> 小役カウンターは引き続き「隠しコマンド (メニュー見出し 7 回タップ)」で有効化した端末のみに表示されるテスト機能。一般ユーザーの画面には影響なし。

### 修正: 設定判別の入力タブで設定6 が画面外で入力できない不具合 (テスト中)
- PC の小役カウンター別ウィンドウ (600×680) や、上下に余裕のないスマホ画面でカードを展開すると、設定1〜4 までしか見えず、設定5〜6 が `.koyaku-hantei-input-list` の表示領域の外側に隠れていた問題に対応
- カードを展開した瞬間に、その行を内側スクロール領域の上端へ自動スクロール (`scrollIntoView({ behavior: "smooth", block: "start" })`) するよう変更。これによりどのウィンドウサイズでも 6 設定が必ず一度に見える位置に来る
- 展開直後の高さ計算が完了してからスクロールするため、`requestAnimationFrame` 1 フレーム待ってから発火させている
- 該当: `src/ui/components/KoyakuHanteiPanel.tsx` (`HanteiInputRow` サブコンポーネント抽出 + 自動スクロール useEffect)

## [0.2.167] - 2026-05-15 (PC + PWA 同期、小役カウンターはテスト中フラグ管理)

> 小役カウンターは引き続き「隠しコマンド (メニュー見出し 7 回タップ)」で有効化した端末のみに表示されるテスト機能。一般ユーザーの画面には影響なし。次バージョン以降でフラグ撤去・正式公開予定。

### 新機能: 設定判別の「結果」タブを本実装 (テスト中)
- 入力タブで登録した設定1〜6 の理論値 (1/X) と、実戦中のカウント結果から、設定別の「一致度スコア (0〜100%)」を計算して表示する
- 計算ロジック (純関数 `computeHanteiResult`):
  - 実測確率 pm = `count / 有効ゲーム数`
  - 理論確率 ps = `1 / theoreticalDenom`
  - 相対誤差 e = `|pm - ps| / ps`
  - 一致度 closeness = `max(0, 1 - e)` (0..1)
  - 設定 s のスコア = その設定が入力された全カードの closeness 平均
  - 総合 = スコア最大の設定 (= 「寄り設定」)
- 結果タブの構成:
  - **サンプル情報バー** (有効ゲーム数 + サンプル少時の「ブレ大」警告バッジ)
  - **設定別スコアバー × 6** (横棒、最高スコアはゴールドで発光強調)
  - **カード別結果一覧** (実測 1/X + カウント数 + 「設定N寄り」バッジ + サンプル少バッジ)
    - 展開で 6 設定の理論値と一致度を全て確認可能
  - **常時免責文** 「統計的な予想であり、確定ではありません」
- データ不足時 (count=0 / eff=0 / 理論未入力) は判別を行わず、入力を促す案内を表示
- 警告閾値: 全体サンプル < 3000G (ブレ大) / カード単位 count < 10 (少バッジ)
- 該当: `src/ui/components/KoyakuHanteiPanel.tsx` / `src/ui/styles/koyaku-counter.css`

## [0.2.166] - 2026-05-15 (PC + PWA 同期、小役カウンターはテスト中フラグ管理)

> 小役カウンターは引き続き「隠しコマンド (メニュー見出し 7 回タップ)」で有効化した端末のみに表示されるテスト機能。一般ユーザーの画面には影響なし。v0.2.165 の隅々レビューで見つかった改修をまとめて反映。

### 改善: 小役グリッドを PC / Android / iPhone で全画面固定収容に統一 (テスト中)
- iPhone 縦で 12 枚表示の時にカード枠が上下スクロールで動いていた問題を解消。`grid-auto-rows: minmax(82px, 1fr)` → `1fr` のみに変更し、行高は画面高に合わせて自動で均等分配されるように
- PC・横画面のベース定義 (`1fr`) と完全に同じ仕組みに揃え、プラットフォーム差を排除
- 数字は `.koyaku-count-btn` の `container-type: size` 基準で追従するため、カードが縮んでも切れずに自然に縮小される
- 該当: `src/ui/styles/koyaku-counter.css`

### 修正: 設定判別の理論値入力で小数 ("8.") の打鍵中に「.」が消える不具合 (テスト中)
- `type="number"` の制御コンポーネントで、入力中に React が値を正規化して小数点が削られていた
- `type="text"` + `inputMode="decimal"` + `pattern="[0-9.]*"` に変更し、入力中は局所 string state のみで保持。確定 (blur / Enter) で初めて数値化してストアにコミットするように
- 該当: `src/ui/components/KoyakuHanteiPanel.tsx`

### 修正: プリセット削除時に対応する設定判別プロファイルが孤立する不具合 (テスト中)
- 小役プリセットを削除しても `koyaku-hantei-store` 側の対応プロファイルが残り、stale データとして累積していた
- `deletePreset` から動的 import で `useKoyakuHanteiStore.deleteProfile(id)` を呼ぶよう配線 (循環依存を避けるため top-level import は使わない)
- 該当: `src/ui/store/koyaku-store.ts`

### 内部: 設定判別パネルの useEffect 依存を primitive ベースに修正 (テスト中)
- `activePreset` オブジェクト参照に依存していたため、無関係な state 更新で配列が再構築されるたびに `ensureProfile` が無駄に再実行されていた
- `id` / `name` の primitive 値ベースに変更。`ensureProfile` 自体は既存があれば早期 return するので影響は実害無しだが、不要な計算を削減
- 該当: `src/ui/components/KoyakuHanteiPanel.tsx`

## [0.2.165] - 2026-05-15 (PC + PWA 同期、小役カウンターはテスト中フラグ管理)

> 小役カウンターは引き続き「隠しコマンド (メニュー見出し 7 回タップ)」で有効化した端末のみに表示されるテスト機能。一般ユーザーの画面には影響なし。

### 新機能: 設定判別 入力タブ (テスト中)
- 小役カウンターのドロワーに「設定判別」ボタンを追加。タップで設定判別画面に切り替わる (モーダル枠は流用)
- アクティブな小役プリセットと 1:1 で連動する設定判別プロファイルを自動生成。プリセットを切り替えると対応する機種データに自動で切り替わる
- 入力タブ: 機種名 + 各カードのアコーディオン (タップで開くと設定1〜6 の「1/[X]」入力欄が縦に並ぶ)。値は即 persist (自動保存)
- 結果タブはプレースホルダ。次リリース (v0.2.166) で「実測確率 vs 各設定理論値」のスコアバー・寄り設定バッジ・免責文 を実装予定
- 新規ストア `koyaku-hantei-store.ts` (永続キー `a-counter-x:koyaku-hantei-v1`) として独立。既存 koyaku-store とは完全別 = カウント/自動判別/保存への影響ゼロ
- 該当: 新規 `src/ui/store/koyaku-hantei-store.ts` / 新規 `src/ui/components/KoyakuHanteiPanel.tsx` / `src/ui/components/KoyakuCounterPanel.tsx` (画面切替) / `src/ui/styles/koyaku-counter.css`

### 改善: 新規プリセットのデフォルトカードを 12 枚構成に拡張 (テスト中)
- 設定判別の精度向上のため、弱/強/確定を別カードに分けた構成へ:
  - 小役 8 枚: ベル(12) / 弱スイカ(4) / 強スイカ(5) / 弱チェリー(6) / 強チェリー(7) / 確定チェリー(2) / チャンス目(1) / リプレイ(3)
  - ボーナス 4 枚: RB / BB / SBB / ART
- カード上限 (`MAX_KOYAKU_CARDS = 12`) ちょうどの構成。色は弱→標準→濃 の進行が一目で分かるよう同系統で濃淡をつけた
- 既存プリセット (旧 9 枚構成) は非破壊で残る (移行ガード方針)。12 枚に切り替えたい場合は編集モードの「デフォルトに戻す」ボタンで再生成、または「＋ 新規プリセット」で作成
- 旧名 (スイカ / チェリー) の払出枚数デフォルトは互換性のため `DEFAULT_PAYOUT_BY_NAME` に残置
- 該当: `src/ui/store/koyaku-store.ts`

## [0.2.164] - 2026-05-15 (PC + PWA 同期、小役カウンターはテスト中フラグ管理)

> 小役カウンターは引き続き「隠しコマンド (メニュー見出し 7 回タップ)」で有効化した端末のみに表示されるテスト機能。一般ユーザーの画面には影響なし。

### 改善: 小役カウンターのドロワー設計を見直し (テスト中)
- 実戦中に見る/触る項目をドロワーの外＝常時表示エリアに引き出した:
  - 「開始ゲーム数 / 総合ゲーム数 / 有効ゲーム数」3 行 (確率の分母、頻繁に確認)
  - 「自動判別」「減算モード」トグル (実戦中に切り替える)
- ステータスバーの「有効 0」表示は撤去 (直下に有効ゲーム数の行が常時出るので重複を回避)。ステータスバーは「プリセット名 + ▼」のみのシンプル表示に
- ドロワーには「プリセット選択 / 編集 / リセット / ボーナス中設定」のセッション設定系のみを残し、開いている時間を最小化
- ドロワーのメディアクエリを「タッチ端末の縦画面」だけでなく「幅 640px 以下の縦画面」にも広げて、PC ブラウザを細くしただけでも動作確認できるようにした (細い縦長ウィンドウなら省スペースの恩恵もある)
- 該当: `src/ui/components/KoyakuCounterPanel.tsx` / `src/ui/styles/koyaku-counter.css`

## [0.2.163] - 2026-05-15 (PC + PWA 同期、小役カウンターはテスト中フラグ管理)

> 小役カウンターは引き続き「隠しコマンド (メニュー見出し 7 回タップ)」で有効化した端末のみに表示されるテスト機能。一般ユーザーの画面には影響なし。

### 改善: 小役カウンターのスマホ縦表示で操作エリアをドロワー化 (テスト中)
- スマホ縦で上部の操作エリア (プリセット選択・ゲーム数・各種トグル) が画面の半分以上を占有し、下部の小役カードが窮屈だった問題に対応
- 常時表示は「プリセット名 + 有効ゲーム数 + ▼」の細いステータスバー 1 本のみにし、操作パネル本体はステータスバーのタップで上から降りてくるドロワーに変更。ドロワーは小役カードに重なる overlay なので、開閉してもカードの位置・サイズは動かない
- 小役カードをタップするとドロワーは自動で閉じる (設定 → カウントがワンタップで戻る)。これでスワイプ不要・カード 12 枚を常時フル表示でタップできる
- 編集モード中は従来どおり操作パネルをインライン展開。PC・横画面はステータスバー非表示で操作パネル常時表示のまま変更なし
- 該当: `src/ui/components/KoyakuCounterPanel.tsx` / `src/ui/styles/koyaku-counter.css`

## [0.2.162] - 2026-05-15 (PC + PWA 同期、小役カウンターはテスト中フラグ管理)

> 小役カウンターは引き続き「隠しコマンド (メニュー見出し 7 回タップ)」で有効化した端末のみに表示されるテスト機能。一般ユーザーの画面には影響なし。

### 修正: 小役カウンターのスマホ縦表示でカウント数字が枠から切れる不具合 (テスト中)
- 12 枚のカードを 3 列×4 行で並べたとき、各カードのカウント数字が色ボタンの枠より大きくなり上下に切れていた
- 原因はカウント数字のサイズ基準がパネル全体の高さ (cqh) になっており、ボタンが潰れても数字が縮まなかったこと。色ボタン自身を size container にして、数字がボタンの実寸に追従するよう修正
- あわせてスマホ縦の上部操作エリア (ゲーム数 3 行・操作ボタン・余白) をコンパクト化し、小役グリッドに最低カード高さ (約 82px) を保証。375 / 390 / 414px で横スクロール・文字切れが出ないことを確認
- 該当: `src/ui/styles/koyaku-counter.css`

### 改善: 小役カードの表示/非表示トグルのアイコンを統一 (テスト中)
- 編集モードの表示/非表示トグルが「目隠しザル 🙈」と「目だけ 👁」で不揃いだったのを、「目隠しザル 🙈 (非表示)」と「目が見えるサル 🐵 (表示中)」の同じサル絵文字ペアに統一
- 該当: `src/ui/components/KoyakuCounterPanel.tsx`

## [0.2.161] - 2026-05-15 (PC + PWA 同期、小役カウンターはテスト中フラグ管理)

> 小役カウンターは引き続き「隠しコマンド (メニュー見出し 7 回タップ)」で有効化した端末のみに表示されるテスト機能。一般ユーザーの画面には影響なし。

### 修正: 自動判別 ON 時のリセット・プリセット切替で有効ゲーム数が跳ね戻る不具合 (テスト中)
- 自動判別 ON のまま「リセット」または「プリセット切替」をすると、自動判別の基準ゲーム番号が古いまま残り、次の信号で総合ゲーム数がリセット前の大きな値に戻ってしまっていた (有効ゲーム数が 0 から数え直しにならない)
- リセット・プリセット切替時に、自動判別 ON なら基準ゲーム番号を「現在の信号ログ地点」に貼り直すよう修正。自動判別 OFF 時の挙動は従来どおり変更なし
- 該当: `src/ui/store/koyaku-store.ts` (`resetCounts` / `setActivePreset` で baseline を再設定)

## [0.2.160] - 2026-05-15 (PC + PWA 同期、小役カウンターはテスト中フラグ管理)

> 小役カウンターは引き続き「隠しコマンド (メニュー見出し 7 回タップ)」で有効化した端末のみに表示されるテスト機能。一般ユーザーの画面には影響なし。

### 改善: 小役カウンターに「デフォルトに戻す」ボタンを追加 (テスト中)
- 編集モードのツールバーに「デフォルトに戻す」ボタンを追加。カード配置を初期状態 (標準 9 カード) に戻せる
- カスタマイズした名前・色・払出枚数・並び順・カウントは破棄される (確認ダイアログあり)
- 該当: `src/ui/store/koyaku-store.ts` (`resetPresetToDefault` 追加) / `src/ui/components/KoyakuCounterPanel.tsx` / `src/ui/styles/koyaku-counter.css`

### 改善: 小役カウンターの初期表示を 9 カードすべてに変更 (テスト中)
- これまで SBB のみ初期非表示だったが、SBB も含めた 9 カード (リプレイ / ベル / スイカ / チェリー / チャンス目 / RB / BB / ART / SBB) をすべて初期表示にした
- 不要なカードは編集モードで個別に非表示にできる
- 既存プリセットの構成は変更しない (新規作成・「デフォルトに戻す」時のみ 9 カード)
- 該当: `src/ui/store/koyaku-store.ts`

## [0.2.159] - 2026-05-15 (PC + PWA 同期、小役カウンターはテスト中フラグ管理)

> 小役カウンターは引き続き「隠しコマンド (メニュー見出し 7 回タップ)」で有効化した端末のみに表示されるテスト機能。一般ユーザーの画面には影響なし。

### 改善: 小役カウンターを「小役カード」と「ボーナスカード」の 2 種別に分離 (テスト中)
- カードに種別 (`type`) を追加し、読み取る信号と判別ロジックを明確に分けた:
  - **小役カード** (リプレイ / ベル / スイカ / チェリー / チャンス目): OUT 信号 (払出) の集計値を払出枚数と照合して判別
  - **ボーナスカード** (RB / BB / SBB / ART): ボーナス信号の立ち上がりで 1 回カウント。払出枚数判定は使わない
- ボーナス信号は長時間 ON になるため、エンジン既存のエッジ検知 (`detectStarted`、本体のボーナスカウントと同じ仕組み) を利用。ON 継続中の重複カウントは起きない (1 回の長時間出力 = 1 ボーナス)
- デフォルトのカードセットを 9 枚に: 上記 8 枚 + SBB (SBB のみ初期非表示)
- 該当: `src/ui/store/koyaku-store.ts` (`KoyakuCardType` / `bonusKind` 追加、`applyAutoDetection` を payout/bonus の 2 系統に分離、永続化 version 4 へ migrate) / `src/ui/components/KoyakuCounterPanel.tsx` (編集 UI をカード種別で分岐)

### 改善: 小役カードのデフォルト払出枚数を設定 (テスト中)
- 標準小役の払出枚数を初期値として設定: リプレイ 3 / ベル 12 / スイカ 6 / チェリー 2 / チャンス目 1
- 新規作成時の初期値に使用。既存データは「払出枚数が未設定 (空欄) の小役」だけ補完し、ユーザーが設定済みの値は上書きしない (永続化 version 3 へ migrate)
- 該当: `src/ui/store/koyaku-store.ts`

### 改善: 小役カードの確率表示を読みやすく拡大 (テスト中)
- カード上部の「1/3.3」等の出現率表示が小さすぎてホール内で見えにくかったため、小役名と同じフォントサイズに拡大
- 該当: `src/ui/styles/koyaku-counter.css`

## [0.2.158] - 2026-05-15 (PC + PWA 同期、小役カウンターはテスト中フラグ管理)

> 小役カウンターは引き続き「隠しコマンド (メニュー見出し 7 回タップ)」で有効化した端末のみに表示されるテスト機能。一般ユーザーの画面には影響なし。

### 機能追加: 小役カウンターに「払出枚数による自動判別」を追加 (テスト中)
- 機械の払出信号 (OUT) の枚数から小役を自動判別してカウントする「自動判別」モードを追加
- 各小役カードに「払出枚数」を設定 (固定値ではなく機種ごとに編集可能)。受信した払出枚数と照合して該当する小役を判別する
- 「OUT のたびに加算」ではなく「1 ゲーム分の OUT 集計値から役を確定してから 1 回だけ加算」する設計
- 確定タイミングは「最後の OUT 信号が一定時間 (既定 500ms) 途切れた時」。次ゲームの IN を待たず、そのゲームのうちにカウントするため 1 ゲーム遅れが起きない
- 同じ払出枚数が複数の小役に設定された場合は表示順 (上のカード) を優先。編集画面で重複を警告表示
- 払出 0 (ハズレ・リプレイ等) は自動判別の対象外 (手動カウントは従来通り可能)
- 該当: `src/ui/store/koyaku-store.ts` / `src/ui/hooks/useKoyakuAutoDetect.ts` / `src/ui/components/KoyakuCounterPanel.tsx` / `electron/main.cjs` (信号ログを別ウィンドウへも配信)

### 機能追加: 小役カウンターに「ボーナス中の小役カウント設定」を追加 (テスト中)
- ボーナス (BB/RB/SBB/ART) 中に小役をカウントするかどうかを制御する設定を追加。手動カウント・自動判別の両方に適用
- 全体モード 3 種: 「カウントしない (既定)」「全小役カウント」「指定した小役のみ」
- 「指定した小役のみ」モードでは、各小役カードごとに「ボーナス中もカウント」を個別設定できる (将来「ボーナス中はベルだけ」等に対応するための小役単位の設計)
- 「小役の判別」と「実際のカウント可否」を分離 — ボーナス中も判別自体は行い、カウントするかどうかだけを設定で制御
- 該当: `src/ui/store/koyaku-store.ts` (`bonusCountMode` / `countDuringBonus` / `shouldCountKoyaku` 追加、永続化 version 2 へ migrate) / `src/ui/components/KoyakuCounterPanel.tsx`

### 改善: 小役カウンターのレスポンシブを 3 画面サイズ向けに再設計 (テスト中)
- 「スマホ縦の押しやすい 1 カラム UI」を全画面サイズの基本デザインに統一。PC も別物の横広レイアウトにせず、その縦バランスを拡大して中央寄せ・最大幅 680px で間延びを防ぐ
- グリッドは基本 3 列 (PC・縦スマホ共通)。縦スマホは操作ボタンを 44px 以上に拡大して片手操作・誤タップ防止。横スマホ (高さ極小) のみ 2 カラム + 余白圧縮
- PC の小役カウンター専用ウィンドウの既定サイズを 920×620 (横長) → 600×680 (縦長寄り) に変更
- 該当: `src/ui/styles/koyaku-counter.css` / `electron/main.cjs`

## [0.2.157] - 2026-05-14 (PC + PWA 同期、小役カウンターはテスト中フラグ管理)

### バグ修正: 小役カウンターのフローティング表示が実機モードで見えない不具合
- v0.2.156 で追加したフローティング表示が、実機モード (PC) で 📌 を押しても表示されない不具合を修正
- 原因: `.koyaku-floating` の z-index が 9000 で、実機モードの `.app-mode` レイヤー (z-index 10000) より下にあり背面に隠れていた
- 修正: `.koyaku-floating` の z-index を 10500 に変更 (`.app-mode` の 10000 より上、他モーダルの 11000 より下)
- 該当: `src/ui/styles/koyaku-counter.css`

## [0.2.156] - 2026-05-14 (PC + PWA 同期、小役カウンターはテスト中フラグ管理)

### 機能追加: 小役カウンターに「フローティング表示」を追加 (PC のみ、テスト中)
- メインのデータカウンター画面を見ながら小役カウンターを使えるよう、PC 限定でフローティングパネル表示モードを追加
- 小役カウンターのヘッダー右の **📌 ボタン** でモーダル ⇔ フローティングを切替
- フローティング時はオーバーレイ無し → **背面のメイン画面をそのまま操作可能**
- ヘッダーをドラッグしてパネルを自由に移動できる。位置は localStorage に保存され次回も同じ場所に表示
- スマホ・タブレットは従来通りモーダル全画面表示 (浮動はタッチ操作に不向きなため)
- 該当:
  - `src/ui/store/koyaku-store.ts` に `floating` / `floatX` / `floatY` 状態 + `setFloating` / `setFloatPos` 追加
  - `src/ui/components/KoyakuCounterPanel.tsx` をモーダル / フローティング両対応に (ドラッグ移動ロジック含む)
  - `src/ui/styles/koyaku-counter.css` に `.koyaku-floating` 追加

## [0.2.155] - 2026-05-14 (PC + PWA 同期、小役カウンターはテスト中フラグ管理)

### 内部対応: 小役カウンターのフィーチャーフラグを「隠しタップコマンド」で切替可能に
- v0.2.154 で小役カウンターを `localStorage` フラグ管理にしたが、本番 Electron は開発者ツールが無効でフラグを手動セットできなかった
- 修正: メインメニューの「メニュー」タイトルを **7 回連続タップ** すると小役カウンター (テスト機能) の有効/無効が切り替わる隠しコマンドを実装 (Android の「ビルド番号 7 回タップ」と同様の仕組み)
- 開発者ツール不要で PC・スマホどちらでもテスト機能を有効化できる。一般ユーザーには通常の見出しに見えるだけ
- 有効化/無効化時は確認アラートを表示
- 該当: `src/ui/components/MainMenu.tsx`

## [0.2.154] - 2026-05-14 (PC + PWA 同期、小役カウンターはテスト中フラグ管理)

### 内部対応: 小役カウンター (v0.2.153) をフィーチャーフラグ管理に変更
- v0.2.153 で追加した小役カウンター機能を、**開発側でのテストが完了するまで一般ユーザーには非表示** にするためフィーチャーフラグで制御
- `localStorage` に `a-counter-x:feature-koyaku` = `"on"` をセットした端末でのみ、メインメニューに「小役カウンター」項目が表示される
- 通常ユーザーのメニューは v0.2.152 以前と同じ見た目 (小役カウンター項目なし)
- テスト完了後、このフラグ判定を撤去する release で全ユーザーに公開予定
- 該当: `src/ui/components/MainMenu.tsx`

## [0.2.153] - 2026-05-14 (PC + PWA 同期、小役カウンターは内部リリース)

### 新機能: 小役カウンター機能を追加 (MVP) — ※ v0.2.154 でテスト中フラグ管理に
- パチスロ実戦中に小役 (ベル・チェリー・スイカ等) の出現回数をカウントし、有効ゲーム数に対する出現率を表示する専用パネルを新設
- **開き方**: メインメニュー (左上ロゴ) → 「小役カウンター」
- **MVP の機能範囲**:
  - **プリセット管理**: 機種ごとの小役構成を複数保存・切替。作成 / 複製 / リネーム / 削除。初期プリセット「汎用 (ノーマル機)」付き (リプレイ・ベル・スイカ・弱チェリー・強チェリー・チャンス目)
  - **小役の編集**: 「小役を編集」モードで 追加 / 名前変更 / 色変更 (10 色パレット) / 並び替え / 表示切替 / 削除
  - **手動カウント**: 各小役の大きな ＋ / − ボタン。押下時にカードがフラッシュ + 対応端末では振動フィードバック
  - **ゲーム数**: 総ゲーム数 / 開始ゲーム数を入力。「連動」ボタンで本体カウンターの総回転数を取り込み。有効ゲーム数 = 総 − 開始
  - **出現率表示**: 各小役を「1/32.5」形式で表示 (有効ゲーム数 ÷ カウント)
  - **永続化**: プリセット・カウント・ゲーム数を localStorage に保存、アプリ再起動後も復元
  - **レスポンシブ**: PC は小役カードを多列グリッド、スマホは 2 列 + 大きめ ±ボタンで片手操作対応。狭幅端末は 1 列
- **将来拡張予定**: 払出枚数による自動判別 / 設定判別 (設定 1〜6 理論値比較) / カウント履歴・取消 / 機種別テンプレート / 共有・エクスポート
- 該当:
  - `src/ui/store/koyaku-store.ts` 新規 (プリセット・カウント・永続化)
  - `src/ui/components/KoyakuCounterPanel.tsx` 新規 (パネル UI、PC/スマホ両対応)
  - `src/ui/styles/koyaku-counter.css` 新規
  - `src/ui/store/ui-store.ts` の `PanelName` に `koyaku` 追加 + `MainMenu.tsx` メニュー項目 + `App.tsx` 配線 + `AppIcon.tsx` に koyaku アイコン追加

## [0.2.152] - 2026-05-10 (PC + PWA 同期)

### バグ修正: 機種選択モーダルの「新規作成」ボタンで現セッションのデータが警告なしに消える不具合
- 機種選択 → 「新規作成」ボタンを押すと、現在プレイ中のデータ (差枚・回転数・履歴) が確認なしに即 0 リセットされる不具合を修正
- カタログ・ビルトイン・ini 読み込み・ライブラリ機種選択は既存の `guardedSwitch` 経由で 3 択ダイアログ (保存して変更 / 保存せず変更 / キャンセル) が出るが、「新規作成」だけが歴史的経緯で `loadMachine` を直接呼んでおりガード漏れだった
- 修正: 「新規作成」の `onClick` も `guardedSwitch` でラップ。`isDirty=true` (プレイ中データあり) のときだけダイアログ表示
- 該当: `src/ui/components/MachineSelector.tsx`
- 全 loadMachine / reset / loadSnapshot 経路を再チェック済 (他は既にガードあり)

## [0.2.151] - 2026-05-06 (PC + PWA + admin-ui 同期、ランディング #changelog 非表示)

### 機能改善: 機種新規追加時のデフォルトで「ART を連荘数に含める」を ON に
- v0.2.150 で連チャン計測を ON にしたが、ART を連荘数に含めるはユーザー判断で OFF にしていた
- ユーザー要望に合わせ、`renchan.includeArt` も `true` (含める) をデフォルトに変更
- 該当: `src/ui/components/MachineSelector.tsx` + `admin-ui/src/shared/machine-config.ts`

## [0.2.150] - 2026-05-06 (PC + PWA + admin-ui 同期、ランディング #changelog 非表示)

### 機能改善: 機種新規追加時のデフォルト設定をユーザー指定 ini に合わせて統一
- 本体アプリ「機種選択 → 新規追加（白紙から）」と admin-ui「機種管理 → +新規追加」の **両方の経路** で、新規機種のデフォルト設定を統一
- 新デフォルト:
  - 信号: IN=1, OUT=2, RB=3, BB=4 / ART/SBB ピン未割当
  - 1 ゲーム IN パルス: 通常 3 / ボーナス 3
  - ART 開始条件: なし / ART 終了条件: 小役判定 (10 件中 3 件)
  - ART 開始時の回転数: 一時停止 / ART 終了時: リセット
  - BB 開始: 信号モード / SBB 開始: なし (機種ごとに編集判断)
  - タイトル: RB / BB のみ既定値、ART / SBB は空
  - 連チャン計測: 使用する / 100 回転を対象範囲 / ART は連荘数に含めない
- 該当: `src/ui/components/MachineSelector.tsx` + `admin-ui/src/shared/machine-config.ts`
- ランディング #changelog 非表示: 設定編集する運営者向けの内部改善のためエンドユーザー関係なし

## [0.2.149] - 2026-05-06 (PC + PWA 同期)

### 機能追加: テスト用信号シミュレーターの IN/OUT に「1回」(パルス送信) ボタンを追加
- 実機の IN/OUT 信号は短いパルスを連打する性質のため、シミュレータでも 1 回ずつクリックして再現したい用途に対応
- 既存の「発火」(トグル式 ON 保持) ボタンに加えて、IN (pin 1) / OUT (pin 2) のみ「1回」ボタンを追加。1 クリックで 60ms ON → OFF のパルスを 1 回送信
- 既存ボタンは変更なし: BB/RB/SBB/ART/ERR 等のボーナス系・状態系ピンは引き続きトグルで ON 保持
- CSS: `.sim-btn-once` クラスでグリーン系の控えめなスタイル
- 該当: `src/ui/components/SignalSimulator.tsx` + `src/ui/styles/simulator.css`

## [0.2.148] - 2026-05-06 (PC + PWA 同期)

### バグ修正: 手動ボーナストグルと物理信号で `totalRotations` リセット動作が違っていた不整合を解消
- 物理信号経由 (`process-frame.ts`) は BB/RB/SBB rising で常時 `totalRotations = 0` だが、手動ボーナストグル (`engine-runtime/index.ts:toggleManualBonus`) は `if (wasInArt)` の条件付き (= ART 中のみリセット) で動作が違っていた
- 結果: テストシミュレータや手動操作機能で通常時の BB/SBB トグルがリセットされず、「ボーナス引いた瞬間 0G」仕様 (2026-04-27 確定) と食い違っていた
- 修正: 手動 BB/SBB トグルも物理信号と同じく **常時 0 リセット** に統一 (`if (wasInArt)` 条件を撤去)
- 手動 ART は引き続き `artStartMode === "resetAndCount"` のみリセット (process-frame.ts の startArt と一致、変更なし)
- 一般ユーザー影響なし (BLE/USB 物理信号経路では既に正しく動作していた)、テスト・開発時の整合性向上が主目的
- 該当: `src/core/engine-runtime/index.ts`

## [0.2.147] - 2026-05-06 (PC + PWA 同期)

### UX 改善: 横画面低高さ時の Y 軸ラベル「1k」「0」を表示しつつ重ならないように位置調整
- v0.2.146 で Y 軸ラベル全体を `visibility: hidden` で非表示にしていたが、ユーザー要望「1k と 0 は出したい (中間 500 だけ省略)」に対応
- 「500」: `display: none` で省略 (中間ラベルなしでも上端と下端の 2 点でバー高さの目安は伝わる)
- 「0」の top 位置を `calc(100% - 60px)` から `calc(100% - 50px)` に再固定。下段 (CSS でコンパクト化された約 50px) の上端 = バー下端に揃え、container 高さに依存せず「1k」(top:30) と十分な間隔を確保
- 該当: `src/ui/styles/counter.css`

## [0.2.146] - 2026-05-06 (PC + PWA 同期、ホットフィックス)

### バグ修正: v0.2.145 でボーナス履歴のバー領域が消える致命的なリグレッションを修正
- v0.2.145 で「Y 軸ラベル全体を `display: none`」にしたところ、CSS Grid の auto-placement により次の子要素 `.bhv4-content` (= バー領域本体) が左 28px の Y 軸列に詰められ、横画面低高さ端末でバーが「現」1 本しか見えなくなる致命的な不具合
- 原因: `.bhv4-grid` の `grid-template-columns: 28px 1fr` で、Y 軸子要素が消えた瞬間、コンテンツ子要素が 28px 列に配置されてしまう (CSS Grid の仕様)
- 修正: `display: none` → `visibility: hidden` に変更。レイアウト (grid 配置) は維持しつつラベルだけ見えなくする
- 該当: `src/ui/styles/counter.css`

## [0.2.145] - 2026-05-06 (PC + PWA 同期)

### UX 改善: 横画面低高さ時にボーナス履歴 Y 軸ラベル全体を非表示化
- v0.2.144 で「500」のみ省略したが、Galaxy Z Flip6 等の極小高さ端末では container 高さ h<90px で「1k」と「0」のラベル位置自体が逆転して重なる問題が残っていた
- 原因: `1k` top=`30px`、`0` top=`100% - 60px` で、container 高さ h のとき「1k と 0 の差 = h - 90px」、h<90 で逆転
- 修正: 横画面低高さ時は Y 軸ラベル全体を `display: none` に変更。バー上の数字 (回転数 + 差枚) で各 cycle の値は直接読めるため、Y 軸補助ラベルは無くてもグラフ理解可能と判断
- bhv4-grid の 28px column は維持 (バーの位置がずれないように)
- 該当: `src/ui/styles/counter.css`

## [0.2.144] - 2026-05-06 (PC + PWA 同期)

### UX 改善: 横画面低高さ時にボーナス履歴 Y 軸ラベル「500」を省略して「0」との重なりを解消
- v0.2.143 で背景色パディングを追加したが、Galaxy Z Flip6 など container 高さが特に小さい (h ≦ 90px) 端末では「500」と「0」のラベル位置が縦方向に重なって読めない問題が残っていた
- 原因: 「500」ラベルの top 位置が `30px + (100% - 30px - 60px) × 0.5` で、container 高さ h のとき「500 と 0 の間隔 = h/2 - 45px」になり、h<90px で完全に重なる
- 修正: `@media (max-height: 600px) and (orientation: landscape)` ブロックに「500」ラベルのみ `display: none` を追加。「1k」(上端) と「0」(下端) だけ表示でバー高さの目安は維持
- 該当: `src/ui/styles/counter.css`

## [0.2.143] - 2026-05-06 (PC + PWA 同期)

### UX 改善: ボーナス履歴グラフの Y 軸ラベル「1k / 500 / 0」がバー上の数字と重なって読みづらい問題を解消
- Galaxy Z Flip6 等の低高さ横画面端末で、Y 軸ラベル (1k/500/0) がバー上の数字 (回転数 + 差枚) やバー本体と重なって視覚的に潰れる問題を改善
- 修正: `.bhv4-y-axis span` にカード背景色のパディング (`background: var(--card)` + `padding: 1px 3px` + `border-radius: 3px` + `z-index: 1`) を追加し、ラベル周辺だけ背景色で抜くことで重なっても文字が埋もれず読めるようにした
- 横画面低高さ時 (`@media (max-height: 600px) and (orientation: landscape)`) は更に控えめに: font-size 9px → 8px、opacity 0.75 でメインバー情報の邪魔にならないように
- 該当: `src/ui/styles/counter.css`

## [0.2.142] - 2026-05-06 (PC + PWA 同期)

### バグ修正: Galaxy Z Flip6 など低高さ横画面端末でボーナス履歴下段の連チャンゲージが見切れる
- Galaxy Z Flip6 横画面 (実 viewport ~750px) で、ボーナス履歴グラフ下段の連チャンゲージ (青い帯) が画面下端で切れる現象を修正
- v0.2.101 で「スマホ横画面で下段見切れ」を対応済みだが、Z Flip6 のような特に高さの低い端末では下段 (履歴番号 + 種別ピル + 連チャンゲージ、合計約 65px) が card cell に収まりきらないケースがあった
- 修正: `@media (max-height: 600px) and (orientation: landscape)` で下段の各要素を margin/height/font-size 単位で詰めて、合計約 50px に圧縮 (reserved 95px 内に余裕を作る)
- 詰める要素: `.bhv4-idx-row` margin/padding、`.bhv4-idx-cell` font-size 10→9px、`.bhv4-type-row` margin、`.bhv4-type-pill` font-size 10→9px / padding、`.bhv4-chain-row` height 18→14px、`.bhv4-chain-segment` height 16→12px / font-size 10→9px
- バー本体 (バー領域 + 上 stack 30px) は維持。デザインの雰囲気と読みやすさを損なわない範囲の調整
- PC や iPhone 横画面 (実 viewport 高さ 800px 以上) には影響なし
- 該当: `src/ui/styles/counter.css`

## [0.2.141] - 2026-05-06 (PC + PWA 同期)

### バグ修正: ART 中に再度 ART rising が来た時、ヘッダ「N連」バッジと連荘ゲージで表示が食い違う不具合
- 「ART を連荘数に含める」ON 設定下で ART 中にもう一度 ART 信号が立ち上がった場合、ヘッダの「N連」バッジは正しく `+1` されるが、ボーナス履歴グラフの連荘ゲージ表示は `1 連` のまま更新されなかった
- 原因: `engine.counts.renchanStreak` (engine 由来) は `startArt` 内で「ART 中の再 rising = 一度終了して再開」として扱い `renchanStreak += 1` するが、`engine-runtime/index.ts` の cycles 操作は `(prevPhase.art=false → nextPhase.art=true)` の rising edge しか見ておらず、再 rising (true → true) で cycles に新 cycle が追加されなかった
- 修正: `engine.counts.artCount` のデルタを見て「再 ART rising」を検知し、`prevPhase.art=true` のときは新 ART cycle を末尾に push するロジックを追加。これにより cycles に「旧 ART」「新 ART」の 2 つが並び、連荘ゲージ length も `+1` される
- 結果: ヘッダ N連バッジと連荘ゲージで表示が一致 (例: ART → 再 ART で両方「2 連」)
- `hideArtInBonusHistory: true` (反映しない) の場合は新 cycle 追加もスキップ (透過 ART 維持)
- 該当: `src/core/engine-runtime/index.ts` の onFrame 内

## [0.2.140] - 2026-05-06 (PC + PWA 同期)

### バグ修正: 「AT/RT/ART 開始時の回転数 = カウントを続行する」設定で ART 突入時にゲーム数が 0 になる不具合
- v0.2.139 の UI 改善時に発生したリグレッション。「ボーナス」タブ「反映しない」のとき UI 表示だけ強制 "continue" にして内部 state は元値のまま、という実装にしていた
- これにより「反映しない」を経由した機種設定で「反映する」に戻すと、UI には「カウントを続行する」と書かれているのに内部 state は古い「リセットしてカウントする」のまま保存されるケースが発生
- 結果として実機動作では ART 突入時に 0 リセットされ、UI 表示と挙動が食い違う不具合が起きていた
- 修正: `MachineEditor.tsx` の `setHideArtInBonusHistory` をラッパー化し、`true` (反映しない) に切り替えた瞬間に `artStartGameCountMode` / `artEndGameCountMode` の内部 state も `"continue"` に強制同期
- 二重ガード: `buildConfig` 内でも `hideArtInBonusHistory: true` のとき `artStartGameCountMode` / `artEndGameCountMode` を強制 `"continue"` 保存。旧仕様 `gameCountMode` 派生も連動
- 該当: `src/ui/components/MachineEditor.tsx`

### 仕様変更: ART 中に再度 ART rising が来た場合、開始モード "continue" を尊重して総回転を維持
- 「開始時 = カウントを続行する」+「終了時 = リセットする」設定で、ART 中に再度 ART rising が来ると `endArt → startArt` の連鎖により総回転が 0 リセットされていた
- 内部的には「一度終了して再開」と解釈されるが、ユーザーが「カウントを続行する」を選ぶ意図は「ART 突入で総回転を維持したい」ため、再 rising でも維持されるべきというユーザー判断
- 修正: `endArt()` に `skipTotalRotationsReset` オプションを追加し、`startArt` 内で再 rising を検知した際に `artStartGameCountMode === "continue"` なら totalRotations リセットを skip
- 通常の ART falling (信号 OFF) 時は従来通り `artEndMode = "reset"` で 0 リセット (機種仕様維持)
- 該当: `src/core/engine/process-frame.ts` の `startArt` / `endArt`

## [0.2.139] - 2026-05-06 (PC + PWA 同期)

### UX 改善: 機種設定エディタの大幅整理 (チェックボックス → ラジオ化、タブ名見直し、設定連動の明示)
- **チェックボックス → ラジオ化** (二重否定や付け忘れの誤解を構造的に減らす):
  - 「AT/RT/ART のボーナス履歴への表示」: ☐ 反映しない → ◯ 反映する / ◯ 反映しない
  - 「ART の連荘数への扱い」: ☐ 含める → ◯ 含める / ◯ 含めない
  - 「連チャン計測・表示機能」: ☐ 使用する → ◯ 使用する / ◯ 使用しない
  - 「AT/RT/ART 中の RB/BB/SBB 発生時の挙動」: ☐ 直ちに終了する → ◯ 継続する / ◯ 直ちに終了する
- **タブ名を意味的なラベルに変更**: 「設定その1/その2/その3」→ 「基本」「ボーナス」「連チャン」。エラーメッセージ・相互参照ヒント文も全て新タブ名に統一
- **設定連動の明示** (前回検証で残課題だった「不整合 2」対応):
  - 「ボーナス」タブの「AT/RT/ART のボーナス履歴への表示」が「反映しない」のとき、同タブの「ART 開始時/終了時の回転数」ラジオを disabled + 強制「カウントを続行する」表示 + 警告ヒント
  - これにより `process-frame.ts` の `resolveArtStartMode/EndMode` での "continue" 強制上書きが UI から見えるようになり、「pause を選んだのに動作していない」混乱を解消
- **「AT/RT/ART 中の RB/BB/SBB 発生時の挙動」セクションを「基本」→「ボーナス」タブへ移動**: ボーナス系設定が「ボーナス」タブに集約され探しやすくなる
- **「連チャン計測・表示機能 = 使用しない」のとき配下設定を完全折りたたみ**: disabled でグレーアウトする代わりに非表示にして UI をスッキリ
- **短いラジオを横並び**: 「使用する/使用しない」のような短いラベルは `editor-radio-row-inline` クラスで横並び化、縦スペース節約

## [0.2.138] - 2026-05-05 (PC + PWA 同期)

### 仕様変更: 設定その2「ART を履歴に反映しない」ON 時、設定その3「ART を連荘数に含める」を強制 OFF に
- 設定その2 ON + 設定その3 ON のとき、ART 単独で引いた場合に **ヘッダの「N連」バッジは「1 連」表示なのに、ボーナス履歴の連荘ゲージは表示なし** という UI 上の食い違いがあった
- 原因: ヘッダは `engine.counts.renchanStreak` (engine 由来)、連荘ゲージは `cycles` 配列由来。設定その2 ON で cycles に ART が記録されない一方、設定その3 ON で renchanStreak には反映されるため情報源が食い違っていた
- 仕様変更: **ART を履歴で透過扱いするなら連荘判定からも除外する** が自然な解釈なので、設定その2 ON のとき設定その3「ART を連荘数に含める」は強制 OFF として保存
- UI: 設定その3 のチェックボックスは disabled (操作不可) + 警告ヒント「⚠ 設定その2 ... が ON のため、この設定は強制的に OFF として動作します」表示
- buildConfig 側でも `includeArt: hideArtInBonusHistory ? false : renchanIncludeArt` で保存時に強制 OFF
- 該当: `src/ui/components/MachineEditor.tsx` (RenchanTab + buildConfig) + `src/ui/styles/machine-selector.css` (`.editor-hint-warn` スタイル追加)

## [0.2.137] - 2026-05-05 (PC + PWA 同期)

### バグ修正: 「ART を連荘数に含める」を OFF にしても連荘ゲージが ART を 1 連としてカウントしていた不具合
- 連荘判定が **engine 側 (ヘッダの「N連」バッジ用) と UI 側 (ボーナス履歴の青い連荘ゲージ用) で別ロジック** だったが、UI 側 (`chain-segments.ts`) は `includeArt` 設定を未参照だった
  - 結果: 設定 OFF でもボーナス履歴グラフ下の連荘ゲージは ART を含めて連荘表示してしまう不整合
  - ヘッダバッジ (engine.counts.renchanStreak) は正しく ART を除外していた → 表示が食い違う
- 修正: `chain-segments.ts` の `computeChainSegments` に `includeArt` 引数を追加し、`includeArt=false` の場合は親 ART cycle (`bonus="ART", duringArt 無し`) を **「連荘範囲は跨ぐが連荘数にカウントしない」** (skip) ロジックに変更
- `ChainSegment` に `endIdx` フィールド追加 (skip cycle を含む実範囲を保持)、`length` は連荘数 (skip 除く)
- `EqBarChart.tsx` で `machineConfig.renchan?.includeArt` を渡す + `findSegmentForIdx` も skip cycle を考慮した位置計算に更新
- 結果: ヘッダの連荘数バッジと連荘ゲージで表示が一致、ART を跨いだ連荘も正しく可視化
- 該当: `src/ui/components/bonus-history/chain-segments.ts` + `src/ui/components/EqBarChart.tsx`

## [0.2.136] - 2026-05-05 (PC + PWA 同期)

### 改善: ART 中サブボーナス (緑枠ボーナス) のバー上の差枚を「ボーナス本体での獲得枚数」表示に変更
- ART 中に発生した BB/RB/SBB のサブボーナス cycle (緑枠) は、これまでバー上の差枚に「ボーナス当選**時**の累積差枚」(= 当時のスナップショット) を表示しており、他の cycle (= サイクル全体差枚) と意味が異なっていた
- v0.2.136 から **「サブボーナス本体での獲得枚数」** (= ボーナス開始 → 終了までの差枚増減) を表示
- 例: ART 中に BB が rising した時の累積差枚 -200、BB 終了時の累積差枚 +300 → サブ BB バー表示 = `+500` (= ボーナスで取った枚数)
- 親 ART cycle はこれまで通り「ART サイクル全体差枚」(サブ込みの増減) を表示するため、両方の意味が直感的に取れるようになる
- 実装:
  - `HistoryCycle` に `diffMedalsAtCycleEnd?: number` を追加 (engine-runtime/types.ts + counter-store.ts 両方同期)
  - `engine-runtime/index.ts`: サブボーナス挿入時に `diffMedalsAtCycleStart = 当選時累積` をセット、サブの falling (BB/RB/SBB) で対応 cycle に `diffMedalsAtCycleEnd` を書き込み
  - `EqBarChart.tsx` の `calcCycleDiff` でサブ cycle (`duringArt === true`) の場合 `end - start` を返す分岐追加
- 旧データ復元時のフォールバック: `diffMedalsAtCycleStart` が無い古いサブ cycle は `diffMedalsAtBonus` (当選時累積) 表示にフォールバック
- グラフのバー上 ⇔ タップ詳細パネルは引き続き同じ計算結果を共有 (整合性維持)

### UX 改善: 機種設定エディタに「ART 履歴表示」と「ART 連荘カウント」が独立であることを明示
- 設定その2「AT/RT/ART をボーナス履歴に一切反映しない」と設定その3「ART を連荘数に含める」が独立した別設定であることを、両方のチェックボックス補足にクロスリファレンスを追加
- 「チェックを入れたつもりが反映されていなかった」事故をさらに減らす目的の UI 改善

## [0.2.135] - 2026-05-05 (PC + PWA 同期)

### UX 改善: 機種設定エディタに未保存変更の検知と保存忘れ防止機能を追加
- 「設定の適用」「設定の適用 + ライブラリ更新」を押さずに閉じてしまうと、変更したつもりのチェックや数値が反映されない事故を防ぐための仕組みを追加
- **視覚マーカー (常時表示)**:
  - エディタタイトル横に「● 未保存」バッジ (赤、点滅)
  - フッター左側に「● 未保存変更があります — 「設定の適用」を押さずに閉じると破棄されます」ヒント
  - 保存ボタン 2 種に未保存時のグロー + 点滅エフェクト
- **確認ダイアログ (閉じる時)**: 未保存変更がある状態で「× ボタン / ESC / オーバーレイクリック / キャンセル」を押すと確認ダイアログを表示
  - 「破棄して閉じる」「保存して閉じる (= 設定の適用のみ)」「編集を続ける」の 3 択
  - 設定エラーがある場合は「保存して閉じる」が disabled
- 該当: `src/ui/components/MachineEditor.tsx` (`isDirty` 検知 + `UnsavedChangesDialog` 追加) + `src/ui/styles/machine-selector.css` (バッジ + ダイアログ + 強調エフェクト)

## [0.2.134] - 2026-05-05 (PC + PWA 同期)

### 仕様再確定: 「総回転」カードを「ボーナス中以外の通常回転数の累積 (リセットなし)」に戻す
- v0.2.133 で「ボーナスごとに 0 リセット」(= ハマリ G 数表示) に変更したが、ユーザー仕様再確認の結果、
  本来の意図は **「ボーナス中の回転数を除いた累積」** = 通常時のみカウントしてリセットされない値、と判明
- これは v0.2.112 〜 v0.2.132 の挙動と同じ。実質的に v0.2.133 の修正だけを撤回する形
- `engine-runtime/index.ts` の `mirrorFromEngine` で `totalRotations: c.totalRotations` → `totalRotations: c.sessionRotations` に戻す
- 結果: 「総回転」= 通常時のみ累積、リセットなし / 「ゲーム数」(mid.gameCount) = ハマリ G 数、ボーナスごと 0 リセット (役割分離)

## [0.2.133] - 2026-05-05 (PC + PWA 同期)

### 仕様変更: 「総回転」カードを「ボーナスごとに 0 リセット」する挙動に戻した
- v0.2.112 (2026-05-04) で「総回転」を `sessionRotations` (= 当日累計、リセットなし) に切り替えていたが、
  ユーザー仕様確認 (2026-05-05) で「ボーナスを引いたら 0 にリセットされるべき」と判断 → 撤回
- `engine-runtime/index.ts` の `mirrorFromEngine` で `totalRotations: c.sessionRotations` → `totalRotations: c.totalRotations` に戻す
- 結果として「総回転」と「ゲーム数」(mid.gameCount) が **同じ値・同じ挙動** になる (両方ともハマリ G 数表示、ボーナス終了で 0 リセット)
- 確率計算 (ART/BB/RB/SBB 確率) は引き続き `sessionRotations` を使用 (ボーナスごとリセットされる値で確率を出すと不安定になるため)

## [0.2.132] - 2026-05-05 (PC + PWA 同期)

### 改善: ボーナス履歴グラフの差枚表示を「cycle 全体の差枚」に再設計
- ユーザー要望「各バーには そのサイクルでの差枚 (前ボーナス終了 → 次ボーナス終了 までの増減) を表示してほしい」「現在進行中も累積して見えるようにしてほしい」「ボーナス引いても 0 リセットしないでほしい」を反映
- 旧仕様: バー上の差枚 = ボーナス当選時の累積差枚スナップショット (固定値、進行中の現在サイクルは空欄)
- 新仕様: 1 cycle = 「前ボーナス終了 〜 次ボーナス終了」の塊として再定義し、各バーに cycle 全体での差枚増減を表示
  - 過去 cycle (完了済): `次cycle.diffMedalsAtCycleStart - 自cycle.diffMedalsAtCycleStart` (確定値)
  - 現在 cycle (末尾): `現在累積差枚 - 自cycle.diffMedalsAtCycleStart` (リアルタイム)
  - ボーナス当選では cycle 境界が変わらない → 「現」位置の数字が引き続いて見える
  - ボーナス終了 (cycleFinalized) で空 cycle が push される瞬間に「現」位置が 0 リセット → 通常時のハマり/勝ちを再蓄積
- 実装:
  - **`HistoryCycle` に `diffMedalsAtCycleStart?: number` を追加** (cycle 開始時の累積差枚スナップショット)。`engine-runtime/types.ts` + `counter-store.ts` 両方で同期
  - **engine-runtime/index.ts**: `cycleFinalized` で空 cycle を push する時 + `INITIAL_CYCLES` + 再起動時に diffMedalsAtCycleStart をセット
  - **EqBarChart.tsx**: バー上の差枚計算を `calcCycleDiff(cycle, nextCycle, currentDiffMedals)` に統一
- 旧データ復元時のフォールバック: `diffMedalsAtCycleStart` が無い古い cycle は従来通り `diffMedalsAtBonus` 表示。グラフとパネルで同じ値が出るので不整合なし

### バグ修正: ボーナス履歴グラフのバー上の差枚と、タップ時詳細パネルの差枚が異なる値だった不具合を修正
- 旧仕様: バー上は cycle 全体差枚、詳細パネルは `cycle.diffMedalsAtBonus` (当選時スナップショット) を直接参照していたため、同じ履歴をタップしても異なる数字が表示されることがあった
- 修正: `BonusDetailContext` に `cycleDiffMedals` フィールドを追加し、EqBarChart で計算した値をそのまま詳細パネルへ渡す形に統一。差円 (`× コインレート`) も同じ値ベースで再計算
- 該当: `src/ui/components/EqBarChart.tsx` + `src/ui/components/bonus-history/BonusDetailPanel.tsx`

## [0.2.131] - 2026-05-04 (PC + PWA 同期)

### 改善: 機種選択 ↔ 機種編集の整合性を完全保証する仕組みを追加
- v0.2.129/130 で大半の不具合は解消したが、残っていた 2 つの懸念 (旧スナップショットでの同名機種曖昧性 / 永続化二重管理によるズレ) を **完全になくす** ための強化
- **新規ヘルパー `findMatchingLibraryEntry`** (`machine-library-store.ts`): 機種設定 (machineConfig) からライブラリエントリを検索する共通関数
  - 1. machineConfig 完全一致 (JSON ディープ等価) → 同名機種が複数あっても信号ピン構成等で識別可能
  - 2. machineName + manufacturer 一致 (フォールバック) → 編集途中の機種にも対応
- **セッション復元時のフォールバック強化** (`SessionManager.handleLoadSession`): 旧スナップショット (libraryId なし) でも config 完全一致で確実に正しいライブラリエントリへ紐づくように
- **App.tsx に reactive subscribe を追加**: counter-store.machineConfig の変化を常時監視し、loadedLibraryId を自動再導出。これにより:
  - アプリ起動時の整合性チェック (IndexedDB 復元後に自動修正)
  - localStorage が消えた / 壊れた状態での起動でも自動回復
  - その他 setLoadedLibraryId を呼び忘れた経路があった場合の保険
- 結果: **`loadedLibraryId` の真実の出所は counter-store.machineConfig 1 個に集約され、ズレが構造的に発生し得なくなる**
- 該当: `src/ui/store/machine-library-store.ts` (helper export) + `src/ui/components/SessionManager.tsx` (fallback 強化) + `src/App.tsx` (subscribe 追加)

## [0.2.130] - 2026-05-04 (PC + PWA 同期)

### バグ修正: 機種選択 ↔ 機種編集の整合性をさらに堅牢化
- v0.2.129 で大きな不具合 (セッション復元後に編集画面が直前の機種を開く) を修正したが、徹底調査の結果、別の経路で同じ症状が出る可能性のあるエッジケースを発見し追加対応
- **修正対象のエッジケース**:
  1. 機種 A をロード中にライブラリの別機種 B の編集ボタンを押す
  2. B の編集をキャンセル (or 保存して閉じる)
  3. このとき内部状態の `editingLibraryId` が B のまま残る
  4. 直後に画面上部の「編集」ピル / メインメニュー → 機種編集 を開くと **B が表示される** (本来は現セッションの A が表示されるべき)
- **修正内容**:
  - **画面上部の「編集」ピル**: 参照元を `editingLibraryId` (transient) から `loadedLibraryId` (現セッションの機種) に変更。常に「今プレイ中の機種」を編集する挙動を保証
  - **エディタを閉じる時**: 必ず `editingLibraryId` を `loadedLibraryId` にリセット。次回エディタを開いた時のデフォルトが現セッションの機種に揃う
- 完了条件:
  - ✅ 全 8 パターンのエントリーポイント (セッション復元・機種選択・最近使った・連続切替・経路混在・新機種選択・アプリ再起動) で機種編集が常に正しい機種を表示
  - ✅ 別ライブラリを編集 → キャンセル/保存後の編集ピルが現セッションの機種を開く
  - ✅ 既存挙動 (ライブラリ行の編集ボタン、新規作成、保存時の現セッション反映) は全て無変更
- 該当: `src/ui/components/MachineSelector.tsx` の編集ピル onClick + MachineEditor の onClose wrapper

## [0.2.129] - 2026-05-04 (PC + PWA 同期)

### バグ修正: セッション復元後に機種編集画面が直前の別機種を開く不具合を修正
- 「メニュー → セッション」から保存済みセッション (機種 A) を選んで復元 → メインメニュー → 機種編集画面を開くと、**直前に編集した別の機種 B** の設定が表示されてしまう不具合を修正
- 原因: セッション復元時 (`handleLoadSession`) に **「現在ロード中のライブラリ機種 ID」(`loadedLibraryId`) が更新されていなかった**。MachineSelector の編集ピルや MainMenu の機種編集はこの ID を参照して開く機種を決定するため、前回の編集対象 (B) のままになっていた
- 修正:
  - **SessionSnapshot に `libraryId` フィールド追加** (v0.2.129+ で保存されるセッション)。セッション保存時の `loadedLibraryId` を一緒に記録
  - **セッション復元時に `loadedLibraryId` を反映**:
    1. snapshot に `libraryId` があればそれを採用
    2. なければ `machineName + manufacturer` 一致でライブラリを検索 (旧スナップショット用フォールバック)
    3. どちらもヒットしなければ null (ライブラリ外からの機種扱い)
  - **MachineSelector の `editingLibraryId` を `loadedLibraryId` と双方向同期** — useEffect で loadedLibraryId が変わるたびに editingLibraryId を追従させる。これにより MachineSelector 経由でない機種ロード (セッション復元・カタログ・ini 読み込み) でも編集ピルが正しい機種を開く
- 完了条件:
  - ✅ セッションで A 起動 → 編集画面 A 表示
  - ✅ 複数セッション切替もそれぞれ正しい機種が表示
  - ✅ 直前に開いた別機種 B が編集画面に残らない
- 該当: `src/ui/store/session-history-store.ts` + `src/ui/services/session-save.ts` + `src/ui/components/SessionManager.tsx` + `src/ui/components/MachineSelector.tsx`

## [0.2.128] - 2026-05-04 (PC + PWA 同期)

### バグ修正: ライブラリ編集ボタンが常に最後の機種を開いてしまう不具合を修正
- v0.2.127 でライブラリ機種ごとの編集を可能にしたが、別の機種の編集ボタンを連続で押すと **どれを押しても最後に開いた機種の設定** が表示されてしまう不具合があった
- 原因: `MachineEditor` の useState 初期値はマウント時に 1 度しか評価されないため、React が同じコンポーネントインスタンスを再利用すると前回の値が残ってしまう。条件付きレンダー (`{isEditorOpen && <MachineEditor>}`) でも、状態遷移によっては React が再マウントせずに props 更新だけで済ませる場合がある
- 修正: `MachineEditor` に `key={editingLibraryId ?? "__new"}` を付与。これにより libraryId が変わるたびに React が確実に **アンマウント → 再マウント** を行い、useState 初期値が新しい機種の config から再計算されるようになる
- 該当: `src/ui/components/MachineSelector.tsx` の `<MachineEditor>` レンダー部分

## [0.2.127] - 2026-05-04 (PC + PWA 同期)

### バグ修正: ライブラリ一覧の「編集」ボタンが空の新規作成画面を開いてしまう不具合を修正
- 「機種選択」モーダルのライブラリ一覧の各行にある **編集ボタン (鉛筆アイコン)** を押した時、本来はその機種の編集画面が開くべきところ、**現在のセッションの機種設定** (新規機種が読み込まれている場合は空の設定) が表示されてしまう不具合を修正
- 原因: MachineEditor が編集対象の config を `useCounterStore.machineConfig` (= 現在のセッションにロード中の機種) からのみ取得していた。`libraryId` で別の機種を指定しても、表示する初期値は現セッションの設定のままだった
- 修正:
  - `MachineEditor` の編集対象 config 決定ロジックを変更: `libraryId` 指定時はライブラリストアからその機種を引いて使用、未指定時は従来通り counterStore を使用
  - 保存時の挙動も合わせて修正: 別のライブラリ機種を編集中の場合は **現セッションに反映しない** (ライブラリだけ更新)。現セッションの機種を編集中の場合のみ `applyMachineConfig` で反映 (従来の挙動)
- これにより、プレイ中の機種を変えずに別のライブラリ機種の設定だけを編集できるようになる
- 該当: `src/ui/components/MachineEditor.tsx` の `current` 派生ロジック + `handleSaveToLibrary`

## [0.2.126] - 2026-05-04 (PC + PWA 同期)

### UX 改善: 機種設定エディタの数値入力欄を自然に編集できるように
- 「機種情報」画面の数値入力欄 (パルス/ゲーム、間合 ms、小役回数、ART 終了ゲーム数、SBB 閾値など 11 箇所) で、「20 → 5」に変更しようとして 20 を全削除しようとすると「2」で止まる、空欄にできない、勝手に補正される、といった操作性の悪さを修正
- 原因: `Number(e.target.value) || 3` で空文字 → 3 に即座に戻り、`Math.max(1, ...)` で入力途中の値を強制補正していた
- 修正:
  - 既存の `RenchanRangeInput` を **`NumberField` 共通コンポーネントに汎用化** し、全 11 箇所で利用
  - 編集中は **string で保持し空欄も一時許容**
  - **フォーカス時に既存値を全選択** (タップで「20」全選択 → 「5」入力で置換可能)
  - **onBlur で検証**: 空欄/0/負数/min 未満 → fallback または直前値に戻す、範囲外 → min/max にクランプ
  - **「0」は最終値として保存できない** (min: 1 強制)
- iOS Bluefy のキーボード表示時の画面崩れも併せて修正:
  - 原因: `.editor-number-input { font-size: 12px }` が **iOS Safari の自動ズームをトリガー** していた (16px 未満の input にフォーカスすると自動でビューポート拡大)
  - 修正: `@media (hover: none) and (pointer: coarse)` でタッチ端末のみ font-size を 16px に拡大、PC は 12px のまま据え置き
- 影響:
  - PC Electron: 入力体験が改善 (フォーカス時全選択)、見た目変化なし (12px のまま)
  - Android PWA: 入力体験が改善、入力欄が少しだけ大きくなる (タップしやすくなる)
  - iOS Bluefy: 入力体験が改善 + **キーボード表示時の画面崩れが解消**
- 該当: `src/ui/components/MachineEditor.tsx` の `NumberField` + `src/ui/styles/machine-selector.css` の `.editor-number-input`

## [0.2.125] - 2026-05-04 (PC + PWA + admin-server 同期)

### UX 改善: 機種検索を全機種でひらがな↔漢字対応に (kuromoji.js 自動付与)
- v0.2.124 では「北斗」「拳」など 170 件の手動辞書で対応していたが、辞書未登録の漢字 (例: 「霹靂」) はヒットしなかった
- 修正: サーバー側 admin-server に **kuromoji.js (日本語形態素解析)** を組み込み、機種カタログ全件にひらがな読み (kana) を自動付与する仕組みを導入
- 仕組み:
  1. **admin-server**: 機種を保存するたびに kuromoji が `name` から自動でふりがなを生成し、catalog の `kana` フィールドに格納
  2. **クライアント**: 検索時にカタログの `kana` フィールドを優先利用 (古い辞書ベースもフォールバック維持)
  3. 既存 626 機種は backfill スクリプト (`backfill-machine-kana.ts`) で一括付与
- これにより **マイナーな機種・難読漢字も全て** ひらがな検索でヒットするように
- 管理者は機種を新規登録するときに **何もしなくてよい** (kana が自動生成される)。手動上書きしたい場合は `kana` フィールドに値を指定可能
- 該当:
  - サーバー: `admin-server/src/shared/kana-generator.ts` 新規 + `routes/admin.ts` の機種保存 3 箇所で auto-kana 統合
  - クライアント: `src/core/catalog/catalog-client.ts` の `CatalogEntry` に `kana?: string` 追加 + `MachineSelector.tsx` の `buildHay` がカタログ kana を優先利用
  - 一括付与: `admin-server/src/scripts/backfill-machine-kana.ts` 新規
- ※ kuromoji の精度は約 95%。固有名詞や当て字で読みを外すケースは将来 admin-ui に手動上書き UI を追加予定

## [0.2.124] - 2026-05-04 (PC + PWA 同期)

### UX 改善: 機種選択検索でひらがな・カタカナ・漢字を相互検索可能に
- 「機種選択」画面の検索窓で、これまで「北斗」(漢字) ではヒットするが「ほくと」(ひらがな) や「ホクト」(カタカナ) では 0 件だった不具合を改善
- 原因: 検索処理がカタカナ↔ひらがなの相互変換のみで、漢字の読みを扱う仕組みが無かった
- 修正: 60+ 件の漢字熟語の読み辞書 `kanji-kana-aliases.ts` を新規追加し、検索 hay 構築時に漢字 → ひらがな読みを補完する仕組みを導入。これにより「北斗」「ほくと」「ホクト」のすべてで同じ機種にヒットするように
- 対応する漢字: 北斗・拳・戦国・乙女・侍・押忍・番長・聖闘士・星矢・魔法少女・進撃・巨人・暗殺・教室・黄門・麻雀・物語 など、パチンコ・パチスロでよく使われる単語を中心に
- 影響範囲: 保存済み機種・サーバーカタログ機種・組込み機種すべて (`buildHay` 関数経由なので自動的に統一)
- 該当: `src/ui/machines/kanji-kana-aliases.ts` 新規 + `src/ui/components/MachineSelector.tsx` の `buildHay` を更新
- ※ サーバーカタログに `kana` フィールドを追加する完全網羅は次フェーズ予定 (kuromoji.js での一括ふりがな付与等)

## [0.2.123] - 2026-05-04 (iOS のみ修正)

### バグ修正: iOS 版で機種名・メーカー再編集時に既存値が消える不具合を解消
- 「機種選択」→「新規作成」→「機種情報 (スロット)」で、iPhone Bluefy 等の iOS 版だけ「機種名」「メーカー」を **再タップした時に入力欄が空欄表示** になる不具合を修正
- 原因: iOS Safari / Bluefy の `window.prompt(message, defaultValue)` は **第二引数の defaultValue を初期値表示しない既知 OS 仕様** がある。空欄のまま OK を押すと値が消えてしまう
- 修正: iOS も Electron と同じく `TextInputDialog` (React モーダル) 経路に切替。`detectPlatform()` の `isIOS` で判定
- Android PWA は引き続き `window.prompt()` を使用 (Android Chrome のテキスト長押しドラッグバグ対策、v0.2.66 の経緯)。iOS には同バグがないので影響なし
- 該当: `src/ui/components/MachineEditor.tsx` の `BasicTab` 内 `useNativeModal = isElectron || platform.isIOS`

## [0.2.122] - 2026-05-04 (PC のみ修正)

### バグ修正: PC 版で機種名・メーカーが入力できない不具合を解消
- 「機種選択」→「新規作成」→「機種情報 (スロット)」画面で、PC Electron 版だけ「機種名」「メーカー」をクリックしても文字入力できない不具合を修正
- 原因: 入力時に `window.prompt()` を使う設計だったが、**Electron は `window.prompt()` を実装していない** ためダイアログが開かず無反応に。Android PWA / iOS Bluefy ではブラウザが prompt を実装しているので動いていた
- 修正: `MachineEditor.tsx` に Electron 検知 (`window.counter` 存在確認) を追加し、Electron のみ `TextInputDialog` (React モーダル) に切替。Android / iOS は引き続き `window.prompt()` を使用 (テキスト長押しドラッグバグ対策のため変更しない、v0.2.85-89 の教訓)
- これにより PC / Android / iOS のすべてのプラットフォームで機種名・メーカー入力が可能になる
- 該当: `src/ui/components/MachineEditor.tsx` の `BasicTab` 関数 (`editMachineName` / `editManufacturer` を Electron 検知で分岐)

## [0.2.121] - 2026-05-04 (PC + PWA 同期)

### UX 改善: ボーナス履歴グラフでスマホ縦画面でも差枚数を表示
- スマホ縦画面 (履歴グラフのカード幅 ≤ 480px) では、これまで各バーの差枚数 (`-2.4k` 等) が非表示になっていたのを、**短縮形で常時表示** するように変更
- 旧仕様: タップで詳細パネルを開かないと差枚が見えなかった
- 新仕様: バー上部に「ゲーム数 (黄)」+「差枚数 (赤/緑)」が 2 段で常時表示
- フォントサイズを微調整 (回転数 10→9px、差枚 9→8px、letter-spacing -0.4px) して縦スペース内に収納
- バー本体の高さは約 14px 短くなるが、`-2.4k` で各履歴の勝ち負けが一目で把握可能に
- PC・モバイル横画面など広いカード幅 (> 480px) の表示は従来通り変化なし
- 該当: `src/ui/styles/counter.css` の `@container bhv4 (max-width: 480px)` 規則と
  `src/ui/components/EqBarChart.tsx` の ResizeObserver 内 reserved 計算

## [0.2.120] - 2026-05-04 (PC + PWA 同期)

### レイアウト調整 (全画面共通)
- **「ART確率 ↔ SBB確率」「ART ↔ SBB」「ART枚 ↔ SBB枚」のカード位置を入れ替え (PC + モバイル縦 + モバイル横)**
  - 旧: `[ART...] [BB...] [RB...] [SBB...]`
  - 新: `[SBB...] [BB...] [RB...] [ART...]`
  - 確率カード行・mid 行 (ボーナス回数)・medal 行 (獲得枚数) の 3 系統すべて統一
  - 該当: `src/ui/dashboard/card-registry.ts` の
    `DEFAULT_PC_LAYOUT` / `DEFAULT_MOBILE_LAYOUT` / `DEFAULT_MOBILE_LANDSCAPE_LAYOUT`
- **横画面では獲得枚数カード (medal) を非表示チップから除外** — 横画面のグリッドが
  y=0..9 まで埋まっており、medal の y=10 デフォルト位置が画面外になるため、編集
  モードで「非表示カード」リストにも表示しない (ユーザーが「クリックしても出ない」
  混乱を予防)。「非表示カードなし (横画面では獲得枚数カードは非対応)」の注記表示
- **layout-store version v11 → v15 マイグレーション** で既存ユーザーも新レイアウトに
  自動切替 (途中段階 v12〜v14 を経て最終 v15、reset 動作で全カード位置がデフォルトに戻る)
- ※ このアップデートでカスタム配置はリセットされる旨をランディング側でも告知済

## [0.2.118] - 2026-05-04 (PC + PWA 同期)

### バグ修正: 信号ログ「更新停止中」+「BLE 受信中」での全削除が反映されない事象を解消（v0.2.117 の追加修正）
- v0.2.117 で「rawGames が空のときは throttle を迂回」する分岐を入れたが、**BLE 受信中は全削除直後に新ゲームが即時 re-populate される**ため、`rawGames.length === 0` の窓が microsecond しか開かず修正が効かないケースが残っていた
- 修正: `useThrottledValue` のフック内 state に依存していた構造をやめ、SignalLogModal が直接 `snapshot` state を持つ形に書き換え。`handleClear` で `setSnapshot([])` と `setExpandedId(null)` を明示的に呼ぶことで、BLE が即時に新ゲームを作っても **表示用スナップショットは凍結状態のまま空** で居続ける（「表示再開」を押すまで新しいゲームは画面に出ない）
- 表示中（live）状態の挙動は従来通り 300ms throttle で追従

## [0.2.117] - 2026-05-04 (PC + PWA 同期)

### バグ修正: 信号ログ「更新停止中」での全削除が即時反映されない事象を解消
- 信号ログ画面が「更新停止中」状態のときに「全削除」ボタンを押しても、画面から行が消えない事象を修正
- 原因: `useThrottledValue` が `paused=true` の間は内部 throttled state を一切更新せず固定する設計のため、store の rawGames が `[]` にクリアされても UI は古いスナップショットを表示し続けていた
- 修正: SignalLogModal で「rawGames が空配列のときは throttle を迂回して即時反映する」分岐を追加。クリアは明示的なユーザー操作なので paused であっても即時反映する仕様に
- 表示中状態（paused=false）では従来通り即時消去。今回はその挙動が更新停止中でも一致するように揃えた形

## [0.2.116] - 2026-05-04 (PC + PWA 同期)

### UX 改善: 信号ログを「初期状態は更新停止」に変更
- 信号ログ画面を開いた瞬間は **更新停止状態** で開くようになりました
  - 開いた時点の最新スナップショットがそのまま表示されるので、過去のログを落ち着いて閲覧できます
  - 旧来は開いた瞬間からライブ更新で、行が押し下がる・スクロール位置が崩れる・タップ展開中に内容が変わるといった閲覧の妨げになっていました
  - 「**▶ 表示再開**」ボタン（橙色 + ブリンク）を能動的に押すとライブ更新が始まり、再度押すと止まります
  - タイトル横にも「**/ 更新停止中**」ラベルを表示（橙色 + ブリンク）して、なぜ値が動かないかが直感的に伝わるように
  - モーダルを閉じて再度開くと、また停止状態から始まります（永続化なし、開く＝閲覧目的と仮定）

## [0.2.115] - 2026-05-04 (PWA のみ)

### バグ修正: 信号ログの行重複（iPhone Bluefy / Android）を解消
- iPhone Bluefy / Android PWA で、信号ログの同じ G# が 2 行表示される事象を修正
  - 原因: signal-log-runtime の Phase 1 awaiting 分岐で `last.endTs = ev.ts` の **in-place mutation** を行っていたため、engine と signal-log-store が同じ renderer に同居している環境では、store 側の既存エントリ（同じ参照）も書き換わり、applyPatch の `endTs == null` 判定が false → push 経路に倒れて重複していました
  - 修正: `{ ...last, endTs: ev.ts }` の spread コピーに変更して既存参照を不変に
  - Electron は IPC シリアライズで自動クローンされるため影響なし（renderer-local モード固有のバグ）

## [0.2.114] - 2026-05-04 (PWA のみ)

### バグ修正: 省電力モード ON 時の信号ログ取りこぼしを解消
- iPhone Bluefy + 省電力モード ON で発生していた以下の症状を修正：
  - 「進行中」表示が大量に残り続ける
  - IN が 1 や 2 のまま（本来は必ず 3）
  - 同じ G# が複数行で表示される
- 原因: 省電力 throttle (100ms) 中に複数の signalLogPatch が届くと、`pendingPayload = payload` で **最後の 1 つだけ残して他を破棄** していたため、`closedGames` を含む patch が消えて store に届かず、過去ゲームの締め処理が永久に走らない状態に
- 修正: pendingPatch に **closedGames は concat、inProgressUpdate は最新のみ、evicted は加算** で集約する形に書き直し、各 patch を確実に届けるように

## [0.2.113] - 2026-05-04 (PC + PWA 同期)

### 仕様修正: 「最大獲得 / 最低獲得」→「最高差枚 / 最低差枚」
- お客様からの「ボーナス1回あたりの最大／最低獲得枚数を表示しているのでは？」という指摘を受け、表示ラベルとデータソースを刷新
- **新仕様**:
  - **最高差枚**: 当日累計差枚の **最高到達値**（一番出ていた瞬間）— ボーナスでピーク更新後、減ってもその値を保持
  - **最低差枚**: 当日累計差枚の **最低到達値**（一番ヘコんだ瞬間）— ハマってボトム更新後、回復してもその値を保持
  - スランプグラフ用の累計差枚データ (`slumpPoints[].y`) + 現在差枚から min/max を算出
  - 符号付き表示: 「+1234」「-50」のように差枚プラス／マイナスが一目で判別
- **CSV エクスポート** の列名・データソースも同期（「最高差枚 / 最低差枚」+ 負数赤字判定対象に追加）
- **per-bonus の内部値（ボーナス1回ごとの獲得枚数）はエンジン内部に温存**（ranking 等の互換のため）

## [0.2.112] - 2026-05-04 (PC + PWA 同期)

### バグ修正: 「総回転」がボーナス当選でリセットされる事象を解消
- お客様からの「総回転がボーナスでリセットされている」という指摘を受け修正
- **新仕様**:
  - **総回転**: 当日累計の **通常時回転数**（ボーナス中は加算停止、ボーナス終了でも **リセットされない**）
  - **ゲーム数** カードは引き続き「現在のハマリ G 数」表示として機能（= ボーナス毎リセット）
  - **純回転** カードは不変（ボーナス中含む全 +1）
- データソースを `engine.counts.totalRotations`（リセットあり）から `engine.counts.sessionRotations`（リセットなし）に切替（mirrorFromEngine の 1 行修正）
- ranking export / SessionManager 等の集計値も自動的により意味のある「日累計の非ボーナス回転数」に切り替わります

## [0.2.111] - 2026-05-03 (PC + PWA 同期)

### 新機能: 省電力モード (iPhone Bluefy 発熱対策)
- **「⚡ 省電力モード」をテーマパネル最上段に追加**
  - ON のとき同時に有効化:
    - engine notify を **100ms throttle** (UI 更新を 33fps → 10fps に間引き、
      engine 内部は 30ms ピッチで処理継続なので信号取りこぼし無し)
    - イルミネーション (枠の虹色アニメーション) 停止 (GPU 削減)
    - ボーナスカード発光エフェクト (パルス + シマー) 停止 (GPU 削減)
    - ヒントパルス停止 (微小な GPU 削減)
  - 静的な色付きボーダーは残るので、ボーナス中の判別は維持
- **iPhone (Bluefy) では既定で ON、Android / PC では既定 OFF**
  - User Agent から iOS 検出 (`platform-detect.ts` 流用)
  - 既存ユーザーも v9→v10 マイグレーションで iOS なら自動 ON 適用
- 背景: iPhone Bluefy で BLE 30ms notify を捌くと WKWebView の CPU/GPU が常時
  100% 近くで本体が発熱する事象への対策。Android Chrome (Blink + V8) は同じ
  コードでも余裕で捌けるため発熱しない。Android ユーザーが ON にすれば
  バッテリー長持ち効果が得られる

### 関連実装
- `src/ui/theme/theme-store.ts`: `lowPowerMode` フィールド + setter +
  v9→v10 マイグレーション (iOS 検出結果を初期値に)
- `src/ui/store/counter-store.ts`: engine subscribe コールバックを条件分岐 —
  lowPowerMode ON のとき 100ms throttle (setTimeout で集約)
- `src/ui/components/IlluminationController.tsx`: `body.low-power-mode` クラス連動
- `src/ui/styles/counter.css`: `body.low-power-mode` スコープでアニメーション停止 +
  色付きボーダーのみ静的に残すルール
- `src/ui/components/ThemePanel.tsx`: 最上段に⚡省電力モードトグル追加
  (シアン左ボーダー + ⚡アイコンで目立たせる)

## [0.2.110] - 2026-05-03 (PC + PWA 同期)

### バグ修正
- **Android 横画面差円カードの単価セレクター位置を card 自体にアンカー (高さチェーン迂回)**
  - v0.2.109 で selector を `.diff-card-body` (position: relative) にアンカーした
    が、Android Chrome で body 自身の `height: 100%` が機能せず content-fit に
    縮み、結果 selector が金額に重なってしまった
  - **v0.2.110**: `.diff-card-body` も `position: static` にして、selector を
    一段外側の **`.dashboard-diff-card` (= `.card`)** にアンカー。card は
    `.dashboard-cell .card { height: 100%; position: relative }` で確実に
    cell 全高を持つため、card 下端からの距離 (bottom: 6px) で selector が
    確実に下端配置される。**内側の高さ計算チェーンを完全に迂回** する設計

## [0.2.109] - 2026-05-03 (PC + PWA 同期)

### バグ修正
- **Android 横画面差円カードの単価セレクター下端配置を最終修正**
  - v0.2.107〜108 で試した grid 1fr auto + flex: 1 のアプローチは、Android Chrome
    の高さ計算挙動差で grid container が content-fit に縮み、selector が金額直下に
    貼り付く事象が継続していた
  - **戦略変更**: `.coin-yen-display` を `position: static` にして、selector が
    grand-parent の `.diff-card-body` (base で `position: relative` を持つ) を
    絶対配置の基準にするように変更。body は外側 flex 親 (.dashboard-diff-card の
    row + align-items: stretch) で確実に card 全高に伸びているため、selector の
    `bottom: 6px` は card 下端からの距離になる。**grid/flex の高さチェーンに
    依存しない** ため Android Chrome の挙動差を回避できる

## [0.2.108] - 2026-05-03 (PC + PWA 同期)

### バグ修正
- **Android 横画面で差円カードの単価セレクターがカード下端に届かない問題を再修正**
  - v0.2.107 で grid 1fr auto を入れたが、Android Chrome では `.coin-yen-display`
    自身の height: 100% が機能せず grid container が content-fit に縮小、結果
    selector が金額直下のままだった
  - 対策: `.coin-yen-display` に `flex: 1; align-self: stretch; min-height: 0` を
    追加。親 `.diff-card-body` の column flex の main 軸 (縦) を強制的に埋め、
    grid container に definite height を確保
- **ボーナス履歴グラフのカードタイトルを「ボーナス履歴（獲得枚数）」→「ボーナス履歴」に修正**
  - v0.2.99 で 5 段構成 v4 に切替えた際、バーが表す値は「獲得枚数」ではなく
    「回転数 (ハマリ数)」になっていたが、タイトルが旧文言「獲得枚数」のままで
    Y 軸ラベル「0/500/1k」と意味が食い違っていた
  - 副題を削除して「ボーナス履歴」のみに統一 (シンプルでカード幅にも収まる)
  - 該当箇所: `src/ui/dashboard/renderCard.tsx` (PC / モバイル横画面用) と
    `src/ui/views/MobilePage2.tsx` (モバイル縦 Page 2)

## [0.2.107] - 2026-05-03 (PC + PWA 同期)

### バグ修正
- **Android で横画面差円カードの密着問題が再発していたのを修正**
  - 旧: `.coin-unit-selector` を `position: absolute; bottom: ...` で配置していたが、
    Android Chrome 固有の flex 高さ伝播挙動 (`.diff-card-body` / `.coin-yen-display`
    の `height: 100%` が一部端末で 0 と評価される) で selector が金額直下に
    貼り付いていた (iOS Bluefy では正常)
  - 新: 横画面のみ `.coin-yen-display` を **CSS Grid** (`grid-template-rows: 1fr auto`)
    に切替え、`.coin-yen-amount` を 1fr セルに、`.coin-unit-selector` を auto セルに
    自動配置。親高さに依存しないため Android でも確実に selector がカード下端に貼り付く

## [0.2.106] - 2026-05-03 (PC + PWA 同期)

### バグ修正
- **ボーナス履歴グラフのバー高さが Y 軸ラベル (0/500/1k) と一致しない問題を修正**
  - 旧: `1G = 0.1px` 固定スケールで、カードが縦長 (例: 600px) のとき
    1000G でも 100px しか伸びず、Y 軸ラベル「1k」(上端) には到達しなかった
    (例: 525G のバーがチャート全体の 8% しか伸びない、ラベル 500 線に届かない)
  - 新: 動的スケール `pxPerG = barHeight / 1000` で「**1000G = 全高**」「500G =
    半分」「0G = 0」を保証。Y 軸ラベルとバー実数が完全に一致
  - メモリ目盛り (.bhv4-bar::after) も 10px 固定 → **10% 区切り** に変更し、
    「1 メモリ = 100G」の意味は維持しつつカードサイズに連動
- **横画面差円カードで金額と単価セレクターが密着する問題を修正 (v0.2.104〜105 持ち越し)**
  - 真の原因: `.dashboard-diff-card` の `align-items: center` が
    `.diff-card-body` を content-fit 高さに縮め、内側 `.coin-yen-display`
    の `height: 100%` + 絶対配置設計を壊していた
  - 対策: `align-items: stretch` (default) に変更し、ラベルだけ
    `align-self: center` で個別中央寄せ。これで body がカード全高に伸び、
    selector がカード下端ピッタリに配置される

## [0.2.105] - 2026-05-03 (PC + PWA 同期)

### バグ修正
- **スマホ横画面で差円カードの金額と単価セレクター (5/10/20/1000) が縦に密着する問題を修正**
  - 原因: v0.2.104 で `.diff-card-body` に追加した `display: flex; flex-direction:
    column; justify-content: center` が、内側 `.coin-yen-display` の `height: 100%`
    + 絶対配置設計を壊し、selector が金額直下に貼り付いていた
  - 対策: 該当の flex 指定を撤回し、元の block レイアウトに戻す。`.coin-yen-display`
    が再びカード全高を取り、`.coin-unit-selector` が `position: absolute; bottom`
    でカード下端ピッタリに配置される (元の設計)

## [0.2.104] - 2026-05-03 (PC + PWA 同期)

### バグ修正
- **スマホ横画面で差枚カードのラベル「差円 / 差枚」が見切れる問題を修正**
  - 旧: column 配置 (ラベル上 + 金額下) で、横画面の浅い高さに対し
    cqh ベースの font-size が大きく出てラベル右端が見切れる事例があった
  - 新: 横画面のみ row 配置に切替 (ラベル左 + 金額右)、letter-spacing: 0 +
    `max-width: 3em` でラベル幅をコンパクト化
- スコープ: `.app-mode-mobileLandscape` および `.view-stack-mobile-landscape`
  のみ。PC・スマホ縦は従来通り

## [0.2.103] - 2026-05-03 (PC + PWA 同期)

### UI 改善
- **連チャン数ラベル「N連」の文字を白色 + ダークネイビー縁取りに変更**
  - 旧: 黒文字 (`#001015`) — シアン背景の濃淡で読みにくい箇所があった
  - 新: 白文字 (`#ffffff`) + 4 方向ダークネイビー縁取り (`#001a26`) +
    軽いダークシャドウ。シアンゲージ全域でくっきり読める

## [0.2.102] - 2026-05-03 (PC + PWA 同期)

### Bluetooth 接続トラブルシュート改善 (お問い合わせ対応)
- **Android 9〜11 ユーザー向けに「位置情報サービス ON」案内を追加**
  - User Agent から Android バージョンを検出 (`platform-detect.ts` 新設)
  - Android 11 以下では BLE スキャンに位置情報サービスが必須なのに、エラー文言が
    「付近のデバイス」(Android 12+ の権限名) しか案内していなかった
  - NotFoundError 時に Android バージョンに応じた最優先案内に切替
- **BlePanel に「動作確認済 Bluetooth 受信機」セクションを追加**
  - 「A-COUNTER 通信アンテナ2 (ABBTM2)」を明記
  - 旧モデル「通信アンテナ1」は本アプリで未対応であることを明示し、
    お客様の期待値ミスマッチを防止
- 注: 通信アンテナ1 への対応は仕様 (BLE / Classic SPP の判別) 確認後に別途検討

## [0.2.101] - 2026-05-03 (PC + PWA 同期)

### バグ修正
- **スマホ横画面でボーナス履歴グラフの下部 (種別ピル + 連荘ゲージ) が見切れる問題を修正**
  - 原因: v0.2.99 で 5 段構成にしたボーナス履歴 v4 が、スマホ横画面の dashboard
    レイアウト (h=3 ≈ 120px) に収まりきらず、下 2 行が枠外に押し出されていた
  - 対策 1: 横画面の `graph.history` / `graph.slump` を `h: 3 → h: 5` に拡大
    (合計行数 8 → 10、動的 rowHeight が 1 行 ≈ 32px に自動調整される)
  - 対策 2: `EqBarChart` の reserved 計算をコンテナ幅で分岐 — 狭い (≤480px) では
    container query で差枚行が非表示になる分の縦余白 (95px → 80px) をバーに回す
  - 対策 3: `layout-store` のマイグレーションバージョンを v10 → v11 に bump し、
    既存ユーザーの mobileLandscape レイアウトを新しいデフォルトに移行
- 注意: 上記マイグレーションは PC / モバイル縦含む全レイアウトをデフォルトに
  リセットします (既存パターン踏襲)。カスタム配置していた場合は再設定が必要です

## [0.2.100] - 2026-05-03 (PC + PWA 同期)

### バグ修正
- **ボーナス履歴 v4 で左右スワイプによる過去履歴表示が動かない問題を修正**
  - 原因: v4 リニューアル時に旧 v3 EqBarChart の `overflow-x: auto` を引き継がず、
    モバイルなど狭い画面で 20 列が画面外にはみ出した分が見られなかった
  - 対策 1: 4 段 (バー / 履歴番号 / 種別 / 連荘ゲージ) を `.bhv4-scroll` ラッパーで
    包んで同期スクロール (旧 v3 同等の `overflow-x: auto` + 慣性 + スクロールバー非表示)
  - 対策 2: 連荘ゲージ行は absolute 子要素のみで自身の幅が決まらないため
    `min-width: 640px` (20 列 × 28px + gaps + padding) を明示してバー行と幅を揃える

## [0.2.99] - 2026-05-03 (PC + PWA 同期)

### 大型新機能: ボーナス履歴グラフ v4 (5 段構成 + タップ詳細)
- **5 段の縦並び表示** (上から: 回転数 / バー / 履歴番号 / ボーナス種別 / 連荘ゲージ)
- **並び順を反転** — 左 = 現在 (進行中)、右 = 過去 (旧 v3 は逆順だった)
- **ハマり度信号機グラデーション** — バーの上方向ほど赤くなる:
  - 0G: 深シアン (安全) → 200G: シアン → 500G: 黄 → 750G: 橙 → 1000G+: 濃赤 (危険)
  - 長いバー (= 深ハマり) ほど赤系が顔を出し、視覚的に「ハマり度」が一目で分かる
- **履歴番号** — 「現在 / 1 / 2 / 3 / ...」で何回前のサイクルか明示。「現在」は金色背景で強調
- **ボーナス種別ピル** — テーマ色 (BB=黄 / RB=橙 / ART=緑 / SBB=紫) でカラー枠線
- **連荘ゲージ** — `renchan.rangeGames` (既定 100G) 以内に次のボーナスが来た連続セットを
  ブランドシアン (ロゴ同色) のゲージで「N連」表示。単発は薄グレーで「1」表示
- **タップ詳細パネル**
  - PC: ホバー / クリックでポップオーバー (Portal で body 直下、フレーム端に画面端 clamp)
  - モバイル / iPhone Bluefy: タップで画面下からボトムシート
  - 内容: 種別 / 回転数 (深ハマりは橙ハイライト) / 差枚 (符号付き色分け) /
    差円 (機種単価から計算) / 連荘ポジション (「3連目 / 計5連」) / 当選時刻
- **レスポンシブ対応** (Container Query)
  - 幅 ≥ 720px: フル表示 (BB / RB / ART / SBB / +1,250)
  - 480〜720px: 差枚短縮形 (+1.2k)
  - ≤ 480px: 差枚非表示 (タップ詳細に逃がす) + 種別を頭文字 (B/R/A/S/現)
- **engine 側でスナップショット保存** — `handleBonusStart` で `diffMedalsAtBonus` /
  `bonusAtTimestamp` を `HistoryCycle` に保存するロジックを追加 (Electron + PWA 共通)

### 新機能: イルミネーション演出設定 (テーマ設定に追加)
- **ボーナス中の枠イルミネーション高速化** — 通常 6 秒/周 → ボーナス進行中 2.5 秒/周。
  CSS 変数 `--illum-speed` + `body.bonus-active` で自動切替
- **枠イルミネーション ON/OFF トグル** — テーマ設定で枠の虹色装飾を完全 OFF にできる。
  シンプルな黒枠のみの見た目に切替可能
- **ボーナスカード発光エフェクト ON/OFF トグル** — パルス + シマー演出を停止できる。
  OFF 時も色付きの静的ボーダー + 弱い glow は残るので、ボーナス中の判別は維持
- すべて `theme-store` の persist 機構で localStorage 保存 (v8→v9 マイグレーション)

## [0.2.98] - 2026-05-02 (PC + PWA 同期)

### 削除
- **「すべてのデバイスを表示」ボタンを削除** (v0.2.96 で追加した機能の撤回)
  - 動作確認の結果、各環境で実用的に機能しないことが判明:
    - PC Electron: チューザー UI なしで `devices[0]` を勝手に掴み、ABBTM2
      以外の BLE 機器 (プリンタ等) が周辺にあると誤接続して失敗する
    - Android Chrome: `acceptAllDevices: true` は周辺の全 BLE アドバタイズを
      「不明またはサポートされていないデバイス」として大量に列挙し、ユーザーが
      ABBTM2 を識別できない
    - iOS Bluefy: 同様に識別困難
  - 接続失敗時の自己解決は v0.2.96 で追加したエラー時チェックリスト
    (権限 / 電源 / 距離 / モード) で十分カバーできるため、フォールバックを撤回
- 関連コード削除: `connectBleDeviceShowAll()` (ble-client) /
  `connectShowAll` アクション (useBleBridge) / フォールバックボタン (BlePanel) /
  formatBleError 内の関連文言

## [0.2.97] - 2026-05-02 (PC + PWA 同期)

### バグ修正・UX 改善 (Bluetooth 接続パネル)
- **PC 版で接続失敗時に「接続中…」のまま固まる問題を修正**
  - 原因 (PC Electron): `select-bluetooth-device` で device が見つからない場合、
    callback を呼ばないため renderer の `requestDevice()` が永久 pending になり、
    `connecting=true` のまま UI が反応しなくなっていた
  - 原因 (iOS Bluefy): チューザー UI が放置された場合に同様にハングする
  - 対策 1 (renderer): `connect()` / `connectShowAll()` を 15 秒タイムアウトで
    `Promise.race`、期限切れ時に「接続がタイムアウトしました」+ チェックリスト表示
  - 対策 2 (Electron main): `select-bluetooth-device` 初回イベントから 15 秒
    タイマーを起動し、期限切れで `callback("")` を呼んで OS スキャンを打ち切り
  - 対策 3 (世代カウンタ): キャンセル後に遅延解決した接続ハンドルを破棄
- **「キャンセル」ボタンを追加** — 接続中 (`connecting=true`) に表示され、
  ユーザー操作で即座に未接続状態へ戻せる
- **失敗状態の文言を統一**
  - 対応デバイスが見つかりませんでした (NotFoundError)
  - 接続がタイムアウトしました (15 秒経過)
  - 接続をキャンセルしました (キャンセルボタン押下)
  - Bluetooth の使用が許可されていません (SecurityError / NotAllowedError)
  - Bluetooth に対応していない環境です (NotSupportedError)
- **失敗後の「接続」ボタンを「再接続」表記に変更** — `lastError` あり時は
  リトライ動作であることを明示
- 全レイアウト (PC / Android / iPhone / モバイル / 横画面) で同一の `BlePanel`
  コンポーネントを使用しているため、表記・状態遷移が自動的に揃う

## [0.2.96] - 2026-05-02 (PC + PWA 同期)

### バグ修正・UX 改善
- **Bluetooth「対応デバイスが見つかりません」エラーの自己解決を支援**
  - 原因: 接続失敗時のエラー文が `NotFoundError` のような技術名のままで、
    ユーザーが何を確認すれば良いか分からず問い合わせに繋がっていた
  - 対策 1: エラー時に複数行のチェックリストを表示
    (電源 / BLE モード / 他端末との競合 / Android 付近のデバイス権限 / 距離)
  - 対策 2: 「すべてのデバイスを表示」フォールバックボタンを追加
    - 通常の filter (namePrefix "ABB" / service UUID) で見つからない時の最終手段
    - `acceptAllDevices: true` で全 BLE デバイスを表示し手動選択可能
    - デバッグ用途も兼ねる (リストに出れば OS スキャンは動作中の確認)
  - 対策 3: モーダル下部の補足文に「すべてのデバイスを表示」の案内を追加

## [0.2.95] - 2026-05-02 (PC + PWA 同期)

### バグ修正
- **スマホ横画面で画像トリミングダイアログのキャンセル/確定ボタンが押せない問題を修正**
  - 原因: 画像プレビュー (max-height: 60vh) + ヘッダー + フッター合計が
    landscape の小さい viewport (~360-400px 高) を超え、フッターが画面外にはみ出していた
  - 対策 1: cropper-modal に `overflow: hidden` + workspace を `flex: 1; overflow: auto`
    にしてフッターを常時画面内に固定、画像エリアだけスクロールさせる
  - 対策 2: 横画面 + 高さ ≤ 500px 用の media query で画像 maxHeight を 45vh に圧縮 +
    補助ヒント文を非表示にしてコンパクト化

## [0.2.94] - 2026-05-02 (PC + PWA + admin 同期)

### 新機能
- **メインメニューに「運営元 A-SLOT」セクションを追加**
  - 区切り線 + セクション見出しでアプリ機能と視覚的に分離
  - 4 リンク: A-SLOT 公式サイト / デジカウンター・A-IO 2.0 / 通信アンテナ2 / FT245RL 対応版
  - すべて UTM 付き (utm_source=acounter-x&utm_medium=in-app&utm_campaign=main-menu)
  - 押し売り感を出さないため控えめなトーン (グレー基調、ホバー時のみゴールド)
- **外部リンククリックのアプリ側計測を追加**
  - `trackOutboundClick(target)` ヘルパーで `/api/public/pwa-event` へ送信
  - PC Electron も含めて計測可能 (絶対 URL + CORS 対応)
  - 管理画面に「外部リンククリック (ターゲット別)」セクション追加

## [0.2.93] - 2026-05-02 (PC + PWA + admin 同期)

### 新機能 (管理画面 — Phase 2/3)
- **アクティブユーザー (DAU/WAU/MAU) 計測を追加** (Phase 3)
  - クライアント: PWA 起動毎に `open` heartbeat を送信、デバイス毎 1 日 1 回で de-dup
    (localStorage に最終送信日を保存)
  - サーバー: `pwa-open` 種別を新設し、ユニーク IP ベースで「今日 / 7 日 / 30 日」の
    アクティブ数を集計
- **iOS バージョン分布の可視化** (Phase 2)
  - PWA イベントの UA から iOS メジャーバージョン (例: "iPhone OS 18_5" → "18") を抽出
  - 管理画面に「iOS バージョン分布」テーブル追加
- **端末 × アプリバージョン マトリクス** (Phase 2)
  - どの端末がどのアプリバージョンを使っているかの分布表
- **日 × 端末 時系列 (直近 30 日)** (Phase 2)
  - 日付別に各端末の PWA イベント発生件数を表示

## [0.2.92] - 2026-05-02 (PC + PWA + admin 同期)

### 新機能 (管理画面)
- **PWA イベントの端末別集計を追加**
  - クライアント側: PWA インストール / 初回訪問の送信ペイロードに `device` を追加。
    UA + `navigator.bluetooth` の有無で `ios-bluefy` / `ios-other` / `android` /
    `desktop` / `other` を判定
  - サーバー側 (`admin-server`): 受信した `device` を `downloads.jsonl` に保存、
    `summarizeDownloads` に `byDevice` 集計を追加
  - 管理画面 (`admin-ui`): ダウンロード統計ページに「PWA 端末別内訳」セクション追加
    (iPhone/Bluefy 経由の利用者数を可視化)
  - v0.2.91 以前のレコードは「不明 (旧レコード)」バケットに集計

## [0.2.91] - 2026-05-02 (PC + PWA 同期)

### バグ修正 (Android PWA)
- **差枚カード内タップ時に中央数字の周りに青い枠線が出る問題を更に追加対策**
  - v0.2.90 では `.coin-yen-amount` の aria-live を撤去したが、症状残存
  - 問題のスコープが「単価切替」だけでなく「枚⇄円のモード切替」でも発生
  - 共通原因: `.diff-card-body` 自体が `role="button"+tabIndex=0` でフォーカス可能
    → Android Chrome がタップ時にデフォルト青ハイライトを描画
  - 対策: `.diff-card-body` および全子孫に `-webkit-tap-highlight-color: transparent`、
    中央表示用要素 (`.diff-num` / `.coin-yen-amount`) に `pointer-events: none` を付与
    → 表示専用要素はタップターゲット候補から完全に外す

## [0.2.90] - 2026-05-02 (PC + PWA 同期)

### バグ修正 (Android PWA)
- **5/10/20円 単価切替時に金額表示の周りに青い枠線が一瞬出る問題を修正**
  - 原因: `.coin-yen-amount` の `aria-live="polite"` で内容変化時に Android Chrome が
    アクセシビリティ用フォーカスリングを瞬間描画していた
  - 対策: `aria-live` 撤去 (単価ボタンに aria-checked が付いており情報損失なし) +
    CSS で `user-select: none` / `-webkit-tap-highlight-color: transparent` /
    `outline: none` を明示

## [0.2.89] - 2026-05-02 (PC + PWA 同期)

### バグ修正 (PC Electron)
- **PC Electron でカスタム単価ダイアログが見えない問題を修正**
  - 原因: ダイアログ overlay が z-index: 9000 で、Electron の `.app-mode` ラッパー
    (z-index: 10000) より下に隠れていた
  - Portal で document.body にマウントしていても、同じ親 (body) 内では z-index で
    スタッキングが決まる
  - 対策: ダイアログ overlay を z-index: 20001 に変更し、app-mode (10000) や
    editor bar (20000) より上に出す
  - v0.2.85〜88 で実は PC でも見えていなかった (隠れていただけ)

## [0.2.88] - 2026-05-02 (PC + PWA 同期)

### バグ修正 (iOS Bluefy)
- **iOS Bluefy のカスタム単価ボタンが動かない問題を環境別ダイアログ方式で解決**
  - v0.2.82〜87 で React モーダル + ghost click ガード等を試したが、iOS Bluefy
    では React モーダルそのものがタップを受け取れない事象を解消できず
  - 解決策: 環境別にダイアログを切り替え:
    - **Electron (PC)**: window.prompt() が無効なので React モーダル
    - **PWA / Android Chrome / iOS Bluefy / その他ブラウザ**: OS ネイティブの
      window.prompt() を使用 (ジェスチャー競合の影響を受けない)
  - 検出は `window.counter` (preload で公開) の有無で分岐
  - Android PWA は v0.2.79 以前と同じ挙動に戻る (確認済の動作パス)

## [0.2.87] - 2026-05-02 (PC + PWA 同期)

### バグ修正 (iOS Bluefy)
- **カスタム単価ボタン押下時の dialog 即時閉じ問題への追加対策**
  - v0.2.86 でも症状が残ることが確認されたため、追加で以下を実装:
  - 対策 1: dialog overlay にマウント直後 300ms の ghost click ガード
    (iOS WKWebView では portal mount → 同じ touch のフォローアップイベントが
    新しい overlay に届いて即 close する事象がある)
  - 対策 2: overlay の click 判定で `target === currentTarget` チェック追加
    (内側 dialog からのバブリング click を確実に除外)
  - 対策 3: コイン単価セレクター自体にも `touch-action: manipulation` を付与

## [0.2.86] - 2026-05-02 (PC + PWA 同期)

### バグ修正 (iOS Bluefy / Android PWA)
- **iOS Bluefy でカスタム単価ボタンが反応しない問題を修正**
  - 原因: ボタンタップが pull-to-refresh ジェスチャーと誤認され、ダイアログが
    開く前にページが再読込されていた
  - 対策 1: `overscroll-behavior-y: contain` で全画面 pull-to-refresh を無効化
  - 対策 2: コイン単価ボタンに `touch-action: manipulation` +
    `-webkit-tap-highlight-color: transparent` を追加
  - 副次効果: BLE 接続中の誤リロード事故も防げるようになった (常時接続アプリの安定性向上)

## [0.2.85] - 2026-05-02 (PC + PWA 同期)

### バグ修正 (PC + Android + iOS Bluefy)
- **コイン単価カスタム入力ダイアログが正しい位置に表示されない問題を修正**
  - 原因: react-grid-layout の transform 親 + .card の overflow:hidden で
    `position: fixed` のダイアログがカード内にクリップされて見切れる
  - 対策: `createPortal(<dialog />, document.body)` で DOM ツリー上の親を超えて
    `<body>` 直下にマウント、viewport 基準で正しく表示
  - PC / Android では偶然視認できる位置だったが iOS Bluefy で発覚し全環境共通修正

## [0.2.84] - 2026-05-01 (PC + PWA 同期)

### 新機能 (PC + Android)
- **ラベルの色・サイズ・縁取りをテーマパネルから自由設定可能に**
  - **文字色**: 既定 `#8a8a99` (薄グレー) → 任意の色に変更可能。背景画像に合わせて視認性確保
  - **文字サイズ**: 70〜140% で拡縮 (既定 100%)。container query 連動でレスポンシブ動作も維持、上限 140% は数字とのバランス保護
  - **縁取り色**: 既定 `#000000` (黒) → 任意の色に変更可能
  - **縁取り強度**: 0〜150% (既定 100%)。0% で縁取り完全 OFF
  - 対象: 各カードラベル (差枚 / IN / 機械割 / BB / RB / ART / SBB / xx確率 / xx払出数) + グラフタイトル (スランプグラフ / ボーナス履歴)
  - persist v6→v8 マイグレーション (既存ユーザーは見た目変化なし)

### UX 改善 (PC + Android)
- **差枚カードの円表示モード時、ラベルが「差枚」→「差円」に切り替わる**
  - 枚モード = 「差枚」、円モード = 「差円」
  - カード本体タップ時のモード切替に同期して即時更新

## [0.2.83] - 2026-05-01 (PC + PWA 同期)

### バグ修正 (PC + Android)
- **金額表示で大きな数字 (10 文字超) がカード幅を超えて切れる問題を修正**
  - 例: カスタム単価 1000 円 × 差枚 4,644 = -4,644,000円 (12 文字) で「円」が右端で切れていた
  - 対策: font-size の幅軸を 13cqw → 9cqw に縮小、letter-spacing 1px → 0.5px、左右に 0.2em の padding
  - 12 文字長まで余裕で収まるよう調整、短い値 (7 文字 "+3,580円") も視認性は十分維持

## [0.2.82] - 2026-05-01 (PC + PWA 同期)

### バグ修正 (PC + Android)
- **PC Electron 版でコイン単価セレクターの「カスタム」が無反応だった問題を修正**
  - 原因: `window.prompt()` は Electron / Chromium で実装されておらず即 null 返却
  - 対策: React モーダル (`CustomUnitDialog`) に置換、Enter/Esc キー対応 + バリデーション
  - PWA / Electron 両環境で同じ動作になり、カスタム値の入力・保存が両方で動く
- **カードラベル (差枚 / 機械割 等 CJK 文字) の下端が切れる問題を修正 (再修正)**
  - v0.2.81 で `line-height: 1.1 → 1.4` にしたが、Android PWA では字 fallback による
    line-box 計算ズレで依然クリップ発生
  - 根本対策: `overflow: hidden` + `text-overflow: ellipsis` を撤廃
  - 長いラベルの境界処理は親 `.card { overflow: hidden }` が担うので個別 ellipsis は不要

## [0.2.81] - 2026-05-01 (PC + PWA 同期)

### バグ修正 (PC + Android)
- **カードラベル「差枚」「機械割」など CJK 文字の下端が切れる問題を修正**
  - 原因: `line-height: 1.1` だと CJK 字の下部が `overflow: hidden` でクリップ
  - 対策: `line-height: 1.4` に拡大して CJK 字の余裕を確保
  - 全カード共通修正 (差枚 / 機械割 / 総回転 / スランプグラフ 等すべてに反映)

## [0.2.80] - 2026-05-01 (PC + PWA 同期)

### UX 改善 (PC + Android)
- **差枚カード金額モードの UI を磨き上げ**
  - コイン単価セレクター (5/10/20/カスタム) をカード下部・横方向中央に配置、右下のトグルアイコンと同じ高さで横並びに
  - セレクターの天地を 26px → 14px の超薄型ピル UI に圧縮、画面占有率を低減
  - カスタム単価ボタンに「1〜1000 円」の任意整数入力サポート (window.prompt)
  - 狭幅 (~300px 以下) では「5/10/20/他」にラベル自動短縮
- **タップで枚数 ↔ 金額を切替できることを示すヒントを刷新**
  - 旧: 下部中央の「タップで金額表示 →」テキスト
  - 新: 右下角に小さな円形アイコン (差枚モード = ¥、金額モード = 枚)
  - 初回限定でゴールドにパルスして発見性を確保

### バグ修正 (PC + Android)
- **金額表示「+3,580円」のカンマや「円」の下端が切れる問題を修正**
  - 原因: `line-height: 1` + `overflow: hidden` でディセンダー (字の下伸び) が矩形クリップ
  - 対策: `line-height: 1.2` + `overflow: hidden` を撤廃
- **金額表示のグラデーションが「四角い塊」に見える違和感を解消**
  - 原因 1: `text-shadow` の blur が px 固定で、字サイズが小さい時に隣の字とグローが過剰に重なる
  - 対策 1: `text-shadow` を em 単位 (0.18em / 0.36em / 0.55em) に変更、字サイズに比例
  - 原因 2: `overflow: hidden` でグローが要素境界で矩形にクリップ
  - 対策 2: 上記カンマ修正と同じ `overflow: hidden` 撤廃で同時解決
- **コイン単価セレクター選択時のゴールド枠の上下幅が不揃いに見える問題を修正**
  - フォントベースラインに依存して padding が対称でも視覚的に非対称に見えていた
  - `inline-flex` + `align-items: center` でグリフを強制的に垂直中央配置

## [0.2.79] - 2026-05-01 (PC + PWA 同期)

### 新機能 (PC + Android 両方)
- **差枚カードに金額表示モードを追加**
  - 差枚カードをタップ/クリックで「差枚 ↔ 勝ち負け金額」を切替
  - コイン単価はプリセット 5円 / 10円 / 20円 + カスタム値 (任意の整数 1〜1000 円)
  - +1,234枚 × 20円 → 「+24,680円」のようにカンマ付きで表示
  - プラスはシアン+ゴールドのグロー、マイナスは赤のグロー (差枚と同じ視覚言語)
  - 単価の選択はリロード後も維持 (localStorage 永続化)
  - 初回起動時は「タップで金額表示 →」がゴールドにパルスして発見性を確保
  - 編集モード中はトグル無効化 (ドラッグと干渉しない)

## [0.2.78] - 2026-05-01 (PC + PWA 同期)

### バグ修正 (PC + Android 両方)
- **連チャン対象範囲の数値入力が編集途中で勝手に戻る問題を修正**
  - 「100」を消して「20」「30」などに変えようとした時、削除キーで「1」だけが残る / 空欄にできない / 勝手に 100 に戻る現象を解消
  - 編集中は文字列として保持し、フォーカスが外れた時点で確定 (1 以上の整数なら反映、空欄/不正値は直前の値に戻す)
  - スマホでの設定変更操作がスムーズに

### マニュアル
- 「連チャン」項目に **初当たりを含めたボーナス回数** であることを明記
- 対象範囲超過後は 1連 から再スタートする挙動も追記

## [0.2.77] - 2026-04-30 (PC + PWA + 管理画面 + ランディング 一括同期)

v0.2.73 PC リリース以降に蓄積された改修をまとめて配信。

### 新機能 / 改善 (PC + Android 両方)
- **差枚カードのカスタム色対応** (v0.2.76)
  - テーマパネルで「差枚数」の色を設定すると実際に反映される (従来は白固定で上書きされていたバグを修正)
  - +/- のグロー (シアン+ゴールド / 赤) は維持され、視覚的な勝ち負け表現は保たれる
- **機種名・メーカー名入力を OS ネイティブダイアログ化** (v0.2.66 〜 v0.2.71)
  - Android Chrome のテキスト長押し→ドラッグでテキストが消える事象を根本回避
  - 機種名 30 文字 / メーカー 15 文字の上限、超過時は警告で再入力
- **メーカー名の自動正規化** (v0.2.75)
  - 全角括弧「SANKYO（三共）」と半角括弧「SANKYO(三共)」を同一視
  - 一覧・フィルター・新規登録すべてで NFKC 正規化された統一表記を使用
- **検索窓の自動フォーカス解除** (v0.2.75)
  - 機種選択モーダルを開いた瞬間にキーボードが立ち上がる事象を解消

### バグ修正 (PC + Android 両方)
- **数字が右端で切れる問題を修正** (v0.2.74)
  - 確率カード「1/9999」等 6 文字、基本カード 5 桁数字までフォントを自動縮小
- **長機種名でヘッダー LED が消える / モーダル左ズレ** (v0.2.61, v0.2.70)
- **連チャン表示が範囲超過後も消えない** (v0.2.63)
- **スランプグラフが枠外で見切れる** (v0.2.72)

### 管理画面 (admin-ui)
- **クライアント側ページネーション**を 5 ページに導入
  - Users / Licenses / Machines / Requests / Voices
  - 25 / 50 / 100 / 500 件/ページの切替
  - 検索フィルター後の件数で動作、PC + スマホ両対応の UI
  - 機種カタログ 600+ 件規模の初期描画負荷を大幅軽減

### ランディングページ
- **FT245RL 対応版商品ページへの導線 4 箇所追加**
  - ヒーロー直下 / 対応ハードウェアカード / ご購入セクション / お問い合わせ前
  - リンク先: <https://www.a-slot.com/SHOP/a-counter-x_ft245rl.html>
- **PWA BETA セクション + 最新バージョン changelog セクション**を v0.2.77 用に更新

### マニュアル (a-counter.net/manual/)
- 「7-4. 数字の色」セクションを v0.2.77 仕様に追記 (差枚カードも対応した点を明記)
- 機種編集の入力 UX 変更 (ネイティブダイアログ化) を反映
- メーカー名の表記ゆれ自動統一について追記

## [0.2.73] - 2026-04-30 (PC + PWA 同期リリース)

PC 版 v0.2.51 以降に蓄積された改修をまとめてリリース。

### 新機能 (PC + Android 両方)
- **数字色のカスタマイズ** (v0.2.60)
  - テーマパネルから 14 個の項目で数字フォント色を自由に変更可能
  - ボーナス系 4 色 (BB / RB / ART / SBB) はカード・履歴バッジ・ART 中表示すべてに連動
  - 個別カード 10 件 (総回転 / 純回転 / 機械割 / IN / OUT / PAY OUT / 最大獲得 / 最低獲得 / 差枚 / ゲーム数) もカード単位で色指定可能
  - 個別 / 全体リセットボタン付き、設定は localStorage に永続化

### バグ修正 (PC + Android 両方)
- **連チャン表示が範囲を超えても消えないバグを修正** (v0.2.63)
  - 「連チャンの対象範囲」を 10 回転に設定した時、10 回転を超えても連チャン表示が居座る不具合を解消
  - 範囲超過したら自動で「N連」表示が消える挙動に変更
- **スランプグラフが下方向に枠外へ伸びて見切れる問題を修正** (v0.2.72)
  - 差枚が大きくマイナスに振れた時、グラフ折れ線が枠外で切られて低い差枚値が見えなくなる現象を解消
- **長い機種名でヘッダーレイアウトが崩れる問題を修正** (v0.2.61, v0.2.62)
  - 機種名は省略表示 (`...`) で 1 行に収まるように
  - 連荘バッジが中央カラムで保護される (モバイル縦画面)

### UX 改善 (PC + Android 両方)
- **機種名 / メーカー名入力を OS ネイティブダイアログ式に変更** (v0.2.68 〜 0.2.71)
  - インライン入力で発生していたテキスト選択 / ドラッグ起因のレイアウト崩れを根本回避
  - 機種名 30 文字 / メーカー 15 文字の上限あり、超過時は警告ダイアログで再入力
- **モーダルの × 閉じるボタンを大きく** (v0.2.64)
  - PC: 28 → 36px、モバイル: 44px (iOS タッチ標準)
- **ESC キーで全モーダルを一括クローズ** (v0.2.64)
- **テキスト選択時のハイライト色を明示** (v0.2.65)
  - シアン背景 + 黒文字で常に視認性を確保
- **ErrorBoundary 追加** (v0.2.64)
  - 万一 React の例外で画面が壊れても、復旧 UI で「再読み込み」できるように

### Android PWA 専用 (BETA 公開)
- **Android スマートフォン版を BETA 公開** (v0.2.52)
  - https://a-counter.net/app/ — Chrome / Edge for Android で「ホームに追加」してインストール
  - Bluetooth 受信機との通信に対応 (Web Bluetooth API)
- **画面いっぱい表示の対応** (v0.2.52, 0.2.57, 0.2.59)
  - 縦画面・横画面とも端末画面いっぱいに自動レイアウト
  - 横画面で項目名が見やすい配置に最適化
- **ホーム追加アイコン** (v0.2.53〜0.2.55)
  - 黒背景 + ロゴ中央配置で Android アダプティブアイコンに対応
- **信号ログの記録対応** (v0.2.56)
  - ゲーム単位の IN/OUT/BB/RB/ART/SBB の信号エッジを記録
- **PWA インストール / 初回訪問の計測** (v0.2.58)
  - 管理画面のダウンロード統計に Android 利用状況が表示される

### その他
- v0.2.66 で旧 grid layout 用の死コード CSS 88 行を削除
- 多数の小さな安定化修正

## [0.2.51] - 2026-04-29 以前

ベータ版開発初期の機能追加 / 安定化修正のため、個別バージョンの詳細記録は
ありません。主な内容: 基本カウンタ・差枚カード・スランプグラフ・ボーナス履歴の
基盤実装、機種編集 UI、テーマシステム、Bluetooth (ABBTM2) / 有線 (A-IO 2.0 /
FT245RL) ハードウェア対応、ランキング / セッション保存などの基本機能。
