<template>
  <div
    ref="platformScreenRef"
    class="large-screen platform-screen"
    :class="{
      'is-home': activeModule.key === 'home',
      'is-forest-grass-wet': activeModule.key === 'forest-grass-wet',
      'is-ecological-protection': activeModule.key === 'ecological-protection',
      'is-grass-livestock-balance': activeModule.key === 'grass-livestock-balance',
      'is-yak-management': activeModule.key === 'yak-management',
      'is-pasture-management': activeModule.key === 'pasture-management',
      'is-yak-industry-chain': activeModule.key === 'yak-industry-chain',
      'is-smart-management': activeModule.key === 'smart-management',
      'is-ecology-national-park': activeModule.key === 'ecological-protection' && activeBottomKey === 'national-park',
    }"
    id="large-screen"
  >
    <div
      v-if="renderedModules.home"
      v-show="activeModule.key === 'home'"
      class="platform-module-pane"
      :aria-hidden="activeModule.key !== 'home'"
      :inert="activeModule.key !== 'home'"
    >
      <home-dashboard
        ref="homeDashboardRef"
        :active="activeModule.key === 'home'"
        @loading-progress="handleHomeLoadingProgress"
        @map-ready="handleHomeMapReady"
        @module-stats="handleModuleStats"
      />
    </div>
    <div
      v-if="renderedModules['forest-grass-wet']"
      v-show="activeModule.key === 'forest-grass-wet'"
      class="platform-module-pane"
      :aria-hidden="activeModule.key !== 'forest-grass-wet'"
      :inert="activeModule.key !== 'forest-grass-wet'"
    >
      <forest-grass-wet
        ref="forestGrassWetRef"
        :active="activeModule.key === 'forest-grass-wet'"
        :show-loading="false"
        @topic-stats="handleModuleStats"
      />
    </div>
    <div
      v-if="renderedModules['ecological-protection']"
      v-show="activeModule.key === 'ecological-protection'"
      class="platform-module-pane"
      :aria-hidden="activeModule.key !== 'ecological-protection'"
      :inert="activeModule.key !== 'ecological-protection'"
    >
      <ecological-protection
        ref="ecologicalProtectionRef"
        :active="activeModule.key === 'ecological-protection'"
        :active-view="activeEcologyView"
        :show-loading="false"
        @module-stats="handleModuleStats"
        @view-change="handleEcologyViewChange"
      />
    </div>
    <div
      v-if="renderedModules['grass-livestock-balance']"
      v-show="activeModule.key === 'grass-livestock-balance'"
      class="platform-module-pane"
      :aria-hidden="activeModule.key !== 'grass-livestock-balance'"
      :inert="activeModule.key !== 'grass-livestock-balance'"
    >
      <grass-livestock-balance
        :active="activeModule.key === 'grass-livestock-balance'"
        @loading-progress="handleHomeLoadingProgress"
        @map-ready="handleHomeMapReady"
        @module-stats="handleModuleStats"
      />
    </div>
    <div
      v-if="renderedModules['yak-management']"
      v-show="activeModule.key === 'yak-management'"
      class="platform-module-pane"
      :aria-hidden="activeModule.key !== 'yak-management'"
      :inert="activeModule.key !== 'yak-management'"
    >
      <yak-management
        ref="yakManagementRef"
        :active="activeModule.key === 'yak-management'"
        :view-key="activeYakView"
        @module-stats="handleModuleStats"
        @view-change="handleYakViewChange"
      />
    </div>
    <div
      v-if="renderedModules['pasture-management']"
      v-show="activeModule.key === 'pasture-management'"
      class="platform-module-pane"
      :aria-hidden="activeModule.key !== 'pasture-management'"
      :inert="activeModule.key !== 'pasture-management'"
    >
      <pasture-management
        ref="pastureManagementRef"
        :active="activeModule.key === 'pasture-management'"
        @loading-progress="handleHomeLoadingProgress"
        @map-ready="handleHomeMapReady"
        @module-stats="handleModuleStats"
      />
    </div>
    <div
      v-if="renderedModules['yak-industry-chain']"
      v-show="activeModule.key === 'yak-industry-chain'"
      class="platform-module-pane"
      :aria-hidden="activeModule.key !== 'yak-industry-chain'"
      :inert="activeModule.key !== 'yak-industry-chain'"
    >
      <yak-industry-chain
        ref="yakIndustryChainRef"
        :active="activeModule.key === 'yak-industry-chain'"
        @loading-progress="handleHomeLoadingProgress"
        @map-ready="handleHomeMapReady"
        @module-stats="handleModuleStats"
      />
    </div>
    <div
      v-if="renderedModules['smart-management']"
      v-show="activeModule.key === 'smart-management'"
      class="platform-module-pane"
      :aria-hidden="activeModule.key !== 'smart-management'"
      :inert="activeModule.key !== 'smart-management'"
    >
      <wisdom-management :active="activeModule.key === 'smart-management'" />
    </div>

    <div class="large-screen-wrap">
      <m-header
        title="红原县数字畜牧业监管平台"
        sub-text="Hongyuan Digital Animal Husbandry Supervision Platform"
      >
        <template #right>
          <div class="m-header-tools">
            <div class="platform-weather" :class="{ 'is-unavailable': !weatherAvailable }">
              <img
                v-if="weatherIconVisible"
                class="platform-weather__icon"
                :src="weatherIconUrl"
                :alt="weather.condition || '天气'"
                @error="handleWeatherIconError"
              />
              <span v-else class="platform-weather__fallback-icon" aria-hidden="true"></span>
              <div class="platform-weather__copy">
                <div class="platform-weather__primary">
                  <strong>{{ weatherAvailable ? weather.condition || "实时天气" : "天气暂无数据" }}</strong>
                  <em v-if="weatherAvailable">{{ weather.temperature }}℃</em>
                </div>
                <small v-if="weatherHumidityAvailable || weatherWindText">
                  <span v-if="weatherHumidityAvailable">湿度 {{ weather.humidity }}%</span>
                  <i v-if="weatherHumidityAvailable && weatherWindText" aria-hidden="true"></i>
                  <span v-if="weatherWindText">{{ weatherWindText }}</span>
                </small>
              </div>
            </div>
            <div class="platform-datetime" aria-label="当前日期和时间">
              <strong>{{ currentTime }}</strong>
              <span>{{ currentDate }}</span>
            </div>
            <button class="logout-button" aria-label="退出登录" title="退出登录" type="button" @click="handleLogout">
              <svg class="logout-icon" viewBox="0 0 24 24" aria-hidden="true">
                <path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4" />
                <path d="M16 17l5-5-5-5" />
                <path d="M21 12H9" />
              </svg>
            </button>
          </div>
        </template>
      </m-header>

      <div class="top-menu">
        <m-menu :default-active="activeModuleKey" @select="handleMenuSelect">
          <template v-for="(item, index) in platformModules" :key="item.key">
            <m-menu-item
              :index="item.key"
              @click="handleTopMenuItemClick(item.key)"
              @keydown.enter="handleTopMenuItemClick(item.key)"
              @keydown.space="handleTopMenuItemClick(item.key)"
            >{{ item.label }}</m-menu-item>
            <div v-if="index === 3" class="top-menu-mid-space"></div>
          </template>
        </m-menu>
      </div>

      <div
        v-if="totalView.length && !['smart-management', 'grass-livestock-balance'].includes(activeModule.key)"
        class="top-count-card"
        :class="{
          'is-four': totalView.length > 3 && totalView.length <= 4,
          'is-multi': totalView.length > 4,
          'is-count-five': totalView.length === 5,
          'is-home-five': topStatsUseHomeFiveStyle,
        }"
      >
        <m-count-card v-for="item in totalView" :key="item.zh" :info="item" />
      </div>

      <div v-if="mapToolsVisible" class="platform-map-tools" aria-label="地图工具">
        <button type="button" :title="platformFullscreenLabel" :aria-label="platformFullscreenLabel" @click="handlePlatformFullscreen">
          <span class="platform-map-tool-icon is-fullscreen" aria-hidden="true"></span>
        </button>
        <button type="button" title="复位地图" aria-label="复位地图" @click="handleActiveMapReset">
          <span class="platform-map-tool-icon is-reset" aria-hidden="true"></span>
        </button>
      </div>

      <div v-if="activeModule.status !== 'ready'" class="module-coming">
        <div class="module-coming-title">{{ activeModule.label }}</div>
        <div class="module-coming-text">模块建设中，平台框架已预留入口</div>
      </div>

      <div
        v-if="!['home', 'forest-grass-wet', 'ecological-protection', 'grass-livestock-balance', 'yak-management', 'pasture-management', 'yak-industry-chain', 'smart-management'].includes(activeModule.key)"
        class="bottom-tray"
      >
        <m-svgline-animation
          class="bottom-svg-line-left"
          :width="721"
          :height="57"
          color="#30DCFF"
          :strokeWidth="2"
          :dir="[0, 1]"
          :length="50"
          path="M1 56.6105C1 31.5123 185.586 10.0503 451.904 1.35519C458.942 1.12543 465.781 4.00883 470.505 9.22964L484.991 25.2383C487.971 28.4775 492.938 30.4201 498.254 30.4201H720.142"
        />
        <m-svgline-animation
          class="bottom-svg-line-left bottom-svg-line-right"
          :width="721"
          :height="57"
          color="#30DCFF"
          :strokeWidth="2"
          :dir="[0, 1]"
          :length="50"
          path="M1 56.6105C1 31.5123 185.586 10.0503 451.904 1.35519C458.942 1.12543 465.781 4.00883 470.505 9.22964L484.991 25.2383C487.971 28.4775 492.938 30.4201 498.254 30.4201H720.142"
        />
        <div class="bottom-tray-arrow">
          <img src="@/assets/images/bottom-menu-arrow-big.svg" alt="" />
          <img src="@/assets/images/bottom-menu-arrow-small.svg" alt="" />
        </div>
        <div class="bottom-menu">
          <div
            v-for="item in bottomMenuItems"
            :key="item.key"
            class="bottom-menu-item"
            :class="{ 'is-active': item.key === activeBottomKey }"
            @click="handleBottomMenuSelect(item)"
          >
            <span>{{ item.bottomLabel }}</span>
          </div>
        </div>
        <div class="bottom-tray-arrow is-reverse">
          <img src="@/assets/images/bottom-menu-arrow-big.svg" alt="" />
          <img src="@/assets/images/bottom-menu-arrow-small.svg" alt="" />
        </div>
      </div>

      <div class="large-screen-left-zsline"></div>
      <div class="large-screen-right-zsline"></div>
    </div>

    <div v-if="loadingVisible" class="loading platform-loading">
      <div class="loading-text">
        <span style="--index: 1">L</span>
        <span style="--index: 2">O</span>
        <span style="--index: 3">A</span>
        <span style="--index: 4">D</span>
        <span style="--index: 5">I</span>
        <span style="--index: 6">N</span>
        <span style="--index: 7">G</span>
      </div>
      <div class="loading-progress">
        <span class="value">{{ loadingProgress }}</span>
        <span class="unit">%</span>
      </div>
    </div>
  </div>
</template>

<script setup>
import { computed, defineAsyncComponent, nextTick, onBeforeUnmount, onMounted, ref, watch } from "vue"
import { useRoute, useRouter } from "vue-router"
import autofit from "autofit.js"
import gsap from "gsap"
import mHeader from "@/components/mHeader/index.vue"
import mMenu from "@/components/mMenu/index.vue"
import mMenuItem from "@/components/mMenuItem/index.vue"
import mCountCard from "@/components/mCountCard/index.vue"
import mSvglineAnimation from "@/components/mSvglineAnimation/index.vue"
import { getModuleByKey, platformModules } from "@/config/modules"
import { ecologicalProtectionMenu } from "@/config/ecologicalProtection"
import { logout } from "@/services/auth"
import { getCurrentWeather } from "@/services/weatherApi"
import "@/assets/style/home.scss"
import "@/assets/style/v21-polish.scss"
import "@/assets/style/v22-unified.scss"

const HomeDashboard = defineAsyncComponent(() => import("@/views/home/index.vue"))
const ForestGrassWet = defineAsyncComponent(() => import("@/views/forestGrassWet/index.vue"))
const EcologicalProtection = defineAsyncComponent(() => import("@/views/ecologicalProtection/index.vue"))
const GrassLivestockBalance = defineAsyncComponent(() => import("@/views/grassLivestockBalance/index.vue"))
const YakManagement = defineAsyncComponent(() => import("@/views/yakManagement/index.vue"))
const PastureManagement = defineAsyncComponent(() => import("@/views/pastureManagement/index.vue"))
const YakIndustryChain = defineAsyncComponent(() => import("@/views/yakIndustryChain/index.vue"))
const WisdomManagement = defineAsyncComponent(() => import("@/views/wisdomManagement/index.vue"))

const route = useRoute()
const router = useRouter()
const initialModuleKey = resolvePlatformModuleKey(route.query.module)
const activeModuleKey = ref(initialModuleKey)
const activeEcologyView = ref(initialModuleKey === "ecological-protection" ? resolveEcologyViewKey(route.query.view) : "ecological-redline")
const activeYakView = ref(initialModuleKey === "yak-management" ? resolveYakViewKey(route.query.view) : "structure")
const maxRetainedModules = 2
const renderedModules = ref({ [initialModuleKey]: true })
let renderedModuleOrder = [initialModuleKey]
const moduleTopStats = ref({})
const loadingVisible = ref(true)
const loadingProgress = ref(0)
const platformScreenRef = ref(null)
const homeDashboardRef = ref(null)
const forestGrassWetRef = ref(null)
const ecologicalProtectionRef = ref(null)
const yakManagementRef = ref(null)
const pastureManagementRef = ref(null)
const yakIndustryChainRef = ref(null)
const platformFullscreen = ref(false)
const currentDate = ref("")
const currentTime = ref("")
const weather = ref({
  condition: "",
  temperature: "--",
  humidity: "--",
  windDirection: "",
  windLevel: "",
  icon: null,
})
const weatherAvailable = ref(false)
const weatherIconFailed = ref(false)
let screenAutofit = null
let clockTimer = null
let weatherTimer = null
let loadingHideStarted = false
let loadingSafetyTimer = null
const loadingStartedAt = Date.now()
const minLoadingVisibleMs = 650
const loadingTweenState = { progress: 0 }
const platformLoadingModuleKeys = new Set([
  "home",
  "grass-livestock-balance",
  "pasture-management",
  "yak-industry-chain",
])

const topStatIconPool = [
  "town",
  "area",
  "wetland",
  "yield",
  "rate",
  "stack",
  "leaf",
  "risk",
  "grass-basic",
  "grass-general",
  "forest",
  "park",
  "project",
  "length",
  "device",
  "certificate",
]
const topStatIconSet = new Set(topStatIconPool)

const activeModule = computed(() => getModuleByKey(activeModuleKey.value))
const weatherIconUrl = computed(() => `/images/weather/W${weather.value.icon}.png`)
const weatherIconVisible = computed(() => weatherAvailable.value && weather.value.icon !== null && !weatherIconFailed.value)
const weatherHumidityAvailable = computed(() => !["", "--", null, undefined].includes(weather.value.humidity))
const weatherWindText = computed(() => {
  const direction = String(weather.value.windDirection || "").trim()
  const level = String(weather.value.windLevel || "").trim()
  if (!direction && !level) return ""
  return `${direction}${direction && level ? " " : ""}${level ? `${level}级` : ""}`
})
const platformFullscreenLabel = computed(() => (platformFullscreen.value ? "退出" : "全屏"))
const mapToolsVisible = computed(() => !["smart-management", "grass-livestock-balance"].includes(activeModule.value.key))
const topStatsUseHomeFiveStyle = computed(() =>
  totalView.value.length === 5
  && (
    activeModule.value.key === "home"
    || (activeModule.value.key === "ecological-protection" && activeBottomKey.value === "national-park")
  )
)
const bottomMenuItems = computed(() => {
  if (activeModuleKey.value === "ecological-protection") return ecologicalProtectionMenu
  return platformModules
})
const activeBottomKey = computed(() => {
  if (activeModuleKey.value === "ecological-protection") return activeEcologyView.value
  return activeModuleKey.value
})
const totalView = computed(() => {
  const currentStats = moduleTopStats.value[activeModuleKey.value]
  if (Array.isArray(currentStats)) return currentStats
  if (currentStats?.length) {
    return currentStats
  }
  return buildTopCountItems([
    {
      zh: "草地面积",
      en: "",
      value: 756.37,
      unit: "万亩",
      decimals: 2,
    },
    {
      zh: "林地总面积",
      en: "",
      value: 177.92,
      unit: "万亩",
      decimals: 2,
    },
    {
      zh: "湿地面积",
      en: "",
      value: 291.82,
      unit: "万亩",
      decimals: 2,
    },
  ])
})

onMounted(() => {
  updateCurrentDateTime()
  loadCurrentWeather()
  clockTimer = window.setInterval(updateCurrentDateTime, 1000)
  weatherTimer = window.setInterval(loadCurrentWeather, 30 * 60 * 1000)
  screenAutofit = autofit.init({
    dh: 1080,
    dw: 1920,
    el: "#large-screen",
    resize: true,
    cssMode: "zoom",
  })
  bindPlatformFullscreenEvents()
  syncPlatformFullscreenState()
  resetRootScroll()
  if (!usesPlatformStartupLoading(activeModuleKey.value)) {
    loadingHideStarted = true
    loadingProgress.value = 100
    loadingVisible.value = false
  } else {
    scheduleLoadingSafetyHide(activeModuleKey.value)
  }
})

onBeforeUnmount(() => {
  if (clockTimer) window.clearInterval(clockTimer)
  if (weatherTimer) window.clearInterval(weatherTimer)
  clearLoadingSafetyTimer()
  screenAutofit?.off?.("#large-screen")
  unbindPlatformFullscreenEvents()
  gsap.killTweensOf(loadingTweenState)
})

function updateCurrentDateTime() {
  const date = new Date()
  const pad = (value) => String(value).padStart(2, "0")
  const weekdays = ["周日", "周一", "周二", "周三", "周四", "周五", "周六"]
  currentDate.value = `${date.getFullYear()}.${pad(date.getMonth() + 1)}.${pad(date.getDate())} ${weekdays[date.getDay()]}`
  currentTime.value = `${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`
}

async function loadCurrentWeather() {
  try {
    weather.value = await getCurrentWeather()
    weatherAvailable.value = true
    weatherIconFailed.value = false
  } catch (error) {
    weatherAvailable.value = false
    console.warn("[platform] weather unavailable", error)
  }
}

function handleWeatherIconError() {
  weatherIconFailed.value = true
}

function handleMenuSelect(key, options = {}) {
  const nextKey = resolvePlatformModuleKey(key)
  const shouldShowHomeDefaultThreeMap = nextKey === "home" && !options.fromRoute
  if (nextKey === "yak-management" && !options.fromRoute) {
    activeYakView.value = "structure"
  }
  if (nextKey === activeModuleKey.value) {
    if (shouldShowHomeDefaultThreeMap) showHomeDefaultThreeMap()
    syncPlatformRoute(nextKey)
    return
  }
  activeModuleKey.value = nextKey
  renderModule(nextKey)
  syncPlatformRoute(nextKey)
  if (shouldShowHomeDefaultThreeMap) showHomeDefaultThreeMap()
  nextTick(resetRootScroll)
}

function handleTopMenuItemClick(key) {
  if (resolvePlatformModuleKey(key) === "home" && activeModuleKey.value === "home") {
    showHomeDefaultThreeMap()
  }
}

function handleBottomMenuSelect(item) {
  if (!item?.key) return
  if (activeModuleKey.value === "ecological-protection") {
    handleEcologyViewChange(item.key)
    return
  }
  handleMenuSelect(item.key)
}

function handleEcologyViewChange(key) {
  const nextKey = ecologicalProtectionMenu.some((item) => item.key === key) ? key : "ecological-redline"
  if (nextKey === activeEcologyView.value && activeModuleKey.value === "ecological-protection") return
  activeEcologyView.value = nextKey
  if (activeModuleKey.value === "ecological-protection") {
    syncPlatformRoute("ecological-protection")
  }
  nextTick(resetRootScroll)
}

function handleYakViewChange(key) {
  const nextKey = resolveYakViewKey(key)
  if (nextKey === activeYakView.value) return
  activeYakView.value = nextKey
  if (activeModuleKey.value === "yak-management") {
    syncPlatformRoute("yak-management")
  }
}

watch(
  () => [route.query.module, route.query.view],
  ([moduleKey, viewKey]) => {
    const nextModuleKey = resolvePlatformModuleKey(moduleKey)
    if (nextModuleKey === "ecological-protection") {
      activeEcologyView.value = resolveEcologyViewKey(viewKey)
    }
    if (nextModuleKey === "yak-management") {
      activeYakView.value = resolveYakViewKey(viewKey)
    }
    if (nextModuleKey !== activeModuleKey.value) {
      handleMenuSelect(nextModuleKey, { fromRoute: true })
    }
  },
)

function syncPlatformRoute(moduleKey = activeModuleKey.value) {
  const nextQuery = { ...route.query, module: moduleKey }
  if (moduleKey === "yak-management") {
    nextQuery.view = activeYakView.value
  } else if (moduleKey === "ecological-protection") {
    nextQuery.view = activeEcologyView.value
  } else {
    delete nextQuery.view
  }
  const currentQuery = route.query || {}
  const sameQuery = String(currentQuery.module || "") === String(nextQuery.module || "")
    && String(currentQuery.view || "") === String(nextQuery.view || "")
  if (route.path === "/platform" && sameQuery) return
  router.replace({ path: "/platform", query: nextQuery }).catch(() => {})
}

function resolvePlatformModuleKey(key) {
  const value = Array.isArray(key) ? key[0] : key
  return platformModules.some((item) => item.key === value) ? value : "home"
}

function resolveYakViewKey(key) {
  const value = Array.isArray(key) ? key[0] : key
  return ["structure", "forecast", "epidemic", "trade"].includes(value) ? value : "structure"
}

function resolveEcologyViewKey(key) {
  const value = Array.isArray(key) ? key[0] : key
  return ecologicalProtectionMenu.some((item) => item.key === value) ? value : "ecological-redline"
}

function handleModuleStats(payload) {
  const moduleKey = payload.moduleKey || (payload.topicKey ? "forest-grass-wet" : activeModuleKey.value)
  moduleTopStats.value = {
    ...moduleTopStats.value,
    [moduleKey]: buildTopCountItems(payload.items || []),
  }
}

function handleHomeLoadingProgress(payload = {}) {
  const nextProgress = typeof payload === "number" ? payload : payload.progress
  updateLoadingProgress(nextProgress)
}

function handleHomeMapReady() {
  clearLoadingSafetyTimer()
  gsap.killTweensOf(loadingTweenState)
  loadingTweenState.progress = 100
  loadingProgress.value = 100
  const elapsed = Date.now() - loadingStartedAt
  const delay = Math.max(80, minLoadingVisibleMs - elapsed)
  window.setTimeout(hidePlatformLoading, delay)
}

function updateLoadingProgress(progress) {
  if (!loadingVisible.value) return
  const nextProgress = Math.max(0, Math.min(100, Math.floor(Number(progress) || 0)))
  if (nextProgress < loadingProgress.value) return
  gsap.to(loadingTweenState, {
    progress: nextProgress,
    duration: 0.35,
    ease: "power2.out",
    onUpdate: () => {
      loadingProgress.value = Math.floor(loadingTweenState.progress)
    },
  })
}

function hidePlatformLoading() {
  if (!loadingVisible.value || loadingHideStarted) return
  clearLoadingSafetyTimer()
  loadingHideStarted = true
  const tl = gsap.timeline({
    onComplete: () => {
      loadingVisible.value = false
    },
  })
  tl.to(".platform-loading .loading-text span", {
    y: "200%",
    opacity: 0,
    ease: "power4.inOut",
    duration: 0.45,
    stagger: 0.035,
  })
  tl.to(
    ".platform-loading .loading-progress",
    { opacity: 0, ease: "power4.inOut", duration: 0.3 },
    "<",
  )
  tl.to(
    ".platform-loading",
    { opacity: 0, ease: "power4.inOut", duration: 0.28 },
    "-=0.12",
  )
}

function usesPlatformStartupLoading(moduleKey) {
  return platformLoadingModuleKeys.has(moduleKey)
}

function scheduleLoadingSafetyHide(moduleKey) {
  clearLoadingSafetyTimer()
  const timeout = moduleKey === "home" ? 12000 : 8000
  loadingSafetyTimer = window.setTimeout(() => {
    if (!loadingVisible.value || loadingHideStarted) return
    gsap.killTweensOf(loadingTweenState)
    loadingTweenState.progress = 100
    loadingProgress.value = 100
    window.setTimeout(hidePlatformLoading, 120)
  }, timeout)
}

function clearLoadingSafetyTimer() {
  if (!loadingSafetyTimer) return
  window.clearTimeout(loadingSafetyTimer)
  loadingSafetyTimer = null
}

function buildTopCountItems(items = []) {
  const usedIcons = new Set()
  return items.slice(0, 10).map((item, index) => {
    const value = Number(item.value) || 0
    const normalized = {
      zh: item.zh || item.name || `指标${index + 1}`,
      en: item.en || "",
      value,
      unit: item.unit || "",
      decimals: item.decimals ?? (Number.isInteger(value) ? 0 : 2),
    }
    const icon = resolveUniqueTopStatIcon({ ...item, ...normalized }, index, usedIcons)
    usedIcons.add(icon)
    return {
      icon,
      ...normalized,
    }
  })
}

function resolveUniqueTopStatIcon(item = {}, index = 0, usedIcons = new Set()) {
  const candidates = getTopStatIconCandidates(item, index)
  const freshIcon = candidates.find((icon) => topStatIconSet.has(icon) && !usedIcons.has(icon))
  if (freshIcon) return freshIcon
  return topStatIconPool.find((icon) => !usedIcons.has(icon)) || topStatIconPool[index % topStatIconPool.length]
}

function getTopStatIconCandidates(item = {}, index = 0) {
  const text = `${item.zh || item.name || ""}${item.unit || ""}`
  const candidates = []
  const pushIcons = (...icons) => {
    icons.forEach((icon) => {
      if (icon && !candidates.includes(icon)) candidates.push(icon)
    })
  }

  pushIcons(item.icon)
  if (/风险|预警|告警/.test(text)) pushIcons("risk", "rate")
  if (/模型|修正|共识|预测|变化|净/.test(text)) pushIcons("rate", "stack")
  if (/率|占比|比例|超载/.test(text)) pushIcons("rate", "project")
  if (/生态牧场|家庭生态/.test(text)) pushIcons("leaf", "town")
  if (/出证|证书|证/.test(text)) pushIcons("certificate", "project")
  if (/交易|销售/.test(text)) pushIcons("yield", "certificate")
  if (/流通|出栏|流出/.test(text)) pushIcons("length", "certificate", "project")
  if (/运输|车辆|无人机|识别|设备|监测/.test(text)) pushIcons("device", "length")
  if (/工程长度|长度|公里/.test(text)) pushIcons("length", "project")
  if (/修复项目|项目|工程|治理/.test(text)) pushIcons("project", "length")
  if (/国家公园|保护范围|保护区|划定/.test(text)) pushIcons("park", "leaf")
  if (/产量|库容|鲜草|饲草|收入|产值|繁殖|补充/.test(text)) pushIcons("yield", "leaf")
  if (/湿地/.test(text)) pushIcons("wetland", "leaf")
  if (/基本草原/.test(text)) pushIcons("grass-basic", "area")
  if (/一般草原/.test(text)) pushIcons("grass-general", "area")
  if (/林地|森林|公益林/.test(text)) pushIcons("forest", "leaf")
  if (/面积|草地|草原|草场|万亩|亩/.test(text)) pushIcons("area", "grass-basic", "grass-general")
  if (/牦牛|存栏|头|结构/.test(text)) pushIcons("stack", "yield", "leaf")
  if (/乡镇|镇域|村|点位|主体|牧户|农户|联户|户|个|覆盖/.test(text)) pushIcons("town", "project")
  if (/生态|林草/.test(text)) pushIcons("leaf", "wetland")

  const start = index % topStatIconPool.length
  pushIcons(...topStatIconPool.slice(start), ...topStatIconPool.slice(0, start))
  return candidates
}

function renderModule(key) {
  if (!["home", "forest-grass-wet", "ecological-protection", "grass-livestock-balance", "yak-management", "pasture-management", "yak-industry-chain", "smart-management"].includes(key)) return
  renderedModuleOrder = renderedModuleOrder.filter((moduleKey) => moduleKey !== key)
  renderedModuleOrder.push(key)
  renderedModuleOrder = renderedModuleOrder.slice(-maxRetainedModules)
  renderedModules.value = Object.fromEntries(
    renderedModuleOrder.map((moduleKey) => [moduleKey, true]),
  )
}

function resetRootScroll() {
  window.scrollTo(0, 0)
  document.documentElement.scrollTop = 0
  document.body.scrollTop = 0
  const app = document.querySelector("#app")
  if (app) app.scrollTop = 0
}

function showHomeDefaultThreeMap(retries = 4) {
  nextTick(() => {
    const homeDashboard = homeDashboardRef.value
    if (homeDashboard?.showDefaultThreeMap) {
      homeDashboard.showDefaultThreeMap()
      return
    }
    if (retries > 0) {
      window.setTimeout(() => showHomeDefaultThreeMap(retries - 1), 80)
    }
  })
}

const platformFullscreenEvents = ["fullscreenchange", "webkitfullscreenchange", "mozfullscreenchange", "MSFullscreenChange"]

function getPlatformFullscreenElement() {
  if (typeof document === "undefined") return null
  return document.fullscreenElement
    || document.webkitFullscreenElement
    || document.mozFullScreenElement
    || document.msFullscreenElement
    || null
}

function syncPlatformFullscreenState() {
  const fullscreenElement = getPlatformFullscreenElement()
  const root = platformScreenRef.value
  platformFullscreen.value = Boolean(root && fullscreenElement && (
    fullscreenElement === root
    || root.contains(fullscreenElement)
    || fullscreenElement.contains?.(root)
  ))
}

function bindPlatformFullscreenEvents() {
  if (typeof document === "undefined") return
  platformFullscreenEvents.forEach((eventName) => document.addEventListener(eventName, syncPlatformFullscreenState))
}

function unbindPlatformFullscreenEvents() {
  if (typeof document === "undefined") return
  platformFullscreenEvents.forEach((eventName) => document.removeEventListener(eventName, syncPlatformFullscreenState))
}

function refreshYakMapAfterResize() {
  getActiveMapModuleRef()?.refreshMapView?.()
}

async function handlePlatformFullscreen() {
  if (typeof document === "undefined") return
  const fullscreenElement = getPlatformFullscreenElement()
  try {
    if (fullscreenElement) {
      const exitFullscreen = document.exitFullscreen
        || document.webkitExitFullscreen
        || document.mozCancelFullScreen
        || document.msExitFullscreen
      await exitFullscreen?.call(document)
    } else {
      const target = platformScreenRef.value || document.documentElement
      const requestFullscreen = target.requestFullscreen
        || target.webkitRequestFullscreen
        || target.mozRequestFullScreen
        || target.msRequestFullscreen
      await requestFullscreen?.call(target)
    }
  } catch (error) {
    console.warn("[platform] fullscreen toggle failed", error)
  } finally {
    syncPlatformFullscreenState()
    window.setTimeout(refreshYakMapAfterResize, 80)
    window.setTimeout(refreshYakMapAfterResize, 280)
  }
}

function handleActiveMapReset() {
  getActiveMapModuleRef()?.resetMap?.()
}

function getActiveMapModuleRef() {
  if (activeModule.value.key === "home") return homeDashboardRef.value
  if (activeModule.value.key === "forest-grass-wet") return forestGrassWetRef.value
  if (activeModule.value.key === "ecological-protection") return ecologicalProtectionRef.value
  if (activeModule.value.key === "yak-management") return yakManagementRef.value
  if (activeModule.value.key === "pasture-management") return pastureManagementRef.value
  if (activeModule.value.key === "yak-industry-chain") return yakIndustryChainRef.value
  return null
}

function handleLogout() {
  logout()
}
</script>

<style lang="scss">
.platform-screen {
  position: fixed !important;
  left: 0;
  top: 0;
  margin: 0;

  // In the standalone reference page this texture sits behind the cards. The
  // platform shell renders modules as siblings, so the same pseudo-element
  // would otherwise cover every module and mute all text, charts and borders.
  > .large-screen-wrap::after {
    content: none;
  }

  &.is-forest-grass-wet {
    .large-screen-wrap::after {
      opacity: 0.28;
    }

    .large-screen-left-zsline,
    .large-screen-right-zsline {
      filter: brightness(1.3) drop-shadow(0 0 14px rgba(48, 220, 255, 0.32));
    }
  }

  &.is-home {
    .large-screen-wrap::after {
      opacity: 0.34;
    }

    .large-screen-left-zsline,
    .large-screen-right-zsline {
      filter: brightness(1.32) drop-shadow(0 0 16px rgba(36, 246, 196, 0.28));
    }
  }

  &.is-ecological-protection {
    .large-screen-wrap::after {
      opacity: 0.22;
    }
  }

  &.is-ecology-national-park {
    .top-menu-mid-space {
      width: 920px;
    }
  }

  &.is-grass-livestock-balance {
    .large-screen-wrap::after {
      opacity: 0.24;
    }

    .large-screen-left-zsline,
    .large-screen-right-zsline {
      filter: brightness(1.24) drop-shadow(0 0 14px rgba(255, 215, 108, 0.18));
    }
  }

  &.is-yak-management {
    .large-screen-wrap::after {
      opacity: 0.24;
    }

    .large-screen-left-zsline,
    .large-screen-right-zsline {
      filter: brightness(1.22) drop-shadow(0 0 14px rgba(48, 220, 255, 0.26));
    }
  }

  &.is-pasture-management {
    .large-screen-wrap::after {
      opacity: 0.26;
    }

    .large-screen-left-zsline,
    .large-screen-right-zsline {
      filter: brightness(1.28) drop-shadow(0 0 14px rgba(36, 246, 196, 0.28));
    }
  }

  &.is-yak-industry-chain {
    .large-screen-wrap::after {
      opacity: 0.24;
    }

    .large-screen-left-zsline,
    .large-screen-right-zsline {
      filter: brightness(1.28) drop-shadow(0 0 14px rgba(48, 220, 255, 0.24));
    }
  }

  &.is-smart-management {
    .large-screen-wrap::after {
      opacity: 0.2;
    }
  }

  .platform-module-pane {
    position: absolute;
    inset: 0;
    z-index: 1;
  }

  // Full-screen business dialogs must sit above the shared header, KPI rail,
  // navigation and map controls that live in .large-screen-wrap.
  .platform-module-pane:has(.home-more-modal) {
    z-index: 120;
  }

  .platform-map-tools {
    position: absolute;
    left: 448px;
    bottom: 168px;
    z-index: 80;
    display: flex;
    flex-direction: column;
    gap: 7px;
    pointer-events: all;
    transform: perspective(var(--screen-side-perspective-left, 500px)) rotateY(6deg);
    transform-origin: left center;

    button {
      display: inline-flex;
      align-items: center;
      justify-content: center;
      width: 34px;
      height: 34px;
      padding: 0;
      border: 1px solid rgba(126, 251, 246, 0.62);
      border-radius: 3px;
      color: #f0feff;
      font-weight: 900;
      background:
        linear-gradient(180deg, rgba(18, 99, 123, 0.92), rgba(4, 36, 56, 0.96)),
        rgba(4, 24, 37, 0.9);
      box-shadow:
        0 0 14px rgba(48, 220, 255, 0.32),
        0 0 3px rgba(126, 251, 246, 0.4),
        inset 0 0 0 1px rgba(255, 255, 255, 0.1),
        inset 0 -8px 14px rgba(48, 220, 255, 0.16);
      cursor: pointer;

      &:hover {
        border-color: rgba(126, 251, 246, 0.76);
        color: #ffffff;
        background:
          linear-gradient(180deg, rgba(25, 127, 148, 0.96), rgba(6, 48, 68, 0.98)),
          rgba(6, 35, 52, 0.92);
        box-shadow:
          0 0 18px rgba(48, 220, 255, 0.42),
          0 0 4px rgba(126, 251, 246, 0.5),
          inset 0 0 0 1px rgba(255, 255, 255, 0.12),
          inset 0 -8px 14px rgba(48, 220, 255, 0.18);
      }

      &:active {
        transform: translateY(1px);
      }
    }
  }

  &:has(.engineering-analysis-panel) .platform-map-tools {
    left: 510px;
    bottom: 168px;
    transform: none;
  }

  &:has(.home-more-modal) {
    .platform-map-tools {
      visibility: hidden;
      opacity: 0;
      pointer-events: none;
    }
  }

  .platform-map-tool-icon {
    position: relative;
    flex: 0 0 15px;
    width: 15px;
    height: 15px;
    color: #7efbf6;

    &.is-fullscreen {
      background:
        linear-gradient(currentColor, currentColor) left top / 5px 2px no-repeat,
        linear-gradient(currentColor, currentColor) left top / 2px 5px no-repeat,
        linear-gradient(currentColor, currentColor) right top / 5px 2px no-repeat,
        linear-gradient(currentColor, currentColor) right top / 2px 5px no-repeat,
        linear-gradient(currentColor, currentColor) left bottom / 5px 2px no-repeat,
        linear-gradient(currentColor, currentColor) left bottom / 2px 5px no-repeat,
        linear-gradient(currentColor, currentColor) right bottom / 5px 2px no-repeat,
        linear-gradient(currentColor, currentColor) right bottom / 2px 5px no-repeat;
    }

    &.is-reset {
      width: 15px;
      height: 15px;
      border: 2px solid currentColor;
      border-left-color: transparent;
      border-radius: 50%;
      box-sizing: border-box;

      &::after {
        content: "";
        position: absolute;
        left: -2px;
        top: 0;
        width: 0;
        height: 0;
        border-top: 3px solid transparent;
        border-bottom: 3px solid transparent;
        border-right: 5px solid currentColor;
        transform: rotate(-18deg);
      }
    }
  }

  .top-menu {
    position: absolute;
    left: 50%;
    top: 46px;
    z-index: 10;
    transform: translateX(-50%);

    .m-menu {
      justify-content: center;
      align-items: center;
    }

    .m-menu-item {
      min-width: 118px;
      height: 34px;
      padding: 0 18px;
      font-size: 14px;
      line-height: 34px;
      letter-spacing: 0;
    }

    .m-menu-item.is-active::after {
      width: calc(100% - 12px);
      height: 28px;
      margin-left: calc(-50% + 6px);
      margin-top: -14px;
      border-radius: 28px;
      transform: none;
      animation: platformMenuActivePulse 1.35s ease-in-out infinite;
    }

    .top-menu-mid-space {
      width: 820px;
      height: 1px;
      pointer-events: none;
    }
  }

  .m-header-right {
    top: 5px;
    right: 14px;
    z-index: 30;
  }

  .m-header-tools {
    display: flex;
    align-items: center;
    gap: 8px;
    min-height: 42px;
    pointer-events: auto;
  }

  .platform-weather {
    position: relative;
    display: flex;
    align-items: center;
    gap: 8px;
    height: 40px;
    min-width: 184px;
    padding: 0 12px 0 4px;
    color: rgba(229, 250, 255, 0.9);
    white-space: nowrap;

    &::after {
      content: "";
      position: absolute;
      left: 4px;
      right: 12px;
      bottom: 0;
      height: 1px;
      background: linear-gradient(90deg, rgba(48, 220, 255, 0.72), rgba(48, 220, 255, 0));
      opacity: 0.54;
    }

    &.is-unavailable {
      min-width: 150px;
      color: rgba(196, 243, 254, 0.58);
    }
  }

  .platform-weather__icon {
    width: 34px;
    height: 34px;
    flex: none;
    object-fit: contain;
    filter: drop-shadow(0 0 8px rgba(48, 220, 255, 0.26));
  }

  .platform-weather__fallback-icon {
    position: relative;
    width: 30px;
    height: 24px;
    flex: none;

    &::before {
      content: "";
      position: absolute;
      left: 2px;
      bottom: 2px;
      width: 24px;
      height: 10px;
      border: 1px solid rgba(92, 232, 255, 0.72);
      border-radius: 8px;
      box-shadow: 0 0 8px rgba(48, 220, 255, 0.18);
    }

    &::after {
      content: "";
      position: absolute;
      left: 8px;
      top: 2px;
      width: 11px;
      height: 11px;
      border: 1px solid rgba(92, 232, 255, 0.72);
      border-radius: 50%;
      background: rgba(8, 42, 58, 0.9);
    }
  }

  .platform-weather__copy {
    display: grid;
    align-content: center;
    gap: 1px;
    min-width: 0;
  }

  .platform-weather__primary {
    display: inline-flex;
    align-items: center;
    gap: 8px;

    strong {
      color: #f2fdff;
      font-size: 13px;
      font-weight: 700;
      line-height: 17px;
    }

    em {
      color: #69eff2;
      font-family: var(--screen-font-number, D-DIN, Arial, sans-serif);
      font-size: 19px;
      font-style: normal;
      font-weight: 800;
      line-height: 19px;
    }
  }

  .platform-weather__copy small {
    display: flex;
    align-items: center;
    gap: 6px;
    color: rgba(196, 243, 254, 0.62);
    font-size: 10px;
    font-weight: 400;
    line-height: 13px;

    i {
      width: 2px;
      height: 2px;
      border-radius: 50%;
      background: rgba(92, 232, 255, 0.6);
      box-shadow: 0 0 4px rgba(48, 220, 255, 0.4);
    }
  }

  .platform-datetime {
    position: relative;
    display: grid;
    justify-items: end;
    align-content: center;
    gap: 0;
    width: 112px;
    height: 40px;
    padding: 0 10px 0 13px;
    white-space: nowrap;

    &::before {
      content: "";
      position: absolute;
      left: 0;
      top: 9px;
      width: 1px;
      height: 22px;
      background: linear-gradient(180deg, transparent, rgba(92, 232, 255, 0.52), transparent);
    }

    span {
      color: rgba(196, 243, 254, 0.64);
      font-size: 10px;
      line-height: 13px;
    }

    strong {
      color: #ecfcff;
      font-family: var(--screen-font-number, D-DIN, Arial, sans-serif);
      font-size: 19px;
      font-weight: 800;
      line-height: 21px;
      text-align: right;
      text-shadow: 0 0 8px rgba(48, 220, 255, 0.18);
    }
  }

  .logout-button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    padding: 0;
    border: 1px solid rgba(92, 232, 255, 0.72);
    border-radius: 2px;
    background:
      linear-gradient(180deg, rgba(28, 126, 166, 0.62), rgba(3, 32, 55, 0.86)),
      rgba(2, 18, 34, 0.72);
    box-shadow: inset 0 0 13px rgba(48, 220, 255, 0.18), 0 0 12px rgba(48, 220, 255, 0.2);
    color: #e7fbff;
    cursor: pointer;
    transition: border-color 0.18s ease, color 0.18s ease, box-shadow 0.18s ease, transform 0.18s ease;
  }

  .logout-icon {
    width: 18px;
    height: 18px;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.9;
    stroke-linecap: round;
    stroke-linejoin: round;
  }

  .logout-button:hover {
    border-color: rgba(48, 220, 255, 0.78);
    box-shadow: inset 0 0 14px rgba(48, 220, 255, 0.16), 0 0 14px rgba(48, 220, 255, 0.22);
    color: #fff;
    transform: translateY(-1px);
  }

  .top-count-card {
    left: 432px;
    right: 432px;
    top: 108px;
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    column-gap: 28px;
    justify-content: stretch;

    & > div {
      min-width: 0;
      padding: 0 !important;
      justify-content: center;
    }

    .count-card {
      min-width: 0;
      min-height: 90px;

      &:before {
        content: none;
      }
    }

    .count-card-title,
    .count-card-left,
    .count-card-right {
      min-width: 0;
    }

    .count-card-icon {
      width: 76px;
      height: 90px;
      flex-basis: 76px;
      margin-right: 2px;
    }

    .count-card-right {
      padding-left: 10px;
    }

    .count-card-right .value {
      min-height: 34px;
      margin-right: 6px;
      font-size: var(--screen-kpi-value-size, 31px);
      line-height: 34px;
      letter-spacing: 0;
    }

    .count-card-right .unit {
      padding-top: 10px;
      font-size: var(--screen-kpi-unit-size, 11px);
      line-height: 1;
    }

    .count-card-title .title-zh {
      font-size: var(--screen-kpi-label-size, 14px);
      line-height: 18px;
    }

    .count-card-title .title-en {
      max-width: 112px;
      overflow: hidden;
      text-overflow: ellipsis;
    }

    &.is-four {
      left: 432px;
      right: 432px;
      top: 102px;
      grid-template-columns: repeat(4, minmax(0, 1fr));
      column-gap: 12px;

      .count-card-icon {
        width: 58px;
        height: 78px;
        flex-basis: 58px;
        margin-right: 0;
      }

      .count-card-right {
        padding-left: 4px;
      }

      .count-card-right .value {
        min-height: 34px;
        font-size: var(--screen-kpi-four-value-size, 29px);
        line-height: 34px;
        margin-right: 4px;
      }

      .count-card-right .unit {
        padding-top: 9px;
        font-size: var(--screen-kpi-four-unit-size, 10px);
      }

      .count-card-title .title-zh {
        font-size: var(--screen-kpi-four-label-size, 13px);
        line-height: 17px;
        white-space: nowrap;
      }

      .count-card-title .title-en {
        max-width: 90px;
        font-size: 10px;
      }
    }

    &.is-multi {
      left: 432px;
      right: 432px;
      top: 102px;
      grid-template-columns: repeat(5, minmax(0, 1fr));
      grid-auto-rows: 72px;
      column-gap: 10px;
      row-gap: 8px;
      z-index: 8;

      & > div {
        justify-content: center;
      }

      .count-card {
        min-height: 72px;
      }

      .count-card-left {
        flex: 0 0 auto;
      }

      .count-card-icon {
        display: block;
        width: 64px;
        height: 72px;
        flex-basis: 64px;
        margin-right: 0;
      }

      .count-card-right {
        flex: 0 0 auto;
        padding-left: 4px;
      }

      .count-card-right .value {
        min-height: 34px;
        margin-right: 4px;
        font-size: var(--screen-kpi-value-size, 31px);
        line-height: 34px;
      }

      .count-card-right .unit {
        padding-top: 9px;
        font-size: var(--screen-kpi-unit-size, 11px);
        opacity: 0.72;
      }

      .count-card-title .title-zh {
        max-width: none;
        font-size: var(--screen-kpi-label-size, 14px);
        line-height: 1.18;
        white-space: nowrap;
      }

      .count-card-title .title-en {
        display: none;
      }

      & > div:nth-child(6) {
        grid-column: 2;
      }

      & > div:nth-child(7) {
        grid-column: 3;
      }

      & > div:nth-child(8) {
        grid-column: 4;
      }
    }

    &.is-count-five > div {
      justify-content: center;
    }

    &.is-home-five {
      left: 432px;
      right: 432px;
      top: 102px;
      display: grid;
      grid-template-columns: repeat(5, minmax(0, 1fr));
      grid-auto-rows: auto;
      column-gap: 12px;
      row-gap: 0;
      justify-content: stretch;
      align-items: center;
      z-index: 9;

      & > div {
        width: 100%;
        min-width: 0;
        justify-content: center;
      }

      .count-card {
        min-height: 76px;
      }

      .count-card-left {
        flex: 0 0 auto;
      }

      .count-card-icon {
        width: 72px;
        height: 80px;
        flex-basis: 72px;
        margin-right: 4px;
      }

      .count-card-right {
        flex: 0 0 auto;
        padding-left: 6px;
      }

      .count-card-right .value {
        min-height: 34px;
        font-size: var(--screen-kpi-value-size, 31px);
        line-height: 34px;
      }

      .count-card-right .unit {
        padding-top: 9px;
        font-size: var(--screen-kpi-unit-size, 11px);
      }

      .count-card-title .title-zh {
        max-width: none;
        font-size: var(--screen-kpi-label-size, 14px);
        line-height: 18px;
        white-space: nowrap;
      }

      .count-card-title .title-en {
        display: none;
      }
    }

  }

  &.is-home {
    .top-count-card.is-home-five {
      left: 432px;
      right: 432px;
      top: 82px;
      display: grid;
      grid-template-columns: repeat(5, minmax(0, 1fr));
      column-gap: 12px;
      justify-items: start;
      align-items: center;

      & > div {
        width: 100%;
        min-width: 0;
        justify-content: flex-start;
      }

      .count-card {
        width: 100%;
        min-height: 74px;
        justify-content: flex-start;
      }

      .count-card-icon {
        width: 58px;
        height: 72px;
        flex-basis: 58px;
        margin-right: 2px;
      }

      .count-card-right {
        padding-left: 3px;
      }

      .count-card-right .value {
        font-size: 28px;
        line-height: 31px;
      }

      .count-card-right .unit {
        padding-top: 8px;
        font-size: 10px;
      }

      .count-card-title .title-zh {
        font-size: 13px;
        line-height: 17px;
      }
    }
  }

  &.is-ecology-national-park {
    .top-count-card.is-home-five {
      left: 432px;
      right: 432px;
      top: 96px;
      display: grid;
      grid-template-columns: repeat(5, minmax(0, 1fr));
      column-gap: 12px;
      justify-content: stretch;

      & > div {
        min-width: 0;
        zoom: 0.88;
      }
    }
  }

  .bottom-menu-item {
    width: 96px !important;
    margin: 0 2px;

    span {
      width: 96px !important;
      font-size: 13px;
    }
  }

  .bottom-svg-line-left,
  .bottom-svg-line-right {
    position: absolute;
    right: 50%;
    bottom: -21px;
    width: 721px;
    height: 57px;
    margin-right: -5px;
  }

  .bottom-svg-line-right {
    left: 50%;
    right: inherit;
    margin-left: -5px;
    margin-right: inherit;
    transform: scaleX(-1);
  }

  .module-coming {
    position: absolute;
    left: 50%;
    top: 50%;
    z-index: 12;
    width: 360px;
    height: 130px;
    padding-top: 28px;
    border: 1px solid rgba(48, 220, 255, 0.28);
    background: rgba(3, 18, 30, 0.72);
    color: #fff;
    text-align: center;
    transform: translate(-50%, -50%);
    pointer-events: none;
    box-sizing: border-box;
  }

  .module-coming-title {
    font-size: 24px;
    font-weight: 700;
  }

  .module-coming-text {
    margin-top: 12px;
    color: rgba(255, 255, 255, 0.62);
    font-size: 14px;
  }

  .platform-loading {
    position: absolute;
    z-index: 99;

    .loading-text {
      gap: 10px;
      letter-spacing: 0;
    }
  }
}

@keyframes platformMenuActivePulse {
  0% {
    opacity: 0.68;
    box-shadow: 0 0 0 rgba(0, 170, 255, 0);
  }

  58% {
    opacity: 0.38;
    box-shadow: 0 0 14px rgba(48, 220, 255, 0.36);
  }

  100% {
    opacity: 0;
    box-shadow: 0 0 22px rgba(48, 220, 255, 0.12);
  }
}
</style>
