<script setup lang="ts">
import { onBeforeUnmount, onMounted, ref, watch, nextTick, computed } from 'vue';
import { assetUrl } from '@/commons/assets.ts'
// import { playGame6Music } from '@/commons/music'

const props = defineProps<{
    imageUrls: Record<string, string>
    countdownInterval: number
    isDivDescVisible: boolean
    tick: number
    rank: number
}>();

const emit = defineEmits<{
    // touch: [mole: boolean]
    scoreChange: [delta: number]
    rankClose: []
}>();

// ========== 常量 ==========
const ROAD_TOP = 421.9;
const ROAD_HEIGHT = 1624 - ROAD_TOP;
const HORSE_W = 131;
const HORSE_H = 285;
const HORSE_BOTTOM_PCT = 19.11;
const ITEM_SIZE = 80;
const GAME_DURATION = 60;

// 设计基准跑道 X 位置（750px 设计稿下的值，窄屏设备上会自动居中偏移）
const DESIGN_LEFT_LANE_X = 150;
const DESIGN_RIGHT_LANE_X = 500;

// 运行时根据视口计算的真实 X 位置（适配不同屏幕宽度）
const leftLaneX = ref(DESIGN_LEFT_LANE_X);
const rightLaneX = ref(DESIGN_RIGHT_LANE_X);

/** 按视口宽度计算 750px 设计区域在 content-bg 中的居中偏移 */
const updateLanePositions = () => {
    const vw = window.visualViewport?.width ?? window.innerWidth;
    const vh = window.visualViewport?.height ?? window.innerHeight;
    // MobileStage contain 模式下 scale = min(scaleX, scaleY)，手机通常由高度决定
    const scaleY = vh / 1624;
    if (!scaleY || scaleY <= 0) return;
    const stageViewportWidth = vw / scaleY;
    const offset = Math.max(0, (stageViewportWidth - 750) / 2);
    leftLaneX.value = DESIGN_LEFT_LANE_X + offset;
    rightLaneX.value = DESIGN_RIGHT_LANE_X + offset;
};

// ========== 马帧 ==========
const HORSE_FRAME_COUNT = 21;
const horseFrames = Array.from({ length: HORSE_FRAME_COUNT }, (_, i) =>
    assetUrl(`game3/horse/1-ma_${String(i).padStart(2, '0')}.png`)
);

// ========== 金币/炸弹帧 ==========
const JINBI_FRAME_COUNT = 25;
const jinbiFrames = Array.from({ length: JINBI_FRAME_COUNT }, (_, i) =>
    assetUrl(`game3/jinbi/1-yuanbao_${String(i).padStart(2, '0')}.png`)
);

const BOM_FRAME_COUNT = 28;
const bomFrames = Array.from({ length: BOM_FRAME_COUNT }, (_, i) =>
    assetUrl(`game3/bom/1-zha_${String(i).padStart(2, '0')}.png`)
);

const fudaiUrl = assetUrl('game3/icon_fudai.webp');
const dileiUrl = assetUrl('game3/icon_dilei.webp');

// ========== 预加载碰撞动画帧（解决 4G 慢网下动画图片未加载的问题） ==========
const preloadFrames = (urls: string[]) => {
    for (const url of urls) {
        const img = new Image();
        img.src = url;
    }
};
preloadFrames(jinbiFrames);
preloadFrames(bomFrames);

// ========== 马状态 ==========
const horseLane = ref<'left' | 'right'>('left');
const horseFrameIndex = ref(0);

const horseX = ref(leftLaneX.value);
const horseTargetX = ref(leftLaneX.value);

const switchToLeft = () => {
    if (horseLane.value !== 'left') {
        horseLane.value = 'left';
        horseTargetX.value = leftLaneX.value;
    }
};

const switchToRight = () => {
    if (horseLane.value !== 'right') {
        horseLane.value = 'right';
        horseTargetX.value = rightLaneX.value;
    }
};

// ========== 键盘控制 ==========
const handleKeydown = (e: KeyboardEvent) => {
    if (!props.isDivDescVisible) return;
    if (e.key === 'ArrowLeft' || e.key === 'a' || e.key === 'A') {
        switchToLeft();
    } else if (e.key === 'ArrowRight' || e.key === 'd' || e.key === 'D') {
        switchToRight();
    }
};

// ========== 路背景加速滚动 ==========
const roadOffset = ref(0);
let roadRafId: number | undefined;
let roadLastTs = 0;
const BASE_ROAD_SPEED = 200;
const MAX_ROAD_SPEED = 700;
const gameElapsed = ref(0);
const currentRoadSpeed = ref(BASE_ROAD_SPEED);

const startRoadScroll = () => {
    stopRoadScroll();
    roadLastTs = 0;
    gameElapsed.value = 0;
    const startTs = performance.now();

    const tick = (ts: number) => {
        if (!props.isDivDescVisible) {
            roadRafId = requestAnimationFrame(tick);
            return;
        }
        if (!roadLastTs) roadLastTs = ts;
        const dt = Math.min(ts - roadLastTs, 100);
        roadLastTs = ts;

        gameElapsed.value = (ts - startTs) / 1000;
        const progress = Math.min(gameElapsed.value / GAME_DURATION, 1);
        currentRoadSpeed.value = BASE_ROAD_SPEED + (MAX_ROAD_SPEED - BASE_ROAD_SPEED) * progress;

        roadOffset.value += currentRoadSpeed.value * dt / 1000;
        if (roadOffset.value >= ROAD_HEIGHT) {
            roadOffset.value -= ROAD_HEIGHT;
        }

        roadRafId = requestAnimationFrame(tick);
    };
    roadRafId = requestAnimationFrame(tick);
};

const stopRoadScroll = () => {
    if (roadRafId) {
        cancelAnimationFrame(roadRafId);
        roadRafId = undefined;
    }
};

// ========== 持续道具生成系统 ==========
type ItemKind = 'coin' | 'bomb';

interface RoadItem {
    id: number;
    kind: ItemKind;
    lane: 'left' | 'right';
    y: number;
    collected: boolean;
    colliding: boolean;   // 防止同一帧内重复触发碰撞特效
    animFrame: number;
    animTimer: ReturnType<typeof setTimeout> | undefined;
}

const roadItems = ref<RoadItem[]>([]);
const effectAnims = ref<{ id: number; kind: ItemKind; frame: number; x: number; y: number }[]>([]);

interface ScoreEffect {
    id: number
    x: number
    y: number
    score: number  // 正数表示加分，负数表示扣分
}
const scoreEffects = ref<ScoreEffect[]>([]);
let scoreEffectIdSeq = 0;

let itemIdCounter = 0;
let genTimerId: ReturnType<typeof setTimeout> | undefined;

function seededRandom(seed: number) {
    const x = Math.sin(seed * 12.9898 + 78.233) * 43758.5453;
    return x - Math.floor(x);
}

function scheduleNextItem() {
    if (!props.isDivDescVisible) return;
    // 游戏越接近尾声，生成间隔越短（1800ms → 350ms），加上随机抖动
    const progress = Math.min(gameElapsed.value / GAME_DURATION, 1);
    const base = 1800 - 1450 * progress;
    const jitter = (Math.random() - 0.5) * 800; // ±400ms 随机
    const interval = Math.max(250, base + jitter);
    genTimerId = setTimeout(generateNewItem, interval);
}

function generateNewItem() {
    if (!props.isDivDescVisible) return;
    
    const seed = Date.now() + itemIdCounter;
    const kind: ItemKind = seededRandom(seed) < 0.75 ? 'coin' : 'bomb';
    
    // 概率分配车道，但避免与前一个同车道道具太近
    let lane: 'left' | 'right' = seededRandom(seed + 1000) < 0.5 ? 'left' : 'right';
    
    // 找到该车道还在顶部附近（y < 200）的未收集道具
    const hasNearbyInLane = (ln: 'left' | 'right') =>
        roadItems.value.some(it => !it.collected && it.lane === ln && it.y < 200);
    
    if (hasNearbyInLane(lane) && !hasNearbyInLane(lane === 'left' ? 'right' : 'left')) {
        // 首选车道已有最近道具，强制换到另一车道
        lane = lane === 'left' ? 'right' : 'left';
    }
    
    const newItem: RoadItem = {
        id: itemIdCounter++,
        kind,
        lane,
        y: -ITEM_SIZE,
        collected: false,
        colliding: false,
        animFrame: 0,
        animTimer: undefined,
    };
    
    roadItems.value.push(newItem);
    
    scheduleNextItem();
}

function stopItemGen() {
    if (genTimerId) {
        clearTimeout(genTimerId);
        genTimerId = undefined;
    }
}

// 道具 y 已是 screen-space（content-bg 坐标系），清理逻辑直接判断
function cleanupOffscreenItems() {
    roadItems.value = roadItems.value.filter(item => {
        // item.y 超出 content-bg 底部即删除，超出顶部也删除
        return item.y < ROAD_HEIGHT && item.y > -ITEM_SIZE;
    });
}




// ========== 碰撞检测 ==========
// 马匹在屏幕上的Y坐标（从 content-bg 顶部算起，horse 使用 bottom: 19.11% 定位）
const horseCSSBottom = ROAD_HEIGHT * (1 - HORSE_BOTTOM_PCT / 100);
const horseCSSTop = horseCSSBottom - HORSE_H;

const checkCollisions = () => {
    const horseCenterX = horseX.value + HORSE_W / 2;
    const horseTopCenterY = horseCSSTop + HORSE_H * 0.15;
    const horseRadius = HORSE_W * 0.35;

    for (const item of roadItems.value) {
        if (item.collected || item.colliding) continue;

        const itemX = item.lane === 'left' ? leftLaneX.value : rightLaneX.value;
        // item.y 已经是屏幕坐标（content-bg 内），无需加 roadOffset
        const itemCenterX = itemX + ITEM_SIZE / 2;
        const itemCenterY = item.y + ITEM_SIZE / 2;

        const dist = Math.hypot(horseCenterX - itemCenterX, horseTopCenterY - itemCenterY);

        if (dist < horseRadius + ITEM_SIZE * 0.35) {
            // 立即标记碰撞中，防止后续帧重复触发
            item.colliding = true;
            // 先启动碰撞特效动画，延迟隐藏道具让动画和道具短暂重叠过渡
            playCollectEffect(item, itemX, item.y);
            setTimeout(() => {
                item.collected = true;
            }, 100);
        }
    }
};

const playCollectEffect = (item: RoadItem, x: number, y: number) => {
    const isCoin = item.kind === 'coin';
    const delta = isCoin ? 5 : -3;

    if (isCoin) {
        emit('scoreChange', 5);
    } else {
        emit('scoreChange', -3);
    }

    const animId = Date.now() + Math.random();
    const totalFrames = isCoin ? JINBI_FRAME_COUNT : BOM_FRAME_COUNT;
    const frameDuration = 1000 / totalFrames;

    // 碰撞动画（大幅放大尺寸，x 往右偏移让动画居中于视觉碰撞点）
    effectAnims.value.push({ id: animId, kind: item.kind, frame: 0, x: x + 65, y });

    let frameIdx = 0;
    const tick = () => {
        frameIdx++;
        if (frameIdx >= totalFrames) {
            effectAnims.value = effectAnims.value.filter(a => a.id !== animId);
            return;
        }
        const anim = effectAnims.value.find(a => a.id === animId);
        if (anim) anim.frame = frameIdx;
        item.animTimer = setTimeout(tick, frameDuration);
    };
    item.animTimer = setTimeout(tick, frameDuration);

    // 积分飘字效果（参考 game5 套中圈 "+10" 动画）
    const effectId = ++scoreEffectIdSeq;
    scoreEffects.value.push({
        id: effectId,
        x: x + ITEM_SIZE / 2 + 25,
        y: y,
        score: delta,
    });
    setTimeout(() => {
        const idx = scoreEffects.value.findIndex(e => e.id === effectId);
        if (idx >= 0) scoreEffects.value.splice(idx, 1);
    }, 800);
};

// ========== 主循环 ==========
let mainRafId: number | undefined;
let mainLastTs = 0;
let perSecondTimer: ReturnType<typeof setInterval> | undefined;

let horseFrameAccum = 0;

const startMainLoop = () => {
    stopMainLoop();
    mainLastTs = 0;
    horseFrameAccum = 0;

    const tick = (ts: number) => {
        if (!props.isDivDescVisible) {
            mainRafId = requestAnimationFrame(tick);
            return;
        }
        if (!mainLastTs) mainLastTs = ts;
        const dt = Math.min(ts - mainLastTs, 200);
        mainLastTs = ts;

        horseFrameAccum += dt;
        const horseInterval = 80 * BASE_ROAD_SPEED / currentRoadSpeed.value;
        while (horseFrameAccum >= horseInterval) {
            horseFrameAccum -= horseInterval;
            horseFrameIndex.value = (horseFrameIndex.value + 1) % HORSE_FRAME_COUNT;
        }

        const lerpFactor = 1 - Math.pow(0.001, dt / 1000);
        horseX.value += (horseTargetX.value - horseX.value) * lerpFactor;

        // 先移动所有道具
        for (const item of roadItems.value) {
            if (!item.collected) {
                item.y += currentRoadSpeed.value * dt / 1000;
            }
        }
        
        // 清理已离开屏幕的道具，避免 roadOffset 回绕后旧道具闪现
        cleanupOffscreenItems();

        // 最后再检测碰撞，确保只检测屏幕内确实可见的道具
        checkCollisions();

        mainRafId = requestAnimationFrame(tick);
    };
    mainRafId = requestAnimationFrame(tick);

    perSecondTimer = setInterval(() => {
        if (props.isDivDescVisible) {
            emit('scoreChange', 2);
        }
    }, 1000);
};

const stopMainLoop = () => {
    if (mainRafId) {
        cancelAnimationFrame(mainRafId);
        mainRafId = undefined;
    }

    if (perSecondTimer) {
        clearInterval(perSecondTimer);
        perSecondTimer = undefined;
    }
};

// ========== 生命周期 ==========
onMounted(() => {
    window.addEventListener('keydown', handleKeydown);
    window.addEventListener('resize', updateLanePositions);
    window.visualViewport?.addEventListener('resize', updateLanePositions);
    updateLanePositions();
    // 初始化马匹在左侧跑道（使用计算后的实际 X 位置）
    horseX.value = leftLaneX.value;
    horseTargetX.value = leftLaneX.value;
    nextTick(() => {
        startRoadScroll();
        startMainLoop();
        scheduleNextItem();
    });
});

onBeforeUnmount(() => {
    window.removeEventListener('keydown', handleKeydown);
    window.removeEventListener('resize', updateLanePositions);
    window.visualViewport?.removeEventListener('resize', updateLanePositions);
    stopRoadScroll();
    stopMainLoop();
    stopItemGen();
    for (const item of roadItems.value) {
        if (item.animTimer) clearTimeout(item.animTimer);
    }
    roadItems.value = [];
    effectAnims.value = [];
    scoreEffects.value = [];
});

watch(() => props.isDivDescVisible, (visible) => {
    if (visible) {
        nextTick(() => {
            roadItems.value = [];
            effectAnims.value = [];
            scoreEffects.value = [];
            roadOffset.value = 0;
            gameElapsed.value = 0;
            updateLanePositions();
            horseX.value = leftLaneX.value;
            horseTargetX.value = leftLaneX.value;
            startRoadScroll();
            startMainLoop();
            scheduleNextItem();
        });
    } else {
        stopRoadScroll();
        stopMainLoop();
        stopItemGen();
        for (const item of roadItems.value) {
            if (item.animTimer) clearTimeout(item.animTimer);
        }
        roadItems.value = [];
        effectAnims.value = [];
        scoreEffects.value = [];
    }
}, { immediate: true });

// 游戏结束：暂停全部动画，显示结果页
// watch(() => props.isGameOver, (over) => {
//     if (over) {
//         stopRoadScroll();
//         stopMainLoop();
//         stopItemGen();
//     }
// });
</script>

<template>
    <div class="h5-page game-stage">
        <div class="only-bg"></div>
        <div class="content-bg">
            <div class="road-track" :style="{ transform: `translateY(${roadOffset}px)` }">
                <div class="road-inner"></div>
                <div class="road-inner"></div>
                <div class="road-inner"></div>
            </div>

            <!-- 道具（屏幕坐标系，独立于跑道滚动） -->
            <template v-for="item in roadItems" :key="item.id">
                <img
                    v-if="!item.collected"
                    :src="item.kind === 'coin' ? fudaiUrl : dileiUrl"
                    class="road-item"
                    :class="`item-lane-${item.lane}`"
                    :style="{
                        top: `${item.y}px`,
                    }"
                />
            </template>

            <!-- 碰撞特效 -->
            <template v-for="anim in effectAnims" :key="anim.id">
                <img
                    :src="(anim.kind === 'coin' ? jinbiFrames : bomFrames)[anim.frame]"
                    class="effect-anim"
                    :style="{ left: `${anim.x}px`, top: `${anim.y}px` }"
                />
            </template>

            <!-- 积分飘字 -->
            <div
                v-for="ef in scoreEffects"
                :key="ef.id"
                class="score-float"
                :class="ef.score > 0 ? 'score-plus' : 'score-minus'"
                :style="{ left: ef.x + 'px', top: ef.y + 'px' }"
            >{{ ef.score > 0 ? '+' : '' }}{{ ef.score }}</div>

            <!-- 马 -->
            <div class="horse-wrapper" :style="{ left: `${horseX}px`, bottom: `${HORSE_BOTTOM_PCT}%` }">
                <img
                    v-for="(url, idx) in horseFrames"
                    :key="idx"
                    :src="url"
                    class="horse-frame"
                    :class="{ active: idx === horseFrameIndex }"
                    alt=""
                />
            </div>
        </div>

        <Transition name="div-desc-slide" appear>
            <div v-if="isDivDescVisible" class="div-desc">
                <span class="desc-clock" aria-hidden="true"></span>
                <span class="desc-time">{{ countdownInterval }}</span>
            </div>
        </Transition>
        <div class="img-logo"></div>
        <div class="img-hydt"></div>
        <div class="img-hammer"></div>
        <div class="img-left" @click="switchToLeft"></div>
        <div class="img-right" @click="switchToRight"></div>

        <!-- 游戏结束结果页覆盖层 -->
        <!-- <Transition name="rank-fade">
            <div v-if="isGameOver" class="rank-overlay">
                <div class="ranklist-container">
                    <div class="txt-title">排行</div>
                    <div class="list-container">
                        <div class="row row-1">
                            <div class="col-1">排名</div>
                            <div class="col-2">用户</div>
                            <div class="col-3">成绩</div>
                        </div>
                        <div class="row-2">
                            <div class="row rank-row" v-for="(item, index) in rankList" :key="`${item.rank}-${index}`">
                                <div class="col-1">
                                    <div>{{ item.rank }}</div>
                                </div>
                                <div class="col-2">
                                    <div class="avatar" :style="item.avatar ? { backgroundImage: `url(${item.avatar})` } : {}"></div>
                                    <div>{{ item.nickname }}</div>
                                </div>
                                <div class="col-3">{{ item.score }}</div>
                            </div>
                        </div>
                        <div class="row row-3">
                            <div class="col-1">{{ userRank > 0 ? userRank : '未上榜' }}</div>
                            <div class="col-2">
                                <div class="avatar" :style="{ backgroundImage: `url(${userAvatar})` }"></div>
                                <div>{{ userNickname }}</div>
                            </div>
                            <div class="col-3">{{ userScore }}</div>
                        </div>
                    </div>
                </div>
                <div class="img-rank-close" @click="$emit('rankClose')"></div>
            </div>
        </Transition> -->
    </div>
</template>

<style scoped>
.game-stage {
    position: absolute;
    width: 750px;
    height: 1624px;
    padding: 0;
}

.only-bg {
    position: absolute;
    top: 0;
    left: var(--stage-viewport-left, 0);
    width: var(--stage-viewport-width, 750px);
    height: 421.9px;
    background: v-bind('imageUrls.bg3') center / cover no-repeat;
}

.content-bg {
    position: absolute;
    top: 421.9px;
    left: var(--stage-viewport-left, 0);
    width: var(--stage-viewport-width, 750px);
    height: 1202.1px;
    overflow: hidden;
    z-index: 1;
}

.road-track {
    width: 100%;
    position: absolute;
    top: -1202.1px;
    left: 0;
    display: flex;
    flex-direction: column;
}

.road-inner {
    width: 100%;
    height: 1202.1px;
    background: v-bind('imageUrls.bg4') center / cover no-repeat;
    flex-shrink: 0;
}

.road-item {
    position: absolute;
    /* width: 80px;
    height: 80px; */
    width: 77px;
    height: 96px;
    z-index: 5;
    pointer-events: none;
}

.item-lane-left {
    /* 当 content-bg 宽于 750px 设计稿时，自动居中 750px 游戏区域 */
    left: calc((var(--stage-viewport-width, 750px) - 750px) / 2 + 170px);
}

.item-lane-right {
    left: calc((var(--stage-viewport-width, 750px) - 750px) / 2 + 520px);
}

.effect-anim {
    position: absolute;
    width: 250px;
    height: 250px;
    z-index: 10;
    pointer-events: none;
    transform: translate(-50%, -50%);
}

/* 积分飘字动画 */
.score-float {
    position: absolute;
    z-index: 25;
    font-size: 56px;
    font-weight: 900;
    pointer-events: none;
    white-space: nowrap;
    transform: translate(-50%, -100%);
    animation: score-float-up 0.8s ease-out forwards;
}

.score-plus {
    color: #FFD700;
    text-shadow: 0 3px 8px rgba(0, 0, 0, 0.7), 0 0 20px rgba(255, 215, 0, 0.5);
}

.score-minus {
    color: #FF4444;
    text-shadow: 0 3px 8px rgba(0, 0, 0, 0.7), 0 0 20px rgba(255, 68, 68, 0.5);
}

@keyframes score-float-up {
    0% {
        opacity: 1;
        transform: translate(-50%, -100%) scale(0.5);
    }
    25% {
        opacity: 1;
        transform: translate(-50%, -140%) scale(1.15);
    }
    100% {
        opacity: 0;
        transform: translate(-50%, -260%) scale(0.8);
    }
}

.horse-wrapper {
    position: absolute;
    width: 131px;
    height: 285px;
    z-index: 8;
}

.horse-frame {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: contain;
    opacity: 0;
    pointer-events: none;
}

.horse-frame.active {
    opacity: 1;
}

.img-hydt {
    position: absolute;
    width: 454px;
    height: 181px;
    top: 174px;
    left: 52%;
    transform: translate(-50%, -50%);
    background: v-bind('imageUrls.hydt') center / cover;
}

.img-left {
    position: absolute;
    width: 128px;
    height: 128px;
    left: 144px;
    bottom: 5.48%;
    z-index: 20;
    background: v-bind('imageUrls.left') center / cover no-repeat;
    cursor: pointer;
}

.img-right {
    position: absolute;
    width: 128px;
    height: 128px;
    right: 144px;
    bottom: 5.48%;
    z-index: 20;
    background: v-bind('imageUrls.right') center / cover no-repeat;
    cursor: pointer;
}

.img-hammer {
    width: 148px;
    height: 148px;
    background: v-bind('imageUrls.hammer') center / cover;
    position: absolute;
    left: 50%;
    bottom: 100px;
    transform: translate(-50%, 0);
}

.div-desc {
    position: absolute;
    top: 150px;
    left: var(--stage-viewport-left, 0);
    z-index: 20;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 24px;
    width: 180px;
    height: 80px;
    border-radius: 0 56px 56px 0;
    background: rgba(40, 12, 8, 0.48);
    color: #fff;

    .desc-clock {
        position: absolute;
        left: 20px;
        width: 38px;
        height: 44px;
        border-radius: 50%;
        background: v-bind('imageUrls.clock') center / cover;
    }

    .desc-time {
        position: absolute;
        right: 40px;
        color: white;
        font-size: 35pt;
        line-height: 1;
    }
}

.div-desc-slide-enter-active {
    transition:
        transform 360ms ease-out 220ms,
        opacity 360ms ease-out 220ms;
}

.div-desc-slide-leave-active {
    transition:
        transform 260ms ease-in,
        opacity 260ms ease-in;
}

.div-desc-slide-enter-from,
.div-desc-slide-leave-to {
    opacity: 0;
    transform: translateX(-110%);
}

.div-desc-slide-enter-to,
.div-desc-slide-leave-from {
    opacity: 1;
    transform: translateX(0);
}

/* 游戏结束结果页覆盖层 */
.rank-overlay {
    position: absolute;
    inset: 0;
    z-index: 100;
    background: rgba(0, 0, 0, 0.65);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
}

.ranklist-container {
    width: 550px;
    background: v-bind('imageUrls.ranklist') center / 100% 100% no-repeat;
    border-radius: 16px;
    padding: 60px 30px 30px;
    display: flex;
    flex-direction: column;
    align-items: center;

    .txt-title {
        font-size: 36px;
        font-weight: bold;
        color: #AA0000;
        letter-spacing: 2px;
        margin-bottom: 16px;
    }

    .list-container {
        width: 100%;
        text-align: center;
        line-height: 56px;
        font-size: 24px;

        .row {
            display: grid;
            grid-template-columns: 100px auto 120px;
            align-items: center;
        }

        .row-1 {
            color: #AA0000;
            font-weight: bold;
            background: linear-gradient(-84deg, #FFD396 0%, #FFF3D1 53%, #FFD59C 100%);
            border-radius: 12px 12px 0 0;
        }

        .row-2 {
            color: #633911;
            max-height: 440px;
            overflow-y: auto;

            .rank-row:nth-child(odd) {
                background: #F2E2AE;
            }

            .rank-row:nth-child(even) {
                background: #FCEEBF;
            }
        }

        .row-3 {
            background: linear-gradient(0deg, #F4B64C 0%, #F7C96F 100%);
            border-radius: 0 0 12px 12px;
            font-weight: bold;
        }

        .col-2 {
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 12px;

            .avatar {
                width: 40px;
                height: 40px;
                flex: 0 0 auto;
                border-radius: 50%;
                background-position: center;
                background-size: cover;
            }
        }
    }
}

.img-rank-close {
    width: 48px;
    height: 48px;
    margin-top: 24px;
    border-radius: 50%;
    background: v-bind('imageUrls.close') center / cover no-repeat;
    cursor: pointer;
}

.rank-fade-enter-active {
    transition: opacity 0.35s ease-out;
}

.rank-fade-leave-active {
    transition: opacity 0.25s ease-in;
}

.rank-fade-enter-from,
.rank-fade-leave-to {
    opacity: 0;
}

.img-logo {
    position: absolute;
    top: 46px;
    left: 20px;
    width: 428px;
    height: 77px;
    background: v-bind('imageUrls.logo') center / cover;
}
</style>
