# MOBILE PASS ROUND 2 — fix spec for https://retire.krisforbes.ca **Spec v1 — written 2026-10-09 by Hermes (GLM). Execution: DSH (local 27B), all steps, zero user interaction.** Round 1 (commit 666b6c5) shipped 8 fixes. Hermes then re-audited the live site with vision-checked screenshots + DOM geometry and found **3 remaining issues** (below). Fix exactly these; do not re-litigate round-1 decisions. ## Evidence (measured by Hermes against the LIVE site, 2026-10-09) Geometry script: `/home/ubuntu/.hermes/cache/scratch/measure2.py` (Playwright, mobile emulation, 390×844 / 360×800 / 320×700). Screenshots: `/home/ubuntu/.hermes/cache/scratch/mobile-audit2/`. ### Issue 1 — Primary CTA hidden behind the bottom sheet on tall steps (all 3 widths) Step 0 (province grid, 13 options) at initial scroll (`scrollY=0`): | Device | Next button (viewport y) | Sheet top | Next behind sheet? | Next tappable? | Nunavut bottom vs sheet top | |---|---|---|---|---|---| | 390×844 | 667–717 | 618 | **yes, fully** | **false** | 630 > 618 (behind) | | 360×800 | 667–717 | 574 | **yes, fully** | **false** | 630 > 574 (behind) | | 320×700 | 701–751 | 474 | **yes, fully** | **false** | 664 > 474 (behind) | Root cause, two parts: - `.scr{padding-bottom:185px}` (mobile) is **smaller than the sheet obstruction** (sheet 218px tall + 8px bottom offset + safe-area = 226px+). At max scroll (70px on 390w) the Next bottom lands at viewport y=647, still 29px **below** the sheet top (618). The padding must be ≥ sheet obstruction + gap. - On tall steps the Back/Next row sits below the fold at load — the primary CTA of step 1 of 14 is invisible until the user scrolls. **Fix (all rules scoped to `@media(max-width:860px)`):** 1. Maintain a CSS var with the live sheet height: on load, on `resize`, and whenever the panel toggles `.open`, run `document.documentElement.style.setProperty('--sheet-h', panel.offsetHeight + 'px')` (guard for the smoke-test shim: `const h = panel && panel.offsetHeight; if (h) …`). Default `--sheet-h:218px` on `:root` so the first paint is correct. 2. `.scr{padding-bottom:calc(var(--sheet-h) + 14px + env(safe-area-inset-bottom))}` (replaces the 185px). 3. `.step-nav{position:sticky;bottom:calc(var(--sheet-h) + 14px + env(safe-area-inset-bottom));background:var(--bg);z-index:20;padding:6px 0}` — Back/Next pin above the sheet on tall steps; on short steps (e.g. income) the nav is naturally above the stick point so nothing changes visually. Keep it below the scrim (z 35) and sheet (z 40). Give the stuck bar a solid background so content scrolling under it doesn't show through. **Verify (programmatic, all 3 widths, step 0 AND step 12/interests):** - At `scrollY=0`: `#btn-next` bottom ≤ panel top − 2, and `document.elementFromPoint(nextCenter)` is inside `#btn-next` (tappable). - While scrolling (scrollY = maxScroll/2): nav bottom stays ≤ panel top − 2 (pinned). - At max scroll: last `.opt` bottom ≤ panel top − 2 (every option reachable above the sheet). - Short step (income, step 3): nav top unchanged vs round 1 (~485), i.e. no visual shift when not stuck. - Desktop (1280px): `.step-nav` computed `position` is `static`, `.scr` padding-bottom back to 80px. ### Issue 2 — "swipe →" pill overlaps the chart's top y-axis tick Vision-confirmed at 320px: the pill (`.chartbox::before` overlay, top-left of the card) sits on top of the topmost y-tick ("$1.05M"). At 390px it grazes the tick area too. **Fix:** remove the `.chartbox::before` overlay entirely. Instead render the hint in the chart card header: in `app.js`'s `chart()` helper, append `swipe →` inside the `.chart-h` div (which already holds the `
`). CSS: `.chart-h{display:flex;align-items:flex-start;justify-content:space-between;gap:10px}`
and `.swipe{display:none}` by default; ≤860px: `.swipe{display:inline-block;font-size:11.5px;color:var(--muted);background:var(--chip);border-radius:99px;padding:3px 9px;white-space:nowrap;flex:none}`.
The hint then lives in the header row and can never overlap SVG content. (The `.chart-h` flex change
is safe on desktop — the span is `display:none` there.)
**Verify:** at 320/360/390, for each of #g0–#g3: the `.swipe` rect does not intersect any `