DS5 — Pricing (Desk-as-hero) + Motion + Empty/Error + archetype glyphs

Part 6 #8 — Desk $44.99 is the hero tier. New DeskShowcase leads the
pricing page with the "$1M terminal · $44.99" story + real feature
visuals (alt-line ladder, quarter-Kelly, parlay φ, real-time feed) in a
balanced two-column layout (kills the dead right-half). Desk is the sole
highlighted tier / single primary CTA (color contract #9); Analyst is
secondary. Real prices: Free 5 scans, Analyst $14.99/$19.99, Desk
$34.99/$44.99. ClaimMeter + Stripe checkout wiring untouched.

Part 4 #7 — Ticker → punctuated stillness. The continuous marquee is
retired; the ticker now RESTS ≥4s on each ranked item and pulses only on
change. The EKG heartbeat is a static readout — the header's ONE idle
proof-of-life is the single SIGNAL-LIVE live-dot (the ticker dropped its
competing pulse). All durations tokenized (--motion-*, --ticker-hold);
prefers-reduced-motion kills the motion entirely.

Part 8 #20 — new EmptyState component modeled on the north-star 404
(scanlines + glitch wordmark + amber system voice + CTA hierarchy),
reused at the bare-red "Team not found", "Game not found", and the
ledger empties — one unified voice.

Part 5 — archetype glyph+chip propagated to STREAKS rows + ledger rows
(optional + self-hiding; absent beats fabricated); grade reveal already
carries ArchetypeBlend.

Tests: new tests/unit/ds5PricingStates.test.js (22) locks all four
workstreams; updated teamHubUI + vyndrDesignSystem for the new surfaces.
237 suites / 2864 tests green; next build exit 0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Kev
2026-07-13 00:31:35 -04:00
parent cf91c04e90
commit a18a3f33fc
14 changed files with 620 additions and 86 deletions
+8 -4
View File
@@ -7,6 +7,7 @@ import GradeBadge from '@/components/vyndr/GradeBadge';
import ArchetypeBadge from '@/components/vyndr/ArchetypeBadge';
import TeamLogo from '@/components/vyndr/TeamLogo';
import ModelRecord from '@/components/vyndr/ModelRecord';
import EmptyState from '@/components/vyndr/EmptyState';
import { playerHref } from '@/lib/playerHref';
import { useParlay, legKey } from '@/contexts/ParlayContext';
@@ -69,11 +70,14 @@ export default function TeamHub({ abbr, sport }: { abbr: string; sport: string }
return <section style={{ minHeight: '50vh', display: 'flex', alignItems: 'center', justifyContent: 'center' }}><p className="mono" style={{ color: 'var(--text-2)' }}>Loading team intelligence</p></section>;
}
if (state === 'error' || !data) {
// DS5 (#20) — the unified empty/error surface, not a bare-red line.
return (
<section style={{ maxWidth: 600, margin: '0 auto', padding: '40px 16px' }}>
<p className="mono" style={{ color: 'var(--miss)' }}>Team not found.</p>
<a href="/dashboard" className="mono" style={{ color: 'var(--g-a)', fontSize: 13 }}> Back to Slate</a>
</section>
<EmptyState
code="TEAM NOT FOUND"
title="No hub for that team."
message="That abbreviation isn't on the board right now. Check tonight's slate for the teams in play."
actions={[{ label: '← Back to the Slate', href: '/dashboard', primary: true }]}
/>
);
}