/* 해리포터 특별전 웹앱 — Variant A · 화면 전용 스타일
   design-system/tokens.css + design-system/components.css 위에 얹는다.
   색·간격·타이포는 토큰만 사용한다. 비토큰 값은 ⚠️ 주석으로 출처를 남긴다.
   여기 있는 요소는 전부 이 시안의 화면 1~2개에서만 쓰이는 one-off — 디자인시스템에 올리지 않는다. */

* { margin: 0; padding: 0; box-sizing: border-box; }

/* 오버레이는 display:flex라 hidden 속성이 무시된다 — 명시적으로 되돌린다. */
[hidden] { display: none !important; }

/* 페이지 캔버스 — iOS 사파리에서 화면 맨 끝까지 칠해지는 **유일한** 레이어다.
   앱 본체(.viewport)는 position:fixed라 아이폰에서는 상태바·툴바 **사이**로만 잡히고,
   그 바깥(상단 상태바 뒤 / 하단 툴바 주변)은 어떤 자식도 칠할 수 없다.
   그래서 화면이 바뀔 때마다 JS(syncCanvasBackground)가 **지금 화면이 실제로 쓰는 배경**
   (그라디언트든 이미지든)을 그대로 여기에 옮겨 담아 배경이 끊기지 않게 한다.
   ⚠️ 단색으로 덮지 말 것 — 화면마다 배경이 달라 경계가 그대로 드러난다. */
/* 무대는 812px 고정이라 문서가 세로로 스크롤될 일이 없다. iOS 사파리의 고무줄 스크롤만은
   그와 무관하게 화면 전체를 위아래로 출렁이게 만드는데, 홈의 가로 캐러셀·아이콘 레일을
   가로로 쓸 때 그게 같이 따라와 "가로 스크롤이 세로로도 움직인다"로 보인다.
   (두 컨테이너 자신은 touch-action: pan-x로 이미 세로 제스처를 막아 뒀다.) */
/* 다크 전용 앱이다 — meta[name=color-scheme]와 같은 선언을 CSS에도 둔다(둘 다 있어야
   CSS가 늦게 붙는 첫 프레임까지 덮인다). UA가 그리는 입력칸·커서·스크롤바가 다크로 나온다. */
:root { color-scheme: dark; }
html, body { height: 100%; overscroll-behavior: none; }
/* iOS 26 홈 화면 앱의 아래 띠(WebKit 버그 301108, 2026-10-19 실기기) — 상태바를 투명하게 덮는(black-translucent ·
   viewport-fit=cover) 홈 화면 앱에서 WebKit 이 보이는 높이를 상태바만큼 짧게 잡는다(393 × 852 에서 793). 고정 틀
   (.viewport, fixed)은 그 짧은 끝에서 그리기를 멈춰, 그 아래(상태바 높이만큼)에 띠가 남았다. 고정 틀을 늘려도
   WebKit 이 그 아래를 그리지 않아 소용없다. 문서가 화면보다 짧을 때만 생기는 일이라 문서를 화면 높이만큼 키우면
   iOS 가 높이를 제대로 돌려준다. min() 은 상태바가 불투명할 때(위 여백 0) 100lvh 가 화면 전체로 잡혀 문서가
   상태바만큼 스크롤되는 것을 막는다(WebKit 316008). 홈 화면 앱에서만 — 사파리 탭은 그대로다. */
@media (display-mode: standalone) {
  html { min-height: min(100lvh, calc(100% + env(safe-area-inset-top, 0px))); }
}
html.is-standalone { min-height: min(100lvh, calc(100% + env(safe-area-inset-top, 0px))); }
/* ⚠️ 2026-08-27: 화면(375px 무대) 밖에는 배경을 그리지 않는다.
   예전에는 JS(syncCanvasBackground)가 지금 화면의 배경을 body에 복사해 칠했는데,
   데스크톱에서 앱 프레임 좌우로 배경이 번져 보였다. 캔버스는 단색 하나로 고정한다. */
body {
  background: #05090A; /* ⚠️ non-token: 무대 밖 캔버스 단색 */
  font-family: var(--font-base);
  -webkit-font-smoothing: antialiased;
}

/* ══════════════ 웹페이지처럼 보이는 터치 반응 막기 — 이슈 #306 (2026-10-27, 스캐너 #149 규칙을 옮김) ══════════════
   누를 때 파란 박스 · 꾹 눌러 글자 선택 · 그림 꾹 누르기 메뉴(아이폰 — 안드로이드는 CSS 가 안 먹어 app.js 가 contextmenu 를
   막는다) · 그림 끌면 따라오는 사본 · 빨리 두 번 눌러 확대 · 가로로 돌렸을 때 글자 키움을 끈다.
   두 손가락 확대는 그대로 둔다(작은 글씨를 키워 보는 분이 있다 — 개발팀 권고).
   ⚠️ touch-action 은 홈 캐러셀(pan-y) · 스플래시(none)처럼 더 좁게 정한 곳이 그대로 이긴다 — 스와이프는 그대로다. */
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
body {
  -webkit-user-select: none;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
  touch-action: manipulation;
}
button, a, label { touch-action: manipulation; }
img, svg { -webkit-user-drag: none; user-drag: none; }
/* 남겨 두는 곳 — app.js 의 contextmenu 막기도 같은 곳을 뺀다.
     · 입력 칸 — 붙여넣기 · 커서 옮기기. 아이폰은 부모의 선택 막기를 물려받으면 입력 칸이 잘 안 눌린다.
     · 약관 · 개인정보처리방침 글 — 읽는 문서라 선택 · 복사를 둔다(링크로 여는 /terms · /privacy 단독 페이지와 같게, 디자이너 10-27).
     · 기숙사 사진 — 키오스크가 만든 완성 사진 한 장이라 꾹 눌러 저장하면 [사진 다운]과 같은 파일이다(디자이너 10-27).
       결과 카드(완드 · 패트로누스 등)는 그림 여러 장을 겹친 화면이라 꾹 누르면 조각만 저장돼 막는다. */
input, textarea, .legal { -webkit-user-select: text; user-select: text; -webkit-touch-callout: default; }
.hphoto__photo img { -webkit-touch-callout: default; }

/* 모바일 375px 기준. 데스크톱에서는 중앙 정렬된 목업 프레임으로 표시된다. */
/* ══════════════ 기기 화면 채우기 ══════════════
   화면 좌표는 전부 피그마 375×812 기준의 절대값이라, 폭을 유연하게 바꾸면 전 화면이 어긋난다.
   그래서 좌표계는 375px 그대로 두고 **무대째 확대**해서 기기 폭을 채운다.
   배율은 JS(syncAppScale)가 재서 --app-scale에 넣는다:
     min(가로/375, max(1, 세로/812))
     · 아이폰15(393×852) → 1.048 : 가로가 딱 맞고 세로도 거의 맞는다
     · 아이폰SE(375×667) → 1     : 짧은 화면은 키우지 않는다(오늘과 같은 동작)
     · 데스크톱          → 세로에 묶여 폰 한 칸 크기로 남는다
   ⚠️ 화면 높이를 쓸 때는 100dvh 대신 --screen-h 를 쓴다. 무대가 확대돼 있어서
      100dvh를 그대로 쓰면 확대 배율만큼 넘쳐 흐른다.

   높이는 **실제로 보이는 만큼**만 쓴다 — JS(syncAppScale)가 window.innerHeight 를 재서
   --screen-h 에 px 로 넣는다(= dvh 와 같은 값). CSS 단위 lvh 는 쓰지 않는다.

   ⚠️ 한때 lvh(주소창이 접힌 상태의 큰 뷰포트)로 잡아 사파리 바 뒤까지 채우려 했으나
      되돌렸다 — .viewport 가 position:fixed 라 보이는 영역으로 잘려서 아무 변화가 없었다.
      경위는 app.js 상단 주석에, 실기기 검증 결과는 이슈 #27 에 있다.
      **브라우저 탭에서 상하 바 영역은 쓸 수 없다.** 화면 전체를 쓰려면 standalone(홈 화면에
      추가)이어야 한다. 탭에서 할 수 있는 최대치는 바를 화면과 같은 색으로 물들이는 것이고,
      그건 .screen 의 background-color 가 정한다.

   --ui-gap 은 바에 가려지는 만큼이 아니라 **홈 인디케이터를 피하는 값**이다
   (= --safe-bottom = env(safe-area-inset-bottom)). 사파리 탭에서는 보통 0 이고
   standalone 에서 실제 값이 들어온다. 하단에 붙는 요소(CTA·토글·토스트)에만 더해 띄운다. */
.viewport {
  position: fixed;
  inset: 0;
  overflow: hidden;
  background: transparent; /* 캔버스(body)의 단색이 그대로 비친다 */
}
.app {
  --app-scale: 1;
  /* JS(syncAppScale)가 px로 넣는다 — lvh/dvh로는 안 된다(app.js 주석 참고). */
  --screen-h: 812px;

  /* 시스템 여백(노치·홈 인디케이터). env()는 기기 실측값이라 그대로 쓰면 되는데,
     무대가 --app-scale로 확대돼 있으니 무대 좌표계로 되돌려서(÷배율) 쓴다.
     사파리로 열면 상하 바가 이 영역을 이미 차지해 보통 0이고,
     홈 화면에 추가(standalone)로 띄우면 실제 값이 들어온다. */
  --safe-top: calc(env(safe-area-inset-top, 0px) / var(--app-scale));
  --safe-bottom: calc(env(safe-area-inset-bottom, 0px) / var(--app-scale));
  /* 하단에 붙는 요소들이 홈 인디케이터를 피하도록 쓰는 값 */
  --ui-gap: var(--safe-bottom);

  /* (홈 ↔ QR 토글의 세로 위치 변수 세 개는 2026-09-16 홈 리프레시로 토글이 사라지며 걷어냈다) */
  position: absolute;
  top: 0;
  left: 50%;
  width: 375px;
  min-height: var(--screen-h);
  overflow: hidden;
  transform: translateX(-50%) scale(var(--app-scale));
  transform-origin: top center;
}

/* ── 화면 가장자리 색 ──
   app.js 의 syncEdgeColor() 가 이 값을 읽어 <meta name="theme-color"> 에 넣는다
   (화면 전환·시트 열고 닫을 때마다).

   ⚠️ 2026-08-27에 걷어낸 것은 syncCanvasBackground() 다 — 이 값을 읽어 **body 에 칠하던**
      쪽으로, 무대 밖까지 배경이 번져 보여서 뺐다. 캔버스는 이제 body 의 단색 하나다.
      syncEdgeColor() 는 그것과 **다른 레버**이고 지금도 살아 있다.

   ⚠️ 다만 **iOS 사파리 26은 theme-color 를 무시**해서 그 브라우저에서는 실제 효과가 없다
      (이슈 #27 의 5·6번 항목). 구버전 iOS 는 볼 수도 있어 그대로 둔다.
      사파리에서 상하 바를 실제로 물들이는 것은 **`.screen` 의 background-color** 다.

   배경이 이미지면 그 하단 평균색을, 그라디언트면 종점 색을 적어 둔다. */
.screen { --edge: var(--color-night-900); }
.screen--onboarding2 { --edge: #0A0C18; } /* 새 온보딩 라디얼 종점 */
/* 시안(375×812)은 위 62 를 상태바, 아래 92 를 툴바 블록으로 두고 **둘 다 #030A11** 로 칠한다.
   사파리 탭에서는 그 두 칸을 브라우저가 가져가므로(이슈 #27) 앱은 가운데 658 만 쓰는데,
   바에 물드는 색은 이 배경색이 정한다 — 시안의 바 색을 그대로 쓴다. */
.screen--home { --edge: #030A11; }
/* 시트 안 화면들 — 시트가 열리면 이 값이 캔버스로 간다 */
.dreveal { --edge: #140A05; }     /* 초상화 벽(portraits/wall.webp) 아래 끝 */
.qreveal { --edge: #3C2B60; } /* ⚠️ non-token: 퀴디치 오늘의 순위 시안(6088:31013) 사파리 화면 아래 끝(시안 714 ~ 720) 평균색 */
.hphoto { --edge: #030A11; }  /* 기숙사 사진 바탕 */

/* ══════════════ 화면(스텝) 공통 ══════════════ */

.screen {
  position: absolute;
  inset: 0;
  display: none;
  flex-direction: column;
  min-height: var(--screen-h);
}
.screen.is-active { display: flex; }

/* 배경: 아트 이미지 + 상단 딤(0.16→0.4) 오버레이.
   Figma는 이미지 뒤에 하단 틸 그라디언트를 한 겹 더 두지만 이미지가 cover라 가려진다 — 동일하게 뒤에 배치. */
.screen__bg {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    linear-gradient(180deg, rgba(0, 0, 0, 0.16) 0%, rgba(0, 0, 0, 0.4) 57.118%), /* ⚠️ non-token: 아트 딤 오버레이 */
    var(--screen-bg) center / cover no-repeat,
    linear-gradient(180deg, rgba(0, 0, 0, 0) 80.357%, rgba(0, 200, 224, 0.3) 100%); /* ⚠️ non-token: 이미지 뒤 틸 */
}

/* 홈·마이페이지는 아트 대신 토큰 기반 야간 그라디언트 위에 콘텐츠를 얹는다.
   ⚠️ asset 필요: 홈 배경 아트 (현재는 gradient-radial 계열 플레이스홀더) */
.screen__bg--home {
  background:
    radial-gradient(110% 55% at 50% 0%, rgba(120, 176, 250, 0.18) 0%, rgba(12, 45, 67, 0.35) 45%, rgba(5, 9, 10, 0) 78%),
    var(--gradient-night);
}

.screen__header {
  position: relative;
  z-index: 1;
  flex-shrink: 0;
  width: 100%;
  /* 상단 네비 고정 위치. 26-09-18 에 36 → 10 으로 올렸다 — 시안과 대조해 보니 헤더가 26px 내려가
     있었다(홈만 20). 헤더가 흐름에 있는 화면은 아래 콘텐츠도 26 따라 올라간다. */
  padding-top: calc(10px + var(--safe-top));
}

.screen__body {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
}

/* 새 온보딩 3화면(언어·이메일·닉네임) 공통 —
   피그마는 타이틀 블록 top 124 · 335px 폭 · 타이틀↔필드 간격 47px.
   헤더가 36(상단여백) + 38(높이) = 74를 차지하므로 여기서는 14px만 더 내린다. */
.screen__body--onb { margin-top: 14px; gap: 47px; align-items: flex-start; padding-inline: 20px; }

/* CTA는 화면 하단 고정 위치.
   2026-09-18: 하단 여백을 51 → 12 로 내렸다. 폰 브라우저에서는 주소창·툴바가 아래를 이미
   먹고 들어와서, 51 을 더 띄우면 버튼이 화면 한가운데쯤 떠 보이고 Q1~Q3 선택지와도 겹쳤다
   (디자이너 지적 + 실기기 스크린샷). 홈 인디케이터는 --ui-gap 이 따로 피한다. */
.screen__cta {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  margin-top: auto;
  padding-bottom: calc(12px + var(--ui-gap));
  width: 100%;
}

/* 피그마 Header 컴포넌트(3085-5858/5859/5861) 높이는 38px 고정이다.
   아래 절대좌표(타이틀 top 88 등)가 이 높이를 전제로 계산돼 있다. */
/* 헤더는 .screen__header와 같은 요소라 padding-top(36 + 노치)까지 높이에 포함된다 —
   내용 칸이 피그마 38px가 되도록 전체 높이를 36 + 38로 잡는다. */
.header--login {
  box-sizing: border-box;
  height: calc(48px + var(--safe-top)); /* 10(상단여백) + 38(피그마 헤더 높이) */
  padding-bottom: 0;
}
/* (.header--home 은 2026-09-16 홈 리프레시부터 이 높이를 쓰지 않는다 — 시안 Header(home) 57px, 홈 블록 참고) */
/* 아이콘이 한쪽만 있는 헤더에서 자리를 잡아 주는 빈 칸(스플래시·로그인의 좌측) */
.header__icon-btn--ghost { width: 24px; height: 24px; }
.header__icon-btn img { display: block; }

/* ══════════════ 브랜드 로고 그룹 ══════════════ */

.brand {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 7px;
  width: 150px;
}
.brand__logo {
  display: block;
  width: 100%;
  height: auto;
}
.brand__tagline {
  width: 100%;
  font-size: 12px;
  font-weight: 500;
  line-height: 16.37px;
  text-align: center;
  color: var(--color-white-60);
}

/* ══════════════ 스플래시 · 로그인 — Figma splash_1 4981-57856 · splash_2 4981-61358 · splash_3 4981-61409
                 (2026-10-06 네이비) ══════════════
   세 시안이 같은 배경 · 같은 로고 자리를 쓴다. 바뀌는 것은 딤 세기와 아래 묶음뿐이다.
     splash_1 — 스플래시          딤 60% · 궤적 · 스니치 80% · "위로 쓸어올려서 시작" + 스와이프 필
     splash_2 — 스플래시 .is-choice 딤 80% · 궤적 · 스니치 20% · [회원가입] + "이미 계정이 있으신가요?"
     splash_3 — 로그인            splash_2 배경 그대로 · 소셜 3종 + "다른 이메일로 계속"
   좌표는 시안 y − 62(상태바). 아래 묶음은 사파리(보이는 높이 658)에서 시안 자리에 오도록 **아래에서** 건다 —
   짧은 화면에서는 위로 올라가 잘리지 않고, 긴 화면(홈 화면에 추가)에서는 엄지 쪽으로 따라 내려간다. */

.screen--splash {
  overflow: hidden;
  background: #0A0C18; /* ⚠️ non-token: 시안 바탕 라디얼 종점 */
}
.screen[data-step="splash"] { touch-action: none; } /* 스와이프 제스처를 브라우저 스크롤보다 우선 */

/* ── 배경 겹 — 라디얼 바탕 → 성 사진 + 딤 → 스니치 궤적(screen 합성) → 스니치 ──
   ⚠️ 궤적의 screen 합성이 성 사진과 섞이려면 둘 사이에 쌓임 맥락이 없어야 한다 — 궤적은 .splash-bg 의 직계 자식으로 둔다. */
.splash-bg {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  /* ⚠️ non-token: 시안 radialGradient(#0E1828 → #0A0C18 89.4%) — 기울어진 타원(svg gradientTransform)을 375 × 812 판 그대로.
     성 사진이 화면을 거의 덮어 사진 아래쪽 바깥에서만 보인다 */
  background:
    url("data:image/svg+xml;utf8,<svg viewBox='0 0 375 812' xmlns='http://www.w3.org/2000/svg' preserveAspectRatio='none'><rect x='0' y='0' height='100%' width='100%' fill='url(%23g)'/><defs><radialGradient id='g' gradientUnits='userSpaceOnUse' cx='0' cy='0' r='10' gradientTransform='matrix(-25.8 41.15 -35.071 -21.989 445 -29.5)'><stop stop-color='rgb(14,24,40)' offset='0'/><stop stop-color='rgb(10,12,24)' offset='0.89426'/></radialGradient></defs></svg>")
      0 calc(-62px + var(--safe-top)) / 375px 812px no-repeat,
    #0A0C18;
  animation: splash-fade 1.2s ease-out both;
}
.splash-bg--static { animation: none; }
/* 성 사진 594 × 827 — 시안 left calc(37.5% + 31.38px) 를 가운데로 · top 0(앱 −62). 사진은 시안의 이미지 보정이 구워진 내보내기다 */
.splash-bg__castle {
  position: absolute;
  top: calc(-62px + var(--safe-top));   /* 홈 화면에 추가하면 상태바만큼 내린다 — 사파리 탭은 0 이다(아래 「standalone」) */
  left: calc(37.5% + 31.38px);
  width: 594px;
  height: 827px;
  translate: -50% 0;
}
.splash-bg__castle img { display: block; width: 100%; height: 100%; object-fit: cover; }
/* 세로 딤 — splash_2 · 3 값(80 · 64 · 80%)으로 칠하고 splash_1 에서는 75% 만 비춘다(= 60 · 48 · 60%) */
.splash-bg__castle::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(179.54deg, rgba(0, 9, 26, 0.8) 0.287%, rgba(0, 9, 26, 0.64) 32.301%, rgba(0, 1, 4, 0.8) 43.64%); /* ⚠️ non-token: 시안 딤 */
  opacity: 0.75;
  transition: opacity 0.6s ease;
}
/* 스니치 궤적(image 776) −15° · screen. 시안(438 × 222 · left −113.734 · top 304.659)을 1.3배 키우고 오른쪽 · 위로 옮겨
   그림 끝(스니치 자리)이 화면 오른쪽 밖(436, 232)에 놓이게 했다 — 스니치가 선을 따라 화면 밖으로 나간다
   (2026-10-22 디자이너 지정). splash_1 에만 있다 — splash_2(회원가입 버튼) · 로그인 화면에서는 걷는다. */
.splash-bg__trail {
  position: absolute;
  top: calc(245.04px + var(--safe-top));
  left: -97.38px;
  width: 569.4px;
  height: 288.6px;
  max-width: none;
  object-fit: cover;
  rotate: -15deg;
  opacity: 0.8;
  mix-blend-mode: screen;
  transition: opacity 0.6s ease;
}
/* 스니치(자산 4-8) 135.783 × 64.93 · 22.03° — 회전 상자(left 229 · top 216 · 150.223 × 111.119)의 가운데.
   시안의 자리 · 자세 그대로 두고, 날 때는 app.js 가 이 자리에서 궤적 머리까지 옮긴다(로그인 화면에는 없다 — 날아가 버렸다) */
.splash-bg__snitch {
  position: absolute;
  top: calc(239.095px + var(--safe-top));
  left: 236.22px;
  width: 135.783px;
  height: 64.93px;
  max-width: none;
  object-fit: cover;
  rotate: 22.03deg;
  opacity: 0.8;
  transition: opacity 0.6s ease;
}
/* splash_1 의 궤적은 선을 따라 그려진다(2026-10-22, app.js 스플래시 궤적) — 칸은 위 .splash-bg__trail 그대로(자리 · 기울기 ·
   screen 합성)이고, 안에 그림 캔버스(__ink) · 파티클 캔버스를 겹친다. 그림 픽셀마다 선 위 어느 지점에 속하는지
   미리 재 두고, 머리가 그 지점을 지날 때 픽셀을 켠다 — 선이 스스로 엇갈리는 곳에서도 지나간 쪽만 보인다.
   한 바퀴가 끝나면 __art 째 걷었다가(.is-fading) 다시 그린다. */
.splash-trail { overflow: visible; }
.splash-trail__art { position: absolute; inset: 0; transition: opacity 0.8s ease; }
.splash-trail.is-fading .splash-trail__art { opacity: 0; }
.splash-trail__ink {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
}
/* 파티클은 칸 밖으로도 흩어진다 — 사방 40 넓게 깐다(app.js 가 같은 여백으로 좌표를 옮긴다) */
.splash-trail__sparks {
  position: absolute;
  top: -40px;
  left: -40px;
  width: calc(100% + 80px);
  height: calc(100% + 80px);
  pointer-events: none;
}
/* splash_1 의 스니치는 궤적 끝자락을 직접 날며 선을 그리고, 선을 따라 화면 밖으로 나간다(app.js 스플래시 궤적).
   같은 그림을 세 장 겹쳐 날개 둘 · 공으로 나눴다 — 날개는 뿌리를 축으로 퍼덕이고, 공이 그 뿌리를 덮는다.
   좌표는 그림 픽셀(619 × 296) 기준: 공 가운데 305 · 225, 반지름 52 / 날개 뿌리 252 · 230 · 358 · 229.
   칸(.splash-bg__snitch)은 자리 · 기울기만 쥐고, 날아오는 이동은 app.js 가 칸의 translate 로 준다.
   (로그인 화면의 스니치는 한 장짜리 그림 그대로다) */
.splash-snitch__body,
.splash-snitch__body > img {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  max-width: none;
}
.splash-snitch__body { opacity: 0; transform-origin: 49.27% 76.01%; }   /* 날 때만 보인다 · 공 가운데를 축으로 기운다 */
.splash-snitch__wing--l { clip-path: inset(0 57% 0 0); transform-origin: 40.71% 77.7%; }
.splash-snitch__wing--r { clip-path: inset(0 0 0 57%); transform-origin: 57.84% 77.36%; }
.splash-snitch__ball { clip-path: circle(11.6px at 49.27% 76.01%); }

.screen.is-choice .splash-bg__castle::after,
.splash-bg--dim .splash-bg__castle::after { opacity: 1; }
/* 회원가입 버튼이 뜨면(splash_2) 궤적 · 스니치를 걷는다 — 버튼에 눈이 가게(2026-10-22 디자이너, 전: 20% 로 흐리게).
   로그인 화면(splash_3)은 같은 배경이라 처음부터 없다(index.html). 다시 그리기도 이때 멈춘다(app.js splashTrail). */
.screen.is-choice .splash-bg__trail,
.screen.is-choice .splash-bg__snitch { opacity: 0; }

/* 로고 234 × 100 — 시안 가운데 + 4.5 · top 142(앱 80). 홈 로고와 같은 그림이다 */
.splash-logo {
  position: absolute;
  z-index: 1;
  top: calc(80px + var(--safe-top));
  left: calc(50% + 4.5px);
  width: 234px;
  height: 100px;
  max-width: none;
  object-fit: cover;
  translate: -50% 0;
  pointer-events: none;
  animation: splash-rise 1.2s 0.3s ease-out both;
}
.splash-logo--static { animation: none; }

@keyframes splash-fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes splash-rise {
  from { opacity: 0; transform: translateY(14px); filter: blur(5px); }
  to   { opacity: 1; transform: none; filter: none; }
}
@keyframes cta-rise {
  from { opacity: 0; transform: translateY(56px); }
  to   { opacity: 1; transform: none; }
}
@keyframes cta-leave {
  from { opacity: 1; transform: none; }
  to   { opacity: 0; transform: translateY(-40px); }
}

/* ── splash_1 — 안내문 + 스와이프 필. 시안 top 542(앱 480) · 높이 168 → 아래끝 648 = 보이는 높이 − 10 ── */
.splash__cta {
  position: absolute;
  z-index: 1;
  left: 50%;
  bottom: calc(10px + var(--ui-gap));
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 18px;
  translate: -50% 0;
  animation: splash-fade 0.8s 1.6s ease-out both;
}
/* accent/body2/R-16 · purple_100 — 두 줄 사이 2 */
.splash__hint {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  margin: 0;
  font-family: var(--font-accent);
  font-weight: 400;
  font-size: 16px;
  line-height: 1.5;
  letter-spacing: -0.16px;
  text-align: center;
  white-space: nowrap;
  color: var(--ice-50); /* 시안은 purple_100 — 2026-10-06 네이비 체계의 옅은 얼음빛으로 */
}
.splash__pill {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 8px;
  border-radius: var(--radius-full);
  background: rgba(4, 4, 4, 0.8); /* ⚠️ non-token: 시안 swipe 표면 */
  cursor: pointer;
}
.splash__slot {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  box-sizing: border-box;
  position: relative;
  border: 1.143px solid transparent;   /* 흰 보더 — 아래 「고리 테두리」 */
  --ring: var(--paint-white);
  --ring-w: 1.143px;
  border-radius: var(--radius-full);
}
/* 화살표 svg 는 아래를 가리킨다 — 시안처럼 위로 돌려 쓴다. 발광 쪽은 그림자를 품은 svg(18.857 × 23.429)다 */
.splash__slot img { display: block; max-width: none; rotate: 180deg; }
.splash__slot--ghost { opacity: 0; }
.splash__slot--ghost img { width: 9.143px; height: 13.714px; }
.splash__slot--glow {
  box-shadow: 0 0 10px rgba(153, 228, 255, 0.6); /* ⚠️ non-token: 시안 swipe 글로우 */
  animation: pill-arrow 2s 2.4s ease-in-out infinite;
}
.splash__slot--glow img { width: 18.857px; height: 23.429px; }
/* 화살표가 위 슬롯으로 떠오르며 스와이프 방향을 암시 */
@keyframes pill-arrow {
  0%, 100% { transform: translateY(0); opacity: 1; }
  45%      { transform: translateY(-44px); opacity: 0; }
  55%      { transform: translateY(10px); opacity: 0; }
}
/* 쓸어올리면 안내문 · 필이 위로 빠지고 splash_2 묶음이 올라온다 */
.screen.is-choice .splash__cta { animation: cta-leave 0.3s ease-in both; pointer-events: none; }

/* ── splash_2 — [회원가입] + "이미 계정이 있으신가요?" + 약관 링크. 시안 5811:6227(2026-10-19) — 묶음 top 535 · 폭 335 ·
   간격 28 · 약관 링크는 40 아래(top 679, 높이 18) → 아래끝 = 보이는 높이 − 23 ── */
.splash-choice {
  position: absolute;
  z-index: 1;
  left: 50%;
  bottom: calc(23px + var(--ui-gap));
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 28px;
  width: 335px;
  translate: -50% 0;
  visibility: hidden;
  opacity: 0;
}
.screen.is-choice .splash-choice { visibility: visible; animation: cta-rise 0.55s 0.15s ease-out both; }
.screen.is-choice.is-leaving .splash-choice { animation: cta-leave 0.3s ease-in both; pointer-events: none; }

/* ── splash_3 — 소셜 3종 + "다른 이메일로 계속" + 약관 링크. 시안 T-0 5811:5380(2026-10-19) — 묶음 top 422 · 폭 335 ·
   간격 28 · 약관 링크는 40 아래(top 679, 높이 18) → 아래끝 = 보이는 높이 − 23 ── */
.login {
  position: absolute;
  z-index: 1;
  left: 20px;
  bottom: calc(23px + var(--ui-gap));
  width: 335px;
}
/* 약관 링크 — 위 묶음과 40(묶음 간격 28 + 12) */
.login__stack .link-legal,
.splash-choice .link-legal { margin-top: 12px; }
.login__stack {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 28px;
  animation: cta-rise 0.55s ease-out both;
}

/* ══════════════ 질문 카피 ══════════════ */

.prompt {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  width: 324px;
}
.prompt--center { align-items: center; text-align: center; gap: var(--space-sm); }
.prompt__label {
  width: 100%;
  font-size: 14px;
  font-weight: 500;
  line-height: 30px;
  color: var(--color-white-60);
}
.prompt__title {
  width: 100%;
  font-size: 20px;
  font-weight: 500;
  line-height: 30px;
  color: var(--color-white-60);
}
.prompt__title em {
  font-style: normal;
  color: var(--color-white-100);
}
.prompt--center .prompt__label { line-height: 20px; }

/* ── 온보딩(언어·이메일·닉네임) 공용 — 큰 타이틀이 위, 옅은 설명이 아래 (Figma nickname_*, email_3) ──
   기존 .prompt__label·__title은 그대로 두고, 이 화면들에서만 크기·순서·색을 새로 맞춘다. */
.prompt--onboarding2 { width: 335px; gap: 8px; }
/* 2026-09-03: 화면 타이틀은 accent/head1/SB-24다 (Figma 3183-23239 · 3085-5228 · 3183-13830 공통).
   구 EASTARJET Heavy 24px에서 Hahmlet SemiBold로 바뀌었다. */
.prompt--onboarding2 .prompt__title {
  font-family: var(--font-accent);
  font-weight: 600;
  font-size: 24px;
  line-height: 1.3;
  letter-spacing: -0.01em;
  color: var(--color-white-100);
}
.prompt--onboarding2 .prompt__title em,
.prompt--onboarding2 .prompt__label em { font-style: normal; color: inherit; }
/* 부제는 accent/body2/R-16. ⚠️ 언어 선택 화면만 base/body1/R-16이라 아래 --base로 덮는다
   (Figma 3183-13842는 NEXON Regular, 나머지 온보딩 화면은 Hahmlet Regular다). */
.prompt--onboarding2 .prompt__label {
  font-family: var(--font-accent);
  font-size: 16px;
  font-weight: 400;
  line-height: 1.5;
  letter-spacing: -0.01em;
  color: rgba(255, 255, 255, 0.5);
}
.prompt--onboarding2 .prompt__label--base {
  font-family: var(--font-base);
  letter-spacing: 0.01em;
}

/* 언어 · 이메일(회원가입 · 로그인) · 닉네임(정보 입력) 공통 배경 — Figma email_1 4357-13539 (2026-10-06 네이비).
   세 겹: 라디얼 바탕(#2A4D7D → #0A0C18, 오른쪽 위 밖에서) → 질감 이미지(50% · darken) → 오른쪽 위 빛 타원(30° · 번짐 60).
   좌표는 시안 y − 62. 라디얼은 시안의 기울어진 타원(svg gradientTransform)을 375 × 812 판 그대로 깐다 —
   CSS radial-gradient 로는 타원을 기울일 수 없다. 판 아래로 길어진 화면은 종점색이 잇는다.
   ⚠️ 질감의 darken 합성이 라디얼과 섞이려면 둘이 한 묶음 안에 있어야 한다 — 라디얼을 이 상자(.screen--onboarding2__bg) 바탕에 둔다. */
.screen--onboarding2 {
  background: #0A0C18; /* ⚠️ non-token: 시안 라디얼 종점 */
  overflow: hidden;
}
.screen--onboarding2__bg {
  position: absolute;
  z-index: 0;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  /* ⚠️ non-token: 시안 radialGradient 스톱 원본값 */
  background:
    url("data:image/svg+xml;utf8,<svg viewBox='0 0 375 812' xmlns='http://www.w3.org/2000/svg' preserveAspectRatio='none'><rect x='0' y='0' height='100%' width='100%' fill='url(%23g)'/><defs><radialGradient id='g' gradientUnits='userSpaceOnUse' cx='0' cy='0' r='10' gradientTransform='matrix(-25.8 41.15 -35.071 -21.989 445 -29.5)'><stop stop-color='rgb(42,77,125)' offset='0'/><stop stop-color='rgb(34,61,100)' offset='0.22356'/><stop stop-color='rgb(26,45,75)' offset='0.44713'/><stop stop-color='rgb(18,28,49)' offset='0.67069'/><stop stop-color='rgb(10,12,24)' offset='0.89426'/></radialGradient></defs></svg>")
      0 calc(-62px + var(--safe-top)) / 375px 812px no-repeat,
    #0A0C18;
}
/* 질감(background) 426 × 1060 — 시안 left calc(62.5% − 29.38px) 를 가운데로 · top −124(앱 −186) · 50% · darken */
.onb-bg__texture {
  position: absolute;
  top: calc(-186px + var(--safe-top));
  left: -8.005px;
  width: 426px;
  height: 1060px;
  max-width: none;
  object-fit: cover;
  opacity: 0.5;
  mix-blend-mode: darken;
}
/* 빛 타원(Ellipse 1623) 644 × 493 · 30° — 회전 상자(가운데 x 337.005 · top −426(앱 −488) · 804.22 × 748.951)의 가운데.
   svg 884 × 733 은 타원 + 블러 여백 */
.onb-bg__glow {
  position: absolute;
  top: calc(-480.025px + var(--safe-top));
  left: -104.995px;
  width: 884px;
  height: 733px;
  max-width: none;
  rotate: 30deg;
}
.screen--onboarding2 .screen__header,
.screen--onboarding2 .screen__body,
.screen--onboarding2 .screen__cta { position: relative; z-index: 1; }

/* ══════════════ 로그인 — 인증 수단 버튼 ══════════════ */

/* Figma splash_3 4981-61409 — 48px 고정 높이 · 335px 폭 · 아이콘 16px · 간격 12 */
.auth-stack {
  display: flex;
  flex-direction: column;
  gap: 12px;
  width: 335px;
}
.auth-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  height: 48px;
  padding: 16px 12px;
  border: none;
  border-radius: 999px;
  font-family: var(--font-base);
  font-weight: 500;
  font-size: 16px;      /* base/body1/M-16 */
  line-height: 1.5;
  letter-spacing: 0.08px;
  cursor: pointer;
}
.auth-btn__icon { display: block; width: 16px; height: 16px; flex-shrink: 0; }
.auth-btn__label { white-space: nowrap; }

/* ⚠️ non-token: 외부 브랜드 고정색(카카오 #FEE500 · 네이버 #03C75A)이라 토큰화 대상이 아니다.
   구글 · 카카오의 밝은 면은 색 대신 단색 그림으로, 검은 글자는 검정 그라디언트를 글자에 클립해서 칠한다 — 밝은 CSS 면과
   어두운 단색 글자는 삼성 인터넷 강제 다크 모드에서 뒤집힌다(tokens.css --paint-*). 로고 그림도 같은 규칙으로 다시 썼다. */
.auth-btn--google { background: var(--paint-white) border-box; border: 1px solid transparent; color: #000; }
.auth-btn--kakao  { background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Crect width='100%25' height='100%25' fill='%23FEE500'/%3E%3C/svg%3E"); color: #000; }
.auth-btn--naver  { background: #03C75A; color: var(--white); }
:is(.auth-btn--google, .auth-btn--kakao) .auth-btn__label {
  background: linear-gradient(#000, #000);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* 밑줄 텍스트 링크 — "다른 이메일로 계속"(splash_3) · "이미 계정이 있으신가요?"(splash_2). base/body2/R-14 · 밑줄 0.4 */
.auth-email {
  padding: 0;
  border: 0;
  /* 흰 밑줄 0.4 — 테두리 칸은 투명하게 두고 그 자리에 흰 단색 그림을 깐다(밝은 테두리는 강제 다크에서 어두워진다) */
  border-bottom: 0.4px solid transparent;
  background: var(--paint-white) 0 100% / 100% 0.4px no-repeat border-box;
  font-family: var(--font-base);
  font-weight: 400;
  font-size: 14px;
  line-height: 1.5;
  letter-spacing: 0.14px;
  text-align: center;
  white-space: nowrap;
  color: var(--white);
  cursor: pointer;
}

/* ══════════════ QR 발급 화면 ══════════════ */

.qr-plate {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-md);
  width: 323px;
  padding: var(--space-lg);
  border-radius: 24px;
  border: 1px solid rgba(215, 247, 255, 0.16); /* ⚠️ blue-300 hue @0.16 — ResultCard 글래스 패널과 동일 */
  background: linear-gradient(90deg,
    rgba(153, 228, 255, 0.12) 0%, rgba(48, 48, 48, 0.12) 50%, rgba(153, 228, 255, 0.12) 100%);
  backdrop-filter: blur(4px);
  animation: qr-pop 0.5s ease-out both;
}
@keyframes qr-pop {
  from { opacity: 0; transform: translateY(10px) scale(0.98); }
  to   { opacity: 1; transform: none; }
}
/* ⚠️ asset 필요: 실제 QR 이미지. DS ResultCard와 동일한 체크 패턴 플레이스홀더. */
.qr-plate__code {
  width: 189px;
  height: 189px;
  border-radius: var(--radius-sm);
  background: repeating-conic-gradient(#ccc 0% 25%, #eee 0% 50%) 0 0 / 20px 20px;
}
.qr-plate__meta {
  font-size: 13px;
  font-weight: 500;
  line-height: 20px;
  letter-spacing: -0.24px;
  color: var(--color-blue-300);
}

/* DS Box의 별 배지는 아이콘 에셋 자리(10×10). 에셋이 들어오기 전까지 글리프로 채운다.
   ⚠️ asset 필요: icon_star_fill */
.box__star {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 8px;
  line-height: 1;
  color: var(--color-blue-300);
}

/* ══════════════ 홈 — Figma wand_before 4981-54844 · wand_after 4981-56403 · 나의 QR 4981-54982
                 · 스크롤 레이아웃 wand_before_full 4981-55872 (2026-10-06 네이비) ══════════════
   세로로 스크롤되는 한 장이다(.screen--home 이 스크롤 상자, .home-page 가 그 안의 판).
     헤더(모자) → 로고 → 콘텐츠 프레임(아트 262 · 캡션 67) → 아이콘 레일 → 아래 화살표 → 나의 QR
   색은 HP Mobile 네이비 체계(design-system/tokens.css)를 쓴다. 좌표·간격은 시안 y − 62(상태바)다 —
   시안 위치: 헤더 20 · 로고 83 · 프레임 174 · 레일 510 · 화살표 608 · 나의 QR 666. */

.screen--home {
  --edge: var(--background-chrome);   /* 사파리 상하 바 — 시안의 상태바·툴바 색 #030A11 */
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior-y: contain;
  scrollbar-width: none;   /* 폰은 겹쳐 뜨는 스크롤바라 폭을 안 먹는다 — 데스크톱에서도 같게 숨긴다 */
  background: var(--background-canvas-end);
}
.screen--home::-webkit-scrollbar { display: none; }
.home-page {
  position: relative;
  z-index: 1;   /* 섹션 배경(.home-bg) 위 */
  display: flex;
  flex-direction: column;
  align-items: center;
  flex-shrink: 0;
  width: 100%;
  overflow: hidden;   /* 칸보다 큰 아트(패트로누스 후)가 판 밖으로 스크롤을 늘리지 않게 */
  /* 시안 home_pr 은 나의 QR 을 화면 위 216 까지 올려 보여 준다 — 그만큼 내려갈 수 있게 아래를 남긴다 */
  padding-bottom: calc(112px + var(--safe-bottom));
  /* 긴 화면에서 나의 QR 이 시안 자리(666)보다 내려가는 만큼 — 화살표 · 나의 QR 이 함께 내려간다 */
  --myqr-shift: max(0px, calc(var(--screen-h) - 658px));
}
.home-page > * { position: relative; z-index: 1; }

/* ── 섹션 배경 — 보고 있는 콘텐츠마다 다르다. 스크롤해도 화면에 붙어 있다 ──
   시안의 나의 QR 화면들(5070-22964 등)이 첫 화면과 **같은 자리**의 배경이라, 판(.home-page)과 같이 움직이지 않게
   스크롤 상자(.screen--home) 맨 위에 sticky 로 붙이고 판이 그 위로 올라오게 겹친다(아래 여백 −보이는 높이).
   콘텐츠를 넘기면 그 콘텐츠의 묶음(.home-bg__set)만 .is-on 으로 켜지고 0.3초에 걸쳐 위에서 덮는다.
   2026-10-12: 묶음마다 **시안 배경 한 장**(375 × 812, Figma 가 그린 그대로 — index.html 주석)을 시안 y − 62 에 깐다.
   판 아래(키 큰 화면에서 812 를 넘는 자리)는 그 그림 맨 아랫줄 색(--bg-tail)으로 이어 칠한다. */
.screen--home > .home-bg {
  position: sticky;
  top: 0;
  z-index: 0;
  flex-shrink: 0;
  width: 100%;
  height: var(--screen-h);
  margin-bottom: calc(-1 * var(--screen-h));
  overflow: hidden;
  pointer-events: none;
}
.home-bg__set {
  position: absolute;
  inset: 0;
  opacity: 0;
  visibility: hidden;
  background: var(--bg-tail, var(--background-canvas-end));
}
/* 2026-10-21: 새 묶음이 **위에서** 0.3초에 덮고, 옛 묶음은 그 아래에 지금 진하기 그대로(.is-under, 진하기는 app.js 가
   인라인으로 붙잡는다) 있다가 다 덮이면 한꺼번에 꺼진다. 예전엔 둘이 같이 0.5초에 걸쳐 흐려져 그림이 다 바뀐(0.25초)
   뒤에도 옛 배경이 비쳤다. */
.home-bg__set.is-under { visibility: visible; }
.home-bg__set.is-on { z-index: 1; opacity: 1; visibility: visible; transition: opacity 0.3s ease; }
.home-bg__set img { position: absolute; top: calc(-62px + var(--safe-top)); left: 0; display: block; width: 375px; height: 812px; max-width: none; }
/* ⚠️ non-token: 각 배경 그림의 맨 아랫줄 색(3배 그림 아래 6px 평균) — 판 아래를 이어 칠한다.
   2026-10-15 완드 · 초상화 · 퀴디치는 그림 바닥에 시안 하단 툴바 뒤 흐림(밝은 띠)이 구워져 있어 잘려 보였다 —
   띠(1x y 757 · 725 · 749 아래)를 위쪽 장면의 색으로 이어 다시 그리고(결은 거울로 잇다 서서히 지움), 꼬리색도 그 색으로 바꿨다. */
.home-bg__set[data-bg="wand"] { --bg-tail: #0E131F; }
.home-bg__set[data-bg="potion"] { --bg-tail: #6D5F7C; }
.home-bg__set[data-bg="patronus"] { --bg-tail: #2C4C78; }
.home-bg__set[data-bg="house"] { --bg-tail: #685D4F; }
.home-bg__set[data-bg="frame"] { --bg-tail: #51453C; }
.home-bg__set[data-bg="quidditch"] { --bg-tail: #604F72; }
/* 홈 화면에 추가했을 때 쓰는 따로 그림(index.html <picture> 의 standalone 소스)의 맨 아랫줄 색 — 그림을 고르는 조건과
   같은 미디어 쿼리로 묶는다. 물약은 원래 그림과 같은 색이다. 키 큰 화면(812 + 상태바 − 62 보다 긴)에서 그림 아래를 칠한다. */
@media (display-mode: standalone) {
  .home-bg__set[data-bg="wand"] { --bg-tail: #0F1521; }
  .home-bg__set[data-bg="frame"] { --bg-tail: #735939; }
  .home-bg__set[data-bg="quidditch"] { --bg-tail: #705B83; }
}
@media (prefers-reduced-motion: reduce) { .home-bg__set, .home-bg__set.is-on { transition: none; } }

/* 헤더 — 모자 마름모 하나가 오른쪽에 선다(QR 마름모는 나의 QR 섹션으로 갔다). 여백은 Figma Header 4981-54865 */
.header--home {
  justify-content: flex-end;
  /* 시안의 상태바(62)는 사파리가 그리므로 화면 맨 위가 앱 영역의 0 이다. 헤더 자체 여백은 2(높이 2+53+2=57). */
  padding: calc(2px + var(--safe-top)) 20px 2px;
}
/* 홈은 시안의 상태바↔헤더 간격을 더 얹는다(26-09-18 에 22 → 20). */
.screen--home .header--home { padding-top: calc(20px + var(--safe-top)); }

/* 로그인은 배경 아트 위에 헤더가 얹히는 화면이라, 헤더가 레이아웃 높이를 차지하면
   아래 약관 문구가 화면 밖으로 밀린다 — 자리만 띄우고 흐름에서는 뺀다. */
[data-step="login"] .screen__header {
  position: absolute;
  top: 0;
  left: 0;
}
.header__spacer { display: block; width: 30px; height: 30px; }

/* 로고 — Figma HP_TITLE_GOLD_F (200 × 85). 홈 간격은 house_after 6021-9721(2026-10-23)을 따른다 — 앱 좌표(시안 − 62):
   헤더 아래끝 75 · 로고 79 ~ 164 · 칸(아트 줄) 175 ~ 405 · 캡션 417 ~ 489 · 레일 507 ~ 593 · 화살표 그림 609
   (전: 로고 83 · 칸 174 · 캡션 416 · 레일 510 · 화살표 608) */
.home-logo {
  display: block;
  width: 200px;
  height: 85px;
  margin-top: 4px;   /* 헤더 아래끝 75 → 79 */
  object-fit: contain;
}

/* 스크롤하면 위쪽 판(모자 · 로고 · 콘텐츠 칸 · 레일)이 50% 로 가라앉는다 — 시안 나의 QR 화면들의 위쪽 묶음 opacity 50%
   (2026-10-06 섹션 배경 시안, 전: home_pr 80%) */
.header--home, .home-logo, .home { transition: opacity 0.3s ease; }
.screen--home.is-scrolled :is(.header--home, .home-logo, .home) { opacity: 0.5; }
/* 아래 화살표는 나의 QR 로 내려오면 사라진다 — 시안 나의 QR 화면들에 화살표가 없다 */
.home-scroll-hint { transition: opacity 0.3s ease; }
.screen--home.is-scrolled .home-scroll-hint { opacity: 0; pointer-events: none; }

.home {
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
}

/* ── 콘텐츠 프레임 — 모양(아트 줄 · 칸 · 아트 · 자물쇠 안내 · 캡션)은 디자인시스템 .home-frame 이다
   (components.css · Figma contentframe 4981-55577, 2026-10-23 옮김). 홈 자리 · 칸 넘김 · 떠다니기만 여기서 잡는다. ── */
.home-frame { margin-top: 11px; }   /* 로고 그림 아래끝 164 → 175 (Figma house_after 6021-9721, 2026-10-23 — 전 168 → 174) */
.home-box { touch-action: pan-y; } /* 가로 끌기는 스와이프(app.js)가 받는다 — 세로는 화면 스크롤 */
.home-slide__open {
  position: absolute;
  inset: 0;
  border: 0;
  background: none;
  cursor: pointer;
}
/* 칸을 갈아끼우는 연출 — 새 칸은 가는 방향에서 40px 미끄러져 들어오고, 옛 칸은 반대쪽으로 빠지며 사라진다.
   2026-10-21: 옛 칸은 처음부터 빨리 빠지고(ease-out 0.12초) 새 칸은 0.06초 뒤에 들어온다 — 예전(옛 칸 ease-in 0.22초)엔
   0.12초쯤 옛 그림 63% · 새 그림 90% 로 같은 자리에 겹쳐 잔상처럼 보였다. */
.home-slide.is-entering-right { animation: home-slide-in-right 0.28s cubic-bezier(0.2, 0.7, 0.2, 1) 0.06s both; }
.home-slide.is-entering-left  { animation: home-slide-in-left  0.28s cubic-bezier(0.2, 0.7, 0.2, 1) 0.06s both; }
.home-slide.is-leaving-left   { animation: home-slide-out-left  0.12s ease-out both; pointer-events: none; }
.home-slide.is-leaving-right  { animation: home-slide-out-right 0.12s ease-out both; pointer-events: none; }
@keyframes home-slide-in-right { from { opacity: 0; transform: translateX(40px); }  to { opacity: 1; transform: none; } }
@keyframes home-slide-in-left  { from { opacity: 0; transform: translateX(-40px); } to { opacity: 1; transform: none; } }
@keyframes home-slide-out-left  { to { opacity: 0; transform: translateX(-40px); } }
@keyframes home-slide-out-right { to { opacity: 0; transform: translateX(40px); } }

/* 아트는 물 위에 뜬 것처럼 위아래로 천천히 움직인다 — transform 은 가로 가운데 정렬이 쓰므로 translate 로 따로 흔든다 */
.home-slide__art { animation: home-slide-float 4.2s ease-in-out infinite; }
@keyframes home-slide-float {
  0%, 100% { translate: 0 0; }
  50%      { translate: 0 -7px; }
}
@media (prefers-reduced-motion: reduce) {
  .home-slide__art { animation: none; }
  .home-slide.is-entering-right, .home-slide.is-entering-left,
  .home-slide.is-leaving-left, .home-slide.is-leaving-right { animation: none; }
}

/* ── 패트로누스 체험 전 — 구체 안이 오묘하게 변한다 (2026-10-26 · Figma patronus_before 5070-28763) ──
   구체 그림을 WebGL 캔버스로 그려 안쪽 안개 결이 천천히 번지며 바뀐다(app.js startPatronusOrb · 테는 그대로).
   캔버스가 첫 장을 그리면(is-live) 그림(<img>)과 자리를 바꾼다 — 그 전 · WebGL 이 없을 때 · 동작 줄이기면 그림 한 장이다. */
.home-orb { display: block; }
.home-orb__img,
.home-orb__gl { position: absolute; inset: 0; display: block; width: 100%; height: 100%; }
.home-orb__gl { visibility: hidden; }
.home-orb.is-live .home-orb__gl { visibility: visible; }
.home-orb.is-live .home-orb__img { visibility: hidden; }

/* ── 아이콘 레일 — 디자인시스템 components.css 로 옮겼다(2026-10-14 — 디자인시스템 페이지에서도 같은 규칙으로 그리려고).
   홈 배치(캡션 아래 18)만 여기 남긴다. ── */
.home .home-rail { margin-top: 18px; }   /* 캡션 자리 아래끝 489 → 507 (전: 67 자리 483 + 27) */

/* ── 아래 화살표 (Figma Vector 789 4981-54980) — 나의 QR 로 내려간다. 그림 26 × 15, 누를 자리는 사방 10 더 ──
   시안은 보이는 높이 658(사파리) 기준으로 그림을 화면 끝에서 49 위(609)에 둔다. 화면이 더 긴 기기
   (홈 화면에 추가한 전체 화면 등)에서는 그 관계를 지켜 **화면 맨 아래로 따라 내려간다** — 그래야 바로 아래의
   나의 QR 이 첫 화면에 비치지 않는다(2026-10-06 결정). 짧은 기기에서는 시안 간격(2)을 지킨다.
   --screen-h 는 app.js syncAppScale 이 넣는 "실제로 보이는 높이"다. */
.home-scroll-hint {
  display: grid;
  place-items: center;
  width: 46px;
  height: 35px;
  margin-top: calc(6px + var(--myqr-shift));   /* 레일 아래끝 593 → 버튼 윗변 599(그림 609) = 보이는 높이 − 59 */
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}
/* svg 는 15 × 26 세로 그림이다 — 시안처럼 90° 돌리고 세로로 뒤집어 아래를 가리키게 한다 */
.home-scroll-hint img { display: block; width: 15px; height: 26px; transform: rotate(90deg) scaleY(-1); }

/* ── 나의 QR — 모양은 디자인시스템 .home-myqr(components.css · Figma myqr 5743-52170)이다. 자리만 여기서 잡는다. ── */
.home-myqr {
  margin-top: 32px;   /* 화살표 버튼 아래끝 634 → 나의 QR 윗변 = 보이는 높이 + 8 (사파리 658 에서 시안 666) */
}

/* ══════════════ 홈 첫 안내 — 코치마크 (2026-10-19 · 시안 2026-10-20 Figma coach 6064:25290 · home_coach_1 · _2) ══════════════
   닉네임을 정하고 홈에 처음 들어올 때 한 번(app.js 홈안내). 홈 위를 navy_950 80% 로 덮고 구멍 하나만 밝게 남긴다 —
   구멍(.coach__spot)의 바깥 그림자가 곧 딤이라, 구멍이 자리 · 크기를 옮기면 딤도 같이 따라간다.
   테두리는 아이스 빛(ice_200)으로 두르고 바깥으로 한 번씩 번진다(홈 아트가 떠오르듯 천천히).
   말풍선은 카드 면(surface/card)에 Tip 표 · 닫기를 얹고, 제목 · 본문 모두 base(NEXON)다.
   .app 안에서 fixed 로 덮는다(.sheet 와 같은 자리 규칙 — 확대를 따라간다). */
.coach {
  position: fixed;
  inset: 0;
  z-index: 19;   /* 화면 위 · 결과 시트(20) · 동의(21) 아래 */
  overflow: hidden;
  touch-action: none;   /* 안내 중에는 홈이 스크롤되지 않는다 — 단계가 정한 자리에서 본다 */
  opacity: 0;
  transition: opacity 0.4s ease;
}
.coach[hidden] { display: none; }
.coach.is-on { opacity: 1; }

/* 구멍 — 자리 · 크기 · 모서리는 app.js 가 넣는다(--spot-*). 단계를 옮기면 홈 스크롤과 같은 시간에 미끄러진다 */
.coach__spot {
  position: absolute;
  top: var(--spot-y, 50%);
  left: var(--spot-x, 50%);
  width: var(--spot-w, 0px);
  height: var(--spot-h, 0px);
  border-radius: var(--spot-r, 24px);
  box-shadow:   /* 1px 고리(ice/200 55%)는 ::before 가 그린다 — 아래 「고리 테두리」 */
    0 0 28px 2px color-mix(in srgb, var(--ice-200) 22%, transparent),
    0 0 0 200vmax color-mix(in srgb, var(--navy-950) 80%, transparent);   /* 딤 */
  pointer-events: none;
  /* 조리개 — 닫힐 때(점으로)와 열릴 때 같은 0.36초. app.js COACH_IRIS 와 같은 값 */
  transition:
    top 0.36s cubic-bezier(0.4, 0, 0.2, 1),
    left 0.36s cubic-bezier(0.4, 0, 0.2, 1),
    width 0.36s cubic-bezier(0.4, 0, 0.2, 1),
    height 0.36s cubic-bezier(0.4, 0, 0.2, 1),
    border-radius 0.36s cubic-bezier(0.4, 0, 0.2, 1);
}
/* 닫힌 점을 새 자리에 놓을 때는 움직이지 않는다 */
.coach__spot.is-instant { transition: none; }
/* 번지는 테두리 — 2.4초마다 바깥으로 한 번 */
.coach__spot { --ring: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Crect width='100%25' height='100%25' fill='%23C2E2FF' fill-opacity='0.55'/%3E%3C/svg%3E"); }
.coach__spot::after {   /* 퍼지는 고리 ice/200 70% — 「고리 테두리」와 같은 마스크로 */
  content: "";
  position: absolute;
  inset: -1px;
  padding: 1px;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Crect width='100%25' height='100%25' fill='%23C2E2FF' fill-opacity='0.7'/%3E%3C/svg%3E");
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
  border-radius: inherit;
  animation: coach-pulse 2.4s ease-out infinite;
}
@keyframes coach-pulse {
  0%   { opacity: 0.8; transform: scale(1); }
  70%  { opacity: 0; transform: scale(1.06); }
  100% { opacity: 0; transform: scale(1.06); }
}

/* 말풍선 — Figma coach 6064:25290(2026-10-20). 폭 335(화면 여백 20) · 위치(top)와 꼬리 자리(--caret-x)는 app.js 가 넣는다.
   맨 위 Tip 표 · 닫기(12) → 제목 · 본문(4) → (16) 단계 수 · 다음. 테두리 1 은 안쪽 여백에서 뺀다(시안 여백 16 · 20, 높이 186). */
.coach__card {
  position: absolute;
  top: var(--card-y, 0);
  left: 20px;
  display: flex;
  flex-direction: column;
  width: 335px;
  padding: 15px 19px;
  box-sizing: border-box;
  border: 1px solid transparent;   /* slate/600 24% — 아래 「고리 테두리」 */
  --ring: linear-gradient(color-mix(in srgb, var(--slate-600) 24%, transparent), color-mix(in srgb, var(--slate-600) 24%, transparent));
  border-radius: 12px;
  background: var(--surface-card);
  /* 꼬리까지 한 덩이로 번지게 filter 로 — ⚠️ non-token: 시안 말풍선 빛(흰 20% · 3) */
  filter: drop-shadow(0 0 3px rgba(255, 255, 255, 0.2));
  transition: opacity 0.26s ease, transform 0.26s ease;
}
/* 단계를 옮기는 동안 — 말풍선은 잠깐 내려앉아 사라졌다가 새 자리에서 떠오른다 */
.coach.is-moving .coach__card,
.coach:not(.is-on) .coach__card { opacity: 0; transform: translateY(8px); pointer-events: none; }
/* 꼬리 — 구멍 쪽 변에 붙는 16 마름모(가운데가 변 위 — 11 튀어나온다). 말풍선이 구멍 아래면 위 변(.is-below), 위면 아래 변 */
.coach__caret {
  position: absolute;
  left: var(--caret-x, 50%);
  bottom: -9px;
  width: 16px;
  height: 16px;
  margin-left: -9px;   /* 반 폭 8 + 말풍선 테두리 1(left 는 테두리 안쪽에서 잰다) — 꼬리 가운데가 구멍 가운데 */
  /* 오른쪽 · 아래 1px 선(slate/600 24%)은 테두리 칸에 깐 그라디언트 — 어두운 테두리 색은 강제 다크에서 밝게 뒤집힌다 */
  border: solid transparent;
  border-width: 0 1px 1px 0;
  --caret-line: color-mix(in srgb, var(--slate-600) 24%, transparent);
  background:
    linear-gradient(var(--caret-line), var(--caret-line)) 100% 0 / 1px 100% no-repeat border-box,
    linear-gradient(var(--caret-line), var(--caret-line)) 0 100% / 100% 1px no-repeat border-box,
    var(--surface-card);
  transform: rotate(45deg);
}
.coach__card.is-below .coach__caret {
  top: -9px;
  bottom: auto;
  border-width: 1px 0 0 1px;
  background-position: 0 0, 0 0;   /* 선이 왼쪽 · 위로 */
}

/* Tip 표 · 닫기 */
.coach__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 20px;
  margin-bottom: 12px;
}
.coach__tag {
  display: inline-flex;
  align-items: center;
  height: 20px;
  padding: 0 10px;
  box-sizing: border-box;
  border-radius: var(--radius-full);
  background: var(--paint-ice-200);   /* ice/200 단색 그림 — 글자는 아래 __tag-label(강제 다크 대비 · tokens.css --paint-*) */
  /* base Medium 11 */
  font-family: var(--font-base);
  font-weight: 500;
  font-size: 11px;
  line-height: 1.5;
  letter-spacing: 0.005em;
  color: var(--navy-950);
}
/* 글자 — 글자색을 그라디언트로 클립한다. 어두운 단색 글자는 삼성 인터넷 강제 다크 모드에서 밝게 뒤집혀 밝은 면 위에서 사라진다 */
.coach__tag-label,
.coach__next-label {
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.coach__tag-label { background-image: linear-gradient(var(--navy-950), var(--navy-950)); }
.coach__next-label { background-image: linear-gradient(var(--navy-700), var(--navy-700)); }
/* 닫기 — 그림은 20, 누를 자리는 사방 10 더(40) */
.coach__close {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  margin: -10px;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}
.coach__close img { display: block; width: 20px; height: 20px; }

.coach__title {
  margin: 0;
  word-break: keep-all;
  /* base/body1/B-16 */
  font-family: var(--font-base);
  font-weight: 700;
  font-size: 16px;
  line-height: 1.5;
  letter-spacing: 0.005em;
  color: var(--text-primary);
}
.coach__body {
  margin: 4px 0 0;
  word-break: keep-all;
  /* base/body2/R-14 */
  font-family: var(--font-base);
  font-weight: 400;
  font-size: 14px;
  line-height: 1.5;
  letter-spacing: 0.01em;
  color: var(--gray-200);
}
.coach__body b { font-weight: 500; letter-spacing: 0.005em; color: var(--text-accent); }

.coach__actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: 16px;
}
/* 단계 수 — 지금 단계만 흰색(1/2) */
.coach__count {
  margin: 0;
  padding: 6px 0;
  /* base/body2/R-14 */
  font-family: var(--font-base);
  font-weight: 400;
  font-size: 14px;
  line-height: 1.5;
  letter-spacing: 0.01em;
  color: var(--gray-200);
}
.coach__count b { font-weight: 400; color: var(--text-primary); }
/* 다음 · 시작하기 */
.coach__next {
  height: 36px;
  padding: 0 18px;
  border: 0;
  border-radius: var(--radius-full);
  background: var(--paint-purple-100);   /* ⚠️ non-token: 시안 다음 버튼 면(Figma scanner/token/purple-100) — 단색 그림, 글자는 __next-label */
  /* base/body2/M-14 */
  font-family: var(--font-base);
  font-weight: 500;
  font-size: 14px;
  line-height: 1.5;
  letter-spacing: 0.005em;
  color: var(--navy-700);
  cursor: pointer;
}
.coach__next:active { transform: translateY(1px); }
.coach__next:focus-visible,
.coach__close:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }

@media (prefers-reduced-motion: reduce) {
  .coach, .coach__spot, .coach__card { transition: none; }
  .coach__spot::after { animation: none; opacity: 0; }
}

/* ══════════════ 콘텐츠 상세 시트 ══════════════ */

.sheet {
  position: fixed;
  inset: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: center;
}
.sheet__scrim {
  position: absolute;
  inset: 0;
  background: var(--surface-scrim);   /* 2026-10-07 딤 하나로(전: black_60 = #0E0E0F 50%) */
  backdrop-filter: blur(6px);
}
.sheet__panel {
  position: relative;
  max-height: var(--screen-h);
  padding: var(--space-lg) 0;
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior-x: none;
  /* ⚠️ fill을 both가 아니라 backwards로 둔다 — 애니메이션이 끝난 뒤에도 transform이
     항등행렬로 **남아 있으면** 이 패널이 position:fixed의 포함 블록이 되고, 그러면
     안에 든 position:fixed 요소가 스크롤을 따라 흘러가 버린다.
     backwards는 시작 전 상태만 유지하고 끝나면 transform을 놓아준다(= none). */
  animation: sheet-in 0.28s ease-out backwards;
}
@keyframes sheet-in {
  from { opacity: 0; transform: translateY(24px); }
  to   { opacity: 1; transform: none; }
}

/* 결과 상세 화면은 풀스크린 — 시트 여백을 제거한다 */
.sheet__panel:has(.wres1),
.sheet__panel:has(.wres),
.sheet__panel:has(.dreveal),
.sheet__panel:has(.qreveal),
.sheet__panel:has(.hres1),
.sheet__panel:has(.hres),
.sheet__panel:has(.pres1),
.sheet__panel:has(.pres),
.sheet__panel:has(.pat1),
.sheet__panel:has(.pat),
.sheet__panel:has(.hphoto) { padding: 0; }

/* ══════════════ 축 목록 (옛 테스트 완료 화면의 잔재 — .testdone 규칙은 2026-09-17 정리) ══════════════ */
.axis-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
  width: 100%;
  padding: var(--space-md) 0;
}

/* ══════════════ 토스트 ══════════════
   모양은 디자인시스템 .toast(components.css — Figma toast 3903:27089, 성공 · 실패)다. 여기서는 자리 · 등장만 정한다.
   2026-10-21 전: 임시 토스트(남색 반투명 상자 · 장식 없음). */

.scope-toast {
  position: fixed;
  left: 50%;
  bottom: calc(100px + var(--ui-gap));
  display: flex;
  justify-content: center;
  width: max-content;
  transform: translate(-50%, 16px);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease, transform 0.2s ease;
  z-index: 40;
}
.scope-toast.is-visible {
  opacity: 1;
  transform: translate(-50%, 0);
}

/* ══════════ 완드 결과 첫 장 (Figma result/hollywand/completed1 4357:15159, 2026-10-20) ══════════
   밤하늘 위에 지팡이 한 자루가 떠 있고 끝의 빛이 숨쉰다 — 10-13 걷었던 완드 소팅(.wsort, 시안 3837-16839)을
   첫 장으로 되살렸다(app.js wandFirstHtml). 그림 · 빛 자리 · 숨쉬기는 그때 디자이너와 맞춘 그대로다.
   좌표는 전부 시안 y − 62(상태바). 문장 · 지팡이 · tap 은 다른 첫 장(.hres1)과 같은 물결로 뜬다 —
   그래서 가운데 맞춤을 transform 이 아니라 left 로 한다(등장 연출이 transform 을 쓴다). */
.wres1 {
  position: relative;
  width: 375px;
  min-height: var(--screen-h);
  overflow: hidden;
  cursor: pointer;
  /* 시안 Fill — 오른쪽 위 모서리를 중심으로 한 타원 그라디언트(.wres 와 같다) */
  background: radial-gradient(ellipse 505px 430px at 375px 0, #060109 0%, #040105 89.4%);
}

/* ── 배경 세 겹 — 셋 다 svg · png 가 블러 여백을 품고 있어 자리 상자보다 크게 그린다(시안 inset 그대로) ── */
.wres1__beam,
.wres1__glow,
.wres1__stars { position: absolute; z-index: 0; display: block; pointer-events: none; }
/* 위에서 내려오는 빛기둥 — 시안은 세로로 뒤집어 쓴다. 홈 화면에 추가하면 그림이 따로라(진하기 · 색) 배경으로 깐다. */
.wres1__beam {
  top: -276px;          /* 시안 −214 */
  left: 0;
  width: 375.254px;
  height: 466px;
  transform: scaleY(-1);
}
.wres1__beam::before {
  content: '';
  position: absolute;
  inset: -12.55% -19.45% -15.66% -19.45%;
  background: url('assets/result/wand/beam-top.svg') center / 100% 100% no-repeat;
}
/* 아래쪽 타원 빛무리 */
.wres1__glow {
  top: 462px;           /* 시안 524 */
  left: calc(50% - 3.5px);
  width: 644px;
  height: 493px;
  transform: translateX(-50%) scaleY(-1);
}
.wres1__glow img { position: absolute; inset: -24.34% -18.63%; width: auto; height: auto; max-width: none; }
/* 별밤 한 장 — 시안은 상자와 그림에 각각 60% 를 걸어 겹친다(합 0.36) */
.wres1__stars {
  top: -186px;          /* 시안 −124 */
  left: calc(50% + 17.5px);
  width: 426px;
  height: 1060px;
  opacity: 0.6;
  transform: translateX(-50%);
}
.wres1__stars img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0.6;
  mix-blend-mode: plus-lighter;
}

.wres1__caption {
  position: absolute;
  z-index: 1;
  top: 97px;            /* 시안 159 */
  left: calc(50% - 164px);
  width: 328px;
  margin: 0;
  /* accent/head1/SB-24 */
  font-family: var(--font-accent);
  font-weight: 600;
  font-size: 24px;
  line-height: 1.3;
  letter-spacing: -0.01em;
  text-align: center;
  color: var(--gray-200);
}

/* 지팡이 무대 — 328 정사각. 안쪽 좌표는 시안 그대로다. */
.wres1__stage {
  position: absolute;
  z-index: 1;
  top: 190.4px;         /* 시안 252.4 */
  left: calc(50% - 164px);
  width: 328px;
  height: 328px;
}
.wres1__halo {
  position: absolute;
  inset: 0;
  pointer-events: none;
}
.wres1__halo img { position: absolute; inset: -60.98%; width: auto; height: auto; max-width: none; }
/* 지팡이 컷(545 × 804)은 이미 대각선으로 그려져 있고 비율(0.678)이 시안 상자(161.617 × 240.363, 0.672)와
   거의 같아 돌리지도 눌러 넣지도 않고 그대로 채운다(시안은 가로 완드를 120° 돌려 쓰는데, 그러면 짧아 보였다 —
   2026-09-19 디자이너가 새로 준 컷). color-burn 은 지팡이를 밤하늘에 눌러 앉히는 맛이라 그대로 둔다. */
.wres1__wand {
  position: absolute;
  top: 44px;            /* 시안 34 + padding 10 */
  left: 83px;           /* 시안 73 + padding 10 */
  width: 161.617px;
  height: 240.363px;
  mix-blend-mode: color-burn;
  pointer-events: none;
}
.wres1__wand img { display: block; width: 100%; height: 100%; object-fit: contain; }
/* 지팡이 끝의 빛 — svg 안에 블러가 구워져 있다(두 겹, 전체 44%). 그냥 얹으면 탁한 회백색이라(디자이너 지적
   2026-09-19) plus-lighter 로 **더해서** 깐다. 자리는 컷 안에 그려진 불빛에 포갠다 — 원본 545 × 804 에서 가장 밝은 점
   (56, 749)이 contain 0.29654 배로 무대 (99.6, 267.1). 디자이너 지정: 살짝씩 커졌다 작아지며 숨쉰다. */
.wres1__light {
  position: absolute;
  top: 253.1px;
  left: 85.6px;
  width: 28px;
  height: 28px;
  pointer-events: none;
  animation: wres1-breathe 2.6s ease-in-out infinite;
}
.wres1__light img {
  position: absolute;
  inset: -14.29%;
  width: auto;
  height: auto;
  max-width: none;
  mix-blend-mode: plus-lighter;
}
@keyframes wres1-breathe {
  0%, 100% { transform: scale(1);    opacity: 0.8; }
  50%      { transform: scale(1.22); opacity: 1; }
}

.wres1__tap {
  position: absolute;
  z-index: 1;
  top: 575.4px;         /* 시안 637.4 */
  left: 0;
  width: 100%;
  margin: 0;
  text-align: center;
  /* Lumos Caps 24 — 시안 행간이 20 이다(글자 크기보다 작다) */
  font-family: var(--font-display);
  font-size: 24px;
  line-height: 20px;
  letter-spacing: -0.5px;
  white-space: nowrap;
  color: var(--white);
}

/* 등장 — 다른 첫 장(.hres1 · .pres1 · .pat1)과 같은 물결: 문장 → 지팡이 → (한 박자 뒤) tap, tap 은 깜빡인다 */
[data-wres1-step] { opacity: 0; transform: translateY(16px); }
.wres1.is-in [data-wres1-step] {
  opacity: 1;
  transform: none;
  transition: opacity 1.1s cubic-bezier(0.33, 1, 0.68, 1), transform 1.1s cubic-bezier(0.16, 1, 0.3, 1);
}
.wres1.is-in [data-wres1-step="1"] { transition-delay: 0.5s; }
.wres1.is-in [data-wres1-step="2"] { transition-delay: 0.7s; }
.wres1.is-in [data-wres1-step="3"] { transition-delay: 1.5s; }
.wres1.is-in .wres1__tap { animation: hres-blink 2.4s ease-in-out 2.6s infinite; }
@media (prefers-reduced-motion: reduce) {
  [data-wres1-step] { opacity: 1; transform: none; }
  .wres1.is-in [data-wres1-step] { transition: none; }
  .wres1__light,
  .wres1.is-in .wres1__tap { animation: none; }
}

/* ══════════ 완드 결과 (Figma completed1 3837-16954 · completed2 3837-17041, 2026-09-19) ══════════
   두 화면이 한 장으로 이어진 스크롤이다. 좌표는 전부 **페이지 좌표**로 옮겨 적었다 —
   페이지 y 0 = completed1 의 앱 좌표 0(= 시안 y 62).

   두 프레임을 잇는 오프셋은 494.2 다 — completed2 의 본문 블록이 앱 190(시안 252)에 서고,
   그 블록이 이어 붙인 페이지에서는 684.2 에 있다. 이때 completed1 의 주재료+본문 블록은
   앱 −121.7 에 걸쳐 보이는데, 시안이 적어 둔 −121(시안 −59)과 0.7 차이다 —
   completed1 흐름에서 쌓인 반올림이라 그대로 둔다.

   시안은 프레임이 둘이라 배경·본문·completed2 가 프레임마다 제자리에 그려져 있다. 한 장으로
   이으면 그냥 굴리는 것만으로는 그 자리들이 맞지 않는다 — 그래서 굴린 양을 --wres-y(px) 와
   --wres-t(0→1) 로 내려보내고, 층마다 제 속도로 움직인다(wireWandReveal). 그 결과가 곧
   디자이너가 말한 "아래에 있던 그라데이션이 위로 올라가는 느낌"이다. */
.wres {
  position: relative;
  width: 375px;
  /* 시트 패널 여백은 위 :has(.wres) 가 0 으로 걷는다 — 예전처럼 음수 margin 으로 당기면 sticky 헤더(X)가
     패널 여백(24)만큼 내려 붙는다(2026-10-13). */
  /* completed1 한 장은 **화면보다 짧을 수 없다** — 짧으면 completed2 가 completed1 에 걸쳐
     보인다(디자이너 지적 2026-09-19). 페이지 높이 = completed1 한 장 + (보이는 높이 − 190)
     → 굴릴 양이 곧 "한 장 − 190" 이 되어 끝까지 굴리면 completed2 가 앱 190 에 선다.
     ⚠️ 한때 658(설계 화면)로 못박았다가, 보이는 높이가 그보다 크면 494.2 까지 굴러가지 못해
        completed2 가 통째로 내려앉았다. 높이는 기기마다 다르므로 반드시 --screen-h 로 잡는다. */
  /* 굴릴 양은 JS 가 재서 --wres-scroll 로 알려준다("첫 주문" 덩이가 화면 한가운데에 오는
     자리 기준). 페이지 높이는 그 값 + 보이는 높이 — 끝까지 굴리면 딱 그 자리에 선다. */
  height: calc(var(--wres-scroll, 494.2px) + var(--screen-h));
  background: radial-gradient(ellipse 505px 430px at 375px 0, #060109 0%, #040105 89.4%);
  /* 넘치는 빛무리는 자르되 clip 으로 자른다 — hidden 은 이 상자를 스크롤 상자로 만들어 안쪽 sticky 헤더(X)가
     굴릴 때 같이 올라가 버렸다(2026-10-13). clip 을 모르는 옛 브라우저는 위 hidden 을 그대로 쓴다. */
  overflow: hidden;
  overflow: clip;
  display: flow-root;   /* clip 은 hidden 과 달리 margin 겹침을 막지 않는다 — 헤더 margin(10)이 바깥으로 새어 상자째 내려가지 않게 */
}

/* ── 배경 ── */
.wres__stars,
.wres__glow { position: absolute; z-index: 0; display: block; pointer-events: none; }
.wres__glow img { position: absolute; inset: -24.34% -18.63%; width: auto; height: auto; max-width: none; }
/* 별밤 — 시안은 completed1·completed2 **둘 다 앱 −186(시안 −124)** 에 둔다. 곧 굴려도
   제자리라는 뜻이라(화면에 붙은 층), 굴린 만큼 같이 내려 화면에서 멎어 있게 한다. */
.wres__stars {
  top: -186px;
  left: calc(62.5% - 29.38px);
  width: 426px;
  height: 1060px;
  opacity: 0.6;
  transform: translateX(-50%) translateY(var(--wres-y, 0px));
}
.wres__stars img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0.6;
  mix-blend-mode: plus-lighter;
}
.wres__glow {
  left: calc(50% - 3.5px);
  width: 644px;
  height: 493px;
}
/* 빛무리는 두 장이다 — 시안이 프레임마다 한 장씩 그려 두었고, **둘의 방향이 다르다.**
   glow-bottom.svg 는 위가 불룩한 돔이라 뒤집느냐 마느냐로 밝은 덩어리의 자리가 뒤바뀐다:
     · completed1 (앱 462, 세로 뒤집힘) → 밝은 덩어리가 화면 아래끝에 걸린다
     · completed2 (앱 −268, 그대로)    → 밝은 덩어리가 화면 위로 빠져 윗머리만 옅게 남는다
   한 장을 돌려쓰려다 completed2 의 제목 언저리가 뿌옇게 떴다(디자이너 지적 2026-09-19).
   그렇다고 둘을 그냥 다 깔면 completed1 한가운데가 밝아져 화면이 통째로 푸르게 뜬다(실측).
   → 굴린 만큼 **엇갈아 넘긴다.** 아래 것은 웃돈 235.8 을 붙여 빠르게 올라가며 물러나고,
     위 것이 그 자리를 이어받는다. 디자이너가 말한 "아래에 있던 그라데이션이 위로 올라가는
     느낌"이 여기서 나온다. */
.wres__glow--a {
  top: 462px;
  opacity: calc(1 - 1.4 * var(--wres-t, 0));
  transform: translateX(-50%) translateY(calc(var(--wres-t, 0) * -235.8px)) scaleY(-1);
}
.wres__glow--b {
  /* completed2 의 위쪽 빛무리(시안 앱 −268). 굴린 양이 화면 높이를 따라 달라지므로 자리도
     거기 붙여 둔다 — 안 그러면 화면 밖으로 밀려 위쪽에 안 보인다. */
  top: calc(var(--wres-scroll, 494.2px) - 268px);
  opacity: calc(1.4 * var(--wres-t, 0) - 0.4);
  transform: translateX(-50%);
}

/* ── 헤더 — 굴려도 따라온다. 흐름 공간은 먹지 않는다(10 + 38 − 48 = 0). ── */
.wres__header {
  position: sticky;
  top: calc(10px + var(--safe-top));   /* 스크롤 상자(시트) 기준이라 상태바를 따로 피한다 */
  z-index: 3;
  display: flex;
  align-items: center;
  justify-content: space-between;
  box-sizing: border-box;
  height: 38px;
  margin: 10px 0 -48px;
  padding: 4px 20px;
}
.wres__close {
  display: block;
  width: 24px;
  height: 24px;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}
.wres__close img { display: block; width: 24px; height: 24px; }

/* ── completed1 ── */
.wres__one {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 25px;
  box-sizing: border-box;
  width: 335px;
  margin: 0 auto;
  padding-top: 58px;    /* 시안 120 */
  /* completed2 는 시안에서 별개 프레임이라 completed1 본문이 몇 줄이든 제자리(페이지 684.2)에
     서야 한다. 그래서 여기서 바닥을 깔아 둔다 — 결과에 따라 본문이 더 길어지면 그때만 밀린다.
     화면이 684.2 보다 높으면 그만큼 늘린다(위 .hres 와 같은 사정). */
  min-height: max(684.2px, var(--screen-h));
}
.wres__block { display: flex; flex-direction: column; align-items: center; gap: 8px; width: 335px; }
/* 완드 이름은 Nimbus Roman 40 — 시안 result/*wand/completed1(4357-15304 등, 2026-10-09)이 컴포넌트 기본(HarryBeast 36)을
   덮어쓴다. 물약 결과(.pres)와 같은 방식이고, 머리말 두 줄 사이 4 도 시안대로 채운다 → 머리말 104 · 그림 앱 170(시안 232). */
.wres .content-title__text { gap: 4px; }
.wres__art {
  position: relative;
  width: 262px;
  height: 204px;
}
/* 결과별 에셋(786 정사각)을 시안 상자에 cover 로 채운다.
   여섯 종 모두 시안의 content/After/Wand/* 와 **같은 그림이고 자리도 같다** — 시안 렌더와
   맞춰 보니 평균차 6~7/255 였다(나머지는 시안 쪽 드롭섀도 번짐). 그림자 여백이 없는
   walnut 으로 재면 어긋남이 (2, 2) 안이다. 다시 내보낼 것 없다.
   ⚠️ 한때 85/255 로 어긋난다고 적었는데 잘못 잰 것이었다 — 시안이 내보낸 wand-holly.png 는
      여백이 다른 별도 파일이라, 크롭을 맞추지 않고 정사각 원본과 바로 견준 값이었다. */
.wres__art img {
  position: absolute;
  top: 0;
  left: calc(50% + 0.08px);
  width: 254.163px;
  height: 198px;
  object-fit: cover;
  transform: translateX(-50%);
  filter: drop-shadow(0 4px 24px rgba(234, 214, 248, 0.2));
}

/* 주재료+본문. completed2 시안에서 이 블록이 앱 −121 에 50% 로 걸쳐 보인다 — 자리는 굴리면
   저절로 맞고(372.5 − 494.2 = −121.7), 투명도만 굴린 만큼 묽힌다.
   ⚠️ 시안은 본문 한 덩이가 아니라 **주재료까지 묶어** 50% 다. 그래서 여기에 건다. */
.wres__text {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 24px;
  width: 335px;
  /* completed2 에서 이 블록이 "첫 주문" 덩이 **82 위**에 **70%** 로 걸쳐 보인다(디자이너 지정
     2026-09-19). 82 자리를 맞추려면 굴리는 것만으로는 모자라 조금 더 옮겨야 하는데, 그 양
     (--wres-lift)은 화면 높이에 따라 달라져 JS 가 재서 알려준다(wresMeasure). */
  opacity: calc(1 - 0.3 * var(--wres-t, 0));
  transform: translateY(calc(var(--wres-t, 0) * var(--wres-lift, 0px)));
}
.wres__meta { display: flex; flex-direction: column; align-items: center; gap: 4px; width: 100%; }
.wres__meta-label {
  width: 302px;
  margin: 0;
  /* base/body3/M-12 */
  font-family: var(--font-base);
  font-weight: 500;
  font-size: 12px;
  line-height: 1.5;
  letter-spacing: 0.005em;
  text-align: center;
  opacity: 0.7;
  color: var(--blue-50);
}
.wres__meta-row {
  display: flex;
  gap: 7px;
  margin: 0;
  /* accent/body3/R-14 */
  font-family: var(--font-accent);
  font-weight: 400;
  font-size: 14px;
  line-height: 1.5;
  letter-spacing: -0.01em;
  white-space: nowrap;
  color: var(--gray-100);
}
/* 본문 — 뒤에 큰 호가 한 겹 깔린다(시안 Group 1173). */
.wres__desc {
  position: relative;
  width: 336px;
  opacity: 0.71;
}
.wres__desc p {
  position: relative;
  z-index: 1;
  margin: 0;
  /* accent/body2/R-16 */
  font-family: var(--font-accent);
  font-weight: 400;
  font-size: 16px;
  line-height: 1.5;
  letter-spacing: -0.01em;
  text-align: center;
  color: var(--gray-200);
}
.wres__desc b,
.wres__desc strong {
  font-weight: 600;
  line-height: 1.3;
  color: var(--white);
}
/* 큰 호(Group 1173 3846:27013)는 주재료 윗변에서 −270(시안 — 세로로 뒤집힌 그룹이라 y 121.2 가 아랫변, 높이 391.2).
   이 상자는 본문(주재료 아래 67)에 붙어 있어 −337 이다. */
.wres__arc {
  position: absolute;
  z-index: 0;
  top: -337px;
  left: 0;
  width: 335.001px;
  height: 391.171px;
  transform: scaleY(-1);
  pointer-events: none;
}
.wres__arc img { position: absolute; inset: -8.84% -8.95% -8.84% -11.9%; width: auto; height: auto; max-width: none; }

.wres__arrow {
  display: block;
  width: 41px;
  height: 41px;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}
/* completed2 시안에는 화살표가 없다 — 굴리기 시작하면 제 할 일이 끝난 것이라 물러난다.
   반쯤 굴렀을 때 이미 없다(t 0.5 에서 0).
   ⚠️ 묽히기는 **안쪽 img** 가 맡는다. 버튼의 opacity 는 등장 연출(step 5)이 쓰고 있어서,
      거기에 겹쳐 쓰면 "화살표가 맨 마지막에 뜬다"가 사라진다. 두 겹이라야 곱해진다. */
.wres__arrow img {
  display: block;
  width: 41px;
  height: 41px;
  opacity: calc(1 - 2 * var(--wres-t, 0));
  transform: rotate(90deg);
}

/* ── completed2 ── */
.wres__two {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  width: 335px;
  margin: 0 auto;
  /* 시안 completed2 의 CTA 도 다른 화면과 같이 바닥에서 12 다(앱 591). 블록 높이를 못박고
     .wres__actions 를 margin-top:auto 로 내려, 주문 설명이 길어져도 배지만 움직이게 한다.
     블록 높이 = 보이는 높이 − 202 (= 블록 시작 684.2 − 굴린 양 494.2 + CTA 55 + 바닥 12).
     658 짜리 화면이면 456 이다. */
  /* CTA 는 다른 화면과 같이 바닥에서 12 다. 덩이가 가운데로 가면서 블록 높이도 화면마다
     달라져 JS 가 재서 알려준다(--wres-two-h = 보이는 높이 − 12 − 가운데 자리). */
  min-height: calc(var(--wres-two-h, calc(var(--screen-h) - 202px)) - var(--ui-gap));   /* 홈 화면에 추가하면 CTA 를 툴바 자리만큼 띄운다 */
}
.wres__spell { position: relative; display: flex; flex-direction: column; gap: 30px; width: 100%; }
.wres__spell-head { display: flex; flex-direction: column; gap: 18px; width: 100%; }
.wres__spell-title {
  margin: 0;
  /* accent/head1/SB-24 */
  font-family: var(--font-accent);
  font-weight: 600;
  font-size: 24px;
  line-height: 1.3;
  letter-spacing: -0.01em;
  white-space: nowrap;
  color: var(--blue-50);
}
.wres__spell-name {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 0;
  font-family: var(--font-accent);
  font-weight: 400;
  font-size: 16px;
  line-height: 1.5;
  letter-spacing: -0.01em;
  white-space: nowrap;
  color: var(--white);
}
.wres__spark { display: block; width: 20px; height: 20px; flex-shrink: 0; }
.wres__spark img { display: block; width: 20px; height: 20px; }
.wres__spell-desc {
  position: relative;
  z-index: 1;
  margin: 0;
  font-family: var(--font-accent);
  font-weight: 400;
  font-size: 16px;
  line-height: 1.5;
  letter-spacing: -0.01em;
  opacity: 0.8;
  color: var(--gray-200);
}
.wres__spell-desc b,
.wres__spell-desc strong { font-weight: 600; line-height: 1.3; opacity: 1; color: var(--white); }
.wres__curve {
  position: absolute;
  z-index: 0;
  /* 주문마다 자리 · 높이가 다르다(app.js WAND_SPELLS curve — 폭은 넷 다 149) */
  top: var(--curve-top, -49px);
  left: var(--curve-left, 178px);
  width: 149px;
  height: var(--curve-h, 131px);
  pointer-events: none;
}
/* 주문 곡선 — completed2 로 내려올 때마다 선이 새로 그려지고(라인 트래킹), 끝에서 화살표가 붙고
   별이 켜진다(디자이너 요청 2026-09-19 · 2026-10-08 주문 넷). 그래서 이것만 인라인 svg 다(app.js 주석 참고).
   · 선(.wres__curve-line) — pathLength="1" 이라 실제 길이와 상관없이 dasharray/offset 1 로 그린 정도가 0→1 이다.
   · 화살표(.wres__curve-arrow) — 시안 도형에서 머리만 떼어 낸 것. 선이 끝에 닿을 즈음 **화살 끝에서 날개가 펴지듯
     자라나**(작게 → 살짝 넘쳤다 제 크기) 그대로 남는다(2026-10-08 디자이너 요청 — 한 번에 툭 켜지면 어색했다).
   · 도형(.wres__curve-glyph) — 시안 export 그대로의 면에서 머리 자리만 비운 것. 선이 다 그려지면 선과 자리를 바꾼다.
     둘을 합친 마지막 모습이 시안 도형 그대로다.
   · 별 — 화살표가 다 자라고 0.4 초 남짓 쉰 뒤에 켜진다(화살표와 별이 거의 동시라 급해 보였다).
     선 0.1~1.3s → 화살표 1.05~1.5s · 선 → 도형 1.3~1.6s → (쉼) → 별 2.0~2.5s.
   도로 올라가면 도형 · 별이 먼저 꺼지고 선이 0.4 초에 걷힌다 — 다시 내려오면 또 그려진다. */
.wres__curve svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.wres__curve-line { stroke-dasharray: 1; stroke-dashoffset: 1; transition: stroke-dashoffset 0.4s ease; }
.wres__curve-glyph { opacity: 0; transition: opacity 0.15s ease; }
.wres__curve-arrow {
  opacity: 0;
  transform: scale(0.2);
  transform-box: view-box;          /* transform-origin 을 svg 좌표(px)로 — 화살 끝, 주문마다 인라인으로 준다 */
  transition: opacity 0.15s ease, transform 0s linear 0.15s;
}
.wres__curve-star { opacity: 0; transition: opacity 0.3s ease; }
.wres.is-two .wres__curve-line {
  stroke-dashoffset: 0;
  opacity: 0;
  transition: stroke-dashoffset 1.2s cubic-bezier(0.33, 1, 0.68, 1) 0.1s, opacity 0.3s ease 1.3s;
}
.wres.is-two .wres__curve-arrow {
  opacity: 1;
  transform: none;
  transition: opacity 0.25s ease 1.05s, transform 0.45s cubic-bezier(0.34, 1.45, 0.64, 1) 1.05s;
}
.wres.is-two .wres__curve-glyph { opacity: 1; transition: opacity 0.3s ease 1.3s; }
.wres.is-two .wres__curve-star { opacity: 1; transition: opacity 0.5s ease 2s; }

.wres__badge {
  display: flex;
  align-items: center;
  gap: 10px;
  box-sizing: border-box;
  width: 100%;
  margin: 33px 0 0;
  padding: 8px 12px;
  background: linear-gradient(90deg, #2A4059 0%, #000000 100%); /* ⚠️ non-token: 시안 배지 */
  font-family: var(--font-accent);
  font-weight: 400;
  font-size: 14px;
  line-height: 1.5;
  letter-spacing: -0.01em;
  white-space: nowrap;
  color: var(--white);
}
.wres__actions { margin-top: auto; }   /* 앱 591 = 바닥에서 12 */

/* ── completed2 문안이 아직 없는 결과 ──
   vine 말고는 "추천하는 첫 주문" 문안이 없다(mock-data.js). 그 경우 completed2 도, 아래로
   끄는 화살표도 없고 저장 버튼만 completed1 바닥에 남는다. 페이지는 딱 한 장(658)이다. */
.wres--solo {
  display: flex;
  flex-direction: column;
  box-sizing: border-box;
  height: auto;
  min-height: var(--screen-h);
  padding-bottom: calc(12px + var(--ui-gap));   /* CTA 를 바닥에서 12 로 — 658 짜리 화면이면 앱 591 */
}
.wres--solo .wres__one { min-height: 0; }
.wres--solo > .wres__actions { margin: auto auto 0; }

/* ── 등장 연출 (디자이너 지정) ──
   ① deco 가 가운데에서 양쪽으로 펼쳐지고 ② 아래가 하나씩 뜨고 ③ 화살표가 맨 마지막에 뜨면서
   아래로 유도한다. 차례는 지연이 만든다.
   ⚠️ ① 은 여기 없다 — 디자인시스템 .content-title 이 들고 있다(결과 화면들이 같이 쓴다).
      뿌리의 .wres.is-in 이 그대로 방아쇠다. */
/* ⚠️ 뜨는 시간(1.1)이 사이 간격(0.2)보다 훨씬 길어야 한다 — 그래야 앞것이 아직 한창 뜨는 중에
      뒤것이 시작해서 다섯이 한 물결로 흐른다. 처음에는 0.55 뜨는데 0.2 씩 띄워 두어 겨우
      겹쳤고, 그래서 따로따로 톡톡 튀어 올라오는 느낌이었다(디자이너 지적 2026-09-19).
      느긋한 쪽이 이 화면에 맞아 한 번 더 늦췄다(0.85 → 1.1). */
[data-wres-step] { opacity: 0; transform: translateY(16px); }
.wres.is-in [data-wres-step] {
  opacity: 1;
  transform: none;
  transition: opacity 1.1s cubic-bezier(0.33, 1, 0.68, 1), transform 1.1s cubic-bezier(0.16, 1, 0.3, 1);
}
.wres.is-in [data-wres-step="1"] { transition-delay: 0.5s; }
.wres.is-in [data-wres-step="2"] { transition-delay: 0.7s; }
.wres.is-in [data-wres-step="3"] { transition-delay: 0.9s; }
.wres.is-in [data-wres-step="4"] { transition-delay: 1.1s; }
/* 화살표만 한 박자 떼어 둔다 — "맨 마지막에 뜨면서 아래로 유도한다"가 읽혀야 한다 */
.wres.is-in [data-wres-step="5"] { transition-delay: 1.7s; }
/* 본문은 등장이 끝나면 시안대로 71% 다 — 위 규칙이 1 로 덮어쓰지 않게 여기서 되돌린다.
   (묽어지는 것은 .wres__text 가 통째로 맡는다) */
.wres.is-in [data-wres-fade] { opacity: 0.71; }
/* 화살표는 다 뜬 뒤(1.7 + 1.1 = 2.8) 아래로 살짝 끄덕인다 */
.wres.is-in .wres__arrow { animation: wres-nudge 2s ease-in-out 2.95s infinite; }
@keyframes wres-nudge {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(6px); }
}

@media (prefers-reduced-motion: reduce) {
  [data-wres-step] { opacity: 1; transform: none; }
  .wres.is-in [data-wres-step] { transition: none; }
  .wres.is-in .wres__arrow { animation: none; }
  .wres__curve-line { stroke-dashoffset: 0; opacity: 0; }
  .wres__curve-glyph,
  .wres__curve-arrow,
  .wres__curve-star { opacity: 1; }
  .wres__curve-arrow { transform: none; }
  .wres__curve-line,
  .wres__curve-glyph,
  .wres__curve-arrow,
  .wres__curve-star,
  .wres.is-two .wres__curve-line,
  .wres.is-two .wres__curve-glyph,
  .wres.is-two .wres__curve-arrow,
  .wres.is-two .wres__curve-star { transition: none; }
}

/* ══════════ 기숙사 결과 (Figma result_house/gryffindor/completed1·2·3, 2026-09-19) ══════════
   물속 연출이 통째로 빠지고 완드 결과와 같은 밤하늘 언어가 됐다. 화면은 둘이다.
     .hres1 — completed1. 문장 하나만 띄우고 "tap to continue". 탭하면 아래로 간다.
     .hres  — completed2+3 을 한 장으로 이은 스크롤(완드 .wres 와 같은 방식).
   좌표는 전부 시안 y − 62(상태바). */

/* 별밤 한 장 — 완드 결과와 같은 에셋·같은 자리다(시안 −124 → 앱 −186). */
.hres__stars {
  position: absolute;
  z-index: 0;
  top: -186px;
  left: calc(62.5% - 29.38px);
  width: 426px;
  height: 1060px;
  opacity: 0.6;
  transform: translateX(-50%);
  pointer-events: none;
}
.hres__stars img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  mix-blend-mode: plus-lighter;
}

/* ── completed1 — 문장 한 장 ── */
.hres1 {
  position: relative;
  width: 375px;
  min-height: var(--screen-h);
  overflow: hidden;
  background: var(--black);
  cursor: pointer;
}
/* 뒤에 깔리는 큰 호 — 시안은 세로로 뒤집어 −10.64° 기울여 쓴다. */
.hres1__arc {
  position: absolute;
  z-index: 0;
  top: 180px;
  left: -25.26px;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 374.517px;
  height: 424.928px;
  pointer-events: none;
}
.hres1__arc img {
  width: 310.832px;
  height: 373.983px;
  max-width: none;
  transform: rotate(-10.64deg) scaleY(-1);
}

.hres1__title {
  position: absolute;
  z-index: 1;
  top: 59px;
  /* ⚠️ 가운데 맞춤을 transform 으로 하지 않는다 — 등장 연출([data-hres1-step])이 transform 을
     쓰고 있어서 겹치면 한쪽이 지워진다(실측). left 로 맞춘다. */
  left: calc(50% - 95px);
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 190px;
}
/* 제목 위로 솟은 왕관 장식 — 글씨보다 28 위에서 시작한다(시안). */
.hres1__crown {
  position: absolute;
  top: -28px;
  left: 49.5px;
  width: 91px;
  height: 98.4px;
}
.hres1__kicker {
  position: relative;
  z-index: 1;
  width: 100%;
  margin: 0 0 -10px;   /* 시안 mb −10 — 밑줄이 글씨에 바짝 붙는다 */
  /* accent/body1/R-18 */
  font-family: var(--font-accent);
  font-weight: 400;
  font-size: 18px;
  line-height: 1.5;
  letter-spacing: -0.01em;
  text-align: center;
  color: #FEFDFC;                          /* ⚠️ non-token: 시안 제목 */
  text-shadow: 0 0 4px #DAB8A3;            /* ⚠️ non-token: 시안 제목 번짐 */
}
.hres1__rule { display: block; width: 190px; height: 21px; }

.hres1__art {
  position: absolute;
  z-index: 1;
  display: flex;
  top: 158px;
  left: calc(50% - 142px);   /* 위 ⚠️ 와 같은 사정 */
  width: 284px;
  height: 284px;
}
/* 시안은 284 칸 안에 그림을 195.349×240.289 로 앉힌다(칸을 꽉 채우지 않는다). */
/* ⚠️ 시안이 적어 둔 그림 상자(195.349×240.289)를 그대로 쓰면 안 된다 — 그건 **시안이 쓴 컷**의
   치수다. 저장소 컷(786 정사각)은 여백이 달라서 그대로 넣으면 방패가 작아진다.
   시안 렌더에서 방패를 실측해(284 칸 안에서 168×208) 맞추면 원본을 칸의 88.7% 로 그리면 된다. */
.hres1__art img {
  display: block;
  width: 88.7%;
  height: 88.7%;
  margin: auto;
  object-fit: contain;
  filter: drop-shadow(0 4.7px 28.2px rgba(234, 214, 248, 0.2));
}
.hres1__tap {
  position: absolute;
  z-index: 1;
  top: 575px;
  left: 0;
  width: 100%;
  margin: 0;
  text-align: center;        /* 위 ⚠️ 와 같은 사정 — transform 을 비워 둔다 */
  /* Lumos Caps 24 — 시안 행간이 20 이다(글자 크기보다 작다) */
  font-family: var(--font-display);
  font-size: 24px;
  line-height: 20px;
  letter-spacing: -0.5px;
  white-space: nowrap;
  color: var(--white);
}

/* completed1 등장 — 완드 completed1 과 같은 물결이다(디자이너 지정). */
[data-hres1-step] { opacity: 0; transform: translateY(16px); }
.hres1.is-in [data-hres1-step] {
  opacity: 1;
  transform: none;
  transition: opacity 1.1s cubic-bezier(0.33, 1, 0.68, 1), transform 1.1s cubic-bezier(0.16, 1, 0.3, 1);
}
.hres1.is-in [data-hres1-step="1"] { transition-delay: 0.5s; }
.hres1.is-in [data-hres1-step="2"] { transition-delay: 0.7s; }
.hres1.is-in [data-hres1-step="3"] { transition-delay: 1.5s; }   /* tap 안내는 한 박자 떼어 둔다 */
.hres1.is-in .hres1__tap { animation: hres-blink 2.4s ease-in-out 2.6s infinite; }
@keyframes hres-blink {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.45; }
}

/* ── completed2 + completed3 — 한 장으로 이은 스크롤 ──
   오프셋 476: completed3 에서 성향 두 단이 앱 −102 에 걸쳐 보이고, 그 블록이 completed2 에서는
   앱 374 에 있다. 굴린 양은 --hres-y(px)·--hres-t(0→1) 로 층들에 내려보낸다(.wres 와 같은 방식). */
.hres {
  position: relative;
  width: 375px;
  /* completed2 한 장은 **화면보다 짧을 수 없다** — 짧으면 completed3(그래프)이 completed2 에
     걸쳐 보인다(디자이너 지적 2026-09-19, 812 화면에서 실측).
     페이지 높이 = completed2 한 장 + (보이는 높이 − 207) → 굴릴 양이 곧 "한 장 − 207" 이 되어
     끝까지 굴리면 그래프가 앱 207 에 선다. */
  height: calc(max(683px, var(--screen-h)) - 207px + var(--screen-h) + var(--hres-extra, 0px));   /* extra — app.js hresExtra */
  overflow: hidden;
  overflow: clip;   /* hidden 만 두면 sticky 헤더(X)가 굴릴 때 따라오지 못한다 — .wres 와 같다 */
  display: flow-root;
  background: var(--black);
}
.hres .hres__stars { transform: translateX(-50%) translateY(var(--hres-y, 0px)); }

.hres__glow { position: absolute; z-index: 0; left: calc(50% + 0.5px); width: 644px; height: 493px; pointer-events: none; }
.hres__glow img { position: absolute; inset: -24.34% -18.63%; width: auto; height: auto; max-width: none; }
/* completed2 의 아래쪽 빛무리(앱 484, 세로 뒤집힘) → completed3 의 위쪽 빛무리(앱 −306)로
   엇갈아 넘긴다. 완드와 같은 사정이다 — 둘을 다 깔면 한가운데가 통째로 밝아진다. */
.hres__glow--a {
  top: 484px;
  opacity: calc(1 - 1.4 * var(--hres-t, 0));
  transform: translateX(-50%) translateY(calc(var(--hres-t, 0) * -170px)) scaleY(-1);
}
.hres__glow--b {
  /* completed3 의 위쪽 빛무리(시안 앱 −306). 굴린 양이 화면 높이에 따라 달라지므로 자리도
     거기 붙여 둔다 — 안 그러면 높은 화면에서 화면 밖으로 밀려 안 보인다. */
  top: calc(var(--hres-scroll, 476px) - 306px);
  opacity: calc(1.4 * var(--hres-t, 0) - 0.4);
  transform: translateX(-50%);
}

.hres__header {
  position: sticky;
  top: calc(10px + var(--safe-top));
  z-index: 3;
  display: flex;
  align-items: center;
  box-sizing: border-box;
  height: 38px;
  margin: 10px 0 -48px;
  padding: 4px 20px;
}
.hres__close { display: block; width: 24px; height: 24px; padding: 0; border: 0; background: none; cursor: pointer; }
.hres__close img { display: block; width: 24px; height: 24px; }

/* ── completed2 ── */
.hres__two {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  box-sizing: border-box;
  width: 336px;
  margin: 0 auto;
  padding-top: 54px;      /* 시안 116 */
  /* completed3 은 시안에서 별개 프레임이라 성향이 몇 줄이든 제자리(페이지 683)에 서야 한다.
     다만 화면이 683 보다 높으면 그만큼 늘려야 그래프가 미리 보이지 않는다(위 .hres 주석). */
  min-height: max(683px, var(--screen-h));
}
/* 기숙사 이름도 Nimbus Roman 40 — 시안 result/*house/completed2(4357-14376 · 15994 · 15805, 2026-10-09). 완드(.wres)와 같은 덮어쓰기.
   머리말 104 → 문장 앱 158(시안 220) · 성향 384(시안 446). 후플푸프 시안(15850)만 옛 배치라 문장이 10 위에 있다. */
.hres .content-title__text { gap: 4px; }
.hres__art { display: flex; width: 220px; height: 220px; }   /* 시안 — 머리말 바로 아래, 틈 없음 */
/* 위 .hres1__art 와 같은 사정 — 칸의 88.7% (시안 220 칸 안에서 방패 131×162 실측). */
.hres__art img {
  display: block;
  width: 88.7%;
  height: 88.7%;
  margin: auto;
  object-fit: contain;
  filter: drop-shadow(0 2.82px 16.922px rgba(234, 214, 248, 0.2));
}

/* 겉 — 굴릴 때 옮기고 묽히는 몫. 성향 두 단이 그래프 82 위에 70% 로 걸치도록,
   모자란 만큼만 더 옮긴다(--hres-lift 는 JS 가 잰다). */
.hres__traits {
  width: 336px;
  margin-top: 6px;
  opacity: calc(1 - 0.3 * var(--hres-t, 0));
  transform: translateY(calc(var(--hres-t, 0) * var(--hres-lift, 0px)));
}
.hres__traits-in { display: flex; flex-direction: column; gap: 24px; width: 100%; }
.hres__trait { display: flex; flex-direction: column; align-items: center; gap: 4px; width: 100%; }
.hres__trait-name {
  display: flex;
  align-items: center;
  gap: 5px;
  margin: 0;
  padding: 0 12px;
  /* accent/body2/R-16 */
  font-family: var(--font-accent);
  font-weight: 400;
  font-size: 16px;
  line-height: 1.5;
  letter-spacing: -0.01em;
  white-space: nowrap;
  color: var(--white);
  /* 번짐 색은 기숙사마다 다르다 — 화면이 --house-shadow 로 내려준다(app.js HOUSE_SKIN). */
  text-shadow: 0 0 4px var(--house-shadow, #DFA0A0);
}
/* 성향 불릿 — 시안 자리는 7.5×15 인데 그림은 그 밖으로 넘쳐 그려진다(inset −26.67% −53.33%).
   자리는 그대로 두고 그림만 넘치게 해야 옆 글씨와의 간격(5)이 시안과 같아진다. */
.hres__bullet { position: relative; display: block; width: 7.5px; height: 15px; flex-shrink: 0; }
/* ⚠️ 크기를 직접 적는다 — img 는 대체 요소라 inset 네 방향을 다 줘도 width/height 가 auto 면
   **원본 크기**로 그려진다(실측 47×69). 시안 값을 px 로 환산: 7.5+2×4 = 15.5, 15+2×4 = 23. */
.hres__bullet img { position: absolute; top: -4px; left: -4px; width: 15.5px; height: 23px; }
.hres__trait-desc {
  width: 100%;
  margin: 0;
  opacity: 0.7;
  font-family: var(--font-accent);
  font-weight: 300;
  font-size: 16px;
  line-height: 1.5;
  letter-spacing: -0.01em;
  text-align: center;
  color: var(--gray-200);
}
/* 첫 줄만 흰색 보통 굵기다(시안) */
.hres__trait-desc b { font-weight: 400; color: var(--white); }
/* 띄어쓰기에서만 줄을 넘긴다 — 글자 단위로 끊으면 "용/기" · "자부/심" 처럼 낱말이 갈린다(패트로누스 .pat__trait-desc 와 같다). */
.hres__trait-desc { word-break: keep-all; }
/* 문안(mock-data.js 기숙사특성 body)의 \n 은 시안이 정해 둔 줄바꿈이다 — 그대로 끊는다(2026-10-21). */
.hres__trait-desc { white-space: pre-line; }

.hres__arrow {
  display: block;
  width: 41px;
  height: 41px;
  margin-top: 12px;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}
/* completed3 시안에는 화살표가 없다 — 굴리기 시작하면 물러난다(완드와 같다). */
.hres__arrow img {
  display: block;
  width: 41px;
  height: 41px;
  opacity: calc(1 - 2 * var(--hres-t, 0));
  transform: rotate(90deg);
}
/* ── completed3 — 입학생 현황 ── */
.hres__three {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 335px;
  margin: 0 auto;
  /* CTA 를 바닥에서 12 로 붙든다(앱 591). 블록이 페이지 683 에서 시작하고 굴린 양이 476 이니
     CTA 바닥은 페이지 476 + 보이는 높이 − 12 → 블록 높이 = 보이는 높이 − 219. */
  min-height: calc(var(--screen-h) - 219px - var(--safe-top) - var(--ui-gap));   /* 홈 화면에 추가하면 위 띠 · 툴바 자리만큼 줄인다 */
}
/* 시안 Group 1161 — 335×238 안에 제목(위 24)과 네 기둥이 함께 들어 있다. */
.hres__graph { position: relative; width: 335px; height: 238px; }
.hres__graph-title {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: 24px;
  margin: 0;
  /* accent/body1/R-18 */
  font-family: var(--font-accent);
  font-weight: 400;
  font-size: 18px;
  line-height: 1.5;
  letter-spacing: -0.01em;
  white-space: nowrap;
  color: var(--white);
}
.hres__graph-title img { display: block; width: 35px; height: 19px; }
.hres__graph-title img:last-child { transform: rotate(180deg) scaleY(-1); }

/* 막대 그래프 — 시안 335×238, 바닥선은 네 기둥이 공통으로 199 다.
   ⚠️ 막대 높이(--h)는 퍼센트에 **비례**하고, 눈금은 JS 가 잡는다(houseStatsHtml) — 가장 높은
      막대의 문장이 제목에서 22 아래에 오도록 맞추기 때문이다(디자이너 지정). 시안 막대
      (138/109/120/132)는 손으로 그린 값이라 32/20/23/25% 와 눈금이 맞지 않는다. */
.hres__col { position: absolute; top: 0; width: 68.639px; height: 100%; }
/* ⚠️ nth-child 는 쓰지 않는다 — 제목 <p> 가 첫 자식이라 한 칸씩 밀린다(실측). */
.hres__col:nth-of-type(1) { left: 0; }
.hres__col:nth-of-type(2) { left: 89.13px; }
.hres__col:nth-of-type(3) { left: 177.23px; }
.hres__col:nth-of-type(4) { left: 266.36px; }

.hres__bar {
  position: absolute;
  z-index: 1;
  bottom: 39px;                              /* 바닥선 199 = 238 − 39 */
  left: 11.27px;
  width: 46.101px;
  height: var(--h);
  /* 우리 기숙사가 아닌 기둥은 회색으로 가라앉는다(시안). */
  background: linear-gradient(180deg, rgba(100, 100, 100, 0.5) 0%, rgba(34, 56, 75, 0) 100%);
}
/* 우리 기숙사 기둥만 제 색으로 선다 — 네 색은 JS 가 --house-* 로 내려준다(HOUSE_SKIN). */
.hres__col.is-mine .hres__bar {
  background: linear-gradient(180deg, var(--house-bar, var(--red-800)) 0%, rgba(217, 217, 217, 0) 100%);
}
/* 문장은 막대 머리에 걸터앉는다 — 22 만큼 겹친다. */
.hres__crest {
  position: absolute;
  bottom: calc(39px + var(--h) - 22px);
  left: 50%;
  z-index: 2;                /* ⚠️ 막대보다 위에 온다 — 안 그러면 문장이 막대에 가린다 */
  display: block;
  width: 65px;               /* 시안 icon/<기숙사> 상자 폭. 높이는 그림 비율이 낸다(45 / 40) */
  transform: translateX(-50%);
  opacity: 0.45;
}
.hres__col.is-mine .hres__crest { opacity: 1; }
.hres__crest img { display: block; width: 100%; height: auto; }

.hres__bar-label {
  position: absolute;
  bottom: 42px;
  left: 50%;
  writing-mode: vertical-rl;
  transform: translateX(-50%);
  opacity: 0.6;
  /* accent/body3/R-14 */
  font-family: var(--font-accent);
  font-weight: 400;
  font-size: 14px;
  line-height: 1.5;
  letter-spacing: -0.01em;
  color: var(--gray-100);
}
.hres__col.is-mine .hres__bar-label { opacity: 1; color: var(--house-bar-label, var(--red-200)); }

/* 퍼센트는 Nimbus Roman 24 — 시안 completed3(4357-16274 · 16198 · 14508 · 16052 · 16126, 2026-10-09 — 전: HarryBeast/R-20).
   글자 상자가 29 로 커져 그래프 블록(238) 아래로 5 넘친다. 위(214)에 붙여야 시안 자리(483)에 서고
   아래 문장(그래프 + 47)도 그대로다. 가로는 시안마다 1~2 씩 흔들려서 막대 가운데에 맞춘다. */
.hres__bar-pct {
  position: absolute;
  top: 214px;
  left: 0;
  width: 68.639px;
  font-family: var(--font-serif-title);
  font-size: 24px;
  line-height: normal;
  text-align: center;
  color: var(--gray-600);
}
.hres__col.is-mine .hres__bar-pct {
  color: var(--house-pct, var(--red-400));
  text-shadow: 0 0 4px var(--house-pct-glow, #FF6767);   /* ⚠️ non-token: 시안 내 기숙사 퍼센트 번짐 */
}

.hres__note {
  margin: 47px 0 0;   /* 시안 — 그래프 블록(238) 아래로 47 */
  /* accent/body1/R-18 */
  font-family: var(--font-accent);
  font-weight: 400;
  font-size: 18px;
  line-height: 1.5;
  letter-spacing: -0.01em;
  text-align: center;
  color: var(--blue-50);
}
.hres__actions { margin-top: auto; }   /* 앱 591 = 바닥에서 12 */

/* completed2 등장 — 완드 completed1 과 같은 물결이다(디자이너 지정 2026-09-19).
   ① 머리말 데코가 가운데에서 양쪽으로 펼쳐지고 ② 아래가 하나씩 뜨고 ③ 화살표가 맨 마지막이다.
   시간도 완드와 같다 — 뜨는 시간 1.1, 사이 간격 0.2, 화살표만 한 박자(1.7) 떼어 둔다.
   ⚠️ ① 은 여기 없다 — 디자인시스템 .content-title 이 들고 있다. 뿌리의 .hres.is-in 이 방아쇠다. */
[data-hres-step] { opacity: 0; transform: translateY(16px); }
.hres.is-in [data-hres-step] {
  opacity: 1;
  transform: none;
  transition: opacity 1.1s cubic-bezier(0.33, 1, 0.68, 1), transform 1.1s cubic-bezier(0.16, 1, 0.3, 1);
}
.hres.is-in [data-hres-step="1"] { transition-delay: 0.5s; }
.hres.is-in [data-hres-step="2"] { transition-delay: 0.7s; }
.hres.is-in [data-hres-step="3"] { transition-delay: 0.9s; }
/* 화살표만 한 박자 떼어 둔다 — "맨 마지막에 뜨면서 아래로 유도한다"가 읽혀야 한다 */
.hres.is-in [data-hres-step="4"] { transition-delay: 1.7s; }
.hres.is-in .hres__arrow { animation: hres-nudge 2s ease-in-out 2.95s infinite; }
@keyframes hres-nudge {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(6px); }
}

/* 막대는 completed3 으로 내려올 때마다 바닥에서 자란다(기존 연출 유지). */
.hres__bar { transform: scaleY(0); transform-origin: 50% 100%; transition: transform 0.5s ease; }
.hres.is-three .hres__bar { transform: scaleY(1); transition: transform 0.9s cubic-bezier(0.22, 1, 0.36, 1); }
.hres.is-three .hres__col:nth-of-type(2) .hres__bar { transition-delay: 0.08s; }
.hres.is-three .hres__col:nth-of-type(3) .hres__bar { transition-delay: 0.16s; }
.hres.is-three .hres__col:nth-of-type(4) .hres__bar { transition-delay: 0.24s; }

@media (prefers-reduced-motion: reduce) {
  [data-hres1-step], [data-hres-step] { opacity: 1; transform: none; }
  .hres1.is-in [data-hres1-step],
  .hres.is-in [data-hres-step] { transition: none; }
  .hres1.is-in .hres1__tap,
  .hres.is-in .hres__arrow { animation: none; }
  .hres__bar { transform: scaleY(1); transition: none; }
}

/* ══════════════ 계정관리 (Figma profile/account 2869-6933) ══════════════
   2026-08-27: 배경이 야간 그라디언트 → 단색 #05090A로, 강조색이 blue → purple_300으로 바뀌었다. */
.screen--account { background: #05090A; } /* ⚠️ non-token: Figma 프레임 배경 원본값 */
.account__title {
  margin: 18px auto 0;  /* 헤더(74) + gap 6 + py 12 = 웹 좌표 92 */
  width: 334px;
  /* accent/head1/SB-24 (Figma 2869-6945, 2026-09-17 확인 — 그전엔 base 500 이었다) */
  font-family: var(--font-accent);
  font-weight: 600;
  font-size: 24px;
  line-height: 1.3;
  letter-spacing: -0.01em;
  color: #EFF5FF;
}
.account {
  display: flex;
  flex-direction: column;
  gap: 28px;
  width: 334px;   /* Figma 컨테이너 폭 */
  padding-inline: 4px;
  box-sizing: border-box;
  margin: 32px auto 0;  /* 타이틀 ↔ 그룹 간격 32 (Figma) */
}
.account__group { display: flex; flex-direction: column; gap: 12px; }
.account__group-title {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  margin: 0;
  font-family: var(--font-base);
  font-weight: 500;
  font-size: 20px;
  line-height: 1.5;
  color: #EFF5FF;
}
.account__group-title img { width: 25.24px; height: 15.52px; }
.account__rows { display: flex; flex-direction: column; gap: var(--space-sm); }
.account__row {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  width: 100%;
  padding: var(--space-sm) 0;
  border: 0;
  background: none;
  cursor: pointer;
}
.account__row-label {
  /* base/body1/R-16 (Figma 2869-6954 — Regular. 2026-09-17 확인, 그전엔 Medium) */
  font-family: var(--font-base);
  font-weight: 400;
  font-size: 16px;
  line-height: 1.5;
  letter-spacing: 0.01em;
  color: var(--gray-100);   /* 2026-10-19 Figma list row(T-3)와 같게 — 전 #C2C4C8(non-token) */
}
.account__row-right {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
  font-family: var(--font-base);
  font-weight: 500;
}
.account__row-right em {
  font-style: normal;
  font-size: 12px;              /* typography/M - 12 */
  letter-spacing: 0.2328px;
  color: var(--ice-100);        /* 2026-10-19 Figma list row type=caption 과 같게 ice/100 — 전 text-accent(ice-200) */
}
.account__row-right b {
  /* base/body1/R-16 (Figma 2869-6958 — Regular) */
  font-weight: 400;
  font-size: 16px;
  letter-spacing: 0.01em;
  color: var(--text-secondary);   /* 2026-10-19 Figma list row 값과 같게(흰 50%) — 전 #878A93(non-token) */
}
.account__row-right img { width: 8px; height: 14px; margin-inline: 8px 3px; }

/* ══════════════ 계정관리 하위 화면 — 언어 설정 · 닉네임 변경 ══════════════
   Figma profile/account/language 2698-21445 · profile/account/nickname 2698-21558
   계정관리(.screen--account)와 같은 단색 배경 위에 올라간다. 절대좌표는 전 화면 공통 규칙대로
   피그마 값에서 36px 뺀 값이다. */
.screen--acset { background: #05090A; } /* ⚠️ non-token: Figma 프레임 배경 원본값 */
/* 새 시안(2869-7082)의 헤더는 뒤로가기 하나뿐이다 — 타이틀·지구본이 없다. */
.header--acset {
  box-sizing: border-box;
  height: calc(48px + var(--safe-top));            /* 10 + 38 */
  padding: calc(10px + var(--safe-top)) 20px 0;   /* 26-09-18 36 → 10 */
}

/* ── 언어 설정 (Figma 2698-21524 · top 146 → 110 · w 327) ── */
.aclang {
  display: flex;
  flex-direction: column;
  gap: 12px;
  width: 334px;
  margin: 46px auto 0; /* 헤더 아래 = 웹 좌표 110 (Figma 146 − 36) */
}
.aclang__title {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  margin: 0;
  font-family: var(--font-base);
  font-weight: 500;
  font-size: 20px;
  line-height: 1.5;
  color: #EFF5FF; /* ⚠️ non-token: Figma 섹션 타이틀 */
}
.aclang__title img { width: 25.24px; height: 15.52px; }
.aclang__list { display: flex; flex-direction: column; gap: 12px; }
.aclang__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  padding: var(--space-xs) 0;
  border: 0;
  background: none;
  /* base/body1/R-16 (Figma 2869-7102 · 7106 — Regular) */
  font-family: var(--font-base);
  font-weight: 400;
  font-size: 16px;
  line-height: 1.5;
  letter-spacing: 0.01em;
  color: #878A93; /* ⚠️ non-token: Figma text/secondary */
  text-align: left;
  cursor: pointer;
}
/* 고른 언어 줄만 흰 글자 + 하늘빛 화살표 (Figma 2869-7082: ENGLISH 줄이 고른 상태의 예시 · ic/arrow 3084-8021 은 2026-10-06 #C2E2FF).
   화살표 자리는 31×16 인데 svg 는 블러 여백까지 55×40 이라 자리보다 크게 그린다(시안 inset -75%/-38.71%).
   방향은 svg 그대로 — 긴 꼬리가 오른쪽(디자이너 확인 2026-10-06). 안 고른 줄은 자리만 지키고 안 보인다. */
.aclang__row[aria-checked="true"] { color: var(--white); }
.aclang__arrow {
  position: relative;
  flex-shrink: 0;
  width: 31px;
  height: 16px;
  opacity: 0;
}
.aclang__row[aria-checked="true"] .aclang__arrow { opacity: 1; }
.aclang__arrow img {
  position: absolute;
  top: -12px;
  left: -12px;
  width: 55px;
  height: 40px;
  max-width: none;
}

/* ── 닉네임 변경 (Figma 2879-13226) ──
   2026-08-27: 온보딩 닉네임 입력과 같은 화면 틀(.screen--onboarding2 + .screen__body--onb)로
   옮겼다. 배경·타이틀 위치·필드·CTA가 전부 그쪽 규칙을 그대로 따르므로 전용 CSS가 없다. */

/* ── 확인 팝업 — 로그아웃 · 회원탈퇴 · 동의 거부가 함께 쓴다 ──
   판 · 글자 · 버튼은 디자인시스템 .dialog(components.css — 코치마크 말풍선과 같은 무드, 2026-10-21)다.
   여기서는 딤과 가운데 자리만 정한다. 2026-10-21 전: 가운데 정렬 판(#141B1E 92%) · 테두리 버튼 두 개(one-off). */
.acdialog {
  position: absolute;
  z-index: 20;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}
.acdialog[hidden] { display: none; }
.acdialog__scrim {
  position: absolute;
  inset: 0;
  background: var(--surface-scrim);   /* 2026-10-07 딤 하나로(전: #05090A 70%) */
}
/* 처리 중(로그아웃 · 회원탈퇴 요청, 길게는 몇 초) — 두 버튼을 잠근다. 실행 버튼 글자는 '처리 중…'(app.js setDialogBusy) */
.acdialog.is-busy .dialog__btn:not(.dialog__btn--go) { opacity: 0.4; }

/* ══════════ 닉네임 변경 바텀시트 (Figma profile/account/nickname 3480-18315) ══════════
   계정관리 위에 깔리는 one-off다 — 화면 전환이 아니라 이 화면 안에서 열고 닫는다.
   좌표·색은 시안 실측: 패널 #191919 · 위 모서리 24 · 안쪽 여백 24 · 줄 간격 28. */
.acnick {
  position: absolute;
  z-index: 21;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
}
.acnick[hidden] { display: none; }
.acnick__scrim {
  position: absolute;
  inset: 0;
  background: var(--surface-scrim);   /* Figma 3480-18314 딤 */
}
.acnick__panel {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 28px;
  width: 100%;
  /* 시안(3480-18315) 패널 높이 360 은 사파리 툴바(92)가 덮는 자리까지 포함한 값이다 — 내용 242 + 위아래 24 에
     툴바 밑 92 가 더 있다. 앱에서는 툴바가 뷰포트 밖이라 아래 여백은 24 + 홈 인디케이터 안전 영역만 둔다(2026-09-17). */
  padding: 24px 24px calc(24px + var(--safe-bottom));
  box-sizing: border-box;
  border-radius: 24px 24px 0 0;
  background: #191919; /* ⚠️ non-token: Figma 바텀시트 면색 */
}
.acnick__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.acnick__title {
  margin: 0;
  /* base/head2/M-18 (Figma 3480-18318) */
  font-family: var(--font-base);
  font-weight: 500;
  font-size: 18px;
  line-height: 1.5;
  letter-spacing: 0.005em;
  color: var(--color-white-100);
}
.acnick__cancel {
  padding: 0;
  border: 0;
  background: none;
  /* base/body2/R-14 (Figma 3480-18320 — Regular) */
  font-family: var(--font-base);
  font-weight: 400;
  font-size: 14px;
  line-height: 1.5;
  letter-spacing: 0.01em;
  color: var(--gray-200);
  cursor: pointer;
}
.acnick__group { display: flex; flex-direction: column; gap: 8px; }
.acnick__field {
  display: flex;
  align-items: center;
  gap: 8px;
  /* 시안 높이 54는 보더를 **포함**한 값이다(피그마 inside stroke) — 세로 여백을 px로 주면
     보더 2px이 더해져 56이 된다. 높이를 못 박고 가운데 정렬로 둔다. */
  height: 54px;
  padding: 0 17px;
  box-sizing: border-box;
  position: relative;
  border: 1px solid transparent;   /* 아래 「고리 테두리」 */
  --ring: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Crect width='100%25' height='100%25' fill='%23EAEBEC'/%3E%3C/svg%3E"); /* ⚠️ non-token: Figma background/teritary */
  border-radius: 12px;
}
.acnick__input {
  flex: 1;
  min-width: 0;
  height: 24px;
  padding: 0;
  border: 0;
  background: none;
  /* base/body1/R-16 (Figma 3480-18324 — Regular) */
  font-family: var(--font-base);
  font-weight: 400;
  font-size: 16px;
  line-height: normal;
  letter-spacing: 0.01em;
  color: var(--color-white-100);
}
.acnick__input:focus { outline: none; }
.acnick__clear {
  display: flex;
  flex-shrink: 0;
  width: 18px;
  height: 18px;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}
.acnick__clear img { width: 100%; height: 100%; }
.acnick__meta {
  display: flex;
  justify-content: space-between;
  /* base/body3/R-12 (Figma 3480-18331 · 18333 — Regular) */
  font-family: var(--font-base);
  font-weight: 400;
  font-size: 12px;
  line-height: 1.5;
  letter-spacing: 0.01em;
  color: var(--gray-200);
}
.acnick__save { width: 100%; max-width: none; }

/* ═══════════ 개인정보 동의 v2 — Figma 동의서 v2 작업본 5811:5043 (2026-10-19) ═══════════
   한 오버레이(.consent) 안에 세 겹이 있다 — 동의 시트(①) · 보호자와 함께 안내(A-2′, 전체 화면 — 2026-10-20 만 14세 미만
   ①안, 전: A-1 나이 확인 시트 · A-2 보호자 동의) · 동의서 상세(②~⑤, 전체 화면). 거부 팝업(.acdialog)이 맨 위다. 시트 모양(머리 · 체크 · 전체 동의 · 항목 · 버튼)은
   design-system/components.css 의 동의 · 약관 컴포넌트가 정하고, 여기는 배치만 한다.
   두 화면 이상이 같이 쓰는 오버레이라 .sheet 처럼 .app 안에서 fixed 로 덮는다(.app 의 확대를 따라간다). */
.consent {
  position: fixed;
  z-index: 21;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
}
.consent[hidden] { display: none; }
.consent__scrim {
  position: absolute;
  inset: 0;
  background: var(--surface-scrim);   /* .acnick__scrim 과 같은 딤 */
}
/* 시트 면 — surface/card · 위 모서리 24 · 여백 24/20 · 줄 간격 24 */
.consent__panel {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 24px;
  width: 100%;
  max-height: calc(100% - 48px - var(--safe-top));   /* 화면 위까지는 안 닿게 — 넘치면 시트 안에서 스크롤 */
  overflow-y: auto;
  padding: 24px 20px calc(24px + var(--safe-bottom));
  box-sizing: border-box;
  border-radius: 24px 24px 0 0;
  background: var(--surface-card);
  animation: consent-up 0.32s cubic-bezier(0.22, 0.9, 0.3, 1);
}
.consent__panel[hidden] { display: none; }
/* 아래에서 올라온다. 움직임만 애니메이션으로 준다 — opacity 를 키프레임에 맡기면 탭이 얼었을 때
   시트가 투명한 채 남는다(.form-row 의 form-row-in 과 같은 이유). */
@keyframes consent-up {
  from { transform: translateY(100%); }
  to   { transform: none; }
}
.consent__go { width: 100%; max-width: none; }

/* ═══════════ 자동 가입 방지 확인 — 이메일 [코드 받기] (이슈 #291, 2026-10-26) ═══════════
   시안 없이 기존 부품으로 만든 1차안(개발팀 흐름 시안을 따랐다 — 디자이너 확인 전).
   ② 확인이 덜 끝났을 때 — [코드 받기]에 is-checking: 글자가 「확인 중」으로 바뀌고 앞에 도는 표시(18 · 버튼 글자색).
      버튼은 잠긴 채(disabled 40%)다 — 코드를 보내는 동안의 잠김과 같은 모양에 글자만 바뀐다.
   ③ 상자를 눌러야 할 때 — 동의 시트 겉모양(.consent)을 빌린 바텀시트. 머리 아래 24 에 상자 칸, 아래 여백 40.
      상자 모양은 Cloudflare 가 그려서 못 바꾼다(폭 300 × 높이 65). 디자인이 조금 바뀌어도 어색하지 않게 칸은 높이를 고정하지 않는다. */
.btn-cta__checking { display: none; }
.btn-cta.is-checking > .btn-cta__label { display: none; }
.btn-cta.is-checking > .btn-cta__checking { position: relative; display: inline-flex; align-items: center; gap: 8px; }
/* 2px 테(navy_700 20%)에 윗 4분의 1만 진하게 — 테두리 대신 원뿔 그라디언트 + 고리 마스크로 그린다. 어두운 테두리 색은
   삼성 인터넷 강제 다크 모드에서 밝게 뒤집혀 밝은 버튼 면 위에서 사라진다(그라디언트의 어두운 색은 그대로다 · 2026-10-27) */
.btn-cta__spin {
  flex: none;
  width: 18px;
  height: 18px;
  box-sizing: border-box;
  background: conic-gradient(from -45deg, var(--navy-700) 0 25%, rgba(20, 26, 54, 0.2) 0);   /* ⚠️ non-token: 버튼 글자색(navy_700)의 옅은 테 */
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 2px), #000 calc(100% - 2px));
  mask: radial-gradient(farthest-side, transparent calc(100% - 2px), #000 calc(100% - 2px));
  border-radius: 50%;
  animation: btn-cta-spin 0.8s linear infinite;
}
@keyframes btn-cta-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .btn-cta__spin { animation-duration: 1.6s; } }

.captcha .consent__panel { padding-bottom: calc(40px + var(--safe-bottom)); }
.captcha__slot { display: flex; justify-content: center; min-height: 65px; }

/* 데모 상자 — 데모 창구가 칸에 넣는 진짜 상자 그림(라이브는 Cloudflare 의 iframe 이 이 자리에 온다). 그림을 그대로 놓기만 한다 —
   상자 모양은 Cloudflare 몫이라 꾸미지 않는다. */
.captcha-demo {
  display: block;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.captcha-demo img { display: block; width: 300px; height: 65px; }

/* ═══════════ [코드 다시 받기] — 이메일 코드 칸 오른쪽 아래 (이슈 #313, 2026-10-27) ═══════════
   시안 없이 기존 부품으로 만든 1차안 — 자리는 디자이너 결정(코드 칸 아래 16 · 오른쪽 끝을 칸과 맞춘다).
   글자는 라벨과 같은 base/body2 14 에 밑줄. 보낸 뒤 60초는 「0:42 뒤 다시 받기」로 흐리게(40%) — 눌리지 않는다(app.js paintResend). */
.code-resend {
  align-self: flex-end;   /* 줄(.form-row — 세로 flex)의 오른쪽 끝 = 코드 칸 오른쪽 끝 */
  margin-top: 8px;        /* 줄 간격 8 + 8 = 칸 아래 16(디자이너 10-27 「좀 더 아래로」 — 전: 8) */
  padding: 0;
  border: 0;
  background: none;
  font-family: var(--font-base);
  font-weight: 500;
  font-size: 14px;
  line-height: 1.5;
  letter-spacing: 0.005em;
  color: var(--gray-100);
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}
.code-resend:disabled {
  opacity: 0.4;
  text-decoration: none;
  font-variant-numeric: tabular-nums;   /* 남은 시간이 줄어도 글자 폭이 흔들리지 않게 */
  cursor: default;
}

/* 항목 목록 — 좌우 16 들여 · 간격 16 */
.consent__list {
  display: flex;
  flex-direction: column;
  gap: 16px;
  margin: 0;
  padding: 0 16px;
  list-style: none;
}
/* 「만 14세 미만인가요?」 — 시안은 목록 칸 안(마지막 항목 아래 16 · 좌 16)의 13 · gray_200 · 밑줄 글. 목록 밖에 두고 시트 줄
   간격(24)에서 8 을 당겨 16 으로 맞춘다. 누를 자리는 위아래로 넓힌다(글 크기 그대로). */
.consent__under14 {
  align-self: flex-start;
  margin: -8px 16px 0;
  padding: 0;
  border: 0;
  background: none;
  font-family: var(--font-base);
  font-weight: 400;
  font-size: 13px;           /* ⚠️ non-token: 시안 13(본문 글 크기 체계 밖) */
  line-height: 1.5;
  letter-spacing: 0.01em;
  color: var(--gray-200);
  text-decoration: underline;
  text-underline-position: from-font;
  cursor: pointer;
}

/* ── A-2′ 만 14세 미만 · 보호자와 함께 안내 (Figma 6017:9626) — 전체 화면 · 세로 스크롤 · neutral/1000 ──
   헤더(뒤로) 아래 20 → 335 폭 본문. 묶음 간격 32 · 머리 묶음(제목 + 어린이 안내) 20 · 제목 묶음 8 · 이렇게 해 주세요 12. */
.under14,
.docview {
  position: absolute;
  inset: 0;
  z-index: 1;
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior-y: contain;
  background: var(--neutral-1000);
}
.under14[hidden],
.docview[hidden] { display: none; }
/* 헤더(뒤로) — 화면 헤더(.screen__header)와 같은 자리 · 높이(위 10 + 38). 본문과 함께 스크롤된다(시안 한 장) */
.under14__header,
.docview__header {
  height: calc(48px + var(--safe-top));
  padding-top: calc(10px + var(--safe-top));
  padding-bottom: 0;
}
.under14__body {
  display: flex;
  flex-direction: column;
  gap: 32px;
  width: 335px;
  margin: 20px auto 0;
  padding-bottom: calc(32px + var(--safe-bottom));
}
.under14__intro { display: flex; flex-direction: column; gap: 20px; }
.under14__head { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; }
.under14__title {
  margin: 0;
  /* accent/head1/SB-24 */
  font-family: var(--font-accent);
  font-weight: 600;
  font-size: 24px;
  line-height: 1.3;
  letter-spacing: -0.01em;
  color: var(--text-primary);
}
.under14__lead {
  margin: 0;
  word-break: keep-all;
  /* base/body2/R-14 */
  font-family: var(--font-base);
  font-weight: 400;
  font-size: 14px;
  line-height: 1.5;
  letter-spacing: 0.01em;
  color: var(--gray-200);
}
.under14__group { display: flex; flex-direction: column; gap: 12px; }
.under14__h {
  margin: 0;
  /* base/body1/M-16 */
  font-family: var(--font-base);
  font-weight: 500;
  font-size: 16px;
  line-height: 1.5;
  letter-spacing: 0.005em;
  color: var(--text-primary);
}
/* 차례 — 시안은 "1. …" 글 세 줄(간격 12)이고 둘째 줄이 번호 아래에서 시작한다(내어쓰기 없음). 번호는 목록이 매긴다. */
.under14__steps {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: under14-step;
  word-break: keep-all;
  /* base/body2/R-14 */
  font-family: var(--font-base);
  font-weight: 400;
  font-size: 14px;
  line-height: 1.5;
  letter-spacing: 0.01em;
  color: var(--gray-200);
}
.under14__steps li::before {
  counter-increment: under14-step;
  content: counter(under14-step) '. ';
}
.under14 .btn-cta { width: 100%; max-width: none; }

/* ── 동의서 상세(②~⑤ · 이용약관) — 헤더 아래 20 → 335 폭 문서 ── */
.docview .legal {
  width: 335px;
  margin: 20px auto 0;
  padding-bottom: calc(56px + var(--safe-bottom));
}

@media (prefers-reduced-motion: reduce) {
  .consent__panel,
  .docsheet__panel { animation: none; }
}

/* ═══════════ 약관 시트 — 로그인 · 스플래시 아래 약관 링크 (Figma S-1 5906:15204 · S-2 5906:15292, 2026-10-19) ═══════════
   거의 전체 높이(시안 72 · 앱 10 에서 시작) · surface/card · 위 모서리 24 · 머리(sheet header document) 고정 ·
   본문만 스크롤 · 아래 48 은 시트 면색으로 흐려 "더 있음"을 보인다. */
.docsheet {
  position: fixed;
  z-index: 21;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
}
.docsheet[hidden] { display: none; }
.docsheet__scrim {
  position: absolute;
  inset: 0;
  background: var(--surface-scrim);
}
.docsheet__panel {
  position: relative;
  display: flex;
  flex-direction: column;
  height: calc(var(--screen-h) - 10px - var(--safe-top));   /* 시안 72(앱 10)에서 시작해 화면 아래끝까지 */
  overflow: hidden;
  border-radius: 24px 24px 0 0;
  background: var(--surface-card);
  animation: consent-up 0.32s cubic-bezier(0.22, 0.9, 0.3, 1);
}
.docsheet__panel::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 48px;
  background: linear-gradient(180deg, transparent 0%, var(--surface-card) 100%);   /* 시안 #191919 0→100 — 면색(surface/card)으로 맞췄다 */
  pointer-events: none;
}
.docsheet__body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior-y: contain;
  padding: 8px 20px calc(24px + 48px + var(--safe-bottom));   /* 시안 아래 24 + 흐림 48 — 마지막 줄이 흐림 위로 올라오게 */
}

/* ═══════════ 약관 · 동의서 문서 — legal.css 로 옮겼다(2026-10-20) ═══════════
   주소로 바로 여는 /terms · /privacy 페이지(terms.html · privacy.html)도 같은 규칙을 써서, 앱 전체(app.css)를 싣지 않게
   따로 뺐다. index.html 은 components.css 다음에 legal.css 를 싣는다. */

/* ═══════════ 약관 페이지 — 계정관리 「약관 및 정책」 (Figma T-1 5811:5471 · T-2 5811:5631) ═══════════
   neutral/1000 바탕 · 헤더(뒤로) 아래 본문이 세로로 스크롤된다(화면이 스크롤 상자 — .screen--home 과 같은 방식). */
.screen--legal {
  --edge: var(--neutral-1000);
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior-y: contain;
  background: var(--neutral-1000);
}

/* ═══════════ 마법약 결과 — 새 시안 (2026-09-21) ═══════════
   Figma completed1 3845-41672 · completed2 3845-41635 (체험중 sorting 4163-14647 은 2026-10-13 걷었다).
   좌표는 전부 시안 y − 62(상태바). 완드·기숙사와 같은 밤하늘 언어다.

   ⚠️ 별 배경(.p*__stars)은 기숙사 것과 **같은 파일**이다(시안 렌더 대조 평균차 0.66/255).
      assets/result/house/bg-stars.webp 를 그대로 가리킨다 — 두 화면이 같이 쓰게 되었으니
      나중에 assets/result/ 로 올리면 좋겠다.
   ⚠️ 빛무리·밑줄도 슬리데린 것과 같은 파일이다(색이 green 계열이라 그렇다). 지금은 물약
      폴더에 사본을 뒀다 — content/title 처럼 색으로 키를 잡아 한 곳에 모으는 게 맞다. */

/* ── 별 배경 — 두 화면이 같이 쓴다(기숙사 .hres__stars 와 같은 자리) ── */
.pres__stars {
  position: absolute;
  z-index: 0;
  top: -186px;
  left: calc(62.5% - 29.38px);
  width: 426px;
  height: 1060px;
  opacity: 0.6;
  transform: translateX(-50%);
  pointer-events: none;
}
.pres__stars img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  mix-blend-mode: plus-lighter;
}
/* 결과 두 화면은 별을 70% 로 깐다(2026-10-07 시안 — export 는 이 70% 를 알파에 구워 둔다) */
.pres__stars img { opacity: 0.7; }

/* 약장 사진 — 결과 두 화면의 맨 아래(2026-10-07 시안 bg-potion). 홈 물약 섹션과 **같은 그림**이다
   (assets/home/section/potion.webp — 그림 40% 는 알파에 들어 있다, 시안 export 와 평균차 2/255).
   887 × 1063 · left −256 · top −313(시안 −251) · 레이어 90% · 그 위에 물약 색의 세로 덮개(POTION_TONE.tint). */
.pres__room {
  position: absolute;
  z-index: 0;
  top: -313px;
  left: -256px;
  width: 887px;
  height: 1063px;
  opacity: 0.9;
  pointer-events: none;
}
.pres__room img { display: block; width: 100%; height: 100%; object-fit: cover; }
.pres__room::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, var(--pres-tint, rgba(2, 56, 0, 0.1) 0%, rgba(60, 82, 0, 0.06) 50%, rgba(2, 56, 0, 0.09) 100%)); /* ⚠️ non-token: 시안 덮개 */
}

/* ── ① completed1 — 병 한 장 ── */
.pres1 {
  position: relative;
  width: 375px;
  min-height: var(--screen-h);
  overflow: hidden;
  background: var(--black);
  cursor: pointer;
}
.pres1__glow {
  position: absolute;
  z-index: 0;
  top: -281px;                  /* 시안 −219 */
  left: calc(50% + 0.5px);
  width: 644px;
  height: 493px;
  transform: translateX(-50%);
  pointer-events: none;
}
.pres1__glow img {
  position: absolute;
  inset: -20.28% -15.53%;       /* export 는 타원 644 × 493 에 번짐 여백 100 씩 — 844 × 693 */
  width: auto;
  height: auto;
  max-width: none;
}
.pres1__title {
  position: absolute;
  z-index: 1;
  top: 65px;
  /* ⚠️ 가운데 맞춤을 transform 으로 하지 않는다 — 등장 연출이 transform 을 쓴다(.hres1 주석). */
  left: calc(50% - 95px);
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 190px;
}
.pres1__kicker {
  width: 100%;
  margin: 0 0 -10px;            /* 시안 mb −10 — 밑줄이 글씨에 바짝 붙는다 */
  /* accent/body1/R-18 */
  font-family: var(--font-accent);
  font-weight: 400;
  font-size: 18px;
  line-height: 1.5;
  letter-spacing: -0.01em;
  text-align: center;
  color: #FEFDFC;                          /* ⚠️ non-token: 시안 제목 */
  text-shadow: 0 0 4px #DAB8A3;            /* ⚠️ non-token: 시안 제목 번짐 */
}
.pres1__rule { display: block; width: 190px; height: 21px; }
/* 병 블록 — 시안 375 폭 안에서 319(폴리주스 · 펠릭스 327) 높이. 사선 한 줄이 병 뒤를 지난다.
   top 은 물약마다 177 · 185 다(POTION_SKIN.artTop). */
.pres1__art {
  position: absolute;
  z-index: 1;
  top: var(--pres1-art-top, 185px);
  left: 0;
  width: 100%;
  height: 319px;
}
/* 사선 칸은 시안 386(387) × 274 를 left −5 · top 22 에 두고, export 는 선 두께만큼 사방으로 조금 크다
   (inset −0.22% −0.13%) — 그 크기가 곧 viewBox(POTION_DIAG w · h)라 1:1 로 앉힌다. */
.pres1__diag {
  position: absolute;
  top: 21.4px;
  left: -5.5px;
  width: var(--diag-w, 386px);
  height: var(--diag-h, 275.203px);
  overflow: visible;
}
/* 병 — 회전 전 칸에 기울기 · 그림자를 건다(POTION_SKIN c1 · c2, potionBottleHtml). 두 화면이 같은 틀이다.
   병은 사선 **앞**이다(시안 레이어 순서 그대로 — 마크업에서 사선 뒤에 온다).
   그림은 칸 안에서 crop 대로 놓이고 칸 밖은 잘린다(지금은 crop 을 쓰는 병이 없다). 그림자(filter)는 그 자르기에 안 걸린다. */
.pres1__bottle,
.pres__bottle {
  position: absolute;
  top: var(--b-top);
  left: var(--b-left);
  width: var(--b-w);
  height: var(--b-h);
  overflow: hidden;
  transform: rotate(var(--b-tilt, 0deg));
  filter: var(--b-filter, none);
}
.pres1__bottle img,
.pres__bottle img {
  position: absolute;
  top: 0;
  left: var(--crop-left, 0%);
  width: var(--crop-w, 100%);
  height: 100%;
  max-width: none;
}
.pres1__tap {
  position: absolute;
  z-index: 1;
  top: 573px;
  left: 0;
  width: 100%;
  margin: 0;
  text-align: center;
  /* Lumos Caps 24 — 시안 행간이 20 이다(글자 크기보다 작다) */
  font-family: var(--font-display);
  font-size: 24px;
  line-height: 20px;
  letter-spacing: -0.5px;
  white-space: nowrap;
  color: var(--white);
}

/* ── ② completed2 — 이름·사용재료·본문·저장 ── */
.pres {
  position: relative;
  width: 375px;
  min-height: var(--screen-h);
  overflow: hidden;
  background: var(--black);
}
.pres__glow {
  position: absolute;
  z-index: 0;
  top: 380px;                   /* 시안 442 */
  left: calc(50% + 0.5px);
  width: 644px;
  height: 493px;
  transform: translateX(-50%) scaleY(-1);
  pointer-events: none;
}
.pres__glow img {
  position: absolute;
  inset: -20.28% -15.53%;
  width: auto;
  height: auto;
  max-width: none;
}
.pres__header {
  position: absolute;
  z-index: 2;
  top: 10px;
  left: 0;
  display: flex;
  align-items: center;
  width: 100%;
  height: 38px;
  padding: 4px 20px;
  box-sizing: border-box;
}
.pres__close {
  display: flex;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}
.pres__close img { display: block; width: 24px; height: 24px; }
/* 머리말은 디자인시스템 .content-title 이다 — 자리만 여기서 잡는다. */
.pres > .content-title {
  position: absolute;
  z-index: 1;
  top: var(--pres-title-top, 54px);   /* 스켈레그로만 58(POTION_SKIN.titleTop) */
  left: calc(50% - 156.248px);
}
/* 시안은 머리말 두 줄 사이가 4 다(Column gap 4 — 머리말 높이 104). 디자인시스템 .content-title 은 이 4 가 빠져 있어
   (컴포넌트 렌더 94 ↔ 시안 98) 물약 화면에서만 채운다 — 완드 · 기숙사 결과는 그 높이에 맞춰 자리를 잡아 두어 손대지 않았다. */
.pres .content-title__text { gap: 4px; }
/* 결과 이름(Nimbus Roman 40)은 디자인시스템 .content-title 의 기본값이다(2026-10-14 — 전: 화면마다 덮어씀). */
/* 살아있는 죽음의 물약(gray) — 이름이 위 흰색에서 아래 회보라 60% 로 흐려진다(시안 5085-19201) */
.pres .content-title--gray .content-title__name {
  /* ⚠️ non-token: 시안 linear-gradient(180deg, #FFFFFF, rgba(125,113,138,.6)) — 단색 + 투명도로 다시 쓴 그림(assets/shared/grad) — CSS 그라디언트는 삼성 인터넷 강제 다크 모드에서 어두워진다(tokens.css --paint-*) */
  background-image: url('assets/shared/grad/text-title-gray-potion.svg');
}
/* 병 — 화면 좌표로 바로 놓는다(POTION_SKIN c2). 이 층은 등장 물결(data-pres-step)만 맡는다. */
.pres__art {
  position: absolute;
  z-index: 1;
  top: 0;
  left: 0;
  width: 100%;
  height: 0;
}
.pres__meta {
  position: absolute;
  z-index: 1;
  top: var(--pres-meta-top, 371px);   /* 물약마다 371~375(POTION_SKIN.metaTop) — 본문은 이 아래 65 */
  left: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  width: 100%;
}
.pres__meta-label {
  width: 302px;
  margin: 0;
  opacity: 0.7;
  /* accent/body4/R-12 */
  font-family: var(--font-accent);
  font-weight: 400;
  font-size: 12px;
  line-height: 1.5;
  letter-spacing: -0.01em;
  text-align: center;
  color: var(--blue-50);
}
.pres__meta-row {
  display: flex;
  gap: 6px;
  margin: 0;
  /* accent/body3/R-14 */
  font-family: var(--font-accent);
  font-weight: 400;
  font-size: 14px;
  line-height: 1.5;
  letter-spacing: -0.01em;
  white-space: nowrap;
  color: var(--gray-100);
}
.pres__desc {
  position: absolute;
  z-index: 1;
  top: calc(var(--pres-meta-top, 371px) + 65px);   /* 사용재료 41 + 간격 24 */
  left: calc(50% - 168px);
  width: 336px;
  margin: 0;
  opacity: 0.7;
  /* accent/body2/R-16 */
  font-family: var(--font-accent);
  font-weight: 400;
  font-size: 16px;
  line-height: 1.5;
  letter-spacing: -0.01em;
  text-align: center;
  color: var(--gray-200);
}
.pres__desc b { font-weight: 400; color: var(--white); }
.pres__desc em { font-style: normal; color: var(--white); }
/* 저장 줄은 화면 바닥에서 12 — 결과 화면 여섯이 같은 자리다(2026-10-22 디자이너 "가장 하단에서 12px 위로 고정").
   전에는 위에서 잰 591(아모텐시아 587)이라 보이는 높이가 658 이 아니면 바닥과의 간격이 달라졌다. */
.pres__actions {
  position: absolute;
  z-index: 1;
  bottom: calc(12px + var(--ui-gap));
  left: calc(50% - 167.5px);
}

/* ── 등장 연출 — 완드·기숙사와 같은 물결이다(뜨는 시간 1.1, 사이 간격 0.2) ──
   ⚠️ 머리말 줄이 좌우로 펼쳐지는 몫은 여기 없다 — .content-title 이 들고 있고
      뿌리의 is-in 이 방아쇠다(design-system/components.css). */
[data-pres1-step], [data-pres-step] { opacity: 0; transform: translateY(16px); }
.pres1.is-in [data-pres1-step],
.pres.is-in [data-pres-step] {
  opacity: 1;
  transform: none;
  transition: opacity 1.1s cubic-bezier(0.33, 1, 0.68, 1), transform 1.1s cubic-bezier(0.16, 1, 0.3, 1);
}
.pres1.is-in [data-pres1-step="1"], .pres.is-in [data-pres-step="1"] { transition-delay: 0.5s; }
.pres1.is-in [data-pres1-step="2"], .pres.is-in [data-pres-step="2"] { transition-delay: 0.7s; }
.pres1.is-in [data-pres1-step="3"] { transition-delay: var(--pres1-tap-delay); }   /* tap — 아랫선까지 다 펼쳐진 뒤 */
.pres.is-in [data-pres-step="3"] { transition-delay: 0.9s; }
.pres.is-in [data-pres-step="4"] { transition-delay: 1.1s; }
.pres.is-in [data-pres-step="5"] { transition-delay: 1.3s; }
/* tap 안내는 다 뜬 뒤(나타나는 1.1s 가 끝난 뒤) 까딱인다 — 일찍 돌면 깜빡임이 opacity 를 쥐어 툭 나타난다 */
.pres1.is-in .pres1__tap { animation: hres-blink 2.4s ease-in-out calc(var(--pres1-tap-delay) + 1.1s) infinite; }

/* completed1 가운데 — 병이 오른쪽 화면 밖에서 기울어진 채(물약마다 −15° ~ 13.7°) 들어와 **가운데에 멈추고**,
   멈춘 순간 뒤의 사선(Vector 716)이 펼쳐진다(2026-10-22 디자이너 지정, 전: 사선과 병이 한 곡선으로 같이 움직였다).
   · 병은 **빠르게 들어와 거의 다 왔을 때 길게 느려지며** 앉는다 — 감속이 긴 ease-out 곡선 하나(0.9s).
     전에는 시안 Smart animate S 곡선(cubic-bezier(0.75, 0, 0.09, 0.84), 800ms)이라 느리게 떼는 첫 박자가
     둔탁하게 읽혔다(2026-10-22 디자이너 피드백). 튕김 없이 그대로 멈춘다.
   · 병이 자리에 앉은 순간(곡선이 거의 끝난 0.72 지점) **윗선이 가운데에서 양옆으로** 퍼지며 생긴다 —
     pathLength=1 이라 dash 길이 t 를 0 → 1 로 늘리면서 시작점을 0.5 − t/2 로 당긴다(dashoffset −0.5 → 0).
     퍼지는 게 눈에 보이게 1s 에 걸쳐 천천히 떠나 부드럽게 닿는다(전 0.45s — 너무 빨라 "퍼진다"가 안 읽혔다,
     2026-10-22 디자이너 피드백).
   · 윗선이 거의 다 펼쳐질 즈음(90%) **아랫선이 윗선 밑에서 아래로** 펼쳐지고, 바탕면(2%)도 윗선에 붙어
     있다가 아랫선을 따라 펼쳐진다 — 천천히 떠나 가운데서 빨라졌다가 제자리에 부드럽게 닿는다(0.45s, 튕김 · 탄성 없음).
     둘은 윗선 아래쪽에서만 보인다(app.js potionDiagHtml 의 pres1-under) — 윗선 위로 삐져나오지 않는다.
     전에는 처음이 너무 빨라 튕겨 나오는 것처럼, 그다음엔 윗선보다 위에서 내려오는 것처럼 보였다(2026-10-22 디자이너 피드백).
   · tap to continue 는 아랫선까지 다 펼쳐진 뒤에 뜨고, 다 뜬 뒤에 깜빡이기 시작한다(--pres1-tap-delay).
   · 효과음(potionReveal)이 이 흐름에 맞춰 한 번 울린다 — 병이 들어올 때 휙 · tap to continue 가 뜰 때 띠링(app.js SOUNDS).
   · 병은 흐려졌다 나타나지 않는다 — 화면 밖(380px)에서 불투명한 채 들어온다. 서서히 드러나면 "등장"이
     아니라 "스르륵 나타남"으로 읽혔다(2026-09-21 디자이너 피드백).
   ⚠️ 병의 기울기는 transform 이 쥐고 있어 움직임은 개별 속성(translate · rotate)으로 준다 —
      한 요소에 transform 둘은 못 건다(인수인계 문서 "거듭 걸렸던 것"). rotate 는 transform 에 더해진다. */
.pres1 {
  --pres1-in-delay: 0.7s;                              /* 머리말 다음 물결 */
  --pres1-in-dur: 0.9s;
  --pres1-in-ease: cubic-bezier(0.16, 1, 0.3, 1);      /* 빠르게 들어와 길게 느려진다(ease-out expo 꼴) */
  --pres1-line-delay: calc(var(--pres1-in-delay) + var(--pres1-in-dur) * 0.72);   /* 병이 자리에 앉은 순간 */
  --pres1-line-dur: 1s;
  --pres1-line-ease: cubic-bezier(0.45, 0, 0.2, 1);     /* 가운데서 천천히 떠나 양끝에 부드럽게 닿는다 */
  --pres1-drop-delay: calc(var(--pres1-line-delay) + var(--pres1-line-dur) * 0.9);
  --pres1-drop-dur: 0.45s;
  --pres1-drop-ease: cubic-bezier(0.45, 0, 0.25, 1);   /* 천천히 떠나 부드럽게 닿는다 — 넘치지 않는다 */
  --pres1-tap-delay: calc(var(--pres1-drop-delay) + var(--pres1-drop-dur));   /* 아랫선이 다 펼쳐진 순간 */
}
.pres1__line { stroke-dasharray: 1 1; }
/* 윗선 — 가운데 한 점(길이 0)에서 시작한다 */
.pres1__line--top { stroke-dasharray: 0 1; stroke-dashoffset: -0.5; }
/* 아랫선은 그려지는 게 아니라 **통째로 내려온다** — 처음부터 다 그려 둔 채 윗선 자리(219.5 위)에
   숨겨 둔다. 두 선의 세로 간격은 왼쪽 끝 218.4 · 오른쪽 끝 220.5 라 평균을 쓴다(모양이 조금 달라
   딱 겹치지는 않지만 내려오는 동안이라 눈에 안 걸린다).
   ⚠️ SVG 안 요소의 translate px 는 viewBox 단위다 — preserveAspectRatio="none" 으로 늘여도 두 선이
      같은 좌표계라 간격이 그대로 맞는다. */
.pres1__line--bottom { stroke-dashoffset: 0; opacity: 0; translate: 0 -219.5px; }
/* 바탕면은 윗선에 붙어 있다가 아랫선을 따라 아래로 펼쳐진다 */
.pres1__band { transform-box: fill-box; transform-origin: 50% 0; scale: 1 0; }
.pres1__bottle { translate: 380px 0; }          /* 가장 왼쪽 병 윤곽(살아있는 죽음의 물약 ~101, 2026-10-12 새 병) + 380 − 그림자 24 > 375 — 전부 화면 밖 */

/* transition 이 아니라 animation 이다 — 시작값이 위 기본값이라 is-in 이 붙는 순간과 상관없이 늘 같은
   궤적을 탄다. */
.pres1.is-in .pres1__bottle {
  animation: pres1-arrive var(--pres1-in-dur) var(--pres1-in-ease) var(--pres1-in-delay) forwards;
}
.pres1.is-in .pres1__line--top {
  animation: pres1-spread var(--pres1-line-dur) var(--pres1-line-ease) var(--pres1-line-delay) forwards;
}
.pres1.is-in .pres1__line--bottom {
  animation: pres1-drop var(--pres1-drop-dur) var(--pres1-drop-ease) var(--pres1-drop-delay) forwards;
}
.pres1.is-in .pres1__band {
  animation: pres1-unroll var(--pres1-drop-dur) var(--pres1-drop-ease) var(--pres1-drop-delay) forwards;
}
/* 보이는 구간 = [0.5 − t/2, 0.5 + t/2] — dash t 를 늘리며 시작점을 가운데에서 왼쪽 끝으로 당긴다 */
@keyframes pres1-spread {
  from { stroke-dasharray: 0 1; stroke-dashoffset: -0.5; }
  to   { stroke-dasharray: 1 1; stroke-dashoffset: 0; }
}
/* 아랫선은 윗선과 겹친 채 나타나면 한 줄이 갑자기 진해 보여서 처음 15% 동안 서서히 드러난다.
   0% 에 opacity 를 적어 둬야 기다리는 동안(delay)은 시작값(숨김)을 쓴다. 곡선(--pres1-drop-ease)은 translate 의
   0 → 100% 한 구간에 한 번 걸린다(15% 에는 opacity 만 있다). */
@keyframes pres1-drop {
  0%   { opacity: 0; translate: 0 -219.5px; }
  15%  { opacity: 1; }
  100% { opacity: 1; translate: 0 0; }
}
@keyframes pres1-unroll { to { scale: 1 1; } }
/* 곡선은 animation 쪽(--pres1-in-ease)이 쥐고 있다 — 여기는 출발점과 도착점뿐이다. */
@keyframes pres1-arrive {
  from { translate: 380px 0; }
  to   { translate: 0 0; }
}

@media (prefers-reduced-motion: reduce) {
  [data-pres1-step], [data-pres-step] { opacity: 1; transform: none; }
  .pres1.is-in [data-pres1-step],
  .pres.is-in [data-pres-step] { transition: none; }
  .pres1.is-in .pres1__tap { animation: none; }
  .pres1__line, .pres1__line--top { stroke-dasharray: 1 1; stroke-dashoffset: 0; }
  .pres1__line--bottom { opacity: 1; translate: none; }
  .pres1__band { scale: none; }
  .pres1__bottle { translate: none; }
  .pres1.is-in .pres1__line, .pres1.is-in .pres1__band, .pres1.is-in .pres1__bottle { animation: none; }
}

/* ══════════════ 패트로누스 결과 (Figma result_patronus/<동물>/completed1 · completed2, 2026-10-09) ══════════════
   물약 결과(.pres1 · .pres)와 같은 두 장이다. 좌표는 전부 시안 y − 62. 동물마다 다른 그림 자리 · 기울기 ·
   성향 top 은 app.js PATRONUS_SKIN 이 --a-* · --pat-traits-top 으로 내려준다. */

/* 밤빛 라디얼 — 우상단에서 아주 옅게 밝아진다(#010209 → #010305 89.4%). 기울어진 타원(svg gradientTransform)을
   375 × 812 판 그대로 깐다(스플래시와 같은 방법). ⚠️ non-token: 시안 값 */
.pat-bg {
  background:
    url("data:image/svg+xml;utf8,<svg viewBox='0 0 375 812' xmlns='http://www.w3.org/2000/svg' preserveAspectRatio='none'><rect x='0' y='0' height='100%' width='100%' fill='url(%23g)'/><defs><radialGradient id='g' gradientUnits='userSpaceOnUse' cx='0' cy='0' r='10' gradientTransform='matrix(-24.75 44 -37.5 -21.094 375 0)'><stop stop-color='rgb(1,2,9)' offset='0'/><stop stop-color='rgb(1,3,5)' offset='0.89426'/></radialGradient></defs></svg>")
      0 -62px / 375px 812px no-repeat,
    #010305;
}

/* ── ① completed1 — 동물 한 마리 ── */
.pat1 {
  position: relative;
  width: 375px;
  min-height: var(--screen-h);
  overflow: hidden;
  cursor: pointer;
}
/* 아래 빛무리(Ellipse 1622, 세로 뒤집힘) — 시안 524 */
.pat1__glow {
  position: absolute;
  z-index: 0;
  top: 462px;
  left: calc(50% - 3.5px);
  width: 644px;
  height: 493px;
  transform: translateX(-50%) scaleY(-1);
  pointer-events: none;
}
.pat1__glow img,
.pat__glow img {
  position: absolute;
  inset: -24.34% -18.63%;       /* export 는 타원 644 × 493 에 번짐 여백 120 씩 — 884 × 733 */
  width: auto;
  height: auto;
  max-width: none;
}
/* 우상단 빛기둥(Group 1160) — 30° 기울고 세로 뒤집힌 채 칸 가운데에 선다. export 는 번짐 여백까지 520 × 627 */
.pat1__beam {
  position: absolute;
  z-index: 0;
  top: -358px;                  /* 시안 −296 */
  left: calc(50% - 144.5px);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 564.739px;
  height: 603.65px;
  pointer-events: none;
}
.pat1__beam img {
  display: block;
  flex: none;
  width: 520.454px;
  height: 626.758px;
  transform: rotate(30deg) scaleY(-1);
}
.pat1__title {
  position: absolute;
  z-index: 1;
  top: 74px;                    /* 시안 136 */
  /* ⚠️ 가운데 맞춤을 transform 으로 하지 않는다 — 등장 연출이 transform 을 쓴다(.hres1 주석). */
  left: calc(50% - 95px);
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 190px;
}
.pat1__kicker {
  width: 100%;
  margin: 0 0 -10px;            /* 시안 mb −10 — 리본이 글씨에 바짝 붙는다 */
  /* accent/body1/R-18 */
  font-family: var(--font-accent);
  font-weight: 400;
  font-size: 18px;
  line-height: 1.5;
  letter-spacing: -0.01em;
  text-align: center;
  color: #FEFDFC;                          /* ⚠️ non-token: 시안 제목(물약 · 기숙사 completed1 과 같다) */
  text-shadow: 0 0 4px #DAB8A3;            /* ⚠️ non-token: 시안 제목 번짐 */
}
.pat1__rule { display: block; width: 190px; height: 21px; }
/* 동물 · 그늘 · 반짝이 층 — 등장 물결(data-pat1-step)만 맡고 자식은 화면 좌표로 놓인다. */
.pat1__art,
.pat__art {
  position: absolute;
  z-index: 1;
  top: 0;
  left: 0;
  width: 100%;
  height: 0;
}
/* 바닥 그늘(Group 1173) — 시안 483, 세로 뒤집힘. export 는 번짐 여백까지 370 × 196 */
.pat1__shadow {
  position: absolute;
  top: 421px;
  left: 60px;
  width: 184.083px;
  height: 68.89px;
  transform: scaleY(-1);
}
.pat1__shadow img {
  position: absolute;
  inset: -92.04% -50.5%;
  width: auto;
  height: auto;
  max-width: none;
}
/* 동물 — 회전 전 칸에 기울기를 건다(PATRONUS_SKIN c1 · c2, patronusArtHtml). 두 화면이 같은 틀이다. */
.pat1__animal,
.pat__animal {
  position: absolute;
  top: var(--a-top);
  left: var(--a-left);
  width: var(--a-w);
  height: var(--a-h);
  transform: rotate(var(--a-tilt, 0deg));
}
.pat1__animal img,
.pat__animal img { display: block; width: 100%; height: 100%; object-fit: cover; }
/* 물방울 반짝이 — 수달 completed1 에만 있다(시안 image 506 여덟 개). 투명도는 개마다 다르다(0.4 · 0.6 · 1). */
.pat1__spark {
  position: absolute;
  top: var(--s-top);
  left: var(--s-left);
  width: var(--s-size);
  height: var(--s-size);
  opacity: var(--s-op, 1);
  transform: rotate(var(--s-tilt, 0deg));
  background: url('assets/result/patronus/sparkle.webp') center / cover no-repeat;
}
.pat1__tap {
  position: absolute;
  z-index: 1;
  top: 575px;                   /* 시안 637 */
  left: 0;
  width: 100%;
  margin: 0;
  text-align: center;
  /* Lumos Caps 24 — 시안 행간이 20 이다(글자 크기보다 작다) */
  font-family: var(--font-display);
  font-size: 24px;
  line-height: 20px;
  letter-spacing: -0.5px;
  white-space: nowrap;
  color: var(--white);
}

/* ── ② completed2 — 이름 · 성향 · 저장 ── */
.pat {
  position: relative;
  width: 375px;
  min-height: var(--screen-h);
  overflow: hidden;
}
/* 커튼(scanner_scan_qr) — 2100 × 816 을 오른쪽으로 치우쳐(가운데 x 398) 깔고 6 만큼 흐린다.
   그림의 80% 는 export 알파에 구워져 있다 — 여기서 다시 묽히지 않는다. 덮개 그라디언트도 흐림 안쪽이다(시안 그대로). */
.pat__curtain {
  position: absolute;
  z-index: 0;
  top: -64px;                   /* 시안 −2 */
  left: -652px;
  width: 2100px;
  height: 816px;
  filter: blur(6px);
  pointer-events: none;
}
.pat__curtain img { position: absolute; inset: 0; width: 100%; height: 100%; }
.pat__curtain::after {
  content: '';
  position: absolute;
  inset: 0;
  /* ⚠️ non-token: 시안 덮개 */
  background: linear-gradient(180deg, rgba(8, 5, 15, 0.5) 26.471%, rgba(4, 3, 8, 0) 44.363%, rgba(0, 0, 0, 0.45) 84.789%);
}
/* 위 빛무리(Ellipse 1623) — 시안 −236 */
.pat__glow {
  position: absolute;
  z-index: 0;
  top: -298px;
  left: calc(50% - 3.5px);
  width: 644px;
  height: 493px;
  transform: translateX(-50%);
  pointer-events: none;
}
/* 머리말은 디자인시스템 .content-title(lightblue) — 자리 · 이름 덮어쓰기는 물약(.pres)과 같다. */
.pat > .content-title {
  position: absolute;
  z-index: 1;
  top: 54px;                    /* 시안 116 */
  left: calc(50% - 156.248px);
}
.pat .content-title__text { gap: 4px; }
.pat__traits {
  position: absolute;
  z-index: 1;
  top: var(--pat-traits-top, 359px);   /* 동물마다 352 ~ 372(PATRONUS_SKIN.traitsTop) */
  left: calc(50% - 168px);
  display: flex;
  flex-direction: column;
  gap: 16px;
  width: 336px;
}
.pat__trait { display: flex; flex-direction: column; align-items: center; gap: 4px; width: 100%; }
.pat__trait-name {
  display: flex;
  align-items: center;
  gap: 5px;
  margin: 0;
  padding: 0 12px;
  /* accent/body2/R-16 */
  font-family: var(--font-accent);
  font-weight: 400;
  font-size: 16px;
  line-height: 1.5;
  letter-spacing: -0.01em;
  white-space: nowrap;
  color: var(--white);
  text-shadow: 0 0 4px #99E4FF;            /* ⚠️ non-token: 시안 번짐(content-title lightblue 장식색과 같다) */
}
/* 불릿 — 시안 자리는 7.5 × 15 인데 그림(번짐 포함)은 사방 4 씩 넘친다(기숙사 불릿과 같은 사정). */
.pat__bullet { position: relative; display: block; width: 7.5px; height: 15px; flex-shrink: 0; }
.pat__bullet img { position: absolute; top: -4px; left: -4px; width: 15.5px; height: 23px; }
.pat__trait-desc {
  width: 100%;
  margin: 0;
  opacity: 0.7;
  /* accent/body2/R-16 */
  font-family: var(--font-accent);
  font-weight: 400;
  font-size: 16px;
  line-height: 1.5;
  letter-spacing: -0.01em;
  text-align: center;
  color: var(--gray-200);
}
.pat__trait-desc b { font-weight: 600; color: var(--white); }   /* 시안 Hahmlet SemiBold 흰색 */
/* 공식 설명 문안(2026-10-09)은 길어서 글자 단위로 끊으면 낱말 · 이름이 줄 끝에서 갈린다("그레/인저") — 띄어쓰기에서만 끊는다. */
.pat__trait-desc { word-break: keep-all; }
.pat__actions {
  position: absolute;
  z-index: 1;
  bottom: calc(12px + var(--ui-gap));   /* 화면 바닥에서 12 — 결과 화면 공통(.pres__actions 참고, 전: 위에서 595) */
  left: calc(50% - 167px);
}

/* ── 등장 연출 — 물약 결과와 같은 물결이다(뜨는 시간 1.1, 사이 간격 0.2) ──
   ⚠️ 머리말 줄이 좌우로 펼쳐지는 몫은 .content-title 이 들고 있다 — 뿌리의 is-in 이 방아쇠다. */
[data-pat1-step], [data-pat-step] { opacity: 0; transform: translateY(16px); }
.pat1.is-in [data-pat1-step],
.pat.is-in [data-pat-step] {
  opacity: 1;
  transform: none;
  transition: opacity 1.1s cubic-bezier(0.33, 1, 0.68, 1), transform 1.1s cubic-bezier(0.16, 1, 0.3, 1);
}
.pat1.is-in [data-pat1-step="1"], .pat.is-in [data-pat-step="1"] { transition-delay: 0.5s; }
.pat1.is-in [data-pat1-step="2"], .pat.is-in [data-pat-step="2"] { transition-delay: 0.7s; }
.pat.is-in [data-pat-step="3"] { transition-delay: 0.9s; }
.pat.is-in [data-pat-step="4"] { transition-delay: 1.1s; }
.pat1.is-in [data-pat1-step="3"] { transition-delay: 1.5s; }   /* tap 안내는 한 박자 떼어 둔다 */
.pat1.is-in .pat1__tap { animation: hres-blink 2.4s ease-in-out 2.6s infinite; }

@media (prefers-reduced-motion: reduce) {
  [data-pat1-step], [data-pat-step] { opacity: 1; transform: none; }
  .pat1.is-in [data-pat1-step],
  .pat.is-in [data-pat-step] { transition: none; }
  .pat1.is-in .pat1__tap { animation: none; }
}

/* ══════════════ 움직이는 초상화 — 결과 (2026-10-13 개편 · 2026-10-26 유리 닦기) ══════════════
   Figma result_digital/completed1 5085-19644(닦는 중) · completed2 6379-32692(영상 · 아래 묶음).
   벽 앞 액자 하나. 초상화를 덮은 유리가 붓 한 획을 따라 닦이고(is-wiping, app.js portraitWipe) 남은 유리가 걷히며
   영상이 돈다(is-revealed). 좌표는 시안 그대로 — app.js 의 무대(dstageHtml) 주석 참고. */
.dreveal {
  --dl-end: 522px;   /* 굴릴 길이 — 액자 아래끝(시안 −22 + 144.83 + 399.29). 다운로드 묶음 .dl-bar 주석 */
  position: relative;
  display: flex;            /* 닫기 · 아래 묶음만 흐름에 둔다(sticky) — 나머지는 다 absolute */
  flex-direction: column;
  width: 375px;
  min-height: max(var(--screen-h), calc(var(--dl-end) + 190px + var(--ui-gap) + var(--dl-band, 0px)));
  overflow: hidden;
  overflow: clip;   /* hidden 은 이 상자를 스크롤 상자로 만들어 안쪽 sticky(닫기 · 아래 묶음)가 듣지 않는다(.wres 와 같은 사정) */
  background: #140A05;   /* 벽 아래 끝 색 — 화면이 무대(앱 696)보다 길면 그 아래를 이 색이 잇는다 */
}

/* 무대 — 시안 Photobooth-QRScan 칸(380×727)을 completed2 자리(x −5 · 앱 y −22 — 액자 창 122.83 · 벽 가운데 341.7)에 놓는다.
   (전: −31 — 머리말이 화살 장식에서 기숙사 사진 같은 제목(65 ~ 103)으로 바뀌며 액자가 9 내려왔다.)
   닦는 동안은 completed1 처럼 6.89 더 내려 있다가(액자 창 129.72) 다 드러나며 올라온다 — 아래 묶음이 들어올 자리를 낸다.
   아래 끝 34px 은 바탕색으로 스며든다 — 시안 화면(658)에서는 보이지 않는 자리라, 더 긴 화면에서만 벽이 칼같이
   끊겨 보이지 않게 하는 몫이다. */
.dstage {
  position: absolute;
  z-index: 0;
  top: -22px;
  left: -5px;
  width: 380px;
  height: 727px;
  pointer-events: none;
  -webkit-mask-image: linear-gradient(180deg, #000 693px, transparent 727px);
  mask-image: linear-gradient(180deg, #000 693px, transparent 727px);
  transform: translateY(6.89px);
  transition: transform 0.9s cubic-bezier(0.33, 0, 0.2, 1);
}
.dreveal.is-revealed .dstage { transform: none; }
.dreveal.is-instant .dstage { transition: none; }
/* 벽 — 시안 Wall_frame 2(407.588×724.602 · 칸 가운데)를 칸으로 잘라 검정 60% 덮개까지 구운 한 장(3배) */
.dstage__wall { position: absolute; inset: 0; display: block; width: 100%; height: 100%; }

/* 캔버스 · 영상 · 유리 칸 — 시안 image 148 (68.05, 160.78) 236.95×351.899. 영상은 캔버스 위, 유리는 영상 위, 액자가 그 위를 두른다. */
.dstage__canvas,
.dstage__photo,
.dstage__glass,
.dstage__sparks {
  position: absolute;
  top: 160.78px;
  left: 68.05px;
  width: 236.95px;
  height: 351.899px;
}
.dstage__canvas img { display: block; width: 100%; height: 100%; object-fit: cover; }
/* 빈 캔버스의 비네트 — 시안 라디얼(가운데 검정 40% → 84% 지점 42.7% → 끝 100%)을 30% 로 얹는다(5085-19644) */
.dstage__canvas::after {
  content: "";
  position: absolute;
  inset: 0;
  opacity: 0.3;
  background: radial-gradient(50% 50% at 50% 50%, rgba(0, 0, 0, 0.4) 0%, rgba(0, 0, 0, 0.4274) 84.345%, #000 100%); /* ⚠️ non-token: 시안 값 */
}
.dstage__photo {
  display: block;
  object-fit: cover;
}
/* 유리(app.js paintPortraitGlass) — 닦이고 남은 것은 다 드러나는 순간 걷힌다. 붓 끝 빛 · 가루는 그 위에 더해 그린다. */
.dstage__glass { display: block; transition: opacity 0.9s ease; }
.dreveal.is-revealed .dstage__glass { opacity: 0; }
.dstage__sparks { display: block; }
/* 닦는 길 — 길이만 재는 보이지 않는 획(app.js dstageHtml 주석) */
.dstage__guide { position: absolute; top: 0; left: 0; width: 200px; height: 298.98px; visibility: hidden; }
/* 본인 영상(<video>)도 사진과 같은 자리 · 같은 등장. 영상 비율이 칸과 달라도 object-fit 이 잘라 맞춘다. */
.dstage__video { background: #000; }

/* 액자 — 시안 _Only_frame 2(343.789×452.391 · 칸 가운데) 안의 그림 303.038×399.293 */
.dstage__frame {
  position: absolute;
  top: 144.83px;
  left: 39.07px;
  display: block;
  width: 303.038px;
  height: 399.293px;
}

/* ── 닫기 · 머리말 — 닦는 동안에도 보인다(시안 5085-19644). 열릴 때 살짝 떠오르기만 한다.
      아래 묶음(dl-bar — 남은 시간 · 영상 다운 · 안내)은 completed2 에만 있다 — 다 드러난 뒤 떠오른다. ── */
.dreveal__header {
  position: absolute;
  z-index: 4;
  top: 10px;   /* 기본 헤더와 같은 자리 (26-09-18 36 → 10). 홈 화면에 추가했을 때 상태바는 뿌리(.dreveal)의 위 띠가 피한다 */
  left: 0;
  display: flex;
  align-items: center;
  box-sizing: border-box;
  width: 375px;
  height: 38px;
  padding: 4px 20px;
}
.dreveal__close {
  display: flex;
  width: 24px;
  height: 24px;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}
.dreveal__close img { display: block; width: 24px; height: 24px; }

/* 닫기 — 굴려도 따라온다(이슈 #305 · 완드 결과 .wres__header 와 같은 방식). 흐름 공간은 먹지 않는다(10 + 38 − 48 = 0).
   ⚠️ 초상화 화면 안에서만 — 퀴디치(.qreveal)는 굴리지 않아 빌려 쓰는 닫기가 absolute 그대로다. */
.dreveal > .dreveal__header,
.hphoto__header {
  position: sticky;
  top: calc(10px + var(--safe-top));   /* 스크롤 상자(시트) 기준이라 상태바를 따로 피한다 */
  flex: none;
  margin: 10px 0 -48px;
}

/* ⚠️ 초상화 화면(.dreveal) 안에서만 숨겨 둔다 — 퀴디치(.qreveal)도 닫기 클래스를 빌려 쓴다. */
.dreveal > .dreveal__header,
.dreveal > .dl-title { opacity: 0; transition: opacity 0.5s ease 0.1s; }
.dreveal.is-in > .dreveal__header,
.dreveal.is-in > .dl-title { opacity: 1; }
.dreveal > .dl-bar { opacity: 0; pointer-events: none; transition: opacity 0.6s ease 0.35s; }
.dreveal.is-revealed > .dl-bar { opacity: 1; pointer-events: auto; }
.dreveal.is-instant > .dl-bar { transition-delay: 0s; }

@media (prefers-reduced-motion: reduce) {
  .dstage,
  .dstage__glass,
  .dreveal__header,
  .dreveal > .dl-title,
  .dreveal > .dl-bar { transition-duration: 0.01ms; transition-delay: 0s; }
}

/* ══════════════ 퀴디치 — 결과 · 오늘의 순위 (2026-10-26 개편) ══════════════
   Figma result_quidditch/sorting 6088:31013. 좌표는 시안 y − 62. 열리는 흐름(초)은 app.js wireQuidditchReveal 주석과 같다.
   닫기는 초상화의 .dreveal__header 를 빌려 쓴다(같은 자리 · 같은 모양).
   (전: 4357-14118 — 트로피 · 시안 렌더 배경 한 장. 트로피가 빠지고 순위표가 들어왔다.) */
.qreveal {
  position: relative;
  width: 375px;
  min-height: var(--screen-h);
  overflow: hidden;
  background: var(--neutral-950);   /* 시안 판 바탕 */
}

/* 배경 — 시안 층 그대로 겹친다. 덮개는 앱 682 · 사진은 709 · 결은 716 에서 끝나 그보다 긴 화면(홈 화면 앱)에서는
   덮개 아래 끝 색으로 잇는다(.qbg::after — 덮개를 늘리면 그라디언트가 늘어나 시안 높이 안의 색이 바뀐다). */
.qbg { position: absolute; z-index: 0; inset: 0; pointer-events: none; }
.qbg > * { position: absolute; display: block; max-width: none; }
.qbg__photo { top: -79px; left: -102px; width: 578px; height: 788px; }
.qbg__photo img { display: block; width: 100%; height: 100%; object-fit: cover; opacity: 0.8; }
.qbg__photo::after { content: ""; position: absolute; inset: 0; background: rgba(0, 0, 0, 0.6); }
.qbg__tint {
  top: -96px;
  left: -120px;
  width: 612px;
  height: 778px;
  opacity: 0.9;
  /* ⚠️ non-token: 시안 보라 덮개(Rectangle 4) */
  background: linear-gradient(180deg, rgba(38, 26, 75, 0.9) 0%, rgba(0, 0, 0, 0.9) 22.439%,
    rgba(0, 0, 0, 0.9) 77.878%, rgba(75, 51, 149, 0.9) 115.62%);
}
.qbg__texture { top: -62px; left: -118px; width: 612px; height: 778px; object-fit: cover; opacity: 0.2; }
/* 사자 문장 — 시안 535.5 × 595 칸(20%) 가운데에 384.37 × 577.15(20% · luminosity). 두 겹을 곱한 4% 는 시안보다 훨씬
   옅어서(미리보기 비교) 20% 한 겹으로 둔다 — 그래야 시안처럼 사자 윤곽이 보인다 */
.qbg__crest {
  top: 64.925px;
  left: -4.435px;
  width: 384.37px;
  height: 577.15px;
  object-fit: contain;
  object-position: bottom;
  opacity: 0.2;
  mix-blend-mode: luminosity;
}
/* GAMEOVER — Monoplex KR Bold Italic 120 의 윤곽을 그림으로(색 #CB81FF 60% 는 그림 안) · overlay. 처음에 천천히 떠오른다 */
.qbg__gameover {
  top: 204px;
  left: -74px;
  width: 524px;
  height: 141px;
  mix-blend-mode: overlay;
  opacity: 0;
  transition: opacity 1.6s ease 0.2s;
}
.qreveal.is-in .qbg__gameover { opacity: 1; }
.qbg::after { content: ""; position: absolute; top: 682px; right: 0; bottom: 0; left: 0; background: rgba(44, 30, 87, 0.81); }  /* ⚠️ non-token: 덮개 아래 끝(100%) 색 × 90% */

/* 머리말 — 시안 title(127 · 190 폭). 글 27 아래로 받침 장식(190×21)이 10 겹친다. 받침은 가운데서 양옆으로 펼쳐진다 */
.qreveal__title {
  position: absolute;
  z-index: 4;
  top: 65px;
  left: 50%;
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 190px;
  transform: translateX(-50%);
  opacity: 0;
  transition: opacity 0.5s ease 0.05s;
}
.qreveal.is-in .qreveal__title { opacity: 1; }
.qreveal__title p {
  position: relative;
  margin: 0 0 -10px;
  font-family: var(--font-accent);
  font-weight: 400;
  font-size: 18px;
  line-height: 1.5;
  letter-spacing: -0.18px;
  white-space: nowrap;
  color: #FDFCFE;                          /* ⚠️ non-token: 시안 값 */
  text-shadow: 0 0 4px #DAB8A3;            /* ⚠️ non-token: 시안 글 번짐(Drop shadow 4) */
}
.qreveal__title-flourish {
  position: relative;
  display: block;
  width: 190px;
  height: 21px;
  clip-path: inset(0 50% 0 50%);
  transition: clip-path 0.7s cubic-bezier(0.22, 1, 0.36, 1) 0.15s;
}
.qreveal.is-in .qreveal__title-flourish { clip-path: inset(0 0 0 0); }

/* 내 기록 — 시안 Frame 2147227296(232 · 274 폭). 등수 한 줄 → 4 → 닉네임 점수 칸. 등수 위로 옅은 문장 장식(91 × 63, 등수 윗변 −38) */
.qreveal__me {
  position: absolute;
  z-index: 2;
  top: 170px;
  left: 50%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  width: 274px;
  transform: translateX(-50%);
}
.qreveal__ornament {
  position: absolute;
  top: -38px;
  left: 91.5px;
  display: block;
  width: 91px;
  height: 63.1846px;
  opacity: 0;
  transition: opacity 0.6s ease 0.35s;
}
.qreveal.is-in .qreveal__ornament { opacity: 1; }
.qreveal__place {
  position: relative;
  width: 100%;
  margin: 0;
  font-family: var(--font-base);
  font-weight: 400;
  font-size: 14px;
  line-height: 1.5;
  letter-spacing: 0.14px;
  text-align: center;
  color: var(--white);
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.5s ease 0.35s, transform 0.5s cubic-bezier(0.22, 1, 0.36, 1) 0.35s;
}
.qreveal.is-in .qreveal__place { opacity: 1; transform: none; }

/* 닉네임 점수 — 274 × 64 칸 · 위아래 4 · 좌우 20 · 사이 12. 뒷면은 보랏빛 라디얼(시안 면 40%) */
.qreveal__score {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  box-sizing: border-box;
  width: 274px;
  height: 64px;
  padding: 4px 20px;
  opacity: 0;
  transform: translateY(10px);
  transition: opacity 0.55s ease 0.55s, transform 0.55s cubic-bezier(0.22, 1, 0.36, 1) 0.55s;
}
.qreveal__score::before {
  content: "";
  position: absolute;
  inset: 0;
  opacity: 0.4;
  /* ⚠️ non-token: Figma 점수 줄 뒷면(타원 136.37 × 53.4) */
  background: radial-gradient(136.37px 53.4px at 50% 50%,
    #8771C4 0%, #6A599C 25%, #4D4174 50%, #30284D 75%, #211C39 87.5%, #131025 100%);
}
.qreveal.is-in .qreveal__score { opacity: 1; transform: none; }
.qreveal__name,
.qreveal__points {
  position: relative;
  line-height: normal;
  white-space: nowrap;
}
/* 닉네임 — EASTARJET Heavy 36 */
.qreveal__name {
  font-family: var(--font-score);
  font-weight: 800;
  font-size: 36px;
  letter-spacing: 0.6984px;
  color: var(--white);
}
/* 점수 — Monoplex KR Bold 48(숫자만 자른 HP Quidditch Score) · 금빛 → 은빛 그라디언트(⚠️ non-token: 시안 값).
   0 에서 올라가는 동안 폭은 마지막 값으로 잡아 두고(app.js) 오른쪽에 붙인다. 멈추면 한 번 부풀며 빛난다(.is-landed) */
.qreveal__points {
  font-family: var(--font-score-digits);
  font-weight: 700;
  font-size: 48px;
  letter-spacing: 0.9312px;
  text-align: right;
  background: url('assets/shared/grad/text-quidditch-points.svg') 0 0 / 100% 100% no-repeat;   /* 시안 180deg #FFF292 → #DADAD6 · 단색 + 투명도로 다시 쓴 그림(assets/shared/grad) — CSS 그라디언트는 삼성 인터넷 강제 다크 모드에서 어두워진다(tokens.css --paint-*) */
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.qreveal__points.is-landed { animation: qreveal-land 0.6s cubic-bezier(0.22, 1, 0.36, 1); }
@keyframes qreveal-land {
  0%   { transform: scale(1);    filter: drop-shadow(0 0 0 rgba(255, 242, 146, 0)); }
  35%  { transform: scale(1.08); filter: drop-shadow(0 0 12px rgba(255, 242, 146, 0.55)); }
  100% { transform: scale(1);    filter: drop-shadow(0 0 0 rgba(255, 242, 146, 0)); }
}

/* ── 오늘의 순위표 — 시안 Frame 2147227875(365 · 350 폭). Today's ranking 줄 → 20 → 표.
   --qb(초)는 app.js 가 정한다 — 열고 1.9초, 순위가 늦게 오면 받은 때. 양옆 줄은 안쪽 끝에서 바깥으로 뻗고, 표 줄은 차례로 오른다 */
.qrank {
  position: absolute;
  z-index: 2;
  top: 303px;
  left: 12.5px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 20px;
  width: 350px;
}
.qrank[hidden] { display: none; }
.qrank__line { display: flex; align-items: center; gap: 9.575px; height: 19px; }
.qrank__line-deco {
  display: block;
  width: 52px;
  height: 7px;
  transform-origin: right center;
  transform: scaleX(0);
  transition: transform 0.55s cubic-bezier(0.22, 1, 0.36, 1) var(--qb, 0s);
}
/* 시안은 오른쪽 줄을 좌우로 뒤집어 둔다 — 뒤집기는 바깥 칸이 맡고, 그림은 왼쪽 줄과 똑같이 안쪽 끝(그림의 오른쪽)에서 뻗는다 */
.qrank__line-flip { display: block; transform: scaleX(-1); }
.qrank.is-ready .qrank__line-deco { transform: scaleX(1); }
.qrank__line-text {
  margin: 0;
  font-family: var(--font-base);
  font-weight: 500;
  font-size: 12.767px;
  line-height: 1.5;
  letter-spacing: 0.0638px;
  white-space: nowrap;
  /* ⚠️ non-token: 시안 금빛 글 · 번짐(text-shadow 대신 filter — 글자 속이 그라디언트라 text-shadow 는 글 위를 덮는다) */
  background: url('assets/shared/grad/text-rank-line.svg') 0 0 / 100% 100% no-repeat;   /* 시안 90deg #E6CB99 → #FDFCCE → #E6CB99 · 강제 다크 대비 그림 */
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  filter: drop-shadow(0 0 8px rgba(230, 203, 153, 0.8));
  opacity: 0;
  transition: opacity 0.5s ease calc(var(--qb, 0s) + 0.1s);
}
.qrank.is-ready .qrank__line-text { opacity: 1; }

.qrank__table { display: flex; flex-direction: column; width: 350px; }
/* 줄 바탕은 시안 채움 그림(350 폭) 그대로 — 머리 · 1등 · 내 줄 셋 */
.qrank__row,
.qrank__gap {
  position: relative;
  display: flex;
  align-items: center;
  box-sizing: border-box;
  width: 350px;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.4s ease calc(var(--qb, 0s) + 0.15s + var(--i, 0) * 0.07s),
    transform 0.4s cubic-bezier(0.22, 1, 0.36, 1) calc(var(--qb, 0s) + 0.15s + var(--i, 0) * 0.07s);
}
.qrank.is-ready .qrank__row,
.qrank.is-ready .qrank__gap { opacity: 1; transform: none; }
.qrank__row {
  height: 34px;
  padding: 0 12px;
  overflow: hidden;
  font-family: var(--font-base);
  font-weight: 500;
  font-size: 12px;
  line-height: 1.5;
  letter-spacing: 0.06px;
  color: var(--white);
  background: 0 0 / 100% 100% no-repeat;
}
.qrank__row--head { height: 30.069px; padding: 0 12.069px; background-image: url('assets/quidditch/rank-row-head.webp'); }
/* 1등 · 내 줄의 왼쪽 선(1.81)은 시안 안쪽 선이라 글자 자리를 밀지 않게 inset 그림자로 긋는다 */
/* 1등 노란 선은 그림 한 겹으로 — 밝은 inset 그림자는 삼성 인터넷 강제 다크 모드에서 어두워진다(tokens.css --paint-*) */
.qrank__row.is-first {
  height: 35.914px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Crect width='100%25' height='100%25' fill='%23FFE476'/%3E%3C/svg%3E"), url('assets/quidditch/rank-row-first.webp');
  background-size: 1.81px 100%, 100% 100%;
}
.qrank__row.is-me { background-image: url('assets/quidditch/rank-row-me.webp'); box-shadow: inset 1.81px 0 0 #7E50FF; }
.qrank__gap { justify-content: center; height: 27.069px; }

.qrank__no { flex: none; width: 22.931px; text-align: center; }
.qrank__row--head .qrank__no { width: auto; text-align: left; }   /* 머리 줄 "rank" 는 제 폭(시안 그대로 이름 칸이 3 오른쪽) */
.qrank__house,
.qrank__nick { flex: none; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.qrank__house { width: 72.414px; margin-left: 36.207px; }
.qrank__nick { width: 120.69px; margin-left: 12.069px; }
.qrank__score { flex: none; width: 48.276px; margin-left: auto; text-align: center; white-space: nowrap; }
/* 점수 · "..." — 흰 → 연분홍 → 흰 그라디언트(⚠️ non-token: 시안 값). 머리 줄 "score" 는 흰 글 */
.qrank__row:not(.qrank__row--head) .qrank__score,
.qrank__gap span {
  background: url('assets/shared/grad/text-rank-score.svg') 0 0 / 100% 100% no-repeat;   /* 시안 90deg #FFFFFF → #F7DBFD → #FFFFFF · 강제 다크 대비 그림 */
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.qrank__gap span {
  width: 48.276px;
  font-family: var(--font-base);
  font-weight: 500;
  font-size: 10px;
  line-height: 1.5;
  letter-spacing: 0.05px;
  text-align: center;
}
/* 1등 배지 — 별(19.91, 그림자 칸 −13.39%) 위에 "1"(base/body4/M-10 · #333) */
.qrank__badge { position: relative; display: block; width: 22.931px; height: 19.914px; }
.qrank__badge img { position: absolute; top: -2.666px; left: -1.456px; display: block; width: 25.2456px; height: 25.2456px; max-width: none; }
.qrank__badge b {
  position: absolute;
  top: 3.017px;
  left: 0;
  width: 22.931px;
  font-weight: 500;
  font-size: 10px;
  line-height: 1.5;
  letter-spacing: 0.05px;
  text-align: center;
  color: #333333;   /* ⚠️ non-token: 시안 값 */
  background: linear-gradient(#333333, #333333);   /* 같은 색을 그라디언트로 클립 — 밝은 별 위 어두운 단색 글자는 강제 다크에서 밝게 뒤집힌다 */
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}
/* 내 줄 — 다 올라온 뒤 빛이 왼쪽 → 오른쪽으로 한 번 지나가고 왼쪽 선이 잠깐 밝아진다(app.js 가 .is-swept · 효과음) */
.qrank__row.is-me::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: url('assets/shared/grad/rank-me-sweep.svg') 0 0 / 100% 100% no-repeat;   /* 시안 100deg 연보라 35% 띠 · 강제 다크 대비 그림 */
  transform: translateX(-100%);
}
.qrank__row.is-me.is-swept::after { animation: qrank-sweep 0.9s cubic-bezier(0.4, 0, 0.2, 1) both; }
.qrank__row.is-me.is-swept { animation: qrank-me-glow 1.2s ease both; }
@keyframes qrank-sweep { to { transform: translateX(100%); } }
@keyframes qrank-me-glow {
  0%, 100% { box-shadow: inset 1.81px 0 0 #7E50FF; }
  40%      { box-shadow: inset 1.81px 0 0 #B79BFF, 0 0 18px rgba(126, 80, 255, 0.45); }   /* ⚠️ non-token */
}

.qreveal .dreveal__header { z-index: 4; }

/* [확인] — 디자인시스템 기본(primary) .btn-cta. 자리만 잡는다(다른 결과 화면의 저장 줄과 같은 바닥 여백) */
.qreveal__actions {
  position: absolute;
  z-index: 4;
  bottom: calc(12px + var(--ui-gap));
  left: 50%;
  width: 335px;
  transform: translateX(-50%);
  opacity: 0;
  transition: opacity 0.5s ease 2.6s;
}
.qreveal.is-in .qreveal__actions { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .qbg__gameover,
  .qreveal__title,
  .qreveal__title-flourish,
  .qreveal__ornament,
  .qreveal__place,
  .qreveal__score,
  .qrank__line-deco,
  .qrank__line-text,
  .qrank__row,
  .qrank__gap,
  .qreveal__actions { transition-duration: 0.01ms; transition-delay: 0s; }
  .qreveal__points.is-landed,
  .qrank__row.is-me.is-swept,
  .qrank__row.is-me.is-swept::after { animation: none; }
}

/* ══════════ 다운로드 묶음 — 제목(dl-title) · 아래 묶음(dl-bar) (2026-10-26 기숙사 사진에서 떼어 냄) ══════════
   키오스크 결과를 내려받는 화면 둘이 같이 쓴다 — 기숙사 사진(Figma download_Kiosk 6379-29479) · 움직이는 초상화
   (result_digital/completed2 6379-32692). 시안 둘 다 제목 65 · 남은 시간 492 · 저장 줄 564 · 안내 631 ~ 652 로 같다.
   남은 시간 넘김 시계는 app.js dlDigit · dlDigitMid · startDlClock, 마크업은 dlBarHtml.
   제목 장식선은 assets/shared/dl-title-flourish.svg(시안 Union 190 × 21) — 전에는 quidditch/rank-flourish.svg 를 빌려 썼는데
   퀴디치 순위 개편(#285)에서 그 그림이 지워져 이 묶음의 것으로 옮겼다. */
.dl-title {
  position: absolute;
  z-index: 2;
  top: 65px;
  left: 50%;
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 190px;
  transform: translateX(-50%);
}
.dl-title p {
  position: relative;
  margin: 0 0 -10px;
  font-family: var(--font-accent);
  font-weight: 600;
  font-size: 18px;
  line-height: 1.5;
  letter-spacing: -0.18px;
  white-space: nowrap;
  color: #FEFDFC;                          /* ⚠️ non-token: 시안 값 */
  text-shadow: 0 0 4px #DAB8A3;            /* ⚠️ non-token: 시안 글 번짐(Drop shadow 4) */
}
.dl-title img { position: relative; display: block; width: 190px; height: 21px; }
/* 아래 묶음은 화면 바닥에 붙어 있고(sticky) 위(제목 · 사진)만 굴러간다(이슈 #305, 2026-10-27).
   시안 그대로면 사진 아래끝이 묶음 그라데이션 밑으로 들어가 짧은 화면(아이폰 SE 사파리 548)에서는 인물까지 가려졌다 —
   저장되는 건 사진 전체라 다 볼 수 있어야 한다.
     · 처음 화면은 시안 그대로다. 굴릴 길이는 사진(액자) 아래끝(--dl-end) + 24 가 남은 시간 상자 윗변
       (바닥에서 166 + --ui-gap)에 닿을 때까지 — 뿌리 높이 = --dl-end + 190 + --ui-gap(+ 홈 화면에 추가했을 때 위 띠).
       시안 화면(658)에서 기숙사 사진은 92 · 초상화는 54, 아이폰 SE 사파리(548)에서는 202 · 164 를 굴린다.
     · 그라데이션은 굴린 만큼(--dl-t 0 → 1, app.js wireDlScroll) 투명한 윗부분이 0 → 108 로 늘어난다 — 끝까지 올리면
       사진 아래끝(묶음 위끝 + 108)까지는 하나도 덮지 않는다. 굴릴 길이가 없는 긴 화면은 처음부터 1 이다. */
.dl-bar {
  position: sticky;
  z-index: 3;
  bottom: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  gap: 24px;
  box-sizing: border-box;
  width: 375px;
  height: calc(298px + var(--ui-gap));
  margin-top: auto;   /* 뿌리 바닥으로 */
  padding-bottom: calc(6px + var(--ui-gap));   /* 안내 아래끝 = 바닥 − 6 (시안 714 · 툴바 738 위 24) */
  background: linear-gradient(180deg, rgba(3, 10, 17, 0) calc(var(--dl-t, 0) * 108px), #030A11 128px);   /* ⚠️ non-token: 시안 bottom 그라데이션 */
}
.dl-bar__timer {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 24px;
  width: 335px;
  padding: 4px 0;
  border-radius: 8px;
  background: rgba(19, 25, 31, 0.4);   /* ⚠️ non-token: 시안 값 */
}
/* "잠시 후 다시 시도해 주세요..." — 남은 시간 상자 자리(335 × 48 · 같은 면)에 loading · failed 때만 선다 */
.dl-bar__notice {
  display: none;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  width: 335px;
  height: 48px;
  margin: 0;
  padding: 4px 0;
  border-radius: 8px;
  background: rgba(19, 25, 31, 0.4);   /* ⚠️ non-token: 시안 값 */
  /* base/body3/M-12 */
  font-family: var(--font-base);
  font-weight: 500;
  font-size: 12px;
  line-height: 1.5;
  letter-spacing: 0.06px;
  color: #FFF6E1;   /* ⚠️ non-token: 시안 값 */
}
.dl-bar__timer-label {
  /* base/body3/M-12 */
  font-family: var(--font-base);
  font-weight: 500;
  font-size: 12px;
  line-height: 1.5;
  letter-spacing: 0.06px;
  white-space: nowrap;
  color: #FFF6E1;   /* ⚠️ non-token: 시안 금빛 흰색 */
}
/* --dl-mid — 숫자 글자(잉크) 한가운데의 높이. 가운데 줄과 카드 접는 자리가 여기에 맞춘다.
   글자가 칸 안 어디에 그려지는지는 브라우저마다 다르다(글꼴 위 · 아래 높이를 정수로 반올림하는 단위가 달라
   1배 화면 · 아이폰 Safari 는 16.2, 3배로 그리는 Chrome 은 16.9) — 그래서 app.js dlDigitMid 가 열 때 재서 넣는다.
   16.17 은 재기 전(글꼴을 받는 동안) 값. */
.dl-bar__clock { --dl-mid: 16.17px; display: flex; align-items: center; }
.dl-bar__pair { display: flex; }
/* 숫자 칸 24 × 36 — 넘김 카드: 위 반쪽(0 ~ mid)이 아래 모서리를 축으로 접히고 아래 반쪽(mid ~ 36)이 위 모서리를 축으로
   펼쳐진다(app.js dlDigit). 반쪽 바탕은 남은 시간 상자 색을 겹친 값(#030A11 위 rgba(19,25,31,.4)) —
   넘어가는 반쪽이 밑의 글자를 가려야 해서 투명으로 둘 수 없다. */
.dl-bar__digit { position: relative; display: block; width: 24px; height: 36px; perspective: 140px; }
.dl-bar__half {
  position: absolute;
  left: 0;
  width: 24px;
  overflow: hidden;
  background: #091017;   /* ⚠️ non-token: 남은 시간 상자 바탕을 화면 바탕에 겹친 색 */
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
}
.dl-bar__half--top { top: 0; height: var(--dl-mid); transform-origin: 50% 100%; }
.dl-bar__half--bottom { top: var(--dl-mid); height: calc(36px - var(--dl-mid)); transform-origin: 50% 0; }
.dl-bar__flap { z-index: 2; }
.dl-bar__half > span {
  position: absolute;
  top: 0;
  left: 0;
  display: block;
  width: 24px;
  font-family: var(--font-base);
  font-weight: 700;
  font-size: 24px;
  line-height: 36px;
  letter-spacing: 0.12px;
  text-align: center;
  /* ⚠️ non-token: 시안 금빛 글씨 그라데이션(90deg #FFF6E1 32.148% → #FFE09A 69.969%) — 단색 + 투명도로 다시 쓴 그림(assets/shared/grad) — CSS 그라디언트는 삼성 인터넷 강제 다크 모드에서 어두워진다(tokens.css --paint-*) */
  background: url('assets/shared/grad/text-dl-digit.svg') 0 0 / 100% 100% no-repeat;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.dl-bar__half--bottom > span { top: calc(-1 * var(--dl-mid)); }
/* 가운데 줄(어두운 1px) — 줄 한가운데가 글자 한가운데에 온다.
   전: 16.5 고정(내려받기 페이지 값) → 1배 화면에서 글자보다 0.8 아래로 지나 가운데가 아니게 보였다(디자이너 지적 10-23). */
.dl-bar__digit-line {
  position: absolute;
  z-index: 3;
  top: calc(var(--dl-mid) - 0.5px);
  left: 0;
  display: block;
  width: 24px;
  height: 1px;
}
.dl-bar__colon {
  box-sizing: border-box;
  width: 30px;
  padding: 8px;
  font-family: var(--font-base);
  font-weight: 500;
  font-size: 16px;
  line-height: 1.5;
  letter-spacing: 0.08px;
  text-align: center;
  background: url('assets/shared/grad/text-dl-colon.svg') 0 0 / 100% 100% no-repeat;   /* ⚠️ non-token: 시안 90deg #FFF6E1 → #FFD372 · 강제 다크 대비 그림 */
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.dl-bar__actions { display: flex; flex-direction: column; align-items: center; gap: 12px; transition: opacity 0.3s ease; }
.dl-bar__info {
  display: flex;
  align-items: center;
  gap: 4px;
  margin: 0;
  /* base/body2/L-14 */
  font-family: var(--font-base);
  font-weight: 300;
  font-size: 14px;
  line-height: 1.5;
  letter-spacing: 0.01em;
  white-space: nowrap;
  color: #5C646A;   /* ⚠️ non-token: 시안 값 */
  background: linear-gradient(#5C646A, #5C646A);   /* 같은 색을 그라디언트로 클립 — 어두운 단색 글자는 강제 다크에서 밝게 뒤집힌다 */
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}
.dl-bar__info img { display: block; width: 16px; height: 16px; }

/* ══════════ 기숙사 사진 — 배정식 키오스크 액자 사진 (Figma download_Kiosk 6379-29479 · 37781 · 45864 · 52410, 2026-10-23) ══════════
   네 기숙사 시안은 배치가 같고 사진(키오스크가 만든 액자 그림)만 다르다 — 사진은 창구가 준다(app.js wireHousePhoto).
   앱 좌표 = 시안 − 62: 닫기 10 · 제목 65 · 장식선 164 · 사진 128 ~ 560(243 × 432).
   아래 묶음(남은 시간 · 저장 줄 · 안내)은 **화면 바닥에 붙인다** — 시안 658 에서 남은 시간 492 · 저장 줄 564 · 안내 631 ~ 652.
   묶음 뒤 그라데이션(투명 → #030A11, 128 에서 다 짙어진다)이 사진 아래 끝을 덮는다(시안 그대로) — 올리면 사진 전체가
   보인다(이슈 #305 — 다운로드 묶음 .dl-bar 주석).
   남은 시간 · 안내 · 장식선은 내려받기 페이지(download/)와 같은 모양 · 같은 그림이다. */
.hphoto {
  --dl-end: 560px;   /* 굴릴 길이 — 사진 아래끝. 다운로드 묶음 .dl-bar 주석 */
  position: relative;
  display: flex;            /* 닫기 · 아래 묶음만 흐름에 둔다(sticky) — 나머지는 다 absolute */
  flex-direction: column;
  width: 375px;
  min-height: var(--screen-h);
  overflow: hidden;
  overflow: clip;   /* hidden 은 이 상자를 스크롤 상자로 만들어 안쪽 sticky(닫기 · 아래 묶음)가 듣지 않는다(.wres 와 같은 사정) */
  background: #030A11;   /* ⚠️ non-token: 시안 바탕(아래 묶음 그라데이션 끝색과 같다) */
}
/* 사진이 섰을 때만 굴린다 — 못 보여 줄 때(네모 상자)는 시안대로 한 화면이다 */
.hphoto[data-state="ready"] { min-height: max(var(--screen-h), calc(var(--dl-end) + 190px + var(--ui-gap) + var(--dl-band, 0px))); }
.hphoto:not([data-state="ready"]) .dl-bar { --dl-t: 0; }
/* 장식선 — 시안 line(Layer 1 629 × 315, x −183 · 시안 y 226) */
.hphoto__line {
  position: absolute;
  z-index: 0;
  top: 164px;
  left: -183px;
  width: 629px;
  height: 315px;
  pointer-events: none;
}
.hphoto__line img,
.hphoto__line svg { display: block; width: 629px; height: 315px; max-width: none; }
/* 그리는 동안 — 반짝이(리본이 아닌 조각)는 꺼 두었다가 리본이 지나가면 톡 켜진다(내려받기 페이지 spark-pop) */
.hphoto__line.is-drawing .spark {
  opacity: 0;
  transform-box: fill-box;
  transform-origin: center;
}
.hphoto__line.is-drawing .spark.is-on { animation: hphoto-spark-pop 900ms ease-out forwards; }
@keyframes hphoto-spark-pop {
  0%   { opacity: 0; transform: scale(0.6); fill-opacity: 0.1; }
  40%  { opacity: 1; transform: scale(1.15); fill-opacity: 0.3; }
  100% { opacity: 1; transform: scale(1); fill-opacity: 0.1; }
}
.hphoto__pen { mix-blend-mode: screen; pointer-events: none; }
.hphoto__header {
  z-index: 4;   /* 자리 · 굴려도 따라오는 건 .dreveal__header 와 같이 둔다(초상화 화면 닫기 규칙) */
  display: flex;
  align-items: center;
  box-sizing: border-box;
  width: 375px;
  height: 38px;
  padding: 4px 20px;
}
.hphoto__close {
  display: flex;
  width: 24px;
  height: 24px;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}
.hphoto__close img { display: block; width: 24px; height: 24px; }
/* 머리말 — "기숙사 사진" + 금빛 장식 190 × 21(퀴디치 등수 장식과 같은 그림). 시안 Hahmlet Bold 18 은 글꼴에 Bold 가 없어
   SemiBold 로 그린다(가짜 굵기를 피한다). */
/* 사진 — 키오스크 액자 사진(9:16). 받는 동안은 자리만, 없으면 은은한 빈 칸 */
.hphoto__photo {
  position: absolute;
  z-index: 1;
  top: 128px;
  left: 66px;
  width: 243px;
  height: 432px;
}
.hphoto__photo img { display: block; width: 100%; height: 100%; object-fit: cover; }

/* ── 사진을 못 보여 줄 때(app.js wireHousePhoto setState) — Figma 6379-63754 loading · 60486 failed · 65378 expired ──
   사진 자리에 241 네모 상자(시안 y 239 → 화면 177). 면은 #181818 80% 를 screen 으로 섞어 뒤 장식선이 비쳐 보인다 —
   면(.hphoto__status-face)과 테두리 · 글자(.hphoto__status)를 따로 두는 까닭은 app.js 마크업 주석.
   상자는 버튼 묶음 그라데이션 위에 둔다(시안 셋 중 둘이 그 순서 — 아래끝이 흐려지지 않는다). */
.hphoto__status-face,
.hphoto__status {
  position: absolute;
  z-index: 4;
  top: 177px;
  left: 67px;
  box-sizing: border-box;
  width: 241px;
  height: 241px;
  border-radius: 20px;
}
.hphoto__status-face {
  background: rgba(24, 24, 24, 0.8);   /* ⚠️ non-token: 시안 면 */
  mix-blend-mode: screen;
}
.hphoto__status {
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid transparent;   /* ⚠️ non-token: 시안 테두리 #2E2E2E — 아래 「고리 테두리」 */
  --ring: linear-gradient(#2E2E2E, #2E2E2E);
}
.hphoto__status-msg {
  display: none;
  flex-direction: column;
  align-items: center;
  gap: 24px;   /* 도는 표시 24 + 24 + 글자 (시안 loading) */
  margin: 0;
  /* base/body2/R-14 */
  font-family: var(--font-base);
  font-size: 14px;
  font-weight: 400;
  line-height: 1.5;
  letter-spacing: 0.14px;
  text-align: center;
  white-space: nowrap;
  color: #6E6E6E;   /* ⚠️ non-token: 시안 흐린 글씨 */
}
.hphoto__status-msg--strong { color: #EAEAEA; }   /* ⚠️ non-token: 만료 안내는 밝은 글씨(시안) */
.hphoto[data-state="loading"] .hphoto__status-msg[data-for="loading"],
.hphoto[data-state="failed"] .hphoto__status-msg[data-for="failed"],
.hphoto[data-state="expired"] .hphoto__status-msg[data-for="expired"] { display: flex; }
.hphoto__spinner {
  display: block;
  width: 24px;
  height: 24px;
  animation: hphoto-spin 1s linear infinite;
}
@keyframes hphoto-spin { to { transform: rotate(360deg); } }
.hphoto[data-state="ready"] :is(.hphoto__status-face, .hphoto__status) { display: none; }
.hphoto:not([data-state="ready"]) .hphoto__photo { display: none; }
/* 불러오는 중 상자 · 안내는 0.25초 뒤에 떠오른다 — 금방 받아지면 상자가 깜빡 보였다 사라지지 않게 */
.hphoto[data-state="loading"] :is(.hphoto__status-face, .hphoto__status, .dl-bar__notice) {
  animation: hphoto-status-in 200ms ease 250ms backwards;
}
@keyframes hphoto-status-in { from { opacity: 0; } }
/* 아래 묶음(app.css 다운로드 묶음) — 사진이 없으면 남은 시간 대신 안내 상자, 버튼 묶음은 흐리게 */
.hphoto:is([data-state="loading"], [data-state="failed"]) .dl-bar__notice { display: flex; }
.hphoto:not([data-state="ready"]) .dl-bar__timer { display: none; }
/* 사진이 없으면 묶음(버튼 · 안내) 통째로 34%(시안 bottom opacity 0.34) — 버튼은 aria-disabled 로 둔다.
   disabled 속성을 쓰면 디자인시스템 disabled 모양(40% · 회색 글로우)이 겹쳐 시안보다 더 흐려진다. */
.hphoto:not([data-state="ready"]) .dl-bar__actions { opacity: 0.34; pointer-events: none; }

/* ══════════════ 온보딩 폼 — 회원가입 · 정보 입력 (2026-09-03 신규) ══════════════
   Figma email_3 4357-13575(회원가입 코드 단계, 2026-10-03) · nickname_1~5(정보 입력 — 닉네임 한 줄).
   두 화면 모두 "라벨 + 필드"를 한 줄로 묶어 세로로 쌓고, 입력을 마친 줄은 지우지 않고
   불투명도 20%로 잠근 채 남겨 둔다 — 무엇을 입력했는지 보이게 하려는 의도다. */
.screen__body--form { gap: 32px; }   /* 타이틀 블록 ↔ 폼 (Figma gap-32) */

.form-stack {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  width: 335px;
}
.form-stack--16 { gap: 16px; }   /* 회원가입 · 정보 입력 (email_3 은 24 → 16, 2026-10-03) */

.form-row {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
  width: 100%;
  transition: opacity 0.25s ease;
}
/* 입력을 마쳐 잠긴 줄 */
/* 지나온 줄은 흐려지지만 **눌리기는 한다** — 코드를 치다가도 이메일을 눌러 그 자리에서
   고칠 수 있어야 한다(app.js makeStepForm의 reopen). pointer-events를 막으면 그 탭이
   아예 오지 않으므로 여기서 막지 않는다.
   불투명도는 Figma email_3 의 이메일 줄(4357-13589 opacity-20)이다 — 전에는 30%. */
.form-row.is-locked { opacity: 0.2; }
.form-row.is-locked .input-field__control { cursor: pointer; }
/* 갓 나타난 줄은 아래에서 살짝 올라온다.
   ⚠️ :not(.is-locked)가 꼭 필요하다 — 이 애니메이션은 fill-mode가 both라 마지막 키프레임
      (opacity:1)을 계속 붙잡고 있고, 애니메이션 값은 캐스케이드에서 위 .is-locked의
      opacity를 이겨 버린다. 잠긴 줄은 아예 애니메이션 대상에서 뺀다. */
/* 갓 열린 줄은 아래에서 살짝 올라온다.
   ⚠️ 키프레임에서 opacity를 건드리지 않는다 — 정지 상태 값을 애니메이션에 맡기면,
      탭이 백그라운드로 내려가 타임라인이 얼었을 때(키오스크·태블릿에서 실제로 생긴다)
      줄이 opacity:0에 붙잡힌 채 안 보이게 된다. 애니메이션이 통째로 건너뛰어도
      불투명도는 항상 위 .form-row / .is-locked 규칙이 정한 값으로 남아야 한다.
      움직임만 애니메이션으로 준다. */
.form-row[data-row]:not([hidden]):not(.is-locked) { animation: form-row-in 0.32s ease; }
@keyframes form-row-in {
  from { transform: translateY(8px); }
  to   { transform: none; }
}

/* 라벨 — base/body2/M-14 */
.form-row__label {
  margin: 0;
  font-family: var(--font-base);
  font-weight: 500;
  font-size: 14px;
  line-height: 1.5;
  letter-spacing: 0.005em;
  color: var(--white);
}

/* 폼 안의 필드는 시안대로 높이 52px 고정 + 흰 테두리 발광이다.
   (DS의 .input-field--pill은 온보딩 밖에서도 쓰이므로 여기서만 덮어쓴다) */
.form-row .input-field--pill { width: 335px; --ring: var(--paint-white); --ring-w: 0.861px; }
.form-row .input-field--pill .input-field__control {
  box-sizing: border-box;
  height: 52px;
  border: 0.861px solid transparent;           /* ⚠️ non-token: Figma textfield 보더 두께 — 흰 색은 틀의 고리(components.css 「고리 테두리」) */
  box-shadow: 0 0 4px 0 rgba(222, 233, 255, 0.6);   /* ice_50 발광(전: 보랏빛 rgba(230,216,255)) */
}
/* 값이 들어간 칸은 Bold + ice_50 (base/body1/B-16) + 옅은 하늘색 발광 (Figma email_3 textfield 3907-33710 — 시안은 blue_50) */
.form-row .input-field--pill.is-filled .input-field__control {
  font-weight: 700;
  color: var(--ice-50);
  text-shadow: 0 0 2px rgba(153, 228, 255, 0.4);   /* ⚠️ non-token: Figma textfield 값 글자 발광 */
}
/* 빈 칸 안내 문구 — Figma email_3 의 textfield 컴포넌트(3907-33710) 플레이스홀더.
   DS 기본(흰색 44%)보다 훨씬 어둡게 가라앉는다. 같은 컴포넌트라 닉네임 칸도 같이 따른다. */
.form-row .input-field--pill .input-field__control::placeholder {
  color: rgba(72, 70, 100, 0.6);                   /* ⚠️ non-token: Figma textfield placeholder */
}

/* ══════════════ 언어 선택 (Figma 3183-13814 · 3183-13830) ══════════════
   카드 스택에서 "화살표 + 필 버튼" 한 줄짜리로 바뀌었다. 고른 줄에만 화살표가 붙고
   고르지 않은 줄은 불투명도 30%로 잠긴다 — 단, 아무것도 고르지 않은 상태에서는 둘 다 온전하다. */

/* ⚠️ 2026-09-07 실측 버그 — 필 안쪽 overlay 레이어(.lang-pill::before)가 blue_100 원색
   그대로 불투명하게 찍히고 있었다. 원인은 위쪽 `.screen--onboarding2 .screen__body`의
   z-index:1이다. 이게 별도 합성 그룹(stacking context)을 만들어서 mix-blend-mode가
   화면 배경까지 닿지 못하고 투명한 바닥과 섞였고, 투명한 바닥과의 blend는 소스색을
   그대로 통과시킨다. 언어 화면에서만 z-index를 떼면 blend 그룹이 .app까지 올라가
   라디얼 배경 위에서 제대로 섞인다 — 배경 이미지(z-index:0)보다 DOM이 뒤라 쌓임 순서는
   그대로다. */
.screen--onboarding2[data-step="language"] .screen__body { z-index: auto; }

.lang-stack {
  display: flex;
  flex-direction: column;
  gap: 16px;
  width: 335px;
}
.lang-row {
  display: flex;
  align-items: center;
  width: 100%;
}
/* 화살표 칸은 고른 줄에서만 열린다 — 시안 3183-13830에서 고르지 않은 줄은 화살표 없이
   335px 폭을 그대로 쓰고(x=20 시작), 고른 줄만 31+22px 안으로 밀려 283px가 된다(x=73 시작).
   그래서 칸을 미리 잡아 두지 않고 flex-basis·margin으로 여닫으며 폭 변화를 애니메이션한다.
   시안의 31×16 글리프는 55×40 SVG 안에 번짐까지 담겨 있어 칸 밖으로 넘치게 그린다.
   방향은 좌우를 뒤집어 긴 꼬리가 왼쪽 — 알약을 가리킨다(디자이너 확인 2026-10-06, 관람 언어 화면과 반대). */
.lang-row__arrow {
  flex: 0 0 0;
  height: 16px;
  position: relative;
  margin-right: 0;
  opacity: 0;
  transition: flex-basis 0.28s cubic-bezier(0.22, 1, 0.36, 1),
              margin-right 0.28s cubic-bezier(0.22, 1, 0.36, 1),
              opacity 0.2s ease;
}
.lang-row__arrow img {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 55px;
  height: 40px;
  transform: translate(-50%, -50%) scaleX(-1);
  max-width: none;
}
.lang-pill {
  flex: 1 0 0;
  min-width: 0;
  position: relative;
  /* 피그마는 스트로크를 면 안쪽에 그려서 필 높이가 정확히 56px다(패딩 16 + 본문 24).
     CSS 보더는 바깥으로 더해지니 패딩에서 1px을 빼야 같은 56px·같은 글자 위치가 된다. */
  padding: 15px;
  border: 1px solid transparent;       /* 색은 아래 「고리 테두리」(::after) */
  --ring: linear-gradient(var(--slate-600), var(--slate-600));  /* 시안 미선택 보더 #4A3E54(보라 회색) → 네이비 slate_600 */
  border-radius: var(--radius-full);
  background: none;
  font-family: var(--font-base);       /* base/body1/M-16 */
  font-weight: 500;
  font-size: 16px;
  line-height: 1.5;
  letter-spacing: 0.005em;
  text-align: center;
  color: var(--ice-50);                /* 시안 blue_50 → 네이비 ice_50 */
  cursor: pointer;
  transition: border-color 0.2s ease, color 0.2s ease, text-shadow 0.2s ease;
}
/* 필 안쪽 overlay 한 층 — 시안의 유리질감이다(시안 blue_100 → 네이비 ice_100) */
.lang-pill::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Crect width='100%25' height='100%25' fill='%23C5DAF3'/%3E%3C/svg%3E");   /* ice/100 — 단색 그림(밝은 CSS 바탕은 강제 다크에서 어두워진다) */
  mix-blend-mode: overlay;
  pointer-events: none;
  transition: opacity 0.2s ease;
}
.lang-row.is-on .lang-row__arrow {
  flex-basis: 31px;
  margin-right: 22px;
  opacity: 1;
}
.lang-row.is-on .lang-pill {
  --ring: var(--paint-white);
  text-shadow: 0 0 10px rgba(222, 233, 255, 0.4);   /* ice_50 @ 40% */
}
/* 하나를 고르면 나머지 줄이 30%로 잠긴다.
   ⚠️ 줄 자체에 opacity를 걸면 안 된다 — 위 z-index 메모와 같은 함정으로, opacity < 1은
   합성 그룹을 만들어서 필 안쪽 overlay가 화면 배경과 못 섞이고 blue_100이 그대로 떠 버린다
   (그래서 잠긴 줄이 어두워지는 대신 밝은 회보라로 떴었다). 피그마도 결과는 "제대로 섞인
   필을 30%로 낮춘 값"이므로(3183-13836 실측 rgb(6,10,21)), 줄 대신 보더·글자·overlay
   레이어를 각각 30%로 낮춰 같은 값을 만든다. */
.lang-stack.has-pick .lang-row:not(.is-on) .lang-pill {
  --ring: linear-gradient(color-mix(in srgb, var(--slate-600) 30%, transparent), color-mix(in srgb, var(--slate-600) 30%, transparent));   /* 미선택 보더 @ 30% */
  color: color-mix(in srgb, var(--ice-50) 30%, transparent);             /* 글자 @ 30% */
}
.lang-stack.has-pick .lang-row:not(.is-on) .lang-pill::before { opacity: 0.3; }

/* ══════════════ 고리 테두리 — 삼성 인터넷 강제 다크 모드 대비 (2026-10-27) ══════════════
   디자인시스템 「고리 테두리」(components.css 맨 아래)와 같은 규칙을 화면 요소에 쓴다 — 테두리 칸은 투명하게 두고 그 자리에
   --ring(밝으면 단색 그림 · 어두우면 같은 색 linear-gradient)으로 고리를 그린다. 언어 필은 ::before 를 안쪽 빛에 쓰고 있어 ::after. */
.splash__slot::before,
.coach__spot::before,
.coach__card::before,
.acnick__field::before,
.hphoto__status::before,
.lang-pill::after {
  content: "";
  position: absolute;
  inset: calc(-1 * var(--ring-w, 1px));
  padding: var(--ring-w, 1px);
  border-radius: inherit;
  background: var(--ring);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
  pointer-events: none;
}

/* ══════════════ 홈 화면에 추가(standalone) — 2026-10-19 ══════════════
   사파리 탭은 상태바(시안 위 62)와 툴바(아래 92)를 브라우저가 가져가 앱이 그 사이 658 만 쓴다 — 화면 좌표가 전부
   "시안 y − 62" 인 까닭이다. 홈 화면에 추가하면 바가 없어져 화면 위아래 끝까지가 앱이라, 그대로 두면 배경이 위로
   62 올라간 채 아래 끝이 모자라 띠가 생기고(디자이너 실기기 스크린샷 10-19) 바닥 버튼은 시안보다 내려간다.
   그래서 이 모드에서만 시안 375 × 812 판과 같은 자리에 오게 한다(Figma splash_1 5957:71978 · email_1 5957:71770 ·
   wand_before 5957:72593 — 상태바 · 툴바를 비우고 배경을 끝까지 깐 판).
     · 위 — 상태바 높이(--safe-top)만큼 내린다. 헤더는 원래 더하고 있었고, 배경 · 떠 있는 요소(스플래시 로고 등)도
       같은 값을 더한다(사파리 탭에서는 0 이라 그대로다).
     · 아래 — 바닥에 붙는 버튼(--ui-gap 을 쓰는 것)을 툴바가 있던 자리만큼 띄운다. 최대 92(시안 툴바),
       짧은 기기는 남는 만큼만(보이는 높이 − 상태바 − 658). 홈 인디케이터보다 아래로 내려가지는 않는다.
     · 배경 — 화면 끝까지 깐다. 스크롤 끝 여백(약관 · 보호자 동의 등)은 홈 인디케이터만 피한다(--safe-bottom).
   <html class="is-standalone"> 는 index.html 머리의 스크립트가 붙인다(display-mode: standalone · navigator.standalone). */
.is-standalone .app {
  --ui-gap: max(var(--safe-bottom), min(92px, calc(var(--screen-h) - var(--safe-top) - 658px)));
}

/* 홈 — Figma wand_before 5957:72593 · potion before 5967:79037(10-19 띠를 걷은 뒤 다시 잡은 배치 — 전: 5967:73321).
   콘텐츠 여섯 모두 같은 배치다. 나의 QR 은 첫 화면에 비치지 않게 화면 아래끝 + 8 에서 시작한다(사파리 탭과 같은 규칙).
     모자 72(헤더 70 + 2) · 로고 136(200 × 85) · 칸 243 · 캡션 485 · 레일 589 · 화살표 720(버튼 710 ~ 745)
     — 앱 좌표는 − 62 + 상태바 */
.is-standalone .screen--home .header--home { padding-top: calc(10px + var(--safe-top)); }
.is-standalone .home-logo { margin-top: 9px; }
.is-standalone .home-frame { margin-top: 22px; }
.is-standalone .home .home-rail { margin-top: 32px; }   /* 캡션 자리가 67 → 72 로 늘어난 만큼 줄여 자리는 그대로(전 37) */
.is-standalone .home-scroll-hint { margin-top: 35px; }
/* 나의 QR 을 상태바 아래 202(시안 264 — app.js myQrScrollTop)까지 올려 볼 수 있게 아래를 남긴다 — 화면이 길수록 더.
   ⚠️ 판의 padding 이 아니라 나의 QR 의 margin 으로 남긴다 — sticky 는 부모의 padding 안으로 못 들어가서,
      padding 으로 두면 아래 화살표가 나의 QR 아래끝에 걸려 굴릴 때 따라 올라간다(실측 720 → 602). */
.is-standalone .home-myqr {
  margin-top: max(33px, calc(var(--screen-h) + 8px - var(--safe-top) - 683px));
  margin-bottom: max(calc(112px + var(--safe-bottom)), calc(var(--screen-h) - 202px - var(--safe-top) - 363px));
}
.is-standalone .home-page {
  padding-bottom: 0;
  overflow: clip;   /* hidden 은 이 판을 스크롤 상자로 만들어 아래 sticky 가 듣지 않는다(.wres 와 같은 사정) */
}
/* 나의 QR 화면 — Figma wand_qr 5967:80815 · potion_qr 5967:81065. 나의 QR 이 264 에 서고, 그 위로 칸 · 캡션 · 레일이
   40% 로 비치며 레일은 119 에 남는다. 한 장으로 굴리기만 하면 레일이 33(상태바 밑)까지 올라가므로,
   콘텐츠 묶음(.home)을 레일이 119 에 닿는 자리에서 멈춰 세운다(sticky) — 남은 86 은 나의 QR 만 올라온다.
   멈추는 자리 = 레일 119 − 칸 윗변에서 레일까지 346 → 칸 윗변 시안 −227. 묶음 윗변은 칸보다 22(칸 margin) 위라
   −249(앱 상태바 − 311)다. */
.is-standalone .home { position: sticky; top: calc(var(--safe-top) - 311px); }
.is-standalone .screen--home.is-scrolled :is(.header--home, .home-logo, .home) { opacity: 0.4; }
/* 화살표는 화면 720 에 붙어 있고, 나의 QR 로 내려오면 사라지지 않고 위를 가리킨다(누르면 맨 위로 — app.js). */
.is-standalone .home-scroll-hint {
  position: sticky;
  top: calc(648px + var(--safe-top));   /* 처음 자리 그대로(시안 710) — 굴려도 거기 남는다 */
  z-index: 2;
}
.is-standalone .home-scroll-hint img { transition: transform 0.3s ease; }
.is-standalone .screen--home.is-scrolled .home-scroll-hint { opacity: 1; pointer-events: auto; }
.is-standalone .screen--home.is-scrolled .home-scroll-hint img { transform: rotate(-90deg) scaleY(-1); }

/* 결과 화면(시트 안의 전체 화면) — 뿌리 위에 상태바만큼 띠를 둔다. 띠는 테두리라 안쪽 좌표(시안 y − 62)가
   통째로 내려가고, 띠 자리는 뿌리 바탕이 칠한다(배경 겹은 안쪽에서 잘리니, 그림이 위끝까지 오는 화면은
   그림 맨 윗줄 색을 --edge-top 으로 준다). 한 장짜리는 띠를 높이 안에 넣어 스크롤이 생기지 않게 한다. */
.is-standalone :is(.wres, .hres1, .hres, .pres1, .pres, .pat1, .pat, .dreveal, .qreveal, .hphoto) {
  border-top: var(--safe-top) solid var(--edge-top, transparent);
  /* 저장 줄(퀴디치는 [확인])은 화면 바닥에서 32 — 12 + 20. 결과 화면들은 저장 줄 바닥 여백이 같다는 규칙이라 여섯 모두
     따른다(2026-10-20 디자이너 결정 — 시안 result_wand/completed3 5967:76004 의 725 ~ 780 로 통일.
     전: 12 + 홈 인디케이터 — result_digital 5967:73431 의 712, 실기기 약 46). 툴바 자리는 비우지 않는다. */
  --ui-gap: 20px;
}
.is-standalone :is(.hres1, .pres1, .pres, .pat1, .pat, .dreveal, .qreveal, .hphoto) { box-sizing: border-box; }
/* 다운로드 묶음 화면(기숙사 사진 · 초상화)의 굴릴 길이에 위 띠를 더한다 — 뿌리 높이가 띠까지 센다(border-box) */
.is-standalone :is(.dreveal, .hphoto) { --dl-band: var(--safe-top); }

/* 완드 결과 — Figma result/hollywand/completed2 5967:74591 · result_wand/completed3 5967:76004(10-19 띠를 걷은 뒤 배치).
   첫 장: 머리말 120 · 그림 242(사파리 232) · 주재료 463(444) · 화살표는 본문 아래 35(25) — 709.
   둘째 장: 주문 덩이는 헤더 아래끝(110)과 저장 줄 윗변(725) 사이 한가운데(app.js wresMeasure),
            머리 → 설명 32(30) · 설명 → 배지 48(33), 저장 줄은 바닥에서 32(725 ~ 780 — 위 결과 화면 공통 --ui-gap).
   빛무리는 아래 것이 574(524), 위 것이 −226(−206) — 앱 안쪽 좌표는 − 62. */
/* 첫 장 — Figma result/hollywand/completed1 5967:74556: 문장 142(사파리 159) · 지팡이 246.4(252.4) · tap 646.4(637.4) ·
   빛기둥 −244(−214, 그림도 따로 — 진하기 80% · 색 #354E71) · 빛무리 574(524) · 별밤 −124(같다).
   ⚠️ 이 장은 위 띠(테두리)를 쓰지 않는다 — 빛기둥이 화면 맨 위(상태바 뒤)부터 내려오는데, 띠를 두면 겹이 안쪽에서
      잘려 상태바 아래끝에 가로 경계가 생긴다(미리보기 실측). 대신 자리마다 상태바를 더한다(시안 − 62 + 상태바). */
.is-standalone .wres1__caption { top: calc(80px + var(--safe-top)); }
.is-standalone .wres1__stage { top: calc(184.4px + var(--safe-top)); }
.is-standalone .wres1__tap { top: calc(584.4px + var(--safe-top)); }
.is-standalone .wres1__beam { top: calc(-306px + var(--safe-top)); }
.is-standalone .wres1__beam::before { background-image: url('assets/result/wand/beam-top-standalone.svg'); }
.is-standalone .wres1__glow { top: calc(512px + var(--safe-top)); }
.is-standalone .wres1__stars { top: calc(-186px + var(--safe-top)); }
.is-standalone .wres__art { margin-top: 10px; }    /* 머리말 아래 8 + 10 = 18 */
.is-standalone .wres__text { margin-top: 9px; }    /* 그림 아래 8 + 9 = 17 */
.is-standalone .wres__one { gap: 35px; }
/* 본문 뒤 큰 호(Group 1173)는 주재료 윗변에서 −260(시안) — 이 상자는 본문(주재료 아래 67)에 붙어 있어 −327 이다 */
.is-standalone .wres__arc { top: -327px; }
.is-standalone .wres__glow--a { top: 512px; }
.is-standalone .wres__glow--b { top: calc(var(--wres-scroll, 494.2px) - 288px); }
.is-standalone .wres__spell { gap: 32px; }
.is-standalone .wres__badge { margin-top: 48px; }
.dreveal { --edge-top: #291B12; }   /* ⚠️ non-token: 벽 그림(portraits/wall.webp)이 잘리는 줄(앱 0 · 그림 31)의 평균색 */
.qreveal { --edge-top: #261B40; }   /* ⚠️ non-token: 퀴디치 오늘의 순위 시안(6088:31013) 앱 맨 윗줄(시안 62 ~ 65) 평균색 */

/* 움직이는 초상화 결과 — Figma result_digital/completed1 5967:73431(홈 화면에 추가 전용, 10-19). 벽 그림이 바뀌었고
   (image 802 — 화면 끝까지 덮는다) 액자가 커지며 30 내려왔다(액자 324 × 427 · 사진 칸 (72, 222) 237 × 352).
   벽 · 액자는 시안 판 그대로 한 장(portraits/wall-standalone.webp, 375 × 812 의 3배)으로 구워 뿌리 바탕에 깐다 —
   액자 그림은 Figma 필터(대비 −77 등)가 걸려 따로 내보내면 바깥이 회색으로 나온다. 위 띠까지 같은 그림이 칠한다.
   빈 캔버스 · 사진(영상) · 붓 획은 그 자리(+8.95, +30.22)로 옮긴다. 옛 벽 · 액자 그림은 숨긴다. */
.is-standalone .dreveal {
  --edge-top: transparent;
  --dl-end: 543px;   /* 굴릴 길이 — 바탕 그림 속 액자 아래끝(그림 605 − 62) */
  background: url('assets/portraits/wall-standalone.webp') 0 calc(-62px + var(--safe-top)) / 375px 812px no-repeat, #0C0502;  /* ⚠️ non-token: 그림 맨 아랫줄 색 */
  background-origin: border-box;
}
.is-standalone .dreveal :is(.dstage__wall, .dstage__frame) { display: none; }
.is-standalone .dreveal :is(.dstage__canvas, .dstage__photo, .dstage__glass, .dstage__sparks) { translate: 8.95px 30.22px; }
/* 바탕 그림의 액자는 움직이지 않으니 무대도 옛 자리(−31)에 두고 내려 있다 올라오는 움직임도 없다 */
.is-standalone .dreveal .dstage { top: -31px; transform: none; }
