Landing HR — cookie banner click-through fix (MC #106413, 2026-08-02)
MC #106413 — cookie banner intercepts submit click (bilko.cloud) — fix
Agent: codecraft
Date: 2026-08-02
Worktree: /Users/makinja/business/ALAI-Holding-AS/products/bilko-wt-106413
Branch: fix/106413-cookie-banner (new worktree, NOT main checkout)
Base: azdo/main @ e81db44a (2026-07-29) — git fetch azdo main fails in this
environment ("could not read Username ... Device not configured", same failure
documented in ~/system/evidence/106411/AUTHENTICATED-AZDO-MAIN-FETCH.txt and
~/system/evidence/103917-gap-closure/AUTHENTICATED-AZDO-MAIN-PROBE-2026-08-02.txt —
not new). e81db44a is the tip multiple other in-flight worktrees
(bilko-wt-106503, 106367-*, etc.) are already built from, so it's the best
available local main. No push, no deploy.
What was already known (not re-derived — read from MC #106413 + evidence/106405/fix-verdict.md §10)
FlowForge (MC #106405) already root-caused this precisely, with a documented
correction of their own first (wrong) hypothesis — see
~/.claude/projects/-Users-makinja/memory/feedback_plausible_story_is_not_diagnosis_2026-07-28.md.
First hypothesis ("banner blocks Turnstile from loading") was measured and
disproved: Turnstile is not consent-gated, loads and runs the challenge
regardless of banner state. The real mechanism, measured with
elementFromPoint at 1280x800:
Suggested fix in that evidence (not previously implemented, this ticket): give
the page bottom padding equal to banner height while visible, OR make the
banner non-blocking via pointer-events so only its own controls stay
clickable. I implemented the second option.
What was changed
apps/landing-hr/index.html (the only file touched):
.cookie-banner {
position: fixed;
left: 0;
right: 0;
bottom: 0;
z-index: 999;
background: var(--white);
border-top: 1px solid var(--border);
box-shadow: 0 -4px 24px rgba(35, 28, 51, 0.12);
padding: 20px;
display: none;
+ pointer-events: none;
}
...
.cookie-banner__text a {
color: var(--plum);
text-decoration: underline;
+ pointer-events: auto;
}
.cookie-banner__actions {
display: flex;
gap: 10px;
flex-wrap: wrap;
flex-shrink: 0;
+ pointer-events: auto;
}
(Full diff saved at time of work; see git diff on the worktree branch, lines
~1365–1415.) A comment was added above /* COOKIE CONSENT BANNER */
explaining the mechanism and why the fix takes this shape, for the next person
who touches this file.
Rationale for pointer-events over the bottom-padding alternative: the banner
is shown/hidden purely via a JS class toggle (is-visible) with no fixed,
known height (text can wrap to 2+ lines on narrow viewports — see the
@media (max-width: 640px) rule), so reserving equivalent bottom padding
would require JS to measure and re-apply the banner's live height on
show/hide/resize. Making the banner's non-control surface click-transparent is
simpler, has no JS dependency, and directly fixes the measured mechanism (the
click landing on .cookie-banner__text): a click on the plain notice text
now passes through to whatever is actually underneath it, while the two
buttons (.cookie-banner__actions) and the policy link
(.cookie-banner__text a) explicitly opt back in with pointer-events: auto
so the banner itself stays fully usable. This also fixes the broader
consequence flagged in the evidence — the banner would have swallowed clicks
on anything landing in that 84px strip, not just this one button.
Checked for a click-outside-to-dismiss or other pointer-dependent behaviour
on the banner container itself before making it pointer-events:none — the
only two listeners are click on the accept/reject buttons
(apps/landing-hr/index.html:2694-2708), which are inside
.cookie-banner__actions and remain fully interactive. No other pointer
event is attached to .cookie-banner/.cookie-banner__inner/.cookie-banner__text
directly.
Verification
-
Existing landing test suite, full run, before touching anything:
npm run test:landingequivalent (node --test tests/landing/*.test.mjs) — 29 pre-existing tests, all pass (lead-kv ×2 markets + conversion_event + turnstile-sitekey). -
New regression test added:
tests/landing/cookie-banner-click-through.test.mjs— 6 cases, static assertions against the<style>block text (no jsdom/Playwright dependency exists intests/landing/today, consistent with the existingturnstile-sitekey.test.mjspattern of plain-Nodenode --test+ regex/ string matching, no framework):- banner markup exists (sanity)
.cookie-bannercarriespointer-events: none;.cookie-banner__actionscarriespointer-events: auto;.cookie-banner__text acarriespointer-events: auto;apps/landing-ba/index.htmlandapps/landing-io/index.htmlhave no cookie-banner markup (scope confirmation, out-of-scope sites unaffected)
Result: 6/6 pass.
-
Mutation check (test must fail without the fix) — actually run, not assumed:
git stash push -- apps/landing-hr/index.html(reverting only the HTML change, test file untouched), re-ran the new test file: 3 of 6 fail — exactly the threepointer-eventsassertions (the.cookie-bannerblock,.cookie-banner__actionsblock,.cookie-banner__text ablock, each showing the pre-fix declaration body with nopointer-eventsline in the assertion diff). The 3 scope/sanity tests still pass, as expected.git stash poprestored the fix; re-ran — 6/6 pass again. -
Full landing suite after the fix + new test file, combined:
node --test tests/landing/*.test.mjs→ 35/35 pass (29 pre-existing + 6 new), 0 fail. -
Formatting:
npx prettier --check apps/landing-hr/index.html tests/landing/cookie-banner-click-through.test.mjs— clean (the new test file needed oneprettier --writepass first, applied and reverified clean). -
Not done / honest limits:
- No live browser or Playwright click-through re-test was run against a
deployed page — this worktree makes no deploy, per instruction, and CF
Pages preview isn't part of this task's scope. The fix directly targets
the measured mechanism (
elementFromPointhit =.cookie-banner__text) from the original diagnosis, and the new test pins the CSS rule that mechanism depends on, but end-to-end proof that a real click at the button's live coordinates now reaches the button (rather than passing through empty space) still needs a real/Playwright browser pass, same caveat the original diagnosis carried for the opposite reason (Turnstile blocks pure automation from completing a real submit). - No visual/screenshot evidence captured (text-only environment). If a visual check is wanted before merge, scroll the bilko.cloud lead form to the end on a fresh (no-consent) session at 1280x800 and click "Pošalji zahtjev" — it should now submit (or show the normal submit-in-flight / error state) instead of doing nothing.
- Did not touch
apps/landing-baorapps/landing-io— confirmed no banner markup there, out of scope per the original diagnosis. - No merge, no push, no deploy, no
mc.js donerun — per instruction, John verifies.
- No live browser or Playwright click-through re-test was run against a
deployed page — this worktree makes no deploy, per instruction, and CF
Pages preview isn't part of this task's scope. The fix directly targets
the measured mechanism (
Status: READY FOR REVIEW (not self-declared done)
Files changed:
/Users/makinja/business/ALAI-Holding-AS/products/bilko-wt-106413/apps/landing-hr/index.html/Users/makinja/business/ALAI-Holding-AS/products/bilko-wt-106413/tests/landing/cookie-banner-click-through.test.mjs(new)
Witness verifikacija (John, nezavisna sesija, 2026-08-02 ~12:45)
- Nezavisno pokrenuo suite u worktree-u: 35/35 pass (node --test).
- Živi browser dokaz (localhost:8106 servirana fixana stranica, Chrome):
- scenario reprodukovan: submit dugme centrom (y=1156) UNUTAR banner strip-a (banner top y=1113)
elementFromPoint→BUTTON.demo-form__submit(prije fixa:.cookie-banner__text)- sintetički klik na tim koordinatama okida button handler: TRUE
- banner Accept dugme i dalje klikabilno: TRUE
- Napomena za buduće testove: stranica ima
scroll-behavior: smooth— programmatic scroll mjerenja moraju čekati animaciju ili forsiratiauto. - NIJE deployano — CF Pages deploy je odvojen korak (veže se na #106418 git-integraciju).
No comments to display
No comments to display