:root,
html[data-theme="zitan"] {
  --ink: #1c1a17;
  --ink-soft: #3a342c;
  --cinnabar: #9a2b2b;
  --cinnabar-deep: #6e1c1c;
  --paper: #f2e8d5;
  --paper-deep: #e6d7bc;
  --board-line: #d4b896;
  --wood-rim-label: #d4b896;
  --gold-mute: #b8965a;
  --mist: rgba(40, 36, 30, 0.06);
  --shadow: rgba(20, 10, 12, 0.38);
  /* 紫檀：盘缘 / 盘面 / 棋子 */
  --wood-frame-border: rgba(12, 4, 6, 0.75);
  --wood-frame-base: #241216;
  --wood-frame-grad: linear-gradient(155deg, #3a1e24 0%, #241216 50%, #160a0e 100%);
  --wood-frame-sheen: linear-gradient(
    125deg,
    rgba(90, 45, 52, 0.45) 0%,
    transparent 35%,
    transparent 60%,
    rgba(20, 8, 10, 0.5) 100%
  );
  --wood-frame-spot: radial-gradient(ellipse 120% 80% at 30% 20%, rgba(80, 40, 48, 0.35), transparent 50%);
  --wood-frame-inset-hi: rgba(160, 100, 110, 0.14);
  --wood-frame-white: rgba(170, 120, 80, 0.28);
  --wood-frame-white-inner: rgba(20, 6, 8, 0.35);
  --wood-board-base: #4a3034;
  --wood-board-grad: linear-gradient(168deg, #5a3a3e 0%, #4a3034 40%, #3a2428 75%, #322022 100%);
  --wood-board-spot-hi: radial-gradient(ellipse 100% 80% at 18% 12%, rgba(110, 65, 70, 0.55), transparent 55%);
  --wood-board-spot-lo: radial-gradient(ellipse 90% 70% at 85% 88%, rgba(25, 10, 14, 0.55), transparent 50%);
  --wood-board-edge: rgba(20, 8, 10, 0.5);
  --wood-board-inset: inset 0 0 90px rgba(8, 2, 4, 0.4), inset 0 0 0 1px rgba(140, 90, 95, 0.1);
  --wood-board-vignette: linear-gradient(90deg, rgba(8, 2, 4, 0.28), transparent 14%, transparent 86%, rgba(8, 2, 4, 0.28)),
    linear-gradient(0deg, rgba(8, 2, 4, 0.22), transparent 12%, transparent 88%, rgba(8, 2, 4, 0.2));
  --wood-board-glow: radial-gradient(ellipse 70% 50% at 40% 30%, rgba(160, 100, 105, 0.12), transparent 60%);
  --wood-grain-light: #6b4044;
  /*
   * ========== 棋子风格：颜色变量（改这里 = 换整套木色）==========
   * 切换主题：html[data-theme="zitan"|"huanghuali"|"baixiangmu"|"shuimo"]（侧栏「主题」按钮 / localStorage）
   *
   * --piece-wood-hi   受光最亮木色 → 顶面高光、环脊亮边
   * --piece-wood-mid  主木色       → 字面底板、侧壁中间调
   * --piece-wood-lo   最暗木色     → 侧壁外缘、落盘影、阴刻深边
   * --piece-ivory     黑方字色     → 紫檀用牙白；黄花梨用近墨色（见下方主题覆盖）
   * --piece-red / -stroke  红方阴刻字色与描边
   * --piece-cast-*    落盘投影浓淡（near 近影 / far 远影 / soft 柔边）
   * --font-piece      棋面字体（马善政）
   */
  --piece-wood-hi: #6e454a;
  --piece-wood-mid: #4a3034;
  --piece-wood-lo: #2e1c20;
  --piece-ivory: #e8d5b5;
  --piece-spot-hi: rgba(140, 90, 95, 0.55);
  --piece-spot-lo: color-mix(in srgb, var(--piece-wood-lo) 55%, transparent);
  --piece-rim-1: color-mix(in srgb, var(--piece-wood-hi) 35%, var(--piece-wood-mid) 65%);
  --piece-rim-2: var(--piece-wood-mid);
  --piece-rim-3: color-mix(in srgb, var(--piece-wood-mid) 40%, var(--piece-wood-lo) 60%);
  --piece-rim-4: var(--piece-wood-lo);
  --piece-cast-near: color-mix(in srgb, var(--piece-wood-lo) 42%, transparent);
  --piece-cast-far: color-mix(in srgb, var(--piece-wood-mid) 28%, transparent);
  --piece-cast-soft: color-mix(in srgb, var(--piece-wood-lo) 32%, transparent);
  --piece-inset-lo: color-mix(in srgb, var(--piece-wood-lo) 48%, transparent);
  --piece-inset-hi: rgba(170, 110, 120, 0.28);
  --piece-edge: color-mix(in srgb, var(--piece-wood-lo) 55%, transparent);
  --piece-red: #c43c3c;
  --piece-red-stroke: #9a2222;
  --font-piece: "Ma Shan Zheng", serif;
  --font-ui: "ZCOOL XiaoWei", "Ma Shan Zheng", serif;
  --font-title: "Ma Shan Zheng", serif;
}

/*
 * 黄花梨主题色（参考木纹，整体提亮偏白）
 * 高光 #f5e0c0 / 主色 #e8c090～#d4a060 / 深纹保留较浅褐 #8a5a32
 */
html[data-theme="huanghuali"] {
  --shadow: rgba(90, 55, 25, 0.28);
  --board-line: #7a4e28;
  --wood-rim-label: #f2e0c4;
  --gold-mute: #e0b878;
  --wood-frame-border: rgba(100, 60, 28, 0.55);
  --wood-frame-base: #a07040;
  --wood-frame-grad: linear-gradient(155deg, #d4a060 0%, #b88848 48%, #8a5a30 100%);
  --wood-frame-sheen: linear-gradient(
    125deg,
    rgba(255, 236, 210, 0.5) 0%,
    transparent 36%,
    transparent 62%,
    rgba(100, 60, 28, 0.35) 100%
  );
  --wood-frame-spot: radial-gradient(ellipse 120% 80% at 28% 18%, rgba(255, 220, 170, 0.42), transparent 52%);
  --wood-frame-inset-hi: rgba(255, 245, 230, 0.35);
  --wood-frame-white: rgba(180, 120, 70, 0.32);
  --wood-frame-white-inner: rgba(100, 60, 28, 0.22);
  /* 盘面：浅蜜金，偏白亮 */
  --wood-board-base: #e8c090;
  --wood-board-grad: linear-gradient(168deg, #f5e0c0 0%, #e8c090 38%, #d4a060 72%, #c49050 100%);
  --wood-board-spot-hi: radial-gradient(ellipse 100% 80% at 18% 12%, rgba(255, 248, 235, 0.7), transparent 55%);
  --wood-board-spot-lo: radial-gradient(ellipse 90% 70% at 85% 88%, rgba(160, 100, 50, 0.22), transparent 50%);
  --wood-board-edge: rgba(140, 85, 40, 0.35);
  --wood-board-inset: inset 0 0 90px rgba(160, 100, 50, 0.12), inset 0 0 0 1px rgba(255, 248, 235, 0.35);
  --wood-board-vignette: linear-gradient(90deg, rgba(160, 100, 50, 0.1), transparent 14%, transparent 86%, rgba(160, 100, 50, 0.1)),
    linear-gradient(0deg, rgba(160, 100, 50, 0.08), transparent 12%, transparent 88%, rgba(160, 100, 50, 0.08));
  --wood-board-glow: radial-gradient(ellipse 70% 50% at 40% 30%, rgba(255, 248, 235, 0.35), transparent 60%);
  --wood-grain-light: #e8c090;
  /* 棋子：浅蜜金面，侧壁略深但仍偏亮 */
  --piece-wood-hi: #f5e0c0;
  --piece-wood-mid: #e0b070;
  --piece-wood-lo: #a07040;
  --piece-ivory: #3a2818;
  --piece-spot-hi: rgba(255, 248, 235, 0.65);
  --piece-spot-lo: color-mix(in srgb, var(--piece-wood-lo) 35%, transparent);
  --piece-rim-1: color-mix(in srgb, var(--piece-wood-hi) 40%, var(--piece-wood-mid) 60%);
  --piece-rim-2: var(--piece-wood-mid);
  --piece-rim-3: color-mix(in srgb, var(--piece-wood-mid) 45%, var(--piece-wood-lo) 55%);
  --piece-rim-4: var(--piece-wood-lo);
  --piece-cast-near: color-mix(in srgb, var(--piece-wood-lo) 32%, transparent);
  --piece-cast-far: color-mix(in srgb, var(--piece-wood-mid) 22%, transparent);
  --piece-cast-soft: color-mix(in srgb, var(--piece-wood-lo) 24%, transparent);
  --piece-inset-lo: color-mix(in srgb, var(--piece-wood-lo) 32%, transparent);
  --piece-inset-hi: rgba(255, 248, 235, 0.4);
  --piece-edge: color-mix(in srgb, var(--piece-wood-lo) 40%, transparent);
  --piece-red: #c43030;
  --piece-red-stroke: #9a1c1c;
}

/*
 * 白橡木：冷调浅米灰白，直纹感；谱线深灰褐
 * 高光 #f7f4ee / 主色 #e8e2d6～#cfc6b6 / 侧壁 #9a9080
 */
html[data-theme="baixiangmu"] {
  --shadow: rgba(60, 55, 48, 0.28);
  --board-line: #5c5346;
  --wood-rim-label: #f0ebe3;
  --gold-mute: #a89c8a;
  --wood-frame-border: rgba(70, 64, 56, 0.5);
  --wood-frame-base: #9a9080;
  --wood-frame-grad: linear-gradient(155deg, #cfc6b6 0%, #a89c8a 48%, #7a7164 100%);
  --wood-frame-sheen: linear-gradient(
    125deg,
    rgba(255, 252, 248, 0.55) 0%,
    transparent 36%,
    transparent 62%,
    rgba(70, 64, 56, 0.32) 100%
  );
  --wood-frame-spot: radial-gradient(ellipse 120% 80% at 28% 18%, rgba(255, 250, 245, 0.4), transparent 52%);
  --wood-frame-inset-hi: rgba(255, 255, 252, 0.4);
  --wood-frame-white: rgba(140, 130, 118, 0.35);
  --wood-frame-white-inner: rgba(70, 64, 56, 0.22);
  --wood-board-base: #e4ddd2;
  --wood-board-grad: linear-gradient(168deg, #f7f4ee 0%, #e8e2d6 40%, #d4ccc0 74%, #c4bab0 100%);
  --wood-board-spot-hi: radial-gradient(ellipse 100% 80% at 18% 12%, rgba(255, 255, 252, 0.75), transparent 55%);
  --wood-board-spot-lo: radial-gradient(ellipse 90% 70% at 85% 88%, rgba(120, 110, 98, 0.2), transparent 50%);
  --wood-board-edge: rgba(100, 92, 82, 0.35);
  --wood-board-inset: inset 0 0 90px rgba(120, 110, 98, 0.1), inset 0 0 0 1px rgba(255, 255, 252, 0.4);
  --wood-board-vignette: linear-gradient(90deg, rgba(120, 110, 98, 0.1), transparent 14%, transparent 86%, rgba(120, 110, 98, 0.1)),
    linear-gradient(0deg, rgba(120, 110, 98, 0.08), transparent 12%, transparent 88%, rgba(120, 110, 98, 0.08));
  --wood-board-glow: radial-gradient(ellipse 70% 50% at 40% 30%, rgba(255, 255, 252, 0.4), transparent 60%);
  --wood-grain-light: #e8e2d6;
  --piece-wood-hi: #f7f4ee;
  --piece-wood-mid: #ddd5c8;
  --piece-wood-lo: #8a8070;
  --piece-ivory: #2c2820;
  --piece-spot-hi: rgba(255, 255, 252, 0.7);
  --piece-spot-lo: color-mix(in srgb, var(--piece-wood-lo) 32%, transparent);
  --piece-rim-1: color-mix(in srgb, var(--piece-wood-hi) 40%, var(--piece-wood-mid) 60%);
  --piece-rim-2: var(--piece-wood-mid);
  --piece-rim-3: color-mix(in srgb, var(--piece-wood-mid) 45%, var(--piece-wood-lo) 55%);
  --piece-rim-4: var(--piece-wood-lo);
  --piece-cast-near: color-mix(in srgb, var(--piece-wood-lo) 30%, transparent);
  --piece-cast-far: color-mix(in srgb, var(--piece-wood-mid) 20%, transparent);
  --piece-cast-soft: color-mix(in srgb, var(--piece-wood-lo) 22%, transparent);
  --piece-inset-lo: color-mix(in srgb, var(--piece-wood-lo) 30%, transparent);
  --piece-inset-hi: rgba(255, 255, 252, 0.45);
  --piece-edge: color-mix(in srgb, var(--piece-wood-lo) 38%, transparent);
  --piece-red: #b82828;
  --piece-red-stroke: #8e1a1a;
}

/*
 * 水墨：宣纸浅底 + 墨色框线；棋子如白玉印面，朱砂 / 浓墨字
 * 高光 #faf8f2 / 主色 #ebe6dc～#d4cfc4 / 墨缘 #5a5650
 */
html[data-theme="shuimo"] {
  --ink: #1a1917;
  --ink-soft: #3c3a36;
  --cinnabar: #8e2e28;
  --cinnabar-deep: #5c1c18;
  --paper: #f2eee6;
  --paper-deep: #e4dfd4;
  --shadow: rgba(30, 28, 26, 0.22);
  --board-line: #2a2824;
  --wood-rim-label: #e8e4dc;
  --gold-mute: #6a6660;
  --mist: rgba(40, 38, 34, 0.05);
  --wood-frame-border: rgba(20, 18, 16, 0.65);
  --wood-frame-base: #2e2c2a;
  --wood-frame-grad: linear-gradient(155deg, #4a4742 0%, #2e2c2a 48%, #1a1917 100%);
  --wood-frame-sheen: linear-gradient(
    125deg,
    rgba(255, 252, 246, 0.12) 0%,
    transparent 38%,
    transparent 58%,
    rgba(0, 0, 0, 0.45) 100%
  );
  --wood-frame-spot: radial-gradient(ellipse 120% 80% at 28% 18%, rgba(90, 86, 80, 0.35), transparent 52%);
  --wood-frame-inset-hi: rgba(220, 216, 208, 0.12);
  --wood-frame-white: rgba(80, 76, 70, 0.4);
  --wood-frame-white-inner: rgba(12, 10, 8, 0.4);
  --wood-board-base: #ebe6dc;
  --wood-board-grad: linear-gradient(168deg, #faf8f2 0%, #efeae0 42%, #e0dacd 78%, #d4cec2 100%);
  --wood-board-spot-hi: radial-gradient(ellipse 100% 80% at 18% 12%, rgba(255, 254, 250, 0.85), transparent 55%);
  --wood-board-spot-lo: radial-gradient(ellipse 90% 70% at 85% 88%, rgba(60, 56, 50, 0.12), transparent 50%);
  --wood-board-edge: rgba(40, 36, 32, 0.28);
  --wood-board-inset: inset 0 0 100px rgba(50, 46, 40, 0.08), inset 0 0 0 1px rgba(255, 254, 250, 0.5);
  --wood-board-vignette: linear-gradient(90deg, rgba(40, 36, 32, 0.08), transparent 16%, transparent 84%, rgba(40, 36, 32, 0.08)),
    linear-gradient(0deg, rgba(40, 36, 32, 0.06), transparent 14%, transparent 86%, rgba(40, 36, 32, 0.06));
  --wood-board-glow: radial-gradient(ellipse 70% 50% at 40% 30%, rgba(255, 254, 250, 0.35), transparent 60%);
  --wood-grain-light: #efeae0;
  --piece-wood-hi: #faf8f2;
  --piece-wood-mid: #e8e2d6;
  --piece-wood-lo: #5a5650;
  --piece-ivory: #1a1917;
  --piece-spot-hi: rgba(255, 254, 250, 0.75);
  --piece-spot-lo: color-mix(in srgb, var(--piece-wood-lo) 28%, transparent);
  --piece-rim-1: color-mix(in srgb, var(--piece-wood-hi) 45%, var(--piece-wood-mid) 55%);
  --piece-rim-2: var(--piece-wood-mid);
  --piece-rim-3: color-mix(in srgb, var(--piece-wood-mid) 50%, var(--piece-wood-lo) 50%);
  --piece-rim-4: var(--piece-wood-lo);
  --piece-cast-near: color-mix(in srgb, var(--piece-wood-lo) 26%, transparent);
  --piece-cast-far: color-mix(in srgb, var(--piece-wood-mid) 18%, transparent);
  --piece-cast-soft: color-mix(in srgb, var(--piece-wood-lo) 20%, transparent);
  --piece-inset-lo: color-mix(in srgb, var(--piece-wood-lo) 28%, transparent);
  --piece-inset-hi: rgba(255, 254, 250, 0.5);
  --piece-edge: color-mix(in srgb, var(--piece-wood-lo) 36%, transparent);
  --piece-red: #a83228;
  --piece-red-stroke: #7a2018;
}

.svg-defs {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  min-height: 100%;
  min-height: 100dvh;
}

body {
  font-family: var(--font-ui);
  color: var(--ink);
  background: #d8cbb3;
  overflow-x: hidden;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

.paper-bg {
  position: fixed;
  inset: 0;
  z-index: -2;
  background:
    radial-gradient(ellipse 90% 70% at 15% 10%, rgba(255, 252, 245, 0.55), transparent 55%),
    radial-gradient(ellipse 70% 60% at 90% 85%, rgba(160, 140, 110, 0.22), transparent 50%),
    linear-gradient(165deg, #efe4d0 0%, #e2d3b8 45%, #d5c4a6 100%);
}

.paper-bg::after {
  content: "";
  position: absolute;
  inset: 0;
  opacity: 0.35;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.5'/%3E%3C/svg%3E");
  mix-blend-mode: multiply;
  pointer-events: none;
}

.ink-wash {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(circle at 8% 70%, rgba(28, 26, 23, 0.08), transparent 28%),
    radial-gradient(circle at 92% 18%, rgba(28, 26, 23, 0.06), transparent 26%);
}

.stage {
  width: min(1280px, 100%);
  margin: 0 auto;
  padding: 2.2rem 1.25rem 3rem;
  padding-left: max(1.25rem, env(safe-area-inset-left));
  padding-right: max(1.25rem, env(safe-area-inset-right));
  padding-bottom: max(3rem, calc(1.5rem + env(safe-area-inset-bottom)));
}

.masthead {
  text-align: center;
  margin-bottom: 1.6rem;
  position: relative;
}

.masthead .seal {
  position: absolute;
  left: 50%;
  top: -0.35rem;
  transform: translateX(-7.5rem) rotate(-8deg);
  width: 2.1rem;
  height: 2.1rem;
  margin: 0;
  display: grid;
  place-items: center;
  border: 1.5px solid var(--cinnabar);
  color: var(--cinnabar);
  font-family: var(--font-title);
  font-size: 1.15rem;
  line-height: 1;
  opacity: 0.85;
  box-shadow: inset 0 0 0 1px rgba(154, 43, 43, 0.25);
}

.masthead h1 {
  margin: 0;
  font-family: var(--font-title);
  font-size: clamp(2.6rem, 6vw, 3.6rem);
  font-weight: 400;
  letter-spacing: 0.35em;
  text-indent: 0.35em;
  color: var(--ink);
}

.masthead .subtitle {
  margin: 0.35rem 0 0;
  font-size: 0.92rem;
  letter-spacing: 0.42em;
  text-indent: 0.42em;
  color: var(--ink-soft);
  opacity: 0.72;
}

.board-panel {
  display: grid;
  /* 棋盘 | 模式列 | 云库列（与模式顶对齐） */
  grid-template-columns: minmax(0, 1fr) 180px minmax(160px, 220px);
  gap: 1.5rem;
  align-items: start;
  justify-content: center;
}

.file-labels {
  /* 紫檀木缘内、白框外；与盘面竖线 10%…90% 对齐 */
  position: absolute;
  left: 1.2rem;
  right: 1.2rem;
  z-index: 4;
  display: grid;
  grid-template-columns: 5% repeat(9, 10%) 5%;
  align-items: center;
  justify-items: center;
  font-family: var(--font-ui);
  color: var(--wood-rim-label);
  opacity: 0.82;
  pointer-events: none;
  user-select: none;
}

.file-labels::before,
.file-labels::after {
  content: "";
}

.file-labels span {
  line-height: 1;
}

.file-labels-black {
  top: 0.28rem;
}

.file-labels-black span {
  font-size: 0.9rem;
}

.file-labels-red {
  bottom: 0.28rem;
}

.file-labels-red span {
  font-size: 0.84rem;
}

.board-frame {
  justify-self: center;
  /* 盘面略放大，配合缩小后的棋子，底排仍留细缝且不显空疏 */
  width: min(100%, 640px);
  /* 上下加厚木缘，供谱线落在白框外 */
  padding: 1.45rem 1.2rem;
  border-radius: 6px;
  position: relative;
  border: 1px solid var(--wood-frame-border);
  background-color: var(--wood-frame-base);
  background-image:
    var(--wood-frame-sheen),
    var(--wood-frame-spot),
    var(--wood-frame-grad);
  box-shadow:
    0 22px 48px var(--shadow),
    inset 0 1px 0 var(--wood-frame-inset-hi),
    inset 0 -3px 10px rgba(0, 0, 0, 0.5);
  transition: background-color 0.35s ease, border-color 0.35s ease;
}

/* 盘面白框：包住盘面，谱线在其外侧木缘上 */
.board-frame::before {
  content: "";
  position: absolute;
  top: 1.2rem;
  right: 0.5rem;
  bottom: 1.2rem;
  left: 0.5rem;
  border: 1px solid var(--wood-frame-white);
  border-radius: 2px;
  pointer-events: none;
  box-shadow: inset 0 0 0 1px var(--wood-frame-white-inner);
  z-index: 3;
}

/* 外框真实木纹：拉长噪点，不做 repeating 条纹 */
.board-frame::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  opacity: 0.55;
  mix-blend-mode: soft-light;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='400' height='400'%3E%3Cfilter id='f'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.012 0.08' numOctaves='3' seed='7' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0.55 0 0 0 0 0.28 0 0 0 0 0.3 0 0 0 0.45 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23f)'/%3E%3C/svg%3E");
  background-size: cover;
}

.board {
  position: relative;
  width: 100%;
  aspect-ratio: 8 / 9;
  color: var(--board-line);
  overflow: hidden;
  user-select: none;
  touch-action: manipulation;
  border: 1px solid var(--wood-board-edge);
  box-shadow: var(--wood-board-inset);
  background-color: var(--wood-board-base);
  background-image:
    var(--wood-board-spot-hi),
    var(--wood-board-spot-lo),
    var(--wood-board-grad);
  transition: background-color 0.35s ease, color 0.35s ease, border-color 0.35s ease;
}

/* 主木纹：拉长的有机噪点（仿年轮纤维，非等距条纹） */
.board::before {
  content: "";
  position: absolute;
  inset: -2%;
  pointer-events: none;
  opacity: 0.7;
  mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='600' height='600'%3E%3Cfilter id='w'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.009 0.055' numOctaves='4' seed='23' stitchTiles='stitch'/%3E%3CfeDiffuseLighting surfaceScale='2.2' diffuseConstant='1.05' lighting-color='%236b4044'%3E%3CfeDistantLight azimuth='45' elevation='55'/%3E%3C/feDiffuseLighting%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23w)'/%3E%3C/svg%3E");
  background-size: 120% 100%;
  background-position: center;
}

html[data-theme="huanghuali"] .board::before {
  opacity: 0.45;
  mix-blend-mode: soft-light;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='600' height='600'%3E%3Cfilter id='w'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.008 0.05' numOctaves='4' seed='29' stitchTiles='stitch'/%3E%3CfeDiffuseLighting surfaceScale='1.8' diffuseConstant='1.15' lighting-color='%23f0d4a8'%3E%3CfeDistantLight azimuth='45' elevation='58'/%3E%3C/feDiffuseLighting%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23w)'/%3E%3C/svg%3E");
}

/* 第二层细纤维 + 包浆光泽 */
.board::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 1;
  opacity: 1;
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='500' height='500'%3E%3Cfilter id='f'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.02 0.12' numOctaves='3' seed='41' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0.15 0 0 0 0 0.06 0 0 0 0 0.08 0 0 0 0.35 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23f)'/%3E%3C/svg%3E"),
    var(--wood-board-glow),
    var(--wood-board-vignette);
  background-size: 100% 100%, auto, auto, auto;
  mix-blend-mode: normal;
}

html[data-theme="huanghuali"] .board::after {
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='500' height='500'%3E%3Cfilter id='f'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.018 0.11' numOctaves='3' seed='47' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0.42 0 0 0 0 0.28 0 0 0 0 0.12 0 0 0 0.22 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23f)'/%3E%3C/svg%3E"),
    var(--wood-board-glow),
    var(--wood-board-vignette);
}

html[data-theme="huanghuali"] .board-frame::after {
  opacity: 0.4;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='400' height='400'%3E%3Cfilter id='f'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.011 0.075' numOctaves='3' seed='11' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0.88 0 0 0 0 0.68 0 0 0 0 0.4 0 0 0 0.32 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23f)'/%3E%3C/svg%3E");
}

.board-lines {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  z-index: 2;
  filter: drop-shadow(0 0.5px 0 rgba(0, 0, 0, 0.35));
}

.board-lines line {
  stroke: currentColor;
  stroke-width: 1.75;
  stroke-linecap: square;
  opacity: 0.78;
}

.board-lines .palace line {
  stroke-width: 1.55;
}

.board-lines .river {
  fill: var(--gold-mute);
  font-family: var(--font-title);
  font-size: 46px;
  letter-spacing: 0.4em;
  opacity: 0.55;
}

html[data-theme="huanghuali"] .board-lines .river {
  fill: #8a5a30;
  opacity: 0.38;
}

html[data-theme="huanghuali"] .board-lines {
  filter: drop-shadow(0 0.5px 0 rgba(255, 248, 235, 0.35));
}

html[data-theme="huanghuali"] body {
  background: #ebdab8;
}

html[data-theme="huanghuali"] .paper-bg {
  background:
    radial-gradient(ellipse 90% 70% at 15% 10%, rgba(255, 252, 245, 0.75), transparent 55%),
    radial-gradient(ellipse 70% 60% at 90% 85%, rgba(220, 180, 120, 0.18), transparent 50%),
    linear-gradient(165deg, #fff8ee 0%, #f5e6c8 45%, #e8d0a8 100%);
}

html[data-theme="baixiangmu"] .board::before {
  opacity: 0.42;
  mix-blend-mode: soft-light;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='600' height='600'%3E%3Cfilter id='w'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.007 0.06' numOctaves='4' seed='33' stitchTiles='stitch'/%3E%3CfeDiffuseLighting surfaceScale='1.6' diffuseConstant='1.12' lighting-color='%23ebe6dc'%3E%3CfeDistantLight azimuth='40' elevation='60'/%3E%3C/feDiffuseLighting%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23w)'/%3E%3C/svg%3E");
}

html[data-theme="baixiangmu"] .board::after {
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='500' height='500'%3E%3Cfilter id='f'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.015 0.14' numOctaves='3' seed='53' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0.35 0 0 0 0 0.32 0 0 0 0 0.28 0 0 0 0.2 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23f)'/%3E%3C/svg%3E"),
    var(--wood-board-glow),
    var(--wood-board-vignette);
}

html[data-theme="baixiangmu"] .board-frame::after {
  opacity: 0.38;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='400' height='400'%3E%3Cfilter id='f'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.01 0.09' numOctaves='3' seed='19' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0.9 0 0 0 0 0.88 0 0 0 0 0.82 0 0 0 0.3 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23f)'/%3E%3C/svg%3E");
}

html[data-theme="baixiangmu"] .board-lines .river {
  fill: #6b6254;
  opacity: 0.4;
}

html[data-theme="baixiangmu"] .board-lines {
  filter: drop-shadow(0 0.5px 0 rgba(255, 255, 252, 0.4));
}

html[data-theme="baixiangmu"] body {
  background: #e6e2da;
}

html[data-theme="baixiangmu"] .paper-bg {
  background:
    radial-gradient(ellipse 90% 70% at 15% 10%, rgba(255, 255, 252, 0.8), transparent 55%),
    radial-gradient(ellipse 70% 60% at 90% 85%, rgba(180, 170, 155, 0.16), transparent 50%),
    linear-gradient(165deg, #faf9f6 0%, #efece6 45%, #e0dbd2 100%);
}

/* 水墨：宣纸纤维 + 淡墨晕染，非木纹 */
html[data-theme="shuimo"] .board::before {
  opacity: 0.55;
  mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='600' height='600'%3E%3Cfilter id='w'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.012 0.018' numOctaves='5' seed='61' stitchTiles='stitch'/%3E%3CfeDiffuseLighting surfaceScale='1.2' diffuseConstant='1.05' lighting-color='%23e8e2d6'%3E%3CfeDistantLight azimuth='50' elevation='65'/%3E%3C/feDiffuseLighting%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23w)'/%3E%3C/svg%3E");
}

html[data-theme="shuimo"] .board::after {
  opacity: 0.9;
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='500' height='500'%3E%3Cfilter id='f'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.025 0.03' numOctaves='4' seed='71' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0.18 0 0 0 0 0.16 0 0 0 0 0.14 0 0 0 0.18 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23f)'/%3E%3C/svg%3E"),
    radial-gradient(ellipse 55% 40% at 72% 22%, rgba(40, 36, 32, 0.07), transparent 70%),
    radial-gradient(ellipse 45% 35% at 18% 78%, rgba(40, 36, 32, 0.05), transparent 65%),
    var(--wood-board-glow),
    var(--wood-board-vignette);
  background-size: 100% 100%, auto, auto, auto, auto;
}

html[data-theme="shuimo"] .board-frame::after {
  opacity: 0.45;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='400' height='400'%3E%3Cfilter id='f'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.02 0.025' numOctaves='3' seed='81' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0.12 0 0 0 0 0.11 0 0 0 0 0.1 0 0 0 0.4 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23f)'/%3E%3C/svg%3E");
}

html[data-theme="shuimo"] .board-lines .river {
  fill: #3a3834;
  opacity: 0.32;
}

html[data-theme="shuimo"] .board-lines {
  filter: drop-shadow(0 0.5px 0 rgba(255, 254, 250, 0.45));
}

html[data-theme="shuimo"] .board-lines line {
  opacity: 0.72;
  stroke-width: 1.55;
}

html[data-theme="shuimo"] body {
  background: #e0dbd2;
}

html[data-theme="shuimo"] .paper-bg {
  background:
    radial-gradient(ellipse 90% 70% at 12% 8%, rgba(255, 254, 250, 0.9), transparent 55%),
    radial-gradient(ellipse 60% 50% at 88% 90%, rgba(50, 46, 40, 0.08), transparent 50%),
    linear-gradient(165deg, #f7f4ee 0%, #ebe6dc 48%, #ddd7cb 100%);
}

.points,
.pieces,
.overlays {
  position: absolute;
  inset: 0;
  z-index: 3;
}

/* 盘面字效（吃子 / 绝杀）：砸入 → 稍停 → 缓慢淡出 */
.board-fx {
  position: absolute;
  inset: 0;
  z-index: 12;
  display: grid;
  place-items: center;
  pointer-events: none;
  visibility: hidden;
}

.board-fx.is-on {
  visibility: visible;
}

.board-fx img {
  width: auto;
  max-width: 48%;
  max-height: 42%;
  object-fit: contain;
  mix-blend-mode: screen;
  filter: contrast(1.12) brightness(1.1);
  transform-origin: center center;
  opacity: 0;
}

/* 吃子图：相对通用 board-fx 缩小 50%（绝杀仍用上面尺寸） */
#captureFx img {
  max-width: 24%;
  max-height: 21%;
}

/* 绝杀图：提亮描边，避免 screen 后在浅色盘上几乎看不见 */
#checkmateFx {
  z-index: 13;
}

#checkmateFx img {
  mix-blend-mode: screen;
  filter: contrast(1.35) brightness(1.85);
}

.board-fx.is-on img {
  /* 0–15% 砸入，15–40% 停留，40–100% 慢慢淡出（总约 2.6s） */
  animation: boardFxInOut 1.5s ease forwards;
}

#checkmateFx.is-on img {
  animation: boardFxInOutBright 1.5s ease forwards;
}

@keyframes boardFxInOut {
  0% {
    opacity: 0;
    transform: scale(1.4);
    filter: contrast(1.12) brightness(2.2);
  }
  12% {
    opacity: 1;
    transform: scale(1);
    filter: contrast(1.12) brightness(1.1);
  }
  43% {
    opacity: 1;
    transform: scale(1);
    filter: contrast(1.12) brightness(1.1);
  }
  100% {
    opacity: 0;
    transform: scale(0.98);
    filter: contrast(1.12) brightness(1.05);
  }
}

@keyframes boardFxInOutBright {
  0% {
    opacity: 0;
    transform: scale(1.45);
    filter: contrast(1.4) brightness(3);
  }
  12% {
    opacity: 1;
    transform: scale(1);
    filter: contrast(1.35) brightness(1.95);
  }
  43% {
    opacity: 1;
    transform: scale(1);
    filter: contrast(1.35) brightness(1.85);
  }
  100% {
    opacity: 0;
    transform: scale(0.98);
    filter: contrast(1.3) brightness(1.5);
  }
}

.pieces {
  z-index: 4;
}

.point {
  position: absolute;
  width: 9.6%;
  height: 8.5%;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  border: none;
  background: transparent;
  padding: 0;
  cursor: pointer;
}

.point:focus-visible {
  outline: 2px solid var(--gold-mute);
  outline-offset: 2px;
}

.marker {
  position: absolute;
  width: 2.2%;
  height: 2%;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  pointer-events: none;
  opacity: 0;
}

.marker.move {
  background: rgba(212, 184, 150, 0.55);
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.25);
  opacity: 1;
}

.marker.capture {
  width: 7.2%;
  height: 6.4%;
  background: transparent;
  border: 2px solid rgba(220, 90, 90, 0.75);
  opacity: 1;
}

.marker.selected {
  width: 8.9%;
  height: 7.91%;
  background: rgba(200, 160, 100, 0.2);
  border: 1.5px solid rgba(212, 184, 150, 0.65);
  opacity: 1;
  animation: breath 2.4s ease-in-out infinite;
}

@keyframes breath {
  0%,
  100% {
    transform: translate(-50%, -50%) scale(1);
    opacity: 0.75;
  }
  50% {
    transform: translate(-50%, -50%) scale(1.06);
    opacity: 1;
  }
}

/*
 * ========== 棋子 DOM / 样式分层（app.js 创建）==========
 *   button.piece.red|black
 *     ├─ span.piece-base     ← 圆柱侧壁（甜甜圈外鼓圈）
 *     └─ span.piece-lift     ← 平整字面
 *          ├─ ::before       ← 字环（阴刻圆线）
 *          ├─ ::after        ← 仅外缘斜切鼓起（中心 mask 挖空）
 *          └─ span.glyph     ← 汉字
 *     · .piece::after        ← 落在盘上的软影（偏右下）
 *
 * 常见调整速查：
 *   棋子大小     → .piece 的 width / height（须保持 宽:高 ≈ 9:8 才正圆）
 *   厚度高低     → .piece-base 的 transform translateY（越大侧壁越高）
 *   侧壁外鼓     → .piece-base 的 left/right 负值（越负越像甜甜圈外扩）
 *   字环远近边   → .piece-lift::before 的 top/right/bottom/left %
 *   字环粗细     → ::before 的 border 宽度
 *   外缘鼓起强弱 → ::after 里 radial 的 62%/72% 等停点 + mask 的 60%/70%
 *   落盘影远近   → .piece::after 的 translate / blur / opacity
 *   字体大小     → .piece-lift 的 font-size
 *   换木色主题   → 改上面 --piece-wood-* 或切换 data-theme
 */

/* 外层定位：交叉点居中。盘宽竖线间距 10%，直径约 8.9% → 底排留细缝 */
.piece {
  position: absolute;
  width: 8.9%; /* ↑ 变大 ↓ 变小；与邻子间距成反比 */
  height: 7.91%; /* 须 ≈ width × (8/9)，否则椭圆变形 */
  transform: translate(-50%, -50%);
  border: none;
  padding: 0;
  background: transparent;
  box-shadow: none;
  cursor: pointer;
  z-index: 2;
  overflow: visible; /* 必须 visible，否则侧壁/投影被裁掉 */
}

/* —— 落盘软影：衬托「棋子离开盘面」的高度感 —— */
.piece::after {
  content: "";
  position: absolute;
  inset: 2%;
  border-radius: 50%;
  z-index: 0;
  pointer-events: none;
  /* translate 越大影越远；blur/opacity 控制软硬与浓淡 */
  transform: translate(5px, 9px) scale(0.96, 0.88);
  background: color-mix(in srgb, var(--piece-wood-lo) 55%, transparent);
  filter: blur(5px);
  opacity: 0.55;
}

/*
 * —— 侧壁 piece-base：可见圆柱高度 + 甜甜圈外鼓环 ——
 * top/right/bottom/left：相对顶面外扩（负 left/right = 环向外鼓）
 * transform translate(x,y)：
 *   y↑ → 露出更多下缘侧壁（更「厚」）；x 微调左右可见量
 * 横向 linear-gradient：左右缘暗 → 圆柱曲面
 * 径向 radial-gradient 停点：接缝暗→环脊亮→外缘暗 = 甜甜圈剖面
 */
.piece-base {
  position: absolute;
  top: 1%;
  right: -0.5%; /* 负值越大外鼓越明显；改成正值则底圈内收 */
  bottom: -0.01%;
  left: -0.5%;
  border-radius: 50%;
  z-index: 1;
  pointer-events: none;
  transform: translate(1px, 2px); /* 第 2 个数 = 厚度视觉高度 */
  background-color: var(--piece-wood-lo);
  background-image:
    linear-gradient(
      90deg,
      color-mix(in srgb, var(--piece-wood-lo) 55%, transparent) 0%,
      transparent 12%, /* ← 左右暗带宽度；减小则曲面更柔 */
      transparent 88%,
      color-mix(in srgb, var(--piece-wood-lo) 55%, transparent) 100%
    ),
    radial-gradient(
      circle at 50% 40%,
      var(--piece-wood-mid) 0%,
      var(--piece-wood-mid) 70%,
      color-mix(in srgb, var(--piece-wood-lo) 80%, #000 20%) 74%, /* 接缝槽 */
      var(--piece-wood-mid) 81%,
      color-mix(in srgb, var(--piece-wood-hi) 55%, var(--piece-wood-mid)) 87%, /* 环脊高光 */
      var(--piece-wood-mid) 93%,
      var(--piece-wood-lo) 98%,
      color-mix(in srgb, var(--piece-wood-lo) 75%, #000 25%) 100% /* 外缘收暗 */
    ),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='64' height='64'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85 0.07' numOctaves='3' seed='9' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0.4 0 0 0 0 0.22 0 0 0 0 0.12 0 0 0 0.4 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: auto, auto, 64px 64px;
  box-shadow:
    1px 2px 3px color-mix(in srgb, var(--piece-wood-lo) 40%, transparent),
    inset 0 -1.5px 2px color-mix(in srgb, var(--piece-wood-lo) 60%, #000 40%);
}

/*
 * —— 字面 piece-lift：保持平整（不做中心球面鼓起）——
 * font-size：汉字大小
 * background 线性渐变：仅轻微面光，勿再加「圆心亮周缘暗」的强径向，否则字面又鼓起来
 * overflow:hidden：裁切外缘斜切层；侧壁在 base 上故不受影响
 */
.piece-lift {
  position: relative;
  display: grid;
  place-items: center;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  font-family: var(--font-piece);
  font-weight: 400;
  font-size: clamp(1.2rem, 3.35vw, 1.78rem); /* 字号 */
  line-height: 1;
  -webkit-font-smoothing: antialiased;
  overflow: hidden;
  color: inherit;
  z-index: 2;
  background-color: var(--piece-wood-mid);
  background-image:
    linear-gradient(
      160deg,
      color-mix(in srgb, var(--piece-wood-hi) 35%, var(--piece-wood-mid)) 0%,
      var(--piece-wood-mid) 42%,
      color-mix(in srgb, var(--piece-wood-mid) 88%, var(--piece-wood-lo) 12%) 100%
    ),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='72' height='72'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.75 0.06' numOctaves='3' seed='13' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0.5 0 0 0 0 0.32 0 0 0 0 0.18 0 0 0 0.28 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: auto, 72px 72px;
  box-shadow:
    0 1px 1px color-mix(in srgb, var(--piece-wood-lo) 35%, transparent), /* 顶面与侧壁接触线 */
    inset 0 0 0 1px color-mix(in srgb, var(--piece-wood-lo) 28%, transparent);
  transition: background-color 0.35s ease, box-shadow 0.25s ease;
}

/*
 * —— 字环 ::before ——
 * inset % 越小越靠外缘；四边不对称时可「略上移」（减小 top、增大 bottom）
 * border 宽度：线粗细；opacity：深浅
 */
.piece-lift::before {
  content: "";
  position: absolute;
  top: 9.5%;
  right: 9.5%;
  bottom: 10.5%;
  left: 10.5%;
  border-radius: 50%;
  pointer-events: none;
  z-index: 1;
  border: 1px solid currentColor; /* ↑ 加粗线 */
  opacity: 0.82;
  box-sizing: border-box;
  box-shadow:
    inset 0 0.5px 0.5px color-mix(in srgb, var(--piece-wood-lo) 35%, transparent),
    0 0.5px 0 color-mix(in srgb, var(--piece-wood-hi) 40%, transparent);
}

/*
 * —— 外缘斜切 ::after（仅圆周鼓起，字面中心被 mask 挖空）——
 * 第 1 个径向：左上肩部高光（circle at / 透明度）
 * 第 2 个径向：右下缘暗
 * 第 3 个径向：transparent→亮→暗 的环带宽度（62% 起斜切）
 * mask：transparent 到 #000 的交界 = 鼓起从哪开始；60%→更靠外，50%→环带更宽
 */
.piece-lift::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  pointer-events: none;
  z-index: 0;
  background-image:
    radial-gradient(
      circle at 22% 18%,
      rgba(255, 245, 220, 0.55) 0%, 高光强度
      transparent 32%
    ),
    radial-gradient(
      circle at 78% 82%,
      color-mix(in srgb, var(--piece-wood-lo) 50%, transparent) 0%,
      transparent 38%
    ),
    radial-gradient(
      circle at 50% 50%,
      transparent 0%,
      transparent 80%, /* 字面平整区半径；减小则斜切更侵入字面 */
      color-mix(in srgb, var(--piece-wood-hi) 55%, var(--piece-wood-mid)) 72%,
      var(--piece-wood-mid) 84%,
      var(--piece-wood-lo) 100%
    );
  -webkit-mask: radial-gradient(
    farthest-side,
    transparent 0%,
    transparent 82%,
    #000 70%,
    #000 100%
  );
  mask: radial-gradient(
    farthest-side,
    transparent 0%,
    transparent 60%,
    #000 70%,
    #000 100%
  );
}

html[data-theme="huanghuali"] .piece-base,
html[data-theme="baixiangmu"] .piece-base,
html[data-theme="shuimo"] .piece-base {
  background-image:
    linear-gradient(
      90deg,
      color-mix(in srgb, var(--piece-wood-lo) 50%, transparent) 0%,
      transparent 22%,
      transparent 78%,
      color-mix(in srgb, var(--piece-wood-lo) 50%, transparent) 100%
    ),
    radial-gradient(
      circle at 50% 40%,
      var(--piece-wood-mid) 0%,
      var(--piece-wood-mid) 70%,
      color-mix(in srgb, var(--piece-wood-lo) 85%, #000 15%) 74%,
      var(--piece-wood-mid) 81%,
      color-mix(in srgb, var(--piece-wood-hi) 55%, var(--piece-wood-mid)) 87%,
      var(--piece-wood-mid) 93%,
      var(--piece-wood-lo) 98%,
      color-mix(in srgb, var(--piece-wood-lo) 80%, #000 20%) 100%
    ),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='64' height='64'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85 0.07' numOctaves='3' seed='11' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0.55 0 0 0 0 0.35 0 0 0 0 0.12 0 0 0 0.35 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: auto, auto, 64px 64px;
}

html[data-theme="baixiangmu"] .piece-base {
  background-image:
    linear-gradient(
      90deg,
      color-mix(in srgb, var(--piece-wood-lo) 45%, transparent) 0%,
      transparent 22%,
      transparent 78%,
      color-mix(in srgb, var(--piece-wood-lo) 45%, transparent) 100%
    ),
    radial-gradient(
      circle at 50% 40%,
      var(--piece-wood-mid) 0%,
      var(--piece-wood-mid) 70%,
      color-mix(in srgb, var(--piece-wood-lo) 80%, #000 20%) 74%,
      var(--piece-wood-mid) 81%,
      color-mix(in srgb, var(--piece-wood-hi) 50%, var(--piece-wood-mid)) 87%,
      var(--piece-wood-mid) 93%,
      var(--piece-wood-lo) 98%,
      color-mix(in srgb, var(--piece-wood-lo) 78%, #000 22%) 100%
    ),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='64' height='64'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8 0.09' numOctaves='3' seed='15' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0.5 0 0 0 0 0.46 0 0 0 0 0.4 0 0 0 0.3 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: auto, auto, 64px 64px;
}

html[data-theme="shuimo"] .piece-base {
  background-image:
    linear-gradient(
      90deg,
      color-mix(in srgb, var(--piece-wood-lo) 40%, transparent) 0%,
      transparent 24%,
      transparent 76%,
      color-mix(in srgb, var(--piece-wood-lo) 40%, transparent) 100%
    ),
    radial-gradient(
      circle at 50% 40%,
      var(--piece-wood-mid) 0%,
      var(--piece-wood-mid) 70%,
      color-mix(in srgb, var(--piece-wood-lo) 75%, #000 25%) 74%,
      var(--piece-wood-mid) 81%,
      color-mix(in srgb, var(--piece-wood-hi) 55%, var(--piece-wood-mid)) 87%,
      var(--piece-wood-mid) 93%,
      var(--piece-wood-lo) 98%,
      color-mix(in srgb, var(--piece-wood-lo) 75%, #000 25%) 100%
    ),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='64' height='64'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.55 0.55' numOctaves='4' seed='91' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0.22 0 0 0 0 0.2 0 0 0 0 0.18 0 0 0 0.22 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: auto, auto, 48px 48px;
}

/*
 * —— 汉字 glyph ——
 * translateY：垂直微调（负值上移）
 * -webkit-text-stroke：字廓粗细；text-shadow 上下反向 = 阴刻感
 */
.piece .glyph {
  position: relative;
  z-index: 2;
  transform: translateY(-0.04em);
  font-weight: 400;
  -webkit-text-stroke: 0.35px currentColor;
  paint-order: stroke fill;
}

/* 红方字色来自 --piece-red；描边/阴影控制阴刻深浅 */
.piece.red,
.piece.red .piece-lift {
  color: var(--piece-red);
}

.piece.red .glyph {
  -webkit-text-stroke: 0.45px var(--piece-red-stroke);
  text-shadow:
    0 1px 0 rgba(255, 200, 190, 0.35),
    0 -1px 0 rgba(60, 0, 0, 0.45),
    inset 0 0 1px rgba(0, 0, 0, 0.2);
}

/* 黑方：紫檀牙白 / 黄花梨墨色（--piece-ivory） */
.piece.black,
.piece.black .piece-lift {
  color: var(--piece-ivory);
}

.piece.black .glyph {
  -webkit-text-stroke: 0.35px color-mix(in srgb, var(--piece-ivory) 70%, #000 30%);
  text-shadow:
    0 1px 0 rgba(255, 240, 210, 0.22),
    0 -1px 0 rgba(20, 8, 8, 0.5);
}

html[data-theme="huanghuali"] .piece.black .glyph {
  -webkit-text-stroke: 0.4px #1a1208;
  text-shadow:
    0 1px 0 rgba(255, 235, 200, 0.35),
    0 -1px 0 rgba(40, 20, 8, 0.4);
}

html[data-theme="baixiangmu"] .piece.black .glyph {
  -webkit-text-stroke: 0.4px #1e1c18;
  text-shadow:
    0 1px 0 rgba(255, 255, 252, 0.4),
    0 -1px 0 rgba(40, 36, 30, 0.35);
}

html[data-theme="shuimo"] .piece.black .glyph {
  -webkit-text-stroke: 0.45px #0e0d0c;
  text-shadow:
    0 1px 0 rgba(255, 254, 250, 0.45),
    0 -1px 0 rgba(20, 18, 16, 0.4);
}

html[data-theme="shuimo"] .piece.red .glyph {
  -webkit-text-stroke: 0.45px #6e1c16;
  text-shadow:
    0 1px 0 rgba(255, 220, 210, 0.3),
    0 -1px 0 rgba(50, 10, 8, 0.4);
}

.piece:hover .piece-lift {
  filter: brightness(1.06); /* 悬停略提亮 */
}

/* 绝杀后：悬停提亮 / Dock 弹跳全部关闭 */
html.is-checkmate .piece:hover .piece-lift {
  filter: none;
}

html.is-checkmate .piece.dock-bounce,
html.is-checkmate .piece.dock-bounce::after {
  animation: none !important;
}

/*
 * 选中：切勿改 .piece-base 的 translate（会拉长侧壁 → 变形 + 深色黑边）
 * Dock 弹跳由 .dock-bounce 触发（悬停 / 点选共用，见 app.js triggerDockBounce）
 */
.piece.selected {
  z-index: 4;
}

.piece.selected::before {
  content: "";
  position: absolute;
  inset: -5px;
  border-radius: 50%;
  pointer-events: none;
  z-index: 0;
  box-shadow:
    0 0 0 1.5px color-mix(in srgb, var(--gold-mute) 70%, transparent),
    0 0 0 5px color-mix(in srgb, var(--gold-mute) 22%, transparent);
}

.piece.selected .piece-lift {
  filter: brightness(1.04);
}

/* 悬停或点选时由 JS 加上，可重复触发 */
.piece.dock-bounce {
  animation: pieceDockBounce 0.48s cubic-bezier(0.22, 1.15, 0.36, 1);
}

.piece.dock-bounce::after {
  animation: pieceDockShadow 0.48s cubic-bezier(0.22, 1.15, 0.36, 1);
}

@keyframes pieceDockBounce {
  0% {
    transform: translate(-50%, -50%) translateY(0) scale(1);
  }
  32% {
    transform: translate(-50%, -50%) translateY(-11px) scale(1.04);
  }
  58% {
    transform: translate(-50%, -50%) translateY(-3px) scale(1.01);
  }
  76% {
    transform: translate(-50%, -50%) translateY(-6px) scale(1.02);
  }
  100% {
    transform: translate(-50%, -50%) translateY(0) scale(1);
  }
}

@keyframes pieceDockShadow {
  0%,
  100% {
    transform: translate(5px, 9px) scale(0.96, 0.88);
    opacity: 0.55;
  }
  32% {
    transform: translate(7px, 16px) scale(0.9, 0.82);
    opacity: 0.35;
  }
  76% {
    transform: translate(6px, 12px) scale(0.93, 0.85);
    opacity: 0.42;
  }
}

/* 刚走完：玻璃光圈。inset 负值 = 环外扩宽度；mask 两线之差 = 环线粗细 */
.piece.last-moved {
  z-index: 3;
}

.piece.last-moved::before {
  content: "";
  position: absolute;
  inset: -2px;
  border-radius: 50%;
  pointer-events: none;
  z-index: 0;
  background: conic-gradient(
    from 0deg,
    rgba(255, 255, 255, 0.06) 0deg,
    rgba(255, 255, 255, 0.55) 55deg,
    rgba(255, 255, 255, 0.1) 110deg,
    rgba(210, 220, 230, 0.4) 180deg,
    rgba(255, 255, 255, 0.08) 240deg,
    rgba(255, 255, 255, 0.62) 300deg,
    rgba(255, 255, 255, 0.06) 360deg
  );
  -webkit-mask: radial-gradient(
    farthest-side,
    transparent calc(100% - 4.5px),
    #000 calc(100% - 3.5px)
  );
  mask: radial-gradient(
    farthest-side,
    transparent calc(100% - 4.5px),
    #000 calc(100% - 3.5px)
  );
  animation: glassRingSpin 2.2s linear infinite;
  filter: blur(0.2px);
  opacity: 0.95;
}

.piece.last-moved .piece-lift {
  position: relative;
  z-index: 1;
  box-shadow:
    0 1px 1px color-mix(in srgb, var(--piece-wood-lo) 35%, transparent),
    0 0 0 1px rgba(255, 255, 255, 0.2),
    inset 0 0 0 1px color-mix(in srgb, var(--piece-wood-lo) 28%, transparent),
    inset 0 1px 0 rgba(255, 255, 255, 0.2);
}

@keyframes glassRingSpin {
  to {
    transform: rotate(360deg);
  }
}

.piece.in-hand {
  z-index: 8;
}

.piece.in-hand::before {
  content: none !important;
  display: none !important;
  box-shadow: none !important;
  animation: none !important;
  background: none !important;
}

/* 悬空时关掉落盘影，避免浅色主题下影团像白坨 */
.piece.in-hand::after {
  opacity: 0;
}

.piece.in-hand .piece-lift {
  box-shadow:
    0 1px 1px color-mix(in srgb, var(--piece-wood-lo) 35%, transparent),
    inset 0 0 0 1px color-mix(in srgb, var(--piece-wood-lo) 28%, transparent);
  filter: none;
}

.piece.capturing {
  z-index: 2;
  pointer-events: none;
}

.piece.check-pulse .piece-lift {
  animation: checkPulse 0.9s ease-in-out 2;
}

@keyframes checkPulse {
  0%,
  100% {
    box-shadow:
      0 3px 8px rgba(0, 0, 0, 0.45),
      inset 0 2px 3px rgba(160, 100, 110, 0.22),
      inset 0 -3px 6px rgba(0, 0, 0, 0.4);
  }
  50% {
    box-shadow:
      0 0 0 3px rgba(200, 80, 80, 0.55),
      0 4px 14px rgba(180, 40, 40, 0.35),
      inset 0 2px 3px rgba(160, 100, 110, 0.22);
  }
}

.board-stars {
  color: var(--board-line);
  opacity: 0.92;
}

.side-panel {
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
  padding-top: 0.4rem;
}

.status-card {
  padding: 1rem 0.9rem;
  background: rgba(255, 250, 240, 0.45);
  border: 1px solid rgba(74, 59, 42, 0.18);
  text-align: center;
}

.status-card.muted {
  background: rgba(154, 43, 43, 0.06);
  border-color: rgba(154, 43, 43, 0.28);
}

.status-card .label {
  margin: 0;
  font-size: 0.75rem;
  letter-spacing: 0.35em;
  text-indent: 0.35em;
  color: var(--ink-soft);
  opacity: 0.7;
}

.status-card .turn {
  margin: 0.35rem 0 0.2rem;
  font-family: var(--font-piece);
  font-size: 1.7rem;
  color: var(--cinnabar-deep);
}

.status-card .turn.black-turn {
  color: var(--ink);
}

.status-card .turn-sub {
  margin-top: 0.65rem;
}

.status-card .turn.free-mode {
  color: var(--ink-soft);
  font-size: 1.45rem;
}

.btn.active {
  background: rgba(154, 43, 43, 0.12);
  border-color: rgba(154, 43, 43, 0.45);
  color: var(--cinnabar-deep);
}

.status-card .hint {
  margin: 0;
  font-size: 0.78rem;
  letter-spacing: 0.12em;
  color: var(--ink-soft);
  opacity: 0.75;
}

.check-text {
  margin: 0.4rem 0 0;
  font-family: var(--font-piece);
  font-size: 1.55rem;
  color: var(--cinnabar);
  letter-spacing: 0.2em;
}

.actions {
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
}

.btn:disabled {
  opacity: 0.38;
  cursor: not-allowed;
}

.ply-hint {
  margin: 0.15rem 0 0;
  text-align: center;
  font-size: 0.75rem;
  letter-spacing: 0.12em;
  color: var(--ink-soft);
  opacity: 0.75;
}

.cloud-card {
  text-align: left;
  /* 与侧栏「模式」卡顶对齐 */
  align-self: start;
  max-height: min(70vh, 36rem);
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.cloud-card[hidden] {
  display: none !important;
}

.cloud-meta {
  margin: 0.35rem 0 0.5rem;
  font-size: 0.72rem;
  line-height: 1.45;
  color: var(--ink-soft);
  word-break: break-all;
  flex-shrink: 0;
}

.cloud-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  /* 不截断隐藏着法：列表可滚，条目全显 */
  max-height: none;
  flex: 1 1 auto;
  overflow: auto;
  min-height: 0;
}

.cloud-list li.cloud-unknown .cloud-stat {
  opacity: 0.65;
}

.cloud-list li.cloud-skip .cloud-move {
  opacity: 0.45;
  cursor: default;
}

.cloud-list li {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.4rem;
  font-size: 0.78rem;
}

.cloud-move {
  font-family: var(--font-ui);
  border: 1px solid rgba(74, 59, 42, 0.25);
  background: rgba(255, 250, 240, 0.7);
  padding: 0.2rem 0.45rem;
  cursor: pointer;
  color: var(--ink);
}

.cloud-move:hover:not(:disabled) {
  border-color: rgba(154, 43, 43, 0.45);
  color: var(--cinnabar);
}

.cloud-move:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

.cloud-list li.cloud-stale .cloud-stat {
  opacity: 0.45;
}

.cloud-stat {
  color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.cloud-note {
  margin: 0.55rem 0 0;
  font-size: 0.68rem;
  line-height: 1.4;
  color: rgba(58, 52, 44, 0.55);
}

.btn {
  appearance: none;
  border: 1px solid rgba(74, 59, 42, 0.35);
  background: rgba(255, 250, 240, 0.55);
  color: var(--ink);
  font-family: inherit;
  font-size: 0.92rem;
  letter-spacing: 0.35em;
  text-indent: 0.35em;
  padding: 0.65rem 0.5rem;
  cursor: pointer;
  transition: background 0.2s ease, border-color 0.2s ease;
}

.btn:hover {
  background: rgba(255, 250, 240, 0.85);
  border-color: rgba(74, 59, 42, 0.55);
}

.btn.ghost {
  background: transparent;
}

.colophon {
  margin: 0.6rem 0 0;
  text-align: center;
  font-size: 0.72rem;
  letter-spacing: 0.28em;
  text-indent: 0.28em;
  color: var(--ink-soft);
  opacity: 0.55;
}

@media (max-width: 980px) {
  .board-panel {
    grid-template-columns: minmax(0, 1fr) 180px;
  }

  .cloud-card {
    grid-column: 1 / -1;
    width: min(100%, 560px);
    justify-self: center;
    max-height: 18rem;
  }
}

@media (max-width: 820px) {
  .stage {
    padding-top: 1.25rem;
    padding-bottom: max(2rem, calc(1rem + env(safe-area-inset-bottom)));
  }

  .masthead {
    margin-bottom: 0.9rem;
  }

  .masthead h1 {
    font-size: clamp(2rem, 9vw, 2.8rem);
    letter-spacing: 0.28em;
    text-indent: 0.28em;
  }

  .masthead .subtitle {
    font-size: 0.8rem;
    letter-spacing: 0.28em;
    text-indent: 0.28em;
  }

  .masthead .seal {
    transform: translateX(-5.6rem) rotate(-8deg);
    width: 1.75rem;
    height: 1.75rem;
    font-size: 0.95rem;
  }

  .board-panel {
    grid-template-columns: 1fr;
    gap: 0.9rem;
    justify-items: stretch;
  }

  .board-frame {
    width: min(100%, 560px);
    justify-self: center;
    padding: 1.1rem 0.85rem;
  }

  .side-panel {
    width: min(100%, 560px);
    justify-self: center;
    flex-direction: row;
    flex-wrap: wrap;
    align-items: stretch;
    gap: 0.65rem;
    padding-top: 0;
  }

  .status-card {
    flex: 1 1 140px;
    padding: 0.7rem 0.75rem;
  }

  .cloud-card {
    width: 100%;
    flex: 1 1 100%;
    max-height: 14rem;
  }

  .actions {
    flex: 1 1 100%;
    flex-direction: row;
    flex-wrap: wrap;
    gap: 0.45rem;
  }

  .btn {
    flex: 1 1 calc(33.33% - 0.35rem);
    min-width: 5.5rem;
    min-height: 2.75rem;
    padding: 0.55rem 0.35rem;
    font-size: 0.84rem;
    letter-spacing: 0.18em;
    text-indent: 0.18em;
  }

  .ply-hint {
    flex: 1 1 100%;
    text-align: center;
    margin: 0.15rem 0 0;
  }

  .colophon {
    flex: 1 1 100%;
    margin-top: 0.2rem;
  }
}

/* 手机竖屏：棋盘优先、控件紧凑可点 */
@media (max-width: 560px) {
  .stage {
    padding-top: max(0.75rem, env(safe-area-inset-top));
    padding-left: max(0.65rem, env(safe-area-inset-left));
    padding-right: max(0.65rem, env(safe-area-inset-right));
  }

  .masthead {
    margin-bottom: 0.55rem;
  }

  .masthead .seal {
    display: none;
  }

  .masthead .subtitle {
    display: none;
  }

  .masthead h1 {
    font-size: 1.85rem;
    letter-spacing: 0.22em;
    text-indent: 0.22em;
  }

  .board-frame {
    width: 100%;
    padding: 0.85rem 0.55rem;
    border-radius: 4px;
  }

  .file-labels-black {
    top: 0.12rem;
  }

  .file-labels-red {
    bottom: 0.12rem;
  }

  .file-labels-black span,
  .file-labels-red span {
    font-size: 0.72rem;
  }

  .side-panel {
    width: 100%;
    gap: 0.5rem;
  }

  .status-card {
    flex: 1 1 calc(50% - 0.3rem);
    min-width: 0;
  }

  .status-card .turn {
    font-size: 1.35rem;
  }

  .status-card .hint {
    font-size: 0.72rem;
    letter-spacing: 0.06em;
  }

  .check-text {
    font-size: 1.25rem;
  }

  .actions {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 0.4rem;
  }

  .btn {
    flex: none;
    width: 100%;
    min-width: 0;
    min-height: 2.85rem;
    letter-spacing: 0.12em;
    text-indent: 0.12em;
  }

  .board-fx img {
    max-width: 62%;
    max-height: 48%;
  }

  #captureFx img {
    max-width: 31%;
    max-height: 24%;
  }
}

@media (max-width: 560px) and (orientation: landscape) {
  .masthead {
    display: none;
  }

  .board-panel {
    grid-template-columns: minmax(0, 1fr) minmax(9.5rem, 34vw);
    align-items: start;
    gap: 0.55rem;
  }

  .board-frame {
    width: min(100%, calc(100dvh - 1.2rem));
  }

  .side-panel {
    width: 100%;
    flex-direction: column;
    flex-wrap: nowrap;
  }

  .status-card {
    flex: 0 0 auto;
  }

  .actions {
    grid-template-columns: 1fr 1fr;
  }
}
