/* ============================================================================
 * 캣포 디펜스 — UI 디자인 시스템
 *
 * 방향: "웹 폼"이 아니라 "모바일 게임"으로 보이게 한다.
 *  · 표면(surface)에 위계를 준다 — 평평한 단색 대신 위에서 빛이 오는 그라디언트 + 안쪽 하이라이트
 *  · 버튼은 눌리는 물체다 — 아래 그림자(0 Npx 0)가 눌릴 때 사라지며 실제로 내려앉는다
 *  · 숫자는 전부 tabular-nums — 값이 바뀔 때 폭이 흔들리지 않는다
 *  · 아이콘은 이모지가 아니라 인라인 SVG — 기기마다 모양/크기가 달라지지 않는다
 * 폰트는 시스템 스택만 쓴다(오프라인에서 CDN 실패가 없도록).
 * ==========================================================================*/

:root {
  /* ── 표면: 아래로 갈수록 어둡다 ── */
  --bg-0:      #0a0d14;   /* 가장 뒤 */
  --bg-1:      #111621;
  --surf-1:    #19202e;   /* 패널 */
  --surf-2:    #212a3b;   /* 패널 위 요소 */
  --surf-3:    #2b364b;   /* 그 위 */
  --line:      #33405a;
  --line-soft: rgba(255,255,255,.07);

  /* 맵 선택과 챕터 선택이 같은 배경을 쓴다. 두 규칙이 500줄 떨어져 있어서
   * 한쪽만 고치는 사고가 나기 쉬우므로 여기 한 곳에 둔다.
   * 카드가 불투명해서 배경은 좌우 여백·카드 틈·목록 아래로만 드러난다.
   * 그래서 스크림을 진하게 눌러도 잃을 게 없다. 맨 뒤 리니어는 그림이
   * 없을 때(오프라인 첫 방문 등) 떨어질 자리다. */
  --bg-select:
    linear-gradient(180deg, rgba(10,13,20,.62), rgba(10,13,20,.80)),
    url(../art/bg-select.jpg) center / cover no-repeat,
    linear-gradient(180deg, var(--bg-1), var(--bg-0));

  /* ── 글자 ── */
  --text:      #eef3fb;
  --text-dim:  #9dabc2;
  --text-faint:#6b7a93;

  /* ── 액센트 ── */
  --gold:      #ffc94d;
  --gold-deep: #d99a1c;
  --mint:      #4fd6b4;
  --mint-deep: #1d8a72;
  --mint-dark: #14614f;
  --danger:    #ff6b6b;
  --danger-deep:#a32f38;
  --ok:        #7fe08a;
  --catnip:    #8fe3a8;
  --violet:    #a98bff;

  /* ── 형태 ── */
  --r-sm: 10px;
  --r-md: 14px;
  --r-lg: 20px;
  --r-pill: 999px;
  --tap: 46px;

  /* ── 그림자 ── */
  --sh-1: 0 1px 2px rgba(0,0,0,.4);
  --sh-2: 0 4px 14px rgba(0,0,0,.45);
  --sh-3: 0 12px 34px rgba(0,0,0,.55);
  --lift: inset 0 1px 0 rgba(255,255,255,.10);
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }

/* ★ hidden 속성이 실제로 먹게 만든다.
   브라우저 기본 스타일의 [hidden]{display:none} 은 '작성자 스타일'보다 우선순위가 낮다.
   그래서 .tower-panel{display:flex} 같은 규칙이 있으면 hidden=true 를 걸어도 요소가
   그대로 남아 화면 아래를 덮고 탭을 삼킨다 — 타워를 한 번 눌렀다 닫으면 그 아래 지도가
   먹통이 되던 원인이었다. 개별 규칙마다 챙기지 말고 여기서 한 번에 못 박는다. */
[hidden] { display: none !important; }

html, body {
  margin: 0; padding: 0;
  height: 100%; overflow: hidden;
  background: var(--bg-0); color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Apple SD Gothic Neo",
               "Malgun Gothic", "Noto Sans KR", system-ui, sans-serif;
  font-size: 15px; line-height: 1.45;
  overscroll-behavior: none;
  /* manipulation = 더블탭 확대만 끄고 스크롤·스와이프는 남긴다.
     none 으로 두면 touch-action 이 조상까지 교차 적용되므로, 폰에서 설정 시트 스크롤과
     맵 목록 세로 스크롤, 상점 가로 스와이프가 통째로 막힌다. 지도만 #canvas 에서 none 을 쓴다. */
  touch-action: manipulation;
  user-select: none; -webkit-user-select: none;
}

#app { height: 100%; display: flex; flex-direction: column; }

.screen {
  position: absolute; inset: 0;
  display: flex; flex-direction: column;
  padding: env(safe-area-inset-top) env(safe-area-inset-right)
           env(safe-area-inset-bottom) env(safe-area-inset-left);
}
.screen[hidden] { display: none; }
.spacer { flex: 1; }
.num { font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1; }

/* SVG 아이콘 — 글자 크기를 따라간다 */
.i { width: 1em; height: 1em; flex: none; display: block; }
#icon-defs { position: absolute; width: 0; height: 0; overflow: hidden; }

/* ═══════════════════ 버튼 ═══════════════════
   눌리는 물체처럼 — 아래 그림자가 두께이고, 누르면 그만큼 내려앉는다. */
.btn {
  position: relative;
  min-height: var(--tap); padding: 0 20px;
  border: none; border-radius: var(--r-md);
  font: inherit; font-weight: 700; font-size: 15px; color: var(--text);
  background: linear-gradient(180deg, var(--surf-3), var(--surf-2));
  box-shadow: 0 3px 0 #131a26, var(--sh-1), var(--lift);
  cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  transition: box-shadow .06s ease, transform .06s ease, filter .15s ease;
}
.btn:active { transform: translateY(3px); box-shadow: 0 0 0 #131a26, var(--lift); }

.btn.primary {
  background: linear-gradient(180deg, #48c9a8, var(--mint-deep));
  color: #04231d; text-shadow: 0 1px 0 rgba(255,255,255,.25);
  box-shadow: 0 3px 0 var(--mint-dark), 0 4px 14px rgba(31,190,155,.28), var(--lift);
}
.btn.primary:active { box-shadow: 0 0 0 var(--mint-dark), var(--lift); }

.btn.gold {
  background: linear-gradient(180deg, #ffd875, var(--gold-deep));
  color: #3a2603; text-shadow: 0 1px 0 rgba(255,255,255,.3);
  box-shadow: 0 3px 0 #96690d, 0 4px 14px rgba(217,154,28,.25), var(--lift);
}
.btn.gold:active { box-shadow: 0 0 0 #96690d, var(--lift); }

.btn.danger {
  background: linear-gradient(180deg, #e15c66, var(--danger-deep));
  color: #fff0f0; box-shadow: 0 3px 0 #6b1f26, var(--sh-1), var(--lift);
}
.btn.danger:active { box-shadow: 0 0 0 #6b1f26, var(--lift); }

.btn.ghost {
  background: rgba(255,255,255,.035); border: 1px solid var(--line);
  box-shadow: none; color: var(--text-dim); font-weight: 600;
}
.btn.ghost:active { transform: scale(.97); background: rgba(255,255,255,.08); }

.btn.wide { width: 100%; }
.btn:disabled { opacity: .38; box-shadow: none; transform: none; cursor: default; filter: grayscale(.4); }

.icon-btn {
  width: var(--tap); height: var(--tap);
  display: inline-flex; align-items: center; justify-content: center;
  border: none; background: transparent; color: var(--text-dim);
  font-size: 20px; cursor: pointer; border-radius: var(--r-sm);
}
.icon-btn .i { width: 20px; height: 20px; }
.icon-btn:active { background: rgba(255,255,255,.09); color: var(--text); }

.chip {
  min-width: 48px; height: 36px; padding: 0 12px;
  display: inline-flex; align-items: center; justify-content: center; gap: 5px;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: linear-gradient(180deg, var(--surf-2), var(--surf-1));
  color: var(--text); box-shadow: var(--lift);
  font: inherit; font-weight: 700; font-size: 13px; cursor: pointer;
  font-variant-numeric: tabular-nums;
}
.chip .i { width: 15px; height: 15px; }
.chip:active { transform: scale(.94); }
.chip.on { border-color: var(--gold); color: var(--gold); background: rgba(255,201,77,.12); }

/* ═══════════════════ 타이틀 ═══════════════════ */
/* 사진을 맨 뒤에 깔고 그 위에 스크림 한 겹.
 *
 * 위쪽 청록 라디얼은 .16 이었다. 그라디언트만 있을 때는 브랜드색이었는데
 * 사진의 푸른 밤하늘 위에 얹히니 초록빛이 돌아 .07 로 낮췄다. 아래 금빛은
 * 사진 속 가로등과 색이 맞아서 그대로 뒀다.
 *
 * 스크림 세기는 눈대중이 아니라 원본을 재서 정했다 — 로고 자리(y .10~.28)
 * 평균밝기 62, 버튼 자리(y .46~.80) 44. 여기에 .45~.68 을 곱하면 31·14 로
 * 떨어져 흰 글씨 대비가 난다. 버튼 쪽을 더 진하게 눌러야 해서 세로 그라디언트다. */
#screen-title {
  align-items: center; justify-content: center; text-align: center;
  background:
    radial-gradient(120% 70% at 50% 0%,   rgba(79,214,180,.07), transparent 62%),
    radial-gradient(90% 55% at 50% 100%,  rgba(255,201,77,.12), transparent 60%),
    linear-gradient(180deg, rgba(6,9,14,.42), rgba(6,9,14,.66)),
    url(../art/bg-title.jpg) center / cover no-repeat,
    linear-gradient(180deg, var(--bg-1), var(--bg-0) 70%);
}
/* 부팅 실패 표시 — 눈에 안 띄면 없는 것과 같다 */
.boot-error {
  margin: 14px auto 0; max-width: 360px; padding: 12px 14px;
  border: 1px solid var(--danger); border-radius: var(--r-md);
  background: rgba(163,47,56,.22); color: #ffd8d8;
  font: inherit; font-size: 13px; text-align: left;
  white-space: pre-wrap; word-break: break-word;
}

/* 배경에 천천히 떠다니는 발자국 */
#screen-title::before {
  content: ""; position: absolute; inset: -10%;
  background-image: radial-gradient(circle at 20% 30%, rgba(255,255,255,.045) 0 3px, transparent 4px),
                    radial-gradient(circle at 72% 62%, rgba(255,255,255,.04) 0 4px, transparent 5px),
                    radial-gradient(circle at 44% 84%, rgba(255,255,255,.03) 0 3px, transparent 4px);
  background-size: 240px 240px, 320px 320px, 180px 180px;
  animation: drift 40s linear infinite; pointer-events: none;
}
@keyframes drift { to { transform: translate3d(-240px, -180px, 0); } }

.title-wrap { position: relative; padding: 24px; max-width: 400px; width: 100%; }
.logo-badge {
  width: 112px; height: 112px; margin: 0 auto 14px;
  display: grid; place-items: center; border-radius: 30px;
  background: linear-gradient(180deg, #2a3346, #171e2b);
  box-shadow: 0 14px 40px rgba(0,0,0,.6), inset 0 2px 0 rgba(255,255,255,.12),
              0 0 0 1px rgba(255,201,77,.18);
  animation: bob 3.4s ease-in-out infinite;
}
.logo-badge img { width: 76px; height: 76px; display: block; }
@keyframes bob { 0%,100% { transform: translateY(0) rotate(-4deg); } 50% { transform: translateY(-9px) rotate(4deg); } }

.title {
  margin: 0 0 6px; font-size: 42px; font-weight: 800; letter-spacing: -1px;
  background: linear-gradient(180deg, #fff3cf 10%, var(--gold) 60%, var(--gold-deep));
  -webkit-background-clip: text; background-clip: text; color: transparent;
  filter: drop-shadow(0 3px 10px rgba(255,201,77,.25));
}
.tagline { margin: 0 0 26px; color: var(--text-dim); font-size: 14px; }
.title-buttons { display: flex; flex-direction: column; gap: 12px; }
.title-buttons .btn.primary { min-height: 56px; font-size: 17px; }
/* 보조 메뉴는 쌓지 않고 한 줄로 — 4개가 세로로 쌓이면 설정 화면처럼 보인다 */
.title-sub { display: flex; gap: 10px; }
.title-sub .btn { flex: 1; flex-direction: column; gap: 3px; min-height: 62px; padding: 0 6px; font-size: 12px; }
.title-sub .btn .i { width: 21px; height: 21px; }
.version { margin-top: 22px; font-size: 11.5px; color: var(--text-faint); }

/* ═══════════════════ 상단 바 ═══════════════════ */
.topbar {
  display: flex; align-items: center; gap: 4px;
  padding: 6px 8px; background: var(--surf-1);
  border-bottom: 1px solid var(--line-soft);
}
.topbar h2 { margin: 0; font-size: 17px; font-weight: 700; }

/* ═══════════════════ 맵 선택 ═══════════════════ */
#screen-maps { background: var(--bg-select); }
.map-list { flex: 1; overflow-y: auto; padding: 14px; display: flex; flex-direction: column; gap: 12px; }
.map-card, .weekly-card {
  position: relative; display: flex; align-items: center; gap: 14px;
  padding: 13px; border: 1px solid var(--line-soft); border-radius: var(--r-lg);
  background: linear-gradient(180deg, var(--surf-2), var(--surf-1));
  box-shadow: var(--sh-2), var(--lift);
  text-align: left; color: var(--text); font: inherit; cursor: pointer; width: 100%;
  transition: transform .08s ease;
}
.map-card:active, .weekly-card:active { transform: scale(.985); }
.map-card[disabled] { opacity: .5; cursor: default; filter: grayscale(.6); }
.map-thumb { width: 68px; height: 68px; border-radius: 12px; flex: none; box-shadow: var(--sh-1); }
.map-card h3, .weekly-card h3 { margin: 0 0 3px; font-size: 16.5px; font-weight: 700; }
.map-card p, .weekly-card p { margin: 0; font-size: 12.5px; color: var(--text-dim); }
.map-meta {
  margin-top: 6px; font-size: 11.5px; color: var(--gold); font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.map-meta.locked { color: var(--text-faint); font-weight: 600; }
.map-body { flex: 1; min-width: 0; }
.lock { color: var(--text-faint); }
.lock .i { width: 22px; height: 22px; }

/* ═══════════════════ HUD ═══════════════════ */
.hud {
  display: flex; align-items: center; gap: 7px;
  padding: 7px 10px;
  background: linear-gradient(180deg, var(--surf-1), #141a26);
  border-bottom: 1px solid var(--line-soft);
  box-shadow: 0 2px 10px rgba(0,0,0,.35);
}
.hud-stat {
  display: flex; align-items: center; gap: 5px;
  padding: 4px 10px 4px 8px; border-radius: var(--r-pill);
  background: rgba(0,0,0,.28); box-shadow: inset 0 1px 0 rgba(255,255,255,.05);
  font-weight: 800; font-size: 14.5px; font-variant-numeric: tabular-nums;
  line-height: 1.3;
}
.hud-stat .i { width: 15px; height: 15px; }
.hud-stat.lives .i { color: var(--danger); }
.hud-stat.gold  .i { color: var(--gold); }
.hud-stat.wave  .i { color: var(--text-dim); }
.hud-stat.wave b { font-size: 13.5px; font-weight: 700; }
.hud-stat.catnip .i { color: var(--catnip); }
.hud-stat.catnip b { color: var(--catnip); }
.hud-stat.catnip { border: 1px solid rgba(143,227,168,.28); cursor: pointer; }
.hud-stat.catnip:active { transform: scale(.95); }

#hud-lives.low { color: var(--danger); }

/* 밀크 마나 — 캡슐 뒤가 차오른다. 숫자만 있으면 최대치 대비 얼마인지 감이 안 온다. */
.hud-stat.mana { position: relative; overflow: hidden; border: 1px solid rgba(159,220,255,.22); }
.hud-stat.mana .fill {
  position: absolute; left: 0; top: 0; bottom: 0; width: 0;
  background: linear-gradient(90deg, rgba(90,168,224,.30), rgba(159,220,255,.42));
  transition: width .18s linear;
}
.hud-stat.mana .i, .hud-stat.mana b { position: relative; z-index: 1; }
.hud-stat.mana .i { color: #cfeaff; }
.hud-stat.mana b { color: #e2f5ff; }
/* 가득 차면 더 모아도 버려진다 — 지금 쓰라는 신호 */
.hud-stat.mana.full {
  border-color: rgba(159,220,255,.75);
  box-shadow: 0 0 12px rgba(159,220,255,.35);
}
/* 값이 오르내릴 때 눈에 띄게 — 안 그러면 골드가 언제 들어왔는지 모른다 */
.hud-stat.bump { animation: bump .34s ease; }
@keyframes bump { 30% { transform: scale(1.22); } }
.hud-stat.hurt { animation: hurt .4s ease; }
@keyframes hurt {
  0%,100% { transform: translateX(0); }
  20% { transform: translateX(-4px); } 45% { transform: translateX(4px); } 70% { transform: translateX(-2px); }
}

/* 웨이브 진행 바 */
.wavebar {
  position: relative; height: 20px;
  background: #0c1018; border-bottom: 1px solid var(--line-soft);
  display: flex; align-items: center; overflow: hidden;
}
.wavebar i {
  position: absolute; left: 0; top: 0; bottom: 0; width: 0;
  background: linear-gradient(90deg, var(--mint-deep), var(--mint));
  box-shadow: 0 0 14px rgba(79,214,180,.5);
  transition: width .2s linear;
}
.wavebar b {
  position: relative; z-index: 1; width: 100%; text-align: center;
  font-size: 10.5px; font-weight: 800; letter-spacing: .10em;
  color: var(--text-dim); text-shadow: 0 1px 3px #000;
  font-variant-numeric: tabular-nums;
}
.wavebar.danger i { background: linear-gradient(90deg, #b8323c, var(--danger)); box-shadow: 0 0 14px rgba(255,107,107,.5); }

/* .shop 이 아래 안전영역을 자기 패딩에 이미 넣는다(.shop 규칙 참고). .screen 이
 * 또 넣으면 노치 기기에서 34px 를 두 번 잃는다 — 전투 화면은 세로가 가장 아쉬운
 * 곳이라 그 34px 가 지도 폭 22px 로 돌아온다. 다른 화면은 .screen 이 계속 맡는다. */
#screen-game { padding-bottom: 0; }

/* ═══════════════════ 스테이지 ═══════════════════ */
.stage { position: relative; flex: 1; min-height: 0; overflow: hidden; background: var(--bg-0); }
#canvas { display: block; width: 100%; height: 100%; touch-action: none; }
/* 가장자리를 살짝 어둡게 — 지도가 화면에 박혀 있는 느낌을 준다 */
.stage::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  box-shadow: inset 0 0 60px 10px rgba(0,0,0,.45);
}

/* 화면 위 고정. 오버레이(50)보다 위라 시트가 떠 있어도 보인다.
 * 전투 중에는 HUD·웨이브바 아래로 내려온다 (body[data-screen] 은 ui.showScreen 이 쓴다). */
.toast {
  position: fixed; left: 50%; top: calc(env(safe-area-inset-top) + 12px); transform: translateX(-50%);
  max-width: 84%; padding: 9px 16px; border-radius: var(--r-pill);
  background: rgba(10,13,20,.92); border: 1px solid var(--line);
  box-shadow: var(--sh-2);
  font-size: 13.5px; font-weight: 700; pointer-events: none;
  animation: pop .18s ease; z-index: 60;
}
/* HUD(≈50px) + 웨이브바(20px) + 미리보기·준비 배지 줄(≈36px) 아래 */
body[data-screen="game"] .toast { top: calc(env(safe-area-inset-top) + 118px); }
/* 버튼 달린 지속형 (새 버전 알림) — 이 변형만 탭을 받는다 */
.toast.action { pointer-events: auto; display: flex; align-items: center; gap: 10px; }
.toast.action .btn { min-height: 30px; padding: 0 12px; font-size: 12.5px; }
@keyframes pop { from { opacity: 0; transform: translate(-50%, -8px) scale(.95); } }

/* 다음 웨이브 미리보기 — 준비 배지와 대칭(좌상단). 탭을 삼키지 않는다. */
.wave-preview {
  position: absolute; left: 10px; top: 10px; z-index: 4; pointer-events: none;
  display: flex; align-items: center; gap: 7px; flex-wrap: wrap; max-width: 62%;
  padding: 5px 10px; border-radius: var(--r-pill);
  background: rgba(10,13,20,.88); border: 1px solid var(--line);
  font-size: 12px; font-weight: 800; color: var(--text); font-variant-numeric: tabular-nums;
  animation: pop .18s ease;
}
.wave-preview .lbl { color: var(--text-dim); font-size: 10.5px; letter-spacing: .08em; }
.wave-preview .pv-item { display: inline-flex; align-items: center; gap: 2px; }
.wave-preview .pv-item canvas { width: 18px; height: 18px; }
.wave-preview .pv-item .mark { width: 12px; height: 12px; }
.wave-preview .pv-item.boss { color: var(--gold); }
.wave-preview .mark.boss { color: var(--gold); }
.wave-preview .mark.air { color: #8fd4ff; }
.wave-preview .mark.armor { color: #c9d2e0; }

/* 도감의 보스 능력 칩 */
.ability-list { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 6px; }
.ability-chip {
  font-size: 11.5px; line-height: 1.35; padding: 3px 8px; border-radius: 8px;
  background: rgba(255,158,203,.10); border: 1px solid rgba(255,158,203,.35); color: var(--text-dim);
}
.ability-chip b { color: #ff9ecb; margin-right: 3px; }

.prep-badge {
  position: absolute; right: 10px; top: 10px; z-index: 4;
  display: flex; align-items: center; gap: 5px;
  padding: 6px 12px; border-radius: var(--r-pill);
  background: rgba(10,13,20,.88); border: 1px solid rgba(255,201,77,.35);
  font-size: 12.5px; font-weight: 800; color: var(--gold);
  font-variant-numeric: tabular-nums; pointer-events: none;
}
.prep-badge .i { width: 13px; height: 13px; }

/* ═══════════════════ 타워 상세 패널 ═══════════════════
   지도 위에 겹쳐 띄운다. 레이아웃을 밀어내면 패널을 열 때마다 지도가 줄었다 늘었다 해서
   조준이 흔들린다 — 그게 조작이 어색하게 느껴지는 원인 중 하나였다. */
.tower-panel {
  position: absolute; left: 8px; right: 8px; bottom: 8px; z-index: 5;
  border: 1px solid var(--line); border-radius: var(--r-lg);
  background: linear-gradient(180deg, rgba(38,47,66,.97), rgba(20,26,38,.97));
  backdrop-filter: blur(10px);
  box-shadow: var(--sh-3), var(--lift);
  padding: 11px 12px 12px; display: flex; flex-direction: column; gap: 10px;
  animation: panelup .18s cubic-bezier(.2,.9,.3,1);
  /* 내용이 타워마다 3~5줄로 늘어난다(효과가 있는 고양이는 줄이 더 붙는다).
   * 상한이 없으면 짧은 화면에서 지도를 통째로 덮어 버린다 — 사거리 원을 못 보면
   * 어디를 때리는지 모른 채 업그레이드하게 된다. */
  max-height: calc(100% - 16px);
  overflow-y: auto;
}
@keyframes panelup { from { opacity: 0; transform: translateY(14px); } }
.tp-head { display: flex; align-items: center; gap: 9px; }
.tp-head canvas { width: 34px; height: 34px; flex: none; }
.tp-head h3 { margin: 0; font-size: 16px; font-weight: 700; }
.tp-lv {
  font-size: 11px; font-weight: 800; color: var(--gold);
  background: rgba(255,201,77,.14); border-radius: var(--r-pill); padding: 2px 8px;
  font-variant-numeric: tabular-nums;
}
.tp-close { margin-left: auto; }
.tp-stats { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
/* 옆 고양이 버프·조합·황금 발바닥이 걸린 상태. 원본 수치까지 같이 적으면 좁은
   폰에서 넘치므로 색으로만 알린다 — 숫자 자체가 이미 오른 값이다. */
.tp-stats.boosted .stat-pill b[data-k] { color: var(--mint); }
.stat-pill {
  display: flex; align-items: baseline; gap: 6px;
  padding: 6px 10px; border-radius: var(--r-sm);
  background: rgba(0,0,0,.26); box-shadow: inset 0 1px 0 rgba(255,255,255,.04);
  font-size: 11.5px; color: var(--text-faint);
}
.stat-pill b { margin-left: auto; color: var(--text); font-size: 13px; font-variant-numeric: tabular-nums; }
.stat-pill .up { color: var(--ok); font-size: 12px; font-weight: 700; }
.tp-actions { display: flex; gap: 8px; }
.tp-actions .btn { flex: 1; padding: 0 8px; font-size: 13px; min-height: 44px; }
.tp-actions .btn.upgrade { flex: 1.35; }
/* 버튼 안 금액 — 아이콘 없이 숫자만. 작은 동전은 그냥 점으로 보인다. */
.tp-actions .btn .amt {
  padding: 1px 7px; border-radius: var(--r-pill);
  background: rgba(0,0,0,.22); font-size: 12.5px; font-weight: 800;
}
/* 표적 버튼은 두 줄 — '선두' 한 단어만 있으면 무슨 버튼인지 알 수 없다 */
.tp-actions .btn.stack { flex-direction: column; gap: 0; line-height: 1.25; }
.tp-actions .btn.stack .lbl { font-size: 10px; font-weight: 700; color: var(--text-faint); }
.tp-actions .btn.stack .val { font-size: 13.5px; font-weight: 700; color: var(--text); }

/* ═══════════════════ 필살기 바 ═══════════════════ */
.specials {
  display: flex; gap: 7px; justify-content: center;
  padding: 8px 10px 4px;
  background: linear-gradient(180deg, #141a26, var(--surf-1));
  border-top: 1px solid var(--line-soft);
}
.special {
  position: relative; flex: 1; max-width: 100px;
  min-height: 58px; padding: 6px 3px 5px;
  border: 1px solid var(--line); border-radius: var(--r-md);
  background: linear-gradient(180deg, var(--surf-2), #171d29);
  color: var(--text-dim); box-shadow: var(--lift);
  font: inherit; cursor: pointer; overflow: hidden;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
  transition: transform .08s ease;
}
.special:active { transform: scale(.94); }
.special .ic { font-size: 21px; line-height: 1.05; opacity: .5; }
.special .ic .i { width: 23px; height: 23px; }
.special .nm { font-size: 10px; font-weight: 700; letter-spacing: -.02em; }
.special .cd {
  position: absolute; inset: 0; background: rgba(10,13,20,.93);
  display: flex; align-items: center; justify-content: center;
  font-size: 17px; font-weight: 800; color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}
.special .fill {
  position: absolute; left: 0; bottom: 0; height: 3px;
  background: var(--mint); box-shadow: 0 0 8px var(--mint);
  transition: width .12s linear;
}
/* 마나 비용 — 얼마를 내는지 버튼에 적어둔다 */
.special .mana-cost {
  display: flex; align-items: center; gap: 2px;
  font-size: 10px; font-weight: 800; color: #9fdcff;
  font-variant-numeric: tabular-nums;
}
.special .mana-cost .i { width: 10px; height: 10px; }
/* 쿨다운은 끝났는데 마나가 모자란 상태 — 이유가 다르면 표시도 달라야 한다 */
.special.poor { border-color: rgba(159,220,255,.35); }
.special.poor .cd { font-size: 12px; color: #9fdcff; letter-spacing: -.01em; }
.special.poor .fill { background: #5aa8e0; box-shadow: none; }
/* 쓸 수 있을 때만 살아난다 — 항상 빛나면 언제 쓸 수 있는지 알 수 없다 */
.special.ready {
  border-color: var(--gold); color: var(--text);
  background: linear-gradient(180deg, #3a3320, #241f14);
  box-shadow: 0 0 0 1px rgba(255,201,77,.3), 0 0 16px rgba(255,201,77,.18), var(--lift);
}
.special.ready .ic { opacity: 1; color: var(--gold); animation: pulse 1.9s ease-in-out infinite; }
.special.ready .nm { color: var(--gold); }
/* 지금 이어 쓰면 연계가 되는 필살기 — 안 알려주면 아무도 못 찾는다 */
.special.linkable {
  box-shadow: inset 0 0 0 2px var(--mint), 0 0 14px rgba(127,209,193,.45);
  animation: linkable 1.1s ease-in-out infinite;
}
@keyframes linkable {
  0%, 100% { box-shadow: inset 0 0 0 2px var(--mint), 0 0 10px rgba(127,209,193,.35); }
  50%      { box-shadow: inset 0 0 0 2px var(--mint), 0 0 20px rgba(127,209,193,.7); }
}
@keyframes pulse { 0%,100% { transform: scale(1); } 50% { transform: scale(1.13); } }

/* ═══════════════════ 상점 ═══════════════════ */
.shop {
  background: linear-gradient(180deg, var(--surf-1), #10151f);
  border-top: 1px solid var(--line-soft);
  padding: 8px 10px calc(10px + env(safe-area-inset-bottom));
  display: flex; flex-direction: column; gap: 9px;
}
.shop-scroll { position: relative; }
/* 오른쪽에 카드가 더 있다는 걸 알려주는 페이드 */
.shop-scroll::after {
  content: ""; position: absolute; right: -1px; top: 0; bottom: 0; width: 26px;
  background: linear-gradient(90deg, transparent, #131924);
  pointer-events: none;
}
.shop-cards {
  display: flex; gap: 8px; overflow-x: auto; padding: 2px 0;
  scrollbar-width: none; -webkit-overflow-scrolling: touch;
}
.shop-cards::-webkit-scrollbar { display: none; }

.shop-card {
  /* pan-x 라야 상점은 가로로 넘기면서, 지도 쪽으로 끌어올리는 동작은 가로챌 수 있다 */
  touch-action: pan-x;
  position: relative; flex: none; width: 84px; padding: 7px 5px 8px;
  border: 1px solid var(--line-soft); border-radius: var(--r-md);
  background: linear-gradient(180deg, var(--surf-2), #171d29);
  box-shadow: var(--sh-1), var(--lift);
  color: var(--text); font: inherit; cursor: pointer; text-align: center;
  transition: transform .08s ease, border-color .12s ease;
}
/* 카드 위쪽 액센트 띠 — 고양이마다 색이 달라 한눈에 구분된다 */
.shop-card::before {
  content: ""; position: absolute; left: 12px; right: 12px; top: 0; height: 2px;
  border-radius: 0 0 3px 3px; background: var(--accent, var(--line));
  opacity: .85;
}
.shop-card:active { transform: scale(.94); }
.shop-card.selected {
  border-color: var(--gold);
  background: linear-gradient(180deg, #3a3320, #241f14);
  box-shadow: 0 0 0 1px rgba(255,201,77,.35), 0 0 18px rgba(255,201,77,.2), var(--lift);
}
.shop-card.poor { opacity: .4; filter: grayscale(.7); }
/* 선택 중 표시 겸 "다시 누르면 취소" 안내. 지도가 아니라 카드 위에 둔다 —
   지도 위에 안내를 띄우면 하필 그 칸에 고양이를 못 짓게 된다. */
.shop-card .x {
  position: absolute; top: 3px; right: 3px;
  width: 17px; height: 17px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--gold); color: #2b1c00;
  pointer-events: none;                 /* 카드 어디를 눌러도 취소된다 */
}
.shop-card .x .i { width: 11px; height: 11px; }
.shop-card canvas { display: block; margin: 0 auto 1px; width: 42px; height: 42px; }
.shop-card .nm { font-size: 12px; font-weight: 700; }
.shop-card .cost {
  display: flex; align-items: center; justify-content: center; gap: 3px;
  font-size: 12px; font-weight: 800; color: var(--gold); font-variant-numeric: tabular-nums;
}
.shop-card .cost .i { width: 12px; height: 12px; color: var(--gold); }
/* 제목·본문 안에 끼워 넣는 금액 표기 */
.cost.inline {
  display: inline-flex; align-items: center; gap: 3px; margin-left: 7px;
  font-size: 12.5px; font-weight: 800; color: var(--gold); vertical-align: middle;
}
.cost.inline .i { width: 12px; height: 12px; }
.cost.inline.catnip { color: var(--catnip); }
.shop-card .tag {
  font-size: 9.5px; color: var(--text-faint); min-height: 13px;
  letter-spacing: -.02em;
}

.wave-btn { min-height: 50px; font-size: 15.5px; }
.wave-btn .sub { font-size: 12px; font-weight: 600; opacity: .8; font-variant-numeric: tabular-nums; }

/* ═══════════════════ 오버레이 / 시트 ═══════════════════ */
.overlay {
  position: fixed; inset: 0; z-index: 50;
  background: rgba(5,7,11,.74); backdrop-filter: blur(4px);
  display: flex; align-items: flex-end; justify-content: center;
  animation: fade .16s ease;
}
@keyframes fade { from { opacity: 0; } }
.overlay[hidden] { display: none; }
.sheet {
  position: relative;
  width: 100%; max-width: 460px; max-height: 88vh; overflow-y: auto;
  background: linear-gradient(180deg, var(--surf-1), #10151f 40%);
  border-radius: var(--r-lg) var(--r-lg) 0 0;
  border-top: 1px solid rgba(255,255,255,.1);
  box-shadow: 0 -12px 40px rgba(0,0,0,.6);
  padding: 20px 16px calc(20px + env(safe-area-inset-bottom));
  animation: slideup .22s cubic-bezier(.2,.9,.3,1);
}
/* 시트 손잡이 — 끌어내릴 수 있다는 신호 */
.sheet::before {
  content: ""; position: sticky; top: -6px; display: block;
  width: 38px; height: 4px; margin: -8px auto 12px;
  border-radius: 999px; background: var(--line);
}
@keyframes slideup { from { transform: translateY(28px); opacity: 0; } }
.sheet h2 { margin: 0 0 4px; font-size: 21px; font-weight: 800; letter-spacing: -.4px; }
.sheet .sub { margin: 0 0 16px; color: var(--text-dim); font-size: 13px; }
.sheet-actions { display: flex; flex-direction: column; gap: 9px; margin-top: 18px; }

/* ═══════════════════ 설정 ═══════════════════ */
.set-group { margin-bottom: 20px; }
.set-group h3 {
  margin: 0 0 6px; font-size: 11px; font-weight: 800;
  color: var(--text-faint); letter-spacing: .1em; text-transform: uppercase;
}
.set-rows {
  border-radius: var(--r-md); background: rgba(0,0,0,.24);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.04); padding: 0 12px;
}
.set-row {
  display: flex; align-items: center; gap: 12px;
  min-height: var(--tap); padding: 7px 0; border-bottom: 1px solid var(--line-soft);
}
.set-row:last-child { border-bottom: none; }
.set-label { flex: 1; font-size: 14px; }
.set-label .hint { display: block; font-size: 11.5px; color: var(--text-faint); }
.set-row select, .set-row input[type="range"] {
  font: inherit; font-size: 13px; color: var(--text); background: var(--surf-2);
  border: 1px solid var(--line); border-radius: var(--r-sm); padding: 7px 9px;
  min-height: 36px; max-width: 48%;
}
.set-row input[type="range"] { padding: 0; accent-color: var(--mint); }

.switch { position: relative; width: 50px; height: 30px; flex: none; }
.switch input { position: absolute; opacity: 0; width: 100%; height: 100%; margin: 0; cursor: pointer; }
.switch span {
  position: absolute; inset: 0; border-radius: 999px;
  background: #0d1119; border: 1px solid var(--line); transition: background .18s, border-color .18s;
  pointer-events: none;
}
.switch span::after {
  content: ""; position: absolute; top: 3px; left: 3px;
  width: 22px; height: 22px; border-radius: 50%;
  background: var(--text-faint); box-shadow: var(--sh-1);
  transition: transform .18s cubic-bezier(.3,1.4,.5,1), background .18s;
}
.switch input:checked + span { background: var(--mint-dark); border-color: var(--mint-deep); }
.switch input:checked + span::after { transform: translateX(20px); background: var(--mint); }

/* ═══════════════════ 도감 ═══════════════════ */
/* 탭이 7개라 가로로 넘긴다 (도감·기록·업적을 한 시트에 — 타이틀에 버튼을 더 넣으면 12px 글자가 된다) */
.codex-tabs { display: flex; gap: 8px; margin-bottom: 14px; overflow-x: auto; flex-wrap: nowrap; padding-bottom: 2px; scrollbar-width: none; }
.codex-tabs::-webkit-scrollbar { display: none; }
.codex-tabs .chip { flex: none; }
.codex-sub { margin: 8px 0 8px; font-size: 13px; color: var(--text-dim); }
h3.codex-sub { margin-top: 18px; font-weight: 700; color: var(--text); }
.special-ic { width: 54px; height: 54px; flex: none; display: grid; place-items: center; border-radius: 14px;
  background: rgba(255,201,77,.10); color: var(--gold); }
.special-ic .i, .special-ic svg { width: 28px; height: 28px; }
.pet-badge.dim { background: rgba(255,255,255,.06); color: var(--text-dim); }
.ach-row .ach-mark { width: 40px; height: 40px; flex: none; display: grid; place-items: center; border-radius: 12px;
  background: rgba(255,201,77,.12); color: var(--gold); }
.ach-row .ach-mark .i { width: 20px; height: 20px; }
.ach-row.locked .ach-mark { background: rgba(255,255,255,.05); color: var(--text-faint); }
.ach-row.locked h4, .ach-row.locked p { opacity: .55; }
.ach-row h4 .catnip-tag { margin-left: 8px; font-size: 11.5px; }
.ach-date { font-size: 11px; color: var(--text-faint); }
.ach-unlocked { margin: 14px 0 0; padding: 12px 14px; border-radius: var(--r-md);
  background: rgba(255,201,77,.08); border: 1px solid rgba(255,201,77,.28); }
.ach-unlocked h3 { margin: 0 0 8px; font-size: 13px; color: var(--gold); }
.ach-line { display: flex; align-items: center; gap: 8px; font-size: 14px; padding: 4px 0; }
.ach-line .i { width: 16px; height: 16px; color: var(--gold); }
/* 출석 시트 */
.daily-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px; margin: 14px 0 6px; }
.daily-cell { padding: 8px 2px; border-radius: 10px; text-align: center; background: rgba(0,0,0,.26);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.04); }
.daily-cell .k { font-size: 10.5px; color: var(--text-faint); }
.daily-cell .v { display: flex; align-items: center; justify-content: center; gap: 3px; font-size: 13px; font-weight: 800;
  color: var(--catnip); margin-top: 4px; }
.daily-cell .v .i { width: 13px; height: 13px; }
.daily-cell.done { opacity: .55; }
.daily-cell.today { outline: 2px solid var(--gold); background: rgba(255,201,77,.12); }
.sheet .hint { margin: 10px 0 0; font-size: 12px; color: var(--text-dim); }
.codex-item {
  display: flex; gap: 12px; padding: 12px; margin-bottom: 8px;
  border-radius: var(--r-md); background: rgba(0,0,0,.24);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.04);
}
.codex-item canvas { width: 54px; height: 54px; flex: none; }
.codex-item h4 {
  margin: 0 0 3px; font-size: 14.5px; font-weight: 700;
  display: flex; align-items: center; gap: 5px;
}
.codex-item h4 .mark { width: 15px; height: 15px; }
.codex-item h4 .mark.boss { color: var(--gold); }
.codex-item h4 .mark.air { color: #8fd4ff; }
.codex-item p { margin: 0 0 6px; font-size: 12.5px; color: var(--text-dim); }
.codex-item .body { flex: 1; min-width: 0; }
/* 조합 탭 — 필요한 고양이를 가로로 늘어놓고 그 뒤에 모양을 적는다 */
.combo-row .combo-cats {
  display: flex; align-items: center; gap: 3px; flex-wrap: wrap;
  margin-top: 2px;
}
.combo-row .combo-cats canvas { width: 30px; height: 30px; flex: none; }
.combo-shape {
  margin-left: 4px; padding: 3px 9px; border-radius: 999px;
  background: rgba(255,255,255,.06); color: var(--text-dim);
  font-size: 11.5px; font-weight: 600;
}
/* 아직 못 만들어 본 것 — 조건은 읽혀야 하므로 그림만 흐리게 한다 */
.codex-item.locked .combo-cats canvas,
.codex-item.locked .pet-icon { filter: grayscale(1) brightness(.65); }
/* 아직 없는 것(카드 고양이·안 산 펫)은 그림도 흐리게 — 목록에서 "가진 것"과 한눈에 갈린다 */
.codex-item.locked > canvas { filter: grayscale(1) brightness(.7); opacity: .8; }
.codex-item.locked h4, .codex-item.locked > div > p { opacity: .7; }
.combo-row.locked h4 { color: var(--text-dim); }

/* ═══════════════════ 펫 고르기 ═══════════════════ */
.pet-row { align-items: center; }
.pet-row.on { box-shadow: inset 0 0 0 1.5px var(--gold), inset 0 1px 0 rgba(255,255,255,.04); }
.pet-row .pet-act { flex: none; display: flex; align-items: center; }
.pet-row .pet-act .btn { min-height: 38px; padding: 0 14px; font-size: 13px; }

/* 도전 — 맵 카드 위에 겹치는 칩과 도전 시트의 규칙 행 */
.map-entry { position: relative; }
.map-chip {
  position: absolute; right: 12px; top: 12px; min-height: 28px; padding: 0 10px;
  font-size: 12px; font-weight: 800; color: var(--gold); border-color: rgba(255,201,77,.45);
  background: rgba(20,24,32,.85);
}
.challenge-row { gap: 12px; }
.challenge-row.on { box-shadow: inset 0 0 0 1.5px var(--gold), inset 0 1px 0 rgba(255,255,255,.04); }
.challenge-badge {
  width: 44px; height: 44px; flex: none; border-radius: 10px;
  display: flex; align-items: center; justify-content: center;
  font-size: 17px; font-weight: 800; color: var(--gold);
  background: linear-gradient(180deg, #2a3244, #1e2532); box-shadow: var(--sh-1);
}
.challenge-row .map-meta { margin-top: 4px; }

/* 훈련 — 단계 핍과 도감의 훈련 줄 */
.rank-pips { display: inline-flex; gap: 3px; align-items: center; vertical-align: middle; }
.rank-pips .pip { width: 8px; height: 8px; border-radius: 50%; background: rgba(255,255,255,.14); display: block; }
.rank-pips .pip.on { background: var(--gold); box-shadow: 0 0 6px rgba(255,201,77,.55); }
.train-row { display: flex; align-items: center; gap: 10px; margin-top: 8px; flex-wrap: wrap; }
.train-label { font-size: 12px; color: var(--text-dim); font-weight: 700; }
.train-row .btn { min-height: 34px; padding: 0 12px; font-size: 12.5px; margin-left: auto; }
/* 필살기 도감 행 — 로드아웃(장착·순서)과 두 트리(세기·쿨다운). 훈련 행의 결을 따른다 */
.loadout-row { justify-content: flex-end; }
.loadout-row .btn { margin-left: 0; }
.loadout-row .move-btn { min-width: 36px; padding: 0 9px; }
.tree-row .tree-name { min-width: 46px; color: inherit; }
.special-row.loaded .special-ic { box-shadow: inset 0 0 0 2px var(--gold); }
.shop-card .rank-pips { position: absolute; top: 7px; left: 8px; gap: 2px; }
.shop-card .rank-pips .pip { width: 5px; height: 5px; }

/* 이번 주 도전 카드 — 맵 목록 맨 위 */
/* 상점 — 잠긴 카드에서 왔을 때 강조하는 상품 */
.store-item.focus { box-shadow: inset 0 0 0 1.5px var(--gold); border-radius: 12px; }

/* 스킨 */
.skin-chip { margin-top: 8px; font-size: 12px; }
.skin-row { gap: 12px; }
.skin-row.on { box-shadow: inset 0 0 0 1.5px var(--gold), inset 0 1px 0 rgba(255,255,255,.04); }

.weekly-card { border-color: rgba(255,201,77,.45); background: linear-gradient(180deg, #2b2f3a, #1d2230); }
.weekly-card.done { border-color: rgba(79,214,180,.45); }
.weekly-card h3 { display: flex; align-items: center; gap: 8px; }
.weekly-badge {
  font-size: 12px; font-weight: 800; color: var(--gold); border: 1px solid rgba(255,201,77,.5);
  border-radius: 999px; padding: 1px 8px; background: rgba(255,201,77,.1);
}
.pet-badge {
  margin-left: 6px; padding: 2px 7px; border-radius: 999px;
  background: rgba(255,201,77,.16); color: var(--gold);
  font-size: 10.5px; font-weight: 700;
}

/* ═══════════════════ 결과 ═══════════════════ */
.result-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin: 16px 0 4px; }
.result-cell {
  background: rgba(0,0,0,.26); border-radius: var(--r-md); padding: 11px 13px;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.04);
}
.result-cell .k { font-size: 11px; color: var(--text-faint); }
.result-cell .v { font-size: 20px; font-weight: 800; font-variant-numeric: tabular-nums; }
.result-cell .v.catnip { display: flex; align-items: center; gap: 6px; color: var(--catnip); }
.result-cell .v.catnip .i { width: 18px; height: 18px; }
/* 이어하기 버튼: 아이콘 + 라벨 + 가격 + 보유량 */
.btn .note { font-size: 11.5px; font-weight: 600; opacity: .7; font-variant-numeric: tabular-nums; }
.btn .cost { display: inline-flex; align-items: center; gap: 3px; }
.btn .cost .i { width: 14px; height: 14px; }

/* ═══════════════════ 상점(캣닢) ═══════════════════ */
.store-section { margin-bottom: 20px; }
.store-section h3 {
  margin: 0 0 4px; font-size: 11px; font-weight: 800;
  color: var(--text-faint); letter-spacing: .1em; text-transform: uppercase;
}
.store-note { margin: 0 0 10px; font-size: 11.5px; color: var(--text-faint); }
.store-item {
  display: flex; align-items: center; gap: 12px; padding: 11px 12px; margin-bottom: 7px;
  border-radius: var(--r-md); background: rgba(0,0,0,.24);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.04);
}
.store-item .ic {
  width: 38px; height: 38px; flex: none; border-radius: 10px;
  display: grid; place-items: center;
  background: rgba(255,255,255,.06); color: var(--gold);
}
.store-item .ic .i { width: 21px; height: 21px; }
.store-item .buy .cost { display: inline-flex; align-items: center; gap: 4px; color: var(--catnip); }
.store-item .buy .cost .i { width: 14px; height: 14px; }
.store-item .body { flex: 1; min-width: 0; }
.store-item h4 { margin: 0 0 2px; font-size: 14.5px; font-weight: 700; }
.store-item p { margin: 0; font-size: 12px; color: var(--text-dim); }
.store-item .buy { flex: none; min-width: 96px; min-height: 40px; padding: 0 12px; font-size: 13px; }
.badge {
  display: inline-block; margin-left: 6px; padding: 1px 7px;
  border-radius: 999px; background: var(--mint-dark); color: var(--catnip);
  font-size: 10px; font-weight: 800;
}
.owned { color: var(--ok); font-weight: 700; font-size: 13px; }
.billing-label {
  margin: 0 0 14px; padding: 9px 12px; border-radius: var(--r-sm);
  background: rgba(255,201,77,.09); border: 1px solid rgba(255,201,77,.28);
  color: var(--gold); font-size: 12px;
}

/* 왼손 모드 — 엄지가 닿기 쉬운 쪽으로 뒤집는다 */
body.left-handed .shop-cards { flex-direction: row-reverse; justify-content: flex-end; }
body.left-handed .hud { flex-direction: row-reverse; }
body.left-handed .specials { flex-direction: row-reverse; }
body.left-handed .prep-badge { right: auto; left: 10px; }
body.left-handed .wave-preview { left: auto; right: 10px; }
body.left-handed .tp-head { flex-direction: row-reverse; }

/* 키보드·스위치 사용자에게 초점이 보이게 */
.btn:focus-visible, .chip:focus-visible, .map-card:focus-visible, .shop-card:focus-visible,
.special:focus-visible, .icon-btn:focus-visible { outline: 2px solid var(--mint); outline-offset: 2px; }

/* OS 의 '움직임 줄이기'는 CSS 쪽 애니메이션을 따른다. 캔버스 흔들림은 게임 설정이 맡는다. */
@media (prefers-reduced-motion: reduce) {
  * { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* 글자 크기 '크게' — 메뉴와 시트만. 전투 HUD 는 자리가 없어 그대로 둔다. */
body.text-lg .sheet, body.text-lg .map-list, body.text-lg .title-wrap { zoom: 1.08; }

/* 큰 화면에서는 조금씩 키운다 */
@media (min-height: 760px) {
  :root { font-size: 16px; }
  .shop-card { width: 90px; }
  .title { font-size: 46px; }
}

/* ── 짧은 화면 — 전투 UI 를 눌러 지도에 자리를 돌려준다 ─────────────────────
 *
 * 왜 필요한가: 전투 화면의 고정 UI(hud 51 + wavebar 20 + 필살기 82 + 상점 191)는
 * 344px 로 화면 높이와 무관하게 일정하다. 스테이지만 줄어드는데, 지도가 9×14 라
 * 세로에 맞춰지므로 세로로 잃은 만큼 가로도 9/14 배로 좁아진다.
 * 실제 아이폰 인앱 브라우저(웹 영역 658px)에서 스테이지 314 · 타일 22.4px ·
 * 지도 폭 202/402 가 나왔다 — 양옆 100px 씩이 죽는 기둥이었다.
 *
 * 기준 720 은 스모크(915)와 실제 폰(658) 사이다. 위 min-height:760 브랜치와
 * 겹치지 않으므로 큰 화면은 전혀 안 건드린다.
 *
 * 손가락 크기는 화면이 짧다고 같이 줄지 않는다 — 필살기·웨이브 버튼은
 * --tap(46px) 아래로 내리지 않는다. 줄이는 것은 여백과 장식뿐이다.        */
@media (max-height: 720px) {
  .hud { padding: 5px 10px; }
  .hud-stat { font-size: 13.5px; padding: 3px 9px 3px 7px; }
  .hud .chip { height: 32px; }

  .specials { padding: 5px 10px 3px; gap: 6px; }
  .special { min-height: 46px; padding: 4px 3px 3px; gap: 1px; }
  .special .ic .i { width: 19px; height: 19px; }

  .shop { padding: 6px 10px 8px; gap: 7px; }
  .shop-card { width: 76px; padding: 5px 4px 6px; }
  .shop-card canvas { width: 34px; height: 34px; }
  .shop-card .nm, .shop-card .cost { font-size: 11px; }
  .shop-card .cost .i { width: 11px; height: 11px; }
  /* '지상 전용' 같은 꼬리표는 도감에서도 볼 수 있다. 여기서는 자리값을 못 한다. */
  .shop-card .tag { display: none; }
  .wave-btn { min-height: 46px; font-size: 14.5px; }

  /* 패널이 지도를 3분의 2 넘게 덮으면 사거리 원이 안 보인다. 내용도 같이 줄인다. */
  .tower-panel { max-height: 62%; padding: 9px 10px 10px; gap: 8px; }
  .tp-head canvas { width: 28px; height: 28px; }
}

/* 움직임 줄이기 설정 — 장식 애니메이션을 끈다 */
body.reduced-motion *, body.reduced-motion *::before, body.reduced-motion *::after {
  animation-duration: .01ms !important; animation-iteration-count: 1 !important;
}

/* ═══════════════════ 시나리오 ═══════════════════ */
#screen-chapters { background: var(--bg-select); }

/* 장 번호 — 맵 썸네일 자리를 그대로 쓴다 (같은 목록이라 같은 리듬이어야 한다) */
.chapter-no {
  width: 68px; height: 68px; flex: none; border-radius: 12px;
  display: flex; align-items: center; justify-content: center;
  font-size: 27px; font-weight: 800; color: var(--gold);
  background: linear-gradient(180deg, #2a3244, #1e2532);
  box-shadow: var(--sh-1); font-variant-numeric: tabular-nums;
}
.map-card[disabled] .chapter-no { color: var(--text-faint); }
/* 막 제목 — 챕터 목록에서 1막·2막을 가른다 */
.act-head {
  font-size: 12px; font-weight: 800; letter-spacing: .14em; color: var(--text-dim);
  padding: 6px 2px 0; text-transform: uppercase;
}
.act-head + .map-card { margin-top: -4px; }
.map-card.paid { opacity: .85; filter: none; cursor: pointer; border-color: rgba(255,201,77,.35); }
.map-card.paid .map-meta.locked { color: var(--gold); }

.stars { display: flex; gap: 3px; margin: 4px 0 2px; }
.star { color: #2f3745; display: inline-flex; }
.star.on { color: var(--gold); }
.star .i { width: 17px; height: 17px; }
.star.on { filter: drop-shadow(0 0 4px rgba(255, 209, 102, .5)); }

.chapter-goals { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 5px; }
.goal {
  font-size: 11px; font-weight: 600; color: var(--text-dim);
  padding: 2px 7px; border-radius: 999px; background: rgba(255, 255, 255, .05);
}
/* 첫 칩이 주 목표다 — 부 목표와 구분되게 */
.chapter-goals .goal:first-child { color: var(--gold); background: rgba(255, 209, 102, .12); }

/* 결과 화면의 목표 판정 */
.goal-list { display: flex; flex-direction: column; gap: 6px; margin: 10px 0 4px; }
.goal-row {
  display: flex; align-items: center; gap: 8px;
  font-size: 13.5px; font-weight: 600; color: var(--text-faint);
  padding: 7px 10px; border-radius: var(--r-md); background: rgba(255, 255, 255, .04);
}
.goal-row.ok { color: var(--text); background: rgba(127, 224, 138, .12); }
.goal-row .i { width: 16px; height: 16px; flex: none; color: #7fe08a; }
.goal-row:not(.ok) .i { color: #6b7a93; }

/* 컷신 — 오버레이 안에만 그린다. 지도 위에 얹으면 그 칸을 못 누르게 된다. */
.sheet.story { padding-bottom: 18px; }

/* 컷신일 때만 오버레이에 장소 사진을 깐다. .overlay 는 일시정지·설정·도감·결과가
 * 전부 함께 쓰므로 클래스로 갈라야 한다 (ui.js 의 openStoryCards / _openSheet).
 *
 * 기본 .overlay 의 rgba(5,7,11,.74) 를 그대로 두면 사진이 거의 안 보인다.
 * 컷신 그림은 대사 상자 자리 평균밝기가 이미 32 라 .42~.62 로 낮춰도 글씨가 읽힌다.
 * backdrop-filter 는 뒤(챕터 화면)를 흐리는 건데 사진이 그걸 다 가리므로 끈다 —
 * 켜 두면 안드로이드 WebView 에서 공짜가 아니다. */
.overlay.story {
  background:
    linear-gradient(180deg, rgba(5,7,11,.42), rgba(5,7,11,.62)),
    url(../art/bg-story.jpg) center / cover no-repeat,
    rgba(5,7,11,.74);
  backdrop-filter: none;
}
.story-box { min-height: 132px; display: flex; align-items: center; }
.story-row { display: flex; align-items: flex-end; gap: 10px; width: 100%; }
.story-row.right { flex-direction: row-reverse; }
.story-row canvas { flex: none; filter: drop-shadow(0 3px 6px rgba(0, 0, 0, .5)); }
.story-bubble {
  flex: 1; min-width: 0; padding: 11px 13px; border-radius: var(--r-lg);
  background: linear-gradient(180deg, var(--surf-2), var(--surf-1));
  border: 1px solid var(--line-soft); box-shadow: var(--sh-1);
}
.story-bubble .nm { font-size: 11.5px; font-weight: 700; color: var(--gold); margin-bottom: 3px; }
.story-bubble p { margin: 0; font-size: 15px; line-height: 1.45; }
.story-hint {
  margin-top: 12px; text-align: center; font-size: 12px; color: var(--text-faint);
  animation: story-blink 1.6s ease-in-out infinite;
}
@keyframes story-blink { 0%, 100% { opacity: .45; } 50% { opacity: 1; } }

/* 아직 못 받은 고양이 — 목록에서 빼지 않고 자물쇠로 보여준다 */
.shop-card.locked { opacity: .55; filter: grayscale(.75); }
.shop-card.locked .lock { position: absolute; top: 4px; right: 5px; }
.shop-card.locked .lock .i { width: 15px; height: 15px; }

/* ═══════════════════ 로딩 ═══════════════════
   타이틀 위에 덮는다. 타이틀을 hidden 으로 두면 bg-title.jpg 요청이 첫 페인트에서
   빠져 나중에 튀고, 스모크의 배경 검사(#screen-title computedStyle)도 깨진다.
   배경은 타이틀과 같은 파일 — 바이트가 안 늘고, 걷힐 때 배경이 이어져 자연스럽다.
   z-index 는 .overlay(50) 위. */
.loading {
  position: fixed; inset: 0; z-index: 100;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  padding: env(safe-area-inset-top) 24px env(safe-area-inset-bottom);
  background:
    linear-gradient(180deg, rgba(6,9,14,.72), rgba(6,9,14,.86)),
    url(../art/bg-title.jpg) center / cover no-repeat,
    var(--bg-0);
  transition: opacity .35s ease;
}
.loading.out { opacity: 0; pointer-events: none; }
.loading-body { width: 100%; max-width: 360px; text-align: center; }
.loading-badge {
  width: 124px; height: 124px; margin: 0 auto 16px;
  display: grid; place-items: center; border-radius: 34px;
  background: linear-gradient(180deg, #2a3346, #171e2b);
  box-shadow: 0 14px 40px rgba(0,0,0,.6), inset 0 2px 0 rgba(255,255,255,.12),
              0 0 0 1px rgba(255,201,77,.18);
  animation: bob 3.4s ease-in-out infinite;            /* 타이틀 로고와 같은 흔들림 */
}
.loading-badge img { width: 88px; height: 88px; display: block; }
.loading-title {
  margin: 0 0 22px; font-size: 34px; font-weight: 800; letter-spacing: -1px;
  background: linear-gradient(180deg, #fff3cf 10%, var(--gold) 60%, var(--gold-deep));
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.loading-bar {
  height: 8px; border-radius: 4px; overflow: hidden;
  background: rgba(255,255,255,.08); box-shadow: inset 0 1px 2px rgba(0,0,0,.5);
}
.loading-bar i {
  display: block; height: 100%; width: 0;
  background: linear-gradient(90deg, var(--mint-deep), var(--mint));
  box-shadow: 0 0 10px rgba(79,214,180,.5);
  transition: width .18s linear;                       /* 웨이브바와 같은 관용구 */
}
.loading-status {
  margin: 10px 0 0; font-size: 12.5px; color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}
.loading-tip {
  margin: 26px 0 0; min-height: 3.2em; font-size: 13.5px; line-height: 1.55;
  color: var(--text); opacity: .92; transition: opacity .25s ease;
}
.loading-tip.swap { opacity: 0; }
.loading-tap {
  margin-top: 22px; padding: 0 28px; min-height: var(--tap);
  border: 1px solid rgba(255,201,77,.45); border-radius: var(--r-pill);
  background: rgba(255,201,77,.10); color: var(--gold);
  font: inherit; font-weight: 700; cursor: pointer;
  animation: tap-pulse 1.6s ease-in-out infinite;
}
@keyframes tap-pulse { 0%,100% { opacity: .55; } 50% { opacity: 1; } }
.loading-version {
  position: absolute; bottom: calc(14px + env(safe-area-inset-bottom));
  font-size: 11px; color: var(--text-faint); font-variant-numeric: tabular-nums;
  pointer-events: none;   /* 표시일 뿐이다 — 짧은 화면에서 탭 버튼 위에 겹쳐도 탭을 삼키면 안 된다 */
}
/* 짧은 화면(가로로 든 폰 412px, 인앱 브라우저)에서는 로딩 레이아웃을 줄인다.
   안 줄이면 버전 표시가 '탭하여 시작' 위에 얹혀 스모크의 가로 패스가 잡아냈다. */
@media (max-height: 520px) {
  .loading-badge { width: 64px; height: 64px; margin-bottom: 8px; border-radius: 18px; }
  .loading-badge img { width: 46px; height: 46px; }
  .loading-title { font-size: 24px; margin-bottom: 10px; }
  .loading-status { margin-top: 6px; }
  .loading-tip { margin-top: 8px; min-height: 2.2em; font-size: 12.5px; line-height: 1.4; }
  .loading-tap { margin-top: 10px; }
  .loading-version { bottom: calc(6px + env(safe-area-inset-bottom)); }
}

/* ═══════════════════ 화면 전환 페이드 ═══════════════════
   검정으로 지나가는 페이드. .screen 이 display:none 토글이라 요소 자체엔 트랜지션을
   못 건다 — 이 막을 90ms 켜고, 그 순간 화면을 바꾸고, 90ms 끈다.
   pointer-events:none 이라 탭을 안 삼킨다. */
.fade {
  position: fixed; inset: 0; z-index: 90; background: #05070b;
  opacity: 0; pointer-events: none; transition: opacity .09s linear;
}
.fade.on { opacity: 1; }

/* ═══════════════════ 타이틀 등장 ═══════════════════
   로딩이 걷히는 순간 한 번. 로고 → 제목 → 부제 → 버튼 순으로 60ms 씩 늦게.
   body.reduced-motion 은 위의 전역 규칙이 animation-duration 을 .01ms 로 눌러
   알아서 생략된다. */
#screen-title.reveal .logo-badge    { animation: rise .45s cubic-bezier(.2,.9,.3,1) both, bob 3.4s ease-in-out .45s infinite; }
#screen-title.reveal .title         { animation: rise .45s .06s cubic-bezier(.2,.9,.3,1) both; }
#screen-title.reveal .tagline       { animation: rise .45s .12s cubic-bezier(.2,.9,.3,1) both; }
#screen-title.reveal .title-buttons { animation: rise .45s .18s cubic-bezier(.2,.9,.3,1) both; }
@keyframes rise { from { opacity: 0; transform: translateY(18px) scale(.96); } }

/* ═══════════════════ 세로로 돌려 주세요 ═══════════════════
   지도는 9×14 격자라 세로로 길다. render.resize 가 빡빡한 쪽에 맞추므로 타일 크기는
   사실상 높이가 정한다: 타일 ≈ (높이 − 190) / 14. 재 보면

     높이 393(아이폰 가로) → 14.5px    높이 540(접은 폴더블) → 25px
     높이 430(프로맥스 가로) → 17.1px   높이 620(작은 데스크톱 창) → 30.7px

   손가락 하나가 44px 인데 타일이 15px 이면 게임이 아니다. 그래서 **가로 + 높이 560px 미만**에서만
   막을 띄운다(560 = 26px 타일). 태블릿 가로(820)·데스크톱(800)은 안 걸린다 — 거기선 잘 돌아간다.

   안드로이드 설치판은 매니페스트의 orientation: portrait 로 애초에 안 눕는다. 이 막이 필요한 건
   **iOS 사파리**(그 값을 무시한다)와 홈 화면에 추가한 웹앱, 그리고 태블릿·폴더블이다.
   회전하면 미디어 쿼리가 저절로 꺼진다 — 자바스크립트가 상태를 들고 있지 않다.
   html.rotate-ok 는 '이대로 하기' 탈출구다(창이 작은 데스크톱용). */
.rotate-hint { display: none; }

@media (orientation: landscape) and (max-height: 560px) {
  .rotate-hint {
    display: flex; position: fixed; inset: 0; z-index: 120;
    align-items: center; justify-content: center;
    background: var(--bg-0); color: var(--text);
    padding: env(safe-area-inset-top) env(safe-area-inset-right)
             env(safe-area-inset-bottom) env(safe-area-inset-left);
  }
  html.rotate-ok .rotate-hint { display: none; }
}

.rotate-box { text-align: center; max-width: 420px; padding: 0 24px; color: var(--mint); }
/* 상점의 '안드로이드 앱 받기' 는 버튼처럼 보이는 <a> 다 — 밑줄이 남으면 버튼이 아니라 링크로 읽힌다 */
a.btn { text-decoration: none; }
.rotate-box h2 { margin: 10px 0 6px; font-size: 20px; color: var(--text); }
.rotate-box p  { margin: 0 0 14px; font-size: 14px; color: var(--text-dim); line-height: 1.5; }

/* 속성 배지 (도감 고양이 행) — 색은 domain/elements.js 의 ELEMENT_LOOK 이 인라인으로 준다 */
.element-badge {
  display: inline-block; margin-top: 6px; padding: 2px 8px; border-radius: 999px;
  border: 1px solid var(--line); background: var(--bg-1);
  font-size: 12px; font-weight: 700; letter-spacing: -0.01em;
}

/* ── 뽑기·카드·룬 (J-3a) ─────────────────────────────────────────────
   확률 표가 화면의 절반이다 — 법이 요구하는 건 "띄운 값이 실제 값"이라 표를 작게 접지 않는다. */
.gacha-purse {
  display: flex; gap: 8px; flex-wrap: wrap; margin: 10px 0 4px;
}
.gacha-purse .purse-item {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 4px 10px; border-radius: 999px; border: 1px solid var(--line);
  background: var(--bg-1); font-size: 13px; font-weight: 700;
}
.gacha-table { margin: 10px 0 4px; border: 1px solid var(--line); border-radius: 12px; overflow: hidden; }
.gacha-row { padding: 9px 12px; border-top: 1px solid var(--line); background: var(--bg-1); }
.gacha-row:first-child { border-top: 0; }
.gacha-row .k { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.gacha-row .k b { font-size: 14px; }
.gacha-row .k .pct { font-size: 14px; font-weight: 800; color: var(--gold); font-variant-numeric: tabular-nums; }
.gacha-row p { margin: 3px 0 0; font-size: 12px; color: var(--text-dim); line-height: 1.4; }

.gacha-result { margin: 8px 0 2px; }
.gacha-grid { display: flex; flex-wrap: wrap; gap: 8px; }
.gain-card {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  min-width: 76px; padding: 8px 6px; border-radius: 12px;
  border: 1px solid var(--line); background: var(--bg-1);
}
.gain-card.dup { opacity: .72; }
.gain-card .gain-name { font-size: 12px; font-weight: 700; }
.gain-card .gain-sub { font-size: 11px; color: var(--text-dim); }
.gain-card .element-badge { margin-top: 0; }

.rune-row { gap: 12px; }
.rune-row.on { box-shadow: inset 0 0 0 1.5px var(--gold), inset 0 1px 0 rgba(255,255,255,.04); }
.rune-chip { margin-top: 8px; margin-right: 6px; }
.rune-wrap { display: flex; flex-wrap: wrap; gap: 8px; margin: 6px 0 12px; }
.rune-count {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 3px 10px; border-radius: 999px; border: 1px solid var(--line);
  background: var(--bg-1); font-size: 13px; font-weight: 700; font-variant-numeric: tabular-nums;
}
.rune-count.dim { opacity: .45; }
.rune-count .element-badge { margin-top: 0; border: 0; padding: 0; background: none; }

/* ── 속성 원정 (J-3b) ────────────────────────────────────────────────
   사다리와 덱을 한 화면에 둔다 — 사다리를 안 보면서 덱을 짜면 아무 뜻이 없다. */
.expedition-card .stage-chain { margin-top: 6px; }
.stage-chain { display: flex; gap: 6px; align-items: center; }
.stage-chain.big { justify-content: center; margin: 10px 0 4px; }
.stage-dot {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; border-radius: 50%;
  border: 1px solid var(--line); background: var(--bg-1);
  font-size: 12px; line-height: 1; opacity: .45;
}
.stage-chain.big .stage-dot { width: 30px; height: 30px; font-size: 15px; }
.stage-dot.done { opacity: 1; border-color: var(--gold); }
.stage-dot.now { box-shadow: 0 0 0 2px rgba(255,201,77,.45); opacity: 1; }

.stage-row { align-items: flex-start; }
.stage-row.done { opacity: .8; }
.stage-row .stat-pill.good { color: #8ee6b0; border-color: rgba(142,230,176,.35); }
.stage-row .stat-pill.bad  { color: #ff9a8a; border-color: rgba(255,154,138,.35); }

.deck-grid { display: flex; flex-wrap: wrap; gap: 8px; margin: 6px 0 4px; }
.deck-cat {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  min-width: 82px; padding: 8px 6px; border-radius: 12px;
  border: 1px solid var(--line); background: var(--bg-1); color: inherit;
  font: inherit; cursor: pointer;
}
.deck-cat.on { box-shadow: inset 0 0 0 1.5px var(--gold); background: var(--bg-2); }
.deck-cat .nm { font-size: 12px; font-weight: 700; }
.deck-cat .element-badge { margin-top: 2px; font-size: 11px; padding: 1px 6px; }
.deck-cat .tally { font-size: 10px; opacity: 0.75; margin-top: 1px; }

/* 원정 칸의 규칙 알약 — 속성 배지와 다른 색이어야 "이건 추가 제약"으로 읽힌다 */
.stage-row .stat-pill.warn { color: #ffb37a; border-color: rgba(255,179,122,.38); }
.codex-tabs .chip.locked { opacity: .4; }

/* 필살기 버튼의 속성 글리프 (O) — 원정에서만 붙는다. 버튼이 작아서 모서리에 얹고 크기를 최소로 둔다. */
.special .el-glyph {
  position: absolute;
  top: 2px;
  right: 4px;
  font-size: 11px;
  line-height: 1;
  pointer-events: none;
}
