:root {
  --bg: #0d1411;
  --page-hi: #17251f;
  --felt: #16563c;
  --felt-dark: #0f3d2a;
  --felt-hi: #1c6b49;
  --felt-edge: #0a2c1e;
  --panel: #16211c;
  --panel-2: #1d2b24;
  --line: #2b3d34;
  --slot: rgba(8, 26, 18, .62);
  --slot-me: rgba(16, 44, 30, .8);
  --dock: rgba(13, 20, 17, .97);
  --text: #e8f1ea;
  --muted: #93a89d;
  --gold: #f0c368;
  --red: #e0563f;
  --green: #4bb47a;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: radial-gradient(circle at 50% 0%, var(--page-hi), var(--bg) 70%);
  color: var(--text);
  font: 15px/1.6 "Noto Sans SC", "PingFang SC", "Microsoft YaHei", system-ui, sans-serif;
  min-height: 100vh;
}

.hidden { display: none !important; }

.screen { max-width: 1240px; margin: 0 auto; padding: 20px; }
/* 门禁开关要问服务端，问到手之前先亮这一行，避免邀请页/建房页谁先冒出来 */
.boot-line { margin: 38vh auto 0; text-align: center; color: var(--muted); font-size: 14px; letter-spacing: .2em; }

button { font: inherit; cursor: pointer; border-radius: 10px; border: 1px solid var(--line); background: var(--panel-2); color: var(--text); padding: 9px 16px; }
button:hover:not(:disabled) { border-color: var(--gold); }
button:disabled { opacity: .4; cursor: not-allowed; }
button.primary { background: linear-gradient(180deg, var(--gold), #d9a63f); color: #241a06; border-color: #b8873a; font-weight: 700; }
button.ghost { background: transparent; border-color: var(--line); }
button.danger { background: #3a1d1a; border-color: #6b332b; color: #ffc7bd; }
button.mini { padding: 3px 9px; font-size: 12px; border-radius: 7px; }

/* 右上角三个开关竖着排：界面适配、桌布皮肤、声音。
   用 grid 而不是 flex：三颗自动等宽（跟着最长那条「界面：自动 · 电脑端」走），文字再统一左对齐，
   不然各按各的内容宽度长，右边齐了左边还是锯齿。 */
#top-controls {
  position: fixed; top: 12px; right: 14px; z-index: 40;
  display: grid; gap: 8px;
}
.sound-btn, .ui-btn, .skin-btn {
  padding: 5px 12px; font-size: 13px; border-radius: 999px; text-align: left;
  background: rgba(29, 43, 36, .92); border-color: var(--line); color: var(--gold);
}
.sound-btn.muted { color: var(--muted); background: rgba(22, 33, 28, .92); }
.ui-btn.auto { color: var(--muted); }

input, select {
  width: 100%; min-width: 0; padding: 9px 11px; border-radius: 9px;
  border: 1px solid var(--line); background: #101a15; color: var(--text); font: inherit;
}
input:focus, select:focus { outline: none; border-color: var(--gold); box-shadow: 0 0 0 3px rgba(240, 195, 104, .15); }
input::placeholder { color: #6d8177; }

.entry-head { margin-bottom: 16px; }
.entry-head h1 { margin: 0; font-size: 28px; letter-spacing: 2px; }
.entry-head h1 span { font-size: 14px; color: var(--gold); font-weight: 400; letter-spacing: 3px; }
.disclaimer { color: var(--muted); font-size: 13px; margin: 6px 0 0; border-left: 3px solid var(--gold); padding-left: 10px; }

.entry-grid { display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, .9fr); gap: 16px; }
@media (max-width: 900px) { .entry-grid { grid-template-columns: minmax(0, 1fr); } }
/* 两张卡拉到等高、提交按钮各自钉在卡片底边：建房卡字段多，以前进房卡下面空一整块很难看，
   现在差额变成卡片内部按钮上方的呼吸空间，两颗按钮还在同一条线上 */
.entry-grid .card-form { display: flex; flex-direction: column; }
.entry-grid .card-form > button { margin-top: auto; }

.invite-wrap { max-width: 560px; margin: 0 auto; }

.card-form { background: linear-gradient(180deg, var(--panel-2), var(--panel)); border: 1px solid var(--line); border-radius: 16px; padding: 18px 20px 20px; box-shadow: 0 10px 26px rgba(0, 0, 0, .26); }
.card-form h2 { margin: 0 0 14px; font-size: 18px; color: var(--gold); display: flex; align-items: center; gap: 9px; }
.card-form h2::before { content: ''; flex: 0 0 auto; width: 4px; height: 16px; border-radius: 2px; background: var(--gold); }
.row { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; margin-bottom: 12px; }
.row.three { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.row.single, .row > label:only-child { grid-template-columns: minmax(0, 1fr); }
.row label { display: flex; flex-direction: column; gap: 5px; font-size: 13px; color: var(--muted); min-width: 0; }
/* 标签长到换行时，输入框仍贴在格子底部，同一排的几个控件不会一个高一个低 */
.row label > input, .row label > select { margin-top: auto; }
.hint-line { font-size: 12.5px; color: var(--muted); margin: -2px 0 12px; line-height: 1.75; }
.hint-line b { color: var(--text); }
.card-form button { width: 100%; margin-top: 6px; }

.switch { display: flex; align-items: center; gap: 10px; flex-direction: row-reverse; justify-content: flex-end; color: var(--text); font-size: 14px; }
.switch input { display: none; }
.slider { flex: 0 0 auto; width: 44px; height: 24px; border-radius: 12px; background: #2a3a32; position: relative; transition: .2s; }
.slider::after { content: ''; position: absolute; top: 3px; left: 3px; width: 18px; height: 18px; border-radius: 50%; background: #6f857a; transition: .2s; }
.switch input:checked + .slider { background: #4d7a3a; }
.switch input:checked + .slider::after { transform: translateX(20px); background: var(--gold); }
/* 喜钱那一排：开关贴左、和上面那排输入框对齐（.row label 的 column 方向会把它压成竖的，这里盖回去） */
.xiqian-row { align-items: end; }
.row label.switch { flex-direction: row; justify-content: flex-start; gap: 10px; padding-bottom: 4px; }

/* 建房摘要压在两张卡下面整条铺开：放在卡片里时它一个人把建房卡撑高 100 多像素，右列就空了一块 */
.preview { margin: 14px 0 0; font-size: 12.5px; line-height: 1.7; color: var(--green); background: #12251c; border: 1px dashed #2f5a41; padding: 10px 14px; border-radius: 12px; }
.preview:empty { display: none; }

.rules { margin-top: 16px; padding: 14px 20px 16px; background: var(--panel); border: 1px solid var(--line); border-radius: 16px; font-size: 12.5px; color: var(--muted); }
.rules-head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px 16px; flex-wrap: wrap; margin-bottom: 8px; }
.rules h3 { color: var(--text); font-size: 14px; margin: 0; }
.rules ol { margin: 0; padding: 0; list-style: none; counter-reset: rl; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 28px; }
.rules li { counter-increment: rl; position: relative; padding: 5px 0 5px 27px; line-height: 1.7; border-top: 1px dashed #24362e; }
/* 双列时第一排（1、2 条）头顶没有东西可分，那条虚线就别画 */
.rules li:nth-child(1), .rules li:nth-child(2) { border-top-color: transparent; }
.rules li::before { content: counter(rl); position: absolute; left: 0; top: 7px; width: 19px; height: 19px; border-radius: 6px; background: rgba(240, 195, 104, .13); color: var(--gold); font-size: 11px; font-weight: 700; line-height: 19px; text-align: center; }
.rules b { color: var(--text); }
.rules-more { margin: 0; }
.rules-link { color: var(--gold); font-weight: 600; text-decoration: none; }
.rules-link:hover { text-decoration: underline; }

/* 完整规则独立页（/rules）：同一套配色，长条文按模式分段，返回入口挂在最上面 */
.doc-body { background: radial-gradient(circle at 50% 0%, var(--page-hi), var(--bg) 60%); }
.doc-bar {
  position: sticky; top: 0; z-index: 5; display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 12px 20px; background: var(--dock); border-bottom: 1px solid var(--line);
}
.doc-back {
  color: var(--text); text-decoration: none; font-size: 13px; padding: 6px 12px;
  border: 1px solid var(--line); border-radius: 10px; background: var(--panel-2); cursor: pointer;
}
.doc-back:hover { border-color: var(--gold); }
.doc-title { font-size: 15px; }
.doc-note { color: var(--muted); font-size: 12px; }
.doc-main { max-width: 900px; margin: 0 auto; padding: 18px 20px 40px; }
.rules-nav { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 6px; }
.rules-nav a {
  font-size: 12.5px; padding: 5px 11px; border-radius: 999px; text-decoration: none;
  color: var(--text); border: 1px solid var(--line); background: var(--panel-2); cursor: pointer;
}
.rules-nav a:hover { border-color: var(--gold); }
.rules-part { margin-top: 26px; padding: 16px 18px; border: 1px solid var(--line); border-radius: 14px; background: var(--panel); }
.rules-part h2 { margin: 0 0 4px; font-size: 17px; color: var(--gold); }
.rules-part h3 { margin: 18px 0 6px; font-size: 14px; color: var(--text); }
.rules-lead { margin: 0 0 10px; font-size: 12.5px; color: var(--muted); }
.rules-part ol { margin: 0; padding-left: 20px; font-size: 13px; color: var(--muted); }
.rules-part li { margin-bottom: 9px; }
.rules-part b { color: var(--text); }
.doc-foot { margin-top: 26px; font-size: 12.5px; color: var(--muted); }
.doc-foot a { color: var(--gold); }

.room-bar { display: flex; justify-content: space-between; align-items: center; gap: 14px; flex-wrap: wrap; background: var(--panel); border: 1px solid var(--line); border-radius: 14px; padding: 11px 16px; margin-bottom: 14px; }
.room-id { display: flex; align-items: center; gap: 9px; font-size: 13px; color: var(--muted); }
.room-id b { font-size: 22px; color: var(--gold); letter-spacing: 3px; }
.room-name { margin-left: 6px; }
.room-meta { display: flex; gap: 16px; font-size: 13px; color: var(--muted); flex-wrap: wrap; }
.room-meta b { color: var(--text); }
.room-meta .chips b { color: var(--gold); font-size: 18px; font-variant-numeric: tabular-nums; }

.table-area { display: grid; grid-template-columns: 1fr 320px; gap: 14px; align-items: start; }
@media (max-width: 980px) { .table-area { grid-template-columns: 1fr; } }

.felt { background: radial-gradient(circle at 50% 30%, var(--felt-hi), var(--felt) 45%, var(--felt-dark)); border: 2px solid var(--felt-edge); border-radius: 22px; padding: 18px; min-height: 420px; position: relative; box-shadow: inset 0 0 60px rgba(0,0,0,.45); }
/* 牌毡最上面这一格：左边放实时排行，中间还是奖池。两侧轨道等宽，所以奖池的位置一个像素都没挪。
   minmax(0,1fr) 是必须的——不写死最小 0，排行撑开会整格把奖池顶右边去。 */
.felt-top { display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); align-items: start; gap: 12px; }
.center-pot { text-align: center; margin: 0 auto 18px; max-width: 340px; background: rgba(0,0,0,.28); border: 1px solid rgba(240,195,104,.35); border-radius: 14px; padding: 10px; }
.pot-label { display: block; font-size: 12px; color: var(--muted); }
.center-pot b { font-size: 28px; color: var(--gold); font-variant-numeric: tabular-nums; }
.bet-info, .turn-info { display: block; font-size: 12.5px; color: #cfe3d6; }
.turn-info { color: var(--green); min-height: 18px; }

/* auto-fit + 上限宽度：两三个人时卡片在桌面上摊开居中，不会全挤在左上角、下面空一大片 */
.seats { display: grid; grid-template-columns: repeat(auto-fit, minmax(186px, 240px)); gap: 12px; justify-content: center; }
.seat { background: var(--slot); border: 1px solid rgba(255,255,255,.12); border-radius: 14px; padding: 10px 12px; transition: .18s; }
/* 自己的卡片走青绿，跟「轮到谁」那圈金光分得开：金色（border-color／box-shadow）是回合专用的颜色，
   所以「这是我」只留三样——1 像素青绿细边＋从左压进来的青绿渐层＋座位号和「你」牌反白成青绿底。
   别再往这里补 box-shadow：那条内粗杠叠在 1 像素边框上，看着就成了「边框好粗」，反而丑。
   轮到我自己＝青绿底＋金色光环，两个状态叠在一起都看得见，谁也不会盖掉谁。
   必须写在 .seat.active 之前：同名属性（border-color／box-shadow）后写的赢，让回合态压过常驻态。
   只动颜色不动尺寸，手机端按人数缩卡片（--sc／--ts）照样吃得住。 */
.seat.me { border-color: rgba(120,220,170,.45); background: linear-gradient(96deg, rgba(120,220,170,.18), rgba(120,220,170,0) 58%), var(--slot-me); }
.seat.me .seat-no { background: #7ee3b3; border-color: #7ee3b3; color: #10281c; }
.seat.active { border-color: var(--gold); box-shadow: 0 0 0 2px rgba(240,195,104,.25), 0 0 22px rgba(240,195,104,.25); }
.seat.folded { opacity: .42; filter: grayscale(.7); }
.seat.spectating { background: rgba(10,16,26,.5); border-style: dashed; border-color: rgba(255,224,138,.35); }
.seat-note { margin: 6px 0 0; font-size: 11.5px; color: #c8bb92; }
/* 座位卡片每一格都常年占位：名字一行还是两行、有没有气泡，都不会把下面几格挤得高低不齐 */
.seat-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 8px; min-height: 40px; }
.seat-head b { flex: none; }
/* 座位号是钉死的，卡片上的号就是这一轮他一直坐的那一格 */
.seat-no { flex: none; width: 20px; height: 20px; line-height: 18px; border-radius: 6px; background: rgba(240,195,104,.14); border: 1px solid rgba(240,195,104,.35); color: var(--gold); font-size: 12px; font-weight: 700; text-align: center; }
/* 昵称最长 10 个字：让它换行完整显示，不裁成省略号 */
.seat-name { flex: 1 1 auto; font-weight: 700; line-height: 1.3; overflow-wrap: anywhere; }
/* 标签区按两行留位（「底注由 xx 代付」碰上十字昵称正好两行） */
.tags { display: flex; gap: 5px; flex-wrap: wrap; margin: 5px 0; min-height: 48px; align-content: flex-start; }
.tag { font-size: 11px; padding: 1px 7px; border-radius: 20px; background: #24382e; color: #b9d3c3; border: 1px solid #35513f; }
.tag.blind { background: #2c2544; border-color: #4b3d71; color: #d3c6ff; }
.tag.seen { background: #1f3d2c; border-color: #37704c; color: #a6ecc2; }
.tag.allin { background: #45240f; border-color: #7a4520; color: #ffc98f; }
.tag.fold { background: #3a1d1a; border-color: #6b332b; color: #ffb3a6; }
.tag.off { background: #222; color: #999; }
.tag.online { background: #1d3a2b; border-color: #33604a; color: #9fd8b6; }
.tag.timer { background: #3d3413; border-color: #6d5b20; color: #ffe08a; font-variant-numeric: tabular-nums; }
.tag.cmp { background: #14323f; border-color: #2b6076; color: #a9e2f5; }
.tag.gift { background: #3a2b12; border-color: #7a5b20; color: #ffd98f; line-height: 1.35; text-align: center; max-width: 100%; }
.tag.watch { background: #3d3413; border-color: #8a6f28; color: #ffe08a; font-weight: 700; letter-spacing: 2px; }
/* 「你」这颗牌子反白成青绿底：满桌的标签都是深底浅字，只有自己这颗是亮的，而且颜色跟「轮到谁」的金色不撞 */
.tag.you { background: #7ee3b3; border-color: #7ee3b3; color: #10281c; font-weight: 700; }
.seat-stats { display: grid; grid-template-columns: auto auto; justify-content: space-between; align-items: baseline; column-gap: 8px; font-size: 12.5px; color: var(--muted); margin-top: 4px; }
.seat-stats b { color: var(--text); }
/* 手上／桌上／已押三个数一眼分层：手上看余额、桌上看池、已押看本局压了多少 */
.hand-chips { font-size: 15px; font-variant-numeric: tabular-nums; }
.seat-stats .paid b { color: var(--gold); font-size: 15.5px; font-variant-numeric: tabular-nums; }
.seat-stats .need b { color: #ffd0a0; font-variant-numeric: tabular-nums; }
/* 「还能押」压在「已投入」正下方：换行只由 grid 定位，需补那列跟着第一行同一条基线，不会左右歪 */
.seat-stats .paid { grid-row: 1; grid-column: 1; }
.seat-stats .need { grid-row: 1; grid-column: 2; justify-self: end; }
.seat-stats .rest { grid-row: 2; grid-column: 1; font-size: .9em; line-height: 1.3; }
.seat-stats .rest b { color: #9fd8b6; font-size: 1.15em; font-variant-numeric: tabular-nums; }
.seat-gift { margin-top: 7px; min-height: 34px; }
.seat-gift button { width: 100%; font-size: 12px; padding: 5px 6px; }
.gift-wait, .gift-done { display: block; font-size: 11.5px; line-height: 1.45; color: var(--gold); overflow-wrap: anywhere; }
.gift-done { color: #a6ecc2; }
.cards { display: flex; gap: 5px; margin-top: 8px; }
.pcard { width: 38px; height: 54px; border-radius: 6px; background: #f7f5ef; color: #161616; display: flex; flex-direction: column; align-items: center; justify-content: center; font-weight: 700; line-height: 1; box-shadow: 0 2px 5px rgba(0,0,0,.35); }
.pcard .r { font-size: 16px; }
.pcard .s { font-size: 15px; }
.pcard.red { color: #cf3b2c; }
.pcard.back { background: repeating-linear-gradient(45deg, #26489c, #26489c 5px, #1b3878 5px, #1b3878 10px); border: 2px solid #d8e2ff; }
.hand-type { font-size: 12px; color: var(--gold); margin-top: 5px; min-height: 24px; }
.seat-actions { margin-top: 8px; display: flex; gap: 6px; flex-wrap: wrap; }

.panel { background: var(--panel); border: 1px solid var(--line); border-radius: 14px; padding: 14px; margin-bottom: 12px; }
.panel h3 { margin: 0 0 8px; font-size: 14px; color: var(--gold); }
.panel .hint { color: var(--muted); font-size: 13px; }
.logs { max-height: 420px; display: flex; flex-direction: column; }
#log-list { overflow-y: auto; font-size: 12.5px; color: #bcd0c4; flex: 1; min-height: 160px; max-height: 360px; }
#log-list div { padding: 3px 0; border-bottom: 1px dashed #22322b; }

.action-bar { position: sticky; bottom: 0; margin-top: 14px; background: var(--panel); border: 1px solid var(--line); border-radius: 14px; padding: 12px 14px; display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.action-bar .group { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.action-bar .sep { width: 1px; height: 26px; background: var(--line); }
.action-bar .cost { font-size: 12px; color: var(--muted); display: block; }
.action-bar .btn-wrap { display: flex; flex-direction: column; gap: 2px; align-items: center; }
.action-bar .status { color: var(--muted); font-size: 13px; }
.action-bar .status.wait { color: var(--gold); }
.action-bar .status.timer { color: #ffe08a; font-weight: 700; font-variant-numeric: tabular-nums; }
.action-bar .status.gift-in { color: #ffd98f; font-weight: 700; }
.action-bar .custom-bet { display: flex; align-items: center; gap: 6px; font-size: 12.5px; color: var(--muted); }
.action-bar .custom-bet input { width: 104px; padding: 7px 9px; }
/* 按下就发出去的那一下：原地暗下去但不消失，手指立刻知道这有点反应 */
button.busy { opacity: .45; }
/* 看牌那一格固定宽度：看完换成灰掉的「已看牌」继续占位，后面的跟注不会被推到指尖底下 */
.action-bar .look-slot { min-width: 5.4em; text-align: center; }
/* 倒计时的数字原位填：等宽数字，每秒变化也不把旁边的字挤得左右跳 */
.cd { font-variant-numeric: tabular-nums; }

.pick-bar { margin-top: 14px; background: #14302a; border: 1px solid var(--gold); border-radius: 14px; padding: 12px 14px; display: flex; gap: 12px; align-items: center; flex-wrap: wrap; }
.pick-bar .group { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.pick-bar .hint { width: 100%; margin: 0; font-size: 12.5px; color: var(--muted); }
.pick-head { font-size: 13.5px; color: #ffe08a; font-weight: 700; }
.pick-head b { font-variant-numeric: tabular-nums; }
.pick-cards { display: flex; gap: 8px; flex-wrap: wrap; }
.pick-slot { position: relative; padding: 4px 5px 16px; background: rgba(0,0,0,.22); border: 1px solid var(--line); border-radius: 10px; cursor: pointer; }
.pick-slot.on { border-color: var(--gold); background: rgba(255,224,138,.16); box-shadow: 0 0 0 2px rgba(255,224,138,.35) inset; }
.pick-slot .slot-no { position: absolute; left: 50%; bottom: 2px; transform: translateX(-50%); font-size: 11px; color: var(--muted); }
.pick-slot.on .slot-no { color: var(--gold); }
.neg { color: #ff8f7d !important; }

.toast { position: fixed; top: 18px; left: 50%; transform: translateX(-50%) translateY(-30px); background: #2a1110; color: #ffd7d0; border: 1px solid #7a3226; padding: 10px 18px; border-radius: 10px; opacity: 0; transition: .25s; z-index: 60; pointer-events: none; font-size: 14px; }
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
.toast.ok { background: #10281a; color: #c8f2d8; border-color: #2c6a44; }

.modal { position: fixed; inset: 0; background: rgba(0,0,0,.66); display: flex; align-items: center; justify-content: center; z-index: 50; padding: 18px; }
.modal-box { background: var(--panel); border: 1px solid var(--gold); border-radius: 16px; padding: 20px; max-width: 620px; width: 100%; max-height: 80vh; overflow: auto; }
.modal-box h3 { margin: 0 0 12px; color: var(--gold); }
.modal-box .settle-row { display: flex; align-items: center; gap: 8px; padding: 7px 8px 7px 5px; border-bottom: 1px dashed var(--line); border-left: 3px solid transparent; font-size: 13.5px; }
.modal-box .settle-row.win { color: var(--gold); }
.modal-box .settle-row.win .settle-name { color: var(--gold); }
.settle-name { min-width: 68px; font-weight: 700; }
.settle-cards { display: flex; gap: 4px; }
.settle-cards .pcard { width: 26px; height: 37px; border-radius: 5px; box-shadow: none; }
.settle-cards .pcard .r { font-size: 12.5px; }
.settle-cards .pcard .s { font-size: 11.5px; }
.settle-plain { color: var(--muted); font-size: 12.5px; }
.settle-type { padding: 2px 8px; border-radius: 999px; border: 1px solid var(--line); font-size: 12px; color: var(--muted); white-space: nowrap; }
.settle-side { margin-left: auto; text-align: right; white-space: nowrap; }
.settle-side em { display: block; font-style: normal; font-size: 11.5px; color: var(--muted); }
/* 喜钱单独占一行，写明谁赔谁、各多少，长名字也不许把弹层撑破 */
.settle-side em.settle-xq { white-space: normal; line-height: 1.45; }
.settle-side em.settle-xq.up { color: #7fd6a1; }
.settle-side em.settle-xq.down { color: var(--red); }
.settle-net { font-size: 14.5px; font-variant-numeric: tabular-nums; }
.settle-net.up { color: #7fd6a1; }
.settle-net.down { color: var(--red); }

/* 牌型特效：单张以外的牌型各占一色，整行描边发光 */
@keyframes settle-fx { 0%, 100% { box-shadow: -6px 0 10px -8px var(--fx); } 50% { box-shadow: -6px 0 16px -6px var(--fx); } }
@keyframes settle-pop { from { opacity: 0; transform: translateY(5px); } to { opacity: 1; transform: none; } }
/* 牌型颜色同时给结算榜单那一行和牌桌上的慢镜头揭晓条用 */
.settle-row.t-pair, .rv-row.t-pair { --fx: #6ec1ff; }
.settle-row.t-straight, .rv-row.t-straight { --fx: #7bd88f; }
.settle-row.t-flush, .rv-row.t-flush { --fx: #b98cff; }
.settle-row.t-strflush, .rv-row.t-strflush { --fx: #ffd166; }
.settle-row.t-triple, .rv-row.t-triple { --fx: #ff6b6b; }
.settle-row.t-235, .rv-row.t-235 { --fx: var(--muted); }
.rv-row.t-235.hot { --fx: #ff6b6b; }
.settle-row[class*=" t-"] { border-left-color: var(--fx); animation: settle-fx 2.4s ease-in-out infinite; }
.settle-row[class*=" t-"] .settle-type { animation: settle-pop .45s ease-out; }
.settle-type.t-pair, .settle-type.t-straight, .settle-type.t-flush, .settle-type.t-strflush, .settle-type.t-triple, .settle-type.t-235 {
  color: #0e1319; border-color: var(--fx); font-weight: 700; }
.settle-type.t-pair { background: #6ec1ff; }
.settle-type.t-straight { background: #7bd88f; }
.settle-type.t-flush { background: #b98cff; }
.settle-type.t-strflush { background: linear-gradient(100deg, #ffd166, #fff3c4 50%, #e0a63c); }
.settle-type.t-triple { background: linear-gradient(100deg, #ff8f6b, #ff4d6d 55%, #ffd166); text-shadow: 0 0 6px rgba(255,255,255,.45); }
.settle-type.t-235 { background: transparent; color: var(--fx); border-style: dashed; }
/* 235 平时没有颜色；本局摊出豹子时它才上色，且颜色一直在跑 —— 一眼就能看出这局撞上了豹子 */
.settle-row.t-235.hot { --fx: #ff6b6b; animation: settle-rainbow 1.8s linear infinite; }
.settle-type.t-235.hot {
  border-style: solid; color: #0e1319; font-weight: 700;
  background: linear-gradient(90deg, #ff6b6b, #ffd166, #7bd88f, #6ec1ff, #b98cff, #ff6b6b);
  background-size: 300% 100%; animation: settle-rainbow-fill 2.6s linear infinite;
}
@keyframes settle-rainbow {
  0% { box-shadow: -6px 0 14px -7px #ff6b6b; border-left-color: #ff6b6b; }
  25% { box-shadow: -6px 0 14px -7px #7bd88f; border-left-color: #7bd88f; }
  50% { box-shadow: -6px 0 14px -7px #6ec1ff; border-left-color: #6ec1ff; }
  75% { box-shadow: -6px 0 14px -7px #b98cff; border-left-color: #b98cff; }
  100% { box-shadow: -6px 0 14px -7px #ff6b6b; border-left-color: #ff6b6b; }
}
@keyframes settle-rainbow-fill { from { background-position: 0 0; } to { background-position: 300% 0; } }

/* 摊牌慢镜头：座位下面这一条（正常流，不盖任何东西），按座位顺序一家一家往外翻 */
.reveal { flex: 0 0 auto; margin-top: 14px; background: rgba(0,0,0,.34); border: 1px solid rgba(240,195,104,.3); border-radius: 14px; padding: 10px 12px; }
.rv-head { font-size: 12.5px; color: var(--gold); margin-bottom: 6px; }
.rv-row { display: flex; align-items: center; gap: 10px; padding: 6px 0; border-left: 3px solid transparent; }
.rv-seat { flex: none; width: 20px; height: 20px; line-height: 18px; border-radius: 6px; border: 1px solid rgba(240,195,104,.35); color: var(--gold); font-size: 12px; font-weight: 700; text-align: center; }
.rv-name { font-weight: 700; min-width: 88px; overflow-wrap: anywhere; }
/* 真·翻牌动作：一张一张各自从牌背转到牌面（整排像书页一样翻是被否掉的），只有刚翻开那一家动 */
.settle-cards .pcard-flip { position: relative; flex: none; width: 26px; height: 37px; perspective: 260px; }
.settle-cards .pcard-turn { position: relative; display: block; width: 100%; height: 100%; transform-style: preserve-3d; animation: rv-flip .6s cubic-bezier(.34,.02,.32,1) both; }
.settle-cards .pcard-turn > .pcard { position: absolute; inset: 0; backface-visibility: hidden; -webkit-backface-visibility: hidden; }
.settle-cards .pcard-turn > .pcard.back { transform: rotateY(180deg); }
.rv-row.fresh .pcard-flip:nth-child(2) .pcard-turn { animation-delay: .13s; }
.rv-row.fresh .pcard-flip:nth-child(3) .pcard-turn { animation-delay: .26s; }
.rv-row.fresh .settle-type { animation: settle-pop .35s ease-out .5s both; }
@keyframes rv-flip { 0% { transform: rotateY(-180deg) translateY(-7px); } 55% { transform: rotateY(0) translateY(2px); } 72% { transform: rotateY(11deg) translateY(-3px); } 88% { transform: rotateY(-4deg) translateY(1px); } 100% { transform: rotateY(0) translateY(0); } }
/* 自己点「看牌」那一下：桌上自己那张卡片＋固定栏钉住的「我的手牌」各自从牌背翻到牌面，复用上面 rv-flip。
   别人的快照里没有牌面，这段 markup 压根不会出现，所以只有我自己看得见。五选三五张一起翻，第 4／5 张接着往后错。 */
.seat .cards .pcard-flip, .my-hand-cards .pcard-flip { position: relative; flex: none; width: 38px; height: 54px; perspective: 300px; }
.seat .cards .pcard-turn, .my-hand-cards .pcard-turn { position: relative; display: block; width: 100%; height: 100%; transform-style: preserve-3d; animation: rv-flip .6s cubic-bezier(.34,.02,.32,1) both; }
.seat .cards .pcard-turn > .pcard, .my-hand-cards .pcard-turn > .pcard { position: absolute; inset: 0; backface-visibility: hidden; -webkit-backface-visibility: hidden; }
.seat .cards .pcard-turn > .pcard.back, .my-hand-cards .pcard-turn > .pcard.back { transform: rotateY(180deg); }
.seat .cards .pcard-flip:nth-child(2) .pcard-turn, .my-hand-cards .pcard-flip:nth-child(2) .pcard-turn { animation-delay: .13s; }
.seat .cards .pcard-flip:nth-child(3) .pcard-turn, .my-hand-cards .pcard-flip:nth-child(3) .pcard-turn { animation-delay: .26s; }
.seat .cards .pcard-flip:nth-child(4) .pcard-turn, .my-hand-cards .pcard-flip:nth-child(4) .pcard-turn { animation-delay: .39s; }
.seat .cards .pcard-flip:nth-child(5) .pcard-turn, .my-hand-cards .pcard-flip:nth-child(5) .pcard-turn { animation-delay: .52s; }
/* 炸裂分档：按牌型大小一级一级往上加，对子最轻、235 撞上豹子最狠（普通 235 与同花 235 都吃不到特效） */
.rv-row.lv1 { box-shadow: 0 0 8px -5px var(--fx); }
.rv-row.lv2 { box-shadow: 0 0 12px -4px var(--fx); }
.rv-row.lv3 { box-shadow: 0 0 17px -3px var(--fx); border-left-color: var(--fx); }
.rv-row.lv4 { box-shadow: 0 0 22px -1px var(--fx); border-left-color: var(--fx); background: linear-gradient(90deg, rgba(255,209,102,.14), transparent 70%); }
.rv-row.lv5 { box-shadow: 0 0 26px 0 var(--fx); background: linear-gradient(90deg, rgba(255,107,107,.18), transparent 72%); animation: rv-shake .6s ease-in-out 2; }
.rv-row.lv6 { box-shadow: 0 0 30px 2px var(--fx); background: linear-gradient(90deg, rgba(255,107,107,.22), transparent 78%); animation: rv-shake .5s ease-in-out 3, settle-rainbow 1.8s linear infinite; }
@keyframes rv-shake { 0%, 100% { transform: translateX(0); } 25% { transform: translateX(-5px); } 75% { transform: translateX(5px); } }

/* 读秒心跳：行动倒计时最后 5 秒，红光滑在 body 内侧边缘——不新建浮层、不挡任何 DOM */
body.tense { box-shadow: inset 0 0 0 3px rgba(255,80,80,.5), inset 0 0 120px rgba(255,60,60,.3); animation: tense-pulse 1s ease-in-out infinite; }
@keyframes tense-pulse { 50% { box-shadow: inset 0 0 0 3px rgba(255,110,110,.9), inset 0 0 170px rgba(255,60,60,.5); } }
/* 读秒心跳顺带把该行动那一家点亮：只有轮到的那张卡片跟着闪，别人家安安静静 */
body.tense .seat.active { animation: tense-seat 1s ease-in-out infinite; }
@keyframes tense-seat {
  0%, 100% { border-color: var(--gold); box-shadow: 0 0 0 2px rgba(240,195,104,.25), 0 0 22px rgba(240,195,104,.25); }
  50% { border-color: #ff6a52; box-shadow: 0 0 0 3px rgba(255,96,80,.75), 0 0 26px rgba(255,70,50,.5); }
}

/* 名场面那一下的特效：一律挂在座位卡自己身上（牌砸一下、圈红、裂开、掉一枚「喜」），
   不新建浮层、不额外占位——牌桌每秒重画一次，特效 class 过点就不再拼进去，动画自己就停了 */
.seat.fx-slam .cards { animation: fx-slam .42s cubic-bezier(.2,1.5,.4,1); }
.seat.fx-owed { border-color: rgba(255,96,80,.75); animation: fx-owed 1s ease-in-out 3; }
.seat.fx-xi { border-color: rgba(240,195,104,.8); box-shadow: 0 0 16px rgba(240,195,104,.35); }
@keyframes fx-slam { 0% { transform: translateY(-14px) scale(1.06); } 60% { transform: translateY(3px) scale(.97); } 100% { transform: none; } }
@keyframes fx-owed { 0%, 100% { box-shadow: 0 0 0 1px rgba(255,96,80,.25); } 50% { box-shadow: 0 0 0 3px rgba(255,96,80,.6), 0 0 18px rgba(255,80,60,.35); } }
/* 比牌输家那三张牌裂开再复原：牌桌上的座位卡与「比牌定胜负」那一条都用这一套 */
.fx-crack { animation: fx-crack-shake .6s ease-out; }
/* 中途比牌的输家同一次重绘里就变成弃牌位，被那条半透明压到几乎看不出裂：裂的这 3.6 秒先给他拉回全亮 */
.seat.fx-crack { opacity: 1; filter: none; }
.fx-crack .pcard { position: relative; animation: fx-crack .78s ease-out; }
.fx-crack .pcard:nth-child(2) { animation-delay: .05s; }
.fx-crack .pcard:nth-child(3) { animation-delay: .1s; }
.fx-crack .pcard::after {
  content: ''; position: absolute; inset: 0; border-radius: inherit; opacity: 0; pointer-events: none;
  background: linear-gradient(115deg, transparent 42%, #fff 44%, transparent 47%, transparent 56%, #fff 58%, transparent 61%);
  animation: fx-crack-line .78s ease-out;
}
@keyframes fx-crack-shake { 0%, 100% { transform: none; } 30% { transform: translateX(-3px); } 65% { transform: translateX(3px); } }
@keyframes fx-crack {
  0% { transform: none; }
  22% { transform: translateY(-4px) rotate(-4deg); }
  46% { transform: translateY(10px) rotate(9deg) scale(.92); }
  62% { transform: translateY(-2px) rotate(-3deg); }
  100% { transform: none; }
}
@keyframes fx-crack-line { 0%, 20% { opacity: 0; } 45% { opacity: .95; } 70% { opacity: .5; } 100% { opacity: 0; } }
/* 喜钱那枚「喜」：从奖池那个方向落进他常年留空的气泡槽，落地顿一下；奖池同一时刻晃一下 */
.xq-hit {
  flex: none; align-self: flex-start; margin: 8px 0 0 6px; padding: 4px 9px; border-radius: 999px;
  background: linear-gradient(100deg, #ffd166, #fff3c4 50%, #e0a63c); color: #2b1d05;
  font-weight: 800; font-size: 12.5px; letter-spacing: .04em; box-shadow: 0 3px 10px rgba(0,0,0,.4);
  animation: xq-drop .62s cubic-bezier(.2,1.4,.35,1) both;
}
@keyframes xq-drop {
  0% { opacity: 0; transform: translate(-70px, -46px) scale(.35); }
  55% { opacity: 1; transform: translate(0, 4px) scale(1.08); }
  100% { opacity: 1; transform: none; }
}
#pot-value.fx-pour { display: inline-block; color: #ffe9a8; animation: pot-pour .6s ease-out 2; }
@keyframes pot-pour { 0%, 100% { transform: none; } 35% { transform: translateY(-4px) scale(1.12); } }
/* 奖池水位：液体在奖池这一格里从底往上长，水面一直有两道波在来回晃。满刻度＝本局奖池最终还能长到的那个数
   （已经进池的钱 + 还在场的人还能押的额度，弃牌/押满/离席的都不再往上涨），也就是「还在场的都把该押的押到底」那一格；
   比牌那一注没有上限（另一半不吃配额），漫过刻度时液面不再长高；最后一注跟到底那一下引擎当场就把池扫走，所以有人把额度押到底时同样点亮锅沿晃一下。颜色一律取当前桌布自己那几个变量（--felt-hi/--felt/--felt-dark），五套桌布换着都不串色。
   数字永远是真的，水只是给人看的：它绝对在格子内、字都压在它上面、点不到它 */
.center-pot { position: relative; overflow: hidden; }
.pot-water {
  position: absolute; left: 0; right: 0; bottom: 0; height: calc(var(--lv, 0) * (100% - 26px));
  /* 液体本体必须比格子底色亮一档，否则跟面板糊成一片、只看得到一条浪线 */
  background: linear-gradient(180deg, color-mix(in srgb, var(--felt-hi) 72%, white) 0,
    color-mix(in srgb, var(--felt) 76%, white) 38%, var(--felt-dark) 100%);
  opacity: min(.86, calc(var(--lv, 0) * 16)); pointer-events: none; transition: height .5s ease-out;
  box-shadow: inset 0 10px 16px rgba(255, 255, 255, .07);
}
/* 浪线用一张正弦曲线的 SVG 当蒙版，颜色由液面自己那层背景出——所以五套桌布换着都不串色。
   两道波的波长（40px / 64px）、快慢与方向都不一样，叠起来才像一汪活的水；
   瓦片左右两端的斜率相同，平铺过去接缝看不出来。液面最高只涨到「本局奖池」那行字下面，浪尖不盖字 */
.pot-water::before, .pot-water::after {
  content: ''; position: absolute; left: -50%; width: 200%; top: -4px; height: 8px;
  /* 浪尖是一条从上往下淡开的柔光，不是一条硬边绳子——硬边会把压在上面的字切断 */
  background: linear-gradient(180deg, var(--pot-crest, color-mix(in srgb, var(--felt-hi) 45%, white)), transparent 92%);
  opacity: .95; -webkit-mask-repeat: repeat-x; mask-repeat: repeat-x;
}
.pot-water::before {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='40' height='6'%3E%3Cpath d='M0 3 Q10 0 20 3 T40 3 V6 H0 Z' fill='%23fff'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='40' height='6'%3E%3Cpath d='M0 3 Q10 0 20 3 T40 3 V6 H0 Z' fill='%23fff'/%3E%3C/svg%3E");
  -webkit-mask-size: 40px 8px; mask-size: 40px 8px; animation: pot-wave 3.4s linear infinite;
}
.pot-water::after {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='64' height='6'%3E%3Cpath d='M0 3 Q16 0 32 3 T64 3 V6 H0 Z' fill='%23fff'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='64' height='6'%3E%3Cpath d='M0 3 Q16 0 32 3 T64 3 V6 H0 Z' fill='%23fff'/%3E%3C/svg%3E");
  -webkit-mask-size: 64px 8px; mask-size: 64px 8px; opacity: .45; animation: pot-wave-back 5.3s linear infinite;
}
@keyframes pot-wave { to { transform: translateX(40px); } }
@keyframes pot-wave-back { to { transform: translateX(-64px); } }
/* 漫过顶格：两道波自己染成桌布那抹金，锅沿再一亮一暗地晃 */
.pot-water.brim { --pot-crest: var(--gold); animation: pot-brim 1.5s ease-in-out infinite; }
@keyframes pot-brim { 0%, 100% { box-shadow: inset 0 -3px 10px rgba(240,195,104,.18); } 50% { box-shadow: inset 0 -9px 20px rgba(240,195,104,.42); } }
.center-pot > .pot-label, .center-pot > b, .center-pot > .bet-info, .center-pot > .turn-info { position: relative; text-shadow: 0 1px 3px rgba(0, 0, 0, .62); }
/* 熄灯追光：摊牌翻到豹子／同花顺／235 吃豹子那一家，整桌压暗 0.8 秒、只有他这一家还亮着。
   和读秒红光是同一套做法——压暗的那层是 .felt 自己的内阴影（画在背景上、内容之下），
   别家只降 opacity，不新建浮层、不定位、不动任何布局，过点那次重画 class 一摘就恢复 */
body.spot .felt { box-shadow: inset 0 0 0 60vmax rgba(3, 9, 6, .74), inset 0 0 60px rgba(0, 0, 0, .45); }
body.spot .seat:not(.spot-lit), body.spot .center-pot, body.spot #deck { opacity: .22; }
body.spot .rv-row:not(.spot-lit) { opacity: .3; }
body.spot .seat, body.spot .rv-row, body.spot .center-pot, body.spot #deck { transition: opacity .18s; }
body.spot .seat.spot-lit {
  border-color: var(--gold); box-shadow: 0 0 0 2px rgba(240,195,104,.4), 0 0 40px rgba(240,195,104,.5);
  transform: scale(1.035);
}
body.spot .rv-row.spot-lit { border-left-color: var(--gold); background: linear-gradient(90deg, rgba(240,195,104,.2), transparent 72%); }
/* 单局每人最多下注剩的已经不够再涨一档（加注整排点不动）：押满那一颗自己发光 */
.action-bar button.last-shot { border-color: var(--gold); color: #ffe9a8; animation: last-shot 1.15s ease-in-out infinite; }
@keyframes last-shot { 0%, 100% { box-shadow: 0 0 0 1px rgba(240,195,104,.4); } 50% { box-shadow: 0 0 14px 2px rgba(240,195,104,.65); } }
/* 牌山发牌：右上角摆一摞牌，按行动顺序一张一张甩到各家座位上。
   每张牌的 animation-delay 全部由引擎给的 dealAt/dealStep/dealStagger 算出来、一局里只算一次并钉死，
   牌桌每秒重画时座位那串 HTML 一个字都不变，动画才不会被打断从头再来 */
.deck { position: relative; justify-self: end; align-self: start; min-width: 78px; padding-top: 2px; pointer-events: none; }
.deck:empty { display: none; }
.deck .pcard { width: 30px; height: 43px; border-radius: 5px; }
.deck-stack { position: relative; height: 52px; }
.deck-stack > .pcard { position: absolute; right: 0; bottom: 0; }
.deck-stack > .pcard:nth-child(1) { transform: translate(-13px, -8px) rotate(-9deg); }
.deck-stack > .pcard:nth-child(2) { transform: translate(-7px, -4px) rotate(-5deg); }
/* 每甩一家，山头上飞掉一枚：这一枚从牌山往桌心去，和落到座位上的那张是同一张牌 */
.deck-shot { position: absolute; right: 3px; bottom: 3px; animation: deck-shot .62s cubic-bezier(.22,.85,.3,1) both; }
@keyframes deck-shot {
  0% { opacity: 1; transform: none; }
  100% { opacity: 0; transform: translate(var(--shot-x, -70px), var(--shot-y, 52px)) rotate(-20deg) scale(.6); }
}
/* 落到座位上的那一张：从右上方飞进来。还没轮到它的时分（正延时）由 both 吃掉 0% 那一帧，先藏好 */
.pcard.fx-fly { animation: card-fly .62s cubic-bezier(.22,.85,.3,1.06) both; }
@keyframes card-fly {
  0% { opacity: 0; transform: translate(var(--fly-x, 76px), var(--fly-y, -58px)) rotate(15deg) scale(.5); }
  70% { opacity: 1; transform: translate(-3px, 3px) rotate(-4deg) scale(1.06); }
  100% { opacity: 1; transform: none; }
}
/* 场上还剩别人那几场比牌：输家这张卡片只演「掉下去」这一下，不裂也不捞回来——掉到底就直接是桌上的弃牌态 */
.seat.fx-drop { animation: seat-drop-fold 2.6s cubic-bezier(.45,.04,.7,.6) both; }
@keyframes seat-drop-fold {
  0% { transform: none; opacity: 1; filter: none; }
  38% { transform: translateY(var(--fall-y, 150px)) rotate(9deg) scale(.9); opacity: 0; filter: none; }
  58% { transform: translateY(var(--fall-y, 150px)) rotate(9deg) scale(.9); opacity: 0; }
  59% { transform: none; opacity: 0; filter: grayscale(.7); }
  100% { transform: none; opacity: .42; filter: grayscale(.7); }
}
/* 只剩两家那一场比牌：裂的是输家整张座位卡片，裂完跟着掉下去，本局榜单排在它走完之后 */
.seat.fx-crack.fx-fall { animation: fx-crack-shake .6s ease-out, seat-fall 1.5s cubic-bezier(.45,.04,.7,.6) 1s both; }
@keyframes seat-fall {
  0% { transform: none; opacity: 1; }
  50% { transform: translateY(26px) rotate(3deg); opacity: .85; }
  100% { transform: translateY(var(--fall-y, 150px)) rotate(9deg) scale(.9); opacity: 0; }
}
/* 收池扫牌：没人摊牌、一家把奖池收走那种结局，三张牌背一起扫向奖池，榜单排在它走完之后 */
.rv-row.fx-sweep .settle-cards .pcard { animation: sweep-backs 1.4s cubic-bezier(.3,.7,.4,1) both; }
.rv-row.fx-sweep .settle-cards .pcard:nth-child(2) { animation-delay: .08s; }
.rv-row.fx-sweep .settle-cards .pcard:nth-child(3) { animation-delay: .16s; }
@keyframes sweep-backs {
  0%, 22% { opacity: 1; transform: none; }
  58% { opacity: 1; transform: translate(-8px, -14px) rotate(-6deg); }
  100% { opacity: 0; transform: translate(-120px, -46px) rotate(-24deg) scale(.55); }
}
.rank-table { width: 100%; border-collapse: collapse; font-size: 13.5px; }
.rank-table td { padding: 6px 4px; border-bottom: 1px dashed var(--line); }
.rank-table td:last-child { text-align: right; color: var(--gold); }

/* 消息气泡：占位槽常年保留（按能装下一整句自己打的话留位），消息出现与消失都不改变座位卡片的高度 */
.bubble-slot { min-height: 96px; display: flex; align-items: flex-start; }
.bubble {
  position: relative; margin-top: 8px; padding: 6px 10px; border-radius: 12px;
  background: linear-gradient(180deg, #fdfaf1, #efe7d3); color: #22301f;
  font-size: 12.5px; line-height: 1.45; box-shadow: 0 3px 8px rgba(0,0,0,.35);
  max-height: 86px; overflow: hidden; overflow-wrap: anywhere;
}
/* 续底气泡带着两个人的昵称，字距收紧才装得下（不然第三行直接被裁掉） */
.bubble.gift { font-size: 11.5px; font-weight: 700; letter-spacing: .02em; }
/* 自己打的一条最长 50 字，密排才装得进同一种卡片 */
.bubble.free { font-size: 11.5px; font-weight: 700; letter-spacing: .02em; }
/* 每秒重画牌桌时气泡是新元素，动画只在这条消息第一次出现时播一遍，否则就是反复弹跳 */
.bubble.in { animation: bubble-in .18s ease-out; }
.bubble::after {
  content: ''; position: absolute; top: -6px; left: 16px;
  border: 6px solid transparent; border-bottom-color: #fdfaf1; border-top: 0;
}
@keyframes bubble-in { from { opacity: 0; transform: translateY(4px) scale(.96); } }

/* 侧栏消息流 */
.chat-list { display: flex; flex-direction: column; gap: 6px; max-height: 190px; overflow-y: auto; }
.chat-list:empty::after { content: '还没有人发过消息'; color: var(--muted); font-size: 12.5px; }
.chat-row { display: flex; gap: 8px; font-size: 12.5px; color: #cfe3d6; padding: 4px 0; border-bottom: 1px dashed #22322b; }
.chat-row b { color: var(--gold); font-weight: 600; flex: 0 0 auto; max-width: 10em; line-height: 1.3; overflow-wrap: anywhere; }
/* 快捷消息一律加粗放大、字间留白 */
.bubble, .chat-row span, .line-grid button {
  font-weight: 800; letter-spacing: .22em; text-transform: uppercase;
}
.chat-row span { font-size: 13px; }
/* 自己打的那句不用留字距，否则一行装不下六个字 */
.chat-row span.free { font-size: 12.5px; letter-spacing: .02em; }

/* 发消息面板：上面是自己打字，下面还是那批预设语句 */
.chat-input-row { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }
.chat-input-row input { flex: 1 1 auto; min-width: 0; padding: 7px 9px; }
.chat-count { flex: 0 0 auto; font-size: 12px; color: var(--muted); }

/* 一轮结束后的总榜单 */
.board { display: flex; flex-direction: column; gap: 8px; margin: 10px 0; }
.board-row {
  display: grid; grid-template-columns: 26px 1fr auto; align-items: center; gap: 8px;
  padding: 8px 10px; border: 1px solid var(--line); border-radius: 10px; background: var(--slot);
}
.board-row.me { border-color: rgba(120, 220, 170, .5); }
.board-rank { color: var(--muted); font-size: 13px; }
.board-name { min-width: 0; font-size: 14px; overflow-wrap: anywhere; }
.board-score { font-size: 17px; color: var(--gold); }
/* 正数是这一轮真赢到分的：一层斜着扫过去的高光，外圈再慢慢呼吸 */
.board-row.pos {
  position: relative; overflow: hidden; border-color: rgba(255, 214, 102, .6);
  box-shadow: 0 0 10px rgba(255, 200, 80, .3); animation: board-glow 1.9s ease-in-out infinite;
}
.board-row.pos::after {
  content: ''; position: absolute; top: 0; left: -60%; width: 45%; height: 100%; pointer-events: none;
  background: linear-gradient(100deg, transparent, rgba(255, 255, 255, .5), transparent);
  animation: board-shine 2.4s linear infinite;
}
.board-row.first .board-name { font-weight: 800; }
.board-row.first .board-name::after { content: ' 🥇'; }
@keyframes board-shine { to { left: 130%; } }
@keyframes board-glow { 50% { box-shadow: 0 0 20px rgba(255, 214, 102, .62); } }
@media (prefers-reduced-motion: reduce) {
  .board-row.pos { animation: none; }
  .board-row.pos::after { animation: none; left: 20%; opacity: .35; }
  .rv-row.lv5, .rv-row.lv6 { animation: none; }
  .rv-row.fresh .pcard-turn, .rv-row.fresh .settle-type { animation: none; }
  .seat .cards .pcard-turn, .my-hand-cards .pcard-turn { animation: none; }
  body.tense { animation: none; }
  body.tense .seat.active { animation: none; }
  .seat.fx-slam .cards, .seat.fx-owed, .fx-crack, .fx-crack .pcard, .fx-crack .pcard::after,
  .pcard.fx-fly, .deck-shot, .seat.fx-crack.fx-fall, .seat.fx-drop, .rv-row.fx-sweep .settle-cards .pcard,
  .xq-hit, #pot-value.fx-pour, .action-bar button.last-shot, .pot-water.brim, .pot-water::before, .pot-water::after { animation: none; }
  .xq-hit { opacity: 1; }
  .fx-crack .pcard::after { opacity: .5; }
  .pcard.fx-fly { opacity: 1; transform: none; }
  .deck-shot { display: none; }
  .seat.fx-crack.fx-fall { opacity: 1; transform: none; }
  .seat.fx-drop { opacity: .42; transform: none; }
  .rv-row.fx-sweep .settle-cards .pcard { opacity: 1; transform: none; }
}

/* 快捷消息选择面板 */
.line-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; }
@media (max-width: 620px) { .line-grid { grid-template-columns: 1fr; } }
.line-grid button { text-align: left; font-size: 13px; }

/* 实时排行：坐在牌毡左上那一格（跟奖池同一行，走正常流，谁都不挡，也不给桌布加一行高度）。
   收成一条＝左边竖排三行「实时／排行／你第几」；点开就往右边长出一张表格：三行＝名次／玩家名／积分，一列一个人，
   格子带边框、行标题钉在左边，装不下就在框里横向滚（滑轮直接滚），名字多长都不裁。手机端收成一条，点开往下摊。 */
.live-rank { justify-self: start; min-width: 0; max-width: 100%; display: flex; align-items: stretch; gap: 6px; padding: 4px; background: rgba(6,14,10,.62); border: 1px solid rgba(240,195,104,.3); border-radius: 14px; font-size: 12.5px; }
/* 一行都还没有的时候别摆个空框在那儿 */
.live-rank:empty { display: none; }
/* 标题那一列：三行撑满，「实时／排行」顶到上边、「你第几」顶到下边，所以展开和收起一样高（行高跟表格对齐） */
.lr-head { display: flex; flex-direction: column; justify-content: space-between; align-items: flex-start; line-height: 24px; flex: 0 0 auto; padding: 4px 9px; background: none; border: 0; color: var(--gold); font-weight: 700; font-size: 12.5px; text-align: left; cursor: pointer; }
.lr-me { color: #a6ecc2; }
/* ▸ 指右＝往右展开表格；展开后转 180° 成 ◂＝收回左边 */
.lr-fold { display: inline-block; margin-left: 4px; font-size: 11px; transition: transform .15s; }
.live-rank.open .lr-fold { transform: rotate(180deg); }
.lr-list { display: none; min-width: 0; max-width: 100%; overflow-x: auto; overflow-y: hidden; scrollbar-width: thin; }
.live-rank.open .lr-list { display: block; }
/* 边框必须一格一格自己画（separate ＋ 只画右和下）：border-collapse 下 Chrome 不给钉住的表头画边框，
   横向滚的时候文字会从边框缝里透出来。 */
.lr-table { border-collapse: separate; border-spacing: 0; border-top: 1px solid rgba(240,195,104,.28); font-size: 12px; line-height: 19px; }
.lr-table th, .lr-table td { border-right: 1px solid rgba(240,195,104,.28); border-bottom: 1px solid rgba(240,195,104,.28); padding: 3px 8px; white-space: nowrap; text-align: center; font-variant-numeric: tabular-nums; }
/* 第一列是行标题（名次／玩家名／积分），横向滚的时候钉在左边别跟着走；底色必须是不透明的 */
.lr-table th { position: sticky; left: 0; z-index: 2; background: #0b1a13; color: var(--gold); font-weight: 700; }
.lr-table td { color: var(--text); }
.lr-table td.lr-s { color: var(--gold); }
.lr-table td.me { background: rgba(120,220,170,.16); }
body.mob .felt-top { display: block; }
/* 手机端整块铺满一行：宽度和父级排版无关——width:100% 管住正常流那一种，justify-self: stretch 管住
   万一还是网格的那一种（桌面那条 justify-self: start 会让它缩成一团，这里必须按掉）。 */
body.mob .live-rank { position: relative; width: 100%; max-width: 100%; justify-self: stretch; flex-direction: column; align-items: stretch; gap: 0; margin-bottom: 8px; }
/* 标题横着排一条，三段全部顶到左边：「实时 排行▴ 你第 3」中间就空一格（gap 6px），不许把「你第几」推到最右 */
body.mob .lr-head { flex-direction: row; justify-content: flex-start; align-items: center; gap: 6px; width: 100%; padding: 7px 9px; }
body.mob .lr-me { margin-left: 0; }
body.mob .lr-fold { margin-left: 0; transform: rotate(90deg); }
body.mob .live-rank.open .lr-fold { transform: rotate(-90deg); }
/* 手机端点开＝挂在标题条下面的一张下拉框：横竖都能拖（两个方向的滚动条都露着），会盖住下面几张卡片，
   但点牌桌别处就收回（app.js 的 dismiss），所以不心疼；也不拉长桌布，因为它是浮起来的。桌面那套一行都不动。 */
body.mob .lr-list { position: absolute; top: calc(100% + 5px); left: 0; right: 0; z-index: 8; max-height: 46vh; overflow: auto; background: #0b1a13; border: 1px solid rgba(240,195,104,.3); border-radius: 12px; box-shadow: 0 12px 26px rgba(0,0,0,.55); }
/* 手机浏览器默认是划到才现身的悬浮条，这里钉成常驻的细条，横竖两条都看得见 */
body.mob .lr-list::-webkit-scrollbar { width: 7px; height: 7px; }
body.mob .lr-list::-webkit-scrollbar-track { background: rgba(255,255,255,.07); border-radius: 4px; }
body.mob .lr-list::-webkit-scrollbar-thumb { background: rgba(240,195,104,.5); border-radius: 4px; }
body.mob .lr-table th, body.mob .lr-table td { padding: 4px 10px; }

/* 房主的开新一轮面板 */
.round-box { margin-top: 10px; padding-top: 8px; border-top: 1px dashed var(--line); }
.round-box h4 { margin: 0 0 6px; font-size: 13px; color: var(--text); font-weight: 600; }
.round-row { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; font-size: 13px; }
.round-row > span { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: #cfe3d6; }
.round-row input { width: 96px; padding: 6px 8px; }
/* 局数输入框在侧栏和榜单弹窗里各出现一次，用 class 不用 id（同名 id 会撞车） */
.next-hand-limit { width: 96px; padding: 6px 8px; }
.round-row button { padding: 6px 12px; font-size: 13px; }

/* 牌桌观感微调 */
.seat { box-shadow: 0 2px 10px rgba(0,0,0,.28); }
.seat:hover .cards .pcard:not(.back) { transform: translateY(-2px); }
.cards .pcard { transition: transform .15s; }
.center-pot { box-shadow: inset 0 0 24px rgba(0,0,0,.35); }
#log-list::-webkit-scrollbar, .chat-list::-webkit-scrollbar { width: 8px; }
#log-list::-webkit-scrollbar-thumb, .chat-list::-webkit-scrollbar-thumb { background: #2b3d34; border-radius: 8px; }

/* 手机端适配：右上角「界面」开关切成手机端（或窄屏触屏自动进入）后生效。
   目标是牌桌一屏看全、任何一块都不用左右划，所以栅格全部收到 1fr、弹性子项一律 min-width:0。 */
body.mob { overflow-x: hidden; }
body.mob #top-controls {
  position: static; display: flex; flex-direction: row; justify-content: flex-end;
  gap: 6px; padding: 8px 10px 0; margin: 0 auto; max-width: 1240px;
}
/* 三颗一起收，漏掉 skin-btn 就会出现中间那颗比两边高一头 */
body.mob .sound-btn, body.mob .ui-btn, body.mob .skin-btn { font-size: 12px; padding: 4px 10px; }
body.mob .screen { padding: 10px 8px 16px; }
body.mob .entry-head h1 { font-size: 20px; letter-spacing: 1px; }
body.mob .entry-head h1 span { display: block; font-size: 12px; letter-spacing: 2px; }
body.mob .disclaimer { font-size: 12px; margin: 6px 0 12px; }
/* 建房那几个字段本来就是短东西：手机端也并排摆，别一家一行堆成长龙 */
body.mob .card-form { padding: 14px 12px 16px; border-radius: 14px; }
body.mob .card-form h2 { font-size: 17px; margin-bottom: 12px; }
body.mob .row { gap: 8px; margin-bottom: 10px; }
/* 三个数字字段收成两列：标签最长的那一个自己占一行，省得三家里挤成两行标签 */
body.mob .row.three { grid-template-columns: repeat(2, minmax(0, 1fr)); }
body.mob .row.three > label:last-child { grid-column: 1 / -1; }
body.mob .row label { font-size: 12px; gap: 4px; }
body.mob input, body.mob select { padding: 8px 9px; font-size: 14px; }
body.mob .hint-line { font-size: 12px; margin: -2px 0 10px; }
body.mob .rules { padding: 12px 12px 14px; }
body.mob .rules ol { grid-template-columns: minmax(0, 1fr); gap: 0; }
body.mob .rules li:nth-child(2) { border-top-color: #24362e; }
body.mob .rules li { padding: 6px 0 6px 26px; line-height: 1.65; }
body.mob .room-bar { padding: 8px 10px; gap: 6px; }
body.mob .room-id { flex-wrap: wrap; }
body.mob .room-id b { font-size: 18px; letter-spacing: 2px; }
body.mob .room-meta { gap: 2px 10px; font-size: 12px; line-height: 1.5; }
body.mob .room-meta span { flex: 1 1 auto; min-width: 0; }
body.mob .table-area { grid-template-columns: 1fr; gap: 10px; }
body.mob .felt { padding: 10px; min-height: 0; border-radius: 16px; }
body.mob .center-pot { max-width: 100%; padding: 8px 10px; margin-bottom: 10px; }
body.mob .center-pot b { font-size: 22px; }
body.mob .bet-info, body.mob .turn-info { font-size: 12px; overflow-wrap: anywhere; }
/* 手机屏窄、牌也小：飞牌的两段距离按比例收短（桌面那几个像素写在 var() 的兜底值里），
   比牌掉出桌外那一下也跟着收，不然一张小卡片要往下飘老远 */
body.mob { --fly-x: 54px; --fly-y: -42px; --shot-x: -40px; --shot-y: 30px; --fall-y: 110px; }
/* 手机端没有排行右边那一格空位可用：牌山浮在牌毡右上角，只在发牌那几秒出现，一点高度都不占、也不吃点击。
   top 从 6 挪到 16：实测那一摞牌（22×28）压在「实时排行」条的上边框上、还高出 4 像素，挪进来就落在条子右边那截空处（字全靠左） */
body.mob .deck { position: absolute; top: 16px; right: 10px; z-index: 4; min-width: 0; }
body.mob .deck .pcard { width: 18px; height: 26px; border-radius: 3px; border-width: 1px; }
body.mob .deck-stack { height: 30px; }
body.mob .deck-stack > .pcard:nth-child(1) { transform: translate(-8px, -5px) rotate(-9deg); }
body.mob .deck-stack > .pcard:nth-child(2) { transform: translate(-4px, -3px) rotate(-5deg); }
/* 五选三五张不许挤在一排被 flex 压扁（十人桌实测压到 13 像素宽，看不清点不准）：
   一张就是一定的尺寸，装不下就让 .cards 那行 wrap 自己折成两排 */
body.mob .seat .cards .pcard { flex: 0 0 auto; }
/* 人多时整张座位卡按比例缩：几何用 --sc（跟着每排几张走），字号只轻缩用 --ts（保证还读得清）。
   档位写在 #seats 的 data-density 上（app.js 按座位数给），--sc:1 时算出来的就是原来那些像素，人少时一模一样。 */
body.mob .seats { --sc: 1; --ts: 1; grid-template-columns: repeat(auto-fill, minmax(calc(150px * var(--sc)), 1fr)); gap: calc(8px * var(--sc)); }
/* 5–7 人：每排 3 张；8–10 人：每排 4 张，十个人三排，基本不用往下翻 */
body.mob .seats[data-density="2"] { --sc: .74; --ts: .88; }
body.mob .seats[data-density="3"] { --sc: .55; --ts: .78; }
body.mob .seat { padding: calc(8px * var(--sc)) calc(9px * var(--sc)); border-radius: calc(12px * var(--sc)); font-size: calc(15px * var(--ts)); }
body.mob .seat-head { min-height: calc(34px * var(--sc)); gap: calc(6px * var(--sc)); }
/* 座位号小方块人多时只缩一点点：再缩就看不出是数字了 */
body.mob .seat-no { width: 16px; height: 16px; line-height: 14px; font-size: calc(11px * var(--ts)); }
body.mob .tags { min-height: calc(40px * var(--sc)); gap: calc(4px * var(--sc)); }
body.mob .tag { font-size: calc(11px * var(--ts)); padding: 1px calc(7px * var(--sc)); }
body.mob .bubble-slot { min-height: calc(74px * var(--sc)); }
body.mob .bubble { font-size: calc(12.5px * var(--ts)); padding: calc(6px * var(--sc)) calc(10px * var(--sc)); max-height: calc(86px * var(--sc)); }
body.mob .bubble.gift, body.mob .bubble.free { font-size: calc(11.5px * var(--ts)); }
body.mob .cards { gap: calc(4px * var(--sc)); flex-wrap: wrap; }
body.mob .pcard { width: calc(32px * var(--sc)); height: calc(46px * var(--sc)); }
/* 翻牌那段的外框跟着 --sc 一起缩，不然手机上三张牌会把卡片撑破 */
body.mob .seat .cards .pcard-flip { width: calc(32px * var(--sc)); height: calc(46px * var(--sc)); }
body.mob .pcard .r { font-size: calc(14px * var(--ts)); }
body.mob .pcard .s { font-size: calc(13px * var(--ts)); }
body.mob .hand-type { font-size: calc(12px * var(--ts)); min-height: calc(24px * var(--sc)); }
body.mob .seat-stats { font-size: calc(12.5px * var(--ts)); }
body.mob .hand-chips { font-size: calc(14px * var(--ts)); }
body.mob .seat-stats .paid b { font-size: calc(14.5px * var(--ts)); }
body.mob .seat-gift { margin-top: calc(7px * var(--sc)); min-height: calc(34px * var(--sc)); }
body.mob .seat-gift button { font-size: calc(12px * var(--ts)); }
body.mob .side { display: grid; grid-template-columns: 1fr; gap: 8px; }
body.mob .side .panel { margin-bottom: 0; }
body.mob .chat-list { max-height: 128px; }
body.mob .logs { max-height: none; }
body.mob #log-list { min-height: 96px; max-height: 150px; }
body.mob .action-bar { padding: 10px; gap: 8px; bottom: 6px; }
body.mob .action-bar button { min-height: 40px; font-size: 13px; padding: 6px 10px; }
body.mob .action-bar .sep { display: none; }
body.mob .action-bar .status { flex: 1 1 100%; min-width: 0; overflow-wrap: anywhere; }
body.mob .action-bar .group { flex: 1 1 auto; min-width: 0; }
body.mob .action-bar .custom-bet { flex: 1 1 100%; min-width: 0; }
body.mob .action-bar .custom-bet input { flex: 1 1 auto; width: auto; min-width: 0; }
body.mob .pick-bar { padding: 10px; gap: 8px; }
body.mob .pick-head { font-size: 12.5px; overflow-wrap: anywhere; }
body.mob .pick-cards { gap: 6px; }
body.mob .pick-bar button { min-height: 40px; }
body.mob .modal { padding: 8px; }
body.mob .modal-box { padding: 12px; max-height: 86vh; }
body.mob .settle-row { flex-wrap: wrap; gap: 6px; }
body.mob .settle-side { margin-left: 0; width: 100%; text-align: left; }
body.mob .round-row input { width: 72px; }
/* 榜单弹窗里的房主操作：按钮做大一点，别让人在结算页上找小开关 */
.modal-box .round-box button { cursor: pointer; font-size: 15px; padding: 11px 14px; }
.modal-box .seat-actions button { cursor: pointer; font-size: 14px; padding: 10px 12px; }
body.mob .line-grid { grid-template-columns: 1fr; }
body.mob .line-grid button { min-height: 40px; }

/* 底部固定栏：手机端的「轮到谁 / 谁在选牌 / 最新一条消息」＋五选三选牌面板＋操作条，
   全钉在屏幕下沿——人多时不用再划到最下面才找得到选牌面板 */
.dock-status { display: none; }
/* 我的手牌：桌面端不需要（座位卡就在眼前），手机端钉进底部固定栏 */
.my-hand { display: none; }
.dock-line { flex: 1 1 auto; min-width: 0; display: flex; gap: 8px; align-items: baseline; font-size: 13px; color: var(--muted); }
.dock-line b { color: var(--gold); white-space: nowrap; }
.dock-line.mine b { color: #ffe08a; text-shadow: 0 0 10px rgba(240, 195, 104, .45); }
.dock-msg { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text); opacity: .82; }
.dock-more { flex: none; cursor: pointer; }

body.mob .dock {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 44;
  display: flex; flex-direction: column; gap: 6px;
  padding: 6px 8px calc(8px + env(safe-area-inset-bottom));
  background: var(--dock); border-top: 1px solid var(--line);
}
body.mob .dock .pick-bar, body.mob .dock .action-bar { position: static; margin-top: 0; bottom: auto; max-height: 42vh; overflow-y: auto; }
body.mob .dock-status { display: flex; align-items: center; gap: 8px; }
/* 固定栏多高就留多高（app.js 量完写进 --dock-h）：写死 220px 的话十个人三排的操作栏能长到四五行，
   最底那排座位卡——也就是我自己的牌——就永远被压在栏底下 */
body.mob .table-area { padding-bottom: calc(var(--dock-h, 240px) + 18px); }
body.mob .my-hand {
  display: flex; align-items: center; gap: 8px; min-width: 0;
  padding: 4px 8px; border: 1px solid var(--line); border-radius: 10px;
  background: var(--panel-2);
}
body.mob .my-hand-label { flex: none; font-size: 12px; color: var(--muted); }
body.mob .my-hand-cards { display: flex; gap: 5px; flex: none; }
/* 这一行在固定栏里，不跟着座位卡按 --sc 缩：自己的牌再怎么也得看得清 */
body.mob .my-hand .pcard { width: 30px; height: 43px; border-radius: 5px; }
body.mob .my-hand-cards .pcard-flip { width: 30px; height: 43px; }
body.mob .my-hand .pcard .r { font-size: 13px; }
body.mob .my-hand .pcard .s { font-size: 12px; }
body.mob .my-hand-type { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12.5px; color: var(--gold); margin-left: auto; }
/* 侧栏收成抽屉：默认推出屏幕，点「消息 · 记录」才滑上来，底部留出固定栏的高度 */
body.mob .side {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 42;
  max-height: 66vh; overflow-y: auto; padding: 10px 10px calc(var(--dock-h, 240px) + 12px);
  background: var(--panel); border-top: 1px solid var(--gold); border-radius: 16px 16px 0 0;
  box-shadow: 0 -14px 30px rgba(0, 0, 0, .55);
  transform: translateY(105%); transition: transform .18s ease;
}
body.mob.drawer .side { transform: none; }

/* 本轮称号：名字后面并排戴，这一轮拿到几个就摆几个 */
.title-chip {
  display: inline-block; margin: 2px 0 0 6px; padding: 1px 7px;
  font-size: 11.5px; font-weight: 600; line-height: 1.6; white-space: nowrap;
  border: 1px solid currentColor; border-radius: 999px;
}
.title-chip.k-gold { color: #ffd36b; background: rgba(240, 195, 104, .14); }
.title-chip.k-red { color: #ff8f7a; background: rgba(224, 86, 63, .16); }
.title-chip.k-green { color: #7fd6a1; background: rgba(75, 180, 122, .16); }
.title-chip.k-blue { color: #8fc7ff; background: rgba(70, 130, 190, .18); }
.title-chip.k-purple { color: #d4a8ff; background: rgba(150, 90, 200, .18); }
.rank-table .title-chip { margin-left: 4px; }

/* 一轮战报：默认只给一个复制按钮，浏览器拒绝写剪贴板时才把纯文本亮出来长按选中 */
/* 本轮对账：一行一笔「谁 给 谁 多少」，走正常流排在榜单下面，不新建浮层、不挡任何东西 */
.settle-head { margin: 10px 0 4px; color: var(--gold); }
.settle-plan { margin: 0; padding: 0; list-style: none; font-size: 13px; }
.settle-plan li { display: flex; align-items: baseline; gap: 6px; padding: 3px 0; border-bottom: 1px dashed var(--line); }
.settle-plan li b { font-weight: 700; overflow-wrap: anywhere; }
.settle-plan li span { color: var(--muted); }
.settle-plan li em { margin-left: auto; font-style: normal; font-weight: 700; color: var(--gold); font-variant-numeric: tabular-nums; }
.report-btn { font-size: 13px; padding: 6px 12px; }
.report-text {
  display: none; margin: 8px 0 0; padding: 8px 10px; white-space: pre-wrap; word-break: break-all;
  font: 12px/1.7 ui-monospace, Menlo, Consolas, monospace;
  color: var(--text); background: var(--panel-2); border: 1px solid var(--line); border-radius: 8px;
}

/* 名场面在牌局记录里单独上色并加一条左竖线：翻记录时不用逐行读字 */
#log-list div[class^="mk-"] { padding-left: 8px; border-left: 3px solid currentColor; font-weight: 600; }
#log-list div.mk-xiqian { color: #ffd36b; }
#log-list div.mk-win { color: #f0c368; }
#log-list div.mk-hot235 { color: #ff6b6b; }
#log-list div.mk-duel { color: #ff9d6b; }
#log-list div.mk-cap { color: #ffb84d; }
#log-list div.mk-round { color: #8ea9c9; }

/* 桌布皮肤：五套压暗的呢面，只换颜色，不动任何布局 */
body.skin-felt {
  --bg: #0d1411; --page-hi: #17251f;
  --felt: #16563c; --felt-dark: #0f3d2a; --felt-hi: #1c6b49; --felt-edge: #0a2c1e;
  --panel: #16211c; --panel-2: #1d2b24; --line: #2b3d34;
  --slot: rgba(8, 26, 18, .62); --slot-me: rgba(16, 44, 30, .8);
  --dock: rgba(13, 20, 17, .97);
}
body.skin-ink {
  --bg: #0b1017; --page-hi: #141d29;
  --felt: #1d3b57; --felt-dark: #132738; --felt-hi: #24486a; --felt-edge: #0b1a28;
  --panel: #131c26; --panel-2: #1a2632; --line: #26394d;
  --slot: rgba(10, 22, 34, .62); --slot-me: rgba(18, 36, 54, .8);
  --dock: rgba(11, 16, 23, .97);
}
body.skin-wood {
  --bg: #120e0a; --page-hi: #1e1812;
  --felt: #4a3323; --felt-dark: #2e1f15; --felt-hi: #5b402b; --felt-edge: #1a110a;
  --panel: #1b1510; --panel-2: #241c15; --line: #3a2e22;
  --slot: rgba(26, 19, 13, .62); --slot-me: rgba(42, 31, 21, .8);
  --dock: rgba(18, 14, 10, .97);
}
body.skin-slate {
  --bg: #0e1012; --page-hi: #191c20;
  --felt: #3a424a; --felt-dark: #262c32; --felt-hi: #464f58; --felt-edge: #171b1f;
  --panel: #16181b; --panel-2: #1e2126; --line: #30353b;
  --slot: rgba(18, 21, 25, .62); --slot-me: rgba(32, 37, 43, .8);
  --dock: rgba(14, 16, 18, .97);
}
body.skin-plum {
  --bg: #100c14; --page-hi: #1a1422;
  --felt: #432c52; --felt-dark: #2b1c36; --felt-hi: #523765; --felt-edge: #1c1124;
  --panel: #181320; --panel-2: #201a2a; --line: #33293e;
  --slot: rgba(22, 16, 28, .62); --slot-me: rgba(36, 26, 46, .8);
  --dock: rgba(16, 12, 20, .97);
}

/* 电脑端：座位少的时候别在桌面上留一大片空白。卡片摊开居中，牌毡不再硬撑 420 高 */
@media (min-width: 981px) {
  body:not(.mob) .felt { min-height: 0; }
  body:not(.mob) .seats { grid-auto-rows: max-content; }
}

/* 电脑端且屏幕够高：整张桌一屏装下，页面本身不滚。
   牌毡、房间信息、消息、牌局记录各自在自己的框里滚，底部操作条始终看得见。
   手动切到手机端布局（body.mob）时这些一概不生效。 */
@media (min-width: 981px) and (min-height: 620px) {
  body:not(.mob) #screen-room {
    display: flex; flex-direction: column; height: 100vh; padding: 12px 20px 14px; overflow: hidden;
  }
  body:not(.mob) #screen-room .room-bar { flex: 0 0 auto; margin-bottom: 12px; }
  body:not(.mob) #screen-room .table-area { flex: 1 1 auto; min-height: 0; align-items: stretch; }
  body:not(.mob) #screen-room .felt { display: flex; flex-direction: column; min-height: 0; overflow-y: auto; }
  body:not(.mob) #screen-room .felt-top { flex: 0 0 auto; }
  body:not(.mob) #screen-room .seats { flex: 1 1 auto; align-content: center; }
  body:not(.mob) #screen-room .side { display: flex; flex-direction: column; min-height: 0; }
  body:not(.mob) #screen-room #phase-panel { flex: 0 1 auto; min-height: 0; overflow-y: auto; }
  body:not(.mob) #screen-room .side .chat { flex: 0 0 auto; }
  body:not(.mob) #screen-room .side .logs { flex: 1 1 auto; min-height: 0; max-height: none; }
  body:not(.mob) #screen-room #log-list { flex: 1 1 auto; min-height: 60px; max-height: none; }
  body:not(.mob) #screen-room .dock { flex: 0 0 auto; }
  body:not(.mob) #screen-room .action-bar { position: static; margin-top: 12px; }
  body:not(.mob) #screen-room .pick-bar { max-height: 38vh; overflow-y: auto; }
}
