/* DADA TOWN — 마을이 주인공이므로 UI는 조용하게 둔다.
   마을이 밝은 대낮 풍경이라 페이지도 흰 갤러리 벽처럼 밝은 톤 하나로 간다. */

:root {
  color-scheme: light;

  --bg: #FFFFFF;
  --surface: #FFFFFF;
  --surface-2: #F5F6F4;
  --ink: #1F241C;
  --sub: #656B60;
  --faint: #9AA093;
  --line: #E6E8E3;
  --accent: #3D7A4E;
  --accent-ink: #FFFFFF;
  --accent-tint: #EAF2EB;
  --shadow: 0 8px 28px rgba(31, 36, 28, .13);
  --radius: 14px;
}

* { box-sizing: border-box; }

/* display를 지정한 요소에도 hidden이 먹도록 (모달이 display:grid라 필요) */
[hidden] { display: none !important; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: "Pretendard Variable", Pretendard, -apple-system, BlinkMacSystemFont,
               "Apple SD Gothic Neo", "Noto Sans KR", "Malgun Gothic", system-ui, sans-serif;
  line-height: 1.6;
  word-break: keep-all;          /* 한국어 어절 단위 줄바꿈 — 단어 중간이 끊기지 않게 */
  overflow-wrap: break-word;
  -webkit-font-smoothing: antialiased;
}

button, input { font: inherit; color: inherit; }

:where(a, button, input, [tabindex]):focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
  border-radius: 6px;
}

/* ── 상단 ────────────────────────────────── */

.topbar {
  position: relative;
  width: 100%; max-width: 1440px;
  margin: 0 auto;
  padding: 34px 20px 20px;
  text-align: center;
}

.wordmark {
  margin: 0;
  font-size: clamp(23px, 2.6vw, 30px);
  font-weight: 800;
  letter-spacing: .18em;
  text-indent: .18em;      /* 자간이 만든 오른쪽 여백만큼 되밀어 시각 중심을 맞춘다 */
  line-height: 1.15;
}

.tagline {
  margin: 7px 0 0;
  font-size: 14px;
  font-weight: 500;
  color: var(--sub);
  letter-spacing: .03em;
}

/* ── 지도 아래 버튼 줄 — 두 버튼을 한 묶음으로 ── */

.actions {
  display: flex; justify-content: center; align-items: center;
  gap: 10px; margin-top: 14px;
}

.list-btn, .picks-btn {
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--line); border-radius: 999px;
  padding: 10px 18px; font-size: 13.5px; font-weight: 600;
  cursor: pointer; box-shadow: var(--shadow);
  white-space: nowrap;
}
.list-btn { background: var(--accent); color: var(--accent-ink); border-color: transparent; }
.list-btn:hover { filter: brightness(1.08); }
.picks-btn { font-weight: 700; }
.picks-btn:hover { background: var(--surface-2); }

/* ── 지도 ────────────────────────────────── */

.stage { width: 100%; max-width: 1440px; margin: 0 auto; padding: 0 20px; }

.map-holder { position: relative; }

/* 마을 전체가 **스크롤 없이** 한 화면에 들어오도록. 1792/1434 = 1.2496
   빼는 336px은 지도 말고 세로로 자리를 차지하는 것들의 합이다 —
   상단 118 + 지도 아래 여백 14 + 안내 22 + 13 + 버튼 44 + 34 + 푸터 90.
   예전에는 290px로 잡아 두어 어느 화면에서나 딱 45px씩 넘쳤다(스크롤바 하나).
   위 숫자를 건드리면 여기도 같이 고쳐야 한다. */
@media (min-width: 700px) {
  .map-holder {
    max-width: min(1020px, calc((100dvh - 336px) * 1.2496));
    margin-inline: auto;
  }
}

.map {
  position: relative;
  /* 안쪽 z-index가 지도 밖(패널·팝업)까지 넘치지 않도록 스택을 가둔다 */
  isolation: isolate;
  aspect-ratio: 1792 / 1434;
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--surface-2);
  box-shadow: var(--shadow);
}

.map-img { display: block; width: 100%; height: 100%; object-fit: cover; }

.layer { position: absolute; inset: 0; pointer-events: none; }

/* 구역 버튼 — 클릭 영역은 블록 전체지만, 뾰옹 하는 건 그 안의 건물뿐.
   .pop은 따로 오려낸 건물 그림(assets/sprites/buildings.png,
   tools/cut_buildings.py)이다. 좌표는 밑변 기준(at/w)이라 JS가 구역 상자(rect)
   안에서 상대 위치로 환산해 left/top/width만 넣는다 — 높이는 그림의 원래
   비율대로 저절로 정해진다. */
.spot {
  position: absolute;
  pointer-events: auto;
  background: none;
  border: 0;
  cursor: pointer;
  padding: 0;
}
/* **세로는 `bottom`으로 앉힌다 — `translateY(-100%)`이 아니다.** 그 -100%는 제
   높이의 100%인데, 스프라이트 상자는 그림이 도착하기 전까지 높이가 0이다(안의
   <img>에 width·height 속성이 없어 비율을 모른다). 그동안 -100%도 0이라 건물이
   제 키만큼 아래에 그려지고, iOS 사파리는 그림이 온 뒤에도 그 값을 다시 계산하지
   않아 **폰에서만 마을이 통째로 흘러내렸다** (자세한 것은 app.js의 `upTo`).
   가로 -50%는 인라인 width에 걸리므로 그대로 둔다. */
.pop {
  position: absolute;
  display: block;
  transform: translateX(-50%);
  transform-origin: 50% 100%;
  pointer-events: none;
  /* 상시로 살짝 부풀었다 가라앉는다 — 여기가 눌러볼 수 있는 곳이라는 신호.
     사람들(folk-idle)과 같은 2.4초 박자·같은 위상으로 함께 움직인다 */
  animation: bldg-idle 2.4s ease-in-out infinite;
  transition: filter .18s ease;
}
/* 한 바퀴에 두 번 뾰잉 — 위로 쭉 늘었다가 옆으로 퍼지며 눌린다.
   양 끝에 잠깐 멈춤(6%·94%)을 둬야 흐물거리지 않고 튀는 느낌이 난다.
   솟는 시점(25%·75%)은 사람들(folk-idle)과 같다 — 마을이 한 박자로 움직인다 */
@keyframes bldg-idle {
  0%, 6%    { transform: translateX(-50%) scale(1, 1); }
  25%       { transform: translateX(-50%) scale(1.005, 1.08); }
  44%, 56%  { transform: translateX(-50%) scale(1.055, 1.002); }
  75%       { transform: translateX(-50%) scale(1.005, 1.08); }
  94%, 100% { transform: translateX(-50%) scale(1, 1); }
}
.pop > img { display: block; width: 100%; height: auto; }

/* 터치 기기에서는 :hover가 탭한 뒤에도 눌린 채 남는다. 그러면 이 규칙의
   animation:none 때문에 그 건물만 얼어붙었다가, 나중에 hover가 풀릴 때
   0부터 다시 시작해 마을과 박자가 어긋난다. 마우스가 있는 기기에서만 건다. */
@media (hover: hover) {
  .spot:hover .pop {
    animation: none;
    transform: translateX(-50%) scale(1.05);
    filter: drop-shadow(0 7px 10px rgba(31, 36, 28, .3)) brightness(1.04);
  }
}
.spot:focus-visible .pop {
  animation: none;
  transform: translateX(-50%) scale(1.05);
  filter: drop-shadow(0 7px 10px rgba(31, 36, 28, .3)) brightness(1.04);
}
.spot[aria-expanded="true"] .pop {
  filter: drop-shadow(0 9px 14px rgba(31, 36, 28, .34)) brightness(1.05);
  animation: boing .55s cubic-bezier(.34, 1.5, .64, 1) forwards;
}
/* 뾰옹: 납작하게 눌렸다가 위로 쭉 늘어나며 튀고 착지 */
@keyframes boing {
  0%   { transform: translateX(-50%) scale(1, 1); }
  25%  { transform: translateX(-50%) scale(1.1, .88); }
  55%  { transform: translateX(-50%) scale(.96, 1.14); }
  78%  { transform: translateX(-50%) scale(1.05, .99); }
  100% { transform: translateX(-50%) scale(1.06, 1.06); }
}

/* 우편함 — 구역과 별개의 문 (districts[].mailbox). 건물은 소개서를 열고
   우편함은 게임 안내서를 연다. 겉의 링크(.mbox-spot)는 가만히 있고 안의
   그림(.mbox)만 움직인다 — "나" 캐릭터와 같은 이유로, 누를 자리는 고정이어야 한다.
   좌표는 건물과 같은 밑변 기준(at/w)이라 "나"·확성기와 같은 방식으로 앉힌다. */
.mbox-spot {
  position: absolute;
  pointer-events: auto;
  display: block;
  transform: translateX(-50%);
  z-index: 4;                      /* 세모집 구역 버튼 위 — 우편함 자리는 우편함이 받는다 */
  line-height: 0;
}
/* 우편함은 지도 폭의 2%라 폰에서 8px 남짓. 판정 영역을 그림보다 넓게 깐다 */
.mbox-spot::after {
  content: '';
  position: absolute;
  left: 50%; top: 50%;
  width: max(100%, 44px); height: max(100%, 44px);
  transform: translate(-50%, -50%);
}
.mbox {
  display: block;
  transform-origin: 50% 100%;
  pointer-events: none;
  /* 건물과 같은 2.4초 박자를 타되 **좌우로 인사하듯 또잉또잉** 흔든다.
     건물은 다 같이 숨쉬고, 개별 요소는 저마다 다른 걸음을 갖는다 —
     우편함은 흔들고, 까마귀는 퍼덕이고 갸웃하고, 쪽지는 뽀잉거린다. */
  animation: mbox-idle 2.4s ease-in-out infinite;
}
.mbox > img { display: block; width: 100%; height: auto; }
@keyframes mbox-idle {
  0%, 12%   { transform: scale(1, 1)       rotate(0deg); }
  24%       { transform: scale(1.34, 1.14) rotate(-7deg); }
  36%       { transform: scale(1.34, 1.14) rotate(7deg); }
  48%       { transform: scale(1.26, 1.08) rotate(-4deg); }
  60%, 100% { transform: scale(1, 1)       rotate(0deg); }
}
@media (hover: hover) {
  .mbox-spot:hover .mbox { animation: none; transform: scale(1.34, 1.16) rotate(-7deg); }
}
.mbox-spot:focus-visible .mbox { animation: none; transform: scale(1.34, 1.16) rotate(-7deg); }
/* 발송 — 안내서가 튀어나오는 순간 한 번 크게. 여기도 1 아래로는 안 내려간다 */
.mbox.send { animation: mbox-send .62s cubic-bezier(.34, 1.5, .64, 1) forwards; }
@keyframes mbox-send {
  0%   { transform: scale(1, 1); }
  22%  { transform: scale(1.34, 1.02); }
  55%  { transform: scale(1.04, 1.52); }
  80%  { transform: scale(1.18, 1.04); }
  100% { transform: scale(1, 1); }
}
/* 우편함에서 날아가는 카드들. 뒤 넉 장은 빈 카드고 맨 위 한 장이 겉장(표지)이다 —
   도착 페이지가 그 그림에서 시작하므로 이어져 보인다 */
.mail-blank { border: 1px solid var(--line); }
.mail-fly {
  position: fixed;
  z-index: 80;
  background: #fff;
  border-radius: 6px;
  box-shadow: var(--shadow);
  object-fit: cover;
  will-change: transform;
  pointer-events: none;
}

/* "나" 캐릭터 — 공원 사람들·건물과 똑같은 folk-idle 박자로 움직인다.
   혼자 다른 리듬으로 움직이면 마을 전체가 어수선해 보인다.

   중요: 움직이는 것은 안쪽 .me-figure고 버튼은 가만히 있는다.
   버튼이 흔들리면 누를 자리도 같이 흔들려 조준이 안 된다 — 캐릭터는
   지도 폭의 5.4%뿐이라 폰에서 20px 남짓이고, 그게 위아래로 뛰기까지 하면
   맞히기 어렵다. */
.me-spot {
  position: absolute;
  pointer-events: auto;
  transform: translateX(-50%);
  background: none; border: 0; padding: 0; cursor: pointer;
  line-height: 0;
  z-index: 5;                      /* 넓힌 판정이 옆 구역 상자에 먹히지 않게 */
}
/* 손가락이 빗나가도 눌리도록 그림보다 넉넉하게. 버튼의 가상요소라
   여기를 눌러도 버튼이 눌린다. 최소 64px은 터치 기준(44px)을 넘긴다. */
.me-spot::after {
  content: "";
  position: absolute; left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  width: max(230%, 64px);
  height: max(210%, 64px);
}
.me-figure {
  display: block;
  transform-origin: 50% 100%;
  animation: me-idle 2.4s ease-in-out infinite;
}
.me-spot img {
  width: 100%; height: auto; display: block;
  filter: drop-shadow(0 3px 4px rgba(0, 0, 0, .28));
}
/* 같은 이유로 마우스가 있는 기기에서만 — 폰에서는 탭한 뒤 계속 폴짝거리게 된다 */
@media (hover: hover) {
  .me-spot:hover .me-figure { animation: hop .55s ease-in-out infinite; }
}
.me-spot:focus-visible .me-figure { animation: hop .55s ease-in-out infinite; }

/* folk-idle과 같은 박자·같은 폭이되 자리 이동(translate)은 버튼이 맡는다 */
@keyframes me-idle {
  0%, 100% { transform: translateY(0)    scale(1, 1)      rotate(0deg); }
  25%      { transform: translateY(-18%) scale(.96, 1.07) rotate(-5deg); }
  50%      { transform: translateY(0)    scale(1.07, .92) rotate(0deg); }
  75%      { transform: translateY(-18%) scale(.96, 1.07) rotate(5deg); }
}

/* 호버하면 반갑게 폴짝 — 굽혔다가 튀어오르고 착지 */
@keyframes hop {
  0%, 100% { transform: translateY(0)    scale(1, 1); }
  28%      { transform: translateY(0)    scale(1.06, .9); }
  62%      { transform: translateY(-14%) scale(.96, 1.05); }
  86%      { transform: translateY(0)    scale(1.03, .96); }
}

/* ── 세모집 마당의 확성기 ────────────────────
   집 테마송이 나오는 자리다. `speaker.song`이 없으면 `.horn-spot`만 있고
   `.horn-live`가 없다 — 그때는 아래에서 `pointer-events: none`으로 막혀 풍경으로만 선다
   (까마귀와 같은 규칙). 노래가 있으면 진짜 버튼이라 `.horn-live`가 붙는다.

   걸음은 **한 박자에 두 번 앞으로 내지르는 것.** 마을의 다른 것들과 겹치지 않아야 해서
   회전(우편함)도 뜀(캐릭터)도 아닌 **반동**을 골랐다 — 소리를 내는 물건이니 앞으로
   밀렸다 돌아오는 게 제 몸짓이다. 건물이 두 번 숨쉬는 것과 같은 자리에서 두 번 지르므로
   마을과 한 박자로 읽히면서도 하는 일은 다르다. */
.horn-spot {
  position: absolute;
  pointer-events: none;             /* 노래가 없으면 끝까지 이 값이다 */
  transform: translateX(-50%);/* 좌표는 받침이 지붕에 닿는 자리 */
  z-index: 3;
  line-height: 0;
}
/* 노래가 있을 때만 문이 된다 — 배경 없는 버튼 + 터치 기준을 넘는 판정 영역 */
.horn-spot.horn-live {
  pointer-events: auto;
  background: none; border: 0; padding: 0; cursor: pointer;
}
.horn-spot.horn-live::after {
  content: '';
  position: absolute; left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  width: max(100%, 44px); height: max(100%, 44px);
}
.horn-fig {
  display: block;
  transform-origin: 34% 92%;        /* 잔디에 닿은 받침 */
  animation: horn-idle 2.4s ease-in-out infinite;
}
/* 호버 확대를 idle 애니메이션과 다른 요소에 건다 — 한 요소에 겹치면 애니메이션의
   transform이 호버의 transform을 덮어쓴다 (새·쪽지에서 이미 겪은 것) */
.horn-zoom { display: block; transition: transform .15s ease; }
.horn-spot.horn-live:hover .horn-zoom,
.horn-spot.horn-live:focus-visible .horn-zoom { transform: scale(1.1); }
.horn-fig img {
  display: block; width: 100%; height: auto;
  filter: drop-shadow(0 2px 3px rgba(31, 36, 28, .28));
}
/* 나팔이 오른쪽을 보므로 내지르는 방향도 오른쪽이다 */
@keyframes horn-idle {
  0%, 8%    { transform: translateX(0)  scale(1, 1)       rotate(0deg); }
  17%       { transform: translateX(8%) scale(1.1, 1.02)  rotate(-5deg); }
  28%       { transform: translateX(0)  scale(1, 1)       rotate(0deg); }
  37%       { transform: translateX(8%) scale(1.1, 1.02)  rotate(-5deg); }
  48%, 100% { transform: translateX(0)  scale(1, 1)       rotate(0deg); }
}
/* **재생 중에는 같은 반동을 더 크고 빠르게** 한다 — 소리가 나고 있다는 것이
   눈에도 보이도록. 마을의 idle 박자(IDLE_ANIMS)에는 들어가지 않는다 — 재생은
   마을의 상시 리듬이 아니라 방문자가 시작한 독립된 사건이라서다. */
.horn-spot.horn-playing .horn-fig { animation: horn-shout .6s ease-in-out infinite; }
@keyframes horn-shout {
  0%, 100% { transform: translateX(0)   scale(1, 1)        rotate(0deg); }
  35%      { transform: translateX(16%) scale(1.2, 1.06)   rotate(-9deg); }
  70%      { transform: translateX(5%)  scale(1.08, 1.02)  rotate(-3deg); }
}

/* 확성기가 여는 패널 — 재생기와 가사. 커스텀 재생·탐색바를 만들지 않고
   `<audio controls>`를 그대로 쓴다. 브라우저 내장 컨트롤이 이미 키보드·스크린리더
   접근성을 갖추고 있어서, 새로 만들면 그걸 다시 흉내 내는 셈이 된다. */
.song-audio { display: block; width: 100%; margin: 2px 0 14px; }

.song-section + .song-section { margin-top: 14px; }
.song-label {
  margin: 0 0 3px;
  font-size: 11px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  color: var(--faint);
}
.song-line { margin: 0; font-size: 13.5px; line-height: 1.65; color: var(--ink); }

/* 까마귀가 펴 보이는 칼럼. 카드가 아니라 **읽는 글**이라 상자를 두르지 않는다 —
   패널 안에서 카드와 나란히 놓일 일이 없으므로 글자만으로 충분하다.
   각 문단 앞의 ✔는 원문의 표식이다. 글자로 넣지 않고 ::before로 세워야
   복사할 때 따라붙지 않고, 두 줄로 넘어가도 본문이 표식 아래로 내려가지 않는다. */
.column { padding: 2px 0 2px; }
.column-note {
  position: relative;
  margin: 0 0 10px;
  padding-left: 17px;
  font-size: 13.5px; line-height: 1.7; color: var(--ink);
}
.column-note::before {
  content: '✔';
  position: absolute; left: 0; top: 0;
  color: var(--accent); font-size: 12px; line-height: 1.9;
}
/* 인용은 원문에서도 색 배경으로 따로 떠 있다 — 요약(개조식)과 사람 말은 결이 다르다 */
.column-quote {
  margin: 14px 0 0;
  padding: 12px 13px;
  background: var(--surface-2);
  border-radius: 12px;
}
.column-quote p { margin: 0; font-size: 13px; line-height: 1.72; color: var(--ink); }
.column-quote p + p { margin-top: 9px; }
.column-by {
  display: block; margin-top: 9px;
  font-size: 12px; font-style: normal; color: var(--sub);
}

/* ── 날아다니는 쪽지 ─────────────────────────
   새·구름은 풍경이고 이건 문이다. 그래서 넷을 다르게 뒀다 —
   길목마다 멈추는 걸음, 마을 박자를 타지 않는 펄럭임(0.55초),
   무엇에도 가리지 않는 높이(z 7 > 하늘 6), 손을 대면 멈추는 비행.

   비행 경로(@keyframes note-fly)는 services.json의 floater.path로 JS가 굽는다. */
.note-spot {
  position: absolute;
  /* 언제든 잡힌다. 한때 멈춰 선 동안만 잡히게 해 뒀는데, 그러면 한 바퀴의 5분의 1만
     눌리는 물건이 된다 — 누르려다 안 눌리는 문은 문이 아니다. 위에 있는 것이 클릭을
     받는 건 원래 그래야 하는 일이고, 머무는 자리가 전부 빈 땅이라 오래 겹치지도 않는다. */
  pointer-events: auto;
  z-index: 7;                       /* 마을에서 가장 위 — 문은 가려지면 안 된다 */
  background: none; border: 0; padding: 0; cursor: pointer;
  line-height: 0;
  /* 쪽지만은 밑변이 아니라 가운데를 잡는다 — 날아다니는 것이라 발밑이 없다.
     그래서 세로 -50%가 제 높이에 걸리는데, 그림이 오기 전에는 그 높이가 0이다
     (건물이 폰에서 흘러내린 것과 같은 함정 — app.js의 `upTo`). 세 장이 모두
     150×102라 비율을 미리 못 박아 두면 그림을 기다리지 않고도 높이가 선다. */
  aspect-ratio: 150 / 102;
  transform: translate(-50%, -50%);
  animation: note-fly linear infinite;
}
/* 판정은 그림만큼. 늘 잡히는 물건이라 그림보다 크게 잡으면 남의 자리까지 먹는다.
   그림이 이미 70px 남짓이라 터치 기준(44px)은 그대로 넘는다. */
.note-spot::after {
  content: '';
  position: absolute; left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  width: max(100%, 44px); height: max(100%, 44px);
}
.note-fig {
  display: block;
  animation: note-bob 1s ease-in-out infinite;
}
.note-zoom {
  display: block; position: relative;
  transition: transform .18s ease;
}
.note-fig img {
  display: block; width: 100%; height: auto;
  filter: drop-shadow(0 4px 5px rgba(31, 36, 28, .22));
}
/* 세 장을 포개 놓고 한 장씩 드러낸다 (까마귀와 같은 방법).
   다만 박자가 다르다 — 마을은 2.4초 한 박자인데 펄럭임은 0.55초다.
   마을의 일부가 아니라 마을 위에 온 것이라 굳이 맞추지 않는다. */
.note-mid, .note-up { position: absolute; left: 0; top: 0; }
.note-fig img + img { opacity: 0; }          /* 기본값은 「첫 장만」 */
.note-down, .note-mid, .note-up { animation: .55s steps(1, end) infinite; }
.note-down { animation-name: note-f-down; }
.note-mid  { animation-name: note-f-mid; }
.note-up   { animation-name: note-f-up; }
@keyframes note-f-down { 0%, 24% { opacity: 1; } 25%, 100% { opacity: 0; } }
@keyframes note-f-mid  { 0%, 24% { opacity: 0; } 25%, 49% { opacity: 1; }
                         50%, 74% { opacity: 0; } 75%, 100% { opacity: 1; } }
@keyframes note-f-up   { 0%, 49% { opacity: 0; } 50%, 74% { opacity: 1; } 75%, 100% { opacity: 0; } }

/* 오르내리면서 **파장처럼 커졌다 작아진다.** 이 뽀잉거림이 「눌러도 되는 것」이라는
   신호다 — 새와 구름은 크기가 변하지 않는다. 마을의 뾰잉(2.4초)과는 박자를 달리해
   같은 것으로 안 읽히게 한다. 커지는 것은 안쪽 그림뿐이고 누를 자리는 고정이다. */
@keyframes note-bob {
  0%, 100% { transform: translateY(-4%) scale(1); }
  25%      { transform: translateY(1%)  scale(1.15); }
  50%      { transform: translateY(4%)  scale(1); }
  75%      { transform: translateY(1%)  scale(.85); }
}

/* **손을 대면 멈춘다.** 날아다니는 것을 눌러야 하므로 이게 없으면 조준이 안 된다.
   멈추면서 살짝 커지는 것이 「잡혔다」는 신호가 된다. */
@media (hover: hover) {
  .note-spot:hover { animation-play-state: paused; }
  .note-spot:hover .note-fig { animation-play-state: paused; }
  .note-spot:hover .note-zoom { transform: scale(1.14); }
}
.note-spot:focus-visible { animation-play-state: paused; }
.note-spot:focus-visible .note-fig { animation-play-state: paused; }
.note-spot:focus-visible .note-zoom { transform: scale(1.14); }
/* 팝업이 열려 있는 동안에도 멈춰 있어야 한다 — 열어 둔 채 날아가 버리면 안 된다 */
.note-spot[aria-expanded="true"] { animation-play-state: paused; }
.note-spot[aria-expanded="true"] .note-fig { animation-play-state: paused; }

/* 아직 주소가 없는 항목 — 누를 수 없는 카드. 죽은 링크보다 낫다 */
.card--soon { cursor: default; opacity: .78; }
.card--soon .card-name { color: var(--sub); }
.badge.soon { background: var(--surface-2); color: var(--sub); }

/* ── 카페 앞 까마귀 Croww ────────────────────
   PlayGrown의 마스코트다. 우편함과 같은 「구역과 별개의 문」이라 링크(<a>)로 만들고,
   움직이는 것은 안쪽 그림(.crow-figure)뿐이다 — 누를 자리가 흔들리면 조준이 안 된다.

   걸음은 마을과 같은 2.4초 한 박자를 타되 안에서 하는 일이 다르다.
   건물은 두 번 숨쉬고, 우편함은 한 번 크게 뛰고, 까마귀는 **한 번 퍼덕이고 한 번 갸웃한다.**
   같은 리듬 위의 다른 걸음이라 같은 요소로 안 읽힌다.

   퍼덕임과 갸웃은 그림 세 장을 번갈아 보여 만든다. 이 마을에는 프레임 애니메이션이
   없어(transform만 쓴다) 날개가 실제로 올라가려면 그림이 여러 장이어야 했다.
   세 장은 같은 배율·같은 기준점의 한 캔버스다 (tools/cut_crow.py). */
.crow-spot {
  position: absolute;
  pointer-events: auto;
  display: block;
  transform: translateX(-50%);   /* 좌표는 발밑이다 (사람들·"나"와 같은 규칙) */
  z-index: 4;
  line-height: 0;
}
/* 폰에서 그림은 24px 남짓. 판정은 그림보다 넉넉하게 (터치 기준 44px) */
.crow-spot::after {
  content: '';
  position: absolute; left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  width: max(150%, 56px); height: max(170%, 56px);
}
/* 열 것이 아무것도 없을 때만 풍경이다 — 누를 수 없는 것이 손가락을 부르면 안 된다.
   지금은 문서 대신 칼럼이 걸려 있어 문이다 (app.js의 makeMascot). */
.crow-spot.scenery { pointer-events: none; cursor: default; }
.crow-spot.scenery::after { content: none; }
/* 칼럼을 여는 까마귀는 <button>이다 — 확성기와 같이 배경 없는 버튼으로 되돌린다 */
button.crow-spot { background: none; border: 0; padding: 0; cursor: pointer; }
.crow-figure {
  position: relative; display: block;
  transform-origin: 50% 100%;
  animation: crow-idle 2.4s ease-in-out infinite;
}
.crow-figure img {
  display: block; width: 100%; height: auto;
  filter: drop-shadow(0 3px 4px rgba(0, 0, 0, .26));
}
/* 세 장을 정확히 포개 놓고 필요한 순간에만 한 장씩 드러낸다.
   같은 배율·같은 기준점의 한 캔버스라(tools/cut_crow.py) 갈아 끼워도 새가 안 튄다. */
.crow-figure .crow-flap, .crow-figure .crow-tilt { position: absolute; left: 0; top: 0; }
/* 기본값은 「첫 장만 보인다」다. 아래 애니메이션이 어떤 이유로든 안 붙어도
   (역할 이름이 CSS와 어긋나는 데이터가 오는 경우 등) 세 장이 한꺼번에 겹쳐 보이지 않는다 */
.crow-figure img + img { opacity: 0; }
.crow-rest, .crow-flap, .crow-tilt { animation: 2.4s steps(1, end) infinite; }
.crow-rest { animation-name: crow-frame-rest; }
.crow-flap { animation-name: crow-frame-flap; }
.crow-tilt { animation-name: crow-frame-tilt; }

/* 한 바퀴에 두 번 — 41~52%에 한 번 퍼덕이고, 76~90%에 한 번 갸웃한다.
   나머지 시간은 가만히 앉아 있다. steps(1)이라 장 사이가 섞이지 않고 딱 갈린다. */
@keyframes crow-frame-rest {
  0%, 40%   { opacity: 1; } 41%, 52% { opacity: 0; }
  53%, 75%  { opacity: 1; } 76%, 90% { opacity: 0; }
  91%, 100% { opacity: 1; }
}
@keyframes crow-frame-flap { 0%, 40% { opacity: 0; } 41%, 52% { opacity: 1; } 53%, 100% { opacity: 0; } }
@keyframes crow-frame-tilt { 0%, 75% { opacity: 0; } 76%, 90% { opacity: 1; } 91%, 100% { opacity: 0; } }

/* 퍼덕일 때 살짝 뜨고, 갸웃할 때 조금 기운다.
   갸웃은 그림(crow-look)이 이미 고개를 들고 있으므로 기울임은 거들기만 한다 —
   여기서 많이 돌리면 갸웃이 아니라 넘어지는 것처럼 보인다. */
@keyframes crow-idle {
  0%, 32%   { transform: translateY(0)    scale(1, 1)      rotate(0deg); }
  44%       { transform: translateY(-11%) scale(1.02, .98) rotate(0deg); }
  52%       { transform: translateY(-13%) scale(1.02, .98) rotate(0deg); }
  62%, 72%  { transform: translateY(0)    scale(1, 1)      rotate(0deg); }
  80%, 88%  { transform: translateY(0)    scale(1, 1)      rotate(-7deg); }
  100%      { transform: translateY(0)    scale(1, 1)      rotate(0deg); }
}
/* 마우스가 있는 기기에서만 — 폰에서는 탭한 뒤 계속 퍼덕이게 된다 */
@media (hover: hover) {
  .crow-spot:hover .crow-figure { animation: crow-hop .5s ease-in-out infinite; }
}
.crow-spot:focus-visible .crow-figure { animation: crow-hop .5s ease-in-out infinite; }
@keyframes crow-hop {
  0%, 100% { transform: translateY(0)    scale(1, 1); }
  30%      { transform: translateY(0)    scale(1.05, .93); }
  65%      { transform: translateY(-16%) scale(.97, 1.05); }
}

/* 지도 위에 얹는 것들. 구름·새·자동차가 떠다니던 자리인데, 마을에 문이 늘면서
   전부 걷어냈다 (app.js 머리말) — 남은 것은 공원 사람들과 앉은 새뿐이다. */
.folk { position: absolute; }
.folk img { display: block; width: 100%; height: auto; }

/* 공원 사람들 — 발 붙이고 미세하게 들썩.
   '사람들' 구역은 공원 땅이 아니라 사람들이 반응한다 */
.folk {
  transform: translateX(-50%);
  transform-origin: 50% 100%;
  animation: folk-idle 2.4s ease-in-out infinite;
}
/* 셋이 **왼쪽 사람부터 오른쪽 사람까지 차례로** 솟는다 — 파도타기다.
   박자는 마을과 같은 2.4초 그대로고 사람마다 조금씩 늦게 시작할 뿐이라
   (app.js가 x 순서대로 animation-delay를 준다) 마을의 리듬을 깨지 않는다.
   §9가 걷어낸 것은 **마을 전체**를 파도로 만든 것이었다 — 저건 건물이 눌린다는
   말을 하려던 표식이었고, 이건 한 무리가 함께 노는 장면이라 다른 이야기다.
   주인공보다는 잔잔하게 두어 시선이 캐릭터로 가게 한다 */
@keyframes folk-idle {
  0%, 100% { transform: translateX(-50%) scale(1, 1) rotate(0deg); }
  25%      { transform: translateX(-50%) translateY(-18%) scale(.96, 1.07) rotate(-5deg); }
  50%      { transform: translateX(-50%) scale(1.07, .92) rotate(0deg); }
  75%      { transform: translateX(-50%) translateY(-18%) scale(.96, 1.07) rotate(5deg); }
}
.folk.person img { transform-origin: 50% 100%; transition: transform .18s ease, filter .18s ease; }
.folks-hot .folk.person img {
  transform: scale(1.12);
  filter: drop-shadow(0 4px 5px rgba(31, 36, 28, .32));
}
.folks-pop .folk.person img { animation: boing .55s cubic-bezier(.34, 1.5, .64, 1); }

/* ── 지도 아래 줄 ────────────────────────── */

/* 지도 바로 아래 안내. 눌러볼 수 있다는 걸 알려주는 유일한 글이다.

   색은 --faint(2.68:1)가 아니라 --sub(5.49:1)를 쓴다 — 눈에 띄게 하려고
   흐린 색에 숨쉬기까지 얹었더니 최저점에서 1.64:1까지 떨어져 오히려 안 읽혔다.
   진하게 만드는 편이 흐리게 깜빡이는 것보다 훨씬 잘 보인다.
   숨쉬기는 남기되 WCAG AA(4.5:1)를 깨지 않는 폭(.92~1, 최저 4.60:1)으로만. */
.hint {
  text-align: center;
  font-size: 13.5px; color: var(--sub);
  margin: 14px 0 0;
  animation: hint-breathe 3.6s ease-in-out infinite;
}
@keyframes hint-breathe { 0%, 100% { opacity: .92; } 50% { opacity: 1; } }
/* 자리는 남겨둔 채 숨긴다 — 사라질 때 아래 것들이 들썩이지 않게 */
.hint.gone { visibility: hidden; }

/* ── 정적 문서 페이지 (/list) ──────────────
   마을은 경험, 이 페이지는 정보. 크롤러와 스크린리더가 읽는 쪽이라
   장식을 걷어내고 글을 읽기 좋은 폭으로만 잡는다. */
.doc {
  width: 100%; max-width: 720px;
  margin: 0 auto; padding: 0 20px 40px;
}
.doc-back { margin: 0 0 18px; font-size: 13.5px; }
.doc-back a { color: var(--sub); text-decoration: none; }
.doc-back a:hover { color: var(--accent); }
.doc-lead { margin: 0 0 28px; color: var(--sub); font-size: 14.5px; }

.doc-group { margin: 0 0 34px; }
.doc-group > h2 {
  margin: 0 0 14px; padding-bottom: 8px;
  font-size: 17px; font-weight: 800;
  border-bottom: 1px solid var(--line);
  display: flex; align-items: baseline; gap: 8px;
}
.doc-count { font-size: 12.5px; font-weight: 600; color: var(--faint); }

.doc-item { margin: 0 0 18px; }
.doc-item h3 {
  margin: 0 0 4px; font-size: 15px; font-weight: 700;
  display: flex; align-items: center; gap: 7px; flex-wrap: wrap;
}
.doc-item h3 a { color: inherit; text-decoration: none; }
.doc-item h3 a:hover { color: var(--accent); text-decoration: underline; }
.doc-item p { margin: 0; font-size: 13.5px; color: var(--sub); line-height: 1.6; }

.doc-sub { margin: 20px 0 8px; font-size: 13px; font-weight: 700; color: var(--faint); }
.doc-date { font-size: 12px; font-weight: 600; color: var(--faint); font-variant-numeric: tabular-nums; }
.doc-list a { color: inherit; text-decoration: none; }
.doc-list a:hover { color: var(--accent); text-decoration: underline; }
.doc-list { margin: 0; padding-left: 18px; font-size: 13.5px; color: var(--sub); line-height: 1.75; }
.doc-list strong { color: var(--ink); font-weight: 700; }
.doc-contact { margin: 18px 0 0; font-size: 13.5px; }
.doc-contact a { color: var(--accent); }

/* 워드마크는 .topbar에 있고 .doc은 <main>이라 자손 선택자로는 안 잡힌다 */
.topbar .wordmark a { color: inherit; text-decoration: none; }
.topbar .wordmark a:hover { color: var(--accent); }

/* 목록 모달 아래의 "전체 목록 페이지" 링크 */
.modal-foot {
  flex: none; padding: 10px 16px 14px; text-align: center;
  border-top: 1px solid var(--line);
  font-size: 13px;
}
.modal-foot a { color: var(--sub); }

/* ── 구역 패널 ───────────────────────────── */

.panel {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 15px;
  margin-top: 14px;
}

/* 데스크톱: 누른 건물 바로 옆에 붙여 띄운다 (위치는 JS가 계산) */
@media (min-width: 700px) {
  .panel-wrap { position: absolute; inset: 0; pointer-events: none; }
  .panel {
    position: absolute; margin-top: 0;
    overflow-y: auto; overscroll-behavior: contain;
    pointer-events: auto;
    animation: panel-in .16s ease-out;
  }
}

@keyframes panel-in { from { opacity: 0; transform: scale(.98); } to { opacity: 1; transform: scale(1); } }

.panel-head { display: flex; align-items: center; gap: 9px; margin-bottom: 11px; }
.panel-title { font-size: 16.5px; font-weight: 800; margin: 0; }
.panel-label { font-size: 11px; font-weight: 700; color: var(--faint); letter-spacing: .08em; }
.panel-close { margin-left: auto; }

.icon-btn {
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: 9px; width: 30px; height: 30px; cursor: pointer;
  display: grid; place-items: center; font-size: 13px;
}
.icon-btn:hover { background: var(--line); }

.group-title { font-size: 12px; font-weight: 700; color: var(--sub); margin: 11px 0 6px; }
.group-title:first-child { margin-top: 0; }

.cards { display: grid; gap: 7px; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); }

/* 목록에서는 카드를 늘리지 않고 폭을 고정한다. 그래야 그 달에 몇 개를 만들었는지가
   줄 길이로 드러난다 — 한 개인 달은 짧고, 세 개인 달은 길다.
   1fr로 늘리면 어느 달이나 화면을 꽉 채워 그 차이가 통째로 사라진다.
   (추천 픽은 그대로 늘어나야 하므로 `.cards` 기본값은 건드리지 않는다) */
.cards.by-time { grid-template-columns: repeat(auto-fill, minmax(min(100%, 230px), 230px)); }
/* 한 줄에 한 장뿐인 폭에서는 길이를 견줄 대상이 없다 — 늘려서 빈자리를 없앤다 */
@media (max-width: 699px) { .cards.by-time { grid-template-columns: 1fr; } }

/* 설명이 두세 문장이라 카드가 여러 줄이 된다. 가운데 정렬이면 아이콘이
   글 한가운데 붕 뜨므로 위에 맞춘다. */
.card {
  display: flex; align-items: flex-start; gap: 11px;
  background: var(--surface-2);
  border: 1px solid transparent;
  border-radius: 12px;
  padding: 11px;
  text-decoration: none; color: inherit;
}
.card:hover { border-color: var(--line); background: var(--surface); box-shadow: 0 2px 8px rgba(31,36,28,.07); }

.card-ico {
  width: 38px; height: 38px; flex: none;
  background: var(--accent-tint); border-radius: 11px;
  display: grid; place-items: center; font-size: 18px;
}
.card-body { min-width: 0; flex: 1; }
.card-name {
  font-size: 14px; font-weight: 700;
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
}
/* 만든 시기. 이름 줄에 끼우면 이름이 긴 항목에서 혼자 다음 줄로 떨어지므로
   이름 위에 얹는다. 「언제」와 「무엇」이 눈으로도 갈린다. */
.card-date {
  font-size: 11px; font-weight: 600; color: var(--faint);
  font-variant-numeric: tabular-nums;
  letter-spacing: .02em; margin-bottom: 1px;
}
/* 설명에 줄바꿈을 넣으면 그대로 줄이 나뉜다 (지금 쓰는 항목은 없다) */
.card-desc { font-size: 12.5px; color: var(--sub); margin-top: 2px; line-height: 1.45; white-space: pre-line; }
.card-go { color: var(--faint); font-size: 15px; flex: none; align-self: center; }

.badge {
  font-size: 11px; font-weight: 700; padding: 1px 6px; border-radius: 5px;
  background: var(--accent-tint); color: var(--accent);
}
.badge.beta, .badge.demo { background: #F7EEDC; color: #8C6A28; }

.empty { text-align: center; color: var(--sub); font-size: 13.5px; padding: 16px 10px; }
.empty strong { display: block; font-size: 14.5px; color: var(--ink); margin-bottom: 3px; }

/* 경력·학력 */
/* 박스 없이 글자만 — 카드가 겹치면 목록이 무거워 보인다 */
.cv { list-style: none; margin: 0 0 6px; padding: 0; display: grid; gap: 7px; }
.cv li { padding: 0; }
.cv-role { font-size: 13.5px; font-weight: 700; }
.cv-meta { font-size: 12.5px; color: var(--sub); margin-top: 1px; }

/* 프로필 (나 구역) */
.profile { display: flex; align-items: center; gap: 12px; padding: 2px 2px 8px; }
.profile-img { width: 52px; height: 69px; flex: none; }
.profile-img img { width: 100%; height: auto; display: block; }
.profile-name { font-size: 17px; font-weight: 800; }
.profile-tag { font-size: 13.5px; color: var(--sub); margin-top: 1px; }
.profile-mail { font-size: 13px; margin-top: 5px; display: inline-block; color: var(--accent); }

/* ── 추천 픽 패널 — 버튼 위로 펼쳐진다 ───── */

.picks-wrap { position: relative; }

.picks-panel {
  position: absolute; left: 0; bottom: calc(100% + 10px); z-index: 45;
  width: min(340px, calc(100vw - 32px));
  background: var(--surface);
  border: 1px solid var(--line); border-radius: 16px;
  box-shadow: var(--shadow);
  padding: 13px;
  animation: panel-in .16s ease-out;
}
.picks-head {
  display: flex; align-items: center; justify-content: space-between;
  font-size: 14px; margin-bottom: 10px;
}
.picks-panel .cards { grid-template-columns: 1fr; }

/* ── 목록 모달 ───────────────────────────── */

.modal-backdrop {
  position: fixed; inset: 0; z-index: 60;
  background: rgba(20, 23, 15, .45);
  display: grid; place-items: end center;
}
@media (min-width: 700px) {
  .modal-backdrop { place-items: center; padding: 24px; }
}

.modal {
  background: var(--surface);
  width: 100%; max-width: 880px;
  max-height: 92dvh;
  border-radius: 18px 18px 0 0;
  display: flex; flex-direction: column;
  overflow: hidden;
  box-shadow: var(--shadow);
}
@media (min-width: 700px) { .modal { border-radius: 18px; max-height: 84dvh; } }

.modal-head { display: flex; align-items: center; gap: 10px; padding: 16px 16px 10px; }
.modal-head h2 { font-size: 16px; margin: 0; font-weight: 800; }
.modal-head .icon-btn { margin-left: auto; }

.modal-tools { padding: 0 16px 12px; display: grid; gap: 10px; }

/* 16px 미만이면 iOS가 입력창에 자동으로 확대해 들어간다 — 반드시 16px 이상 */
#search {
  width: 100%; background: var(--surface-2);
  border: 1px solid var(--line); border-radius: 10px;
  padding: 10px 12px; font-size: 16px;
}

.chips { display: flex; gap: 6px; flex-wrap: wrap; }
.chip {
  border: 1px solid var(--line); background: var(--surface-2);
  color: var(--sub); border-radius: 999px;
  padding: 5px 12px; font-size: 12.5px; font-weight: 600; cursor: pointer;
}
.chip[aria-pressed="true"] {
  background: var(--accent); border-color: var(--accent); color: var(--accent-ink);
}

.modal-body { overflow-y: auto; padding: 0 16px 20px; overscroll-behavior: contain; }
.modal-body .group-title { position: sticky; top: 0; background: var(--surface); padding-top: 8px; }

.no-result { text-align: center; color: var(--sub); padding: 28px 0; font-size: 14px; }

/* ── 푸터 ────────────────────────────────── */

/* 내용이 화면보다 짧을 때 푸터가 어중간하게 뜨지 않고 바닥에 붙도록 */
body { display: flex; flex-direction: column; min-height: 100dvh; }

.site-footer {
  width: 100%; max-width: 1440px;
  margin: 34px auto 0; padding: 18px 20px 28px;
  text-align: center;
  font-size: 13px; color: var(--sub);
}
.foot-name { margin: 0 0 2px; font-weight: 700; color: var(--ink); }
.foot-contact { margin: 0; }
.foot-contact a { color: var(--accent); }

/* ── 모바일 ──────────────────────────────── */

@media (max-width: 699px) {
  .topbar { padding: 22px 14px 14px; }
  .panel { padding: 13px; }
  .hint { margin-top: 12px; }

  /* 남는 세로 공간을 아래에 몰아두지 말고 위아래로 나눠 지도를 가운데 둔다 */
  .stage {
    flex: 1;
    display: flex; flex-direction: column; justify-content: center;
    padding: 8px 14px 20px;
  }

  /* 아래 여백이 휑하지 않게: 지도-힌트-푸터를 위로 모으고 푸터는 바닥에 붙인다 */
  .site-footer {
    margin-top: auto;
    padding: 20px 14px 28px;
    border-top: 1px solid var(--line);
  }

  .actions { gap: 8px; margin-top: 12px; }
  .list-btn, .picks-btn { padding: 10px 14px; font-size: 13px; }
  /* 좁은 화면에서는 버튼 위가 아니라 화면 아래에서 시트처럼 올라온다 */
  .picks-panel {
    position: fixed; left: 14px; right: 14px; bottom: 14px;
    width: auto; max-height: 66dvh; overflow-y: auto; z-index: 46;
  }
}

/* ── 좌표 조정 모드 (?tune) ──────────────── */

.tuning .spot { background: rgba(255, 90, 90, .18); border-color: rgba(255, 90, 90, .9); }
.tuning .spot-label { opacity: 1; transform: translateX(-50%); }
.tune-readout {
  position: fixed; left: 12px; bottom: 12px; z-index: 90;
  background: #14170F; color: #EFEFE7; font-size: 12px;
  font-family: ui-monospace, Menlo, monospace;
  padding: 8px 12px; border-radius: 8px; white-space: pre;
}

/* ── 아트북 팝업 — 지도와 똑같은 크기로 지도 위에 얹힌다 ── */

.book-overlay {
  position: absolute; inset: 0; z-index: 50;
  border-radius: var(--radius);
  padding: 10px 14px 12px;
  display: flex; flex-direction: column; gap: 8px;
  color: #EFEFEA;
  box-shadow: 0 18px 50px rgba(0, 0, 0, .45);
}

/* 어두운 바탕은 팝업이 아니라 이 가상요소가 맡는다. 팝업째로 페이드하면
   ① 날아오는 책까지 같이 흐려지고 ② 0.18초 만에 새까매져서 출발지(집)가
   안 보인다 — 검은 화면에서 나타나는 것처럼 보이는 게 그 때문이다.
   책이 날아오는 480ms 동안 지도가 보이게 천천히 덮는다. */
.book-overlay::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: #0B0C0B; border-radius: inherit;
  animation: veil-in .58s ease-out both;
}
/* 앞의 4분의 1은 거의 투명하게 버틴다 — 그 동안 지도와 집이 보여야
   "저 집에서 나왔다"가 읽힌다. 그 뒤에 덮는다. */
@keyframes veil-in {
  0%   { opacity: 0; }
  24%  { opacity: .07; }
  60%  { opacity: .62; }
  100% { opacity: 1; }
}
@keyframes veil-out { from { opacity: 1; } to { opacity: 0; } }

/* 위아래 UI는 책보다 조금 늦게 스며든다 — 같이 튀어나오면 비행이 안 읽힌다 */
.book-bar, .book-strip { animation: fade-in .5s ease-out both; }

.book-overlay.closing::before { animation: veil-out .24s ease-in both; }
.book-overlay.closing .book-bar,
.book-overlay.closing .book-strip { animation: fade-out .18s ease-in both; }
@keyframes fade-out { from { opacity: 1; } to { opacity: 0; } }

.book-bar { display: flex; align-items: center; gap: 10px; flex: none; }
.book-title { font-size: 14px; font-weight: 800; }
.book-count {
  margin-left: auto; font-size: 12.5px; color: #9A9E95;
  font-variant-numeric: tabular-nums;
}
.book-count b { color: #EFEFEA; }
.book-overlay .icon-btn {
  background: rgba(255, 255, 255, .08); border-color: rgba(255, 255, 255, .16);
  color: #EFEFEA; width: 28px; height: 28px;
}
.book-overlay .icon-btn:hover { background: rgba(255, 255, 255, .18); }

/* 책이 남는 높이를 다 쓰되 그 책의 비율을 지킨다 (--ratio는 JS가 권마다 넣는다) */
.book {
  position: relative;
  flex: 1; min-height: 0;
  width: min(100%, calc((100% - 0px) * 1));
  aspect-ratio: var(--ratio, 16 / 9);
  max-height: 100%;
  margin: 0 auto;
  perspective: 2000px;
  user-select: none; -webkit-user-select: none;
}
/* 좌우로 삐져나온 종이 두께 — 읽은 만큼 왼쪽이 두꺼워진다 */
.book::before, .book::after {
  content: ""; position: absolute; top: 2%; bottom: 2%;
  background: repeating-linear-gradient(90deg, #d9d6cd 0 1px, #a9a69d 1px 2px, #f0ede4 2px 3px);
  border-radius: 2px;
  box-shadow: 0 8px 18px rgba(0, 0, 0, .5);
  transition: width .35s ease;
}
.book::before { right: 100%; width: var(--read, 0px); border-radius: 3px 0 0 3px; }
.book::after  { left: 100%;  width: var(--left, 9px); border-radius: 0 3px 3px 0; }

/* 카탈로그는 책이 아니라 브로슈어다 — 종이 두께와 책등 그늘을 뺀다.
   세로 페이지는 가로 컨테이너 안에서 가운데 놓이므로, 컨테이너 가장자리에 붙는
   두께 장식이 페이지에서 멀리 떨어져 허공에 뜬 선으로 보인다. */
.book.flat::before, .book.flat::after,
.book.flat .leaf::before { display: none; }
/* 브로슈어는 종이 한 장만 난다. 컨테이너의 검은 판까지 같이 기울면
   날아오는 동안 기운 검은 슬래브가 그대로 보인다. */
.book.flat .leaf { background: none; box-shadow: none; }
.book.flat .leaf img { filter: drop-shadow(0 14px 34px rgba(0, 0, 0, .5)); }

.leaf {
  position: absolute; inset: 0;
  border-radius: 3px; overflow: hidden; background: #000;
  box-shadow: 0 14px 40px rgba(0, 0, 0, .6), 0 0 0 1px rgba(255, 255, 255, .07);
}
/* 책등 쪽 그늘 — 펼친 책처럼 */
.leaf::before {
  content: ""; position: absolute; inset: 0; z-index: 2; pointer-events: none;
  background: linear-gradient(90deg, rgba(0, 0, 0, .42), rgba(0, 0, 0, 0) 7%);
}
.leaf img { display: block; width: 100%; height: 100%; object-fit: contain; }

/* 넘어가는 장 — 뒷면이 보이면 사라진다 */
.leaf.flipping { z-index: 3; backface-visibility: hidden; -webkit-backface-visibility: hidden; }
.leaf.turn-next { transform-origin: left center;  animation: turn-next .78s cubic-bezier(.42, .02, .28, 1) forwards; }
.leaf.turn-prev { transform-origin: right center; animation: turn-prev .78s cubic-bezier(.42, .02, .28, 1) forwards; }
@keyframes turn-next {
  0%   { transform: rotateY(0deg)    translateZ(0);    filter: brightness(1); }
  18%  { transform: rotateY(-14deg)  translateZ(16px); filter: brightness(1.04); }
  100% { transform: rotateY(-172deg) translateZ(0);    filter: brightness(.42); }
}
@keyframes turn-prev {
  0%   { transform: rotateY(0deg)    translateZ(0);    filter: brightness(1); }
  18%  { transform: rotateY(14deg)   translateZ(16px); filter: brightness(1.04); }
  100% { transform: rotateY(172deg)  translateZ(0);    filter: brightness(.42); }
}
.leaf.flipping::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg, rgba(0, 0, 0, .5), rgba(0, 0, 0, 0) 45%);
  opacity: 0; animation: shade .78s ease-out forwards;
}
@keyframes shade { 0% { opacity: 0; } 45% { opacity: 1; } 100% { opacity: .2; } }

/* 좌우 넘김 영역 */
.zone {
  position: absolute; top: 0; bottom: 0; width: 26%; z-index: 5;
  display: grid; place-items: center;
  background: none; border: 0; padding: 0; color: inherit; cursor: pointer;
  opacity: 0; transition: opacity .18s ease;
}
.zone.prev { left: 0; }
.zone.next { right: 0; }
.book:hover .zone:not(:disabled) { opacity: .55; }
.zone:hover:not(:disabled) { opacity: 1 !important; }
.zone:disabled { cursor: default; }
.zone span {
  width: 40px; height: 40px; border-radius: 50%;
  background: rgba(12, 13, 12, .72); border: 1px solid rgba(255, 255, 255, .16);
  display: grid; place-items: center; font-size: 16px;
}

/* 하단 쪽 띠 */
.book-strip {
  flex: none;
  display: flex; gap: 6px; justify-content: center;
  overflow-x: auto; scrollbar-width: none;
}
.book-strip::-webkit-scrollbar { display: none; }
.book-strip .thumb {
  flex: none; width: 58px; aspect-ratio: var(--ratio, 16 / 9);
  border-radius: 3px; overflow: hidden; padding: 0;
  opacity: .36; transition: opacity .18s ease, outline-color .18s ease;
  outline: 2px solid transparent; outline-offset: 2px;
}
.book-strip .thumb img { display: block; width: 100%; height: 100%; object-fit: cover; }
.book-strip .thumb:hover { opacity: .75; }
.book-strip .thumb[aria-current="true"] { opacity: 1; outline-color: #8FD6A2; }

/* 세로로 긴 책은 넓은 화면에서도 지도 안에 가두면 높이가 모자라 글씨가 작아진다.
   지도 대신 화면 전체를 쓴다 (JS가 세로 비율을 보고 .full을 붙인다). */
@media (min-width: 700px) {
  .book-overlay.full {
    position: fixed; inset: 0; z-index: 70;
    border-radius: 0; padding: 14px 18px 16px;
    justify-content: center;
  }
}

@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }

/* 좁은 화면에서는 화면 전체를 쓴다 — 지도 크기로는 책이 너무 작아진다 */
@media (max-width: 699px) {
  .book-overlay {
    position: fixed; inset: 0; z-index: 70;
    border-radius: 0; padding: 12px;
    justify-content: center;
  }
  .book { flex: none; }
  .book-strip { justify-content: flex-start; }
  .zone { opacity: .35; }
}

@media (prefers-reduced-motion: reduce) {
  .book-overlay { animation: none; }
}
