/* 원본 포털에서 그대로 뽑아낸 디자인 스타일이다. 로직 작업으로 고치지 않는다. */
:root{
  --bg:#030616; --glass:rgba(7,13,39,.88); --line:rgba(181,145,255,.55);
  --text:#fff; --muted:#cfd4ee; --accent:#b76cff; --cyan:#72dfff; --gold:#ffe38a;
}
*{box-sizing:border-box}
html,body{margin:0;background:var(--bg);color:var(--text);font-family:system-ui,-apple-system,"Noto Sans KR","Malgun Gothic",sans-serif}
body{overflow-x:hidden}
button{font:inherit}
.app{min-height:100vh;background:
  radial-gradient(circle at 50% 25%,rgba(90,82,220,.16),transparent 34%),
  radial-gradient(circle at 15% 70%,rgba(0,180,255,.08),transparent 30%),#030616}
.portal-wrap{position:relative;width:min(100%,1024px);margin:auto;line-height:0}
.portal-image{display:block;width:100%;height:auto;user-select:none;-webkit-user-drag:none}
.hotspot{position:absolute;z-index:4;border:0;background:transparent;padding:0;cursor:pointer;border-radius:18px;outline:none}
.hotspot::after{content:"";position:absolute;inset:0;border:1px solid transparent;border-radius:inherit;transition:.2s}
.hotspot:hover::after,.hotspot:focus-visible::after{border-color:rgba(220,185,255,.72);box-shadow:0 0 25px rgba(163,105,255,.28),inset 0 0 18px rgba(163,105,255,.08);background:rgba(160,100,255,.045)}
.hotspot:active::after{transform:scale(.985)}
.pulse{animation:pulse 2.5s ease-in-out infinite}
@keyframes pulse{0%,100%{box-shadow:0 0 0 0 rgba(189,112,255,0)}50%{box-shadow:0 0 28px 6px rgba(189,112,255,.18)}}
.cursor-glow{position:fixed;z-index:3;width:160px;height:160px;border-radius:50%;pointer-events:none;background:radial-gradient(circle,rgba(154,118,255,.13),transparent 68%);transform:translate(-50%,-50%);mix-blend-mode:screen}
.toast{position:fixed;z-index:30;left:50%;bottom:22px;transform:translate(-50%,120px);background:rgba(6,10,31,.94);border:1px solid rgba(171,131,255,.6);border-radius:999px;padding:12px 18px;color:#fff;box-shadow:0 10px 40px rgba(0,0,0,.45);transition:.35s;max-width:90vw;text-align:center}
.toast.show{transform:translate(-50%,0)}
.modal-backdrop{position:fixed;inset:0;z-index:50;background:rgba(0,0,15,.68);backdrop-filter:blur(9px);display:none;align-items:center;justify-content:center;padding:18px}
.modal-backdrop.open{display:flex}
.modal{width:min(620px,100%);max-height:min(780px,92vh);overflow:auto;background:linear-gradient(180deg,rgba(17,20,62,.98),rgba(5,10,31,.98));border:1px solid rgba(188,146,255,.58);border-radius:28px;box-shadow:0 30px 100px rgba(0,0,0,.65),0 0 60px rgba(129,83,255,.16);padding:24px}
.modal h2{margin:0 0 8px;font-size:clamp(24px,5vw,34px)}
.modal p{color:var(--muted);line-height:1.65}
.modal .close{float:right;width:40px;height:40px;border-radius:50%;border:1px solid rgba(255,255,255,.2);background:rgba(255,255,255,.06);color:white;cursor:pointer}
.choice-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:12px;margin-top:18px}
.choice{border:1px solid rgba(180,145,255,.4);background:rgba(255,255,255,.05);color:white;border-radius:18px;padding:18px;text-align:left;cursor:pointer;transition:.2s}
.choice:hover{transform:translateY(-2px);background:rgba(172,117,255,.12);border-color:rgba(213,182,255,.72)}
.choice b{display:block;font-size:18px;margin-bottom:5px}
.choice small{color:#bdc4df;line-height:1.5}
.dialogue{margin-top:18px;padding:18px;border-radius:18px;background:rgba(255,255,255,.05);border:1px solid rgba(255,255,255,.09)}
.dialogue .bubble{padding:13px 15px;border-radius:16px;margin:8px 0;line-height:1.55}
.ai{background:rgba(139,95,255,.16);border:1px solid rgba(181,145,255,.24)}
.me{background:rgba(75,193,255,.1);border:1px solid rgba(75,193,255,.2);text-align:right}
.phrase{display:flex;gap:8px;margin-top:12px;flex-wrap:wrap}
.phrase button,.primary{border:0;border-radius:999px;padding:11px 16px;background:linear-gradient(135deg,#6b5cff,#c05cff);color:white;cursor:pointer;font-weight:700}
.progress-line{height:8px;border-radius:99px;background:rgba(255,255,255,.1);overflow:hidden;margin:12px 0}
.progress-line i{display:block;height:100%;width:0;background:linear-gradient(90deg,#67dfff,#c16bff);transition:.45s}
.hint{font-size:12px;color:#9fa8ca;margin-top:12px;line-height:1.5}
@media (max-width:640px){
  .choice-grid{grid-template-columns:1fr}
  .modal{padding:18px;border-radius:22px}
  .cursor-glow{display:none}
}
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.01ms!important;transition-duration:.01ms!important}
}

/* ─────────────────────────────────────────────────────────────
   적응형 레이어 — PC · 모바일 웹 · 안드로이드/애플 앱(WebView)

   위쪽은 원본 포털에서 그대로 뽑은 디자인이라 손대지 않는다.
   여기부터는 그 프레임(1024x1536) 한 장을 화면 크기에 담는 규칙이다.
   핫스팟 좌표가 %라서 프레임 크기만 맞추면 버튼 15개가 그대로 따라온다.
   숫자의 출처는 portal.design.json 의 frame/adaptive 이고, 로직이 CSS 변수로 흘려보낸다.
   아래 기본값은 JSON 이 아직 안 왔을 때 화면이 튀지 않도록 둔 같은 값이다.
   ───────────────────────────────────────────────────────────── */
:root{
  --portal-frame-w:1024;
  --portal-frame-h:1536;
  --portal-max-w:1024px;
  --portal-gutter:8px;
  --portal-min-touch:44px;
  --safe-t:env(safe-area-inset-top,0px);
  --safe-r:env(safe-area-inset-right,0px);
  --safe-b:env(safe-area-inset-bottom,0px);
  --safe-l:env(safe-area-inset-left,0px);
  --vh100:100vh;
}
/* 모바일 주소창이 접혔다 펴질 때 100vh 는 잘린 높이를 안 따라온다. dvh 가 있으면 그걸 쓴다. */
@supports (height:100dvh){ :root{ --vh100:100dvh; } }

html{-webkit-text-size-adjust:100%}
body{overscroll-behavior:none;-webkit-tap-highlight-color:transparent;touch-action:manipulation}

/* 프레임을 화면 한가운데에 담는다. 안전영역만큼 밀어 노치와 홈 인디케이터를 피한다. */
.app{
  min-height:var(--vh100);
  display:flex;align-items:center;justify-content:center;
  padding:calc(var(--portal-gutter) + var(--safe-t)) calc(var(--portal-gutter) + var(--safe-r))
          calc(var(--portal-gutter) + var(--safe-b)) calc(var(--portal-gutter) + var(--safe-l));
}

/* 세로가 짧으면(PC·가로 폰) 높이에, 가로가 짧으면(세로 폰) 폭에 맞춰진다.
   셋 중 가장 작은 값이라 어느 쪽에서도 스크롤이 안 생기고, 원본 폭 1024 를 넘지 않는다. */
.portal-wrap{
  --avail-h:calc(var(--vh100) - 2 * var(--portal-gutter) - var(--safe-t) - var(--safe-b));
  width:min(100%, var(--portal-max-w), var(--avail-h) * var(--portal-frame-w) / var(--portal-frame-h));
  aspect-ratio:var(--portal-frame-w) / var(--portal-frame-h);
  margin:auto;
}
.portal-image{height:100%;object-fit:contain;-webkit-touch-callout:none}

/* 작은 화면에서 5.5%x3.5% 짜리 버튼은 20px 도 안 된다. 보이는 자리는 그대로 두고
   가운데를 기준으로 눌리는 면적만 44px 까지 넓힌다. */
.hotspot{touch-action:manipulation;-webkit-tap-highlight-color:transparent}
.hotspot::before{
  content:"";position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
  width:max(100%,var(--portal-min-touch));height:max(100%,var(--portal-min-touch));
}

/* 손가락에는 hover 가 없다. 탭한 뒤 테두리가 남아 눌린 것처럼 보이는 것을 막는다. */
@media (hover:none){
  .hotspot:hover::after{border-color:transparent;box-shadow:none;background:transparent}
  .cursor-glow{display:none}
}

/* 모달과 토스트도 같은 안전영역 안에 둔다. */
.modal-backdrop{
  padding:calc(18px + var(--safe-t)) calc(18px + var(--safe-r))
          calc(18px + var(--safe-b)) calc(18px + var(--safe-l));
}
.modal{
  max-height:min(780px, calc(var(--vh100) - 36px - var(--safe-t) - var(--safe-b)));
  overscroll-behavior:contain;-webkit-overflow-scrolling:touch;
}
.toast{bottom:calc(22px + var(--safe-b))}

/* 가로로 누운 폰은 세로가 400px 도 안 된다. 여백을 줄여 프레임을 조금이라도 키운다. */
@media (max-height:480px){ :root{ --portal-gutter:2px } }

/* ─────────────────────────────────────────────────────────────
   레이어 — 배경 한 장을 잘라 낸 33장을 같은 % 좌표계로 얹는다

   좌표는 핫스팟과 같은 출처(portal.design.json)에서 온다.
   그림은 바뀌지 않는다. 한 장이던 것이 조각으로 나뉘었을 뿐이라,
   조각마다 따로 떠오르고 따로 움직일 수 있다.
   핫스팟(z-index 4)은 그대로 위에 남아 클릭을 받는다. 레이어는 밑(2)이다.
   ───────────────────────────────────────────────────────────── */
.portal-layer{
  position:absolute;margin:0;padding:0;border:0;background:transparent;z-index:2;
  transform:translate3d(var(--px,0px),var(--py,0px),0) scale(var(--s,1));
  transition:transform .28s cubic-bezier(.2,.7,.3,1), filter .28s ease;
  pointer-events:none;
}
.portal-layer>img{display:block;width:100%;height:100%;user-select:none;-webkit-user-drag:none}
/* 핫스팟에 손이 닿으면 짝지어진 조각이 떠오른다. 로직이 .lit 을 걸어 준다. */
.portal-layer.lit{
  --s:1.045;z-index:9;
  filter:drop-shadow(0 10px 26px rgba(150,95,255,.42)) drop-shadow(0 0 12px rgba(190,140,255,.28));
}
.portal-layer.pressed{--s:1.012;transition-duration:.08s}
/* 메뉴바로 옮겨 왔을 때 어디로 왔는지 알려 준다 */
.portal-layer.flash{z-index:12;animation:layer-flash 1.15s ease-out}
@keyframes layer-flash{
  0%{filter:drop-shadow(0 0 0 rgba(126,231,255,0))}
  22%{filter:drop-shadow(0 0 26px rgba(126,231,255,.95)) drop-shadow(0 0 52px rgba(126,231,255,.55))}
  100%{filter:drop-shadow(0 0 0 rgba(126,231,255,0))}
}
/* 레이어는 하나도 클릭을 받지 않는다.
   상단 메뉴를 낱개 버튼으로 만들어 봤더니 44px 히트영역이 이웃 핫스팟을 삼켰다
   (action-nav·action-music 이 눌리지 않게 됐다). 클릭은 계속 핫스팟 15개만 받고,
   낱개 목적지 8곳은 메뉴바로 간다 — 거기가 44px 을 지킬 수 있는 자리다. */

/* ── 이동 메뉴바 — 그림 속 좌표가 아니라 새로 만든 요소라 44px 터치를 지킨다 ──
   그림 속 글자는 360px 화면에서 12px 까지 작아진다. 그건 그림의 성질이라 못 고친다.
   대신 같은 목적지로 가는 길을 하나 더 낸다. */
.menubar{
  position:fixed;left:0;right:0;bottom:0;z-index:25;
  height:calc(var(--portal-menubar) + var(--safe-b));
  padding:8px calc(12px + var(--safe-r)) calc(8px + var(--safe-b)) calc(12px + var(--safe-l));
  display:flex;gap:14px;align-items:center;overflow-x:auto;overflow-y:hidden;
  background:rgba(5,9,28,.95);border-top:1px solid rgba(150,110,235,.42);
  backdrop-filter:blur(10px);scrollbar-width:thin;overscroll-behavior-x:contain;
}
.mgroup{display:flex;gap:6px;align-items:center;flex:0 0 auto;
  padding-right:14px;border-right:1px solid rgba(255,255,255,.1)}
.mgroup:last-child{border-right:0}
.mgroup>b{font-size:11px;color:#a9b0d4;writing-mode:vertical-rl;text-orientation:mixed;
  letter-spacing:.06em;margin-right:2px;font-weight:600}
.mi{flex:0 0 auto;min-width:64px;min-height:var(--portal-min-touch);
  display:flex;flex-direction:column;align-items:center;gap:3px;padding:5px 7px;
  cursor:pointer;color:#e9e6ff;background:rgba(255,255,255,.05);
  border:1px solid rgba(255,255,255,.12);border-radius:14px;transition:.18s;
  touch-action:manipulation;-webkit-tap-highlight-color:transparent}
.mi>img{width:38px;height:38px;border-radius:9px;object-fit:cover;display:block;
  background:rgba(0,0,0,.35)}
.mi>span{font-size:11px;line-height:1.15;white-space:nowrap}
.mi:hover{background:rgba(150,100,255,.2);border-color:rgba(206,176,255,.7);transform:translateY(-2px)}
.mi:focus-visible{outline:3px solid rgba(226,200,255,.95);outline-offset:2px}
.mi[aria-current="true"]{background:rgba(120,220,255,.2);border-color:rgba(126,231,255,.85)}

/* 메뉴바가 뜨면 그 높이만큼 프레임이 앉을 자리를 줄인다. 안 그러면 스크롤이 생긴다. */
:root{--portal-menubar:0px}
html.has-menubar{--portal-menubar:80px}
html.has-menubar .app{
  padding-bottom:calc(var(--portal-gutter) + var(--safe-b) + var(--portal-menubar));
}
html.has-menubar .portal-wrap{
  --avail-h:calc(var(--vh100) - 2 * var(--portal-gutter) - var(--safe-t) - var(--safe-b)
                 - var(--portal-menubar));
}
html.has-menubar .toast{bottom:calc(22px + var(--safe-b) + var(--portal-menubar))}

@media (max-width:640px){
  .mgroup>b{display:none}
  .mi{min-width:58px}
}
@media (max-height:480px){
  html.has-menubar{--portal-menubar:66px}
  .mi>img{width:30px;height:30px}
}
@media (prefers-reduced-motion:reduce){
  .portal-layer{transition:none}
  .portal-layer.flash{animation:none}
}
/* 상단 메뉴 바로가기는 글자만이라 썸네일 자리를 비운다 */
.mi.mi-text{min-width:auto;justify-content:center;padding:0 12px}
.mi.mi-text>span{font-size:12px}

/* 가로 화면은 프레임이 높이에 갇혀 좌우가 남는다(가로 폰이면 639px 이 빈다).
   거기에 메뉴바를 세우면 프레임을 줄이지 않고도 같은 자리를 얻는다.
   세로 화면은 반대로 폭에 갇히므로 아래쪽 띠가 맞다. */
@media (min-aspect-ratio:1/1){
  html.has-menubar{--portal-menubar:0px;--portal-rail:96px}
  .menubar{
    top:0;bottom:0;right:0;left:auto;
    width:calc(var(--portal-rail) + var(--safe-r));height:auto;
    padding:calc(10px + var(--safe-t)) calc(8px + var(--safe-r)) calc(10px + var(--safe-b)) 8px;
    flex-direction:column;gap:10px;overflow-x:hidden;overflow-y:auto;
    border-top:0;border-left:1px solid rgba(150,110,235,.42);
    overscroll-behavior-y:contain;
  }
  .mgroup{
    flex-direction:column;gap:6px;width:100%;
    padding:0 0 10px;border-right:0;border-bottom:1px solid rgba(255,255,255,.1);
  }
  .mgroup:last-child{border-bottom:0;padding-bottom:0}
  .mgroup>b{writing-mode:horizontal-tb;text-orientation:initial;display:block;margin:0;text-align:center}
  .mi{width:100%;min-width:0}
  html.has-menubar .app{
    padding-right:calc(var(--portal-rail) + var(--safe-r) + var(--portal-gutter));
  }
  html.has-menubar .toast{bottom:calc(22px + var(--safe-b))}
}
@media (min-aspect-ratio:1/1) and (max-height:480px){
  html.has-menubar{--portal-rail:80px}
  .mi>img{width:26px;height:26px}
  .mi>span{font-size:10px}
}
