:root{--ink:#10151c;--paper:#f7fafd;--line:#d7e2ec;--accent:#1f6fd0;--warn:#c8442f;--ok:#1a7f4b;
--hud:rgba(9,14,22,.72);--font:"Pretendard Variable",system-ui,-apple-system,"Segoe UI",sans-serif}
*{box-sizing:border-box;-webkit-tap-highlight-color:transparent}
html,body{margin:0;height:100%;background:#0b1017;color:var(--ink);font-family:var(--font);overscroll-behavior:none;touch-action:none;
 -webkit-user-select:none;user-select:none;-webkit-touch-callout:none}
/* 🔴 입력란·순위표만 선택 허용 — 나머지를 선택 가능하게 두면 안드로이드에서 롱프레스가 «선택 핸들» 을 띄우고,
   그 뒤의 손가락 드래그가 스틱이 아니라 선택 범위를 끌게 된다(실측: 주행 중 HUD 가 통째로 파랗게 선택됨). */
input,textarea,#board,#lic,.lic{-webkit-user-select:text;user-select:text}
#app{position:fixed;inset:0;overflow:hidden}
canvas#gl{position:absolute;inset:0;width:100%;height:100%;display:block}
.screen{position:absolute;inset:0;display:none;flex-direction:column;align-items:center;justify-content:center;
 background:linear-gradient(160deg,#eaf3fb,#cfe0f0);padding:20px;gap:14px;overflow-y:auto}
/* 🔴 플레이 화면은 «캔버스 위의 투명 레이어»다. 여기에 배경을 깔면 3D 가 통째로 가려진다(실측). */
#play{background:none;padding:0;pointer-events:none}
/* 🔴 #stick 은 «표시» 전용이다 — 여기에 pointer-events:auto 를 주면(id 2개라 특이도가 더 높다)
   원 위를 누른 손가락이 스틱 영역(#stickZone)의 핸들러에 닿지 못한다(D21 실측 stickOk=false). */
#play button,#play #stickZone,#play .btn{pointer-events:auto}
#play #stick,#play #knob{pointer-events:none}
.screen.on{display:flex}
.card{background:#fff;border:1px solid var(--line);border-radius:16px;padding:18px 20px;max-width:520px;width:100%;
 box-shadow:0 10px 30px rgba(16,32,54,.12)}
h1{font-size:26px;margin:0 0 2px}
h2{font-size:19px;margin:0 0 8px}
.sub{color:#4a5b6c;font-size:14px;margin:0}
button{font:inherit;font-weight:700;border:0;border-radius:12px;padding:14px 18px;background:var(--accent);color:#fff;
 min-height:48px;min-width:48px;cursor:pointer}
button.ghost{background:#eef3f8;color:#22303f;border:1px solid var(--line)}
button[disabled]{opacity:.45;cursor:not-allowed}
.row{display:flex;gap:10px;flex-wrap:wrap;align-items:center}
.grid{display:grid;grid-template-columns:1fr 1fr;gap:8px}
table{width:100%;border-collapse:collapse;font-size:14px}
th,td{padding:7px 6px;border-bottom:1px solid var(--line);text-align:left}
td.num,th.num{text-align:right;font-variant-numeric:tabular-nums}
tr.me{background:#e8f1fd;font-weight:700}
/* HUD */
#hud{position:absolute;inset:0;pointer-events:none;font-variant-numeric:tabular-nums}
#hud .tl{position:absolute;left:12px;top:10px;max-width:38vw;color:#fff;text-shadow:0 2px 6px rgba(0,0,0,.55)}
#hud .tr{position:absolute;right:12px;top:10px;max-width:34vw;color:#fff;text-align:right;text-shadow:0 2px 6px rgba(0,0,0,.55)}
#hud .bc{position:absolute;left:50%;transform:translateX(-50%);bottom:96px;color:#fff;text-align:center;text-shadow:0 2px 6px rgba(0,0,0,.55)}
#hud .big{font-size:30px;font-weight:800;line-height:1.05}
#hud .lbl{font-size:11px;opacity:.85;letter-spacing:.04em}
#hud .chip{display:inline-block;background:var(--hud);border-radius:999px;padding:5px 10px;font-size:12px;color:#fff;margin-right:6px}
#toast{position:absolute;left:50%;top:14%;transform:translateX(-50%);background:var(--hud);color:#fff;padding:9px 14px;
 border-radius:999px;font-size:14px;opacity:0;transition:opacity .18s}
#toast.on{opacity:1}
#vignette{position:absolute;inset:0;pointer-events:none;opacity:0;transition:opacity .25s;
 background:radial-gradient(ellipse at center,rgba(0,0,0,0) 52%,rgba(0,0,0,.42) 100%)}
#lines{position:absolute;inset:0;pointer-events:none;opacity:0;transition:opacity .2s;
 background:repeating-linear-gradient(90deg,rgba(255,255,255,.10) 0 2px,transparent 2px 64px)}
/* 결과 피드백 — «통과/실패를 몸으로 알 수 있게». 소리만으로는 아무도 못 알아챈다(사용자 지적). */
#flash{position:absolute;inset:0;pointer-events:none;opacity:0;transition:opacity .5s ease-out}
#flash.ok{background:radial-gradient(ellipse at center,rgba(26,200,120,0) 45%,rgba(26,200,120,.55) 100%);opacity:1;transition:none}
#flash.bad{background:radial-gradient(ellipse at center,rgba(220,60,40,0) 40%,rgba(220,60,40,.7) 100%);opacity:1;transition:none}
#burst{position:absolute;left:50%;top:34%;transform:translate(-50%,-50%) scale(.7);pointer-events:none;
 font-size:52px;font-weight:900;letter-spacing:-.02em;opacity:0;color:#fff;
 text-shadow:0 4px 18px rgba(0,0,0,.6),0 0 26px currentColor}
#burst.on{animation:burstPop .72s cubic-bezier(.16,1,.3,1) forwards}
#burst.ok{color:#2ee08a}#burst.bad{color:#ff6a54}#burst.big{color:#ffd166}
@keyframes burstPop{
 0%{opacity:0;transform:translate(-50%,-50%) scale(.55)}
 22%{opacity:1;transform:translate(-50%,-50%) scale(1.14)}
 55%{opacity:1;transform:translate(-50%,-50%) scale(1)}
 100%{opacity:0;transform:translate(-50%,-58%) scale(1)}}
#combo{position:absolute;left:50%;top:46%;transform:translateX(-50%);pointer-events:none;
 font-size:20px;font-weight:800;color:#ffd166;opacity:0;text-shadow:0 2px 10px rgba(0,0,0,.6)}
#combo.on{animation:comboPop .8s ease-out forwards}
@keyframes comboPop{0%{opacity:0;transform:translateX(-50%) translateY(6px)}25%{opacity:1;transform:translateX(-50%) translateY(0)}100%{opacity:0}}
#play.shake{animation:shake .32s}
@keyframes shake{0%,100%{transform:translate(0,0)}20%{transform:translate(-7px,3px)}40%{transform:translate(6px,-3px)}60%{transform:translate(-4px,-2px)}80%{transform:translate(3px,2px)}}
@media (prefers-reduced-motion:reduce){#burst.on,#combo.on,#play.shake{animation:none}#burst.on,#combo.on{opacity:1}}
/* 터치 컨트롤 */
#touch{position:absolute;inset:0;pointer-events:none;display:none}
/* 왼쪽 아래 «영역» 전체가 스틱이다 — 132 px 원을 정확히 짚어야만 조향되면 폰에서는 «안 먹는다» 가 된다. */
#stickZone{position:absolute;left:0;bottom:0;width:52%;height:56%;pointer-events:auto;touch-action:none}
#touch.on{display:block}
#stick{position:absolute;left:18px;bottom:calc(18px + env(safe-area-inset-bottom,0px));width:132px;height:132px;border-radius:50%;transition:opacity .12s;
 background:rgba(255,255,255,.14);border:2px solid rgba(255,255,255,.4);pointer-events:none}
#knob{position:absolute;left:50%;top:50%;width:56px;height:56px;margin:-28px 0 0 -28px;border-radius:50%;background:rgba(255,255,255,.85)}
.btn{position:absolute;width:74px;height:74px;border-radius:50%;background:rgba(255,255,255,.18);
 border:2px solid rgba(255,255,255,.45);color:#fff;font-size:13px;font-weight:800;display:flex;align-items:center;
 justify-content:center;pointer-events:auto;user-select:none}
#bTuck{right:118px;bottom:calc(104px + env(safe-area-inset-bottom,0px))}
#bBrake{right:22px;bottom:calc(104px + env(safe-area-inset-bottom,0px))}
#bJump{right:70px;bottom:calc(22px + env(safe-area-inset-bottom,0px))}
/* 시점 버튼은 «오른쪽 위» 에 두면 체크포인트 표시와 겹친다(실측 4뷰포트 전부) — 스틱 위로 옮긴다 */
#bView{left:22px;bottom:calc(160px + env(safe-area-inset-bottom,0px));width:56px;height:56px;font-size:12px}
#pauseBtn{position:absolute;left:50%;transform:translateX(-50%);top:10px;width:56px;height:48px;pointer-events:auto;font-size:12px;padding:0}
#quitBtn{position:absolute;left:50%;transform:translateX(calc(-50% + 64px));top:10px;width:56px;height:48px;pointer-events:auto;font-size:12px;padding:0}
/* 전체화면 버튼 — 좁은 폰에서 가운데 줄에 두면 체크포인트 표시와 겹친다(실측 360·390 폭).
   체크포인트 «아래» 오른쪽 끝에 붙인다. 지원하지 않는 브라우저에서는 hidden 이라 자리도 안 차지한다. */
#fsBtn{position:absolute;right:12px;top:46px;width:64px;height:40px;pointer-events:auto;font-size:12px;padding:0}
@media (max-width:420px){#hud .big{font-size:24px}}
@media (prefers-reduced-motion:reduce){#vignette,#lines{transition:none}}

.lic { margin: 10px 0 4px; padding-left: 18px; line-height: 1.75; font-size: 13px; color: var(--fg-2, #46505c); }
.lic code { font-size: 12px; background: rgba(0,0,0,.05); padding: 1px 4px; border-radius: 4px; }

/* 인라인 style 속성 0 — CSP style-src 'self' 에서 인라인 스타일은 «차단»된다(실측 콘솔 에러 15건) */
.hr-soft { border: 0; border-top: 1px solid var(--line); margin: 14px 0; }
.big-num { font-size: 28px; font-weight: 800; }
.mt6 { margin-top: 6px; } .mt8 { margin-top: 8px; } .mt12 { margin-top: 12px; } .mt14 { margin-top: 14px; }
.my10 { margin: 10px 0; } .my12 { margin: 12px 0; } .my12b { margin: 12px 0 4px; }
.list-in { margin: 0 0 12px 18px; }

/* ── 기록 HUD (델타·스플릿·밸런스) ─────────────────────────────────────────── */
/* 🔴 델타는 «지금 PB보다 앞서는가»를 한눈에 — 색만으로 말하지 않고 부호까지 쓴다(색각이상). */
#hud .tc{position:absolute;left:50%;transform:translateX(-50%);top:64px;text-align:center;
 color:#fff;text-shadow:0 2px 8px rgba(0,0,0,.6);pointer-events:none}
#hud .delta{font-size:22px;font-weight:800;letter-spacing:.01em;min-height:26px}
#hud .delta.ahead{color:#7ef0b2}
#hud .delta.behind{color:#ff9a8b}
#hud .split{font-size:13px;opacity:0;transition:opacity .25s;margin-top:2px}
#hud .split.on{opacity:1}
#hud .bl{position:absolute;left:12px;bottom:calc(150px + env(safe-area-inset-bottom,0px));color:#fff;
 text-shadow:0 2px 6px rgba(0,0,0,.55);opacity:0;transition:opacity .2s}
#hud .bl.on{opacity:1}
#hBalWrap{width:120px;height:9px;border-radius:999px;background:rgba(255,255,255,.28);overflow:hidden;margin-top:4px}
#hBal{height:100%;width:100%;background:#7ef0b2;transition:width .1s linear,background .2s}
#hBal.warn{background:#ffd166}
#hBal.danger{background:#ff6b5e}
@keyframes balPulse{0%,100%{opacity:1}50%{opacity:.45}}
#hud .bl.danger{animation:balPulse .5s infinite}

/* ── 선택 화면·기록실 ─────────────────────────────────────────────────────── */
.card.wide{max-width:860px}
.cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:8px;margin:8px 0 4px}
.pick{text-align:left;background:var(--card-2,rgba(255,255,255,.06));border:2px solid var(--line);
 border-radius:12px;padding:10px;cursor:pointer;color:inherit;font:inherit;width:100%}
.pick:hover{border-color:#8ab4f8}
.pick[aria-pressed="true"]{border-color:#2f6fd0;background:rgba(47,111,208,.12)}
.pick b{display:block;font-size:15px;margin-bottom:2px}
.pick .meta{font-size:12px;opacity:.82;line-height:1.5}
.pick .tags{margin-top:6px;display:flex;flex-wrap:wrap;gap:4px}
.pick .tag{font-size:11px;padding:2px 6px;border-radius:999px;background:rgba(0,0,0,.08)}
.pick .dot{display:inline-block;width:10px;height:10px;border-radius:50%;margin-right:6px;vertical-align:-1px}
.bars{margin-top:6px;font-size:11px;line-height:1.7}
.bar{display:inline-block;width:52px;height:6px;border-radius:999px;background:rgba(0,0,0,.12);
 vertical-align:middle;margin-left:6px;overflow:hidden}
.bar i{display:block;height:100%;background:#2f6fd0}
table.rec{width:100%;border-collapse:collapse;font-size:13px}
table.rec th,table.rec td{padding:6px 8px;border-bottom:1px solid var(--line);text-align:left}
table.rec .num{text-align:right;font-variant-numeric:tabular-nums}
.medal{font-weight:800}
.medal.seolbong{color:#5ac8fa}.medal.gold{color:#d4a017}.medal.silver{color:#8b98a5}.medal.bronze{color:#b1703c}
.medalline{margin-top:8px;font-size:15px;font-weight:700}
.gain{color:#1d9f7a}.loss{color:#c2453a}

/* 캐릭터 색 점 — 인라인 style 금지(CSP style-src self) */
.dot.suit-narae{background:#2f6fd0}
.dot.suit-beomu{background:#d94f3d}
.dot.suit-sorang{background:#7a53c9}
.dot.suit-haneul{background:#1d9f7a}
.dot.suit-dolsoe{background:#c98a2b}
/* 막대 폭 클래스 — 10 % 단위(인라인 style 대신) */
.bar i.w10{width:12%}
.bar i.w15{width:19%}
.bar i.w20{width:25%}
.bar i.w25{width:31%}
.bar i.w30{width:38%}
.bar i.w35{width:44%}
.bar i.w40{width:50%}
.bar i.w45{width:56%}
.bar i.w50{width:62%}
.bar i.w55{width:69%}
.bar i.w60{width:75%}
.bar i.w65{width:81%}
.bar i.w70{width:88%}
.bar i.w75{width:94%}
.bar i.w80{width:100%}

/* 통과 점수 팝업 — 숫자가 «크게» 튀어 오른다. 색은 연속 단계(t0~t3)를 따른다. */
#pops{position:absolute;inset:0;pointer-events:none;overflow:hidden}
#pops .pop{position:absolute;font-weight:900;font-size:46px;letter-spacing:-1px;
  -webkit-text-stroke:3px rgba(12,18,28,.72);paint-order:stroke fill;
  text-shadow:0 3px 0 rgba(0,0,0,.35),0 0 24px currentColor;animation:popUp .95s cubic-bezier(.16,1,.3,1) forwards}
#pops .pop.t0{color:#ffe37a}#pops .pop.t1{color:#ffd23c}#pops .pop.t2{color:#ff8a3c}#pops .pop.t3{color:#37e0c8}
#pops .pop.big{font-size:62px}
@keyframes popUp{0%{transform:translate(-50%,0) scale(.4) rotate(-6deg);opacity:0}
  18%{transform:translate(-50%,-14px) scale(1.25) rotate(2deg);opacity:1}
  40%{transform:translate(-50%,-34px) scale(1) rotate(0)}
  100%{transform:translate(-50%,-120px) scale(.92);opacity:0}}
/* 연속 단계 배너 — 3·6·9… 에서 화면 가운데를 가로지른다 */
#banner{position:absolute;left:0;right:0;top:40%;text-align:center;pointer-events:none;opacity:0;
  font-weight:900;font-size:64px;letter-spacing:-2px;color:#fff;-webkit-text-stroke:4px rgba(12,18,28,.75);paint-order:stroke fill;text-shadow:0 4px 0 rgba(0,0,0,.3),0 0 40px #ffd23c}
#banner.on{animation:bannerSlam .95s cubic-bezier(.16,1,.3,1) forwards}
#banner.t2{text-shadow:0 4px 0 rgba(0,0,0,.3),0 0 40px #ff8a3c}
#banner.t3{text-shadow:0 4px 0 rgba(0,0,0,.3),0 0 46px #37e0c8}
@keyframes bannerSlam{0%{opacity:0;transform:scale(2.6) rotate(-8deg)}
  22%{opacity:1;transform:scale(1) rotate(0)}
  70%{opacity:1;transform:scale(1.04)}
  100%{opacity:0;transform:scale(1.15)}}
@media (prefers-reduced-motion:reduce){#pops .pop,#banner.on{animation:none;opacity:0}}

/* 실시간 점수 — «지금 얼마 벌고 있나»가 한눈에 보여야 한다(화면 위 가운데, 시간·속도와 같은 급) */
#hud .sc{position:absolute;left:50%;top:78px;transform:translateX(-50%);text-align:center;pointer-events:none;z-index:3}
#hScore{font-weight:900;font-size:40px;letter-spacing:-1px;line-height:1;color:#fff;
  -webkit-text-stroke:3px rgba(12,18,28,.62);paint-order:stroke fill;text-shadow:0 2px 0 rgba(0,0,0,.3)}
#hMult{margin-top:2px;font-weight:800;font-size:17px;color:#ffd23c;
  -webkit-text-stroke:2px rgba(12,18,28,.55);paint-order:stroke fill}
#hMult.hot{color:#ff8a3c}#hMult.max{color:#37e0c8}
#hScore.up{animation:scorePop .28s ease-out}
@keyframes scorePop{0%{transform:scale(1)}40%{transform:scale(1.14)}100%{transform:scale(1)}}
@media (max-width:480px){#hScore{font-size:34px}}
@media (prefers-reduced-motion:reduce){#hScore.up{animation:none}}

/* 이니셜 태그 입력 — 세 글자, 가운데는 서버로 가기 전에 별표로 가려진다 */
.tagin{width:7.5em;font-size:26px;font-weight:800;letter-spacing:.32em;text-align:center;padding:6px 8px;
  border-radius:10px;border:2px solid #2b3440;background:#0f151d;color:#fff}
.tagin:focus{outline:none;border-color:#ffd23c}
#tagHint.bad{color:#ff6a54}#tagHint.ok{color:#2ee08a}


/* 다음 관문 안내 — «어디로 가야 하나»(2026-09-18 사용자). 화살표는 카메라 기준 방위로 돈다.
   🔴 화면 한가운데를 가리지 않도록 아래쪽에 두고, 정면(±7°)일 때는 흐리게 죽인다. */
#hGate {
  position: absolute; left: 50%; bottom: 96px; transform: translateX(-50%);
  display: none; align-items: center; gap: 8px;
  padding: 5px 12px; border-radius: 999px;
  background: rgba(12, 18, 30, .46); color: #ffd23c;
  font-weight: 800; font-size: 15px; letter-spacing: .02em;
  text-shadow: 0 1px 3px rgba(0, 0, 0, .7); pointer-events: none;
  opacity: .45; transition: opacity .18s ease;
}
#hGate.on { display: flex; }
#hGate.off { opacity: 1; }
#hGate .arrow { display: inline-block; font-size: 18px; line-height: 1; will-change: transform; }
@media (max-width: 560px) { #hGate { bottom: 140px; font-size: 13px; } }
/* 🔴 터치 조작이 켜지면 아래쪽은 통째로 버튼 차지다(웅크림 버튼이 화면 가운데까지 온다) —
   가로 폰(640×360)에서는 위로 올려도 점수와 부딪힌다. 안내는 «점수 바로 아래»로 고정한다. */
#play.touch #hGate { top: calc(150px + env(safe-area-inset-top, 0px)); bottom: auto; }

/* 착지 타이밍 — 고리가 줄어들어 «창»에 들어오면 색이 바뀐다(2026-09-18 사용자 제안).
   🔴 화면 한가운데에 두되 클릭을 먹지 않는다(pointer-events: none) — 안내가 조작을 삼키면 안 된다. */
#hLand {
  position: absolute; left: 50%; top: 46%; transform: translate(-50%, -50%);
  display: none; flex-direction: column; align-items: center; gap: 10px; pointer-events: none;
}
#hLand.on { display: flex; }
#hLandRing {
  width: 132px; height: 132px; border-radius: 50%;
  border: 5px solid rgba(255, 255, 255, .72); box-shadow: 0 0 18px rgba(0, 0, 0, .35) inset;
  will-change: transform;
}
#hLand .land-key {
  font-weight: 800; font-size: 15px; letter-spacing: .02em; color: #eaf4ff;
  text-shadow: 0 2px 6px rgba(0, 0, 0, .75);
}
#hLand.hot #hLandRing { border-color: #ffd23c; box-shadow: 0 0 26px rgba(255, 210, 60, .55); }
#hLand.hot .land-key { color: #ffd23c; }
@media (max-width: 560px) { #hLandRing { width: 104px; height: 104px; } }

/* 속도계 — 우측 하단, 크게(2026-09-18 사용자 요청). 속도는 «지금 얼마나 위험한가» 이기도 하다.
   🔴 모바일에서는 터치 버튼(오른쪽 아래)과 겹치므로 그 위로 올린다 — 겹치면 숫자가 조작을 가린다. */
#hud .br {
  position: absolute; right: 16px; bottom: calc(18px + env(safe-area-inset-bottom, 0px));
  display: flex; align-items: baseline; gap: 6px; color: #fff;
  text-shadow: 0 2px 10px rgba(0, 0, 0, .6); pointer-events: none;
}
#hSpeed {
  font-size: 54px; font-weight: 900; line-height: 1;
  font-variant-numeric: tabular-nums; letter-spacing: -.02em;
}
#hud .br .unit { font-size: 15px; font-weight: 700; opacity: .8; }
#hud .br.warm #hSpeed { color: #ffd23c; }
#hud .br.hot #hSpeed { color: #ff8a3c; text-shadow: 0 0 18px rgba(255, 138, 60, .5), 0 2px 10px rgba(0, 0, 0, .6); }
#hud .br.red #hSpeed {
  color: #ff3b30; text-shadow: 0 0 24px rgba(255, 59, 48, .65), 0 2px 10px rgba(0, 0, 0, .6);
  animation: spdPulse .55s ease-in-out infinite;
}
#hud .br.red .unit { color: #ff8a80; opacity: 1; }
@keyframes spdPulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.07); } }
@media (prefers-reduced-motion: reduce) { #hud .br.red #hSpeed { animation: none; } }
#play.touch #hud .br { bottom: calc(196px + env(safe-area-inset-bottom, 0px)); }
#play.touch #hSpeed { font-size: 42px; }
@media (max-width: 420px) { #hSpeed { font-size: 36px; } }
