Skip to content
(function () {
var root = document.documentElement;
var toggle = document.querySelector('[data-theme-toggle]');
var menu = document.querySelector('[data-menu-toggle]');
var mobileNav = document.getElementById('mobile-nav');
function setTheme(theme) {
var dark = theme === 'dark';
root.setAttribute('data-theme', dark ? 'dark' : 'light');
if (toggle) {
toggle.setAttribute('aria-pressed', dark ? 'true' : 'false');
toggle.setAttribute('aria-label', dark ? 'Switch to light mode' : 'Switch to dark mode');
var icon = toggle.querySelector('.theme-icon');
var label = toggle.querySelector('.theme-label');
if (icon) icon.textContent = dark ? '☀' : '☾';
if (label) label.textContent = dark ? 'Light' : 'Dark';
}
var meta = document.getElementById('theme-color-meta');
if (meta) meta.setAttribute('content', dark ? '#0b1220' : '#0d172a');
try { localStorage.setItem('ff-theme', dark ? 'dark' : 'light'); } catch (e) {}
}
if (toggle) {
setTheme(root.getAttribute('data-theme') === 'dark' ? 'dark' : 'light');
toggle.addEventListener('click', function () {
setTheme(root.getAttribute('data-theme') === 'dark' ? 'light' : 'dark');
});
}
if (menu && mobileNav) {
menu.addEventListener('click', function () {
var open = menu.getAttribute('aria-expanded') === 'true';
menu.setAttribute('aria-expanded', open ? 'false' : 'true');
menu.setAttribute('aria-label', open ? 'Open menu' : 'Close menu');
mobileNav.hidden = open;
});
mobileNav.querySelectorAll('a').forEach(function (link) {
link.addEventListener('click', function () {
menu.setAttribute('aria-expanded', 'false');
mobileNav.hidden = true;
});
});
}
var searchToggle = document.querySelector('[data-search-toggle]');
var headerSearch = document.getElementById('header-search');
if (searchToggle && headerSearch) {
searchToggle.addEventListener('click', function () {
var open = headerSearch.classList.contains('is-open');
headerSearch.classList.toggle('is-open', !open);
searchToggle.setAttribute('aria-expanded', open ? 'false' : 'true');
searchToggle.setAttribute('aria-label', open ? 'Search movies' : 'Close search');
if (!open) {
var input = headerSearch.querySelector('input[type="search"]');
if (input) setTimeout(function () { input.focus(); }, 50);
}
});
}
}());
(function () {
var primaryAttempts = 5;
var fallbackAttempts = 3;
function markLoaded(img) {
img.dataset.posterLoaded = '1';
img.classList.add('is-loaded');
img.classList.remove('is-loading', 'is-failed');
}
function markFailed(img) {
img.classList.remove('is-loading', 'is-loaded');
img.classList.add('is-failed');
}
function retryPoster(img) {
if (!img || img.dataset.posterLoaded === '1') return;
var primary = img.dataset.posterSrc || img.getAttribute('src') || '';
var fallback = img.dataset.posterFallbackSrc || '';
var primaryTry = parseInt(img.dataset.posterTry || '0', 10) || 0;
var fallbackTry = parseInt(img.dataset.posterFallbackTry || '0', 10) || 0;
var useFallback = primaryTry >= primaryAttempts && fallback && fallback !== primary;
var nextUrl = '';
var delayIndex = primaryTry + fallbackTry;
if (useFallback) {
if (fallbackTry >= fallbackAttempts) {
markFailed(img);
return;
}
fallbackTry += 1;
img.dataset.posterFallbackTry = String(fallbackTry);
nextUrl = fallback;
} else {
if (primaryTry >= primaryAttempts) {
markFailed(img);
return;
}
primaryTry += 1;
img.dataset.posterTry = String(primaryTry);
nextUrl = primary;
}
img.classList.add('is-loading');
img.classList.remove('is-loaded', 'is-failed');
window.setTimeout(function () {
if (!document.documentElement.contains(img) || img.dataset.posterLoaded === '1') return;
img.removeAttribute('src');
window.setTimeout(function () {
if (!document.documentElement.contains(img) || img.dataset.posterLoaded === '1') return;
img.src = nextUrl;
}, 30);
}, Math.min(9000, 650 * Math.pow(1.7, delayIndex)));
}
function bindPoster(img) {
if (!img || img.dataset.posterBound === '1') return;
img.dataset.posterBound = '1';
if (!img.dataset.posterSrc) {
img.dataset.posterSrc = img.currentSrc || img.getAttribute('src') || '';
}
img.addEventListener('load', function () {
if (img.naturalWidth > 0) markLoaded(img);
});
img.addEventListener('error', function () {
retryPoster(img);
});
if (img.complete) {
if (img.naturalWidth > 0) {
markLoaded(img);
} else {
retryPoster(img);
}
} else {
img.classList.add('is-loading');
}
}
function scanPosters() {
document.querySelectorAll('img[data-poster-retry]').forEach(bindPoster);
}
window.ffRetryPoster = retryPoster;
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', scanPosters);
} else {
scanPosters();
}
window.addEventListener('pageshow', scanPosters);
}());