
/* ============================================================
   다크모드 CSS 변수 (2026-09-05 신설, 사용자 요청 — "배터리 보존을 위한 다크모드")
   이 항목은 앞으로 새 UI를 만들 때 항상 고려해야 하는 표준 원칙이다(todo.md/toAgent.md 참고) —
   새로 추가하는 배경/텍스트/테두리 색은 아래 변수를 재사용하고, 브랜드/의미색(#1957D6, #ef4444,
   #ffaa00, #3b82f6 등)처럼 테마와 무관하게 고정되어야 하는 색만 하드코딩한다.
   ============================================================ */
:root {
	--dk-bg-page: #d0d6e0;
	--dk-bg-surface: #ffffff;
	--dk-bg-surface-alt: #f8f9fa;
	--dk-bg-surface-alt-2: #e2e8f0;
	--dk-text-primary: #1a1f27;
	--dk-text-secondary: #5a6577;
	--dk-text-tertiary: #949eb0;
	--dk-text-inverse: #ffffff;
	--dk-border: #cdd4df;
	--dk-border-soft: #e4e7ec;
	--dk-region-bg: #edf3ff;
	--dk-region-text: #244b87;
	--dk-region-border: #d5e2f5;
	--dk-shadow-sm: 0 2px 6px rgba(15, 23, 42, 0.05);
	--dk-shadow-md: 0 4px 12px rgba(15, 23, 42, 0.08);
}


/* ============================================================
   역할 토큰 (2026-09-11 신설, ui_todo.md SYS-01)

   왜 만드나 — 지금 이 파일에는 font-size가 26가지 값, border-radius가 28가지, padding 조합이
   101가지 있다. 화면마다 그때그때 정한 수치라 같은 성격의 요소가 화면마다 다르게 보이고,
   후반부 재정의가 앞의 값을 덮으면서 어디가 진짜 기준인지 알 수 없게 됐다.

   쓰는 법 — **전역 치환하지 말 것.** 새로 만들거나 손대는 컴포넌트부터 하나씩 이 토큰으로
   옮긴다. 토큰에 없는 값이 필요하면 그 자리에 이유를 주석으로 남긴다(광학 보정 2px 등).

	   ⚠️ 색은 여기 넣지 않는다 — 위 배경(--dk-bg-*)·텍스트(--dk-text-*) 블록이 이미 담당하고, 다크모드 대응이
   필요해서 :root와 body.dark-mode 두 곳을 함께 고쳐야 하기 때문이다. 아래 값들은 테마와
   무관하므로 :root 한 곳에만 둔다.
   ============================================================ */
:root {
	/* 간격 — 4=붙은 메타, 8=필드 내부, 12=행 내부, 16=필드 간, 24=섹션 간, 32=큰 구획 */
	--dk-space-1: 4px;
	--dk-space-2: 8px;
	--dk-space-3: 12px;
	--dk-space-4: 16px;
	--dk-space-6: 24px;
	--dk-space-8: 32px;

	/* 화면 좌우 여백 — 같은 화면의 제목·목록·입력창 시작선을 맞추는 기준 */
	--dk-gutter: 16px;
	--dk-gutter-dense: 12px;

	/* 글자 — 역할 이름으로 부른다. 크기를 줄이기보다 역할을 맞추는 게 목적이다. */
	--dk-font-title: 18px;        /* 화면 대제목. 한 화면에 하나 */
	--dk-font-section: 15px;      /* 섹션 제목. 본문과는 무게·간격으로 구분 */
	--dk-font-item: 14px;         /* 목록 제목 */
	--dk-font-body: 15px;         /* 대화·게시글 본문 */
	--dk-font-body-long: 16px;    /* 긴 상세 글 */
	--dk-font-meta: 12px;         /* 날짜·수량 등 보조 정보 */
	--dk-font-micro: 10px;        /* 배지처럼 아주 작은 라벨(지역 배지 등) */

	--dk-leading-title: 26px;
	--dk-leading-section: 22px;
	--dk-leading-item: 20px;
	--dk-leading-body: 22px;
	--dk-leading-body-long: 24px;
	--dk-leading-meta: 16px;
	--dk-leading-micro: 15px;

	/* 모서리 — 알약(9999px)은 선택 칩·상태 배지처럼 의미가 있을 때만 */
	--dk-radius-control: 8px;
	--dk-radius-card: 12px;
	--dk-radius-sheet: 16px;
	--dk-radius-pill: 9999px;

	/* 컨트롤 높이 — 글자가 커져도 잘리지 않게 height가 아니라 min-height로 쓴다 */
	--dk-control-primary: 48px;   /* 주요 버튼·입력 */
	/* (2026-09-11 SYS-07) 입력 요소 글자 크기의 하한. **16px 미만이면 iOS 사파리가 입력창에
	   초점이 갈 때 화면을 제멋대로 확대한다.** 그래서 이건 취향이 아니라 제약이다 —
	   여기를 낮추면 채팅할 때마다 화면이 확 커지는 증상이 돌아온다. */
	--dk-input-font: 16px;
	--dk-control-compact: 34px;   /* 보조 버튼의 "보이는" 높이 */
	--dk-touch-min: 44px;         /* 실제 조작 영역 하한(보이는 크기와 별개) */

	/* 아이콘·아바타 — 그림 크기와 터치 영역은 별개다 */
	--dk-icon: 22px;
	--dk-avatar-list: 34px;

	/* 알림 의미별 색 (2026-09-11 NOTICE-02) — ui.md "알림 색" 표가 유일한 기준이다.
	   예전엔 같은 의미가 화면마다 다른 값으로 하드코딩돼 있어서 **서버채팅 점이 핑크(=공지 색),
	   개인채팅 테두리가 파랑(=서버채팅 색)** 으로 서로 뒤바뀌어 있었다. 색을 여기 한 곳에
	   모아 두면 그런 어긋남이 다시 생기지 않는다. 값을 바꿀 땐 ui.md도 같이 고칠 것. */
	--dk-notify-server: #1957D6;   /* 서버채팅 안읽음 — 브랜드 블루 */
	--dk-notify-dm: #ef4444;       /* 개인채팅(DM) 안읽음 — 레드 */
	--dk-notify-notice: #ec4899;   /* 공지 미확인 — 핑크 */
	--dk-notify-dm-surface: #fef2f2;   /* 안읽은 DM 행의 옅은 바탕(테두리 레드에 맞춘 값) */

	/* 키보드가 덮은 높이(SYS-04). main.html의 updateKeyboardInset이 실시간으로 덮어쓴다.
	   JS가 안 도는 환경·데스크톱에서는 이 0px가 그대로 쓰여 아무 영향도 없다. */
	--dk-keyboard-inset: 0px;
}

/* 눈에는 안 보이지만 화면 읽기 도구에는 읽히는 텍스트 (2026-09-11 SYS-03/SYS-06).
   display:none이나 visibility:hidden은 읽기 도구에서도 사라지므로 쓸 수 없다 —
   1px 상자로 줄이고 clip으로 잘라내는 이 방식이 표준적인 해법이다. */
.sr-only {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

/* body.dark-mode 토글은 main.html의 applyTheme()(다른 에이전트는 이 이름으로 검색해서 재사용) 참고 */
body.dark-mode {
	/* 안읽음 바탕만 테마별로 다르다 — 알림 신호색 자체는 테마와 무관하게 같은 값을 쓴다. */
	--dk-notify-dm-surface: #2a1d1d;
	--dk-bg-page: #0f1115;
	--dk-bg-surface: #1c1f26;
	--dk-bg-surface-alt: #262a33;
	--dk-bg-surface-alt-2: #21242b;
	--dk-text-primary: #eef1f5;
	--dk-text-secondary: #a7adb8;
	--dk-text-tertiary: #7e8796;
	--dk-text-inverse: #ffffff;
	--dk-border: #333844;
	--dk-border-soft: #2b2f38;
	--dk-region-bg: #25354d;
	--dk-region-text: #c2d9ff;
	--dk-region-border: #405675;
	--dk-shadow-sm: none;
	--dk-shadow-md: none;
}



body.dark-mode .app-title-tagline {
	color: #6fb0ff;
}

body.dark-mode .posting-feed-item--featured {
	background: rgba(245, 166, 35, 0.15);
}

body.dark-mode .chat-room-item--wide {
	background: rgba(25, 87, 214, 0.15);
	border-color: rgba(25, 87, 214, 0.3);
}

body.dark-mode .chat-room-fill {
	background: rgba(25, 87, 214, 0.2);
}

body.dark-mode .ranking-item--me {
	background: rgba(25, 87, 214, 0.15);
	border-color: rgba(25, 87, 214, 0.5);
}

body.dark-mode .item-inventory-capacity-pill {
	color: var(--dk-text-secondary);
}
body.dark-mode .item-inventory-count strong {
	color: #6fb0ff;
}

body.dark-mode .item-inventory-slot-icon.cat-mat {
	background: radial-gradient(circle at 50% 30%, #3a4150 0%, var(--dk-bg-surface) 100%);
}
body.dark-mode .item-inventory-slot-icon.cat-food {
	background: radial-gradient(circle at 50% 30%, #5c3a21 0%, var(--dk-bg-surface) 100%);
	border-color: #8c5b35;
}
body.dark-mode .item-inventory-slot-icon.cat-furn {
	background: radial-gradient(circle at 50% 30%, #1e462d 0%, var(--dk-bg-surface) 100%);
	border-color: #3b7d53;
}
body.dark-mode .item-inventory-slot-icon.cat-gift {
	background: radial-gradient(circle at 50% 30%, #592543 0%, var(--dk-bg-surface) 100%);
	border-color: #9e4779;
}
body.dark-mode .item-inventory-slot-icon.cat-consumable {
	background: radial-gradient(circle at 50% 30%, #442a5c 0%, var(--dk-bg-surface) 100%);
	border-color: #7b52a3;
}

body.dark-mode .ticker-speaker-button {
	background: var(--dk-bg-surface-alt);
	color: var(--dk-text-primary);
}

body.dark-mode .field-hud-wrap {
	background: var(--dk-bg-surface);
}

body.dark-mode .toilet-fab::before {
	background-color: var(--dk-text-secondary);
}

* {
	box-sizing: border-box;
}

html, body {
	touch-action: manipulation;
	-webkit-text-size-adjust: 100%;
	/* 바텀시트 스와이프 제스처가 안드로이드 크롬의 pull-to-refresh와 충돌해 페이지가 리로드되던 버그 — overscroll-behavior-y로 브라우저 기본 오버스크롤 동작을 차단 */
	overscroll-behavior-y: contain;
}

/* ============================================================
   누를 수 있는 것은 눌린 티가 나야 한다 — 공통 바닥값
   (2026-09-10 신설. todo.md "클릭 가능한 요소는 전부 눌렀을 때 인터랙션 반응이 있어야 함" 원칙,
    2026-08-16 사용자 지적 "눌러도 아무 반응 없는 죽은 UI를 만들지 말 것")

   감사 시점 기준 cursor:pointer가 88곳인데 :active 반응은 17곳뿐이라, 개별 컴포넌트를 하나씩
   훑는 대신 여기서 바닥값을 깔았다. 컴포넌트가 자기 :active를 이미 갖고 있으면 클래스 선택자가
   더 구체적이라(0,2,0 > 0,1,1) 그쪽이 그대로 이긴다 — 이 규칙은 아무 반응도 없던 것들만 메운다.

   ⚠️ transform은 일부러 안 쓴다. .chat-room-item(skewX(-3deg))처럼 이미 transform을 쓰는
   요소가 있어서, 여기서 scale을 걸면 눌리는 순간 기울기가 풀려버린다. 대신 opacity만 낮춘다 —
   어느 배경 위에서도(라이트/다크 모두) 같은 정도로 눌린 티가 나고 다른 속성과 충돌하지 않는다.
   ============================================================ */
/* 선택자를 전부 :where()로 감싼 이유 — :where()는 특정도(specificity)에 0을 기여하므로 이 블록은
   "가장 약한 바닥값"이 되어 어떤 컴포넌트 규칙에도 진다. 감싸지 않으면 button:not(:disabled)가
   (0,1,1)이라 평범한 클래스 규칙 .foo { cursor: default } (0,1,0)를 이겨버려서, 바닥값이라고
   적어놓고 실제로는 개별 컴포넌트의 의도를 덮어쓰는 규칙이 된다. */
:where(button:not(:disabled), summary, [role="button"]:not([aria-disabled="true"])) {
	cursor: pointer;
}

:where(button:not(:disabled), summary, a, label[for], [role="button"]:not([aria-disabled="true"])):active {
	opacity: 0.72;
}

/* 비활성 컨트롤은 눌러도 안 되는 게 정상이므로 반대로 "못 누른다"를 커서로 알린다. */
:where(button:disabled, [role="button"][aria-disabled="true"]) {
	cursor: default;
}

/* 키보드 사용자에게도 같은 원칙 — 포커스가 어디 있는지 항상 보여야 한다. 컴포넌트가 자기
   focus-visible 스타일을 이미 가지고 있으면(예: .shop-modal button) 그쪽이 이긴다. */
:where(button, summary, [role="button"]):focus-visible {
	outline: 2px solid #1957D6;
	outline-offset: 2px;
}

body {
	margin: 0;
	font-family: -apple-system, "Roboto", "Noto Sans KR", sans-serif;
	background: var(--dk-bg-page);
	color: var(--dk-text-primary);
	word-break: keep-all;
	overflow-wrap: break-word;
}

/* 필드 지도만 줌인/줌아웃되고 나머지 UI는 고정 크기를 유지하도록 더블탭/핀치 줌 브라우저 동작을 억제 */
button,
.app-header,
.bottom-nav,
.tab-sheet,
.place-post-sheet,
.field-hud-wrap,
.item-info-popup,
.toilet-fab,
.item-inventory-slot,
.item-inventory-filter-chip {
	touch-action: manipulation;
	user-select: none;
	-webkit-user-select: none;
	-webkit-touch-callout: none;
}

.app {
	max-width: 480px;
	height: 100vh;
	height: 100dvh;
	/* (2026-09-11 SYS-04) 키보드가 화면만 덮고 레이아웃 뷰포트는 그대로인 브라우저에서 입력창이
	   키보드 뒤로 숨는 것을 막는다. --dk-keyboard-inset은 레이아웃이 이미 줄어든 브라우저에서는
	   0이라 이 계산이 아무 영향도 주지 않는다(main.html의 updateKeyboardInset 주석 참고). */
	height: calc(100dvh - var(--dk-keyboard-inset, 0px));
	margin: 0 auto;
	background: var(--dk-bg-surface);
	display: flex;
	flex-direction: column;
}
.app:has(.tab-sheet.open) {
	height: auto;
	min-height: 100vh;
	min-height: 100dvh;
	/* 위 .app과 같은 이유. 안 줄이면 키보드가 열린 동안 화면 밖에 빈 공간이 남는다. */
	min-height: calc(100dvh - var(--dk-keyboard-inset, 0px));
}

.app-header {
	position: relative;
	
	padding: 10px 12px;
}

.app-title {
	display: flex;
	align-items: center;
	gap: 8px;
}

.app-title-button {
	border: none;
	background: transparent;
	padding: 0;
	font: inherit;
	color: var(--dk-text-primary);
	text-align: left;
	cursor: pointer;
}

/* 캐릭터 뒤 배경은 PNG에 직접 그리지 않고 CSS로 분리 — 색 변경 시 이미지 재합성이 불필요. 브랜드 키 컬러(#1957D6)와 그 밝은 짝(#4d8dff, 랭킹 배지 그라데이션과 동일 계열)으로 벽/바닥이 대각선으로 나뉘는 느낌을 표현. */
.app-logo-badge {

	width: 40px;
	height: 40px;
	border-radius: 11px;
	
	background: linear-gradient(188deg, #1957D6 0%, #1957D6 42%, #6fb0ff 68%, #6fb0ff 100%);
	display: flex;
	align-items: center;
	justify-content: center;
	overflow: hidden;
	flex-shrink: 0;
}

.app-logo {
	height: 100%;
	width: 100%;
	object-fit: contain;
}

.app-header h1 {
	margin: 0;
	
	font-size: 20px;
	text-align: center;
}

.app-title-text {
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	line-height: 1.25;
}

.app-title-tagline {

	font-size: 9.68px;
	line-height: 1;
	font-weight: normal;
	color: #1957D6;
}

.app-header h1.app-title-brand {
	margin: 0;
	
	font-size: 20px;
	text-align: left;
}

.app-title-brand-hint {
	
	font-size: 14.55px;
	font-weight: normal;
	margin-right: 2px;
}

.menu-button {
	position: absolute;
	top: 50%;
	transform: translateY(-50%);
	right: 12px;
	width: 44px;
	height: 44px;
	border: none;
	background: transparent;
	color: var(--dk-text-primary);
	font-size: 24px;
	line-height: 1;
	cursor: pointer;
}

.notification-bell {
	position: absolute;
	top: 50%;
	transform: translateY(-50%);
	right: 56px;
	width: 44px;
	height: 44px;
	display: flex;
	align-items: center;
	justify-content: center;
	border: none;
	background: transparent;
	color: var(--dk-text-primary);
	cursor: pointer;
}

/* 하단 탭바 "채팅"의 안읽음 점 — 서버채팅(파랑)과 개인채팅(레드)을 붙여서 하나의 알림 덩어리로
   보이게 한다(2026-08-25 사용자 요청 — "빨간도트에 파랑도트를 20%가 겹쳐도 되니 붙여줘").
   6px 폭 기준 20%(1.2px)만큼 겹친다 — left 좌표 차이가 그 겹침이다.

   ⚠️ (2026-09-11 복구) 이 두 규칙은 3b3eadc "코드 주석을 요약본으로 압축 복원" 커밋에서
   주석과 함께 **실수로 같이 지워졌다.** JS는 계속 has-badge-server/has-badge-dm 클래스를
   붙이고 있었지만 그릴 규칙이 없어서, 그 뒤로 하단 탭바 안읽음 점이 아예 안 보였다.
   색은 ui.md "알림 색" 표를 따르는 토큰을 쓴다(NOTICE-02). */
.bottom-nav-item.has-badge-server::before {
	content: '';
	position: absolute;
	top: 7px;
	left: calc(50% + 0.2px);
	width: 6px;
	height: 6px;
	border-radius: 50%;
	background: var(--dk-notify-server);
	border: 1px solid var(--dk-bg-surface);
}

.bottom-nav-item.has-badge-dm::after {
	content: '';
	position: absolute;
	top: 7px;
	left: calc(50% + 5px);
	width: 6px;
	height: 6px;
	border-radius: 50%;
	background: var(--dk-notify-dm);
	border: 1px solid var(--dk-bg-surface);
}

.notification-bell.has-badge::after {
	content: '';
	position: absolute;
	top: 8px;
	right: 8px;
	width: 9px;
	height: 9px;
	border-radius: 50%;
	background: var(--dk-notify-notice);
	border: 1.5px solid var(--dk-bg-surface);
}

/* 공지 전체화면 — 지도 자리를 통째로 대체하는 방식으로 렌더링. .tab-sheet-body(다른 탭과 공유하는 전체 화면 시트) 안에 그대로 렌더링됨. */
.announcement-list {
	display: flex;
	flex-direction: column;
	gap: 8px;
	padding: 10px 0;
}

.announcement-item {
	position: relative;
	padding: 16px 20px;
	background: var(--dk-bg-surface);
	border-radius: 12px;
	border: 1px solid var(--dk-border-soft);
	/* (2026-09-11 SYS-03) 예전엔 펼칠 수 있는 공지에만 오른쪽 여백 36px을 줬다. 그래서 한 목록
	   안에서 공지마다 글 끝선이 달라 들쭉날쭉해 보였다. 화살표 자리는 항상 비워 끝선을 맞춘다. */
	padding-right: 36px;
}

.announcement-item.clickable {
	cursor: pointer;
}

.announcement-item.clickable:active {
	background: var(--dk-bg-surface-alt-2);
}

.announcement-item-chevron {
	position: absolute;
	right: 16px;
	top: 50%;
	transform: translateY(-50%);
	font-size: 22px;
	color: var(--dk-text-secondary);
}

/* 공지 목록 (2026-09-11 NOTICE-01) — 제목·시각·새 공지 배지를 먼저 훑고 본문은 펼쳐서 읽는다.
   예전엔 모든 공지의 본문이 통째로 펼쳐져 있어서 10건이면 화면을 한참 내려야 했다. */
.announcement-actions {
	display: flex;
	justify-content: flex-end;
	padding: 0 var(--dk-space-1) var(--dk-space-2);
}

.announcement-mark-all {
	min-height: var(--dk-control-compact);
	padding: 0 var(--dk-space-3);
	border: 1px solid var(--dk-border-soft);
	border-radius: var(--dk-radius-pill);
	background: var(--dk-bg-surface);
	color: var(--dk-text-secondary);
	font-family: inherit;
	font-size: var(--dk-font-micro);
	font-weight: bold;
	cursor: pointer;
}

.announcement-item-head {
	display: flex;
	align-items: center;
	gap: var(--dk-space-2);
}

/* 색이 아니라 글자로 알린다 — 공지 색(핑크)을 구분 못 해도 "새 공지"는 읽힌다. */
.announcement-item-new {
	flex: 0 0 auto;
	padding: 1px 5px;
	border-radius: var(--dk-radius-pill);
	background: var(--dk-notify-notice);
	color: var(--dk-text-inverse);
	font-size: var(--dk-font-micro);
	line-height: var(--dk-leading-micro);
	font-weight: bold;
}

.announcement-item-time {
	margin-top: 2px;
	color: var(--dk-text-tertiary);
	font-size: var(--dk-font-micro);
	line-height: var(--dk-leading-micro);
}

/* 접힌 공지는 첫 두 줄만 보여준다 — 무엇에 대한 공지인지 알기엔 충분하고,
   목록을 훑는 데 드는 스크롤은 확 줄어든다. */
.announcement-item--collapsible .announcement-item-content {
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
}

.announcement-item--collapsible.announcement-item--open .announcement-item-content {
	display: block;
	overflow: visible;
}

.announcement-item-title {
	font-size: 15px;
	font-weight: bold;
}

.announcement-item-content {
	font-size: 14px;
	color: var(--dk-text-tertiary);
	margin-top: 4px;
	line-height: 1.4;
}

.announcement-item.read .announcement-item-title,
.announcement-item.read .announcement-item-content {
	color: var(--dk-text-secondary);
}

.menu-dropdown {
	display: none;
	position: absolute;
	top: 100%;
	right: 12px;
	flex-direction: column;
	background: var(--dk-bg-surface);
	border-radius: 10px;
	box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
	overflow: hidden;
	z-index: 300;
}

.menu-dropdown.open {
	display: flex;
}

.menu-group {
	display: flex;
	flex-direction: column;
}

.menu-separator {
	height: 1px;
	background-color: var(--dk-border-soft);
	margin: 2px 0;
}

.menu-group a,
.menu-group button {
	padding: 12px 18px;
	border: none;
	background: none;
	font-family: inherit;
	font-size: 15px;
	font-weight: 600;
	letter-spacing: -0.2px;
	color: var(--dk-text-primary);
	text-decoration: none;
	white-space: nowrap;
	text-align: left;
	cursor: pointer;
	width: 100%;
	box-sizing: border-box;
}

.menu-group a:active,
.menu-group button:active {
	background: var(--dk-bg-surface-alt);
}

.menu-utility button {
	color: #1957D6;
	font-weight: 700;
}

.menu-legal {
	flex-direction: row;
	justify-content: center;
	padding: 12px 18px;
	gap: 16px;
	background-color: var(--dk-bg-surface-alt-2);
}

.menu-legal a {
	padding: 0;
	font-size: 12px;
	font-weight: 400;
	color: var(--dk-text-secondary);
	width: auto;
}

.menu-legal a:active {
	background: none;
	text-decoration: underline;
}

.back-link {
	position: absolute;
	top: 12px;
	left: 12px;
	width: 44px;
	height: 44px;
	display: flex;
	align-items: center;
	justify-content: center;
	font-size: 22px;
	color: var(--dk-text-primary);
	text-decoration: none;
}

.form-page {
	flex: 1;
	min-width: 0;
	padding: 20px;
	overflow-y: auto;
	box-sizing: border-box;
}

/* ============================================================
   정적 페이지 공용 푸터 (2026-09-10 신설)
   templates/fragments/site-footer.html이 이 클래스를 쓴다. 목적은 디자인보다 크롤 경로 —
   지도 한 장짜리로 보이는 서비스라 크롤러가 텍스트 페이지를 못 찾고 "콘텐츠 부족"으로
   판단하지 않도록, 텍스트 페이지 8개가 서로를 링크한다(todo.md 애드센스 항목).
   ============================================================ */
.site-footer {
	margin-top: 32px;
	/* 좌우 -20px은 부모 .form-page의 padding(20px)을 상쇄해 푸터 배경만 화면 끝까지 닿게 하려는 것 —
	   본문 글과 같은 20px 안쪽에서 시작하면 구분선이 어중간하게 떠 보인다. 안쪽 여백은 padding으로
	   다시 준다.
	   ⚠️ margin-bottom은 일부러 안 준다. 부모가 overflow-y:auto인 스크롤 컨테이너라, 마지막 자식에
	   음수 아래 마진을 주면 브라우저에 따라 스크롤 높이가 그만큼 줄어 푸터 끝줄이 잘릴 수 있다.
	   아래에 20px 여백이 남는 편이 잘리는 것보다 낫다. */
	margin-left: -20px;
	margin-right: -20px;
	padding: 20px;
	border-top: 1px solid var(--dk-border-soft);
	background: var(--dk-bg-surface-alt);
	color: var(--dk-text-secondary);
}

.site-footer-nav {
	display: flex;
	flex-wrap: wrap;
	gap: 8px 14px;
}

.site-footer-nav a {
	color: var(--dk-text-secondary);
	font-size: 13px;
	text-decoration: none;
}

.site-footer-nav a:hover, .site-footer-nav a:focus-visible {
	color: #1957D6;
	text-decoration: underline;
}

.site-footer-note {
	margin: 14px 0 0;
	font-size: 12px;
	color: var(--dk-text-tertiary);
}

.policy-content {
	font-size: 14px;
	line-height: 1.5;
	letter-spacing: -0.2px;
	color: var(--dk-text-primary);
}

.policy-content .policy-updated {
	margin: 0 0 16px;
	font-size: 12px;
	color: var(--dk-text-secondary);
}

.policy-content h2 {
	margin: 22px 0 8px;
	font-size: 16px;
}

.policy-content h2:first-of-type {
	margin-top: 0;
}

.policy-content p {
	margin: 0 0 10px;
}

.policy-content ul {
	margin: 0 0 10px;
	padding-left: 20px;
}

.policy-content li {
	margin-bottom: 5px;
}

.policy-content code {
	background: var(--dk-bg-surface-alt);
	padding: 2px 4px;
	border-radius: 4px;
	font-size: 13px;
}

.policy-content a {
	color: #1957D6;
}

.policy-toc {
	margin: 0 0 24px;
	padding: 14px 16px;
	background: var(--dk-bg-surface-alt-2);
	border-radius: 8px;
}

.policy-toc ol {
	margin: 0;
	padding-left: 20px;
}

.policy-toc li {
	margin-bottom: 4px;
	font-size: 13px;
}

.policy-toc a {
	color: var(--dk-text-primary);
	text-decoration: none;
}

.policy-toc a:hover {
	text-decoration: underline;
}

/* point-guide.html이 원래 자체 어두운 글래스모피즘 테마(남색 배경, 반투명 카드, 주황 그라데이션)를 따로 썼는데, privacy.html 등 다른 서브 페이지와 같은 라이트 테마로 통일하며 카드 스타일을 여기로 옮김. */
.point-guide-intro {
	margin: 0 0 20px;
	padding: 14px 16px;
	background: var(--dk-bg-surface-alt-2);
	border-radius: 8px;
	font-size: 13px;
	line-height: 1.6;
	color: var(--dk-text-secondary);
}

.point-guide-cards {
	display: flex;
	flex-direction: column;
	gap: 12px;
}

.point-guide-card {
	padding: 16px;
	border: 1px solid #eeeeee;
	border-radius: 14px;
	background: var(--dk-bg-surface);
	cursor: pointer;
	user-select: none;
	transition: background 0.15s ease;
}

.point-guide-card:active {
	background: var(--dk-bg-surface-alt-2);
}

.point-guide-card-header {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 8px;
	margin-bottom: 8px;
}

.point-guide-card-title {
	flex: 1;
	min-width: 0;
	margin: 0;
	font-size: 15px;
	font-weight: bold;
	color: var(--dk-text-primary);
}

/* 포인트 뱃지 색은 필드 HUD의 "P" 아이콘/point-up-text와 동일한 주황(#ffaa00) — 앱 전체에서
   "포인트"를 가리키는 색으로 이미 자리 잡은 값이라 그대로 재사용. */
.point-guide-badge {
	flex: 0 0 auto;
	padding: 3px 10px;
	border-radius: 999px;
	background: #ffaa00;
	color: var(--dk-text-primary);
	font-size: 12px;
	font-weight: bold;
	white-space: nowrap;
}

/* (2026-09-05 신설) 포인트와 배달력(경험치)이 항상 1:1로 같이 적립되는 카드라 뱃지 두 개를 세로로 묶어
   병렬 표기 — 헤더 폭이 좁아 가로로 나란히 두면 제목과 겹칠 수 있어 세로 스택 선택. */
.point-guide-badge-group {
	flex: 0 0 auto;
	display: flex;
	flex-direction: column;
	align-items: flex-end;
	gap: 3px;
}

.point-guide-badge-xp {
	background: #fee2e2;
	color: #b91c1c;
}

.point-guide-badge-xp img {
	vertical-align: middle;
	margin-right: 2px;
}

.point-guide-card-desc {
	margin: 0 0 8px;
	font-size: 13px;
	line-height: 1.55;
	color: var(--dk-text-secondary);
}

.point-guide-hint {
	font-size: 12px;
	font-weight: bold;
	color: #1957D6;
}

.notice {
	margin: 0 0 20px;
	padding: 14px 16px;
	border-radius: 10px;
	background: #E7EEFC;
	color: #1957D6;
	font-weight: bold;
}

.notice-error {
	background: #fdecea;
	color: #c0392b;
}

.simple-form {
	display: flex;
	flex-direction: column;
	gap: 20px;
}

.simple-form label {
	display: block;
	margin-bottom: 8px;
	font-size: 16px;
	font-weight: bold;
}

.simple-form input[type="text"],
.simple-form textarea {
	width: 100%;
	padding: 16px;
	font-size: var(--dk-input-font);
	border: 1px solid var(--dk-border);
	border-radius: 12px;
	font-family: inherit;
	resize: vertical;
	box-sizing: border-box;
	background: var(--dk-bg-surface);
	box-shadow: 0 1px 2px rgba(0,0,0,0.05);
}

.field-hint {
	margin: -4px 0 8px;
	font-size: 13px;
	color: var(--dk-text-secondary);
}

.field-label-row {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	margin-bottom: 8px;
}

.field-label-row label {
	margin-bottom: 0;
}

.field-label-row .field-hint {
	margin: 0;
}

.token-row,
.input-with-icon {
	display: flex;
	gap: 8px;
}

.token-row input,
.input-with-icon input {
	flex: 1;
	min-width: 0;
	padding: 14px;
	font-size: 16px;
	border: 1px solid var(--dk-border);
	border-radius: 10px;
	font-family: inherit;
}

.address-static {
	margin: 0;
	padding: 14px;
	font-size: 16px;
	background: var(--dk-bg-surface-alt-2);
	color: var(--dk-text-tertiary);
	border-radius: 10px;
	
	white-space: normal;
	/* 한글은 아무 글자에서나 끊기면 번역기 돌린 것처럼 어색해서 keep-all로 어절 단위로만 끊고, overflow-wrap은 공백 없는 긴 문자열(URL 등) 대비용으로만 남겨둠. */
	word-break: keep-all;
	overflow-wrap: break-word;
}

.token-row input[readonly] {
	background: var(--dk-bg-surface-alt-2);
	color: var(--dk-text-tertiary);
}

.icon-button {
	flex: 0 0 auto;
	width: 48px;
	height: 48px;
	display: flex;
	align-items: center;
	justify-content: center;
	border: none;
	border-radius: 10px;
	background: var(--dk-bg-surface-alt);
	color: var(--dk-text-tertiary);
	cursor: pointer;
}

.icon-button:active {
	background: var(--dk-bg-surface-alt);
}

.token-form {
	margin-top: 24px;
}

.factor-grid {
	display: flex;
	flex-wrap: wrap;
	gap: 6px;
}

.factor-chip {
	position: relative;
	flex-shrink: 0;
}

.factor-chip input {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	margin: 0;
	opacity: 0;
	cursor: pointer;
}

.factor-chip span {
	display: inline-block;
	padding: 8px 12px;
	border-radius: 18px;
	border: 1px solid var(--dk-border);
	font-size: 13px;
	font-weight: bold;
	color: var(--dk-text-primary);
	background: var(--dk-bg-surface);
	white-space: nowrap;
}

.factor-chip:has(input:checked) span {
	background: #1957D6;
	border-color: #1957D6;
	color: var(--dk-text-inverse);
}

.big-button {
	width: 100%;
	min-height: 64px;
	font-size: 20px;
	font-weight: bold;
	border: none;
	border-radius: 12px;
	background: #1957D6;
	color: var(--dk-text-inverse);
	cursor: pointer;
}

.big-button:active {
	background: #0F3FA6;
}

.big-button:disabled {
	background: var(--dk-border);
	color: var(--dk-text-secondary);
	cursor: not-allowed;
}

/* "내 정보" 탭 아이디 전환/재발급 버튼 둘만 20% 낮춤(64px→51px) — .big-button은 register 등록 버튼 등과 공유하는 클래스라 여기서만 스코프. */
.big-button.me-account-button {
	min-height: 51px;
}

.form-page-floating {
	padding-bottom: 100px;
}

.floating-submit-wrap {
	position: fixed;
	left: 0;
	right: 0;
	bottom: 0;
	z-index: 100;
	display: flex;
	
	flex-direction: column;
	align-items: center;
	gap: 8px;
	padding: 12px 20px calc(12px + env(safe-area-inset-bottom));
	/* 닉네임 공개 토글 추가로 바가 두 줄이 되면서, 원래 위쪽이 투명하게 흐려지는 그라데이션이었던 배경에 뒤 콘텐츠가 비쳐 보여 완전 불투명으로 교체. */
	background: var(--dk-bg-surface);
}

.floating-submit-wrap .big-button {
	max-width: 480px;
}

.nickname-public-toggle {
	display: flex;
	align-items: center;
	gap: 6px;
	font-size: 13px;
	color: var(--dk-text-tertiary);
	cursor: pointer;
}

.nickname-public-toggle input[type="checkbox"] {
	width: 16px;
	height: 16px;
	accent-color: #1957D6;
}

.register-reporter-banner {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: 6px;
	margin-bottom: 16px;
	padding: 8px 12px;
	background: var(--dk-bg-surface-alt-2);
	border-radius: 8px;
	font-size: 13px;
}

.register-reporter-icon {
	flex: 0 0 auto;
	width: 22px;
	height: 22px;
	border-radius: 50%;
	object-fit: cover;
}

.register-reporter-nickname {
	flex: 0 1 auto;
	min-width: 0;
	font-weight: bold;
	color: var(--dk-text-primary);
	overflow-wrap: anywhere;
}

.register-reporter-level {
	flex: 0 0 auto;
	font-size: 11px;
	font-weight: bold;
	color: #1957D6;
	background: #eaf1fd;
	padding: 1px 5px;
	border-radius: 4px;
}

.register-reporter-hint {
	color: var(--dk-text-secondary);
}

.register-reporter-badge {
	font-weight: bold;
	color: #1957D6;
}

.map-bubble {
	display: flex;
	flex-direction: column;
	align-items: center;
}

.map-bubble-card {
	position: relative;
	display: flex;
	flex-direction: column;
	align-items: stretch;
	gap: 10px;
	padding: 10px;
	padding-top: 22px;
	max-width: 240px;
	background: var(--dk-bg-surface);
	border-radius: 14px;
	box-shadow: 0 2px 10px rgba(0, 0, 0, 0.25);
}

/* 카드 위쪽 왼편에 붙는 책갈피 탭 — .ranking-category-tab(서버채팅/개인채팅 책갈피)과 같은 시각 언어(위만 둥근 모서리). bottom:100%로 카드 바로 위에 붙임(.map-bubble-side-actions와 반대쪽/위쪽 버전). */
.map-bubble-reporter-tab {
	position: absolute;
	bottom: 100%;
	/* 카드 모서리가 14px 둥글어 8px는 그 곡선 구간과 겹쳐 갭처럼 보였다 — 곡선을 확실히 지나는 값으로. */
	left: 18px;
	box-sizing: border-box;
	max-width: calc(100% - 36px);
	display: flex;
	align-items: center;
	gap: 4px;
	padding: 4px 10px 4px 4px;
	border-radius: 10px 10px 0 0;
	background: var(--dk-bg-surface);
	white-space: nowrap;
}

/* 탭 컨테이너(.map-bubble-reporter-tab) 자체는 불투명 유지, "내가 쓴 글" 문구 이 글자만 딤드 대신 또렷한 검정으로 — 공개 상태일 땐 부가 라벨, 비공개일 땐 이 클래스가 문구 전체를 담당. */
.map-bubble-reporter-mine {
	font-size: 11px;
	font-weight: bold;
	color: var(--dk-text-primary);
}

.map-bubble-reporter-icon {
	flex: 0 0 auto;
	width: 18px;
	height: 18px;
	border-radius: 50%;
	object-fit: cover;
}

.map-bubble-reporter-nickname {
	flex: 1 1 auto;
	min-width: 0;
	font-size: 11px;
	font-weight: bold;
	color: var(--dk-text-primary);
	overflow: hidden;
	text-overflow: ellipsis;
}

.map-bubble-reporter-level {
	flex: 0 0 auto;
	font-size: 10px;
	font-weight: bold;
	color: #1957D6;
	background: #eaf1fd;
	padding: 1px 5px;
	border-radius: 4px;
}

/* X 버튼과 "목록으로" 버튼(내가 쓴 글일 때만 팝업)이 같이 있는 자리 — 개수가 바뀌어도 위치 계산 다시 안 하도록 gap으로만 간격을 준다. */
.map-bubble-actions {
	position: absolute;
	top: -8px;
	right: -8px;
	display: flex;
	align-items: center;
	gap: 6px;
}

.map-bubble-close {
	flex: 0 0 auto;
	width: 24px;
	height: 24px;
	display: flex;
	align-items: center;
	justify-content: center;
	border: none;
	border-radius: 50%;
	background: var(--dk-bg-surface);
	color: var(--dk-text-tertiary);
	box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
	cursor: pointer;
}

.map-bubble-list-return {
	flex: 0 0 auto;
	height: 24px;
	padding: 0 10px;
	display: flex;
	align-items: center;
	justify-content: center;
	border: none;
	border-radius: 12px;
	background: var(--dk-bg-surface);
	color: #1957D6;
	font-size: 11px;
	font-weight: bold;
	font-family: inherit;
	white-space: nowrap;
	box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
	cursor: pointer;
}

.map-bubble-tail {
	width: 0;
	height: 0;
	border-left: 9px solid transparent;
	border-right: 9px solid transparent;
	border-top: 10px solid var(--dk-bg-surface);
	margin-top: -1px;
	filter: drop-shadow(0 2px 1px rgba(0, 0, 0, 0.15));
}

.map-bubble-tags {
	display: flex;
	flex-wrap: wrap;
	gap: 6px;
}

.map-bubble-tag {
	padding: 4px 10px;
	border-radius: 999px;
	background: var(--dk-bg-surface-alt);
	color: var(--dk-text-primary);
	font-size: 12px;
	white-space: nowrap;
}

.map-bubble-bottom-actions {
	display: flex;
	border-top: 1px solid var(--dk-border-soft);
	margin-top: 10px;
	padding-top: 8px;
}

.map-bubble-action-button {
	flex: 1;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	padding: 6px 0;
	background: none;
	border: none;
	border-right: 1px solid var(--dk-border-soft);
	cursor: pointer;
	color: var(--dk-text-secondary);
	font-size: 12px;
	font-weight: 600;
	gap: 4px;
}

.map-bubble-action-button:last-child {
	border-right: none;
}

.map-bubble-action-button svg {
	color: var(--dk-text-tertiary);
}

.map-bubble-action-button.active {
	color: #1957D6;
}
.map-bubble-action-button.active svg {
	color: #1957D6;
}

.map-bubble-action-button.map-bubble-flag-button.active {
	color: #e53e3e;
}
.map-bubble-action-button.map-bubble-flag-button.active svg {
	color: #e53e3e;
}

.map-bubble-action-button.map-bubble-delete-button {
	color: #e53e3e;
}
.map-bubble-action-button.map-bubble-delete-button svg {
	color: #e53e3e;
}

.map-bubble-action-button:disabled {
	cursor: default;
	opacity: 0.5;
}

.map-bubble-like-button.active {
	background: #1957D6;
	color: var(--dk-text-inverse);
}

.map-bubble-like-button.active svg {
	fill: currentColor;
}

.map-bubble-flag-button.active {
	background: #e74c3c;
	color: var(--dk-text-inverse);
	opacity: 1;
}

.map-bubble-flag-button.active svg {
	fill: currentColor;
}

/* 게시글 버튼은 좋아요/신고와 달리 토글이 아니라 화면 전환용이라 활성/비활성 색 구분 없이 중립 톤 하나만 사용. */
.map-bubble-post-button {
	color: var(--dk-text-tertiary);
}

.map-bubble-address-row {
	display: flex;
	align-items: center;
	gap: 8px;
}

.map-bubble-address {
	flex: 1;
	min-width: 0;
	font-size: 13px;
	color: var(--dk-text-primary);
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

.map-bubble-copy {
	flex: 0 0 auto;
	width: 32px;
	height: 32px;
	display: flex;
	align-items: center;
	justify-content: center;
	border: none;
	border-radius: 8px;
	background: var(--dk-bg-surface-alt);
	color: var(--dk-text-tertiary);
	cursor: pointer;
}

.map-confirm-button {
	padding: 14px 18px;
	font-size: 15px;
	font-weight: bold;
	border: none;
	border-radius: 10px;
	background: #1957D6;
	color: var(--dk-text-inverse);
	white-space: nowrap;
	cursor: pointer;
}

.map-confirm-button:disabled {
	background: var(--dk-border);
	color: var(--dk-text-secondary);
	cursor: not-allowed;
}

.map-wrap {
	position: relative;
	flex: 1;
	overflow: hidden;
	order: 1;
}

.map-wrap.hidden {
	display: none;
}

.app-map {
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	bottom: 0;
	width: 100%;
	height: 100%;
}

.difficulty-fab-wrap {
	position: absolute;
	top: 14px;
	right: 14px;
	z-index: 150;
	display: flex;
	flex-direction: column;
	align-items: flex-end;
	gap: 5px;
}

.difficulty-fab {
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 6px 12px;
	border: none;
	border-radius: 999px;
	background: var(--dk-bg-surface);
	color: var(--dk-text-primary);
	font-size: 11px;
	font-weight: bold;
	font-family: inherit;
	box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
	cursor: pointer;
	transition: background 0.2s ease, color 0.2s ease;
}

.difficulty-fab.active {
	background: #1957D6;
	color: var(--dk-text-inverse);
}

.toilet-fab {
	position: relative;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	height: 24px;
	width: fit-content;
	padding: 0 10px 0 26px;
	border: none;
	border-radius: 999px;
	background: var(--dk-bg-surface);
	opacity: 0.95;
	color: var(--dk-text-primary);
	font-size: 11px;
	font-weight: 700;
	font-family: inherit;
	letter-spacing: -0.3px;
	box-shadow: 0 2px 6px rgba(0, 0, 0, 0.12);
	backdrop-filter: blur(4px);
	cursor: pointer;
	box-sizing: border-box;
	transition: background-color 0.2s ease, color 0.2s ease, box-shadow 0.2s ease, transform 0.1s ease, padding 0.2s ease;
	white-space: nowrap;
	user-select: none;
}

.toilet-fab::before {
	content: '';
	position: absolute;
	top: 2px;
	left: 2px;
	width: 20px;
	height: 20px;
	border-radius: 50%;
	background-color: var(--dk-bg-surface-alt);
	box-shadow: 0 1px 3px rgba(0,0,0,0.2);
	transition: left 0.2s ease, background-color 0.2s ease;
}

/* 예전엔 :hover에도 border-color/color: #1957D6가 걸려있어서 토글을 OFF해도 마우스/터치 포커스가 남으면 계속 파란색으로 "안 꺼진 것처럼" 보이던 버그 — hover는 밝기/그림자만 강조하고 파란색은 .active일 때만. */
.toilet-fab:hover {
	background: var(--dk-bg-surface);
	color: var(--dk-text-primary);
	box-shadow: 0 3px 8px rgba(0, 0, 0, 0.16);
}

.toilet-fab:active {
	transform: scale(0.97);
}

.toilet-fab.active {
	padding: 0 26px 0 10px;
	background: #1957D6;
	color: var(--dk-text-inverse);
	box-shadow: 0 2px 8px rgba(25, 87, 214, 0.35);
}

.toilet-fab.active::before {
	left: calc(100% - 22px);
	background-color: var(--dk-bg-surface);
}

.toilet-fab.active:hover {
	background: #0F3FA6;
	color: var(--dk-text-inverse);
}

.bottom-nav {
	position: sticky;
	bottom: 0;
	z-index: 260;
	display: flex;
	flex: 0 0 auto;
	order: 2;
	background: var(--dk-bg-surface);
}

/* 선택된 탭을 따라다니며 100%에서 서서히 옅어지는 그라데이션 라인 (두께 2px 유지) */
.bottom-nav::before {
	content: '';
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	height: 2px;
	background: #1957D6; /* 기본 색상 */
	transition: background 0.3s ease;
}

body[data-active-tab="location"] .bottom-nav::before {
	background: linear-gradient(to right, rgba(25,87,214,1) 0%, rgba(25,87,214,1) 20%, rgba(25,87,214,0.15) 100%);
}
body[data-active-tab="history"] .bottom-nav::before {
	background: linear-gradient(to right, rgba(25,87,214,0.15) 0%, rgba(25,87,214,1) 20%, rgba(25,87,214,1) 40%, rgba(25,87,214,0.15) 100%);
}
body[data-active-tab="community"] .bottom-nav::before {
	background: linear-gradient(to right, rgba(25,87,214,0.15) 0%, rgba(25,87,214,1) 40%, rgba(25,87,214,1) 60%, rgba(25,87,214,0.15) 100%);
}
body[data-active-tab="ranking"] .bottom-nav::before {
	background: linear-gradient(to right, rgba(25,87,214,0.15) 0%, rgba(25,87,214,1) 60%, rgba(25,87,214,1) 80%, rgba(25,87,214,0.15) 100%);
}
body[data-active-tab="me"] .bottom-nav::before {
	background: linear-gradient(to right, rgba(25,87,214,0.15) 0%, rgba(25,87,214,1) 80%, rgba(25,87,214,1) 100%);
}

.bottom-nav-item {
	position: relative;
	flex: 1;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 4px;
	padding: 10px 0 max(8px, env(safe-area-inset-bottom));
	border: none;
	background: transparent;
	color: var(--dk-text-secondary);
	font-size: 12px;
	font-weight: bold;
	font-family: inherit;
	text-decoration: none;
	cursor: pointer;
}

.bottom-nav-item svg,
.bottom-nav-item span {
	transition: transform 0.15s ease, font-size 0.15s ease;
}

/* 아이콘 SVG가 stroke="currentColor"를 쓰므로 color만 바꿔도 아이콘까지 같이 흰색이 된다. */
.bottom-nav-item.active {
	background: #1957D6;
	color: #ffffff;
}

.bottom-nav-item.active svg {
	transform: scale(1.1);
}

.bottom-nav-item.active span {
	font-size: 13.2px;
}

/* 지도클릭→정보등록→포인트 지급처럼 실제로 포인트가 나가는 루트의 버튼에만 붙이는 공용 표시 점 — 정보 수정처럼 포인트가 안 나가는 경우는 이 클래스를 안 붙인다. 새 포인트 지급 버튼에도 재사용(qa.md/ui.md 정책). */
.point-award-badge {
	position: relative;
}

.point-award-badge::after {
	
	content: '+' attr(data-points) 'p';
	position: absolute;
	top: -10px;
	
	right: -12px;
	/* 카드 오른쪽 .map-bubble-side-actions(좋아요/신고/게시글)와 위치가 겹치는데, 둘 다 z-index:auto라 DOM상 나중에 나오는 쪽이 위에 그려져 뱃지가 가려졌다 — 항상 위로 오도록 z-index 지정. */
	z-index: 2;
	min-width: 24px;
	height: 20px;
	padding: 0 5px;
	display: flex;
	align-items: center;
	justify-content: center;
	border-radius: 10px;
	/* 대각선 광택 띠 2줄을 얹은 유리알(glossy) 느낌 — 그라디언트는 먼저 나열된 레이어일수록 위에 그려진다. */
	background:
		linear-gradient(120deg,
			rgba(255, 255, 255, 0) 0%,
			rgba(255, 255, 255, 0) 15%,
			rgba(255, 255, 255, 0.67) 17%,
			rgba(255, 255, 255, 0.67) 27%,
			rgba(255, 255, 255, 0) 29%,
			rgba(255, 255, 255, 0) 42%,
			rgba(255, 255, 255, 0.67) 43%,
			rgba(255, 255, 255, 0.67) 45%,
			rgba(255, 255, 255, 0) 46%,
			rgba(255, 255, 255, 0) 100%),
		#f5a623;
	color: var(--dk-text-inverse);
	font-size: 11px;
	font-weight: 800;
	line-height: 1;
	white-space: nowrap;
	border: 1.5px solid var(--dk-bg-surface);
	box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.08);

	text-shadow: -1px 1px 0 rgba(0, 0, 0, 0.5);
}

/* (2026-09-05 신설, 사용자 요청 — "배달력을 얻는 위치에 경험치 표시 마커처럼 배달력도 얻는곳을 표기해줘")
   .point-award-badge와 항상 같은 조건으로 같이 붙는다(포인트=배달력이 PointLedgerStore.award()에서
   1:1로 같이 지급되므로) — 같은 data-points 속성값을 그대로 재사용해서 새 속성 없이 표시.
   (2026-09-05 갱신, 사용자 요청 — "밝은 파랑, 글자 때문에 버튼이 너무 큼, 불 아이콘이 글로시보다
   위에 있어서 가려지면 안됨, 간격 2px, 불꽃 아이콘 더 크게") 세 가지를 한번에 반영:
   1) 배경 레이어 순서를 아이콘이 맨 위(gloss/색보다 먼저 나열)로 바꿔 광택 줄무늬가 아이콘을 덮지
      않게 함(CSS는 먼저 나열된 background 레이어가 위에 그려짐).
   2) 아이콘 크기 10px→14px로 확대, 왼쪽 패딩도 그만큼 늘림.
   3) font-size/padding/height를 줄여 텍스트로 인한 배지 크기를 줄임.
   4) 간격: 실제 사용처(#mapConfirmButton/#submitButton)의 data-points는 이제 둘 다 서버
      PointPolicy.MAP_REGISTER 값을 받아 쓴다(2026-09-10, 하드코딩 제거). 현재 값이 두 자리(10)라
      포인트 배지("+10p")의 어림 폭(~38px)을 기준으로 정확히 2px 띄우도록 right: 40px로 계산 —
      PointPolicy에서 이 값을 세 자리로 올리면 이 40px도 같이 넓혀야 한다(위 포인트 배지 쪽
      주석과 동일한 전제). */
.xp-award-badge {
	position: relative;
}

.xp-award-badge::before {
	/* 아이콘은 배경 이미지로(모든 브라우저에서 안전), 숫자는 그대로 attr() 텍스트로 — content에
	   url()과 문자열을 섞어 쓰는 방식은 호환성이 불확실해 피했다. */
	content: '+' attr(data-points);
	position: absolute;
	top: -10px;
	right: 40px;
	z-index: 2;
	min-width: 22px;
	height: 18px;
	padding: 0 4px 0 18px;
	display: flex;
	align-items: center;
	justify-content: center;
	border-radius: 9px;
	/* 아이콘을 맨 위 레이어로 — 광택 줄무늬(반투명 흰색)가 아이콘을 덮지 않도록. */
	background:
		url(/images/icons/flame.svg) no-repeat 2px center / 14px 14px,
		linear-gradient(120deg,
			rgba(255, 255, 255, 0) 0%,
			rgba(255, 255, 255, 0) 15%,
			rgba(255, 255, 255, 0.67) 17%,
			rgba(255, 255, 255, 0.67) 27%,
			rgba(255, 255, 255, 0) 29%,
			rgba(255, 255, 255, 0) 42%,
			rgba(255, 255, 255, 0.67) 43%,
			rgba(255, 255, 255, 0.67) 45%,
			rgba(255, 255, 255, 0) 46%,
			rgba(255, 255, 255, 0) 100%),
		#3b82f6;
	color: var(--dk-text-inverse);
	font-size: 10px;
	font-weight: 800;
	line-height: 1;
	white-space: nowrap;
	border: 1.5px solid var(--dk-bg-surface);
	box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.08);
	text-shadow: -1px 1px 0 rgba(0, 0, 0, 0.5);
}

/* 지도 자리를 통째로 대체하는 전체 전환 방식(.map-wrap과 같은 자리, order: 1) — 뷰포트 기준 고정 위치/vh 계산 없이 .app { height: 100dvh } 레이아웃이 안전 영역 계산과 자연스럽게 맞물린다. */
.tab-sheet {
	display: none;
	flex: 1;
	flex-direction: column;
	overflow: visible;
	background: var(--dk-bg-surface);
	order: 1;
}

.tab-sheet.open {
	display: flex;
}

.sheet-drag-handle {
	width: 36px;
	height: 4px;
	background: var(--dk-border);
	border-radius: 2px;
	margin: 6px auto 2px;
	cursor: grab;
	touch-action: none;
}

.tab-sheet-header {
	flex: 0 0 auto;
	display: flex;
	align-items: center;
	touch-action: none;
	/* #tabSheetTitle가 항상 숨겨져 flex 흐름에서 빠지면서, space-between이면 유일하게 남은 자식(설정 버튼)이 왼쪽 끝으로 밀려버려 — 오른쪽 정렬로 고정. */
	justify-content: flex-end;
	padding: 8px 14px 2px 18px;
	border-bottom: none;
	font-size: 13px;
	color: rgba(0, 0, 0, 0.5);
	font-weight: bold;
	position: relative;
	z-index: 1;
	box-shadow: 0 0 0 rgba(0, 0, 0, 0);
	transition: box-shadow 0.15s ease;
}

.tab-sheet-header--elevated {
	box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08);
}

.place-post-sheet {
	display: none;
	position: fixed;
	left: 0;
	right: 0;
	bottom: 0;
	top: 20%;
	z-index: 500;
	flex-direction: column;
	background: var(--dk-bg-surface);
	border-radius: 16px 16px 0 0;
	box-shadow: 0 -4px 20px rgba(0, 0, 0, 0.18);
	overflow: hidden;
}

.place-post-sheet.open {
	display: flex;
}

.place-post-sheet-header {
	flex: 0 0 auto;
	display: flex;
	align-items: center;
	touch-action: none;
	justify-content: space-between;
	padding: 8px 14px 10px 18px;
	font-size: 15px;
	font-weight: bold;
	color: var(--dk-text-primary);
	border-bottom: 1px solid var(--dk-border-soft);
}

.place-post-sheet-body {
	flex: 1;
	overflow-y: visible;
	padding: 10px 16px max(16px, env(safe-area-inset-bottom));
	overscroll-behavior-y: contain;
}

.place-post-write-button {
	width: 100%;
	padding: 10px;
	margin-bottom: 10px;
	border: 1px dashed var(--dk-border);
	border-radius: 10px;
	background: var(--dk-bg-surface-alt-2);
	color: var(--dk-text-tertiary);
	font-size: 13px;
	font-weight: bold;
	font-family: inherit;
	cursor: pointer;
}

/* 쓰다 만 글 안내 (2026-09-11 POST-03) — 되살렸다는 사실을 말해 주지 않으면
   "왜 전에 쓴 글이 여기 있지?"가 된다. 버리는 길도 같은 줄에 둔다. */
.posting-draft-notice {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--dk-space-2);
	padding: var(--dk-space-2) var(--dk-space-3);
	border-radius: var(--dk-radius-control);
	background: var(--dk-bg-surface-alt-2);
	color: var(--dk-text-secondary);
	font-size: var(--dk-font-meta);
	line-height: var(--dk-leading-meta);
}

.posting-draft-discard {
	flex: 0 0 auto;
	min-height: var(--dk-control-compact);
	padding: 0 var(--dk-space-3);
	border: 1px solid var(--dk-border-soft);
	border-radius: var(--dk-radius-pill);
	background: var(--dk-bg-surface);
	color: var(--dk-text-primary);
	font-family: inherit;
	font-size: var(--dk-font-micro);
	font-weight: bold;
	cursor: pointer;
}

.place-post-write-form {
	display: flex;
	flex-direction: column;
	gap: 8px;
	margin-bottom: 12px;
}

.place-post-section + .place-post-section {
	margin-top: 16px;
}

.place-post-section-label {
	margin-bottom: 8px;
	font-size: 12px;
	font-weight: bold;
	color: var(--dk-text-secondary);
}

.place-post-write-place-info {
	margin: 0;
	font-size: 12px;
	color: var(--dk-text-secondary);
}

.place-post-write-textarea {
	width: 100%;
	min-height: 120px;
	padding: 10px 12px;
	border: 1px solid var(--dk-border);
	border-radius: 10px;
	font-family: inherit;
	font-size: var(--dk-input-font);
	resize: vertical;
}

.place-post-write-title-input {
	width: 100%;
	padding: 10px 12px;
	border: 1px solid var(--dk-border);
	border-radius: 10px;
	font-family: inherit;
	font-size: var(--dk-input-font);
}

.place-post-write-actions {
	display: flex;
	justify-content: flex-end;
	gap: 8px;
}

.place-post-write-cancel {
	border: none;
	background: transparent;
	color: var(--dk-text-secondary);
	font-size: 13px;
	font-family: inherit;
	cursor: pointer;
	padding: 8px 10px;
}

.place-post-write-submit {
	border: none;
	border-radius: 8px;
	background: #1957D6;
	color: var(--dk-text-inverse);
	font-size: 13px;
	font-weight: bold;
	font-family: inherit;
	cursor: pointer;
	padding: 8px 14px;
}

.place-post-item {
	padding: 4px 10px 5px;
	margin-bottom: 2px;
	background: var(--dk-bg-surface);
	border: 1px solid var(--dk-border-soft);
	border-radius: 8px;
}

.place-post-item-header {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 6px;
	width: calc(100% + 4px);
	margin-left: -2px;
	padding: 2px 6px 2px 3px;
	background: var(--dk-bg-surface-alt);
	border-radius: 4px;
	min-height: 22px;
}

.place-post-item-author {
	display: flex;
	align-items: center;
	gap: 4px;
	min-width: 0;
}

.place-post-item-nickname {
	min-width: 0;
	font-size: 12px;
	font-weight: bold;
	color: var(--dk-text-primary);
	line-height: 1.2;
	overflow-wrap: anywhere;
}

.place-post-item-level {
	flex: 0 0 auto;
	font-size: 9.5px;
	font-weight: bold;
	color: #1957D6;
	background: #eaf1fd;
	padding: 1px 4px;
	border-radius: 3px;
	line-height: 1.2;
}

.place-post-item-time {
	font-size: 10.5px;
	color: var(--dk-text-secondary);
	line-height: 1.2;
}

.place-post-item-content {
	margin-top: 3px;
	font-size: 13.5px;
	line-height: 1.38;
	color: var(--dk-text-primary);
	white-space: pre-wrap;
	word-break: keep-all;
	overflow-wrap: break-word;
}

.place-post-item-reactions {
	display: flex;
	justify-content: flex-end;
	gap: 6px;
	margin-top: 3px;
}

.place-post-item-reaction {
	flex: 0 0 auto;
	display: flex;
	align-items: center;
	gap: 3px;
	padding: 2px 6px;
	border: none;
	border-radius: 4px;
	background: var(--dk-bg-surface-alt);
	color: var(--dk-text-tertiary);
	font-size: 10.5px;
	font-weight: bold;
	font-family: inherit;
	line-height: 1.2;
	cursor: pointer;
}

.place-post-item-reaction svg {
	width: 12px;
	height: 12px;
}

.place-post-item-reaction.active.place-post-like {
	background: #1957D6;
	color: var(--dk-text-inverse);
}

.place-post-item-reaction.active.place-post-dislike {
	background: #e74c3c;
	color: var(--dk-text-inverse);
}

/* "포스팅" 탭 — 장소별 "게시글"(.place-post-item*)과는 별개의 실제 게시글 피드. 내활동 탭(.history-item*)과 톤을 맞춘 카드형(테두리+둥근 모서리+흰 배경). */
.posting-tab-header-row {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 8px;
	margin-bottom: 6px;
}

.posting-tab-header-row .my-info-summary-bar {
	margin-bottom: 0;
	flex: 1;
	min-width: 0;
}

.posting-top-write-button {
	flex: 0 0 auto;
	display: inline-flex;
	align-items: center;
	min-height: 30px;
	gap: 4px;
	padding: 4px 9px;
	border: 1px solid #1957D6;
	border-radius: 6px;
	background: var(--dk-bg-surface);
	color: #1957D6;
	font-size: 11.5px;
	font-weight: bold;
	font-family: inherit;
	cursor: pointer;
	box-shadow: 0 1px 3px rgba(25, 87, 214, 0.08);
	transition: all 0.15s ease;
	line-height: 1.2;
}

.posting-top-write-button svg {
	width: 12px;
	height: 12px;
}

.posting-top-write-button:hover {
	background: #1957D6;
	color: var(--dk-text-inverse);
}

.posting-write-button {
	width: 100%;
	padding: 10px;
	
	margin-top: 4px;
	border: 1px dashed var(--dk-border);
	border-radius: 10px;
	background: var(--dk-bg-surface-alt-2);
	color: var(--dk-text-tertiary);
	font-size: 13px;
	font-weight: bold;
	font-family: inherit;
	cursor: pointer;
}

#postingSentinel {
	margin: 4px 0 0;
	height: 14px;
}

.posting-featured-header {
	display: flex;
	align-items: center;
	justify-content: space-between;
	padding: 2px 4px;
	margin-bottom: 2px;
}

.posting-featured-header-title {
	font-size: 11px;
	font-weight: 800;
	color: var(--dk-text-secondary);
	letter-spacing: -0.2px;
}

/* (2026-09-11 POST-02) 추천은 지역 필터와 무관하게 항상 전국 기준이다. 지역을 걸어 둔 채로 보면
   바로 아래 피드와 범위가 달라서 "왜 다른 지역 글이 있지?"가 된다 — 그 사실을 작게 적어 둔다.
   부모가 space-between이라 margin-right:auto로 제목 옆에 붙여 두고 접기 버튼만 오른쪽에 남긴다. */
.posting-featured-scope {
	margin-right: auto;
	margin-left: var(--dk-space-2);
	padding: 1px 5px;
	border-radius: var(--dk-radius-pill);
	background: var(--dk-bg-surface-alt-2);
	color: var(--dk-text-tertiary);
	font-size: var(--dk-font-micro);
	line-height: var(--dk-leading-micro);
	font-weight: bold;
}

.posting-featured-toggle-btn {
	border: none;
	background: none;
	font-size: 10.5px;
	font-weight: 700;
	color: var(--dk-text-secondary);
	cursor: pointer;
	padding: 2px 6px;
	border-radius: 4px;
	transition: all 0.15s ease;
}

.posting-featured-toggle-btn:hover {
	color: #1957D6;
	background: var(--dk-bg-surface-alt);
}

.posting-featured-list {
	display: flex;
	flex-direction: column;
	gap: 4px;
	margin-bottom: 4px;
}

.posting-feed {
	display: flex;
	flex-direction: column;
	
	gap: 4px;
	padding: 4px 0;
}

.posting-feed-item {
	position: relative;
	padding: 5px 12px;
	border: 1px solid var(--dk-border-soft);
	border-radius: 10px;
	background: var(--dk-bg-surface);
}

/* 페이지네이션과 무관하게 항상 최상단 고정되는 이번달 좋아요 최다 글 — 일반 카드와 같은 크기/폰트, 골드 톤 테두리+배경으로만 구분(포인트 지급 뱃지의 골드 톤과 같은 계열, ui.md 참고). */
.posting-feed-item--featured {
	border: 1.5px solid #f5a623;
	background: #fffaf0;
	margin-bottom: 4px;
}

/* 오늘의 포스팅은 금색 대신 은색 톤으로 덮어씀 — 배지 색도 같이 은색 계열로 맞춰 금색 텍스트가 남지 않게 함. */
.posting-feed-item--featured-today {
	border-color: #a9b0b8;
	background: var(--dk-bg-surface-alt-2);
}

.posting-feed-item--featured-today .posting-feed-featured-badge {
	color: var(--dk-text-secondary);
}

.posting-feed-featured-badge {
	margin-bottom: 6px;
	font-size: 11px;
	font-weight: bold;
	color: #c07a00;
}

.posting-feed-item-header {
	display: flex;
	align-items: center;
	/* 지역 배지가 합류해 요소가 늘었다 — 좁은 폭에서 넘치면 접는다. */
	flex-wrap: wrap;
	gap: var(--dk-space-1, 4px) var(--dk-space-2, 8px);
}

/* 유저정보(왼쪽)/좋아요·댓글수(오른쪽)를 담는 맨 아래 한 줄.
   (2026-09-11 POST-01) 지역 배지가 이 줄로 합류했다. 좁은 화면에서 지역명이 길면 글자를 자르는
   대신 줄을 하나 더 쓰도록 wrap을 허용한다 — 지명은 잘리면 의미가 사라지는 정보다. */
.posting-feed-item-meta {
	display: flex;
	align-items: center;
	justify-content: space-between;
	flex-wrap: wrap;
	gap: var(--dk-space-1) var(--dk-space-2);
	margin-top: var(--dk-space-2);
}

.posting-feed-item-nickname {
	font-size: 13px;
	font-weight: bold;
	color: var(--dk-text-primary);
	line-height: 1.2;
}

.posting-feed-item-level {
	flex: 0 0 auto;
	font-size: 10px;
	font-weight: bold;
	color: #1957D6;
	background: #eaf1fd;
	padding: 2px 5px;
	border-radius: 4px;
	line-height: 1.2;
	display: inline-flex;
	align-items: center;
}

.posting-feed-item-time {
	font-size: 11px;
	color: var(--dk-text-secondary);
	line-height: 1;
	margin-left: 2px;
}

.posting-feed-item-header > .posting-feed-item-time {
	margin-left: 0;
	white-space: nowrap;
}

.posting-feed-item > .posting-feed-item-header {
	margin-top: 4px;
}

.posting-feed-item-bottom {
	flex-wrap: nowrap;
	gap: 8px;
	margin-top: 6px;
}

.posting-feed-item-bottom > .posting-feed-item-footer {
	flex: 1 1 0;
	min-width: 0;
}

.posting-feed-item-bottom .posting-feed-item-nickname {
	min-width: 0;
	overflow-wrap: anywhere;
}

.posting-feed-item-reactions {
	display: flex;
	align-items: center;
	flex: 0 0 auto;
	gap: 10px;
	margin-left: auto;
	white-space: nowrap;
}

.posting-feed-item-title {
	flex: 1 1 auto;
	min-width: 0;
	font-size: 13.5px;
	font-weight: bold;
	color: var(--dk-text-primary);
	line-height: 1.35;
	letter-spacing: -0.2px;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

.posting-feed-item-footer {
	display: flex;
	align-items: center;
	gap: 4px;
	flex-shrink: 0;
}

.posting-feed-like {
	flex: 0 0 auto;
	display: inline-flex;
	align-items: center;
	gap: 3px;
	border: none;
	background: none;
	padding: 0;
	color: var(--dk-text-secondary);
	font-size: 11px;
	font-weight: bold;
	font-family: inherit;
	line-height: 1;
	cursor: pointer;
}

.posting-feed-like svg {
	width: 14px;
	height: 14px;
	display: block;
}

.posting-feed-like.active {
	color: #1957D6;
}

.posting-feed-item-comment-count {
	display: inline-flex;
	align-items: center;
	gap: 3px;
	font-size: 11px;
	color: var(--dk-text-secondary);
	line-height: 1;
}

.posting-feed-item-comment-count svg {
	width: 14px;
	height: 14px;
	display: block;
}

.posting-detail-card {
	padding: 2px 2px 8px;
	margin-bottom: 6px;
}

.posting-detail-title {
	font-size: 17px;
	font-weight: bold;
	color: var(--dk-text-primary);
	letter-spacing: -0.2px;
	word-break: keep-all;
	overflow-wrap: break-word;
}

.posting-detail-address {
	margin-top: 2px;
	display: flex;
	align-items: center;
	gap: 3px;
	font-size: 11.5px;
	color: var(--dk-text-secondary);
}

.posting-detail-address-arrow {
	flex: 0 0 auto;
	display: flex;
	align-items: center;
	padding: 2px;
	border: none;
	background: none;
	color: var(--dk-text-secondary);
	cursor: pointer;
}

.posting-detail-card .posting-feed-item-header {
	margin-top: 4px;
	gap: 6px;
}

.posting-detail-content {
	margin-top: 6px;
	font-size: var(--dk-font-body);
	line-height: var(--dk-leading-body);
	color: var(--dk-text-primary);
	white-space: pre-wrap;
	word-break: keep-all;
	overflow-wrap: break-word;
}

.posting-detail-reactions {
	display: flex;
	align-items: center;
	justify-content: flex-end;
	gap: var(--dk-space-2);
	margin-top: var(--dk-space-2);
}

.posting-detail-reactions .posting-feed-like,
.posting-detail-reactions .posting-detail-comment-jump {
	justify-content: center;
	min-width: var(--dk-touch-min);
	min-height: var(--dk-touch-min);
	font-size: var(--dk-font-meta);
}

.posting-detail-comments {
	display: flex;
	flex-direction: column;
	gap: var(--dk-space-3);
	margin-bottom: var(--dk-space-2);
	padding-top: var(--dk-space-3);
	border-top: 1px solid var(--dk-border-soft);
}

.posting-detail-comments .place-post-item {
	margin-bottom: 0;
}

/* 최상위 댓글 작성 폼 — 댓글 목록 맨 아래. */
.posting-comment-write {
	display: flex;
	flex-direction: column;
	gap: var(--dk-space-2);
	margin-top: var(--dk-space-1);
}

/* POST-06: 읽는 글은 14–15px, 조작 문구는 14px로 맞추고 입력 글자는 16px를 유지한다. */
.posting-comment-write .place-post-write-textarea {
	min-height: 96px; /* 짧은 댓글을 쓰는 3줄 높이. 긴 글은 세로로 늘려 쓸 수 있다. */
	padding: var(--dk-space-3);
	border-radius: var(--dk-radius-control);
	background: var(--dk-bg-surface);
	color: var(--dk-text-primary);
	font-size: var(--dk-input-font);
	font-weight: normal;
	line-height: var(--dk-leading-body-long);
}

.posting-comment-write .place-post-write-textarea::placeholder,
.posting-detail-comments .place-post-reply-write-input::placeholder {
	color: var(--dk-text-secondary);
	opacity: 1;
}

.posting-comment-write .place-post-write-submit,
.posting-detail-comments .place-post-reply-write-submit {
	min-height: var(--dk-touch-min);
	padding: var(--dk-space-2) var(--dk-space-4);
	border-radius: var(--dk-radius-control);
	font-size: var(--dk-font-item);
	font-weight: 600;
	line-height: var(--dk-leading-item);
}

.posting-detail-comments .place-post-reply-write-input {
	min-height: var(--dk-touch-min);
	border-radius: var(--dk-radius-control);
	background: var(--dk-bg-surface);
	color: var(--dk-text-primary);
	font-size: var(--dk-input-font);
	line-height: var(--dk-leading-body-long);
}

.posting-detail-comments .place-post-item-content,
.posting-detail-comments .place-post-reply-item-content {
	font-size: var(--dk-font-item);
	line-height: var(--dk-leading-body);
}

.posting-detail-comments .place-post-reply-item-header {
	width: 100%;
	margin-left: 0;
}

.posting-comment-list > .state-block {
	padding: var(--dk-space-3) 0;
}

.posting-comment-list .state-block-message {
	font-size: var(--dk-font-item);
	line-height: var(--dk-leading-body);
}

/* 댓글 이동 버튼 (2026-09-11 POST-04) — 댓글 수와 [댓글 쓰기]를 눌러 각각의 자리로 데려간다.
   댓글 수는 원래 그냥 <span>이었다. <button>으로 바꾸되 **보이는 모양은 그대로 두고**
   (숫자 옆에 아이콘) 터치 영역만 확보한다 — 갑자기 버튼처럼 생기면 정보가 아니라 조작으로 읽힌다. */
.posting-detail-comment-jump {
	border: none;
	background: none;
	padding: 0;
	font-family: inherit;
	font-weight: inherit;
	cursor: pointer;
	/* 아이콘이 11px이라 그대로 두면 손가락으로 못 누른다. 보이는 크기는 그대로 두고 영역만 넓힌다. */
	position: relative;
}

.posting-detail-comment-jump::after {
	content: '';
	position: absolute;
	top: 50%;
	left: 50%;
	width: var(--dk-touch-min);
	height: var(--dk-touch-min);
	transform: translate(-50%, -50%);
}

/* 댓글이 50개인 글에서 끝까지 내려가지 않고 바로 쓰기로 가는 길. */
.posting-detail-comment-write-jump {
	min-height: var(--dk-touch-min);
	padding: 0 var(--dk-space-2);
	border: none;
	border-radius: var(--dk-radius-control);
	background: transparent;
	color: var(--dk-text-secondary);
	font-family: inherit;
	font-size: var(--dk-font-item);
	font-weight: 600;
	line-height: var(--dk-leading-item);
	cursor: pointer;
}

/* 댓글 목록 — 작성폼과 구분되는 자기 영역을 갖는다(새 댓글은 이 안에만 붙는다). */
.posting-comment-list {
	display: flex;
	flex-direction: column;
	gap: var(--dk-space-2);
}

.place-post-reply-toggle {
	flex: 0 0 auto;
	display: flex;
	align-items: center;
	gap: 3px;
	padding: 2px 6px;
	border: none;
	border-radius: 4px;
	background: var(--dk-bg-surface-alt);
	color: var(--dk-text-tertiary);
	font-size: 10.5px;
	font-weight: bold;
	font-family: inherit;
	line-height: 1.2;
	cursor: pointer;
}

.place-post-reply-toggle svg {
	width: 12px;
	height: 12px;
}

.place-post-replies {
	margin-top: 3px;
	padding-left: 10px;
	display: flex;
	flex-direction: column;
	gap: 3px;
}

.place-post-reply-item {
	padding: 2px 0;
	background: transparent;
}

.place-post-reply-item-header {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 6px;
	width: calc(100% + 4px);
	margin-left: -2px;
	padding: 2px 6px 2px 3px;
	background: var(--dk-bg-surface-alt);
	border-radius: 4px;
	min-height: 20px;
}

.place-post-reply-item-author {
	display: flex;
	align-items: center;
	gap: 4px;
	min-width: 0;
}

.place-post-reply-item-nickname {
	min-width: 0;
	font-size: 11.5px;
	font-weight: bold;
	color: var(--dk-text-primary);
	line-height: 1.2;
	overflow-wrap: anywhere;
}

.place-post-reply-item-time {
	font-size: 10px;
	color: var(--dk-text-secondary);
	line-height: 1.2;
}

.place-post-reply-item-content {
	margin-top: 2px;
	
	font-size: 12px;
	line-height: 1.35;
	color: var(--dk-text-primary);
	white-space: pre-wrap;
	word-break: keep-all;
	overflow-wrap: break-word;
}

.place-post-reply-write {
	display: flex;
	gap: 4px;
	align-items: center;
	margin-top: 3px;
}

.place-post-reply-write-input {
	flex: 1;
	min-width: 0;
	padding: 5px 8px;
	border: 1px solid var(--dk-border);
	border-radius: 5px;
	font-family: inherit;
	font-size: var(--dk-input-font);
}

.place-post-reply-write-submit {
	flex: 0 0 auto;
	border: none;
	border-radius: 5px;
	background: #1957D6;
	color: var(--dk-text-inverse);
	font-size: 11.5px;
	font-weight: bold;
	font-family: inherit;
	cursor: pointer;
	padding: 5px 12px;
}

/* 개인채팅 서브탭 — 서버채팅(정원/게이지 개념 있는 타일)과 달리 정원 개념 없는 메신저 인박스형 세로 목록. .chat-occupant-item과 비슷하지만 마지막 메시지 미리보기+시간이 오른쪽에 붙는다. */
.dm-room-list {
	display: flex;
	flex-direction: column;
	gap: 6px;
}

.dm-room-item {
	position: relative;
	display: flex;
	align-items: center;
	gap: 10px;
	width: 100%;
	padding: 10px 12px;
	border: 1px solid var(--dk-border-soft);
	border-radius: 12px;
	background: var(--dk-bg-surface-alt-2);
	font-family: inherit;
	text-align: left;
	cursor: pointer;
}

/* 방 단위 점 표시 대신 사각형 테두리를 브랜드 블루 띠로 둘러 안읽음을 알림.
   (2026-09-11 SYS-03) 예전엔 여기서 테두리를 1px→2px로 키웠다. 두께가 바뀌면 상자 크기가
   같이 바뀌어서, 방을 읽는 순간 행이 2px 줄고 안쪽 내용이 1px씩 밀렸다. 이제 두께는 그대로 두고
   box-shadow(레이아웃에 영향을 주지 않는다)로 같은 굵기를 그린다. */
.dm-room-item--unread {
	border-color: var(--dk-notify-dm);
	box-shadow: inset 0 0 0 1px var(--dk-notify-dm);
	/* 레드 테두리에 맞춘 아주 옅은 바탕 — 예전엔 파랑 계열이라 서버채팅과 구분이 안 됐다. */
	background: var(--dk-notify-dm-surface);
}

.dm-room-item-avatar {
	flex: 0 0 auto;
	width: 40px;
	height: 40px;
	border-radius: 50%;
	object-fit: cover;
}

.dm-room-item-info {
	flex: 1;
	min-width: 0;
	display: flex;
	flex-direction: column;
	gap: 2px;
}

.dm-room-item-name {
	font-size: 14px;
	font-weight: bold;
	color: var(--dk-text-primary);
}

.dm-room-item-preview {
	font-size: 12px;
	color: var(--dk-text-secondary);
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

/* 시간(위) + 안읽음 배지(아래)를 담는 오른쪽 칸.
   왼쪽 정보 칸과 gap을 맞춰야 이름/시간, 미리보기/배지의 기준선이 나란히 선다(SYS-03). */
.dm-room-item-side {
	flex: 0 0 auto;
	display: flex;
	flex-direction: column;
	align-items: flex-end;
	justify-content: center;
	gap: 2px;
}

.dm-room-item-unread {
	min-width: 18px;
	padding: 1px 5px;
	border-radius: var(--dk-radius-pill);
	background: var(--dk-notify-dm);
	color: var(--dk-text-inverse);
	font-size: var(--dk-font-micro);
	line-height: var(--dk-leading-micro);
	font-weight: bold;
	text-align: center;
}

.dm-room-item-time {
	font-size: 11px;
	line-height: var(--dk-leading-micro);
	color: var(--dk-text-secondary);
}

.dm-start-popup {
	position: fixed;
	z-index: 700;
	background: var(--dk-bg-surface);
	border: 1px solid var(--dk-border-soft);
	border-radius: 10px;
	box-shadow: 0 2px 12px rgba(0, 0, 0, 0.15);
	overflow: hidden;
}

.dm-start-popup-button {
	display: flex;
	align-items: center;
	gap: 6px;
	border: none;
	background: transparent;
	color: #1957D6;
	font-size: 13px;
	font-weight: bold;
	font-family: inherit;
	padding: 10px 16px;
	cursor: pointer;
	white-space: nowrap;
}

.dm-start-popup-button:active {
	background: #eef4ff;
}

.dm-start-popup-button + .dm-start-popup-button {
	border-top: 1px solid var(--dk-border-soft);
}

/* (2026-09-06 신설) 채팅에서 상대 둥지를 읽기 전용으로 보여주는 모달. */
.nest-view-modal {
	position: fixed;
	inset: 0;
	z-index: 9000;
	background: rgba(0, 0, 0, 0.6);
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 20px;
}
.nest-view-modal-inner {
	width: 100%;
	max-width: 420px;
	background: var(--dk-bg-surface);
	border-radius: 12px;
	overflow: hidden;
}
.nest-view-modal-header {
	display: flex;
	align-items: center;
	justify-content: space-between;
	padding: 12px 16px;
	font-weight: bold;
	font-size: 14px;
	color: var(--dk-text-primary);
	border-bottom: 1px solid var(--dk-border-soft);
}
/* 활동 보기는 목록만 스크롤한다. 둥지 장면/좋아요 모달의 크기는 바꾸지 않는다. */
.activity-view-modal {
	padding: var(--dk-space-4);
}

.activity-view-modal .nest-view-modal-inner {
	display: flex;
	flex-direction: column;
	max-height: calc(100vh - 32px);
	max-height: calc(100dvh - 32px);
}

.activity-view-modal .nest-view-modal-header {
	flex: 0 0 auto;
	gap: var(--dk-space-2);
	padding: var(--dk-space-2) var(--dk-space-3) var(--dk-space-2) var(--dk-space-4);
}

.activity-view-modal .nest-view-modal-header h2 {
	min-width: 0;
	margin: 0;
	font-size: var(--dk-font-title);
	line-height: var(--dk-leading-title);
	overflow-wrap: anywhere;
}

.activity-view-modal .nest-view-modal-close {
	flex: 0 0 var(--dk-touch-min);
	min-width: var(--dk-touch-min);
	min-height: var(--dk-touch-min);
}

.activity-view-body {
	flex: 1 1 auto;
	min-height: 0;
	overflow-y: auto;
	overscroll-behavior: contain;
	padding: var(--dk-gutter);
	display: flex;
	flex-direction: column;
	gap: var(--dk-space-6);
}

.activity-section {
	flex: 0 0 auto;
	min-width: 0;
	display: flex;
	flex-direction: column;
	gap: var(--dk-space-2);
}

.activity-section-title {
	margin: 0;
	font-size: var(--dk-font-section);
	line-height: var(--dk-leading-section);
	color: var(--dk-text-primary);
}

.activity-section-empty {
	margin: 0;
	color: var(--dk-text-secondary);
	font-size: var(--dk-font-meta);
	line-height: var(--dk-leading-meta);
}

/* 제목과 보조 정보의 순서는 유지하되 긴 주소는 필요한 만큼 줄바꿈한다. */
.activity-item {
	flex: 0 0 auto;
	min-width: 0;
	display: flex;
	flex-direction: column;
	gap: 2px;
	padding: var(--dk-space-3);
	border: 1px solid var(--dk-border-soft);
	border-radius: var(--dk-radius-card);
	background: var(--dk-bg-surface-alt-2);
}

.activity-item--clickable {
	cursor: pointer;
	min-height: var(--dk-touch-min);
	justify-content: center;
}

.activity-item-title {
	font-size: var(--dk-font-item);
	line-height: var(--dk-leading-item);
	font-weight: bold;
	color: var(--dk-text-primary);
	overflow-wrap: anywhere;
}

.activity-item-meta {
	font-size: var(--dk-font-meta);
	line-height: var(--dk-leading-meta);
	color: var(--dk-text-secondary);
	overflow-wrap: anywhere;
}

.nest-view-modal-close {
	border: none;
	background: none;
	font-size: 16px;
	line-height: 1;
	color: var(--dk-text-secondary);
	cursor: pointer;
	padding: 4px 6px;
}

.nest-view-modal-footer {
	display: flex;
	justify-content: center;
	padding: 10px 16px;
	border-top: 1px solid var(--dk-border-soft);
}
.nest-view-like-button {
	display: flex;
	align-items: center;
	gap: 6px;
	border: 1px solid var(--dk-border-soft);
	background: var(--dk-bg-surface-alt);
	color: var(--dk-text-primary);
	border-radius: 20px;
	padding: 8px 18px;
	font-size: 14px;
	font-weight: bold;
	font-family: inherit;
	cursor: pointer;
}
.nest-view-like-button.liked {
	border-color: #ff6b81;
	background: rgba(255, 107, 129, 0.12);
	color: #ff6b81;
}

.chat-occupant-item--clickable {
	cursor: pointer;
}

/* 탭 이름+닫기(X)는 하단 탭바로 이미 어느 탭인지 알 수 있고 같은 탭 재클릭으로 닫히는 토글이 있어 중복이라 항상 숨김. 채팅 탭 톱니바퀴(설정) 버튼은 openTabSheet()가 별도로 노출 관리. */
#tabSheetTitle,
#tabSheetCloseButton {
	display: none;
}

.tab-sheet-close {
	width: 30px;
	height: 30px;
	display: flex;
	align-items: center;
	justify-content: center;
	border: none;
	background: none;
	font-size: 13px;
	color: rgba(0, 0, 0, 0.5);
	cursor: pointer;
}

.tab-sheet-header-actions {
	display: flex;
	align-items: center;
	gap: 2px;
}

.chat-settings-button {
	width: 44px;
	height: 44px;
	display: flex;
	align-items: center;
	justify-content: center;
	border: none;
	background: none;
	color: rgba(0, 0, 0, 0.5);
	cursor: pointer;
}

.chat-settings-panel {
	position: fixed;
	z-index: 700;
	padding: 10px 12px;
	background: var(--dk-bg-surface);
	border-radius: 12px;
	box-shadow: 0 2px 14px rgba(0, 0, 0, 0.18);
}

.chat-settings-panel-title {
	font-size: 12px;
	font-weight: bold;
	color: var(--dk-text-secondary);
	margin-bottom: 8px;
}

.chat-settings-swatches {
	display: flex;
	gap: 8px;
}

.chat-settings-swatches-neutral {
	margin-top: 8px;
}

.chat-settings-swatch {
	width: 28px;
	height: 28px;
	border-radius: 50%;
	border: 1px solid var(--dk-border);
	cursor: pointer;
	padding: 0;
}

.chat-settings-swatch.active {
	border: 2px solid #1957D6;
}

.tab-sheet-body {
	flex: 1;
	overflow-y: visible;
	background-color: var(--dk-bg-surface-alt);
	/* 이 padding 단축 속성이 예전엔 별도의 padding-bottom safe-area 규칙보다 뒤에 있어 그 여백을 무효화시키고 있었다 — 하나로 합침. */
	padding: 2px 20px max(20px, env(safe-area-inset-bottom)) 20px;
	/* 시트 내부 스크롤이 맨 위에서 더 당겨질 때 문서로 오버스크롤이 전파돼 브라우저 pull-to-refresh가 같이 발동하지 않게 로컬에서 막음(html,body의 overscroll-behavior-y와 같은 목적, 이중 방어). */
	overscroll-behavior-y: contain;
}

.my-info-summary-bar {
	display: flex;
	align-items: center;
	box-sizing: border-box;
	min-height: 36px;
	margin-bottom: 6px;
	background: var(--dk-bg-surface);
	padding: 2px 10px;
	border-radius: 8px;
	border: 1px solid var(--dk-border-soft);
	box-shadow: var(--dk-shadow-sm);
}

.my-info-summary-user {
	display: flex;
	align-items: center;
	min-width: 0;
	gap: 4px;
}

.my-info-summary-nickname {
	font-weight: 800;
	color: var(--dk-text-primary);
	font-size: 14px;
	min-width: 0;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

.my-info-summary-divider {
	width: 1px;
	flex-shrink: 0;
	height: 14px;
	background-color: var(--dk-border);
	margin: 0 8px;
}

.my-info-summary-stats {
	display: flex;
	align-items: center;
	gap: 8px;
	flex: 0 0 auto;
	white-space: nowrap;
}

.my-info-summary-stat {
	display: flex;
	align-items: center;
	gap: 4px;
	background: none;
	border: none;
	padding: 0;
	color: var(--dk-text-tertiary);
	font-size: 13px;
	font-weight: 600;
	cursor: pointer;
}

.received-likes-icon {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex: 0 0 14px;
	width: 14px;
	height: 14px;
	font-size: 14px;
	line-height: 1;
}

.my-info-summary-bar #chatSettingsButton {
	margin-left: auto;
	flex-shrink: 0;
}

/* 세 탭의 요약 바는 같은 높이를 사용하고 버튼의 터치 영역은 유지한다. */
.my-info-summary-bar .my-info-summary-stat-clickable {
	min-height: 30px;
	font-size: 12px;
	line-height: 1.4;
}

.my-info-summary-bar .rider-level-badge {
	position: relative;
	z-index: 0;
	display: inline-flex;
	align-items: center;
	padding: 0 6px;
	background: none;
	font-size: 10px;
}

/* 배지는 얇게 표시하되 투명한 위아래 영역까지 클릭할 수 있다. */
.my-info-summary-bar .rider-level-badge::before {
	content: '';
	position: absolute;
	inset: 6px 0;
	z-index: -1;
	border-radius: inherit;
	background: #1957D6;
}

.my-info-summary-level {
	flex: 0 0 auto;
	font-size: 10px;
	font-weight: bold;
	color: #1957D6;
	background: #eaf1fd;
	padding: 1px 5px;
	border-radius: 4px;
}

.my-info-summary-stat {
	color: var(--dk-text-secondary);
}

/* <button>이지만 기본 스타일을 지워 .my-info-summary-stat과 완전히 같은 순수 텍스트로 보이게 — 클릭은 되지만 밑줄 등 시각적 힌트는 주지 않는다. */
.my-info-summary-stat-clickable {
	border: none;
	background: none;
	padding: 0;
	font: inherit;
	cursor: pointer;
}

/* .my-info-summary-level이 <button>이 되며 위 규칙의 padding:0/background:none과 같은 특이도라 나중 정의가 이겨 알약 모양이 깨졌다 — 클래스를 합친 선택자로 특이도를 높여 되돌림. */
.my-info-summary-level.my-info-summary-stat-clickable {
	padding: 1px 5px;
	background: #eaf1fd;
	font-size: 10px;
}

/* 방 안에서는 문서가 아니라 메시지 목록만 스크롤한다. 일반 탭의 height:auto를 제한한다. */
.app:has(.tab-sheet.open .chat-mode) {
	height: 100vh;
	height: 100dvh;
	/* 채팅이 키보드를 가장 많이 쓰는 화면이다. 여기서 안 줄이면 입력창이 키보드 뒤로 숨는다. */
	height: calc(100dvh - var(--dk-keyboard-inset, 0px));
	min-height: 0;
	overflow: hidden;
}

.tab-sheet.open:has(.chat-mode) {
	min-height: 0;
	overflow: hidden;
}

.tab-sheet-body.chat-mode {
	display: flex;
	flex-direction: column;
	min-height: 0;
	padding: 0;
	overflow: hidden;
}

/* 상태 블록 (2026-09-11 SYS-05) — 로딩/빈 상태/실패를 눈으로 구분하기 위한 공통 틀.
   .tab-sheet-placeholder(회색 한 줄)는 로딩·빈 상태 전용으로 남기고, 실패는 아래 --error를 쓴다. */
.state-block {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: var(--dk-space-3);
	padding: var(--dk-space-6) var(--dk-space-4);
	text-align: center;
}

.state-block-message {
	margin: 0;
	color: var(--dk-text-secondary);
	font-size: var(--dk-font-body);
	line-height: var(--dk-leading-body);
}

/* 실패는 '비어 있음'과 반드시 달라 보여야 한다 — 예전엔 둘 다 똑같은 회색 한 줄이었다. */
.state-block--error {
	gap: var(--dk-space-3);
	border: 1px solid var(--dk-border-soft);
	border-radius: var(--dk-radius-card);
	background: var(--dk-bg-surface-alt-2);
}

.state-block--error .state-block-message {
	color: var(--dk-text-primary);
	font-weight: bold;
}

.state-block-action {
	min-height: var(--dk-touch-min);
	padding: 0 var(--dk-space-6);
	border: none;
	border-radius: var(--dk-radius-control);
	background: #1957D6;
	color: var(--dk-text-inverse);
	font-family: inherit;
	font-size: var(--dk-font-item);
	font-weight: bold;
	cursor: pointer;
}

/* 재시도가 진행 중임을 보이게 한다 — 눌렀는데 아무 반응이 없으면 또 누른다. */
.state-block-action:disabled {
	background: var(--dk-bg-surface-alt);
	color: var(--dk-text-secondary);
	cursor: default;
}

.tab-sheet-placeholder {
	color: var(--dk-text-secondary);
	font-size: 14px;
	text-align: center;
	margin-top: 40px;
}

.chat-room-list {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: 10px;
}

.chat-room-item {
	position: relative;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 4px;
	width: 100%;
	padding: 10px 6px;
	transform: skewX(-3deg);
	background: var(--dk-bg-surface);
	border: 1px solid var(--dk-border-soft);
	border-radius: 12px;
	box-shadow: var(--dk-shadow-sm);
	font-family: inherit;
	color: var(--dk-text-primary);
	cursor: pointer;
	text-align: center;
	overflow: hidden;
}

.chat-room-item.full {
	opacity: 0.5;
}


.chat-room-item--wide {
	grid-column: 1 / -1;
	flex-direction: row;
	justify-content: space-between;
	text-align: left;
	background: #eaf1ff;
	border-color: #c7d9fb;
}

.chat-room-item--participating {
	background: #eef4ff;
	/* (2026-09-11 SYS-03) 테두리 두께(1px->2px)를 바꾸면 상자 크기가 같이 바뀌어 참여 상태에
	   따라 타일 안쪽 내용이 1px씩 밀린다. 두께는 그대로 두고 box-shadow로 굵기를 그린다. */
	border-color: var(--dk-notify-server);
	box-shadow: inset 0 0 0 1px var(--dk-notify-server), var(--dk-shadow-sm);
	/* (2026-09-11 CHAT-05) 예전엔 구석 리본과 겹치지 않으려고 padding-top: 18px을 더했다.
	   그래서 참여 여부에 따라 타일 안쪽 기준선이 내려갔다(SYS-03이 남겨 둔 마지막 한 건).
	   리본을 인라인 "내 방" 표시로 바꿔 겹칠 일이 없어졌으므로 보정도 함께 지웠다. */
}

/* 방 타일 안의 작은 표시 (2026-09-11 CHAT-05) — "내 방", "운영진에게 1:1 문의".
   예전엔 구석에 기울어진 리본을 절대 배치로 얹었는데, 가운데 정렬된 이름과 겹쳐서
   참여 중인 타일에만 상단 여백을 더해 피하고 있었다(= 참여 여부로 기준선이 움직였다).
   이름·인원과 같은 흐름에 놓으면 겹칠 일이 없다. */
.chat-room-badge {
	position: relative;
	z-index: 1;
	max-width: 100%;
	padding: 1px 5px;
	border-radius: var(--dk-radius-pill);
	font-size: var(--dk-font-micro);
	line-height: var(--dk-leading-micro);
	font-weight: bold;
	/* 타일이 기울어 있으므로 글자는 반대로 되돌려 수평으로 읽히게 한다. */
	transform: skewX(3deg);
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.chat-room-badge--mine {
	background: var(--dk-notify-server);
	color: var(--dk-text-inverse);
}

.chat-room-badge--purpose {
	background: var(--dk-bg-surface-alt-2);
	color: var(--dk-text-secondary);
}

.chat-room-item--unread::after {
	content: '';
	position: absolute;
	top: 6px;
	right: 6px;
	z-index: 1;
	width: 9px;
	height: 9px;
	border-radius: 50%;
	/* (2026-09-11 NOTICE-02) 여기는 서버채팅이다. 예전엔 공지 색(핑크)이 박혀 있었다. */
	background: var(--dk-notify-server);
	border: 1.5px solid var(--dk-bg-surface);
	transform: skewX(3deg);
}

/* 정원 게이지 (2026-09-11 CHAT-05 갱신) — 예전엔 초록→노랑→주황으로 채웠다.
   그건 ui.md가 "브랜드/UI 크롬 색으로 재사용하지 않는다"고 못 박은 **난이도 경고 스펙트럼**이다.
   주행 중 화면을 훑는 라이더가 "이 주황이 위험한 지역인가, 방이 찼다는 뜻인가"를 헷갈리면
   안전 문제로 이어진다(ui.md 맨 앞 원칙). 정원은 위험 신호가 아니므로 쿨톤 한 색의 농도로만
   나타낸다 — 찰수록 진해져서 "얼마나 찼는지"는 그대로 읽힌다. */
.chat-room-fill {
	position: absolute;
	top: 0;
	left: 0;
	bottom: 0;
	background: rgba(25, 87, 214, 0.12);
	transition: width 0.2s ease, background-color 0.3s ease;
	z-index: 0;
}

.chat-room-fill--tight {
	background: rgba(25, 87, 214, 0.22);
}

.chat-room-fill--full {
	background: rgba(25, 87, 214, 0.34);
}

.chat-room-name {
	position: relative;
	z-index: 1;
	font-size: 14px;
	font-weight: bold;
	transform: skewX(3deg);
}

.chat-room-count {
	position: relative;
	z-index: 1;
	font-size: 12px;
	color: var(--dk-text-secondary);
	transform: skewX(3deg);
}

body:not(.is-desktop-view) .chat-room-list {
	gap: 6px;
}

body:not(.is-desktop-view) .chat-room-item {
	padding: 6px 6px;
	gap: 2px;
}

.chat-wrap {
	flex: 1;
	min-height: 0;
	display: flex;
	flex-direction: column;
	overflow: hidden;
}

.chat-back-button {
	flex: 0 0 auto;
	min-width: 44px;
	min-height: 44px;
	padding: 0 8px;
	border: none;
	background: none;
	color: #1957D6;
	font-size: 13px;
	font-weight: bold;
	font-family: inherit;
	text-align: left;
	cursor: pointer;
}

.chat-header-row {
	flex: 0 0 auto;
	display: flex;
	align-items: center;
	min-width: 0;
	min-height: var(--dk-touch-min);
	border-bottom: 1px solid var(--dk-border-soft);
}

.chat-header-row .chat-back-button {
	flex: 1;
	border-bottom: none;
}


.dm-leave-button {
	flex: 0 0 auto;
	min-width: 44px;
	min-height: 44px;
	padding: 0 10px;
	border: none;
	background: none;
	color: var(--dk-text-secondary);
	font-size: 13px;
	font-weight: bold;
	font-family: inherit;
	cursor: pointer;
}

.dm-leave-button:active {
	color: #ef4444;
}

.chat-occupancy {
	flex: 0 0 auto;
	width: 100%;
	padding: 8px 16px;
	border: none;
	border-bottom: 1px solid var(--dk-border-soft);
	background: none;
	color: var(--dk-text-secondary);
	font-size: 12px;
	font-family: inherit;
	text-align: left;
	cursor: pointer;
}

/* 유니코드 글리프 대신 테두리 2개를 45도 회전시켜 그리는 순수 CSS 화살표 — 폰트/인코딩 이슈에서 자유롭다. 패널이 열리면(.open) 뒤집어서 "접을 수 있다"를 같이 알려줌. */
.chat-occupancy::after {
	content: '';
	display: inline-block;
	float: right;
	width: 7px;
	height: 7px;
	margin-top: 2px;
	border-right: 2px solid var(--dk-text-secondary);
	border-bottom: 2px solid var(--dk-text-secondary);
	transform: rotate(45deg);
	transition: transform 0.2s ease;
}

.chat-occupancy.open::after {
	margin-top: 6px;
	transform: rotate(225deg);
}

.chat-occupant-list {
	flex: 0 0 auto;
	max-height: 40%;
	overflow-y: auto;
	border-bottom: 1px solid var(--dk-border-soft);
}

.chat-occupant-item {
	display: flex;
	align-items: center;
	gap: 10px;
	padding: 8px 16px;
}

.chat-occupant-item img {
	flex: 0 0 auto;
	width: 32px;
	height: 32px;
	border-radius: 50%;
	object-fit: cover;
}

.chat-occupant-item-name {
	font-size: 13px;
}

.chat-message-list {
	--chat-meta-foreground: var(--dk-text-secondary);
	--chat-date-surface: var(--dk-bg-surface-alt-2);
	--chat-date-text: var(--dk-text-secondary);
	--chat-received-bubble: var(--dk-bg-surface);
	--chat-received-text: var(--dk-text-primary);
	--chat-received-border: var(--dk-border-soft);
	flex: 1;
	min-height: 0;
	overflow-y: auto;
	overscroll-behavior-y: contain;
	padding: 16px 12px;
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: 12px;
}

/* (2026-09-10) 메시지가 컨테이너를 다 못 채울 때 위가 아니라 아래에 붙게 한다.
   히스토리를 50건에서 10건으로 줄인 뒤, 대화가 적은 방에서 메시지가 화면 위쪽에 뜨고 아래가
   텅 비어 "채팅이 안 나온다"처럼 보이는 제보가 있었다.
   ⚠️ justify-content: flex-end가 아니라 첫 자식의 margin-top: auto를 쓰는 이유 — flex-end는
   내용이 넘칠 때 위쪽으로 삐져나간 부분을 스크롤로 되돌릴 수 없게 만드는 브라우저 버그가 있다.
   margin-top: auto는 남는 공간이 있을 때만 밀어내고, 넘치면 자동으로 0이 되어 정상 스크롤된다. */
.chat-message-list > .chat-message:first-child {
	margin-top: auto;
}

/* 날짜 구분선이 첫 자식인 날에도 짧은 대화의 하단 정렬을 유지한다. */
.chat-message-list > .chat-date-separator:first-child {
	margin-top: auto;
}

.chat-message {
	flex-shrink: 0;
	display: flex;
	align-items: flex-start;
	gap: 8px;
}

/* 연속 메시지 묶음 (2026-09-11 CHAT-03) — 같은 사람이 3분 안에 이어 쓴 말.
   목록의 gap이 12px(묶음 사이)이므로 8px을 되돌려 묶음 안쪽을 4px로 만든다.
   음수 margin이 편법처럼 보이지만, gap을 4px로 낮추고 묶음 시작마다 margin을 더하는 방식은
   ".chat-message:first-child { margin-top: auto }"(CHAT-01의 스크롤 보정)와 충돌한다. */
.chat-message--grouped {
	margin-top: -8px;
}

/* 위 규칙보다 특이도가 높아야 한다 — 과거 대화를 위에 끼워 넣으면 묶인 메시지가 첫 줄이 될 수 있고,
   그때 -8px가 이기면 CHAT-01의 스크롤 보정이 깨진다. */
.chat-message-list > .chat-message--grouped:first-child {
	margin-top: auto;
}

/* 아바타 자리는 남긴다 — 없애면 이어진 말들이 왼쪽으로 튀어나와 묶음으로 안 읽힌다. */
.chat-message--grouped .chat-message-avatar {
	visibility: hidden;
}

.chat-message--grouped .chat-message-nickname {
	display: none;
}

/* 시간은 묶음의 마지막 하나만 남긴다 — 같은 시각이 세 번, 네 번 반복되는 게 원래 문제였다. */
.chat-message--time-hidden .chat-message-time {
	display: none;
}

/* 이름도 시간도 없으면 머리글 줄 자체가 빈 채로 자리를 먹는다. */
.chat-message--grouped.chat-message--time-hidden .chat-message-header {
	display: none;
}

.chat-history-more {
	flex: 0 0 auto;
	min-height: var(--dk-touch-min);
	border: 0;
	border-bottom: 1px solid var(--dk-border-soft);
	background: var(--dk-bg-surface);
	color: var(--dk-text-secondary);
	font: inherit;
	font-size: var(--dk-font-meta);
	cursor: pointer;
}

.chat-history-more[hidden] {
	display: none;
}

.chat-message-own {
	align-self: flex-end;
	flex-direction: row-reverse;
	text-align: right;
	max-width: 78%;
}

.chat-message:not(.chat-message-own) {
	max-width: 78%;
}

.chat-message-avatar {
	flex: 0 0 auto;
	width: 37px;
	height: 37px;
	border-radius: 50%;
	object-fit: cover;
	cursor: pointer;
	transition: transform 0.15s ease;
}

.chat-message-avatar:hover,
.chat-message-avatar.zoomed {
	position: relative;
	z-index: 5;
	transform: scale(2);
}

.chat-message-body {
	min-width: 0;
}

.chat-message-header {
	display: flex;
	align-items: baseline;
	gap: 6px;
}

.chat-message-own .chat-message-header {
	flex-direction: row-reverse;
}

.chat-message-nickname {
	font-size: 13px;
	font-weight: bold;
}

.chat-message-nickname--clickable {
	cursor: pointer;
}

.chat-message-time {
	font-size: 11px;
	color: var(--chat-meta-foreground);
}

.chat-message-text {
	display: inline-block;
	font-size: 14px;
	line-height: 20px;
	margin-top: 4px;
	padding: 8px 12px;
	background: var(--chat-received-bubble, var(--dk-bg-surface));
	color: var(--chat-received-text, var(--dk-text-primary));
	border: 1px solid var(--chat-received-border, var(--dk-border-soft));
	border-radius: 4px 16px 16px 16px;
	/* keep-all/overflow-wrap 이유는 .address-static 코멘트 참고(한글이 아무데서나 안 끊기게). */
	word-break: keep-all;
	overflow-wrap: anywhere;
	text-align: left;
	white-space: pre-wrap;
}

.chat-message-own .chat-message-text {
	background: #1957D6;
	color: var(--dk-text-inverse);
	border-color: #1957D6;
	border-radius: 16px 4px 16px 16px;
}

/* 개인채팅은 상대 프로필을 표시하고, 시각은 말풍선 옆 아래에 둔다. 서버채팅 DOM은 그대로 둔다. */
.dm-chat-header .chat-back-button {
	flex: 0 0 auto;
}

.dm-partner-profile {
	flex: 1;
	min-width: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 6px;
	padding: 2px 4px;
}

.dm-partner-avatar {
	flex: 0 0 auto;
	width: 28px;
	height: 28px;
	border-radius: 50%;
	object-fit: cover;
}

.dm-partner-name {
	min-width: 0;
	max-width: 120px;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
	font-size: 13px;
	font-weight: 700;
	color: var(--dk-text-primary);
}

.chat-header-row .chat-settings-button {
	flex: 0 0 var(--dk-touch-min);
	width: var(--dk-touch-min);
	height: var(--dk-touch-min);
	color: var(--dk-text-secondary);
}

.chat-message.chat-message--dm {
	align-items: flex-start;
	width: 100%;
	max-width: 100%;
}

.chat-message.chat-message--dm.chat-message-own {
	max-width: 100%;
}

.chat-message--dm .chat-message-avatar {
	width: 34px;
	height: 34px;
}

.chat-message--dm .chat-message-body {
	flex: 1 1 auto;
	min-width: 0;
	max-width: calc(100% - 42px);
	display: flex;
	flex-direction: column;
	align-items: flex-start;
}

.chat-message--dm.chat-message-own .chat-message-body {
	width: 100%;
	max-width: 100%;
	align-items: flex-end;
}

.chat-message--dm .chat-message-header {
	min-width: 0;
	margin: 0 0 3px 2px;
}

/* 묶음의 둘째 메시지부터는 닉네임 줄 자체를 없앤다. 아바타 칸은 위 공통 규칙대로 유지한다. */
.chat-message--dm.chat-message--grouped .chat-message-header {
	display: none;
}

.chat-message--dm .chat-message-nickname {
	max-width: 180px;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
	color: var(--chat-meta-foreground);
}

.dm-message-content-row {
	display: flex;
	align-items: flex-end;
	gap: 6px;
	min-width: 0;
	width: 100%;
	max-width: 100%;
}

.chat-message--dm.chat-message-own .dm-message-content-row {
	flex-direction: row-reverse;
}

.chat-message--dm .chat-message-text {
	flex: 0 1 auto;
	min-width: 0;
	max-width: calc(100% - 48px);
	margin-top: 0;
}

.chat-message--dm .chat-message-time {
	flex: 0 0 auto;
	margin-bottom: 1px;
	white-space: nowrap;
	line-height: 1.2;
}

.chat-date-separator {
	flex: 0 0 auto;
	align-self: center;
	max-width: calc(100% - 24px);
	padding: 4px 10px;
	border-radius: var(--dk-radius-pill);
	background: var(--chat-date-surface, var(--dk-bg-surface-alt-2));
	color: var(--chat-date-text, var(--dk-text-secondary));
	font-size: 11px;
	line-height: 16px;
	font-weight: 600;
	text-align: center;
}

.chat-system-message {
	align-self: center;
	color: var(--dk-text-secondary);
	font-size: 13px;
	text-align: center;
	margin: 4px 0;
}


/* (2026-09-11, ui_todo.md CHAT-01) 위를 읽는 중에 새 메시지가 오면 입력창 바로 위에 뜬다.
   본문을 가리지 않도록 목록이 아니라 .chat-wrap의 흐름에 넣었다 — 떠 있는 오버레이로 만들면
   마지막 메시지를 가려서, 정작 확인하려는 내용이 안 보이는 문제가 생긴다. */
.chat-jump-latest {
	flex: 0 0 auto;
	align-self: center;
	margin: 0 0 6px;
	min-height: var(--dk-control-compact);
	padding: 0 14px;
	border: 0;
	border-radius: var(--dk-radius-pill);
	background: #1957D6;
	color: #ffffff;
	font-family: inherit;
	font-size: 12px;
	font-weight: 700;
	box-shadow: var(--dk-shadow-md);
	cursor: pointer;
}

/* 연결 상태 줄 (2026-09-11 CHAT-06) — 실시간 연결이 끊겼을 때만 잠깐 뜨는 줄.
   예전엔 연결이 끊기면 알 방법이 없어서, 새 메시지가 안 오는 걸 보고나서야 알았다.
   대화 내용을 건드리지 않고 위에 줄만 더하는 게 핵심이다. */
.chat-connection-bar {
	flex: 0 0 auto;
	display: flex;
	align-items: center;
	justify-content: center;
	gap: var(--dk-space-2);
	padding: var(--dk-space-2) var(--dk-space-3);
	background: var(--dk-bg-surface-alt-2);
	color: var(--dk-text-secondary);
	font-size: var(--dk-font-meta);
	line-height: var(--dk-leading-meta);
	text-align: center;
}

/* hidden은 브라우저 기본 스타일보다 위의 author display:flex가 우선할 수 있다. 정상 연결 상태에서
   내용 없는 회색 띠가 메시지 목록 위에 남지 않도록 명시적으로 흐름에서도 제거한다. */
.chat-connection-bar[hidden] {
	display: none;
}

/* 재연결 중은 곧 돌아올 가능성이 높아 조용히 두고, 완전히 끊긴 경우만 경고색을 쓴다. */
.chat-connection-bar--failed {
	background: #fdecef;
	color: #b3261e;
	font-weight: bold;
}

body.dark-mode .chat-connection-bar--failed {
	background: #3a1f22;
	color: #ffb4ab;
}

.chat-connection-retry {
	flex: 0 0 auto;
	padding: 2px 10px;
	border: 1px solid currentColor;
	border-radius: var(--dk-radius-pill);
	background: none;
	color: inherit;
	font-family: inherit;
	font-size: var(--dk-font-micro);
	font-weight: bold;
	cursor: pointer;
}

.chat-input-row {
	flex: 0 0 auto;
	display: flex;
	align-items: flex-end;
	gap: 6px;
	padding: 8px 12px calc(8px + env(safe-area-inset-bottom));
	border-top: 1px solid var(--dk-border-soft);
	background: var(--dk-bg-surface);
}

.chat-input-row textarea {
	flex: 1;
	min-width: 0;
	box-sizing: border-box;
	height: 44px;
	min-height: 44px;
	max-height: 104px;
	padding: 11px 14px;
	font-size: var(--dk-input-font);
	line-height: 20px;
	border: 1px solid var(--dk-border);
	border-radius: 22px;
	background: var(--dk-bg-surface);
	color: var(--dk-text-primary);
	font-family: inherit;
	resize: none;
	overflow-y: hidden;
	word-break: keep-all;
	overflow-wrap: anywhere;
}

.chat-send-button {
	flex: 0 0 72px;
	width: 72px;
	height: 44px;
	box-sizing: border-box;
	min-height: var(--dk-touch-min);
	align-self: flex-end;
	padding: 0 8px;
	border: none;
	border-radius: 20px;
	background: #1957D6;
	color: var(--dk-text-inverse);
	font-size: 12px;
	font-weight: bold;
	font-family: inherit;
	cursor: pointer;
	white-space: nowrap;
}

.rider-profile-header {
	display: flex;
	align-items: flex-start;
	gap: 10px;
}

.rider-profile-main {
	flex: 1;
	min-width: 0;
}

.rider-icon-button {
	position: relative;
	flex: 0 0 auto;
	width: 76px;
	height: 76px;
	border-radius: 22px;
	border: 2px solid var(--dk-border-soft);
	background: var(--dk-bg-surface-alt-2);
	padding: 0;
	cursor: pointer;
	overflow: visible;
}

.rider-icon-button img {
	width: 100%;
	height: 100%;
	border-radius: 20px;
	object-fit: cover;
	display: block;
}

.rider-icon-button-placeholder {
	width: 100%;
	height: 100%;
	border-radius: 20px;
	display: flex;
	align-items: center;
	justify-content: center;
	color: var(--dk-text-secondary);
	font-size: 22px;
	font-weight: bold;
}

.rider-icon-button-badge {
	position: absolute;
	right: -4px;
	bottom: -4px;
	width: 24px;
	height: 24px;
	border-radius: 50%;
	background: #1957D6;
	color: var(--dk-text-inverse);
	display: flex;
	align-items: center;
	justify-content: center;
	border: 2px solid var(--dk-bg-surface);
}

.rider-profile-row {
	display: flex;
	align-items: flex-start;
	justify-content: space-between;
	gap: 10px;
	min-height: 26px;
}

.rider-nickname {
	font-size: 16px;
	font-weight: 800;
	color: var(--dk-text-primary);
	flex: 1;
	min-width: 0;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
	line-height: 1.3;
}

.rider-nickname-edit {
	flex: 0 0 auto;
	border: 1px solid var(--dk-border);
	background: var(--dk-bg-surface);
	color: #1957D6;
	border-radius: 6px;
	padding: 4px 10px;
	font-size: 11px;
	font-weight: bold;
	font-family: inherit;
	cursor: pointer;
	white-space: nowrap;
}

.rider-nickname-input {
	flex: 1;
	min-width: 0;
	padding: 10px 12px;
	font-size: var(--dk-input-font);
	border: 1px solid var(--dk-border);
	border-radius: 8px;
	font-family: inherit;
}

.rider-companion-days {
	display: flex;
	align-items: flex-start;
	justify-content: space-between;
	gap: 6px;
	font-size: 13px;
	margin-top: 4px;
	margin-bottom: 2px;
	min-height: 24px;
}

.rider-companion-days-text {
	color: var(--dk-text-secondary);
	flex: 1;
	min-width: 0;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
	line-height: 1.3;
}

.rider-companion-days-name {
	color: var(--dk-text-primary);
	font-weight: bold;
}

.rider-companion-days-edit {
	flex: 0 0 auto;
	border: 1px solid var(--dk-border);
	background: var(--dk-bg-surface);
	color: #1957D6;
	border-radius: 6px;
	padding: 4px 10px;
	font-size: 11px;
	font-weight: bold;
	font-family: inherit;
	cursor: pointer;
	white-space: nowrap;
}

.rider-icon-interaction-count {
	font-size: 11px;
	color: var(--dk-text-secondary);
	margin-top: 2px;
	min-height: 14px;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

.rider-profile-level-row {
	display: flex;
	align-items: center;
	gap: 6px;
	margin-top: 4px;
}

.rider-level-badge {
	flex-shrink: 0;
	font-size: 11px;
	font-weight: bold;
	color: var(--dk-text-inverse);
	background: #1957D6;
	border-radius: 9px;
	padding: 2px 7px;
	line-height: 1.4;
}

.rider-level-bar-track {
	position: relative;
	flex: 1;
	min-width: 0;
	height: 16px;
	background: var(--dk-bg-surface-alt);
	border-radius: 8px;
	overflow: hidden;
}

.rider-level-bar-fill {
	height: 100%;
	width: 0%;
	background: linear-gradient(90deg, #4d8dff, #1957D6);
	border-radius: 8px;
	transition: width 0.3s ease;
}

/* 필드 HUD(.field-hud-xp-percent, 아래 4266줄대)와 동일하게 블러 반경 0인 1px 오프셋 4방향 text-shadow로 1도트 흰 외곽선만 — 채워진/안 채워진 배경 둘 다에서 읽히도록 필드 정책을 그대로 통일. */
.rider-level-bar-text {
	position: absolute;
	inset: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	font-size: 10px;
	font-weight: bold;
	color: #1957D6;
	text-shadow:
		-1px -1px 0 #ffffff,
		1px -1px 0 #ffffff,
		-1px 1px 0 #ffffff,
		1px 1px 0 #ffffff;
	pointer-events: none;
}

.rider-profile-stats {
	display: flex;
	gap: 28px;
	margin-top: 6px;
}

.rider-stat {
	display: flex;
	flex-direction: column;
}

.rider-stat-value {
	font-size: 20px;
	font-weight: bold;
	color: #1957D6;
	line-height: 1;
}

.rider-stat-label {
	font-size: 12px;
	color: var(--dk-text-secondary);
	margin-top: 1px;
	text-decoration: underline;
}

/* 포인트가 올랐을 때 뜨는 "+N" 플로팅 텍스트 + 숫자 자체의 짧은 펄스 — field-hud-points/riderPoints 공용(playPointGainAnimation). 부모에 JS가 즉석에서 position:relative를 걸어 별도 래퍼 없이 절대 위치로 겹쳐 띄운다. */
@keyframes pointGainFloat {
	0% { opacity: 0; transform: translate(-50%, 0) scale(0.85); }
	15% { opacity: 1; transform: translate(-50%, -6px) scale(1); }
	75% { opacity: 1; transform: translate(-50%, -22px) scale(1); }
	100% { opacity: 0; transform: translate(-50%, -30px) scale(1); }
}

.point-gain-float {
	position: absolute;
	left: 50%;
	top: -2px;
	transform: translate(-50%, 0);
	font-size: 13px;
	font-weight: bold;
	color: #ffaa00;
	white-space: nowrap;
	pointer-events: none;
	animation: pointGainFloat 1.1s ease-out forwards;
	z-index: 50;
}

@keyframes pointGainPulse {
	0% { transform: scale(1); }
	30% { transform: scale(1.3); }
	100% { transform: scale(1); }
}

.point-gain-pulse {
	display: inline-block;
	animation: pointGainPulse 0.4s ease-out;
}

.rider-stat-clickable {
	border: none;
	background: none;
	padding: 0;
	font: inherit;
	text-align: left;
	cursor: pointer;
}

.rider-level-row-clickable {
	cursor: pointer;
}

.history-screen-note {
	margin: 4px 0 0;
	padding: 0 4px;
	font-size: 12px;
	color: var(--dk-text-secondary);
}

.point-history-list {
	display: flex;
	flex-direction: column;
}

.point-history-item {
	display: flex;
	align-items: center;
	justify-content: space-between;
	padding: 12px 4px;
	border-bottom: 1px solid var(--dk-border-soft);
}

.point-history-main {
	display: flex;
	flex-direction: column;
	gap: 3px;
	min-width: 0;
}

.point-history-reason {
	font-size: 14px;
	font-weight: bold;
}

.point-history-time {
	font-size: 12px;
	color: var(--dk-text-secondary);
	font-weight: normal;
}

.point-history-delta {
	flex: 0 0 auto;
	font-size: 15px;
	font-weight: bold;
	color: #1957D6;
}

.point-history-delta-negative {
	color: #e74c3c;
}

/* 지나온 레벨(1~내 레벨)은 전부, 앞으로는 내 레벨+15까지 목록, 다음 4개는 JS에서 opacity를 인라인으로 25%p씩 깎아 점점 흐려지게(renderLevelGuideScreen), 그 이후는 렌더링 없이 .level-guide-row-ellipsis 한 줄로 갈음. */
.level-guide-list {
	display: flex;
	flex-direction: column;
}

/* (2026-09-05 신설, 사용자 요청 — UI_ref 스크린샷 "_04"(지휘관 경로) 참고해서 레벨 가이드 개선)
   세로 트랙 선 + 노드는 행마다 독립적으로 그린다(::before가 선, ::after가 노드) — 지난 행은
   level-guide-row--passed로 파랑, 아직 안 지난 행은 회색이라 행끼리 이어 붙으면 저절로 "여기까지
   왔다"는 하나의 선으로 보인다(누적 픽셀 계산 불필요). 노드 자리(left:20px)만큼 기존 gap 앞에
   여백을 둬야 해서 padding-left를 늘림. */
.level-guide-row {
	position: relative;
	display: flex;
	align-items: center;
	gap: 10px;
	padding: 10px 4px 10px 38px;
	border-bottom: 1px solid var(--dk-border-soft);
	transition: opacity 0.2s ease;
}

.level-guide-row::before {
	content: '';
	position: absolute;
	left: 19px;
	top: 0;
	bottom: 0;
	width: 2px;
	background: var(--dk-bg-surface-alt);
}

.level-guide-row--passed::before {
	background: #1957D6;
}

.level-guide-row::after {
	content: '';
	position: absolute;
	left: 14px;
	top: 50%;
	transform: translateY(-50%);
	width: 12px;
	height: 12px;
	border-radius: 50%;
	background: var(--dk-bg-surface);
	border: 2px solid var(--dk-border-soft);
	box-sizing: border-box;
	z-index: 1;
}

.level-guide-row--passed::after {
	background: #1957D6;
	border-color: #1957D6;
}

.level-guide-row--current::after {
	width: 16px;
	height: 16px;
	left: 12px;
	background: var(--dk-bg-surface);
	border-color: #1957D6;
	box-shadow: 0 0 0 3px rgba(25, 87, 214, 0.18);
}

.level-guide-row--current {
	background: #eef4ff;
	border-radius: 8px;
	padding-right: 8px;
}

.level-guide-row-ellipsis {
	padding: 10px 4px 10px 38px;
	text-align: center;
	font-size: 16px;
	font-weight: bold;
	color: var(--dk-text-secondary);
	letter-spacing: 2px;
}

/* (2026-09-05 갱신) 레벨 숫자를 더 크게 — ref.md가 지적한 "레벨 번호를 보상 아이콘만큼 크게" 반영. */
.level-guide-row-level {
	flex: 0 0 auto;
	font-size: 18px;
	font-weight: 800;
	color: #1957D6;
	min-width: 52px;
}

.level-guide-row-xp {
	flex: 1;
	font-size: 13px;
	color: var(--dk-text-tertiary);
}

.level-guide-row-current-badge {
	flex: 0 0 auto;
	font-size: 11px;
	font-weight: bold;
	color: var(--dk-text-inverse);
	background: #1957D6;
	border-radius: 9px;
	padding: 2px 7px;
}

.point-history-place-link {
	padding: 0;
	border: none;
	background: none;
	font: inherit;
	font-size: 12px;
	font-weight: normal;
	color: #1957D6;
	text-decoration: underline;
	text-align: left;
	cursor: pointer;
}

/* (2026-09-05 신설, 사용자 요청 — "선택중인 캐릭터의 경우 상단 공간을 할애해서... 캐릭터 설명창"
   source2learn/UI_ref/ref.md 1-4 "상단에 캐릭터 일러스트+타이틀"을 참고하되, ref.md 3-2 원칙대로
   게임처럼 화려하게 꾸미지 않고 배맵 톤(연한 배경/얇은 테두리)에 맞춰 절제된 카드로 구성. */
.icon-picker-current-card {
	display: flex;
	align-items: flex-start;
	gap: 12px;
	margin: 4px 24px 12px;
	padding: 12px;
	background: var(--dk-bg-surface-alt-2);
	border: 1px solid var(--dk-border-soft);
	border-radius: 16px;
}

.icon-picker-current-portrait {
	flex: 0 0 auto;
	width: 72px;
	height: 72px;
	border-radius: 20px;
	object-fit: cover;
}

.icon-picker-current-info {
	flex: 1;
	min-width: 0;
}

.icon-picker-current-name-row {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: 6px;
	margin-bottom: 4px;
}

.icon-picker-current-name {
	font-size: 15px;
	font-weight: bold;
	color: var(--dk-text-primary);
}

.icon-picker-current-days {
	font-size: 11px;
	font-weight: bold;
	color: #1957D6;
	background: #e7eefc;
	border-radius: 999px;
	padding: 2px 8px;
}

.icon-picker-current-intro {
	margin: 0;
	font-size: 12.5px;
	line-height: 1.55;
	color: var(--dk-text-tertiary);
}

/* 그리드 카드 안, 이름 아래 작게 붙는 동행일수 캡션 — 배지(코너 태그)와 자리가 겹치지 않는 별도 줄. */
.icon-picker-item-days {
	font-size: 9px;
	color: var(--dk-text-secondary);
	margin-top: -2px;
	max-width: 100%;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

/* (2026-09-05 전면 재설계, 사용자 요청 — "기존 UI는 폐기라고 보고 KakaoTalk_..._03.jpg 이미지와
   ref문서를 참고해서... 한줄에 4개 노출하도록") source2learn/UI_ref/ref.md 1-3 "카드 앵커토미" 패턴
   (카드 본체 + 우상단 코너 오버플로 뱃지)을 4열 그리드로 재구성 — 지그재그 배치는 3열 전용 꼼수라
   폐기, 카드형으로 명확히 구분되는 경계(테두리+옅은 그림자)를 줘서 참고 화면의 "카드가 쌓인" 느낌만
   가져오고 색은 ref.md 3-2 원칙대로 배맵 중립 팔레트 그대로 사용(고채도 탄/보라 그라데이션은 배제). */
.icon-picker-grid {
	display: grid;
	grid-template-columns: repeat(4, 1fr);
	gap: 8px;
	padding: 8px 12px 20px;
}

.icon-picker-item {
	position: relative;
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 3px;
	width: 100%;
	padding: 8px 2px 6px;
	background: var(--dk-bg-surface);
	border: 1px solid var(--dk-border-soft);
	border-radius: 14px;
	box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
	font-family: inherit;
	cursor: pointer;
	box-sizing: border-box;
	overflow: hidden;
}

.icon-picker-item.equipped {
	border: 2px solid #1957D6;
	background: #E7EEFC;
	padding: 7px 1px 5px;
}

.icon-picker-item img {
	width: 56px;
	max-width: 100%;
	aspect-ratio: 1 / 1;
	border-radius: 14px;
	object-fit: cover;
	display: block;
}

.icon-picker-item-name {
	margin-top: 2px;
	max-width: 100%;
	font-size: 11px;
	color: var(--dk-text-primary);
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

.icon-picker-item.equipped .icon-picker-item-name {
	font-weight: bold;
	color: #1957D6;
}

.icon-picker-item-badge {
	position: absolute;
	top: -1px;
	right: -1px;
	padding: 2px 7px 2px 6px;
	border-radius: 0 12px 0 10px;
	font-size: 9px;
	font-weight: bold;
	line-height: 1.2;
	white-space: nowrap;
	background: var(--dk-bg-surface);
	border-bottom: 1px solid var(--dk-border);
	border-left: 1px solid var(--dk-border);
	color: var(--dk-text-secondary);
	z-index: 2;
	pointer-events: none;
}

.icon-picker-item.equipped .icon-picker-item-badge {
	background: #1957D6;
	border: none;
	color: var(--dk-text-inverse);
}

/* (2026-09-05 갱신, ref.md 3-1 "색상 시맨틱" — 모양은 그대로, 색으로만 의미 구분) 미보유 가격
   배지는 앱 전역에서 "포인트"를 가리키는 골드 톤(필드 HUD의 "P" 배지/point-award-badge와 동일 계열)
   으로 통일 — 예전엔 무채색이라 장착중(파랑) 배지와만 구분되고 "보유" 상태와는 안 겹치는 게
   우연이었는데, 지금은 3색 다 의도적으로 다른 의미 색. */
.icon-picker-item-badge.icon-picker-item-price {
	background: #fff6e0;
	border-bottom: 1px solid #f5cb7a;
	border-left: 1px solid #f5cb7a;
	color: #a9720d;
	top: -1px;
	right: -1px;
}

/* (2026-09-05 신설) 보유했지만 미장착 상태 — 예전엔 배지가 아예 없어서 구경 중인 캐릭터와 구분이
   안 됐다. 초록(보유/완료를 뜻하는 앱 공용 색 — register.html의 등록 완료 체크 등과 같은 계열). */
.icon-picker-item-badge.icon-picker-item-owned {
	background: #eafaf1;
	border-bottom: 1px solid #b7e4c7;
	border-left: 1px solid #b7e4c7;
	color: #1e8449;
	top: -1px;
	right: -1px;
}

.item-inventory-wrap {
	display: flex;
	flex-direction: column;
	gap: 12px;
	padding: 4px 4px 20px;
}

.item-inventory-header {
	background: linear-gradient(145deg, var(--dk-bg-surface) 0%, var(--dk-bg-surface-alt-2) 100%);
	border: 1px solid var(--dk-border);
	border-radius: 14px;
	padding: 12px 14px;
	box-shadow: 0 2px 8px rgba(0, 0, 0, 0.03);
	display: flex;
	align-items: center;
	justify-content: space-between;
}

.item-inventory-header-top {
	display: flex;
	align-items: center;
	justify-content: space-between;
	width: 100%;
}

.item-inventory-title {
	display: flex;
	align-items: center;
	gap: 6px;
	font-size: 14px;
	font-weight: 800;
	color: var(--dk-text-primary);
	letter-spacing: -0.3px;
}

.item-inventory-title-icon {
	font-size: 15px;
}

.item-inventory-capacity-pill {
	display: flex;
	align-items: center;
	gap: 6px;
	background: var(--dk-bg-surface-alt);
	padding: 4px 10px;
	border-radius: 999px;
	font-size: 11px;
	color: var(--dk-text-tertiary);
}

.item-inventory-count strong {
	color: #1957D6;
	font-weight: 800;
}

/* Category Filter Chips */
.item-inventory-filter-bar {
	display: flex;
	align-items: center;
	gap: 6px;
	overflow-x: auto;
	padding-bottom: 2px;
	scrollbar-width: none;
}
.item-inventory-filter-bar::-webkit-scrollbar {
	display: none;
}

.item-inventory-filter-chip {
	flex: 0 0 auto;
	border: 1px solid var(--dk-border);
	background: var(--dk-bg-surface);
	color: var(--dk-text-secondary);
	font-size: 11px;
	font-weight: 600;
	padding: 5px 11px;
	border-radius: 999px;
	cursor: pointer;
	transition: all 0.2s ease;
	font-family: inherit;
}

.item-inventory-filter-chip:hover {
	background: var(--dk-bg-surface-alt-2);
	color: var(--dk-text-primary);
	border-color: var(--dk-border);
}

.item-inventory-filter-chip.active {
	background: #0f172a;
	color: var(--dk-text-inverse);
	border-color: #0f172a;
	box-shadow: 0 2px 6px rgba(15, 23, 42, 0.2);
}

.item-inventory-empty-filter {
	text-align: center;
	padding: 30px 10px;
	color: var(--dk-text-secondary);
	font-size: 12px;
	grid-column: 1 / -1;
}

/* Grid Layout */
.item-inventory-grid {
	display: grid;
	grid-template-columns: repeat(4, 1fr);
	gap: 9px;
}

.item-inventory-slot {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 4px;
	width: 100%;
}

.item-inventory-slot-icon {
	position: relative;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 100%;
	aspect-ratio: 1 / 1;
	border-radius: 14px;
	background: radial-gradient(circle at 50% 30%, #f1f4f9 0%, #e2e8f0 100%);
	border: 1px solid var(--dk-border);
	box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.8), 0 2px 5px rgba(0, 0, 0, 0.05);
	cursor: pointer;
	overflow: hidden;
	transition: all 0.2s cubic-bezier(0.16, 1, 0.3, 1);
	box-sizing: border-box;
}

.item-inventory-slot-icon:hover {
	transform: translateY(-2px);
	box-shadow: 0 8px 20px rgba(25, 87, 214, 0.18), 0 0 0 1.5px #1957D6;
	border-color: #1957D6;
}

.item-inventory-slot-img {
	width: 82%;
	height: 82%;
	object-fit: contain;
	filter: drop-shadow(0 4px 8px rgba(15, 23, 42, 0.18));
	transition: transform 0.2s cubic-bezier(0.16, 1, 0.3, 1);
}

.item-inventory-slot-icon:hover .item-inventory-slot-img {
	transform: scale(1.08);
}

.item-inventory-slot-emoji {
	font-size: 26px;
	filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.1));
}

/* Quantity Pill */
.item-inventory-slot-qty {
	position: absolute;
	top: 4px;
	right: 4px;
	background: rgba(15, 23, 42, 0.82);
	backdrop-filter: blur(4px);
	-webkit-backdrop-filter: blur(4px);
	color: var(--dk-text-inverse);
	font-size: 9.5px;
	font-weight: 800;
	padding: 1.5px 5.5px;
	border-radius: 999px;
	border: 1px solid rgba(255, 255, 255, 0.2);
	box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
	line-height: 1.2;
	pointer-events: none;
}

/* (2026-09-05 신설, target.md Part 3) 둥지에 배치된 아이템 표시용 리본 — 수량 뱃지와 반대쪽 하단에 */
.item-inventory-slot-placed-badge {
	position: absolute;
	left: 0;
	right: 0;
	bottom: 0;
	background: rgba(25, 87, 214, 0.85);
	backdrop-filter: blur(4px);
	-webkit-backdrop-filter: blur(4px);
	color: #fff;
	font-size: 8.5px;
	font-weight: 800;
	padding: 2px 0;
	text-align: center;
	pointer-events: none;
}

.item-inventory-slot-name {
	font-size: 11px;
	font-weight: 700;
	color: var(--dk-text-primary);
	text-align: center;
	line-height: 1.25;
	height: 28px;
	display: -webkit-box;
	-webkit-box-orient: vertical;
	-webkit-line-clamp: 2;
	overflow: hidden;
	width: 100%;
	word-break: keep-all;
	padding: 0 2px;
	letter-spacing: -0.3px;
}

.item-inventory-slot-name-empty {
	visibility: hidden;
}

/* Empty Slot */
.item-inventory-slot-icon-empty {
	background: var(--dk-bg-surface-alt);
	border: 1.5px dashed var(--dk-border);
	box-shadow: none;
	cursor: default;
}

.item-inventory-slot-icon-empty::after {
	content: '';
	width: 5px;
	height: 5px;
	border-radius: 50%;
	background: #94a3b8;
	opacity: 0.6;
}

.item-inventory-slot-icon-empty:hover {
	transform: none;
	box-shadow: none;
	border-color: var(--dk-border);
	background: var(--dk-bg-surface-alt);
}

/* Expand Button */
.item-inventory-slot-expand {
	background: linear-gradient(135deg, #eef5ff 0%, #e0edff 100%);
	border: 1.5px dashed #3b82f6;
	color: #1957D6;
	cursor: pointer;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 0;
}

.item-expand-plus {
	font-size: 24px;
	font-weight: 800;
	line-height: 1;
	transition: transform 0.2s ease;
}

.item-inventory-slot-expand:hover {
	background: #1957D6;
	border-color: #1957D6;
	color: var(--dk-text-inverse);
	transform: translateY(-2px);
	box-shadow: 0 8px 18px rgba(25, 87, 214, 0.25);
}

.item-inventory-slot-expand:hover .item-expand-plus {
	transform: scale(1.15) rotate(90deg);
}

.item-inventory-slot-icon.cat-mat {
	background: radial-gradient(circle at 50% 30%, var(--dk-bg-surface-alt) 0%, #e2e8f0 100%);
	border-color: var(--dk-border);
}
.item-inventory-slot-icon.cat-food {
	background: radial-gradient(circle at 50% 30%, #fff7ed 0%, #fed7aa 100%);
	border-color: #fdba74;
}
.item-inventory-slot-icon.cat-furn {
	background: radial-gradient(circle at 50% 30%, #f0fdf4 0%, #bbf7d0 100%);
	border-color: #86efac;
}
.item-inventory-slot-icon.cat-gift {
	background: radial-gradient(circle at 50% 30%, #fdf2f8 0%, #fbcfe8 100%);
	border-color: #f472b6;
}
.item-inventory-slot-icon.cat-consumable {
	background: radial-gradient(circle at 50% 30%, #faf5ff 0%, #e9d5ff 100%);
	border-color: #c084fc;
}

/* Item Info Popover */
.item-info-popup {
	position: fixed;
	max-width: 220px;
	padding: 12px 14px;
	border-radius: 14px;
	background: var(--dk-bg-surface);
	border: 1px solid var(--dk-border);
	color: var(--dk-text-primary);
	font-size: 12px;
	line-height: 1.4;
	box-shadow: 0 10px 25px rgba(0, 0, 0, 0.12), 0 2px 6px rgba(0, 0, 0, 0.04);
	z-index: 800;
	display: none;
	pointer-events: none;
	animation: itemPopupFadeIn 0.15s cubic-bezier(0.16, 1, 0.3, 1);
}

@keyframes itemPopupFadeIn {
	from { opacity: 0; transform: scale(0.95); }
	to { opacity: 1; transform: scale(1); }
}

.item-info-popup-cat {
	display: inline-block;
	font-size: 9.5px;
	font-weight: 800;
	letter-spacing: 0.3px;
	padding: 2px 7px;
	border-radius: 6px;
	margin-bottom: 6px;
	background: #eff6ff;
	color: #1d4ed8;
	border: 1px solid #bfdbfe;
}

.item-info-popup-cat.cat-food { background: #fff7ed; color: #c2410c; border-color: #fed7aa; }
.item-info-popup-cat.cat-furn { background: #f0fdf4; color: #15803d; border-color: #bbf7d0; }
.item-info-popup-cat.cat-gift { background: #fdf2f8; color: #be185d; border-color: #fbcfe8; }
.item-info-popup-cat.cat-consumable { background: #faf5ff; color: #7e22ce; border-color: #e9d5ff; }

.item-info-popup-name {
	font-size: 13.5px;
	font-weight: 800;
	color: var(--dk-text-primary);
	margin-bottom: 4px;
	letter-spacing: -0.2px;
}

.item-info-popup-desc {
	color: var(--dk-text-tertiary);
	font-size: 11.5px;
	line-height: 1.45;
	margin-bottom: 8px;
	word-break: keep-all;
}

.item-info-popup-meta {
	display: flex;
	align-items: center;
	justify-content: space-between;
	font-size: 11px;
	color: var(--dk-text-secondary);
	border-top: 1px solid var(--dk-border-soft);
	padding-top: 6px;
}

.item-info-popup-meta b {
	color: #1957D6;
	font-weight: 800;
}

.item-info-popup-arrow {
	position: absolute;
	bottom: -5px;
	width: 10px;
	height: 10px;
	background: var(--dk-bg-surface);
	border-right: 1px solid var(--dk-border);
	border-bottom: 1px solid var(--dk-border);
	transform: translateX(-50%) rotate(45deg);
	border-radius: 2px;
}

.item-info-popup-below .item-info-popup-arrow {
	bottom: auto;
	top: -5px;
	border-right: none;
	border-bottom: none;
	border-left: 1px solid var(--dk-border);
	border-top: 1px solid var(--dk-border);
}

.history-list {
	display: flex;
	flex-direction: column;
	gap: 8px;
}

.history-item {
	width: 100%;
	padding: 10px 12px;
	border: 1px solid var(--dk-border-soft);
	border-radius: 10px;
	background: var(--dk-bg-surface);
	font-family: inherit;
	color: var(--dk-text-primary);
	text-align: left;
	cursor: pointer;
}

.history-item-address {
	font-size: 13px;
	font-weight: bold;
	letter-spacing: -0.2px;
}

.history-item-updated {
	font-size: 11px;
	color: var(--dk-text-secondary);
	font-weight: normal;
	letter-spacing: -0.1px;
}

.history-item-factors {
	display: flex;
	flex-wrap: wrap;
	gap: 4px;
	margin-top: 6px;
}

.history-item-factor-chip {
	padding: 2px 7px;
	border-radius: 999px;
	background: var(--dk-bg-surface-alt);
	color: var(--dk-text-tertiary);
	font-size: 10px;
	letter-spacing: -0.1px;
}

.history-item-reactions {
	display: flex;
	gap: 10px;
}

.history-item-footer {
	display: flex;
	align-items: center;
	justify-content: space-between;
	margin-top: 6px;
}

.history-item-reaction {
	display: flex;
	align-items: center;
	gap: 3px;
	font-size: 11px;
	font-weight: bold;
	color: var(--dk-text-secondary);
}

.history-item-reaction svg {
	width: 12px;
	height: 12px;
}

.history-sentinel {
	height: 20px;
	margin: 10px 0 0;
	text-align: center;
	font-size: 12px;
	color: var(--dk-text-secondary);
}

.ranking-category-tabs {
	display: flex;
	gap: 4px;
	margin-bottom: 8px;
	border-bottom: 2px solid #1957D6;
}

/* 라벨 글자 수(예: "서버채팅" vs "계정")에 따라 탭 폭이 제각각이었다 — flex:1로 부모(.ranking-category-tabs) 안에서 균등 분배. 그룹마다 탭 개수가 다르므로 그룹 안에서만 같은 폭이고 그룹 간 실제 px는 다르다(고정폭 하드코딩 아님). */
.ranking-category-tab {
	flex: 1;
	/* (2026-09-10) 좌우 패딩을 고정 16px에서 clamp로 바꿨다 — 폭이 좁아지면 패딩이 먼저 줄어들어
	   라벨이 줄바꿈되기 전에 공간을 양보한다. 예전엔 패딩이 고정이라 폭이 420px 근처로 좁아지면
	   "인벤토리"/"지역별 완성도" 같은 라벨이 버튼 안에서 두 줄로 접히며 탭 높이가 들쭉날쭉해졌다. */
	min-width: 0;
	padding: 10px clamp(4px, 2.5vw, 16px);
	border: none;
	border-radius: 12px 12px 0 0;
	background: var(--dk-bg-surface);
	color: var(--dk-text-secondary);
	font-size: 14px;
	font-weight: bold;
	font-family: inherit;
	text-align: center;
	cursor: pointer;
	/* 라벨은 절대 접지 않는다 — 그래도 안 들어가면 줄바꿈 대신 말줄임으로 처리해서 탭 한 줄
	   높이를 유지한다(#rankingCategoryTabs는 원래 nowrap이었고, 나머지 탭 행에도 같은 규칙을 적용). */
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

.ranking-category-tab.active {
	background: #1957D6;
	color: var(--dk-text-inverse);
}

/* 랭킹의 네 가지 분류는 한 줄로 압축하고 긴 지역 라벨에 폭을 더 배분한다. */
#rankingCategoryTabs {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr)) minmax(0, 1.5fr);
	margin-bottom: 6px;
	border-bottom: none;
}

#rankingCategoryTabs .ranking-category-tab {
	min-width: 0;
	min-height: 32px;
	padding: 6px 4px;
	border-radius: 6px;
	font-size: 12px;
	line-height: 18px;
	white-space: nowrap;
}

.ranking-category-tab {
	position: relative;
}

/* 값은 정책과 맞다 — 하드코딩을 토큰으로 옮겨 두는 것뿐이다(NOTICE-02). */
.ranking-category-tab.chat-category-tab--unread::after {
	content: '';
	position: absolute;
	top: 3px;
	right: 5px;
	width: 5px;
	height: 5px;
	border-radius: 50%;
	background: var(--dk-notify-dm);
	border: 1px solid var(--dk-bg-surface);
}

.ranking-item {
	display: flex;
	align-items: center;
	/* (2026-09-10 사용자 요청 — "아이콘을 조금 왼쪽으로 옮기고 글자도 옆으로 조금 옮겨서 닉네임
	   잘리는 걸 줄이자") 간격 12→8, 좌우 패딩 8→6. 순위/아이콘이 왼쪽으로 붙는 만큼 그대로
	   이름 칸이 넓어진다(이름 칸이 flex:1이라 남는 공간을 전부 가져간다). 360px 기준 약 +12px. */
	gap: 8px;
	padding: 6px 6px;
	margin: 4px 2px;
	border: 1px solid var(--dk-border-soft);
	border-radius: 8px;
	background: var(--dk-bg-surface);
	position: relative;
}

/* ============================================================
   1~3위 강조 (2026-09-11 재작업, ui_todo.md RANK-01)
   예전엔 transform: scale(1.09/1.06/1.03)로 행 자체를 키우고 margin도 각각 다르게 줬다.
   문제가 세 가지였다.
     1) scale은 레이아웃 폭을 안 바꾸고 그리기만 확대해서, 1위 행의 내용이 카드 밖으로 삐져나간다.
        (닉네임이 잘리는 문제와 같은 계열 — 실제 폭은 그대로인데 글자만 커지니 더 빨리 잘린다.)
     2) 순위마다 margin/scale이 달라 순위 열·이름 열·점수 열의 기준선이 행마다 어긋난다.
     3) scale + box-shadow + 두꺼운 테두리가 겹쳐 목록 전체의 밀도가 들쭉날쭉해진다.
   이제 크기는 건드리지 않고 **테두리 색과 왼쪽 띠**로만 구분한다. 순위 숫자/애칭의 금·은·동
   색상(.ranking-item-rank--gold 등)은 그대로 살아 있어서 강조가 사라지지는 않는다.
   ============================================================ */
.ranking-item--gold,
.ranking-item--silver,
.ranking-item--bronze {
	/* 왼쪽 띠로 등급을 표시한다 — 행 높이와 기준선을 건드리지 않는 유일한 방향. */
	border-left-width: 3px;
}

.ranking-item--gold {
	border-color: #FFD700;
	background: linear-gradient(90deg, rgba(255, 215, 0, 0.10), transparent 40%);
}

.ranking-item--silver {
	border-color: #C0C0C0;
	background: linear-gradient(90deg, rgba(160, 160, 160, 0.10), transparent 40%);
}

.ranking-item--bronze {
	border-color: #CD7F32;
	background: linear-gradient(90deg, rgba(205, 127, 50, 0.10), transparent 40%);
}

.ranking-item--me {
	/* 이 규칙이 위 1~3위 배경보다 뒤에 있어야 "내가 1위"일 때 내 랭킹 표시가 이긴다. */
	margin-bottom: 8px;
	/* 위 .ranking-item과 같은 값이어야 한다 — 다르면 "내 랭킹" 행만 이름 칸이 좁아진다. */
	padding: 6px 6px;
	background: #eef4ff;
	border: 1px solid #1957D6;
	border-radius: 10px;
}

.ranking-item-rank {
	flex: 0 0 auto;
	width: 26px;
	text-align: center;
	font-size: 14px;
	font-weight: bold;
	color: var(--dk-text-secondary);
}

/* 예전엔 그라디언트+광택 띠+drop-shadow로 금속 느낌을 냈으나, 애칭 줄(.ranking-item-icon-nickname--*)과 통일감을 위해 전부 걷어내고 단색으로 정리. */
.ranking-item-rank--gold {
	color: #C99A2E;
}

.ranking-item-rank--silver {
	color: #949494;
}

.ranking-item-rank--bronze {
	color: #A85C25;
}

.ranking-item img {
	flex: 0 0 auto;
	width: 30px;
	height: 30px;
	border-radius: 50%;
	object-fit: cover;
}

/* (2026-09-06 신설) 지역별 완성도 탭 — 캐릭터 아이콘 자리를 대신하는 이모지 */
.ranking-item-region-emoji {
	flex: 0 0 auto;
	width: 30px;
	height: 30px;
	display: flex;
	align-items: center;
	justify-content: center;
	font-size: 18px;
}

.ranking-item-name {
	flex: 1;
	font-size: 14px;
	font-weight: bold;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.ranking-item-icon-nickname {
	font-size: 9px;
	font-weight: bold;
	line-height: 1.1;
	margin-bottom: 1px;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.ranking-item-icon-nickname--gold {
	color: #C99A2E;
}

.ranking-item-icon-nickname--silver {
	color: #949494;
}

.ranking-item-icon-nickname--bronze {
	color: #A85C25;
}

.ranking-item-icon-nickname-particle {
	font-size: 0.8em;
	font-weight: normal;
}

.ranking-item-name--gold {
	color: #C99A2E;
}

.ranking-item-name--silver {
	color: #949494;
}

.ranking-item-name--bronze {
	color: #A85C25;
}

.ranking-item-score {
	flex: 0 0 auto;
	font-size: 13px;
	font-weight: bold;
	color: #1957D6;
}

/* 글로벌 전광판 (Ticker) — 필드(location) 탭에서만 노출 */
#globalTicker {
    display: none;
    background-color: var(--dk-bg-surface);
    color: var(--dk-text-primary);
    font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, sans-serif;
    font-size: 13px;
    font-weight: 400;
    padding: 5px 0;
    overflow: hidden;
    white-space: nowrap;
    position: relative;
    border-bottom: 1px solid var(--dk-border);
}
/* 플라스틱 판 대각선 글로우 */
#globalTicker::before {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(
        135deg,
        rgba(0,0,0,0.03) 0%,
        rgba(0,0,0,0.01) 30%,
        transparent 50%,
        rgba(0,0,0,0.008) 70%,
        rgba(0,0,0,0.02) 100%
    );
    pointer-events: none;
    z-index: 2;
}
/* LED 소자 알갱이(dot-matrix) 오버레이 */
#globalTicker::after {
    content: '';
    position: absolute;
    inset: 0;
    background:
        repeating-linear-gradient(
            0deg,
            rgba(0,0,0,0.015) 0px,
            rgba(0,0,0,0.015) 1px,
            transparent 1px,
            transparent 3px
        ),
        repeating-linear-gradient(
            90deg,
            rgba(0,0,0,0.015) 0px,
            rgba(0,0,0,0.015) 1px,
            transparent 1px,
            transparent 3px
        );
    pointer-events: none;
    z-index: 1;
}
body[data-active-tab="location"] #globalTicker {
    display: block;
}

/* #globalTicker가 이미 position:relative라 여기 기준 절대 배치. LED 오버레이(::before/::after, z-index 1~2)보다 위에 두어 스크롤 텍스트에 안 가리게. */
.ticker-speaker-button {
    position: absolute;
    right: 4px;
    top: 50%;
    transform: translateY(-50%);
    z-index: 3;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    padding: 0;
    border: none;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.85);
    color: #1957D6;
    cursor: pointer;
}

.ticker-speaker-button svg {
    width: 14px;
    height: 14px;
}

.ticker-compose-textarea {
    width: 100%;
    min-height: 72px;
    padding: 12px 14px;
    border: 1px solid var(--dk-border);
    border-radius: 10px;
    font: inherit;
    font-size: var(--dk-input-font);
    resize: none;
    box-sizing: border-box;
}

.ticker-compose-counter {
    margin-top: 4px;
    text-align: right;
    font-size: 12px;
    color: var(--dk-text-secondary);
}

.ticker-compose-color-label {
    margin-top: 16px;
    margin-bottom: 8px;
    font-size: 13px;
    font-weight: bold;
    color: var(--dk-text-primary);
}

.ticker-compose-color-row {
    display: flex;
    gap: 10px;
}

.ticker-compose-color-swatch {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    border: 2px solid transparent;
    padding: 0;
    cursor: pointer;
}

.ticker-compose-color-swatch.selected {
    border-color: var(--dk-text-primary);
    box-shadow: 0 0 0 2px #ffffff inset;
}

.ticker-compose-preview-wrap {
    margin-top: 20px;
    padding: 14px 0;
    text-align: center;
    background: var(--dk-bg-surface);
    border: 1px solid var(--dk-border);
    border-radius: 10px;
}

.ticker-compose-preview-text {
    font-size: 14px;
    font-weight: bold;
    color: var(--dk-text-primary);
}

.ticker-content {
    display: inline-block;
    padding-left: 100%;
}

.ticker-content.active {
    animation: marquee 20s linear 1 forwards;
}

@keyframes marquee {
    0% { transform: translateX(0); }
    100% { transform: translateX(-100%); }
}

/* 필드 탭 좌상단 상태 (HUD) */
/* 화면 모서리에 거의 딱 붙임(12px→8px→2px). padding도 줄여 아바타가 탭을 꽉 채우는 느낌(아래 .field-hud-avatar 확대와 짝을 이룸). */
.field-hud-wrap {
	position: absolute;
	top: 2px;
	left: 2px;
	z-index: 100;
	display: flex;
	align-items: center;
	background: rgba(255, 255, 255, 0.95);
	padding: 4px 12px 4px 4px;
	border-radius: 20px;
	box-shadow: 0 2px 6px rgba(0,0,0,0.15);
	gap: 8px;
	backdrop-filter: blur(4px);
	border: 1px solid rgba(0,0,0,0.05);
	cursor: pointer;
	text-align: left;
}

.field-hud-wrap:active {
	background: var(--dk-bg-surface-alt);
}

.field-hud-avatar-wrap {
	flex-shrink: 0;
}

.field-hud-avatar {
	
	width: 52px;
	height: 52px;
	border-radius: 16px;
	overflow: hidden;
	background: var(--dk-bg-surface-alt-2);
	border: 1px solid var(--dk-border-soft);
	display: flex;
	align-items: center;
	justify-content: center;
}

.field-hud-speaker-button {
	/* 예전엔 아바타 모서리 기준 크게/멀리 띄워 박스 밖으로 삐져나왔다가, -6px 음수 오프셋도 #fieldHudWrap(top/left:2px)과 합쳐지면 화면 좌표가 음수라 여전히 화면 밖으로 나감 — 박스 안쪽(0,0)에 둬서 절대 화면 밖으로 안 나가게 함. */
	position: absolute;
	top: 0;
	left: 0;
	width: 20px;
	height: 20px;
	padding: 0;
	border: 1.5px solid var(--dk-bg-surface);
	border-radius: 50%;
	background: #1957D6;
	color: var(--dk-text-inverse);
	display: flex;
	align-items: center;
	justify-content: center;
	box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);
	cursor: pointer;
	z-index: 1;
}

.field-hud-speaker-button svg {
	width: 11px;
	height: 11px;
}

.field-hud-avatar img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* transform(translateY/scale)만 쓰는 GPU 합성 애니메이션이라 배터리/CPU 비용이 거의 없음 — 라이더가 다중 거치대로 화면을 오래 켜두는 특성상 prefers-reduced-motion을 존중해 배터리를 아낀다. */
@media (prefers-reduced-motion: no-preference) {
	.field-hud-avatar img {
		animation: fieldHudCharacterIdle 3s ease-in-out infinite;
	}
}

@keyframes fieldHudCharacterIdle {
	0% { transform: translateY(0) scale(1); }
	50% { transform: translateY(-1.5px) scale(1.02); }
	100% { transform: translateY(0) scale(1); }
}

.field-hud-info {
	display: flex;
	flex-direction: column;
	min-width: 64px;
}

.field-hud-name-row {
	display: flex;
	align-items: center;
	gap: 4px;
}

.field-hud-name {
	font-size: 11px;
	font-weight: bold;
	color: var(--dk-text-primary);
}

.field-hud-level {
	flex-shrink: 0;
	font-size: 9px;
	font-weight: bold;
	color: var(--dk-text-inverse);
	background: #1957D6;
	border-radius: 8px;
	padding: 1px 5px;
	line-height: 1.3;
	
	cursor: pointer;
}

.field-hud-stats {
	display: flex;
	gap: 8px;
	font-size: 12px;
	font-weight: bold;
	color: #1957D6;
	margin-top: 1px;
	line-height: 1;
}

.field-hud-stat {
	display: flex;
	align-items: center;
	gap: 2px;
}

.field-hud-xp-track {
	position: relative;
	margin-top: 3px;
	width: 100%;
	height: 14px;
	background: var(--dk-bg-surface-alt);
	border-radius: 3px;
	overflow: hidden;
}

.field-hud-xp-fill {
	height: 100%;
	width: 0%;
	background: linear-gradient(90deg, #4d8dff, #1957D6);
	border-radius: 3px;
	transition: width 0.3s ease;
}

/* 게이지 위에 겹쳐 항상 가운데 표시 — 배경 칩/블러 없이 블러 반경 0인 1px 오프셋 4방향 text-shadow로 1도트 흰 외곽선만(도트/픽셀 폰트 스타일), 채워진/안 채워진 배경 둘 다에서 읽히도록. */
.field-hud-xp-percent {
	position: absolute;
	inset: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	font-size: 9px;
	font-weight: bold;
	color: #1957D6;
	text-shadow:
		-1px -1px 0 #ffffff,
		1px -1px 0 #ffffff,
		-1px 1px 0 #ffffff,
		1px 1px 0 #ffffff;
	pointer-events: none;
	white-space: nowrap;
}

/* 5분마다 필드 HUD 캐릭터가 말을 거는 말풍선 — 몸통+꼬리를 박스+clip-path 조각으로 따로 그리다 이음매 문제가 계속 나서, 이제 위치/애니메이션/그림자만 여기서 맡고 실제 모양은 자식 SVG <path> 하나로 통째로 그린다.
   말풍선 여러 개를 쌓는 컨테이너 — 좌표 기준점(72px/50px)은 예전 단일 말풍선 값을 그대로 옮겨온 것. 컨테이너 자체는 안 보이고 각 말풍선이 top(스택 순서)을 인라인으로 받는다. */
.field-hud-speech-stack {
	position: absolute;
	top: 72px;
	left: 50px;
	/* position:absolute인 이 컨테이너에 폭 지정이 없으면 폭 0으로 잡혀서, 안의 말풍선(width:auto)의 셋-투-핏 계산 기준(containing block)도 좁아져 텍스트가 세로로 찌그러져 줄바꿈되던 버그 — 말풍선 max-width와 같은 값으로 복원. */
	width: 168px;
	z-index: 101;
	pointer-events: none;
}

.field-hud-speech-bubble {
	position: absolute;
	left: 0;
	/* top은 JS가 스택 순서(몇 번째로 쌓였는지)에 맞춰 인라인으로 매긴다 — 최근 것이 top:0(맨 위),
	   오래된 것일수록 아래로. z-index도 같이 인라인으로 줘서 최근 것이 항상 앞에 오게 한다. */
	max-width: 168px;
	pointer-events: none;
	opacity: 0;
	transform: scale(0.6) translateY(4px);
	transform-origin: left top;
	transition: opacity 0.25s ease, transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1), top 0.2s ease;
	
	filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.12));
}

/* SVG가 몸통+꼬리 도형(흰 채움 + 종별 컬러 테두리)을 그리는 배경 레이어 — 꼬리가 몸통 위로 튀어나온
   만큼(SPEECH_BUBBLE_TAIL_HEIGHT) 텍스트보다 위로 올려서 배치한다. width/height/viewBox/path는
   JS(showFieldHudSpeechBubble)가 텍스트 크기를 잰 뒤 매번 새로 계산해서 넣는다. */
.field-hud-speech-bubble-svg {
	position: absolute;
	/* SPEECH_BUBBLE_TAIL_HEIGHT(main.html)와 반드시 같은 값 — 꼬리가 몸통 위로 튀어나오는 만큼만 끌어올려서 배치. */
	top: -12px;
	left: 0;
	z-index: 0;
	overflow: visible;
}

.field-hud-speech-bubble-svg path {
	fill: var(--dk-bg-surface);
}

.field-hud-speech-bubble-text {
	position: relative;
	z-index: 1;
	display: block;
	padding: 8px 12px;
	color: var(--dk-text-primary);
	font-size: 12px;
	font-weight: bold;
	line-height: 1.35;
}

.field-hud-speech-bubble.show {
	opacity: 1;
	transform: scale(1) translateY(0);
	animation: fieldHudSpeechBounce 2.4s ease-in-out infinite;
}

@keyframes fieldHudSpeechBounce {
	0%, 100% { transform: scale(1) translateY(0); }
	50% { transform: scale(1) translateY(-3px); }
}

.point-up-text {
	position: fixed;
	pointer-events: none;
	font-family: 'Outfit', sans-serif;
	font-weight: 900;
	font-size: 26px;
	color: #ffaa00;
	text-shadow: 0 0 10px rgba(255, 170, 0, 0.8), 0 2px 4px rgba(0, 0, 0, 0.4);
	z-index: 99999;
	/* 이 클래스를 공유하는 main.html/point-guide.html/register.html의 triggerPointEffect() setTimeout 제거 타이머도 전부 2400으로 맞춰야 한다 — 안 맞으면 애니메이션 도중 엘리먼트가 잘려나감. */
	animation: uprisingText 2.4s cubic-bezier(0.18, 0.89, 0.32, 1.28) forwards;
}

/* (2026-09-05 신설) 포인트 이펙트와 나란히 뜨는 배달력(경험치) 전용 색 — 같은 .point-up-text/uprisingText
   타이밍을 공유하고 색/폰트 크기만 오버라이드. 위치(left/top)를 포인트 텍스트보다 살짝 오른쪽·아래로
   어긋나게 인라인 스타일로 주는 건 호출부(main.html/point-guide.html/register.html) 책임. */
.xp-up-text {
	font-size: 20px;
	color: #ef4444;
	text-shadow: 0 0 10px rgba(239, 68, 68, 0.8), 0 2px 4px rgba(0, 0, 0, 0.4);
}

.flame-icon {
	vertical-align: middle;
	flex-shrink: 0;
}

@keyframes uprisingText {
	0% {
		transform: translate(-50%, -50%) scale(0.5);
		opacity: 0;
	}
	20% {
		transform: translate(-50%, -100%) scale(1.3);
		opacity: 1;
	}
	
	100% {
		transform: translate(-50%, -240%) scale(1.3);
		opacity: 0;
	}
}

.point-particle {
	position: fixed;
	pointer-events: none;
	z-index: 99998;
	border-radius: var(--radius, 50%);
	background-color: var(--color, #ff007f);
	opacity: 1;
	animation: particleFly var(--duration, 0.8s) cubic-bezier(0.1, 0.8, 0.3, 1) forwards;
}

@keyframes particleFly {
	0% {
		transform: translate(-50%, -50%) translate(0, 0) rotate(0deg);
		opacity: 1;
	}
	100% {
		transform: translate(-50%, -50%) translate(var(--tx, 50px), var(--ty, 50px)) rotate(var(--rot, 360deg));
		opacity: 0;
	}
}

/* 데스크톱 웹 레이아웃 — 기존 UI는 "웹앱" 전제로 항상 .app이 480px 폭 모바일 컬럼이었는데, PC 폭에서는 하단 탭바를 좌측 세로 사이드바로 옮긴다. 순수 미디어쿼리 대신 body.is-desktop-view 클래스 기반 — 햄버거 메뉴로 사용자가 강제 전환 가능해야 해서(applyViewMode()가 기본은 matchMedia 자동판단, localStorage 강제 설정이 있으면 그걸 우선). 아래 규칙 전부 이 클래스 하나만 보므로 미디어쿼리/강제전환 둘 다 중복 없이 처리됨. */
body.is-desktop-view .app {
	max-width: none;
	display: grid;
	grid-template-columns: 84px 1fr;
	grid-template-rows: auto auto 1fr;
	grid-template-areas:
		"header header"
		"ticker ticker"
		"nav    main";
}

body.is-desktop-view .app-header {
	grid-area: header;
}

/* 모바일은 top:8px 고정이라 헤더가 커지면 버튼이 위로 치우쳐 보일 수 있어, PC 한정으로 헤더 높이와 무관하게 항상 수직 가운데. */
body.is-desktop-view .notification-bell,
body.is-desktop-view .menu-button {
	top: 50%;
	transform: translateY(-50%);
}

/* 모바일은 필드(location) 탭에서만 전광판이 보이는데, PC는 좌측 사이드바 + 넓은 화면이라 어느
   탭에 있든(채팅/랭킹/내활동/내정보) 항상 보이게 한다. body[data-active-tab="location"]
   #globalTicker 규칙(전광판 기본 노출 조건)과 별개로 그냥 덮어쓴다 — 위치 탭일 때는 두 규칙이
   같은 값이라 충돌 없음. */
body.is-desktop-view #globalTicker {
	grid-area: ticker;
	display: block;
}

/* PC 한정으로 전광판 스크롤을 50% 느리게(20s → 40s). */
body.is-desktop-view .ticker-content.active {
	animation-duration: 40s;
}

body.is-desktop-view .map-wrap,
body.is-desktop-view #tabSheet {
	grid-area: main;
	min-width: 0;
}

/* PC는 챗/랭킹/내활동/내정보 탭을 전체화면 대신 왼쪽 오버레이로, 지도는 오른쪽에 그대로 — .map-wrap과 #tabSheet가 같은 grid-area(main)를 공유하는 걸 그대로 이용해 #tabSheet만 폭을 좁혀 왼쪽 정렬하면 지도가 자연히 드러난다(#tabSheet가 DOM상 뒤에 있어 이미 위에 그려짐). 모바일의 "탭 열리면 지도 완전 숨김"은 PC에서만 무효화. 폭 420px은 모바일 설계 폭(.app max-width:480px)과 비슷한 비율(채팅/랭킹 UI가 그 폭 기준)로 재사용, 좁은 창 대비 max-width:45% 상한. */
body.is-desktop-view .map-wrap.hidden {
	display: flex;
}

body.is-desktop-view #tabSheet {
	width: 420px;
	max-width: 45%;
	justify-self: start;
	/* 실제 브라우저에서 겪은 버그 — .map-wrap이 안 숨겨지면서 필드 HUD(100)/말풍선(101)/난이도 버튼(150)이 이 패널과 스태킹 컨텍스트를 경쟁, 낮은 값으론 HUD가 패널을 뚫고 비쳐 보였다. 690으로 올리되 #dmStartPopup/#chatSettingsPanel(700)이나 포인트 이펙트(99999)보다는 반드시 아래여야 함 — 700 넘지 말 것. */
	z-index: 690;
	box-shadow: 4px 0 20px rgba(0, 0, 0, 0.15);
	border-right: 1px solid var(--dk-border);
}

/* .tab-sheet-body 기본 위쪽 padding(2px)은 모바일 기준이라 PC 오버레이 패널에서는 빡빡해 보여 15px 추가(2px+15px=17px). */
body.is-desktop-view .tab-sheet-body {
	padding-top: 17px;
}

/* #tabSheet(690)가 #fieldHudWrap(100)보다 위에 그려져 패널이 열려있는 동안 HUD를 가리던 문제 — #tabSheet가 DOM상 나중 형제라 일반 형제 결합자(~)로는 앞쪽을 스타일링할 수 없어 :has()로 뒤쪽 형제 상태를 앞에서 조회. #tabSheet의 실제 폭만큼 HUD를 오른쪽으로 밀어 패널 옆 지도 위에 계속 보이게 함. */
body.is-desktop-view .map-wrap:has(~ #tabSheet.open) #fieldHudWrap {
	left: calc(min(420px, 45vw) + 10px);
}

/* 하단 탭바 → 좌측 세로 사이드바. 아이콘/글자 색·활성 탭 채움
   스타일(.bottom-nav-item.active 등)은 모바일과 동일 규칙을 그대로 재사용 — 배치만 바꾼다. */
body.is-desktop-view .bottom-nav {
	grid-area: nav;
	flex-direction: column;
	align-items: stretch;
	justify-content: flex-start;
	width: 84px;
	border-top: none;
	border-right: 1px solid #1957D6;
	padding-bottom: 0;
	padding-top: 12px;
	gap: 4px;
}

body.is-desktop-view .bottom-nav-item {
	flex: 0 0 auto;
	padding: 14px 0;
}

/* 랭킹 1/2/3위는 모바일 폭(480px) 기준으로 만들어진 레이아웃이라, PC에서 #tabSheet가 그리드 남은 폭 전체(수백~1000px대)로 늘어나면 scale(1.09 등) 변형이 커진 기준폭 그대로 확대돼 화면 밖까지 밀려난다 — 원래 폭(480px) 유지하고 가운데만 정렬. 랭킹 탭 전용 id로 스코프(#chatCategoryTabs 등 다른 탭은 안 건드림). */
body.is-desktop-view #rankingCategoryTabs,
body.is-desktop-view #rankingList {
	max-width: 480px;
	margin-left: auto;
	margin-right: auto;
}

body.is-desktop-view #rankingList .ranking-item-icon-nickname {
	font-size: 10px;
}

.oauth-section {
	margin-top: 18px;
	padding-top: 14px;
	border-top: 1px solid var(--dk-border-soft);
}

.oauth-connected-list {
	margin-bottom: 12px;
	display: flex;
	flex-direction: column;
	gap: 8px;
}

.oauth-connected-item {
	display: flex;
	align-items: center;
	justify-content: space-between;
	padding: 12px 14px;
	background: var(--dk-bg-surface-alt-2);
	border: 1px solid var(--dk-border);
	border-radius: 8px;
}

.oauth-connected-info {
	display: flex;
	align-items: center;
	gap: 10px;
}

.oauth-provider-badge {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 26px;
	height: 26px;
	border-radius: 6px;
	font-size: 14px;
	font-weight: 900;
	color: var(--dk-text-inverse);
}

.oauth-provider-badge.naver {
	background-color: #03C75A;
}

.oauth-provider-badge.google {
	background-color: #4285F4;
}

.oauth-connected-meta {
	display: flex;
	flex-direction: column;
	flex: 1;
	min-width: 0;
	word-break: keep-all;
}

.oauth-connected-title {
	font-size: 14px;
	font-weight: bold;
	color: var(--dk-text-primary);
}

.oauth-connected-email {
	font-size: 12px;
	color: var(--dk-text-secondary);
}

.oauth-connected-actions {
	display: flex;
	align-items: center;
	gap: 8px;
}

.oauth-logout-btn {
	padding: 6px 12px;
	background: var(--dk-bg-surface);
	border: 1px solid var(--dk-border);
	border-radius: 6px;
	color: var(--dk-text-primary);
	font-size: 12px;
	font-weight: bold;
	cursor: pointer;
	transition: background 0.15s, border-color 0.15s;
}

.oauth-logout-btn:hover {
	background: var(--dk-bg-surface-alt);
	border-color: #94a3b8;
}

.oauth-unlink-btn {
	padding: 4px 6px;
	background: transparent;
	border: none;
	color: var(--dk-text-secondary);
	font-size: 11px;
	text-decoration: underline;
	cursor: pointer;
	transition: color 0.15s;
}

.oauth-unlink-btn:hover {
	color: #ef4444;
}

.oauth-button-area {
	display: flex;
	flex-direction: column;
	gap: 8px;
}

.btn-naver-oauth {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 10px;
	width: 100%;
	height: 44px;
	background-color: #03C75A;
	color: var(--dk-text-inverse);
	font-size: 14px;
	font-weight: bold;
	border-radius: 8px;
	text-decoration: none;
	transition: background-color 0.15s, transform 0.1s;
	box-sizing: border-box;
}

.btn-naver-oauth:hover {
	background-color: #02b351;
	color: var(--dk-text-inverse);
}

.btn-naver-oauth:active {
	transform: scale(0.99);
}

.btn-naver-oauth .naver-icon {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	font-weight: 900;
	font-size: 16px;
	line-height: 1;
}

/* 계정 연동 충돌 비교 선택 모달 */
.account-conflict-modal-overlay {
	position: fixed;
	top: 0;
	left: 0;
	right: 0;
	bottom: 0;
	background: rgba(0, 0, 0, 0.65);
	z-index: 10000;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 10px;
	box-sizing: border-box;
	animation: fadeIn 0.2s ease-out;
}

.account-conflict-modal {
	background: var(--dk-bg-surface);
	border-radius: 16px;
	max-width: 540px;
	width: 100%;
	max-height: 95vh;
	overflow-y: auto;
	box-shadow: 0 12px 32px rgba(0, 0, 0, 0.25);
	padding: 16px 14px;
	box-sizing: border-box;
	text-align: center;
}

.account-conflict-header {
	margin-bottom: 10px;
}

.account-conflict-icon {
	font-size: 22px;
	margin-bottom: 4px;
}

.account-conflict-title {
	font-size: 16px;
	font-weight: bold;
	color: var(--dk-text-primary);
	margin: 0 0 4px 0;
}

.account-conflict-desc {
	font-size: 12px;
	color: var(--dk-text-secondary);
	line-height: 1.35;
	margin: 0;
}

.account-conflict-cards {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: 8px;
	margin-bottom: 12px;
}

.account-compare-card {
	background: var(--dk-bg-surface-alt-2);
	border: 2px solid var(--dk-border);
	border-radius: 12px;
	padding: 10px 8px;
	display: flex;
	flex-direction: column;
	align-items: center;
	position: relative;
	transition: all 0.15s ease;
}

.account-compare-card.current {
	border-color: #3b82f6;
	background: #f4f8ff;
}

.account-compare-card.linked {
	border-color: #03c75a;
	background: #f2faf5;
}

.account-compare-badge {
	font-size: 10px;
	font-weight: bold;
	padding: 3px 6px;
	border-radius: 12px;
	margin-bottom: 6px;
}

.account-compare-card.current .account-compare-badge {
	background: #dbeafe;
	color: #1d4ed8;
}

.account-compare-card.linked .account-compare-badge {
	background: #dcfce7;
	color: #15803d;
}

.account-compare-avatar {
	width: 40px;
	height: 40px;
	border-radius: 50%;
	overflow: hidden;
	display: flex;
	align-items: center;
	justify-content: center;
	margin-bottom: 6px;
	box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
}

.account-compare-avatar img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.account-compare-name {
	font-size: 13px;
	font-weight: bold;
	color: var(--dk-text-primary);
	margin-bottom: 0;
	max-width: 100%;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.account-compare-level {
	flex: 0 0 auto;
	margin-bottom: 0;
}

.account-compare-identity {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 4px;
	width: 100%;
	min-width: 0;
	margin-bottom: 6px;
}

.account-compare-stats {
	width: 100%;
	display: flex;
	justify-content: space-around;
	background: rgba(0, 0, 0, 0.04);
	border-radius: 8px;
	padding: 5px 4px;
	margin-bottom: 8px;
	font-size: 11px;
	font-weight: bold;
	color: var(--dk-text-primary);
}

.account-compare-stat-item {
	display: flex;
	align-items: center;
	gap: 4px;
}

.account-compare-btn {
	width: 100%;
	padding: 8px 6px;
	border: none;
	border-radius: 8px;
	font-size: 12px;
	font-weight: bold;
	cursor: pointer;
	transition: opacity 0.15s, transform 0.1s;
	margin-top: auto;
	line-height: 1.3;
}

.account-compare-btn:active {
	transform: scale(0.98);
}

.account-compare-btn.btn-overwrite {
	background: #3b82f6;
	color: var(--dk-text-inverse);
}

.account-compare-btn.btn-overwrite:hover {
	background: #2563eb;
}

.account-compare-btn.btn-load {
	background: #03c75a;
	color: var(--dk-text-inverse);
}

.account-compare-btn.btn-load:hover {
	background: #02b351;
}

.account-conflict-cancel-btn {
	width: 100%;
	padding: 8px;
	background: none;
	border: 1px solid #d0d0d0;
	border-radius: 8px;
	color: var(--dk-text-secondary);
	font-size: 12px;
	font-weight: bold;
	cursor: pointer;
	transition: background 0.15s;
}

.account-conflict-cancel-btn:hover {
	background: var(--dk-bg-surface-alt-2);
}

.confirm-modal {
	max-width: 380px;
	text-align: left;
}

.confirm-modal-message {
	font-size: 14px;
	line-height: 1.6;
	color: var(--dk-text-primary);
	margin: 4px 0 18px 0;
	white-space: normal;
}

.confirm-modal-actions {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: 8px;
}

.confirm-modal-actions .confirm-modal-cancel-btn,
.confirm-modal-actions .confirm-modal-ok-btn {
	width: 100%;
}

.app-toast {
	position: fixed;
	bottom: calc(68px + max(8px, env(safe-area-inset-bottom)));
	left: 50%;
	transform: translateX(-50%) translateY(16px);
	background: rgba(15, 23, 42, 0.90);
	backdrop-filter: blur(8px);
	-webkit-backdrop-filter: blur(8px);
	color: var(--dk-text-inverse);
	padding: 8px 18px;
	border-radius: 20px;
	font-size: 12.5px;
	font-weight: 700;
	font-family: inherit;
	box-shadow: 0 4px 16px rgba(0, 0, 0, 0.25);
	pointer-events: none;
	opacity: 0;
	visibility: hidden;
	transition: opacity 0.22s ease, transform 0.22s cubic-bezier(0.16, 1, 0.3, 1), visibility 0.22s;
	z-index: 10000;
	/* (2026-09-10 수정) 예전엔 white-space: nowrap이 걸려 있었다. max-width: 90%와 같이 쓰면
	   긴 문구가 줄바꿈을 못 해 배경 밖으로 그대로 삐져나간다(사용자 제보 — 집중 모드 안내가
	   그랬다). 실제로 40자대 토스트가 여러 개 있어서 좁은 화면에서는 전부 같은 증상이었다.
	   nowrap을 걷어내면 짧은 문구는 어차피 한 줄이라 보이는 게 그대로고, 긴 문구만 접힌다.
	   한글 줄바꿈은 body의 word-break: keep-all을 그대로 물려받아 단어 중간에서 안 끊긴다. */
	max-width: min(90%, 420px);
	line-height: 1.45;
	text-align: center;
}

.app-toast.show {
	opacity: 1;
	visibility: visible;
	transform: translateX(-50%) translateY(0);
}

.completion-marker {
	background-color: rgba(255, 255, 255, 0.90);
	border: 1.5px solid #1957D6;
	border-radius: 8px;
	padding: 6px 10px;
	box-shadow: 0 4px 6px rgba(0, 0, 0, 0.15);
	display: flex;
	flex-direction: column;
	align-items: center;
	transform: translate(-50%, -50%);
	pointer-events: none;
	backdrop-filter: blur(4px);
	-webkit-backdrop-filter: blur(4px);
}

.completion-region {
	font-size: 13px;
	font-weight: 800;
	color: var(--dk-text-primary);
	letter-spacing: -0.5px;
	line-height: 1.2;
}

.completion-stats {
	display: flex;
	align-items: center;
	gap: 6px;
	margin-top: 4px;
}

.completion-percent {
	font-size: 12px;
	font-weight: 700;
	color: #1957D6;
}

.completion-count {
	font-size: 11px;
	font-weight: 600;
	color: var(--dk-text-tertiary);
	background-color: var(--dk-bg-surface-alt);
	padding: 2px 6px;
	border-radius: 4px;
}

/* --- New Account Tab UI --- */
.account-card {
	background: var(--dk-bg-surface);
	border-radius: 12px;
	padding: 16px 10px;
	margin-bottom: 8px;
	box-shadow: var(--dk-shadow-md);
	border: 1px solid rgba(0,0,0,0.04);
}

.account-card-title {
	font-size: 15px;
	font-weight: 700;
	color: var(--dk-text-primary);
	margin: 0 0 4px 0;
}

.account-card-desc {
	font-size: 13px;
	color: var(--dk-text-secondary);
	margin: 0;
	line-height: 1.4;
	word-break: keep-all;
}

.btn-inline-primary {
	background: #1957D6;
	color: var(--dk-text-inverse);
	border: none;
	border-radius: 8px;
	padding: 0 14px;
	font-size: 13px;
	font-weight: bold;
	height: 44px;
	margin-left: 6px;
	cursor: pointer;
	white-space: nowrap;
}

.btn-inline-primary:active {
	background: #0F3FA6;
}

.advanced-details summary {
	list-style: none; /* Hide default arrow */
	cursor: pointer;
	font-size: 14px;
	font-weight: 600;
	color: var(--dk-text-tertiary);
	display: flex;
	justify-content: space-between;
	align-items: center;
	padding: 4px 0;
	user-select: none;
}

.advanced-details summary::-webkit-details-marker {
	display: none;
}

.advanced-details[open] summary .summary-arrow {
	transform: rotate(180deg);
}

.summary-arrow {
	transition: transform 0.2s ease;
	font-size: 12px;
	color: var(--dk-text-secondary);
}

.advanced-content {
	margin-top: 16px;
	padding-top: 16px;
	border-top: 1px solid #eeeeee;
}

.account-footer-actions {
	text-align: center;
	margin-top: 24px;
	margin-bottom: 40px;
}

.btn-text-danger {
	background: none;
	border: none;
	color: #e74c3c;
	font-size: 12px;
	text-decoration: underline;
	cursor: pointer;
	padding: 8px;
	word-break: keep-all;
}

/* ============================================================
   ����(Nest) �� ���� ��Ÿ��
   ============================================================ */
.nest-controls {
	display: flex;
	justify-content: space-between;
	align-items: center;
	padding: 12px 16px;
	background: var(--dk-bg-surface);
	border-bottom: 1px solid var(--dk-border-soft);
}
.nest-toggle-group {
	display: flex;
	gap: 8px;
}
.nest-toggle-group button {
	padding: 6px 12px;
	border: 1px solid var(--dk-border);
	background: var(--dk-bg-surface);
	color: var(--dk-text-secondary);
	border-radius: 20px;
	font-size: 13px;
	font-weight: 600;
	cursor: pointer;
}
.nest-toggle-group button.active {
	background: var(--dk-text-primary);
	color: var(--dk-bg-surface);
	border-color: var(--dk-text-primary);
}
.nest-controls .nest-edit-btn {
	padding: 6px 16px;
	border: none;
	background: #1957D6;
	color: #fff;
	border-radius: 8px;
	font-size: 13px;
	font-weight: 700;
	cursor: pointer;
}
.nest-controls .nest-edit-btn.active {
	background: #ff4757;
}
.nest-viewport {
	position: relative;
	width: 100%;
	aspect-ratio: 4 / 3; /* 화면비 4:3 */
	background: #000;
	overflow: hidden;
}
/* (2026-09-06 신설) 내 둥지가 받은 좋아요 수 배지 — 채팅 "둥지보기"에서 남들이 누른 것. */
.nest-like-badge {
	position: absolute;
	top: 10px;
	left: 10px;
	z-index: 20;
	display: flex;
	align-items: center;
	gap: 4px;
	background: rgba(0, 0, 0, 0.5);
	color: #fff;
	font-size: 12px;
	font-weight: bold;
	padding: 5px 10px;
	border-radius: 999px;
	cursor: pointer;
}
.nest-like-list {
	max-height: 60vh;
	overflow-y: auto;
	padding: 4px 0;
}
.nest-like-list-row {
	display: flex;
	align-items: center;
	gap: 10px;
	padding: 10px 16px;
	border-bottom: 1px solid var(--dk-border-soft);
}
.nest-like-list-row:last-child {
	border-bottom: none;
}
.nest-like-list-row img {
	width: 36px;
	height: 36px;
	border-radius: 50%;
	object-fit: cover;
	flex: 0 0 auto;
}
.nest-like-list-row-text {
	flex: 1;
	min-width: 0;
	display: flex;
	flex-direction: column;
	gap: 2px;
}
.nest-like-list-row-name {
	font-size: 13px;
	font-weight: bold;
	color: var(--dk-text-primary);
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.nest-like-list-row-icon-nickname {
	font-size: 11px;
	color: var(--dk-text-tertiary);
}
.nest-like-list-row-time {
	font-size: 11px;
	color: var(--dk-text-tertiary);
	flex: 0 0 auto;
}
.nest-bg-layer {
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: opacity 0.3s ease, filter 0.6s ease;
}
/* 외부 뷰 3레이어. 2번은 둥지 자체를 밖에서 보여주는 이미지가 아니라, 둥지 안에서 바라본
   창가/입구 프레임이다. 도시/해안 등 테마가 늘어도 이 카메라 시점은 유지한다.
   z-order(뒤->앞): 원경(1) < 중경(2) < 날씨 이펙트(3) < 입구 프레임(4). */
.nest-bg-layer-far,
.nest-bg-layer-mid,
.nest-bg-layer-front {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	pointer-events: none;
	user-select: none;
	-webkit-user-drag: none;
	transition: filter 0.6s ease;
}
.nest-bg-layer-far { z-index: 1; }
.nest-bg-layer-mid { z-index: 2; }
.nest-bg-layer-front {
	z-index: 4;
}
.nest-viewport.nest-exterior .nest-bg-layer-far {
	/* 원본 비율로 실제 이미지 박스를 화면보다 넓게 만든 뒤 GPU transform으로 움직인다. */
	inset: auto;
	top: -4px;
	left: 50%;
	width: auto;
	min-width: 100%;
	max-width: none;
	height: calc(100% + 8px);
	transform: translate3d(calc(-50% + var(--nest-far-x, 0px)), var(--nest-far-y, 0), 0);
}
.nest-viewport.nest-exterior .nest-bg-layer-mid {
	/* 기존 transform 감도를 유지하고, 세로 이동분만 고정 오버스캔한다. */
	inset: auto;
	top: -8px;
	left: 50%;
	width: auto;
	min-width: 100%;
	max-width: none;
	height: calc(100% + 16px);
	transform: translate3d(calc(-50% + var(--nest-mid-x, 0px)), var(--nest-mid-y, 0), 0);
}
.nest-viewport.nest-exterior .nest-bg-layer-front {
	/* 16:9 원본을 높이에 맞춰 비율 그대로 렌더링하면 4:3 화면보다 좌우가 넓다. 그 실제 이미지
	   박스를 transform으로 움직여 원본을 더 보여준다. object-position 재페인트로 생긴 이질적인
	   감도는 없애고 기존 GPU 드래그 반응을 복원한다. */
	inset: auto;
	top: 0;
	left: 50%;
	width: auto;
	min-width: 100%;
	max-width: none;
	height: 100%;
	transform: translate3d(calc(-50% + var(--nest-front-x, 0px)), 0, 0);
}
.nest-viewport.nest-exterior.nest-parallax-enabled {
	touch-action: none;
	cursor: grab;
}
.nest-viewport.nest-exterior.nest-parallax-enabled.is-parallax-dragging {
	cursor: grabbing;
}
.nest-viewport.nest-exterior.nest-parallax-enabled .nest-bg-layer-far,
.nest-viewport.nest-exterior.nest-parallax-enabled .nest-bg-layer-mid,
.nest-viewport.nest-exterior.nest-parallax-enabled .nest-bg-layer-front {
	will-change: transform;
}
/* (2026-09-05, target.md Part 3) 낮/밤은 실물 레이어 없이 프론트 필터로만 동적 처리 — 원본
   이미지는 그대로 두고 밝기/채도/색조만 낮 밤에 맞춰 바꾼다("베이킹 금지" 원칙). 인테리어 이미지와
   3레이어 전부에 같이 적용되도록 자손 선택자로 묶는다. */
.nest-viewport.nest-night .nest-bg-layer,
.nest-viewport.nest-night .nest-bg-layer-far,
.nest-viewport.nest-night .nest-bg-layer-mid,
.nest-viewport.nest-night .nest-bg-layer-front {
	filter: brightness(0.55) saturate(0.75) hue-rotate(-6deg);
}
.nest-viewport.nest-night::after {
	content: '';
	position: absolute;
	inset: 0;
	background: rgba(20, 28, 70, 0.22);
	pointer-events: none;
	z-index: 8; /* 근경(4)/가구(5)/슬롯마커(7)까지 전부 덮어서 장면 전체가 어두워지게 */
}
/* 근경 대용 날씨 파티클(봄=벚꽃) — 실물 근경 레이어 이미지가 없어 CSS로 대신 "동적 근경 요소"를
   구현(target.md Part 3 "근경에 애니메이션 요소" 원칙). pointer-events:none이라 배치 탭을 막지 않음. */
.nest-weather-layer {
	position: absolute;
	inset: 0;
	overflow: hidden;
	pointer-events: none;
	z-index: 3; /* 외부 뷰: 중경(2)과 근경(4) 사이 — 사용자 지정 z-order */
}
.nest-petal {
	position: absolute;
	top: -6%;
	width: 9px;
	height: 7px;
	background: #ffc9dd;
	border-radius: 60% 40% 60% 40%;
	opacity: 0.85;
	animation-name: nestPetalFall;
	animation-timing-function: linear;
	animation-iteration-count: infinite;
}
@keyframes nestPetalFall {
	0% { transform: translate(0, 0) rotate(0deg); opacity: 0; }
	10% { opacity: 0.85; }
	100% { transform: translate(var(--nest-petal-drift, 20px), 118vh) rotate(300deg); opacity: 0.6; }
}
.nest-furniture-container {
	position: absolute;
	top: 0; left: 0; right: 0; bottom: 0;
	pointer-events: none; /* 배경은 클릭 이벤트를 캡처하되, 가구는 각자 핸들러 */
	z-index: 15; /* 편집 모드의 그리드(10)보다 위로 올려야 아이템 탭이 가능함 */
}
.nest-furniture-item {
	position: absolute;
	transform: translate(-50%, -50%); /* 중심을 기준점 */
	pointer-events: auto;
	cursor: pointer;
	max-width: 60px;
	max-height: 60px;
	/* 가구 파일의 실제 바닥 접촉 그림자를 존중한다. 모든 자산에 같은 타원 그림자를 더하면
	   벽걸이·천장형 가구와 횃대가 공중에 뜬 것처럼 보여 런타임 공통 그림자는 사용하지 않는다. */
	filter: none;
}
.nest-furniture-item.nest-furniture-fixed {
	max-width: 15%;
	max-height: 15%;
}
.nest-furniture-item:hover {
	outline: 2px dashed #ffaa00;
}
/* 아바타(캐릭터 아이콘) 자유 배치 */
.nest-avatar-item {
	--nest-avatar-facing: 1;
	position: absolute;
	transform: translate(-50%, -50%) scaleX(var(--nest-avatar-facing));
	pointer-events: auto;
	cursor: pointer;
	width: 15%;
	max-width: 68px;
	filter: drop-shadow(0 4px 6px rgba(0,0,0,0.3));
}
.nest-avatar-item--sleeping {
	transform-origin: 50% 78%;
	animation: nestAvatarSleepBreathing 2.8s ease-in-out infinite;
}
.nest-avatar-sleep-bubble {
	position: absolute;
	z-index: 31;
	transform: translate(-8%, calc(-100% - 34px));
	padding: 4px 8px;
	border: 1.5px solid var(--nest-sleep-color, #D7A35B);
	border-radius: 12px 12px 12px 3px;
	background: rgba(255, 255, 255, 0.94);
	color: #536176;
	font-size: 11px;
	font-weight: 800;
	line-height: 1;
	letter-spacing: 0.4px;
	box-shadow: 0 2px 6px rgba(0,0,0,0.12);
	pointer-events: none;
	animation: nestAvatarSleepZzz 2.8s ease-in-out infinite;
}
.nest-avatar-sleep-bubble--below {
	transform: translate(-8%, 24px);
}
@keyframes nestAvatarSleepBreathing {
	0%, 100% { transform: translate(-50%, -50%) scaleX(var(--nest-avatar-facing)) scaleY(1); }
	50% { transform: translate(-50%, -49%) scaleX(var(--nest-avatar-facing)) scaleY(0.965); }
}
@keyframes nestAvatarSleepZzz {
	0%, 100% { opacity: 0.58; }
	50% { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
	.nest-avatar-item--sleeping,
	.nest-avatar-sleep-bubble {
		animation: none;
	}
}
.nest-avatar-speech {
	position: absolute;
	transform: translate(-50%, calc(-100% - 34px));
	z-index: 30;
	max-width: min(58%, 220px);
	padding: 7px 10px;
	border: 2px solid var(--nest-speech-color, #D7A35B);
	border-radius: 12px;
	background: rgba(255, 255, 255, 0.96);
	color: #222;
	font-size: 12px;
	font-weight: 700;
	line-height: 1.35;
	text-align: center;
	box-shadow: 0 3px 10px rgba(0,0,0,0.2);
	pointer-events: none;
	animation: nestAvatarSpeechIn 0.2s ease-out;
}
.nest-avatar-speech::after {
	content: '';
	position: absolute;
	left: 50%;
	bottom: -8px;
	width: 12px;
	height: 12px;
	background: rgba(255, 255, 255, 0.96);
	border-right: 2px solid var(--nest-speech-color, #D7A35B);
	border-bottom: 2px solid var(--nest-speech-color, #D7A35B);
	transform: translateX(-50%) rotate(45deg);
}
.nest-avatar-speech--below {
	transform: translate(-50%, 34px);
	animation-name: nestAvatarSpeechBelowIn;
}
.nest-avatar-speech--below::after {
	top: -8px;
	bottom: auto;
	border: 0;
	border-left: 2px solid var(--nest-speech-color, #D7A35B);
	border-top: 2px solid var(--nest-speech-color, #D7A35B);
}
@keyframes nestAvatarSpeechIn {
	from { opacity: 0; transform: translate(-50%, calc(-100% - 26px)) scale(0.94); }
	to { opacity: 1; transform: translate(-50%, calc(-100% - 34px)) scale(1); }
}
@keyframes nestAvatarSpeechBelowIn {
	from { opacity: 0; transform: translate(-50%, 26px) scale(0.94); }
	to { opacity: 1; transform: translate(-50%, 34px) scale(1); }
}
/* 고정 슬롯 자리 표시 — 편집 모드에서만 보임. 채워진 슬롯은 은은한 링만, 빈 슬롯은 라벨까지 노출. */
.nest-slot-marker-container {
	position: absolute;
	inset: 0;
	pointer-events: none;
	z-index: 7;
}
.nest-slot-marker {
	position: absolute;
	transform: translate(-50%, -50%);
	border-radius: 50%;
	display: flex;
	align-items: center;
	justify-content: center;
}
.nest-slot-marker.empty {
	border: 2px dashed rgba(255, 255, 255, 0.85);
	background: rgba(0, 0, 0, 0.18);
}
.nest-slot-marker.filled {
	border: 2px solid rgba(255, 170, 0, 0.55);
}
.nest-slot-marker-label {
	font-size: 10px;
	font-weight: 700;
	color: #fff;
	text-shadow: 0 1px 2px rgba(0,0,0,0.6);
	text-align: center;
	padding: 0 2px;
}
.nest-edit-grid {
	position: absolute;
	top: 0; left: 0; right: 0; bottom: 0;
	cursor: crosshair;
	z-index: 10;
}
.nest-inventory-panel {
	background: var(--dk-bg-surface);
	border-top: 1px solid var(--dk-border);
	padding: 12px;
}
.nest-inv-mode-tabs {
	display: flex;
	gap: 8px;
	margin-bottom: 8px;
}
.nest-inv-mode-tabs button {
	flex: 1;
	padding: 6px 0;
	border: 1px solid var(--dk-border);
	background: var(--dk-bg-surface-alt);
	color: var(--dk-text-secondary);
	border-radius: 8px;
	font-size: 13px;
	font-weight: 700;
	cursor: pointer;
}
.nest-inv-mode-tabs button.active {
	background: #1957D6;
	color: #fff;
	border-color: #1957D6;
}
.nest-inventory-panel p.guide {
	text-align: center;
	color: var(--dk-text-secondary);
	font-size: 13px;
	margin: 0 0 10px 0;
}
.nest-inv-scroll {
	display: grid;
	grid-template-columns: repeat(4, 1fr);
	gap: 8px;
	padding-bottom: 8px;
}
.nest-inv-btn {
	width: 100%;
	height: 84px;
	border: 2px solid transparent;
	background: var(--dk-bg-surface-alt);
	border-radius: 8px;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	cursor: pointer;
	transition: all 0.2s;
	min-width: 0;
	overflow: hidden;
}
.nest-inv-btn.selected {
	border-color: #1957D6;
	background: #E7EEFC;
}
.nest-inv-btn img {
	width: 40px;
	height: 40px;
	object-fit: contain;
}
.nest-inv-btn span {
	font-size: 11px;
	color: var(--dk-text-primary);
	margin-top: 6px;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
	width: 100%;
	text-align: center;
}
.nest-inv-fixed-badge {
	font-style: normal;
	font-size: 9px;
	font-weight: 700;
	color: #ffaa00;
}

.posting-feed-item-title { flex: 1 1 auto; }

.ranking-item { position: relative; }
/* 랭킹 한 줄의 오른쪽 열(지역 배지 + 점수). 이 열의 콘텐츠 폭이 그대로 닉네임 칸을 깎아먹는다 —
   이름 쪽(nameCol)이 flex:1(basis 0)이라 남는 공간만 받기 때문이다. 그래서 여기에 상한을 둔다. */
.ranking-item-right {
	display: flex;
	flex-direction: column;
	align-items: flex-end;
	gap: 4px;
	/* 없으면 min-content 아래로 절대 안 줄어든다. */
	min-width: 0;
	/* 지역 열을 제한해 닉네임에 공간을 우선 배정한다. */
	max-width: 30%;
	/* 위에서 행 간격을 8px로 줄였는데, 이름과 지역 배지까지 붙으면 읽기 나빠져서 여기만 되돌린다. */
	margin-left: 4px;
}

/* 상한에 걸리면 배지 쪽이 줄어들지, 이름을 밀어내지 않게 한다. */
.ranking-item-region-tags .region-tag-1,
.ranking-item-region-tags .region-tag-2,
.ranking-item-region-tags .region-tag-normal {
	font-size: var(--dk-font-micro, 10px);
	line-height: 14px;
	padding: 0 4px;
	border-radius: 4px;
	overflow: hidden;
	text-overflow: ellipsis;
}

.ranking-item-name-wrap {
	display: flex;
	align-items: center;
	flex-wrap: nowrap;
	gap: 5px;
	min-width: 0;
}

/* The companion label shares the nickname column, independently of badge width. */
.ranking-item-identity {
	display: grid;
	grid-template-columns: auto minmax(0, 1fr);
	column-gap: 5px;
	flex: 1;
	min-width: 0;
}
.ranking-item-identity > .ranking-item-icon-nickname {
	grid-column: 2;
	grid-row: 1;
}
.ranking-item-identity > .ranking-item-name-wrap { display: contents; }
.ranking-item-identity .bird-level-badge {
	grid-column: 1;
	grid-row: 2;
	align-self: center;
}
.ranking-item-identity .ranking-item-name {
	grid-column: 2;
	grid-row: 2;
	align-self: center;
}

/* 긴 닉네임도 같은 열 안에서 줄바꿈해 새 이름과 시작점을 맞춘다. */
.ranking-item-name-wrap > .ranking-item-name {
	flex: 1 1 auto;
	min-width: 0;
	max-width: 100%;
	white-space: normal;
	overflow-wrap: anywhere;
	overflow: visible;
	text-overflow: clip;
}

.ranking-item-region-tags {
	display: flex;
	flex-wrap: wrap;
	justify-content: flex-end;
	gap: 4px;
}

.posting-feed-title-row {
	display: flex;
	justify-content: space-between;
	align-items: flex-start;
	gap: 8px;
	margin-bottom: 6px;
}

.posting-feed-region-tags {
	flex: 0 0 auto;
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--dk-space-1, 4px);
	/* margin-top 제거 — 더 이상 자기 행이 아니라 메타 행 안에 있다(POST-01). */
}

/* 포스팅의 지역 태그는 제목보다 작은 보조 정보로 표시한다. */
.posting-feed-region-tags > .region-tag-1,
.posting-feed-region-tags > .region-tag-2 {
	font-size: var(--dk-font-micro, 10px);
	line-height: 14px;
	padding: 0 4px;
	border-radius: 4px;
}

/* 지역명은 색상 암기 없이 읽을 수 있도록 시·도 / 시·군·구 두 단계로만 구분한다.
   ⚠️ 치수는 작게 유지할 것(2026-09-10 사용자 제보 — "포스팅에서도 지역 뱃지가 너무 커",
   "랭킹에서 닉네임이 잘린다"). 같은 날 개편이 10px → 12px + 패딩/테두리를 키웠는데, 랭킹 줄에서는
   이 배지가 닉네임과 가로 공간을 직접 나눠 쓰기 때문에 오른쪽 열이 약 16px 넓어지며 이름이 잘렸다.
   이 배지는 애초에 "유저 랭킹도 작은 태그로 해야지"(2026-09-06 사용자 요청)로 만들어진 것이다.
   개편의 핵심이던 배경/테두리/2단계 색 구분과 다크모드 대비는 그대로 유지한다 — 되돌린 건 치수뿐. */
.region-tag-1, .region-tag-2, .region-tag-normal {
	display: inline-flex;
	align-items: center;
	max-width: 100%;
	padding: 1px 5px;
	border: 1px solid var(--dk-border-soft);
	border-radius: 5px;
	background: var(--dk-bg-surface-alt);
	color: var(--dk-text-secondary);
	font-size: var(--dk-font-micro);
	font-weight: 600;
	line-height: var(--dk-leading-micro);
	overflow-wrap: anywhere;
}

.region-tag-1 {
	border-color: var(--dk-region-border);
	background: var(--dk-region-bg);
	color: var(--dk-region-text);
	font-weight: 700;
	white-space: nowrap;
}

/* ============================================================
   상점(Shop) — 2026-09-08 신설
   사용자 요청: "모든 하단탭을 누르더라도 왼쪽 밑에 노출되는 개념". 그래서 탭 시트(z-index 690)보다
   위(700)에 position:fixed로 띄운다. 배경/텍스트/테두리는 전부 --dk-* 변수만 사용(todo.md 표준 UI
   원칙 — 배경과 텍스트는 항상 짝지어 확인).
   ============================================================ */


/* ============================================================
   집중 모드 (2026-09-10 신설, 사용자 요청 — "맵에 집중할 수 있도록")
   토글 버튼은 내 위치 버튼 바로 위에 세로로 붙는다. 숨김 대상은 아래 한 블록에 모아뒀으니
   추가/제거는 여기만 고치면 된다(JS는 body.focus-mode 클래스만 토글한다).
   ⚠️ 규칙을 [data-active-tab="location"]으로 묶은 건 의도다 — 집중 모드를 켠 채 다른 탭으로
   가면 헤더가 사라져 메뉴를 못 여는 상태가 되기 때문에, 필드에서만 걸리게 했다.
   사용자 요청대로 모바일 기준 기능이라, 데스크톱 뷰(좌측 사이드바 레이아웃)에서는 버튼 자체를
   숨긴다 — 그쪽은 화면이 넓어 가릴 이유가 없다.
   ============================================================ */
.focus-mode-fab {
	position: absolute;
	right: 14px;
	/* 내 위치 버튼(bottom 44px + 높이 52px) 위에 8px 띄워 세로로 나란히. */
	bottom: 104px;
	z-index: 150;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 1px;
	width: 52px;
	height: 52px;
	padding: 0;
	border: 1px solid var(--dk-border-soft);
	border-radius: 50%;
	background: var(--dk-bg-surface);
	color: var(--dk-text-secondary);
	box-shadow: var(--dk-shadow-md);
	font-family: inherit;
	cursor: pointer;
}

.focus-mode-fab-label {
	font-size: 9px;
	font-weight: 700;
	line-height: 1;
}

/* 켜진 상태는 브랜드 블루로 채워 "지금 켜져 있다"를 분명히 한다(끄는 법을 못 찾으면 안 되므로). */
.focus-mode-fab.is-on {
	background: #1957D6;
	border-color: #1957D6;
	color: #ffffff;
}

.focus-mode-fab:active {
	transform: scale(0.94);
}

body.is-desktop-view .focus-mode-fab {
	display: none;
}

/* --- 집중 모드에서 숨기는 것들 (필드 탭 한정) --- */
body.focus-mode:not(.is-desktop-view)[data-active-tab="location"] .app-header,
body.focus-mode:not(.is-desktop-view)[data-active-tab="location"] #globalTicker,
body.focus-mode:not(.is-desktop-view)[data-active-tab="location"] .difficulty-fab-wrap,
body.focus-mode:not(.is-desktop-view)[data-active-tab="location"] #fieldHudWrap,
body.focus-mode:not(.is-desktop-view)[data-active-tab="location"] #fieldHudSpeechStack {
	display: none !important;
}

/* (2026-09-10 변경) 예전엔 position:fixed로 모든 탭 위에 떠 있었으나, 사용자 요청으로 필드 전용이
   됐다 — .map-wrap 안 absolute라 지도가 숨거나 탭 시트가 덮으면 같이 사라진다(.my-location-fab과
   같은 방식). 그래서 화면 폭에 맞춰 left를 계산하던 max() 식도 더 이상 필요 없다(부모가 이미
   480px 컬럼이다). 우하단 내 위치 버튼과 좌우로 갈라 겹치지 않는다. */
.shop-fab {
	position: absolute;
	left: 14px;
	bottom: 44px;
	z-index: 150;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 1px;
	width: 52px;
	height: 52px;
	padding: 0;
	border: 1px solid var(--dk-border-soft);
	border-radius: 50%;
	background: var(--dk-bg-surface);
	/* 브랜드 블루 — 내 위치 버튼과 같은 계열로 맞춰 필드 위 두 버튼이 한 세트로 보이게 한다. */
	color: #1957D6;
	box-shadow: var(--dk-shadow-md);
	cursor: pointer;
}

.shop-fab:active {
	background: var(--dk-bg-surface-alt);
	transform: scale(0.94);
}


.shop-fab-label {
	font-size: 9px;
	font-weight: 700;
	line-height: 1;
}


/* 둥지 만물상: 브랜드 블루와 공용 테마 색, 큰 상품 진열대. */
.shop-modal {
	position:fixed;
	inset:0;
	z-index:10000;
	display:flex;
	align-items:stretch;
	justify-content:center;
	background:var(--dk-bg-surface);
	overscroll-behavior:contain;
}

.shop-modal-inner {
	width:100%;
	height:100vh;
	height:100dvh;
	display:flex;
	flex-direction:column;
	background:var(--dk-bg-surface);
	color:var(--dk-text-primary);
	border-radius:0;
	padding-top:env(safe-area-inset-top);
	padding-left:env(safe-area-inset-left);
	padding-right:env(safe-area-inset-right);
	box-sizing:border-box;
	overflow:hidden;
	box-shadow:var(--dk-shadow-md);
}

.shop-modal-header {
	display:flex;
	align-items:center;
	justify-content:space-between;
	gap:8px;
	padding:16px 20px;
	border-bottom:1px solid var(--dk-border-soft);
	flex-shrink:0;
}

.shop-eyebrow {
	display:block;
	font-size:11px;
	color:var(--dk-text-secondary);
	margin-bottom:5px;
	font-weight:500;
}

#shopTitle {
	margin:0;
	font-size:23px;
	letter-spacing:-1px;
}

.shop-modal-header-right {
	display:flex;
	align-items:center;
	gap:8px;
}

.shop-point {
	font-size:12px;
	font-weight:750;
	padding:9px 11px;
	border:1px solid var(--dk-border);
	border-radius:20px;
	white-space:nowrap;
	color:var(--dk-text-primary);
	background:var(--dk-bg-surface-alt);
}

.shop-keeper {
	display:flex;
	align-items:center;
	gap:12px;
	padding:12px 16px;
	margin:14px 16px 0;
	border:1px solid var(--dk-border-soft);
	border-radius:18px;
	background:var(--dk-bg-surface-alt);
	color:var(--dk-text-primary);
}

.shop-keeper-icon {
	flex-shrink:0;
	width:64px;
	height:64px;
	object-fit:contain;
	filter:drop-shadow(0 5px 3px rgba(0,0,0,.08));
}

.shop-keeper strong {
	font-size:14px;
}

.shop-keeper-bubble {
	font-size:12px;
	line-height:1.6;
	margin-top:6px;
	color:var(--dk-text-secondary);
}

.shop-category-tabs {
	display:flex;
	gap:4px;
	margin:16px 16px 0;
	padding:4px;
	border:1px solid var(--dk-border-soft);
	border-radius:16px;
	background:var(--dk-bg-surface-alt);
	flex-shrink:0;
}

.shop-category-tab {
	flex:1;
	min-width:0;
	min-height:44px;
	padding:10px 8px;
	appearance:none;
	-webkit-appearance:none;
	-webkit-tap-highlight-color:transparent;
	-webkit-user-select:none;
	user-select:none;
	border:0;
	border-radius:12px;
	background:transparent;
	color:var(--dk-text-secondary);
	font-family:inherit;
	font-size:14px;
	line-height:20px;
	font-weight:700;
	cursor:pointer;
}

.shop-category-tab.active {
	background:#1957D6;
	color:var(--dk-text-inverse);
}

.shop-guide {
	margin:12px 20px 14px;
	font-size:12px;
	line-height:1.5;
	color:var(--dk-text-secondary);
}

.shop-grid {
	flex:1;
	min-height:0;
	overflow-y:auto;
	overscroll-behavior:contain;
	display:grid;
	/* (2026-09-09) 2열 → 3열. 사용자 지적 "밀도가 낮다" — 한 화면에 보이는 상품 수를 늘린다. */
	grid-template-columns:repeat(3,minmax(0,1fr));
	align-content:start;
	gap:8px;
	padding:0 12px 12px;
}

.shop-item {
	position:relative;
	display:flex;
	min-width:0;
	flex-direction:column;
	align-items:stretch;
	gap:5px;
	padding:8px 7px;
	border:1px solid var(--dk-border-soft);
	border-radius:14px;
	background:var(--dk-bg-surface);
	color:var(--dk-text-primary);
	cursor:pointer;
	text-align:left;
}

.shop-item:hover {
	border-color:#1957D6;
	box-shadow:var(--dk-shadow-sm);
}

.shop-item:active {
	background:var(--dk-bg-surface-alt);
}

.shop-artwork {
	position:relative;
	display:grid;
	place-items:center;
	width:100%;
	/* 3열로 좁아진 카드에 맞춰 정사각에 가깝게 — 고정 128px은 세로만 길어 보였다. */
	aspect-ratio:1 / 1;
	height:auto;
	flex-shrink:0;
	border-radius:10px;
	background:var(--dk-bg-surface-alt);
	overflow:hidden;
}

.shop-item-icon {
	position:absolute;
	width:90%;
	height:90%;
	object-fit:contain;
}

.shop-image-fallback {
	font-size:11px;
	color:var(--dk-text-secondary);
}

.shop-item-name {
	/* (2026-09-09 가독성) 3열에서도 읽히도록 자간/줄수를 고정한다 — 2줄 클램프로 카드 높이도 정렬된다. */
	font-size:12px;
	font-weight:700;
	line-height:1.35;
	min-height:2.7em;
	display:-webkit-box;
	-webkit-line-clamp:2;
	-webkit-box-orient:vertical;
	overflow:hidden;
	word-break:keep-all;
}

.shop-item-description {
	color:var(--dk-text-secondary);
	font-size:11px;
	line-height:1.5;
	display:none;
	-webkit-line-clamp:2;
	-webkit-box-orient:vertical;
	overflow:hidden;
}

.shop-item-price {
	font-size:13px;
	font-weight:800;
	color:var(--dk-text-primary);
	font-variant-numeric:tabular-nums;
	white-space:nowrap;
}

.shop-item-owned {
	position:absolute;
	top:11px;
	right:10px;
	padding:2px 6px;
	border:1px solid var(--dk-border-soft);
	border-radius:10px;
	background:var(--dk-bg-surface);
	font-size:10px;
	font-weight:700;
	color:var(--dk-text-secondary);
}

.shop-item-action {
	padding-top:8px;
	border-top:1px solid var(--dk-border-soft);
	font-size:11px;
	font-weight:600;
	color:var(--dk-text-secondary);
}

.shop-empty {
	grid-column:1/-1;
	padding:28px 12px;
	color:var(--dk-text-secondary);
	font-size:13px;
	text-align:center;
}

.shop-footer {
	padding:8px 16px;
	margin:0;
	border-top:1px solid var(--dk-border-soft);
	font-size:11px;
	text-align:center;
	color:var(--dk-text-secondary);
	flex-shrink:0;
}

.shop-navigation {
	display:flex;
	align-items:center;
	gap:12px;
	flex-shrink:0;
	padding:12px 16px calc(12px + env(safe-area-inset-bottom));
	border-top:1px solid var(--dk-border-soft);
	background:var(--dk-bg-surface);
}

.shop-return {
	flex-shrink:0;
	min-height:50px;
	padding:12px 20px;
	border:1px solid var(--dk-border);
	border-radius:12px;
	background:var(--dk-bg-surface-alt);
	color:var(--dk-text-primary);
	font:inherit;
	font-size:14px;
	font-weight:700;
	cursor:pointer;
	-webkit-tap-highlight-color:transparent;
}

.shop-back-hint {
	font-size:11px;
	line-height:1.5;
	color:var(--dk-text-secondary);
}

/* 스와이프 안내는 터치로 조작하는 기기에서만 보여준다 — 마우스 환경에서는 "왼쪽 가장자리에서
   오른쪽으로 밀어" 자체를 할 수 없어서 오히려 혼란스럽다. 여기서 body.is-desktop-view(레이아웃
   전환용 클래스, 사용자가 강제 전환 가능) 대신 포인터 종류를 보는 이유는, 터치 스크린 노트북을
   데스크톱 뷰로 강제해놨어도 스와이프는 실제로 되기 때문 — 이건 레이아웃이 아니라 입력 수단 문제다. */
@media (hover: hover) and (pointer: fine) {
	.shop-back-hint {
		display:none;
	}
}

.shop-purchase-action {
	flex:1;
	min-width:0;
}

.shop-detail {
	flex:1;
	min-height:0;
	overflow-y:auto;
	overscroll-behavior:contain;
	padding:0 20px 20px;
}

.shop-modal.is-detail .shop-keeper, .shop-modal.is-detail .shop-guide {
	display:none;
}

.shop-modal.is-detail .shop-category-tabs {
	margin-bottom:14px;
}

.shop-detail .shop-artwork {
	height:clamp(160px, 30vh, 320px);
	margin:10px 0 16px;
}

.shop-detail h3 {
	font-size:21px;
	margin:0 0 8px;
}

.shop-detail-description {
	font-size:13px;
	line-height:1.7;
	color:var(--dk-text-secondary);
}

.shop-detail-owned {
	font-size:12px;
	color:var(--dk-text-secondary);
}

.shop-detail-balance {
	font-size:13px;
	font-weight:700;
	padding:14px 0;
	border-top:1px solid var(--dk-border-soft);
}

.shop-back {
	min-height:44px;
	padding:8px 12px;
	border:1px solid var(--dk-border);
	border-radius:10px;
	color:var(--dk-text-primary);
	background:var(--dk-bg-surface);
	cursor:pointer;
}

/* (2026-09-10) 상세 화면 수량 선택기 — 서버가 원래부터 지원하던 1~99개 구매를 프론트에 연결.
   최대 1개만 살 수 있는 상황에서는 JS가 아예 안 그린다(누를 데 없는 죽은 UI 방지). */
.shop-quantity {
	display:flex;
	align-items:center;
	gap:8px;
	margin:4px 0 2px;
}

.shop-quantity-step {
	flex:0 0 auto;
	width:44px;
	min-height:44px;
	border:1px solid var(--dk-border);
	border-radius:10px;
	background:var(--dk-bg-surface);
	color:var(--dk-text-primary);
	font-size:18px;
	font-weight:700;
	line-height:1;
	cursor:pointer;
}

.shop-quantity-value {
	flex:1 1 auto;
	text-align:center;
	color:var(--dk-text-primary);
	font-size:16px;
	font-weight:700;
	/* 수량이 1→2자리로 바뀔 때 좌우 버튼이 밀리지 않게 자릿수 폭을 고정한다. */
	font-variant-numeric:tabular-nums;
}

.shop-quantity-max {
	flex:0 0 auto;
	min-height:44px;
	padding:0 12px;
	border:1px solid var(--dk-border);
	border-radius:10px;
	background:var(--dk-bg-surface);
	color:var(--dk-text-secondary);
	font-size:12px;
	font-weight:700;
	white-space:nowrap;
	cursor:pointer;
}

.shop-quantity-step:disabled, .shop-quantity-max:disabled {
	background:var(--dk-bg-surface-alt-2);
	color:var(--dk-text-tertiary);
	cursor:default;
}

.shop-buy {
	width:100%;
	min-height:var(--dk-control-primary);
	border:0;
	border-radius:14px;
	background:#1957D6;
	color:var(--dk-text-inverse);
	font-size:15px;
	font-weight:700;
	cursor:pointer;
}

.shop-buy:disabled {
	background:var(--dk-bg-surface-alt-2);
	color:var(--dk-text-secondary);
	cursor:default;
}

.shop-modal [hidden] {
	display:none !important;
}

.shop-modal button:focus-visible, .shop-fab:focus-visible {
	outline:3px solid #1957D6;
	outline-offset:2px;
}

@media (min-width:768px) {
	.shop-grid { grid-template-columns:repeat(4,minmax(0,1fr)); }
	.shop-modal-inner > * { padding-left: max(24px, calc((100vw - 1160px) / 2)); padding-right: max(24px, calc((100vw - 1160px) / 2)); }
	.shop-modal-inner > .shop-category-tabs { padding:4px; margin-left:max(24px, calc((100vw - 1160px) / 2)); margin-right:max(24px, calc((100vw - 1160px) / 2)); }
	.shop-keeper { border:0; margin:0; border-radius:0; }
	.shop-detail { width:100%; max-width:720px; box-sizing:border-box; align-self:center; }
	.shop-modal-inner > .shop-detail { padding:16px 24px; }
	.shop-artwork { height:180px; }
	.shop-back-hint { margin-left:auto; }

}

@media (max-width:360px) {
	.shop-navigation { gap:8px; padding-left:12px; padding-right:12px; }
	.shop-return { padding:12px; font-size:12px; }
	.shop-buy { font-size:12px; }
}

@media (max-height:650px) {
	.shop-keeper {
		padding:8px 14px;
	}

	.shop-keeper-icon {
		width:48px;
		height:48px;
	}

	.shop-modal-header {
		padding:10px 16px;
	}

	.shop-keeper strong,.shop-eyebrow {
		display:none;
	}

	.shop-category-tabs {
		margin-top:10px;
	}

}

/* ============================================================
   상점 개선 (2026-09-09) — 사용자 지적 "밀도가 낮고, 구매욕을 높이는 요소가 없고, 가독성이 떨어진다"
   + "유저의 인벤토리도 접근할 수 있게".
   - 밀도: 모바일 3열 + 카드/여백 축소(위 .shop-grid/.shop-item 규칙에서 조정).
   - 구매욕: 가짜 급함(한정 세일 등)을 만들지 않고, "지금 살 수 있는지"를 색과 필터로 즉시 보이게 한다.
   - 가독성: 카드 안 정보를 이름(2줄) / 가격+상태 한 줄로 고정해 카드마다 높이와 시선 흐름을 통일.
   - 보관함: 같은 시트 안에서 상점 ↔ 보관함을 전환해 "사고 → 들어왔는지 확인"이 끊기지 않게 한다.
   색은 전부 --dk-* 변수 + 브랜드 블루/의미색만 사용(다크모드 원칙).
   ============================================================ */

/* 상점 / 보관함 전환 */
.shop-mode-tabs {
	display:flex;
	gap:6px;
	flex-shrink:0;
	margin:10px 16px 0;
	padding:4px;
	border-radius:12px;
	background:var(--dk-bg-surface-alt);
}

.shop-mode-tab {
	flex:1;
	min-height:38px;
	border:0;
	border-radius:9px;
	background:transparent;
	color:var(--dk-text-secondary);
	font:inherit;
	font-size:13px;
	font-weight:700;
	cursor:pointer;
	-webkit-tap-highlight-color:transparent;
}

.shop-mode-tab.active {
	background:#1957D6;
	color:var(--dk-text-inverse);
}

/* 필터/정렬 줄 — 칩 형태로 한 줄에 모아 목록 높이를 거의 안 먹게 한다. */
.shop-filters {
	display:flex;
	align-items:center;
	gap:6px;
	flex-shrink:0;
	padding:8px 16px;
}

.shop-chip {
	min-height:32px;
	padding:6px 12px;
	border:1px solid var(--dk-border);
	border-radius:16px;
	background:var(--dk-bg-surface);
	color:var(--dk-text-secondary);
	font:inherit;
	font-size:12px;
	font-weight:700;
	cursor:pointer;
	white-space:nowrap;
	-webkit-tap-highlight-color:transparent;
}

.shop-chip.active {
	background:#1957D6;
	border-color:#1957D6;
	color:var(--dk-text-inverse);
}

.shop-count {
	margin-left:auto;
	font-size:11px;
	font-weight:700;
	color:var(--dk-text-tertiary);
	font-variant-numeric:tabular-nums;
}

/* 가격 + 상태를 한 줄로 — 카드마다 같은 자리에 오게 해서 눈이 한 번에 훑히게 한다. */
.shop-item-price-row {
	display:flex;
	align-items:baseline;
	justify-content:space-between;
	gap:4px;
	margin-top:auto;
	min-width:0;
}

.shop-item-state {
	font-size:10px;
	font-weight:700;
	line-height:1.3;
	white-space:nowrap;
	overflow:hidden;
	text-overflow:ellipsis;
	color:var(--dk-text-tertiary);
}

/* 지금 살 수 있는 카드만 또렷하게 — 살 수 없는 카드는 눌러서 상세를 볼 수는 있어야 하므로
   완전히 감추지 않고 채도만 낮춘다(부족한 포인트는 상태 문구에 정확한 숫자로 남긴다). */
.shop-item.is-buyable {
	border-color:#1957D6;
}

.shop-item.is-buyable .shop-item-state {
	color:#1957D6;
}

.shop-item.is-short .shop-artwork,
.shop-item.is-full .shop-artwork {
	opacity:.55;
}

.shop-item.is-short .shop-item-price,
.shop-item.is-full .shop-item-price {
	color:var(--dk-text-secondary);
}

/* 보관함 */
.shop-bag {
	flex:1;
	min-height:0;
	overflow-y:auto;
	overscroll-behavior:contain;
	display:flex;
	flex-direction:column;
}

.shop-bag-head {
	margin:0;
	padding:10px 16px 6px;
	font-size:12px;
	font-weight:700;
	color:var(--dk-text-secondary);
	font-variant-numeric:tabular-nums;
}

/* 보관함 칸은 누를 수 없는 정보 카드라 커서/테두리 강조를 뺀다. */
.shop-grid--bag {
	flex:0 0 auto;
	overflow:visible;
}

.shop-item.is-owned {
	cursor:default;
	border-color:var(--dk-border-soft);
}

@media (min-width:768px) {
	/* PC는 카드가 커도 여유가 있으니 5열까지 늘려 밀도를 더 높인다. */
	.shop-grid { grid-template-columns:repeat(5,minmax(0,1fr)); }
	.shop-item-name { font-size:13px; }
	.shop-mode-tabs { max-width:320px; }
}

/* ============================================================
   내 위치로 버튼 (2026-09-09, 사용자 요청 — "필드 오른쪽 아래에 내 위치로 버튼")
   .map-wrap 안의 absolute라 지도가 숨거나 탭 시트가 덮으면 같이 사라진다(필드 전용).
   ⚠️ bottom을 44px로 띄운 이유: 지도 하단 우측에 네이버 축척바/로고가 깔리는데, 저작권 표기는
   가려선 안 되는 요소라 그 위로 올렸다. 좌하단 상점 버튼(.shop-fab)과는 좌우로 갈라 안 겹친다.
   색/그림자는 같은 지도 위 버튼인 .toilet-fab 계열의 디자인 언어를 그대로 따른다.
   ============================================================ */
.my-location-fab {
	position: absolute;
	right: 14px;
	bottom: 44px;
	z-index: 150;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 1px;
	width: 52px;
	height: 52px;
	padding: 0;
	border: 1px solid var(--dk-border-soft);
	border-radius: 50%;
	background: var(--dk-bg-surface);
	color: #1957D6;
	box-shadow: 0 2px 6px rgba(0, 0, 0, 0.18);
	cursor: pointer;
	-webkit-tap-highlight-color: transparent;
}

.my-location-fab:active {
	background: var(--dk-bg-surface-alt);
	transform: scale(0.94);
}

/* 위치를 찾는 동안(disabled) 눌러도 반응 없는 게 아니라 "지금 찾고 있다"로 읽히게 한다. */
.my-location-fab:disabled {
	cursor: progress;
	opacity: 0.6;
}

.my-location-fab-label {
	font-size: 9px;
	font-weight: 800;
	line-height: 1;
	letter-spacing: -0.3px;
	color: var(--dk-text-secondary);
}

/* 데스크톱은 하단 탭바가 좌측 사이드바로 바뀌어 지도 폭이 넓어지지만, 축척바는 여전히 지도
   우하단이라 같은 오프셋을 유지한다. */
body.is-desktop-view .my-location-fab {
	bottom: 48px;
}

/* ============================================================
   채팅 이모티콘 (2026-09-13, ui_todo.md CHAT-11D/11E)

   기본 팩은 개별 투명 RGBA PNG 6장을 쓰고, 과거 스프라이트 카탈로그도 읽을 수 있다.
   두 방식 모두 background-image 대신 img로 그린다. img여야 로드 실패를 감지해 대체 문구를 띄울 수 있다.

	자산은 컬러 채팅 배경·다크모드에서 사각 매트가 보이지 않는 투명 RGBA여야 한다.
	파일 알파와 셀 모서리 투명도는 회귀 테스트가 검증한다(ui_todo.md CHAT-11A/11F).
   ============================================================ */

.chat-emoticon {
	position: relative;
	display: block;
	overflow: hidden;
	background-color: transparent;
	/* 대화 안에서는 좁은 화면도 96px을 보장하고, 여유가 있으면 112px까지 쓴다. */
	width: clamp(96px, 26vw, 112px);
	height: clamp(96px, 26vw, 112px);
	max-width: 112px;
	max-height: 112px;
	flex: 0 0 auto;
}

.chat-emoticon-image {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: contain;
	background-color: transparent;
}

/* 시트 한 장을 3배×2배로 키우고 밀어 넣어 한 칸만 남긴다 — 좌표는 JS가 인라인으로 준다. */
.chat-emoticon-image--atlas {
	position: absolute;
	object-fit: fill;
}

/* 그림을 못 불러온 경우 — 행을 비우지 않고 무슨 이모티콘이었는지는 남긴다. */
.chat-emoticon--broken {
	display: inline-flex;
	align-items: center;
	width: auto;
	height: auto;
	padding: 6px 10px;
	border: 1px dashed var(--dk-border);
	border-radius: 10px;
	background: var(--dk-bg-surface-alt);
}

.chat-emoticon-fallback {
	font-size: 13px;
	color: var(--dk-text-secondary);
}

/* 대화 안의 그림 — 텍스트 말풍선의 배경·패딩을 중복으로 씌우지 않는다(지시서 2절). */
.chat-message-emoticon {
	display: flex;
	padding: 0;
	background: none;
	border: none;
}

.chat-message-own .chat-message-emoticon {
	justify-content: flex-end;
}

/* 카탈로그에서 사라진 코드 — 대체 문구만 남고, 왜 그림이 없는지 알 수 있게 표시한다. */
.chat-message-text--unsupported {
	font-style: italic;
	color: var(--chat-received-text, var(--dk-text-secondary));
}

/* ---------------------------------------------------------------- 선택기 */

.chat-emoticon-button {
	flex: 0 0 auto;
	/* 조작 영역은 44×44px 이상(지시서 2절·7절). */
	box-sizing: border-box;
	width: 44px;
	height: 44px;
	min-width: 44px;
	min-height: 44px;
	padding: 0;
	border: 2px solid var(--dk-border);
	border-radius: 20px;
	background: var(--dk-bg-surface);
	color: var(--dk-text-secondary);
	font-size: 20px;
	line-height: 1;
	font-family: inherit;
	cursor: pointer;
}

/* 무언가 골라 둔 상태 — 색과 선택기 내부 체크 표시를 함께 바꾼다. */
.chat-emoticon-button.has-selection {
	border: 2px solid #1957D6;
	color: #1957D6;
}

.chat-emoticon-button[disabled] {
	opacity: 0.5;
	cursor: default;
}

.chat-emoticon-panel {
	flex: 0 0 auto;
	max-height: 46vh;
	overflow-y: auto;
	padding: 10px 16px;
	border-top: 1px solid var(--dk-border-soft);
	background: var(--dk-bg-surface);
}

/* hidden의 사용자 에이전트 규칙보다 명시적으로 우선해 닫힌 선택기가 높이를 전혀 남기지 않게 한다. */
.chat-emoticon-panel[hidden] {
	display: none !important;
	height: 0;
	padding: 0;
	border: 0;
}

.chat-emoticon-panel-status {
	margin: 0;
	font-size: 13px;
	color: var(--dk-text-secondary);
}

.chat-emoticon-pack-name {
	margin: 0 0 8px;
	font-size: 12px;
	font-weight: bold;
	letter-spacing: 0.03em;
	color: var(--dk-text-secondary);
}

/* 3열 고정 — 320px에서도 가로 스크롤 없이 들어가야 한다(지시서 2절). */
.chat-emoticon-grid {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: 8px;
}

.chat-emoticon-choice {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 4px;
	min-width: 44px;
	min-height: 44px;
	padding: 6px 4px;
	border: 2px solid transparent;
	border-radius: 12px;
	background: none;
	font-family: inherit;
	cursor: pointer;
}

/* 선택은 색만이 아니라 테두리와 체크 표시로 알린다(색을 못 가리는 사용자 대응). */
.chat-emoticon-choice.is-selected {
	border-color: #1957D6;
	background: rgba(25, 87, 214, 0.08);
}

.chat-emoticon-choice.is-selected .chat-emoticon-choice-name::after {
	content: ' ✓';
}

.chat-emoticon-choice .chat-emoticon {
	width: clamp(56px, 15vw, 64px);
	height: clamp(56px, 15vw, 64px);
}

.chat-emoticon-choice-name {
	font-size: 11px;
	color: var(--dk-text-secondary);
	text-align: center;
	line-height: 1.2;
}

/* ---------------------------------------------------------------- 1회 재생 연출

   전부 transform만 쓴다 — 행 높이·스크롤 위치·시간 표시가 움직이면 안 되기 때문이다.
   무한 반복·화면 흔들기·배경 점멸은 넣지 않는다(지시서 5절).
   prefers-reduced-motion에서는 아무 규칙도 켜지지 않아 정지 이미지가 그대로 최종 프레임이 된다.
   ---------------------------------------------------------------- */

@media (prefers-reduced-motion: no-preference) {

	/* 공통 등장 — 표정별 연출이 없어도 이건 한 번 재생된다. */
	.chat-emoticon--play {
		animation: emoticon-pop 200ms ease-out 1;
	}

	.chat-emoticon--play[data-anim="THUMBS_UP"] { animation: emoticon-thumbs-up 600ms ease-out 1; }
	.chat-emoticon--play[data-anim="SPARKLE"]   { animation: emoticon-sparkle 780ms ease-in-out 1; }
	.chat-emoticon--play[data-anim="JOY_TEARS"] { animation: emoticon-joy-tears 880ms ease-in-out 1; }
	.chat-emoticon--play[data-anim="HALO"]      { animation: emoticon-halo 820ms ease-in-out 1; }
	.chat-emoticon--play[data-anim="ANGRY"]     { animation: emoticon-angry 550ms ease-in-out 1; }
	.chat-emoticon--play[data-anim="SOB"]       { animation: emoticon-sob 950ms ease-in-out 1; }
}

@keyframes emoticon-pop {
	0%   { transform: scale(0.92); }
	60%  { transform: scale(1.03); }
	100% { transform: scale(1); }
}

/* 엄지척 — 한 번 작게 튕긴다. */
@keyframes emoticon-thumbs-up {
	0%   { transform: scale(0.94) translateY(2px); }
	35%  { transform: scale(1.06) translateY(-3px); }
	65%  { transform: scale(0.99) translateY(1px); }
	100% { transform: scale(1) translateY(0); }
}

/* 반짝 기대 — 몸이 살짝 기울었다 돌아온다. */
@keyframes emoticon-sparkle {
	0%   { transform: rotate(0deg) scale(0.95); }
	30%  { transform: rotate(-3deg) scale(1.04); }
	60%  { transform: rotate(2deg) scale(1.01); }
	100% { transform: rotate(0deg) scale(1); }
}

/* 기쁨의 눈물 — 어깨가 두 번 들썩인다. */
@keyframes emoticon-joy-tears {
	0%   { transform: translateY(0) scale(0.96); }
	25%  { transform: translateY(-3px) scale(1.03); }
	50%  { transform: translateY(0) scale(1); }
	75%  { transform: translateY(-2px) scale(1.02); }
	100% { transform: translateY(0) scale(1); }
}

/* 평온한 천사 — 한 번 부드럽게 떠올랐다 내려앉는다. */
@keyframes emoticon-halo {
	0%   { transform: translateY(3px) scale(0.97); }
	45%  { transform: translateY(-4px) scale(1.02); }
	100% { transform: translateY(0) scale(1); }
}

/* 발끈 — 좌우로 최대 2px 움찔한다(지시서 5절의 상한). */
@keyframes emoticon-angry {
	0%   { transform: translateX(0) scale(1); }
	20%  { transform: translateX(-2px) scale(1.04); }
	40%  { transform: translateX(2px) scale(1.04); }
	60%  { transform: translateX(-2px) scale(1.02); }
	80%  { transform: translateX(1px) scale(1.01); }
	100% { transform: translateX(0) scale(1); }
}

/* 서러운 울음 — 어깨가 두 번 작게 내려앉는다. */
@keyframes emoticon-sob {
	0%   { transform: translateY(-2px) scale(1); }
	20%  { transform: translateY(2px) scale(0.98); }
	45%  { transform: translateY(-1px) scale(1); }
	70%  { transform: translateY(2px) scale(0.98); }
	100% { transform: translateY(0) scale(1); }
}

/* ============================================================
   재화 "버드" 주화 (2026-09-13, ui_todo.md CUR-01)

   포인트의 사용자 표기를 문자 `P`가 아니라 깃털 금화로 바꾼다. 문자 배지는 뜻을 추측시키고,
   `20P`처럼 붙여 쓰면 숫자의 일부로도 읽힌다.

   자산은 96×96 RGBA(`bird-coin-v1-96.png`) 한 장이고 화면에서는 14~32px로만 쓴다 —
   글자·숫자·그림자를 굽지 않은 그림이라 크기와 그림자는 여기서 정한다.

   ⚠️ 주화만 홀로 놓지 않는다. 항상 숫자나 `버드` 문구와 한 묶음이어야 뜻이 전달된다
   (지시서 2절). 접근성 이름은 묶음(.bird-amount)이 갖고 그림은 alt=""로 비워 둔다 —
   안 그러면 "주화 1,250"처럼 두 번 읽힌다.
   ============================================================ */

:root {
	--dk-bird-coin: url(/images/icons/bird-coin-v1-96.png);
	/* 기존 포인트 배지(.point-award-badge)와 같은 금색 — 앱 전체에서 재화를 뜻하는 톤이다. */
	--dk-bird-gold: #f5a623;
}

.bird-coin {
	display: inline-block;
	/* 기본은 글자 크기를 따라간다 — 14/16/20/24px 문맥에 그대로 얹으면 비율이 맞는다. */
	width: 1em;
	height: 1em;
	/* 숫자의 가운데선에 맞춘다. baseline 정렬로 두면 주화가 글자보다 아래로 처진다. */
	vertical-align: -0.125em;
	flex: 0 0 auto;
}

/* 문맥이 글자 크기를 안 정해 주는 자리(HUD 배지 등)를 위한 고정 크기.
   권장 크기는 필드 HUD 14px, 일반 요약·가격 16px, 강조 잔액 20~24px, 최대 32px(지시서 2절). */
.bird-coin--hud { width: 14px; height: 14px; }
.bird-coin--md  { width: 16px; height: 16px; }
.bird-coin--lg  { width: 24px; height: 24px; }
.bird-coin--xl  { width: 32px; height: 32px; }

/* 주화와 숫자를 한 묶음으로 — 둘 사이가 줄바꿈으로 갈라지면 숫자만 남아 뜻을 잃는다. */
.bird-amount {
	display: inline-flex;
	align-items: center;
	gap: 4px;
	white-space: nowrap;
	/* 자릿수가 바뀌어도 숫자 폭이 흔들리지 않게 — 잔액은 자주 바뀐다. */
	font-variant-numeric: tabular-nums;
}

/* 지도 등록 버튼의 "+10" 배지 — 예전에는 '+10p'로 끝났다.
   xp-award-badge와 같은 방식이다: 그림은 배경으로, 숫자만 attr() 텍스트로. content에 url()과
   문자열을 섞는 방식은 브라우저 호환이 불확실하다. */
.point-award-badge::after {
	content: '+' attr(data-points);
	padding: 0 5px 0 19px;
	background:
		var(--dk-bird-coin) no-repeat 3px center / 13px 13px,
		linear-gradient(120deg,
			rgba(255, 255, 255, 0) 0%,
			rgba(255, 255, 255, 0) 15%,
			rgba(255, 255, 255, 0.67) 17%,
			rgba(255, 255, 255, 0.67) 27%,
			rgba(255, 255, 255, 0) 29%,
			rgba(255, 255, 255, 0) 42%,
			rgba(255, 255, 255, 0.67) 43%,
			rgba(255, 255, 255, 0.67) 45%,
			rgba(255, 255, 255, 0) 46%,
			rgba(255, 255, 255, 0) 100%),
		var(--dk-bird-gold);
}

/* 획득 연출에 뜨는 주화 — 글자와 함께 한 번만 작게 팝(160~240ms). */
.bird-coin--pop {
	animation: bird-coin-pop 200ms ease-out 1;
}

@keyframes bird-coin-pop {
	0%   { transform: scale(0.7); }
	60%  { transform: scale(1.12); }
	100% { transform: scale(1); }
}

/* 움직임을 줄이는 설정에서는 정지 상태가 최종 프레임이다(지시서 2절). */
@media (prefers-reduced-motion: reduce) {
	.bird-coin--pop { animation: none; }
}

/* 아직 지급하지 않는 가이드 항목 (2026-09-13, ui_todo.md CUR-01D).
   다른 카드와 같은 모양이면 "누르면 받는 것"으로 읽힌다 — 누를 수 없다는 걸 커서와 톤으로 알린다. */
.point-guide-card--upcoming {
	cursor: default;
	opacity: 0.72;
}

.point-guide-badge--upcoming {
	background: var(--dk-bg-surface-alt-2);
	color: var(--dk-text-secondary);
}

/* 필드 보물상자: 생성 원본 대신 96px 배포본을 56px 이하로만 표시한다. */
.field-item-chest-marker {
	display: block;
	width: 35px;
	height: 35px;
	object-fit: contain;
	filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.35));
}

.field-item-chest-opening {
	display: block;
	width: 56px;
	height: 56px;
	object-fit: contain;
	pointer-events: none;
	filter: drop-shadow(0 3px 4px rgba(35, 24, 18, 0.32));
}

/* ============================================================
   필드 보상 공개 카드 (2026-09-13, ui_todo.md FIELD-01 3절)

   상자가 열리는 순간 무엇을 얼마나 받았는지 글자로 남긴다. 캐릭터 말풍선 대사는 캐릭터마다
   달라서 아이템 이름이 안 나올 수 있고, 등급은 대사에 아예 없다.

   ⚠️ 희귀도를 색만으로 전하지 않는다 — 등급 이름(일반/고급/희귀/영웅)을 항상 글자로 같이
   띄우고, 색은 거기에 얹는 보조 신호다.
   ============================================================ */

.field-reward-card-host {
	position: fixed;
	/* 지도 중앙보다 살짝 아래 — 상자 마커와 겹치지 않게 둔다. */
	left: 50%;
	bottom: calc(96px + env(safe-area-inset-bottom));
	transform: translateX(-50%);
	z-index: 9998;
	pointer-events: none;
}

.field-reward-card {
	display: flex;
	align-items: center;
	gap: 10px;
	max-width: min(88vw, 320px);
	padding: 10px 14px;
	border-radius: 14px;
	background: var(--dk-bg-surface);
	border: 1px solid var(--dk-border);
	box-shadow: 0 6px 20px rgba(0, 0, 0, 0.18);
}

.field-reward-icon {
	width: 40px;
	height: 40px;
	flex: 0 0 auto;
	object-fit: contain;
}

.field-reward-body {
	display: flex;
	align-items: baseline;
	gap: 6px;
	min-width: 0;
	flex-wrap: wrap;
}

.field-reward-rarity {
	flex: 0 0 auto;
	padding: 2px 7px;
	border-radius: 8px;
	font-size: 11px;
	font-weight: bold;
	/* 기본은 일반 등급 톤 — 아래에서 등급별로 덮는다. */
	background: var(--dk-bg-surface-alt-2);
	color: var(--dk-text-secondary);
}

.field-reward-rarity--uncommon { background: #dcfce7; color: #166534; }
.field-reward-rarity--rare     { background: #dbeafe; color: #1e40af; }
.field-reward-rarity--epic     { background: #f3e8ff; color: #6b21a8; }

.field-reward-name {
	min-width: 0;
	font-size: 15px;
	font-weight: bold;
	color: var(--dk-text-primary);
	overflow-wrap: anywhere;
}

.field-reward-quantity {
	flex: 0 0 auto;
	font-size: 14px;
	font-weight: bold;
	color: var(--dk-text-secondary);
	font-variant-numeric: tabular-nums;
}

/* 어두운 테마에서는 등급 배경을 낮추고 글자를 밝게 — 밝은 파스텔 위 진한 글자를 그대로 두면
   주변 카드보다 과하게 튄다. */
@media (prefers-color-scheme: dark) {
	:root:not([data-theme="light"]) .field-reward-rarity--uncommon { background: #14532d; color: #bbf7d0; }
	:root:not([data-theme="light"]) .field-reward-rarity--rare     { background: #1e3a8a; color: #bfdbfe; }
	:root:not([data-theme="light"]) .field-reward-rarity--epic     { background: #4c1d95; color: #e9d5ff; }
}

:root[data-theme="dark"] .field-reward-rarity--uncommon { background: #14532d; color: #bbf7d0; }
:root[data-theme="dark"] .field-reward-rarity--rare     { background: #1e3a8a; color: #bfdbfe; }
:root[data-theme="dark"] .field-reward-rarity--epic     { background: #4c1d95; color: #e9d5ff; }

/* 내 현장정보 활동 요약 (2026-09-13, MAP-01-F3 / 재설계안 5장)
 * 네 칸 — 320px에서도 두 줄로 접히고 가로로 넘치지 않는다. */
.contribution-activity {
	display: grid;
	grid-template-columns: repeat(2, 1fr);
	gap: 8px;
	margin-bottom: 12px;
}

.contribution-activity:empty {
	display: none;
	margin: 0;
}

.contribution-activity-cell {
	display: flex;
	flex-direction: column;
	gap: 2px;
	padding: 10px 12px;
	border: 1px solid var(--dk-border);
	border-radius: 12px;
	background: var(--dk-bg-surface);
}

.contribution-activity-value {
	font-size: 16px;
	font-weight: 700;
	color: var(--dk-text-primary);
	/* 숫자가 자리를 지켜야 네 칸이 들쭉날쭉해 보이지 않는다. */
	font-variant-numeric: tabular-nums;
}

.contribution-activity-label {
	font-size: 12px;
	color: var(--dk-text-secondary);
}

/* 현장정보 진입 버튼 (2026-09-13, field_contribution_redesign.md 4.1)
 * "필드에 고정된 `+ 현장정보` 버튼을 둔다."
 *
 * 내 위치 버튼 바로 위에 같은 모양으로 쌓는다 — 오른쪽 아래는 이미 라이더가 엄지로 닿는 자리다.
 * 색을 채워 두는 이유: 이건 "이동"이 아니라 **이 화면의 주된 행동**이라, 다른 원형 버튼들과
 * 같은 비중으로 보이면 안 된다. */
.field-contribution-fab {
	position: absolute;
	right: 14px;
	bottom: 104px;
	z-index: 150;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 1px;
	width: 52px;
	height: 52px;
	padding: 0;
	border: none;
	border-radius: 50%;
	background: #1957D6;
	color: #ffffff;
	box-shadow: 0 2px 8px rgba(25, 87, 214, 0.35);
	cursor: pointer;
	-webkit-tap-highlight-color: transparent;
}

.field-contribution-fab:active {
	transform: scale(0.94);
}

.field-contribution-fab-label {
	font-size: 9px;
	font-weight: 800;
	line-height: 1;
	letter-spacing: -0.3px;
	color: #ffffff;
}

body.is-desktop-view .field-contribution-fab {
	bottom: 108px;
}

/* 시트가 열린 동안에는 진입 버튼을 숨긴다 — 시트 위에 떠 있으면 "또 열라"는 뜻으로 읽힌다. */
body.fc-sheet-open .field-contribution-fab {
	display: none;
}

/* "장소 변경"을 눌러 지도에서 위치를 고르는 동안 — 지금 무엇을 기다리는지 커서로도 알린다. */
body.fc-picking-place .app-map {
	cursor: crosshair;
}
