@charset "utf-8";
/* ============================================================================
   visual.css  —  메인 비주얼(GLB Dot Form) 컨테이너 스타일
   df/test/bust-dots-demo/style.css 를 .visual_con 안으로 스코프해서 옮긴 것.

   원본은 position:fixed 로 화면 전체를 덮는 랩 페이지였으나,
   여기서는 .visual_con 안에서만 동작하도록 전부 컨테이너 기준으로 바꿨다.
   ( html,body { overflow:hidden } 같은 전역 규칙도 전부 제거 — 페이지가 스크롤돼야 하므로 )

   2026-09-08 변경 — 슬라이드 배경으로 편입
     · .visual_con 이 .visual_slide_con(메인 슬라이드) 안쪽 첫 자식으로 들어갔다.
     · 높이를 100vh 로 따로 잡던 것을 폐기하고 absolute inset:0 으로 슬라이드 박스에 묶었다.
       → 리사이징하면 슬라이드와 완전히 같은 비율로 같이 줄고 는다.
     · 순수 배경으로 쓰기로 해서 pointer-events:none. 스와이프·클릭은 전부 슬라이드가 받는다.
   ============================================================================ */

/* ---- 스태킹 : 배경(비주얼) 아래, 슬라이드 위 ------------------------------
   .visual_slide_con 은 main_style.css 에서 position 지정이 없다.
   배경 레이어의 기준 박스가 되어야 하므로 여기서 relative 를 준다.
   ※ main_style.css 를 건드리지 않기 위해 이 파일에서 잡는다.
      (visual.css 는 header.html 의 CSS 들보다 뒤에 로드되므로 동일 특이도에서 이긴다) */
#main_con > .visual_slide_con {
	position: relative;
	z-index: 0;
}
#main_con > .visual_slide_con > .swiper-container {
	z-index: 1;                 /* 슬라이드 콘텐츠가 배경 위에 온다 */
	background-color: transparent;
}

/* ---- 컨테이너 : 슬라이드 박스에 그대로 묶는다 -----------------------------
   높이를 따로 정하지 않는다. inset:0 이라 .visual_slide_con 의 실측 높이를
   그대로 따라가고, 그 높이는 슬라이드 .contents_con 이 만든다.

     데스크탑  .contents_con  min(1820px,94.79vw) x min(1080px,56.25vw)  = 1820:1080 고정
     모바일    .contents_con  88.54vw x 200vw                            =  850:1920 고정
       (main_style.css · main_common_all.css)

   즉 브레이크포인트마다 값을 따로 적지 않아도 배경이 슬라이드와 같은 비율로
   리사이징된다. 카메라의 세로 화각이 고정이므로 컨테이너 높이에 비례해
   모델 크기도 같이 변한다 — 슬라이드 텍스트가 vw 로 커지고 줄는 것과 정확히 같은 배율이다.
   (모바일은 박스가 세로로 길어 모델이 잘리므로 visual.js 에서 스케일을 보정한다) */
#main_con .visual_con {
	z-index: 0;
	background-color: #000000;
	overflow: hidden;
	/* 순수 배경 — 마우스/터치는 전부 통과시켜 슬라이드(Swiper 스와이프·버튼)가 받는다 */
	pointer-events: none;
	-webkit-user-select: none;
	-ms-user-select: none;
	user-select: none;
}

/* [A] 슬라이드 배경으로 쓰일 때 (index.html) --------------------------------
   .visual_slide_con 안에 들어가 있는 경우에만 슬라이드 박스에 묶는다. */
#main_con > .visual_slide_con > .visual_con {
	position: absolute;
	top: 0; right: 0; bottom: 0; left: 0;
}

/* [B] 단독으로 쓰일 때 (index_tmp.html 등) ----------------------------------
   #main_con 바로 아래에 홀로 놓인 경우다. 이때는 위 [A] 를 쓰면 안 된다 —
   #main_con 이 static 이라 absolute 가 body 기준으로 붙어버리고,
   문서 흐름에서 빠지는 바람에 #container 높이가 0 이 돼 푸터가 위로 올라온다.
   (2026-09-08 실측으로 확인하고 되돌린 부분)
   그래서 단독일 때는 원래대로 흐름 안에서 자기 높이를 갖는다. */
#main_con > .visual_con {
	position: relative;
	top: 0; left: 0;
	width: 100%;
	height: 100vh;
	min-height: 560px;
	max-height: 1080px;
}

/* ---- WebGL 캔버스 --------------------------------------------------------
   크기는 JS(ResizeObserver)가 컨테이너 실측값으로 잡는다.
   여기서는 레이아웃상 자리만 채워둔다. */
#main_con .visual_con .visual_canvas {
	display: block;
	position: absolute;
	top: 0; left: 0;
	width: 100%;
	height: 100%;
	z-index: 1;
	/* 배경 전용이라 캔버스는 입력을 받지 않는다. 컨테이너의 pointer-events:none 을
	   그대로 물려받지만, OrbitControls 가 domElement 에 인라인 스타일을 넣던 흔적이
	   남지 않도록 여기서도 명시해 둔다. (visual.js 는 INTERACTIVE=false 로 돈다) */
	pointer-events: none;
	touch-action: auto;
}

/* ---- 로딩 오버레이 -------------------------------------------------------
   GLB 3개(약 45MB) + 대륙 GeoJSON 을 받는 동안만 보인다. 로드가 끝나면 .hidden. */
#main_con .visual_con .visual_overlay {
	position: absolute;
	top: 0; left: 0; right: 0; bottom: 0;
	z-index: 5;
	display: flex;
	align-items: center;
	justify-content: center;
	color: rgba(255,255,255,0.55);
	text-align: center;
	pointer-events: none;
	transition: opacity 0.4s ease;
}
#main_con .visual_con .visual_overlay.hidden {
	opacity: 0;
}
#main_con .visual_con .visual_overlay .box {
	padding: 28px 36px;
	border: 1px dashed rgba(255,255,255,0.25);
	border-radius: 8px;
	font-size: 13px;
	line-height: 1.7;
	letter-spacing: 0.02em;
}

/* ---- 안내 워딩 숨김 -------------------------------------------------------
   원본 데모(df/test/bust-dots-demo/style.css)와 동일하게 처리.
   기능은 그대로 두고 화면에만 안 보이게 한다.
     · .visual_hint        하단 설명 문구
     · .visual_overlay .box 가운데 로딩/드래그 안내 박스
   ※ .visual_filepick 은 아래에서 opacity:0 으로 처리한다(?glbdev=1 일 때만 클릭 유지).
   문구를 다시 띄우려면 이 블록만 지우면 된다. */
#main_con .visual_con .visual_hint,
#main_con .visual_con .visual_overlay .box {
	display: none;
}

/* ---- 하단 안내 문구 ------------------------------------------------------ */
#main_con .visual_con .visual_hint {
	position: absolute;
	bottom: 14px; left: 50%;
	transform: translateX(-50%);
	z-index: 5;
	color: rgba(255,255,255,0.3);
	pointer-events: none;
	white-space: nowrap;
	font-size: 13px;
	letter-spacing: 0.02em;
}

/* ---- GLB 교체 UI ---------------------------------------------------------
   opacity 0 이라 눈에는 안 보이지만 클릭·파일선택은 동작한다.
   (display:none 으로 지우면 클릭이 안 되므로 쓰지 않는다)

   ※ 컨테이너가 pointer-events:none 이므로 클릭을 되살리려면 여기서 auto 로 되돌려야 한다.
     운영 화면에서 이 투명 박스가 슬라이드 클릭을 가로채면 안 되므로
     visual.js 가 ?glbdev=1 일 때만 .is_dev 를 붙이고, 그때만 클릭이 살아난다.
   완전히 없애려면 visual.js 의 GLB_PICKER_ALWAYS_ON 을 false 로 바꾼다. */
#main_con .visual_con .visual_filepick {
	position: absolute;
	/* 데모는 top:16px 였지만, 이 페이지는 #header(고정, 높이 100px / 모바일 102px)가
	   그 자리를 덮어 클릭이 헤더 로고에 먹힌다. 헤더 아래로 내린다. */
	top: 116px; left: 16px;
	z-index: 6;
	color: rgba(255,255,255,0.5);
	font-size: 13px;
	opacity: 0;
	pointer-events: none;
}
#main_con .visual_con .visual_filepick.is_dev {
	pointer-events: auto;
}
#main_con .visual_con .visual_filepick input {
	display: none;
}
#main_con .visual_con .visual_filepick label {
	display: inline-block;
	padding: 6px 12px;
	border: 1px solid rgba(255,255,255,0.25);
	border-radius: 6px;
	cursor: pointer;
}
#main_con .visual_con .visual_filepick label:hover {
	border-color: rgba(255,255,255,0.6);
	color: #ffffff;
}

/* ---- 모바일 -------------------------------------------------------------
   높이를 여기서 다시 잡지 않는다. 슬라이드 박스(.contents_con 88.54vw x 200vw)를
   그대로 따라가야 비율이 어긋나지 않기 때문이다.
   세로로 길어진 만큼 모델이 잘리는 문제는 visual.js 의 스케일 보정이 처리한다. */
@media all and (max-width: 1024px) {
	#main_con .visual_con .visual_hint {
		font-size: 11px;
	}
	/* 단독 사용([B])일 때만 높이를 조정한다. 배경([A])은 슬라이드 박스를 따라가야 하므로 건드리지 않는다. */
	#main_con > .visual_con {
		height: 78vh;
		min-height: 440px;
	}
}

@media all and (max-width: 640px) {
	#main_con > .visual_con {
		height: 68vh;
		min-height: 380px;
	}
}

/* ---- 모션 최소화 설정 ----------------------------------------------------
   JS 쪽에서도 애니메이션 루프를 돌리지 않고 정지 프레임 1장만 그린다.
   (CLAUDE.md 지켜야 할 것 1번) 여기서는 UI 문구의 트랜지션만 죽인다. */
@media (prefers-reduced-motion: reduce) {
	#main_con .visual_con .visual_overlay {
		transition: none;
	}
	#main_con .visual_con .visual_hint {
		display: none;
	}
}
