feat(brand+promotion): brand-gradient system, restyled /about/* + team + contact, alias-based client matcher
Three coupled rollouts in one shot.
PART A — client highlight matcher (DB migration applied separately):
- promoted-articles.ts: AdvertiserName now carries brand_aliases; matcher
iterates legal name + every alias with word-boundary regex and picks the
longest match across all candidates so "Magewell Launches…" resolves to
"Magewell Electronics Co., Ltd." via its Magewell alias.
- New isStoryAboutClient gate: hard-accept at position 0, accept if any
editorial frame ("Product Spotlight:", "Review:", "First Look", …) appears
in the prefix, hard-reject if the prefix ends with a partner/usage phrase
("with", "using", "powered by", "dealer of", "integration with", "used",
"deploys", "runs on", "leverages", …), otherwise accept within a 32-char
subject window. Validated against 5,000 historical posts: 27 partner
false-positives blocked, 3 editorial-frame stories correctly saved, the
Magewell article now highlights.
PART B — restyling /about, /about/team, /about/contact:
- New .brand-gradient utility: #2563EB→#1E3A8A linear-gradient with a
16%-opacity diagonal sheen that sweeps in the first 30% of a 7s cycle
and rests offscreen-right for the rest. Respects prefers-reduced-motion
(band parked statically at 6% opacity).
- Team page: dark legacy hero (red radial, #ff5a55 eyebrows) replaced with
brand-gradient hero; outer text wrapper #e5e7eb → #0F172A so section
headings stop being white-on-white; all serif H1/H2/H3 → font-display;
red accents (#ff5a55 / #ff6b66 / rgba(214,7,1)) → blue (#93C5FD / #7DD3FC
/ rgba(29,78,216)).
- About page: H1 + Stat values → font-display; Stat cards get a brand-
gradient top stripe.
- Contact page: outer wrapper #e5e7eb → #0F172A (fixes the white-on-white
Contact H1); H1 gets explicit text-[#0F172A] + font-display; dark contact
cards keep dark bg but gain a brand-gradient top stripe + explicit
text-[#e5e7eb] body + brighter cyan eyebrow/link colors.
PART C — richer Industry News client highlight:
- ArticleFeed: client-promoted row swaps the static border-l-4 for an
absolute-positioned .brand-gradient strip on the left edge (sheen pulses
through). Row gets a slightly richer bg tint (from-#1D4ED8/12 via /4).
- HIGHLIGHT pill now uses .brand-gradient instead of the static blue chip.
Also shipping the earlier-staged work:
- AnimatedLogo onDark: white ring around tile + brighter (#E2E8F0) tagline
+ cyan accent rule for the blue header.
- Article-prose: em/strong/code dark colors (em fixes the trailing
copyright/trademark ghost text), hr line color, figcaption readable.
- ArticleComments: "Sign in to join the discussion" bar uses brand-gradient
+ white/outline buttons that read on blue.
- Forum: Discover/Following, Newest/Top Voted/Unanswered, Sign in to post,
Start a thread, Create account — slim pills, brand-gradient active.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -93,21 +93,20 @@ export default async function TeamPage() {
|
||||
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-[#0F172A]">
|
||||
<div className="lg:grid lg:grid-cols-[1fr,300px] lg:gap-10">
|
||||
<main>
|
||||
{/* Hero */}
|
||||
<header className="relative overflow-hidden rounded-xl mb-10 border border-[#1a1f2a] bg-gradient-to-br from-[#0d1118] via-[#0b0f17] to-[#0d1118]">
|
||||
<div className="absolute inset-0 opacity-[0.04] bg-[radial-gradient(ellipse_at_top_right,#d60701,transparent_60%)]" aria-hidden />
|
||||
<div className="relative px-6 py-10 sm:px-10 sm:py-14">
|
||||
<div className="inline-flex items-center gap-2 text-[10px] font-mono uppercase tracking-[0.22em] text-[#ff5a55] mb-3">
|
||||
<span className="w-6 h-px bg-[#1D4ED8]" />
|
||||
{/* Hero — brand-gradient (animated sheen) */}
|
||||
<header className="brand-gradient rounded-xl mb-10">
|
||||
<div className="px-6 py-10 sm:px-10 sm:py-14">
|
||||
<div className="inline-flex items-center gap-2 text-[10px] font-mono uppercase tracking-[0.22em] text-white/85 mb-3">
|
||||
<span className="w-6 h-px bg-white/60" />
|
||||
AV Beat · editorial
|
||||
</div>
|
||||
<h1 className="font-serif text-4xl md:text-5xl lg:text-6xl font-bold tracking-tight leading-tight">
|
||||
<h1 className="font-display text-4xl md:text-5xl lg:text-6xl font-bold tracking-tight leading-tight text-white">
|
||||
The team behind every byline
|
||||
</h1>
|
||||
<p className="mt-4 text-[#9ca3af] text-base md:text-lg max-w-2xl leading-relaxed">
|
||||
<p className="mt-4 text-white/80 text-base md:text-lg max-w-2xl leading-relaxed">
|
||||
Beats covered by trained AI personas working under house style, plus the
|
||||
business and support people who keep things moving.
|
||||
</p>
|
||||
@@ -117,7 +116,7 @@ export default async function TeamPage() {
|
||||
{/* Editorial team — three-col grid on desktop, larger portraits */}
|
||||
<section className="mb-14">
|
||||
<div className="flex items-baseline justify-between mb-5">
|
||||
<h2 className="font-serif text-2xl md:text-3xl font-bold tracking-tight">Editorial</h2>
|
||||
<h2 className="font-display text-2xl md:text-3xl font-bold tracking-tight">Editorial</h2>
|
||||
<span className="text-[10px] font-mono uppercase tracking-[0.18em] text-[#6c7686]">
|
||||
{team.length} {team.length === 1 ? "writer" : "writers"}
|
||||
</span>
|
||||
@@ -129,7 +128,7 @@ export default async function TeamPage() {
|
||||
return (
|
||||
<li
|
||||
key={p.slug}
|
||||
className="group relative rounded-xl border border-[#1a1f2a] bg-[#0b0f17] p-5 hover:border-[#1D4ED8]/50 hover:shadow-[0_0_0_1px_rgba(214,7,1,0.15)] transition-all"
|
||||
className="group relative rounded-xl border border-[#1a1f2a] bg-[#0b0f17] p-5 hover:border-[#1D4ED8]/50 hover:shadow-[0_0_0_1px_rgba(29,78,216,0.20)] transition-all"
|
||||
>
|
||||
{/* Top accent */}
|
||||
<div className="absolute top-0 left-5 right-5 h-px bg-gradient-to-r from-transparent via-[#1D4ED8]/40 to-transparent opacity-0 group-hover:opacity-100 transition-opacity" aria-hidden />
|
||||
@@ -146,16 +145,16 @@ export default async function TeamPage() {
|
||||
/>
|
||||
</a>
|
||||
) : (
|
||||
<div className="w-24 h-24 rounded-full border-2 border-[#1a1f2a] bg-[#141a25] flex items-center justify-center font-serif font-bold text-2xl text-[#6c7686] flex-shrink-0">
|
||||
<div className="w-24 h-24 rounded-full border-2 border-[#1a1f2a] bg-[#141a25] flex items-center justify-center font-display font-bold text-2xl text-[#6c7686] flex-shrink-0">
|
||||
{initials(p.name)}
|
||||
</div>
|
||||
)}
|
||||
<div className="flex-1 min-w-0">
|
||||
<a href={`/authors/${p.slug}`} className="block hover:underline">
|
||||
<h3 className="font-serif text-xl font-bold leading-tight">{p.name}</h3>
|
||||
<h3 className="font-display text-xl font-bold leading-tight">{p.name}</h3>
|
||||
</a>
|
||||
{(p.beat || p.slug === "ryan-salazar") && (
|
||||
<div className="inline-block mt-1.5 px-2 py-0.5 rounded-sm bg-[#1D4ED8]/10 border border-[#1D4ED8]/25 text-[10px] font-mono uppercase tracking-[0.12em] text-[#ff6b66]">
|
||||
<div className="inline-block mt-1.5 px-2 py-0.5 rounded-sm bg-[#1D4ED8]/15 border border-[#1D4ED8]/35 text-[10px] font-mono uppercase tracking-[0.12em] text-[#93C5FD]">
|
||||
{displayBeat(p)}
|
||||
</div>
|
||||
)}
|
||||
@@ -173,11 +172,11 @@ export default async function TeamPage() {
|
||||
<ObfuscatedEmail
|
||||
user={e.user}
|
||||
domain={e.domain}
|
||||
className="text-[#aab1bd] hover:text-[#ff6b66] font-mono"
|
||||
className="text-[#aab1bd] hover:text-[#7DD3FC] font-mono"
|
||||
/>
|
||||
<a
|
||||
href={`/authors/${p.slug}`}
|
||||
className="text-[10px] font-mono uppercase tracking-[0.12em] text-[#6c7686] hover:text-[#ff6b66]"
|
||||
className="text-[10px] font-mono uppercase tracking-[0.12em] text-[#6c7686] hover:text-[#7DD3FC]"
|
||||
>
|
||||
View →
|
||||
</a>
|
||||
@@ -193,14 +192,14 @@ export default async function TeamPage() {
|
||||
{ops.length > 0 && (
|
||||
<section>
|
||||
<div className="flex items-baseline justify-between mb-5">
|
||||
<h2 className="font-serif text-2xl md:text-3xl font-bold tracking-tight">
|
||||
<h2 className="font-display text-2xl md:text-3xl font-bold tracking-tight">
|
||||
Accounts & support
|
||||
</h2>
|
||||
<span className="text-[10px] font-mono uppercase tracking-[0.18em] text-[#6c7686]">
|
||||
{ops.length} {ops.length === 1 ? "contact" : "contacts"}
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-[#9ca3af] text-sm mb-5 max-w-2xl">
|
||||
<p className="text-[#475569] text-sm mb-5 max-w-2xl">
|
||||
For billing, accounts receivable, vendor onboarding, sales, and
|
||||
general support questions — these are the people to reach.
|
||||
</p>
|
||||
@@ -220,13 +219,13 @@ export default async function TeamPage() {
|
||||
className="w-20 h-20 rounded-full border-2 border-[#1a1f2a] flex-shrink-0 object-cover"
|
||||
/>
|
||||
) : (
|
||||
<div className="w-20 h-20 rounded-full border-2 border-[#1a1f2a] flex-shrink-0 bg-[#141a25] flex items-center justify-center font-serif font-bold text-xl text-[#6c7686]">
|
||||
<div className="w-20 h-20 rounded-full border-2 border-[#1a1f2a] flex-shrink-0 bg-[#141a25] flex items-center justify-center font-display font-bold text-xl text-[#6c7686]">
|
||||
{initials(p.display_name)}
|
||||
</div>
|
||||
)}
|
||||
<div className="flex-1 min-w-0">
|
||||
<h3 className="font-serif text-lg font-bold leading-tight">{p.display_name}</h3>
|
||||
<div className="inline-block mt-1 px-2 py-0.5 rounded-sm bg-[#FFFFFF] border border-[#1D4ED8]/30 text-[10px] font-mono uppercase tracking-[0.12em] text-[#7ba0ff]">
|
||||
<h3 className="font-display text-lg font-bold leading-tight">{p.display_name}</h3>
|
||||
<div className="inline-block mt-1 px-2 py-0.5 rounded-sm bg-[#1D4ED8]/15 border border-[#1D4ED8]/35 text-[10px] font-mono uppercase tracking-[0.12em] text-[#93C5FD]">
|
||||
{p.role}
|
||||
</div>
|
||||
<div className="text-xs text-[#aab1bd] mt-3 space-y-1">
|
||||
@@ -235,13 +234,13 @@ export default async function TeamPage() {
|
||||
if (!e) return null;
|
||||
return (
|
||||
<div className="font-mono">
|
||||
<ObfuscatedEmail user={e.user} domain={e.domain} className="hover:text-[#ff6b66]" />
|
||||
<ObfuscatedEmail user={e.user} domain={e.domain} className="hover:text-[#7DD3FC]" />
|
||||
</div>
|
||||
);
|
||||
})()}
|
||||
{p.phone && (
|
||||
<div>
|
||||
<a href={`tel:${p.phone.replace(/[^\d+]/g, '')}`} className="hover:text-[#ff6b66] font-mono">
|
||||
<a href={`tel:${p.phone.replace(/[^\d+]/g, '')}`} className="hover:text-[#7DD3FC] font-mono">
|
||||
{p.phone}{p.extension ? ` ext. ${p.extension}` : ''}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user