Spaces:
Sleeping
Sleeping
| {% extends 'base.html' %} | |
| {% block title %}The Pool — everyone’s picks — {{ app_brand }}{% endblock %} | |
| {% block head %} | |
| <style> | |
| .pool-hero { | |
| position: relative; | |
| padding: 2rem 1.5rem 1.5rem; | |
| margin: -0.5rem -0.5rem 1.75rem; | |
| border-radius: var(--radius); | |
| background: | |
| linear-gradient(135deg, rgba(249,115,22,0.12) 0%, transparent 45%), | |
| linear-gradient(225deg, rgba(59,130,246,0.08) 0%, transparent 40%), | |
| var(--card); | |
| border: 1px solid var(--border); | |
| overflow: hidden; | |
| } | |
| .pool-hero::before { | |
| content: ''; | |
| position: absolute; inset: 0; | |
| background: repeating-linear-gradient( | |
| -18deg, | |
| transparent, | |
| transparent 12px, | |
| rgba(255,255,255,0.02) 12px, | |
| rgba(255,255,255,0.02) 13px | |
| ); | |
| pointer-events: none; | |
| } | |
| .pool-hero-inner { position: relative; z-index: 1; } | |
| .pool-kicker { | |
| font-size: 0.75rem; font-weight: 700; letter-spacing: 0.2em; | |
| color: var(--orange); text-transform: uppercase; | |
| } | |
| .pool-title { | |
| font-family: var(--font-display); | |
| font-size: clamp(2.2rem, 5vw, 3.25rem); | |
| letter-spacing: 3px; | |
| color: var(--white); | |
| line-height: 1.05; | |
| margin-top: 0.35rem; | |
| } | |
| .pool-tagline { color: var(--muted2); font-size: 0.95rem; max-width: 36rem; margin-top: 0.5rem; } | |
| .pool-stats { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); | |
| gap: 0.75rem; | |
| margin-top: 1.25rem; | |
| } | |
| .pool-stat { | |
| background: rgba(0,0,0,0.25); | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius-sm); | |
| padding: 0.75rem 1rem; | |
| text-align: center; | |
| } | |
| .pool-stat-val { | |
| font-family: var(--font-mono); | |
| font-size: 1.35rem; | |
| font-weight: 700; | |
| color: var(--gold); | |
| } | |
| .pool-stat-lbl { font-size: 0.72rem; color: var(--muted); text-transform: uppercase; letter-spacing: 0.06em; } | |
| .pool-toolbar { | |
| display: flex; flex-wrap: wrap; gap: 0.75rem; | |
| align-items: flex-end; | |
| margin-bottom: 1.5rem; | |
| padding: 1rem 1.25rem; | |
| background: var(--bg2); | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius); | |
| } | |
| .pool-toolbar .form-group { margin: 0; flex: 1; min-width: 200px; } | |
| .pool-toolbar label { font-size: 0.72rem; } | |
| .pool-match { | |
| margin-bottom: 2rem; | |
| border-radius: var(--radius); | |
| border: 1px solid var(--border); | |
| background: linear-gradient(180deg, var(--card) 0%, rgba(20,28,46,0.97) 100%); | |
| overflow: hidden; | |
| box-shadow: 0 24px 48px rgba(0,0,0,0.35); | |
| } | |
| .pool-match-head { | |
| display: grid; | |
| grid-template-columns: 1fr auto 1fr; | |
| gap: 0.5rem; | |
| align-items: center; | |
| padding: 1.25rem 1rem; | |
| border-bottom: 1px solid var(--border); | |
| background: rgba(0,0,0,0.2); | |
| } | |
| @media (max-width: 720px) { | |
| .pool-match-head { grid-template-columns: 1fr; text-align: center; } | |
| } | |
| .pool-team-tag { | |
| font-family: var(--font-display); | |
| font-size: clamp(1.4rem, 4vw, 2rem); | |
| letter-spacing: 1px; | |
| } | |
| .pool-vs { | |
| font-family: var(--font-display); | |
| font-size: 1.5rem; | |
| color: var(--muted); | |
| letter-spacing: 4px; | |
| } | |
| .pool-meta { | |
| font-size: 0.8rem; | |
| color: var(--muted2); | |
| margin-top: 0.35rem; | |
| } | |
| .pool-bar-wrap { | |
| height: 10px; | |
| border-radius: 99px; | |
| overflow: hidden; | |
| display: flex; | |
| margin: 0 1.25rem 1rem; | |
| background: var(--bg); | |
| } | |
| .pool-bar-a { height: 100%; transition: width 0.6s ease; } | |
| .pool-bar-b { height: 100%; flex: 1; min-width: 0; transition: width 0.6s ease; } | |
| .pool-split { | |
| display: grid; | |
| grid-template-columns: 1fr 1fr; | |
| gap: 0; | |
| min-height: 120px; | |
| } | |
| @media (max-width: 640px) { .pool-split { grid-template-columns: 1fr; } } | |
| .pool-side { | |
| padding: 1rem 1.1rem 1.35rem; | |
| border-top: 3px solid transparent; | |
| } | |
| .pool-side-a { border-top-color: var(--c1, var(--orange)); background: linear-gradient(180deg, rgba(249,115,22,0.06), transparent); } | |
| .pool-side-b { border-top-color: var(--c2, var(--blue)); background: linear-gradient(180deg, rgba(59,130,246,0.06), transparent); } | |
| @media (min-width: 641px) { | |
| .pool-side-a { border-right: 1px solid var(--border); } | |
| } | |
| .pool-side-h { | |
| display: flex; justify-content: space-between; align-items: baseline; | |
| margin-bottom: 0.75rem; | |
| flex-wrap: wrap; gap: 0.35rem; | |
| } | |
| .pool-side-label { font-size: 0.7rem; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase; color: var(--muted); } | |
| .pool-side-sum { font-family: var(--font-mono); font-size: 0.85rem; color: var(--gold); } | |
| .pool-picks { display: flex; flex-direction: column; gap: 0.5rem; } | |
| .pool-card { | |
| display: flex; align-items: center; gap: 0.65rem; | |
| padding: 0.55rem 0.65rem; | |
| border-radius: var(--radius-sm); | |
| background: var(--bg2); | |
| border: 1px solid var(--border); | |
| transition: transform 0.15s, border-color 0.15s; | |
| } | |
| .pool-card:hover { border-color: var(--muted); transform: translateX(2px); } | |
| .pool-card.me { | |
| border-color: rgba(251,191,36,0.45); | |
| box-shadow: 0 0 0 1px rgba(251,191,36,0.15); | |
| } | |
| .pool-av { | |
| width: 2.35rem; height: 2.35rem; border-radius: 10px; | |
| display: flex; align-items: center; justify-content: center; | |
| font-family: var(--font-mono); font-size: 0.72rem; font-weight: 700; | |
| flex-shrink: 0; | |
| background: linear-gradient(135deg, var(--bg3), var(--border)); | |
| color: var(--orange2); | |
| } | |
| .pool-card-body { flex: 1; min-width: 0; } | |
| .pool-name { font-weight: 700; font-size: 0.9rem; color: var(--text); } | |
| .pool-you { font-size: 0.65rem; font-weight: 700; color: var(--gold); margin-left: 0.35rem; letter-spacing: 0.05em; } | |
| .pool-sub { font-size: 0.75rem; color: var(--muted2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } | |
| .pool-bid { | |
| font-family: var(--font-mono); font-weight: 700; font-size: 0.85rem; | |
| color: var(--orange); flex-shrink: 0; | |
| } | |
| .pool-out { | |
| font-size: 0.75rem; | |
| margin-top: 0.15rem; | |
| display: flex; align-items: center; gap: 0.35rem; flex-wrap: wrap; | |
| } | |
| .pool-empty-side { | |
| color: var(--muted); | |
| font-size: 0.85rem; | |
| font-style: italic; | |
| padding: 0.5rem 0; | |
| } | |
| </style> | |
| {% endblock %} | |
| {% block content %} | |
| <div class="page"> | |
| <div class="pool-hero"> | |
| <div class="pool-hero-inner"> | |
| <div class="pool-kicker">Cards on the table</div> | |
| <h1 class="pool-title">THE POOL</h1> | |
| <p class="pool-tagline">Every active member’s winner pick, MOTM call, and stake — match by match.</p> | |
| <div class="pool-stats"> | |
| <div class="pool-stat"> | |
| <div class="pool-stat-val">{{ totals.n or 0 }}</div> | |
| <div class="pool-stat-lbl">Picks logged</div> | |
| </div> | |
| <div class="pool-stat"> | |
| <div class="pool-stat-val">{{ totals.members or 0 }}</div> | |
| <div class="pool-stat-lbl">Players in pool</div> | |
| </div> | |
| <div class="pool-stat"> | |
| <div class="pool-stat-val">{{ totals.matches_touched or 0 }}</div> | |
| <div class="pool-stat-lbl">Matches with picks</div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <form class="pool-toolbar" method="get" action="{{ url_for('team_pool') }}"> | |
| <div class="form-group"> | |
| <label for="match_id">Match</label> | |
| <select name="match_id" id="match_id" onchange="this.form.submit()"> | |
| <option value="">All matches with predictions</option> | |
| {% for sm in selector_matches %} | |
| <option value="{{ sm.id }}" {% if match_filter == sm.id %}selected{% endif %}> | |
| #{{ sm.match_number or '?' }} · {{ sm.team1_abbr }} vs {{ sm.team2_abbr }} · {{ sm.match_date|format_date }} · {{ sm.status }} | |
| </option> | |
| {% endfor %} | |
| </select> | |
| </div> | |
| <div class="form-group" style="min-width:200px;"> | |
| <label for="member_id">Find a teammate</label> | |
| <select name="member_id" id="member_id" onchange="this.form.submit()"> | |
| <option value="">All teammates</option> | |
| {% for tm in pool_teammates %} | |
| <option value="{{ tm.id }}" {% if member_filter == tm.id %}selected{% endif %}> | |
| {{ tm.display_name or tm.username }} | |
| </option> | |
| {% endfor %} | |
| </select> | |
| </div> | |
| <button type="submit" class="btn btn-primary btn-sm" style="margin-bottom:2px;">Apply</button> | |
| {% if member_filter or match_filter %} | |
| <a href="{{ url_for('team_pool') }}" class="btn btn-ghost btn-sm" style="margin-bottom:2px;">Reset</a> | |
| {% endif %} | |
| </form> | |
| {% if not pool_rows %} | |
| <div class="card" style="text-align:center; padding:3rem 1.5rem;"> | |
| <div style="font-size:2.5rem; margin-bottom:0.75rem;">🎴</div> | |
| <div style="font-weight:700; color:var(--white); margin-bottom:0.5rem;">No picks to show yet</div> | |
| <p style="color:var(--muted2); max-width:420px; margin:0 auto 1.25rem;"> | |
| {% if member_filter %}No picks from that teammate for these filters — try another match or reset. | |
| {% else %}Once teammates submit predictions, they’ll show up here — match by match, side by side. | |
| {% endif %} | |
| </p> | |
| <a href="{{ url_for('dashboard') }}" class="btn btn-primary">Go predict a match</a> | |
| </div> | |
| {% endif %} | |
| {% for row in pool_rows %} | |
| {% set m = row.match %} | |
| <article class="pool-match"> | |
| <header class="pool-match-head"> | |
| <div style="text-align:right;"> | |
| <div class="pool-team-tag" style="color:{{ m.team1_color }};">{{ m.team1_abbr }}</div> | |
| <div class="pool-meta">{{ m.team1 }}</div> | |
| </div> | |
| <div style="text-align:center;"> | |
| <div class="pool-vs">VS</div> | |
| <div class="pool-meta">#{{ m.match_number or '?' }} · {{ m.match_date|format_date }} {{ m.match_time }}</div> | |
| <div style="margin-top:0.4rem;"> | |
| <span class="badge badge-{{ m.status }}">{{ m.status }}</span> | |
| {% if m.winner and m.winner != 'ABANDONED' %} | |
| <span style="margin-left:0.35rem; color:var(--green); font-size:0.8rem; font-weight:600;">🏆 {{ m.winner }}</span> | |
| {% endif %} | |
| </div> | |
| </div> | |
| <div style="text-align:left;"> | |
| <div class="pool-team-tag" style="color:{{ m.team2_color }};">{{ m.team2_abbr }}</div> | |
| <div class="pool-meta">{{ m.team2 }}</div> | |
| </div> | |
| </header> | |
| <div class="pool-bar-wrap" title="Share of picks (by headcount)"> | |
| <div class="pool-bar-a" style="width:{{ row.pct1 }}%; background:linear-gradient(90deg,{{ m.team1_color }},{{ m.team1_color }}cc);"></div> | |
| <div class="pool-bar-b" style="background:linear-gradient(90deg,{{ m.team2_color }}99,{{ m.team2_color }}55);"></div> | |
| </div> | |
| <div style="display:flex; justify-content:space-between; margin:-0.35rem 1.25rem 0.75rem; font-size:0.72rem; color:var(--muted);"> | |
| <span>{{ row.pct1 }}% picks · {{ '%.0f'|format(row.bid1) }} pts staked</span> | |
| <span>{{ 100 - row.pct1 }}% picks · {{ '%.0f'|format(row.bid2) }} pts staked</span> | |
| </div> | |
| <div class="pool-split"> | |
| <div class="pool-side pool-side-a" style="--c1:{{ m.team1_color }};"> | |
| <div class="pool-side-h"> | |
| <span class="pool-side-label" style="color:{{ m.team1_color }};">Backing {{ m.team1_abbr }}</span> | |
| <span class="pool-side-sum">{{ row.side1|length }} · {{ '%.0f'|format(row.bid1) }} pts</span> | |
| </div> | |
| <div class="pool-picks"> | |
| {% for p in row.side1 %} | |
| <div class="pool-card{% if p.user_uid == user.id %} me{% endif %}"> | |
| <div class="pool-av">{{ (p.display_name or p.username)|initials }}</div> | |
| <div class="pool-card-body"> | |
| <div class="pool-name">{{ p.display_name or p.username }}{% if p.user_uid == user.id %}<span class="pool-you">YOU</span>{% endif %}</div> | |
| <div class="pool-sub">MOTM: {{ p.predicted_motm or '—' }}</div> | |
| {% if p.is_settled %} | |
| <div class="pool-out"> | |
| {% if p.winner_correct == 1 %}<span style="color:var(--green);">Winner ✓</span>{% elif p.winner_correct == 0 %}<span style="color:var(--red);">Winner ✗</span>{% endif %} | |
| {% if p.predicted_motm %} | |
| {% if p.motm_correct == 1 %}<span style="color:var(--green);">MOTM ✓</span>{% elif p.motm_correct == 0 %}<span style="color:var(--red);">MOTM ✗</span>{% endif %} | |
| {% endif %} | |
| <span class="{{ p.points_earned|delta_class }}" style="font-family:var(--font-mono); font-weight:700;">{{ p.points_earned|delta_sign }}</span> | |
| </div> | |
| {% endif %} | |
| </div> | |
| <div class="pool-bid">{{ '%.0f'|format(p.bid_amount) }}</div> | |
| </div> | |
| {% else %} | |
| <div class="pool-empty-side">Nobody’s on this side yet.</div> | |
| {% endfor %} | |
| </div> | |
| </div> | |
| <div class="pool-side pool-side-b" style="--c2:{{ m.team2_color }};"> | |
| <div class="pool-side-h"> | |
| <span class="pool-side-label" style="color:{{ m.team2_color }};">Backing {{ m.team2_abbr }}</span> | |
| <span class="pool-side-sum">{{ row.side2|length }} · {{ '%.0f'|format(row.bid2) }} pts</span> | |
| </div> | |
| <div class="pool-picks"> | |
| {% for p in row.side2 %} | |
| <div class="pool-card{% if p.user_uid == user.id %} me{% endif %}"> | |
| <div class="pool-av">{{ (p.display_name or p.username)|initials }}</div> | |
| <div class="pool-card-body"> | |
| <div class="pool-name">{{ p.display_name or p.username }}{% if p.user_uid == user.id %}<span class="pool-you">YOU</span>{% endif %}</div> | |
| <div class="pool-sub">MOTM: {{ p.predicted_motm or '—' }}</div> | |
| {% if p.is_settled %} | |
| <div class="pool-out"> | |
| {% if p.winner_correct == 1 %}<span style="color:var(--green);">Winner ✓</span>{% elif p.winner_correct == 0 %}<span style="color:var(--red);">Winner ✗</span>{% endif %} | |
| {% if p.predicted_motm %} | |
| {% if p.motm_correct == 1 %}<span style="color:var(--green);">MOTM ✓</span>{% elif p.motm_correct == 0 %}<span style="color:var(--red);">MOTM ✗</span>{% endif %} | |
| {% endif %} | |
| <span class="{{ p.points_earned|delta_class }}" style="font-family:var(--font-mono); font-weight:700;">{{ p.points_earned|delta_sign }}</span> | |
| </div> | |
| {% endif %} | |
| </div> | |
| <div class="pool-bid">{{ '%.0f'|format(p.bid_amount) }}</div> | |
| </div> | |
| {% else %} | |
| <div class="pool-empty-side">Nobody’s on this side yet.</div> | |
| {% endfor %} | |
| </div> | |
| </div> | |
| </div> | |
| {% if row.other %} | |
| <div style="padding:0 1.25rem 1.25rem;"> | |
| <div class="card-sm" style="background:rgba(239,68,68,0.08); border-color:rgba(239,68,68,0.25);"> | |
| <div style="font-size:0.75rem; font-weight:700; color:var(--red); margin-bottom:0.5rem;">Unusual picks (data check)</div> | |
| {% for p in row.other %} | |
| <div style="font-size:0.85rem; color:var(--muted2);">{{ p.display_name or p.username }} → {{ p.predicted_winner }}</div> | |
| {% endfor %} | |
| </div> | |
| </div> | |
| {% endif %} | |
| </article> | |
| {% endfor %} | |
| </div> | |
| {% endblock %} | |