/* ==========================================================================
   app.css —— 页面骨架、卡片网格、播放页、虚拟键盘
   令牌和基础控件在 base.css。
   ========================================================================== */

/* ---------- 骨架 ---------- */
.head,
main,
footer.site { position: relative; z-index: 1; }

.head { position: sticky; top: 0; z-index: 20; }

.topbar {
  position: relative;
  z-index: 2;
  --glass-bg: linear-gradient(to bottom, color-mix(in srgb, #fff 18%, transparent), color-mix(in srgb, var(--surface) 42%, transparent));
  --glass-filter: blur(14px) saturate(1.25);
  border-bottom: 1px solid var(--line);
}
.topbar-inner {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 9px 18px;
  display: flex;
  align-items: center;
  gap: 12px;
}

.brand { display: flex; align-items: center; gap: 9px; color: var(--ink); text-decoration: none; flex: 0 0 auto; }
.brand:hover { text-decoration: none; }
.brand-mark {
  width: 30px;
  height: 30px;
  border-radius: 8px;
  display: grid;
  place-items: center;
  color: #fff;
  background: linear-gradient(165deg, var(--accent), color-mix(in srgb, var(--accent) 55%, #06201a));
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.3), 0 2px 7px color-mix(in srgb, var(--accent) 34%, transparent);
  flex: 0 0 auto;
}
.brand-mark svg { display: block; }
.brand-text { display: flex; flex-direction: column; line-height: 1.15; }
.brand-name { font-size: 15px; font-weight: 700; letter-spacing: 0.2px; }
.brand-sub { font-size: 10.5px; font-weight: 500; color: var(--ink-3); letter-spacing: 0.3px; }

.search { flex: 1 1 300px; min-width: 150px; max-width: 520px; position: relative; }
.search input {
  width: 100%;
  height: 32px;
  padding: 0 30px 0 31px;
  border: 1px solid var(--line-2);
  border-radius: 999px;
  background: var(--surface-2);
  color: var(--ink);
  font: inherit;
  font-size: 13.5px;
  transition: border-color 0.14s, background 0.14s, box-shadow 0.14s;
}
.search input::placeholder { color: var(--ink-3); }
.search input:focus { outline: none; background: var(--surface); border-color: var(--accent); box-shadow: var(--ring); }
.search .icon { position: absolute; left: 10px; top: 50%; transform: translateY(-50%); color: var(--ink-3); pointer-events: none; display: grid; }
.search .clear {
  position: absolute; right: 5px; top: 50%; transform: translateY(-50%);
  border: 0; background: none; color: var(--ink-3); cursor: pointer;
  padding: 4px; display: none; border-radius: 50%; line-height: 0;
}
.search .clear:hover { color: var(--ink); background: var(--surface-3); }
.search.has-value .clear { display: grid; }
.search .slash {
  position: absolute; right: 9px; top: 50%; transform: translateY(-50%);
  pointer-events: none; color: var(--ink-3); font-size: 10.5px;
  border: 1px solid var(--line-2); border-radius: 4px; padding: 0 4px; line-height: 15px;
}
.search.has-value .slash, .search:focus-within .slash { display: none; }

.topbar-actions { display: flex; align-items: center; gap: 6px; margin-left: auto; flex: 0 0 auto; }

/* ---------- 分类条 ---------- */
.filterbar {
  position: relative;
  z-index: 1;
  --glass-bg: color-mix(in srgb, var(--surface) 34%, transparent);
  --glass-filter: blur(14px) saturate(1.25);
  border-bottom: 1px solid var(--line);
}
.filterbar-inner {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 7px 18px;
  display: flex;
  gap: 5px;
  overflow-x: auto;
  scrollbar-width: thin;
}
.filterbar-inner::-webkit-scrollbar { height: 4px; }
.filterbar-inner::-webkit-scrollbar-thumb { background: var(--line-2); border-radius: 2px; }

.chip {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 10px;
  border: 1px solid transparent;
  border-radius: 999px;
  background: transparent;
  color: var(--ink-2);
  font: inherit;
  font-size: 12.5px;
  font-weight: 550;
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.13s, color 0.13s, border-color 0.13s;
}
.chip:hover { background: var(--surface-2); color: var(--ink); }
.chip[aria-pressed="true"] { background: var(--accent); border-color: transparent; color: var(--accent-ink); font-weight: 650; }
.chip .n { font-size: 10.5px; font-weight: 600; opacity: 0.62; font-variant-numeric: tabular-nums; }
.chip[aria-pressed="true"] .n { opacity: 0.85; }

/* ---------- 主区 ---------- */
main { max-width: var(--maxw); margin: 0 auto; padding: 16px 18px 8px; }

.toolbar {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  padding: 0 0 13px;
}
.toolbar .spacer { flex: 1 1 auto; }
.toolbar h2 { font-size: 14px; font-weight: 650; letter-spacing: 0; }

/* 继续游玩：横向滚动条，卡片矮一点，避免抢主网格 */
.strip { margin: 0 0 16px; }
.strip-head { display: flex; align-items: baseline; gap: 8px; margin-bottom: 8px; }
.strip-head h2 { font-size: 13px; font-weight: 650; }
.strip-head .count { font-size: 12px; }
.strip-rail { display: flex; gap: 9px; overflow-x: auto; padding-bottom: 6px; scrollbar-width: thin; }
.strip-rail::-webkit-scrollbar { height: 5px; }
.strip-rail::-webkit-scrollbar-thumb { background: var(--line-2); border-radius: 3px; }
.strip-rail .card { flex: 0 0 116px; width: 116px; }
.strip-rail .card .card-title { font-size: 12px; -webkit-line-clamp: 1; min-height: 0; }
.strip-rail .card .thumb { width: calc(100% - 16px); margin: 8px 8px 0; aspect-ratio: 1 / 1; }

/* ---------- 网格与卡片 ---------- */
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(var(--card-min), 1fr)); gap: var(--gap); }

.card {
  position: relative;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  cursor: pointer;
  border: 1px solid color-mix(in srgb, var(--accent) 12%, var(--line));
  border-radius: var(--radius-lg);
  /* 大网格里逐卡开 backdrop-filter 是掉帧主因。
     玻璃感改由"半透明底色 + 边框反光 + 内高光"承担，一次绘制即可。 */
  background:
    linear-gradient(150deg, var(--glass-tint), transparent 42%),
    color-mix(in srgb, var(--surface) 84%, transparent);
  box-shadow: 0 2px 8px rgba(20, 35, 29, 0.07), inset 0 1px 0 color-mix(in srgb, #fff 58%, transparent);
  transition: border-color 0.18s, box-shadow 0.22s var(--ease-out);
  content-visibility: auto;
  contain-intrinsic-size: auto 268px;
}
:root[data-theme="dark"] .card {
  background:
    linear-gradient(150deg, var(--glass-tint), transparent 46%),
    color-mix(in srgb, #0b100e 78%, transparent);
  border-color: color-mix(in srgb, var(--glass-edge) 72%, var(--line));
}
.card::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  border-radius: inherit;
  box-shadow: inset 0 1px 0 var(--glass-edge), inset 0 -1px 0 color-mix(in srgb, var(--accent) 9%, transparent);
}
.card:hover {
  border-color: var(--accent-line);
  transform: translateY(-2px);
  transition: transform 0.18s var(--ease-out), border-color 0.18s, box-shadow 0.18s;
  box-shadow: 0 10px 24px rgba(20, 35, 29, 0.13), 0 0 0 1px var(--accent-line);
}
.card:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) { .card:hover { transform: none; } }

.thumb {
  position: relative;
  width: calc(100% - 18px);
  margin: 9px 9px 0;
  aspect-ratio: 3 / 4;
  overflow: hidden;
  background: transparent;
  border: 1px solid color-mix(in srgb, var(--glass-edge) 38%, var(--line));
  border-radius: 10px;
  box-shadow: 0 2px 8px rgba(8, 16, 13, 0.12);
}
.thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: top center;
  image-rendering: pixelated;
  display: block;
}
/* 底部压一层暗，badge 和播放键才不会糊在图上 */
.thumb::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 46%;
  background: linear-gradient(to top, rgba(6, 12, 9, 0.5), transparent);
  pointer-events: none;
}

.thumb .fallback {
  position: absolute;
  inset: 0;
  display: none;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 7px;
  padding: 12px 10px;
  text-align: center;
  color: var(--ink);
  background:
    linear-gradient(145deg, var(--glass-glow), transparent 56%),
    repeating-linear-gradient(45deg, color-mix(in srgb, var(--accent) 8%, transparent) 0 1px, transparent 1px 7px),
    color-mix(in srgb, var(--surface) 88%, transparent);
}
.thumb.noimg .fallback { display: flex; }
.thumb .fallback b {
  display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical;
  overflow: hidden; font-size: 12.5px; font-weight: 650; line-height: 1.42;
  color: var(--ink);
}
.thumb .fallback i {
  font-style: normal; font-size: 9.5px; letter-spacing: 1.4px;
  color: var(--ink-2); border-top: 1px solid var(--line); padding-top: 5px;
}

.thumb .badge { position: absolute; left: 6px; top: 6px; z-index: 2; }

.go {
  position: absolute;
  right: 7px;
  bottom: 7px;
  z-index: 2;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--accent);
  color: var(--accent-ink);
  box-shadow: 0 3px 10px rgba(0, 0, 0, 0.3);
  opacity: 0;
  transform: scale(0.82);
  transition: opacity 0.16s, transform 0.16s;
  pointer-events: none;
}
.card:hover .go, .card:focus-visible .go { opacity: 1; transform: scale(1); }
@media (pointer: coarse) { .go { opacity: 1; transform: scale(1); } }

.card-body { padding: 10px 11px 12px; display: flex; flex-direction: column; gap: 3px; flex: 1; }
.card-title {
  font-size: 13px;
  font-weight: 650;
  line-height: 1.35;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  min-height: 2.7em;
}
.card-meta {
  margin-top: auto;
  display: flex;
  align-items: center;
  gap: 5px;
  font-size: 11.5px;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}
.card-meta .dot { width: 3px; height: 3px; border-radius: 50%; background: currentColor; opacity: 0.5; flex: 0 0 auto; }
.card-meta .fav { color: var(--danger); display: grid; }

/* 列表视图 */
.grid.list { grid-template-columns: 1fr; gap: 8px; }
.grid.list .card { flex-direction: row; align-items: stretch; contain-intrinsic-size: auto 92px; }
.grid.list .card .thumb { width: 70px; flex: 0 0 70px; aspect-ratio: 3 / 4; border-bottom: 0; border-right: 1px solid var(--line); }
.grid.list .card .thumb .fallback b { -webkit-line-clamp: 2; font-size: 10.5px; }
.grid.list .card .thumb .fallback i { display: none; }
.grid.list .card .go { width: 22px; height: 22px; right: 4px; bottom: 4px; }
.grid.list .card-body { padding: 9px 11px; }
.grid.list .card-title { -webkit-line-clamp: 1; min-height: 0; font-size: 13.5px; }

.skeleton { height: 258px; border-radius: var(--radius-lg); background: linear-gradient(90deg, var(--surface-2) 25%, var(--surface-3) 50%, var(--surface-2) 75%); background-size: 400% 100%; animation: shimmer 1.4s infinite; }
@keyframes shimmer { from { background-position: 100% 0; } to { background-position: 0 0; } }

.empty { padding: 68px 20px; text-align: center; color: var(--ink-3); }
.empty svg { color: var(--line-2); margin-bottom: 6px; }
.empty p { margin: 0 0 14px; font-size: 13.5px; }

/* ---------- 详情弹窗内容 ---------- */
.shots { display: flex; gap: 8px; overflow-x: auto; padding-bottom: 8px; margin-bottom: 14px; scrollbar-width: thin; }
.shots img {
  height: 176px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  image-rendering: pixelated;
  background: var(--screen);
  cursor: zoom-in;
  flex: 0 0 auto;
}
.lightbox {
  padding: 10px;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line-2);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  max-width: calc(100vw - 24px);
}
.lightbox[open] { display: grid; place-items: center; }
.lightbox[hidden] { display: none !important; }
.lightbox img { max-width: 100%; max-height: 76dvh; image-rendering: pixelated; background: #000; border-radius: var(--radius); }
.lightbox img.broken { display: none; }
.shots img.broken { display: none; }
.lightbox-note { display: none; margin: 6px 4px; font-size: 13px; color: var(--ink-2); }
.lightbox.img-broken .lightbox-note { display: block; }
.intro { color: var(--ink-2); line-height: 1.7; margin: 0 0 15px; font-size: 13.5px; white-space: pre-wrap; word-break: break-word; }

/* ---------- 页脚 ---------- */
footer.site { position: relative; border-top: 1px solid var(--line); --glass-bg: color-mix(in srgb, var(--surface) 72%, transparent); --glass-filter: blur(8px); padding: 18px 20px 26px; margin-top: 26px; }
footer.site .inner { max-width: var(--maxw); margin: 0 auto; font-size: 12.5px; color: var(--ink-3); line-height: 1.85; display: flex; flex-wrap: wrap; gap: 4px 14px; align-items: baseline; }
footer.site .inner > span { flex: 1 1 340px; }

.prose { max-width: 780px; }
.prose h1 { font-size: 22px; margin: 4px 0 16px; }
.prose h2 { font-size: 15.5px; margin: 24px 0 8px; }
.prose p, .prose li { color: var(--ink-2); line-height: 1.8; font-size: 13.5px; }
.prose ul { padding-left: 20px; }
.prose code { background: var(--surface-2); border: 1px solid var(--line); border-radius: 4px; padding: 1px 5px; font-size: 12.5px; }

/* ---------- 回到顶部 ---------- */
.totop {
  position: fixed;
  right: 18px;
  bottom: calc(18px + env(safe-area-inset-bottom, 0px));
  z-index: 40;
  opacity: 0;
  pointer-events: none;
  transform: translateY(8px);
  transition: opacity 0.18s, transform 0.18s;
  --glass-bg: color-mix(in srgb, var(--surface) 92%, transparent);
  --glass-filter: blur(12px);
}
.totop.show { opacity: 1; pointer-events: auto; transform: none; }

/* ==========================================================================
   播放页
   ========================================================================== */
.play-shell {
  height: 100dvh;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 322px;
  grid-template-rows: auto minmax(0, 1fr);
  background: var(--stage);
}

.play-bar {
  grid-column: 1 / -1;
  position: relative;
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 8px 12px;
  --glass-bg: color-mix(in srgb, var(--surface) 92%, transparent);
  --glass-filter: blur(12px) saturate(1.4);
  border-bottom: 1px solid var(--line);
  flex-wrap: wrap;
  position: relative;
  z-index: 30;
}
.play-bar h1 { font-size: 14.5px; font-weight: 650; max-width: 34ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.play-bar .spacer { flex: 1 1 auto; }

.stage {
  position: relative;
  display: grid;
  place-items: center;
  overflow: hidden;
  background:
    radial-gradient(120% 80% at 50% 0%, color-mix(in srgb, var(--accent) 9%, transparent), transparent 62%),
    var(--player-stage-bg, var(--stage));
  min-height: 0;
}
.stage iframe { width: 100%; height: 100%; border: 0; background: var(--player-stage-bg, var(--stage)); display: block; will-change: transform; }

/* 全屏模式的退出按钮：右上角浮层，全屏时顶栏看不见，必须留可见出口 */
#fsExit {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 6;
  opacity: 0.88;
}
#fsExit[hidden] { display: none !important; }

.stage-loading {
  position: absolute;
  inset: 0;
  z-index: 3;
  display: grid;
  place-content: center;
  justify-items: center;
  gap: 12px;
  padding: 24px;
  text-align: center;
  color: #d8e2dc;
  background: var(--stage);
}
.stage-loading[hidden] { display: none; }
.stage-loading .l1 { font-size: 14px; font-weight: 600; }
.stage-loading .l2 { font-size: 12px; color: #8d9a93; }
.stage-loading .spin {
  width: 26px; height: 26px;
  border-radius: 50%;
  border: 2.5px solid rgba(255, 255, 255, 0.16);
  border-top-color: var(--accent);
  animation: spin 0.8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

.bar { width: min(320px, 72vw); height: 5px; border-radius: 999px; background: rgba(255, 255, 255, 0.1); overflow: hidden; }
.bar > i { display: block; height: 100%; width: 0; background: var(--accent); transition: width 0.16s; }

.stage-error {
  position: absolute;
  inset: 0;
  z-index: 4;
  display: grid;
  place-content: center;
  justify-items: center;
  gap: 10px;
  padding: 26px;
  text-align: center;
  color: #e6dede;
  background: color-mix(in srgb, var(--danger) 12%, var(--stage));
}
.stage-error[hidden] { display: none; }
.stage-error h3 { font-size: 15px; color: #fff; }
.stage-error p { font-size: 12.5px; color: #b9a9a9; max-width: 44ch; line-height: 1.7; }

/* ---------- 侧栏 ---------- */
.side {
  grid-row: 2;
  grid-column: 2;
  position: relative;
  display: flex;
  flex-direction: column;
  min-height: 0;
  --glass-bg: color-mix(in srgb, var(--surface) 90%, transparent);
  --glass-filter: blur(16px) saturate(1.4);
  border-left: 1px solid var(--line);
}
.side .tabs { flex: 0 0 auto; padding: 6px 8px 0; background: color-mix(in srgb, var(--surface) 92%, transparent); }
.side-body { flex: 1; overflow-y: auto; overscroll-behavior: contain; padding: 14px; display: flex; flex-direction: column; gap: 16px; }
.side-body section > .section-label { display: flex; align-items: center; gap: 6px; }
.side-body section + section { padding-top: 15px; border-top: 1px solid var(--line); }

.setting-row { display: grid; grid-template-columns: 1fr auto; align-items: center; gap: 8px 10px; padding: 5px 0; }
.setting-row > label { font-size: 12.5px; color: var(--ink-2); }
.setting-row select, .setting-row input[type="number"] { min-width: 108px; }
input[type="number"] { font-variant-numeric: tabular-nums; }

.key-action { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 3px 0; }
.key-action > span { font-size: 12.5px; color: var(--ink-2); }
.key-action button {
  min-width: 92px;
  padding: 4px 8px;
  border: 1px solid var(--line-2);
  border-radius: var(--radius);
  background: var(--surface-2);
  color: var(--ink);
  font: inherit;
  font-size: 12px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
  transition: border-color 0.13s, background 0.13s, color 0.13s, box-shadow 0.13s;
}
.key-action button:hover { border-color: var(--accent-line); background: var(--surface); }
.key-action button.listening {
  border-color: var(--accent);
  color: var(--accent);
  background: var(--accent-soft);
  box-shadow: var(--ring);
}

.save-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface-2);
  font-size: 12.5px;
}
.save-item .grow { flex: 1 1 auto; min-width: 0; }
.save-item b { display: block; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.save-item small { color: var(--ink-3); font-size: 11px; font-variant-numeric: tabular-nums; }

/* ==========================================================================
   虚拟键盘（父页面持有，覆盖在画面下方，跟着主题色走）
   ========================================================================== */
.keypad {
  position: absolute;
  left: 50%;
  top: 50%;
  z-index: 5;
  display: none;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  /* 面板尺寸跟随本站原生布局；整体缩放由根容器统一处理 */
  width: fit-content;
  max-width: min(96vw, 430px);
  padding: 8px;
  border: 1px solid rgba(255, 255, 255, 0.13);
  border-radius: 16px;
  /* 机身：上缘受光、下缘压暗，做出一点厚度，而不是贴一块半透明黑 */
  --glass-bg:
    linear-gradient(180deg, rgba(255, 255, 255, 0.09), transparent 22%),
    linear-gradient(168deg, rgba(30, 42, 36, 0.94), rgba(6, 11, 9, 0.96));
  --glass-filter: blur(10px);
  box-shadow:
    0 20px 52px rgba(0, 0, 0, 0.42),
    0 2px 0 rgba(0, 0, 0, 0.5),
    inset 0 1px 0 rgba(255, 255, 255, 0.14),
    inset 0 -2px 0 rgba(0, 0, 0, 0.4);
  user-select: none;
  -webkit-user-select: none;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  transform: scale(var(--kp-scale, 1));
  transform-origin: center center;
  /* 整体透明度：叠在游戏画面上的键盘可以调淡，读到哪个主题/自定义色都不影响 */
  opacity: var(--kp-opacity, 1);
}
/* 键盘发糊的根因之一：backdrop-filter 会把面板连同文字一起送进背景根重光栅化。
   播放页一律不模糊，对比度由 --glass-bg 的 9 成不透明底承担（≤1000px 的同款
   规则在响应式区，这里补齐桌面端）。 */
.playing .keypad { --glass-filter: none; }
.keypad[hidden] { display: none !important; }
.stage.has-keypad .keypad { display: flex; }
.stage.has-keypad iframe { width: 100%; height: 100%; }

.kp-handle {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
  /* 把手挪进内核/缩放中间那一格：贴着功能键，不再飘到面板外面 */
  justify-self: center;
  align-self: center;
  height: 22px;
  padding: 0 5px;
  width: max-content;
  max-width: 100%;
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  border: 0;
  border-radius: 8px;
  color: var(--kp-handle-ink, rgba(236, 244, 238, 0.55));
  background: var(--kp-handle-bg, rgba(255, 255, 255, 0.05));
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.07);
  font: 600 10.5px/1 inherit;
  font-family: inherit;
  cursor: grab;
  touch-action: none;
}
.kp-handle:active { cursor: grabbing; }
.kp-handle i { flex: 0 0 auto; width: 12px; height: 2px; border-radius: 2px; background: currentColor; opacity: 0.58; box-shadow: 0 -4px 0 currentColor, 0 4px 0 currentColor; }

/* 各组一律用 vw/px 定宽，不用百分比：百分比在 shrink-to-fit 父级里解不出来，
   会把整块键盘塌成文字最小宽（按键只剩 21px）。
   宽度同时乘单键缩放系数：键真实变大，网格跟着让位，而不是 transform
   视觉放大互相压盖（keyScale>1.1 时重叠、文字按原尺寸拉伸发糊，真机踩过）。 */
.kp-shell { display: flex; flex-direction: column; gap: 7px; }
.kp-group { display: grid; gap: 6px; }
/* 直板机的纵向顺序：功能键最上一排，软键第二排左右角，十字居中，数字盘贴底。
   中间三列加宽给十字，两侧窄列给软键和功能键收口，
   方向键既不会被挤成窄条，也不会跟着软键一起摊扁。 */
.kp-dpad {
  grid-template-columns: 0.74fr 1.34fr 1.26fr 1.34fr 0.74fr;
  grid-template-areas:
    "f1   f1   hd   f2   f2"
    "sl   sl   .    sr   sr"
    ".    .    up   .    ."
    ".    left ok   right ."
    ".    .    down .    .";
  width: min(54vw, calc(268px * var(--kp-key-scale, 1)));
}
/* 轻量内核没有「内核菜单/1:1 缩放」这两个动作（用户实测无反馈，要求隐藏）：
   软1/软2 上移到第一排两侧占原功能键槽位（变成大按钮），把手居中原尺寸，
   原软键行整行省掉，键盘矮一行 */
.kp-dpad.dpad-nofn {
  grid-template-areas:
    "sl   sl   hd   sr   sr"
    ".    .    up   .    ."
    ".    left ok   right ."
    ".    .    down .    .";
}
/* 数字盘在并排布局里让位给方向组：游戏时它用得少，缩到 3 列窄盘即可 */
.kp-num { grid-template-columns: repeat(3, 1fr); width: min(34vw, calc(168px * var(--kp-key-scale, 1))); }
.k-sl { grid-area: sl; }
.k-f1 { grid-area: f1; }
.k-f2 { grid-area: f2; }
.k-sr { grid-area: sr; }
.k-up { grid-area: up; }
.k-left { grid-area: left; }
.k-ok { grid-area: ok; }
.k-right { grid-area: right; }
.k-down { grid-area: down; }
.k-hd { grid-area: hd; }

/* 十字单独加高：40px 高的方向键看着就是扁药片，46px 才有实体方向键的手感。
   选择器要压过下面 .stage.kp-classic .key 这类三类规则，所以多挂一层。
   软键也加高：30px 上下的软键就是扁条，实体机软键又宽又厚，
   38px 起才有按压手感（真机反馈"太扁"）。 */
.stage .kp-shell .kp-dpad .key { min-height: calc(50px * var(--kp-key-scale, 1)); }
.stage .kp-shell .kp-dpad .k-f1,
.stage .kp-shell .kp-dpad .k-f2 { min-height: calc(26px * var(--kp-key-scale, 1)); }
.stage .kp-shell .kp-dpad .k-sl,
.stage .kp-shell .kp-dpad .k-sr { min-height: calc(38px * var(--kp-key-scale, 1)); }

/* 双手 / 紧凑 / 宽屏三种布局必须真差异化（用户点名"布局了个寂寞"）：
   宽度一律用 flex 比例或 vw 上限，**绝不用 vw 相加**——
   58vw + 38vw 在窄屏必然把两组推出面板（2026-09-11 修）。
   面板必须给确定宽度，flex 才有可分配的空间；fit-content 配 flex-basis:0 会塌。
   - game  双手：左右两组完全分离贴边（space-between），键加厚——横握双手拇指区
   - compact 紧凑：并排居中但整体最小化（面板/键高/gap 全面缩小）——少挡画面
   - wide  宽屏：横条式——十字横排成操作条、数字盘 6 列两行，整体最矮——横屏贴底 */
.stage.kp-game .keypad { width: min(100vw - 16px, 470px); }
.stage.kp-compact .keypad { width: min(88vw, 360px); }
.stage.kp-wide .keypad { width: min(98vw, 560px); }

.stage.kp-game .kp-shell,
.stage.kp-compact .kp-shell {
  flex-direction: row;
  /* 两组等高：数字盘只有 4 行、方向组有 5 行，flex-end 会在右上角留一块空。
     stretch + 数字盘行高 1fr，两边上下都对齐，看着才像一套手柄。 */
  align-items: stretch;
  justify-content: center;
  gap: clamp(8px, 2.4vw, 16px);
}
.stage.kp-game .kp-dpad,
.stage.kp-compact .kp-dpad { flex: 5 1 0; min-width: 0; width: auto; }
.stage.kp-game .kp-num,
.stage.kp-compact .kp-num { flex: 3 1 0; min-width: 0; width: auto; grid-auto-rows: 1fr; align-content: stretch; }

/* game 双手：两组甩开贴边，中缝让给画面；键加厚到 56px 有握感 */
.stage.kp-game .kp-shell { justify-content: space-between; gap: 10px; }
.stage.kp-game .kp-shell .kp-dpad .key { min-height: calc(56px * var(--kp-key-scale, 1)); }
.stage.kp-game .kp-shell .kp-num .key { min-height: calc(52px * var(--kp-key-scale, 1)); }

/* compact 紧凑：整体小一号，键薄、缝窄 */
.stage.kp-compact .kp-shell { gap: 5px; }
.stage.kp-compact .kp-shell .kp-dpad .key { min-height: calc(34px * var(--kp-key-scale, 1)); font-size: calc(11px * var(--kp-key-scale, 1)); }
.stage.kp-compact .kp-shell .kp-dpad .k-sl,
.stage.kp-compact .kp-shell .kp-dpad .k-sr { min-height: calc(28px * var(--kp-key-scale, 1)); }
.stage.kp-compact .kp-shell .kp-dpad .k-f1,
.stage.kp-compact .kp-shell .kp-dpad .k-f2 { min-height: calc(22px * var(--kp-key-scale, 1)); }
.stage.kp-compact .kp-shell .kp-num .key { min-height: calc(34px * var(--kp-key-scale, 1)); font-size: calc(11px * var(--kp-key-scale, 1)); }

/* wide 宽屏：横条式。十字改横排操作条（软1 左 OK 右 软2 一行，
   功能/上/把手/下 一行），数字盘 6 列两行；总高约为并排布局的 2/3 */
.stage.kp-wide .kp-shell { flex-direction: column; gap: 5px; }
.stage.kp-wide .kp-dpad {
  grid-template-columns: repeat(5, 1fr);
  grid-template-areas:
    "sl    left ok    right sr"
    "f1    up   hd    down  f2";
  width: 100%;
}
.stage.kp-wide .kp-num { grid-template-columns: repeat(6, 1fr); width: 100%; }
.stage.kp-wide .kp-shell .kp-dpad .key,
.stage.kp-wide .kp-shell .kp-num .key { min-height: calc(38px * var(--kp-key-scale, 1)); font-size: calc(12px * var(--kp-key-scale, 1)); }
.stage.kp-wide .kp-shell .kp-dpad .k-f1,
.stage.kp-wide .kp-shell .kp-dpad .k-f2 { min-height: calc(24px * var(--kp-key-scale, 1)); }

/* 单键缩放走真实布局尺寸，不再用 transform 视觉放大：
   transform 不参与排版，键一大就互相压盖，文字也按原始尺寸拉伸发糊。 */
.stage .kp-shell .key.active { transform: translateY(3px); }

/* 经典按键机：导航和数字纵向堆叠，保留实体机从屏幕到键盘的顺序。 */
.stage.kp-classic .kp-shell { align-items: center; }
/* 经典布局拉满机身宽度；功能排最矮、软键次之、十字和数字盘最厚，
   主次分明，也不会把键盘顶出画面。 */
.stage.kp-classic .kp-dpad { width: min(92vw, calc(322px * var(--kp-key-scale, 1))); }
.stage.kp-classic .kp-num { width: min(78vw, calc(272px * var(--kp-key-scale, 1))); }
.stage.kp-classic .key { min-height: calc(44px * var(--kp-key-scale, 1)); font-size: calc(14px * var(--kp-key-scale, 1)); }
.stage.kp-classic .key.fn { min-height: calc(26px * var(--kp-scale, 1) * var(--kp-key-scale, 1)); }
.stage.kp-classic .key.soft { min-height: calc(36px * var(--kp-scale, 1) * var(--kp-key-scale, 1)); }
.stage.kp-classic .key small { font-size: calc(8px * var(--kp-key-scale, 1)); }

.key {
  position: relative;
  border: 1px solid var(--kp-edge, rgba(255, 255, 255, 0.14));
  border-radius: 10px;
  min-height: 42px;
  padding: 0 2px;
  /* 实体键：顶面受光、底面留一道暗边和一层投影，按下时整块下沉。
     面色/墨色抽成变量：配色主题与自定义色只换变量，形状手感不动。 */
  background: var(--kp-face, linear-gradient(180deg, rgba(255, 255, 255, 0.16), rgba(255, 255, 255, 0.055) 62%, rgba(255, 255, 255, 0.1)));
  color: var(--kp-ink, #eef4f0);
  font: 650 15px/1 -apple-system, "Segoe UI", "Noto Sans SC", "Microsoft YaHei", sans-serif;
  cursor: pointer;
  display: grid;
  place-items: center;
  gap: 1px;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.3),
    inset 0 -2px 0 rgba(0, 0, 0, 0.32),
    0 3px 0 rgba(0, 0, 0, 0.44),
    0 7px 15px rgba(0, 0, 0, 0.36);
  transition: transform 0.06s, box-shadow 0.06s, filter 0.1s, background 0.1s;
  /* 单键大小：zoom 参与排版（键真实变大、网格让位），比 transform 好——
     transform 不参与排版，键一大就互相压盖。不支持 zoom 的老内核
     忽略此行，键保持基础大小（优雅降级）。 */
  zoom: var(--ks, 1);
}
.key.kp-selected { outline: 2px dashed var(--accent); outline-offset: 2px; }
.key small { font-size: calc(8.5px * var(--kp-key-scale, 1)); font-weight: 500; letter-spacing: 0.4px; color: var(--kp-sub-ink, rgba(255, 255, 255, 0.55)); }
.key b { font-size: inherit; font-weight: inherit; }
.stage:not(.kp-classic) .key { min-height: calc(36px * var(--kp-key-scale, 1)); font-size: calc(14px * var(--kp-key-scale, 1)); }
.stage:not(.kp-classic) .key small { font-size: calc(8px * var(--kp-key-scale, 1)); }
/* 紧凑：整体收一档，给画面留地方。
   必须排在上面两条通用规则之后，否则同权重被它们盖掉（老代码就踩过这个坑）。 */
.stage.kp-compact .key { min-height: calc(30px * var(--kp-key-scale, 1)); font-size: calc(12.5px * var(--kp-key-scale, 1)); }
.stage.kp-compact .kp-dpad .key { min-height: calc(34px * var(--kp-key-scale, 1)); }
.stage.kp-compact .key small { display: none; }
/* 按下：下沉 3px，底边投影一起收掉，手感才对得上视觉 */
.key.active {
  transform: translateY(3px);
  filter: brightness(1.3);
  box-shadow:
    inset 0 2px 9px rgba(0, 0, 0, 0.5),
    inset 0 -1px 0 rgba(0, 0, 0, 0.3),
    0 0 0 rgba(0, 0, 0, 0);
}
.key.dir {
  font-size: calc(19px * var(--kp-key-scale, 1));
  background: var(--kp-dir-face, linear-gradient(180deg, rgba(255, 255, 255, 0.21), rgba(255, 255, 255, 0.08) 62%, rgba(255, 255, 255, 0.13)));
}
.key.soft {
  background: var(--kp-soft-face, linear-gradient(180deg, rgba(255, 200, 120, 0.26), rgba(255, 196, 112, 0.1) 62%, rgba(255, 196, 112, 0.17)));
  color: var(--kp-soft-ink, #fbe6c6);
  border-color: var(--kp-soft-edge, rgba(255, 205, 130, 0.3));
}
.key.ok {
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--accent) 74%, #fff 14%),
    color-mix(in srgb, var(--accent) 46%, #000 12%) 62%,
    color-mix(in srgb, var(--accent) 60%, transparent));
  color: #fff;
  border-color: color-mix(in srgb, var(--accent) 62%, #fff 10%);
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
}
.key.fn {
  background: var(--kp-fn-face, linear-gradient(180deg, rgba(158, 192, 255, 0.22), rgba(150, 186, 255, 0.08) 62%, rgba(150, 186, 255, 0.14)));
  color: var(--kp-fn-ink, #dfe8ff);
  border-color: var(--kp-fn-edge, rgba(168, 198, 255, 0.26));
  font-size: calc(12px * var(--kp-key-scale, 1));
  font-weight: 650;
}
.key.fn small { font-size: calc(7.5px * var(--kp-key-scale, 1)); }

/* 横屏：面板仍然贴合按键并整体居中，OK 键和游戏中线保持一条竖线；
   安全区由内核消息精确预留。
   固定宽只给 classic（横屏纵向列需要限宽防顶出）——game/compact/wide
   有自己的 flex/宽度体系，被这里的固定宽压住会溢出面板（compact 实测
   数字键凸出 23px）或横条变并排（wide），必须加 kp-classic 限定。 */
.stage.has-keypad.kp-landscape.kp-classic .kp-dpad { width: var(--kp-side, 206px); }
.stage.has-keypad.kp-landscape.kp-classic .kp-num { width: var(--kp-side, 190px); }
.stage.has-keypad.kp-landscape .kp-shell { gap: 10px; }

/* 横屏时舞台很矮（手机横过来只有 360px 上下），经典布局整列 450+ 会顶出
   舞台上下缘（实测 3 个键越界）。把这一列整体压到约 0.78 档。 */
.stage.has-keypad.kp-landscape.kp-classic .key { min-height: calc(30px * var(--kp-key-scale, 1)); }
.stage.has-keypad.kp-landscape.kp-classic .kp-dpad .key { min-height: calc(38px * var(--kp-key-scale, 1)); }
.stage.has-keypad.kp-landscape.kp-classic .kp-dpad .key.fn { min-height: calc(20px * var(--kp-key-scale, 1)); }
.stage.has-keypad.kp-landscape.kp-classic .kp-dpad .key.soft { min-height: calc(28px * var(--kp-key-scale, 1)); }

.keypad-dragging { border-color: var(--accent); box-shadow: 0 24px 64px rgba(0, 0, 0, 0.4), var(--ring); }
.keypad-setting { margin-top: 8px; }

/* 键盘浮层必须压在遮罩之上：否则抽屉打开时点键盘会误触遮罩、把抽屉关掉 */
.stage > .keypad { z-index: 46; }

/* ---------- 响应式 ---------- */
@media (max-width: 1000px) {
  .play-shell { grid-template-columns: minmax(0, 1fr); grid-template-rows: auto minmax(0, 1fr); }
  .side {
    position: fixed;
    left: 0; right: 0; bottom: 0;
    z-index: 50;
    grid-row: auto;
    grid-column: auto;
    max-height: 74dvh;
    border-left: 0;
    border-top: 1px solid var(--line);
    border-radius: 14px 14px 0 0;
    box-shadow: var(--shadow-lg);
    transform: translateY(100%);
    transition: transform 0.24s var(--ease-out, ease);
  }
  .side.open { transform: none; }
  .side-sheet-handle { display: block; }
  .play-bar .desk-only { display: none; }
}

.drawer-mask {
  position: fixed;
  inset: 0;
  z-index: 45;
  background: rgba(3, 7, 5, 0.48);
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px);
  border: 0;
}
.drawer-mask[hidden] { display: none !important; }
:root.drawer-open, :root.drawer-open body { overflow: hidden; }

/* 键盘浮层必须压在遮罩之上：否则抽屉打开时点键盘会误触遮罩、把抽屉关掉 */
.stage > .keypad { z-index: 46; }

/* ---------- 调整模式：抽屉只留一个入口按钮，控件全在这块悬浮面板里 ---------- */
/* 注意：背景必须实打实写在这个元素上——毛玻璃 ::before 机制是 base.css 的
   点名制（.tune-bar 不在名单），设了 --glass 变量也不会有背景层，
   这里漏了就是全透明浮在游戏上，字直接看不见（真机踩过）。 */
.tune-bar {
  position: absolute;
  top: 8px;
  left: 50%;
  translate: -50% 0;
  /* 必须压过抽屉（50）和键盘（46），否则调的时候会被设置面板盖住 */
  z-index: 60;
  display: flex;
  flex-direction: column;
  gap: 7px;
  /* 固定宽度：以前只有 max-width + flex-wrap，窄屏上会塌成 206×214 的竖条，
     既难看又挤压画面（用户反馈"被设置遮挡、看不到调节情况"）。 */
  width: min(100% - 16px, 460px);
  box-sizing: border-box;
  padding: 9px 11px 11px;
  border: 1px solid var(--line-2);
  border-radius: 15px;
  background: color-mix(in srgb, var(--surface) 97%, transparent);
  box-shadow: 0 18px 44px rgba(0, 0, 0, 0.5);
  animation: tune-in 0.18s var(--ease-out, ease);
}
@keyframes tune-in { from { opacity: 0; translate: -50% -6px; } to { opacity: 1; translate: -50% 0; } }
.tune-head { display: flex; align-items: center; gap: 8px; }
.tune-title { font-size: 13px; font-weight: 700; color: var(--ink); white-space: nowrap; }
.tune-tip { flex: 1; min-width: 0; font-size: 11px; color: var(--ink-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tune-row { display: flex; align-items: center; flex-wrap: wrap; gap: 6px 8px; }
.tune-lbl { font-size: 11.5px; color: var(--ink-2); white-space: nowrap; }
.tune-seg { padding: 2px; }
.tune-seg button { padding: 5px 9px; font-size: 12px; min-height: 28px; }
/* 滑条一行放两条，窄屏各占一半，永远不会撑破面板 */
.tune-scale { display: flex; align-items: center; gap: 6px; flex: 1 1 45%; min-width: 0; }
.tune-scale span { font-size: 11.5px; color: var(--ink-2); white-space: nowrap; }
.tune-scale b { font-size: 11.5px; font-variant-numeric: tabular-nums; color: var(--ink); min-width: 34px; text-align: right; }
.tune-scale input[type="range"] { flex: 1; min-width: 56px; }
/* 超窄屏（≤360）：提示文案让位，别把标题和完成按钮挤走 */
@media (max-width: 380px) {
  .tune-tip { display: none; }
  .tune-seg button { padding: 5px 7px; }
}

/* ---------- 键盘配色主题 ---------- */
/* 面色/墨色全部走变量（.key 规则里带默认值），主题只覆写变量，形状手感不动。 */
.keypad[data-kp-theme="midnight"] {
  --kp-face: linear-gradient(180deg, rgba(96, 106, 100, 0.85), rgba(38, 46, 42, 0.92) 62%, rgba(22, 28, 25, 0.95));
  --kp-dir-face: linear-gradient(180deg, rgba(120, 132, 124, 0.88), rgba(48, 58, 52, 0.94) 62%, rgba(28, 36, 32, 0.96));
  --kp-ink: #dfe7e2;
  --kp-sub-ink: rgba(223, 231, 226, 0.42);
  --kp-soft-face: linear-gradient(180deg, rgba(255, 184, 108, 0.3), rgba(214, 142, 70, 0.12) 62%, rgba(214, 142, 70, 0.2));
  --kp-soft-ink: #ffd9a8;
  --kp-soft-edge: rgba(255, 190, 120, 0.34);
  --kp-fn-face: linear-gradient(180deg, rgba(148, 170, 210, 0.26), rgba(120, 146, 196, 0.1) 62%, rgba(120, 146, 196, 0.18));
  --kp-fn-ink: #ccd9f2;
  --kp-fn-edge: rgba(150, 176, 220, 0.3);
  --kp-handle-ink: rgba(223, 231, 226, 0.5);
  --kp-handle-bg: rgba(255, 255, 255, 0.07);
}
.keypad[data-kp-theme="ivory"] {
  --kp-face: linear-gradient(180deg, #ffffff, #eef0ec 62%, #e2e6e0);
  --kp-dir-face: linear-gradient(180deg, #ffffff, #f2f4f0 62%, #e8ebe6);
  --kp-ink: #242b26;
  --kp-sub-ink: rgba(24, 32, 26, 0.5);
  --kp-edge: rgba(30, 40, 34, 0.22);
  --kp-soft-face: linear-gradient(180deg, #ffe7c2, #fcd9a4 62%, #f4cd96);
  --kp-soft-ink: #5f4318;
  --kp-soft-edge: rgba(150, 110, 50, 0.4);
  --kp-fn-face: linear-gradient(180deg, #dde7f8, #cddcf4 62%, #c2d3ef);
  --kp-fn-ink: #2c3d61;
  --kp-fn-edge: rgba(60, 90, 150, 0.35);
  --kp-handle-ink: rgba(40, 52, 44, 0.62);
  --kp-handle-bg: rgba(20, 30, 24, 0.1);
}
.keypad[data-kp-theme="amber"] {
  --kp-face: linear-gradient(180deg, rgba(196, 142, 66, 0.92), rgba(146, 98, 40, 0.94) 62%, rgba(112, 72, 28, 0.96));
  --kp-dir-face: linear-gradient(180deg, rgba(214, 160, 84, 0.94), rgba(162, 110, 46, 0.95) 62%, rgba(126, 82, 32, 0.97));
  --kp-ink: #ffedcb;
  --kp-sub-ink: rgba(255, 237, 203, 0.5);
  --kp-soft-face: linear-gradient(180deg, rgba(255, 214, 150, 0.95), rgba(240, 186, 110, 0.9) 62%, rgba(224, 168, 92, 0.92));
  --kp-soft-ink: #4c3410;
  --kp-soft-edge: rgba(120, 84, 36, 0.5);
  --kp-fn-face: linear-gradient(180deg, rgba(240, 214, 160, 0.35), rgba(220, 188, 128, 0.16) 62%, rgba(210, 176, 112, 0.26));
  --kp-fn-ink: #ffe9c0;
  --kp-fn-edge: rgba(255, 226, 170, 0.35);
  --kp-handle-ink: rgba(255, 237, 203, 0.6);
  --kp-handle-bg: rgba(255, 226, 170, 0.12);
}
.keypad[data-kp-theme="neon"] {
  --kp-face: linear-gradient(180deg, color-mix(in srgb, var(--accent) 86%, #fff 10%), color-mix(in srgb, var(--accent) 72%, #000 24%) 62%, color-mix(in srgb, var(--accent) 66%, #000 32%));
  --kp-dir-face: linear-gradient(180deg, color-mix(in srgb, var(--accent) 94%, #fff 12%), color-mix(in srgb, var(--accent) 80%, #000 18%) 62%, color-mix(in srgb, var(--accent) 74%, #000 26%));
  --kp-ink: #ffffff;
  --kp-sub-ink: rgba(255, 255, 255, 0.72);
  --kp-edge: color-mix(in srgb, var(--accent) 55%, #fff 20%);
  --kp-soft-face: linear-gradient(180deg, color-mix(in srgb, var(--accent) 60%, #ffd28a 34%), color-mix(in srgb, var(--accent) 48%, #e8a54e 30%) 62%, color-mix(in srgb, var(--accent) 44%, #c9883a 30%));
  --kp-soft-ink: #fff7e8;
  --kp-soft-edge: color-mix(in srgb, var(--accent) 45%, #ffd28a 45%);
  --kp-fn-face: linear-gradient(180deg, color-mix(in srgb, var(--accent) 42%, #9ec2ff 30%), color-mix(in srgb, var(--accent) 30%, #7ea6e8 24%) 62%, color-mix(in srgb, var(--accent) 34%, #6c94d8 28%));
  --kp-fn-ink: #eef4ff;
  --kp-fn-edge: color-mix(in srgb, var(--accent) 40%, #9ec2ff 40%);
  --kp-handle-ink: rgba(255, 255, 255, 0.66);
  --kp-handle-bg: color-mix(in srgb, var(--accent) 24%, transparent);
}
/* 自定义色：player.js 按所选颜色算出渐变后内联写入同一组变量 */

/* 配色 swatch（抽屉与调节条共用） */
.kp-theme-row { display: inline-flex; align-items: center; gap: 5px; padding: 3px 5px; }
.kp-swatch { width: 22px; height: 22px; min-width: 22px; padding: 0; border-radius: 7px; border: 1px solid var(--line-2); cursor: pointer; }
.kp-swatch.is-on { outline: 2px solid var(--accent); outline-offset: 1px; }
.kp-swatch[data-kp-theme="default"] { background: linear-gradient(180deg, rgba(255, 255, 255, 0.22), rgba(255, 255, 255, 0.08) 62%, rgba(255, 255, 255, 0.14)), #232b26; }
.kp-swatch[data-kp-theme="midnight"] { background: linear-gradient(180deg, #3c443f, #161c19); }
.kp-swatch[data-kp-theme="ivory"] { background: linear-gradient(180deg, #ffffff, #e2e6e0); }
.kp-swatch[data-kp-theme="amber"] { background: linear-gradient(180deg, #c48e42, #70481c); }
.kp-swatch[data-kp-theme="neon"] { background: linear-gradient(180deg, color-mix(in srgb, var(--accent) 88%, #fff 8%), color-mix(in srgb, var(--accent) 68%, #000 30%)); }
.kp-swatch-custom { position: relative; overflow: hidden; display: grid; place-items: center; background: conic-gradient(#f66, #fc6, #6f9, #69f, #c6f, #f66); }
.kp-swatch-custom input[type="color"] { position: absolute; inset: -4px; opacity: 0; width: calc(100% + 8px); height: calc(100% + 8px); cursor: pointer; }

/* 调节条分区行与单键面板 */
/* 单键缩放那一行：点选某个键后才浮出来（面板其余部分见上面的 .tune-bar 区块） */
.kp-perkey { display: none; align-items: center; gap: 7px; padding: 5px 8px; border: 1px dashed var(--line-2); border-radius: 10px; font-size: 11.5px; color: var(--ink-2); }
.kp-perkey.show { display: flex; flex-wrap: wrap; justify-content: center; }
.kp-perkey b { color: var(--ink); font-variant-numeric: tabular-nums; }
.kp-perkey input[type="range"] { flex: 1; min-width: 90px; }

@media (min-width: 1001px) {
  .side-sheet-handle { display: none; }
  .play-bar .mobile-only { display: none; }
}

.side-sheet-handle {
  width: 38px; height: 4px; border-radius: 999px;
  background: var(--line-2);
  margin: 8px auto 0;
  flex: 0 0 auto;
}

@media (max-width: 720px) {
  main { padding: 12px 12px 6px; }
  .topbar-inner { padding: 8px 12px; gap: 8px; }
  .topbar-count { display: none; }
  .topbar-actions { gap: 3px; min-width: 0; }
  .topbar-actions .btn .btn-label { display: none; }
  .topbar-actions .btn,
  .topbar-actions .icon-btn { width: 28px; height: 28px; min-width: 28px; padding-left: 0; padding-right: 0; justify-content: center; flex: 0 0 auto; }
  .topbar-actions .field { width: 82px; min-width: 0; padding-left: 6px; padding-right: 18px; font-size: 12px; }
  .filterbar-inner { padding: 6px 12px; }
  .brand-text { display: none; }
  .search { flex: 1 1 0; min-width: 0; }
  .search .slash { display: none; }
  dialog.modal { width: calc(100vw - 16px); max-height: calc(100dvh - 24px); border-radius: 14px; }
  .shots img { height: 142px; }
  .play-bar { padding: 6px 8px; gap: 5px; flex-wrap: nowrap; }
  /* 单行设计，但按钮一律图标+文字（光秃图标看不懂）：标题和模板下拉弹性收缩 */
  .play-bar h1 { flex: 1 1 auto; min-width: 0; max-width: none; font-size: 13.5px; }
  .play-bar .count { display: none; }
  .play-bar .btn .btn-label { display: inline; font-size: 11.5px; }
  /* 播放页按钮组误挂了 topbar-actions 类名，首页的 28px 纯图标规则会把它压瘪——
     按钮宽度必须还原自适应，文字才能完整放下（真机踩过：键盘/全屏文字被裁） */
  .play-bar .topbar-actions .btn { width: auto; min-width: 0; height: auto; padding-left: 6px; padding-right: 6px; }
  .play-bar > .btn { flex: 0 0 auto; }
  .play-bar .topbar-actions { flex: 0 1 auto; min-width: 0; }
  /* "自动"两个字 24px + 内边距 6px + 箭头位 20px：56px 会裁成一个"自"字（真机踩过）。
     min-width 72px 硬下限：超长标题（"狂野飙车4-gameloft(中文版)"26 字）会把
     可收缩的 tpl 挤到 26px 只剩半个字（真机踩过），标题自己有省略号，让标题让位 */
  .play-bar #tpl { flex: 0 1 78px; min-width: 72px; padding-left: 6px; font-size: 12px; }
  /* 手机性能第二层：画布每帧都在重绘，压在上面的毛玻璃会跟着逐帧重模糊。
     播放页的悬浮面一律去掉 backdrop-filter，用 --glass-bg 的 9 成不透明底保对比度。 */
  .play-bar::before, .side::before, .keypad::before {
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
  /* 卡片移动端收紧（原文件尾 refresh 补丁并入）。
     间距走 --gap 令牌而不是直接写 .grid gap——密度设置（:root[data-density]）
     特异性更高，照样能压过这个移动端缺省，不会再犯"密度失效"的错 */
  :root { --gap: 10px; }
  .card { border-radius: 12px; }
  .card:hover { transform: none; }
  .thumb { margin: 7px 7px 0; width: calc(100% - 14px); }
  .card-body { padding: 8px 9px 10px; }
}

@media (max-width: 420px) {
  .grid { --card-min: 132px; }
  .key { min-height: 34px; }
}

/* 播放页移动端稳定布局：独立命名空间，避免首页 topbar 规则污染。 */
.play-page, .play-shell { min-width: 0; }
.play-bar { flex-wrap: nowrap; min-width: 0; }
.play-bar > h1 { min-width: 0; flex: 1 1 auto; }
.play-bar .topbar-actions { min-width: 0; flex: 0 1 auto; }
.side-body { padding-bottom: calc(18px + env(safe-area-inset-bottom, 0px)); }
.keypad-layout-grid { display: grid !important; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 4px; }
.keypad-layout-grid button { min-width: 0; min-height: 34px; padding-inline: 5px; white-space: normal; line-height: 1.2; }

@media (max-width: 720px) {
  .play-bar { gap: 4px; padding-inline: max(8px, env(safe-area-inset-left, 0px)) max(8px, env(safe-area-inset-right, 0px)); }
  .play-bar h1 { font-size: 13px; }
  .play-bar .topbar-actions { gap: 2px; }
  .play-bar #tpl { width: clamp(72px, 20vw, 88px); flex: 0 1 clamp(72px, 20vw, 88px); min-width: 72px; }
  .play-bar .topbar-actions .btn { min-width: 30px; min-height: 30px; }
  .side { max-width: 100vw; }
  .side-body { overflow-x: hidden; }
}

@media (max-width: 380px) {
  .play-bar { gap: 2px; }
  .play-bar .btn-label { display: none !important; }
  .play-bar #tpl { width: 62px; flex-basis: 62px; }
}

@media (prefers-reduced-motion: reduce), (pointer: coarse) {
  .play-shell .stage { background: var(--stage); }
}




