<template>
  <div class="yak-industry-chain">
    <map-scene
      ref="mapSceneRef"
      class="industry-map-scene"
      :active-layer="industryMapLayer"
      :map-ranking="mapRanking"
      :admin-boundary-line-scale="1.65"
      :auto-apply-layer-map-view="false"
      :max-zoom="21"
      @feature-info="handleMapFeatureInfo"
    />
    <div class="industry-map-scrim"></div>
    <div v-if="!mapReady" class="industry-map-loading">3D地图加载中</div>

    <div v-if="leftStagePanels.length" class="fgw-left industry-side-panel industry-side-panel--left">
      <div class="fgw-side-stack industry-side-stack is-left">
        <m-card
          v-for="panel in leftStagePanels"
          :key="panel.key"
          class="fgw-side-card industry-side-card left-card"
          :class="`industry-side-card--${panel.key}`"
          :title="panel.title"
          :width="sideCardWidth"
          :height="panel.height"
        >
          <v-chart
            v-if="isTownColumnPanel(panel) && hasTownColumnData(panel)"
            class="industry-town-column-chart"
            :option="createTownColumnOption(panel)"
            :autoresize="true"
          />
          <div v-else-if="isTownColumnPanel(panel)" class="industry-panel-empty">
            暂无业务统计数据
          </div>
          <business-panel-renderer
            v-else-if="panel.renderer === 'business'"
            :panel="panel"
            compact
            @row-select="handlePanelRowSelect"
          />
          <div v-else-if="panel.renderer === 'featured'" class="industry-featured-base-list">
            <button
              v-for="(item, index) in panel.rows"
              :key="item.key"
              class="industry-featured-base"
              :class="{ 'is-active': selectedFeaturedBaseKey === item.key }"
              type="button"
              :disabled="!item.point"
              :aria-label="`查看${item.name}`"
              @click="handleFeaturedBaseSelect(item)"
            >
              <span class="industry-featured-base__index">{{ `0${index + 1}` }}</span>
              <span class="industry-featured-base__copy">
                <strong>{{ item.name }}</strong>
                <em>{{ item.town }} · {{ item.tag }}</em>
                <small>{{ item.summary }}</small>
              </span>
            </button>
          </div>
          <div v-else-if="panel.renderer === 'leadershipMode'" class="industry-leadership-mode-list">
            <div v-for="(item, index) in panel.rows" :key="item.key" class="industry-leadership-mode">
              <i :style="{ color: item.color, background: item.color }"></i>
              <span>{{ `0${index + 1}` }}</span>
              <div>
                <strong>{{ item.name }}</strong>
                <small>{{ item.description }}</small>
              </div>
            </div>
          </div>
          <div v-else-if="panel.renderer === 'ledger'" class="industry-ledger-list">
            <div v-for="item in panel.rows" :key="item.key" class="industry-ledger-row">
              <div>
                <strong>{{ item.name }}</strong>
                <span>{{ item.typeName }} / {{ item.town }}</span>
              </div>
              <em>{{ item.valueText }}</em>
            </div>
          </div>
        </m-card>
      </div>
    </div>

    <div v-if="rightStagePanels.length" class="fgw-right industry-side-panel industry-side-panel--right">
      <div class="fgw-side-stack industry-side-stack is-right">
        <m-card
          v-for="panel in rightStagePanels"
          :key="panel.key"
          class="fgw-side-card industry-side-card right-card"
          :class="`industry-side-card--${panel.key}`"
          :title="panel.title"
          :width="sideCardWidth"
          :height="panel.height"
        >
          <v-chart
            v-if="isTownColumnPanel(panel) && hasTownColumnData(panel)"
            class="industry-town-column-chart"
            :option="createTownColumnOption(panel)"
            :autoresize="true"
          />
          <div v-else-if="isTownColumnPanel(panel)" class="industry-panel-empty">
            暂无业务统计数据
          </div>
          <business-panel-renderer
            v-else-if="panel.renderer === 'business'"
            :panel="panel"
            compact
            @row-select="handlePanelRowSelect"
          />
          <div v-else-if="panel.renderer === 'featured'" class="industry-featured-base-list">
            <button
              v-for="(item, index) in panel.rows"
              :key="item.key"
              class="industry-featured-base"
              :class="{ 'is-active': selectedFeaturedBaseKey === item.key }"
              type="button"
              :disabled="!item.point"
              :aria-label="`查看${item.name}`"
              @click="handleFeaturedBaseSelect(item)"
            >
              <span class="industry-featured-base__index">{{ `0${index + 1}` }}</span>
              <span class="industry-featured-base__copy">
                <strong>{{ item.name }}</strong>
                <em>{{ item.town }} · {{ item.tag }}</em>
                <small>{{ item.summary }}</small>
              </span>
            </button>
          </div>
          <div v-else-if="panel.renderer === 'leadershipMode'" class="industry-leadership-mode-list">
            <div v-for="(item, index) in panel.rows" :key="item.key" class="industry-leadership-mode">
              <i :style="{ color: item.color, background: item.color }"></i>
              <span>{{ `0${index + 1}` }}</span>
              <div>
                <strong>{{ item.name }}</strong>
                <small>{{ item.description }}</small>
              </div>
            </div>
          </div>
          <div v-else-if="panel.renderer === 'ledger'" class="industry-ledger-list">
            <div v-for="item in panel.rows" :key="item.key" class="industry-ledger-row">
              <div>
                <strong>{{ item.name }}</strong>
                <span>{{ item.typeName }} / {{ item.town }}</span>
              </div>
              <em>{{ item.valueText }}</em>
            </div>
          </div>
        </m-card>
      </div>
    </div>

    <div v-if="isArtificialGrassland" class="industry-artificial-layer-tools">
      <layer-panel
        v-model="artificialLayerKeys"
        topic-key="yak-industry-chain"
        :layers="artificialLayerOptions"
        :width="248"
        :height="112"
        :show-legend="false"
        multiple
        compact
      />
    </div>

    <div v-if="selectedArtificialFeature && artificialFeaturePositionReady" class="industry-map-feature-info" :style="artificialFeaturePanelStyle">
      <feature-info-panel title="人工草地详情" :feature="selectedArtificialFeature" :width="460" :height="374" />
    </div>

    <div v-if="selectedPoint" class="industry-point-detail" :style="pointDetailStyle">
      <div class="industry-point-detail__head">
        <span>{{ selectedPointTitle }}</span>
        <button type="button" title="关闭" @click="clearSelectedPoint">×</button>
      </div>
      <div class="industry-point-detail__name">{{ selectedPointName }}</div>
      <div v-if="selectedBaseProfile" class="industry-point-detail__profile">
        <div class="industry-point-detail__profile-head">
          <span>基地介绍</span>
          <strong>{{ selectedBaseProfile.tag }}</strong>
        </div>
        <p>{{ selectedBaseProfile.summary }}</p>
        <img
          v-if="selectedBaseProfile.image"
          class="industry-point-detail__image"
          :src="selectedBaseProfile.image"
          :alt="`${selectedBaseProfile.name}项目资料图`"
        />
        <div class="industry-point-detail__facts">
          <div v-for="item in selectedBaseProfile.facts" :key="item.label">
            <span>{{ item.label }}</span>
            <strong>{{ item.value }}</strong>
            <small>{{ item.note }}</small>
          </div>
        </div>
        <div class="industry-point-detail__highlights">
          <span>示范亮点</span>
          <i v-for="item in selectedBaseProfile.highlights" :key="item">{{ item }}</i>
        </div>
      </div>
      <div class="industry-point-detail__grid" :class="{ 'is-family-layout': selectedPoint?.categoryCode === 'YC-FAMILY-PASTURE' }">
        <div v-for="row in selectedPointRows" :key="row.label" class="industry-point-detail__row" :class="{ 'is-wide': row.wide }">
          <span>{{ row.label }}</span>
          <strong>{{ row.value }}</strong>
        </div>
      </div>
    </div>

    <div class="industry-bottom-switcher">
      <topic-switcher
        :model-value="activeStageKey"
        :topics="stageSwitcherTopics"
        compact
        @update:model-value="handleStageSelect"
      />
    </div>
  </div>
</template>

<script setup>
import { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from "vue"
import VChart from "vue-echarts"
import mCard from "@/components/mCard/index.vue"
import MapScene from "@/components/CesiumMap/index.vue"
import BusinessPanelRenderer from "@/views/forestGrassWet/components/BusinessPanelRenderer.vue"
import FeatureInfoPanel from "@/views/forestGrassWet/components/FeatureInfoPanel.vue"
import LayerPanel from "@/views/forestGrassWet/components/LayerPanel.vue"
import TopicSwitcher from "@/views/forestGrassWet/components/TopicSwitcher.vue"
import { Assets } from "@/views/forestGrassWet/assets"
import { getLayerByKey } from "@/config/layers"
import { SCREEN2_LAYOUT, getScreen2SideCardHeight, getScreen2SpanHeight } from "@/utils/screen2Standard"
import {
  chartAxisTextColor,
  chartFontFamily,
  chartGridLineColor,
  chartNumberFontFamily,
  chartPalette,
  chartSecondaryTextColor,
  chartStrongTextColor,
  chartTextColor,
  chartTooltip,
  systemBarGradient,
  withChartDefaults,
} from "@/utils/chartTheme"
import {
  getStageDef,
  getStageTopStats,
  getFamilyPastureTownMapRows,
  getFeaturedBreedingBaseProfile,
  getStagePanelConfig,
  getPointExtraRows,
  industryStageDefs,
} from "./data"

const props = defineProps({
  active: {
    type: Boolean,
    default: true,
  },
})
const emit = defineEmits(["module-stats", "loading-progress", "map-ready"])
const sideCardWidth = SCREEN2_LAYOUT.sideCardWidth
const screenViewportHeight = ref(typeof window === "undefined" ? 1080 : window.innerHeight)
const sidePanelGap = SCREEN2_LAYOUT.sideCardGap
const sidePanelTop = SCREEN2_LAYOUT.sidePanelTop
const sidePanelBottomGap = SCREEN2_LAYOUT.sidePanelBottom
const sidePanelMinHeight = SCREEN2_LAYOUT.sideCardMinHeight
const sidePanelHeight = computed(() => getScreen2SideCardHeight(screenViewportHeight.value))
const sidePanelDoubleHeight = computed(() => getScreen2SpanHeight(sidePanelHeight.value, 2))
const sidePanelFullHeight = computed(() => getScreen2SpanHeight(sidePanelHeight.value, 4))
const activeStageKey = ref("family-pasture")
const mapSceneRef = ref(null)
const mapReady = ref(false)
const selectedPoint = ref(null)
const selectedFeaturedBaseKey = ref("")
const selectedPointScreen = ref({ x: 0, y: 0 })
const selectedArtificialFeature = ref(null)
const selectedArtificialFeatureScreen = ref({ x: 0, y: 0 })
const artificialFeaturePositionReady = ref(false)
const artificialLayerKeys = ref(["artificial-grassland-plots"])
let mapAssets = null
let mapAssetsReady = false
let mapLoadStarted = false
let mapLoadTimer = null
let pointScreenSyncFrame = null
let destroyed = false

const activeStage = computed(() => getStageDef(activeStageKey.value))
const isFamilyPasture = computed(() => activeStageKey.value === "family-pasture")
const isArtificialGrassland = computed(() => activeStageKey.value === "artificial-grassland")
const artificialLayerOptions = computed(() => [
  {
    key: "artificial-grassland-plots",
    name: "待核定种草图斑",
    color: "#30DCFF",
    stroke: "#C9FBFF",
  },
  {
    key: "yak-industry-points",
    name: "人工种草基地点",
    color: "#19FFC6",
    stroke: "#B7FFF2",
  },
])
const activePanelConfig = computed(() => getStagePanelConfig(activeStageKey.value))
const stagePanelGroups = computed(() => normalizeStagePanelGroups(activePanelConfig.value))
const leftStagePanels = computed(() => {
  const panels = stagePanelGroups.value.left
  return panels
    .filter((panel) => !panel?.placeholder)
    .map((panel) => normalizeStagePanelHeight(panel, panels.length))
})
const rightStagePanels = computed(() => {
  const panels = stagePanelGroups.value.right
  return panels.map((panel) => normalizeStagePanelHeight(panel, panels.length))
})
const industryMapLayer = computed(() => {
  const pointLayer = getLayerByKey("yak-industry-chain", "yak-industry-points")
  if (isArtificialGrassland.value) {
    const layers = []
    if (artificialLayerKeys.value.includes("artificial-grassland-plots")) {
      const plotLayer = getLayerByKey("yak-industry-chain", "artificial-grassland-plots")
      if (plotLayer) {
        layers.push({
          ...plotLayer,
          activeLegend: plotLayer.legends?.[0],
        })
      }
    }
    if (artificialLayerKeys.value.includes("yak-industry-points") && pointLayer) {
      const baseLegend = pointLayer.legends?.find((item) => item.key === "yak-industry-artificial-grassland")
      layers.push({
        ...pointLayer,
        showPointLabels: false,
        activeLegend: baseLegend,
      })
    }
    if (!layers.length) return null
    const [activeLayer, ...overlayLayers] = layers
    return {
      ...activeLayer,
      overlayLayers,
    }
  }
  const legend = pointLayer?.legends?.find((item) =>
    item.match?.value === activeStageKey.value || item.key === `yak-industry-${activeStageKey.value}`,
  )
  if (!pointLayer) return pointLayer
  return {
    ...pointLayer,
    hidePointFeatures: activeStageKey.value === "family-pasture",
    hidePointMarkers: activeStageKey.value === "family-pasture",
    showPointLabels: activeStageKey.value === "family-pasture" ? false : pointLayer.showPointLabels,
    activeLegend: legend || {
      key: `yak-industry-empty-${activeStageKey.value}`,
      name: activeStage.value.name,
      fillColor: activeStage.value.color,
      strokeColor: activeStage.value.color,
      match: { field: "stageKey", value: activeStageKey.value },
    },
  }
})
const stageSwitcherTopics = computed(() =>
  industryStageDefs.filter((stage) => stage.key !== "farm-equipment").map((stage) => ({
    key: stage.key,
    name: stage.name,
    color: stage.color,
    width: stage.width,
  }))
)
const mapRanking = computed(() => {
  const isFamilyPasture = activeStageKey.value === "family-pasture"
  const showArtificialPoints = isArtificialGrassland.value && artificialLayerKeys.value.includes("yak-industry-points")
  return {
    showTownNames: true,
    showBars: false,
    showPointMarkers: !isFamilyPasture && !isArtificialGrassland.value || showArtificialPoints,
    showMissingTownStats: isFamilyPasture,
    title: isFamilyPasture ? "家庭生态牧场" : `${activeStage.value.name}排行`,
    metricLabel: isFamilyPasture ? "生态牧场" : activeStage.value.metricLabel,
    unit: activeStage.value.unit,
    rows: isFamilyPasture ? getFamilyPastureTownMapRows() : [],
  }
})

const selectedBaseProfile = computed(() => getFeaturedBreedingBaseProfile({
  ...(selectedPoint.value || {}),
  featuredBaseKey: selectedFeaturedBaseKey.value || selectedPoint.value?.featuredBaseKey,
}))

const selectedPointRows = computed(() => {
  const point = selectedPoint.value
  if (!point) return []
  if (selectedBaseProfile.value) {
    const profile = selectedBaseProfile.value
    const baseRows = getPointExtraRows(point)
      .filter((row) => ["设计存栏", "年出栏量"].includes(row.label))
    return [
      { label: "所在地", value: `${profile.town} ${profile.village}` },
      { label: "运营单位", value: profile.operator },
      ...baseRows,
    ].filter((row) => row.value !== undefined && row.value !== null && String(row.value).trim() !== "")
  }
  if (point.categoryCode === "YC-FAMILY-PASTURE") {
    return [
      { label: "所在乡镇", value: formatDisplayText(point.town) },
      ...getPointExtraRows(point),
    ].filter((row) => row.value !== undefined && row.value !== null && String(row.value).trim() !== "")
  }
  return [
    { label: "所属环节", value: formatDisplayText(point.stageName) },
    { label: "主体类型", value: formatDisplayText(point.categoryName) },
    { label: "所在乡镇", value: formatDisplayText(point.town) },
    { label: "能力规模", value: formatCapacity(point) },
    { label: "运行状态", value: formatDisplayText(point.status) },
    ...getPointExtraRows(point),
  ].filter((row) => row.value !== undefined && row.value !== null && String(row.value).trim() !== "")
})
const selectedPointTitle = computed(() => selectedBaseProfile.value ? "重点示范基地" : formatDisplayText(selectedPoint.value?.categoryName || selectedPoint.value?.stageName))
const selectedPointName = computed(() => selectedBaseProfile.value?.name || formatDisplayText(selectedPoint.value?.name))
const pointDetailStyle = computed(() => {
  const panelWidth = 456
  const isFamilyPoint = selectedPoint.value?.categoryCode === "YC-FAMILY-PASTURE"
  const familyWideRows = selectedPointRows.value.filter((row) => row.wide).length
  const familyGridRows = Math.ceil(Math.max(0, selectedPointRows.value.length - familyWideRows) / 2) + familyWideRows
  const panelHeight = selectedBaseProfile.value
    ? selectedBaseProfile.value.image ? 576 : 532
    : isFamilyPoint
      ? Math.min(400, Math.max(318, 150 + familyGridRows * 38))
      : Math.min(520, Math.max(252, 116 + selectedPointRows.value.length * 40))
  const margin = 24
  const pointerGap = 28
  const point = {
    x: Math.max(margin, Math.min(1920 - margin, Number(selectedPointScreen.value.x || 0))),
    y: Math.max(margin, Math.min(1080 - margin, Number(selectedPointScreen.value.y || 0))),
  }
  const mapLeft = sideCardWidth + 46
  const mapRight = 1920 - sideCardWidth - 46
  const x = Math.min(Math.max(point.x - panelWidth / 2, mapLeft), mapRight - panelWidth)
  const y = Math.min(Math.max(point.y - panelHeight - pointerGap, 128), 1080 - panelHeight - 116)
  const arrowLeft = Math.min(Math.max(point.x - x, 34), panelWidth - 34)
  return {
    left: `${x}px`,
    top: `${y}px`,
    "--point-arrow-left": `${arrowLeft}px`,
    "--point-arrow-top": "100%",
    "--point-arrow-x": "-50%",
    "--point-arrow-y": "-8px",
    "--point-arrow-rotate": "45deg",
  }
})
const artificialFeaturePanelStyle = computed(() => {
  const panelWidth = 460
  const panelHeight = 374
  const mapLeft = 452
  const mapRight = 1468
  const mapTop = 116
  const mapBottom = 944
  const popupGap = 26
  const point = {
    x: Math.max(mapLeft, Math.min(mapRight, Number(selectedArtificialFeatureScreen.value.x || 960))),
    y: Math.max(128, Math.min(960, Number(selectedArtificialFeatureScreen.value.y || 540))),
  }
  const x = Math.min(Math.max(point.x - panelWidth / 2, mapLeft), mapRight - panelWidth)
  const aboveTop = point.y - panelHeight - popupGap
  const isAbove = aboveTop >= mapTop
  const y = isAbove
    ? aboveTop
    : Math.min(Math.max(point.y + popupGap, mapTop), mapBottom - panelHeight)
  const arrowLeft = Math.min(Math.max(point.x - x, 26), panelWidth - 26)
  return {
    left: `${x}px`,
    top: `${y}px`,
    "--feature-arrow-left": `${arrowLeft}px`,
    "--feature-arrow-top": isAbove ? `${panelHeight - 6}px` : "-6px",
    "--feature-arrow-rotate": isAbove ? "45deg" : "225deg",
  }
})

watch(activeStageKey, (stageKey) => {
  emitIndustryTopStats(stageKey)
}, { immediate: true })

onMounted(() => {
  updateScreenViewportHeight()
  window.addEventListener("resize", updateScreenViewportHeight)
  initIndustryMap()
})

onBeforeUnmount(() => {
  destroyed = true
  window.removeEventListener("resize", updateScreenViewportHeight)
  if (mapLoadTimer) window.clearTimeout(mapLoadTimer)
  if (pointScreenSyncFrame) window.cancelAnimationFrame(pointScreenSyncFrame)
  mapSceneRef.value?.destroyMap?.()
})

watch(
  () => props.active,
  (active) => {
    if (!mapSceneRef.value) return
    if (active) {
      scheduleIndustryMapLoad()
      mapSceneRef.value.resume?.()
    } else {
      mapSceneRef.value.pause?.()
    }
  },
)

watch(artificialLayerKeys, () => {
  clearSelectedPoint()
}, { deep: true })

function handleStageSelect(key) {
  if (key === activeStageKey.value) return
  activeStageKey.value = key
  clearSelectedPoint()
}

function normalizeStagePanelGroups(config = {}) {
  const left = filterDisplayPanels(config.left)
  const right = filterDisplayPanels(config.right)
  if (right.length) {
    return { left, right }
  }
  const panels = [...left, ...right]
  if (panels.length <= 4) {
    return { left: panels, right: [] }
  }
  return { left, right }
}

function normalizeStagePanelHeight(panel, groupCount = 0) {
  if (panel?.fixedHeight === true) {
    return {
      ...panel,
      height: sidePanelHeight.value,
    }
  }
  if (panel?.fillHeight === true) {
    return {
      ...panel,
      height: getPanelHeightForCount(groupCount),
    }
  }
  if (["projectTable", "projectLedger"].includes(panel?.type)) {
    return {
      ...panel,
      height: getProjectTablePanelHeight(panel),
    }
  }
  const isDouble = Number(panel?.height || 0) >= 400 || panel?.span === 2
  const keepSpanHeight = panel?.keepSpanHeight === true
  return {
    ...panel,
    height: groupCount === 1 && !keepSpanHeight ? sidePanelFullHeight.value : isDouble ? sidePanelDoubleHeight.value : sidePanelHeight.value,
  }
}

function getPanelHeightForCount(groupCount = 1) {
  const count = Math.max(1, Number(groupCount) || 1)
  const viewportHeight = Math.max(1080, Number(screenViewportHeight.value) || 1080)
  const availableHeight = viewportHeight - sidePanelTop - sidePanelBottomGap - sidePanelGap * Math.max(count - 1, 0)
  return Math.max(sidePanelMinHeight, Math.floor(availableHeight / count))
}

function getProjectTablePanelHeight(panel = {}) {
  if (panel?.span === 2 || panel?.keepSpanHeight === true) return sidePanelDoubleHeight.value
  const rows = Array.isArray(panel.rows) ? panel.rows : []
  const headerHeight = 100
  const rowHeight = 32
  const preferredHeight = headerHeight + 25 + rows.length * rowHeight
  return Math.min(sidePanelDoubleHeight.value, Math.max(sidePanelHeight.value, preferredHeight))
}

function filterDisplayPanels(panels = []) {
  return panels.filter(Boolean)
}

function isTownColumnPanel(panel = {}) {
  return panel?.renderer === "business" && panel?.type === "column" && panel?.variant === "townCompact"
}

function hasTownColumnData(panel = {}) {
  return Array.isArray(panel.rows) && panel.rows.some((item) => Number(item?.zero ? 0 : item?.value || 0) > 0)
}

function createTownColumnOption(panel = {}) {
  const rows = Array.isArray(panel.rows) ? panel.rows : []
  const values = rows.map((item) => Number(item?.zero ? 0 : item?.value || 0))
  const maxValue = Math.max(...values, 1)
  const unit = getSharedUnit(rows)
  return withChartDefaults({
    animationDuration: 720,
    animationEasing: "cubicOut",
    grid: {
      top: 30,
      right: 8,
      bottom: 58,
      left: 8,
      containLabel: false,
    },
    tooltip: chartTooltip((params = []) => {
      const items = Array.isArray(params) ? params : [params]
      const data = items[0]?.data || {}
      const value = data.zero ? "0" : data.displayValue
      const valueUnit = data.unit || unit || ""
      const extra = data.extra ? `<br/><span style="color:${chartSecondaryTextColor}">${data.extra}</span>` : ""
      return `${data.name || ""}<br/><b style="color:${chartStrongTextColor}">${value}${valueUnit}</b>${extra}`
    }, {
      trigger: "axis",
      axisPointer: {
        type: "shadow",
        shadowStyle: {
          color: "rgba(48, 220, 255, 0.06)",
        },
      },
      confine: true,
    }),
    graphic: unit
      ? [{
          type: "text",
          right: 10,
          top: 4,
          silent: true,
          style: {
            text: `单位：${unit}`,
            fill: chartSecondaryTextColor,
            font: `10px ${chartFontFamily}`,
          },
        }]
      : [],
    xAxis: {
      type: "category",
      data: rows.map((item) => item?.name || ""),
      axisTick: { show: false },
      axisLine: {
        show: true,
        lineStyle: {
          color: "rgba(48, 220, 255, 0.26)",
        },
      },
      axisLabel: {
        color: chartTextColor,
        fontSize: 10,
        fontWeight: 700,
        lineHeight: 14,
        interval: 0,
        margin: 10,
        formatter: panel?.axisLabelMode === "short" ? formatShortTownAxisLabel : formatTownAxisLabel,
      },
    },
    yAxis: {
      type: "value",
      min: 0,
      max: Math.ceil(maxValue * 1.18),
      splitNumber: 3,
      axisLabel: { show: false },
      axisTick: { show: false },
      axisLine: { show: false },
      splitLine: {
        show: true,
        lineStyle: {
          color: chartGridLineColor,
          type: "dashed",
        },
      },
    },
    series: [{
      type: "bar",
      data: rows.map((item, index) => {
        const zero = Boolean(item?.zero || item?.isZero)
        const value = zero ? 0 : Number(item?.value || 0)
        return {
          name: item?.name,
          value,
          displayValue: item?.displayValue ?? formatChartNumber(value),
          unit: item?.unit || unit || "",
          extra: item?.extra || "",
          zero,
          itemStyle: {
            color: zero
              ? "rgba(48, 220, 255, 0.1)"
              : panel?.uniformColor
                ? uniformTownColumnColor()
                : townColumnColor(index, item),
          },
        }
      }),
      barWidth: 6,
      barMinHeight: 3,
      showBackground: true,
      backgroundStyle: {
        color: "rgba(48, 220, 255, 0.06)",
        borderColor: "rgba(48, 220, 255, 0.08)",
        borderWidth: 1,
      },
      itemStyle: {
        borderRadius: [4, 4, 0, 0],
      },
      label: {
        show: true,
        position: "top",
        distance: 5,
        color: chartStrongTextColor,
        fontFamily: chartNumberFontFamily,
        fontSize: 10,
        fontWeight: 700,
        formatter(params = {}) {
          const data = params.data || {}
          if (data.zero) return ""
          return data.displayValue ?? formatChartNumber(Number(data.value || 0))
        },
      },
      emphasis: {
        focus: "series",
        itemStyle: {
          shadowBlur: 0,
          shadowColor: "rgba(48, 220, 255, 0)",
        },
      },
    }],
  })
}

function getSharedUnit(rows = []) {
  const units = [...new Set(rows.map((item) => item?.unit).filter(Boolean))]
  return units.length === 1 ? units[0] : ""
}

function formatTownAxisLabel(name) {
  const text = String(name || "").replace(/\s+/g, "")
  return Array.from(text).slice(0, 3).join("\n")
}

function formatShortTownAxisLabel(name) {
  return Array.from(String(name || "").replace(/\s+/g, "")).slice(0, 2).join("")
}

function townColumnColor(index, item = {}) {
  if (item.color || item.fillColor) return item.color || item.fillColor
  return systemBarGradient(chartPalette[index % chartPalette.length])
}

function uniformTownColumnColor() {
  return systemBarGradient(chartPalette[0])
}

function formatChartNumber(value) {
  const number = Number(value)
  if (!Number.isFinite(number)) return "--"
  return Number.isInteger(number) ? `${number}` : `${Number(number.toFixed(2))}`
}

function updateScreenViewportHeight() {
  screenViewportHeight.value = typeof window === "undefined" ? 1080 : window.innerHeight
}

function emitIndustryTopStats(stageKey = activeStageKey.value) {
  const currentStageKey = stageKey || activeStageKey.value
  emit("module-stats", {
    moduleKey: "yak-industry-chain",
    items: getStageTopStats(currentStageKey),
  })
}

function initIndustryMap() {
  mapAssets = new Assets()
  mapAssetsReady = false
  emit("loading-progress", { progress: 0 })
  mapAssets.instance?.on?.("onProgress", (path, itemsLoaded, itemsTotal) => {
    const total = itemsTotal || 1
    emit("loading-progress", {
      progress: Math.floor((itemsLoaded / total) * 100),
      path,
      itemsLoaded,
      itemsTotal,
    })
  })
  mapAssets.ready?.then(() => {
    mapAssetsReady = true
    scheduleIndustryMapLoad()
  }).catch(() => {
    mapReady.value = true
    emit("map-ready")
  })
}

function scheduleIndustryMapLoad() {
  if (destroyed || !props.active || !mapAssetsReady || mapLoadStarted) return
  mapLoadStarted = true
  if (mapLoadTimer) window.clearTimeout(mapLoadTimer)
  mapLoadTimer = window.setTimeout(() => {
    mapLoadTimer = null
    loadIndustryMapOnce()
  }, 600)
}

async function loadIndustryMapOnce(attempt = 0) {
  if (destroyed) return
  if (!props.active) {
    mapLoadStarted = false
    return
  }
  await nextTick()
  if (!props.active) {
    mapLoadStarted = false
    return
  }
  const scene = mapSceneRef.value
  scene?.loadMap?.(mapAssets)
  if (scene?.canvasMap) {
    mapReady.value = true
    emit("loading-progress", { progress: 100 })
    emit("map-ready")
    scene.play?.()
    return
  }
  if (attempt < 24) {
    window.setTimeout(() => loadIndustryMapOnce(attempt + 1), 120)
    return
  }
  mapLoadStarted = false
  mapReady.value = true
  emit("map-ready")
}

function clearIndustryMapLoadTimer() {
  if (!mapLoadTimer) return
  window.clearTimeout(mapLoadTimer)
  mapLoadTimer = null
}

function refreshMapView() {
  mapSceneRef.value?.resume?.()
  mapSceneRef.value?.refreshView?.()
}

function resetMap() {
  clearSelectedPoint()
  if (mapSceneRef.value?.hasMap?.()) {
    mapReady.value = true
    refreshMapView()
    return
  }
  clearIndustryMapLoadTimer()
  mapReady.value = false
  mapLoadStarted = false
  nextTick(() => {
    scheduleIndustryMapLoad()
  })
}

defineExpose({
  refreshMapView,
  resetMap,
})

function handleMapFeatureInfo(payload = {}) {
  const selectedFeature = payload.feature || null
  const properties = selectedFeature?.properties || {}
  if (selectedFeature?.layer?.key === "artificial-grassland-plots") {
    selectedPoint.value = null
    selectedArtificialFeature.value = selectedFeature
    const screen = payload.screen || mapSceneRef.value?.getVectorFeatureScreen?.(selectedFeature.feature)
    if (screen) selectedArtificialFeatureScreen.value = normalizeFeatureScreen(screen)
    artificialFeaturePositionReady.value = Boolean(screen)
    return
  }
  selectedArtificialFeature.value = null
  artificialFeaturePositionReady.value = false
  if (properties.stageKey) {
    if (String(properties.stageKey) !== String(activeStageKey.value)) {
      selectedPoint.value = null
      selectedFeaturedBaseKey.value = ""
      return
    }
    selectedFeaturedBaseKey.value = getFeaturedBreedingBaseProfile(properties)?.key || ""
    selectedPoint.value = properties
    selectedPointScreen.value = normalizeFeatureScreen(payload.screen)
    return
  }
  selectedPoint.value = null
  selectedFeaturedBaseKey.value = ""
}

async function handlePanelRowSelect(row = {}) {
  if (row.stageKey === "artificial-grassland") {
    await handleArtificialGrasslandSelect(row)
    return
  }
  await handleIndustryListSelect(row)
}

async function handleArtificialGrasslandSelect(row = {}) {
  if (!row?.canLocate) return
  if (!isArtificialGrassland.value) {
    activeStageKey.value = "artificial-grassland"
    await nextTick()
  }
  selectedPoint.value = null
  selectedFeaturedBaseKey.value = ""
  selectedArtificialFeature.value = null
  selectedArtificialFeatureScreen.value = { x: 960, y: 510 }
  artificialFeaturePositionReady.value = false
  window.setTimeout(() => focusArtificialGrasslandFeature(row), 90)
}

function focusArtificialGrasslandFeature(row = {}, attempt = 0) {
  const result = mapSceneRef.value?.focusVectorFeature?.(row)
  if (!result?.feature) {
    if (attempt < 4) window.setTimeout(() => focusArtificialGrasslandFeature(row, attempt + 1), 180)
    return
  }
  selectedArtificialFeature.value = {
    id: result.feature.properties?.id || row.id,
    properties: result.feature.properties || {},
    feature: result.feature,
    layer: getLayerByKey("yak-industry-chain", "artificial-grassland-plots"),
  }
  const selectedId = selectedArtificialFeature.value.id
  window.setTimeout(() => {
    if (selectedArtificialFeature.value?.id !== selectedId) return
    syncArtificialFeatureScreen(result.feature, result.screen)
    artificialFeaturePositionReady.value = true
  }, 820)
}

function syncArtificialFeatureScreen(feature, fallbackScreen = null) {
  const screen = mapSceneRef.value?.getVectorFeatureScreen?.(feature) || fallbackScreen
  if (screen) selectedArtificialFeatureScreen.value = normalizeFeatureScreen(screen)
}

async function handleIndustryListSelect(row = {}) {
  if (!row.canLocate) return
  const stageChanged = Boolean(row.stageKey && row.stageKey !== activeStageKey.value)
  if (stageChanged) {
    activeStageKey.value = row.stageKey
    await nextTick()
  }
  const point = buildListPoint(row)
  selectedFeaturedBaseKey.value = getFeaturedBreedingBaseProfile(point)?.key || ""
  selectedPoint.value = point
  selectedPointScreen.value = { x: 960, y: 500 }
  window.setTimeout(() => {
    const focusResult = mapSceneRef.value?.focusYakIndustryPoint?.(point)
    syncSelectedPointScreen(point, focusResult)
    trackSelectedPointScreen(point)
  }, stageChanged ? 320 : 80)
}

async function handleFeaturedBaseSelect(profile = {}) {
  if (!profile.point) return
  selectedFeaturedBaseKey.value = profile.key
  await handleIndustryListSelect(profile.point)
}

function clearSelectedPoint() {
  selectedPoint.value = null
  selectedFeaturedBaseKey.value = ""
  selectedArtificialFeature.value = null
  artificialFeaturePositionReady.value = false
  if (pointScreenSyncFrame) {
    window.cancelAnimationFrame(pointScreenSyncFrame)
    pointScreenSyncFrame = null
  }
  const canvasMap = mapSceneRef.value?.canvasMap?.value || mapSceneRef.value?.canvasMap
  canvasMap?.clearSelectedFeature?.()
}

function buildListPoint(row = {}) {
  const longitude = Number(row.longitude)
  const latitude = Number(row.latitude)
  return {
    ...row,
    id: row.key || row.id,
    name: row.fullName || row.name,
    stageKey: row.stageKey,
    stageName: row.stageName || getStageDef(row.stageKey)?.name,
    categoryName: row.categoryName || row.typeName,
    capacity: row.value,
    capacityUnit: row.unit,
    longitude,
    latitude,
    geometry: Number.isFinite(longitude) && Number.isFinite(latitude)
      ? { type: "Point", coordinates: [longitude, latitude] }
      : undefined,
    preferCoordinateMatch: Number.isFinite(longitude) && Number.isFinite(latitude),
    status: row.status,
  }
}

function syncSelectedPointScreen(point, focusResult = null) {
  const screen = mapSceneRef.value?.getYakIndustryPointScreen?.(point) || focusResult?.screen
  if (screen) selectedPointScreen.value = normalizeFeatureScreen(screen)
}

function trackSelectedPointScreen(point, duration = 920) {
  if (pointScreenSyncFrame) window.cancelAnimationFrame(pointScreenSyncFrame)
  const startedAt = window.performance?.now?.() || Date.now()
  const update = () => {
    if (!selectedPoint.value || selectedPoint.value.id !== point.id) {
      pointScreenSyncFrame = null
      return
    }
    syncSelectedPointScreen(point)
    const elapsed = (window.performance?.now?.() || Date.now()) - startedAt
    if (elapsed < duration) {
      pointScreenSyncFrame = window.requestAnimationFrame(update)
      return
    }
    pointScreenSyncFrame = null
  }
  pointScreenSyncFrame = window.requestAnimationFrame(update)
}

function formatCapacity(point) {
  if (point.capacity === undefined || point.capacity === null || point.capacity === "") return ""
  return `${point.capacity}${point.capacityUnit || ""}`
}

function formatDisplayText(value) {
  return String(value ?? "")
    .replace(/\bcxpt[-_./\s]*/gi, "")
    .replace(/\s+/g, " ")
    .trim()
}

function normalizeFeatureScreen(screen = {}) {
  const root = document.querySelector("#large-screen")
  const rect = root?.getBoundingClientRect?.()
  const scaleX = rect?.width ? 1920 / rect.width : 1
  const scaleY = rect?.height ? 1080 / rect.height : 1
  const left = rect?.left || 0
  const top = rect?.top || 0
  return {
    x: (Number(screen.x) - left) * scaleX,
    y: (Number(screen.y) - top) * scaleY,
  }
}

</script>

<style lang="scss">
.yak-industry-chain {
  position: absolute;
  inset: 0;
  z-index: 1;
  overflow: hidden;
  color: #fff;
  background: #03121c;
}

.industry-map-scene {
  position: absolute;
  inset: 0;
  z-index: 1;
}

.industry-map-scrim {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background:
    radial-gradient(circle at 50% 48%, rgba(4, 18, 28, 0) 0%, rgba(4, 18, 28, 0.05) 37%, rgba(2, 10, 17, 0.34) 78%, rgba(1, 7, 12, 0.62) 100%),
    linear-gradient(90deg, rgba(0, 12, 20, 0.42), transparent 26%, transparent 74%, rgba(0, 12, 20, 0.42));
}

.industry-map-loading {
  position: absolute;
  left: 50%;
  top: 50%;
  z-index: 4;
  transform: translate(-50%, -50%);
  color: rgba(220, 250, 255, 0.78);
  font-size: 18px;
}

.industry-artificial-layer-tools {
  position: absolute;
  right: 452px;
  bottom: 122px;
  z-index: 8;
  width: 248px;
  pointer-events: all;

  .m-card {
    width: 100% !important;
  }
}

.industry-map-feature-info {
  position: absolute;
  z-index: 10;
  pointer-events: all;

  &::after {
    position: absolute;
    top: var(--feature-arrow-top);
    left: var(--feature-arrow-left);
    z-index: 0;
    width: 12px;
    height: 12px;
    content: "";
    border-right: 1px solid rgba(48, 220, 255, 0.58);
    border-bottom: 1px solid rgba(48, 220, 255, 0.58);
    background: rgba(5, 26, 38, 0.94);
    box-shadow: 3px 3px 8px rgba(0, 0, 0, 0.24);
    transform: translateX(-50%) rotate(var(--feature-arrow-rotate));
  }

  > .m-card {
    position: relative;
    z-index: 1;
  }
}

.industry-side-panel {
  position: absolute;
  top: 128px;
  bottom: 8px;
  z-index: 6;
  width: 398px;
  perspective-origin: 50% 50%;
  pointer-events: all;
}

.industry-side-panel--left {
  left: 32px;
  perspective: var(--screen-side-perspective-left, 500px);
}

.industry-side-panel--right {
  right: 32px;
  perspective: var(--screen-side-perspective-right, 800px);
}

.industry-side-stack {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
  transform-style: preserve-3d;

  &.is-left {
    transform: translate3d(0, 0, 0) rotateY(6deg);
    transform-origin: left center;
  }

  &.is-right {
    transform: translate3d(0, 0, 0) rotateY(-6deg);
    transform-origin: right center;
  }

}

.industry-side-card {
  flex: 0 0 auto;

  .m-card-bd-content {
    top: 36px;
    bottom: 0;
    color: #f3feff;
    overflow: hidden;
  }

  .industry-town-column-chart {
    position: relative;
    z-index: 1;
    width: 100%;
    height: 100%;
    min-height: 0;
  }

  .industry-panel-empty {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
    color: rgba(226, 251, 255, 0.68);
    font-size: 13px;
    font-weight: 600;
    letter-spacing: 0;
    text-shadow: 0 0 8px rgba(48, 220, 255, 0.14);
  }

  .business-columns.is-variant-plain {
    grid-template-columns: repeat(auto-fit, minmax(34px, 1fr));
    gap: 8px;
    padding-right: 12px;
    padding-left: 12px;
  }

  .business-columns.is-variant-plain .business-column-item {
    grid-template-rows: 16px minmax(62px, 1fr) 32px;
  }

  .business-columns.is-variant-plain .business-column-item span {
    display: -webkit-box;
    max-width: 58px;
    color: rgba(240, 253, 255, 0.86);
    line-height: 13px;
    white-space: normal;
    word-break: keep-all;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
  }

  .business-columns.is-variant-plain .business-column-track {
    width: 6px;
  }

  .business-columns.is-variant-townCompact {
    grid-template-columns: repeat(10, minmax(0, 1fr));
    gap: 5px;
    padding: 35px 13px 10px;
  }

  .business-columns.is-variant-townCompact::before {
    left: 13px;
    right: 13px;
    top: 55px;
    bottom: 40px;
    opacity: 0.46;
    background:
      linear-gradient(to bottom, transparent calc(100% - 1px), rgba(48, 220, 255, 0.58) calc(100% - 1px)),
      repeating-linear-gradient(
        to bottom,
        rgba(159, 220, 230, 0.16) 0 1px,
        transparent 1px 21px
      );
  }

  .business-columns.is-variant-townCompact::after {
    content: "";
    position: absolute;
    left: 13px;
    right: 13px;
    bottom: 39px;
    height: 1px;
    pointer-events: none;
    background: linear-gradient(90deg, transparent, rgba(60, 244, 255, 0.72), transparent);
    box-shadow: none;
  }

  .business-columns.is-variant-townCompact .business-column-item {
    position: relative;
    z-index: 1;
    grid-template-rows: 17px minmax(74px, 1fr) 29px;
    min-width: 0;
  }

  .business-columns.is-variant-townCompact .business-column-item strong {
    width: 100%;
    color: rgba(244, 252, 255, 0.94);
    font-size: 10px;
    line-height: 14px;
    text-align: center;
    text-shadow: none;
  }

  .business-columns.is-variant-townCompact .business-column-item span {
    display: -webkit-box;
    align-self: start;
    width: 100%;
    max-width: 36px;
    height: 25px;
    margin-top: 3px;
    color: rgba(232, 252, 255, 0.82);
    font-size: 10px;
    line-height: 12px;
    text-align: center;
    white-space: normal;
    word-break: break-all;
    writing-mode: horizontal-tb;
    text-orientation: initial;
    letter-spacing: 0;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
  }

  .business-columns.is-variant-townCompact .business-column-track {
    width: 8px;
    height: 100%;
    min-height: 74px;
    align-self: end;
    border: 0;
    border-radius: 2px 2px 0 0;
    background:
      linear-gradient(180deg, rgba(48, 220, 255, 0.12), rgba(36, 246, 196, 0.015)),
      linear-gradient(90deg, rgba(48, 220, 255, 0.1), rgba(48, 220, 255, 0.02) 48%, rgba(48, 220, 255, 0.1)),
      rgba(4, 26, 38, 0.22);
    box-shadow: inset 0 -1px 0 rgba(48, 220, 255, 0.16);
  }

  .business-columns.is-variant-townCompact .business-column-track::after {
    content: "";
    position: absolute;
    left: 50%;
    bottom: -5px;
    width: 18px;
    height: 7px;
    border-radius: 50%;
    background: radial-gradient(ellipse at center, rgba(48, 220, 255, 0.12), rgba(48, 220, 255, 0) 68%);
    transform: translateX(-50%);
  }

  .business-columns.is-variant-townCompact .business-column-track i {
    left: 0;
    right: 0;
    min-height: 5px;
    border-radius: 3px 3px 0 0;
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.24);
  }

  .business-columns.is-variant-townCompact .business-column-track i::before,
  .business-columns.is-variant-townCompact .business-column-track i::after {
    display: none;
  }

  .business-columns.is-variant-townCompact .business-column-item.is-zero strong {
    opacity: 0;
  }

  .business-columns.is-variant-townCompact .business-column-item.is-zero .business-column-track i {
    height: 4px !important;
    opacity: 0.16;
    box-shadow: none;
  }

  .business-bars.is-rank-bar {
    padding-right: 12px;
    padding-left: 12px;
  }

  .business-bars.is-rank-bar .business-bar-name {
    font-size: 12px;
    line-height: 14px;
  }
}

.industry-featured-base-list {
  position: relative;
  z-index: 1;
  display: grid;
  gap: 8px;
  height: 100%;
  padding: 2px 3px;
}

.industry-side-card--breeding-town-rank {
  .business-stat-list.is-compact {
    display: grid;
    grid-auto-rows: minmax(0, 1fr);
    align-content: stretch;
    gap: 2px;
    padding: 5px 13px 8px;
    overflow: hidden;
  }

  .business-stat-list.is-compact .business-stat-row {
    height: auto;
    min-height: 0;
    gap: 10px;
    grid-template-columns: 25px minmax(0, 1fr) 104px;
  }

  .business-stat-list.is-compact .business-stat-rank {
    width: 18px;
    height: 18px;
    font-size: 12px;
    line-height: 19px;
  }

  .business-stat-list.is-compact .business-stat-name {
    font-size: 13px;
    line-height: 16px;
  }

  .business-stat-list.is-compact .business-stat-bar {
    height: 5px;
    margin-top: 6px;
  }

  .business-stat-list.is-compact .business-stat-value strong {
    font-size: 16px;
    line-height: 18px;
  }

  .business-stat-list.is-compact .business-stat-value em {
    font-size: 12px;
  }

  .business-stat-list.is-compact .business-stat-value span {
    margin-top: 3px;
    font-size: 11px;
    line-height: 13px;
  }
}

.industry-featured-base {
  position: relative;
  display: grid;
  grid-template-columns: 28px minmax(0, 1fr);
  gap: 10px;
  width: 100%;
  min-height: 76px;
  padding: 9px 28px 9px 9px;
  overflow: hidden;
  border: 1px solid rgba(48, 220, 255, 0.16);
  border-radius: 3px;
  background:
    linear-gradient(90deg, rgba(18, 88, 106, 0.27), rgba(6, 25, 38, 0.3)),
    rgba(3, 20, 31, 0.46);
  color: inherit;
  cursor: pointer;
  text-align: left;
  transition: border-color 160ms ease, background 160ms ease, transform 160ms ease;

  &::after {
    content: ">";
    position: absolute;
    right: 10px;
    top: 50%;
    color: rgba(36, 246, 196, 0.9);
    font-size: 16px;
    font-weight: 800;
    transform: translateY(-50%);
  }

  &:hover,
  &:focus-visible {
    border-color: rgba(36, 246, 196, 0.54);
    background:
      linear-gradient(90deg, rgba(18, 112, 120, 0.38), rgba(6, 31, 43, 0.38)),
      rgba(3, 20, 31, 0.56);
    outline: 0;
    transform: translateX(2px);
  }

  &.is-active {
    border-color: rgba(36, 246, 196, 0.72);
    background:
      linear-gradient(90deg, rgba(30, 124, 119, 0.38), rgba(7, 41, 48, 0.42)),
      rgba(3, 26, 34, 0.62);
    box-shadow: inset 3px 0 0 rgba(36, 246, 196, 0.9), 0 0 16px rgba(36, 246, 196, 0.11);

    &::after {
      color: #c9fbff;
    }
  }

  &:disabled {
    cursor: default;
    opacity: 0.58;
  }
}

.industry-featured-base__index {
  display: grid;
  width: 28px;
  height: 28px;
  place-items: center;
  border: 1px solid rgba(48, 220, 255, 0.42);
  background: rgba(48, 220, 255, 0.09);
  color: #35f1ff;
  font-family: "D-DIN", "DIN Alternate", sans-serif;
  font-size: 14px;
  font-weight: 800;
}

.industry-featured-base__copy {
  display: grid;
  min-width: 0;
  gap: 2px;

  strong,
  em,
  small {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  strong {
    color: rgba(246, 255, 255, 0.96);
    font-size: 14px;
    font-weight: 760;
    line-height: 18px;
  }

  em {
    color: rgba(36, 246, 196, 0.92);
    font-size: 11px;
    font-style: normal;
    line-height: 15px;
  }

  small {
    color: rgba(205, 238, 244, 0.66);
    font-size: 11px;
    line-height: 15px;
  }
}

.industry-leadership-mode-list {
  position: relative;
  z-index: 1;
  display: grid;
  gap: 7px;
  padding: 3px 5px;
}

.industry-leadership-mode {
  display: grid;
  grid-template-columns: 4px 26px minmax(0, 1fr);
  gap: 8px;
  align-items: center;
  min-height: 48px;
  padding: 5px 6px;
  border-bottom: 1px solid rgba(48, 220, 255, 0.1);

  > i {
    display: block;
    width: 4px;
    height: 30px;
    box-shadow: 0 0 10px currentColor;
  }

  > span {
    color: rgba(207, 247, 255, 0.46);
    font-family: "D-DIN", "DIN Alternate", sans-serif;
    font-size: 13px;
    font-weight: 800;
  }

  div {
    display: grid;
    min-width: 0;
    gap: 2px;
  }

  strong {
    color: rgba(246, 255, 255, 0.95);
    font-size: 13px;
    font-weight: 760;
  }

  small {
    overflow: hidden;
    color: rgba(205, 238, 244, 0.66);
    font-size: 11px;
    line-height: 15px;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
}

.industry-ledger-list {
  display: grid;
  gap: 7px;
}

.industry-ledger-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 10px;
  align-items: center;
  min-height: 42px;
  padding: 7px 8px;
  border: 1px solid rgba(48, 220, 255, 0.1);
  border-radius: 4px;
  background: rgba(4, 20, 31, 0.42);

  div {
    min-width: 0;
  }

  strong,
  span {
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  strong {
    color: rgba(241, 254, 255, 0.92);
    font-size: 13px;
    font-weight: 760;
  }

  span {
    margin-top: 4px;
    color: rgba(201, 237, 244, 0.58);
    font-size: 11px;
  }

  em {
    color: #c9fbff;
    font-size: 12px;
    font-style: normal;
    font-weight: 800;
    white-space: nowrap;
  }
}

.industry-point-detail {
  position: absolute;
  z-index: 7;
  width: 456px;
  padding: 18px 20px 20px;
  border: 1px solid rgba(48, 220, 255, 0.42);
  background:
    linear-gradient(180deg, rgba(12, 54, 70, 0.86), rgba(5, 24, 37, 0.9)),
    radial-gradient(circle at 20% 0%, rgba(36, 246, 196, 0.18), transparent 46%);
  box-shadow:
    0 0 24px rgba(48, 220, 255, 0.18),
    inset 0 0 18px rgba(48, 220, 255, 0.08);
  color: #efffff;
  box-sizing: border-box;
  pointer-events: all;
}

.industry-point-detail::after {
  content: "";
  position: absolute;
  left: var(--point-arrow-left, 50%);
  top: var(--point-arrow-top, 50%);
  width: 16px;
  height: 16px;
  border-right: 1px solid rgba(48, 220, 255, 0.42);
  border-bottom: 1px solid rgba(48, 220, 255, 0.42);
  background: rgba(5, 24, 37, 0.9);
  transform: translate(var(--point-arrow-x, -50%), var(--point-arrow-y, -50%)) rotate(var(--point-arrow-rotate, 45deg));
}

.industry-point-detail__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  color: #c9fbff;
  font-size: 16px;
  font-weight: 700;

  button {
    width: 26px;
    height: 26px;
    border: 1px solid rgba(48, 220, 255, 0.36);
    border-radius: 0;
    background: rgba(6, 28, 43, 0.72);
    color: rgba(239, 255, 255, 0.88);
    cursor: pointer;
    font-size: 20px;
    line-height: 20px;
  }
}

.industry-point-detail__name {
  margin-top: 12px;
  color: #ffffff;
  font-size: 23px;
  font-weight: 800;
  line-height: 1.35;
}

.industry-point-detail__profile {
  margin-top: 12px;
  padding-top: 11px;
  border-top: 1px solid rgba(48, 220, 255, 0.2);
}

.industry-point-detail__profile-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;

  span {
    color: rgba(202, 241, 248, 0.72);
    font-size: 13px;
  }

  strong {
    color: #8bf7ff;
    font-size: 13px;
    font-weight: 760;
  }
}

.industry-point-detail__profile > p {
  display: -webkit-box;
  margin: 6px 0 0;
  overflow: hidden;
  color: rgba(237, 252, 255, 0.86);
  font-size: 14px;
  line-height: 20px;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
}

.industry-point-detail__image {
  display: block;
  width: 100%;
  height: 116px;
  margin-top: 9px;
  border: 1px solid rgba(48, 220, 255, 0.22);
  object-fit: cover;
  object-position: center 35%;
}

.industry-point-detail__facts {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 6px;
  margin-top: 9px;

  div {
    min-width: 0;
    padding: 6px 7px;
    border: 1px solid rgba(48, 220, 255, 0.13);
    background: rgba(2, 18, 30, 0.3);
  }

  span,
  strong,
  small {
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  span,
  small {
    color: rgba(199, 236, 243, 0.62);
    font-size: 11px;
    line-height: 14px;
  }

  strong {
    margin: 1px 0;
    color: #c9fbff;
    font-family: "D-DIN", "DIN Alternate", sans-serif;
    font-size: 18px;
    font-weight: 800;
    line-height: 20px;
  }
}

.industry-point-detail__highlights {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
  align-items: center;
  margin-top: 9px;

  > span {
    margin-right: 2px;
    color: rgba(202, 241, 248, 0.68);
    font-size: 12px;
  }

  i {
    padding: 3px 6px;
    border: 1px solid rgba(36, 246, 196, 0.28);
    background: rgba(36, 246, 196, 0.08);
    color: rgba(220, 255, 211, 0.92);
    font-size: 11px;
    font-style: normal;
    line-height: 15px;
  }
}

.industry-point-detail__grid {
  display: grid;
  gap: 9px;
  margin-top: 16px;
}

.industry-point-detail__row {
  display: grid;
  grid-template-columns: 88px minmax(0, 1fr);
  gap: 12px;
  min-height: 34px;
  align-items: center;
  border-bottom: 1px solid rgba(48, 220, 255, 0.12);

  span {
    color: rgba(196, 237, 244, 0.74);
    font-size: 15px;
  }

  strong {
    overflow: hidden;
    color: rgba(246, 255, 255, 0.95);
    font-size: 16px;
    font-weight: 700;
    line-height: 1.35;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
}

.industry-point-detail__grid.is-family-layout {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 6px 14px;
  margin-top: 14px;

  .industry-point-detail__row {
    grid-template-columns: 74px minmax(0, 1fr);
    gap: 8px;
    min-height: 31px;
    padding: 2px 0;

    &.is-wide {
      grid-column: 1 / -1;
    }
  }

  .industry-point-detail__row span {
    font-size: 13px;
    line-height: 16px;
  }

  .industry-point-detail__row strong {
    font-size: 14px;
    line-height: 18px;
  }
}

.industry-bottom-switcher {
  position: absolute;
  left: 50%;
  bottom: 48px;
  z-index: 8;
  display: flex;
  align-items: center;
  justify-content: center;
  transform: translateX(-50%);
  pointer-events: all;
}
</style>
