/* ===========================================================
   world.css  ——  可玩版的场景层
   ------------------------------------------------------------
   叠在 style.css 之上（后者管文本排版与配色，这里管「三栏变成
   一层场景 + 三个可收起的浮层」）。

   几种状态由 body 的类切换：
     .mode-create   建卡：技能栏在左，开场卡居中
     .mode-scene    在走：只有 HUD 和热点，底部没有对话框
     .mode-dialog   在读：对话框从底部升起，热点层隐藏

   三条已知的无头截图坑，这里都避开了：
     · 不用 inset 简写
     · 不用 backdrop-filter
     · 不写「从 opacity:0 开始」的入场动画（浮层会在截图里整个消失）
       —— 需要出现/消失的一律用 transform + display。
   =========================================================== */

/* 左栏宽度提成变量：建卡模式下底部那条提示条要知道「左栏有多宽」，
   才能把自己在「左栏右边那块空地」里居中。写死两个宽度会在窄屏上
   差出几十像素 —— 760px 宽的窗口里提示条左半截会钻到技能栏底下
   （实测在 736×384 下重叠 5258px²，1280×800 下完全看不出来）。 */
:root { --panelw: 328px; }

/* ---------------- 画布：铺满，压在最底层 ---------------- */
body > canvas {
  position: fixed;
  top: 0; left: 0;
  width: 100%; height: 100%;
  display: block;
  z-index: 0;
}
body.dragging { cursor: grabbing; }
/* 俯视第三人称里没有准星了 —— 交互靠点光点/点地面，不是「对准」。
   十字准星光标会暗示一个不存在的瞄准动作。 */
body.mode-scene > canvas { cursor: default; }

/* ---------------- 开机遮罩 ---------------- */
#cover {
  position: fixed; top: 0; left: 0; width: 100%; height: 100%;
  z-index: 90;
  display: flex; align-items: center; justify-content: center;
  background: #06080c;
  transition: opacity .55s ease;
}
#cover.gone { opacity: 0; pointer-events: none; }
.cv-in { text-align: center; }
.cv-t {
  font-family: var(--serif); font-size: 40px; letter-spacing: .34em;
  color: var(--gold); text-indent: .34em;
}
.cv-s { margin-top: 10px; font-family: var(--serif); font-size: 17px; letter-spacing: .5em; color: var(--txt2); text-indent: .5em; }
.cv-bar { margin: 24px auto 0; width: 200px; height: 2px; background: #1b2230; overflow: hidden; }
.cv-bar i { display: block; width: 38%; height: 100%; background: var(--gold); animation: cvslide 1.15s ease-in-out infinite; }
@keyframes cvslide { 0% { transform: translateX(-110%); } 100% { transform: translateX(290%); } }

/* ---------------- HUD ----------------
   底色块不是装饰：开场那个机位正对着发光的店面，纯文字压在亮面上会糊成
   一片（浅灰 12px 字 + 亮绿雨棚 = 读不出来）。给一层近乎不透明的深夜底色，
   顺便和底部升起的对话框呼应。
   注意：无头截图里 backdrop-filter 不可靠，所以用纯色半透明，不写毛玻璃。 */
#hud {
  position: fixed; top: 16px; left: 18px; z-index: 25;
  pointer-events: none;
  font-size: 12px; letter-spacing: .06em;
  padding: 10px 15px 10px;
  border-radius: 10px;
  background: rgba(6, 9, 14, .74);
  border: 1px solid rgba(255, 255, 255, .06);
  border-left: 2px solid rgba(214, 178, 106, .5);
  transition: opacity .18s ease;
}
/* 左栏（技能）打开时，HUD 正好压在它的表头上 —— 收起自己让位。
   位置是同一个角，靠 z-index 硬顶只会把两行字叠在一起。 */
#hud.behind { opacity: 0; }
/* 底部那条操作提示也一样：左栏一开就压在它上面（栏 z-index 32，提示 25）。
   同一个病因，同一个治法。 */
#hint.behind { opacity: 0; }
.hud-region {
  font-family: var(--serif); font-size: 15px; color: var(--txt);
  letter-spacing: .16em;
  text-shadow: 0 1px 10px #000;
}
.hud-detail {
  margin-top: 6px; color: var(--dim);
  text-shadow: 0 1px 8px #000;
}
.hud-detail b { color: var(--gold); font-weight: 600; }

/* 底部操作提示：现在右边多了一条整屏高的常驻栏，提示条必须给它让开。
   不加这条限制，窄窗口下（758px 宽时右栏仍占 303px）提示条的右半截
   会钻到栏底下 —— 又一次「元素在、屏幕上没有」。 */
#hint {
  position: fixed; left: 18px; bottom: 14px; z-index: 25;
  pointer-events: none;
  font-size: 11.5px; color: #98a4b8; letter-spacing: .05em;
  padding: 7px 13px; border-radius: 14px;
  background: rgba(6, 9, 14, .82);
  border: 1px solid rgba(255, 255, 255, .07);
  max-width: min(600px, calc(100vw - 500px));
  line-height: 1.7;
}
body.mode-dialog #hint { display: none; }
/* 建卡模式的提示条也占 left:18px / bottom:14px —— 两条会叠在同一个位置。
   建卡时只留 #hint-create（说怎么开局），走动的那条让位。 */
body.mode-create #hint { display: none; }

/* 建卡模式：提示条放另一个版本，告诉玩家怎么开局。
   不要让这个版本在 scene / dialog 模式出现（会被另一条规则挡住）。 */
/* 建卡时这条要压在建卡卡片和左侧技能栏之上。
   原先跟着 #hint 放在 left:18px / z-index:25，结果整条被 328px 宽的
   技能栏（z-index 32→33）盖掉左边一半，只剩「完成后点下方金色按钮…」
   这半截露在外面。改成底部居中、两行，谁都挡不着。 */
#hint-create {
  /* 在「左栏右边那块空地」里居中，而不是在整个视口里居中 ——
     视口居中在窄屏上会把左半截送到技能栏底下（同一页两块浮层重叠）。 */
  position: fixed;
  left: calc(var(--panelw) + (100% - var(--panelw)) / 2);
  bottom: 18px; transform: translateX(-50%);
  z-index: 41;
  pointer-events: none;
  font-size: 12px; color: #c8b48a; letter-spacing: .08em;
  line-height: 1.7; text-align: center; white-space: normal;
  max-width: calc(100% - var(--panelw) - 40px);
  padding: 9px 20px; border-radius: 12px;
  background: rgba(6, 9, 14, .86);
  border: 1px solid rgba(214, 178, 106, .35);
  display: none;
}
body.mode-create #hint-create { display: block; }

#notice {
  position: fixed; left: 50%; top: 68px; z-index: 45;
  transform: translateX(-50%);
  display: none;
  padding: 9px 18px; border-radius: 20px;
  background: rgba(14,18,27,.94);
  border: 1px solid var(--line2);
  color: var(--txt2); font-size: 13px;
}
#notice.show { display: block; }

/* ---------------- 热点标记 ----------------
   圆点 = 本来就有的东西；菱形 = 因为你在这项技能上看得多，才多出来的东西。 */
#marks {
  position: fixed; top: 0; left: 0; width: 100%; height: 100%;
  z-index: 20;
  pointer-events: none;
  overflow: hidden;
}
.mark {
  position: absolute; top: 0; left: 0;
  display: flex; align-items: center; gap: 8px;
  pointer-events: auto; cursor: pointer;
  padding: 4px;
  white-space: nowrap;
}
.mark.hidden { display: none; }

.mk-dot {
  flex: none;
  width: 12px; height: 12px; border-radius: 50%;
  background: #ffd9a0;
  border: 1px solid rgba(255,246,230,.55);
  box-shadow: 0 0 12px rgba(255,185,94,.85), 0 0 4px rgba(255,255,255,.5);
}
.mark-detail .mk-dot {
  width: 9px; height: 9px; border-radius: 2px;
  transform: rotate(45deg);
  background: #9df0e2;
  border-color: rgba(220,255,250,.6);
  box-shadow: 0 0 12px rgba(70,201,180,.9), 0 0 4px rgba(255,255,255,.4);
}

.mk-label {
  font-size: 12.5px; letter-spacing: .06em;
  color: #e7ecf3;
  padding: 3px 9px;
  border-radius: 3px;
  background: rgba(10,13,19,.72);
  border-left: 2px solid rgba(255,190,110,.75);
  text-shadow: 0 1px 6px #000;
}
.mark-detail .mk-label { border-left-color: rgba(110,230,208,.85); }

/* 够不着：只留一个小点，不给名字 —— 「那边有东西」和「我能碰它」是两回事 */
.mark.far { cursor: default; }
.mark.far .mk-dot { transform: scale(.62); box-shadow: 0 0 8px rgba(255,185,94,.55); }
.mark-detail.far .mk-dot { transform: rotate(45deg) scale(.62); }
.mark.far .mk-label { display: none; }
/* 准星指着它，但还没走近：报名字，只是压暗一点 */
.mark.aim.far .mk-label { display: block; opacity: .72; }
.mark-need, .mk-need { display: none; }

.mark.near:hover .mk-dot,
.mark.near.hover .mk-dot { transform: scale(1.5); }
.mark-detail.near:hover .mk-dot,
.mark-detail.near.hover .mk-dot { transform: rotate(45deg) scale(1.5); }
.mark.near:hover .mk-label,
.mark.near.hover .mk-label { background: rgba(22,28,40,.94); }

/* ---------------- 左栏：技能（可收起） ---------------- */
#panel {
  position: fixed; top: 0; left: 0; bottom: 0;
  width: var(--panelw); z-index: 32;
  overflow-y: auto;
  background: linear-gradient(180deg, #0c1018, #090c12);
  border-right: 1px solid var(--line);
  padding: 16px 14px 40px;
  display: none;
}
body.mode-create #panel { display: block; }
body.mode-scene #panel.open,
body.mode-dialog #panel.open { display: block; }

/* ---------------- 左栏之二：状态 / 想法 / 日志（可收起） ----------------
   原来贴在右边（350px），但右边现在归常驻文字栏了。挪到左边与技能栏
   同侧，并靠 60_loop.js 的 toggle() 保证两块互斥 —— 两块同宽的浮层
   叠在同一个位置只会变成一坨。 */
#side {
  position: fixed; top: 0; left: 0; bottom: 0;
  width: 340px; z-index: 32;
  overflow-y: auto;
  background: linear-gradient(180deg, #0c1018, #090c12);
  border-right: 1px solid var(--line);
  padding: 16px 14px 40px;
  display: none;
}
body.mode-create #side.open,
body.mode-scene #side.open,
body.mode-dialog #side.open { display: block; }

/* ---------------- 右侧常驻文字栏（极乐迪斯科式） ----------------
   对话不再「从底部升起、走开就消失」，而是占住右边一条，走路时也在：
   左边是空间，右边是文字 —— 「我在哪」和「我在想什么」同时可见。
   底部的对话框做不到这件事：它一升起就把下半屏的地面全盖掉，
   而俯视视角里地面恰恰是信息量最大的地方。

   ⚠ 这一条会盖住 #marks（z-index 20 < 40）。场景模式下栏里列着
   「附近够得着的东西」，是同一批热点的第二个入口，所以不会出现
   「有个热点被栏压住、点不到」的死角。改栏宽时记得同步
   00_core.js 的 SB.CAM.lensX（镜头平移量），否则角色会被压到栏下。 */
#stage {
  position: fixed; top: 0; right: 0; bottom: 0;
  /* 40vw 是「跟窗口成比例」，但窄屏上不能低于 300px —— 再窄就放不下
     一行正文，栏会变成一条谁都读不了的缝。 */
  width: max(300px, min(430px, 40vw));
  z-index: 40;
  display: none;
  overflow-y: auto;
  background: linear-gradient(90deg, rgba(11,14,21,.88), rgba(8,10,15,.985));
  border-left: 1px solid var(--line2);
  box-shadow: -22px 0 60px rgba(0,0,0,.55);
  padding: 24px 26px 32px;
  scrollbar-width: thin;
}
body.mode-scene #stage,
body.mode-dialog #stage { display: block; }

/* ---- 走路时右栏的待机内容：我在哪 / 附近能碰什么 / 怎么操作 ---- */
.idle-head {
  font-family: var(--serif); font-size: 19px; letter-spacing: .14em;
  color: var(--txt);
}
.idle-sub { margin-top: 7px; font-size: 12px; color: var(--dim); letter-spacing: .06em; }
.idle-list { margin-top: 16px; }
#stage .choice.idle-i {
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
  width: 100%; text-align: left; margin: 0 0 7px;
  padding: 11px 14px;
  background: rgba(255,255,255,.03);
  border: 1px solid rgba(255,255,255,.07);
  border-left: 3px solid rgba(255,190,110,.6);
  border-radius: 4px;
  color: var(--txt2); font-size: 13.5px; letter-spacing: .06em;
}
#stage .choice.idle-i:hover { background: rgba(214,178,106,.10); color: #f1dcab; border-color: rgba(214,178,106,.5); }
#stage .choice.idle-detail { border-left-color: rgba(110,230,208,.7); }
#stage .choice.idle-detail .i-name { color: #9df0e2; }
.idle-i .i-dist {
  flex: none; font-family: var(--serif); font-size: 11.5px; color: var(--dim);
}
.idle-hint {
  margin-top: 20px; padding-top: 14px;
  border-top: 1px solid rgba(255,255,255,.07);
  font-size: 11px; line-height: 1.9; color: #7f8a9c; letter-spacing: .05em;
}
.idle-empty { margin-top: 16px; font-size: 12.5px; color: var(--dim); line-height: 1.85; }

/* 建卡时：#stage 变成一张居中的卡，两侧都不压满。
   ⚠ 必须显式写 display: block —— #stage 的基础规则是 display: none，
   只有 mode-dialog 那一条给了 block。少这一行的话，整张建卡卡片
   （连同「开始」按钮）都不会渲染，玩家打开页面看到的只有左侧技能表
   和场景，找不到任何入口 —— 表现就是「无法操控」。 */
body.mode-create #stage {
  display: block;
  left: 50%; right: auto;
  /* 结构性约束，而不是「预留多少像素」：
     卡片被夹在「视口顶端 → 提示条上边」这条带子里，再用 auto 外边距
     在带子里居中。预留像素那套（先写 84vh-76px、再改 92px）永远在赌
     提示条会不会折行 —— 实测 736×384 下提示条折成三行，卡片底边就
     压了上去，而 1280×800 完全正常。现在重叠在几何上不可能发生。 */
  top: 0; bottom: 116px;
  margin: auto 0;
  width: min(700px, 88vw);
  max-height: calc(100vh - 124px);
  overflow-y: auto;
  transform: translateX(-50%);
  border: 1px solid var(--line2);
  border-radius: 10px;
  box-shadow: 0 30px 80px rgba(0,0,0,.7);
  padding: 26px 30px 28px;
}
body.mode-create #panel { z-index: 33; }

/* 关闭全部面板后的提示 */
.col::after { content: none; }

/* 对话框里的选项按钮：宽度收在同一条轴上，不要横跨整个屏幕 */
#stage .choice { display: block; width: 100%; text-align: left; }

/* 入场门：建卡面板的「开始」按钮，必须比任何选项都显眼 */
#stage .choice.begin-cta {
  margin-top: 26px;
  padding: 16px 22px;
  font-size: 15px;
  letter-spacing: .10em;
  text-align: center;
  border: 1px solid var(--gold);
  border-left: 3px solid var(--gold);
  color: var(--gold);
  background: rgba(214, 178, 106, .06);
  position: relative;
}
#stage .choice.begin-cta::before {
  content: '›';
  margin-right: 10px;
  font-size: 18px;
  opacity: .7;
}
#stage .choice.begin-cta:hover {
  background: rgba(214, 178, 106, .14);
  color: #f1dcab;
  border-color: #f1dcab;
}
#stage .choice.begin-cta .kbd-hint {
  display: block;
  margin-top: 6px;
  font-size: 10.5px;
  letter-spacing: .22em;
  color: var(--dim);
  font-weight: normal;
}

/* 「回到街面」是出口，不是剧情选项——但它是「真正进入游戏」的门，
   不能做得太虚。给它一点存在感，加一行简短提示。 */
#stage .choice.back-scene {
  margin-top: 18px;
  padding: 12px 18px;
  background: transparent;
  border: 1px solid var(--line2);
  border-left: 3px solid var(--gold);
  color: var(--txt2);
  text-align: center;
  font-size: 13px;
  letter-spacing: .18em;
}
#stage .choice.back-scene .kbd-hint {
  display: block;
  margin-top: 4px;
  font-size: 10.5px;
  letter-spacing: .20em;
  color: var(--dim);
  font-weight: normal;
}
#stage .choice.back-scene:hover { color: #f1dcab; border-color: #f1dcab; }

/* ---------------- 检定浮层压在对话框之上 ---------------- */
#overlay { z-index: 60; }
#toast { z-index: 70; }

/* ---------------- 窄屏 ---------------- */
@media (max-width: 980px) {
  :root { --panelw: 280px; }
  #side { width: 300px; }
  /* 窄屏上右栏最多占 46%，再多就没有场景可看了 */
  #stage { width: max(300px, min(360px, 46vw)); padding-left: 20px; padding-right: 20px; }
  #hint { font-size: 10.5px; }
}

/* ===========================================================
   触摸与手机横屏
   ------------------------------------------------------------
   判定写在 JS 里（body.ux-phone / ux-touch / ux-portrait，见 55_ux.js
   与 00_core.js 的 uxDetect），这里**不写媒体查询**。
   理由是实测出来的：844×390 的手机横屏比不少桌面窗口还宽，
   「按宽度写断点」必然把手机认成桌面、把被拉扁的桌面窗口认成手机 ——
   两者要的布局恰好相反（前者要窄栏大字，后者就是桌面那套）。

   桌面那份规则一个字节都没改：下面每条都挂在 body.ux-phone 之下。
   =========================================================== */

/* ---- 手势：不要让浏览器把游戏手势抢走 ----
   画布上的一切手势都是输入：按住 = 转视角，点一下 = 走过去。
   不写 touch-action: none 的话，手机上按住一拖就变成滚页面 / 下拉刷新，
   玩家会觉得「视角根本转不动」——而且控制台一声不响，没有任何线索。
   文字区（左右栏与常驻文字栏）反过来要保留滚动：那是阅读区，不是游戏区。 */
html { -webkit-text-size-adjust: 100%; }
html, body { overscroll-behavior: none; }
body > canvas {
  touch-action: none;
  -webkit-user-select: none; user-select: none;
  -webkit-tap-highlight-color: transparent;
}
#panel, #side, #stage { touch-action: pan-y; -webkit-overflow-scrolling: touch; }

/* ---- 手机横屏：两个宽度变量 ----
   --panelw 左栏（技能 / 状态），--colw 右侧常驻文字栏。
   提成变量是为了让「卡片居中于左栏右边那块空地」与「提示条别钻到右栏底下」
   两处算术共用同一个数 —— 写死两个宽度，在 780 与 844 两档下会各错一次。 */
body.ux-phone {
  --panelw: max(268px, min(300px, 38vw));
  --colw: max(288px, min(320px, 34vw));
}
/* 右栏下限 288px 不是随手取的：自检那条「右栏够宽」要求 > 280，
   而 34vw 在 780px 宽的窗口下只有 265px —— 没有这个下限，
   同一份样式在 844 上过、在 780 上挂，且挂的是一条布局断言，很难归因。 */
body.ux-phone #stage {
  width: var(--colw);
  padding: 18px 20px calc(24px + env(safe-area-inset-bottom));
  padding-right: calc(20px + env(safe-area-inset-right));
}
body.ux-phone #panel,
body.ux-phone #side {
  width: var(--panelw);
  padding: 14px 12px calc(28px + env(safe-area-inset-bottom));
  padding-left: calc(12px + env(safe-area-inset-left));
  box-shadow: 18px 0 44px rgba(0, 0, 0, .5);
}
/* 刘海与圆角：横屏时缺口在左右两侧，贴边的东西都要让开。
   没写 safe-area 的话，HUD 的「马路上」正好印在缺口上。 */
body.ux-phone #hud {
  top: calc(10px + env(safe-area-inset-top));
  left: calc(10px + env(safe-area-inset-left));
  font-size: 11px; padding: 8px 12px 8px;
}
/* 提示条与右栏都贴底，是这一页最容易撞的一对。
   上限直接由 --colw 推出来：右栏左边缘 = 100vw − --colw，
   提示条左边缘 18px，中间留 8px 缝。 */
body.ux-phone #hint {
  left: calc(10px + env(safe-area-inset-left));
  bottom: calc(8px + env(safe-area-inset-bottom));
  font-size: 10.5px;
  max-width: calc(100vw - var(--colw) - 26px);
  line-height: 1.6;
}
body.ux-phone #hint-create {
  bottom: calc(8px + env(safe-area-inset-bottom));
  font-size: 11.5px; padding: 7px 14px;
}

/* ---- 手机上的建卡：卡片居中于「左栏右边」，入口按钮钉在卡片底部 ---- */
body.ux-phone.mode-create #stage {
  left: calc(var(--panelw) + (100% - var(--panelw)) / 2);
  width: min(720px, calc(100% - var(--panelw) - 28px));
  top: 0; bottom: calc(92px + env(safe-area-inset-bottom));
  max-height: calc(100vh - 100px - env(safe-area-inset-bottom));
  padding: 16px 20px 18px;
  font-size: 13px;
}
/* ⚠ 入口按钮必须留在视野里。横屏只有 360~430px 高，装不下这张卡的全部
   正文，卡片会滚动 —— 而「走进去」是**唯一的入口**，被折到屏幕外就等于
   「打开网页后无法操控」。sticky + 近乎不透明的底把它钉在卡片下沿，
   正文从它后面滚过去。自检那条断言量的是「按钮矩形落在卡片可见矩形里」，
   而不是「按钮存在」——后者对滚动容器里的按钮永远为真。 */
body.ux-phone.mode-create #stage .choice.begin-cta {
  position: sticky; bottom: 0;
  margin-top: 18px;
  background: linear-gradient(180deg, rgba(13, 17, 25, .88), #0d1119 38%);
}

/* ---- 左侧工具条 ----
   手机上 Tab / L / M / N 四个开关本来只挂在键盘上，等于没有。
   做成 2×2 的小方块贴在左边缘中段：横屏时左手拇指够得到，
   又避开了上面（HUD）和下面（提示条）两条贴着边的浮层。
   z-index 高于 #panel/#side(32) 与 #stage(40)：面板开着的时候
   它必须留在最上面，否则「打开了关不掉」。 */
#tools { display: none; }
body.ux-phone #tools {
  display: grid;
  position: fixed;
  left: calc(6px + env(safe-area-inset-left));
  top: 50%;
  transform: translateY(-50%);
  grid-template-columns: 44px 44px;
  gap: 8px;
  z-index: 47;
}
/* 建卡那屏左边本来就是技能栏、中间是卡片，工具条只会碍事 */
body.ux-phone.mode-create #tools { display: none; }
body.ux-phone #tools .ux-tool {
  width: 44px; height: 38px;
  display: flex; align-items: center; justify-content: center;
  font-family: var(--serif); font-size: 15px; letter-spacing: .04em;
  color: #b9c4d4;
  background: rgba(9, 13, 20, .84);
  border: 1px solid rgba(255, 255, 255, .12);
  border-radius: 7px;
  padding: 0;
  -webkit-appearance: none; appearance: none;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}
body.ux-phone #tools .ux-tool.on {
  color: #f1dcab;
  border-color: rgba(214, 178, 106, .75);
  background: rgba(48, 38, 18, .9);
}

/* ---- 竖屏：不支持态，铺满屏幕请你转过来 ----
   这套布局是按横屏排的。390px 宽的竖屏装不下「左栏 268 + 右栏 288」，
   两栏必然叠成一坨 —— 所以竖屏不做布局（用户明确只要横屏）。
   但「不做布局」不等于「把一坨重叠的界面亮给用户」，那是打开即坏的第一
   印象。做法是拿一块**铺满全屏**的提示把它盖住：底下的场景照旧在跑，
   转过来立刻就是游戏，只是竖着的时候看不见。
   ⚠ 这块必须铺满，不能只做一条顶部小横幅 —— 小横幅时代底下那两栏是
   露着的，用户先看到的就是重叠；自检里那两条「两栏不重叠」的断言在
   390px 竖屏下直接 FAIL（重叠 74272px²）。盖满之后问题才真正消失。
   ⚠ 刻意不用 backdrop-filter：全屏模糊正好吃掉我们刚为手机省下的帧，
   同一件事上不能一边降画质一边加全屏合成层。半透明底色够了。
   pointer-events: none 也是刻意的：判定是「指针粗细 + 短边」，触屏笔记本
   或被拉成竖条的窗口可能命中；不吃事件的话用户至少还能操作底下那层，
   不至于彻底锁死。 */
#rotate {
  position: fixed; inset: 0;
  z-index: 66;                    /* 高于 #overlay(60)，低于 #toast(70) */
  display: none;
  flex-direction: column; align-items: center; justify-content: center;
  gap: 12px; padding: 24px; text-align: center;
  pointer-events: none;
  background: radial-gradient(125% 95% at 50% 42%, rgba(11, 15, 22, .90), rgba(4, 6, 10, .975));
  color: var(--txt2); font-size: 13px; line-height: 1.75;
}
#rotate.show { display: flex; }
#rotate .rot-ico {
  display: block; font-size: 40px; line-height: 1;
  color: var(--gold); opacity: .9;
}
#rotate b { display: block; color: var(--gold); font-size: 15px; letter-spacing: .16em; }
#rotate span { display: block; color: var(--dim); max-width: min(86vw, 360px); }

/* ---- 触摸目标 ----
   .mark 是手机上唯一的「点一下」目标，而默认那圈只有 4px padding：
   圆点 12px + 4×2 = 20px 的可点区域，手指按不准。
   ⚠ 这里必须**对称**加 padding。.mark 是靠 transform: translate(-50%,-50%)
   居中在投影点上的，左右各加同样的量时圆点相对投影点的位置一个像素都不动；
   只加左边就会让圆点整体偏出热点本身（这种偏移在截图里看不出来，
   越走越偏才被发现）。 */
body.ux-phone .mark { padding: 11px; }
body.ux-phone .mk-label { font-size: 12px; }

