fix(contrast,brand): full audit sweep — white-on-white + cross-component renames

- forum/page.tsx: text-white → navy on TopThreads, Following feed, Discover feed cards, search input, select, category grid, Community Guidelines; greys lightened where applicable for new white surface
- forum/[slug]/page.tsx: same sweep for category page (h1, h2, thread rows, new-thread form, search/sort bar) + hover:bg-[#1e2a3a] → slate-200
- forum/user/[username]/page.tsx: text-[#cccccc]/[#bfbfbf]/[#e0e0e0] + bg-[#222] tag chip + #9ca3af labels → readable on white card
- authors/[slug]/page.tsx: profile contact/facts cards readable
- search/page.tsx: h1 + h2 navy + hover slate
- news/[slug]/NewsArticleDetailClient.tsx: toast color
- news/NewsPageClient.tsx: import cleanExcerpt, strip HTML from listing excerpts
- privacy/terms/page.tsx: h1 + h2 + body greys to readable navy/slate
- error.tsx: page-level text to navy + button border slate
- about/page.tsx: page body text + Stat/Block cards to white surface w/ navy text
- Header.tsx: mobile hamburger + dropdown links → readable navy + slate border
- NotificationCenter.tsx: hover + unread bg flipped to light blue
- AISuggestedArticles.tsx: hover bg → slate-200
- Footer.tsx: link greys to #475569 + #DCE6F2 borders
- AskBBAI.tsx: copy rename 'BB AI' → 'AV Beat AI' (greeting, button, header, aria)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-03 22:13:42 +00:00
parent 2826f0b566
commit 6e9a163cfd
16 changed files with 160 additions and 159 deletions

View File

@@ -11,7 +11,7 @@ export default function AboutPage() {
return (
<div className="min-h-screen bg-background">
<Header />
<div className="max-w-container mx-auto px-4 py-12 text-[#e5e7eb]">
<div className="max-w-container mx-auto px-4 py-12 text-[#1e293b]">
<div className="lg:grid lg:grid-cols-[1fr,300px] lg:gap-10">
<main>
<header className="mb-8 border-b border-[#DCE6F2] pb-6">
@@ -19,7 +19,7 @@ export default function AboutPage() {
AV Beat
</div>
<h1 className="font-serif text-4xl md:text-5xl font-bold tracking-tight">About</h1>
<p className="mt-3 text-[#9ca3af] text-base max-w-2xl">
<p className="mt-3 text-[#475569] text-base max-w-2xl">
An independent trade publication covering pro AV, live production, display tech, and signal-flow technology.
</p>
</header>
@@ -30,7 +30,7 @@ export default function AboutPage() {
<Stat label="Stories archived" value="29k+" />
</div>
<section className="space-y-6 text-[#d1d5db] text-[15px] leading-relaxed">
<section className="space-y-6 text-[#1e293b] text-[15px] leading-relaxed">
<Block title="What we cover">
AV Beat reports on the equipment, services, and people
that move the professional video industry forward. We follow
@@ -79,9 +79,9 @@ export default function AboutPage() {
function Stat({ label, value }: { label: string; value: string }) {
return (
<div className="rounded border border-[#DCE6F2] bg-[#0b0f17] p-4">
<div className="font-serif text-3xl text-white">{value}</div>
<div className="mt-1 text-[10px] font-mono uppercase tracking-[0.16em] text-[#6b7280]">
<div className="rounded border border-[#DCE6F2] bg-[#FFFFFF] p-4">
<div className="font-serif text-3xl text-[#0F172A]">{value}</div>
<div className="mt-1 text-[10px] font-mono uppercase tracking-[0.16em] text-[#475569]">
{label}
</div>
</div>
@@ -90,7 +90,7 @@ function Stat({ label, value }: { label: string; value: string }) {
function Block({ title, children }: { title: string; children: React.ReactNode }) {
return (
<div className="rounded border border-[#1e1e1e] bg-[#0b0f17]/70 p-5">
<div className="rounded border border-[#DCE6F2] bg-[#FFFFFF] p-5">
<h2 className="font-mono text-xs uppercase tracking-[0.18em] text-[var(--color-text-info,#60a5fa)] mb-2">
{title}
</h2>

View File

@@ -290,7 +290,7 @@ export default function AuthorProfilePage() {
<span className="font-body text-[10px] text-[#555]">·</span>
<span className="font-body text-[10px] text-[#555]">{article.readTime}</span>
</div>
<h3 className="font-heading text-sm font-bold text-[#e0e0e0] group-hover:text-[#1D4ED8] transition-colors leading-snug mb-2 line-clamp-2">
<h3 className="font-heading text-sm font-bold text-[#0F172A] group-hover:text-[#1D4ED8] transition-colors leading-snug mb-2 line-clamp-2">
{article.title}
</h3>
<p className="font-body text-xs text-[#777] leading-relaxed line-clamp-2 mb-3">
@@ -311,7 +311,7 @@ export default function AuthorProfilePage() {
<div className="bg-[#FFFFFF] border border-[#DCE6F2] rounded-sm p-6">
<p className="section-label mb-4">Biography</p>
{profile.bio ? (
<p className="font-body text-sm text-[#aaaaaa] leading-relaxed whitespace-pre-line">
<p className="font-body text-sm text-[#1e293b] leading-relaxed whitespace-pre-line">
{profile.bio}
</p>
) : (
@@ -336,7 +336,7 @@ export default function AuthorProfilePage() {
<p className="font-body text-xs font-bold uppercase tracking-wider text-[#555] mb-1">
Address
</p>
<address className="font-body text-sm text-[#cccccc] not-italic leading-relaxed">
<address className="font-body text-sm text-[#1e293b] not-italic leading-relaxed">
{addressLines.map((line, i) => (
<span key={i}>
{line}
@@ -400,7 +400,7 @@ export default function AuthorProfilePage() {
<p className="font-body text-xs font-bold uppercase tracking-wider text-[#555] mb-1">
Location
</p>
<p className="font-body text-sm text-[#cccccc]">{locationLine}</p>
<p className="font-body text-sm text-[#1e293b]">{locationLine}</p>
</div>
)}
{profile.joined_label && (
@@ -408,14 +408,14 @@ export default function AuthorProfilePage() {
<p className="font-body text-xs font-bold uppercase tracking-wider text-[#555] mb-1">
Member Since
</p>
<p className="font-body text-sm text-[#cccccc]">{profile.joined_label}</p>
<p className="font-body text-sm text-[#1e293b]">{profile.joined_label}</p>
</div>
)}
<div>
<p className="font-body text-xs font-bold uppercase tracking-wider text-[#555] mb-1">
Articles Published
</p>
<p className="font-body text-sm text-[#cccccc]">
<p className="font-body text-sm text-[#1e293b]">
{articleTotal.toLocaleString()}
</p>
</div>
@@ -423,7 +423,7 @@ export default function AuthorProfilePage() {
<p className="font-body text-xs font-bold uppercase tracking-wider text-[#555] mb-1">
Role
</p>
<p className="font-body text-sm text-[#cccccc]">{profile.role}</p>
<p className="font-body text-sm text-[#1e293b]">{profile.role}</p>
</div>
</div>
</div>

View File

@@ -13,14 +13,14 @@ export default function Error({
console.error("[route error]", error);
}, [error]);
return (
<div className="min-h-screen flex items-center justify-center bg-[#F8FAFC] text-[#e0e0e0] p-6">
<div className="min-h-screen flex items-center justify-center bg-[#F8FAFC] text-[#0F172A] p-6">
<div className="max-w-md text-center">
<h2 className="font-heading text-2xl mb-3">Something went wrong</h2>
<p className="text-[#888] text-sm mb-4 font-body">
<p className="text-[#475569] text-sm mb-4 font-body">
We hit an error rendering this page. Try again, or head back to the home page.
</p>
{error?.digest && (
<p className="text-[#444] text-xs font-mono mb-4">ref: {error.digest}</p>
<p className="text-[#666] text-xs font-mono mb-4">ref: {error.digest}</p>
)}
<div className="flex gap-3 justify-center">
<button
@@ -31,7 +31,7 @@ export default function Error({
</button>
<Link
href="/home-page"
className="px-4 py-2 border border-[#333] text-sm rounded-sm hover:border-[#1D4ED8] transition-colors"
className="px-4 py-2 border border-[#DCE6F2] text-[#0F172A] text-sm rounded-sm hover:border-[#1D4ED8] transition-colors"
>
Home
</Link>

View File

@@ -84,7 +84,7 @@ function TopThreadsWidget({ categoryId }: { categoryId: string }) {
<div className="flex items-center justify-between px-5 py-4 border-b border-[#DCE6F2]">
<div className="flex items-center gap-2">
<span className="text-lg">🏆</span>
<h2 className="text-white font-heading font-bold text-base">Top Performing Threads</h2>
<h2 className="text-[#0F172A] font-heading font-bold text-base">Top Performing Threads</h2>
</div>
{/* Metric Tabs */}
<div className="flex gap-1 bg-[#111] border border-[#DCE6F2] rounded-lg p-1">
@@ -132,7 +132,7 @@ function TopThreadsWidget({ categoryId }: { categoryId: string }) {
<Link
key={thread.id}
href={`/forum/thread/${thread.id}`}
className="flex items-center gap-3 px-5 py-3 hover:bg-[#1e2a3a] transition-colors group"
className="flex items-center gap-3 px-5 py-3 hover:bg-[#e2e8f0] transition-colors group"
>
{/* Rank */}
<span className={`flex-shrink-0 w-6 text-center font-heading font-bold text-sm ${
@@ -142,7 +142,7 @@ function TopThreadsWidget({ categoryId }: { categoryId: string }) {
</span>
{/* Thread info */}
<div className="flex-1 min-w-0">
<p className="text-white font-body text-sm font-semibold group-hover:text-[#1D4ED8] transition-colors truncate leading-snug">
<p className="text-[#0F172A] font-body text-sm font-semibold group-hover:text-[#1D4ED8] transition-colors truncate leading-snug">
{thread.title}
</p>
<p className="text-[#555] font-body text-xs mt-0.5">
@@ -284,15 +284,15 @@ export default function ForumCategoryPage() {
<nav className="text-sm font-body text-[#666] mb-3">
<Link href="/forum" className="hover:text-[#1D4ED8] transition-colors">Forum</Link>
<span className="mx-2"></span>
<span className="text-[#aab4c4]">{category?.name || slug}</span>
<span className="text-[#0F172A]">{category?.name || slug}</span>
</nav>
<div className="flex items-center justify-between gap-4">
<div className="flex items-center gap-3">
<span className="text-2xl">{category?.icon || '💬'}</span>
<div>
<h1 className="text-2xl font-heading font-bold text-white">{category?.name || 'Loading...'}</h1>
<h1 className="text-2xl font-heading font-bold text-[#0F172A]">{category?.name || 'Loading...'}</h1>
{category && (
<p className="text-[#aab4c4] font-body text-sm mt-0.5">{category.thread_count} threads</p>
<p className="text-[#475569] font-body text-sm mt-0.5">{category.thread_count} threads</p>
)}
</div>
</div>
@@ -318,8 +318,8 @@ export default function ForumCategoryPage() {
<div className="max-w-container mx-auto px-4 py-6">
{/* New Thread Form — auth-gated */}
{showNewThread && isAuthenticated && (
<form onSubmit={handleNewThread} className="bg-[#FFFFFF] border border-[#2a3a50] rounded-lg p-5 mb-6">
<h3 className="text-white font-heading font-semibold mb-4">Start a New Thread</h3>
<form onSubmit={handleNewThread} className="bg-[#FFFFFF] border border-[#DCE6F2] rounded-lg p-5 mb-6">
<h3 className="text-[#0F172A] font-heading font-semibold mb-4">Start a New Thread</h3>
<div className="space-y-3">
<input
type="text"
@@ -327,7 +327,7 @@ export default function ForumCategoryPage() {
value={newTitle}
onChange={e => setNewTitle(e.target.value)}
required
className="w-full bg-[#111] border border-[#333] rounded-lg px-3 py-2 text-white font-body text-sm placeholder-[#555] focus:outline-none focus:border-[#1D4ED8]"
className="w-full bg-[#F8FAFC] border border-[#DCE6F2] rounded-lg px-3 py-2 text-[#0F172A] font-body text-sm placeholder-[#888] focus:outline-none focus:border-[#1D4ED8]"
/>
<textarea
placeholder="What would you like to discuss? *"
@@ -335,7 +335,7 @@ export default function ForumCategoryPage() {
onChange={e => setNewBody(e.target.value)}
required
rows={5}
className="w-full bg-[#111] border border-[#333] rounded-lg px-3 py-2 text-white font-body text-sm placeholder-[#555] focus:outline-none focus:border-[#1D4ED8] resize-none"
className="w-full bg-[#F8FAFC] border border-[#DCE6F2] rounded-lg px-3 py-2 text-[#0F172A] font-body text-sm placeholder-[#888] focus:outline-none focus:border-[#1D4ED8] resize-none"
/>
<div className="flex items-center gap-3">
<ImageAttachButton onInsert={(md) => setNewBody((b) => (b || "") + md)} />
@@ -357,7 +357,7 @@ export default function ForumCategoryPage() {
<button
type="button"
onClick={() => setShowNewThread(false)}
className="bg-[#DCE6F2] hover:bg-[#333] text-[#aaa] font-body text-sm px-5 py-2 rounded-lg transition-colors"
className="bg-[#DCE6F2] hover:bg-[#cbd5e1] text-[#0F172A] font-body text-sm px-5 py-2 rounded-lg transition-colors"
>
Cancel
</button>
@@ -378,7 +378,7 @@ export default function ForumCategoryPage() {
placeholder="Search threads in this category..."
value={search}
onChange={e => setSearch(e.target.value)}
className="w-full bg-[#FFFFFF] border border-[#DCE6F2] focus:border-[#1D4ED8] rounded-lg pl-9 pr-4 py-2.5 text-white font-body text-sm placeholder-[#555] focus:outline-none transition-colors"
className="w-full bg-[#FFFFFF] border border-[#DCE6F2] focus:border-[#1D4ED8] rounded-lg pl-9 pr-4 py-2.5 text-[#0F172A] font-body text-sm placeholder-[#888] focus:outline-none transition-colors"
/>
{search && (
<button
@@ -402,7 +402,7 @@ export default function ForumCategoryPage() {
className={`px-3 py-1.5 rounded-md text-xs font-body font-semibold transition-colors whitespace-nowrap ${
sort === opt.value
? 'bg-[#1D4ED8] text-white'
: 'text-[#888] hover:text-white'
: 'text-[#888] hover:text-[#0F172A]'
}`}
>
{opt.label}
@@ -426,8 +426,8 @@ export default function ForumCategoryPage() {
)}
{!loading && !threadsLoading && !error && threads.length === 0 && (
<div className="text-center py-16 text-[#555] font-body">
<p className="text-lg mb-2">
<div className="text-center py-16 text-[#475569] font-body">
<p className="text-lg mb-2 text-[#0F172A] font-semibold">
{search ? 'No threads match your search' : sort === 'unanswered' ? 'No unanswered threads' : 'No threads yet'}
</p>
<p className="text-sm">
@@ -445,7 +445,7 @@ export default function ForumCategoryPage() {
<Link
key={thread.id}
href={`/forum/thread/${thread.id}`}
className="flex items-center gap-4 bg-[#FFFFFF] hover:bg-[#1e2a3a] border border-[#DCE6F2] hover:border-[#1D4ED8] rounded-lg px-4 py-3 transition-all group"
className="flex items-center gap-4 bg-[#FFFFFF] hover:bg-[#e2e8f0] border border-[#DCE6F2] hover:border-[#1D4ED8] rounded-lg px-4 py-3 transition-all group"
>
<div className="flex-1 min-w-0">
<div className="flex items-center gap-2 flex-wrap">
@@ -458,7 +458,7 @@ export default function ForumCategoryPage() {
{thread.reply_count === 0 && (
<span className="text-xs bg-[#f59e0b]/10 text-[#f59e0b] px-2 py-0.5 rounded font-body">UNANSWERED</span>
)}
<h3 className="text-white font-body font-semibold text-sm group-hover:text-[#1D4ED8] transition-colors truncate">
<h3 className="text-[#0F172A] font-body font-semibold text-sm group-hover:text-[#1D4ED8] transition-colors truncate">
{thread.title}
</h3>
</div>
@@ -468,13 +468,13 @@ export default function ForumCategoryPage() {
</p>
</div>
<div className="flex-shrink-0 text-right hidden sm:block">
<div className="text-[#aaa] font-body text-sm font-semibold">{thread.reply_count}</div>
<div className="text-[#555] font-body text-xs">replies</div>
<div className="text-[#0F172A] font-body text-sm font-semibold">{thread.reply_count}</div>
<div className="text-[#475569] font-body text-xs">replies</div>
</div>
{sort === 'top-voted' && (
<div className="flex-shrink-0 text-right hidden md:block">
<div className="text-[#22c55e] font-body text-sm font-semibold">+{thread.upvotes ?? 0}</div>
<div className="text-[#555] font-body text-xs">votes</div>
<div className="text-[#475569] font-body text-xs">votes</div>
</div>
)}
<div className="flex-shrink-0 text-right hidden md:block">

View File

@@ -151,7 +151,7 @@ function TopThreadsWidget({ categoryId }: { categoryId?: string }) {
</>
)}
{!loading && threads.length === 0 && (
<div className="px-5 py-8 text-center text-[#555] font-body text-sm">
<div className="px-5 py-8 text-center text-[#475569] font-body text-sm">
No threads yet. Be the first to start a discussion!
</div>
)}
@@ -161,7 +161,7 @@ function TopThreadsWidget({ categoryId }: { categoryId?: string }) {
<Link
key={thread.id}
href={`/forum/thread/${thread.id}`}
className="flex items-center gap-3 px-5 py-3 hover:bg-[#1e2a3a] transition-colors group"
className="flex items-center gap-3 px-5 py-3 hover:bg-[#e2e8f0] transition-colors group"
>
{/* Rank */}
<span className={`flex-shrink-0 w-6 text-center font-heading font-bold text-sm ${
@@ -171,11 +171,11 @@ function TopThreadsWidget({ categoryId }: { categoryId?: string }) {
</span>
{/* Thread info */}
<div className="flex-1 min-w-0">
<p className="text-white font-body text-sm font-semibold group-hover:text-[#1D4ED8] transition-colors truncate leading-snug">
<p className="text-[#0F172A] font-body text-sm font-semibold group-hover:text-[#1D4ED8] transition-colors truncate leading-snug">
{thread.title}
</p>
<p className="text-[#555] font-body text-xs mt-0.5">
<Link href={`/forum/user/${encodeURIComponent(thread.author_name)}`} className="text-[#666] hover:text-[#1D4ED8] hover:underline" onClick={(e) => e.stopPropagation()}>{thread.author_name}</Link>
<p className="text-[#475569] font-body text-xs mt-0.5">
<Link href={`/forum/user/${encodeURIComponent(thread.author_name)}`} className="text-[#475569] hover:text-[#1D4ED8] hover:underline" onClick={(e) => e.stopPropagation()}>{thread.author_name}</Link>
{thread.forum_categories && (
<> · <span className="text-[#1D4ED8]">{thread.forum_categories.name}</span></>
)}
@@ -333,7 +333,7 @@ export default function ForumIndexPage() {
<button
onClick={() => setFeedMode('discover')}
className={`px-4 py-2 rounded-md text-sm font-body font-semibold transition-colors flex items-center gap-2 ${
feedMode === 'discover' ? 'bg-[#1D4ED8] text-white' : 'text-[#888] hover:text-white'
feedMode === 'discover' ? 'bg-[#1D4ED8] text-white' : 'text-[#888] hover:text-[#0F172A]'
}`}
>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" aria-hidden="true">
@@ -344,7 +344,7 @@ export default function ForumIndexPage() {
<button
onClick={() => setFeedMode('following')}
className={`px-4 py-2 rounded-md text-sm font-body font-semibold transition-colors flex items-center gap-2 ${
feedMode === 'following' ? 'bg-[#1D4ED8] text-white' : 'text-[#888] hover:text-white'
feedMode === 'following' ? 'bg-[#1D4ED8] text-white' : 'text-[#888] hover:text-[#0F172A]'
}`}
>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" aria-hidden="true">
@@ -359,8 +359,8 @@ export default function ForumIndexPage() {
{feedMode === 'following' && (
<div className="mb-8">
{!currentUserId && (
<div className="bg-[#FFFFFF] border border-[#2a3a50] rounded-lg p-8 text-center">
<p className="text-[#aab4c4] font-body text-sm mb-3">Sign in to see threads from people you follow.</p>
<div className="bg-[#FFFFFF] border border-[#DCE6F2] rounded-lg p-8 text-center">
<p className="text-[#475569] font-body text-sm mb-3">Sign in to see threads from people you follow.</p>
<Link
href="/login"
className="inline-block bg-[#1D4ED8] text-white font-body text-sm font-bold px-5 py-2 rounded-lg hover:bg-[#1E3A8A] transition-colors"
@@ -379,8 +379,8 @@ export default function ForumIndexPage() {
{currentUserId && !followingLoading && followingThreads.length === 0 && (
<div className="bg-[#FFFFFF] border border-[#DCE6F2] rounded-lg p-10 text-center">
<div className="text-3xl mb-3">👥</div>
<p className="text-[#aaa] font-body text-sm font-semibold mb-1">Your following feed is empty</p>
<p className="text-[#555] font-body text-sm mb-4">Follow other members to see their threads here.</p>
<p className="text-[#0F172A] font-body text-sm font-semibold mb-1">Your following feed is empty</p>
<p className="text-[#475569] font-body text-sm mb-4">Follow other members to see their threads here.</p>
<Link
href="/forum"
onClick={() => setFeedMode('discover')}
@@ -398,10 +398,10 @@ export default function ForumIndexPage() {
<Link
key={thread.id}
href={`/forum/thread/${thread.id}`}
className="flex items-center gap-4 bg-[#FFFFFF] hover:bg-[#1e2a3a] border border-[#DCE6F2] hover:border-[#1D4ED8] rounded-lg px-4 py-3 transition-all group"
className="flex items-center gap-4 bg-[#FFFFFF] hover:bg-[#e2e8f0] border border-[#DCE6F2] hover:border-[#1D4ED8] rounded-lg px-4 py-3 transition-all group"
>
<div className="flex-1 min-w-0">
<h3 className="text-white font-body font-semibold text-sm group-hover:text-[#1D4ED8] transition-colors truncate">
<h3 className="text-[#0F172A] font-body font-semibold text-sm group-hover:text-[#1D4ED8] transition-colors truncate">
{thread.title}
</h3>
<p className="text-[#666] font-body text-xs mt-0.5">
@@ -420,12 +420,12 @@ export default function ForumIndexPage() {
</p>
</div>
<div className="flex-shrink-0 text-right hidden sm:block">
<div className="text-[#aaa] font-body text-sm font-semibold">{thread.reply_count}</div>
<div className="text-[#555] font-body text-xs">replies</div>
<div className="text-[#0F172A] font-body text-sm font-semibold">{thread.reply_count}</div>
<div className="text-[#475569] font-body text-xs">replies</div>
</div>
<div className="flex-shrink-0 text-right hidden md:block">
<div className="text-[#aaa] font-body text-sm font-semibold">{thread.view_count}</div>
<div className="text-[#555] font-body text-xs">views</div>
<div className="text-[#0F172A] font-body text-sm font-semibold">{thread.view_count}</div>
<div className="text-[#475569] font-body text-xs">views</div>
</div>
</Link>
))}
@@ -450,7 +450,7 @@ export default function ForumIndexPage() {
placeholder="Search threads..."
value={search}
onChange={e => setSearch(e.target.value)}
className="w-full bg-[#FFFFFF] border border-[#DCE6F2] focus:border-[#1D4ED8] rounded-lg pl-9 pr-4 py-2.5 text-white font-body text-sm placeholder-[#555] focus:outline-none transition-colors"
className="w-full bg-[#FFFFFF] border border-[#DCE6F2] focus:border-[#1D4ED8] rounded-lg pl-9 pr-4 py-2.5 text-[#0F172A] font-body text-sm placeholder-[#888] focus:outline-none transition-colors"
/>
{search && (
<button
@@ -470,7 +470,7 @@ export default function ForumIndexPage() {
<select
value={selectedCategory}
onChange={e => setSelectedCategory(e.target.value)}
className="appearance-none bg-[#FFFFFF] border border-[#DCE6F2] focus:border-[#1D4ED8] rounded-lg pl-3 pr-8 py-2.5 text-sm font-body text-white focus:outline-none transition-colors cursor-pointer min-w-[160px]"
className="appearance-none bg-[#FFFFFF] border border-[#DCE6F2] focus:border-[#1D4ED8] rounded-lg pl-3 pr-8 py-2.5 text-sm font-body text-[#0F172A] focus:outline-none transition-colors cursor-pointer min-w-[160px]"
>
<option value="">All Categories</option>
{categories.map(cat => (
@@ -491,7 +491,7 @@ export default function ForumIndexPage() {
className={`px-3 py-1.5 rounded-md text-xs font-body font-semibold transition-colors whitespace-nowrap ${
sort === opt.value
? 'bg-[#1D4ED8] text-white'
: 'text-[#888] hover:text-white'
: 'text-[#888] hover:text-[#0F172A]'
}`}
>
{opt.label}
@@ -511,8 +511,8 @@ export default function ForumIndexPage() {
</div>
)}
{!threadsLoading && threads.length === 0 && (
<div className="text-center py-12 text-[#555] font-body">
<p className="text-base mb-1">No threads found</p>
<div className="text-center py-12 text-[#475569] font-body">
<p className="text-base mb-1 text-[#0F172A] font-semibold">No threads found</p>
<p className="text-sm">Try adjusting your search or filters.</p>
</div>
)}
@@ -523,10 +523,10 @@ export default function ForumIndexPage() {
<Link
key={thread.id}
href={`/forum/thread/${thread.id}`}
className="flex items-center gap-4 bg-[#FFFFFF] hover:bg-[#1e2a3a] border border-[#DCE6F2] hover:border-[#1D4ED8] rounded-lg px-4 py-3 transition-all group"
className="flex items-center gap-4 bg-[#FFFFFF] hover:bg-[#e2e8f0] border border-[#DCE6F2] hover:border-[#1D4ED8] rounded-lg px-4 py-3 transition-all group"
>
<div className="flex-1 min-w-0">
<h3 className="text-white font-body font-semibold text-sm group-hover:text-[#1D4ED8] transition-colors truncate">
<h3 className="text-[#0F172A] font-body font-semibold text-sm group-hover:text-[#1D4ED8] transition-colors truncate">
{thread.title}
</h3>
<p className="text-[#666] font-body text-xs mt-0.5">
@@ -538,13 +538,13 @@ export default function ForumIndexPage() {
</p>
</div>
<div className="flex-shrink-0 text-right hidden sm:block">
<div className="text-[#aaa] font-body text-sm font-semibold">{thread.reply_count}</div>
<div className="text-[#555] font-body text-xs">replies</div>
<div className="text-[#0F172A] font-body text-sm font-semibold">{thread.reply_count}</div>
<div className="text-[#475569] font-body text-xs">replies</div>
</div>
{sort === 'top-voted' && (
<div className="flex-shrink-0 text-right hidden md:block">
<div className="text-[#22c55e] font-body text-sm font-semibold">+{thread.upvotes ?? 0}</div>
<div className="text-[#555] font-body text-xs">votes</div>
<div className="text-[#475569] font-body text-xs">votes</div>
</div>
)}
</Link>
@@ -584,30 +584,30 @@ export default function ForumIndexPage() {
<Link
key={cat.id}
href={`/forum/${cat.slug}`}
className="flex items-center gap-4 bg-[#FFFFFF] hover:bg-[#1e2a3a] border border-[#DCE6F2] hover:border-[#1D4ED8] rounded-lg p-4 transition-all group"
className="flex items-center gap-4 bg-[#FFFFFF] hover:bg-[#e2e8f0] border border-[#DCE6F2] hover:border-[#1D4ED8] rounded-lg p-4 transition-all group"
>
<span className="text-3xl flex-shrink-0 w-10 text-center">{cat.icon}</span>
<div className="flex-1 min-w-0">
<h2 className="text-white font-heading font-semibold text-lg group-hover:text-[#1D4ED8] transition-colors">
<h2 className="text-[#0F172A] font-heading font-semibold text-lg group-hover:text-[#1D4ED8] transition-colors">
{cat.name}
</h2>
<p className="text-[#888] font-body text-sm mt-0.5 truncate">{cat.description}</p>
<p className="text-[#475569] font-body text-sm mt-0.5 truncate">{cat.description}</p>
{cat.last_thread_title && (
<p className="text-[10px] text-[#666] font-body mt-1.5 truncate">
<span className="text-[#555]">Last post:</span>{' '}
<span className="text-[#aaa]">{cat.last_thread_title}</span>
<p className="text-[10px] text-[#475569] font-body mt-1.5 truncate">
<span className="text-[#666]">Last post:</span>{' '}
<span className="text-[#1e293b]">{cat.last_thread_title}</span>
{cat.last_activity_at && (
<span className="text-[#555]"> · {timeAgoFresh(cat.last_activity_at, cat.id)}</span>
<span className="text-[#666]"> · {timeAgoFresh(cat.last_activity_at, cat.id)}</span>
)}
</p>
)}
</div>
<div className="flex-shrink-0 text-right hidden sm:block">
<div className="text-white font-body font-semibold text-sm">{cat.thread_count}</div>
<div className="text-[#0F172A] font-body font-semibold text-sm">{cat.thread_count}</div>
<div className="text-[#666] font-body text-xs">threads</div>
</div>
<div className="flex-shrink-0 text-right hidden md:block">
<div className="text-white font-body font-semibold text-sm">{cat.post_count}</div>
<div className="text-[#0F172A] font-body font-semibold text-sm">{cat.post_count}</div>
<div className="text-[#666] font-body text-xs">posts</div>
</div>
<svg className="w-4 h-4 text-[#555] group-hover:text-[#1D4ED8] flex-shrink-0 transition-colors" fill="none" stroke="currentColor" viewBox="0 0 24 24">
@@ -624,9 +624,9 @@ export default function ForumIndexPage() {
)}
{/* Forum guidelines */}
<div className="mt-8 bg-[#FFFFFF] border border-[#2a3a50] rounded-lg p-5">
<h3 className="text-white font-heading font-semibold mb-2">Community Guidelines</h3>
<ul className="text-[#aab4c4] font-body text-sm space-y-1">
<div className="mt-8 bg-[#FFFFFF] border border-[#DCE6F2] rounded-lg p-5">
<h3 className="text-[#0F172A] font-heading font-semibold mb-2">Community Guidelines</h3>
<ul className="text-[#475569] font-body text-sm space-y-1">
<li> Be respectful and professional this is a community of peers</li>
<li> Share real-world experience and cite sources when possible</li>
<li> The <span className="text-[#1D4ED8]">AV Beat AI</span> assistant is available in threads to help answer questions it is clearly labeled</li>

View File

@@ -182,7 +182,7 @@ export default function ForumUserPage() {
</span>
)}
{profile.role_title && (
<span className="font-body text-[10px] font-bold uppercase tracking-wider text-[#9ca3af] bg-[#9ca3af]/10 border border-[#9ca3af]/30 px-2 py-1 rounded-sm">
<span className="font-body text-[10px] font-bold uppercase tracking-wider text-[#475569] bg-[#9ca3af]/10 border border-[#9ca3af]/30 px-2 py-1 rounded-sm">
{profile.role_title}
</span>
)}
@@ -198,7 +198,7 @@ export default function ForumUserPage() {
</div>
{profile.bio && (
<p className="font-body text-sm text-[#bfbfbf] leading-relaxed mt-5 pt-5 border-t border-[#DCE6F2]">
<p className="font-body text-sm text-[#1e293b] leading-relaxed mt-5 pt-5 border-t border-[#DCE6F2]">
{profile.bio}
</p>
)}
@@ -206,7 +206,7 @@ export default function ForumUserPage() {
{profile.expertise_tags && profile.expertise_tags.length > 0 && (
<div className="flex flex-wrap gap-2 mt-4">
{profile.expertise_tags.map((tag) => (
<span key={tag} className="font-body text-[11px] text-[#9ca3af] bg-[#222] border border-[#DCE6F2] px-2 py-0.5 rounded-sm">
<span key={tag} className="font-body text-[11px] text-[#475569] bg-[#F8FAFC] border border-[#DCE6F2] px-2 py-0.5 rounded-sm">
#{tag}
</span>
))}
@@ -226,7 +226,7 @@ export default function ForumUserPage() {
<ul className="space-y-2 mb-8">
{threads.map((t) => (
<li key={t.id} className="bg-[#FFFFFF] border border-[#DCE6F2] rounded-sm p-3 hover:border-[#1D4ED8]/50 transition-colors">
<Link href={`/forum/thread/${t.id}`} className="font-body text-sm font-semibold text-[#e0e0e0] hover:text-[#1D4ED8] block">
<Link href={`/forum/thread/${t.id}`} className="font-body text-sm font-semibold text-[#0F172A] hover:text-[#1D4ED8] block">
{t.title}
</Link>
<div className="flex items-center gap-3 mt-1 text-[11px] text-[#666]">
@@ -255,7 +255,7 @@ export default function ForumUserPage() {
<Link href={`/forum/thread/${r.thread_id}`} className="font-body text-xs font-semibold text-[#1D4ED8] hover:underline">
{r.forum_threads?.title || "(thread)"}
</Link>
<p className="font-body text-sm text-[#bfbfbf] leading-relaxed mt-1 line-clamp-3">{r.body}</p>
<p className="font-body text-sm text-[#1e293b] leading-relaxed mt-1 line-clamp-3">{r.body}</p>
<div className="mt-1 text-[11px] text-[#666]">
<time>{new Date(r.created_at).toLocaleDateString()}</time>
</div>
@@ -269,12 +269,12 @@ export default function ForumUserPage() {
<div className="bg-[#FFFFFF] border border-[#DCE6F2] rounded-sm p-4 sticky top-4">
<h3 className="font-body text-xs font-bold uppercase tracking-wider text-[#888] mb-2">Profile facts</h3>
<dl className="text-sm space-y-2">
<div><dt className="text-[#666] text-[11px] uppercase tracking-wider">Role</dt><dd className="text-[#cccccc]">{profile.role_title || "—"}</dd></div>
{profile.company && <div><dt className="text-[#666] text-[11px] uppercase tracking-wider">Company</dt><dd className="text-[#cccccc]">{profile.company}</dd></div>}
<div><dt className="text-[#666] text-[11px] uppercase tracking-wider">Threads</dt><dd className="text-[#cccccc]">{profile.thread_count}</dd></div>
<div><dt className="text-[#666] text-[11px] uppercase tracking-wider">Replies</dt><dd className="text-[#cccccc]">{profile.reply_count}</dd></div>
{profile.years_experience && <div><dt className="text-[#666] text-[11px] uppercase tracking-wider">Years in industry</dt><dd className="text-[#cccccc]">{profile.years_experience}</dd></div>}
<div><dt className="text-[#666] text-[11px] uppercase tracking-wider">Member since</dt><dd className="text-[#cccccc]">{fmtDate(profile.join_date)}</dd></div>
<div><dt className="text-[#666] text-[11px] uppercase tracking-wider">Role</dt><dd className="text-[#0F172A]">{profile.role_title || "—"}</dd></div>
{profile.company && <div><dt className="text-[#666] text-[11px] uppercase tracking-wider">Company</dt><dd className="text-[#0F172A]">{profile.company}</dd></div>}
<div><dt className="text-[#666] text-[11px] uppercase tracking-wider">Threads</dt><dd className="text-[#0F172A]">{profile.thread_count}</dd></div>
<div><dt className="text-[#666] text-[11px] uppercase tracking-wider">Replies</dt><dd className="text-[#0F172A]">{profile.reply_count}</dd></div>
{profile.years_experience && <div><dt className="text-[#666] text-[11px] uppercase tracking-wider">Years in industry</dt><dd className="text-[#0F172A]">{profile.years_experience}</dd></div>}
<div><dt className="text-[#666] text-[11px] uppercase tracking-wider">Member since</dt><dd className="text-[#0F172A]">{fmtDate(profile.join_date)}</dd></div>
</dl>
</div>
</aside>

View File

@@ -9,6 +9,7 @@ import AppImage from "@/components/ui/AppImage";
import type { Article } from "@/lib/articles/types";
import AISuggestedArticles from "@/components/AISuggestedArticles";
import SidebarAdStack from "@/components/SidebarAdStack";
import { cleanExcerpt } from "@/lib/articles/excerpt";
const CATEGORIES = ["All", "Cloud", "AI", "IP Workflows", "Live Production", "Streaming", "Audio", "Cameras", "NAB Show", "EAS", "Sports Broadcasting", "Ad Tech"];
@@ -276,7 +277,7 @@ export default function NewsPage({
<h2 className="font-heading text-[#0F172A] text-base font-bold leading-snug mb-2 group-hover:text-[#1D4ED8] transition-colors line-clamp-2">
{article.title || "Untitled"}
</h2>
<p className="text-[#777] font-body text-sm leading-relaxed line-clamp-2">{article.excerpt || ""}</p>
<p className="text-[#475569] font-body text-sm leading-relaxed line-clamp-2">{cleanExcerpt(article.excerpt || "")}</p>
<div className="flex items-center gap-2 mt-2">
<span className="text-[#555] font-body text-xs">By {article.author || "AV Beat"}</span>
<span className="text-[#444] text-[10px]">·</span>

View File

@@ -890,7 +890,7 @@ export default function NewsArticleDetailClient({
<div
role="status"
aria-live="polite"
className="fixed bottom-4 right-4 bg-[#FFFFFF] border border-[#1D4ED8] text-white px-4 py-3 rounded-sm text-sm font-body shadow-lg z-50">
className="fixed bottom-4 right-4 bg-[#FFFFFF] border border-[#1D4ED8] text-[#0F172A] px-4 py-3 rounded-sm text-sm font-body shadow-lg z-50">
{saveToast}
</div>
)}

View File

@@ -17,40 +17,40 @@ export default function PrivacyPage() {
<Header />
<div className="bg-[#111] border-b border-[#222] py-8">
<div className="max-w-container mx-auto px-4">
<h1 className="font-heading text-white text-3xl font-bold">Privacy Policy</h1>
<p className="text-[#888] font-body text-sm mt-2">Last updated: April 2026 Relevant Media Properties, LLC</p>
<h1 className="font-heading text-[#0F172A] text-3xl font-bold">Privacy Policy</h1>
<p className="text-[#475569] font-body text-sm mt-2">Last updated: April 2026 Relevant Media Properties, LLC</p>
</div>
</div>
<main id="main-content" className="max-w-container mx-auto px-4 py-10">
<div className="max-w-3xl space-y-8 font-body text-[#aaa] leading-relaxed">
<div className="max-w-3xl space-y-8 font-body text-[#1e293b] leading-relaxed">
<section aria-labelledby="section-intro">
<p id="section-intro">
This Privacy Policy describes how <strong className="text-[#e0e0e0]">Relevant Media Properties, LLC</strong> ("we," "us," or "our"), publisher of AV Beat, Broadcast Beat, and BroadcastEngineering.com, collects, uses, and shares information about you when you use our websites and services. We are committed to protecting your privacy and complying with applicable data protection laws including GDPR and CCPA.
This Privacy Policy describes how <strong className="text-[#0F172A]">Relevant Media Properties, LLC</strong> ("we," "us," or "our"), publisher of AV Beat, Broadcast Beat, and BroadcastEngineering.com, collects, uses, and shares information about you when you use our websites and services. We are committed to protecting your privacy and complying with applicable data protection laws including GDPR and CCPA.
</p>
</section>
<section aria-labelledby="section-1">
<h2 id="section-1" className="font-heading text-[#e0e0e0] text-xl font-bold mb-3">1. Information We Collect</h2>
<h3 className="font-heading text-[#ccc] text-base font-semibold mb-2">Information You Provide</h3>
<h2 id="section-1" className="font-heading text-[#0F172A] text-xl font-bold mb-3">1. Information We Collect</h2>
<h3 className="font-heading text-[#1e293b] text-base font-semibold mb-2">Information You Provide</h3>
<p>We collect information you provide directly to us, such as when you subscribe to our newsletter, create an account, post in our forum, or contact us. This may include your name, email address, username, and professional information.</p>
<h3 className="font-heading text-[#ccc] text-base font-semibold mb-2 mt-4">Information Collected Automatically</h3>
<h3 className="font-heading text-[#1e293b] text-base font-semibold mb-2 mt-4">Information Collected Automatically</h3>
<p className="mt-2">We also collect information automatically when you use our sites, including:</p>
<ul className="list-disc list-inside mt-2 space-y-1 text-[#999]">
<ul className="list-disc list-inside mt-2 space-y-1 text-[#475569]">
<li>IP address and approximate geographic location</li>
<li>Browser type, version, and operating system</li>
<li>Pages visited, time spent, and referring URLs</li>
<li>Device identifiers and cookie data</li>
<li>Interaction data (clicks, scrolls, video plays)</li>
</ul>
<h3 className="font-heading text-[#ccc] text-base font-semibold mb-2 mt-4">Cookies and Tracking Technologies</h3>
<h3 className="font-heading text-[#1e293b] text-base font-semibold mb-2 mt-4">Cookies and Tracking Technologies</h3>
<p className="mt-2">We use cookies, web beacons, and similar tracking technologies. You can control cookie preferences through our cookie consent banner or your browser settings. Essential cookies required for site functionality cannot be disabled.</p>
</section>
<section aria-labelledby="section-2">
<h2 id="section-2" className="font-heading text-[#e0e0e0] text-xl font-bold mb-3">2. How We Use Your Information</h2>
<h2 id="section-2" className="font-heading text-[#0F172A] text-xl font-bold mb-3">2. How We Use Your Information</h2>
<p>We use the information we collect to:</p>
<ul className="list-disc list-inside mt-2 space-y-1 text-[#999]">
<ul className="list-disc list-inside mt-2 space-y-1 text-[#475569]">
<li>Provide, maintain, and improve our editorial content and services</li>
<li>Send newsletters and editorial content you have subscribed to</li>
<li>Respond to your comments, questions, and support requests</li>
@@ -59,73 +59,73 @@ export default function PrivacyPage() {
<li>Detect and prevent fraud, abuse, and security incidents</li>
<li>Comply with legal obligations</li>
</ul>
<p className="mt-3"><strong className="text-[#ccc]">Legal basis (GDPR):</strong> We process your data based on consent (newsletter subscriptions, analytics cookies), legitimate interests (site security, fraud prevention), and contractual necessity (account management).</p>
<p className="mt-3"><strong className="text-[#1e293b]">Legal basis (GDPR):</strong> We process your data based on consent (newsletter subscriptions, analytics cookies), legitimate interests (site security, fraud prevention), and contractual necessity (account management).</p>
</section>
<section aria-labelledby="section-3">
<h2 id="section-3" className="font-heading text-[#e0e0e0] text-xl font-bold mb-3">3. Information Sharing</h2>
<h2 id="section-3" className="font-heading text-[#0F172A] text-xl font-bold mb-3">3. Information Sharing</h2>
<p>We do not sell your personal information. We may share information with:</p>
<ul className="list-disc list-inside mt-2 space-y-1 text-[#999]">
<li><strong className="text-[#ccc]">Service providers</strong> who assist in operating our websites (hosting, email delivery, analytics)</li>
<li><strong className="text-[#ccc]">Advertising partners</strong> for serving and measuring ad campaigns (subject to your consent)</li>
<li><strong className="text-[#ccc]">Legal authorities</strong> when required by law or to protect our rights</li>
<li><strong className="text-[#ccc]">Business successors</strong> in the event of a merger, acquisition, or sale of assets</li>
<ul className="list-disc list-inside mt-2 space-y-1 text-[#475569]">
<li><strong className="text-[#1e293b]">Service providers</strong> who assist in operating our websites (hosting, email delivery, analytics)</li>
<li><strong className="text-[#1e293b]">Advertising partners</strong> for serving and measuring ad campaigns (subject to your consent)</li>
<li><strong className="text-[#1e293b]">Legal authorities</strong> when required by law or to protect our rights</li>
<li><strong className="text-[#1e293b]">Business successors</strong> in the event of a merger, acquisition, or sale of assets</li>
</ul>
</section>
<section aria-labelledby="section-4">
<h2 id="section-4" className="font-heading text-[#e0e0e0] text-xl font-bold mb-3">4. Cookies Policy</h2>
<h2 id="section-4" className="font-heading text-[#0F172A] text-xl font-bold mb-3">4. Cookies Policy</h2>
<p>We use the following categories of cookies:</p>
<div className="mt-3 space-y-3">
<div className="bg-[#FFFFFF] border border-[#DCE6F2] rounded p-3">
<p className="font-bold text-[#ccc] text-sm">Essential Cookies</p>
<p className="font-bold text-[#1e293b] text-sm">Essential Cookies</p>
<p className="text-sm mt-1">Required for the website to function. Cannot be disabled. Includes session management and security tokens.</p>
</div>
<div className="bg-[#FFFFFF] border border-[#DCE6F2] rounded p-3">
<p className="font-bold text-[#ccc] text-sm">Analytics Cookies</p>
<p className="font-bold text-[#1e293b] text-sm">Analytics Cookies</p>
<p className="text-sm mt-1">Help us understand how visitors interact with our site (Google Analytics). Requires your consent.</p>
</div>
<div className="bg-[#FFFFFF] border border-[#DCE6F2] rounded p-3">
<p className="font-bold text-[#ccc] text-sm">Advertising Cookies</p>
<p className="font-bold text-[#1e293b] text-sm">Advertising Cookies</p>
<p className="text-sm mt-1">Used to serve relevant ads and measure campaign performance. Requires your consent.</p>
</div>
</div>
</section>
<section aria-labelledby="section-5">
<h2 id="section-5" className="font-heading text-[#e0e0e0] text-xl font-bold mb-3">5. Your Rights</h2>
<h2 id="section-5" className="font-heading text-[#0F172A] text-xl font-bold mb-3">5. Your Rights</h2>
<p>Depending on your location, you may have the following rights regarding your personal data:</p>
<ul className="list-disc list-inside mt-2 space-y-1 text-[#999]">
<li><strong className="text-[#ccc]">Access:</strong> Request a copy of the personal data we hold about you</li>
<li><strong className="text-[#ccc]">Correction:</strong> Request correction of inaccurate or incomplete data</li>
<li><strong className="text-[#ccc]">Deletion:</strong> Request deletion of your personal data ("right to be forgotten")</li>
<li><strong className="text-[#ccc]">Portability:</strong> Receive your data in a structured, machine-readable format</li>
<li><strong className="text-[#ccc]">Opt-out (CCPA):</strong> California residents may opt out of the sale of personal information</li>
<li><strong className="text-[#ccc]">Unsubscribe:</strong> Opt out of marketing emails at any time via the unsubscribe link</li>
<ul className="list-disc list-inside mt-2 space-y-1 text-[#475569]">
<li><strong className="text-[#1e293b]">Access:</strong> Request a copy of the personal data we hold about you</li>
<li><strong className="text-[#1e293b]">Correction:</strong> Request correction of inaccurate or incomplete data</li>
<li><strong className="text-[#1e293b]">Deletion:</strong> Request deletion of your personal data ("right to be forgotten")</li>
<li><strong className="text-[#1e293b]">Portability:</strong> Receive your data in a structured, machine-readable format</li>
<li><strong className="text-[#1e293b]">Opt-out (CCPA):</strong> California residents may opt out of the sale of personal information</li>
<li><strong className="text-[#1e293b]">Unsubscribe:</strong> Opt out of marketing emails at any time via the unsubscribe link</li>
</ul>
<p className="mt-3">To exercise any of these rights, contact us at <a href="mailto:privacy@avbeat.com" className="text-[#1D4ED8] underline hover:text-blue-400 transition-colors">privacy@avbeat.com</a>. We will respond within 30 days.</p>
</section>
<section aria-labelledby="section-6">
<h2 id="section-6" className="font-heading text-[#e0e0e0] text-xl font-bold mb-3">6. Data Retention</h2>
<h2 id="section-6" className="font-heading text-[#0F172A] text-xl font-bold mb-3">6. Data Retention</h2>
<p>We retain personal data for as long as necessary to provide our services and comply with legal obligations. Newsletter subscriber data is retained until you unsubscribe. Account data is retained for the life of your account plus 90 days after deletion.</p>
</section>
<section aria-labelledby="section-7">
<h2 id="section-7" className="font-heading text-[#e0e0e0] text-xl font-bold mb-3">7. Children's Privacy</h2>
<h2 id="section-7" className="font-heading text-[#0F172A] text-xl font-bold mb-3">7. Children's Privacy</h2>
<p>Our services are not directed to children under 13 years of age. We do not knowingly collect personal information from children under 13. If you believe we have inadvertently collected such information, please contact us immediately.</p>
</section>
<section aria-labelledby="section-8">
<h2 id="section-8" className="font-heading text-[#e0e0e0] text-xl font-bold mb-3">8. Changes to This Policy</h2>
<h2 id="section-8" className="font-heading text-[#0F172A] text-xl font-bold mb-3">8. Changes to This Policy</h2>
<p>We may update this Privacy Policy from time to time. We will notify you of significant changes by posting a notice on our website or sending an email to newsletter subscribers. Your continued use of our services after changes take effect constitutes acceptance of the updated policy.</p>
</section>
<section aria-labelledby="section-9">
<h2 id="section-9" className="font-heading text-[#e0e0e0] text-xl font-bold mb-3">9. Contact Us</h2>
<h2 id="section-9" className="font-heading text-[#0F172A] text-xl font-bold mb-3">9. Contact Us</h2>
<p>For privacy-related questions, data requests, or to report a concern:</p>
<address className="not-italic mt-3 space-y-1 text-[#999]">
<p><strong className="text-[#ccc]">Relevant Media Properties, LLC</strong></p>
<address className="not-italic mt-3 space-y-1 text-[#475569]">
<p><strong className="text-[#1e293b]">Relevant Media Properties, LLC</strong></p>
<p>Privacy Officer</p>
<p>Email: <a href="mailto:privacy@avbeat.com" className="text-[#1D4ED8] underline hover:text-blue-400 transition-colors">privacy@avbeat.com</a></p>
</address>

View File

@@ -35,7 +35,7 @@ export default async function SearchPage({ searchParams }: SearchPageProps) {
<span className="section-label">Search</span>
<div className="flex-1 h-px bg-[#DCE6F2]" />
</div>
<h1 className="font-heading text-white text-3xl font-bold">
<h1 className="font-heading text-[#0F172A] text-3xl font-bold">
{query ? `Results for "${query}"` : "Search AV Beat"}
</h1>
<p className="text-[#777] font-body text-sm mt-2">
@@ -64,7 +64,7 @@ export default async function SearchPage({ searchParams }: SearchPageProps) {
<Link
key={article.slug}
href={`/news/${article.slug}`}
className="flex gap-4 py-5 border-b border-[#222] group hover:bg-[#111] transition-colors px-2 -mx-2"
className="flex gap-4 py-5 border-b border-[#DCE6F2] group hover:bg-[#e2e8f0] transition-colors px-2 -mx-2 rounded-sm"
>
<div className="flex-shrink-0 w-[160px] h-[105px] relative overflow-hidden rounded-sm">
<AppImage
@@ -81,7 +81,7 @@ export default async function SearchPage({ searchParams }: SearchPageProps) {
{article.category || "NEWS"}
</span>
</div>
<h2 className="font-heading text-[#e0e0e0] text-base font-bold leading-snug mb-2 group-hover:text-[#1D4ED8] transition-colors line-clamp-2">
<h2 className="font-heading text-[#0F172A] text-base font-bold leading-snug mb-2 group-hover:text-[#1D4ED8] transition-colors line-clamp-2">
{article.title || "Untitled"}
</h2>
<p className="text-[#777] font-body text-sm leading-relaxed line-clamp-2">

View File

@@ -14,38 +14,38 @@ export default function TermsPage() {
<Header />
<div className="bg-[#111] border-b border-[#222] py-8">
<div className="max-w-container mx-auto px-4">
<h1 className="font-heading text-white text-3xl font-bold">Terms of Service</h1>
<p className="text-[#555] font-body text-sm mt-2">Last updated: March 2026</p>
<h1 className="font-heading text-[#0F172A] text-3xl font-bold">Terms of Service</h1>
<p className="text-[#475569] font-body text-sm mt-2">Last updated: March 2026</p>
</div>
</div>
<main className="max-w-container mx-auto px-4 py-10">
<div className="max-w-3xl space-y-8 font-body text-[#aaa] leading-relaxed">
<div className="max-w-3xl space-y-8 font-body text-[#1e293b] leading-relaxed">
<section>
<h2 className="font-heading text-[#e0e0e0] text-xl font-bold mb-3">1. Acceptance of Terms</h2>
<h2 className="font-heading text-[#0F172A] text-xl font-bold mb-3">1. Acceptance of Terms</h2>
<p>By accessing and using AV Beat, you accept and agree to be bound by the terms and provisions of this agreement. If you do not agree to these terms, please do not use our service.</p>
</section>
<section>
<h2 className="font-heading text-[#e0e0e0] text-xl font-bold mb-3">2. Use of Content</h2>
<h2 className="font-heading text-[#0F172A] text-xl font-bold mb-3">2. Use of Content</h2>
<p>All content on AV Beat is the property of Relevant Media Properties or its content suppliers and is protected by applicable intellectual property laws. You may not reproduce, distribute, or create derivative works from our content without express written permission.</p>
</section>
<section>
<h2 className="font-heading text-[#e0e0e0] text-xl font-bold mb-3">3. User Accounts</h2>
<h2 className="font-heading text-[#0F172A] text-xl font-bold mb-3">3. User Accounts</h2>
<p>If you create an account on AV Beat, you are responsible for maintaining the confidentiality of your account credentials and for all activities that occur under your account. You agree to notify us immediately of any unauthorized use of your account.</p>
</section>
<section>
<h2 className="font-heading text-[#e0e0e0] text-xl font-bold mb-3">4. Community Standards</h2>
<h2 className="font-heading text-[#0F172A] text-xl font-bold mb-3">4. Community Standards</h2>
<p>Users participating in our forum and community features agree to maintain respectful discourse. We reserve the right to remove content and suspend accounts that violate our community standards, including content that is abusive, defamatory, or otherwise harmful.</p>
</section>
<section>
<h2 className="font-heading text-[#e0e0e0] text-xl font-bold mb-3">5. Disclaimer of Warranties</h2>
<h2 className="font-heading text-[#0F172A] text-xl font-bold mb-3">5. Disclaimer of Warranties</h2>
<p>AV Beat is provided "as is" without warranty of any kind. We do not warrant that the service will be uninterrupted or error-free. We make no warranties regarding the accuracy or completeness of any content on the site.</p>
</section>
<section>
<h2 className="font-heading text-[#e0e0e0] text-xl font-bold mb-3">6. Limitation of Liability</h2>
<h2 className="font-heading text-[#0F172A] text-xl font-bold mb-3">6. Limitation of Liability</h2>
<p>Relevant Media Properties shall not be liable for any indirect, incidental, special, consequential, or punitive damages resulting from your use of or inability to use the service.</p>
</section>
<section>
<h2 className="font-heading text-[#e0e0f0] text-xl font-bold mb-3">7. Contact</h2>
<h2 className="font-heading text-[#0F172A] text-xl font-bold mb-3">7. Contact</h2>
<p>Questions about these Terms? Contact us at <a href="mailto:legal@avbeat.com" className="text-[#1D4ED8] hover:underline">legal@avbeat.com</a>.</p>
</section>
</div>

View File

@@ -168,7 +168,7 @@ export default function AISuggestedArticles({ variant = 'compact' }: Props) {
<Link
key={article.slug}
href={`/news/${article.slug}`}
className="flex gap-3 group hover:bg-[#111] transition-colors -mx-1 px-1 py-1 rounded-sm"
className="flex gap-3 group hover:bg-[#e2e8f0] transition-colors -mx-1 px-1 py-1 rounded-sm"
>
<div className="relative w-16 h-12 flex-shrink-0 overflow-hidden rounded-sm">
<AppImage

View File

@@ -15,7 +15,7 @@ export default function AskBBAI() {
{
role: "assistant",
content:
"Hi — I'm BB AI. Ask me anything about broadcast, production, or post technology. I'll cite sources from the AV Beat archive.",
"Hi — I'm AV Beat AI. Ask me anything about pro AV, live production, or display technology. I'll cite sources from the AV Beat archive.",
},
]);
const [err, setErr] = useState<string | null>(null);
@@ -68,13 +68,13 @@ export default function AskBBAI() {
type="button"
onClick={() => setOpen(true)}
className="fixed bottom-16 right-6 z-40 bg-black text-white rounded-full pl-5 pr-5 py-3 shadow-2xl flex items-center gap-3 hover:bg-zinc-900 transition-colors"
aria-label="Ask BB AI"
aria-label="Ask AV Beat AI"
>
<span className="relative inline-block w-3 h-3">
<span className="absolute inset-0 rounded-full bg-[var(--color-text-info,#60a5fa)]" />
<span className="bb-ring" />
</span>
<span className="font-serif">Ask BB AI</span>
<span className="font-serif">Ask AV Beat AI</span>
</button>
)}
@@ -82,7 +82,7 @@ export default function AskBBAI() {
<div
ref={drawerRef}
role="dialog"
aria-label="Ask BB AI"
aria-label="Ask AV Beat AI"
className="fixed right-0 top-0 bottom-0 z-50 w-full sm:w-[420px] bg-[#0a0a0a] border-l border-[#DCE6F2] flex flex-col"
>
<header className="flex items-center justify-between px-5 py-4 border-b border-[#DCE6F2]">
@@ -91,7 +91,7 @@ export default function AskBBAI() {
<span className="absolute inset-0 rounded-full bg-[var(--color-text-info,#60a5fa)]" />
<span className="bb-ring" />
</span>
<h2 className="font-serif text-lg font-semibold text-white">BB AI</h2>
<h2 className="font-serif text-lg font-semibold text-white">AV Beat AI</h2>
</div>
<button
onClick={() => setOpen(false)}

View File

@@ -63,7 +63,7 @@ const footerColumns = [
export default function Footer() {
return (
<footer className="bg-[#F8FAFC] border-t border-[#222]">
<footer className="bg-[#F8FAFC] border-t border-[#DCE6F2]">
{/* Footer Ad Row — site-wide 728x90 (rotates if multiple in pool) */}
<div className="max-w-container mx-auto px-4 pt-8 pb-4">
{pickAds("728x90", 1).length > 0 && (
@@ -73,7 +73,7 @@ export default function Footer() {
)}
{/* Multi-column link section */}
<div className="border-t border-[#222] pt-8 pb-6 grid grid-cols-2 md:grid-cols-4 gap-8">
<div className="border-t border-[#DCE6F2] pt-8 pb-6 grid grid-cols-2 md:grid-cols-4 gap-8">
{footerColumns?.map((col) =>
<div key={col?.heading}>
<h4 className="font-body font-bold text-xs text-[#1D4ED8] uppercase tracking-widest mb-4 pb-2 border-b border-[#1D4ED8]/20">
@@ -87,13 +87,13 @@ export default function Footer() {
href={link?.href}
target="_blank"
rel="noopener noreferrer"
className="footer-link font-body text-sm text-[#777777] hover:text-[#1D4ED8] transition-colors leading-relaxed inline-block">
className="footer-link font-body text-sm text-[#475569] hover:text-[#1D4ED8] transition-colors leading-relaxed inline-block">
{link?.label}
</a> :
<Link
href={link?.href}
className="footer-link font-body text-sm text-[#777777] hover:text-[#1D4ED8] transition-colors leading-relaxed inline-block">
className="footer-link font-body text-sm text-[#475569] hover:text-[#1D4ED8] transition-colors leading-relaxed inline-block">
{link?.label}
</Link>
}
@@ -106,7 +106,7 @@ export default function Footer() {
{/* Footer Bottom */}
{/* DO NOT OVERRIDE — footer bottom bar layout */}
<div className="border-t border-[#222] pt-5 pb-3 flex flex-col sm:flex-row items-center justify-between gap-4">
<div className="border-t border-[#DCE6F2] pt-5 pb-3 flex flex-col sm:flex-row items-center justify-between gap-4">
<Link
href="/home-page"
aria-label="AV Beat — home"
@@ -121,24 +121,24 @@ export default function Footer() {
<div className="flex items-center gap-4">
<a href="https://linkedin.com/company/avbeat" target="_blank" rel="noopener noreferrer" aria-label="AV Beat on LinkedIn"
className="text-[#555] hover:text-[#1D4ED8] transition-colors social-icon">
className="text-[#475569] hover:text-[#1D4ED8] transition-colors social-icon">
<LinkedInIcon size={17} />
</a>
<a href="https://instagram.com/avbeat" target="_blank" rel="noopener noreferrer" aria-label="AV Beat on Instagram"
className="text-[#555] hover:text-[#1D4ED8] transition-colors social-icon">
className="text-[#475569] hover:text-[#1D4ED8] transition-colors social-icon">
<InstagramIcon size={17} />
</a>
<a href="https://twitter.com/avbeat" target="_blank" rel="noopener noreferrer" aria-label="AV Beat on Twitter/X"
className="text-[#555] hover:text-[#1D4ED8] transition-colors social-icon">
className="text-[#475569] hover:text-[#1D4ED8] transition-colors social-icon">
<TwitterXIcon size={17} />
</a>
<a href="https://facebook.com/avbeat" target="_blank" rel="noopener noreferrer" aria-label="AV Beat on Facebook"
className="text-[#555] hover:text-[#1D4ED8] transition-colors social-icon">
className="text-[#475569] hover:text-[#1D4ED8] transition-colors social-icon">
<FacebookIcon size={17} />
</a>
</div>
<div className="flex items-center gap-4 text-xs font-body text-[#555]">
<div className="flex items-center gap-4 text-xs font-body text-[#475569]">
<Link href="/privacy" className="hover:text-[#1D4ED8] transition-colors">Privacy Policy</Link>
<Link href="/terms" className="hover:text-[#1D4ED8] transition-colors">Terms of Service</Link>
<span>

View File

@@ -298,7 +298,7 @@ export default function Header() {
{/* Mobile Hamburger */}
<button
ref={hamburgerRef}
className="lg:hidden p-2 text-[#cccccc] focus:outline-none focus-visible:ring-2 focus-visible:ring-[#1D4ED8]"
className="lg:hidden p-2 text-white focus:outline-none focus-visible:ring-2 focus-visible:ring-[#1D4ED8]"
onClick={() => setMobileOpen(!mobileOpen)}
aria-label={mobileOpen ? "Close menu" : "Open menu"}
aria-expanded={mobileOpen}
@@ -340,7 +340,7 @@ export default function Header() {
{currentUserId && (
<Link
href="/account"
className="px-2 py-2.5 text-sm font-body font-bold uppercase tracking-wide text-[#cccccc] hover:text-[#1D4ED8] hover:bg-[#FFFFFF] border-b border-[#222] transition-colors focus:outline-none focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-[#1D4ED8] flex items-center gap-2"
className="px-2 py-2.5 text-sm font-body font-bold uppercase tracking-wide text-[#0F172A] hover:text-[#1D4ED8] hover:bg-[#FFFFFF] border-b border-[#DCE6F2] transition-colors focus:outline-none focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-[#1D4ED8] 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" />
@@ -352,7 +352,7 @@ export default function Header() {
{isAdmin && (
<Link
href="/admin/import"
className="px-2 py-2.5 text-sm font-body font-bold uppercase tracking-wide text-[#cccccc] hover:text-[#1D4ED8] hover:bg-[#FFFFFF] border-b border-[#222] transition-colors focus:outline-none focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-[#1D4ED8] flex items-center gap-2"
className="px-2 py-2.5 text-sm font-body font-bold uppercase tracking-wide text-[#0F172A] hover:text-[#1D4ED8] hover:bg-[#FFFFFF] border-b border-[#DCE6F2] transition-colors focus:outline-none focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-[#1D4ED8] 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" />

View File

@@ -338,7 +338,7 @@ function NotificationItem({ notification: n }: { notification: Notification }) {
if (dismissed) return null;
const content = (
<div className={`group flex items-start gap-3 px-4 py-3 border-b border-[#1e1e1e] hover:bg-[#1e2a3a] transition-colors ${!n.is_read ? "bg-[#1a2030]" : ""}`}>
<div className={`group flex items-start gap-3 px-4 py-3 border-b border-[#DCE6F2] hover:bg-[#e2e8f0] transition-colors ${!n.is_read ? "bg-[#EFF6FF]" : ""}`}>
{/* Type icon */}
<div className={`flex-shrink-0 mt-0.5 ${cfg.color}`}>{cfg.icon}</div>