upgrade landing page

This commit is contained in:
SowinskiBraeden committed 2026-06-27 11:25:18 -07:00
1 parent 964a0651f5
commit c645c722d5
5 files changed
+649 -68

No files matched your search

+1 -1
View File
@@ -9,7 +9,7 @@ DATA_PATH = BASE_DIR / "data" / "entries.csv"
DEFAULT_DATABASE_URL = f"sqlite:///{BASE_DIR / 'data' / 'boker-dev.sqlite3'}"
ELIGIBLE_MIN_SESSIONS = 3
APP_VERSION = "2.5.9"
APP_VERSION = "2.5.10"
def load_local_env(env_path: Path) -> None:
+484 -4
View File
@@ -3882,14 +3882,13 @@ select.control { cursor: pointer; }
content: "♠";
position: absolute;
font-size: clamp(420px, 55vw, 820px);
color: rgba(155,140,240,.055);
color: rgba(155,140,240,.075);
line-height: 1;
pointer-events: none;
user-select: none;
top: 50%;
left: 5%;
right: auto;
transform: translateY(-50%);
left: 50%;
transform: translate(-50%, -50%);
}
.lp-hero__content {
@@ -5225,5 +5224,486 @@ select.control { cursor: pointer; }
font-weight: 600;
color: var(--accent);
transition: gap .15s;
}
/* ================================================================
LANDING — stats bar
================================================================ */
.lp-stats-bar {
border-top: 1px solid rgba(255,255,255,.06);
border-bottom: 1px solid rgba(255,255,255,.06);
background: rgba(155,140,240,.022);
}
.lp-stats-bar__inner {
max-width: var(--w-public);
margin: 0 auto;
padding: 22px clamp(24px, 5vw, 80px);
display: flex;
align-items: center;
justify-content: space-around;
gap: 16px;
flex-wrap: wrap;
}
.lp-stats-bar__item {
display: flex;
flex-direction: column;
align-items: center;
gap: 5px;
text-align: center;
}
.lp-stats-bar__val {
font-size: 1.25rem;
font-weight: 800;
color: var(--text-strong);
letter-spacing: -.03em;
line-height: 1;
}
.lp-stats-bar__lbl {
font-family: var(--font-mono);
font-size: .6rem;
letter-spacing: .1em;
text-transform: uppercase;
color: rgba(255,255,255,.3);
}
.lp-stats-bar__sep {
width: 1px;
height: 36px;
background: rgba(255,255,255,.08);
flex-shrink: 0;
}
@media (max-width: 680px) {
.lp-stats-bar__sep { display: none; }
.lp-stats-bar__inner { justify-content: center; gap: 16px 32px; }
}
/* ================================================================
LANDING — leaderboard callout section
================================================================ */
.lp-callout {
padding: clamp(56px, 6vw, 88px) clamp(24px, 5vw, 80px);
border-top: 1px solid rgba(255,255,255,.06);
background:
radial-gradient(ellipse 60% 70% at 5% 50%, rgba(155,140,240,.045) 0%, transparent 55%),
var(--bg);
}
.lp-callout__inner {
max-width: var(--w-public);
margin: 0 auto;
display: grid;
grid-template-columns: 1fr 1.25fr;
gap: clamp(40px, 6vw, 88px);
align-items: center;
}
.lp-callout__text {
max-width: 480px;
}
.lp-callout__title {
font-size: clamp(22px, 2.8vw, 34px);
font-weight: 800;
color: var(--text);
letter-spacing: -.035em;
line-height: 1.15;
margin: 10px 0 16px;
}
.lp-callout__body {
font-size: .9375rem;
color: rgba(255,255,255,.45);
line-height: 1.72;
margin: 0 0 22px;
}
.lp-callout__list {
list-style: none;
margin: 0;
padding: 0;
display: grid;
gap: 9px;
}
.lp-callout__list li {
display: flex;
align-items: center;
gap: 10px;
font-size: .875rem;
color: rgba(255,255,255,.52);
line-height: 1.4;
}
.lp-callout__list li::before {
content: "";
width: 5px;
height: 5px;
border-radius: 50%;
background: var(--accent);
flex-shrink: 0;
opacity: .75;
}
.lp-callout__demo {
position: relative;
}
@media (max-width: 900px) {
.lp-callout__inner { grid-template-columns: 1fr; }
.lp-callout__text { max-width: none; }
}
@media (max-width: 440px) {
.lp-callout { padding-left: 16px; padding-right: 16px; }
}
/* ================================================================
AUTH SPLIT LAYOUT
================================================================ */
.page--auth {
padding: 0;
max-width: none;
}
.auth-split {
display: flex;
min-height: calc(100vh - 62px);
}
.auth-split__form-col {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
padding: clamp(40px, 5vw, 72px) clamp(24px, 5vw, 60px);
min-width: 0;
}
.auth-split__form-inner {
width: 100%;
max-width: 380px;
}
.auth-split__brand {
display: flex;
align-items: center;
gap: 10px;
text-decoration: none;
margin-bottom: 36px;
}
.auth-split__brand-mark {
width: 28px;
height: 28px;
border-radius: 7px;
background: linear-gradient(135deg, var(--accent) 0%, color-mix(in srgb, var(--accent) 72%, #7c6fd4) 100%);
box-shadow: 0 0 0 1px var(--accent-a30), 0 4px 18px var(--accent-a22);
position: relative;
flex: none;
}
.auth-split__brand-mark::after {
content: "";
position: absolute;
inset: 0; margin: auto;
width: 11px; height: 11px;
border-radius: 2px;
background: var(--accent-ink);
transform: rotate(45deg);
}
.auth-split__brand-name {
font-size: 16px;
font-weight: 700;
color: var(--text);
letter-spacing: -.01em;
}
.auth-split__brand-tld {
color: var(--faintest);
font-weight: 400;
}
.auth-split__title {
font-size: clamp(24px, 3vw, 32px);
font-weight: 800;
color: var(--text);
letter-spacing: -.035em;
margin: 0 0 8px;
line-height: 1.1;
}
.auth-split__sub {
font-size: .9375rem;
color: rgba(255,255,255,.42);
margin: 0 0 28px;
line-height: 1.58;
}
.auth-field {
display: grid;
gap: 7px;
margin-bottom: 16px;
}
.auth-field label {
font-family: var(--font-mono);
font-size: 10px;
letter-spacing: .1em;
text-transform: uppercase;
color: rgba(255,255,255,.38);
}
.auth-field input {
width: 100%;
padding: 11px 14px;
background: var(--field);
border: 1px solid var(--border-strong);
border-radius: var(--r-sm);
color: var(--text);
font: 14px var(--font-ui);
outline: none;
transition: border-color .15s, box-shadow .15s;
}
.auth-field input:focus {
border-color: var(--accent-chip-bd);
box-shadow: 0 0 0 3px var(--accent-a22);
}
.auth-field input::placeholder {
color: var(--faintest-2);
}
.auth-links {
margin: -8px 0 16px;
text-align: right;
}
.auth-links a {
font-size: .8125rem;
color: var(--muted);
transition: color .13s;
}
.auth-links a:hover { color: var(--accent); }
.auth-submit {
width: 100%;
justify-content: center;
margin-top: 4px;
padding: 12px 24px;
font-size: 15px;
}
.auth-alt {
margin: 20px 0 0;
font-size: .875rem;
color: rgba(255,255,255,.38);
text-align: center;
}
.auth-alt a {
color: var(--accent);
font-weight: 600;
}
.auth-alt a:hover { text-decoration: underline; }
/* ---- visual / right column ---- */
.auth-split__visual {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
position: relative;
overflow: hidden;
background:
radial-gradient(ellipse 80% 80% at 50% 50%, #1a0c36 0%, #0d0b18 58%, var(--bg) 100%);
border-left: 1px solid rgba(255,255,255,.055);
}
/* large suit background symbol */
.auth-split__visual::before {
position: absolute;
font-size: clamp(300px, 38vw, 520px);
color: rgba(155,140,240,.055);
line-height: 1;
pointer-events: none;
user-select: none;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.auth-split__visual--club::before { content: "♣"; }
.auth-split__visual--diamond::before { content: "♦"; }
.auth-visual__body {
position: relative;
z-index: 1;
max-width: 320px;
padding: 24px;
}
.auth-visual__icon {
width: 52px;
height: 52px;
background: var(--accent-chip);
border: 1px solid var(--accent-chip-bd);
border-radius: 14px;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 20px;
box-shadow: 0 0 0 1px var(--accent-a22), 0 8px 28px var(--accent-a22);
}
.auth-visual__suit-sym {
font-size: 1.625rem;
line-height: 1;
color: var(--accent);
}
.auth-visual__title {
font-size: 1.5rem;
font-weight: 800;
color: var(--text);
letter-spacing: -.03em;
margin: 0 0 10px;
line-height: 1.2;
}
.auth-visual__sub {
font-size: .875rem;
color: rgba(255,255,255,.42);
line-height: 1.65;
margin: 0 0 24px;
}
.auth-visual__preview {
background: rgba(255,255,255,.04);
border: 1px solid rgba(255,255,255,.1);
border-radius: var(--r-md);
padding: 16px 18px;
}
.auth-visual__preview-kicker {
font-family: var(--font-mono);
font-size: .6rem;
letter-spacing: .1em;
text-transform: uppercase;
color: var(--accent);
margin-bottom: 13px;
}
.auth-visual__preview-row {
display: flex;
justify-content: space-between;
align-items: center;
padding: 7px 0;
border-bottom: 1px solid rgba(255,255,255,.06);
font-size: .875rem;
color: rgba(255,255,255,.6);
}
.auth-visual__preview-row:last-child { border-bottom: none; }
.auth-visual__preview-row strong { font-weight: 600; }
@media (max-width: 800px) {
.auth-split__visual { display: none; }
.auth-split__form-col { min-height: calc(100vh - 62px); }
}
@media (max-width: 480px) {
.auth-split__form-col {
padding: 32px 24px;
align-items: flex-start;
}
}
/* ================================================================
LANDING — hero kicker (replaces pill eyebrow in hero only)
================================================================ */
.lp-kicker {
font-family: var(--font-mono);
font-size: .625rem;
letter-spacing: .18em;
text-transform: uppercase;
color: rgba(255,255,255,.3);
margin: 0 0 18px;
display: block;
}
/* ================================================================
LANDING — hero live feed card
================================================================ */
.lp-live-dot {
font-family: var(--font-mono);
font-size: .6rem;
letter-spacing: .06em;
text-transform: uppercase;
color: var(--pos);
margin-left: 8px;
font-weight: 600;
}
.lp-feed__rows { padding: 0; }
.lp-feed__row {
display: grid;
grid-template-columns: 38px 1fr auto auto;
gap: 10px;
align-items: center;
padding: 10px 22px;
border-bottom: 1px solid rgba(255,255,255,.04);
transition: background .1s;
}
.lp-feed__row:last-child { border-bottom: none; }
.lp-feed__row:hover { background: rgba(155,140,240,.05); }
.lp-feed__time {
font-family: var(--font-mono);
font-size: .635rem;
color: rgba(255,255,255,.22);
white-space: nowrap;
}
.lp-feed__player {
font-size: .875rem;
font-weight: 500;
color: rgba(255,255,255,.8);
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.lp-feed__pill {
font-family: var(--font-mono);
font-size: .58rem;
letter-spacing: .07em;
text-transform: uppercase;
padding: 2px 7px;
border-radius: 4px;
font-weight: 600;
white-space: nowrap;
}
.lp-feed__pill--buyin {
background: var(--accent-chip);
color: var(--accent);
border: 1px solid var(--accent-chip-bd);
}
.lp-feed__pill--cashout {
background: rgba(111,192,147,.12);
color: var(--pos);
border: 1px solid rgba(111,192,147,.28);
}
.lp-feed__pill--rebuy {
background: rgba(224,177,92,.1);
color: var(--warn);
border: 1px solid rgba(224,177,92,.28);
}
.lp-feed__amt {
font-family: var(--font-mono);
font-size: .8125rem;
color: rgba(255,255,255,.5);
text-align: right;
font-variant-numeric: tabular-nums;
white-space: nowrap;
}
.lp-feed__summary {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1px;
background: rgba(255,255,255,.07);
border-top: 1px solid rgba(255,255,255,.07);
}
.lp-feed__summary-cell {
background: rgba(10,9,18,.9);
padding: 11px 16px;
}
+3 -6
View File
@@ -36,13 +36,10 @@
</div>
</div>
<div class="auth-split__visual" aria-hidden="true">
<div class="auth-split__visual auth-split__visual--club" aria-hidden="true">
<div class="auth-visual__body">
<div class="auth-visual__icon">
<svg width="26" height="26" viewBox="0 0 26 26" fill="none">
<path d="M13 2L22 7.5V18.5L13 24L4 18.5V7.5L13 2Z" stroke="rgba(155,140,240,.65)" stroke-width="1.4" fill="none"/>
<path d="M13 8L18 11V17L13 20L8 17V11L13 8Z" fill="rgba(155,140,240,.25)" stroke="rgba(155,140,240,.55)" stroke-width="1"/>
</svg>
<span class="auth-visual__suit-sym"></span>
</div>
<p class="auth-visual__title">Track every chip.</p>
<p class="auth-visual__sub">Sessions, leaderboards, and debts — all in one place for your private poker league.</p>
@@ -58,7 +55,7 @@
</div>
<div class="auth-visual__preview-row" style="opacity:.5">
<span>Okafor</span>
<strong style="color:var(--neg);">-$210</strong>
<strong style="color:var(--neg);">$210</strong>
</div>
</div>
</div>
+2 -6
View File
@@ -38,14 +38,10 @@
</div>
</div>
<div class="auth-split__visual" aria-hidden="true">
<div class="auth-split__visual auth-split__visual--diamond" aria-hidden="true">
<div class="auth-visual__body">
<div class="auth-visual__icon">
<svg width="26" height="26" viewBox="0 0 26 26" fill="none">
<rect x="3" y="5" width="20" height="16" rx="3" stroke="rgba(155,140,240,.65)" stroke-width="1.4" fill="none"/>
<path d="M3 10h20" stroke="rgba(155,140,240,.45)" stroke-width="1.2"/>
<path d="M8 15h4M8 18h6" stroke="rgba(155,140,240,.55)" stroke-width="1.2" stroke-linecap="round"/>
</svg>
<span class="auth-visual__suit-sym"></span>
</div>
<p class="auth-visual__title">Free to start.</p>
<p class="auth-visual__sub">No credit card, no monthly fees, no payment processor taking a cut of your buy-ins.</p>
+159 -51
View File
@@ -3,9 +3,10 @@
{% block page_class %}page--landing{% endblock %}
{% block content %}
<!-- ── Hero ──────────────────────────────────────────────────── -->
<div class="lp-hero">
<div class="lp-hero__content">
<span class="lp-eyebrow">Home poker tracking</span>
<p class="lp-kicker">Home Poker Tracking</p>
<h1 class="lp-h1">
<span class="lp-h1__line">Your</span>
<span class="lp-h1__line">league,</span>
@@ -37,71 +38,99 @@
<div class="lp-demo__card">
<div class="lp-demo__head">
<div>
<span class="lp-demo__kicker">Friday Night Poker</span>
<span class="lp-demo__title">Leaderboard · Eligible</span>
<span class="lp-demo__kicker">Friday Night Poker · Session #006</span>
<span class="lp-demo__title">Live event log <span class="lp-live-dot">● live</span></span>
</div>
<span class="lp-demo__meta">18 sessions · 5 players</span>
<span class="lp-demo__meta">Jun 21 · 5 players</span>
</div>
<div class="lp-demo__table">
<div class="lp-demo__thead lp-demo__thead--lb">
<span class="lp-demo__th">#</span>
<span class="lp-demo__th">Player</span>
<span class="lp-demo__th">Δ</span>
<span class="lp-demo__th">Net</span>
<span class="lp-demo__th">Win%</span>
<span class="lp-demo__th">ROI</span>
<div class="lp-feed__rows">
<div class="lp-feed__row">
<span class="lp-feed__time">10:14</span>
<span class="lp-feed__player">Rivera</span>
<span class="lp-feed__pill lp-feed__pill--buyin">buy-in</span>
<span class="lp-feed__amt">$100</span>
</div>
<div class="lp-demo__row lp-demo__row--lb">
<span class="lp-demo__rank lp-demo__rank--1">1</span>
<span class="lp-demo__player">Rivera</span>
<span class="lp-demo__delta lp-demo__delta--up">▲1</span>
<span class="lp-demo__num lp-demo__num--pos">+$1,420</span>
<span class="lp-demo__num lp-demo__num--pos">72%</span>
<span class="lp-demo__num lp-demo__num--pos">+46%</span>
<div class="lp-feed__row">
<span class="lp-feed__time">10:22</span>
<span class="lp-feed__player">Chen</span>
<span class="lp-feed__pill lp-feed__pill--buyin">buy-in</span>
<span class="lp-feed__amt">$50</span>
</div>
<div class="lp-demo__row lp-demo__row--lb">
<span class="lp-demo__rank lp-demo__rank--2">2</span>
<span class="lp-demo__player">Chen</span>
<span class="lp-demo__delta"></span>
<span class="lp-demo__num lp-demo__num--pos">+$640</span>
<span class="lp-demo__num lp-demo__num--pos">56%</span>
<span class="lp-demo__num lp-demo__num--pos">+18%</span>
<div class="lp-feed__row">
<span class="lp-feed__time">10:41</span>
<span class="lp-feed__player">Okafor</span>
<span class="lp-feed__pill lp-feed__pill--buyin">buy-in</span>
<span class="lp-feed__amt">$50</span>
</div>
<div class="lp-demo__row lp-demo__row--lb">
<span class="lp-demo__rank lp-demo__rank--3">3</span>
<span class="lp-demo__player">Okafor</span>
<span class="lp-demo__delta lp-demo__delta--down">▼1</span>
<span class="lp-demo__num lp-demo__num--neg">$210</span>
<span class="lp-demo__num lp-demo__num--neg">43%</span>
<span class="lp-demo__num lp-demo__num--neg">7%</span>
<div class="lp-feed__row">
<span class="lp-feed__time">11:56</span>
<span class="lp-feed__player">Novak</span>
<span class="lp-feed__pill lp-feed__pill--cashout">cashout</span>
<span class="lp-feed__amt lp-demo__num--pos">$160</span>
</div>
<div class="lp-demo__row lp-demo__row--lb lp-demo__row--fade">
<span class="lp-demo__rank">4</span>
<span class="lp-demo__player">Walsh</span>
<span class="lp-demo__delta"></span>
<span class="lp-demo__num lp-demo__num--neg">$850</span>
<span class="lp-demo__num lp-demo__num--neg">31%</span>
<span class="lp-demo__num lp-demo__num--neg">27%</span>
<div class="lp-feed__row">
<span class="lp-feed__time">12:02</span>
<span class="lp-feed__player">Rivera</span>
<span class="lp-feed__pill lp-feed__pill--rebuy">re-buy</span>
<span class="lp-feed__amt">$50</span>
</div>
<div class="lp-demo__row lp-demo__row--lb lp-demo__row--fade2">
<span class="lp-demo__rank">5</span>
<span class="lp-demo__player">Novak</span>
<span class="lp-demo__delta lp-demo__delta--down">▼2</span>
<span class="lp-demo__num lp-demo__num--neg">$1,000</span>
<span class="lp-demo__num lp-demo__num--neg">25%</span>
<span class="lp-demo__num lp-demo__num--neg">42%</span>
<div class="lp-feed__row lp-demo__row--fade">
<span class="lp-feed__time">12:08</span>
<span class="lp-feed__player">Walsh</span>
<span class="lp-feed__pill lp-feed__pill--cashout">cashout</span>
<span class="lp-feed__amt lp-demo__num--neg">$30</span>
</div>
</div>
<div class="lp-feed__summary">
<div class="lp-feed__summary-cell">
<span class="lp-recon-label">Cash in</span>
<span class="lp-recon-val">$350</span>
</div>
<div class="lp-feed__summary-cell">
<span class="lp-recon-label">Paid out</span>
<span class="lp-recon-val lp-demo__num--pos">$190</span>
</div>
<div class="lp-feed__summary-cell">
<span class="lp-recon-label">House holds</span>
<span class="lp-recon-val lp-demo__num--neg">$160</span>
</div>
</div>
</div>
</div>
</div>
<!-- Features -->
<!-- ── Stats bar ──────────────────────────────────────────────── -->
<div class="lp-stats-bar">
<div class="lp-stats-bar__inner">
<div class="lp-stats-bar__item">
<span class="lp-stats-bar__val">$0</span>
<span class="lp-stats-bar__lbl">Platform fee, always</span>
</div>
<span class="lp-stats-bar__sep"></span>
<div class="lp-stats-bar__item">
<span class="lp-stats-bar__val"></span>
<span class="lp-stats-bar__lbl">Sessions &amp; players</span>
</div>
<span class="lp-stats-bar__sep"></span>
<div class="lp-stats-bar__item">
<span class="lp-stats-bar__val">Append-only</span>
<span class="lp-stats-bar__lbl">Tamper-proof ledger</span>
</div>
<span class="lp-stats-bar__sep"></span>
<div class="lp-stats-bar__item">
<span class="lp-stats-bar__val">Private</span>
<span class="lp-stats-bar__lbl">Your data, your league</span>
</div>
</div>
</div>
<!-- ── Features ──────────────────────────────────────────────── -->
<section class="lp-features">
<div class="lp-features__inner">
<div class="lp-sec-head">
<span class="lp-eyebrow">What's included</span>
<h2 class="lp-sec-title">No spreadsheets. No Venmo math. No guessing.</h2>
<p class="lp-sec-sub">Everything your group needs to run a real poker league — built from the ground up for home games.</p>
</div>
<div class="lp-feat-grid">
<div class="lp-feat">
@@ -140,13 +169,13 @@
</div>
</section>
<!-- App demos -->
<!-- ── App showcase ───────────────────────────────────────────── -->
<section class="lp-showcase">
<div class="lp-showcase__inner">
<div class="lp-sec-head">
<span class="lp-eyebrow">In the app</span>
<h2 class="lp-sec-title">Sessions and results</h2>
<p class="lp-sec-sub">Every number your group tracks, in one place.</p>
<h2 class="lp-sec-title">Your game. Your data. Always in sync.</h2>
<p class="lp-sec-sub">Every number your group tracks, in one place — from the moment chips hit the table.</p>
</div>
<div class="lp-showcase__grid" aria-hidden="true">
@@ -287,6 +316,85 @@
</div>
</section>
<!-- ── Leaderboard callout ────────────────────────────────────── -->
<section class="lp-callout">
<div class="lp-callout__inner">
<div class="lp-callout__text">
<span class="lp-eyebrow">Leaderboards</span>
<h2 class="lp-callout__title">Rankings built on raw data, not trust.</h2>
<p class="lp-callout__body">Every leaderboard stat is computed directly from the same append-only ledger that records each buy-in and cashout. Net profit, ROI, and win rate update the moment a session closes — no manual entry, no formulas to break.</p>
<ul class="lp-callout__list">
<li>Set a session minimum before a player earns a rank</li>
<li>Track rank movement with live ▲▼ deltas</li>
<li>Multiple sort modes: net, ROI, win rate, recent form</li>
<li>Provisional players shown separately until they qualify</li>
</ul>
</div>
<div class="lp-callout__demo" aria-hidden="true">
<div class="lp-demo__card">
<div class="lp-demo__head">
<div>
<span class="lp-demo__kicker">Friday Night Poker</span>
<span class="lp-demo__title">Leaderboard · Sort: Net</span>
</div>
<span class="lp-demo__meta">18 sessions · eligible</span>
</div>
<div class="lp-demo__table">
<div class="lp-demo__thead lp-demo__thead--lb">
<span class="lp-demo__th">#</span>
<span class="lp-demo__th">Player</span>
<span class="lp-demo__th">Δ</span>
<span class="lp-demo__th">Net</span>
<span class="lp-demo__th">Win%</span>
<span class="lp-demo__th">ROI</span>
</div>
<div class="lp-demo__row lp-demo__row--lb">
<span class="lp-demo__rank lp-demo__rank--1">1</span>
<span class="lp-demo__player">Rivera</span>
<span class="lp-demo__delta lp-demo__delta--up">▲1</span>
<span class="lp-demo__num lp-demo__num--pos">+$1,420</span>
<span class="lp-demo__num lp-demo__num--pos">72%</span>
<span class="lp-demo__num lp-demo__num--pos">+46%</span>
</div>
<div class="lp-demo__row lp-demo__row--lb">
<span class="lp-demo__rank lp-demo__rank--2">2</span>
<span class="lp-demo__player">Chen</span>
<span class="lp-demo__delta"></span>
<span class="lp-demo__num lp-demo__num--pos">+$640</span>
<span class="lp-demo__num lp-demo__num--pos">56%</span>
<span class="lp-demo__num lp-demo__num--pos">+18%</span>
</div>
<div class="lp-demo__row lp-demo__row--lb">
<span class="lp-demo__rank lp-demo__rank--3">3</span>
<span class="lp-demo__player">Okafor</span>
<span class="lp-demo__delta lp-demo__delta--down">▼1</span>
<span class="lp-demo__num lp-demo__num--neg">$210</span>
<span class="lp-demo__num lp-demo__num--neg">43%</span>
<span class="lp-demo__num lp-demo__num--neg">7%</span>
</div>
<div class="lp-demo__row lp-demo__row--lb lp-demo__row--fade">
<span class="lp-demo__rank">4</span>
<span class="lp-demo__player">Walsh</span>
<span class="lp-demo__delta"></span>
<span class="lp-demo__num lp-demo__num--neg">$850</span>
<span class="lp-demo__num lp-demo__num--neg">31%</span>
<span class="lp-demo__num lp-demo__num--neg">27%</span>
</div>
<div class="lp-demo__row lp-demo__row--lb lp-demo__row--fade2">
<span class="lp-demo__rank">5</span>
<span class="lp-demo__player">Novak</span>
<span class="lp-demo__delta lp-demo__delta--down">▼2</span>
<span class="lp-demo__num lp-demo__num--neg">$1,000</span>
<span class="lp-demo__num lp-demo__num--neg">25%</span>
<span class="lp-demo__num lp-demo__num--neg">42%</span>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- ── Bottom CTA ─────────────────────────────────────────────── -->
{% if not is_logged_in %}
<section class="lp-bottom-cta">
<div class="lp-bottom-cta__inner">