diff --git a/counters/mitour by antoshika/deps/countUp.umd.js b/counters/mitour by antoshika/deps/countUp.umd.js
new file mode 100644
index 00000000..0aaa6b51
--- /dev/null
+++ b/counters/mitour by antoshika/deps/countUp.umd.js
@@ -0,0 +1,245 @@
+(function (global, factory) {
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
+ typeof define === 'function' && define.amd ? define(['exports'], factory) :
+ (global = global || self, factory(global.countUp = {}));
+}(this, (function (exports) { 'use strict';
+
+ var __assign = (undefined && undefined.__assign) || function () {
+ __assign = Object.assign || function(t) {
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
+ s = arguments[i];
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
+ t[p] = s[p];
+ }
+ return t;
+ };
+ return __assign.apply(this, arguments);
+ };
+ var CountUp = (function () {
+ function CountUp(target, endVal, options) {
+ var _this = this;
+ this.target = target;
+ this.endVal = endVal;
+ this.options = options;
+ this.version = '2.0.7';
+ this.defaults = {
+ startVal: 0,
+ decimalPlaces: 0,
+ duration: 2,
+ useEasing: true,
+ useGrouping: true,
+ smartEasingThreshold: 999,
+ smartEasingAmount: 333,
+ separator: ',',
+ decimal: '.',
+ prefix: '',
+ suffix: ''
+ };
+ this.finalEndVal = null;
+ this.useEasing = true;
+ this.countDown = false;
+ this.error = '';
+ this.startVal = 0;
+ this.paused = true;
+ this.count = function (timestamp) {
+ if (!_this.startTime) {
+ _this.startTime = timestamp;
+ }
+ var progress = timestamp - _this.startTime;
+ _this.remaining = _this.duration - progress;
+ if (_this.useEasing) {
+ if (_this.countDown) {
+ _this.frameVal = _this.startVal - _this.easingFn(progress, 0, _this.startVal - _this.endVal, _this.duration);
+ }
+ else {
+ _this.frameVal = _this.easingFn(progress, _this.startVal, _this.endVal - _this.startVal, _this.duration);
+ }
+ }
+ else {
+ if (_this.countDown) {
+ _this.frameVal = _this.startVal - ((_this.startVal - _this.endVal) * (progress / _this.duration));
+ }
+ else {
+ _this.frameVal = _this.startVal + (_this.endVal - _this.startVal) * (progress / _this.duration);
+ }
+ }
+ if (_this.countDown) {
+ _this.frameVal = (_this.frameVal < _this.endVal) ? _this.endVal : _this.frameVal;
+ }
+ else {
+ _this.frameVal = (_this.frameVal > _this.endVal) ? _this.endVal : _this.frameVal;
+ }
+ _this.frameVal = Number(_this.frameVal.toFixed(_this.options.decimalPlaces));
+ _this.printValue(_this.frameVal);
+ if (progress < _this.duration) {
+ _this.rAF = requestAnimationFrame(_this.count);
+ }
+ else if (_this.finalEndVal !== null) {
+ _this.update(_this.finalEndVal);
+ }
+ else {
+ if (_this.callback) {
+ _this.callback();
+ }
+ }
+ };
+ this.formatNumber = function (num) {
+ var neg = (num < 0) ? '-' : '';
+ var result, x, x1, x2, x3;
+ result = Math.abs(num).toFixed(_this.options.decimalPlaces);
+ result += '';
+ x = result.split('.');
+ x1 = x[0];
+ x2 = x.length > 1 ? _this.options.decimal + x[1] : '';
+ if (_this.options.useGrouping) {
+ x3 = '';
+ for (var i = 0, len = x1.length; i < len; ++i) {
+ if (i !== 0 && (i % 3) === 0) {
+ x3 = _this.options.separator + x3;
+ }
+ x3 = x1[len - i - 1] + x3;
+ }
+ x1 = x3;
+ }
+ if (_this.options.numerals && _this.options.numerals.length) {
+ x1 = x1.replace(/[0-9]/g, function (w) { return _this.options.numerals[+w]; });
+ x2 = x2.replace(/[0-9]/g, function (w) { return _this.options.numerals[+w]; });
+ }
+ return neg + _this.options.prefix + x1 + x2 + _this.options.suffix;
+ };
+ this.easeOutExpo = function (t, b, c, d) {
+ return c * (-Math.pow(2, -10 * t / d) + 1) * 1024 / 1023 + b;
+ };
+ this.options = __assign(__assign({}, this.defaults), options);
+ this.formattingFn = (this.options.formattingFn) ?
+ this.options.formattingFn : this.formatNumber;
+ this.easingFn = (this.options.easingFn) ?
+ this.options.easingFn : this.easeOutExpo;
+ this.startVal = this.validateValue(this.options.startVal);
+ this.frameVal = this.startVal;
+ this.endVal = this.validateValue(endVal);
+ this.options.decimalPlaces = Math.max( this.options.decimalPlaces);
+ this.resetDuration();
+ this.options.separator = String(this.options.separator);
+ this.useEasing = this.options.useEasing;
+ if (this.options.separator === '') {
+ this.options.useGrouping = false;
+ }
+ this.el = (typeof target === 'string') ? document.getElementById(target) : target;
+ if (this.el) {
+ this.printValue(this.startVal);
+ }
+ else {
+ this.error = '[CountUp] target is null or undefined';
+ }
+ }
+ CountUp.prototype.determineDirectionAndSmartEasing = function () {
+ var end = (this.finalEndVal) ? this.finalEndVal : this.endVal;
+ this.countDown = (this.startVal > end);
+ var animateAmount = end - this.startVal;
+ if (Math.abs(animateAmount) > this.options.smartEasingThreshold) {
+ this.finalEndVal = end;
+ var up = (this.countDown) ? 1 : -1;
+ this.endVal = end + (up * this.options.smartEasingAmount);
+ this.duration = this.duration / 2;
+ }
+ else {
+ this.endVal = end;
+ this.finalEndVal = null;
+ }
+ if (this.finalEndVal) {
+ this.useEasing = false;
+ }
+ else {
+ this.useEasing = this.options.useEasing;
+ }
+ };
+ CountUp.prototype.start = function (callback) {
+ if (this.error) {
+ return;
+ }
+ this.callback = callback;
+ if (this.duration > 0) {
+ this.determineDirectionAndSmartEasing();
+ this.paused = false;
+ this.rAF = requestAnimationFrame(this.count);
+ }
+ else {
+ this.printValue(this.endVal);
+ }
+ };
+ CountUp.prototype.pauseResume = function () {
+ if (!this.paused) {
+ cancelAnimationFrame(this.rAF);
+ }
+ else {
+ this.startTime = null;
+ this.duration = this.remaining;
+ this.startVal = this.frameVal;
+ this.determineDirectionAndSmartEasing();
+ this.rAF = requestAnimationFrame(this.count);
+ }
+ this.paused = !this.paused;
+ };
+ CountUp.prototype.reset = function () {
+ cancelAnimationFrame(this.rAF);
+ this.paused = true;
+ this.resetDuration();
+ this.startVal = this.validateValue(this.options.startVal);
+ this.frameVal = this.startVal;
+ this.printValue(this.startVal);
+ };
+ CountUp.prototype.update = function (newEndVal) {
+ cancelAnimationFrame(this.rAF);
+ this.startTime = null;
+ this.endVal = this.validateValue(newEndVal);
+ if (this.endVal === this.frameVal) {
+ return;
+ }
+ this.startVal = this.frameVal;
+ if (!this.finalEndVal) {
+ this.resetDuration();
+ }
+ this.finalEndVal = null;
+ this.determineDirectionAndSmartEasing();
+ this.rAF = requestAnimationFrame(this.count);
+ };
+ CountUp.prototype.printValue = function (val) {
+ var result = this.formattingFn(val);
+ if (this.el.tagName === 'INPUT') {
+ var input = this.el;
+ input.value = result;
+ }
+ else if (this.el.tagName === 'text' || this.el.tagName === 'tspan') {
+ this.el.textContent = result;
+ }
+ else {
+ this.el.innerHTML = result;
+ }
+ };
+ CountUp.prototype.ensureNumber = function (n) {
+ return (typeof n === 'number' && !isNaN(n));
+ };
+ CountUp.prototype.validateValue = function (value) {
+ var newValue = Number(value);
+ if (!this.ensureNumber(newValue)) {
+ this.error = "[CountUp] invalid start or end value: " + value;
+ return null;
+ }
+ else {
+ return newValue;
+ }
+ };
+ CountUp.prototype.resetDuration = function () {
+ this.startTime = null;
+ this.duration = Number(this.options.duration) * 1000;
+ this.remaining = this.duration;
+ };
+ return CountUp;
+ }());
+
+ exports.CountUp = CountUp;
+
+ Object.defineProperty(exports, '__esModule', { value: true });
+
+})));
diff --git a/counters/mitour by antoshika/deps/fonts.css b/counters/mitour by antoshika/deps/fonts.css
new file mode 100644
index 00000000..eb7139c5
--- /dev/null
+++ b/counters/mitour by antoshika/deps/fonts.css
@@ -0,0 +1,79 @@
+@font-face {
+ font-family: 'Montserrat';
+ font-style: normal;
+ font-weight: 400;
+ font-display: swap;
+ src: url('./fonts/montserrat-400.woff2') format('woff2');
+}
+
+@font-face {
+ font-family: 'Montserrat';
+ font-style: normal;
+ font-weight: 600;
+ font-display: swap;
+ src: url('./fonts/montserrat-600.woff2') format('woff2');
+}
+
+@font-face {
+ font-family: 'Montserrat';
+ font-style: normal;
+ font-weight: 700;
+ font-display: swap;
+ src: url('./fonts/montserrat-700.woff2') format('woff2');
+}
+
+@font-face {
+ font-family: 'Montserrat';
+ font-style: normal;
+ font-weight: 800;
+ font-display: swap;
+ src: url('./fonts/montserrat-800.woff2') format('woff2');
+}
+
+@font-face {
+ font-family: 'Montserrat';
+ font-style: normal;
+ font-weight: 900;
+ font-display: swap;
+ src: url('./fonts/montserrat-900.woff2') format('woff2');
+}
+
+@font-face {
+ font-family: 'Manrope';
+ font-style: normal;
+ font-weight: 400;
+ font-display: swap;
+ src: url('./fonts/manrope-400.woff2') format('woff2');
+}
+
+@font-face {
+ font-family: 'Manrope';
+ font-style: normal;
+ font-weight: 500;
+ font-display: swap;
+ src: url('./fonts/manrope-500.woff2') format('woff2');
+}
+
+@font-face {
+ font-family: 'Manrope';
+ font-style: normal;
+ font-weight: 600;
+ font-display: swap;
+ src: url('./fonts/manrope-600.woff2') format('woff2');
+}
+
+@font-face {
+ font-family: 'Manrope';
+ font-style: normal;
+ font-weight: 700;
+ font-display: swap;
+ src: url('./fonts/manrope-700.woff2') format('woff2');
+}
+
+@font-face {
+ font-family: 'Manrope';
+ font-style: normal;
+ font-weight: 800;
+ font-display: swap;
+ src: url('./fonts/manrope-800.woff2') format('woff2');
+}
diff --git a/counters/mitour by antoshika/deps/fonts/manrope-400.woff2 b/counters/mitour by antoshika/deps/fonts/manrope-400.woff2
new file mode 100644
index 00000000..ba11e1bd
Binary files /dev/null and b/counters/mitour by antoshika/deps/fonts/manrope-400.woff2 differ
diff --git a/counters/mitour by antoshika/deps/fonts/manrope-500.woff2 b/counters/mitour by antoshika/deps/fonts/manrope-500.woff2
new file mode 100644
index 00000000..90745bda
Binary files /dev/null and b/counters/mitour by antoshika/deps/fonts/manrope-500.woff2 differ
diff --git a/counters/mitour by antoshika/deps/fonts/manrope-600.woff2 b/counters/mitour by antoshika/deps/fonts/manrope-600.woff2
new file mode 100644
index 00000000..ee7ac5e8
Binary files /dev/null and b/counters/mitour by antoshika/deps/fonts/manrope-600.woff2 differ
diff --git a/counters/mitour by antoshika/deps/fonts/manrope-700.woff2 b/counters/mitour by antoshika/deps/fonts/manrope-700.woff2
new file mode 100644
index 00000000..a21c3b0a
Binary files /dev/null and b/counters/mitour by antoshika/deps/fonts/manrope-700.woff2 differ
diff --git a/counters/mitour by antoshika/deps/fonts/manrope-800.woff2 b/counters/mitour by antoshika/deps/fonts/manrope-800.woff2
new file mode 100644
index 00000000..2bfa6cb8
Binary files /dev/null and b/counters/mitour by antoshika/deps/fonts/manrope-800.woff2 differ
diff --git a/counters/mitour by antoshika/deps/fonts/montserrat-400.woff2 b/counters/mitour by antoshika/deps/fonts/montserrat-400.woff2
new file mode 100644
index 00000000..d13c06aa
Binary files /dev/null and b/counters/mitour by antoshika/deps/fonts/montserrat-400.woff2 differ
diff --git a/counters/mitour by antoshika/deps/fonts/montserrat-600.woff2 b/counters/mitour by antoshika/deps/fonts/montserrat-600.woff2
new file mode 100644
index 00000000..9528cb3b
Binary files /dev/null and b/counters/mitour by antoshika/deps/fonts/montserrat-600.woff2 differ
diff --git a/counters/mitour by antoshika/deps/fonts/montserrat-700.woff2 b/counters/mitour by antoshika/deps/fonts/montserrat-700.woff2
new file mode 100644
index 00000000..5c136d76
Binary files /dev/null and b/counters/mitour by antoshika/deps/fonts/montserrat-700.woff2 differ
diff --git a/counters/mitour by antoshika/deps/fonts/montserrat-800.woff2 b/counters/mitour by antoshika/deps/fonts/montserrat-800.woff2
new file mode 100644
index 00000000..b05b230e
Binary files /dev/null and b/counters/mitour by antoshika/deps/fonts/montserrat-800.woff2 differ
diff --git a/counters/mitour by antoshika/deps/fonts/montserrat-900.woff2 b/counters/mitour by antoshika/deps/fonts/montserrat-900.woff2
new file mode 100644
index 00000000..712dc4c8
Binary files /dev/null and b/counters/mitour by antoshika/deps/fonts/montserrat-900.woff2 differ
diff --git a/counters/mitour by antoshika/favicon.svg b/counters/mitour by antoshika/favicon.svg
new file mode 100644
index 00000000..cef4d3af
--- /dev/null
+++ b/counters/mitour by antoshika/favicon.svg
@@ -0,0 +1,33 @@
+
\ No newline at end of file
diff --git a/counters/mitour by antoshika/index.html b/counters/mitour by antoshika/index.html
new file mode 100644
index 00000000..8cd8da59
--- /dev/null
+++ b/counters/mitour by antoshika/index.html
@@ -0,0 +1,96 @@
+
+
+
+
+ antoshika osu! Tournament Overlay
+
+
+
+
+
+
+
+
+
+
+
+
PICK
+
+
+
+
+
+
+
+
+
+
CS0
+
AR0
+
OD0
+
SR0.0★
+
BPM0
+
Length0:00
+
ID0
+
+
+
+
+
+
+
+
+
+ WARMUP
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/counters/mitour by antoshika/js/socket.js b/counters/mitour by antoshika/js/socket.js
new file mode 100644
index 00000000..d8710a08
--- /dev/null
+++ b/counters/mitour by antoshika/js/socket.js
@@ -0,0 +1,54 @@
+class Socket {
+ constructor(host) {
+ this.version = '0.1.5';
+
+ if (host) {
+ this.host = host;
+ }
+
+ this.createConnection = this.createConnection.bind(this);
+
+ this.sockets = {};
+ }
+
+ createConnection(url, callback, filters) {
+ let INTERVAL = '';
+
+ const that = this;
+ let counterPath = window.COUNTER_PATH || "";
+ this.sockets[url] = new WebSocket(`ws://${this.host}${url}${url === '/websocket/commands' ? `?l=${encodeURI(counterPath)}` : ''}`);
+
+ this.sockets[url].onopen = () => {
+ console.log(`[OPEN] ${url}: Connected`);
+
+ if (INTERVAL) clearInterval(INTERVAL);
+
+ if (url === '/websocket/commands') {
+ this.sockets[url].send(`getSettings:${encodeURI(counterPath)}`);
+ }
+
+ if (Array.isArray(filters)) {
+ this.sockets[url].send(`applyFilters:${JSON.stringify(filters)}`);
+ }
+ };
+
+ this.sockets[url].onclose = (event) => {
+ console.log(`[CLOSED] ${url}: ${event.reason}`);
+
+ delete this.sockets[url];
+ INTERVAL = setTimeout(() => {
+ that.createConnection(url, callback, filters);
+ }, 1000);
+ };
+
+ this.sockets[url].onerror = (err) => {
+ console.error(`[ERROR] ${url}: ${err.message}`);
+ this.sockets[url].close();
+ };
+
+ this.sockets[url].onmessage = (event) => {
+ const data = JSON.parse(event.data);
+ callback(data);
+ };
+ };
+};
diff --git a/counters/mitour by antoshika/main.js b/counters/mitour by antoshika/main.js
new file mode 100644
index 00000000..9455fd4a
--- /dev/null
+++ b/counters/mitour by antoshika/main.js
@@ -0,0 +1,1237 @@
+let OSU_API_KEY = "";
+
+let teamSeeds = {};
+let TEAMS_CONFIG = {};
+
+function processBracketData(data) {
+ if (data && data.Teams) {
+ teamSeeds = {};
+ data.Teams.forEach(t => {
+ if (t.FullName) teamSeeds[t.FullName.toLowerCase()] = t.Seed;
+ if (t.Acronym) teamSeeds[t.Acronym.toLowerCase()] = t.Seed;
+ });
+ }
+ if (document.getElementById('slideContainer') && data) {
+ initSeedRevealWithData(data);
+ }
+}
+
+const messageTimeCache = new Map();
+
+let currentPlayer = "";
+let isAnimatingPlayer = false;
+
+window.onload = () => {
+ window.focus();
+ if (document.body) document.body.focus();
+
+ const playerEl = document.getElementById("player");
+ if(playerEl) fitTextToContainer(playerEl);
+
+ if (!document.getElementById('player') && typeof TEAMS_CONFIG !== 'undefined' && DEBUG_MODE) {
+ const firstTeamName = Object.keys(TEAMS_CONFIG)[0];
+ if (firstTeamName) showWinnerScene(firstTeamName, 'red');
+ }
+
+ const isMainOverlay = document.getElementById('mappool-overlay') && document.getElementById('top-bar');
+
+ let urlParams = new URLSearchParams(window.location.search);
+ let pathFromUrl = window.location.pathname.split('/')[1] || "";
+ if (pathFromUrl) pathFromUrl = decodeURIComponent(pathFromUrl);
+ let currentPathForWelcome = window.COUNTER_PATH || urlParams.get('l') || pathFromUrl || "mitour by antoshika";
+
+ window.WELCOME_STORAGE_KEY = 'mitour_welcome_hidden_' + currentPathForWelcome;
+
+ if (isMainOverlay && !localStorage.getItem(window.WELCOME_STORAGE_KEY)) {
+ const welcomeHtml = `
+
+
+
+
🥬 Welcome to mitour!
+
Use the tosu settings panel to configure the bracket, mappool, and teams. Or you can read documentation.
+
+
+
+
39!
+
+
+ `;
+ document.body.insertAdjacentHTML('beforeend', welcomeHtml);
+ }
+};
+
+window.closeWelcome = function() {
+ const dontShow = document.getElementById('welcomeDontShow').checked;
+ if (dontShow) localStorage.setItem(window.WELCOME_STORAGE_KEY, 'true');
+ const el = document.getElementById('welcomeOverlay');
+ el.style.opacity = '0';
+ setTimeout(() => el.remove(), 400);
+};
+
+window.addEventListener('resize', () => {
+ const playerEl = document.getElementById("player");
+ if(playerEl) {
+ playerEl.style.transform = "scale(1)";
+ fitTextToContainer(playerEl);
+ }
+});
+
+window.addEventListener('mousedown', () => {
+ window.focus();
+ document.body.focus();
+});
+
+window.addEventListener('keydown', (e) => {
+ if (!document.getElementById('slideContainer')) {
+ if (e.key === 'm' || e.key === 'M' ||
+ e.key === 'ь' || e.key === 'Ь' ||
+ e.code === 'KeyM' || e.keyCode === 77) {
+ toggleMappool();
+ }
+ }
+});
+
+let urlParams = new URLSearchParams(window.location.search);
+let pathFromUrl = window.location.pathname.split('/')[1] || "";
+if (pathFromUrl) pathFromUrl = decodeURIComponent(pathFromUrl);
+window.COUNTER_PATH = window.COUNTER_PATH || urlParams.get('l') || pathFromUrl || "mitour by antoshika";
+
+const socket = new Socket(window.location.host);
+
+socket.createConnection("/ws", (data) => {
+ if (document.getElementById('slideContainer')) return;
+
+ try {
+ let pName = "";
+ try {
+ if (data.resultsScreen && data.resultsScreen.name) {
+ pName = data.resultsScreen.name;
+ } else if (data.gameplay && data.gameplay.name) {
+ pName = data.gameplay.name;
+ }
+
+ if (pName && pName.trim() !== "") {
+ if (pName !== currentPlayer && !isAnimatingPlayer) {
+ updatePlayerName(pName);
+ }
+ }
+ } catch (e) {}
+
+ updateOverlay(data);
+
+ if (!DEBUG_MODE && data.tourney && data.tourney.manager) {
+ handleWinnerData(data.tourney.manager);
+ }
+ } catch (err) { }
+});
+
+socket.createConnection("/websocket/commands", (data) => {
+ try {
+ if (data.command === 'getSettings') {
+ const msg = data.message;
+ if (msg.osuApiKey && msg.osuApiKey.trim() !== "") {
+ OSU_API_KEY = msg.osuApiKey.trim();
+ }
+ if (msg.bracketData && msg.bracketData.trim() !== "" && msg.bracketData !== "{}") {
+ try {
+ const parsed = JSON.parse(msg.bracketData);
+ processBracketData(parsed);
+ } catch(e) {}
+ }
+ if (msg.mappoolData && msg.mappoolData.trim() !== "" && msg.mappoolData !== "{}") {
+ try {
+ const lines = msg.mappoolData.split('\n');
+ const newPicks = {};
+ lines.forEach(line => {
+ const parts = line.split(':');
+ if (parts.length === 2) {
+ const mod = parts[0].trim();
+ const id = parts[1].trim();
+ if (mod && id) newPicks[id] = mod;
+ }
+ });
+ picksData = newPicks;
+ if(document.getElementById('pool-grid')) {
+ renderMappool();
+ fetchMapDetails();
+ }
+ if(document.getElementById('pick-bar')) {
+ const pickName = picksData[String(currentMapId)] || "WARMUP";
+ updatePickBar(pickName);
+ }
+ if(document.getElementById('inner-pick-badge')) {
+ checkInnerPickBadge(currentMapId);
+ }
+ } catch(e) {}
+ }
+ if (msg.teamsData && msg.teamsData.trim() !== "" && msg.teamsData !== "{}") {
+ try {
+ const lines = msg.teamsData.split('\n');
+ const newTeams = {};
+ lines.forEach(line => {
+ const parts = line.split(':');
+ if (parts.length >= 2) {
+ const teamName = parts.shift().trim();
+ const idsStr = parts.join(':');
+ const ids = idsStr.split(',').map(id => parseInt(id.trim())).filter(id => !isNaN(id));
+ if (teamName && ids.length > 0) newTeams[teamName] = ids;
+ }
+ });
+ TEAMS_CONFIG = newTeams;
+ } catch(e) {}
+ }
+ }
+ } catch(e) {}
+});
+
+let currentSetId = -1;
+let currentMapId = -1;
+let picksData = {};
+const mapCache = {};
+const mapStates = {};
+let lastChatCount = 0;
+
+const countUpOptions = { duration: 0.8, useEasing: true, separator: ' ' };
+let redCountUp = null;
+let blueCountUp = null;
+
+let currentWinner = null;
+let isDataLoading = false;
+const DEBUG_MODE = false;
+
+if (typeof countUp !== 'undefined') {
+ if(document.getElementById('red-score')) {
+ redCountUp = new countUp.CountUp('red-score', 0, countUpOptions);
+ blueCountUp = new countUp.CountUp('blue-score', 0, countUpOptions);
+ redCountUp.start();
+ blueCountUp.start();
+ }
+}
+
+
+function updatePlayerName(newText) {
+ const el = document.getElementById("player");
+ if(!el) return;
+
+ isAnimatingPlayer = true;
+ el.classList.add("hidden");
+
+ setTimeout(() => {
+ el.style.transform = "scale(1)";
+ el.innerText = newText;
+
+ requestAnimationFrame(() => {
+ fitTextToContainer(el);
+
+ el.classList.remove("hidden");
+ currentPlayer = newText;
+
+ setTimeout(() => { isAnimatingPlayer = false; }, 300);
+ });
+ }, 300);
+}
+
+function fitTextToContainer(el) {
+ if (!el.parentElement) return;
+
+ el.style.transform = "scale(1)";
+ const containerWidth = el.parentElement.offsetWidth;
+ const actualWidth = el.scrollWidth;
+
+ if (actualWidth === 0 || containerWidth === 0) return;
+
+ if (actualWidth > containerWidth) {
+ const scale = containerWidth / actualWidth;
+ el.style.transform = `scale(${scale})`;
+ }
+}
+
+const LOCAL_IMG_CACHE_KEY = 'mitour_team_img_exts';
+let persistentExtCache = {};
+try {
+ persistentExtCache = JSON.parse(localStorage.getItem(LOCAL_IMG_CACHE_KEY) || '{}');
+} catch(e) {}
+
+const teamImageCache = {};
+
+function setImageWithFallback(element, teamNameRaw, isImgTag = false) {
+ if (!teamNameRaw) return;
+ const teamName = teamNameRaw.trim();
+
+ if (teamImageCache[teamName]) {
+ const src = teamImageCache[teamName];
+ if (src === 'none' || src === 'loading') {
+ if (src === 'none') {
+ if (isImgTag) element.style.display = 'none';
+ else element.style.backgroundImage = 'none';
+ }
+ return;
+ }
+ if (isImgTag) {
+ element.src = src;
+ element.style.display = 'block';
+ } else {
+ element.style.backgroundImage = `url('${src}')`;
+ }
+ return;
+ }
+
+ teamImageCache[teamName] = 'loading';
+
+ let exts = ['png', 'jpg', 'jpeg', 'gif', 'webp'];
+
+ const knownExt = persistentExtCache[teamName];
+ if (knownExt && exts.includes(knownExt)) {
+ exts = [knownExt, ...exts.filter(e => e !== knownExt)];
+ }
+
+ let cur = 0;
+
+ function tryNext() {
+ if (cur >= exts.length) {
+ teamImageCache[teamName] = 'none';
+ if (isImgTag) element.style.display = 'none';
+ else element.style.backgroundImage = 'none';
+ return;
+ }
+
+ const ext = exts[cur];
+ const src = `imgs/${encodeURIComponent(teamName)}.${ext}`;
+
+ const img = new Image();
+ img.onload = () => {
+ teamImageCache[teamName] = src;
+ persistentExtCache[teamName] = ext;
+ try {
+ localStorage.setItem(LOCAL_IMG_CACHE_KEY, JSON.stringify(persistentExtCache));
+ } catch(e) {}
+
+ if (isImgTag) {
+ element.src = src;
+ element.style.display = 'block';
+ } else {
+ element.style.backgroundImage = `url('${src}')`;
+ }
+ };
+ img.onerror = () => {
+ cur++;
+ tryNext();
+ };
+ img.src = src;
+ }
+
+ tryNext();
+}
+
+function updateOverlay(data) {
+ const chatOverlay = document.getElementById('chat-overlay');
+ if (chatOverlay) {
+ let isPlaying = false;
+ if (data.menu && data.menu.state === 2) isPlaying = true;
+ if (data.tourney && data.tourney.manager && data.tourney.manager.ipcState === 3) isPlaying = true;
+
+ if (isPlaying) chatOverlay.classList.add('hidden');
+ else chatOverlay.classList.remove('hidden');
+ }
+
+ if (data.menu && data.menu.bm) {
+ const bm = data.menu.bm;
+ const metadata = bm.metadata;
+ const stats = bm.stats;
+ const time = bm.time;
+
+ const titleEl = document.getElementById('title');
+ const titleWrap = document.querySelector('.title-overflow-wrap');
+
+ if(titleEl && titleWrap) {
+ const newTitle = metadata.title || "";
+ if(titleEl.innerText !== newTitle) {
+ titleEl.classList.remove('scrolling');
+ titleEl.style.removeProperty('--text-width');
+ titleEl.style.removeProperty('--parent-width');
+ titleEl.innerText = newTitle;
+ void titleEl.offsetWidth;
+
+ if (titleEl.scrollWidth > titleWrap.clientWidth) {
+ titleEl.style.setProperty('--text-width', `${titleEl.scrollWidth}px`);
+ titleEl.style.setProperty('--parent-width', `${titleWrap.clientWidth}px`);
+ titleEl.classList.add('scrolling');
+ }
+ }
+ }
+
+ if(document.getElementById('artist')) document.getElementById('artist').innerText = metadata.artist || "";
+ if(document.getElementById('mapid')) document.getElementById('mapid').innerText = bm.id || 0;
+
+ if(document.getElementById('cs')) document.getElementById('cs').innerText = stats.CS != null ? stats.CS : 0;
+ if(document.getElementById('ar')) document.getElementById('ar').innerText = stats.AR != null ? stats.AR : 0;
+ if(document.getElementById('od')) document.getElementById('od').innerText = stats.OD != null ? stats.OD : 0;
+ if(document.getElementById('sr')) document.getElementById('sr').innerText = (stats.fullSR != null ? stats.fullSR : 0).toFixed(2) + "★";
+ if(document.getElementById('bpm')) document.getElementById('bpm').innerText = Math.round(stats.BPM != null ? stats.BPM.max : 0);
+
+ const currentMs = time.current;
+ const totalMs = time.full;
+ if(document.getElementById('len')) document.getElementById('len').innerText = `${formatTime(currentMs)} / ${formatTime(totalMs)}`;
+
+ let progressPercent = 0;
+ if (totalMs > 0) progressPercent = (currentMs / totalMs) * 100;
+ if (progressPercent > 100) progressPercent = 100;
+ if (progressPercent < 0) progressPercent = 0;
+
+ if(document.getElementById('progress-fill')) document.getElementById('progress-fill').style.width = `${progressPercent}%`;
+
+ if (bm.set !== currentSetId) {
+ currentSetId = bm.set;
+ let bgUrl = currentSetId > 0
+ ? `https://assets.ppy.sh/beatmaps/${currentSetId}/covers/cover@2x.jpg`
+ : `http://127.0.0.1:24050/Background?time=${new Date().getTime()}`;
+
+ const thumbDiv = document.getElementById('map-thumb');
+ const bgDiv = document.getElementById('card-bg');
+
+ if(thumbDiv) thumbDiv.style.backgroundImage = `url('${bgUrl}')`;
+ if(bgDiv) bgDiv.style.backgroundImage = `url('${bgUrl}')`;
+ }
+
+ if (bm.id !== currentMapId) {
+ currentMapId = bm.id;
+ const pickName = picksData[String(bm.id)] || "WARMUP";
+ if(document.getElementById('pick-bar')) updatePickBar(pickName);
+ if(document.getElementById('inner-pick-badge')) checkInnerPickBadge(bm.id);
+ }
+
+ if(document.getElementById('map-status')) {
+ updateMapStatus(bm.rankedStatus);
+ }
+ }
+
+ if (data.tourney && data.tourney.manager) {
+ const manager = data.tourney.manager;
+ const ipc = data.tourney.ipcClients;
+ const leftNameRaw = manager.teamName.left || "Red";
+ const rightNameRaw = manager.teamName.right || "Blue";
+
+ let leftSeed = teamSeeds[leftNameRaw.toLowerCase()];
+ let rightSeed = teamSeeds[rightNameRaw.toLowerCase()];
+
+ let leftDisplay = leftSeed ? `#${leftSeed} ${leftNameRaw}` : leftNameRaw;
+ let rightDisplay = rightSeed ? `${rightNameRaw} #${rightSeed}` : rightNameRaw;
+
+ if(document.getElementById('red-name')) document.getElementById('red-name').innerHTML = leftDisplay;
+ if(document.getElementById('blue-name')) document.getElementById('blue-name').innerHTML = rightDisplay;
+ if(document.getElementById('red-icon')) setImageWithFallback(document.getElementById('red-icon'), leftNameRaw);
+ if(document.getElementById('blue-icon')) setImageWithFallback(document.getElementById('blue-icon'), rightNameRaw);
+ if(document.getElementById('red-stars')) renderStars('red-stars', manager.stars.left, manager.bestOF);
+ if(document.getElementById('blue-stars')) renderStars('blue-stars', manager.stars.right, manager.bestOF);
+
+ let redS = 0, blueS = 0;
+ if (ipc) {
+ ipc.forEach(c => {
+ let currentScore = (c.gameplay && c.gameplay.score) ? c.gameplay.score : 0;
+ if (c.team === 'left' || c.team === 'Red') redS += currentScore;
+ if (c.team === 'right' || c.team === 'Blue') blueS += currentScore;
+ });
+ }
+ if (redCountUp) redCountUp.update(redS);
+ else if(document.getElementById('red-score')) document.getElementById('red-score').innerText = redS;
+
+ if (blueCountUp) blueCountUp.update(blueS);
+ else if(document.getElementById('blue-score')) document.getElementById('blue-score').innerText = blueS;
+
+ const diff = Math.abs(redS - blueS);
+ const redDiffEl = document.getElementById('red-diff');
+ const blueDiffEl = document.getElementById('blue-diff');
+
+ if(redDiffEl && blueDiffEl) {
+ redDiffEl.innerText = "";
+ blueDiffEl.innerText = "";
+ redDiffEl.classList.remove('visible');
+ blueDiffEl.classList.remove('visible');
+
+ if (redS > blueS) {
+ blueDiffEl.innerText = `-${diff.toLocaleString()}`;
+ blueDiffEl.classList.add('visible');
+ } else if (blueS > redS) {
+ redDiffEl.innerText = `-${diff.toLocaleString()}`;
+ redDiffEl.classList.add('visible');
+ }
+ }
+
+ if(document.getElementById('team-red')) document.getElementById('team-red').classList.toggle('leading', redS > blueS);
+ if(document.getElementById('team-blue')) document.getElementById('team-blue').classList.toggle('leading', blueS > redS);
+ }
+
+ let chatSource = null;
+ if (data.tourney) {
+ if (data.tourney.chat) chatSource = data.tourney.chat;
+ else if (data.tourney.manager && data.tourney.manager.chat) chatSource = data.tourney.manager.chat;
+ } else if (data.chat) {
+ chatSource = data.chat;
+ }
+
+ if (chatSource) updateChat(chatSource);
+}
+
+function updateMapStatus(status) {
+ const el = document.getElementById('map-status');
+ if (!el) return;
+ el.className = 'status-badge';
+ let activeClass = '';
+ if (status === 4) activeClass = 'status-ranked';
+ else if (status === 7) activeClass = 'status-loved';
+ else if (status === 3 || status === 6) activeClass = 'status-qualified';
+ else if (status === 5) activeClass = 'status-approved';
+ else if (status === 2 || status === 0) activeClass = 'status-pending';
+ else if (status === -1) activeClass = 'status-wip';
+ else if (status === -2) activeClass = 'status-graveyard';
+ else if (status === 1 || status === null || status === undefined) activeClass = 'status-none';
+ if (activeClass) el.classList.add(activeClass, 'visible');
+ else el.classList.remove('visible');
+}
+
+function handleWinnerData(manager) {
+ if (!document.getElementById('winner-container')) return;
+ const bestOf = manager.bestOF;
+ const winsNeeded = Math.ceil(bestOf / 2);
+ const starsLeft = manager.stars.left;
+ const starsRight = manager.stars.right;
+
+ let winnerTeam = null;
+ let winnerSide = null;
+
+ if (starsLeft >= winsNeeded) {
+ winnerTeam = manager.teamName.left;
+ winnerSide = 'red';
+ } else if (starsRight >= winsNeeded) {
+ winnerTeam = manager.teamName.right;
+ winnerSide = 'blue';
+ } else {
+ hideWinner();
+ return;
+ }
+
+ if (winnerTeam && winnerTeam !== currentWinner) {
+ currentWinner = winnerTeam;
+ showWinnerScene(winnerTeam, winnerSide);
+ }
+}
+
+async function showWinnerScene(teamName, side) {
+ const container = document.getElementById('winner-container');
+ if(!container) return;
+ isDataLoading = true;
+ const labelEl = document.getElementById('team-label');
+ const nameEl = document.getElementById('team-name');
+ const logoEl = document.getElementById('team-logo');
+
+ container.classList.remove('winner-red', 'winner-blue');
+ container.classList.add(side === 'red' ? 'winner-red' : 'winner-blue');
+ labelEl.innerText = side === 'red' ? "TEAM RED" : "TEAM BLUE";
+
+ let seed = teamSeeds[teamName.toLowerCase()];
+ if (seed) {
+ nameEl.innerHTML = `#${seed} ${teamName}`;
+ } else {
+ nameEl.innerText = teamName;
+ }
+
+ setImageWithFallback(logoEl, teamName);
+
+ let playerIds = TEAMS_CONFIG[teamName];
+ if (!playerIds) {
+ const key = Object.keys(TEAMS_CONFIG).find(k => k.toLowerCase() === teamName.toLowerCase());
+ if (key) playerIds = TEAMS_CONFIG[key];
+ }
+ if (playerIds) {
+ try {
+ const players = await Promise.all(playerIds.map(id => fetchPlayer(id)));
+ renderPlayers(players);
+ } catch (e) { console.error(e); }
+ } else {
+ document.getElementById('players-grid').innerHTML = 'No Data
';
+ }
+ container.classList.remove('hidden');
+ isDataLoading = false;
+}
+
+function hideWinner() {
+ const container = document.getElementById('winner-container');
+ if (container && !container.classList.contains('hidden')) {
+ container.classList.add('hidden');
+ currentWinner = null;
+ }
+}
+
+async function fetchPlayer(userId) {
+ if (userId == 18815482) return { name: "antoshika", country: "RU", rank: 0 };
+ if (!userId || isNaN(userId)) return { name: "Unknown", country: null, rank: 0 };
+ if (OSU_API_KEY) {
+ try {
+ const res = await fetch(`https://osu.ppy.sh/api/get_user?k=${OSU_API_KEY}&u=${userId}&type=id`);
+ if (res.ok) {
+ const json = await res.json();
+ if (json && json.length > 0) return { name: json[0].username, country: json[0].country, rank: parseInt(json[0].pp_rank) || 0 };
+ }
+ } catch (e) { }
+ }
+ try {
+ const res = await fetch(`https://api.nerinyan.moe/u/${userId}`);
+ if (res.ok) {
+ const json = await res.json();
+ return { name: json.username, country: json.country_code, rank: json.statistics ? json.statistics.global_rank : 0 };
+ }
+ } catch (e) { }
+ try {
+ const res = await fetch(`https://catboy.best/api/v2/user/${userId}`);
+ if (res.ok) {
+ const json = await res.json();
+ return { name: json.username, country: json.country, rank: json.statistics ? json.statistics.global_rank : 0 };
+ }
+ } catch (e) { }
+ return { name: `Player ${userId}`, country: null, rank: 0 };
+}
+
+function renderPlayers(players) {
+ const grid = document.getElementById('players-grid');
+ if(!grid) return;
+ grid.innerHTML = '';
+ players.forEach(p => {
+ const div = document.createElement('div');
+ div.className = 'player-item';
+ let flagHtml = '';
+ if (p.country) {
+ const countryCode = p.country.toLowerCase();
+ flagHtml = `
`;
+ }
+ div.innerHTML = `${flagHtml} ${p.name}`;
+ grid.appendChild(div);
+ });
+}
+
+function checkInnerPickBadge(mapId) {
+ const badge = document.getElementById('inner-pick-badge');
+ if(!badge) return;
+ const status = mapStates[mapId];
+ badge.classList.remove('red', 'blue', 'visible');
+ if (status === 'picked-red') {
+ badge.innerText = "PICK";
+ badge.classList.add('red', 'visible');
+ } else if (status === 'picked-blue') {
+ badge.innerText = "PICK";
+ badge.classList.add('blue', 'visible');
+ }
+}
+
+function updateBadgeIfCurrent(clickedMapId) {
+ if (Number(clickedMapId) === Number(currentMapId)) checkInnerPickBadge(clickedMapId);
+}
+
+function updatePickBar(pickText) {
+ const bar = document.getElementById('pick-bar');
+ const textEl = document.getElementById('pick-text');
+ const topBar = document.getElementById('top-bar');
+
+ if(textEl) textEl.innerText = pickText;
+ let colorVar = getColorForMod(pickText);
+ const colorVal = `var(${colorVar})`;
+
+ if(topBar) {
+ topBar.style.setProperty('--active-color', colorVal);
+
+ if (pickText === "WARMUP") {
+ topBar.style.borderColor = "rgba(255,255,255,0.1)";
+ } else {
+ topBar.style.borderColor = colorVal;
+ }
+ }
+}
+
+function getColorForMod(modStr) {
+ if (modStr === "WARMUP") return '--mod-warmup';
+ if (modStr.startsWith("NM")) return '--mod-nm';
+ if (modStr.startsWith("HD")) return '--mod-hd';
+ if (modStr.startsWith("HR")) return '--mod-hr';
+ if (modStr.startsWith("DT")) return '--mod-dt';
+ if (modStr.startsWith("FM")) return '--mod-fm';
+ if (modStr.startsWith("AP")) return '--mod-ap';
+ if (modStr.startsWith("TB")) return '--mod-tb';
+ if (modStr.startsWith("EZ")) return '--mod-ez';
+ return '--mod-def';
+}
+
+function formatTime(ms) {
+ if (isNaN(ms) || ms < 0) return "0:00";
+ const totalSeconds = Math.floor(ms / 1000);
+ const m = Math.floor(totalSeconds / 60);
+ const s = totalSeconds % 60;
+ return `${m}:${s < 10 ? '0' : ''}${s}`;
+}
+
+function renderStars(elementId, currentWins, bestOf) {
+ const container = document.getElementById(elementId);
+ if(!container) return;
+ container.innerHTML = '';
+ const winsNeeded = Math.ceil(bestOf / 2);
+ for (let i = 0; i < winsNeeded; i++) {
+ let div = document.createElement('div');
+ div.className = 'star-point';
+ if (i < currentWins) div.classList.add('active');
+ container.appendChild(div);
+ }
+}
+
+function toggleMappool() {
+ const el = document.getElementById('mappool-overlay');
+ if(el) el.classList.toggle('visible');
+}
+
+async function fetchMapDetails() {
+ const ids = Object.keys(picksData);
+ const BATCH_SIZE = 5;
+ for (let i = 0; i < ids.length; i += BATCH_SIZE) {
+ const batch = ids.slice(i, i + BATCH_SIZE);
+ await Promise.all(batch.map(id => loadSingleMap(id)));
+ }
+}
+
+async function loadSingleMap(id) {
+ if (mapCache[id]) return;
+ try {
+ const response = await fetch(`https://api.nerinyan.moe/b/${id}`);
+ if (!response.ok) throw new Error("Err");
+ const data = await response.json();
+ let mapper = data.beatmapset ? data.beatmapset.creator : "Unknown";
+ let diffName = data.version;
+ if (!diffName || diffName === "Undefined") diffName = "Unknown";
+ mapCache[id] = { title: data.title, artist: data.artist, mapper: mapper, diff: diffName, setId: data.beatmapset_id };
+ } catch (error) {
+ try {
+ const sayoRes = await fetch(`https://api.sayobot.cn/v2/beatmapinfo?K=${id}`);
+ const sayoJson = await sayoRes.json();
+ if(sayoJson && sayoJson.data) {
+ let diffName = "Unknown";
+ if (sayoJson.data.bid_data) {
+ const bData = sayoJson.data.bid_data.find(b => String(b.bid) === String(id));
+ if (bData && bData.version && bData.version !== "Undefined") diffName = bData.version;
+ else if (sayoJson.data.bid_data.length > 0) diffName = sayoJson.data.bid_data[0].version;
+ }
+ mapCache[id] = { title: sayoJson.data.title, artist: sayoJson.data.artist, mapper: sayoJson.data.creator, diff: diffName, setId: sayoJson.data.sid };
+ }
+ } catch (e2) {
+ mapCache[id] = { title: `Map ID: ${id}`, artist: "Artist", mapper: "Mapper", diff: "Unknown", setId: 0 };
+ }
+ }
+ updateCardUI(id);
+}
+
+function updateCardUI(id) {
+ const card = document.querySelector(`.pool-card[data-id="${id}"]`);
+ if (card && mapCache[id]) {
+ const info = mapCache[id];
+ const bg = card.querySelector('.pool-card-bg');
+ if (info.setId > 0) bg.style.backgroundImage = `url('https://assets.ppy.sh/beatmaps/${info.setId}/covers/cover.jpg')`;
+ else bg.style.backgroundColor = '#333';
+ card.querySelector('.pc-title').innerText = info.title;
+ card.querySelector('.pc-artist').innerText = info.artist;
+ card.querySelector('.pc-mapper').innerHTML = `mapper ${info.mapper} diff ${info.diff}`;
+ }
+}
+
+function renderMappool() {
+ const container = document.getElementById('pool-grid');
+ if(!container) return;
+ container.innerHTML = '';
+ const groups = { NM: [], HD: [], HR: [], DT: [], EZ: [], FM: [], AP: [], TB: [] };
+ Object.entries(picksData).forEach(([id, modStr]) => {
+ let prefix = modStr.replace(/[0-9]/g, '');
+ if (groups[prefix]) groups[prefix].push({ id, modStr });
+ });
+ const order = ['NM', 'HD', 'HR', 'DT', 'EZ', 'FM', 'AP', 'TB'];
+ order.forEach(modTag => {
+ const maps = groups[modTag];
+ if (maps.length === 0) return;
+ maps.sort((a, b) => a.modStr.localeCompare(b.modStr, undefined, {numeric: true}));
+ const row = document.createElement('div');
+ row.className = 'pool-row';
+ maps.forEach(item => {
+ const card = document.createElement('div');
+ card.className = 'pool-card';
+ card.dataset.id = item.id;
+ let colorVar = getColorForMod(item.modStr);
+ card.innerHTML = `
+
+
+
+
+
+
Loading...
+
Map ID: ${item.id}
+
wait...
+
+
+ ${item.modStr}
+
+
+ `;
+ card.onmousedown = (e) => handlePoolClick(card, e, item.id);
+ row.appendChild(card);
+ });
+ container.appendChild(row);
+ });
+}
+
+function handlePoolClick(card, e, mapId) {
+ e.preventDefault();
+ const classes = ['picked-red', 'picked-blue', 'banned-red', 'banned-blue', 'protect-red', 'protect-blue'];
+ let newStatus = null;
+ if (e.shiftKey) {
+ classes.forEach(c => card.classList.remove(c));
+ mapStates[mapId] = null;
+ updateBadgeIfCurrent(mapId);
+ return;
+ }
+ classes.forEach(c => card.classList.remove(c));
+ if (e.altKey) {
+ if (e.button === 0) { card.classList.add('protect-red'); newStatus = 'protect-red'; }
+ if (e.button === 2) { card.classList.add('protect-blue'); newStatus = 'protect-blue'; }
+ } else if (e.ctrlKey) {
+ if (e.button === 0) { card.classList.add('banned-red'); newStatus = 'banned-red'; }
+ if (e.button === 2) { card.classList.add('banned-blue'); newStatus = 'banned-blue'; }
+ } else {
+ if (e.button === 0) { card.classList.add('picked-red'); newStatus = 'picked-red'; }
+ if (e.button === 2) { card.classList.add('picked-blue'); newStatus = 'picked-blue'; }
+ }
+ mapStates[mapId] = newStatus;
+ updateBadgeIfCurrent(mapId);
+}
+
+function updateChat(chatData) {
+ if (!chatData) return;
+ if (chatData.length === lastChatCount) return;
+ const container = document.getElementById('chat-messages');
+ if(!container) return;
+ container.innerHTML = '';
+ const startIndex = Math.max(chatData.length - 8, 0);
+ const messagesToShow = chatData.slice(startIndex);
+ messagesToShow.forEach((msg, idx) => {
+ const originalIndex = startIndex + idx;
+ let timeStr;
+ if (!messageTimeCache.has(originalIndex)) {
+ const now = new Date();
+ timeStr = now.toLocaleTimeString('ru-RU', { hour: '2-digit', minute: '2-digit', second: '2-digit' });
+ messageTimeCache.set(originalIndex, timeStr);
+ }
+ timeStr = messageTimeCache.get(originalIndex);
+ let teamClass = 'team-unknown';
+ let roleClass = '';
+ if (msg.team === 'left' || msg.team === 'Red') teamClass = 'team-left';
+ else if (msg.team === 'right' || msg.team === 'Blue') teamClass = 'team-right';
+ if (msg.name === 'BanchoBot') roleClass = 'role-banchobot';
+ else if (teamClass === 'team-unknown') roleClass = 'role-referee';
+ let messageText = msg.messageBody || msg.message || "";
+ if (!messageText) return;
+ const line = document.createElement('div');
+ line.className = 'chat-irc-line';
+ line.innerHTML = `[${timeStr}]${msg.name}: ${messageText}`;
+ container.appendChild(line);
+ });
+ lastChatCount = chatData.length;
+}
+
+document.addEventListener('contextmenu', event => event.preventDefault());
+
+const SEED_CONFIG = { jsonPath: 'conf/bracket.json' };
+const seedMapCache = new Map();
+let seedTeams = [];
+let seedCurrentTeamIndex = 0;
+const MOD_ORDER = ['NM', 'HD', 'HR', 'DT', 'EZ', 'FM', 'AP', 'TB'];
+
+window.nextSlide = async function() {
+ if (seedCurrentTeamIndex > 0) {
+ seedCurrentTeamIndex--;
+ await updateSlideWithAnimation();
+ }
+};
+
+window.prevSlide = async function() {
+ if (seedCurrentTeamIndex < seedTeams.length - 1) {
+ seedCurrentTeamIndex++;
+ await updateSlideWithAnimation();
+ }
+};
+
+async function initSeedRevealWithData(data) {
+ try {
+ if (!data || !data.Teams) throw new Error("Teams not found");
+ seedTeams = data.Teams.map(t => {
+ let groupedMaps = {};
+ MOD_ORDER.forEach(mod => groupedMaps[mod] = []);
+ groupedMaps['OTHER'] = [];
+ if (t.SeedingResults) {
+ t.SeedingResults.forEach(group => {
+ let modName = group.Mod;
+ let targetList = groupedMaps[modName] ? groupedMaps[modName] : groupedMaps['OTHER'];
+ if(group.Beatmaps) {
+ group.Beatmaps.forEach((m, idx) => {
+ const poolId = `${modName}${idx + 1}`;
+ let embeddedInfo = null;
+ if (m.BeatmapInfo && m.BeatmapInfo.Metadata) {
+ embeddedInfo = {
+ title: m.BeatmapInfo.Metadata.Title,
+ artist: m.BeatmapInfo.Metadata.Artist,
+ mapper: m.BeatmapInfo.Metadata.Author.Username,
+ diff: m.BeatmapInfo.DifficultyName,
+ cover: m.BeatmapInfo.Covers ? m.BeatmapInfo.Covers['cover@2x'] : null
+ };
+ }
+ targetList.push({ mod: modName, poolId: poolId, seed: parseInt(m.Seed, 10) || m.Seed, score: m.Score, id: m.ID, info: embeddedInfo });
+ });
+ }
+ });
+ }
+ let teamFlagUpper = 'XX';
+ if (t.FlagName) teamFlagUpper = t.FlagName.toUpperCase();
+ let roster = [];
+ if (t.Players) {
+ roster = t.Players.map(p => {
+ let cCode = 'XX';
+ if (p.country_code) cCode = p.country_code;
+ else if (p.country && p.country.code) cCode = p.country.code;
+ if (cCode) cCode = cCode.toUpperCase();
+ let pName = p.Username || p.username || p.Name || p.name;
+ if (!pName && t.Players.length === 1) pName = t.FullName;
+ let pId = p.id || p.ID;
+ return { name: pName || (pId ? `Player ${pId}` : null), country: cCode, id: pId };
+ }).filter(p => p.name !== null);
+ }
+ return {
+ ...t,
+ _seed: parseInt(t.Seed, 10),
+ _avgRank: t.AverageRank ? Math.round(t.AverageRank) : 0,
+ _groupedMaps: groupedMaps,
+ _roster: roster,
+ _acronym: t.Acronym,
+ _fullname: t.FullName,
+ _flagName: teamFlagUpper
+ };
+ });
+ seedTeams.sort((a, b) => a._seed - b._seed);
+ seedCurrentTeamIndex = seedTeams.length - 1;
+ await preloadMapsForTeam(seedTeams[seedCurrentTeamIndex]);
+ renderSlide();
+
+ const container = document.getElementById('slideContainer');
+ if (container) container.classList.remove('seed-hidden');
+
+ document.addEventListener('keydown', (e) => {
+ if (e.code === 'Space' || e.code === 'ArrowRight') nextSlide();
+ if (e.code === 'ArrowLeft') prevSlide();
+ });
+ } catch (e) {
+ console.error(e);
+ document.body.innerHTML = "Error: " + e.message + "
";
+ }
+}
+
+async function fetchBeatmapData(id) {
+ if (OSU_API_KEY) {
+ try {
+ const res = await fetch(`https://osu.ppy.sh/api/get_beatmaps?k=${OSU_API_KEY}&b=${id}`);
+ if (res.ok) {
+ const json = await res.json();
+ if (json && json.length > 0) {
+ const data = json[0];
+ return {
+ title: data.title,
+ artist: data.artist,
+ mapper: data.creator,
+ diff: data.version,
+ setId: data.beatmapset_id,
+ cover: `https://assets.ppy.sh/beatmaps/${data.beatmapset_id}/covers/cover.jpg`
+ };
+ }
+ }
+ } catch(e) {}
+ }
+
+ try {
+ const sayoRes = await fetch(`https://api.sayobot.cn/v2/beatmapinfo?K=${id}&T=4`);
+ if (sayoRes.ok) {
+ const sayoJson = await sayoRes.json();
+ if(sayoJson && sayoJson.data) {
+ let diffName = "Unknown";
+ if (sayoJson.data.bid_data) {
+ const bData = sayoJson.data.bid_data.find(b => String(b.bid) === String(id));
+ if (bData && bData.version && bData.version !== "Undefined") diffName = bData.version;
+ else if (sayoJson.data.bid_data.length > 0) diffName = sayoJson.data.bid_data[0].version;
+ }
+ return {
+ title: sayoJson.data.title,
+ artist: sayoJson.data.artist,
+ mapper: sayoJson.data.creator,
+ diff: diffName,
+ setId: sayoJson.data.sid,
+ cover: `https://assets.ppy.sh/beatmaps/${sayoJson.data.sid}/covers/cover.jpg`
+ };
+ }
+ }
+ } catch (e2) {}
+
+ return { title: `Map ID: ${id}`, artist: "Artist", mapper: "Mapper", diff: "Unknown", setId: 0, cover: null };
+}
+
+async function loadSingleMap(id) {
+ if (mapCache[id]) return;
+ const data = await fetchBeatmapData(id);
+ mapCache[id] = data;
+ updateCardUI(id);
+}
+
+async function getMapInfo(beatmapId) {
+ if (seedMapCache.has(beatmapId)) return seedMapCache.get(beatmapId);
+ const data = await fetchBeatmapData(beatmapId);
+ seedMapCache.set(beatmapId, data);
+ return data;
+}
+
+async function preloadMapsForTeam(team) {
+ if (!team) return;
+ const promises = [];
+ if (team._groupedMaps) {
+ for (const mod in team._groupedMaps) {
+ team._groupedMaps[mod].forEach(m => {
+ if (!m.info && m.id) {
+ promises.push(getMapInfo(m.id).then(data => {
+ m.info = data;
+ }));
+ }
+ });
+ }
+ }
+ if (team._roster) {
+ team._roster.forEach(p => {
+ if ((p.name && p.name.startsWith('Player ')) || !p._rankFetched) {
+ promises.push(fetchPlayer(p.id).then(data => {
+ p.name = data.name;
+ if (data.country) p.country = data.country.toUpperCase();
+ if (data.rank) p.rank = data.rank;
+ p._rankFetched = true;
+ }));
+ }
+ });
+ }
+ await Promise.all(promises);
+
+ if (!team._avgRank || team._avgRank === 0) {
+ if (team._roster && team._roster.length > 0) {
+ const validRanks = team._roster.filter(p => p.rank && p.rank > 0).map(p => p.rank);
+ if (validRanks.length > 0) {
+ team._avgRank = Math.round(validRanks.reduce((a, b) => a + b, 0) / validRanks.length);
+ }
+ }
+ }
+}
+
+async function updateSlideWithAnimation() {
+ const container = document.getElementById('slideContainer');
+ if (container) {
+ container.style.opacity = 0;
+ container.style.transition = 'opacity 0.3s ease';
+ setTimeout(async () => {
+ await preloadMapsForTeam(seedTeams[seedCurrentTeamIndex]);
+ renderSlide();
+ container.style.opacity = 1;
+ }, 300);
+ } else {
+ await preloadMapsForTeam(seedTeams[seedCurrentTeamIndex]);
+ renderSlide();
+ }
+}
+
+function renderSlide() {
+ const team = seedTeams[seedCurrentTeamIndex];
+ if (!team) return;
+
+ const teamSeedEl = document.getElementById('teamSeed');
+ if (teamSeedEl) teamSeedEl.innerText = `#${team._seed}`;
+
+ const seedWrapper = document.getElementById('seedWrapper');
+ if (seedWrapper) {
+ seedWrapper.classList.remove('seed-gold', 'seed-silver', 'seed-bronze');
+ if (team._seed === 1) seedWrapper.classList.add('seed-gold');
+ else if (team._seed === 2) seedWrapper.classList.add('seed-silver');
+ else if (team._seed === 3) seedWrapper.classList.add('seed-bronze');
+ }
+
+ const fullnameEl = document.getElementById('teamFullname');
+ if (fullnameEl) fullnameEl.innerText = team._fullname || team._acronym || "Unknown Team";
+
+ const flagEl = document.getElementById('teamFlag');
+ if (flagEl) {
+ if (team._flagName && team._flagName !== 'XX') {
+ flagEl.src = `https://flagcdn.com/w40/${team._flagName.toLowerCase()}.png`;
+ flagEl.style.display = 'block';
+ } else {
+ flagEl.style.display = 'none';
+ }
+ }
+
+ const avatarEl = document.getElementById('teamAvatar');
+ if (avatarEl) {
+ const teamName = team._fullname || team._acronym;
+ if (teamName) {
+ setImageWithFallback(avatarEl, teamName, true);
+ } else {
+ avatarEl.style.display = 'none';
+ }
+ }
+
+ const rankEl = document.getElementById('teamRank');
+ if (rankEl) {
+ rankEl.innerText = `#${team._avgRank || 0}`;
+ document.getElementById('rankBlock').style.display = 'block';
+ }
+
+ const rosterBlock = document.getElementById('rosterBlock');
+ const rosterList = document.getElementById('rosterList');
+ if (rosterBlock && rosterList) {
+ rosterList.innerHTML = '';
+ if (team._roster && team._roster.length > 0) {
+ rosterBlock.style.display = 'block';
+ team._roster.forEach(player => {
+ const pDiv = document.createElement('div');
+ pDiv.className = 'player-card';
+
+ const pAvatar = document.createElement('img');
+ pAvatar.className = 'p-avatar';
+ pAvatar.src = player.id ? `https://a.ppy.sh/${player.id}` : '';
+ pAvatar.onerror = () => pAvatar.style.display = 'none';
+
+ const pInfo = document.createElement('div');
+ pInfo.className = 'p-info';
+
+ if (player.country && player.country !== 'XX') {
+ const pFlag = document.createElement('img');
+ pFlag.className = 'p-flag';
+ pFlag.src = `https://flagcdn.com/w40/${player.country.toLowerCase()}.png`;
+ pInfo.appendChild(pFlag);
+ }
+
+ const pName = document.createElement('span');
+ pName.className = 'p-name';
+ pName.innerText = player.name;
+ pInfo.appendChild(pName);
+
+ pDiv.appendChild(pAvatar);
+ pDiv.appendChild(pInfo);
+ rosterList.appendChild(pDiv);
+ });
+ } else {
+ rosterBlock.style.display = 'none';
+ }
+ }
+
+ const modsContainer = document.getElementById('modsContainer');
+ if (modsContainer) {
+ modsContainer.innerHTML = '';
+ MOD_ORDER.forEach(mod => {
+ const maps = team._groupedMaps[mod];
+ if (!maps || maps.length === 0) return;
+
+ const modCol = document.createElement('div');
+ modCol.className = 'mod-column';
+
+ const modHeader = document.createElement('div');
+ modHeader.className = 'mod-header';
+ modHeader.innerText = mod;
+ let colorVar = getColorForMod(mod);
+ modHeader.style.color = `var(${colorVar})`;
+ modHeader.style.borderLeftColor = `var(${colorVar})`;
+ modCol.appendChild(modHeader);
+
+ maps.forEach(m => {
+ const card = document.createElement('div');
+ card.className = 'map-card';
+
+ const info = m.info || { title: `Map ID: ${m.id}`, mapper: "Unknown", diff: "Unknown", cover: null, setId: 0 };
+
+ let bgUrl = '';
+ if (info.cover) bgUrl = info.cover;
+ else if (info.setId > 0) bgUrl = `https://assets.ppy.sh/beatmaps/${info.setId}/covers/cover.jpg`;
+
+ let rankClass = '';
+ if (m.seed === 1) rankClass = 'rank-gold';
+ else if (m.seed === 2) rankClass = 'rank-silver';
+ else if (m.seed === 3) rankClass = 'rank-bronze';
+
+ card.innerHTML = `
+ ${bgUrl ? `` : ``}
+
+
+
${m.poolId || ''}
+
+
+ ${info.title} [${info.diff}]
+
+
${info.mapper}
+
+
+
+ #${m.seed || 0}
+ ${m.score ? (Math.round(m.score * 100) / 100).toLocaleString('en-US') : 0}
+
+
+ `;
+ modCol.appendChild(card);
+ });
+ modsContainer.appendChild(modCol);
+ });
+
+ setTimeout(() => {
+ document.querySelectorAll('.song-title-seed').forEach(el => {
+ if (el.scrollWidth > el.parentElement.clientWidth) {
+ el.classList.add('scroll');
+ } else {
+ el.classList.remove('scroll');
+ }
+ });
+ }, 100);
+ }
+}
\ No newline at end of file
diff --git a/counters/mitour by antoshika/metadata.txt b/counters/mitour by antoshika/metadata.txt
new file mode 100644
index 00000000..f908aba1
--- /dev/null
+++ b/counters/mitour by antoshika/metadata.txt
@@ -0,0 +1,7 @@
+Usecase: obs-overlay
+Name: mitour
+Author: antoshika
+Version: 1.3.9
+CompatibleWith: tosu
+Resolution: 1920x1080
+authorLinks: https://osu.ppy.sh/users/18815482,https://discord.com/3jBQs9buYe
\ No newline at end of file
diff --git a/counters/mitour by antoshika/seed.html b/counters/mitour by antoshika/seed.html
new file mode 100644
index 00000000..1bc93139
--- /dev/null
+++ b/counters/mitour by antoshika/seed.html
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
![]()
+
+
+
+
TEAM NAME
+
![]()
+
+
+
+
+
+
+
+
+ AVG RANK
+ #0
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/counters/mitour by antoshika/settings.json b/counters/mitour by antoshika/settings.json
new file mode 100644
index 00000000..53754ec6
--- /dev/null
+++ b/counters/mitour by antoshika/settings.json
@@ -0,0 +1,58 @@
+[
+ {
+ "uniqueID": "documentation",
+ "type": "button",
+ "title": "Documentation",
+ "description": "all about how configure overlay",
+ "options": "",
+ "value": "https://hatsunemiku39.ru/documentation"
+ },
+ {
+ "uniqueID": "getApiButtonLink",
+ "type": "button",
+ "title": "Get osu!API Key",
+ "description": "",
+ "options": "",
+ "value": "https://osu.ppy.sh/home/account/edit#legacy-api"
+ },
+ {
+ "uniqueID": "osuApiKey",
+ "type": "text",
+ "title": "osu!API Key",
+ "description": "Paste your API key here",
+ "options": "",
+ "value": ""
+ },
+ {
+ "uniqueID": "tourneySection",
+ "type": "title",
+ "title": "Tournament Parts",
+ "description": "========================================================",
+ "options": "",
+ "value": ""
+ },
+ {
+ "uniqueID": "mappoolData",
+ "type": "textarea",
+ "title": "Mappool",
+ "description": "Fill your mappool.",
+ "options": "",
+ "value": ""
+ },
+ {
+ "uniqueID": "teamsData",
+ "type": "textarea",
+ "title": "Teams",
+ "description": "Example: Red: 18815482, 18815482 | Blue: 18815482, 18815482",
+ "options": "",
+ "value": ""
+ },
+ {
+ "uniqueID": "bracketData",
+ "type": "textarea",
+ "title": "Bracket",
+ "description": "Paste the contents of your 'bracket.json' here",
+ "options": "",
+ "value": ""
+ }
+]
\ No newline at end of file
diff --git a/counters/mitour by antoshika/showcase.html b/counters/mitour by antoshika/showcase.html
new file mode 100644
index 00000000..af5be7bd
--- /dev/null
+++ b/counters/mitour by antoshika/showcase.html
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
+
+
+
+
+
PICK
+
+
+
+
+
+
+
+
+
Replay by:
+
+ Guest
+
+
+
+
+
Artist
+
+
+
+
+
CS0
+
AR0
+
OD0
+
SR0.0★
+
BPM0
+
Length0:00
+
ID0
+
+
+
+
+
+
+
+
+
+ WARMUP
+
+
+
+
+
+
\ No newline at end of file
diff --git a/counters/mitour by antoshika/style.css b/counters/mitour by antoshika/style.css
new file mode 100644
index 00000000..2bd1f0c6
--- /dev/null
+++ b/counters/mitour by antoshika/style.css
@@ -0,0 +1,851 @@
+:root {
+ --red-team: #ff5e5e;
+ --blue-team: #5e9eff;
+ --bg-dark: #1a1a1a;
+ --text-white: #ffffff;
+ --text-gray: #b3b3b3;
+ --accent: #ffd700;
+ --white: #ffffff;
+ --font-main: 'Montserrat', sans-serif;
+ --font-seed: 'Manrope', sans-serif;
+
+ --mod-nm: #5e9eff;
+ --mod-hd: #ffd700;
+ --mod-hr: #ff5e5e;
+ --mod-dt: #9d5eff;
+ --mod-fm: #2E8B57;
+ --mod-tb: #5F9EA0;
+ --mod-ap: #888888;
+ --mod-ez: #a5d6a7;
+ --mod-warmup: #000000;
+ --mod-def: #555555;
+
+ --st-ranked: #76C8FF;
+ --st-loved: #ff66aa;
+ --st-qualified: #66cc66;
+ --st-approved: #66cc66;
+ --st-gray: #888888;
+ --st-none: #ff4444;
+
+ --bg-color: transparent;
+ --text-main: #ffffff;
+ --text-dim: #999;
+}
+
+body {
+ margin: 0; padding: 0;
+ width: 1920px; height: 1080px;
+ background-color: transparent;
+ font-family: var(--font-main);
+ color: var(--text-white);
+ overflow: hidden;
+ user-select: none;
+ outline: none;
+}
+
+#app {
+ position: relative;
+ width: 100%;
+ height: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.top-bar {
+ position: absolute;
+ top: 30px;
+ left: 50%;
+ transform: translateX(-50%);
+ width: 640px;
+ height: 142px;
+ border-radius: 16px;
+ background: var(--bg-dark);
+ display: flex;
+ flex-direction: column;
+ border: 3px solid var(--active-color, var(--mod-nm));
+ transition: border-color 0.5s ease;
+ z-index: 20;
+ box-shadow: 0 15px 40px rgba(0,0,0,0.4);
+ overflow: hidden;
+}
+
+.card-bg {
+ position: absolute; top: 0; left: 0; width: 100%; height: 100%;
+ background-size: cover; background-position: center;
+ filter: blur(8px) brightness(0.4); z-index: 0;
+}
+
+.card-content {
+ position: relative; z-index: 1;
+ display: flex; padding: 12px 15px; gap: 15px; align-items: center;
+ padding-right: 60px;
+ height: 100%;
+ box-sizing: border-box;
+}
+
+.map-thumb {
+ width: 80px; height: 80px; border-radius: 12px;
+ background-size: cover; background-position: center;
+ box-shadow: 0 5px 15px rgba(0,0,0,0.3); background-color: #333; flex-shrink: 0;
+}
+
+.map-details {
+ flex: 1; display: flex; flex-direction: column; justify-content: center; overflow: hidden; gap: 4px;
+ min-width: 0;
+}
+
+.text-info {
+ display: flex; flex-direction: column;
+ width: 100%;
+ overflow: hidden;
+}
+
+.title-row {
+ display: flex;
+ align-items: center;
+ width: 100%;
+ gap: 8px;
+}
+
+.title-overflow-wrap {
+ flex: 0 1 auto;
+ min-width: 0;
+ overflow: hidden;
+ position: relative;
+}
+
+.song-title {
+ font-size: 18px; font-weight: 800; white-space: nowrap;
+ text-shadow: 0 2px 4px rgba(0,0,0,0.5);
+ display: inline-block;
+ transform: translateX(0);
+}
+
+.song-title.scrolling {
+ animation: scrollText 20s linear infinite;
+ padding-right: 0;
+}
+
+@keyframes scrollText {
+ 0% { transform: translateX(0); }
+ 15% { transform: translateX(0); }
+ 45% { transform: translateX(calc(-1 * var(--text-width) - 50px)); opacity: 1; }
+
+ 45.01% { transform: translateX(calc(var(--parent-width) + 50px)); opacity: 0; }
+
+ 50% { opacity: 1; }
+
+ 85% { transform: translateX(0); }
+ 100% { transform: translateX(0); }
+}
+
+.song-artist {
+ font-size: 12px; color: rgba(255,255,255,0.9); font-weight: 600;
+ white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
+}
+
+.status-badge {
+ display: none;
+ width: 32px;
+ height: 20px;
+ border-radius: 10px;
+ border: 1.5px solid transparent;
+ background-color: rgba(0, 0, 0, 0.4);
+ backdrop-filter: blur(4px);
+ background-position: center;
+ background-repeat: no-repeat;
+ background-size: 14px;
+ flex-shrink: 0;
+ box-shadow: 0 2px 5px rgba(0,0,0,0.3);
+ transition: all 0.3s ease;
+}
+
+.status-badge.visible {
+ display: block;
+ animation: fadeIn 0.3s ease-out;
+}
+
+@keyframes fadeIn {
+ from { opacity: 0; transform: scale(0.8); }
+ to { opacity: 1; transform: scale(1); }
+}
+
+.status-ranked {
+ border-color: var(--st-ranked);
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%2376C8FF' d='M12 2l-9.5 9.5 2.5 2.5 7-7 7 7 2.5-2.5L12 2zM12 9l-9.5 9.5 2.5 2.5 7-7 7 7 2.5-2.5L12 9z'/%3E%3C/svg%3E");
+}
+
+.status-loved {
+ border-color: var(--st-loved);
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23ff66aa' d='M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z'/%3E%3C/svg%3E");
+}
+
+.status-qualified, .status-approved {
+ border-color: var(--st-qualified);
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%2366cc66' d='M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z'/%3E%3C/svg%3E");
+}
+
+.status-wip, .status-pending, .status-graveyard {
+ border-color: var(--st-gray);
+ background-image: url('https://i.ppy.sh/7631fe2c5bcbd32c4c2eeb0060302a5bc2bac077/68747470733a2f2f6f73752e7070792e73682f77696b692f696d616765732f7368617265642f7374617475732f70656e64696e672e706e67');
+ filter: grayscale(10%) brightness(1.2);
+ background-size: 10px;
+}
+
+.status-none {
+ border-color: var(--st-none);
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23ff4444' d='M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z'/%3E%3C/svg%3E");
+}
+
+.stats-row {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ margin-top: 2px;
+}
+
+.stats-grid {
+ display: flex; gap: 10px; background: rgba(0,0,0,0.4); padding: 5px 12px; border-radius: 8px; width: fit-content;
+}
+.stat-item { display: flex; flex-direction: column; align-items: center; line-height: 1; }
+.stat-item .label { font-size: 9px; font-weight: 700; color: var(--text-gray); margin-bottom: 2px; text-transform: uppercase; }
+.stat-item .val { font-size: 12px; font-weight: 700; }
+.stat-item.highlight .val { color: var(--accent); }
+
+.pick-bar {
+ position: relative;
+ z-index: 2;
+ width: 100%;
+ height: 38px;
+ background: var(--active-color, var(--mod-nm));
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: #fff;
+ font-weight: 900;
+ font-size: 18px;
+ letter-spacing: 2px;
+ margin-top: auto;
+ padding: 0 20px;
+ box-sizing: border-box;
+ text-shadow: 0 2px 4px rgba(0,0,0,0.6);
+
+ border-radius: 0 0 13px 13px;
+
+ box-shadow: none;
+}
+
+.pick-bar span {
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ max-width: 100%;
+}
+
+.inner-pick-badge {
+ position: absolute;
+ right: 0;
+ top: 0;
+ bottom: 0;
+ width: 0;
+ background: #000;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ writing-mode: vertical-rl;
+ text-orientation: mixed;
+ color: #fff;
+ font-weight: 900;
+ letter-spacing: 3px;
+ font-size: 16px;
+ z-index: 30;
+ transition: width 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+ box-shadow: -5px 0 20px rgba(0,0,0,0.5);
+ overflow: hidden;
+}
+.inner-pick-badge.visible { width: 50px; }
+.inner-pick-badge.red { background: var(--red-team); }
+.inner-pick-badge.blue { background: var(--blue-team); }
+
+.bottom-bar {
+ position: absolute; bottom: 40px; left: 50%; transform: translateX(-50%);
+ display: flex; align-items: center; gap: 15px; width: 100%; justify-content: center; z-index: 10;
+}
+.team {
+ display: flex; align-items: center; background: rgba(20, 20, 20, 0.85);
+ backdrop-filter: blur(10px); padding: 5px 40px; border-radius: 16px;
+ box-shadow: 0 10px 30px rgba(0,0,0,0.2); border: 1px solid rgba(255,255,255,0.05);
+ height: 70px; min-width: 400px; transition: all 0.3s ease;
+}
+.team.leading {
+ background: rgba(40, 40, 40, 0.95); box-shadow: 0 0 25px rgba(255, 255, 255, 0.1);
+ border-color: rgba(255,255,255,0.3); transform: scale(1.02); z-index: 5;
+}
+.team.red { border-bottom: 3px solid var(--red-team); justify-content: flex-end; }
+.team.blue { border-bottom: 3px solid var(--blue-team); justify-content: flex-start; }
+.team.losing { opacity: 0.8; transform: scale(0.98); }
+
+.team-info-left, .team-info-right { display: flex; flex-direction: column; justify-content: center; gap: 4px; }
+.team-info-left { align-items: flex-end; }
+.team-info-right { align-items: flex-start; }
+
+.team-name { font-size: 20px; font-weight: 700; text-transform: uppercase; margin: 0; }
+.team-icon { width: 50px; height: 50px; border-radius: 8px; background-size: cover; background-position: center; box-shadow: 0 4px 10px rgba(0,0,0,0.3); margin: 0 15px; background-color: transparent; }
+
+.score-wrapper { display: flex; flex-direction: column; align-items: center; justify-content: center; min-width: 120px; height: 100%; }
+
+.score { font-size: 38px; font-weight: 800; font-variant-numeric: tabular-nums; line-height: 1; margin-bottom: 0; }
+.red .score { color: var(--red-team); }
+.blue .score { color: var(--blue-team); }
+
+.diff-val {
+ font-size: 14px;
+ font-weight: 700;
+ color: var(--text-gray);
+ height: 0;
+ overflow: hidden;
+ transition: all 0.3s ease;
+ margin-top: 0;
+ opacity: 0;
+}
+.diff-val.visible { height: 16px; opacity: 0.9; margin-top: 2px; }
+
+.vs-marker {
+ font-weight: 800; font-size: 20px; font-style: italic;
+ background: rgba(0, 0, 0, 0.5);
+ backdrop-filter: blur(5px);
+ color: #fff;
+ width: 50px; height: 50px; display: flex; align-items: center; justify-content: center;
+ border-radius: 50%; box-shadow: 0 5px 15px rgba(0,0,0,0.3); flex-shrink: 0;
+}
+.stars { display: flex; gap: 5px; }
+.star-point { width: 22px; height: 10px; background: rgba(255,255,255,0.15); border-radius: 5px; transition: all 0.3s ease; }
+.star-point.active { background: #fff; box-shadow: 0 0 8px white; transform: scale(1.1); }
+
+#mappool-overlay {
+ position: fixed; top: 0; left: 0; width: 100%; height: 100%;
+ background: rgba(5, 5, 5, 0.96); z-index: 100;
+ display: flex; flex-direction: column; align-items: center; justify-content: center;
+ opacity: 0; pointer-events: none; transition: opacity 0.4s ease;
+ padding: 40px 80px; box-sizing: border-box;
+ overflow-y: auto;
+}
+#mappool-overlay.visible { opacity: 1; pointer-events: all; }
+
+.pool-header {
+ font-size: 24px; font-weight: 900; letter-spacing: 4px;
+ background: #fff; color: #000; padding: 5px 20px;
+ border-radius: 12px; margin-bottom: 30px; text-transform: uppercase;
+ flex-shrink: 0;
+}
+
+.pool-grid {
+ display: flex; flex-direction: column; align-items: center;
+ gap: 15px; width: 100%; max-width: 1700px;
+}
+
+.pool-row {
+ display: flex; flex-wrap: wrap; justify-content: center;
+ gap: 15px; width: 100%;
+}
+
+.pool-card {
+ position: relative;
+ width: 440px; height: 75px; background: #111;
+ overflow: hidden; display: flex; align-items: center; cursor: pointer;
+ border: 2px solid rgba(255,255,255,0.05); border-radius: 10px;
+ box-shadow: 0 4px 10px rgba(0,0,0,0.5);
+ transition: transform 0.2s, border-color 0.2s;
+}
+.pool-card:hover { transform: translateY(-3px); border-color: rgba(255,255,255,0.3); }
+
+.pool-card-bg {
+ position: absolute; top: 0; left: 0; width: 100%; height: 100%;
+ background-size: cover; background-position: center; opacity: 0.8; transition: opacity 0.3s;
+}
+.pool-card-gradient {
+ position: absolute; top: 0; left: 0; width: 100%; height: 100%;
+ background: linear-gradient(90deg, rgba(0,0,0,0.95) 0%, rgba(0,0,0,0.85) 60%, rgba(0,0,0,0.2) 100%);
+ z-index: 1;
+}
+
+.pool-card-content {
+ position: relative; z-index: 2; display: flex; justify-content: space-between; align-items: center;
+ width: 100%; height: 100%; padding-left: 20px;
+}
+.song-info-block { display: flex; flex-direction: column; justify-content: center; max-width: 330px; }
+
+.pc-title {
+ font-size: 15px; font-weight: 800; color: #fff; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
+ text-shadow: 0 2px 4px rgba(0,0,0,0.8); line-height: 1.2;
+}
+.pc-artist {
+ font-size: 12px; font-weight: 600; color: #ccc; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-bottom: 3px;
+}
+.pc-mapper { font-size: 11px; color: #888; font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; width: 100%; display: block; }
+.pc-mapper span { color: #aaa; font-weight: 700; margin-right: 5px; }
+
+.mod-tag {
+ height: 100%; width: 60px; display: flex; align-items: center; justify-content: center;
+ font-size: 20px; font-weight: 900; color: #fff;
+ text-shadow: 0 2px 4px rgba(0,0,0,0.5); box-shadow: -5px 0 15px rgba(0,0,0,0.3);
+}
+
+.status-overlay {
+ position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 10;
+ background: rgba(0,0,0,0.7); display: flex; align-items: center; justify-content: center;
+ opacity: 0; transition: 0.3s;
+ font-size: 26px; font-weight: 900; letter-spacing: 3px; text-transform: uppercase;
+ backdrop-filter: blur(2px); border-radius: 10px;
+ pointer-events: none;
+}
+
+.pool-card.picked-red .status-overlay { opacity: 1; background: rgba(255, 94, 94, 0.5); content: "PICK"; }
+.pool-card.picked-red .status-overlay::after { content: "PICK"; color: #fff; }
+.pool-card.picked-red { border-color: var(--red-team); }
+
+.pool-card.picked-blue .status-overlay { opacity: 1; background: rgba(94, 158, 255, 0.5); }
+.pool-card.picked-blue .status-overlay::after { content: "PICK"; color: #fff; }
+.pool-card.picked-blue { border-color: var(--blue-team); }
+
+.pool-card.banned-red .status-overlay { opacity: 1; background: rgba(255, 94, 94, 0.2); }
+.pool-card.banned-red .status-overlay::after { content: "BAN"; color: var(--red-team); text-decoration: line-through; }
+.pool-card.banned-red { opacity: 0.5; }
+
+.pool-card.banned-blue .status-overlay { opacity: 1; background: rgba(94, 158, 255, 0.2); }
+.pool-card.banned-blue .status-overlay::after { content: "BAN"; color: var(--blue-team); text-decoration: line-through; }
+.pool-card.banned-blue { opacity: 0.5; }
+
+.pool-card.protect-red { box-shadow: 0 0 15px var(--red-team); border-color: var(--red-team); }
+.pool-card.protect-red .status-overlay { opacity: 1; background: rgba(0, 0, 0, 0); backdrop-filter: none; }
+.pool-card.protect-red .status-overlay::after { content: "PROTECT"; color: #74c274; text-shadow: 0 0 10px rgba(116, 194, 116, 0.2); }
+
+.pool-card.protect-blue { box-shadow: 0 0 15px var(--blue-team); border-color: var(--blue-team); }
+.pool-card.protect-blue .status-overlay { opacity: 1; background: rgba(0, 0, 0, 0); backdrop-filter: none; }
+.pool-card.protect-blue .status-overlay::after { content: "PROTECT"; color: #74c274; text-shadow: 0 0 10px rgba(116, 194, 116, 0.2); }
+
+.progress-container {
+ margin-top: 6px;
+ width: 100%;
+}
+
+.progress-bar-bg {
+ width: 100%; height: 4px;
+ background: rgba(255,255,255,0.15);
+ border-radius: 2px;
+ overflow: hidden;
+ margin-top: 4px;
+}
+
+.progress-fill {
+ height: 100%; width: 0%;
+ background: var(--text-white);
+ transition: width 0.1s linear;
+ box-shadow: 0 0 10px rgba(255,255,255,0.5);
+}
+
+.chat-overlay {
+ position: absolute;
+ top: -95px;
+ right: 210px;
+ width: 380px;
+ height: 300px;
+ background: rgba(5, 5, 5, 0.95);
+ backdrop-filter: blur(10px);
+ border: 2px solid rgb(53 53 53);
+ border-top: none;
+ border-radius: 0 0 16px 16px;
+ z-index: 200;
+ padding: 10px 15px;
+ box-sizing: border-box;
+ display: flex;
+ flex-direction: column;
+ justify-content: flex-end;
+ box-shadow: 0 5px 20px rgba(0,0,0,0.6);
+ mask-image: linear-gradient(to bottom, transparent 0%, black 10%);
+ -webkit-mask-image: linear-gradient(to bottom, transparent 0%, black 10%);
+ transition: transform 0.6s cubic-bezier(0.22, 1, 0.36, 1), opacity 0.6s ease;
+}
+
+.chat-overlay.hidden {
+ transform: translateY(-120%);
+ opacity: 0;
+}
+
+.chat-messages {
+ display: flex;
+ flex-direction: column;
+ gap: 4px;
+ overflow-y: hidden;
+ justify-content: flex-end;
+}
+
+.chat-irc-line {
+ font-size: 13px;
+ font-weight: 600;
+ line-height: 1.4;
+ color: #fff;
+ text-shadow: 0 1px 2px rgba(0,0,0,0.9);
+ word-wrap: break-word;
+}
+
+.time-stamp {
+ color: #888;
+ font-size: 11px;
+ margin-right: 6px;
+ font-family: monospace;
+}
+
+.user-name {
+ font-weight: 800;
+ margin-right: 4px;
+}
+
+.user-name.team-left { color: var(--red-team); }
+.user-name.team-right { color: var(--blue-team); }
+.user-name.team-unknown { color: var(--text-gray); }
+
+.user-name.role-referee {
+ background-color: #ffd700;
+ color: #000 !important;
+ border-radius: 6px;
+ padding: 0 5px;
+ margin-right: 6px;
+ display: inline-block;
+ vertical-align: middle;
+ line-height: 1.2;
+ font-weight: 800;
+}
+
+.user-name.role-banchobot {
+ background-color: #9d5eff;
+ color: #000 !important;
+ border-radius: 6px;
+ padding: 0 5px;
+ margin-right: 6px;
+ display: inline-block;
+ vertical-align: middle;
+ line-height: 1.2;
+ font-weight: 800;
+}
+
+.msg-content {
+ color: #eee;
+}
+
+.background-layer {
+ position: absolute;
+ top: 0; left: 0; width: 100%; height: 100%;
+ background: radial-gradient(circle at 30% 50%, rgba(80, 0, 0, 0.4), transparent 70%);
+ z-index: 0;
+}
+
+.hidden {
+ opacity: 0;
+ pointer-events: none;
+ transform: translateY(20px);
+ transition: all 0.5s ease;
+}
+
+#winner-container {
+ display: flex;
+ width: 1600px;
+ height: 800px;
+ z-index: 1;
+ opacity: 1;
+ transform: translateY(0);
+ transition: all 0.6s cubic-bezier(0.16, 1, 0.3, 1);
+}
+
+.left-panel {
+ flex: 1;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ position: relative;
+}
+
+.avatar-ring {
+ position: relative;
+ width: 450px;
+ height: 450px;
+ border-radius: 50%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.avatar-glow {
+ position: absolute;
+ width: 100%; height: 100%;
+ border-radius: 50%;
+ border: 10px solid var(--red-team);
+ box-shadow: 0 0 50px var(--red-team), inset 0 0 30px var(--red-team);
+ animation: rotateGlow 10s linear infinite;
+ opacity: 0.8;
+}
+
+.winner-blue .avatar-glow {
+ border-color: var(--blue-team);
+ box-shadow: 0 0 50px var(--blue-team), inset 0 0 30px var(--blue-team);
+}
+
+.team-logo {
+ width: 380px;
+ height: 380px;
+ border-radius: 50%;
+ background-size: cover;
+ background-position: center;
+ background-color: #000;
+ z-index: 2;
+ border: none;
+}
+
+.right-panel {
+ flex: 1.2;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ padding-left: 50px;
+}
+
+.top-meta {
+ display: none;
+}
+
+.winner-title {
+ font-size: 130px;
+ font-weight: 900;
+ line-height: 1;
+ letter-spacing: 4px;
+ margin-bottom: 40px;
+ text-transform: uppercase;
+ text-shadow: 0 5px 15px rgba(0,0,0,0.5);
+}
+
+.team-info-block {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 5px;
+ margin-bottom: 40px;
+}
+
+.team-label {
+ background: var(--red-team);
+ padding: 5px 15px;
+ font-size: 20px;
+ font-weight: 800;
+ text-transform: uppercase;
+ letter-spacing: 1px;
+}
+
+.winner-blue .team-label { background: var(--blue-team); }
+
+.team-name-box {
+ background: #fff;
+ color: #000;
+ padding: 10px 30px;
+ font-size: 60px;
+ font-weight: 800;
+ box-shadow: 0 10px 30px rgba(0,0,0,0.3);
+ min-width: 300px;
+}
+
+.players-grid {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+ margin-top: 10px;
+}
+
+.player-item {
+ font-size: 24px;
+ font-weight: 500;
+ color: #eee;
+ display: flex;
+ align-items: center;
+ gap: 15px;
+ text-shadow: -2px 2px 0px rgba(0,0,0,1);
+}
+
+.player-flag {
+ width: auto;
+ height: 25px;
+ border-radius: 3px;
+ box-shadow: 0 2px 4px rgba(0,0,0,0.3);
+ flex-shrink: 0;
+}
+
+@keyframes rotateGlow {
+ 0% { transform: rotate(0deg) scale(1); }
+ 50% { transform: rotate(180deg) scale(1.02); }
+ 100% { transform: rotate(360deg) scale(1); }
+}
+
+.seed-hidden { display: none !important; }
+
+.click-zone { position: absolute; top: 0; bottom: 0; width: 30%; z-index: 99999; cursor: pointer; pointer-events: auto; }
+.zone-left { left: 0; }
+.zone-right { right: 0; }
+
+@keyframes slideIn {
+ from { opacity: 0; transform: translateX(50px); }
+ to { opacity: 1; transform: translateX(0); }
+}
+
+.slide-container {
+ display: flex; width: 100%; height: 100%;
+ padding: 60px; box-sizing: border-box; gap: 40px;
+ animation: slideIn 0.5s cubic-bezier(0.16, 1, 0.3, 1);
+ font-family: var(--font-seed);
+}
+
+.left-panel-seed {
+ width: 450px; height: 100%;
+ display: flex; flex-direction: column; justify-content: center;
+ border-right: 1px solid rgba(255,255,255,0.1); padding-right: 30px;
+}
+.left-content-wrapper { display: flex; flex-direction: column; gap: 30px; }
+
+.seed-header { border-left: 6px solid transparent; padding-left: 20px; }
+.seed-label { display: block; font-size: 1.2rem; font-weight: 700; letter-spacing: 4px; color: var(--text-dim); margin-bottom: -5px; }
+#teamSeed { font-size: 8rem; font-weight: 800; line-height: 0.9; color: #fff; }
+.seed-gold { border-left-color: #ffd700; } .seed-gold #teamSeed { color: #ffd700; text-shadow: 0 0 40px rgba(255, 215, 0, 0.4); }
+.seed-silver { border-left-color: #e0e0e0; } .seed-silver #teamSeed { color: #e0e0e0; text-shadow: 0 0 40px rgba(255, 255, 255, 0.4); }
+.seed-bronze { border-left-color: #cd7f32; } .seed-bronze #teamSeed { color: #cd7f32; text-shadow: 0 0 40px rgba(205, 127, 50, 0.4); }
+
+.team-block { display: flex; flex-direction: column; align-items: flex-start; }
+.team-avatar {
+ height: 100px; width: 100px; object-fit: cover;
+ border-radius: 16px; margin-bottom: 20px;
+ box-shadow: 0 5px 20px rgba(0,0,0,0.6);
+ background: #222; transition: opacity 0.3s;
+}
+.team-info-wrapper { display: flex; flex-direction: column; }
+.name-flag-row { display: flex; align-items: center; gap: 15px; flex-wrap: wrap; }
+.team-fullname { font-size: 3rem; color: #fff; font-weight: 800; text-transform: uppercase; line-height: 1; margin-bottom: 2px; word-break: break-word; }
+.team-flag { height: 35px; border-radius: 4px; box-shadow: 0 2px 8px rgba(0,0,0,0.5); margin-top: 4px; }
+.team-acronym { font-size: 1.4rem; font-weight: 600; color: var(--text-dim); letter-spacing: 2px; margin-top: 5px; }
+
+.roster-block { display: none; margin-top: 10px; }
+.roster-list { display: flex; flex-direction: row; flex-wrap: wrap; gap: 20px; align-items: flex-start; }
+
+.player-card { display: flex; flex-direction: column; align-items: center; gap: 8px; width: 90px; text-align: center; }
+.p-avatar {
+ width: 64px; height: 64px; border-radius: 12px;
+ object-fit: cover; border: 2px solid rgba(255,255,255,0.15);
+ background: #1a1a1a; box-shadow: 0 4px 8px rgba(0,0,0,0.5);
+}
+.p-info { display: flex; align-items: center; justify-content: center; gap: 6px; width: 100%; }
+.p-name { font-size: 0.9rem; font-weight: 700; color: #eee; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 65px; }
+.p-flag { width: 18px; border-radius: 2px; box-shadow: 0 1px 3px rgba(0,0,0,0.5); display: block; }
+
+.rank-block { display: none; margin-top: auto; }
+.stat-label { font-size: 0.9rem; color: var(--text-dim); letter-spacing: 2px; font-weight: 700; text-transform: uppercase; margin-bottom: 5px; }
+.stat-value { font-size: 2.5rem; font-weight: 700; display: block; }
+
+.right-panel-seed { flex: 1; display: flex; align-items: center; justify-content: center; height: 100%; }
+.mods-container { display: flex; flex-direction: row; gap: 20px; flex-wrap: wrap; align-items: flex-start; justify-content: center; align-content: center; width: 100%; max-height: 98vh; }
+.mod-column {
+ display: flex; flex-direction: column; gap: 10px; width: 270px;
+ background: rgba(0, 0, 0, 0.4); backdrop-filter: blur(10px);
+ padding: 12px; border-radius: 12px; border: 1px solid rgba(255,255,255,0.05);
+}
+.mod-header { font-size: 1.4rem; font-weight: 900; padding-left: 10px; border-left: 4px solid #fff; line-height: 1; text-transform: uppercase; margin-bottom: 5px; opacity: 0.9; }
+
+.map-card {
+ height: 95px; background: #151515; border-radius: 8px; position: relative; overflow: hidden;
+ border: 1px solid rgba(255,255,255,0.1); display: flex; flex-direction: column;
+ box-shadow: 0 4px 8px rgba(0,0,0,0.4);
+}
+.map-bg { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-size: cover; background-position: center; opacity: 0.3; }
+.map-bg-fallback { position: absolute; top: 0; left: 0; width: 100%; height: 100%; opacity: 0.15; }
+.map-content { position: relative; z-index: 2; padding: 6px 10px; height: 100%; display: flex; flex-direction: column; justify-content: space-between; }
+.map-top { display: flex; justify-content: space-between; align-items: flex-start; gap: 8px; }
+.pool-id { font-size: 1.1rem; font-weight: 900; font-style: italic; line-height: 1; margin-right: 5px; }
+
+.map-info { display: flex; flex-direction: column; overflow: hidden; width: 100%; }
+.marquee-container {
+ width: 100%; overflow: hidden; white-space: nowrap; position: relative;
+}
+.song-title-seed { font-size: 0.8rem; font-weight: 700; color: #fff; display: inline-block; white-space: nowrap; }
+
+.song-title-seed.scroll {
+ animation: scroll-text 10s linear infinite;
+ padding-right: 20px;
+}
+
+@keyframes scroll-text {
+ 0%, 15% { transform: translateX(0); }
+ 70% { transform: translateX(calc(-100% + 220px)); }
+ 85% { transform: translateX(calc(-100% + 220px)); }
+ 100% { transform: translateX(0); }
+}
+
+.map-mapper { font-size: 0.65rem; color: #ccc; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-top: 1px; }
+.map-bot { display: flex; justify-content: space-between; align-items: flex-end; }
+.map-rank { font-size: 1.2rem; font-weight: 800; }
+.rank-gold { color: #ffd700; text-shadow: 0 0 5px rgba(255,215,0,0.5); }
+.rank-silver { color: #e0e0e0; text-shadow: 0 0 5px rgba(255,255,255,0.5); }
+.rank-bronze { color: #cd7f32; text-shadow: 0 0 5px rgba(205,127,50,0.5); }
+.map-score { font-size: 1.2rem; font-weight: 700; line-height: 1; }
+
+.showcase-mode {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background-color: transparent;
+ width: 1920px;
+ height: 1080px;
+ margin: 0;
+}
+
+.showcase-mode .top-bar {
+ position: relative;
+ top: auto;
+ left: auto;
+ transform: scale(1.3);
+ margin: 0;
+ border-radius: 9px; !important
+ border: 3px solid var(--active-color, var(--mod-nm)); !important
+ box-shadow: 0 10px 30px rgba(0,0,0,0.5);
+ overflow: visible;
+}
+
+.replay-row {
+ display: flex;
+ align-items: baseline;
+ gap: 6px;
+ margin-bottom: 2px;
+ border-bottom: 1px solid rgba(255, 255, 255, 0.1);
+ padding-bottom: 2px;
+}
+
+.replay-prefix {
+ font-size: 10px;
+ font-weight: 700;
+ color: #999;
+ text-transform: uppercase;
+}
+
+.replay-name-wrapper {
+ flex-grow: 1;
+ overflow: hidden;
+ height: 20px;
+ display: flex;
+ align-items: center;
+}
+
+.replay-name {
+ font-family: var(--font-main);
+ font-size: 16px;
+ font-weight: 700;
+ color: var(--text-white);
+ white-space: nowrap;
+ text-shadow: 0 1px 2px rgba(0,0,0,0.5);
+ transform-origin: left center;
+ transition: opacity 0.3s ease;
+}
+.replay-name.hidden { opacity: 0; }
\ No newline at end of file
diff --git a/counters/mitour by antoshika/winner.html b/counters/mitour by antoshika/winner.html
new file mode 100644
index 00000000..e55c9550
--- /dev/null
+++ b/counters/mitour by antoshika/winner.html
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
WINNER
+
+
+
TEAM RED
+
+ TEAM NAME
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file