Files
SREBOT/web/views/index.ejs
T
FURRO404 2b399fdb81 add SREBOT, SHARED, TSSBOT contents (fixup for #1223)
PR #1223 only staged the deletions of the old paths because the new
top-level directories were still untracked when the commit was authored.
This commit adds the actual restructured tree: SREBOT/ (existing bot),
SHARED/ (vromfs, data_parser, ICONS/MAPS/FONTS, DAGOR_FILES,
update_game_files), and TSSBOT/ (skeleton).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 23:17:02 -07:00

651 lines
30 KiB
Plaintext

<!DOCTYPE html>
<html lang="<%= lang %>">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
<title>
<%= botName %>
</title>
<meta name="description" content="<%= botName %> - The Best Squadron Battles Bot.">
<link rel="icon" type="image/png" href="/images/transparent_toothlessssss.png">
<!-- Preload Critical Resources -->
<link rel="preload" href="/Fonts/symbols_skyquake.ttf" as="font" type="font/ttf" crossorigin="anonymous">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<!-- Optimized Font Loading -->
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<link rel="stylesheet" href="/css/output.css">
<!-- Defer non-critical CSS -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"
media="print" onload="this.media='all'">
<style>
@font-face {
font-family: 'skyquakesymbols';
src: url('/Fonts/symbols_skyquake.ttf');
font-display: swap;
}
/* Performance-optimized base styles */
* {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
}
body {
min-height: 100vh;
}
/* Remove individual section backgrounds - let body gradient show through */
.hero-bg {
background: transparent;
}
.hero-overlay {
background: transparent;
}
/* Optimized gradient text */
.gradient-text {
background: linear-gradient(135deg, #F5F5DC 0%, #E8E8D0 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
/* Enhanced Card styles */
.feature-card {
background: linear-gradient(135deg, rgba(62, 78, 62, 0.2) 0%, rgba(44, 44, 44, 0.2) 100%);
border: 1px solid rgba(245, 245, 220, 0.08);
backdrop-filter: blur(12px);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.card-hover:hover {
transform: translateY(-3px);
background: linear-gradient(135deg, rgba(62, 78, 62, 0.3) 0%, rgba(44, 44, 44, 0.3) 100%);
border-color: rgba(144, 238, 144, 0.3);
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.3);
}
.card-hover:hover i {
color: #F5F5DC;
/* Icon turns cream on hover */
transform: scale(1.1);
transition: transform 0.3s ease;
}
/* Premium Button Glow */
.btn-primary {
background: linear-gradient(135deg, #F5F5DC 0%, #E8E8D0 100%);
box-shadow: 0 4px 20px rgba(245, 245, 220, 0.15), inset 0 1px 0 rgba(255, 255, 255, 0.4);
color: #1E1E1E;
font-weight: 700;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
position: relative;
overflow: hidden;
}
.btn-primary:hover {
box-shadow: 0 8px 25px rgba(245, 245, 220, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.4);
transform: translateY(-2px);
}
.btn-primary:active {
transform: translateY(0);
}
/* Search Input Polish */
.search-input-glass {
background: rgba(30, 30, 30, 0.6);
border: 1px solid rgba(245, 245, 220, 0.1);
backdrop-filter: blur(10px);
transition: all 0.3s ease;
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.2);
}
.search-input-glass:focus {
background: rgba(40, 40, 40, 0.8);
border-color: rgba(144, 238, 144, 0.4);
box-shadow: 0 0 0 2px rgba(144, 238, 144, 0.1), inset 0 2px 4px rgba(0, 0, 0, 0.2);
}
/* Trusted by animation - GPU accelerated */
@keyframes scroll {
0% {
transform: translate3d(0, 0, 0);
}
100% {
transform: translate3d(-50%, 0, 0);
}
}
.animate-scroll {
animation: scroll 60s linear infinite;
will-change: transform;
}
.trusted-scroll {
mask-image: linear-gradient(90deg, transparent, black 10%, black 90%, transparent);
-webkit-mask-image: linear-gradient(90deg, transparent, black 10%, black 90%, transparent);
}
/* Utility classes */
.text-accent {
color: #F5F5DC;
}
.text-muted {
color: #90EE90;
}
/* Reduce animations on low-end devices */
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
/* Unified Search Bar */
.search-bar {
background: rgba(28, 28, 28, 0.6);
border: 1px solid rgba(144, 238, 144, 0.06);
border-radius: 16px;
backdrop-filter: blur(20px);
transition: border-color 0.3s ease;
}
.search-bar:focus-within {
border-color: rgba(144, 238, 144, 0.18);
}
.search-drop {
position: absolute;
left: -4px;
right: -4px;
top: calc(100% + 8px);
border-radius: 12px;
max-height: 260px;
overflow-y: auto;
z-index: 999;
background: rgba(20, 20, 20, 0.98);
border: 1px solid rgba(144, 238, 144, 0.1);
backdrop-filter: blur(24px);
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5);
}
.search-drop::-webkit-scrollbar { width: 4px; }
.search-drop::-webkit-scrollbar-thumb { background: rgba(144, 238, 144, 0.15); border-radius: 4px; }
.search-hit {
display: block;
color: inherit;
text-decoration: none;
padding: 10px 16px;
cursor: pointer;
transition: background 0.15s;
border-bottom: 1px solid rgba(255, 255, 255, 0.03);
}
.search-hit:last-child { border-bottom: none; }
.search-hit:hover { background: rgba(144, 238, 144, 0.05); }
.sq-active { color: #90EE90 !important; font-family: 'skyquakesymbols', 'Inter', sans-serif; }
#squadronInput::placeholder, #playerInput::placeholder { color: rgba(255,255,255,0.35); }
#squadronInput:focus, #playerInput:focus { outline: none; }
</style>
</head>
<body class="text-white antialiased">
<%- include('partials/nav', { activePage: 'home' }) %>
<!-- Hero Section - Balanced Spacing -->
<section class="hero-bg pt-32 pb-16 lg:pt-40 lg:pb-20 relative">
<div class="hero-overlay absolute inset-0 pointer-events-none"></div>
<div class="max-w-[1400px] mx-auto px-6 lg:px-8 relative z-10">
<!-- Top Row: Title and CTA -->
<div class="text-center">
<!-- Heading -->
<h1 class="text-3xl sm:text-4xl lg:text-5xl xl:text-6xl font-bold leading-[1.1] tracking-tight">
<span class="gradient-text"><%= t('home.squadronBattles') %></span><br>
<span class="text-muted"><%= t('home.madeSimple') %></span>
</h1>
<!-- CTA Buttons -->
<div class="flex flex-col sm:flex-row items-center justify-center gap-4" style="margin-top: 3rem;">
<a href="#" class="btn-primary px-6 py-2.5 rounded-lg text-sm font-bold inline-flex items-center"
id="ctaInviteBtn">
<i class="fab fa-discord text-base mr-2"></i>
<%= t('home.addToDiscord') %>
</a>
<a href="/docs"
class="px-6 py-2.5 rounded-lg border text-accent font-semibold text-sm inline-flex items-center transition-colors hover:bg-white/5 bg-[rgba(168,230,207,0.06)] border-[rgba(168,230,207,0.2)]">
<i class="fas fa-book mr-2"></i>
<%= t('home.learnMore') %>
</a>
</div>
</div>
<!-- Search Section -->
<div class="max-w-[800px] mx-auto relative" style="margin-top: 5rem; margin-bottom: 4rem; z-index: 100;">
<div class="search-bar flex p-3" id="searchBar">
<div class="flex-1 px-4 py-3 relative">
<div class="text-[10px] font-bold tracking-[0.2em] uppercase mb-2" style="color: rgba(144,238,144,0.35)"><%= t('home.searchBySquadron') %></div>
<div class="flex items-center">
<input type="text" id="squadronInput"
style="flex:1; background:transparent; border:none; outline:none; color:#fff; font-size:14px; font-weight:500; padding:0;"
placeholder="<%= t('home.typeSquadronName') %>" autocomplete="off">
<button id="squadronClear" class="hidden" style="background:none; border:none; color:rgba(255,255,255,0.2); cursor:pointer; font-size:11px; padding:4px 8px; transition:color 0.2s;">
<i class="fas fa-times"></i>
</button>
</div>
<div id="squadronDropdown" class="search-drop hidden"></div>
</div>
<div class="self-stretch my-3" style="width: 1px; background: rgba(144,238,144,0.06)"></div>
<div class="flex-1 px-4 py-3 relative">
<div class="text-[10px] font-bold tracking-[0.2em] uppercase mb-2" style="color: rgba(144,238,144,0.35)"><%= t('home.orByPlayer') %></div>
<div class="flex items-center">
<input type="text" id="playerInput"
style="flex:1; background:transparent; border:none; outline:none; color:#fff; font-size:14px; font-weight:500; padding:0;"
placeholder="<%= t('home.typePlayerName') %>" autocomplete="off">
</div>
<div id="playerDropdown" class="search-drop hidden"></div>
</div>
</div>
</div>
<!-- Feature Cards Grid -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6" style="gap: 1.5rem;">
<!-- Feature Cards - Compact -->
<a href="/games" class="feature-card card-hover rounded-lg p-4 block">
<div class="flex items-center gap-3">
<div
class="w-10 h-10 rounded-lg flex items-center justify-center bg-[rgba(168,230,207,0.1)] border border-[rgba(168,230,207,0.2)] flex-shrink-0">
<i class="fas fa-broadcast-tower text-accent"></i>
</div>
<div>
<h3 class="text-base font-semibold text-accent leading-tight"><%= t('home.liveFeed') %></h3>
<p class="text-xs text-muted leading-tight mt-0.5"><%= t('home.realTimeMatches') %></p>
</div>
</div>
</a>
<a href="/leaderboard/players" class="feature-card card-hover rounded-lg p-4 block">
<div class="flex items-center gap-3">
<div
class="w-10 h-10 rounded-lg flex items-center justify-center bg-[rgba(168,230,207,0.1)] border border-[rgba(168,230,207,0.2)] flex-shrink-0">
<i class="fas fa-trophy text-accent"></i>
</div>
<div>
<h3 class="text-base font-semibold text-accent leading-tight"><%= t('nav.leaderboards') %></h3>
<p class="text-xs text-muted leading-tight mt-0.5"><%= t('home.topPlayers') %></p>
</div>
</div>
</a>
<a href="/leaderboard/vehicles" class="feature-card card-hover rounded-lg p-4 block">
<div class="flex items-center gap-3">
<div
class="w-10 h-10 rounded-lg flex items-center justify-center bg-[rgba(168,230,207,0.1)] border border-[rgba(168,230,207,0.2)] flex-shrink-0">
<i class="fas fa-fighter-jet text-accent"></i>
</div>
<div>
<h3 class="text-base font-semibold text-accent leading-tight"><%= t('home.vehicleStatsCard') %></h3>
<p class="text-xs text-muted leading-tight mt-0.5"><%= t('home.performanceMetrics') %></p>
</div>
</div>
</a>
<a href="/analytics" class="feature-card card-hover rounded-lg p-4 block">
<div class="flex items-center gap-3">
<div
class="w-10 h-10 rounded-lg flex items-center justify-center bg-[rgba(168,230,207,0.1)] border border-[rgba(168,230,207,0.2)] flex-shrink-0">
<i class="fas fa-chart-bar text-accent"></i>
</div>
<div>
<h3 class="text-base font-semibold text-accent leading-tight"><%= t('home.analyticsCard') %></h3>
<p class="text-xs text-muted leading-tight mt-0.5"><%= t('home.globalStatistics') %></p>
</div>
</div>
</a>
<a href="/squadrons" class="feature-card card-hover rounded-lg p-4 block">
<div class="flex items-center gap-3">
<div
class="w-10 h-10 rounded-lg flex items-center justify-center bg-[rgba(168,230,207,0.1)] border border-[rgba(168,230,207,0.2)] flex-shrink-0">
<i class="fas fa-users text-accent"></i>
</div>
<div>
<h3 class="text-base font-semibold text-accent leading-tight"><%= t('home.squadronHubCard') %></h3>
<p class="text-xs text-muted leading-tight mt-0.5"><%= t('home.squadronStats') %></p>
</div>
</div>
</a>
<a href="/leaderboard/comparison" class="feature-card card-hover rounded-lg p-4 block">
<div class="flex items-center gap-3">
<div
class="w-10 h-10 rounded-lg flex items-center justify-center bg-[rgba(168,230,207,0.1)] border border-[rgba(168,230,207,0.2)] flex-shrink-0">
<i class="fas fa-balance-scale text-accent"></i>
</div>
<div>
<h3 class="text-base font-semibold text-accent leading-tight"><%= t('home.comparisonCard') %></h3>
<p class="text-xs text-muted leading-tight mt-0.5"><%= t('home.compareStats') %></p>
</div>
</div>
</a>
</div>
</div>
</section>
<!-- CTA Section -->
<section class="py-16 lg:py-20 relative overflow-hidden">
<div class="max-w-[1400px] mx-auto px-6 lg:px-8 relative z-10">
<div class="text-center max-w-3xl mx-auto">
<h2 class="text-3xl lg:text-4xl font-bold mb-4 text-accent" id="random-squadron-cta">Meow</h2>
<p class="text-lg text-muted mb-8"><%= t('home.joinServers') %></p>
<a href="#" class="btn-primary px-10 py-4 rounded-xl text-lg inline-flex items-center font-bold"
id="ctaInviteBtn2">
<i class="fab fa-discord text-2xl mr-3"></i>
<%= t('home.addToDiscord') %>
</a>
</div>
</div>
</section>
<!-- Footer -->
<%- include('partials/footer') %>
<script>
window.__lang = '<%= lang %>';
window.__i18n = <%- localeJson %>;
window.__t = function(key) {
var parts = key.split('.'), obj = window.__i18n;
for (var i = 0; i < parts.length; i++) { obj = obj && obj[parts[i]]; }
return obj !== undefined ? obj : key;
};
window.switchLanguage = function(lang) {
var next = lang || (document.documentElement.lang === 'en' ? 'ru' : 'en');
if (next === document.documentElement.lang) return;
document.cookie = 'lang=' + next + ';path=/;max-age=31536000;SameSite=Lax';
window.location.reload();
};
</script>
<script src="/js/main.js?v=3"></script>
<script src="/js/api-client.js"></script>
<script>
let playersData = [];
let allSquadrons = [];
let selectedSquadron = null;
let selectedSquadronClanId = null;
let selectedSquadronShort = null;
let searchTimeout, squadronTimeout;
let playersState = 'unloaded'; // unloaded → loading → ready | error
let squadronsState = 'unloaded';
const escapeHtml = (t) => { const d = document.createElement('div'); d.textContent = t; return d.innerHTML; };
const loadSquadronData = async () => {
squadronsState = 'loading';
try {
const response = await window.apiClient.getSquadronLeaderboard();
allSquadrons = (response.squadrons || []).map(s => ({
name: s.long_name || s.tag_name || s.squadron_name,
tag_name: s.tag_name,
short_name: s.short_name || s.tag_name,
clan_id: s.clan_id,
player_count: s.player_count || 0
}));
squadronsState = 'ready';
} catch (e) {
console.error('Error loading squadron data:', e);
squadronsState = 'error';
}
};
const loadPlayerData = async () => {
if (playersState === 'ready' || playersState === 'loading') return;
playersState = 'loading';
try {
const response = await window.apiClient.getPlayerLeaderboard();
playersData = (response.players || []).map(p => ({
...p,
total_kills: p.total_kills || ((p.ground_kills || 0) + (p.air_kills || 0)),
})).sort((a, b) => b.total_kills - a.total_kills);
playersState = 'ready';
if (!plDrop.classList.contains('hidden')) {
renderPlayers(plInput.value.trim().toLowerCase());
}
} catch (e) {
console.error('Error loading player data:', e);
playersState = 'error';
}
};
const sqInput = document.getElementById('squadronInput');
const plInput = document.getElementById('playerInput');
const sqDrop = document.getElementById('squadronDropdown');
const plDrop = document.getElementById('playerDropdown');
const sqClear = document.getElementById('squadronClear');
// --- Squadron search ---
sqInput.addEventListener('input', () => {
clearTimeout(squadronTimeout);
if (selectedSquadron) {
selectedSquadron = null;
selectedSquadronClanId = null;
selectedSquadronShort = null;
sqInput.classList.remove('sq-active');
sqClear.classList.add('hidden');
plInput.placeholder = __t('home.typePlayerName');
}
const val = sqInput.value.trim().toLowerCase();
if (val.length < 1) { sqDrop.classList.add('hidden'); return; }
if (squadronsState !== 'ready') {
sqDrop.innerHTML = '<div class="p-3 text-center text-xs" style="color:rgba(144,238,144,0.25)">' + __t('common.loading') + '</div>';
sqDrop.classList.remove('hidden');
return;
}
squadronTimeout = setTimeout(() => {
const hits = allSquadrons.filter(s => {
const names = [s.name, s.tag_name, s.short_name].filter(Boolean).map(n => n.toLowerCase());
return names.some(n => n.includes(val));
}).slice(0, 12);
if (!hits.length) {
sqDrop.innerHTML = '<div class="p-3 text-center text-xs" style="color:rgba(144,238,144,0.25)">' + __t('home.noSquadronsFound') + '</div>';
} else {
sqDrop.innerHTML = hits.map(s =>
`<div class="search-hit" data-name="${escapeHtml(s.tag_name || s.name)}" data-short="${escapeHtml(s.short_name)}" data-clanid="${s.clan_id != null ? s.clan_id : ''}">
<span class="font-['skyquakesymbols'] text-sm" style="color:#A8E6CF">${escapeHtml(s.name)}</span>
<span class="text-[11px] ml-2" style="color:rgba(144,238,144,0.25)">${s.player_count} ${__t('common.playersCount')}</span>
</div>`
).join('');
sqDrop.querySelectorAll('.search-hit').forEach(el =>
el.addEventListener('click', () => pickSquadron(el.dataset.name, el.dataset.short, el.dataset.clanid))
);
}
sqDrop.classList.remove('hidden');
}, 100);
});
sqInput.addEventListener('keydown', (e) => {
if (e.key === 'Tab') {
const val = sqInput.value.trim().toLowerCase();
if (!selectedSquadron && val.length >= 1) {
const hits = allSquadrons.filter(s => {
const names = [s.name, s.tag_name, s.short_name].filter(Boolean).map(n => n.toLowerCase());
return names.some(n => n.includes(val));
});
if (hits.length >= 1) {
e.preventDefault();
pickSquadron(hits[0].tag_name || hits[0].name, hits[0].short_name, hits[0].clan_id);
}
}
}
if (e.key === 'Enter') {
e.preventDefault();
if (selectedSquadronClanId != null) {
window.location.href = '/squadrons/' + selectedSquadronClanId;
} else if (selectedSquadronShort) {
window.location.href = '/squadrons/' + encodeURIComponent(selectedSquadronShort);
} else {
const val = sqInput.value.trim().toLowerCase();
const match = allSquadrons.find(s => {
const names = [s.name, s.tag_name, s.short_name].filter(Boolean).map(n => n.toLowerCase());
return names.some(n => n === val);
});
if (match) {
const path = match.clan_id != null ? String(match.clan_id) : encodeURIComponent(match.short_name || match.name);
window.location.href = '/squadrons/' + path;
}
}
}
if (e.key === 'Escape') { sqDrop.classList.add('hidden'); sqInput.blur(); }
});
function pickSquadron(tagName, shortName, clanId) {
selectedSquadron = tagName;
selectedSquadronClanId = clanId != null && clanId !== '' ? Number(clanId) : null;
selectedSquadronShort = shortName || tagName;
sqInput.value = tagName;
sqInput.classList.add('sq-active');
sqClear.classList.remove('hidden');
sqDrop.classList.add('hidden');
plInput.placeholder = __t('home.searchPlayersIn') + ' ' + (tagName || '') + '...';
plInput.focus();
}
sqClear.addEventListener('click', () => {
selectedSquadron = null;
selectedSquadronClanId = null;
selectedSquadronShort = null;
sqInput.value = '';
sqInput.classList.remove('sq-active');
sqClear.classList.add('hidden');
plInput.placeholder = __t('home.typePlayerName');
plDrop.classList.add('hidden');
sqInput.focus();
});
// --- Player search ---
function renderPlayers(val) {
if (playersState === 'loading') {
plDrop.innerHTML = '<div class="p-3 text-center text-xs" style="color:rgba(144,238,144,0.25)"><i class="fas fa-spinner fa-spin mr-1"></i>' + __t('common.loading') + '</div>';
plDrop.classList.remove('hidden');
return;
}
if (playersState === 'error') {
plDrop.innerHTML = '<div class="p-3 text-center text-xs" style="color:rgba(255,80,80,0.5)">Failed to load. <button onclick="playersState=\'unloaded\';loadPlayerData()" style="text-decoration:underline;background:none;border:none;color:rgba(144,238,144,0.5);cursor:pointer">' + __t('common.retry') + '</button></div>';
plDrop.classList.remove('hidden');
return;
}
let src = playersData;
if (selectedSquadronClanId != null) {
src = src.filter(p => p.squadron_clan_id === selectedSquadronClanId);
} else if (selectedSquadron) {
src = src.filter(p => (p.squadron_name || '').toLowerCase() === selectedSquadron.toLowerCase());
}
const hits = val.length >= 2
? src.filter(p => p.nick.toLowerCase().includes(val))
: (selectedSquadron ? src : []);
const results = hits.slice(0, 20);
if (!results.length && (val.length >= 2 || selectedSquadron)) {
plDrop.innerHTML = '<div class="p-3 text-center text-xs" style="color:rgba(144,238,144,0.25)">' + __t('home.noPlayersFound') + '</div>';
} else if (!results.length) {
plDrop.classList.add('hidden'); return;
} else {
plDrop.innerHTML = results.map(p => {
const tag = (!selectedSquadron && p.squadron_name)
? `<span class="font-['skyquakesymbols'] text-[11px] mr-1.5" style="color:rgba(144,238,144,0.25)">${escapeHtml(p.squadron_name)}</span>` : '';
return `<a href="/players/${p.uid}" class="search-hit">${tag}<span class="text-sm font-medium" style="color:#A8E6CF">${escapeHtml(p.nick)}</span></a>`;
}).join('');
}
plDrop.classList.remove('hidden');
}
plInput.addEventListener('input', () => {
clearTimeout(searchTimeout);
const val = plInput.value.trim().toLowerCase();
if (val.length < 2 && !selectedSquadron) { plDrop.classList.add('hidden'); return; }
if (playersState !== 'ready') {
loadPlayerData();
renderPlayers(val);
return;
}
searchTimeout = setTimeout(() => renderPlayers(val), 100);
});
plInput.addEventListener('focus', () => {
if (playersState !== 'ready') {
loadPlayerData();
}
if (selectedSquadron && plInput.value.trim() === '') {
if (playersState === 'ready') {
renderPlayers('');
} else {
renderPlayers('');
}
}
});
plInput.addEventListener('keydown', (e) => {
if (e.key === 'Enter' && selectedSquadron && plInput.value.trim() === '') {
e.preventDefault();
if (selectedSquadronClanId != null) {
window.location.href = '/squadrons/' + selectedSquadronClanId;
} else {
window.location.href = '/squadrons/' + encodeURIComponent(selectedSquadronShort);
}
}
if (e.key === 'Escape') { plDrop.classList.add('hidden'); plInput.blur(); }
});
// Close dropdowns on outside click
document.addEventListener('click', (e) => {
if (!e.target.closest('#searchBar')) { sqDrop.classList.add('hidden'); plDrop.classList.add('hidden'); }
});
// --- Mobile menu ---
document.getElementById('mobileMenuBtn').addEventListener('click', () => {
document.getElementById('mobileMenu').classList.toggle('hidden');
});
// --- Random CTA ---
const ctaPhrases = [__t('home.ctaElev8'), __t('home.ctaReign'), __t('home.ctaMeow'), __t('home.ctaPurr'), __t('home.ctaRawr')];
function setRandomCTA() {
const el = document.getElementById('random-squadron-cta');
if (el) el.textContent = ctaPhrases[Math.floor(Math.random() * ctaPhrases.length)];
}
// --- Subtitle cycling ---
const subtitles = [__t('index.subtitle1'), __t('index.subtitle2'), __t('index.subtitle3'), __t('index.subtitle4')];
let subIdx = 0;
const cycleSubtitle = () => {
const el = document.getElementById('cycling-subtitle');
if (el) { el.style.opacity = '0.5'; setTimeout(() => { subIdx = (subIdx + 1) % subtitles.length; el.textContent = subtitles[subIdx]; el.style.opacity = '1'; }, 300); }
};
// --- Init ---
document.addEventListener('DOMContentLoaded', () => {
setRandomCTA();
loadSquadronData();
// Preload player data in background so it's ready when user searches
setTimeout(loadPlayerData, 500);
setTimeout(() => setInterval(cycleSubtitle, 4000), 3000);
});
</script>
</body>
</html>