# QA Issue Report: QA-BUG-CLI-20261002-02

## 1. Header Metadata
- **Bug ID**: `QA-BUG-CLI-20261002-02`
- **Department**: Client Architecture (`CLI`)
- **Severity**: `CRITICAL`
- **Status**: `RESOLVED / VERIFIED`
- **Date**: `2026-10-02T17:02:28Z` (Resolved: `2026-10-03`)
- **Reporter**: Autonomous QA Automation Lead (`worker_1`)
- **Target File(s)**: `client/webapp/index.html:38-115`, `client/webapp/css/hud_skills.css:186-193`, `client/webapp/css/main.css`

---

## 2. Title & Executive Summary
- **Title**: Portrait Orientation Critical Layout Breakage & Header Overflow
- **Executive Summary**: When FreeExile WebApp is accessed on standard mobile portrait viewports (e.g. iPhone 393 x 852 px), the interface experiences catastrophic layout collision: the top header bar overflows by 276 px (`scrollWidth = 669px` vs `clientWidth = 393px`), pushing Bag, Stash, and Settings buttons off-screen. The 328px Action Bar overlaps both the Life Orb and Mana Orb, the Minimap obscures top navigation icons, and no portrait rotation warning overlay exists to prompt the user to rotate to landscape.

---

## 3. Severity & Impact Justification
- **Classification**: `CRITICAL`
- **Justification**:
  - Unplayable Mobile Experience: Users launching the PWA or browser link in default vertical orientation are completely locked out of settings, inventory, character sheet, and language selection.
  - Multi-touch Collision: The Action Bar, Mana Orb, and Chat Bar occupy identical pixel coordinates, causing touches intended for skill execution to trigger potion consumption or open chat modals.
  - Zero Orientation Protection: Lack of an orientation gate violates ARPG mobile design standards, where landscape isometric perspective is mandatory.

---

## 4. Environment & Test Configuration
- **Harness**: Playwright Headless Browser (`tools/qa/run_browser_qa_suite.py`)
- **Emulated Device**: iPhone 15 Pro Portrait (`viewport = {"width": 393, "height": 852}`)
- **Device Pixel Ratio**: 3.0
- **Base URL**: `http://127.0.0.1:8088/index.html`
- **Visual Artifact**: `docs/qa/reports/telemetry/r2_mobile_portrait.png`

---

## 5. Step-by-Step Reproduction Procedure
1. Start local web server: `python tools/serve_webapp.py --port 8088`.
2. Launch browser with viewport `393x852` (or open mobile Safari without auto-rotate locked).
3. Navigate to `http://127.0.0.1:8088/index.html`.
4. Inspect the top header element (`header`):
   ```javascript
   const h = document.querySelector('header');
   console.log('Scroll:', h.scrollWidth, 'Client:', h.clientWidth, 'Diff:', h.scrollWidth - h.clientWidth);
   ```
5. Inspect bottom combat controls:
   - Notice `#skill-action-bar` directly overlapping `#hud-mana-orb-wrapper` and `#hud-life-orb-wrapper`.
   - Notice `#minimap-canvas` covering `#btn-open-settings` and `#lang-select`.

---

## 6. Empirical Telemetry, Logs & Evidence
- **Telemetry Extract (`qa_browser_telemetry.json`)**:
  - `headerScrollWidth`: `669`
  - `headerClientWidth`: `393`
  - `isOverflowing`: `true`
  - **Header Clip**: Exactly `276px` of navigation controls hidden past the right viewport boundary.
- **Bounding Box Collisions**:
  - `#skill-action-bar`: `x: 57 to 385`, `y: 760 to 844`.
  - `#hud-mana-orb-wrapper`: `x: 307 to 381`, `y: 768 to 842` (100% collision with rightmost skills).
  - `#hud-life-orb-wrapper`: `x: 12 to 86`, `y: 768 to 842` (30% collision with left flask slots).
- **Screenshot Evidence**: `docs/qa/reports/telemetry/r2_mobile_portrait.png` demonstrates illegible element stacking.

---

## 7. Root Cause Technical Analysis
1. **Lack of Orientation CSS Guard**:
   `manifest.json` specifies `"orientation": "landscape"`, but standard browser tabs (non-installed web apps) do not enforce web manifest orientation constraints.
2. **Fixed Desktop Header Widths**:
   `header` in `index.html:38` contains an un-collapsible flex container housing the player card, FPS/ping badges, 12 navigation action buttons, and language dropdown. At 393px width, min-content width is 669px.
3. **Hardcoded CSS Positioning**:
   `hud_skills.css:186-193` positions `#skill-action-bar` at `bottom: 8px; right: 8px; width: 328px;` regardless of whether viewport width is 393px or 1920px.

---

## 8. Actionable Fix Proposal & Architecture Alignment
### Fix 1: Mandatory Rotation Lock Overlay (`main.css`)
Implement a full-screen backdrop when device orientation is portrait:
```css
@media (orientation: portrait) {
  #portrait-rotate-overlay {
    display: flex !important;
    position: fixed;
    inset: 0;
    z-index: 99999;
    background: #09090b;
    color: #fef08a;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    padding: 24px;
  }
}
```
### Fix 2: Responsive Action Bar Collapsing
On narrow screens (`@media (max-width: 640px)`), collapse top header into a single dropdown hamburger menu (`#btn-menu-drawer`) and stack Dual Orbs vertically.

---

## 9. Verification & Regression Criteria
- [x] Rotating mobile viewport to `393x852` displays clean "Please Rotate Device" overlay.
- [x] Landscape viewport `852x393` automatically dismisses overlay and restores game view.
- [x] Zero DOM element overlaps between Action Bar and Dual Orbs in landscape mode.
- [x] Re-run `python tools/qa/run_browser_qa_suite.py` confirming `isOverflowing: false` under orientation lock.

---

## 10. Resolution Details
- **Implemented Fix**:
  1. In `client/webapp/index.html`, added `#portrait-rotate-overlay` with animated orientation icon and reactive 9-language microcopy (`rotate_screen_title`, `rotate_screen_desc`).
  2. In `client/webapp/css/main.css`, added `@media (orientation: portrait)` rule forcing overlay visibility (`display: flex !important`) and hiding combat HUD elements.
  3. Added responsive containment on `#hud-top-right` (`max-width: calc(100vw - 190px)`) with flex-wrap and horizontal scrolling prevention.
- **Empirical Proof**: Verified by `tools/qa/run_browser_qa_suite.py` scenario `mobile_portrait`: `headerScrollWidth: 393`, `headerClientWidth: 393`, `isOverflowing: false`.

