diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx
index b2e1c81..5d41b2c 100644
--- a/frontend/src/App.jsx
+++ b/frontend/src/App.jsx
@@ -1,4 +1,4 @@
-import { useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react'
+import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react'
import Tree, { prewarmTreeCanvas } from '../Tree/Tree'
import FallingLeaves from '../Tree/FallingLeaves'
import ReplayCanvasPanel from './ReplayCanvas'
@@ -3771,9 +3771,14 @@ function TournamentsPage({ navigate }) {
type="button"
>
-
- {tournament.name || `Tournament ${tournament.tournament_id}`}
-
+
+
+ {tournament.name || `Tournament ${tournament.tournament_id}`}
+
+
+ {tournamentFormatMeta(tournament.format).label}
+
+
TID {tournament.tournament_id} · {tournamentDateRange(tournament.date_start, tournament.date_end)}
@@ -3794,37 +3799,74 @@ function TournamentsPage({ navigate }) {
)
}
-function TournamentMatchCard({ match, navigate }) {
+function TournamentMatchCard({ match, navigate, onHover }) {
const winner = displayTeamName(match.winner_name).toLowerCase()
const teamA = displayTeamName(match.team_a_name)
const teamB = displayTeamName(match.team_b_name)
const aWon = winner && teamA && winner === teamA.toLowerCase()
const bWon = winner && teamB && winner === teamB.toLowerCase()
+ const decided = Boolean(winner)
const battles = Array.isArray(match.battles) ? match.battles : []
+ const fire = onHover || (() => {})
+ const lastKey = useRef('')
- const teamRow = (name, score, won, emptyLabel = 'TBD') => (
-
- {name ? (
-
- ) : (
- {emptyLabel}
- )}
- {formatNumber(score)}
-
- )
+ // Hover a team name → light just that team's run (green). Hover anywhere else on
+ // the card → light both teams' runs (winner green, loser red). A registered team
+ // that forfeited (technical walkover) shows gold rather than red.
+ const matchHighlight = () => {
+ const map = {}
+ if (teamA) map[teamA.toLowerCase()] = !decided || aWon ? 'win' : 'loss'
+ if (teamB) map[teamB.toLowerCase()] = !decided || bWon ? 'win' : 'loss'
+ return Object.keys(map).length ? map : null
+ }
+ const handleOver = (event) => {
+ const teamEl = event.target.closest('[data-team]')
+ const map = teamEl ? { [teamEl.dataset.team.toLowerCase()]: 'win' } : matchHighlight()
+ const key = map ? Object.entries(map).map(([k, v]) => `${k}:${v}`).sort().join('|') : ''
+ if (key === lastKey.current) return
+ lastKey.current = key
+ fire(map)
+ }
+ const handleLeave = () => {
+ lastKey.current = ''
+ fire(null)
+ }
+
+ const teamRow = (name, score, won, emptyLabel = 'TBD') => {
+ const lost = decided && name && !won
+ const noShow = lost && match.status === 'technical'
+ const nameColor = won ? 'text-win' : noShow ? 'text-fury-violet' : lost ? 'text-loss' : 'text-text'
+ const scoreColor = won ? 'text-win' : noShow ? 'text-fury-violet' : lost ? 'text-loss' : 'text-text-soft'
+ return (
+
+ {name ? (
+
+ ) : (
+ {emptyLabel}
+ )}
+ {formatNumber(score)}
+
+ )
+ }
const emptyLabel = match.status === 'bye' ? 'BYE' : 'TBD'
return (
-
+
{teamRow(teamA, match.score_a, aWon, emptyLabel)}
{teamRow(teamB, match.score_b, bWon, emptyLabel)}
@@ -3838,7 +3880,11 @@ function TournamentMatchCard({ match, navigate }) {