/* ==========================================================================
   牌友汇（客户端）· 小程序风格样式表
   - 手机优先：360px ~ 桌面自适应，宽屏下居中成「手机壳」形态
   - 适配：刘海屏安全区、横竖屏、触摸操作
   - 结构：.phone > (.navbar / .view / .tabbar)
   ========================================================================== */

:root {
  /* 色板：微信小程序风格（浅色主题） */
  --app-bg: #f6f7fb;
  --surface: #ffffff;
  --surface-2: #f2f4f8;
  --ink: #14161a;
  --ink-2: #3d4657;
  --muted: #8a94a6;
  --line: #eceff5;
  --brand: #07c160;
  --brand-d: #06ad56;
  --brand-ink: #0f5132;
  --accent: #ff9f1a;
  --danger: #fa5151;
  --blue: #2f6fed;
  --felt-1: #1b8f5b;
  --felt-2: #0b3f27;
  --radius: 14px;
  --radius-lg: 18px;
  --shadow: 0 4px 16px rgba(20, 30, 55, .07);
  --shadow-lg: 0 16px 44px rgba(15, 25, 45, .20);
  --safe-t: env(safe-area-inset-top, 0px);
  --safe-b: env(safe-area-inset-bottom, 0px);
  --navbar-h: 46px;
  --tabbar-h: 52px;
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
html, body { height: 100%; }
body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
  background: #e7ebf2;
  color: var(--ink);
  font-size: 15px;
  line-height: 1.5;
  overflow: hidden;
  -webkit-user-select: none; user-select: none;
  -webkit-text-size-adjust: 100%;
  overscroll-behavior: none;
}
input, textarea { -webkit-user-select: text; user-select: text; }
.hidden { display: none !important; }
button { font-family: inherit; }
h1, h2, h3, h4 { margin: 0; font-weight: 700; }
p { margin: 0 0 8px; }

/* ---------- 手机壳 ---------- */
.phone {
  position: relative;
  width: 100%;
  height: 100vh;
  height: 100dvh;
  max-width: 480px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  background: var(--app-bg);
  overflow: hidden;
}
@media (min-width: 560px) {
  body { display: flex; align-items: center; justify-content: center; }
  .phone {
    height: min(880px, calc(100dvh - 32px));
    border-radius: 24px;
    box-shadow: 0 24px 70px rgba(15, 25, 45, .22);
    border: 1px solid #dde3ee;
  }
}

/* ---------- 顶部导航栏 ---------- */
.navbar {
  flex: 0 0 auto;
  padding-top: var(--safe-t);
  height: calc(var(--navbar-h) + var(--safe-t));
  display: flex; align-items: center;
  background: var(--surface);
  border-bottom: 1px solid var(--line);
  position: relative; z-index: 30;
}
.nav-left, .nav-right { display: flex; align-items: center; gap: 4px; padding: 0 8px; min-width: 62px; }
.nav-right { justify-content: flex-end; }
.nav-title {
  flex: 1; text-align: center; font-size: 16px; font-weight: 700;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.nav-btn {
  border: none; background: transparent; font-size: 18px; line-height: 1;
  padding: 6px 8px; border-radius: 10px; cursor: pointer; color: var(--ink-2);
}
.nav-btn:active { background: var(--surface-2); }
.nav-btn .nav-txt { font-size: 13px; font-weight: 600; }
.nav-back { display: inline-flex; align-items: center; gap: 2px; font-size: 14px; font-weight: 600; color: var(--ink-2); }

/* ---------- 视图容器 ---------- */
.view {
  flex: 1 1 auto; min-height: 0; overflow-y: auto; overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
  display: flex; flex-direction: column;
}
.view.no-scroll { overflow: hidden; }

/* ---------- 底部标签栏 ---------- */
.tabbar {
  flex: 0 0 auto;
  height: calc(var(--tabbar-h) + var(--safe-b));
  padding-bottom: var(--safe-b);
  display: flex; background: var(--surface);
  border-top: 1px solid var(--line);
}
.tabbar.hidden { display: none !important; }
.tab-item {
  flex: 1; position: relative; display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 2px; border: none; background: transparent; cursor: pointer; color: var(--muted);
  font-size: 10.5px; font-weight: 600; padding: 4px 0;
}
.tab-item .ti-ico { font-size: 20px; line-height: 1; filter: grayscale(1) opacity(.55); }
.tab-item.on { color: var(--brand); }
.tab-item.on .ti-ico { filter: none; }

/* ---------- 按钮 ---------- */
.btn {
  border: 1px solid transparent; border-radius: 10px; padding: 9px 16px;
  font-size: 14px; font-weight: 600; cursor: pointer; background: var(--brand); color: #fff;
  transition: transform .08s ease, filter .15s ease, background .15s ease;
  white-space: nowrap;
}
.btn:hover { filter: brightness(1.05); }
.btn:active { transform: translateY(1px); filter: brightness(.96); }
.btn:disabled { opacity: .45; cursor: not-allowed; filter: none; }
.btn-sm { padding: 6px 12px; font-size: 13px; border-radius: 9px; }
.btn-lg { padding: 13px 26px; font-size: 16px; border-radius: 12px; }
.btn-ghost { background: var(--surface-2); color: var(--ink); border-color: var(--line); }
.btn-outline { background: #fff; color: var(--brand-d); border-color: var(--brand); }
.btn-accent { background: var(--accent); color: #3a2a00; }
.btn-danger { background: var(--danger); }
.btn-blue { background: var(--blue); }
.btn-block { width: 100%; }
.btn-mini { padding: 4px 9px; font-size: 12px; border-radius: 8px; }

/* ---------- 通用块 ---------- */
.panel { background: var(--surface); border-radius: var(--radius); box-shadow: var(--shadow); overflow: hidden; }
.panel-hd {
  padding: 13px 15px; border-bottom: 1px solid var(--line);
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
}
.panel-hd h3 { font-size: 15px; }
.panel-bd { padding: 15px; }
.muted { color: var(--muted); }
.tiny { font-size: 12px; }
.center { text-align: center; }
.row { display: flex; gap: 10px; align-items: center; }
.row-wrap { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.spread { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.mt8 { margin-top: 8px; } .mt12 { margin-top: 12px; } .mt16 { margin-top: 16px; } .mt24 { margin-top: 24px; }
.stack { display: flex; flex-direction: column; gap: 10px; }
.pad { padding: 12px; }

/* 列表行（小程序 cell） */
.cell {
  display: flex; align-items: center; gap: 12px; padding: 13px 15px;
  background: var(--surface); border-bottom: 1px solid var(--line); cursor: pointer;
}
.cell:last-child { border-bottom: none; }
.cell:active { background: var(--surface-2); }
.cell .c-ico {
  width: 38px; height: 38px; border-radius: 11px; display: grid; place-items: center;
  font-size: 20px; background: var(--surface-2); flex: 0 0 auto;
}
.cell .c-main { flex: 1; min-width: 0; }
.cell .c-title { font-size: 15px; font-weight: 600; }
.cell .c-sub { font-size: 12px; color: var(--muted); margin-top: 2px; }
.cell .c-arrow { color: #c6ccd8; font-size: 15px; }
.cell-group { border-radius: var(--radius); overflow: hidden; box-shadow: var(--shadow); }

/* ---------- 登录页 ---------- */
.login-page {
  flex: 1; display: flex; flex-direction: column; padding: 26px 22px calc(24px + var(--safe-b));
  background: linear-gradient(170deg, #e8f8ef 0%, var(--app-bg) 42%);
  overflow-y: auto;
}
.login-hero { text-align: center; padding: 18px 0 8px; }
.login-logo {
  width: 78px; height: 78px; margin: 0 auto 12px; border-radius: 22px;
  background: linear-gradient(160deg, #0f9c5d, #0b6b3f);
  display: grid; place-items: center; font-size: 42px;
  box-shadow: 0 12px 30px rgba(11, 107, 63, .32);
}
.login-hero h1 { font-size: 23px; letter-spacing: 1px; }
.login-hero .sub { color: var(--muted); font-size: 12.5px; margin-top: 5px; }
.login-card { background: var(--surface); border-radius: var(--radius-lg); box-shadow: var(--shadow); padding: 18px; margin-top: 16px; }
.field { margin-bottom: 16px; }
.field label { display: block; font-size: 12.5px; font-weight: 600; color: var(--muted); margin-bottom: 7px; }
.input {
  width: 100%; padding: 11px 13px; border: 1px solid var(--line); border-radius: 11px;
  font-size: 15px; background: var(--surface-2); outline: none;
  transition: border-color .15s, box-shadow .15s, background .15s;
}
.input::placeholder { color: #b3bac7; }
.input:focus { border-color: var(--brand); box-shadow: 0 0 0 3px rgba(7,193,96,.13); background: #fff; }
.input-row { display: flex; gap: 8px; }
.input-row .input { flex: 1; min-width: 0; }

.avatar-grid { display: grid; grid-template-columns: repeat(6, 1fr); gap: 8px; }
.avatar-opt {
  aspect-ratio: 1; border-radius: 13px; display: grid; place-items: center; font-size: 22px;
  border: 2px solid transparent; cursor: pointer; background: var(--surface-2);
  transition: transform .1s, box-shadow .15s;
}
.avatar-opt:active { transform: scale(.94); }
.avatar-opt.on { border-color: var(--brand); box-shadow: 0 0 0 3px rgba(7,193,96,.18); }
.login-tip { text-align: center; color: var(--muted); font-size: 12px; margin-top: 14px; }
.invite-banner {
  background: #eafaf1; border: 1px solid #b6e6cb; color: #0d6b3f;
  border-radius: 12px; padding: 12px 14px; margin-top: 14px; font-size: 13px; line-height: 1.6;
}
.login-actions { display: flex; gap: 10px; margin-top: 4px; }
.login-actions .btn { flex: 1; }

/* ---------- 页内滚动内容 ---------- */
.page { padding: 12px; display: flex; flex-direction: column; gap: 12px; }
.page-title { font-size: 13px; font-weight: 700; color: var(--muted); padding: 2px 4px; display: flex; align-items: center; justify-content: space-between; }

/* 中继提示条 */
.relay-bar {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  background: #fff7e3; border: 1px solid #f0d089; color: #6b5320;
  border-radius: 12px; padding: 10px 12px; font-size: 12.5px; line-height: 1.5;
}
.relay-bar.bad { background: #fdeceb; border-color: #f2b8b8; color: #7a2222; }
.relay-bar .rb-txt { flex: 1 1 200px; }
.relay-bar .rb-broker { flex: 0 0 100%; word-break: break-all; }

/* ---------- 大厅：玩法卡片 ---------- */
.game-list { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.game-card {
  background: var(--surface); border-radius: var(--radius); box-shadow: var(--shadow);
  padding: 14px; cursor: pointer; position: relative; overflow: hidden;
  transition: transform .12s;
}
.game-card:active { transform: scale(.97); }
.game-card .gc-ico { font-size: 30px; line-height: 1.1; }
.game-card .gc-name { font-size: 16px; font-weight: 800; margin-top: 6px; }
.game-card .gc-meta { font-size: 11.5px; color: var(--muted); margin-top: 3px; }
.game-card .gc-tags { margin-top: 9px; display: flex; gap: 5px; flex-wrap: wrap; }
.tag { font-size: 10.5px; padding: 2px 7px; border-radius: 999px; background: #eef3ff; color: var(--blue); font-weight: 600; }
.tag.green { background: #e7f6ee; color: var(--brand-d); }
.tag.amber { background: #fdf3e0; color: #a86a00; }

.room-item {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 11px 13px; border-radius: 12px; background: var(--surface); box-shadow: var(--shadow);
}
.room-item .ri-code { font-weight: 800; letter-spacing: 1.5px; font-size: 16px; }
.room-item .ri-meta { font-size: 11.5px; color: var(--muted); }
.empty { text-align: center; color: var(--muted); padding: 24px 12px; font-size: 13px; }

/* ---------- 弹窗 / 抽屉 ---------- */
.overlay {
  position: fixed; inset: 0; background: rgba(15, 25, 45, .48); z-index: 100;
  display: flex; align-items: center; justify-content: center; padding: 18px;
  backdrop-filter: blur(3px);
}
.modal {
  background: var(--surface); border-radius: var(--radius-lg); box-shadow: var(--shadow-lg);
  width: 100%; max-width: 420px; max-height: 86vh; overflow: auto; animation: pop .2s ease;
}
.modal.wide { max-width: 560px; }
@keyframes pop { from { transform: scale(.95); opacity: .5; } to { transform: scale(1); opacity: 1; } }
.modal-hd {
  padding: 15px 16px; border-bottom: 1px solid var(--line); display: flex; align-items: center;
  justify-content: space-between; position: sticky; top: 0; background: var(--surface); z-index: 2;
}
.modal-hd h3 { font-size: 16px; }
.modal-bd { padding: 16px; }
.modal-ft {
  padding: 13px 16px; border-top: 1px solid var(--line); display: flex; gap: 10px;
  justify-content: flex-end; position: sticky; bottom: 0; background: var(--surface);
}
.icon-btn { border: none; background: transparent; font-size: 19px; cursor: pointer; color: var(--muted); line-height: 1; padding: 4px 8px; border-radius: 8px; }
.icon-btn:active { background: var(--surface-2); }

.sheet-mask {
  position: fixed; inset: 0; background: rgba(15, 25, 45, .42); z-index: 95;
  display: flex; align-items: flex-end; justify-content: center;
}
.sheet {
  width: 100%; max-width: 480px; background: var(--surface);
  border-radius: 18px 18px 0 0; box-shadow: var(--shadow-lg);
  max-height: 82vh; overflow-y: auto; padding-bottom: var(--safe-b);
  animation: slideUp .22s ease;
}
@keyframes slideUp { from { transform: translateY(24px); opacity: .6; } to { transform: translateY(0); opacity: 1; } }
.sheet-hd { padding: 14px 16px 8px; display: flex; align-items: center; justify-content: space-between; }
.sheet-hd h3 { font-size: 16px; }
.sheet-bd { padding: 4px 16px 18px; }

/* 选项组 */
.opt-group { display: flex; gap: 8px; flex-wrap: wrap; }
.opt {
  padding: 8px 14px; border: 1px solid var(--line); border-radius: 10px; background: var(--surface-2);
  cursor: pointer; font-size: 13.5px; font-weight: 600; transition: all .12s;
}
.opt.on { background: var(--brand); color: #fff; border-color: var(--brand); }
.tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--line); margin-bottom: 14px; }
.tab { padding: 9px 13px; cursor: pointer; font-weight: 600; font-size: 14px; color: var(--muted); border-bottom: 2px solid transparent; }
.tab.on { color: var(--brand-d); border-bottom-color: var(--brand); }
.tab-body { display: none; }
.tab-body.on { display: block; }
.rules-text { white-space: pre-wrap; font-size: 13.5px; line-height: 1.85; color: var(--ink-2); }
.tut-step { display: flex; gap: 12px; margin-bottom: 15px; }
.tut-step .num {
  flex: 0 0 26px; height: 26px; border-radius: 50%; background: var(--brand); color: #fff;
  display: grid; place-items: center; font-weight: 700; font-size: 12.5px;
}
.tut-step .tt { font-weight: 700; margin-bottom: 3px; font-size: 14px; }
.tut-step .tx { font-size: 12.5px; color: var(--ink-2); line-height: 1.7; }

/* ---------- 房间等待区 ---------- */
.room-hero {
  background: linear-gradient(160deg, #0f9c5d, #0b6b3f); color: #fff;
  border-radius: var(--radius-lg); padding: 16px; box-shadow: 0 10px 26px rgba(11,107,63,.26);
}
.room-hero .rh-top { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.room-hero .rh-game { font-size: 16px; font-weight: 800; }
.room-hero .rh-code { font-size: 32px; font-weight: 900; letter-spacing: 6px; margin: 10px 0 6px; }
.room-hero .rh-code small { font-size: 12px; font-weight: 600; letter-spacing: 0; opacity: .85; }
.room-hero .rh-meta { display: flex; gap: 8px; flex-wrap: wrap; }
.room-hero .chip { background: rgba(255,255,255,.18); color: #fff; }

.seats { display: grid; grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); gap: 10px; }
.seat {
  padding: 12px 8px; text-align: center; border-radius: 14px; border: 1px dashed var(--line);
  background: var(--surface-2); position: relative;
}
.seat.filled { border-style: solid; background: var(--surface); }
.seat .av { width: 50px; height: 50px; border-radius: 50%; margin: 0 auto 7px; display: grid; place-items: center; font-size: 24px; box-shadow: 0 3px 10px rgba(0,0,0,.12); }
.seat .nm { font-weight: 700; font-size: 13.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.seat .rl { font-size: 11px; color: var(--muted); margin-top: 2px; }
.seat .badge { position: absolute; top: 6px; right: 6px; font-size: 10px; padding: 1px 6px; border-radius: 999px; background: var(--accent); color: #3a2a00; font-weight: 700; }
.seat .badge.ready { background: var(--brand); color: #fff; }
.seat .seat-x { position: absolute; top: 5px; left: 6px; font-size: 12px; color: var(--danger); cursor: pointer; padding: 2px 4px; }
.seat.empty { opacity: .75; }

.code-box { text-align: center; }
.qr-box { display: grid; place-items: center; margin: 10px 0; }
.qr-box img { width: 156px; height: 156px; border-radius: 12px; border: 1px solid var(--line); background: #fff; }
.link-line { font-size: 11.5px; word-break: break-all; color: var(--muted); background: var(--surface-2); padding: 8px 10px; border-radius: 9px; }

/* ---------- 排行榜 / 结算 ---------- */
.result-list { display: flex; flex-direction: column; gap: 8px; }
.result-row { display: flex; align-items: center; gap: 10px; padding: 10px 12px; border-radius: 12px; background: var(--surface-2); }
.result-row .rk { width: 25px; height: 25px; border-radius: 50%; display: grid; place-items: center; font-weight: 800; font-size: 12.5px; background: #e5e9f2; color: #4a5468; }
.result-row.r1 .rk { background: linear-gradient(135deg,#ffd94a,#f0a020); color: #4a3200; }
.result-row.r2 .rk { background: linear-gradient(135deg,#e2e8f2,#b9c3d4); color: #3a4356; }
.result-row.r3 .rk { background: linear-gradient(135deg,#f0c39a,#d99b62); color: #4a2f10; }
.result-row .rav { width: 34px; height: 34px; border-radius: 50%; display: grid; place-items: center; font-size: 17px; }
.result-row .rnm { flex: 1; font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 14px; }
.result-row .rsc { font-weight: 800; font-size: 14.5px; }
.result-row .rsc.pos { color: var(--danger); }   /* 中式：赢为红 */
.result-row .rsc.neg { color: var(--brand-d); } /* 中式：输为绿 */
.result-row .rdelta { font-size: 11.5px; color: var(--muted); margin-left: 5px; }

/* 战绩 */
.hist-item { background: var(--surface); border-radius: var(--radius); box-shadow: var(--shadow); padding: 12px 13px; }
.hist-top { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.hist-game { font-weight: 700; font-size: 14.5px; }
.hist-time { font-size: 11.5px; color: var(--muted); }
.hist-rank { margin-top: 8px; display: flex; flex-wrap: wrap; gap: 6px; }
.hist-pill { font-size: 11.5px; padding: 3px 8px; border-radius: 999px; background: var(--surface-2); color: var(--ink-2); }
.hist-pill.me { background: #e7f6ee; color: var(--brand-d); font-weight: 700; }

/* ==========================================================================
   牌桌
   ========================================================================== */
.table-page { flex: 1; min-height: 0; display: flex; flex-direction: column; background: #0b2c1c; }
/* 竖屏：牌桌在上，侧栏（聊天室 / 手牌 / 操作 / 输入）在下；
 * 横屏与桌面宽屏：侧栏挪到右边一列（见文件末尾的媒体查询）。 */
.table-main { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
/* min-width:0 很关键：手牌是 nowrap 的，不设的话它会把侧栏撑到「内容宽度」，
 * 横屏/桌面切双栏时牌桌会被挤成 0 宽。 */
.table-side { flex: 0 0 auto; min-width: 0; min-height: 0; display: flex; flex-direction: column; }
.table-topbar {
  flex: 0 0 auto; display: flex; align-items: center; gap: 6px; padding: 7px 10px;
  background: var(--surface); border-bottom: 1px solid var(--line);
  overflow-x: auto; white-space: nowrap; scrollbar-width: none;
}
.table-topbar::-webkit-scrollbar { display: none; }
.chip { font-size: 11.5px; padding: 3px 9px; border-radius: 999px; background: #eef3ff; color: var(--blue); font-weight: 700; flex: 0 0 auto; }
.chip.amber { background: #fdf3e0; color: #a86a00; }
.chip.green { background: #e7f6ee; color: var(--brand-d); }
.chip.red { background: #fdeaec; color: var(--danger); }
.chip.dark { background: rgba(0,0,0,.32); color: #fff; }

.felt {
  position: relative; flex: 1 1 auto; min-height: 150px; margin: 8px; border-radius: 16px;
  background: radial-gradient(120% 90% at 50% 0%, var(--felt-1) 0%, var(--felt-2) 76%);
  box-shadow: inset 0 0 55px rgba(0,0,0,.42);
  overflow: hidden;
}
.felt::after {
  content: ''; position: absolute; inset: 10px; border: 1px solid rgba(255,255,255,.09);
  border-radius: 12px; pointer-events: none;
}

/* 回合横幅 */
.turn-banner {
  position: absolute; left: 50%; top: 8px; transform: translateX(-50%);
  z-index: 9; background: rgba(0,0,0,.44); color: #fff; padding: 4px 13px;
  border-radius: 999px; font-size: 12px; font-weight: 700; white-space: nowrap;
  backdrop-filter: blur(4px); border: 1px solid rgba(255,255,255,.16);
  transition: background .2s, transform .2s;
}
.turn-banner.mine { background: var(--accent); color: #3a2a00; border-color: rgba(0,0,0,.12); animation: bannerPulse 1.3s infinite; }
@keyframes bannerPulse { 0%,100% { transform: translateX(-50%) scale(1); } 50% { transform: translateX(-50%) scale(1.05); } }

/* 座位 */
.seat-abs { position: absolute; transform: translate(-50%, -50%); width: 96px; text-align: center; z-index: 5; }
.seat-abs .pav {
  width: 44px; height: 44px; border-radius: 50%; margin: 0 auto; display: grid; place-items: center;
  font-size: 21px; border: 2px solid rgba(255,255,255,.6); box-shadow: 0 4px 14px rgba(0,0,0,.32);
  position: relative; transition: box-shadow .18s, border-color .18s;
}
.seat-abs.turn .pav {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(255,159,26,.6), 0 4px 14px rgba(0,0,0,.32);
  animation: pulse 1.4s infinite;
}
@keyframes pulse {
  0%,100% { box-shadow: 0 0 0 3px rgba(255,159,26,.55), 0 4px 14px rgba(0,0,0,.32); }
  50% { box-shadow: 0 0 0 8px rgba(255,159,26,.12), 0 4px 14px rgba(0,0,0,.32); }
}
.seat-abs .pav.speaking {
  border-color: #34e07a;
  box-shadow: 0 0 0 4px rgba(52,224,122,.55), 0 0 16px rgba(52,224,122,.5);
}
.seat-abs .pav .pav-mute { position: absolute; right: -3px; bottom: -3px; font-size: 11px; }
.seat-abs .pnm { color: #fff; font-size: 11.5px; font-weight: 700; margin-top: 4px; text-shadow: 0 1px 3px rgba(0,0,0,.65); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 座位信息块（昵称 / 分数 / 剩牌 / 身份）：竖屏与宽屏下是**透明层** ——
 * display:contents 让里面几行直接参与 .seat-abs 的纵向堆叠，和加这层包装之前
 * 完全一致；横屏下才把它变成「头像右边的一列」（见文件末尾 .landscape 段）。 */
.seat-abs .pmeta { display: contents; }
.seat-abs .pscore { display: inline-block; margin-top: 3px; padding: 1px 8px; border-radius: 999px; background: rgba(255,255,255,.93); color: #14324a; font-size: 11.5px; font-weight: 800; min-width: 30px; }
.seat-abs .pscore.neg { background: rgba(178,235,205,.95); color: #0a4a2c; }
.seat-abs .pinfo { color: rgba(255,255,255,.86); font-size: 10.5px; margin-top: 2px; text-shadow: 0 1px 3px rgba(0,0,0,.6); }
.seat-abs .ptag { display: inline-block; margin-top: 3px; font-size: 9.5px; padding: 1px 6px; border-radius: 999px; background: rgba(0,0,0,.38); color: #ffe08a; font-weight: 700; }
.seat-abs.off { opacity: .5; }
.seat-abs .turn-bar {
  position: absolute; left: 50%; bottom: -7px; transform: translateX(-50%);
  width: 58px; height: 3px; border-radius: 2px; background: rgba(255,255,255,.22); overflow: hidden;
}
.seat-abs .turn-bar > i { display: block; height: 100%; width: 100%; background: var(--accent); }

/* 中央区 */
.center-area {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  width: 90%; max-width: 420px; display: flex; flex-direction: column; align-items: center; gap: 7px; z-index: 3;
}
.center-hint { color: rgba(255,255,255,.88); font-size: 12px; text-align: center; text-shadow: 0 1px 3px rgba(0,0,0,.55); }
.play-row { display: flex; gap: 3px; justify-content: center; flex-wrap: wrap; }

/* 我的区域 */
.my-area { flex: 0 0 auto; min-width: 0; display: flex; flex-direction: column; gap: 6px; padding: 0 8px 6px; }
.hand-row { display: flex; justify-content: center; align-items: flex-end; min-height: 66px; padding: 2px 4px; flex-wrap: nowrap; }
/* 叠牌间距由 JS 按容器真实宽度算出来（见 views/table.js 的 layoutHand），
 * 保证每张牌至少露出左上角「点数+花色」角标那段宽度。 */
.hand-row .card + .card { margin-left: var(--ov, 0px); }
.hand-row.dense .card { width: 38px; height: 54px; }
.hand-row.dense .card .s { font-size: 16px; margin: 8px 0 0 6px; }
.hand-row .card:first-child { margin-left: 0; }
/* 兜底：容器实在太窄（例如 667px 宽的横屏小屏 + 20 张手牌），
 * 硬叠到每张只剩一条缝反而更看不清 —— 改成左右可滑，牌面保持可辨识的宽度。 */
.hand-row.scrollable { overflow-x: auto; overflow-y: hidden; justify-content: flex-start; -webkit-overflow-scrolling: touch; }
.hand-row.scrollable::-webkit-scrollbar { height: 3px; }
.hand-row.scrollable::-webkit-scrollbar-thumb { background: rgba(255,255,255,.3); border-radius: 2px; }
.actions { display: flex; gap: 8px; justify-content: center; flex-wrap: wrap; padding: 2px 0; }
.actions .btn { padding: 8px 14px; font-size: 13.5px; }
.hint-row { display: flex; gap: 8px; justify-content: center; flex-wrap: wrap; }

/* ---------- 扑克牌 ---------- */
.card {
  width: 42px; height: 60px; border-radius: 6px; background: #fff; position: relative;
  border: 1px solid #d8dde8; box-shadow: 0 2px 6px rgba(10,20,40,.22);
  display: flex; align-items: center; justify-content: center; flex: 0 0 auto;
  color: #1b2333; transition: transform .12s ease, box-shadow .12s ease; user-select: none;
}
.card .ci { position: absolute; top: 2px; left: 3px; display: flex; flex-direction: column; align-items: center; line-height: 1; font-weight: 800; }
.card .ci-r { font-size: 12px; }
.card .ci-s { font-size: 10px; margin-top: 1px; }
.card .s { font-size: 19px; line-height: 1; margin: 9px 0 0 7px; opacity: .95; }
.card .s2 { position: absolute; bottom: 3px; right: 4px; font-size: 10px; font-weight: 700; opacity: .55; }
.card.red { color: var(--danger); }
.card.small { width: 30px; height: 42px; border-radius: 5px; }
.card.small .ci { top: 2px; left: 2px; }
.card.small .ci-r { font-size: 9.5px; }
.card.small .ci-s { font-size: 8.5px; }
.card.small .s { font-size: 12px; margin: 6px 0 0 4px; }
.card.small .s2 { display: none; }
.card.tiny { width: 23px; height: 33px; border-radius: 4px; }
.card.tiny .ci { top: 1px; left: 2px; }
.card.tiny .ci-r { font-size: 8.5px; }
.card.tiny .ci-s { font-size: 7.5px; margin-top: 0; }
.card.tiny .s { font-size: 10px; margin: 5px 0 0 3px; }
.card.tiny .s2 { display: none; }
.card.back { background: repeating-linear-gradient(45deg, #3355c8, #3355c8 5px, #4767e0 5px, #4767e0 10px); border-color: #2b47a8; }
.card.back .ci, .card.back .s, .card.back .s2, .card.back .jk { display: none; }
.card.joker .jk { font-size: 12px; font-weight: 800; writing-mode: vertical-rl; letter-spacing: 1px; }
.card.selectable { cursor: pointer; }
.card.selectable:hover { transform: translateY(-6px); }
.card.sel { transform: translateY(-18px); box-shadow: 0 0 0 2px var(--accent), 0 8px 16px rgba(0,0,0,.28); }
.card.dim { opacity: .42; }
.card.live { box-shadow: 0 0 0 2px #7bf1a8, 0 2px 6px rgba(10,20,40,.22); }
.card.pending { opacity: 0; }
.card.reveal { animation: cardIn .22s ease both; }
@keyframes cardIn { from { opacity: 0; transform: translateY(6px) scale(.94); } to { opacity: 1; transform: none; } }

/* 排七 */
.sevens-board { display: flex; flex-direction: column; gap: 5px; width: 100%; }
.sevens-line { display: flex; align-items: center; gap: 3px; justify-content: center; min-height: 34px; }
.sevens-line .suit-mark { color: rgba(255,255,255,.92); font-size: 16px; width: 16px; text-align: center; text-shadow: 0 1px 3px rgba(0,0,0,.5); }
.sevens-line .ph { width: 23px; height: 33px; border-radius: 4px; border: 1px dashed rgba(255,255,255,.22); }

/* 排火车 */
.train-line { display: flex; gap: 2px; flex-wrap: wrap; justify-content: center; max-height: 150px; overflow: hidden; }
.train-line .card { width: 28px; height: 40px; }
.train-line .card .ci-r { font-size: 9px; }
.train-line .card .ci-s { font-size: 8px; }
.train-line .card .s { font-size: 11px; margin: 6px 0 0 3px; }
.train-line .card .s2 { display: none; }
.pile-row { display: flex; gap: 12px; justify-content: center; color: #fff; font-size: 11.5px; flex-wrap: wrap; }

/* 斗牛 / 21点 */
.multi-hands { display: flex; flex-wrap: wrap; gap: 7px; justify-content: center; width: 100%; }
.hand-box { background: rgba(0,0,0,.2); border-radius: 10px; padding: 6px 8px; text-align: center; }
.hand-box .hb-name { color: #fff; font-size: 11px; font-weight: 700; margin-bottom: 4px; }
.hand-box .hb-cards { display: flex; gap: 2px; justify-content: center; }
.hand-box .hb-res { color: #ffe08a; font-size: 11px; font-weight: 700; margin-top: 4px; }
.hand-box.banker { box-shadow: 0 0 0 2px var(--accent); }
.hand-box.done { opacity: .78; }

/* ---------- 底部输入条（聊天 / 语音 / 表情） ---------- */
.composer {
  flex: 0 0 auto; display: flex; align-items: center; gap: 6px;
  padding: 6px 8px calc(6px + var(--safe-b)); background: var(--surface);
  border-top: 1px solid var(--line);
}
.cbtn {
  width: 34px; height: 34px; flex: 0 0 auto; border-radius: 10px; display: grid; place-items: center;
  font-size: 18px; background: var(--surface-2); border: none; cursor: pointer; color: var(--ink-2);
}
.cbtn:active { background: #e6eaf1; }
.cbtn.on { background: var(--brand); color: #fff; }
.cbtn.talking { background: var(--danger); color: #fff; animation: talkPulse .8s infinite; }
@keyframes talkPulse { 0%,100% { box-shadow: 0 0 0 0 rgba(250,81,81,.5); } 50% { box-shadow: 0 0 0 6px rgba(250,81,81,0); } }
.composer .c-input {
  flex: 1; min-width: 0; height: 34px; border-radius: 17px; border: 1px solid var(--line);
  background: var(--surface-2); padding: 0 13px; font-size: 14px; outline: none;
}
.composer .c-input:focus { border-color: var(--brand); background: #fff; }
.composer .c-send { height: 34px; padding: 0 15px; border-radius: 17px; background: var(--brand); color: #fff; border: none; font-weight: 700; font-size: 13.5px; cursor: pointer; }
/* 没内容可发（既没待发送项、输入框也空）时置灰，避免「按了没反应」 */
.composer .c-send:disabled { opacity: .45; cursor: default; }

.composer-wrap { position: relative; flex: 0 0 auto; display: flex; flex-direction: column; }

/* ---------- 常驻输入区（#dock） ----------
 * 挂在 #view 外面（#view 的兄弟节点），只有牌桌 / 房间用它。
 * 为什么必须这样：#view 每次对局状态更新都会被整块重建（innerHTML=''），
 * 输入框留在里面就会被反复销毁 —— 焦点、光标、草稿、手机软键盘全丢
 * （实测：输入框聚焦后来一条 room 更新，activeElement 立刻变成 BODY）。 */
.dock {
  flex: 0 0 auto; position: relative; z-index: 30;
  display: flex; flex-direction: column;
  background: var(--surface); border-top: 1px solid var(--line);
}
.dock.hidden { display: none; }
.dock .composer { border-top: none; }

/* 发送回执：不看聊天框也知道发出去了没有 */
.c-receipt {
  flex: 0 0 auto; padding: 5px 12px; font-size: 12px; font-weight: 700;
  color: var(--brand-d); background: #eafaf1; border-top: 1px solid #d8f2e4;
  text-align: center; animation: receiptIn .18s ease both;
}
.c-receipt.bad { color: var(--danger); background: #fdeeef; border-top-color: #f8d7da; }
.c-receipt.hidden { display: none; }
@keyframes receiptIn { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }

/* ---------- 待发送预览条（点选表情/常用语 → 按「发送」才发出） ----------
 * 这是「二次确认」的可视锚点：没有它，用户点了表情却什么也没发生会以为坏了。
 * 左侧标注状态、中间原样显示要发的内容、右侧 ✕ 取消。
 *
 * 和 .composer-panel 一样做成**浮层**（`position:absolute; bottom:100%`），
 * 不能用 flex 子项：竖屏下 `.table-main` 是 `flex:1 1 auto`，
 * 塞一个 37px 高的条进去会直接把牌桌内容区压矮 37px（实测过）。
 * 浮层则不占布局，牌桌纹丝不动。
 * 锚点是 `.composer-rowwrap`（只包输入行），所以正好贴在输入行上方。 */
.composer-rowwrap { position: relative; flex: 0 0 auto; }
.c-pending {
  position: absolute; left: 0; right: 0; bottom: 100%; z-index: 39;
  display: flex; align-items: center; gap: 8px;
  padding: 6px 10px; font-size: 13px;
  background: #fff8e6; border-top: 1px solid #ffe6ad;
  box-shadow: 0 -6px 18px rgba(15, 25, 45, .14);
  animation: receiptIn .16s ease both;
}
.c-pending.hidden { display: none; }
.c-pending-label {
  flex: 0 0 auto; font-size: 10.5px; font-weight: 800; letter-spacing: .04em;
  color: #8a6100; background: #ffe9b0; border-radius: 999px; padding: 2px 8px;
}
.c-pending-text {
  flex: 1; min-width: 0; font-weight: 700; color: var(--ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.c-pending-x {
  flex: 0 0 auto; width: 24px; height: 24px; border-radius: 50%;
  border: none; cursor: pointer; font-size: 12px; font-weight: 800;
  background: #ffe0a3; color: #8a6100;
}
.c-pending-x:active { background: #ffd27a; }
/* 被选中的表情 / 常用语：描边高亮，一眼看出「选中了哪个」 */
.emote-item.picked, .phrase-item.picked {
  outline: 2px solid var(--brand); outline-offset: -2px; background: #eafaf1;
}
/* 展开时改成**向上浮出的浮层**（不再撑开输入区）。
 * 为什么改：之前是 static 撑开，面板一展开就把整条输入区和语音条往上顶，
 * 手机横屏 / 牌桌矮的时候手牌和操作按钮会被挤出可视区；桌面宽屏下右栏也跟着跳。
 * 现在面板绝对定位挂在**输入行正上方**（锚 .composer-rowwrap，只包输入行），
 * 输入区自己**一点不动**，选表情时还能看见手里的牌。
 * 代价：面板会盖住输入区上方那块区域，所以内容要能自己滚（见 max-height）。 */
.composer-panel {
  position: absolute; left: 0; right: 0; bottom: 100%;
  z-index: 40;
  background: var(--surface); border-top: 1px solid var(--line);
  border-radius: 14px 14px 0 0;
  max-height: min(40vh, 260px); overflow-y: auto; padding: 9px;
  box-shadow: 0 -10px 30px rgba(15, 25, 45, .22);
  animation: panelUp .16s ease both;
}
/* 面板是浮层了，聊天室不用再让位 —— 反而应该留着，
 * 这样一边挑常用语一边能看到大家在说什么。 */
@keyframes panelUp { from { opacity: .4; transform: translateY(10px); } to { opacity: 1; transform: none; } }
.panel-tabs { display: flex; gap: 6px; margin-bottom: 8px; }
.panel-tab { font-size: 12.5px; font-weight: 700; padding: 4px 10px; border-radius: 999px; background: var(--surface-2); color: var(--muted); border: none; cursor: pointer; }
.panel-tab.on { background: var(--brand); color: #fff; }

.emote-grid { display: grid; grid-template-columns: repeat(6, 1fr); gap: 6px; }
.emote-item {
  aspect-ratio: 1; border-radius: 11px; display: grid; place-items: center; font-size: 24px;
  background: var(--surface-2); border: none; cursor: pointer;
}
.emote-item:active { transform: scale(.9); }
.emote-item .ei-txt { font-size: 10px; font-weight: 800; }

.phrase-list { display: flex; flex-direction: column; gap: 6px; }
.phrase-item {
  text-align: left; padding: 9px 12px; border-radius: 10px; background: var(--surface-2);
  border: none; font-size: 13.5px; cursor: pointer; color: var(--ink);
}
.phrase-item:active { background: #e6eaf1; }
.phrase-group-title { font-size: 11.5px; color: var(--muted); font-weight: 700; margin: 6px 2px 2px; }

/* 漂浮气泡 */
.bubble-layer { position: absolute; inset: 0; pointer-events: none; z-index: 8; overflow: hidden; }
.bubble {
  position: absolute; transform: translate(-50%, 0); max-width: 62%;
  background: #fff; color: #1b2333; border-radius: 13px; padding: 6px 10px;
  font-size: 12px; line-height: 1.4; box-shadow: 0 6px 18px rgba(0,0,0,.28);
  animation: bubbleIn .22s ease both;
}
@keyframes bubbleIn { from { opacity: 0; transform: translate(-50%, 8px) scale(.9); } to { opacity: 1; transform: translate(-50%, 0) scale(1); } }
.bubble.bubble-out { animation: bubbleOut .35s ease both; }
@keyframes bubbleOut { to { opacity: 0; transform: translate(-50%, -10px) scale(.94); } }
.bubble .b-who { font-size: 10px; color: var(--muted); font-weight: 700; }
.bubble.emote { background: rgba(255,255,255,.96); font-size: 30px; padding: 6px 12px; border-radius: 16px; text-align: center; }
.bubble.sticker { background: linear-gradient(150deg,#fff6d9,#ffe0b8); text-align: center; }
.bubble.sticker .st-emoji { font-size: 28px; }
.bubble.sticker .st-txt { display: block; font-size: 12px; font-weight: 800; color: #8a4b00; }

/* 聊天抽屉里的消息 */
.chat-log { display: flex; flex-direction: column; gap: 10px; }
.msg-row { display: flex; gap: 8px; align-items: flex-start; }
.msg-row.mine { flex-direction: row-reverse; }
.msg-av { width: 32px; height: 32px; border-radius: 50%; display: grid; place-items: center; font-size: 16px; flex: 0 0 auto; }
.msg-body { max-width: 74%; }
.msg-name { font-size: 10.5px; color: var(--muted); margin-bottom: 3px; }
.msg-row.mine .msg-name { text-align: right; }
.msg-bubble {
  background: var(--surface-2); border-radius: 12px; padding: 8px 11px; font-size: 13.5px;
  line-height: 1.5; word-break: break-word;
}
.msg-row.mine .msg-bubble { background: var(--brand); color: #fff; }
.msg-bubble.quote { background: #fff6e6; color: #7a4b00; font-weight: 600; }
.msg-row.mine .msg-bubble.quote { background: #ffe9c2; color: #6b3d00; }
.msg-bubble.emote { background: transparent; padding: 0; font-size: 34px; line-height: 1.1; }
.msg-bubble.sticker { background: linear-gradient(150deg,#fff6d9,#ffe0b8); text-align: center; }
.msg-bubble.sticker .st-emoji { font-size: 32px; display: block; }
.msg-bubble.sticker .st-txt { font-size: 12.5px; font-weight: 800; color: #8a4b00; }
.msg-sys { font-size: 11.5px; color: var(--muted); text-align: center; width: 100%; }

/* 语音条 */
.voice-bar {
  display: flex; align-items: center; gap: 8px; padding: 7px 11px; background: var(--surface);
  border: 1px solid var(--line); border-radius: 999px; box-shadow: var(--shadow);
}
.voice-dot { width: 8px; height: 8px; border-radius: 50%; background: #c8cfdb; flex: 0 0 auto; }
.voice-dot.on { background: #22c55e; box-shadow: 0 0 0 3px rgba(34,197,94,.2); }
.voice-hint { font-size: 11.5px; color: var(--muted); }
.voice-sound-ask {
  background: var(--accent); color: #3a2a00; border: none; border-radius: 999px;
  font-size: 11.5px; font-weight: 700; padding: 4px 10px; cursor: pointer;
}

/* ---------- 牌桌聊天室（常驻，实时可见，不遮牌桌） ---------- */
.chat-side {
  flex: 0 0 auto; min-width: 0; display: flex; flex-direction: column;
  min-height: 130px;                      /* 竖屏也要能一次看到 ~3 条，不用翻 */
  margin: 0 8px 6px; border-radius: 12px; overflow: hidden;
  background: rgba(5, 22, 14, .68); border: 1px solid rgba(255,255,255,.09);
  transition: border-color .3s, box-shadow .3s;
}
.chat-side.flash { border-color: rgba(123,241,168,.55); box-shadow: 0 0 0 2px rgba(123,241,168,.22); }
.chat-side-hd { display: flex; align-items: center; gap: 6px; padding: 5px 10px; background: rgba(255,255,255,.07); }
.chat-side-hd .cs-title { color: #fff; font-size: 11.5px; font-weight: 700; }
.chat-side-hd .cs-sp { flex: 1; }
.chat-side-hd .cs-more {
  background: rgba(255,255,255,.15); color: #fff; border: none; border-radius: 999px;
  font-size: 10.5px; font-weight: 700; padding: 3px 9px; cursor: pointer;
}
.chat-side-log { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 6px 9px; max-height: 100px; }
.chat-side .chat-log { gap: 7px; }
.chat-side .msg-av { width: 22px; height: 22px; font-size: 12px; }
.chat-side .msg-name { font-size: 10px; color: rgba(255,255,255,.62); margin-bottom: 2px; }
.chat-side .msg-body { max-width: 88%; }
.chat-side .msg-bubble { font-size: 12.5px; padding: 5px 9px; border-radius: 10px; }
.chat-side .msg-bubble.emote { font-size: 26px; }
.chat-side .msg-sys { color: rgba(255,255,255,.62); }
.chat-side .empty { color: rgba(255,255,255,.6); }

/* 自己的消息：先本地显示（pending 半透明），回声到了恢复；超时标「未送达」 */
.msg-row.pending .msg-bubble { opacity: .55; }
.msg-row.failed .msg-bubble { box-shadow: 0 0 0 1px rgba(250,81,81,.55); }
.msg-flag { display: inline-block; margin-top: 3px; font-size: 10.5px; font-weight: 700; color: var(--danger); }
.msg-row.mine .msg-flag { display: block; text-align: right; }

/* 有人说话：在他的头像上挂一个「💬」提示，停一会儿再消失 */
.seat-abs.has-msg .pav::after {
  content: '💬'; position: absolute; top: -6px; right: -6px; font-size: 12px; line-height: 1;
  animation: msgPop .34s ease both;
}
.seat-abs.has-msg .pav { box-shadow: 0 0 0 3px rgba(123,241,168,.5), 0 4px 14px rgba(0,0,0,.32); }
@keyframes msgPop { from { opacity: 0; transform: scale(.35); } to { opacity: 1; transform: scale(1); } }

/* ---------- 结算 ---------- */
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* ---------- Toast ---------- */
.toasts { position: fixed; left: 50%; bottom: 26px; transform: translateX(-50%); z-index: 300; display: flex; flex-direction: column; gap: 8px; align-items: center; pointer-events: none; padding: 0 12px; }
.toast {
  background: rgba(22, 30, 48, .93); color: #fff; padding: 10px 18px; border-radius: 999px;
  font-size: 13px; box-shadow: var(--shadow-lg); animation: toastIn .2s ease; max-width: 88vw; text-align: center;
}
@keyframes toastIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }

/* ---------- 飞牌动画 ---------- */
.fly-card {
  position: fixed; z-index: 400; pointer-events: none; will-change: transform, opacity;
  border-radius: 6px;
}

/* ---------- 客户端补充 ---------- */
.nav-code { font-size: 12px; font-weight: 600; color: var(--muted); }

/* 隐藏滚动条（保留滚动能力），更像原生 App */
.view, .login-page, .composer-panel, .sheet, .modal, .chat-log, .page {
  scrollbar-width: none; -ms-overflow-style: none;
}
.view::-webkit-scrollbar, .login-page::-webkit-scrollbar, .composer-panel::-webkit-scrollbar,
.sheet::-webkit-scrollbar, .modal::-webkit-scrollbar, .chat-log::-webkit-scrollbar,
.page::-webkit-scrollbar { width: 0; height: 0; display: none; }

/* 牌桌：轮到我时给桌面一点暖光 */
.felt.my-turn { box-shadow: inset 0 0 55px rgba(0,0,0,.42), 0 0 0 2px rgba(255,159,26,.45); }

/* 出牌者闪烁（放在 .turn 之后，保证闪烁时盖过脉冲） */
.seat-abs.flash .pav { animation: seatFlash .5s ease; }
@keyframes seatFlash {
  0% { transform: scale(1); }
  35% { transform: scale(1.22); box-shadow: 0 0 0 7px rgba(255,255,255,.4); }
  100% { transform: scale(1); }
}

/* 座位旁的聊天气泡（向上展开） */
.bubble.seat { transform: translate(-50%, -100%); animation: bubbleInSeat .22s ease both; }
.bubble.seat.bubble-out { animation: bubbleOutSeat .35s ease both; }
@keyframes bubbleInSeat { from { opacity: 0; transform: translate(-50%, -88%) scale(.9); } to { opacity: 1; transform: translate(-50%, -100%) scale(1); } }
@keyframes bubbleOutSeat { to { opacity: 0; transform: translate(-50%, -114%) scale(.94); } }

/* 正上方会压住中央出牌区时，气泡改贴到头像左侧 / 右侧 / 下方
 * （位置由 views/table.js 的 pickBubbleSpot 决定）。这几种位置不能再用
 * 带 translate 位移的关键帧动画，否则会把定位用的 transform 覆盖掉。 */
.bubble.seat.side-l { transform: translate(-100%, -50%); animation: bubbleInPlain .22s ease both; }
.bubble.seat.side-r { transform: translate(0, -50%); animation: bubbleInPlain .22s ease both; }
.bubble.seat.below { transform: translate(-50%, 0); animation: bubbleInPlain .22s ease both; }
.bubble.seat.side-l.bubble-out,
.bubble.seat.side-r.bubble-out,
.bubble.seat.below.bubble-out { animation: bubbleOutPlain .35s ease both; }
@keyframes bubbleInPlain { from { opacity: 0; } to { opacity: 1; } }
@keyframes bubbleOutPlain { to { opacity: 0; } }

/* 牌桌太矮（横屏手机 / 聊天面板展开把牌桌顶上去）时收紧中央出牌区：
 * 「底牌 + 最近出牌」整体小一档并上移一点，避免被回合横幅或贴底手牌压住。 */
.felt.tight .center-area { top: 44%; }
.felt.tight .center-hint { font-size: 10.5px; }
.felt.tight .play-row .card { width: 30px; height: 42px; border-radius: 5px; }
.felt.tight .play-row .card .ci { top: 2px; left: 2px; }
.felt.tight .play-row .card .ci-r { font-size: 9.5px; }
.felt.tight .play-row .card .ci-s { font-size: 8.5px; }
.felt.tight .play-row .card .s { font-size: 12px; margin: 6px 0 0 4px; }
.felt.tight .turn-banner { font-size: 11px; padding: 3px 10px; }
.felt.tight .seat-abs { width: 84px; }
.felt.tight .seat-abs .pav { width: 36px; height: 36px; font-size: 17px; }
.felt.tight .seat-abs .pnm { font-size: 10.5px; }
.felt.tight .seat-abs .pscore { font-size: 10.5px; padding: 0 6px; }

/* 聊天记录按钮 + 未读角标 */
.composer .c-log { position: relative; }
.composer .c-badge {
  position: absolute; top: -4px; right: -4px; min-width: 16px; height: 16px; padding: 0 4px;
  border-radius: 999px; background: var(--danger); color: #fff; font-size: 10px; font-weight: 800;
  font-style: normal; line-height: 16px; text-align: center; box-shadow: 0 1px 4px rgba(0,0,0,.25);
}

/* ---------- 横屏 / 小屏适配 ---------- */
@media (max-height: 620px) {
  :root { --navbar-h: 42px; --tabbar-h: 48px; }
  .seat-abs { width: 84px; }
  .seat-abs .pav { width: 38px; height: 38px; font-size: 18px; }
  .card { width: 36px; height: 52px; }
  .card .s { font-size: 17px; }
  .felt { margin: 6px; }
}
@media (max-height: 560px) {
  .center-area { gap: 4px; }
  .hand-row { min-height: 56px; }
}
@media (min-width: 700px) {
  .center-area { max-width: 460px; }
}

/* ---------- 宽屏：手机横过来 / 桌面 → 牌桌铺满整屏 + 聊天室在右 ----------
 * 判定在 table.js 的 isWide()，结果以 `.phone.wide` 落到 DOM 上。
 * 不再维护「横屏媒体查询 + 桌面媒体查询」两套断点，免得和 JS 打架
 * （老问题是：媒体查询说宽屏、JS 按窄屏算，手牌间距全错）。 */
.phone.wide { max-width: 1060px; --side-w: clamp(230px, 32%, 340px); }
.phone.wide .table-main { flex-direction: row; }
.phone.wide .felt { flex: 1 1 0; min-width: 0; min-height: 0; margin: 8px; }
.phone.wide .table-side {
  flex: 0 0 var(--side-w); min-width: 0; border-left: 1px solid rgba(255,255,255,.08);
  padding-bottom: var(--dock-h, 92px);      /* 别被绝对定位的输入区盖住 */
}
.phone.wide .chat-side { flex: 1 1 auto; min-height: 0; margin: 8px 8px 6px; }
.phone.wide .chat-side-log { max-height: none; }
.phone.wide .center-area { max-width: min(620px, 82%); }
.phone.wide .hint-row { display: none; }

/* 手牌贴在牌桌底部：横屏可用高度只有 320~390px，单独占一行会把出牌区挤没。
 * 贴上去之后手牌横跨整个牌桌宽度，20 张也放得下，出牌区在正中间不被遮挡。 */
.phone.wide .my-area.on-felt {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 7;
  padding: 6px 10px 4px;
  background: linear-gradient(180deg, rgba(6,32,20,0) 0%, rgba(6,32,20,.5) 38%, rgba(6,32,20,.84) 100%);
}
.phone.wide .my-area.on-felt .hand-row { min-height: 0; padding-bottom: 2px; }
.phone.wide .my-area.on-felt .actions { padding: 4px 0 0; }
.phone.wide .actions .btn { padding: 5px 12px; font-size: 12.5px; }

/* 自己的座位不画（手牌已经贴在牌桌底部，再站一个头像只会压住手牌与出牌区），
 * 对手收在上方两侧、换紧凑样式，中间整块让给出牌区。 */
.phone.wide .felt.compact .seat-abs.mine { display: none; }
.phone.wide .felt.compact .seat-abs { width: 80px; }
.phone.wide .felt.compact .seat-abs .pav { width: 34px; height: 34px; font-size: 16px; }
.phone.wide .felt.compact .seat-abs .pnm { font-size: 10.5px; margin-top: 2px; }
.phone.wide .felt.compact .seat-abs .pscore { font-size: 10.5px; padding: 0 6px; margin-top: 2px; }
.phone.wide .felt.compact .seat-abs .ptag { font-size: 9px; padding: 0 5px; margin-top: 2px; }
.phone.wide .felt.compact .turn-banner { font-size: 11px; padding: 3px 10px; }

/* 输入区对齐到右侧栏底部：#dock 是 #view 的兄弟节点（不能被重建），
 * 只能用绝对定位把它贴到右栏那一列。 */
.phone.wide #dock {
  position: absolute; right: 0; bottom: 0; width: var(--side-w); z-index: 31;
  border-left: 1px solid var(--line);
}
/* 面板是浮层了：宽屏下限制矮一点，别一路顶到牌桌顶部把手牌盖住 */
.phone.wide #dock .composer-panel { max-height: min(38vh, 240px); }
.phone.wide #dock .composer { padding: 4px 6px calc(4px + var(--safe-b)); gap: 5px; }
.phone.wide #dock .cbtn { width: 30px; height: 30px; font-size: 16px; border-radius: 9px; }
.phone.wide #dock .composer .c-input { height: 30px; font-size: 13px; padding: 0 11px; }
.phone.wide #dock .composer .c-send { height: 30px; padding: 0 12px; font-size: 12.5px; }
.phone.wide #dock .c-pending { padding: 4px 9px; font-size: 12px; }
.phone.wide #dock .voice-bar { padding: 3px 9px; gap: 6px; }
.phone.wide .chat-side-hd { padding: 3px 8px; gap: 5px; }
.phone.wide .chat-side .msg-av { width: 20px; height: 20px; font-size: 11px; }
.phone.wide .chat-side .msg-bubble { font-size: 12px; padding: 4px 8px; }

/* 横屏手机上别套「居中手机壳」，直接铺满整屏 */
@media (orientation: landscape) and (max-height: 620px) {
  body { display: block; }
  .phone.wide { max-width: 100%; border-radius: 0; height: 100dvh; }
}


/* ==========================================================================
   全屏对局（沉浸式）—— 手机端竖屏 / 横屏
   ==========================================================================
   目标：手机上「对局覆盖整个屏幕」。
   改造前竖屏被切成 6 段（导航栏 46px / 信息条 30px / 牌桌 / 聊天室 150px /
   手牌 66px + 按钮 / 输入区 90px），真正留给牌桌的高度不到一半 ——
   对手座位、底牌、出牌区挤成一团，聊天室反倒占掉三分之一屏。
   改造后：导航栏、信息条、手牌、操作按钮、输入区**全部浮在牌桌上**，
   牌桌从屏幕最顶端铺到最底端；聊天室收成一个可开合的浮层面板，
   开关摆在操作行最右侧（大拇指自然位置，且不多占一行高度）。

   判定在 app.js（view === 'table' && !isWide()），结果以 `body.immersive` +
   `.phone.immersive` 落到 DOM；桌面 / 平板宽屏（≥1024px）仍走「牌桌 + 右栏」双栏。
   ========================================================================== */

body.immersive { display: block; }
.phone.immersive {
  max-width: 100%; height: 100dvh;
  border-radius: 0; border: none; box-shadow: none;
  background: #04231a;
}
.phone.immersive .view { overflow: hidden; }

/* ---- 1. 导航栏 → 浮在牌桌上端的透明条（不再占 46px 高度） ---- */
.phone.immersive .navbar {
  position: absolute; top: 0; left: 0; right: 0; z-index: 40;
  background: linear-gradient(180deg, rgba(0,0,0,.62) 0%, rgba(0,0,0,.26) 66%, rgba(0,0,0,0) 100%);
  border-bottom: none;
}
.phone.immersive .navbar .nav-title,
.phone.immersive .navbar .nav-btn,
.phone.immersive .navbar .nav-back { color: #fff; text-shadow: 0 1px 4px rgba(0,0,0,.75); }
.phone.immersive .navbar .nav-code { color: rgba(255,255,255,.86); }
.phone.immersive .navbar .nav-btn:active { background: rgba(255,255,255,.18); }

/* ---- 2. 牌桌铺满整屏 ---- */
.phone.immersive .table-page { position: relative; background: transparent; }
.phone.immersive .table-main { position: relative; flex: 1 1 auto; min-height: 0; }
.phone.immersive .felt {
  margin: 0; border-radius: 0; box-shadow: none; min-height: 0;
  /* 整屏一块绒布：上浅下深，底部正好被手牌浮层的暗色渐变接住 */
  background: radial-gradient(128% 74% at 50% 3%, #21a86c 0%, #128052 27%, #0a5232 60%, #04291a 100%);
}
.phone.immersive .felt::after { inset: 0; border: none; border-radius: 0; }
.phone.immersive .felt.my-turn { box-shadow: none; }

/* 信息条 → 第二行居中的半透明 chip（也不占高度） */
.phone.immersive .table-topbar {
  position: absolute; left: 0; right: 0; z-index: 35;
  top: calc(var(--navbar-h) + var(--safe-t));
  justify-content: center; padding: 3px 10px 4px;
  background: transparent; border-bottom: none;
}
.phone.immersive .chip { backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px); }
.phone.immersive .chip.dark { background: rgba(0,0,0,.4); }

/* 回合横幅挂在信息条下面一行，别顶到导航栏上 */
.phone.immersive .turn-banner { top: calc(var(--navbar-h) + var(--safe-t) + 34px); }
/* 中央出牌区上移：底部三层浮层（手牌 / 按钮 / 输入区）要占掉一百多像素 */
.phone.immersive .center-area { top: 41%; }
/* 矮屏（手机 640 高竖屏、390 高横屏）再收紧：牌小一档、间距压到 4px，
 * 「底牌」这行标签直接省掉 —— 不这么干，出牌区底边一定会被贴底的手牌浮层压住。 */
.phone.immersive .felt.tight .center-area { top: 36%; gap: 4px; }
.phone.immersive .felt.tight .center-hint { display: none; }

/* ---- 3. 座位：自己的不画（手牌已经贴底了），对手收在上方两侧 ---- */
.phone.immersive .felt.compact .seat-abs.mine { display: none; }

/* ---- 4. 手牌 + 操作按钮：贴底浮层（手牌在最下，按钮压在它上面） ---- */
.phone.immersive .my-area.on-felt {
  position: absolute; left: 0; right: 0; z-index: 12;
  bottom: calc(var(--dock-h, 62px) + 6px);   /* 让出最底下那条输入区，再留一点缝 */
  display: flex; flex-direction: column-reverse;  /* DOM 是 手牌/按钮/日志，反过来即「手牌贴底」 */
  gap: 6px; padding: 14px 10px 4px;
  background: linear-gradient(180deg, rgba(4,30,18,0) 0%, rgba(4,30,18,.55) 46%, rgba(4,30,18,.9) 100%);
}
.phone.immersive .my-area.on-felt .hand-row { min-height: 0; }
.phone.immersive .actions { padding: 0; gap: 7px; }
.phone.immersive .actions .btn {
  padding: 10px 13px; font-size: 13.5px; border-radius: 12px;
  box-shadow: 0 4px 14px rgba(0,0,0,.34);
}
/* 「过牌 / 清空 / 聊天」这类次要按钮走半透明深色，别和「出牌」抢眼 */
.phone.immersive .actions .btn-ghost {
  background: rgba(255,255,255,.16); color: #fff; border-color: rgba(255,255,255,.24);
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
}
.phone.immersive .actions-chat { position: relative; }   /* 未读角标要挂它右上角 */
.phone.immersive .actions-chat.has-unread { color: #ffe08a; border-color: rgba(255,159,26,.7); }
.phone.immersive .hint-row .tiny { color: rgba(255,255,255,.74); }
/* 矮屏（640 竖屏 / 390 横屏）连日志行都省掉 —— 先保出牌区不被压 */
.phone.immersive .felt.tight .hint-row { display: none; }

/* ---- 5. 聊天室：浮层面板（默认收起，点「💬 聊天」开合） ---- */
.phone.immersive .table-side {
  position: absolute; inset: 0; z-index: 34;
  display: block; padding: 0; pointer-events: none;   /* 只做定位容器，别挡住牌桌 */
}
.phone.immersive .chat-side {
  position: absolute; left: 10px; right: 10px;
  top: calc(var(--navbar-h) + var(--safe-t) + 34px);
  bottom: calc(var(--dock-h, 62px) + 8px);
  margin: 0; max-height: none; display: none;
  pointer-events: auto; border-radius: 16px;
  /* 完全不透明：这是一张盖在牌桌上的浮层，底下透出 6% 的牌面残影只会让人分心。
   * （踩坑记录：一开始写 rgba(4,22,14,.94)，截图里能隐约看到背后的牌，
   *   量出来白牌面区域平均色 13 vs 面板 4 —— 确实只是漏光，不是没画。） */
  background: #04160e; border: 1px solid rgba(255,255,255,.14);
  box-shadow: 0 18px 48px rgba(0,0,0,.55);
  animation: chatSheetUp .2s ease both;
}
/* 入场动画**只能动 transform，绝不能动 opacity**。
 * 踩过的坑：原来写 `from { opacity: 0 }`，结果在「动画帧被节流」的环境里
 * （无头截图、被判定为隐藏的标签页、部分 WebView 后台）动画永远停在首帧，
 * 面板就一直是透明的 —— 看起来像「聊天室坏了」，其实只是首帧没被换掉。
 * 现在就算一帧都不走，面板也只是往下偏 18px，绝不会看不见。 */
@keyframes chatSheetUp { from { transform: translateY(18px); } to { transform: none; } }
.phone.immersive .table-page.chat-open .chat-side { display: flex; }
.phone.immersive .chat-side-log { max-height: none; padding: 8px 10px; }
.phone.immersive .chat-side .msg-av { width: 26px; height: 26px; font-size: 14px; }
.phone.immersive .chat-side .msg-name { font-size: 10.5px; }
.phone.immersive .chat-side .msg-bubble { font-size: 13px; padding: 6px 10px; }
.phone.immersive .chat-side-hd { padding: 7px 10px; }
.phone.immersive .chat-side-hd .cs-title { font-size: 12.5px; }
.phone.immersive .chat-side-hd .cs-close {
  width: 22px; height: 22px; border-radius: 50%; border: none; cursor: pointer;
  background: rgba(255,255,255,.18); color: #fff; font-size: 12px; line-height: 1;
  flex: 0 0 auto; margin-left: 4px;
}
/* 遮罩：点任意处收起聊天室（不用特意去找 ✕） */
.phone.immersive .chat-mask { display: none; }
.phone.immersive .table-page.chat-open .chat-mask {
  display: block; position: absolute; inset: 0; z-index: 33; background: rgba(0,0,0,.36);
}

/* ---- 6. 输入区：贴底半透明浮层（仍常驻 —— 输入框一被重建，手机键盘就弹不出来） ---- */
.phone.immersive #dock {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 44;
  background: transparent; border-top: none;
}
.phone.immersive #dock .composer {
  margin: 0 8px 6px; padding: 5px 7px;
  border: 1px solid rgba(255,255,255,.16); border-radius: 22px;
  background: rgba(5,24,15,.66);
  backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
}
.phone.immersive #dock .cbtn { background: rgba(255,255,255,.13); color: #fff; }
.phone.immersive #dock .cbtn:active { background: rgba(255,255,255,.26); }
.phone.immersive #dock .composer .c-input {
  background: rgba(255,255,255,.13); border-color: transparent; color: #fff;
}
.phone.immersive #dock .composer .c-input::placeholder { color: rgba(255,255,255,.58); }
.phone.immersive #dock .composer .c-input:focus { background: rgba(255,255,255,.2); border-color: var(--brand); }
.phone.immersive #dock .voice-bar {
  margin: 0 8px 6px; border-radius: 22px; border-color: rgba(255,255,255,.16);
  background: rgba(5,24,15,.66);
  backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
}
.phone.immersive #dock .voice-hint { color: rgba(255,255,255,.76); }
.phone.immersive #dock .c-receipt {
  margin: 0 8px 4px; border: none; border-radius: 14px;
  background: rgba(7,193,96,.94); color: #fff;
}
.phone.immersive #dock .c-receipt.bad { background: rgba(250,81,81,.95); color: #fff; }
.phone.immersive #dock .composer-panel { max-height: min(42vh, 300px); }
/* toast 也上移：全屏对局底部压着输入区 + 手牌浮层 + 操作按钮，
 * 默认位置正好把提示语糊在牌和按钮上。 */
body.immersive .toasts { bottom: calc(var(--dock-h, 62px) + 170px); }

/* ---- 7. 横屏（宽 > 高）：对手贴两侧、底部压成两行，中间整块给出牌区 ----
 * 排布参照主流斗地主（欢乐斗地主等）的横屏牌桌：头像 / 积分离散地贴四个角，
 * 顶上一条只做信息，中间一大片绒布只放打出去的牌，底部只留「手牌 + 按钮」一行
 * 和输入行一行。
 * 竖屏那套（信息条一行、昵称/分数/剩牌/身份竖着摞四行、语音条再单占一行）
 * 在横屏会把高度吃光：底牌被回合横幅压住、打出去的牌被贴底手牌压住。
 *
 * 判据是 app.js 落下的 `.phone.immersive.landscape`，**不用媒体查询** ——
 * 手机横屏的**逻辑高度**会随 DPR / WebView 缩放超过 620（实测有 700+），
 * 媒体查询那一档就漏掉了，横屏拿到的是竖屏排布。
 * ========================================================================== */

/* (1) 顶部：信息 chips 居中、回合横幅挪到右上角，同一条带上左右分置。
 *     两者都不占布局高度，也都不会压到中央出牌区（出牌区从这条带子下面开始）。 */
.phone.immersive.landscape .table-topbar {
  top: calc(var(--navbar-h) + var(--safe-t));
  padding: 2px 10px 3px;
}
.phone.immersive.landscape .turn-banner {
  left: auto; right: 10px; transform: none;
  top: calc(var(--navbar-h) + var(--safe-t) + 2px);
  font-size: 11.5px; padding: 3px 11px;
}
.phone.immersive.landscape .turn-banner.mine { animation: none; }  /* 窄带上别缩放抖动 */

/* (2) 座位：头像在左、信息在右的**一行**（右侧座位镜像）。
 *     四五行信息竖着摞会在横屏挡住半张牌桌，也让不出顶部那条 HUD。 */
.phone.immersive.landscape .seat-abs {
  width: 134px; display: flex; flex-direction: row; align-items: center;
  gap: 7px; text-align: left;
}
.phone.immersive.landscape .seat-abs.right { flex-direction: row-reverse; text-align: right; }
.phone.immersive.landscape .seat-abs .pav {
  margin: 0; flex: 0 0 auto; width: 36px; height: 36px; font-size: 17px;
}
.phone.immersive.landscape .seat-abs .pmeta {
  display: flex; flex-direction: column; align-items: flex-start; gap: 1px; min-width: 0;
}
.phone.immersive.landscape .seat-abs.right .pmeta { align-items: flex-end; }
.phone.immersive.landscape .seat-abs .pnm { margin-top: 0; font-size: 11px; max-width: 86px; }
.phone.immersive.landscape .seat-abs .pscore { margin-top: 0; font-size: 10.5px; padding: 0 7px; min-width: 24px; }
.phone.immersive.landscape .seat-abs .pinfo { margin-top: 0; font-size: 10px; }
.phone.immersive.landscape .seat-abs .ptag { margin-top: 0; font-size: 9px; padding: 0 5px; }
.phone.immersive.landscape .seat-abs .turn-bar { bottom: -6px; width: 46px; }

/* (3) 中央出牌区：定位成一条**带子**（HUD 底 → 手牌浮层顶），内容在带子里垂直居中。
 *     以前是 `top: 41% + translateY(-50%)`：**块一高，上边缘就顶进 HUD**，
 *     横屏正好被回合横幅压住底牌（用户截图里的原样）。
 *     改成带子之后，内容再高也只是把带子填满，绝不会越到横幅上去。 */
.phone.immersive.landscape .felt .center-area {
  top: calc(var(--navbar-h) + var(--safe-t) + 30px);
  bottom: calc(var(--dock-h, 50px) + var(--my-h, 64px) + 8px);
  transform: translateX(-50%);
  max-height: none; justify-content: center;
  gap: 3px; --center-gap: 4px;
}
.phone.immersive.landscape .felt .center-hint { font-size: 10.5px; }
/* 极矮（小屏横屏）：连「底牌」这行标签都省掉，高度全留给牌 */
.phone.immersive.landscape .felt.cramped .center-area .center-hint { display: none; }
.phone.immersive.landscape .felt.cramped .play-row .card { width: 27px; height: 38px; }

/* (4) 手牌 + 操作按钮：同一行（手牌在左、按钮在右）。手牌区宽度交给 flex，
 *     layoutHand() 会照真实宽度重算叠牌间距。 */
.phone.immersive.landscape .my-area.on-felt {
  flex-direction: row; align-items: center; gap: 8px; padding: 5px 10px 4px;
}
.phone.immersive.landscape .my-area.on-felt .hand-row { flex: 1 1 auto; min-width: 0; }
.phone.immersive.landscape .actions { flex: 0 0 auto; flex-wrap: nowrap; gap: 6px; }
.phone.immersive.landscape .actions .btn { padding: 8px 11px; font-size: 12.5px; border-radius: 11px; }
.phone.immersive.landscape .hand-row .card { width: 38px; height: 54px; }
.phone.immersive.landscape .hint-row { display: none; }

/* (5) 输入区：语音条折进输入行**同一行**（左边一个小胶囊）。
 *     横屏最缺高度，「语音条 + 输入行」各占一整行是压垮出牌区的最后两根稻草。 */
.phone.immersive.landscape #dock .composer-wrap {
  display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: center; gap: 6px;
}
.phone.immersive.landscape #dock .voice-bar { grid-column: 1; margin: 0 0 0 8px; padding: 4px 9px; }
.phone.immersive.landscape #dock .composer-rowwrap { grid-column: 2; }
.phone.immersive.landscape #dock .composer { margin: 4px 8px 4px 0; padding: 4px 6px; }
.phone.immersive.landscape #dock .cbtn { width: 30px; height: 30px; font-size: 16px; border-radius: 9px; }
.phone.immersive.landscape #dock .composer .c-input { height: 30px; font-size: 13px; padding: 0 11px; }
.phone.immersive.landscape #dock .composer .c-send { height: 30px; padding: 0 12px; font-size: 12.5px; }
/* 语音胶囊只留圆点 + 按钮（「语音 / 语音已开启」这行字在横屏太占横向空间）。
 * 用 :has() 判断真有按钮才藏字 —— 环境不支持语音时那行字就是唯一的信息，
 * 藏了会剩一个空胶囊。老 WebView 不认 :has() 时只是字还在，不影响功能。 */
.phone.immersive.landscape #dock .voice-bar:has(> button) .voice-hint { display: none; }
/* 发送回执改成浮层贴在输入行上方：出现时不再把输入区顶高一整行（会挤掉出牌区） */
.phone.immersive.landscape #dock .c-receipt {
  position: absolute; left: 8px; right: 8px; bottom: 100%;
  margin: 0 0 6px; border-radius: 12px;
}
.phone.immersive.landscape #dock .composer-panel { max-height: min(46vh, 240px); }

/* 聊天浮层：让开顶部 HUD 与底部输入区 */
.phone.immersive.landscape .chat-side {
  top: calc(var(--navbar-h) + var(--safe-t) + 30px);
  bottom: calc(var(--dock-h, 50px) + 8px);
}
/* toast 别糊在手牌 / 按钮上 */
body.immersive.landscape .toasts {
  bottom: calc(var(--dock-h, 50px) + var(--my-h, 64px) + 12px);
}
