/* ════════════════════════════════════════════════════════════════════
   shop-oracle-ui.css — 도사집(청운) 화면 배치
   ────────────────────────────────────────────────────────────────────
   2026-09-03 전체계획 #151 · 계약 정본 `00_메인헤더\경험계약.md` §5-3.

   사람이 정한 값 (계약 §5-3 — 감으로 정한 숫자가 하나도 없다):
     · 상단 35~40%  = 청운 / 상담실
     · 하단 60~65%  = 채팅
     · 청운 왼쪽 말풍선 · 손님 오른쪽 말풍선
     · 입력은 자유입력이 기본. chip 은 필요한 순간에만 입력창 **위에** 뜬다.

   ── 왜 파일을 새로 냈나 ─────────────────────────────────────────────
   앞판의 `body.dj-on` 규칙 여덟 줄은 `shop-tarojip.css` 안에 있었다. 그 파일은
   **타로집의 정본**이다 — 도사집을 고치다 손이 미끄러지면 루나 화면이 같이 깨진다
   (`reading.html` 을 둘이 나눠 쓴다 · 감사 §⑭ 의 [높음] 위험 두 개 중 하나).
   그래서 도사집 몫만 이 파일로 옮겼다. 여기 있는 선택자는 **전부 `body.dj-on` 으로 시작한다** —
   그 클래스는 `shop-oracle.js` 가 도사집일 때만 붙인다. 타로집에는 한 줄도 안 닿는다.

   ── 앞판과 무엇이 다른가 ────────────────────────────────────────────
   앞판은 나뉜 화면이 아니었다. 무대를 `inset:0` 으로 화면 전체에 깔고, 그 위에
   대화창을 통째로 얹은 뒤 `padding-top:42vh` 로 밀어 둔 것이었다. 그래서
     · 대화가 길어지면 말풍선이 청운의 얼굴 위로 **올라가 덮었다**
     · 청운은 글 뒤에 깔린 배경이라 [마주 앉은 사람] 으로 안 읽혔다
   이제 띠 두 개로 **실제로 나눈다.** 무대는 위 띠 안에서만 그려지고, 대화는
   아래 띠 안에서만 구른다. 서로 넘어가지 않는다.
   ════════════════════════════════════════════════════════════════════ */

body.dj-on{
  /* 계약 §5-3 = 상단 35~40%. 가운데값 38% 를 기본으로 잡는다. */
  --dj-stage-h: 38dvh;
  /* 아래 고정 바(입력칸 + chip + 배너)의 실제 높이. `shop-oracle.js` 가 재서 넣는다.
     못 재도 화면이 깨지지 않게 기본값을 둔다. */
  --dj-bottom-h: 72px;
  /* 말풍선 단 폭 — 넓은 화면(폴드 펼침 1968px)에서 글이 가로로 늘어지지 않게. */
  --dj-col: 520px;
  /*  띠 안에서 무엇을 보여 줄지 — 청운의 얼굴이 놓인 세로 위치.
      ★ **원화가 바뀌면 이 한 줄만 갈면 된다**(2026-09-03 사람: 인물 원화 변경 예정).
        다시 재는 법 — 새 첫 프레임을 브라우저에 띄우고 행마다 살색 화소를 세어
        가장 진한 60px 구간의 중심 Y 를 구한 뒤, 아래 식으로 이 값을 낸다:
          Y% = (얼굴Y*배율 - 띠높이/2) / (원본높이*배율 - 띠높이),  배율 = 띠폭 / 원본폭
        지금 값 28% 는 `cheongun-greeting-last.jpg`(720x1280)에서 얼굴 Y=421(32.9%)로 잰 것이다. */
  --dj-face-y: 28%;

  /*  ★ 2026-09-06 [3번방 실기기 UX 수정] §4 — `shop-oracle.js` 의 `뷰포트감시()` 가
      `visualViewport` 실측으로 `--dj-vvh`(몸통)·`--dj-stage-h`(무대, px)를 직접 박는다.
      JS 가 아직 안 돌았을 때(첫 페인트)만 `100dvh`/위 38dvh 기본값이 쓰인다. */
  height: var(--dj-vvh, 100dvh);
  overflow: hidden;          /* 몸통은 안 구른다 — 구르는 것은 대화창 하나뿐이다 */
  background: #1a1128;
}

/* ── 위 띠 · 청운 ────────────────────────────────────────────────── */
/*  `.tj-stage` 는 타로집에서 `position:fixed; inset:0` 이다(shop-tarojip.css:31).
    도사집에서는 **위 띠로만** 잘라 쓴다. 파일을 나눠 쓰되 배치는 여기서 다시 잡는다. */
body.dj-on .tj-stage{
  inset: 0 0 auto 0;
  height: var(--dj-stage-h);
  z-index: 0;
}
/*  띠의 아랫단만 어둡게 — 대화창과 닿는 자리를 부드럽게 잇는다.
    앞판은 화면 전체를 덮었다(글이 인물 위에 있었으니 그래야 읽혔다). 이제 안 겹치므로
    청운을 어둡게 만들 이유가 없다. 얼굴이 그만큼 밝게 보인다. */
body.dj-on .tj-stage::after{
  content: ""; position: absolute; inset: auto 0 0 0; height: 38%;
  pointer-events: none;
  background: linear-gradient(180deg, rgba(26,17,40,0) 0%, rgba(26,17,40,.86) 100%);
}

/* ── 띠 안에서 인물이 보이게 ────────────────────────────────────── */
/*  ★ 이것을 안 하면 띠는 서는데 **인물이 안 나온다**(2026-09-03 실기기에서 잡았다 —
      띠에 천장·종만 나오고 인물이 위로 잘렸다).
    왜 — `shop-tarojip.css:45` 의 `object-position:46% 16%` 은 **세로 폰 전체 화면** 기준이다
    (그 파일 주석: "세로 폰에서는 cover 가 세로를 채우고 좌우를 잘라내므로 Y 는 아무 일도 안 한다").
    맞는 말이지만 도사집의 띠는 이제 **가로로 넓고 납작하다**(실기기 펼침 749x297 · 비 2.52).
    원본은 720x1280(비 0.5625)이라 cover 가 가로를 채우고 세로를 크게 잘라내므로
    **이번엔 Y 가 전부를 정한다.** 값과 다시 재는 법은 위 `--dj-face-y` 에 적어 두었다.
    ★ 타로집은 안 건드린다 — 이 규칙은 `body.dj-on` 안에만 있다.
      (타로집도 펼친 폴드에서 루나가 안 보인다. 그건 판2 #207·#208 몫이다.) */
body.dj-on .tj-stage .tj-video,
body.dj-on .tj-stage .tj-still,
body.dj-on .tj-stage .tj-shot{
  object-position: 46% var(--dj-face-y);
}
/*  배경 사진(무대가 못 서서 CSS 배경만 남는 판)도 같은 자리를 본다. */
body.dj-on .tj-stage{
  background-position: center var(--dj-face-y);
}

/* ── 머리말 — 하나의 정돈된 바 (2026-09-05 도사집 메인 화면 개선 §3) ─────── */
/*  앞판은 배경이 없는 오버레이 글자(청운 이름·부제)였다. 이제 [← 마을 · 도사집]
    한 줄짜리 얇은 바로 바꾼다 — 반투명 짙은 남색 + 얇은 금색 테두리, 상태바 안전영역은
    침범하지 않는다. 실제 [← 마을] 버튼은 이 바 안의 DOM 이 아니라 back-home.js 가 만드는
    `.ui-topbar`(고정 · z-index 9400)다 — 그 파일은 건드리지 않고, 여기서는 **같은 높이·
    같은 위쪽 여백의 배경 바**를 깔아 시각적으로 한 헤더처럼 보이게만 한다.
    가운데 "도사집" 글자는 DOM 을 새로 만들지 않는다 — 기존 `.char-name strong` 을
    shop-oracle.js 의 헤더갈아끼우기() 가 "도사집" 으로 채워 넣고, 부제(span)와 아바타는
    감춘다. CSS 는 그 채워진 글자를 가운데 두는 자리만 만든다. */
body.dj-on header.char-header{
  position: fixed; top: 0; left: 0; right: 0;
  z-index: 4;
  display: flex; align-items: center; justify-content: center;
  /*  60px 는 새 숫자가 아니다 — back-home.css 가 [← 마을] 줄 하나의 표준 행 높이로 이미
      쓰고 있다(`body.backhome-on{padding-top:60px}`). 그 값과 맞춰야 이 바 배경이
      `.ui-topbar`(뒤로가기 pill)를 위아래로 넉넉히 담아 한 헤더처럼 보인다. */
  height: calc(60px + env(safe-area-inset-top,0px));
  padding: env(safe-area-inset-top,0px) 16px 0;
  background: rgba(26,17,40,.72);
  border-bottom: 1px solid rgba(212,175,90,.32);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  text-shadow: none;
}
body.dj-on header.char-header .back,
body.dj-on header.char-header .char-avatar,
body.dj-on header.char-header .char-name{ display: none; }

/* ── 2026-09-06 사람 지시 [신점 상담 최종 개편] §8·§1 — 중앙 제목을 완전히 뺀다 ────
   앞줄(2026-09-05)은 [← 마을 · 가운데 도사집]이었다. 이제는 **가운데를 비운다** —
   "도사집"·"청운"·"청운 상담" 무엇도 다시 넣지 않는다(지시 절대금지 목록). 왼쪽은
   `.backhome`(back-home.js — 이전 씬 이름을 그대로 읽어 실제로 [‹ 도사집]이 된다),
   오른쪽은 아래 §HUD 절이 🎵·ⓘ 한 쌍으로 채운다. 이 파일의 `header.char-header` 바는
   그 배경만 계속 깐다(할 일이 없어도 지우면 안전영역 계산이 바뀐다). */

/* ── HUD — 재화를 숨기고, 음악·안내를 우측 아이콘 한 쌍으로(2026-09-06 §1·§2·§3) ──
   지시 §2 — 상시 노출되는 영문 BGM 제목 바(`Hall of the Great Tiger`)를 없애고
     🎵 아이콘 하나로 접는다. 누르면 여는 기존 곡 고르기 창은 그대로다(기능 삭제 아님).
   지시 §3 — 재화(은화·연속일수)는 이 화면의 핵심 정보가 아니다. **로직은 그대로 두고**
     노출만 끈다 — 다른 화면(마을 HUD)에서는 계속 보인다.
   ★ 이전 규칙(HUD 두 조각을 얼굴 아래로 내리기)은 이제 필요 없다 — 아예 오른쪽 위,
     ⓘ 옆으로 옮기므로 얼굴과 안 겹친다. */
body.dj-on.premium-hud .tarot-coin-widget{ display: none; }
body.dj-on.premium-hud .bgm-chip,
body.dj-on.premium-hud.bgm-chip-on .bgm-chip{
  top: var(--pg-row1); left: auto; right: 56px;   /* ⓘ(36px) + 8px 간격 + 12px 여백 */
  bottom: auto;
  width: 36px; min-width: 36px; height: 36px; min-height: 36px;
  padding: 0; gap: 0; justify-content: center;
  border-radius: 50%;
}
body.dj-on.premium-hud .bgm-chip .bgm-chip-title,
body.dj-on.premium-hud .bgm-chip .bgm-eq{ display: none; }
body.dj-on.premium-hud .bgm-chip::before{ content: "🎵"; font-size: .96rem; line-height: 1; }

/* ── 아래 띠 · 대화 ──────────────────────────────────────────────── */
body.dj-on #chat{
  position: fixed; left: 0; right: 0;
  /*  ★ 2026-09-12 2차[HERO/CHAT 레이아웃 안정화] — CHAT 시작선(top)은 **딱 하나의 값**
      (--dj-stage-h, HERO 바로 아래)으로 고정한다. 1차에서 만든 --dj-chat-top(키보드 열리면
      더 작은 값으로 줄여 채팅이 청운 위로 겹쳐 올라오는 방식)은 화면마다 시작선이 달라
      [불규칙한 구조]로 보였다 — 폐기. 키보드가 뜨면 body.dj-on{ height:var(--dj-vvh) }
      (뷰포트감시() 실측)로 몸통 자체가 줄고, 이 #chat 은 fixed 라 그 축소된 뷰포트를
      그대로 따라간다 — top 은 안 바뀌고 bottom(입력창 바로 위)만 위로 딸려 와 CHAT 이
      보이는 세로 폭만 준다. 청운은 절대 안 가린다("HERO=고정 · CHAT viewport=축소"). */
  top: var(--dj-stage-h);
  /*  ★ 배너 높이를 **더해서** 뺀다. `--dj-bottom-h` 는 바 자체의 높이일 뿐이고, 배너가 뜨면
      그 바가 배너만큼 위로 올라간다(.dj-bottom 의 bottom). 이 줄에서 배너를 안 더하면
      바가 채팅 마지막 줄을 그만큼 덮는다 — 2026-09-03 배너 64px 로 재서 잡았다(RW-045 와 같은 결). */
  bottom: calc(var(--dj-bottom-h) + var(--banner-ad-height, 0px));
  margin: 0; max-width: none;
  /*  가운데 한 단으로 모은다. 좁은 화면에서는 16px 여백만 남는다. */
  padding: 14px max(16px, calc(50% - var(--dj-col) / 2)) 10px;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;      /* 끝까지 굴러도 몸통이 안 딸려 온다 */
  z-index: 2;
  background: transparent;
}

/* ── 아래 고정 바 — chip + 입력칸 ─────────────────────────────────── */
/*  `--banner-ad-height` 는 `ads.js:52` 가 실측해 넣는 값이다. 배너는 WebView 아래 끝이
    아니라 그 위에 겹치는 **네이티브 뷰**라(ads.js:36 · SM-F966N 실측), 이 값을 안 빼면
    입력칸의 첫 탭이 배너에 먹힌다(RW-045 재현 이력). 새로 만드는 바닥 UI 는 전부 이 값을 탄다. */
body.dj-on .dj-bottom{
  position: fixed; left: 0; right: 0;
  bottom: var(--banner-ad-height, 0px);
  z-index: 3;
  background: linear-gradient(180deg, rgba(26,17,40,.86) 0%, #1a1128 42%);
  padding-bottom: env(safe-area-inset-bottom, 0px);
}
/*  ★ 2026-09-06 [3번방 실기기 UX 수정] §15·§16 — 기존 `#composer`/`#user-input`/`#send-btn` 은
    `reading.css` 공용 크림·갈색 톤(`var(--card)`·`var(--accent)`)을 그대로 물려받고 있었다
    (실기기에서 [갈색 큰 textarea]로 보인 원인). 도사집 채팅에서만 한 줄 알약 바로 다시 입힌다 —
    다른 네 상점은 이 선택자가 전부 `body.dj-on` 안이라 한 픽셀도 안 바뀐다. */
body.dj-on #composer{
  position: static; max-width: var(--dj-col); margin: 0 auto;
  display: flex; align-items: center; gap: 6px;
  min-height: 52px; padding: 4px 6px 4px 14px;
  border-radius: 999px;
  border: 1px solid rgba(190,170,225,.4);
  background: linear-gradient(165deg, rgba(63,49,102,.58), rgba(26,17,40,.7));
  box-shadow: 0 0 0 rgba(0,0,0,0);
}
body.dj-on #composer:focus-within{
  border-color: rgba(233,199,123,.55);
  box-shadow: 0 0 12px rgba(233,199,123,.18);
}
body.dj-on #user-input{
  flex: 1 1 auto; min-width: 0;
  background: transparent; border: 0; box-shadow: none;
  color: #f3e9ff; font: inherit; font-size: .9rem;
  padding: 8px 2px;
  max-height: calc(1.4em * 3 + 16px);   /* §15 — 최대 3줄, 그 이상은 내부 스크롤 */
  overflow-y: auto;
}
body.dj-on #user-input::placeholder{ color: rgba(216,201,239,.55); }
/*  §19 — 전송 버튼을 원형 아이콘으로. `#send-btn` 은 공용 `<button>보내기</button>` 이지만
    글자를 지우지 않는다(스크린리더용) — 시각만 아이콘으로 덮는다. */
body.dj-on #send-btn{
  flex: 0 0 auto; min-width: 40px; min-height: 40px; width: 40px; height: 40px;
  padding: 0; border-radius: 50%; border: 0;
  background: linear-gradient(135deg, #b19ce0, #8f6fc9);
  color: transparent; font-size: 0;
  box-shadow: 0 0 0 rgba(151,127,191,0);
  transition: box-shadow .15s ease, opacity .15s ease;
  position: relative;
}
body.dj-on #send-btn::before{
  content: "➤"; position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  font-size: 1rem; color: #fff9ed;
}
body.dj-on #send-btn:not(:disabled){ box-shadow: 0 0 10px rgba(151,127,191,.4); }
body.dj-on #send-btn:disabled{ opacity: .4; }
/* §18 — 소리 아이콘을 입력창 옆으로. 새 기능이 아니라 `.tarot-audio-widget` 그대로를
   부르는 대리 버튼(shop-oracle.js 바닥세우기()) — 원래 떠 있던 자리는 아래에서 숨긴다. */
body.dj-on .dj-audio-ico{
  flex: 0 0 auto; min-width: 40px; min-height: 40px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 999px; border: 1px solid rgba(190,170,225,.34);
  background: rgba(56,42,76,.62); color: #efe7ff; font-size: 1rem;
  cursor: pointer;
}
body.dj-on:not(.dj-landing) .tarot-audio-widget{ display: none; }
/* §20 — 무료 상담 표시. 입력창 아래, 더 옅게 — 시각적 위계를 낮춘다. */
body.dj-on .dj-free-badge{
  text-align: center; margin: 4px auto 2px; max-width: var(--dj-col);
  font-size: .64rem; letter-spacing: .02em; color: rgba(233,199,123,.72);
}

/* ── quick reply 카드 (계약 §5-3 · 2026-09-06 [3번방 최종 개편] §12) ────── */
/*  ★ 선택 버튼을 **메인 UI 로 쓰지 않는다** — 자유입력이 기본이다(계약 §5-3).
    그래서 카드는 입력칸을 밀어내지 않고 그 **위에**만 뜬다. 막힌 사람을 위한
    보조이지, 고르는 화면이 아니다. 누르면 손님 말풍선으로 바뀌어 전송된다.
    ★ 3번.png 목표시안 — [❓ 방금 물은 것] 라벨 + 2열 보기 그리드로 카드화(예전엔 한 줄 스크롤 알약). */
body.dj-on .dj-chips{ display: none; }
body.dj-on .dj-chips.has{
  display: block;
  max-width: var(--dj-col); margin: 0 auto;
  padding: 8px max(16px, calc(50% - var(--dj-col) / 2)) 2px;
}
body.dj-on .dj-chip-q{
  display: flex; align-items: center; gap: 6px;
  margin-bottom: 6px; padding: 6px 10px;
  border-radius: 12px;
  border: 1px solid rgba(151,127,191,.32);
  background: rgba(63,49,102,.42);
  color: #d8c9ef; font-size: .78rem; font-weight: 700;
}
body.dj-on .dj-chip-q-ico{ flex: 0 0 auto; font-size: .82rem; }
/*  ★ 2026-09-06 [3번방 실기기 UX 수정] §14 — 2열 grid 를 고정하면 긴 문구가 칸에 못 들어가
    "...(ellipsis)"로 잘렸다(실기기 재현). grid 를 버리고 **줄바꿈되는 flex** 로 바꾼다 —
    문구가 짧으면 한 줄에 여럿(3번.png 목표시안처럼), 길면 다음 줄로 자연스럽게 내려간다.
    말줄임은 아예 안 쓴다 — 문구 자체를 짧게 받는 쪽(server.js quickReplies 12자 제한)이 맡는다. */
body.dj-on .dj-chip-grid{
  display: flex; flex-wrap: wrap; gap: 6px;
}
/*  ★ 2026-09-12 3차[VISUAL DENSITY 정리] §6 — 퀵리플라이는 말풍선·결과카드보다 시각적
    비중이 낮아야 한다. 높이·좌우 padding 을 한 단 더 줄인다(그림자는 원래 없다 — 테두리 1px
    그대로 단순 유지). 텍스트 크기(font-size)는 안 건드려 읽기는 그대로 쉽다. */
body.dj-on .dj-chips button{
  flex: 0 1 auto;
  min-height: 36px; padding: 0 12px;
  border-radius: 999px;
  border: 1px solid rgba(190,170,225,.34);
  background: rgba(56,42,76,.62);
  color: #efe7ff;
  font: inherit; font-size: .82rem; line-height: 1.3;
  cursor: pointer;
  white-space: normal; word-break: keep-all;
}
body.dj-on .dj-chips button:active{ background: rgba(78,60,104,.86); }
/*  §13 A — 질문 라벨이 없는 [예시] 칩. 상담 시작 전 손님이 먼저 꺼낼 말 후보라 더 크고
    outline 느낌(테두리 위주, 배경 옅게)으로 [B 보다 비중 있게] 보이게 한다. */
body.dj-on .dj-chips:not(.has-q) button{
  min-height: 40px; padding: 0 14px;
  background: rgba(56,42,76,.32);
  border-color: rgba(190,170,225,.5);
  font-weight: 600;
}
/*  §13 B — 청운이 방금 물은 것에 대한 실제 답. 조금 더 작고 조용한 선택형 칩. */
body.dj-on .dj-chips.has-q button{
  min-height: 33px; padding: 0 10px;
  font-size: .78rem;
}

/* ── [청운의 정리] 카드 (계약 §5-3 상담 종료) ─────────────────────── */
/*  ★ 일반적인 AI 마지막 답변으로 끝내지 않는다 — 정해진 네 칸으로 닫는다.
    말풍선이 아니라 **카드**여야 [받아 가는 것]으로 읽힌다. */
/*  ★ 2026-09-12 3차[VISUAL DENSITY 정리] §1·§2 — 카드가 화면을 지배하지 않게 내부 여백을
    약 18% 줄인다(14→12px · 16→13px · dt간격 10→8px · quote 12→9px). 칸 수·문구는 안 건드린다
    (정리카드() 는 이미 최대 2칸+한마디로 짧다 — 여기서는 [여백]만 줄인다). */
body.dj-on .dj-summary{
  align-self: stretch;
  margin: 6px 0 2px;
  padding: 12px 13px;
  border-radius: 14px;
  border: 1px solid rgba(190,170,225,.30);
  background: rgba(38,27,58,.92);
  box-shadow: 0 6px 22px rgba(0,0,0,.34);
}
body.dj-on .dj-summary h3{
  margin: 0 0 8px; font-size: .82rem; font-weight: 700;
  letter-spacing: .04em; color: #cbb6f2;
}
/*  9차[PREMIUM CONSULTATION FINALE] §9 — 핵심 판정 한 줄을 카드 맨 위에서 한 단 더 또렷하게.
    새 칸을 만드는 게 아니라(구조는 그대로) 기존 방향(summary) 문장의 [보이는 무게]만 올린다. */
body.dj-on .dj-summary-lead{
  margin: 0 0 10px; font-size: 1.02rem; font-weight: 700; line-height: 1.45;
  color: #fff9ee;
}
body.dj-on .dj-summary dl{ margin: 0; }
body.dj-on .dj-summary dt{
  font-size: .74rem; color: #a996c9; margin-top: 8px;
}
body.dj-on .dj-summary dt:first-of-type{ margin-top: 0; }
body.dj-on .dj-summary dd{
  margin: 3px 0 0; font-size: .9rem; line-height: 1.5; color: #efe7ff;
}
body.dj-on .dj-summary ol{ margin: 3px 0 0; padding-left: 18px; }
body.dj-on .dj-summary li{ font-size: .9rem; line-height: 1.5; color: #efe7ff; }
/* ── [오늘의 청운 한마디](§11 · 2026-09-11) — 카드 하단, 절제된 인용구 한 줄.
   서버가 이번 상담 맥락으로 지어 준 것만 나온다(없으면 칸 자체가 없다). */
body.dj-on .dj-summary-quote{
  margin: 9px 0 0; padding: 8px 6px 0; border: none; border-top: 1px solid rgba(190,170,225,.24);
  font-size: .88rem; line-height: 1.5; font-style: normal; color: #efe7ff; text-align: center;
}

/* ── [신점 카드] — 대화 중간, 아주 가끔(§14). .dj-summary 보다 가볍다 — 마무리 카드와
   같은 무게로 보이면 [늘 뜨는 것]으로 읽힌다. */
body.dj-on .dj-insight{
  align-self: stretch;
  margin: 4px 0;
  padding: 9px 12px;
  border-radius: 12px;
  border: 1px solid rgba(190,170,225,.26);
  background: rgba(38,27,58,.7);
}
body.dj-on .dj-insight-head{
  display: block; margin-bottom: 3px;
  font-size: .72rem; font-weight: 700; letter-spacing: .02em; color: #cbb6f2;
}
body.dj-on .dj-insight p{ margin: 0; font-size: .86rem; line-height: 1.45; color: #efe7ff; }

/* ── 화면이 짧을 때 ──────────────────────────────────────────────── */
/*  계약이 준 폭은 35~40% 다. 짧은 화면에서 38% 를 그대로 쓰면 채팅이 세 줄로 줄어드는데,
    그건 계약 §5-3 이 [하단 60~65%] 로 막아 둔 상태다. 그래서 **띠를 35% 로 줄인다**
    — 계약 범위의 아래끝이지 범위 밖이 아니다. */
@media (max-height: 700px){
  body.dj-on{ --dj-stage-h: 35dvh; }
}
/*  폴드를 접으면 가로가 확 좁아진다(커버 1080x2520 → 가로/세로 0.43). 세로가 길면 띠를
    40% 까지 올려도 채팅이 넉넉하다 — 계약 범위의 위끝.
    ★ `max-aspect-ratio` 다. `min-` 은 **넓은 화면**에 걸린다 — 처음에 그렇게 썼다가
      펼친 폴드(1968x2184 · 0.90)가 40% 를 받았다(2026-09-03 실기기에서 잡았다). */
@media (max-aspect-ratio: 1/2){
  body.dj-on{ --dj-stage-h: 40dvh; }
}
/*  가로로 눕히면 띠가 화면을 다 먹는다. 이때만 범위 밖으로 내린다 —
    가로는 계약이 다루지 않는 자세다(계약 §5-3 은 세로 기준). */
@media (orientation: landscape) and (max-height: 520px){
  body.dj-on{ --dj-stage-h: 46dvh; --dj-col: 620px; }
}

/* 동작 줄이기 — 띠가 바뀔 때 튀지 않게만. */
@media (prefers-reduced-motion: no-preference){
  body.dj-on .tj-stage{ transition: height .28s ease; }
  /*  ★ 2026-09-12 — 무대(--dj-stage-h)는 이제 고정이라 안 바뀐다. 이 transition 은
      #chat 의 top(--dj-chat-top)이 키보드 열림·닫힘으로 바뀔 때만 실제로 움직인다
      (채팅 패널이 청운 위로 겹쳐 올라오는 순간이 매끄럽게). */
  body.dj-on #chat{ transition: top .28s ease; }
}

/* ── 소리 위젯이 입력칸을 덮지 않게 ─────────────────────────────── */
/*  `.tarot-audio-widget`(audio.js:840) 은 전 화면 공통으로 좌하단(배너 위 14px · left 12px)에 고정돼 있다.
    도사집은 입력칸이 그 자리(아래 바)에 눕게 되어 위젯이 placeholder 앞 두 글자를 덮었다
    (2026-09-03 PC 412×915 실측 · 09_작업2팀 산출물 도사집_412x915.png). 위젯은 지우지 않는다 —
    좁은 화면에서 입력칸 왼쪽을 위젯 폭만큼 비운다. 넓은 화면은 입력칸이 가운데 520px 라 안 겹친다. */
@media (max-width: 600px){
  body.dj-on #composer{ padding-left: 64px; }
}

/* ── 소리 위젯이 랜딩 CTA 버튼을 덮지 않게 ─────────────────────────── */
/*  `.tarot-audio-widget`(audio.js:1081)는 좌하단 고정(x12~55·y865~901, 412px 실측)인데
    2번방 랜딩의 CTA 버튼(.dj-cta-primary)이 그 자리에 눕게 되면서 버튼 왼쪽 모서리를 덮었다
    (2026-09-06 헤드리스 412x915 재검증). 위젯은 지우지 않는다 — shop-tarojip.css:624 가 이미 쓴
    방식대로 랜딩 화면에서만 자리를 위로 올린다(주제 카드 목록이 끝나고 무대 사이의 빈 자리). */
/*  ★ 2026-09-22 — [위로 올린다]로는 더 못 피한다. 실기기(SM-F966N · 411×903) 실측에서
    이 규칙이 살아 있는데도 위젯 y651~693 이 [고민 있어] 카드 y568~662 아래 끝과 겹쳤다.
    **숫자 점지 카드(2026-09-22 신설) 때문이 아니다** — 카드를 숨기고 다시 재도 위젯은
    [고민 있어]·`.dj-cta-footer`(y690~727)에 그대로 걸렸다(같은 날 대조 실측). 132px 를 더
    키우면 상담 카드 둘(568~662)보다 위로 올라가 청운 얼굴을 덮는다 — 피할 자리가 없다.
    그래서 사주집이 같은 위젯·같은 이유로 이미 정한 길(`saju-landing.css:348`
    `body.sj-landing-active .tarot-audio-widget{display:none}`)로 바꾼다.
    **지우지 않고 랜딩 동안만 숨긴다** — 상담이 시작되면 :232 가 이어받고(그쪽도 숨김이다),
    소리 조작 창구는 랜딩에서도 상단 음악 칩(bgm-player.css · z 9500)이 그대로 맡는다.
    ★ `dj-on` 을 같이 걸지 않는다 — `dj-on`(무대가 선 뒤)과 `dj-landing`(랜딩이 뜨는 순간)은
    붙는 시점이 달라, 무대가 안 서는 경우 규칙이 통째로 안 걸린다(2026-09-22 헤드리스 실측). */
body.dj-landing .tarot-audio-widget{ display: none !important; }

/* ── 펼친 폴드 — 띠가 낮고 넓어 cover 가 위아래를 잘랐다 ───────────── */
/*  750×832(폴드 펼침) 실측에서 청운의 머리 위가 잘리고 제목 "청운" 이 이마 위에 겹쳤다
    (2026-09-03 art-director 관찰 2 · 도사집_750x832.png). 세로 폰은 object-position 16%(shop-tarojip.css:48)가
    맞지만, 가로가 넓은 자세에서는 위를 0% 로 붙여 머리부터 보인다. 값은 두 자세 실측에서 왔다. */
/*  ★ 2026-09-06 실기기 재실측 — 이 규칙은 [진짜 넓은 화면](폴드 펼침)을 겨눈 것인데,
    키보드가 뜨면 **세로 폰도 뷰포트 종횡비가 일시적으로 이 문턱을 넘는다**(키보드 ON 에서
    412×543 ≈ 0.76 > 0.75) — 얼굴 대신 창밖 벚꽃·달이 보인 원인이 이것이었다. `dj-kb-on`
    (뷰포트감시() 가 붙인다)일 때는 이 규칙을 끈다 — 키보드는 화면을 넓힌 게 아니라 좁힌 것이다. */
@media (min-aspect-ratio: 3/4){
  body.dj-on:not(.dj-kb-on) .tj-stage .tj-video,
  body.dj-on:not(.dj-kb-on) .tj-stage .tj-still,
  body.dj-on:not(.dj-kb-on) .tj-stage .tj-shot{ object-position: 46% 0%; }
}

/* ── 랜딩 전용 정지 합성 그림(2번.png 목표시안) — 상담 시작 전에만 영상 위에 얹힌다 ── */
/*  `assets/village/shops/dosajip/landing-scene.jpg` 가 아직 없으면 shop-oracle.js 의
    onerror 가 이 엘리먼트를 숨겨 지금 쓰는 영상 무대가 그대로 보인다(청운_도사집_상담로비_배경씬_발주서.md). */
body.dj-on.dj-landing .dj-landing-scene{
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: 50% 20%;
  z-index: 5;   /* .tj-video(1/2)·.tj-shot(3)·.tj-still(4) 다 위 — shop-tarojip.css:36-65 */
}
/* ★ 2026-09-10 3차 사람 지시 — 사람이 [청운이 이미 탁자에 앉은 완성 합성본]을 배경
   그림 자체로 새로 줬다(같은 자리 `dosajip/landing-scene.jpg` 교체). 따로 얹던 청운
   전신 컷·접지 그림자 레이어는 배경 그림 안에 같이 들어 있어 **완전히 끈다** — 두 장을
   겹치면 청운이 둘로 보인다. DOM 은 지우지 않고(shop-oracle.js 가 매번 새로 만들었다
   지운다) display:none 으로만 물러난다. */
body.dj-on.dj-landing .dj-landing-char,
body.dj-on.dj-landing .dj-landing-char-shadow{ display: none; }

/* ── 머리말 부제가 밝은 머리카락 위에서 안 읽혔다 ───────────────── */
/*  `.char-name span` 은 reading.css:53 의 --muted 색이다 — 크림 배경용이라 청운 머리 위에서는 판독 불가
    (art-director 관찰 3). 도사집에서만 흰 글자 + 진한 그림자. */
body.dj-on header.char-header .char-name span{
  color: rgba(255,255,255,.92);
  text-shadow: 0 1px 3px rgba(0,0,0,.95), 0 0 10px rgba(0,0,0,.8);
}

/* ════════════════════════════════════════════════════════════════════
   Live2D 청운 무대 (2026-09-03 사람 지시 [청운 Live2D 상담] §22·§23·§39)
   ────────────────────────────────────────────────────────────────────
   ★ 이 절은 `body.dj-l2d` 가 붙었을 때만 산다. 그 클래스는 `shop-oracle.js` 의
     `라이브2D세우기()` 가 **Live2D 가 실제로 뜬 뒤에만** 붙인다 — Core 가 없는 지금은
     한 번도 안 붙는다. 그래서 이 절이 지금 화면을 바꾸는 일은 없다.
   ★ 자리·높이는 위 `.tj-stage` 와 **같은 변수**(--dj-stage-h)를 쓴다. 영상 무대에서
     Live2D 로 갈아도 띠 높이·채팅 자리가 그대로다(§22 [고정 비율 hardcoding 금지] —
     35/40/46dvh 브레이크포인트는 위에서 이미 화면 크기로 갈린다).
   ════════════════════════════════════════════════════════════════════ */
body.dj-on .l2d-stage{
  position: fixed;
  inset: 0 0 auto 0;
  height: var(--dj-stage-h);
  z-index: 0;
  overflow: hidden;
  background: #1a1128;
}
/*  대화창과 닿는 아랫단 — 영상 무대와 같은 그라데이션이라 갈아도 이음매가 안 보인다. */
body.dj-on .l2d-stage::after{
  content: ""; position: absolute; inset: auto 0 0 0; height: 38%;
  pointer-events: none;
  background: linear-gradient(180deg, rgba(26,17,40,0) 0%, rgba(26,17,40,.86) 100%);
}
body.dj-on .l2d-camera{ position: absolute; inset: 0; }

/*  정지 그림 — Live2D 가 첫 프레임을 그리기 전과, 그리다 실패했을 때 이 자리를 지킨다(§35).
    캔버스가 그 위에 투명하게 올라가므로 성공하면 자연스럽게 덮인다. */
body.dj-on .l2d-still{
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: 46% 0%;
}
/*  ★ 캔버스는 CSS 로 늘리지 않는다 — `live2d-stage.js` 의 `크기맞추기()` 가 dpr 을 곱해
    **픽셀 수 자체**를 맞춘다. 여기서 width/height 를 늘리면 그림이 번진다. */
body.dj-on .l2d-canvas{
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  display: block;
}
/*  렌더가 실패하면 캔버스를 걷고 정지 그림만 남긴다 — 검은 사각형이 얼굴을 덮지 않게. */
body.dj-on .l2d-stage[data-l2d="실패"] .l2d-canvas{ display: none; }

/*  모션 축소 — Live2D 는 애초에 안 선다(`live2d-stage.js` 가 `만들기()` 에서 null 을 돌려준다).
    그래도 어떤 길로든 떠 있으면 여기서 멈춘 그림처럼 보이게 한다(§40). */
@media (prefers-reduced-motion: reduce){
  body.dj-on .l2d-canvas{ display: none; }
}

/* ════════════════════════════════════════════════════════════════════
   도사집 메인(랜딩) 화면 — 2026-09-05 개선
   ────────────────────────────────────────────────────────────────────
   상담이 자동으로 시작되던 자리에 [먼저 보는 화면]을 하나 끼운다. 상담 중(#chat) 레이아웃은
   위 절들이 그대로 맡고, 이 절은 `body.dj-on.dj-landing` 이 붙어 있는 동안만 산다 —
   shop-oracle.js 의 랜딩보이기()/닫기() 가 그 클래스와 여기 쓰는 DOM 을 만들고 지운다.
   ════════════════════════════════════════════════════════════════════ */

/* ── 청운을 키운다 — 상담 중 띠(38dvh)보다 랜딩 띠를 넓힌다 ─────────── */
/*  object-fit:cover 인 영상/스틸을 담는 컨테이너가 커지면 화면에서 청운이 차지하는
    자리도 그만큼 커진다(§4 "적절히 확대"). `.tj-cam`/`.tj-video`/`.tj-still` 에 직접
    transform 을 더 얹지 않는다 — `.tj-cam` 은 shop-stage.js 의 카메라흔들기() 가 6.8초마다
    인라인 transform 을 다시 얹고(:232), `.tj-still` 은 숨결 애니메이션이 이미 transform
    자리를 쓴다(shop-tarojip.css:75 · 그 파일 주석이 "같은 자리를 다투어 한쪽이 사라진다"고
    이미 적어 뒀다). 컨테이너 높이 하나로만 키우면 그 다툼을 아예 안 만든다.
    46dvh 는 새 값이 아니다 — 가로 자세 규칙(§215 아래)이 이미 같은 값을 쓰고 있다.
    ★ 2026-09-05 실기기(SM-F966N) 실측 — 46dvh + 실제 배너 광고(80px, 헤드리스 시험엔 없던 값)
    조합에서 아래 CTA 패널이 랜딩 영역 바닥을 넘어 [시작] 버튼 아랫부분이 스크롤 없인 안 보였다
    (`.dj-cta` bottom 878 vs `.dj-landing` bottom 823 — 55px 부족). 42dvh 로 낮춰 그 여유를 만든다 —
    그래도 상담 중 기본값(38dvh)보다는 크다(§4 "적절히 확대"는 여전히 지킨다). */
/*  ★ 2026-09-06 사람 지시 [2번방 최종 수정] §5·§13·§24 — 42dvh 에서도 실기기 광고(80px)와
    겹쳐 CTA 가 잘렸다(사람 스크린샷 실측). 15~20%↓ 로 한 번 더 낮춘다 — 청운 얼굴은
    여전히 상담 중 기본값(38dvh)보다 크게 유지한다(§5 "청운 얼굴이 충분히 커야 한다"). */
/*  2026-09-07(3차 — [사주방/타로방/도사방 입구씬 UI 최종 리마스터]) — #256 주석(위)이 이미
    "청운·배경이 화면 65~75%를 차지해야 한다"고 정해 뒀는데 이 값이 실제로는 한 번도 안 먹고
    있었다. **진짜 원인**은 이 CSS가 아니라 `shop-oracle.js` 의 뷰포트감시() — 키보드 대응
    으로 상담(채팅) 화면의 무대 높이를 `visualViewport` 실측 30%(키보드 열림 17%)로 매 리사이즈
    마다 `document.body.style.setProperty("--dj-stage-h", …)` **인라인 스타일**로 박아 넣는다
    (shop-oracle.js:874). 인라인 스타일은 일반 우선순위 규칙보다 세서, `!important` 가 없는
    이 자리의 어떤 값(34dvh 였든 70dvh 였든)도 항상 그 30%(실측 274~311px)에 졌다 —
    사주방·타로방과 달리 도사방만 [입구씬인데 상담용 30% 무대 자를 그대로 뒤집어쓰는] 구조라
    이 화면만 안 커졌던 것이다. 상담(§ [3번방]) 쪽의 키보드 대응 로직은 그대로 두고
    건드리지 않는다(그건 이 사이클 범위 밖이다) — 대신 랜딩 상태에서만 `!important` 로
    되찾는다. */
body.dj-on.dj-landing{ --dj-stage-h: 68dvh !important; }
@media (max-height: 700px){
  body.dj-on.dj-landing{ --dj-stage-h: 62dvh !important; }
}
@media (max-aspect-ratio: 1/2){
  /*  2026-09-08 실기기(SM-F966N) 실측 — 헤드리스 시뮬레이션(915px 가정)보다 실제 innerHeight 가
      낮아(903px) 64dvh 에서도 [오늘 무료 상담] 배지 아랫단이 광고 배너에 12px 겹쳤다. 62dvh 로
      한 단 더 낮춰 실기기 여유를 확보한다. */
  body.dj-on.dj-landing{ --dj-stage-h: 62dvh !important; }
}
/*  펼친 폴드(가로 넓음) — 상담 중 규칙(§233 아래)은 object-position Y 를 0% 로 박아 둔다.
    그 값은 **더 낮은 상담 띠(38dvh)** 에서 "머리 위가 잘리는 것"을 막으려고 정한 값이다
    (그 규칙 주석 — 750×832 실측). 랜딩 띠는 46~48dvh 로 그보다 크므로 같은 0% 를 쓰면
    오히려 이마 언저리에서 잘려 눈이 하나도 안 보인다(2026-09-05 749×832 실측). 랜딩에서는
    이 값을 조금 내려 얼굴이 보이게 한다 — 상담 중 화면(body.dj-on 만)은 안 건드린다. */
@media (min-aspect-ratio: 3/4){
  body.dj-on.dj-landing .tj-stage .tj-video,
  body.dj-on.dj-landing .tj-stage .tj-still,
  body.dj-on.dj-landing .tj-stage .tj-shot{ object-position: 46% 17%; }
}

/* ── 랜딩 중에는 상담용 아래 바·채팅을 감춘다 ────────────────────── */
/*  `.dj-bottom` 은 무대세우기() 가 랜딩보다 먼저 만들어 둔다(입력칸 자리를 재는 로직이 늘
    돌아야 해서) — 그래서 지우지 않고 랜딩 동안만 숨긴다. */
body.dj-on.dj-landing .dj-bottom,
body.dj-on.dj-landing #chat{ display: none; }

/* ── 말풍선 — 청운 옆(위 띠 아랫단)에 붙는다 ─────────────────────── */
body.dj-on.dj-landing .dj-bubble{
  position: fixed; left: 0; right: 0;
  /*  ★ `top` 이 아니라 `bottom` 으로 앉힌다 — HUD 두 조각(BGM 칩·은화 위젯)이 이미
      `bottom: calc(100dvh - var(--dj-stage-h) + 8px)` 로 [상담 띠 경계에서 위로 8px]에
      떠 있다(위 §94-111). 말풍선을 `top` 으로 앉히면 인사말이 두 줄로 접힐 때 아래쪽으로
      자라 그 HUD 줄을 덮는다(2026-09-05 412x915 실측). `bottom` 앵커는 글이 길어져도
      **위로만** 자라 그 줄과 안 겹친다. */
  /*  ★ 2026-09-06 사람 지시 [조금 더 아래로 + 오른편으로] — 68px→34px(HUD 8px 줄과는 여전히
      26px 떨어져 안 겹친다), 가운데 정렬→오른쪽 정렬. */
  bottom: calc(100dvh - var(--dj-stage-h) + 34px);
  z-index: 3;
  display: flex; justify-content: flex-end;
  padding: 0 max(16px, calc(50% - var(--dj-col) / 2));
  pointer-events: none;
}
/*  ★ 2번.png 목표시안 — 크림색 말풍선(어두운 무대 위에서 더 또렷하게 읽힌다). 꼬리 방향은
    캐릭터가 왼쪽에 있는 지금 구도 기준 그대로 두고, 색만 바꾼다.
    ★ 2026-09-06 사람 지시 [말풍선이 얼굴을 가림 → 작게 축소] — 랜딩 배경씬(landing-scene.jpg)
    반입 뒤 실기기 실측으로 확인된 문제. 자리는 그대로 두고 크기만 줄여 가리는 면적을 줄인다. */
/* #258(2026-09-08) — 값 그대로: 배경 rgba(255,250,244,.94) · radius 18~22px. */
body.dj-on.dj-landing .dj-bubble-inner{
  pointer-events: auto;
  display: flex; align-items: flex-start; gap: 7px;
  max-width: calc(var(--dj-col) * .84);
  background: rgba(255,250,244,.94);
  border: 1px solid rgba(212,175,90,.4);
  border-radius: 6px 20px 20px 20px;         /* 왼쪽 위만 살짝 접힌다 — 위(청운) 쪽을 가리키는 꼬리 대신 */
  padding: 7px 10px;
  box-shadow: 0 6px 18px rgba(0,0,0,.4);
}
body.dj-on.dj-landing .dj-bubble-avatar{
  width: 24px; height: 24px; border-radius: 50%; object-fit: cover; flex: 0 0 auto;
  border: 1px solid rgba(212,175,90,.6);
}
/* #258 — 연한 라벤더 배지(사주방 .sj-landing-bubble-name·타로방 .tj-landing-bubble-name 과 같은 결).
   ★ 2026-09-10 6차 사람 지시 [사주집/도사집 공통 타이포그래피 개선] — NPC Name·Conversation
   역할을 `village-typography.css` 공통 토큰으로(reading.html 이 이 파일보다 먼저 읽는다).
   본문은 그대로 시스템 고딕(§5 "장식 폰트로 만들지 않는다") — 청운도 같은 폰트 패밀리를 쓰되
   §4 "색상·weight·spacing 만 차분하게"는 색(딥 네이비 #1f3450 계열)으로 이미 구분돼 있다. */
body.dj-on.dj-landing .dj-bubble-body strong{
  display: inline-flex; align-items: center;
  margin-bottom: 3px; padding: 2px 8px;
  border-radius: 999px; background: #d9caf0;
  font-size: .62rem; font-weight: var(--vt-w-npc-name); color: #3a2e63; letter-spacing: .02em;
  font-family: var(--vt-font-display);
}
body.dj-on.dj-landing .dj-bubble-body p{
  margin: 0; font-size: .78rem; font-weight: var(--vt-w-convo); line-height: 1.4; letter-spacing: .01em;
  color: #3a2e22; font-family: var(--vt-font-body);
  white-space: pre-line;   /* #258 — 대사.랜딩말풍선 의 \n 을 실제 줄바꿈으로(textContent 대입은 그대로) */
}

/* ── 랜딩 본문 — 오늘의 한마디 · 고민 주제 · CTA 패널 ──────────────── */
/* #253(2026-09-07 입구씬 리마스터) — §8 "기존 분위기는 유지하되 하단 패널만 더 귀엽고
   가볍게": 어두운 Deep Indigo 몰입형 배경을 걷고, 사주방/타로방과 같은 반투명 크림/라벤더
   패널로 맞춘다(§3 공통 스타일 — 진한 보라 면적 과다 금지). 레이아웃·칩 구조·이벤트는
   한 글자도 안 바뀐다 — 색과 배경만 갈아 끼운다. */
/* #256(2026-09-07 2차 재수정 · 사람 지시 [방향 재수정]) — 큰 패널을 걷는다. 청운·배경이
   화면 65~75%를 그대로 차지해야 한다. 이 래퍼는 투명 레이아웃 컨테이너일 뿐이고, 그 안의
   요소 하나하나가 [배경 위에 뜬 독립 오브젝트]다(사주방/타로방과 같은 원칙). */
body.dj-on.dj-landing .dj-landing{
  position: fixed; left: 0; right: 0;
  top: var(--dj-stage-h);
  bottom: var(--banner-ad-height, 0px);
  z-index: 2;
  display: flex; flex-direction: column; gap: 7px;
  padding: 8px max(16px, calc(50% - var(--dj-col) / 2)) 6px;
  overflow-y: auto; -webkit-overflow-scrolling: touch; overscroll-behavior: contain;
  background: none;
}
/* #256 — 스페이서가 flex:1 로 남는 공간을 다 먹으면 카드와 CTA 사이에 큰 빈 구멍이 생긴다
   (참고 이미지는 카드 바로 아래 CTA 가 붙어 있다). 큰 패널이 없어진 지금은 고정 간격만
   준다 — 내용이 화면 65~75% 캐릭터 구역 바로 아래에 짧게 뭉쳐 보이게 한다(§ "20~28% 안쪽"). */
body.dj-on.dj-landing .dj-landing-spacer{ flex: 0 0 auto; min-height: 14px; }

/* [오늘의 청운 한마디] — #256: 카드 배경을 걷고 아주 작은 한 줄로(배경이 그대로 비친다). */
body.dj-on.dj-landing .dj-today{
  flex: 0 0 auto;
  display: flex; align-items: center; gap: 6px;
  padding: 0 2px;
}
@media (prefers-reduced-motion: no-preference){
  body.dj-on.dj-landing .dj-today{ animation: dj-fade-in .45s ease both; }
}
@keyframes dj-fade-in{ from{ opacity:0; transform:translateY(6px); } to{ opacity:1; transform:none; } }
body.dj-on.dj-landing .dj-today-ico{ flex: 0 0 auto; width: 14px; height: 14px; filter: drop-shadow(0 1px 3px rgba(20,10,40,.6)); }
body.dj-on.dj-landing .dj-today-body{ display: flex; align-items: baseline; gap: 5px; min-width: 0; }
body.dj-on.dj-landing .dj-today-body h4{
  flex: 0 0 auto; margin: 0; font-size: .6rem; letter-spacing: .02em; font-weight: 700;
  color: #fff3d6; text-shadow: 0 1px 4px rgba(20,10,40,.8);
}
body.dj-on.dj-landing .dj-today-body p{
  margin: 0; font-size: .7rem; line-height: 1.3; color: #fff8ec; text-shadow: 0 1px 4px rgba(20,10,40,.8);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ── 큰 카드 둘(고민 있어 / 그냥 궁금해서) — #259(2026-09-08 [청운 입구씬 단독 교체] 사람 지시)
   값 그대로: linear-gradient · blur(8px) · 72~84px · radius 20~22px.
   카드 자체가 상담 진입 버튼이다(별도 대형 CTA 없음 — shop-oracle.js 가 클릭에 직접 닫기() 를 붙인다).
   ★ 2026-09-10 사람 지시 [3집 내부 리뉴얼] §6 — 도사집 정체성을 WARM IVORY+CLEAR NAVY+SOFT
   TEAL+LANTERN GOLD 로. 옛 짙은 라벤더/남보라 글래스(§3 "크고 무거운 짙은 보라색 선택 패널 느낌을
   줄인다")를 아이보리 글래스로 밝히고, 텍스트·아이콘 배지를 남청으로 바꿔 대비를 지킨다.
   배경·청운도 남청 계열이라 카드까지 남색으로 채우면 온통 남색이 되므로(§6 "UI 전체를 남색으로
   채우지 않는다") 카드 바탕은 아이보리를 主로 쓴다. ── */
body.dj-on.dj-landing .dj-topics-wrap{ flex: 0 0 auto; display: flex; flex-direction: column; gap: 6px; }
body.dj-on.dj-landing .dj-topics-primary{ display: grid; grid-template-columns: repeat(2, minmax(0,1fr)); gap: 9px; }
/* ★ 2026-09-10 2차 §9·§10 — 높이 80px→68px(-15%) · 제목 .8rem→.72rem(보조 문구에 위계를
   더 준다) · 테두리를 샴페인골드 1px 로 더 옅게 · 그림자 최소화 · 내부 여백은 오히려 늘린다. */
body.dj-on.dj-landing .dj-topic-primary,
body.dj-on.dj-landing .dj-topics-primary .dj-topic-free{
  min-width: 0; min-height: 68px; width: 100%; box-sizing: border-box;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 4px; padding: 10px 10px;
  border: 1px solid rgba(201,166,90,.32); border-radius: 21px;
  background: linear-gradient(145deg, rgba(253,249,240,.92), rgba(238,229,209,.86));
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  box-shadow: 0 3px 8px rgba(20,30,50,.1);
  color: #1f3450; font: inherit; text-align: center;
  cursor: pointer; transition: transform .12s ease, box-shadow .12s ease;
}
body.dj-on.dj-landing .dj-topic-primary:active,
body.dj-on.dj-landing .dj-topics-primary .dj-topic-free:active{
  transform: translateY(-2px) scale(1.02); box-shadow: 0 5px 14px rgba(20,30,50,.16);
}
body.dj-on.dj-landing .dj-topic-primary-ico{ display: flex; }
body.dj-on.dj-landing .dj-topic-primary-ico img{ width: 24px; height: 24px; object-fit: contain; }
/* Card Title/Description 역할(§7) — "고민 있어"/"그냥 궁금해서"는 600~700, 서브 문구는 400~500. */
body.dj-on.dj-landing .dj-topic-primary-tt{
  font-size: .72rem; font-weight: var(--vt-w-card-title); color: #1f3450;
  font-family: var(--vt-font-display);
}
body.dj-on.dj-landing .dj-topic-primary-sub{
  font-size: .62rem; font-weight: var(--vt-w-card-desc); color: rgba(45,90,95,.78);
  font-family: var(--vt-font-display);
}
/* [그냥 궁금해서] 큰 카드 안의 기존 dj-topic-* 서브구조(아이콘 원형 배지·제목·부제·화살)를
   위 flex-column 카드 안에서도 자연스럽게 보이도록 정리 — 클릭·선택 로직은 그대로. */
body.dj-on.dj-landing .dj-topics-primary .dj-topic-ico{ width: 30px; height: 30px; }
body.dj-on.dj-landing .dj-topics-primary .dj-topic-text{ align-items: center; }
body.dj-on.dj-landing .dj-topics-primary .dj-topic-text strong{ color: #1f3450; }
body.dj-on.dj-landing .dj-topics-primary .dj-topic-sub{
  white-space: normal; text-align: center; color: rgba(45,90,95,.78);
}
body.dj-on.dj-landing .dj-topics-primary .dj-topic-arrow{ display: none; }

/* #259 — 연애/인간관계/진로/마음 네 갈래 상세 칩(.dj-topics)은 이 화면에서 더는 안 만든다
   (shop-oracle.js 주제칩세우기() 참고 · 함수·데이터는 남아 있다). 아래 .dj-topic-chip 계열
   규칙은 [그냥 궁금해서] 큰 카드(.dj-topic-free)가 그대로 재사용한다 — 지우지 않는다. */
/* ★ 2026-09-06 §9 — [사람 때문에 지쳤어]가 3줄로 깨지고 보조 문구가 "학교 · ..."로 잘리던
   문제를 고친다. 아이콘·패딩·간격을 줄여 글자에 폭을 더 주고, 제목은 최대 2줄로 못박고,
   보조는 폰트를 살짝만 줄여 **한 줄에 실제로 들어가게** 한다(글자를 지나치게 줄이지 않는다
   — 부제 문구 자체도 shop-oracle.js 에서 짧게 다듬었다: "학교/직장"·"불안 · 스트레스 · 마음"). */
/* #253(2026-09-07) — 칩·CTA 도 같은 크림/라벤더 카드 재질로. 구조·클릭·aria-pressed 는 그대로. */
body.dj-on.dj-landing .dj-topic-chip{
  min-width: 0; min-height: 58px; width: 100%; box-sizing: border-box;
  display: flex; align-items: center; gap: 7px;
  padding: 7px 9px;
  border-radius: 14px;
  border: 1px solid rgba(255,255,255,.8);
  background: rgba(255,255,255,.78);
  box-shadow: 0 3px 10px rgba(120,90,150,.08);
  color: #4a3b63; font: inherit; text-align: left;
  cursor: pointer;
  transition: transform .12s ease, box-shadow .12s ease;
}
body.dj-on.dj-landing .dj-topic-chip.is-on{
  border-color: rgba(151,127,191,.6);
  background: rgba(238,229,250,.88);
  box-shadow: 0 0 0 2px rgba(151,127,191,.22), 0 4px 12px rgba(120,90,150,.16);
  transform: scale(1.015);
}
/*  ★ 2번.png 목표시안 — 아이콘을 원형 배지로 키운다(새 그림 없이 기존 라인아이콘 + 배경원).
    배경색은 shop-oracle.js 카드만들기() 가 인라인으로 주제별 `색`을 얹는다. */
body.dj-on.dj-landing .dj-topic-ico{
  flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; border-radius: 50%; font-size: 1.05rem;
}
/* #253 — [그냥 얘기할래] 칩은 이모지 대신 img 아이콘(반짝별)을 쓴다. */
body.dj-on.dj-landing .dj-topic-ico img{ width: 20px; height: 20px; object-fit: contain; }
body.dj-on.dj-landing .dj-topic-text{ display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1 1 auto; }
body.dj-on.dj-landing .dj-topic-text strong{
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden;
  font-size: .82rem; font-weight: var(--vt-w-card-title); line-height: 1.22; color: #4a3b63; word-break: keep-all;
  font-family: var(--vt-font-display);
}
body.dj-on.dj-landing .dj-topic-sub{
  font-size: .62rem; font-weight: var(--vt-w-card-desc); line-height: 1.25; color: rgba(90,70,120,.65);
  font-family: var(--vt-font-display);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* 카드 오른쪽 [›] — 2번.png 는 카드가 다음 화면으로 넘어가는 느낌의 화살을 준다(요청 §14 동적 CTA와
   같은 취지 — "이 카드를 고르면 이야기로 넘어간다"는 신호). 실제 이동은 없다 — 시각 신호만. */
body.dj-on.dj-landing .dj-topic-arrow{
  flex: 0 0 auto; font-size: 1.1rem; color: rgba(90,70,120,.45); line-height: 1;
}
body.dj-on.dj-landing .dj-topic-chip.is-on .dj-topic-arrow{ color: rgba(74,59,99,.85); }

/* ── 가장 아래 정보 바 — #259: [오늘 상담 n회 남음] 왼쪽 · [지난 이야기 ›] 오른쪽, 한 줄
   pill(값 그대로 — 34~40px · radius 14~16px · rgba(30,22,55,.45) · border rgba(220,205,245,.13)).
   대형 CTA 는 이제 없다 — 카드 둘 자체가 진입 버튼이다(§13). "무료"를 강조하지 않는다. ── */
/* ★ 2026-09-10 §6 — 아이보리 글래스로. 배너·본문이 남청이라 이 바만 옅게 밝혀 대비를 준다. */
/* ★ 2026-09-10 2차 §11·§12 — "clear navy text" 로 읽히려면 배경이 실제로 밝아야 한다
   (옅은 .14 알파는 뒤 어두운 배경에 묻혀 사실상 다크였다). 아이보리를 확실히 올리고 텍스트를
   남청으로 바꾼다 — 카드 2장(§9)보다 한 단 약하게 보이도록 배경 알파·그림자를 카드보다 낮게 유지. */
body.dj-on.dj-landing .dj-cta-footer{
  flex: 0 0 auto; min-height: 37px; box-sizing: border-box;
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 0 14px calc(env(safe-area-inset-bottom,0px));
  border: 1px solid rgba(201,166,90,.28);
  border-radius: 15px;
  background: rgba(253,249,240,.72);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
}
/* Small Label 역할(§7) — 카드 2장보다 시각 우선순위가 낮다(§11 그대로 유지). */
body.dj-on.dj-landing .dj-cta-badge{
  font-size: .68rem; font-weight: var(--vt-w-small-label); letter-spacing: .01em;
  color: #1f3450; font-family: var(--vt-font-display);
  background: none; padding: 0;
}
body.dj-on.dj-landing .dj-cta-secondary{
  background: transparent; border: 0;
  color: #a8791f;
  font: inherit; font-size: .7rem; font-weight: var(--vt-w-small-label);
  font-family: var(--vt-font-display);
  min-height: 37px; padding: 0; cursor: pointer;
}
/* [‹ 마을] — 6차 §2 "상단 마을 텍스트에도 공통 Rounded Font". 크기·자리는 전역
   premium-hud.css 규칙을 그대로 물려받고, 랜딩 동안만(body.dj-on.dj-landing) 폰트만 얹는다. */
body.dj-on.dj-landing .backhome{ font-family: var(--vt-font-display); }

/* 짧은 화면 — 여백만 줄인다. 청운·카드의 순서는 그대로(요청 §9) */
@media (max-height: 700px){
  body.dj-on.dj-landing .dj-landing{ gap: 5px; padding-top: 6px; }
  body.dj-on.dj-landing .dj-topic-primary,
  body.dj-on.dj-landing .dj-topics-primary .dj-topic-free{ min-height: 60px; }
}

/* 넓은 화면(펼친 폴드) — 콘텐츠가 무한히 늘어나지 않게 --dj-col 이 이미 최대 폭을 잡는다.
   `.dj-landing`·`.dj-bubble` 모두 그 변수로 좌우 여백을 계산하므로 별도 규칙이 필요 없다. */

/* ════════════════════════════════════════════════════════════════════
   3번방(상담 채팅) — 2026-09-06 사람 지시 [신점 도사 청운 AI 상담방 최종 개편]
   ────────────────────────────────────────────────────────────────────
   §11 — 청운 메시지마다 반복되던 수정구(🔮) 아바타를 뺀다. 위에 이미 청운 영상이
   있으니 화자는 작은 글자 라벨 하나("청운 ✦")로 충분하다 — 새 DOM 을 만들지 않고
   `.msg.bot::before` 하나를 아이콘에서 라벨로 바꿔치기한다(`reading.css:69`).
   §14 색 — 손님은 라벤더 계열 오른쪽, 청운은 인디고 계열 왼쪽(다른 상점 색은 안 건드린다 —
   전부 `body.dj-on` 스코프). ════════════════════════════════════════════════ */
body.dj-on .msg.bot::before{
  content: "청운 ✦";
  position: absolute; left: 26px; top: -18px; bottom: auto;
  /*  ★ 2026-09-06 실기기 실측 버그 — `width:auto` 가 타이핑 점 세 개짜리 작은 말풍선(58px)을
      만나면 [available width] 계산이 그 좁은 상자 폭을 따라가 30px 로 잘리고, "청운 ✦" 가
      "청운" · "✦" 두 줄로 접혔다(카톡 스크린샷 2026-09-06 17:02 실측). `width:auto` 는
      `left` 만 있고 `right` 가 없을 때 컨테이너 폭에 갇힌다(CSS2.1 §10.3.7) — 내용 그대로
      한 줄로 재려면 `max-content` 로 못박아야 한다. */
  width: max-content; height: auto; white-space: nowrap;
  border-radius: 0; background: none;
  font-size: .68rem; font-weight: 700; letter-spacing: .03em;
  color: #cbb6f2;
}
/*  ★ 3번.png 목표시안 — 라벨 왼쪽에 작은 원형 아바타(청운). 새 DOM 을 안 만들고
    `.msg.bot` 의 빈 ::after 자리를 쓴다(이 선택자는 지금까지 아무 것도 안 그렸다).
    쓰는 사진은 앱 전역에서 이미 확정된 한복 크롭(`npc.js` `프로필`)과 같은 파일이다. */
body.dj-on .msg.bot::after{
  content: ""; position: absolute; left: 0; top: -22px;
  width: 20px; height: 20px; border-radius: 50%;
  background: url("assets/village/npc/cheongun.png") center/cover;
  border: 1px solid rgba(212,175,90,.55);
}
body.dj-on .msg.bot{
  margin-left: 0; margin-top: 22px;
  background: rgba(38,27,58,.90); border-color: rgba(190,170,225,.28);
  color: #efe7ff;
}
body.dj-on .msg.user{
  background: linear-gradient(135deg, rgba(151,127,191,.94), rgba(120,96,166,.94));
  color: #fff9ed;
}
body.dj-on .msg.system{ color: #cbb6f2; }

/* §9 — 보낸 시각. 대화 안 작은 보조 정보 — 굵기·크기 모두 본문보다 한참 낮춘다. */
body.dj-on .msg .dj-msg-time{
  display: block; margin-top: 4px;
  font-size: .6rem; line-height: 1; letter-spacing: .01em;
  opacity: .5;
}
body.dj-on .msg.user .dj-msg-time{ text-align: right; }

/* §23 — 무대 배경(base.jpg)에 인쇄된 큰 태극 문양이 채팅 가독성을 방해했다.
   그림을 새로 굽지 않고 무대 띠 안에 어두운 결을 한 겹 더해 문양만 죽인다(다른 상점은
   각자 다른 배경을 쓰거나 무대 위 절이 따로 있어 이 스코프 밖이다). */
body.dj-on .tj-stage{
  background-blend-mode: multiply;
  background-color: rgba(26,17,40,.34);
}

/* §6 — [청운이 흐름을 살피고 있어…] 작은 문구. 타이핑 점 바로 위, 카드처럼 무겁지 않게. */
/*  §10 — [청운이 흐름을 살피고 있어…] 카드. 일반 말풍선보다 얇게 · 반투명 Indigo ·
    작은 아이콘 · 아주 약한 glow(요청 문구 그대로). 로딩 점 셋은 옆에 붙는 기존 타이핑
    말풍선(addTyping, 공통 부품)이 그대로 맡는다 — 여기서 새로 만들지 않는다. */
body.dj-on .dj-sensing{
  display: flex; align-items: center; gap: 6px;
  align-self: flex-start; margin: 2px 0 2px 4px;
  padding: 5px 12px;
  border-radius: 999px;
  border: 1px solid rgba(151,127,191,.4);
  background: rgba(63,49,102,.38);
  box-shadow: 0 0 10px rgba(151,127,191,.22);
  font-size: .74rem; font-style: italic; color: #d8c9ef;
  animation: dj-sensing-pulse 1.8s ease-in-out infinite;
}
body.dj-on .dj-sensing::before{ content: "⌛"; font-style: normal; font-size: .82rem; }
@keyframes dj-sensing-pulse{ 0%,100%{ opacity:.72; } 50%{ opacity:1; } }
@media (prefers-reduced-motion: reduce){ body.dj-on .dj-sensing{ animation: none; opacity: .85; } }

/* ════════════════════════════════════════════════════════════════════
   밝은 도사집 AI 상담화면 — 2026-09-10 사람 지시 [도사집 청운 AI 상담화면 최종 디자인 교체]
   ────────────────────────────────────────────────────────────────────
   검보라·딥 네이비 판(위 절들)을 **이 절이 덮는다.** 위 절의 규칙은 지우지 않았다 —
   이 절을 통째로 지우면 옛 판으로 그대로 돌아간다(되돌리는 법).
   숫자는 지시서 §8~§22 가 준 값 그대로다(말풍선 .90~.96 · 모서리 18~22 · 입력창 .92~.97 ·
   모서리 26~30 · 사용자 #DCE8F6 · 글자 #25304A · 시간 10~11px/.45~.55 · 프로필 36~40px/1~1.5px 금테).
   그림 — 배경 `consult-bg.jpg`(에셋 A) · 기본 청운 `cheongun-consult-master.jpg`(에셋 B) ·
   프로필 `cheongun-consult-profile.jpg`(에셋 C) — 경로 정본은 shop-oracle.js `상담그림`.
   ★ 장식(벚꽃 파티클·달·마법진·별 애니메이션·빛 입자·고양이)은 넣지 않는다(§23) — 배경 그림에 이미 있다.
   ════════════════════════════════════════════════════════════════════ */
body.dj-on{
  --dj-ink: #25304A;                       /* §11·§13 짙은 남청 본문 */
  --dj-navy: #2B3A5C;                      /* 이름·아이콘 — 청운 의상 남청 */
  --dj-sub: rgba(37,48,74,.56);            /* 보조 글자 — 그레이블루 */
  --dj-line: rgba(222,198,176,.62);        /* 아주 옅은 피치 테두리 */
  --dj-gold-line: rgba(201,169,97,.5);     /* 샴페인 골드 얇은 선 */
  --dj-mist: 248,242,233;                  /* 청운 띠 ↔ 채팅 사이 아이보리 안개(§7 아주 약한 아이보리 오버레이) */
  /*  에셋 B(941x1672)는 영상(720x1280)과 비율이 같다(0.563) — 같은 object-position 이 둘에 같은 틀을 준다.
      에셋 B 실측(100px 격자): 머리끝 y≈236 · 눈 ≈480 · 입 ≈600 · 턱 ≈650 (영상 greeting-last 눈 ≈30% 와 거의 같은 높이).
      ★ 재보정(같은 날 2차 지시 §3) — 청운을 9% 키운다(아래 [청운 띠] 절 · 그림 상자 폭 109%).
      412x339(37%) 띠 · 배율 .477 기준 14% = 머리끝 48px(HUD 줄 12~48px 는 좌우 끝에만 있다) · 턱 245px ·
      어깨 ≈269px — 아래 18% 안개(278px~)보다 위에 온다. 머리 전체 + 얼굴 + 어깨 일부 + 창밖 야경. */
  --dj-face-y: 14%;
  background: #F5EDE2;
}
@media (max-height: 700px){
  /*  360x640: 띠 237px. 15% 는 머리끝 29px 라 [‹ 마을](y12~48)이 앞머리에 얹혔다(art-director 재판정 16).
      12% = 머리끝 ≈43 · 턱 ≈216 — 안개는 아래 [청운 띠] 절에서 짧은 화면만 10%(213px~)로 줄인다. */
  body.dj-on{ --dj-face-y: 12%; }
}
/*  ★ 2026-09-12 [청운 카메라/크기 완전 고정] — 키보드가 떠도 face-y 를 더는 바꾸지 않는다
    (옛 규칙 `body.dj-on.dj-kb-on{ --dj-face-y: 27%; }` 삭제). 청운은 같은 자리에 그대로
    앉아 있고, 공간이 부족하면 채팅 패널이 위로 겹쳐 올라온다(--dj-chat-top, §144). */
@media (min-aspect-ratio: 3/4){
  /*  펼친 폴드 — 위 §381 규칙이 영상을 0%(천장)로 붙였다. 새 청운은 그 값에서 머리 위 방만 보여
      얼굴이 안 들어온다. 영상·MASTER 를 **같은 변수**로 함께 내린다(§5 [같은 object-position]).
      그림 상자는 [청운 띠] 절에서 가운데 480px 로 줄인다 — 그 상자 기준 15% = 머리끝 40 · 턱 252. */
  body.dj-on{ --dj-face-y: 15%; }
  body.dj-on .tj-stage .tj-video,
  body.dj-on .tj-stage .tj-still,
  body.dj-on .tj-stage .tj-shot,
  body.dj-on .tj-stage .dj-master{ object-position: 46% var(--dj-face-y); }
}

/* ── 전체 배경 = 에셋 A (§6) ──────────────────────────────────────────
   premium-hud 의 흐린 원형 문양(reading-ui.css:94-104 · [중앙 워터마크])을 걷고 그 자리를 배경 그림으로 쓴다.
   높이는 `--dj-base-h`(키보드와 무관한 원래 화면 높이 · shop-oracle.js 뷰포트감시)로 고정 —
   키보드가 열려도 배경 배율이 안 바뀐다(§25 화면 점프 없음).
   `auto 128%` · 아래 붙임 = 그림의 넓은 아이보리 여백(원본 y 850~1450)이 채팅 자리에 온다.
   세로가 덜 긴 화면(가로/세로 > .72)에서는 그 값이 폭을 못 채우므로 cover 로 바꾼다. */
/*  ★ 아래에 붙인다(bottom:0) — 키보드가 뜨면 보이는 화면은 [원래 화면의 아래쪽]이 되어야 채팅 뒤가
      계속 아이보리다. 위에 붙였더니 키보드 ON 에서 채팅 뒤로 창밖 산·호수가 올라왔다(412x549 헤드리스 실측). */
body.dj-on.premium-hud::before{
  inset: auto 0 0 0; height: var(--dj-base-h, 100dvh);
  background: #F5EDE2 url("assets/village/shops/dosajip/consult-bg.jpg") 50% 100% / auto 128% no-repeat;
}
@media (min-aspect-ratio: 18/25){
  body.dj-on.premium-hud::before{ background-size: cover; background-position: 50% 72%; }
}
/*  원형 문양 자리 → 청운 띠 바로 아래 아이보리 안개 한 겹(채팅 첫 줄이 창틀·난간 위에 얹히지 않게). */
body.dj-on.premium-hud::after{
  left: 0; right: 0; bottom: auto; top: var(--dj-stage-h);
  width: auto; height: 76px; aspect-ratio: auto; transform: none;
  border: 0; border-radius: 0; box-shadow: none;
  background: linear-gradient(180deg, rgba(var(--dj-mist),.94) 0%, rgba(var(--dj-mist),.55) 55%, rgba(var(--dj-mist),0) 100%);
  z-index: 1;
}
@media (prefers-reduced-motion: no-preference){
  body.dj-on.premium-hud::after{ transition: top .28s ease; }
}

/* ── 청운 띠 (§4·§5) ───────────────────────────────────────────────── */
/*  옛 base.jpg(태극 문양)·곱하기 어둠을 걷는다 — 인라인(shop-stage.js)이라 !important. MASTER 가 떴을 때만. */
body.dj-on .tj-stage.has-master{
  background-image: none !important;
  background-color: #F5EDE2;
  background-blend-mode: normal;
}
/*  아랫단 — 검은 그라데이션(§63) 대신 아이보리 안개로 채팅과 잇는다. 검은 직선 경계 0(§4). */
/*  ★ 3차 [최종 UX 보정] §2 — 18% 도 넓었다(얼굴·목·어깨·의상 윗단에 걸림). 띠 끝(412 기준 원본 y≈847,
    가슴 윗단)에서 **9%(≈30px)만** 짧게 녹인다 — 412x339 에서 305px~ = 원본 y≈775 아래(쇄골·손 아래).
    얼굴·목·어깨는 한 픽셀도 안 덮는다. 청운 그림 자체의 opacity 는 늘 1 이다. */
body.dj-on .tj-stage::after{
  height: 9%; z-index: 1;
  background: linear-gradient(180deg, rgba(var(--dj-mist),0) 0%, rgba(var(--dj-mist),.5) 55%, rgba(var(--dj-mist),.92) 100%);
}
/*  짧은 화면(360x640 · 띠 237px)은 턱이 ≈216px 에 온다 — 8%(218px~)로 턱 아래에서만 녹인다.
    (같은 높이의 상태 pill 은 아래 [상태 표시] 절에서 물러난다.) */
@media (max-height: 700px){
  body.dj-on .tj-stage::after{ height: 8%; }
}
/*  ★ 3차 §1 [청운 표시 완전 고정] — 무대 카메라(shop-stage.js 카메라흔들기 · 시선두기)는 6.8초마다, 그리고
    상태가 thinking/serious 로 바뀔 때마다 `.tj-cam` 에 scale(1.035↔1.075)·translate 를 인라인으로 얹어 화면이
    당겨졌다 풀렸다 했다 — [상태가 바뀌면 카메라가 움직인 것처럼] 보이는 바로 그 원인이다. 도사방에서는 그
    변형을 그리지 않는다(함수·호출은 그대로 돈다 — 인라인이라 !important). 스틸의 숨결(scale 애니메이션)도 끈다.
    이제 MASTER·영상·스틸·컷은 같은 상자·같은 fit/position 에 **변형 0** 으로 선다. */
body.dj-on .tj-stage .tj-cam{
  transform: none !important;
  transition: none !important;
}
body.dj-on .tj-stage .tj-still,
body.dj-on .tj-stage .mood-layer{ animation: none !important; }
/*  채팅 윗단 — 띠 끝에서 말풍선이 칼로 자른 듯 잘렸다(art-director: 첫 줄 글자 반쪽 · 프로필 윗단).
    대화창 자체의 위 22px 를 투명→불투명으로 녹여, 굴러 올라가는 말이 청운 띠 쪽으로 스며들게 한다.
    청운 그림에는 아무것도 얹지 않는다(재보정 §2 — 페이드는 캐릭터↔채팅 연결부에만). */
body.dj-on #chat{
  padding-top: 22px; padding-bottom: 16px;   /* 맨 아래까지 굴렀을 때 마지막 말은 녹는 띠 밖에 선다 */
  /*  아랫단(추천질문·입력창과 닿는 곳)도 같은 이유로 14px 녹인다(art-director 재판정 — 17 셋째 줄 반쪽). */
  -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 22px, #000 calc(100% - 14px), transparent 100%);
          mask-image: linear-gradient(180deg, transparent 0, #000 22px, #000 calc(100% - 14px), transparent 100%);
}
/*  기본 청운 한 장 — 영상·스틸과 **같은 카메라 · 같은 크기 · 같은 fit/position**. 다른 것은 opacity 뿐.
    `data-mood-base="clip"` = 상태 영상이 실제로 화면을 덮은 순간(shop-mood.js 순간()) — 그때만 걷힌다.
    영상이 끝나 기분이 스틸로 내려앉으면(`still`) 다시 덮는다. 0.3초 opacity 만 — 검은 프레임이 끼지 않는다
    (걷히는 순간 밑에는 이미 불투명하게 덮인 영상이 있고, 돌아올 때는 영상 위로 덮는다). */
body.dj-on .tj-stage .dj-master{
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: 46% var(--dj-face-y);
  z-index: 6;                       /* 스틸(4)·기분 층(5) 위 — shop-tarojip.css:59 · shop-mood.css:9 */
  opacity: 1; transition: opacity .3s ease;
  pointer-events: none;
}
/*  ★ 재보정 §1 [청운이 흐려 보임] 원인 — 걷히는 시점이 너무 일렀다. 기분(shop-mood.js 순간())은 영상의
    인라인 opacity 가 "1" 이 되자마자 300ms 뒤 `clip` 을 적는데, 영상은 그때 CSS 로 0.9초에 걸쳐
    올라오는 중이라(shop-tarojip.css:58) 겨우 10~30% 만 불투명했다. 그 틈으로 뒤 바탕이 비쳐 청운 전체가
    흰 안개를 쓴 것처럼 보였다(2026-09-10 헤드리스 캡처 a2_3typed). 영상이 다 올라온 뒤(.6s 지연)에만 걷는다.
    돌아올 때(스틸로)는 지연 없이 바로 덮는다 — 전환은 여전히 opacity 하나뿐, 검은 프레임·레이아웃 점프 0. */
body.dj-on .tj-stage[data-mood-base="clip"] .dj-master{ opacity: 0; transition: opacity .3s ease .6s; }
/*  옛 의상 표정 컷은 MASTER 밑에서 **그리지만 않는다**(로직은 그대로 돈다). 안 가리면 영상이 도는
    순간에도 옛 표정 컷(z5)이 영상을 덮어 [상태 영상]이 안 보인다 — 영상이 온전히 보이게 한다.
    ★ 옛 스틸(.tj-still)은 가리지 않는다(재보정) — 영상이 올라오는 동안 뒤를 불투명하게 받치는 판이다. */
body.dj-on .tj-stage.has-master .mood-layer{ visibility: hidden; }
/*  ★ 2026-09-15 [청운 프리미엄화] §IDLE/LISTEN — 위 줄이 옛 표정 컷(mood-face)·입 컷(mood-talk)은
    그대로 가리되, 깜빡임 층(mood-blink)만 다시 보인다. 눈 감은 정지 사진 한 장(cheongun-blink.jpg)을
    MASTER 위로 잠깐 덮는 opacity 토글이라 스케일 변형이 없다 — §4 가 막는 [뭉개짐]과 무관하다.
    타이머·주기(shop-mood.js 깜빡예약)는 그대로 돈다 — 여기서는 안 보이던 것을 보이게만 한다. */
body.dj-on .tj-stage.has-master .mood-layer .mood-blink{
  visibility: visible; z-index: 7;   /* MASTER(z6) 위에 와야 실제로 덮인다 */
}
/*  ★ 재보정 §4 — MASTER 전체에 [카메라처럼] 크게 확대·축소하는 숨결은 걸지 않는다(합성 레이어가
    크게 늘어나면 눈·머리카락 잔선이 뭉개졌다 · 2026-09-10). 대신 §4 가 막지 않은 훨씬 작은 값 —
    shop-mood.css 의 mood-breathe 그대로(다른 두 캐릭터와 같은 진폭 공식 · 청운 --mood-amp 0.4 =
    스케일 0.32%)를 MASTER 한 장에만 건다. 이 폭에서 뭉개짐이 다시 보이면 이 규칙부터 지운다. */
@media (prefers-reduced-motion: no-preference){
  body.dj-on .tj-stage.has-master .dj-master{
    animation: mood-breathe 7.5s ease-in-out infinite;
  }
}
@media (prefers-reduced-motion: reduce){
  body.dj-on .tj-stage .dj-master{ transition: none; }
}
/*  ★ 재보정 §3 — 청운 9% 확대(지시 8~10%). 영상·스틸·컷·MASTER 가 **같은 상자**를 쓰도록 넷을 한꺼번에
    109% 폭으로 넓힌다(좌우 4.5% 씩 밖으로) — 전환 때 크기·자리가 안 바뀐다(1차 지시 §5).
    transform 을 쓰지 않는다: 스틸의 숨결·카메라(shop-stage.js 인라인 transform)와 자리를 다툰다. */
body.dj-on .tj-stage .tj-video,
body.dj-on .tj-stage .tj-still,
body.dj-on .tj-stage .tj-shot,
body.dj-on .tj-stage .dj-master,
body.dj-on .tj-stage .mood-face,
body.dj-on .tj-stage .mood-talk,
body.dj-on .tj-stage .mood-blink{
  inset: 0 auto 0 -4.5%; width: 109%; height: 100%;
}
/*  펼친 폴드(가로/세로 ≥ .75) — 전체 폭으로 깔면 배율이 .8 이 넘어 머리(330px)가 띠(308px)에 안 들어가고
    정수리가 잘렸다(art-director 2026-09-10 · 750x832). 그림 상자를 가운데 480px 로 줄여 머리 전체가 들어오게
    하고(배율 .51 · 머리끝 40 · 턱 252 · 안개 253~), 좌우 빈 곳은 배경 그림 A 가 받치며 상자 가장자리는
    48px 에 걸쳐 녹인다. 영상·스틸·컷·MASTER 가 같은 상자라 전환 규칙(같은 크기·같은 자리)은 그대로다. */
/*  ★ `:not(.dj-kb-on)` — 세로 폰도 키보드가 뜨면 보이는 화면이 411x544(.755)로 이 문턱을 넘는다. 그때 이 규칙이
    걸려 청운 상자가 가운데 480(=화면폭)으로 바뀌고 가장자리가 녹아 청운이 오른쪽으로 쏠렸다(v0.1.474 실기기).
    키보드는 화면을 넓힌 게 아니라 좁힌 것이다 — §381 규칙과 같은 이유로 뺀다. */
@media (min-aspect-ratio: 3/4){
  body.dj-on:not(.dj-kb-on) .tj-stage .tj-video,
  body.dj-on:not(.dj-kb-on) .tj-stage .tj-still,
  body.dj-on:not(.dj-kb-on) .tj-stage .tj-shot,
  body.dj-on:not(.dj-kb-on) .tj-stage .dj-master,
  body.dj-on:not(.dj-kb-on) .tj-stage .mood-face,
  body.dj-on:not(.dj-kb-on) .tj-stage .mood-talk,
  body.dj-on:not(.dj-kb-on) .tj-stage .mood-blink{
    inset: 0 auto 0 calc(50% - 240px); width: 480px; max-width: 100%;
    -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 48px, #000 calc(100% - 48px), transparent 100%);
            mask-image: linear-gradient(90deg, transparent 0, #000 48px, #000 calc(100% - 48px), transparent 100%);
  }
  body.dj-on:not(.dj-kb-on) .tj-stage.has-master{
    background: #F5EDE2 url("assets/village/shops/dosajip/consult-bg.jpg") 50% 22% / cover no-repeat !important;
  }
}

/* ── 청운 상태 표시 "● 청운 ✦ 상담 중" (§9) ──────────────────────────── */
body.dj-on .dj-status{
  position: fixed; z-index: 3;
  left: max(14px, calc(50% - var(--dj-col) / 2));
  top: calc(var(--dj-stage-h) - 32px);
  display: inline-flex; align-items: center; gap: 5px;
  height: 24px; padding: 0 10px 0 9px; box-sizing: border-box;
  border-radius: 999px;
  border: 1px solid rgba(201,169,97,.42);
  background: rgba(255,251,244,.8);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  box-shadow: 0 1px 6px rgba(37,48,74,.10);
  font-family: var(--vt-font-display); font-size: .68rem; line-height: 1;
  pointer-events: none;
}
body.dj-on .dj-status-dot{
  width: 6px; height: 6px; border-radius: 50%;
  background: #4CB782; box-shadow: 0 0 0 2px rgba(76,183,130,.18);
}
body.dj-on .dj-status b{ color: var(--dj-navy); font-weight: 700; }
body.dj-on .dj-status-star{ color: #C9A961; font-size: .6rem; }
body.dj-on .dj-status-text{ color: var(--dj-sub); }
/*  랜딩 동안·키보드가 열려 띠가 좁을 때는 얼굴을 가리지 않게 물러난다. */
body.dj-on.dj-landing .dj-status,
body.dj-on.dj-kb-on .dj-status{ display: none; }
/*  짧은 화면(360x640)은 pill 이 턱·첫 프로필과 부딪혔다(art-director 06 실측) — 키보드 ON 과 같은 이유로 뺀다. */
@media (max-height: 700px){ body.dj-on .dj-status{ display: none; } }
@media (prefers-reduced-motion: no-preference){ body.dj-on .dj-status{ transition: top .28s ease; } }

/* ── 상단 네비게이션 (§8) — 기능·자리는 그대로, 모양만 밝은 글래스로 ─────────── */
/*  랜딩(입구) 화면의 HUD 는 그 화면 절의 몫이라 건드리지 않는다 — 상담(채팅) 중에만. */
body.dj-on:not(.dj-landing) header.char-header{
  /*  상태바 글자가 읽힐 만큼만 — 머리끝(48px~)에 닿기 전에 0 이 된다(재보정 §2 [상단 전체를 덮지 않는다]). */
  height: calc(40px + env(safe-area-inset-top,0px));
  background: linear-gradient(180deg, rgba(37,48,74,.16), rgba(37,48,74,0));
  border-bottom: 0;
  -webkit-backdrop-filter: none; backdrop-filter: none;
}
body.dj-on.premium-hud:not(.dj-landing) .backhome,
body.dj-on.premium-hud:not(.dj-landing) .backhome.jelly,
body.dj-on.premium-hud:not(.dj-landing) .hud-info,
body.dj-on.premium-hud:not(.dj-landing) .bgm-chip,
body.dj-on.premium-hud.bgm-chip-on:not(.dj-landing) .bgm-chip{
  background: rgba(255,251,244,.74);
  border: 1px solid rgba(201,169,97,.55);
  color: var(--dj-ink);
  box-shadow: 0 2px 10px rgba(37,48,74,.12);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  text-shadow: none;
}
body.dj-on.premium-hud:not(.dj-landing) .backhome{ font-family: var(--vt-font-display); font-weight: 600; }
/*  🎵 이모지는 보라 네온으로 그려진다(§8 축소 대상) — 남청 선 음표로 바꾼다. 누르면 여는 창은 그대로. */
body.dj-on.premium-hud:not(.dj-landing) .bgm-chip::before{
  content: ""; width: 18px; height: 18px;
  background: center / contain no-repeat url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%232B3A5C' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9 17V6.2l10-2.2v11'/%3E%3Ccircle cx='6.6' cy='17' r='2.4' fill='%232B3A5C' fill-opacity='.16'/%3E%3Ccircle cx='16.6' cy='15' r='2.4' fill='%232B3A5C' fill-opacity='.16'/%3E%3C/svg%3E");
}
body.dj-on.premium-hud:not(.dj-landing) .hud-note{
  background: rgba(255,251,244,.95); color: var(--dj-ink);
  border: 1px solid rgba(201,169,97,.45);
  box-shadow: 0 6px 20px rgba(37,48,74,.14);
}

/* ── 대화 (§10~§15) ─────────────────────────────────────────────────── */
/*  §13 — 이미 번들된 둥근 한글 글꼴(Cafe24 Ssurround · village-typography.css `--vt-font-display`)을
    다시 쓴다. 새 글꼴 0. 한글 밖 글자(숫자·기호)는 그 파일의 unicode-range 가 맑은 고딕으로 넘긴다. */
/*  ★ 3차 §6 — 본문이 굵고 컸다. 크기 .96 → .9rem(−6%). 굵기는 **낮출 수 없다** — 이 글꼴은 파일이 한 벌
    (village-typography.css:30-35 가 400~700 을 그 한 파일로 받는다)이라 300 을 줘도 같은 획으로 그려진다
    (art-director 3차: 획 두께 불변 실측). 그래서 **보이는 무게**는 글자색을 한 단 풀어(#25304A → #3A4766)
    덜어낸다 — 흰 말풍선 위 대비 ≈9:1(본문 기준 4.5:1 의 두 배). 실제로 더 가늘게 하려면 본문 글꼴 교체뿐이다. */
body.dj-on #chat .msg.bot,
body.dj-on #chat .msg.user{
  font-family: var(--vt-font-display);
  font-size: .9rem; font-weight: 400; line-height: 1.55; letter-spacing: .01em;
  padding: 11px 15px 9px;
  color: #3A4766;
  word-break: keep-all; overflow-wrap: anywhere;
}
/*  청운 말풍선 — 오프화이트 · 짙은 남청 · 모서리 20(첫 말만 왼쪽 위 6 = 프로필 쪽을 가리키는 꼬리 대신) */
body.dj-on #chat .msg.bot{
  max-width: min(78%, 400px);
  margin-left: 46px; margin-top: 22px;
  border-radius: 6px 20px 20px 20px;
  border: 1px solid var(--dj-line);
  background: rgba(255,255,255,.93);
  box-shadow: 0 2px 10px rgba(37,48,74,.07);
}
/*  이름 — 말풍선 위 작은 남청 글자 */
body.dj-on #chat .msg.bot::before{
  content: "청운";
  left: 0; top: -18px;
  font-family: var(--vt-font-display);
  font-size: .66rem; font-weight: 700; letter-spacing: .02em;   /* 3차 §6 — 본문(.9)보다 확실히 작게 */
  color: var(--dj-navy);
}
/*  프로필 — 에셋 C 원형 38px · 1.5px 샴페인 골드 · 아주 약한 그림자(§10) */
body.dj-on #chat .msg.bot::after{
  left: -46px; top: -19px;
  width: 38px; height: 38px; box-sizing: border-box;
  border-radius: 50%;
  background: var(--dj-profile, url("assets/village/shops/dosajip/cheongun-consult-profile.jpg")) center / cover no-repeat;
  border: 1.5px solid rgba(201,169,97,.85);
  box-shadow: 0 2px 6px rgba(37,48,74,.14);
}
/*  같은 청운의 연속 말 = 한 묶음 — 프로필·이름은 첫 말에만, 간격은 좁게(§10 과하게 반복하지 않는다). */
body.dj-on #chat .msg.bot + .msg.bot{ margin-top: -6px; border-top-left-radius: 20px; }
body.dj-on #chat .msg.bot + .msg.bot::before,
body.dj-on #chat .msg.bot + .msg.bot::after{ display: none; }
/*  손님 말풍선 — 연한 블루 · 오른쪽 · 프로필 없음(§12) */
body.dj-on #chat .msg.user{
  max-width: min(78%, 400px);
  border-radius: 20px 20px 6px 20px;
  border: 1px solid rgba(120,150,190,.22);
  background: #DCE8F6;
  box-shadow: 0 2px 8px rgba(37,48,74,.06);
}
body.dj-on #chat .msg.user + .msg.user{ margin-top: -6px; border-bottom-right-radius: 20px; }
body.dj-on #chat .msg.system{ color: var(--dj-sub); }
/*  시간 — 보조 정보(§14 10~11px · .45~.55). 같은 사람이 이어 말하면 마지막 말에만 남긴다. */
body.dj-on #chat .msg .dj-msg-time{
  font-family: var(--vt-font-body);
  font-size: .62rem; margin-top: 3px; opacity: .45; color: inherit;   /* 3차 §6 — 가장 낮은 위계 */
}
body.dj-on #chat .msg.bot:has(+ .msg.bot:not(.typing-msg)) .dj-msg-time,
body.dj-on #chat .msg.user:has(+ .msg.user) .dj-msg-time{ display: none; }

/*  생각 중(§15) — 프로필 옆 작은 밝은 말풍선 + 점 셋(공통 addTyping 그대로) · 그 밑 한 줄 문구 */
body.dj-on #chat .msg.bot.typing-msg{ padding: 13px 16px; }
body.dj-on #chat .msg.bot.typing-msg .typing span{ background: rgba(58,76,110,.45); }
body.dj-on #chat .dj-sensing{
  align-self: flex-start;
  margin: -6px 0 0 50px; padding: 0;
  border: 0; border-radius: 0; background: none; box-shadow: none;
  font-family: var(--vt-font-display); font-size: .72rem; font-style: normal;
  color: rgba(58,76,110,.66);
}
body.dj-on #chat .dj-sensing::before{ content: none; }

/* 면책 한 줄 · 신고 줄 · 선택지 — 밝은 바탕에서 읽히게(safety-gate.css 가 뒤에 실려 선택자를 한 단 세게) */
body.dj-on #chat .sg-disclaimer{
  color: rgba(37,48,74,.62);
  background: rgba(255,255,255,.55);
  border: 1px solid rgba(222,198,176,.45);
}
body.dj-on #chat .sg-report{ margin-left: 50px; color: var(--dj-sub); }
body.dj-on #chat .sg-report button{
  color: rgba(37,48,74,.62); border-color: rgba(37,48,74,.2); background: rgba(255,255,255,.5);
}
/*  ★ 2026-09-12 3차[VISUAL DENSITY 정리] §3·§4 — 버튼이 4개 넘게 뜰 때도 전부 같은 무게로
    안 보이게 한다. PRIMARY(조금 더 물어볼래)·SECONDARY(오늘 신점 저장·기본 모양) 두 칸을
    한 줄에, TERTIARY(공유·마을로·조건부 안내)는 더 작게 두 칸씩 — 버튼이 몇 개든 세로로만
    늘고 가로 폭은 항상 2열이라 입력칸이 아래로 밀리지 않는다(§4). */
body.dj-on #chat .choices{ margin-left: 46px; display: flex; flex-wrap: wrap; gap: 8px; }
body.dj-on #chat .choices button{
  flex: 1 1 calc(50% - 4px);
  border: 1px solid rgba(201,169,97,.5);
  background: #FBF6EC; color: var(--dj-ink);
  font-family: var(--vt-font-display); font-size: .84rem;
  box-shadow: 0 2px 6px rgba(37,48,74,.06);
}
/* 1.1.2 — 광고 버튼은 반 칸(50%)에 글이 두세 줄로 접혔다 → 한 줄 · 가로 전체 */
body.dj-on #chat .choices button.choice-ad{ flex: 1 1 100%; white-space: nowrap; justify-content: center; }
body.dj-on #chat .choices button:hover,
body.dj-on #chat .choices button:active{ background: #F3EADB; color: var(--dj-ink); }
body.dj-on #chat .choices button.choice-primary{
  border-color: rgba(201,169,97,.75);
  background: linear-gradient(180deg, rgba(233,199,123,.4), rgba(233,199,123,.22));
  color: var(--dj-navy); font-weight: 700;
  box-shadow: 0 3px 10px rgba(201,169,97,.22);
}
body.dj-on #chat .choices button.choice-primary:hover,
body.dj-on #chat .choices button.choice-primary:active{
  background: linear-gradient(180deg, rgba(233,199,123,.5), rgba(233,199,123,.3));
}
body.dj-on #chat .choices button.choice-tertiary{
  min-height: 36px; padding: 0 10px;
  font-size: .76rem; font-weight: 400;
  background: rgba(255,255,255,.4);
  border-color: rgba(190,170,225,.3);
  box-shadow: none;
  color: var(--dj-sub);
}
body.dj-on #chat .choices button.choice-tertiary:hover,
body.dj-on #chat .choices button.choice-tertiary:active{ background: rgba(255,255,255,.65); }
/*  9차[PREMIUM CONSULTATION FINALE] §11 — QUIET([마을로 돌아가기] 전용). tertiary보다 한 단
    더 가라앉는다 — 테두리·배경 없이 글자만, 밑줄로만 [버튼이다]를 알린다. §31 터치 타깃(최소
    44px)은 유지한다(padding으로 높이를 채운다, 글자를 작게 만들지 않는다). */
body.dj-on #chat .choices button.choice-quiet{
  flex: 1 1 100%;
  min-height: 44px; padding: 6px 10px;
  font-size: .78rem; font-weight: 400;
  background: transparent; border: none; box-shadow: none;
  color: var(--dj-sub);
  text-decoration: underline; text-underline-offset: 3px;
  text-decoration-color: rgba(37,48,74,.28);
}
body.dj-on #chat .choices button.choice-quiet:hover,
body.dj-on #chat .choices button.choice-quiet:active{ color: var(--dj-ink); }

/* ── 출생정보 카드 (3차 [최종 UX 보정] §3·§4) ─────────────────────────────────────
   birth-form.js 의 폼(사주집 공용)을 도사방 말풍선과 같은 재질의 카드로. 이 화면은 saju.css 를 안 싣기 때문에
   지금까지 브라우저 기본 입력칸·체크박스·라디오가 그대로 드러났다. DOM 은 shop-oracle.js 생일카드다듬기()가
   단위 글자만 감쌌을 뿐 — 입력칸·name·value 는 그대로다. 모든 입력 컨트롤 = 높이 44 · 둥근 알약(§4 통일). */
body.dj-on #chat .birth-form{
  align-self: stretch; box-sizing: border-box;
  margin: 4px 0 6px; padding: 16px 16px 14px;
  display: flex; flex-direction: column; gap: 8px;
  border-radius: 22px;
  border: 1px solid rgba(201,169,97,.42);
  background: rgba(255,255,255,.94);
  box-shadow: 0 4px 16px rgba(37,48,74,.08);
  color: #2F3B58; font-family: var(--vt-font-display);
}
body.dj-on #chat .birth-form .saju-icon{ display: none; }   /* 사주집 태극 아이콘 — 도사방 카드에는 안 쓴다 */
body.dj-on #chat .birth-form .birth-intro{
  margin: 0 0 2px; text-align: left;
  font-size: .9rem; line-height: 1.5; color: #3A4766;
}
body.dj-on #chat .birth-form .dj-bf-label,
body.dj-on #chat .birth-form .birth-gender legend{
  margin: 6px 0 0; padding: 0;
  font-size: .72rem; font-weight: 700; letter-spacing: .02em; color: var(--dj-navy);
}
body.dj-on #chat .birth-form .birth-row{ display: flex; gap: 8px; }
body.dj-on #chat .birth-form .birth-row label{
  flex: 1 1 0; min-width: 0; box-sizing: border-box;
  display: flex; align-items: center; gap: 3px;
  height: 44px; padding: 0 14px 0 12px;
  border-radius: 999px;
  border: 1px solid rgba(222,198,176,.85);
  background: #FFFDF8;
  font-size: .82rem; color: var(--dj-sub);
}
body.dj-on #chat .birth-form .dj-bf-date label:first-child{ flex-grow: 1.45; }   /* 네 자리 연도 칸만 조금 넓게 */
body.dj-on #chat .birth-form .birth-row label:focus-within{
  border-color: rgba(201,169,97,.85);
  box-shadow: 0 0 0 3px rgba(201,169,97,.16);
}
body.dj-on #chat .birth-form .birth-row input{
  flex: 1 1 auto; min-width: 0; width: 100%;
  margin: 0; padding: 0; border: 0; outline: none; background: transparent; box-shadow: none;
  font: inherit; font-family: var(--vt-font-display); font-size: .95rem; color: #25304A;
  text-align: right;
  -moz-appearance: textfield; appearance: textfield;
}
body.dj-on #chat .birth-form .birth-row input::-webkit-outer-spin-button,
body.dj-on #chat .birth-form .birth-row input::-webkit-inner-spin-button{ -webkit-appearance: none; margin: 0; }
body.dj-on #chat .birth-form .birth-row input::placeholder{ color: rgba(58,76,110,.36); }
body.dj-on #chat .birth-form .dj-bf-unit{ flex: 0 0 auto; }
/*  시간 모름 — 시·분 칸이 잠긴 것이 한눈에 보이게 */
body.dj-on #chat .birth-form.dj-bf-notime .dj-bf-time label{ background: #F3EEE6; border-style: dashed; opacity: .5; }
/*  잠긴 칸에 예시(14·30)가 남으면 [14:30 으로 고정됐다]로 읽힌다(art-director 3차) — 잠기면 예시를 지운다. */
body.dj-on #chat .birth-form.dj-bf-notime .dj-bf-time input::placeholder{ color: transparent; }
/*  [태어난 시간을 몰라요] — 기본 체크박스 모양을 걷고 같은 높이의 알약 토글로 */
body.dj-on #chat .birth-form .birth-checkbox{
  align-self: flex-start; box-sizing: border-box;
  display: inline-flex; align-items: center; gap: 8px;
  height: 44px; padding: 0 16px 0 12px;
  border-radius: 999px;
  border: 1px solid rgba(222,198,176,.85);
  background: #FFFDF8;
  font-size: .82rem; color: #2F3B58; cursor: pointer;
}
body.dj-on #chat .birth-form .birth-checkbox input{
  -webkit-appearance: none; appearance: none;
  flex: 0 0 auto; width: 18px; height: 18px; margin: 0;
  border-radius: 50%; border: 1.5px solid rgba(58,76,110,.45); background: #fff;
}
body.dj-on #chat .birth-form .birth-checkbox input:checked{
  border-color: #2B3A5C; background: #2B3A5C; box-shadow: inset 0 0 0 3px #fff;
}
body.dj-on #chat .birth-form .birth-checkbox:has(input:checked){
  background: #E3ECF7; border-color: rgba(43,58,92,.45); color: #1F3450;
}
/*  성별 — 라디오는 그대로 두고(값·name 유지) 모양만 숨긴다. 라벨 전체가 [남성][여성] 세그먼트 버튼이다. */
body.dj-on #chat .birth-form .birth-gender{
  margin: 0; padding: 0; border: 0; min-width: 0;
  display: grid; grid-template-columns: 1fr 1fr; gap: 8px;
}
body.dj-on #chat .birth-form .birth-gender legend{ margin-bottom: 8px; }
body.dj-on #chat .birth-form .birth-gender label{
  position: relative; box-sizing: border-box;
  display: flex; align-items: center; justify-content: center;
  height: 44px; border-radius: 999px;
  border: 1px solid rgba(222,198,176,.85);
  background: #FFFDF8;
  font-size: .88rem; color: #2F3B58; cursor: pointer;
}
body.dj-on #chat .birth-form .birth-gender input{
  position: absolute; width: 1px; height: 1px; margin: 0; opacity: 0; pointer-events: none;
}
body.dj-on #chat .birth-form .birth-gender label:has(input:checked){
  background: #DCE8F6; color: #1F3450; font-weight: 700;
  border: 1.5px solid rgba(201,169,97,.85);
}
body.dj-on #chat .birth-form .birth-gender label:has(input:focus-visible){
  box-shadow: 0 0 0 3px rgba(43,58,92,.18);
}
/*  CTA — 기존 제출 버튼 그대로(type=submit). 모양만 남청 알약. */
body.dj-on #chat .birth-form .birth-submit{
  -webkit-appearance: none; appearance: none;
  margin-top: 6px; width: 100%; height: 48px; box-sizing: border-box;
  border: 0; border-radius: 999px;
  background: linear-gradient(180deg, #34446A, #27345A);
  color: #FFF9EE; font-family: var(--vt-font-display); font-size: .95rem; font-weight: 700; letter-spacing: .02em;
  box-shadow: 0 3px 10px rgba(39,52,90,.25);
  cursor: pointer;
}
body.dj-on #chat .birth-form .birth-submit:active{ transform: translateY(1px); }
body.dj-on #chat .birth-form .birth-submit:disabled{ opacity: .55; }
body.dj-on #chat .birth-form .birth-error{ margin: 0; font-size: .78rem; color: #B4553F; }
body.dj-on #chat .birth-form .birth-error.hidden{ display: none; }
/*  §5 — 카드에 적는 동안은 아래 채팅 바(보기 칩·입력창·무료 배지)를 잠시 걷는다. 이때 입력창은 이미
    `.hidden`(청운 차례 · shop-oracle.js 입력칸닫기) 상태라 **쓸 수 없는 칸이 자리만 차지**하고 있었다 —
    걷으면 카드가 그만큼 넓은 자리를 얻고 키보드가 떠도 입력칸과 겹칠 일이 없다. 카드가 사라지면 그대로 돌아온다. */
body.dj-on:has(#chat form.birth-form) .dj-bottom{ display: none; }

/* [오늘 청운이 본 흐름] · [신점 카드] — 밝은 카드로 */
body.dj-on .dj-summary{
  background: rgba(255,252,246,.95);
  border: 1px solid rgba(201,169,97,.45);
  box-shadow: 0 6px 18px rgba(37,48,74,.10);
}
body.dj-on .dj-summary h3{ color: var(--dj-navy); font-family: var(--vt-font-display); }
body.dj-on .dj-summary-lead{ color: var(--dj-ink); font-family: var(--vt-font-display); }
body.dj-on .dj-summary dt{ color: var(--dj-sub); font-family: var(--vt-font-display); }
body.dj-on .dj-summary dd,
body.dj-on .dj-summary li{ color: var(--dj-ink); }
body.dj-on .dj-summary-quote{ border-top-color: rgba(201,169,97,.35); color: var(--dj-navy); font-family: var(--vt-font-display); }
body.dj-on .dj-insight{
  background: rgba(255,255,255,.84);
  border: 1px solid var(--dj-line);
}
body.dj-on .dj-insight-head{ color: var(--dj-navy); font-family: var(--vt-font-display); }
body.dj-on .dj-insight p{ color: var(--dj-ink); }

/* ── 아래 바 — 보기 칩 · 빠른 질문 · 입력창 · 무료 배지 (§16~§22) ─────────────── */
body.dj-on .dj-bottom{
  background: linear-gradient(180deg, rgba(var(--dj-mist),0) 0%, rgba(var(--dj-mist),.8) 30%, rgba(var(--dj-mist),.9) 100%);
  padding-bottom: calc(env(safe-area-inset-bottom, 0px) + 6px);   /* §22 광고와 한 숨 띄운다 */
  /* 2026-09-13 [긴급 회귀 조사] — 여기 있던 `position: relative;` 가 172행의 진짜 배선
     (`position: fixed; bottom: var(--banner-ad-height,0px);`)을 같은 특이성·더 늦은 순서로
     덮어써, `.dj-bottom`(칩·입력창·무료배지)이 뷰포트 하단이 아니라 DOM 순서상 위치(HERO
     바로 아래)에 그대로 눌러앉아 청운 얼굴을 큰 반투명 띠로 덮는 회귀였다(실측 — 지우면
     즉시 172행의 fixed/bottom 값으로 복귀해 10차 확정 구조로 돌아온다). `::after` 금색 선은
     `position:fixed` 도 이미 유효한 포지셔닝 컨텍스트라 이 줄이 없어도 그대로 동작한다. */
}
/*  ★ 2026-09-12 3차[VISUAL DENSITY 정리] §9 — 광고(WebView 아래 겹치는 네이티브 뷰)가
    상담 UI 의 일부처럼 안 붙어 보이게, 그 경계에 아주 옅은 금색 실선 하나만 긋는다.
    광고 크기·배치 자체는 안 건드린다(ads.js 그대로). */
body.dj-on .dj-bottom::after{
  content: ""; position: absolute; left: 16px; right: 16px;
  bottom: calc(env(safe-area-inset-bottom, 0px) + 6px);
  height: 1px; background: rgba(201,169,97,.16);
  pointer-events: none;
}
/*  §238 의 좌우 여백 `max(16px, calc(50% - col/2))` 은 [폭 520 상자 + 가운데 정렬]과 겹쳐 두 번 가운데로
    몰았다 — 펼친 폴드(750)에서 칩이 x230 부터 290px 폭에 갇혔다(2026-09-10 실측, 옛 판부터 있던 것).
    상자가 이미 가운데 520 이므로 안쪽 여백은 빠른 질문 줄·입력창과 같은 12px 로 맞춘다. */
/*  ★ 재보정 §7 — 고정 메뉴 줄이 빠진 자리: [추천질문 → 적절한 여백 → 입력창]. 아래 10px 가 그 여백이다. */
body.dj-on .dj-chips.has{ padding: 8px 12px 10px; }
body.dj-on .dj-chip-q{
  border-color: var(--dj-line);
  background: rgba(255,255,255,.72);
  color: var(--dj-navy);
}
body.dj-on .dj-chips button{
  border: 1px solid rgba(201,169,97,.42);
  background: rgba(255,255,255,.86);
  color: var(--dj-ink);
  font-family: var(--vt-font-display);
}
body.dj-on .dj-chips button:active{ background: #F3EADB; }
body.dj-on .dj-chips:not(.has-q) button{
  min-height: 40px; padding: 0 14px;
  background: rgba(255,255,255,.74);
  border-color: rgba(201,169,97,.5);
  font-weight: 400;
}
/*  3차 §6 — 추천질문도 말풍선과 같은 계층: 같은 글꼴·같은 색, 본문(.9)보다 한 단 작게. */
body.dj-on .dj-chips button,
body.dj-on .dj-chips.has-q button{ font-size: .82rem; font-weight: 400; color: #3A4766; }
body.dj-on .dj-chip-q{ font-size: .74rem; font-family: var(--vt-font-display); }
/*  빠른 질문 줄 — 웜 아이보리 알약 · 얇은 피치/샴페인 선 · 남청 글자 · 높이 40(§16 38~44).
    좁으면 가로로 민다(글자를 줄이지 않는다). 입력칸이 닫힌 동안은 같이 숨는다. */
body.dj-on .dj-quick{
  display: flex; gap: 6px;
  max-width: var(--dj-col); margin: 0 auto;
  padding: 4px 12px 6px; box-sizing: border-box;
  overflow-x: auto; overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch; scrollbar-width: none;
}
body.dj-on .dj-quick::-webkit-scrollbar{ display: none; }
body.dj-on .dj-bottom:has(#composer.hidden) .dj-quick{ display: none; }
/*  청운이 방금 물은 것에 답하는 칩(has-q)이 떠 있으면 그쪽이 먼저다 — 두 줄을 겹겹이 쌓아 채팅을
    1/3 로 줄이지 않는다(412x915 실측: 칩 카드+빠른 질문+입력창 = 262px). 빠른 질문은 [첫 말 꺼내기] 자리다. */
body.dj-on .dj-bottom:has(.dj-chips.has-q) .dj-quick{ display: none; }
/*  §25 키보드 ON — 띠가 17% 로 줄고 남는 높이가 절반이 된다. 빠른 질문 줄·무료 배지까지 얹으면 채팅이
    한 줄도 안 남는다(412x549 실측: 채팅 110px). 글을 쓰는 동안에는 둘 다 잠시 물러난다. */
body.dj-on.dj-kb-on .dj-quick,
body.dj-on.dj-kb-on .dj-free-badge{ display: none; }
/*  짧은 화면(360x640)·키보드 ON — 보기 칩이 한 줄에 하나씩 세 줄로 쌓여(412·360 실측) 채팅이 한 줄만 남았다.
    칩 줄을 **가로로 미는 한 줄**로 바꾼다. 글자는 줄이지도 자르지도 않는다(§14 [말줄임 안 씀] 그대로 —
    칩마다 문구 전체가 보이고, 넘치는 칩은 옆으로 밀어 본다). */
@media (max-height: 700px){
  body.dj-on .dj-chip-grid{ flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; overscroll-behavior-x: contain; }
  body.dj-on .dj-chip-grid::-webkit-scrollbar{ display: none; }
  body.dj-on .dj-chips button{ flex: 0 0 auto; white-space: nowrap; }
}
body.dj-on.dj-kb-on .dj-chip-grid{ flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; overscroll-behavior-x: contain; }
body.dj-on.dj-kb-on .dj-chip-grid::-webkit-scrollbar{ display: none; }
body.dj-on.dj-kb-on .dj-chips button{ flex: 0 0 auto; white-space: nowrap; }
body.dj-on .dj-quick-btn{
  flex: 0 0 auto;
  display: inline-flex; align-items: center; gap: 4px;
  height: 40px; min-height: 40px; padding: 0 12px 0 9px; box-sizing: border-box;
  border-radius: 999px;
  border: 1px solid rgba(214,180,140,.55);
  background: linear-gradient(180deg, #FFFCF6, #FAF2E4);
  color: var(--dj-ink);
  font: inherit; font-family: var(--vt-font-display); font-size: .82rem; line-height: 1;
  white-space: nowrap; cursor: pointer;
  box-shadow: 0 1px 4px rgba(37,48,74,.06);
  transition: transform .12s ease, background .12s ease;
}
body.dj-on .dj-quick-btn img{ width: 20px; height: 20px; object-fit: contain; flex: 0 0 auto; }
body.dj-on .dj-quick-btn:active{ transform: scale(.97); background: #F3EADB; }
/*  입력창 — 밝은 떠 있는 카드(§18) */
body.dj-on #composer{
  box-sizing: border-box;
  width: calc(100% - 24px); max-width: var(--dj-col); margin: 0 auto;
  min-height: 52px; padding: 5px 6px 5px 18px; gap: 6px;
  border-radius: 28px;
  border: 1px solid rgba(222,198,176,.78);
  background: rgba(255,255,255,.95);
  box-shadow: 0 4px 16px rgba(37,48,74,.10);
}
/*  3차[VISUAL DENSITY 정리] §7 — glow 를 한 단 줄인다(18px→12px · 3px 링→2px, 옅게) —
    입력창은 항상 있는 요소라 너무 튀면 결과카드·대화보다 시선을 먼저 끈다. */
body.dj-on #composer:focus-within{
  border-color: rgba(201,169,97,.7);
  box-shadow: 0 3px 12px rgba(37,48,74,.10), 0 0 0 2px rgba(201,169,97,.11);
}
/*  위 §360 의 왼쪽 64px 는 소리 위젯(좌하단) 자리였다 — 상담 중에는 그 위젯이 숨어(§225) 빈칸만 남았다. */
@media (max-width: 600px){
  body.dj-on:not(.dj-landing) #composer{ padding-left: 18px; }
}
body.dj-on #user-input{
  color: #2F3B58;
  font-family: var(--vt-font-display); font-size: .9rem;   /* 3차 §6 — 말풍선 본문과 같은 크기 */
  /*  ★ 재보정 §8 — 버튼 둘은 입력칸 **안에 겹쳐 뜬 것이 아니라** 옆 칸(flex 형제)이라 글이 그 밑으로 들어갈
      수는 없다. 다만 글 끝이 소리 버튼 테두리에 딱 붙어 [밑으로 들어간 것]처럼 보였다(a2_3typed) —
      글 칸 오른쪽에 숨 쉴 자리를 준다. `#composer` gap 6px + 이 10px = 버튼까지 16px. */
  padding: 8px 10px 8px 2px;
  text-overflow: ellipsis;
}
/*  실기기 WebView 가 포커스된 입력칸에 네모난 기본 테두리를 한 겹 더 그렸다(v0.1.459 실측) — 포커스 표시는
    바깥 카드(#composer:focus-within 금빛 테두리)가 이미 맡는다. */
body.dj-on #user-input:focus{ text-overflow: clip; outline: none; }
body.dj-on #user-input::placeholder{ color: rgba(37,48,74,.42); }
/*  소리 버튼(§19 — 입력창 오른쪽 작은 원형 · 아이보리 · 남청 아이콘). 누르면 하는 일은 그대로. */
body.dj-on .dj-audio-ico{
  width: 40px; height: 40px; min-width: 40px; min-height: 40px; padding: 0;
  border-radius: 50%;
  border: 1px solid rgba(222,198,176,.85);
  background: #F7F0E3; color: var(--dj-navy);
}
body.dj-on .dj-audio-ico:active{ background: #EFE4D2; }
/*  전송 버튼(§20) — 청운 의상 남청 원형 · 아이보리 아이콘 · 빈 입력이면 disabled(기존 배선) 그대로 */
body.dj-on #send-btn{
  background: linear-gradient(180deg, #34446A, #27345A);
  box-shadow: 0 2px 8px rgba(39,52,90,.28);
}
body.dj-on #send-btn::before{
  content: "";
  background: center / 19px 19px no-repeat url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M4.6 11.2 18.7 5.1c.8-.3 1.5.4 1.2 1.2l-6.1 14.1c-.3.8-1.5.7-1.7-.1l-1.4-5.3-5.4-1.4c-.8-.2-.9-1.4-.1-1.7z' fill='%23FFF9EE'/%3E%3C/svg%3E");
}
body.dj-on #send-btn:not(:disabled){ box-shadow: 0 2px 8px rgba(39,52,90,.30); }
body.dj-on #send-btn:disabled{ opacity: .35; box-shadow: none; }
/*  오늘 무료 상담 — 작은 알약(§21) · 글은 실제 상태에서(shop-oracle.js 무료배지갱신)
    ★ 2026-09-12 3차[VISUAL DENSITY 정리] §8 — 상태 정보일 뿐이니 대비를 한 단 낮춘다
    (테두리·배경을 더 옅게, 글자색도 채도를 낮춰). 기능·문구는 그대로. */
body.dj-on .dj-free-badge{
  display: table; margin: 6px auto 0; padding: 3px 11px;
  border-radius: 999px;
  border: 1px solid rgba(201,169,97,.3);
  background: rgba(255,250,240,.55);
  color: rgba(138,106,46,.72);
  font-family: var(--vt-font-display); font-size: .62rem; letter-spacing: .01em;
}

/* ════════════════════════════════════════════════════════════════════
   8차[PREMIUM SPACE FINAL IMPLEMENTATION] (2026-09-12) — 공간 연출만.
   ────────────────────────────────────────────────────────────────────
   AMBIENT LIGHT · STATE LIGHTING · FOREGROUND · 시그니처 오브젝트 넷.
   5~7차(상담 엔진·FIRST HIT·재방문 기억)는 이 절에서 한 줄도 안 건드린다 — 전부 새 선택자고,
   전부 shop-oracle.js `깊이층세우기()`(DOM 만 놓는다)가 만든 새 요소에만 붙는다.
   §6 [카메라 완전 고정] — 이 절의 무엇도 .tj-cam·.tj-video·.tj-still·.dj-master 의 크기·자리·
   transform 을 안 건드린다. 그 위·아래에 얇게 겹칠 뿐이다.
   ════════════════════════════════════════════════════════════════════ */

/* ── 공통 상자 — 캐릭터 층과 같은 상자(109%/-4.5%)를 그대로 물려받는다.
   이래야 좌우 좌표(x%)가 캐릭터·영상과 같은 기준으로 맞는다(§6 [같은 카메라]). */
body.dj-on .tj-stage .dj-ambient,
body.dj-on .tj-stage .dj-foreground,
body.dj-on .tj-stage .dj-state-scrim{
  position: absolute; inset: 0 auto 0 -4.5%; width: 109%; height: 100%;
  pointer-events: none;
}

/* ── LAYER 2 — AMBIENT LIGHT (§8·§9) ────────────────────────────────
   실측 좌표 — `assets\village\shops\dosajip\consult-bg.jpg`(941x1672)에 격자를 그어 직접 쟀다.
   위 띠(청운 크롭)가 보여주는 원본 범위는 8%~50.5%(object-position-y 14~15% · object-fit:cover ·
   109% 폭 기준 역산) — 그 안에 좌우 등불 전신과 달이 전부 들어온다. 그 자리에 radial-gradient
   만 얹는다 — 새 그림·파티클 0개(§9 금지 목록: 금가루·별가루·마법진·lens flare 전부 안 씀). */
body.dj-on .tj-stage .dj-ambient{ z-index: 7; }
body.dj-on .tj-stage .dj-amb-glow{
  position: absolute; border-radius: 50%;
  mix-blend-mode: screen;    /*  색을 덮지 않고 밝기만 더한다 — 얼굴 톤이 안 바뀐다(§11) */
  opacity: .5;
}
body.dj-on .tj-stage .dj-amb-lantern-l,
body.dj-on .tj-stage .dj-amb-lantern-r{
  top: 4%; width: 15%; height: 46%;
  background: radial-gradient(closest-side, rgba(255,196,110,.30), rgba(255,196,110,0) 72%);
}
body.dj-on .tj-stage .dj-amb-lantern-l{ left: -3%; }
body.dj-on .tj-stage .dj-amb-lantern-r{ right: -3%; }
body.dj-on .tj-stage .dj-amb-moon{
  left: 58%; top: 9%; width: 16%; height: 16%;
  background: radial-gradient(closest-side, rgba(210,222,255,.26), rgba(210,222,255,0) 70%);
}
/*  좌우 등불이 같은 박자로 숨 쉬면 [효과가 들어갔다]로 바로 읽힌다(§9) — 3.2초 어긋낸다.
    주기도 9~12초로 길게 잡아 "화면이 왜인지 살아 있다" 선에서 멈춘다(§8 목표). */
@media (prefers-reduced-motion: no-preference){
  body.dj-on .tj-stage .dj-amb-lantern-l{ animation: dj-amb-lantern 9s ease-in-out infinite; }
  body.dj-on .tj-stage .dj-amb-lantern-r{ animation: dj-amb-lantern 9s ease-in-out infinite 3.2s; }
  body.dj-on .tj-stage .dj-amb-moon{ animation: dj-amb-moon 12s ease-in-out infinite; }
}
@keyframes dj-amb-lantern{ 0%,100%{ opacity: .42; } 50%{ opacity: .55; } }   /* §8-A·B 등불 ±2~3%·느린 변화 */
@keyframes dj-amb-moon{ 0%,100%{ opacity: .20; } 50%{ opacity: .30; } }      /* §8-D 달 주변 미세한 호흡 */
/*  §8-C 창밖 마을빛·§8-E 벚꽃 움직임은 넣지 않았다 — 완료 보고 §8·§14 [남은 한계]에 이유를 적는다. */

/* ── LAYER 4 — FOREGROUND DEPTH (§4~§7) ─────────────────────────────
   같은 원판을 한 번 더 부른다(`consult-bg.jpg` — 새 이미지 0장, 이미 `body::before` 가 읽어
   브라우저 캐시에 있다). 청운 띠 맨 아래 9%만 그 원판의 **맨 아랫단**(bottom-anchored cover)을
   보여 준다 — 원판 속 돗자리 가장자리·염주 술 끝이 있는 바로 그 자리다.
   ★ §5 [손·얼굴·목·어깨 가림 금지] — 이 9%는 지금 카메라(§6 고정 · object-position-y 14~15%)
   에서 **이미 화면 밖인 구간**이다(청운 손은 원본 y≈69~75%, 이 띠는 91~100%만 보여준다) —
   가릴 손이 애초에 이 자리에 없다. 그래서 [허벅지/무릎/하단 video edge] 요구를 [손보다 훨씬
   아래, 화면에 없던 자리를 슬쩍 채운다]로 만족시킨다 — 청운을 축소하거나 내리지 않고(§6). */
body.dj-on .tj-stage .dj-foreground{
  top: auto; bottom: 0; height: 9%;
  overflow: hidden; z-index: 7;
  object-fit: cover; object-position: 46% 100%;
  filter: brightness(.88) saturate(.92);     /* 살짝 그늘 — [카메라에 더 가깝다]는 느낌만 */
  -webkit-mask-image: linear-gradient(180deg, transparent 0%, #000 60%);
          mask-image: linear-gradient(180deg, transparent 0%, #000 60%);
}
@media (max-height: 700px){
  body.dj-on .tj-stage .dj-foreground{ height: 8%; }   /* 위 [청운 띠] 절 §947-951 과 같은 짧은 화면 보정 */
}

/* ── 시그니처 오브젝트 (§16·§17) — 염주(우선순위 1번), 이미 전경 띠 안에 걸쳐 있다 ─────
   READING 이 도는 순간에만 표면 반사광이 아주 약하게 한 번 스쳤다가, 천천히 돌아온다.
   켜고 끄는 판정은 `[data-mood-clip="READING"]` 하나뿐 — 언제 READING 을 부르는지는 그대로
   shop-oracle.js 상담한턴() 몫이다(이 파일은 그 신호를 읽기만 한다 · §0 동결 목록 미접촉). */
body.dj-on .tj-stage .dj-fg-glint{
  position: absolute; left: 60%; bottom: 1%; width: 10%; height: 40%;
  border-radius: 50%; z-index: 8; pointer-events: none;
  background: radial-gradient(closest-side, rgba(255,225,170,.55), rgba(255,225,170,0) 75%);
  opacity: 0;
}
@media (prefers-reduced-motion: no-preference){
  body.dj-on .tj-stage .dj-fg-glint{ transition: opacity 1.6s ease; }   /* 꺼질 때 — 천천히 돌아온다(§17) */
  body.dj-on .tj-stage[data-mood-base="clip"][data-mood-clip="READING"] .dj-fg-glint{
    opacity: 1; transition: opacity .5s ease;                          /* 켜질 때만 조금 빠르게 — "한 번 스친다" */
  }
}

/* ── LAYER 3.5 — STATE LIGHTING (§10~§12) ───────────────────────────
   얼굴(--dj-face-y)을 중심으로 투명하고, 가장자리로 갈수록만 어두워지는 radial-gradient 한 장.
   중앙(얼굴)은 반지름 40%까지 완전히 투명 — "중앙을 검게 만들지 않는다"(§10)를 숫자로 지킨다.
   `--dj-scrim` 하나만 상태별로 바뀐다 — IDLE 0 · THINK .06 · READING(그 위에 얹혀) .10 · EXPLAIN
   은 별도 규칙 없이 그냥 0(기본값)으로 돌아간다. `@property` 로 등록해야 숫자 값 자체가
   부드럽게 전환된다(그냥 background 를 통째로 바꾸면 뚝 끊겨 보인다 · Android WebView Chromium
   105+ 지원). */
@property --dj-scrim{
  syntax: '<number>'; inherits: true; initial-value: 0;
}
body.dj-on{ --dj-scrim: 0; }
body.dj-on .tj-stage[data-mood="thinking"]{ --dj-scrim: .06; }
body.dj-on .tj-stage[data-mood-base="clip"][data-mood-clip="READING"]{ --dj-scrim: .10; }
body.dj-on .tj-stage .dj-state-scrim{
  z-index: 9;
  background: radial-gradient(ellipse 75% 65% at 46% var(--dj-face-y),
    transparent 40%, rgba(10,9,20, var(--dj-scrim)) 100%);
}
@media (prefers-reduced-motion: no-preference){
  /*  §11 — 600~1200ms 범위. 900ms 하나로 THINK 진입·복귀·READING 추가분 전부 같은 속도로 묶는다
      (상태가 바뀐 것을 효과로 강조하지 않는다 — 다 같은 느린 리듬으로 녹는다). */
  body.dj-on .tj-stage{ transition: --dj-scrim .9s ease; }
}

/* ═══ WO-57(0820) 청운 상담 입구를 시안(cheongun_oracle_mock.png)대로 — 말풍선 · 카드 둘 · 하단 줄 ═══
   값만 바꾼다: 흐름·클릭·횟수 로직은 shop-oracle.js 그대로. 글자는 줄이지 않는다(제목 ≥17 · 부제 ≥15 · 터치 ≥44) — 간격으로 맞춘다. */
/* 말풍선: 오른쪽 · 캐릭터 가슴 높이 · 종이색 카드 · [아바타 + 보라 알약] 윗줄 + 본문 17px · 오른쪽 위 분홍 노리개 */
body.dj-on.dj-landing .dj-bubble{ bottom: calc(100dvh - var(--dj-stage-h) + 34px + 72px); }
body.dj-on.dj-landing .dj-bubble-inner{
  position: relative; display: grid; grid-template-columns: auto 1fr; grid-template-areas: "av pill" "txt txt"; align-items: center; column-gap: 8px; row-gap: 4px;
  max-width: calc(var(--dj-col) * .72); padding: 10px 16px 11px 12px;
  background: linear-gradient(165deg, #fffaf0, #fbefd9); border: 1.5px solid #e2c88e; border-radius: 22px 22px 22px 22px;
  box-shadow: 0 6px 18px rgba(0,0,0,.4);
}
body.dj-on.dj-landing .dj-bubble-inner::before{ content: ""; position: absolute; left: 26px; top: -9px; width: 16px; height: 16px; background: #fffaf0; border-left: 1.5px solid #e2c88e; border-top: 1.5px solid #e2c88e; transform: rotate(45deg); border-radius: 3px 0 0 0; }
body.dj-on.dj-landing .dj-bubble-body{ display: contents; }
body.dj-on.dj-landing .dj-bubble-avatar{ grid-area: av; width: 34px; height: 34px; border: 1.5px solid #d9b472; }
body.dj-on.dj-landing .dj-bubble-body strong{ grid-area: pill; justify-self: start; margin: 0; padding: 3px 11px; font-size: 15px; line-height: 1.2; background: #e4d8f6; color: #3a2e63; }
body.dj-on.dj-landing .dj-bubble-body p{ grid-area: txt; font-size: 17px; line-height: 1.45; font-weight: 600; color: #3a2e22; }
body.dj-on.dj-landing .dj-bubble-nori{ position: absolute; right: -9px; top: -10px; width: 26px; height: auto; pointer-events: none; filter: drop-shadow(0 1px 2px rgba(60,30,30,.35)); }

/* 카드 둘: 종이색 · 금테 · [아이콘 | 제목+부제 | ›] · 왼쪽 아래 벚꽃 */
body.dj-on.dj-landing .dj-topics-primary{ gap: 10px; }
body.dj-on.dj-landing .dj-topics-wrap .dj-topics-primary > button{
  position: relative; min-height: 76px; padding: 10px 10px 10px 9px; display: flex; flex-direction: row; align-items: center; justify-content: flex-start; gap: 6px; text-align: left;
  background: linear-gradient(160deg, #fffaf0, #fbeed6); border: 1.5px solid #d9b472; border-radius: 22px;
  -webkit-backdrop-filter: none; backdrop-filter: none; box-shadow: 0 3px 10px rgba(30,20,10,.3); color: #4a3526;
}
body.dj-on.dj-landing .dj-topics-wrap .dj-topics-primary > button::after{
  content: ""; position: absolute; left: -7px; bottom: -8px; width: 28px; height: 28px; pointer-events: none;
  background: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='%23f4a8bb' stroke='%23e58aa3' stroke-width='.6'%3E%3Ccircle cx='12' cy='5.2' r='4'/%3E%3Ccircle cx='18.5' cy='9.9' r='4'/%3E%3Ccircle cx='16' cy='17.6' r='4'/%3E%3Ccircle cx='8' cy='17.6' r='4'/%3E%3Ccircle cx='5.5' cy='9.9' r='4'/%3E%3C/g%3E%3Ccircle cx='12' cy='12' r='3.2' fill='%23f7d77a'/%3E%3C/svg%3E") center / contain no-repeat;
}
body.dj-on.dj-landing .dj-topics-wrap .dj-topics-primary > button .dj-topic-ico{ flex: 0 0 auto; width: 42px; height: 42px; background: none !important; box-shadow: none !important; border-radius: 0; }
body.dj-on.dj-landing .dj-topics-wrap .dj-topics-primary > button .dj-topic-ico img{ width: 42px; height: 42px; object-fit: contain; }
body.dj-on.dj-landing .dj-topics-wrap .dj-topics-primary > button .dj-topic-text{ flex: 1 1 auto; min-width: 0; align-items: flex-start; gap: 2px; }
body.dj-on.dj-landing .dj-topics-wrap .dj-topics-primary > button .dj-topic-text strong{ font-size: 17px; line-height: 1.2; font-weight: 800; color: #4a3526; -webkit-line-clamp: 2; word-break: keep-all; }
body.dj-on.dj-landing .dj-topics-wrap .dj-topics-primary > button .dj-topic-sub{ font-size: 15px; line-height: 1.25; white-space: normal; text-align: left; color: #7a6652; word-break: keep-all; overflow: visible; }
body.dj-on.dj-landing .dj-topics-wrap .dj-topics-primary > button .dj-topic-arrow{
  display: block; flex: 0 0 14px; width: 14px; height: 14px; font-size: 0; opacity: 1;
  background: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpolyline points='9 5 16 12 9 19' fill='none' stroke='%238a6a3a' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat;
}

/* 하단 줄: 알약·바탕을 걷고 [말풍선 SVG + 글 15px+] — 지난 이야기 버튼(있을 때)은 오른쪽에 그대로 */
body.dj-on.dj-landing .dj-cta-footer{ background: none; border: 0; box-shadow: none; padding: 2px 4px 0; -webkit-backdrop-filter: none; backdrop-filter: none; }
body.dj-on.dj-landing .dj-cta-badge{ display: inline-flex; align-items: center; gap: 9px; font-size: 15px; line-height: 1.3; font-weight: 600; color: #f6efe0; text-shadow: 0 1px 4px rgba(10,6,24,.7); }
body.dj-on.dj-landing .dj-cta-badge-ico{ flex: 0 0 auto; width: 22px; height: 22px; color: #f6efe0; }

/* 위 줄 오른쪽 [♪] [ⓘ] 둥근 버튼 — 시안은 큰 보라 원 · 터치 44px 이상(기능·자리는 그대로) */
body.dj-on .ui-topbar .bgm-chip,
body.dj-on .ui-topbar .hud-info,
body.dj-on .bgm-chip,
body.dj-on .hud-info{ min-width: 44px !important; min-height: 44px !important; width: 44px !important; height: 44px !important; }
body.dj-on .ui-topbar .bgm-chip, body.dj-on .ui-topbar .hud-info, body.dj-on .bgm-chip, body.dj-on .hud-info{
  background: rgba(36,24,70,.9) !important; border: 1.5px solid rgba(165,145,225,.75) !important; color: #e9dfff !important; box-shadow: 0 2px 8px rgba(8,4,24,.5) !important; }
body.dj-on .bgm-chip svg, body.dj-on .bgm-chip i, body.dj-on .hud-info{ color: #e9dfff; }
/* 좁은 폭(≤380): 카드 안쪽을 조금 조여 부제와 › 가 맞닿지 않게(글자 크기는 그대로) */
@media (max-width: 380px){
  body.dj-on.dj-landing .dj-topics-wrap .dj-topics-primary > button{ padding: 10px 8px 10px 8px; gap: 5px; }
  body.dj-on.dj-landing .dj-topics-wrap .dj-topics-primary > button .dj-topic-ico{ width: 36px; height: 36px; }
  body.dj-on.dj-landing .dj-topics-wrap .dj-topics-primary > button .dj-topic-ico img{ width: 36px; height: 36px; }
  body.dj-on.dj-landing .dj-topics-wrap .dj-topics-primary > button .dj-topic-arrow{ flex-basis: 12px; width: 12px; height: 12px; }
}
