:root{--night:#102d3b;--water:#2b7f96;--water-light:#58adbd;--water-deep:#1f657d;--bank:#c9a86e;--bank-dark:#9f7a45;--panel:rgba(249,245,231,.94);--ink:#263136;--muted:#69767a;--north:#306b84;--south:#b2533f;--north-dark:#214c60;--south-dark:#7f352b;--wood:#a97742;--wood-dark:#6d472a;--legal:#70ddb0;--capture:#ff766d;--cannon:#ffd166;--shadow:0 18px 60px rgba(5,27,37,.2)}
*{box-sizing:border-box}html,body{min-height:100%}body{margin:0;color:var(--ink);font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Microsoft YaHei",sans-serif;background:radial-gradient(circle at 16% 0%,rgba(95,174,192,.24),transparent 31%),linear-gradient(160deg,var(--night),#0c2632 72%)}button,input{font:inherit}button{-webkit-tap-highlight-color:transparent}.hidden{display:none!important}
.app-shell{width:min(1380px,96vw);margin:0 auto;padding:15px 0 30px}.topbar{min-height:58px;display:flex;align-items:center;justify-content:space-between;gap:14px;margin-bottom:12px;color:#fff8e7}.eyebrow{font-size:10px;font-weight:900;letter-spacing:.24em;opacity:.62}h1{margin:2px 0 0;font-family:"STKaiti","KaiTi","FangSong",serif;font-size:clamp(28px,3vw,42px);line-height:1}h1 span{margin-left:5px;font-family:system-ui,sans-serif;font-size:.34em;vertical-align:.66em;opacity:.55}.brand-sub{margin-top:4px;font-size:11px;letter-spacing:.15em;opacity:.55}.connection-badge{flex:none;padding:7px 10px;border-radius:999px;border:1px solid rgba(255,255,255,.14);font-size:11px;font-weight:800}.connection-badge.online{background:rgba(62,157,117,.24);color:#baf0d5}.connection-badge.offline{background:rgba(186,74,68,.22);color:#ffc0ba}
.lobby-card,.panel{border:1px solid rgba(255,255,255,.12);border-radius:19px;box-shadow:var(--shadow);backdrop-filter:blur(14px)}.lobby-card{display:grid;grid-template-columns:1.15fr 1fr;gap:16px;padding:17px;margin-bottom:14px;background:rgba(247,240,220,.94)}.lobby-copy h2{margin:4px 0 6px;font-size:22px}.lobby-copy p{margin:0;color:var(--muted);font-size:13px;line-height:1.6}.lobby-actions{display:flex;flex-direction:column;justify-content:center;gap:9px}.join-row{display:grid;grid-template-columns:1fr auto;gap:8px}.join-row input{min-width:0;border:1px solid rgba(38,49,54,.16);border-radius:11px;padding:10px 12px;background:#fffaf0;outline:none}.join-row input:focus{border-color:var(--north);box-shadow:0 0 0 3px rgba(48,107,132,.12)}.primary-btn,.secondary-btn,.cannon-btn{border:0;cursor:pointer;border-radius:11px;font-weight:800;transition:.14s ease}.primary-btn:hover,.secondary-btn:hover,.cannon-btn:hover{transform:translateY(-1px)}.primary-btn:disabled,.secondary-btn:disabled,.cannon-btn:disabled{cursor:not-allowed;opacity:.4;transform:none}.primary-btn{padding:10px 13px;background:var(--night);color:white}.secondary-btn{padding:9px 12px;background:#e7ddc4;color:var(--ink)}.room-card{grid-column:1/-1;display:grid;grid-template-columns:repeat(3,1fr);gap:7px}.room-card>div{padding:9px 11px;border-radius:11px;background:rgba(255,250,240,.8);border:1px solid rgba(38,49,54,.08)}.room-card span{display:block;color:var(--muted);font-size:10px}.room-card strong{display:block;margin-top:3px;font-size:14px}#roomCode{letter-spacing:.18em;font-size:18px}
.game-layout{display:grid;grid-template-columns:minmax(430px,1fr) minmax(220px,278px) minmax(250px,310px);gap:14px;align-items:start}.panel{padding:14px;background:var(--panel)}.board-stage{display:flex;flex-direction:column;align-items:center;min-width:0}.battle-label{color:rgba(255,248,231,.55);font-family:"STKaiti","KaiTi",serif;font-size:11px;letter-spacing:.35em;line-height:1}.north-label{margin-bottom:5px}.south-label{margin-top:5px}
.board{position:relative;width:min(72vh,100%);aspect-ratio:8/9;overflow:hidden;border:2px solid rgba(255,255,255,.18);border-radius:18px;background:linear-gradient(to bottom,var(--bank-dark) 0%,var(--bank) 8%,var(--water-light) 10%,var(--water) 18%,var(--water-deep) 50%,var(--water) 82%,var(--water-light) 90%,var(--bank) 92%,var(--bank-dark) 100%);box-shadow:0 24px 70px rgba(0,0,0,.28),inset 0 0 45px rgba(4,48,64,.24);touch-action:manipulation}.river-texture{position:absolute;inset:10% 0;overflow:hidden;pointer-events:none}.river-texture i{position:absolute;display:block;width:42%;height:1px;border-radius:99px;background:linear-gradient(90deg,transparent,rgba(216,248,247,.34),transparent);animation:drift 8s linear infinite}.river-texture i:nth-child(1){top:12%;left:6%}.river-texture i:nth-child(2){top:29%;left:52%;width:33%;animation-delay:-2s}.river-texture i:nth-child(3){top:49%;left:13%;width:29%;animation-delay:-4s}.river-texture i:nth-child(4){top:68%;left:47%;width:44%;animation-delay:-6s}.river-texture i:nth-child(5){top:84%;left:5%;width:38%;animation-delay:-1s}@keyframes drift{0%{transform:translateX(-10px);opacity:.25}50%{opacity:.75}100%{transform:translateX(22px);opacity:.25}}
.grid-lines,.points-layer{position:absolute;inset:7.5%}.grid-lines{opacity:.13}.grid-line{position:absolute;background:rgba(239,253,250,.8);border-radius:99px}.grid-line.horizontal{left:0;width:100%;height:1px;transform:translateY(-50%)}.grid-line.vertical{top:0;width:1px;height:100%;transform:translateX(-50%)}
.point{position:absolute;width:clamp(32px,5.1vw,48px);height:clamp(32px,5.1vw,48px);border:0;border-radius:50%;padding:0;background:transparent;transform:translate(-50%,-50%);cursor:pointer;z-index:4;overflow:visible}.point:disabled{cursor:default}.target-ring{position:absolute;left:50%;top:50%;width:11px;height:11px;transform:translate(-50%,-50%);border-radius:50%;background:rgba(232,251,249,.22);box-shadow:0 0 0 1px rgba(233,255,252,.15)}.point.start .target-ring{opacity:0}.point.legal-empty .target-ring,.point.legal-capture .target-ring,.point.legal-cannon .target-ring{width:70%;height:70%;background:rgba(255,255,255,.07);animation:target-pulse 1.15s ease-in-out infinite alternate}.point.legal-empty .target-ring{border:2px solid var(--legal);box-shadow:0 0 12px rgba(112,221,176,.8)}.point.legal-capture .target-ring{border:2px solid var(--capture);box-shadow:0 0 13px rgba(255,118,109,.84)}.point.legal-cannon .target-ring{width:80%;height:80%;border:2px solid var(--cannon);box-shadow:0 0 17px rgba(255,209,102,.96)}@keyframes target-pulse{from{transform:translate(-50%,-50%) scale(.9);opacity:.65}to{transform:translate(-50%,-50%) scale(1.07);opacity:1}}
.bridge{position:absolute;left:50%;top:50%;width:78%;height:50%;opacity:0;transform:translate(-50%,-50%) rotate(-1deg) scale(.72);border:1px solid rgba(73,45,24,.55);border-radius:4px;background:var(--wood);box-shadow:0 4px 6px rgba(21,52,59,.24);transition:.18s ease}.bridge:before,.bridge:after{content:"";position:absolute;left:3%;width:94%;height:4px;border-radius:99px;background:var(--wood-dark)}.bridge:before{top:3px}.bridge:after{bottom:3px}.bridge i{position:absolute;top:2px;bottom:2px;width:1px;background:rgba(84,48,24,.36)}.bridge i:nth-child(1){left:25%}.bridge i:nth-child(2){left:50%}.bridge i:nth-child(3){left:75%}.point.piece .bridge{opacity:1;transform:translate(-50%,-50%) rotate(-1deg) scale(1)}
.engineer{position:absolute;left:50%;top:48%;width:24px;height:29px;opacity:0;transform:translate(-50%,-55%) scale(.62);z-index:4;filter:drop-shadow(0 2px 2px rgba(0,0,0,.28));transition:.18s ease;--uniform:var(--north);--uniform-dark:var(--north-dark)}.point.piece .engineer{opacity:1;transform:translate(-50%,-55%) scale(1)}.point.piece-1 .engineer{--uniform:var(--south);--uniform-dark:var(--south-dark)}.engineer .head{position:absolute;left:9px;top:5px;width:8px;height:8px;border-radius:50%;background:#d9ad7c;border:1px solid rgba(61,41,27,.28)}.engineer .helmet{position:absolute;left:7px;top:2px;width:12px;height:6px;z-index:2;border-radius:9px 9px 3px 3px;background:var(--uniform-dark)}.engineer .body{position:absolute;left:6px;top:12px;width:14px;height:14px;border-radius:4px 4px 6px 6px;background:var(--uniform);border:1px solid rgba(0,0,0,.18)}.engineer .body:before,.engineer .body:after{content:"";position:absolute;top:11px;width:5px;height:10px;border-radius:3px;background:var(--uniform-dark)}.engineer .body:before{left:1px}.engineer .body:after{right:1px}.engineer .arm{position:absolute;top:13px;width:5px;height:13px;border-radius:4px;background:var(--uniform);transform-origin:top center}.engineer .arm-left{left:3px;transform:rotate(23deg)}.engineer .arm-right{right:3px;transform:rotate(-23deg)}
.camp{position:absolute;left:50%;top:50%;width:56px;height:40px;transform:translate(-50%,-50%);z-index:1;pointer-events:none;--camp-color:var(--north);--camp-dark:var(--north-dark)}.camp-1{--camp-color:var(--south);--camp-dark:var(--south-dark)}.camp .tent{position:absolute;left:7px;bottom:3px;width:33px;height:22px;clip-path:polygon(50% 0,100% 100%,0 100%);background:linear-gradient(90deg,var(--camp-dark),var(--camp-color));filter:drop-shadow(0 3px 3px rgba(0,0,0,.22))}.camp .flag-pole{position:absolute;left:42px;top:3px;width:2px;height:31px;background:#4f3c29}.camp .flag{position:absolute;left:44px;top:4px;width:11px;height:8px;background:var(--camp-color);clip-path:polygon(0 0,100% 16%,75% 100%,0 82%)}.camp .shore-gun{position:absolute;left:0;bottom:2px;width:16px;height:7px;border-radius:5px;background:#4c514b;transform:rotate(-12deg)}.start-1 .camp .shore-gun{transform:rotate(12deg)}.point.start.piece .camp{opacity:.44}
.fx{position:absolute;left:50%;top:50%;width:8px;height:8px;transform:translate(-50%,-50%);border-radius:50%;pointer-events:none;z-index:8;opacity:0}.point.build-anim .bridge{animation:bridge-build .44s cubic-bezier(.2,.85,.25,1.2)}@keyframes bridge-build{0%{opacity:0;transform:translate(-50%,-50%) scale(.2) rotate(-8deg)}70%{opacity:1;transform:translate(-50%,-50%) scale(1.12) rotate(2deg)}100%{opacity:1;transform:translate(-50%,-50%) scale(1) rotate(-1deg)}}.point.capture-anim .engineer{animation:engineer-rush .68s cubic-bezier(.18,.78,.27,1.14)}.point.capture-anim .fx{opacity:1;background:#e6fbff;animation:splash .68s ease-out}@keyframes engineer-rush{0%{opacity:.2;transform:translate(-130%,-55%) scale(.7) rotate(-14deg)}48%{opacity:1;transform:translate(-28%,-56%) scale(1.12) rotate(9deg)}100%{opacity:1;transform:translate(-50%,-55%) scale(1)}}@keyframes splash{0%{box-shadow:0 0 0 0 rgba(229,251,255,.95)}60%{box-shadow:-12px -6px 0 -3px #e5fbff,12px -7px 0 -3px #e5fbff,0 -15px 0 -4px #e5fbff}100%{opacity:0;transform:translate(-50%,-130%) scale(1.3)}}.point.cannon-anim .fx{opacity:1;background:#ffd166;animation:cannon-hit .74s ease-out}@keyframes cannon-hit{0%{transform:translate(-50%,-50%) scale(.2);box-shadow:0 0 0 0 rgba(255,209,102,.95)}35%{transform:translate(-50%,-50%) scale(1.5);box-shadow:0 0 0 14px rgba(255,209,102,.24),0 0 22px 10px rgba(255,105,67,.6)}100%{opacity:0;transform:translate(-50%,-50%) scale(2.2);box-shadow:0 0 0 28px rgba(255,209,102,0)}}
.board-message{min-height:20px;margin-top:7px;color:rgba(255,248,231,.72);font-size:12px;text-align:center}.turn-card,.skill-card,.legend-card,.log-card{background:rgba(255,250,240,.74);border:1px solid rgba(38,49,54,.08);border-radius:13px;padding:12px}.turn-label,.skill-desc,.turn-hint,.metric span,.legend-row,.move-log,details li{color:var(--muted)}.turn-label{font-size:10px;font-weight:800}.player-line{display:flex;align-items:center;gap:8px;margin-top:6px;font-size:17px}.player-dot{width:13px;height:13px;border-radius:50%;display:inline-block;border:2px solid rgba(0,0,0,.12)}.player-dot.player-0{background:var(--north)}.player-dot.player-1{background:var(--south)}.turn-hint{margin-top:8px;font-size:12px;line-height:1.5}.metric-grid{display:grid;grid-template-columns:1fr 1fr;gap:7px;margin:8px 0}.metric{padding:8px 9px;border:1px solid rgba(38,49,54,.08);border-radius:10px;background:rgba(255,255,255,.48)}.metric span{display:block;font-size:10px}.metric strong{display:block;margin-top:2px;font-size:13px}.skill-card{margin-top:8px}.skill-head{display:flex;justify-content:space-between;gap:10px;align-items:start}.skill-title{font-weight:900}.skill-desc{margin-top:2px;font-size:10px}.badge{flex:none;padding:3px 7px;border-radius:999px;background:#f1dda6;color:#755916;font-size:10px;font-weight:900}.badge.used{background:#ddd8ca;color:#777}.cannon-btn{width:100%;margin-top:9px;padding:9px 10px;display:flex;align-items:center;justify-content:center;gap:7px;color:#5e4612;background:linear-gradient(180deg,#ffe399,#ebc15d)}.cannon-btn.active{color:#fff8da;background:#8c6923}.skill-card .secondary-btn{width:100%;margin-top:7px}.legend-card{margin-top:8px}.legend-title,.log-title{margin-bottom:7px;font-size:11px;font-weight:900}.legend-row{display:flex;align-items:center;gap:7px;margin:5px 0;font-size:11px}.legend-dot{width:10px;height:10px;border:2px solid;border-radius:50%}.legend-dot.empty{border-color:#3bbf85}.legend-dot.capture{border-color:#e3524c}.legend-dot.cannon{border-color:#c99826}details summary{cursor:pointer;font-weight:900;font-size:13px}details ol{padding-left:20px;margin-bottom:0}details li{margin:6px 0;font-size:11px;line-height:1.45}.log-card{margin-top:9px}.move-log{max-height:300px;overflow:auto;font-size:11px;line-height:1.5}.log-item{padding:4px 0;border-bottom:1px solid rgba(38,49,54,.06)}
.modal{position:fixed;inset:0;display:grid;place-items:center;padding:18px;z-index:30;background:rgba(5,20,27,.62);backdrop-filter:blur(5px)}.modal-card{width:min(390px,100%);padding:23px;border-radius:19px;background:#fff8e8;box-shadow:0 26px 90px rgba(0,0,0,.36)}.modal-card h2{margin:5px 0 8px;font-family:"STKaiti","KaiTi",serif;font-size:30px}.modal-card p{color:var(--muted);line-height:1.6}.modal-card .primary-btn{width:100%;margin-top:7px}
@media(max-width:1050px){.game-layout{grid-template-columns:minmax(400px,1.4fr) minmax(220px,1fr)}.rules-panel{grid-column:1/-1}}
@media(max-width:720px){body.game-active{height:100dvh;overflow:hidden}.app-shell{width:min(100% - 12px,680px);padding:6px 0 10px}.topbar{min-height:44px;margin-bottom:5px}h1{font-size:27px}.brand-sub,.topbar .eyebrow{display:none}.connection-badge{padding:5px 8px;font-size:9px}.lobby-card{grid-template-columns:1fr;padding:12px;margin-bottom:8px}.room-card{grid-template-columns:1fr 1fr}.room-card>div:first-child{grid-column:1/-1}body.game-active .lobby-card{padding:5px 7px;border-radius:10px;margin-bottom:5px;box-shadow:none}body.game-active .lobby-copy,body.game-active .lobby-actions{display:none}body.game-active .room-card{grid-template-columns:.9fr 1.2fr 1fr;gap:4px}body.game-active .room-card>div,body.game-active .room-card>div:first-child{grid-column:auto;padding:4px 6px;border-radius:7px}body.game-active .room-card span{font-size:8px}body.game-active .room-card strong{margin-top:0;font-size:10px}body.game-active #roomCode{font-size:12px}.game-layout{display:flex;flex-direction:column;gap:5px}.board-stage{order:1;width:100%}.status-panel{order:2;width:100%}.rules-panel{order:3;width:100%}body.game-active .rules-panel{display:none}.board{width:min(92vw,calc(58dvh * 8 / 9),520px)}.battle-label{font-size:9px}.north-label{margin-bottom:3px}.south-label{margin-top:3px}.board-message{min-height:16px;margin-top:3px;font-size:10px}.point{width:clamp(30px,9vw,43px);height:clamp(30px,9vw,43px)}.camp{transform:translate(-50%,-50%) scale(.78)}.panel{padding:7px;border-radius:12px}.turn-card{padding:7px 9px}.turn-label{display:none}.player-line{margin-top:0;font-size:13px}.turn-hint{margin-top:3px;font-size:10px;line-height:1.35}.metric-grid{grid-template-columns:repeat(4,1fr);gap:4px;margin:5px 0}.metric{padding:5px 3px;text-align:center}.metric span{font-size:8px}.metric strong{margin-top:0;font-size:10px}.skill-card{display:grid;grid-template-columns:1fr 1fr;gap:5px;padding:6px;margin-top:0}.skill-head{align-items:center}.skill-title{font-size:11px}.skill-desc{display:none}.badge{font-size:8px}.cannon-btn,.skill-card .secondary-btn{margin-top:0;min-height:34px;font-size:10px}.skill-card .secondary-btn{grid-column:1/-1}.legend-card{display:none}}
@media(max-width:390px){.board{width:min(95vw,calc(56dvh * 8 / 9))}.camp{transform:translate(-50%,-50%) scale(.7)}}
@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}}


/* ===== V0.4 动画与战场精修 ===== */
.grid-lines{opacity:.075}
.board{isolation:isolate}
.board::marker{display:none}
.board.turn-player-0{box-shadow:0 24px 70px rgba(0,0,0,.28),inset 0 23px 30px rgba(89,176,211,.13),inset 0 0 45px rgba(4,48,64,.24)}
.board.turn-player-1{box-shadow:0 24px 70px rgba(0,0,0,.28),inset 0 -23px 30px rgba(220,100,78,.13),inset 0 0 45px rgba(4,48,64,.24)}
.board.my-turn{outline:1px solid rgba(255,246,213,.14);outline-offset:2px}
.board.cannon-mode{filter:saturate(.92) contrast(1.03)}
.board.cannon-mode .river-texture{opacity:.5}

.room-code-line{display:flex;align-items:center;gap:7px;margin-top:2px}
.copy-room-btn{border:0;border-radius:7px;padding:3px 7px;background:#e7ddc4;color:#4e4a3f;font-size:9px;font-weight:800;cursor:pointer}
.copy-room-btn:active{transform:translateY(1px)}

.camp b{position:absolute;left:50%;bottom:-7px;transform:translateX(-50%);white-space:nowrap;padding:1px 4px;border-radius:5px;background:rgba(255,248,231,.8);color:#3f3b31;font:800 7px/1.2 ui-sans-serif,system-ui,sans-serif;letter-spacing:.08em;box-shadow:0 1px 3px rgba(0,0,0,.12)}

/* 被夺桥/被炮击时保留一个“旧工程兵”幽灵，用于踢落水动画。 */
.defeated-engineer{position:absolute;left:50%;top:48%;width:24px;height:29px;opacity:0;transform:translate(-50%,-55%) scale(1);z-index:7;pointer-events:none;filter:drop-shadow(0 2px 2px rgba(0,0,0,.25));--uniform:var(--north);--uniform-dark:var(--north-dark)}
.point.victim-0 .defeated-engineer{--uniform:var(--north);--uniform-dark:var(--north-dark)}
.point.victim-1 .defeated-engineer{--uniform:var(--south);--uniform-dark:var(--south-dark)}
.defeated-engineer .head{position:absolute;left:9px;top:5px;width:8px;height:8px;border-radius:50%;background:#d9ad7c;border:1px solid rgba(61,41,27,.28)}
.defeated-engineer .helmet{position:absolute;left:7px;top:2px;width:12px;height:6px;z-index:2;border-radius:9px 9px 3px 3px;background:var(--uniform-dark)}
.defeated-engineer .body{position:absolute;left:6px;top:12px;width:14px;height:14px;border-radius:4px 4px 6px 6px;background:var(--uniform);border:1px solid rgba(0,0,0,.18)}
.defeated-engineer .body::before,.defeated-engineer .body::after{content:"";position:absolute;top:11px;width:5px;height:10px;border-radius:3px;background:var(--uniform-dark)}
.defeated-engineer .body::before{left:1px;transform:rotate(5deg)}
.defeated-engineer .body::after{right:1px;transform:rotate(-5deg)}
.defeated-engineer .arm{position:absolute;top:13px;width:5px;height:13px;border-radius:4px;background:var(--uniform);transform-origin:top center}
.defeated-engineer .arm-left{left:3px;transform:rotate(23deg)}
.defeated-engineer .arm-right{right:3px;transform:rotate(-23deg)}

.destroyed-bridge{position:absolute;left:50%;top:50%;width:78%;height:50%;opacity:0;transform:translate(-50%,-50%) rotate(-1deg);z-index:6;pointer-events:none;border:1px solid rgba(73,45,24,.55);border-radius:4px;background:var(--wood);box-shadow:0 4px 6px rgba(21,52,59,.24)}
.destroyed-bridge::before,.destroyed-bridge::after{content:"";position:absolute;left:3%;width:94%;height:4px;border-radius:99px;background:var(--wood-dark)}
.destroyed-bridge::before{top:3px}.destroyed-bridge::after{bottom:3px}
.destroyed-bridge i{position:absolute;top:2px;bottom:2px;width:1px;background:rgba(84,48,24,.36)}
.destroyed-bridge i:nth-child(1){left:25%}.destroyed-bridge i:nth-child(2){left:50%}.destroyed-bridge i:nth-child(3){left:75%}

.point.capture-anim .defeated-engineer{opacity:1;animation:kicked-overboard .82s cubic-bezier(.25,.55,.28,1) forwards}
.point.capture-anim .engineer{animation:engineer-charge .82s cubic-bezier(.17,.82,.26,1.08)}
.point.capture-anim .bridge{animation:bridge-jolt .45s ease-out}
.point.capture-anim .fx{opacity:1;background:#e6fbff;animation:water-plop .86s ease-out}

@keyframes engineer-charge{
  0%{opacity:.05;transform:translate(-150%,-55%) scale(.65) rotate(-12deg)}
  42%{opacity:1;transform:translate(-35%,-58%) scale(1.13) rotate(10deg)}
  58%{transform:translate(-45%,-55%) scale(1.04) rotate(-5deg)}
  100%{opacity:1;transform:translate(-50%,-55%) scale(1)}
}
@keyframes kicked-overboard{
  0%{opacity:1;transform:translate(-50%,-55%) scale(1) rotate(0)}
  25%{opacity:1;transform:translate(calc(-50% + var(--kick-x)*.25),-70%) scale(1.02) rotate(26deg)}
  65%{opacity:.95;transform:translate(calc(-50% + var(--kick-x)*.8),28%) scale(.88) rotate(88deg)}
  100%{opacity:0;transform:translate(calc(-50% + var(--kick-x)),105%) scale(.55) rotate(145deg)}
}
@keyframes bridge-jolt{0%{transform:translate(-50%,-50%) rotate(-1deg)}35%{transform:translate(-50%,-50%) rotate(4deg) scale(1.05)}70%{transform:translate(-50%,-50%) rotate(-4deg) scale(.99)}100%{transform:translate(-50%,-50%) rotate(-1deg) scale(1)}}
@keyframes water-plop{
  0%,48%{opacity:0;transform:translate(calc(-50% + var(--kick-x)*.8),25%) scale(.15);box-shadow:0 0 0 0 rgba(229,251,255,.95)}
  62%{opacity:1;box-shadow:-11px -5px 0 -3px rgba(229,251,255,.88),11px -6px 0 -3px rgba(229,251,255,.88),0 -14px 0 -4px rgba(229,251,255,.78)}
  100%{opacity:0;transform:translate(calc(-50% + var(--kick-x)),80%) scale(1.55);box-shadow:-16px -10px 0 -5px rgba(229,251,255,0),16px -10px 0 -5px rgba(229,251,255,0),0 -20px 0 -6px rgba(229,251,255,0)}
}

/* 岸炮命中：旧桥先显形，再炸成碎片；工程兵一同被震落。 */
.point.cannon-anim .destroyed-bridge{opacity:1;animation:bridge-blast .9s cubic-bezier(.22,.69,.25,1) forwards}
.point.cannon-anim .defeated-engineer{opacity:1;animation:cannon-victim .9s ease-out forwards}
.point.cannon-anim .fx{opacity:1;background:#ffd166;animation:cannon-impact-v04 .92s ease-out}
@keyframes bridge-blast{
  0%{opacity:1;transform:translate(-50%,-50%) rotate(-1deg) scale(1)}
  22%{opacity:1;transform:translate(-50%,-50%) rotate(3deg) scale(1.12);filter:brightness(1.35)}
  52%{opacity:.85;transform:translate(-50%,-45%) rotate(-13deg) scale(.92)}
  100%{opacity:0;transform:translate(-50%,35%) rotate(28deg) scale(.48)}
}
@keyframes cannon-victim{
  0%{opacity:1;transform:translate(-50%,-55%) scale(1)}
  28%{opacity:1;transform:translate(calc(-50% + var(--kick-x)*.2),-105%) scale(1.08) rotate(24deg)}
  100%{opacity:0;transform:translate(calc(-50% + var(--kick-x)*1.1),70%) scale(.45) rotate(190deg)}
}
@keyframes cannon-impact-v04{
  0%{opacity:1;transform:translate(-50%,-50%) scale(.15);box-shadow:0 0 0 0 rgba(255,225,124,.98)}
  20%{opacity:1;transform:translate(-50%,-50%) scale(1.5);box-shadow:0 0 0 12px rgba(255,209,102,.3),0 0 28px 12px rgba(255,104,59,.75)}
  48%{opacity:.85;box-shadow:-17px -15px 0 -4px rgba(255,220,126,.72),17px -12px 0 -5px rgba(255,170,84,.65),0 -25px 0 -6px rgba(255,231,162,.75)}
  100%{opacity:0;transform:translate(-50%,-50%) scale(2.7);box-shadow:0 0 0 34px rgba(255,209,102,0)}
}

.point.legal-empty:active .target-ring,.point.legal-capture:active .target-ring,.point.legal-cannon:active .target-ring{transform:translate(-50%,-50%) scale(.78)}

@media(max-width:720px){
  .copy-room-btn{padding:2px 5px;font-size:8px}
  .camp b{font-size:6px;bottom:-5px}
}

/* ===== V0.5 沉浸式游戏界面 ===== */
.board-stage{position:relative;padding-top:48px}
.board{overflow:visible}
.board::after{border-radius:0 0 16px 16px}
.board::before{border-radius:16px 16px 0 0}

/* 直接覆盖在战场上的双方状态条 */
.battle-hud{
  position:absolute;
  inset:-42px 9px auto;
  z-index:14;
  display:grid;
  grid-template-columns:1fr auto 1fr;
  align-items:start;
  gap:7px;
  pointer-events:none;
}
.camp-pill{
  min-width:0;
  padding:5px 7px;
  border:1px solid rgba(255,255,255,.19);
  border-radius:10px;
  background:rgba(7,31,41,.54);
  color:#f7f0dc;
  box-shadow:0 4px 14px rgba(0,0,0,.16);
  backdrop-filter:blur(7px);
  transition:.2s ease;
}
.camp-pill-1{text-align:right}
.camp-pill b{display:block;font-size:10px;line-height:1.1;letter-spacing:.08em}
.camp-pill small{display:block;margin-top:2px;font-size:7px;line-height:1.1;opacity:.64}
.camp-pill.active-turn{border-color:rgba(255,239,190,.62);box-shadow:0 0 0 1px rgba(255,239,190,.11),0 5px 18px rgba(0,0,0,.18)}
.camp-pill.my-camp b::after{content:" · 我方";opacity:.62;font-size:.78em}
.camp-pill.cannon-spent small{text-decoration:line-through;opacity:.42}
.mini-flag{display:inline-block;width:6px;height:6px;margin-right:4px;border-radius:2px;background:var(--north);vertical-align:1px}
.camp-pill-1 .mini-flag{background:var(--south);margin-right:0;margin-left:4px;float:right}

.turn-banner{
  align-self:start;
  min-width:80px;
  padding:6px 10px;
  border-radius:999px;
  color:#fff8e8;
  background:rgba(10,36,46,.72);
  border:1px solid rgba(255,255,255,.18);
  box-shadow:0 5px 18px rgba(0,0,0,.2);
  backdrop-filter:blur(8px);
  text-align:center;
  font-size:9px;
  font-weight:900;
  letter-spacing:.08em;
  white-space:nowrap;
}
.turn-banner.player-0{background:rgba(33,76,96,.82)}
.turn-banner.player-1{background:rgba(127,53,43,.82)}
.turn-banner.mine{box-shadow:0 0 0 2px rgba(255,244,208,.13),0 5px 18px rgba(0,0,0,.22)}
.turn-banner.cannon{background:rgba(118,88,25,.9);color:#fff0ba}
.turn-banner.waiting{opacity:.75}
.turn-banner.finished{background:rgba(36,39,38,.82)}

/* 岸炮成为战场实体，按钮本身就是炮台。 */
.camp-cannon-control{
  position:absolute;
  z-index:18;
  width:68px;
  height:48px;
  padding:0;
  border:0;
  background:transparent;
  color:#f8efcf;
  cursor:pointer;
  transform:translate(-50%,-50%);
  filter:drop-shadow(0 4px 4px rgba(0,0,0,.28));
  transition:filter .18s ease,opacity .18s ease,transform .18s ease;
}
.camp-cannon-0{left:50%;top:4%}
.camp-cannon-1{left:50%;top:96%}
.camp-cannon-control:disabled{cursor:default;opacity:.58}
.camp-cannon-control.available{opacity:1;filter:drop-shadow(0 0 8px rgba(255,209,102,.78)) drop-shadow(0 4px 4px rgba(0,0,0,.3));animation:cannon-ready 1.05s ease-in-out infinite alternate}
.camp-cannon-control.aiming{filter:drop-shadow(0 0 12px rgba(255,209,102,1)) drop-shadow(0 4px 4px rgba(0,0,0,.3));transform:translate(-50%,-50%) scale(1.08)}
.camp-cannon-1.aiming{transform:translate(-50%,-50%) scale(1.08)}
.camp-cannon-control.spent{opacity:.28;filter:grayscale(.9) drop-shadow(0 2px 2px rgba(0,0,0,.25))}
.gun-body{
  position:absolute;
  left:8px;
  top:11px;
  width:29px;
  height:12px;
  border-radius:7px 5px 5px 7px;
  background:linear-gradient(180deg,#555d58,#323936);
  border:1px solid rgba(15,21,19,.42);
}
.gun-body::before{
  content:"";
  position:absolute;
  left:20px;
  top:3px;
  width:22px;
  height:5px;
  border-radius:0 5px 5px 0;
  background:#373e3b;
  transform:rotate(-12deg);
  transform-origin:left center;
}
.gun-body::after{
  content:"";
  position:absolute;
  left:5px;
  top:9px;
  width:18px;
  height:8px;
  border-radius:50%;
  border:3px solid #373e3b;
  background:#7c785e;
}
.gun-body i{
  position:absolute;
  left:2px;
  top:-5px;
  width:8px;
  height:7px;
  border-radius:2px;
  background:#626961;
}
.gun-label{
  position:absolute;
  left:50%;
  bottom:-4px;
  transform:translateX(-50%);
  padding:1px 4px;
  border-radius:5px;
  color:#fff3c5;
  background:rgba(10,31,37,.65);
  font-size:7px;
  font-weight:900;
  white-space:nowrap;
}
@keyframes cannon-ready{
  from{transform:translate(-50%,-50%) scale(.96)}
  to{transform:translate(-50%,-50%) scale(1.06)}
}
.camp-cannon-1.available{animation:cannon-ready-south 1.05s ease-in-out infinite alternate}
@keyframes cannon-ready-south{
  from{transform:translate(-50%,-50%) rotate(180deg) scale(.96)}
  to{transform:translate(-50%,-50%) rotate(180deg) scale(1.06)}
}

/* 反馈直接出现在河面中央，减少视线离开棋盘。 */
.action-toast{
  position:absolute;
  left:50%;
  top:50%;
  z-index:22;
  min-width:76px;
  padding:8px 13px;
  border-radius:999px;
  opacity:0;
  pointer-events:none;
  transform:translate(-50%,-30%) scale(.88);
  color:#fff9e8;
  background:rgba(13,39,48,.83);
  border:1px solid rgba(255,255,255,.16);
  box-shadow:0 8px 24px rgba(0,0,0,.24);
  backdrop-filter:blur(8px);
  text-align:center;
  font-size:11px;
  font-weight:900;
  letter-spacing:.08em;
}
.action-toast.show{animation:action-toast-in 1.05s ease forwards}
.action-toast.build{background:rgba(32,113,84,.88)}
.action-toast.capture{background:rgba(144,58,49,.9)}
.action-toast.cannon{background:rgba(129,91,19,.92);color:#fff0b4}
@keyframes action-toast-in{
  0%{opacity:0;transform:translate(-50%,-15%) scale(.78)}
  18%{opacity:1;transform:translate(-50%,-50%) scale(1.03)}
  72%{opacity:1;transform:translate(-50%,-56%) scale(1)}
  100%{opacity:0;transform:translate(-50%,-92%) scale(.92)}
}

.battle-caption{
  width:min(72vh,100%);
  display:flex;
  justify-content:space-between;
  align-items:center;
  gap:8px;
  min-height:24px;
  margin-top:5px;
  padding:0 4px;
  color:rgba(255,248,231,.72);
}
.board-message{margin:0;text-align:left}
.hint-key{flex:none;font-size:8px;opacity:.64;white-space:nowrap}
.hint-dot{display:inline-block;width:6px;height:6px;margin:0 2px 0 5px;border:1.5px solid;border-radius:50%;vertical-align:0}
.hint-dot.empty{border-color:var(--legal)}
.hint-dot.capture{border-color:var(--capture)}
.hint-dot.cannon{border-color:var(--cannon)}

.compact-skill-card .secondary-btn{width:100%;margin-top:8px}
.badge.aiming{background:#f2ce72;color:#67490d}

/* 对岸行动时整体轻微压暗，但工程兵和桥仍保持清晰。 */
.board.enemy-turn .river-texture{opacity:.7}
.board.enemy-turn .point:not(.piece) .target-ring{opacity:.55}

@media(max-width:1050px){
  .battle-caption{width:min(72vh,100%)}
}

@media(max-width:720px){
  body.game-active .topbar{display:none}
  body.game-active .app-shell{width:100%;padding:0 5px max(4px,env(safe-area-inset-bottom))}
  body.game-active .lobby-card{
    position:relative;
    z-index:20;
    margin:3px 0 2px;
    padding:3px 5px;
    border-radius:8px;
    border-color:rgba(255,255,255,.08);
    background:rgba(247,240,220,.93);
  }
  body.game-active .room-card{grid-template-columns:1fr 1fr 1fr;gap:2px}
  body.game-active .room-card>div,body.game-active .room-card>div:first-child{padding:2px 4px}
  body.game-active .room-card span{display:none}
  body.game-active .room-card strong{font-size:9px;line-height:1.3;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  body.game-active #roomCode{font-size:11px;letter-spacing:.12em}
  body.game-active .copy-room-btn{padding:1px 4px;font-size:7px}
  body.game-active .room-code-line{margin:0;gap:3px}

  .game-layout{gap:2px}
  .board-stage{width:100%}
  .board{
    width:min(96vw,calc(65dvh * 8 / 9),560px);
    border-radius:14px;
  }
  .battle-caption{width:min(96vw,calc(65dvh * 8 / 9),560px);min-height:18px;margin-top:2px;padding:0 2px}
  .board-message{font-size:9px;line-height:1.15}
  .hint-key{font-size:7px}

  .board-stage{padding-top:38px}.battle-hud{inset:-34px 6px auto;gap:4px}
  .camp-pill{padding:4px 5px;border-radius:8px}
  .camp-pill b{font-size:8px}
  .camp-pill small{font-size:6px}
  .turn-banner{min-width:70px;padding:5px 7px;font-size:8px}

  .camp-cannon-control{width:58px;height:42px}
.camp-cannon-0{left:50%;top:4%}
.camp-cannon-1{left:50%;top:96%}
  .gun-body{transform:scale(.88);transform-origin:left center}
  .gun-label{font-size:6px;bottom:-1px}

  .status-panel{
    width:min(96vw,560px);
    align-self:center;
    padding:4px;
    border-radius:9px;
    background:rgba(247,240,220,.92);
  }
  .turn-card{display:none}
  .metric-grid{margin:0;gap:3px}
  .metric{padding:4px 2px;border-radius:7px}
  .metric span{font-size:7px}
  .metric strong{font-size:9px}
  .compact-skill-card{
    display:grid;
    grid-template-columns:1fr auto;
    align-items:center;
    gap:4px;
    margin-top:3px;
    padding:4px 5px;
    border-radius:7px;
  }
  .compact-skill-card .skill-title{font-size:9px}
  .compact-skill-card .skill-desc{display:block;margin-top:0;font-size:7px;line-height:1.2}
  .compact-skill-card .badge{font-size:7px}
  .compact-skill-card .secondary-btn{grid-column:1/-1;margin:0;min-height:28px;padding:5px 8px;font-size:9px}
  .rules-panel{display:none!important}
  .action-toast{padding:7px 11px;font-size:10px}

  .point{width:clamp(30px,9.2vw,45px);height:clamp(30px,9.2vw,45px)}
  .camp{transform:translate(-50%,-50%) scale(.73)}
}

@media(max-width:390px){
  .board{width:min(97vw,calc(62dvh * 8 / 9))}
  .battle-caption{width:min(97vw,calc(62dvh * 8 / 9))}
  .status-panel{width:min(97vw,520px)}
.camp-cannon-0{left:50%;top:4%}
.camp-cannon-1{left:50%;top:96%}
  .camp-pill small{display:none}
  .turn-banner{min-width:64px;font-size:7px}
}
/* 浅色炮击范围提示 */
.point.legal-cannon .target-ring{background:rgba(255,244,190,.18);border-color:rgba(255,239,170,.72);box-shadow:0 0 10px rgba(255,239,170,.42)}
