Files
avbeat-com/src/components/Header.tsx
Ryan Salazar (via Claude) 52fe7bceb6 slice 4: accent palette refinement — blue → teal
Replace the four accent-family hex codes site-wide with the teal palette
(keeps the dark theme; only swaps the accent family, not the dark base):

  #3b82f6 (accent primary CTA)   → #5B7C8D  (teal)        [839×]
  #2563eb (accent-dark / hover)  → #4A6473  (darker teal) [44×]
  #60a5fa (info link, lighter)   → #8FB0C3  (mid teal)    [68×]
  #1e3a5f (accent-muted bg)      → #2F4F5F  (navy)        [44×]

tailwind.config.js tokens updated to match (accent/accent-dark/accent-muted).
Sweep also covers tailwind.css. 108 files touched. The dark base (#0d0d0d,
#111, #161616, #1a1a1a etc.) is intentionally untouched.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 23:33:04 +00:00

574 lines
30 KiB
TypeScript

"use client";
import React, { useState, useEffect, useRef } from "react";
import Link from "next/link";
import { useRouter } from "next/navigation";
import AppImage from "@/components/ui/AppImage";
import {
LinkedInIcon,
InstagramIcon,
FacebookIcon,
RssIcon,
MenuIcon,
CloseIcon,
SearchIcon,
} from "@/components/ui/Icons";
import { createClient } from "@/lib/supabase/client";
import NotificationCenter from "@/components/NotificationCenter";
import LanguageSwitcher from "@/components/LanguageSwitcher";
import AdImage from "@/components/AdImage";
import EventsDropdown from "@/components/EventsDropdown";
import AboutDropdown from "@/components/AboutDropdown";
import { ADS_728X90, shuffle } from "@/lib/ads";
interface NavItem {
label: string;
href: string;
dropdown?: { label: string; href: string }[];
}
const navLinks: NavItem[] = [
{ label: "Newsletter", href: "/newsletter" },
{ label: "Forum", href: "/forum" },
];
export default function Header() {
const router = useRouter();
const [scrolled, setScrolled] = useState(false);
const [mobileOpen, setMobileOpen] = useState(false);
const [searchQuery, setSearchQuery] = useState("");
const [searchFocused, setSearchFocused] = useState(false);
const submitSearch = () => {
const q = searchQuery.trim();
if (!q) return;
setMobileOpen(false);
router.push(`/search?q=${encodeURIComponent(q)}`);
};
const [currentUserId, setCurrentUserId] = useState<string | null>(null);
const [currentUserEmail, setCurrentUserEmail] = useState<string | null>(null);
const [isAdmin, setIsAdmin] = useState(false);
const [subEmail, setSubEmail] = useState("");
const [subStatus, setSubStatus] = useState<"idle" | "loading" | "success" | "error">("idle");
const [subMessage, setSubMessage] = useState("");
const searchRef = useRef<HTMLInputElement>(null);
const mobileMenuRef = useRef<HTMLDivElement>(null);
const hamburgerRef = useRef<HTMLButtonElement>(null);
const navLinksRef = useRef<(HTMLAnchorElement | null)[]>([]);
useEffect(() => {
const handler = () => setScrolled(window.scrollY > 60);
window.addEventListener("scroll", handler, { passive: true });
return () => window.removeEventListener("scroll", handler);
}, []);
useEffect(() => {
const supabase = createClient();
const ADMIN_ROLES = new Set([
"administrator", "admin", "super_admin", "editor", "support",
]);
const refreshAdmin = async (userId: string | null) => {
if (!userId) { setIsAdmin(false); return; }
const { data } = await supabase
.from("user_profiles")
.select("role")
.eq("id", userId)
.maybeSingle();
setIsAdmin(!!data?.role && ADMIN_ROLES.has(data.role));
};
supabase.auth.getUser().then(({ data: { user } }) => {
setCurrentUserId(user?.id || null);
setCurrentUserEmail(user?.email || null);
refreshAdmin(user?.id || null);
});
const { data: { subscription } } = supabase.auth.onAuthStateChange((_event, session) => {
setCurrentUserId(session?.user?.id || null);
setCurrentUserEmail(session?.user?.email || null);
refreshAdmin(session?.user?.id || null);
});
return () => subscription.unsubscribe();
}, []);
// Global keyboard shortcuts
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
const tag = document.activeElement?.tagName;
const isInput = tag === "INPUT" || tag === "TEXTAREA";
// "/" to focus search
if (e.key === "/" && !isInput) {
e.preventDefault();
searchRef.current?.focus();
}
// Cmd/Ctrl+Shift+A — open AI Console
if ((e.metaKey || e.ctrlKey) && e.shiftKey && e.key === "A") {
e.preventDefault();
window.location.href = "/dashboard/ai-console";
}
// Escape: close mobile menu or clear search
if (e.key === "Escape") {
if (mobileOpen) {
setMobileOpen(false);
hamburgerRef.current?.focus();
} else if (searchFocused) {
setSearchQuery("");
searchRef.current?.blur();
}
}
};
window.addEventListener("keydown", handleKeyDown);
return () => window.removeEventListener("keydown", handleKeyDown);
}, [searchFocused, mobileOpen]);
// Arrow key navigation for desktop nav links
const handleNavKeyDown = (e: React.KeyboardEvent, index: number, refs: React.MutableRefObject<(HTMLAnchorElement | null)[]>) => {
const items = refs.current.filter(Boolean);
if (e.key === "ArrowRight" || e.key === "ArrowDown") {
e.preventDefault();
const next = items[(index + 1) % items.length];
next?.focus();
} else if (e.key === "ArrowLeft" || e.key === "ArrowUp") {
e.preventDefault();
const prev = items[(index - 1 + items.length) % items.length];
prev?.focus();
} else if (e.key === "Home") {
e.preventDefault();
items[0]?.focus();
} else if (e.key === "End") {
e.preventDefault();
items[items.length - 1]?.focus();
}
};
// Trap focus inside mobile menu when open
useEffect(() => {
if (!mobileOpen) return;
const menu = mobileMenuRef.current;
if (!menu) return;
const focusable = menu.querySelectorAll<HTMLElement>(
'a[href], button, input, [tabindex]:not([tabIndex="-1"])'
);
const first = focusable[0];
const last = focusable[focusable.length - 1];
first?.focus();
const trap = (e: KeyboardEvent) => {
if (e.key !== "Tab") return;
if (e.shiftKey) {
if (document.activeElement === first) {
e.preventDefault();
last?.focus();
}
} else {
if (document.activeElement === last) {
e.preventDefault();
first?.focus();
}
}
};
menu.addEventListener("keydown", trap);
return () => menu.removeEventListener("keydown", trap);
}, [mobileOpen]);
const handleSubscribe = async (e: React.FormEvent) => {
e.preventDefault();
if (!subEmail || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(subEmail)) {
setSubStatus("error");
setSubMessage("Enter a valid email");
return;
}
setSubStatus("loading");
try {
const res = await fetch("/api/newsletter/subscribe", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email: subEmail, topics: [] }),
});
if (res.ok) {
setSubStatus("success");
setSubMessage("You're subscribed!");
setSubEmail("");
setTimeout(() => setSubStatus("idle"), 4000);
} else {
const data = await res.json();
setSubStatus("error");
setSubMessage(data?.error || "Failed. Try again.");
setTimeout(() => setSubStatus("idle"), 3000);
}
} catch {
setSubStatus("error");
setSubMessage("Network error. Try again.");
setTimeout(() => setSubStatus("idle"), 3000);
}
};
return (
<>
{/* TOP BAR */}
<div className="bg-[#1a2535] border-b border-[#2a3a50]">
<div className="max-w-container mx-auto px-4 h-8 flex items-center justify-between">
<p className="text-[#999999] text-xs font-body hidden sm:block">
News & Intelligence for Broadcast, Post-Production & Streaming Technology
</p>
<div className="flex items-center gap-3 ml-auto">
<a href="https://linkedin.com/company/broadcastbeat" target="_blank" rel="noopener noreferrer" aria-label="BroadcastBeat on LinkedIn"
className="text-[#999] hover:text-[#5B7C8D] focus:text-[#5B7C8D] focus:outline-none focus-visible:ring-1 focus-visible:ring-[#5B7C8D] transition-colors social-icon">
<LinkedInIcon size={14} />
</a>
<a href="https://instagram.com/broadcastbeat" target="_blank" rel="noopener noreferrer" aria-label="BroadcastBeat on Instagram"
className="text-[#999] hover:text-[#5B7C8D] focus:text-[#5B7C8D] focus:outline-none focus-visible:ring-1 focus-visible:ring-[#5B7C8D] transition-colors social-icon">
<InstagramIcon size={14} />
</a>
<a href="https://facebook.com/broadcastbeat" target="_blank" rel="noopener noreferrer" aria-label="BroadcastBeat on Facebook"
className="text-[#999] hover:text-[#5B7C8D] focus:text-[#5B7C8D] focus:outline-none focus-visible:ring-1 focus-visible:ring-[#5B7C8D] transition-colors social-icon">
<FacebookIcon size={14} />
</a>
<a href="/rss" aria-label="BroadcastBeat RSS Feed" className="text-[#999] hover:text-[#5B7C8D] focus:text-[#5B7C8D] focus:outline-none focus-visible:ring-1 focus-visible:ring-[#5B7C8D] transition-colors social-icon">
<RssIcon size={14} />
</a>
<div className="w-px h-3.5 bg-[#333] mx-1" />
{/* Language Switcher — Section 18B */}
<LanguageSwitcher compact />
<div className="w-px h-3.5 bg-[#333] mx-1" />
{/* Sign In / Register removed — PR firms now authenticate at
distribution.relevantmediaproperties.com; /wp-login,
/wp-admin, /login redirect there from middleware. */}
{currentUserId && (
<Link href="/account" className="text-[#999] hover:text-[#5B7C8D] focus:text-[#5B7C8D] focus:outline-none focus-visible:ring-1 focus-visible:ring-[#5B7C8D] transition-colors text-xs font-body font-bold uppercase tracking-wider">
My Profile
</Link>
)}
{isAdmin && (
<>
<Link href="/admin/import" className="text-[#999] hover:text-[#5B7C8D] focus:text-[#5B7C8D] focus:outline-none focus-visible:ring-1 focus-visible:ring-[#5B7C8D] transition-colors text-xs font-body font-bold uppercase tracking-wider">
WP Import
</Link>
<Link href="/admin/articles" className="text-[#999] hover:text-[#5B7C8D] focus:text-[#5B7C8D] focus:outline-none focus-visible:ring-1 focus-visible:ring-[#5B7C8D] transition-colors text-xs font-body font-bold uppercase tracking-wider">
Articles
</Link>
<Link href="/dashboard/editorial" className="text-[#999] hover:text-[#5B7C8D] focus:text-[#5B7C8D] focus:outline-none focus-visible:ring-1 focus-visible:ring-[#5B7C8D] transition-colors text-xs font-body font-bold uppercase tracking-wider">
Editorial
</Link>
<Link href="/admin/newsletter" className="text-[#999] hover:text-[#5B7C8D] focus:text-[#5B7C8D] focus:outline-none focus-visible:ring-1 focus-visible:ring-[#5B7C8D] transition-colors text-xs font-body font-bold uppercase tracking-wider">
Newsletter
</Link>
{/* TOOLS dropdown — admin tools consolidated */}
<div className="relative group/tools">
<button
type="button"
aria-haspopup="true"
className="text-[#999] hover:text-[#5B7C8D] focus:text-[#5B7C8D] focus:outline-none focus-visible:ring-1 focus-visible:ring-[#5B7C8D] transition-colors text-xs font-body font-bold uppercase tracking-wider inline-flex items-center gap-1">
Tools
<svg width="9" height="9" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" aria-hidden="true">
<polyline points="6 9 12 15 18 9" />
</svg>
</button>
<div
role="menu"
aria-label="Admin tools"
className="absolute right-0 top-full min-w-[200px] bg-[#0d0d0d] border border-[#252525] shadow-xl rounded-sm py-1 opacity-0 invisible translate-y-1 group-hover/tools:opacity-100 group-hover/tools:visible group-hover/tools:translate-y-0 group-focus-within/tools:opacity-100 group-focus-within/tools:visible group-focus-within/tools:translate-y-0 transition-all duration-150 z-50">
<Link href="/admin/users" role="menuitem" className="block px-4 py-2 text-xs font-body text-[#bbb] hover:bg-[#1a1a1a] hover:text-[#5B7C8D] focus:outline-none focus-visible:bg-[#1a1a1a] focus-visible:text-[#5B7C8D] uppercase tracking-wider transition-colors">Users</Link>
<Link href="/admin/analytics" role="menuitem" className="block px-4 py-2 text-xs font-body text-[#bbb] hover:bg-[#1a1a1a] hover:text-[#5B7C8D] focus:outline-none focus-visible:bg-[#1a1a1a] focus-visible:text-[#5B7C8D] uppercase tracking-wider transition-colors">Analytics</Link>
<Link href="/admin/audit-log" role="menuitem" className="block px-4 py-2 text-xs font-body text-[#bbb] hover:bg-[#1a1a1a] hover:text-[#5B7C8D] focus:outline-none focus-visible:bg-[#1a1a1a] focus-visible:text-[#5B7C8D] uppercase tracking-wider transition-colors">Audit Log</Link>
<Link href="/admin/notifications" role="menuitem" className="block px-4 py-2 text-xs font-body text-[#bbb] hover:bg-[#1a1a1a] hover:text-[#5B7C8D] focus:outline-none focus-visible:bg-[#1a1a1a] focus-visible:text-[#5B7C8D] uppercase tracking-wider transition-colors">Notifications</Link>
<Link href="/admin/forum-seed" role="menuitem" className="block px-4 py-2 text-xs font-body text-[#bbb] hover:bg-[#1a1a1a] hover:text-[#5B7C8D] focus:outline-none focus-visible:bg-[#1a1a1a] focus-visible:text-[#5B7C8D] uppercase tracking-wider transition-colors">Forum Seed</Link>
<Link href="/admin/company-tracker" role="menuitem" className="block px-4 py-2 text-xs font-body text-[#bbb] hover:bg-[#1a1a1a] hover:text-[#5B7C8D] focus:outline-none focus-visible:bg-[#1a1a1a] focus-visible:text-[#5B7C8D] uppercase tracking-wider transition-colors">Company Tracker</Link>
<Link href="/dashboard/show-calendar" role="menuitem" className="block px-4 py-2 text-xs font-body text-[#bbb] hover:bg-[#1a1a1a] hover:text-[#5B7C8D] focus:outline-none focus-visible:bg-[#1a1a1a] focus-visible:text-[#5B7C8D] uppercase tracking-wider transition-colors">Show Calendar</Link>
<Link href="/dashboard/ai-console" role="menuitem" className="block px-4 py-2 text-xs font-body text-[#5B7C8D] hover:bg-[#1a1a1a] hover:text-blue-300 focus:outline-none focus-visible:bg-[#1a1a1a] focus-visible:text-blue-300 uppercase tracking-wider transition-colors">AI Console</Link>
<Link href="/admin/banned-terms" role="menuitem" className="block px-4 py-2 text-xs font-body text-[#bbb] hover:bg-[#1a1a1a] hover:text-[#5B7C8D] focus:outline-none focus-visible:bg-[#1a1a1a] focus-visible:text-[#5B7C8D] uppercase tracking-wider transition-colors">Banned Terms</Link>
</div>
</div>
<Link href="/admin" className="text-[#5B7C8D] hover:text-blue-300 focus:text-blue-300 focus:outline-none focus-visible:ring-1 focus-visible:ring-[#5B7C8D] transition-colors text-xs font-body font-bold uppercase tracking-wider">
Dashboard
</Link>
</>
)}
{/* Inline Email Subscription Form */}
{subStatus === "success" ? (
<span className="text-[#5B7C8D] text-xs font-body font-bold whitespace-nowrap">{subMessage}</span>
) : (
<form onSubmit={handleSubscribe} className="flex items-center gap-1" aria-label="Newsletter subscription">
<input
type="email"
value={subEmail}
onChange={(e) => setSubEmail(e.target.value)}
placeholder="your@email.com"
aria-label="Email address for newsletter"
disabled={subStatus === "loading"}
className="h-5 px-2 text-[11px] bg-[#0d1520] border border-[#2a3a50] text-[#ccc] placeholder-[#555] rounded focus:outline-none focus:border-[#5B7C8D] focus-visible:ring-1 focus-visible:ring-[#5B7C8D] w-32 disabled:opacity-50 transition-colors"
/>
<button
type="submit"
disabled={subStatus === "loading"}
className="h-5 px-2.5 text-[11px] font-body font-bold uppercase tracking-wider bg-[#5B7C8D] hover:bg-[#4A6473] text-white rounded disabled:opacity-50 transition-colors whitespace-nowrap focus:outline-none focus-visible:ring-1 focus-visible:ring-white focus-visible:ring-offset-1 focus-visible:ring-offset-[#5B7C8D]"
>
{subStatus === "loading" ? "..." : "Subscribe"}
</button>
{subStatus === "error" && (
<span className="text-red-400 text-[10px] whitespace-nowrap">{subMessage}</span>
)}
</form>
)}
</div>
</div>
</div>
{/* MAIN NAV */}
<div className={`sticky top-0 z-50 transition-shadow duration-200 ${scrolled ? "shadow-nav" : ""}`}>
<nav className="bg-[#111111] border-b border-[#252525]" role="navigation" aria-label="Main navigation">
<div className="max-w-container mx-auto px-4">
<div className="flex items-center justify-between h-[60px] gap-4">
{/* Logo */}
<Link href="/home-page" className="flex-shrink-0 focus:outline-none focus-visible:ring-2 focus-visible:ring-[#5B7C8D] focus-visible:ring-offset-1 focus-visible:ring-offset-[#111]">
<AppImage
src="/assets/images/logo.png"
alt="BroadcastBeat logo"
width={200}
height={26}
priority={true}
className="h-7 w-auto object-contain"
/>
</Link>
{/* Desktop Nav Links — arrow key navigable + dropdowns */}
<div className="hidden lg:flex items-stretch gap-5" role="list" aria-label="Site sections">
{/* nav-desktop-redesign:start */}
<EventsDropdown />
{/* nav-desktop-redesign:end */}
{navLinks?.map((link, i) => (
<div
key={link?.label}
className="relative group/nav"
role="listitem">
<Link
href={link?.href}
ref={(el) => { navLinksRef.current[i] = el; }}
className="nav-link-bb h-[60px] flex items-center focus:outline-none focus-visible:ring-1 focus-visible:ring-[#5B7C8D] focus-visible:ring-offset-1 focus-visible:ring-offset-[#111]"
onKeyDown={(e) => handleNavKeyDown(e, i, navLinksRef)}
tabIndex={i === 0 ? 0 : -1}
aria-haspopup={link?.dropdown ? "true" : undefined}>
{link?.label}
</Link>
{link?.dropdown && (
<div
className="absolute left-0 top-full min-w-[200px] bg-[#0d0d0d] border border-[#252525] shadow-xl rounded-sm py-1 opacity-0 invisible translate-y-1 group-hover/nav:opacity-100 group-hover/nav:visible group-hover/nav:translate-y-0 group-focus-within/nav:opacity-100 group-focus-within/nav:visible group-focus-within/nav:translate-y-0 transition-all duration-150 z-50"
role="menu"
aria-label={`${link.label} categories`}>
{link.dropdown.map((sub) => (
<Link
key={sub.href + sub.label}
href={sub.href}
role="menuitem"
className="block px-4 py-2 text-xs font-body text-[#bbb] hover:bg-[#1a1a1a] hover:text-[#5B7C8D] focus:outline-none focus-visible:bg-[#1a1a1a] focus-visible:text-[#5B7C8D] uppercase tracking-wider transition-colors">
{sub.label}
</Link>
))}
</div>
)}
</div>
))}
{/* nav-desktop-redesign:after */}
<AboutDropdown />
{/* nav-desktop-redesign:after:end */}
{/* Reading List Icon Link */}
<Link
href="/reading-list"
aria-label="Reading List"
className="flex items-center text-[#888] hover:text-[#5B7C8D] transition-colors focus:outline-none focus-visible:ring-1 focus-visible:ring-[#5B7C8D] focus-visible:ring-offset-1 focus-visible:ring-offset-[#111]">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" aria-hidden="true">
<path d="M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z" />
</svg>
</Link>
{/* Notification Bell */}
<NotificationCenter />
</div>
{/* Enhanced Search */}
<div className="hidden md:flex items-center gap-2">
<div className={`search-bar-wrapper ${searchFocused ? "search-bar-expanded" : ""}`}>
<input
ref={searchRef}
type="search"
placeholder={searchFocused ? "Search articles..." : "Search..."}
value={searchQuery}
onChange={(e) => setSearchQuery(e?.target?.value)}
onFocus={() => setSearchFocused(true)}
onBlur={() => setSearchFocused(false)}
onKeyDown={(e) => {
if (e.key === "Enter") {
e.preventDefault();
submitSearch();
}
}}
className="search-input search-input-enhanced pr-16"
aria-label="Search articles (press / to focus)"
/>
{searchQuery && (
<button
type="button"
onClick={() => { setSearchQuery(""); searchRef.current?.focus(); }}
className="search-clear-btn"
aria-label="Clear search">
<CloseIcon size={11} />
</button>
)}
{!searchQuery && !searchFocused && (
<span className="search-kbd-hint" aria-hidden="true">/</span>
)}
{(searchQuery || searchFocused) && (
<button
type="button"
onClick={submitSearch}
aria-label="Submit search"
className="absolute right-2.5 top-1/2 -translate-y-1/2 text-[#5B7C8D] hover:text-[#8FB0C3] transition-colors cursor-pointer"
>
<SearchIcon size={13} strokeWidth={1.75} />
</button>
)}
{!searchQuery && !searchFocused && (
<button
type="button"
onClick={() => searchRef.current?.focus()}
aria-label="Focus search"
className="absolute right-8 top-1/2 -translate-y-1/2 text-[#666] hover:text-[#5B7C8D] transition-colors cursor-pointer"
>
<SearchIcon size={13} strokeWidth={1.75} />
</button>
)}
</div>
</div>
{/* Mobile Hamburger */}
<button
ref={hamburgerRef}
className="lg:hidden p-2 text-[#cccccc] focus:outline-none focus-visible:ring-2 focus-visible:ring-[#5B7C8D]"
onClick={() => setMobileOpen(!mobileOpen)}
aria-label={mobileOpen ? "Close menu" : "Open menu"}
aria-expanded={mobileOpen}
aria-controls="mobile-menu">
{mobileOpen ? <CloseIcon size={22} /> : <MenuIcon size={22} />}
</button>
</div>
{/* Mobile Menu */}
{mobileOpen && (
<div
id="mobile-menu"
ref={mobileMenuRef}
className="lg:hidden mobile-menu-open border-t border-[#252525] pb-4 bg-[#111111]"
role="dialog"
aria-label="Mobile navigation menu">
<div className="flex flex-col gap-0 pt-2">
{navLinks?.map((link, i) => (
<Link
key={link?.label}
href={link?.href}
ref={(el) => { navLinksRef.current[i] = el; }}
className="px-2 py-2.5 text-sm font-body font-bold uppercase tracking-wide text-[#cccccc] hover:text-accent hover:bg-[#1a1a1a] border-b border-[#222] transition-colors focus:outline-none focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-[#5B7C8D]"
onClick={() => setMobileOpen(false)}>
{link?.label}
</Link>
))}
{/* Reading List mobile link */}
<Link
href="/reading-list"
className="px-2 py-2.5 text-sm font-body font-bold uppercase tracking-wide text-[#cccccc] hover:text-accent hover:bg-[#1a1a1a] border-b border-[#222] transition-colors focus:outline-none focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-[#5B7C8D] flex items-center gap-2"
onClick={() => setMobileOpen(false)}>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" aria-hidden="true">
<path d="M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z" />
</svg>
Reading List
</Link>
{/* Sign In / Register removed — see desktop bar comment. */}
{currentUserId && (
<Link
href="/account"
className="px-2 py-2.5 text-sm font-body font-bold uppercase tracking-wide text-[#cccccc] hover:text-[#5B7C8D] hover:bg-[#1a1a1a] border-b border-[#222] transition-colors focus:outline-none focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-[#5B7C8D] flex items-center gap-2"
onClick={() => setMobileOpen(false)}>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" aria-hidden="true">
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" /><circle cx="12" cy="7" r="4" />
</svg>
My Profile
</Link>
)}
{/* WP Import mobile link */}
{isAdmin && (
<Link
href="/admin/import"
className="px-2 py-2.5 text-sm font-body font-bold uppercase tracking-wide text-[#cccccc] hover:text-[#5B7C8D] hover:bg-[#1a1a1a] border-b border-[#222] transition-colors focus:outline-none focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-[#5B7C8D] flex items-center gap-2"
onClick={() => setMobileOpen(false)}>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" aria-hidden="true">
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" /><polyline points="7 10 12 15 17 10" /><line x1="12" y1="15" x2="12" y2="3" />
</svg>
WP Import
</Link>
)}
</div>
<div className="flex flex-col gap-0 border-t border-[#252525] mt-1">
{navLinks
.filter((n) => n.dropdown && n.dropdown.length > 0)
.map((section) => (
<div key={section.label} className="border-b border-[#222]">
<div className="px-2 py-2 text-[10px] font-body font-bold text-[#5B7C8D] uppercase tracking-widest bg-[#0d0d0d]">
{section.label}
</div>
{section.dropdown!.map((link) => (
<Link
key={link.href + link.label}
href={link.href}
className="px-4 py-2 text-xs font-body text-[#888] hover:text-accent hover:bg-[#1a1a1a] block transition-colors focus:outline-none focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-[#5B7C8D]"
onClick={() => setMobileOpen(false)}>
{link.label}
</Link>
))}
</div>
))}
</div>
<div className="mt-3 px-2">
<div className="relative">
<input
type="search"
placeholder="Search articles..."
value={searchQuery}
onChange={(e) => setSearchQuery(e?.target?.value)}
onKeyDown={(e) => {
if (e.key === "Enter") {
e.preventDefault();
submitSearch();
}
}}
className="search-input search-input-enhanced w-full pr-8"
aria-label="Search articles mobile"
/>
<button
type="button"
onClick={submitSearch}
aria-label="Submit search"
className="absolute right-2.5 top-1/2 -translate-y-1/2 text-[#666] hover:text-[#5B7C8D] transition-colors cursor-pointer"
>
<SearchIcon size={13} strokeWidth={1.75} />
</button>
</div>
</div>
</div>
)}
</div>
</nav>
</div>
{/* HEADER LEADERBOARD — site-wide 728x90 between main nav and the ticker */}
{ADS_728X90.length > 0 && (
<div className="bg-[#0a0a0a] border-b border-[#1a1a1a] py-3 hidden md:block">
<div className="max-w-container mx-auto px-4 flex justify-center">
<AdImage ad={shuffle(ADS_728X90)[0]} priority page="header" />
</div>
</div>
)}
</>
);
}