/* 호텔 매핑 검수 — 화면 꾸미기. 애니메이션은 전부 CSS(0.5초 이내).
   색·크기 값은 여기 적지 않는다 — 전부 tokens.css 의 이름을 부른다(설계서 9-1 5번 12번). */
* { box-sizing: border-box; }
[hidden] { display: none !important; }   /* display:flex 같은 규칙이 hidden 을 이기지 못하게 */
html, body { margin: 0; min-height: 100vh; background: var(--bg); color: var(--ink); font: 15px/1.5 "Noto Sans KR", "Malgun Gothic", "Apple SD Gothic Neo", system-ui, sans-serif; }  /* min-height 없으면 body.bg-scene 바탕 그림이 카드 높이만큼만 칠해지고 그 아래는 --bg 회색이 드러남(태스크27, docs/시각검증_2026-09-03.md 1번 항목) */
/* 화면별 바탕(설계서 §5-1·§5-4) - 그 화면(login.js·collection.js)이 mount 될 때만 body 에 클래스를 붙이고, 떠날 때 지운다 */
body.bg-login { background-image: linear-gradient(135deg, var(--login-bg-1), var(--login-bg-2) 55%, var(--login-bg-3)); }
body.bg-collection { background-color: var(--collection-bg); }
/* 시안 배경(설계서 §4-2 · 개정 1) - 그 화면(countries.js·board.js)이 켤 때만 body 에 붙이고 떠날 때
   지운다(bg-login·bg-collection 과 같은 관례). 겹을 따로 띄우지 않고 body 의 배경 그림 두 장으로 깐다 -
   아래가 풍경, 위가 흰 막이다. 배경 그림은 누르는 것을 가로채지 않으므로 "배경이 글자·단추를 먹는다"
   (설계서 §7 함정 1)가 아예 생길 수 없고, 옅은 정도는 막의 진하기 숫자 하나로 잰다. */
body.bg-scene { background-image: var(--scene-veil), var(--scene-url); background-size: cover, cover; background-position: center top, center top; background-repeat: no-repeat, no-repeat; background-attachment: fixed, fixed; }
body.scene-strong { --scene-veil: var(--veil-clear); }
body.scene-faint { --scene-veil: var(--veil-heavy); }
/* 제목 줄(.page-head)은 배경 위에 놓이는 글자라 흰 띠를 깔아 대비를 지킨다(요소를 지우지 않고,
   지금 있는 .page-head 에 카드 옷만 입힌다). ⚠ 2026-09-10: .page-head 밖에도 배경 위에 바로
   놓이는 글자가 있다(도감의 <h2>나라별 캐릭터</h2> — 실측 대비비 5.76:1 로 읽기는 된다). */
body.bg-scene .page-head { background: var(--card); border-radius: var(--radius); box-shadow: var(--shadow); padding: 10px 16px; }
a { color: var(--primary); text-decoration: none; }
/* 숫자·영문 제목은 Poppins(설계서 §4-1). Poppins 에는 한글 글자가 없어서, 같은 자리에 한글이
   섞이면 글자마다 뒤의 Noto Sans KR 로 물러난다 - 그래서 둘째를 반드시 Noto Sans KR 로 둔다. */
.num, .big, .tile .huge, .energy .ring-text, .board-head .progress-text, .page .title,
.grid2 .pet-tile h3 { font-family: "Poppins", "Noto Sans KR", "Malgun Gothic", sans-serif; }
button { font: inherit; }
main#app { max-width: 1120px; margin: 0 auto; padding: 20px 16px 60px; }

/* 검수 표 화면만 내용을 창 세로 가운데로 내린다(사용자 결정 10, 2026-09-08 축소판 - 「왜 다 위에 붙어
   있어?」). board.js 가 이 화면에 들어올 때만 body 에 screen-board 를 붙이고 떠날 때 뗀다(bg-scene 과
   같은 관례). 국가 고르기 화면은 이번 범위 밖이라 그대로 둔다. 근거와 실측은 설계서 §11 개정 2.
   - 가운데로 모으는 방법은 auto 여백이다. 남는 자리가 없으면 auto 여백은 0이 되어 예전처럼 위부터
     놓인다. (이 짜임에서는 main#app 이 내용만큼 늘어나 남는 자리가 음수로 가지 않으므로
     justify-content:center 로 바꿔도 윗부분이 안 잘린다 - 적대적 검수가 실측으로 확인했다. 그래도
     auto 여백을 쓰는 까닭은, 나중에 main#app 에 높이 제한이 생겨 남는 자리가 음수가 되는 날에도
     안전한 쪽이기 때문이다.)
   - .board 의 자리잡기(min-height)는 **가운데 정렬이 새로 만든 흔들림을 줄이는 장치**다. 고치기 전에는
     내용이 늘 맨 위에 붙어 머리줄 y 가 69 로 고정이었다(흔들림 0). 가운데로 모으면 표 카드 높이가
     호텔마다 달라 머리줄이 따라 움직인다(자리잡기 없이 실측 108~160, 52px 폭). 그래서 흔한 높이만큼
     자리를 미리 잡아 그 안에서는 머리줄이 한 자리에 서 있게 한다 - 칩 두 줄(실사용 기본) 상태로
     높이별 실측: 호텔 94.3%가 y=108 에 고정되고, 표가 아주 긴 5.7%에서만 74~97 로 올라간다(폭 34px).
     값 733 = 머리줄 68 + 틈 14 + 표 카드 570 + 틈 14 + 칩 띠 두 줄 67. 570 은 진짜 베트남 자료
     244건을 전수로 재어 나온 90% 지점이다(범위 482~638 · 549 는 85.25%밖에 안 돼 처음 잡았던 712 를
     검수 지적으로 올렸다).
     흰 카드(.page)가 아니라 그 바깥 덩어리에 주므로 카드 안에는 빈 자리가 안 생기고, 남는 만큼은
     배경이 비치는 투명한 자리가 된다.
   - clamp 로 「창에 들어가는 만큼만」 자리를 잡는다. 89 = 위 메뉴 49 + main 위아래 여백 20+20.
     ⚠ min(…, 100%) 로 적으면 안 된다 - 그 자리의 100% 는 기준 높이를 못 찾아 0으로 떨어지고
     자리잡기가 통째로 사라진다(2026-09-08 실측). 창 높이로 자르면 ① 어느 창 높이에서도 자리잡기가
     스크롤을 새로 만들지 않고 ② 창을 줄일 때 특정 지점에서 머리줄이 툭 튀지도 않는다(문턱을 두는
     방식은 그 지점에서 최대 67px 튄다 - 검수가 실측으로 잡아 이 방식으로 바꿨다).
     알림 띠(#banner)가 떠 있는 동안에는 그 높이만큼 89 가 모자라 띠 높이만큼 스크롤이 생길 수 있다 -
     잠깐 떴다 사라지는 띠라 그대로 둔다.
   - 아래 안쪽 여백은 이 화면에서만 위와 같은 20px 로 맞춘다(60이면 가운데가 40px 아래로 치우친다). */
body.screen-board { display: flex; flex-direction: column; min-height: 100vh; }
body.screen-board main#app { flex: 1; display: flex; flex-direction: column; padding-bottom: 20px; }
body.screen-board .board { margin-block: auto; min-height: clamp(0px, calc(100vh - 89px), 733px); }
.muted { color: var(--muted); } .small { font-size: 13px; } .center { text-align: center; }
.error { color: var(--danger); }

/* 상단 메뉴 */
.topbar { display: flex; align-items: center; gap: 20px; padding: 10px 20px; background: var(--card); border-bottom: 1px solid var(--line); position: sticky; top: 0; z-index: 5; }
.topbar .brand { font-weight: 700; color: var(--ink); }
.topbar .nav a { margin-right: 14px; color: var(--muted); padding: 6px 4px; border-bottom: 2px solid transparent; }
.topbar .nav a.active { color: var(--primary); border-color: var(--primary); }
.topbar .me { margin-left: auto; display: flex; align-items: center; gap: 8px; font-size: 14px; }
.topbar .me a { font-size: 12px; color: var(--muted); }

/* 띠·알림·덮개 */
.banner { padding: 10px 20px; text-align: center; font-weight: 600; }
.banner.error { background: var(--tone-red-bg); color: var(--danger); } .banner.warn { background: var(--tone-amber-bg); color: var(--warn); } .banner.info { background: var(--band-info-bg); color: var(--primary); }
.band { padding: 10px 14px; border-radius: 10px; margin: 8px 0; font-weight: 600; }
.band.error { background: var(--tone-red-bg); color: var(--danger); } .band.warn { background: var(--tone-amber-bg); color: var(--warn); }
.band.info { background: var(--band-info-bg); color: var(--band-info-fg); display: flex; align-items: center; gap: 12px; justify-content: space-between; }
.toast { position: fixed; left: 20px; bottom: 20px; background: var(--toast-bg); color: var(--primary-ink); padding: 12px 16px; border-radius: 12px; box-shadow: var(--shadow); display: flex; gap: 12px; align-items: center; z-index: 20; animation: rise .25s ease; }
.toast .link { background: none; border: 0; color: var(--toast-link-fg); cursor: pointer; font-weight: 700; }
/* 축하 덮개(설계서 §4-1·§4-3·§5-5, 태스크25) - 단계 오름 때 board.js 의 stageUpScreen() 만 이 자리를 쓴다
   (다른 확인창이 아직 없다). 뒤는 부화와 같은 어두운 덮개(--overlay-bg), 카드는 축하 초록(--celebrate-bg)
   이다 - 값은 tokens.css 한 곳에만 있다(9-1 5번·12번 함정, test_화면_꾸미기에_색을_직접_적지_않았다 가
   주석까지 정규식으로 훑어 검사한다). 폭은 40%로 딱 고정하지 않고(내용 길이가 사람 이름마다 달라진다)
   90vw 와 480px 중 작은 값으로 - 넓은 화면에서 폭이 과하게 늘어나지 않으면서도 폰 폭(--pill-ratio 등)을
   그대로 쓰지 않는다(9-1 6번 함정과 같은 취지). */
.overlay { position: fixed; inset: 0; background: var(--overlay-bg); display: flex; align-items: center; justify-content: center; z-index: 30; }
.overlay-card {
  background: var(--celebrate-card); color: var(--celebrate-ink); border-radius: 20px; padding: 32px 40px; box-shadow: var(--shadow);
  width: min(90vw, 480px); position: relative; overflow: hidden; text-align: center; animation: pop .3s ease;
}
.overlay-card .muted { color: var(--celebrate-ink); opacity: .68; }
/* 흰 알약 단추(9-1 함정 6번) - 이 카드 자신의 폭(위에서 최대 480px로 이미 제한) 기준 83.5% 라 화면 폭의 절반을 넘지 않는다 */
.overlay-card .btn.primary {
  height: var(--pill-h); border-radius: var(--pill-r); width: var(--pill-ratio); padding: 0 18px; margin: 4px auto 0;
  display: flex; align-items: center; justify-content: center; background: var(--celebrate-bg); color: var(--card); border-color: var(--celebrate-bg); box-shadow: var(--shadow);
}

/* 카드·단추·꼬리표 */
.card { background: var(--card); border-radius: var(--radius); box-shadow: var(--shadow); padding: 24px; }
.btn { display: inline-block; border: 1px solid var(--line); background: var(--card); color: var(--ink); padding: 10px 18px; border-radius: 10px; cursor: pointer; font-weight: 600; }
.btn.primary { background: var(--primary); color: var(--primary-ink); border-color: var(--primary); }
.btn.hold { background: var(--hold); color: var(--primary-ink); border-color: var(--hold); }
.btn:disabled { background: var(--line); color: var(--disabled-fg); border-color: var(--line); cursor: not-allowed; }
.tag { display: inline-block; font-size: 12px; padding: 2px 8px; border-radius: 999px; background: var(--tag-default-bg); color: var(--tag-default-fg); margin-right: 6px; white-space: nowrap; }
.tag.ours { background: var(--tone-green-bg); color: var(--tone-green-fg); } .tag.ai { background: var(--tone-amber-bg); color: var(--tag-ai-fg); } .tag.del { background: var(--tone-red-bg); color: var(--tone-red-fg); }
.tag.warn { background: var(--tone-orange-bg); color: var(--tone-orange-fg); } .tag.chosen { background: var(--band-info-bg); color: var(--tag-chosen-fg); font-weight: 700; } .tag.ai-was { background: var(--tone-gray-bg); color: var(--tone-gray-fg); }
.tag.edit { background: var(--tag-edit-bg); color: var(--tag-edit-fg); }
input[type=text], input[type=email], input[type=number], input:not([type]), select { font: inherit; padding: 9px 12px; border: 1px solid var(--line); border-radius: 10px; width: 100%; background: var(--card); }
input.error { border-color: var(--danger); background: var(--input-error-bg); }
/* 읽기 전용 칸(관리 화면의 회사 도메인 - 서버가 바꾸기를 거절한다 §6-3) - 못 고친다는 것이 보이게 흐리게 */
input[readonly] { background: var(--tone-gray-bg); color: var(--muted); cursor: not-allowed; }
label { display: block; font-size: 13px; color: var(--muted); }

/* 입장 */
.login-card { max-width: 420px; margin: 80px auto; text-align: center; border-radius: 20px; }
.login-card h1 { font-size: 24px; margin: 0 0 8px; }
.login-card form { display: grid; gap: 12px; margin-top: 20px; }
/* 흰 알약 단추(설계서 §4-2 실측값) - 이 화면의 확정 단추(들어가기)에 적용.
   흰 바탕 + 이 화면 계열(파랑) 글씨, 폰 폭은 상자(카드) 폭의 83.5% */
.login-card .btn.primary {
  height: var(--pill-h); border-radius: var(--pill-r); width: var(--pill-ratio); padding: 0 18px;
  margin: 0 auto var(--pill-gap); display: flex; align-items: center; justify-content: center;
  background: var(--card); color: var(--primary); border-color: var(--card); box-shadow: var(--shadow);
}
/* 잠긴 단추는 이 카드 안에서도 잠겨 보여야 한다 - 위 흰 알약 규칙이 .btn:disabled 보다 명시도가 높아(0,3,0 > 0,2,0)
   「시작하기」(이름 빈칸)와 「들어가기」(보내는 동안)가 켜진 것처럼 그려졌다(2026-09-29 · test_48). 색은 .btn:disabled 와 같은 토큰. */
.login-card .btn.primary:disabled { background: var(--line); color: var(--disabled-fg); border-color: var(--line); }
/* 구글 단추 자리(설계서 2026-10-21 §5-1) - 구글 스크립트가 이 안에 단추를 그린다. 들어가기 단추(흰 알약)와 같은 폭 ·
   높이 · 아래 간격을 미리 잡아, 불러오는 동안과 그린 뒤에 카드 높이가 출렁이지 않게 한다. 색은 구글 단추 자신의 것이다. */
.login-card .google-btn {
  width: var(--pill-ratio); min-height: var(--pill-h); margin: 20px auto var(--pill-gap);
  display: flex; align-items: center; justify-content: center;
}
.egg-stage { display: flex; justify-content: center; margin: 20px 0; }

/* 빛줄기 배경(설계서 §4-3 예외 - 부화 연출은 화면 끝까지, §5-1 캐릭터 탄생은 알 상자 안에 작게).
   .rays-bg 를 붙인 요소 자신이 위치 기준이 되고, 그 요소의 테두리 둥글기를 그대로 물려받는다. */
.rays-bg { position: relative; }
.rays-bg::before {
  content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  background: repeating-conic-gradient(from 0deg, var(--hatch-bg) 0deg 8deg, transparent 8deg 20deg);
  opacity: .3;
}
.egg-stage.rays-bg { border-radius: 50%; overflow: hidden; }

/* 캐릭터(설계서 §6-1) - 그림 파일(png)은 자를 때 이미 세로 채움 비율·발밑 위치를 맞춰
   뒀으므로(tools/cutout.py), 화면에서는 세로를 상자에 꽉 채우되(규칙 1) 그러다 가로가
   상자를 넘으면 그때만 가로 기준으로 줄인다(규칙 2 원문 그대로 - 이전 주석은 이 문장을
   거꾸로 적어 "넘으면 자연스레 벗어난다"고 해 뒀었다. max-height 와 max-width 를 함께
   100% 로 주면, width:auto·height:auto 인 그림은 두 제약을 동시에 지키는 쪽(둘 중 더
   작아지는 쪽)으로 브라우저가 줄인다 - 알파카처럼 세로로 긴 것은 그대로 세로 100%,
   소·부엉이처럼 옆으로 넓은 것은 가로 100% 가 기준이 된다). img 박스 자체가 실제로
   보이는 그림 크기와 같아지므로, .char 의 align-items:flex-end 로 아래쪽 가운데 기준이
   그대로 유지된다(규칙 3 - 태스크28 재검수 ①, tests/test_screens.py 의 test_21 이 8종
   전부 x 상자 6칸에서 상자를 안 넘는지·말풍선과 안 겹치는지·발밑이 맞는지를 잰다).
   색 6종은 더 이상 currentColor 가 아니라 파일 자체가 미리 색을 입고 있다(§10 미결 1). */
.char { display: inline-flex; align-items: flex-end; justify-content: center; width: var(--size, 64px); height: var(--size, 64px); vertical-align: middle; position: relative; overflow: visible; }
.char img { max-height: 100%; max-width: 100%; height: auto; width: auto; display: block; }
.char.tap img { animation: tap .35s ease 5; } .char.born img { animation: char-hop .62s cubic-bezier(.2, .85, .3, 1.5); } .char.crack img { animation: shake .3s ease 4; }
.char-row { display: flex; align-items: center; gap: 10px; margin: 10px 0; }
.bubble { position: relative; background: var(--card); border: 1px solid var(--line); border-radius: 12px; padding: 6px 10px; font-size: 13px; box-shadow: var(--shadow); }
.bubble.static::before { content: ""; position: absolute; left: -6px; top: 12px; border: 6px solid transparent; border-right-color: var(--card); border-left: 0; }
.board-head .head-char .bubble { position: absolute; right: 56px; top: 0; white-space: nowrap; opacity: 0; transition: opacity .15s; pointer-events: none; }
.board-head .head-char .bubble.show { opacity: 1; }

/* 부화 넓은 화면(설계서 §4-3·§5-3, 태스크24) - main(#app, max-width 1120px) 안에 넣지만 position:fixed 라
   그 폭에 갇히지 않고 화면 전체가 기준이 된다(위 어떤 조상도 transform 등으로 containing block 을
   새로 만들지 않는다). 뒤를 어둡게 덮고(.hatch-cover) 가운데 40%x38% 상자(.hatch-stage)를 띄운다.
   상자 안이 폰 화면의 세로 구도(.egg-stage 재사용)가 된다. */
.hatch-cover { position: fixed; inset: 0; background: var(--overlay-bg); display: flex; align-items: center; justify-content: center; z-index: 25; }
/* 빛줄기(9-1 함정 표 §4-3 예외) - 부화 연출만 상자 밖 화면 끝까지 퍼진다. .rays-bg(login.js 의 작은 탄생
   연출)와 같은 무늬를 화면 전체 크기로 다시 쓴다 - 값을 새로 적지 않고 --hatch-bg 를 그대로 부른다. */
.hatch-rays { position: absolute; inset: 0; pointer-events: none; background: repeating-conic-gradient(from 0deg, var(--hatch-bg) 0deg 8deg, transparent 8deg 20deg); opacity: .25; }
.hatch-stage {
  position: relative; width: var(--stage-w); height: var(--stage-h); min-width: 300px; min-height: 260px;
  background: var(--hatch-bg); color: var(--primary-ink); border-radius: var(--radius); box-shadow: var(--shadow);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 14px; padding: 24px; overflow: hidden;
}
.hatch-stage p { margin: 0; max-width: 85%; }
/* 흰 알약 단추(9-1 함정 6번) - 상자 자신의 폭 기준 83.5% 라 화면 폭의 절반을 넘지 않는다(폰 폭 그대로 적용 금지) */
.hatch-stage .btn.primary {
  height: var(--pill-h); border-radius: var(--pill-r); width: var(--pill-ratio); padding: 0 18px; margin-top: 2px;
  display: flex; align-items: center; justify-content: center; background: var(--card); color: var(--hatch-bg); border-color: var(--card); box-shadow: var(--shadow);
}

/* 색종이(설계서 §5-3 부화 완료·§5-5 축하, 태스크24·25 공용 무늬) - 위치·기울기·시작 시각만 자바스크립트가
   무작위로 정하고(web/js/scene.js 의 confettiHtml), 색은 여기서 캐릭터 색 6종(--c0~5)을 그대로
   돌려쓴다(새 색을 만들지 않는다 - 9-1 5번 함정). 담는 칸(.hatch-stage·.overlay-card)이 position:relative
   라 이 겹이 그 칸 안에서만 떨어진다. */
.confetti-layer { position: absolute; inset: 0; overflow: hidden; pointer-events: none; }
/* 축하 덮개에서는 카드 안이 아니라 **화면 전체**에 흩날린다(2026-09-08 사용자 지적 - 카드에
   갇혀 있어 눈에 안 띄었다. .overlay-card 의 overflow:hidden 이 잘라내고 있었다). 참고로 삼은
   축하 화면들(Alan·Nibble·Ahead)이 전부 화면 전체를 쓴다. board.js 가 이 겹을 카드 **밖**
   (.overlay 바로 밑)에 넣으므로 아래 규칙이 걸리고, 떨어지는 거리와 시간이 화면 크기에 맞게 늘어난다.
   카드보다 DOM 앞에 있어 글자를 가리지 않는다. */
.overlay > .confetti-layer { --fall: 104vh; --fall-time: 2.4s; }
.confetti {
  position: absolute; top: -6%; left: var(--x, 50%); width: 7px; height: 12px;
  background: var(--c0); transform: rotate(var(--r, 0deg));
  animation: confetti-fall var(--fall-time, 1.4s) ease-in var(--d, 0s) both;
}
.confetti:nth-child(6n+2) { background: var(--c1); } .confetti:nth-child(6n+3) { background: var(--c2); }
.confetti:nth-child(6n+4) { background: var(--c3); } .confetti:nth-child(6n+5) { background: var(--c4); }
.confetti:nth-child(6n)   { background: var(--c5); }

/* 캐릭터 뒤에서 사방으로 뻗는 햇살 무늬(2026-09-08 사용자 지적 「밍숭맹숭하다」 · 참고 Me+·Kit).
   그림 파일을 새로 만들지 않고 CSS 무늬 하나로 그린다 - 무늬와 오려 내는 틀은 색이라 tokens.css
   에 있다(--burst-rays·--burst-mask). 아주 천천히 돌아 눈에 거슬리지 않는다. */
.burst { position: relative; display: flex; align-items: center; justify-content: center; margin: 6px 0 2px; }
.burst::before {
  content: ''; position: absolute; width: 340px; height: 340px; border-radius: 50%; pointer-events: none;
  background: var(--burst-rays);
  -webkit-mask-image: var(--burst-mask); mask-image: var(--burst-mask);
  animation: burst-spin 24s linear infinite;
}
.burst > .char { position: relative; }
@keyframes burst-spin { to { transform: rotate(1turn); } }

/* 진화 화면의 전·후 나란히(설계서 §12-7) - 왼쪽이 진화 전(작게), 오른쪽이 진화 후(크게).
   가운데 화살표는 글자다. 발밑을 맞춰야 「커졌다」가 눈에 보이므로 align-items:flex-end 다.
   .before / .after 는 flex 자식이라 저절로 덩어리(block)가 되어 .lv 가 그림 아래에 놓인다.
   햇살(.burst)은 「후」쪽만 감싼다 - 340px 원이 전·후 가운데에 오면 커진 쪽 강조가 흐려진다. */
.stage-up-pair { display: flex; align-items: flex-end; justify-content: center; gap: 18px; }
.stage-up-pair .lv { display: block; text-align: center; font-weight: 600; margin-top: 6px; }
.stage-up-pair .arrow { font-size: 28px; align-self: center; }
.stage-up-pair .before { opacity: 0.75; }

/* 캐릭터가 아래에서 톡 뛰어올라 등장한다(2026-09-08 사용자 지적 · 참고 Duolingo). 전에는 pop
   .5s ease 로 그냥 커지기만 했다. 단계 오름(board.js)과 첫 등장(login.js) 두 자리가 이걸 쓴다. */
@keyframes char-hop {
  0%   { transform: translateY(30px) scale(.55); opacity: 0; }
  55%  { transform: translateY(-16px) scale(1.08); opacity: 1; }
  78%  { transform: translateY(0) scale(.97); }
  100% { transform: translateY(0) scale(1); opacity: 1; }
}

/* 도감에서 내 캐릭터를 누르면 톡 뛴다(2026-09-10 §5-3). 새 움직임을 만들지 않고 char-hop 을 그대로 쓴다.
   명시도를 .char.born img(:143)보다 높게 잡아, 같은 명시도끼리 뒤 선언이 animation 을 통째로 덮는 사고를 피한다. */
.collection-me .char.person { cursor: pointer; }
.collection-me .char.person.hop img { animation: char-hop .62s cubic-bezier(.2, .85, .3, 1.5); }

/* 국가 선택 */
.page-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 16px; }
.cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 16px; }
.card.country header { display: flex; justify-content: space-between; align-items: center; }
.card.country h2 { margin: 0; font-size: 20px; }
.progress { height: 14px; background: var(--line); border-radius: 999px; overflow: hidden; margin: 12px 0 6px; }
.progress .bar { height: 100%; background: var(--primary); transition: width .3s; }
.big { font-size: 22px; font-weight: 700; margin: 4px 0; }
.card.country.complete { border: 2px solid var(--match); }
.card.country.complete .stamp-badge { display: inline-flex; align-items: center; gap: 4px; }
.card.country.complete .stamp-badge::before {
  content: "✓"; display: inline-flex; align-items: center; justify-content: center;
  width: 14px; height: 14px; border-radius: 50%; background: var(--tone-green-fg); color: var(--card);
  font-size: 10px; font-weight: 900; line-height: 1;
}
/* 동그랗게(설계서 §5-3, 10_완료표시 참고 - 태스크28 재검수 ④): 각진 6px 대신 알약(pill) 모양으로.
   .tag·.badge·.recent .chip 등 이 저장소의 다른 「동그란 배지」들과 같은 999px 관례를 따른다(9-1
   5번 함정과 같은 취지 - 새 값을 안 만들고 이미 쓰던 반지름 값을 그대로 재사용). */
.stamp-badge { font-size: 12px; font-weight: 700; padding: 3px 8px; border-radius: 999px; background: var(--tone-green-bg); color: var(--tone-green-fg); }
.stamp-badge.match { background: var(--tone-green-bg); color: var(--tone-green-fg); } .stamp-badge.changed { background: var(--tone-orange-bg); color: var(--tone-orange-fg); }
.stamp-badge.none { background: var(--tone-gray-bg); color: var(--tone-gray-fg); } .stamp-badge.hold { background: var(--badge-hold-bg); color: var(--badge-hold-fg); }
.energy { display: flex; align-items: center; gap: 8px; }
.energy .ring { width: 80px; height: 48px; }
.energy .ring-text { font-size: 14px; } .energy .ring-text b { font-size: 18px; }

/* 매핑 보드 */
.board-head { display: flex; align-items: center; gap: 18px; background: var(--card); border-radius: var(--radius); padding: 10px 16px; box-shadow: var(--shadow); margin-bottom: 14px; }
.board-head .country { font-weight: 700; font-size: 18px; }
.board-head .head-char { margin-left: auto; position: relative; display: flex; align-items: center; gap: 8px; }
.page-wrap { perspective: 1400px; }
.page { background: var(--card); border-radius: var(--radius); box-shadow: var(--shadow); padding: 22px 26px; position: relative; transform-origin: left center; min-height: 320px; }
.page.entering { animation: deal-in .3s cubic-bezier(.2, .8, .3, 1.1); }
.page.leaving { animation: fly-to-pile .38s cubic-bezier(.4, 0, .9, .6) forwards; transform-origin: center; box-shadow: var(--fly-shadow); }
/* 도장이 닿는 순간 표가 살짝 흔들린다(설계서 §4-3 개정 1 걸음 2). board.js 가 0.26초 뒤에 뗀다 */
.page.slammed { animation: table-shake .18s ease .08s; }
.page .title { font-size: 26px; margin: 4px 0 14px; }
table.compare { width: 100%; border-collapse: collapse; table-layout: fixed; }
table.compare th { text-align: left; font-size: 12px; color: var(--muted); padding: 6px 8px; border-bottom: 1px solid var(--line); }
table.compare td { padding: 10px 8px; border-bottom: 1px solid var(--line); vertical-align: top; word-break: break-word; }
table.compare th:nth-child(1), table.compare td:nth-child(1) { width: 190px; }
table.compare th:nth-child(4), table.compare td:nth-child(4) { width: 110px; }
table.compare th:nth-child(5), table.compare td:nth-child(5) { width: 80px; }
table.compare th:nth-child(6), table.compare td:nth-child(6) { width: 150px; }
tr.strong td { font-weight: 600; color: var(--ink); }
tr.weak td { color: var(--disabled-fg); }
tr.weak .tag { opacity: .7; }
tr.ours td { background: var(--row-ours-bg); }
tr.chosen td { background: var(--row-chosen-bg); font-weight: 700; color: var(--ink); }
tr.excluded td { color: var(--row-faint-fg); text-decoration: line-through; }
tr.missing td { color: var(--row-faint-fg); }
td.pick label { display: inline; color: inherit; font-size: inherit; cursor: pointer; }
td.pick input { margin-right: 4px; }
.eye { border: 0; background: none; cursor: pointer; font-size: 15px; padding: 0 4px; }
.reason { display: grid; grid-template-columns: 2fr 1fr; gap: 12px; margin: 16px 0 8px; }
.actions { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-top: 10px; }
.actions .keys { font-size: 12px; margin-left: auto; }
.stamp-layer { position: absolute; inset: 0; display: none; align-items: center; justify-content: center; pointer-events: none; z-index: 3; }
.stamp-layer.show { display: flex; }
.stamp { font-size: 44px; font-weight: 900; padding: 10px 28px; border: 6px solid; border-radius: 16px; transform: rotate(-12deg); background: var(--stamp-overlay-bg); animation: stamp-slam .26s cubic-bezier(.2, .9, .25, 1.4); letter-spacing: .1em; }
.stamp.match { color: var(--match); border-color: var(--match); } .stamp.changed { color: var(--changed); border-color: var(--changed); }
.stamp.none { color: var(--none); border-color: var(--none); } .stamp.hold { color: var(--stamp-hold); border-color: var(--stamp-hold); }
.recent { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 14px; align-items: center; }
.recent .chip { border: 1px solid var(--line); background: var(--card); border-radius: 999px; padding: 4px 10px; cursor: pointer; font-size: 13px; }
.recent .chip::before { content: ""; display: inline-block; width: 9px; height: 9px; border-radius: 50%; margin-right: 6px; background: var(--none); }
/* 방금 쌓인 칸이 톡 튄다(설계서 §4-4 개정 1 걸음 4). 「쌓였다」가 눈에 보여야 처리한 느낌이 난다 */
.recent .chip.just-added { animation: chip-pop .32s cubic-bezier(.2, .9, .3, 1.5); }
/* 진행 숫자가 한 칸 오를 때 톡 튄다. b 는 원래 줄글 안 글자라 transform 이 안 먹으므로 상자로 만든다 */
.board-head .progress-text b { display: inline-block; }
.board-head .progress-text.bumped b { animation: count-pop .34s ease; }
.recent .chip.match::before { background: var(--match); } .recent .chip.changed::before { background: var(--changed); } .recent .chip.hold::before { background: var(--stamp-hold); }

/* 요약·통계·도감·관리 */
table.list { width: 100%; border-collapse: collapse; background: var(--card); border-radius: var(--radius); overflow: hidden; box-shadow: var(--shadow); }
table.list th, table.list td { padding: 10px 12px; border-bottom: 1px solid var(--line); text-align: left; vertical-align: top; }
table.list th { font-size: 12px; color: var(--muted); }
table.list tr.mine { cursor: pointer; } table.list tr.mine:hover td { background: var(--row-chosen-bg); }
/* 관리 · 나라 목록의 진행 칸(2026-10-22) - 같은 줄의 입력칸 · 고르기 칸과 높이 가운데를 맞추고 숫자가 줄바꿈되지 않게 */
#countries-table td.c-progress { vertical-align: middle; white-space: nowrap; }
.tiles { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 16px; margin-bottom: 20px; }
.tile { background: var(--card); border-radius: var(--radius); padding: 18px; box-shadow: var(--shadow); }
.tile h2 { margin: 0; font-size: 16px; } .tile .huge { font-size: 40px; font-weight: 800; margin: 6px 0; }
.badge { font-size: 12px; padding: 2px 8px; border-radius: 999px; font-weight: 700; }
.badge.yes { background: var(--tone-green-bg); color: var(--tone-green-fg); } .badge.no { background: var(--tone-red-bg); color: var(--tone-red-fg); }
.section { margin: 18px 0; }
.section h2 { font-size: 18px; margin: 0 0 10px; }
.grid2 { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 12px; }
.form-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 12px; }
.inline { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.inline input, .inline select { width: auto; }
.collection-me { display: flex; gap: 20px; align-items: center; }
/* 다음 단계까지 진행 막대(설계서 §5-4 - collection.js 가 값을 채운다). .progress 를 그대로 재사용해
   굵고 둥근 모양(태스크23)이 이 카드 안에서도 같다 - 값만 다르고 규칙은 하나. 태스크32(병합 전
   검수 권고 ⑤-1) - max-width 만 있고 margin 이 없어 카드(collection-me·overlay-card) 왼쪽에
   붙어 있었다(카드 가운데와 막대 가운데가 안 맞음 - "가득"·"단계 오름" 두 화면 다 board.js 가
   이 클래스를 그대로 쓴다). .progress 의 세로 margin(12px 0 6px)은 그대로 두고 좌우만 채워
   가운데로 보낸다. */
.stage-progress { max-width: 260px; margin-left: auto; margin-right: auto; }
/* 도감 격자 칸(설계서 §5-4 - 05_도감 참고) - 둥근 네모, 안 깬 칸(.locked)은 알 그림 위에 물음표 배지를 얹는다
   (그림 자체는 그대로 두어 test_11 의 `.char.egg` 셈이 안 바뀐다). */
.grid2 .pet-tile { position: relative; border-radius: 20px; transition: transform .15s ease, box-shadow .15s ease; }
/* 그림자는 새 값을 적지 않고 --shadow 를 그대로 쓴다(9-1 5번·12번 함정 - rgba 도 색이다) */
.grid2 .pet-tile:hover { transform: translateY(-2px); box-shadow: var(--shadow); }
.grid2 .pet-tile h3 { margin: 10px 0 4px; }
.grid2 .pet-tile.locked::after {
  content: "?"; position: absolute; top: 12px; right: 14px; width: 24px; height: 24px; border-radius: 50%;
  background: var(--tone-gray-bg); color: var(--tone-gray-fg); font-weight: 800; font-size: 14px;
  display: flex; align-items: center; justify-content: center;
}

@keyframes rise { from { transform: translateY(10px); opacity: 0; } to { transform: none; opacity: 1; } }
/* 통계 타일이 차례로 나타난다(2026-09-10 §5-4). 새 움직임을 만들지 않고 rise 를 그대로 쓴다.
   차례는 nth-child 로 박지 않고 --i 를 받는다 - 나라 수가 늘어도 규칙을 더 안 적는다.
   backwards 를 주어 시작 전에도 rise 의 0% 상태(투명)로 있게 한다. */
.tiles .tile { animation: rise .35s ease backwards; animation-delay: calc(var(--i, 0) * 60ms); }
@keyframes pop { from { transform: scale(.6); opacity: 0; } to { transform: scale(1); opacity: 1; } }
@keyframes tap { 0%, 100% { transform: rotate(0); } 50% { transform: rotate(8deg) translateY(-4px); } }
@keyframes shake { 0%, 100% { transform: rotate(0); } 25% { transform: rotate(-6deg); } 75% { transform: rotate(6deg); } }
@keyframes stamp-slam { 0% { transform: rotate(-12deg) scale(2.2); opacity: 0; } 60% { transform: rotate(-12deg) scale(.92); opacity: 1; } 100% { transform: rotate(-12deg) scale(1); opacity: 1; } }
@keyframes table-shake { 0%, 100% { transform: translate(0, 0); } 25% { transform: translate(-3px, 2px); } 50% { transform: translate(3px, -2px); } 75% { transform: translate(-2px, 1px); } }
@keyframes fly-to-pile { from { transform: none; opacity: 1; } to { transform: translate(16%, 118%) rotate(9deg) scale(.28); opacity: 0; } }
@keyframes deal-in { from { transform: translateY(44px) scale(.96); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes chip-pop { from { transform: scale(.4); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes count-pop { 0% { transform: none; } 40% { transform: scale(1.45); } 100% { transform: none; } }
@keyframes confetti-fall { from { transform: translateY(0) rotate(var(--r, 0deg)); opacity: 1; } to { transform: translateY(var(--fall, 160px)) rotate(calc(var(--r, 0deg) + 220deg)); opacity: 0; } }
