/* DOM parts of the game screen (src/client/play/ui.ts): the player menu,
   invitations, the trade house window and the panel's 行会 / 商城 / 充值 pages, in the HUD's colours.
   Typefaces and sizes: the same three faces and one scale as the canvas (src/shared/fonts.ts):
   --gm-kai 题字 (page titles, the death screen), --gm-hei 正文 (everything read), --gm-num 跳字. */
@import url(/play/fonts/kai/kai.css);
@font-face { font-family: DmgDigits; src: url(/play/fonts/cinzel-digits.woff2) format("woff2"); font-weight: 700; }
:root { --gm-hei: "PingFang SC", "Microsoft YaHei", "Noto Sans SC", sans-serif; --gm-kai: Kai, "Kaiti SC", "STKaiti", "KaiTi", serif;
  --gm-num: DmgDigits, var(--gm-hei); --gm-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  /* Colours (docs/colors.md): the same names and values as src/shared/colors.ts COLOR; tools/colors-test.ts checks they match. */
  --gm-c-main: #f2ead8; --gm-c-sub: #c9bfa9; --gm-c-dim: #9a8f7c; --gm-c-off: #5c5446; --gm-c-gold: #e6c88a; --gm-c-bright: #f0d69a;
  --gm-c-good: #8fd18a; --gm-c-bad: #e0584a; --gm-c-hp: #ff8a7a; --gm-c-mp: #9ab8ff; --gm-c-ink: #1a1612; --gm-c-coin: #8fd0ff; --gm-c-blood: #b3271d;
  /* Surfaces, lines, corners, control heights (docs/ui-rules.md「面、线与按钮」): the same as src/shared/colors.ts SURFACE, LINE,
     RADIUS, CONTROL_H; tools/colors-test.ts checks they match and that nothing else is written. Hover lifts one step. */
  --gm-s-sunk: #0c0a08; --gm-s-card: #15120e; --gm-s-raise: #2a251f; --gm-s-hover: #3a332a; --gm-s-gold: #3a2f1c; --gm-s-gold-hover: #4a3c24;
  --gm-s-bad: #3a201b; --gm-s-bad-hover: #4a2822; --gm-s-coin: #16293a; --gm-s-float: rgba(18, 15, 12, .95);
  --gm-l-line: #3b3428; --gm-l-faint: #221c15; --gm-l-edge: #6b5a3e; --gm-l-gold: #e6c88a;
  --gm-r-s: 3px; --gm-r-m: 6px; --gm-r-full: 999px; --gm-h-lg: 32px; --gm-h-md: 28px; --gm-h-sm: 22px; --gm-off: .45;
  /* Spacing (docs/ui-rules.md「间距」): the same as src/shared/space.ts SPACE; gaps, paddings and margins are only these seven numbers
     (a control's own inside — buttons, chips, tabs — and art that says 「材质」 aside). tools/space-test.ts checks. */
  --gm-sp-hair: 2px; --gm-sp-tight: 4px; --gm-sp-near: 6px; --gm-sp-row: 8px; --gm-sp-inner: 10px; --gm-sp-section: 14px; --gm-sp-page: 18px;
  /* Motion (docs/ui-rules.md「动效」): the same as src/shared/motion.ts MOTION; in fast and settling, out slow then fast. */
  --gm-t-quick: 120ms; --gm-t-mid: 300ms; --gm-t-slow: 500ms; --gm-t-hold: 1200ms; --gm-t-blink: 1000ms; --gm-t-breathe: 1400ms;
  --gm-ease-out: cubic-bezier(.33, 1, .68, 1); --gm-ease-in: cubic-bezier(.32, 0, .67, 0);
  /* What covers what (docs/ui-rules.md「叠放顺序和鼠标」), over the game canvas, bottom to top: the Alt+X countdown, the DOM pages,
     the update line, the see-through canvas with the item in hand and the tooltips (.gm-top), menus and invitations, the
     confirmation card, the lost-connection box. #ui is not a layer of its own, so its parts can sit on both sides of .gm-top.
     tools/space-test.ts checks z-index reads these. */
  --gm-z-countdown: 3; --gm-z-ui: 5; --gm-z-update: 6; --gm-z-top: 7; --gm-z-pop: 8; --gm-z-ask: 50; --gm-z-alarm: 60; }
#ui { position: fixed; inset: 0; pointer-events: none; font: 13px var(--gm-hei); color: var(--gm-c-main); }
#ui > * { pointer-events: auto; }
#ui button { font: inherit; }
:where(#ui) small { font-size: 11px; } /* 注脚 (no weight: a class sets its own size over it); the browser's own 「smaller」 is 10.8, off the ladder (docs/ui-rules.md「字体规划」) */
.gm-menu { position: fixed; z-index: var(--gm-z-pop); min-width: 168px; padding: 6px; border-radius: var(--gm-r-m); background: var(--gm-s-float); border: 1px solid var(--gm-l-edge);
  box-shadow: 0 10px 28px rgba(0, 0, 0, .55); }
.gm-menu-head { display: flex; flex-direction: column; padding: 6px 10px 6px; }
.gm-menu-head b { color: var(--gm-c-main); font-size: 15px; font-weight: 600; }
.gm-menu-head span { color: var(--gm-c-sub); font-size: 12px; } /* the guild under a name is 字·次, as over heads (docs/colors.md) */
.gm-sep { height: 1px; margin: 4px 6px; background: var(--gm-l-line); }
.gm-item { display: block; width: 100%; text-align: left; padding: 6px 10px; border: 0; border-radius: var(--gm-r-s); background: none; color: var(--gm-c-main); cursor: pointer;
  transition: background var(--gm-t-quick) var(--gm-ease-out); }
.gm-item:hover { background: var(--gm-s-raise); }
.gm-item.danger { color: var(--gm-c-bad); }
.gm-item small { margin-left: 4px; color: var(--gm-c-dim); }
.gm-item:disabled { color: var(--gm-c-dim); cursor: default; background: none; }
#gm-invites { position: fixed; z-index: var(--gm-z-pop); left: 16px; top: 16px; transform-origin: 0 0; display: flex; flex-direction: column; gap: 6px; }
#gm-invites.gm-after-party:not(:empty) { margin-top: 6px; padding-top: 14px; border-top: 1px solid var(--gm-l-line); }
/* An invitation: as big as a party card (170 × 38), top left under them (用户决定，2026-09-30). */
.gm-inv { position: relative; overflow: hidden; box-sizing: border-box; width: 170px; min-height: 38px; display: flex; align-items: center; gap: 4px; padding: 4px 4px 4px 8px;
  border-radius: var(--gm-r-m); background: var(--gm-s-float); border: 1px solid var(--gm-l-gold); font-size: 12px; }
.gm-inv-text { flex: 1; min-width: 0; line-height: 1.4; overflow-wrap: anywhere; } /* a long guild name wraps to a second line, nothing is cut off (规范检查 2026-10-07: was … with the browser title) */
.gm-inv-text b { color: var(--gm-c-gold); font-weight: 500; margin-right: 4px; }
.gm-inv button { width: 24px; height: var(--gm-h-sm); padding: 0; border: 0; border-radius: var(--gm-r-full); cursor: pointer; font-size: 12px; line-height: 22px; }
.gm-inv-yes { background: var(--gm-s-gold); color: var(--gm-c-gold); transition: background var(--gm-t-quick) var(--gm-ease-out); }
.gm-inv-no { background: var(--gm-s-raise); color: var(--gm-c-bad); transition: background var(--gm-t-quick) var(--gm-ease-out); }
.gm-inv-yes:hover { background: var(--gm-s-gold-hover); }
.gm-inv-no:hover { background: var(--gm-s-hover); color: var(--gm-c-bad); } /* ✕ = 拒绝: 坏, like 行会页's 拒绝 (colors.md) */
.gm-inv i { position: absolute; left: 0; bottom: 0; height: 2px; width: 100%; background: var(--gm-l-gold); animation: gm-shrink linear forwards; }
/* The gold you offer in a trade: a text box over the HUD's gold box (src/client/hud/hud.ts buildTrade). */
.gm-trade-gold.bad { color: var(--gm-c-bad); } /* filled wrong: the canvas draws its edge, so its words turn red (四种状态·错) */
.gm-trade-gold { position: fixed; transform-origin: 0 0; box-sizing: border-box; padding: 0; border: 0; background: transparent; color: var(--gm-c-gold); font: 13px var(--gm-hei); outline: none; }
/* Every 弹窗 (src/client/play/ui.ts dialog, docs/ui-rules.md「弹窗」, 用户定 2026-10-09): the panel pages' head, the body, the
   buttons on the last row at the right. Gold edge like the invite cards: gold = waiting for your answer (用户选 B，
   2026-10-05, https://claude.ai/artifact/PPcAoKHGHQAyrFUNQ4X5M7). In the middle by default (questions, 元神归位). */
.gm-dlg { position: fixed; left: 50%; top: 38%; transform: translate(-50%, -50%); box-sizing: border-box; width: 340px; padding: 0 18px 18px; border-radius: var(--gm-r-m);
  background: var(--gm-s-float); border: 1px solid var(--gm-l-gold); box-shadow: 0 14px 40px rgba(0, 0, 0, .6); z-index: var(--gm-z-ask); }
.gm-dlg > .gm-ph { margin-bottom: 14px; }
.gm-dlg p { margin: 0; font-size: 13px; line-height: 1.7; }
.gm-dlg em { font-style: normal; font-weight: 500; color: var(--gm-c-bright); }
.gm-dlg em.gm-coin { color: var(--gm-c-coin); }
.gm-ask-note { display: block; margin-top: 4px; font-size: 12px; color: var(--gm-c-dim); }
.gm-ask-input { display: block; width: 100%; margin-top: 10px; }
.gm-dlg .gm-say { margin-top: 6px; }
.gm-ask-input + .gm-say + .gm-ask-note { margin-top: 2px; }
.gm-dlg .gm-row { justify-content: flex-end; margin-top: 14px; }
.gm-dlg .gm-btn.danger { background: var(--gm-s-bad); }
.gm-dlg .gm-btn.danger:hover { background: var(--gm-s-bad-hover); }
.gm-dlg .gm-btn small { margin-left: 6px; font-size: 11px; font-weight: 400; color: var(--gm-c-dim); }
/* 断开了 / 出错了: over everything, the game cannot go on under it. */
.gm-alarm { z-index: var(--gm-z-alarm); }
/* 绑定 Telegram (src/client/play/guest-bind.ts, docs/login.md「试玩账号」): the QR code for the phone. */
.gm-bind-body { display: flex; flex-direction: column; align-items: center; gap: var(--gm-sp-row); text-align: center; }
.gm-bind-qr { width: 148px; height: 148px; padding: 6px; box-sizing: border-box; background: #fff; border-radius: var(--gm-r-s); } /* 材质：二维码要白底 */
.gm-bind-qr svg { display: block; width: 100%; height: 100%; }
.gm-guest { margin-bottom: var(--gm-sp-section); }
.gm-guest p { margin: 0; line-height: 1.7; }
.gm-guest .gm-btn { align-self: flex-start; }
/* The season pass offer: above the skill bar, wider; it does not stop the game. */
.gm-pass { top: auto; bottom: 200px; transform: translateX(-50%); width: 440px; z-index: var(--gm-z-pop); }
/* 元神归位 (src/client/play/spirit-window.ts, docs/hud.md「元神归位」); the experience counts up (the window itself appears at once).
   What came back is one group (near), the button row another (page): 同组近、异组远. Written like the gains at the bottom
   right, 「+N 经验」「+N 金币」, experience one step bigger (用户选 A1, 2026-10-09). */
.gm-spirit-got { display: flex; flex-direction: column; gap: var(--gm-sp-near); }
.gm-spirit-got p { display: flex; align-items: baseline; gap: var(--gm-sp-inner); margin: 0; }
.gm-spirit-got small { margin-left: var(--gm-sp-tight); }
.gm-spirit-exp b { font: 700 20px/1 var(--gm-num); color: var(--gm-c-bright); font-variant-numeric: tabular-nums; }
.gm-spirit-exp small { font-size: 13px; }
.gm-spirit-exp span { margin-left: auto; font-size: 12px; color: var(--gm-c-sub); white-space: nowrap; }
.gm-spirit-gold b { font: 700 15px/1 var(--gm-num); color: var(--gm-c-gold); font-variant-numeric: tabular-nums; }
.gm-spirit-gold small { font-size: 12px; }
.gm-dlg.gm-spirit .gm-row { margin-top: var(--gm-sp-page); }
@keyframes gm-shrink { from { width: 100%; } to { width: 0; } }
.gm-row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
/* Buttons (用户选 B，2026-09-30, https://claude.ai/artifact/TrDWzij8dL5byC7pFQ2pK7; three sizes 2026-10-04): round, solid; md 28 by
   default, lg 32 for the main one of a page (gold) and the confirmation card, sm 22 in a table row. Danger is red words. */
.gm-btn { box-sizing: border-box; height: var(--gm-h-md); padding: 0 14px; border: 0; border-radius: var(--gm-r-full); background: var(--gm-s-raise);
  color: var(--gm-c-main); font-size: 13px; line-height: var(--gm-h-md); white-space: nowrap; cursor: pointer; transition: background var(--gm-t-quick) var(--gm-ease-out); }
.gm-btn:hover { background: var(--gm-s-hover); }
/* Focus is the gold line (docs/ui-rules.md「面、线与按钮」, 规范检查 2026-10-12: a clicked 「绑定 Telegram」 wore the browser's blue ring);
   a mouse click shows none, the keyboard's focus shows the gold. */
.gm-btn:focus { outline: none; }
.gm-btn:focus-visible { outline: 1px solid var(--gm-l-gold); outline-offset: 1px; }
.gm-btn.lg, .gm-btn.gold { height: var(--gm-h-lg); line-height: var(--gm-h-lg); padding: 0 20px; }
.gm-btn.sm { height: var(--gm-h-sm); line-height: var(--gm-h-sm); padding: 0 10px; font-size: 12px; }
.gm-btn.gold { background: var(--gm-s-gold); color: var(--gm-c-gold); font-weight: 600; }
.gm-btn.gold:hover { background: var(--gm-s-gold-hover); }
.gm-btn.gold.md { height: var(--gm-h-md); line-height: var(--gm-h-md); padding: 0 14px; } /* 商城卡片和道具行的「购买」：金色，比大号小一档；旁边的「送人」再小一档 */
.gm-btn.danger { color: var(--gm-c-bad); }
.gm-btn:disabled { opacity: var(--gm-off); cursor: default; background: var(--gm-s-raise); }
.gm-btn small { margin-left: 4px; font-size: 12px; font-weight: 400; }
.gm-muted { color: var(--gm-c-dim); }
.gm-gold { color: var(--gm-c-gold); }
.gm-sub { color: var(--gm-c-sub); }
.gm-coin { color: var(--gm-c-coin); }
/* One line saying how it went, under the box or button it is about (docs/ui-rules.md「页面的四种状态」·错): 12, red when
   it failed, green when it worked; the box it is about gets a red edge. The canvas draws the same (FS.label). */
.gm-say { min-height: 1.5em; margin: 0; font-size: 12px; line-height: 1.5; color: var(--gm-c-dim); }
.gm-say.good { color: var(--gm-c-good); }
.gm-say.bad { color: var(--gm-c-bad); }
.gm-input.bad { border-color: var(--gm-c-bad); }
/* Waiting for the server (·等): nothing for the first --gm-t-mid, then 「读取中…」 where the content will be. */
.gm-wait { margin: 0; color: var(--gm-c-dim); opacity: 0; animation: gm-in var(--gm-t-quick) var(--gm-ease-out) var(--gm-t-mid) forwards; }
@keyframes gm-in { to { opacity: 1; } }
.gm-input { box-sizing: border-box; height: var(--gm-h-lg); padding: 0 10px; border-radius: var(--gm-r-s); border: 1px solid var(--gm-l-edge); background: var(--gm-s-sunk); color: var(--gm-c-main); font: inherit; outline: none; user-select: text; }
.gm-input:focus { border-color: var(--gm-l-gold); }
.gm-input.num { width: 110px; text-align: right; font-variant-numeric: tabular-nums; }
.gm-table { width: 100%; border-collapse: collapse; font-variant-numeric: tabular-nums; }
.gm-table th { text-align: left; color: var(--gm-c-dim); font-weight: 400; font-size: 12px; padding: 4px 8px; border-bottom: 1px solid var(--gm-l-line); }
.gm-table td { padding: 6px 8px; border-bottom: 1px solid var(--gm-l-faint); }
.gm-table td.r, .gm-table th.r { text-align: right; }
.gm-box { padding: 10px; border-radius: var(--gm-r-m); background: var(--gm-s-card); border: 1px solid var(--gm-l-faint); display: flex; flex-direction: column; gap: 8px; }
/* 金币 | 降龍币 switch (trade house: 寄售 per item, 买装备 filter) */
.gm-seg { box-sizing: border-box; height: var(--gm-h-lg); display: inline-flex; border: 1px solid var(--gm-l-edge); border-radius: var(--gm-r-s); overflow: hidden; vertical-align: middle; }
.gm-seg button { border: 0; background: none; color: var(--gm-c-dim); padding: 0 10px; cursor: pointer; font: inherit; transition: background var(--gm-t-quick) var(--gm-ease-out); }
.gm-seg button:hover { background: var(--gm-s-raise); color: var(--gm-c-main); }
.gm-seg button.on.gold { background: var(--gm-s-gold); color: var(--gm-c-gold); }
.gm-seg button.on.coins { background: var(--gm-s-coin); color: var(--gm-c-coin); }
.gm-seg button.on.all { background: var(--gm-s-raise); color: var(--gm-c-main); }
/* 商城 → 充值 (sketch https://claude.ai/artifact/11ZgYCuVp7u3zEJU6w1T2s) */
.gm-tiers { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--gm-sp-near); margin-top: 4px; }
.gm-tier { position: relative; display: flex; flex-direction: column; align-items: flex-start; gap: 2px; padding: 8px 10px; border-radius: var(--gm-r-m); border: 1px solid var(--gm-l-line); background: var(--gm-s-card); color: var(--gm-c-main); font: inherit; cursor: pointer; text-align: left; }
.gm-tier:hover { border-color: var(--gm-l-edge); }
.gm-tier.on { border-color: var(--gm-l-gold); background: var(--gm-s-gold); }
.gm-tier .u { color: var(--gm-c-dim); font-size: 12px; }
.gm-tier .c { color: var(--gm-c-coin); font-size: 15px; font-weight: 600; font-variant-numeric: tabular-nums; }
.gm-tier .c small { font-size: 12px; font-weight: 400; }
.gm-tier .bonus { position: absolute; top: -8px; right: 8px; padding: 0 6px; border-radius: var(--gm-r-s); background: var(--gm-s-raise); color: var(--gm-c-bright); font-size: 11px; }
.gm-tier-other { grid-column: 1 / -1; display: flex; align-items: center; gap: 8px; padding: 6px 10px; border-radius: var(--gm-r-m); border: 1px dashed var(--gm-l-line); }
.gm-tier-other.on { border: 1px solid var(--gm-l-gold); background: var(--gm-s-gold); }
.gm-topup-pay { display: grid; grid-template-columns: minmax(0, 1fr) 150px; gap: 14px; align-items: start; }
.gm-topup-amt { font-size: 26px; font-weight: 600; font-variant-numeric: tabular-nums; } /* 字号例外：要付的金额，整页最要紧的一个数 */
.gm-topup-amt em { font-style: normal; color: var(--gm-c-bright); } /* 认人的四位小数：强调，不是「坏」 */
.gm-topup-line { display: flex; align-items: center; gap: 10px; }
.gm-topup-addr { flex: 1; min-width: 0; font-family: var(--gm-mono); font-size: 12px; word-break: break-all; user-select: text; }
.gm-topup-pay .gm-box { gap: 6px; }
.gm-topup-pay p { font-size: 12px; line-height: 1.5; }
.gm-topup-qr { display: flex; flex-direction: column; align-items: center; gap: 6px; text-align: center; font-size: 12px; }
.gm-topup-qr > div { width: 138px; height: 138px; padding: 4px; border-radius: var(--gm-r-s); background: #f3ead8; } /* 材质：二维码要浅底才扫得出 */
.gm-topup-qr svg { width: 100%; height: 100%; display: block; }
.gm-ok { color: var(--gm-c-good); font-size: 15px; }
a.gm-btn { display: inline-block; text-decoration: none; align-self: flex-start; }
/* Dying (src/client/play/death.ts): big words straight on the greying world, no box (方案 B, 2026-10-01). */
.gm-death { position: fixed; left: 0; right: 0; top: 30%; transform: translateY(-50%); text-align: center; pointer-events: none; }
.gm-death p { margin: 0; }
.gm-death-title { font-family: var(--gm-kai); font-weight: 700; font-size: 72px; line-height: 1.1;
  letter-spacing: .3em; padding-left: .3em; color: var(--gm-c-blood); text-shadow: 0 0 18px rgba(0, 0, 0, .95), 0 0 4px rgba(0, 0, 0, .9); }
.gm-death-rule { width: 340px; max-width: 70vw; height: 1px; margin: 10px auto 12px; background: linear-gradient(90deg, transparent, rgba(217, 180, 90, .65), transparent); } /* 材质：死亡大字下面渐隐的线 */
.gm-death-by { /* 字号例外：「被 X 杀死」黑体 20，场面，和「你死了」一起看（2026-10-10 用户同意） */ font-size: 20px; letter-spacing: 1px; color: var(--gm-c-main); text-shadow: 0 0 6px #000, 0 0 2px #000; }
.gm-death-back { margin-top: 14px !important; font-size: 15px; color: var(--gm-c-gold); font-variant-numeric: tabular-nums; text-shadow: 0 0 6px #000, 0 0 2px #000; }
.gm-death.gm-death-out { animation: gm-death-fade var(--gm-t-slow) var(--gm-ease-in) forwards; }
@keyframes gm-death-fade { to { opacity: 0; } }
@media (prefers-reduced-motion: no-preference) { .gm-death { animation: gm-death-in var(--gm-t-slow) var(--gm-ease-out) both; } } /* 例外：死亡是场面转换，进来也用慢 */
@keyframes gm-death-in { from { opacity: 0; transform: translateY(-46%); } }
/* The panel's DOM pages (src/client/play/panel-pages.ts): 行会, 商城, 充值, 交易行 laid into the frame
   the HUD draws (docs/hud.md "面板的标签"). No box of their own: the frame is the box. The page head is the
   one every page has (统一版式, 2026-10-02; the canvas pages draw the same, Hud.pageHead): 46 high from
   the frame's inner top, the title in 楷书 20, the page's state on the right, a line under it; the
   body starts 14 below the line and scrolls on its own. */
.gm-page { position: fixed; z-index: var(--gm-z-ui); transform-origin: 0 0; display: flex; flex-direction: column; }
.gm-page[hidden] { display: none; }
.gm-top { position: fixed; inset: 0; z-index: var(--gm-z-top); pointer-events: none; }
.gm-top canvas { pointer-events: none; }
.gm-page-head { flex: none; margin-bottom: 14px; }
.gm-ph { height: 46px; display: flex; align-items: center; justify-content: space-between; gap: 10px; border-bottom: 1px solid var(--gm-l-line); }
.gm-ph > b { font: 700 20px/1 var(--gm-kai); color: var(--gm-c-gold); letter-spacing: .14em; white-space: nowrap; transform: translateY(-1px); }
.gm-ph > span { font-size: 12px; color: var(--gm-c-dim); white-space: nowrap; }
/* The head's numbers are 字·主; money keeps its own colour (金币 gold, 降龍币 coin) — a count is not money (规范检查 2026-10-07). */
.gm-ph > span b { font-size: 13px; font-weight: 500; color: var(--gm-c-main); font-variant-numeric: tabular-nums; }
.gm-ph > span b.gm-gold { color: var(--gm-c-gold); }
.gm-ph > span b.gm-coin { color: var(--gm-c-coin); }
.gm-jump { display: flex; gap: 6px; margin-top: 14px; }
/* What an NPC said as its window opened (the 铁匠): under the head's line, 字·副 13, two lines at most. */
.gm-page .gm-talk { margin-top: var(--gm-sp-section); font-size: 13px; line-height: 1.6; color: var(--gm-c-sub); }
.gm-talk + .gm-jump { margin-top: var(--gm-sp-inner); }
.gm-page-body { position: relative; flex: 1; min-height: 0; overflow-y: auto; overflow-x: hidden; display: flex; flex-direction: column; gap: 10px;
  padding: 0 6px 10px 0; margin-right: -6px; scrollbar-width: thin; scrollbar-color: var(--gm-l-edge) transparent; overscroll-behavior: contain; }
.gm-page p { margin: 0; line-height: 1.6; }
.gm-page .gm-table td { padding: 4px 6px; }
/* 小组标题, the only heading in a page (2026-10-05 用户选方案一): 15 white, a line to the right, its note on the line's end. */
.gm-page-body > :first-child { margin-top: 0; }
.gm-grp { margin: 4px 0 -4px; display: flex; align-items: center; gap: 10px; font-size: 15px; font-weight: 500; color: var(--gm-c-main); }
.gm-grp::after { content: ""; flex: 1; height: 1px; background: var(--gm-l-line); order: 1; }
.gm-grp .gm-muted { order: 2; font-size: 12px; font-weight: 400; }
.gm-nowrap { flex-wrap: nowrap; }
.gm-dim { color: var(--gm-c-dim); }
.gm-grow { flex: 1; }
.gm-notice { width: 100%; height: auto; padding: 6px 10px; line-height: 1.6; resize: none; box-sizing: border-box; }
.gm-notice-text { white-space: pre-wrap; line-height: 1.6; }
.gm-members tr.off td { color: var(--gm-c-dim); }
.gm-name-link { cursor: pointer; border-radius: var(--gm-r-s); transition: background var(--gm-t-quick) var(--gm-ease-out); }
.gm-name-link:hover { background: var(--gm-s-raise); }
.gm-role { margin-left: var(--gm-sp-tight); padding: 0 4px; border-radius: var(--gm-r-s); font-size: 11px; background: var(--gm-s-gold); color: var(--gm-c-gold); }
.gm-role.vice { background: var(--gm-s-raise); color: var(--gm-c-sub); }
/* 行会战: who declared (docs/game.md「行会战」) */
.gm-role.war { background: var(--gm-s-raise); color: var(--gm-c-main); } /* 我方宣战：不是坏事，不用红（2026-10-05 规范检查） */
.gm-role.war.them { background: var(--gm-s-raise); color: var(--gm-c-dim); }
.gm-members tr.off .gm-role { opacity: .6; }
.gm-foot { justify-content: flex-end; margin-top: auto; padding-top: 4px; }
.gm-pass-card { display: flex; flex-direction: column; gap: 6px; padding: 10px; border-radius: var(--gm-r-m); border: 1px solid var(--gm-l-gold);
  background: linear-gradient(135deg, rgba(230, 200, 138, .13), rgba(0, 0, 0, .35)); } /* 材质：通行证卡片的金光 */
.gm-pass-card > b { font-size: 15px; }
.gm-looks { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--gm-sp-near); }
.gm-looks.pet { grid-template-columns: repeat(2, minmax(0, 1fr)); }
/* 技能: one stage, the picked look cast on black (src/client/play/skill-stages.ts); the price and 购买 under it; the names below */
.gm-stage { flex: none; aspect-ratio: 3 / 2; background: #000; border: 1px solid var(--gm-l-faint); border-radius: var(--gm-r-s); /* 材质：技能外观的黑舞台 */ overflow: hidden; }
.gm-stage canvas { display: block; width: 100%; height: 100%; }
.gm-stage-foot { display: flex; align-items: center; gap: 10px; min-height: 32px; }
.gm-stage-foot > b { font-size: 15px; font-weight: 600; }
.gm-names { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 14px; }
.gm-names-job { grid-column: 1 / -1; margin: 6px 0 2px; font-size: 12px; color: var(--gm-c-dim); }
.gm-names-job:first-child { margin-top: 0; }
.gm-name { display: flex; align-items: baseline; gap: 8px; min-width: 0; padding: 4px 8px; border: 0; border-radius: var(--gm-r-s); background: none;
  color: var(--gm-c-main); font: 13px var(--gm-hei); text-align: left; cursor: pointer; transition: background var(--gm-t-quick) var(--gm-ease-out); }
.gm-name:hover { background: var(--gm-s-raise); }
.gm-name.on { background: var(--gm-s-gold); color: var(--gm-c-gold); }
.gm-name:focus-visible { outline: 1px solid var(--gm-l-gold); }
.gm-name > span { flex: 1; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.gm-name > i { font-style: normal; font-size: 12px; }
.gm-look-card { display: flex; flex-direction: column; gap: 4px; min-width: 0; padding: 6px 6px 8px; border: 1px solid var(--gm-l-line); border-radius: var(--gm-r-m);
  background: linear-gradient(rgba(40, 32, 22, .7), rgba(10, 8, 6, .6)); } /* 材质：外观卡片 */
.gm-look-card:hover { border-color: var(--gm-l-edge); }
.gm-look-card > b { font-weight: 600; font-size: 13px; line-height: 1.35; }
.gm-look-pic { display: flex; justify-content: center; align-items: flex-end; aspect-ratio: 1; border-radius: var(--gm-r-s);
  background: radial-gradient(65% 55% at 50% 55%, rgba(230, 200, 138, .1), rgba(0, 0, 0, .45)); } /* 材质：外观底下的光 */
.gm-look-pic canvas { width: 100%; height: 100%; object-fit: contain; }
.gm-looks.pet .gm-look-pic { aspect-ratio: 5 / 4; padding: 4px 2px; overflow: hidden; }
.gm-pet-grid { display: grid; width: 100%; align-self: stretch; justify-content: center; column-gap: 3%; align-items: end; justify-items: center; }
.gm-pet-grid canvas { width: 150%; height: auto; }
.gm-pet-lab { color: var(--gm-c-dim); font-size: 11px; line-height: 1.3; min-height: 1.3em; padding-top: 2px; }
.gm-look-note { font-size: 11px; line-height: 1.4; }
/* The price on its own line, then 送人 (small, its own width) and 购买 (gold, the rest of the line) side by side
   (用户，2026-10-05: in one line with the price they ran out of a card three to a row); owned: 已拥有 takes the
   price's line and 送人 stands alone at the left (docs/hud.md「商城页」). */
.gm-look-foot { display: flex; flex-direction: column; gap: 4px; margin-top: auto; padding-top: 2px; font-size: 12px; }
.gm-look-btns { display: flex; align-items: center; gap: var(--gm-sp-row); }
.gm-look-foot .gm-look-btns > .gm-btn.gold { flex: 1; }
.gm-look-foot .gm-btn { min-width: 0; }
.gm-keep { white-space: nowrap; } /* a name in 「」 does not break in two */
/* 道具 (商城价格, 改名卡): one row each, the picture, the name and what it is, the price and the buttons on the right. */
.gm-shop-items { display: flex; flex-direction: column; gap: var(--gm-sp-near); } /* 道具: one block of cards, 6 apart */
.gm-shop-item { display: flex; align-items: center; gap: 10px; padding: 8px 10px 8px 8px; border: 1px solid var(--gm-l-line); border-radius: var(--gm-r-m); background: var(--gm-s-card); }
.gm-shop-item:hover { border-color: var(--gm-l-edge); }
.gm-shop-item .gm-pic { width: 52px; height: 52px; }
.gm-shop-item-mid { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.gm-shop-item-mid > b { font-size: 15px; font-weight: 600; }
.gm-shop-item-desc { font-size: 12px; color: var(--gm-c-sub); }
.gm-shop-item-end { flex: none; display: flex; flex-direction: column; align-items: flex-end; gap: 6px; font-size: 13px; }
/* 送人 (docs/money.md「送人」): the recipient page's rows, one person each: name, 〈guild〉, 「已有」 on the right when
   they have it. Like the guild page, one known to be offline is dim (字·弱), as is one who has it, who does nothing. */
.gm-who-list { display: flex; flex-direction: column; }
.gm-who { display: flex; align-items: center; gap: 8px; width: 100%; height: var(--gm-h-lg); padding: 0 10px; border: 0; border-radius: var(--gm-r-s); background: none;
  color: var(--gm-c-main); font: 13px var(--gm-hei); text-align: left; cursor: pointer; transition: background var(--gm-t-quick) var(--gm-ease-out); }
.gm-who:hover { background: var(--gm-s-raise); }
.gm-who:focus-visible { outline: 1px solid var(--gm-l-gold); }
.gm-who > b { font-weight: 500; }
.gm-who.off, .gm-who.has { color: var(--gm-c-dim); }
.gm-who.has { cursor: default; }
.gm-who.has:hover { background: none; }
.gm-who-g { color: var(--gm-c-dim); font-size: 12px; }
.gm-who-st { margin-left: auto; font-size: 12px; color: var(--gm-c-dim); }
.gm-page .gm-tier-other .gm-input.num { width: 90px; }
.gm-page .gm-topup-pay { grid-template-columns: minmax(0, 1fr) 120px; gap: 10px; }
.gm-page .gm-topup-qr > div { width: 112px; height: 112px; }
.gm-page-body > .gm-btn.gold { align-self: flex-start; }
.gm-saved { margin-left: 8px; font-size: 12px; font-weight: 400; color: var(--gm-c-good); animation: gm-out var(--gm-t-slow) var(--gm-ease-in) var(--gm-t-hold) forwards; }
@keyframes gm-out { to { opacity: 0; } }
/* 交易行 (CLAUDE.md "交易行", sketch https://claude.ai/artifact/31Dc4onDL12JdTJmv1BPXS): the shelf,
   the slot that unfolds under its row, and 买东西. */
.gm-pic { width: 34px; height: 34px; flex: none; }
.gm-shelf { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: var(--gm-sp-near); }
.gm-sl { position: relative; height: 76px; border-radius: var(--gm-r-s); border: 1px solid var(--gm-l-line); background: var(--gm-s-sunk); display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px; min-width: 0; }
.gm-sl.click { cursor: pointer; }
.gm-holding .gm-sl.empty.click { cursor: default; } /* putting the thing in hand down is a game action: the arrow */
.gm-sl.click:hover { border-color: var(--gm-l-edge); }
.gm-sl .pr { font-size: 11px; font-variant-numeric: tabular-nums; white-space: nowrap; }
.gm-sl .t { font-size: 11px; color: var(--gm-c-dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; }
.gm-sl.empty { border-style: dashed; }
.gm-sl.empty .t { color: var(--gm-c-off); }
.gm-sl.sold { border-color: var(--gm-l-gold); background: var(--gm-s-gold); }
.gm-sl.back { border-color: var(--gm-l-edge); }
.gm-sl.on { border: 1px solid var(--gm-l-gold); }
.gm-sl.on::after { content: ""; position: absolute; left: 50%; bottom: -11px; margin-left: -6px; border: 6px solid transparent; border-bottom-color: var(--gm-l-edge); }
.gm-unfold { grid-column: 1 / -1; margin: 4px 0 2px; padding: 10px; border-radius: var(--gm-r-m); background: var(--gm-s-card); border: 1px solid var(--gm-l-edge); display: flex; flex-direction: column; gap: 8px; font-size: 13px; }
.gm-unfold .gm-input.num { width: 104px; }
.gm-unfold .gm-row { flex-wrap: nowrap; }
.gm-end { justify-content: flex-end; }
.gm-small { font-size: 12px; }
.gm-chips { display: flex; flex-wrap: wrap; gap: var(--gm-sp-near); } /* chips side by side: 6, like the shop's jump row (用户同意 2026-10-10) */
.gm-chips.gm-nowrap .gm-chip { padding: 0 8px; }
.gm-chip { box-sizing: border-box; height: var(--gm-h-sm); line-height: var(--gm-h-sm); padding: 0 10px; border: 0; white-space: nowrap; flex: none; border-radius: var(--gm-r-full); background: var(--gm-s-raise); color: var(--gm-c-dim); font-size: 12px; cursor: pointer; transition: background var(--gm-t-quick) var(--gm-ease-out); }
.gm-chip:hover { background: var(--gm-s-hover); color: var(--gm-c-main); }
.gm-chip.on { background: var(--gm-s-gold); color: var(--gm-c-bright); }
.gm-chip.gm-sort { margin-left: auto; height: var(--gm-h-lg); line-height: var(--gm-h-lg); padding: 0 12px; }
.gm-lots { display: flex; flex-direction: column; } /* 买东西: one block; the rows apart by their own padding and line */
.gm-lot { display: flex; align-items: center; gap: var(--gm-sp-row); padding: var(--gm-sp-near) 0; border-bottom: 1px solid var(--gm-l-faint); }
.gm-lot-text { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.gm-lot-text > span:first-child { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.gm-lot-text .gm-muted { font-size: 12px; }
/* 技能 (src/client/play/skill-page.ts): two columns of cards; picked = gold, the bar's slots light up. */
.gm-skills { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--gm-sp-near); }
.gm-skill { position: relative; display: flex; align-items: center; gap: 10px; height: 54px; box-sizing: border-box; padding: 0 8px; border: 1px solid var(--gm-l-line);
  border-radius: var(--gm-r-m); background: var(--gm-s-card); cursor: pointer; user-select: none; }
.gm-skill:hover { border-color: var(--gm-l-edge); }
.gm-skill.on { border-color: var(--gm-l-gold); background: var(--gm-s-gold); }
.gm-skill-ic { flex: none; display: flex; align-items: center; justify-content: center; width: 40px; height: 40px; box-sizing: border-box;
  border: 1px solid var(--gm-l-edge); background: var(--gm-s-sunk); }
.gm-skill-ic canvas { width: 36px; height: 34px; }
.gm-skill-ic.passive { border: 0; background: #8a7550; clip-path: polygon(7px 0, calc(100% - 7px) 0, 100% 7px, 100% calc(100% - 7px), calc(100% - 7px) 100%, 7px 100%, 0 calc(100% - 7px), 0 7px); } /* 材质：the passive's gold octagon frame (用户定 2026-10-02, option C) */
.gm-skill-ic.passive > canvas { clip-path: polygon(6px 0, calc(100% - 6px) 0, 100% 6px, 100% calc(100% - 6px), calc(100% - 6px) 100%, 6px 100%, 0 calc(100% - 6px), 0 6px); background: var(--gm-s-sunk); }
.gm-skill-mid { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 6px; }
.gm-skill-mid > b { font-weight: 400; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.gm-skill-lv { display: flex; align-items: center; gap: 6px; height: 8px; padding-left: 2px; }
.gm-skill-lv > i { flex: none; width: 6px; height: 6px; box-sizing: border-box; border: 1px solid var(--gm-l-edge); transform: rotate(45deg); }
.gm-skill-lv > i.on { border-color: var(--gm-l-gold); background: var(--gm-l-gold); }
.gm-train { flex: 1; height: 2px; margin-left: 2px; background: var(--gm-s-raise); }
.gm-train > i { display: block; height: 100%; background: var(--gm-l-edge); } /* our own bar: 线·框 (规范检查 2026-10-10: was marked 材质) */
.gm-train.slow > i { background: var(--gm-c-off); } /* dull while the character's level is short */
.gm-skill-key { flex: none; min-width: 24px; height: 24px; box-sizing: border-box; padding: 0 4px; border: 1px solid var(--gm-l-edge); border-radius: var(--gm-r-s);
  background: var(--gm-s-card); font-size: 12px; line-height: 22px; text-align: center; }
.gm-skill-key.none { border-color: var(--gm-l-line); background: var(--gm-s-sunk); color: var(--gm-c-off); }
.gm-skill-tag { flex: none; height: 18px; padding: 0 6px; border: 1px solid var(--gm-l-edge); border-radius: var(--gm-r-full); font-size: 11px; line-height: 16px; color: var(--gm-c-sub); }
.gm-skill-hint { position: absolute; left: 0; top: calc(100% + 4px); z-index: var(--gm-z-pop); height: 26px; padding: 0 10px; border: 1px solid var(--gm-l-edge); border-radius: var(--gm-r-m); background: var(--gm-s-float);
  font-size: 12px; line-height: 24px; color: var(--gm-c-sub); white-space: nowrap; pointer-events: none;
  animation: gm-out var(--gm-t-slow) var(--gm-ease-in) var(--gm-t-hold) forwards; }
/* 收购 / 买卖 (src/client/play/sell-page.ts): today's lot on a grid like the storage's, then what was sold. */
.gm-bad { color: var(--gm-c-bad); }
.gm-sell-grid { position: relative; flex: none; align-self: center; background-repeat: repeat; }
/* An item on its cells, drawn like the bag's (src/client/play/item-cells.ts): the cell picture behind, the bag picture centred. */
.gm-cell-it { position: relative; flex: none; box-sizing: border-box; display: flex; align-items: center; justify-content: center; background-size: 100% 100%; }
.gm-cell-it canvas { pointer-events: none; }
.gm-cell-it .gm-cell-short { position: absolute; inset: 0; background-size: 100% 100%; pointer-events: none; }
.gm-sell-it { position: absolute; } /* 物品是箭头（docs/ui-rules.md「叠放顺序和鼠标」）*/
.gm-cell-it small { position: absolute; right: 4px; bottom: 2px; font-size: 11px; font-weight: 700; color: var(--gm-c-main); }
/* 查看装备 (src/client/play/inspect-page.ts): his eight slots placed like the character page's gear block. */
.gm-gear { position: relative; flex: none; align-self: center; }
.gm-gear-slot { position: absolute; } /* 物品是箭头（docs/ui-rules.md「叠放顺序和鼠标」）*/
.gm-sell-back { display: flex; flex-direction: column; gap: var(--gm-sp-near); }
.gm-sell-row { display: flex; align-items: center; gap: 10px; padding: 4px 8px 4px 4px; border: 1px solid var(--gm-l-line); border-radius: var(--gm-r-m); background: var(--gm-s-card); }
.gm-sell-row:hover { border-color: var(--gm-l-edge); }
.gm-sell-mid { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.gm-sell-mid > b { font-weight: 400; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.gm-sell-mid > span { font-size: 11px; }
/* 告示栏 (src/client/play/board-page.ts, docs/hud.md「告示栏」): 写意见 pinned under the head, a box like the guild's 公告, the
   warning, the count and 交上去 under it; the tabs with 最近 N 天 on their right; each post a like box, the text, who and
   when under it; rows apart by their padding and a faint line, like 买东西. */
.gm-board-write { display: flex; flex-direction: column; gap: var(--gm-sp-near); margin-top: var(--gm-sp-section); }
.gm-board-write .gm-grp { margin: 0; }
.gm-board-write .gm-input:disabled { cursor: default; }
.gm-board-write .gm-input:disabled::placeholder { color: var(--gm-c-dim); } /* 写满了 / 禁言: said in the box, readable */
.gm-board-foot { display: flex; align-items: center; gap: var(--gm-sp-inner); }
.gm-board-foot > .gm-muted { flex: 1; min-width: 0; font-size: 12px; line-height: 1.5; }
.gm-board-count { flex: none; font-size: 12px; color: var(--gm-c-dim); font-variant-numeric: tabular-nums; }
.gm-board-days { margin-left: auto; align-self: center; font-size: 12px; color: var(--gm-c-dim); }
.gm-posts { display: flex; flex-direction: column; }
.gm-post { display: flex; align-items: flex-start; gap: var(--gm-sp-row); padding: var(--gm-sp-near) 0; border-bottom: 1px solid var(--gm-l-faint); }
.gm-like { flex: none; width: 40px; box-sizing: border-box; padding: var(--gm-sp-tight) 0; display: flex; flex-direction: column; align-items: center; gap: var(--gm-sp-hair);
  border: 1px solid var(--gm-l-edge); border-radius: var(--gm-r-s); background: var(--gm-s-sunk); color: var(--gm-c-dim); font: inherit; font-size: 12px; cursor: pointer; transition: background var(--gm-t-quick) var(--gm-ease-out); }
.gm-like b { font-size: 13px; font-weight: 500; color: var(--gm-c-main); font-variant-numeric: tabular-nums; }
.gm-like:hover { background: var(--gm-s-card); }
.gm-like.on { border-color: var(--gm-l-gold); color: var(--gm-c-gold); }
.gm-like.on b { color: var(--gm-c-gold); }
.gm-like:disabled { cursor: default; background: var(--gm-s-sunk); }
.gm-post-mid { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--gm-sp-hair); }
.gm-post-mid > p { overflow-wrap: anywhere; }
.gm-post-meta { display: flex; flex-wrap: wrap; gap: 0 var(--gm-sp-row); font-size: 12px; color: var(--gm-c-dim); }
.gm-good { color: var(--gm-c-good); }
/* 设置 (src/client/play/settings-page.ts, docs/hud.md「设置页」): two columns of rows, the name left and the switch or
   keycaps right; the row under the mouse lights up. */
.gm-set-cols { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 14px; }
.gm-set-col { display: flex; flex-direction: column; min-width: 0; }
.gm-set-row { box-sizing: border-box; height: 30px; display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 0 6px; margin: 0 -6px;
  border: 0; border-bottom: 1px solid var(--gm-l-faint); border-radius: 0; background: none; color: var(--gm-c-main); font: inherit; text-align: left; cursor: pointer; transition: background var(--gm-t-quick) var(--gm-ease-out); }
div.gm-set-row { cursor: default; }
.gm-set-row:hover { background: var(--gm-s-raise); } /* 指着升一档：行本身没有底，升到凸 */
.gm-set-row > span:first-child { min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.gm-switch { flex: none; position: relative; box-sizing: border-box; width: 34px; height: 18px; border-radius: var(--gm-r-full); border: 1px solid var(--gm-l-edge); background: var(--gm-s-card); }
.gm-switch::after { content: ""; position: absolute; top: 3px; left: 3px; width: 10px; height: 10px; border-radius: var(--gm-r-full); background: var(--gm-l-edge); }
.gm-switch.on { border-color: var(--gm-l-gold); background: var(--gm-s-gold); }
.gm-switch.on::after { left: auto; right: 3px; background: var(--gm-l-gold); }
.gm-caps { flex: none; display: flex; gap: 4px; }
.gm-cap { box-sizing: border-box; min-width: 46px; height: 22px; padding: 0 8px; border: 1px solid var(--gm-l-edge); border-radius: var(--gm-r-s); background: var(--gm-s-card);
  color: var(--gm-c-main); font: 12px var(--gm-hei); cursor: pointer; transition: background var(--gm-t-quick) var(--gm-ease-out); }
.gm-cap:hover { background: var(--gm-s-raise); } /* 底 → 凸，一档 */
.gm-cap.on { border-color: var(--gm-l-gold); background: var(--gm-s-gold); color: var(--gm-c-gold); }
.gm-cap.none { border-color: var(--gm-l-line); background: var(--gm-s-sunk); color: var(--gm-c-off); }
.gm-seg.sm { height: var(--gm-h-sm); font-size: 12px; }
.gm-set-fixed { margin: 0; display: flex; flex-wrap: wrap; gap: 6px 14px; font-size: 12px; color: var(--gm-c-dim); }
.gm-set-fixed > span { display: inline-flex; align-items: center; gap: 6px; }
.gm-set-fixed kbd { padding: 0 4px; border: 1px solid var(--gm-l-line); border-radius: var(--gm-r-s); font: 12px var(--gm-hei); color: var(--gm-c-sub); }
.gm-set-foot { margin-top: auto; display: flex; align-items: center; justify-content: space-between; gap: 10px; padding-top: 14px; }
/* 外观 (src/client/play/looks-page.ts, docs/hud.md「外观页」): the places as small boxes (what each wears now), the
   chosen one gold; the owned looks for it as cards, three to a row, the picture square on top and the name under it. */
.gm-lk-places { display: grid; gap: var(--gm-sp-near); }
.gm-lk-place { box-sizing: border-box; min-width: 0; height: 44px; display: flex; flex-direction: column; justify-content: center; align-items: flex-start; gap: 2px; padding: 0 8px;
  border: 1px solid var(--gm-l-line); border-radius: var(--gm-r-m); background: var(--gm-s-card); color: var(--gm-c-sub); font: 13px var(--gm-hei); text-align: left; cursor: pointer; }
.gm-lk-place > span { font-size: 12px; }
.gm-lk-place > b { max-width: 100%; font-weight: 400; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.gm-lk-place > b.worn { color: var(--gm-c-main); }
.gm-lk-place:hover { border-color: var(--gm-l-edge); }
.gm-lk-place.on { border-color: var(--gm-l-gold); background: var(--gm-s-gold); }
.gm-lk-cards { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--gm-sp-near); }
.gm-lk-card { box-sizing: border-box; min-width: 0; display: flex; flex-direction: column; align-items: center; gap: 4px; padding: 8px 8px 10px;
  border: 1px solid var(--gm-l-line); border-radius: var(--gm-r-m); background: var(--gm-s-card); color: var(--gm-c-main); font: 12px var(--gm-hei); cursor: pointer; }
.gm-lk-card:hover { border-color: var(--gm-l-edge); }
.gm-lk-card.on { border-color: var(--gm-l-gold); background: var(--gm-s-gold); color: var(--gm-c-gold); }
.gm-lk-card.none { justify-content: center; min-height: 100%; color: var(--gm-c-dim); }
.gm-lk-pic { width: 100%; aspect-ratio: 1; }
.gm-lk-card.none.on { color: var(--gm-c-gold); }

/* ---- The phone grip (src/client/play/touch.ts, docs/hud.md「手机」) ----------------------------------------
   Laid out for a phone on its side (about 852 × 393); everything sits in the corners, the middle is the fight. */
html.gm-touch-on #status:not(.reconnect) { display: none; } /* the admins' test line: on a phone the top line shows the ping */
html.gm-touch-on, html.gm-touch-on body, html.gm-touch-on #stage { touch-action: none; overscroll-behavior: none; -webkit-touch-callout: none; -webkit-user-select: none; }
#ui > .gm-touch, .gm-touch { position: fixed; inset: 0; pointer-events: none; z-index: var(--gm-z-ui); font: 12px var(--gm-hei); color: var(--gm-c-main); } /* #ui > * would make the whole screen its own: only its keys take taps */
.gm-touch > * { pointer-events: auto; outline: none; }
.gm-touch [hidden] { display: none !important; }
:where(.gm-touch) button { all: unset; box-sizing: border-box; position: absolute; } /* no hand: a phone has no pointer to hover */
/* left: the joystick zone (the base comes where the thumb lands; at rest it waits at the lower left) */
.gm-t-joyzone { position: absolute; left: 0; bottom: 0; width: 38%; height: 70%; }
/* our own drawing, not the original's steel ring: a faint ring and a soft ball */
.gm-t-joy { position: absolute; left: calc(env(safe-area-inset-left, 0px) + 56px); top: calc(100% - 157px); box-sizing: border-box; width: 108px; height: 108px; border-radius: var(--gm-r-full);
  border: 1.5px solid var(--gm-c-sub); background: radial-gradient(circle, color-mix(in srgb, var(--gm-s-sunk) 15%, transparent) 55%, color-mix(in srgb, var(--gm-s-sunk) 45%, transparent));
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--gm-s-sunk) 60%, transparent), 0 0 0 1px color-mix(in srgb, var(--gm-s-sunk) 50%, transparent); opacity: .45; pointer-events: none; } /* JS puts its middle under the thumb */
.gm-t-joy.act { opacity: .9; }
.gm-t-knob { position: absolute; left: calc(50% - 21px); top: calc(50% - 21px); width: 42px; height: 42px; border-radius: var(--gm-r-full);
  background: radial-gradient(circle at 38% 30%, var(--gm-c-sub), var(--gm-c-dim) 55%, var(--gm-c-off));
  box-shadow: 0 0 0 1.5px var(--gm-s-sunk), 0 2px 5px var(--gm-s-sunk); } /* a grey ball with the keys' dark edge: gold only says 「on」 (docs/hud.md「手机的按键」) */
/* 跑 / 走 (a 40 round key like 翻页 and 锁人): the fourth on 随机 / 回城 / 药's arc, at its top (78 out from the resting
   joystick's middle, 78° above the right; touch.ts QUICK_ARC; 用户 2026-10-13 选 C, 草图 https://claude.ai/artifact/42yR4MnAYZeVVEYBsVaJee );
   the running one, the walking one lit, as big as 药 and the scrolls.
   No ground under it, like the map key: the figure with a dark outline and a shadow (用户 2026-10-13 选 A, 草图 https://claude.ai/artifact/V4anBDUugk7b6Q5MiQBwsY ) */
.gm-t-walkkey { left: calc(env(safe-area-inset-left, 0px) + 106px); bottom: 159px; width: 40px; height: 40px; padding: 0; border-radius: var(--gm-r-full); display: grid; place-items: center;
  color: var(--gm-c-sub); filter: drop-shadow(0 1px 1.5px var(--gm-s-sunk)); }
.gm-t-walkkey.on { color: var(--gm-c-bright); filter: drop-shadow(0 0 5px color-mix(in srgb, var(--gm-c-bright) 85%, transparent)) drop-shadow(0 1px 1.5px var(--gm-s-sunk)); }
.gm-t-walkkey svg { width: 32px; height: 32px; fill: none; stroke: currentColor; stroke-width: 2.6; stroke-linecap: round; stroke-linejoin: round; pointer-events: none; }
.gm-t-walkkey svg circle { fill: currentColor; stroke: none; }
.gm-t-walkkey svg .o path { stroke: var(--gm-s-sunk); stroke-width: 4.6; }
.gm-t-walkkey svg .o circle { fill: var(--gm-s-sunk); }
/* 宝宝 (attack <-> rest, = Ctrl+A): one step past 跑 / 走 round the same arc (78 out, 114° above the right: 48 from it,
   touch.ts QUICK_ARC), only with a pet out. A paw drawn like 跑 / 走: no ground, grey, a dark outline and a shadow; resting,
   gold and glowing with a crescent moon; the paw 36 as in the sketch (用户 2026-10-13：「没有你的图片好看」; 选 B、攻击不标, 草图 https://claude.ai/artifact/83bd1pwJPvwvfszBzRWoxm ) */
.gm-t-petkey { left: calc(env(safe-area-inset-left, 0px) + 58px); bottom: 154px; width: 40px; height: 40px; padding: 0; border-radius: var(--gm-r-full); display: grid; place-items: center;
  color: var(--gm-c-sub); filter: drop-shadow(0 2px 2px var(--gm-s-sunk)); }
.gm-t-petkey.on { color: var(--gm-c-bright); filter: drop-shadow(0 0 5px color-mix(in srgb, var(--gm-c-bright) 85%, transparent)) drop-shadow(0 2px 2px var(--gm-s-sunk)); }
.gm-t-petkey svg { width: 36px; height: 36px; fill: currentColor; stroke: var(--gm-s-sunk); stroke-width: 1.5; pointer-events: none; overflow: visible; }
/* right (the user's sketch): the main key at the corner, one big key above it, four small ones round it, 翻页 above.
   The pictures are the skills' round icons (手机圆图标): full circles with the keys' one dark edge and shadow
   (docs/hud.md「手机的按键」). Cooling: a dark sweep and the seconds; short of MP: grey. */
.gm-t-keys { position: absolute; inset: 0; pointer-events: none; }
.gm-t-keys > * { pointer-events: auto; }
.gm-touch .gm-t-skill, .gm-t-main { border-radius: var(--gm-r-full); }
.gm-t-main { right: calc(env(safe-area-inset-right, 0px) + 63px); bottom: 26px; width: 74px; height: 74px; }
.gm-t-main .gm-t-ic { position: absolute; inset: 0; border-radius: var(--gm-r-full); overflow: hidden; }
.gm-touch .gm-t-skill canvas, .gm-t-main canvas { display: block; width: 100%; height: 100%; border-radius: var(--gm-r-full); box-shadow: 0 0 0 1.5px var(--gm-s-sunk), 0 2px 5px color-mix(in srgb, var(--gm-s-sunk) 80%, transparent); }
.gm-t-cd { position: absolute; inset: 0; border-radius: var(--gm-r-full); background: conic-gradient(color-mix(in srgb, var(--gm-s-sunk) 70%, transparent) var(--cd, 0%), transparent 0); pointer-events: none; }
.gm-t-cdn { position: absolute; inset: 0; display: grid; place-items: center; font: 700 15px var(--gm-num); color: var(--gm-c-main); pointer-events: none;
  text-shadow: -1px -1px 0 var(--gm-s-sunk), 1px -1px 0 var(--gm-s-sunk), -1px 1px 0 var(--gm-s-sunk), 1px 1px 0 var(--gm-s-sunk), 0 1px 2px var(--gm-s-sunk); }
.gm-touch .gm-t-skill.nomp canvas { filter: grayscale(.85) brightness(.6); }
.gm-touch canvas.square { box-shadow: 0 0 0 2px var(--gm-l-edge); } /* a skill without a round icon yet: its square art in a ring */
.gm-touch .gm-t-skill { width: 44px; height: 44px; }
.gm-touch .gm-t-skill.cancel canvas { box-shadow: 0 0 0 2px var(--gm-c-bad), 0 2px 5px color-mix(in srgb, var(--gm-s-sunk) 80%, transparent); } /* aiming, the thumb back on the key: let go and nothing is cast */
.gm-touch .gm-t-skill.empty { display: grid; place-items: center; } /* no ring: a small ＋, the whole key still takes the tap that puts a skill here */
.gm-t-plus { width: 14px; height: 14px; fill: none; stroke: var(--gm-c-gold); stroke-width: 3; stroke-linecap: round; opacity: .75; filter: drop-shadow(0 1px 1.5px var(--gm-s-sunk)); pointer-events: none; }
.gm-t-plus .o { stroke: var(--gm-s-sunk); stroke-width: 6; }
.gm-touch .down { filter: brightness(1.4); }
.gm-touch .gm-t-skill.on canvas, .gm-t-main.on canvas { box-shadow: 0 0 0 2px var(--gm-l-gold), 0 0 10px var(--gm-l-gold); }
/* 锁人: the one who hurt you most lately; the ring is his HP, his name under it in his head's colour */
.gm-t-lock { width: 40px; height: 40px; border-radius: var(--gm-r-full); display: grid; place-items: center;
  background: conic-gradient(var(--gm-c-bad) var(--hp, 100%), color-mix(in srgb, var(--gm-s-sunk) 60%, transparent) 0);
  box-shadow: 0 0 0 1.5px var(--gm-s-sunk), 0 2px 5px color-mix(in srgb, var(--gm-s-sunk) 80%, transparent); }
.gm-t-lock b { width: 32px; height: 32px; border-radius: var(--gm-r-full); display: grid; place-items: center; background: var(--gm-s-card); font: 700 15px var(--gm-kai); color: var(--gm-c-main); }
.gm-t-lock.lit { filter: drop-shadow(0 0 6px var(--gm-l-gold)); }
.gm-t-lockname { position: absolute; top: 42px; left: 50%; transform: translateX(-50%); white-space: nowrap; font-size: 11px;
  text-shadow: -1px -1px 0 var(--gm-s-sunk), 1px -1px 0 var(--gm-s-sunk), -1px 1px 0 var(--gm-s-sunk), 1px 1px 0 var(--gm-s-sunk), 0 1px 2px var(--gm-s-sunk); }
/* the party under the map's name (用户 2026-10-13 选 A, 草图 https://claude.ai/artifact/V6Xis2vhuuKWCqka3U1YyM): round keys like 锁人's,
   four a row; the name's first character, the ring his HP, the leader's crown (the desktop card's, 用户 2026-09-30), the job on a chip */
.gm-touch > .gm-t-party { position: absolute; left: calc(env(safe-area-inset-left, 0px) + 12px); top: 56px; display: grid; grid-template-columns: repeat(4, 40px); gap: var(--gm-sp-row); pointer-events: none; }
.gm-t-mate { position: relative; width: 40px; height: 40px; border-radius: var(--gm-r-full); display: grid; place-items: center; pointer-events: auto;
  background: conic-gradient(var(--gm-c-bad) var(--hp, 100%), color-mix(in srgb, var(--gm-s-sunk) 60%, transparent) 0);
  box-shadow: 0 0 0 1.5px var(--gm-s-sunk), 0 2px 5px color-mix(in srgb, var(--gm-s-sunk) 80%, transparent); }
.gm-touch .gm-t-mate[hidden] { display: none; }
.gm-t-mate b { width: 32px; height: 32px; border-radius: var(--gm-r-full); display: grid; place-items: center; background: var(--gm-s-card); font: 700 15px var(--gm-kai); color: var(--gm-c-main); }
.gm-t-mate.far { opacity: var(--gm-off); } /* out of sight */
.gm-t-mate.lit { filter: drop-shadow(0 0 6px var(--gm-l-gold)); } /* locked: as 锁人 */
.gm-t-mate .gm-t-crown { position: absolute; right: -2px; top: -3px; width: 12px; height: 9px; background: var(--gm-c-gold); clip-path: polygon(0 100%, 0 25%, 25% 60%, 50% 0, 75% 60%, 100% 25%, 100% 100%); filter: drop-shadow(0 0 1px var(--gm-s-sunk)); }
.gm-t-mate .gm-t-job { position: absolute; right: -3px; bottom: -2px; width: 15px; height: 15px; border-radius: var(--gm-r-full); display: grid; place-items: center; background: var(--gm-s-raise); color: var(--gm-c-sub); font-size: 11px; box-shadow: 0 0 0 1px var(--gm-s-sunk); }
/* 技能 (a long press on a skill key, a tap on an empty one; docs/hud.md「手机」): a sheet on the left reaching to the keys
   (touch.ts sets its width), the keys stay on the right and take taps and drags; the scene between is a little darker,
   a tap on it shuts the sheet; over one another in their order in .gm-touch (touch.ts), no z-index */
.gm-t-sheetscrim, .gm-t-sheet { display: none; }
.gm-touch.sheet .gm-t-sheetscrim { display: block; position: absolute; inset: 0; background: color-mix(in srgb, var(--gm-s-sunk) 30%, transparent); }
.gm-touch.sheet .gm-t-lock, .gm-touch.sheet .gm-t-main { pointer-events: none; }
.gm-touch.sheet .gm-t-sheet { display: block; position: absolute; left: 0; top: 0; bottom: 0; max-width: 560px; box-sizing: border-box; overflow: auto;
  padding: 0 var(--gm-sp-section) var(--gm-sp-inner) calc(env(safe-area-inset-left, 0px) + var(--gm-sp-section));
  background: var(--gm-s-card); border-right: 1px solid var(--gm-l-edge); box-shadow: 6px 0 18px color-mix(in srgb, var(--gm-s-sunk) 50%, transparent); }
.gm-t-sheet > .gm-ph { margin-bottom: var(--gm-sp-row); }
/* 没装上 first, then 已在键上 (dimmer, where each is under its name; the open key's 「这一格」 lit) */
.gm-t-shgrp { margin: 0 0 var(--gm-sp-tight); font-size: 12px; color: var(--gm-c-sub); }
.gm-t-shgrp small { margin-left: var(--gm-sp-tight); font-size: 12px; color: var(--gm-c-dim); }
.gm-t-shlist + .gm-t-shgrp { margin-top: var(--gm-sp-row); padding-top: var(--gm-sp-row); border-top: 1px solid var(--gm-l-faint); }
.gm-t-shlist { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: var(--gm-sp-hair) var(--gm-sp-tight); }
.gm-t-sheet .gm-t-sk { position: relative; display: grid; justify-items: center; align-content: start; gap: var(--gm-sp-tight); padding: var(--gm-sp-tight) 0; border-radius: var(--gm-r-s);
  font-size: 12px; color: var(--gm-c-main); text-align: center; touch-action: none; }
.gm-t-sk.on { color: var(--gm-c-sub); }
.gm-t-sk.on .gm-t-skic { opacity: .5; }
.gm-t-sk small { margin-top: calc(-1 * var(--gm-sp-hair)); font-size: 11px; color: var(--gm-c-dim); }
.gm-t-sk.here { background: var(--gm-s-raise); color: var(--gm-c-bright); }
.gm-t-sk.here small { color: inherit; }
.gm-t-sk.here .gm-t-skic { opacity: 1; }
.gm-t-skic, .gm-t-skic canvas { display: block; width: 40px; height: 40px; border-radius: var(--gm-r-full); }
.gm-t-sk.here .gm-t-skic canvas { box-shadow: 0 0 0 2px var(--gm-l-gold), 0 0 8px var(--gm-l-gold); }
.gm-t-shnone { margin: var(--gm-sp-section) 0; color: var(--gm-c-dim); }
/* the key a tapped skill goes on: lit gold. Dragging: the keys it can go on ringed faintly, the one under the thumb lit
   and a little bigger, the one it came off faint; the skill itself under the thumb */
.gm-touch .gm-t-skill.pick canvas { box-shadow: 0 0 0 3px var(--gm-l-gold), 0 0 14px var(--gm-l-gold); }
.gm-touch .gm-t-skill.pick.empty { box-shadow: 0 0 0 2px var(--gm-l-gold), 0 0 12px var(--gm-l-gold); }
.gm-touch.sheet .gm-t-plus { opacity: 1; }
.gm-touch.dragging .gm-t-skill.drop:not(.over) canvas { box-shadow: 0 0 0 1.5px var(--gm-s-sunk), 0 0 0 4px color-mix(in srgb, var(--gm-c-gold) 40%, transparent); }
.gm-touch.dragging .gm-t-skill.drop.empty:not(.over) { box-shadow: 0 0 0 1.5px color-mix(in srgb, var(--gm-c-gold) 55%, transparent); }
.gm-touch .gm-t-skill.over { transform: scale(1.12); transition: transform var(--gm-t-quick); }
.gm-touch .gm-t-skill.over canvas, .gm-touch .gm-t-skill.over.empty { box-shadow: 0 0 0 3px var(--gm-l-gold), 0 0 18px var(--gm-l-gold); }
.gm-touch .gm-t-skill.lift { opacity: .3; }
.gm-t-ghost { position: absolute; width: 52px; height: 52px; pointer-events: none; transform: scale(1.1); filter: drop-shadow(0 6px 8px var(--gm-s-sunk)); }
.gm-t-ghost canvas { display: block; width: 100%; height: 100%; border-radius: var(--gm-r-full); }
/* the − on a mage's or a taoist's outer key: 18 drawn at its upper left like an iPhone's app, 28 for the thumb; no shaking
   (用户 2026-10-13：「学习iphone里面删除app一样」) */
.gm-t-minus { position: absolute; left: -9px; top: -9px; width: 28px; height: 28px; display: grid; place-items: center; }
.gm-t-minus::before, .gm-t-minus::after { content: ""; grid-area: 1 / 1; }
.gm-t-minus::before { width: 18px; height: 18px; border-radius: var(--gm-r-full); background: var(--gm-s-raise); box-shadow: 0 0 0 1px var(--gm-c-dim), 0 1px 3px var(--gm-s-sunk); }
.gm-t-minus::after { width: 8px; height: 2px; border-radius: var(--gm-r-s); background: var(--gm-c-main); }
/* 随机, 回城, 药: on an arc up and right of the resting joystick (touch.ts QUICK_ARC; 用户 2026-10-13 选 A), the left thumb's,
   the same for every job. No ground under them, the thing itself is the key (docs/hud.md「手机的按键」), the count at its
   lower right; just used: a dark sweep; none left (or not here): grey */
.gm-touch > .gm-t-quick { position: absolute; left: env(safe-area-inset-left, 0px); bottom: 0; width: 0; height: 0; pointer-events: none; }
.gm-t-quick .gm-t-q { position: absolute; box-sizing: border-box; width: 40px; height: 40px; padding: var(--gm-sp-tight); pointer-events: auto; filter: drop-shadow(0 0 1px var(--gm-s-sunk)) drop-shadow(0 1px 2px var(--gm-s-sunk)); }
.gm-t-quick .gm-t-q.off { filter: grayscale(1) brightness(.55) drop-shadow(0 0 1px var(--gm-s-sunk)); }
.gm-t-quick .gm-t-q.off b { color: var(--gm-c-dim); }
.gm-t-quick .gm-t-cd { inset: 6px; }
.gm-t-quick b { position: absolute; right: 1px; bottom: 0; font: 700 12px var(--gm-num); color: var(--gm-c-main);
  text-shadow: -1px -1px 0 var(--gm-s-sunk), 1px -1px 0 var(--gm-s-sunk), -1px 1px 0 var(--gm-s-sunk), 1px 1px 0 var(--gm-s-sunk), 0 1px 2px var(--gm-s-sunk); }
.gm-t-quick canvas { display: block; width: 100%; height: 100%; object-fit: contain; }
/* top: the map key (Tab, no ground under it), the scene and the attack mode, the level after it; battery · time · ping; the chat key, the menu key */
.gm-t-map { left: calc(env(safe-area-inset-left, 0px) + 12px); top: 6px; width: 44px; height: 44px; }
.gm-t-map svg { position: absolute; left: 7px; top: 7px; width: 30px; height: 30px; filter: drop-shadow(0 1px 1.5px var(--gm-s-sunk)); }
.gm-t-map svg * { stroke-linejoin: round; }
/* shut: a dim grey-brown map, the pin dark */
.gm-t-map svg .a { fill: var(--gm-s-raise); }
.gm-t-map svg .b { fill: var(--gm-s-hover); }
.gm-t-map svg .r { fill: none; stroke: none; stroke-width: .8; stroke-dasharray: 1.2 1; }
.gm-t-map svg .k { fill: none; stroke: var(--gm-c-off); stroke-width: .9; }
.gm-t-map svg .o { fill: none; stroke: var(--gm-c-dim); stroke-width: 1.3; }
.gm-t-map svg .pin { fill: color-mix(in srgb, var(--gm-c-blood) 50%, var(--gm-s-raise)); stroke: var(--gm-s-sunk); stroke-width: .7; }
.gm-t-map svg .h { fill: var(--gm-s-raise); }
/* open (近看 / 全貌): gold paper, a red pin, a route, a ring of light */
.gm-t-map.lit svg { filter: drop-shadow(0 0 5px color-mix(in srgb, var(--gm-c-bright) 80%, transparent)) drop-shadow(0 1px 1.5px var(--gm-s-sunk)); }
.gm-t-map.lit svg .a { fill: color-mix(in srgb, var(--gm-c-gold) 75%, var(--gm-l-edge)); }
.gm-t-map.lit svg .b { fill: var(--gm-c-bright); }
.gm-t-map.lit svg .r { stroke: color-mix(in srgb, var(--gm-c-blood) 45%, var(--gm-l-edge)); }
.gm-t-map.lit svg .k { stroke: var(--gm-l-edge); }
.gm-t-map.lit svg .o { stroke: var(--gm-c-main); stroke-width: 1.2; }
.gm-t-map.lit svg .pin { fill: var(--gm-c-bad); stroke: color-mix(in srgb, var(--gm-c-blood) 50%, var(--gm-s-sunk)); }
.gm-t-map.lit svg .h { fill: var(--gm-c-main); }
.gm-t-mapname { position: absolute; left: calc(env(safe-area-inset-left, 0px) + 60px); top: 9px; text-shadow: 0 1px 2px var(--gm-s-sunk); pointer-events: none; white-space: nowrap; }
.gm-t-mapname small { margin-left: var(--gm-sp-row); font-size: 12px; color: var(--gm-c-sub); font-variant-numeric: tabular-nums; } /* the character's cell, right of the map's name */
.gm-t-modeline { position: absolute; left: calc(env(safe-area-inset-left, 0px) + 60px); top: 27px; display: flex; align-items: baseline; white-space: nowrap; pointer-events: none; } /* 和平 and the level share a baseline whatever fonts the phone has */
.gm-t-mode { position: relative; pointer-events: auto; font: 700 15px var(--gm-kai); letter-spacing: 4px; text-shadow: -1px -1px 0 var(--gm-s-sunk), 1px 1px 0 var(--gm-s-sunk), 0 0 3px var(--gm-s-sunk); }
/* battery · time · ping: top right beside the menu key, on the map name's line (the top middle is the Boss bar's and the banners') */
.gm-t-status { position: absolute; right: calc(env(safe-area-inset-right, 0px) + 106px); top: 4px; height: 44px; display: flex; gap: var(--gm-sp-row); align-items: center; font-size: 12px; font-variant-numeric: tabular-nums; text-shadow: 0 1px 2px var(--gm-s-sunk); pointer-events: none; } /* one line, its middle on the chat and menu keys' middle (用户 2026-10-13) */
.gm-t-ping { color: var(--gm-c-good); }
.gm-t-ping.slow { color: var(--gm-c-gold); }
.gm-t-ping.bad { color: var(--gm-c-bad); }
.gm-t-bat { width: 20px; height: 10px; border: 1px solid var(--gm-c-main); border-radius: var(--gm-r-s); background: linear-gradient(90deg, var(--gm-c-main) var(--b, 100%), transparent var(--b, 100%)); }
.gm-t-menu { right: calc(env(safe-area-inset-right, 0px) + 10px); top: 4px; width: 44px; height: 44px; }
.gm-t-menu svg.bars { position: absolute; left: 9px; top: 11px; width: 26px; height: 22px; fill: var(--gm-c-sub); stroke: var(--gm-s-sunk); stroke-width: 1.6; paint-order: stroke; filter: drop-shadow(0 1px 1.5px var(--gm-s-sunk)); } /* grey like 跑: gold says 「on」 */
/* the chat key: two bubbles drawn like the map key; gold while the chat is open, a red dot for a 私聊 not seen yet */
.gm-t-chat { right: calc(env(safe-area-inset-right, 0px) + 54px); top: 4px; width: 44px; height: 44px; }
.gm-t-chat svg { position: absolute; left: 7px; top: 7px; width: 30px; height: 30px; filter: drop-shadow(0 1px 1.5px var(--gm-s-sunk)); }
.gm-t-chat svg .a { fill: var(--gm-s-raise); }
.gm-t-chat svg .b { fill: var(--gm-s-hover); }
.gm-t-chat svg .o { fill: none; stroke: var(--gm-c-dim); stroke-width: 1.3; stroke-linejoin: round; }
.gm-t-chat svg .d { fill: var(--gm-c-dim); }
.gm-t-chat svg .pin { display: none; fill: var(--gm-c-bad); stroke: var(--gm-s-sunk); stroke-width: .8; }
.gm-t-chat.dot svg .pin { display: inline; }
.gm-t-chat.lit svg { filter: drop-shadow(0 0 5px color-mix(in srgb, var(--gm-c-bright) 80%, transparent)) drop-shadow(0 1px 1.5px var(--gm-s-sunk)); }
.gm-t-chat.lit svg .a { fill: color-mix(in srgb, var(--gm-c-gold) 75%, var(--gm-l-edge)); }
.gm-t-chat.lit svg .b { fill: var(--gm-c-bright); }
.gm-t-chat.lit svg .o { stroke: var(--gm-c-main); stroke-width: 1.2; }
.gm-t-chat.lit svg .d { fill: var(--gm-c-ink); }
/* the safe area's edges, measured (touch.ts chatBox) */
.gm-touch > .gm-t-safe { position: absolute; left: env(safe-area-inset-left, 0px); right: env(safe-area-inset-right, 0px); top: 0; height: 0; pointer-events: none; }
/* the chat open (its sheet, drawn by the HUD): the keys put away, like the menu's */
html.gm-chat-on .gm-touch > :not(.gm-t-rotate, .gm-t-safe) { display: none; } /* the safe area's edges stay measurable (touch.ts chatBox) */
/* the level on the attack mode's line, starting under the coordinates, written like them (用户 2026-10-13：「lv和上方的坐标没有对齐」
   「字体和颜色也需要向上方的坐标对齐」; touch.ts puts it there) */
.gm-t-level { font-size: 12px; color: var(--gm-c-sub); font-variant-numeric: tabular-nums; text-shadow: 0 1px 2px var(--gm-s-sunk); pointer-events: none; white-space: nowrap; }
/* held upright: one line, turn it sideways */
/* held upright: turn it sideways; under it how to unlock a locked screen (iPhone: Apple's button, as it looks on → off) */
.gm-t-rotate { display: none; position: fixed; inset: 0; box-sizing: border-box; padding: 0 var(--gm-sp-page); background: var(--gm-s-sunk); color: var(--gm-c-main); flex-direction: column; align-items: center; justify-content: center; gap: var(--gm-sp-section); text-align: center; }
.gm-t-rotate b { font-size: 17px; font-weight: 500; letter-spacing: 2px; }
.gm-t-rotate p { margin: 0; max-width: 300px; font-size: 13px; line-height: 1.8; color: var(--gm-c-sub); }
.gm-t-locks { display: flex; align-items: center; gap: var(--gm-sp-section); }
.gm-t-locks svg { width: 60px; height: 60px; }
.gm-t-locks svg.to { width: 24px; height: 12px; fill: none; stroke: var(--gm-c-dim); stroke-width: 1.5; }
.gm-t-locks .ring, .gm-t-locks .sh { fill: none; stroke-width: 3; stroke-linecap: round; }
.gm-t-locks .sh { stroke-width: 2.6; }
.gm-t-locks .lk-on .bg { fill: #fff; } /* 材质：苹果控制中心「屏幕方向锁定」开着的样子（白底红锁） */
.gm-t-locks .lk-on .ring, .gm-t-locks .lk-on .sh { stroke: #ff3b30; } /* 材质：同上 */
.gm-t-locks .lk-on .head, .gm-t-locks .lk-on .lk { fill: #ff3b30; } /* 材质：同上 */
.gm-t-locks .lk-off .bg { fill: rgba(120, 120, 120, .45); } /* 材质：关着的样子（灰底、灰圈、白色开锁） */
.gm-t-locks .lk-off .ring { stroke: #a5a5a5; } /* 材质：同上 */
.gm-t-locks .lk-off .head { fill: #a5a5a5; } /* 材质：同上 */
.gm-t-locks .lk-off .sh { stroke: #fff; } /* 材质：同上 */
.gm-t-locks .lk-off .lk { fill: #fff; } /* 材质：同上 */
@media (orientation: portrait) { .gm-t-rotate { display: flex; z-index: var(--gm-z-alarm); } }
/* the 主屏幕 card (iPhone, once): a 提示卡 on a phone held sideways, under the top line */
.gm-home { top: 56px; bottom: auto; width: min(440px, calc(100vw - 32px)); }
/* ---- The phone's menu (src/client/play/phone-menu.ts, docs/hud.md「手机的菜单」) -----------------------------------
   A sheet on the right; the strip on the left stays the fight (a tap there closes it). The HUD draws the picked
   thing's card into the detail column's top part, on its canvas over the DOM (no tooltips on a phone). */
html.gm-pm-on .gm-touch > :not(.gm-t-rotate, .gm-t-safe) { display: none; } /* the safe area's edges stay measurable (touch.ts chatBox) */
.gm-pm { position: fixed; inset: 0; z-index: var(--gm-z-ui); font: 13px var(--gm-hei); color: var(--gm-c-main); -webkit-user-select: none; user-select: none; }
.gm-pm[hidden] { display: none; }
.gm-pm-scrim { position: absolute; left: 0; top: 0; bottom: 0; width: calc(env(safe-area-inset-left, 0px) + 170px); }
.gm-pm-sheet { position: absolute; top: 0; bottom: 0; right: 0; left: calc(env(safe-area-inset-left, 0px) + 170px); display: flex; border-left: 1px solid var(--gm-l-edge); }
.gm-pm-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
/* the tabs down the sheet's left edge (用户 2026-10-13): 楷书, the lit one gold with a gold line on its left */
.gm-pm-tabs { flex: 0 0 56px; display: flex; flex-direction: column; background: var(--gm-s-float); border-right: 1px solid var(--gm-l-line); }
.gm-pm-tabs button { flex: 1; min-height: 0; padding: 0; border: 0; background: none; color: var(--gm-c-dim); font: 700 17px/1 var(--gm-kai); letter-spacing: .1em; position: relative; }
.gm-pm-tabs button.on { color: var(--gm-c-gold); background: var(--gm-s-gold); }
.gm-pm-tabs button.on::after { content: ""; position: absolute; left: 0; top: 18%; bottom: 18%; width: 2px; background: var(--gm-l-gold); }
.gm-pm-tabs button[hidden] { display: none; }
.gm-pm-body { flex: 1; min-height: 0; position: relative; background: var(--gm-s-float); }
.gm-pm-body.dom { padding: var(--gm-sp-inner) calc(env(safe-area-inset-right, 0px) + var(--gm-sp-section)) 0 var(--gm-sp-section); }
.gm-pm-own { position: absolute; inset: 0; display: flex; }
.gm-pm-own[hidden] { display: none; }
.gm-pm-left { flex: 0 0 auto; width: 236px; display: flex; flex-direction: column; padding: var(--gm-sp-section); border-right: 1px solid var(--gm-l-line); }
.gm-pm-right { flex: 1; min-width: 0; display: flex; flex-direction: column; padding: var(--gm-sp-section) calc(env(safe-area-inset-right, 0px) + var(--gm-sp-section)) var(--gm-sp-section) var(--gm-sp-section); }
.gm-pm-list { min-width: 0; }
.gm-pm-under { flex: 1; min-height: 0; margin-top: var(--gm-sp-section); display: flex; flex-direction: column; }
.gm-pm-card { flex: 1; min-height: 0; } /* the HUD draws the picked thing's card here, without its frame */
.gm-pm-acts { flex: none; display: flex; flex-wrap: wrap; gap: var(--gm-sp-near); margin-top: auto; padding-top: var(--gm-sp-inner); }
.gm-pm-acts:empty { display: none; }
.gm-pm-lbl { display: flex; justify-content: space-between; margin-bottom: var(--gm-sp-near); font-size: 12px; color: var(--gm-c-sub); }
.gm-pm-lbl b { color: var(--gm-c-main); font-weight: 500; font-variant-numeric: tabular-nums; }
.gm-pm-grid { position: relative; background-repeat: repeat; }
.gm-pm-grid .gm-cell-it { position: absolute; }
.gm-pm .gm-cell-it.sel { outline: 2px solid var(--gm-l-gold); outline-offset: -2px; } /* drawn last in the grid, so its ring is on top */
.gm-pm-stats { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--gm-sp-row) var(--gm-sp-tight); }
.gm-pm-stats div { display: flex; flex-direction: column; align-items: center; gap: var(--gm-sp-hair); }
.gm-pm-stats span { font-size: 11px; color: var(--gm-c-dim); white-space: nowrap; }
.gm-pm-stats b { font-size: 13px; font-weight: 700; font-variant-numeric: tabular-nums; white-space: nowrap; }
/* the desktop's gear places (EQUIP_LAYOUT × 0.8), in the column's middle */
.gm-pm-gear { position: relative; flex: none; align-self: center; }
.gm-pm-gear[hidden] { display: none; }
.gm-pm-gear > * { position: absolute; }
.gm-pm-empty { background-size: 100% 100%; }
/* An NPC's window on a phone (phone-menu.ts): the NPC's head in place of the tabs, its things left, the bag right. */
.gm-pm-npchead { flex: none; display: flex; align-items: center; gap: var(--gm-sp-row); height: 44px; padding: 0 calc(env(safe-area-inset-right, 0px) + var(--gm-sp-row)) 0 var(--gm-sp-section); background: var(--gm-s-float); border-bottom: 1px solid var(--gm-l-line); }
.gm-pm-npchead[hidden], .gm-pm-tabs[hidden], .gm-pm-npc[hidden] { display: none; }
.gm-pm-npchead > b { flex: none; font: 700 20px/1 var(--gm-kai); letter-spacing: .14em; color: var(--gm-c-gold); }
.gm-pm-npchead > span { flex: 1; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font-size: 12px; color: var(--gm-c-dim); }
.gm-pm-npc { position: absolute; inset: 0; display: flex; }
.gm-pm-col { flex: 1 1 0; min-width: 0; position: relative; display: flex; flex-direction: column; padding: var(--gm-sp-section); overflow: hidden; }
.gm-pm-block { align-self: center; max-width: 100%; display: flex; flex-direction: column; }
.gm-pm-block > .gm-pm-chips, .gm-pm-block > .gm-pm-lbl:first-child { height: var(--gm-h-sm); flex-wrap: nowrap; align-items: center; margin-bottom: var(--gm-sp-row); }
.gm-pm-col + .gm-pm-col { border-left: 1px solid var(--gm-l-line); padding-right: calc(env(safe-area-inset-right, 0px) + var(--gm-sp-section)); }
.gm-pm-chips { flex: none; margin-bottom: var(--gm-sp-row); }
/* the NPC's grid and the bag's start on one line (用户 2026-10-13：「格子做到平齐吧」): the chips row and a label row are one height */
.gm-pm-col > .gm-pm-chips, .gm-pm-col > .gm-pm-lbl:first-child { height: var(--gm-h-sm); flex-wrap: nowrap; align-items: center; margin-bottom: var(--gm-sp-row); }
.gm-pm-goldlbl { margin-top: var(--gm-sp-row); }
.gm-pm-goldrow { display: flex; gap: var(--gm-sp-near); align-items: center; }
.gm-pm-goldin { flex: 1; min-width: 0; height: var(--gm-h-md); font-variant-numeric: tabular-nums; }
.gm-pm-claims { display: flex; flex-direction: column; gap: var(--gm-sp-hair); overflow: auto; min-height: 0; }
.gm-pm-claim { display: flex; align-items: center; gap: var(--gm-sp-row); padding: var(--gm-sp-hair) var(--gm-sp-near); border-radius: var(--gm-r-s); }
.gm-pm-claim.sel { background: var(--gm-s-raise); }
.gm-pm-claim span { flex: 1; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.gm-pm-claim small { font-size: 11px; color: var(--gm-c-dim); }
.gm-pm-claim > * { pointer-events: none; }
.gm-pm-none { padding: var(--gm-sp-row) 0; font-size: 12px; color: var(--gm-c-dim); }
/* the picked thing under the bag: a section under a line (no frame in the frame), the HUD's card in it */
.gm-pm-pick { flex: 1; min-height: 0; display: flex; flex-direction: column; margin-top: var(--gm-sp-section); padding-top: var(--gm-sp-inner); border-top: 1px solid var(--gm-l-line); }
.gm-pm-pick .gm-pm-card { flex: 1; min-height: 0; }
/* The menu's pages on a phone (panel-pages.ts split()): no title (the tab says it), two columns each scrolling on its own. */
.gm-page.phone .gm-page-head { margin-bottom: var(--gm-sp-row); }
.gm-page.phone .gm-ph { display: none; } /* its title and state are on the menu's head (phone-menu.ts) */
.gm-page.phone .gm-page-head:not(:has(> :not(.gm-ph))) { display: none; }
.gm-pm-npchead .gm-pm-headstate { flex: 1; text-align: right; font-size: 12px; color: var(--gm-c-dim); }
.gm-pm-headstate b { font-size: 13px; font-weight: 500; color: var(--gm-c-main); font-variant-numeric: tabular-nums; }
.gm-pm-headstate b.gm-gold { color: var(--gm-c-gold); }
.gm-pm-headstate b.gm-coin { color: var(--gm-c-coin); }
.gm-page.phone .gm-pcol .gm-row.gm-nowrap { flex-wrap: wrap; } /* 交易行's search row: the box on its own line, the rest under it */
.gm-page.phone .gm-pcol .gm-row.gm-nowrap > .gm-input { flex: 1 0 100%; }
.gm-page.phone .gm-page-body:has(> .gm-pcols) { overflow: hidden; padding: 0; margin-right: 0; }
.gm-pcols { flex: 1; min-height: 0; display: flex; gap: var(--gm-sp-section); }
.gm-pcol { flex: 1 1 0; min-width: 0; overflow-y: auto; overflow-x: hidden; display: flex; flex-direction: column; gap: 10px; padding-bottom: 10px; overscroll-behavior: contain; scrollbar-width: none; }
.gm-pcol + .gm-pcol { border-left: 1px solid var(--gm-l-line); padding-left: var(--gm-sp-section); }
.gm-pcol > :first-child { margin-top: 0; }
.gm-pcol.gm-lk-left { flex: 0 0 220px; }
.gm-page.phone .gm-shelf { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.gm-page.phone .gm-tiers { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.gm-page.phone .gm-lk-place { flex-direction: row; justify-content: space-between; align-items: center; }
.gm-pick-bag { display: flex; flex-wrap: wrap; gap: var(--gm-sp-hair); }
.gm-pick-bag .gm-sl { width: 40px; height: 40px; }
.gm-pick-bag .gm-sl small { position: absolute; right: 2px; bottom: 0; font-size: 11px; font-weight: 700; }
/* 商城 on a phone: its jump row a column on the left, the list on the right (样机) */
.gm-page.phone[data-tab="shop"]:has(.gm-page-head > .gm-jump) { flex-direction: row; }
.gm-page.phone[data-tab="shop"] .gm-page-head:has(> .gm-jump) { flex: 0 0 88px; margin: 0 var(--gm-sp-section) 0 0; display: flex; flex-direction: column; }
.gm-page.phone[data-tab="shop"] .gm-jump { flex-direction: column; margin-top: var(--gm-sp-row); }
.gm-page.phone[data-tab="shop"] .gm-jump .gm-chip { height: var(--gm-h-md); line-height: var(--gm-h-md); text-align: center; }
.gm-page.phone .gm-seg button { white-space: nowrap; }
/* 电脑上看手机版 (/play/?phone, src/render/resolution.ts phoneView): the page is an iPhone's screen held sideways in the
   window's top left corner; its transform makes it the box every fixed thing (canvases, pages, the menu) sits in. At
   (0, 0), so the pages placed by the window's coordinates (a canvas's getBoundingClientRect) land where they should: in
   the middle they were off by the frame's offset (用户 2026-10-13: the 充值 page's tiers at the bottom right). */
html.gm-phone-view body { position: relative; width: 852px; height: 393px; overflow: hidden; transform: translateZ(0); box-shadow: 1px 1px 0 var(--gm-l-edge); }
/* iPhone from the home screen with a viewport short of the screen (src/render/resolution.ts fillIphoneScreen): the page
   is the screen's size, and its transform makes it the box every fixed thing sits in, as in the phone view. */
html.gm-fill, html.gm-fill body { height: var(--gm-screen-h); }
html.gm-fill body { position: relative; overflow: hidden; transform: translateZ(0); }
/* 角色页: the picked thing's numbers under the bag, plainly (no card) */
.gm-pm-detail { flex: 1; min-height: 0; overflow: auto; display: flex; flex-direction: column; gap: var(--gm-sp-near); margin-top: var(--gm-sp-section); }
.gm-pm-detail:empty { display: none; }
.gm-pm-dname { font-size: 15px; font-weight: 700; }
.gm-pm-drows { display: flex; flex-wrap: wrap; gap: var(--gm-sp-tight) var(--gm-sp-page); } /* each value right after its name (用户 2026-10-13：「太开了」) */
.gm-pm-drows div { display: flex; align-items: baseline; gap: var(--gm-sp-near); }
.gm-pm-drows span { font-size: 12px; color: var(--gm-c-dim); }
.gm-pm-drows b { font-size: 13px; font-weight: 700; font-variant-numeric: tabular-nums; }
.gm-pm-dfoot { margin: 0; font-size: 12px; color: var(--gm-c-dim); }
/* 交易行 on a phone (panels.ts phoneMarket): a picked lot, the bag's picked thing, the shelf's terms on the chips' row */
.gm-page.phone .gm-lot.on { box-shadow: inset 0 0 0 1.5px var(--gm-l-gold); }
.gm-page .gm-pm-grid .gm-cell-it.sel { outline: 2px solid var(--gm-l-gold); outline-offset: -2px; }
.gm-chips .gm-r { text-align: right; font-size: 12px; white-space: nowrap; }
.gm-pm-dtext { margin: 0; font-size: 13px; line-height: 1.6; color: var(--gm-c-sub); }
/* 交易行 on a phone: the 挂出 box under the picked thing's numbers, no frame of its own and no second name */
.gm-page.phone .gm-pm-detail .gm-unfold { padding: 0; border: 0; background: none; }
.gm-page.phone .gm-pm-detail .gm-unfold > :first-child { display: none; }
.gm-pm-dcore { margin: 0; font-size: 13px; color: var(--gm-c-sub); }
.gm-pm-dcore b { font-size: 15px; color: var(--gm-c-gold); user-select: text; }
/* 挂出 / 取消 at the start of their row like every phone button row, the fee after them, one height */
.gm-page.phone .gm-pm-detail .gm-unfold .gm-row:last-child > .gm-grow { display: none; }
.gm-page.phone .gm-pm-detail .gm-unfold .gm-row:last-child > .gm-muted { order: 3; margin-left: var(--gm-sp-row); }
.gm-page.phone .gm-pm-detail .gm-btn.gold { height: var(--gm-h-md); line-height: var(--gm-h-md); padding: 0 14px; }
/* the phone menu's button rows: the gold one as tall as the rest (用户 2026-10-13：「这个穿上的按钮 是不是不太对劲」) */
.gm-pm .gm-pm-acts .gm-btn.gold { height: var(--gm-h-md); line-height: var(--gm-h-md); padding: 0 14px; }

/* ---- A phone's 弹窗 (docs/ui-rules.md「手机：弹窗」, 用户 2026-10-13, 草图 https://claude.ai/artifact/V6Xis2vhuuKWCqka3U1YyM) ------------- */
/* ① a question in the middle (393 high: at 38% it met the map's name); its buttons a thumb's 40, no keys on them (ui.ts dialogButton) */
html.gm-touch-on .gm-dlg { top: 50%; }
html.gm-touch-on .gm-dlg .gm-row .gm-btn { height: 40px; line-height: 40px; }
/* ② the notice slot: one card at a time in the top middle, the rest wait (ui.ts notice, placeNotices sets its top) */
#gm-slot { position: fixed; z-index: var(--gm-z-pop); left: 50%; top: 56px; transform: translateX(-50%); }
#gm-slot .gm-inv { width: auto; max-width: calc(100vw - 32px); min-height: 52px; gap: var(--gm-sp-row); padding: var(--gm-sp-near) var(--gm-sp-near) var(--gm-sp-near) var(--gm-sp-section); font-size: 13px; }
#gm-slot .gm-inv button { width: 40px; height: 40px; line-height: 40px; font-size: 15px; }
#gm-slot .gm-inv .gm-btn { width: auto; padding: 0 var(--gm-sp-section); }
.gm-inv-more { margin-left: var(--gm-sp-row); font-size: 12px; color: var(--gm-c-dim); white-space: nowrap; }
/* the pass and bind offers' card, opened from the slot: a sheet from the right like the menu's, the fight's strip left of
   it (a tap there closes it; docs/ui-rules.md「手机：拉出的页」) */
html.gm-touch-on .gm-dlg.gm-sheet { left: calc(env(safe-area-inset-left, 0px) + 170px); right: 0; top: 0; bottom: 0; width: auto; transform: none; overflow-y: auto;
  border: 0; border-left: 1px solid var(--gm-l-edge); border-radius: 0; padding-right: calc(env(safe-area-inset-right, 0px) + var(--gm-sp-page)); }
.gm-sheet-scrim { position: fixed; left: 0; top: 0; bottom: 0; width: calc(env(safe-area-inset-left, 0px) + 170px); z-index: var(--gm-z-pop); }
html.gm-sheet-on .gm-touch > :not(.gm-t-rotate, .gm-t-safe) { display: none; }
/* ④ the player menu (a long press on a player, a party key): a thumb's 40 a line */
html.gm-touch-on .gm-item { min-height: 40px; display: flex; align-items: center; }
