diff --git a/web/public/js/replay-canvas.js b/web/public/js/replay-canvas.js
index fbbdcc6..3438bd7 100644
--- a/web/public/js/replay-canvas.js
+++ b/web/public/js/replay-canvas.js
@@ -736,32 +736,21 @@ class ReplayCanvas {
}
// ── Tickets meter ──────────────────────────────────────────────────────
- _teamSlotName(slot) {
- return (this._teamNames && this._teamNames[String(slot)])
- || (slot === this._winnerSlot ? 'Winner' : 'Loser');
- }
-
_buildTicketsBar(center) {
if (!this._tickets) return;
const winSlot = this._winnerSlot || 1;
- const loseSlot = winSlot === 1 ? 2 : 1;
this._tkWinSlot = winSlot;
- this._tkLoseSlot = loseSlot;
+ this._tkLoseSlot = winSlot === 1 ? 2 : 1;
const bar = document.createElement('div');
bar.className = 'rc-tickets';
+ // No team names here — the win/lose team sections flank the bar already.
bar.innerHTML = `
-
- ${this._esc(this._teamSlotName(winSlot))}
- 0
-
+ 0
-
- 0
- ${this._esc(this._teamSlotName(loseSlot))}
-
`;
+ 0`;
center.appendChild(bar);
this.ticketsBar = bar;
this._tkWinFill = bar.querySelector('.rc-tk-fill-win');
@@ -780,6 +769,8 @@ class ReplayCanvas {
this._tkLoseFill.style.width = (100 - wPct).toFixed(1) + '%';
this._tkWinVal.textContent = w;
this._tkLoseVal.textContent = l;
+ // Game over (loser bled out) → glow the winning side.
+ this.ticketsBar.classList.toggle('rc-tk-finished', l <= 0);
}
async _loadEntityIcons() {
diff --git a/web/views/game-detail.ejs b/web/views/game-detail.ejs
index 50a0850..a7fb236 100644
--- a/web/views/game-detail.ejs
+++ b/web/views/game-detail.ejs
@@ -505,17 +505,24 @@
font-size: 0.7rem;
color: rgba(255,255,255,0.8);
}
- .rc-tk-side { display: flex; align-items: center; gap: 0.35rem; flex: 0 0 auto; min-width: 0; }
- .rc-tk-lose { justify-content: flex-end; }
- .rc-tk-name { font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 8rem; }
- .rc-tk-win .rc-tk-name { color: #5cdf5c; }
- .rc-tk-lose .rc-tk-name { color: #e85555; }
- .rc-tk-val { font-variant-numeric: tabular-nums; opacity: 0.85; min-width: 2.6rem; }
- .rc-tk-win .rc-tk-val { text-align: right; }
+ .rc-tk-val { font-variant-numeric: tabular-nums; font-weight: 600; min-width: 2.6rem; }
+ .rc-tk-val-win { color: #5cdf5c; text-align: right; }
+ .rc-tk-val-lose { color: #e85555; text-align: left; }
.rc-tk-track { flex: 1 1 auto; display: flex; height: 10px; border-radius: 5px; overflow: hidden; background: rgba(255,255,255,0.08); }
.rc-tk-fill { height: 100%; transition: width 0.1s linear; }
.rc-tk-fill-win { background: #2a8f2a; }
.rc-tk-fill-lose { background: #b22020; }
+ /* Winner glow once the loser has bled out (game over) */
+ .rc-tickets.rc-tk-finished .rc-tk-track { animation: rcTkGlow 1.2s ease-in-out infinite; }
+ .rc-tickets.rc-tk-finished .rc-tk-val-win { animation: rcTkTextGlow 1.2s ease-in-out infinite; }
+ @keyframes rcTkGlow {
+ 0%, 100% { box-shadow: 0 0 4px 0 rgba(92,223,92,0.5); }
+ 50% { box-shadow: 0 0 13px 3px rgba(92,223,92,0.95); }
+ }
+ @keyframes rcTkTextGlow {
+ 0%, 100% { text-shadow: 0 0 4px rgba(92,223,92,0.45); }
+ 50% { text-shadow: 0 0 11px rgba(92,223,92,0.95); }
+ }
.rc-controls {
display: flex;
align-items: center;