Navigation
Structure
┌──────────────────────────────────────────────────────────────────────────────┐│ [BJ] brettjohnson.xyz SPEAKER CONSULTING PODCAST MEDIA CONTACT │└──────────────────────────────────────────────────────────────────────────────┘The navigation bar is a sticky header that sits at the top of all pages. On mobile it collapses into a hamburger menu [≡].
Layout
<header className="sticky top-0 z-10 border-b border-brand-gray bg-brand-charcoal/95 backdrop-blur-sm"> <div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8"> <nav className="flex h-16 items-center justify-between"> <Logo /> <DesktopLinks /> <MobileMenuButton /> </nav> </div></header>Desktop Links
| Label | Route | Notes |
|---|---|---|
| Speaker | /speaking | Drops into services grid section on home |
| Consulting | /consulting | Links to consulting sub-section |
| Podcast | /podcast | AnglerPhish + Online Fraudcast page |
| Media | /media | Press kit and appearances |
| Training | /training | Law enforcement training portal |
| Contact | /contact | Booking form and Calendly |
Active state: border-b-2 border-brand-red text-white (underline in red).
Default state: text-white/70 hover:text-white transition-colors.
Mobile Navigation
Breakpoint: < md (768px). The desktop link list is hidden; a hamburger button appears.
On toggle, a full-width dropdown slides down:
┌──────────────────────────────┐│ [BJ] brettjohnson.xyz [✕] │├──────────────────────────────┤│ SPEAKER ││ CONSULTING ││ PODCAST ││ MEDIA ││ TRAINING ││ CONTACT │└──────────────────────────────┘- Background:
bg-brand-charcoal - Each link:
py-4 px-6 text-base font-semibold border-b border-brand-gray - Active:
text-brand-red
Accessibility
- Nav uses
<nav aria-label="Main navigation"> - Mobile toggle button uses
aria-expandedandaria-controls - Active page link uses
aria-current="page" - Focus trap is active while mobile menu is open
Scroll Behavior
The nav background starts fully transparent on the hero section and transitions to bg-brand-charcoal/95 backdrop-blur-sm after scrolling past 60px.
const [scrolled, setScrolled] = useState(false);
useEffect(() => { const handleScroll = () => setScrolled(window.scrollY > 60); window.addEventListener('scroll', handleScroll, { passive: true }); return () => window.removeEventListener('scroll', handleScroll);}, []);