:root {
  color-scheme: light;
  --bg: #f6f0eb;
  --panel: #fffdfb;
  --ink: #24211d;
  --muted: #706a60;
  --line: #e3d4c8;
  --accent: #7f4b26;
  --accent-strong: #5f341b;
  --accent-soft: #f0e3d7;
  --gold: #9a682c;
  --danger: #a52206;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  min-height: 100vh;
  overflow: hidden;
  background: var(--bg);
  color: var(--ink);
  font-family: "Microsoft YaHei", "PingFang SC", system-ui, sans-serif;
}

[hidden] { display: none !important; }

.story-view {
  position: fixed;
  inset: 0;
  overflow: hidden;
  padding: clamp(8px, 1.4vw, 20px);
  background: var(--bg);
}

.story-card {
  width: 100%;
  height: 100%;
  margin: 0 auto;
  padding: clamp(14px, 2.2vw, 32px);
  display: flex;
  flex-direction: column;
  border: 0;
  border-radius: 0;
  background: transparent;
  box-shadow: none;
}

.story-card-head {
  position: relative;
  flex: 0 0 auto;
  padding: 0 0 clamp(10px, 1.3vw, 18px);
  border-bottom: 1px solid var(--line);
}

.story-book-title,
.story-section {
  color: var(--accent-strong);
  font-size: clamp(11px, 1vw, 15px);
  font-weight: 800;
}

.story-section {
  margin-top: 3px;
  color: var(--muted);
}

.story-card h1 {
  max-width: calc(100% - 100px);
  margin: 6px 0 0;
  font-size: clamp(20px, 2.5vw, 36px);
  line-height: 1.35;
  font-family: "Songti SC", "Noto Serif CJK SC", SimSun, Georgia, serif;
  font-weight: 600;
  letter-spacing: .04em;
  color: var(--accent-strong);
}

.story-entry-id {
  position: absolute;
  top: 0;
  right: 0;
  padding: 5px 10px;
  border: 0;
  border-left: 1px solid var(--line);
  border-radius: 0;
  background: transparent;
  color: var(--accent-strong);
  font-size: clamp(15px, 1.6vw, 22px);
  font-weight: 900;
}

.story-body {
  min-height: 0;
  flex: 1 1 auto;
  overflow: auto;
  padding-top: clamp(10px, 1.4vw, 20px);
  color: var(--ink);
  font-family: "Microsoft YaHei", "PingFang SC", "Noto Sans CJK SC", system-ui, sans-serif;
  font-size: 18px;
  line-height: 1.75;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  scrollbar-color: var(--line) transparent;
  /* 栏数由 app.js 按「字号能给到多大」挑（两栏 / 三栏），见 fitStoryTextToViewport。 */
  column-count: var(--story-columns, 2);
  column-gap: clamp(24px, 4vw, 64px);
  column-rule: 1px solid var(--line);
  column-fill: balance;
}

/* 正文里的管道表格（原书排版遗留，见 story/assets/story-tables.js）。
   结构与主屏一致：字符保真的 span，竖线和分隔行只隐藏不删除，混排才能按字符偏移插图。 */
.story-table {
  display: table;
  width: 100%;
  margin: 12px 0 16px;
  border-collapse: collapse;
  border: 1px solid var(--line);
  background: var(--panel);
  font-size: 0.94em;
  white-space: normal;
  column-span: all;
}

.story-table-row { display: table-row; }

.story-table-cell {
  display: table-cell;
  padding: 8px 10px;
  border: 1px solid var(--line);
  text-align: left;
  vertical-align: top;
  overflow-wrap: anywhere;
}

.story-table-head {
  background: var(--accent-soft);
  color: var(--accent-strong);
  font-weight: 700;
}

.story-table-row:not(.story-table-sep-row):nth-child(even) .story-table-cell {
  background: rgba(255, 255, 255, 0.5);
}

.story-table-bar,
.story-table-sep,
.story-table-sep-row {
  display: none;
}

.story-view.images-only { padding: 0; background: var(--panel); }
.images-only .story-card { padding: 0; border: 0; border-radius: 0; background: transparent; box-shadow: none; }
.images-only .story-card-head { display: none; }
.images-only .story-body { padding: 0; white-space: normal; column-count: 1; column-rule: 0; }
.images-only .story-body img { display: block; width: 100%; height: 100%; object-fit: contain; }

/* 正文里有块状媒体（版图、铭文图……）时（app.js 给 .story-view 加上 .story-scroll）：
   正文照旧双栏、图片留在原来的锚点位置，整屏改成纵向滚动。
   为什么高度要交给内容：.story-body 只要还是「定高 + 多栏」容器，装不下的内容就会继续往右
   分栏、被排到屏幕外（见 release-notes/c45-items4-5-report-20261005.md 的实测：1180px 视口
   scrollWidth 7949px、约 7 栏）。高度 auto + 多栏只会把两栏拉高，多出来的高度交给外面这层
   .story-view 纵向滚动，内容不会被挤到看不见的地方。
   选择器带 .story-view.story-scroll 是为了压过 mixed-media/styles.css 里
   .story-body.ato-mm-layout 的 column-count / column-width / overflow（那份样式表在本文件
   之后加载，同权重时它会赢）。 */
.story-view.story-scroll { overflow: auto; scrollbar-color: var(--line) transparent; }
.story-view.story-scroll .story-card { height: auto; min-height: 100%; }
/* 标题跟着滚也没关系，但别让它被正文盖住：贴顶 + 底色。 */
.story-view.story-scroll .story-card-head {
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--bg);
}

.story-view.story-scroll .story-body.ato-mm-layout {
  flex: 0 0 auto;
  height: auto;
  overflow: visible;
  column-count: var(--story-columns, 2);
  column-width: auto;
  column-rule: 1px solid var(--line);
  column-fill: balance;
  /* 正文里有大量分段空行（原书排版），行高这里收紧一点，好让整屏二分能找到更大的字号。 */
  line-height: 1.6;
}

/* 块状媒体缩成正文里的小图：上限按 em 走，字号一缩图跟着缩（app.js 的整屏二分就靠这个单调性），
   点图仍然可以放大看原图。小图（铭文、字形）本来就小于上限，保持原尺寸。 */
.story-view.story-scroll .story-body .ato-mm-block img {
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: 13em;
}

.pair-view {
  position: fixed;
  inset: 0;
  z-index: 20;
  display: grid;
  place-items: center;
  padding: 20px;
  background: var(--bg);
}

.pair-card {
  width: min(430px, 100%);
  display: grid;
  gap: 17px;
  padding: 26px;
  border: 1px solid var(--line);
  border-radius: 0;
  background: var(--panel);
  box-shadow: none;
}

.pair-card p { margin: 0; color: var(--muted); }

.pair-card form {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 8px;
}

.pair-card input,
.pair-card button {
  min-height: 46px;
  border: 1px solid var(--line);
  border-radius: 0;
  font: inherit;
}

.pair-card input {
  min-width: 0;
  padding: 0 13px;
  background: var(--panel);
  color: var(--ink);
  font-size: 20px;
  font-weight: 900;
  letter-spacing: .15em;
}

.pair-card button {
  padding: 0 18px;
  background: var(--accent-strong);
  color: #fff;
  font-weight: 900;
  cursor: pointer;
}

.pair-message { min-height: 20px; color: var(--danger); font-size: 13px; }

.screen-shell {
  width: 100vw;
  height: 100vh;
  padding: 0;
}

.screen-head,
.screen-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
}

.eyebrow {
  color: var(--accent);
  font-size: 11px;
  font-weight: 900;
  letter-spacing: 0.18em;
}

h1 {
  margin: 3px 0 0;
  font-size: clamp(24px, 4vw, 44px);
  line-height: 1;
}

.screen-meta,
.screen-footer {
  color: var(--muted);
  font-size: clamp(12px, 1.4vw, 16px);
}

.screen-meta {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 8px 16px;
}

.screen-meta strong { color: var(--gold); }

.connection-status {
  padding: 5px 9px;
  border-radius: 0;
  background: var(--accent-soft);
  color: var(--accent);
  font-weight: 900;
}

.connection-status.error {
  background: rgba(239, 114, 105, 0.14);
  color: var(--danger);
}

.map-stage {
  position: fixed;
  inset: 0;
  overflow: hidden;
  border: 0;
  border-radius: 0;
  background: var(--panel);
  box-shadow: none;
}

.map-frame {
  width: 100%;
  height: 100%;
  display: block;
  border: 0;
  background: var(--panel);
}

.battle-view {
  --battle-scale: 1;
  --battle-safe-height: 100vh;
  --battle-safe-width: 100vw;
  --battle-board-column: 50vw;
  --boss-small-card-width: 96px;
  --boss-small-card-height: 132px;
  --boss-panel-width: 280px;
  --boss-panel-height: 264px;
  --trait-area-height: 139px;
  --resolution-area-height: 220px;
  --terrain-card-area-height: 0px;
  --battle-rotation: 0deg;
  --sidebar-content-width: 50vw;
  --sidebar-content-height: 100vh;
  /* app.js 量到「正在结算」卡牌仍然越界时会把它压到 1 以下，整块侧栏等比缩到屏幕内。 */
  --sidebar-fit-scale: 1;
  position: fixed;
  left: 50%;
  top: 50%;
  width: var(--battle-safe-width);
  height: var(--battle-safe-height);
  transform: translate(-50%, -50%);
  display: grid;
  grid-template-columns: minmax(260px, 1fr) minmax(260px, var(--battle-board-column));
  overflow: hidden;
  background: var(--bg);
}

.battle-view.swapped {
  grid-template-columns: minmax(260px, var(--battle-board-column)) minmax(260px, 1fr);
}

.battle-view.swapped .battle-sidebar {
  grid-column: 2;
  grid-row: 1;
}

.battle-view.swapped .battle-board-stage {
  grid-column: 1;
  grid-row: 1;
}

.battle-view.board-hidden {
  grid-template-columns: minmax(0, 1fr);
}

.battle-view.board-hidden .battle-sidebar {
  grid-column: 1;
  grid-row: 1;
  border-right: 0;
}

.battle-view.board-hidden .battle-board-stage {
  display: none;
}

.battle-sidebar {
  position: relative;
  min-width: 0;
  height: 100%;
  overflow: hidden;
  border-right: 1px solid var(--line);
  background: var(--bg);
}

.battle-sidebar-content {
  position: absolute;
  left: 50%;
  top: 50%;
  width: var(--sidebar-content-width);
  height: var(--sidebar-content-height);
  transform: translate(-50%, -50%) rotate(var(--battle-rotation)) scale(var(--sidebar-fit-scale, 1));
  transform-origin: center;
  display: grid;
  grid-template-rows: var(--boss-panel-height) var(--trait-area-height) minmax(0, 1fr);
  gap: 10px;
  padding: 10px;
  overflow: hidden;
  background: var(--bg);
}

.battle-sidebar-content.quarter-turn,
.battle-sidebar-content.aibp-mirror {
  grid-template-columns: var(--boss-panel-width) minmax(0, 1fr);
}

.battle-sidebar-content.quarter-turn,
.battle-sidebar-content.aibp-mirror:not(.has-terrain-cards) {
  grid-template-rows: var(--boss-panel-height) var(--trait-area-height);
}

.battle-sidebar-content.aibp-mirror.has-terrain-cards {
  grid-template-rows: var(--boss-panel-height) var(--trait-area-height) var(--terrain-card-area-height);
}

.battle-sidebar-content.quarter-turn .boss-summary,
.battle-sidebar-content.aibp-mirror .boss-summary {
  grid-column: 1;
  grid-row: 1;
}

.battle-sidebar-content.quarter-turn .support-cards,
.battle-sidebar-content.aibp-mirror .support-cards {
  position: relative;
  grid-column: 1 / span 2;
  grid-row: 2;
  grid-template-rows: var(--boss-small-card-height);
  overflow: auto hidden;
}

.battle-sidebar-content.quarter-turn .trait-cards img,
.battle-sidebar-content.aibp-mirror .trait-cards img {
  position: relative;
  z-index: 4;
}

.battle-sidebar-content.quarter-turn .resolution-panel,
.battle-sidebar-content.aibp-mirror .resolution-panel {
  position: relative;
  z-index: 3;
  grid-column: 2;
  grid-row: 1 / span 2;
  margin-left: 10px;
  padding-top: 0;
  padding-left: 10px;
  border-top: 0;
  border-left: 1px solid var(--line);
  background: var(--panel);
}

.battle-sidebar-content.quarter-turn .pending-cards,
.battle-sidebar-content.aibp-mirror .pending-cards {
  margin-top: 0;
}

/* 旋转 90/270 度时整块侧栏内容是转过来看的，所以「上下」要按卡牌自己的方向算：
   信息块（当前卡背 / BP 卡背 / 弃牌 / 当前损伤）排到「正在结算」卡牌的上方。
   也就是结算区由左右两列改成上下两行 —— 第一行信息块，第二行卡牌。
   （内容被旋转过，所以这里的「上」在物理屏幕上分别是左/右，不是屏幕的正上方。） */
.battle-sidebar-content.quarter-turn .resolution-panel {
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: auto minmax(0, 1fr);
  gap: 8px;
}

.battle-sidebar-content.quarter-turn .resolution-panel .aibp-slot {
  grid-column: 1;
  grid-row: 1;
  /* 信息在左、损伤牌在右：信息块只占内容高度，剩下的高度全留给卡牌。 */
  grid-template-columns: auto minmax(0, 1fr);
  grid-template-rows: minmax(0, 1fr);
}

.battle-sidebar-content.quarter-turn .resolution-panel .pending-cards {
  grid-column: 1;
  grid-row: 2;
}

.battle-terrain-cards {
  display: none;
}

.battle-sidebar-content.aibp-mirror.has-terrain-cards .battle-terrain-cards {
  min-width: 0;
  min-height: 0;
  grid-column: 1 / span 2;
  grid-row: 3;
  display: grid;
  grid-template-rows: auto minmax(0, 1fr);
  gap: 6px;
  padding-top: 8px;
  overflow: hidden;
  border-top: 1px solid var(--line);
}

.battle-terrain-cards-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  color: var(--gold);
}

.battle-terrain-cards-head h2 {
  margin: 0;
  font-size: 13px;
}

.battle-terrain-cards-head span {
  color: var(--muted);
  font-size: 11px;
}

.battle-terrain-card-list {
  min-width: 0;
  min-height: 0;
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(92px, calc(var(--terrain-card-area-height) * .62));
  justify-content: start;
  gap: 8px;
  overflow: auto hidden;
}

.battle-terrain-card {
  min-width: 0;
  min-height: 0;
  margin: 0;
  display: grid;
  grid-template-rows: minmax(0, 1fr) auto;
  gap: 3px;
}

.battle-terrain-card img {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: contain;
}

.battle-terrain-card figcaption {
  overflow: hidden;
  color: var(--ink);
  font-size: 10px;
  line-height: 1.2;
  text-align: center;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.boss-summary {
  min-height: 0;
  display: block;
}

.boss-panel {
  width: var(--boss-panel-width);
  height: var(--boss-panel-height);
}

.boss-small-card {
  width: var(--boss-small-card-width);
  height: var(--boss-small-card-height);
}

.card-slot {
  position: relative;
  min-width: 0;
  min-height: 0;
  margin: 0;
  display: grid;
  place-items: center;
  overflow: hidden;
  background: var(--panel);
}

.boss-token-layer {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

/* 大迷宫轨道红圈（迷宫机牛 / 吞域兽）：坐标由控制台随快照一起送过来，和 boss 大卡上的
   印出来的轨道格同一份百分比。宽度按面板宽度算，所以换屏幕尺寸也贴着格。 */
.boss-labyrinth-track {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.boss-labyrinth-track span {
  position: absolute;
  left: var(--track-left, 50%);
  top: var(--track-top, 50%);
  transform: translate(-50%, -50%);
  width: clamp(14px, var(--track-width, 5.6%), 140px);
  aspect-ratio: 1 / 1;
  border: 3px solid rgba(255, 88, 82, 0.88);
  border-radius: 999px;
  background: rgba(255, 88, 82, 0.04);
  box-shadow:
    0 0 0 1px rgba(20, 8, 6, 0.62),
    0 0 10px rgba(255, 72, 66, 0.22),
    inset 0 0 8px rgba(255, 72, 66, 0.12);
}

.boss-token {
  position: absolute;
  width: clamp(34px, calc(var(--boss-panel-width) * .072), 68px);
  min-width: 34px;
  aspect-ratio: 1;
  transform: translate(-50%, -50%);
  filter: drop-shadow(0 8px 13px rgba(0, 0, 0, .62));
}

.boss-token img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  border-radius: 999px;
  opacity: 0.62;
}

.boss-token.custom-token {
  border-radius: 50%;
  background: transparent url("../aibp/ps/other/custom-token-cm.png?v=20260930-medium-rim1") center / contain no-repeat;
}

.boss-token.custom-token img {
  opacity: 1;
}

.boss-token.custom-token b {
  right: -10%;
  bottom: -7.5%;
  min-width: 42.5%;
  height: 42.5%;
  border-color: rgba(240, 238, 229, .55);
  background: #454542;
  font-weight: 700;
}

.boss-token b {
  position: absolute;
  right: -16.667%;
  bottom: -14.583%;
  min-width: 50%;
  height: 50%;
  display: grid;
  place-items: center;
  padding: 0 10.417%;
  border: 1px solid rgba(255, 255, 255, 0.25);
  border-radius: 999px;
  background: rgba(180, 52, 44, 0.94);
  color: #fff;
  font-size: 27.083%;
  font-weight: 900;
  line-height: 1;
  opacity: 0.95;
}

.card-slot img,
.current-card img,
.trait-cards img,
.damage-cards img {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: contain;
}

.support-cards {
  min-width: 0;
  min-height: 0;
  display: grid;
  grid-template-rows: repeat(2, var(--boss-small-card-height));
  align-content: start;
  justify-content: start;
  column-gap: 0;
  row-gap: 7px;
  overflow: auto hidden;
  padding-top: 2px;
  border-top: 1px solid var(--line);
}

.trait-cards {
  display: contents;
}

.support-cards > .boss-small-card,
.trait-cards img {
  width: var(--boss-small-card-width);
  height: var(--boss-small-card-height);
}

.resolution-panel {
  min-height: 0;
  display: grid;
  grid-template-columns: 2fr 3fr;
  gap: 10px;
  padding-top: 10px;
  /* 底下留一点余量：「正在结算」的卡牌下缘别贴着屏幕底边（电视过扫描会直接切掉）。 */
  padding-bottom: 18px;
  border-top: 1px solid var(--line);
}

.aibp-slot {
  min-width: 0;
  min-height: 0;
  height: 100%;
  display: grid;
  grid-template-rows: auto minmax(0, 1fr);
  gap: 8px;
  overflow: hidden;
}

.pending-cards {
  position: relative;
  z-index: 2;
  min-width: 0;
  min-height: 0;
  margin-top: calc((var(--boss-small-card-height) + 23px) * -1);
  display: grid;
  background: var(--panel);
}

.pending-card {
  min-width: 0;
  min-height: 0;
  display: grid;
  grid-template-rows: auto minmax(0, 1fr);
  gap: 5px;
}

.pending-card > span {
  color: var(--gold);
  font-size: 12px;
  font-weight: 900;
  text-align: center;
}

.current-card {
  position: relative;
  min-width: 0;
  min-height: 0;
  display: grid;
  place-items: center;
  overflow: hidden;
  background: var(--panel);
}

/* 「正在结算」的卡牌必须按框缩放：图片改成绝对定位铺满整个框，再用 object-fit: contain。
   静态定位时图片会按自身比例把所在的行撑高（例：框 353×300，图被撑成 353×495），
   多出来的下半张就被 .current-card 的 overflow:hidden 裁掉 —— 决战版图缩小、侧栏变宽时
   最容易出现，看起来就是「正在结算的卡下半段在屏幕外」。 */
.current-card img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.empty-card,
.empty-list {
  color: var(--muted);
  font-size: 12px;
  text-align: center;
}

.battle-facts {
  min-width: 0;
  display: grid;
  align-content: start;
  gap: 5px;
  font-size: clamp(10px, .9vw, 13px);
}

.battle-facts div {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 8px;
  padding-bottom: 4px;
  border-bottom: 1px solid var(--line);
}

.battle-facts b { color: var(--gold); }
.battle-facts span { min-width: 0; overflow-wrap: anywhere; }

.damage-cards {
  min-width: 0;
  min-height: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(38px, 1fr));
  grid-auto-rows: minmax(58px, 1fr);
  gap: 5px;
  overflow: hidden auto;
}

.battle-board-stage {
  min-width: 0;
  min-height: 0;
  display: grid;
  place-items: center;
  overflow: auto;
  padding: clamp(6px, 1.1vmin, 12px);
  background: var(--panel);
}

.battle-board-frame {
  flex: none;
  position: relative;
  width: min(100%, calc((var(--battle-safe-height) - clamp(12px, 2.2vmin, 24px)) * 1.4285714286 * var(--battle-scale)));
  aspect-ratio: 10 / 7;
  filter: none;
}

.battle-board-grid {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: none;
  pointer-events: none;
  background-image:
    linear-gradient(to right, rgba(239, 68, 58, .78) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(239, 68, 58, .78) 1px, transparent 1px);
  background-size: 5% 100%, 100% calc(100% / 14);
}

.battle-board-frame.coordinates-visible .battle-board-grid {
  display: block;
}

.battle-board-image {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  object-fit: contain;
}

.battle-terrain-layer {
  position: absolute;
  inset: 0;
  z-index: 2;
  overflow: hidden;
  pointer-events: none;
}

.battle-start-layer {
  position: absolute;
  inset: 0;
  z-index: 3;
  overflow: hidden;
  pointer-events: none;
}

/* 视线 / 射程 / 距离标注层 —— 与 aibp/battle_map_control.css 保持同一套类名和配色，
   因为两端都由 battle_los.js 的 renderLosOverlay 绘制，样式必须对得上。
   层级放在地形(2)之上、起始位(3)之下：标注盖住地形，但不遮挡 A / T 起始标记。 */
.battle-map-los-layer {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 2;
  overflow: hidden;
  pointer-events: none;
}
.battle-map-los-layer > div { position: absolute; }
.battle-map-los-visible {
  background: rgba(74, 222, 128, .30);
  box-shadow: inset 0 0 0 1px rgba(74, 222, 128, .55);
}
.battle-map-los-blocked { background: transparent; }
.battle-map-los-layer.dim-blocked .battle-map-los-blocked {
  background: rgba(4, 6, 6, .62);
}
.battle-map-los-source {
  z-index: 5;
  border-radius: 999px;
  background: rgba(56, 132, 255, .95);
  box-shadow: 0 0 0 2px rgba(190, 220, 255, .95), 0 0 12px rgba(56, 132, 255, .72);
  transform: translate(-50%, -50%) scale(.48);
}
.battle-map-los-obscuring {
  box-shadow: inset 0 0 0 2px rgba(250, 204, 21, .85);
  background: rgba(250, 204, 21, .12);
}
.battle-map-los-cloud {
  box-shadow: inset 0 0 0 2px rgba(96, 180, 240, .95);
  background: rgba(96, 180, 240, .18);
}
.battle-map-los-in-range {
  box-shadow: inset 0 0 0 2px rgba(180, 132, 255, .75);
}
.battle-map-los-in-range.has-los {
  box-shadow: inset 0 0 0 2px rgba(200, 160, 255, .98);
  background: rgba(180, 132, 255, .16);
}
.battle-map-los-move-target {
  box-sizing: border-box;
  z-index: 6;
  border-radius: 999px;
  background: rgba(255, 255, 255, .96);
  box-shadow: 0 0 0 2px rgba(20, 20, 20, .88), 0 0 12px rgba(255, 255, 255, .58);
  transform: translate(-50%, -50%) scale(.48);
}
.battle-map-los-move-step {
  box-sizing: border-box;
  z-index: 4;
  pointer-events: none;
}
.battle-map-los-move-a {
  background: rgba(239, 68, 58, .28);
  box-shadow: inset 0 0 0 2px rgba(239, 68, 58, .88);
}
.battle-map-los-move-b {
  background: rgba(250, 204, 21, .30);
  box-shadow: inset 0 0 0 2px rgba(250, 204, 21, .94);
}
.battle-map-los-move-overlap {
  background: rgba(251, 146, 60, .34);
  box-shadow: inset 0 0 0 2px rgba(251, 146, 60, .96);
}
.battle-map-los-move-final {
  box-sizing: border-box;
  z-index: 6;
  border-radius: 999px;
  transform: translate(-50%, -50%) scale(.48);
}
.battle-map-los-move-final.battle-map-los-move-a {
  background: rgba(239, 68, 58, .96);
  box-shadow: 0 0 0 2px rgba(255, 235, 235, .92), 0 0 12px rgba(239, 68, 58, .76);
}
.battle-map-los-move-final.battle-map-los-move-b {
  background: rgba(250, 204, 21, .96);
  box-shadow: 0 0 0 2px rgba(255, 250, 205, .92), 0 0 12px rgba(250, 204, 21, .76);
}
.battle-map-los-move-final.battle-map-los-move-overlap {
  background: rgba(251, 146, 60, .96);
  box-shadow: 0 0 0 2px rgba(255, 238, 214, .92), 0 0 12px rgba(251, 146, 60, .76);
}
.battle-map-los-move-facing {
  position: absolute;
  z-index: 6;
  font-size: clamp(11px, 1.05vw, 22px);
  line-height: 1;
  text-shadow: 0 0 3px #000, 0 1px 3px #000;
  transform-origin: center;
  pointer-events: none;
}
.battle-map-los-move-facing-a { color: #ef4444; }
.battle-map-los-move-facing-b { color: #facc15; }
.battle-map-los-move-facing-overlap { color: #fb923c; }
/* 距离数字贴右下角，避开居中的坐标标签，两组字不会重叠。 */
.battle-map-los-distance {
  display: grid;
  place-items: end;
  padding: 0 2px 1px 0;
  color: rgba(255, 255, 255, .82);
  font-size: clamp(7px, .66vw, 13px);
  font-weight: 700;
  line-height: 1;
  text-shadow: 0 1px 2px #000, 0 -1px 2px #000, 1px 0 2px #000, -1px 0 2px #000;
  white-space: nowrap;
}
.battle-map-los-distance.in-range { color: rgba(224, 205, 255, .98); }
.battle-map-los-distance.is-source { color: rgba(190, 220, 255, .95); }
/* 朝向箭头：painter 用内联 left/top/transform 定位，这里只管样式。 */
.battle-map-los-facing {
  position: absolute;
  color: #ffd166;
  font-size: clamp(11px, 1.05vw, 22px);
  line-height: 1;
  text-shadow: 0 0 3px #000, 0 1px 3px #000;
  transform-origin: center;
  pointer-events: none;
  z-index: 3;
}
.battle-map-los-blindspot {
  box-shadow: inset 0 0 0 2px rgba(255, 255, 255, .6);
  background: repeating-linear-gradient(
    45deg,
    rgba(12, 14, 18, .78) 0 5px,
    rgba(190, 190, 200, .5) 5px 10px
  );
}
.battle-map-los-wall {
  background: rgba(239, 68, 58, .95);
  box-shadow: 0 0 4px rgba(239, 68, 58, .9);
}
.battle-map-los-wall.horizontal { height: 3px; transform: translateY(-1.5px); }
.battle-map-los-wall.vertical { width: 3px; transform: translateX(-1.5px); }
.battle-map-los-wall-ignored {
  background: none;
  box-shadow: none;
  opacity: .75;
}
.battle-map-los-wall-ignored.horizontal {
  background-image: linear-gradient(
    to right, rgba(239, 68, 58, .9) 0 6px, transparent 6px 12px);
  background-size: 12px 3px;
}
.battle-map-los-wall-ignored.vertical {
  background-image: linear-gradient(
    to bottom, rgba(239, 68, 58, .9) 0 6px, transparent 6px 12px);
  background-size: 3px 12px;
}

.battle-coordinate-layer {
  position: absolute;
  inset: 0;
  z-index: 4;
  display: grid;
  grid-template-columns: repeat(20, minmax(0, 1fr));
  grid-template-rows: repeat(14, minmax(0, 1fr));
  overflow: hidden;
  pointer-events: none;
}

.battle-coordinate {
  display: grid;
  place-items: center;
  min-width: 0;
  min-height: 0;
  color: rgba(255, 255, 255, .9);
  font-size: clamp(7px, .72vw, 12px);
  font-weight: 900;
  line-height: 1;
  text-align: center;
  text-shadow: 0 1px 2px #000, 0 -1px 2px #000;
  white-space: nowrap;
}

.battle-terrain-tile {
  position: absolute;
  display: block;
  object-fit: contain;
  transform-origin: center;
  filter: drop-shadow(0 1px 1px rgba(0, 0, 0, .28));
}

.battle-terrain-light-range {
  position: absolute;
  box-sizing: border-box;
  pointer-events: none;
  background: rgba(255, 231, 131, .24);
  box-shadow: inset 0 0 0 1px rgba(255, 244, 190, .86), 0 0 10px rgba(255, 210, 86, .68);
  mix-blend-mode: screen;
}

.battle-terrain-special {
  position: absolute;
  display: grid;
  place-items: center;
  transform-origin: center;
  border: 2px solid color-mix(in srgb, var(--battle-special-color, #f0c15d) 72%, #fff 28%);
  border-radius: 3px;
  background:
    radial-gradient(circle at 50% 42%, rgba(255, 255, 255, .34), transparent 30%),
    linear-gradient(180deg, color-mix(in srgb, var(--battle-special-color, #f0c15d) 82%, #fff 18%), var(--battle-special-color, #f0c15d));
  box-shadow:
    inset 0 0 0 2px rgba(0, 0, 0, .44),
    0 0 0 1px rgba(255, 255, 255, .28),
    0 0 14px var(--battle-special-glow, rgba(240, 193, 93, .5));
  filter: drop-shadow(0 1px 1px rgba(0, 0, 0, .28));
}

.battle-terrain-special-label {
  display: grid;
  place-items: center;
  width: 70%;
  height: 70%;
  border: 2px solid rgba(255, 255, 255, .86);
  border-radius: 999px;
  color: #fff;
  font-size: clamp(10px, 1.2vw, 18px);
  font-weight: 950;
  line-height: 1;
  text-shadow: 0 1px 3px rgba(0, 0, 0, .86);
  background: rgba(0, 0, 0, .22);
}

.battle-start-marker {
  position: absolute;
  display: grid;
  place-items: center;
  transform: translate(-50%, -50%);
  border: 2px solid rgba(255, 255, 255, .92);
  color: #fff;
  font-weight: 950;
  line-height: 1;
  text-shadow: 0 1px 3px #000;
  box-shadow: 0 3px 10px rgba(0, 0, 0, .58);
}

.battle-start-marker.apostle {
  border-color: #f36f62;
  background: rgba(146, 31, 25, .78);
  font-size: clamp(12px, 1.7vw, 25px);
}

.battle-start-facing {
  position: absolute;
  left: 50%;
  top: 50%;
  color: #ffd166;
  font-size: .72em;
  line-height: 1;
  text-shadow: 0 1px 3px #000;
  transform-origin: center;
}

.battle-start-marker.titan {
  border-radius: 999px;
  border-color: #73d2c1;
  background: rgba(18, 94, 82, .82);
  font-size: clamp(8px, .9vw, 13px);
}

@media (max-aspect-ratio: 4 / 3) {
  .battle-view {
    grid-template-columns: minmax(230px, 1fr) minmax(220px, var(--battle-board-column));
  }
}

.screen-footer {
  flex-wrap: wrap;
  justify-content: flex-start;
}

.screen-footer span:last-child { margin-left: auto; }

@media (max-width: 640px) {
  .screen-head { align-items: flex-start; }
  .screen-meta { display: grid; justify-items: end; }
  .screen-footer span:last-child { width: 100%; margin-left: 0; }
}
