# スマホ限定フォントサイズ仕様

`UserInputService.TouchEnabled and not UserInputService.MouseEnabled` をスマホ判定とし、
`UITextSizeConstraint.MaxTextSize` で各 UI 要素のフォントサイズ上限を px 単位で固定する。
PC / タブレット等の非モバイル環境では制約は一切かからず `TextScaled` のみで動作する。

## 一覧

| 対象 | UI要素 | 通常 (デスクトップ) | 縮小 (スマホ, HM表示中) | 縮小 (スマホ, HM非表示) | 備考 |
|---|---|---:|---:|---:|---|
| 上部バー | `infoLabel` (科目/残り/得点) | 未設定 (TextScaled) | **16** | **16** | スマホは 2/3 にキャップ |
| 上部バー | `skipBtn` (今すぐ解答する) | 未設定 (TextScaled) | **16** | **16** | スマホは 2/3 にキャップ |
| 上部バー | `assistBtn` (解答アシスト) | 未設定 (TextScaled) | **16** | **16** | スマホは 2/3 にキャップ |
| 上部バー | `shopBtn` (ショップ) | 未設定 (TextScaled) | **16** | **16** | スマホは 2/3 にキャップ |
| 出題 | `qBody` (問題文) | 未設定 (TextScaled) | **21** | **24** | HM非表示時は全幅でゆったり |
| 選択肢 | `letter` (A/B/C/D 記号) | 未設定 (TextScaled) | **16** | **24** | スマホのみ、状態で切替 |
| 選択肢 | `body` (選択肢テキスト) | 未設定 (TextScaled) | **11** | **16** | スマホのみ、状態で切替 |
| その他 | `qIndex` (問 N/M 表示) | 未設定 (TextScaled) | 未設定 (TextScaled) | 未設定 (TextScaled) | 問題番号なので小さく自然 |

> **HM表示中** と **HM非表示** の列は独立して設定可能。
> 選択肢 `letter` / `body` は HM非表示で選択肢フレームが全幅化するのに合わせて大きめに切替。
> 動的切替は `applyHeatmapLayout()` 内で `pgui:GetAttributeChangedSignal("HeatmapShown")` と連動。

## 実装場所

- `src/client/QuizHUD.client.lua`
  - `qBody` の制約: 出題パネル生成直後 (`IS_MOBILE` 判定内、スマホのみ 21px 上限)
  - 選択肢 `letter` / `body` の制約: choiceLabels 生成直後 (`IS_MOBILE` 判定内、スマホのみ)
  - 上部バーの制約: 末尾のモバイル HUD 縮小ブロック内で `capText()` ヘルパー経由で付与 (スマホのみ)

## 変更履歴

| 日付 | 対象 | 変更内容 |
|---|---|---|
| 2026-04-15 | `qBody` | 初回導入: MaxTextSize=14 でハーフ相当にキャップ |
| 2026-04-15 | 上部バー 4要素 | 初回導入: MaxTextSize=16 で約 2/3 にキャップ |
| 2026-04-15 | `qBody` | 14 → 21 (1.5倍) に拡大して可読性を確保 |
| 2026-04-15 | 選択肢 `letter` / `body` | デスクトップにも常時適用開始 (letter=21, body=16)。スマホは従来通り (letter=16, body=11) |
| 2026-04-15 | 選択肢 `letter` / `body` | デスクトップ適用を撤回し未設定(TextScaled)に戻す。一覧を HM表示中/HM非表示 の 2 列に分離 |

---

# UI 枠レイアウト仕様 (通常 / 縮小)

`UDim2.new(scaleX, offsetX, scaleY, offsetY)` 表記。`scale` は親の割合 (ScreenGui=画面)、`offset` は px。
縮小化（スマホ）は `IS_MOBILE == true` かつ `screen.IgnoreGuiInset = true`（座標系の原点が画面最上段 y=0）。

## 上部バー (`topBar`)

| 状態 | 左上 X | 左上 Y | 横幅 (Width) | 高さ (Height) |
|---|---|---|---|---|
| **通常 (デスクトップ)** | `(0, 0)` | `(0, 0)` | `(1, 0)` = 画面幅100% | `(0, 60)` = 60px |
| **縮小 (スマホ)** | `(0.5, 2)` | `(0, 0)` | `(0.5, -46)` = 画面幅の50%-46px | `(0, 72)` = 72px |

- スマホ縮小時は右半分から開始し、右端 44px は Roblox プレイヤーリスト避け
- 行1 (y=0〜36) = Roblox アイコン帯、`infoLabel` を右寄せ
- 行2 (y=38〜72) = Roblox strip 直下、`skipBtn` / `assistBtn` / `shopBtn` を横並び

## 出題パネル (`panel`) + `qIndex` / `qBody`

| 状態 | 左上 X | 左上 Y | 横幅 (Width) | 高さ (Height) |
|---|---|---|---|---|
| **通常 (デスクトップ, 出題中)** | `(0.15, 0)` | `(0, 66)` | `(0.7, 0)` = 画面幅70% | `(0, 120)` = 120px |
| **通常 (デスクトップ, 科目選択中 compact)** | `(0.02, 0)` | `(0, 66)` | `(0.63, 0)` = 画面幅63% | `(0, 120)` = 120px |
| **縮小 (スマホ, HM表示中)** | `(0.5, 2)` | `(0, 78)` | `(0.5, -4)` = 画面幅50%-4px | `(0, 70)` = 70px |
| **縮小 (スマホ, HM非表示)** | `(0, 4)` | `(0, 78)` | `(1, -8)` = 画面幅100%-8px | `(0, 140)` = 140px |

- スマホ縮小時は上部バー (y=0〜72) の直下に 6px 間隔で配置
- HM非表示 (`HeatmapShown=false`) の間は画面全幅・高さ140pxを使用し、HM表示に切替わると右半分・高さ70pxに縮小
- `qIndex` (問N/M) : `Position=(0,8,0,2)` `Size=(1,-16,0,16)`
- `qBody` (問題文) : `Position=(0,8,0,20)` `Size=(1,-16,1,-22)` → 残り高さを可変

## 選択肢フレーム (`choicesFrame`)

| 状態 | 左上 X | 左上 Y | 横幅 (Width) | 高さ (Height) |
|---|---|---|---|---|
| **通常 (デスクトップ)** | `(0.1, 0)` | `(1, -85)` = 下端-85px | `(0.8, 0)` = 画面幅80% | `(0, 65)` = 65px |
| **縮小 (スマホ, HM表示中)** | `(0.5, 2)` | `(0, 152)` | `(0.5, -4)` = 画面幅50%-4px | `(0, 50)` = 50px |
| **縮小 (スマホ, HM非表示)** | `(0, 4)` | `(0, 224)` | `(1, -8)` = 画面幅100%-8px | `(0, 100)` = 100px |

- デスクトップは画面下端基準 (`UDim scale Y = 1` + オフセット `-85`)
- スマホ HM表示中: 上部バー+出題パネル (〜148px) の下に y=152 で配置
- スマホ HM非表示: 出題パネル (y=78〜218) の下に y=224 で配置、全幅で高さ100px
- 内部の選択肢ボックス (A/B/C/D) はそれぞれ `Size=(0.24, 0, 1, 0)` (25%幅, 高さ100%) で 4 等分

## 科目選択 / 配点ヒートマップ

`src/client/HeatmapUI.client.lua` の別 `ScreenGui` に存在。トグルボタンとパネルの 2 要素。
スマホ時は `screen.IgnoreGuiInset = true`、初期状態は閉じ (`panel.Visible = not IS_MOBILE`)。

### トグルボタン (`toggleBtn`)

| 状態 | 左上 X | 左上 Y | 横幅 (Width) | 高さ (Height) |
|---|---|---|---|---|
| **通常 (デスクトップ)** | `(1, -170)` = 右端-170px | `(0, 66)` | `(0, 160)` = 160px | `(0, 28)` = 28px |
| **縮小 (スマホ)** | `(0, 160)` | `(0, 6)` | `(0, 120)` = 120px | `(0, 26)` = 26px |

- スマホでは上部に配置。Roblox バーガーメニュー + 周辺コアアイコンを確実に避けるため **x=160 から開始**
- ボタンのテキストは開閉で `科目選択 ▲` / `科目選択 ▼` を切替

### パネル本体 (`panel`)

| 状態 | 左上 X | 左上 Y | 横幅 (Width) | 高さ (Height) |
|---|---|---|---|---|
| **通常 (デスクトップ)** | `(1, -360)` = 右端-360px | `(0, 100)` | `(0, 340)` = 340px | `(1, -112)` = 画面高-112px |
| **縮小 (スマホ)** | `(0, 6)` | `(0, 40)` | `(0.5, -12)` = 画面幅50%-12px | `(1, -48)` = 画面高-48px |

- デスクトップは右端に幅固定 340px の縦長パネル
- スマホは **左半分全体を占有** (右側 HUD と重ならない)、上は y=40 から下端まで

### パネル内要素

| 要素 | 左上 X | 左上 Y | 横幅 | 高さ | 備考 |
|---|---|---|---|---|---|
| `title` (ヘッダー) | `(0, 0)` | `(0, 0)` | `(1, 0)` = 100% | `(0, 36)` = 36px | 「科目選択 / 配点ヒートマップ」 |
| `statusLabel` (状態文) | `(0, 10)` | `(0, 38)` | `(1, -20)` = 100%-20px | `(0, 22)` = 22px | ▶ クリック案内 / 実行中 等 |
| `container` (ScrollingFrame) | `(0, 10)` | `(0, 66)` | `(1, -20)` = 100%-20px | `(1, -80)` = 親高-80px | 縦スクロール、`AutomaticCanvasSize=Y` |
| 各科目 `row` | — (UIListLayout 自動配置) | — | `(1, -14)` = 100%-14px (スクロールバー余白) | `(0, 52)` = 52px | 7 科目、8px パディング |
| 科目ボタン (凹凸) | `(0, 0)` | `(0, 3)` | `(0, 110)` = 110px | `(1, -6)` = 行高-6px | 名前+点数 2行表示 |
| `barArea` (分野バー) | `(0, 115)` | `(0, 3)` | `(1, -115)` = 行幅-115px | `(1, -6)` = 行高-6px | 分野ごとに内部で横分割 |

## レイアウト図 (スマホ縮小時)

```
画面 (幅 W, 高さ H)
┌──────────────────┬──────────────────┐ y=0
│                     │ [info label]       │ ← Roblox アイコン帯 (y=0-36)
│                     ├──────────────────┤
│  [heatmap toggle]  │ [skip][assist][shop] │ ← y=38-72 (topBar 行2)
│                     ├──────────────────┤ y=72
│                     │                        │
│                     │   [出題パネル]     │ y=78-148
│ [heatmap panel]  │                        │
│  (縦スクロール) │                        │
│                     ├──────────────────┤ y=152
│                     │ [A][B][C][D]       │ y=152-202 (選択肢)
│                     │                        │
│                     │                        │
└──────────────────┴──────────────────┘ y=H
 左半分 (0 ~ 0.5W)  │ 右半分 (0.5W ~ W-44)
```

