/* ==========================================================================
   games.zzxcd.cn · shell.css
   --------------------------------------------------------------------------
   只有一件事：七个游戏页面 markup 里**字面相同**的那几个容器的骨架 ——
     .app / .home / .game     顶层层级
     .header .logo .title .subtitle
     .cards .card*            首页模式列表
     .footer
     .help-overlay .help-card 帮助面板
     .settings-*              右抽屉设置面板
     .toast                   轻提示
   每个游戏在 assets/<游戏>.css 里重画自己的专属部分（棋盘、状态条、按钮…），
   各写各的，不共享组件类名。
   ========================================================================== */

/* ---------- 顶层 ---------- */
/* ⚠️ 对局区（.game / #gameView）在各页 markup 里是 .app 的**兄弟节点**，不是子节点，
   所以它必须自己再声明一次内容列宽度，否则会撑满视口（实测 1280 视口下量到 1280px，
   状态栏被顶出屏幕、右侧按钮压在一起）。
   `.home` 也要列进来：华容道与俄罗斯方块的首页 markup 里没有 .app 包裹，
   否则页脚的 border-top 会通栏 1280（卡片列只有 660）。 */
.app,
#app,
.home,
.game,
#gameView {
  position: relative;
  z-index: 1;
  width: min(100% - 1.6rem, 1040px);
  margin: 0 auto;
  --pad-x: 0rem;
}

.app,
#app,
.home {
  padding: clamp(1.1rem, 3.4vh, 2.4rem) 0 2rem;
}

.game,
#gameView {
  padding: 1rem 0 2rem;
  padding-left: var(--pad-x);
  padding-right: var(--pad-x);
}

/* 嵌在 .app 里的对局区（2048 / 扫雷 / 数独 / 纸牌）不要再来一次 1040px 约束：
   父级已经是内容列了，再套一层两边各吃掉 12.8px（实测纸牌牌桌 1014.4 而不是 1040，
   手机上 364.4 而不是 377.2）。撑不出父级，直接 100% 即可。 */
.app .game,
.app #gameView,
#app .game,
#app #gameView {
  width: 100%;
}

/* ---------- 棋盘 canvas 的颜色钩子 ---------- */
/* 五子棋（gomoku.js）与跳棋（checkers.js）的棋盘是 canvas 画的，颜色一律从这几个
   变量读 —— 读不到就用 JS 里的兜底常量，那样切主题棋盘纹丝不动。
   ⚠️ 跳棋毡面**不能挂在 --accent 上**：强调色是用户从色盘里挑的，实测选砖红之后
   整块棋盘变成红棕色 —— 棋盘是"物件"，不该跟着强调色走。绿毡是这一页的身份，
   所以在这里定死绿色系；暗色主题另给一档深绿（本站主题由用户选择、写在
   localStorage 里，纯 CSS 读不到，用系统深浅作可靠兜底）。 */
:root {
  --gomoku-line: color-mix(in srgb, var(--ink) 55%, var(--sheet));
  --ck-felt-1: #3d8f68;
  --ck-felt-2: #24593f;
  --ck-hole: rgb(0 0 0 / 34%);
  /* 毡面是深色，所以骨架线用浅色、孔用更暗的色（压在毡面上才看得见） */
  --ck-grid: rgb(255 255 255 / 13%);
  --ck-p1: #c0442c;
  --ck-p2: #2f5f9e;
}

@media (prefers-color-scheme: dark) {
  :root {
    --ck-felt-1: #2f7355;
    --ck-felt-2: #1c4632;
    --ck-p1: #d4614a;
    --ck-p2: #5b8fd0;
  }
}

/* 手机上内容列本来就窄，再留 0.8rem×2 的边距，棋盘只能摊到 80% 宽 —— 收掉 */
@media (max-width: 720px) {
  .app,
  #app,
  .home,
  .game,
  #gameView {
    width: 100%;
    --pad-x: 0.4rem;
  }

  .app,
  #app,
  .home {
    padding-left: var(--pad-x);
    padding-right: var(--pad-x);
  }
}

/* ---------- 页头 ---------- */
.header {
  display: grid;
  justify-items: center;
  gap: 0.5rem;
  padding: 0 0 1.4rem;
  text-align: center;
}

.logo {
  width: 3.4rem;
  height: 3.4rem;
  display: grid;
  place-items: center;
  border: var(--rule);
  background: var(--accent);
  box-shadow: var(--shadow-sm);
}

.logo svg {
  width: 100%;
  height: 100%;
  display: block;
}

.title {
  font-size: clamp(calc(1.9rem * var(--font-scale, 1)), 6.5vw, calc(2.7rem * var(--font-scale, 1)));
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.05;
}

.subtitle {
  font-family: var(--font-mono);
  font-size: calc(0.78rem * var(--font-scale, 1));
  letter-spacing: 0.02em;
  color: var(--ink-soft);
  max-width: 34ch;
}

/* ---------- 首页模式列表 ---------- */
/* 竖排列表：这一世界的首页是"菜单"，不是仪表盘 —— 卡片横向铺满只会剩下空格子 */
.cards {
  display: grid;
  gap: 0.85rem;
  margin: 0 auto;
  width: 100%;
  max-width: 660px;
}

.card {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 0.9rem;
  width: 100%;
  padding: 0.85rem 1rem;
  border: var(--rule);
  background: var(--sheet);
  box-shadow: var(--shadow);
  text-align: left;
  transition: transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease),
    background-color var(--dur) var(--ease);
}

.card:hover {
  background: color-mix(in srgb, var(--accent) 9%, var(--sheet));
}

.card:active {
  transform: translate(4px, 4px);
  box-shadow: 0 0 0 var(--ink);
}

.card-icon {
  width: 2.9rem;
  height: 2.9rem;
  display: grid;
  place-items: center;
  border: var(--rule);
  background: color-mix(in srgb, var(--accent) 14%, var(--sheet));
}

.card-icon svg {
  width: 1.7rem;
  height: 1.7rem;
  display: block;
}

.card-body {
  min-width: 0;
}

.card-name {
  font-size: calc(1.02rem * var(--font-scale, 1));
  font-weight: 700;
  line-height: 1.25;
}

.card-desc {
  font-family: var(--font-mono);
  font-size: calc(0.72rem * var(--font-scale, 1));
  color: var(--ink-soft);
  line-height: 1.45;
}

.card-best {
  margin-top: 0.2rem;
  font-family: var(--font-mono);
  font-size: calc(0.72rem * var(--font-scale, 1));
  font-weight: 600;
  color: var(--accent-ink);
}

.card-side {
  display: grid;
  place-items: center;
  width: 1.6rem;
  height: 1.6rem;
  border: var(--rule);
  background: var(--ink);
  color: var(--sheet);
  flex: none;
}

/* 卡片两端的图标。
   ⚠️ 必须在这里统一写 fill:none —— 描边类图标（polyline/path/rect）只有 fill:none
   才画得出线，否则 SVG 默认 fill:#000 会把它们填成实心黑块。
   七个页面里有的包了 .chevron 有的没包（俄罗斯方块、华容道的箭头是 .card-side > svg），
   只在 .chevron 里写会让没包的页面把箭头画成黑三角（实测 tetris 就是这样，
   黑压黑 1.19:1）。所以这里按「卡片里的任何 svg」写。 */
.card-icon svg,
.card-side svg,
.chevron svg {
  display: block;
  fill: none;
  stroke: currentColor;
  stroke-linecap: square;
}

.card-icon svg {
  width: 1.7rem;
  height: 1.7rem;
  stroke-width: 1.8;
}

.card-side svg,
.chevron svg {
  width: 1rem;
  height: 1rem;
  stroke-width: 2.4;
}

.chevron {
  display: grid;
  place-items: center;
}

/* ---------- 页脚 ---------- */
/* ---------- 页脚 ---------- */
/* 与计算器/翻译页一致：居中一行小字，**没有**上边框、没有分隔线 */
.footer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  margin-top: 1.4rem;
  padding: 0 0.9rem 0.6rem;
  font-family: var(--font-mono);
  font-size: calc(0.7rem * var(--font-scale, 1));
  color: var(--ink-soft);
}

.footer a {
  color: var(--ink-soft);
  text-decoration: none;
}

.footer a:hover {
  color: var(--accent-ink);
}

.footer-sep {
  opacity: 0.5;
}

/* ---------- 帮助面板 ---------- */
.help-btn {
  position: fixed;
  top: 0.9rem;
  right: 0.9rem;
  z-index: 60;
  width: 2.4rem;
  height: 2.4rem;
  display: grid;
  place-items: center;
  border: var(--rule);
  background: var(--sheet);
  box-shadow: var(--shadow-sm);
  font-family: var(--font-mono);
  font-size: calc(0.95rem * var(--font-scale, 1));
  font-weight: 700;
  transition: transform var(--dur) var(--ease), background-color var(--dur) var(--ease);
}

.help-btn:hover {
  background: var(--accent);
  color: var(--on-accent);
}

/* 帮助面板按内容列流式排布：align-items:flex-start + 顶部内距，
   不要用 position:absolute; left:50%（那是相对视口居中，桌面下会飘出内容列） */
.help-overlay {
  position: fixed;
  inset: 0;
  z-index: 90;
  display: none;
  background: var(--scrim);
  align-items: flex-start;
  justify-content: center;
  padding: 3.4rem 0.9rem 2rem;
  overflow-y: auto;
}

.help-overlay.open {
  display: flex;
}

.help-card {
  width: 100%;
  max-width: 26rem;
  position: relative;
  background: var(--sheet);
  border: 3px solid var(--ink);
  box-shadow: var(--shadow-lg);
  padding: 1rem;
  max-height: 86vh;
  overflow-y: auto;
}

.help-card h2,
.help-card h3 {
  font-weight: 800;
  font-size: calc(0.94rem * var(--font-scale, 1));
  margin: 0 0 0.6rem;
  padding-bottom: 0.4rem;
  border-bottom: 3px solid var(--ink);
}

.help-card ul {
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
}

.help-card li {
  position: relative;
  padding-left: 0.9rem;
  font-size: calc(0.76rem * var(--font-scale, 1));
  line-height: 1.6;
  color: var(--ink-soft);
}

.help-card .dot {
  position: absolute;
  left: 0;
  top: 0.42rem;
  width: 0.42rem;
  height: 0.42rem;
  background: var(--accent);
  border: 1px solid var(--ink);
}

.help-card b {
  color: var(--ink);
  font-weight: 700;
}

.help-card kbd {
  display: inline-block;
  min-width: 1.5rem;
  padding: 0 0.3rem;
  margin: 0 0.1rem;
  border: 1px solid var(--ink);
  background: color-mix(in srgb, var(--ink) 8%, var(--sheet));
  font-family: var(--font-mono);
  font-size: calc(0.72rem * var(--font-scale, 1));
  text-align: center;
}

/* ---------- 设置抽屉（右） ----------
   ⚠️ 这一整段照抄计算器/翻译页的实现（视觉真相源 .impeccable/nb-css-draft.css
   的「设置抽屉头 / 覆层 / 卡片面 / 选项」几段），单位原样是 rem。
   游戏页曾经自己另写一套：卡片只有一条左边框、关闭钮做成墨底反白、
   色点选中用 outline、活跃项用强调色填充 —— 打开抽屉一眼就是两个世界的皮。 */
.settings-fab {
  position: fixed;
  top: 0.9rem;
  right: 3.7rem;
  z-index: 60;
  width: 2.4rem;
  height: 2.4rem;
  display: grid;
  place-items: center;
  border: var(--rule);
  background: var(--sheet);
  box-shadow: var(--shadow-sm);
  transition: transform var(--dur) var(--ease), background-color var(--dur) var(--ease);
}

.settings-fab:hover {
  background: var(--accent);
  color: var(--on-accent);
}

.settings-fab svg {
  width: 1.15rem;
  height: 1.15rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
}

/* 按下即压平：位移量 = 投影偏移量，手感是「按进去」而不是「缩一下」。
   规范见 docs/DEVELOP.md 2.6.1 —— 这一条此前游戏这边漏了，按下去毫无反馈，
   而 life 两页（翻译/计算器）一直是有的。 */
.help-btn:active,
.settings-fab:active {
  transform: translate(3px, 3px);
  box-shadow: 0 0 0 var(--ink);
}

.settings-overlay {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: none;
  background: var(--scrim);
  align-items: stretch;
  justify-content: flex-end;
  padding: 0;
}

.settings-overlay.open {
  display: flex;
}

.settings-panel {
  width: 100%;
  max-width: 21rem;
  height: 100%;
  display: flex;
  flex-direction: column;
  gap: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  background: var(--sheet);
  border: 3px solid var(--ink);
  box-shadow: var(--shadow-lg);
  padding: 1rem;
  /* 抽屉从右侧滑入：机械位移，不是淡入 */
  transform: translateX(100%);
}

.settings-overlay.open .settings-panel {
  animation: shell-slide 200ms var(--ease-out) forwards;
}

@keyframes shell-slide {
  to {
    transform: translateX(0);
  }
}

.settings-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-bottom: 0.6rem;
  margin-bottom: 0.8rem;
  border-bottom: 3px solid var(--ink);
}

.settings-title {
  font-weight: 800;
  font-size: calc(0.94rem * var(--font-scale, 1));
  letter-spacing: -0.02em;
}

.settings-close {
  width: 1.7rem;
  height: 1.7rem;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: var(--rule);
  background: var(--sheet);
  color: var(--ink);
  font-size: calc(0.8rem * var(--font-scale, 1));
  font-weight: 700;
  transition: transform var(--dur) var(--ease);
}

.settings-close:active {
  transform: translate(2px, 2px);
}

.settings-section {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  margin-bottom: 1rem;
}

.settings-section-title {
  font-family: var(--font-mono);
  font-size: calc(0.7rem * var(--font-scale, 1));
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.option-row,
.color-picker-row,
.switch-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.3rem;
}

.color-picker-row {
  gap: 0.35rem;
}

/* 当前所处的位置用**实心墨块反白**表达，不是换色 —— 这是本世界表达选中态的唯一方式 */
.opt-btn {
  padding: 0.5rem 0.8rem;
  border: var(--rule);
  background: var(--sheet);
  color: var(--ink);
  font-size: calc(0.72rem * var(--font-scale, 1));
  font-weight: 700;
  transition: background-color var(--dur) var(--ease), color var(--dur) var(--ease);
}

.opt-btn.active {
  background: var(--ink);
  color: var(--sheet);
}

.opt-btn:active {
  transform: translate(1px, 1px);
}

.color-label {
  flex: 0 0 auto;
  width: 2.4rem;
  font-family: var(--font-mono);
  font-size: calc(0.7rem * var(--font-scale, 1));
  color: var(--ink-soft);
}

.color-dot {
  width: 1.6rem;
  height: 1.6rem;
  display: inline-block;
  border: var(--rule);
  transition: transform var(--dur) var(--ease);
}

.color-dot:hover {
  transform: translate(-1px, -1px);
  box-shadow: 2px 2px 0 var(--ink);
}

/* 选中的色点用双内描边，不用 outline —— 与计算器一致 */
.color-dot.sel {
  box-shadow: inset 0 0 0 2px var(--sheet), inset 0 0 0 4px var(--ink);
}

.switch-label {
  flex: 1;
  font-size: calc(0.82rem * var(--font-scale, 1));
}

.switch {
  position: relative;
  width: 2.8rem;
  height: 1.5rem;
  border: var(--rule);
  background: var(--sheet);
  flex: none;
}

.switch::after {
  content: '';
  position: absolute;
  top: 2px;
  left: 2px;
  width: 1rem;
  height: 0.72rem;
  background: var(--ink-soft);
  transition: transform var(--dur) var(--ease), background-color var(--dur) var(--ease);
}

.switch.on::after {
  transform: translateX(1.16rem);
  background: var(--accent);
}

/* ---------- 对局顶栏（七个页面共用一套尺寸） ---------- */
/* 整行内容水平居中：原来返回钮顶在内容列最左缘（实测 x=13），
   而内容列宽 721 —— 一行内容只占 13..351，右边空一半，看起来就是偏左。
   居中后与棋盘对齐（棋盘本来就是居中的）。 */
.status-row,
.top,
.stats,
.nav-bar {
  justify-content: center;
}

/* 四个棋类的标题条也一样居中：返回钮与标题成组，而不是把返回钮钉在最左缘。
   注意：2048 的顶栏是 grid（auto + minmax(0,1fr)），grid 项默认 stretch，
   读数格会被拉到整行高（实测 54px）。这里让 grid 项垂直居中，保持统一高度。

   实测各页原来是各写各的：返回钮 37×37 / 38×31 / 38×38 / 40×54 四种，
   模式标签高 31 / 32 / 35，读数格高 24~54，行内间距 8 / 8.8 / 9.6 三种，
   读数标签字号 9.28 / 9.6、数值 16 / 16.32 —— 换一页就换一个样子。
   这里定死一套：返回钮 38 见方、标签与读数格同高、间距 0.55rem。 */
.top {
  align-items: center;
}

.back-btn {
  width: 2.375rem;
  height: 2.375rem;
  display: grid;
  place-items: center;
  border: var(--rule);
  background: var(--sheet);
  color: var(--ink);
  box-shadow: none;
  flex: none;
  transition: background-color var(--dur) var(--ease), color var(--dur) var(--ease),
    transform var(--dur) var(--ease);
}

.back-btn svg,
.back svg {
  width: 1.125rem;
  height: 1.125rem;
  display: block;
  fill: none;
  stroke: currentColor;
  stroke-width: 2.4;
  stroke-linecap: square;
}

.chip,
.title-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  height: 2rem;
  padding: 0 0.65rem;
  border: var(--rule);
  background: var(--accent);
  color: var(--on-accent);
  font-family: var(--font-mono);
  font-size: calc(0.74rem * var(--font-scale, 1));
  font-weight: 700;
  letter-spacing: 0.04em;
  line-height: 1;
  white-space: nowrap;
  flex: none;
}

.title-chip .stars {
  font-size: calc(0.7rem * var(--font-scale, 1));
  letter-spacing: 0.1em;
  opacity: 0.85;
}

/* 读数格：纸面底 + 2px 墨框，标签等宽小字、数值等宽大字 */
.stat-box,
.stat {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.35rem;
  height: 2rem;
  min-width: 0;
  padding: 0 0.55rem;
  border: var(--rule);
  background: var(--sheet);
}

.stat-box > span:first-child,
.stat-box .lb,
.stat-label {
  font-family: var(--font-mono);
  font-size: calc(0.58rem * var(--font-scale, 1));
  letter-spacing: 0.08em;
  color: var(--ink-soft);
  line-height: 1;
}

.stat-box .v,
.stat-box .clock,
.stat-box .remain,
.stat-value,
.score-val,
.clock-time {
  font-family: var(--font-mono);
  font-size: calc(0.95rem * var(--font-scale, 1));
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 1;
}

/* ---------- 屏幕顶部的两个固定圆钮 ---------- */
/* 对局页右上角压着「设置」「帮助」两个固定按钮，横铺到最右边的状态条会被它们盖住
   （实测 klotski 的读数格与按钮重叠 775px）。所以对局里的横向状态条在右端留出位置。
   ⚠️ 只在真有悬停指针的宽屏上留：进对局后这两个按钮会被 JS 加上 .hidden 收起来
   （各页 newGame 里都做了），窄屏再留 6.4rem 会把读数格压成两行、还会让
   工具条比棋盘短一截（实测数独工具条右端比棋盘短 102.4px）。 */
@media (min-width: 721px) and (hover: hover) {
  .status-row,
  .top,
  .stats {
    padding-right: 6.4rem;
  }
}

@media (max-width: 720px) {
  .status-row,
  .top,
  .stats,
  .toolbar {
    flex-wrap: wrap;
    padding-right: 0;
  }
}

/* ---------- 轻提示 ---------- */
.toast {
  position: fixed;
  left: 50%;
  bottom: 1.4rem;
  z-index: 200;
  transform: translateX(-50%) translateY(0.6rem);
  max-width: 84vw;
  padding: 0.55rem 0.95rem;
  border: var(--rule);
  background: var(--ink);
  color: var(--sheet);
  font-size: calc(0.72rem * var(--font-scale, 1));
  font-weight: 700;
  text-align: center;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease);
}

.toast.show {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

/* ---------- 断点 ---------- */
/* 手机上屏幕顶部的两个圆钮会压住内容，把固定按钮那一行的空间留出来 */
@media (max-width: 720px) {
  .card {
    grid-template-columns: auto minmax(0, 1fr);
  }

  .card-side {
    display: none;
  }

  /* 顶栏在窄屏上更紧凑：字号与内距各收一档，
     并让模式标签在极窄时可以截断，而不是把读数挤出去。
     （实测 320px 时 返回钮 + 标签 + 三个读数 已经把整行占满。） */
  .chip,
  .title-chip {
    height: 1.85rem;
    padding: 0 0.5rem;
    font-size: calc(0.68rem * var(--font-scale, 1));
    letter-spacing: 0.02em;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 46vw;
  }

  /* ⚠️ 这里只能写 .back-btn，绝不能带裸 `.back` ——
     纸牌的**牌背**类名就叫 .back（`.face.back`），而这条在源码顺序上比
     solitaire.css 的同优先级规则更靠后，会把牌背强制成 2.2rem 的正方形
     （实测牌背 35.19×35.19 而正面 51×71，用户圈出来的就是这个）。 */
  .back-btn {
    width: 2.2rem;
    height: 2.2rem;
  }

  .stat-box,
  .stat {
    height: 1.85rem;
    padding: 0 0.45rem;
  }

  .stat-box .v,
  .stat-box .clock,
  .stat-box .remain,
  .stat-value,
  .score-val,
  .clock-time {
    font-size: calc(0.88rem * var(--font-scale, 1));
  }
}

@media (max-width: 400px) {
  /* 极窄：让读数条整行换到第二行，顶栏不再和读数抢宽度 */
  .status-row {
    row-gap: 0.4rem;
  }

  .title-chip {
    max-width: 38vw;
  }
}
