:root{
    --bg:#0d1b2a; --panel:#1b263b; --panel2:#223049;
    --text:#f0f4f8; --muted:#aab8cc;
    --accent:#4dabf7; --accent2:#74c0fc;
    --good:#51cf66; --warn:#fcc419; --danger:#ff6b6b;
    --focus:#ffd43b;
  }
  *{box-sizing:border-box;}
  html,body{margin:0;padding:0;}
  body{background:var(--bg);color:var(--text);font-family:"Microsoft YaHei","PingFang SC",system-ui,sans-serif;font-size:18px;line-height:1.6;}
  .hidden{display:none!important;}

  header.topbar{position:sticky;top:0;z-index:50;background:var(--panel);border-bottom:2px solid var(--accent);padding:10px 16px;display:flex;flex-wrap:wrap;gap:10px;align-items:center;}
  header.topbar .status{display:flex;flex-wrap:wrap;gap:8px 16px;margin-left:auto;align-items:center;}
  .badge{background:var(--panel2);padding:4px 10px;border-radius:20px;font-size:16px;}
  .badge b{color:var(--accent2);}
  .gold{color:var(--warn);font-weight:bold;}

  nav.tabs{display:flex;gap:8px;padding:10px 16px;flex-wrap:wrap;background:var(--panel2);}
  nav.tabs button{background:var(--panel);color:var(--text);border:2px solid transparent;font-size:18px;padding:10px 18px;border-radius:10px;cursor:pointer;}
  nav.tabs button:hover{border-color:var(--accent);}
  nav.tabs button[aria-selected="true"]{background:var(--accent);color:#0d1b2a;font-weight:bold;}

  /* ===== 二级/三级卡片 = <a class="plink">（2026-10-05）=====
     为什么从 <button role="tab"> 改成真链接：
       ① tab/tabpanel 语义要求「一组页签共享一个 tablist」，而本站是**最多三级的树**
          （页签 › 子页面 › 孙页面）。三层各自是 tablist 时，读屏念出来的是三个互不相关的
         「第 N 个，共 M 个」，用户听不出自己在一级还是三级。
       ② 链接能表达「这是一个可以去的地方」：可复制、可新标签打开、可被浏览器历史记录，
          点错了能后退。按钮三样都做不到。
     ⚠ **一级页签仍是 <button role="tab">**（nav.tabs 那组）：顶栏是真正的 tablist，
       子面板的 role 也还是 tabpanel。这条界线不能糊，一糊 Alt+1~5 与读屏的页签语义一起坏。
     ⚠ .plink 必须自己写出 color / text-decoration / cursor —— 浏览器给 <a> 的默认样式
       （蓝字 + 下划线 + 手型光标）会把卡片区的可点性提示全丢掉。 */
  .subtabs{display:flex;gap:8px;flex-wrap:wrap;margin-top:10px;}
  .subtabs .plink{
    display:inline-block;background:var(--panel2);color:var(--text);text-decoration:none;
    border:2px solid transparent;font-size:16px;padding:8px 16px;border-radius:8px;cursor:pointer;
  }
  .subtabs .plink:hover{border-color:var(--accent2);}
  .subtabs .plink[aria-current="page"]{background:var(--accent2);color:#0d1b2a;font-weight:bold;}
  /* 焦点框：链接默认有，但样式被上面的 border 覆盖过一次，这里显式给足对比度 */
  .subtabs .plink:focus-visible{outline:3px solid var(--focus);outline-offset:2px;}

  /* ===== 一级页 → 子页面（层级门户）=====
     每个一级页点开后**先只列出子页面卡片**（名字 + 一句说明），点进某张卡片才出现它的功能表单。
     门户态 / 进入态由根 <section> 上的 .entered 类区分，显示与否交给 CSS，JS 只负责加类 ——
     两边都管显示的话，JS 把面板设成可见、CSS 又判 .entered 关掉，就会出现「点了没反应」。
     ⚠ 这条 `[role="tabpanel"]` 是**后代**选择器。2026-10-02 起层级到了**三级**
       （页签 → 子页面 → 孙页面，例如 个人中心 › 帮助 › 键盘快捷键），
       所以规则从「写死了 section 标签的那个版本」放宽成 `.hier`：谁带 .hier，谁就管自己那一层的
       「门户态藏内容」。外层 .entered 不替内层做决定，内层也不替外层做。
       反面例子：选择器写成带 section 标签的版本时，嵌在里面的 `div.hier` **整个失效** ——
       点「帮助」后 7 个章节卡片会一直摊在下面，进某一章也看不出任何变化。 */
  .hier:not(.entered) [role="tabpanel"],
  .hier:not(.entered) [role="region"]{display:none;}

  .hier .subbar{display:flex;flex-wrap:wrap;gap:12px;align-items:center;margin:10px 0 2px;padding:8px 0;border-bottom:1px solid var(--panel2);}
  /* 门户态没有「当前位置」可返回，返回栏整条不出现（用 :not 显式关掉，别只靠 JS） */
  .hier:not(.entered) .subbar{display:none;}
  .crumb{font-size:15px;color:var(--muted);}
  .crumb b{color:var(--accent2);}

  /* 门户态：卡片网格（整块可点，名字大字 + 说明小字） */
  .hier:not(.entered) .subtabs{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:12px;margin-top:14px;}
  .hier:not(.entered) .subtabs .plink{
    display:flex;flex-direction:column;align-items:flex-start;gap:4px;text-align:left;
    padding:14px 16px;border-radius:12px;font-size:18px;line-height:1.4;min-height:76px;
    border:2px solid var(--muted);
  }
  .hier:not(.entered) .subtabs .plink:hover{border-color:var(--accent2);}
  /* 2026-10-27 用户诉求：入口卡片列表要「一目了然」，不再单独高亮某一张「默认项」。
     （原先用 accent 描边标默认卡；现在家园/个人中心都停在列表层，高亮反而像「已选中」。）
     这里把门户态的 aria-current 卡还原成与普通卡一致：同底色、同文字色、不加粗、灰描边。 */
  .hier:not(.entered) .subtabs .plink[aria-current="page"]{background:var(--panel2);color:var(--text);font-weight:normal;}

  .pname{font-weight:bold;font-size:18px;}
  .pdesc{font-size:14px;font-weight:normal;color:var(--muted);line-height:1.45;}

  /* ===== 进入态：上一层内容**全部隐藏**（2026-10-06 用户诉求②）=====
   原设计是「把卡片压成一条紧凑切换条」（.subtabs 仍display，上面的 plink 变小）。
   用户要的是「进入二级页面后，上一层内容全部隐藏，只保留新页面内容和返回上一级」。

   🚨 为什么不能直接 `display:none` 掉 .subtabs：
      集市的子页面有 4 个（我要出售 / 在售商品 / 求购需求 / 我的单据）。
      卡片区一藏，玩家进「我要出售」后就**没有任何办法去「我的单据」**——
      只能先点「返回家园」退回门户、再点别的卡、再进来，一来一回三次点击。
      所以这里改成：卡片区整块隐藏，改在**返回栏里**放一个「切换子页面」下拉，
      一个控件同时满足「上一层不外露」+「还能横向跳」（诉求②原话：
      「就保持新页面内容和返回上一级」—— 返回条本身就是那个出口）。
   ⚠ 下拉的可见性必须跟 .entered 走：门户态时它是多余的（卡片区就在眼前），
      所以只在 .entered 下 display。 */
  .hier.entered .subtabs{display:none;}
  .hier.entered .pdesc{display:none;}

  /* 进入子页面后，分组标题与「门户态概况行」一起收起（2026-10-09 用户诉求①）。
     门户态显示的是归属与身份概况（「家园」+「阳光村 · 1 级 · 我的职位…土地/账户/税率」、
     「个人中心」+「用户名/等级经验/财富」）；进了某个子页面之后，它既占屏幕
     又占读屏时间，而**面包屑已经写着「家园 › 游乐场」**，返回栏也还在 —— 那段概况是纯重复。
     ⚠ 只收「门户态概况」，**绝不收操作读数**。同样是门户态头部里的元素，
       集市 #marketSummary（随身宠币 / 交易税率 / 还能挂几单）、合作小铺 #coopHead
       （今日种子与化肥额度）、银行 #goldHere / #balance（随身与银行余额）、
       外村横幅 #venueBanner（费用按消费地算）都是**当前子页面的操作依据**，
       跟着一起藏就等于把数据搬走了。所以这里按**逐个元素**打标记类，
       而不是按「整块 .panel」隐藏 —— 与「.row 的边界就是语义边界」同一条纪律。
     ⚠ 标记类 + .entered 的纯 CSS 联动，与上面那条 .subtabs 同一套机制：
       JS 里漏调一次就会留下「标题还在、卡片没了」这种半隐半显状态，CSS 是原子的。
     ⚠ 别把 #venueBanner 收进去：它是 role="status" 活动区，display:none 会连带
       把它从无障碍树里摘掉，外村玩家就再也听不到「价格按月亮村算」了。 */
  .hier.entered .portalonly{display:none;}
  /* 🚨 嵌套门户的补丁 —— 与上面 `.subtabs` / `.pdesc` 那两条**同一套**，缺一不可。
     为什么必须补：` .hier.entered .portalonly` 是**后代**选择器，
     外层分组一 entered，就会把**里层门户**的 portalonly 也一起收掉。
     而里层门户（家园 › 宠物店 / 军队 / 房产 / 村子）在它自己的**卡片列表态**，
     正是需要这行标题与说明的时候 —— 2026-10-09 实测踩到：
     点开「军队」卡后 `#vpanel-army h2` 的 computed display 直接是 none，
     整块头部凭空消失（页面上看着像「这一页没有标题」）。
     补一条**更具体**的规则把它放回来（5 个类 > 2 个类，必然胜出）。
     ⚠ display 值只能是 block：本项目打 portalonly 的只有 <h2> 与 <p>，两者都是 block；
       将来若有行内元素要打这个标记，必须改成对应的行内值，否则会改变布局。 */
  .hier.entered .hier:not(.entered) .portalonly{display:block;}

  /* 进入态的返回栏里那个「切换子页面」下拉 —— 卡片区藏起来之后的横向出口 */
  .hier .subjump{display:none;}
  .hier.entered .subjump{display:inline-block;margin-left:auto;}
  .hier.entered .subjump select{max-width:220px;}

  /* ===== 三级嵌套的补丁（2026-10-02 建立，2026-10-06 随进入态改动重写）=====
     外层一旦进入态，上面的**后代**规则会顺手打到「里层仍处在门户态」的卡片上：
       · `.hier.entered .subtabs{display:none}` → 里层门户的卡片整块消失。
         这是最严重的一条：**用户点「集市」→ 进「我要出售」→ 里层「我的单据」那组卡没了**，
         症状是「明明有 4 个子页面却只剩 1 个能点」，不报任何错，静态守卫也看不出来。
       · `.hier.entered .pdesc{display:none}` → 里层门户的卡片只剩名字，说明行整批消失。
     用更高优先级的规则把里层门户态显式还原回来。
     ⚠ 还原的第一条必须是 display:grid（**不是 margin-top**）——
        旧版进入态是「压成紧凑条」，subtabs 一直有 display，所以补丁只需复位 margin；
        现在进入态是整块 display:none，补丁不复位 display 的话里层卡片就真的丢了。 */
  .hier.entered .hier:not(.entered) .subtabs{
    display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:12px;margin-top:14px;}
  .hier.entered .hier:not(.entered) .pdesc{display:block;}
  .hier.entered .hier:not(.entered) .subtabs .plink{padding:14px 16px;border-radius:12px;min-height:76px;}

  /* 嵌套门户（第三级）的返回栏**两种状态都要显示**（HTML 里给 .subbar 加 alwaysbar）。
     它是唯一的「回上一级」出口：按门户态一律 display:none 的话，用户点进「帮助」
     看到 7 张章节卡片后就卡在那儿出不来了 —— 顶栏已经没有「帮助」页签可点。
     注意选择器要比上面那条 `.hier:not(.entered) .subbar` 多一个类才盖得住。 */
  .hier:not(.entered) .subbar.alwaysbar{display:flex;}

  main{padding:16px;max-width:1000px;margin:0 auto;}
  section[role="tabpanel"]{display:none;}
  section[role="tabpanel"].active{display:block;}

  .panel{background:var(--panel);border-radius:14px;padding:16px;margin-bottom:16px;}
  .panel h2{margin:0 0 12px;font-size:20px;border-left:5px solid var(--accent);padding-left:10px;}
  .panel h3{margin:0 0 8px;font-size:18px;color:var(--accent2);}

  button.btn{background:var(--accent);color:#0d1b2a;border:none;font-size:17px;padding:10px 16px;border-radius:8px;cursor:pointer;font-weight:bold;}
  button.btn:hover{background:var(--accent2);}
  button.btn.secondary{background:var(--panel2);color:var(--text);border:1px solid var(--accent);}
  /* 对比度修复：白字 #fff 放在 --danger(#ff6b6b) 上只有约 2.8:1，
     而按钮文字是 17px 粗体，未达「大字」门槛（需 18.66px 粗体以上），必须满足 4.5:1。
     这些恰恰是最重要的破坏性按钮（投票、删除账号、自爆、离开牌桌）。
     改用与 .btn.good 一致的深色文字 #0d1b2a，实测约 6.4:1，同时保持「危险=红底」的视觉语义。 */
  button.btn.danger{background:var(--danger);color:#0d1b2a;}
  button.btn.good{background:var(--good);color:#0d1b2a;}
  button:focus-visible,input:focus-visible,select:focus-visible{outline:3px solid var(--focus);outline-offset:2px;}

  input,select{font-size:18px;padding:8px 10px;border-radius:8px;border:1px solid var(--muted);background:var(--panel2);color:var(--text);}
  label{display:block;margin:8px 0 4px;}

  /* 2026-10-12 用户诉求②：`.plots` / `.plot`（含 .rowlab / .crop / .stage / .bar）
     那一整段样式**已删除** —— 地块网格换成了 #plotSelect 组合框（见 index.html 里
     #plotSelect 的注释）。§61：删控件必须连样式一起删；留着一堆没有宿主的规则，
     下次改动会有人以为「这块网格还在」。 */

  .attrs{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:10px;}
  .attr{background:var(--panel2);border-radius:10px;padding:10px;}
  .attr .name{color:var(--muted);font-size:15px;}
  .attr .val{font-size:22px;font-weight:bold;}
  .attr .bar{height:10px;background:#0d1b2a;border-radius:5px;margin-top:6px;overflow:hidden;}
  .attr .bar span{display:block;height:100%;}

  .lvlbar{height:14px;background:#0d1b2a;border-radius:7px;overflow:hidden;margin:6px 0;}
  .lvlbar span{display:block;height:100%;background:var(--accent);width:0;transition:width .3s;}

  table{width:100%;border-collapse:collapse;margin-top:10px;}
  th,td{border:1px solid var(--muted);padding:8px;text-align:left;vertical-align:middle;}
  th{background:var(--panel2);}

  #announce, #announceUrgent{position:fixed;left:-9999px;top:0;width:1px;height:1px;overflow:hidden;}
  /* 2026-10-08 用户诉求②：可视播报区（.speakbox）已整块删除。
     #lastSpeech 保留为**屏外探针** —— 3 个真机脚本靠它判「系统有反馈」，
     节点不能删（删了那些判据会静默恒假红），但屏幕上不许出现任何东西。
     写法与 #announce 同款：固定到视口外、1px 见方。
     🚨 刻意不加 aria-live / role：真正驱动朗读的是 #announce / #announceUrgent，
        这里再来一条等于让读屏把每句话念两遍。 */
  .offscreen{position:fixed;left:-9999px;top:0;width:1px;height:1px;overflow:hidden;}
  .history{font-size:15px;color:var(--muted);margin-top:8px;}
  .history li{margin:2px 0;}

  .row{display:flex;flex-wrap:wrap;gap:10px;align-items:center;margin:8px 0;}
  /* 「标签 + 控件」组合。包起来才能保证 flex 换行时两者不被拆开
     （否则会出现 label 留在行尾、控件甩到下一行的错位）。 */
  .fld{display:inline-flex;align-items:center;gap:6px;white-space:nowrap;}
  .fld>label{margin:0;}
  .small{font-size:14px;color:var(--muted);}

  /* ===== 折叠区块：让长规则、单人口、设置类内容默认收起，页面更清爽 ===== */
  details.fold{background:var(--panel);border-radius:14px;padding:12px 16px;margin-bottom:16px;}
  details.fold>summary{cursor:pointer;font-size:18px;font-weight:bold;color:var(--accent2);padding:4px 0;border-radius:6px;}
  details.fold>summary:focus-visible{outline:3px solid var(--focus);outline-offset:2px;}
  details.fold[open]>summary{margin-bottom:10px;border-bottom:1px solid var(--panel2);padding-bottom:8px;}
  details.fold>p,details.fold>ul,details.fold>ol{margin-top:8px;}
  details.fold h3{margin-top:16px;}
  details.fold h3:first-of-type{margin-top:4px;}

  /* ===== 对局「行动聚焦」区（2026-10-07，用户诉求②）=====
     轮到我行动时，参考信息（存活名单/ 座位表 / 发言记录 / 狼队语音 / 自爆）
     收进这个 <details>。三点要求：
       ① 它是**折叠**不是 display:none —— 内容仍在 DOM 里、点一下summary 就能看到。
          本项目禁止「用隐藏减功能」，折叠是唯一既能减 Tab 站位又不砍功能的手段
          （collapsed <details> 的后代不进顺序焦点导航）。
       ② 视觉上要一眼看出「这是可选的参考，不是当前要做的操作」——
          边框用弱化色、标题色继承面板色，与操作区（按钮高亮）明确区分。
       ③ 内容区加左内缩进，让人看得出「这里面是次级信息」。 */
  details.fold.pg-fold{border:1px dashed var(--panel2);background:transparent;padding:8px 14px;}
  details.fold.pg-fold>summary{font-size:16px;font-weight:normal;color:var(--muted);opacity:.85;}
  details.fold.pg-fold>summary::marker{color:var(--muted);}
  details.fold.pg-fold>summary:hover{opacity:1;}
  details.fold.pg-fold .foldbody{margin-top:8px;padding-left:12px;border-left:2px solid var(--panel2);opacity:.92;}
  details.fold.pg-fold .foldbody h3:first-of-type{margin-top:0;}

  /* ===== 三步开局引导 ===== */
  ol.steps{margin:6px 0;padding-left:24px;}
  ol.steps li{margin:6px 0;}

  /* ===== 顶部标签分组：家园 / 社交 / 系统 ===== */
  nav.tabs .tabgroup{display:flex;flex-wrap:wrap;gap:8px;align-items:center;}
  nav.tabs .tabgroup + .tabgroup{padding-left:16px;border-left:2px solid var(--panel);}
  nav.tabs .grouplab{font-size:13px;color:var(--muted);letter-spacing:1px;}

  .conn{font-size:13px;color:var(--muted);}
  .conn.ok{color:var(--good);}
  .conn.bad{color:var(--danger);}

  .overlay{position:fixed;inset:0;background:rgba(13,27,42,.97);display:flex;align-items:center;justify-content:center;z-index:100;padding:20px;}
  .overlay.hidden{display:none;}
  .authCard{background:var(--panel);border:2px solid var(--accent);border-radius:16px;padding:24px;max-width:440px;width:100%;}
  .authCard h1{font-size:22px;margin:0 0 8px;}
  .authCard input{width:100%;}

  /* ===== 注册协议：长文可滚动、行距放宽，低视力用户也能读 ===== */
  .aggBody{
    background:var(--panel2);
    border:1px solid var(--muted);
    border-radius:10px;
    padding:14px 18px;
    margin:12px 0;
    max-height:52vh;
    overflow:auto;
    line-height:1.75;
    font-size:15px;
    white-space:pre-wrap;
  }
  .aggBody:focus-visible{outline:3px solid var(--focus);outline-offset:2px;}
  /* 按钮样式的链接（「《用户注册协议》」）：保留按钮的可聚焦/可回车语义，但看着像链接 */
  .btn.link{
    background:none;border:none;color:var(--accent2);
    text-decoration:underline;padding:0 2px;font-size:inherit;cursor:pointer;
  }
  .btn.link:focus-visible{outline:3px solid var(--focus);outline-offset:2px;border-radius:4px;}
  .btn[disabled]{opacity:.5;cursor:not-allowed;}

  /* ============================================================
     移动端适配（2026-10-07）
     改之前只有一条 @media(max-width:640px){.plots{3列} h1{18px}}，
     而本站是**三级树形导航 + 大量表格 + 顶栏多枚徽章**的结构，
     窄屏上真正会坏的是这五处（按危害排序）：

       ① 一级页签 nav.tabs 换行 —— 5 个页签 + 3 个分组标签挤在 375px 里，
          每个按钮被压到不足 44px 触控高度，点不准。
       ② 表格（集市挂单、好友列表、仓库、税率表决）—— table 默认
          `width:100%` 但**内容不缩**，窄屏必然撑破布局，
          后果是整页出现横向滚动条，连顶栏都被推走。
       ③ 门户态卡片网格 minmax(230px,1fr) —— 230px 在 375px 屏上
          只能放一列且左右留白，看起来像「卡住了」。
       ④ 浮层 .authCard —— 登录/协议在手机上高度超屏且**不能滚**
          （overlay 是 flex 居中 + inset:0），底部的按钮点不到。
       ⑤ 触控目标尺寸 —— 桌面鼠标下 8px padding 够用，手指下不够。

     两条贯穿原则：
       · **不靠删内容来适配**。这里没有任何 `display:none` ——
         那正是本项目明令禁止的「用隐藏减少焦点/功能」（记忆 §60.2）。
         移动端该做的是换排布，不是砍功能。
       · 断点只按**布局需要**设，不按设备名设。900px 以下是「顶栏+页签
         开始互相挤压」的临界点，640px 以下是「卡片与表格必须单列」的临界点。
     ============================================================ */

  /* ---- 全局：窄屏降一点基准字号与留白 ----
     ⚠ 只降 body 字号、不降控件字号：控件（按钮/输入/下拉）保持 17~18px，
        它们是触摸目标，字小了更难点。 */
  @media (max-width:900px){
    body{font-size:17px;}
    main{padding:12px 10px;}
    .panel{padding:14px 12px;border-radius:12px;}
    header.topbar{padding:8px 10px;gap:8px;}
    /* 顶栏徽章在窄屏改成整行左对齐：margin-left:auto 会把它们推到右边，
       而 .status 是 flex-wrap 的，5 枚徽章换行后右对齐会排成阶梯状，很难看。 */
    header.topbar .status{margin-left:0;width:100%;gap:6px 10px;}
  }

  /* ---- ① 一级页签：横向滚动而不是换行 ----
     为什么横滚而不是 wrap：一级页签是 tablist，5 项换行后第 3 项独占一行，
     「当前在哪一级」这件事在视觉上被割裂了。横滚保持它们在同一条基线上，
     与二级卡片的横滚出口（.subjump）行为一致。
     ⚠ scrollbar 隐藏会让「右边还有内容」看不出来，所以保留细滚动条
       （不要写 scrollbar-width:none）。 */
  @media (max-width:900px){
    nav.tabs{
      flex-wrap:nowrap;overflow-x:auto;-webkit-overflow-scrolling:touch;
      padding:8px 10px;gap:8px;
      scroll-snap-type:x proximity;
    }
    nav.tabs .tabgroup{flex-wrap:nowrap;padding-left:0;border-left:none;}
    nav.tabs .tabgroup + .tabgroup{padding-left:8px;}
    nav.tabs button{
      flex:0 0 auto;min-height:44px;padding:10px 14px;font-size:17px;
      scroll-snap-align:start;white-space:nowrap;
    }
    nav.tabs .grouplab{display:none;}   /* 窄屏上分组标签只占宽度不提供信息 */
  }

  /* ---- ② 卡片网格：230px 下限在小屏必然只能一列，改成两列/单列 ---- */
  @media (max-width:900px){
    .hier:not(.entered) .subtabs{grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:10px;}
    .hier.entered .hier:not(.entered) .subtabs{grid-template-columns:repeat(auto-fill,minmax(150px,1fr));}
    .hier:not(.entered) .subtabs .plink{padding:12px 12px;min-height:72px;font-size:17px;}
    .hier.entered .hier:not(.entered) .subtabs .plink{padding:12px 12px;min-height:72px;}
    .pdesc{font-size:13px;}
  }
  @media (max-width:560px){
    .hier:not(.entered) .subtabs,
    .hier.entered .hier:not(.entered) .subtabs{grid-template-columns:1fr;}
  }

  /* ---- ③ 表格：横向滚动容器 ----
     ⚠ 不能直接给 table 设 `display:block;overflow:auto` ——
        那样 <th>/<td> 脱离表格布局，视觉上会全部塌成块级、左对齐错乱。
     正解：给表格**外面套一层可滚容器**。本站的表格都直接放在 .panel 里，
     用 `overflow-x:auto` 的 .panel 兜住；表格自身保持 table 布局并给
     `min-width` —— 不给 min-width 的话浏览器会为了塞进容器把列压到
     每格几个字（「0」「1」），比横向滚动更糟。 */
  @media (max-width:900px){
    .panel{overflow-x:auto;-webkit-overflow-scrolling:touch;}
    table{min-width:420px;}
    /* 表格里的操作按钮在窄屏单独占一行，避免挤成两三个手指难点 */
    th,td{padding:8px 6px;}
  }

  /* ---- ④ 触控目标：按钮/输入/下拉/链接卡达到 44px ----
     44px 是 iOS 与 Material 都认的最小舒适触控高度。 */
  @media (max-width:900px){
    button.btn{min-height:44px;padding:11px 16px;}
    input,select{min-height:44px;}
    .btn.link{min-height:44px;padding:0 6px;}
    .subtabs .plink{min-height:44px;padding:10px 12px;}
    /* 2026-10-12：窄屏「地块格子改 2 列 / 压高度」那三条随 .plots / .plot 一起删除 ——
       地块已经是原生 <select>，尺寸由上面 input,select 那条 min-height:44px 统一管。 */
  }

  /* ---- ⑤ 浮层：小屏可滚，且贴顶对齐 ----
     .overlay 是 flex + align-items:center + inset:0：内容比屏高时
     上下两端都会被裁掉且**无法滚动到**（因为滚动发生在 .authCard 上，
     而 .authCard 没有 max-height）。改成 align-items:flex-start +
     .authCard 自己 max-height + overflow:auto。 */
  @media (max-width:900px){
    .overlay{padding:12px 10px;align-items:flex-start;overflow-y:auto;}
    .authCard{padding:18px 14px;max-height:none;max-width:100%;}
    /* 协议正文原来用 52vh：小屏上再留 52vh 给协议、输入框就被挤到屏幕外了 */
    .aggBody{max-height:none;font-size:15px;padding:12px 14px;}
    /* 2026-10-08：这里原先有一条 .speakbox 的移动端圆角/内边距规则。
       可视播报区已整块删除（用户诉求②），规则随之删除 ——
       留着就是一条**死规则**：永远匹配不到元素，读起来却像「播报条还在手机上做过适配」。
       真要改 #lastSpeech 的呈现，只能改 .offscreen（且它永远不可见）。 */
  }

  /* ---- ⑥ 农场：地块 2 列（替换原先那条只改 plots 的老规则）----
     老规则在文件更早处（640px / 3列），这里用 560px / 2列 覆盖它 ——
     同优先级下后写的赢，所以顺序必须在这里。 */
  @media (max-width:560px){
    .badge{font-size:15px;padding:4px 8px;}
    /* 顶栏徽章在极窄屏去掉胶囊圆角：375px 宽放不下 5 枚圆角胶囊 */
    .badge{border-radius:8px;}
  }

  /* ---- ⑦ 刘海屏 / 手势条安全区（配合 viewport-fit=cover）----
     ⚠ 只给「会贴边」的四个方向加内边距，不要给 body 全加：
     给 body 加会让页面整体缩进，而页面本身并不需要缩那么多。 */
  @supports (padding:max(0px)){
    @media (max-width:900px){
      header.topbar{padding-left:max(10px,env(safe-area-inset-left));
                     padding-right:max(10px,env(safe-area-inset-right));}
      main{padding-bottom:calc(12px + env(safe-area-inset-bottom));}
      nav.tabs{padding-left:max(10px,env(safe-area-inset-left));}
    }
  }

  /* ---- ⑧ 减少动效偏好 ----
     唯一一处 transition 是 .lvlbar span 的宽度动画，0.3s。
     前庭功能障碍用户在横竖屏切换时对动画敏感，这里尊重系统设置。 */
  @media (prefers-reduced-motion:reduce){
    .lvlbar span{transition:none;}
  }

  /* ---- ⑨ 深作用域：移动端「一屏显示完整」（2026-10-08 用户诉求⑤）----
     诉求①把顶栏与一级页签整块收起之后，手机上第一屏原本浪费在
     「返回条上下留白 + 面包屑 + 面板内边距」上；诉求⑤要求
     **焦点内容在一屏内就能看全**，所以这里做三件事，全是排布：

       ① 返回条吸顶。深作用域下它是**唯一**的出路（「← 返回上一级」），
          一旦内容长、需要往下滚，它必须一直够得着 —— 否则玩家会卡在
          子页面里出不来（这与「藏了 #btn-logout」的兜底论证是同一件事）。
       ② 返回条压扁：margin/padding 各减一半，面板内边距收紧，
          省下的高度全部还给内容。
       ③ .subjump 下拉限宽 —— 它是卡片区隐藏后的横向出口，
          不限宽在 375px 屏上会把返回条撑成两行，把 ① 的吸顶条撑得又高又笨。

     ⚠ 这里**绝不能写 display:none**：静态守卫第 30 段从「移动端适配」段
        起扫到文件末尾，除装饰性的 .grouplab 外任何 display:none 都判红。
        「少焦点」由 JS 的 syncPageChrome 作用域机制负责，CSS 只管排布。 */
  @media (max-width:900px){
    /* 深作用域省下的高度先还给内容：上面不再需要给顶栏留位置 */
    body.deep-scope main{padding-top:8px;padding-bottom:calc(8px + env(safe-area-inset-bottom));}
    /* 返回条吸顶。要 opaque 背景，否则滚上来的正文会透出来叠字。
       ⚠ 别用 top:<顶栏高度> —— 深作用域下顶栏已 display:none，
         留偏移会凭空多出一条空隙，正好和「一屏显示完整」相反。 */
    body.deep-scope .subbar{
      position:sticky;top:0;z-index:20;
      margin:0 0 8px;padding:6px 0;gap:8px;
      background:var(--panel);border-bottom:1px solid var(--panel2);
    }
    body.deep-scope .subbar .crumb{font-size:13px;}
    body.deep-scope .subbar .subjump select{max-width:38vw;}
    body.deep-scope .panel{padding:12px 10px;margin-bottom:12px;}
  }

  /* ===== 家园设施 / 村长竞选 / 研究所（2026-10-01）=====
     全部用主题变量上色（--panel2 / --muted / --accent / --accent2），
     不要写死颜色：这个项目在明暗两套主题下都要能用。 */
  .fac{
    border:1px solid var(--muted);border-radius:10px;padding:10px 12px;
    margin:10px 0;background:var(--panel2);
  }
  .fac .fhead{display:flex;flex-wrap:wrap;gap:10px;align-items:baseline;}
  .fac .ftier{color:var(--accent2);font-size:14px;}
  .fac p{margin:4px 0;}
  /* 竞选候选人一行：名字 + 等级 + 票数 + 投票按钮。
     用 flex-wrap 而不是固定列宽 —— 昵称最长 20 字符，窄屏上必须能换行。 */
  .cands{margin:8px 0;}
  .cand{
    display:flex;flex-wrap:wrap;gap:8px;align-items:center;
    padding:6px 8px;border-radius:8px;border:1px solid var(--muted);margin:6px 0;
  }
  .cand.me{border-color:var(--accent);}
  .cand .votes{color:var(--accent2);font-weight:bold;}
  /* 进行中的研究：左侧色条，与候选人列表区分开 */
  .research{padding:6px 8px;border-left:3px solid var(--accent2);margin:6px 0;}

/* ── 字段组（roving tabindex）──────────────────────────────────────────────
   2026-10-06：把「一行 N 个字段」压成 1 个 Tab 位后，必须给用户一个
   **看得见**的提示：焦点在组内移动时，这一组要看起来是"被选中"的。
   否则键盘用户按了 ←/→ 焦点动了，但眼睛不知道落在哪个字段上。
   视觉线索用 inset box-shadow（不占布局、不像 outline 那样遮住内容）。 */
  .fgroup{position:relative;}
  .fgroup:focus-within{box-shadow:inset 0 0 0 2px var(--focus);border-radius:8px;}
  /* 组内成员获得焦点时给一条左侧竖条，指示"当前在组内第几个" */
  .fgroup>:focus-visible{outline:3px solid var(--focus);outline-offset:1px;border-radius:6px;}

/* ===== 存档备份与回滚（2026-10-29）=====
   每个备份是一颗整行按钮：读屏用户 Tab 到它就念出「回滚到 X 时的备份，N 个账号」，
   不需要先读一行时间再去找对应的按钮（那会变成 2N 个停点）。 */
.bklist{list-style:none;margin:6px 0 10px;padding:0;}
.bklist li{margin:4px 0;}
.bklist button{width:100%;text-align:left;}
.bklist .bksub{color:var(--muted);font-size:14px;}

/* 2026-11-02：原「跳到本页操作区」的 .skipbtn 规则（position:absolute + left:-10000px，
   聚焦时移到左上角）随按钮一起删除 —— 按钮已从 index.html 移除，
   留着这条规则只会让以后的人以为还有那么一颗按钮。 */

/* 行动聚焦（2026-10-29 用户诉求③）：轮到我行动时，其它区域被设为 inert。
   为什么还要压暗：inert 对**视力用户是完全不可见的**——Tab 进不去、点不动，
   但屏幕上看起来和平时一模一样，人会以为是卡了。
   只压暗 45%，不隐藏、不位移：关掉后不会抖一下，也不会让低视力用户误以为页面坏了。
   行动区自己不加任何样式：它是唯一还能操作的地方，保持原样最不容易被读错。 */
body.actionFocus [inert]{opacity:.45;transition:opacity .12s linear;}
body.actionFocus #actionFocusBar{
  position:sticky;top:0;z-index:50;background:#fffdf5;border:2px solid var(--focus);
  border-radius:8px;padding:8px 10px;margin:0 0 10px;
}

/* 禁言时长对话框（2026-11-02 起用原生 <dialog>，替换掉原来的 prompt）。
   本项目只有深色一套主题，而 UA 默认给 dialog 的是白底黑字 —— 不覆盖就会在
   深色页面中间弹出一块刺眼的白色，且里面的 .small 说明文字按 15% 灰算完全看不清。
   所以这里把 panel / text / accent 三组变量显式套上去；::backdrop 用半透明黑，
   保留"后面的内容还在、只是暂时不能动"的视觉暗示。 */
dialog{
  background:var(--panel);color:var(--text);
  border:2px solid var(--accent);border-radius:12px;
  padding:18px 20px;max-width:460px;width:calc(100% - 32px);
  font-family:inherit;font-size:18px;
}
dialog::backdrop{background:rgba(0,0,0,.62);}
dialog h2{margin:0 0 6px;font-size:20px;}
dialog label{display:block;margin:12px 0 4px;color:var(--muted);font-size:15px;}
dialog select{
  width:100%;padding:8px 10px;border-radius:8px;font-size:18px;
  background:var(--panel2);color:var(--text);border:1px solid var(--accent);
}
dialog .row{margin-top:14px;gap:10px;}
/* 黑名单区（好友页）：拉黑不通知对方，所以说明里必须写清楚"对方不会收到通知"，
   否则用户会担心点了以后对方立刻知道，从而不敢用。 */
#blockList .panel{border-color:var(--muted);}

/* ===== 全服公告横幅（2026-11-04）=====
   位置在 <header> 之后、<main> 之前：所有页签都看得到，不随页面切换消失。
   颜色用 --warn 的浅色变体而不是纯红：公告多数是「维护 / 活动」，不是错误。 */
.noticebar{
  display:flex;flex-wrap:wrap;align-items:baseline;gap:6px 10px;
  margin:10px 16px 0;padding:8px 14px;border-radius:10px;
  background:rgba(252,196,25,.14);border:1px solid rgba(252,196,25,.5);
}
.noticebar .noticeicon{
  font-size:14px;font-weight:700;padding:1px 8px;border-radius:6px;
  background:rgba(252,196,25,.28);color:var(--warn);
}
.noticebar #globalNoticeText{flex:1 1 320px;}
.noticebar .small{color:var(--muted);}

/* 管理日志列表：每条一行「时间 · 操作人 · 动作 · 对象 · 内容」，
   用 dl 而不是 table —— 日志条目长度差异大，表格列宽会把内容挤成竖条。 */
.loglist{margin:0;padding:0;list-style:none;}
.loglist li{
  padding:8px 10px;margin:0 0 6px;border-radius:8px;
  background:var(--panel2);border-left:3px solid var(--accent);
}
.loglist .loghead{display:flex;flex-wrap:wrap;gap:4px 10px;align-items:baseline;}
.loglist .logtime{color:var(--muted);font-size:15px;}
.loglist .logactor{font-weight:700;color:var(--accent2);}
.loglist .logact{color:var(--warn);}
.loglist .logtarget{font-weight:700;}
.loglist .logdetail{color:var(--muted);font-size:15px;}
