## Refined Implementation Plan: Fix Poll Option Unresponsiveness on Android/Chrome **Changes Required – based on investigation findings** ### 1. `engagement.css` – Remove Absolute Child and `overflow: hidden` from Button **Problem reframed:** The root cause is the combination of `overflow: hidden` on a button that contains an absolutely positioned child (`.poll-option-bar` with `inset: 0`). Chrome Android’s hit-test algorithm can fail to dispatch touch events through this stack, even with `pointer-events: none` on the child. **Fix (replace child bar with `::before` pseudo-element and remove `overflow: hidden`):** - **Remove** the `.poll-option-bar` rule entirely (approx. line 210). - **Update** `.poll-option`: ```css .poll-option { position: relative; /* keep – needed for ::before positioning */ /* remove overflow: hidden */ /* this was causing hit-test clipping */ } ``` - **Add** `::before` pseudo-element for the visual bar: ```css .poll-option::before { content: ''; position: absolute; top: 0; left: 0; height: 100%; width: var(--vote-percent, 0%); background: ; /* copy from .poll-option-bar, e.g. var(--accent) */ pointer-events: none; /* explicit – ensures clicks pass through */ } ``` Copy any additional styles from `.poll-option-bar` (border-radius, transition) to `::before`. ### 2. `PollManager.js` – Optimistic UI Feedback + Bar Width via CSS Custom Property - **On vote click** (the branch that calls `this.vote(option)`), immediately add a CSS class `poll-option--voting` to `target.closest('.poll-option')`. Remove that class after the fetch settles (both success and failure). - **After successful vote**, set `--vote-percent` on the `.poll-option` element: ```javascript optionElement.style.setProperty('--vote-percent', `${percentage}%`); ``` Remove any direct manipulation of `.poll-option-bar` (it no longer exists). - **No change to event type** – still `pointerdown`. The hit-test fix makes this reliable. (Adding a `click` fallback is *not* required but would be a minor safety net; if desired, a single `click` listener can be added to the same handler, but it is not necessary for the fix.) ### 3. `engagement.css` – Add `poll-option--voting` Style ```css .poll-option--voting { background-color: rgba(0,0,0,0.05); transition: background-color 0s; } ``` This gives immediate visual feedback (subtle darkening) before the server responds. ### Files Modified - `engagement.css` – remove `.poll-option-bar`, add `::before` on `.poll-option`, remove `overflow: hidden`, add `.poll-option--voting` rule. - `PollManager.js` – add optimistic class toggle; replace bar-width setter with CSS variable assignment. ### Rollback Revert the two files. All changes are backward-compatible with existing browsers. --- ## Definition of Done - [ ] Run `pip install -e '.[dev]' -q && make test-unit` – all unit tests pass, including existing poll API tests. - [ ] Run `pip install -q ruff && ruff check .` – no new lint errors. - [ ] Manual verification on an Android device or emulator with Chrome: - Open a page containing a poll. - Tap a poll option – a subtle background change appears instantly. - After the vote completes, the bar (pseudo-element) reflects the new percentage. - Tapping the exact center of the option (where the old bar used to be) triggers the vote every time. - [ ] Confirm desktop behavior is unchanged – the bar renders identically in non‑mobile browsers. - [ ] Verify that `overflow: hidden` has been removed from `.poll-option` (grep after change). - [ ] Verify that `.poll-option-bar` no longer exists in `engagement.css`. - [ ] Verify that `--vote-percent` is set on `.poll-option` in the JS vote handler (no crash when the element is missing the old child).