AV beat banners point at images on broadcastbeat.com and on
advertising.relevantmediaproperties.com. Without these in the Next.js
remotePatterns allowlist, /_next/image proxy returns 400 and the page
falls back to article-placeholder-v2.svg.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Per Ryan 2026-06-05. The avbeat-domain editor@ address routed to the
local AVB mailbox; RMP-wide editorial inbox is the canonical destination
going forward. Single href + display-text change on /about/contact.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three pointed fixes:
/manufacturers (cloned from BB; still had broadcast vibe)
• Drop the hardcoded "NAB + IBC" filter chip.
• Per-card "2026 NAB Show" / "IBC 2026" badges replaced by dynamic
pills generated from shows_attending intersected with av.events
(so each card now shows the actual AV shows that exhibitor is
attending — InfoComm, CEDIA, ISE, DSE, etc.).
• Page intro counts: drop nabCount / ibcCount hardcoding, compute
"top 3 shows by exhibitor count" from the data and surface those
counts dynamically. With only InfoComm 2026 currently tagged the
line reads "851 at InfoComm 2026" — adds more rows once other
shows are scraped.
• Meta description + OG: pro-AV / display / signage instead of
"broadcast, post-production, and live-production."
/about/team phone formatting
• New formatPhone() helper: E.164 → "(213) 418-2600" pattern.
• Extension format: ", Ext. NNN" (capital E, comma-separated).
• tel: link still uses the raw digits + RFC-3966 ',ext' pause for
PBX auto-dial on supported clients.
/about page media-kit link
• Was href="/about/advertise" — a relative path that 404s (no such
route exists). Replaced with the absolute media-kit URL on
relevantmediaproperties.com that the /advertise + /about/contact
pages already use. Opens in a new tab.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
/show-coverage cards have bg-[#0b0f17] but the H3 had no color, so it
inherited text-[#0F172A] from the page wrapper — dark-on-dark, unreadable.
Forced text-white to match the header's main-menu text color.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mike Nann's distribute.users record has skip_rewrite=true (set when task
#19 added the column). distribute-rmp's submit route forwards the flag
in its payload (task #20). BB's receive route handles it (task #21).
AV Beat's receive route was missing the branch entirely AND was writing
to .schema('bb') instead of 'av' — a copy-paste bug from when this file
was cloned from BB. So every Mike Nann submission to AV Beat was either
landing in BB's schema (wrong) or trying to and failing.
Fixed in this commit:
src/app/api/submission-receive/route.ts
• .schema('bb') → .schema('av') (the copy-paste bug)
• Added skip_rewrite branch: when payload has skip_rewrite=true,
insert straight into av.wp_imported_posts with status=published,
noindex=true, and the contributor's firm/contact_name as byline.
Skips the native_articles → AI-rewrite path entirely. Mirrors BB's
pattern exactly. Audit row still written to original_submissions.
src/lib/articles/types.ts
• Article.noindex?: boolean — surfaces the DB column to the renderer.
src/lib/articles/legacy-source.ts
• SELECT_COLS adds noindex
• ImportedPostRow gains noindex field
• rowToArticle propagates !!row.noindex
src/app/news/[slug]/page.tsx + src/app/articles/[slug]/page.tsx
• generateMetadata: when article.noindex, set robots = no-index +
no-follow + nocache + googleBot no-image-index + other meta key
"googlebot-news": "noindex". Matches BB's pattern.
src/app/news-sitemap.xml/route.ts
• Adds .or('noindex.is.null,noindex.eq.false') so passthrough rows
don't pollute the Google News sitemap.
src/app/rss/route.ts
• Filters out a.noindex before emitting items.
Mike's existing user record is already flagged (DB verified), so the
moment this deploys + he submits, the next press release publishes
verbatim, gets noindex on every Google/social surface, and shows up
on the AV Beat news index without going through the AI rewrite job.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mobile admin chrome
- New <AdminShell> component: sticky dark top bar w/ hamburger that opens
a right-side drawer listing every admin section grouped by area
(Content / Editorial / Companies / Newsletter / AdOps / Accounting /
People). Closes on route change, Esc, or backdrop tap. Body scroll
locks while open.
- Wrapped /admin (dashboard) and /admin/articles with the shell. Other
admin pages still render their own layouts — they'll get the wrapper
in follow-ups; the shell sits ABOVE them so nothing breaks today.
Promote-story MVP (share URLs, no OAuth yet)
- New /admin/promote/[slug] page: per-article promote sheet w/ one button
per platform. Each uses that platform's standard share URL:
• LinkedIn → /sharing/share-offsite/?url=
• X → /intent/tweet?text=…&url=…&hashtags=…
• Facebook → /sharer/sharer.php?u=…
• Instagram → copies caption to clipboard + opens instagram:// camera
• Email → mailto: with subject + body pre-filled
On iPhone each button opens the platform's native app via universal
link. No OAuth, no API keys, works tonight.
- New "Promote" action button on every published article row in
/admin/articles — links to /admin/promote/<slug>.
Next session
- Meta OAuth (Facebook Page + IG Business) — Ryan to register the Meta
App in Business Suite first, then we wire one-tap server-side posting.
- LinkedIn OAuth + Marketing API.
- X paid API ($100/mo Basic decision pending).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Critical mobile bugs flagged from an iPhone screenshot.
1) Mobile hamburger menu — all main nav items (HOME / SHOW COVERAGE /
DIRECTORY / FORUM / READING LIST) were `text-white` on
`bg-[#F8FAFC]`, i.e. white-on-light. Effectively invisible. Legacy
styling from the dark-theme era that never got updated. Flipped to
`text-[#0F172A]` + `hover:bg-[#FFFFFF]` + `border-[#DCE6F2]` to match
the My Profile / WP Import links right below them that were already
correctly themed.
2) Secondary top nav (social icons / language switcher / Sign In + Join
/ newsletter email input) was a single h-8 flex row that always
rendered — on a phone-width viewport the row spills the email input
off the right edge. Added `hidden md:flex` so the whole bar
disappears on mobile. Affordances stay reachable via the hamburger
menu, in-forum Sign In/Join buttons, and the footer.
3) Forum auth pages (login, register, forgot-password, reset-password)
had `text-white` on every H1 AND on every form input that uses
`bg-[#F8FAFC]`. So users opening any of those four pages saw a blank
white card with invisible labels and couldn't see what they were
typing into the password fields. Same dark-theme regression as #1.
Blanket-replaced `text-white` with `text-[#0F172A]` across all four
files, then restored `text-white` only inside classNames that also
contain `bg-[#1D4ED8]` / `bg-[#1E3A8A]` / `brand-gradient` (the
submit buttons — those WERE correct).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The new A-monogram placeholder shipped in d8ca8ff was correct in the
deployed container, but Cloudflare was serving the previous cached SVG
(cf-cache-status: HIT, last-modified from this morning) because the
account token doesn't carry Zone:Cache Purge scope, so we couldn't
issue an API purge.
Renaming the file to article-placeholder-v2.svg gives CF a fresh URL
to cache, sidestepping the missing-permission entirely. Updated all
6 referencing files (AppImage fallback, legacy-source FALLBACK_IMAGE
constants, FeaturedBento[FromDb], manufacturers/authors pages).
Old file (cached as the old wordmark) just becomes a dangling asset —
not referenced from anywhere, harmless.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two pointed bugs on the article detail page:
1) Width alignment. The right-rail Related Articles and Related Forum
Posts boxes were free-stretching to the lg:col-span-4 width while the
SidebarAdStack below them rendered ads at their natural 300px (items-
end, right-aligned). The visual result: boxes overhung the ad column
on both edges. Wrapped each sidebar in an inner `w-full lg:w-[300px]
lg:ml-auto` div so every block (ads + boxes + newsletter) shares one
300px column on lg+ and stays full-width on mobile. Applied to both
article templates (/articles/[slug] and /news/[slug]).
2) Placeholder rendered the old "AV BEAT" wordmark when an article had no
featured image. Rebuilt article-placeholder.svg around the new brand
mark — the A-monogram tile with the blue gradient (#2563EB→#1E3A8A)
that matches AnimatedLogo + the rest of the brand-gradient system.
Same 1200×630 dimensions so OG/feed embeds aren't affected.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two unrelated production bugs called out in the same review pass:
1) AI persona disclosure — strictly removed everywhere readers see it.
- /about/team hero subtitle no longer says "trained AI personas working
under house style"; copy now reads like every other newsroom team page.
- /about "How we work" block drops the line about AI assistants
rewriting press releases + the "Our AI personas are clearly labeled"
sentence. Reworded to just describe the editorial process.
- ArticleComments no longer renders the small "AI" chip beside
is_ai_seeded commenters. The flag stays in the DB for internal
accounting; it just doesn't surface in the UI.
- Stale code comments in articles/[slug] + news/[slug] that referenced
"AI personas participate (tagged)" cleaned up.
The is_ai_seeded / is_ai_response columns are now strictly internal-only.
2) Team page card visibility — the page wrapper got switched from
text-[#e5e7eb] to text-[#0F172A] in the recent restyle, which fixed
white-on-white outside the cards but left the dark-card H3 names
inheriting dark navy on a dark navy bg = invisible. Forced text-white
on both H3s (editorial + ops). Email rows now use min-w-0 + flex-1 +
block truncate so long addresses ellipsis inside the card instead of
pushing the layout past the right edge.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds a no-auth star rating system backed by a centralized cross-property
table on supabase01.
Database:
- distribute.article_ratings (id, property, article_slug, rating 1..5,
session_id, ip_hash, user_agent, created_at) with UNIQUE
(property, article_slug, session_id). property column means every RMP
site shares one table; AV Beat writes 'avbeat', BB writes 'bb', etc.
- distribute.article_rating_aggregates view rolls up real_count + real_avg
per (property, slug).
API (/api/articles/rating):
- GET ?slug=X → { avg, count, my_rating } — reads aggregate, plus the
current session's vote if any.
- POST { slug, rating } → inserts the vote; unique_violation on duplicate
is silently swallowed (one vote per session). Returns updated summary.
- Session lives in `av_rate_sid` cookie (uuid, 1y, sameSite=lax). Cookie
is minted by the API on first request, so the client never has to know
about it.
StarRating component:
- Now interactive — hover preview, click to submit, "thanks!" affordance.
- Merges the existing deterministic baseline (slug-hash → 4.0–5.0 + age-
scaled count) with the real aggregate using the baseline as a Bayesian
prior, so a single real rating doesn't crater the displayed average.
- Once the current session has voted, stars show "your rating" and
hover/click are disabled.
- Text colors updated #d0d0d0 → #0F172A so the rating number is readable
on AV Beat's light backgrounds.
Property identifier hardcoded as "avbeat" at the top of the route — when
porting to BB / SNS / BLB / etc., change that constant and keep
everything else identical.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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>
The 720px media query had its own ::first-letter override at 52px that
survived the desktop-rule removal — first letter was still rendering
oversized on mobile. Removing this completes the drop-cap rip-out.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two complaints on /news/[slug]:
- the oversized first-letter drop-cap looked editorial-magazine, not in
spec — first paragraph should start as normal prose
- inline links rendered near-white against the white page because
Tailwind Typography's prose-a variable was overriding the (no-!important)
brand-blue rule, leaving ghost links unreadable
Drop the ::first-letter rule entirely. Force link color to #1e293b body,
font-family to inherit, and decoration color to currentColor so the
underline is the only visual link cue (still WCAG-distinguishable
without relying on color). Hover keeps brand blue.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Header bar is #1D4ED8 but logo was rendering with navy text on the tile's
#2563EB→#1E3A8A gradient — wordmark + tagline were nearly invisible. Flip
all three header breakpoints to variant="onDark" (white wordmark, slate-200
tagline). Also: switch the onDark tagline accent rule from #1D4ED8 (same
blue, invisible) to #7DD3FC cyan, and paint a faint white ring around the
tile so the rounded mark stays distinct from the header background.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Header: replaces AvBeatLogo across all 3 breakpoints (full / no-tagline / iconOnly).
- Footer: replaces AvBeatLogo full variant.
- AnimatedLogo: new iconOnly prop hides the wordmark+tagline span entirely for the mobile breakpoint.
Existing AvBeatLogo file kept on disk for now (unimported, can be deleted later) so we have a quick rollback target if anyone wants the static A+V monogram back.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Article excerpts sometimes contain raw <p> tags; Next.js HTML-escapes
them into the page <meta>, surfacing as literal '<p>' in view-source
and breaking SEO previews. cleanExcerpt() strips tags + entities for all
plain-text meta surfaces.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Boxes stay sized; tall/odd-ratio images letterbox cleanly against the
existing slate card background instead of being chopped at the edges.
Applied to FeaturedBento, FeaturedBentoFromDb, ArticleFeed, NewsPageClient,
SpotlightCarousel, FeaturedCarousel, AISuggestedArticles, search/page.tsx.
Avatars (rounded-full) unchanged — still object-cover.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sarah Quinn's author page (and any article missing a featured_image) was
showing the old BB-branded placeholder. New SVG uses the AV Beat navy/cyan
palette and 'PRO AV · DISPLAY · LIVE PRODUCTION' tagline.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mirror of the BB article-prose change. Font-family swap only; colors were
already dark on AVB. Body smoothing re-enabled per Ryan.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adverts/contact UI emails on /about/contact + /advertise now point at the
central advertising alias (forwarded to ryan.salazar@). Media-kit hyperlink
on /about/contact corrected to relevantmediaproperties.com/av-beat---media-kit.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Was 11px mono with no background; now a navy outlined pill with uppercase
bold tracking, light-blue fill, and hover state. Same target route.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
src/styles/tailwind.css:195 .article-card:hover background-color was #1c1c1c (near-black, leftover from the dark theme). On the white page that made the card go black on hover and the text disappear into it. Swapped to #e2e8f0 (Tailwind slate-200) so the hover reads as a clean dark-gray distinct from the white surface while keeping the navy article title + slate excerpt fully readable.
src/app/advertise/page.tsx:55 — hero CTA was pointing at the in-page
anchor '#contact'. Swapped to absolute URL
https://relevantmediaproperties.com/av-beat---media-kit (the AV Beat
media-kit landing). target=_blank + rel=noopener so the article tab
isn't replaced.