Skip to content

Pass 1 follow-ups: sticky header + mobile scroll lock + docs#1

Merged
blackbrowed-labs merged 3 commits into
mainfrom
dev
Apr 24, 2026
Merged

Pass 1 follow-ups: sticky header + mobile scroll lock + docs#1
blackbrowed-labs merged 3 commits into
mainfrom
dev

Conversation

@larsweiser
Copy link
Copy Markdown
Collaborator

Summary

Three post-Pass-1 follow-ups, verified on dev.blackbrowedlabs.com.

  • 15cbd20 — Lock body scroll while mobile menu is open. body.menu-open { overflow: hidden } gated to <768px, focus management (move into panel on open, return to hamburger on Escape/tap-outside), focus trap (Tab/Shift+Tab cycle), auto-close on resize to desktop. No position: fixed — scroll position is preserved through open→close cycle.
  • da5cef7 — SiteHeader sticky. position: sticky; top: 0; z-index: 50. Opaque var(--color-bg) background, hairline bottom border preserved. scroll-padding-top: 5rem on html so the skip-link target (and any future anchor) lands below the sticky header.
  • deabf17 — Docs-only. Adds docs/TECH_STACK.md §8.4 documenting repo visibility (public as of 2026-04-23), gitleaks pre-flip procedure, and the protect-main / protect-dev branch protection rulesets. Trims §2.1 to cross-reference §8.4.

Test plan

Already completed on dev.blackbrowedlabs.com:

  • Sticky header pinned to viewport top on all four pages × light/dark × mobile/tablet/desktop
  • Skip-link activates → #main lands below the sticky header, not behind it
  • Mobile menu: body scroll locked while open, scroll position preserved on close, focus management, Tab cycles within panel, resize to desktop auto-closes, prefers-reduced-motion honored
  • Desktop: no hamburger, no scroll lock, nav always visible
  • Playwright smoke test (plans/diagnose-mobile-menu.mjs): 12/12 pass

Post-merge on production (I'll run once deploy completes):

  • Apex 200; email MX/SPF/DKIM/DMARC unchanged from Pass 1 baseline
  • Dark-mode --color-bg alias still live
  • Sticky + scroll-lock behave identically to staging

blackbrowed-labs and others added 3 commits April 24, 2026 09:17
Adds §8.4 covering:
- Repository visibility: public as of 2026-04-23, post secret scan
- Pre-flip secret scan procedure (gitleaks)
- Branch protection rulesets: protect-main and protect-dev
- Rationale for deferring the required-status-checks toggle to Pass 2

Also trims §2.1's visibility bullet to cross-reference §8.4 instead of
duplicating the pre-flip scan procedure.

Also adds Pass 2 backlog item #5 for adding a PR-triggered CI workflow
that can serve as the required status check once in place (backlog file
itself is under plans/ and gitignored — this commit is docs-only).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- SiteHeader.astro: change .site-header from position: relative to
  position: sticky; top: 0; z-index: 50. Keeps the hairline bottom
  border. Background is already opaque (var(--color-bg)) — header will
  not show through to scrolled content.
- global.css: add scroll-padding-top: 5rem to html so the "Skip to
  main content" link's target (#main) lands below the sticky header
  instead of behind it. Also covers any future anchor jumps.

No JS, no scroll-driven effects, no frosted/translucent surface —
plain position: sticky per CLAUDE_DESIGN_BRIEF §8 (paper before screen,
no ornament). No animation, so prefers-reduced-motion is unaffected.

Z-index 50 sits above the in-header mobile-nav panel (10) and
ThemeToggle menu (20), well below the SkipLink (1000) so the skip
link stays visible on focus.

sticky also qualifies as a "positioned" value, so the mobile nav
panel's `position: absolute; top: 100%` still anchors to the header
correctly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Standard mobile modal pattern: when the hamburger menu is open, body
scrolling is disabled via `body.menu-open { overflow: hidden }` gated
to mobile breakpoints only. Preserves scroll position on close
(no position: fixed reset).

Includes focus management (move to first nav item on open, return to
hamburger on close via Escape or tap-outside), focus trap within the
menu panel (Tab / Shift+Tab cycle), aria-expanded toggling on the
hamburger button, and auto-close if the viewport resizes to desktop
while the menu is still open. Honors prefers-reduced-motion (the menu
has no transitions, so nothing to disable beyond the existing global
@media gate in global.css).

Desktop nav unaffected — always visible, never locks body scroll.

Smoke-tested via plans/diagnose-mobile-menu.mjs (Playwright, 360px
viewport): 12/12 checks pass covering class toggle, aria-expanded,
body overflow state, nav data-open, focus placement, scroll
preservation, Escape/focus-restore, focus trap, resize auto-close,
and desktop no-op gating.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@blackbrowed-labs blackbrowed-labs merged commit d00d6f1 into main Apr 24, 2026
1 check passed
blackbrowed-labs added a commit that referenced this pull request Apr 28, 2026
Reconciles the squash-merge commit d00d6f1 (Pass 1 follow-ups PR #1)
that landed on main on 2026-04-24 with the original commits on dev.
Conflict in src/components/SiteHeader.astro resolved by keeping dev's
typed-locals form from 78c0202 (TS strict-mode fix) — main's squash
predates that fix.

Pre-step for the natural Pass 2 dev → main release PR (#4) so the merge
becomes a clean fast-forward instead of carrying a conflict into review.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
blackbrowed-labs added a commit that referenced this pull request Apr 28, 2026
- src/worker/index.ts: entry router; POST /api/contact → dynamic
  import of ./contact handler, otherwise fall through to ASSETS.fetch.
- src/worker/contact.ts: seven-step handler — parse → honeypot drop
  → rate-limit → Turnstile siteverify (graceful no-JS path) →
  validation → mimetext + EmailMessage send via cloudflare:email →
  303 redirect with locale-aware _returnTo allowlist.
- src/worker/env-augment.d.ts: patches CONTACT_RATELIMIT (RateLimit)
  + TURNSTILE_SECRET_KEY (Worker secret) into the global Env until
  wrangler types emits them automatically.
- worker-configuration.d.ts: committed per ad-hoc team decision —
  reproducible types in CI without a build-time wrangler dep.
- wrangler.jsonc: per-env main, assets.binding=ASSETS, send_email,
  ratelimit (CONTACT_RATELIMIT), vars.TURNSTILE_SITE_KEY,
  compatibility_flags=[nodejs_compat]; leading comment refreshed to
  reflect the hybrid Workers + Static Assets posture.
- package.json: add mimetext@^3.0.28 runtime dep.

Worker is unverified at runtime until G B.1.3a staging smoke
(A12 §9 UNVERIFIED #1: cross-zone send_email).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
larsweiser pushed a commit that referenced this pull request Apr 28, 2026
- src/worker/index.ts: entry router; POST /api/contact → dynamic
  import of ./contact handler, otherwise fall through to ASSETS.fetch.
- src/worker/contact.ts: seven-step handler — parse → honeypot drop
  → rate-limit → Turnstile siteverify (graceful no-JS path) →
  validation → mimetext + EmailMessage send via cloudflare:email →
  303 redirect with locale-aware _returnTo allowlist.
- src/worker/env-augment.d.ts: patches CONTACT_RATELIMIT (RateLimit)
  + TURNSTILE_SECRET_KEY (Worker secret) into the global Env until
  wrangler types emits them automatically.
- worker-configuration.d.ts: committed per ad-hoc team decision —
  reproducible types in CI without a build-time wrangler dep.
- wrangler.jsonc: per-env main, assets.binding=ASSETS, send_email,
  ratelimit (CONTACT_RATELIMIT), vars.TURNSTILE_SITE_KEY,
  compatibility_flags=[nodejs_compat]; leading comment refreshed to
  reflect the hybrid Workers + Static Assets posture.
- package.json: add mimetext@^3.0.28 runtime dep.

Worker is unverified at runtime until G B.1.3a staging smoke
(A12 §9 UNVERIFIED #1: cross-zone send_email).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
blackbrowed-labs added a commit that referenced this pull request Apr 29, 2026
…failures" design

Adds verify-cloudflare-facts.yml weekly cron workflow + scripts/checks/dpf.mjs
+ scripts/checks/cwa-retention.mjs + 6 fixtures + scripts/run-verifier.mjs
orchestrator. Extends scripts/check-cloudflare-facts-freshness.mjs to read
_meta.last_check_attempt with 30-day threshold (down from 90).

Migrates src/data/cloudflare-facts.json to verifier-era schema (schema_version
1; per-fact status + value fields; _meta block; structured cwa_retention with
integer month values; raw_events_retention_months explicitly null per
Cloudflare's documented absence). Updates src/lib/cloudflare-facts.ts type +
adds getEffectiveVerifiedDate helper (worst-case freshness signal: older of
the two per-fact verified_at). Privacy pages (datenschutz.astro, en/privacy.astro)
read via the helper.

Verifier shape per plans/active/pass-2/g-d-2/spec.md: 1/5/15-min retry budget
(21 min total, fits 30-min workflow timeout); status-return error handling
(no throws cross check boundaries); explicit registry per spec §9.6;
hand-written validator per §9.7; status-enum rename ('ok' CheckResult →
'active' JSON) per §6.2; v1-coverage smoke step inside verifier workflow only,
mode #8 deploy-triggered limitation acknowledged per §3.8.

All synthetic failure modes (#2, #4, #5, #6) verified via MOCK_SCENARIO=
fixture routing. Mode #1 (freshness gate) verified via stale last_check_attempt.
Modes #3, #7, #8, #9 deferred to controller-side post-commit per prompt's
"may defer" guidance. Outcome record at
plans/active/pass-2/g-d-7/verifier-test-matrix.md (workspace, gitignored).

Closes backlog #8.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants