/* ============================================================
   QR 스캔 태블릿 — 스타일
   디자인 시스템: design-system/tokens.css + components.css (먼저 로드)
   색상은 토큰만 사용. 홈 화면·포인트 컬러는 세 섹션(s6·s7·s9) 공통이다.
   ============================================================ */

* { margin: 0; padding: 0; box-sizing: border-box; }

/* 본문 서체는 design-system/fonts-nexon.css(NEXON Lv2 Gothic OTF),
   제목 서체는 design-system/fonts-hahmlet.css(Hahmlet). 둘 다 자체 호스팅이라
   전시장 내부망에서 외부 요청 없이 렌더된다. */

/* 넥슨 워헤이븐(Warhaven OTF)은 라이선스로 쓰지 않는다(26-10-02 디자이너 확인) — 글꼴 파일 · 선언을 지웠다.
   제목은 전부 Hahmlet(design-system/fonts-hahmlet.css 400 · 600 · 700): 화면 제목(StepTitle) · 로그인 제목 Bold 700,
   시작 화면 타이틀 Regular 400. 영문도 같은 Hahmlet(완드와 같은 결정). */

:root {
  /* ⚠ 26-09-29 키 컬러 네이비(#7691FF) 전환 — 이 파일의 보라 계열 값도 디자인시스템 tokens.css 와 같은
     규칙(색상 228° · 채도·명도 유지)으로 옮겼다. 아래 주석의 날짜 붙은 '보라' 는 그때의 기록이다. */
  /* 기능 컬러 — 에러는 PRD 명세(빨강). 성공은 26-08-24 디자이너 지시로 PRD의 초록 대신
     골드(#EFDB7E)를 쓴다 — 보라 팔레트에서 초록이 유일하게 튀고, 로고 골드와 맞물린다.
     ⚠ 에러(빨강)와는 색상만이 아니라 아이콘 모양(체크 / 느낌표)으로도 구분된다. */
  --func-success: #EFDB7E;
  /* --func-error · --focus-ring 은 26-09-28 부터 tokens.css(두 태블릿 공통)에 있다 */
}

/* 타이포그래피 — Figma 시안 그대로. base/* 는 NEXON Lv2 Gothic OTF,
   accent/* 는 Hahmlet 이고, 그 구분을 primary/display 토큰에 그대로 매핑한다. */
body {
  --font-primary: "NEXON Lv2 Gothic OTF", "넥슨Lv2고딕 OTF", system-ui, sans-serif;
  --font-secondary: "NEXON Lv2 Gothic OTF", "넥슨Lv2고딕 OTF", system-ui, sans-serif;
  /* ⚠ --font-display 는 덮지 않는다 — tokens.css 의 Hahmlet(자체 호스팅)을 그대로 쓴다. */
}

/* 영문 타이틀 서체 — 영문 타이틀(.start-title · .step-title · .popup__title · 로그인 제목)은 디자인시스템 공통 규칙이
   --font-display-en 으로 갈아 끼우므로, 이 앱에서 그 변수를 한국어와 같은 Hahmlet 으로 덮는다(굵기는 공통 규칙대로 400).
   26-09-30 Harry Beast → Warhaven 으로 바꿨다가 26-10-02 Warhaven 이 라이선스로 빠져 Hahmlet(완드와 같은 결정).
   예전 값(tokens.css)은 Harry Beast Cyr — 그래서 design-system/fonts-harrybeast.css 도 더는 불러오지 않는다. */
:root { --font-display-en: "Hahmlet", "Noto Serif KR", serif; }

/* 포인트 컬러 — 26-09-17 부터 **네 섹션이 같은 값을 쓴다**(홈 화면 통일 지시).
   섹션별로 갈라두면 배경이 같아진 뒤에도 배지·스피너 색만 미묘하게 달라 보인다.
   섹션마다 다시 나눠야 하면 여기 네 줄을 되살리면 된다. */
body { --accent: var(--color-peri-400); --accent-soft: rgba(123, 146, 238, 0.35); }

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;
  /* 홈 화면에 추가해 전체화면으로 쓰는 전제의 방어들 —
     길게 눌러 뜨는 복사/공유 메뉴 차단, 더블탭 확대 차단, 고무줄 스크롤 차단.
     touch-callout 은 아이폰 · 아이패드 사파리에서만 먹는다 — 안드로이드 크롬의 길게 누르기 메뉴는 app.js 가 contextmenu 를 막는다(이슈 #149). */
  -webkit-touch-callout: none;
  touch-action: manipulation;
  overscroll-behavior: none;
}

/* 그림 끌기 막기 — 안드로이드 크롬에서 그림을 길게 눌러 끌면 그림이 떨어져 나와 따라온다(이슈 #149). 버튼 누르기 · 패트로누스 목록 끌기와는 상관없다 */
img, svg { -webkit-user-drag: none; user-drag: none; }

/* ---------- 00 운영자 로그인 — 완드 운영자 로그인과 같은 화면 (26-09-30 지시) ----------
   완드 wand/styles.css "00 운영자 로그인"(Figma 4596:22747, 744×1133)의 숫자를 **그대로** 옮기고 단위만 --u 로 쓴다.
   완드 --fu(짧은 변 744 기준)와 스캐너 --u(짧은 변 744 기준)는 같은 태블릿에서 같은 픽셀이라 숫자를 바꿀 필요가 없다.
   틀: 시작 화면과 같은 배경(.bg-start + 입자 .home-fx) · 헤더엔 로고만(자리는 이 앱 홈 헤더 = 공통 StartScreen 그대로).
   본문: 헤더 아래 남은 높이(위 24 + 헤더 80 · 아래 48 을 뺀 곳)의 가운데에 폭 400 묶음 —
         [제목 109(Hahmlet Bold 48 — 시안은 Warhaven Bold, 라이선스로 교체) → 24 → 입력칸 둘(사이 23)] → 70 → 큰 버튼 400×87.
   폼(.login-* · 비밀번호 마스크 서체)은 디자인시스템 공통 Login(components.css)을 여기서 시안 값으로 덮는다
   (공통 원본은 옛 스캐너 프레임 값이라 — 완드도 같은 방식으로 덮는다. 두 앱이 같아졌으니 공통으로 올릴 후보). */
#screen-login { padding: 0; }
.login-stage {
  position: relative;                            /* 헤더(공통 .start-header, absolute)의 기준 — 홈 .home-stage 와 같은 상자 */
  width: min(100%, calc(1440 * var(--u)));
  height: calc(744 * var(--u));
  padding: calc(104 * var(--u)) 0 calc(48 * var(--u));
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  text-align: center;
}
.screen--login .login-form {
  display: flex; flex-direction: column; align-items: center;
  gap: calc(70 * var(--u));
  width: calc(400 * var(--u));
}
.login-fields {
  align-self: stretch;
  display: flex; flex-direction: column; align-items: center;
  gap: calc(24 * var(--u));
}
.login-fieldset {
  align-self: stretch;
  display: flex; flex-direction: column;
  gap: calc(23 * var(--u));
}
.screen--login .login-title {
  width: 100%;
  font-family: var(--font-display); font-weight: 700;
  font-size: calc(48 * var(--u)); line-height: calc(108.154 * var(--u)); letter-spacing: calc(-0.085 * var(--u));
  height: calc(109 * var(--u));
  text-align: center;
  color: var(--color-white-100);
  text-shadow: 0 calc(3.541 * var(--u)) calc(23.604 * var(--u)) rgba(5, 7, 15, 0.55);
}
/* 영문도 같은 Hahmlet Bold 48 — 예전엔 Harry Beast(한 굵기라 400) → Warhaven Bold 였다(26-10-02 라이선스로 Hahmlet) */
/* 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(--u)); }
/* 라벨만 왼쪽 정렬 — 26-09-30 사용자 지시(완드 로그인은 가운데). 입력칸 글자 · 제목 · 버튼은 가운데 그대로 */
.screen--login .login-label { font-size: calc(17 * var(--u)); line-height: calc(25.7 * var(--u)); letter-spacing: calc(0.086 * var(--u)); text-align: left; }
.screen--login .login-input {
  height: calc(59 * var(--u));
  padding: calc(15 * var(--u)) calc(19 * var(--u));
  font-size: calc(19 * var(--u)); line-height: calc(28.55 * var(--u)); letter-spacing: 0;
  box-shadow: 0 0 calc(3.807 * var(--u)) 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(--u)); }
/* 큰 버튼 — btn/main/big 을 폭 400 틀로 늘린 인스턴스(400×87). 완드 .dcta--stage 규칙을 그대로 옮겼다.
   로그인 버튼과 시작 화면 [시작하기](26-09-30 Figma 홈 6종 "Start Button" 400×87)에 건다
   (공통 .dcta--stage 는 1.727배 × --wu 라 크기 · 글자가 시안보다 컸다).
   틀 400×87 안에서 면 381.915×78 은 위 5 · 아래 4 · 왼쪽 8.511 · 오른쪽 9.574 — 가운데보다 0.53 왼쪽이다.
   면 테두리 1.846 은 border 대신 안쪽 그림자(::after)로 그린다 — border 는 기기 픽셀로 깎여 가늘고 흐려진다. */
:is(.login-cta, .start-cta).dcta--stage {
  --k: 1;
  --swu: var(--u);
  left: calc(-0.53 * var(--u));
  width: calc(381.915 * var(--u));
  min-width: 0;
  padding: 0;
  margin: calc(5 * var(--u)) 0 calc(4 * var(--u));
  flex: none;
  border-width: 0;
}
:is(.login-cta, .start-cta).dcta--stage::after {
  content: ""; position: absolute; inset: 0;
  box-shadow: inset 0 0 0 calc(1.846 * var(--u)) var(--color-purple-100);
  pointer-events: none;
}
:is(.login-cta, .start-cta).dcta--stage::before {
  inset: calc(-5 * var(--u)) calc(-9.574 * var(--u)) calc(-4 * var(--u)) calc(-8.511 * var(--u));
}
:is(.login-cta, .start-cta).dcta--stage .dcta__label { top: calc(1 * var(--u)); }
:is(.login-cta, .start-cta).dcta--stage .dcta__corner { z-index: 1; }                 /* 시안처럼 테두리(::after) 위에 */
:is(.login-cta, .start-cta).dcta--stage .dcta__corner--tl { left: calc(-5.32 * var(--u)); top: calc(-4 * var(--u)); }
:is(.login-cta, .start-cta).dcta--stage .dcta__corner--tr { right: calc(-5.32 * var(--u)); top: calc(-4 * var(--u)); }
:is(.login-cta, .start-cta).dcta--stage .dcta__corner--bl { left: calc(-5.32 * var(--u)); bottom: calc(-4 * var(--u)); }
:is(.login-cta, .start-cta).dcta--stage .dcta__corner--br { right: calc(-5.32 * var(--u)); bottom: calc(-4 * var(--u)); }
/* 꺼져 있으면 시안처럼 20%(공통 .dcta:disabled 는 45%) — 완드와 같다 */
.login-cta:disabled { opacity: 0.2; cursor: default; }
.login-cta:disabled::before { opacity: 1; }

/* ---------- 00-2 관리자 설정 — Figma 4155:16746 · 16654 · 16564 · 16339 ----------
   로그인 뒤 이 태블릿이 어느 콘텐츠의 몇 번 기기인지 정하는 모달.
   ⚠ 26-09-28 부터 **다른 화면과 같이 --u 로 스케일한다**(모든 화면 반응형 지시). 예전엔
     "가까이서 조작하는 폼이라 고정 px"였는데, 그러면 기기마다 이 화면만 크기가 따로 놀고
     키가 낮은 화면(800x500)에서는 모달(551)이 화면을 넘어 제목·닫기가 잘렸다.
     로그인 화면도 같다. 수치는 시안 프레임(1133x744) 값 × --u. */
.admin-modal {
  width: calc(400 * var(--u)); max-width: calc(560 * var(--u)); max-height: calc(760 * var(--u));
  display: flex; flex-direction: column;
  /* ⚠ 시안은 overflow-clip 이지만 그대로 두면 **드롭다운 목록이 모달에 잘린다.**
     내비게이션이 자체 배경을 갖지 않아 둥근 모서리를 자를 일도 없어서 클립을 뺀다. */
  background: #46474C;                                   /* 시안 bg/tertiary */
  border: 1px solid rgba(112, 115, 124, 0.28);           /* 시안 line/normal/tertiary */
  border-radius: calc(24 * var(--u));
  box-shadow: 0 calc(4 * var(--u)) calc(12 * var(--u)) 0 rgba(0, 0, 0, 0.16);          /* 시안 Shadow/lg */
}
/* 내비게이션 — 제목은 늘 정가운데, 닫기는 오른쪽 끝(시안 Leading/Trailing 구조) */
.admin-nav {
  position: relative;
  display: flex; align-items: center; justify-content: center;
  padding: calc(20 * var(--u));
  border-bottom: 1px solid rgba(112, 115, 124, 0.22);    /* 시안 line/normal/normal */
}
.admin-nav__title {
  font-size: calc(16 * var(--u)); font-weight: 500; line-height: 1.5; letter-spacing: 0.005em;
  color: var(--color-white-100);
}
.admin-nav__close {
  position: absolute; right: calc(20 * var(--u)); top: 50%; transform: translateY(-50%);
  display: flex; align-items: center; justify-content: center;
  width: calc(24 * var(--u)); height: calc(24 * var(--u)); padding: 0;
  background: none; border: 0; color: var(--color-white-100); cursor: pointer;
}
/* 터치 타깃만 넓힌다 — 아이콘 크기(24)는 시안 그대로 두고 레이아웃도 안 건드린다 */
.admin-nav__close::before { content: ""; position: absolute; inset: calc(-10 * var(--u)); }
.admin-nav__close svg { width: 100%; height: 100%; }

.admin-body {
  display: flex; flex-direction: column; gap: calc(40 * var(--u));       /* 시안 Heading gap 40 */
  padding: calc(20 * var(--u)) calc(28 * var(--u)) calc(28 * var(--u));
}
.admin-fields { display: flex; flex-direction: column; gap: calc(16 * var(--u)); }
.admin-field { display: flex; flex-direction: column; gap: calc(8 * var(--u)); }
.admin-label {
  font-size: calc(14 * var(--u)); font-weight: 500; line-height: 1.5; letter-spacing: 0.005em;
  color: rgba(225, 226, 228, 0.61);                      /* 시안 text/normal/tertiary */
}

/* 콘텐츠 선택 — 알약형 드롭다운. 고르기 전은 회색+회색 글자, 고른 뒤는 네이비+밝은 글자. */
.admin-select { position: relative; }
.admin-select__btn {
  display: flex; align-items: center; justify-content: space-between; gap: calc(12 * var(--u));
  width: 100%; height: calc(52 * var(--u)); padding: calc(12 * var(--u)) calc(24 * var(--u));
  background: var(--color-gray-700); border: 0.861px solid var(--color-white-100);
  border-radius: 999px;
  filter: drop-shadow(0 0 calc(2 * var(--u)) rgba(216, 224, 255, 0.6));
  font-family: var(--font-primary); font-size: calc(16 * var(--u)); font-weight: 700;
  line-height: 1.5; letter-spacing: 0.005em;
  color: var(--color-gray-200);                          /* 미선택: 시안 gray_200 */
  cursor: pointer; text-align: left;
}
.admin-select__btn[data-chosen="true"] {
  background: var(--color-purple-700);
  color: var(--color-blue-50);
  text-shadow: 0 0 calc(2 * var(--u)) rgba(153, 228, 255, 0.4);
}
.admin-select__value { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.admin-select__chev { width: calc(24 * var(--u)); height: calc(24 * var(--u)); flex-shrink: 0; }
.admin-select__btn[aria-expanded="true"] .admin-select__chev { transform: rotate(180deg); }
/* 목록 — 시안에 펼친 상태가 없어, 버튼과 같은 재질로 아래에 붙인다 */
.admin-select__list {
  position: absolute; left: 0; right: 0; top: calc(100% + calc(6 * var(--u))); z-index: 5;
  margin: 0; padding: calc(6 * var(--u)); list-style: none;
  max-height: calc(232 * var(--u)); overflow-y: auto;
  background: #3A3B40; border: 1px solid rgba(255, 255, 255, 0.24);
  border-radius: calc(16 * var(--u));
  box-shadow: 0 calc(8 * var(--u)) calc(20 * var(--u)) rgba(0, 0, 0, 0.32);
}
.admin-select__list[hidden] { display: none; }
.admin-select__opt {
  display: flex; align-items: center;
  width: 100%; min-height: calc(44 * var(--u)); padding: calc(10 * var(--u)) calc(18 * var(--u));
  background: none; border: 0; border-radius: 999px;
  font-family: var(--font-primary); font-size: calc(16 * var(--u)); font-weight: 500;
  color: var(--color-white-100); text-align: left; cursor: pointer;
}
.admin-select__opt[aria-selected="true"] { background: var(--color-purple-700); font-weight: 700; }

/* 기기 — 168px 칩 두 개씩 감긴다(시안 wrap, gap 8) */
.admin-devices { display: flex; flex-wrap: wrap; gap: calc(8 * var(--u)); }
.admin-device {
  width: calc(168 * var(--u)); height: calc(52 * var(--u)); flex: 1 1 calc(158 * var(--u));
  display: flex; align-items: center; justify-content: center;
  background: var(--color-gray-700); border: 1px solid var(--color-white-100);
  border-radius: 999px;
  font-family: var(--font-primary); font-size: calc(16 * var(--u)); font-weight: 500;
  line-height: 1.5; letter-spacing: 0.005em;
  color: var(--color-white-100); text-shadow: 0 0 calc(10 * var(--u)) rgba(238, 241, 254, 0.4);
  cursor: pointer;
}
.admin-device[aria-pressed="true"] {
  background: var(--color-purple-700); border-width: 0.861px;
  font-weight: 700; color: var(--color-blue-50);
  text-shadow: 0 0 calc(2 * var(--u)) rgba(153, 228, 255, 0.4);
  filter: drop-shadow(0 0 calc(2 * var(--u)) rgba(216, 224, 255, 0.6));
}

.admin-field__error {
  margin: 0; font-family: var(--font-primary); font-weight: 500;
  font-size: calc(14 * var(--u)); line-height: 1.5; color: var(--color-purple-200);
}
.admin-field__error[hidden] { display: none; }
.admin-actions { display: flex; flex-direction: column; gap: calc(40 * var(--u)); }
/* 테스트 — 알약이 아니라 반경 16 사각(시안) */
.admin-test {
  width: 100%; height: calc(52 * var(--u)); padding: calc(16 * var(--u));
  display: flex; align-items: center; justify-content: center;
  background: var(--color-gray-700); border: 1px solid var(--color-gray-100);
  border-radius: calc(16 * var(--u));
  font-family: var(--font-primary); font-size: calc(16 * var(--u)); font-weight: 500;
  line-height: 1.5; letter-spacing: 0.005em;
  color: var(--color-white-100); text-shadow: 0 0 calc(10 * var(--u)) rgba(238, 241, 254, 0.4);
  cursor: pointer;
}
.admin-test:active, .admin-device:active, .admin-select__btn:active { opacity: 0.8; }
/* 테스트 결과 한 줄 — 시안엔 없지만, 눌러도 아무 반응이 없으면 고장인지 알 수 없다.
   흐름에 끼어들지 않게 버튼 바로 아래 잠깐 떴다 사라진다. */
.admin-test__status {
  margin: calc(-32 * var(--u)) 0 0; text-align: center;
  font-size: calc(14 * var(--u)); line-height: 1.5; color: var(--color-blue-50);
}
.admin-test__status[hidden] { display: none; }
/* 설정 완료 — btn/main/small 을 모달 폭에 맞춰 늘린다(시안 332 = 내부 폭) */
.dcta--small.admin-done { width: 100%; }   /* 아래 .dcta--small(× --u)보다 앞에 있어 선택자를 올린다 */

/* 단계별 노출 — 콘텐츠를 고르기 전엔 나머지가 아예 없다(시안 4155:16746).
   (자리 없는 콘텐츠 판 — 시안 4155:16339 · 예전 S02 완드 — 은 26-09-29 걷어냈다.) */
.admin-modal[data-step="content"] #admin-device-field,
.admin-modal[data-step="content"] .admin-actions,
.admin-modal[data-step="device"] .admin-actions { display: none; }

/* ---------- 00-3 운영자 PIN (26-10-21) — 시작 화면 모서리 5번 탭 → 이 화면 → [확인]으로 맞으면 운영자 설정 ----------
   26-10-21 기숙사 키오스크(정인화님) 수정 시안(6196:78959 빈 · 6204:5542 4자리 · 6204:5661 틀림)과 같은 구성 — 운영자 설정 모달(.admin-modal ·
   .admin-nav 제목 + 닫기 ✕)을 그대로 쓰고, 본문 [안내 → 동그라미 칸 52 → 키패드 3×4]. [확인] 버튼은 없다 — 4자리면 바로 확인(Figma 6228:3276, 26-10-21 다원).
   숫자는 시안(1080 세로 키오스크, 모달 880)을 이 앱 모달(400)에 맞춰 ÷2.2: 키 91×47 · 사이 9/11 · 동그라미 13 · 사이 14.5 · 안내 14.
   색은 이 앱 것 — 채운 동그라미 · 누른 키는 키 컬러 네이비(--color-purple-200), 틀림은 스캔 실패와 같은 #FF8484(키오스크 시안도 같은 값),
   키 판 #141417 · 테두리 흰 30%(시안은 크림 #FEFDED — 키오스크 금색 계열이라 흰색으로). */
#screen-pin { padding: 0; }
.pin-body {                                          /* .admin-body 와 같은 여백 */
  display: flex; flex-direction: column;
  padding: calc(20 * var(--u)) calc(28 * var(--u)) calc(28 * var(--u));
}
.pin-input { display: flex; flex-direction: column; gap: calc(16 * var(--u)); }
.pin-entry { display: flex; flex-direction: column; gap: calc(8 * var(--u)); }
/* 안내 — 운영자 설정 필드 이름표(.admin-label)와 같은 글자. 틀리면 같은 자리에 빨간 안내가 대신 선다(줄 높이가 같아 키패드가 밀리지 않는다) */
.pin-desc, .pin-error {
  margin: 0;
  font-size: calc(14 * var(--u)); font-weight: 500; line-height: 1.5; letter-spacing: 0.005em;
  text-align: center; word-break: keep-all;
}
.pin-desc { color: rgba(225, 226, 228, 0.61); }      /* 시안 text/normal/tertiary — .admin-label 과 같다 */
.pin-error { display: none; color: #FF8484; }        /* ⚠ 시안 원본값 — 스캔 실패 red_500 과 같다 */
.pin-modal[data-state="error"] .pin-desc { display: none; }
.pin-modal[data-state="error"] .pin-error { display: block; }
.pin-field { height: calc(52 * var(--u)); display: flex; align-items: center; justify-content: center; }
.pin-dots { display: flex; gap: calc(14.5 * var(--u)); }
.pin-dot {
  width: calc(13 * var(--u)); height: calc(13 * var(--u));
  border-radius: 50%;
  border: calc(1 * var(--u)) solid rgba(255, 255, 255, 0.45);   /* 시안 빈 칸 #FEFDED 45% → 흰색 */
  box-sizing: border-box;
  transition: background-color 0.12s ease, border-color 0.12s ease;
}
.pin-dot--on { background: var(--color-purple-200); border-color: var(--color-purple-200); }
.pin-modal[data-state="error"] .pin-dot { border-color: #FF8484; }
/* 키패드 3×4 — 알약 키, 누르면 네이비로 잠깐 */
.pin-pad {
  display: grid; justify-content: center;
  grid-template-columns: repeat(3, calc(91 * var(--u)));
  gap: calc(9 * var(--u)) calc(11 * var(--u));
}
.pin-key {
  height: calc(47 * var(--u));
  display: flex; align-items: center; justify-content: center;
  padding: 0;
  border: calc(1 * var(--u)) solid rgba(255, 255, 255, 0.3);
  border-radius: 9999px;
  background: #141417;                               /* ⚠ 시안 원본값 neutral/950 */
  color: var(--color-white-100);
  font-family: var(--font-display); font-weight: 400;   /* 시안 Hahmlet Medium — 이 앱은 400 · 600 · 700 만 있어 가장 가까운 400 */
  font-size: calc(20 * var(--u)); line-height: 1;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;                        /* 빨리 두 번 눌러도 확대되지 않게 */
  transition: background-color 0.1s ease, border-color 0.1s ease;
}
.pin-key:active { background: rgba(118, 145, 255, 0.35); border-color: var(--color-purple-200); }
.pin-key--blank { visibility: hidden; }
.pin-key--del { border-color: transparent; background: none; }
.pin-key--del svg { width: calc(22 * var(--u)); height: calc(22 * var(--u)); }

/* 운영자 전용 재설정 진입 — 관람객에게는 보이지 않는 모서리 영역.
   ⚠ 26-10-21 부터 **시작 화면에서만** 반응한다(#251 지훈님 · 다원 결정 — 키오스크 · 완드와 같게).
     체험 중 화면에서 열면 관람객 판이 되돌려지고, 로그인 · PIN · 설정 화면에서 켜두면 자기 자신을 다시 여는 꼴이 된다.
   DEMO 패널은 왼쪽 아래라 겹치지 않는다. */
.admin-hotspot {
  position: fixed; right: 0; bottom: 0; z-index: 25;
  width: 96px; height: 96px;
  display: none;
}
body[data-screen="home"] .admin-hotspot { display: block; }   /* 26-10-21 시작 화면에서만(#251) — 체험 중 화면에서 열면 관람객 판이 되돌려진다 */

/* ---------- 배경 레이어 ---------- */
.bg-layer { position: fixed; inset: 0; z-index: 0; pointer-events: none; }
/* 시작 화면 배경(.bg-start)과 서로 스며들게 옛 배경도 같은 시간으로 전환한다 — 완드와 같다 */
.bg-art, .bg-night, .bg-band { transition: opacity 0.8s ease; }
.bg-art {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover;
  /* 원본이 3:4 세로(Figma 프레임 768x1024)라 가로 화면에서는 위아래가 잘린다.
     가운데 정렬이면 성이 윗단으로 밀려 잘리므로, 성과 호수가 같이 남는 지점을 잡는다. */
  object-position: center 34%;
  /* 아트가 화면의 인상을 만든다 — 가리지 않고 거의 그대로 노출 */
  opacity: 0.92;
}
/* ⚠ 26-09-17 배경 교체로 **섹션별 색보정(hue-rotate)을 걷어냈다.** 새 아트는 이미
   보라 톤으로 완성된 한 장이라, 예전처럼 색을 돌리면 두 번 보정돼 색이 무너진다. */
/* 아트 위 스크림 — 위쪽은 아트를 살리고, 아래로 갈수록 어둡게 해 글과 버튼을 받친다 */
.bg-night {
  position: absolute; inset: 0;
  background: linear-gradient(180deg,
    rgba(5, 7, 15, 0) 0%,
    rgba(5, 7, 15, 0.12) 42%,
    rgba(5, 7, 15, 0.55) 74%,
    rgba(5, 7, 15, 0.86) 100%);
}
/* 하단 글로우 — 시안(4045:14655 'back')의 radial gradient.
   화면 아래 가운데에서 위로 퍼지는 넓고 납작한 네이비 빛으로, 성의 아랫단을 감싸고
   그 위에 놓이는 문구·CTA 를 받친다. 예전의 '타이틀 뒤 타원'을 이걸로 대체했다. */
/* 26-09-17 홈 시안 4종(4075:19711 'back')으로 갱신 — 타원 중심이 프레임 아래(y 802.5)로
   내려가고 반지름은 가로 1565 · 세로 802.5(= 위쪽 끝이 프레임 상단에 닿는다).
   gradientTransform 행렬을 풀면: 가로 반지름 156.5x10/1133 = 138%, 세로 802.5/744 = 108%.
   레이어 opacity 0.7 은 각 stop 알파에 곱해 넣었다. */
.bg-band {
  position: absolute; left: 0; right: 0; bottom: 0;
  height: 100%;
  background: radial-gradient(138% 108% at 50% 108%,
    rgba(112, 141, 255, 0.70) 0%,
    rgba(92, 113, 199, 0.60) 12.2%,
    rgba(71, 86, 144, 0.49) 24.4%,
    rgba(51, 58, 88, 0.385) 36.6%,
    rgba(14, 30, 32, 0.28) 48.8%,
    rgba(12, 39, 62, 0.56) 100%);
}

/* 시작 화면 배경 — 디자인시스템 공통 .bg-start(시안 4393:4273, 완드와 같은 배경).
   ⚠ 사진(assets/bg-start.jpg)은 1080x1920 **세로**라 가로 화면에서는 세로의 약 35% 띠만 보인다.
     가운데로 자르면 첨탑이 잘려 성이 안 읽혀서, 첨탑 끝부터 성 몸체까지 남는 지점(위에서 12%)을 잡았다.
     가로용으로 다시 뽑은 사진이 오면 그걸로 바꾸는 게 낫다. */
.bg-start img { object-position: center 12%; }
body:is([data-screen="home"], [data-screen="login"]) .bg-start { opacity: 1; }
/* 시작 화면에서는 옛 성 배경 세 겹(아트 · 스크림 · 하단 글로우)을 끈다 — 완드와 같다.
   운영자 로그인도 시작 화면과 같은 배경이다(26-09-30, 완드 로그인 4596:22747 과 같게).
   다른 화면(관리자 설정 · 결과)은 그대로 쓴다. */
body:is([data-screen="home"], [data-screen="login"]) :is(.bg-art, .bg-night, .bg-band) { opacity: 0; }

/* 배경 아트 — 26-09-17 Figma 4063:15283 기준으로 **결과 화면에도 켠다**(시안에 성이 보인다).
   홈 연출(입자·빛무리)과 하단 글로우는 홈에서만 — 다른 화면에서는 산만하다. */
body:not([data-screen="home"]) .bg-band { display: none; }
/* 어두운 성 배경 — 시안의 래스터(어둡게 깐 성, 4074:16074)를 그대로 깐다. 홈 아트에
   스크림을 얹어 흉내 내면 밝기가 시안과 달라진다. 예전엔 QR 스캔 화면 배경이었는데 26-09-30 스캔 화면을
   완드와 같은 배경으로 바꿔, 지금은 소진 · 체험 중인 QR · 패트로누스 선택 화면만 쓴다.
   ⚠ 2.1MB PNG 지만 유지한다 — 전시장 내부망이라 한 번 받으면 캐시된다. */
.bg-scan {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover; object-position: center;
  display: none;
}
/* 소진(4172:36544) · 체험 중인 QR 화면은 이 어두운 성 배경을 쓴다(패트로누스 선택은 26-10-01 시안부터 아래 네이비 배경) */
body[data-screen="limit"] .bg-scan,
body[data-screen="inprogress"] .bg-scan { display: block; }
body[data-screen="limit"] .bg-art, body[data-screen="limit"] .bg-night,
body[data-screen="inprogress"] .bg-art, body[data-screen="inprogress"] .bg-night { display: none; }
/* QR 스캔 화면 — 26-09-30 완드 QR 스캔 화면과 같은 배경(wand/styles.css 배경 "02 QR 스캔", Figma 4472:777):
   #05070F + 성 사진(bg-home.jpg — 완드와 같은 파일) 50% · 밝기(luminosity) 블렌드 + 세로 그라디언트 60%.
   사진 자르는 위치는 이 앱 가로 화면 값(위에서 34%) 그대로. */
/* 기숙사 선택(26-09-30 Figma 4741:11541 · 11340) · 패트로누스 선택(26-10-01 Figma 4741:11871 외)도 같은 배경이다 —
   #08050F(→ 네이비 #05070F) + 성 사진 50% 밝기 블렌드 + 세로 그라디언트 60%.
   26-10-06 부터 콘텐츠별 사진으로 덮는다(아래 "물약 QR 스캔" · "퀴디치 QR 스캔 · 기숙사 선택" · "패트로누스 QR 스캔 · 패트로누스 선택"). */
body:is([data-screen="scan"], [data-screen="house"], [data-screen="nickname"], [data-screen="patronus"]) .bg-layer { background: #05070F; isolation: isolate; }
body:is([data-screen="scan"], [data-screen="house"], [data-screen="nickname"], [data-screen="patronus"]) .bg-art { opacity: 0.5; mix-blend-mode: luminosity; }
body:is([data-screen="scan"], [data-screen="house"], [data-screen="nickname"], [data-screen="patronus"]) .bg-night {
  background: linear-gradient(180deg, #010102 0%, #141A36 40.6%, #1E3686 74.9%, #202E6B 78.9%, #010102 93.1%);   /* ⚠ 시안 원본값(비토큰) */
  opacity: 0.6;
}
/* 결과 화면 배경 — 세 섹션이 각자 체험존 사진. 시안의 'Exclude' 레이어는
   #010101 을 8% 로 덮은 단색이라 에셋 없이 .bg-night 로 그린다. */
.bg-result {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover; object-position: center;
  display: none;
}
body[data-screen="result"] .bg-result { display: block; }
body[data-screen="result"] .bg-art { display: none; }
body[data-screen="result"] .bg-night {
  background: rgba(1, 1, 1, 0.08);   /* 시안 Exclude */
}
/* 퀴디치 배경만 세로 원본(843x1150)이라 cover 로 자를 때 보이는 구간을 시안에 맞춘다
   (시안: 높이 207.74% · top -45.95% → 세로 가운데가 약 46%). */
body[data-mission="quidditch"] .bg-result { object-position: center 46%; }
/* 결과 화면 스크림 — 시안은 홈보다 어둡다(폰 목업과 문구가 주인공) */
body[data-screen="result"] .bg-night {
  background: linear-gradient(180deg,
    rgba(1, 1, 1, 0.62) 0%,
    rgba(1, 1, 1, 0.74) 50%,
    rgba(1, 1, 1, 0.92) 100%);
}

/* 시작 화면 바닥 빛 — 26-09-30 Figma 홈 6종 배경 채움의 라디얼(아래 가운데 · 가로 반지름 1448.4 = 128.06% · 세로 744 = 100%):
   #051343 → rgba(14,25,32,.3) 48.8% → rgba(12,39,62,.1). 입자 위에 한 겹(시안은 배경 캡처 위에 얹었다). */
.bg-home-glow {
  position: absolute; inset: 0;
  background: radial-gradient(128.06% 100% at 50% 100%,
    rgba(5, 19, 67, 1) 0%, rgba(14, 25, 32, 0.3) 48.796%, rgba(12, 39, 62, 0.1) 100%);   /* ⚠ 시안 원본값 */
  opacity: 0;
  transition: opacity 0.8s ease;
}
body[data-screen="home"] .bg-home-glow { opacity: 1; }

/* ---------- 홈 연출 (네 섹션 공통) ---------- */
.home-fx { position: absolute; inset: 0; overflow: hidden; }
/* 홈 화면일 때만 표시 (이후 화면에선 산만하지 않게 숨김) — 운영자 로그인은 홈과 같은 배경이라 같이 켠다(완드와 같다) */
body:not([data-screen="home"]):not([data-screen="login"]) .home-fx { display: none; }

/* 떠오르는 마법 입자 */
.fx-sparkle {
  position: absolute; bottom: -12px;
  width: 5px; height: 5px; border-radius: 50%;
  background: var(--color-blue-300);
  box-shadow: 0 0 10px 2px rgba(155, 173, 245, 0.55); /* blue-400 글로우 */
  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; transform: scale(0.7); }
.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;  transform: scale(0.6); }
.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; transform: scale(0.8); }
.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; transform: scale(0.65); }
.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; transform: scale(0.75); }
@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: 34vh; width: 120vw; bottom: -6vh;
  background: radial-gradient(ellipse 60% 50% at 50% 60%,
    rgba(203, 213, 255, 0.05) 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: 10vw; bottom: -12vh; animation: fog-drift 52s ease-in-out infinite alternate-reverse; }
@keyframes fog-drift { from { transform: translateX(0); } to { transform: translateX(24vw); } }

.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: 56px; height: 56px; left: 12%; top: 62%; animation-delay: 0s; }
.fx-orb--2 { width: 30px; height: 30px; left: 26%; top: 30%; animation-delay: 3.5s; }
.fx-orb--3 { width: 74px; height: 74px; left: 80%; top: 55%; animation-delay: 7s; }
.fx-orb--4 { width: 36px; height: 36px; left: 70%; top: 22%; animation-delay: 10.5s; }
@keyframes orb-float {
  0%, 100% { transform: translate(0, 0) scale(1);        opacity: 0.12; }
  25%      { transform: translate(3vw, -4vh) scale(1.08); opacity: 0.3; }
  50%      { transform: translate(-2vw, -7vh) scale(0.95); opacity: 0.18; }
  75%      { transform: translate(2vw, -3vh) scale(1.05);  opacity: 0.28; }
}

/* ---------- 화면 공통 ---------- */
/* 화면은 **안전영역 안**에 둔다 — 전체화면으로 띄워도 안드로이드 내비게이션 바(제스처
   바)나 상태바가 남는 기기가 있어, inset:0 이면 그 자리에 가린다.
   배경(.bg-layer)은 inset:0 그대로라 아트는 화면 끝까지 깔린다.
   안전영역이 없는 환경에서는 env() 가 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;
  padding: 4vh 5vw;
}
/* 홈(시작 화면)은 스캔 화면처럼 스테이지(.home-stage) 하나를 가운데에 놓는다 — 01 홈화면 참고.
   .screen 의 기본 패딩은 스테이지 좌표를 흔드니 뺀다. */
#screen-home { padding: 0; align-items: center; justify-content: center; }

/* 등장 — 끝난 뒤엔 값을 붙잡지 않는다(backwards). both 로 opacity 를 붙잡고 있으면 크롬이 화면을 backdrop root 로 보아, 화면 안 뒤 흐림(backdrop-filter —
   대기 배지 · 패트로누스 원 · 닉네임 칸)이 화면 뒤 배경(.bg-layer)을 못 보고 아무것도 흐리지 않는다(26-10-06 확인 — 픽셀 차이 0). 끝 값 = 기본 값이라 보이는 건 같다 */
.screen--active { display: flex; animation: screen-in 0.45s ease backwards; }
@keyframes screen-in {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}

/* ---------- 01 홈화면 (시작 화면) ----------
   완드 체험 태블릿(wand/) 시작 화면과 **같은 구조·같은 크기**다(26-09-28 지시).
   아래 숫자는 완드 앱(wand/styles.css "01 대기" · .dcta--stage)의 값을 그대로 옮긴 것이고,
   단위만 --wu 로 쓴다. 완드 쪽 수치가 바뀌면 같은 숫자로 따라 바꾸면 된다.

   --wu(완드 단위) = 완드 앱의 --u 를 스캐너 좌표로 옮긴 값.
     완드  : 세로 1200x1920 프레임 → --u = 짧은 변 / 1200
     스캐너: 가로 1133x744 프레임  → --u = 짧은 변 / 744
   두 앱 모두 16:10 태블릿의 **짧은 변**으로 크기가 정해져, 같은 기기에서
   완드 1u = 스캐너 744/1200 u 다. 그래서 --wu = --u × 744/1200.
   예) 레노버 16:10 — 완드(세로 800x1280) --u 0.667 · 스캐너(가로 1280x800) --wu 0.667 → 같은 픽셀.
   참고로 완드 헤더 수치는 스캐너 초안(4081:19988, 744 폭)을 ×1200/744 한 값이라, 되돌리면
   스캐너 초안 값(여백 24·36 · 로고 196 · 국기 56 · 간격 24)이 그대로 나온다.

   ⚠ 예전 홈 시안(4075:19710 · 19555 · 4063:15989 · 4075:19658)의 섹션 아이콘과 유니온 데코는
     완드 시작 화면에 없어 뺐다(에셋 assets/home/icon-*.svg · deco-union.svg 는 남겨 뒀다).
   ⚠ 타이틀 줄 수는 콘텐츠 · 언어마다 다르다(26-09-30 Figma 홈 3종) — 아래 "시작 화면 타이틀" 참고. */
:root { --wu: calc(var(--u) * 744 / 1200); }

/* ===== 시작 화면 — 26-09-30 Figma 홈 6종(4734:9654 · 9970 물약 / 4734:9703 · 9747 퀴디치 / 4734:9884 · 9927 패트로누스,
   각 [다른 사람 체험 중 · 평소], 1131×744) 그대로. 숫자는 시안 px × --u.
   구조: 스테이지(위 24 · 아래 48) > 헤더(폭 1053 가운데 · 높이 80, [로고 196×72 | 국기 56 · 사이 24])
         > 남은 높이(104 ~ 696)의 가운데에 [제목 묶음 → 50 → 큰 버튼 400×87] (+ 대기 땐 칩: 묶음 위에서 427)
         제목 묶음 = [타이틀 96 → 32 → 서브텍스트 블록], 서브텍스트 블록 폭 = 타이틀 폭(구분선이 타이틀 폭만큼).
   ⚠ 시안 색 중 보라였던 것(프레임 #08050F · 서브텍스트 라디얼 #16122D · 칩 안쪽 그림자 #CFB8FB)은 키 컬러 네이비 규칙대로
     옮긴 값을 쓴다(#05070F · #12172D · #7691FF). ===== */
.home-stage {
  position: relative;
  width: min(100%, calc(1440 * var(--u)));
  height: calc(744 * var(--u));
  padding: calc(104 * var(--u)) 0 calc(48 * var(--u));     /* 위 24 + 헤더 80 · 아래 48 */
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 0;
  text-align: center;
}

/* 헤더 · 로고 · 언어 선택 · 타이틀 · 서브텍스트 블록 · 큰 CTA 는 디자인시스템 공통 StartScreen · LanguageToggle · QuestButton
   (components.css, 단위 --ds-wu)을 쓰고, 시안 값과 다른 곳만 아래에서 덮는다. */
:root { --ds-wu: var(--wu); }                 /* 공통 컴포넌트의 완드 프레임 숫자 → 스캐너 좌표 */
/* 헤더 — 폭 1053 을 가운데에(시안 1131 프레임 좌우 39), 위 24 · 높이 80 · 가운데 정렬. 운영자 로그인도 같은 자리. */
.start-header { z-index: 3; }                 /* .home-fx(입자·빛무리) 위로 */
:is(#screen-home, #screen-login) .start-header {
  top: calc(24 * var(--u)); left: calc(50% - 526.5 * var(--u)); right: auto;
  width: calc(1053 * var(--u)); height: calc(80 * var(--u));
  align-items: center;
}
/* 시작 화면(물약 · 퀴디치 · 패트로누스) 헤더 폭 = QR 스캔 화면 헤더 폭 — 26-10-13 다원님 요청("가운데로 몰린 느낌").
   스테이지(.home-stage — 스캔 .scan-stage 와 같은 상자: 기기 폭 · 최대 1440)의 양끝에서 36 안쪽(스캔 #screen-scan .scan-header 좌우 36)이라
   국기가 스캔 화면 [도움말]과 같은 오른쪽 끝에 선다. 전엔 시안 폭 1053 을 가운데에 두어(시안 프레임 좌우 40) 1133 보다 넓은 화면에서
   국기가 안쪽으로 몰렸다(1280 폭이면 끝에서 113). 1133×744 에선 시안보다 4 바깥이다. 높이 · 위 24 는 그대로, 로그인 화면은 그대로 */
#screen-home .start-header { left: calc(36 * var(--u)); right: calc(36 * var(--u)); width: auto; }
:is(#screen-home, #screen-login) .start-logo { width: calc(196 * var(--u)); }   /* 196×72 */
:is(#screen-home, #screen-login) .start-logo img { filter: none; }              /* 시안 로고엔 글로우가 없다 */
/* 국기 — Btn/flag 56 · 사이 24(완드 시작 화면과 같은 규칙). 비선택: 여백 3 · 원판 #EAEBEC · 그림자 두 겹(0 0 0.259 · 0 2.068 3.102,
   drop-shadow 라 반경 절반). 선택: 여백 2 · 원판 #F7F7F8 + 바깥 테두리 2 #E1E2E4(Figma stroke OUTSIDE — box-shadow 로). */
#screen-home .lang-toggle { gap: calc(24 * var(--u)); }
#screen-home .lang-btn {
  width: calc(56 * var(--u));
  padding: calc(3 * var(--u));
  border: 0;
  filter: drop-shadow(0 0 calc(0.13 * var(--u)) rgba(66, 71, 76, 0.32))
          drop-shadow(0 calc(2.068 * var(--u)) calc(1.551 * var(--u)) rgba(66, 71, 76, 0.08));
  transition: box-shadow 0.25s ease;
}
#screen-home .lang-btn--on {
  padding: calc(2 * var(--u));
  box-shadow: 0 0 0 calc(2 * var(--u)) #E1E2E4;          /* line/solid/primary */
}
/* 본문 묶음(시안 Text Container) — 제목 묶음 → 50 → 버튼. 대기 칩은 묶음 기준 절대 위치. */
.home-content {
  position: relative;
  display: flex; flex-direction: column; align-items: center;
  gap: calc(50 * var(--u));
}
/* 제목 묶음(시안 Title) — 타이틀 → 32 → 서브텍스트 블록. 서브텍스트 블록은 묶음 폭(= 타이틀 폭)으로 늘어난다. */
.home-title-block {
  display: flex; flex-direction: column; align-items: stretch;
  gap: calc(32 * var(--u));
}
/* 타이틀 — Hahmlet Regular(400), 한국어 · 영어 모두. 시안(퀴디치 4734:9703 · 패트로누스 4734:9884 · 9927)은 아직 Warhaven OTF Regular 지만
   Warhaven 은 라이선스로 쓰지 않아(26-10-02) 같은 굵기의 Hahmlet 으로 그린다 — Figma 도 맞출 것. 상자 높이 96 을 고정하고 아래로 붙인다(justify-end):
   큰 줄 80 · 행간 1.2(= 96)가 상자를 채우고, 작은 줄(29 · 행간 normal)은 12 위로 상자 밖에 걸친다 —
   그래서 한 줄(POTION CLASS)이든 두 줄(MEET YOUR / PATRONUS)이든 서브텍스트 · 버튼 자리가 같다. 자간 0 · 그림자 없음(시안). */
#screen-home .start-title {
  height: calc(96 * var(--u));
  display: flex; flex-direction: column; align-items: center; justify-content: flex-end;
  gap: calc(12 * var(--u));
  font-family: var(--font-display); font-weight: 400;
  line-height: normal; letter-spacing: 0;
  text-shadow: none;
}
#screen-home .start-title__sm { font-size: calc(29 * var(--u)); line-height: normal; }
#screen-home .start-title__lg { font-size: calc(80 * var(--u)); line-height: 1.2; white-space: nowrap; }
/* 서브텍스트 블록(시안 Subtext Container) — 반짝이 51.296 상자(36.272 네모를 -45° 돌린 것)가 아래로 -28 겹치고,
   설명 상자(위 헤어라인 4 · 여백 40 · 10 · 모서리 20 · 위 가운데 라디얼)가 이어진다.
   26-10-01 완드 시작 화면(wand/styles.css "서브텍스트")과 같게: 마름모 윗변 두 쪽의 밝은 선(#EFF8FF · 위로 2)은 Figma 가 돌린 **뒤**
   화면 기준으로 그린다(시안 Icon Container 4734:9943 = 45° · 그림자 (0, -2)) — 그래서 그림(deco-diamond.svg)만 돌리고
   그림자는 돌리지 않은 바깥 칸에 준다. 예전 deco-sparkle.svg 는 그림자를 돌리기 전에 구워 넣어 한쪽 변("/")만 밝았다. */
#screen-home .start-sub { width: auto; margin-top: 0; isolation: isolate; }
#screen-home .start-sub__spark {
  display: flex; align-items: center; justify-content: center;
  width: calc(51.296 * var(--u)); height: calc(51.296 * var(--u));
  margin-bottom: calc(-28 * var(--u));
  transform: none;
  filter: drop-shadow(0 calc(-2 * var(--u)) 0 #EFF8FF);
}
#screen-home .start-sub__spark img {
  display: block;
  width: calc(36.272 * var(--u)); height: calc(36.272 * var(--u));
  transform: rotate(-45deg);
}
#screen-home .start-sub__body {
  /* 위 44 = 헤어라인 4(시안은 위 테두리 4 라 높이에 들어간다 — 여기선 ::before 로 그려서 여백으로 채운다) + 40 */
  padding: calc(44 * var(--u)) calc(10 * var(--u)) calc(40 * var(--u));
  border-radius: calc(20 * var(--u));
  /* 라디얼 — 위 가운데에서 가로 27.74% · 세로 90.53%(시안 행렬 값을 상자 비율로): #12172D → #090C17 50% → 투명 */
  background: radial-gradient(27.74% 90.53% at 50% 0%,
    rgba(18, 23, 45, 1) 0%, rgba(9, 12, 23, 0.5) 50%, rgba(0, 0, 0, 0) 100%);
}
/* 헤어라인 4 — 완드와 같은 그라디언트(5% 투명 → 50% #EFF8FF → 94.5% 투명). 공통(70%)보다 밝다 */
#screen-home .start-sub__body::before {
  height: calc(4 * var(--u));
  background: linear-gradient(90deg,
    rgba(239, 248, 255, 0) 5%, rgba(239, 248, 255, 1) 50%, rgba(239, 248, 255, 0) 94.5%);
}
#screen-home .start-desc {
  font-size: calc(22 * var(--u)); font-weight: 400;       /* NEXON Regular 22 */
  line-height: 1.5; letter-spacing: 0.01em;              /* 시안 0.22px */
  color: #EFF8FF;                                        /* ⚠ 시안 원본값 */
  white-space: nowrap;
}
/* 대기 배지(다른 사람이 체험 중) — 26-10-06 완드 #119(wand_01_대기 4990:10080 · 4990:10113)와 같은 배지로 통일(사용자 결정: 자리는 [시작하기] 자리 ·
   글자색은 스캐너 칩 색 #92DBFA 그대로). busy 면 [시작하기]를 숨기고 그 자리(묶음 흐름 안 — 제목 묶음 → 같은 간격 → 배지)에 배지가 들어가
   묶음이 화면 가운데로 다시 맞춰진다. 판은 스캔 화면 칩(.scan-chip)과 같다 — 높이 35 · 흰 → #CFD6F0 → 흰 10% · 테두리 #FEFDFC 32% 1(바깥)
   · 안쪽 그림자 네이비 40% 8 · 뒤 흐림 6. 글자 NEXON Regular 18 / 27 · 자간 1% · #92DBFA(lightblue_500).
   두 문구("다른 사람이 체험중입니다" ↔ "잠시만 기다려주세요")를 같은 자리에 겹쳐 두고 2.6초마다 번갈아(app.js swapWaitChip): 나가는 문구는 위로 ·
   들어오는 문구는 아래에서 올라오며 흐림이 걷힌다. 폭은 문구 폭 + 40(app.js fitWaitChip), 0.6초에 걸쳐 바뀐다. 움직임은 완드와 같은 앱 움직임(시안은 두 장면). */
.home-wait-chip {
  display: none;
  position: relative; flex: none;
  height: calc(35 * var(--u));
  margin: 0;
  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(--u)) rgba(254, 253, 252, 0.32), inset 0 0 calc(8 * var(--u)) rgba(118, 145, 255, 0.4);
  -webkit-backdrop-filter: blur(calc(6 * var(--u)));
          backdrop-filter: blur(calc(6 * var(--u)));
  overflow: hidden;
  transition: width 0.6s cubic-bezier(0.4, 0, 0.2, 1);
}
.home-wait-chip__text {
  position: absolute; left: 50%; top: 50%;
  transform: translate(-50%, calc(-50% + 12 * var(--u)));
  opacity: 0; filter: blur(calc(3 * var(--u)));
  font-size: calc(18 * var(--u)); line-height: 1.5; letter-spacing: 0.01em; font-weight: 400;
  color: #92DBFA;                                        /* ⚠ 시안 원본값 — lightblue_500 */
  white-space: nowrap;
  transition: transform 0.6s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.45s ease, filter 0.45s ease;
}
.home-wait-chip__text.is-on { transform: translate(-50%, -50%); opacity: 1; filter: none; }
.home-wait-chip__text.is-out { transform: translate(-50%, calc(-50% - 12 * var(--u))); opacity: 0; filter: blur(calc(3 * var(--u))); }
.home-wait-chip__text.no-trans { transition: none; }
/* 시작 화면을 눌렀을 때 — 시작이 안 된다는 걸 배지가 한 번 살짝 커졌다 돌아와 알린다(app.js nudgeWaitChip, 완드 sub-nudge 와 같은 값) */
.home-wait-chip.is-nudge { animation: wait-nudge 0.9s ease; }
@keyframes wait-nudge {
  0%, 100% { transform: scale(1); }
  25%      { transform: scale(1.1); }
  50%      { transform: scale(0.98); }
  70%      { transform: scale(1.04); }
}
body[data-zone="busy"] #screen-home .start-cta { display: none; }
body[data-zone="busy"] #screen-home .home-wait-chip { display: block; }
/* 짝 자리 기기 켜는 중(이슈 #149, 26-10-07 다원님 결정 — 시안 없음) — 시작 화면은 위 대기 배지를 같이 쓰고 첫 문구만
   "체험 기기를 켜는 중이에요"(app.js syncWaitChip — 다른 사람 체험 중보다 앞선다). QR 스캔 화면은 아래 "자리 기기 켜는 중" */
body[data-seat="off"] #screen-home .start-cta { display: none; }
body[data-seat="off"] #screen-home .home-wait-chip { display: block; }

/* 작은 CTA — 디자인 시스템 .dcta--small(Figma btn/main/small 3084:8124, 310x66)은 px 고정이라
   반응형 화면(알림 판 · 패트로누스 · 결과) 안에서도 버튼만 크기가 멈춰 있었다(1920x1080 에서
   판은 1.45배인데 버튼은 310x66). 컴포넌트 값을 그대로 × --u 로 덮는다 — 기본 .dcta 의 보더·
   안쪽 글로우 두께도 같이 키워야 비율이 시안과 같다(.dcta--stage 와 같은 방식). */
.dcta--small {
  width: calc(310 * var(--u)); height: calc(66 * var(--u));
  border-width: calc(1.846 * var(--u));
}
.dcta--small::before {
  border-width: calc(18.457 * var(--u));
  filter: blur(calc(3.691 * var(--u)));
}
.dcta--small .dcta__label { font-size: calc(20 * var(--u)); }
.dcta--small .dcta__corner { width: calc(11.07 * var(--u)); height: calc(11.07 * var(--u)); }
.dcta--small .dcta__corner--tl { left: calc(-4.4 * var(--u)); top: calc(-3.2 * var(--u)); }
.dcta--small .dcta__corner--tr { right: calc(-4.4 * var(--u)); top: calc(-3.2 * var(--u)); }
.dcta--small .dcta__corner--bl { left: calc(-4.4 * var(--u)); bottom: calc(-3.2 * var(--u)); }
.dcta--small .dcta__corner--br { right: calc(-4.4 * var(--u)); bottom: calc(-3.2 * var(--u)); }

/* 홈 CTA 숨쉬기 — 26-09-30 완드 시작 버튼과 같게(wand/styles.css .start-cta · cta-breathe): 네이비(#7691FF) 바깥 그림자가
   2.8초에 10 ↔ 44 로 번졌다 줄어든다(알파 25% ↔ 60%). 완드 --u(1200 프레임)는 이 앱의 --wu 라 숫자는 그대로 × --wu.
   (예전 스캐너는 흰 drop-shadow 2.6초였다.) 공통으로 올릴 후보. */
.start-cta { animation: cta-breathe 2.8s ease-in-out infinite; }   /* 위로 56 은 공통 .start-cta */
.start-cta:active { transform: scale(0.97); }
@keyframes cta-breathe {
  0%, 100% { box-shadow: 0 0 calc(10 * var(--wu)) rgba(118, 145, 255, 0.25); }
  50%      { box-shadow: 0 0 calc(44 * var(--wu)) rgba(118, 145, 255, 0.6); }
}


/* ---------- 02 QR 스캔 화면 — Figma 4063:15483 ---------- */
:root {
  --scan-key: #7691FF;                        /* 스캔 화면 키컬러 (purple_200) */
  --scan-frame-bg: rgba(27, 20, 17, 0.1);      /* 뷰파인더 프레임 배경 (Figma 값) */
  /* 스캔 화면 단위 — 시안은 1133x744 고정 프레임이다. vh/clamp 로 요소마다 따로
     줄이면 화면 비율에 따라 간격·크기가 제각각 틀어져서 시안과 안 맞는다.
     대신 프레임이 화면에 들어가는 최대 배율을 하나 구해, 아래 모든 치수를
     "시안 px × --u" 로 적는다. 1133 폭 화면에서 --u = 1 → 시안 수치 그대로. */
  --u: min(
    (100vw - env(safe-area-inset-left, 0px) - env(safe-area-inset-right, 0px)) / 1133,
    (100vh - env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px)) / 744
  );
}

/* 스테이지 — 크기(--u)는 시안 프레임 1133x744 에 맞추되, **가로는 기기 폭을 다 쓴다**
   (완드 체험 태블릿 wand/ 의 26-09-23 그리드 재설계를 그대로 옮겼다).
   예전엔 1133 폭에 묶여 시안보다 넓은 기기에서 양옆에 빈 띠가 생기고, 뒤로·홈 버튼이
   화면 가장자리에서 한참 안쪽에 떠 보였다 — 레노버 16:10(1280x800)에서 띠 31 · 버튼 74 안쪽.
   홈 화면은 로고·언어 버튼이 끝에서 36 이라, 홈 → 스캔으로 넘어갈 때 버튼이 안으로 튀었다.
   이제 헤더는 화면 끝에서 시안 px 40 안쪽에 붙고, 가운데 내용(명판·뷰파인더·안내)은 가운데에 선다.
   상한 1440 은 홈 시안(4075:19557)의 max 1440 과 같다 — 가로가 긴 화면에서 끝없이 벌어지지 않게.
   1133x744 기기에서는 예전과 똑같다.
   .screen 의 기본 패딩(4vh 5vw)은 프레임 좌표를 흔드니 스캔 화면에선 뺀다. */
#screen-scan { padding: 0; align-items: center; justify-content: center; }
.scan-stage {
  position: relative;
  width: min(100%, calc(1440 * var(--u)));
  height: calc(744 * var(--u));
  padding: calc(36 * var(--u)) 0;             /* 시안 루트 py 36 */
  display: flex; flex-direction: column;
}
/* 본문 — 시안 4063:15502: 헤더 바로 아래에서 시작(위 정렬), pt 32, 패널→안내 gap 40.
   세로 가운데 정렬이 아니다 — 가운데로 두면 화면이 높을수록 헤더와 벌어진다. */
.scan-layout {
  flex: 1; min-height: 0;
  display: flex; flex-direction: column; align-items: center;
  padding-top: calc(32 * var(--u));
  gap: calc(40 * var(--u));
  text-align: center;
}

/* 헤더 — Figma 4063:15488: px 40, 버튼 자리 py 30 → 높이 120. 3열 그리드(뒤로 /
   타이틀 / 홈)라 양옆 버튼 폭과 무관하게 타이틀이 늘 정가운데. 흐름 안에 있어야
   아래 본문의 pt 32 가 헤더 바닥에서 시작한다. */
.scan-header {
  position: relative; z-index: 4;
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: center;
  padding: calc(30 * var(--u)) calc(40 * var(--u));
}
.scan-header > :first-child { justify-self: start; }
.scan-header > :last-child { justify-self: end; }

/* 화면 타이틀 — 26-09-28 부터 디자인시스템 공통 StepTitle(.title-deco + .step-title--glow, 완드와 같은 크기 · 단위
   --ds-wu). 예전 명판(.scan-plaque, 육각 플레이트)은 팝업 안에서만 쓴다(공통 Popup 의 명판). */
.scan-header > .title-deco { grid-column: 2; }
.scan-header .step-title { white-space: nowrap; }   /* 가운데 칸은 글자 폭만큼 — 양옆 버튼과 겹치지 않게 한 줄 */

/* 원형 아이콘 버튼 — 시안 4045:14191 의 좌(뒤로)·우(홈) 둘 다 유리질 원판이다
   (뒤로 아이콘 에셋 0db6b.svg 안에 backdrop-blur 7px 원이 들어 있다). */
.scan-icon-btn {
  display: flex; align-items: center; justify-content: center;
  width: calc(60 * var(--u)); height: calc(60 * var(--u)); padding: 0;
  background: none; border: none; border-radius: var(--radius-full);
  color: var(--scan-key); cursor: pointer;
}
.scan-icon-btn svg { width: calc(28 * var(--u)); height: calc(28 * var(--u)); }
.scan-icon-btn img { width: calc(28 * var(--u)); height: auto; }
.scan-icon-btn:active { opacity: 0.7; }
.scan-icon-btn--glass {
  background: rgba(255, 255, 255, 0.08);
  border: 1.379px solid rgba(100, 100, 100, 0.16);
  backdrop-filter: blur(calc(7 * var(--u)));
  box-shadow: 0 1px calc(24 * var(--u)) 0 rgba(0, 0, 0, 0.25);
}

/* ===== 26-10-01 Figma 스캐너 QR 스캔 3종(1133×744) 그대로 — 대기 scanner_scan_qr 4738:10012 · 확인 중 scanner_scan_loading 4741:10593
   · 완료 scanner_scan_completed 4741:10445. 틀(헤더 · 제목 · 원 · 안내)은 26-09-30 완드 통일 때와 같고 숫자만 시안 값으로 바꿨다.
   세로 배치: 위 48 → 헤더 80(뒤로 56 · 제목 · 도움말 56, 좌우 36) → 본문 568 가운데에 [원 400 → 32 → 안내 33 → 12 → 구분선 안내 52]
   (원 위 147.5) → 아래 48. [건너뛰기]는 본문 오른쪽 40 · 위 538 에 떠 있다(화면 위에서 666).
   상태별: 대기 = 옅은 링 + 움직이는 스캔라인 / 확인 중 = 밝은 호가 돈다 / 완료 = 링 전체가 빛나고 뷰파인더 가운데에 "스캔 완료" 칩,
   뒤로 · 도움말은 숨는다(자리는 남는다). 안내 문구 · [건너뛰기]는 세 상태 모두 그대로 보인다.
   예전 스캐너 패널(검은 원 + 두 겹 네이비 링 SVG + 사각 뷰파인더 + 초록 체크 글리프)은 걷어냈다(에셋 assets/scan/*.svg 는 남겨 뒀다). ===== */
#screen-scan .scan-stage { padding: calc(48 * var(--u)) 0; }
#screen-scan .scan-header { height: calc(80 * var(--u)); padding: 0 calc(36 * var(--u)); }
#screen-scan .scan-layout { position: relative; padding-top: 0; gap: calc(32 * var(--u)); justify-content: center; }
/* 뒤로 버튼 — 완드 .icon-back: 56 원 · 표면 frost-5 · 테두리 없음 · 흰 셰브론 24 */
.icon-back {
  flex-shrink: 0;
  width: calc(56 * var(--u)); height: calc(56 * var(--u));
  display: flex; align-items: center; justify-content: center;
  padding: 0; border: 0; border-radius: 50%;
  background: var(--surface-frost-5);
  color: var(--color-white-100);
  cursor: pointer;
}
.icon-back svg { width: calc(24 * var(--u)); height: calc(24 * var(--u)); }
.icon-back:active { transform: scale(0.94); }
/* 확인 중 · 완료엔 뒤로 · 도움말 · 건너뛰기를 막는다 — 검증 응답이 화면을 떠난 뒤 도착하지 않게.
   완료엔 뒤로 · 도움말이 숨는다(시안 4741:10445 은 양옆이 빈 56 자리) — [건너뛰기]는 시안대로 보인다. */
#screen-scan:is([data-state="loading"], [data-state="done"]) :is(.icon-back, .skip-btn) { pointer-events: none; }   /* 실패(fail)는 대기처럼 다 눌린다 */
#screen-scan[data-state="done"] .scan-header > .icon-back { visibility: hidden; }
/* 선택 화면 — [선택하기]를 누르고 저장을 기다리는 동안엔 뒤로를 막는다(스캔 화면 확인 중과 같은 까닭, 26-10-02 #100 리뷰 ③) */
:is(#screen-patronus, #screen-house, #screen-nickname)[data-saving="true"] .icon-back { pointer-events: none; opacity: 0.4; }
/* 제목 — Figma StepHeader/TitleDeco(4477:770) 값: Hahmlet Bold 42 · 행간 53.109 · 자간 -0.425 · 화살 52×28 · 사이 16 · 글로우 #FAF7D4 50%.
   공통 StepTitle(Hahmlet 72 × --ds-wu)을 이 화면들에서 덮는다. 영문도 같은 Hahmlet Bold(26-10-02 Warhaven 은 라이선스로 뺐다). */
:is(#screen-scan, #screen-house, #screen-nickname, #screen-patronus) .title-deco { height: calc(80 * var(--u)); align-items: center; gap: calc(16 * var(--u)); }
:is(#screen-scan, #screen-house, #screen-nickname, #screen-patronus) .title-deco__arrow { width: calc(52 * var(--u)); height: calc(28 * var(--u)); }
:is(#screen-scan, #screen-house, #screen-nickname, #screen-patronus, #screen-result) .step-title {
  font-family: var(--font-display); font-weight: 700;
  font-size: calc(42 * var(--u)); line-height: calc(53.109 * var(--u)); letter-spacing: calc(-0.425 * var(--u));
}
:is(#screen-scan, #screen-house, #screen-nickname, #screen-patronus, #screen-result) .step-title--glow { text-shadow: calc(-0.649 * var(--u)) calc(-0.649 * var(--u)) calc(16.346 * var(--u)) rgba(250, 247, 212, 0.5); }

/* 스캔 패널 — Figma QRScanPanel/ScanPanel(4479:804)을 시안 3종의 400 크기로(컴포넌트 424 의 0.943배).
   [링] 398.113 원(가장자리에서 0.943) · 두께 7.962 · #D9D9D9 10% → 확인 중엔 그 위에 밝은 호(#FFFEEE, 306°)가 돌고, 완료면 링 전체가 빛난다
       (호 · 링은 시안 SVG 필터 그대로: 흰 60% 글로우 표준편차 5.66 → 전체 흐림 2.83. CSS drop-shadow 의 값은 표준편차의 두 배라 11.32).
   [뷰파인더] 237.736 둥근 사각(17.379) · 채움 #1B1411 40% · 테두리 #E2E2E2 51% 2.049 · 브래킷 28.692(#E2E2E2 2.869 · 둥근 끝)
       · 스캔라인 176.252×2.049(그라디언트 #10121C → #7ECEF4 60% → #10121C 80%). 완료에도 체크 글리프는 없다(시안). */
.scan-panel {
  position: relative; flex: none;
  width: calc(400 * var(--u)); aspect-ratio: 1;
  display: flex; align-items: center; justify-content: center;
}
.scan-ring {
  position: absolute; inset: calc(0.943 * var(--u));
  border-radius: 50%;
  border: calc(7.962 * var(--u)) solid rgba(217, 217, 217, 0.1);       /* ⚠ 시안 원본값(비토큰) */
  pointer-events: none;
}
.scan-ring--glow {
  display: none;
  border: 0;
  filter: drop-shadow(0 0 calc(11.32 * var(--u)) rgba(255, 255, 255, 0.6)) blur(calc(2.83 * var(--u)));
}
.scan-ring--glow::before {
  content: ""; position: absolute; inset: 0;
  border-radius: 50%;
  border: calc(7.962 * var(--u)) solid #FFFEEE;                         /* ⚠ 시안 원본값(비토큰) */
}
#screen-scan:is([data-state="loading"], [data-state="done"]) .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); } }
.viewfinder {
  position: relative;
  width: calc(237.736 * var(--u)); height: calc(237.736 * var(--u));
  box-sizing: border-box;
  border-radius: calc(17.379 * var(--u));
  overflow: hidden;
  background: rgba(27, 20, 17, 0.4);                                     /* ⚠ 시안 원본값(비토큰) */
  border: calc(2.049 * var(--u)) solid rgba(226, 226, 226, 0.51);       /* ⚠ 시안 원본값(비토큰) */
}
/* 확인 중 · 완료 — 카메라 · 카메라 꺼짐 안내는 숨긴다(뷰파인더 틀은 남는다). 스캔라인은 시안처럼 가운데에 멈춰 남는다 */
#screen-scan:is([data-state="loading"], [data-state="done"]) #camera-feed,
#screen-scan:is([data-state="loading"], [data-state="done"]) .vf-camera-off { visibility: hidden; }
#screen-scan:is([data-state="loading"], [data-state="done"]) .vf-scanline { animation: none; top: calc(116.111 * var(--u)); }
/* 스캔 실패(fail) — 26-10-02 Figma 4864:28953(완드 QR 스캔 실패와 같은 모양): 브래킷만 빨강 #FF8484(red_500 · 선 굵기 그대로),
   링 · 뷰파인더 · 카메라 · 스캔라인은 대기와 같다(바로 다시 댈 수 있게). ERROR_HOLD_MS 뒤 대기로 돌아간다(app.js endScanFail). */
#screen-scan[data-state="fail"] .vf-bracket { stroke: #FF8484; }                     /* ⚠ 시안 원본값 — 공통 Toast 실패색과 같은 red_500 */
/* 전면 카메라는 **거울처럼 좌우를 뒤집어** 보여준다 — 그래야 관람객이 손을 오른쪽으로
   옮겼을 때 화면에서도 오른쪽으로 움직여서 QR 을 맞추기 쉽다(영상통화 앱과 같은 관행).
   ⚠ 인식에는 영향이 없다. BarcodeDetector 와 jsQR 은 CSS 가 아니라 원본 프레임을 읽는다. */
#camera-feed {
  width: 100%; height: 100%; object-fit: cover;
  transform: scaleX(-1);
}
/* 코너 브래킷 — 28.692 ㄱ자, 선 2.869 둥근 끝. 틀 바깥 가장자리에서 18.445(테두리 안쪽 기준이라 2.049 를 뺀 16.396).
   ⚠ 아래 두 개는 시안 그대로 위보다 6.149 더 안쪽(22.545)이다 — 컴포넌트의 브래킷 줄 간격이 137.313 이라 아래 줄이 바닥에 닿지 않는다. */
.vf-bracket {
  position: absolute; z-index: 2; pointer-events: none;
  width: calc(28.692 * var(--u)); height: calc(28.692 * var(--u));
  overflow: visible;
  fill: none; stroke: #E2E2E2; stroke-width: 2.869;                     /* ⚠ 시안 원본값(비토큰) · 선 굵기는 viewBox 단위 */
  stroke-linecap: round; stroke-linejoin: round;
}
.vf-bracket--tl { top: calc(16.396 * var(--u)); left: calc(16.396 * var(--u)); }
.vf-bracket--tr { top: calc(16.396 * var(--u)); right: calc(16.396 * var(--u)); transform: scaleX(-1); }
.vf-bracket--bl { bottom: calc(22.545 * var(--u)); left: calc(16.396 * var(--u)); transform: scaleY(-1); }
.vf-bracket--br { bottom: calc(22.545 * var(--u)); right: calc(16.396 * var(--u)); transform: rotate(180deg); }
/* 스캔라인 — 176.252×2.049, 왼쪽에서 28.686. 대기엔 14% ↔ 84% 를 2.2초에 오가고(완드와 같다), 확인 중 · 완료엔 시안 자리(가운데)에 멈춘다.
   그라디언트 위치는 시안 SVG(-24.68 → 206.8 구간의 16.3% · 50% · 84%)를 선 길이 기준으로 옮긴 값 */
.vf-scanline {
  position: absolute; z-index: 2; pointer-events: none;
  left: calc(28.686 * var(--u));
  width: calc(176.252 * var(--u)); height: calc(2.049 * var(--u));
  background: linear-gradient(90deg, #10121C 7.47%, rgba(126, 206, 244, 0.6) 51.67%, rgba(16, 18, 28, 0.8) 96.32%);   /* ⚠ 시안 원본값(#13101C → 네이비 #10121C) */
  animation: vf-scanline 2.2s ease-in-out infinite alternate;
}
@keyframes vf-scanline { from { top: 14%; } to { top: 84%; } }
/* 카메라를 못 켰을 때만 — app.js 가 켠다(뷰파인더 안을 덮는다). 완드 .scan-off 값(완드 --u = 스캐너 --wu) */
.vf-camera-off {
  display: none;
  position: absolute; inset: 0; z-index: 3;
  flex-direction: column; align-items: center; justify-content: center;
  gap: calc(20 * var(--wu));
  background: rgba(5, 7, 15, 0.9);
  color: var(--color-ice-200); text-align: center;
  padding: 0 calc(44 * var(--wu));
}
.vf-camera-off--show { display: flex; }
.vf-camera-off svg { width: calc(80 * var(--wu)); height: calc(80 * var(--wu)); color: var(--color-gray-200); }
.vf-camera-off p { margin: 0; font-size: calc(28 * var(--wu)); line-height: 1.5; word-break: keep-all; }

/* 원 아래 안내 묶음(폭 400 = 원 폭) — 안내 한 줄(NEXON Medium 22 / 33 · #EFF8FF) → 12 → 구분선 안내. 세 상태 모두 같다 */
.scan-state {
  width: calc(400 * var(--u));
  display: flex; flex-direction: column; align-items: center;
  gap: calc(12 * var(--u));
}
.scan-desc {
  margin: 0;
  font-size: calc(22 * var(--u)); line-height: 1.5; letter-spacing: 0.005em; font-weight: 500;
  color: #EFF8FF;                                                    /* ⚠ 시안 원본값(비토큰) */
  word-break: keep-all;
}
/* 칩 "스캔 완료" — 완료에만 뷰파인더 가운데(시안 4741:10497). 높이 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;
  position: absolute; left: 50%; top: 50%; z-index: 3;
  transform: translate(-50%, -50%);
  height: calc(35 * var(--u));
  padding: calc(4 * var(--u)) calc(20 * var(--u));
  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(--u)) rgba(254, 253, 252, 0.32), inset 0 0 calc(8 * var(--u)) rgba(118, 145, 255, 0.4);
  -webkit-backdrop-filter: blur(calc(6 * var(--u)));
          backdrop-filter: blur(calc(6 * var(--u)));
}
.scan-chip__text {
  font-size: calc(18 * var(--u)); line-height: 1.5; letter-spacing: 0.01em; font-weight: 400;
  color: #92FA9B;                                                    /* ⚠ 시안 원본값(비토큰) */
  white-space: nowrap;
}
/* 뷰파인더 가운데 칩만 — 안내 한 줄 자리 칩(실패 · 체험 기기 켜는 중)은 빼야 한다. 26-10-26 전엔 :not(.scan-chip--fail) 이라
   "체험 기기 켜는 중" 칩까지 완료 때마다 안내 아래에 떠 묶음이 41 길어지고 원이 20 위로 밀렸다(기기가 켜져 있어도) */
#screen-scan[data-state="done"] .scan-panel .scan-chip { display: inline-flex; }
/* "스캔 실패" 칩 — 실패에만, 안내 한 줄 자리(가운데 띄우지 않고 흐름 안). 칩 높이 35 를 안내 줄 33 에 맞춰 위아래 -1 → 아래 구분선이 안 움직인다.
   글자만 빨강 #FF8484, 틀은 완료 칩과 같다(시안 Scan Complete Button Container — 안쪽 그림자 보라 → 네이비). */
.scan-chip--fail { position: static; transform: none; margin: calc(-1 * var(--u)) 0; }
.scan-chip--fail .scan-chip__text { color: #FF8484; }                               /* ⚠ 시안 원본값(red_500) */
#screen-scan[data-state="fail"] .scan-desc { display: none; }
#screen-scan[data-state="fail"] .scan-chip--fail { display: inline-flex; }
/* "체험 기기 켜는 중" 칩 — 짝 자리 PC 가 꺼져 있거나 켜지는 중(body[data-seat="off"], 이슈 #149). 대기 · 실패 상태일 때 안내 한 줄 자리에
   (실패 칩과 같은 자리 · 같은 틀), 글자만 대기 배지와 같은 파랑 #92DBFA. 구분선 아래는 "잠시만 기다려주세요". 확인 중 · 완료는 그대로 둔다.
   [건너뛰기]를 누르면 칩이 한 번 튄다(app.js nudgeSeatChip — 대기 배지 nudge 와 같은 움직임). */
.scan-chip--seat { position: static; transform: none; margin: calc(-1 * var(--u)) 0; }
.scan-chip--seat .scan-chip__text { color: #92DBFA; }                              /* ⚠ 시안 원본값 — lightblue_500(대기 배지와 같다) */
.scan-chip--seat.is-nudge { animation: wait-nudge 0.9s ease; }
body[data-seat="off"] #screen-scan:is([data-state="scan"], [data-state="fail"]) :is(.scan-desc, .scan-chip--fail) { display: none; }
body[data-seat="off"] #screen-scan:is([data-state="scan"], [data-state="fail"]) .scan-chip--seat { display: inline-flex; }
/* 실패 안내 — 실패에만 구분선 아래 건너뛰기 안내 자리에 할 일 한 줄(26-10-02 지시: 토스트 대신 이 자리에).
   글자 모양 · 자리는 건너뛰기 안내(.info-note p) 그대로라 실패로 바뀌어도 아무것도 움직이지 않는다. */
.info-note .scan-fail-note { display: none; }
.info-note .scan-seat-note { display: none; }
body[data-seat="off"] #screen-scan:is([data-state="scan"], [data-state="fail"]) .info-note p { display: none; }
body[data-seat="off"] #screen-scan:is([data-state="scan"], [data-state="fail"]) .info-note .scan-seat-note { display: block; }
#screen-scan[data-state="fail"] .info-note p:not(.scan-fail-note) { display: none; }
#screen-scan[data-state="fail"] .info-note .scan-fail-note { display: block; }
/* 구분선 안내 — 위 선 1 #A6BCD8 · 여백 12 · 40 · NEXON Regular 18 / 27 · 자간 1% · #EFF8FF 70%(완드 .info-note 와 같다).
   문구(404)가 묶음 폭 400 보다 길어 양옆으로 조금 넘친다 — 시안도 같다. */
.info-note {
  align-self: stretch;
  display: flex; justify-content: center;
  padding: calc(12 * var(--u)) calc(40 * var(--u));
  border-top: calc(1 * var(--u)) solid #A6BCD8;                     /* ⚠ 시안 원본값(비토큰) */
  box-sizing: border-box;
}
.info-note p {
  margin: 0;
  font-size: calc(18 * var(--u)); line-height: 1.5; letter-spacing: 0.01em; font-weight: 400;
  color: rgba(239, 248, 255, 0.7);                                   /* ⚠ 시안 원본값(비토큰) */
  white-space: nowrap;
}
/* 건너뛰기 — 시안 4741:10611: 본문 오른쪽 40 · 위 538 에 뜬 글자 버튼(채움 · 테두리 없음). 여백 12 · 32 · 사이 10
   · NEXON Bold 20 / 30 · 자간 0.5% · #E6FBFF + 열린 삼각 화살 14×16(선 1 · 같은 색). 시안 화살의 잡티(noise) 필터는 뺐다 — 화면에서 안 보이는 25% 점. */
.skip-btn {
  position: absolute; right: calc(40 * var(--u)); top: calc(538 * var(--u)); z-index: 2;
  display: inline-flex; align-items: center; justify-content: center;
  gap: calc(10 * var(--u));
  padding: calc(12 * var(--u)) calc(32 * var(--u));
  border: 0; border-radius: var(--radius-full);
  background: none;
  font-family: var(--font-primary);
  font-size: calc(20 * var(--u)); line-height: 1.5; letter-spacing: 0.005em; font-weight: 700;
  color: #E6FBFF;                                                    /* ⚠ 시안 원본값(비토큰) */
  white-space: nowrap;
  cursor: pointer;
}
.skip-btn__arrow { flex: none; width: calc(14 * var(--u)); height: calc(16 * var(--u)); overflow: visible; }
.skip-btn:active { opacity: 0.7; }
/* 검증 중 표시는 별도 스피너가 아니라 스캔 화면의 loading 상태(링 회전)다 — 위 참고. */

/* ---------- 02-2 패트로누스 선택 (s9 전용) — 26-10-01 Figma 4741:11871(말) + 동물별 4774:12310(고양이) · 12380(강아지) · 12454(수달)
   · 12524(불사조) · 12594(수사슴), 1133×744 — 26-10-06 같은 노드 수정본(배경 밤 숲 · 원 채움 · [선택하기] 250, 그림 배치는 그대로) ----------
   틀은 기숙사 선택과 같다(.house-stage · .house-head — 아래 02-3 규칙을 함께 쓴다). 본문(위아래 20 · 폭 980 · 높이 490) = PatronusPicker 한 줄:
   [왼쪽 490: 높이 401 칸 맨 위에 Patronus Image 320(화면 (161.5, 230.5))]
   [오른쪽 490: Info Container 423(26-10-06 가운데 — 전엔 왼쪽 붙음) = 이름 목록(남은 높이 · 사이 24 · 좌우 180) → 10 → [선택하기] 250×59(26-10-06, 전 280)].
   Patronus Image = 원 테두리(Ellipse 1675 — 지름 320 · 선 3.7 #99E4FF 60% · 글로우 28.5 #C9EAF6 30%, 시안 SVG 그대로 — 26-10-07 글로우 ring-glow.svg · 모양 ring-shape.svg 로 나눔)
   + 동물 그림. 그림은 시안처럼 **원 + 오른쪽 네모 창**(Rectangle 240652625 마스크, art-mask.svg — 왼쪽은 원을 따라 둥글고
   오른쪽 · 위는 원보다 34 · 5 넓은 네모)으로 잘려, 동물 머리 · 앞발이 원 밖 오른쪽으로 나온다.
   26-10-06 시안: 원 안에 채움 #1A2552 20%(ring-shape.svg) + 배경 흐림 20(.pat-img::before) — 뒤 숲이 흐리게 비친다. 글로우는 100% → 30%.
   동물마다 그림 자리 · 자르기 · 창이 다르다(app.js PATRONUS[].art — 26-10-07 새 그림 6장, 불사조 · 수사슴 창 따로). 26-10-16 불사조만 있던 프레임 바깥 빛은 시안에서 빠져 뺐다. */
#screen-patronus { padding: 0; align-items: center; justify-content: center; }
#screen-patronus .house-body { padding: calc(20 * var(--u)) 0; }
.pat-picker { flex: 1; min-height: 0; align-self: stretch; display: flex; align-items: center; }
.pat-picker__stage {
  flex: 1 1 0; min-width: 0; height: calc(401 * var(--u));
  display: flex; flex-direction: column; align-items: center;
}
.pat-img { position: relative; flex: none; width: calc(320 * var(--u)); height: calc(320 * var(--u)); }
/* 원 안 배경 흐림 — 시안 Ellipse 1675 Background blur 20(CSS 절반). 원은 상자보다 0.5 오른쪽 아래(지름 320), 채움 · 선은 ring-shape.svg 가 위에 그린다 */
.pat-img::before {
  content: ""; position: absolute;
  left: calc(0.5 * var(--u)); top: calc(0.5 * var(--u));
  width: calc(320 * var(--u)); height: calc(320 * var(--u));
  border-radius: 50%;
  -webkit-backdrop-filter: blur(calc(10 * var(--u))); backdrop-filter: blur(calc(10 * var(--u)));
  pointer-events: none;
}
.pat-img__ring {                                     /* 시안 SVG 상자 377.037(글로우 자리 포함) · 가운데에서 0.5 오른쪽 아래 — 글로우 · 모양 두 장 같은 자리 */
  position: absolute; left: calc(-28.0185 * var(--u)); top: calc(-28.0185 * var(--u));
  width: calc(377.037 * var(--u)); height: calc(377.037 * var(--u));
  display: block; max-width: none; pointer-events: none;
}
/* 원 테두리 + 동물 그림 한 층(시안 Patronus Image 프레임 내용) */
.pat-img__frame { position: absolute; inset: 0; }
/* 동물 그림 — 창(.pat-art, 마스크 · 고정) > 움직임 층(.pat-art__move, 바뀔 때 커지는 애니메이션) > 그림 상자(.pat-art__box, 자르기 · 뒤집기) > 그림.
   마스크가 창에 고정이라, 바뀔 때 동물이 원 안에서 작게 시작해 커지면서 원 밖 오른쪽 창까지 차오른다. */
.pat-art {
  position: absolute; pointer-events: none;
  -webkit-mask-size: 100% 100%; mask-size: 100% 100%;
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
}
.pat-art__move { position: absolute; inset: 0; }
.pat-art__box { position: absolute; overflow: hidden; }
.pat-art__box--flip { transform: scaleX(-1); }
.pat-art__img { position: absolute; display: block; max-width: none; }
.pat-art__img--cover { inset: 0; width: 100%; height: 100%; object-fit: cover; }
/* 반짝이 가루 — 원 둘레보다 넓은 520 칸(원 가운데 기준), 그림 위 */
.pat-sparks {
  position: absolute; left: calc(-100 * var(--u)); top: calc(-100 * var(--u));
  width: calc(520 * var(--u)); height: calc(520 * var(--u));
  pointer-events: none;
}
/* 오른쪽 — Info Container 423 은 카드(490) 가운데(26-10-06 시안 — 전엔 왼쪽에 붙었다, 화면 x 600). 이름 목록이 남은 높이를 갖고 버튼은 아래(사이 10) */
.pat-card { flex: 1 1 0; min-width: 0; align-self: stretch; display: flex; align-items: center; justify-content: center; }
.pat-panel {
  position: relative; align-self: stretch;
  width: calc(423 * var(--u));
  display: flex; flex-direction: column; align-items: center;
  gap: calc(10 * var(--u));
}
#screen-patronus .house-status { top: calc(100% + 6 * var(--u)); bottom: auto; }
.pat-names {
  position: relative;                               /* 굴러 나가는 이름(.pat-name--ghost)의 기준 */
  touch-action: none; user-select: none; -webkit-user-select: none;   /* 위아래 끌기(app.js) — 화면이 같이 끌리지 않게 */
  flex: 1; min-height: 0; align-self: stretch;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: calc(24 * var(--u));
  padding: 0 calc(180 * var(--u));
}
/* 이름 — 가운데(고른 것) NEXON Medium 32 / 48 · 자간 0.5%, 한 칸 옆 Light 24 / 36 60%, 두 칸 옆 Light 22 / 33 20%.
   목록은 app.js 가 고른 것을 가운데(3번째)로 돌려 5개만 보인다(6종 중 반대편 하나는 숨김) — 시안 문구 배치와 같다. */
.pat-name {
  position: relative;
  margin: 0; padding: 0; border: 0; background: none;
  font-family: var(--font-primary); font-weight: 300;
  font-size: calc(22 * var(--u)); line-height: 1.5; letter-spacing: 0.005em;
  color: var(--color-white-100); opacity: 0.2;
  white-space: nowrap; cursor: pointer;
  transition: opacity 0.25s ease, font-size 0.25s ease;
}
.pat-name[data-dist="1"] { font-size: calc(24 * var(--u)); opacity: 0.6; }
.pat-name[data-dist="0"] { font-weight: 500; font-size: calc(32 * var(--u)); letter-spacing: 0.005em; opacity: 1; }   /* 가운데 = 고른 것(또는 초점) */
.pat-name[aria-checked="true"] { cursor: default; }
/* 브래킷 — 가운데 이름 왼쪽 70 에 붙는다(시안 Selected Patronus: [브래킷 31×16] 70 [이름]). 그림 63.5×40(번짐 자리 포함)을 좌우 뒤집어 쓴다.
   바깥 번짐은 시안 보라 #CFB8FB → 네이비 #7691FF(키 컬러 규칙), 안쪽 #BBD4FE 는 그대로. */
.pat-name:not(.pat-name--ghost)[data-dist="0"]::before {
  content: ""; position: absolute;
  right: calc(100% + 70 * var(--u)); top: calc(50% - 20.5 * var(--u));
  width: calc(63.5 * var(--u)); height: calc(40 * var(--u));
  background: url("assets/patronus/card-border.svg") center / 100% 100% no-repeat;
  transform: scaleX(-1);
  pointer-events: none;
}
/* 굴러 나가는 이름 — 고른 순간의 자리에 띄워 두고 app.js(rollPatronusNames)가 밀어내며 지운다 */
.pat-name--ghost { position: absolute; left: 0; right: 0; pointer-events: none; }
.pat-name:focus-visible { outline: none; box-shadow: var(--focus-ring); }
/* [선택하기] — 기숙사 선택 알약과 같은 틀. 26-10-06 Figma 4990:10567: 250×59(전 280) · 글자 #242425(전 #858587) ·
   별 무늬(#16557F 4%) 안쪽 테두리 기준 1 · -83 · 오른쪽 점 안쪽 테두리 기준 237.5(왼쪽 점 · 판 · 그림자 · 안쪽 테두리는 그대로).
   CSS 는 안쪽 테두리 선(0.5) 안쪽이 기준이라 0.5 씩 뺀다 */
.house-ok.pat-ok { flex: none; width: calc(250 * var(--u)); }   /* 아래 .house-ok(257.5)보다 뒤에 오지 않아 선택자를 올린다 */
.pat-ok .house-ok__label { color: #242425; }                     /* ⚠ 시안 원본값(비토큰) */
.pat-ok .house-ok__deco { left: calc(0.5 * var(--u)); top: calc(-83.5 * var(--u)); }
.pat-ok .house-ok__dot--r { left: calc(237 * var(--u)); }

/* ---------- 02-3 기숙사 선택 (s7 퀴디치 전용) — 26-09-30 Figma 4741:11541(고르기 전) · 4741:11340(고른 뒤), 1133×744 ----------
   숫자는 시안 px × --u. 틀: 위아래 48 > [헤더(뒤로 56 · 제목 데코 80 · 빈 56, 좌우 36) → 8 → 안내 한 줄]
   > 남은 높이: 폭 980 · 위 20 · 아래 40 안에 [카드 줄(가운데) → [선택하기] 257.5×59].
   카드는 Figma 컴포넌트 kioskHouseSelect(4610:27169, 원본 422×458)를 시안에서 줄여 쓴 것 — 안 고른 카드 0.524배, 고른 카드 0.5854배.
   그래서 카드 안 숫자는 컴포넌트 원본 값 × --hs(배율) × --u 로 적는다. 색은 기숙사마다(--house-key, app.js HOUSES). */
:is(#screen-house, #screen-nickname) { padding: 0; align-items: center; justify-content: center; }
.house-stage {
  position: relative;
  width: min(100%, calc(1440 * var(--u)));
  height: calc(744 * var(--u));
  padding: calc(48 * var(--u)) 0;
  display: flex; flex-direction: column; align-items: center;
}
.house-head { align-self: stretch; display: flex; flex-direction: column; align-items: center; gap: calc(8 * var(--u)); }
.house-head__bar {
  align-self: stretch;
  display: flex; align-items: center; justify-content: space-between;
  padding: 0 calc(36 * var(--u));
}
.house-head__bar .title-deco { flex: 1; justify-content: center; }
.house-head__empty { flex: none; width: calc(56 * var(--u)); height: calc(56 * var(--u)); }
/* 안내 — NEXON Regular 20 / 30 · 자간 1% · #EFF8FF(base/head1/R-20) */
.house-desc {
  margin: 0;
  font-size: calc(20 * var(--u)); line-height: 1.5; letter-spacing: 0.01em; font-weight: 400;
  color: #EFF8FF;                                                    /* ⚠ 시안 원본값(비토큰) */
  white-space: nowrap;
}
.house-body {
  flex: 1; min-height: 0;
  width: calc(980 * var(--u));
  padding: calc(20 * var(--u)) 0 calc(40 * var(--u));
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  position: relative;
}
.house-list { flex: 1; min-height: 0; align-self: stretch; display: flex; align-items: center; justify-content: center; }
/* 카드 줄 — 사이 12 · 위 맞춤. 안 고른 카드는 남은 폭을 나눠 갖고(고르기 전 236), 고른 카드만 260 고정 */
.house-grid {
  width: 100%;
  display: flex; align-items: flex-start;
  gap: calc(12 * var(--u));
}
/* 고를 때 · 바꿀 때 움직임(26-10-01) — 고른 카드는 커지면서 잠깐 한 번 더 부풀었다가(house-pop) 자리 잡고, 다른 카드를 고르면
   앞 카드는 원래 크기로 부드럽게 줄어든다. 크기는 전부 배율(--hs) · 문장 기준 크기(--crest-w/h) · 틀 여백 · 테두리 · 색(--house-key)
   변수에 묶여 있어, 이 변수들을 @property 로 등록해 카드에서 한꺼번에 전환한다(자식마다 width 전환을 걸면 매 프레임 다시 걸려 끊긴다).
   @property 를 모르는 브라우저에선 예전처럼 바로 바뀐다. */
@property --hs        { syntax: "<number>"; inherits: true; initial-value: 0.524; }
@property --crest-w   { syntax: "<number>"; inherits: true; initial-value: 294; }
@property --crest-h   { syntax: "<number>"; inherits: true; initial-value: 350.522; }
@property --frame-pad { syntax: "<number>"; inherits: true; initial-value: 6; }
@property --frame-bw  { syntax: "<number>"; inherits: true; initial-value: 0.524; }
@property --house-key { syntax: "<color>";  inherits: true; initial-value: #878787; }
:root { --house-ease: cubic-bezier(0.22, 1, 0.36, 1); --house-dur: 0.45s; }
.house-card {
  --hs: 0.524;                                   /* 컴포넌트 원본(422 폭) → 시안 크기 배율 */
  --house-key: #878787;                          /* 안 고른 카드 색(Select=Off, app.js HOUSE_OFF) — 고르면 app.js 가 기숙사 색으로 */
  --crest-w: 294; --crest-h: 350.522;            /* 문장 그림 기준 크기(× --hs) — 기숙사마다 아래 */
  --frame-pad: 6; --frame-bw: 0.524;             /* 틀 여백 · 테두리 */
  flex: 1 1 0; min-width: 0;
  height: calc(240 * var(--u));
  display: flex; flex-direction: column; justify-content: flex-end;
  padding: 0; border: 0; background: none; color: inherit; font: inherit;
  cursor: pointer;
  transition:
    --hs var(--house-dur) var(--house-ease), --crest-w var(--house-dur) var(--house-ease), --crest-h var(--house-dur) var(--house-ease),
    --frame-pad var(--house-dur) var(--house-ease), --frame-bw var(--house-dur) var(--house-ease), --house-key var(--house-dur) var(--house-ease),
    flex var(--house-dur) var(--house-ease), height var(--house-dur) var(--house-ease), opacity 0.25s ease;
}
.house-card__frame {
  flex: 1; min-height: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: flex-end;
  padding: calc(var(--frame-pad) * var(--u));
  border: calc(var(--frame-bw) * var(--u)) solid var(--house-key);
  transform-origin: 50% 100%;
}
/* 문장 그림 — 설명 판 위로 303 겹친다(아래 맞춤 · 가운데라 고른 카드에선 카드 위로 솟는다). 그림은 컴포넌트의 흰 벡터 그대로
   (assets/house/*-crest*.svg, 26-10-15). 크기는 기숙사 · 고름마다 컴포넌트 값 */
.house-card__crest {
  flex: none; display: block;
  width: calc(var(--crest-w) * var(--hs) * var(--u)); height: calc(var(--crest-h) * var(--hs) * var(--u));
  margin-bottom: calc(-303 * var(--hs) * var(--u));
  position: relative; z-index: 0;
  pointer-events: none;
}
.house-card[data-house="slytherin"]  { --crest-w: 252; --crest-h: 344; }
.house-card[data-house="hufflepuff"] { --crest-w: 294; --crest-h: 326.605; }
.house-card[data-house="ravenclaw"]  { --crest-w: 337; --crest-h: 349.252; }
/* 설명 판 — 위(6.166%)는 투명, 아래로 기숙사 색. 여백 좌우 37. 높이 381 × 배율 — 안 고른 카드에선 시안의 '남은 높이 채우기'(200.0)와
   0.4 차이라 같은 식으로 둬서 고를 때 함께 자라게 했다(내용은 아래 맞춤이라 고른 카드의 위 여백 205 는 보이는 차이가 없다). */
.house-card__panel {
  position: relative; z-index: 1;
  align-self: stretch;
  flex: none; height: calc(381 * var(--hs) * var(--u));
  display: flex; flex-direction: column; align-items: center; justify-content: flex-end;
  padding: 0 calc(37 * var(--hs) * var(--u));
  background: linear-gradient(180deg, color-mix(in srgb, var(--house-key) 0%, transparent) 6.166%, var(--house-key) 100%);
}
.house-card__info {
  width: calc(335.578 * var(--hs) * var(--u));
  padding: calc(20 * var(--hs) * var(--u)) 0;
  display: flex; flex-direction: column; align-items: center;
  gap: calc(20 * var(--hs) * var(--u));
}
/* 기숙사 이름 — Hahmlet SemiBold 33.548 · 행간 1.3 · 자간 -1% · 흰색, 대문자(시안) */
.house-card__name {
  align-self: stretch;
  font-family: var(--font-display); font-weight: 600;
  font-size: calc(33.548 * var(--hs) * var(--u)); line-height: 1.3; letter-spacing: -0.01em;
  color: var(--color-white-100); text-align: center; text-transform: uppercase;
}
/* 배지 줄 — 높이 72 · 폭 224 · 사이 24(그리핀도르만 22): [작은 원 배지 | 글자 원 | 작은 원 배지] */
.house-card__badges {
  width: calc(224 * var(--hs) * var(--u)); height: calc(72 * var(--hs) * var(--u));
  display: flex; align-items: center; justify-content: center;
  gap: calc(24 * var(--hs) * var(--u));
}
.house-card[data-house="gryffindor"] .house-card__badges { gap: calc(22 * var(--hs) * var(--u)); }
.house-card__badge {
  position: relative; flex: none;
  width: calc(54.515 * var(--hs) * var(--u)); height: calc(54.515 * var(--hs) * var(--u));
}
/* 배지 그림 — 컴포넌트의 테두리 · 그림 · 노이즈 링을 한 장으로 내려받은 60.749 SVG(assets/house/*-badge-l/r.svg).
   54.515 상자 왼쪽 위에서 -3.406 · -2.840 에 놓인다(시안 위치 그대로) */
.house-card__badge img {
  position: absolute; display: block;
  left: calc(-3.40634 * var(--hs) * var(--u)); top: calc(-2.83986 * var(--hs) * var(--u));
  width: calc(60.7488 * var(--hs) * var(--u)); height: calc(60.7488 * var(--hs) * var(--u));
  pointer-events: none;
}
/* 가운데 글자 원 — 71.289 상자, 그림(테두리 · 링 · 글자 SVG)은 상자 밖으로 조금 넘친다(시안 inset) */
.house-card__letter { position: relative; flex: none; width: calc(71.289 * var(--hs) * var(--u)); height: calc(71.289 * var(--hs) * var(--u)); }
.house-card__letter img { position: absolute; top: -10.01%; left: -11.13%; width: 119.86%; height: 119.86%; }   /* 시안 inset -10.01 · -8.73 · -9.85 · -11.13 % */
/* 고른 카드(Select=On) — 260 × 239 고정, 테두리 · 판이 기숙사 색. 배율 0.5854, 여백 3.512, 테두리 0.585, 판 높이 381 */
.house-card[aria-checked="true"] {
  --hs: 0.5854;
  --crest-w: 328; --crest-h: 391.059;
  --frame-pad: 3.512; --frame-bw: 0.585;
  flex: 0 0 calc(260 * var(--u));
  height: calc(239 * var(--u));
}
.house-card[data-house="slytherin"][aria-checked="true"]  { --crest-w: 268; --crest-h: 367; }
.house-card[data-house="hufflepuff"][aria-checked="true"] { --crest-w: 336; --crest-h: 373.263; }
.house-card[data-house="ravenclaw"][aria-checked="true"]  { --crest-w: 358.001; --crest-h: 371.015; }
/* 고르는 순간 잠깐 4% 더 부풀었다 돌아온다(아래 가운데 기준 — 문장은 위로 솟는다) */
.house-card[aria-checked="true"] .house-card__frame { animation: house-pop 0.5s ease-out; }
@keyframes house-pop {
  0%   { transform: scale(1); }
  40%  { transform: scale(1.04); }
  100% { transform: scale(1); }
}
/* 하나를 고르면 나머지는 32% */
.house-grid[data-picked="true"] .house-card:not([aria-checked="true"]) { opacity: 0.32; }
.house-card:focus-visible { outline: none; box-shadow: var(--focus-ring); }

/* [선택하기] — Figma 4741:11359: 257.5×59 · 여백 4 · 흰 → #E8FFFF(아래→위) · 그림자 0 2 2 #565150 · 둥근 알약.
   안쪽 테두리 0.5 #858587 · 글자 NEXON Medium 22 / 33 · 자간 0.5% · #858587. 양끝에 작은 점(#F4FFFF 판 · #858587 점),
   가운데 별 무늬(#16557F 4%)는 알약 밖으로 넘쳐 잘린다. 고르기 전엔 투명(자리는 그대로 — 시안 opacity 0). */
.house-ok {
  position: relative; flex: none;
  width: calc(257.5 * var(--u)); height: calc(59 * var(--u));
  padding: calc(4 * var(--u));
  display: flex; align-items: center; justify-content: center;
  border: 0; border-radius: var(--radius-full);
  background: linear-gradient(0deg, #FFFFFF 0%, #E8FFFF 100%);          /* ⚠ 시안 원본값(비토큰) */
  box-shadow: 0 calc(2 * var(--u)) calc(2 * var(--u)) 0 #565150;
  overflow: hidden;
  cursor: pointer;
  transition: opacity 0.25s ease;
}
.house-ok:disabled { opacity: 0; pointer-events: none; }
.house-ok:active { transform: scale(0.97); }
.house-ok__inner {
  position: relative; flex: 1; align-self: stretch;
  display: flex; align-items: center; justify-content: center;
  gap: calc(5 * var(--u));
  border: calc(0.5 * var(--u)) solid #858587;
  border-radius: var(--radius-full);
}
.house-ok__label {
  font-family: var(--font-primary); font-weight: 500;
  font-size: calc(22 * var(--u)); line-height: 1.5; letter-spacing: 0.005em;
  color: #858587;                                                     /* ⚠ 시안 원본값(비토큰) */
  white-space: nowrap;
}
.house-ok__deco {
  position: absolute; left: calc(15.5 * var(--u)); top: calc(-83.5 * var(--u));
  width: calc(217 * var(--u)); height: calc(217 * var(--u));
  pointer-events: none;
}
.house-ok__dot {
  position: absolute;
  display: flex; align-items: center;
  padding: calc(2 * var(--u));
  border-radius: var(--radius-full);
  background: #F4FFFF;
}
.house-ok__dot span { width: calc(4 * var(--u)); height: calc(4 * var(--u)); border-radius: 50%; background: #858587; }
.house-ok__dot--r { left: calc(245 * var(--u)); top: 50%; transform: translateY(-50%); }   /* 안쪽 테두리 기준 */
.house-ok__dot--l { left: 0; top: calc(25.5 * var(--u)); }                                 /* 알약 기준 */
/* 저장 실패 안내 — 버튼 아래(시안에 없는 상태라 판 없이 한 줄) */
.house-status {
  position: absolute; left: 0; right: 0; bottom: calc(8 * var(--u));
  margin: 0; text-align: center;
  font-size: calc(16 * var(--u)); color: var(--func-error);
}

/* ---------- 04 알림 화면 (소진 4172:36544 · 체험 중인 QR — 26-09-29, 사전 테스트 미완료 4180:36996 은 걷어냄) ----------
   두 화면은 디자인시스템 공통 팝업(.popup — components.css)을 그대로 쓴다. 26-09-28 이 알림 판(NoticePanel)이
   공통 Popup 으로 올라가면서 .notice-* 규칙과 전용 명판 에셋은 원본(design-system/assets/popup/)으로 옮겼다.
   크기는 공통 팝업이 이 앱의 --u 를 그대로 쓴다. */
/* 소진 문구의 횟수 강조(Bold + 네이비)는 공통 Popup 의 .popup__em 이다(renderLimitBody). */


/* ===== 그림 시작 화면 — 콘텐츠별 새 시안(26-10-02 ~): 물약 4734:9970 · 4890:32575 / 퀴디치 4901:33547 · 4901:33597 /
   패트로누스 4990:9846 · 4990:9968 · 4990:10015(26-10-06), 1133×744 =====
   틀은 위 "시작 화면"(26-09-30 홈 6종)과 같고, 새 시안이 온 콘텐츠만 body[data-home-art] 로 덮는다(app.js applySection — MISSION_ART 에
   타이틀 그림이 있는 콘텐츠). 26-10-06 패트로누스까지 와서 이제 세 콘텐츠 모두 이 틀이다.
   같은 것: 헤더 로고 투명(시안 opacity 0 — 자리는 남김) · 스테이지 아래 여백 60(공통 48) · 글자 대신 로고 그림 타이틀 ·
            서브텍스트 블록 620(아래 여백 0 — 상자 77 = 헤어라인 4 + 40 + 문구 33, 헤어라인 #FFF8EC 15% → 50% → 85%) ·
            그림 버튼 360×87 · 공통 시작 배경(.bg-start) · 바닥 빛 · 입자는 끈다(시안에 없다).
            다른 사람이 체험 중이면 버튼 대신 대기 배지(위 "대기 배지" — 26-10-06 완드와 같은 배지로 통일, 시안의 대기 버튼 · 칩은 따르지 않음).
   콘텐츠마다 다른 값은 변수(아래 [data-mission=…]):
     --art-title-w · -h · -gap  로고 상자와 두 장 사이      --art-gap  로고 → 서브텍스트      --art-content-gap  묶음 → 버튼      --art-stage-pb  스테이지 아래 여백(기본 60)
     --art-spark-edge  마름모 위 밝은 테두리      --art-sub-glow  서브텍스트 라디얼(위 가운데 · 가로 172 · 세로 69.705)
     --art-sub-line  서브텍스트 윗선 색(r, g, b — 15% → 50% → 85% 로 번진다)
     --art-cta-text  버튼 글자 그라디언트      --art-cta-breathe  숨쉬기 색(r, g, b)
   배경만 body(화면 · 콘텐츠) 기준이고, 나머지는 [data-home-art][data-mission] 아래면 어디든 걸린다 — DS 프리뷰가 같은 규칙으로 견본을 그린다. */
[data-mission="potion"] {
  --art-title-w: 467; --art-title-h: 220; --art-title-gap: 0;    /* 26-10-12 새 로고 한 장 POTION CLASS 467×220(Figma 5415:2600 LOGO_포션클래스 — 보정 없음, 원본 1948×916 을 시안 FILL 대로 잘라 둔 그림) */
  --art-gap: 40; --art-content-gap: 70;
  --art-stage-pb: 80;                                              /* 스테이지 아래 여백 — 26-10-12 물약 · 퀴디치 시안 80(Sub Header 560, 패트로누스는 60) */
  --art-spark-edge: #E4DDD2;                                                                                   /* ⚠ 시안 원본값 */
  --art-sub-glow: radial-gradient(27.74% 90.53% at 50% 0%, rgba(38, 32, 32, 1) 0%, rgba(38, 32, 32, 0) 100%);   /* ⚠ 시안 원본값 */
  --art-cta-text: linear-gradient(90deg, #9FEE9C 32.148%, #14E30E 69.969%);                                     /* ⚠ 시안 원본값 */
  --art-cta-breathe: 20, 227, 14;
  --art-count-em: #EDBD54;                                                                                     /* ⚠ 시안 원본값 — 결과 남은 초 */
}
[data-mission="quidditch"] {
  --art-title-w: 569; --art-title-h: 212; --art-title-gap: 0;    /* 26-10-12 새 로고 QUIDDITCH / GAME 두 줄 569×212(Figma 5415:2631 — 전 714×100 한 줄, 26-10-08 THE 지움) */
  --art-gap: 20; --art-content-gap: 70;                           /* 26-10-12 시안 묶음 → 버튼 70(전 80) */
  --art-stage-pb: 80;                                              /* 스테이지 아래 여백 — 26-10-12 시안 Sub Header 560(물약과 같다) */
  --art-spark-edge: #E4DDD2;                                                                                   /* ⚠ 시안 원본값 */
  --art-sub-glow: radial-gradient(27.74% 90.53% at 50% 0%, rgba(91, 101, 67, 1) 0%, rgba(36, 38, 32, 0) 100%);  /* ⚠ 시안 원본값 */
  --art-cta-text: linear-gradient(90deg, #E1C7FC 32.148%, #B771FD 69.969%);                                     /* ⚠ 시안 원본값(보라 — 콘텐츠 색) */
  --art-cta-breathe: 121, 14, 227;
  --art-count-em: #7D54ED;                                                                                     /* ⚠ 시안 원본값 — 결과 남은 초(4982:8944) */
}
/* 패트로누스 — 26-10-06 Figma 4990:9846: 틀은 퀴디치와 같고 그림 · 색만 파랑(마름모 #10141D → #343E4D · 반짝이 #CDE2FD · 윗선 #ECF4FF) */
[data-mission="patronus"] {
  --art-title-w: 561; --art-title-h: 167; --art-title-gap: 12;   /* MEET YOUR 525×52 → 12 → PATRONUS 561×103(26-10-08 새 로고 — 전 THE 120×50 → 14 → FORBIDDEN FOREST 750×88) */
  --art-gap: 35; --art-content-gap: 80;                            /* 묶음 → 버튼 80(26-10-08 시안 — 전 70) */
  --art-spark-edge: #D2DAE4;                                                                                   /* ⚠ 시안 원본값 */
  --art-sub-glow: radial-gradient(27.74% 90.53% at 50% 0%, rgba(67, 82, 101, 1) 0%, rgba(32, 35, 38, 0) 100%);  /* ⚠ 시안 원본값 */
  --art-sub-line: 236, 244, 255;                                                                               /* ⚠ 시안 원본값 #ECF4FF */
  --art-cta-text: linear-gradient(90deg, #C7DEFC 32.148%, #71ADFD 69.969%);                                     /* ⚠ 시안 원본값(파랑 — 콘텐츠 색) */
  --art-cta-breathe: 39, 138, 243;                                                                             /* 버튼 면 그림의 진한 파랑 #278AF3 */
  --art-count-em: #A3AFFC;                                                                                     /* ⚠ 시안 원본값 — 결과 남은 초(4990:10745) */
}

/* 배경 — 물약: 아치 그림(image 726 — 26-10-12 새 그림: 안쪽 선반이 흐린 아치 · 아래 솥, 프레임 기준 -20, -408 · 1174×1408) + 초록 라디얼
   (Figma 시작 5415:3555 · 5415:3519 · 결과 5415:3647 — 전 그림은 양옆 물약병 선반 아치, -90 · -187 · 1314×1578)
   반응형(26-10-13 — 갤럭시 탭 16:10 에서 양옆이 비던 것): 그림이 프레임보다 양옆 20 씩만 넓어서, 시안보다 가로로 넓은 화면(1280×728 등)에서
   --u(프레임이 화면에 들어가는 배율)로만 키우면 양옆에 빈 띠가 생겼다(1280×728 에서 66 씩). 그래서 그림만 따로 --pu 배율을 쓴다 —
   --u 와 같되, 상자가 화면을 다 덮는 데 모자라면 그만큼 더 키운다(프레임 가운데 기준 · 가로 100vw/1173 · 세로 100vh/1256). 시안 비율(1133×744)이나
   그보다 세로로 긴 화면에선 --u 그대로라 시안과 같다. 글자 · 버튼 · 움직임(.art-fx)은 --u 그대로 */
.bg-potion-home {
  --pu: max(var(--u), 100vw / 1173, 100vh / 1256);
  position: absolute;
  left: calc(50% - 586.5 * var(--pu)); top: calc(50% - 780 * var(--pu));   /* 화면 가운데 프레임(1133×744) 기준 -20 · -408 */
  width: calc(1174 * var(--pu)); height: calc(1408 * var(--pu));
  opacity: 0;
  transition: opacity 0.8s ease;
}
/* 그림 — 시안 채움(FILL: 원본 2000×2800 을 상자에 cover — 위아래 7.17% 씩 넘침)만 잘라 둔 파일(1600×1919)이라 상자에 그대로 채운다 */
.bg-potion-home img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: fill; display: block; }
/* 라디얼 — 상자 기준 가운데 (595.28, 1072.5) · 가로 반지름 1570.6 · 세로 689. 26-10-13 시안 색 수정(5415:3519 · 3555 · 3647): 가운데 #BAAD84 60%(전 초록 #0E5A0C 60%) ·
   가로 반지름 1570.6(전 1090.3 — 26-10-12 새 그림 땐 666.27 · 1003.8 · 1209.4 × 765.31), 나머지 정지점(#0B1D0C 40% · #201D0E 55% · #211D12 80%)은 그대로.
   26-10-12 시안부터 결과 화면도 이 라디얼 그대로(전엔 가운데 80%). 그림과 같이 --pu 로 키운다(그림에 붙어 있어야 해서) */
.bg-potion-home::after {
  content: ""; position: absolute; inset: 0;
  background: radial-gradient(calc(1570.6 * var(--pu)) calc(689 * var(--pu)) at calc(595.28 * var(--pu)) calc(1072.5 * var(--pu)),
    rgba(186, 173, 132, 0.6) 0%, rgba(11, 29, 12, 0.4) 48.799%, rgba(32, 29, 14, 0.55) 70.084%, rgba(33, 29, 18, 0.8) 100%);   /* ⚠ 시안 원본값 */
}
body[data-mission="potion"][data-screen="home"] .bg-potion-home { opacity: 1; }
/* 배경 — 퀴디치: 경기장 사진(시안 채움 CROP 원본 843×1150 의 위 26.33% ~ 74.46% 를 잘라 둔 파일) + 아래 가운데 라디얼(가로 반지름 2150.2 · 세로 744,
   가운데는 프레임 가운데보다 8 오른쪽), 그림 전체를 흐림 2(시안 레이어 블러 — CSS 는 절반). 프레임 크기 그림이라 화면을 덮도록 cover,
   흐림이 가장자리를 비우지 않게 4 바깥까지 */
.bg-quidditch-home {
  position: absolute; inset: calc(-4 * var(--u));
  filter: blur(calc(1 * var(--u)));
  opacity: 0;
  transition: opacity 0.8s ease;
}
.bg-quidditch-home img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
.bg-quidditch-home::after {
  content: ""; position: absolute; inset: calc(4 * var(--u));
  background: radial-gradient(calc(2150.2 * var(--u)) calc(744 * var(--u)) at calc(50% + 7.99 * var(--u)) 100%,
    rgba(89, 139, 8, 0.6) 0%, rgba(25, 39, 12, 0.6) 35.27%, rgba(3, 16, 17, 0.85) 70.084%, rgba(14, 6, 23, 1) 100%);   /* ⚠ 시안 원본값 */
}
body[data-mission="quidditch"][data-screen="home"] .bg-quidditch-home { opacity: 1; }
/* 배경 — 패트로누스: 밤 숲 · 수사슴 패트로누스 그림 + 왼쪽 아래 파란 라디얼,
   그림은 26-10-07 새 그림(시안 채움 CROP: 원본 1915×821 의 왼쪽 12.08% 부터 폭 65.29% 를 잘라 둔 파일 — 시안엔 옛 그림 채움이 밑에 남아 있지만 새 그림이 불투명하게 덮는다).
   그림 전체 흐림 2(CSS 절반 — 퀴디치와 같다). 라디얼은 살짝 돌아간 타원이라(시안 gradientTransform) 돌린 상자에 그린다:
   가운데 = 프레임 왼쪽 밖 61 · 맨 아래(프레임 가운데보다 627.5 왼쪽), 반지름 1916.73(가로축) × 2229.29(세로축), 시계 방향 5.148°.
   상자는 반지름 큰 쪽 × 2 정사각형 — 돌려도 화면을 다 덮고, 넘친 곳은 overflow 로 자른다 */
.bg-patronus-home {
  position: absolute; inset: calc(-4 * var(--u));
  overflow: hidden;
  filter: blur(calc(1 * var(--u)));
  opacity: 0;
  transition: opacity 0.8s ease;
}
.bg-patronus-home img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
.bg-patronus-home::after {
  content: ""; position: absolute;
  left: calc(50% - (627.5 + 2229.29) * var(--u)); top: calc(100% - (4 + 2229.29) * var(--u));
  width: calc(4458.58 * var(--u)); height: calc(4458.58 * var(--u));
  transform: rotate(5.148deg);
  /* ⚠ 시안 원본값(#5A9CF1 0% → #061528 60% 35.27% → #030A11 85% 70.084% → #060D17 100%). 첫 구간은 불투명 → 60% 라
     CSS(미리 곱한 알파로 섞음)로는 Figma(그대로 섞음)보다 밝아진다 — Figma 가 CSS 용으로 내주는 중간 단계 넷을 그대로 넣었다.
     26-10-07 새 그림과 함께 색이 바뀜: #74A9ED → #5A9CF1, 35.27% #0C1727 → #061528(둘 다 60%) — 자리 · 크기 · 기울기는 그대로 */
  background: radial-gradient(calc(1916.73 * var(--u)) calc(2229.29 * var(--u)) at 50% 50%,
    rgba(90, 156, 241, 1) 0%, rgba(69, 122, 191, 0.9) 8.8175%, rgba(48, 89, 141, 0.8) 17.635%, rgba(27, 55, 90, 0.7) 26.452%,
    rgba(16, 38, 65, 0.65) 30.861%, rgba(6, 21, 40, 0.6) 35.27%, rgba(3, 10, 17, 0.85) 70.084%, rgba(6, 13, 23, 1) 100%);
}
body[data-mission="patronus"][data-screen="home"] .bg-patronus-home { opacity: 1; }
body[data-home-art][data-screen="home"] :is(.bg-start, .bg-home-glow) { opacity: 0; }
body[data-home-art][data-screen="home"] .home-fx { display: none; }

[data-home-art] #screen-home .start-logo { opacity: 0; }
[data-home-art] .home-stage { padding-bottom: calc(var(--art-stage-pb, 60) * var(--u)); }   /* 콘텐츠별 --art-stage-pb(물약 · 퀴디치 80), 없으면 60 */
[data-home-art] .home-content { gap: calc(var(--art-content-gap) * var(--u)); }
[data-home-art] .home-title-block { align-items: center; gap: calc(var(--art-gap) * var(--u)); }
[data-home-art] #screen-home .start-title {
  width: calc(var(--art-title-w) * var(--u)); height: calc(var(--art-title-h) * var(--u));
  justify-content: flex-start;
  gap: calc(var(--art-title-gap) * var(--u));
}
/* 타이틀 그림(app.js MISSION_ART) — 크기는 시안 px(--art-w · --art-h) × --u. 파일은 상자 비율 그대로 뽑아 늘이지 않는다 */
#screen-home .start-title__art {
  display: block; flex: none;
  width: calc(var(--art-w) * var(--u)); height: calc(var(--art-h) * var(--u));
  object-fit: fill;
}
/* 타이틀 금빛 가루(26-10-22 — 완드 대기 화면 #275 · 기숙사 배정 키오스크 DS .ds-logo-fx 와 같은 짜임, app.js "시작 화면 금빛 가루").
   줄 상자(.start-title__line) 둘에 magic-dust.js 가 흐림 · 투명도를 준다. 한 장에 두 줄인 그림(물약 · 퀴디치)은 같은 그림을 두 상자에 겹쳐
   --split(그림 높이 % — app.js MISSION_ART, 두 줄 사이 투명한 곳)에서 위 · 아래로 자른다: 위 상자가 자리를 잡고 아래 상자는 그 위에 겹친다.
   줄마다 그림인 로고(패트로누스)는 그림 하나가 한 줄 상자라 자르지 않는다.
   가루 캔버스는 타이틀 상자보다 사방 147(house 140px 을 1133 화면으로) 넓다 — 가루가 그림 밖으로 날아갈 여유. */
[data-home-art] #screen-home .start-title { position: relative; }
#screen-home .start-title__line { position: relative; display: block; flex: none; }
#screen-home .start-title__line--bottom { position: absolute; inset: 0; }
#screen-home .start-title__line--top .start-title__art { clip-path: inset(0 0 calc(100% - var(--split) * 1%) 0); }
#screen-home .start-title__line--bottom .start-title__art { clip-path: inset(calc(var(--split) * 1%) 0 0 0); }
#screen-home .start-title__dust {
  position: absolute; left: calc(-147 * var(--u)); top: calc(-147 * var(--u));
  width: calc(100% + 294 * var(--u)); height: calc(100% + 294 * var(--u));
  pointer-events: none;
}
/* 가끔 반짝 — 완드 .start-logo-fx__glint(house .ds-logo-fx__glint)와 같은 별빛(가는 십자 + 둥근 빛) · 같은 움직임(3.6초마다, 1.2초 뒤 시작).
   자리(left · top — 그림 기준 %)와 크기(--glint — house 72px(로고 967)을 그림 폭 비율로)는 app.js MISSION_ART.title[].glint.
   줄 상자 안이라 그 줄과 함께 흐려진다. 아래 값은 완드 48 기준 그대로이고 --gu 로 이 크기에 맞춘다 */
#screen-home .start-title__glint {
  --gu: calc(var(--glint) / 48 * var(--u));
  position: absolute;
  width: calc(48 * var(--gu)); height: calc(48 * var(--gu)); margin: calc(-24 * var(--gu)) 0 0 calc(-24 * var(--gu));
  pointer-events: none;
  background:
    radial-gradient(circle, rgba(255, 252, 240, 0.95) 0 calc(1.3 * var(--gu)), rgba(255, 226, 160, 0.5) calc(3.3 * var(--gu)), rgba(255, 211, 114, 0) calc(10.7 * var(--gu))),
    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(--gu)) calc(1.4 * var(--gu)) 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(--gu)) calc(48 * var(--gu)) no-repeat;
  mix-blend-mode: screen; opacity: 0;
  animation: start-title-glint 3.6s ease-in-out 1.2s infinite;
}
@keyframes start-title-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); }
}
/* [시작하기] 뒤 사라지기(26-10-22) — 완드 #screen-start.is-sweeping(house app.css .screen-layer--leaving)과 같은 마스크: --sweep(%)을 magic-dust.js 가
   매 프레임 올려 시작 화면을 아래부터 지운다(흐려지는 폭 16%). 가루는 화면 전체를 덮는 캔버스에(.magic-exit, 누름은 통과) */
#screen-home.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; }
/* 서브텍스트 블록 — 마름모 그림(면 · 반짝이)은 app.js MISSION_ART.spark, 위 테두리 · 라디얼은 변수. 문구는 공통과 같다(NEXON Regular 22 #EFF8FF). */
[data-home-art] #screen-home .start-sub { width: calc(620 * var(--u)); }
[data-home-art] #screen-home .start-sub__spark { filter: drop-shadow(0 calc(-2 * var(--u)) 0 var(--art-spark-edge)); }
[data-home-art] #screen-home .start-sub__body {
  padding-bottom: 0;
  background: var(--art-sub-glow);
}
[data-home-art] #screen-home .start-sub__body::before {
  background: linear-gradient(90deg,
    rgba(var(--art-sub-line, 255, 248, 236), 0) 15%, rgba(var(--art-sub-line, 255, 248, 236), 1) 50%, rgba(var(--art-sub-line, 255, 248, 236), 0) 85%);   /* ⚠ 시안 원본값 — 물약 · 퀴디치 #FFF8EC */
}
/* 그림 버튼 — 시안 Start Button 360×87(완드 금색 [시작하기] 4864:9401 과 같은 틀 · 색만 콘텐츠 색). 공통 QuestButton 의 면 · 테두리 · 코너는 끈다.
     .start-cta__art   틀 그대로 · 넘침 자름
       __face  Vector(353.4×86, 틀 기준 2.85, 1) 그림 그대로(콘텐츠 색 — app.js MISSION_ART.cta)
       __glow  Button Border(Stroke) 그림 그대로(374.766×100.766 — 틀 기준 -0.5, 0.852 에 흐림 여백 7.383)
     글자  NEXON Medium 32 · 행간 1.5 · 자간 0.16, 콘텐츠 색 그라디언트(왼→오 32.148% → 69.969%). 상자 343.723 · 위 21 · 가운데보다 0.36 오른쪽
     그림자 Shadow/lg(0 4 12 — drop-shadow 는 반경 절반)
   숨쉬기(::before — 면 상자에)는 공통 네이비 대신 콘텐츠 색으로: 완드 금색 버튼(cta-breathe-gold)과 같은 앱 움직임(시안엔 정지 화면만 있다). */
.start-cta__art { display: none; }
[data-home-art] .start-cta.dcta--stage {
  left: 0;
  width: calc(360 * var(--u)); height: calc(87 * var(--u));
  margin: 0; padding: 0;
  border: 0; background: none;
  animation: none;
  filter: drop-shadow(0 calc(4 * var(--u)) calc(6 * var(--u)) rgba(0, 0, 0, 0.16));
}
[data-home-art] .start-cta.dcta--stage::after,
[data-home-art] .start-cta.dcta--stage .dcta__corner { display: none; }
[data-home-art] .start-cta.dcta--stage::before {
  inset: auto; left: calc(2.85 * var(--u)); top: calc(1 * var(--u));
  width: calc(353.4 * var(--u)); height: calc(86 * var(--u));
  border: 0; filter: none;
  animation: cta-breathe-art 2.8s ease-in-out infinite;
}
@keyframes cta-breathe-art {
  0%, 100% { box-shadow: 0 0 calc(10 * var(--u)) rgba(var(--art-cta-breathe), 0.2); }
  50%      { box-shadow: 0 0 calc(44 * var(--u)) rgba(var(--art-cta-breathe), 0.45); }
}
[data-home-art] .start-cta.dcta--stage .start-cta__art { display: block; position: absolute; inset: 0; overflow: hidden; }
.start-cta__face {
  position: absolute; left: calc(2.85 * var(--u)); top: calc(1 * var(--u));
  width: calc(353.4 * var(--u)); height: calc(86 * var(--u));
  display: block;
}
.start-cta__glow {
  position: absolute; left: calc(-7.883 * var(--u)); top: calc(-6.531 * var(--u));
  width: calc(374.766 * var(--u)); height: calc(100.766 * var(--u));
  display: block;
}
[data-home-art] .start-cta.dcta--stage .dcta__label {
  position: absolute; left: calc(50% + 0.36 * var(--u)); top: calc(21 * var(--u));
  width: calc(343.723 * var(--u));
  transform: translateX(-50%);
  font-size: calc(32 * var(--u)); line-height: 1.5; letter-spacing: calc(0.16 * var(--u));
  text-align: center; white-space: nowrap;
  background: var(--art-cta-text);
  -webkit-background-clip: text; background-clip: text;
  color: transparent;
}
/* 퀴디치 — 26-10-06 색 수정(4901:33547 · 4901:33597): 서브텍스트 #F3EFFF(라벤더 흰색, 물약은 #EFF8FF 그대로). */
[data-mission="quidditch"] #screen-home .start-desc { color: #F3EFFF; }                 /* ⚠ 시안 원본값(비토큰) */
/* 패트로누스 — 26-10-06 Figma 4990:9846: 서브텍스트 #EFF6FF(공통 #EFF8FF 보다 살짝 파랑). */
[data-mission="patronus"] #screen-home .start-desc { color: #EFF6FF; }                  /* ⚠ 시안 원본값(비토큰) */

/* ===== 그림 시작 화면 움직임 — 26-10-06 다원님 요청 "배경에 맞는 미니멀한 애니메이션"(시안엔 정지 화면만 있다) =====
   배경 위 · 화면 글자 아래(.bg-layer 안 .art-fx)에 콘텐츠마다 두세 가지만, 느리고 옅게. transform · opacity 만 움직인다.
   자리는 화면 %(배경 그림이 화면을 cover 로 덮어 % 가 그림 자리와 거의 같다), 크기는 --u. 알갱이마다 자리 · 때는 index.html 의 style 변수.
   시작 화면에서만 보이고(배경처럼 0.8초에 걸쳐 나타남) 다른 화면에선 멈춘다. 동작 줄이기 설정이면 멈추고 알갱이 · 스니치는 숨긴다(맨 아래).
     물약 — 아치 아래 초록 빛이 6초에 한 번 숨쉬고(#14E30E — 버튼 숨쉬기와 같은 색), 가운데 조리대에서 초록 빛 줄기가 뱅글뱅글 돌며 올라간다(26-10-06, 캔버스 — app.js).
     퀴디치 — 배경이 26초에 걸쳐 4% 다가왔다 물러나고(빗자루로 떠 있는 느낌), 왼쪽 위 구석에서 스니치가 그림 속 꼬리 궤도를 따라 날며 꼬리를 그리고, 멈추지 않고 오른쪽 위로 날아올라 사라진다(26-10-07 Figma 5092:9631 — 6초 한 바퀴).
     패트로누스 — 수사슴 둘레 빛이 5초에 한 번 숨쉬고, 은청색 알갱이가 수사슴 둘레(왼쪽)와 맞은편(오른쪽, 26-10-06 균형)에서 떠오르며, 숲 바닥 안개가 천천히 흐른다. */
.art-fx {
  position: absolute; inset: 0; overflow: hidden; pointer-events: none;
  opacity: 0; visibility: hidden;
  transition: opacity 0.8s ease, visibility 0s linear 0.8s;
}
.art-fx * { animation-play-state: paused; }
body[data-mission="potion"][data-screen="home"] .art-fx--potion,
body[data-mission="quidditch"][data-screen="home"] .art-fx--quidditch,
body[data-mission="patronus"][data-screen="home"] .art-fx--patronus { opacity: 1; visibility: visible; transition: opacity 0.8s ease; }
body[data-mission="potion"][data-screen="home"] .art-fx--potion *,
body[data-mission="quidditch"][data-screen="home"] .art-fx--quidditch *,
body[data-mission="patronus"][data-screen="home"] .art-fx--patronus * { animation-play-state: running; }

/* 빛 숨쉬기 — 둥근 빛이 옅어졌다 짙어진다 */
.art-fx__glow { position: absolute; border-radius: 50%; animation: art-glow-breathe 6s ease-in-out infinite; }
@keyframes art-glow-breathe { 0%, 100% { opacity: 0.5; } 50% { opacity: 1; } }
.art-fx--potion .art-fx__glow {
  left: 50%; bottom: calc(-170 * var(--u));
  width: calc(640 * var(--u)); height: calc(360 * var(--u));
  transform: translateX(-50%);
  background: radial-gradient(closest-side, rgba(20, 227, 14, 0.2), rgba(20, 227, 14, 0));
}
.art-fx--patronus .art-fx__glow {
  left: 19%; top: 70%;
  width: calc(440 * var(--u)); height: calc(440 * var(--u));
  transform: translate(-50%, -50%);
  background: radial-gradient(closest-side, rgba(170, 210, 255, 0.26), rgba(170, 210, 255, 0));
  animation-duration: 5s;
}

/* 떠오르는 알갱이 — --x 자리에서 --rise 만큼 오르며 --sway 만큼 옆으로, 처음 · 끝은 투명 */
.art-fx__mote {
  position: absolute; left: var(--x); bottom: 0;
  width: calc(4 * var(--u)); height: calc(4 * var(--u));
  border-radius: 50%;
  opacity: 0;
  animation: art-mote-rise var(--t, 10s) ease-out var(--d, 0s) infinite;
}
@keyframes art-mote-rise {
  0%   { transform: translate(0, 0) scale(0.5); opacity: 0; }
  15%  { opacity: 0.85; }
  60%  { opacity: 0.55; }
  100% { transform: translate(calc(var(--sway, 0) * var(--u)), calc(var(--rise, 240) * var(--u) * -1)) scale(1); opacity: 0; }
}
/* 물약 소용돌이 — 화면 전체 캔버스(app.js "물약 소용돌이"가 그린다). 26-10-06 김 알갱이(CSS) → 뱅글뱅글 오르는 빛 줄기(다원님 참고 그림) */
.art-fx__swirl { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.art-fx--patronus .art-fx__mote {
  bottom: 10%;
  width: calc(3.5 * var(--u)); height: calc(3.5 * var(--u));
  background: #E4EFFF; box-shadow: 0 0 calc(9 * var(--u)) calc(2 * var(--u)) rgba(150, 200, 255, 0.55);
}

/* 숲 바닥 안개 — 넓고 흐린 타원이 30초에 걸쳐 오른쪽으로 갔다 돌아온다 */
.art-fx__mist {
  position: absolute; left: -25%; bottom: -8%;
  width: 90%; height: 30%;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(150, 190, 255, 0.12), rgba(150, 190, 255, 0));
  animation: art-mist-drift 30s ease-in-out infinite alternate;
}
@keyframes art-mist-drift { from { transform: translateX(0); } to { transform: translateX(45%); } }

/* 퀴디치 배경 다가옴 — 그림 · 라디얼 · 흐림 한 판을 통째로(합성 층 하나라 가볍다). 결과 화면도 같은 배경이라 같이 움직인다 */
body[data-mission="quidditch"] .bg-quidditch-home {
  will-change: transform;
  animation: art-push-in 26s ease-in-out infinite alternate;
}
@keyframes art-push-in { from { transform: scale(1); } to { transform: scale(1.04); } }

/* 금빛 스니치 — 26-10-07 Figma 퀴디치 시작 화면 4901:33547 background > Mask group(5092:9648) "Snitch 1"(5092:9631)로 바꿈(전: SNITCH02 가 대각선으로 오가던 것).
   그림(원본 4096×1832 — 꼬리 궤도 끝에 스니치)을 머리 · 꼬리로 나눠, 머리가 그림 속 꼬리의 가운데 선을 따라 날며 꼬리를 그려 간다. 꼬리 끝(시안 모습)에서
   멈추지 않고 오른쪽 위로 날아올라 화면 위로 사라지고 꼬리도 옅어진다(26-10-07 다원님 — 길을 위로 늘림).
   움직임 · 마스크는 index.html 의 SVG(SMIL — 원본 px 좌표라 크기가 같이 따라간다)가 하고, 여기선 자리만: 시안 프레임 -96 · 56 에 442×197(원본을 FILL —
   가로 기준 0.10791 배, 세로는 위아래 0.35 넘침). 넘치는 날개 · 꼬리가 잘리지 않게 overflow visible. 시작 화면이 아니면 멈춘다(app.js syncQuidditchSnitch). */
.art-fx__snitch {
  position: absolute;
  left: calc(50% - (566.5 + 96) * var(--u)); top: calc(50% - (372 - 56) * var(--u));
  width: calc(442 * var(--u)); height: calc(197 * var(--u));
  overflow: visible;
}



/* ===== 물약 QR 스캔 — 26-10-02 Figma 4738:10012(대기) · 4890:32638(확인 중) · 4890:32700(완료), 1133×744 =====
   틀(헤더 · 원 · 안내 · [건너뛰기] · 링 상태 · 칩)은 위 "QR 스캔 3종" 그대로이고 물약만:
   - 배경(26-10-12 새 시안): 바탕 = 세로 그라디언트 #1A1810(위 32.02% 까지) → #343331(아래 끝) — 불투명이라 #08050F/#05070F 바탕은 안 보인다.
     그 위 아치 테두리 그림(안쪽이 투명한 새 원본 1000×1400 의 시안 채움 CROP 가로 6.33% ~ 93.67% · 세로 36.45% ~ 77.42% 를 잘라 둔 PNG) 50% 보통 블렌드,
     맨 위 세로 그라디언트 60% 올리브 · 베이지(26-10-13 시안 색 수정: #010201 → #4A4B29 40.571% → #BAAD84 80% 74.914% → #9B9362 80% 78.942% → #010201 93.061% —
     전 초록 #143618 · #1E862A · #206B29).
     (전: 바탕 #05070F 위 물약병 없는 아치 그림 JPG 50%)
   - 제목 양옆 화살 끝색 금빛(#FCF3A3) — 그림 교체는 app.js MISSION_ART.arrow(결과 화면 제목엔 26-10-06 부터 화살 없음)
   - [뒤로]는 확인 중에도 숨고(시안 4890:32638 빈 56 자리), [도움말]은 완료에도 보인다(4890:32700). 둘 다 확인 중 · 완료엔 눌리지 않는다(위 공통 규칙) */
.bg-potion-scan {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover;
  opacity: 0.5;
  display: none;
}
body[data-mission="potion"][data-screen="scan"] .bg-layer { background: linear-gradient(180deg, #1A1810 32.02%, #343331 100%); }   /* ⚠ 시안 원본값 */
body[data-mission="potion"][data-screen="scan"] .bg-potion-scan { display: block; }
body[data-mission="potion"][data-screen="scan"] .bg-art { display: none; }
body[data-mission="potion"][data-screen="scan"] .bg-night {
  background: linear-gradient(180deg, #010201 0%, #4A4B29 40.571%, rgba(186, 173, 132, 0.8) 74.914%, rgba(155, 147, 98, 0.8) 78.942%, #010201 93.061%);   /* ⚠ 시안 원본값 — 60% 는 위 공통 규칙 */
}
[data-mission="potion"] #screen-scan[data-state="loading"] #btn-scan-back { visibility: hidden; }
[data-mission="potion"] #screen-scan[data-state="done"] #btn-help { visibility: visible; }

/* ===== 퀴디치 QR 스캔 · 기숙사 선택 — 26-10-06 Figma 4741:10673(대기) · 4741:10694(확인 중) · 4741:10773(완료) · 4741:11541(고르기 전) · 4741:11340(고른 뒤) =====
   틀 · 상태는 위 "QR 스캔 3종" · 기숙사 선택 그대로이고 퀴디치만:
   - 배경: 성 사진 대신 퀴디치 경기장 사진(시작 화면과 같은 원본 843×1150 의 아래쪽 — 시안 채움 CROP 52.48% ~ 100.6% · 노출 -0.64 를
     Figma 에서 그대로 렌더해 둔 파일) 50% · 보통 블렌드(26-10-06 "은은하게 배경 이미지" — 그 전엔 세로 성 사진 밝기 블렌드) + 세로 그라디언트 60% 올리브
     (#010201 → #293614 40.571% → #5E861E 74.914% → #4E6B20 78.942% → #020201 93.061%). 바탕 #08050F 는 네이비 규칙 #05070F 그대로(위 공통 규칙)
   - 제목 양옆 화살 끝색 라벤더 #BBA3FC(app.js MISSION_ART.arrow — 결과 화면 제목엔 26-10-06 부터 화살 없음)
   - [뒤로] · [도움말]은 공통 그대로(확인 중엔 보이고 · 완료엔 숨는다 — 시안 4741:10694 · 4741:10773)
   - 글자 · 구분선 색은 아래 "글자 · 선 색"(26-10-06 수정) */
.bg-quidditch-scan {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover;
  opacity: 0.5;
  display: none;
}
body[data-mission="quidditch"]:is([data-screen="scan"], [data-screen="house"], [data-screen="nickname"]) .bg-quidditch-scan { display: block; }
body[data-mission="quidditch"]:is([data-screen="scan"], [data-screen="house"], [data-screen="nickname"]) .bg-art { display: none; }
body[data-mission="quidditch"]:is([data-screen="scan"], [data-screen="house"], [data-screen="nickname"]) .bg-night {
  background: linear-gradient(180deg, #010201 0%, #293614 40.571%, #5E861E 74.914%, #4E6B20 78.942%, #020201 93.061%);   /* ⚠ 시안 원본값 — 60% 는 위 공통 규칙 */
}
/* 기숙사 [선택하기] — 26-10-06 Figma 4982:8861: 336×70 · 여백 4 · 흰 → #C8B5FE(아래 → 위) · 그림자 0 2.373 2.373 #565150 ·
   안쪽 테두리 0.593 #858587 · 글자 NEXON Medium 26.102 #242425 · 양끝 점(#FFFBF4 판 · 여백 2.373 · #858587 점 4.746) ·
   별 무늬 257.458(#32167F 4% — assets/house/select-btn-deco-lavender.svg, 안쪽 테두리 기준 18.39 · -99.07). 패트로누스 [선택하기]는 그대로. */
#screen-house .house-ok {
  width: calc(336 * var(--u)); height: calc(70 * var(--u));
  padding: calc(4 * var(--u));
  background: linear-gradient(0deg, #FFFFFF 0%, #C8B5FE 100%);           /* ⚠ 시안 원본값(비토큰) */
  box-shadow: 0 calc(2.373 * var(--u)) calc(2.373 * var(--u)) 0 #565150;
}
#screen-house .house-ok__inner { border-width: calc(0.593 * var(--u)); gap: calc(5.932 * var(--u)); }
#screen-house .house-ok__label { font-size: calc(26.102 * var(--u)); color: #242425; }   /* ⚠ 시안 원본값(비토큰) */
#screen-house .house-ok__deco {
  left: calc(18.39 * var(--u)); top: calc(-99.07 * var(--u));
  width: calc(257.458 * var(--u)); height: calc(257.458 * var(--u));
}
#screen-house .house-ok__dot { padding: calc(2.373 * var(--u)); background: #FFFBF4; }
#screen-house .house-ok__dot span { width: calc(4.746 * var(--u)); height: calc(4.746 * var(--u)); }
#screen-house .house-ok__dot--r { left: auto; right: calc(-4.35 * var(--u)); top: calc(50% + 0.25 * var(--u)); }
#screen-house .house-ok__dot--l { top: calc(30.25 * var(--u)); }

/* ===== 닉네임 입력 (퀴디치 · [건너뛰기]로 온 관람객만) — 26-10-06 Figma 5013:9088(빈 칸) · 5013:13203(입력 중) · 5019:15265(입력 뒤) =====
   틀 · 배경 · 헤더 · 안내 · 화살은 기숙사 선택과 같다(.house-stage · .house-head · .house-body 위아래 20 · 40 — [가운데 칸] → [입력 완료]).
   입력 칸 = 공통 TextField(.login-input — Figma textfield 3183:14183 와 같은 컴포넌트: 352×62 알약 · 여백 16 · 20 · NEXON Medium 20 가운데 ·
     바탕 검정 20% · 글로우 4)에 퀴디치 값만 덮는다: 선 1 흰색 · 글자 #F3EFFF · 빈 칸 안내 Regular 20 · 자간 1% · 같은 색 40% ·
     글로우 #CFB8FB 40% · 뒤 흐림 25(CSS 절반 — 공통 TextField 엔 없다).
     ⚠ 뒤 흐림은 <input> 에 직접 주면 크롬이 그리지 않는다(26-10-06 확인 — 픽셀 차이 0). 그래서 칸을 틀(.nick-field)로 감싸 틀의 ::before 가 흐림을 맡고,
       입력 중 위로 옮기는 것도 틀이 한다.
   입력 중([data-typing] — 칸에 포커스, 기기 키보드가 아래 346 을 덮는다. app.js 가 focus · blur 로 붙인다 — :focus 는 창 포커스가 없으면 안 맞는다):
     칸이 남은 자리(166 ~ 398)의 가운데 y 241 로 올라가고(360.5 → -119.5) 선 1.5 #BB9BFA(글로우는 그대로 — 공통 TextField 의 포커스 네이비 글로우는 끈다),
     [입력 완료]는 숨는다(시안 5013:13203 에 없다 — 키보드를 내리면 다시 보인다).
   보라 · 라벤더는 퀴디치 콘텐츠 색이라 시안 그대로다(기숙사 [선택하기] #C8B5FE · 화살 #BBA3FC 와 같은 쪽). */
.nick-field {
  position: relative; display: block; flex: none;
  width: calc(352 * var(--u)); height: calc(62 * var(--u));
  border-radius: var(--radius-full);
  transition: transform 0.35s cubic-bezier(0.4, 0, 0.2, 1);
}
.nick-field::before {
  content: ""; position: absolute; inset: 0;
  border-radius: inherit;
  -webkit-backdrop-filter: blur(calc(12.5 * var(--u))); backdrop-filter: blur(calc(12.5 * var(--u)));
  pointer-events: none;
}
.login-input.nick-input {
  position: relative; display: block;
  width: 100%;
  margin: 0;
  border: calc(1 * var(--u)) solid #FFFFFF;
  color: #F3EFFF; caret-color: #F3EFFF;                                                    /* ⚠ 시안 원본값(비토큰) */
  box-shadow: 0 0 calc(4 * var(--u)) rgba(207, 184, 251, 0.4);                          /* ⚠ 시안 원본값(퀴디치 라벤더) */
  -webkit-appearance: none; appearance: none;
  transition: border-color 0.2s ease;
}
.login-input.nick-input::placeholder {
  font-weight: 400; letter-spacing: 0.01em;
  color: rgba(243, 239, 255, 0.4);
}
.login-input.nick-input:focus { border-color: #FFFFFF; box-shadow: 0 0 calc(4 * var(--u)) rgba(207, 184, 251, 0.4); }
#screen-nickname[data-typing] .nick-field { transform: translateY(calc(-119.5 * var(--u))); }
#screen-nickname[data-typing] .nick-input {
  border-width: calc(1.5 * var(--u)); border-color: #BB9BFA;                               /* ⚠ 시안 원본값(퀴디치 라벤더) */
}
/* [입력 완료] — 기숙사 [선택하기] 틀(Figma 5019:15280): 352×59 · 여백 4 · 흰 → #EEE8FF(아래 → 위) · 그림자 0 2 2 #565150 · 안쪽 테두리 0.5 #858587 ·
   글자 NEXON Medium 22 #242425 · 양끝 점 #F7F4FF 판 · 별 무늬 217(#32167F 4% — 라벤더 그림)은 안쪽 테두리 기준 16 · -83.
   CSS 는 안쪽 테두리 선(0.5) 안쪽이 기준이라 0.5 씩 뺀다(별 무늬는 기본값 15.5 · -83.5 그대로). 비었으면 투명(자리는 그대로 — 시안 opacity 0) */
.house-ok.nick-ok {
  width: calc(352 * var(--u));
  background: linear-gradient(0deg, #FFFFFF 0%, #EEE8FF 100%);                             /* ⚠ 시안 원본값(비토큰) */
}
.nick-ok .house-ok__label { color: #242425; }                                               /* ⚠ 시안 원본값(비토큰) */
.nick-ok .house-ok__dot { background: #F7F4FF; }
.nick-ok .house-ok__dot--r { left: calc(339 * var(--u)); }
#screen-nickname[data-typing] .nick-ok { visibility: hidden; }
/* 글자 · 선 색 — 26-10-06 색 수정(4741:10673 · 10694 · 10773 · 11541 · 11340): 라벤더 쪽으로. 물약은 그대로(#EFF8FF · #A6BCD8 · #E6FBFF)
   안내 한 줄 · 기숙사 안내 #F3EFFF · 구분선 #B3A6D8 · 건너뛰기 안내 #F3EFFF 70% · [건너뛰기] #ECE6FF(화살도 같은 색) */
[data-mission="quidditch"] :is(#screen-scan .scan-desc, #screen-house .house-desc, #screen-nickname .house-desc) { color: #F3EFFF; }   /* ⚠ 시안 원본값(비토큰) */
[data-mission="quidditch"] #screen-scan .info-note { border-top-color: #B3A6D8; }
[data-mission="quidditch"] #screen-scan .info-note p { color: rgba(243, 239, 255, 0.7); }
[data-mission="quidditch"] #screen-scan .skip-btn { color: #ECE6FF; }

/* ===== 패트로누스 QR 스캔 · 패트로누스 선택 — 26-10-06 Figma 4741:10825(대기) · 4741:10846(확인 중) · 4741:10867(완료) · 4741:11871 외 동물별 5장 =====
   틀 · 상태 · 글자색은 위 "QR 스캔 3종" · 아래 "패트로누스 선택" 그대로(제목 화살도 공통 그림 — 끝색 #A3AFFC 가 시안과 같다)이고 패트로누스만:
   - 배경: 성 사진(밝기 블렌드) 대신 밤 숲 사진(원본 2048×768 을 시안처럼 FILL · 노출 -0.13 — Figma 에서 그대로 렌더해 둔 파일) 50% · 보통 블렌드
     + 세로 그라디언트 60% 파랑(#050A11 → #142336 40.571% → #609FF1 74.914% → #5A96E5 78.942% → #15519F 93.061%). 바탕 #08050F 는 네이비 규칙 #05070F 그대로 */
.bg-patronus-scan {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover;
  opacity: 0.5;
  display: none;
}
body[data-mission="patronus"]:is([data-screen="scan"], [data-screen="patronus"]) .bg-patronus-scan { display: block; }
body[data-mission="patronus"]:is([data-screen="scan"], [data-screen="patronus"]) .bg-art { display: none; }
body[data-mission="patronus"]:is([data-screen="scan"], [data-screen="patronus"]) .bg-night {
  background: linear-gradient(180deg, #050A11 0%, #142336 40.571%, #609FF1 74.914%, #5A96E5 78.942%, #15519F 93.061%);   /* ⚠ 시안 원본값 — 60% 는 위 공통 규칙 */
}

/* ===== 그림 결과 — 물약 26-10-02 Figma 4890:32908 · 퀴디치 26-10-06 4982:8944 · 패트로누스 26-10-06 4990:10745, 1133×744 =====
   결과 새 시안이 온 콘텐츠만 body[data-result-art](app.js applySection — MISSION_ART.result)로 켠다. 26-10-06 패트로누스까지 와서 세 콘텐츠 모두 이 틀이다.
   - 배경: 시작 화면 배경 그대로 — 물약은 아치 그림 + 초록 라디얼(.bg-potion-home — 26-10-12 새 시안 5415:3647 부터 라디얼도 시작 화면과 같다, 전엔 가운데 80%),
     퀴디치는 경기장 사진 + 아래 가운데 라디얼(.bg-quidditch-home), 패트로누스는 밤 숲 · 수사슴 그림 + 왼쪽 아래 파란 라디얼(.bg-patronus-home) — 둘 다 시작 화면과 똑같다.
     체험존 사진(.bg-result)과 어두운 막(.bg-night)은 끈다
   - 묶음 폭 521, 화면 가운데: [두 줄 제목 → 40 → 완료 · 남은 초 두 줄] → 80 → 콘텐츠 색 그림 버튼 [홈으로] 360×87
   - 제목은 QR 스캔 제목과 같은 StepTitle(42 / 53.109 · 글로우). 시안의 양옆 화살 데코는 26-10-06 다원님 요청으로 뺐다(세 콘텐츠 모두)
   - 완료 · 남은 초: base/head1/R-20(NEXON Regular 20 / 1.5 · 자간 1%, 26-10-06 — 전엔 Medium 20 · 자간 0.5%) · 흰색, 남은 초("10초")만 콘텐츠 색(--art-count-em). 1초마다 줄어든다(app.js renderResultCount) */
body[data-mission="potion"][data-screen="result"] .bg-potion-home { opacity: 1; }
body[data-mission="quidditch"][data-screen="result"] .bg-quidditch-home { opacity: 1; }
body[data-mission="patronus"][data-screen="result"] .bg-patronus-home { opacity: 1; }
body[data-result-art][data-screen="result"] :is(.bg-result, .bg-night) { display: none; }

.result-art { display: none; }
[data-result-art] #screen-result .result-layout { display: none; }
[data-result-art] #screen-result .result-art {
  display: flex; flex-direction: column; align-items: center;
  gap: calc(80 * var(--u));
  width: calc(521 * var(--u));
}
.result-art__head {
  display: flex; flex-direction: column; align-items: center;
  gap: calc(40 * var(--u));
  width: 100%;
}
#screen-result .result-art .title-deco { align-items: center; gap: calc(16 * var(--u)); }
#screen-result .result-art .step-title { white-space: pre; text-align: center; }   /* 줄은 문구의 \n 에서만 — 영문이 길어도 접지 않고 양옆으로 넘친다 */
/* 완료 · 남은 초 — base/head1/R-20(NEXON Regular 20 / 1.5 · 자간 1%, 26-10-06 — 전엔 Medium 20 · 자간 0.5%) */
.result-art__count {
  margin: 0;
  font-size: calc(20 * var(--u)); font-weight: 400; line-height: 1.5; letter-spacing: 0.01em;
  color: var(--color-white-100);
  text-align: center; white-space: nowrap;
}
.result-art__sec { color: var(--art-count-em); }

/* 그림 버튼(.art-cta) — 시안 Start Button 360×87 을 진짜 버튼으로(결과 [홈으로] — 시작 화면 [시작하기]와 같은 콘텐츠 색 그림, 면은 app.js MISSION_ART.cta).
     .art-cta__btn   틀 그대로 · 넘침 자름 · 그림자 Shadow/lg(0 4 12 — drop-shadow 는 반경 절반)
       __face  Vector(353.4×86, 틀 기준 2.85, 1) — 면 #1C1A1D + 초록 라디얼 · 테두리 #9FEE9C → #14E30E · 네 모서리 삼각 · 노이즈 결
       __glow  Button Border(Stroke)(374.766×100.766 — 틀 기준 -0.5, 0.852 에 흐림 여백 7.383) — #A5A5A5 20% 굵은 테두리 흐림
     글자 NEXON Medium 32 · 행간 1.5 · 자간 0.16, 콘텐츠 색 그라디언트(--art-cta-text — 물약 #9FEE9C → #14E30E · 퀴디치 #E1C7FC → #B771FD). 상자 343.723 · 위 21 · 가운데보다 0.36 오른쪽
   (완드 금색 버튼 wand/styles.css .gold-cta 와 같은 틀 · 색만 다르다) */
.art-cta {
  position: relative; flex: none;
  width: calc(360 * var(--u)); height: calc(87 * var(--u));
  margin: 0; padding: 0; border: 0; background: none;
  font: inherit; cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.art-cta:active .art-cta__btn { transform: scale(0.97); }
.art-cta:focus-visible { outline: 2px solid #14E30E; outline-offset: calc(4 * var(--u)); }
/* 결과 [홈으로] 늦게 나타나기 — 26-10-13 다원님 요청("홈으로 버튼을 나중에 · 자연스러운 인터랙션", 물약 · 퀴디치 · 패트로누스 공통).
   화면이 뜨고(0.45초) 제목 · 남은 초를 먼저 읽게 둔 뒤, 1.1초에 버튼이 아래에서 살짝 떠오르며(20 → 0 · 97% → 100%) 흐림이 걷히고 또렷해진다(0.8초, 끝이 부드럽게 멈춤).
   나타나기 전엔 visibility hidden 이라 눌리지 않는다(안 보이는 버튼을 잘못 눌러 홈으로 가지 않게). fill backwards — 끝난 뒤엔 값을 붙잡지 않는다
   (붙잡으면 [홈으로]를 누를 때 줄어드는 효과 · 위 .screen--active 와 같은 이유). 결과 화면이 다시 뜰 때마다 처음부터. 동작 줄이기 설정이면 바로 보인다. */
#screen-result .art-cta { animation: result-cta-in 0.8s cubic-bezier(0.22, 1, 0.36, 1) 1.1s backwards; }
@keyframes result-cta-in {
  from { opacity: 0; transform: translateY(calc(20 * var(--u))) scale(0.97); filter: blur(calc(6 * var(--u))); visibility: hidden; }
  to   { opacity: 1; transform: none; filter: none; visibility: visible; }
}
@media (prefers-reduced-motion: reduce) { #screen-result .art-cta { animation: none; } }
.art-cta__btn {
  position: absolute; inset: 0;
  overflow: hidden;
  filter: drop-shadow(0 calc(4 * var(--u)) calc(6 * var(--u)) rgba(0, 0, 0, 0.16));
}
.art-cta__face {
  position: absolute; left: calc(2.85 * var(--u)); top: calc(1 * var(--u));
  width: calc(353.4 * var(--u)); height: calc(86 * var(--u));
  display: block;
}
.art-cta__glow {
  position: absolute; left: calc(-7.883 * var(--u)); top: calc(-6.531 * var(--u));
  width: calc(374.766 * var(--u)); height: calc(100.766 * var(--u));
  display: block;
}
.art-cta__label {
  position: absolute; left: calc(50% + 0.36 * var(--u)); top: calc(21 * var(--u));
  width: calc(343.723 * var(--u));
  transform: translateX(-50%);
  font-family: var(--font-primary); font-weight: 500;
  font-size: calc(32 * var(--u)); line-height: 1.5; letter-spacing: calc(0.16 * var(--u));
  text-align: center; white-space: nowrap;
  background: var(--art-cta-text);
  -webkit-background-clip: text; background-clip: text;
  color: transparent;
}


/* ---------- 03 결과 도출 완료 화면 — Figma 4063:15283 ---------- */
.result-layout {
  display: flex; flex-direction: column; align-items: center; text-align: center;
  gap: calc(36 * var(--u));   /* 시안 Content gap 36 */
}

/* 완료 마크 + 문구 한 덩어리 (시안 Result Info, gap 24) */
.result-info {
  display: flex; flex-direction: column; align-items: center;
  gap: calc(24 * var(--u));                              /* 시안 Result Info gap 24 */
}
/* 완료 마크는 **초록(#92FA9B) 한 가지**다 — 26-09-18 디자이너 확인.
   완드 시안(4063:15283)은 보라(#BB9BFA), 나머지 세 시안(4172:36948 등)은 초록이라
   갈려 있었는데 초록으로 통일했다. 기능 컬러가 아니라 장식이라 SVG 에 색을 박아 둔다.
   체크 인터랙션(26-09-23 지시) — 화면이 뜨면 원이 12시에서 한 바퀴 그려지고, 이어서 체크가
   왼쪽에서 오른쪽으로 그어진 뒤 살짝 튀었다 가라앉는다. 결과 화면이 뜰 때마다 다시 그려진다
   (.screen 이 display:none → flex 로 바뀔 때 애니메이션이 처음부터 돈다).
   획 길이는 pathLength="1" 로 1 에 맞춰 두어 dash 값이 도형 크기와 무관하다.
   기본값(애니메이션 없음)은 **다 그려진 상태**다 — 줄인 모션 설정에선 애니메이션만 빠지고 마크는 보인다. */
.done-mark { width: calc(64 * var(--u)); height: auto; aspect-ratio: 1; overflow: visible; }
.done-mark__ring,
.done-mark__tick { stroke-dasharray: 1; stroke-dashoffset: 0; }
/* 화면 진입(0.45s)과 겹치게 시작 → 원 0.15~0.65s → 체크 0.55~0.9s → 튐 0.9~1.25s */
#screen-result.screen--active .done-mark__ring { animation: done-draw 0.5s cubic-bezier(0.65, 0, 0.35, 1) 0.15s both; }
#screen-result.screen--active .done-mark__tick { animation: done-draw 0.35s cubic-bezier(0.65, 0, 0.35, 1) 0.55s both; }
#screen-result.screen--active .done-mark { animation: done-settle 0.35s ease-out 0.9s both; }
@keyframes done-draw { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } }
@keyframes done-settle { 0%, 100% { transform: scale(1); } 45% { transform: scale(1.12); } }

.result-title {
  /* 시안 base/head1 계열 Bold 36 / lh 1.3 / ls -1% */
  font-size: calc(36 * var(--u)); font-weight: 700;
  letter-spacing: -0.01em; line-height: 1.3;
  color: var(--color-white-100);
  word-break: keep-all;
}


/* ---------- 도움말 다이얼로그 ----------
   공통 팝업(.popup)과 오버레이(.popup-overlay)를 그대로 쓴다 — 크기는 이 앱의 --u, 버튼은 위 .dcta--small(× --u).
   알림 화면과 같은 판이라 여기서 덮을 값이 없다. */

/* ---------- 체험 중 무동작 확인 팝업(26-10-01) ----------
   공통 팝업 그대로 + 버튼 둘을 패널 안쪽 폭(638 − 94×2 = 450)에 나란히: 217 · 16 · 217. 왼쪽 [홈으로] 보조(투명 알약) · 오른쪽 [계속하기] 주(공통 PillButton).
   26-10-01 디자인시스템 #104 부터 팝업 확인 버튼은 전부 PillButton(밝은 알약) — 소진 · 체험 중인 QR · 도움말 · 이 팝업.
   본문은 두 줄(\n) — 남은 초는 공통 강조색(.popup__em). */
#idle-body { white-space: pre-line; }
.popup__actions { display: flex; gap: calc(16 * var(--u)); }
.popup__actions .pill-btn { width: calc(217 * var(--u)); }
/* 보조 알약 [홈으로] — 공통 PillButton 의 투명판. Figma 공통 모달 scanner_idle_ask 팝업 4781:1340 의 [홈으로](4781:24328, 26-10-07 디자이너 확정):
   217×59 · 투명 바탕 · 바깥 테두리 1(안쪽) #EEF1FE 60% → 여백 4 → 안쪽 테두리 0.5 #EEF1FE 45%(207×49) · 글자 #BCC4E6(ice-200) · 별 무늬 없음.
   양끝 점 — #EEF1FE 15% 판(8) 위 #BCC4E6 점(4): 왼쪽은 바깥 테두리 바로 안(1), 오른쪽은 끝에서 1.5(테두리 1 + 0.5).
   시안의 그림자(0 2 2 #565150)는 바탕이 없는 버튼이라 Figma 에서도 보이지 않아(버튼 묶음이 아래를 자른다) 넣지 않는다. */
.pill-btn--ghost {
  background: none; box-shadow: none;
  border: calc(1 * var(--u)) solid rgba(238, 241, 254, 0.6);   /* ⚠ 시안 원본값 */
}
.pill-btn--ghost:focus-visible { box-shadow: var(--focus-ring); }
.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, var(--color-ice-200) 0 calc(2 * var(--u)), rgba(238, 241, 254, 0.15) calc(2 * var(--u))); }
.pill-btn--ghost::after { right: calc(0.5 * var(--u)); }
.pill-btn--ghost .pill-btn__label { color: var(--color-ice-200); }

/* ---------- 포커스 / 모션 접근성 ---------- */
:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.dcta:focus-visible { box-shadow: var(--focus-ring); }   /* 상시 글로우가 없어져 포커스 링만 */

@media (prefers-reduced-motion: reduce) {
  /* 장식 애니메이션은 정지, 상태 전달에 필요한 전환만 짧게 유지 */
  .fx-sparkle, .fx-fog, .fx-orb, .scan-ring--glow, .vf-scanline,
  .start-cta, .start-cta::before, .home-wait-chip, .scan-chip--seat, .done-mark, .done-mark__ring, .done-mark__tick, .house-card__frame { animation: none !important; }
  .fx-sparkle, .fx-orb { opacity: 0.5; }
  .art-fx *, .art-fx *::before, .bg-quidditch-home { animation: none !important; }   /* 그림 시작 화면 움직임 — 빛은 그대로 두고 알갱이 · 스니치는 숨김 */
  .art-fx__mote { display: none; }   /* 스니치는 app.js 가 시안 모습(다 그린 꼬리 + 스니치)에서 멈춘다 */
  #screen-home .start-title__glint { display: none; }   /* 타이틀 금빛 가루도 하지 않는다(magic-dust.js) */
  .screen--active { animation: none !important; }   /* 오버레이 등장은 components.css 가 끈다 */
  * { transition-duration: 0.01ms !important; }
}

/* ---------- 데모 컨트롤 패널 ---------- */
.demo-panel {
  position: fixed; left: 14px; bottom: 14px; z-index: 50;
  font-family: var(--font-secondary);
}
.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.4);
  border: 1px dashed rgba(255,255,255,0.25); border-radius: 8px;
  padding: 6px 12px; cursor: pointer;
}
/* 패널은 버튼 **위**에 띄운다(absolute) — 묶음이 화면 아래에 붙어 있어서, 버튼 아래 흐름에
   두면 열 때 묶음이 위로 자라며 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--col { flex-direction: column; align-items: stretch; }
.demo-row > span { color: #64748b; font-weight: 600; }
.demo-cred {
  font-size: 12px; color: #e2e8f0; background: #1e293b;
  border: 1px solid #334155; border-radius: 6px; padding: 3px 8px;
  letter-spacing: 0.04em; user-select: text;
}
.demo-btn {
  font-size: 12px; color: #e2e8f0; background: #1e293b;
  border: 1px solid #334155; border-radius: 8px;
  padding: 7px 10px; cursor: pointer; text-align: left;
}
.demo-btn:hover { background: #334155; }
.demo-btn--on { background: #3b5bdb; border-color: #3b5bdb; }
.demo-btn--wide { width: 100%; }
