# RC110 · Pass page standardization QA

## Purpose

RC110 is a targeted cleanup release on top of RC109. The goal is to bring the pass page closer to the standardized NEXT app structure by reusing shared functions/classes and removing old pass-overview helper leftovers.

This release deliberately does **not** refactor the sensitive active exercise player/video/timer lifecycle.

## Reference implementation carried forward

Read before change:

- `docs/ARCHITECTURE_DECISIONS.md`
- `docs/DO_NOT_TOUCH_WITHOUT_DESIGN.md`
- `docs/RC108_EXERCISE_LIBRARY_REAL_DOM_QA.md`
- `docs/RC109_STABLE_ASSET_PATH_CLEANUP_QA.md`

Carried forward unchanged:

- Static `preview.html` shell and script order.
- Existing dashboard/calendar/program/profile/library renderer boundaries.
- Existing active player lifecycle functions:
  - `startWorkout`
  - `renderStep`
  - `renderVideo`
  - `renderRest`
  - timer/wake-lock/preload/YouTube/server/local backup behavior
- Existing exercise library/image system.
- Existing S2P1 direct-composite route:
  - `assets/img/exercises/premium/s2p1/<exerciseKey>.webp`

No new exercise images were generated. Image generation remains paused.

## RC110 changes

### Pass overview renderer standardization

Updated existing renderer only:

- `assets/js/renderers/overview-renderer.js`

The renderer now exposes and reuses small helper functions instead of a long inline template:

- `renderMetaChips`
- `renderEquipment`
- `renderOverviewBlock`
- `renderOverviewGroup`
- `renderOverviewExerciseRow`

The output uses shared NEXT app classes and pass-specific aliases:

- `.next-pass-overview-page`
- `.next-pass-overview-hero`
- `.next-pass-overview-layout`
- `.next-pass-overview-block`
- `.next-pass-overview-actions`
- `.next-pass-equipment-panel`
- `.next-overview-exercise-row`

Legacy pass-overview helper leftovers with old `ov*` class names were removed from `assets/js/app.js`.

### Active pass DOM class contract

Updated markup in `preview.html` to add canonical aliases while keeping all existing IDs and legacy classes intact:

- `#exerciseScreen.next-pass-screen`
- `.sticky-nav.next-pass-topbar`
- `.progress-meta.next-pass-progress`
- `.pass-bottom-controls.next-pass-controls`
- `.stage-layout.next-pass-layout`
- `.video-card.next-pass-media-card`
- `#videoWrap.next-pass-video-wrap`
- `.info-card.next-pass-info-card`
- `.exercise-kicker.next-pass-kicker`
- `#exerciseName.next-pass-exercise-name`
- `#exerciseReps.next-pass-prescription`
- `.playlist-card.next-pass-playlist-card`
- `#miniList.next-pass-mini-list`

These are aliases for styling/QA ownership. They do not introduce a new player renderer.

### Pass-mode screen ownership fix

Real-DOM QA showed that when `body.exercise-active` is set, non-player screens could remain in document flow because the existing hide/show rules were scoped to `body:not(.exercise-active)`.

RC110 adds pass-mode screen ownership in `assets/css/next-system.css`:

```css
body.exercise-active .screen:not(#exerciseScreen){ display:none; }
body.exercise-active #exerciseScreen.active{ display:block; }
```

This keeps dashboard/calendar/program/profile from sitting above the active player during real pass mode.

### Fixed bottom controls containment

Real-DOM QA also caught a CSS containment issue: `backdrop-filter`/containment on the sticky pass header made the fixed bottom controls anchor to the header instead of the viewport in Chromium. RC110 removes that containment for `.next-pass-topbar` so `.next-pass-controls` anchors to the viewport bottom as intended.

## Explicit non-changes

- No new images.
- No image generation.
- No new foreground/background cutout workflow.
- No new exercise image model.
- No new player/video renderer.
- No `renderVideo` source model change.
- No timer/autoplay/wake-lock lifecycle refactor.
- No change to server/local backup priority.
- No change to RC109 stable asset paths.

## Browser/DOM QA method

As in RC108/RC109, direct browser navigation to local `file://` and local `http://127.0.0.1` is unreliable/blocked in this sandbox.

RC110 real-DOM QA uses Chromium + Playwright with `page.set_content()` after inlining the actual `preview.html`, CSS and scripts. This exercises the real runtime DOM and CSS cascade.

For screenshots only, local images are converted to data URIs after render so screenshots show actual assets. DOM metrics still verify production classes and paths.

QA script:

- `tests/rc110_pass_page_real_dom_qa.py`

Metrics:

- `qa_screenshots/rc110_pass_page_dom_metrics.json`

## Screenshots created

Pass overview:

- `qa_screenshots/rc110_pass_overview_mobile_390x844.png`
- `qa_screenshots/rc110_pass_overview_ipad_820x1180.png`
- `qa_screenshots/rc110_pass_overview_desktop_1440x1024.png`

Active pass:

- `qa_screenshots/rc110_active_pass_mobile_390x844.png`
- `qa_screenshots/rc110_active_pass_ipad_820x1180.png`
- `qa_screenshots/rc110_active_pass_desktop_1440x1024.png`

## DOM verification results

Pass overview metrics confirmed:

- `screen = overviewScreen`
- `bodyExerciseActive = false`
- `.next-pass-overview-page` rendered
- `.next-pass-overview-block` count: 2
- `.next-overview-exercise-row` count: 11
- legacy `ov*` classes in rendered overview: 0
- start button uses `.next-button.next-button-primary`
- equipment panel uses `.next-card.next-equipment-panel.next-pass-equipment-panel`

Active pass metrics confirmed:

- `screen = exerciseScreen`
- `bodyExerciseActive = true`
- `#exerciseScreen` class includes `.next-pass-screen.active`
- topbar class includes `.next-pass-topbar`
- video wrapper class includes `.next-pass-video-wrap.start-video-wrap`
- exercise name rendered as `Hopprep`
- next/start button text: `Starta pass ▶`
- local broken image count: 0
- bottom controls anchor to viewport bottom after RC110 containment correction

## Automated checks run

```bash
node tests/rc109_asset_path_cleanup_smoke.js
node tests/rc107_asset_and_library_smoke.js
node tests/rc109_library_compactness_static_smoke.js
node tests/rc110_pass_page_standardization_smoke.js
node tests/rc104_direct_composite_smoke.js
node tests/rc106_smoke.js assets/js/core/exercise-illustrations.js "$PWD"
node tests/rc91_service_smoke.js
node tests/rc92_action_smoke.js
node tests/rc93_library_service_smoke.js
node tests/rc96_server_video_service_smoke.js
node tests/rc97_exercise_catalog_smoke.js
bash tests/rc95_static_checks.sh
bash tests/rc96_static_checks.sh
bash tests/rc97_static_checks.sh
find assets/js -name '*.js' -print0 | xargs -0 -n1 node --check
php -l ota_youtube_proxy.php
php -l video_backup_api.php
python3 tests/rc110_pass_page_real_dom_qa.py
python3 tests/rc109_library_real_dom_qa.py
```

Result: checks passed.

## Known QA limitation

The real deployed host was not available in this sandbox. OTA proxy/network behavior should still be verified after deploy. RC110 did not change OTA/player source logic.
