/* ============================================================
   ORANGE SERVER · 像素 UI 设计系统
   ------------------------------------------------------------
   全站共用的一份样式：调色板 / 流体尺度 / CRT 背景 / 像素窗口 /
   按钮 / 面板 / 表单 / 工作台三栏 / 弹窗 / 灯箱 / 页脚。
   各页只保留自己独有的模块，不再各自抄一遍调色板和窗口样式。

   ------------------------------------------------------------
   适配策略（取代旧的「设计宽度 + JS zoom 整页缩放」）
   ------------------------------------------------------------
   旧方案是：按一个固定设计宽度画好，再用 JS 算出 zoom 把整页
   等比塞进视口。它有两个绕不过去的毛病：

     · 13 寸笔记本（~1280×800）高度不够 → fit 常落在 0.6~0.75，
       整页连字一起缩小，像素字被压到看不清；
     · 外接大屏（2K / 4K）fit 被 min(1, …) 卡住 → 窗口还是设计宽，
       四周留一大圈空，画面撑不满。

   新方案把「缩放」换成「流体排版」：

     1) 字号 / 间距 / 控件高度一律取流体变量 --fs-* / --sp-*，
        取值 = min(跟宽度相关的项, 跟高度相关的项) 再 clamp。
        宽屏自然放大、矮屏自动收紧，两端都有上下限兜底。
     2) 断点回归纯 CSS 媒体查询 —— 没有 zoom 之后浏览器不会在
        缩放后提前重排，媒体查询可以放心用（旧的 layout-single /
        layout-tiny 类名切换因此删掉）。
     3) 窗口宽度 = clamp(320px, 94vw, 各页上限)：小屏跟着视口收，
        大屏长到该有的尺寸就停，不再靠缩小来塞进去。
     4) 高度实在不够时允许页面正常滚动，而不是把内容压成一团。
   ============================================================ */

/* ------------------------------------------------------------
   1. 调色板
   ------------------------------------------------------------ */
:root {
  --bg:        #1a1033;
  --bg-2:      #0d0820;
  --panel:     #2a1845;
  --border:    #000000;
  --orange:    #fb923c;
  --orange-l:  #ffc078;
  --orange-d:  #c2410c;
  --green:     #4ade80;
  --green-d:   #16a34a;
  --pink:      #f472b6;
  --red:       #ef4444;
  --yellow:    #facc15;
  --white:     #fff7ed;
  --muted:     #a78bcc;

  /* ----------------------------------------------------------
     2. 流体尺度
     每项都是 min(宽度项, 高度项) 再 clamp：
       宽度项 —— 外接大屏上把界面放大到舒服的尺寸；
       高度项 —— 13 寸这类矮屏上自动收紧，避免一屏塞不下；
       clamp  —— 手机和 4K 都不至于极端。
     参考值：1280×800 → 正文字号 ≈17px；1920×1080 → ≈20px；
             2560×1440 及以上 → 取上限 21px。
     ---------------------------------------------------------- */
  --fs-body:   clamp(15px, min(0.45vw + 11px, 1.10vh +  9px), 21px);
  --fs-lead:   clamp(17px, min(0.55vw + 12px, 1.30vh + 10px), 24px);
  --fs-small:  clamp(13px, min(0.30vw + 10px, 0.80vh +  8px), 17px);
  --fs-pix:    clamp(9px,  min(0.20vw +  7px, 0.42vh +  6px), 12px);
  --fs-pix-l:  clamp(11px, min(0.30vw +  8px, 0.62vh +  7px), 15px);
  --fs-pix-xl: clamp(14px, min(0.50vw + 10px, 1.00vh +  9px), 20px);

  /* 基准间距：其余间距都由它派生，改一处全站跟着动 */
  --sp:        clamp(7px, min(0.50vw, 0.95vh), 13px);
  --sp-2:      calc(var(--sp) * 1.6);
  --sp-3:      calc(var(--sp) * 2.4);
  --sp-4:      calc(var(--sp) * 3.4);

  /* 面板内边距 / 页面外边距 / 控件最小高度 */
  --pad:       clamp(10px, min(1.00vw, 1.60vh), 22px);
  --pad-page:  clamp(10px, min(1.60vw, 2.40vh), 32px);
  --ctrl-h:    clamp(38px, min(2.60vw, 4.40vh), 54px);

  /* 窗口宽度：小屏跟视口收，大屏长到上限为止（各页覆盖 --win-w） */
  --win-w:     clamp(320px, 94vw, 760px);
  --win-shadow: 8px 8px 0 0 var(--border);
}

/* ------------------------------------------------------------
   2b. 矮屏补偿：13 寸笔记本（~1280×800）纵向很紧，
       把间距 / 内边距 / 控件高度再压一档，尽量一屏看完。
       字号不动 —— 缩小字号才是「看不清」的元凶，压缩留白不是。
   ------------------------------------------------------------ */
@media (max-height: 880px) {
  :root {
    --sp:       clamp(5px,  min(0.40vw, 0.72vh), 10px);
    --pad:      clamp(8px,  min(0.85vw, 1.35vh), 16px);
    --pad-page: clamp(8px,  min(1.20vw, 1.90vh), 22px);
    --ctrl-h:   clamp(34px, min(2.20vw, 3.90vh), 46px);
  }
}

/* ------------------------------------------------------------
   3. 基础
   ------------------------------------------------------------ */
* { margin: 0; padding: 0; box-sizing: border-box; }

html { height: 100%; -webkit-text-size-adjust: 100%; overflow-x: hidden; }

body {
  min-height: 100vh;
  min-height: 100dvh;
  /* 居中用子项 margin:auto：内容超高时不会像 align-items:center 那样
     把顶部顶到视口外、滚不回去。 */
  display: flex;
  padding: var(--pad-page);
  padding-left:  max(var(--pad-page), env(safe-area-inset-left));
  padding-right: max(var(--pad-page), env(safe-area-inset-right));
  background: radial-gradient(circle at 50% 30%, var(--panel) 0%, var(--bg-2) 70%);
  background-attachment: fixed;
  background-color: var(--bg-2);
  color: var(--white);
  font-family: "VT323", "Courier New", monospace;
  font-size: var(--fs-body);
  line-height: 1.5;
  image-rendering: pixelated;
  -webkit-font-smoothing: none;
}

/* 舞台：窗口 + 页脚。宽度由 --win-w 决定，高度随内容 */
.stage {
  position: relative; z-index: 1;
  margin: auto;
  width: 100%;
  max-width: var(--win-w);
  display: flex; flex-direction: column;
  gap: var(--sp-3);
}

/* ------------------------------------------------------------
   4. 星空 / CRT 扫描线 / 暗角
   ------------------------------------------------------------ */
.stars { position: fixed; inset: 0; pointer-events: none; z-index: 0; overflow: hidden; }
.star {
  position: absolute;
  width: 3px; height: 3px;
  background: var(--white);
  animation: twinkle 2s steps(2) infinite;
}
@keyframes twinkle { 0%,100%{opacity:1;} 50%{opacity:.2;} }

.scanlines {
  position: fixed; inset: 0; pointer-events: none; z-index: 100;
  background: repeating-linear-gradient(
    to bottom, rgba(0,0,0,0) 0, rgba(0,0,0,0) 2px,
    rgba(0,0,0,.18) 3px, rgba(0,0,0,.18) 4px);
  mix-blend-mode: multiply;
}
.crt-vignette {
  position: fixed; inset: 0; pointer-events: none; z-index: 99;
  background: radial-gradient(ellipse at center, transparent 55%, rgba(0,0,0,.55) 100%);
}

/* ------------------------------------------------------------
   5. 像素窗口
   ------------------------------------------------------------ */
.window {
  position: relative;
  width: 100%;
  display: flex; flex-direction: column;
  background: var(--panel);
  border: 4px solid var(--border);
  box-shadow: var(--win-shadow),
              inset -6px -6px 0 0 rgba(0,0,0,.35),
              inset 6px 6px 0 0 rgba(255,255,255,.08);
  animation: winIn .5s steps(6) both;
}
@keyframes winIn {
  0%   { opacity:0; transform: translate(20px,20px); }
  100% { opacity:1; transform: translate(0,0); }
}

.titlebar {
  flex: 0 0 auto;
  background: var(--orange);
  border-bottom: 4px solid var(--border);
  padding: var(--sp-2) var(--sp-3);
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-2);
  font-family: "Press Start 2P", monospace;
  font-size: var(--fs-pix-l);
  color: var(--bg-2);
  letter-spacing: 1px;
}
.titlebar > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lights { display: flex; gap: 6px; flex: 0 0 auto; }
.light { width: 14px; height: 14px; border: 2px solid var(--border); }
.light.r { background: var(--red); }
.light.y { background: var(--yellow); }
.light.g { background: var(--green); }

.content { padding: var(--pad); text-align: center; }

/* ------------------------------------------------------------
   6. 标题 / 文本
   ------------------------------------------------------------ */
h1 {
  font-family: "Press Start 2P", monospace;
  font-size: var(--fs-pix-xl);
  line-height: 1.6;
  color: var(--orange-l);
  margin-bottom: var(--sp);
  text-shadow: 3px 3px 0 var(--orange-d);
}
.subtitle {
  font-size: var(--fs-lead);
  color: var(--muted);
  margin-bottom: var(--sp-3);
}
.cursor {
  display: inline-block;
  width: 0.55em; height: 1.05em;
  background: var(--green);
  vertical-align: -0.18em;
  margin-left: 4px;
  animation: blink 1s steps(2) infinite;
}
@keyframes blink { 0%,50%{opacity:1;} 51%,100%{opacity:0;} }

/* ------------------------------------------------------------
   6b. 橙子 Hero / 大状态块（主页 / 404 / NO SLEEP 共用）
   外壳只有「暗底 + 像素内阴影」一套，尺寸走 --orange-size；
   主页在它上面叠 hover 位移，404 叠摇头动画，各自只留差异部分。
   ------------------------------------------------------------ */
.orange-wrap {
  display: inline-block;
  margin-bottom: var(--sp-3);
  padding: 8px;
  background: var(--bg-2);
  border: 4px solid var(--border);
  box-shadow: inset 4px 4px 0 0 rgba(255,255,255,.06),
              inset -4px -4px 0 0 rgba(0,0,0,.5);
  position: relative;
}
#orange-svg {
  display: block;
  /* 宽高双向约束：矮屏收小免得一屏放不下，大屏放开到 --orange-size 封顶 */
  width: var(--orange-size, clamp(104px, min(11.5rem, 20vh), 208px));
  height: auto;
  aspect-ratio: 1 / 1;
}

/* NO SLEEP v1 / v2 的大状态块，行高与内边距差异由各页覆盖 */
.big-status {
  font-family: "Press Start 2P", monospace;
  font-size: var(--fs-pix-l);
  line-height: 1.8;
  text-align: center;
  padding: var(--sp-3) var(--sp-2);
  margin-bottom: var(--sp-3);
  border: 4px solid var(--border);
  background: var(--bg-2);
  box-shadow: inset 4px 4px 0 0 rgba(255,255,255,.05),
              inset -4px -4px 0 0 rgba(0,0,0,.5);
  color: var(--muted);
}
.big-status.on  { color: var(--green); text-shadow: 3px 3px 0 var(--green-d); }
.big-status.err { color: var(--red); }

/* ------------------------------------------------------------
   7. 终端信息块：.terminal（主页 / 404 / NO SLEEP 共用）
   ------------------------------------------------------------ */
.terminal {
  background: var(--bg-2);
  border: 4px solid var(--border);
  padding: var(--sp-2) var(--pad);
  text-align: left;
  font-size: var(--fs-body);
  line-height: 1.55;
  box-shadow: inset 4px 4px 0 0 rgba(255,255,255,.05),
              inset -4px -4px 0 0 rgba(0,0,0,.5);
}
.terminal .row {
  display: flex; justify-content: space-between;
  gap: var(--sp-3); padding: 2px 0;
  align-items: baseline;
  flex-wrap: wrap;
}
.terminal .k { color: var(--pink); flex: 0 0 auto; }
.terminal .v { color: var(--green); text-align: right; word-break: break-word; }
.terminal .v.warn  { color: var(--yellow); }
.terminal .v.err   { color: var(--red); }
.terminal .v.off   { color: var(--muted); }
.terminal .v.flash { animation: flash 1s steps(2) infinite; }
@keyframes flash { 0%,100%{opacity:1;} 50%{opacity:.3;} }

.terminal-title {
  font-family: "Press Start 2P", monospace;
  font-size: var(--fs-pix);
  color: var(--orange-l);
  letter-spacing: 1px;
  margin-bottom: var(--sp-2);
  padding-bottom: var(--sp);
  border-bottom: 2px dashed rgba(167,139,204,.35);
}
.terminal .hint {
  display: block;
  color: var(--muted);
  margin-top: var(--sp-2);
  padding-top: var(--sp-2);
  border-top: 2px dashed rgba(167,139,204,.3);
}
.terminal .hint .path { color: var(--orange-l); }

/* ------------------------------------------------------------
   8. 按钮
   ------------------------------------------------------------ */
.btn-row { display: flex; gap: var(--sp-2); justify-content: center; flex-wrap: wrap; }
/* 默认按内容宽度居中排（首页 / 404 / NO SLEEP 的观感）；
   工作台三栏里要铺满列宽，由那一页自己覆盖成 flex: 1 1 0。 */
.btn-row > .btn { flex: 0 1 auto; }

.btn {
  font-family: "Press Start 2P", monospace;
  font-size: var(--fs-pix);
  color: var(--bg-2);
  background: var(--orange);
  border: 3px solid var(--border);
  padding: var(--sp-2) var(--sp-3);
  min-height: var(--ctrl-h);
  cursor: pointer;
  box-shadow: 4px 4px 0 var(--border);
  transition: background .08s steps(2), transform .08s steps(2), box-shadow .08s steps(2);
  text-decoration: none;
  display: inline-flex; align-items: center; justify-content: center;
  text-align: center;
  -webkit-tap-highlight-color: transparent;
}
.btn:hover {
  background: var(--orange-l);
  transform: translate(-2px,-2px);
  box-shadow: 6px 6px 0 var(--border);
}
.btn:active { transform: translate(2px,2px); box-shadow: 2px 2px 0 var(--border); }
.btn:focus-visible { outline: 3px solid var(--yellow); outline-offset: 3px; }
.btn[disabled] { opacity: .45; cursor: not-allowed; transform: none; box-shadow: 4px 4px 0 var(--border); }
.btn.alt   { background: var(--pink); }
.btn.alt:hover   { background: #f9a8d4; }
.btn.ghost { background: var(--panel); color: var(--orange-l); }
.btn.ghost:hover { background: #3a2260; }
.btn.on    { background: var(--green); }
.btn.on:hover    { background: var(--green-d); color: var(--white); }
.btn-wide  { width: 100%; }

.mini-btn {
  font-family: "Press Start 2P", monospace;
  font-size: var(--fs-pix);
  background: var(--panel); color: var(--orange-l);
  border: 2px solid var(--border);
  padding: 4px 7px;
  cursor: pointer;
  box-shadow: 2px 2px 0 var(--border);
  white-space: nowrap;
}
.mini-btn:hover { background: #3a2260; }
.mini-btn.on { background: var(--green-d); color: var(--white); }
.mini-btn:disabled { opacity: .4; cursor: not-allowed; }

.mini-field {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: var(--fs-small); color: var(--muted);
  white-space: nowrap;
}
.mini-field select, .mini-field input {
  font-family: "VT323", monospace; font-size: var(--fs-small);
  background: var(--panel); color: var(--white);
  border: 2px solid var(--border); padding: 2px 5px;
}
.mini-field input[type=number] { width: 62px; }

/* ------------------------------------------------------------
   9. 表单 / 提示文本
   ------------------------------------------------------------ */
.grp { margin-bottom: var(--sp-3); }
.grp:last-child { margin-bottom: 0; }
.grp-title {
  font-family: "Press Start 2P", monospace;
  font-size: var(--fs-pix);
  color: var(--pink);
  letter-spacing: 1px;
  margin-bottom: var(--sp-2);
  padding-bottom: var(--sp);
  border-bottom: 2px dashed rgba(167,139,204,.35);
}
.field-row { display: flex; gap: var(--sp-2); margin-bottom: var(--sp-2); flex-wrap: wrap; }
.field-row > .field { flex: 1 1 120px; min-width: 0; }
.field { display: block; font-size: var(--fs-small); color: var(--muted); }
.field > span.lab { display: block; margin-bottom: 4px; }
.field select, .field input[type=text], .field input[type=number] {
  width: 100%;
  font-family: "VT323", monospace; font-size: var(--fs-body);
  background: var(--panel); color: var(--white);
  border: 3px solid var(--border);
  padding: 5px 7px;
  outline: none;
}
.field select:focus, .field input:focus { border-color: var(--orange); }
.field .hintline { display: block; font-size: var(--fs-small); color: #8b74b5; margin-top: 3px; line-height: 1.35; }

.check-row {
  display: flex; align-items: center; gap: var(--sp-2);
  font-size: var(--fs-body); color: var(--white);
  cursor: pointer; margin-bottom: var(--sp-2);
  text-align: left;
}
.check-row input { width: 18px; height: 18px; accent-color: var(--orange); cursor: pointer; flex: 0 0 auto; }

.hint { font-size: var(--fs-small); color: var(--muted); line-height: 1.5; text-align: left; }
.hint code {
  background: var(--panel); border: 2px solid var(--border);
  padding: 0 4px; color: var(--orange-l);
}
ul.hint { padding-left: 20px; margin: var(--sp) 0; }
ul.hint li { margin: 3px 0; }

/* ------------------------------------------------------------
   10. 进度条
   ------------------------------------------------------------ */
.progress {
  height: clamp(18px, min(1.4vw, 2.4vh), 24px);
  background: var(--bg-2);
  border: 3px solid var(--border);
  position: relative;
  box-shadow: inset 2px 2px 0 0 rgba(0,0,0,.6);
  margin-bottom: var(--sp-2);
  overflow: hidden;
}
.progress .bar {
  position: absolute; top: 3px; bottom: 3px; left: 3px; width: 0%;
  background: repeating-linear-gradient(
    to right, var(--green) 0 10px, var(--green-d) 10px 13px);
  transition: width .12s steps(6);
}
.progress .bar.busy { animation: barPulse 1.2s steps(4) infinite; }
@keyframes barPulse { 0%,100%{filter:brightness(1);} 50%{filter:brightness(1.4);} }

/* ------------------------------------------------------------
   11. 工作台三栏（pdf2img / imgmerge）
   轨道宽度是各页尺寸决定项，由页面覆盖 .workbench 的 grid-template-columns。
   ------------------------------------------------------------ */
.workbench {
  flex: 1 1 auto;
  min-height: 0;
  display: grid;
  grid-template-areas: "queue stage ctrl";
  grid-template-columns: minmax(0, 320px) minmax(0, 1fr) minmax(0, 340px);
  gap: var(--sp-3);
  padding: var(--sp-3);
  align-items: stretch;
  /* 高度随视口：13 寸矮屏收到 ~500，外接大屏放到 760 封顶 */
  height: clamp(380px, 68vh, 760px);
}

.panel {
  min-width: 0;
  background: var(--bg-2);
  border: 4px solid var(--border);
  box-shadow: inset 4px 4px 0 0 rgba(255,255,255,.05),
              inset -4px -4px 0 0 rgba(0,0,0,.5);
  display: flex; flex-direction: column;
  min-height: 0;
}
.panel-head {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  border-bottom: 3px solid var(--border);
  background: #1b0d33;
  font-family: "Press Start 2P", monospace;
  font-size: var(--fs-pix);
  color: var(--orange-l);
  letter-spacing: 1px;
  flex: 0 0 auto;
  white-space: nowrap;
  overflow: hidden;
}
.panel-head > span:first-child { overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.panel-head .tick {
  display: inline-block; width: 8px; height: 8px;
  background: var(--green); margin-right: 7px; vertical-align: 1px;
  animation: blink 1.4s steps(2) infinite;
}
.panel-head .cnt {
  font-family: "VT323", monospace;
  font-size: var(--fs-small);
  color: var(--muted);
  letter-spacing: 0;
  white-space: nowrap;
}
.panel-head-actions,
.stage-head-actions { display: flex; align-items: center; gap: var(--sp-2); flex: 0 0 auto; }

.panel-body { flex: 1 1 auto; min-height: 0; overflow: auto; padding: var(--pad); }
/* 滚动条也做成像素条 */
.panel-body::-webkit-scrollbar { width: 12px; height: 12px; }
.panel-body::-webkit-scrollbar-track { background: #12082a; border-left: 3px solid var(--border); }
.panel-body::-webkit-scrollbar-thumb { background: var(--orange-d); border: 3px solid var(--border); }

.panel-queue { grid-area: queue; }
.panel-stage { grid-area: stage; }
.panel-ctrl  { grid-area: ctrl; }

/* 面板里的操作按钮铺满列宽（单栏页面仍按内容居中，见 .btn-row） */
.panel .btn-row > .btn { flex: 1 1 0; }
.panel .btn-row { margin-bottom: var(--sp-2); }
.panel-body > .hint { margin-top: var(--sp-3); }

/* ---------- 拖放区 ----------
   label 默认是 inline：padding 撑不出盒子，虚线会只剩左右两条竖线，
   必须是块级盒子。 */
.dropzone {
  display: block;
  border: 3px dashed #5b3f8c;
  background: rgba(0,0,0,.35);
  padding: var(--sp-3) var(--sp-2);
  text-align: left;
  overflow-wrap: anywhere;
  cursor: pointer;
  transition: background .08s steps(2), border-color .08s steps(2);
  margin-bottom: var(--sp-3);
}
.dropzone:hover, .dropzone.over { background: #33205a; border-color: var(--orange); }
.dropzone .big {
  display: block;
  font-family: "Press Start 2P", monospace;
  font-size: var(--fs-pix);
  color: var(--orange-l);
  margin-bottom: var(--sp-2);
}
.dropzone .sub { display: block; font-size: var(--fs-small); color: var(--muted); line-height: 1.4; }
.dropzone input[type=file] { display: none; }

/* ---------- 中栏空态 ---------- */
.stage-empty {
  height: 100%;
  min-height: 180px;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--sp-2); color: var(--muted); text-align: center;
  font-size: var(--fs-body); line-height: 1.5;
}
/* display:flex 会覆盖 [hidden] 的 display:none，必须显式压回去 */
.stage-empty[hidden] { display: none; }
.stage-empty .glyph {
  font-family: "Press Start 2P", monospace;
  font-size: var(--fs-pix-xl); color: var(--orange-d);
}

/* 输出预估框 */
.output-check {
  border: 3px solid var(--border);
  background: rgba(0,0,0,.4);
  padding: var(--sp-2) var(--sp-3);
  font-size: var(--fs-small); line-height: 1.45;
  color: var(--muted);
  margin-bottom: var(--sp-3);
  text-align: left;
}
.output-check b { color: var(--green); font-weight: normal; }
.output-check .warn { color: var(--yellow); }
.output-check .err  { color: var(--red); }

/* ---------- 工作台断点：没有 zoom 之后可以放心用媒体查询 ---------- */
/* 中等窗口：三栏放不下就两栏，设置栏整行挪到下面 */
@media (max-width: 1180px) {
  .workbench {
    grid-template-columns: minmax(0, 300px) minmax(0, 1fr);
    grid-template-areas:
      "queue stage"
      "ctrl  ctrl";
    height: clamp(420px, 74vh, 900px);
  }
  /* 设置栏变宽后横排分组，免得输入框被拉成超长条；
     按钮组 / 进度 / 预估 / 说明仍然独占整行 */
  .panel-ctrl .panel-body {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: var(--sp-3);
    align-content: start;
  }
  .panel-ctrl .panel-body > .btn-row,
  .panel-ctrl .panel-body > .progress,
  .panel-ctrl .panel-body > .output-check,
  .panel-ctrl .panel-body > .hint { grid-column: 1 / -1; }
}
/* 窄窗口（手机竖屏）：单列，高度交给内容 */
@media (max-width: 860px) {
  .workbench {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "queue" "stage" "ctrl";
    height: auto;
  }
  .workbench .panel { max-height: 70vh; }
  .panel-ctrl .panel-body { display: block; }
  .titlebar { font-size: var(--fs-pix); }
}

/* ------------------------------------------------------------
   12. 工具清单卡（主页弹窗）
   用 grid 分区，防中文按单字换行把卡片撑高
   ------------------------------------------------------------ */
.card {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) max-content max-content;
  grid-template-areas: "ico body tags go";
  align-items: center;
  gap: var(--sp-3);
  background: var(--bg-2);
  border: 3px solid var(--border);
  box-shadow: 4px 4px 0 var(--border);
  padding: var(--sp-2) var(--sp-3);
  text-decoration: none;
  color: var(--white);
  transition: transform .08s steps(2), box-shadow .08s steps(2), background .08s steps(2);
}
.card:hover { background: #33205a; transform: translate(-2px,-2px); box-shadow: 6px 6px 0 var(--border); }
.card:active { transform: translate(2px,2px); box-shadow: 2px 2px 0 var(--border); }
.card:focus-visible { outline: 3px solid var(--yellow); outline-offset: 2px; }
.card + .card { margin-top: var(--sp-2); }

.card-ico {
  grid-area: ico;
  width: clamp(36px, 3vw, 48px); height: clamp(36px, 3vw, 48px);
  background: var(--panel);
  border: 3px solid var(--border);
  box-shadow: inset 3px 3px 0 0 rgba(255,255,255,.06),
              inset -3px -3px 0 0 rgba(0,0,0,.5);
  display: flex; align-items: center; justify-content: center;
  font-size: var(--fs-lead);
  line-height: 1;
}
.card-body { grid-area: body; min-width: 0; overflow-wrap: break-word; }
.card-name {
  display: block;
  font-family: "Press Start 2P", monospace;
  font-size: var(--fs-pix);
  color: var(--white);
  margin-bottom: var(--sp);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.card-name em {
  font-style: normal;
  font-family: "VT323", "Courier New", monospace;
  font-size: var(--fs-small);
  color: var(--muted);
  margin-left: 6px;
}
.card-desc { display: block; font-size: var(--fs-small); line-height: 1.35; color: var(--muted); }
.card-tags { grid-area: tags; display: flex; gap: 6px; flex-wrap: wrap; }
.card-tags i {
  font-style: normal;
  font-family: "Press Start 2P", monospace;
  font-size: var(--fs-pix);
  padding: 4px 6px;
  border: 2px solid var(--border);
  background: #3a2260;
  color: var(--white);
  white-space: nowrap;
}
.card-tags i.g { background: var(--green-d); }
.card-tags i.y { background: #a16207; }
.card-go {
  grid-area: go;
  font-family: "Press Start 2P", monospace;
  font-size: var(--fs-pix);
  color: var(--orange-l);
  white-space: nowrap;
  animation: blink 1.4s steps(2) infinite;
}
.card-hint { margin-top: var(--sp-3); font-size: var(--fs-small); line-height: 1.45; color: var(--muted); }

@media (max-width: 720px) {
  .card {
    grid-template-columns: auto minmax(0, 1fr);
    grid-template-areas:
      "ico body"
      "ico tags";
    gap: var(--sp-2) var(--sp-3);
    align-items: start;
  }
  .card-go { display: none; }
  .card-name { white-space: normal; }
}

/* ------------------------------------------------------------
   13. 弹窗 / 遮罩（固定定位，不参与任何缩放）
   ------------------------------------------------------------ */
.modal {
  position: fixed; inset: 0; z-index: 220;
  background: rgba(6,2,16,.88);
  display: none; align-items: center; justify-content: center;
  padding: max(3vh, 12px) max(3vw, 12px);
  overflow: auto;
}
.modal.on { display: flex; }
.modal-box {
  width: 100%; max-width: min(760px, 100%);
  max-height: min(88vh, 88dvh);
  background: var(--panel);
  border: 4px solid var(--border);
  box-shadow: 8px 8px 0 var(--border),
              inset -6px -6px 0 0 rgba(0,0,0,.35),
              inset 6px 6px 0 0 rgba(255,255,255,.08);
  display: flex; flex-direction: column;
  animation: winIn .28s steps(6) both;
}
.modal-box .titlebar { font-size: var(--fs-pix); }
.modal-head { flex: 0 0 auto; }
.modal-body { flex: 1 1 auto; min-height: 0; overflow: auto; overscroll-behavior: contain; padding: var(--pad); font-size: var(--fs-body); line-height: 1.5; }
.modal-body p { margin-bottom: var(--sp-2); color: var(--muted); }
.modal-body b { color: var(--white); font-weight: normal; }
.modal-foot { flex: 0 0 auto; padding: 0 var(--pad) var(--pad); display: flex; gap: var(--sp-2); }

/* ------------------------------------------------------------
   14. 灯箱
   图片盒样式两页不同（PDF 页白底当相纸，图片页要透出棋盘格），由各页补。
   ------------------------------------------------------------ */
.lightbox {
  position: fixed; inset: 0; z-index: 200;
  background: rgba(6,2,16,.92);
  display: none;
  align-items: center; justify-content: center;
  gap: var(--sp-2);
  padding: 4vh 4vw;
  cursor: zoom-out;
}
.lightbox.on { display: flex; flex-direction: column; }
.lightbox .lb-bar {
  font-family: "Press Start 2P", monospace;
  font-size: var(--fs-pix);
  color: var(--orange-l); letter-spacing: 1px;
}
.lightbox img { max-width: 100%; max-height: 82vh; border: 4px solid var(--border); box-shadow: 8px 8px 0 var(--border); }

/* ------------------------------------------------------------
   15. 页脚
   ------------------------------------------------------------ */
footer {
  flex: 0 0 auto;
  font-size: var(--fs-small);
  color: var(--muted);
  text-align: center;
  overflow-wrap: break-word;
  text-wrap: balance;
}
footer .heart { color: var(--pink); }
footer .copy  { color: var(--yellow); }
footer a      { color: var(--orange-l); }

/* ------------------------------------------------------------
   16. 单屏模式（NO SLEEP v1 / v2）
   这两页要求「一个屏幕显示完、不出现滚动条」：内容比视口高时
   整体等比缩小，而不是让页面滚动。缩放由 assets/fit-screen.js
   量出舞台实际尺寸后写回 --fit-scale；居中用 fixed + translate，
   缩完上下左右都不会被裁掉。
   ------------------------------------------------------------ */
body.fit-screen {
  display: block;
  height: 100vh;
  height: 100dvh;
  padding: 0;
  overflow: hidden;
}
body.fit-screen .stage {
  position: fixed;
  top: 50%;
  left: 50%;
  margin: 0;
  transform: translate(-50%, -50%) scale(var(--fit-scale, 1));
  transform-origin: center center;
}

/* ------------------------------------------------------------
   16. 尊重系统「减少动态效果」
   ------------------------------------------------------------ */
@media (prefers-reduced-motion: reduce) {
  .stars { display: none; }
  .star  { animation: none; }
  .window { animation: none; }
}
