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

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

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;

  // 播放音效：金币用 game3_1.mp3，炸弹用 game3_2.mp3
  if (isCoin) {
    playGame3Music(1); // 金币音效
  } else {
    playGame3Music(2); // 炸弹音效
  }

  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>
