/* 《未发送》Ch1 切片 —— 配色按《美术生成规格》的 Ch1「暖黄」档
   1958 年邮电所：绿罩台灯、牛皮纸、铅笔。跟 Ch4 的冷白是两套。

   状态区分只用 alpha 与描边，不依赖色相（UI 规格 §5 色盲项）。
   唯一的例外是预算条超额的红，那里额外加了抖动作为非色相提示。 */

:root {
  --fs: 1;                 /* 字号缩放，无障碍项 */
  --ink: #2b2724;
  --ink-soft: #6d665f;
  --paper: #f0ebe1;        /* Ch1 牛皮黄 */
  --lamp: #c8a86b;         /* 绿罩台灯下的暖光 */
  /* 同一个暖黄提亮一档，只给「压在照片上的小字」用（结局页那两处）。
     #c8a86b 亮度 0.41，14px 小字压在插图最亮处只有 2.35，靠压暗补要压到 alpha .47，
     插图就没了。提亮文字 + 轻遮罩两头凑，插图能留住。色相不变，还是那盏灯。 */
  --lamp-hi: #e3caa0;
  --ghost: 0.25;           /* 幽灵态 alpha —— 唯一定义处 */
  --grid-line: rgba(109, 102, 95, .30);
}

* { box-sizing: border-box; margin: 0; padding: 0; }

html, body {
  height: 100%;
  background: #14110e;
  font-family: "Songti SC", "SimSun", "Source Han Serif SC", serif;
  color: var(--ink);
  overflow: hidden;
  -webkit-tap-highlight-color: transparent;
}

#stage {
  position: relative;
  width: 100%; height: 100%;
  overflow: hidden;
}

/* ---------- 画面 ---------- */
.screen {
  position: absolute; inset: 0;
  display: none;
  align-items: center; justify-content: center;
  flex-direction: column;
}
.screen.active { display: flex; }

.bg {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  z-index: 0;
}
.bg.dim { filter: brightness(.34) saturate(.7); }
.paper-bg { filter: brightness(1.02) saturate(.9); }

/* 柜台：c02 里有一处近乎过曝的亮区（台灯热点），奶白台词压在那儿最差只有 3.2，
   动作行那档 1.7。单靠压暗要压到 .44 才够，柜台就变成背板了 ——
   改成「轻压 + 一条通栏遮罩」：照片留在 .62，两档文字最差 10.2 / 5.5。
   遮罩做成通栏且上下都淡出到 0：满宽所以没有左右硬边，淡出所以没有上下硬边。
   （先试过给台词块加椭圆遮罩，渐变在盒子边界还剩 0.57，屏幕中间浮出一个灰方块。） */
#screen-counter .bg { filter: brightness(.62) saturate(.85); }
#screen-counter::before {
  content: '';
  position: absolute; inset: 0; z-index: 1;
  pointer-events: none;
  background: linear-gradient(rgba(20, 17, 14, 0) 6%,
                              rgba(20, 17, 14, .74) 28%,
                              rgba(20, 17, 14, .74) 76%,
                              rgba(20, 17, 14, 0) 96%);
}

/* ---------- 按钮 ---------- */
.btn-main, .btn-ghost {
  position: relative; z-index: 5;
  font-family: inherit;
  font-size: calc(17px * var(--fs));
  padding: 10px 30px;
  border: 1px solid rgba(240, 235, 225, .5);
  background: rgba(20, 17, 14, .5);
  color: #f0ebe1;
  cursor: pointer;
  transition: background .18s, border-color .18s, opacity .2s;
  backdrop-filter: blur(3px);
}
.btn-main:hover, .btn-ghost:hover {
  background: rgba(200, 168, 107, .28);
  border-color: var(--lamp);
}
.btn-main:disabled {
  opacity: .32;
  cursor: default;
  border-color: rgba(240, 235, 225, .22);
}
.btn-main:disabled:hover { background: rgba(20, 17, 14, .5); border-color: rgba(240, 235, 225, .22); }
.hidden { display: none !important; }

/* ---------- 标题 ----------
   e01 是整套素材里最亮的一张（雪原 + 灰白天空）。奶白标题直接叠上去
   中位对比度 1.12 —— 「第一章」三个字实测完全看不见。
   做法跟 Ch4 的 .title-block 一致：底部一条渐变遮罩，字压在遮罩上。
   遮罩只吃下半幅雪地，上三分之一的空白天空、那排烟囱、右边那行脚印都留着 ——
   美术规格 §7 E-01 特意留的上部空白不能白留。 */
.title-inner {
  position: absolute; bottom: 0; left: 0;
  width: 100%;
  z-index: 5;
  text-align: center;
  color: #f0ebe1;
  padding: 74px 6vw 7vh;
  background: linear-gradient(rgba(20, 17, 14, 0) 0%, rgba(20, 17, 14, .76) 54%);
  text-shadow: 0 1px 3px rgba(0, 0, 0, .6);
}
.ch-no   { font-size: calc(15px * var(--fs)); letter-spacing: .5em; opacity: .8; }
.ch-name { font-size: calc(64px * var(--fs)); letter-spacing: .22em; margin: 10px 0 18px; }
.ch-meta { font-size: calc(14px * var(--fs)); opacity: .72; margin-bottom: 40px; letter-spacing: .08em; }

/* ---------- 心声浮字 ---------- */
.voice-stack {
  position: relative; z-index: 5;
  max-width: 44em;
  padding: 0 6vw;
  text-align: center;
}
.voice-line {
  font-size: calc(21px * var(--fs));
  line-height: 2.1;
  color: #ece5d8;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 1s, transform 1s;
  text-shadow: 0 1px 18px rgba(0, 0, 0, .85);
}
.voice-line.in { opacity: 1; transform: none; }

/* ---------- 柜台 ---------- */
.dialog-box {
  position: relative; z-index: 5;
  max-width: 40em;
  padding: 0 6vw;
  text-align: center;
}
.beat {
  font-size: calc(20px * var(--fs));
  line-height: 2;
  margin: 14px 0;
  opacity: 0;
  transform: translateY(6px);
  transition: opacity .8s, transform .8s;
  text-shadow: 0 1px 16px rgba(0, 0, 0, .9);
}
.beat.in { opacity: 1; transform: none; }
.beat.clerk { color: #f0ebe1; }
/* 动作行：不是台词，压暗一档 */
.beat.act { color: #b9ae9c; font-size: calc(17px * var(--fs)); font-style: italic; }

#counter-next, #intro-next, #settle-next { position: absolute; bottom: 7vh; }

/* ---------- 预算条：顶部常驻 ---------- */
#budget-bar {
  position: absolute; top: 0; left: 0; right: 0;
  z-index: 10;
  display: flex; gap: 2.4em;
  justify-content: center; align-items: center;
  padding: 14px 20px;
  background: linear-gradient(rgba(20, 17, 14, .82), rgba(20, 17, 14, .58) 70%, transparent);
  color: #f0ebe1;
  font-size: calc(16px * var(--fs));
  letter-spacing: .06em;
  font-variant-numeric: tabular-nums;
}
#budget-cost { color: var(--lamp); }
#budget-left { opacity: .78; }

/* 超额：字数变红 + 抖 2px。红是提示，抖才是给色盲的那一份 */
#budget-bar.over #budget-count {
  color: #e06a52;
  animation: shake .42s infinite;
}
@keyframes shake {
  0%, 100% { transform: translateX(0); }
  25%      { transform: translateX(-2px); }
  75%      { transform: translateX(2px); }
}

/* ---------- 电报纸 ---------- */
#paper {
  position: relative; z-index: 5;
  padding: 30px 34px;
  background: rgba(240, 235, 225, .93);
  box-shadow: 0 18px 60px rgba(0, 0, 0, .55), inset 0 0 60px rgba(200, 168, 107, .10);
  transition: filter .5s;
}
/* 发送时纸面轻微压暗 —— 电报键在响，纸已经不是玩家的了 */
#paper.sending { filter: brightness(.86) saturate(.85); }

#grid { display: flex; flex-direction: column; gap: 6px; }
.grid-row { display: flex; gap: 6px; }

/* ---------- 字元 CharToken ----------
   四种状态见 UI 规格 §1。幽灵态是本作的视觉签名：
   被删的字永远留在原位，不消失、不重排、不塌缩。这条规则不允许任何例外。 */
.cell {
  position: relative;
  width: calc(46px * var(--fs));
  height: calc(46px * var(--fs));
  display: flex; align-items: center; justify-content: center;
  border: 1px solid var(--grid-line);
  cursor: pointer;
  opacity: 0;
  transition: opacity .35s;
  outline: none;
}
.cell.in { opacity: 1; }

.cell .glyph {
  font-size: calc(27px * var(--fs));
  line-height: 1;
  color: var(--ink);
  /* 铅笔字：稍微歪一点，别像印刷体 */
  transform: rotate(-.6deg);
  transition: opacity .12s, transform .12s;
}

/* 格位号：淡到几乎看不见，但 1A 那句「在第十九个格子」要能被数出来 */
.cell-no {
  position: absolute; top: 1px; left: 3px;
  font-size: calc(9px * var(--fs));
  font-style: normal;
  color: var(--ink-soft);
  opacity: .30;
  pointer-events: none;
}

/* hover/按下放大 1.05，给出可点反馈 */
.cell:hover .glyph, .cell:focus-visible .glyph { transform: scale(1.05) rotate(-.6deg); }
.cell:focus-visible { border-color: var(--lamp); }

/* deleted：alpha 0.25，位置不变，可点击恢复 */
.cell.deleted .glyph {
  opacity: var(--ghost);
  transform: scale(.9) rotate(-.6deg);
}
.cell.deleted:hover .glyph { opacity: .42; }

/* dragging：提起，投影 + 放大 1.08 */
.cell.dragging {
  z-index: 20;
  border-color: var(--lamp);
}
.cell.dragging .glyph {
  transform: scale(1.08) rotate(-.6deg);
  text-shadow: 0 6px 14px rgba(0, 0, 0, .45);
}
/* 点选态（无障碍替代拖动）：描边，不靠色相 */
.cell.picked { border-color: var(--ink); border-width: 2px; }

/* ---------- 电报员 / 心声 ----------
   这两条浮在电报纸照片上，纸只占 16:9 画面的 23%，其余全是亮照片。
   实测中位对比度：电报员 1.67、心声 1.16 —— 16px 的 text-shadow 是光晕，不是对比度。
   各自带一条通栏渐变遮罩，跟同屏的 #budget-bar 是同一个办法（那条一直是可读的，
   因为它本来就有渐变底）。上下淡出到 0，所以看不出边；照片一点没动。 */
#clerk-line, #voice-line {
  position: absolute; z-index: 8;
  left: 0; right: 0;
  text-align: center;
  padding: 16px 8vw;
  /* 加了遮罩之后这两条从「一行文字高」变成 53px 高的通栏块，z-index 8 又高于纸（5）。
     窄窗口下它们可能盖到格子上，吞掉点击 —— 它们纯展示，直接关掉命中测试。 */
  pointer-events: none;
  background: linear-gradient(rgba(20, 17, 14, 0) 0%,
                              rgba(20, 17, 14, .80) 36%,
                              rgba(20, 17, 14, .80) 64%,
                              rgba(20, 17, 14, 0) 100%);
  opacity: 0;
  transition: opacity .7s;
  text-shadow: 0 1px 4px rgba(0, 0, 0, .85);
}
#clerk-line {
  top: 9vh;
  font-size: calc(18px * var(--fs));
  color: #ece5d8;
}
/* 心声：手写体档位，比电报员小一号，是她/他脑子里的声音不是嘴里的 */
#voice-line {
  bottom: 15vh;
  font-size: calc(19px * var(--fs));
  color: var(--lamp);
  letter-spacing: .04em;
}
#clerk-line.in, #voice-line.in { opacity: 1; }

#puzzle-actions {
  position: absolute; bottom: 6vh; z-index: 8;
  display: flex; gap: 14px;
}

/* ---------- 结局 ---------- */
#screen-ending { justify-content: flex-start; }
#ending-scroll {
  position: relative; z-index: 5;
  width: min(56em, 88vw);
  max-height: 100%;
  overflow-y: auto;
  padding: 8vh 2em 6vh;
  text-align: center;
  scrollbar-width: thin;
}
/* 三张结局插图（d1a/d1b/d1c）都是室内暖光，压到 .42 之后最亮处还有 107,107,106。
   结局页文字满屏且可滚动 —— 文字会滚过画面任何一处，所以这里必须按「最亮像素」验收，
   不能按中位。压暗前：正文 4.26、电报串 2.35、标题 2.44、成就 2.35。
   纯压暗要 alpha .47 才够，插图会糊成一团黑（它是这一章的情绪落点，不能糊）。
   改成两头凑：小字提亮到 --lamp-hi、电报串抬到 24px 进大字档、再加 .30 的通铺遮罩。
   遮罩是四边通铺的纯色，没有渐变也就没有边 —— 不会像椭圆遮罩那样浮出一个方块。
   验收后（最亮像素处）：正文 6.43、电报串 5.07、标题 5.58、成就 5.07、叠字 6.77。 */
#screen-ending .bg { filter: brightness(.42) saturate(.75); }
#screen-ending::before {
  content: '';
  position: absolute; inset: 0; z-index: 1;
  pointer-events: none;
  background: rgba(20, 17, 14, .30);
}

/* 她收到的那封电报：一串，没有格子 —— 发出去就是一串 */
#ending-telegram {
  font-size: calc(24px * var(--fs));   /* 24px 进 WCAG 大字档（阈值 3.0 而不是 4.5） */
  letter-spacing: .28em;
  color: var(--lamp-hi);
  padding: 18px 0;
  border-top: 1px solid rgba(227, 202, 160, .34);
  border-bottom: 1px solid rgba(227, 202, 160, .34);
  margin-bottom: 26px;
  word-break: break-all;
}
#ending-title {
  font-size: calc(15px * var(--fs));
  letter-spacing: .4em;
  color: #ded6c8;
  margin-bottom: 30px;
}
.ending-line {
  font-size: calc(18px * var(--fs));
  line-height: 2.15;
  color: #ece5d8;
  margin: 12px 0;
  opacity: 0;
  transform: translateY(6px);
  transition: opacity .9s, transform .9s;
  text-shadow: 0 1px 14px rgba(0, 0, 0, .85);
}
.ending-line.in { opacity: 1; transform: none; }

/* 1B 的回电五个字：引擎叠字，一个一个砸出来 */
.stamp {
  display: flex; gap: .5em;
  justify-content: center;
  margin: 34px 0;
}
.stamp span {
  font-size: calc(40px * var(--fs));
  color: #f0ebe1;
  opacity: 0;
  transform: scale(1.6);
  transition: opacity .18s, transform .18s;
  text-shadow: 0 2px 20px rgba(0, 0, 0, .9);
}
.stamp span.in { opacity: 1; transform: none; }

#ending-ach {
  font-size: calc(14px * var(--fs));
  letter-spacing: .2em;
  color: var(--lamp-hi);
  margin: 36px 0 26px;
}
.ending-btns { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; }
#share-canvas {
  display: block;
  width: min(300px, 62vw);
  height: auto;
  margin: 26px auto 0;
  box-shadow: 0 12px 40px rgba(0, 0, 0, .6);
}

/* ---------- DEV 面板：正式版整块删掉 ---------- */
#dev {
  position: fixed; right: 10px; bottom: 10px;
  z-index: 100;
  background: rgba(20, 17, 14, .93);
  border: 1px solid rgba(200, 168, 107, .45);
  padding: 10px 12px;
  font-family: ui-monospace, Consolas, monospace;
  font-size: 12px;
  color: #d8cfbd;
  min-width: 210px;
}
.dev-row { display: flex; gap: 6px; align-items: center; margin: 5px 0; flex-wrap: wrap; }
#dev button {
  font-family: inherit; font-size: 11px;
  background: #2b2724; color: #d8cfbd;
  border: 1px solid rgba(200, 168, 107, .4);
  padding: 3px 7px; cursor: pointer;
}
#dev button:hover { background: rgba(200, 168, 107, .3); }
#dev-readout { color: #8fa89a; font-size: 11px; }

/* ---------- 窄屏：Ch1 是 16:9，竖屏下把纸缩掉 ----------
   格子行宽跟着草稿的断句走，不是等宽栅格 —— Ch1 那 42 个字排成 8/10/5/6/6/7，
   最宽一行 10 格。原来这里写死 38px，10 格 + 9 条 6px 间隙 + 纸的左右内边距 = 474px，
   在 414 宽的手机上左右各切掉 30px，两头那两列字是残的。
   改成按视口反解：38px 当上限，塞不下就让格子缩到刚好放得下最宽那行，留 16px 余量。
   代价是竖屏下 --fs 调到 150% 时格子不再跟着长（物理放不下），字号缩放在横屏是完整的。 */
@media (max-aspect-ratio: 1/1) {
  :root {
    --cell: min(calc(38px * var(--fs)), calc((100vw - 94px) / 10));
  }
  .cell { width: var(--cell); height: var(--cell); }
  .cell .glyph { font-size: min(calc(22px * var(--fs)), calc(var(--cell) * .58)); }
  #paper { padding: 18px 12px; }
  #budget-bar { gap: 1.2em; font-size: calc(13px * var(--fs)); }
}

/* ===== 构建期注入（build.py）=====
   调试面板在公开版永久关闭。bindDev() 的调用已在构建时摘掉，
   这条 CSS 是第二道保险 —— 面板里有「填真解」「折第4行」
   「extend_recall 4min」这类直接给答案或改核心机制的按钮。
   display:none 同时也把它从 tab 顺序和无障碍树里摘掉了。 */
#dev, #devpanel { display: none !important; }
