/**
 * 「棋·弈」联机层（只归属 games/chess/）
 *
 * 布局（用户选的方案）：**宽屏棋盘居中 + 右侧固定一列**，窄屏棋盘在上、侧栏竖着折到下面。
 * 断点 1000px。只写本页自己的 `.co-*`；按钮/输入沿用 table.css 的 .tbl-btn / .tbl-input。
 * ⚠️ 不要在这里声明 shell.css 已定义的顶层容器宽度（PITFALLS：后加载的同优先级样式会盖掉内容列）。
 */

/* ---------- 首页模式开关 ---------- */
.co-modeswitch {
  display: flex;
  gap: 0;
  border: 2px solid var(--ink);
  background: var(--sheet);
  width: fit-content;
  margin: 0.9rem auto 0;
  box-shadow: 3px 3px 0 var(--ink);
}
.co-modeswitch .opt-btn {
  border: 0;
  border-right: 2px solid var(--ink);
  background: transparent;
  color: var(--ink);
  font: inherit;
  padding: 0.45rem 1.1rem;
  cursor: pointer;
}
.co-modeswitch .opt-btn:last-child { border-right: 0; }
.co-modeswitch .opt-btn.active { background: var(--ink); color: var(--sheet); }

#home .cards .card.soon { opacity: 0.45; }
#home .cards .card.soon .card-desc::after { content: ' · 联机待做'; }

/* ---------- 联机大厅（建房 / 加入） ---------- */
.co-lobby { margin: 1.2rem 0; }
.co-lobby-row { display: flex; gap: 0.5rem; flex-wrap: wrap; align-items: center; }
.co-lobby-row .tbl-input { min-width: 8rem; }

/* ---------- 通用面板 ---------- */
.co-panel {
  border: 2px solid var(--ink);
  background: var(--sheet);
  box-shadow: 4px 4px 0 var(--ink);
  padding: 0.8rem 0.9rem;
  margin-bottom: 0.9rem;
}
.co-panel-head {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  justify-content: space-between;
  border-bottom: 2px solid var(--ink);
  padding-bottom: 0.5rem;
  margin-bottom: 0.7rem;
}
.co-panel-title { font-weight: 700; }
.co-code { font-family: var(--mono, monospace); letter-spacing: 0.16em; }
.co-status { font-size: 0.74rem; opacity: 0.8; }

/* 座位 */

.co-seat {
  border: 2px solid var(--ink);
  padding: 0.45rem 0.55rem;
  background: var(--paper, #fff);
}
.co-seat.me { background: var(--accent); color: #fff; }
.co-seat.empty { opacity: 0.45; border-style: dashed; }
.co-seat-name { font-weight: 700; font-size: 0.86rem; }
.co-seat-tag { font-size: 0.7rem; opacity: 0.85; }

/* 房规 */
.co-rules { display: flex; flex-direction: column; gap: 0.3rem; }
.co-rule {
  display: flex;
  justify-content: space-between;
  gap: 0.6rem;
  border: 2px solid var(--ink);
  padding: 0.34rem 0.5rem;
  font-size: 0.78rem;
}
.co-rule.clickable { cursor: pointer; }
.co-rule.clickable:hover { background: var(--accent); color: #fff; }
.co-rule-val { font-weight: 700; }
.co-hint { font-size: 0.72rem; opacity: 0.75; margin-top: 0.4rem; }

/* 记录 / 聊天 */
.co-log { display: flex; flex-direction: column; gap: 0.2rem; font-size: 0.76rem; max-height: 12rem; overflow: auto; }
.co-log-line { border-left: 3px solid var(--ink); padding-left: 0.4rem; }
.co-chat { display: flex; flex-direction: column; gap: 0.25rem; max-height: 11rem; overflow: auto; font-size: 0.78rem; }
.co-chat-line b { font-weight: 700; }
.co-chatform { display: flex; gap: 0.4rem; margin-top: 0.5rem; }
.co-chatform .tbl-input { flex: 1 1 auto; min-width: 0; }

/* 联机态：棋盘组件里那些「单机壳」全部藏掉 —— 状态行、双方时钟、三个按钮、返回箭头、
   先手文案在侧栏里都有对应控件，两套并排会重复（截图发现）。只留棋盘本身。 */
.co-online .nav-bar,
.co-online .status,
.co-online .clocks,
.co-online .turn-hint,
.co-online .controls,
.co-online .captured-row,
.co-online .setup-mask { display: none !important; }
/* ⚠️ .result-mask 是**结算弹窗**，联机同样需要（之前一并隐藏 → 对局结束没有任何提示）。
   只把「再来一局」那颗按钮藏掉：联机的再来一局要走房间征询，不能是类的本地重开。 */
/* ⚠️ 「再来一局」在联机下**必须留着** —— 它现在会发 {t:rematch} 走房间征询（以前藏起来 →
   用户只能重开房间）。CSS 不再隐藏它。 */
.co-online .gomoku { padding: 0; }
.co-online .board-wrap { margin: 0; }

/* ---------- 对局：宽屏侧栏 / 窄屏竖排 ---------- */
.co-layout { display: grid; gap: 0.9rem; }
/* ⚠️ 面板必须**自己定宽**：单机棋盘的尺寸是 width:min(100%, calc(100vh-12rem), 520px)，
   而 fit-content 的 grid 子项宽度由内容决定 → 100% 无解、互相锁死，棋盘被压成约 110×150px
   （截图实测：功能断言全绿，只有出图才看得见）。 */
.co-boardpanel { width: min(100%, 32.5rem); background: var(--sheet); outline: 2px solid var(--ink); outline-offset: 0.5rem; box-shadow: 6px 6px 0 var(--ink); }   /* 与单机同款：单框 outline */
#co-board { width: 100%; }
.co-statusbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.6rem;
  border: 2px solid var(--ink);
  background: var(--ink);
  color: var(--sheet);
  padding: 0.35rem 0.6rem;
  margin-bottom: 0.6rem;
  font-size: 0.82rem;
}
.co-statusbar.mine { background: var(--accent); }
.co-statusbar.done { background: var(--paper, #fff); color: var(--ink); }
.co-side { display: flex; flex-direction: column; gap: 0.9rem; }
.co-sidebox { border: 2px solid var(--ink); background: var(--sheet); padding: 0.6rem 0.7rem; }
.co-player { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; padding: 0.3rem 0; border-bottom: 1px solid var(--ink); }
.co-player:last-child { border-bottom: 0; }
.co-player.active { background: var(--accent); color: #fff; }
.co-who { font-size: 0.8rem; }
.co-remain { font-family: var(--mono, monospace); font-weight: 700; }
.co-player.offline .co-who::after { content: ' · 掉线'; font-size: 0.7rem; opacity: 0.8; }
.co-actions { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0.4rem; }
.co-actions .tbl-btn { width: 100%; }

/* 征询弹窗 */
.co-vote {
  position: fixed;
  left: 50%;
  bottom: 1rem;
  translate: -50% 0;
  z-index: 60;
  border: 3px solid var(--ink);
  background: var(--sheet);
  box-shadow: 6px 6px 0 var(--ink);
  padding: 0.7rem 0.9rem;
  display: flex;
  align-items: center;
  gap: 0.7rem;
  max-width: min(92vw, 26rem);
}
.co-vote .co-vote-text { font-size: 0.82rem; }
.co-vote-btns { display: flex; gap: 0.4rem; }

@media (min-width: 1000px) {
  .co-layout { grid-template-columns: minmax(0, 1fr) 19rem; align-items: start; }
  /* 棋盘面板按内容收紧并居中：否则 1fr 会让面板比棋盘宽一大截（截图发现） */
  .co-boardpanel { width: min(100%, 32.5rem); justify-self: center; }   /* 与单机棋盘同宽（520） */
  .co-side { position: sticky; top: 0.8rem; }
  
}
@media (max-width: 999px) {
  .co-layout { grid-template-columns: minmax(0, 1fr); }
  
}

/* ═══ P3：观战条 + 复盘面板（与 .co-vote 同一套语言：墨线 + 硬投影 + 一个强调块）═══ */

/* 旁观条：固定底部居中，和征询条同一个位置——两者不会同时出现 */
.co-spectate {
  position: fixed;
  left: 50%;
  bottom: 4.6rem;   /* ⚠️ 让开底部居中的轻提示 .toast —— 都在 1rem 时过期的 toast 会压住房号（截图实测） */
  translate: -50% 0;
  z-index: 60;
  border: 3px solid var(--ink);
  background: var(--sheet);
  box-shadow: 6px 6px 0 var(--ink);
  padding: 0.6rem 0.9rem;
  display: flex;
  align-items: center;
  gap: 0.7rem;
  max-width: min(92vw, 30rem);
}
.co-spectate-tag {
  background: var(--c-orange, #b8442a);
  color: #fff;
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  padding: 0.22rem 0.5rem;
  border: 2px solid var(--ink);
  flex: 0 0 auto;
}
.co-spectate-txt {
  font-family: var(--font-mono, ui-monospace, monospace);
  font-size: 0.74rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* 复盘面板：贴着棋盘下方的窄条，四个按钮等宽 */
.co-replay {
  border: 3px solid var(--ink);
  background: var(--paper, #fff);
  box-shadow: 6px 6px 0 var(--ink);
  padding: 0.6rem 0.7rem;
  margin-top: 0.8rem;
  display: grid;
  gap: 0.5rem;
}
.co-replay-head {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  border-bottom: 2px solid var(--ink);
  padding-bottom: 0.4rem;
}
.co-replay-step {
  font-family: var(--font-mono, ui-monospace, monospace);
  font-size: 0.74rem;
  margin-right: auto;
}
.co-replay-row { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0.4rem; }
.co-replay .tbl-btn { width: 100%; }

@media (max-width: 720px) {
  .co-replay-row { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ═══════════════ 共用对局骨架（单机 / 联机同一套）═══════════════
   方案 3：棋盘居中 + 右侧栏。≥1000px 两栏，窄屏单列（侧栏折到棋盘下方）。
   单机四个壳的 DOM 不动 —— 用 CSS 网格把它们既有的 .status / .clocks / .board /
   .move-record / .controls 归位到同一骨架里。 */
.ct-table { display: grid; gap: 0.9rem; align-items: start; max-width: 62rem; margin-inline: auto; }   /* 与单机 #game 同宽居中 */
.ct-left { display: grid; grid-template-columns: minmax(0, 1fr); gap: 0.9rem; min-width: 0; }
/* ⚠️ 必须把 grid-area 清成 auto：旧规则残留的 `grid-area: status` 会把这些元素按**具名区**排到
   别处（实测状态条被扔到最下面、操作行跑到第二列）。 */
.ct-left > .co-statusbar, .ct-left > .ct-main, .ct-left > .ct-ops { grid-area: auto; }
.ct-main { min-width: 0; }
.ct-side { display: flex; flex-direction: column; gap: 0.9rem; min-width: 0; }
.ct-box { border: 2px solid var(--ink); background: var(--sheet); padding: 0.6rem 0.7rem; }
.ct-ops { display: flex; gap: 0.5rem; }
.ct-ops > * { flex: 1 1 0; min-width: 0; }
/* 聊天盒：列表撑满、输入行钉底、输入框吃掉剩余宽度（原来列表不撑 → 输入框浮在中间且被挤窄） */
.ct-chat { flex: 1 1 auto; overflow-y: auto; min-height: 3rem; }
.ct-side > .ct-box:last-child { display: flex; flex-direction: column; }
.ct-side .co-chatform { display: flex; gap: 0.35rem; margin-top: 0.45rem; }
.ct-side .co-chatform .tbl-input { flex: 1 1 auto; min-width: 0; }
.ct-side .co-chatform .tbl-btn { flex: 0 0 auto; }
.ct-side > :last-child { flex: 1 1 auto; }   /* 最后一个盒子（联机=聊天，单机=对局记录）吃满剩余高度 */

@media (min-width: 1000px) {
  /* 与单机同构：左列一栏（状态条 / 棋盘 / 操作行），右列侧栏 —— 状态条与操作行只在左列内，
     与单机的 730px 完全一致（单机做不到通栏：类容器不能加子元素也不能 display:contents）。 */
  .ct-table { grid-template-columns: minmax(0, 1fr) 15.5rem; align-items: start; }
  .ct-left { grid-column: 1; grid-row: 1; }
  .ct-side { grid-column: 2; grid-row: 1; align-self: stretch; }
  /* 与单机 .status 一模一样的一条通栏。⚠️ 原 .co-statusbar 是 flex + space-between，
     只写 text-align:center 不生效 —— 必须 justify-content:center（实测文字一直贴左）。 */
  .ct-left > .co-statusbar {
    /* ⚠️ 这里**不能**再写 grid-area: status —— 本选择器比上面的 reset 更靠后，
       会把状态条按具名区排走，.ct-left 因此凭空多出几列（实测列宽 441/191/68，全乱）。 */
    border: 2px solid var(--ink);
    background: var(--sheet);
    justify-content: center;
    text-align: center;
    font-size: 0.8rem;
    padding: 0.5rem 0;
    /* ⚠️ .tbl-status 原本是"墨底浅字"，这里底色换成了浅纸面 → 必须把字色改回墨色，
       否则文字与底色同色＝看不见（实测：状态条成了一条空框）。 */
    color: var(--ink);
  }
  /* ⚠️ 必须连**底色**一起写：上面那条 .ct-table > .co-statusbar 把背景设成了纸面，
     而原 .co-statusbar.mine 的强调色底写在更前面、同优先级 → 被盖掉 → 白字压白底＝看不见
     （实测 computed: color rgb(255,255,255) / background rgb(255,255,255)）。 */
  /* 与单机一致：状态条**始终浅底居中**，"该谁走"由侧栏那一行的强调色块表达 */
  .ct-left > .co-statusbar.mine, .ct-left > .co-statusbar.done { background: var(--sheet); color: var(--ink); }
  .ct-left > .co-statusbar.done { background: var(--paper, #fff); color: var(--ink); }
  .ct-left { display: grid; grid-template-columns: minmax(0, 1fr); gap: 0.9rem; min-width: 0; }
.ct-main { min-width: 0; }


}

/* ═══ 单机：与联机同一套骨架（方案 3）═══
   结构：
     #game                       ← 两栏网格（左：棋类容器；右：侧栏）
       > .nav-bar                ← 通栏
       > .{gomoku|ck|xq|ch}      ← 左列，单列自上而下：状态条 / 棋盘 / 提示 / 操作行
       > .ct-side                ← 右列（app.js 注入：时钟镜像 + 信息盒 + 对局记录）
   ⚠️ 四条实测教训：
     ① 侧栏**必须挂在 #game 上**、不能塞进棋类容器：往 .{棋类} 里加子节点会让四个游戏类
        的落子逻辑失灵（点棋盘没反应，test-chess-ui 红 3 条；去掉注入则 122 项全绿）。
     ② 类自己的 .clocks / .captured-row / .move-record 只**隐藏**不移动（搬动同样会出问题）。
     ③ 棋盘面板的框用 outline，不用 border+padding（类按父宽算落点，内距会把映射算歪）。
     ④ 选择器一律限定 #game（联机棋盘宿主里有同名容器）。 */
#game > .gomoku, #game > .ck, #game > .xq, #game > .ch { display: grid; gap: 0.9rem; align-items: start; }
/* 左列单列：状态 → 棋盘 → 提示 → 操作 */
#game > .gomoku > .status, #game > .ck > .status, #game > .xq > .status, #game > .ch > .status,
#game > .gomoku > .turn-hint, #game > .ck > .turn-hint, #game > .xq > .turn-hint, #game > .ch > .turn-hint {
  width: 100%; max-width: none; margin-inline: 0;
}
#game > .gomoku > .board-wrap, #game > .ck > .board-wrap,
#game > .xq > .board, #game > .ch > .board {
  width: min(100%, 32.5rem); max-width: 32.5rem; justify-self: center; margin-inline: auto;
  background: var(--sheet); outline: 2px solid var(--ink); outline-offset: 0.5rem; box-shadow: 6px 6px 0 var(--ink);
}
#game > .gomoku > .controls, #game > .ck > .controls, #game > .xq > .controls, #game > .ch > .controls {
  display: flex; gap: 0.5rem; width: 100%; max-width: none; margin-inline: 0;
}
#game > .gomoku > .controls > *, #game > .ck > .controls > *, #game > .xq > .controls > *, #game > .ch > .controls > * { flex: 1 1 0; min-width: 0; }
/* 类自带的这几块在单机里由右列镜像，隐藏掉（**只隐藏，不搬动**） */
#game > .gomoku > .clocks, #game > .ck > .clocks, #game > .xq > .clocks, #game > .ch > .clocks,
#game > .gomoku > .captured-row, #game > .ck > .captured-row, #game > .xq > .captured-row, #game > .ch > .captured-row,
#game > .xq > .move-record, #game > .ch > .move-record { display: none; }

/* 右列：时钟镜像 / 信息盒 / 对局记录，盒子紧贴，记录盒吃满剩余高度 */
#game > .ct-side { display: flex; flex-direction: column; gap: 0.9rem; min-width: 0; }
#game > .ct-side > .ct-clocks, #game > .ct-side > .ct-info, #game > .ct-side > .ct-record {
  border: 2px solid var(--ink); background: var(--sheet); padding: 0.5rem 0.6rem; font-size: 0.78rem;
}
#game > .ct-side > .ct-clocks { display: grid; grid-template-columns: 1fr; gap: 0; padding: 0; }
#game > .ct-side .ct-clock { display: flex; justify-content: space-between; align-items: center; padding: 0.4rem 0.6rem; }
#game > .ct-side .ct-clock + .ct-clock { border-top: 2px solid var(--ink); }
#game > .ct-side .ct-clock.active { background: var(--c-orange, #b8442a); color: #fff; }
#game > .ct-side .ct-clock.active .ct-time, #game > .ct-side .ct-clock.active .ct-who { color: #fff; }
#game > .ct-side > .ct-record { flex: 1 1 auto; }
#game > .ct-side > .ct-record .ct-record-title { border-bottom: 2px solid var(--ink); padding-bottom: 0.3rem; margin-bottom: 0.4rem; }
#game > .ct-side > .ct-record .ct-record-list { white-space: pre-line; color: var(--c-text-sub, #6b6459); line-height: 1.5; }
#game > .ct-side > .ct-info .ct-row { display: flex; justify-content: space-between; gap: 0.5rem; }
#game > .ct-side > .ct-info .ct-row + .ct-row { margin-top: 0.25rem; }

@media (min-width: 1000px) {
  #game { display: grid; grid-template-columns: minmax(0, 1fr) 15.5rem; gap: 0.9rem; align-items: start; max-width: 62rem; margin-inline: auto; }
  #game > .nav-bar { grid-column: 1 / -1; }
  /* ⚠️ 容器既不能加子元素、也不能 display:contents —— 两种都试过，四个游戏类都会失灵
     （点棋盘没反应）。所以单机的状态条/操作行注定只在左列内（≈730），联机照此对齐。 */
  #game > .gomoku, #game > .ck, #game > .xq, #game > .ch { grid-column: 1; grid-row: 2; }
  #game > .ct-side { grid-column: 2; grid-row: 2; align-self: stretch; }
}

/* ═══ 联机大厅（方案 B）：左「开一局新的」/ 右「进现有的局」 ═══
   两条互斥路径，房号只出现一次；≤720px 自动竖排。
   ⚠️ 不要再把四个动作并排成一行（原来创建/房号/加入/观战同权重，房号归属不明）。 */
.co-lobby2 { display: grid; grid-template-columns: 1fr 1fr; gap: 0.9rem; align-items: start; }
.co-lobby2 > .co-lobby-card {
  border: 2px solid var(--ink); background: var(--sheet); box-shadow: 4px 4px 0 var(--ink);
  padding: 0.8rem 0.9rem; display: flex; flex-direction: column; gap: 0.5rem;
}
.co-lobby2 .co-lobby-h { font-size: 0.86rem; border-bottom: 2px solid var(--ink); padding-bottom: 0.4rem; }
.co-lobby2 .co-lobby-rules { display: grid; grid-template-columns: auto 1fr; gap: 0.25rem 0.7rem; margin: 0; font-size: 0.76rem; }
.co-lobby2 .co-lobby-rules dt { color: var(--c-text-sub, #6b6459); }
.co-lobby2 .co-lobby-rules dd { margin: 0; }
/* ⚠️ 卡片是 flex 列：不给子项定死 flex，按钮/输入框会被拉伸成一大块（实测创建房间变成 120px 高）。 */
.co-lobby2 .co-lobby-card > * { flex: 0 0 auto; }
.co-lobby2 .co-lobby-card > .tbl-btn { width: 100%; }
.co-lobby2 > .co-lobby-card { align-self: start; }
.co-lobby2 .co-lobby-pick { display: flex; gap: 0.5rem; }
.co-lobby2 .co-lobby-pick > * { flex: 1 1 0; min-width: 0; }
@media (max-width: 720px) {
  .co-lobby2 { grid-template-columns: minmax(0, 1fr); }
}
