/* 360 투어 뷰어 스타일 */

/* ---------------------------------------------------------- 기본 폰트
   Noto Sans KR (SIL Open Font License) 를 프로젝트에 포함해 쓴다.
   외부 CDN 을 부르지 않으므로 내보낸 폴더만으로 오프라인에서도 같은 화면이 나온다.
   fonts/noto-sans-kr-LICENSE.txt 참고. */
@font-face {
	font-family: 'Noto Sans KR'; font-style: normal; font-weight: 400; font-display: swap;
	src: url(fonts/noto-sans-kr-latin-400-normal.woff2) format('woff2');
	unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
		U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191,
		U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
	font-family: 'Noto Sans KR'; font-style: normal; font-weight: 700; font-display: swap;
	src: url(fonts/noto-sans-kr-latin-700-normal.woff2) format('woff2');
	unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
		U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191,
		U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
	font-family: 'Noto Sans KR'; font-style: normal; font-weight: 400; font-display: swap;
	src: url(fonts/noto-sans-kr-korean-400-normal.woff2) format('woff2');
	unicode-range: U+1100-11FF, U+3001-3003, U+3008-3011, U+3013-301F, U+302E-3030,
		U+3131-318E, U+3200-321E, U+3260-327E, U+A960-A97F, U+AC00-D7A3, U+D7B0-D7FF,
		U+FF01-FF60, U+FFE0-FFE6;
}
@font-face {
	font-family: 'Noto Sans KR'; font-style: normal; font-weight: 700; font-display: swap;
	src: url(fonts/noto-sans-kr-korean-700-normal.woff2) format('woff2');
	unicode-range: U+1100-11FF, U+3001-3003, U+3008-3011, U+3013-301F, U+302E-3030,
		U+3131-318E, U+3200-321E, U+3260-327E, U+A960-A97F, U+AC00-D7A3, U+D7B0-D7FF,
		U+FF01-FF60, U+FFE0-FFE6;
}

:root {
	/* **움직임 곡선 한 곳.** 「점점 빠르게 → 점점 느리게」(easeInOut).
	   슬라이드·전환·화면 이동이 모두 같은 느낌이어야 한 프로그램처럼 읽힌다.
	   `viewer/js/controls.js` 의 `glideTo()` 도 같은 모양의 식을 쓴다. */
	--ease: cubic-bezier(0.65, 0, 0.35, 1);
	--accent: #7cc4ff;
	--panel: rgba(16, 18, 22, 0.82);
	--edge: rgba(255, 255, 255, 0.12);
	--text: #eef1f5;
	--dim: rgba(238, 241, 245, 0.62);
	--radius: 12px;
	--shadow: 0 8px 30px rgba(0, 0, 0, 0.45);
}

* { box-sizing: border-box; }
/* hidden 인데도 자리를 차지하면 빈 띠가 생긴다(로고를 숨겨도 margin 이 남던 문제).
   스튜디오 CSS 에는 있던 규칙인데 뷰어에는 빠져 있었다. */
[hidden] { display: none !important; }

html, body {
	margin: 0; padding: 0; width: 100%; height: 100%;
	overflow: hidden; background: #0e1013; color: var(--text);
	font: 14px/1.45 'Noto Sans KR', -apple-system, BlinkMacSystemFont,
		"Apple SD Gothic Neo", "Malgun Gothic", "Segoe UI", sans-serif;
	-webkit-font-smoothing: antialiased;
	overscroll-behavior: none;
}

/* 사진 빼가기 막기 — 끌어 내리기, 길게 눌러 저장, 글자 잡히는 것까지 끊는다.
   (viewer.js 의 contextmenu·dragstart 막기와 한 벌이다) */
#stage canvas, #ui img, #ui .tv-thumb, #ui .tv-menu-item {
	-webkit-user-drag: none; -webkit-touch-callout: none;
	user-select: none; -webkit-user-select: none;
}

#stage { position: fixed; inset: 0; z-index: 1; }
/* 캔버스가 영상 층보다 **위**여야 한다 — 그 위에 그린 핫스팟·사진이 영상을 덮는다 */
#stage canvas {
	display: block; width: 100%; height: 100%; touch-action: none; cursor: grab;
	position: relative; z-index: 1;
}
#stage canvas:active { cursor: grabbing; }

/*
 * 벽에 붙인 유튜브·비메오. **캔버스 뒤**에 둔다(z-index 0).
 * 파노라마는 캔버스에서 그 자리를 투명하게 지우고(shapes.js 의 「구멍」),
 * 그 구멍으로 이 층이 보인다. 그래서 **핫스팟도 겹쳐 놓은 사진도 영상을 덮는다** —
 * 3DVista 와 같은 순서다.
 */
.tv-embeds { position: fixed; inset: 0; z-index: 0; pointer-events: none; overflow: hidden; }
.tv-embed {
	position: absolute; left: 0; top: 0;
	transform-origin: 0 0; pointer-events: auto; will-change: transform;
	background: #000;
}
.tv-embed iframe { width: 100%; height: 100%; border: 0; display: block; }
.tv-embed.noclick { pointer-events: none; }

#ui { position: fixed; inset: 0; z-index: 2; pointer-events: none; }
#ui > * { pointer-events: auto; }
/* 투어 데이터가 오기 전 — 시작 화면과 안내만 남기고 감춘다 */
#ui.booting > *:not(.tv-splash):not(.tv-loading) { visibility: hidden; }

body.in-vr #ui { display: none; }

/* ------------------------------------------------------------- 타이틀 */
.tv-title {
	position: absolute; top: 0; left: 0; right: 0; padding: 18px 22px 34px;
	font-size: 17px; font-weight: 600; letter-spacing: -0.01em;
	/* 어두운 그라데이션 없이 글자 그림자만으로 읽힌다 (메뉴 옆에 검은 띠가 지지 않게) */
	text-shadow: 0 1px 3px rgba(0, 0, 0, 0.55), 0 2px 14px rgba(0, 0, 0, 0.8);
	background: none;
	pointer-events: none;
}

/* -------------------------------------------------------------- 로딩 */
.tv-loading {
	position: absolute; inset: 0; display: none;
	flex-direction: column; align-items: center; justify-content: center;
	gap: 14px; background: rgba(10, 12, 15, 0.55); backdrop-filter: blur(3px);
	color: var(--dim); font-size: 13px; pointer-events: none;
}
.tv-loading.on { display: flex; }
.tv-spinner {
	width: 34px; height: 34px; border-radius: 50%;
	border: 2.5px solid rgba(255, 255, 255, 0.16);
	border-top-color: var(--accent); animation: tv-spin 0.85s linear infinite;
}
@keyframes tv-spin { to { transform: rotate(360deg); } }

/* 장면을 넘길 때의 기다림 링 — **화면 한가운데.**
   krpano 로더처럼 조용히 돌면서 실제 타일 로딩만큼 채워진다.
   판을 깔지 않으므로 옛 장면이 그대로 보인다. */
/* **화면 전체를 덮는 판이라 클릭을 먹으면 안 된다.**
   `#ui > *` 가 pointer-events:auto 를 걸어 두므로 그보다 센 선택자로 눌러야 하고,
   안 보일 때는 아예 `display:none` 으로 빼 둔다 — 실제로 이걸 안 해서
   미리보기의 버튼이 전부 안 눌렸다. */
#ui > .tv-spin {
	position: absolute; inset: 0; z-index: 6; pointer-events: none;
	/* **`display:none` 이 아니라 `visibility`** — 감춰 두어도 회전 애니메이션이
	   계속 돌기 때문이다. 그래야 뜰 때 「이미 돌고 있던 것이 배어 나오는」 것처럼
	   보인다. `display:none` 이면 뜰 때마다 12시부터 다시 돌기 시작해 툭 튄다.
	   (클릭은 `pointer-events:none` 과 `visibility:hidden` 둘 다로 막힌다) */
	display: grid; place-items: center;
	visibility: hidden; opacity: 0;
	transition: opacity 0.55s ease, visibility 0s linear 0.55s;
}
/* **여리게.** 새 장면이 흐릿한 동안 위에 얹히는 것이라, 또렷하면 시선을 뺏는다.
   나타날 때는 0.8초에 걸쳐 서서히 배어 나온다. */
#ui > .tv-spin.on {
	visibility: visible; opacity: 0.5;
	transition: opacity 0.8s ease, visibility 0s;
}
#ui > .tv-spin svg {
	width: 44px; height: 44px; display: block;
	/* 12시에서 시작해 시계 방향으로 차고, 판 전체가 천천히 돈다 */
	transform: rotate(-90deg);
	animation: tv-spin-turn 2.6s linear infinite;
	/* **선을 번지게 한다.** 또렷한 선은 사진 위에서 도형처럼 튀는데,
	   살짝 흩어 놓으면 「빛이 도는」 느낌이라 덜 거슬린다.
	   blur 로 가장자리를 풀고, 대표색 글로우를 얹어 색이 배어 나오게 한다. */
	filter: blur(1.8px)
		drop-shadow(0 0 12px var(--accent-fill, var(--accent)))
		drop-shadow(0 0 22px var(--accent-fill, var(--accent)))
		drop-shadow(0 1px 3px rgba(0, 0, 0, 0.18));
}

@keyframes tv-spin-turn { to { transform: rotate(270deg); } }
.tv-spin circle { fill: none; }
/* 꼬리(s1) → 머리(s3). 굵기와 진하기를 함께 키워 **가늘어지는 호**로 보이게 한다 */
.tv-spin-arc.s1 { stroke-width: 1.1; opacity: 0.4; }
.tv-spin-arc.s2 { stroke-width: 2.2; opacity: 0.72; }
.tv-spin-arc.s3 { stroke-width: 3.4; opacity: 1; stroke-linecap: round; }
.tv-spin-arc {
	stroke: var(--accent-fill, var(--accent));
	stroke-dasharray: 0 125.66;            /* 2π × r20 — ui.js 의 SPIN_LEN 과 같은 값 */
	stroke-dashoffset: 0;
	transition: stroke-dasharray 0.35s var(--ease),
		stroke-dashoffset 0.35s var(--ease);
}

/* --------------------------------------------------- 첫 로딩(시작) 화면 */
.tv-splash {
	position: absolute; inset: 0; z-index: 5; display: grid; place-items: center;
	padding: 32px; opacity: 1; transition: opacity 0.45s ease;
}
.tv-splash.out { opacity: 0; pointer-events: none; }
.tv-splash-box {
	display: flex; flex-direction: column; align-items: center; gap: 18px;
	width: min(420px, 66vw);
}
.tv-splash-box { width: min(1100px, 86vw); }
.tv-splash-logo {
	width: 34%; max-width: 100%; max-height: 46vh; height: auto; object-fit: contain;
	animation: tv-fadein 0.6s ease both;
}
.tv-splash-title {
	font-weight: 700; letter-spacing: -0.01em; text-align: center; line-height: 1.25;
	animation: tv-fadein 0.7s ease both;
}
.tv-splash-sub {
	font-weight: 400; text-align: center; line-height: 1.4; opacity: 0.72;
	animation: tv-fadein 0.9s ease both;
}
.tv-splash-bar { max-width: 420px; }
.tv-splash-bar {
	width: 100%; height: 3px; border-radius: 2px;
	background: rgba(255, 255, 255, 0.18); overflow: hidden;
}
.tv-splash-bar i {
	display: block; width: 0; height: 100%; background: var(--accent);
	transition: width 0.25s ease;
}
.tv-splash-pct {
	font-size: 11px; letter-spacing: 0.06em; color: rgba(255, 255, 255, 0.55);
	font-variant-numeric: tabular-nums; opacity: 0.7;
}
/* 편집기 미리보기용 안내 */
.tv-splash.preview { cursor: pointer; }
.tv-splash-note {
	position: absolute; left: 50%; bottom: 22px; transform: translateX(-50%);
	padding: 6px 14px; border-radius: 999px; font-size: 12px;
	background: rgba(0, 0, 0, 0.42); color: rgba(255, 255, 255, 0.8);
	border: 1px solid rgba(255, 255, 255, 0.18);
}
@keyframes tv-fadein { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; } }

.tv-fatal {
	position: absolute; inset: 0; display: flex; align-items: center;
	justify-content: center; color: #ff9b9b; font-size: 14px; padding: 24px;
	text-align: center;
}

/* ------------------------------------------- 화면 아래 묶음 (썸네일 + 바) */
/* 썸네일이 위, 컨트롤 바가 아래. 높이를 px 로 박지 않고 세로로 쌓기만 하므로
   썸네일 크기가 해상도에 따라 바뀌어도 둘이 겹치지 않는다. */
#ui .tv-dock {
	position: absolute; left: 0; right: 0; bottom: 0; z-index: 3;
	display: flex; flex-direction: column; align-items: center; gap: 6px;
	padding: 0 0 max(9px, env(safe-area-inset-bottom));
	pointer-events: none;   /* 빈 곳은 파노라마 드래그가 통과해야 한다 */
	background: none;       /* 어두운 그라데이션 없이 파노라마 위에 그대로 얹는다 */
}
.tv-dock > * { pointer-events: auto; }

/* ------------------------------------------------------------ 컨트롤 바 */
/* 컨트롤 바 숨기기(`settings.barHidden`) — 「⋯」 까지 통째로 */
.tv-bar.off { display: none !important; }
.tv-bar {
	display: flex; align-items: center; gap: 1px; padding: 3px;
	background: var(--panel); border: 1px solid var(--edge);
	border-radius: 999px;
	backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
	/* 메뉴가 차지한 폭을 빼야 바가 화면 밖으로 밀려 잘리지 않는다 */
	max-width: calc(100vw - 24px - var(--menu-left, 0px) - var(--menu-right, 0px));
	overflow-x: auto; scrollbar-width: none;
	flex: 0 0 auto;
}
.tv-bar::-webkit-scrollbar { display: none; }

/* ── 컨트롤 바 자리: 가운데 아래(가로) · 왼쪽/오른쪽 아래(세로) ────────────
   세로로 세울 때는 ui.js 가 바를 아래 묶음(dock) 밖으로 빼낸다. 그래야 dock 의
   세로 흐름에 끼지 않고 모서리에 붙는다.
   **아래에 붙이고 위로 자란다** — 그래야 펴질 때 마지막 버튼 자리가 안 움직인다.
   썸네일 바(--dock-h)와 메뉴(--menu-*)가 차지한 만큼 비켜난다. */
#ui .tv-bar.pos-left, #ui .tv-bar.pos-right {
	position: absolute; z-index: 3; pointer-events: auto;
	top: auto; transform: none;
	bottom: calc(8px + var(--dock-h, 0px) + var(--menu-bottom, 0px));
	max-width: none; max-height: calc(100vh - 140px);
	overflow-x: visible; overflow-y: auto;
	transition: left 0.34s var(--ease),
		right 0.34s var(--ease),
		bottom 0.34s var(--ease);
}
#ui .tv-bar.pos-left { left: calc(12px + var(--menu-left, 0px)); }
#ui .tv-bar.pos-right { right: calc(12px + var(--menu-right, 0px)); }
.tv-bar.vertical { flex-direction: column; }
.tv-bar.vertical .tv-sep { width: 17px; height: 1px; margin: 3px 0; }

/* ── 접었다 펴기 ────────────────────────────────────────────────────────
   평소에는 「남길 버튼」 + 「⋯」 만 보이고, **⋯ 를 누르면** 나머지가 원래 자리로
   끼어들며 펴진다. 버튼 순서는 그대로라 늘 같은 자리에서 찾을 수 있다.
   마우스를 올리는 것만으로는 펴지지 않는다 — 화면을 보다 스치기만 해도 펴지면
   거슬리고, 터치 기기에서는 아예 되지도 않는다. 바 밖을 누르면 도로 접힌다.

   **`:focus-within` 을 쓰면 안 된다.** 마우스로 버튼을 눌러도 포커스가 들어가므로,
   남겨 둔 버튼(평면도 등)을 한 번 누를 때마다 숨겨 둔 나머지가 펴져 버린다.
   키보드로 들어오는 길은 `ui.js` 가 tabIndex 로 막고 「⋯」 만 남겨 해결한다. */
.tv-bar-more { order: 99; }                 /* 가로 배치에서는 맨 오른쪽 */
.tv-bar:not(.collapsed) .tv-bar-more { display: none; }
.tv-bar.vertical .tv-bar-more svg { transform: rotate(90deg); }
/* 세로 배치는 **맨 위**. 바가 아래에 붙어 위로 자라므로, 「⋯」 가 위에 있어야
   어느 쪽으로 펴지는지를 그 버튼이 가리킨다. 남긴 버튼은 아래 끝에 그대로 붙어
   있고 「⋯」 만 펴진 높이만큼 따라 올라간다. */
.tv-bar.vertical .tv-bar-more { order: -1; }
.tv-btn, .tv-sep {
	transition: background 0.15s, color 0.15s, transform 0.16s,
		width 0.3s var(--ease),
		height 0.3s var(--ease),
		margin 0.3s var(--ease),
		opacity 0.22s;
}
.tv-bar.collapsed:not(.open) .tv-btn:not(.pinned),
.tv-bar.collapsed:not(.open) .tv-sep {
	margin: 0; padding: 0; border: 0;
	opacity: 0; transform: scale(0.6); overflow: hidden; pointer-events: none;
}
/* 가로 배치는 폭을, 세로 배치는 높이를 접는다.
   `:not(.vertical)` 로 갈라 둬야 한쪽 값이 다른 쪽에 남아 붙지 않는다. */
.tv-bar.collapsed:not(.vertical):not(.open) .tv-btn:not(.pinned),
.tv-bar.collapsed:not(.vertical):not(.open) .tv-sep {
	width: 0; min-width: 0;
}
.tv-bar.collapsed.vertical:not(.open) .tv-btn:not(.pinned),
.tv-bar.collapsed.vertical:not(.open) .tv-sep {
	height: 0; min-height: 0;
}
/* 「⋯」 는 펴져 있는 동안 눌린 상태로 보인다 (다시 누르면 접힌다) */
.tv-bar-more.on { color: var(--on-fill, #0b0d10); background: var(--accent-fill, var(--accent)); }

.tv-btn {
	/* padding 0 이 **중요하다.** 버튼의 브라우저 기본 padding(1px 6px)이 남아 있으면
	   안쪽 상자가 좁아지고, 그보다 큰 SVG 는 가운데 정렬이 안 먹어 한쪽으로 밀린다
	   (평면도 닫기 X: 28px 버튼 안쪽 16px 에 21px 그림 -> 2.5px 오른쪽으로 밀렸다). */
	flex: 0 0 auto; width: 33px; height: 33px; display: grid; place-items: center;
	padding: 0; border: 0; border-radius: 50%; background: transparent; color: var(--text);
	cursor: pointer; transition: background 0.15s, color 0.15s, transform 0.12s;
}
.tv-btn svg { width: 18px; height: 18px; }
.tv-btn:hover { background: rgba(255, 255, 255, 0.12); }
/* 썸네일 좌우 화살표는 transform 을 세로 중앙 정렬에 쓰므로 제외한다.
   여기서 scale() 만 걸면 정렬이 날아가 버튼이 아래로 떨어진다. */
.tv-btn:active:not(.tv-thumbs-nav) { transform: scale(0.93); }
/* 켜진 버튼 — **대표색으로 꽉 채운다.** 옅은 틴트는 켜졌는지 알아보기 어렵다.
   색은 대표색에서 뽑아 쓰므로(`_applyAccent`) 대표색을 어둡게 잡아도
   어두운 바 위에서 사라지지 않는다. */
.tv-btn.on { color: var(--on-fill, #0b0d10); background: var(--accent-fill, var(--accent)); }
.tv-sep { width: 1px; height: 17px; margin: 0 3px; background: var(--edge); flex: 0 0 auto; }

/* -------------------------------------------------------------- 썸네일 */
.tv-thumbs {
	position: relative; width: 100%; padding: 0 12px; box-sizing: border-box;
	/* 접힘/펼침은 높이로 처리한다. 위치를 옮기지 않으므로 바를 밀어낼 일이 없다. */
	max-height: 0; opacity: 0; overflow: hidden; pointer-events: none;
	transform: translateY(10px);
	transition: max-height 0.3s var(--ease),
		opacity 0.22s linear, transform 0.3s var(--ease);
}
.tv-thumbs.open {
	max-height: 40vh; opacity: 1; transform: none; pointer-events: auto;
}
.tv-thumbs-inner {
	display: flex; gap: 8px; overflow-x: auto; padding: 4px 0;
	scrollbar-width: none; scroll-behavior: smooth;
	/* 잡아끌기: 가로 제스처는 우리가 쓰고 세로는 페이지에 넘긴다 */
	touch-action: pan-y; cursor: grab;
}
/* 데스크톱에서 한 화면에 다 들어오면 썸네일 묶음 자체를 화면 정중앙에 둔다.
   장면이 많아 넘치거나 모바일일 때는 왼쪽부터 훑도록 기존 정렬을 유지한다. */
@media (min-width: 601px) {
	.tv-thumbs:not(.scrollable) .tv-thumbs-inner { justify-content: center; }
}
.tv-thumbs-inner::-webkit-scrollbar { display: none; }
.tv-thumbs-inner.dragging {
	cursor: grabbing; scroll-behavior: auto; scroll-snap-type: none;
}
/* 끌고 있는 동안에는 썸네일이 눌린 것처럼 보이지 않게 */
.tv-thumbs-inner.dragging .tv-thumb { transform: none; }
.tv-thumbs-inner.dragging img { pointer-events: none; }

/* 좌우 화살표 — 넘칠 때만 보인다 */
/* transform 은 세로 중앙 정렬(-50%)에 이미 쓰이므로, 눌림 효과는 배율 변수만
   바꾼다. .tv-btn:active 의 scale() 을 그대로 두면 중앙 정렬이 날아가 버튼이
   아래로 뚝 떨어진다. */
.tv-thumbs-nav {
	position: absolute; top: 50%; z-index: 1;
	transform: translateY(-50%) scale(var(--nav-scale, 1));
	width: 34px; height: 52px; display: none; place-items: center;
	border: 1px solid var(--edge); border-radius: 10px; padding: 0;
	background: rgba(14, 16, 20, 0.82); color: var(--text); cursor: pointer;
	backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
	transition: opacity 0.12s, background 0.12s, color 0.12s,
		border-color 0.12s, transform 0.12s;
}
.tv-thumbs-nav svg { width: 19px; height: 19px; }
.tv-thumbs-nav.left { left: 4px; }
.tv-thumbs-nav.right { right: 4px; }
.tv-thumbs.scrollable .tv-thumbs-nav { display: grid; }
.tv-thumbs-nav:hover { --nav-scale: 1.06; background: rgba(28, 32, 38, 0.92); }
/* 누르면 강조색으로 바뀌며 살짝 커진다 */
.tv-thumbs-nav:active,
.tv-thumbs-nav.pressed {
	--nav-scale: 1.14;
	/* transform 을 여기서 다시 명시한다. 변수만 바꾸면 다른 :active 규칙이
	   transform 자체를 덮어썼을 때 세로 정렬을 잃는다. */
	transform: translateY(-50%) scale(1.14);
	background: var(--accent); border-color: var(--accent); color: var(--on-accent, #0b0d10);
	transition-duration: 0.06s;
}
.tv-thumbs-nav:disabled { opacity: 0; pointer-events: none; }

/* 화살표에 가려 썸네일이 잘려 보이지 않도록 양끝에 여백을 준다 */
.tv-thumbs.scrollable .tv-thumbs-inner { padding-left: 36px; padding-right: 36px; }

.tv-thumb {
	flex: 0 0 auto; width: 124px; padding: 0; border: 2px solid transparent;
	border-radius: 9px; overflow: hidden; background: #14171c; cursor: pointer;
	color: var(--dim); font: inherit; font-size: 11px; text-align: center;
	transition: border-color 0.15s, transform 0.15s, color 0.15s;
}
.tv-thumb img { display: block; width: 100%; height: 78px; object-fit: cover; }
.tv-thumb span {
	display: block; padding: 5px 7px 6px; white-space: nowrap;
	overflow: hidden; text-overflow: ellipsis;
}
.tv-thumb:hover { transform: translateY(-2px); color: var(--text); }
.tv-thumb.on { border-color: var(--accent-ink, var(--accent)); color: var(--text); }

/* ------------------------------------------------------------- 나침반 */
/* 별(또는 바늘)이 돌고 **북쪽 표시가 늘 진짜 북쪽**을 가리킨다.
   장면마다의 북방향(northOffset)을 그대로 쓰므로 새로 넣을 값이 없다.
   그림은 SVG 라 크게 키워도 안 깨지고, 모양은 settings.compass.style 이 고른다. */
.tv-compass {
	position: absolute; z-index: 3;
	width: var(--c-size, 64px); height: var(--c-size, 64px);
	margin: calc(var(--head-h, 0px) + var(--menu-top, 0px)) var(--menu-right, 0) var(--menu-bottom, 0) var(--menu-left, 0);
}
/* 3x3 자리 — 미니맵과 같은 규칙 */
/* **N 이 원 밖 위에 서는 모양(시야)** 은 그만큼(지름의 ¼) 더 내려야 위 띠에 안 먹힌다
   (양주 10/1 — N 윗변이 띠 아랫변과 딱 붙거나 5px 겹쳤다). 다른 모양은 N 이 원 안이라 0. */
.tv-compass { --c-over: 0px; }
.tv-compass.sty-view:not(.no-n) { --c-over: calc(var(--c-size, 64px) * 0.25); }
.tv-compass.at-tl, .tv-compass.at-tc, .tv-compass.at-tr { top: calc(var(--c-my, 16px) + var(--c-over)); }
.tv-compass.at-ml, .tv-compass.at-mc, .tv-compass.at-mr { top: 50%; transform: translateY(-50%); }
.tv-compass.at-bl, .tv-compass.at-bc, .tv-compass.at-br {
	bottom: calc(var(--c-my, 16px) + var(--dock-h, 0px));
}
.tv-compass.at-tl, .tv-compass.at-ml, .tv-compass.at-bl { left: var(--c-mx, 16px); }
.tv-compass.at-tr, .tv-compass.at-mr, .tv-compass.at-br { right: var(--c-mx, 16px); }

/* **자유 위치 — 「비례 기준점」이다.**
 *
 * 0 이면 왼쪽(위) 끝에 딱 붙고, 50 이면 가운데, 100 이면 오른쪽(아래) 끝에 붙는다.
 * 자기 크기만큼 되밀기 때문에(`translate(-100% × n)`) **9칸 앵커와 정확히 같은 줄**
 * 에 선다 — 여백도 그대로 지킨다.
 *
 * 예전에는 「칸 한가운데의 백분율 + translate(-50%,-50%)」였는데, 그러면 맨 윗줄에
 * 놓아도 중심이 화면 10% 지점까지 내려와 **앵커로 놓은 것과 높이가 어긋났다**
 * (「1·3·5열은 붙는데 2·4열은 떠 있다」). 값은 0~100 의 **단위 없는 수**다. */
.tv-compass.at-free, .tv-cats.at-free, .tv-vars.at-free, .tv-title.anchored.at-free {
	--n-x: calc(var(--free-x, 50) / 100);
	--n-y: calc(var(--free-y, 50) / 100);
	right: auto; bottom: auto; margin: 0;
	left: calc(var(--fm-x, 16px) + (100% - 2 * var(--fm-x, 16px)) * var(--n-x));
	/* **고지문 띠 위까지만.** 아래 묶음은 떠 있는 것이라 자유 배치가 그 위에 겹쳐도
	   되지만, 고지문은 **화면 바닥에 못 박힌 띠**라 그 위에 앉으면 글자를 덮는다.
	   놓을 수 있는 높이에서 띠 높이를 뺀다 — y 100 이 띠 **바로 위**가 된다. */
	top: calc(var(--fm-y, 16px)
		+ (100% - 2 * var(--fm-y, 16px) - var(--legal-h, 0px)) * var(--n-y));
	transform: translate(calc(-100% * var(--n-x)), calc(-100% * var(--n-y)));
}
.tv-compass.at-free {
	--free-x: var(--c-x, 50); --free-y: var(--c-y, 50);
	--fm-x: var(--c-mx, 16px); --fm-y: var(--c-my, 16px);
	/* **위 띠 아래로만.** 자유 위치는 화면 세로의 % 라, 화면이 낮으면(윈도우 125% 세로 ~740)
	   같은 y 가 띠 쪽으로 올라가 N 이 띠에 먹혔다 — 띠 높이는 px 로 그대로이기 때문.
	   자리는 예전 계산 그대로 두고, **띠 + N 몫보다 위로는 못 올라가게만** 막는다
	   (translate 가 끌어올리는 몫 `지름 × y` 를 더해 둔다). 띠가 없으면 --head-h 가 0 이다. */
	top: max(calc(var(--fm-y, 16px)
			+ (100% - 2 * var(--fm-y, 16px) - var(--legal-h, 0px)) * var(--n-y)),
		calc(var(--head-h, 0px) + var(--menu-top, 0px) + var(--c-over) + 8px
			+ var(--c-size, 64px) * var(--n-y)));
}
/* **고지문 띠 오른쪽에 걸터앉기.** 조감 투어 레퍼런스가 그렇다 — 화면 오른쪽
   아래, 「오리발」 띠의 끝에 나침반이 얹힌다. 9칸 자리·자유 위치를 **덮어쓰므로**
   그 규칙들보다 뒤에 둔다.
   띠 한가운데에 맞추되, 나침반이 띠보다 크면 바닥에 붙이고 **위로 넘치게** 둔다
   (레퍼런스가 그 모양이다). 좌우는 「여백 ↔」이 그대로 정하고, 세로 메뉴가
   오른쪽에 있으면 그만큼 비켜난다. */
.tv-compass.on-legal {
	/* **띠보다 커지지 않는다.** 폰에서는 고지문 글자·여백이 줄어 띠가 얇아지므로
	   나침반도 같이 줄어야 한다 — 안 그러면 띠 위아래로 삐져나온다.
	   상한(`--legal-fit`)은 띠를 실제로 재는 `_measureDock()` 이 알려 준다
	   (띠가 없으면 999px = 상한 없음). */
	--c-real: min(var(--c-size, 64px), var(--legal-fit, 999px));
	width: var(--c-real); height: var(--c-real);
	top: auto; left: auto; margin: 0; transform: none; z-index: 4;
	right: calc(var(--menu-right, 0px) + var(--c-mx, 16px));
	bottom: max(0px, calc((var(--legal-h, 0px) - var(--c-real)) / 2));
}
.tv-cats.at-free, .tv-vars.at-free {
	--free-x: var(--v-x, 50); --free-y: var(--v-y, 50);
	--fm-x: var(--v-mx, 16px); --fm-y: var(--v-my, 16px);
}
.tv-title.anchored.at-free {
	--free-x: var(--t-x, 50); --free-y: var(--t-y, 50);
	--fm-x: var(--t-mx, 16px); --fm-y: var(--t-my, 16px);
}

/* **투어 제목 자리.** 안 정해 두면 예전 그대로 위쪽 전체 폭이다(`anchored` 없음).
   자리를 정하면 글자 크기만큼만 차지하고 그 자리로 간다. */
.tv-title.anchored {
	right: auto; bottom: auto; width: max-content; max-width: 72%;
	padding: 10px 14px; margin: 0;
}
.tv-title.anchored.at-tl, .tv-title.anchored.at-tc, .tv-title.anchored.at-tr { top: var(--t-my, 16px); }
.tv-title.anchored.at-ml, .tv-title.anchored.at-mc, .tv-title.anchored.at-mr {
	top: 50%; transform: translateY(-50%);
}
.tv-title.anchored.at-bl, .tv-title.anchored.at-bc, .tv-title.anchored.at-br {
	top: auto; bottom: calc(var(--t-my, 16px) + var(--dock-h, 0px));
}
.tv-title.anchored.at-tl, .tv-title.anchored.at-ml, .tv-title.anchored.at-bl { left: var(--t-mx, 16px); }
.tv-title.anchored.at-tr, .tv-title.anchored.at-mr, .tv-title.anchored.at-br {
	left: auto; right: var(--t-mx, 16px);
}
.tv-title.anchored.at-tc, .tv-title.anchored.at-bc { left: 50%; transform: translateX(-50%); }
.tv-title.anchored.at-mc { left: 50%; transform: translate(-50%, -50%); }


/* **컨트롤 바 자유 배치.** 변에 붙지 않고 화면 아무 자리에나 띄운다.
   변에 붙을 때와 달리 자리를 차지하지 않으므로 `--dock-h` 에 끼지 않는다. */
#ui .tv-bar.pos-free {
	--n-x: calc(var(--bar-x, 50) / 100);
	--n-y: calc(var(--bar-y, 50) / 100);
	position: absolute; right: auto; bottom: auto; margin: 0;
	left: calc(12px + (100% - 24px) * var(--n-x));
	/* 고지문 띠 위까지만 — 위 `.at-free` 와 같은 사정이다 */
	top: calc(12px + (100% - 24px - var(--legal-h, 0px)) * var(--n-y));
	transform: translate(calc(-100% * var(--n-x)), calc(-100% * var(--n-y)));
}

.tv-compass.at-tc, .tv-compass.at-mc, .tv-compass.at-bc { left: 50%; }
.tv-compass.at-tc, .tv-compass.at-bc { transform: translateX(-50%); }
.tv-compass.at-mc { transform: translate(-50%, -50%); }

.tv-compass-btn {
	width: 100%; height: 100%; padding: 0; border: 0; background: none;
	display: block; cursor: pointer; border-radius: 50%;
	filter: drop-shadow(0 3px 10px rgba(0, 0, 0, 0.28));
	transition: transform 0.14s;
}
.tv-compass-btn:hover { transform: scale(1.06); }
.tv-compass-btn:active { transform: scale(0.96); }
.tv-compass-svg { display: block; width: 100%; height: 100%; overflow: visible; }
/* **사진 나침반.** 올린 그림을 그대로 돌린다 — N 이 위를 보게 그려 오면 된다.
   비율이 안 맞는 그림도 안 찌그러진다(`contain`). */
.tv-compass-img {
	display: block; width: 100%; height: 100%; object-fit: contain;
	transform: rotate(var(--c-rot, 0deg));
	transition: transform 0.08s linear;
	-webkit-user-drag: none; user-select: none;
}

/* 바탕 — 밝게 / 어둡게 / 없음 */
.tv-c-face { fill: rgba(255, 255, 255, 0.93); }
.face-dark .tv-c-face { fill: rgba(16, 18, 22, 0.86); }
.face-none .tv-c-face { fill: none; }
.tv-c-ring { fill: none; stroke: rgba(255, 255, 255, 0.9); stroke-width: 3; }
.face-dark .tv-c-ring { stroke: rgba(16, 18, 22, 0.86); }
.face-none .tv-c-ring { stroke: rgba(255, 255, 255, 0.55); }

/* --------------------------------------------- 장면 온오프 (인테리어 온/오프)
   장면은 그대로 두고 사진만 갈아 끼운다. 자리 규칙은 나침반과 같다.
   (스튜디오에서 부르는 이름이 「사진 고르개」에서 **「장면 온오프」**로 바뀌었다.) */
.tv-vars {
	position: absolute; z-index: 4;
	display: flex; align-items: center; gap: 8px;
	font-size: var(--v-fs, 13px);
	margin: calc(var(--head-h, 0px) + var(--menu-top, 0px)) var(--menu-right, 0) var(--menu-bottom, 0) var(--menu-left, 0);
}
/* 분류 버튼 줄 — 자리 규칙과 알약 생김새를 사진 변형과 나눠 쓴다 */
.tv-cats {
	position: absolute; z-index: 4;
	display: flex; align-items: center; flex-wrap: wrap; gap: var(--v-gap, 0px);
	font-size: var(--v-fs, 13px);
	padding: 4px; border-radius: 999px;
	background: var(--panel); border: 1px solid var(--edge);
	backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
	box-shadow: 0 6px 22px rgba(0, 0, 0, 0.3);
	margin: calc(var(--head-h, 0px) + var(--menu-top, 0px)) var(--menu-right, 0) var(--menu-bottom, 0) var(--menu-left, 0);
	max-width: calc(100% - 32px);
}
/* **세로로 돌리기.** 분류가 예닐곱이면 가로 줄이 화면 폭을 다 먹는다 —
   옆으로 세우면 왼쪽·오른쪽 여백에 붙일 수 있다. 컨트롤 바의 `.vertical` 과 같은 뜻. */
/* **분류 버튼의 그림.** 세로로 세운 버튼은 그림이 글자 위에, 가로로 늘어놓은
   버튼은 글자 왼쪽에 붙는다 — 어느 쪽이든 줄 높이는 그림이 정한다. */
.tv-cat-ico {
	display: block; width: var(--v-ico, 22px); height: var(--v-ico, 22px);
	object-fit: contain; margin: 0 auto 3px;
}
.tv-cats:not(.vertical) .tv-cat {
	display: inline-flex; align-items: center; gap: 6px;
}
.tv-cats:not(.vertical) .tv-cat-ico { margin: 0; }
/* **그림만.** 그림이 붙은 버튼에서만 글자를 감춘다 — 그림을 안 넣은 분류
   (흔히 「전체」)까지 감추면 빈 네모가 된다. 글자는 `title` 로 남아 마우스를
   올리면 뜬다. */
.tv-cats.icon-only .tv-cat:has(.tv-cat-ico) .tv-cat-tx { display: none; }
/* **그림이 곧 단추다.** 켜짐·꺼짐을 그림 두 장이 말해 주므로 단추의 여백·바탕·
   모서리·흐리기가 오히려 방해다 — 전부 걷어내고 그림만 꽉 채운다.
   세로 비율은 그림을 따른다(정사각이 아닌 그림도 안 찌그러진다). */
.tv-cats.icon-only .tv-cat:has(.tv-cat-ico),
.tv-cats.icon-only .tv-cat:has(.tv-cat-ico):hover,
.tv-cats.icon-only .tv-cat.on:has(.tv-cat-ico) {
	padding: 0; background: none; border: 0; border-radius: 0; opacity: 1;
}
.tv-cats.icon-only .tv-cat:has(.tv-cat-ico) .tv-cat-ico {
	margin: 0; width: var(--v-ico, 22px); height: auto;
}

/* **칸 사이 구분선.** 띄우는 것만으로는 나뉘어 보이지 않을 때 실선 한 줄을 긋는다.
   가로줄이면 버튼 왼쪽에, 세로줄이면 버튼 위에 붙는다 — 맨 앞 버튼에는 안 붙는다.
   그림만 쓰는 버튼(`icon-only`)은 위에서 테두리를 통째로 걷어내므로, **그보다
   뒤에** 같은 무게(클래스 넷)로 다시 그어 준다 — 뒤에 온 쪽이 이긴다.
   두께를 0 으로 두면 `has-line` 이 안 붙어 예전 모습 그대로다. */
.tv-cats.has-line .tv-cat + .tv-cat,
.tv-cats.has-line.icon-only .tv-cat + .tv-cat {
	border-left: var(--v-line, 1px) solid var(--v-line-c, rgba(255, 255, 255, 0.22));
}
.tv-cats.has-line.vertical .tv-cat + .tv-cat,
.tv-cats.has-line.vertical.icon-only .tv-cat + .tv-cat {
	border-left: 0;
	border-top: var(--v-line, 1px) solid var(--v-line-c, rgba(255, 255, 255, 0.22));
}

.tv-cats.vertical, .tv-vars.vertical {
	flex-direction: column; flex-wrap: nowrap; align-items: stretch;
	border-radius: 22px; max-width: none; max-height: calc(100% - 32px);
}
.tv-cats.vertical .tv-cat { width: 100%; text-align: center; }
.tv-vars.vertical { gap: 6px; }
.tv-vars.vertical .tv-var { width: 100%; text-align: center; }

.tv-cats.at-tl, .tv-cats.at-tc, .tv-cats.at-tr,
.tv-vars.at-tl, .tv-vars.at-tc, .tv-vars.at-tr { top: var(--v-my, 16px); }
.tv-cats.at-ml, .tv-cats.at-mc, .tv-cats.at-mr,
.tv-vars.at-ml, .tv-vars.at-mc, .tv-vars.at-mr { top: 50%; transform: translateY(-50%); }
.tv-cats.at-bl, .tv-cats.at-bc, .tv-cats.at-br,
.tv-vars.at-bl, .tv-vars.at-bc, .tv-vars.at-br {
	bottom: calc(var(--v-my, 16px) + var(--dock-h, 0px));
}
.tv-cats.at-tl, .tv-cats.at-ml, .tv-cats.at-bl,
.tv-vars.at-tl, .tv-vars.at-ml, .tv-vars.at-bl { left: var(--v-mx, 16px); }
.tv-cats.at-tr, .tv-cats.at-mr, .tv-cats.at-br,
.tv-vars.at-tr, .tv-vars.at-mr, .tv-vars.at-br { right: var(--v-mx, 16px); }
.tv-cats.at-tc, .tv-cats.at-mc, .tv-cats.at-bc,
.tv-vars.at-tc, .tv-vars.at-mc, .tv-vars.at-bc { left: 50%; }
.tv-cats.at-tc, .tv-cats.at-bc,
.tv-vars.at-tc, .tv-vars.at-bc { transform: translateX(-50%); }
.tv-cats.at-mc,
.tv-vars.at-mc { transform: translate(-50%, -50%); }

/* 탭 — 사진이 몇 장이든 쓸 수 있다 */
.tv-vars.sty-tabs {
	gap: 0; padding: 4px; border-radius: 999px;
	background: var(--panel); border: 1px solid var(--edge);
	backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
	box-shadow: 0 6px 22px rgba(0, 0, 0, 0.3);
}
.tv-var, .tv-cat {
	appearance: none; border: 0; background: none; cursor: pointer;
	color: var(--text); opacity: 0.72;
	font: inherit; font-family: inherit; line-height: 1;
	padding: 8px 16px; border-radius: 999px;
	transition: background 0.15s, opacity 0.15s, color 0.15s;
	white-space: nowrap;
}
.tv-var:hover, .tv-cat:hover { opacity: 1; background: rgba(255, 255, 255, 0.08); }
.tv-var.on, .tv-cat.on {
	opacity: 1; font-weight: 700;
	color: var(--on-fill, #0e1013); background: var(--v-accent, var(--accent-fill, var(--accent)));
}

/* 스위치 — 두 장일 때. 「비움 ( ●) 인테리어」 */
.tv-vars.sty-switch {
	padding: 6px 12px; border-radius: 999px;
	background: var(--panel); border: 1px solid var(--edge);
	backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
	box-shadow: 0 6px 22px rgba(0, 0, 0, 0.3);
}
.tv-var-lab {
	color: var(--text); opacity: 0.55; cursor: pointer; white-space: nowrap;
	transition: opacity 0.15s;
}
.tv-var-lab.on { opacity: 1; font-weight: 700; }
/* **앞에 붙는 이름** — 무엇을 켜고 끄는지 알려 준다(「인테리어 [온 ● 오프]」).
   고른 쪽 이름과 헷갈리지 않게 **누르는 것이 아님**을 굵기와 여백으로 보인다. */
.tv-var-name {
	color: var(--text); font-weight: 700; white-space: nowrap;
	margin-right: 2px; opacity: 0.9;
}
.tv-var-sw {
	appearance: none; border: 0; cursor: pointer; padding: 0;
	width: calc(var(--v-fs, 13px) * 2.9); height: calc(var(--v-fs, 13px) * 1.6);
	border-radius: 999px; background: rgba(255, 255, 255, 0.22);
	position: relative; transition: background 0.18s;
	flex: none;
}
.tv-vars.two .tv-var-sw { background: var(--v-accent, var(--accent)); }
.tv-var-sw i {
	position: absolute; top: 50%; left: 3px;
	width: calc(var(--v-fs, 13px) * 1.15); height: calc(var(--v-fs, 13px) * 1.15);
	border-radius: 50%; background: #fff;
	transform: translateY(-50%);
	transition: left 0.18s var(--ease);
	box-shadow: 0 1px 3px rgba(0, 0, 0, 0.35);
}
.tv-vars.two .tv-var-sw i { left: calc(100% - var(--v-fs, 13px) * 1.15 - 3px); }

/* 전시품목 스위치 — 장면 온오프와 같은 손잡이지만 켜짐 표시가 `.on` 이다
   (장면 온오프는 「두 번째 사진을 골랐나」를 `.two` 로 나타낸다). */
.tv-itemsw.on .tv-var-sw { background: var(--v-accent, var(--accent)); }
.tv-itemsw.on .tv-var-sw i { left: calc(100% - var(--v-fs, 13px) * 1.15 - 3px); }

/* ------------------------------------------------------------- 생김새 프리셋
   분류 버튼 줄 · 전시품목 스위치 · 장면 온오프가 **같은 이름의 모양**을 나눠 쓴다.
   기본(`look-pill`)은 지금까지의 알약이라 안 고른 투어의 모습이 안 바뀐다. */
.tv-cats.look-square, .tv-vars.look-square .tv-var-box { border-radius: 8px; }
.tv-cats.look-square .tv-cat { border-radius: 6px; }

/* 테두리만 — 배경을 비우고 선으로 */
.tv-cats.look-outline {
	background: transparent; border-color: rgba(255, 255, 255, 0.55);
	box-shadow: none; backdrop-filter: none; -webkit-backdrop-filter: none;
}
.tv-cats.look-outline .tv-cat { color: #fff; text-shadow: 0 1px 3px rgba(0,0,0,0.6); }

/* 채움 — 강조색 판 위에 */
.tv-cats.look-solid {
	background: var(--v-accent, var(--accent)); border-color: transparent;
	backdrop-filter: none; -webkit-backdrop-filter: none;
}
.tv-cats.look-solid .tv-cat { color: #08131c; }
.tv-cats.look-solid .tv-cat.on { background: rgba(0, 0, 0, 0.28); color: #fff; }

/* 조용히 — 판 없이 글자만 (파노라마 위에 얹는다) */
.tv-cats.look-quiet {
	background: none; border-color: transparent; box-shadow: none;
	backdrop-filter: none; -webkit-backdrop-filter: none;
	/* **판이 없으면 판 여백도 없다.** 바탕과 테두리만 지우고 `padding: 4px` ·
	   `border-width: 1px` 은 남겨 두었더니, 「여백 ↔」을 0 까지 내려도 단추가
	   화면 끝에서 **5px 떨어진 채** 멈췄다 — 보이지도 않는 판이 자리를 먹고
	   있었던 것이다(사용자: 「분류는 밸런스상 오른쪽으로 더 들어가야 돼」).
	   이 모양을 쓰는 투어는 청라 하나뿐이라 그대로 걷어낸다. */
	padding: 0; border-width: 0;
}
.tv-cats.look-quiet .tv-cat {
	color: #fff; text-shadow: 0 1px 4px rgba(0, 0, 0, 0.75), 0 0 12px rgba(0, 0, 0, 0.5);
}

/* 원형 — **어두운 동그라미 하나하나가 단추**(판 없음). 목동 레퍼런스(사용자 스크린샷):
   짙은 회색 원 · 흰 테두리 · 흰 굵은 글자, 오른쪽에 세로로. 고른 것은 흰 원에 짙은 글자.
   지름은 글자 크기를 따른다(13px → 44px). 두 글자 이름에 맞춘 크기라 긴 이름은 두 줄로 접힌다. */
.tv-cats.look-circle {
	background: none; border: 0; box-shadow: none; padding: 0;
	backdrop-filter: none; -webkit-backdrop-filter: none;
	align-items: center;
}
.tv-cats.look-circle .tv-cat,
.tv-cats.look-circle.vertical .tv-cat {
	width: calc(var(--v-fs, 13px) * 3.4); height: calc(var(--v-fs, 13px) * 3.4);
	padding: 2px; border-radius: 50%;
	display: grid; place-items: center; text-align: center;
	background: rgba(40, 42, 46, 0.9); color: #fff; opacity: 1;
	border: 1.5px solid rgba(255, 255, 255, 0.92);
	box-shadow: 0 2px 8px rgba(0, 0, 0, 0.35);
	font-weight: 700; line-height: 1.1; letter-spacing: -0.02em;
	white-space: normal; word-break: keep-all;
}
.tv-cats.look-circle .tv-cat:hover { background: rgba(60, 63, 68, 0.95); }
.tv-cats.look-circle .tv-cat.on { background: #fff; color: #1d1f22; }
/* 원 안에 그림을 넣었으면 그림을 원 크기에 맞춘다 */
.tv-cats.look-circle .tv-cat-ico { width: 60%; height: 60%; margin: 0; }
/* 원끼리는 구분선 대신 틈으로 나뉜다 */
.tv-cats.look-circle.has-line .tv-cat + .tv-cat { border-top-width: 1.5px; border-left-width: 1.5px; }

/* 스위치 계열(전시품목 · 장면 온오프)의 글자 판 */
.tv-vars.look-outline .tv-var-lab, .tv-vars.look-solid .tv-var-lab,
.tv-vars.look-quiet .tv-var-lab { text-shadow: 0 1px 4px rgba(0, 0, 0, 0.7); }
.tv-vars.look-square .tv-var-sw { border-radius: 6px; }
.tv-vars.look-square .tv-var-sw i { border-radius: 3px; }

/* 장미 — 방위마다 밝은 쪽/어두운 쪽 */
.tv-c-lit { fill: #ffffff; }
.tv-c-dim { fill: #d7dbe0; }
.face-dark .tv-c-lit { fill: #6b7480; }
.face-dark .tv-c-dim { fill: #3a4048; }

/* 북쪽 표시 — 설정에서 색을 고른다 */
.tv-c-north { fill: var(--c-north, #e8384f); }
.tv-c-north-dark { fill: var(--c-north, #e8384f); filter: brightness(0.82); }
.tv-c-south { fill: #b9c0c9; }
.face-dark .tv-c-south { fill: #566070; }

.tv-c-hub { fill: #ffffff; stroke: #d7dbe0; stroke-width: 1; }
.face-dark .tv-c-hub { fill: #20242b; stroke: #3a4048; }

/* 눈금 링 */
.tv-c-tick { stroke: #b9c0c9; stroke-width: 2; stroke-linecap: round; }
.tv-c-tick.big { stroke: #7b8492; stroke-width: 3; }
.face-dark .tv-c-tick { stroke: #566070; }

/* 방위 글자 */
.tv-c-let {
	font: 700 15px 'Noto Sans KR', sans-serif; fill: #6b7480;
	text-anchor: middle; dominant-baseline: middle;
}
.tv-c-let.dim { font-size: 12px; opacity: 0.55; }
.face-dark .tv-c-let { fill: #cfd5dd; }
.sty-ring .tv-c-let, .sty-needle .tv-c-let { font-size: 13px; }

/* **시야** — 판·N 은 가만히, 부채꼴만 **보는 쪽으로**(판과 반대 방향) 돈다.
   바탕은 옅게(파노라마가 비친다) · 테두리 흰 링 · 가운데 흰 점 · N 은 원 **바깥 위**. */
.sty-view .tv-c-face { fill: rgba(255, 255, 255, 0.12); }
.face-dark.sty-view .tv-c-face { fill: rgba(16, 18, 22, 0.42); }
.face-none.sty-view .tv-c-face { fill: none; }
.tv-c-cone {
	transform: rotate(calc(-1 * var(--c-rot, 0deg)));
	transform-origin: 50px 50px;
	transition: transform 0.08s linear;
}
/* 색은 「시야 부채꼴 색」(compass.cone → --c-cone) — 안 정했으면 바탕에 따라 */
.tv-c-cone path { fill: var(--c-cone, rgba(30, 36, 46, 0.72)); }
.face-dark .tv-c-cone path { fill: var(--c-cone, rgba(255, 255, 255, 0.55)); }
.tv-c-vhub { fill: #ffffff; }
.tv-c-vn {
	fill: var(--c-north, #e8384f); font: 800 18px/1 system-ui, sans-serif; text-anchor: middle;
	paint-order: stroke; stroke: rgba(255, 255, 255, 0.75); stroke-width: 2.5px;
}

/* 돌아가는 것은 이 묶음 하나뿐 — 모양이 바뀌어도 회전 코드는 그대로다 */
.tv-c-rose {
	transform: rotate(var(--c-rot, 0deg));
	transform-origin: 50px 50px;
	transition: transform 0.08s linear;
}

/* -------------------------------------------------------------- 평면도 */
/* 미니맵 — 화면 어디에 놓을지는 settings.minimap 이 정한다(3x3 자리 또는 자유 위치) */
.tv-map {
	position: absolute;
	/* `--map-w` 는 ui.js 가 **인라인으로** 박는다 — 인라인 커스텀 속성은 미디어쿼리를
	   이기므로, 작은 화면에서 줄이려면 변수를 다시 정의해선 안 되고 **상한(--map-max)**
	   을 따로 둬야 한다. 예전에는 미디어쿼리가 아예 먹지 않았다. */
	/* 상한(--map-max)과 **하한(--map-min)** 을 둘 다 둔다. 폰에서는 하한이 있어야
	   「크기」를 작게 잡아 둔 투어도 같은 크기로 보인다 — 프로젝트마다 도면 크기가
	   달라 폰에서 어떤 건 53%, 어떤 건 60% 로 제각각이었다. 화면 밖으로는 절대
	   못 나간다(맨 바깥 min 이 그것을 지킨다). */
	width: min(
		max(var(--map-min, 0px), min(var(--map-w, 280px), var(--map-max, 100vw))),
		calc(100vw - 2 * var(--map-mx, 16px)));
	/* 「크기」는 판 전체 너비다. 안쪽 버퍼는 판이 아니라 **지도에만** 준다
	   (아래 .tv-map-body) — 제목·탭 줄은 위에 그대로 꽉 차게 둔다. */
	box-sizing: border-box;
	/* 배경색·투명도는 settings.minimap 이 정할 수 있다. 안 정해 두면 --map-bg 가
	   없으므로 예비값인 테마 판 색(--panel)을 그대로 쓴다. */
	background: var(--map-bg, var(--panel));
	border: var(--map-bd, 1px) solid var(--map-edge, var(--edge));
	border-radius: var(--radius);
	overflow: hidden;
	/* 배경을 완전히 투명하게 하면 흐림도 함께 끈다(--map-blur: 0px) — 배경을 없앤
	   뜻인데 뒤가 흐려지면 「없앤」 것으로 안 보인다. */
	backdrop-filter: blur(var(--map-blur, 14px));
	-webkit-backdrop-filter: blur(var(--map-blur, 14px));
}
/* 3x3 자리 — 여백은 가로·세로를 따로 준다 (--map-mx / --map-my).
   기본은 메뉴가 차지한 폭(--menu-*)과 아래 바(--dock-h)만큼 비켜나고,
   edge-exact 를 켜면 비켜나지 않아 **화면 모서리에서 잰 거리 그대로**가 된다. */
.tv-map.at-tl, .tv-map.at-tc, .tv-map.at-tr { top: var(--map-my, 16px); }
.tv-map.at-ml, .tv-map.at-mc, .tv-map.at-mr { top: 50%; transform: translateY(-50%); }
/* 아래쪽에 놓을 때는 썸네일·컨트롤 바(--dock-h) 위로 올라간다 */
.tv-map.at-bl, .tv-map.at-bc, .tv-map.at-br {
	bottom: calc(var(--map-my, 16px) + var(--dock-h, 0px));
	transition: bottom 0.3s var(--ease);
}
.tv-map.at-tl, .tv-map.at-ml, .tv-map.at-bl { left: var(--map-mx, 16px); }
.tv-map.at-tr, .tv-map.at-mr, .tv-map.at-br { right: var(--map-mx, 16px); }
.tv-map.at-tc, .tv-map.at-mc, .tv-map.at-bc { left: 50%; }
.tv-map.at-tc { transform: translateX(-50%); }
.tv-map.at-bc { transform: translateX(-50%); }
.tv-map.at-mc { transform: translate(-50%, -50%); }
/* 자유 위치 — 다른 부속과 같은 비례 기준점 (0 = 끝, 50 = 가운데, 100 = 반대 끝).
   **메뉴가 차지한 만큼은 놓을 수 있는 넓이에서 뺀다** — 마진으로 밀면 반대쪽 끝
   (100%)에 놓았을 때 그만큼 화면 밖으로 나간다. 여기서는 넓이 자체를 줄인다. */
.tv-map.at-free {
	--n-x: calc(var(--map-x, 50) / 100);
	--n-y: calc(var(--map-y, 50) / 100);
	--in-t: calc(var(--map-my, 16px) + var(--head-h, 0px) + var(--menu-top, 0px));
	--in-b: calc(var(--map-my, 16px) + var(--menu-bottom, 0px) + var(--legal-h, 0px));
	--in-l: calc(var(--map-mx, 16px) + var(--menu-left, 0px));
	--in-r: calc(var(--map-mx, 16px) + var(--menu-right, 0px));
	right: auto; bottom: auto;
	margin: 0;                       /* 인셋을 위 계산에 넣었으므로 마진으로 또 밀지 않는다 */
	left: calc(var(--in-l) + (100% - var(--in-l) - var(--in-r)) * var(--n-x));
	top: calc(var(--in-t) + (100% - var(--in-t) - var(--in-b)) * var(--n-y));
	transform: translate(calc(-100% * var(--n-x)), calc(-100% * var(--n-y)));
}
.tv-map-title {
	flex: 1; min-width: 0; padding: 4px 6px; font-size: 12px;
	color: var(--map-fg, var(--text));
	overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.tv-map-tabs {
	display: flex; align-items: center; gap: 4px; padding: 4px 5px 3px;
	border-bottom: 1px solid var(--map-edge, var(--edge));
	/* **대표색 바.** 색을 고른 투어에서만 채워진다 — 그때는 색 자체가 경계가 되므로
	   아래 실선을 지운다(선이 겹치면 바가 두 겹으로 보인다). */
	background: var(--map-bar, transparent);
}
.tv-map-tabs[data-bar] { border-bottom: 0; }
/* 색을 채운 바 위에서는 글자·탭·✕ 가 그 색에 맞춰 뒤집힌다 */
.tv-map-tabs[data-bar] .tv-map-title,
.tv-map-tabs[data-bar] .tv-map-tab,
.tv-map-tabs[data-bar] .tv-map-close { color: var(--map-bar-fg, #fff); }
.tv-map-tabs[data-bar] .tv-map-tab.on {
	background: var(--map-bar-hv, rgba(255, 255, 255, 0.22));
	color: var(--map-bar-fg, #fff);
}
.tv-map-tabs[data-bar] .tv-map-close::before { background: var(--map-bar-hv, rgba(255, 255, 255, 0.22)); }
.tv-map-tab {
	border: 0; background: transparent; color: var(--map-dim, var(--dim));
	font: inherit; font-size: 12px;
	padding: 4px 9px; border-radius: 7px; cursor: pointer;
}
.tv-map-tab.on {
	background: var(--map-hv, rgba(255, 255, 255, 0.13));
	color: var(--map-fg, var(--text));
}
.tv-map-close { margin-left: auto; width: 30px; height: 28px; color: var(--map-fg, var(--text)); }
.tv-map-close svg { width: 20px; height: 20px; position: relative; }
/* 닫기 X 의 마우스온 배경 — 누를 자리는 넓게 두고 **배경만 가운데 동그라미**로
   그린다. 칸이 정사각형이 아니라서 .tv-btn 의 border-radius:50% 가 타원을 만들고,
   그 타원이 판의 둥근 모서리(--radius)에 물려 한쪽이 잘려 보였다. */
.tv-map-close { position: relative; --x-dot: 22px; }
.tv-map-close::before {
	content: ''; position: absolute; left: 50%; top: 50%;
	width: var(--x-dot); height: var(--x-dot);
	margin: calc(var(--x-dot) / -2) 0 0 calc(var(--x-dot) / -2);
	border-radius: 50%; background: transparent; transition: background 0.15s;
}
.tv-map-close:hover { background: transparent; }
.tv-map-close:hover::before { background: var(--map-hv, rgba(255, 255, 255, 0.12)); }
/* 제목도 탭도 없이 **닫기 X 만 남은 상단바** — 글자가 없으니 얇게 줄이고
   그만큼 X 를 키운다. 줄이 비어 보이지 않게 하는 게 목적이다. */
.tv-map-tabs.bare { padding: 0 2px; border-bottom: 0; }
/* 얇은 줄에서는 동그라미도 한 치 줄여 판 모서리에 닿지 않게 한다 */
.tv-map-tabs.bare .tv-map-close { width: 28px; height: 22px; --x-dot: 20px; }
.tv-map-tabs.bare .tv-map-close svg { width: 21px; height: 21px; }

/* 안쪽 버퍼 — 지도만 안으로 들인다. 판 크기도 제목·탭 줄도 그대로다. */
.tv-map-body { position: relative; line-height: 0; margin: var(--map-pad, 0px); }
.tv-map-img { width: 100%; display: block; }
/* 사진별 그림으로 바뀔 때 옛 그림이 위에서 스르르 사라진다 — ui.js `_fadeMapFrom` */
.tv-map-ghost {
	position: absolute; left: 0; top: 0; width: 100%; height: 100%;
	display: block; pointer-events: none; opacity: 1;
	transition: opacity 0.6s ease-in-out;
}
.tv-map-dots { position: absolute; inset: 0; }
/* 레이더를 잡아 돌릴 수 있는 자리 — 손 모양은 ui.js 가 자리를 재서 켜 준다.
   부채꼴 자체는 pointer-events:none 이라 이 판이 눌림을 받는다. */
.tv-map-dots.radar-grab { cursor: grab; }
.tv-map-dots.radar-drag { cursor: grabbing; }
/* 돌리는 동안에는 점의 커서·전이가 끼어들지 않게 한다 */
.tv-map-dots.radar-drag .tv-dot { cursor: grabbing; }

.tv-dot {
	position: absolute; width: 14px; height: 14px; margin: -7px 0 0 -7px;
	padding: 0; border: 0; background: transparent; cursor: pointer;
}
.tv-dot-core {
	position: absolute; inset: 3px; border-radius: 50%;
	background: #fff; box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.45);
	transition: background 0.15s, inset 0.15s;
}
.tv-dot:hover .tv-dot-core { inset: 1px; }
/* **지금 있는 장면의 점.** 레이더 색을 따로 안 고르면 부채꼴이 대표색을 그대로 쓰므로
   (`ui.js` 의 `--radar-fill` 폴백) 점과 부채꼴이 **같은 색**이 되어 점이 묻혔다.
   색을 바꾸면 이미 만든 투어의 모습이 흔들리므로, 대신 **테를 두 겹** 두른다 —
   어두운 부채꼴에서는 안쪽 흰 테가, 밝은 부채꼴에서는 바깥 어두운 테가 경계를 만든다
   (도형 손잡이가 쓰는 것과 같은 수법이다). */
.tv-dot.on .tv-dot-core {
	background: var(--accent); inset: 2px;
	box-shadow: 0 0 0 2px #fff, 0 0 0 3.5px rgba(0, 0, 0, 0.5);
}
.tv-dot-cone { display: none; }
/* 점마다 끈 레이더(`scene.noRadar`) — 아래 `.tv-dot.on` 보다 앞서야 해서 더 구체적으로 */
.tv-dot.on.no-radar .tv-dot-cone { display: none; }
/* 레이더(시야 부채꼴) — 색·투명도·크기·각도는 settings.radar 가 정한다 */
.tv-dot.on .tv-dot-cone {
	display: block; position: absolute; left: 50%; top: 50%;
	/* 크기는 px 지만 **고정값이 아니다.** 화면이 좁아 미니맵이 줄면 레이더만 그대로
	   남아 비율이 깨지므로(도면 170->143 인데 레이더 130 = 76%->91%), `ui.js` 의
	   `updateMap()` 이 **실제로 그려진 도면 폭**에 맞춰 이 값을 다시 넣어 준다.
	   여기서 %를 쓸 수는 없다 — 부채꼴의 부모는 도면이 아니라 **14px 짜리 점**이다. */
	width: var(--radar-size, 130px); height: var(--radar-size, 130px);
	margin: calc(var(--radar-size, 130px) / -2) 0 0 calc(var(--radar-size, 130px) / -2);
	transform: rotate(var(--yaw, 0deg));
	/* **색이 고른 단색 부채꼴.** 예전에는 각도를 따라 한쪽만 밝고 반대쪽이 투명해서
	   (conic-gradient 의 기본 보간) 어느 쪽을 보고 있는지 읽기가 어려웠다.
	   각도 끝의 1.5deg 와 바깥 테두리의 2% 만 페더로 남긴다 — 계단(에일리어싱)을
	   지우는 최소한이고, 눈에는 단색으로 보인다. */
	background: conic-gradient(
		from calc(var(--radar-angle, 105deg) / -2),
		var(--radar-fill, rgba(124, 196, 255, 0.75)) 0
			calc(var(--radar-angle, 105deg) - 1.5deg),
		transparent var(--radar-angle, 105deg));
	border-radius: 50%;
	/* 바깥 가장자리. `--radar-in` 이 「단색으로 꽉 찬 데까지」의 반지름이다.
	   70% = 원으로 딱 떨어짐(기본) / 52% = 바깥으로 서서히 흐려짐(settings.radar.fade).
	   끝 지점(72%)은 어느 쪽이든 같아서 `radar.size` 가 뜻하는 크기가 바뀌지 않는다. */
	-webkit-mask-image: radial-gradient(circle, #000 0 var(--radar-in, 70%), transparent 72%);
	mask-image: radial-gradient(circle, #000 0 var(--radar-in, 70%), transparent 72%);
	pointer-events: none;
}

/* -------------------------------------------------------------- 툴팁 */
.tv-tooltip {
	position: absolute; transform: translate(-50%, -100%); padding: 5px 10px;
	background: rgba(10, 12, 15, 0.9); border: 1px solid var(--edge);
	border-radius: 7px; font-size: 12px; white-space: nowrap; opacity: 0;
	transition: opacity 0.12s; pointer-events: none;
}
.tv-tooltip.on { opacity: 1; }

/* -------------------------------------------------------------- 팝업 */
.tv-modal {
	/* **화면에 있는 것을 전부 덮는다.** 예전에는 4 라 상단 띠(6)와 폰의 평형
	   단추(7)만 말짱하게 남아, 나머지는 어두워졌는데 머리만 환한 어정쩡한 그림이
	   됐다. 팝업은 「지금은 이것만 보라」는 뜻이니 덮는 것이 맞다. */
	position: absolute; inset: 0; z-index: 8; display: none; align-items: center;
	justify-content: center; padding: 24px; background: rgba(6, 7, 9, 0.62);
	backdrop-filter: blur(4px);
	/* 화면 전체로 넘어갈 때 **뒷배경이 서서히** 어두워진다 — 한 번에 바뀌면
	   그 순간이 끊겨 보인다(「갑자기 너무 어두워져서 끊겨 보여」). */
	transition: background-color 0.4s ease, backdrop-filter 0.4s ease, padding 0.3s ease;
}
/* **뜨고 지는 것을 눈에 보이게 한다.**
   `display` 를 바꾸는 것만으로는 전이가 안 걸려 **딱 하고 나타났다.** 손님이 보는
   자리라 그 한 순간이 곧 만듦새로 읽힌다 — 뒷배경은 스며들고, 카드는 아주 조금
   커지며 떠오른다(위에서 내려오면 「알림」처럼 보이고, 확 커지면 값싸 보인다).
   **`display` 가 바뀌는 순간에도 `animation` 은 돈다** — 그래서 전이가 아니라
   애니메이션이다. */
.tv-modal.on { display: flex; animation: tvFadeIn 0.26s ease both; }
/* 장면 인트로에서 「배경 흐림」을 끈 것 — 어둡게도 흐리게도 하지 않는다 */
.tv-modal.clear { background: transparent; backdrop-filter: none; -webkit-backdrop-filter: none; }
.tv-modal.on .tv-modal-card { animation: tvRise 0.34s cubic-bezier(0.16, 0.84, 0.24, 1) both; }
/* 닫을 때 — `ui.js` 가 이 표를 붙이고 다 진 뒤에 치운다 */
.tv-modal.out { animation: tvFadeOut 0.18s ease both; }
.tv-modal.out .tv-modal-card { animation: tvSink 0.18s ease both; }

@keyframes tvFadeIn  { from { opacity: 0; } to { opacity: 1; } }
@keyframes tvFadeOut { from { opacity: 1; } to { opacity: 0; } }
@keyframes tvRise {
	from { opacity: 0; transform: translateY(10px) scale(0.972); }
	to   { opacity: 1; transform: none; }
}
@keyframes tvSink {
	from { opacity: 1; transform: none; }
	to   { opacity: 0; transform: translateY(4px) scale(0.99); }
}
/* **움직임을 줄여 달라고 한 사람에게는 안 움직인다.** 어지럼을 타는 분들이 있고,
   그 설정을 무시하면 「예쁘게 만든 것」이 곧장 못 쓰는 것이 된다. */
@media (prefers-reduced-motion: reduce) {
	.tv-modal.on, .tv-modal.on .tv-modal-card,
	.tv-modal.out, .tv-modal.out .tv-modal-card { animation-duration: 0.01ms; }
}
.tv-modal-card {
	position: relative; width: min(560px, 100%); max-height: 84vh; overflow: auto;
	background: #14171c; border: 1px solid var(--edge); border-radius: 16px;
	box-shadow: var(--shadow);
	/* 카드 껍데기(판·테두리·그림자)도 **서서히** 벗겨진다 — 배경과 같은 박자로 */
	transition: background-color 0.4s ease, border-color 0.4s ease,
		box-shadow 0.4s ease, border-radius 0.3s ease;
}
.tv-modal-img { width: 100%; display: block; }
/* ── 팝업 그림 확대 (휠 · 두 손가락 · 두 번 누르기) ──────────────────────
   도면·평면 안내를 한 장으로 띄우면 글씨가 작아 안 읽힌다. 팝업을 화면만큼 키우면
   뒤가 안 보이므로 **띄운 자리에서 키워 보게** 한다. */
.tv-modal-img {
	/* **처음부터 확대 커서로 대기하지 않는다.** 늘 돋보기가 떠 있으면 「눌러야 하나」
	   싶고, 정작 눌러도 아무 일이 없다(확대는 휠·두 손가락·두 번 누르기다).
	   끌 것이 생겼을 때만 손 모양으로 바꾼다. */
	cursor: default; touch-action: none;      /* 두 손가락을 브라우저가 채가지 않게 */
	transform-origin: 50% 50%;
	/* 끄는 동안에는 전이를 끄고, 휠·더블클릭에서만 부드럽게 — 아래 .zoomed 참고 */
	transition: transform 0.12s ease-out;
	will-change: transform;
}
.tv-modal-img.zoomed { cursor: grab; }
.tv-modal-img.zoomed:active { cursor: grabbing; transition: none; }
/* **틀이 그림과 함께 커진다.** 크기는 `ui.js` 의 `_zoomable` 이 px 로 넣어 준다 —
   화면에 자리가 있는 동안은 틀이 커지고, 화면 끝에 닿으면 그때부터 그림만 커지며
   여기서 잘린다(그때 끌어서 옮긴다). */
.tv-modal-imgwrap {
	display: flex; align-items: center; justify-content: center;
	overflow: hidden; line-height: 0; margin: 0 auto;
	transition: width 0.12s ease-out, height 0.12s ease-out;
}
.tv-modal-card.kind-image .tv-modal-imgwrap { border-radius: inherit; }
/* 그림 크기는 코드가 px 로 잡는다 — `width: 100%` 가 그것을 덮으면 안 된다 */
.tv-modal-imgwrap > .tv-modal-img { width: auto; max-width: none; max-height: none; }

/* ── 화면 전체로 보기 ──────────────────────────────────────────────────
   카드에 더 담을 수 없을 만큼 키우면 **껍데기를 벗고 화면 전체가 틀**이 된다.
   「틀 안에서 커지는」 것이 낯설다는 말을 듣고 이렇게 바꿨다 — 사진 보기 창과 같다. */
/* 0.92 는 너무 짙어 파노라마가 아주 사라졌다 — 뒤가 비치는 정도로 낮춘다.
   대신 흐림을 조금 더 줘서 그림에 눈이 가게 한다. */
.tv-modal.full { padding: 0; background: rgba(6, 7, 9, 0.76); backdrop-filter: blur(7px); }
.tv-modal.full .tv-modal-card {
	width: 100vw; height: 100vh; max-width: none; max-height: none;
	background: none; border: 0; box-shadow: none; border-radius: 0; overflow: hidden;
	display: flex; align-items: center; justify-content: center;
}
.tv-modal.full .tv-modal-imgwrap { border-radius: 0; }
/* 닫기는 화면 구석에 — 껍데기가 없어도 나가는 길은 늘 같은 자리에 있어야 한다 */
.tv-modal.full .tv-modal-close {
	right: 16px; top: 16px; width: 40px; height: 40px;
	background: rgba(0, 0, 0, 0.6);
}

/* ── 조작 안내 (이용자용) ──────────────────────────────────────────────
   360 투어는 「끌어서 둘러본다」가 당연해 보이지만, 처음 보는 사람은 화면을 누르기만
   하고 돌려 볼 생각을 못 한다. 켜 둔 투어에서만 뜬다. */
.tv-modal-card.kind-help { width: min(420px, 100%); }
.tv-help { padding: 22px 24px 20px; color: var(--text); }
.tv-help h3 { margin: 0 0 14px; font-size: 17px; font-weight: 700; letter-spacing: -0.01em; }
.tv-help h4 {
	margin: 18px 0 8px; font-size: 11px; font-weight: 600; color: var(--dim);
	letter-spacing: 0.08em; text-transform: uppercase;
}
.tv-help-sec { display: grid; gap: 2px; }
.tv-help-row {
	display: grid; grid-template-columns: minmax(96px, auto) 1fr; gap: 14px;
	align-items: baseline; padding: 7px 0;
}
.tv-help-row + .tv-help-row { border-top: 1px solid rgba(255, 255, 255, 0.06); }
.tv-help-keys { display: flex; flex-wrap: wrap; gap: 4px; align-items: center;
	font-size: 12px; color: var(--dim); }
.tv-help-what { font-size: 13px; line-height: 1.45; }
/* 자판 글쇠 — 실제 키캡처럼 보이면 「눌러 보라」는 게 바로 읽힌다 */
.tv-help kbd {
	display: inline-block; min-width: 22px; padding: 3px 7px; text-align: center;
	font: 600 12px/1 var(--font, inherit); color: var(--text);
	background: #1e232b; border: 1px solid rgba(255, 255, 255, 0.14);
	border-bottom-width: 2px; border-radius: 6px;
}
@media (max-width: 420px) {
	.tv-help { padding: 18px 16px 16px; }
	.tv-help-row { grid-template-columns: 1fr; gap: 3px; }
	.tv-help-what { color: var(--dim); }
}
/* **이미지만 띄울 때는 카드가 이미지에 딱 맞는다.**
   예전에는 카드를 1100px 로 못박아 놓아서, 그보다 좁은 그림(세로로 긴 도면·
   투시도)을 열면 **양옆에 카드 바탕이 남아** 「이미지 밖에 공간이 보인다」가 됐다.
   폭을 그림에 맡기고 상한만 둔다. */
.tv-modal-card.kind-image { width: auto; max-width: min(1600px, 94vw); }
.tv-modal-img.big { max-height: 84vh; width: auto; max-width: min(1100px, 94vw); display: block; }
/* 글도 링크도 없이 **그림 한 장뿐**이면 카드 자체를 지운다 — 판·테두리가 남으면
   모서리에 얇은 띠로 비친다. 그림만 담박하게 보이는 게 이 팝업의 뜻이다. */
.tv-modal-card.kind-image.bare {
	background: none; border: 0; box-shadow: none; overflow: visible;
}
.tv-modal-card.kind-image.bare .tv-modal-img.big { border-radius: 12px; }
/* **제목·글이 붙으면 그림을 그만큼 낮춘다.** 그림이 84vh 를 다 먹으면 글은 카드
   아래로 밀려나 **스크롤하기 전에는 안 보인다** — 있는 줄도 모르고 닫게 된다. */
.tv-modal-card.kind-image:not(.bare) .tv-modal-img.big { max-height: 60vh; }
/* 영상 — 16:9 를 지키고 카드를 넓게 */
.tv-modal-card.kind-video, .tv-modal-card.kind-youtube, .tv-modal-card.kind-vimeo {
	width: min(1100px, 94vw);
}
.tv-modal-media { position: relative; width: 100%; aspect-ratio: 16 / 9; background: #000; }
.tv-modal-media > iframe, .tv-modal-media > video {
	position: absolute; inset: 0; width: 100%; height: 100%; border: 0; display: block;
}
/* 직접 쓴 HTML — 투어를 만든 사람이 넣은 것이다 */
.tv-modal-card.kind-html { width: min(900px, 94vw); }
.tv-modal-html { padding: 20px 22px; max-height: 80vh; overflow: auto; line-height: 1.6; }
.tv-modal-html img, .tv-modal-html iframe, .tv-modal-html video { max-width: 100%; }
.tv-modal-html a { color: var(--accent-ink, var(--accent)); }
.tv-modal-text { padding: 18px 20px 22px; }
.tv-modal-text h3 { margin: 0 0 8px; font-size: 17px; }
.tv-modal-text p { margin: 0; color: var(--dim); white-space: pre-wrap; }
.tv-modal-text a { display: inline-block; margin-top: 12px; color: var(--accent-ink, var(--accent)); }
.tv-modal-close {
	/* **그림 위에 있어야 한다.** 그림에 `will-change: transform` 이 붙으면서 그림이
	   쌓임 맥락을 만들어, 트리에서 뒤에 있는 그림이 닫기 버튼을 덮어 버렸다
	   (「엑스 버튼이 사라졌어」). z-index 를 줘서 늘 위에 둔다. */
	z-index: 2;
	position: absolute; right: 10px; top: 10px; width: 32px; height: 32px;
	display: grid; place-items: center; border: 0; border-radius: 50%;
	background: rgba(0, 0, 0, 0.45); color: #fff; cursor: pointer;
}
.tv-modal-close svg { width: 16px; height: 16px; }

/* ---------------------------------------------------------- 메뉴(스킨) */
/* 상·하·좌·우 어디에도 붙일 수 있다. 붙은 쪽 두께를 #ui 의 --menu-<위치> 로 알려
   주면 타이틀·미니맵·아래 묶음이 그만큼 비켜난다(겹치지 않게). */
/* 크기·글자·간격·색은 menu.js 가 --m-* 로 넣어 준다 (스튜디오에서 조절) */
.tv-menu {
	position: absolute; z-index: 4; display: flex;
	pointer-events: none;                      /* 빈 곳은 파노라마를 잡을 수 있게 */
	--m-size: 224px; --m-font: 13px; --m-gap: 2px; --m-radius: 8px; --m-pad: 8px;
	--m-bg: var(--panel); --m-fg: var(--text);
}
.tv-menu > * { pointer-events: auto; }
.tv-menu[hidden] { display: none; }

.tv-menu-panel {
	display: flex; flex-direction: column; gap: var(--m-gap);
	/* 드릴다운 판이 200% 폭이라 가로는 잘라내고 세로만 스크롤한다 */
	overflow-y: auto; overflow-x: hidden;
	padding: var(--m-pad, 8px); box-sizing: border-box;
	background: var(--m-bg); color: var(--m-fg); border: 1px solid var(--edge);
	backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
	/* 그림자 없음 — 큰 그림자를 깔면 메뉴 둘레에 검은 얼룩처럼 번진다 */
	transition: transform 0.34s var(--ease), opacity 0.24s;
	scrollbar-width: thin;
}
/* 로고 — 위·아래 여백을 설정에서 정한다(높낮이를 맞추는 손잡이다) */
.tv-menu-logo {
	display: block; margin: var(--m-logo-t, 2px) auto var(--m-logo-b, 8px);
	max-width: 100%; height: auto;
}
/* **메뉴 안 사업명.** 항목과 같은 결의 단단한 판으로 세운다 — 판 없는 메뉴에서는
   글자만 사진 위에 놓이면 안 읽힌다. 색은 「켜진 항목」을 따라간다. */
.tv-menu-title {
	/* 아래 항목과의 사이는 **항목끼리의 간격을 그대로** 따른다 — 간격 0 이면
	   딱 붙고, 그때 헷갈리지 않게 얇은 가름선을 둔다. */
	margin: 0 0 var(--m-gap, 6px);
	/* 위·아래는 **로고와 같은 「머리 여백」**을 쓴다(안 정했으면 10px) */
	padding: var(--m-logo-t, 10px) var(--m-ipad, 10px) var(--m-logo-b, 10px);
	box-shadow: inset 0 -1px 0 rgba(255, 255, 255, 0.22);
	border-radius: var(--m-radius, 8px);
	background: var(--m-item-bg-on, var(--m-item-bg, rgba(0, 0, 0, 0.35)));
	color: var(--m-fg-on, var(--m-fg, #fff));
	font-weight: 700; line-height: 1.25; letter-spacing: -0.01em;
	white-space: pre-line; word-break: keep-all;
}

/* ── 세로 (좌·우) ── */
.tv-menu.left, .tv-menu.right { top: 0; bottom: 0; align-items: stretch; }
.tv-menu.left { left: 0; flex-direction: row; }
.tv-menu.right { right: 0; flex-direction: row-reverse; }
.tv-menu.left .tv-menu-panel, .tv-menu.right .tv-menu-panel {
	width: var(--m-size); height: 100%;
}
.tv-menu.left .tv-menu-panel { border-width: 0 1px 0 0; }
.tv-menu.right .tv-menu-panel { border-width: 0 0 0 1px; }
/* **판 모양 — 내용만큼 / 판 없이.**
   기본은 변을 세로로 꽉 채우는 판이다. 조감 투어처럼 사진이 주인공인 짜임에서는
   그 판이 왼쪽을 통째로 덮어 버려, 버튼 두어 개 때문에 화면 한 자락을 잃는다.
   `fit` 은 **버튼만큼만** 차지하고, `none` 은 거기서 **판까지 지운다**(버튼만 뜬다).
   버튼이 사진 위에 바로 놓이므로 **항목 배경색**을 함께 정해 두어야 읽힌다. */
.tv-menu.left.pn-fit, .tv-menu.right.pn-fit,
.tv-menu.left.pn-none, .tv-menu.right.pn-none { bottom: auto; align-items: flex-start; }
.tv-menu.left.pn-fit .tv-menu-panel, .tv-menu.right.pn-fit .tv-menu-panel,
.tv-menu.left.pn-none .tv-menu-panel, .tv-menu.right.pn-none .tv-menu-panel {
	height: auto; max-height: calc(100vh - var(--head-h, 0px) - 24px);
}
.tv-menu.pn-none .tv-menu-panel {
	background: transparent; border: 0;
	backdrop-filter: none; -webkit-backdrop-filter: none;
}
.tv-menu.left.closed .tv-menu-panel { transform: translateX(-100%); }
.tv-menu.right.closed .tv-menu-panel { transform: translateX(100%); }

/* ── 가로 (상·하) ── */
.tv-menu.top, .tv-menu.bottom { left: 0; right: 0; flex-direction: column; }
/* 상단 띠를 켜면 메뉴는 그 아래 줄로 내려간다 */
.tv-menu.top { top: var(--head-h, 0px); }
.tv-menu.bottom { bottom: 0; flex-direction: column-reverse; }
/* **상단 띠 안에 얹은 메뉴**(`menu.inHead`) — 로고 오른쪽 같은 줄. 자리(left·top)와 띠 높이는
   menu.js `_placeInHead` 가 재서 넣는다. 띠 위에 떠야 하므로 띠(z 6)보다 한 칸 위,
   판은 띠 색이 비치게 투명하게. 자리가 모자라면 클래스가 빠져 예전처럼 띠 아래 줄로 간다. */
.tv-menu.top.inhead-on { right: 0; height: var(--inhead-h, auto); z-index: 7; justify-content: center; }
.tv-menu.top.inhead-on.inhead-b { justify-content: flex-end; }   /* 띠 아래쪽에 붙이기 */
.tv-menu.top.inhead-on .tv-menu-panel { background: transparent !important; border: 0; box-shadow: none; }
/* 가로 막대는 **내용에 딱 맞춘다.** 높이를 숫자로 정하면 남는 만큼 막대 안에
   빈 띠가 생긴다(위아래로 쓸데없는 여백). 높이는 글자 크기·항목 모양이 정하고,
   비켜날 여백은 실제로 그려진 높이를 재서 알려 준다(menu.js 의 ResizeObserver). */
.tv-menu.top .tv-menu-panel, .tv-menu.bottom .tv-menu-panel {
	width: 100%; height: auto; max-height: 60vh;
	/* 정해 둔 높이가 있으면 그만큼은 차지한다(0·빈칸이면 내용대로) — 남는
	   자리는 위아래로 고르게 나눠 글자가 가운데 앉는다 */
	min-height: var(--m-barh, 0px);
	display: flex; flex-direction: column; justify-content: center;
	/* 막대 양끝 — 옆 버튼(좌우 화살표)이 붙는 자리다. 폭을 설정에서 정한다. */
	padding-left: var(--m-side, 10px); padding-right: var(--m-side, 10px);
}
.tv-menu.top .tv-menu-panel { border-width: 0 0 1px; }
.tv-menu.bottom .tv-menu-panel { border-width: 1px 0 0; }
.tv-menu.top.closed .tv-menu-panel { transform: translateY(-100%); }
.tv-menu.bottom.closed .tv-menu-panel { transform: translateY(100%); }
.tv-menu.closed .tv-menu-panel { opacity: 0; }

/* ── 접기 손잡이 ──
   화면 구석에 따로 떠 있으면 무엇을 여는 버튼인지 알기 어렵다. 패널 가장자리
   한가운데에 붙여 서랍 손잡이처럼 만들고, 방향 화살표로 여닫는 쪽을 알린다. */
.tv-menu-toggle {
	position: absolute; z-index: 1; flex: 0 0 auto; margin: 0; padding: 0;
	display: grid; place-items: center;
	/* 반원 탭도 색을 정할 수 있다 — 안 정하면 막대 색을 그대로 쓴다 */
	background: var(--m-tg-bg, var(--m-bg, var(--panel)));
	color: var(--m-tg-fg, var(--m-fg, var(--text)));
	border: 1px solid var(--edge); cursor: pointer;
	backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
	/* 패널과 같은 곡선으로 함께 미끄러지도록 위치도 전환 대상에 넣는다 */
	transition: left 0.34s var(--ease),
		right 0.34s var(--ease),
		top 0.34s var(--ease),
		bottom 0.34s var(--ease),
		background 0.15s, color 0.15s, border-color 0.15s;
}
/* 세로 배치 — 패널 오른/왼 모서리 한가운데에 반원형 손잡이 */
.tv-menu.left .tv-menu-toggle, .tv-menu.right .tv-menu-toggle {
	top: 50%; margin-top: -27px; width: 22px; height: 54px;
}
.tv-menu.left .tv-menu-toggle {
	left: 100%; border-left: 0; border-radius: 0 9px 9px 0;
}
.tv-menu.right .tv-menu-toggle {
	right: 100%; border-right: 0; border-radius: 9px 0 0 9px;
}
/* **네모 손잡이.** 기본은 판 옆에 붙는 반원 탭이다. 각진 판(모서리 0)에
   반원이 붙으면 따로 논다 — 이 모양은 **사업명 줄과 같은 높이의 네모**로 서고,
   색을 뒤집어(흰 바탕 + 짙은 화살표) 판 밖에서도 또렷하게 보인다. */
.tv-menu.tg-square .tv-menu-toggle {
	border-radius: 0; border: 0;
	background: var(--m-tg-bg, #ffffff);
	/* 화살표 색 — 안 정하면 「켜진 항목」 색을 따른다 */
	color: var(--m-tg-fg, var(--m-item-bg-on, var(--m-item-bg, #333)));
	backdrop-filter: none; -webkit-backdrop-filter: none;
}
.tv-menu.left.tg-square .tv-menu-toggle, .tv-menu.right.tg-square .tv-menu-toggle {
	width: var(--m-tg-size, 44px); height: var(--m-tg-size, 44px);
	top: 0; margin-top: 0;
}
.tv-menu.tg-square .tv-menu-bars i {
	border-width: 0 var(--m-arrow-bw, 2.5px) var(--m-arrow-bw, 2.5px) 0;
}

/* **판이 짧으면 손잡이도 맨 위로.**
   변을 세로로 꽉 채우던 시절에는 한가운데가 손 닿기 좋았다. 그런데 버튼 몇 개만
   떠 있는 짜임(`fit`·`none`)에서는 판은 위에 있는데 손잡이만 허공 한가운데에
   동그마니 뜬다. 제목 줄 높이에 붙여 **한 덩어리로** 보이게 한다. */
.tv-menu.left.pn-fit .tv-menu-toggle, .tv-menu.right.pn-fit .tv-menu-toggle,
.tv-menu.left.pn-none .tv-menu-toggle, .tv-menu.right.pn-none .tv-menu-toggle {
	/* **높이는 여기서 정하지 않는다.** 예전에는 44px 로 박아 두었는데, 이 규칙이
	   네모 단추 규칙보다 뒤에 있어 **정사각으로 자라지 못했다**(한 변 50 을 넣어도
	   50×44). 자리만 맡기고 크기는 「단추 한 변」이 정하게 둔다. */
	top: 0; margin-top: 0;
}
/* 가로 배치 — 아래/위 모서리 한가운데 */
.tv-menu.top .tv-menu-toggle, .tv-menu.bottom .tv-menu-toggle {
	left: 50%; margin-left: -27px; width: 54px; height: 22px;
}
.tv-menu.top .tv-menu-toggle { top: 100%; border-top: 0; border-radius: 0 0 9px 9px; }
.tv-menu.bottom .tv-menu-toggle { bottom: 100%; border-bottom: 0; border-radius: 9px 9px 0 0; }

.tv-menu-toggle:hover { background: var(--accent); color: var(--on-accent, #0b0d10); border-color: var(--accent); }

/* 화살표 — 접히는 방향을 그대로 가리킨다 */
/* 화살표 한 변 — 굵기도 같이 따라 커진다(8px 에 1.7px 이 원래 비율) */
.tv-menu-bars { display: block; width: var(--m-arrow, 8px); height: var(--m-arrow, 8px); }
.tv-menu-bars i {
	/* **가운데로 되돌리는 값.** 갈매기표는 네모의 두 변(오른쪽·아래)으로 그리므로
	   그 덩어리의 무게중심이 네모 한가운데가 아니라 모서리 쪽으로 치우친다.
	   그냥 돌리면 단추 안에서 비뚤어 보인다 — 제 축 기준으로 되돌려 앉힌다.
	   (위·아래 메뉴에는 `-1px` 로 어림잡아 넣어 두었는데, 화살표 크기를 바꿀 수
	   있게 된 뒤로는 크기에 따라 같이 움직여야 맞다.) */
	/* **획의 무게중심을 단추 한가운데로 되돌리는 값** — `menu.js` 가 재어 넣는다.
	   갈매기표는 네모의 두 변으로 그리므로 획이 모서리 쪽으로 쏠린다. 되돌릴
	   거리는 「한 변 빼기 선 굵기」에 비례하는데, 굵기가 모양마다 달라
	   (기본 0.2125 · 네모 단추 0.31) **CSS 로 계산하면 중첩 calc 가 되어 변환이
	   통째로 무효가 됐다.** 그래서 px 값으로 받아만 쓴다. */
	display: block; width: 100%; height: 100%;
	border-right: var(--m-arrow-bw, 1.7px) solid currentColor;
	border-bottom: var(--m-arrow-bw, 1.7px) solid currentColor;
	transition: transform 0.3s var(--ease);
}
.tv-menu-bars i + i { display: none; }        /* 화살표는 한 개만 쓴다 */
/* **화살표는 「누르면 이렇게 된다」를 가리킨다.** 위·아래 메뉴는 그렇게 돼 있었는데
   좌·우만 거꾸로였다 — 왼쪽 메뉴가 펼쳐져 있으면 누를 때 **왼쪽으로 접히므로**
   `‹` 가 맞고, 접혀 있으면 오른쪽으로 펴지므로 `›` 다. */
.tv-menu.left  .tv-menu-bars i { transform: translate(var(--m-arrow-nudge, 1.7px), 0) rotate(135deg); }   /* ‹ 접기 */
.tv-menu.right .tv-menu-bars i { transform: translate(calc(var(--m-arrow-nudge, 1.7px) * -1), 0) rotate(-45deg); }   /* › 접기 */
.tv-menu.top   .tv-menu-bars i { transform: translate(0, var(--m-arrow-nudge, 1.7px)) rotate(-135deg); }
.tv-menu.bottom .tv-menu-bars i { transform: translate(0, calc(var(--m-arrow-nudge, 1.7px) * -1)) rotate(45deg); }
.tv-menu.left.closed  .tv-menu-bars i { transform: translate(calc(var(--m-arrow-nudge, 1.7px) * -1), 0) rotate(-45deg); }   /* › 펴기 */
.tv-menu.right.closed .tv-menu-bars i { transform: translate(var(--m-arrow-nudge, 1.7px), 0) rotate(135deg); }   /* ‹ 펴기 */
.tv-menu.top.closed   .tv-menu-bars i { transform: translate(0, calc(var(--m-arrow-nudge, 1.7px) * -1)) rotate(45deg); }
.tv-menu.bottom.closed .tv-menu-bars i { transform: translate(0, var(--m-arrow-nudge, 1.7px)) rotate(-135deg); }

/* 접혀 있을 때도 손잡이는 화면에 남아야 다시 열 수 있다 */
.tv-menu.closed .tv-menu-toggle { position: absolute; }
.tv-menu.left.closed .tv-menu-toggle { left: 0; }
.tv-menu.right.closed .tv-menu-toggle { right: 0; }
.tv-menu.top.closed .tv-menu-toggle { top: 0; }
.tv-menu.bottom.closed .tv-menu-toggle { bottom: 0; }

/* ── 평형(그룹) ── */
.tv-menu-group {
	display: flex; align-items: center; justify-content: space-between; gap: 8px;
	width: 100%; margin-top: 3px;
	/* 좌우 여백은 설정에서(--m-gpadx). 안 정하면 배치별 기본값을 그대로 쓴다 */
	padding: var(--m-gpad, 6px) var(--m-gpadx, 11px);
	border: 1px solid transparent; border-radius: var(--m-radius);
	background: transparent; color: var(--m-fg); opacity: 0.65; font: inherit;
	font-size: var(--m-gfont, 15px); font-weight: 700; letter-spacing: 0.01em; cursor: pointer;
	text-align: left; transition: background 0.15s, opacity 0.15s;
}
.tv-menu-group:hover { background: rgba(255, 255, 255, 0.07); opacity: 1; }
.tv-menu-group.on { opacity: 1; }
.tv-menu-caret {
	width: 7px; height: 7px; border-right: 1.6px solid currentColor;
	border-bottom: 1.6px solid currentColor; transform: rotate(-45deg);
	transition: transform 0.26s var(--ease);
}
.tv-menu-group.on .tv-menu-caret { transform: rotate(45deg); }

/* 접힘/펼침 — 높이로 처리해서 아래 항목이 자연스럽게 밀린다 */
.tv-menu-fold {
	max-height: 0; overflow: hidden; opacity: 0;
	transition: max-height 0.32s var(--ease), opacity 0.22s;
}
.tv-menu-fold.on { max-height: 70vh; opacity: 1; }

/* ── 장면 항목 ── */
.tv-menu-list { display: flex; flex-direction: column; gap: var(--m-gap); }
.tv-menu.top .tv-menu-list, .tv-menu.bottom .tv-menu-list {
	/* 가로 줄도 「항목 간격」을 따른다 (예전엔 6px 로 박혀 있어 설정이 안 먹었다) */
	flex-direction: row; gap: var(--m-gap); overflow-x: auto; scrollbar-width: none;
}
.tv-menu.top .tv-menu-list::-webkit-scrollbar,
.tv-menu.bottom .tv-menu-list::-webkit-scrollbar { display: none; }

.tv-menu-item {
	/* 여백은 설정에서 정한다 — 좌우(--m-ipad)는 「거실」 같은 이름 양옆,
	   상하(--m-ipady)는 줄 높이다. 평형 글자를 키우면 막대가 그만큼 높아지는데,
	   상하가 6px 로 박혀 있으면 장면 이름만 위아래로 붕 떠 보인다. */
	flex: 0 0 auto; padding: var(--m-ipady, 6px) var(--m-ipad, 10px);
	border: 0; border-radius: var(--m-radius);
	background: transparent; font: inherit; font-size: var(--m-font);
	/* 지정한 글자색(--m-fg)을 따른다 — var(--dim) 을 그대로 쓰면 글자색 설정이
	   아무 효과가 없다.
	   **흐리기(opacity)는 걸지 않는다.** 예전에는 「고르지 않은 항목은 0.66」이
	   적혀 있었지만, 바로 아래 등장 애니메이션이 `fill: both` 로 **opacity 를 1 에
	   못 박아** 화면에는 한 번도 나타난 적이 없다. 애니메이션을 「펼칠 때만」으로
	   옮기자 그 0.66 이 뒤늦게 살아나 **메뉴 단추가 비쳐 보였다**(사용자:
	   「메뉴 부분 투명해졌어」). 지금까지 보이던 모습이 맞는 모습이라 1 로 둔다. */
	color: var(--m-fg); opacity: 1;
	/* 배경은 설정에서(--m-item-bg). 안 정하면 투명 — 막대 색이 그대로 보인다 */
	background: var(--m-item-bg, transparent);
	text-align: left; white-space: nowrap; cursor: pointer;
	transition: background 0.15s, color 0.15s, padding-left 0.18s;
}
/* **펼쳐질 때만 위에서부터 차례로 스며든다.**
   예전에는 항목에 그냥 걸어 두어서, 장면을 옮겨 목록을 다시 그릴 때도(평형이
   다른 방으로 넘어갈 때) 전체가 한 번씩 흐렸다 진해졌다 — 층을 누를 때마다
   **깜빡이는 것처럼** 보였다. 이제 `menu.js` 가 손으로 목록을 바꾼 때만
   `anim-in` 을 붙인다. */
.tv-menu.anim-in .tv-menu-item {
	animation: tv-menu-in 0.34s both;
	animation-delay: calc(var(--i, 0) * 28ms);
}
@keyframes tv-menu-in {
	from { opacity: 0; transform: translateY(-4px); }
	to { opacity: 1; transform: none; }
}
/* 마우스 온 — 「켜짐」 색을 옅게(30%) 깐다. 켜진 항목과 같은 계열이라 지금 어디를
   가리키는지 바로 읽힌다. 이미 켜진 항목은 그대로 둔다(더 진해지면 눌린 것처럼 보인다). */
/* **세로 메뉴의 글자 정렬.** `al-*` 는 여태 가로 막대에서만 뜻이 있었다 —
   세로로 세운 메뉴에서도 가운데·오른쪽으로 세울 수 있어야 한다. */
.tv-menu.left.al-center .tv-menu-item, .tv-menu.right.al-center .tv-menu-item,
.tv-menu.left.al-center .tv-menu-title, .tv-menu.right.al-center .tv-menu-title {
	text-align: center;
}
.tv-menu.left.al-right .tv-menu-item, .tv-menu.right.al-right .tv-menu-item,
.tv-menu.left.al-right .tv-menu-title, .tv-menu.right.al-right .tv-menu-title {
	text-align: right;
}
/* **올린 색은 제 바탕 「위에」 깐다 — 갈아 끼우지 않는다.**
   예전에는 `background` 를 통째로 바꿔서, 「메뉴 배경(꺼짐)」을 칠해 둔 투어는
   마우스를 올리는 순간 그 색이 사라지고 반투명 물만 남아 **버튼이 투명해졌다**
   (판 없이 버튼만 쓰는 조감 투어에서는 사진이 그대로 비쳤다).
   바탕색은 그대로 두고 `background-image` 로 한 겹 얹는다. */
.tv-menu-item:not(.on):hover {
	background-image: linear-gradient(var(--m-item-hover, rgba(255, 255, 255, 0.09)),
		var(--m-item-hover, rgba(255, 255, 255, 0.09)));
	opacity: 1;
}
.tv-menu.left .tv-menu-item:hover, .tv-menu.right .tv-menu-item:hover {
	padding-left: calc(var(--m-ipad, 10px) + 6px);
}
/* 켜진 항목 — 배경·글자를 설정에서 따로 준다.
   안 정하면 지금까지처럼 강조색 바탕에 검정 글자다. */
.tv-menu-item.on {
	color: var(--m-fg-on, var(--on-accent, #0b0d10)); background: var(--m-item-bg-on, var(--accent));
	font-weight: 600; opacity: 1;
}
/* **켜진 장면을 밑줄로.** 레퍼런스 투어들이 쓰는 모양 — 바탕을 칠하지 않고
   막대 맨 아래에 굵은 선을 긋는다. 칠하기와 달리 짙은 막대에서도 글자가 안 묻힌다.
   선 색은 「메뉴 배경(켜짐)」 칸을 그대로 쓴다(안 고르면 켜짐 글자색). */
.tv-menu.io-underline .tv-menu-item { position: relative; }
.tv-menu.io-underline .tv-menu-item.on {
	background: none; color: var(--m-fg-on, var(--m-fg));
}
.tv-menu.io-underline .tv-menu-item.on::after {
	content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 3px;
	background: var(--m-item-bg-on, var(--m-fg-on, currentColor));
}
/* 세로 배치에서는 아래가 아니라 **왼쪽**에 긋는다 (아래는 다음 항목과 붙는다) */
.tv-menu.left.io-underline .tv-menu-item.on::after,
.tv-menu.right.io-underline .tv-menu-item.on::after {
	left: 0; right: auto; top: 0; bottom: 0; width: 3px; height: auto;
}

.tv-menu-tabs {
	display: flex; gap: 5px; margin-bottom: 4px; overflow-x: auto;
	scrollbar-width: none;
}
.tv-menu-tabs::-webkit-scrollbar { display: none; }
/* 평형은 장면보다 **크고 진하게** — 지금 어느 평형인지 한눈에 보여야 한다.
   크기(--m-gfont) · 줄 여백(--m-gpad) · 강조 방식(gs-*) 은 설정에서 정한다. */
.tv-menu-tab {
	/* 칸만 넓히고 그 안에서 글자 자리를 정한다 (둘 다 안 정하면 예전 그대로) */
	min-width: var(--m-gw, 0px); text-align: var(--m-galign, center);
	flex: 0 0 auto; padding: var(--m-gpad, 6px) var(--m-gpadx, 14px);
	border: 1px solid var(--edge); border-radius: var(--m-radius);
	background: transparent; color: var(--m-fg); opacity: 0.65; font: inherit;
	font-size: var(--m-gfont, 15px); font-weight: 700; letter-spacing: 0.01em;
	white-space: nowrap; cursor: pointer;
	transition: background 0.15s, opacity 0.15s, border-color 0.15s, color 0.15s;
}
.tv-menu-tab:hover { opacity: 1; border-color: rgba(255, 255, 255, 0.3); }
/* 켜진 평형 — 배경·글자를 설정에서(--m-gbg / --m-gfg). 안 정하면 강조색.
   **꺼짐 글자는 건드리지 않는다** — 막대 글자색을 따라야 어두운 바탕에 어두운
   글자가 되는 일이 없다. */
.tv-menu-tab.on {
	opacity: 1; border-color: var(--m-gbg, var(--accent));
	background: var(--m-gbg, rgba(124, 196, 255, 0.14));
	color: var(--m-gfg, inherit);
}

/* 평형 강조 방식 — 탭(가로)과 머리글(세로)에 똑같이 걸린다 */
.tv-menu.gs-fill .tv-menu-tab, .tv-menu.gs-fill .tv-menu-group { border-color: transparent; }
.tv-menu.gs-fill .tv-menu-tab.on, .tv-menu.gs-fill .tv-menu-group.on {
	background: var(--m-gbg, var(--accent)); color: var(--m-gfg, var(--on-accent, #0b0d10));
	border-color: transparent;
}
.tv-menu.gs-underline .tv-menu-tab, .tv-menu.gs-underline .tv-menu-group {
	border: 0; border-bottom: 3px solid transparent; border-radius: 0; background: none;
}
.tv-menu.gs-underline .tv-menu-tab.on, .tv-menu.gs-underline .tv-menu-group.on {
	border-bottom-color: var(--m-gbg, var(--accent));
	color: var(--m-gfg, var(--m-gbg, var(--accent-ink, var(--accent)))); background: none;
}
.tv-menu.gs-plain .tv-menu-tab, .tv-menu.gs-plain .tv-menu-group {
	border: 0; background: none;
}
.tv-menu.gs-plain .tv-menu-tab.on, .tv-menu.gs-plain .tv-menu-group.on {
	color: var(--m-gfg, var(--m-gbg, var(--accent-ink, var(--accent)))); background: none;
}

/* 탭을 막대 폭에 꽉 채우기 (레퍼런스 투어의 84A | 118A 처럼 반씩) */
.tv-menu.gfull .tv-menu-tabs { gap: 0; }
.tv-menu.gfull .tv-menu-tab { flex: 1 1 0; text-align: var(--m-galign, center); }
/* inline 배치에서는 「꽉 채우기」가 **막대 끝까지 채우는 것**을 뜻한다.
   패널 안쪽 여백(--m-side · --m-pad)만큼 밖으로 빼서 평형 색이 막대 왼쪽 끝과
   위·아래 모서리에 그대로 닿게 하고, 오른쪽은 구분선까지 채운다. */
/* 본문이 항목을 **가운데 정렬**하고 있어 평형 칸만 늘여도 줄 높이 계산에 걸려
   위·아래가 안 찼다. 여기서는 항목을 늘여 준다.
   **틈도 없앤다** — 「꽉 채우기」는 평형 칸이 구분선까지, 장면 줄이 그 바로 옆에서
   시작한다는 뜻이다. 붙어도 헷갈리지 않는 건 평형이 색 덩어리로 확실히 구분되고
   그 사이에 구분선이 있기 때문이다. */
.tv-menu.lay-inline.gfull .tv-menu-body { align-items: stretch; gap: 0; }
/* 막대의 테두리 1px 도 없앤다 — 「꽉 채우기」인데 위에 실선 한 줄이 남으면
   평형 색이 모서리에 안 닿는다. 막대는 제 배경색으로 이미 구분된다.
   (패널이 overflow 를 자르므로 음수 여백으로는 테두리를 덮을 수 없다) */
.tv-menu.top.lay-inline.gfull .tv-menu-panel,
.tv-menu.bottom.lay-inline.gfull .tv-menu-panel { border-width: 0; }
.tv-menu.lay-inline.gfull .tv-menu-tabs {
	align-self: stretch;
	margin: calc(var(--m-pad, 8px) * -1) 0 calc(var(--m-pad, 8px) * -1)
		calc(var(--m-side, 10px) * -1);
	/* 구분선까지 색이 닿게 안쪽 여백을 없앤다. 장면과 붙지 않는 것은 본문의
	   gap(최소 10px)이 지켜 주므로 「현관」이 평형에 달라붙지 않는다. */
	padding-right: 0;
}
.tv-menu.lay-inline.gfull .tv-menu-tab {
	align-self: stretch; display: flex; align-items: center;
	justify-content: var(--m-gjust, center);
}
/* **평형과 방이 한 줄로 읽히던 것을 고친다.**
   위에서 `gap: 0` 을 준 것은 「평형 색이 구분선까지 닿게」 하려는 뜻이었는데,
   바로 아래 주석은 「장면과 붙지 않는 것은 본문의 gap(최소 10px)이 지켜 준다」고
   적혀 있었다 — **그 gap 을 같은 규칙이 0 으로 만들어 놓고** 그것에 기대고 있었다.
   그래서 실측 0px, 「59B 거실 침실1」이 한 덩어리로 보였다.

   틈은 **장면 줄 쪽에서** 준다(막대 끝 여백·화살표 자리와 겹치지 않게 바깥 여백으로).
   구분선도 진하게 — `--edge` 는 흰색 12% 라 색 있는 막대 위에서는 안 보인다. */
.tv-menu.lay-inline.gfull { --row-gap-l: max(10px, var(--m-side, 10px)); }
.tv-menu.lay-inline.gfull .tv-menu-tabs { border-right-color: rgba(0, 0, 0, 0.3); }
/* 오른쪽 정렬은 좌우가 뒤집힌다 — 왼쪽 여백 대신 오른쪽에 준다 */
.tv-menu.al-right.lay-inline.gfull { --row-gap-l: 0px; }
.tv-menu.al-right.lay-inline.gfull .tv-menu-scroll.is-row {
	margin-right: max(10px, var(--m-side, 10px));
}
/* 오른쪽 정렬이면 반대쪽 끝을 채운다 (본문이 row-reverse 다) */
.tv-menu.al-right.lay-inline.gfull .tv-menu-tabs {
	margin: calc(var(--m-pad, 8px) * -1) calc(var(--m-side, 10px) * -1)
		calc(var(--m-pad, 8px) * -1) 0;
	padding-right: 0; padding-left: 0;
}
.tv-menu-empty { padding: 12px 10px; color: var(--dim); font-size: 12px; }

/* 장면 줄 왼쪽의 평형 이름 (레퍼런스 투어의 「84A 현관 복도 …」 형태).
   이름표는 **스크롤되는 줄 밖**에 두고 줄만 넘어가게 한다 — 안에 넣으면 넘겨 볼 때
   이름이 왼쪽으로 밀려 화살표 버튼에 덮인다. */
.tv-menu-rowbox { display: flex; align-items: stretch; min-width: 0; }
.tv-menu-rowbox > .tv-menu-scroll { flex: 1; min-width: 0; }
.tv-menu-glabel {
	flex: 0 0 auto; align-self: stretch; display: flex; align-items: center;
	padding: 0 var(--m-gpadx, 14px); margin-right: max(10px, var(--m-side, 10px));
	background: var(--accent); color: var(--on-accent, #0b0d10);
	font-size: var(--m-gfont, 15px); font-weight: 700; white-space: nowrap;
}
.tv-menu.al-right .tv-menu-glabel { margin: 0 0 0 max(10px, var(--m-side, 10px)); order: 9; }

/* ── 메뉴가 차지한 만큼 다른 UI 가 비켜난다 ── */
.tv-title {
	margin-left: var(--menu-left, 0); margin-right: var(--menu-right, 0);
	margin-top: calc(var(--head-h, 0px) + var(--menu-top, 0px));
	transition: margin 0.34s var(--ease);
}
#ui .tv-dock {
	padding-left: var(--menu-left, 0); padding-right: var(--menu-right, 0);
	margin-bottom: var(--menu-bottom, 0);
	transition: padding 0.34s var(--ease),
		margin 0.34s var(--ease);
}
.tv-map {
	margin-right: var(--menu-right, 0); margin-top: calc(var(--head-h, 0px) + var(--menu-top, 0px));
	margin-left: var(--menu-left, 0); margin-bottom: var(--menu-bottom, 0);
	transition: margin 0.34s var(--ease);
}
/* 버튼이 설 자리는 **모서리 간격(`--map-my`)에 얹어** 벌린다 — `ui.js` 참조.
   여백(margin)으로 밀면 「모서리에서 그대로」가 `margin: 0 !important` 로 죽인다. */

/* -------------------------------------------------------------- 모바일 */
@media (max-width: 640px) {
	/* 폰에서 평면도는 **화면 가로의 60%**. 46% 로 두었더니 도면이 손톱만 해져
	   방 위치를 짚을 수가 없었다(도면은 작으면 아무 쓸모가 없다).
	   상한과 하한을 같이 줘서 **모든 투어가 폰에서 같은 크기**로 보인다 —
	   투어마다 정해 둔 「크기」는 넓은 화면에서만 쓰인다. */
	.tv-map { --map-max: 60vw; --map-min: 60vw; }
	/* 「LX 폰」 — **아래에 떠 있는 자유 자리 바와 평면도가 만나지 않게.**
	   폰에선 평면도가 60vw 로 커져 가운데 바(⟳ 🗺 ⛶ ⋯)와 거의 늘 겹친다.
	   바 윗변(--bar-lift, ui.js `_measureBarLift`) + 8px 보다 아래로는 안 내려간다.
	   PC 는 손대지 않는다(넓어서 안 만나고, 정해 둔 자리를 지킨다). */
	.tv-map.at-free {
		--in-b: max(calc(var(--map-my, 16px) + var(--menu-bottom, 0px) + var(--legal-h, 0px)),
			calc(var(--bar-lift, 0px) + 8px));
	}
	.tv-map.at-bl, .tv-map.at-bc, .tv-map.at-br {
		bottom: max(calc(var(--map-my, 16px) + var(--dock-h, 0px)), calc(var(--bar-lift, 0px) + 8px));
	}
	/* **메뉴 — 평형 칸이 폰 폭의 절반을 먹지 않게.** 「평형 칸 폭」(--m-gw)은 PC 기준이라
	   LX(196px)는 375px 폰에서 방 이름 자리가 150px 뿐 — 「현관」 하나만 보였다.
	   폰에선 화면 30% 까지만, 방 이름 좌우 여백도 12px 까지만. */
	.tv-menu-tab { min-width: min(var(--m-gw, 0px), 30vw); }
	.tv-menu-item {
		padding-left: min(var(--m-ipad, 10px), 12px); padding-right: min(var(--m-ipad, 10px), 12px);
	}
	.tv-thumb { width: 104px; }
	.tv-thumb img { height: 66px; }
	.tv-btn { width: 36px; height: 36px; }
	.tv-title { font-size: 15px; padding: 14px 16px 28px; }
}

/* ------------------------------------------------- 화면이 낮을 때(가로 폰) */
/* 아래 묶음(썸네일+바)과 평면도가 서로 닿지 않도록 둘 다 함께 줄인다. */
@media (max-height: 620px) {
	/* 낮은 화면에서는 하한을 푼다 — 아래 바·썸네일과 겹친다 */
	.tv-map { --map-max: min(210px, 34vw); --map-min: 0px; }
	.tv-thumb { width: 104px; }
	.tv-thumb img { height: 58px; }
	.tv-dock { gap: 8px; }
}
@media (max-height: 460px) {
	.tv-map { --map-max: min(140px, 24vw); --map-min: 0px; }
	.tv-thumb { width: 92px; font-size: 10px; }
	.tv-thumb img { height: 48px; }
	.tv-btn { width: 34px; height: 34px; }
	.tv-title { padding: 10px 14px 22px; }
}

/* ═══════════════════════════════════════════════ 버튼 스타일 프리셋
   settings.ui.buttonStyle 이 #ui 에 btn-<이름> 클래스를 붙인다.
   **네 곳이 저마다 제 모양을 갖는다** — 컨트롤 바 · 메뉴 · 평면도 · 썸네일 바.
   그래서 규칙을 `#ui.btn-…` 이 아니라 **그 요소에** 건다(`.tv-bar.bs-square` 처럼).
   `#ui` 에 걸어 두면 한 벌만 가능하고, 하나만 다르게 하려 해도 셈이 세서 안 먹는다.
   어느 모양을 입을지는 `ui.js` 가 정한다(각자 값이 없으면 「한 벌」을 따른다). */

/* ── pill (기본) ── 지금까지의 모습. 규칙은 위쪽 기본 스타일이 그대로 담당한다 */

/* ── square ── 각진 사각. 도면·건축 느낌 */
.tv-bar.bs-square { border-radius: 4px; padding: 4px; }
.tv-bar.bs-square .tv-btn { border-radius: 3px; }
.tv-menu.bs-square .tv-menu-panel,
.tv-menu.bs-square .tv-menu-toggle { border-radius: 0 !important; }
.tv-menu.bs-square .tv-menu-item, .tv-menu.bs-square .tv-menu-group { border-radius: 0; }
.tv-map.bs-square { border-radius: 4px; }
.tv-thumbs.bs-square .tv-thumb { border-radius: 2px; }

/* ── minimal ── 판을 없애고 아이콘만. 파노라마를 가장 적게 가린다 */
.tv-bar.bs-minimal {
	background: none; border-color: transparent; backdrop-filter: none;
	-webkit-backdrop-filter: none; gap: 6px;
}
/* 판이 없으니 밝은 바닥 위에서 아이콘이 묻힌다 — 그림자를 두 겹으로 세게 준다 */
.tv-bar.bs-minimal .tv-btn {
	filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.95))
		drop-shadow(0 0 9px rgba(0, 0, 0, 0.7));
}
.tv-bar.bs-minimal .tv-btn:hover { background: rgba(255, 255, 255, 0.16); }
.tv-menu.bs-minimal .tv-menu-panel { background: rgba(8, 9, 12, 0.44); border-color: transparent; }
.tv-menu.bs-minimal .tv-menu-toggle { border-color: transparent; }
.tv-map.bs-minimal { background: rgba(8, 9, 12, 0.44); border-color: transparent; }
.tv-thumbs.bs-minimal .tv-thumbs-inner { background: none; }

/* ── outline ── 테두리만 있는 선 스타일 */
.tv-bar.bs-outline { background: rgba(8, 9, 12, 0.34); border-color: currentColor; }
.tv-bar.bs-outline .tv-btn { border: 1px solid var(--edge); }
.tv-bar.bs-outline .tv-btn:hover { border-color: var(--accent-ink, var(--accent)); color: var(--accent-ink, var(--accent)); background: none; }
.tv-bar.bs-outline .tv-btn.on { border-color: var(--accent-ink, var(--accent)); color: var(--accent-ink, var(--accent)); background: none; }
.tv-menu.bs-outline .tv-menu-item { border: 1px solid transparent; }
.tv-menu.bs-outline .tv-menu-item:hover { border-color: var(--edge); background: none; }
.tv-menu.bs-outline .tv-menu-item.on {
	background: none; border-color: var(--accent-ink, var(--accent)); color: var(--accent-ink, var(--accent));
}
.tv-map.bs-outline { background: rgba(8, 9, 12, 0.34); border-color: currentColor; }
.tv-thumbs.bs-outline .tv-thumb.on { outline-color: var(--accent-ink, var(--accent)); }

/* ── solid ── 강조색으로 꽉 채운 버튼. 눈에 가장 잘 띈다 */
.tv-bar.bs-solid { padding: 5px; gap: 5px; }
.tv-bar.bs-solid .tv-btn { background: rgba(255, 255, 255, 0.1); }
.tv-bar.bs-solid .tv-btn:hover { background: var(--accent-fill, var(--accent)); color: var(--on-fill, #0b0d10); }
.tv-bar.bs-solid .tv-btn.on { background: var(--accent-fill, var(--accent)); color: var(--on-fill, #0b0d10); }
.tv-menu.bs-solid .tv-menu-toggle { background: var(--accent); color: var(--on-accent, #0b0d10); border-color: var(--accent); }
.tv-menu.bs-solid .tv-menu-group.on { background: rgba(255, 255, 255, 0.08); }

/* ── glass ── 유리판. 흐림을 세게 주고 테두리를 밝게 */
/* 흰 유리로 만들면 밝은 파노라마 위에서 흰 글자가 묻힌다 — 어두운 유리로 간다 */
.tv-bar.bs-glass, .tv-menu.bs-glass .tv-menu-panel, .tv-map.bs-glass,
.tv-thumbs.bs-glass .tv-thumbs-inner {
	background: rgba(18, 21, 27, 0.34);
	border-color: rgba(255, 255, 255, 0.3);
	backdrop-filter: blur(24px) saturate(1.5);
	-webkit-backdrop-filter: blur(24px) saturate(1.5);
}
.tv-menu.bs-glass .tv-menu-toggle {
	background: rgba(18, 21, 27, 0.42); border-color: rgba(255, 255, 255, 0.3);
}
.tv-bar.bs-glass .tv-btn:hover { background: rgba(255, 255, 255, 0.24); }

/* **항목 사이 구분선.** 「항목 사이」(간격)만으로는 나뉘어 보이지 않을 때,
   실선 한 줄을 사이에 긋는다. 세로 메뉴는 위쪽에, 가로 막대는 왼쪽에 붙는다 —
   맨 앞 항목에는 안 붙는다. 평형 머리글 사이에도 같은 줄이 간다.
   버튼 모양(`bs-outline` 등)이 테두리를 만지므로 **그 뒤에** 둔다. */
.tv-menu.has-line .tv-menu-item + .tv-menu-item,
.tv-menu.has-line .tv-menu-group + .tv-menu-group,
.tv-menu.has-line .tv-menu-fold + .tv-menu-group {
	border-top: var(--m-line, 1px) solid var(--m-line-c, rgba(255, 255, 255, 0.18));
}
.tv-menu.has-line.top .tv-menu-item + .tv-menu-item,
.tv-menu.has-line.bottom .tv-menu-item + .tv-menu-item,
.tv-menu.has-line.top .tv-menu-group + .tv-menu-group,
.tv-menu.has-line.bottom .tv-menu-group + .tv-menu-group {
	border-top: 0;
	border-left: var(--m-line, 1px) solid var(--m-line-c, rgba(255, 255, 255, 0.18));
}

/* ── 메뉴 항목 스타일: 썸네일 + 제목 ── */
.tv-menu-list.thumbs .tv-menu-item {
	display: flex; align-items: center; gap: 8px; padding: 4px 6px; white-space: normal;
}
.tv-menu-list.thumbs .tv-menu-item img {
	width: 46px; height: 30px; flex: 0 0 auto; object-fit: cover;
	border-radius: calc(var(--m-radius) - 3px); background: #0a0c0f;
}
.tv-menu-list.thumbs .tv-menu-item span {
	flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* 가로 배치에서는 썸네일 위에 제목을 얹어 한 줄 높이를 지킨다 */
.tv-menu.top .tv-menu-list.thumbs .tv-menu-item,
.tv-menu.bottom .tv-menu-list.thumbs .tv-menu-item {
	flex-direction: column; gap: 3px; padding: 3px;
}
.tv-menu.top .tv-menu-list.thumbs .tv-menu-item img,
.tv-menu.bottom .tv-menu-list.thumbs .tv-menu-item img { width: 62px; height: 38px; }
.tv-menu.top .tv-menu-list.thumbs .tv-menu-item span,
.tv-menu.bottom .tv-menu-list.thumbs .tv-menu-item span { max-width: 62px; font-size: 0.85em; }


/* **판을 닫아도 자리는 남긴다.** 위에 상주하는 토글 버튼이 판의 자리를 재서
   따라다니므로 `display: none` 으로 지우면 버튼이 갈 곳을 잃는다. */
.tv-map.closed { visibility: hidden; pointer-events: none; }

/* 「평면도 닫기 ›」 — 판 **바깥**에 붙는 글자 버튼.
   상단바의 작은 ✕ 를 못 찾는 분들이 있어 본보기 투어처럼 하나 더 둔다.
   판을 기준으로 붙으므로 판을 어디로 옮겨도 따라간다.
   위가 좁으면 `ui.js` 의 `_placeMapHide()` 가 `.below` 를 붙여 **아래로** 돌린다. */
.tv-map-hide {
	/* 자리는 `ui.js` 의 `_placeMapHide()` 가 판을 재서 넣는다 — 판의 자식으로 두면
	   `overflow: hidden` 에 잘리므로 UI 뿌리에 두고 좌표로 따라간다. */
	position: absolute; left: 0; top: 0; z-index: 3;
	padding: 7px 12px; border: 0; border-radius: 3px;
	background: var(--map-bar, var(--accent)); color: var(--map-bar-fg, #fff);
	font: inherit; font-size: 12.5px; font-weight: 600; letter-spacing: -0.2px;
	white-space: nowrap; cursor: pointer; pointer-events: auto;
	box-shadow: 0 2px 10px rgba(0, 0, 0, 0.22);
	transition: filter 0.15s;
}
.tv-map-hide:hover { filter: brightness(1.12); }
/* 닫혀 있을 때 — 같은 자리에 그대로 있되 **한 톤 죽인다.** 없어지면 다시 열 길이
   컨트롤 바 아이콘뿐이라, 이 버튼이 곧 여는 문이다. */
.tv-map-hide.off { opacity: 0.82; }
.tv-map-hide.off:hover { opacity: 1; }
.tv-map-hide[hidden] { display: none; }

/* 미니맵 끌기 — 「자유 위치」일 때 상단바를 잡아 옮긴다 */
.tv-map.movable .tv-map-tabs { cursor: grab; }
.tv-map.movable .tv-map-tabs button { cursor: pointer; }
.tv-map.dragging, .tv-map.dragging .tv-map-tabs { cursor: grabbing; }
.tv-map.dragging { opacity: 0.94; }
/* 자유 위치는 보는 사람이 놓은 그 자리다 — 메뉴 회피 여백을 적용하지 않는다.
   (끌기 시작할 때 여백이 빠지면 지도가 그만큼 옆으로 튀어 커서에서 도망간다) */
.tv-map.at-free { margin: 0 !important; }
/* 모서리에서 그대로 띄우기 — 메뉴도 아래 바도 비켜나지 않는다 */
/* **「모서리에서 그대로」가 무시하는 것은 아래 바(썸네일·컨트롤)뿐이다.**
   메뉴까지 무시하면 상단 메뉴 위에 판이 그대로 얹혀 둘 다 못 읽는다 —
   「여백을 모서리에서 잰다」는 말이 「메뉴를 덮어도 된다」는 뜻은 아니다.
   그래서 **닿는 쪽의 메뉴 인셋만** 되살린다(반대쪽은 0 이라 자리에 영향이 없다). */
.tv-map.edge-exact { margin: 0 !important; }
.tv-map.edge-exact.at-tl, .tv-map.edge-exact.at-tc, .tv-map.edge-exact.at-tr,
.tv-map.edge-exact.at-ml, .tv-map.edge-exact.at-mc, .tv-map.edge-exact.at-mr {
	margin-top: calc(var(--head-h, 0px) + var(--menu-top, 0px)) !important;
}
.tv-map.edge-exact.at-ml, .tv-map.edge-exact.at-mc, .tv-map.edge-exact.at-mr,
.tv-map.edge-exact.at-bl, .tv-map.edge-exact.at-bc, .tv-map.edge-exact.at-br {
	margin-bottom: var(--menu-bottom, 0) !important;
}
.tv-map.edge-exact.at-tl, .tv-map.edge-exact.at-ml, .tv-map.edge-exact.at-bl {
	margin-left: var(--menu-left, 0) !important;
}
.tv-map.edge-exact.at-tr, .tv-map.edge-exact.at-mr, .tv-map.edge-exact.at-br {
	margin-right: var(--menu-right, 0) !important;
}
.tv-map.edge-exact.at-bl, .tv-map.edge-exact.at-bc, .tv-map.edge-exact.at-br {
	bottom: var(--map-my, 16px);
}
.tv-map.dragging { transition: none !important; }
/* 자유 위치에서는 상단바가 손잡이임을 알 수 있게 살짝 구분해 준다 */
.tv-map.movable .tv-map-tabs::before {
	content: ''; width: 18px; height: 3px; border-radius: 2px; flex: 0 0 auto;
	background: currentColor; opacity: 0.3; margin-right: 4px;
}

/* ── 한 단계 들어가기(드릴다운) — 두 판을 나란히 두고 통째로 민다 ── */
.tv-menu-stage {
	display: flex; width: 200%; overflow: hidden;
	transition: transform 0.32s var(--ease);
}
.tv-menu-stage.in { transform: translateX(-50%); }
.tv-menu-pane {
	width: 50%; flex: 0 0 50%; box-sizing: border-box;
	display: flex; flex-direction: column; gap: var(--m-gap);
}
/* 오른쪽으로 들어가는 화살표 */
.tv-menu-next {
	width: 6px; height: 6px; flex: 0 0 auto;
	border-right: 1.6px solid currentColor; border-bottom: 1.6px solid currentColor;
	transform: rotate(-45deg);
}
/* 뒤로 가기 */
.tv-menu-back {
	display: flex; align-items: center; gap: 8px; width: 100%;
	padding: 6px 9px; margin-bottom: 2px; border: 0; border-radius: var(--m-radius);
	background: transparent; color: var(--m-fg); font: inherit;
	font-size: var(--m-font); font-weight: 600; cursor: pointer; text-align: left;
	transition: background 0.15s;
}
.tv-menu-back:hover { background: rgba(255, 255, 255, 0.09); }
.tv-menu-prev {
	width: 6px; height: 6px; flex: 0 0 auto;
	border-left: 1.6px solid currentColor; border-bottom: 1.6px solid currentColor;
	transform: rotate(45deg);
}

/* ── 가로 배치의 장면 줄 — 탭을 다시 누르면 슬라이드로 접힌다 ── */
.tv-menu-row {
	max-height: 0; opacity: 0; overflow: hidden;
	transition: max-height 0.3s var(--ease), opacity 0.2s;
}
.tv-menu-row.on { max-height: 30vh; opacity: 1; }

/* ══════════════════════ 상·하 메뉴의 줄 배치 · 정렬 ══════════════════════ */

/* 정렬 — 평형 탭 줄과 장면 줄을 함께 좌/중앙/우로 */
.tv-menu.al-left .tv-menu-tabs, .tv-menu.al-left .tv-menu-list { justify-content: flex-start; }
.tv-menu.al-center .tv-menu-tabs, .tv-menu.al-center .tv-menu-list { justify-content: center; }
.tv-menu.al-right .tv-menu-tabs, .tv-menu.al-right .tv-menu-list { justify-content: flex-end; }
/* **넘치면 가운데 정렬을 접는다.** 좁은 화면(휴대폰)에서는 장면이 막대보다 길어지는데,
   그때 `center` 로 두면 넘친 만큼이 **양쪽으로** 밀려 나가 왼쪽 끝(첫 장면 「거실1」)이
   잘린 채 **스크롤로도 닿지 않는다.** `safe` 를 붙이면 넘칠 때만 왼쪽부터로 돌아간다.
   `safe` 를 모르는 브라우저는 위 줄(가운데)을 그대로 쓴다. */
.tv-menu.al-center .tv-menu-tabs, .tv-menu.al-center .tv-menu-list { justify-content: safe center; }
.tv-menu.al-right .tv-menu-tabs, .tv-menu.al-right .tv-menu-list { justify-content: safe flex-end; }

/* inline — 그룹명이 장면 줄 **왼쪽**에 나란히 붙는다 */
/* 평형과 장면 사이는 **절대 붙지 않는다.** 막대 양끝을 0 으로 줄이면 이 틈까지
   0 이 돼 「현관」이 평형 탭에 붙어 같은 줄 항목처럼 보였다 (특히 항목 좌우 여백을
   키웠을 때). 최소 10px 은 남기고, 그보다 크게 잡으면 그 값을 따른다. */
.tv-menu.lay-inline .tv-menu-body {
	display: flex; flex-direction: row; align-items: center;
	gap: max(10px, var(--m-side, 10px));
}
.tv-menu.lay-inline .tv-menu-tabs {
	margin: 0; flex: 0 0 auto; border-right: 1px solid var(--edge);
	padding-right: max(10px, var(--m-side, 10px));
}
/* 폭 배분은 **감싸개**끼리 해야 한다. 줄(list)에만 flex 를 걸어 두면 감싸개가
   내용보다 좁게 눌리고, 줄이 감싸개 밖으로 삐져나가 옆 칸(평형 탭)을 침범한다 —
   그 위에 얹힌 화살표 버튼이 평형 탭을 덮어 보였던 진짜 이유다. */
.tv-menu.lay-inline .tv-menu-scroll.is-tabs { flex: 0 0 auto; }
.tv-menu.lay-inline .tv-menu-scroll.is-row { flex: 1 1 0; min-width: 0; }
.tv-menu.lay-inline .tv-menu-row { flex: 1; min-width: 0; max-height: none; opacity: 1; }
.tv-menu.al-right.lay-inline .tv-menu-body { flex-direction: row-reverse; }
/* **평형 자리를 따로 정한 경우**는 정렬보다 이쪽이 이긴다 —
   「방 이름은 오른쪽 정렬, 평형은 왼쪽」 같은 짜임이 안 되던 것을 푼다. */
.tv-menu.gside-left.lay-inline .tv-menu-body { flex-direction: row; }
.tv-menu.gside-right.lay-inline .tv-menu-body { flex-direction: row-reverse; }
/* 자리를 뒤집으면 **구분선·여백도 따라 뒤집어야** 한다 — 안 그러면 선이
   평형 바깥쪽(막대 끝)에 그어지고 방 이름이 평형에 달라붙는다. */
.tv-menu.gside-left.lay-inline .tv-menu-tabs {
	border-right: 1px solid var(--edge); border-left: 0;
	padding-right: max(10px, var(--m-side, 10px)); padding-left: 0;
}
.tv-menu.gside-left.lay-inline.gfull {
	--row-gap-l: max(10px, var(--m-side, 10px));
}
.tv-menu.gside-left.lay-inline.gfull .tv-menu-tabs {
	margin: calc(var(--m-pad, 8px) * -1) 0 calc(var(--m-pad, 8px) * -1)
		calc(var(--m-side, 10px) * -1);
	padding-right: 0;
}
.tv-menu.gside-left.lay-inline.gfull .tv-menu-scroll.is-row { margin-right: 0; }

.tv-menu.gside-right.lay-inline .tv-menu-tabs {
	border-right: 0; border-left: 1px solid var(--edge);
	padding-right: 0; padding-left: max(10px, var(--m-side, 10px));
}
.tv-menu.gside-right.lay-inline.gfull { --row-gap-l: 0px; }
.tv-menu.gside-right.lay-inline.gfull .tv-menu-tabs {
	margin: calc(var(--m-pad, 8px) * -1) calc(var(--m-side, 10px) * -1)
		calc(var(--m-pad, 8px) * -1) 0;
	padding-right: 0; padding-left: 0;
}
.tv-menu.gside-right.lay-inline.gfull .tv-menu-scroll.is-row {
	margin-right: max(10px, var(--m-side, 10px));
}
.tv-menu.al-right.lay-inline .tv-menu-tabs {
	border-right: 0; padding-right: 0;
	border-left: 1px solid var(--edge); padding-left: max(10px, var(--m-side, 10px));
}

/* split — 평형은 화면 맨 위, 장면은 화면 맨 아래로 갈라놓는다.
   틀이 화면 전체를 덮으므로 **마우스를 통과시켜야** 한다. 안 그러면 가운데
   파노라마를 잡고 돌릴 수가 없다(#ui > * 가 auto 로 켜 놓기 때문에 꺼 줘야 한다).
   실제로 누를 수 있어야 하는 두 띠만 다시 켠다. */
/* 갈라놓은 배치는 화면을 위아래로 다 쓴다 — 다만 **상단 띠 아래**부터다
   (띠를 켜면 위 평형 줄이 띠 밑으로 숨어 안 보였다) */
.tv-menu.lay-split { top: var(--head-h, 0px); bottom: 0; }
/* #ui > * 가 pointer-events:auto 를 id 로 걸어 두므로 여기도 #ui 를 붙여야 이긴다 */
#ui .tv-menu.lay-split { pointer-events: none; }
#ui .tv-menu.lay-split .tv-menu-toggle { pointer-events: auto; }
/* 갈라놓은 배치의 판은 **화면 전체를 덮는 빈 틀**이다. 배경도 흐림도 있으면 안 된다.
   버튼 스타일(#ui.btn-glass 등)이 셈이 더 세서 여길 덮어쓰는 바람에, 「화면 위아래로」로
   바꾸는 순간 파노라마 전체가 흐려지고 어두운 판이 씌워졌다 — 아무것도 안 바뀐 것처럼
   보였다. 스타일 프리셋보다 세게 못 박는다. */
.tv-menu.lay-split .tv-menu-panel {
	height: 100%; max-height: none; padding: 0;
	background: none !important; border: 0 !important;
	backdrop-filter: none !important; -webkit-backdrop-filter: none !important;
	box-shadow: none !important;
	pointer-events: none;               /* 가운데 빈 곳은 파노라마를 잡을 수 있게 */
	gap: 0; border-radius: 0;
}
/* 대신 위·아래 두 띠가 그 스타일을 이어받는다 */
.tv-menu.bs-glass.lay-split .tv-menu-tabs,
.tv-menu.bs-glass.lay-split .tv-menu-row,
.tv-menu.bs-glass.lay-split .tv-menu-rowbox {
	background: rgba(18, 21, 27, 0.34);
	border-color: rgba(255, 255, 255, 0.3);
	backdrop-filter: blur(24px) saturate(1.5);
	-webkit-backdrop-filter: blur(24px) saturate(1.5);
}
.tv-menu.bs-minimal.lay-split .tv-menu-tabs,
.tv-menu.bs-minimal.lay-split .tv-menu-row,
.tv-menu.bs-minimal.lay-split .tv-menu-rowbox {
	background: rgba(8, 9, 12, 0.44); border-color: transparent;
}
/* 접으면 위 줄은 위로, 아래 줄은 아래로 각각 빠진다 */
.tv-menu.lay-split.closed .tv-menu-tabs { transform: translateY(-110%); }
.tv-menu.lay-split.closed .tv-menu-row { transform: translateY(110%); }
.tv-menu.lay-split .tv-menu-tabs, .tv-menu.lay-split .tv-menu-row {
	transition: transform 0.32s var(--ease);
}
.tv-menu.lay-split .tv-menu-body {
	height: 100%; display: flex; flex-direction: column; justify-content: space-between;
}

.tv-menu.lay-split .tv-menu-tabs, .tv-menu.lay-split .tv-menu-row {
	pointer-events: auto; margin: 0;
	padding: var(--m-pad, 8px) var(--m-side, 10px);
	background: var(--m-bg); backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
	max-height: none; opacity: 1;
}
.tv-menu.lay-split .tv-menu-tabs { border-bottom: 1px solid var(--edge); }
.tv-menu.lay-split .tv-menu-row { border-top: 1px solid var(--edge); }
/* **아래 줄은 언제나 아래에 붙는다.**
   `space-between` 은 아이가 둘일 때만 위·아래로 갈라 준다. 평형 줄을 끄면
   (「메뉴 바에 평형 줄 표시」 해제) 남은 장면 줄 하나가 **맨 위로 올라가** 상단 띠
   밑에 깔려 사라진 것처럼 보였다. 자리를 아이 수에 맡기지 않는다.
   장면 줄은 스크롤 상자에 한 번 싸여 있으므로 **몸통의 마지막 아이**를 밀어야 한다
   (줄 자체에 걸면 아무 일도 안 일어난다 — 그 아이는 상자다). */
#ui .tv-menu.lay-split .tv-menu-body > :last-child:not(:first-child) { margin-top: auto; }
/* **한 줄만 남으면 「위치」 설정을 따른다.** 평형 줄을 끄면 갈라놓을 것이 없다 —
   그때는 위·아래 중 어디에 둘지를 사람이 정한 값(상단/하단)이 답이다. */
#ui .tv-menu.bottom.lay-split .tv-menu-body > :only-child { margin-top: auto; }
#ui .tv-menu.top.lay-split .tv-menu-body > :only-child { margin-bottom: auto; }
/* 위로 올라간 줄은 경계선도 아래쪽에 긋는다 */
#ui .tv-menu.top.lay-split .tv-menu-body > :only-child .tv-menu-row,
#ui .tv-menu.top.lay-split .tv-menu-body > :only-child.tv-menu-row {
	border-top: 0; border-bottom: 1px solid var(--edge);
}

/* 평형 이름표를 쓰면 아래 띠는 [이름표][넘어가는 장면 줄] 두 칸이 된다.
   띠의 배경·테두리·슬라이드는 바깥 상자가 맡고, 줄은 알맹이만 담는다.
   (이름표가 띠 높이를 꽉 채워야 레퍼런스와 같은 모양이 나온다) */
.tv-menu.lay-split .tv-menu-rowbox {
	pointer-events: auto; background: var(--m-bg);
	backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
	border-top: 1px solid var(--edge);
	transition: transform 0.32s var(--ease);
}
.tv-menu.lay-split.closed .tv-menu-rowbox { transform: translateY(110%); }
.tv-menu.lay-split .tv-menu-rowbox > .tv-menu-scroll {
	padding-block: var(--m-pad, 8px); padding-inline: var(--m-side, 10px);
}
.tv-menu.lay-split .tv-menu-rowbox .tv-menu-row {
	padding: 0; background: none; border: 0; transform: none;
	backdrop-filter: none; -webkit-backdrop-filter: none;
}

/* ── 가로로 넘치는 줄: 좌우 화살표 ── */
.tv-menu-scroll { position: relative; display: flex; align-items: center; min-width: 0; }
.tv-menu-scroll > .tv-menu-list, .tv-menu-scroll > .tv-menu-tabs {
	flex: 1; min-width: 0; cursor: grab; scroll-behavior: smooth;
}
.tv-menu-scroll > .dragging { cursor: grabbing; scroll-behavior: auto; }
.tv-menu-scroll > .dragging img { pointer-events: none; }
.tv-menu-arrow {
	position: absolute; top: 50%; z-index: 2; transform: translateY(-50%);
	width: 22px; height: 30px; display: none; place-items: center; padding: 0;
	border: 1px solid var(--edge); border-radius: 7px;
	background: var(--m-bg, var(--panel)); color: var(--m-fg, var(--text));
	cursor: pointer; transition: background 0.14s, color 0.14s, opacity 0.14s;
}
.tv-menu-arrow.left { left: 0; }
.tv-menu-arrow.right { right: 0; }
.tv-menu-scroll.scrollable > .tv-menu-arrow { display: grid; }
/* 화살표가 놓일 자리를 **감싸개**에 비워 둔다.
   줄(list)에 padding 을 주면 그 여백까지 같이 스크롤돼, 넘겨 보는 순간 항목이
   화살표 밑으로 기어 들어간다(평형 이름·장면 이름이 버튼에 덮여 보였다).
   감싸개가 비워 두면 스크롤 영역 자체가 좁아져 절대 겹치지 않는다. */
.tv-menu-scroll.can-prev { padding-left: calc(22px + var(--m-side, 10px)); }
.tv-menu-scroll.can-next { padding-right: calc(22px + var(--m-side, 10px)); }
/* 갈라놓은 배치는 감싸개가 띠 여백도 함께 가진다 — 위 규칙보다 셈이 세므로 다시 적는다 */
.tv-menu.lay-split .tv-menu-rowbox > .tv-menu-scroll.can-prev,
.tv-menu.lay-split .tv-menu-body > .tv-menu-scroll.can-prev {
	padding-left: calc(22px + var(--m-side, 10px));
}
.tv-menu.lay-split .tv-menu-rowbox > .tv-menu-scroll.can-next,
.tv-menu.lay-split .tv-menu-body > .tv-menu-scroll.can-next {
	padding-right: calc(22px + var(--m-side, 10px));
}
/* **화살표 자리가 뚫려 보이던 것.**
   갈라놓은 배치에서는 판이 투명하고 **띠 색은 줄(list)에만** 칠해져 있었다.
   넘치기 시작하면 감싸개에 좌우 여백(22px+)이 붙는데 그 여백은 아무도 안 칠해
   **그 자리만 사진이 비쳤다.** 감싸개가 같은 띠 색을 갖게 한다.
   (`is-row` 는 줄이 실제로 펼쳐졌을 때만 붙으므로 접힌 줄에 띠가 남지 않는다) */
#ui .tv-menu.lay-split .tv-menu-body > .tv-menu-scroll.is-row,
#ui .tv-menu.lay-split .tv-menu-rowbox > .tv-menu-scroll.is-row {
	background: var(--m-bg);
	backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
}
.tv-menu-arrow:hover:not(:disabled) { background: var(--accent); color: var(--on-accent, #0b0d10); }
.tv-menu-arrow:disabled { opacity: 0; pointer-events: none; }
.tv-menu-arrow i {
	width: 7px; height: 7px;
	border-right: 1.7px solid currentColor; border-bottom: 1.7px solid currentColor;
}
.tv-menu-arrow.left i { transform: rotate(135deg) translate(-1px, -1px); }
.tv-menu-arrow.right i { transform: rotate(-45deg) translate(-1px, -1px); }

/* 세로 목록: 평형이 길어도 패널이 스크롤하므로 접힘 상한만 넉넉히 */
.tv-menu-fold.on { max-height: 3000px; }

/* ------------------------------------------------- 손가락으로 누를 때
   **보이는 크기는 그대로 두고 「누를 수 있는 영역」만 넓힌다.** 마우스로 맞추던
   14px 짜리 점을 손가락으로 찍기는 어렵다. 디자인을 바꾸면 투어를 만든 사람이
   맞춰 둔 모습이 폰에서만 달라지므로, 눈에 보이는 것은 건드리지 않는다.
   `pointer: coarse` 는 손가락·펜처럼 정밀하지 않은 입력일 때만 참이다.

   **이 블록은 파일 맨 끝에 둔다.** 같은 특정도면 나중에 나온 규칙이 이기므로,
   앞쪽에 두면 뒤에 오는 기본 규칙(.tv-menu-arrow 등)에 덮인다. */
@media (pointer: coarse) {
	/* 평면도 점 — 점은 14px 그대로, 잡히는 영역만 34px 로 넓힌다.
	   ::after 는 버튼의 일부라 여기를 눌러도 그 점이 눌린다. */
	.tv-dot::after { content: ''; position: absolute; inset: -10px; }
	/* 미니맵 닫기 X — 얇은 바는 유지하면서 손가락이 닿을 만큼만 키운다 */
	.tv-map-tabs.bare { padding: 1px 2px; }
	.tv-map-tabs.bare .tv-map-close { width: 34px; height: 30px; --x-dot: 26px; }
	.tv-map-tabs.bare .tv-map-close svg { width: 22px; height: 22px; }
	/* 메뉴 항목 — 글자 크기·좌우 여백 설정은 그대로 두고 **높이만 바닥을 깔아 준다.**
	   버튼은 원래 내용을 세로 가운데에 두므로 `display` 를 건드릴 필요가 없다 —
	   flex 로 바꾸면 썸네일+제목 항목(그림 위, 글자 아래)이 옆으로 눕는다. */
	.tv-menu-item, .tv-menu-tab, .tv-menu-group { min-height: 40px; }
	/* 좌우 화살표 — **높이만 올린다.**
	   가로는 `.tv-menu-scroll` 의 여백 계산이 22px 를 박아 쓰므로 넓히면 항목과
	   겹치고, ::after 로 영역만 넓히는 것도 **스크롤 컨테이너의 overflow 에 잘려**
	   듣지 않는다(실측 눌리는 폭 12px). 세로로만 키워 둔다. */
	.tv-menu-arrow { min-height: 40px; }
}

/* ------------------------------------------------- 전시품목 목록 패널
   옆에서 밀려 들어온다. 한 줄을 누르면 그 핫스팟을 바라본다(포커싱). */
#ui > .tv-items {
	position: absolute; top: 0; bottom: 0; z-index: 5;
	width: var(--it-w, 260px); max-width: 78vw;
	background: var(--panel); border-right: 1px solid var(--edge);
	backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);
	color: var(--text); display: flex; flex-direction: column;
	/* 옆에서 밀려 들어오는 판은 조금 더 여유 있게 */
	transition: transform 0.42s var(--ease);
	pointer-events: auto;
}
#ui > .tv-items.at-left { left: 0; transform: translateX(-102%); }
#ui > .tv-items.at-right {
	right: 0; left: auto; transform: translateX(102%);
	border-right: 0; border-left: 1px solid var(--edge);
}
#ui > .tv-items.on { transform: none; }
.tv-items-head {
	display: flex; align-items: center; gap: 10px;
	padding: 16px 14px 12px; border-bottom: 1px solid var(--edge);
}
.tv-items-head b { flex: 1; font-size: 15px; font-weight: 700; }
.tv-items-x {
	appearance: none; border: 0; background: none; color: inherit;
	font-size: 17px; line-height: 1; cursor: pointer; opacity: 0.7; padding: 4px 6px;
}
.tv-items-x:hover { opacity: 1; }
.tv-items-list { list-style: none; margin: 0; padding: 8px 0; overflow-y: auto; }
.tv-items-list li {
	display: flex; align-items: baseline; gap: 10px; padding: 9px 14px;
	cursor: pointer; transition: background 0.14s;
}
.tv-items-list li:hover { background: rgba(255, 255, 255, 0.08); }
.tv-items-list li.on { background: var(--accent-soft, rgba(124, 196, 255, 0.18)); }
.tv-items-list li i {
	font-style: normal; font-size: 20px; font-weight: 700; line-height: 1;
	color: var(--accent-ink, var(--accent)); min-width: 22px;
}
.tv-items-list li span { font-size: 13px; line-height: 1.35; }
.tv-items-none { color: var(--dim, #9aa3ad); cursor: default; }


/* ==========================================================================
   장면 온오프 · 전시품목 — **생김새/디자인 넷씩**
   ========================================================================== */

/* ── 장면 온오프 ─────────────────────────────────────────────────────────
   두 장일 때만 뜻이 통하는 것들이다. 세 장부터는 탭으로 떨어진다. */

/* 세그먼트 — 두 칸이 붙어 있고 고른 쪽이 채워진다 */
.tv-vars.sty-segment {
	gap: 0; padding: 3px; border-radius: 999px;
	background: var(--panel); border: 1px solid var(--edge);
	backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
	box-shadow: 0 6px 22px rgba(0, 0, 0, 0.3);
}
.tv-vars.sty-segment .tv-var {
	border: 0; background: none; color: var(--dim); cursor: pointer;
	padding: 5px 14px; border-radius: 999px; font-size: var(--v-fs, 13px);
	transition: background 0.16s, color 0.16s;
}
.tv-vars.sty-segment .tv-var.on {
	background: var(--v-accent, var(--accent)); color: #08131c; font-weight: 600;
}

/* 아이콘 — 그림 하나. 켜지면 강조색으로 찬다 */
.tv-var-icon {
	appearance: none; cursor: pointer; padding: 0;
	width: calc(var(--v-fs, 13px) * 2.8); height: calc(var(--v-fs, 13px) * 2.8);
	display: grid; place-items: center;
	border-radius: 50%; color: #fff;
	background: var(--panel); border: 1px solid var(--edge);
	backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
	box-shadow: 0 6px 22px rgba(0, 0, 0, 0.3);
	transition: background 0.16s, color 0.16s, transform 0.1s;
}
.tv-var-icon svg { width: 58%; height: 58%; }
.tv-var-icon:hover { transform: scale(1.06); }
.tv-vars.two .tv-var-icon {
	background: var(--v-accent, var(--accent)); border-color: transparent; color: #08131c;
}

/* 큰 알약 — 「다음에 갈 곳」을 적어 준다 */
.tv-var-pill {
	appearance: none; cursor: pointer; display: flex; align-items: center; gap: 8px;
	padding: 7px 16px; border-radius: 999px; font-size: var(--v-fs, 13px);
	color: var(--text); background: var(--panel); border: 1px solid var(--edge);
	backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
	box-shadow: 0 6px 22px rgba(0, 0, 0, 0.3);
	transition: border-color 0.16s, transform 0.1s;
}
.tv-var-pill b { font-weight: 600; }
.tv-var-pill i { font-style: normal; color: var(--v-accent, var(--accent)); }
.tv-var-pill:hover { border-color: var(--v-accent, var(--accent)); transform: translateY(-1px); }

/* ── 전시품목 목록 ───────────────────────────────────────────────────────
   `de-*` 가 **여는 방법과 뜨는 자리**를 통째로 바꾼다. 기본(`de-drawer`)은
   지금까지의 옆 서랍이라 안 고른 투어의 모습이 안 바뀐다. */

/* 손잡이 — 가장자리에 붙어 있다가 당기면 목록이 딸려 나온다 (스위치가 없다) */
.tv-items-grab { display: none; }
.tv-items.de-handle .tv-items-grab {
	position: absolute; top: 50%; display: flex; align-items: center; gap: 6px;
	padding: 12px 8px; cursor: pointer;
	writing-mode: vertical-rl; text-orientation: mixed;
	font-size: 12px; color: var(--text);
	background: var(--panel); border: 1px solid var(--edge); border-left: 0;
	box-shadow: 4px 0 18px rgba(0, 0, 0, 0.35);
	transition: background 0.14s;
}
.tv-items.de-handle .tv-items-grab i {
	width: 3px; height: 22px; border-radius: 2px; background: var(--accent); flex: none;
}
.tv-items.de-handle .tv-items-grab:hover { background: #1d222a; }
.tv-items.de-handle.at-left .tv-items-grab {
	left: 100%; transform: translateY(-50%); border-radius: 0 10px 10px 0;
}
.tv-items.de-handle.at-right .tv-items-grab {
	right: 100%; transform: translateY(-50%); border-radius: 10px 0 0 10px;
	border-left: 1px solid var(--edge); border-right: 0;
}
/* 손잡이형은 닫혀 있어도 손잡이가 화면 안에 남아야 한다 */
#ui > .tv-items.de-handle.at-left { transform: translateX(-100%); }
#ui > .tv-items.de-handle.at-right { transform: translateX(100%); }
#ui > .tv-items.de-handle.on { transform: none; }

/* 아래 시트 — 아래에서 올라온다. 파노라마를 덜 가린다 */
#ui > .tv-items.de-sheet {
	left: 0; right: 0; top: auto; bottom: 0; width: auto; height: auto;
	max-height: 46vh; border-radius: 16px 16px 0 0;
	transform: translateY(102%);
	border-top: 1px solid var(--edge);
}
#ui > .tv-items.de-sheet.on { transform: none; }
.tv-items.de-sheet .tv-items-list { display: flex; flex-wrap: wrap; gap: 6px; padding: 10px; }
.tv-items.de-sheet .tv-items-list li {
	flex: 0 0 auto; border-radius: 999px; background: var(--panel2);
	padding: 7px 13px; max-width: 46%;
}

/* 떠 있는 카드 — 화면 안쪽에 둥근 카드로 */
#ui > .tv-items.de-card {
	top: 50%; bottom: auto; height: auto; max-height: 66vh;
	width: var(--it-w, 260px); border-radius: 14px;
	border: 1px solid var(--edge); box-shadow: 0 18px 50px rgba(0, 0, 0, 0.55);
	opacity: 0; visibility: hidden;
	transition: opacity 0.18s var(--ease), transform 0.18s var(--ease), visibility 0.18s;
}
#ui > .tv-items.de-card.at-left { left: 22px; transform: translate(-8px, -50%) scale(0.98); }
#ui > .tv-items.de-card.at-right { right: 22px; left: auto; transform: translate(8px, -50%) scale(0.98); }
#ui > .tv-items.de-card.on { opacity: 1; visibility: visible; transform: translate(0, -50%) scale(1); }

/* ------------------------------------------------ 하단 고지문 (주의 문구)
   「본 콘텐츠는 … 실제와 다를 수 있습니다」 같은 안내. 아래 묶음의 **마지막 칸**
   이라 자리를 따로 잡지 않고, 그만큼 --dock-h 가 커져 평면도가 위로 비켜난다.
   줄바꿈은 적은 그대로 지킨다(pre-line) — 문장마다 ※ 를 붙여 쓰기 때문이다. */
.tv-legal {
	/* **팝업(z 4) 아래**에 있어야 한다. 5 로 뒀더니 그림 팝업 위를 덮었다 —
	   고지문은 늘 깔려 있는 바닥 띠이지 앞에 나설 것이 아니다. 묶음과 같은 3. */
	/* **세로 메뉴를 피해 시작한다.** 왼쪽 세로 메뉴를 쓰는 짜임(조감 투어가
	   그렇다)에서는 메뉴가 고지문 앞머리를 덮어 「※ 본 …」가 안 보였다.
	   평면도·컨트롤 바가 이미 쓰고 있는 변수(`--menu-left/right`)를 같이 쓴다. */
	position: absolute; left: var(--menu-left, 0px); right: var(--menu-right, 0px);
	bottom: 0; z-index: 3;
	box-sizing: border-box;
	/* **좁은 화면에서는 상한을 걸어 줄인다.**
	   `--legal-*` 는 ui.js 가 **인라인으로** 박으므로 미디어쿼리로 다시 정의해도
	   못 이긴다(평면도 `--map-max` 와 같은 사정이다). 그래서 **상한 변수**를 따로
	   두고 `min()` 으로 고른다 — 넓은 화면에서는 적어 둔 값 그대로, 좁아지면
	   상한이 이긴다. 안 그러면 폰에서 11px 글이 열 줄 넘게 접혀 **띠가 화면 절반을
	   먹었다**(「박스가 커지네」). 여백·줄간격도 함께 줄여야 뜻이 있다. */
	padding: min(var(--legal-py, 7px), var(--legal-py-max, 99px))
		min(var(--legal-px, 16px), var(--legal-px-max, 999px))
		max(min(var(--legal-py, 7px), var(--legal-py-max, 99px)), env(safe-area-inset-bottom));
	background: var(--legal-bg, rgba(10, 14, 24, 0.86));
	color: var(--legal-fg, rgba(255, 255, 255, 0.8));
	font-size: min(var(--legal-fs, 11px), var(--legal-fs-max, 99px));
	line-height: min(var(--legal-lh, 1.55), var(--legal-lh-max, 9));
	white-space: pre-line; text-align: var(--legal-al, left);
}
/* 태블릿 — 글자만 살짝 */
@media (max-width: 900px) {
	.tv-legal { --legal-fs-max: 10px; --legal-px-max: 18px; --legal-lh-max: 1.5; }
}
/* 폰(가로) */
@media (max-width: 640px) {
	.tv-legal { --legal-fs-max: 9px; --legal-px-max: 12px; --legal-py-max: 6px; --legal-lh-max: 1.4; }
}
/* 폰(세로) — 글이 길면 여기서 가장 많이 접힌다 */
@media (max-width: 420px) {
	.tv-legal { --legal-fs-max: 8px; --legal-px-max: 9px; --legal-py-max: 5px; --legal-lh-max: 1.35; }
}
/* **띠는 화면 끝까지, 글은 좁게.** 폭을 정해 두면 글만 그 폭으로 가운데 모인다 —
   넓은 모니터에서 한 줄이 화면을 가로질러 읽기 힘들어지는 것을 막는다. */
.tv-legal-in { display: block; max-width: var(--legal-mw, none); margin: 0 auto; }
/* **띠 높이만큼 나머지가 올라간다.** 아래 묶음(썸네일·컨트롤 바)과 아래에 붙인
   메뉴가 띠에 가리지 않게. 아래쪽 부속(평면도·나침반 …)은 `--dock-h` 를 통해
   저절로 따라 올라간다 — 묶음이 이미 그만큼 올라가 있기 때문이다. */
#ui .tv-dock { bottom: var(--legal-h, 0px); }
#ui .tv-menu.bottom { bottom: var(--legal-h, 0px); }

/* ---------------------------------------------------------------- 상단 띠
   로고·사업명이 왼쪽, 안내 링크가 오른쪽인 한 줄. 장면 메뉴는 이 아래 줄이다.
   (레퍼런스 투어들이 거의 다 이 모양이다 — 흰 띠 + 그 아래 짙은 막대) */
.tv-head {
	position: absolute; left: 0; right: 0; top: 0; z-index: 6;
	background: var(--hd-bg, #fff); color: var(--hd-fg, #1b2430);
	border-bottom: 1px solid rgba(0, 0, 0, 0.1);
	pointer-events: auto;
	padding-top: env(safe-area-inset-top, 0px);
}
.tv-head.noline { border-bottom: 0; }
/* 위 메뉴와 같은 색이면 이음매가 되므로 걷는다 — ui.js `seamless` */
.tv-head.seamless { border-bottom: 0; }
.tv-head[hidden] { display: none; }
.tv-head-in {
	display: flex; align-items: center; gap: 14px;
	min-height: var(--hd-h, 56px);
	padding: 0 max(var(--hd-pad, 22px), env(safe-area-inset-left, 0px))
	         0 max(var(--hd-pad, 22px), env(safe-area-inset-right, 0px));
}
.tv-head-brand { display: flex; align-items: center; gap: 12px; min-width: 0; }
/* 로고·사업명을 누르면 처음 화면으로 — 누를 수 있을 때만 손 모양이 된다 */
.tv-head-brand.link { cursor: pointer; transition: opacity 0.14s; }
.tv-head-brand.link:hover { opacity: 0.7; }
/* **칸보다 넓은 로고는 칸에 맞춰 줄인다.** `flex: none` 만 두면 그림이 제 비율대로 넓어져
   칸(brand)을 뚫고 나가 방 이름 단추 밑에 깔렸다 — 양주(1024×96, 글자까지 든 긴 로고)가 폰에서
   384px 로 그려져 184px 칸을 넘었다(10/1). 높이(설정값)는 그대로 두고 그림만 칸 안에 담는다. */
.tv-head-logo { display: block; width: auto; flex: 0 1 auto; min-width: 0; max-width: 100%;
	object-fit: contain; object-position: left center; }
.tv-head-title {
	font-size: var(--hd-title, 20px); font-weight: 700; letter-spacing: -0.02em;
	white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* 링크는 오른쪽 끝에. 많아지면 **그 줄 안에서만** 가로로 밀린다
   (줄바꿈을 허용하면 띠 높이가 들쭉날쭉해져 아래 메뉴가 따라 움직인다) */
/* 링크 줄은 **띠 높이를 꽉 채운다** — 지금 보고 있는 평형의 표시가 띠 맨 아래,
   남색 막대와 맞닿는 자리에 붙어야 한다(레퍼런스가 그 모양이다). 글자 바로 밑에
   그으면 띠 가운데에 짧은 선이 떠 있어 무엇을 가리키는지 약해 보인다. */
.tv-head-nav {
	margin-left: auto; align-self: stretch;
	display: flex; align-items: stretch; gap: var(--hd-gap, 22px);
	overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch;
}
.tv-head-nav::-webkit-scrollbar { display: none; }
.tv-head-link {
	position: relative;
	display: flex; align-items: center;
	font-size: var(--hd-link, 14px); font-weight: 600; white-space: nowrap;
	color: inherit; text-decoration: none; opacity: 0.72;
	/* 평형 링크는 <button> 이다 — 브라우저 기본 모양을 지운다 */
	font-family: inherit; background: none; border: 0; cursor: pointer;
	padding: 0; transition: opacity 0.14s;
}
a.tv-head-link:hover, button.tv-head-link:hover { opacity: 1; }
/* 지금 보고 있는 페이지 — 주소가 같으면 저절로 켜진다.
   표시는 **띠 맨 아래**에 붙는 굵은 선이다(두께는 「선택 표시 두께」). */
.tv-head-link.on { opacity: 1; color: var(--hd-accent, #1b3a6b); }
.tv-head-link.on::after {
	content: ''; position: absolute; bottom: 0;
	/* 글자 폭에 딱 맞추면 선이 짧아 허전하다 — **양옆으로 조금 더** 뺀다
	   (「선택 표시 여유」). 링크 사이 간격보다 크게 주면 옆 링크와 닿는다. */
	left: calc(-1 * var(--hd-markpad, 8px));
	right: calc(-1 * var(--hd-markpad, 8px));
	height: var(--hd-mark, 4px); background: currentColor;
}
/* 주소 없이 글자만 둔 것(「기본제공」 같은 머리말) — 누를 수 없다 */
.tv-head-link.plain { opacity: 0.55; font-weight: 500; cursor: default; }

/* ------------------------------------------------------- 좁은 화면에서 접기
   링크가 한 줄에 안 들어가면 단추 하나로 접는다(`header.js` 의 `_fold`).
   **감추는 것이 아니다** — 접힌 목록에는 몇 개든 다 들어간다. 잘린 채 밀 수
   있다는 표시도 없던 예전 모습이 옆 평형으로 갈 길을 사실상 막고 있었다. */
.tv-head-more {
	margin-left: auto; display: flex; align-items: center; gap: 9px;
	font: inherit; font-size: var(--hd-link, 14px); font-weight: 700;
	color: var(--hd-accent, #1b3a6b); background: none; border: 0;
	padding: 7px 2px 7px 10px; cursor: pointer; white-space: nowrap;
}
.tv-head-more[hidden] { display: none; }
/* **여기가 드롭다운이라는 표시.** 작은 세모 하나로는 눌러야 뭐가 나오는 자리인지
   안 읽혔다 — **둥근 칸에 든 갈매기표**로 바꿔 「고르는 칸」처럼 보이게 한다.
   바탕은 회색 반투명이라 흰 띠·짙은 막대 어느 쪽에서도 한 톤 도드라진다. */
.tv-head-caret {
	width: 22px; height: 22px; flex: 0 0 auto; border-radius: 7px;
	background: rgba(128, 128, 128, 0.3);
	display: grid; place-items: center;
	transition: transform 0.18s, background 0.14s;
}
.tv-head-caret::before {
	content: ''; width: 8px; height: 8px; margin-top: -3px;
	border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
	transform: rotate(45deg);
}
.tv-head-more:hover .tv-head-caret { background: rgba(128, 128, 128, 0.45); }
.tv-head.open .tv-head-caret { transform: rotate(180deg); }

.tv-head.folded .tv-head-nav {
	position: absolute; left: 0; right: 0; top: 100%;
	flex-direction: column; align-items: stretch; gap: 0;
	background: var(--hd-bg, #fff); overflow: hidden auto;
	max-height: 0; transition: max-height 0.2s ease-out;
	border-radius: 0 0 14px 14px;
	box-shadow: 0 16px 30px rgba(0, 0, 0, 0.22);
}
.tv-head.folded.open .tv-head-nav { max-height: 60vh; padding: 7px 0 9px; }
.tv-head.folded .tv-head-link {
	position: relative; text-align: left; width: 100%; opacity: 1;
	margin: 0 8px; width: auto; border-radius: 10px; border-bottom: 0;
	padding: 12px 40px 12px calc(max(var(--hd-pad, 22px), env(safe-area-inset-left, 0px)) - 4px);
	transition: background 0.14s;
}
.tv-head.folded .tv-head-link:active { background: rgba(127, 127, 127, 0.16); }
/* 주소 없는 머리말 — 목록에서는 **작은 구분 글씨**. 아래에 옅은 선을 하나 긋는다 */
.tv-head.folded .tv-head-link.plain {
	font-size: 11px; font-weight: 600; opacity: 0.45; letter-spacing: 0.04em;
	padding: 12px 16px 7px; margin: 0 8px 4px; border-radius: 0;
	border-bottom: 1px solid rgba(127, 127, 127, 0.22);
}
/* **지금 보고 있는 것.** 줄 하나만 그어 두면 골라진 줄이 어느 것인지 안 읽혔다 —
   왼쪽 굵은 막대 · 강조색 · 굵은 글씨 · 오른쪽 체크, 넷을 함께 준다.
   (바탕을 칠하지 않는 까닭: 띠 색을 어둡게 잡은 투어에서 옅은 칠은 안 보인다) */
.tv-head.folded .tv-head-link.on {
	color: var(--hd-accent, #1b3a6b); font-weight: 800;
}
.tv-head.folded .tv-head-link.on::before {
	content: ''; position: absolute; left: 0; top: 9px; bottom: 9px;
	width: 3px; border-radius: 2px; background: currentColor;
}
.tv-head.folded .tv-head-link.on::after {
	content: '\2713'; left: auto; right: 16px; top: 50%; bottom: auto;
	transform: translateY(-50%); width: auto; height: auto;
	background: none; font-size: 0.94em; line-height: 1;
}

/* 좁은 화면 — 띠를 낮추고 글자를 줄인다.
   **사업명이 먼저 줄어든다** — 링크는 길이고, 이름은 안내다. */
@media (max-width: 720px) {
	/* 폰 로고 높이를 따로 정한 투어(`header.logoSizeM`) — 인라인 높이를 이긴다 */
	.tv-head.logo-m .tv-head-logo { height: var(--hd-logo-m) !important; }
	/* 폰에서 로고 가운데(`header.centerM`) */
	.tv-head.center-m .tv-head-in { justify-content: center; }
	/* 빈 링크 줄이 `margin-left:auto` 로 남은 폭을 다 먹어 로고가 왼쪽에 붙어 있었다 */
	.tv-head.center-m .tv-head-nav:empty { display: none; }
	.tv-head.center-m .tv-head-logo { object-position: center; }
	/* 오른쪽 정렬 막대의 오른쪽 여백(평형 칸과 띄우는 몫)은 폰에서는 빈자리일 뿐이다 —
	   화살표 자리(can-next)와 겹쳐 오른쪽만 크게 비었다(LX). 오른쪽 정렬을 쓰는 투어는 LX 뿐. */
	.tv-menu.al-right.lay-inline.gfull .tv-menu-scroll.is-row { margin-right: 0; }
	.tv-head-in {
		min-height: calc(var(--hd-h, 56px) * 0.78);
		gap: 8px; padding-left: 14px; padding-right: 14px;
	}
	.tv-head-brand { min-width: 0; flex: 0 1 auto; }
	.tv-head-title { font-size: calc(var(--hd-title, 20px) * 0.8); }
	/* 좁은 화면에서는 사이를 조금 좁힌다(설정값의 70%, 최소 10px) */
	.tv-head-nav { flex: 0 1 auto; gap: max(10px, calc(var(--hd-gap, 22px) * 0.7)); }
	/* 폰 글자 크기 — 「링크 크기(모바일)」를 정해 뒀으면 그 값, 아니면 PC 값의 92% */
	.tv-head-link { font-size: var(--hd-link-m, calc(var(--hd-link, 14px) * 0.92)); }
	.tv-head.folded .tv-head-link { font-size: var(--hd-link-m, calc(var(--hd-link, 14px) * 1.02)); }
	.tv-head-more { font-size: var(--hd-link-m, var(--hd-link, 14px)); }
	/* **로고 크기가 방 이름 길이를 따라 바뀌면 안 된다.** 로고 칸이 「남는 자리」였을 때는
	   「49층뷰(석경)」에서 184px, 「30층뷰」에서 더 넓게 — 방을 옮길 때마다 로고가
	   커졌다 작아졌다 했다(양주, 10/1). 로고는 **띠의 절반까지** 제 크기를 갖고 줄지 않으며,
	   남은 쪽(방 이름 단추)이 줄어 긴 이름은 말줄임(…)으로 자른다. 로고 하나만 있는 띠
	   (`onbar` — 단추가 아래 막대로 내려간 짜임)는 예전대로 가운데에 제 크기다. */
	.tv-head:not(.onbar) .tv-head-brand:has(+ .tv-head-more:not([hidden])) {
		flex: 0 0 auto; max-width: 50%;
	}
	.tv-head-more { min-width: 0; flex: 0 1 auto; }
	.tv-head-more > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
}

/* **좁은 화면 — 평형 단추를 방 이름 막대 왼쪽에 얹는다.**
   띠 두 줄(로고 / 평형) + 막대 한 줄이면 폰에서 사진이 볼 것이 없다.
   단추를 막대 안으로 넣으면 **줄이 하나 준다** — 위는 로고, 아래는 [평형 ▾][거실…].
   막대 색은 메뉴가 `#ui` 에 올려 준 값(`--menu-bg`)을 그대로 쓴다. */
@media (max-width: 720px) {
	/* 평형 단추가 아래 막대로 내려가면 윗줄에는 로고뿐이다 — **가운데로** 둔다
	   (왼쪽에 붙여 두면 오른쪽이 통째로 비어 한쪽으로 쏠려 보인다) */
	.tv-head.onbar .tv-head-in { justify-content: center; }
	.tv-head.onbar .tv-head-brand { flex: 0 1 auto; }
	.tv-head.onbar .tv-head-more {
		/* **`100%` 가 아니라 `--head-h`.** 띠 높이가 55.5px 처럼 소수로 나오면
		   `100%` 는 55, 아래 막대는 반올림한 56 에서 시작해 **1px 어긋난다**
		   (단추 윗변만 남색 막대 위로 삐져나와 보인다). 둘이 같은 값을 쓴다. */
		position: absolute; left: 0; top: var(--head-h, 100%); margin: 0; z-index: 7;
		height: var(--menu-top, 44px); padding: 0 14px;
		/* **한 겹 어둡게.** 같은 막대에 나란히 앉으므로 색이 같으면 어디까지가
		   평형인지 안 갈린다. 막대 색 위에 검정을 옅게 덮으면 **흰 막대든 짙은
		   막대든** 한 단계 짙어져, 색을 따로 정하지 않아도 구분이 생긴다. */
		background: linear-gradient(rgba(0, 0, 0, 0.46), rgba(0, 0, 0, 0.46)),
			var(--menu-bg, var(--panel));
		color: var(--menu-fg, var(--text));
	}
	/* **평형과 방 이름 사이 경계.** 같은 막대에 나란히 앉아 있어 어디까지가
	   평형이고 어디부터가 방인지 안 갈렸다. 막대 글자색을 옅게 깐 세로선 하나로
	   가른다 — 색을 박지 않아 흰 막대·짙은 막대 어느 쪽에서도 묻히지 않는다. */
	.tv-head.onbar .tv-head-more::after {
		content: ''; position: absolute; right: 0; top: 22%; bottom: 22%;
		width: 1px; background: currentColor; opacity: 0.4;
	}
	/* 펼친 목록은 **막대 아래**에서 내려온다 (막대를 덮으면 어디였는지 잃는다) */
	.tv-head.onbar .tv-head-nav { top: calc(var(--head-h, 100%) + var(--menu-top, 44px)); }
}
/* **띠에 평형 고르개가 얹혔으면 메뉴 쪽 평형 탭은 감춘다.**
   폰에서는 띠가 접히며 「59A ▾」 고르개가 메뉴 막대 왼쪽에 얹힌다(`onbar`).
   거기에 메뉴의 평형 탭까지 나오면 **평형이 두 벌**이 되고, 실측 375px 화면에서
   방 줄이 308px 부터 시작해 **방 이름이 한 칸도 안 보였다.** 평형은 얹힌
   고르개 하나로 충분하다 — 넓은 화면에서는 띠가 안 접히므로 그대로 나온다. */
#ui .tv-head.onbar ~ .tv-menu.lay-inline .tv-menu-scroll.is-tabs { display: none; }
#ui .tv-head.onbar ~ .tv-menu.lay-inline { --row-gap-l: 0px; }

/* 방 이름들이 그 단추를 피해 시작한다. 얹지 않았을 때는 0 이라 아무 일도 없다.
   **여백(padding)이 아니라 바깥 여백(margin)** 이다 — 여백으로 밀면 ① 막대가 이미
   갖고 있는 좌우 여백에 **덧붙어** PC 에서도 왼쪽이 한 뼘 벌어지고, ② 화살표 자리를
   비워 두는 `can-prev` 의 여백을 덮어써 **왼쪽 화살표가 사라진다.**
   바깥 여백으로 밀면 스크롤 영역 자체가 오른쪽에서 시작해 둘 다 성립한다. */
#ui .tv-menu.top .tv-menu-scroll.is-row {
	margin-left: calc(var(--head-more-w, 0px) + var(--row-gap-l, 0px));
}

/* 가로로 눕힌 폰 — 세로가 375px 밖에 안 된다. 띠와 메뉴가 화면의 3분의 1을
   차지하면 정작 사진이 안 보인다. 높이만 더 줄인다(글자는 그대로 읽히게). */
@media (max-height: 480px) and (orientation: landscape) {
	.tv-head-in { min-height: 40px; }
	.tv-head-title { font-size: calc(var(--hd-title, 20px) * 0.72); }
	.tv-head.folded.open .tv-head-nav { max-height: 72vh; }
}

/* 출력 HTML의 첫 로고와 런타임 진행률이 같은 레이아웃을 공유한다. */
.boot-continuous > div { position: relative; }
.boot-continuous .tv-splash-bar { position: absolute; top: calc(100% + 18px); left: 50%; transform: translateX(-50%); }
.boot-continuous .tv-splash-pct { position: absolute; top: calc(100% + 32px); left: 50%; transform: translateX(-50%); margin: 0; }
@media (prefers-reduced-motion: reduce) { .tv-splash, .tv-splash-bar i { transition: none; } }

/* ================================================================
   「한 판」 하단 짜임 (`settings.dockStyle = 'panel'`)
   ----------------------------------------------------------------
   썸네일과 컨트롤 바를 **회색 판 하나**에 담는다. 썸네일은 평형마다 검은 머리
   (STANDARD · PREMIUM)로 묶고, 바는 왼쪽(◀◀ · 목록) · 가운데(◀ ▶ ▲ ▼ + −) ·
   오른쪽(전체화면 · 접기 · ▶▶) 세 칸이다. 엘리베이터·마감재처럼 **「고르는」
   투어**의 레퍼런스 짜임. 버튼 모양(bs-*)보다 **뒤에** 둬야 이긴다.
   ================================================================ */
/* 숨긴 버튼은 정말 숨는다 — `.tv-btn { display:grid }` 가 [hidden] 을 이기므로 */
#ui .tv-btn[hidden] { display: none !important; }

#ui .tv-dock.panel {
	left: 50%; right: auto; transform: translateX(-50%);
	width: max-content;
	max-width: calc(100vw - 16px - var(--menu-left, 0px) - var(--menu-right, 0px));
	gap: 0; padding: 8px 8px max(3px, env(safe-area-inset-bottom));
	background: var(--dp-bg, rgba(118, 122, 128, 0.8));
	backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
}
/* 판 폭에 **묶어야** 넘칠 때 옆으로 밀린다 — 안 묶으면 줄이 판 밖으로 삐져나가고
   (폰에서 686px 가 359px 판 양옆으로) 넘길 것이 없어 슬라이드가 안 됐다. */
.tv-dock.panel .tv-thumbs {
	width: auto; padding: 0; align-self: stretch; min-width: 0; max-width: 100%;
}
.tv-dock.panel .tv-thumbs.open { max-height: 50vh; }
.tv-dock.panel .tv-thumbs-inner {
	gap: 6px; padding: 0 0 5px; justify-content: flex-start;
}
.tv-dock.panel .tv-thumbs.scrollable .tv-thumbs-inner { padding-left: 0; padding-right: 0; }
/* PC 에서 한 판에 다 들어오면 썸네일 묶음을 판 가운데로(바가 더 넓을 때 왼쪽에 붙어 있었다).
   넘칠 때(.scrollable)는 왼쪽부터 — 가운데로 두면 앞쪽이 잘려 못 넘긴다. */
@media (min-width: 601px) {
	.tv-dock.panel .tv-thumbs:not(.scrollable) .tv-thumbs-inner { justify-content: center; }
}
/* 평형 묶음 — 검은 머리 + 한 줄 */
.tv-tgroup { flex: 0 0 auto; display: flex; flex-direction: column; gap: 6px; }
.tv-tgroup-head {
	background: #000; color: #fff; font-weight: 700; font-size: 12.5px;
	letter-spacing: 0.02em; text-align: center; padding: 5px 10px;
	white-space: nowrap;
}
.tv-tgroup-row { display: flex; gap: 6px; }
/* 썸네일 — 사진 + 밝은 이름 띠. 고른 것은 흰 테두리 + 흰 띠 */
/* 폭은 `settings.dockThumbW`(px, 기본 116) → --dp-tw. 사진 높이는 폭을 따라 같은 비율(68/116) */
.tv-dock.panel .tv-thumb {
	width: var(--dp-tw, 116px); border-radius: 0; border: 2px solid transparent;
	background: #d6d8db; color: #2a2d31; font-size: 12px; outline: 0;
}
.tv-dock.panel .tv-thumb img { height: calc(var(--dp-tw, 116px) * 0.586); }
.tv-dock.panel .tv-thumb span { padding: 4px 4px 5px; }
/* 「이름 두 줄」(`dockThumbWrap`) — 넘으면 둘째 줄 끝에 … . 한 줄짜리도 두 줄 높이를
   잡아 둬 옆 썸네일과 높이가 같다. 한글은 낱말 중간에서 끊지 않는다(keep-all). */
.tv-dock.panel.wrap2 .tv-thumb span {
	white-space: normal; word-break: keep-all; overflow-wrap: anywhere;
	display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
	/* **한 줄이면 두 줄 칸의 가운데로**(TKE 「두 줄이 현재 없는데 상하 정렬」). 요즘 크롬은 줄 자르기
	   상자를 블록(flow-root)으로 다뤄 옛 box-pack 이 안 먹는다 — 블록의 세로 가운데(align-content)를 쓴다.
	   두 줄이면 칸을 꽉 채워 예전과 같다. */
	-webkit-box-pack: center; align-content: center;
	line-height: 1.25; height: 2.5em; box-sizing: content-box;
	/* 안쪽 여백에 셋째 줄이 비쳐 보이므로 여백은 바깥(margin)으로 뺀다 */
	padding: 0; margin: 4px 4px 5px;
}
.tv-dock.panel .tv-thumb:hover { transform: none; background: #eceef0; color: #000; }
.tv-dock.panel .tv-thumb.on { border-color: #fff; background: #fff; color: #000; }
/* 바 — 판이 바탕이므로 알약을 걷고 세 칸 격자로 */
#ui .tv-dock.panel .tv-bar {
	display: grid; grid-template-columns: 1fr auto 1fr; align-items: center;
	width: 100%; box-sizing: border-box; min-width: 360px;
	padding: 1px 0 0; background: none; border: 0; border-radius: 0;
	backdrop-filter: none; -webkit-backdrop-filter: none;
	max-width: none; overflow: visible;
}
/* 「판에서 뺄 버튼」(`dockHide`) */
#ui .tv-dock.panel .tv-btn.tv-dh { display: none !important; }
/* 칸 구분선은 세 칸이 대신한다 — 남겨 두면 격자 칸을 먹는다 */
.tv-dock.panel .tv-bar > .tv-sep { display: none; }
.tv-dock.panel .tv-zone { display: flex; align-items: center; gap: 2px; }
.tv-dock.panel .tv-zone-l { justify-self: start; }
.tv-dock.panel .tv-zone-c { justify-self: center; padding: 0 12px; }
.tv-dock.panel .tv-zone-r { justify-self: end; }
/* 아이콘 크기는 `settings.dockIcon`(px, 기본 44 — 처음 22 의 두 배) → --dp-ic.
   단추는 아이콘보다 가로 14 · 세로 8 크다. */
.tv-dock.panel .tv-btn {
	width: calc(var(--dp-ic, 44px) + 14px); height: calc(var(--dp-ic, 44px) + 8px);
	border-radius: 3px; color: #fff; background: none;
}
.tv-dock.panel .tv-btn svg { width: var(--dp-ic, 44px); height: var(--dp-ic, 44px); }
.tv-dock.panel .tv-btn:hover { background: rgba(255, 255, 255, 0.18); }
/* 켜짐(목록 열림 등)은 판 위에서 과하지 않게 — 바탕만 옅게 */
.tv-dock.panel .tv-btn.on { color: #fff; background: rgba(0, 0, 0, 0.22); }
.tv-dock.panel .tv-hold { touch-action: none; user-select: none; -webkit-user-select: none; }
/* ⏬ 접기 — 판을 걷고 버튼 하나만 남긴다 */
#ui .tv-dock.panel.folded {
	background: none; backdrop-filter: none; -webkit-backdrop-filter: none; padding: 0 0 4px;
}
.tv-dock.panel.folded .tv-thumbs { display: none; }
#ui .tv-dock.panel.folded .tv-bar { min-width: 0; grid-template-columns: auto; }
.tv-dock.panel.folded .tv-zone-l, .tv-dock.panel.folded .tv-zone-c { display: none; }
.tv-dock.panel.folded .tv-zone-r > .tv-btn:not(.tv-fold) { display: none !important; }
.tv-dock.panel.folded .tv-fold { background: var(--dp-bg, rgba(118, 122, 128, 0.8)); }
/* 좁은 화면 — 버튼을 줄여 한 줄에 들어가게 */
@media (max-width: 600px) {
	#ui .tv-dock.panel .tv-bar { min-width: 0; }
	.tv-dock.panel .tv-btn { width: 27px; height: 30px; }
	.tv-dock.panel .tv-btn svg { width: 18px; height: 18px; }
	.tv-dock.panel .tv-zone { gap: 0; }
	.tv-dock.panel .tv-zone-c { padding: 0 4px; }
	/* 폰에선 ▲ ▼ 를 뺀다 — 손가락으로 끌면 되고, 한 줄에 다 들어가야 한다(375px 에서 13개는 넘친다) */
	.tv-dock.panel .tv-zone-c > .tv-btn:nth-child(3),
	.tv-dock.panel .tv-zone-c > .tv-btn:nth-child(4) { display: none; }
	/* 폰은 정한 폭의 80% (기본 116 → 93px) */
	.tv-dock.panel .tv-thumb { width: calc(var(--dp-tw, 116px) * 0.8); }
	.tv-dock.panel .tv-thumb img { height: calc(var(--dp-tw, 116px) * 0.8 * 0.586); }
}

/* ------------------------------------------------------------- 떠 있는 로고
   `settings.logoMark` — 상단 띠 없이 파노라마 위에 얹는 로고(기본 우상단).
   나침반과 같은 9칸 규칙: 상단 띠·메뉴가 차지한 만큼 비켜나고, 아래 줄은
   썸네일·컨트롤 바(--dock-h) 위로 올라간다. 높이 기준 — 폭은 그림 비율대로. */
.tv-logomark {
	position: absolute; z-index: 3; display: block; line-height: 0;
	margin: calc(var(--head-h, 0px) + var(--menu-top, 0px)) var(--menu-right, 0) var(--menu-bottom, 0) var(--menu-left, 0);
	pointer-events: none;
}
.tv-logomark[hidden] { display: none; }
.tv-logomark.linked { pointer-events: auto; cursor: pointer; }
/* 폰에서는 화면 폭의 11% 를 넘지 않는다 — 44px 로고가 375px 에서 41px */
.tv-logomark img {
	display: block; height: min(var(--lg-h, 44px), 11vw); width: auto;
	max-width: 40vw; object-fit: contain; user-select: none; -webkit-user-drag: none;
}
.tv-logomark.at-tl, .tv-logomark.at-tc, .tv-logomark.at-tr { top: var(--lg-m, 16px); }
.tv-logomark.at-ml, .tv-logomark.at-mc, .tv-logomark.at-mr { top: 50%; transform: translateY(-50%); }
.tv-logomark.at-bl, .tv-logomark.at-bc, .tv-logomark.at-br {
	bottom: calc(var(--lg-m, 16px) + var(--dock-h, 0px));
}
.tv-logomark.at-tl, .tv-logomark.at-ml, .tv-logomark.at-bl { left: var(--lg-m, 16px); }
.tv-logomark.at-tr, .tv-logomark.at-mr, .tv-logomark.at-br { right: var(--lg-m, 16px); }
.tv-logomark.at-tc, .tv-logomark.at-bc { left: 50%; transform: translateX(-50%); }
.tv-logomark.at-mc { left: 50%; transform: translate(-50%, -50%); }

/* 안드로이드 앱 안 — 이미 전체 화면이다(viewer.js 가 html.in-app 을 붙인다) */
html.in-app .tv-btn.is-full { display: none !important; }
