<script>
	import {createEventDispatcher, getContext, onMount} from 'svelte';
	import {fade, fly, slide} from 'svelte/transition';

	import Value from '../../Common/Value.svelte';
	import Badge from '../../Common/Badge.svelte';
	import Icons from '../../Song/Icons.svelte';
	import {formatDiffStatus, DifficultyStatus, wrapBLStatus, getSongSortingValue} from '../../../utils/beatleader/format';
	import {configStore} from '../../../stores/config';
	import HashDisplay from '../../Common/HashDisplay.svelte';
	import SongStatus from './SongStatus.svelte';
	import MapperList from '../../Leaderboard/MapperList.svelte';
	import LeaderboardStats from '../../Leaderboard/LeaderboardStats.svelte';
	import ModesList from './ModesList.svelte';
	import SongPlayer from './SongPlayer.svelte';
	import {songPlayerStore} from '../../../stores/songPlayer';
	import MapRequirements from './MapRequirements.svelte';
	import Popover from '../../Common/Popover.svelte';
	import {navigate} from 'svelte-routing';
	import MapTypeDescription from './MapTypeDescription.svelte';

	export let map;
	export let sortBy = 'stars';
	export let forcePlaceholder = false;
	export let dateType = 'ranked';

	const dispatch = createEventDispatcher();
	const {open, close} = getContext('simple-modal');

	function onSelectedGroupEntryChanged() {
		dispatch('group-changed');
	}

	let status = null;
	let requirements = null;

	let isHovered = false;

	let mapCardElement;
	let mapCardWrapper;
	let mapCardRect;

	let bottomContainer;
	let bottomContainerHeight = 0;
	let bottomContainerObserver;

	function calculateStatus(song) {
		for (const status of [
			DifficultyStatus.ranked,
			DifficultyStatus.qualified,
			DifficultyStatus.nominated,
			DifficultyStatus.inevent,
			DifficultyStatus.ost,
		]) {
			if (song.difficulties.find(difficulty => difficulty.status == status)) {
				return status;
			}
		}

		return song.difficulties.length > 0 ? song.difficulties[0].status : null;
	}

	function calculateRequirements(song) {
		var result = 0;
		for (const difficulty of song.difficulties) {
			result |= difficulty.requirements;
		}
		return result;
	}

	let song = null;
	let hash = null;
	let name = null;
	let sortValue = null;
	let coverUrl = null;
	let mapType = null;

	function getSong(map) {
		if (!map) return;

		song = map;

		if (song.placeholder) {
			song.updateCallback = newMap => {
				getSong(newMap);
			};
		} else {
			if (song.difficulties) {
				status = calculateStatus(song);
				requirements = calculateRequirements(song);
				mapType = song.difficulties?.filter(d => d.value && d.applicable).sort((a, b) => b.value - a.value)?.[0]?.type;
			}
			hash = song.hash;
			name = song.name;
			coverUrl = song.coverImage;
			sortValue = getSongSortingValue(song, null, sortBy);
		}
	}

	$: getSong(map);

	let cinematicsCanvas;
	let rootcinematicsCanvas;

	let headerContainer;
	let headerContainerHeight = 0;

	function updateHeaderContainerHeight(headerContainer) {
		headerContainerHeight = headerContainer?.getBoundingClientRect().height ?? 0;
	}

	$: headerContainer && updateHeaderContainerHeight(headerContainer);

	let hoverTimeout;
	let playingSong = false;
	let mouseInside = false;

	let modesListContainer;
	let scrollPosition = 0;
	let containerHeight = 0;
	let contentHeight = 0;
	let currentHeight = 0;
	let currentTargetHeight = 0;

	let currentAnimation = null;
	let scheduledAnimation = null;

	function lerp(start, end, t) {
		return start * (1 - t) + end * t;
	}

	function animateHeight(targetHeight, callback) {
		if (!modesListContainer) return;

		// Cancel any ongoing animation
		if (currentAnimation) {
			cancelAnimationFrame(currentAnimation);
		}

		function update(currentTime) {
			if (!modesListContainer) return;

			currentHeight = lerp(currentHeight, targetHeight, targetHeight > 0 ? 0.3 : 0.6);
			modesListContainer.style.height = `${currentHeight}px`;

			containerHeight = modesListContainer.clientHeight;
			contentHeight = modesListContainer.scrollHeight;

			if (Math.abs(currentHeight - targetHeight) > 1) {
				currentAnimation = requestAnimationFrame(update);
				if (contentHeight > 350 && Math.abs(currentHeight - targetHeight) < 50) {
					callback?.();
				}
			} else {
				currentAnimation = null;
				if (targetHeight > 0) {
					currentHeight = modesListContainer.scrollHeight;
				} else {
					currentHeight = 0;
				}
				callback?.();
				modesListContainer.style.height = 'auto';
			}
		}

		currentTargetHeight = targetHeight;
		currentAnimation = requestAnimationFrame(update);
	}

	var shouldInit = false;

	function handleHover(hovering, userHovering = false) {
		mouseInside = hovering && userHovering;
		if (!hovering && playingSong) {
			return;
		}
		clearTimeout(hoverTimeout);
		hoverTimeout = setTimeout(() => {
			if (isHovered == hovering) return;

			clearTimeout(scheduledAnimation);
			isHovered = hovering;
			if (hovering) {
				if (!mapCardWrapper) {
					return;
				}
				mapCardRect = mapCardWrapper.getBoundingClientRect();

				// Start observing bottom container when hovered
				if (bottomContainer && bottomContainerObserver) {
					bottomContainerObserver.observe(bottomContainer);
				}
				modesListContainer.style.height = `${currentHeight}px`;

				scheduledAnimation = setTimeout(() => {
					if (modesListContainer) {
						shouldInit = true;
						animateHeight(modesListContainer.scrollHeight, () => {
							if (shouldInit) {
								updateMaskImage(true);
								shouldInit = false;
							}
						});
					}
				}, 0);
			} else {
				if (modesListContainer) {
					let callback = () => {
						// Stop observing when not hovered
						if (bottomContainerObserver) {
							bottomContainerObserver.disconnect();
						}
					};

					if (currentHeight > 0) {
						animateHeight(0, callback);
					} else {
						callback();
						if (currentAnimation) {
							cancelAnimationFrame(currentAnimation);
						}
						currentAnimation = null;
						currentHeight = 0;
						modesListContainer.style.height = 'auto';
					}
				}
			}
		}, 0);
	}

	onMount(() => {
		bottomContainerObserver = new ResizeObserver(entries => {
			for (const entry of entries) {
				bottomContainerHeight = entry.contentRect.height;
			}
		});

		return () => {
			if (bottomContainerObserver) {
				bottomContainerObserver.disconnect();
			}
			if (currentAnimation) {
				cancelAnimationFrame(currentAnimation);
			}
		};
	});

	let currentGradient = {
		transparent: 0,
		whiteStart: 0,
		whiteEnd: 345,
		transparentEnd: 345,
	};

	// Define target gradient positions based on scroll
	let targetGradient = currentGradient;

	let needsUpdate = false;

	function animateMask() {
		if (!modesListContainer) return;
		const easing = 0.15; // Controls animation speed (0-1)

		// Interpolate each value
		for (let key in currentGradient) {
			if (Math.abs(currentGradient[key] - targetGradient[key]) > 0.1) {
				currentGradient[key] = lerp(currentGradient[key], targetGradient[key], easing);
				needsUpdate = true;
			} else {
				currentGradient[key] = targetGradient[key];
			}
		}

		const maskImage = `linear-gradient(180deg, 
			transparent ${currentGradient.transparent}px, 
			white ${currentGradient.whiteStart}px, 
			white ${currentGradient.whiteEnd}px, 
			transparent ${currentGradient.transparentEnd}px)`;

		modesListContainer.style.maskImage = maskImage;
		modesListContainer.style.webkitMaskImage = maskImage;

		if (needsUpdate) {
			requestAnimationFrame(animateMask);
		}
	}

	function updateMaskImage(initial = false) {
		if (!modesListContainer) return;

		if (Math.abs(contentHeight - containerHeight) < 5) {
			targetGradient = {
				transparent: 0,
				whiteStart: 0,
				whiteEnd: containerHeight + 5,
				transparentEnd: containerHeight + 5,
			};
		} else {
			const scrollPercentage = scrollPosition / (contentHeight - containerHeight);

			if (scrollPosition === 0) {
				targetGradient = {
					transparent: 0,
					whiteStart: 0,
					whiteEnd: 320,
					transparentEnd: containerHeight,
				};
			} else if (Math.abs(scrollPercentage - 1) <= 0.05) {
				targetGradient = {
					transparent: 0,
					whiteStart: 20,
					whiteEnd: containerHeight,
					transparentEnd: containerHeight,
				};
			} else {
				targetGradient = {
					transparent: 0,
					whiteStart: 20,
					whiteEnd: 320,
					transparentEnd: containerHeight,
				};
			}
		}

		if (initial) {
			currentGradient = {...targetGradient};
			const maskImage = `linear-gradient(180deg, 
			transparent ${currentGradient.transparent}px, 
			white ${currentGradient.whiteStart}px, 
			white ${currentGradient.whiteEnd}px, 
			transparent ${currentGradient.transparentEnd}px)`;

			modesListContainer.style.maskImage = maskImage;
			modesListContainer.style.webkitMaskImage = maskImage;
		} else {
			// Animate the gradient positions

			if (!needsUpdate) {
				requestAnimationFrame(animateMask);
			}
		}
	}

	function handleScroll(e) {
		scrollPosition = e.target.scrollTop;
		containerHeight = e.target.clientHeight;
		contentHeight = e.target.scrollHeight;
		updateMaskImage();
	}

	function handlePlay(currentHash, songHash) {
		if (currentHash === songHash) {
			if (!isHovered) {
				handleHover(true);
			}
			playingSong = true;
		} else {
			playingSong = false;
			if (isHovered && !mouseInside) {
				handleHover(false);
			}
		}
	}

	let mapLink = null;

	function getMapLink(song) {
		if (song.difficulties) {
			mapLink = `/leaderboard/global/${song.difficulties?.filter(d => d.value && d.applicable).sort((a, b) => b.value - a.value)?.[0]?.leaderboardId}`;
		} else {
			mapLink = `/leaderboard/global/${song.id}`;
		}
	}

	$: getMapLink(song);

	let titleTextElement;
	let authorElement;
	let mappersElement;

	$: hash && handlePlay($songPlayerStore?.currentHash, hash);
</script>

{#if song}
	{#if !forcePlaceholder && !song.placeholder}
		<Popover triggerEvents={['hover', 'focus']} placement="top" referenceElement={titleTextElement} forOverflow={true} hoverDelay={200}>
			<div class="title-tooltip">
				{name}
				{#if $configStore?.leaderboardPreferences?.showSubtitleInHeader && song.subName}
					<span class="tooltip-subname">{song.subName}</span>
				{/if}
			</div>
		</Popover>
		<Popover triggerEvents={['hover', 'focus']} placement="top" referenceElement={authorElement} forOverflow={true} hoverDelay={200}>
			<div class="title-tooltip">
				<span class="tooltip-author">{song.author}</span>
			</div>
		</Popover>
		<Popover
			triggerEvents={['hover', 'focus']}
			placement="top"
			referenceElement={mappersElement}
			forOverflow={true}
			spaceAway={4}
			hoverDelay={200}>
			<div class="title-tooltip">
				<MapperList {song} maxHeight="unset" maxWidth="25em" fontSize="0.9em" noArrow={true} tooltip={true} />
			</div>
		</Popover>
		<div
			class="map-card-wrapper"
			class:transparent={song.transparent}
			class:is-hovered={isHovered}
			class:long={$configStore.mapCards.wideCards}
			bind:this={mapCardWrapper}>
			{#if isHovered}
				<div
					transition:fade={{duration: 150}}
					class="cinematics root-cinematics"
					style={isHovered ? `height: ${mapCardRect.height}px;` : ''}>
					<div class="cinematics-canvas root-canvas">
						<div
							style="position: absolute; background-size: cover;
			background-position: center; background-image: url({coverUrl}); width: 100%; height: 100%" />
					</div>
				</div>
			{/if}
			<div
				class="map-card"
				class:is-hovered={isHovered || currentAnimation}
				class:expanding={currentAnimation && currentTargetHeight > 0}
				class:player-hovered={isHovered && mouseInside}
				style={isHovered || currentAnimation ? `position: absolute;` : ''}
				bind:this={mapCardElement}
				tabindex="-1"
				role="button"
				on:mouseover={() => handleHover(true, true)}
				on:mouseout={() => handleHover(false, true)}
				on:focus={() => handleHover(true, true)}
				on:blur={() => handleHover(false, true)}>
				<div class="cinematics">
					<div class="cinematics-canvas">
						{#if $configStore.mapCards.cinematics}
							<div
								style="position: absolute; background-size: cover; background-position: center; background-image: url({coverUrl}); width: 100%; height: 100%" />
						{:else}
							<div
								style="position: absolute; background-size: cover; background-position: center; background-color: #777777; width: 100%; height: 100%" />
						{/if}
					</div>
				</div>

				<a on:click|preventDefault|stopPropagation={() => navigate(mapLink)} class="header-link" href={mapLink}></a>
				<div class="header" style="height: {headerContainerHeight < 150 ? '100%' : 'unset'};" class:is-hovered={isHovered}>
					<div
						class="map-cover"
						style={coverUrl
							? `background: url(${coverUrl}); background-repeat: no-repeat; background-size: cover; background-position: center;`
							: ''}>
						<div class="sort-value-background" class:with-value={sortValue} class:is-hovered={sortValue && isHovered}></div>
					</div>

					{#if requirements && isHovered && $configStore.mapCards.requirements}
						<div transition:fly|local={{x: -40, duration: 300, y: 0}} class="requirements-icons">
							<MapRequirements type={requirements} />
						</div>
					{/if}

					<a on:click|preventDefault|stopPropagation={() => navigate(mapLink)} class="main-container" href={mapLink}>
						<div class="header-container" bind:this={headerContainer}>
							<div class="header-top-part">
								<h1 class="song-title">
									<div class="title-text" bind:this={titleTextElement}>
										<span class="name">{name}</span>
										{#if $configStore?.leaderboardPreferences?.showSubtitleInHeader && song.subName}
											<span class="subname">{song.subName}</span>
										{/if}
									</div>
								</h1>

								<div class="title-container">
									<span class="author" bind:this={authorElement}>{song.author}</span>
								</div>
							</div>

							<div class="mapper-container">
								<MapperList {song} maxHeight="2.2em" fontSize="0.9em" noArrow={true} bind:rootElement={mappersElement} />
							</div>
							<div class="status-container" class:is-hovered={isHovered}>
								{#if status && status != DifficultyStatus.unranked && status != DifficultyStatus.unrankable}
									<SongStatus songStatus={wrapBLStatus(status)} />
								{/if}
								{#if song.externalStatuses}
									{#each song.externalStatuses as songStatus}
										<SongStatus {songStatus} />
									{/each}
								{/if}
								{#if mapType && $configStore.mapCards.mapType}
									<MapTypeDescription type={mapType} />
								{/if}
							</div>
						</div>
					</a>
					{#if status != DifficultyStatus.ost}
						<div class="icons-container" class:is-hovered={isHovered}>
							<Icons {song} icons={['preview', 'bsr', 'bs', 'oneclick']} />
						</div>
					{/if}
				</div>
				<div class="bottom-container-background" class:is-hovered={isHovered} style="--bottom-container-height: {bottomContainerHeight}px;">
				</div>
				<div
					class="bottom-container"
					class:has-sort-value={!!sortValue}
					class:is-hovered={isHovered}
					bind:this={bottomContainer}
					style="--margin-top-value: -{headerContainerHeight < 150 ? 2.4 : 0}em;">
					<div class="placeholder">
						{#if sortValue}
							<div class="sort-value" class:is-hovered={isHovered || currentAnimation}>
								{sortValue}
							</div>
						{/if}
					</div>

					{#if isHovered || currentAnimation}
						<div class="song-player">
							<SongPlayer {song} />
						</div>
						<div
							class="mobile-chevron-container hovered mobile-only"
							on:click={() => handleHover(false, true)}
							on:keydown={() => handleHover(false, true)}
							tabindex="-1"
							role="button">
							<i class="fas fa-chevron-up"></i>
						</div>
					{/if}
					<div
						class="modes-list-container"
						class:is-hovered={isHovered || currentAnimation}
						on:scroll={handleScroll}
						bind:this={modesListContainer}>
						<ModesList {song} isHovered={isHovered || currentAnimation} {sortValue} {sortBy} {dateType} />
					</div>
					{#if !isHovered && !currentAnimation}
						<div class="mobile-chevron-container mobile-only">
							<i class="fas fa-chevron-down"></i>
						</div>
					{/if}
				</div>
			</div>
		</div>
	{:else}
		<div class="map-card-wrapper" class:long={$configStore.mapCards.wideCards}>
			<div class="map-card-placeholder">
				<div class="map-card-loading">Loading...</div>
			</div>
		</div>
	{/if}
{/if}

<style>
	.map-card-wrapper {
		position: relative;
		width: 32em;
		height: 10em;
		margin-bottom: 1.2em;
		overflow: visible;
		background-color: #000000;
		border-radius: 12px;
	}

	.map-card-wrapper.long {
		width: 40em;
	}

	.map-card-wrapper.is-hovered {
		border-radius: 12px 12px 16px 16px;
	}

	.map-card-wrapper.transparent {
		opacity: 0;
		pointer-events: none;
	}

	.map-card {
		position: relative;
		border-radius: 0.4em;
		overflow: hidden;
		width: 100%;
		border-radius: 12px;
		box-shadow: 0 4px 10px rgba(0, 0, 0, 0.4);
		transition: box-shadow 0.3s ease;
		height: 100%;
		display: flex;
		flex-direction: column;
	}

	.map-card.is-hovered {
		z-index: 3;
		box-shadow: 0 4px 10px rgba(0, 0, 0, 0.7);
		background-color: #141414;
		height: unset;
		border-radius: 12px 12px 16px 16px;
	}

	.map-card.player-hovered {
		z-index: 5;
	}

	.map-card.expanding {
		z-index: 4;
	}

	.map-card-placeholder {
		display: flex;
		align-items: center;
		justify-content: center;
		height: 100%;
		width: 100%;
		background-color: #1c1c1c;
		border-radius: 12px;
	}

	.root-cinematics {
		opacity: 0.9;
		z-index: -1;
	}

	.song-player {
		flex: 1;
	}
	.header {
		padding: 0.5em;
		color: var(--alternate);
		display: flex;
		align-items: flex-start;
		justify-content: start !important;
		gap: 0.8em;
		width: 100%;
		flex: 1;
	}

	.header.is-hovered {
		height: unset;
	}

	.bottom-container {
		display: flex;
		flex-wrap: wrap;
		padding: 0.3em;
		z-index: 1;
		position: relative;
		background-color: #0000004f;
		border-radius: 0 0 12px 12px;
		margin-top: var(--margin-top-value);
		align-items: center;
	}

	.bottom-container.has-sort-value {
		z-index: 2;
	}

	.bottom-container.is-hovered {
		background-color: transparent;
	}

	.bottom-container-background {
		display: none;
		z-index: -2;
		height: calc(var(--bottom-container-height) + 9px);
	}

	.bottom-container-background.is-hovered {
		display: block;
		position: absolute;
		bottom: 0;
		left: 0;
		width: 100%;
		background-color: black;
	}

	.requirements-icons {
		position: absolute;
		top: 0em;
		width: 2em;
		display: flex;
		flex-wrap: wrap;
		justify-content: start;
		align-items: center;
		gap: 0.2em;
		z-index: 2;
		padding-top: 0.6em;
		padding-left: 0.13em;
	}

	:global(.requirements-icons:has(> :nth-child(4))) {
		width: 4em;
	}

	.sort-value {
		z-index: 2;
		font-weight: 600;
		font-size: 0.9em;
		margin-bottom: 0.4em;
	}

	.sort-value.is-hovered {
		margin-bottom: 0.49em;
	}

	.sort-value-background {
		height: 1.88em;
		position: absolute;
		display: block;
		bottom: 0;
		background-color: transparent;
		width: 100%;
		border-radius: 0 0 8px 8px;
	}

	.sort-value-background.is-hovered {
		background-color: #00000066 !important;
	}

	.sort-value-background.with-value {
		background-color: #0000004a;
	}

	.modes-list-container {
		overflow: scroll;
		-ms-overflow-style: none;
		scrollbar-width: none;
		width: calc(100% - 10.5em);
	}

	.modes-list-container::-webkit-scrollbar {
		display: none;
	}

	.modes-list-container.is-hovered {
		max-height: 22em;
		width: 100%;
		margin-top: 0.1em;
	}

	.header-link {
		position: absolute;
		top: 0;
		left: 0;
		width: 100%;
		height: 100%;
	}

	:global(.map-card-wrapper .icons-container .buttons-container.flat) {
		flex-direction: column;
	}

	.header:before {
		position: absolute;
		content: ' ';
		top: 0;
		left: 0;
		width: 100%;
		height: 100%;
		opacity: 0.1;
		background-repeat: no-repeat;
		background-size: cover;
		pointer-events: none;
	}

	.main-container {
		display: flex;
		justify-content: space-between;
		flex: 1;
		z-index: 1;
		user-select: text;
		-webkit-user-select: text;
		-webkit-user-drag: none;
		overflow: hidden;
	}

	.mobile-chevron-container {
		cursor: pointer;
		pointer-events: auto;
		color: #ffffffa1;
	}

	.mobile-chevron-container.hovered {
		margin-left: 1em;
	}

	.buttons-container {
		position: absolute;
		bottom: 0;
		height: 2.7em;
		margin-left: -0.6em;
		width: 100%;
		display: flex;
		justify-content: space-between;
		background-color: #0000004f;
		padding: 0.6em;
		border-radius: 0 0 12px 12px;
	}

	.icons-container {
		width: fit-content;
		margin-top: 0.25em;
		transform: scale(1.1);
		margin-right: -2em;
		transition: margin-right 0.15s;
	}

	.icons-container.is-hovered {
		margin-right: 0;
	}

	.version-selector-container {
		transform: scale(1.15);
		margin-bottom: -0.5em;
	}

	.header .song-title {
		color: inherit !important;
		margin-bottom: 0;
		width: 100%;
	}

	.header .song-title .title-text {
		display: block;
		white-space: nowrap;
		overflow: hidden;
		text-overflow: ellipsis;
		width: 100%;
		color: #ffffff93 !important;
	}

	.header h1 {
		margin-bottom: 0.2em;
		max-width: 100%;
		overflow: hidden;
	}

	.header h1 span.name {
		color: #ffffffcc !important;
		font-size: 1.3em;
		font-weight: 600;
		margin-top: -0.2em;
	}

	.subname {
		color: #ffffff93;
		font-size: 0.8em;
	}

	.map-cover {
		position: relative;
		width: 9em;
		aspect-ratio: 1;
		border-radius: 8px;
		z-index: 2;
		pointer-events: none;
	}

	.placeholder {
		width: 9.7em;
		display: flex;
		justify-content: center;
	}

	.author {
		color: #ffffffa3;
		font-size: 1em;
		overflow: hidden;
		text-overflow: ellipsis;
		white-space: nowrap;
		max-width: 100%;
	}

	.diff-status {
		color: white;
	}

	.capture-status {
		position: absolute;
		top: 0;
		left: 0;
		height: 6em;
		overflow: hidden;
		z-index: 2;
	}

	.header h2.song-title {
		font-size: 1em !important;
		color: var(--increase, #42b129) !important;
		margin-top: 0.5em;
		margin-bottom: 0.5em;
	}

	.header-container {
		display: flex;
		justify-content: start;
		flex-direction: column;
		gap: 0.2em;
		width: 100%;
		overflow: hidden;
		height: 7em;
	}

	.header-top-part {
		display: flex;
		flex-direction: column;
		justify-content: flex-start;
		z-index: 1;
		width: 100%;
		overflow: hidden;
	}

	:global(.map-card-wrapper.long) {
		.header-top-part {
			flex-direction: row;
			gap: 0.5em;
		}

		.author {
			margin-top: unset;
		}

		.title-container {
			width: unset;
		}

		.song-title {
			width: unset;
		}
	}

	.header-bottom-part {
		z-index: 1;
	}

	.title-container {
		display: flex;
		justify-content: center;
		flex-direction: column;
		grid-gap: 0.2em;
		width: 100%;
		overflow: hidden;
	}

	.mapper-container {
		display: flex;
		font-size: 0.9em;
		white-space: nowrap;
		overflow: hidden;
		width: 100%;
		margin-top: -0.1em;
		mask-image: linear-gradient(90deg, white 0%, white 80%, transparent 100%);
	}

	.status-container {
		display: flex;
		gap: 0.3em;
		font-size: 0.9em;
		justify-content: flex-start;
		margin-top: 0.1em;
		white-space: nowrap;
		overflow: hidden;
		width: 100%;
	}

	.title-tooltip {
		background: rgba(0, 0, 0, 0.8);
		color: white;
		padding: 0.3em 0.5em;
		border-radius: 0.6em;
		pointer-events: none;
		white-space: normal;
		width: max-content;
		max-width: 24vw;
		z-index: 8;
	}

	.tooltip-subname {
		opacity: 0.8;
		font-size: 0.9em;
		margin-left: 0.05em;
	}

	.tooltip-author {
		color: #ffffffee;
	}

	.cinematics {
		position: absolute;
		top: 0;
		right: 0;
		bottom: 0;
		left: 0;
		pointer-events: none;
	}

	.cinematics-canvas {
		filter: blur(5em) opacity(0.5) saturate(250%);
		left: 0;
		pointer-events: none;
		position: absolute;
		top: 0;
		transform: scale(1.1) translateZ(0);
		width: 100%;
		height: 100%;
	}

	.root-canvas {
		transform: scale(0.9) translateZ(0);
	}

	.status-and-type {
		display: flex;
		gap: 0.6em;
		overflow: hidden;
		white-space: nowrap;
	}

	:global(.title-container .stats) {
		justify-content: start !important;
		color: #ffffffa3;
		max-width: 35em;
	}

	.group-select {
		height: fit-content;
		padding: 0.175rem;
		text-align: center;
		text-align-last: center;
		white-space: nowrap;
		border: 0;
		border-radius: 6px;
		cursor: pointer;
		color: #363636;
		background-color: #dbdbdb;
		box-shadow: none;
		opacity: 0.35;
		font-family: inherit;
		font-size: 0.875rem;
		font-weight: 500;
		width: 100%;
		margin-bottom: -0.6em;
	}

	.group-option {
		color: black;
		font-family: inherit;
	}

	.requirements {
		display: flex;
		flex-wrap: nowrap;
		justify-content: center;
		align-items: center;
		gap: 0.2em;
		row-gap: 0.5em;
		padding-top: 0.7em;
		padding-bottom: 0.7em;
		overflow: hidden;
	}

	.header small {
		font-size: 0.75em;
		color: var(--ppColour);
	}

	.header .diff :global(.reversed) {
		display: inline-block;
		padding: 0.1em 0.25em 0.25em 0.25em;
		margin-left: 0.5em;
		margin-right: 0.5em;
		border-radius: 0.25em;
	}

	:global(.voter-feedback-button) {
		height: 1.8em;
	}

	:global(.battleroyalebtn) {
		margin-left: 1em;
		margin-bottom: 0.5em;
	}

	.title-and-buttons {
		display: flex;
		align-items: center;
		align-self: stretch;
		justify-content: center;
		flex-wrap: nowrap;
		flex-direction: column;
		padding: 0.5em;
		min-width: fit-content;
		overflow: hidden;
	}

	.mobile-triangle {
		position: absolute;
		left: 8em;
		top: 8.4em;
		z-index: 2;
	}

	.mobile-only {
		display: none;
	}

	:global(.voteButton) {
		margin-top: 0 !important;
		height: 1.8em;
	}

	@media screen and (max-width: 1024px) {
		.header {
			margin-inline: 0;
		}
	}

	@media screen and (max-width: 767px) {
		.map-card-wrapper {
			width: 100%;
			margin-bottom: 0.2em;
			height: 7.2em;
		}

		.map-card-wrapper.long {
			width: 100%;
		}

		.bottom-container {
			padding: 0.2em;
			margin-top: calc(var(--margin-top-value) + 0.8em);
		}

		.header {
			margin-inline: 0;
			padding: 0.4em 0.4em 0.15em 0.4em;
			gap: 0.5em;
			width: 100%;
		}

		.song-player {
			width: calc(100vw - 9.7em);
			flex: unset;
		}

		.sort-value {
			font-size: 0.8em;
		}

		.desktop-only {
			display: none;
		}

		.mobile-only {
			display: flex;
		}

		.buttons-container {
			position: relative;
			margin-left: 0;
			border-radius: 0;
			justify-content: flex-start;
			gap: 0.6em;
			height: unset;
		}

		.cinematics-canvas {
			transform: scaleY(1.2) translateZ(0);
		}

		:global(.player .clan-badges) {
			display: none;
		}

		.main-container {
			min-height: unset;
		}

		.header .song-title {
			margin-left: unset;
		}

		.header {
			border-radius: 0;
			margin-bottom: 0;
		}

		.song-statuses {
			flex-wrap: nowrap;
		}

		.author {
			font-size: 0.9em;
			margin-top: -0.2em;
		}

		.map-cover {
			width: 6.4em;
		}

		.placeholder {
			width: 6.8em;
			height: 1em;
		}

		.icons-container {
			transform: scale(0.75);
			margin-top: -0.8em;
			margin-right: -2.2em;
			transition:
				margin-right 0.15s,
				margin-left 0.15s;
		}

		.icons-container.is-hovered {
			margin-left: 0;
		}

		.main-container {
			font-size: 0.8em;
			max-width: calc(100vw - 9.5em);
		}

		.requirements-icons {
			padding-top: 0.5em;
			left: 0.4em;
		}

		.header h1 span.name {
			font-size: 1.1em;
		}

		.bottom-container-background {
			height: calc(var(--bottom-container-height) + 7px);
		}

		.modes-list-container {
			width: calc(100% - 8.3em);
		}

		:global(.song-statuses .song-status) {
			font-size: 0.6em;
		}

		:global(.leaderboard-header-box) {
			margin: 0.6em 0 0 !important;
			border-radius: 0 !important;
		}
	}
</style>
