<template>
  <div class="page" @mousemove="onMouseMove" @mouseleave="onMouseLeave">
    <!-- Top Header -->
    <header class="topbar">
      <div class="top-left">
        <div class="weather">
          <i class="dot-sun" aria-hidden="true"></i>
          <span class="w1">{{ header.weatherText }}</span>
          <span class="w2">{{ header.tempText }}</span>
        </div>
      </div>

      <div class="top-center" style="visibility: hidden;">
        <div class="title-frame">
          <div class="title">交通信号控制平台</div>
        </div>
      </div>

      <div class="top-right">
        <div class="clock">
          <div class="time">{{ header.timeText }}</div>
          <div class="date">
            <span>{{ header.weekText }}</span>
            <span class="sep">·</span>
            <span>{{ header.dateText }}</span>
          </div>
        </div>
      </div>
    </header>

    <!-- Main Layout -->
    <main class="grid">
      <!-- Left -->
      <section class="col left">
        <!-- 在线状态（2s循环：信号机/检测器/相机） -->
        <div class="card card-a">
          <div class="card-h">
            <span class="h-dot"></span>
            <span>在线状态</span>
          </div>

          <div class="tabs">
            <button
              v-for="t in onlineTabs"
              :key="t.key"
              class="tab"
              :class="{ active: onlineTab === t.key }"
              @click="setOnlineTab(t.key, true)"
            >
              {{ t.label }}
            </button>
          </div>

          <div class="row">
            <div ref="onlineChart" class="chart donut"></div>
            <div class="legend">
              <div class="lg">
                <span class="b b-on"></span><span>在线</span>
                <span class="num">{{ onlineView.online }}</span>
              </div>
              <div class="lg">
                <span class="b b-off"></span><span>离线</span>
                <span class="num">{{ onlineView.offline }}</span>
              </div>
              <div class="lg">
                <span class="b b-rate"></span><span>在线率</span>
                <span class="num">{{ onlineView.rate }}%</span>
              </div>

              <div class="subnote">
                {{ onlineTabsMap[onlineTab] }} · {{ onlineView.online }}/{{ onlineView.total }}
              </div>
            </div>
            <!-- <div class="dock-arrow right" @click="dockNext" title="下一页"></div> -->
          </div>
        </div>

        <!-- 控制模式（GB20999 / GAT1049） -->
        <div class="card card-b">
          <div class="card-h">
            <span class="h-dot"></span>
            <span>在线状态</span>
          </div>

          <div class="tabs small">
            <button class="tab" :class="{ active: true }">信号机</button>
            <button class="tab">检测器</button>
            <button class="tab">红绿灯</button>
          </div>

          <div class="row row-b">
            <div class="legend legend-b">
              <div class="lg" v-for="it in controlLegend" :key="it.k">
                <span class="b" :class="it.cls"></span><span>{{ it.t }}</span>
                <span class="num">{{ it.v }}</span>
              </div>
            </div>

            <div ref="controlChart" class="chart donut small"></div>
          </div>
        </div>

        <!-- 故障报警（展示4条，可忽略/查看，超过4条自动上移） -->
        <div class="card card-c grow">
          <div class="card-h">
            <span class="h-dot"></span>
            <span>故障报警</span>
          </div>

          <div class="alarm-list">
            <div class="alarm-item" v-for="a in alarmsView" :key="a.id">
              <div class="a-left">
                <div class="a-title">
                  <span class="lvl" :class="'lv-' + a.level">{{ a.levelText }}</span>
                  <span class="txt">{{ a.title }}</span>
                </div>
                <div class="a-sub">
                  <span class="loc">{{ a.loc }}</span>
                  <!-- <span class="time">{{ a.time }}</span> -->
                </div>
              </div>
              <div class="a-actions">
                <button class="btn ghost" @click="ignoreAlarm(a.id)">忽略</button>
                <button class="btn primary" @click="viewAlarm(a)">查看</button>
              </div>
            </div>

            <div v-if="alarmsView.length === 0" class="empty">暂无告警</div>
          </div>
        </div>
      </section>

      <!-- Middle -->
      <section class="col mid">
        <div class="map-wrap">
          <div class="map-frame">
            <!-- Top tools -->
            <div class="map-tools">
              <div class="search">
                <input v-model="mapQuery" placeholder="查询" />
                <button class="btn icon" @click="doSearch">查询</button>
              </div>
              <div class="select">
                <span class="lbl">全选</span>
                <span class="caret">▾</span>
              </div>
            </div>

            <!-- Map placeholder (可替换背景图) -->
            <div class="map-canvas" :style="mapBgStyle">
              <!-- roads overlay (placeholder) -->
              <svg class="roads" viewBox="0 0 1000 560" preserveAspectRatio="none" aria-hidden="true">
                <path class="r g" d="M80 410 C260 420, 380 360, 520 360 C660 360, 820 420, 940 420"/>
                <path class="r g" d="M120 150 C240 150, 310 190, 420 210 C520 230, 640 210, 820 150"/>
                <path class="r b" d="M520 60 L520 520"/>
                <path class="r g" d="M350 80 L350 520"/>
                <path class="r y" d="M170 330 L840 330"/>
                <path class="r red" d="M700 220 C720 260, 700 300, 680 330"/>
                <g class="nodes">
                  <circle v-for="n in 10" :key="n" :cx="520" :cy="60 + n*42" r="6" class="node"/>
                </g>
              </svg>

              <!-- Popup (from alarm view) -->
              <div v-if="mapPopup" class="popup">
                <div class="popup-title">{{ mapPopup.title }}</div>
                <div class="popup-line">路口：{{ mapPopup.loc }}</div>
                <div class="popup-line">发生时间：{{ mapPopup.time }}</div>
              </div>

              <!-- Legend -->
              <div class="legend-box">
                <div class="legend-title">图例</div>
                <div class="legend-row" v-for="it in legendItems" :key="it.k">
                  <span class="chip" :class="it.cls"></span>
                  <span class="legend-t">{{ it.t }}</span>
                </div>
              </div>
            </div>

          <!-- Bottom Dock (overlay on map) -->
          <div class="dock-wrap" @mousemove="onDockMove" @mouseleave="onDockLeave">
            <div class="dock-arrow left" @click="dockPrev" title="上一页"></div>
            <div class="dockbar">
              <div
                v-for="(m, idx) in modules"
                :key="m.key"
                class="dock-item"
                :class="{ active: activeModule === m.key }"
                :style="navItemStyle(idx)"
                @click="selectModule(m)"
              >
                <div class="dock-icon" :style="navIconStyle(m)"></div>
                <div class="dock-label">{{ m.title }}</div>
              </div>
            </div>
            <div class="dock-arrow right" @click="dockNext" title="下一页"></div>
          </div>
          </div>
        </div>
      </section>

      <!-- Right -->
      <section class="col right">
        <!-- 设备状态（2s循环：信号机/检测器/红绿灯） -->
        <div class="card card-a">
          <div class="card-h">
            <span class="h-dot"></span>
            <span>设备状态</span>
          </div>

          <div class="tabs">
            <button
              v-for="t in deviceTabs"
              :key="t.key"
              class="tab"
              :class="{ active: deviceTab === t.key }"
              @click="setDeviceTab(t.key, true)"
            >
              {{ t.label }}
            </button>
          </div>

          <div class="row">
            <div ref="deviceChart" class="chart donut"></div>
            <div class="legend">
              <div class="lg">
                <span class="b b-ok"></span><span>正常</span>
                <span class="num">{{ deviceView.normal }}</span>
              </div>
              <div class="lg">
                <span class="b b-bad"></span><span>故障</span>
                <span class="num">{{ deviceView.fault }}</span>
              </div>
              <div class="subnote">
                {{ deviceTabsMap[deviceTab] }} · {{ deviceView.fault === 0 ? "全绿" : "需处理" }}
              </div>
            </div>
            <!-- <div class="dock-arrow right" @click="dockNext" title="下一页"></div> -->
          </div>
        </div>

        <!-- 勤务执行（>5滚动，点击可高亮地图） -->
        <div class="card card-c grow">
          <div class="card-h">
            <span class="h-dot"></span>
            <span>勤务执行</span>
          </div>

          <div class="tbl-wrap">
            <table class="tbl">
              <thead>
                <tr>
                  <th style="width: 12%;">序号</th>
                  <th style="width: 30%;">名称</th>
                  <th style="width: 15%;">执行人</th>
                  <th style="width: 15%;">等级</th>
                  <th style="width: 15%;">状态</th>
                  <th style="width: 13%;">操作</th>
                </tr>
              </thead>
              <tbody :style="dutyScrollStyle">
                <tr v-for="(r,i) in duty" :key="r.id" :class="{ hl: activeDutyId === r.id }">
                  <td>{{ i + 1 }}</td>
                  <td :title="r.name" class="name">{{ r.name }}</td>
                  <td>{{ r.executor }}</td>
                  <td><span class="tag" :class="'lv' + r.level">{{ r.levelText }}</span></td>
                  <td><span class="st" :class="r.statusKey">{{ r.status }}</span></td>
                  <td><a class="link" href="javascript:;" @click="goDuty(r)">查看</a></td>
                </tr>
              </tbody>
            </table>
          </div>
        </div>

        <!-- 关键路口（保留原平台设计界面：占位结构） -->
        <div class="card card-b">
          <div class="card-h">
            <span class="h-dot"></span>
            <span>关键路口</span>
          </div>
          <table class="tbl simple">
            <thead>
              <tr>
                <th>路口</th>
                <th style="width:98px;">运营模式</th>
                <th style="width:68px;">方案号</th>
              </tr>
            </thead>
            <tbody>
              <tr v-for="k in keyJunctions" :key="k.id">
                <td class="name">{{ k.name }}</td>
                <td>{{ k.mode }}</td>
                <td>{{ k.plan }}</td>
              </tr>
            </tbody>
          </table>
        </div>
      </section>
    </main>
  </div>
</template>

<script>
import * as echarts from "echarts";

export default {
  // eslint-disable-next-line vue/multi-word-component-names
  name: "Home",
  data() {
    return {
      baseW: 1920,
      baseH: 1080,
      scale: 1,
      mouseX: null,
      mouseY: null,
      activeDockIndex: 0,
      header: {
        weatherText: "晴",
        tempText: "32/17°C",
        timeText: "--:--:--",
        dateText: "--",
        weekText: "周五"
      },

      mapQuery: "",
      mapPopup: null,
      mapBgUrl: "", // 后期替换真实底图：在这里填 url

      legendItems: [
        { k: "center", t: "中心计划", cls: "c1" },
        { k: "coord", t: "干线协调", cls: "c2" },
        { k: "bus", t: "勤务路线", cls: "c3" },
        { k: "cycle", t: "定周期控制", cls: "c4" },
        { k: "sense", t: "感应控制", cls: "c5" },
        { k: "self", t: "自适应控制", cls: "c6" },
        { k: "manual", t: "手动控制", cls: "c7" },
        { k: "spec", t: "特殊控制", cls: "c8" },
        { k: "offline", t: "离线", cls: "c9" },
        { k: "drop", t: "降级", cls: "c10" },
        { k: "fault", t: "故障", cls: "c11" }
      ],

      onlineTab: "signal",
      onlineTabs: [
        { key: "signal", label: "信号机" },
        { key: "detector", label: "检测器" },
        { key: "camera", label: "相机" }
      ],
      onlineTabsMap: { signal: "信号机", detector: "检测器", camera: "相机" },
      onlineData: {
        signal: { online: 980, offline: 20, total: 1000, rate: 98 },
        detector: { online: 461, offline: 39, total: 500, rate: 92 },
        camera: { online: 298, offline: 12, total: 310, rate: 96 }
      },

      
      // 左侧第二块：控制信息（示例图的环形图）
      controlLegend: [
        { k: "cycle", t: "定周期控制", cls: "c4", v: 400 },
        { k: "sense", t: "感应控制", cls: "c5", v: 50 },
        { k: "coord", t: "干线协调", cls: "c2", v: 200 },
        { k: "spec", t: "黄闪控制", cls: "c8", v: 5 }
      ],
      controlTotal: 650,
deviceTab: "signal",
      deviceTabs: [
        { key: "signal", label: "信号机" },
        { key: "detector", label: "检测器" },
        { key: "lamp", label: "红绿灯" }
      ],
      deviceTabsMap: { signal: "信号机", detector: "检测器", lamp: "红绿灯" },
      deviceData: {
        signal: { normal: 128, fault: 0 },
        detector: { normal: 89, fault: 2 },
        lamp: { normal: 312, fault: 4 }
      },

      alarms: [
        { id: "a1", level: 1, levelText: "一级", title: "通讯中断", loc: "中关村大街-科学院南路口-设备离线", time: "16:28:28" },
        { id: "a2", level: 2, levelText: "二级", title: "降级黄闪", loc: "中关村大街-科学院南路口-设备离线", time: "16:28:28" },
        { id: "a3", level: 3, levelText: "三级", title: "信号灯报警", loc: "知春路-学院路口-信号灯异常", time: "16:18:02" }
      ],
      duty: [
        { id: "d1", name: "大型活动交通安保", executor: "赵刚", level: 1, levelText: "一级", statusKey: "wait", status: "未开始" },
        { id: "d2", name: "道路施工路段交通引导", executor: "林小宇", level: 1, levelText: "一级", statusKey: "wait", status: "未开始" },
        { id: "d3", name: "酒驾醉驾专项查缉", executor: "周婷", level: 2, levelText: "二级", statusKey: "doing", status: "进行中" },
        { id: "d4", name: "交通信号灯故障排查", executor: "吴磊", level: 1, levelText: "一级", statusKey: "wait", status: "未开始" },
        { id: "d5", name: "应急救援通道清障", executor: "郑晓东", level: 1, levelText: "一级", statusKey: "wait", status: "未开始" }
      ],
      dutyScrollOffset: 0,
      activeDutyId: "",

      keyJunctions: [
        { id: "k1", name: "实行东街铁双园路交叉路口", mode: "定周期控制", plan: 4 },
        { id: "k2", name: "实行东街铁双园路交叉路口", mode: "自适应控制", plan: 1 },
        { id: "k3", name: "实行东街铁双园路交叉路口", mode: "感应控制", plan: 5 }
      ],

      modules: [
        { key: "home", title: "首页", img: "main-home.png", route: { path: "/home" } },
        { key: "watch", title: "状态监控", img: "main-watch.png", route: { path: "/home", query: { panel: "watch" } } },
        { key: "vip", title: "特勤安保", img: "main-security.png", route: { path: "/home", query: { panel: "security" } } },
        { key: "corr", title: "干线协调", img: "main-coor.png", route: { path: "/home", query: { panel: "coor" } } },
        { key: "overview", title: "状态展示", img: "main-surve.png", route: { path: "/home", query: { panel: "surve" } } },
        { key: "settings", title: "系统设置", img: "main-setting.png", route: { path: "/home", query: { panel: "setting" } } }
      ],
      activeModule: "home",
      hoverModule: "",
onlineChart: null,
      controlChart: null,
      deviceChart: null,

      timerClock: null,
      timerCycle: null,
      timerDutyScroll: null,
      cycleIdx: 0,
      deviceCycleIdx: 0
    };
  },
  computed: {
    onlineView() {
      return this.onlineData[this.onlineTab] || { online: 0, offline: 0, total: 0, rate: 0 };
    },
    deviceView() {
      return this.deviceData[this.deviceTab] || { normal: 0, fault: 0 };
    },
    alarmsView() {
      const arr = [...this.alarms].sort((a, b) =>
        a.level !== b.level ? a.level - b.level : (b.time || "").localeCompare(a.time || "")
      );
      return arr.slice(0, 4);
    },

    mapBgStyle() {
      if (!this.mapBgUrl) return {};
      return { backgroundImage: `url(${this.mapBgUrl})` };
    },
    dutyScrollStyle() {
      if (this.duty.length <= 5) return {};
      return { transform: `translateY(${-this.dutyScrollOffset}px)` };
    }
  },
  mounted() {
    this.updateScale();
    window.addEventListener("resize", this.updateScale, { passive: true });
    this.startClock();
    this.initCharts();
    this.renderCharts();

    this.timerCycle = setInterval(() => {
      this.cycleIdx = (this.cycleIdx + 1) % this.onlineTabs.length;
      this.setOnlineTab(this.onlineTabs[this.cycleIdx].key, false);

      this.deviceCycleIdx = (this.deviceCycleIdx + 1) % this.deviceTabs.length;
      this.setDeviceTab(this.deviceTabs[this.deviceCycleIdx].key, false);
    }, 2000);

    this.timerDutyScroll = setInterval(() => {
      if (this.duty.length <= 5) return;
      this.dutyScrollOffset += 34;
      const max = (this.duty.length - 5) * 34;
      if (this.dutyScrollOffset > max) this.dutyScrollOffset = 0;
    }, 2200);

    window.addEventListener("resize", this.onResize, { passive: true });
  },
  beforeDestroy() {
    window.removeEventListener("resize", this.updateScale);
    window.removeEventListener("resize", this.onResize);
    clearInterval(this.timerClock);
    clearInterval(this.timerCycle);
    clearInterval(this.timerDutyScroll);
    this.onlineChart && this.onlineChart.dispose();
    this.controlChart && this.controlChart.dispose();
    this.deviceChart && this.deviceChart.dispose();
  },
  methods: {
    onMouseMove(e) {
      const rect = this.$el.getBoundingClientRect();
      this.mouseX = e.clientX - rect.left;
      this.mouseY = e.clientY - rect.top;
    },
    onMouseLeave() {
      this.mouseX = null;
      this.mouseY = null;
    },
    updateScale() {
      const w = window.innerWidth || this.baseW;
      const h = window.innerHeight || this.baseH;
      this.scale = Math.min(w / this.baseW, h / this.baseH);
      this.$el && this.$el.style.setProperty("--s", this.scale.toFixed(6));
    },
    onDockMove(e) {
      const rect = this.$el.getBoundingClientRect();
      this.mouseX = e.clientX - rect.left;
      this.mouseY = e.clientY - rect.top;
    },
    onDockLeave() {
      this.mouseX = null;
      this.mouseY = null;
    },
    navItemStyle(idx) {
      if (this.mouseX == null) return { transform: "translateZ(0) scale(1)" };
      const dock = this.$el.querySelector(".dockbar");
      const el = dock && dock.children && dock.children[idx];
      if (!el) return { transform: "translateZ(0) scale(1)" };
      const r = el.getBoundingClientRect();
      const root = this.$el.getBoundingClientRect();
      const cx = (r.left - root.left) + r.width / 2;
      const cy = (r.top - root.top) + r.height / 2;
      const dx = this.mouseX - cx;
      const dy = this.mouseY - cy;
      const dist = Math.sqrt(dx * dx + dy * dy);
      const R = 220 * this.scale;
      const t = Math.max(0, 1 - dist / R);
      const s = 1 + 0.35 * (t * t);
      return { transform: `translateZ(0) scale(${s.toFixed(4)})` };
    },

    onResize() {
      this.onlineChart && this.onlineChart.resize();
      this.controlChart && this.controlChart.resize();
      this.deviceChart && this.deviceChart.resize();
    },
    startClock() {
      const tick = () => {
        const d = new Date();
        const pad = (n) => String(n).padStart(2, "0");
        this.header.timeText = `${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
        this.header.dateText = `${d.getFullYear()}.${pad(d.getMonth() + 1)}.${pad(d.getDate())}`;
        const wk = ["周日", "周一", "周二", "周三", "周四", "周五", "周六"][d.getDay()];
        this.header.weekText = wk;
      };
      tick();
      this.timerClock = setInterval(tick, 1000);
    },

    initCharts() {
      this.onlineChart = echarts.init(this.$refs.onlineChart);
      this.controlChart = echarts.init(this.$refs.controlChart);
      this.deviceChart = echarts.init(this.$refs.deviceChart);
    },

    renderCharts() {
      this.renderOnlineChart();
      this.renderControlChart();
      this.renderDeviceChart();
    },

    renderOnlineChart() {
      const v = this.onlineView;
      this.onlineChart.setOption({
        animation: true,
        series: [
          {
            type: "pie",
            radius: ["70%", "88%"],
            center: ["50%", "50%"],
            silent: true,
            label: { show: false },
            labelLine: { show: false },
            data: [
              { value: v.online, name: "在线" },
              { value: Math.max(0, v.total - v.online), name: "离线" }
            ]
          }
        ],
        graphic: [
          {
            type: "text",
            left: "center",
            top: "40%",
            style: {
              text: `${v.rate}%`,
              fill: "rgba(235,255,255,0.92)",
              fontSize: 22,
              fontWeight: 800
            }
          },
          {
            type: "text",
            left: "center",
            top: "58%",
            style: {
              text: `${v.online}/${v.total}`,
              fill: "rgba(190,225,255,0.70)",
              fontSize: 12,
              fontWeight: 600
            }
          }
        ]
      });
    },

    renderControlChart() {
      const items = this.controlLegend || [];
      const total = this.controlTotal || items.reduce((s, x) => s + (x.v || 0), 0) || 0;
      this.controlChart.setOption({
        animation: true,
        series: [
          {
            type: "pie",
            radius: ["72%", "90%"],
            center: ["50%", "50%"],
            silent: true,
            label: { show: false },
            labelLine: { show: false },
            data: items.map((x) => ({ value: x.v, name: x.t }))
          }
        ],
        graphic: [
          {
            type: "text",
            left: "center",
            top: "40%",
            style: {
              text: `${total}个`,
              fill: "rgba(235,255,255,0.92)",
              fontSize: 18,
              fontWeight: 800
            }
          },
          {
            type: "text",
            left: "center",
            top: "58%",
            style: {
              text: "控制信息",
              fill: "rgba(190,225,255,0.70)",
              fontSize: 12,
              fontWeight: 600
            }
          }
        ]
      });
    },

    renderDeviceChart() {
      const v = this.deviceView;
      this.deviceChart.setOption({
        animation: true,
        series: [
          {
            type: "pie",
            radius: ["70%", "88%"],
            center: ["50%", "50%"],
            silent: true,
            label: { show: false },
            labelLine: { show: false },
            data: [
              { value: v.fault, name: "故障" },
              { value: Math.max(0, v.normal), name: "正常" }
            ]
          }
        ],
        graphic: [
          {
            type: "text",
            left: "center",
            top: "45%",
            style: {
              text: v.fault === 0 ? "故障 0" : `故障 ${v.fault}`,
              fill: "rgba(235,255,255,0.92)",
              fontSize: 18,
              fontWeight: 800
            }
          }
        ]
      });
    },

    setOnlineTab(key, byUser) {
      this.onlineTab = key;
      this.renderOnlineChart();
      if (byUser) this.cycleIdx = this.onlineTabs.findIndex((x) => x.key === key);
    },
    setDeviceTab(key, byUser) {
      this.deviceTab = key;
      this.renderDeviceChart();
      if (byUser) this.deviceCycleIdx = this.deviceTabs.findIndex((x) => x.key === key);
    },

    ignoreAlarm(id) {
      this.alarms = this.alarms.filter((x) => x.id !== id);
    },
    viewAlarm(a) {
      this.mapPopup = { title: a.title, loc: a.loc, time: a.time };
      setTimeout(() => {
        if (this.mapPopup && this.mapPopup.title === a.title) this.mapPopup = null;
      }, 3000);
    },

    goDuty(r) {
      this.activeDutyId = r.id;
      this.mapPopup = {
        title: "勤务任务提醒",
        loc: r.name,
        time: this.header.dateText + " " + this.header.timeText
      };
    },

    doSearch() {
      this.mapPopup = {
        title: "查询结果",
        loc: this.mapQuery || "（未输入）",
        time: this.header.dateText + " " + this.header.timeText
      };
      setTimeout(() => (this.mapPopup = null), 2200);
    },
    assetUrl(file) {
      try {
        return require("@/assets/main/" + file);
      } catch (e) {
        return "";
      }
    },
    navIconStyle(m) {
      return { backgroundImage: `url(${this.assetUrl(m.img)})` };
    },
    selectModule(m) {
      this.activeModule = m.key;
      if (m.route && this.$router) this.$router.push(m.route);
    },
    dockPrev() {
      if (typeof this.activeDockIndex !== "number") this.activeDockIndex = 0;
      const n = (this.dockItems && this.dockItems.length) ? this.dockItems.length : 6;
      this.activeDockIndex = (this.activeDockIndex - 1 + n) % n;
    },
    dockNext() {
      if (typeof this.activeDockIndex !== "number") this.activeDockIndex = 0;
      const n = (this.dockItems && this.dockItems.length) ? this.dockItems.length : 6;
      this.activeDockIndex = (this.activeDockIndex + 1) % n;
    },
  }
};
</script>

<style scoped>


/* ====== Root ====== */
.page{
  width:100vw;
  height:100vh;
  overflow:hidden;
  background: radial-gradient(1200px 700px at 50% 25%, rgba(40,120,255,0.22), rgba(5,12,30,1) 58%);
  position:relative;
  --s: 1;
  font-family: "Microsoft YaHei", system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif;
  display:flex;
  flex-direction:column;
}


/* ====== Top ====== */
.topbar{
  height: calc(var(--s) * 100px);
  display:grid;
  grid-template-columns: 1fr 1.6fr 1fr;
  align-items:center;
  padding: 0 calc(var(--s) * 26px);
  position:relative;
  background: center/100% 100% no-repeat;
  background-image: url("~@/assets/main/main-header.png");
  z-index: 10;
}
.topbar::before{ display:none; }
.title-frame{
  width: min(62vw, calc(var(--s) * 980px));
  height: calc(var(--s) * 64px);
  border-radius: calc(var(--s) * 14px);
  background: rgba(10,35,70,0.35);
  box-shadow: inset 0 0 calc(var(--s) * 26px) rgba(0,160,255,0.18);
  display:flex;
  align-items:center;
  justify-content:center;
}
.title{
  font-size: calc(var(--s) * 34px);
  letter-spacing: calc(var(--s) * 2px);
  text-shadow: 0 0 calc(var(--s) * 10px) rgba(90, 200, 255, 0.35);
  font-weight: 600;
}

.clock{ text-align:right; color: rgba(235,255,255,0.92); }
.time{ font-weight: 900; font-size: clamp(18px, 1.6vw, 28px); letter-spacing: 1px; }
.date{ margin-top:4px; font-size: 12px; color: rgba(190,225,255,0.78); }
.sep{ margin: 0 6px; opacity: 0.6; }

/* ====== Grid ====== */
.grid{
  flex: 1;
  min-height: 0;
  padding: clamp(10px, 1.6vw, 18px);
  display:grid;
  grid-template-columns: 1fr 2.1fr 1fr;
  gap: clamp(10px, 1.2vw, 16px);
}
.col{ min-width:0; min-height:0; }
.col.left, .col.right{ display:grid; grid-template-rows: 1fr 1fr 1fr; gap: clamp(10px, 1.2vw, 16px); }
.col.mid{ display:flex; flex-direction:column; gap: clamp(10px, 1.2vw, 16px); }
.grow{ flex:1; min-height:0; overflow:hidden; }

/* ====== Cards ====== */
.card{
  display:flex;
  flex-direction:column;
  min-height:0;
  border-radius: 14px;
  background: linear-gradient(180deg, rgba(8,22,60,0.58), rgba(8,22,60,0.28));
  border: 1px solid rgba(80,200,255,0.18);
  box-shadow: 0 0 24px rgba(0,160,255,0.08);
  padding: 12px 12px;
  position:relative;
  overflow:hidden;
}
.card::before{
  content:"";
  position:absolute;
  inset:0;
  background:
    radial-gradient(500px 220px at 30% 0%, rgba(0,220,255,0.16), rgba(0,0,0,0)),
    radial-gradient(420px 220px at 80% 100%, rgba(30,120,255,0.10), rgba(0,0,0,0));
  pointer-events:none;
}
.card-h{
  position:relative;
  z-index:1;
  display:flex;
  align-items:center;
  gap:10px;
  color: rgba(230,250,255,0.92);
  font-weight: 800;
  letter-spacing: 0.5px;
  margin-bottom: 10px;
}
.h-dot{
  width: 6px; height: 6px; border-radius: 50%;
  background: rgba(0,240,255,0.9);
  box-shadow: 0 0 12px rgba(0,240,255,0.55);
}

/* Tabs */
.tabs{
  position:relative; z-index:1;
  display:flex;
  gap: 10px;
  margin-bottom: 10px;
}
.tab{
  flex:1;
  height: 28px;
  border-radius: 8px;
  border: 1px solid rgba(80,200,255,0.18);
  background: rgba(10,30,80,0.28);
  color: rgba(190,225,255,0.82);
  cursor:pointer;
  font-weight:700;
  font-size: 12px;
}
.tabs.small{ margin-bottom: 8px; }
.tabs.small .tab{ height: 26px; font-size: 12px; }
.tab.active{
  background: rgba(0,180,255,0.18);
  color: rgba(235,255,255,0.92);
  box-shadow: 0 0 16px rgba(0,200,255,0.14);
}

/* Charts */
.row{ position:relative; z-index:1; display:grid; grid-template-columns: 140px 1fr; gap: 12px; align-items:center; }
.chart.donut{ width: 140px; height: 120px; }
.chart.donut.small{ width: 120px; height: 108px; }
.row.row-b{ grid-template-columns: 1fr 120px; }
.legend.legend-b{ gap: 8px; }
.legend.legend-b .lg{ grid-template-columns: 14px 1fr auto; }
.legend{ display:flex; flex-direction:column; gap: 8px; }
.lg{ display:flex; align-items:center; gap: 8px; color: rgba(200,235,255,0.78); font-size: 12px; }
.lg .num{ margin-left:auto; color: rgba(235,255,255,0.92); font-weight: 800; }
.subnote{ margin-top: 2px; color: rgba(170,215,255,0.62); font-size: 12px; }

.b{ width:8px; height:8px; border-radius: 2px; display:inline-block; }
.b-on{ background: rgba(80,240,255,0.95); }
.b-off{ background: rgba(255,200,60,0.85); }
.b-rate{ background: rgba(0,160,255,0.85); }
.b-ok{ background: rgba(80,255,160,0.85); }
.b-bad{ background: rgba(255,90,90,0.9); }

/* Modes */
.mode-grid{ position:relative; z-index:1; display:grid; gap: 10px; }
.mode{
  border: 1px solid rgba(80,200,255,0.12);
  background: rgba(6,18,55,0.22);
  border-radius: 12px;
  padding: 10px;
}
.mode-h{ color: rgba(220,250,255,0.88); font-weight: 800; font-size: 12px; margin-bottom: 8px; }
.mode-b{ display:flex; flex-wrap: wrap; gap: 8px; }
.pill{
  padding: 6px 10px;
  border-radius: 999px;
  border: 1px solid rgba(80,200,255,0.16);
  background: rgba(10,30,80,0.28);
  color: rgba(190,225,255,0.82);
  font-size: 12px;
  font-weight: 700;
}
.pill.warn{ border-color: rgba(255,200,60,0.25); background: rgba(255,200,60,0.10); color: rgba(255,230,170,0.9); }
.pill.mute{ border-color: rgba(160,180,220,0.16); background: rgba(10,30,80,0.12); color: rgba(170,200,240,0.75); }

/* Alarms */
.alarm-list{
  flex:1;
  min-height:0;
  overflow:auto;
 position:relative; z-index:1; height: 100%; overflow:hidden; padding-right: 6px; }
.alarm-item{
  display:flex;
  justify-content:space-between;
  gap: 10px;
  padding: 10px 0;
  border-bottom: 1px solid rgba(80,200,255,0.10);
}
.a-title{ display:flex; align-items:center; gap: 10px; }
.lvl{
  min-width: 38px;
  height: 18px;
  display:inline-flex;
  align-items:center;
  justify-content:center;
  border-radius: 6px;
  font-size: 11px;
  font-weight: 900;
  letter-spacing: 0.5px;
}
.lv-1{ background: rgba(255,90,90,0.16); border: 1px solid rgba(255,90,90,0.35); color: rgba(255,170,170,0.95); }
.lv-2{ background: rgba(255,200,60,0.14); border: 1px solid rgba(255,200,60,0.30); color: rgba(255,235,190,0.92); }
.lv-3{ background: rgba(0,200,255,0.12); border: 1px solid rgba(0,200,255,0.25); color: rgba(190,245,255,0.92); }
.lv-4{ background: rgba(160,180,220,0.12); border: 1px solid rgba(160,180,220,0.22); color: rgba(205,225,255,0.85); }
.txt{ color: rgba(235,255,255,0.92); font-weight: 900; }
.a-sub{ margin-top: 6px; display:flex; gap: 10px; color: rgba(180,220,255,0.68); font-size: 12px; }
.a-sub .time{ margin-left:auto; opacity:0.85; }
.a-actions{ display:flex; align-items:center; gap: 8px; }
.btn{
  height: 28px;
  padding: 0 10px;
  border-radius: 10px;
  border: 1px solid rgba(80,200,255,0.18);
  background: rgba(10,30,80,0.22);
  color: rgba(200,235,255,0.82);
  cursor:pointer;
  font-weight: 800;
  font-size: 12px;
}
.btn.primary{
  background: rgba(0,200,255,0.16);
  color: rgba(235,255,255,0.92);
}
.btn.ghost{ background: rgba(10,30,80,0.12); }
.btn.icon{ height: 30px; border-radius: 10px; }
.empty{ padding: 18px 0; color: rgba(180,220,255,0.55); text-align:center; }

/* Map */
.map-wrap{ flex:1; min-height:0; }
.map-frame{
  position: relative;
  height:100%;
  border-radius: 16px;
  border: 1px solid rgba(80,200,255,0.18);
  background: linear-gradient(180deg, rgba(8,22,60,0.42), rgba(8,22,60,0.18));
  box-shadow: 0 0 28px rgba(0,160,255,0.08);
  position:relative;
  overflow:hidden;
}
.map-tools{
  position:absolute;
  top: 10px;
  left: 12px;
  right: 12px;
  display:flex;
  justify-content:space-between;
  gap: 10px;
  z-index: 3;
}
.search{
  display:flex;
  gap: 8px;
  align-items:center;
}
.search input{
  width: 180px;
  height: 30px;
  border-radius: 10px;
  border: 1px solid rgba(80,200,255,0.18);
  background: rgba(0,0,0,0.18);
  color: rgba(235,255,255,0.9);
  padding: 0 10px;
  outline:none;
}
.select{
  height: 30px;
  min-width: 100px;
  border-radius: 10px;
  border: 1px solid rgba(80,200,255,0.18);
  background: rgba(0,0,0,0.18);
  color: rgba(200,235,255,0.85);
  display:flex;
  align-items:center;
  justify-content:space-between;
  padding: 0 10px;
}
.caret{ opacity:0.8; }

.map-canvas{
  padding-bottom: calc(var(--s) * 120px);
  position:absolute;
  inset:0;
  background-image:
    radial-gradient(900px 520px at 50% 35%, rgba(0,220,255,0.10), rgba(0,0,0,0)),
    radial-gradient(720px 420px at 30% 75%, rgba(30,120,255,0.10), rgba(0,0,0,0));
  background-size: cover;
  background-position:center;
}
.roads{
  position:absolute;
  inset:0;
  z-index: 1;
  opacity: 0.9;
}
.r{
  fill:none;
  stroke-width: 10;
  stroke-linecap: round;
  filter: drop-shadow(0 0 8px rgba(0,255,255,0.25));
}
.r.g{ stroke: rgba(60,255,160,0.82); }
.r.b{ stroke: rgba(60,190,255,0.88); }
.r.y{ stroke: rgba(255,220,80,0.88); }
.r.red{ stroke: rgba(255,90,90,0.92); }
.node{ fill: rgba(0,220,255,0.7); stroke: rgba(255,255,255,0.25); stroke-width: 2; }

.popup{
  position:absolute;
  left: 50%;
  top: 62%;
  transform: translate(-50%, -50%);
  width: min(360px, 46vw);
  border-radius: 14px;
  border: 1px solid rgba(80,200,255,0.20);
  background: rgba(0,0,0,0.35);
  backdrop-filter: blur(10px);
  padding: 12px 14px;
  z-index: 2;
}
.popup-title{ color: rgba(235,255,255,0.92); font-weight: 900; margin-bottom: 6px; }
.popup-line{ color: rgba(190,225,255,0.78); font-size: 12px; margin-top: 4px; }

.legend-box{
  position:absolute;
  right: 14px;
  bottom: calc(var(--s) * 150px);
  width: 140px;
  border-radius: 14px;
  border: 1px solid rgba(80,200,255,0.16);
  background: rgba(0,0,0,0.22);
  backdrop-filter: blur(8px);
  padding: 10px 10px;
  z-index: 2;
}
.legend-title{ color: rgba(230,250,255,0.9); font-weight: 900; margin-bottom: 8px; }
.legend-row{ display:flex; align-items:center; gap: 8px; padding: 4px 0; color: rgba(190,225,255,0.78); font-size: 12px; }
.chip{ width:10px; height:10px; border-radius: 3px; display:inline-block; }
.c1{ background: rgba(60,190,255,0.88); }
.c2{ background: rgba(60,255,160,0.82); }
.c3{ background: rgba(255,220,80,0.88); }
.c4{ background: rgba(0,220,255,0.78); }
.c5{ background: rgba(170,255,240,0.78); }
.c6{ background: rgba(140,190,255,0.78); }
.c7{ background: rgba(255,180,120,0.78); }
.c8{ background: rgba(255,200,60,0.78); }
.c9{ background: rgba(120,140,180,0.78); }
.c10{ background: rgba(255,220,80,0.72); }
.c11{ background: rgba(255,90,90,0.90); }

/* Tables */
.tbl-wrap{
  flex:1;
  min-height:0;
  overflow:auto;
  height:100%; overflow:hidden; }
.tbl{
  width:100%;
  border-collapse: collapse;
  color: rgba(220,250,255,0.86);
  font-size: 12px;
  table-layout: fixed;
}
.tbl thead th{
  position:sticky;
  top:0;
  z-index:1;
  background: rgba(8,22,60,0.65);
  color: rgba(180,230,255,0.72);
  font-weight: 900;
  border-bottom: 1px solid rgba(80,200,255,0.12);
  padding: 8px 6px;
  text-align: center;
  box-sizing: border-box;
}
.tbl td{
  padding: 8px 6px;
  border-bottom: 1px solid rgba(80,200,255,0.10);
  text-align: center;
  box-sizing: border-box;
}
.tbl .name{
  color: rgba(235,255,255,0.92); 
  font-weight: 800;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  cursor: default;
}
.tbl tbody tr.hl{ background: rgba(0,200,255,0.10); }
.tag{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  height: 18px;
  min-width: 40px;
  border-radius: 6px;
  font-weight: 900;
  font-size: 11px;
  border: 1px solid rgba(80,200,255,0.14);
  color: rgba(190,245,255,0.9);
  background: rgba(0,200,255,0.10);
}
.tag.lv1{ border-color: rgba(0,220,255,0.20); }
.tag.lv2{ border-color: rgba(255,220,80,0.25); color: rgba(255,240,200,0.92); background: rgba(255,220,80,0.10); }
.tag.lv3{ border-color: rgba(255,140,140,0.24); color: rgba(255,200,200,0.92); background: rgba(255,90,90,0.10); }
.tag.lv4{ border-color: rgba(160,180,220,0.18); color: rgba(210,230,255,0.86); background: rgba(160,180,220,0.10); }

.st{ font-weight: 900; }
.st.wait{ color: rgba(190,225,255,0.78); }
.st.run{ color: rgba(255,220,80,0.92); }

.link{
  color: rgba(130,230,255,0.95);
  text-decoration:none;
  font-weight: 900;
}
.tbl.simple thead th{ position:static; background: transparent; }

/* ====== Bottom nav ====== */
.bottombar{
  flex: 0 0 auto;
  height: clamp(88px, 11vh, 122px);
  display:flex;
  align-items:center;
  justify-content:center;
  padding: 0 14px 10px;
}
.nav-row{
  display:flex;
  align-items:center;
  justify-content:center;
  gap: clamp(10px, 1vw, 16px);
}
.bottombar::before{
  content:"";
  position:absolute;
  inset:0;
  background: linear-gradient(0deg, rgba(10,30,80,0.85), rgba(10,30,80,0.20));
  border-top: 1px solid rgba(80,200,255,0.16);
  pointer-events:none;
}
.nav-viewport{
  width: min(860px, 78vw);
  overflow:hidden;
  position:relative;
  z-index: 1;
}
.nav-track{
  display:flex;
  gap: 12px;
  transition: transform 0.25s ease;
  will-change: transform;
}
.nav-item{
  width: clamp(92px, 6.8vw, 124px);
  height: clamp(72px, 9vh, 96px);
  border-radius: 16px;
  border: 1px solid rgba(80,200,255,0.16);
  background: rgba(0,0,0,0.12);
  cursor:pointer;
  display:flex;
  flex-direction:column;
  align-items:center;
  justify-content:center;
  gap: 8px;
  color: rgba(200,235,255,0.76);
  position:relative;
  transition: transform .16s ease, border-color .16s ease, box-shadow .16s ease;
}
.nav-item.active{
  background: rgba(0,200,255,0.10);
  color: rgba(235,255,255,0.92);
  box-shadow: 0 0 20px rgba(0,200,255,0.14);
}
.nav-item:hover{
  transform: translateZ(0) scale(1.03);
  border-color: rgba(0,220,255,0.26);
  box-shadow: 0 0 20px rgba(0,220,255,0.10);
}
.nav-ic{
  width: clamp(58px, 4.8vw, 86px);
  height: clamp(52px, 5.8vh, 78px);
  border-radius: 14px;
  display:flex;
  align-items:center;
  justify-content:center;
  border: 1px solid rgba(80,200,255,0.18);
  background: rgba(10,30,80,0.22);
}
.nav-img{
  width: 100%;
  background: center/contain no-repeat;
  filter: drop-shadow(0 0 10px rgba(80,200,255,0.35));
}
.nav-ic.glow{
  box-shadow: 0 0 18px rgba(0,220,255,0.22);
  background: rgba(0,200,255,0.10);
}
.nav-t{ font-weight: 900; font-size: 12px; }

.arrow{
  position:relative;
  z-index: 2;
  width: 38px; height: 38px;
  border-radius: 999px;
  border: 1px solid rgba(80,200,255,0.18);
  background: rgba(0,0,0,0.18);
  color: rgba(220,250,255,0.9);
  font-size: 22px;
  line-height: 38px;
  cursor:pointer;
}

/* Icons (CSS placeholders) */
.ic{ width:18px; height:18px; display:inline-block; position:relative; }
.ic-home::before{ content:""; position:absolute; inset:2px 3px 6px 3px; border:2px solid rgba(190,245,255,0.85); border-bottom:none; transform: skewY(-10deg); }
.ic-home::after{ content:""; position:absolute; left:5px; right:5px; bottom:6px; height:10px; border:2px solid rgba(190,245,255,0.85); background: rgba(0,200,255,0.06); }
.ic-eye::before{ content:""; position:absolute; left:1px; right:1px; top:5px; height:10px; border:2px solid rgba(190,245,255,0.85); border-radius: 999px; }
.ic-eye::after{ content:""; position:absolute; left:7px; top:9px; width:4px; height:4px; border-radius: 999px; background: rgba(190,245,255,0.85); }
.ic-shield::before{ content:""; position:absolute; left:4px; right:4px; top:2px; bottom:2px; border:2px solid rgba(190,245,255,0.85); border-radius: 8px; clip-path: polygon(0 0, 100% 0, 100% 55%, 50% 100%, 0 55%); }
.ic-road::before{ content:""; position:absolute; left:7px; top:2px; bottom:2px; width:4px; border-left:2px solid rgba(190,245,255,0.85); border-right:2px solid rgba(190,245,255,0.85); }
.ic-road::after{ content:""; position:absolute; left:9px; top:4px; bottom:4px; width:0; border-left:2px dashed rgba(190,245,255,0.65); }
.ic-chart::before{ content:""; position:absolute; left:2px; right:2px; bottom:2px; top:2px; border:2px solid rgba(190,245,255,0.85); border-radius: 6px; }
.ic-chart::after{ content:""; position:absolute; left:5px; bottom:6px; width:10px; height:6px; border-left:2px solid rgba(0,220,255,0.85); border-bottom:2px solid rgba(0,220,255,0.85); transform: skewX(-15deg); }
.ic-gear::before{ content:""; position:absolute; inset:3px; border:2px solid rgba(190,245,255,0.85); border-radius: 999px; }
.ic-gear::after{ content:""; position:absolute; inset:7px; background: rgba(190,245,255,0.85); border-radius: 999px; opacity:0.8; }
.ic-bell::before{ content:""; position:absolute; left:4px; right:4px; top:3px; bottom:4px; border:2px solid rgba(190,245,255,0.85); border-radius: 10px 10px 8px 8px; }
.ic-bell::after{ content:""; position:absolute; left:8px; bottom:2px; width:4px; height:4px; border-radius: 999px; background: rgba(190,245,255,0.85); }
.ic-chip::before{ content:""; position:absolute; inset:3px; border:2px solid rgba(190,245,255,0.85); border-radius: 6px; }
.ic-chip::after{ content:""; position:absolute; left:6px; right:6px; top:8px; height:0; border-top:2px dashed rgba(190,245,255,0.65); }

/* Responsive */
@media (max-width: 1180px){
  .grid{ grid-template-columns: 1fr; }
  .nav-viewport{ width: 94vw; }
  .map-frame{ min-height: 42vh; }
}


/* ====== Chart layout align with UI sample ====== */
.card-a .row{ flex-direction: row-reverse; gap: calc(var(--s) * 14px); }
.card-a .donut{ width: calc(var(--s) * 160px); height: calc(var(--s) * 160px); }
.card-a .legend{ flex: 1; padding-right: calc(var(--s) * 6px); }

.card-b .row-b{ flex-direction: row; gap: calc(var(--s) * 14px); }
.card-b .donut.small{ width: calc(var(--s) * 150px); height: calc(var(--s) * 150px); }

.card-r1 .row{ flex-direction: row-reverse; gap: calc(var(--s) * 14px); }
.card-r1 .donut{ width: calc(var(--s) * 160px); height: calc(var(--s) * 160px); }


/* ====== Bottom Dock (overlay on map) ====== */
.dock-wrap{
  position:absolute;
  left:50%;
  bottom: calc(var(--s) * 14px);
  transform: translateX(-50%);
  width: min(86%, calc(var(--s) * 980px)); /* 基本与地图主体宽度一致 */
  display:flex;
  justify-content:center;
  pointer-events:auto;
  z-index: 9;
}
.dockbar{
  width: 100%;
  display:flex;
  align-items:flex-end;
  justify-content:space-between;
  gap: calc(var(--s) * 22px);
  padding: calc(var(--s) * 6px) calc(var(--s) * 10px);
}
.dock-item{
  width: calc(var(--s) * 98px);
  height: calc(var(--s) * 124px);
  display:flex;
  flex-direction:column;
  align-items:center;
  justify-content:flex-start;
  cursor:pointer;
  transform-origin: 50% 80%;
  transition: transform .08s linear;
}
.dock-icon{
  width: calc(var(--s) * 98px);
  height: calc(var(--s) * 86px);
  background: center/contain no-repeat;
  filter: drop-shadow(0 0 calc(var(--s) * 12px) rgba(70, 190, 255, .35));
}
.dock-label{
  margin-top: calc(var(--s) * 10px);
  font-size: calc(var(--s) * 14px);
  line-height: 1;
  opacity: .92;
  text-shadow: 0 0 calc(var(--s) * 8px) rgba(0, 160, 255, .25);

  color: rgba(235,255,255,0.92);
  text-shadow: 0 0 calc(var(--s) * 10px) rgba(0,160,255,.35);
}
.dock-item:hover .dock-icon{
  filter: drop-shadow(0 0 calc(var(--s) * 18px) rgba(120, 230, 255, .65));
}




/* ====== Patch: header corner info (match 示例图) ====== */
.top-left, .top-right{
  align-self: start;
  padding-top: calc(var(--s) * 60px);
}
.weather{
  display:flex;
  align-items:center;
  gap: calc(var(--s) * 10px);
  color: rgba(235,255,255,0.92);
}
.dot-sun{
  width: calc(var(--s) * 8px);
  height: calc(var(--s) * 8px);
  border-radius: 50%;
  background: rgba(255,220,120,0.95);
  box-shadow: 0 0 calc(var(--s) * 10px) rgba(255,220,120,0.55);
  display:inline-block;
}
.w1{ font-size: calc(var(--s) * 18px); font-weight: 700; letter-spacing: 1px; }
.w2{ font-size: calc(var(--s) * 16px); opacity: .9; }

.clock{ text-align:right; color: rgba(235,255,255,0.92); }
.time{
  font-weight: 900;
  font-size: calc(var(--s) * 28px);
  line-height: 1;
  letter-spacing: 1px;
  text-shadow: 0 0 calc(var(--s) * 10px) rgba(90, 200, 255, 0.28);
}
.date{
  margin-top: calc(var(--s) * 6px);
  font-size: calc(var(--s) * 12px);
  color: rgba(190,225,255,0.78);
}

/* ====== Patch: side cards sizing (avoid squashed/hidden) ====== */
.left .card-a, .right .card-a{ flex: 0 0 calc(var(--s) * 220px); }
.left .card-b{ flex: 0 0 calc(var(--s) * 240px); }
.right .card-b{ flex: 0 0 calc(var(--s) * 230px); }
.left .grow, .right .grow{ flex: 1 1 auto; min-height: calc(var(--s) * 230px); }

/* ====== Patch: dock arrows + label color (match 示例图) ====== */
.dock-wrap{
  display:flex;
  align-items:center;
  justify-content:center;
  gap: calc(var(--s) * 22px);
}
.dock-arrow{
  width: calc(var(--s) * 54px);
  height: calc(var(--s) * 54px);
  background: center/contain no-repeat;
  opacity: .92;
  cursor: pointer;
  transition: transform .18s ease, opacity .18s ease, filter .18s ease;
  filter: drop-shadow(0 0 calc(var(--s) * 10px) rgba(60, 180, 255, .35));
}
.dock-arrow:hover{
  opacity: 1;
  transform: translateZ(0) scale(1.08);
  filter: drop-shadow(0 0 calc(var(--s) * 14px) rgba(90, 210, 255, .6));
}
.dock-arrow.left{ background-image: url("~@/assets/main/main-left.png"); }
.dock-arrow.right{ background-image: url("~@/assets/main/main-right.png"); }

.dock-label{
  color: rgba(235,255,255,0.92) !important;
  text-shadow: 0 0 calc(var(--s) * 8px) rgba(0, 160, 255, 0.28);
}
</style>