MISSION 1 — real sportsbook wordmarks (kills lowercase "betmgm"):
- books.js: add the 6 missing ALLOWED_BOOKS keys (fanatics/bet365/
hardrockbet/betrivers/pointsbet/pinnacle) with real brand names +
colors — no live book falls to neutral gray. Add `slug` fields +
bookSlug()/hasBookSvg() + BUNDLED_BOOK_SVGS.
- Bundle 8 self-authored styled-text wordmark SVGs under
web/public/books/{slug}.svg (draftkings/fanduel/betmgm/caesars/
bet365/pinnacle/hardrockbet/betrivers). NOT copied trademarked logo
glyphs — the book's NAME in brand weight+color; official press-kit
art can drop into the same paths with zero code change.
- BookWordmark: render the local SVG when bundled, else the brand-color
styled-text fallback (never a broken image; never a lowercase key).
- Import BookWordmark into the ledger row (page.tsx:368) + the identical
public-profile row, replacing bare {row.book} text. vyndr/GameCard
line-grid book cell now proper-cases via bookInfo().name (keeps the
preferred-book green highlight).
MISSION 2 — team-logo coverage gaps:
- teamMeta.js: add ESPN-schedule ball-sport abbr aliases the feed emits
that fell to monograms — SA→SAS, NY→NYK, WSH→WAS, BRK→BKN (NBA),
CONN→CON (WNBA). Real-abbr-first lookup means MLB WSH (Nationals) +
WNBA NY (Liberty) still resolve directly; NY in MLB stays null.
Tests: new tests/unit/bookWordmark.test.js (all 10 ALLOWED_BOOKS resolve
to a real brand+non-gray color; 8 bundled SVGs exist; BookWordmark
SVG-first + no-lowercase-leak; ledger/profile import + use BookWordmark).
entityLayer.test.js extended for the new aliases. Full suite green
(239 suites / 2891 tests); next build exit 0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Founder's #1 priority. A single cached asset+rendering system, swapped into
every surface, so entities stop being flat gray strings (DESIGN-SPEC Part 2).
- web/src/lib/teamMeta.js: static registry for ALL 4 sports — 30 MLB, 30 NBA,
13 WNBA teams + 48 World Cup national teams, each with real colors + the
ESPN logo/flag CDN abbr. resolveTeam (abbr/full-name/nickname/alias),
teamLogoUrl (statsapi->ESPN mapping: AZ->ari, CWS->chw; soccer via the
countries/ flag CDN), accentColor (picks the VISIBLE color of the pair so a
#000000 primary never renders an invisible accent on #06060B). Colors +
abbrs sourced once from ESPN's team API — stable public facts, zero-latency
static data, no paid dependency.
- TeamLogo: real ESPN-CDN logo with a team-colored MONOGRAM fallback (never a
gray box / bare abbr). PlayerAvatar: real headshot with a team-colored
monogram fallback (kills the gray silhouette). BookWordmark: brand-color
wordmark, proper casing (DraftKings, not 'draftkings').
- Swapped into the class-level shared components so it propagates to ALL
surfaces: GameCard (team logos + team-colored accent edge), StatStrip
(player identity avatar), StreaksPanel (P0 billboard avatars), TeamHub
header (the team's real crest leads its hub). Barrel-exported.
ZERO OUT-OF-POCKET: ESPN logo/flag CDN + league headshot CDNs, all verified
200 image/png across MLB/NBA/WNBA/soccer.
ACCEPTANCE (SSR render proof): /entity-demo harness server-rendered the exact
real asset URLs across all 4 sports — mlb/500/nyy.png, mlb/500/chw.png (White
Sox, correct ESPN abbr), nba/500/lal.png, wnba/500/ny.png, countries/500/
usa.png + bra/eng/arg/jpn flags, real mlbstatic/nba headshots (Judge 592450,
LeBron 2544), DraftKings/FanDuel wordmarks. Each URL curl-verified 200
image/png. Harness removed post-proof (not a product surface). Pixel
screenshot blocked by WSL2<->Windows-Chrome localhost networking, not code.
2757 -> 2776 tests (+13 entityLayer, +6 boot resilience), web build exit 0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>