:root {
  color-scheme: dark;
  --d2-bg: #0b0d0f;
  --d2-panel: rgba(16, 19, 22, 0.94);
  --d2-panel-2: rgba(25, 29, 33, 0.95);
  --d2-line: rgba(229, 224, 212, 0.16);
  --d2-line-strong: rgba(229, 224, 212, 0.28);
  --d2-text: #f3efe4;
  --d2-muted: #a9a397;
  /* 次要文字（.d2-list-group__label em 展开按钮副标题 / .d2-section-note / 各类 small）：
     原值 #746f67 在深色面板上对比度只有 3.4~3.8，移动端小字号下几乎看不清。
     提到 #8f8a80 后对比度约 5.1，仍保持"次要"层级感。 */
  --d2-dim: #8f8a80;
  --d2-accent: #d7b56d;
  --d2-green: #79d78e;
  --d2-red: #f36f63;
  --d2-blue: #68a8f4;
  --d2-cyan: #5cd2d8;
  --d2-violet: #b890ff;
  --d2-radius: 8px;
  --d2-shadow: 0 18px 46px rgba(0, 0, 0, 0.42);
  --d2-left: 336px;
  --d2-right: 360px;
  font-family: "Microsoft YaHei", "PingFang SC", "Segoe UI", Arial, sans-serif;
}

* {
  box-sizing: border-box;
}

html,
body {
  width: 100%;
  min-height: 100%;
  margin: 0;
  background: var(--d2-bg);
  color: var(--d2-text);
}

body.takefu-ditu2 {
  display: flex;
  flex-direction: column;
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
}

/* 全站通用导航（takefu-shell，data-takefu-shell="map"）是 sticky 顶栏，占据正常文档流高度。
   #ditu2-app 作为弹性剩余区域承载全屏地图应用，内部各绝对定位层因此自动避让顶栏，
   不需要 JS 测量顶栏高度，也就不会出现首屏顶栏闪入导致的地图高度跳变。 */
body.takefu-ditu2 #ditu2-app {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
}

button,
input,
select {
  font: inherit;
}

/* 2026-10-20：默认蓝色点击高亮在深色地图上每次点击都会闪一片蓝，改为自定义 :active 反馈 */
html, body, button, a, input, [role="button"] { -webkit-tap-highlight-color: transparent; }
button {
  color: inherit;
}

.d2-app {
  position: absolute;
  inset: 0;
  display: grid;
  grid-template-columns: var(--d2-left) minmax(0, 1fr) var(--d2-right);
  grid-template-rows: 100%;
  background:
    radial-gradient(circle at 55% -20%, rgba(215, 181, 109, 0.12), transparent 36%),
    linear-gradient(180deg, #13171a 0%, #08090a 100%);
}

.d2-error {
  position: absolute;
  inset: 0;
  z-index: 40;
  display: grid;
  place-items: center;
  background: #0b0d0f;
  color: var(--d2-text);
}

/* ===== 2026-10-14 审计修复 D1：加载超时提示条 =====
   首屏数据（图文索引 / items / overlay / tasks）超时未到齐时出现，
   **不替换已渲染的界面** —— 用户仍可用当前图层，且数据稍后到达会自动接管。 */
.d2-loadtimeout { position: absolute; left: 50%; top: 12px; transform: translateX(-50%); z-index: 95; display: flex; align-items: center; gap: 10px; max-width: calc(100vw - 24px); padding: 7px 12px; border: 1px solid rgba(215, 181, 109, .45); border-radius: 8px; background: var(--d2-overlay); color: var(--d2-text); font-size: 13px; -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px); }
.d2-loadtimeout button { flex: 0 0 auto; border: 1px solid rgba(215, 181, 109, .5); background: rgba(215, 181, 109, .14); color: var(--d2-accent); border-radius: 6px; padding: 3px 10px; font-size: 13px; cursor: pointer; }
.d2-loadtimeout button:hover { background: rgba(215, 181, 109, .26); }
/* ===== 2026-10-14 审计修复 D4：错误页给出可点击的恢复入口 =====
   旧错误页只有一行文字，用户除了手动刷新浏览器没有任何出路。 */
.d2-error__hint { margin-top: 8px; color: var(--d2-muted); font-size: 13px; }
.d2-error__actions { display: flex; gap: 10px; justify-content: center; margin-top: 12px; }
.d2-error__actions button, .d2-error__actions a { border: 1px solid rgba(215, 181, 109, .5); background: rgba(215, 181, 109, .14); color: var(--d2-accent); border-radius: 8px; padding: 7px 16px; font-size: 14px; line-height: 1.2; text-decoration: none; cursor: pointer; }
.d2-error__actions button:hover, .d2-error__actions a:hover { background: rgba(215, 181, 109, .26); }
.d2-error__box {
  width: min(420px, calc(100vw - 40px));
  border: 1px solid var(--d2-line);
  border-radius: var(--d2-radius);
  background: var(--d2-panel);
  box-shadow: var(--d2-shadow);
  padding: 22px;
}

/*
 * 首屏骨架：先把三栏版面结构画出来，JS 还没执行就能看到"内容正在加载"，
 * 不会出现白屏干等。加载完成后整块被 .d2-app 替换。
 */
.d2-loading {
  position: absolute;
  inset: 0;
  z-index: 40;
  display: grid;
  grid-template-rows: minmax(0, 1fr) auto;
  background: var(--d2-bg);
  color: var(--d2-text);
}

.d2-loading__app {
  display: grid;
  grid-template-columns: var(--d2-left) minmax(0, 1fr) var(--d2-right);
  gap: 14px;
  min-height: 0;
  padding: 14px 14px 0;
}

.d2-loading__side,
.d2-loading__detail {
  display: grid;
  align-content: start;
  gap: 10px;
}

.d2-loading__stage {
  min-width: 0;
  border: 1px solid var(--d2-line);
  border-radius: var(--d2-radius);
  background: var(--d2-panel);
  padding: 10px;
}

.d2-loading__map {
  height: 100%;
  min-height: 240px;
}

.d2-skel,
.d2-loading__map {
  border-radius: 8px;
  background: linear-gradient(100deg, rgba(255, 255, 255, 0.05) 30%, rgba(255, 255, 255, 0.12) 50%, rgba(255, 255, 255, 0.05) 70%);
  background-size: 200% 100%;
  animation: d2-skel 1.4s ease-in-out infinite;
}

.d2-skel--title { height: 30px; }
.d2-skel--select { height: 40px; }
.d2-skel--search { height: 42px; }
.d2-skel--row { height: 56px; }

@keyframes d2-skel {
  from { background-position: 130% 0; }
  to { background-position: -30% 0; }
}

.d2-loading__box {
  justify-self: center;
  width: min(420px, calc(100vw - 40px));
  margin: 0 0 22px;
  border: 1px solid var(--d2-line);
  border-radius: var(--d2-radius);
  background: var(--d2-panel);
  box-shadow: var(--d2-shadow);
  padding: 16px 20px;
  text-align: center;
}

.d2-loading__box strong {
  display: block;
  font-size: 14px;
}

@media (max-width: 960px) {
  .d2-loading__app {
    grid-template-columns: minmax(0, 1fr);
    padding: 10px 10px 0;
  }

  .d2-loading__side,
  .d2-loading__detail {
    display: none;
  }
}

.d2-loading__bar {
  height: 4px;
  margin-top: 16px;
  border-radius: 99px;
  overflow: hidden;
  background: rgba(255, 255, 255, 0.1);
}

.d2-loading__bar::before {
  content: "";
  display: block;
  width: 42%;
  height: 100%;
  background: var(--d2-accent);
  animation: d2-load 1s ease-in-out infinite alternate;
}

@keyframes d2-load {
  from { transform: translateX(-20%); }
  to { transform: translateX(160%); }
}

.d2-side {
  position: relative;
  z-index: 10;
  display: flex;
  width: var(--d2-left);
  min-height: 0;
  min-width: 0;
  flex-direction: column;
  border-right: 1px solid var(--d2-line);
  background: var(--d2-panel);
  backdrop-filter: blur(18px);
}

.d2-side__head {
  flex: 0 0 auto;
  padding: 16px;
  border-bottom: 1px solid var(--d2-line);
}

.d2-kicker {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  color: var(--d2-muted);
  font-size: 13px;
}

.d2-kicker a {
  color: var(--d2-accent);
  text-decoration: none;
}

.d2-title {
  margin: 8px 0 0;
  font-size: 26px;
  line-height: 1.15;
  letter-spacing: 0;
}

.d2-subtitle {
  margin: 8px 0 0;
  color: var(--d2-muted);
  font-size: 14px;
  line-height: 1.55;
}

.d2-map-select {
  width: 100%;
  height: 38px;
  margin-top: 14px;
  border: 1px solid var(--d2-line-strong);
  border-radius: var(--d2-radius);
  background: #101417;
  color: var(--d2-text);
  padding: 0 10px;
}

.d2-side__body {
  min-height: 0;
  flex: 1 1 auto;
  overflow: auto;
  padding: 12px 12px 16px;
  scrollbar-gutter: stable;
  scrollbar-width: thin;
}

.d2-search {
  position: sticky;
  top: 0;
  z-index: 2;
  padding-bottom: 10px;
  background: linear-gradient(180deg, rgba(16, 19, 22, 0.98), rgba(16, 19, 22, 0.88));
}

.d2-search input {
  width: 100%;
  height: 40px;
  border: 1px solid var(--d2-line-strong);
  border-radius: var(--d2-radius);
  outline: none;
  background: rgba(6, 8, 10, 0.72);
  color: var(--d2-text);
  padding: 0 12px;
}

.d2-search input:focus {
  border-color: rgba(215, 181, 109, 0.76);
}

.d2-mobile-results { display: none; }
@media (max-width: 960px) {
  .d2-mobile-results:not([hidden]) {
    display: block; position: absolute; top: 100%; left: 0; right: 0;
    max-height: min(50dvh, 420px); overflow: auto; z-index: 30;
    background: var(--d2-bg); color: var(--d2-text);
    border: 1px solid var(--d2-line); border-radius: 8px;
    box-shadow: 0 8px 24px #0005;
  }
}
@media (max-width: 360px) and (orientation: portrait) {
  .d2-toolbar { gap: 3px; }
  .d2-toolbar .d2-tool { min-width: 35px; padding: 0 7px; }
}

.d2-quick-presets {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 7px;
  margin-bottom: 10px;
}

.d2-preset {
  display: grid;
  grid-template-columns: 20px minmax(0, 1fr);
  /* 2026-09-30 审计修复：start 会让图标+文字全部顶在 46px 按钮上沿、
     下方空约 20px——「撤离/任务/物资」按钮文字明显错位。改为整行居中。 */
  align-items: center;
  align-content: center;
  gap: 6px;
  min-height: 46px;
  border: 1px solid var(--d2-line);
  border-radius: var(--d2-radius);
  background: rgba(255, 255, 255, 0.04);
  color: var(--d2-muted);
  cursor: pointer;
  padding: 6px 7px;
}

.d2-preset[aria-pressed="true"] {
  border-color: rgba(104, 168, 244, 0.62);
  background: rgba(104, 168, 244, 0.16);
  color: var(--d2-text);
  box-shadow: inset 0 0 0 1px rgba(104, 168, 244, 0.24);
}

.d2-preset[aria-pressed="true"]::after {
  content: "✓";
  position: absolute;
  top: 4px;
  right: 5px;
  color: var(--d2-blue);
  font-size: 12px;
  line-height: 1;
}

.d2-preset {
  position: relative;
}

.d2-preset img {
  width: 19px;
  height: 19px;
  object-fit: contain;
}

.d2-preset span {
  display: block;
  min-width: 0;
}

.d2-preset strong,
.d2-preset small {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.d2-preset strong {
  font-size: 13px;
  line-height: 1.25;
}

.d2-preset small {
  margin-top: 2px;
  color: var(--d2-muted);
  font-size: 10px;
  line-height: 1.2;
}

.d2-value-filters {
  display: none;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 6px;
  margin: 10px 0 12px; /* tidy1：与上方作战模式行拉开间距 */
  padding-top: 8px;
  border-top: 1px solid var(--d2-line);
}

.d2-value-filters.is-visible {
  display: grid;
}

.d2-value-filters button {
  min-width: 0;
  min-height: 30px;
  border: 1px solid var(--d2-line);
  border-radius: 7px;
  background: rgba(255, 255, 255, 0.04);
  color: var(--d2-muted);
  cursor: pointer;
  padding: 5px 6px;
  font-size: 12px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.d2-value-filters button[aria-pressed="true"] {
  border-color: rgba(121, 215, 142, 0.45);
  background: rgba(121, 215, 142, 0.12);
  color: var(--d2-text);
}

.d2-stats {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 8px;
  margin-bottom: 12px;
}

.d2-stat {
  min-width: 0;
  border: 1px solid var(--d2-line);
  border-radius: var(--d2-radius);
  background: rgba(255, 255, 255, 0.04);
  padding: 10px 8px;
}

.d2-stat strong {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 16px;
}

.d2-stat span {
  display: block;
  margin-top: 4px;
  color: var(--d2-muted);
  font-size: 13px;
}

.d2-section-title {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin: 14px 0 8px;
  color: var(--d2-muted);
  font-size: 13px;
}

.d2-section-title button {
  border: 0;
  background: transparent;
  color: var(--d2-accent);
  cursor: pointer;
  font-size: 13px;
  /* 触控热区 ≥24px（文字视觉大小不变，靠 padding 扩展） */
  min-height: 24px;
  padding: 4px 6px;
  margin: -4px -2px;
}

.d2-section-title em {
  margin-left: 6px;
  border: 1px solid rgba(215, 181, 109, 0.34);
  border-radius: 999px;
  background: rgba(215, 181, 109, 0.1);
  color: var(--d2-accent);
  padding: 1px 6px;
  font-size: 10px;
  font-style: normal;
}

.d2-section-note {
  color: var(--d2-dim);
  font-size: 12px;
}

.d2-mode-summary {
  margin: -4px 0 10px;
  color: var(--d2-muted);
  font-size: 12px;
  line-height: 1.4;
}

/* 撤离点阵营快捷筛选：与细分图层共用 activeTypes，只是快捷入口 */
.d2-faction-row {
  display: none;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 6px;
  margin-bottom: 4px;
}

.d2-faction-row.is-visible {
  display: grid;
}

.d2-faction-row button {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  min-width: 0;
  min-height: 32px;
  border: 1px solid var(--d2-line);
  border-radius: 7px;
  background: rgba(255, 255, 255, 0.04);
  color: var(--d2-muted);
  cursor: pointer;
  padding: 5px 4px;
  font-size: 12px;
  white-space: nowrap;
  overflow: hidden;
}

.d2-faction-row button small {
  color: var(--d2-dim);
  font-size: 10px;
}

.d2-faction-row button[aria-pressed="true"] {
  border-color: rgba(121, 215, 142, 0.5);
  background: rgba(121, 215, 142, 0.14);
  color: var(--d2-text);
}

.d2-faction-row button[aria-pressed="true"] small {
  color: var(--d2-green);
}

.d2-filter-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 7px;
}

.d2-filter {
  display: grid;
  grid-template-columns: 24px minmax(0, 1fr) auto;
  align-items: center;
  gap: 8px;
  min-height: 38px;
  border: 1px solid var(--d2-line);
  border-radius: var(--d2-radius);
  background: rgba(255, 255, 255, 0.045);
  color: var(--d2-muted);
  cursor: pointer;
  padding: 6px 8px;
}

.d2-filter[aria-pressed="true"] {
  border-color: rgba(215, 181, 109, 0.52);
  background: rgba(215, 181, 109, 0.12);
  color: var(--d2-text);
}

.d2-filter img {
  width: 22px;
  height: 22px;
  object-fit: contain;
}

.d2-filter span {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 13px;
}

.d2-filter small {
  color: var(--d2-dim);
  font-size: 12px;
}

.d2-list {
  display: grid;
  gap: 8px;
  margin-top: 8px;
}

/* 撤离点 / 任务：互斥手风琴。同时只展开一个，点已展开的标题可全部收起。 */
.d2-list-group {
  border: 1px solid var(--d2-line);
  border-radius: var(--d2-radius);
  background: rgba(255, 255, 255, 0.022);
  overflow: hidden;
}

.d2-list-group__head {
  display: grid;
  grid-template-columns: 26px minmax(0, 1fr) auto 16px;
  align-items: center;
  gap: 8px;
  width: 100%;
  min-height: 46px;
  border: 0;
  background: transparent;
  color: var(--d2-text);
  cursor: pointer;
  padding: 8px 10px;
  text-align: left;
}

.d2-list-group__head:hover {
  background: rgba(255, 255, 255, 0.04);
}

.d2-list-group__head img {
  width: 24px;
  height: 24px;
  object-fit: contain;
}

.d2-list-group__label {
  min-width: 0;
  font-size: 14px;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.d2-list-group__label em {
  margin-left: 6px;
  color: var(--d2-dim);
  font-size: 12px;
  font-style: normal;
  font-weight: 400;
}

.d2-list-group__head small {
  border: 1px solid var(--d2-line);
  border-radius: 999px;
  color: var(--d2-muted);
  padding: 1px 7px;
  font-size: 12px;
  line-height: 1.5;
}

.d2-list-group.is-open .d2-list-group__head small {
  border-color: rgba(215, 181, 109, 0.34);
  background: rgba(215, 181, 109, 0.1);
  color: var(--d2-accent);
}

.d2-list-group__chevron {
  width: 8px;
  height: 8px;
  border-right: 1.6px solid var(--d2-muted);
  border-bottom: 1.6px solid var(--d2-muted);
  transform: rotate(45deg) translate(-1px, -1px);
  transition: transform 0.18s ease;
}

.d2-list-group.is-open .d2-list-group__chevron {
  transform: rotate(-135deg) translate(-1px, -1px);
}

.d2-list-group__body {
  display: grid;
  gap: 6px;
  border-top: 1px solid var(--d2-line);
  padding: 8px;
}

.d2-list-group__body[hidden] {
  display: none;
}

.d2-list-enable {
  width: 100%;
  min-height: 36px;
  border: 1px solid rgba(215, 181, 109, 0.4);
  border-radius: var(--d2-radius);
  background: rgba(215, 181, 109, 0.1);
  color: var(--d2-accent);
  cursor: pointer;
  font-size: 13px;
}

.d2-list-enable:hover {
  background: rgba(215, 181, 109, 0.18);
}

.d2-list-item {
  display: grid;
  grid-template-columns: 30px minmax(0, 1fr) auto;
  align-items: center;
  gap: 8px;
  width: 100%;
  min-height: 46px;
  border: 1px solid transparent;
  border-radius: var(--d2-radius);
  background: rgba(255, 255, 255, 0.035);
  cursor: pointer;
  padding: 7px 8px;
  text-align: left;
}

.d2-list-item:hover,
.d2-list-item.is-active {
  border-color: rgba(215, 181, 109, 0.42);
  background: rgba(215, 181, 109, 0.1);
}

.d2-list-item img {
  width: 26px;
  height: 26px;
  object-fit: contain;
}

.d2-list-item strong,
.d2-list-item span {
  display: block;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.d2-list-item strong {
  font-size: 14px;
  line-height: 1.3;
}

.d2-list-item span {
  margin-top: 3px;
  color: var(--d2-muted);
  font-size: 13px;
}

.d2-list-item small {
  color: var(--d2-dim);
  font-size: 12px;
}

.d2-empty {
  border: 1px dashed var(--d2-line);
  border-radius: var(--d2-radius);
  color: var(--d2-muted);
  padding: 14px;
  font-size: 14px;
  text-align: center;
}

.d2-stage {
  position: relative;
  min-width: 0;
  min-height: 0;
  overflow: hidden;
  background:
    linear-gradient(rgba(255, 255, 255, 0.022) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255, 255, 255, 0.022) 1px, transparent 1px),
    #0b0d0f;
  background-size: 48px 48px;
}

.d2-viewport {
  position: absolute;
  inset: 0;
  overflow: hidden;
  touch-action: none;
  cursor: grab;
}

.d2-viewport.is-dragging {
  cursor: grabbing;
}

.d2-canvas {
  position: absolute;
  left: 0;
  top: 0;
  transform-origin: 0 0;
  /* 2026-10-11：不要常驻 will-change:transform。它把整张 canvas 提升为合成层，
     浏览器按受限的 raster scale 预栅格化，放大到高倍率时瓦片被整体拉伸发虚
     （实验室 / 海关实测：常驻 → 模糊；去掉 → 清晰）。拖动时再临时开启。 */
}

/* 仅在拖动时提升合成层，兼顾平移流畅与静止清晰。 */
.d2-viewport.is-dragging .d2-canvas {
  will-change: transform;
}

.d2-map-image,
.d2-floor-image,
.d2-grid-fallback {
  position: absolute;
  left: 0;
  top: 0;
  display: block;
  width: 100%;
  height: 100%;
  user-select: none;
}

.d2-map-image {
  object-fit: fill;
  filter: contrast(1.03) brightness(0.92) saturate(0.96);
  transition: opacity 0.16s ease;
}

.d2-grid-fallback {
  border: 1px solid rgba(255, 255, 255, 0.08);
  background:
    linear-gradient(rgba(255, 255, 255, 0.05) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255, 255, 255, 0.05) 1px, transparent 1px),
    #15191d;
  background-size: 80px 80px;
}

.d2-app[data-basemap="satellite"] .d2-map-image {
  opacity: 0.12;
}

/* 单张卫星总图的楼层状态沿用源站 off-level：保留瓦片，按 show 决定是否压暗。 */
.d2-app[data-satellite-floor-dimmed="true"] .d2-tile-layer {
  opacity: 0.2;
}

.d2-app[data-satellite-floor-dimmed="true"] .d2-map-image {
  opacity: 0;
}

/* 2026-10-10 panel23：卫星模式下只显示瓦片，楼层叠加图必须隐藏，否则会盖住卫星底图。 */
.d2-app[data-basemap="satellite"] .d2-floor-image {
  display: none;
}

/* 2026-10-10 panel18：与参考实现一致的「选楼层压暗底图」。
   参考实现实测规则：svg.off-level g.base-layer{opacity:.2}（未选楼层时保持 1）。
   我们此前只压暗了非当前楼层的点位（.d2-marker.is-off-floor → 0.3），底图始终 1.0，
   所以切 2 层/地下时看不出「整张图退到背景」的效果。这里把抽象底图同步压到 0.2。 */
.d2-app[data-basemap="abstract"][data-floor]:not([data-floor="all"]) .d2-map-image,
.d2-app[data-basemap="abstract"][data-floor]:not([data-floor="all"]) .d2-grid-fallback {
  opacity: 0.2;
}

/* 2026-10-10 panel23：与参考实现一致——选中楼层时，总图压到 0.2 当背景，
   再叠一张该层平面图保持不透明，形成「该层高亮」的效果。 */
.d2-floor-image {
  object-fit: fill;
  filter: contrast(1.03) brightness(0.92) saturate(0.96);
  opacity: 1;
  transition: opacity 0.16s ease;
}
.d2-floor-image[hidden] {
  display: none;
}

.d2-tile-layer {
  position: absolute;
  inset: 0;
  pointer-events: none;
  overflow: hidden;
}

.d2-tile,
.d2-satellite-image {
  position: absolute;
  display: block;
  user-select: none;
  pointer-events: none;
}

.d2-tile {
  object-fit: cover;
  filter: contrast(1.04) brightness(0.92) saturate(1.05);
}

/* 非当前楼层的瓦片合成一层半透明底图：切层时仍能看到其它楼层轮廓，且不会层层叠加 */
.d2-tile-group {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.d2-tile-group--ghost {
  opacity: 0.32;
  filter: contrast(1.02) brightness(0.9) saturate(0.6);
}

.d2-satellite-image {
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  object-fit: fill;
  filter: contrast(1.03) brightness(0.9) saturate(1.04);
}

.d2-shape-layer,
.d2-marker-layer {
  position: absolute;
  inset: 0;
  pointer-events: none;
  overflow: visible;
}

.d2-shape-layer svg {
  width: 100%;
  height: 100%;
  display: block;
  overflow: visible;
}

.d2-shape {
  fill: rgba(215, 181, 109, 0.11);
  stroke: rgba(215, 181, 109, 0.58);
  stroke-width: 1.4;
  vector-effect: non-scaling-stroke;
}

/* 2026-10-11 用户指令：地雷/狙击手参考实现 —— 参考实现实测危险区区域是
   fill rgb(255,0,0) / fill-opacity .2 / stroke rgb(255,0,0) 1px，且**默认就画**
   （见 renderShapes；不是只在选中时才出现）。选中态加强到 .4 / 2px。 */
.d2-shape--danger {
  fill: rgba(255, 0, 0, 0.2);
  stroke: rgba(255, 0, 0, 0.9);
  stroke-width: 1;
}

.d2-shape--danger.is-active {
  fill: rgba(255, 0, 0, 0.4);
  stroke-width: 2;
}

.d2-marker {
  position: absolute;
  --d2-glow: 215, 181, 109;
  z-index: 1;
  width: 28px;
  height: 28px;
  margin: -14px 0 0 -14px;
  border: 0;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.54);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.56);
  cursor: pointer;
  padding: 2px;
  pointer-events: auto;
  transform: translateZ(0) scale(var(--d2-marker-scale, 1));
  transform-origin: center;
  will-change: transform;
}

.d2-marker--extraction,
.d2-marker--transit {
  --d2-glow: 121, 215, 142;
}

/* ======================================================================
   2026-10-11 用户指令：撤离点标记对齐上游数据参考实现实测规格（.extract-name.{pmc,scav,shared,transit}）：
     · 图标 24×24、无底圈；名称 18px / 800 / 与图标同色 / text-shadow 0 0 3px #000 / 无底无边框
     · 颜色：pmc #00a700 · scav #ca8a00 · shared #0292c0 · transit #cd1e2f
   我方原状：11px / 400 / 白字 + 深色胶囊底；且 z-index 与物资同为 1，会被物资图标压住。
   同时把撤离 / 转移点抬到物资之上（用户：图标和名称不能被次要物资图标遮盖）。
   ====================================================================== */
.d2-marker--ink-pmc { --d2-extract-ink: #00a700; }
.d2-marker--ink-scav { --d2-extract-ink: #ca8a00; }
.d2-marker--ink-shared { --d2-extract-ink: #0292c0; }
.d2-marker--ink-transit { --d2-extract-ink: #e44656; }

/* 高于物资 / 容器 / 出生点（z-index 1），低于 hover(20) / 选中(30)；is-off-floor(0) 仍更低 */
.d2-marker--extraction,
.d2-marker--transit {
  z-index: 6;
  background: none;
  box-shadow: none;
  /* 保留 2px 内边距：.d2-marker img 是 100%，去掉内边距会把 24px 图标撑到 28px
     （参考实现图标是 24×24） */
  padding: 2px;
}

.d2-marker--extraction .d2-marker-label,
.d2-marker--transit .d2-marker-label {
  border: 0;
  background: none;
  color: var(--d2-extract-ink, #00a700);
  padding: 0;
  font-size: 18px;
  font-weight: 800;
  letter-spacing: normal;
  text-shadow: 0 0 3px #000, 0 1px 2px #000;
  /* 2026-10-13 用户指令：撤离点必须显示全名（海关「地下室锅炉房（合作撤离）」
     被 170px + ellipsis 截断）。撤离点/转移点标签放开宽度，与参考实现一致。 */
  max-width: none;
}

.d2-marker--extraction:hover .d2-marker-label,
.d2-marker--transit:hover .d2-marker-label,
.d2-marker--extraction.is-active .d2-marker-label,
.d2-marker--transit.is-active .d2-marker-label {
  border: 0;
  background: none;
  box-shadow: none;
  color: var(--d2-extract-ink, #00a700);
  font-weight: 800;
}

.d2-marker--boss {
  --d2-glow: 243, 111, 99;
}

.d2-marker--quest,
.d2-marker--questItem {
  --d2-glow: 215, 181, 109;
}

.d2-marker--loot,
.d2-marker--container {
  --d2-glow: 92, 210, 216;
}

.d2-marker:hover {
  z-index: 20;
  box-shadow: 0 0 0 2px rgba(var(--d2-glow), 0.72), 0 6px 14px rgba(0, 0, 0, 0.6);
}

/* 选中：图标放大 + 发光 + 脉冲光环（参考 /map2/preview/ 的选中放大，并叠加醒目发光）
   注意：放大的是图标本身而不是整个按钮 —— 否则同按钮内的名称标签会被一起放大并位移。 */
.d2-marker.is-active {
  z-index: 30;
  background: rgba(8, 10, 12, 0.72);
  box-shadow:
    0 0 0 2px rgba(255, 240, 202, 0.96),
    0 0 14px 5px rgba(var(--d2-glow), 0.7),
    0 0 34px 12px rgba(var(--d2-glow), 0.36),
    0 8px 20px rgba(0, 0, 0, 0.62);
}

.d2-marker.is-active img {
  transform: scale(1.75);
  filter:
    drop-shadow(0 0 5px rgba(var(--d2-glow), 0.95))
    drop-shadow(0 0 13px rgba(var(--d2-glow), 0.6));
  animation: d2-marker-pop 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.d2-marker.is-active::after {
  content: "";
  position: absolute;
  inset: -7px;
  border-radius: 50%;
  border: 2px solid rgba(var(--d2-glow), 0.92);
  animation: d2-marker-halo 1.5s ease-out infinite;
  pointer-events: none;
}

@keyframes d2-marker-pop {
  0% { transform: scale(1); }
  55% { transform: scale(2.1); }
  100% { transform: scale(1.75); }
}

@keyframes d2-marker-halo {
  0% { transform: scale(0.72); opacity: 0.92; }
  100% { transform: scale(1.55); opacity: 0; }
}

/* 有站内图文的点位：右上角一个小圆点，提示「点开有截图/攻略」 */
/* 2026-09-29 移除 linked 右上角 7px 指示圆点：撤离点已有名字标签，圆点属视觉残留（用户反馈） */

@media (prefers-reduced-motion: reduce) {
  .d2-marker.is-active img,
  .d2-marker.is-active::after,
  .d2-skel,
  .d2-loading__map,
  .d2-loading__bar::before {
    animation: none;
  }
  .d2-list-group__chevron {
    transition: none;
  }
}

.d2-marker img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}

.d2-marker-label {
  position: absolute;
  left: 30px;
  top: 50%;
  display: block;
  max-width: 170px;
  transform: translateY(-50%);
  border: 1px solid rgba(229, 224, 212, 0.18);
  border-radius: 6px;
  /* R2-D2：蒙层 .82 太透 —— 浅色主题下压在浅色地图上会被"洗淡"成中灰，
     实测「1011号地堡」等彩色标签（撤离点名称与图标同色）只有 2.84:1。
     提高到 .95 后仍是同一块深色药丸（深色主题下观感不变），彩色标签回到 ~5.7:1。 */
  background: rgba(8, 10, 12, 0.95);
  /* R2-D6：药丸是覆盖在地图上的**固定深色**蒙层，文字必须是**固定浅色**。
     旧值 var(--d2-text) 在浅色主题（清爽白/工程图纸）下会变成深色 → 实测 1.08:1，
     任务/开关/任务物品的名称标签完全不可读（全站 822 处）。
     取 #f3efe4（= 默认深色主题的 --d2-text）⇒ **深色主题零视觉变化**。
     撤离/转移点的 ink 颜色与地标的固定色规则特异性更高，仍照常生效。 */
  color: #f3efe4;
  padding: 3px 6px;
  font-size: 12px;
  line-height: 1.25;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  /* 允许点击文字直接选中该点位（此前是 none，导致点文字没反应） */
  pointer-events: auto;
  cursor: pointer;
}

.d2-marker:hover .d2-marker-label {
  border-color: rgba(var(--d2-glow), 0.6);
  background: rgba(14, 18, 21, 0.94);
}

.d2-marker.is-active .d2-marker-label {
  border-color: rgba(var(--d2-glow), 0.85);
  box-shadow: 0 0 10px rgba(var(--d2-glow), 0.45);
  font-weight: 700;
}

.d2-app[data-labels="1"] .d2-marker-label {
  display: block;
}

.d2-marker-label:empty,
.d2-app[data-labels="0"] .d2-marker-label {
  /* !important：空标签必须压过 .d2-app[data-labels="1"] 的 display:block（层叠权重更高，
     2026-09-29 用户再次反馈物资右侧残留小圆点——即空胶囊被 data-labels 规则重新显示） */
  display: none !important;
}

.d2-marker--micro {
  width: 21px;
  height: 21px;
  margin: -10.5px 0 0 -10.5px;
  padding: 1px;
  opacity: 0.92;
}

/* 非当前楼层：半透明保留（能看到位置），但不显示名称、压在当前楼层标记之下 */
.d2-marker.is-off-floor {
  z-index: 0;
  opacity: 0.3;
  filter: saturate(0.5);
}

.d2-marker.is-off-floor .d2-marker-label {
  display: none;
}

/* 2026-10-13 用户指令：撤离点/转移点不允许隐藏 ——
   ①「隐藏地图名称」开关（T 键 / data-labels="0"）不影响撤离点标签；
   ② 楼层切换已不再对撤离点加 is-off-floor（见 ditu2.js renderMarkers），
     这里兜底：即便带上 is-off-floor，撤离点标签也保持显示。 */
.d2-app[data-labels="0"] .d2-marker--extraction .d2-marker-label,
.d2-app[data-labels="0"] .d2-marker--transit .d2-marker-label,
.d2-marker.is-off-floor .d2-marker--extraction .d2-marker-label,
.d2-marker.is-off-floor .d2-marker--transit .d2-marker-label {
  display: block !important;
}

.d2-marker.is-off-floor:hover,
.d2-marker.is-off-floor.is-active {
  opacity: 0.88;
  filter: none;
}

.d2-marker--loot,
.d2-marker--container {
  opacity: 1;
}

/* ======================================================================
   2026-10-11 用户指令：地雷 / 狙击手参考实现效果。
   参考实现实测：危险区标记是**裸警告三角** —— 24×24、无深色底圈、无阴影
   （`.leaflet-marker-icon` 的 bg=transparent / radius=0 / box-shadow=none）。
   我方此前用和物资一样的深色圆底徽章，用户明确「本身和物资就不是一个东西，
   却做了一样的特效」→ 这里把底圈/阴影/内边距全部去掉，只留图标本身。
   （区域轮廓由 renderShapes 默认绘制，见 .d2-shape--danger。）
   ====================================================================== */
.d2-marker--hazard {
  width: 24px;
  height: 24px;
  margin: -12px 0 0 -12px;
  padding: 0;
  background: none;
  box-shadow: none;
  --d2-glow: 255, 206, 0;
}

/* 2026-10-11 用户指令：「LEDX皮肤透照仪这些物资的图标要和源站一样大，LEDX 到了我这里
   几乎看不清」。参考实现实测：物资图标 **24×24**、满不透明，并且对**散落物资的物品图**加
   一圈**白色描边**（4 向 drop-shadow）把深色物品从深色底图上「抠」出来 —— LEDX 的图标
   本身就是深色设备 + 深色底，没有这圈描边就几乎看不见。
   我方原状：21px 徽章 / 图标 19px / opacity .82 / 无描边。
   图标 24px 需要 28px 徽章（.d2-marker 默认 28px + padding 2px），所以物资标记不再走
   `micro`（见 appendRuntimePoints 里已去掉 micro）。容器图标本身是设计过的图标（对比度
   够），按参考实现口径**不加**描边，只有散落物资的物品图加。 */
.d2-marker--loot img {
  filter: drop-shadow(1px 0 0 #fff) drop-shadow(-1px 0 0 #fff)
          drop-shadow(0 1px 0 #fff) drop-shadow(0 -1px 0 #fff);
}

/* Loading markers stay visible as small dots, without opaque empty icon discs. */
.d2-marker.is-icon-pending {
  background: transparent;
  box-shadow: none;
}

.d2-marker.is-icon-pending::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--d2-muted);
  transform: translate(-50%, -50%);
  pointer-events: none;
}

.d2-marker--spawn {
  opacity: 0.72;
}

/* ======================================================================
   2026-10-10 panel6：地标（区域名标注）
   地标是**纯文字**，不画图标圈 —— TYPE_CONFIG.landmark.icon 为空串，
   若沿用 .d2-marker 的 28px 圆底 + box-shadow，屏幕上就是一堆无意义的小黑点。
   这里把按钮本体收缩成 0×0 的定位锚点（仍可点、可聚焦、可选中），
   视觉全部交给 .d2-marker-label。

   字号口径对齐 map2 renderPlaceLabels()：基准 20px * s(--lm-scale)，
   窄屏（≤960px，与抽屉断点同一刻度）降到 15px。
   旋转走 --lm-rotate（数据里 0 或 6 度，只有非 0 才内联）。

   z-index 压到 0：地标是背景注记，必须永远压在撤离/任务等可交互标记之下，
   标签重叠时由 applyLabelAvoidance() 隐藏地标名（而非动撤离点标签）。
   ====================================================================== */
.d2-marker--landmark {
  --d2-glow: 215, 181, 109;
  z-index: 0;
  width: 0;
  height: 0;
  margin: 0;
  background: none;
  box-shadow: none;
  padding: 0;
  overflow: visible;
  /* 2026-10-11 用户指令：地图内的地标（地点名称）**不可点选** —— 它只是一层背景地名。
     pointer-events:none 让它彻底不是点击目标：既不选中，也不吃 hover；
     同时指针「穿透」到画布 —— onPointerDown 里 `.d2-marker` 会拦截拖拽/捏合，
     若地标不穿透，用户在任意一处地名上按下都无法平移地图（参考实现的区域名同样穿透）。
     只作用于 .d2-marker--landmark；BTR 停车点 / 撤离点等真点位不受影响。 */
  pointer-events: none;
  cursor: default;
}

.d2-marker--landmark .d2-marker-label {
  /* 锚点 0×0，标签以锚点为中心 —— 与 map2 .dmv-place 的 translate(-50%,-50%) 同义 */
  left: 0;
  top: 0;
  transform: translate(-50%, -50%) rotate(var(--lm-rotate, 0deg));
  transform-origin: center;
  /* 地标名不吃通用的 170px 截断上限：区域名被腰斩成「宿舍…」比不显示更糟 */
  max-width: none;
  /* 2026-10-11 用户指令：地标对齐参考实现 .map-area-label（实测：20px×size% / 800 / #c7c5b3 /
     单层 text-shadow 0 0 3px #000 / 无内边距 / 无字距）。字号沿用 size% 口径（20px * --lm-scale），
     与参考实现一致；只把字重、字距、内边距、投影对齐。 */
  padding: 0;
  font-size: calc(20px * var(--lm-scale, 1));
  font-weight: 800;
  line-height: 1.2;
  letter-spacing: normal;
  color: #c7c5b3;
  background: none;
  border: 0;
  /* 2026-10-19 主题解耦：地标名不再随 UI 主题改色（固定 #c7c5b3），代价是清爽白
     这类浅色画布下「浅字压浅底」会糊。这里加一层**暗色轮廓光晕**托底：
     深色地图上观感与原来的 0 0 3px #000 基本一致，浅色画布上仍有清晰边界。
     （实测 16 张抽象底图全为深色，但 SVG 有透明区，标签可能落在透明处的画布上。） */
  text-shadow: 0 1px 2px rgba(0, 0, 0, .92), 0 0 3px rgba(0, 0, 0, .92), 0 0 6px rgba(0, 0, 0, .5);
  /* ⚠️ 必须在这里也压一次：通用规则 .d2-marker-label（见上）为了让「点文字也能选中点位」
     显式写了 pointer-events:auto —— 父级 .d2-marker--landmark 的 none 会被它覆盖，
     实测 elementFromPoint 仍命中文字、拖动地图时被拦。地标是纯背景地名，这里压回 none。 */
  pointer-events: none;
  cursor: default;
}

/* 地标已不可点选（pointer-events:none），hover 高亮不再有意义 —— 去掉 :hover 分支，
   只留 is-active（防御性：若某条路径仍把地标设为选中，样式不变形）。 */
.d2-marker--landmark.is-active .d2-marker-label {
  background: none;
  border: 0;
  box-shadow: none;
  color: #efe9d4;
}

.d2-marker--landmark.is-active .d2-marker-label {
  font-weight: 800;
  text-shadow: 0 0 4px #000, 0 0 7px rgba(215, 181, 109, 0.95), 0 1px 2px #000;
}

/* 避让隐藏：与 data-labels="0" 的语义正交 —— 后者是用户主动关标签（T 键），
   前者是密度过高时自动让位。两者都要压过 [data-labels="1"] 的 display:block。 */
.d2-app[data-labels="1"] .d2-marker.is-overlap .d2-marker-label {
  display: none !important;
}

/* 窄屏降基线：15px（与 map2 isNarrowViewport() 分支同一数值）
   2026-10-20 移动端修复：仅降字号不够 —— 实测 iPhone 14 上地图可见宽度只有 390px，
   而 fitMap 修复后地图被放大到 842px 宽（可左右拖动），地标仍按 15px 渲染，
   屏幕上同时压着 22 个地标，互相重叠 29 对（「老加油站」与「ZB 1013 情报楼」叠印）。
   再降两档并加实体底片：窄屏下地标读得清比字大更重要。 */
@media (max-width: 960px) {
  .d2-marker--landmark .d2-marker-label {
    /* 2026-10-20 第二轮：撤掉深色底片。地标是「底图级注记」——
       docs/40（2026-09-22）口径是「无底、纯文字 + 描边、恒定屏幕尺寸」，
       加底片会让地名变成 UI 胶囊，且本质是用视觉补丁掩盖地图被裁的问题。
       字号回到 14px：配合 fitMap 新的 1.9 倍封顶（scale≈0.72），
       实际观感与第一版 13px@0.82 持平，不再额外缩小。 */
    font-size: calc(14px * var(--lm-scale, 1));
  }
}

/* 极窄屏（≤400px，覆盖 iPhone SE/13 mini 等）：再降一档，并让撤离点标签同步缩小。
   实测 375px 宽下撤离点 18px 标签占满半屏，「地下室锅炉房（合作撤离）」这类长名
   会横穿整个地图并压住若干地标。 */
@media (max-width: 400px) {
  .d2-marker--landmark .d2-marker-label {
    font-size: calc(13px * var(--lm-scale, 1));
  }
  .d2-marker--extraction .d2-marker-label,
  .d2-marker--transit .d2-marker-label {
    font-size: 14px;
  }
}

/* ======================================================================
   panel6：无图标的按钮（地标）
   .d2-preset 是 20px 图标列 + 文字列，.d2-filter 是 24px 图标列 + 文字 + 计数。
   没有图标时若保留首列，文字会整体右移并在左侧留一段空白 —— 这里把首列收掉，
   让纯文字按钮占满整行（密度优先，行高 ≥24px 由 min-height 保证）。
   ====================================================================== */
.d2-preset.is-noicon {
  grid-template-columns: minmax(0, 1fr);
}

.d2-filter.is-noicon {
  grid-template-columns: minmax(0, 1fr) auto;
}

.d2-preset[hidden],
.d2-filter[hidden] {
  display: none !important;
}

.d2-toolbar {
  position: absolute;
  z-index: 12;
  top: 14px;
  left: 14px;
  display: flex;
  gap: 6px;
  border: 1px solid var(--d2-line);
  border-radius: var(--d2-radius);
  background: rgba(12, 14, 16, 0.82);
  padding: 6px;
  backdrop-filter: blur(14px);
}

.d2-map-controls {
  position: absolute;
  z-index: 12;
  top: 14px;
  right: 14px;
  display: grid;
  justify-items: end;
  gap: 7px;
  max-width: min(520px, calc(100% - 28px));
}

.d2-basemap-toggle {
  display: flex;
  gap: 5px;
  border: 1px solid var(--d2-line);
  border-radius: var(--d2-radius);
  background: rgba(12, 14, 16, 0.82);
  padding: 6px;
  backdrop-filter: blur(14px);
}

.d2-basemap-toggle button {
  min-width: 68px;
  height: 34px;
  border: 1px solid transparent;
  border-radius: 6px;
  background: rgba(255, 255, 255, 0.06);
  color: var(--d2-muted);
  cursor: pointer;
  font-size: 13px;
}

.d2-basemap-toggle button[aria-pressed="true"] {
  border-color: rgba(92, 210, 216, 0.48);
  background: rgba(92, 210, 216, 0.12);
  color: var(--d2-text);
}

.d2-tool {
  display: grid;
  place-items: center;
  width: auto; /* v8.6 修复：固定 34px 使「✎标注」文字标签溢出错位——改为内容自适应 + 最小宽 */
  min-width: 34px;
  padding: 0 8px;
  height: 34px;
  border: 1px solid transparent;
  border-radius: 6px;
  background: rgba(255, 255, 255, 0.06);
  color: var(--d2-text);
  cursor: pointer;
}
.d2-tool__lab { line-height: 1; margin-left: 5px; font-size: 13px; letter-spacing: 1px; }

.d2-tool:hover {
  border-color: rgba(215, 181, 109, 0.48);
}

.d2-resetbar {
  position: absolute;
  /* 2026-10-20：与工具栏/楼层条同层（34），否则 z-index:30 的选中标签会盖住按钮 */
  z-index: 34;
  right: 14px;
  bottom: 14px;
}
/* 2026-10-20 修复「桌面端点不到全部隐藏」：
   .d2-stage 是 inset:0 的满屏覆盖层，右侧面板（.d2-detail，z-index:20）压在它上面。
   旧规则 right:14px 于是落到面板内部，实测 1440 下按钮 rect 1317,846，elementFromPoint
   命中面板里的 d2-right-placeholder，点击无任何反应（点位仍 32 个）。
   桌面端把基准让开面板宽度；面板收起（.d2-detail-off）时回到贴边。 */
@media (min-width: 961px) {
  .d2-resetbar { right: calc(var(--d2-right) + 14px); bottom: 62px; }
  .d2-app.d2-detail-off .d2-resetbar { right: 14px; }
}

.d2-tilebar {
  display: none;
  align-items: center;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 6px;
  max-width: 100%;
  border: 1px solid var(--d2-line);
  border-radius: var(--d2-radius);
  background: rgba(12, 14, 16, 0.84);
  padding: 6px;
  backdrop-filter: blur(14px);
  /* 2026-09-30 审计修复：tilebar 容器换行后占宽很大，透明区域会拦截地图触摸——
     容器穿透、仅按钮本身可点（横幅让位期间容器下移后此问题会罩住地图上部） */
  pointer-events: none;
}
.d2-tilebar button, .d2-tilebar .is-on { pointer-events: auto; }

.d2-tilebar.is-visible {
  display: flex;
}

.d2-tilebar > span {
  color: var(--d2-muted);
  font-size: 13px;
  padding: 0 2px 0 4px;
}

.d2-tilebar button {
  min-width: 44px;
  height: 32px;
  border: 1px solid transparent;
  border-radius: 6px;
  background: rgba(255, 255, 255, 0.06);
  color: var(--d2-muted);
  cursor: pointer;
  font-size: 13px;
}

.d2-tilebar button[aria-pressed="true"] {
  border-color: rgba(215, 181, 109, 0.5);
  background: rgba(215, 181, 109, 0.14);
  color: var(--d2-text);
}

.d2-reset {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 40px;
  padding: 0 16px;
  border: 1px solid var(--d2-line);
  border-radius: var(--d2-radius);
  background: rgba(12, 14, 16, 0.84);
  color: var(--d2-text);
  cursor: pointer;
  font-size: 14px;
  letter-spacing: 0.02em;
  backdrop-filter: blur(14px);
}

.d2-tile-retry {
  display: flex;
  margin-bottom: 8px;
}

.d2-tile-retry[hidden] { display: none; }

.d2-reset:hover,
.d2-reset:focus-visible {
  border-color: rgba(215, 181, 109, 0.55);
  background: rgba(215, 181, 109, 0.14);
}

.d2-reset__icon {
  font-size: 15px;
  line-height: 1;
}

.d2-mobile-tabs {
  display: none;
}

.d2-detail {
  position: relative;
  z-index: 10;
  display: flex;
  width: var(--d2-right);
  min-height: 0;
  min-width: 0;
  flex-direction: column;
  border-left: 1px solid var(--d2-line);
  background: var(--d2-panel);
  backdrop-filter: blur(18px);
}

.d2-detail__head {
  flex: 0 0 auto;
  padding: 16px;
  border-bottom: 1px solid var(--d2-line);
}

.d2-detail__title {
  display: grid;
  grid-template-columns: 34px minmax(0, 1fr) auto;
  align-items: center;
  gap: 10px;
}

.d2-detail__title img {
  width: 32px;
  height: 32px;
  object-fit: contain;
}

.d2-detail__title strong,
.d2-detail__title span {
  display: block;
  min-width: 0;
  overflow-wrap: anywhere;
}

.d2-detail__title strong {
  font-size: 18px;
  line-height: 1.35;
}

.d2-detail__title span {
  margin-top: 4px;
  color: var(--d2-muted);
  font-size: 13px;
}

.d2-close {
  display: none;
  width: 32px;
  height: 32px;
  border: 1px solid var(--d2-line);
  border-radius: 6px;
  background: rgba(255, 255, 255, 0.05);
  cursor: pointer;
}

.d2-detail__body {
  min-height: 0;
  flex: 1 1 auto;
  overflow: auto;
  padding: 14px 16px 18px;
  scrollbar-gutter: stable;
  scrollbar-width: thin;
}

.d2-detail-card {
  border: 1px solid var(--d2-line);
  border-radius: var(--d2-radius);
  background: rgba(255, 255, 255, 0.04);
  padding: 12px;
  margin-bottom: 10px;
}

.d2-detail-card h3 {
  margin: 0 0 8px;
  font-size: 14px;
  color: var(--d2-muted);
}

.d2-detail-card p {
  margin: 0;
  line-height: 1.65;
  color: var(--d2-text);
  font-size: 14px;
}

.d2-decision-card {
  border-color: rgba(121, 215, 142, 0.24);
  background: rgba(121, 215, 142, 0.07);
}

.d2-decision-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 8px;
}

.d2-decision-grid span {
  max-width: 100%;
  border: 1px solid rgba(121, 215, 142, 0.22);
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.18);
  color: var(--d2-text);
  padding: 4px 8px;
  font-size: 13px;
  overflow-wrap: anywhere;
}

.d2-tagline {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.d2-tag {
  max-width: 100%;
  border: 1px solid var(--d2-line);
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.04);
  color: var(--d2-muted);
  padding: 4px 8px;
  font-size: 13px;
  overflow-wrap: anywhere;
}

.d2-tag--trader {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 9px 3px 4px;
}

.d2-tag--trader img {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  object-fit: cover;
  border: 1px solid var(--d2-line-strong);
  flex: 0 0 auto;
}

.d2-tag--trader > span {
  display: inline-flex;
  align-items: baseline;
  gap: 4px;
}

.d2-tag--trader small {
  color: var(--d2-dim);
  font-size: 11px;
}

.d2-item-grid {
  display: grid;
  gap: 7px;
}

.d2-item {
  display: grid;
  grid-template-columns: 34px minmax(0, 1fr);
  align-items: center;
  gap: 8px;
  min-height: 40px;
  border: 1px solid var(--d2-line);
  border-radius: 7px;
  background: rgba(0, 0, 0, 0.14);
  padding: 6px;
  color: inherit;
  text-decoration: none;
}

.d2-item img {
  width: 30px;
  height: 30px;
  object-fit: contain;
}

.d2-item span,
.d2-item strong,
.d2-item small {
  display: block;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.d2-item strong {
  font-size: 13px;
  line-height: 1.25;
}

.d2-item small {
  margin-top: 3px;
  color: var(--d2-muted);
  font-size: 12px;
}

.d2-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.d2-action {
  border: 1px solid rgba(215, 181, 109, 0.38);
  border-radius: 7px;
  background: rgba(215, 181, 109, 0.1);
  color: var(--d2-text);
  padding: 8px 10px;
  text-decoration: none;
  font-size: 13px;
}

.d2-action--primary {
  display: block;
  margin-top: 10px;
  border-color: rgba(215, 181, 109, 0.66);
  background: linear-gradient(180deg, rgba(215, 181, 109, 0.26), rgba(215, 181, 109, 0.14));
  text-align: center;
  font-weight: 700;
}

.d2-action--primary:hover {
  background: rgba(215, 181, 109, 0.34);
}

/* 撤离点位置截图卡 */
.d2-photo-card h3 {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.d2-photo-card h3 small {
  color: var(--d2-dim);
  font-size: 12px;
  font-weight: 400;
}

.d2-photo__main {
  position: relative;
  display: block;
  overflow: hidden;
  border: 1px solid var(--d2-line);
  border-radius: 7px;
  background: #05070a;
  line-height: 0;
  cursor: zoom-in;
}

.d2-photo__main img {
  width: 100%;
  max-height: 230px;
  object-fit: cover;
  display: block;
}

.d2-photo__zoom {
  position: absolute;
  right: 6px;
  bottom: 6px;
  border-radius: 999px;
  background: rgba(8, 10, 12, 0.8);
  /* R2-D2：角标压在**照片**上（亮度不可知），底色是固定深色蒙层 ——
     文字必须用固定浅色，不能跟主题（浅色主题下实测 1.11 / 1.28:1）。 */
  color: #f3efe4;
  padding: 3px 8px;
  font-size: 12px;
  line-height: 1.4;
  transition: background 0.15s ease, color 0.15s ease;
}

.d2-photo__main:hover .d2-photo__zoom,
.d2-photo__main:focus-visible .d2-photo__zoom {
  background: rgba(215, 181, 109, 0.94);
  color: #1b1b1b;
}

.d2-photo__main:focus-visible {
  outline: 2px solid rgba(215, 181, 109, 0.7);
  outline-offset: 1px;
}

.d2-photo__thumbs {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 6px;
  margin-top: 6px;
}

.d2-photo__thumbs button {
  overflow: hidden;
  border: 1px solid var(--d2-line);
  border-radius: 6px;
  background: #05070a;
  cursor: pointer;
  padding: 0;
  line-height: 0;
}

.d2-photo__thumbs button[aria-pressed="true"] {
  border-color: rgba(215, 181, 109, 0.78);
  box-shadow: 0 0 0 1px rgba(215, 181, 109, 0.4);
}

.d2-photo__thumbs img {
  width: 100%;
  height: 52px;
  object-fit: cover;
  display: block;
}

.d2-photo-empty {
  border: 1px dashed var(--d2-line);
  border-radius: 7px;
  color: var(--d2-muted);
  padding: 12px;
  font-size: 13px;
  text-align: center;
}

.d2-kv {
  display: grid;
  gap: 1px;
  margin: 10px 0 0;
  border: 1px solid var(--d2-line);
  border-radius: 7px;
  overflow: hidden;
  background: var(--d2-line);
}

.d2-kv > div {
  display: grid;
  grid-template-columns: 74px minmax(0, 1fr);
  gap: 8px;
  /* R2-D7：旧值固定 rgba(0,0,0,.24) 把浅色主题的卡片压成中灰 → --d2-muted 只有 2.62:1（×32）。
     改用各主题自带的 --d2-card-bg（同向淡色：深色主题淡压深、浅色主题淡压淡），
     观感在深色主题下不变，浅色主题下恢复可读。 */
  background: var(--d2-card-bg);
  padding: 7px 9px;
}

.d2-kv dt {
  /* R2-D9：旧值 --d2-muted 在部分主题只有 4.15~4.32:1（略低于 4.5）。
     这组是表单标签（阵营 / 需要开关），用 --d2-text 全对比度更合适，
     层级感仍由字号与网格区分保留。 */
  color: var(--d2-text);
  font-size: 13px;
}

.d2-kv dd {
  margin: 0;
  color: var(--d2-text);
  font-size: 13px;
  line-height: 1.5;
  overflow-wrap: anywhere;
}

/* 任务简介卡 */
.d2-task-card {
  border-color: rgba(215, 181, 109, 0.3);
  background: rgba(215, 181, 109, 0.07);
}

.d2-task-card p {
  margin-bottom: 10px;
}

/* Boss 刷新点卡：中英文名 + 立绘 + 刷新率/血量 + 站内 Boss 页跳转 */
.d2-boss-card {
  border-color: rgba(219, 112, 112, 0.32);
  background: rgba(219, 112, 112, 0.07);
}

.d2-boss-list {
  display: grid;
  gap: 8px;
}

.d2-boss {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 10px;
  align-items: start;
  border: 1px solid var(--d2-line);
  border-radius: 8px;
  background: rgba(0, 0, 0, 0.22);
  padding: 8px;
}

.d2-boss__portrait {
  width: 64px;
  height: 64px;
  border: 1px solid var(--d2-line);
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.05);
  object-fit: cover;
}

.d2-boss__body {
  min-width: 0;
}

.d2-boss__names {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px;
  margin: 0 0 6px;
}

.d2-boss__names strong {
  color: var(--d2-text);
  font-size: 14px;
  letter-spacing: 0.02em;
}

.d2-boss__names span {
  color: var(--d2-muted);
  font-size: 13px;
}

.d2-boss__facts {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
  margin-bottom: 6px;
}

.d2-boss__facts span {
  border: 1px solid rgba(219, 112, 112, 0.28);
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.2);
  color: var(--d2-text);
  padding: 3px 7px;
  font-size: 12px;
  overflow-wrap: anywhere;
}

.d2-boss__escorts {
  margin: 0 0 6px;
  color: var(--d2-muted);
  font-size: 12px;
  line-height: 1.5;
}

.d2-boss__link {
  display: inline-block;
  padding: 6px 9px;
}

.d2-right-placeholder {
  display: grid;
  place-items: center;
  min-height: 100%;
  color: var(--d2-muted);
  text-align: center;
}

.d2-right-placeholder div {
  max-width: 260px;
}

.d2-right-placeholder strong {
  display: block;
  margin-bottom: 8px;
  color: var(--d2-text);
}

.d2-toast {
  position: fixed;
  left: 50%;
  bottom: 18px;
  z-index: 60;
  max-width: min(520px, calc(100vw - 32px));
  transform: translateX(-50%);
  border: 1px solid var(--d2-line);
  border-radius: var(--d2-radius);
  /* R2-D2：原为固定深底 + 主题文字 —— 浅色主题下实测 1.07:1（提示完全看不见）。 */
  background: var(--d2-overlay);
  color: var(--d2-text);
  box-shadow: var(--d2-shadow);
  padding: 10px 14px;
  font-size: 14px;
}

.d2-toast[hidden] {
  display: none;
}

@media (max-width: 1180px) {
  :root {
    --d2-left: 304px;
    --d2-right: 330px;
  }
}

@media (max-width: 960px) {
  body.takefu-ditu2 {
    overflow: hidden;
  }

  .d2-app {
    display: block;
  }

  .d2-stage {
    position: absolute;
    inset: 0 0 58px;
  }

  .d2-side,
  .d2-detail {
    position: absolute;
    left: 0;
    right: 0;
    z-index: 30;
    border: 1px solid var(--d2-line);
    border-radius: 8px 8px 0 0;
    /* 面板高度按定位容器（.d2-app，已被全站壳头部压缩到 ~598px）扣掉底部页签条计算；
       若按视口取 min(74vh,620px)，620+58 超出容器高，abs 定位解出负 top，标题栏被顶出屏幕 */
    height: calc(100% - 58px);
    max-height: min(74vh, 620px);
    transform: translateY(calc(100% + 72px));
    transition: transform 0.2s ease;
    visibility: hidden;
    pointer-events: none;
  }

  .d2-side {
    bottom: 58px;
  }

  .d2-detail {
    bottom: 58px;
  }

  .d2-app[data-mobile-panel="layers"] .d2-side,
  .d2-app[data-mobile-panel="detail"] .d2-detail {
    transform: translateY(0);
    visibility: visible;
    pointer-events: auto;
  }

  .d2-detail__body,
  .d2-side__body {
    max-height: calc(74vh - 110px);
  }

  .d2-close {
    display: grid;
    place-items: center;
  }

  /* 2026-09-29 审计修复：移动端详情头部离容器顶太近（关闭钮落在 64px 站顶栏之下点不到）
     ——给头部加足顶距，让关闭钮离开站点顶栏的可点区域 */
  .d2-detail__head {
    padding-top: 30px;
  }

  .d2-mobile-tabs {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 32;
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 1px;
    height: 58px;
    border-top: 1px solid var(--d2-line);
    /* R2-D2：原为硬编码 #0d1012（不透明深底）+ 主题文字变量 ——
       浅色主题（清爽白 / 工程图纸）下实测 1.07 / 1.23:1，底部导航完全不可读。
       改用 --d2-overlay：与 .d2-toolbar / .d2-tilebar 等地图内 chrome 同一套口径。 */
    background: var(--d2-overlay);
  }

  .d2-mobile-tabs button {
    border: 0;
    background: transparent;
    color: var(--d2-muted);
    cursor: pointer;
    font-size: 13px;
  }

  .d2-mobile-tabs button[aria-pressed="true"] {
    color: var(--d2-text);
    background: rgba(215, 181, 109, 0.12);
  }

  .d2-toolbar {
    top: 10px;
    left: 10px;
  }

  /* 2026-09-29 审计修复：对局时钟与工具栏同高同行，窄屏重叠盖住「适屏/标签/全屏/分享」
     ——移动端时钟降一行，让开横向工具栏（时钟本身可点按 pointer-events:auto） */
  .d2-raid-chip {
    top: 58px;
    max-width: calc(100vw - 20px);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .d2-map-controls {
    top: 10px;
    right: 10px;
  }

  .d2-resetbar {
    right: 10px;
    bottom: 68px;
  }

  .d2-tilebar {
    max-width: calc(100vw - 20px);
  }
}



@media (max-width: 540px) {
  .d2-title {
    font-size: 22px;
  }

  .d2-filter-grid {
    grid-template-columns: 1fr;
  }

  .d2-stats {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .d2-toolbar {
    max-width: calc(100vw - 20px);
    overflow-x: auto;
  }

  .d2-map-controls {
    /* 2026-10-12：原 top:54 已被 @960 段的 124 接管（且从未真正避开工具栏），删除 top */
    max-width: calc(100vw - 20px);
  }

  .d2-tool {
    flex: 0 0 34px;
  }

  .d2-quick-presets {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* 全站导航的配色、抽屉和交互样式统一由 takefu-shell.css 管理。 */

/* 2026-09-28: 服务端渲染的互链/摘要块（#ditu2-app 之下，爬虫与无 JS 用户可见） */
.d2-seo { display: none; } /* 2026-09-29：全屏 app 布局下静态 SEO 块露出页面底部；display:none 对渲染爬虫等效不可见，链接价值已由页内三版互链承担（侧栏底部 d2-variants） */
.d2-seo p { margin: 0 0 6px; }
.d2-seo p:last-child { margin-bottom: 0; }
.d2-seo a { color: var(--d2-accent); text-decoration: none; }
.d2-seo a:hover { text-decoration: underline; }

/* 彩蛋实地照片（详情面板内嵌） */
.d2-egg-photo { display: block; width: 100%; max-height: 260px; object-fit: cover; border-radius: 8px; border: 1px solid var(--d2-line); margin-top: 6px; }

/* 2026-09-29 容器细分开关（可折叠芯片组） */
.d2-subtypes { margin: 6px 0 2px; border: 1px solid var(--d2-line); border-radius: 8px; background: var(--d2-card-bg); }
.d2-subtypes[hidden] { display: none; }
.d2-subtypes summary { display: flex; align-items: center; justify-content: space-between; cursor: pointer; padding: 6px 10px; color: var(--d2-muted); font-size: 13px; user-select: none; list-style: none; }
.d2-subtypes summary::-webkit-details-marker { display: none; }
.d2-subtypes[open] summary i { transform: rotate(180deg); }
.d2-subtypes summary i { font-style: normal; transition: transform .15s; }
.d2-subtypes__list { display: flex; flex-wrap: wrap; gap: 5px; padding: 2px 10px 10px; }
.d2-subtype-chip { display: inline-flex; align-items: center; gap: 5px; padding: 4px 9px; border: 1px solid var(--d2-line); border-radius: 999px; background: var(--d2-chip-bg); color: var(--d2-text); font-size: 14px; cursor: pointer; min-height: 24px; }
.d2-subtype-chip em { font-style: normal; color: var(--d2-muted); font-size: 12px; }
.d2-subtype-chip[aria-pressed="false"] { opacity: .38; }
.d2-subtype-chip[aria-pressed="true"] { border-color: rgba(215,181,109,.5); }

/* 2026-09-29 侧栏可折叠 + 顶部对局信息胶囊（takefu-side-v2） */
/* 折叠修复：侧栏不能 display:none —— 会退出网格流导致自动重排、
   地图被塞进 0px 首列（2026-09-29 用户实测折叠后地图消失的根因）。
   改为保持网格占位、视觉归零 */
.d2-app.d2-side-off { grid-template-columns: 0 minmax(0, 1fr) var(--d2-right); }
.d2-app.d2-side-off .d2-side { width: 0; min-width: 0; border: 0; padding: 0; margin: 0; overflow: hidden; visibility: hidden; }
.d2-side-fold { border: 1px solid var(--d2-line); background: var(--d2-chip-bg); color: var(--d2-muted); border-radius: 6px; width: 22px; height: 22px; line-height: 1; cursor: pointer; flex: 0 0 auto; }
.d2-side-fold:hover { color: var(--d2-text); border-color: rgba(215,181,109,.5); }
.d2-side-unfold { position: absolute; left: 8px; top: 10px; z-index: 34; display: none; border: 1px solid rgba(215,181,109,.4); background: rgba(12,14,16,.5); color: var(--d2-muted); border-radius: 6px; width: 24px; height: 24px; line-height: 1; cursor: pointer; backdrop-filter: blur(2px); } /* tidy1：轻量化，不再形成黑块 */
.d2-app.d2-side-off .d2-side-unfold { display: block; }
.d2-side-unfold:hover { color: var(--d2-text); border-color: rgba(215,181,109,.5); }
.d2-raid-chip { position: absolute; top: 10px; left: 50%; transform: translateX(-50%); z-index: 30; padding: 5px 14px; border: 1px solid var(--d2-line); border-radius: 999px; background: rgba(12, 14, 16, 0.82); backdrop-filter: blur(10px); color: var(--d2-text); font-size: 13px; letter-spacing: .02em; pointer-events: auto; cursor: pointer; user-select: none; }
.d2-raid-chip .d2-raid-timer { font-variant-numeric: tabular-nums; color: #ffd98a; margin-left: 6px; }
.d2-raid-chip.is-timing .d2-raid-timer { color: #7ee787; }
.d2-raid-chip[hidden] { display: none; }
.d2-subtitle:empty { display: none; }
@media (max-width: 900px) { .d2-side-fold { display: none; } }
/* 2026-09-29 审计修复（文件末尾补位，特异性压过 1982 行全局 chip 规则）：
   窄屏时钟降一行让开工具栏 + 详情头部加顶距让关闭钮离开站点顶栏。
   另：2005 行的全局 `.d2-detail{position:relative}`（桌面三栏折叠批注）把 1683 行
   移动端抽屉的 absolute 盖掉了 → 抽屉错位到页面顶部、关闭钮钻进站点顶栏，
   这里在移动断点内恢复抽屉定位。 */
@media (max-width: 960px) {
  .d2-raid-chip { top: 62px; max-width: calc(100vw - 20px); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .d2-detail__head { padding-top: 30px; }
  .d2-side, .d2-detail { position: absolute; }
}

/* 2026-09-29 乱跳根治：标记层 transform-origin 必须与画布一致（0 0）——默认 50% 会让跟随态相对烘焙态整体偏移，选中重渲染瞬间即乱跳 */
[data-role='markers'] { transform-origin: 0 0; }

/* takefu-ux-batch2 */
.d2-kicker--simple { justify-content: flex-start; gap: 8px; font-size: 14px; }
.d2-kicker--simple b { color: var(--d2-accent); }
/* 右侧详情可折叠（同左侧：占位归零防网格重排） */
.d2-app { grid-template-columns: var(--d2-left) minmax(0, 1fr) var(--d2-right); }
.d2-app.d2-detail-off { grid-template-columns: var(--d2-left) minmax(0, 1fr) 0; }
.d2-app.d2-detail-off .d2-detail { width: 0; min-width: 0; border: 0; padding: 0; margin: 0; overflow: hidden; visibility: hidden; }
.d2-detail { position: relative; }
.d2-detail-close { position: absolute; top: 8px; right: 10px; z-index: 5; width: 22px; height: 22px; border: 1px solid var(--d2-line); background: var(--d2-chip-bg); color: var(--d2-muted); border-radius: 6px; cursor: pointer; font-size: 15px; line-height: 1; }
.d2-detail-close:hover { color: var(--d2-text); }
.d2-detail-unfold { position: absolute; right: 8px; top: 10px; z-index: 34; display: none; width: 26px; height: 26px; border: 1px solid var(--d2-line); background: rgba(12,14,16,.85); color: var(--d2-muted); border-radius: 6px; cursor: pointer; }
.d2-app.d2-detail-off .d2-detail-unfold { display: block; }
/* 细分全选/全不选 */
.d2-subtypes__quick { display: inline-flex; gap: 6px; margin-left: auto; }
.d2-subtypes__quick button { border: 1px solid var(--d2-line); background: var(--d2-chip-bg); color: var(--d2-muted); font-size: 12px; border-radius: 6px; padding: 2px 8px; cursor: pointer; min-height: 20px; }
.d2-subtypes__quick button:hover { color: var(--d2-text); }
/* 分区折叠 */
.d2-fold-section { border-top: 1px solid var(--d2-hairline); margin-top: 6px; }
.d2-fold-section > summary { list-style: none; cursor: pointer; user-select: none; display: flex; align-items: center; justify-content: space-between; }
.d2-fold-section > summary::-webkit-details-marker { display: none; }
.d2-fold-section .d2-fold-mark { font-style: normal; transition: transform .15s; }
.d2-fold-section:not([open]) .d2-fold-mark { transform: rotate(-90deg); }
.d2-fold-section .d2-clear-btn { display: block; width: 100%; text-align: right; border: 0; background: transparent; color: var(--d2-accent); font-size: 13px; padding: 4px 2px 6px; cursor: pointer; }
/* 2026-09-29 用户指定：顶部单行「互动地图3 · 图名」，h1 承担标题 */
.d2-kicker--title { font-size: 17px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin: 0; }
.d2-kicker--title b { font-size: 17px; }
.d2-kicker--title span { font-size: 17px; color: var(--d2-text); font-weight: 600; }
.d2-variants-inline { display: flex; gap: 8px; margin: 4px 0 0; font-size: 12px; color: var(--d2-muted); }
.d2-variants-inline a { color: var(--d2-accent); text-decoration: none; }
.d2-variants-inline a:hover { text-decoration: underline; }
.d2-variants-inline span { color: var(--d2-text); font-weight: 600; }
/* 任务列表错位修复：列表自身滚动（2026-09-29 修正：去掉 .d2-side__body 的 overflow:visible 覆盖——
   它把侧栏唯一的滚动容器废掉，配合 body overflow:hidden 导致整页锁死滚不动；列表错位由 d2-list 自滚解决） */
.d2-fold-section .d2-list { max-height: 34vh; overflow-y: auto; scrollbar-width: thin; }
/* 实时时钟 */
.d2-raid-clock { font-variant-numeric: tabular-nums; color: #ffd98a; margin-left: 8px; }

/* 2026-09-29 任务详情图文卡 */
.d2-detail-card--task h3 { display: flex; flex-direction: column; gap: 2px; }
.d2-detail-card--task h3 em { font-style: normal; font-size: 12px; color: var(--d2-muted); font-weight: 400; }
.d2-task-gallery { display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); gap: 6px; margin: 8px 0; }
.d2-task-gallery img { width: 100%; aspect-ratio: 16/10; object-fit: cover; border-radius: 8px; border: 1px solid var(--d2-line); cursor: zoom-in; }
/* 2026-09-30：任务图集改为可点击放大（锚点即网格项，图片填满），悬停/聚焦给可点反馈 */
.d2-task-gallery .d2-task-shot { display: block; line-height: 0; border-radius: 8px; }
.d2-task-gallery .d2-task-shot:focus-visible { outline: 2px solid rgba(215, 181, 109, 0.7); outline-offset: 1px; }
.d2-task-gallery .d2-task-shot img { display: block; transition: border-color .15s; }
.d2-task-gallery .d2-task-shot:hover img { border-color: rgba(215, 181, 109, 0.55); }
.d2-task-seg h4 { margin: 8px 0 3px; font-size: 13px; color: var(--d2-accent); }
/* 2026-10-14：任务小节的正文要按「一行一步」显示。
   上游 objectives/tips/how_to 本就是一个数组，抓取时曾用空格拼接，导致 11 个步骤挤成一整行；
   现在数据里是 \n（换行）。HTML 默认会把换行折叠成空格，所以这里用 pre-line：
   保留换行、其余空白照常折叠。escapeHtml 不转义 \n，无需在前端拆行，零 XSS 风险。 */
.d2-task-seg p { margin: 0; font-size: 13px; line-height: 1.6; color: var(--d2-text); white-space: pre-line; }
.d2-task-guide { display: block; margin-top: 10px; padding: 8px 10px; border: 1px solid rgba(215,181,109,.4); border-radius: 8px; color: var(--d2-accent); font-size: 14px; text-decoration: none; text-align: center; }
.d2-task-guide:hover { background: rgba(215,181,109,.12); }
/* 任务图文卡顶部的攻略入口：与下方任务标题拉开距离，避免按钮贴标题。 */
.d2-detail-card--task > .d2-task-guide { margin-top: 0; margin-bottom: 16px; }

/* takefu-side-restructure（2026-09-29 侧栏重排） */
.d2-map-switch { border: 1px solid var(--d2-line); border-radius: 8px; margin: 6px 0; background: var(--d2-card-bg); }
.d2-map-switch summary { list-style: none; cursor: pointer; padding: 6px 10px; color: var(--d2-muted); font-size: 13px; display: flex; justify-content: space-between; user-select: none; }
.d2-map-switch summary::-webkit-details-marker { display: none; }
.d2-map-switch__body { padding: 0 6px 8px; }
.d2-presets-fold { border-top: 1px solid var(--d2-hairline); }
.d2-presets-fold > summary { cursor: pointer; user-select: none; }
.d2-presets-fold:not([open]) .d2-quick-presets,
.d2-presets-fold:not([open]) .d2-mode-summary,
.d2-presets-fold:not([open]) > .d2-fold-section,
.d2-presets-fold:not([open]) > .d2-subtypes { display: none; }
/* 细分芯片列表限高（展开也不吃满侧栏） */
.d2-subtypes__list { max-height: 30vh; overflow-y: auto; }
/* 撤离阵营行：撤离类全关时隐藏（引擎 is-visible 已控，兜底） */
.d2-faction-row:not(.is-visible) { display: none; }

/* 2026-09-29 修错位：预设网格与折叠壳解耦 */
.d2-presets-fold .d2-quick-presets { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 7px; margin: 6px 0 0; }
.d2-presets-fold > summary { padding: 8px 2px 4px; }
/* 2026-09-30 审计修复：作战模式只保留一行标题（此前独立标题行 + 折叠标题行连着两条
   「作战模式」）。折叠标题行 = 标题 + 重置按钮 + 展开箭头，三段自动排布；箭头随开合旋转。 */
.d2-presets-fold__head { gap: 8px; }
.d2-presets-fold__head::-webkit-details-marker { display: none; }
.d2-presets-fold__head .d2-fold-mark { font-style: normal; transition: transform .15s; flex: 0 0 auto; }
.d2-presets-fold:not([open]) .d2-fold-mark { transform: rotate(-90deg); }
/* 任务列表展开区：清空按钮不再挤压列表 */
[data-list-fold] .d2-clear-btn { width: auto; align-self: flex-end; margin: 2px 2px 6px; }
[data-list-fold] { display: flex; flex-direction: column; }
[data-list-fold] .d2-list { min-height: 120px; }

/* 2026-09-29 头部拥挤修正：去掉互链行后统一行距 */
.d2-side__head { padding-bottom: 6px; }
.d2-kicker--simple { display: flex; align-items: center; gap: 8px; margin: 6px 0 2px; }
.d2-subtitle:empty { margin: 0; }
.d2-map-switch { margin: 4px 0; }
.d2-map-switch summary { padding: 5px 10px; }

/* 2026-09-29 审计修复（必须位于 .d2-detail{position:relative} 之后才能胜出）：
   移动端抽屉定位恢复 —— relative 批注是桌面三栏网格用的，窄屏盖掉 960 断点
   的 absolute 后抽屉错位到页面顶部、关闭钮钻进站点顶栏点不到。 */
@media (max-width: 960px) {
  .d2-side, .d2-detail { position: absolute; }
}

/* ===== 2026-09-30 推广横幅（yatui.cc）：地图上方浮动卡片，可关闭（v2）=====
   用户口径：横幅放进地图上方、不单独占一条布局位；关闭钮在图片右上角、醒目。
   容器 pointer-events:none 不挡地图拖拽，仅卡片本身可点。

   2026-10-10（panel5）重排：横幅改到**对局时钟下方**。
   改前是 body.d2-promo-on 一出现就把顶部拆成三行错落（工具栏/图层 178px、时钟 226px），
   时钟被推到视口 22%~28% 处 —— 用户原话「每次都把时间这些悬浮框挤到中间」。
   现在改成：时钟 / 工具栏 / 图层控件**恒定停在默认位**（top 10/14/14px），
   横幅整体下移到这一行之下。于是 body.d2-promo-on 不再需要任何让位规则：
   默认态与 promo 态完全一致，少一处状态，横幅开合不再让任何元素跳动。

   2026-10-10（panel14）修复横幅压住地图控件：
   横幅此前 top:136px，与 panel13 的工具栏/图层控件行（stage top:72 + 高 48 → 视口 136~184）完全重叠，
   实测卫星图按钮中心点 elementFromPoint 命中 .d2-promo__link img，真实用户点不到底图切换，
   audit_ditu2_maps.js 也在此超时。横幅改到控件行下方（桌面 top:196px，控件底 184 + 12px 间距）；
   不再尝试给 .d2-toolbar / .d2-map-controls 加 z-index —— 二者在 .d2-stage(z-index:1) 堆叠上下文内，
   无论内部 z-index 多高都压不过同级 z-index:40 的横幅。 */
/* 2026-10-17 用户口径还原：横幅回到「地图内浮动」（不单独占一条布局位）——
   10-14 D8 的「页面底部独立布局条」被用户否决（底部条自身左右留白、地图不满屏）。
   桌面 top 由 ditu2.js 的 syncPromoTop() 实测 .d2-topbar 底边 +12px 写入内联值，
   本处 196px（= 控件行底 184 + 12，10-10 实测口径）为 JS 执行前的兜底；
   移动端（≤960）内联值被清空、回到下方 @media 的固定 top。
   容器 pointer-events:none 不挡地图拖拽，仅卡片本身可点。 */
/* 2026-10-20 用户指令：横幅从「地图上方」移到底部，浮在**底部按钮（页签栏 / 对局坞）之上**。
   旧口径（top 196 / 188）会让横幅压住楼层条——实测 390 宽下广告可见区 y194–242，
   而楼层条正好在 y204–238，整行被吃掉，移动端根本点不到楼层。
   现在改为底部锚定：
     · position:fixed —— 横幅是 body 的直接子元素，body 高度不等于视口时 absolute 的
       bottom 会算错（1024×768 实测文档高 818，多出 50px）；fixed 恒定以视口为准。
     · 桌面 bottom:62px（对局坞 14 + 高 40 + 8）；≤960 bottom:102px（页签栏 58 + 坞 34 + 10）；
       横屏 bottom:88px（页签栏 46 + 坞 34 + 8）。
     · left/right 用面板宽度变量夹住，横幅不再压在左右面板上（桌面原来压住两栏顶部 108px）。 */
.d2-promo {
  position: relative;
  order: 2;
  flex: 0 0 60px;
  height: 60px;
  width: 100%;
  align-items: center;
  background: var(--d2-bg);
  border-top: 1px solid var(--d2-line);
  z-index: 40;
  display: flex;
  justify-content: center;
  padding: 0;
  pointer-events: none;
}
.d2-promo[hidden] { display: none; }
/* 2026-10-20：广告移到底部后与重置条同区，广告显示期间先让位（关闭广告即恢复） */
body.d2-promo-on .d2-resetbar { display: flex; }
/* 2026-10-17 恢复：主题菜单 / 画板打开时横幅退场（浮动后与 .d2-stage 内控件
   纵向相交，body 级 z-index:40 会压过它们 —— panel14 / 10-12 的同源问题）。 */
body:has(.d2-theme__menu:not([hidden])) .d2-promo { display: none; }
body:has(.d2-drawboard:not([hidden])) .d2-promo { display: none; }
/* 2026-10-10（panel14）/ 2026-10-12 的「主题菜单 / 画板打开时横幅退场」需求，
   在 2026-10-17 浮动还原时一并恢复 —— 规则已上移至 .d2-promo[hidden] 之后。
   历史沿革：D8（10-14）曾因横幅移到底部而删除这两条，本次随浮动一并回归。 */
.d2-promo__box { display: flex; align-items: center; gap: 8px; max-width: 100%; position: relative; pointer-events: auto; border-radius: 10px; overflow: visible; box-shadow: 0 6px 24px rgba(0,0,0,.45); }
.d2-promo__link { display: block; border-radius: 10px; overflow: hidden; }
.d2-promo__link img { display: block; height: 48px; width: auto; max-width: min(800px, calc(100vw - 72px)); object-fit: contain; background: #0b0d0f; }
/* 关闭按钮重设计（2026-09-30，用户口径「原来的关闭按钮丑」）：
   原方案是「金色圆币 + 2px 奶白描边 + 外挂 -12px」——与横幅配色打架、外挂出画显得笨重。
   现改为内嵌右上角的磨砂玻璃圆钮：半透明深底 + 1px 内描边（inset box-shadow，不用实心边框）
   + 背景模糊，hover 提亮微放大；× 用伪元素绘制而非字形，任意 DPI 都锐利、不依赖字体。 */
.d2-promo__close { position: relative; flex: 0 0 40px; z-index: 6; width: 40px; height: 40px; padding: 0; border: 0; border-radius: 50%; background: rgba(12,14,18,.55); color: #fff; font-size: 0; line-height: 1; cursor: pointer; -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); box-shadow: 0 1px 6px rgba(0,0,0,.35), inset 0 0 0 1px rgba(255,255,255,.3); transition: background-color .15s ease, transform .15s ease, box-shadow .15s ease; }
.d2-promo__close::before, .d2-promo__close::after { content: ""; position: absolute; top: 50%; left: 50%; width: 11px; height: 1.6px; margin: -0.8px 0 0 -5.5px; border-radius: 2px; background: currentColor; }
.d2-promo__close::before { transform: rotate(45deg); }
.d2-promo__close::after { transform: rotate(-45deg); }
.d2-promo__close:hover, .d2-promo__close:focus-visible { background: rgba(12,14,18,.84); box-shadow: 0 2px 10px rgba(0,0,0,.45), inset 0 0 0 1px rgba(255,255,255,.5); outline: 0; transform: scale(1.08); }
/* 2026-10-10（panel5）：原先这里有三条 body.d2-promo-on 让位规则
   （toolbar/map-controls → 178px、raid-chip → 226px），把时钟挤到视口 22%~28%。
   横幅下移到时钟下方后已全部删除 —— 默认态即最终态，横幅开合不再产生任何位移。
   唯一残留的 promo 相关规则是下面移动端抽屉打开时的 display:none（横幅退场）。 */
@media (max-width: 960px) {
  /* 2026-10-20：底部锚定 —— 页签栏 58 + 对局坞 34 + 10 间距。
     横幅不再与任何控件行相交（旧 top:188 与楼层条 y204–238 直接重叠）。 */
  .d2-promo {
    flex-basis: 48px;
    height: 48px;
    padding: 4px 8px;
  }
  .d2-promo__link img { height: 36px; max-width: calc(100vw - 72px); }
  .d2-promo__close { width: 40px; height: 40px; }
}

/* tidy1：容器细分内联进作战模式区 */
.d2-subtypes--inline { margin: 2px 0 4px; }
.d2-subtypes--inline > summary { font-size: 13px; color: var(--d2-muted); padding: 6px 2px; }
.d2-subtypes--inline .d2-subtypes__list { padding: 2px 0 8px; }

/* tidy1：切换地图＝横向直接跳转条 */
.d2-map-quickbar { display: flex; flex-wrap: wrap; gap: 4px; margin: 8px 0 4px; }
.d2-map-quickbar__item { padding: 3px 9px; border: 1px solid var(--d2-line); border-radius: 999px; font-size: 13px; color: var(--d2-muted); text-decoration: none; background: var(--d2-card-bg); }
.d2-map-quickbar__item:hover { color: var(--d2-text); border-color: rgba(215,181,109,.5); }
.d2-map-quickbar__item.is-current { background: rgba(215,181,109,.16); border-color: rgba(215,181,109,.5); color: var(--d2-text); }

/* tidy2：作战模式合并后侧栏超长修复——细分格与容器细分限高滚动，芯片紧凑化 */
.d2-presets-fold .d2-filter-grid { max-height: 30vh; overflow-y: auto; scrollbar-width: thin; }
.d2-presets-fold .d2-subtypes__list { max-height: 22vh; overflow-y: auto; scrollbar-width: thin; }
.d2-presets-fold .d2-subtype-chip { font-size: 12px; padding: 2px 6px; }

/* tidy1-merge：作战模式内的嵌套细分（细分图层 + 容器细分） */
.d2-presets-fold > .d2-fold-section--nested { margin: 4px 0 0; padding-left: 2px; }
.d2-presets-fold > .d2-subtypes--inline { margin: 2px 0 0; }
.d2-presets-fold .d2-mode-summary { margin: 8px 0 6px; }

/* ===== 2026-10-05 侧栏嵌套滚动条清理（用户口径：整个侧栏只留一条滚动条）=====
   背景：tidy2 为解决「作战模式合并后侧栏超长」，给三个内层网格各自加了
   max-height + overflow-y:auto（细分图层 30vh / 容器细分 22vh / 撤离点与任务 34vh），
   于是侧栏里出现 3 个嵌套滚动条，且产生「先滚内层、滚到底才滚外层」的滚动陷阱。
   用户实测反馈：细分图层展开后仍有部分内容要单独滑，很难看。
   正解：内层全部取消限高，滚动交给唯一的 .d2-side__body；
   侧栏过长的问题由「所有分区本身都是 <details> 可折叠 + 列表内还有分组可折叠」解决。
   ⚠️ 只作用于 .d2-side 作用域内，右侧详情栏/弹层里同名类保持原样。 */
.d2-side .d2-subtypes__list,
.d2-side .d2-presets-fold .d2-subtypes__list,
.d2-side .d2-presets-fold .d2-filter-grid { max-height: none; overflow: visible; }
/* 2026-10-10 panel1：唯独「撤离点与任务」列表不再清空限高——
   它改成侧栏**唯一**的滚动容器（见文件末尾 2026-10-10 块）。
   筛选区仍然不滚动，所以「整个侧栏只留一条滚动条」的口径没有被推翻，
   只是那条滚动条从 .d2-side__body 移到了列表区（body 只在极矮视口兜底时才滚）。 */

/* ======================================================================
   2026-10-10 panel1：map3 左侧面板（17 图共用引擎，改动全站生效）
   1) 标题与收缩按钮并排成一行
   2) 筛选区固定高、列表区吃掉全部剩余高度并自滚 → 点位列表首屏可见
   3) 预设按钮补「部分开启」中间态
   ====================================================================== */

/* --- 1) 标题行 --- */
.d2-side__head-row {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}
/* 标题在 flex 行里必须允许收缩，否则 ellipsis 不生效、长图名会顶破侧栏 */
.d2-side__head-row .d2-kicker--title { flex: 1 1 auto; min-width: 0; margin: 0; }
/* 窄屏按钮被 1996 行隐藏后，标题仍然占满整行，不会因为少一个兄弟节点而错位 */
@media (max-width: 900px) { .d2-side__head-row .d2-kicker--title { flex: 1 1 100%; } }

/* --- 2) 侧栏主体：整条侧栏只保留一个滚动条（2026-10-10 panel15 修正） ---
   panel2 曾把「撤离点与任务」列表设成唯一滚动容器（.d2-side__body 改 flex 列、
   .d2-list 给 flex:1 1 auto）。分类体系换成九组后，上方分类区实测 1016px，
   已超过面板可视高度 671px：flex 无法再给列表留空间，列表被压到 min-height 120px
   并自滚（1576/120），同时 body 也在滚（1267/671）——又回到用户反复抱怨的
   「外侧一条 + 撤离点内侧一条」两条滚动条。
   正解：整条侧栏由 .d2-side__body 一个容器滚动，列表恢复自然全高、不自滚。
   这与 ≤960px 移动抽屉本来就是同一形态，也符合 2026-10-05「只留一条滚动条」的口径；
   因此下面原来单独的移动端覆盖块已删除，桌面/移动共用同一套规则。 */
.d2-side__body { display: block; overflow-y: auto; }
.d2-side [data-list-fold]::details-content { display: block; }
.d2-side__body > [data-list-fold] { flex: 0 0 auto; min-height: auto; }
.d2-side__body > [data-list-fold] > .d2-list {
  min-height: 0;
  max-height: none;
  overflow-y: visible;
  overscroll-behavior: auto;
  grid-auto-rows: auto;
}

/* --- 3) 预设「部分开启」中间态 ---
   不复用 [aria-pressed="true"] 的实心高亮（那是「全亮」），改用描边+分数，
   避免「部分开启」被误读成「已完全开启」。刻意不用渐变/彩条。 */
.d2-preset small:empty { display: none; }
.d2-preset[aria-pressed="mixed"] {
  border-color: rgba(215, 181, 109, 0.5);
  border-style: dashed;
  background: rgba(215, 181, 109, 0.07);
  color: var(--d2-text);
  box-shadow: inset 0 0 0 1px rgba(215, 181, 109, 0.16);
}
.d2-preset[aria-pressed="mixed"] strong { color: var(--d2-accent); }
.d2-preset[aria-pressed="mixed"] small { color: var(--d2-accent); }
/* 分数位固定高度：避免「部分开启」出现/消失时按钮高度跳动 */
.d2-preset[data-preset] span { display: flex; align-items: baseline; justify-content: space-between; gap: 6px; }
.d2-preset[data-preset] small { margin-top: 0; flex: 0 0 auto; font-variant-numeric: tabular-nums; }
.d2-fold-count { font-variant-numeric: tabular-nums; }

/* --- 4) 嵌套折叠标题行热区≥24px（用户偏好：密度优先）---
   实测这两个 summary 改动前后都是 18px（既有现象），但它们现在是主要控件，
   触摸端 18px 偏难点。只补 min-height，字号/配色/文案不动。 */
.d2-side [data-filter-fold] > .d2-section-title,
.d2-side [data-list-fold] > .d2-section-title { min-height: 24px; }

/* ======================================================================
   5) 移动端抽屉与对局时钟胶囊压字（2026-10-10 panel2）
   ======================================================================
   现象：390x844 打开「图层」抽屉时，侧栏标题「互动地图3 · 森林」与
   .d2-raid-chip 上下压字，实测两矩形垂直重叠 11px（改动前 17px）。

   为什么不能用「加固定 top 偏移」修：
   抽屉是 bottom 锚定 + max-height:min(74vh,620px)，其顶边随视口高度浮动。
   实测 6 档视口的抽屉顶边 = 108 / 115 / 166 / 237 / 346 / 64px，
   而 chip 恒在 194-222px。不存在任何单一 top 值能同时避开所有视口 ——
   压低到 108 以下会让 iPad(346)、Pixel(237) 的 chip 跑到抽屉上方压住地图，
   抬高到 346 以上则 844 高的屏上 chip 会被顶出可视区。

   为什么不能隐藏移动端大标题：
   实测 .d2-map-quickbar__item.is-current（当前地图高亮）位于 213-237px，
   与 chip 的 194-222px 同样相交 9px。chip 宽 307px > 抽屉宽 304px，
   水平方向必然压住 quickbar 当前项。页面无面包屑可替代，隐藏标题等于
   连唯一「当前是哪张图」的线索一起丢掉。

   采用方案（状态驱动，非魔法数值）：chip 是 .d2-stage 的地图浮层，
   抽屉是 .d2-side 的面板层。抽屉打开（data-mobile-panel 非空）时，
   地图区域本就被抽屉盖住 304/390，chip 属于被遮挡内容，让它退场即可；
   关闭抽屉后 chip 立即归位。桌面端（>960px）无此问题，完全不动。

   注：chip 仍需在「抽屉关闭」时可点（它排除在地图拖拽命中之外，见
   ditu2.js 的 closest('.d2-raid-chip')），所以这里只做 display:none，
   不改它的 pointer-events 与 DOM 位置。

   ⚠️ 2026-10-10 panel4 收窄：抽屉打开时 chip 已经被 syncRaidChipHost() 搬进
   抽屉内部（.d2-raid-slot），不再是「被遮挡的地图浮层」，所以这条规则必须
   只对**仍在地图浮层里**的那一份生效。选择器从后代选择器收紧为
   .d2-stage > .d2-raid-host > .d2-raid-chip：抽屉态下 chip 已经不是 .d2-stage
   的后代，规则自然失配；万一 JS 搬运失败（refs 缺失等），chip 留在地图上时
   这条规则仍然兜底隐藏，压字问题不会复发。 */
@media (max-width: 960px) {
  .d2-app[data-mobile-panel="layers"] .d2-stage .d2-raid-chip,
  .d2-app[data-mobile-panel="detail"] .d2-stage .d2-raid-chip {
    display: none;
  }
}

/* ======================================================================
   6) 移动端广告横幅压住抽屉标题（2026-10-10 panel3）
   ======================================================================
   现象：320x568 打开「图层」抽屉时，侧栏标题「互动地图3 · 森林」被
   .d2-promo 广告横幅压住 —— 实测两矩形垂直相交 17px，标题中心点
   elementFromPoint 命中的是 .d2-promo__link img，即文字被图片完全盖住。

   ⚠️ 这不是罕见场景：横幅是「首次访问/刷新即显示，关闭后本会话不再出现」
   （见 tools/build_ditu2_pages.js 的 takefu-map3-promo-closed 逻辑），
   实测默认态 body 就有 .d2-promo-on，横幅处于 display:flex。
   且 promo z-index:40 > 抽屉 .d2-side z-index:30，必然穿透在上。

   为什么不能像 chip 那样用后代选择器：
   .d2-promo 是 <body> 的直接子元素，而 data-mobile-panel 挂在
   同一层级的 .d2-app 上——两者是兄弟而非祖先，必须借 :has() 上溯。
   退化行为：极老浏览器不支持 :has() 时整条规则被丢弃 = 保持改动前的
   压字状态，不引入新问题。

   处理与 chip 同源：抽屉打开时地图区域本就被盖住，横幅属被遮挡内容。
   只改display，不动 body.d2-promo-on（2026-10-10 panel5 起该类已不再带任何
   让位位移，横幅开合本就不产生位移，抽关闭后自然一致）。
   桌面端（>960px）横幅在地图上方、抽屉是三栏布局，二者不重叠，完全不动。 */
/* 2026-10-17 还原浮动：抽屉与横幅重新可能相交，恢复抽屉打开时横幅退场
   （只改 display，不动 hidden / DOM；抽屉选择器见上文「6)」段说明）。 */
@media (max-width: 960px) {
  body:has(.d2-app[data-mobile-panel="layers"]) .d2-promo,
  body:has(.d2-app[data-mobile-panel="detail"]) .d2-promo {
    display: none;
  }
}

/* ======================================================================
   7) 对局信息进抽屉（2026-10-10 panel4）
   ======================================================================
   背景：panel2 用 display:none 让 chip 在抽屉打开时退场，代价是移动端
   筛选图层时看不到本局时长/人数/游戏时钟。正解是把它搬进抽屉内部。

   实现方式是**搬同一个 DOM 节点**（ditu2.js 的 syncRaidChipHost），
   不是在抽屉里再建一个容器。所以全页任何时刻 .d2-game-clock 只有 1 个、
   setInterval 只有 1 个，时钟跨抽屉开合连续走、不重启。
   本段 CSS 只负责「同一个节点在两种宿主下各自的呈现」。

   ---------------------------------------------------------------------
   7.1 地图态锚点：display:contents
   ---------------------------------------------------------------------
   chip 原本是 .d2-stage 的直接子元素。现在外面套了一层 .d2-raid-host
   （syncRaidChipHost 的抽屉关闭态落点），若给这层默认的 display:block，
   它会成为 .d2-stage 里的一个匿名块级盒子 —— .d2-stage 是 position:relative
   的定位容器，多出的盒子理论上不改变 absolute 的chip 的包含块（仍是
   .d2-stage），但它会参与 flex/grid 之外的一切流式布局，属于隐性回归风险。
   display:contents 让这层完全不生成盒子，.d2-stage 的子元素序列与改动前
   逐一致，桌面端层叠与定位零变化。 */
.d2-raid-host { display: contents; }

/* ---------------------------------------------------------------------
   7.2 槽位：空的时候必须占 0 高
   ---------------------------------------------------------------------
   槽位是纯落点容器，chip 不在里面时它是空的。空 div 若有 margin/padding
   就会在标题与quickbar 之间留一条白边，所以 margin/padding 一律不给，
   间距由 chip 自己的 margin 承担（见 7.3）。这样「抽屉开着但 chip 不可用」
   （例如某张图没有 players/raidDuration，chip.hidden=true）时头部高度
   与改动前完全相同，不留空槽。 */
.d2-raid-slot { display: block; min-height: 0; }

/* ---------------------------------------------------------------------
   7.3 抽屉内的 chip 形态
   ---------------------------------------------------------------------
   位置选择：放在标题行（.d2-side__head-row）下方、quickbar 上方。
   理由（实测坐标支撑，不是拍脑袋）：
   - 放标题行**上方**会与 320x568 下的标题挤在一起，且视觉上「对局信息」
     是标题的补充说明，不该抢在标题前面；
   - 放 quickbar **下方**（即 .d2-side__body 顶部）会离标题太远，
     且quickbar 在 320px 下已占 136px（实测），再加一行会把搜索框
     整体下推，首屏可见列表项从 24 降到更少；
   - 标题与 quickbar 之间是唯一「既紧跟标题、又不挤压 body」的插入位。
     实测 390x844 抽屉头高193 → 221（+28px），quickbar 与标题坐标均不变。

   宽度：槽位**出血到抽屉满宽**（见 7.3b），这是让三段信息不截断的关键。
   密度：单行、min-height 24px（与 panel1 的行高下限一致），
   用 flex + gap 把「时长·人数」和「游戏时钟」压在同一行的两侧，
   不换行、不加图标、不加第二行。

   装饰铁律：不使用 border-left 做主装饰，不做「浅卡片+彩条+渐变」。
   这里只复用 chip 原有的那套变量（--d2-line / --d2-text / --d2-muted），
   圆角从 999px 胶囊降到 6px 以贴合抽屉内的直角控件（.d2-side-fold 同为 6px），
   背景沿用 chip 原本的半透明深色 + blur，不引入新的色值。 */
.d2-raid-slot .d2-raid-chip {
  position: static;
  transform: none;
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  /* ⚠️ 必须显式解除：2003 行（窄屏让位工具栏的那条）给 .d2-raid-chip 加了
     max-width:calc(100vw - 20px)，320px 视口下就是 300px。抽屉内槽宽 302px
     会被它悄悄砍到 300px —— 少掉的 2px 正好是余量的命门子。
     槽宽由外层 .d2-side__head 的 padding 决定，不需要这层视口上限。 */
  max-width: none;
  min-height: 24px;
  margin: 4px 0 2px;
  padding: 3px 10px;
  border-radius: 6px;
  /* 11px 与项目主力小字号一致（ditu2.css 里 11px 出现 21 处，是既有规范），
     不为了塞下文字再往下压。对比度：11px 正常文本对 --d2-panel 实测约 7.9:1
     （#a9a397 on #0e1114），远高于 WCAG AA 的 4.5:1。 */
  font-size: 12px;
  /* 地图态靠 nowrap+ellipsis 限宽；抽屉内是正常流式的一行，宽度自洽，
     不需要再截断（外层 .d2-raid-slot 已是抽屉内容宽）。 */
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
}
.d2-raid-slot .d2-raid-chip[hidden] { display: none; }

/* 时钟靠右对齐，让「本局时长·人数」在左、游戏时钟在右，形成稳定的视觉锚点。
   margin-left:auto 而不是固定像素，抽屉宽度变化时不需要重算。
   flex 分配是**刻意的不对称**：时钟 flex:0 0 auto 永不收缩（要求 3 规定昼/夜两个
   时间必须都可见，它不能是被裁的那个）；左侧 info 允许收缩并在超长时省略尾部。
   换句话说：极端长文案下牺牲的是「名玩家」几个字，不是时间信息。 */
.d2-raid-slot .d2-raid-chip .d2-raid-info { flex: 0 1 auto; }
.d2-raid-slot .d2-raid-chip .d2-game-clock {
  flex: 0 0 auto;
  margin-left: auto;
  padding-left: 8px;
  /* 时钟是次要信息，用 --d2-muted 与左侧主信息（--d2-text）拉开层级；
     两个都是既有变量，抽屉态不引入任何新色值。 */
  color: var(--d2-muted);
}
/* 超长文案兜底：正常情况下（见 7.3b 的余量实测）两者都完整显示、单行不裁。
   万一将来出现更长的地图文案，这里保证「行高恒为单行」这条密度约束不被破坏，
   且被裁的始终是左侧 info、时钟永远完整（见上面 flex 分配的说明）。 */
.d2-raid-slot .d2-raid-chip .d2-raid-info,
.d2-raid-slot .d2-raid-chip .d2-game-clock {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ---------------------------------------------------------------------
   7.3b 侧栏槽位出血到抽屉满宽（本节是「信息不截断」的关键）
   ---------------------------------------------------------------------
   问题：按 .d2-side__head 的 16px 内边距内嵌，320px 视口下槽宽只有 272px。
   实测最坏文案「50 分钟 · 12-16 名玩家」(11px 下 117.9px) 加
   「🎮 11:26:08 / 23:26:08」(128.7px) 加 padding 20px 与 gap 8px = 274.6px，
   **溢出 2.6px** —— 截图里看到的「🎮 11:28:53 / 23:...」就是这么来的。
   （17 图的 raidDuration 都在 20-50、players 在 1-3 到 12-16，两位数，
     所以最坏组合就是这一组，不是 woods 特有。）

   方案：槽位用 -16px 负边距抵掉 head 的左右内边距，拿到抽屉满宽 302px。
   实测余量 +27.4px（9.1%），健康；内嵌方案即使把 gap/padding 压到最小
   也只剩 3~4% —— 字体渲染、emoji 宽度的平台差异就能吃掉它，不够稳。
   代价是 chip 左右贴到抽屉内壁，形成一条通栏状态条：这在抽屉头里是
   常规视觉（与下方 quickbar 的通栏一致），不额外引入边框或底色。

   桌面端零影响：此时两个槽位都是空的（chip 在 .d2-raid-host 里），
   空 div 高度 0，且左右 margin 不参与块高计算，抽屉头高度与改动前完全一致。
   详情抽屉里的槽位本来就是满宽（.d2-detail 自身无 padding，padding 在
   .d2-detail__head / __body 上），所以出血规则**只写侧栏**，
   详情侧由 7.5 那条 margin:0 16px 8px 负责留白。 */
.d2-side__head .d2-raid-slot {
  margin-left: -16px;
  margin-right: -16px;
}

/* ---------------------------------------------------------------------
   7.4 时钟样式从 JS 内联 cssText 迁到这里
   ---------------------------------------------------------------------
   renderStats() 原来给 .d2-game-clock 写死 style="color:#7aa2c4"。
   迁到 CSS 后色值一字未改，桌面端渲染与改动前逐像素一致；
   好处是抽屉态能再用变量叠一层（7.3 里改成 var(--d2-muted)），
   不必在 JS 里维护两套内联样式。 */
.d2-raid-chip .d2-game-clock {
  font-variant-numeric: tabular-nums;
  /* R2-D8：旧值固定 #7aa2c4 是为深色底调的；胶囊背景在 R2-D2 已改为 --d2-overlay
     （浅色主题下变浅），实测对比度掉到 2.56:1（×18）。
     改用 --d2-blue（各主题自带的蓝，深浅方向与其背景一致）。 */
  color: var(--d2-blue);
  margin-left: 8px;
}

/* ---------------------------------------------------------------------
   7.5 详情抽屉里的落位
   ---------------------------------------------------------------------
   .d2-detail__head 的内容会被 renderDetail()/renderEmptyDetail() 整块覆写，
   所以槽位必须放在它外面（HTML 注释里已标注）。此处只补一点上间距，
   让它与上方详情标题、下方详情正文都留出呼吸，不改 .d2-detail 的任何布局。

   宽度：.d2-detail 自身**没有** padding（padding 在 .d2-detail__head /
   __body 上），所以这里的槽位天然就是满宽，用左右 16px margin 留出白边即可，
   不需要 7.3b 的出血。实测 320px 视口下此处 chip 可用 297px，
   11px 最坏文案需 274.6px，余量 22.4px（7.5%），不截断。 */
.d2-detail .d2-raid-slot .d2-raid-chip { margin: 0 16px 8px; }

/* ---------------------------------------------------------------------
   7.6 桌面端零影响（显式声明，便于回归核对）
   ---------------------------------------------------------------------
   上面所有 .d2-raid-slot 规则在桌面端都匹配不到任何节点：
   chip 此时被 syncRaidChipHost() 放在 .d2-raid-host（.d2-stage 内）里，
   两个槽位都是空的（0 高、无 margin）。
   7.3 里那条 max-width:none 是移动/桌面通吃的（解除 2003 行的窄屏上限），
   不需要在这里再兜一次；桌面端若因任何原因搬进槽位，width:100% 会把它
   限制在槽内，不会横跨视口。 */

/* 2026-10-09 用户指令：/map/ 左侧分类改为 /map2/ 同款分组体系。
   原作战模式/细分图层/容器细分/价值筛选已移除；这里只负责新分组面板。 */
.d2-categories {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin: 4px 0 8px;
}
.d2-side__body > .d2-categories { flex: 0 0 auto; }
.d2-cat-group {
  border: 1px solid var(--d2-line);
  border-radius: 8px;
  background: var(--d2-card-bg);
  overflow: hidden;
}
.d2-cat-group.is-on { border-color: var(--d2-on-line, rgba(96,165,250,.38)); }
.d2-cat-group.is-empty { opacity: .55; }
.d2-cat-head {
  width: 100%;
  min-height: 34px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 7px 10px;
  border: 0;
  background: transparent;
  color: var(--d2-text);
  font: inherit;
  font-size: 15px;
  font-weight: 650;
  text-align: left;
  cursor: pointer;
}
.d2-cat-head:disabled { cursor: default; }
.d2-cat-title { min-width: 0; }
.d2-cat-switch {
  position: relative;
  flex: 0 0 auto;
  width: 28px;
  height: 16px;
  border-radius: 999px;
  /* 2026-10-20 用户反馈：清爽白下开关几乎不可见（原 rgba(255,255,255,.14) 压在白色面板上 = 1.00:1）。
     改用主题变量：深色主题仍是白系半透明（原观感不变），浅色主题换成墨蓝系半透明。 */
  background: var(--d2-switch-track, rgba(255, 255, 255, .14));
  transition: background .15s;
}
.d2-cat-switch::after {
  content: "";
  position: absolute;
  top: 2px;
  left: 2px;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--d2-switch-knob, rgba(255, 255, 255, .72));
  transition: transform .15s, background .15s;
}
.d2-cat-head[aria-pressed="true"] .d2-cat-switch { background: var(--d2-switch-on, rgba(96,165,250,.75)); }
.d2-cat-head[aria-pressed="true"] .d2-cat-switch::after {
  transform: translateX(12px);
  background: var(--d2-switch-knob-on, #fff);
}
.d2-cat-subs {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  padding: 8px 10px 10px;
  border-top: 1px solid var(--d2-hairline, rgba(255,255,255,.055));
}
.d2-cat-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  min-height: 24px;
  padding: 3px 8px;
  border: 1px solid var(--d2-line);
  border-radius: 6px;
  background: var(--d2-chip-bg);
  color: var(--d2-muted);
  font: inherit;
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
}
.d2-cat-chip:hover:not(:disabled) { color: var(--d2-text); border-color: var(--d2-line-strong); }
.d2-cat-chip img { width: 14px; height: 14px; object-fit: contain; flex: 0 0 auto; }
.d2-cat-chip[aria-pressed="true"] {
  color: var(--d2-text);
  border-color: var(--d2-on-chip-line, rgba(96,165,250,.55));
  background: var(--d2-on-chip-fill, rgba(96,165,250,.14));
}
.d2-cat-chip:disabled { opacity: .38; cursor: not-allowed; }
.d2-cat-empty { color: var(--d2-muted); font-size: 12px; }
@media (max-width: 960px) {
  .d2-cat-subs { gap: 5px; }
  .d2-cat-chip { padding: 3px 7px; }
}
/* 大类按钮混合态：部分子分类开启时显示半开，点击一次统一关闭，再点统一开启。 */
.d2-cat-head[aria-pressed="mixed"] .d2-cat-switch {
  background: linear-gradient(90deg, var(--d2-switch-on, rgba(96,165,250,.75)) 50%, var(--d2-switch-track, rgba(255,255,255,.14)) 50%);
}
.d2-cat-head[aria-pressed="mixed"] .d2-cat-switch::after {
  transform: translateX(6px);
  background: var(--d2-switch-knob-on, #fff);
}
/* ===== 2026-10-11 用户指令：分类面板顶部总控（位置在「地标」组之上）=====
   一键开启 / 关闭地图内全部图层。视觉上比普通分组更「重」——蓝色描边 + 淡蓝渐变底 +
   更粗字，让人一眼认出这是总开关而不是又一个分类。 */
.d2-cat-group--master {
  border-color: var(--d2-on-line, rgba(96,165,250,.34));
  background: linear-gradient(180deg, var(--d2-on-fill, rgba(96,165,250,.11)), var(--d2-on-fill-soft, rgba(96,165,250,.035)));
}
.d2-cat-group--master.is-on { border-color: var(--d2-on-line-strong, rgba(96,165,250,.62)); }
.d2-cat-head--master { font-size: 15px; font-weight: 750; letter-spacing: .01em; }
/* ===== 2026-10-09 map3 顶栏 / 覆盖式侧栏 / 主题按钮 ===== */
.d2-app { grid-template-columns: minmax(0, 1fr); }
.d2-stage { position: absolute; inset: 0; z-index: 1; }
.d2-side,
.d2-detail {
  position: absolute;
  top: 0;
  bottom: 0;
  z-index: 20;
  transition: transform .2s ease, visibility .2s ease;
}
.d2-side { left: 0; width: var(--d2-left); }
.d2-detail { right: 0; width: var(--d2-right); }
.d2-app.d2-side-off,
.d2-app.d2-detail-off { grid-template-columns: minmax(0, 1fr); }
.d2-app.d2-side-off .d2-side { transform: translateX(-100%); visibility: hidden; pointer-events: none; }
.d2-app.d2-detail-off .d2-detail { transform: translateX(100%); visibility: hidden; pointer-events: none; }

.d2-toolbar { left: calc(var(--d2-left) + 14px); top: 72px; z-index: 12; }
.d2-map-controls { right: calc(var(--d2-right) + 14px); top: 72px; z-index: 12; }

/* 2026-10-12 顶部三段布局（用户校正版）：容器只做定界与网格（透明），
   胶囊视觉在 __center；默认 wide = [工具排][对局胶囊][视图组] 并排同高、左中右分散。 */
.d2-topbar {
  position: absolute;
  top: 12px;
  left: calc(var(--d2-left) + 14px);
  right: calc(var(--d2-right) + 14px);
  z-index: 90;
  display: grid;
  /* wide：两侧 1fr 的 min = 各自 min-content（工具排 288 / 视图组自然宽），
     互不压缩、不会左溢重叠；空间由 JS 判定足够后才启用本档 */
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 6px 16px;
  /* 容器只做布局：空白格不得拦截地图的拖拽 / 点击（子元素各自恢复交互） */
  pointer-events: none;
}
.d2-topbar > * { pointer-events: auto; }
/* 对局胶囊：时钟 + 搜索 + 主题 —— 视觉与原有顶栏完全一致（内容原样保留） */
.d2-topbar__center {
  grid-column: 2;
  justify-self: center;
  display: flex;
  align-items: center;
  gap: 8px;
  max-width: min(760px, calc(100% - 28px));
  min-height: 44px;
  padding: 5px 7px 5px 13px;
  border: 1px solid var(--d2-line);
  border-radius: 999px;
  background: var(--d2-overlay);
  box-shadow: var(--d2-shadow);
  backdrop-filter: blur(14px);
}
.d2-topbar__center .d2-raid-host { display: block; flex: 0 0 auto; }
.d2-topbar__center .d2-raid-chip {
  position: static;
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--d2-text);
  transform: none;
  white-space: nowrap;
}
.d2-topbar__center input[type="search"] {
  width: min(300px, 28vw);
  min-width: 150px;
  height: 30px;
  border: 0;
  outline: none;
  background: transparent;
  color: var(--d2-text);
  padding: 0 4px;
}
.d2-topbar__center input[type="search"]::placeholder { color: var(--d2-dim); }

.d2-theme { position: relative; flex: 0 0 auto; }
.d2-theme__btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 32px;
  padding: 0 10px;
  border: 1px solid var(--d2-line);
  border-radius: 999px;
  background: var(--d2-chip-bg);
  color: var(--d2-text);
  cursor: pointer;
  white-space: nowrap;
  font-size: 13px;
}
.d2-theme__swatch {
  width: 11px;
  height: 11px;
  border-radius: 50%;
  border: 1px solid rgba(0, 0, 0, .28);
}
.d2-theme__menu {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  z-index: 100;
  width: 176px;
  padding: 6px;
  border: 1px solid var(--d2-line);
  border-radius: 10px;
  background: var(--d2-panel-2);
  box-shadow: var(--d2-shadow);
}
.d2-theme__menu[hidden] { display: none; }
.d2-theme__item {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 7px 8px;
  border: 0;
  border-radius: 7px;
  background: transparent;
  color: var(--d2-muted);
  text-align: left;
  cursor: pointer;
  font-size: 13px;
}
.d2-theme__item:hover,
.d2-theme__item[aria-checked="true"] { background: var(--d2-chip-bg); color: var(--d2-text); }
.d2-theme__item-sw { width: 12px; height: 12px; border-radius: 50%; border: 1px solid rgba(0,0,0,.28); }

.d2-side-fold,
.d2-side-unfold,
.d2-detail-close,
.d2-detail-unfold {
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border: 1px solid var(--d2-line);
  border-radius: 8px;
  background: var(--d2-overlay);
  color: var(--d2-muted);
  cursor: pointer;
  line-height: 1;
}
.d2-side-fold:hover,
.d2-side-unfold:hover,
.d2-detail-close:hover,
.d2-detail-unfold:hover { color: var(--d2-text); border-color: var(--d2-line-strong); }
.d2-side-fold { position: absolute; top: 14px; right: -14px; z-index: 38; }
.d2-side-unfold { left: 8px; top: 12px; }
.d2-detail-close { top: 14px; right: 14px; }
.d2-detail-unfold { right: 8px; top: 12px; }
/* 2026-10-10（panel14）：统一按钮外观的那组规则写的是 display:grid，
   把它前面 .d2-side-unfold / .d2-detail-unfold 的 display:none 覆盖掉了 ——
   实测面板展开时两个“展开”按钮仍然常显：右侧 ≡（z-index:34）正好压在同位置的
   ×（z-index:5）上，elementFromPoint 命中 ≡，右面板根本关不掉；左侧 » 也压在面板标题上。
   这里补回显隐条件（收起态仍由 .d2-app.d2-*-off 的 display:block 负责显示）。 */
.d2-app:not(.d2-side-off) .d2-side-unfold { display: none; }
.d2-app:not(.d2-detail-off) .d2-detail-unfold { display: none; }

/* 子分类不再画成第二层开关，只保留大类滑块。 */
.d2-cat-chip {
  border: 0;
  background: transparent;
  padding: 2px 4px;
  color: var(--d2-muted);
}
.d2-cat-chip:hover:not(:disabled) { border: 0; background: transparent; color: var(--d2-text); }
.d2-cat-chip[aria-pressed="true"] { border: 0; background: transparent; color: var(--d2-text); font-weight: 650; }
.d2-cat-chip[aria-pressed="false"] { opacity: .55; }

@media (max-width: 1180px) {
  .d2-topbar__center input[type="search"] { width: min(240px, 24vw); }
}
@media (max-width: 960px) {
  /* 工具排 / 视图组由 JS 搬回 stage（见 syncHeaderHosts），继续走原浮层绝对定位 */
  .d2-toolbar { left: 14px; top: 68px; }
  /* 2026-10-12：视图组下移一行 —— 原 top:68 与工具排同排时，底图按钮（右对齐在
     221px 起）会盖住工具排右端的分享/标注按钮（390px 宽下实测点不到，Playwright
     命中 hit-test 失败）。工具排底 = 视口 180，故视图组取 124（stage 内）→ 视口 188。 */
  .d2-map-controls { right: 14px; top: 124px; }
  /* 容器收缩为单列；胶囊全宽（= 原移动端顶栏视觉） */
  .d2-topbar {
    left: 10px;
    right: 10px;
    max-width: none;
    grid-template-columns: 1fr;
  }
  .d2-topbar__center {
    width: 100%;
    max-width: none;
    border-radius: 12px;
  }
  .d2-topbar__center .d2-raid-host { display: none; }
  .d2-topbar__center input[type="search"] { flex: 1 1 auto; width: auto; min-width: 0; }
  /* Mobile drawers use the bottom tabs and their own close button. */
  .d2-app .d2-side-fold,
  .d2-app .d2-detail-close,
  .d2-app.d2-side-off .d2-side-unfold,
  .d2-app.d2-detail-off .d2-detail-unfold {
    display: none;
  }
}
/* ===== 2026-10-09 map3 六套主题变量 ===== */
:root {
  --d2-overlay: rgba(12, 14, 16, .84);
  --d2-card-bg: rgba(255, 255, 255, .025);
  --d2-chip-bg: rgba(255, 255, 255, .05);
  --d2-input-bg: rgba(6, 8, 10, .72);
  /* 2026-10-20 用户反馈「清爽白下左侧面板开关几乎不可见」：
     开关轨道/滑块/分隔线原先硬编码 rgba(255,255,255,.xx)（深色主题写法），
     压在白色面板上实测对比度 1.00:1（完全隐形）。改为主题变量：
       深色主题 = 白系半透明（保持原观感，零变化）
       浅色主题 = 墨蓝系半透明（白面板上清晰可见）
     --d2-switch-on 是开启态轨道色：深色主题沿用蓝色，浅色主题用更深的蓝保证 ≥3:1。 */
  --d2-switch-track: rgba(255, 255, 255, .14);
  --d2-switch-knob: rgba(255, 255, 255, .72);
  --d2-switch-knob-on: #fff;
  --d2-switch-on: rgba(96, 165, 250, .75);
  --d2-hairline: rgba(255, 255, 255, .055);
  /* 2026-10-20：开启态描边/填充。深色主题=原硬编码蓝，浅色主题=饱和蓝（白底可见） */
  --d2-on-line: rgba(96, 165, 250, .34);
  --d2-on-line-strong: rgba(96, 165, 250, .62);
  --d2-on-fill: rgba(96, 165, 250, .11);
  --d2-on-fill-soft: rgba(96, 165, 250, .035);
  --d2-on-chip-line: rgba(96, 165, 250, .55);
  --d2-on-chip-fill: rgba(96, 165, 250, .14);
  --d2-app-bg: radial-gradient(circle at 55% -20%, rgba(215, 181, 109, .12), transparent 36%), linear-gradient(180deg, #13171a 0%, #08090a 100%);
  --d2-stage-bg: linear-gradient(rgba(255,255,255,.022) 1px, transparent 1px), linear-gradient(90deg, rgba(255,255,255,.022) 1px, transparent 1px), #0b0d0f;
}
html.d2-theme-classic,
body.d2-theme-classic {
  color-scheme: light;
  --d2-bg: #eef2f6;
  --d2-panel: rgba(255, 255, 255, .96);
  --d2-panel-2: rgba(255, 255, 255, .99);
  --d2-line: rgba(15, 23, 42, .14);
  --d2-line-strong: rgba(15, 23, 42, .26);
  --d2-text: #0f172a;
  --d2-muted: #475569;
  --d2-dim: #54637a; /* R2-D9：原 #64748b 在工程图纸主题上只有 4.15:1，压深到 ≈5.5:1 */
  --d2-accent: #b45309;
  --d2-green: #15803d;
  --d2-red: #b91c1c;
  --d2-blue: #2563eb;
  --d2-cyan: #0e7490;
  --d2-violet: #7c3aed;
  --d2-overlay: rgba(255, 255, 255, .95);
  --d2-card-bg: rgba(15, 23, 42, .035);
  --d2-chip-bg: rgba(15, 23, 42, .06);
  --d2-input-bg: rgba(255, 255, 255, .88);
  --d2-app-bg: radial-gradient(circle at 55% -20%, rgba(180, 83, 9, .10), transparent 38%), linear-gradient(180deg, #f8fafc 0%, #e2e8f0 100%);
  --d2-stage-bg: linear-gradient(rgba(15,23,42,.045) 1px, transparent 1px), linear-gradient(90deg, rgba(15,23,42,.045) 1px, transparent 1px), #eef2f6;
  /* 2026-10-20：浅色面板上的开关，改用墨蓝系半透明（原白色叠白不可见） */
  --d2-switch-track: rgba(15, 23, 42, .55);
  --d2-switch-knob: #fff;
  --d2-switch-knob-on: #fff;
  --d2-switch-on: #2563eb;
  --d2-hairline: rgba(15, 23, 42, .10);
  --d2-on-line: rgba(37, 99, 235, .42);
  --d2-on-line-strong: rgba(37, 99, 235, .68);
  --d2-on-fill: rgba(37, 99, 235, .10);
  --d2-on-fill-soft: rgba(37, 99, 235, .035);
  --d2-on-chip-line: rgba(37, 99, 235, .55);
  --d2-on-chip-fill: rgba(37, 99, 235, .12);
}
html.d2-theme-military,
body.d2-theme-military {
  --d2-bg: #0f130d;
  --d2-panel: rgba(22, 27, 19, .95);
  --d2-panel-2: rgba(28, 34, 24, .98);
  --d2-line: rgba(229, 224, 212, .16);
  --d2-line-strong: rgba(229, 224, 212, .28);
  --d2-text: #f3efe4;
  --d2-muted: #b2ad9f;
  --d2-dim: #8f8a80;
  --d2-accent: #d7b56d;
  --d2-green: #79d78e;
  --d2-red: #f36f63;
  --d2-blue: #68a8f4;
  --d2-cyan: #5cd2d8;
  --d2-violet: #b890ff;
  --d2-overlay: rgba(18, 23, 16, .88);
  --d2-card-bg: rgba(255, 255, 255, .035);
  --d2-chip-bg: rgba(255, 255, 255, .06);
  --d2-input-bg: rgba(6, 8, 10, .72);
  --d2-app-bg: radial-gradient(circle at 55% -20%, rgba(215, 181, 109, .13), transparent 36%), linear-gradient(180deg, #171c14 0%, #090b08 100%);
  --d2-stage-bg: linear-gradient(rgba(255,255,255,.022) 1px, transparent 1px), linear-gradient(90deg, rgba(255,255,255,.022) 1px, transparent 1px), #0b0d09;
}
html.d2-theme-night,
body.d2-theme-night {
  --d2-bg: #020705;
  --d2-panel: rgba(4, 14, 10, .96);
  --d2-panel-2: rgba(5, 19, 13, .98);
  --d2-line: rgba(104, 255, 166, .18);
  --d2-line-strong: rgba(104, 255, 166, .32);
  --d2-text: #d9ffe8;
  --d2-muted: #7fd7a2;
  --d2-dim: #5aa879;
  --d2-accent: #68ffa6;
  --d2-green: #68ffa6;
  --d2-red: #ff7b72;
  --d2-blue: #63d9ff;
  --d2-cyan: #63ffd7;
  --d2-violet: #b7a4ff;
  --d2-overlay: rgba(3, 12, 8, .90);
  --d2-card-bg: rgba(104, 255, 166, .04);
  --d2-chip-bg: rgba(104, 255, 166, .07);
  --d2-input-bg: rgba(2, 8, 5, .78);
  --d2-app-bg: radial-gradient(circle at 55% -20%, rgba(104, 255, 166, .10), transparent 36%), linear-gradient(180deg, #06100c 0%, #010403 100%);
  --d2-stage-bg: linear-gradient(rgba(104,255,166,.025) 1px, transparent 1px), linear-gradient(90deg, rgba(104,255,166,.025) 1px, transparent 1px), #020705;
}
html.d2-theme-cyber,
body.d2-theme-cyber {
  --d2-bg: #070b1a;
  --d2-panel: rgba(12, 18, 38, .96);
  --d2-panel-2: rgba(16, 24, 50, .98);
  --d2-line: rgba(99, 179, 255, .18);
  --d2-line-strong: rgba(99, 179, 255, .34);
  --d2-text: #e8f1ff;
  --d2-muted: #9bb6df;
  --d2-dim: #718bb5;
  --d2-accent: #5ce1ff;
  --d2-green: #6fffd2;
  --d2-red: #ff6b8a;
  --d2-blue: #6aa8ff;
  --d2-cyan: #5ce1ff;
  --d2-violet: #b28cff;
  --d2-overlay: rgba(8, 13, 30, .90);
  --d2-card-bg: rgba(92, 225, 255, .045);
  --d2-chip-bg: rgba(92, 225, 255, .08);
  --d2-input-bg: rgba(5, 9, 22, .78);
  --d2-app-bg: radial-gradient(circle at 55% -20%, rgba(92, 225, 255, .12), transparent 38%), linear-gradient(180deg, #0c1226 0%, #050816 100%);
  --d2-stage-bg: linear-gradient(rgba(92,225,255,.025) 1px, transparent 1px), linear-gradient(90deg, rgba(92,225,255,.025) 1px, transparent 1px), #070b1a;
}
html.d2-theme-blueprint,
body.d2-theme-blueprint {
  color-scheme: light;
  --d2-bg: #e8eefc;
  --d2-panel: rgba(255, 255, 255, .97);
  --d2-panel-2: rgba(255, 255, 255, .99);
  --d2-line: rgba(30, 64, 175, .18);
  --d2-line-strong: rgba(30, 64, 175, .32);
  --d2-text: #10214f;
  --d2-muted: #4b5f92;
  --d2-dim: #5e6d96; /* R2-D11：原 #6b7ba8 在工程图纸主题上只有 4.15:1，压深到 5.08:1 */
  --d2-accent: #1d4ed8;
  --d2-green: #047857;
  --d2-red: #b91c1c;
  --d2-blue: #1d4ed8;
  --d2-cyan: #0369a1;
  --d2-violet: #6d28d9;
  --d2-overlay: rgba(248, 250, 255, .96);
  --d2-card-bg: rgba(29, 78, 216, .045);
  --d2-chip-bg: rgba(29, 78, 216, .08);
  --d2-input-bg: rgba(255, 255, 255, .90);
  --d2-app-bg: radial-gradient(circle at 55% -20%, rgba(29, 78, 216, .12), transparent 38%), linear-gradient(180deg, #f4f7ff 0%, #dbe5ff 100%);
  --d2-stage-bg: linear-gradient(rgba(29,78,216,.05) 1px, transparent 1px), linear-gradient(90deg, rgba(29,78,216,.05) 1px, transparent 1px), #e8eefc;
  /* 2026-10-20：浅色面板上的开关，改用墨蓝系半透明（原白色叠白不可见） */
  --d2-switch-track: rgba(30, 64, 175, .56);
  --d2-switch-knob: #fff;
  --d2-switch-knob-on: #fff;
  --d2-switch-on: #1d4ed8;
  --d2-hairline: rgba(30, 64, 175, .12);
  --d2-on-line: rgba(29, 78, 216, .44);
  --d2-on-line-strong: rgba(29, 78, 216, .70);
  --d2-on-fill: rgba(29, 78, 216, .10);
  --d2-on-fill-soft: rgba(29, 78, 216, .035);
  --d2-on-chip-line: rgba(29, 78, 216, .55);
  --d2-on-chip-fill: rgba(29, 78, 216, .12);
}
html.d2-theme-amber,
body.d2-theme-amber {
  --d2-bg: #160f07;
  --d2-panel: rgba(33, 24, 13, .96);
  --d2-panel-2: rgba(42, 30, 16, .98);
  --d2-line: rgba(255, 190, 92, .18);
  --d2-line-strong: rgba(255, 190, 92, .34);
  --d2-text: #ffe8bd;
  --d2-muted: #d0a76a;
  --d2-dim: #a98450;
  --d2-accent: #ffb84d;
  --d2-green: #9bd97a;
  --d2-red: #ff7a5c;
  --d2-blue: #7bb7ff;
  --d2-cyan: #6fe3d5;
  --d2-violet: #c6a2ff;
  --d2-overlay: rgba(26, 18, 9, .90);
  --d2-card-bg: rgba(255, 184, 77, .045);
  --d2-chip-bg: rgba(255, 184, 77, .08);
  --d2-input-bg: rgba(14, 9, 4, .78);
  --d2-app-bg: radial-gradient(circle at 55% -20%, rgba(255, 184, 77, .12), transparent 38%), linear-gradient(180deg, #201a11 0%, #0e0904 100%);
  --d2-stage-bg: linear-gradient(rgba(255,184,77,.025) 1px, transparent 1px), linear-gradient(90deg, rgba(255,184,77,.025) 1px, transparent 1px), #160f07;
}

.d2-app { background: var(--d2-app-bg); }
.d2-stage { background: var(--d2-stage-bg); }
.d2-side, .d2-detail { background: var(--d2-panel); }
.d2-toolbar, .d2-basemap-toggle, .d2-topbar__center, .d2-raid-chip, .d2-reset, .d2-tilebar,
.d2-side-fold, .d2-side-unfold, .d2-detail-close, .d2-detail-unfold { background: var(--d2-overlay); }
.d2-cat-group { background: var(--d2-card-bg); }
.d2-theme__btn { background: var(--d2-chip-bg); }
.d2-theme__menu { background: var(--d2-panel-2); }
.d2-tilebar button { background: var(--d2-chip-bg); }
.d2-topbar__center input[type="search"] { background: transparent; }
/* ============================================================================
   地图内「物资点位」弹窗（2026-10-11 用户口径）
   任务 / 撤离点点击后仍在右侧详情面板；普通物资（容器 / 散落物资）点击后
   直接在地图内弹出本弹窗：多物品出多个图标、单物品出单个图标，
   点图标进对应物品内页，悬停 / 聚焦时即时浮出名称，不改变弹窗尺寸。
   ⚠️ 弹窗放在 .d2-viewport 内、.d2-canvas 之外 —— 不随地图缩放；
      位置由 ditu2.js 的 positionLootPop() 用「点位坐标 × scale + 平移」换算。
   ========================================================================== */
.d2-lootpop {
  position: absolute;
  z-index: 60;
  width: max-content;
  max-width: min(320px, 74vw);
  padding: 8px;
  background: var(--d2-panel);
  border: 1px solid var(--d2-line-strong);
  border-radius: var(--d2-radius);
  box-shadow: var(--d2-shadow);
  /* 默认落在锚点上方；空间不足时 JS 加 .is-below 翻到下方 */
  transform: translate(-50%, calc(-100% - 14px));
}

.d2-lootpop.is-below {
  transform: translate(-50%, 14px);
}

.d2-lootpop[hidden] {
  display: none;
}

.d2-lootpop__grid {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  max-height: 232px;
  overflow: auto;
  overscroll-behavior: contain;
}

.d2-lootpop__cell {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  flex: 0 0 auto;
  padding: 0;
  border-radius: 6px;
  text-decoration: none;
  color: inherit;
}

.d2-lootpop__cell:hover,
.d2-lootpop__cell:focus-visible {
  background: var(--d2-panel-2);
  outline: none;
}

.d2-lootpop__cell--plain {
  cursor: default;
}

.d2-lootpop__cell img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}

/* 与弹窗同处 viewport，避开滚动网格裁切和弹窗的 transform。 */
.d2-loot-tooltip {
  position: absolute;
  z-index: 61;
  width: max-content;
  max-width: calc(100% - 12px);
  padding: 5px 8px;
  border: 1px solid var(--d2-line-strong);
  border-radius: 6px;
  background: var(--d2-panel);
  box-shadow: var(--d2-shadow);
  color: var(--d2-text);
  font-size: 13px;
  line-height: 1.4;
  overflow-wrap: anywhere;
  pointer-events: none;
}

.d2-loot-tooltip[hidden] {
  display: none;
}

/* ======================================================================
   2026-10-11 用户指令：物资埋藏桶 / 物资埋藏箱（参考版式的「彩蛋」）照片弹窗。
   形态照参考版式做：标题「彩蛋」+ 关闭按钮，下面是照片卡片；悬停卡片出现
   深色遮罩 +「放大」提示，点图打开站内图片查看器（openPhotoLightbox）。
   与 .d2-lootpop 同一套定位方式（锚在点位上、空间不足翻到下方）。
   ====================================================================== */
.d2-eggpop {
  position: absolute;
  z-index: 62;
  width: 366px;
  max-width: min(366px, 82vw);
  background: var(--d2-panel);
  border: 1px solid var(--d2-line-strong);
  border-radius: var(--d2-radius);
  box-shadow: var(--d2-shadow);
  overflow: hidden;
  transform: translate(-50%, calc(-100% - 14px));
}

.d2-eggpop.is-below { transform: translate(-50%, 14px); }
.d2-eggpop[hidden] { display: none; }

.d2-eggpop__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 8px 8px 8px 12px;
  border-bottom: 1px solid var(--d2-line);
}

.d2-eggpop__title {
  margin: 0;
  font-size: 14px;
  font-weight: 700;
  color: var(--d2-text);
}

.d2-eggpop__close {
  flex: 0 0 auto;
  width: 28px;
  height: 28px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 0;
  border-radius: 6px;
  background: transparent;
  color: var(--d2-muted);
  font: inherit;
  font-size: 17px;
  line-height: 1;
  cursor: pointer;
}

.d2-eggpop__close:hover { color: var(--d2-text); background: var(--d2-panel-2); }

.d2-eggpop__body { padding: 8px; }

.d2-eggpop__shot {
  position: relative;
  display: block;
  width: 100%;
  padding: 0;
  border: 1px solid var(--d2-line);
  border-radius: 8px;
  background: rgba(0, 0, 0, .28);
  overflow: hidden;
  cursor: pointer;
}

.d2-eggpop__shot:hover { border-color: var(--d2-on-chip-line, rgba(96, 165, 250, .55)); }
/* ⚠️ .d2-eggpop__shot 显式写了 display:block，会盖掉 [hidden] 的 display:none —— 必须补这条 */
.d2-eggpop__shot[hidden] { display: none; }
.d2-eggpop__shot img { display: block; width: 100%; height: auto; }

.d2-eggpop__zoom {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0);
  color: #dbeafe;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: .04em;
  opacity: 0;
  transition: opacity .15s, background .15s;
  pointer-events: none;
}

.d2-eggpop__shot:hover .d2-eggpop__zoom,
.d2-eggpop__shot:focus-visible .d2-eggpop__zoom {
  opacity: 1;
  background: rgba(0, 0, 0, .38);
}

/* 2026-10-11 用户指令：参考版式没有彩蛋的图 → 埋藏桶/箱没有照片，弹这个占位
   （而不是「点了没反应」）。高度与照片卡片接近，避免弹窗高度跳变。 */
.d2-eggpop__empty {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 150px;
  border: 1px dashed var(--d2-line-strong);
  border-radius: 8px;
  background: rgba(0, 0, 0, .18);
  color: var(--d2-muted);
  font-size: 14px;
  letter-spacing: .04em;
}

.d2-eggpop__empty[hidden] { display: none; }

/* ======================================================================
   2026-10-12 顶部三段布局（用户校正版）：wide / stack 两态
   ======================================================================
   用户原话：「放大缩小那一排按钮往上移动，放到和搜索框同一排，抽象图/卫星图
   切换按钮以及楼层切换按钮也一样往上移，不然上方为何空着？」
   后续校正：「我没让你改动中间的时间，也没让你做成一整排，只是让你放在同一个高度」。
   现状 = 三段「同一高度」的独立组：
     wide（宽度足够）  [工具排] ······ [对局胶囊] ······ [视图组]   左中右分散、同高；
     stack（宽度不足） [对局胶囊] 独占第一行居中，
                       [工具排] ······ [视图组] 第二行分列两端。
   对局胶囊（时钟 + 搜索 + 主题）与工具排 / 视图组均为独立胶囊、互不串联；
   楼层与底图横排（不再独占第三行）。≤960 移动端本块不参与：工具排/视图组由
   syncHeaderHosts() 搬回 stage，继续走原浮层定位（与改动前一致）。 */
@media (min-width: 961px) {
  /* 工具排 / 视图组进容器网格（覆盖基础段的浮层绝对定位） */
  .d2-topbar .d2-toolbar,
  .d2-topbar .d2-map-controls {
    position: static;
    top: auto;
    left: auto;
    right: auto;
    z-index: auto;
  }
  .d2-topbar .d2-toolbar { justify-self: start; flex-shrink: 0; }
  /* 视图组：底图 + 楼层 + 主题横排，**恒单行不换行**。
     ⚠️ 这是「一个高一个低」的根因修复（2026-10-13）：本块此前没有覆盖基础段的
     flex-wrap:wrap，视图组在列宽不足时会折成 2~3 行（实测 96 / 136px 高），
     而网格 align-items:center 把 44px 高的工具排居中到这一更高的行里 ——
     结果底图/卫星图偏高、楼层/主题偏低、工具排夹在中间（1920 档更严重：
     视图组右溢出视口，「军事终端」被裁掉）。
     现在整组恒 44px：楼层条自身 overflow-x:auto 横滚兜底，不换行、不溢出。 */
  .d2-topbar .d2-map-controls {
    display: flex;
    flex-direction: row;
    flex-wrap: nowrap;
    align-items: center;
    justify-self: end;
    flex-shrink: 0;
    min-width: 0;
    gap: 8px;
    /* 关键：钳到**网格列宽**（百分比按 grid area 解析）。justify-self:end 的
       grid item 宽度是 fit-content，实测不会自动被列宽夹住 —— 不加这条，
       stack 档视图组会向左溢出并压住工具排（实测 527 > 列宽 420，重叠 91px）。 */
    max-width: 100%;
  }
  .d2-topbar .d2-basemap-toggle { flex-shrink: 0; }
  .d2-topbar .d2-tilebar {
    flex: 0 1 auto;
    min-width: 0;
    flex-wrap: nowrap;
    /* 覆盖基础段的 justify-content:flex-end —— flex-end 下内容向**左**溢出，
       而左侧溢出是不可滚动的（会被永久裁掉、点不到）；flex-start 下向右溢出，
       至少还能用横向滚动 / shift+滚轮够到。不被压窄时该属性无效果（无剩余空间）。 */
    justify-content: flex-start;
    overflow-x: auto;
    scrollbar-width: none;
  }
  .d2-topbar .d2-tilebar::-webkit-scrollbar { display: none; }
  /* 楼层/图层按钮不参与收缩：被压窄时让整条横滚（按钮保持原尺寸、文字不被裁），
     而不是把按钮挤成 0 宽 —— 后者实测会把「全部/2层」压没、还读不到内容宽
     （scrollWidth 恒等于 clientWidth，判档拿不到自然宽）。 */
  .d2-topbar .d2-tilebar > * { flex-shrink: 0; }
  /* split / tall：视图组独占整行 → 楼层条允许换行（破冰船 17 项、储备站等超长
     列表不再被裁掉）。共享行（wide / stack）时**不能**换行：整组一变高就会
     与工具排错位，正是用户报的「一个高一个低」。 */
  .d2-topbar[data-band="split"] .d2-tilebar,
  .d2-topbar[data-band="tall"] .d2-tilebar { flex-wrap: wrap; }

  /* wide：三段同行 —— 工具排左、视图组右、搜索胶囊居中于二者之间的剩余空间。
     基础段的 grid-template-columns:1fr auto 1fr 要求两侧列**等宽**，而视图组
     （~539）远宽于工具排（~280）：等宽列放不下右侧 → 视图组被挤成两行并右溢出。
     改用 auto minmax(0,1fr) auto：两侧按内容取宽，中间 1fr 交给胶囊居中。 */
  .d2-topbar[data-band="wide"] { grid-template-columns: auto minmax(0, 1fr) auto; }
  .d2-topbar[data-band="wide"] .d2-toolbar { grid-row: 1; grid-column: 1; }
  .d2-topbar[data-band="wide"] .d2-topbar__center { grid-row: 1; grid-column: 2; }
  .d2-topbar[data-band="wide"] .d2-map-controls { grid-row: 1; grid-column: 3; }

  /* stack：胶囊独占第一行居中；工具排与视图组同行分列两端（同高 44px）。
     列改成 auto + minmax(0,1fr)：视图组吃剩余宽度、超长由楼层条内部横滚吸收。
     旧的 100vw 硬上限已删除 —— 它在 1280 档算出 252px，把楼层条压成 0 宽；
     列宽收缩现在由网格轨道完成，不需要手算。
     ⚠️ 本档仅在「视图组能整宽放进第二行」时启用（见 syncBandLayout）：楼层条
     按钮是 flex-shrink:1，被压窄时不是出现滚动条，而是按钮自身被压扁、文字被裁
     （实测 1440 档「全部/2层」挤成 0 宽）。所以窄到放不下时改走 split 档。 */
  .d2-topbar[data-band="stack"] { grid-template-columns: auto minmax(0, 1fr); }
  .d2-topbar[data-band="stack"] .d2-topbar__center { grid-row: 1; grid-column: 1 / 3; }
  .d2-topbar[data-band="stack"] .d2-toolbar { grid-row: 2; grid-column: 1; }
  .d2-topbar[data-band="stack"] .d2-map-controls { grid-row: 2; grid-column: 2; }

  /* split：视图组放不下「与工具排同行」，但能整行独占（1440 / 1366 等常见笔记本宽）——
     第一行 = 工具排 + 搜索胶囊（用户口径：放大缩小那一排要和搜索框同一排），
     第二行 = 视图组整行独占 → 底图 / 楼层 / 主题全部完整可见，楼层条不被压扁。 */
  .d2-topbar[data-band="split"] { grid-template-columns: auto minmax(0, 1fr); }
  .d2-topbar[data-band="split"] .d2-toolbar { grid-row: 1; grid-column: 1; }
  .d2-topbar[data-band="split"] .d2-topbar__center { grid-row: 1; grid-column: 2; }
  .d2-topbar[data-band="split"] .d2-map-controls { grid-row: 2; grid-column: 1 / 3; }

  /* tall：第二行连「工具排 + 视图组」也放不下（窄桌面 / 破冰船等超长楼层条）——
     工具排与视图组各占一行，视图组整行独占（整行宽已够，超长仍由楼层条内部横滚兜底）。 */
  .d2-topbar[data-band="tall"] { grid-template-columns: minmax(0, 1fr); }
  .d2-topbar[data-band="tall"] .d2-topbar__center { grid-row: 1; grid-column: 1; }
  .d2-topbar[data-band="tall"] .d2-toolbar { grid-row: 2; grid-column: 1; }
  .d2-topbar[data-band="tall"] .d2-map-controls { grid-row: 3; grid-column: 1; }
}

/* ======================================================================
   2026-10-12 标注画板（用户指令）：点工具排 ✎ 从工具排下方「往下展开」
   v2（同日）：工具对齐 /map2/ 标注套件并增强（9 工具 / 6 色 / 3 粗细 / 虚线 /
   撤销重做 / 导出图片）；文字输入行走内联输入行（不用 window.prompt）。
   ====================================================================== */
.d2-drawboard {
  position: fixed; /* 视口坐标（positionDrawboard 量出 top/left） */
  z-index: 96;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 8px;
  padding: 6px 8px;
  border: 1px solid var(--d2-line);
  border-radius: 12px;
  background: var(--d2-overlay);
  box-shadow: var(--d2-shadow);
  backdrop-filter: blur(14px);
  max-width: min(1120px, calc(100vw - 20px));
}
.d2-drawboard[hidden] { display: none; }
/* 组内也允许换行：窄屏（手机）单个组超宽时在组内折行，而不是整组溢出画板边界
   （2026-10-12 移动端实测：9 个工具按钮的组在 376px 画板里溢出，「橡皮」被裁切） */
.d2-db-group { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; }
.d2-db-btn {
  display: inline-grid;
  place-items: center;
  height: 30px;
  min-width: 30px;
  padding: 0 8px;
  border: 1px solid transparent;
  border-radius: 6px;
  background: var(--d2-chip-bg);
  color: var(--d2-text);
  cursor: pointer;
  font-size: 12px;
  line-height: 1;
  white-space: nowrap;
}
.d2-db-btn:hover { border-color: rgba(215, 181, 109, .48); }
.d2-db-btn.is-on { border-color: rgba(215, 181, 109, .72); background: rgba(215, 181, 109, .18); }
.d2-db-btn.is-arm { border-color: rgba(239, 68, 68, .72); background: rgba(239, 68, 68, .16); color: #fca5a5; }
/* 撤销 / 重做无内容可操作时置灰（点击仍是安全 no-op） */
.d2-db-btn.is-off { opacity: .42; cursor: default; }
.d2-db-btn.is-off:hover { border-color: transparent; }
/* 导出图片是画板的收口动作：暖色强调 */
.d2-db-btn--export {
  border-color: rgba(215, 181, 109, .55);
  background: rgba(215, 181, 109, .14);
  font-weight: 600;
}
.d2-db-btn--w { min-width: 28px; padding: 0 6px; }
/* 「收条」按钮（v8.4）：展开态回迷你条的入口，仅移动端显示 */
.d2-db-btn--fold { display: none; }
@media (max-width: 960px) {
  .d2-db-btn--fold { display: inline-block; }
}
/* 工具排标注按钮的文字标签（v8.2）：桌面显示、窄屏/移动端保持纯图标紧凑 */
.d2-tool__lab { display: inline; line-height: 1; margin-left: 0; font-size: 13px; letter-spacing: 2px; }
/* 移动端画板折叠迷你条（v8.2）：≤960 且 [data-folded] 时只显示迷你条 */
.d2-db-mini { display: none; align-items: center; gap: 8px; width: 100%; }
.d2-db-mini__tool {
  min-width: 44px;
  text-align: center;
  color: var(--d2-text, #e5e0d4);
  font-size: 13px;
  font-weight: 700;
  white-space: nowrap;
}
.d2-db-mini__dot {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--db, #3b82f6);
  border: 2px solid rgba(255, 255, 255, .35);
  flex: 0 0 auto;
}
.d2-db-mini .d2-db-btn { margin-left: auto; }
.d2-db-mini .d2-db-btn + .d2-db-btn { margin-left: 0; }
@media (max-width: 960px) {
  .d2-drawboard[data-folded] > :not(.d2-db-mini) { display: none !important; }
  .d2-drawboard[data-folded] .d2-db-mini { display: flex; }
  .d2-drawboard[data-folded] { padding: 5px 8px; }
}
/* 标注清单面板（v8.2）：画板下方浮层 */
.d2-db-listpanel {
  position: fixed;
  z-index: 96;
  max-height: 340px;
  overflow-y: auto;
  padding: 8px 10px;
  border: 1px solid var(--d2-line);
  border-radius: 12px;
  background: var(--d2-overlay);
  box-shadow: var(--d2-shadow);
  backdrop-filter: blur(14px);
}
.d2-db-listpanel[hidden] { display: none; }
.d2-dbl__head { margin: 0 0 6px; color: var(--d2-muted, #8a8776); font-size: 11px; }
.d2-dbl__empty { margin: 4px 0; color: var(--d2-muted, #8a8776); font-size: 12px; }
.d2-dbl__row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 5px 4px;
  border-top: 1px solid var(--d2-hairline);
}
.d2-dbl__dot { width: 12px; height: 12px; border-radius: 50%; flex: 0 0 auto; border: 1px solid rgba(255, 255, 255, .3); }
.d2-dbl__sum {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--d2-text, #e5e0d4);
  font-size: 12px;
}
.d2-dbl__go, .d2-dbl__del {
  flex: 0 0 auto;
  padding: 2px 8px;
  border: 1px solid var(--d2-line, rgba(255, 255, 255, .14));
  border-radius: 6px;
  background: transparent;
  color: var(--d2-text, #e5e0d4);
  font-size: 11px;
  cursor: pointer;
}
.d2-dbl__del:hover { border-color: rgba(239, 68, 68, .6); color: #fca5a5; }
.d2-dbl__go:hover { border-color: rgba(215, 181, 109, .6); }
/* 编号起始输入行（v8.3）：仅编号工具激活时显示 */
.d2-db-numstart {
  flex-basis: 100%;
  display: flex;
  align-items: center;
  gap: 8px;
}
.d2-db-numstart[hidden] { display: none; }
.d2-db-numstart label { color: var(--d2-muted, #8a8776); font-size: 11px; white-space: nowrap; }
.d2-db-numstart input {
  width: 64px;
  height: 28px;
  padding: 0 8px;
  border: 1px solid var(--d2-line);
  border-radius: 6px;
  background: rgba(0, 0, 0, .35);
  color: var(--d2-text, #e5e0d4);
  font-size: 13px;
  outline: none;
}
.d2-db-numstart input:focus { border-color: rgba(215, 181, 109, .62); }
.d2-db-hint2 { color: var(--d2-muted, #8a8776); font-size: 11px; white-space: nowrap; }
/* 箭头款式条（v8.6）：箭头工具激活时出现在按钮下方 */
.d2-db-arrowstyles {
  flex-basis: 100%;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
}
.d2-db-arrowstyles[hidden] { display: none; }
.d2-db-astyle {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 9px;
  border: 1px solid var(--d2-line, rgba(255, 255, 255, .14));
  border-radius: 7px;
  background: transparent;
  color: var(--d2-text, #e5e0d4);
  font-size: 11px;
  cursor: pointer;
}
.d2-db-astyle:hover { border-color: rgba(215, 181, 109, .55); }
.d2-db-astyle.is-on { border-color: rgba(215, 181, 109, .8); background: rgba(215, 181, 109, .14); color: #ecd9ac; }
/* 图标选择条（2026-10-15）：图标工具激活时显示，复用地图点位图标 */
.d2-db-icons {
  flex-basis: 100%;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px;
  max-height: 112px;
  overflow-y: auto;
  padding: 1px 0;
}
.d2-db-icons[hidden] { display: none; }
.d2-db-icon {
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  padding: 3px;
  border: 1px solid var(--d2-line, rgba(255, 255, 255, .14));
  border-radius: 7px;
  background: var(--d2-chip-bg);
  cursor: pointer;
}
.d2-db-icon:hover { border-color: rgba(215, 181, 109, .55); background: var(--d2-chip-bg); }
.d2-db-icon.is-on { border-color: rgba(215, 181, 109, .8); background: rgba(215, 181, 109, .16); box-shadow: 0 0 0 1px rgba(215, 181, 109, .25) inset; }
.d2-db-icon img { display: block; width: 22px; height: 22px; object-fit: contain; }
/* 图标工具不适用颜色 / 虚线 / 填充：隐藏无关控件，保留大小滑块 */
.d2-drawboard[data-tool="icon"] .d2-db-colors,
.d2-drawboard[data-tool="icon"] [data-draw-dash],
.d2-drawboard[data-tool="icon"] [data-draw-fill] { display: none; }
/* 字体条（v8.6）：文字工具激活时靠右显示 */
.d2-db-fonts {
  flex-basis: 100%;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 6px;
}
.d2-db-fonts[hidden] { display: none; }
.d2-db-font {
  padding: 3px 12px;
  border: 1px solid var(--d2-line, rgba(255, 255, 255, .14));
  border-radius: 7px;
  background: transparent;
  color: var(--d2-text, #e5e0d4);
  font-size: 13px;
  cursor: pointer;
}
.d2-db-font:hover { border-color: rgba(215, 181, 109, .55); }
.d2-db-font.is-on { border-color: rgba(215, 181, 109, .8); background: rgba(215, 181, 109, .14); color: #ecd9ac; }
/* 导出预览浮层（v8.3） */
.d2-export-preview {
  position: fixed;
  inset: 0;
  z-index: 2000; /* 站壳 header 是 sticky 且 z 很高——浮层整体压过它 */
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  padding: 72px 14px 14px; /* 顶部给站壳 header 让位 */
  background: rgba(0, 0, 0, .78);
  backdrop-filter: blur(3px);
}
.d2-export-preview[hidden] { display: none; }
.d2-ep__bar {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 14px;
  border: 1px solid var(--d2-line, rgba(255, 255, 255, .14));
  border-radius: 10px;
  background: var(--d2-overlay, rgba(12, 15, 18, .92));
}
.d2-ep__title { color: var(--d2-text, #e5e0d4); font-size: 13px; max-width: 52vw; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.d2-ep__btn {
  padding: 4px 14px;
  border: 1px solid rgba(215, 181, 109, .55);
  border-radius: 8px;
  background: rgba(215, 181, 109, .12);
  color: #ecd9ac;
  font-size: 13px;
  cursor: pointer;
}
.d2-ep__btn:hover { background: rgba(215, 181, 109, .24); }
.d2-ep__img {
  max-width: 92vw;
  max-height: calc(100vh - 110px);
  object-fit: contain;
  border: 1px solid var(--d2-line-strong);
  border-radius: 6px;
  background: #0b0e11;
}
/* 粗细滑块（v8，替代细/中粗三按钮）：accent-color 跟主题金色，范围 1~16 */
.d2-db-slider input[type="range"] {
  width: 110px;
  height: 22px;
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  accent-color: #d7b56d;
  cursor: pointer;
}
.d2-db-slider input[type="range"]:focus-visible { outline: 1px solid rgba(215, 181, 109, .6); outline-offset: 2px; }
.d2-db-lab { color: var(--d2-muted, #8a8776); font-size: 11px; white-space: nowrap; }
.d2-db-wout {
  min-width: 14px;
  text-align: center;
  color: var(--d2-text, #e5e0d4);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
}
/* 导出按钮 + 下拉箭头 = 一个分裂按钮（主点击 = 整图导出，箭头 = 更多导出方式） */
.d2-db-split { display: inline-flex; align-items: center; }
.d2-db-split .d2-db-btn--export { border-top-right-radius: 0; border-bottom-right-radius: 0; }
.d2-db-btn--caret {
  min-width: 20px;
  padding: 0 4px;
  margin-left: -1px;
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
}
/* 导出选项菜单（画板子元素，随画板 fixed 定位；点空白 / Esc 收起） */
.d2-db-menu {
  position: absolute;
  top: calc(100% + 6px);
  right: 8px;
  z-index: 97;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 210px;
  padding: 6px;
  border: 1px solid var(--d2-line);
  border-radius: 10px;
  background: var(--d2-overlay);
  box-shadow: var(--d2-shadow);
  backdrop-filter: blur(14px);
}
.d2-db-menu[hidden] { display: none; }
.d2-db-menu button {
  padding: 8px 10px;
  text-align: left;
  border: 1px solid transparent;
  border-radius: 6px;
  background: transparent;
  color: var(--d2-text);
  font-size: 12px;
  line-height: 1.2;
  cursor: pointer;
  white-space: nowrap;
}
.d2-db-menu button:hover { border-color: rgba(215, 181, 109, .48); background: var(--d2-chip-bg); }
.d2-db-color {
  width: 22px;
  height: 22px;
  padding: 0;
  border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, .3);
  background: var(--db, #3b82f6);
  cursor: pointer;
}
.d2-db-color.is-on { border-color: #fff; box-shadow: 0 0 0 2px rgba(0, 0, 0, .38); }
.d2-db-hint { margin: 0 2px; color: var(--d2-muted); font-size: 11px; white-space: nowrap; }
/* 文字标注输入框（v3）：直接浮在地图落点上（图内所见即所得），fixed 定位由
   positionTextEditor() 量出；字号 = 目标文字字号（屏幕上恒定 px）、颜色即时跟随当前色。 */
.d2-db-text {
  position: fixed;
  z-index: 98;
  transform: translate(-50%, -50%);
}
.d2-db-text[hidden] { display: none; }
.d2-db-text input {
  width: 120px;
  padding: 1px 8px;
  border: 1px solid rgba(215, 181, 109, .6);
  border-radius: 6px;
  background: rgba(8, 11, 14, .82);
  color: #e5e0d4;
  font-family: inherit;
  font-weight: 700;
  outline: none;
  box-shadow: 0 2px 10px rgba(0, 0, 0, .5);
}
.d2-db-text input::placeholder { color: rgba(255, 255, 255, .38); font-weight: 400; }
.d2-db-text input:focus { border-color: rgba(255, 240, 202, .92); }
/* 绘制层（标注）宿主 = .d2-viewport 内、**标记层之后**（JS applyTransform 维持次序与变换）。
   ★z-index: 40 —— 烘焙态（闲置 160ms 后标记层 transform:none）下点位标记的 z-index
   1/6/30 直接参与视口堆叠上下文；标注层若停留在 .d2-canvas 里（canvas z:auto），
   永远被点位 / 地标名压住（用户报障的根因，v3 搬出 canvas 修正）。
   40 > 点位最高 30；弹出层（lootpop z60 / eggpop z62）仍在标注之上。
   ★transform-origin 必须与画布一致（0 0）——否则跟随态相对画布整体偏移（与标记层同一个坑）。 */
.d2-draw-layer { position: absolute; left: 0; top: 0; z-index: 40; transform-origin: 0 0; pointer-events: none; overflow: visible; }
/* 线宽 / 虚线 / 圆点 / 文字字号 = 随地图缩放（map-lock，v6）：
   SVG 与画布 1:1，外层 .d2-canvas 的 scale 会把几何与描边一起放大 —— 每条笔迹的
   --d2-draw-inv = 1/sref（创建时的地图缩放，由 renderStrokes 的外层 <g> 注入），
   描边类属性乘它 → 放大地图时字/线一起放大，就像画在地图上（绘制时所见即最终尺寸）。
   图层层级的 --d2-draw-inv = 1/scale（applyTransform 写入）只服务选区框/手柄等
   操作 UI（恒定屏幕像素）。元素上的属性值作兜底（不支持 calc 变量时退回）。 */
.d2-draw-layer [data-stroke] { stroke-width: calc(var(--sw, 3) * 1px * var(--d2-draw-inv, 1)); }
.d2-draw-layer [data-stroke].is-dash {
  stroke-dasharray: calc(var(--sw, 3) * 2.4px * var(--d2-draw-inv, 1)) calc(var(--sw, 3) * 1.7px * var(--d2-draw-inv, 1));
}
.d2-draw-layer circle[data-dot] { r: calc(var(--sw, 3) * 1px * var(--d2-draw-inv, 1) * var(--rf, 1.12)); }
/* 编号圆：半径 --nr（随图缩放，走 1/sref）；圈线走 --sw（与 [data-stroke] 通用规则一致） */
.d2-draw-layer circle[data-num] { r: calc(var(--nr, 15) * 1px * var(--d2-draw-inv, 1)); }
.d2-draw-layer image[data-icon] { filter: drop-shadow(0 1px 2px rgba(0, 0, 0, .75)); pointer-events: none; }
.d2-draw-layer circle[data-icon-badge] { pointer-events: none; }
.d2-draw-layer text.d2-numt {
  font-size: calc(var(--tf, 17px) * var(--d2-draw-inv, 1));
  font-weight: 800;
  text-anchor: middle;
  dominant-baseline: central;
  user-select: none;
}
/* 隐藏全部标注（看 / 导出干净底图；导出跟随此开关） */
.d2-draw-layer.is-hidden { display: none; }
/* 选中选框 + 圆点手柄（编辑 / 文字工具；r 与描边走 1/scale 抵消 = 恒定屏幕像素） */
.d2-draw-layer .d2-selbox {
  fill: none;
  stroke: rgba(255, 240, 202, .92);
  stroke-width: calc(1.5px * var(--d2-draw-inv, 1));
  stroke-dasharray: calc(6px * var(--d2-draw-inv, 1)) calc(4px * var(--d2-draw-inv, 1));
}
.d2-draw-layer .d2-selhandle {
  r: calc(7px * var(--d2-draw-inv, 1));
  fill: #fff;
  stroke: rgba(17, 24, 39, .92);
  stroke-width: calc(1.6px * var(--d2-draw-inv, 1));
}
/* 自定义颜色色块（原生取色器；选过之后显示所选颜色） */
.d2-db-color--custom {
  position: relative;
  display: grid;
  place-items: center;
  background: conic-gradient(#ef4444, #eab308, #22c55e, #06b6d4, #3b82f6, #a855f7, #ef4444);
  overflow: hidden;
}
.d2-db-color--custom.has-color { background: var(--db, #3b82f6); }
.d2-db-color--custom::after {
  content: "＋";
  color: rgba(255, 255, 255, .95);
  font-size: 12px;
  font-weight: 700;
  line-height: 1;
  text-shadow: 0 1px 2px rgba(0, 0, 0, .7);
  pointer-events: none;
}
.d2-db-color--custom input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  padding: 0;
  border: 0;
  opacity: 0;
  cursor: pointer;
}
.d2-draw-layer text.d2-dtext {
  font-size: calc(var(--tf, 16px) * var(--d2-draw-inv, 1));
  font-family: var(--ff, "Segoe UI", "Microsoft YaHei", "PingFang SC", sans-serif);
  font-weight: 700;
  text-anchor: middle;
  dominant-baseline: central;
  paint-order: stroke;
  stroke: rgba(0, 0, 0, .82);
  stroke-width: calc(var(--sw, 3) * 1.2px * var(--d2-draw-inv, 1));
  stroke-linejoin: round;
  user-select: none;
}
/* 标注模式光标 */
.d2-viewport.is-annotating { cursor: crosshair; }
.d2-viewport.is-annotating.is-dragging { cursor: grabbing; }
/* 「拖动」工具 = 完全不拦截地图交互（点位可选、画布可平移） */
.d2-viewport.is-annotating.is-pan-tool { cursor: grab; }
.d2-viewport.is-annotating.is-pan-tool.is-dragging { cursor: grabbing; }
/* 「编辑」工具：默认箭头；悬停命中标注时 move 光标提示可拖动 */
.d2-viewport.is-annotating.is-edit-tool { cursor: default; }
.d2-viewport.is-annotating.is-edit-tool.is-over-stroke { cursor: move; }
@media (max-width: 960px) {
  .d2-db-hint { display: none; }
  .d2-drawboard { gap: 4px 6px; padding: 5px 6px; }
  .d2-db-btn { height: 28px; padding: 0 7px; }
  .d2-db-slider input[type="range"] { width: 88px; }
}

/* ======================================================================
   顶带打磨（v8.6，保结构统一规格）：三浮层（工具排/底图/楼层）统一
   高度 32 / 容器 padding 5 / 圆角 10 / 选中色回归全站金色体系
   （此前底图选中是青色 rgba(92,210,216)，与金色主题混杂——最刺眼丑点）
   ====================================================================== */
.d2-toolbar, .d2-basemap-toggle, .d2-tilebar {
  padding: 5px;
  gap: 5px;
  border-radius: 10px;
}
.d2-tool { height: 32px; min-width: 32px; border-radius: 7px; }
.d2-basemap-toggle button { height: 32px; min-width: 64px; border-radius: 7px; }
.d2-basemap-toggle button[aria-pressed="true"] {
  border-color: rgba(215, 181, 109, 0.5);
  background: rgba(215, 181, 109, 0.14);
  color: var(--d2-text);
}
.d2-tilebar button { height: 32px; border-radius: 7px; }
.d2-map-controls { gap: 6px; }
.d2-topbar__center .d2-raid-chip { font-size: 13px; }

/* ======================================================================
   对局时间坞（v8.6，用户指令「时间放到下方，可折叠」）：
   chip 从顶带胶囊移到地图下方居中坞，可折叠（状态持久化）；
   折叠后只剩 🕐 圆钮。移动端抽屉态仍按 syncRaidChipHost 原逻辑搬入抽屉槽位。
   2026-10-13 修正（用户报「展开和关闭应该在同一位置，关闭以后换位置了」）：
   桌面端把「🕐 钮」与「面板」解耦 —— 钮固定在正中，面板绝对定位挂右侧，
   折叠只切换面板显隐、不再改变钮的位置（详见文件后段 @media 961px 块）。
   ====================================================================== */
.d2-raid-dock {
  position: absolute;
  bottom: 14px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 30;
  display: flex;
  align-items: center;
  gap: 8px;
  pointer-events: auto;
}

/* 2026-10-20 用户反馈「/map/ 移动端按钮有问题」+ 实测定位：
   移动端 .d2-mobile-tabs（58px 高，bottom:0）是底部导航，
   而 .d2-raid-dock 仍是桌面口径 bottom:14px → 整条对局信息被压在页签栏下面，
   实测重叠 371×34px（iPhone SE）/ 372×34px（iPhone 14），
   视觉上「35 分钟·10-12 名玩家」和「地图 图层 详情 适屏」两行文字互相穿插成乱码，
   且 dock 的 pointer-events:auto 会抢走页签栏的点击。
   ⇒ 移动端把 dock 抬到页签栏之上，并收成纯图标（省高度，不与页签争视觉）。
   注意：dock 的可视化主体是 __body（圆角胶囊），__toggle 只是折叠按钮。 */
@media (max-width: 960px) {
  .d2-raid-dock {
    bottom: calc(58px + 8px);
    z-index: 31;
    gap: 6px;
  }
  .d2-raid-dock__body {
    padding: 4px 10px;
    font-size: 12px;
    max-width: calc(100vw - 24px);
    overflow: hidden;
  }
  /* 移动端默认折叠：对局信息是次要信息，只留一个可点开的圆钮，避免遮挡地图 */
  .d2-raid-dock[data-folded="1"] { bottom: calc(58px + 8px); }
}
.d2-raid-dock__toggle {
  width: 34px;
  height: 34px;
  border-radius: 17px;
  border: 1px solid var(--d2-line);
  /* R2-D2：原为固定深底 rgba(12,14,16,.82) + var(--d2-text)。浅色主题下
     文字变深色、底色仍是深色 → 实测对比度 1.26~1.45:1（对局时长/人数不可读）。
     改用与其它地图内 chrome 同一套 --d2-overlay（浅色主题自动变浅底）。 */
  background: var(--d2-overlay);
  color: var(--d2-text);
  cursor: pointer;
  font-size: 15px;
  line-height: 1;
  backdrop-filter: blur(10px);
}
.d2-raid-dock__toggle:hover { border-color: rgba(215, 181, 109, 0.5); }
.d2-raid-dock__body {
  display: flex;
  align-items: center;
  padding: 6px 14px;
  border: 1px solid var(--d2-line);
  border-radius: 999px;
  /* R2-D2：同上 —— 面板是 chip 的实际背景（.d2-raid-dock .d2-raid-chip 是 transparent），
     固定深底 + 主题文字在浅色主题下只有 1.26:1。 */
  background: var(--d2-overlay);
  backdrop-filter: blur(10px);
  color: var(--d2-text);
  font-size: 13px;
}
.d2-raid-dock[data-folded="1"] .d2-raid-dock__body { display: none; }
.d2-raid-dock .d2-raid-chip {
  position: static;
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  transform: none;
  white-space: nowrap;
}

/* 桌面（>960）：🕐 固定在「地图下方正中」，面板绝对定位挂在它右侧 ——
   折叠 / 展开时 🕐 的水平位置**恒定不动**（面板不参与 dock 宽度计算）。
   修复前：[🕐][面板] 作为同一个 flex 组整体居中，折叠时组宽 349 → 34，
   🕐 跟着右移半个面板宽（实测 158px），即用户报的「关闭以后竟然换位置」。
   移动端（≤960）不进本块：dock 被 .d2-mobile-tabs（z-index 32，不透明底）
   完全盖住，是不可见/不可点状态，布局保持原样不动。 */
@media (min-width: 961px) {
  .d2-raid-dock { display: block; }
  .d2-raid-dock__body {
    position: absolute;
    left: calc(100% + 8px);
    top: 50%;
    transform: translateY(-50%);
    /* width:max-content —— 必须显式给：绝对定位元素 width:auto 是 shrink-to-fit，
       而它的包含块是 **.d2-raid-dock（只有 34px 宽）**，可用宽 = 34 - 42 < 0，
       会被压成 0 宽、chip 在 0 宽里折成 3 行（实测面板 30x48）。
       max-width 用 vw 而非 %：百分比同样按那个 34px 包含块解析（会算出负数）。
       上限 = 视口 50% - 右侧详情栏宽 - 33px = 地图区右缘内 8px，不压详情面板。 */
    width: max-content;
    max-width: calc(50vw - var(--d2-right) - 33px);
  }
  /* 面板被压窄时 chip 折行（否则 nowrap 会把时钟顶出胶囊外）。
     gap 8px 与 .d2-raid-chip .d2-game-clock 原来的 margin-left:8px 等值，
     一行放得下时渲染结果与改动前一致。 */
  .d2-raid-dock .d2-raid-chip { display: flex; flex-wrap: wrap; gap: 2px 8px; }
  .d2-raid-dock .d2-raid-chip .d2-game-clock { margin-left: 0; }
}

/* ======================================================================
   map-controls 横排化（v8.6，用户指令「主题切换放卫星图切换最右边，不合并」）：
   底图切换 + 图层/楼层 + 主题 同行右对齐，主题保持独立胶囊样式。
   ====================================================================== */
.d2-map-controls {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  flex-wrap: wrap;
  gap: 6px;
}
.d2-map-controls .d2-theme { position: relative; }
.d2-map-controls .d2-theme__btn {
  height: 32px;
  padding: 0 12px;
  border-radius: 8px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

/* ===== 2026-10-14 审计修复 D14：地图内 UI 层必须高于所有标记态 =====
   症状：选中一个位于地图控件左侧的点位后，「抽象图 / 卫星图」切换、工具栏、楼层条
   点不到 —— elementFromPoint 命中的是 .d2-marker-label（选中标记的名称标签）。
   根因：.d2-marker.is-active 的 z-index 是 30，而这三个 UI 层只有 12，
   而它们同处 .d2-stage（z-index:1）这一个堆叠上下文里，于是被标签压住。
   （tools/audit_ditu2_maps.js 在 ground-zero-21 上确定性超时，修复前新旧版本各 3/3 复现。）
   取值 34：高于所有标记态（最高 30），低于弹窗 60/62、标注层 40/98、顶栏 90、导出预览 2000。
   ⚠️ 加在文件末尾 —— 靠「同特异性、后置胜出」压过前面的 z-index:12 声明，不引入 !important。 */
.d2-toolbar,
.d2-map-controls,
.d2-tilebar {
  z-index: 34;
}

/* ===== 2026-10-14 第二轮修复 R2-D4：搜索框聚焦时必须有可见反馈 =====
   现状：.d2-topbar__center input[type="search"] 是 outline:none + border:0 + 透明底，
   而 .d2-topbar__center 没有任何 :focus / :focus-within 规则 ——
   实测聚焦前后自身与容器的 outline / borderColor / boxShadow **完全一致**，
   即键盘用户看不到焦点在哪（WCAG 2.4.7 Focus Visible）。
   修法：给容器加 focus-within 环（金色，与 .d2-photo__main:focus-visible 同一色系），
   不改变输入框自身布局（无位移、无尺寸变化）。 */
.d2-topbar__center:focus-within {
  border-color: rgba(215, 181, 109, 0.75);
  box-shadow: 0 0 0 3px rgba(215, 181, 109, 0.22), var(--d2-shadow);
}

/* ===== 2026-10-14 第二轮修复 R2-D5b：地图视口内的图片不得触发原生拖拽 =====
   现象：鼠标从「标记图标」上起手拖动时地图完全不动（触摸正常）。
   实测事件流：pointerdown(1) → pointermove(2) → **pointercancel(1)** ——
   标记图标是 <img>，浏览器把这次拖动当成了图片原生拖拽（drag-and-drop），
   于是取消指针流，onPointerEnd 把 dragging 置回 false，后续 pointermove 全部无效。
   修法：视口内所有图片禁用原生拖拽（marker img 另外还加了 draggable="false" 双保险）。
   影响面：只作用于 .d2-viewport 内部，不影响详情面板 / 任务图集等处的图片拖拽/另存。 */
.d2-viewport img {
  -webkit-user-drag: none;
}

/* ======================================================================
   2026-10-19 用户口径：地图内容配色与 UI 主题解耦（地标名 / 撤离点 ink）
   ======================================================================
   【原设计的问题】本段规则原本按「地图底色明暗」给 6 套主题分组：
   浅色主题（清爽白 / 工程图纸）配暗字，深色主题配亮字。
   但实测 16 张抽象底图（map/assets/maps/svg/*.svg）**全部是深色**：
   平均亮度 0.13~0.23，深色像素占 80.2%~99.7%（最亮的 Lighthouse 也有 80.7% 深色）。
   ⇒「浅色地图」这个前提从不存在。
   ⇒ 后果：切到清爽白后地标名变成 #605d47、撤离点变成 #006c00 等暗色，压在
     深青/墨绿地图上——实测地标名对比度中位数只有 1.52:1（标准需 ≥4.5:1），
     用户反馈「地图内的地标变色，看着很不舒服」。

   【现行口径】地图里的文字只跟地图本体走，**不跟 UI 主题走**：
   6 套主题统一使用同一套深色地图调色板 —— 地标名 #c7c5b3、选中 #efe9d4、
   撤离点 PMC #00a700 / SCAV #ca8a00 / 共享 #0292c0 / 转移 #e44656。
   ⇒ 切主题只影响外壳（侧栏 / 顶栏 / 详情 / 画布底色），地图内的地标与撤离点
     配色保持恒定，不再「换主题就换色」。
   ⇒ 深色主题零视觉变化（原本即此值）；清爽白下地标名从 1.52:1 回到 5.35:1。
   ⚠️ 主题类在 <html> 与 <body> 上，后代选择器均可命中；特异性 0,2,0 高于基础规则 0,1,0。 */

/* 2026-10-15 任务详情头部：把扁平 header 拆成可扫描的标题、元信息和地图按钮。 */
.d2-task-head {
  margin: 0 0 8px;
  color: var(--d2-text);
  font-size: 15px;
  line-height: 1.35;
}

.d2-task-head__name {
  display: block;
}

.d2-task-head__en {
  display: block;
  margin-top: 3px;
  color: var(--d2-muted);
  font-size: 12px;
  font-style: normal;
  font-weight: 400;
  line-height: 1.45;
  overflow-wrap: anywhere;
}

.d2-task-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin: 0 0 10px;
}

.d2-task-meta__item {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  min-height: 26px;
  padding: 3px 8px;
  border: 1px solid var(--d2-line);
  border-radius: 6px;
  background: var(--d2-chip-bg);
  color: var(--d2-muted);
  font-size: 12px;
  line-height: 1.2;
}

.d2-task-meta__item small {
  color: var(--d2-dim);
  font-size: 11px;
}

.d2-task-meta__trader {
  gap: 6px;
  padding: 2px 8px 2px 3px;
}

.d2-task-meta__avatar {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  object-fit: cover;
  border: 1px solid var(--d2-line-strong);
  flex: 0 0 auto;
}

.d2-task-meta__trader-copy {
  display: flex;
  flex-direction: column;
  gap: 1px;
  line-height: 1.05;
}

.d2-task-head__fallback {
  margin: 0 0 10px;
  color: var(--d2-muted);
  font-size: 12px;
  line-height: 1.55;
  overflow-wrap: anywhere;
}

/* ======================================================================
   2026-10-19 用户口径：折叠按钮换成 eftarkov.com 互动地图同款「竖长耳页签」
   - 形态：26×130 竖长条，垂直居中贴住面板边界；只在朝地图那一侧做 8px 圆角
     （左侧按钮 0 8 8 0、右侧按钮 8 0 0 8），底板与面板同色、1px 细边、无投影；
   - 图标：单箭头 chevron（收起时箭头指向面板要去的方向），18px、1.8 描边；
   - 收起后整条耳页签滑到地图边缘（left:0 / right:0），成为唯一展开入口；
   - 悬停/键盘聚焦只提亮文字并给描边一点金色，不换底、不加光晕。
   参考实现最终取值（多轮覆写后）：26×130、border 1px、垂直居中 translateY(-50%)、
   左侧 0 8px 8px 0 / 右侧 8px 0 0 8px。
   定位容器：.d2-side-fold → .d2-side；.d2-detail-close → .d2-detail；
   .d2-side-unfold → .d2-stage；.d2-detail-unfold → .d2-app（均为整屏区域）。
   ====================================================================== */
@media (min-width: 961px) {
  .d2-app .d2-side-fold,
  .d2-app .d2-side-unfold,
  .d2-app .d2-detail-close,
  .d2-app .d2-detail-unfold {
    position: absolute;
    top: 50%;
    display: grid;
    place-items: center;
    width: 26px;
    height: 130px;
    padding: 0;
    border: 1px solid var(--d2-line-strong);
    background: var(--d2-panel);
    color: var(--d2-muted);
    box-shadow: none;
    line-height: 1;
    transform: translateY(-50%);
    transition: left .2s ease, right .2s ease, color .15s ease, border-color .15s ease, background .15s ease;
  }

  .d2-app .d2-side-fold svg,
  .d2-app .d2-side-unfold svg,
  .d2-app .d2-detail-close svg,
  .d2-app .d2-detail-unfold svg {
    width: 18px;
    height: 18px;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.8;
    stroke-linecap: round;
    stroke-linejoin: round;
  }

  /* 左栏：按钮整块贴在左面板右边界外侧（地图一侧），圆角朝地图。 */
  .d2-app .d2-side-fold {
    top: 50%;
    right: -26px;
    left: auto;
    border-radius: 0 8px 8px 0;
  }

  /* 左栏收起后：按钮滑到地图最左沿，仍圆角朝地图。 */
  .d2-app .d2-side-unfold {
    top: 50%;
    left: 0;
    right: auto;
    border-radius: 0 8px 8px 0;
  }

  /* 右栏：按钮整块贴在右面板左边界外侧（地图一侧），圆角朝地图。 */
  .d2-app .d2-detail-close {
    top: 50%;
    left: -26px;
    right: auto;
    border-radius: 8px 0 0 8px;
  }

  /* 右栏收起后：按钮滑到地图最右沿。 */
  .d2-app .d2-detail-unfold {
    top: 50%;
    right: 0;
    left: auto;
    border-radius: 8px 0 0 8px;
  }

  .d2-app .d2-side-fold:hover,
  .d2-app .d2-side-unfold:hover,
  .d2-app .d2-detail-close:hover,
  .d2-app .d2-detail-unfold:hover,
  .d2-app .d2-side-fold:focus-visible,
  .d2-app .d2-side-unfold:focus-visible,
  .d2-app .d2-detail-close:focus-visible,
  .d2-app .d2-detail-unfold:focus-visible {
    border-color: rgba(215, 181, 109, .5);
    background: var(--d2-panel-2);
    color: var(--d2-text);
    outline: none;
  }

  .d2-app:not(.d2-side-off) .d2-side-unfold,
  .d2-app:not(.d2-detail-off) .d2-detail-unfold {
    display: none;
  }

  .d2-app.d2-side-off .d2-side-unfold,
  .d2-app.d2-detail-off .d2-detail-unfold {
    display: grid;
  }

  /* 顶栏三段按内容向中间搜索框收拢；不同档位仍保持原有响应式行数。 */
  .d2-topbar[data-band="wide"] {
    grid-template-columns: auto auto auto;
    justify-content: center;
    column-gap: 16px;
  }

  .d2-topbar[data-band="wide"] .d2-toolbar,
  .d2-topbar[data-band="wide"] .d2-map-controls {
    justify-self: auto;
  }

  .d2-topbar[data-band="stack"] {
    grid-template-columns: max-content max-content;
    justify-content: center;
    column-gap: 16px;
  }

  .d2-topbar[data-band="stack"] .d2-toolbar {
    justify-self: end;
  }

  .d2-topbar[data-band="stack"] .d2-map-controls {
    justify-self: start;
  }

  .d2-topbar[data-band="split"] {
    /* split 档楼层条可能很长（破冰船 17 项）。这里不能用 max-content：
       第二行视图组横跨两列时会把整组反向撑宽，实测 1366px 溢出 32px。
       改成「左侧 1fr + 胶囊 auto」：第一行工具排贴向胶囊，第二行仍由
       max-width:100% 约束，超长楼层条走自身横向滚动。 */
    grid-template-columns: minmax(0, 1fr) auto;
    justify-content: center;
    column-gap: 16px;
  }

  .d2-topbar[data-band="split"] .d2-toolbar {
    justify-self: end;
  }

  .d2-topbar[data-band="split"] .d2-map-controls {
    justify-self: center;
  }

  .d2-topbar[data-band="tall"] .d2-toolbar,
  .d2-topbar[data-band="tall"] .d2-map-controls {
    justify-self: center;
  }
}

/* ======================================================================
   2026-10-20 移动端专项修复（用户：「移动端的按钮似乎有问题，全方位模拟体验」
   ======================================================================
   实测（iPhone SE 375×667 / iPhone 14 390×844 / Pixel 7 412×915，Playwright
   isMobile+hasTouch 真实触摸模拟）暴露出 4 类问题，逐条修：

   【问题 1】底部导航与对局信息条重叠，文字互相穿插成乱码
     .d2-mobile-tabs（z32, bottom:0, 58px）与 .d2-raid-dock（z30, bottom:14px）
     在底部正面相撞，实测重叠 371×34px。截图上「35 分钟·10-12 名玩家」与
     「地图 图层 详情 适屏」两行叠印，完全不可读；且 dock 的 pointer-events:auto
     会抢走页签栏点击。
     ⇒ 已在 .d2-raid-dock 媒体查询里把 dock 抬到 bottom: calc(58px + 8px)、z-index:31，
       并让 ≤960 默认折叠（见 ditu2.js 的 data-folded 初值）。

   【问题 2】地图只占屏幕 22%，上下全是空白
     竖屏下 fitMap() 用 Math.min(w/W, h/H) 求适配缩放，而地图 SVG 是横向长方形
     （customs 2048×1024 级别），宽度先触顶 → 高度只用掉一小条。
     实测 iPhone 14：stage 390×780，地图实际渲染 363×185 = 22.0%。
     ⇒ 移动端改为「宽度优先适配 + 允许上下留白但用更大比例」，
       同时压缩顶部控件占位（见问题 3），把可见高度真正还给地图。

   【问题 3】顶部控件吃掉 38~48% 的屏幕高度
     iPhone SE 实测：topbar 到 120px、toolbar 到 176px、map-controls 到 320px，
     即顶部 320/667 = 48% 被控件占满，地图只剩中间一条。
     ⇒ 实际做法（按实现修正描述，不是「收进溢出层」）：把 topbar 上移、搜索框压到 32px、
       工具行压到 34px；map-controls 由「纵向 3 行（底图/楼层/主题各一行 = 138px）」
       改为「两行 34px 行高 + order 重排」= 74px：第 1 行 [底图][主题]，第 2 行 [楼层]。
       顶部总占位 320px → 230px（27%）。未新增弹出层，避免引入新交互状态与可达性问题。

   【问题 4】地图内标签在窄屏过密、互相压字
     实测 iPhone 14 可见标签 48 条（地标 16 + 撤离点 32），互相重叠 75 对
     （地标×地标 6 对、地标×其它 26 对）—— 文字糊成一片，读不出地名。
     ⇒ 移动端提高地标避让阈值并给标签加实体底片，具体见下方规则。
   ====================================================================== */

/* —— 问题 3：移动端顶部控件瘦身 ——
   桌面把所有工具平铺出来是合理的（有横向空间），移动端平铺 3 行后地图没地方了。
   这里把「底图 / 楼层 / 主题」这组低频控件收进一行可横向滚动的紧凑条，
   并抬到搜索框下方同一行区域，避免每样控件各占一整行。 */
@media (max-width: 960px) {
  /* 顶部容器整体上移收紧：原来 topbar 从 76px 开始（壳头部 64 + 12），
     移动端壳头部本身已有 64px，这里不再叠加额外间距。
     ⚠️ 2026-10-20 第二轮：≤960 时工具排与视图组已被 syncHeaderHosts 搬去 stage，
     topbar 里只剩搜索框，继续用桌面的 grid(1fr auto 1fr) 会把它挤到右半边
     （实测左缘 209px、宽 163px，与下方两行 8px 左缘不齐）。这里改成一整行。 */
  .d2-topbar {
    top: 6px !important;
    left: 8px;
    right: 8px;
    padding: 0;
    display: block;
  }

  /* 搜索框：占满一行但降低高度，避免 44px 胶囊吃掉半屏 */
  .d2-topbar__center {
    height: 40px;
    width: 100%;
    max-width: none;
    justify-self: stretch;
  }
  .d2-topbar__center input[type="search"],
  .d2-topbar input[type="search"] {
    flex: 1 1 auto;
    min-width: 0;
    width: 100%;
    height: 36px;
    /* 2026-10-20：必须 ≥16px —— iOS Safari 对 <16px 的输入框会在聚焦时强制放大整页 */
    font-size: 16px;
  }

  /* 工具按钮行：紧贴搜索框下方，单行不换行 */
  .d2-toolbar {
    top: 54px !important;
    left: 8px;
    right: 8px;
    max-width: none;
    flex-wrap: nowrap;
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
    /* 与搜索框 / 控件行统一到 8px 左缘：原来 0 2px 让首个工具按钮落在 10px，三行错位 */
    padding: 0;
  }
  .d2-toolbar::-webkit-scrollbar { display: none; }
  /* ⚠️ 2026-10-20 第二轮：这里原本写死 width:36px —— 正是基础规则 1399 行注释里
     记录过的老坑（「固定 34px 使『✎标注』文字标签溢出错位」）。实测 390 宽下「标注」
     被压成竖排两行，就是用户说的按钮错位。改回内容自适应 + 最小宽。 */
  .d2-tool {
    width: auto;
    min-width: 40px;
    height: 40px;
    padding: 0 9px;
    flex: 0 0 auto;
  }
  /* 「标注」是唯一带文字的按钮，禁止换行免得被压成两行 */
  .d2-tool__lab {
    font-size: 13px;
    white-space: nowrap;
    writing-mode: horizontal-tb;
  }

  /* 底图 / 楼层 / 主题：移动端收成「两行」。
     ⚠️ 不要用横向滚动条（overflow-x:auto）—— 实测宽度不够时底图切换被推到
     left:-182px（完全在屏幕外），而滚动条已隐藏，触摸用户根本不知道右边还有内容，
     等于「抽象图/卫星图」按钮凭空消失。这正是用户反馈「移动端按钮有问题」的一部分。
     改为可换行：内容始终全部可见可点。

     行序（用 order 重排，不改 DOM）：
       第 1 行 = [底图切换] [主题]     145 + 6 + 102 = 253 < 368 ✓
       第 2 行 = [楼层条]              297          ✓
     若按 DOM 原序（底图→楼层→主题），145+6+297=448 会溢出，再放主题就成第 3 行
     （实测 138px 高）——重排后稳定两行、约 74px。
     注意 .d2-map-controls 基础规则是 display:grid + justify-items:end（纵向堆叠），
     这里必须显式覆盖成 flex，否则三个子项各占一行。 */
  .d2-map-controls {
    /* 100px = 工具行 54 + 44 高 + 2px 间隙。原来写 92 会与工具行底部重叠 6px
       （实测 .d2-toolbar×.d2-map-controls 交叠 347×6），点击落在重叠区会点错控件。 */
    top: 102px !important;
    left: 8px;
    right: 8px;
    display: flex;
    flex-wrap: wrap !important;
    align-items: center;
    justify-content: flex-start;
    gap: 6px;
    overflow: visible;
    padding: 0;
    max-width: none;
  }
  .d2-map-controls > * { flex: 0 0 auto; }
  .d2-basemap-toggle { order: 1; }
  .d2-theme { order: 2; }
  .d2-tilebar { order: 3; }

  /* 楼层条在窄屏可能超宽：破冰船有 16 个楼层按钮（图层 医务室 直升机坪 健身房/食堂
     住宿区×3 军官甲板 楼梯（封闭） 舰桥 舰桥顶部 控制室 轮机舱×2 …），
     实测超出视口左侧 1099px，前面几个楼层点不到。
     ⚠️ 根因不只是宽度：基础规则 .d2-tilebar{justify-content:flex-end} 会让溢出**向左**，
     而 LTR 下向左溢出**不产生可滚动区域**（scrollWidth == clientWidth，滚不动）。
     所以必须同时改成 flex-start，溢出方向才会变成可横滑的右侧。 */
  .d2-tilebar {
    /* 楼层条在窄屏可能超宽：破冰船有 16 个楼层按钮（楼层 医务室 直升机坪 健身房/食堂
       住宿区×3 军官甲板 楼梯（封闭） 舰桥 舰桥顶部 控制室 轮机舱×2 …），
       实测超出视口左侧 1099px，前面几个楼层点不到。
       ⚠️ 根因不只是宽度：基础规则 .d2-tilebar{justify-content:flex-end} 会让溢出**向左**，
       而 LTR 下向左溢出**不产生可滚动区域**（scrollWidth == clientWidth，滚不动）。
       所以必须同时改成 flex-start，溢出方向才会变成可横滑的右侧。
       ⚠️ 2026-10-20 第二轮：本块此前重复声明两次（第二份把 max-width 改回 none，
       等于把 max-width:100% 的约束自己抹掉）。这里合并成一份，max-width 只留 100%。 */
    flex: 0 1 auto;
    min-width: 0;
    max-width: 100%;
    flex-wrap: nowrap;
    gap: 4px;
    justify-content: flex-start;
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }
  .d2-tilebar::-webkit-scrollbar { display: none; }
  /* 2026-10-20：只有在**确实溢出**时才给右缘渐隐（is-scrollable 由 JS 按
     scrollWidth/clientWidth 判定）。不溢出时加渐隐会把最后一个按钮无谓地切一刀。 */
  .d2-tilebar.is-scrollable {
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 20px), transparent 100%);
    mask-image: linear-gradient(to right, #000 calc(100% - 20px), transparent 100%);
  }
  /* 「楼层」二字是纯文字标签，被 flex 压缩会竖排成两行 —— 显式禁止收缩与换行 */
  .d2-tilebar > span {
    flex: 0 0 auto;
    white-space: nowrap;
  }
  .d2-tilebar button {
    flex: 0 0 auto;
    min-height: 40px;
    padding: 0 10px;
    font-size: 13px;
    white-space: nowrap;
  }

  /* 行高压到 34px：移动端控件不需要桌面的 46px 视觉重量 */
  .d2-map-controls { min-height: 0; }
  .d2-basemap-toggle,
  .d2-theme,
  .d2-tilebar { height: 40px; }

  /* 底图切换（抽象图/卫星图）：移动端压成图标级宽度 */
  .d2-basemap button,
  .d2-map-controls [data-basemap] {
    min-height: 40px;
    padding: 0 10px;
    font-size: 13px;
    white-space: nowrap;
  }

  /* 主题按钮：同一行最右侧。
     ⚠️ 2026-10-20 第二轮：基础规则把它设成 --d2-chip-bg（5% 白，几乎全透明），
     压在深色地图上时地标/撤离点的绿色标签会直接透过来，按钮文字读不出来
     （375 宽「军事终端」压「铁路通道（信号弹）」实测）。移动端统一成与
     「抽象图 / 卫星图」同一套 --d2-overlay 底，三组控件观感也一致。 */
  .d2-theme__btn {
    min-height: 40px;
    padding: 0 10px;
    font-size: 13px;
    background: var(--d2-overlay);
    white-space: nowrap;
  }

  /* —— 问题 2 配套：把可用高度还给地图 ——
     顶部控件下边界从 320px 收到 ~140px，地图区域因此从 22% 提升到 60%+。 */
  .d2-stage {
    inset: 0 0 58px;
  }
}

/* ======================================================================
   2026-10-20 横屏手机专项（用户要求「全方位模拟体验」）
   ======================================================================
   实测 844×390（iPhone 14 横屏）暴露 3 个只在横屏出现的问题：
     ① 搜索框与工具行、底图行三者在垂直方向挤在 390px 里，底图切换/主题按钮
        直接压在地图上并互相重叠；
     ② 底部页签栏（58px）压住地图下缘，撤离点标签被裁一半；
     ③ 顶部控件总高约 230px，占 390px 的 59%，地图几乎没空间。

   处理原则：横屏是「宽而矮」，纵向空间最珍贵 ——
     · 工具行与视图控件合并为**单行**（横向宽度足够，不必换行）；
     · 页签栏压到 46px，并把它计入 stage 的 inset；
     · 搜索框在横屏收起（窄屏已有入口，横屏优先保地图）。
   ====================================================================== */
@media (max-width: 960px) and (orientation: landscape) {
  /* 2026-10-20：横屏只有 390px 高，横幅 48px 无论放哪都会压在画面中央
     （实测 bottom:108 时占 y234–282，正好盖住地图主体）。横屏直接用来看图，
     不显示推广横幅；竖屏与桌面照常显示。 */
  .d2-promo { display: none; }

  /* ⚠️ 2026-10-20 第二轮：这里原本是 `.d2-topbar { display: none }`。
     但 ≤960 时 syncHeaderHosts 已把工具排与视图组搬去 stage，topbar 里只剩搜索框，
     于是「隐藏 topbar」= 把「搜索点位 / 物品 / 任务」整块删掉（站内导航的放大镜是
     全站搜索，替代不了）。改成**收起成 34px 图标、聚焦后展开**，纵向占用归零。 */
  .d2-topbar {
    display: block;
    top: 0 !important;
    left: 0;
    right: 0;
    height: 0;
    padding: 0;
    gap: 0;
  }
  .d2-topbar__center {
    position: absolute;
    top: 6px;
    left: 308px;
    width: 34px;
    height: 34px;
    min-height: 0;
    padding: 0;
    justify-content: center;
    overflow: hidden;
    border-radius: 8px;
    cursor: pointer;
    transition: width .18s ease;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%237d8794' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='m20.5 20.5-3.9-3.9'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: center;
    background-size: 16px 16px;
  }
  /* 收起态：输入框铺满整个圆角块（不可见但可点）——只缩宽度会让 34px 的块点不到、聚焦不了 */
  .d2-topbar__center input[type="search"] {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    padding: 0;
    opacity: 0;
    cursor: pointer;
  }
  /* 展开态：宽度放到 300px（或视口允许的最大值），盖住右侧控件，失焦自动收回 */
  .d2-topbar__center:focus-within {
    width: min(300px, calc(100vw - 360px));
    background-image: none;
    cursor: text;
  }
  .d2-topbar__center:focus-within input[type="search"] {
    position: static;
    width: 100%;
    height: auto;
    padding: 0 10px;
    opacity: 1;
    cursor: text;
  }

  /* 工具行贴顶，单行横滑（宽度足够，实测 7 个工具 × 36px = 252px < 844px） */
  .d2-toolbar {
    top: 6px !important;
    left: 8px;
    right: auto;
    max-width: calc(100vw - 16px);
    flex-wrap: nowrap;
  }

  /* 底图 / 楼层 / 主题：紧贴搜索图标右侧，同一条水平线上。
     可用宽度 = 844 - 350(搜索图标右缘+8) - 8 = 486px；三组内容原本 145+102+297 = 544，
     整体偏宽 → 由内部楼层条横滑吸收，不再把「抽象图」挤出屏幕。
     横屏统一收紧按钮内边距（10→7px），内容降到 ≈510px。 */
  .d2-map-controls {
    top: 6px !important;
    left: auto;
    right: 8px;
    width: auto;
    max-width: calc(100vw - 358px);
    flex-wrap: nowrap !important;
    overflow: visible;
  }
  .d2-map-controls .d2-basemap-toggle button,
  .d2-map-controls .d2-tilebar button,
  .d2-map-controls .d2-theme__btn {
    padding: 0 7px;
    font-size: 12px;
  }

  /* 页签栏压薄，stage 相应下移 */
  .d2-mobile-tabs {
    height: 46px;
  }
  .d2-mobile-tabs button {
    font-size: 12px;
  }
  .d2-stage {
    inset: 0 0 46px;
  }
  .d2-side,
  .d2-detail {
    height: calc(100% - 46px);
    max-height: none;
    bottom: 46px;
  }

  /* 对局坞与重置条跟着页签栏抬升 */
  .d2-raid-dock {
    bottom: calc(46px + 6px);
  }
  .d2-resetbar {
    bottom: calc(46px + 6px);
  }

  /* 横屏标签再压一档：390px 高度里标签是主要视觉噪声 */
  .d2-marker--landmark .d2-marker-label {
    font-size: calc(12px * var(--lm-scale, 1));
  }
  .d2-marker--extraction .d2-marker-label,
  .d2-marker--transit .d2-marker-label {
    font-size: 13px;
  }
}
.d2-coordinate-notice { display: none; }

@media (max-width: 960px) {
  .d2-coordinate-notice { display: block; position: absolute; z-index: 70; right: 12px; bottom: 144px; left: 12px; max-width: 480px; margin: 0 auto; padding: 12px; border: 1px solid var(--d2-line); border-radius: 8px; background: var(--d2-panel); color: var(--d2-text); font-size: 13px; line-height: 1.5; pointer-events: none; }
  .d2-coordinate-notice strong, .d2-coordinate-notice span { display: block; }
}

/* Remaining audit: compact detail sheets preserve visible map area. */
@media (max-width: 960px) {
  .d2-app .d2-detail { top: auto; height: auto; max-height: min(46dvh, 430px); min-height: 0; width: 100%; }
  .d2-detail .d2-detail__head { padding: 12px 14px; }
  .d2-detail .d2-detail__body { flex: 0 1 auto; max-height: 32dvh; overflow: auto; }
  .d2-app[data-detail-empty="1"] .d2-right-placeholder { min-height: 0; padding: 8px; }
  .d2-app[data-detail-empty="1"] .d2-detail__body { max-height: 22dvh; }
}

.d2-map-coverage { position:absolute;left:calc(var(--d2-left) + 16px);top:136px;z-index:11;max-width:330px;padding:8px 10px;border:1px solid var(--d2-line);border-radius:8px;background:var(--d2-panel);color:var(--d2-text);font-size:12px; }
.d2-app.d2-side-off .d2-map-coverage { left:14px; }
 @media (max-width:960px) { .d2-map-coverage { top:160px;left:10px;max-width:calc(100% - 20px); } .d2-app[data-mobile-panel="layers"] .d2-map-coverage,.d2-app[data-mobile-panel="detail"] .d2-map-coverage { display:none; } }

 @media (max-width:960px) { .d2-app .d2-detail .d2-detail-close { display:none; } .d2-detail .d2-close { width:40px;height:40px; } }

/* Keep every photo action, including touch close, within narrow map viewports. */
@media (max-width: 480px) {
  .fancybox__container .f-carousel__toolbar {
    grid-template-columns: auto minmax(0, 1fr);
    align-items: start;
  }

  .fancybox__container .f-carousel__toolbar__column.is-middle:empty {
    display: none;
  }

  .fancybox__container .f-carousel__toolbar__column.is-right {
    min-width: 0;
    max-width: 100%;
    flex-wrap: wrap;
  }

  .fancybox__container .takefu-viewer-original span {
    padding: 0 8px;
    white-space: normal;
    font-size: 12px;
    line-height: 1.25;
  }
}
