Skip to main content

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:

  • .cookie-banner is position: fixed; bottom: 0; z-index: 999, occupying the bottom ~84px of the viewport (measured y 715.6–800).
  • Submit button scrolled to viewport centre → hit = the button itself, not covered.
  • Submit button scrolled to the end of the form (its natural resting position after a visitor reads through the form) → button rect y 754.6–799.6, entirely inside the banner strip → elementFromPoint returns .cookie-banner__text, not the button.
  • The click goes to the banner, the submit handler never runs → zero feedback (no error, no spinner, no message). Dismissing the banner ("Samo nužni") removes the overlay and the same submit works immediately.
  • Scope: bilko.cloud (apps/landing-hr/index.html) only. Confirmed by grep: class="cookie-banner" markup exists nowhere in apps/landing-ba/index.html or apps/landing-io/index.html — those two sites have no banner and no interception.

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

  1. Existing landing test suite, full run, before touching anything: npm run test:landing equivalent (node --test tests/landing/*.test.mjs) — 29 pre-existing tests, all pass (lead-kv ×2 markets + conversion_event + turnstile-sitekey).

  2. 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 in tests/landing/ today, consistent with the existing turnstile-sitekey.test.mjs pattern of plain-Node node --test + regex/ string matching, no framework):

    • banner markup exists (sanity)
    • .cookie-banner carries pointer-events: none;
    • .cookie-banner__actions carries pointer-events: auto;
    • .cookie-banner__text a carries pointer-events: auto;
    • apps/landing-ba/index.html and apps/landing-io/index.html have no cookie-banner markup (scope confirmation, out-of-scope sites unaffected)

    Result: 6/6 pass.

  3. 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 three pointer-events assertions (the .cookie-banner block, .cookie-banner__actions block, .cookie-banner__text a block, each showing the pre-fix declaration body with no pointer-events line in the assertion diff). The 3 scope/sanity tests still pass, as expected. git stash pop restored the fix; re-ran — 6/6 pass again.

  4. Full landing suite after the fix + new test file, combined: node --test tests/landing/*.test.mjs35/35 pass (29 pre-existing + 6 new), 0 fail.

  5. Formatting: npx prettier --check apps/landing-hr/index.html tests/landing/cookie-banner-click-through.test.mjs — clean (the new test file needed one prettier --write pass first, applied and reverified clean).

  6. 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 (elementFromPoint hit = .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-ba or apps/landing-io — confirmed no banner markup there, out of scope per the original diagnosis.
    • No merge, no push, no deploy, no mc.js done run — per instruction, John verifies.

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)
    • elementFromPointBUTTON.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 forsirati auto.
  • NIJE deployano — CF Pages deploy je odvojen korak (veže se na #106418 git-integraciju).