/* ===== 공룡 대전 페이지 전용(dino-battle-page.js) - 타일 설정 카드, 1:1 공룡 스택 대전 화면 =====
   css/style.css를 여러 파일로 분리한 것 중 하나 - index.html에 링크된 순서(cascade 순서)가
   원본과 동일하게 유지되도록 주의할 것 ===== */

/* ===== 공룡 대전 페이지 =====
   모바일(기본): 가운데 전투 화면만 보이고, 내 공룡/상대 공룡 설정은 화면 밖에 숨겨뒀다가
   좌우 가장자리의 탭(peek 버튼)을 누르면 슬라이드 패널로 들어옴.
   데스크톱(1100px 이상): 컨테이너 폭을 넓혀서 좌-내공룡 / 중앙-전투 / 우-상대공룡 3단 그리드로 항상 다 보이게 함. */

/* 아레나(css/arena.css)와 같은 이유로 넓은 PC 화면(1440~1920px대 모니터)에서 1240px 고정 폭이
   화면 양옆에 큰 여백을 남겨 작아 보이는 문제(사용자 지적) - 뷰포트에 비례해서 채우되 상한만 둠.
   비율은 아레나(0.82:1.7:0.82, 전투 화면 비중을 훨씬 크게 둠)만큼 극단적으로 가운데를 키우지는
   않음 - 이 페이지의 가운데 카드는 전투 설정/빠른 계산 탭도 같이 쓰는 자리라 아레나의 "거의
   전투 화면 전용" 가운데 열과 달리 양옆 공룡 설정도 확실히 같이 커져야 함(사용자 확정 - "중간
   카드를 키우고 나서 양 옆 공룡 설정도 크기를 키우고") - 그래도 "먼저 중간을" 요청대로 가운데
   비중을 원래(1:1.15:1)보다 더 키움. 전투 육각형(.battle-hex-stage)은 max-width:900px라 가운데
   카드가 그보다 커져도 그 이상은 안 늘어나고 여백만 넉넉해짐(의도된 동작, 위 주석 참고) */
@media (min-width: 1400px) {
  body[data-page="dino-battle"] .container {
    width: min(96vw, 1760px);
  }
  body[data-page="dino-battle"] .battle-layout {
    grid-template-columns: 1fr 1.4fr 1fr;
  }
}

/* 1100~1399px 구간(사용자 지적) - PC 모니터에서 가로를 줄이다가 1400px 밑으로 내려가는 순간
   위 넓은 화면 규칙이 꺼지고 공용 3단 규칙(combat-shared.css, 컨테이너 min(100%,1240px) +
   1:1.15:1 비율)으로 돌아가는데, 두 규칙의 공식이 이 경계에서 서로 안 이어져서 가운데 전투
   카드가 그 지점에서 훅 작아져 보였음(실측: 1399px에서 423px였다가 1400px 미만으로는 423px에서
   더 줄어드는 게 아니라 그 밑 1100~1399 전체가 원래도 423px 부근에 고정 - 즉 1400px를 기준으로
   위/아래 폭 공식이 서로 다른 값에서 만나 "계단"처럼 뚝 떨어짐). 아레나(css/arena.css)가 이미
   쓰는 해법을 그대로 적용 - 이 구간만 3단을 욱여넣는 대신 전투 카드는 위에 풀 폭으로, 좌우 설정
   패널은 그 아래 2열로 내림. 아레나와 달리 이 페이지는 1100px 미만에서도 딱히 붐비지 않아서
   (실측 확인 - 로그인 상태의 "친구 초대/설정 불러오기" 버튼이 있어도 헤더가 줄바꿈 안 됨) 아래쪽
   경계는 아레나의 700px이 아니라 기존 모바일 오프캔버스 경계(1100px)를 그대로 씀(그 밑은 공용
   모바일 규칙이 계속 담당) */
@media (min-width: 1100px) and (max-width: 1399px) {
  body[data-page="dino-battle"] .battle-layout {
    grid-template-columns: 1fr 1fr;
    grid-template-areas:
      "battle battle"
      "my opp";
  }
  body[data-page="dino-battle"] .battle-arena-wrap {
    grid-area: battle;
  }
  body[data-page="dino-battle"] .battle-side-panel.my-side { grid-area: my; }
  body[data-page="dino-battle"] .battle-side-panel.opp-side { grid-area: opp; }
}

/* 전투 설정/빠른 계산/시뮬레이션/조합 찾기 4탭 - 공용 .battle-mode-indicator는 2탭 폭(50%)으로
   짜여있어서 4탭 폭(25%)만 여기서 따로 덮어씀(titan-mode-tabs-4와 같은 패턴, titan.css 참고).
   이 페이지는 순서가 설정(0번, 기본 위치라 별도 규칙 불필요)/빠른 계산(1번)/시뮬레이션(2번)/
   조합 찾기(3번)라, 공용 .mode-live 규칙(1번 자리 이동)을 그대로 못 쓰고 이 스코프 안에서
   mode-quick=1번, mode-live=2번, mode-optimize=3번으로 다시 정의함 - combat-shared.css보다 이
   파일이 늦게 로드되므로(index.html 링크 순서) 명시도(specificity)가 같아도 나중에 온 이
   규칙이 이김 */
.dino-mode-tabs-4 .battle-mode-indicator {
  width: calc(25% - 5px);
}

.dino-mode-tabs-4.mode-quick .battle-mode-indicator {
  transform: translateX(calc(100% + 4px));
}

.dino-mode-tabs-4.mode-live .battle-mode-indicator {
  transform: translateX(calc(200% + 8px));
}

.dino-mode-tabs-4.mode-optimize .battle-mode-indicator {
  transform: translateX(calc(300% + 12px));
}

/* 전투 설정 탭만 파란색으로 표시(사용자 확정 - "전투 설정은 파란색이어야 해, 타이탄 전투 설정
   색깔" - 타이탄/건물의 #3cb4be를 그대로 씀). data-active-idx가 아니라 이 페이지 고유의
   mode-settings 클래스로 스코프(위 mode-quick/mode-live와 같은 방식) */
.dino-mode-tabs-4.mode-settings .battle-mode-indicator {
  background: linear-gradient(135deg, #3cb4be, color-mix(in srgb, #3cb4be 78%, black));
  box-shadow: 0 3px 10px color-mix(in srgb, #3cb4be 40%, transparent);
}

.dino-mode-tabs-4.mode-settings #modeTabSettings.active {
  color: #eef4ff;
}

/* 조합 찾기 탭 안의 모드 A/B/C 서브 토글 - 공용 .battle-mode-indicator는 2탭(50%) 기준이라
   3탭 폭(33.333%)을 이 스코프에서 다시 정의함(combat-shared.css의 .dummy-mode-tabs-3과 동일한
   패턴). 이동 규칙도 여기서 새로 정의(dino-mode-tabs-4의 mode-live 규칙과 이름이 겹치지 않도록
   mode-modeB/mode-modeC로 명명) */
.dino-optimize-submode-tabs .battle-mode-indicator {
  width: calc(33.333% - 5.333px);
}

.dino-optimize-submode-tabs.mode-modeB .battle-mode-indicator {
  transform: translateX(calc(100% + 4px));
}

.dino-optimize-submode-tabs.mode-modeC .battle-mode-indicator {
  transform: translateX(calc(200% + 8px));
}

/* 타일 설정: 라벨+컨트롤이 붙은 작은 덩어리(chip)로 만들어서 폭이 남으면 한 줄에 여러 개, 좁으면
   자동 줄바꿈되게 함(항목이 4개로 늘어나도 안정적). "전투 설정" 탭(battle-mode-panel)으로 옮기기
   전에는 독립된 .card였어서 자체 padding이 있었는데, 이제는 .battle-main-card(.card)의
   --p-base 패딩을 그대로 물려받으므로(.battle-mode-panel 자체는 패딩 없음, combat-shared.css)
   .battle-tile-card는 클래스명만 유지하고(아래 자식 선택자들의 스코프용) padding은 없앰 */
.battle-tile-card {
  padding: 0;
}

/* "환경"(자연 구조물과 인접/부족 점령 상태/서버 레벨캡/서버 별자리캡)만 이 .setting-list를 씀
   ("진영별 설정"은 .tile-side-grid라는 별개 구조라 안 겹침) - 예전엔 flex-wrap이라 각 항목이
   자기 내용물 크기만큼만 차지해서 자연/부족이 정확히 반반으로 안 나뉘었음(사용자 지적) - 2열
   grid로 바꿔서 각 항목이 정확히 절반씩 차지하게 함. 서버 레벨캡/서버 별자리캡 페어(.setting-stack-pair,
   base.css)는 그 자체가 내부에서 다시 2열로 나뉘는 블록이라 이 바깥 grid에서는 2칸을 통째로
   차지해야 함(안 그러면 페어가 절반 폭에 눌려 들어가서 위치가 이상해짐 - 사용자 지적) */
.battle-tile-card .setting-list {
  margin-top: 0;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px 16px;
}

.battle-tile-card .setting-list > .setting-stack-pair {
  grid-column: 1 / -1;
}

.battle-tile-card .setting-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  border-top: none;
  padding: 0;
}

.battle-tile-card .setting-row .setting-control {
  width: 96px;
  max-width: 96px;
}

/* 이 카드 안 드롭다운은 다른 페이지의 큰 입력칸용 높이를 그대로 쓰기엔 과해서 한 줄짜리로 축소 */
.battle-tile-card .selected-value {
  height: 30px;
  padding: 0 26px 0 10px;
  line-height: 30px;
  font-size: 12px;
}

/* 항목이 늘어날수록(버프 타워 추가 등) 한 덩어리로 뭉쳐 보이지 않도록 "환경"/"진영별 설정"으로
   묶고, 그룹 사이는 얇은 구분선으로 나눔 */
.tile-group + .tile-group {
  margin-top: 16px;
  padding-top: 14px;
  border-top: 1px solid var(--border-color);
}

.tile-group-label {
  font-size: 11px;
  font-weight: 700;
  color: var(--text-sub);
  letter-spacing: 0.3px;
  margin-bottom: 10px;
}

/* 진영별 설정(배치/버프 타워)은 내 공룡·상대 공룡을 좌우로 나란히 둬서 대칭 비교가 쉽게 함 */
.tile-side-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6px 20px;
}

.tile-side-col {
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-width: 0;
}

.tile-side-col-label {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  font-weight: 700;
  color: var(--text-main);
}

.tile-side-col-label::before {
  content: "";
  width: 6px;
  height: 6px;
  flex-shrink: 0;
  border-radius: 50%;
}

.tile-side-col-label.my-side-label::before {
  background: var(--accent);
  box-shadow: 0 0 6px color-mix(in srgb, var(--accent) 70%, transparent);
}

.tile-side-col-label.opp-side-label::before {
  background: #e0473f;
  box-shadow: 0 0 6px rgba(224, 71, 63, 0.6);
}

.tile-side-field {
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.tile-side-field label {
  margin: 0;
  font-size: 11px;
  color: var(--text-sub);
}

.battle-arena {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  padding: clamp(16px, 6cqw, 40px) 0;
}

/* ===== flat-top 육각형(위/아래 변이 평행 - 허수아비/타이탄 페이지와 같은 계열) 3개를 진짜
   3D 원근 공간에 배치 =====
   flat-top은 가로 일직선으로 나란히 두면 점 하나에서만 만나서, 대각선 이웃 스텝(+75,-43.3)을
   한 방향으로 두 번 이어야 진짜로 변이 맞물림(내 쪽이 아래/큼, 상대 쪽이 위/작음 - 결합 viewBox
   250x173.2). .battle-hex-field에 real perspective를 주고 .battle-hex-tilt를 그 안에서
   rotateX(55deg)로 기울이는 건 허수아비 페이지(.dummy-field-wrap/.dummy-hexagon)와 완전히 같은
   기법 - 다만 이번엔 바닥(svg)뿐 아니라 앵커/팀 그룹/아바타 슬롯까지 전부 같은 preserve-3d
   스택 안에 넣어서(체인 중 하나라도 빠지면 그 지점에서 3D가 평면으로 뭉개짐) 상대 쪽 육각형과
   그 위 공룡이 실제로 원근에 의해 작게 보이게 함(사용자 확정 요구사항 - 순수 평면으로는 불가능) */
.battle-hex-field {
  position: relative;
  width: 100%;
  display: flex;
  justify-content: center;
}

/* 예전 CSS rotateX+perspective 가짜 3D 시절엔 카메라에 가까운 쪽이 스테이지의 평평한 레이아웃
   박스보다 더 튀어나와 보여서(사용자 지적 - "내 공룡 타일 왼쪽이 잘림") 카드가 좁을 때 여백을 더
   주는 보정(width:81%)이 필요했는데, 바닥이 Three.js 진짜 3D로 바뀌면서 아바타는
   projectToScreen()이 주는 %좌표로만 배치되고 항상 [0,100]% 안에 있어서 더는 박스 밖으로
   튀어나오지 않음 - 이 보정 자체가 불필요해짐(사용자 지적 - "최대한 크게 볼 수 있어야 해"에 맞춰
   제거, 남겨두면 카드 폭이 640px 밑일 때 내용물만 쓸데없이 더 작아 보임) */

.battle-hex-stage {
  position: relative;
  width: 100%;
  /* 카드 폭이 넓은 화면에서 640px에 막히지 않도록 상한을 넉넉히 올림(실제 병목은 3열 레이아웃의
     가운데 카드 자체 폭이라 이 값이 걸릴 일은 거의 없지만, 좁은 사이드바 없이 혼자 넓게 보일 수
     있는 경우까지 대비) */
  max-width: 900px;
  aspect-ratio: 250 / 173.2;
  margin: 0 auto;
}

/* Three.js가 여기에 canvas를 붙임(js/core/hex-scene3d.js의 mount()) - 바닥은 이제 진짜 WebGL 3D,
   CSS rotateX+perspective는 더 이상 안 씀 */
.battle-hex-tilt {
  position: absolute;
  inset: 0;
  filter: drop-shadow(0 10px 14px rgba(0, 0, 0, 0.35));
}

/* ===== 세계좌표 + 카메라 촬영 방식(사용자 확정 - "싹 갈아엎자") =====
   formationGroup 2개(내/상대)만 두고, 그 안 슬롯들의 left/top은 js/pages/dino-battle-page.js의
   updateStackDisplay()가 바닥과 완전히 같은 결합 좌표계(0~250, 0~173.2) 위에서 실제 삼각함수
   (정삼각형 등)로 계산해서 hexScene.projectToScreen()으로 매번 직접 심음 - 여기 CSS엔 위치 관련
   규칙이 없음. */
.battle-formation-group {
  position: absolute;
  inset: 0;
}

/* 앞장끼리(내 편 vs 상대 편) 화면에서 맞붙어 겹칠 때, 카메라에 더 가까운 쪽(항상 내 편 - 세계좌표
   상 내 대기 타일이 상대 대기 타일보다 카메라에 가까움)이 위에 그려져야 함(사용자 확정 - "공룡끼리도
   앞쪽에 위치한 공룡이 위쪽에 위치해야 함") */
#myFormationGroup { z-index: 2; }
#oppFormationGroup { z-index: 1; }

.battle-team-slot {
  position: absolute;
  display: none;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  /* 평범한 2D 위치 앵커(hexScene.projectToScreen()이 계산한 좌표) - 예전엔 CSS 3D(rotateX 역회전
     +translateZ)로 빌보드를 흉내내고, 슬롯 전체가 preserve-3d 스택 안에 실제로 들어가 있어서 근/원
     크기 차이(가까운 내 편 크게/먼 상대 작게)가 체력바/공/이름표 통째로 저절로 생겼는데, 이제
     바닥이 Three.js로 바뀌면서 슬롯은 평면 DOM이 됐으니 그 원근 축소를 scale()로 직접 재현함
     (--perspective-scale은 hexScene.projectToScreen()의 distance 값으로 updateStackDisplay()가
     계산해서 심어줌) - scale은 translate 이후(왼쪽)에 와도 %기반 translate 자체는 항상 이 요소의
     원래(스케일 전) 레이아웃 박스 크기 기준이라 순서와 무관하게 정확히 목표 지점에 중심이 옴 */
  transform: translate(-50%, -50%) scale(var(--perspective-scale, 1));
}

/* 앞장(avatar)은 팀이 살아있는 한 항상 보임(대기는 js가 display를 직접 토글). z-index는 더 이상
   정적 tier가 아니라 js/pages/dino-battle-page.js의 updateStackDisplay()가 카메라와의 실제 거리로
   매 프레임 계산해서 심음(가까울수록 위) - 대기 3마리 중 실제로 카메라에 가장 가까운(앞) 자리가
   항상 위에 오도록(사용자 지적 - "가까이 있는게 되려 가려져") */
.battle-team-slot-avatar {
  display: flex;
}

.battle-hp-bar-mini {
  /* 가로 길이를 공룡 실제 렌더 폭(.battle-avatar와 완전히 같은 공식)과 정확히 맞춤 - 예전엔 고정
     clamp()라 화면 폭/원근 배율에 따라 공룡 크기와 체력바 길이 비율이 안 맞을 수 있었음(사용자
     지적 - "공룡 크기에 비해 체력바가 짧아 보임"). 처음엔 1.1배로 했다가 "너무 길다"는 재지적을
     받아 1배로 조정하고, 대신 세로 두께도 기존 바의 원래 비율(가로 46px일 때 세로 4px)을 그대로
     유지한 채 같이 줄어들게 함 - 세로를 4px 고정값으로 그냥 두면 가로만 줄어들 때 상대적으로
     두꺼워 보이는 문제가 있었음(사용자 지적). max()의 2px 바닥은 아주 작은 화면에서 세로가
     안 보일 만큼 얇아지는 것만 방지하는 안전판. 부모(.battle-team-slot)의 --perspective-scale
     변환은 체력바/공룡 둘 다 똑같이 받으므로 이 비율(1:1, 그리고 원래 세로 비율)은 화면
     크기·원근 배율과 무관하게 항상 유지됨 */
  width: calc(var(--avatar-base-px, 60px) * var(--avatar-formation-scale, 1) * var(--dino-scale, 1));
  height: max(2px, calc(var(--avatar-base-px, 60px) * var(--avatar-formation-scale, 1) * var(--dino-scale, 1) * 4 / 46));
  border-radius: 999px;
  background: var(--input-bg);
  border: 1px solid var(--border-color);
  overflow: hidden;
}

.battle-hp-fill-mini {
  height: 100%;
  width: 100%;
  transition: width 0.4s cubic-bezier(0.22, 1, 0.36, 1);
  border-radius: 999px;
}

.my-hp-fill {
  background: linear-gradient(90deg, var(--accent-strong), var(--accent));
}

.opp-hp-fill {
  background: linear-gradient(90deg, #a4241f, #e0473f);
}

/* 체력바는 공룡 머리 위, 닉네임은 발 밑(사용자 확정) - DOM 순서(hp-bar-mini → avatar → name)가
   그대로 이 위/아래 배치가 됨. 개별 공룡 고유 닉네임 데이터는 없어서 "내 공룡"/"상대 공룡"(또는
   친구 세션 중이면 그 닉네임)을 슬롯마다 반복 표시함 - updateFriendLabels()가 갱신 */
.battle-team-slot-name {
  font-size: clamp(8px, 2cqw, 10px);
  color: var(--text-sub);
  white-space: nowrap;
  max-width: 60px;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* 내 공룡 이름은 초록색, 상대 공룡 이름은 빨간색으로 구분(사용자 확정) */
#myFormationGroup .battle-team-slot-name { color: #4ade80; }
#oppFormationGroup .battle-team-slot-name { color: #e0473f; }

/* --avatar-base-px는 육각형 크기 기준 통일 크기(js/core/hex-scene3d.js의 DINO_AVATAR_DIAMETER_WORLD)
   를 center 타일 위에 투영한 픽셀 지름 - dinoBattleRefreshReferenceSize()가 #battleArena에 심어줌
   (자식으로 상속). --dino-scale은 매머드의 힘(1.12배)/압축된 힘(0.88배) 룬 장착 여부에 따라
   applyDinoScale()이 formationGroup에 심어주는 배율. --avatar-formation-scale은 중앙 절반처럼
   좁은 자리에 3마리가 들어갈 때만 updateStackDisplay()가 슬롯별로 심어주는 축소 배율(둘 다
   js/pages/dino-battle-page.js) - 서로 독립적으로 곱해짐(룬 배율은 대형과 무관하게 항상 적용).
   카메라 원근 축소(가까운 내 편 크게/먼 상대 작게)는 --perspective-scale로 따로 처리 - 예전엔
   아바타가 CSS 3D preserve-3d 스택 안에 실제로 들어있어서 체력바/이름표까지 통째로 저절로 커지고
   작아졌는데, 바닥이 Three.js로 바뀌며 슬롯 전체가 평면 DOM이 된 뒤로는 그 통째 축소를
   .battle-team-slot의 transform에 scale()로 재현함(아래 참고) - 여기(개별 공 크기)는 그것과
   독립적으로 곱해짐 */
.battle-avatar {
  position: relative;
  width: calc(var(--avatar-base-px, 60px) * var(--avatar-formation-scale, 1) * var(--dino-scale, 1));
  height: calc(var(--avatar-base-px, 60px) * var(--avatar-formation-scale, 1) * var(--dino-scale, 1));
  border-radius: 50%;
  transition: transform 0.32s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.my-avatar {
  background: radial-gradient(circle at 35% 30%, color-mix(in srgb, var(--accent) 70%, white), var(--accent-strong) 75%);
  box-shadow: 0 0 22px color-mix(in srgb, var(--accent) 55%, transparent);
}

.opp-avatar {
  background: radial-gradient(circle at 35% 30%, #ff8a80, #a4241f 75%);
  box-shadow: 0 0 22px rgba(224, 71, 63, 0.55);
}

/* 공격/피격 모션(사용자 확정 - 구체로 되돌리면서 다시 필요해짐, 스프라이트 도입 전 원본 그대로) -
   공격자는 상대 쪽으로 살짝 튀어나갔다 돌아옴(lunge), 피격자는 제자리에서 떨림(hit-shake) */
.battle-avatar.lunge-right {
  animation: battle-lunge-right 0.35s ease;
}

.battle-avatar.lunge-left {
  animation: battle-lunge-left 0.35s ease;
}

.battle-avatar.hit-shake {
  animation: battle-hit-shake 0.35s ease;
}

@keyframes battle-lunge-right {
  0% { transform: translateX(0) scale(1); }
  45% { transform: translateX(28px) scale(1.08); }
  100% { transform: translateX(0) scale(1); }
}

@keyframes battle-lunge-left {
  0% { transform: translateX(0) scale(1); }
  45% { transform: translateX(-28px) scale(1.08); }
  100% { transform: translateX(0) scale(1); }
}

/* 피격 흔들림 폭을 절반으로(사용자 확정 - "사이트의 모든 피격 시 떨림 정도를 절반으로 줄여") -
   밝기 플래시(filter)는 흔들림 자체가 아니라서 그대로 둠. 아레나 페이지도 이 keyframe을 그대로
   재사용함(css/arena.css) */
@keyframes battle-hit-shake {
  0%, 100% { transform: translateX(0); filter: brightness(1); }
  20% { transform: translateX(-3px); filter: brightness(1.8); }
  40% { transform: translateX(3px); }
  60% { transform: translateX(-2px); }
  80% { transform: translateX(2px); }
}

/* 피격 이펙트 이미지는 허수아비/타이탄과 완전히 같은 것을 재사용함(assets/sprites/Hit_Effect.png,
   css/dummy.css의 .dummy-hit-effect - 빨갛게 물들이는 filter까지 그대로) - js/pages/dino-battle-
   page.js의 playLungeAndShake()가 dummySpawnHitEffect/titanPlayHit과 같은 방식으로 img를 만들어
   붙임(사용자 확정 - 직접 만든 CSS 발톱 자국 대신 이 이미지를 쓰기로 함) */

/* 앞장이 죽어서 대기 중이던 공룡이 승격될 때 그 자리로 실제로 이동해온 것처럼 보이는 연출
   (사용자 확정) - .battle-team-slot이 이미 3D 빌보드 transform을 갖고 있어서 그 transform을
   건드리면 깨지므로, 화면 평면 기준 2차원 이동은 자식인 .battle-avatar 쪽에 얹음(부모의 3D
   변환이 이미 카메라를 향해 평평하게 세워둔 뒤라 여기서의 translate는 그냥 화면상 이동으로 보임).
   "다른 타일"이라 대기가 실제 화면 위치를 갖고 있으면 FLIP 기법(js의 handlePromotionEffects가
   이동 전/후 실제 좌표 차이를 재서 --flip-dx/dy로 넘겨줌)으로 진짜 그 위치에서 온 것처럼 이동 -
   시작 상태(.promote-in-flip)는 트랜지션 없이 즉시 적용하고, 다음 프레임에 .promote-in-flip-
   active를 얹어야 브라우저가 "즉시 이동 후 트랜지션"이 아니라 "그 지점에서부터 트랜지션"으로
   처리함(고전적 FLIP 2단계 클래스 패턴) */
.battle-avatar.promote-in-flip {
  transform: translate(var(--flip-dx, 0), var(--flip-dy, 0)) scale(0.7);
  opacity: 0.5;
}
/* 예전 cubic-bezier(0.22,1,0.36,1)(easeOutQuint류)는 너무 앞쪽에 몰려서(실측 결과 시작 20ms만에
   전체 이동 거리의 22%, 40ms만에 58%가 이미 끝나버림) 320ms 애니메이션이라 적어놓고도 눈에는
   "슥 나타남"처럼 거의 순간이동으로 보였음(사용자 지적 - 이동 모션이 안 보인다고 함). ease-out은
   실측상 100ms에 약 39%, 200ms에 약 76%로 훨씬 고르게 퍼져서 이동 궤적이 실제로 눈에 보임 */
.battle-avatar.promote-in-flip-active {
  transition: transform 0.38s ease-out, opacity 0.38s ease;
  transform: translate(0, 0) scale(1);
  opacity: 1;
}

/* "한 타일"이라 대기가 애초에 화면에 없었을 때만 쓰는 대체용 고정 슬라이드(실제 이동 거리를
   잴 방법이 없어서 방향만 맞춤 - 내 편은 왼쪽에서, 상대는 오른쪽에서) */
.battle-avatar.promote-in-left { animation: battle-promote-in-left 0.3s ease-out; }
.battle-avatar.promote-in-right { animation: battle-promote-in-right 0.3s ease-out; }
@keyframes battle-promote-in-left {
  0% { transform: translateX(-28px) scale(0.82); opacity: 0.55; }
  100% { transform: translateX(0) scale(1); opacity: 1; }
}
@keyframes battle-promote-in-right {
  0% { transform: translateX(28px) scale(0.82); opacity: 0.55; }
  100% { transform: translateX(0) scale(1); opacity: 1; }
}

/* 승격으로 빈 대기 슬롯에 오버플로우(가려져 있던) 공룡이 새로 나타날 때 - 작음에서 원래 크기로
   확대되는 팝인(사용자 확정, "수면 위로 올라오는" 느낌) */
.battle-avatar.reserve-pop-in { animation: battle-reserve-pop-in 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); }
@keyframes battle-reserve-pop-in {
  0% { transform: scale(0.35); opacity: 0.3; }
  100% { transform: scale(1); opacity: 1; }
}

/* 배치 설정을 "다른 타일"→"한 타일"로 바꾸는 순간, 그때까지 대기 육각형에 떠 있던 아바타 자리에
   똑같이 생긴 "유령"을 임시로 띄운 뒤 앞장(전투 자리) 쪽으로 날아가며 축소+페이드 - 실제 상태 전환
   (아바타 숨김 + 체력바 전환)은 이 애니메이션과 동시에 바로 진행되므로, 유령이 날아가는 짧은 순간
   동안만 "모여드는" 느낌을 겹쳐서 보여줌(js의 playConvergeGhosts가 실측 좌표로 --converge-dx/dy를
   구해서 넘김 - FLIP과 같은 방식). z-index를 높여 다른 3D 빌보드 레이어 위에 그대로 보이게 함 */
.battle-converge-ghost {
  z-index: 60;
  pointer-events: none;
  transform: scale(1);
  opacity: 1;
}
.battle-converge-ghost-active {
  transition: transform 0.34s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.34s ease;
  transform: translate(var(--converge-dx, 0), var(--converge-dy, 0)) scale(0.25);
  opacity: 0;
}

/* 아바타 3마리(앞장 포함) 한도를 넘는 나머지 공룡들 - 아바타 없이 얇은 체력바만, 타일들 밑에
   따로 모아서 보여줌(사용자 확정) */
.battle-overflow-row {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  width: 100%;
  max-width: 640px;
}

.battle-overflow-group {
  flex: 1;
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  align-content: flex-start;
}

/* 내 대기 공룡은 왼쪽, 상대 대기 공룡은 오른쪽으로 붙여서 그림 - 둘 다 그냥 왼쪽 정렬이면
   상대 쪽 바들이 화면 가운데 쪽으로 쏠려 보여서 "누구 건지" 헷갈렸음(사용자 지적) */
.my-overflow-group { justify-content: flex-start; }
.opp-overflow-group { justify-content: flex-end; }

.battle-overflow-bar {
  width: clamp(20px, 6cqw, 30px);
  height: 6px;
  border-radius: 999px;
  background: var(--input-bg);
  border: 1px solid var(--border-color);
  overflow: hidden;
  flex-shrink: 0;
  animation: battle-overflow-bar-in 0.25s ease;
}

@keyframes battle-overflow-bar-in {
  0% { opacity: 0; transform: scaleX(0.4); }
  100% { opacity: 1; transform: scaleX(1); }
}

.battle-overflow-bar-fill {
  height: 100%;
  transition: width 0.3s ease;
}

/* 죽음 = "원래 크기 -> 축소되며 사라짐"(사용자 확정 - 예전의 펀치+회전+그레이스케일 플래시
   대신). 이 자리(앞장 아바타)는 바로 다음 공룡으로 교체돼서 재사용되므로, 이 애니메이션이 끝나는
   시점(js의 setTimeout 350ms)에 맞춰 새 공룡의 승격 슬라이드 애니메이션이 이어서 시작함
   (handlePromotionEffects) - 같은 엘리먼트에 두 애니메이션이 동시에 걸리면 CSS가 하나만
   적용하므로 반드시 순서대로 재생되도록 js에서 지연시킴 */
.battle-avatar.front-defeated {
  animation: battle-front-defeated 0.35s ease-in forwards;
}

@keyframes battle-front-defeated {
  0% { transform: scale(1); opacity: 1; }
  100% { transform: scale(0.1); opacity: 0; }
}

/* 전멸(그 진영에 더 이상 남은 공룡이 없음) 전용 - 승격 전 잠깐 재생되는 위 front-defeated(축소+
   투명화 애니메이션)와 달리 자리는 그대로 남기고 무채색으로 "죽었지만 위치는 보이게" 영구
   표시함(사용자 확정 - 완전히 안 보이면 체력바/닉네임만 붕 떠 보여서 어색하다는 피드백으로
   재설계, playDeathFlash 참고). 처음엔 filter:grayscale+opacity로 반투명하게 남겼는데, opacity가
   그 뒤에 실시간 렌더링되는 3D 육각 타일(부족 점령 상태에 따라 흰색/골드/빨강으로 바뀜)과
   알파 합성되면서 색이 살짝 섞여 들어가 타일보다 위/아래인지 헷갈린다는 피드백(사용자 제보) -
   반투명 자체를 없애고 완전 불투명한 회색으로 바꿔서 경계를 또렷하게 함 */
.battle-avatar.front-eliminated {
  background: #4d4d4d;
  box-shadow: none;
  filter: none;
  opacity: 1;
  transition: background 0.35s ease-in;
}

.battle-arena.area-flash {
  animation: battle-area-flash 0.4s ease;
}

@keyframes battle-area-flash {
  0%, 100% { background: transparent; }
  40% { background: color-mix(in srgb, var(--accent) 16%, transparent); }
}

