Rule handbook metadata
- Rule
DET.NAV.DEPTH· lanedeterministic- Page status
- current
- page_version
bd3562025ebc5525d93f3f5d235936a70a33683cf2056afc850e561df77f8aee- generated_at
- 2026-05-25T18:00:00.000Z
- registry_fingerprint
2ce40848effce579d3e4879f6ca85535183a14db201870a6c007da424624550c
How this rule is fixed
Pilot deterministic fixer: handbook_after · harness mode standalone · verify expect_rule_clean.
- Harness:
apply-harness-fixture-remediation.pycopies the After example HTML from this handbook page onto the defect fixture, theninvoke-det-ruleset-remediation-verify.shre-audits and expects zero findings for this rule. - Production sites:
run-website-ux-remediation-loop.shrunshandbook_html_patch(HTML patches inlib/ux-deterministic-fixers/fixers/patches/) before invoking the Cursor agent when the quality gate still fails.
Detection module: docs/design/ux-audit/deterministic-design-rules.md#det-nav-depth. Scroll down for Before / After examples and Evidence and remediation steps.
Purpose
Curated global navigation (Kpn, nav.fs-primary-nav-global; marketing landing-nav) must stay shallow so first-time visitors scan one horizon of site IA. Nested flyouts beyond top level + one tier force hover chains, obscure keyboard paths, and compete with handbook side rails (Ksr) that are designed for deep section trees.
This deterministic rule runs during the metrics phase. Playwright evaluates visible nav roots outside main matching:
nav.fs-primary-nav-global,[data-ks-hash="Kpn"]nav.landing-nav,header.landing-header .landing-navheader.site-header nav[aria-label*="Site navigation" i]
It measures list depth — nested ul, ol, or [role="menu"] tiers containing a[href] — and applies caps from det-nav-depth.check.js:
| Pattern | Max list depth |
|---|---|
| Standard global nav (no mega-menu marker) | 2 |
Explicit mega-menu (.fs-mega-menu, .fs-mega-nav, [data-fs-mega-menu], etc.) |
4 |
Excluded subtrees: theme preference dropdowns (.forge-theme-dropdown, .forge-theme-menu, [data-forge-pref]) — not primary IA.
Sidebar / offcanvas doc rails (aside.forge-sidebar, #ks-sidebar-aside, .fs-sidebar, Ksr) are not global-nav roots; deep handbook trees there are expected and do not satisfy this rule by themselves if the masthead still nests flyouts.
Plan: Audit global chrome selectors and list nesting before shipping HTML. Do: Keep Kpn / landing-nav to curated top-level links plus at most one fs-nav-dropdown or Bootstrap dropdown-menu tier; relocate handbook depth to Ksr or mobile Kco offcanvas. Check: navDepthReport.violations is empty and maxListDepth ≤ 2 (or ≤ 4 with mega-menu marker). Adjust: Flatten nested <ul> flyouts; adopt mega-menu contract only when columnar IA is intentional per Kpn.
Passing signals
Kpn(nav.fs-primary-nav-global) exposes flat primary links (Overview, Trust, Quickstart) with zero or one flyout tier viafs-nav-dropdown(data-fs-nav-dropdown,.fs-nav-dropdown__trigger,.fs-nav-dropdown__panel-inner) or a single.dropdown-menu—list_depth ≤ 2.landing-navonlanding_page/marketing_pageuses horizontal.landing-nav-linkanchors or one dropdown panel — no nested<ul>chains inside the global root.- Deep section IA lives in
Ksr(aside.forge-sidebar,#ks-sidebar-aside,.fs-sidebar) orKcooffcanvas (#fsNav) — outside the global-nav depth budget. - When a mega-menu is justified, root includes
.fs-mega-menu/[data-fs-mega-menu]and total list depth stays ≤ 4. - Theme / preference menus (
.forge-theme-menu) do not inflate primary-nav depth metrics. - Evidence shape:
nav_depth list_depth=2 max=2 mega=no kind=nested-flyout-depthabsent; report showsmaxListDepthwithin cap.
Failing signals
nested-flyout-depth— global nav nests<ul>inside<ul>inside<ul>(list depth 3+) without a mega-menu marker; common smell: full handbook tree copied intolanding-navorKpn.mega-depth-exceeded— mega-menu marker present but list depth > 4 (column stacks or recursive flyouts still too deep).- Nested flyouts in
.site-header navon showcase/handbook shells whenKsralready carries the same tree — often co-failsDET.NAV.DEDUPandDET.CONTEXT.BURDEN. - Keyboard/hover traps: third-tier links only reachable through chained
:hoverpanels onfs-primary-nav-global. - Severity escalates to major when depth exceeds cap by more than one tier (
list_depth > max + 1). - Evidence shape:
nav_depth list_depth=4 max=2 mega=no kind=nested-flyout-depth hint="nav.landing-nav".
Before example
Before (failing example)
Global nav list_depth=4 — auditor flags nested-flyout-depth on nav.landing-nav.
Failing KS markup: landing-nav nests four list tiers (handbook-style tree in global chrome) — exceeds the primary-nav budget of 2 without a mega-menu pattern.
After example
After (passing example)
Global nav list_depth=2; deep IA in Ksr — passes DET.NAV.DEPTH.
Passing KS markup: shallow Kpn with one fs-nav-dropdown tier; deep handbook links live in Ksr sidebar (outside global-nav roots).
Evidence and remediation
Evidence: Playwright collectNavDepthReport → metrics.navDepthReport with navRootCount, maxListDepth, hasMegaMenu, and violations[] (kind, listDepth, maxAllowed, selectorHint). Findings cite nav_depth list_depth=N max=M mega=yes|no kind=nested-flyout-depth|mega-depth-exceeded hint="nav.fs-primary-nav-global".
Remediate (in order):
- Flatten masthead flyouts — remove nested
<ul>chains fromKpn/landing-nav; keep at most onefs-nav-dropdownor.dropdown-menutier per top-level item. - Relocate handbook trees — move section links into
Ksr(aside.forge-sidebar,.fs-sidebar) orKcooffcanvas; pair withKbcbreadcrumb for orientation (DET.NAV.BREADCRUMB). - Adopt mega-menu deliberately — when columnar IA is required, add
.fs-mega-menu/[data-fs-mega-menu]per Kpn contract and cap column depth at 4 list tiers; do not use mega-menu to hide uncurated link walls. - De-duplicate bands — if the same deep tree appears in global nav and sidebar, remove the masthead copy (
DET.NAV.DEDUP). - Verify focus order — after flattening, re-check keyboard traversal through
fs-nav-dropdown__triggerand panels (DET.NAV.FOCUS_ORDER). - Re-run
analyze-website-ux.mjs; for harness fixtures useauditor-tests/invoke-det-ruleset-harness.sh --only-rule DET.NAV.DEPTH.