feat(brand): AV BEAT 2026 rebrand — blue/navy/white identity

- New AvBeatLogo inline-SVG component (rounded-square emblem with
  forward-leaning AV monogram + horizontal beam detail) at
  src/components/AvBeatLogo.tsx, three variants (full/wordmark/icon).
- Header.tsx now uses the responsive AV BEAT logo lockup in the
  top-left, links to /, full lockup on desktop (emblem+wordmark+tagline),
  emblem+wordmark on tablet, emblem-only on mobile.
- Removed DualSpeedTicker (the 'RECENT FORUM POSTS' ticker strip);
  the news ticker / glow chrome does not match the new aesthetic and the
  forum row was the explicit removal target.
- Tailwind theme + globals.css now expose the AV BEAT 2026 palette as
  semantic tokens: --brand-blue (#1D4ED8), --brand-blue-bright (#38BDF8),
  --brand-navy (#0F172A), --brand-bg (#F8FAFC), --brand-surface, --brand-border,
  --brand-text, --brand-text-muted. Legacy --color-* aliases re-point to the
  new tokens so any inline-styled component re-themes for free.
- Site-wide hex sweep migrates 2,769 hardcoded color literals across 144
  files from the old dark-broadcast palette to the new tokens (orange
  -> blue, dark-brown -> white surface / navy text, cream -> navy).
- Layout body class flipped from 'bb-neon' to 'bg-brand-bg text-brand-text'
  so the dark glow chrome no longer leaks through the new light theme.
This commit is contained in:
2026-06-03 12:07:18 +00:00
parent 39d2bf9073
commit 8042024c4a
146 changed files with 2219 additions and 2081 deletions

View File

@@ -9,7 +9,7 @@ const FLIGHT_COLORS: Record<string, string> = {
scheduled: 'bg-blue-400/10 text-blue-400 border-blue-400/20',
paused: 'bg-gray-600/20 text-gray-400 border-gray-600/20',
expired: 'bg-red-400/10 text-red-400 border-red-400/20',
cancelled: 'bg-[#231d18] text-[#555] border-[#3a322b]',
cancelled: 'bg-[#FFFFFF] text-[#555] border-[#DCE6F2]',
};
export default function AdOpsDashboardPage() {
@@ -43,7 +43,7 @@ export default function AdOpsDashboardPage() {
useEffect(() => { if (user) load(); }, [user, load]);
if (loading) return <div className="min-h-screen bg-[#0a0a0a] flex items-center justify-center"><div className="w-8 h-8 border-2 border-[#F0A623] border-t-transparent rounded-full animate-spin" /></div>;
if (loading) return <div className="min-h-screen bg-[#0a0a0a] flex items-center justify-center"><div className="w-8 h-8 border-2 border-[#1D4ED8] border-t-transparent rounded-full animate-spin" /></div>;
if (!user) return null;
return (
@@ -64,7 +64,7 @@ export default function AdOpsDashboardPage() {
{ label: 'Unpaid Active', key: 'unpaid_active', color: 'text-orange-400' },
{ label: 'Email Blasts Scheduled', key: 'email_scheduled', color: 'text-purple-400' },
].map(c => (
<div key={c.key} className="bg-[#111] border border-[#3a322b] rounded-lg p-4">
<div key={c.key} className="bg-[#111] border border-[#DCE6F2] rounded-lg p-4">
<p className={`text-2xl font-bold ${c.color}`}>{stats?.[c.key] ?? 0}</p>
<p className="text-xs text-[#888] mt-1">{c.label}</p>
</div>
@@ -73,25 +73,25 @@ export default function AdOpsDashboardPage() {
{/* Filters */}
<div className="flex gap-2 flex-wrap">
<select value={filterSite} onChange={e => setFilterSite(e.target.value)} className="px-2 py-1 bg-[#111] border border-[#3a322b] rounded text-xs text-[#888] focus:outline-none">
<select value={filterSite} onChange={e => setFilterSite(e.target.value)} className="px-2 py-1 bg-[#111] border border-[#DCE6F2] rounded text-xs text-[#888] focus:outline-none">
<option value="">All Sites</option>
{['avbeat','broadcastbeat','backlotbeat','broadcastengineering'].map(s => <option key={s} value={s}>{s}</option>)}
</select>
<select value={filterStatus} onChange={e => setFilterStatus(e.target.value)} className="px-2 py-1 bg-[#111] border border-[#3a322b] rounded text-xs text-[#888] focus:outline-none">
<select value={filterStatus} onChange={e => setFilterStatus(e.target.value)} className="px-2 py-1 bg-[#111] border border-[#DCE6F2] rounded text-xs text-[#888] focus:outline-none">
<option value="">All Statuses</option>
{['active','scheduled','paused','expired','cancelled'].map(s => <option key={s} value={s}>{s}</option>)}
</select>
</div>
{/* Active Flights Table */}
<div className="bg-[#111] border border-[#3a322b] rounded-lg overflow-x-auto">
<div className="px-4 py-3 border-b border-[#3a322b] flex items-center justify-between">
<div className="bg-[#111] border border-[#DCE6F2] rounded-lg overflow-x-auto">
<div className="px-4 py-3 border-b border-[#DCE6F2] flex items-center justify-between">
<h2 className="text-sm font-semibold">Active Flights</h2>
<Link href="/admin/adops/ios" className="text-xs text-[#F0A623] hover:underline">View All IOs </Link>
<Link href="/admin/adops/ios" className="text-xs text-[#1D4ED8] hover:underline">View All IOs </Link>
</div>
<table className="w-full text-sm">
<thead>
<tr className="border-b border-[#231d18]">
<tr className="border-b border-[#FFFFFF]">
{['Client','Product','Site','Start','End','Status','Salesperson','Paid',''].map(h => (
<th key={h} className="px-3 py-2 text-left text-xs text-[#555] font-medium whitespace-nowrap">{h}</th>
))}
@@ -103,7 +103,7 @@ export default function AdOpsDashboardPage() {
) : flights.length === 0 ? (
<tr><td colSpan={9} className="px-4 py-8 text-center text-[#555] text-xs">No flights found</td></tr>
) : flights.map((f: any) => (
<tr key={f.id} className="border-b border-[#231d18] hover:bg-[#231d18]">
<tr key={f.id} className="border-b border-[#FFFFFF] hover:bg-[#FFFFFF]">
<td className="px-3 py-2 text-white text-xs">{f.rmp_clients?.company_name ?? '—'}</td>
<td className="px-3 py-2 text-[#ccc] text-xs">{f.rmp_products?.name ?? '—'}</td>
<td className="px-3 py-2 text-[#888] text-xs capitalize">{f.rmp_orders?.site ?? '—'}</td>
@@ -117,7 +117,7 @@ export default function AdOpsDashboardPage() {
<span className={`px-2 py-0.5 rounded-full text-xs ${f.is_paid ? 'bg-green-400/10 text-green-400' : f.is_comp ? 'bg-blue-400/10 text-blue-400' : 'bg-yellow-400/10 text-yellow-400'}`}>{f.is_comp ? 'Comp' : f.is_paid ? 'Paid' : 'Unpaid'}</span>
</td>
<td className="px-3 py-2">
<Link href={`/admin/adops/ios/${f.id}`} className="text-xs text-[#F0A623] hover:underline">View</Link>
<Link href={`/admin/adops/ios/${f.id}`} className="text-xs text-[#1D4ED8] hover:underline">View</Link>
</td>
</tr>
))}
@@ -126,13 +126,13 @@ export default function AdOpsDashboardPage() {
</div>
{/* Email Schedule */}
<div className="bg-[#111] border border-[#3a322b] rounded-lg overflow-hidden">
<div className="px-4 py-3 border-b border-[#3a322b]">
<div className="bg-[#111] border border-[#DCE6F2] rounded-lg overflow-hidden">
<div className="px-4 py-3 border-b border-[#DCE6F2]">
<h2 className="text-sm font-semibold">Email Distribution Schedule</h2>
</div>
<table className="w-full text-sm">
<thead>
<tr className="border-b border-[#231d18]">
<tr className="border-b border-[#FFFFFF]">
{['Client','Type','Site','Scheduled Date','Status',''].map(h => (
<th key={h} className="px-3 py-2 text-left text-xs text-[#555] font-medium">{h}</th>
))}
@@ -142,7 +142,7 @@ export default function AdOpsDashboardPage() {
{emailSchedule.length === 0 ? (
<tr><td colSpan={6} className="px-4 py-6 text-center text-[#555] text-xs">No email blasts scheduled</td></tr>
) : emailSchedule.map((e: any) => (
<tr key={e.id} className="border-b border-[#231d18] hover:bg-[#231d18]">
<tr key={e.id} className="border-b border-[#FFFFFF] hover:bg-[#FFFFFF]">
<td className="px-3 py-2 text-white text-xs">{e.rmp_clients?.company_name ?? '—'}</td>
<td className="px-3 py-2 text-[#888] text-xs">{e.rmp_products?.product_type?.replace(/_/g, ' ')}</td>
<td className="px-3 py-2 text-[#888] text-xs capitalize">{e.rmp_orders?.site ?? '—'}</td>
@@ -151,7 +151,7 @@ export default function AdOpsDashboardPage() {
<span className={`px-2 py-0.5 rounded-full text-xs ${e.email_sent_at ? 'bg-green-400/10 text-green-400' : 'bg-blue-400/10 text-blue-400'}`}>{e.email_sent_at ? 'Sent' : 'Pending'}</span>
</td>
<td className="px-3 py-2">
{e.email_html_url && <a href={e.email_html_url} target="_blank" rel="noopener noreferrer" className="text-xs text-[#F0A623] hover:underline">Preview</a>}
{e.email_html_url && <a href={e.email_html_url} target="_blank" rel="noopener noreferrer" className="text-xs text-[#1D4ED8] hover:underline">Preview</a>}
</td>
</tr>
))}