/* ============================================================
   app.css — 번개셈 스킨: 시안 A "크로노" (design/DESIGN.md · draft-A.html)
   컨셉: 스톱워치를 켜는 감각 — 웜 블랙 + 본화이트 + 핫오렌지 하나. 숫자가 주인공.
   base.css 구조 규칙(.wrap 높이·헤더 relative·has-ad)은 그대로 — 여기서 덮어쓰지 않는다.
   색 토큰은 base.css :root에서 교체됨(체크리스트 허용 범위). 아래는 앱 전용 토큰.
   ============================================================ */

/* 프리텐다드 내장 (지록 확정 2026-07-16) — CDN 금지(오프라인 앱), 가변 1파일로 전 굵기 커버 */
@font-face {
  font-family: "Pretendard Variable";
  src: url("../fonts/PretendardVariable.woff2") format("woff2-variations");
  font-weight: 45 920;
  font-style: normal;
  font-display: swap;
}

:root {
  --panel-hi: #232127;                 /* 키 눌림 상태 */
  --accent-ink: #180a05;               /* 오렌지 버튼 위 글자색 (흰색 금지) */
  /* 헤더가 2줄(로고 + 슬로건)이 되면서 상향 — base.css 토큰 교체(구조 규칙은 그대로).
     ⚠️ .brand gap 을 벌릴 때마다 이 값도 같이 키워야 한다. 안 그러면 슬로건이 헤더 밖으로 삐져나간다.
        현재: 워드마크 22 + gap 10 + 슬로건 11.4 ≈ 44 → 여유 6px */
  --header-content-h: 50px;
  /* 숫자도 프리텐다드 — 폭 고정은 tabular-nums 가 담당 (모노스페이스 대체) */
  --num: "Pretendard Variable", Pretendard, -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", system-ui, sans-serif;
  --sans: "Pretendard Variable", Pretendard, -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Noto Sans KR", system-ui, sans-serif;
}

body {
  font-family: var(--sans);
  /* 시안 A 배경: 위에서 내려오는 라디얼 (base.css 노이즈 레이어는 유지) */
  background-image:
    var(--noise),
    radial-gradient(120% 90% at 50% 0%, var(--bg-grad-a) 0%, var(--bg-base) 55%, var(--bg-grad-b) 100%);
}
button { font: inherit; color: inherit; cursor: pointer; -webkit-tap-highlight-color: transparent; }

/* ---------- 공통 조각 ---------- */
.k-label {
  font-size: 11px; font-weight: 700; letter-spacing: 0.14em;
  color: var(--muted); text-transform: uppercase;
}
.num { font-family: var(--num); font-variant-numeric: tabular-nums; }

/* ---------- 아이콘 (이모지 전면 금지 — 지록 확정 2026-07-16) ----------
   크기는 font-size(1em)로, 색은 currentColor 로 — 버튼 색만 바꾸면 아이콘이 따라온다.
   ⚠️ 도형별 fill/stroke 는 여기서 못 준다 (<use> 그림자 DOM — index.html 심볼 주석 참고). */
.svg-defs { display: none; }
.ico {
  width: 1em; height: 1em; flex-shrink: 0;
  color: inherit; /* currentColor 가 심볼 안까지 상속된다 */
}
.ico.spark { color: var(--accent); font-size: 13px; } /* 구 ✨ 자리 */

/* ---------- 헤더 ----------
   좌: brand(로고+슬로건, 가변 폭) / 우: 버튼군(폭 고정).
   ⭐ 한↔영 전환 시 버튼이 안 움직이는 이유: brand 는 좌측 고정, 버튼군은 우측 고정에
      각자 폭이 언어와 무관(FREE·아이콘·고정폭 EN/한). brand 가 길어져도 밀지 않게 min-width:0. */
.brand {
  display: flex; flex-direction: column; justify-content: center;
  gap: 10px; /* 로고↔슬로건 — 지록 피드백으로 2→5→10 (붙어 보인다고 두 번 벌림) */
  min-width: 0; flex: 1 1 auto;
  margin-right: auto;
}
.wordmark { font-size: 20px; font-weight: 800; letter-spacing: -0.02em; line-height: 1.1; white-space: nowrap; }
.wordmark i { font-style: normal; color: var(--accent); } /* 손맛 포인트 ①: 오렌지 점 */
.slogan {
  font-size: 9.5px; letter-spacing: 0.12em; line-height: 1.2;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.pill-btn {
  min-height: 28px; padding: 4px 10px;
  display: inline-flex; align-items: center; justify-content: center; gap: 4px;
  border: 1px solid var(--line); border-radius: 999px;
  background: none; color: var(--muted);
  font-size: 10px; font-weight: 700; letter-spacing: 0.08em;
  white-space: nowrap; flex-shrink: 0;
}
/* ⭐ 언어 버튼 폭 고정 — "EN"(2글자) ↔ "한"(1글자) 이 자리를 흔들지 않게 (지록 피드백) */
.pill-btn.lang { width: 38px; padding: 4px 0; }
body.is-premium .pill-btn.plan { display: none; } /* 결제 후엔 FREE 필 자체가 사라진다 */

/* 아이콘 전용 버튼 (게임 나가기 ✕) */
.icon-btn {
  width: 32px; height: 32px; flex-shrink: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--line); border-radius: 999px;
  background: none; color: var(--muted);
  font-size: 17px; /* .ico 가 1em 이라 이 값이 아이콘 크기 */
  transition: color 0.15s, border-color 0.15s, transform 0.1s;
}
.icon-btn:active { transform: scale(0.92); }
/* 게임·카운트다운 중에는 헤더 숨김 (시안 A: 게임 화면은 HUD가 머리) */
body.no-head .app-head { display: none; }

/* ---------- 화면 공통 ---------- */
.stage { flex: 1; min-height: 0; display: flex; flex-direction: column; padding: 0 22px; }
.screen { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.screen[hidden] { display: none; }

/* ---------- M10: 화면 전환 (지록 요청 2026-07-16 "페이지 이동에 모션") ----------
   showScreen() 이 hidden 을 토글하면 display:none→flex 가 되면서 애니가 자동 재시작된다
   (JS에서 클래스를 다시 붙일 필요 없음).
   ⚠️ fill-mode 를 주지 않는다 — 끝난 뒤 transform 이 남으면 그 화면이 fixed 자식의
      containing block 이 되어 나중에 팝업·비네트가 어긋난다.
   이징은 기존 M1(문제 슬라이드 인)과 같은 곡선으로 통일. */
.screen { animation: screenIn 0.24s cubic-bezier(0.2, 0.9, 0.3, 1); }
@keyframes screenIn { from { opacity: 0; transform: translateY(10px); } }

/* 게임·카운트다운은 시간이 곧 점수 — 미끄러지는 연출로 반응을 늦추지 않는다. 짧은 페이드만 */
.screen-game, .screen-count { animation: screenFade 0.14s linear; }
@keyframes screenFade { from { opacity: 0; } }

.btn-big {
  height: 56px; border: 0; border-radius: 16px;
  font-size: 17px; font-weight: 800;
  background: var(--accent); color: var(--accent-ink);
  transition: transform 0.1s;
}
.btn-big:active { transform: scale(0.97); }
/* 되돌릴 수 없는 액션(게임 나가기) — 오렌지(=진행)와 색으로 구분 */
.btn-big.danger { background: none; border: 1.5px solid var(--danger); color: var(--danger); }
.btn-ghost {
  height: 48px; border: 1px solid var(--line); border-radius: 14px;
  background: none; font-size: 15px; font-weight: 600; color: var(--muted);
}
.res-actions { display: flex; flex-direction: column; gap: 10px; padding-top: 16px; flex: 0 0 auto; }

/* ---------- ① 홈 ---------- */
.setup { margin-top: 22px; display: flex; flex-direction: column; gap: 22px; }
.set-group .k-label { display: block; margin-bottom: 9px; padding-left: 2px; }
.seg {
  display: flex; gap: 6px;
  background: var(--panel); border: 1px solid var(--line);
  border-radius: 14px; padding: 5px;
}
.seg-btn {
  flex: 1; min-height: 44px; border: 0; border-radius: 9px;
  background: none; font-size: 15px; font-weight: 600; color: var(--muted);
  transition: background 0.15s, color 0.15s, transform 0.1s;
}
.seg-btn:active { transform: scale(0.97); }
.seg-btn.on { background: var(--text); color: #141318; font-weight: 800; } /* 선택 = 본화이트 (오렌지는 시작 버튼에 양보) */
.seg-btn .num { font-size: 15px; }
.seg-btn small { font-size: 10px; font-weight: 600; margin-left: 2px; opacity: 0.7; }

/* margin-top:auto 는 start-zone 이 flex:1 이 된 뒤 0으로 죽는다 — 고정 간격으로 */
.best-line { margin: 18px 0 0; text-align: center; font-size: 13px; color: var(--muted); }
.best-line b { color: var(--text); font-weight: 700; }
.best-line .num { font-size: 15px; }

/* 스톱워치 시작 버튼 — 베젤 눈금 링 + 원형 (손맛 포인트 ③: 12시 눈금만 오렌지) */
/* 남는 세로 공간을 시작 버튼 구역이 차지 — © 줄은 화면 맨 아래로 (지록 지시 2026-08-20) */
.start-zone { display: flex; justify-content: center; align-items: center; padding: 18px 0 34px; flex: 1 1 auto; min-height: 0; }
.start-wrap { position: relative; width: 168px; height: 168px; }
.start-wrap svg { position: absolute; inset: 0; color: var(--line); }
.start-wrap svg .tick-hi { color: var(--accent); opacity: 0.9; }
.btn-start {
  position: absolute; inset: 22px; border: 0; border-radius: 50%;
  background: radial-gradient(100% 100% at 30% 25%, #ff7b47 0%, var(--accent) 60%, #e0451c 100%);
  color: var(--accent-ink);
  font-size: 22px; font-weight: 800; letter-spacing: 0.06em;
  box-shadow: 0 10px 30px rgba(255, 90, 42, 0.35), inset 0 1px 0 rgba(255, 255, 255, 0.35);
  transition: transform 0.12s cubic-bezier(0.2, 0.9, 0.3, 1.4), box-shadow 0.12s; /* M9 */
}
.btn-start:active { transform: scale(0.94); box-shadow: 0 4px 14px rgba(255, 90, 42, 0.3); }

/* ---------- ② 카운트다운 ---------- */
.screen-count { align-items: center; justify-content: center; gap: 12px; }
.count-player { color: var(--accent); min-height: 14px; }
.count-num { font-size: 100px; font-weight: 800; line-height: 1; }
.count-num.pop { animation: countPop 0.7s cubic-bezier(0.2, 0.9, 0.3, 1); }
@keyframes countPop {
  from { transform: scale(1.35); opacity: 0.2; }
}

/* ---------- ③ 게임 ---------- */
/* 나가기 줄 — 헤더가 숨는 게임 화면에서 유일한 탈출구.
   우측 상단 독립 줄에 두고 그 아래로 콘텐츠(HUD·문제·키패드)가 온다 (지록 배치 지시 2026-07-16).
   숫자에 시선을 안 뺏기게 작고 조용히. */
.game-bar { display: flex; justify-content: flex-end; flex: 0 0 auto; }
.hud-exit { width: 32px; height: 32px; font-size: 16px; }

/* 닫기 아래 여백 — 지록 피드백으로 6→11 */
.hud { display: flex; justify-content: space-between; align-items: flex-end; margin-top: 11px; flex: 0 0 auto; }
.hud .cell { display: flex; flex-direction: column; gap: 3px; }
.hud .cell.right { align-items: flex-end; }
.hud-num { font-size: 34px; font-weight: 800; line-height: 1; }
#solvedNum.bump { animation: bump 0.22s cubic-bezier(0.2, 1.4, 0.4, 1); } /* M2 */
@keyframes bump { 40% { transform: scale(1.35); color: var(--accent); } }
#timer.panic { color: var(--danger); animation: panic 1s steps(1) infinite; } /* M4 */
@keyframes panic { 50% { opacity: 0.45; } }

.t-track { margin-top: 14px; height: 3px; background: var(--line); border-radius: 2px; overflow: hidden; flex: 0 0 auto; }
.t-fill {
  height: 100%; width: 100%; background: var(--accent); border-radius: 2px;
  transform-origin: left;
  transition: transform 1s linear, background 0.3s; /* scaleX로만 감소 — width 애니 금지 */
}
.t-fill.panic { background: var(--danger); }

.arena {
  flex: 1; min-height: 0;
  display: flex; flex-direction: column; justify-content: center; align-items: center;
  gap: 26px; overflow: hidden;
}
.problem {
  font-size: 58px; font-weight: 800; letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums; /* 문제 숫자 폭 고정 — 문제 바뀔 때 흔들림 방지 */
  display: flex; gap: 14px; align-items: center; line-height: 1;
}
.problem .op { color: var(--accent); font-weight: 700; font-size: 44px; }
.problem.in { animation: probIn 0.16s cubic-bezier(0.2, 0.9, 0.3, 1); } /* M1 */
@keyframes probIn { from { opacity: 0; transform: translateX(26px); } }
.arena.shake .problem, .arena.shake .answer { animation: shake 0.28s; } /* M3 */
@keyframes shake {
  20% { transform: translateX(-9px); } 40% { transform: translateX(8px); }
  60% { transform: translateX(-5px); } 80% { transform: translateX(3px); }
}
.answer {
  min-width: 130px; min-height: 56px;
  display: flex; justify-content: center; align-items: center; gap: 2px;
  font-size: 42px; font-weight: 800;
  border-bottom: 3px solid var(--line); padding: 0 10px 6px;
  transition: border-color 0.15s;
}
.answer.bad { border-color: var(--danger); }
.answer .caret { width: 2px; height: 36px; background: var(--accent); animation: blink 1s steps(1) infinite; }
@keyframes blink { 50% { opacity: 0; } }

.pad { display: grid; grid-template-columns: repeat(3, 1fr); gap: 9px; padding-top: 16px; flex: 0 0 auto; }
.pad .key {
  height: 60px; border: 1px solid var(--line); border-radius: 14px;
  background: var(--panel);
  font-family: var(--num); font-variant-numeric: tabular-nums;
  font-size: 24px; font-weight: 700; color: var(--text);
  transition: transform 0.08s, background 0.08s; /* M8 */
}
.pad .key:active { transform: scale(0.95); background: var(--panel-hi); }
.pad .key.fn { font-family: var(--sans); font-size: 15px; font-weight: 700; color: var(--muted); }
.pad .key.go { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); font-family: var(--sans); font-size: 17px; font-weight: 800; }
.pad .key.go:active { background: #e0451c; }

/* 마지막 5초 — 화면 가장자리 붉은 비네트 (M4, 터치 안 막음) */
.vignette {
  position: fixed; inset: 0; pointer-events: none; opacity: 0;
  transition: opacity 0.4s;
  box-shadow: inset 0 0 90px rgba(255, 46, 61, 0.5);
  z-index: 40;
}
body.last5 .vignette { opacity: 1; animation: vig 1s ease-in-out infinite; }
@keyframes vig { 50% { opacity: 0.45; } }

/* ---------- ④ 2P 차례 ---------- */
.handoff-body {
  flex: 1; min-height: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px;
}
.handoff-msg { font-size: 44px; font-weight: 800; letter-spacing: -0.02em; }

/* ---------- ⑤ 결과 ---------- */
.res-body {
  flex: 1; min-height: 0;
  display: flex; flex-direction: column; justify-content: center; align-items: center; gap: 10px;
}
.result-solo { display: flex; flex-direction: column; align-items: center; gap: 10px; }
.result-solo[hidden] { display: none; } /* display:flex가 hidden을 이기지 않게 */
.score-big { font-size: 112px; font-weight: 800; line-height: 1; letter-spacing: -0.03em; }
.score-unit { font-size: 16px; color: var(--muted); margin-top: -4px; }
.tag-best {
  margin-top: 14px; padding: 7px 14px; border-radius: 999px;
  border: 1.5px solid var(--accent); color: var(--accent);
  font-size: 13px; font-weight: 800; letter-spacing: 0.04em;
  transform: rotate(-2deg); /* 손맛 포인트 ②: 도장 삐딱하게 */
  animation: stamp 0.3s cubic-bezier(0.2, 1.6, 0.4, 1) both; animation-delay: 0.95s; /* M6 */
}
@keyframes stamp { from { opacity: 0; transform: rotate(-2deg) scale(1.6); } }
.res-detail { margin: 0; font-size: 13px; color: var(--muted); }
.result-solo .res-detail { margin-top: 18px; }
.res-detail b { color: var(--text); font-weight: 700; }

/* 겨루기 비교 — C안 "전광판" 26:19 대치 구도 차용, 색·타이포는 A안 토큰 */
.result-versus { width: 100%; display: flex; flex-direction: column; align-items: center; gap: 18px; }
.result-versus[hidden] { display: none; }
.duel { width: 100%; display: flex; align-items: center; gap: 10px; }
.duel-side {
  flex: 1; text-align: center;
  border: 1px solid var(--line); border-radius: 14px;
  background: var(--panel); padding: 18px 8px 14px;
}
.duel-side .who { font-size: 11px; font-weight: 700; letter-spacing: 0.2em; color: var(--muted); }
.duel-side .pts { font-size: 54px; font-weight: 800; line-height: 1.2; color: var(--muted); }
.duel-side.win { border-color: var(--accent); }
.duel-side.win .who, .duel-side.win .pts { color: var(--accent); }
.duel-colon { font-size: 30px; color: var(--muted); }
.duel-verdict { margin: 0; text-align: center; font-size: 15px; font-weight: 800; }
.duel-verdict b { color: var(--accent); }

/* ---------- 바텀시트 (페이월 · 게임 나가기 확인) ----------
   M11: 팝업 등장 모션 (지록 요청 2026-07-16 "팝업 등장은 모션을 넣어줘")
   스크림은 페이드, 시트는 아래에서 밀려 올라온다.

   ⚠️ transition 이 아니라 animation 을 쓰는 이유 (실측으로 갈아엎음):
      display:none → flex 로 바뀌는 요소에 transition 을 걸면 브라우저가 "전환 전 상태"를
      잡지 못해 그냥 최종값으로 점프해버린다. void offsetWidth 리플로우 트릭도 안 먹었다.
      animation 은 display 가 none→flex 가 되는 순간 알아서 처음부터 재생된다 —
      .screen 화면 전환(M10)과 똑같은 방식이라 한 가지 원리로 통일된다.
   ⚠️ 닫을 땐 .out 을 붙여 역재생시키고, 끝난 뒤에 hidden (game.js closeSheet). */
.sheet-scrim {
  position: fixed; inset: 0; z-index: 100;
  display: flex; align-items: flex-end;
  background: rgba(0, 0, 0, 0.6);
  animation: scrimIn 0.22s ease both;
}
.sheet-scrim[hidden] { display: none; }
.sheet {
  width: 100%;
  border-radius: 20px 20px 0 0;
  background: var(--panel); border-top: 1px solid var(--line);
  padding: 24px 22px calc(max(var(--sab), env(safe-area-inset-bottom)) + 18px);
  display: flex; flex-direction: column; gap: 12px;
  animation: sheetIn 0.28s cubic-bezier(0.2, 0.9, 0.3, 1) both;
}
@keyframes scrimIn { from { opacity: 0; } }
@keyframes sheetIn { from { transform: translateY(100%); } }

/* 닫힘 — 역재생 */
.sheet-scrim.out { animation: scrimOut 0.2s ease both; }
.sheet-scrim.out .sheet { animation: sheetOut 0.22s cubic-bezier(0.4, 0, 1, 1) both; }
@keyframes scrimOut { to { opacity: 0; } }
@keyframes sheetOut { to { transform: translateY(100%); } }
.sheet-title { font-size: 18px; font-weight: 800; display: flex; align-items: center; gap: 6px; }
.sheet-desc { margin: 0; font-size: 14px; color: var(--muted); line-height: 1.5; }
.sheet-note { margin: 0; text-align: center; font-size: 12px; color: var(--accent); }
.sheet-close { min-height: 44px; border: 0; background: none; color: var(--muted); font-size: 14px; font-weight: 600; }

/* ---------- 짧은 화면(375×520 등) — 한 화면 원칙 유지 ----------
   ⚠️ 헤더가 2줄(로고+슬로건)이 되며 9px 늘어 375×520 에서 시작 버튼이 광고바에 잘렸다.
      → 여기서 헤더·시작버튼을 같이 조여 되돌린다. 세로 여유가 없는 화면이라 한 곳만 줄여선 안 맞음. */
@media (max-height: 640px) {
  /* 워드마크 19.8 + gap 8 + 슬로건 10.8 ≈ 39 → 42 로 여유 3px */
  :root { --header-content-h: 42px; }
  .brand { gap: 8px; } /* 큰 화면 10px 을 조금만 줄임 — 벌린 티는 유지 */
  .wordmark { font-size: 18px; }
  .slogan { font-size: 9px; letter-spacing: 0.1em; }
  .hud { margin-top: 8px; }
  .setup { margin-top: 12px; gap: 12px; }
  .set-group .k-label { margin-bottom: 6px; }
  /* 헤더를 벌릴 때마다 여기서 되찾아야 한다 — 세로 여유가 없어 시작 버튼이 광고바에 바로 잘린다 */
  .start-zone { padding: 6px 0 10px; }
  .start-wrap { width: 98px; height: 98px; }
  .btn-start { inset: 13px; font-size: 16px; }
  .best-line { font-size: 12px; }
  .pad .key { height: 52px; }
  .arena { gap: 16px; }
  .problem { font-size: 44px; }
  .problem .op { font-size: 34px; }
  .answer { min-height: 46px; font-size: 34px; }
  .hud-num { font-size: 28px; }
  .score-big { font-size: 84px; }
  .res-actions { padding-top: 10px; gap: 8px; }
  .btn-big { height: 50px; }
  .btn-ghost { height: 44px; }
}
/* ── 게임물 표시의무 (게임산업법 제33조 + 시행령 별표3) ────────────────
   모바일게임물 표시 여섯: 제명 · 상호 · 이용등급 · 등급분류번호 · 제작연월일 ·
   게임물제작업자 등록번호.  등급 마크는 별표3 기준 가로 1cm × 세로 1.2cm 이상.
   ⚠️ 등급분류번호 한 칸은 아직 비어 있다 — 자체등급분류(구글 IARC)는 유통 뒤
      게임위로 연계되며 번호가 부여되는 것으로 보인다. 나오면 .law-rating 을 채운다.
   ⚠️ 등급 마크는 임시 도안이다. 게임위 공식 이미지로 교체할 것.
   정본: docs/개인사업자/게임물-표시의무.md */
/* margin-bottom 에 --sab 금지 — 컨테이너(base.css)가 이미 sab+18 을 비워둬서 이중이 된다
   (2026-08-20 실기기: © 줄이 48px 떠 보임) */
.law-mark{max-width:330px;margin:16px auto 6px;padding:0 14px}
.law-badge{width:10mm;height:12mm;min-width:34px;min-height:41px;flex:none}
.law-text{margin:0;text-align:center;font-size:10.5px;line-height:1.5;
  color:var(--muted);word-break:keep-all}

/* 초기화면 이용등급 표시 — 별표3 "게임 초기화면의 우측 상단에 3초 이상".
   하단 .law-mark 는 제작 정보(상호·등록번호·제작연월일)를 맡고, 등급 자체는 여기서 띄운다.
   3.4초 뒤 조용히 사라진다. 규정은 "3초 이상"이라 여유를 뒀다. */
.law-splash{position:fixed;top:calc(var(--sat, 0px) + 10px);right:12px;z-index:9999;
  width:10mm;height:12mm;min-width:34px;min-height:41px;pointer-events:none;
  filter:drop-shadow(0 2px 6px rgba(0,0,0,.25));transition:opacity .6s ease}
.law-splash.gone{opacity:0}
