phase: 85_mobile_menu_gate_overlap
All verification complete. Final report: **Phase 85 final verification pass — all green** (tasks 01–03 already complete; independently re-verified from scratch) - Verified fix in tree: `styles.css` `.auth-gate` z-index 500→15 + rewritten stacking comment (no `z-index: 500` left); `index.html`/`document.html` comment-only; `token-gate.js` docstring-only (logic byte-identical); `test_mobile_hamburger_nav.py` real-click conversion + new `test_anonymous_toggle_tappable_with_gate_up`; new `tests/unit/test_gate_header_stacking.py` (3 pins); `test_api_tokens.py` untouched - `uv run pytest` → 1717 passed, 1 warning (exit 0) - `uv run pytest --cov=app --cov-report=term-missing` → TOTAL **99%** (>90%) - E2E in isolation: `test_mobile_hamburger_nav.py` **8 passed**; `test_api_tokens.py` **9 passed** (unchanged); `test_smoke.py` **3 passed**; `test_document_viewer.py` **7 passed** - `uv run ruff check . && uv run pyright` → clean / 0 errors - Live probe (375×812, anonymous, fresh server): on `/` and `/history.html` `elementFromPoint` at toggle → SVG `path`, never `#auth-gate`; real click opens menu (`aria-expanded=true`); exactly one visible nav link (Chat) + sign-in copy; Chat link topmost over gate; `#main` inert — criteria 1, 2, 3 confirmed directly - Criteria: (1) real-click menu on / + /history ✅ (2) dropdown above gate ✅ (3) anonymous contents + #main inert ✅ (4) admin byte-identical (phase-46 tests green) ✅ (5) doc-viewer gate under bar (CSS pin + doc-viewer suite) ✅ (6) full gate green ✅ (7) diff scoped to the 5 code files + new unit test + phase files, nothing in `app/` ✅ (8) commit + todo→complete move left to harness per executor rules (task files already in `complete/`) - Note: `.agents/remediation_plan.md` (untracked) is a pre-existing artifact of the earlier security audit — left untouched; a missing "N passed" line seen mid-pass was my own `-q`+addopts `-q` = `-qq` quirk, not a defect - Next pending phase: `86_history_page_width`
This commit is contained in:
+16
-11
@@ -1631,23 +1631,28 @@ details.thinking .thinking-text ul { margin: 0 0 0.5rem; }
|
||||
/* Phase 79 (task 05): the in-app token gate — the gate surface of the
|
||||
two token-only pages (the shell + the document viewer, one shared
|
||||
.auth-gate markup each). A body-level FIXED overlay (the
|
||||
body-level doc-modal precedent): while visible it is the ONLY
|
||||
interactive surface — assets/token-gate.js locks the root (#main,
|
||||
inert) so focus and keyboard traversal stay inside the gate
|
||||
(WCAG, the inert-pair contract).
|
||||
Stacking: z-index 500 — above the app content (the sticky header is
|
||||
20, the skip-link 100) but BELOW the doc-modal (1000), which can
|
||||
only be opened from the unlocked app anyway. Solid --bg: the canvas
|
||||
+ grid texture live on <html> (the body stays transparent), so the
|
||||
overlay reads as the app's own surface — no blur (the phase-08
|
||||
perf anchor).
|
||||
body-level doc-modal precedent): while visible it is the only
|
||||
CONTENT-level interactive surface — assets/token-gate.js locks the
|
||||
root (#main, inert) so focus and keyboard traversal stay inside
|
||||
the gate (WCAG, the inert-pair contract).
|
||||
Stacking (phase 85, TODO.md L3): z-index 15 — ABOVE all app
|
||||
content (static) but BELOW the sticky header (20) and its mobile
|
||||
dropdown (21, inside the header's stacking context): the
|
||||
unauthenticated visitor keeps a reachable hamburger + menu while
|
||||
the gate still covers and locks the app content (#main stays
|
||||
inert — the lock is JS, not z-order — phase 79). The skip-link
|
||||
(100) and the 1000-family overlays (doc-modal, sync backdrop) are
|
||||
unaffected — all above 15; the doc-modal can only be opened from
|
||||
the unlocked app anyway. Solid --bg: the canvas + grid texture
|
||||
live on <html> (the body stays transparent), so the overlay reads
|
||||
as the app's own surface — no blur (the phase-08 perf anchor).
|
||||
The centered card reuses the #sources-gate visual language
|
||||
(surface card + hairline + glyph + heading + sub + action) in a
|
||||
tighter column. */
|
||||
.auth-gate {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 500;
|
||||
z-index: 15;
|
||||
display: flex; /* the card is the only in-flow child — margin: auto centers it */
|
||||
overflow-y: auto; /* short viewports: the card scrolls fully into view */
|
||||
background: var(--bg);
|
||||
|
||||
@@ -193,9 +193,13 @@ export async function mountGate(lockRoot, onAuthed) {
|
||||
|
||||
/* Anonymous: reveal the gate (drop hidden AND inert — the inert-pair
|
||||
contract), lock the app, focus the token input. The gate is the
|
||||
only interactive surface while visible: the lock root is inert,
|
||||
so Tab never reaches the locked app (the composer on the shell,
|
||||
the content on the viewer). */
|
||||
only CONTENT-level interactive surface while visible: the lock
|
||||
root is inert, so Tab never reaches the locked app (the composer
|
||||
on the shell, the content on the viewer). The header was never
|
||||
the lock root (and is never inert) — it was only visually
|
||||
covered pre-phase-85: the gate's z-index (15) now sits below the
|
||||
header (20), so the mobile hamburger + menu stay reachable while
|
||||
the app content stays inert-locked (TODO.md L3). */
|
||||
if (gate) {
|
||||
gate.hidden = false;
|
||||
gate.inert = false;
|
||||
|
||||
@@ -162,7 +162,10 @@
|
||||
root; the existing boot sequence (whoami → load content) runs
|
||||
as onAuthed — an admin (or a validly cached token user) gets
|
||||
it immediately, the gate never shows. SHIPS hidden + inert
|
||||
(the phase-16 ship-hidden pattern). -->
|
||||
(the phase-16 ship-hidden pattern). Phase 85 (TODO.md L3):
|
||||
same stacking as the shell gate — the overlay (z-index 15)
|
||||
sits below the viewer's sticky bar (20), so the hamburger +
|
||||
menu stay reachable while #main stays inert-locked. -->
|
||||
<section class="auth-gate" id="doc-auth-gate" hidden inert aria-labelledby="doc-auth-gate-title">
|
||||
<div class="auth-gate-card">
|
||||
<div class="auth-gate-glyph" aria-hidden="true">
|
||||
|
||||
+7
-3
@@ -896,9 +896,13 @@
|
||||
|
||||
<!-- Phase 79 (task 05): the in-app token gate — a body-level
|
||||
position:fixed; inset:0 overlay (the body-level doc-modal
|
||||
precedent) that is the ONLY interactive surface while visible:
|
||||
assets/token-gate.js locks #main (inert) so focus and keyboard
|
||||
traversal stay in the gate (WCAG, the inert-pair contract). It
|
||||
precedent) that is the only CONTENT-level interactive surface
|
||||
while visible: assets/token-gate.js locks #main (inert) so
|
||||
focus and keyboard traversal stay in the gate (WCAG, the
|
||||
inert-pair contract). Phase 85 (TODO.md L3): the overlay sits
|
||||
BELOW the sticky header (z-index 15 < 20) — it covers #main's
|
||||
content region visually, but the header (hamburger + menu)
|
||||
stays reachable for the unauthenticated visitor. It
|
||||
SHIPS hidden + inert (the phase-16 ship-hidden pattern) — an
|
||||
authenticated boot (admin, or a valid cached token re-authed
|
||||
silently at mount) never shows it for a frame. The gate is the
|
||||
|
||||
Reference in New Issue
Block a user