/* ============================================================
   work.html — Three.js 3D 워크스루 프로토타입 (1단계)
   색상 토큰(--motion-rgb 등)은 styles.css :root에 유지되어 있으며
   game.js에서 조명/캐릭터 색으로 재사용할 수 있다.
   ============================================================ */

body.game-page {
  overflow: hidden;
  height: 100vh;
  /* v5.9: dvh는 모바일 브라우저의 주소창/툴바가 접히고 펼쳐지는 실제 높이를
     따라간다 — 가로 모드 폰에서 캔버스 아래가 잘리거나 남는 문제를 없앤다.
     (미지원 브라우저는 위 100vh 폴백을 그대로 쓴다) */
  height: 100dvh;
}

#game-root {
  position: fixed;
  inset: 0;
  top: 72px;
  z-index: 0;
  background: #0b0c10;
  /* click 리스너가 걸려 있어 안드로이드에서 캔버스 탭마다 회색 플래시가
     떴다 — 버튼류는 styles.css 공통 규칙이 처리하고, 여기는 별도 지정 */
  -webkit-tap-highlight-color: transparent;
  /* inset:0만으로는 레이아웃 뷰포트(=고정 100vh) 기준이라 툴바가 접힐 때
     캔버스 하단이 남는다 — 실제 가시 높이에서 나브를 뺀 값으로 고정한다. */
  height: calc(100dvh - 72px);
}

#game-root canvas {
  display: block;
  width: 100%;
  height: 100%;
}

/* ── 입장 암막 연출 — 로딩이 끝나면 좌우로 걷혀 공간을 드러낸다 ────── */
.game-curtain {
  position: fixed;
  inset: 0;
  top: 72px;
  z-index: 100;
  display: flex;
  pointer-events: none;
}

.game-curtain-panel {
  width: 50%;
  height: 100%;
  background: #08090c;
  background-image: linear-gradient(90deg, rgba(0, 0, 0, 0.15), rgba(0, 0, 0, 0) 40%);
  transition: transform 1.3s cubic-bezier(0.65, 0, 0.2, 1);
}

.game-curtain-left { transform: translateX(0); }
.game-curtain-right { transform: translateX(0); }

.game-curtain.is-open .game-curtain-left { transform: translateX(-100%); }
.game-curtain.is-open .game-curtain-right { transform: translateX(100%); }

.game-curtain.is-done { display: none; }

@media (prefers-reduced-motion: reduce) {
  .game-curtain-panel { transition: none; }
}

/* ── 출구 시퀀스 흰 페이드 — 출구 문이 열리며 화면 전체가 따뜻한 화이트로
   덮인 뒤 work-grid.html?from=exit로 이동한다(game.js updateExitSequence).
   전환 시간(1.3s)은 game.js EXIT_NAVIGATE_AT 계산과 세트다. 나브(top:72px)까지
   덮어 완전한 순백에서 다음 페이지로 이어지게 한다. ───────────────────── */
.game-exit-fade {
  position: fixed;
  inset: 0;
  z-index: 400; /* 로딩(500) 제외 모든 게임 UI(온보딩 300 포함)보다 위 */
  background: #fff7ea;
  opacity: 0;
  pointer-events: none;
  transition: opacity 1.3s ease;
}

.game-exit-fade.is-active {
  opacity: 1;
  pointer-events: auto; /* 페이드 중 뒤쪽 UI 오클릭 방지 */
}

@media (prefers-reduced-motion: reduce) {
  .game-exit-fade { transition: opacity 0.3s ease; }
}

.game-hud {
  position: fixed;
  left: 28px;
  bottom: 24px;
  z-index: 10;
  display: flex;
  flex-direction: column;
  gap: 8px;
  align-items: flex-start;
  pointer-events: none;
}

.game-hud-text {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.04em;
  color: var(--ink-muted);
  background: rgba(11, 12, 16, 0.55);
  border: 1px solid var(--hairline);
  border-radius: 100px;
  padding: 8px 16px;
  margin: 0;
}

/* ── Pointer Lock 안내 — 처음 진입 시/해제 시에만 잠깐 화면 중앙에 표시 ── */
.game-pointerlock-hint {
  position: fixed;
  top: 50%;
  left: 50%;
  z-index: 20;
  transform: translate(-50%, -50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 18px 28px;
  background: rgba(11, 12, 16, 0.62);
  border: 1px solid var(--hairline-strong);
  border-radius: 14px;
  backdrop-filter: blur(8px);
  pointer-events: none;
  text-align: center;
  opacity: 0;
  transition: opacity 0.35s ease;
}

.game-pointerlock-hint.is-visible { opacity: 1; }

.game-pointerlock-hint-main {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 14px;
  letter-spacing: 0.04em;
  color: var(--ink);
}

.game-pointerlock-hint-sub {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.04em;
  color: var(--ink-muted);
}

/* ── 1인칭/3인칭 시점 전환 버튼 (우하단, 진행 바와 겹치지 않게) ────── */
.game-view-toggle {
  position: fixed;
  right: 28px;
  bottom: 24px;
  z-index: 10;
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.04em;
  color: var(--ink-muted);
  background: rgba(11, 12, 16, 0.55);
  border: 1px solid var(--hairline);
  border-radius: 100px;
  padding: 8px 16px;
  cursor: pointer;
  transition: color 0.2s ease, border-color 0.2s ease, background 0.2s ease;
}

.game-view-toggle:hover {
  color: var(--ink);
  border-color: var(--hairline-strong);
}

.game-view-toggle.is-first-person {
  color: var(--ink);
  border-color: var(--ai);
}

.game-view-toggle-icon { flex: none; }

/* 주인공 남/여 — 시점·소리 버튼과 같은 알약, 그 위에 쌓는다(우하단 열) */
.game-lead-toggle {
  position: fixed;
  right: 28px;
  bottom: 108px;
  z-index: 10;
  display: flex;
  align-items: center;
  gap: 4px;
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.04em;
  color: var(--ink-muted);
  background: rgba(11, 12, 16, 0.55);
  border: 1px solid var(--hairline);
  border-radius: 100px;
  padding: 4px 4px 4px 14px;
}
.game-lead-toggle .game-view-toggle-icon { margin-right: 4px; }
.game-lead-toggle button {
  appearance: none;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  letter-spacing: inherit;
  padding: 4px 10px;
  border-radius: 100px;
  cursor: pointer;
  transition: color 0.2s ease, background 0.2s ease;
}
.game-lead-toggle button:hover { color: var(--ink); }
.game-lead-toggle button.is-on { color: #0b0c10; background: var(--ink); }

.game-view-toggle-key {
  font-size: 10px;
  color: var(--ink-muted);
  border: 1px solid var(--hairline);
  border-radius: 4px;
  padding: 1px 5px;
  line-height: 1.4;
}

/* ── 미디어월 공간 음향 토글 — 시점 전환 버튼 바로 위, 같은 톤의 pill ──── */
.game-audio-toggle {
  position: fixed;
  right: 28px;
  bottom: 66px;
  z-index: 10;
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.04em;
  color: var(--ink-muted);
  background: rgba(11, 12, 16, 0.55);
  border: 1px solid var(--hairline);
  border-radius: 100px;
  padding: 8px 16px;
  cursor: pointer;
  transition: color 0.2s ease, border-color 0.2s ease, background 0.2s ease;
}

.game-audio-toggle:hover {
  color: var(--ink);
  border-color: var(--hairline-strong);
}

.game-audio-toggle.is-on {
  color: var(--ink);
  border-color: var(--motion);
}

/* 켜짐/꺼짐에 따라 스피커 아이콘을 바꿔 끼운다 */
.game-audio-icon-on,
.game-audio-icon-off { flex: none; }
.game-audio-toggle .game-audio-icon-on { display: none; }
.game-audio-toggle .game-audio-icon-off { display: block; }
.game-audio-toggle.is-on .game-audio-icon-on { display: block; }
.game-audio-toggle.is-on .game-audio-icon-off { display: none; }

/* ── 배경음 플레이어 — 주인공 선택 버튼 위, 같은 톤의 pill(소리 켜짐일 때만) ── */
.game-bgm {
  position: fixed;
  right: 28px;
  bottom: 150px;
  z-index: 10;
  display: flex;
  align-items: center;
  gap: 2px;
  max-width: min(320px, calc(100vw - 56px));
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.02em;
  color: var(--ink-muted);
  background: rgba(11, 12, 16, 0.55);
  border: 1px solid var(--hairline);
  border-radius: 100px;
  padding: 3px;
  opacity: 0;
  transform: translateY(6px);
  pointer-events: none;
  transition: opacity 0.3s ease, transform 0.3s ease;
}
.game-bgm.is-visible { opacity: 1; transform: none; pointer-events: auto; }
.game-bgm button {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  cursor: pointer;
  border-radius: 100px;
  display: flex;
  align-items: center;
  transition: color 0.2s ease, background 0.2s ease;
}
.game-bgm button:hover, .game-bgm button:focus-visible { color: var(--ink); background: rgba(255, 255, 255, 0.07); }
.game-bgm-btn { padding: 6px 8px; flex: none; }
.game-bgm-title { gap: 7px; padding: 6px 10px; min-width: 0; }
.game-bgm-title span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.game-bgm .game-bgm-icon-order { display: none; }
.game-bgm.is-order .game-bgm-icon-order { display: block; }
.game-bgm.is-order .game-bgm-icon-shuffle { display: none; }
/* 음악만 끄기(2026-11-11) — 환경음·효과음은 그대로. 꺼지면 ▶ 아이콘 + 나머지 버튼·제목을 흐리게 */
.game-bgm .game-bgm-icon-off { display: none; }
.game-bgm.is-muted .game-bgm-icon-on { display: none; }
.game-bgm.is-muted .game-bgm-icon-off { display: block; }
.game-bgm.is-muted .game-bgm-mute { color: var(--motion); }
.game-bgm.is-muted [data-bgm-mode], .game-bgm.is-muted [data-bgm-title], .game-bgm.is-muted [data-bgm-next] { opacity: 0.45; }
.game-bgm-list {
  position: absolute;
  right: 0;
  bottom: calc(100% + 8px);
  margin: 0;
  padding: 6px;
  list-style: none;
  min-width: 240px;
  max-width: min(340px, calc(100vw - 32px));
  max-height: 46vh;
  overflow-y: auto;
  background: rgba(11, 12, 16, 0.9);
  border: 1px solid var(--hairline);
  border-radius: 14px;
  backdrop-filter: blur(8px);
}
.game-bgm-list li {
  padding: 9px 12px;
  border-radius: 9px;
  cursor: pointer;
  color: var(--ink-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.game-bgm-list li:hover, .game-bgm-list li:focus-visible { color: var(--ink); background: rgba(255, 255, 255, 0.07); outline: none; }
.game-bgm-list li[aria-selected="true"] { color: var(--ink); }
.game-bgm-list li[aria-selected="true"]::before { content: "♪ "; color: var(--motion); }

/* ── 풀스크린 로딩 화면 — 그래파이트 블랙 + 타이틀 + 진행률 바 ────── */
.game-loading {
  position: fixed;
  inset: 0;
  z-index: 500;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #0b0c10;
  transition: opacity 0.6s ease;
}

.game-loading.is-hidden {
  opacity: 0;
  pointer-events: none;
}
/* 로딩 중에도 상단 바(로고 = 첫 화면, 메뉴)를 누를 수 있게 로딩 화면 위로 올린다 — 로딩이 걷히면 원래 층(100)으로 */
body.game-page:has(.game-loading:not(.is-hidden)) .nav { z-index: 501; }
/* 세로 화면 회전 안내(전체 화면 게이트, z 12000)가 떠 있을 때도 로고로 나갈 수 있게 */
body.game-page:has(.game-orientation-gate.is-blocking) .nav { z-index: 12001; }

.game-loading-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 20px;
  width: min(320px, 80vw);
}

/* v5.8: 브랜드 타이틀은 "전시장 이름판"처럼 작고 조용하게 물러나고, 화면의
   주인공은 아래 순차 안내 멘트가 된다(예전에는 큰 정적 타이틀이 주인공이었다). */
.game-loading-title {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.34em;
  text-indent: 0.34em; /* 자간이 커서 생기는 우측 쏠림 보정 */
  color: var(--ink-muted);
  margin: 0;
}

.game-loading-bar-track {
  width: 100%;
  height: 3px;
  border-radius: 100px;
  background: var(--hairline-strong);
  overflow: hidden;
}

.game-loading-bar-fill {
  width: 0%;
  height: 100%;
  border-radius: 100px;
  background: linear-gradient(90deg, var(--motion), var(--ai), var(--apps));
  transition: width 0.25s ease-out;
}

/* v5.6: 메인 스레드가 블로킹(셰이더 컴파일 등)돼 width/% 갱신이 멈춰도 로딩이
   살아 보이도록, 트랙 위를 오가는 하이라이트를 컴포지터 전용 속성(transform/
   opacity) 애니메이션으로 얹는다 — JS가 멈춰도 이 애니메이션은 계속 돈다. */
.game-loading-bar-track {
  position: relative;
}

.game-loading-bar-track::after {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  width: 40%;
  height: 100%;
  border-radius: 100px;
  background: linear-gradient(90deg, transparent, rgba(241, 239, 231, 0.55), transparent);
  animation: game-loading-shimmer 1.4s ease-in-out infinite;
  will-change: transform;
  pointer-events: none;
}

@keyframes game-loading-shimmer {
  0% { transform: translateX(-100%); }
  100% { transform: translateX(350%); }
}

/* 문구 옆 점 펄스 — 같은 이유로 CSS 전용(블로킹 중에도 살아있는 신호) */
.game-loading-phrase::after {
  content: "";
  display: inline-block;
  width: 6px;
  height: 6px;
  margin-left: 8px;
  border-radius: 50%;
  background: var(--ink-muted);
  vertical-align: 1px;
  animation: game-loading-dot 1.1s ease-in-out infinite;
  will-change: transform, opacity;
}

@keyframes game-loading-dot {
  0%, 100% { opacity: 0.25; transform: scale(0.8); }
  50% { opacity: 1; transform: scale(1.15); }
}

@media (prefers-reduced-motion: reduce) {
  .game-loading-bar-track::after,
  .game-loading-phrase::after { animation: none; }
}

.game-loading-pct {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.04em;
  color: var(--ink-muted);
  margin: 0;
}

/* 단계별 로딩 문구 — game.js가 진행률에 맞춰 텍스트를 교체하며,
   .is-swapping 동안 잠깐 투명해졌다가 새 문구로 페이드인한다 */
.game-loading-phrase {
  font-size: 16px;
  line-height: 1.5;
  letter-spacing: 0.01em;
  color: var(--ink);
  margin: 18px 0 0;
  min-height: 2.6em; /* 두 줄짜리 멘트에서도 레이아웃이 흔들리지 않게 */
  text-align: center;
  text-wrap: balance;
  opacity: 0.96;
  transition: opacity 0.16s ease;
}

/* 대기 팀 수 / 관람객 번호 — 문구는 그대로 두고 숫자만 바뀌며 살짝 튀어오른다 */
.game-loading-count {
  display: inline-block;
  font-family: var(--font-mono);
  font-weight: 600;
  color: var(--motion);
  font-variant-numeric: tabular-nums; /* 자릿수가 바뀌어도 문장이 흔들리지 않게 */
}

.game-loading-count.is-bump {
  animation: game-loading-count-bump 0.42s cubic-bezier(0.22, 1, 0.36, 1);
}

@keyframes game-loading-count-bump {
  0% { transform: translateY(-0.35em) scale(1.25); opacity: 0; }
  55% { transform: translateY(0) scale(1.06); opacity: 1; }
  100% { transform: translateY(0) scale(1); opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .game-loading-count.is-bump { animation: none; }
}

.game-loading-phrase.is-swapping {
  opacity: 0;
}

/* ── 진행 네비게이션 (미술관 안내도 스타일) ───────────────────────── */
.game-progress {
  position: fixed;
  left: 50%;
  bottom: 24px;
  transform: translateX(-50%);
  z-index: 10;
  width: min(560px, calc(100vw - 48px));
  padding: 14px 20px 10px;
  background: rgba(11, 12, 16, 0.6);
  border: 1px solid var(--hairline);
  border-radius: 16px;
  backdrop-filter: blur(8px);
  /* 아래 호버 글로우(락 해제 시)가 즉시 점등하지 않게 — 테두리/그림자류의
     사이트 공통 전환 시간(0.25s ease) */
  transition: border-color 0.25s ease, box-shadow 0.25s ease;
}

/* ── 시간대 라벨 — "GOLDEN HOUR — 18:42" ─────────────────────────── */
.game-time-of-day {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.1em;
  text-align: center;
  color: var(--ink-muted);
  margin: 0 0 10px;
}

.game-progress-track {
  position: relative;
  height: 3px;
  border-radius: 100px;
  background: var(--hairline-strong);
  margin-bottom: 10px;
}

.game-progress-fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: 0%;
  border-radius: 100px;
  background: linear-gradient(90deg, var(--motion), var(--ai), var(--apps));
}

.game-progress-dot {
  position: absolute;
  top: 50%;
  left: 0%;
  width: 10px;
  height: 10px;
  margin: -5px 0 0 -5px;
  border-radius: 50%;
  background: var(--ink);
  box-shadow: 0 0 8px 2px rgba(241, 239, 231, 0.6);
  transition: left 0.1s linear;
}

.game-progress-labels {
  display: flex;
  justify-content: space-between;
  gap: 4px;
}

.game-progress-stop {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.02em;
  color: var(--ink-muted);
  background: none;
  border: none;
  padding: 2px 4px;
  cursor: pointer;
  transition: color 0.2s ease, text-shadow 0.25s ease;
}

.game-progress-stop:hover { color: var(--ink); }

.game-progress-stop.is-active { font-weight: 600; }
.game-progress-stop[data-progress-cat="motion"].is-active { color: var(--motion); }
.game-progress-stop[data-progress-cat="ai"].is-active { color: var(--ai); }
.game-progress-stop[data-progress-cat="apps"].is-active { color: var(--apps); }
.game-progress-stop[data-progress-cat="violet"].is-active { color: var(--violet); }
.game-progress-stop:not([data-progress-cat]).is-active { color: var(--ink); }

/* ── 근접 인터랙션 프롬프트(방명록/엘리베이터 공용) — 화면 중앙(센터보다
   살짝 아래)에 은은한 글로우와 함께 페이드인한다. 거리 기반으로
   is-visible이 토글되고, E 키로도 동일하게 활성화된다(game.js). ────── */
@keyframes interact-prompt-glow {
  0%, 100% { box-shadow: 0 0 22px 2px rgba(232, 163, 61, 0.35), inset 0 0 14px rgba(232, 163, 61, 0.12); }
  50% { box-shadow: 0 0 34px 6px rgba(232, 163, 61, 0.55), inset 0 0 18px rgba(232, 163, 61, 0.2); }
}

.game-interact-prompt {
  position: fixed;
  top: 58%;
  left: 50%;
  z-index: 20;
  transform: translate(-50%, -40%) scale(0.94);
  display: flex;
  align-items: center;
  gap: 14px;
  font-family: var(--font-mono);
  font-size: 19px;
  letter-spacing: 0.04em;
  color: var(--ink);
  background: rgba(20, 16, 8, 0.55);
  border: 1px solid rgba(232, 163, 61, 0.6);
  border-radius: 100px;
  padding: 16px 34px;
  cursor: pointer;
  backdrop-filter: blur(6px);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.4s ease, transform 0.4s ease;
}

.game-interact-prompt.is-visible {
  opacity: 1;
  pointer-events: auto;
  transform: translate(-50%, -50%) scale(1);
  animation: interact-prompt-glow 2.4s ease-in-out infinite;
}

.game-interact-prompt:hover { background: rgba(30, 22, 10, 0.68); }
.game-interact-prompt.is-visible.is-busy { opacity: 0.55; animation: none; } /* 앉기 — 동작 묶음을 받는 중 */

/* ── 특별 NPC 말풍선(v5.24) — 머리 위 mono 1줄. left/top은 game.js가 투영 좌표로 매 프레임 쓴다(translate로 중앙·위 정렬).
   프롬프트와 같은 톤(어두운 반투명 + 앰버 테두리), 아래 꼬리는 ::after 삼각형. 1줄 유지: nowrap + 최대 폭에서 말줄임. */
.game-npc-bubble {
  position: fixed;
  left: 50%;
  top: 40%;
  z-index: 18;
  transform: translate(-50%, calc(-100% - 10px)) scale(0.96);
  /* 대사가 길면 여러 줄로 감싼다(2026-11-08 — 한 줄 고정 + 말줄임표라 NPC 대화가 잘렸다). 한국어는 어절 단위로 끊는다. */
  width: max-content;
  max-width: min(72vw, 340px);
  white-space: normal;
  word-break: keep-all;
  overflow-wrap: anywhere;
  text-align: center;
  font-family: var(--font-mono);
  font-size: 14px;
  letter-spacing: 0.03em;
  line-height: 1.4;
  color: var(--ink);
  background: rgba(20, 16, 8, 0.72);
  border: 1px solid rgba(232, 163, 61, 0.7);
  border-radius: 10px;
  padding: 8px 14px;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.25s ease, transform 0.25s ease;
}
.game-npc-bubble::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: -6px;
  width: 10px;
  height: 10px;
  background: rgba(20, 16, 8, 0.72);
  border-right: 1px solid rgba(232, 163, 61, 0.7);
  border-bottom: 1px solid rgba(232, 163, 61, 0.7);
  transform: translateX(-50%) rotate(45deg);
}
.game-npc-bubble.is-visible {
  opacity: 1;
  transform: translate(-50%, calc(-100% - 10px)) scale(1);
}
@media (max-width: 720px) {
  .game-npc-bubble { font-size: 12px; padding: 6px 11px; }
}

.game-interact-prompt-key {
  font-size: 13px;
  font-weight: 600;
  color: #14161a;
  background: #e8a33d;
  border-radius: 6px;
  padding: 3px 9px;
  line-height: 1.4;
}

/* ── 나가기 프롬프트(엘리베이터 전용 오버라이드) — 탑승 중 화면 정중앙에 떠
   있으면 몰입을 해쳐서, 우하단 구석(시점/소리 토글 위)에 작게 쌓는다.
   탑승 3초 뒤 game.js가 is-dimmed를 붙여 거의 투명해지고, 마우스를 움직이면
   다시 밝아진다 — E키 동작은 이 상태와 무관하게 항상 유효하다. */
.game-interact-prompt[data-elevator-exit-prompt] {
  top: auto;
  left: auto;
  right: 28px;
  bottom: 152px; /* 주인공 남/여 선택(108px) 위 */
  transform: translate(0, 8px) scale(0.96);
  font-size: 12px;
  gap: 8px;
  padding: 8px 16px;
}

.game-interact-prompt[data-elevator-exit-prompt].is-visible {
  transform: translate(0, 0) scale(1);
  /* 중앙 프롬프트용 글로우 펄스는 구석 상주 버튼에는 과하다 — 은은한 고정 그림자만 */
  animation: none;
  box-shadow: 0 0 14px rgba(232, 163, 61, 0.22);
}

.game-interact-prompt[data-elevator-exit-prompt] .game-interact-prompt-key {
  font-size: 11px;
  padding: 2px 7px;
}

.game-interact-prompt[data-elevator-exit-prompt].is-dimmed {
  opacity: 0.14;
}

.game-interact-prompt[data-elevator-exit-prompt].is-dimmed:hover {
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  .game-interact-prompt.is-visible { animation: none; }
}

@media (max-width: 640px) {
  .game-hud { left: 16px; bottom: 16px; }
  .game-progress { bottom: 12px; padding: 10px 14px 8px; }
  .game-progress-stop { font-size: 9px; }
  /* 좁은 화면에서는 진행 바가 거의 전체 폭을 차지하므로, 겹치지 않게
     우하단 버튼을 진행 바 위쪽으로 쌓는다 */
  .game-view-toggle { right: 16px; bottom: 84px; padding: 6px 12px; font-size: 11px; }
  .game-audio-toggle { right: 16px; bottom: 124px; padding: 6px 12px; font-size: 11px; }
  .game-lead-toggle { right: 16px; bottom: 164px; font-size: 11px; }
  .game-bgm { right: 16px; bottom: 204px; font-size: 11px; max-width: calc(100vw - 32px); }
  .game-audio-toggle .game-view-toggle-key { display: none; } /* 터치 기기엔 M 단축키가 없다 */
  .game-interact-prompt { font-size: 15px; padding: 12px 24px; gap: 10px; }
  /* 좁은 화면에서는 토글들이 진행 바 위로 쌓이므로(84/124) 그 위에 배치 */
  .game-interact-prompt[data-elevator-exit-prompt] { right: 16px; bottom: 208px; }
}

/* ── 조준점(크로스헤어) — Pointer Lock 중에는 커서가 없으므로 화면 중앙에
   항상 작은 원을 띄운다. 클릭 가능한 대상(작품/방명록 스탠드/엘리베이터) 위에
   있으면 링 형태로 확장되고, 카테고리색 등 --crosshair-glow로 물든다.
   레이캐스트는 항상 NDC(0,0) = "캔버스(#game-root)의 정중앙"을 쏜다. 예전엔
   이 크로스헤어가 top:50%/left:50%로 "브라우저 뷰포트 정중앙"에 떠 있었는데,
   #game-root가 상단 네비바(72px)만큼 아래로 밀려 있어(inset:0; top:72px)
   캔버스의 실제 중앙은 뷰포트 중앙보다 36px(네비 높이의 절반) 아래에 있다 —
   그 결과 화면상 크로스헤어와 실제 레이캐스트 지점이 항상 36px 어긋나
   있었다(카메라 pitch/구도와는 무관한 순수 DOM 레이아웃 버그). #game-root/
   .game-curtain과 완전히 같은 박스(inset:0; top:72px)를 쓰고 그 안에서
   flex로 중앙 정렬해, 네비 높이가 앞으로 바뀌어도(반응형 줄바꿈 등) 항상
   캔버스 중앙과 정확히 일치하게 한다. */
.game-crosshair {
  position: fixed;
  inset: 0;
  top: 72px;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 15;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.2s ease;
  --crosshair-color: rgba(241, 239, 231, 0.7);
  --crosshair-glow: rgba(241, 239, 231, 0.35);
}

.game-crosshair.is-visible { opacity: 1; }

.game-crosshair-dot {
  display: block;
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--crosshair-color);
  box-shadow: 0 0 4px 1px var(--crosshair-glow);
  transition: width 0.16s ease, height 0.16s ease, background 0.16s ease, border 0.16s ease, box-shadow 0.16s ease;
}

.game-crosshair.is-active .game-crosshair-dot {
  width: 22px;
  height: 22px;
  background: transparent;
  border: 1.5px solid var(--crosshair-color);
  box-shadow: 0 0 16px 3px var(--crosshair-glow);
}

/* ── 하단 진행 네비게이션 호버 글로우 — Pointer Lock을 해제한(ESC) 상태에서만
   실제 커서로 조작하는 UI이므로, 그 상태에서만 호버 글로우를 준다. ────── */
body:not(.is-pointer-locked) .game-progress:hover {
  border-color: var(--hairline-strong);
  box-shadow: 0 0 24px 2px rgba(241, 239, 231, 0.12);
}

body:not(.is-pointer-locked) .game-progress-stop:hover {
  text-shadow: 0 0 10px rgba(241, 239, 231, 0.55);
}

/* ══ 모바일 조작 체계 ═════════════════════════════════════════════════
   모든 규칙이 body.is-touch-controls 아래에만 들어간다 — game.js가 "손가락이
   주 입력장치"인 기기(pointer: coarse, 또는 좁은 화면 + 터치)에서만 이 클래스를
   붙이므로, PC(터치스크린 노트북 포함)는 위쪽 기존 규칙만 적용받아 조작/UI가
   그대로 유지된다. 화면 폭이 아니라 입력 방식으로 갈라야 하는 이유: 좁게 줄인
   데스크톱 브라우저 창에 조이스틱이 뜨면 안 되고, 넓은 태블릿에는 떠야 한다.
   ═══════════════════════════════════════════════════════════════════ */

/* 조이스틱/시선 드래그 중에 페이지가 스크롤되거나 당겨서 새로고침이 걸리면
   조작이 통째로 끊긴다. 캔버스는 touch-action:none으로 브라우저 기본 제스처
   (스크롤/핀치줌/더블탭줌)를 모두 넘겨받고, overscroll-behavior:none으로
   고무줄 스크롤과 pull-to-refresh를 막는다. */
body.game-page {
  overscroll-behavior: none;
}

body.is-touch-controls #game-root {
  touch-action: none;
}

/* PC 조작 안내는 모바일에서 전부 감춘다 — 첫 진입 온보딩 한 장이 그 역할을
   대신한다. 크로스헤어와 Pointer Lock 안내는 터치에 개념 자체가 없다. */
body.is-touch-controls .game-hud,
body.is-touch-controls .game-pointerlock-hint,
body.is-touch-controls .game-crosshair {
  display: none;
}

/* 키 배지(V / M / E)는 물리 키보드가 없으면 의미가 없다 */
body.is-touch-controls .game-view-toggle-key,
body.is-touch-controls .game-interact-prompt-key {
  display: none;
}

/* ── 가상 조이스틱 ──────────────────────────────────────────────────── */
.game-joystick {
  position: fixed;
  left: 22px;
  bottom: 104px; /* 컴팩트 진행 바(아래) 위로 띄운다 */
  z-index: 12;
  width: 132px;
  height: 132px;
  display: none;
  pointer-events: none; /* 터치는 캔버스가 받는다 — game.js가 좌표로 판정 */
}

body.is-touch-controls .game-joystick {
  display: block;
}

/* 오버레이 패널(작품 상세/방명록 등)이 열려 있는 동안은 이동 자체가 멈추므로
   조이스틱도 함께 숨긴다 — 패널 위에 떠 있으면 조작 가능한 것처럼 오해된다. */
body.is-touch-controls.overlay-open .game-joystick {
  display: none;
}

/* 조작 중에는 손가락을 그대로 따라가야 하고(지연 0), 손을 떼면 부드럽게 집으로
   돌아가야 한다. 그래서 duration만 --stick-ease로 바꿔 끼운다.
   transition 단축속성 자체를 바꾸면 안 된다: is-active가 transition을
   `background`만으로 덮으면 조작 중에는 transform이 "전환 대상 속성"에서
   빠지는데, 손을 떼는 순간 클래스 제거와 transform 변경이 같은 스타일 계산에
   묶여 들어가면서 브라우저가 전환을 시작하지 못하고 스틱이 밀린 자리에 그대로
   얼어붙는 버그가 있었다(inline style은 0으로 돌아갔는데 computed는 그대로).
   transition-property를 항상 고정해 두면 이 경계 케이스가 사라진다. */
.game-joystick-base,
.game-joystick-stick {
  --stick-ease: 0.22s;
}

.game-joystick.is-active .game-joystick-base,
.game-joystick.is-active .game-joystick-stick {
  --stick-ease: 0s;
}

.game-joystick-base {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 50%, rgba(241, 239, 231, 0.07), rgba(11, 12, 16, 0.42) 72%);
  border: 1px solid rgba(241, 239, 231, 0.22);
  box-shadow: inset 0 0 22px rgba(0, 0, 0, 0.35);
  backdrop-filter: blur(3px);
  opacity: 0.5;
  transition: transform var(--stick-ease) cubic-bezier(0.22, 1, 0.36, 1), opacity 0.18s ease;
}

.game-joystick.is-active .game-joystick-base {
  opacity: 0.92;
}

.game-joystick-stick {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 58px;
  height: 58px;
  margin: -29px 0 0 -29px;
  border-radius: 50%;
  background: rgba(241, 239, 231, 0.5);
  border: 1px solid rgba(241, 239, 231, 0.55);
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.45);
  transition: transform var(--stick-ease) cubic-bezier(0.22, 1, 0.36, 1), background 0.12s ease;
}

.game-joystick.is-active .game-joystick-stick {
  background: rgba(241, 239, 231, 0.78);
}

@media (prefers-reduced-motion: reduce) {
  .game-joystick-base,
  .game-joystick-stick { --stick-ease: 0s; }
}

/* ── 시점 전환 / 소리 토글 — 아이콘 + 텍스트, 키 배지만 제거 ──────────
   키 배지(V/M)는 위쪽 규칙에서 이미 숨겼다. 라벨 텍스트는 남긴다 — 아이콘만
   두면 눈 모양이 "1인칭/3인칭"을 뜻하는지, 스피커가 어느 쪽으로 토글되는지
   알 수 없어 처음 온 사람이 누르기를 망설인다. */
body.is-touch-controls .game-view-toggle,
body.is-touch-controls .game-audio-toggle {
  min-height: 40px; /* 글자는 작아도 손가락이 닿을 높이는 확보 */
  padding: 8px 14px;
  gap: 7px;
  font-size: 11px;
  /* 3D 화면은 벽면 대형 텍스트처럼 밝고 복잡한 배경이 그대로 뒤에 깔린다 —
     데스크톱(0.55)보다 짙게 깔고 블러를 넣어야 글자가 읽힌다. */
  background: rgba(11, 12, 16, 0.74);
  backdrop-filter: blur(6px);
  color: var(--ink);
}

body.is-touch-controls .game-view-toggle { right: 14px; bottom: 104px; }
body.is-touch-controls .game-audio-toggle { right: 14px; bottom: 154px; }
body.is-touch-controls .game-lead-toggle { right: 14px; bottom: 204px; min-height: 40px; background: rgba(11, 12, 16, 0.74); backdrop-filter: blur(6px); color: var(--ink); }
body.is-touch-controls .game-interact-prompt[data-elevator-exit-prompt] { right: 14px; bottom: 252px; }

body.is-touch-controls .game-view-toggle-icon,
body.is-touch-controls .game-audio-icon-on,
body.is-touch-controls .game-audio-icon-off {
  width: 20px;
  height: 20px;
}

/* ── 컴팩트 진행 바 — 높이를 줄이고 시간/날씨 라벨을 한 줄로 접는다 ────── */
body.is-touch-controls .game-progress {
  bottom: 10px;
  width: calc(100vw - 20px);
  padding: 7px 12px 6px;
  border-radius: 12px;
}

body.is-touch-controls .game-time-of-day {
  font-size: 8px;
  letter-spacing: 0.06em;
  margin: 0 0 5px;
  /* 시간대 + 날씨가 길어지면 줄바꿈으로 진행 바가 두 배 높아진다 — 한 줄로 잘라둔다 */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  opacity: 0.7;
}

body.is-touch-controls .game-progress-track {
  height: 2px;
  margin-bottom: 6px;
}

body.is-touch-controls .game-progress-dot {
  width: 8px;
  height: 8px;
  margin: -4px 0 0 -4px;
}

body.is-touch-controls .game-progress-stop {
  font-size: 9px;
  padding: 3px 2px; /* 글자는 작아도 탭 영역은 확보 */
}

/* ── 첫 진입 온보딩 ─────────────────────────────────────────────────── */
.game-onboarding {
  position: fixed;
  inset: 0;
  z-index: 300;
  display: none;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: rgba(8, 9, 12, 0.82);
  backdrop-filter: blur(6px);
  opacity: 0;
  transition: opacity 0.3s ease;
}

.game-onboarding.is-visible {
  display: flex;
  opacity: 1;
}

.game-onboarding-card {
  width: min(340px, 100%);
  padding: 26px 24px 18px;
  background: rgba(16, 18, 23, 0.92);
  border: 1px solid var(--hairline-strong);
  border-radius: 18px;
  text-align: left;
}

.game-onboarding-title {
  margin: 0 0 20px;
  font-family: var(--font-mono);
  font-size: 13px;
  letter-spacing: 0.08em;
  text-align: center;
  color: var(--ink);
}

.game-onboarding-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.game-onboarding-row {
  display: flex;
  align-items: center;
  gap: 14px;
}

.game-onboarding-icon {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 46px;
  height: 46px;
  border-radius: 12px;
  background: rgba(241, 239, 231, 0.06);
  border: 1px solid var(--hairline);
  color: var(--ink);
}

.game-onboarding-text {
  font-family: var(--font-mono);
  font-size: 12.5px;
  letter-spacing: 0.02em;
  line-height: 1.5;
  color: var(--ink);
}

/* 320px급 좁은 폰에서는 "…으로 이동"의 마지막 두 글자만 다음 줄로 떨어져
   보기 나쁘다. 글자와 여백을 조금 줄여 한 줄에 들어가게 한다. */
@media (max-width: 360px) {
  .game-onboarding-card { padding: 22px 16px 16px; }
  .game-onboarding-row { gap: 11px; }
  .game-onboarding-icon { width: 40px; height: 40px; }
  .game-onboarding-text { font-size: 11px; letter-spacing: 0; }
}

.game-onboarding-dismiss {
  margin: 22px 0 0;
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.06em;
  text-align: center;
  color: var(--ink-muted);
}

@media (prefers-reduced-motion: reduce) {
  .game-onboarding { transition: none; }
}

/* ── 가로 모드 안내 게이트 (v5.12) ──────────────────────────────────────
   세로에서 전시 진입을 막고 회전을 안내한다. 실기기에서 "탭이 안 먹는다"는
   보고의 원인이 조상 스택 문맥/내비 겹침이었으므로:
     · z-index 12000 (내비 100 · 온보딩 300 · 로딩 500 · 토스트 9999 위)
     · 스크립트가 document.body 직속으로 옮겨 붙인다(조상 transform 무력화)
     · 해제 시 opacity뿐 아니라 visibility/pointer-events까지 확실히 끈다
       — 투명한 채로 남아 탭을 먹는 유령 오버레이가 되지 않도록
   높이는 visualViewport 실측값을 인라인으로 넣어 iOS 주소창 애니메이션 중에도
   화면을 정확히 덮는다(100vh는 그 구간에서 어긋난다). */
.game-orientation-gate {
  position: fixed;
  inset: 0;
  z-index: 12000;
  display: none;
  align-items: center;
  justify-content: center;
  padding: 24px calc(24px + env(safe-area-inset-right)) calc(24px + env(safe-area-inset-bottom)) calc(24px + env(safe-area-inset-left));
  background:
    radial-gradient(120% 90% at 50% 12%, rgba(var(--ai-rgb), 0.16), transparent 62%),
    radial-gradient(120% 90% at 50% 100%, rgba(var(--motion-rgb), 0.13), transparent 60%),
    rgba(8, 9, 12, 0.97);
  backdrop-filter: blur(14px);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.32s ease;
  -webkit-tap-highlight-color: transparent;
}

.game-orientation-gate.is-blocking {
  display: flex;
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
}

.game-orientation-gate-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  max-width: 420px;
  text-align: center;
  color: var(--ink);
}

.game-orientation-phone { color: var(--ai); }

.game-orientation-phone-body {
  transform-origin: 70px 58px;
  animation: game-orientation-rotate 2.8s cubic-bezier(0.65, 0, 0.35, 1) infinite;
}

.game-orientation-arc {
  stroke: var(--ai);
  opacity: 0.5;
}

@keyframes game-orientation-rotate {
  0%, 22% { transform: rotate(0deg); }
  48%, 78% { transform: rotate(-90deg); }
  100% { transform: rotate(0deg); }
}

.game-orientation-gate-title {
  margin: 6px 0 0;
  font-size: 18px;
  font-weight: 600;
  letter-spacing: -0.01em;
}

.game-orientation-gate-sub {
  margin: 0;
  color: var(--ink-muted);
  font-size: 13px;
  line-height: 1.6;
}

.game-orientation-gate-progress {
  margin: 2px 0 0;
  min-height: 15px;
  color: rgba(255, 255, 255, 0.42);
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.04em;
}

/* v5.13: 회전 잠금 해제 안내 — 실기기에서 잠금이 켜져 있으면 웹은 강제 회전을
   할 수 없으므로, 안내 문구만으로 끝내지 않고 OS별 해제 경로를 아이콘과 함께 준다. */
.game-orientation-lockhelp {
  margin: 4px 0 0;
  padding: 10px 14px;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 8px;
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid var(--hairline);
  border-radius: 12px;
  text-align: left;
}

.game-orientation-lockhelp li {
  display: flex;
  align-items: center;
  gap: 9px;
  color: var(--ink-muted);
  font-size: 12px;
  line-height: 1.5;
}

.game-orientation-lockhelp svg { flex: none; color: var(--ai); }
.game-orientation-lockhelp b { color: var(--ink); font-weight: 600; }

.game-orientation-gate-foot {
  margin: 6px 0 0;
  color: rgba(255, 255, 255, 0.38);
  font-size: 11px;
  line-height: 1.5;
}

/* 안전장치 버튼 — 어떤 경우에도 눌러서 빠져나올 수 있어야 한다.
   탭 타깃을 44px 이상으로 잡고, 게이트 안에서 가장 위에 오도록 z-index를 준다. */
.game-orientation-gate-continue {
  position: relative;
  z-index: 1;
  margin-top: 10px;
  min-height: 46px;
  padding: 12px 26px;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid var(--hairline-strong);
  border-radius: 100px;
  color: var(--ink);
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.04em;
  cursor: pointer;
  transition: background 0.2s ease, border-color 0.2s ease;
}

.game-orientation-gate-continue:hover,
.game-orientation-gate-continue:active {
  background: rgba(255, 255, 255, 0.12);
  border-color: rgba(255, 255, 255, 0.34);
}

@media (prefers-reduced-motion: reduce) {
  .game-orientation-gate { transition: none; }
  .game-orientation-phone-body { animation: none; }
}

/* ── 세로 모드 권장 안내 — 강제하지 않고 상단에 잠깐 띄운다 ───────────── */
/* ── 가로 권장 안내 배지 (v5.11) ────────────────────────────────────────
   방향 강제(전체 화면 게이트)는 실기기에서 진입 자체를 막는 사고가 반복돼
   폐기했다(blueprint §35). 세로에서도 관람은 그대로 되고, 상단에 작은 배지로
   권장만 한다 — 탭하면 사라진다. 화면을 가리지 않도록 z-index는 HUD 수준으로
   낮게, 폭도 최소로 유지한다. */
.game-orientation-hint {
  position: fixed;
  /* top은 orientation-gate.js가 실제 내비 높이를 재서 인라인으로 넣는다
     (모바일 세로에서 내비 링크가 줄바꿈돼 72px보다 커지기 때문) */
  top: calc(80px + env(safe-area-inset-top));
  left: 50%;
  z-index: 30;
  transform: translate(-50%, -6px);
  display: none;
  align-items: center;
  gap: 7px;
  padding: 7px 14px;
  background: rgba(11, 12, 16, 0.82);
  border: 1px solid var(--hairline-strong);
  border-radius: 100px;
  backdrop-filter: blur(6px);
  color: var(--ink);
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.03em;
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.3s ease, transform 0.3s ease;
}

.game-orientation-hint.is-visible {
  display: flex;
  opacity: 1;
  transform: translate(-50%, 0);
}

.game-orientation-hint svg { flex: none; color: var(--ai); }

@media (prefers-reduced-motion: reduce) {
  .game-orientation-hint { transition: none; }
}

/* ── 가로 모드 폰 최적화 (v5.9) ─────────────────────────────────────────
   노치/홈 인디케이터가 있는 기기에서 조이스틱·버튼이 잘리거나 가려지지 않도록
   모든 고정 UI를 세이프에어리어 안쪽으로 민다. 오른쪽 버튼 두 개는 우하단에
   세로로 쌓고, 조이스틱은 좌하단에 둔다(엄지 위치 그대로). */
body.is-touch-controls .game-joystick {
  left: calc(16px + env(safe-area-inset-left));
  bottom: calc(74px + env(safe-area-inset-bottom));
}

body.is-touch-controls .game-view-toggle {
  right: calc(16px + env(safe-area-inset-right));
  bottom: calc(70px + env(safe-area-inset-bottom));
}

body.is-touch-controls .game-audio-toggle {
  right: calc(16px + env(safe-area-inset-right));
  bottom: calc(118px + env(safe-area-inset-bottom)); /* 시점 버튼 위로 세로 스택 */
}

body.is-touch-controls .game-lead-toggle {
  right: calc(16px + env(safe-area-inset-right));
  bottom: calc(166px + env(safe-area-inset-bottom)); /* 소리 버튼 위 */
}

body.is-touch-controls .game-progress {
  bottom: calc(8px + env(safe-area-inset-bottom));
  left: 50%;
  width: min(560px, calc(100vw - 32px - env(safe-area-inset-left) - env(safe-area-inset-right)));
}

body.is-touch-controls .game-hud {
  left: calc(28px + env(safe-area-inset-left));
  bottom: calc(24px + env(safe-area-inset-bottom));
}

body.is-touch-controls .game-exit-prompt,
body.is-touch-controls .game-interact-prompt {
  margin-bottom: env(safe-area-inset-bottom);
}

/* ── 세로 관람 최적화 (v5.13) ───────────────────────────────────────────
   회전 잠금이 켜진 기기에서는 "세로로 계속 보기"로 들어오게 되므로, 세로에서도
   관람이 되도록 UI를 다시 짠다. 세로 화면은 폭이 좁고 세로로 길어서
     · 하단 진행 바(폭 560px 기준)와 조이스틱·버튼이 서로 겹치고
     · 각 요소가 차지하는 면적 비율이 커져 3D 화면을 크게 가린다.
   is-portrait-view는 orientation-gate.js가 "실측 뷰포트 세로 + 모바일 조작
   체계"일 때만 붙인다(방향 API가 아니라 실측 비율 — §36 참고). */
body.is-portrait-view .game-progress {
  bottom: calc(6px + env(safe-area-inset-bottom));
  width: calc(100vw - 16px);
  padding: 8px 10px 6px;
  border-radius: 12px;
}

body.is-portrait-view .game-progress-labels { gap: 0; }

body.is-portrait-view .game-progress-stop {
  font-size: 9.5px;
  padding: 2px 1px;
  letter-spacing: 0;
}

body.is-portrait-view .game-time-of-day { font-size: 9.5px; }

/* 조이스틱은 진행 바 위로 올리고 한 단계 작게 — 엄지 도달 범위는 유지 */
body.is-portrait-view.is-touch-controls .game-joystick {
  width: 108px;
  height: 108px;
  left: calc(10px + env(safe-area-inset-left));
  bottom: calc(78px + env(safe-area-inset-bottom));
}

/* 우하단 버튼 두 개 — 좁은 폭에서 라벨까지 다 넣으면 조이스틱과 만나므로
   아이콘 중심의 컴팩트 pill로 줄인다. */
body.is-portrait-view.is-touch-controls .game-view-toggle,
body.is-portrait-view.is-touch-controls .game-audio-toggle {
  gap: 5px;
  padding: 7px 11px;
  font-size: 10.5px;
  right: calc(10px + env(safe-area-inset-right));
}

body.is-portrait-view.is-touch-controls .game-view-toggle {
  bottom: calc(78px + env(safe-area-inset-bottom));
}

body.is-portrait-view.is-touch-controls .game-audio-toggle {
  bottom: calc(122px + env(safe-area-inset-bottom));
}

body.is-portrait-view.is-touch-controls .game-lead-toggle {
  right: calc(10px + env(safe-area-inset-right));
  bottom: calc(166px + env(safe-area-inset-bottom));
  font-size: 10.5px;
}

/* 상단 안내 배지도 한 줄로 짧게 */
body.is-portrait-view .game-orientation-hint {
  font-size: 10px;
  padding: 6px 11px;
}
