/* ==========================================================================
   8BIT GAMES · 站点样式
   基准分辨率 384×216，整数倍缩放，UI 层高分辨率渲染。
   见 docs/asset-spec.md
   ========================================================================== */

/*
  调色板 —— 一台实体掌机的配色，不是「深色主题」。

  三组色各有分工，别混用：

    --shell / --shell-edge / --bezel
      机身与面板：塑料灰。它是「物理」，所以按钮、机身、屏幕边框都用它。

    --screen / --screen-deep / --phosphor
      屏幕发光：老式荧光的暖白绿。屏幕里的东西是「电子」，用这组。

    --accent / --accent-2 / --danger
      功能色：电源黄、信号青、故障红。只用在状态与强调上，不参与大面积铺色 ——
      铺开了就不是掌机，是圣诞树。
*/
:root {
  /* 机身（物理层） */
  --shell:      #2c2f35;
  --shell-hi:   #3d424b;
  --shell-lo:   #1c1e23;
  --shell-edge: #14161a;
  --bezel:      #0d0f12;

  /* 屏幕（电子层） */
  --screen:      #0a0e0b;
  --screen-deep: #04060a;
  --phosphor:    #b9f6d0;

  /* 文字 */
  --fg:      #e8ecf4;
  --fg-dim:  #98a2b8;
  --fg-dust: #6a7285;

  --bg:      #0b0c10;
  --bg-soft: #12141a;
  --bg-card: #171a21;
  --line:    #2b313d;

  /* 功能色 */
  --accent:   #ffd23f;
  --accent-2: #4ecdc4;
  --danger:   #ff5f56;

  /* 世界图层缩放倍率，由 play.js 写入 */
  --scale: 1;

  --radius: 8px;
  --maxw: 1180px;

  /* 像素感的关键：等宽字体 + 无抗锯齿氛围 */
  --font: 'SF Mono', 'Cascadia Mono', Menlo, Consolas, 'Liberation Mono', monospace;

  /*
    硬边阴影，不用模糊。
    掌机的按键、面板都是注塑件，光打上去是硬边高光，
    用 `0 4px 12px rgba(0,0,0,.5)` 那种柔和阴影会立刻变「网页毛玻璃」，
    失去塑料感。所以阴影一律是 0 模糊的实心偏移。
  */
  --hard: 0 2px 0 0 rgba(0, 0, 0, .55);
  --hard-in: inset 0 1px 0 0 rgba(255, 255, 255, .07);
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
}

/*
  整页背景 = 机身面板。
  用两层极细的斜纹（透明度 2%–3%）模拟注塑件的磨砂，比纯色多一点「料」，
  又不至于看出图案 —— 看得出图案就成壁纸了。
*/
body {
  background-color: var(--bg);
  background-image:
    repeating-linear-gradient(45deg, rgba(255, 255, 255, .014) 0 1px, transparent 1px 3px),
    repeating-linear-gradient(-45deg, rgba(0, 0, 0, .12) 0 1px, transparent 1px 3px);
  color: var(--fg);
  font-family: var(--font);
  font-size: 14px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  min-height: 100vh;
}

a { color: inherit; text-decoration: none; }

img { max-width: 100%; display: block; }

/* 站点图标的像素边界：任何图标都别插值 */
.brand__mark, .card__img--placeholder { image-rendering: pixelated; }

/* ---------- 页头 ---------- */

/*
  页头 = 机身顶栏。
  刻意做成「一块有厚度的面板」：上沿高光、下沿深色倒角、底部一条硬阴影，
  于是它看起来浮在整页背景之上，而不是一条贴边的色带。
*/
.site-header {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  gap: 20px;
  padding: 12px 20px;
  background: linear-gradient(180deg, var(--shell-hi), var(--shell) 55%, var(--shell-lo));
  border-bottom: 2px solid var(--shell-edge);
  box-shadow: 0 2px 0 0 rgba(0, 0, 0, .5), var(--hard-in);
  backdrop-filter: none;
}

.brand {
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 700;
  letter-spacing: 1px;
}

/*
  品牌标 = 电源指示灯。
  不是装饰：它亮着，就是在告诉用户「这台机器开着机」。
*/
.brand__mark {
  color: var(--accent);
  font-size: 12px;
  line-height: 1;
  padding: 4px 5px;
  border-radius: 3px;
  background: #1a1706;
  border: 1px solid #4a3d0c;
  box-shadow: 0 0 8px rgba(255, 210, 63, .45);
  animation: power-blink 4.5s ease-in-out infinite;
}

@keyframes power-blink {
  0%, 92%, 100% { opacity: 1; }
  95% { opacity: .35; }
}

.brand__name {
  font-size: 15px;
  text-shadow: 0 1px 0 rgba(0, 0, 0, .6);
}

.site-nav {
  display: flex;
  gap: 6px;
  margin-left: auto;
  font-size: 12px;
  color: var(--fg-dim);
  text-transform: uppercase;
  letter-spacing: 1px;
}

/* 丝印按钮：平贴在机身上，按下去才亮 */
.site-nav a {
  padding: 5px 10px;
  border: 1px solid transparent;
  border-radius: 4px;
}

.site-nav a:hover { color: var(--fg); border-color: var(--shell-edge); }

.site-nav a[aria-current="page"] {
  color: var(--accent);
  border-color: var(--shell-edge);
  background: rgba(255, 210, 63, .07);
  box-shadow: var(--hard-in);
}

.site-header__membership { font-size: 12px; }

.membership-hint { color: var(--fg-dim); }

/* ---------- 主体 ---------- */

.site-main {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 28px 20px 60px;
}

.hero { padding: 0 0 16px; }

/* 标题在屏幕里 —— 用荧光色，不是机身上的强调色 */
.hero__title {
  margin: 0 0 4px;
  font-size: 26px;
  letter-spacing: 4px;
  color: var(--phosphor);
  text-shadow: 0 0 12px rgba(185, 246, 208, .28);
}

.hero__tagline {
  margin: 0;
  color: var(--fg-dim);
  font-size: 13px;
  letter-spacing: 1px;
}

.hero__spec {
  margin: 0 0 4px;
  font-size: 12px;
  color: var(--fg-dim);
}

.hero__spec strong { color: var(--accent-2); font-weight: 600; }

.hero__count {
  margin: 0;
  font-size: 12px;
  color: var(--fg-dim);
}

.hero__count strong { color: var(--fg); }

/* ==========================================================================
   掌机外壳（.console）—— 全站 UI 的基础单元
   大厅、游戏库、模拟器都用它，差别只在屏幕里装什么。
   见 docs/UI.md
   ========================================================================== */

.site-main--console { padding: 22px 20px 64px; }

.console {
  max-width: var(--maxw);
  margin: 0 auto;
}

/*
  机身上半：屏幕 + 控制面板。
  内层用立体边框做出「面壳浮在底壳上」的一层，而不是一整块塑料。
*/
.console__body {
  position: relative;
  padding: 18px;
  border-radius: 16px;
  background: linear-gradient(180deg, var(--shell-hi), var(--shell) 30%, var(--shell-lo));
  border: 1px solid var(--shell-edge);
  /* 硬边投影：注塑件落在桌面上的影子是有边界的，不能糊 */
  box-shadow:
    0 6px 0 0 var(--shell-edge),
    0 10px 0 0 rgba(0, 0, 0, .35),
    var(--hard-in);
}

/* 屏幕外面那圈黑框。真机的屏幕玻璃比可视区大一整圈 */
.console__screen {
  position: relative;
  border-radius: 10px;
  padding: 10px;
  background: linear-gradient(180deg, var(--bezel), #05060a);
  border: 1px solid #000;
  box-shadow:
    inset 0 2px 6px rgba(0, 0, 0, .9),
    0 1px 0 0 rgba(255, 255, 255, .05);
}

/* 屏幕玻璃反光：一条 6% 白斜切，位置固定在左上，不随滚动 */
.console__screen::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 10px;
  pointer-events: none;
  background: linear-gradient(118deg, rgba(255, 255, 255, .06) 0 34%, transparent 34.2%);
}

/* 屏幕点亮后的底色 */
.screen-body {
  border: 1px solid #1b2320;
  border-radius: 6px;
  background: linear-gradient(180deg, #0a0e0b, var(--screen-deep));
  padding: 16px;
  min-height: 240px;
  /* 荧光屏的余晖：极淡的内辉光，别调大，大了就成「暗黑风」了 */
  box-shadow: inset 0 0 40px rgba(78, 205, 196, .035);
}

/* 屏幕顶部状态栏：像真机的 LCD 行，永远贴在最上面 */
.screen-bar {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 0 4px 8px;
  font-size: 11px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--fg-dust);
  text-shadow: 0 0 6px rgba(185, 246, 208, .18);
}

.screen-bar__item strong { color: var(--phosphor); }
.screen-bar__spacer { flex: 1; }

.screen-bar__item--live { color: var(--accent-2); }

/* 机身控制面板：一块凹进去的塑料，与屏幕区分开 */
.console__controls {
  margin-top: 16px;
  padding: 12px 14px;
  border-radius: 10px;
  background: linear-gradient(180deg, var(--shell-lo), #23262b);
  border: 1px solid var(--shell-edge);
  box-shadow: inset 0 2px 6px rgba(0, 0, 0, .55);
}

/*
  机身丝印。用 tabular-nums 而不是普通等宽 —— 数字宽窄一致才像丝印，
  否则「8BIT GAMES」下面的规格数字会歪。
*/
.console__label {
  display: block;
  margin-bottom: 5px;
  font-size: 10px;
  letter-spacing: 2px;
  color: var(--fg-dust);
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
}

/* 底壳铰链：两颗螺丝 + 一行刻字，给机身一个「收口」 */
.console__hinge {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 10px;
  padding: 0 8px;
}

.console__screw {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, #4a505a, var(--shell-lo));
  border: 1px solid var(--shell-edge);
  box-shadow: inset 0 0 0 3px rgba(0, 0, 0, .25);
}

.console__engrave {
  flex: 1;
  text-align: center;
  font-size: 10px;
  letter-spacing: 3px;
  color: #4d545f;
  text-transform: uppercase;
}

.controls__chips { display: flex; flex-wrap: wrap; gap: 8px; }

/* ---------- 搜索与筛选 ---------- */

.controls {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: center;
  margin: 8px 0 20px;
}

.controls__search { flex: 1 1 240px; }

#search {
  width: 100%;
  padding: 9px 12px;
  background: #0e1013;
  border: 1px solid var(--shell-edge);
  border-radius: 6px;
  color: var(--fg);
  font-family: inherit;
  font-size: 13px;
  outline: none;
  /* 内凹：输入框是机身里挖出来的一道槽，不是贴上去的一块 */
  box-shadow: inset 0 2px 4px rgba(0, 0, 0, .6);
}

#search:focus {
  border-color: var(--accent-2);
  box-shadow: inset 0 2px 4px rgba(0, 0, 0, .6), 0 0 0 2px rgba(78, 205, 196, .18);
}

#search::placeholder { color: #5b6478; }

.controls__filters {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

/*
  分类键 = 机身上的实体键。
  有厚度（底面 2px 硬阴影）、按下去会「陷进去」，
  这是整套 UI 里最主要的可点触反馈语言，按钮都该长这样。
*/
.chip {
  padding: 6px 12px;
  background: linear-gradient(180deg, var(--shell-hi), var(--shell));
  border: 1px solid var(--shell-edge);
  border-radius: 5px;
  color: var(--fg-dim);
  font-family: inherit;
  font-size: 12px;
  cursor: pointer;
  box-shadow: var(--hard), var(--hard-in);
  transition: transform .06s, box-shadow .06s, color .15s;
}

.chip:hover { color: var(--fg); }

.chip:active {
  transform: translateY(2px);
  box-shadow: none;
}

/* 选中的键是「按下去的」，不是「高亮的」—— 亮着的那是电源灯 */
.chip.is-active {
  background: linear-gradient(180deg, #c9a227, #8a6f12);
  border-color: #4a3d0c;
  color: #14161c;
  font-weight: 700;
  transform: translateY(2px);
  box-shadow: inset 0 2px 4px rgba(0, 0, 0, .45);
}

/* ---------- 游戏网格 ---------- */

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 18px;
}

.card {
  position: relative;
  background: #0d1210;
  border: 1px solid #1d2620;
  border-radius: 6px;
  overflow: hidden;
  transition: transform .12s, border-color .12s, box-shadow .12s;
}

/* 悬停 = 选中这一格，屏幕上的光标感：亮边框 + 荧光外辉 */
.card:hover {
  transform: translateY(-2px);
  border-color: var(--accent-2);
  box-shadow: 0 0 0 1px rgba(78, 205, 196, .35), 0 0 18px rgba(78, 205, 196, .18);
}

.card__link { display: block; }

.card__thumb {
  position: relative;
  /* 缩略图统一 384×216 比例，避免不同游戏卡片高度参差 */
  aspect-ratio: 384 / 216;
  background: var(--screen-deep);
  overflow: hidden;
}

/*
  扫描线。
  ⚠️ 必须 pointer-events: none —— 否则这层浮在最上面，
  把卡片的点击整个吃掉，点进去玩就变成了「点了没反应」。
  透明度压在 10% 以下：看得见纹理，但不影响认内容。
*/
.card__thumb::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: repeating-linear-gradient(
    180deg,
    rgba(0, 0, 0, .18) 0 1px,
    transparent 1px 3px
  );
  opacity: .55;
}

.card__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* 缩略图是像素画，放大也别插值 */
  image-rendering: pixelated;
}

.card__img--placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 46px;
  font-weight: 700;
  color: #2b3446;
  background:
    repeating-conic-gradient(#10141c 0% 25%, #0b0e14 0% 50%) 50% / 16px 16px;
}

.card__flag {
  position: absolute;
  top: 8px;
  left: 8px;
  padding: 2px 8px;
  background: var(--accent);
  color: #14161c;
  border-radius: 4px;
  font-size: 11px;
  font-weight: 700;
}

.card__body { padding: 12px 14px 14px; }

.card__title {
  margin: 0 0 6px;
  font-size: 14px;
  letter-spacing: .5px;
}

.card__desc {
  margin: 0 0 10px;
  color: var(--fg-dim);
  font-size: 12px;
  line-height: 1.5;
  /* 两行截断，保证卡片等高 */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.card__meta { display: flex; flex-wrap: wrap; gap: 6px; }

.card__fav {
  position: absolute;
  top: 8px;
  right: 8px;
  width: 30px;
  height: 30px;
  display: grid;
  place-items: center;
  background: rgba(7, 8, 13, 0.75);
  border: 1px solid var(--line);
  border-radius: 6px;
  color: var(--fg-dim);
  font-size: 15px;
  cursor: pointer;
}

.card__fav:hover { color: var(--accent); }

.card__fav.is-on { color: var(--accent); border-color: var(--accent); }

/* ---------- 徽章 ---------- */

.badge {
  display: inline-block;
  padding: 2px 7px;
  background: #1b2130;
  border-radius: 4px;
  color: var(--fg-dim);
  font-size: 11px;
  line-height: 1.6;
}

.badge--muted { background: transparent; border: 1px solid var(--line); }

.badge--score { color: var(--accent); }

.badge--member { background: var(--accent-2); color: #0b1412; font-weight: 700; }

/* ---------- 按钮 ---------- */

/* 按钮 = 机身实体键。有厚度、按下去会陷进去，与 .chip 同一套语言 */
.btn {
  padding: 7px 13px;
  background: linear-gradient(180deg, var(--shell-hi), var(--shell));
  border: 1px solid var(--shell-edge);
  border-radius: 5px;
  color: var(--fg);
  font-family: inherit;
  font-size: 12px;
  cursor: pointer;
  box-shadow: var(--hard), var(--hard-in);
  transition: transform .06s, box-shadow .06s;
}

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

.btn:active {
  transform: translateY(2px);
  box-shadow: none;
}

.btn:disabled {
  opacity: .45;
  cursor: default;
  transform: none;
  box-shadow: var(--hard), var(--hard-in);
}

.btn--sm { padding: 5px 10px; font-size: 12px; }

.btn--primary {
  background: linear-gradient(180deg, #ffdd6a, #d8a916);
  border-color: #4a3d0c;
  color: #14161c;
  font-weight: 700;
}

/* ---------- 空状态与页脚 ---------- */

.empty-state {
  padding: 48px 0;
  text-align: center;
  color: var(--fg-dim);
  font-size: 13px;
}

.site-footer {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 24px 20px 40px;
  border-top: 1px solid var(--line);
  color: var(--fg-dim);
  font-size: 12px;
}

.site-footer p { margin: 0 0 4px; }

.site-footer__note { color: #5b6478; }

/* ==========================================================================
   播放页
   ========================================================================== */

.page-play {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

.play-bar {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 16px;
  border-bottom: 1px solid var(--line);
  background: var(--bg-soft);
}

.play-bar__back {
  font-size: 12px;
  color: var(--fg-dim);
  white-space: nowrap;
}

.play-bar__back:hover { color: var(--accent); }

.play-bar__title {
  flex: 1;
  margin: 0;
  font-size: 14px;
  letter-spacing: .5px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.play-bar__actions {
  display: flex;
  align-items: center;
  gap: 8px;
}

/* 缩放控件：− / 倍率 / ＋。倍率文字兼作当前档位指示 */
.zoom {
  display: flex;
  align-items: center;
  border: 1px solid var(--line);
  border-radius: 6px;
  overflow: hidden;
}

.zoom__btn {
  appearance: none;
  border: 0;
  background: transparent;
  color: var(--fg);
  font: inherit;
  font-size: 14px;
  line-height: 1;
  padding: 5px 9px;
  cursor: pointer;
}

.zoom__btn:hover:not(:disabled) { background: var(--bg-card); color: var(--accent); }

.zoom__btn:disabled { color: #4a5265; cursor: default; }

.zoom__value {
  min-width: 44px;
  text-align: center;
  font-size: 12px;
  color: var(--fg-dim);
  border-left: 1px solid var(--line);
  border-right: 1px solid var(--line);
  padding: 3px 4px;
  font-variant-numeric: tabular-nums;
}

.play-stage {
  flex: 1;
  display: grid;
  place-items: center;
  padding: 16px;
  background: #04050a;
}

/*
  世界图层容器。
  容器与内部 iframe 都按 --scale 整数倍取真实尺寸。
  关键四条（asset-spec.md 第 5 节）：
    1. 尺寸必须是 384×216 的整数倍
    2. image-rendering: pixelated —— 禁止线性插值
    3. overflow hidden，缩放后不留半像素边缘
    4. ⚠️ 用真实 width/height 放大，**不要**用 transform: scale()

  ⚠️ 第 4 条是踩过坑的，别改回去：
  用 transform: scale() 放大时，指针事件不会被反算 ——
  浏览器按**变换前**的局部坐标投递事件。于是 --scale=3 时
  用户点画面正中（页面坐标 576,324），游戏收到的是 (192,108)，
  整整差 3 倍。星野那种「按点击位置算飞船 Y」的游戏会直接玩不了
  （点哪都撞陨石），像素跑者虽然能靠整屏点击触发跳跃，
  但任何基于坐标的判断全错。

  直接给 width/height 就没有这个问题：innerWidth 与 rect 一致，
  坐标天然对齐。放大后的图像由 GPU 走 nearest 采样，
  image-rendering: pixelated 保证是硬边像素而不是糊的。
*/
.game-frame {
  position: relative;
  width:  calc(384px * var(--scale));
  height: calc(216px * var(--scale));
  max-width: 100%;
  background: #000;
  border: 1px solid var(--line);
  border-radius: 6px;
  overflow: hidden;
}

.game-frame__iframe {
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
  /* 只许最近邻放大，硬边像素 */
  image-rendering: pixelated;
  image-rendering: crisp-edges;
}

.game-frame__loading {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: grid;
  place-items: center;
  background: #0b0e14;
  color: var(--fg-dim);
  font-size: 12px;
  transition: opacity .25s;
}

.game-frame.is-loaded .game-frame__loading { opacity: 0; pointer-events: none; }

.game-info {
  padding: 18px 20px 40px;
  max-width: 900px;
  margin: 0 auto;
  width: 100%;
}

.game-info__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin-bottom: 8px;
}

.game-info__head h2 { margin: 0; font-size: 16px; }

.game-info__badges { display: flex; flex-wrap: wrap; gap: 6px; }

.game-info__desc {
  margin: 0 0 8px;
  color: var(--fg-dim);
  font-size: 13px;
}

.game-info__tags { margin: 0; color: #5b6478; font-size: 12px; }


/* ==========================================================================
   虚拟按键（模拟器页）
   按机种渲染，见 src/js/lib/inputs.js 与 emu.js 的 renderVirtualPad
   ========================================================================== */

/*
  触摸设备上才显示。桌面端用键盘和手柄就够了，
  给鼠标用户塞一排虚拟键反而挡住画面。
*/
.emu-pad {
  display: none;
  margin-top: 12px;
  padding: 12px 10px;
  border-radius: 10px;
  background: linear-gradient(180deg, var(--shell-lo), #23262b);
  border: 1px solid var(--shell-edge);
  box-shadow: inset 0 2px 6px rgba(0, 0, 0, .5);
  /* 连点会选中文字，触屏上很碍事 */
  user-select: none;
  -webkit-user-select: none;
  touch-action: none;
}

.emu-pad[hidden] { display: none; }

@media (pointer: coarse), (max-width: 720px) {
  .emu-pad:not([hidden]) { display: block; }
}

.vpad__row {
  display: flex;
  justify-content: center;
  gap: 8px;
}

.vpad__row--shoulder { margin-bottom: 10px; }

.vpad__row--menu { margin-top: 10px; }

/*
  主区：十字键在左、面键在右。
  这里刻意用「左方形 + 右菱形」而不是两排按钮 ——
  手指记住的是**位置**，位置固定才能盲操；真机手柄也是这个道理。
*/
.vpad__main {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}

.vpad__dpad {
  display: grid;
  /*
    固定 3×3，不是 repeat(3, 40px) —— 后者是**生成**三列，
    cell 数量不够时列会被合并：NES 只有 up/left/right/down 四个 cell，
    三行摊下来只剩两行，十字键直接压成一条横线。
    auto-rows 也不管用（列数还是会变），所以列模板必须写死。
  */
  grid-template-columns: 40px 40px 40px;
  grid-template-rows: 40px 40px 40px;
  gap: 2px;
}

/* 十字键的摆位：上中、中左、正中心留空、中右、下中 */
.vpad__dpad .vbtn[data-key="up"]    { grid-area: 1 / 2; }
.vpad__dpad .vbtn[data-key="left"]  { grid-area: 2 / 1; }
.vpad__dpad .vbtn[data-key="right"] { grid-area: 2 / 3; }
.vpad__dpad .vbtn[data-key="down"]  { grid-area: 3 / 2; }

/*
  面键菱形。用 grid 的三三格摆四个角 ——
  于是「哪个键在上面」永远固定在同一个物理位置，
  换机种（NES 两个键 / PSX 四个键）也不会挪位。
*/
.vpad__face {
  display: grid;
  /* 同样写死 3×3：四个面键要占满菱形的四个角，列不能被合并 */
  grid-template-columns: 40px 40px 40px;
  grid-template-rows: 40px 40px 40px;
  gap: 2px;
}

.vpad__face .vbtn:nth-child(1) { grid-area: 1 / 2; }
.vpad__face .vbtn:nth-child(2) { grid-area: 2 / 3; }
.vpad__face .vbtn:nth-child(3) { grid-area: 3 / 2; }
.vpad__face .vbtn:nth-child(4) { grid-area: 2 / 1; }
/* 只有 1～2 个面键的机种（NES/GB/MS）：摆在菱形的右半边，别散开 */
.vpad__face .vbtn:only-child { grid-area: 3 / 2; }

/* 单个按钮：圆形实体键 */
.vbtn {
  display: grid;
  place-items: center;
  min-width: 40px;
  padding: 0;
  border-radius: 50%;
  border: 1px solid var(--shell-edge);
  background: radial-gradient(circle at 50% 28%, var(--shell-hi), var(--shell-lo));
  color: var(--fg);
  font-family: var(--font);
  font-size: 13px;
  line-height: 1;
  cursor: pointer;
  box-shadow: var(--hard), var(--hard-in);
  /* 触屏上别让浏览器等 300ms 判断双击 */
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}

/* 肩键与功能键做成胶囊形，形状本身就区分了它们的身份 */
.vbtn--shoulder,
.vbtn--menu {
  border-radius: 6px;
  padding: 0 12px;
  min-width: 52px;
  height: 30px;
  font-size: 11px;
  letter-spacing: 1px;
}

.vbtn.is-down {
  transform: translateY(2px);
  box-shadow: none;
  color: #14161c;
  background: linear-gradient(180deg, #ffdd6a, #d8a916);
}

/* 面键给一点色相差异，跟真机上的丝印一样能一眼分辨 */
.vpad__face .vbtn { color: var(--accent-2); }
.vpad__face .vbtn.is-down { color: #14161c; }

/* ---------- 手柄状态条 ---------- */

.pad-status {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin-top: 14px;
  padding: 8px 12px;
  border-radius: 8px;
  background: linear-gradient(180deg, var(--shell-lo), #23262b);
  border: 1px solid var(--shell-edge);
  box-shadow: inset 0 2px 6px rgba(0, 0, 0, .45);
  font-size: 12px;
  color: var(--fg-dim);
}

.pad-status[hidden] { display: none; }

.pad-status__dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #4a505a;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .5);
  flex: 0 0 auto;
}

/* 认到的手柄亮青色 —— 与电源灯的黄色区分：一个是「开机」，一个是「有输入」 */
.pad-status[data-state="on"] .pad-status__dot {
  background: var(--accent-2);
  box-shadow: 0 0 8px rgba(78, 205, 196, .7);
}

.pad-status__list { display: flex; flex-wrap: wrap; gap: 6px; }

.pad-status__chip {
  padding: 1px 7px;
  border: 1px solid var(--line);
  border-radius: 4px;
  font-size: 11px;
  color: var(--accent-2);
  max-width: 220px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ---------- 模拟器页 ---------- */

/*
  ⚠️ 与 .game-frame 的区别，别混淆：

  .game-frame 是我们能控制尺寸的「世界图层」—— 我们知道逻辑分辨率是
  384×216，所以能强制整数倍缩放（asset-spec.md 的硬约束）。

  .emu-stage 里挂的是第三方模拟器（EmulatorJS），分辨率由 ROM 自身的
  机种决定（NES 256×240、GBA 240×160、PSX 320×240…），我们事先不知道。
  所以这里不套 --scale，交给模拟器自己适配容器，我们只保证容器够大。

  这也意味着 asset-spec 的整数倍约束**不适用于这一页** ——
  那是给平台自研游戏定的规格，不是给任意 ROM 的播放器的。
*/
.page-emu .site-main { max-width: 1000px; }

.emu-setup__title {
  margin: 0 0 6px;
  font-size: 22px;
  letter-spacing: 2px;
}

.emu-setup__lead {
  margin: 0 0 22px;
  color: var(--fg-dim);
  font-size: 13px;
  max-width: 62ch;
}

.emu-setup__lead strong { color: var(--accent-2); }

.emu-setup__grid {
  display: grid;
  grid-template-columns: 220px 1fr;
  gap: 16px;
  align-items: start;
}

.emu-field { display: flex; flex-direction: column; gap: 6px; }

.emu-field__label {
  font-size: 12px;
  color: var(--fg-dim);
  text-transform: uppercase;
  letter-spacing: 1px;
}

.emu-field select,
.emu-field input[type="url"] {
  width: 100%;
  padding: 9px 11px;
  background: var(--bg-card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  color: var(--fg);
  font-family: var(--font);
  font-size: 13px;
}

.emu-field select:focus,
.emu-field input[type="url"]:focus {
  outline: none;
  border-color: var(--accent-2);
}

/*
  拖放区。虚线边框是「可以往这里丢东西」的通用暗示。
  is-over 用强调色，让用户知道松手会生效。
*/
.emu-drop {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 22px 16px;
  border: 1px dashed var(--line);
  border-radius: var(--radius);
  background: var(--bg-card);
  text-align: center;
  transition: border-color .15s, background .15s;
  /* 整块都是 <label for="emu-file">，所以整块可点 —— 光标要说实话 */
  cursor: pointer;
}

/*
  .emu-drop 里的「选择文件…」是 <span>，不是 <button>：
  它现在靠外层 label 的原生关联开选择框，做成 <button> 会出现
  「按钮套在 label 里」的双重触发。外观仍按 .btn 走。
*/
.emu-drop .btn { user-select: none; }

.emu-drop:hover { border-color: #3a4762; }
.emu-drop:hover .btn { border-color: #3a4762; }

/* 键盘可达性：label 不能聚焦，但里面的文件输入能被 Tab 到 */
.emu-drop:focus-within {
  border-color: var(--accent-2);
  outline: 1px solid var(--accent-2);
  outline-offset: 2px;
}

.emu-drop.is-over {
  border-color: var(--accent-2);
  background: #16222a;
}

.emu-drop__hint { font-size: 12px; color: #5b6478; }

.emu-advanced {
  margin-top: 18px;
  border-top: 1px solid var(--line);
  padding-top: 12px;
}

.emu-advanced summary {
  cursor: pointer;
  font-size: 13px;
  color: var(--fg-dim);
  user-select: none;
}

.emu-advanced summary:hover { color: var(--fg); }
.emu-advanced > .emu-field { margin-top: 12px; }

.emu-url-row { display: flex; gap: 8px; }
.emu-url-row input { flex: 1; }

.emu-note {
  margin: 8px 0 0;
  font-size: 12px;
  color: #5b6478;
  line-height: 1.6;
}

.emu-note--keys { text-align: center; padding: 0 16px 30px; }

.emu-note kbd {
  display: inline-block;
  padding: 1px 5px;
  border: 1px solid var(--line);
  border-bottom-width: 2px;
  border-radius: 4px;
  background: var(--bg-card);
  font-family: var(--font);
  font-size: 11px;
  color: var(--fg);
}

.emu-error {
  margin: 16px 0 0;
  padding: 10px 12px;
  border: 1px solid var(--danger);
  border-radius: var(--radius);
  background: #2a1618;
  color: #ffb4b4;
  font-size: 13px;
}

.emu-legal {
  margin-top: 26px;
  padding: 14px 16px;
  border-left: 2px solid var(--accent);
  background: var(--bg-soft);
  border-radius: 0 var(--radius) var(--radius) 0;
}

.emu-legal__title { margin: 0 0 6px; font-size: 13px; }
.emu-legal p { margin: 0; font-size: 12px; color: var(--fg-dim); line-height: 1.7; }
.emu-legal strong { color: var(--accent); }

/* ---------- 模拟器运行区 ---------- */

.emu-stage {
  position: relative;
  background: #04050a;
  border-radius: var(--radius);
  padding: 12px;
  min-height: 320px;
  display: grid;
  place-items: center;
}

/*
  挂载点。EmulatorJS 会往这里塞它自己的 DOM（canvas + 菜单栏 + 虚拟按键）。
  给它一个下限尺寸，避免核心还没加载完时容器塌成 0 高、加载提示无处可放。
*/
.emu-stage__mount {
  width: 100%;
  min-height: 300px;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* EmulatorJS 的 canvas 默认可能比屏幕宽，限制一下别撑破布局 */
.emu-stage__mount canvas {
  max-width: 100%;
  height: auto !important;
}

.emu-stage__loading {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  margin: 0;
  background: #04050a;
  color: var(--fg-dim);
  font-size: 13px;
  border-radius: var(--radius);
}

.emu-stage__loading[hidden] { display: none; }

.play-bar__name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 13px;
  color: var(--fg-dim);
}


/* ==========================================================================
   游戏库（/library/）
   收录别人的免费游戏 —— 只存元数据与作者发布页链接，页面里没有任何 ROM。
   视觉上刻意与大厅的卡片区分：大厅是「点进去玩」，这里是「去作者那儿拿」。
   ========================================================================== */

/* 游戏库的引言块也放在「屏幕」里：与大厅同一块玻璃的观感 */
.library-intro {
  max-width: 720px;
  margin: 0 0 28px;
  padding: 16px;
  border: 1px solid #1b2320;
  border-radius: 6px;
  background: linear-gradient(180deg, #0a0e0b, var(--screen-deep));
  box-shadow: inset 0 0 40px rgba(78, 205, 196, .035);
}

.library-intro__title {
  margin: 0 0 10px;
  font-size: 22px;
  letter-spacing: 2px;
  color: var(--accent);
}

.library-intro__lead {
  margin: 0 0 12px;
  color: var(--fg-dim);
  font-size: 14px;
}

.library-intro__lead strong { color: var(--accent-2); font-weight: 600; }

/* 版权声明要显眼但不喧宾夺主：左边一条强调色竖线就够 */
.library-intro__policy {
  margin: 0;
  padding: 10px 14px;
  border-left: 2px solid var(--accent);
  background: var(--bg-soft);
  border-radius: 0 var(--radius) var(--radius) 0;
  color: var(--fg-dim);
  font-size: 13px;
}

.library-intro__policy strong { color: var(--fg); }

.library-list {
  padding: 16px;
  border: 1px solid #1b2320;
  border-radius: 6px;
  background: linear-gradient(180deg, #0a0e0b, var(--screen-deep));
  box-shadow: inset 0 0 40px rgba(78, 205, 196, .035);
}

.library-list__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px 16px;
  margin: 0 0 16px;
}

.library-list__title { margin: 0; font-size: 15px; color: var(--fg); }
.library-list__hint { margin: 0; font-size: 12px; color: var(--fg-dim); }

.lib-card {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  justify-content: space-between;
  padding: 14px 16px;
  margin-bottom: 10px;
  background: #0d1210;
  border: 1px solid #1d2620;
  border-radius: 6px;
  transition: border-color .12s, box-shadow .12s;
}

.lib-card:hover {
  border-color: var(--accent-2);
  box-shadow: 0 0 0 1px rgba(78, 205, 196, .3), 0 0 16px rgba(78, 205, 196, .14);
}

.lib-card__main { flex: 1 1 380px; min-width: 0; }

.lib-card__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 10px;
  margin-bottom: 6px;
}

.lib-card__title { margin: 0; font-size: 15px; color: var(--fg); }

.lib-card__system {
  padding: 1px 7px;
  border: 1px solid var(--line);
  border-radius: 4px;
  font-size: 11px;
  color: var(--accent-2);
  white-space: nowrap;
}

.lib-card__desc {
  margin: 0 0 10px;
  font-size: 13px;
  color: var(--fg-dim);
  line-height: 1.65;
}

.lib-card__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 18px;
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 12px;
  color: var(--fg-dim);
}

.lib-card__k {
  margin-right: 6px;
  color: var(--fg-dim);
  opacity: .7;
}

.lib-card__meta code {
  padding: 1px 5px;
  background: var(--bg-soft);
  border: 1px solid var(--line);
  border-radius: 4px;
  font-size: 11px;
  color: var(--accent-2);
}

.lib-card__tags {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 10px 0 0;
  padding: 0;
  list-style: none;
}

.lib-card__tags .tag {
  padding: 1px 7px;
  background: var(--bg-soft);
  border: 1px solid var(--line);
  border-radius: 4px;
  font-size: 11px;
  color: var(--fg-dim);
}

/* 操作区：竖直排列，主按钮在前 */
.lib-card__actions {
  display: flex;
  flex-direction: column;
  gap: 8px;
  flex: 0 0 160px;
  align-self: center;
}

.lib-card__actions .btn { width: 100%; text-align: center; }

.library-empty {
  padding: 40px 0;
  text-align: center;
  color: var(--fg-dim);
}

.library-howto,
.library-policy {
  max-width: 720px;
  margin-top: 36px;
  padding-top: 24px;
  border-top: 1px solid var(--line);
}

.library-howto__title,
.library-policy__title {
  margin: 0 0 14px;
  font-size: 15px;
  color: var(--accent-2);
}

.library-howto__steps {
  margin: 0 0 14px;
  padding-left: 20px;
  color: var(--fg-dim);
  font-size: 13px;
  line-height: 1.9;
}

.library-howto__steps strong { color: var(--fg); }
.library-howto__steps a { color: var(--accent); }

.library-howto__note,
.library-policy__note {
  margin: 0;
  font-size: 13px;
  color: var(--fg-dim);
  line-height: 1.7;
}

.library-policy__list {
  margin: 0 0 14px;
  padding-left: 20px;
  color: var(--fg-dim);
  font-size: 13px;
  line-height: 1.9;
}

.library-policy__list strong { color: var(--fg); }

/* ==========================================================================
   游戏设计器（/studio/）
   这一面是「开发机」：屏幕里是工具清单，机身键是玩法与环节。
   ========================================================================== */

.studio-intro { margin: 0 0 22px; }

.studio-intro__title {
  margin: 0 0 10px;
  font-size: 20px;
  letter-spacing: 2px;
  color: var(--fg);
}

.studio-intro__lead {
  margin: 0 0 12px;
  font-size: 14px;
  line-height: 1.8;
  color: var(--fg-dim);
}

.studio-intro__lead strong { color: var(--phosphor); }

.studio-intro__policy {
  margin: 0;
  font-size: 13px;
  line-height: 1.75;
  color: var(--fg-dim);
}

.studio-intro__policy strong { color: var(--fg); }

/*
  状态条 —— 一眼看出当前是「已开启」还是「规划中」。
  颜色跟着 data-state 走，而不是靠文案里的形容词：
  文案会被人改，data-state 是机器认的（自检也读它）。
*/
.studio-status {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin: 0 0 12px;
  padding: 9px 12px;
  border: 1px solid var(--line);
  border-left: 3px solid var(--accent);
  border-radius: 4px;
  background: var(--bg-soft);
  font-size: 13px;
  line-height: 1.7;
  color: var(--fg-dim);
}

.studio-status[data-state="ready"] { border-left-color: var(--accent-2); }
.studio-status[data-state="pending"] { border-left-color: var(--accent); }

.studio-status__dot {
  flex: 0 0 auto;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 6px var(--accent);
}

.studio-status[data-state="ready"] .studio-status__dot {
  background: var(--accent-2);
  box-shadow: 0 0 6px var(--accent-2);
}

.studio-status__text b { color: var(--fg); }

/* ---------- 玩法卡片 ---------- */

.studio-plans { margin: 0 0 30px; }

.studio-plans__title {
  margin: 0 0 6px;
  font-size: 15px;
  letter-spacing: 1.5px;
  color: var(--accent);
}

.studio-plans__hint {
  margin: 0 0 14px;
  font-size: 13px;
  color: var(--fg-dim);
}

.studio-plans__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 14px;
}

.plan-card {
  padding: 16px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--bg-card);
  box-shadow: var(--hard), var(--hard-in);
}

.plan-card__title {
  margin: 0 0 8px;
  font-size: 14px;
  letter-spacing: .5px;
  color: var(--phosphor);
}

.plan-card__summary {
  margin: 0 0 12px;
  font-size: 13px;
  line-height: 1.75;
  color: var(--fg-dim);
}

/* 「需要什么」做成一排小块：读起来像清单，不像段落 */
.plan-card__needs {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 0 0 12px;
  padding: 0;
  list-style: none;
}

.plan-card__needs li {
  padding: 3px 8px;
  border: 1px solid var(--line);
  border-radius: 3px;
  background: var(--bg-soft);
  font-size: 11.5px;
  color: var(--fg-dust);
}

.plan-card__fit {
  margin: 0 0 12px;
  padding-left: 9px;
  border-left: 2px solid var(--line);
  font-size: 12.5px;
  line-height: 1.7;
  color: var(--fg-dim);
}

.plan-card__picks {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px;
  margin: 0;
  font-size: 12.5px;
}

.plan-card__picks-label {
  letter-spacing: 1px;
  font-size: 11px;
  color: var(--accent);
}

.plan-card__picks-list { color: var(--fg); }

/* ---------- 工具清单 ---------- */

.studio-tools { margin: 0 0 30px; }

.studio-tools__title {
  margin: 0 0 6px;
  font-size: 15px;
  letter-spacing: 1.5px;
  color: var(--accent);
}

.studio-tools__hint {
  margin: 0 0 18px;
  font-size: 13px;
  color: var(--fg-dim);
}

.studio-tools__hint strong { color: var(--fg); }

.tool-group { margin: 0 0 22px; }

.tool-group__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 10px;
  margin: 0 0 10px;
  padding-bottom: 7px;
  border-bottom: 1px solid var(--line);
}

.tool-group__title {
  margin: 0;
  font-size: 13.5px;
  letter-spacing: 2px;
  color: var(--fg);
}

.tool-group__count {
  font-size: 11.5px;
  color: var(--fg-dust);
}

.tool-group__hint {
  flex: 1 1 100%;
  margin: 0;
  font-size: 12px;
  color: var(--fg-dust);
}

.tool-group__list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 12px;
}

.tool-card {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 14px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--bg-card);
}

.tool-card__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin: 0 0 8px;
}

.tool-card__name {
  margin: 0;
  font-size: 14px;
  color: var(--fg);
}

.tool-card__license {
  flex: 0 0 auto;
  padding: 2px 6px;
  border: 1px solid var(--line);
  border-radius: 3px;
  background: var(--bg-soft);
  font-size: 11px;
  color: var(--accent-2);
}

.tool-card__summary {
  margin: 0 0 9px;
  font-size: 13px;
  line-height: 1.75;
  color: var(--fg-dim);
}

.tool-card__bestfor,
.tool-card__note {
  margin: 0 0 7px;
  font-size: 12.5px;
  line-height: 1.7;
  color: var(--fg-dim);
}

.tool-card__note { color: var(--fg-dust); }

.tool-card__k {
  display: inline-block;
  min-width: 34px;
  margin-right: 6px;
  padding: 1px 5px;
  border-radius: 3px;
  background: var(--bg-soft);
  font-size: 11px;
  color: var(--accent);
}

.tool-card__link,
.tool-card__url { align-self: flex-start; margin-top: auto; }

/*
  开关关着时工具不给死链，只把地址摆出来 —— 想用的人自己复制。
  颜色用磷光绿而不是 --accent-2：那个色已经被许可证标签占了，
  同色会让「工具名旁边那串字」读起来也像标签，而不是一个能去的地方。
*/
.tool-card__url {
  font-size: 11.5px;
  color: var(--phosphor);
  opacity: .75;
  word-break: break-all;
}

.tool-card__url::before {
  content: '↗ ';
  opacity: .6;
}

/* ---------- 路线图 ---------- */

.studio-roadmap {
  padding: 18px;
  border: 1px dashed var(--line);
  border-radius: var(--radius);
  background: var(--bg-soft);
}

.studio-roadmap__title {
  margin: 0 0 12px;
  font-size: 13.5px;
  letter-spacing: 2px;
  color: var(--accent);
}

.studio-roadmap__list {
  margin: 0 0 12px;
  padding-left: 20px;
  font-size: 13px;
  line-height: 1.9;
  color: var(--fg-dim);
}

.studio-roadmap__list strong { color: var(--fg); }

.studio-roadmap__note {
  margin: 0;
  font-size: 12.5px;
  line-height: 1.75;
  color: var(--fg-dust);
}

.studio-roadmap__note a { color: var(--accent); }

/* ---------- 小屏 ---------- */

@media (max-width: 640px) {
  .hero__title { font-size: 24px; letter-spacing: 2px; }
  .site-main { padding: 20px 14px 40px; }
  .grid { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 12px; }
  .card__desc { -webkit-line-clamp: 3; }
  .play-bar__title { font-size: 13px; }
  .game-info { padding: 14px 16px 30px; }
  .play-bar { gap: 8px; padding: 8px 10px; }
  .zoom__value { min-width: 38px; }
  .zoom__btn { padding: 5px 7px; }
  .emu-setup__grid { grid-template-columns: 1fr; }
  .emu-stage { padding: 6px; }
  .emu-setup__title { font-size: 18px; }
  .library-intro__title { font-size: 18px; }
  .studio-intro__title { font-size: 18px; }
  .studio-plans__grid,
  .tool-group__list { grid-template-columns: 1fr; }
  .studio-roadmap { padding: 14px; }
  .lib-card { padding: 14px; }
  .lib-card__actions { flex: 1 1 100%; flex-direction: row; }
  .lib-card__actions .btn { width: auto; flex: 1; }
}

/* 尊重系统的减弱动效偏好 */
@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
  .card:hover { transform: none; }
}
