/*
 * 한달음 윷놀이 — 전자칠판 우선 레이아웃.
 *
 * 구조 원칙 3가지 (전부 실측으로 데인 것):
 *  1) HUD 패딩과 소리 dock의 오른쪽 여백을 **같은 변수(--edge)** 로 묶는다. 따로 두면 어긋나 겹친다.
 *  2) dock 폭은 상수가 아니라 **높이에서 계산**한다(--dock-w). 상수면 버튼 2개가 넘쳐 HUD를 침범한다.
 *  3) 좁은 화면 글자는 dvh만으로는 **가로를 넘친다**. vw 상한을 반드시 병기한다.
 *
 * 세로 배치: HUD 25dvh / 스테이지 50dvh / 트레이 25dvh
 *  → 필수 터치(놀이판)가 정확히 화면 세로 25~75% 밴드에 들어간다.
 */

:root {
  --bg: #22303f;
  --bg2: #2b3b4d;
  --ink: #f2f7fc;
  --ink-dim: #b9c9dc;
  --accent: #ffd451;
  --line: #46596e;

  --edge: 1vw;
  --dock-h: clamp(56px, 8.6dvh, 112px);
  --dock-w: calc(var(--dock-h) * 2 + var(--edge));

  --fs-value: clamp(30px, 9.6dvh, 150px);   /* 1080 → 103.7px  (핵심 수치 ≥96) */
  --fs-body:  clamp(14px, 4.7dvh, 62px);    /* 1080 →  50.8px  (본문 ≥48)      */
  /* ⚠️ 처음 3.0dvh(=32.4px @1080)로 뒀다가 QA에 걸렸다. 이 티어가 쓰이는 곳이
     **분포 그래프 라벨·로스터 상태줄** — 즉 이 게임의 교육 payload 자체다.
     6~8m 뒤에서 읽혀야 하므로 본문 하한 48px을 똑같이 지켜야 한다. */
  --fs-small: clamp(11px, 4.5dvh, 50px);
  --fs-huge:  clamp(44px, 16dvh, 240px);
}

* { box-sizing: border-box; margin: 0; padding: 0; }

html, body {
  height: 100%;
  background: var(--bg);
  color: var(--ink);
  font-family: system-ui, -apple-system, 'Segoe UI', 'Apple SD Gothic Neo', 'Malgun Gothic', sans-serif;
  overflow: hidden;
  -webkit-text-size-adjust: 100%;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  user-select: none;
}

/* ── 화면 전환 ─────────────────────────────── */
.screen {
  position: fixed; inset: 0;
  display: none;
  flex-direction: column;
  align-items: center; justify-content: center;
  gap: 1.6dvh;
  padding: 2dvh var(--edge);
  text-align: center;
}
.screen.is-on { display: flex; }
#scr-play.is-on { justify-content: flex-start; gap: 0; padding: 0; }

/* ── 소리 dock ─────────────────────────────── */
.sound-dock {
  position: fixed; top: var(--edge); right: var(--edge);
  z-index: 40; display: flex; gap: calc(var(--edge) * 0.5);
}
.sound-btn {
  width: var(--dock-h); height: var(--dock-h);
  font-size: calc(var(--dock-h) * 0.55);
  line-height: 1;
  border: 3px solid var(--line);
  border-radius: 18px;
  background: var(--bg2); color: var(--ink);
  cursor: pointer;
}
.sound-btn.is-off { opacity: 0.38; }

/* ── HUD ───────────────────────────────────── */
.hud {
  width: 100%; height: 25dvh;
  display: grid;
  grid-template-columns: var(--dock-w) 1fr 1fr 1fr var(--dock-w);
  align-items: center;
  padding: 0 var(--edge);
}
.hud-slot { min-width: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 0.4dvh; }
.hud-label { font-size: var(--fs-body); color: var(--ink-dim); font-weight: 700; white-space: nowrap; }
.hud-label .sm { display: none; }
.hud-value {
  font-size: var(--fs-value); font-weight: 800; line-height: 1;
  font-variant-numeric: tabular-nums;
  white-space: nowrap; max-width: 100%;
  display: flex; align-items: center; gap: 0.18em;
}
.hud-value.is-low { color: #ff8f7a; }
/* 결승선이 걸린 순간(누군가 목표 도달 · 안전망 30초) — 이 칸만 조여든다 */
.hud-slot.is-final .hud-label { color: var(--accent); }
.hud-slot.is-final { animation: goalPulse 1s ease-in-out infinite; }
@keyframes goalPulse { 0%, 100% { transform: scale(1) } 50% { transform: scale(1.06) } }
.hud-mark { font-size: 0.92em; }

/* ── 스테이지 (세로 25~75% 밴드) ─────────────── */
.stage {
  width: 100%; height: 50dvh;
  display: grid;
  grid-template-columns: minmax(0, 24vw) auto minmax(0, 24vw);
  /* ⚠️ `auto` 행으로 두면 캔버스 고유크기(600px)가 행을 부풀려 50dvh 컨테이너를 뚫고 나간다.
     실측: 스테이지 540px인데 놀이판이 600px → 밴드가 25~80.6%로 벗어났다.
     `minmax(0, 1fr)`이라야 행이 컨테이너 높이에 고정되고 내용보다 작아질 수 있다. */
  grid-template-rows: minmax(0, 1fr);
  justify-content: center; align-items: center;
  gap: var(--edge);
  padding: 0 var(--edge);
}
.board-wrap { height: 100%; max-height: 100%; aspect-ratio: 1 / 1; }
#board { display: block; width: 100%; height: 100%; max-width: 100%; max-height: 100%; cursor: pointer; }

.side { height: 100%; min-width: 0; display: flex; flex-direction: column; justify-content: center; gap: 0.8dvh; }
.side-left { align-items: flex-start; }
.side-right { align-items: stretch; }

/* 순서 로스터 */
.rosterline {
  display: flex; align-items: center; gap: 0.4em;
  font-size: var(--fs-small); font-weight: 700; color: var(--ink-dim);
  white-space: nowrap; max-width: 100%; overflow: hidden;
}
.rosterline.is-now { color: var(--ink); font-size: var(--fs-body); }
.rosterline .dot { font-size: 1.15em; }
/* 목표까지의 막대 — 승리 조건이 시간에서 점수로 바뀐 뒤, 이게 곧 "남은 시간"이다.
   숫자만 있으면 24와 223과 400을 머리로 빼야 하는데 그 계산이 곧 흥미의 손실이다. */
.rosterline .rbar {
  flex: 1 1 3.2em; max-width: 7em; min-width: 2.4em; height: 0.55em;
  border-radius: 999px; background: rgba(255, 255, 255, 0.16); overflow: hidden;
}
.rosterline .rfill {
  display: block; height: 100%; width: 0; border-radius: 999px;
  transition: width .18s linear;
}
.rosterline .rfill.is-done { box-shadow: 0 0 0 2px var(--accent); }
/* 대기 중인 말 — 점으로 표시한다. 숫자를 하나 더 늘리면 점수와 헷갈린다 */
.rosterline .wait { color: var(--ink-dim); letter-spacing: 0.12em; font-size: 1.3em; line-height: 0.6; }
.statline { font-size: var(--fs-small); color: var(--ink-dim); white-space: nowrap; }
.statline b { color: var(--ink); font-size: 1.25em; }

/* 실측 분포 그래프 — 이 게임이 킹수학에 있을 이유 */
.dist-head {
  display: flex; justify-content: space-between; align-items: baseline;
  font-size: var(--fs-small); color: var(--ink-dim); font-weight: 700;
  padding-bottom: 0.4dvh; border-bottom: 2px solid var(--line);
}
.dist-legend::before {
  content: ''; display: inline-block; width: 1.4em; height: 0;
  border-top: 3px dashed var(--accent); margin-right: 0.4em; vertical-align: middle;
}
.dist { display: flex; flex-direction: column; gap: 0.5dvh; margin-top: 0.6dvh; }
.dist-row { display: grid; grid-template-columns: 3.3em 1fr 2.1em; align-items: center; gap: 0.35em; font-size: var(--fs-small); }
.dist-name { font-weight: 800; color: var(--ink); white-space: nowrap; }
.dist-track { position: relative; height: 1.5em; background: #1a2430; border-radius: 5px; overflow: hidden; }
.dist-bar { position: absolute; inset: 0 auto 0 0; background: #6ba3d6; border-radius: 5px; transition: width .18s ease-out; }
.dist-theory { position: absolute; top: -2px; bottom: -2px; width: 0; border-left: 3px dashed var(--accent); }
.dist-n { text-align: right; font-variant-numeric: tabular-nums; color: var(--ink); font-weight: 700; }

/* ── 트레이 ───────────────────────────────────
   가운데 열(윷·끗수·힌트)은 표시 전용이다. 건너뛰기만 오른쪽 끝에 따로 앉힌다 —
   놀이판 탭이 몰리는 중앙에서 떼어 놓아야 남의 차례를 실수로 날리지 않는다.
   (필수 터치인 굴리기·말 고르기는 여전히 세로 25~75% 안에만 있다. 건너뛰기는 이탈 대비 탈출구다.) */
.tray {
  position: relative;
  width: 100%; height: 25dvh;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 0.8dvh; padding: 0 var(--edge);
}
.tray .btn-skip {
  position: absolute; right: var(--edge); top: 50%; transform: translateY(-50%);
  min-width: 88px; min-height: 88px;              /* 트랙 HARD: 터치 타겟 ≥88px */
  font-size: var(--fs-small); padding: 0.4em 0.7em;
  opacity: 0.62;
}
.tray .btn-skip:active { opacity: 1; }

/* 한 번 더(윷·모·잡기) — "기기를 넘기지 마라"는 신호라 놓치면 판이 꼬인다 */
.again-badge {
  font-size: var(--fs-body); font-weight: 800; color: #141d27;
  background: var(--accent); border-radius: 999px; padding: 0.15em 0.8em;
  animation: againPop .5s ease-out;
}
.again-badge[hidden] { display: none; }
@keyframes againPop { from { transform: scale(0.6); opacity: 0 } to { transform: scale(1); opacity: 1 } }

/* 차례가 넘어간 직후 — 기기를 물리적으로 넘기는 순간이라 3m 밖에서도 보여야 한다 */
.hud-who.is-flash { animation: turnFlash .45s ease-out 2; }
@keyframes turnFlash {
  0%, 100% { transform: scale(1); filter: none }
  50% { transform: scale(1.12); filter: brightness(1.5) }
}
@media (prefers-reduced-motion: reduce) {
  .hud-who.is-flash { animation: none; outline: 4px solid var(--accent); border-radius: 12px; }
  .again-badge { animation: none; }
  .hud-slot.is-final { animation: none; }
  .hint.is-catch { animation: none; }
}
/* 던지는 순간이 이 게임에서 가장 자주 반복되는 동작이다 — 여기가 밋밋하면 게임 전체가 밋밋하다.
   원래 translateY(-14%)로 살짝 떨기만 했고, 실플레이 결론이 "노잼"이었다. */
.sticks { display: flex; gap: clamp(6px, 1.2dvh, 18px); height: 10dvh; }
.sticks.is-land { animation: landSquash .26s ease-out; }
@keyframes landSquash {
  0%   { transform: translateY(-20%) scaleY(1.12); }
  45%  { transform: translateY(0) scaleY(0.82); }
  100% { transform: none; }
}
.stick {
  width: clamp(15px, 2.8dvh, 38px); height: 100%;
  border-radius: 999px; border: 3px solid #141d27;
  background: #6b543a;                               /* 등(둥근 면) */
  position: relative; transition: transform .12s, background .1s;
}
.stick.is-flat { background: #f0e2c8; }              /* 배(평평한 면) */
.stick.is-flat::after {
  content: ''; position: absolute; left: 50%; top: 18%; bottom: 18%;
  width: 3px; margin-left: -1.5px; background: #8d6f4b; border-radius: 2px;
}
/* 네 개가 한 몸처럼 떨면 "구른다"가 아니라 "떤다"로 보인다 → 개별 지연으로 어긋나게 */
.stick.is-rolling { animation: tumble .3s cubic-bezier(.4, 0, .6, 1) infinite; }
.stick:nth-child(2).is-rolling { animation-delay: -.075s; }
.stick:nth-child(3).is-rolling { animation-delay: -.15s; }
.stick:nth-child(4).is-rolling { animation-delay: -.225s; }
@keyframes tumble {
  0%   { transform: translateY(0) rotate(0deg) scaleY(1); }
  30%  { transform: translateY(-72%) rotate(150deg) scaleY(0.86); }
  60%  { transform: translateY(-32%) rotate(300deg) scaleY(1.08); }
  100% { transform: translateY(0) rotate(360deg) scaleY(1); }
}

.roll-out { display: flex; align-items: baseline; gap: 0.4em; min-height: 1.05em; }
.roll-name { font-size: var(--fs-value); font-weight: 800; line-height: 1; color: var(--accent); }
/* 끗수가 정해지는 순간 = 이 게임에서 가장 기다리는 순간 */
.roll-name.is-pop { animation: rollPop .4s cubic-bezier(.2, 1.6, .4, 1); }
@keyframes rollPop {
  0%   { transform: scale(0.3); opacity: 0; }
  60%  { transform: scale(1.28); opacity: 1; }
  100% { transform: scale(1); }
}
/* 윷·모 = 한 번 더. 눈에 띄어야 "오!" 소리가 나온다 */
.roll-name.is-extra { text-shadow: 0 0 22px rgba(255, 212, 81, 0.75); }
@media (prefers-reduced-motion: reduce) {
  .stick.is-rolling, .sticks.is-land, .roll-name.is-pop { animation: none; }
}
.roll-steps { font-size: var(--fs-body); font-weight: 700; color: var(--ink-dim); }
.hint { font-size: var(--fs-body); font-weight: 700; color: var(--ink-dim); white-space: nowrap; }
/* 잡을 수 있는 자리가 있을 때 — 판 위 표식(가시 링·붉은 ✕)과 **같은 색**으로 묶는다.
   그림과 글자가 따로 놀면 "이 표식이 그 말이었나"를 또 연결해야 한다. */
.hint.is-catch { color: #ff6b60; font-weight: 800; animation: catchPulse .9s ease-in-out infinite; }
@keyframes catchPulse { 0%, 100% { opacity: 1 } 50% { opacity: 0.55 } }
.safe-gap { height: 0; }

/* ── 시작 / 핸드오프 / 카운트 / 결과 ─────────── */
.title { font-size: clamp(30px, 9dvh, 132px); font-weight: 800; letter-spacing: -0.02em; }
.tagline { font-size: var(--fs-body); color: var(--ink-dim); }
.pick-label { font-size: var(--fs-body); font-weight: 700; margin-top: 1dvh; }
.pick { display: flex; flex-wrap: wrap; justify-content: center; gap: clamp(8px, 1.4dvh, 22px); }
.pick-btn {
  width: clamp(60px, 11dvh, 150px); height: clamp(60px, 11dvh, 150px);
  font-size: clamp(24px, 5.4dvh, 72px); font-weight: 800;
  border: 4px solid var(--line); border-radius: 22px;
  background: var(--bg2); color: var(--ink); cursor: pointer;
}
.pick-btn.is-on { border-color: var(--accent); background: #3c4f66; }
.best { font-size: var(--fs-body); color: var(--ink-dim); min-height: 1.2em; }
.sunhaengssam-link {
  position: absolute;
  left: 50%;
  bottom: max(1.5dvh, env(safe-area-inset-bottom, 0px));
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 0.5em 1.4em;
  border-radius: 999px;
  background: var(--bg2);
  color: var(--ink-dim);
  font-size: clamp(12px, 2.4dvh, 20px);
  font-weight: 600;
  text-decoration: none;
  text-align: center;
  max-width: min(92vw, 420px);
}

.handoff-turn { font-size: var(--fs-huge); font-weight: 800; line-height: 1; display: flex; align-items: center; gap: 0.2em; }
.handoff-sub { font-size: var(--fs-body); color: var(--ink-dim); font-weight: 700; }
.roster { display: flex; flex-wrap: wrap; justify-content: center; gap: 0.6em; font-size: var(--fs-body); color: var(--ink-dim); }
.row { display: flex; gap: clamp(10px, 1.6dvh, 26px); flex-wrap: wrap; justify-content: center; }
.btn {
  min-width: clamp(120px, 22dvh, 300px);
  min-height: clamp(60px, 10dvh, 132px);
  padding: 0 1em;
  font-size: clamp(20px, 4.6dvh, 60px); font-weight: 800;
  border: 4px solid var(--line); border-radius: 22px;
  background: var(--bg2); color: var(--ink); cursor: pointer;
}
.btn-go { background: var(--accent); color: #1d1704; border-color: #caa42e; }

.count-num { font-size: clamp(70px, 30dvh, 440px); font-weight: 800; line-height: 1; color: var(--accent); }
.count-sub { font-size: var(--fs-body); color: var(--ink-dim); }

.result-head { font-size: clamp(26px, 7dvh, 96px); font-weight: 800; }
.result-table { display: flex; flex-direction: column; gap: 0.5dvh; width: min(92vw, 900px); }
.result-row {
  /* 던진 횟수 칸이 하나 늘었다 — 점수는 목표에서 멈추므로 실력은 횟수에 남는다 */
  display: grid; grid-template-columns: 2.2em 1fr auto auto;
  align-items: center; gap: 0.5em;
  font-size: var(--fs-body); font-weight: 700;
  background: var(--bg2); border-radius: 14px; padding: 0.35em 0.7em;
}
.result-row.is-top { background: #3f5470; border: 3px solid var(--accent); }
.result-row .sc { font-variant-numeric: tabular-nums; font-size: 1.25em; }
.result-row .thr {
  font-variant-numeric: tabular-nums; color: var(--ink-dim);
  font-size: 0.85em; font-weight: 700; white-space: nowrap;
}
.result-note { font-size: var(--fs-small); color: var(--ink-dim); }

/* ── 좁은 화면 (스마트폰) ────────────────────
   dvh 기준 글자는 여기서 가로를 넘친다 → vw 상한 병기가 핵심이다. */
@media (max-width: 899px) {
  :root {
    --edge: 2vw;
    --dock-h: clamp(50px, 7dvh, 64px);
    --fs-value: clamp(22px, 8.6vw, 46px);
    --fs-body:  clamp(12px, 4.4vw, 23px);
    --fs-small: clamp(10px, 3.2vw, 17px);
    --fs-huge:  clamp(40px, 17vw, 96px);
  }
  .hud-label .lg { display: none; }
  .hud-label .sm { display: inline; }
  /* 폰에서는 dock 예약 열이 HUD 가로의 61%를 먹어 슬롯이 48px로 눌렸다(실측 텍스트 59px 넘침).
     → dock을 세로 스택으로 바꾸고 **오른쪽 한 칸만** 예약한다. */
  .sound-dock { flex-direction: column; }
  .hud { grid-template-columns: 1fr 1fr 1fr calc(var(--dock-h) + var(--edge)); }
  .hud-pad:first-child { display: none; }
  .stage {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto minmax(0, 1fr) auto;
    gap: 0.6dvh;
  }
  .board-wrap { height: 100%; aspect-ratio: 1 / 1; margin: 0 auto; max-width: 100%; }
  /* ⚠️ 순차 교대판에서는 여기가 `display:none`이었다. 한 번에 한 명만 뛰니 남의 점수가
     화면에 없어도 됐기 때문이다. **턴제에서는 누가 앞서는지가 곧 게임**이라 지우면 안 된다.
     세로 목록 대신 가로 한 줄로 접어 board 위에 올린다. */
  .side-left { flex-direction: row; flex-wrap: wrap; justify-content: center; height: auto; gap: 0.7em; }
  .side-left .rosterline { gap: 0.15em; }
  .side-left .statline { flex-basis: 100%; text-align: center; }
  .side-right { height: auto; }
  .dist { flex-direction: row; gap: 0.4em; }
  .dist-row { grid-template-columns: 1fr; grid-template-rows: auto auto auto; justify-items: center; gap: 0.1em; flex: 1; }
  .dist-track { width: 100%; height: 0.9em; }
  .sticks { height: 6dvh; }
  .hint { white-space: normal; }
}

@media (max-width: 899px) and (orientation: landscape) {
  /* ⚠️ 여기 `1fr`로 뒀다가 짧은 가로 창(728×412)에서 **놀이판이 694px로 창을 뚫고 나갔다.**
     `1fr` = `minmax(auto, 1fr)`이라 캔버스 고유크기(600px)가 행의 최소 높이를 밀어올린다.
     세로 레이아웃에서 같은 실수를 이미 한 번 했는데(밴드가 25~80.6%로 이탈) 이 분기에만 남아 있었다.
     → **모든 그리드 행·열은 `minmax(0, …)`으로 쓴다.** QA 뷰포트에 짧은 가로를 추가해 지킨다. */
  .stage { grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); grid-template-rows: minmax(0, 1fr); }
  .side-left { flex-direction: column; height: 100%; justify-content: center; }
  .side-left .statline { flex-basis: auto; text-align: left; }
  .side-right { height: 100%; }
  .dist { flex-direction: column; }
  .dist-row { grid-template-columns: 2.6em 1fr 1.8em; grid-template-rows: auto; justify-items: stretch; }
}
/* @gb-juice-css v1 — kit/juice/juice.css. 게임 스타일시트 끝에 그대로 붙인다(CSP style-src 'self' 라 JS 가 <style> 을 넣지 않는다). */
.gbj-layer{position:fixed;inset:0;pointer-events:none;z-index:40;overflow:hidden}
.gbj-pop{position:absolute;transform:translate(-50%,-50%) scale(var(--s));font:900 22px/1 system-ui,sans-serif;text-shadow:0 2px 0 #0008,0 0 12px currentColor;white-space:nowrap;animation:gbjPop .9s cubic-bezier(.2,1.6,.4,1) forwards}
@keyframes gbjPop{0%{opacity:0;transform:translate(-50%,-50%) scale(calc(var(--s)*.3))}15%{opacity:1;transform:translate(-50%,-80%) scale(calc(var(--s)*1.35))}35%{transform:translate(calc(-50% + var(--dx)),-120%) scale(var(--s))}100%{opacity:0;transform:translate(calc(-50% + var(--dx)),-260%) scale(calc(var(--s)*.9))}}
.gbj-punch{animation:gbjPunch .32s cubic-bezier(.2,2,.4,1)}
@keyframes gbjPunch{0%{transform:scale(1)}30%{transform:scale(var(--gbj-p))}100%{transform:scale(1)}}
.gbj-flash{position:absolute;inset:0;opacity:0}
.gbj-flash.gbj-go{animation:gbjFlash .35s ease-out forwards}
@keyframes gbjFlash{to{opacity:0}}
/* 가운데 큰 글자 — 자리는 게임이 --gbj-banner-top 으로 옮긴다(HUD 배너·선택 카드와 겹치지 않게 · 2026-10-12 끝까지 진화 실측). 좁은 화면에서 넘치지 않게 vw 로 줄인다 */
.gbj-banner{position:absolute;left:50%;top:var(--gbj-banner-top,40%);transform:translate(-50%,-50%);font:900 clamp(22px,8vw,44px)/1.1 system-ui,sans-serif;text-align:center;opacity:0;text-shadow:0 3px 0 #000a,0 0 24px currentColor;max-width:92vw;width:max-content}
.gbj-banner.gbj-go{animation:gbjBan var(--d,1.4s) cubic-bezier(.2,1.5,.4,1) forwards}
@keyframes gbjBan{0%{opacity:0;transform:translate(-50%,-50%) scale(.2) rotate(-8deg)}15%{opacity:1;transform:translate(-50%,-50%) scale(1.25) rotate(2deg)}30%{transform:translate(-50%,-50%) scale(1)}80%{opacity:1}100%{opacity:0;transform:translate(-50%,-70%) scale(1.05)}}
@media (prefers-reduced-motion:reduce){.gbj-pop,.gbj-banner.gbj-go,.gbj-punch{animation-duration:.01s}}
