/* ============================================================
   완드 체험 태블릿 — 스타일
   디자인 시스템: design-system/tokens.css + components.css (먼저 로드)
   ------------------------------------------------------------
   화면은 **태블릿 세로**다. 기준 프레임 1200 x 1920 (16:10 태블릿을 세운 크기).
   스캐너와 같은 방식으로, 프레임이 화면에 들어가는 최대 배율 --u 를 한 번 구하고
   아래 모든 수치를 "기준 px × --u" 로 적는다. 1200 폭에서 --u = 1 이다.
   요소마다 clamp/vh 로 따로 줄이면 기기 비율이 조금만 달라져도 간격이 제각각 틀어진다.

   ⚠ 이 화면의 치수는 **일반 앱보다 2~3배 크다**(노션 안건 B). 관람객은 마법을 고른 뒤
   패드에서 두세 걸음 물러나 지팡이를 휘두르기 때문에, 시전 대기 화면의 궤적·문구는
   그 거리에서 읽혀야 한다. 작아 보인다고 줄이지 말 것.
   ============================================================ */

/* 넥슨 워헤이븐(Warhaven OTF)은 26-10-02 라이선스 문제로 쓰지 않는다 — 제목은 Hahmlet(Figma TitleDeco 4477:770 = Hahmlet Bold),
   글꼴 파일도 저장소에서 지웠다. Hahmlet Bold(700)는 공통 fonts-hahmlet.css 에 있다(DS #112 — 처음엔 완드 전용 파일로 두었다가 공통으로 옮김). */

* { margin: 0; padding: 0; box-sizing: border-box; }

:root {
  /* ⚠ 마법별 포인트 색 — tokens.css 에 없는 **새 값**이다. 네 마법을 멀리서 구분하려면
     키 컬러 한 계열(26-09-30 부터 네이비)만으로는 부족해서 넣었다(안건 B). 팔레트 확장이라 디자이너 확인 필요.
     명도·채도는 어두운 배경 위에서 흰 글자와 같이 떠 보이도록 맞췄다. 26-09-30 네이비 전환에서 이 네 색은 그대로 뒀다(마법끼리 구분). */
  --spell-fire: #F2955E;       /* 인센디오 — 호박 */
  --spell-water: #7FC8F0;      /* 아구아멘티 — 얼음빛 */
  --spell-light: #F3F6FF;      /* 루모스 — 흰빛(26-10-23 시안 4596:22227 · 5368:14 · 5388:60, 그전 골드 #EFDB7E) */
  /* 루모스만 빛 번짐을 두 색으로(26-10-23 다원님 — 흰빛 레퍼런스처럼 그림자에 빛 색을 섞음): 차가운 푸른 흰빛 + 가장자리에 옅은 주황.
     다른 마법은 번짐이 마법색 그대로(앱이 --*-shine 을 accent 로, --*-warm 을 transparent 로 넣는다). */
  --spell-light-glow: #A9C3FF;
  --spell-light-warm: rgba(255, 178, 122, 0.23);   /* #FFB27A — 시안: 빛 그림자 진하기의 22.5% · 흐림 40% · 왼쪽 아래로 비킴 */
  --spell-light-deep: #7E99DE;  /* 시전 · 성공 무대 바닥 빛(그전 시안 금빛 #C39418 자리) */
  --spell-levitate: #B79BF5;   /* 레비오사 — 라일락(마법 고유색, 09-30 네이비 전환에서 제외) */

  /* 포커스 링 — 공통(tokens.css)은 바깥 링 6px 이다. 완드는 멀리서 보는 화면이라 7px 로 덮어 쓴다.
     (--func-error 는 26-09-28 tokens.css 로 옮겨 갔다) */
  --focus-ring: 0 0 0 3px var(--color-night-900), 0 0 0 7px var(--color-blue-400);

  /* 기준 프레임 1200x1920 이 화면 안에 들어가는 최대 배율 */
  --u: min(
    (100vw - env(safe-area-inset-left, 0px) - env(safe-area-inset-right, 0px)) / 1200,
    (100vh - env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px)) / 1920
  );
  /* 공통 컴포넌트 크기 단위(tokens.css) — Popup · Login 은 스캐너 프레임(가로 1133×744) 숫자라 완드 좌표로 옮긴다.
     시작 화면 · stage 버튼 · 국기 · 화면 제목은 완드 프레임 숫자(--ds-wu)라 따로 줄 것 없이 --u 그대로. */
  --ds-u: calc(var(--u) * 1200 / 744);
  /* Figma 1px — 시안 프레임이 실제 기기 크기(744×1133, 아이패드 미니 세로)로 바뀌었다(26-09-29).
     744×1133 에서 정확히 1px 이고, 다른 기기에서는 --u 와 같은 비율로 커지고 준다(스테이지 높이 1920u = 1133fu).
     Figma 와 똑같이 맞춘 화면은 시안 숫자에 이 단위를 곱한다 — 지금은 01 대기. */
  --fu: calc(var(--u) * 1920 / 1133);
  /* 영문 타이틀 서체 — 공통 토큰(tokens.css)은 Harry Beast Cyr 인데, 완드는 한국어와 같은 **Hahmlet** 으로 둔다
     (26-09-30 Warhaven OTF 로 바꿨다가 26-10-02 라이선스로 Warhaven 을 빼서 Hahmlet). 공통 사본은 sync 로만 고치므로 여기서 토큰을 덮는다 —
     공통 규칙(step-title · popup__title · start-title 의 영문)까지 한 번에 바뀐다. (Harry Beast TTF 도 라이선스로 커밋하지 않는다) */
  --font-display-en: "Hahmlet", "Noto Serif KR", serif;
}

html, body { height: 100%; }

body {
  font-family: var(--font-primary);
  color: var(--color-white-100);
  background: var(--gradient-night);
  overflow: hidden;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
  /* 무인 키오스크 방어 — 길게 눌러 뜨는 메뉴, 더블탭 확대, 고무줄 스크롤 차단 */
  -webkit-touch-callout: none;
  touch-action: manipulation;
  overscroll-behavior: none;
}

/* 쿨타임 동안은 화면 전체가 잠긴다(노션 5번: "터치가 잠김").
   데모 패널만 예외 — 리뷰 중에 건너뛸 수 있어야 한다. */
body[data-locked="1"] .screen { pointer-events: none; }
/* 예외 — 쿨타임 화면의 [그만두기]만은 잠금 중에도 눌린다 */
body[data-locked="1"] .screen .quit-btn { pointer-events: auto; }

/* ---------- 배경 — Figma 프레임 채움 그대로(26-09-29, 단위 --fu) ----------
   02 QR 스캔 · 03 완드 선택(4472:777 · 4591:20971, 26-10-01 두 번째 갱신): #05070F + **대기 화면과 같은 마법 궤적 무늬 그림**(7% · 밝기(luminosity) 블렌드,
       성 사진은 시안에서 꺼짐) + 세로 그라디언트 100%(#010102 0% → #141A36 65% 28.7% → #1E4986 65% 74.9% → #204B6B 70% 78.9% → #010102 99%)
   04 마법 선택(4591:21053): 사진 없이 #05070F + 같은 그라디언트인데 74.9% 자리가 **가운데 카드의 마법색** 69%, 78.9% 는 #202E6B 30%
       (마법색은 app.js 가 --select-accent 로 준다)
   05 시전 대기 · 06 성공(4596:22039 · 4472:807): #010102 + 바닥 가운데서 퍼지는 타원 라디얼 65%(가로 반지름 1879 · 세로 1133):
       마법색 진한 톤 3.9% → 마법색 40% 36.2% → #141A36 40% 72.4% → #010102 100%. 실패(05c 4596:22645)는 #FC5F5F → #E33737 40%.
   01 대기(26-10-01 4795:34428): #05070F + 마법 궤적 무늬(cover) + 세로 그라디언트 88%(.bg-wand-start).
   00 로그인: 공통 StartScreen 의 .bg-start(성 사진 전체).
   ⚠ 26-09-30 키 컬러 네이비(#7691FF, #93): Figma 완드 시안은 아직 보라라, 이 파일의 보라 값은 색상만 228° 로 옮겨 적었다
     (채도 · 명도 · 알파 그대로, 예 #08050F → #05070F). "⚠ 시안 원본값" 표시가 붙은 값도 마찬가지 — 레비오사 마법색만 예외. */
.bg-layer { position: fixed; inset: 0; z-index: 0; pointer-events: none; overflow: hidden; background: #05070F; isolation: isolate; }
.bg-art, .bg-night, .bg-band, .bg-stage { transition: opacity 0.8s ease; }
.bg-art {                                      /* 안은 무늬 합성(.pat) */
  position: absolute; inset: 0;
  opacity: 0.07;
  mix-blend-mode: luminosity;
}
.bg-night {
  position: absolute; inset: 0;
  background: linear-gradient(180deg, #010102 0%, rgba(20, 26, 54, 0.65) 28.7%, rgba(30, 73, 134, 0.65) 74.9%, rgba(32, 75, 107, 0.7) 78.9%, #010102 99%);   /* ⚠ 시안 원본값(비토큰), 26-10-01 */
  opacity: 1;
}
/* 04 — 마법색이 섞인 그라디언트(사진 없음). 마법 선택 화면에서만 켠다 */
.bg-band {
  position: absolute; inset: 0;
  background: linear-gradient(180deg, #010102 0%, #141A36 40.6%,
    var(--select-accent, var(--color-peri-400)) 69%, rgba(32, 46, 107, 0.3) 78.9%, #010102 93.1%);
  opacity: 0;
  transition: opacity 0.8s ease, background 0.5s ease;
}
body[data-screen="select"] .bg-art,
body[data-screen="select"] .bg-night { opacity: 0; }
body[data-screen="select"] .bg-band { opacity: 0.6; }
/* 로그인 배경(.bg-start · 성 사진 · 덮는 그라디언트)은 공통 StartScreen(components.css). 보이는 때만 앱이 정한다(4596:22747). */
body[data-screen="login"] .bg-start { opacity: 1; }
/* 대기 화면 배경 — 26-10-01 시안 4795:34428 채움 그대로: #08050F(→ 네이비 규칙 #05070F) · 마법 궤적 무늬 그림(FILL = cover) ·
   세로 그라디언트 88%(26-10-02 시안 4864:9381: #010102 0% → #141A36 22.583% → #1E4986 90% 65.762% → #204B6B 81.747% → #141A36 99.303%).
   시안의 CROP 그림 채움은 꺼져 있다. 무늬 그림은 안의 .pat 합성(아래)이고, 그라디언트(::after)가 그 위를 88% 덮는다. */
.bg-wand-start {
  position: absolute; inset: 0;
  background: #05070F;
  opacity: 0;
  transition: opacity 0.8s ease;
}
.bg-wand-start::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(180deg, #010102 0%, rgba(20, 26, 54, 0.92) 22.583%, rgba(30, 73, 134, 0.86) 65.762%, rgba(32, 75, 107, 0.95) 81.747%, #141A36 99.303%);   /* ⚠ 시안 원본값(비토큰) — 26-10-08 시안 background 5092:9620: 가운데 색이 92 · 86 · 95% 로 옅어져 무늬가 조금 더 보인다(전엔 100 · 90 · 100%) */
  opacity: 0.88;
}
body[data-screen="start"] .bg-wand-start { opacity: 1; }

/* ---------- 마법 궤적 무늬 합성(.pat, 10-01) ----------
   시안 배경 그림(26-10-07 교체, 원본 4096×3024 → 2048×1512)을 바탕 base.jpg 와 조각(마법 기호 11 · 완드 4, webp)으로 나눠 **원래 자리에** 겹쳐 그린다(app.js PATTERN · buildPattern).
   틀은 그림 px 그대로 두고 통째로 scale 해 background-size: cover 와 같은 크기 · 자르기를 만든다(--pat-s = max(화면폭/2048, 화면높이/1512), app.js fitPattern).
   대기 화면(.pat--live)에서만 조각이 **각각 제자리에서 느리게 돈다**(사용자 지시 10-01): 기호는 반 바퀴 왕복(28~34초) 또는 한 바퀴 회전(42~52초),
   완드는 반 바퀴 왕복(30~40초)만, 방식 · 방향(--dir) · 위상은 조각마다 열 때마다 랜덤. transform 만 움직인다(태블릿 부담 적음).
   대기 화면이 아닐 땐 멈추고, 움직임 줄이기 설정이면 정지 그림만. 02 · 03 의 .bg-art 안 사본은 늘 정지. */
.pat {
  position: absolute; left: 50%; top: 50%;
  width: 2048px; height: 1512px;                 /* 그림 px — app.js PATTERN_W · PATTERN_H */
  /* 26-10-07 시안 채움은 가운데 cover 가 아니라 CROP — 그림 가로 0.2076 ~ 0.6924(세로는 전부)를 보인다(대기 5092:9620 · 체험 완료 4864:15331 · 28759 같은 값).
     보이는 가운데가 그림의 0.45 라, 그림을 화면 가운데보다 그림 폭의 0.05 만큼 오른쪽으로 민다(가운데 정렬 뒤 102.4px × 배율). */
  transform: translate(calc(-50% + 102.4px * var(--pat-s, 1)), -50%) scale(var(--pat-s, 1));
  transform-origin: 50% 50%;
  pointer-events: none;
}
.pat__base { position: absolute; left: 0; top: 0; width: 100%; height: 100%; display: block; }
.pat__s { position: absolute; display: block; transform-origin: 50% 50%; }
.pat--live .pat__s--full { animation: pat-full var(--od) linear var(--odl) infinite; }
.pat--live .pat__s--half { animation: pat-half var(--od) ease-in-out var(--odl) infinite; }
body:not([data-screen="start"]) .pat--live .pat__s { animation-play-state: paused; }
@keyframes pat-full {
  from { transform: rotate(0deg); }
  to   { transform: rotate(calc(360deg * var(--dir))); }
}
@keyframes pat-half {
  0%, 100% { transform: rotate(0deg); }
  50%      { transform: rotate(calc(180deg * var(--dir))); }
}
/* 예전 대기 화면 입자 · 안개 · 빛무리(.bg-fx)는 이 움직임으로 바꿨다 */
body[data-screen="start"] .bg-fx { display: none; }

@media (prefers-reduced-motion: reduce) {
  .pat__s { animation: none !important; }
  .cast-spark, .start-cast__flash, .start-cast__wand { display: none; }
  .start-cta.is-casting .start-cast__magic { animation: none; --mr: 220%; }   /* 끝 장면(시안 그림)만 */
}
body:is([data-screen="start"], [data-screen="login"]) :is(.bg-art, .bg-night, .bg-band) { opacity: 0; }

/* ---------- 시전 대기 · 성공 무대 — 마법색 라디얼(26-09-29 시안으로 교체) ----------
   [마법 확정] 순간 성이 사라지고(0.8초 크로스페이드) 어두운 바닥에서 마법색 빛이 올라온다.
   --stage-accent 는 app.js 가 마법마다 준다. 진한 톤(--stage-deep)은 인센디오만 시안 값(#C44516)이고
   나머지 셋은 시안이 없어 같은 관계(색상 -6° · 명도 43%)로 만든 값이다 — ⚠ 디자이너 확인 필요. */
.bg-stage {
  position: absolute; inset: 0;
  background: #010102;
  opacity: 0;
}
.bg-stage::before {
  content: ""; position: absolute; inset: 0;
  background: radial-gradient(calc(1879 * var(--fu)) calc(1133 * var(--fu)) at 50% 100%,
    var(--stage-deep, hsl(from var(--stage-accent, var(--color-peri-400)) calc(h - 6) s 43%)) 3.9%,
    color-mix(in srgb, var(--stage-accent, var(--color-peri-400)) 40%, transparent) 36.2%,
    rgba(20, 26, 54, 0.4) 72.4%,
    #010102 100%);
  opacity: 0.65;
  transition: background 0.4s ease;
}
/* 실패 순간(05c) — 궤적이 붉어지는 동안 바닥 빛도 붉게 */
body[data-cast="fail"] .bg-stage { --stage-accent: #E33737; --stage-deep: #FC5F5F; }   /* ⚠ 시안 원본값(비토큰) */
body[data-screen="cast"] .bg-stage,
body[data-screen="success"] .bg-stage { opacity: 1; }
body:is([data-screen="cast"], [data-screen="success"]) :is(.bg-art, .bg-night, .bg-band) { opacity: 0; }
/* 쿨타임("마법이 펼쳐지는 중") — 성공 연출(앞 3초)이 끝나면 마법색 라디얼에서 0.8초 크로스페이드로 바뀐다(마법 종류와 무관).
   26-10-06 지시: **⑦ 체험 완료(건너뛰기, 시안 4864:15331) 배경과 같게** — 무늬 그림 30%(luminosity) + 세로 그라디언트 100%(.bg-night 기본).
   (26-09-30 엔 03 과 같은 배경이라며 무늬 50% · 그라디언트 60% 였는데, 무늬가 너무 밝아 화면이 뿌옇게 떴다.)
   떠다니는 불티 · 빛무리(.bg-fx)는 끈다(마법진 둘레를 도는 빛 입자 .cool__motes 는 쿨타임 화면 자체라 그대로). */
body[data-screen="success"][data-phase="cool"] .bg-stage { opacity: 0; }
body[data-screen="success"][data-phase="cool"] .bg-art { opacity: 0.3; }   /* 26-10-07 새 그림: ⑦ 건너뛰기(70%)와 같게 했더니 무늬가 너무 눈에 띄어 30% 로(사용자 지시) — 그라디언트는 100% 그대로 */
body[data-screen="success"][data-phase="cool"] .bg-night { opacity: 1; }
body[data-screen="success"][data-phase="cool"] .bg-fx { opacity: 0; }

/* 입자 · 안개 · 빛무리 — 대기/쿨타임처럼 '기다리는 화면'과 시전 무대에서만 켠다.
   고르는 화면에서는 산만하다. 시전 무대에서는 마법색 불티로 바뀐다. */
.bg-fx { position: absolute; inset: 0; transition: opacity 0.8s ease; }
body:not([data-screen="start"]):not([data-screen="login"]):not([data-screen="success"]):not([data-screen="cast"]) .bg-fx { display: none; }   /* 로그인도 대기 화면과 같은 배경(4596:22747) */
body[data-screen="cast"] .bg-fx {
  --fx-color: #FFFFFF;
  --fx-glow: var(--stage-accent, rgba(155, 173, 245, 0.55));
}
/* 키 컬러(네이비) 빛무리·안개는 성 배경용이다 — 마법색 무대 위에선 색이 겉돌아 불티만 남긴다 */
body[data-screen="cast"] .fx-orb,
body[data-screen="cast"] .fx-fog { display: none; }

.fx-sparkle {
  position: absolute; bottom: -12px;
  width: calc(7 * var(--u)); height: calc(7 * var(--u)); border-radius: 50%;
  background: var(--fx-color, var(--color-blue-300));
  box-shadow: 0 0 14px 3px var(--fx-glow, rgba(155, 173, 245, 0.55));
  opacity: 0;
  animation: sparkle-rise 11s linear infinite;
}
.fx-sparkle:nth-child(1)  { left: 6%;  animation-delay: 0s;   animation-duration: 12s; }
.fx-sparkle:nth-child(2)  { left: 15%; animation-delay: 3.2s; animation-duration: 10s; }
.fx-sparkle:nth-child(3)  { left: 24%; animation-delay: 6.4s; animation-duration: 13s; }
.fx-sparkle:nth-child(4)  { left: 35%; animation-delay: 1.6s; animation-duration: 9s; }
.fx-sparkle:nth-child(5)  { left: 47%; animation-delay: 8s;   animation-duration: 12s; }
.fx-sparkle:nth-child(6)  { left: 58%; animation-delay: 4.8s; animation-duration: 11s; }
.fx-sparkle:nth-child(7)  { left: 68%; animation-delay: 0.8s; animation-duration: 10s; }
.fx-sparkle:nth-child(8)  { left: 78%; animation-delay: 5.6s; animation-duration: 13s; }
.fx-sparkle:nth-child(9)  { left: 88%; animation-delay: 2.4s; animation-duration: 11s; }
.fx-sparkle:nth-child(10) { left: 95%; animation-delay: 7.2s; animation-duration: 12s; }
@keyframes sparkle-rise {
  0%   { transform: translateY(0);      opacity: 0; }
  8%   { opacity: 0.9; }
  45%  { opacity: 0.5; }
  70%  { opacity: 0.85; }
  100% { transform: translateY(-105vh); opacity: 0; }
}

.fx-fog {
  position: absolute; height: 30vh; width: 130vw; bottom: -4vh;
  background: radial-gradient(ellipse 60% 50% at 50% 60%,
    rgba(203, 213, 255, 0.06) 0%, rgba(203, 213, 255, 0.02) 55%, transparent 75%);
  filter: blur(30px);
}
.fx-fog--1 { left: -30vw; animation: fog-drift 38s ease-in-out infinite alternate; }
.fx-fog--2 { left: 6vw; bottom: -10vh; animation: fog-drift 52s ease-in-out infinite alternate-reverse; }
@keyframes fog-drift { from { transform: translateX(0); } to { transform: translateX(22vw); } }

.fx-orb {
  position: absolute; border-radius: 50%;
  background: radial-gradient(circle,
    rgba(222, 229, 255, 0.85) 0%, rgba(155, 173, 245, 0.25) 40%, transparent 70%);
  filter: blur(1px);
  animation: orb-float 14s ease-in-out infinite;
}
.fx-orb--1 { width: calc(90 * var(--u)); height: calc(90 * var(--u)); left: 10%; top: 64%; animation-delay: 0s; }
.fx-orb--2 { width: calc(48 * var(--u)); height: calc(48 * var(--u)); left: 28%; top: 26%; animation-delay: 4s; }
.fx-orb--3 { width: calc(120 * var(--u)); height: calc(120 * var(--u)); left: 78%; top: 52%; animation-delay: 8s; }
@keyframes orb-float {
  0%, 100% { transform: translate(0, 0) scale(1);         opacity: 0.12; }
  25%      { transform: translate(3vw, -4vh) scale(1.08); opacity: 0.30; }
  50%      { transform: translate(-2vw, -7vh) scale(0.95); opacity: 0.18; }
  75%      { transform: translate(2vw, -3vh) scale(1.05);  opacity: 0.28; }
}

/* ---------- 성공 섬광 (안건 C) ----------
   성공 순간 화면 가운데서 마법 색 빛이 한 번 터졌다 사라진다. */
.success-flash {
  position: fixed; inset: 0; z-index: 39; pointer-events: none;
  background: radial-gradient(circle at 50% 46%,
    rgba(255, 255, 255, 0.9) 0%,
    var(--flash-accent, var(--color-peri-400)) 24%,
    transparent 72%);
  opacity: 0;
}
.success-flash.is-on { animation: success-flash 1.1s ease-out both; }
@keyframes success-flash {
  0% { opacity: 0; } 12% { opacity: 0.85; } 100% { opacity: 0; }
}

/* ---------- 화면 공통 ---------- */
.screen {
  position: fixed; z-index: 1;
  top: env(safe-area-inset-top, 0px);
  right: env(safe-area-inset-right, 0px);
  bottom: env(safe-area-inset-bottom, 0px);
  left: env(safe-area-inset-left, 0px);
  display: none;
  align-items: center; justify-content: center;
}
.screen--active { display: flex; animation: screen-in 0.45s ease both; }
@keyframes screen-in {
  from { opacity: 0; transform: translateY(calc(18 * var(--u))); }
  to   { opacity: 1; transform: none; }
}

/* 스테이지 — 크기(--u)는 기준 프레임 1200x1920 에 맞추되, **가로는 기기 폭을 다 쓴다**(26-09-23 그리드 재설계).
   예전엔 1200 폭에 묶여 16:10 보다 넓은 기기(3:4 등)에서 양옆에 빈 띠가 생기고, 뒤로 버튼·로고가
   화면 가장자리에서 한참 안쪽에 떠 보였다. 이제 헤더는 화면 끝에서 72 안쪽에 붙고 가운데 내용은 가운데에 선다.
   세로 태블릿 중 가장 넓은 3:4(1440)까지만 넓어진다 — 데스크톱 미리보기처럼 가로가 긴 화면에서 끝없이 벌어지지 않게.
   16:10(1200x1920) 기기에서는 예전과 똑같다. */
.stage {
  position: relative;
  width: min(100%, calc(1440 * var(--u)));
  height: calc(1920 * var(--u));
  padding: calc(96 * var(--u)) calc(72 * var(--u));
  display: flex; flex-direction: column; align-items: center;
  text-align: center;
}

/* 화면 제목(.title-deco · .title-deco__arrow · .step-title · .step-title--glow)은 공통 StepTitle(components.css).
   시안 4408:12764 · 1200 기준 값 그대로 올라갔다(26-09-28). 여기엔 시전 대기 제목의 변형만 남긴다. */
/* (시전 대기 제목의 96 특례는 26-09-29 시안에서 다른 화면과 같은 StepTitle 42 가 되어 없앴다) */

/* ===================== 00 운영자 로그인 — Figma 4596:22747(744×1133) 그대로 (26-09-29) =====================
   틀은 대기 화면과 같다(.stage--start · .start-header · .start-main — 아래 "01 대기" 규칙을 함께 쓴다). 헤더엔 로고만.
   본문(폭 400 · 남은 높이 가운데): [제목 109(Hahmlet Bold 48 — 시안은 Warhaven, 26-10-02 라이선스로 교체) → 24 → 입력칸 둘(사이 23)] → 70 → 큰 버튼 400×87.
   공통 Login(components.css)은 옛 스캐너 프레임 값(× --ds-u)이라 여기서 시안 값 × --fu 로 덮는다(공통 원본은 스캐너도 쓴다). */
.screen--login .login-form {
  display: flex; flex-direction: column; align-items: center;
  gap: calc(70 * var(--fu));
  width: calc(400 * var(--fu));
}
.login-fields {
  align-self: stretch;
  display: flex; flex-direction: column; align-items: center;
  gap: calc(24 * var(--fu));
}
.login-fieldset {
  align-self: stretch;
  display: flex; flex-direction: column;
  gap: calc(23 * var(--fu));
}
.screen--login .login-title {
  width: 100%;
  font-family: var(--font-display); font-weight: 700;   /* ⚠ 시안 4596:22747 은 아직 Warhaven OTF Bold 48 — 라이선스로 Hahmlet Bold(TitleDeco 와 같은 서체, 26-10-02) */
  font-size: calc(48 * var(--fu)); line-height: calc(108.154 * var(--fu)); letter-spacing: calc(-0.085 * var(--fu));
  height: calc(109 * var(--fu));
  text-align: center;
  color: var(--color-white-100);
  text-shadow: 0 calc(3.541 * var(--fu)) calc(23.604 * var(--fu)) rgba(5, 7, 15, 0.55);
}
body[data-lang="en"] .screen--login .login-title { font-family: var(--font-display-en); }   /* 한국어와 같은 Hahmlet Bold */
/* TextField — Figma 4483:861 을 폭 400 으로 늘린 인스턴스: 라벨 NEXON Bold 17 / 25.7 → 11 → 입력 59(여백 15 · 19, 글자 Medium 19 / 28.55)
   · 채움 #000 20% · 흰 테두리 0.861(안쪽) · 글로우 #7691FF 40% 3.807 · 플레이스홀더 #BBD4FE 20% */
.screen--login .login-field { gap: calc(11 * var(--fu)); }
.screen--login .login-label { font-size: calc(17 * var(--fu)); line-height: calc(25.7 * var(--fu)); letter-spacing: calc(0.086 * var(--fu)); }
.screen--login .login-input {
  height: calc(59 * var(--fu));
  padding: calc(15 * var(--fu)) calc(19 * var(--fu));
  font-size: calc(19 * var(--fu)); line-height: calc(28.55 * var(--fu)); letter-spacing: 0;
  box-shadow: 0 0 calc(3.807 * var(--fu)) 0 rgba(118, 145, 255, 0.4);
}
.screen--login .login-input::placeholder { color: rgba(187, 212, 254, 0.2); }   /* ⚠ 시안 원본값(비토큰) */
.screen--login .login-error { font-size: calc(14 * var(--fu)); }
/* 로그인 버튼 — btn/main/big(아래 .dcta--stage 완드 규칙). 꺼져 있으면 시안처럼 20% */
.login-cta { margin-top: 0; }
.login-cta:disabled { opacity: 0.2; cursor: default; }
.login-cta:disabled::before { opacity: 1; }

/* 팝업 버튼 — 26-10-01 공통 팝업의 확인 버튼이 PillButton(components.css .pill-btn, 밝은 알약)으로 바뀌었다(#104 · Figma 4774:12664 등).
   크기는 공통 규칙이 --ds-u 로 재서 스캐너와 같은 픽셀. "체험 중인 QR" · 소진 팝업의 [확인]은 공통 280×59 그대로. */
.popup-pill { margin-top: calc(40 * var(--ds-u)); }        /* 본문과 버튼 사이 40 — 예전 QuestButton 자리와 같다 */
/* 버튼 두 개짜리 팝업(시작 화면으로 나가기 전 주의) — Figma Buttons · 사이 16(4781:24327): [홈으로] 217 · 16 · [계속하기] 217.
   [홈으로]는 투명 알약 — Figma 공통 모달 4781:1340 의 [홈으로](4781:24328, 26-10-07 디자이너 확정 · 스캐너 무동작 팝업과 같은 버튼).
   공통 PillButton 엔 아직 없는 변형이라 여기서 .pill-btn--ghost 로 덮는다(DS 로 올릴 때 옮길 것 — 스캐너 styles.css 에도 같은 규칙):
   217×59 · 투명 바탕 · 바깥 테두리 1(안쪽) #EEF1FE 60% → 여백 4 → 안쪽 테두리 0.5 #EEF1FE 45%(207×49) · 글자 #BCC4E6 · 별 무늬 없음.
   양끝 점 — #EEF1FE 15% 판(8) 위 #BCC4E6 점(4): 왼쪽은 바깥 테두리 바로 안(1), 오른쪽은 끝에서 1.5(테두리 1 + 0.5).
   시안의 그림자(0 2 2 #565150)는 버튼 묶음이 아래를 잘라 시안에서도 보이지 않아 넣지 않는다(시안의 면 · 별 무늬는 꺼져 있다). */
.popup-actions { display: flex; justify-content: center; gap: calc(16 * var(--ds-u)); margin-top: calc(40 * var(--ds-u)); }
.popup-actions .popup-pill { margin-top: 0; }
.popup-pill--half { width: calc(217 * var(--ds-u)); }
/* [마법 확정] 체험 종료 안내의 초 세기 줄(26-10-06 #116) — 본문(왜 끝났는지 · 할 일) 아래 한 줄, 본문보다 작고 라일락 보조색.
   "N초"는 공통 강조(.popup__em). 본문과 16 — 공통 .popup__panel 의 gap 40 을 -24 로 당긴다. 버튼까지는 다른 팝업의 본문 → 버튼과 같다.
   시안 없음 — 앱이 정한 값. */
.popup__count {
  margin: calc(-24 * var(--pu)) 0 0;
  text-align: center;
  font-family: var(--font-primary);
  font-size: calc(18 * var(--pu)); line-height: 1.5; letter-spacing: 0.01em;
  color: var(--color-ice-200);
}
.pill-btn--ghost {
  background: transparent; box-shadow: none;
  border: calc(1 * var(--pbu)) solid rgba(238, 241, 254, 0.6);   /* ⚠ 시안 원본값(비토큰) — 26-10-12 시안 4781:24328 */
}
.pill-btn--ghost:focus-visible { box-shadow: var(--focus-ring, 0 0 0 2px #7691FF); }
.pill-btn--ghost .pill-btn__inner { border-color: rgba(238, 241, 254, 0.45); }   /* ⚠ 시안 원본값(비토큰) */
.pill-btn--ghost .pill-btn__inner::before { display: none; }
.pill-btn--ghost::before, .pill-btn--ghost::after {
  background: radial-gradient(circle, #BCC4E6 0 calc(2 * var(--pbu)), rgba(238, 241, 254, 0.15) calc(2 * var(--pbu)));   /* ⚠ 시안 원본값(비토큰) */
}
.pill-btn--ghost::after { right: calc(0.5 * var(--pbu)); }   /* 테두리 1 안에서 0.5 — 바깥 끝에서 1.5 */
.pill-btn--ghost .pill-btn__label { color: #BCC4E6; }   /* ⚠ 시안 원본값(비토큰) */

/* ④ [마법 확정] 기다리는 동안(26-10-02 새 계약 — 서버 완료 응답 뒤 시전 화면) — 버튼은 눌린 채 "확인 중"으로 흐려지고,
   버튼 위 한 줄 안내(.select-note)가 뜬다: 느릴 때(연결이 느려요 · 라일락) / 실패(완료를 저장하지 못했어요 · 실패색 #FC5F5F, 시전 실패와 같은 값).
   표시 · 문구는 시안이 없어 앱이 정한 것 — 26-10-02 디자이너 확인(그대로). 안내는 흐름(step-body)에 끼지 않게 absolute 로 버튼 바로 위에 둔다. */
.select-cta.is-waiting { opacity: 0.55; cursor: default; animation: none; }
.step-body { position: relative; }
.select-note {
  position: absolute; left: 0; right: 0; bottom: calc(138 * var(--fu));   /* 버튼(아래 여백 40 + 70) 위 28 — 26-10-06 버튼이 알약으로 바뀌며 150 → 138 */
  margin: 0; text-align: center;
  font-size: calc(18 * var(--fu)); line-height: 1.5; letter-spacing: calc(0.09 * var(--fu));
  color: var(--color-ice-200);
  opacity: 0; transition: opacity 0.25s ease;
  pointer-events: none;
}
.select-note[data-key="confirmFail"] { color: #FC5F5F; }   /* ⚠ 시안 원본값(비토큰, 05c 실패색) */
.select-note--show { opacity: 1; }

/* ===================== ⑦ 체험 완료 — 26-10-02 Figma wand_completed_webapp(4864:28759) · wand_completed_none(4864:15331) =====================
   배경은 02 · 03 과 같은 층(무늬 그림 luminosity + 세로 그라디언트 .bg-night)인데 무늬가 건너뛰기 70% · 웹앱 12%(26-10-07 새 무늬 그림 — 건너뛰기는 그전 30%, 02 · 03 은 7%).
   웹앱(QR 을 찍은 관람객): 헤더(위 40 · 제목 데코 80 → 10 → 안내 한 줄 NEXON Medium 20) → 본문(위아래 40 · 남은 높이 가운데: 휴대폰 목업 642×486 → 60 → [홈으로] 360×87)
     · 뒤에 소용돌이 선(.bg-result-deco — 시안 「자산 1 2」, 744×592 를 틀 기준 위 285.577, 40% · 오버레이).
   건너뛰기: 남은 높이 가운데에 [제목 데코 80 → 40 → 두 줄(체험이 완료되었습니다 / N초 뒤 홈으로 돌아갑니다 — "N초" #EDBD54)] → 80 → [홈으로]. */
body[data-screen="result"] .bg-art { opacity: 0.1; }
/* 26-10-02 시안 갱신 — 무늬 그림 투명도를 화면마다 올렸다: 건너뛰기(4864:15331) 30% · 웹앱(4864:28759) 12% (luminosity 그대로) */
body[data-screen="result"][data-result="none"] .bg-art { opacity: 0.7; }   /* 26-10-07 새 무늬 그림과 함께 30% → 70%(시안 4864:15331) */
body[data-screen="result"][data-result="webapp"] .bg-art { opacity: 0.12; }
.bg-result-deco {
  position: absolute; left: 50%;
  top: calc(50% - 566.5 * var(--fu) + 285.577 * var(--fu));   /* 스테이지(1133)는 화면 가운데 — 시안 프레임 기준 위 285.577 */
  width: calc(744 * var(--fu)); height: calc(592 * var(--fu));
  transform: translateX(-50%);
  mix-blend-mode: overlay;
  opacity: 0;
  transition: opacity 0.8s ease;
  pointer-events: none;
}
body[data-screen="result"][data-result="webapp"] .bg-result-deco { opacity: 0.4; }
/* 소용돌이 위를 흐르는 빛(26-10-21 다원님 요청 — 기숙사 키오스크 결과 화면과 같은 인터랙션).
   house/client/src/components/result/CurveTrace.tsx · house DS .ds-result-trace 를 그대로 옮겼다: 고리 선 하나(앞쪽 고리 A)의 윤곽선을 따라
   혜성 모양 빛줄기(꼬리가 흐려지는 세 겹)와 머리의 반짝이(✦)가 한 줄기만 9초에 한 바퀴 돈다. 빛줄기는 고리 모양 안에서만 밝히고(clipPath),
   옅은 번짐만 바깥까지. 색 · 진하기 · 섞기(screen)는 house 값 그대로, 굵기 · 반짝이 크기는 house 1080 화면 → 이 그림(744×592)의 비율 0.651 로 줄였다.
   자리는 .bg-result-deco 와 같다(같은 그림 「자산 1 2」의 같은 상자). 휴대폰 · 제목 아래에 깔린다. 동작 줄이기 설정이면 숨긴다. */
.bg-result-trace {
  position: absolute; left: 50%;
  top: calc(50% - 566.5 * var(--fu) + 285.577 * var(--fu));
  width: calc(744 * var(--fu)); height: calc(592 * var(--fu));
  transform: translateX(-50%);
  overflow: visible; pointer-events: none;
  mix-blend-mode: screen;
  opacity: 0;
  transition: opacity 0.8s ease;
}
body[data-screen="result"][data-result="webapp"] .bg-result-trace { opacity: 1; }
.bg-result-trace use { fill: none; stroke-linecap: round; }
.bg-result-trace__line use { stroke: rgba(196, 220, 255, 0.55); stroke-width: 7.8; }   /* house 12px × 0.651 — 고리 안에서만, 선 자체가 살짝 밝아진다 */
.bg-result-trace__halo use { stroke: rgba(130, 172, 255, 0.08); stroke-width: 7.8; }   /* 선 바깥으로 아주 옅게 번진다 */
.bg-result-trace__star { fill: rgba(226, 238, 255, 0.8); transform-box: fill-box; transform-origin: center; animation: result-trace-twinkle 0.9s ease-in-out infinite alternate; }
@keyframes result-trace-twinkle {
  from { transform: scale(0.7) rotate(0deg); opacity: 0.55; }
  to   { transform: scale(1) rotate(30deg); opacity: 0.85; }
}
.stage--result { padding: calc(48 * var(--fu)) 0; gap: 0; justify-content: flex-start; }
.result-web, .result-none { display: none; flex: 1; align-self: stretch; flex-direction: column; align-items: center; min-height: 0; }
.screen--result[data-variant="webapp"] .result-web,
.screen--result[data-variant="none"] .result-none { display: flex; }
.screen--result .title-deco { height: calc(80 * var(--fu)); align-items: center; gap: calc(16 * var(--fu)); }
.result-web__head {
  display: flex; flex-direction: column; align-items: center;
  gap: calc(10 * var(--fu));
  padding-top: calc(40 * var(--fu));
}
.result-web__sub, .result-none__desc {
  margin: 0;
  font-family: var(--font-primary); font-weight: 500;
  font-size: calc(20 * var(--fu)); line-height: 1.5; letter-spacing: calc(0.1 * var(--fu));
  color: #FFFFFF; text-align: center; white-space: nowrap;
}
.result-web__body {
  flex: 1; min-height: 0; align-self: stretch;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: calc(60 * var(--fu));
  padding: calc(40 * var(--fu)) 0;
}
/* 휴대폰 목업 — 시안 Mask group 642×486(마스크: 위 74.2% 까지 그대로 → 아래 끝 투명). 안의 자리는 마스크 상자 기준 시안 px */
.result-phone {
  position: relative; flex: none;
  width: calc(642 * var(--fu)); height: calc(486 * var(--fu));
  overflow: hidden;
  -webkit-mask-image: linear-gradient(180deg, #000 74.2%, transparent 100%);
          mask-image: linear-gradient(180deg, #000 74.2%, transparent 100%);
}
.result-phone__base {                            /* 시안 15 Pro — 흰 화면 바탕 274.632×595.385 · 둥근 32 */
  position: absolute; left: calc(183.254 * var(--fu)); top: calc(15.157 * var(--fu));
  width: calc(274.632 * var(--fu)); height: calc(595.385 * var(--fu));
  border-radius: calc(32 * var(--fu));
  background: #FFFFFF;
}
.result-phone__frame {                           /* 시안 iPhone 15 Pro - TitaniumGray 그림 329.139×645 */
  position: absolute; left: calc(156 * var(--fu)); top: calc(-10 * var(--fu));
  width: calc(329.139 * var(--fu)); height: calc(645 * var(--fu));
  display: block;
}
.result-phone__screen {                          /* 시안 Elder_wand 등 273.938×487 · 위 모서리 둥근 37.229 — 틀 그림 위에 얹는다(시안 순서) */
  position: absolute; left: calc(183.619 * var(--fu)); top: calc(15.5 * var(--fu));
  width: calc(273.938 * var(--fu)); height: calc(487 * var(--fu));
  border-radius: calc(37.229 * var(--fu)) calc(37.229 * var(--fu)) 0 0;
  overflow: hidden; display: block;
}
.result-phone__card { display: block; width: 100%; height: 100%; object-fit: cover; }
/* 고른 주문 곡선(26-10-13) — 웹앱 결과카드처럼 카드 바탕 위 시안 자리에. 자리 · 폭은 app.js 가 카드 기준 % 로 넣는다 */
.result-phone__spell { position: absolute; display: block; height: auto; max-width: none; }
.result-none {
  justify-content: center;
  gap: calc(80 * var(--fu));
  padding: calc(40 * var(--fu)) 0;
}
.result-none__copy { display: flex; flex-direction: column; align-items: center; gap: calc(40 * var(--fu)); }
.result-none__sec { color: #EDBD54; }                                   /* ⚠ 시안 원본값(비토큰) */
/* ⑦ 차례로 나타나기 — 26-10-21 다원님 요청("타이틀 · 서브텍스트가 먼저 나타난 뒤, 좀 있다가 [홈으로]").
   제목(0.1초) → 서브텍스트(0.4초) → 휴대폰 목업(웹앱 판, 0.7초)이 아래에서 살짝 떠오르며 흐림이 걷히고,
   1.5초에 [홈으로]가 같은 방식으로 나타난다(스캐너 결과 [홈으로] 늦게 나타나기 scanner/styles.css result-cta-in 과 같은 움직임).
   나타나기 전엔 visibility hidden 이라 안 보이는 버튼을 잘못 눌러 홈으로 가지 않는다. fill backwards — 끝난 뒤 값을 붙잡지 않아
   [홈으로]를 누를 때 줄어드는 효과가 그대로 된다. 화면이 다시 뜰 때마다 처음부터. 동작 줄이기 설정이면 바로 보인다(아래 reduced-motion). */
.screen--result .title-deco                            { animation: result-rise 0.6s cubic-bezier(0.22, 1, 0.36, 1) 0.1s backwards; }
.screen--result :is(.result-web__sub, .result-none__desc) { animation: result-rise 0.6s cubic-bezier(0.22, 1, 0.36, 1) 0.4s backwards; }
.screen--result .result-phone                          { animation: result-rise 0.8s cubic-bezier(0.22, 1, 0.36, 1) 0.7s backwards; }
.screen--result .result-home                           { animation: result-cta-in 0.8s cubic-bezier(0.22, 1, 0.36, 1) 1.5s backwards; }
@keyframes result-rise {
  from { opacity: 0; transform: translateY(calc(14 * var(--fu))); filter: blur(calc(4 * var(--fu))); }
  to   { opacity: 1; transform: none; filter: none; }
}
@keyframes result-cta-in {
  from { opacity: 0; transform: translateY(calc(20 * var(--fu))) scale(0.97); filter: blur(calc(6 * var(--fu))); visibility: hidden; }
  to   { opacity: 1; transform: none; filter: none; visibility: visible; }
}

/* ===================== 01 대기 — Figma wand_01_대기(4472:774, 744×1133) 그대로 (26-09-29 · 26-09-30 타이틀 변경) =====================
   공통 StartScreen · LanguageToggle(components.css)은 옛 1200 프레임 값이다. 완드 시안이 기기 크기로 다시 그려져서
   이 화면은 시안 숫자 × --fu 로 **덮어쓴다**(공통 원본은 스캐너도 쓰므로 여기서만 바꾼다).
   구조: 스테이지(위 24 · 아래 48) > 헤더(높이 80 · 좌우 36, [로고 | 국기] 양끝 · 가운데)
         + 본문(남은 높이의 가운데, 폭 575 · 간격 70: 타이틀 → 서브텍스트 → CTA 400) — 26-09-30 폭 400 → 575 */
.screen--start { cursor: pointer; }
/* 아래 .start-header · .start-logo · .start-main 규칙은 00 로그인(.stage--login)도 같이 쓴다 */
.stage--start {
  padding: calc(24 * var(--fu)) 0 calc(48 * var(--fu));
  justify-content: flex-start;
  gap: 0;
}
:is(.screen--start, .screen--login) .start-header {
  position: relative; z-index: 2;               /* 흐름 안으로(공통은 absolute) · 배경 연출 레이어 위로 */
  top: auto; left: auto; right: auto;
  align-self: stretch;
  height: calc(80 * var(--fu));
  padding: 0 calc(36 * var(--fu));
  align-items: center;
}
:is(.screen--start, .screen--login) .start-logo { width: calc(196 * var(--fu)); }   /* 196×72 — 자르는 비율은 공통 그대로 */
:is(.screen--start, .screen--login) .start-logo img { filter: none; }               /* 시안 로고엔 글로우가 없다 */
/* 국기 — Btn/flag 56 · 사이 24. 비선택: 여백 3 안에 원판 50.
   선택: 여백 2 안에 원판 52 + 테두리 2(#E1E2E4)가 버튼 **바깥**에 그려진다(Figma stroke OUTSIDE) —
   그래서 테두리와 원판 사이 2 가 비어 배경이 어둡게 비친다. 바깥 테두리는 box-shadow 로 그린다.
   그림자 두 겹(0 0 0.259 · 0 2.068 3.102)은 drop-shadow 라 반경을 절반(표준편차)으로 준다. */
.screen--start .lang-toggle { gap: calc(24 * var(--fu)); }
.screen--start .lang-btn {
  width: calc(56 * var(--fu));
  padding: calc(3 * var(--fu));
  border: 0;
  filter: drop-shadow(0 0 calc(0.13 * var(--fu)) rgba(66, 71, 76, 0.32))
          drop-shadow(0 calc(2.068 * var(--fu)) calc(1.551 * var(--fu)) rgba(66, 71, 76, 0.08));
  transition: box-shadow 0.25s ease;
}
.screen--start .lang-btn--on {
  padding: calc(2 * var(--fu));
  box-shadow: 0 0 0 calc(2 * var(--fu)) #E1E2E4;          /* line/solid/primary */
}

.start-main {                                   /* 시안 Sub Header(104 ~ 1085) — 남은 높이의 가운데 */
  flex: 1; min-height: 0;
  align-self: stretch;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: calc(70 * var(--fu));
}
/* 26-10-02 대기 화면(4864:7556) — [글 묶음(타이틀 로고 → 48 → 장식 선 → 48 → 설명)] → 140 → CTA. 로그인(.stage--login)은 예전 간격 70 그대로 */
.screen--start .start-main { gap: calc(140 * var(--fu)); }
/* 26-10-02 시안: 대기 화면 헤더의 해리포터 로고는 불투명도 0(Logo 4864:7559 — 자리는 남는다). 로그인 화면 로고는 그대로 */
.screen--start .start-logo { opacity: 0; }
.start-copy {
  display: flex; flex-direction: column; align-items: center;
  gap: calc(48 * var(--fu));
  width: calc(575 * var(--fu));
}
.start-ornament {                               /* 26-10-07 시안 Ingredient Label 363×9(예전 244×14 그림) */
  display: block; flex: none;
  width: calc(363 * var(--fu)); height: calc(9 * var(--fu));
}
/* 타이틀 로고 — 26-10-12 시안 Logo Container 575×200: 그림 한 장(LOGO_완드 674×422, 투명 여백 포함)을 상자 가운데에 두고 넘치게(시안 -49.5 · -111).
   그전엔 금속 그림 두 장(WAND 541×79 → 20 → EXPERIENCE 575×89, 높이 188)이었다 — 상자가 12 커져 묶음 전체가 6 위로 올라간다(시안 313.5).
   한국어 화면도 같은 로고(한글판 그림 없음). 공통 .start-title(디자인시스템)은 글자 타이틀용이라 쓰지 않는다. */
.start-logo-title {
  position: relative;
  width: calc(575 * var(--fu)); height: calc(200 * var(--fu));
  margin: 0;
}
/* 타이틀 연출(26-10-22) — 기숙사 배정 키오스크 DS .ds-logo-fx 와 같은 짜임: 같은 그림을 두 장 겹쳐 위(WAND) · 아래(EXPERIENCE)로 자르고
   (그림 높이 49.5% — 두 줄 사이 빈 곳), 줄마다 magic-dust.js 가 흐림 · 투명도를 준다. 가루 캔버스는 그림 상자보다 사방 96(house 140px 을 744 화면으로) 넓다. */
.start-logo-fx__line { position: absolute; inset: 0; }
.start-logo-fx__line--top .start-logo-title__img { clip-path: inset(0 0 50.5% 0); }
.start-logo-fx__line--bottom .start-logo-title__img { clip-path: inset(49.5% 0 0 0); }
/* 가끔 반짝 — 기숙사 배정 키오스크 .ds-logo-fx__glint 와 같은 별빛(가는 십자 + 둥근 빛) · 같은 움직임(3.6초마다, 1.2초 뒤 시작).
   자리는 WAND 의 "D" 둥근 면에서 가장 밝은 금속 빛(그림 70.5% · 37.0%, 26-10-22 다원님 "괜찮은 자리"). 위 줄 상자 안이라 WAND 와 함께 흐려진다.
   크기는 house 72px(로고 폭 967 기준)을 이 그림 폭 674 비율로 48 */
.start-logo-fx__glint {
  position: absolute; left: calc(50% + 138.2 * var(--fu)); top: calc(50% - 54.9 * var(--fu));
  width: calc(48 * var(--fu)); height: calc(48 * var(--fu)); margin: calc(-24 * var(--fu)) 0 0 calc(-24 * var(--fu));
  pointer-events: none;
  background:
    radial-gradient(circle, rgba(255, 252, 240, 0.95) 0 calc(1.3 * var(--fu)), rgba(255, 226, 160, 0.5) calc(3.3 * var(--fu)), rgba(255, 211, 114, 0) calc(10.7 * var(--fu))),
    linear-gradient(90deg, rgba(255, 240, 200, 0) 0%, rgba(255, 240, 200, 0.9) 50%, rgba(255, 240, 200, 0) 100%) center / calc(48 * var(--fu)) calc(1.4 * var(--fu)) no-repeat,
    linear-gradient(0deg, rgba(255, 240, 200, 0) 0%, rgba(255, 240, 200, 0.9) 50%, rgba(255, 240, 200, 0) 100%) center / calc(1.4 * var(--fu)) calc(48 * var(--fu)) no-repeat;
  mix-blend-mode: screen; opacity: 0;
  animation: start-logo-glint 3.6s ease-in-out 1.2s infinite;
}
@keyframes start-logo-glint {
  0%, 60%, 100% { opacity: 0; transform: scale(0.3) rotate(0deg); }
  72% { opacity: 1; transform: scale(1) rotate(25deg); }
  86% { opacity: 0; transform: scale(0.5) rotate(45deg); }
}
.start-logo-fx__dust {
  position: absolute; left: 50%; top: 50%;
  width: calc((674 + 192) * var(--fu)); height: calc((422 + 192) * var(--fu));
  margin: calc(-307 * var(--fu)) 0 0 calc(-433 * var(--fu));
  pointer-events: none;
}
/* [시작하기] 뒤 사라지기(26-10-22) — 기숙사 배정 키오스크 app.css .screen-layer--leaving 과 같은 마스크: --sweep(%)을 magic-dust.js 가 매 프레임 올려
   대기 화면을 아래부터 지운다(흐려지는 폭 16%). 가루는 화면 전체를 덮는 캔버스에(.magic-exit, 누름은 통과) */
#screen-start.is-sweeping {
  --sweep: -2%;
  -webkit-mask-image: linear-gradient(to top, transparent calc(var(--sweep) - 16%), #000 calc(var(--sweep) + 2%));
          mask-image: linear-gradient(to top, transparent calc(var(--sweep) - 16%), #000 calc(var(--sweep) + 2%));
}
.magic-exit { position: fixed; inset: 0; width: 100%; height: 100%; z-index: 45; pointer-events: none; }
.start-logo-title__img {
  position: absolute; left: 50%; top: 50%;
  width: calc(674 * var(--fu)); height: calc(422 * var(--fu));
  margin: calc(-211 * var(--fu)) 0 0 calc(-337 * var(--fu));   /* 가운데 — transform 은 등장 효과(filter)와 겹치지 않게 비워 둔다 */
  max-width: none;
}
/* 설명 — 26-10-01 시안(4795:34446): 마름모 · 윗선 · 위아래 여백이 빠지고 폭 575 · 높이 30(문구 한 줄) · 좌우 여백 10 · 둥근 20.
   배경은 옅은 타원 라디얼 20%(가운데 50% · 44.75%, 가로 반지름 246.4 · 세로 16.6, #12172D → 투명 — 시안 #16122D 는 네이비 규칙으로 바꿈). */
.screen--start .start-sub { width: calc(575 * var(--fu)); margin-top: 0; }
.screen--start .start-sub__body {
  display: flex; justify-content: center;       /* 시안 가로 오토레이아웃 — 문구가 박스보다 길어도(영문) 가운데서 넘친다 */
  padding: 0 calc(10 * var(--fu));
  border-radius: calc(20 * var(--fu));
  background: radial-gradient(calc(246.4 * var(--fu)) calc(16.6 * var(--fu)) at 50% 44.75%,
    rgba(18, 23, 45, 0.2) 0%, rgba(0, 0, 0, 0) 100%);
}
.screen--start .start-sub__body::before { content: none; }
.screen--start .start-desc {                   /* NEXON Regular 20 · 행간 1.5 · 자간 1% · #EFF8FF(⚠ 시안 원본값) */
  font-size: calc(20 * var(--fu));
  font-weight: 400;
  white-space: nowrap;
}
/* 큰 CTA(.dcta--stage) — 완드의 큰 버튼은 전부 Figma btn/main/big 을 폭 400 틀로 늘린 인스턴스(Start Button 400×87)다:
   대기 [시작하기](4562:20375) · 로그인 · 완드 [선택 완료](4591:20929) · 마법 [마법 확정](4591:21053). 값은 원본 그대로(배율 1).
   공통 .dcta--stage 는 1.727배라 배율 k 를 1, 단위를 --fu 로 바꿔 쓴다.
   틀 400×87 안에서 면 381.915×78 은 위 5 · 아래 4 · 왼쪽 8.511 · 오른쪽 9.574 — 가운데보다 0.53 왼쪽이다.
   · 안쪽 글로우(굵은 반투명 보더 + 흐림)는 면이 아니라 **틀 전체**에 걸려 면 바깥으로도 번진다.
   · 글자는 면 위에서 16(가운데보다 1 아래). · 모서리 브래킷은 면 바깥으로 가로 5.32 · 세로 4. */
.dcta--stage {
  --k: 1;
  --swu: var(--fu);
  left: calc(-0.53 * var(--fu));
  width: calc(381.915 * var(--fu));
  min-width: 0;
  padding: 0;
  margin: calc(5 * var(--fu)) 0 calc(4 * var(--fu));
  flex: none;
}
/* 면 테두리 1.846 — 브라우저는 border 를 기기 픽셀로 깎아(1.5) 시안보다 가늘고 흐려진다.
   그래서 border 를 없애고 같은 두께를 안쪽 그림자(깎이지 않는다)로 ::after 에 그린다.
   border 가 없어져서 아래 절대 위치 값은 시안의 "면 바깥선 기준" 그대로다. */
.dcta--stage { border-width: 0; }
.dcta--stage::after {
  content: ""; position: absolute; inset: 0;
  box-shadow: inset 0 0 0 calc(1.846 * var(--fu)) var(--color-purple-100);
  pointer-events: none;
}
.dcta--stage::before {
  inset: calc(-5 * var(--fu)) calc(-9.574 * var(--fu)) calc(-4 * var(--fu)) calc(-8.511 * var(--fu));
}
.dcta--stage .dcta__label { top: calc(1 * var(--fu)); }
.dcta--stage .dcta__corner { z-index: 1; }                 /* 시안처럼 테두리(::after) 위에 */
.dcta--stage .dcta__corner--tl { left: calc(-5.32 * var(--fu)); top: calc(-4 * var(--fu)); }
.dcta--stage .dcta__corner--tr { right: calc(-5.32 * var(--fu)); top: calc(-4 * var(--fu)); }
.dcta--stage .dcta__corner--bl { left: calc(-5.32 * var(--fu)); bottom: calc(-4 * var(--fu)); }
.dcta--stage .dcta__corner--br { right: calc(-5.32 * var(--fu)); bottom: calc(-4 * var(--fu)); }

/* 영문 타이틀 — 한국어와 같은 Hahmlet(:root 의 --font-display-en, 26-10-02 Warhaven 라이선스로 교체). 굵기는 한국어와 같게 둔다:
   화면 · 시전 · 쿨타임 제목은 Hahmlet Bold(시안 TitleDeco), 성공 마법 이름은 Regular. 공통 영문 규칙이 400 으로 누르던 것을 되돌린다.
   마법 카드 이름은 영문도 한국어와 같은 **NEXON** 그대로(26-09-30 사용자 지시 — 예전엔 영문만 Harry Beast 였다).
   로마자 병기 줄(INCENDIO 등)은 영문에선 제목과 겹쳐 숨긴다. */
body[data-lang="en"] :is(.step-title, .cast-head .cast-title, .cool .cool__title) { font-family: var(--font-display-en); font-weight: 700; }
body[data-lang="en"] .burst__name {
  font-family: var(--font-display-en);
  font-weight: 400;
}
body[data-lang="en"] .spell-card__en { display: none; }
/* 금색 [시작하기] — 26-10-02 시안 Start Button(4864:9401). 화면 전체가 버튼이라 이건 '어디를 누르는지' 알려주는 표지다 — 실제 버튼이 아니다.
   틀 360×87(공통 .start-cta 의 위 56 은 쓰지 않는다 — 시안은 설명 아래 140 이 틀 위) 안에:
     .gold-cta__btn    틀 그대로 · 넘침 자름 · 그림자 0 4 6 rgba(0,0,0,.16) (⑦ [홈으로]도 같은 .gold-cta 그림)
       __face  시안 Vector(353.4×86, 틀 기준 2.85, 1) 그림 그대로 — 면 343.72×78(틀 기준 7.66, 5) · 금빛 라디얼 40% · 바깥 테두리 3(#FDE4AB → #FEC33F) ·
               안쪽 금선 1 · 네 모서리 금 삼각 16(위 · 아래 왼쪽 #FDE3AA, 오른쪽 #FEC340) · 검정 30% 노이즈 결
       __glow  시안 Button Border(Stroke) 그림 그대로(374.77×101.77, 틀 기준 -7.38, -7.38 — 틀 밖은 잘린다): #A5A5A5 20% 굵은 테두리를 3.69 흐림
       __label 글자 NEXON Medium 32 · 행간 1.5 · 자간 0.16, 금 그라디언트(왼→오 #FDE4AB 32.148% → #FEC33F 69.969%). 상자 343.723 · 위 21 · 가운데보다 0.36 오른쪽
   숨쉬기 금빛(::before — 바깥 테두리 상자에)은 앱 움직임(시안엔 정지 화면만 있다). */
/* 금색 큰 버튼 공통(.gold-cta) — [시작하기](표지) · ⑦ [홈으로](진짜 버튼)가 같은 그림을 쓴다 */
.gold-cta {
  position: relative; flex: none;
  width: calc(360 * var(--fu)); height: calc(87 * var(--fu));
  margin: 0; padding: 0; border: 0; background: none;
  font: inherit; cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
button.gold-cta:active .gold-cta__btn { transform: scale(0.97); }
button.gold-cta:focus-visible { outline: 2px solid #FEC33F; outline-offset: calc(4 * var(--fu)); }
.start-cta.start-cta--gold {
  margin: 0;
  cursor: default;                              /* 누르는 건 화면 전체다 */
}
.start-cta--gold::before {
  content: ""; position: absolute;
  left: calc(2.85 * var(--fu)); top: calc(1 * var(--fu));
  width: calc(353.4 * var(--fu)); height: calc(86 * var(--fu));
  animation: cta-breathe-gold 2.8s ease-in-out infinite;
  pointer-events: none;
}
.gold-cta__btn {
  position: absolute; inset: 0;
  overflow: hidden;
  filter: drop-shadow(0 calc(4 * var(--fu)) calc(6 * var(--fu)) rgba(0, 0, 0, 0.16));   /* 시안 Shadow */
}
.gold-cta__face {
  position: absolute; left: calc(2.85 * var(--fu)); top: calc(1 * var(--fu));
  width: calc(353.4 * var(--fu)); height: calc(86 * var(--fu));
  display: block;
}
.gold-cta__glow {
  position: absolute; left: calc(-7.383 * var(--fu)); top: calc(-7.383 * var(--fu));
  width: calc(374.766 * var(--fu)); height: calc(101.766 * var(--fu));
  display: block;
}
.gold-cta__label {
  position: absolute; left: calc(50% + 0.36 * var(--fu)); top: calc(21 * var(--fu));
  width: calc(343.723 * var(--fu));
  transform: translateX(-50%);
  font-family: var(--font-primary); font-weight: 500;
  font-size: calc(32 * var(--fu)); line-height: 1.5; letter-spacing: calc(0.16 * var(--fu));
  text-align: center; white-space: nowrap;
  background: linear-gradient(90deg, #FDE4AB 32.148%, #FEC33F 69.969%);   /* ⚠ 시안 원본값(비토큰) */
  -webkit-background-clip: text; background-clip: text;
  color: transparent;
}
@keyframes cta-breathe-gold {
  0%, 100% { box-shadow: 0 0 calc(10 * var(--u)) rgba(254, 195, 63, 0.2); }
  50%      { box-shadow: 0 0 calc(44 * var(--u)) rgba(254, 195, 63, 0.45); }
}
/* [시작하기]를 누른 1초 — 26-10-02 시안 wand_01(4864:9336) Start Button(400×87): 버튼 자리에 마법 지팡이 그림 179×119(가운데 · 위 -31.5).
   틀 400×87 은 버튼 틀(360×87)과 가운데가 같다. 자리 · 크기는 시안 px × --fu.
   그림 좌표(그림 상자 기준 %): 지팡이 끝(별빛) 70% · 22.85%, 손잡이 끝 6.5% · 94.1%. 줄기는 끝 쪽으로 53.3° 방향.
   is-casting(app.js castStart) 동안(1초, 움직임은 앱이 정한 것):
     0~0.2s  버튼(면 그림 · 테두리 빛 · 글자)이 사라진다
     0.05~0.4s 지팡이(.start-cast__wand — 그림을 줄기 띠 마스크로 가린 것)가 손잡이를 축으로 10° 들어 올려지며 나타난다
     0.28~0.78s 지팡이 끝 섬광(.start-cast__flash)
     0.3~0.8s 마법(.start-cast__magic — 그림 전체)이 지팡이 끝에서 둥글게 번져 나오며(마스크 반지름 --mr) 밝게(2.2배) 터졌다가 가라앉는다
     0.85s~  지팡이 띠 사본은 사라지고 그림 한 장만 남는다 = 시안 끝 장면
   빛방울(.cast-spark)은 app.js 가 지팡이 끝에서 흩뿌린다. 움직임 줄이기면 끝 장면만 보인다. */
@property --mr { syntax: "<percentage>"; inherits: false; initial-value: 0%; }
.start-cast {
  position: absolute; left: 50%; top: 50%;
  width: calc(400 * var(--fu)); height: calc(87 * var(--fu));
  transform: translate(-50%, -50%);
  pointer-events: none;
  opacity: 0; visibility: hidden;
}
.start-cast__wand, .start-cast__magic {
  position: absolute; left: calc(110.5 * var(--fu)); top: calc(-31.5 * var(--fu));
  width: calc(179 * var(--fu)); height: calc(119 * var(--fu));
  display: block;
}
.start-cast__wand {                              /* 지팡이 줄기만 — 줄기를 따라가는 띠(143.3°) ∩ 손잡이 → 끝 범위(53.3°) */
  transform-origin: 6.5% 94.1%;
  -webkit-mask-image:
    linear-gradient(143.3deg, transparent 40%, #000 44%, #000 51.5%, transparent 55.5%),
    linear-gradient(53.3deg, #000 70%, transparent 78%);
  -webkit-mask-composite: source-in;
  mask-image:
    linear-gradient(143.3deg, transparent 40%, #000 44%, #000 51.5%, transparent 55.5%),
    linear-gradient(53.3deg, #000 70%, transparent 78%);
  mask-composite: intersect;
  opacity: 0;
}
.start-cast__magic {                             /* 그림 전체 — 지팡이 끝에서 번져 나온다 */
  --mr: 0%;
  -webkit-mask-image: radial-gradient(var(--mr) var(--mr) at 70% 22.85%, #000 0%, #000 65%, transparent 100%);
  mask-image: radial-gradient(var(--mr) var(--mr) at 70% 22.85%, #000 0%, #000 65%, transparent 100%);
}
/* 빛방울 — 지팡이 끝에서 app.js 가 뿌린다(위치는 틀 400×87 기준 %, 크기 --s(시안 px) · 번짐 --b · 흘러가는 방향 --dx/--dy · 수명 --life · 시작 --delay).
   금빛 라디얼 점이 커졌다가 흩어지며 사라진다. 별빛(--star)은 네 갈래 십자 반짝임. */
.start-cast__sparks { position: absolute; inset: 0; pointer-events: none; }
.cast-spark {
  position: absolute; left: var(--x); top: var(--y);
  width: calc(var(--s) * var(--fu)); height: calc(var(--s) * var(--fu));
  margin: calc(var(--s) * var(--fu) / -2) 0 0 calc(var(--s) * var(--fu) / -2);
  border-radius: 50%;
  background: radial-gradient(circle, #FFFBE6 0%, #FFD76A 30%, rgba(255, 190, 70, 0.6) 52%, rgba(255, 170, 50, 0) 70%);
  filter: blur(calc(var(--b, 0) * var(--fu)));
  opacity: 0;
  animation: cast-spark var(--life, 1s) ease-out var(--delay, 0s) both;
}
.cast-spark--star {
  border-radius: 0; filter: none;
  background:
    linear-gradient(#FFFBE6, #FFFBE6) center / 14% 100% no-repeat,
    linear-gradient(#FFFBE6, #FFFBE6) center / 100% 14% no-repeat,
    radial-gradient(circle, rgba(255, 236, 170, 0.9) 0%, rgba(255, 200, 90, 0) 60%);
}
@keyframes cast-spark {
  0%   { opacity: 0; transform: translate(0, 0) scale(0.2); }
  18%  { opacity: 1; transform: translate(calc(var(--dx) * var(--fu) * 0.15), calc(var(--dy) * var(--fu) * 0.15)) scale(1); }
  100% { opacity: 0; transform: translate(calc(var(--dx) * var(--fu)), calc(var(--dy) * var(--fu))) scale(0.55); }
}
/* 지팡이 끝 섬광 — 그림의 별빛 자리(틀 기준 235.8, -4.3)에서 한 번 크게 번졌다 사라진다 */
.start-cast__flash {
  position: absolute; left: calc(235.8 * var(--fu)); top: calc(-4.3 * var(--fu));
  width: calc(150 * var(--fu)); height: calc(150 * var(--fu));
  margin: calc(-75 * var(--fu)) 0 0 calc(-75 * var(--fu));
  border-radius: 50%;
  background: radial-gradient(circle, #FFFFFF 0%, #FFF1C2 16%, rgba(255, 205, 100, 0.5) 38%, rgba(255, 180, 60, 0) 70%);
  opacity: 0; transform: scale(0.3);
  pointer-events: none;
}
.start-cta.is-casting::before { animation: none; box-shadow: none; }
.start-cta.is-casting .gold-cta__btn { opacity: 0; transition: opacity 0.2s ease; }
.start-cta.is-casting .start-cast { opacity: 1; visibility: visible; }
.start-cta.is-casting .start-cast__wand  { animation: cast-wand 1s cubic-bezier(0.2, 0.8, 0.3, 1) both; }
.start-cta.is-casting .start-cast__magic { animation: cast-magic 1s ease-out both; }
.start-cta.is-casting .start-cast__flash { animation: cast-flash 0.5s ease-out 0.28s both; }
@keyframes cast-wand {
  0%, 5% { opacity: 0; transform: rotate(-10deg) translateY(calc(4 * var(--fu))); }
  40%    { opacity: 1; transform: none; }
  82%    { opacity: 1; transform: none; }
  100%   { opacity: 0; transform: none; }
}
@keyframes cast-magic {
  0%, 30% { --mr: 0%;   filter: brightness(2.2); }
  80%     { --mr: 220%; filter: brightness(1.15); }
  100%    { --mr: 220%; filter: brightness(1); }
}
@keyframes cast-flash {
  0%   { opacity: 0; transform: scale(0.3); }
  25%  { opacity: 1; transform: scale(1); }
  100% { opacity: 0; transform: scale(1.5); }
}


/* ===================== 02~04 공통 틀 — Figma wand_02 · 03 · 04(744×1133, 26-09-29) =====================
   스테이지(위아래 48 · 좌우 0) > 헤더(.step-head = Instructions Container, 사이 40): 상단 바 56(뒤로 56 왼쪽 36 · 진행 바 284 가운데) → 제목 데코 80
   > 본문(.step-body = Spell Subcontainer: 폭 664 · 위아래 40 · 사이 80) > 목록(.step-list = Spell List: 세로 · 가운데 · 사이 60) → 큰 버튼 / 작은 알약. */
.stage--step { padding: calc(48 * var(--fu)) 0; gap: 0; justify-content: flex-start; }
.stage--step .step-head { align-self: stretch; align-items: stretch; gap: calc(40 * var(--fu)); text-align: center; }
.stage--step .step-bar { height: calc(56 * var(--fu)); padding: 0 calc(36 * var(--fu)); }
.stage--step .step-head__main .title-deco,
.cast-head .title-deco { height: calc(80 * var(--fu)); align-items: center; gap: calc(16 * var(--fu)); }
.step-body {
  width: calc(664 * var(--fu)); max-width: 100%;
  padding: calc(40 * var(--fu)) 0;
  display: flex; flex-direction: column; align-items: center;
  gap: calc(80 * var(--fu));
}
.step-list {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: calc(60 * var(--fu));
}
/* 작은 알약 버튼 — 26-10-02 Figma 컴포넌트 QRScanPanel/SkipButton(4476:787) 그대로: 131×47 · 여백 14 · 32 · 채움 #05070F 40% · 테두리 #EEF1FE 35% 1.5(안쪽)
   · NEXON Medium 19 / 18.293(글자 상자 19) · #BBD4FE. 시안의 #08050F · #F3EEFE 는 키 컬러 규칙(26-09-29)대로 네이비 톤으로 둔다.
   테두리는 안쪽이라 크기에 안 들어간다 — border 대신 안쪽 그림자로 그려 폭(글자 + 64) · 높이 47 이 시안과 같게 한다.
   스캔 [건너뛰기]는 흐름 안에, 쿨타임 [그만두기]만 하단 고정(같은 컴포넌트 — 시안 설명). */
.skip-btn, .quit-btn {
  display: inline-flex; align-items: center; justify-content: center;
  height: calc(47 * var(--fu)); box-sizing: border-box;     /* 시안 47 — 글자 상자 반올림으로 커지지 않게 높이를 못 박는다 */
  padding: 0 calc(32 * var(--fu));
  border: 0;
  box-shadow: inset 0 0 0 calc(1.5 * var(--fu)) rgba(238, 241, 254, 0.35);   /* ⚠ 시안 원본값(비토큰) */
  border-radius: var(--radius-full);
  background: rgba(5, 7, 15, 0.4);
  font-family: var(--font-primary);
  font-size: calc(19 * var(--fu)); line-height: calc(18.293 * var(--fu)); font-weight: 500;
  color: #BBD4FE;                                                    /* ⚠ 시안 원본값(비토큰) */
  white-space: nowrap;
  cursor: pointer;
}
.skip-btn { flex: none; }
.skip-btn:active { transform: scale(0.95); }
/* 구분선 안내 — Figma Additional Info Container · Guide Subcontainer: 위 선 1 #A6BCD8(안쪽) · 여백 12 · 40
   · NEXON Regular 18 / 27 · 자간 1% · #EFF8FF 70%. 문구가 칸보다 길면 가운데서 양옆으로 넘친다(시안 02). */
.info-note {
  align-self: stretch;
  display: flex; justify-content: center;
  padding: calc(12 * var(--fu)) calc(40 * var(--fu));
  border-top: calc(1 * var(--fu)) solid #A6BCD8;                     /* ⚠ 시안 원본값(비토큰) */
  box-sizing: border-box;
}
.info-note p {
  margin: 0;
  font-size: calc(18 * var(--fu)); line-height: 1.5; letter-spacing: 0.01em; font-weight: 400;
  color: rgba(239, 248, 255, 0.7);                                   /* ⚠ 시안 원본값(비토큰) */
  white-space: nowrap;
}

/* ===================== 02 QR 스캔 =====================
   목록(.step-list--scan)은 시안 Spell List 500×654(남은 높이를 채움) — 원 424 → 60 → 안내 묶음(.scan-state, 사이 20). 그 아래 80 에 [건너뛰기](47).
   (시안 첫 프레임 4472:777 의 목록은 폭이 원에 맞춰 424 이고 확인 중 · 완료 프레임은 500 이다 — 상태에 따라 선 길이가 달라지지 않게 500 으로 둔다.)
   스캔 패널은 Figma QRScanPanel/ScanPanel(4479:804, 26-09-29 새 시안) 그대로 — 단위 --fu(시안 1px).
   [링] 422 원 · 두께 4%(8.44) · #D9D9D9 10%  → 확인 중엔 그 위에 밝은 호(#FFFEEE, 306°)가 돌고, 완료면 링 전체가 빛난다
       (호 · 링은 시안 layer blur 6 + 흰 글로우 12 — CSS blur 3 + drop-shadow 6).
   [뷰파인더] 252 둥근 사각(17.379) · 채움 #1B1411 40% · 테두리 #E2E2E2 51% 2.172 · 안쪽 19.552 에 브래킷 30.414(#E2E2E2 3.041 · 둥근 끝)
       · 가운데 스캔라인 186.828×2.172(그라디언트 #10121C → #7ECEF4 60% → #10121C 80%) — 위아래로 오가는 건 앱 움직임.
   예전(스캐너에서 옮긴 검은 원 + 보라 링 + 초록 체크)은 걷어냈다. 완료 화면에도 체크 글리프는 없다(시안). */
.step-list--scan { width: calc(500 * var(--fu)); height: calc(654 * var(--fu)); }
/* 26-10-02 [건너뛰기]가 47 로 커지면서(SkipButton 4476:787) 시안 목록은 남은 높이를 채우는(FILL) 654 가 됐다(4472:777 · 4562:20548):
   1133 − 위아래 48 · 48 − 헤더 176 − 본문 위아래 40 · 40 − 사이 80 − 버튼 47 = 654. 버튼 위치(998)는 그대로다. */
.scan-panel {
  position: relative; flex: none;
  width: calc(424 * var(--fu)); aspect-ratio: 1;
  display: flex; align-items: center; justify-content: center;
}
/* 원 아래 안내 묶음 — 대기: 안내 한 줄(NEXON Medium 22 / 33 · #EFF8FF) / 확인 중 · 완료: 초록 글자 칩 → 구분선 안내 */
.scan-state {
  align-self: stretch;
  display: flex; flex-direction: column; align-items: center;
  gap: calc(20 * var(--fu));
}
.scan-desc {
  margin: 0;
  font-size: calc(22 * var(--fu)); line-height: 1.5; letter-spacing: 0.005em; font-weight: 500;
  color: #EFF8FF;                                                    /* ⚠ 시안 원본값(비토큰) */
  word-break: keep-all;
}
/* 칩 "스캔 중" · "스캔 완료" — 시안 Scan Complete Button Container: 높이 35(여백 4 · 20) · 채움 흰 → #CFD6F0 → 흰 가로 그라디언트 10%
   · 테두리 #FEFDFC 32% 1(바깥) · 안쪽 그림자 #7691FF 40% 8 · 뒤 흐림 12 · 글자 NEXON Regular 18 / 27 · 자간 1% · #92FA9B */
.scan-chip {
  display: none; align-items: center; justify-content: center;
  height: calc(35 * var(--fu));
  padding: calc(4 * var(--fu)) calc(20 * var(--fu));
  border-radius: var(--radius-full);
  background: linear-gradient(90deg, rgba(255, 255, 255, 0.1) 0%, rgba(207, 214, 240, 0.1) 50%, rgba(255, 255, 255, 0.1) 100%);   /* ⚠ 시안 원본값 */
  box-shadow: 0 0 0 calc(1 * var(--fu)) rgba(254, 253, 252, 0.32), inset 0 0 calc(8 * var(--fu)) rgba(118, 145, 255, 0.4);
  -webkit-backdrop-filter: blur(calc(6 * var(--fu)));
          backdrop-filter: blur(calc(6 * var(--fu)));
}
.scan-chip__text {
  font-size: calc(18 * var(--fu)); line-height: 1.5; letter-spacing: 0.01em; font-weight: 400;
  color: #92FA9B;                                                    /* ⚠ 시안 원본값(비토큰) */
  white-space: nowrap;
}
#screen-scan:not([data-state="scan"]) .scan-desc { display: none; }
#screen-scan:not([data-state="scan"]) .scan-chip { display: inline-flex; }
/* 링 — 422 원(안쪽 1), 두께 8.44 */
.scan-ring {
  position: absolute; inset: calc(1 * var(--fu));
  border-radius: 50%;
  border: calc(8.44 * var(--fu)) solid rgba(217, 217, 217, 0.1);        /* ⚠ 시안 원본값(비토큰) */
  pointer-events: none;
}
/* 확인 중 · 완료 — 밝은 호/링. 흐림은 바깥 요소에, 호 자르기(마스크)는 ::before 에 둬서 호 끝도 부드럽게 번진다(시안 순서: 그린 뒤 흐림). */
.scan-ring--glow {
  display: none;
  border: 0;
  filter: blur(calc(3 * var(--fu))) drop-shadow(0 0 calc(6 * var(--fu)) rgba(255, 255, 255, 0.6));
}
.scan-ring--glow::before {
  content: ""; position: absolute; inset: 0;
  border-radius: 50%;
  border: calc(8.44 * var(--fu)) solid #FFFEEE;                          /* ⚠ 시안 원본값(비토큰) */
}
#screen-scan:not([data-state="scan"]):not([data-state="fail"]) .scan-ring--glow { display: block; }
/* 확인 중 — 12시에서 시계 방향으로 306° 만 그린 호가 돈다(시안 각도 270°→576°) */
#screen-scan[data-state="loading"] .scan-ring--glow { animation: rings-spin 2.4s linear infinite; }
#screen-scan[data-state="loading"] .scan-ring--glow::before {
  -webkit-mask: conic-gradient(#000 0 306deg, transparent 306deg);
          mask: conic-gradient(#000 0 306deg, transparent 306deg);
}
@keyframes rings-spin { to { transform: rotate(360deg); } }
/* 뷰파인더 — 252 둥근 사각. 테두리는 안쪽(INSIDE)이라 border-box 그대로 */
.viewfinder {
  position: relative;
  width: calc(252 * var(--fu)); height: calc(252 * var(--fu));
  box-sizing: border-box;
  border-radius: calc(17.379 * var(--fu));
  overflow: hidden;
  background: rgba(27, 20, 17, 0.4);                                     /* ⚠ 시안 원본값(비토큰) */
  border: calc(2.172 * var(--fu)) solid rgba(226, 226, 226, 0.51);       /* ⚠ 시안 원본값(비토큰) */
}
/* 확인 중 · 완료 — 카메라 · 스캔라인 · 카메라 꺼짐 안내는 숨긴다(뷰파인더 틀은 남는다 — 시안) */
#screen-scan:not([data-state="scan"]):not([data-state="fail"]) .vf-scanline,
#screen-scan:not([data-state="scan"]):not([data-state="fail"]) .scan-video,
#screen-scan:not([data-state="scan"]):not([data-state="fail"]) .scan-off { visibility: hidden; }
/* 실패(26-10-02 시안 wand_02 4864:28953) — 잘못된 QR · 네트워크 오류: 토스트 대신 뷰파인더 브래킷이 #FF8484 로 바뀌고
   원 아래 칩이 "스캔 실패"(같은 칩 · 글자 #FF8484)가 된다. 링 · 스캔라인 · 카메라는 대기 때 그대로(시안). 3.2초 뒤 대기로 돌아간다(app.js scanFailed). */
#screen-scan[data-state="fail"] .vf-bracket { stroke: #FF8484; }                 /* ⚠ 시안 원본값(비토큰, red_500) */
#screen-scan[data-state="fail"] .scan-chip__text { color: #FF8484; }
/* #107(지훈님) — 확인 중 · 완료 표시 중엔 [뒤로] · [건너뛰기]가 눌리지 않는다(스캐너 #100 과 같은 방식, app.js 도 막는다).
   응답 전에 나가면 서버엔 체험이 시작된 채 남거나, 다시 들어온 스캔 화면이 늦은 응답으로 넘어간다. 실패 표시 중엔 진행 중인 요청이 없어 눌린다. */
#screen-scan:is([data-state="loading"], [data-state="done"]) :is(.icon-back, .skip-btn) { pointer-events: none; }

/* 실패 토스트 — 모양은 디자인시스템 공통 Toast(.toast--fail, Figma 3903:27090 · 단위 --ds-u).
   여기는 자리와 나타나기만: 원 한가운데 위에 띄운다 — 하단 안내·버튼을 가리지 않음.
   절대 위치라 폭이 원 절반으로 줄지 않게 글자 폭(max-content)으로 두고, 안내가 길면 472(장식 포함)에서 접는다.
   ⚠ 뒤 흐림(backdrop-filter)은 넣지 않는다 — 디자이너 결정으로 스캐너에만 있다(26-09-28). */
.scan-toast {
  position: absolute; left: 50%; top: calc(514.5 * var(--fu)); z-index: 20;   /* 원 가운데(시안: 48 + 176 + 40 + 38.5 + 212) */
  width: max-content; max-width: calc(472 * var(--ds-u));
  transform: translate(-50%, calc(-50% + 20 * var(--u)));
  opacity: 0; pointer-events: none;
  transition: opacity 0.25s ease, transform 0.25s ease;
}
.scan-toast--show { opacity: 1; transform: translate(-50%, -50%); }

.scan-video {
  width: 100%; height: 100%; object-fit: cover;
  transform: scaleX(-1);            /* 전면 카메라 — 거울처럼 보여야 손이 자연스럽다 */
}
/* 코너 브래킷 — 30.414 ㄱ자, 선 3.041 둥근 끝, 틀 가장자리에서 19.552(절대 위치 기준은 테두리 안쪽이라 2.172 를 뺀다) */
.vf-bracket {
  position: absolute; z-index: 2; pointer-events: none;
  width: calc(30.414 * var(--fu)); height: calc(30.414 * var(--fu));
  overflow: visible;
  fill: none; stroke: #E2E2E2; stroke-width: 3.041;                     /* ⚠ 시안 원본값(비토큰) · 선 굵기는 viewBox 단위 */
  stroke-linecap: round; stroke-linejoin: round;
}
.vf-bracket--tl { top: calc(17.38 * var(--fu)); left: calc(17.38 * var(--fu)); }
.vf-bracket--tr { top: calc(17.38 * var(--fu)); right: calc(17.38 * var(--fu)); transform: scaleX(-1); }
.vf-bracket--bl { bottom: calc(17.38 * var(--fu)); left: calc(17.38 * var(--fu)); transform: scaleY(-1); }
.vf-bracket--br { bottom: calc(17.38 * var(--fu)); right: calc(17.38 * var(--fu)); transform: rotate(180deg); }
/* 스캔라인 — 186.828×2.172, 가운데(시안). 14% ↔ 84% 를 2.2초에 오가는 건 앱 움직임(스캐너와 같다) */
.vf-scanline {
  position: absolute; z-index: 2; pointer-events: none;
  left: calc(30.405 * var(--fu));
  width: calc(186.828 * var(--fu)); height: calc(2.172 * var(--fu));
  background: linear-gradient(90deg, #10121C 23.1%, rgba(126, 206, 244, 0.6) 48.8%, rgba(16, 18, 28, 0.8) 74.6%);   /* ⚠ 시안 원본값 */
  animation: vf-scanline 2.2s ease-in-out infinite alternate;
}
@keyframes vf-scanline { from { top: 14%; } to { top: 84%; } }
/* 카메라를 못 켰을 때만 — app.js 가 켠다(뷰파인더 안을 덮는다) */
.scan-off {
  display: none;
  position: absolute; inset: 0; z-index: 3;
  flex-direction: column; align-items: center; justify-content: center;
  gap: calc(20 * var(--u));
  background: rgba(5, 7, 15, 0.9);
  color: var(--color-ice-200); text-align: center;
  padding: 0 calc(44 * var(--u));
}
.scan-off--show { display: flex; }
.scan-off svg { width: calc(80 * var(--u)); height: calc(80 * var(--u)); color: var(--color-gray-200); }
.scan-off p { font-size: calc(28 * var(--u)); line-height: 1.5; word-break: keep-all; }
/* ===================== 03 완드 선택 — Figma wand_03(4591:20971 · 4591:20833) 그대로 (26-09-29) =====================
   패스트트랙 Q3(지팡이 주인 선택)를 옮긴 화면. 목록(.step-list--wand 781) > 묶음(.wand-group 634, 가운데 · 사이 40):
     지팡이(그림 3:1 틀 · 아래 "?" 또는 캡션 Hahmlet Light 18) + 이름 필 상자(여백 44 · 24, 줄 사이 24, 필 사이 16)
   → 60 → [선택 완료] 금색 알약 336×70(고르기 전 opacity 0, 26-10-06 시안 — 아래 .pill-btn--cta). 묶음은 남은 높이 651(781 − 60 − 70)의 가운데.
   시안 목록 폭은 이름 필 상자에 맞춰 늘어난다(HUG: 430 → 화살표가 붙으면 440). 지팡이 그림은 26-10-08 부터 440 고정(고를 때 출렁이지 않게). */
.step-list--wand { height: calc(781 * var(--fu)); justify-content: flex-start; }
.wand-group {
  height: calc(651 * var(--fu));                /* 26-10-06 시안: 목록 781 − 60 − 버튼 70(예전 큰 버튼 틀 87 일 땐 634). 폭은 이름 필 상자(HUG)와 지팡이 440 중 넓은 쪽 */
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: calc(40 * var(--fu));
}
.wand-display {
  position: relative;
  /* 폭 440 고정(26-10-08) — 예전엔 이름 필 상자 폭(HUG)을 따라가서, 이름을 고를 때마다(화살표가 붙은 줄이 바뀌면) 지팡이 그림이 392 ~ 428 로
     커졌다 줄며 아래 이름 줄까지 위아래로 출렁였다. 시안 선택 상태 폭(440)으로 고정해 그림 크기가 늘 같다(402.6). */
  width: calc(440 * var(--fu));
  display: flex; flex-direction: column; align-items: center;
  gap: calc(8 * var(--fu));                     /* 캡션은 8 아래(시안 Wand Info Frame). "?" 는 아래 .wand-display__mark 가 8 끌어올려 그림에 붙인다 */
  text-align: center;
}
/* 그림 틀 — 시안 img/Potter'sWand 는 3:1 화면(440×146.7)에 지팡이가 가운데 68.35 만큼 보인다(틀 440×68.35).
   우리 그림(assets/wands/*.png)은 여백 없는 컷이라 틀 폭의 91.5%(시안에서 지팡이가 보이는 길이 402/440)로 놓는다.
   ⚠ 글로우(filter)를 img 가 아니라 래퍼에 건다 — 패스트트랙 주석대로 WebKit 이 필터 출력을
   박스에 맞춰 잘라내는 버그가 있어, 래퍼를 패딩으로 부풀리고 같은 크기의 음수 마진으로 되돌린다. */
.wand-display__img-wrap {
  align-self: stretch;
  display: flex; align-items: center; justify-content: center;
  aspect-ratio: 440 / 68.35;
  box-sizing: content-box;
  padding: calc(60 * var(--fu)); margin: calc(-60 * var(--fu));
  filter: drop-shadow(0 0 calc(10 * var(--fu)) rgba(255, 255, 255, 0.4)) brightness(0.4);    /* 시안 03: 흰 글로우 20 + 어두운 지팡이 그림(별도 이미지) — 밝기 0.4 로 흉내낸다 */
  transition: filter 0.3s ease;
}
.wand-display__img { display: block; width: 91.5%; height: auto; }
/* "?" 와 캡션 — 같은 자리(27 높이)에서 교차한다. Hahmlet Light 18 / 27 · #FFF0CA */
.wand-display__label {
  position: relative;
  display: flex; align-items: center; justify-content: center;
  height: calc(27 * var(--fu));
  color: #FFF0CA;                                                    /* ⚠ 시안 원본값(비토큰) */
  font-family: var(--font-display); font-weight: 300;
  font-size: calc(18 * var(--fu)); line-height: 1.5;
}
.wand-display__mark {
  position: absolute; left: 50%; top: 0;
  /* "?" 는 그림에 붙는다(시안 03 사이 0) — 사이 8 은 늘 두고(고를 때 줄이 내려앉지 않게, 26-10-08) "?" 만 8 끌어올린다 */
  transform: translate(-50%, calc(-8 * var(--fu)));
  transition: opacity 0.25s ease;
}
.wand-display__caption {
  margin: 0;
  white-space: nowrap;
  opacity: 0;
  clip-path: inset(0 50% 0 50%);               /* 가운데서 좌우로 열리는 리빌 */
  transition: opacity 0.3s ease 0.15s, clip-path 0.4s ease 0.15s;
}
.wand-display.is-revealed .wand-display__mark { opacity: 0; }
.wand-display.is-revealed .wand-display__caption { opacity: 1; clip-path: inset(0 0 0 0); }
/* 이름을 고르면 "반짝" — 글로우가 순간 커졌다 가라앉는다. 시안 03b: #FFF0CA 60% 40 */
.wand-display.is-revealed .wand-display__img-wrap {
  filter: drop-shadow(0 0 calc(20 * var(--fu)) rgba(255, 240, 202, 0.6)) brightness(1);
  animation: wand-spark 0.6s ease;
}
@keyframes wand-spark {
  0%   { filter: drop-shadow(0 0 calc(20 * var(--fu)) rgba(255, 240, 202, 0.6)) brightness(1); }
  35%  { filter: drop-shadow(0 0 calc(56 * var(--fu)) rgba(255, 240, 202, 1)) brightness(1.7); }
  100% { filter: drop-shadow(0 0 calc(20 * var(--fu)) rgba(255, 240, 202, 0.6)) brightness(1); }
}

/* 이름 필 — Figma wizard_selection(size=large): 여백 10 · 20(한 글자 "론"은 10 · 32) · 채움 #30394F 40% · NEXON Medium 20 / 30 · 자간 0.5%.
   고른 것만 왼쪽에 화살표(31×16, 사이 8)가 펼쳐지고, 나머지는 50% 로 흐려진다. */
.wizard-row {
  display: flex; flex-direction: column; align-items: center;
  gap: calc(24 * var(--fu));
  padding: calc(44 * var(--fu)) calc(24 * var(--fu));
}
.wizard-row__line { display: flex; align-items: center; gap: calc(16 * var(--fu)); }
.wizard-pill {
  display: flex; align-items: center;
  background: none; border: 0; padding: 0;
  cursor: pointer;
}
.wizard-pill__arrow {
  position: relative; flex: none;
  width: 0; height: calc(16 * var(--fu));
  margin-right: 0; opacity: 0;
  transition: width 0.25s ease, margin-right 0.25s ease, opacity 0.2s ease;
}
.wizard-pill.is-selected .wizard-pill__arrow { width: calc(31 * var(--fu)); margin-right: calc(8 * var(--fu)); opacity: 1; }
/* 화살표 파일은 글로우까지 담은 55×40 캔버스라 박스(31×16) 밖으로 사방 12 삐져나오게 둔다 */
.wizard-pill__arrow img {
  position: absolute; top: calc(-12 * var(--fu)); left: calc(-12 * var(--fu));
  display: block; width: calc(55 * var(--fu)); height: calc(40 * var(--fu));
  pointer-events: none;
}
.wizard-pill__label {
  padding: calc(10 * var(--fu)) calc(20 * var(--fu));
  background: rgba(48, 57, 79, 0.4);                                 /* ⚠ 시안 원본값(비토큰 — --surface-chip 와 다르다) */
  border-radius: var(--radius-full);
  color: var(--color-white-100);
  font-family: var(--font-primary); font-weight: 500;
  font-size: calc(20 * var(--fu)); line-height: 1.5; letter-spacing: 0.005em;
  white-space: nowrap;
  transition: opacity 0.2s ease;
}
.wizard-pill--wide .wizard-pill__label { padding-left: calc(32 * var(--fu)); padding-right: calc(32 * var(--fu)); }
.wizard-row.has-selection .wizard-pill:not(.is-selected) { opacity: 0.5; }

/* [선택 완료] — 고르기 전엔 자리만 잡고 투명하다(시안 Start Button opacity 0) */
.wand-cta {
  opacity: 0; visibility: hidden;
  transition: opacity 0.3s ease;
}
.wand-cta.is-visible { opacity: 1; visibility: visible; }

/* 큰 CTA — 26-10-06 시안 Select Button Container(③ [선택 완료] 4591:20833 · ④ [마법 확정] 4591:21053 · 4596:22117 · 4596:22227 · 4596:22350).
   공통 PillButton(.pill-btn, 280×59)을 금색으로 키운 것 — 크기 비율이 70/59 라 단위(--pbu)를 그만큼 키우고 폭 · 여백 · 오른쪽 점 자리만 시안 값으로 덮는다:
   336×70 · 여백 4 · 흰 → #FEE8B5(아래 → 위) · 그림자 0 2.373 2.373 #565150 · 안쪽 테두리 0.593 #858587
   · 별 무늬 assets/pill-cta-deco.svg(시안 Union 그대로 — 257.458 · #7F6116 4%)를 안쪽 기준 (18.39, -99.07)에 · 양끝 점 #FFFBF4 판 9.49 · #858587 점 4.75
   (오른쪽 점은 알약 오른쪽 끝에서 0.24 안) · 글자 NEXON Medium 26.1 · 자간 0.5% · #242425.
   예전 큰 버튼(.dcta--stage — 어두운 면 · 금속 테두리 · 모서리 브래킷, 틀 400×87)을 대신한다. 대기 [시작하기] · 로그인은 그대로. ⚠ 색은 시안 원본값(비토큰). */
.pill-btn--cta, .pill-btn--cta .pill-btn__inner, .pill-btn--cta .pill-btn__label { --pbu: calc(var(--fu) * 70 / 59); }
.pill-btn--cta {
  width: calc(336 * var(--fu));
  padding: calc(4 * var(--fu));
  background: linear-gradient(0deg, #FFFFFF 0%, #FEE8B5 100%);
}
.pill-btn--cta .pill-btn__inner::before { background-image: url("assets/pill-cta-deco.svg"); }
.pill-btn--cta::before, .pill-btn--cta::after {
  background: radial-gradient(circle, #858587 0 calc(2 * var(--pbu)), #FFFBF4 calc(2 * var(--pbu)));
}
.pill-btn--cta::after { right: calc(0.24 * var(--fu)); }
.pill-btn--cta .pill-btn__label { color: #242425; }

/* ===================== 04 마법 선택 — Figma wand_04(4591:21053 · 4596:22117 · 4596:22227 · 4596:22350) (26-09-29) =====================
   목록(.step-list--select 631, 사이 40) > 카드 줄 904×462(옆 230 · 사이 40 · 가운데 364) + 점 표시 → 80 → [마법 확정] 금색 알약 336×70(26-10-06 시안). */
.step-head { display: flex; flex-direction: column; }
.step-head--stack { align-self: stretch; }
/* 상단 바 — 왼쪽 끝 뒤로 버튼 · 가운데 진행 바(26-09-23).
   3열 그리드(1fr auto 1fr)라 뒤로 버튼 폭과 무관하게 진행 바가 화면 정가운데에 선다(스캐너 헤더와 같은 방식). */
.step-bar {
  align-self: stretch;
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: center;
}
.step-bar .icon-back { justify-self: start; }
.step-bar .icon-home { justify-self: end; }
/* 헤더 본문(제목) — 가운데 정렬(26-09-23) */
.step-head__main {
  align-self: stretch;
  display: flex; flex-direction: column; align-items: center;
  text-align: center;
}
/* 단계 진행 바 — "STEP 0N" 글자를 대신한다(26-09-23). 4칸: 지난 칸·현재 칸이 켜지고,
   현재 칸은 화면에 들어올 때 왼쪽에서부터 차오른다. 색은 스캔 링과 같은 purple_200. */
/* ── StepHeader — Figma StepProgress 4476:786 · BackButton 4476:771 · TitleDeco 4477:770 그대로(26-09-29, 단위 --fu = 시안 1px) ── */
/* 진행 바 — 칸 90×4 셋 · 사이 7(= 284) · 둥글기 2. 꺼진 칸 purple_100 18%, 켜진 칸 흰색 + 글로우 #436CF5 40% 8.261 */
.step-progress {
  display: flex; gap: calc(7 * var(--fu));
  width: calc(284 * var(--fu));
}
.step-progress__seg {
  position: relative; flex: 1;
  height: calc(4 * var(--fu));
  border-radius: calc(2 * var(--fu));
  background: color-mix(in srgb, var(--color-purple-100) 18%, transparent);
}
.step-progress__seg::after {
  content: ""; position: absolute; inset: 0;
  border-radius: inherit;
  background: var(--color-white-100);
  box-shadow: 0 0 calc(8.261 * var(--fu)) rgba(67, 108, 245, 0.4);     /* ⚠ 시안 원본값(비토큰) */
  transform: scaleX(0); transform-origin: left center;
}
.step-progress__seg.is-done::after,
.step-progress__seg.is-current::after { transform: scaleX(1); }
.screen--active .step-progress__seg.is-current::after { animation: step-fill 0.7s 0.2s ease-out both; }
@keyframes step-fill { from { transform: scaleX(0); } to { transform: scaleX(1); } }

/* 뒤로 버튼 — 56 원 · 표면 frost-5 · 테두리 없음(시안에서 테두리 칠을 껐다) · 셰브론 아이콘 24.
   홈 버튼(.icon-home, 26-09-30)도 같은 판 — 아이콘은 스캐너 헤더 홈(scanner/assets/scan/ic-home.svg)과 같은 모양, 폭 24.
   ⚠ 완드 Figma 에 홈 버튼 시안은 아직 없다 — 뒤로 버튼과 짝으로 맞췄다. */
:is(.icon-back, .icon-home) {
  flex-shrink: 0;
  width: calc(56 * var(--fu)); height: calc(56 * var(--fu));
  display: flex; align-items: center; justify-content: center;
  border: 0;
  border-radius: 50%;
  background: var(--surface-frost-5);
  color: var(--color-white-100);
  cursor: pointer;
}
.icon-back svg { width: calc(24 * var(--fu)); height: calc(24 * var(--fu)); }
.icon-home svg { width: calc(24 * var(--fu)); height: calc(19.286 * var(--fu)); }       /* 28 × 22.5 비율 */
/* ⑤ 시전 — 헤더 줄이 없어 스테이지 오른쪽 위에 띄운다(③ · ④ 의 홈과 같은 자리: 위 48 · 오른쪽 36) */
.icon-home--float { position: absolute; top: calc(48 * var(--fu)); right: calc(36 * var(--fu)); z-index: 2; }
/* 화면 제목 — 공통 StepTitle(components.css)은 옛 1200 프레임 값(Hahmlet 72). 완드 시안 TitleDeco(4477:770)는 **Hahmlet Bold 42**
   (26-10-02 — 그전 Warhaven OTF Bold, 라이선스로 교체) · 행간 53.109 · 자간 -0.425 · 화살 52×28 · 사이 16 · 글로우 #FAF7D4 50%(-0.649, -0.649, 16.346).
   공통 원본은 스캐너도 쓰므로 여기서만 덮는다. 시전 대기 · 쿨타임 제목(TitleDeco 인스턴스)도 같은 서체 — 크기는 그 화면 규칙대로. 영문도 Hahmlet Bold.
   Bold(700) 글꼴은 공통 fonts-hahmlet.css(DS #112). */
.step-title, .cast-head .cast-title, .cool .cool__title { font-family: var(--font-display); font-weight: 700; }   /* 시전 · 쿨타임 제목은 뒤에 자기 규칙이 있어 우선순위를 올린다 */
.step-title {
  font-size: calc(42 * var(--fu));
  line-height: calc(53.109 * var(--fu));
  letter-spacing: calc(-0.425 * var(--fu));
}
.step-head .title-deco { gap: calc(16 * var(--fu)); }
.title-deco__arrow { width: calc(52 * var(--fu)); height: calc(28 * var(--fu)); }
.step-title--glow { text-shadow: calc(-0.649 * var(--fu)) calc(-0.649 * var(--fu)) calc(16.346 * var(--fu)) rgba(250, 247, 212, 0.5); }
:is(.icon-back, .icon-home):active { transform: scale(0.94); }

/* ---------- 카드 캐러셀 — 패스트트랙 Q1 기숙사 선택(.house-carousel · .house-card)을 옮겼다(26-09-23).
   그쪽은 768 폭 기준이라 모든 수치에 1200/768 = 1.5625 를 곱했다.
     옆 카드 250×318 → 391×497 · 가운데 카드 300×382 → 469×597
     카드 중심 간 거리 295 → 461(app.js SPELL_STEP) · 점 12 / 간격 6 → 19 / 9
   카드는 절대좌표로 겹쳐 두고 app.js 가 translateX 만 준다. 가운데 맞춤은 퍼센트 transform 이 아니라
   **고정 마진**(카드 크기의 절반)으로 잡는다 — 패스트트랙에서 겪은 Safari 버그(크기가 바뀌는 동안
   퍼센트 transform 을 다시 계산하지 않아 카드가 튄다) 때문이다. */
#screen-select { overflow: hidden; }           /* 화면 밖으로 걸친 옆 카드를 자른다 */
.step-list--select { height: calc(631 * var(--fu)); gap: calc(40 * var(--fu)); }   /* 26-10-06 시안: 본문 861 − 위아래 80 − 사이 80 − 버튼 70(예전 큰 버튼 틀 87 일 땐 614) */
.spell-carousel {
  position: relative; flex: none;
  width: calc(904 * var(--fu));                /* 옆 카드 230 + 40 + 가운데 364 + 40 + 230 — 본문(664)보다 넓어 화면 밖으로 걸친다 */
  height: calc(462 * var(--fu));               /* 가운데 카드 높이 */
}
.spell-carousel__track { position: absolute; inset: 0; touch-action: pan-y; }
.spell-carousel__track, .spell-carousel__track * { -webkit-user-select: none; user-select: none; -webkit-user-drag: none; }
/* 점 표시 — 카드 아래 40(목록 사이). 시안: 점 11.212 · 사이 5.311 · 지금 흰색 / 나머지 #464C64 50% */
.spell-carousel__dots { display: flex; gap: calc(5.311 * var(--fu)); }
.spell-carousel__dot {
  width: calc(11.212 * var(--fu)); height: calc(11.212 * var(--fu));
  border-radius: 50%;
  background: #464C64;                          /* ⚠ 시안 원본값(비토큰) */
  opacity: 0.5;
  transition: opacity 0.3s ease, background 0.3s ease;
}
.spell-carousel__dot.is-active { opacity: 1; background: var(--color-white-100); }

/* 카드 — 패스트트랙 HouseCard 의 결: 순검정 면 + 마법 색 테두리 + 오른쪽 아래로 번지는 마법 색. */
/* 마법 카드 — Figma SpellCarousel/SpellCard(4482:834, 26-09-29 시안 그대로, 단위 --fu).
   옆 카드(side) 230×294 · 여백 20 · 둥글기 30 / 가운데(focus) 364×462 · 여백 20 · 둥글기 47. 테두리 마법색 0.922 · 채움 #010202.
   순서는 [궤적] → [효과 칩] → [이름] → [로마자] — 칩이 이름 **위**다. 글꼴은 전부 NEXON(이름 focus Medium 32 · side Bold 20).
   옆 카드는 궤적을 위에, 글 묶음을 바닥에 붙인다(시안 SPACE_BETWEEN). */
.spell-card {
  position: absolute; left: 50%; top: 50%;
  width: calc(230 * var(--fu)); height: calc(294 * var(--fu));
  margin-left: calc(-115 * var(--fu)); margin-top: calc(-147 * var(--fu));
  padding: calc((20 - 0.922) * var(--fu));         /* 시안 여백 20 은 테두리(INSIDE) 안쪽이 아니라 카드 가장자리 기준 — border-box 라 테두리만큼 뺀다 */
  box-sizing: border-box;
  display: flex; flex-direction: column; align-items: center;
  gap: 0;
  overflow: hidden;
  border: calc(0.922 * var(--fu)) solid var(--card-accent, var(--color-peri-400));
  border-radius: calc(30 * var(--fu));
  background: #010202;
  /* 카드는 <button> 이라 글자색·서체를 부모에서 물려받지 않는다 — 다시 지정한다 */
  color: var(--color-white-100);
  font-family: var(--font-primary);
  cursor: pointer;
  transition: transform 0.4s cubic-bezier(0.22, 1, 0.36, 1), width 0.35s ease, height 0.35s ease,
    padding 0.35s ease, opacity 0.35s ease, margin-left 0.35s ease, margin-top 0.35s ease,
    border-radius 0.35s ease;
}
/* 드래그 중엔 위치·투명도가 손을 바로 따라온다 */
.spell-carousel__track.is-dragging .spell-card {
  transition: width 0.35s ease, height 0.35s ease, padding 0.35s ease,
    margin-left 0.35s ease, margin-top 0.35s ease, border-radius 0.35s ease;
}
.spell-card:not(.is-selected) { opacity: 0.4; }
/* 가운데 카드 — 26-09-23 약 1.3배로 키움(469x597 → 616x784, 비율 그대로). 옆 카드는 그대로라 대비가 더 커진다. */
.spell-card.is-selected {
  z-index: 1; cursor: default;
  width: calc(364 * var(--fu)); height: calc(462 * var(--fu));
  margin-left: calc(-182 * var(--fu)); margin-top: calc(-231 * var(--fu));
  border-radius: calc(47 * var(--fu));
}
/* 마법 색 번짐 — 패스트트랙 house-tint(테두리 색 60%)와 같은 그라디언트 */
/* 마법 색 번짐 — 시안 그라디언트: 왼쪽 위 → 오른쪽 아래, 48.7% 까지 투명 → 끝에서 마법색 28.7% */
.spell-card::before {
  content: ""; position: absolute; inset: 0; z-index: 0;
  background: linear-gradient(to bottom right, transparent 48.7%,
    color-mix(in srgb, var(--card-accent, var(--color-peri-400)) 28.7%, transparent) 100%);
  pointer-events: none;
}
.spell-card > * { position: relative; z-index: 1; }

/* 미세 인터랙션(26-09-23) ①: 카드가 가운데로 오는 순간 — 살짝 작아졌다 커지며 자리 잡고,
   테두리 밖으로 마법 색이 한 번 번졌다 가라앉는다.
   ⚠ 위치는 app.js 가 transform(translateX)으로 주고 있어서 크기는 개별 속성 `scale` 로 움직인다
     — transform 에 scale 을 섞으면 위치가 덮어써진다. */
.spell-card.is-focus-in { animation: card-focus-in 0.6s cubic-bezier(0.2, 0.8, 0.2, 1); }
@keyframes card-focus-in {
  0%   { scale: 0.95; box-shadow: 0 0 0 transparent; }
  55%  { scale: 1.03; box-shadow: 0 0 calc(56 * var(--u)) color-mix(in srgb, var(--card-shine, var(--card-accent, var(--color-peri-400))) 55%, transparent); }
  100% { scale: 1;    box-shadow: 0 0 0 transparent; }
}
/* 미세 인터랙션 ②: 궤적을 다 그린 순간 — 궤적이 살짝 줌인했다 돌아오며 한 번 더 밝게 빛난다.
   다시 그리기 시작할 때까지 1.2초 멈춰 있는 동안(app.js PLAIN_HOLD_MS) 끝난다. */
.traj--card.is-drawn .traj__svg { animation: traj-drawn 0.7s cubic-bezier(0.2, 0.8, 0.2, 1); }
@keyframes traj-drawn {
  0%   { transform: scale(1);    filter: none; }
  35%  { transform: scale(1.08); filter: drop-shadow(0 0 calc(20 * var(--u)) var(--traj-shine, var(--traj-accent, var(--color-peri-400)))) brightness(1.25); }
  100% { transform: scale(1);    filter: none; }
}
.spell-card:focus-visible { outline: none; box-shadow: var(--focus-ring); }

/* 궤적 자리 — side 214×154(궤적 154) / focus 332×282 에 궤적 292 가 위아래로 5 씩 넘친다(시안 인스턴스 y -5) */
.spell-card__traj { flex: none; width: calc(214 * var(--fu)); height: calc(154 * var(--fu)); }
.spell-card.is-selected .spell-card__traj { width: calc(332 * var(--fu)); height: calc(292 * var(--fu)); margin: calc(-5 * var(--fu)) 0; }
/* 이름 — 패스트트랙 house-card__name 처럼 마법 색 → 흰색 → 마법 색 그라디언트 글자 */
/* 이름 — NEXON, 행간 1.5, 자간 0.5%. 채움은 가로 그라디언트(마법색 5% → 흰 28% → 마법색 90%) */
.spell-card__name {
  margin-top: calc(8 * var(--fu));                /* side: 칩 아래 8 */
  font-family: var(--font-primary);
  font-size: calc(20 * var(--fu));
  font-weight: 700;
  line-height: 1.5;
  letter-spacing: 0.005em;
  white-space: nowrap;
  background: linear-gradient(90deg, var(--card-accent, var(--color-peri-400)) 5%,
    var(--color-white-100) 28%, var(--card-accent, var(--color-peri-400)) 90%);
  -webkit-background-clip: text; background-clip: text;
  color: transparent;
  transition: font-size 0.35s ease;
}
.spell-card.is-selected .spell-card__name { margin-top: calc(16 * var(--fu)); font-size: calc(32 * var(--fu)); font-weight: 500; }   /* focus: 칩 아래 16 · Medium 32 */
/* 이름이 긴 '윙가르디움 레비오사'만 한 단계 줄인다 — 두 줄까지는 허용 */
/* 로마자 — NEXON Regular 14 · 자간 1% · ice-200. 이름 아래 4 */
.spell-card__en {
  margin-top: calc(4 * var(--fu));
  font-size: calc(14 * var(--fu));
  font-weight: 400;
  line-height: 1.5;
  letter-spacing: 0.01em;
  color: var(--color-ice-200);
  text-transform: uppercase;
}
/* 효과 칩 — 이름 위. side: 높이 24 · 좌우 10 · NEXON Medium 12 / focus: 여백 3·14 · Medium 16. 테두리 · 글자 = 마법색 */
.spell-card__effect {
  margin-top: auto;                               /* side: 글 묶음을 바닥으로 */
  display: flex; align-items: center;
  height: calc(24 * var(--fu));
  padding: 0 calc(10 * var(--fu));
  box-sizing: border-box;
  border: calc(1 * var(--fu)) solid var(--card-accent, var(--color-peri-400));
  border-radius: var(--radius-full);
  font-size: calc(12 * var(--fu));
  font-weight: 500;
  line-height: 1.5;
  letter-spacing: 0.005em;
  color: var(--card-accent, var(--color-peri-400));
}
.spell-card.is-selected .spell-card__effect {
  margin-top: calc(8 * var(--fu));                /* focus: 궤적 아래 8 */
  height: auto;
  padding: calc(3 * var(--fu)) calc(14 * var(--fu));
  font-size: calc(16 * var(--fu));
}
/* 마법 설명 문구는 26-09-28 기획 결정으로 없앴다 — 카드 아래는 점 표시뿐이다. */
/* [마법 확정] — 완드 선택 화면과 같은 금색 알약(.pill-btn--cta), 목록 아래 80. */

/* 시전 대기의 멈춤 안내가 쓴다(원래 상세 화면 블록에 있던 것 — 상세 화면을 지우며 남겼다) */
@keyframes dwell-pulse {
  0%, 100% { transform: scale(1);   opacity: 0.6; }
  50%      { transform: scale(1.5); opacity: 1; }
}

/* ===================== 05 시전 대기 — Figma wand_05(4596:22039 · 05b 4596:22460 · 05c 4596:22645) 그대로 (26-09-29 · 26-09-30 갱신) =====================
   스테이지(위아래 48) > 머리(.cast-head: 위 16 · 사이 24, 높이 190 — 26-10-06 시안): 고른 마법 줄(장식선 142.5×9 · 사이 12 · 마법 이름 NEXON Medium 16, 마법색 · 검정 그림자 12)
     → [제목 80(StepTitle 42, 양옆 ✦ 화살 없음 — 26-10-06 시안 4984:9721) → 16 → 안내 한 줄(NEXON Medium 20)]
   > 시전 영역(.cast-area: 폭 500 · 사이 64, 26-09-30 전 46): 궤적 566 → 안내 묶음(멈춤 안내 한 줄 · 아래 구분선).
     시안은 시전 영역을 머리 아래 남은 높이(837)의 **가운데**에 둔다(평소 높이 688 → 위 74.5).
     실패(05c)는 안내가 두 줄 + 20 + 선으로 길어져 시안에선 궤적이 40 올라가지만, 실패할 때마다 화면이 튀지 않게
     **궤적은 평소 자리에 고정**하고 늘어난 안내만 아래로 내려간다(26-09-30 사용자 결정) — 그래서 영역 높이를 평소 값 688 로 못 박는다.
   (시안의 [다른 마법 고르기] 알약은 26-09-30 사용자 결정으로 삭제 — [마법 확정]이 곧 체험 완료 · 결과 도출.
    구분선 아래 "틀려도 괜찮아요…" 안내도 26-09-30 시안에서 빠졌다) */
.stage--cast { padding: calc(48 * var(--fu)) 0; justify-content: flex-start; gap: 0; }
.cast-head {
  align-self: stretch;
  display: flex; flex-direction: column; align-items: center;
  padding-top: calc(16 * var(--fu));
  gap: calc(24 * var(--fu));
}
.cast-head__main {
  align-self: stretch;
  display: flex; flex-direction: column; align-items: center;
  gap: calc(16 * var(--fu));
}
/* 고른 마법 줄 — 양옆 장식선(시안 Union 그림 그대로, 오른쪽은 좌우 반전) · 사이 12. 실패(05c)에도 마법색 그대로 */
.cast-spell-row { display: flex; align-items: center; gap: calc(12 * var(--fu)); }
.cast-spell-row__line { display: block; flex: none; width: calc(142.5 * var(--fu)); height: calc(9 * var(--fu)); }
.cast-spell-row__line--r { transform: scaleX(-1); }
.cast-spell {
  margin: 0;
  font-size: calc(16 * var(--fu)); line-height: 1.5; letter-spacing: calc(0.08 * var(--fu)); font-weight: 500;
  color: var(--cast-accent, var(--color-ice-200));
  text-shadow: 0 0 calc(12 * var(--fu)) #000;
  white-space: nowrap;
}
/* 제목은 다른 화면과 같은 StepTitle(.step-title, 위 StepHeader 규칙) — 예전 96 특례는 없앴다 */
.cast-title { white-space: nowrap; }
.cast-sub {
  margin: 0;
  font-size: calc(20 * var(--fu)); line-height: 1.5; letter-spacing: 0.005em; font-weight: 500;
  color: var(--color-white-100);
  word-break: keep-all;
}
/* 화면을 누르면 — 이 줄이 한 번 커졌다 돌아온다 */
.cast-sub.is-nudge { animation: sub-nudge 0.9s ease; }
@keyframes sub-nudge {
  0%, 100% { transform: scale(1); }
  25%      { transform: scale(1.1); }
  50%      { transform: scale(0.98); }
  70%      { transform: scale(1.04); }
}

.cast-area {
  width: calc(500 * var(--fu));
  height: calc(688 * var(--fu));               /* 평소(05 · 05b) 높이 = 궤적 566 + 64 + 안내 58. 실패 땐 안내가 이 밖으로 늘어난다(overflow 보임) */
  margin: auto 0;                               /* 머리 아래 남은 높이의 가운데(시안 Spell Subcontainer 가운데 정렬) */
  display: flex; flex-direction: column; align-items: center;
  gap: calc(64 * var(--fu));
}
.traj--cast {
  flex: none;
  width: calc(566 * var(--fu)); height: calc(566 * var(--fu));
  margin: 0 calc(-33 * var(--fu));             /* 시안: 500 폭 영역에서 양옆으로 33 넘친다 */
}

/* 궤적 아래 안내 — 시안 Guide Container: 여백 12 · 16 · 아래 선 1 #A6BCD8(안쪽) 안에 멈춤 안내 한 줄
   (NEXON Medium 22 / 33 · #EFF8FF, "잠깐 멈춰야"만 Bold · #92DBFA — 26-09-30 시안, 전엔 마법색). 높이 58. */
.cast-guides {
  align-self: stretch;
  flex: none;
  display: flex; flex-direction: column; align-items: center;
  gap: calc(20 * var(--fu));
  padding: calc(12 * var(--fu)) calc(16 * var(--fu));
  border-bottom: calc(1 * var(--fu)) solid #A6BCD8;                  /* ⚠ 시안 원본값(비토큰) */
  box-sizing: border-box;
}
.dwell-line {
  margin: 0;
  font-size: calc(22 * var(--fu)); line-height: 1.5; letter-spacing: 0.005em; font-weight: 500;
  color: #EFF8FF;                                                    /* ⚠ 시안 원본값(비토큰) */
  text-align: center;
  white-space: pre-line;
  word-break: keep-all;
}
.dwell-line strong { font-weight: 700; color: #92DBFA; }             /* ⚠ 시안 원본값(비토큰) — 마법과 상관없이 같은 색 */
/* 실패하면(05c) — 멈춤 안내 자리가 잠깐 "아쉽게 빗나갔어요! / 궤적을 따라 정확하게 다시 그려 보세요"(두 줄, 흰색)로 바뀐다.
   시안 05c 안내 묶음: 여백 없이 문구 → 20 → 선(위 선 1 #A6BCD8, 폭 500). 끝나면 원래대로(app.js onFail · restoreGuide). */
.cast-area.is-miss .cast-guides { padding: 0; border-bottom: 0; }
.cast-area.is-miss .cast-guides::after {
  content: ""; align-self: stretch;
  height: calc(1 * var(--fu));
  background: #A6BCD8;                                               /* ⚠ 시안 원본값(비토큰) */
}
.dwell-line.is-swap { animation: sub-swap 0.35s ease both; }
@keyframes sub-swap { from { opacity: 0; transform: translateY(calc(6 * var(--fu))); } }

/* ===================== 05 성공 · 쿨타임 ===================== */
.stage--success { justify-content: center; gap: calc(60 * var(--u)); }

/* 성공 순간 — 앞 몇 초. Figma wand_06(4472:807): 마법 이름 → 32 → 성공 문구, 화면 가운데. 뒤 빛은 배경(.bg-stage)이 맡고,
   고리 하나가 퍼져 나가는 것과 불꽃 조각은 앱 연출(시안엔 정지 화면만 있다). */
.burst {
  position: relative; isolation: isolate;
  display: none; flex-direction: column; align-items: center; gap: calc(32 * var(--fu));
}
.burst::after {
  content: ""; position: absolute; left: 50%; top: 50%; z-index: -1;
  width: calc(900 * var(--u)); height: calc(900 * var(--u));
  border-radius: 50%;
  pointer-events: none;
  border: calc(3 * var(--u)) solid var(--burst-accent, var(--color-peri-400));
  box-shadow: 0 0 calc(30 * var(--u)) var(--burst-shine, var(--burst-accent, var(--color-peri-400))),
              calc(-2 * var(--u)) calc(2 * var(--u)) calc(12 * var(--u)) var(--burst-warm, transparent);
  animation: burst-ring 1.6s cubic-bezier(0.2, 0.7, 0.3, 1) both;
}
@keyframes burst-ring {
  from { opacity: 1; transform: translate(-50%, -50%) scale(0.15); }
  to   { opacity: 0; transform: translate(-50%, -50%) scale(1.25); }
}
.burst__sub {                                  /* NEXON Medium 22 / 33 · 자간 0.5% · 흰색 */
  margin: 0;
  font-size: calc(22 * var(--fu)); line-height: 1.5; letter-spacing: 0.005em; font-weight: 500;
  color: var(--color-white-100);
  animation: burst-sub 0.5s ease 0.35s both;
}
@keyframes burst-sub { from { opacity: 0; transform: translateY(calc(16 * var(--u))); } }

/* 가운데서 사방으로 튀는 불꽃 — 조각은 app.js 가 만든다(각도 --a · 거리 --dist).
   rotate 로 방향을 잡고 translateX 로 날아가므로 조각은 가로로 긴 꼴이다. */
.burst__sparks { position: absolute; left: 50%; top: 50%; width: 0; height: 0; z-index: -1; }
.spark {
  position: absolute; left: 0; top: 0;
  width: calc(34 * var(--u)); height: calc(6 * var(--u));
  margin-top: calc(-3 * var(--u));
  border-radius: var(--radius-full);
  background: linear-gradient(90deg, transparent, var(--burst-accent, var(--color-peri-400)) 40%, #FFFFFF);
  box-shadow: 0 0 calc(12 * var(--u)) var(--burst-shine, var(--burst-accent, var(--color-peri-400))),
              calc(-1 * var(--u)) calc(1 * var(--u)) calc(5 * var(--u)) var(--burst-warm, transparent);
  transform-origin: 0 50%;
  animation: spark-fly 1.3s cubic-bezier(0.15, 0.7, 0.3, 1) var(--delay, 0s) both;
}
@keyframes spark-fly {
  from { opacity: 1; transform: rotate(var(--a)) translateX(calc(40 * var(--u))) scaleX(0.4); }
  70%  { opacity: 1; }
  to   { opacity: 0; transform: rotate(var(--a)) translateX(var(--dist)) scaleX(1); }
}
body[data-phase="burst"] .burst { display: flex; animation: burst-in 0.6s ease both; }
.burst__name {                                 /* Hahmlet Regular 78 / 89.578(26-10-02 시안 4472:807 — 그전 Warhaven) · 마법색 · 글로우 마법색 35.406 */
  margin: 0;
  font-family: var(--font-display);
  font-size: calc(78 * var(--fu)); line-height: calc(89.578 * var(--fu));
  font-weight: 400;
  color: var(--burst-accent, var(--color-white-100));
  text-shadow: 0 0 calc(35.406 * var(--fu)) var(--burst-shine, var(--burst-accent, rgba(123, 146, 238, 0.7))),
               calc(-2.8 * var(--fu)) calc(2.8 * var(--fu)) calc(14.2 * var(--fu)) var(--burst-warm, transparent);
  word-break: keep-all;
}
@keyframes burst-in {
  from { opacity: 0; transform: scale(0.82); filter: blur(calc(10 * var(--u))); }
  to   { opacity: 1; transform: none; filter: none; }
}

/* 쿨타임 — 60초 동안 도는 마법진 */
.cool { display: none; flex-direction: column; align-items: center; gap: calc(56 * var(--u)); }

/* 작은 보조 버튼 — 스테이지 기준 하단 가운데, 작고 옅게. 쿨타임 [그만두기] · QR 스캔 [건너뛰기] 공용.
   그만두기는 쿨타임(카운트다운) 동안만 보인다(성공 연출 3초 동안은 숨는다) — 잠금 화면에서
   눈에 띄는 버튼이 되지 않게. 건너뛰기는 스캔 화면에 늘 보인다. */
.quit-btn {
  display: none;
  position: absolute; left: 50%; bottom: calc(88 * var(--fu));   /* 26-10-13 지시: ② QR 스캔 [건너뛰기]와 같은 자리 — 화면 아래에서 88(Container 48 + 본문 여백 40). 그전 48 은 너무 아래 */
  transform: translateX(-50%);
}
.quit-btn:active { transform: translateX(-50%) scale(0.95); }
body[data-phase="cool"] .quit-btn { display: inline-flex; animation: quit-in 0.6s ease both; }
@keyframes quit-in { from { opacity: 0; } }      /* transform 은 건드리지 않는다(가운데 정렬이 translateX 다) */
body[data-phase="cool"] .cool { display: flex; animation: screen-in 0.6s ease both; }

.cool__circle {
  position: relative;
  width: calc(660 * var(--u)); height: calc(660 * var(--u));
  display: flex; align-items: center; justify-content: center;
}
.rune {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  fill: none;
  stroke: var(--color-ice-300);
  stroke-width: 0.7;
}
.rune__dashed { stroke-dasharray: 3 7; }
.rune--outer { opacity: 0.35; animation: rune-spin 46s linear infinite; }
.rune--mid   { opacity: 0.5;  animation: rune-spin 30s linear infinite reverse; stroke-width: 0.9; }
.rune--inner { opacity: 0.7;  animation: rune-spin 20s linear infinite; stroke-width: 1.1;
               stroke: var(--color-peri-400); filter: drop-shadow(0 0 6px rgba(123, 146, 238, 0.8)); }
@keyframes rune-spin { to { transform: rotate(360deg); } }

/* 마법진 둘레를 도는 빛 입자 — 반지름(--r)·주기(--d)·크기(--s)가 제각각이라
   같은 궤도를 돌아도 기계적으로 보이지 않는다. 마법 색을 따른다. */
.cool__motes { position: absolute; inset: 0; pointer-events: none; }
.mote {
  position: absolute; left: 50%; top: 50%;
  width: var(--s); height: var(--s);
  margin: calc(var(--s) / -2) 0 0 calc(var(--s) / -2);
  border-radius: 50%;
  background: #FFFFFF;
  box-shadow: 0 0 calc(var(--s) * 1.6) calc(var(--s) * 0.4) var(--burst-shine, var(--burst-accent, var(--color-peri-400)));
  animation:
    mote-orbit var(--d) linear infinite var(--delay),
    mote-twinkle var(--t) ease-in-out infinite alternate var(--delay);
}
@keyframes mote-orbit {
  from { transform: rotate(0deg) translateX(var(--r)); }
  to   { transform: rotate(360deg) translateX(var(--r)); }
}
@keyframes mote-twinkle { from { opacity: 0.2; } to { opacity: 1; } }

/* 남은 시간 링 — 12시에서 시작해 시계 방향으로 줄어든다 */
.cool-ring { position: absolute; inset: 0; width: 100%; height: 100%; transform: rotate(-90deg); fill: none; }
.cool-ring__track { stroke: rgba(222, 229, 255, 0.12); stroke-width: 3; }
.cool-ring__arc {
  stroke: var(--color-ice-300); stroke-width: 3; stroke-linecap: round;
  filter: drop-shadow(0 0 5px rgba(203, 213, 255, 0.9));
  transition: stroke-dashoffset 0.3s linear;
}
.cool__center { position: relative; display: flex; align-items: baseline; gap: calc(22 * var(--u)); }
.cool__num {
  font-family: var(--font-display);
  font-size: calc(160 * var(--u));
  font-weight: 600; line-height: 1;
  font-variant-numeric: tabular-nums;
}
.cool__unit { font-size: calc(40 * var(--u)); color: var(--color-ice-200); }

.cool__title {
  font-family: var(--font-display);
  font-size: calc(76 * var(--u));
  font-weight: 600; line-height: 1.2;
}
.cool__desc {
  font-size: calc(36 * var(--u));
  line-height: 1.6;
  color: var(--color-ice-200);
  word-break: keep-all;
}

/* ===================== 궤적 컴포넌트 =====================
   안건 A 의 답. 궤적을 한 번 그리는 동안
     ① 시작점 글로우가 커졌다 작아지며 0.5초 머문다
     ② 선이 그려진다(빛나는 점이 선두에서 달린다)
     ③ 끝점 글로우가 0.8초 머문다
   순서로 재생한다. 따로 튜토리얼 GIF 를 붙이지 않고 궤적 자체가 멈춤을 연기한다. */
.traj { position: relative; }
.traj__svg { width: 100%; height: 100%; overflow: visible; }

.traj__ghost {
  fill: none;
  stroke: rgba(222, 229, 255, 0.16);
  stroke-linecap: round; stroke-linejoin: round;
}
.traj__draw {
  fill: none;
  stroke: var(--traj-accent, var(--color-ice-300));
  stroke-linecap: round; stroke-linejoin: round;
  filter: drop-shadow(0 0 var(--traj-glow, 6px) var(--traj-shine, var(--traj-accent, var(--color-ice-300))))
          drop-shadow(-1px 1px calc(var(--traj-glow, 6px) * 0.4) var(--traj-warm, transparent));
}
/* 선 두께는 '멀리서 보이게' 기준(안건 B) — 화면이 클수록 굵다 */
.traj--card .traj__ghost, .traj--card .traj__draw { stroke-width: 7; }
.traj--cast .traj__ghost, .traj--cast .traj__draw { stroke-width: 6.5; }
.traj--cast { --traj-glow: 10px; }

/* 시작점 · 화살촉 — 기획서(HP_인터랙티브3) 제스처 아이콘처럼 시작은 점, 끝은 화살촉(26-09-23).
   26-10-01 Figma「사용 어셋」글리프(4815:35468 · 4795:34784 · 34798 · 34800)에 맞춰 촉을 길쭉하게(app.js HEAD_D),
   선 중간에도 진행 방향 화살표(.traj__mark, spells.js marks)를 둔다 — 선이 지나간 뒤 0.2초에 떠오른다. */
.traj__origin,
.traj__head,
.traj__mark {
  fill: var(--traj-accent, var(--color-ice-300));
  filter: drop-shadow(0 0 var(--traj-glow, 6px) var(--traj-shine, var(--traj-accent, var(--color-ice-300))))
          drop-shadow(-1px 1px calc(var(--traj-glow, 6px) * 0.4) var(--traj-warm, transparent));
}
.traj__head, .traj__mark { transition: opacity 0.2s ease; }
.traj.is-fail .traj__head,
.traj.is-fail .traj__mark { opacity: 0 !important; }
/* 선두에서 달리는 빛 — 어느 방향으로 그리는지 알려 준다 */
.traj__runner {
  fill: #FFFFFF;
  filter: drop-shadow(0 0 8px var(--traj-shine, var(--traj-accent, var(--color-ice-300))));
  opacity: 0;
}

/* 지팡이 — 시전 대기에서만. 끝(tip)이 궤적 위를 달리고, 손잡이는 오른쪽 아래로 늘어진다.
   손가락 점 대신 지팡이가 그리니 "태블릿을 누르는 게 아니라 이걸 휘두르는 것"이 읽힌다.
   26-09-29 시안(wand_05 "Wand Image" img/Potter'sWand 186×62 · 143.26° · 글로우 #FFF0CA 60% 40 + 끝의 흰 점 27 · 흐림 13):
   고른 지팡이 그림(assets/wands/*.png)을 그대로 쓴다. ⚠ 아래 filter 값은 SVG 안이라 px 가 아니라 viewBox 단위다(566 화면에서 1 단위 = 2.44px). */
.traj__wand { opacity: 0; transition: opacity 0.25s ease; }
.traj__wand.is-on { opacity: 1; }
.traj__wand-img { filter: drop-shadow(0 0 8.2px rgba(255, 240, 202, 0.6)); }
.traj__wand-tip { fill: #FFFFFF; filter: blur(2.66px); }
/* 불티 꼬리 — 이미 그려진 선 위라 같은 색이면 묻힌다. 흰 불티를 선 옆으로 조금씩 흩뿌린다. */
.traj__trail { fill: #FFFFFF; opacity: 0; filter: drop-shadow(0 0 3px var(--traj-shine, var(--traj-accent, #fff))); }
.traj.is-fail .traj__wand,
.traj.is-fail .traj__trail { opacity: 0 !important; }

/* 시작·끝 멈춤 글로우 */
.traj__dwell { pointer-events: none; }
.traj__dwell-ring {
  fill: none;
  stroke: var(--traj-accent, var(--color-ice-300));
  stroke-width: 2;
  opacity: 0.35;
}
.traj__dwell-core {
  fill: var(--traj-accent, var(--color-ice-300));
  filter: drop-shadow(0 0 10px var(--traj-shine, var(--traj-accent, var(--color-ice-300))))
          drop-shadow(-1px 1px 4px var(--traj-warm, transparent));
  opacity: 0.55;
}
/* 재생 중 '지금 멈추는 지점'만 켜진다 */
.traj__dwell.is-active .traj__dwell-core { opacity: 1; animation: dwell-core 0.5s ease-in-out infinite alternate; }
.traj__dwell.is-active .traj__dwell-ring { opacity: 0.9; animation: dwell-ring 1.1s ease-out infinite; }
@keyframes dwell-core { from { transform: scale(1); } to { transform: scale(1.35); } }
@keyframes dwell-ring { 0% { r: 12; opacity: 0.9; } 100% { r: 26; opacity: 0; } }

/* ---------- 실패 인터랙션 — 궤적 안에서만 (안건 C) ----------
   제스처가 빗나가면 화면 전체가 아니라 **관람객이 보고 따라 그리던 궤적 자체**가 반응한다.
     ① 궤적 전체가 붉게 바뀐다 (선 · 글로우 · 시작/끝 원 모두 — --traj-accent 한 줄로)
     ② 좌우로 짧게 흔들린다 — "아니야"의 몸짓
     ③ 선이 점선으로 부서지며 흩어진다 — 마법이 불발돼 사그라드는 느낌
   그 뒤 원래 색으로 돌아와 시작점 멈춤부터 다시 재생한다(app.js TrajectoryPlayer.fail).
   ⚠ --traj-accent 는 app.js 가 인라인으로 넣는 값이라 !important 로만 덮인다. */
.traj.is-fail {
  --traj-accent: var(--func-error) !important;
  animation: traj-shake 0.5s ease;
}
.traj.is-fail .traj__draw {
  animation: traj-crumble var(--fail-ms, 1100ms) ease-in both;
}
.traj.is-fail .traj__ghost { stroke: rgba(248, 113, 113, 0.18); }
.traj.is-fail .traj__runner,
.traj.is-fail .traj__tag { opacity: 0 !important; }
@keyframes traj-shake {
  0%, 100% { transform: none; }
  20% { transform: translateX(calc(-22 * var(--u))); }
  40% { transform: translateX(calc(16 * var(--u))); }
  60% { transform: translateX(calc(-10 * var(--u))); }
  80% { transform: translateX(calc(4 * var(--u))); }
}
/* 인라인 dasharray(그리기용)를 애니메이션이 덮는다. 주기 24 를 유지한 채 선분만 줄여
   '끊긴 선 → 가루'로 무너진다. 처음 30% 는 온전한 붉은 선으로 보여 준다. */
@keyframes traj-crumble {
  0%   { stroke-dasharray: 24 0;  stroke-dashoffset: 0; opacity: 1; }
  30%  { stroke-dasharray: 24 0;  stroke-dashoffset: 0; opacity: 1; }
  60%  { stroke-dasharray: 12 12; stroke-dashoffset: 6; opacity: 0.9; }
  100% { stroke-dasharray: 1 23;  stroke-dashoffset: 18; opacity: 0; }
}

/* 멈춤 라벨 — 상세·시전 화면에서만. 카드 썸네일에는 붙이지 않는다(작아서 읽히지 않는다) */
/* Figma CastStage/DwellTag: 여백 6 · 12 · 채움 #05070F 88% · 테두리 마법색 0.708(안쪽) · NEXON Bold 14 / 17.113 · 흰색 */
.traj__tag {
  position: absolute;
  padding: calc(6 * var(--fu)) calc(12 * var(--fu));
  border-radius: var(--radius-full);
  background: rgba(5, 7, 15, 0.88);
  border: calc(0.708 * var(--fu)) solid var(--traj-accent, var(--color-ice-300));
  font-size: calc(14 * var(--fu)); line-height: calc(17.113 * var(--fu));
  font-weight: 700;
  color: var(--color-white-100);
  white-space: nowrap;
  transform: translate(-50%, -50%);
  opacity: 0;
  transition: opacity 0.2s ease;
}
.traj__tag.is-on { opacity: 1; }
.traj--card .traj__tag { display: none; }

/* ---------- 포커스 / 모션 접근성 ---------- */
:focus-visible { outline: none; box-shadow: var(--focus-ring); }

@media (prefers-reduced-motion: reduce) {
  .fx-sparkle, .fx-fog, .fx-orb, .rune, .start-cta, .start-cta--gold::before, .dwell-line__dot,
  .mote, .traj.is-fail, .cast-sub.is-nudge, .dwell-line.is-swap,
  .spell-card.is-focus-in, .traj--card.is-drawn .traj__svg { animation: none !important; }
  .spark { display: none; }
  .fx-sparkle, .fx-orb { opacity: 0.4; }
  .screen--active, .burst, .cool { animation: none !important; }
  .screen--result :is(.title-deco, .result-web__sub, .result-none__desc, .result-phone, .result-home) { animation: none !important; }
  .start-logo-fx__glint { display: none; }
  .bg-result-trace { display: none; }
  /* 궤적은 멈추지 않는다 — 무엇을 그려야 하는지 알려주는 정보 자체다.
     대신 app.js 가 반복 속도를 늦춘다. */
  * { transition-duration: 0.01ms !important; }
}

/* ---------- 데모 패널 (현장 주소에서는 숨는다) ---------- */
.demo-panel { position: fixed; left: 14px; bottom: 14px; z-index: 50; font-family: var(--font-secondary); }   /* 왼쪽 아래 — 스캐너와 같은 자리 */
.demo-panel[hidden] { display: none; }
.demo-panel-toggle {
  font-size: 11px; font-weight: 700; letter-spacing: 0.1em;
  color: rgba(255, 255, 255, 0.45); background: rgba(0, 0, 0, 0.45);
  border: 1px dashed rgba(255, 255, 255, 0.25); border-radius: 8px;
  padding: 6px 12px; cursor: pointer;
}
/* 패널은 버튼 **위**에 띄운다(absolute) — 스캐너(scanner/styles.css, 944c527)와 같은 방식.
   묶음이 화면 아래에 붙어 있어서 버튼 아래 흐름에 두면 열 때 묶음이 위로 자라며 DEMO 버튼이 밀려 올라갔다.
   이제 버튼은 제자리다. 버튼이 왼쪽 아래라 패널도 왼쪽 끝에 맞춘다.
   키가 낮은 화면에서 위로 넘치지 않게 높이를 막고 안에서 스크롤한다. */
.demo-panel-body {
  display: none;
  position: absolute; left: 0; bottom: calc(100% + 8px);
  width: 300px;
  max-height: calc(100vh - 14px - 27px - 8px - 14px);   /* 아래 여백 · 버튼 · 틈 · 위 여백 */
  overflow-y: auto;
  background: rgba(12, 14, 22, 0.95);
  border: 1px solid rgba(255, 255, 255, 0.15); border-radius: 12px;
  padding: 14px; color: #CBD5E1; font-size: 12px;
}
.demo-panel--open .demo-panel-body { display: block; }
.demo-panel-title { font-weight: 700; margin-bottom: 10px; color: #94A3B8; line-height: 1.5; }
.demo-row { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin-bottom: 10px; }
.demo-row > span { color: #64748B; font-weight: 600; }
.demo-btn {
  font-size: 12px; color: #E2E8F0; background: #1E293B;
  border: 1px solid #334155; border-radius: 8px; padding: 5px 10px; cursor: pointer;
}
.demo-btn:hover { background: #334155; }
.demo-input {
  font-size: 12px; color: #E2E8F0; background: #0F172A;
  border: 1px solid #334155; border-radius: 6px; padding: 4px 8px; width: 70px;
}
.demo-state { color: #94A3B8; }
